1e67f3b95SDavid du Colombier /* cdfs - CD, DVD and BD reader and writer file system */
27dd7cddfSDavid du Colombier #include <u.h>
37dd7cddfSDavid du Colombier #include <libc.h>
47dd7cddfSDavid du Colombier #include <auth.h>
57dd7cddfSDavid du Colombier #include <fcall.h>
67dd7cddfSDavid du Colombier #include <thread.h>
77dd7cddfSDavid du Colombier #include <9p.h>
87dd7cddfSDavid du Colombier #include <disk.h>
97dd7cddfSDavid du Colombier #include "dat.h"
107dd7cddfSDavid du Colombier #include "fns.h"
117dd7cddfSDavid du Colombier
129a747e4fSDavid du Colombier typedef struct Aux Aux;
139a747e4fSDavid du Colombier struct Aux {
149a747e4fSDavid du Colombier int doff;
159a747e4fSDavid du Colombier Otrack *o;
169a747e4fSDavid du Colombier };
179a747e4fSDavid du Colombier
188ad6bb6aSDavid du Colombier ulong getnwa(Drive *);
198ad6bb6aSDavid du Colombier
207dd7cddfSDavid du Colombier static void checktoc(Drive*);
217dd7cddfSDavid du Colombier
227dd7cddfSDavid du Colombier int vflag;
237dd7cddfSDavid du Colombier
24684b447eSDavid du Colombier static Drive *drive;
25684b447eSDavid du Colombier static int nchange;
267dd7cddfSDavid du Colombier
277dd7cddfSDavid du Colombier enum {
289a747e4fSDavid du Colombier Qdir = 0,
299a747e4fSDavid du Colombier Qctl = 1,
309a747e4fSDavid du Colombier Qwa = 2,
319a747e4fSDavid du Colombier Qwd = 3,
329a747e4fSDavid du Colombier Qtrack = 4,
337dd7cddfSDavid du Colombier };
347dd7cddfSDavid du Colombier
357dd7cddfSDavid du Colombier char*
geterrstr(void)367dd7cddfSDavid du Colombier geterrstr(void)
377dd7cddfSDavid du Colombier {
389a747e4fSDavid du Colombier static char errbuf[ERRMAX];
397dd7cddfSDavid du Colombier
409a747e4fSDavid du Colombier rerrstr(errbuf, sizeof errbuf);
417dd7cddfSDavid du Colombier return errbuf;
427dd7cddfSDavid du Colombier }
437dd7cddfSDavid du Colombier
4459cc4ca5SDavid du Colombier void*
emalloc(ulong sz)4559cc4ca5SDavid du Colombier emalloc(ulong sz)
4659cc4ca5SDavid du Colombier {
4759cc4ca5SDavid du Colombier void *v;
4859cc4ca5SDavid du Colombier
49dd12a5c6SDavid du Colombier v = mallocz(sz, 1);
5059cc4ca5SDavid du Colombier if(v == nil)
5114cc0f53SDavid du Colombier sysfatal("malloc %lud fails", sz);
5259cc4ca5SDavid du Colombier return v;
5359cc4ca5SDavid du Colombier }
5459cc4ca5SDavid du Colombier
557dd7cddfSDavid du Colombier static void
fsattach(Req * r)569a747e4fSDavid du Colombier fsattach(Req *r)
577dd7cddfSDavid du Colombier {
589a747e4fSDavid du Colombier char *spec;
599a747e4fSDavid du Colombier
609a747e4fSDavid du Colombier spec = r->ifcall.aname;
617dd7cddfSDavid du Colombier if(spec && spec[0]) {
627dd7cddfSDavid du Colombier respond(r, "invalid attach specifier");
637dd7cddfSDavid du Colombier return;
647dd7cddfSDavid du Colombier }
657dd7cddfSDavid du Colombier
667dd7cddfSDavid du Colombier checktoc(drive);
679a747e4fSDavid du Colombier r->fid->qid = (Qid){Qdir, drive->nchange, QTDIR};
689a747e4fSDavid du Colombier r->ofcall.qid = r->fid->qid;
699a747e4fSDavid du Colombier r->fid->aux = emalloc(sizeof(Aux));
707dd7cddfSDavid du Colombier respond(r, nil);
717dd7cddfSDavid du Colombier }
727dd7cddfSDavid du Colombier
739a747e4fSDavid du Colombier static char*
fsclone(Fid * old,Fid * new)749a747e4fSDavid du Colombier fsclone(Fid *old, Fid *new)
757dd7cddfSDavid du Colombier {
769a747e4fSDavid du Colombier Aux *na;
777dd7cddfSDavid du Colombier
789a747e4fSDavid du Colombier na = emalloc(sizeof(Aux));
799a747e4fSDavid du Colombier *na = *((Aux*)old->aux);
809a747e4fSDavid du Colombier if(na->o)
819a747e4fSDavid du Colombier na->o->nref++;
829a747e4fSDavid du Colombier new->aux = na;
839a747e4fSDavid du Colombier return nil;
847dd7cddfSDavid du Colombier }
857dd7cddfSDavid du Colombier
869a747e4fSDavid du Colombier static char*
fswalk1(Fid * fid,char * name,Qid * qid)879a747e4fSDavid du Colombier fswalk1(Fid *fid, char *name, Qid *qid)
887dd7cddfSDavid du Colombier {
897dd7cddfSDavid du Colombier int i;
907dd7cddfSDavid du Colombier
917dd7cddfSDavid du Colombier checktoc(drive);
929a747e4fSDavid du Colombier switch((ulong)fid->qid.path) {
937dd7cddfSDavid du Colombier case Qdir:
947dd7cddfSDavid du Colombier if(strcmp(name, "..") == 0) {
959a747e4fSDavid du Colombier *qid = (Qid){Qdir, drive->nchange, QTDIR};
969a747e4fSDavid du Colombier return nil;
977dd7cddfSDavid du Colombier }
987dd7cddfSDavid du Colombier if(strcmp(name, "ctl") == 0) {
999a747e4fSDavid du Colombier *qid = (Qid){Qctl, 0, 0};
1009a747e4fSDavid du Colombier return nil;
1017dd7cddfSDavid du Colombier }
102436f307dSDavid du Colombier if(strcmp(name, "wa") == 0 && drive->writeok &&
103cdf9e71cSDavid du Colombier (drive->mmctype == Mmcnone ||
104cdf9e71cSDavid du Colombier drive->mmctype == Mmccd)) {
1059a747e4fSDavid du Colombier *qid = (Qid){Qwa, drive->nchange, QTDIR};
1069a747e4fSDavid du Colombier return nil;
1077dd7cddfSDavid du Colombier }
1087dd7cddfSDavid du Colombier if(strcmp(name, "wd") == 0 && drive->writeok) {
1099a747e4fSDavid du Colombier *qid = (Qid){Qwd, drive->nchange, QTDIR};
1109a747e4fSDavid du Colombier return nil;
1117dd7cddfSDavid du Colombier }
1127dd7cddfSDavid du Colombier for(i=0; i<drive->ntrack; i++)
1137dd7cddfSDavid du Colombier if(strcmp(drive->track[i].name, name) == 0)
1147dd7cddfSDavid du Colombier break;
1158ad6bb6aSDavid du Colombier if(i == drive->ntrack)
1169a747e4fSDavid du Colombier return "file not found";
1179a747e4fSDavid du Colombier *qid = (Qid){Qtrack+i, 0, 0};
1189a747e4fSDavid du Colombier return nil;
1197dd7cddfSDavid du Colombier
1207dd7cddfSDavid du Colombier case Qwa:
1217dd7cddfSDavid du Colombier case Qwd:
1227dd7cddfSDavid du Colombier if(strcmp(name, "..") == 0) {
1239a747e4fSDavid du Colombier *qid = (Qid){Qdir, drive->nchange, QTDIR};
1249a747e4fSDavid du Colombier return nil;
1257dd7cddfSDavid du Colombier }
1269a747e4fSDavid du Colombier return "file not found";
1277dd7cddfSDavid du Colombier default: /* bug: lib9p could handle this */
1289a747e4fSDavid du Colombier return "walk in non-directory";
1297dd7cddfSDavid du Colombier }
1307dd7cddfSDavid du Colombier }
1317dd7cddfSDavid du Colombier
1327dd7cddfSDavid du Colombier static void
fscreate(Req * r)1339a747e4fSDavid du Colombier fscreate(Req *r)
1347dd7cddfSDavid du Colombier {
1359a747e4fSDavid du Colombier int omode, type;
1367dd7cddfSDavid du Colombier Otrack *o;
1379a747e4fSDavid du Colombier Fid *fid;
1389a747e4fSDavid du Colombier
1399a747e4fSDavid du Colombier fid = r->fid;
1409a747e4fSDavid du Colombier omode = r->ifcall.mode;
1417dd7cddfSDavid du Colombier
1427dd7cddfSDavid du Colombier if(omode != OWRITE) {
1437dd7cddfSDavid du Colombier respond(r, "bad mode (use OWRITE)");
1447dd7cddfSDavid du Colombier return;
1457dd7cddfSDavid du Colombier }
1467dd7cddfSDavid du Colombier
1479a747e4fSDavid du Colombier switch((ulong)fid->qid.path) {
1487dd7cddfSDavid du Colombier case Qdir:
1497dd7cddfSDavid du Colombier default:
1507dd7cddfSDavid du Colombier respond(r, "permission denied");
1517dd7cddfSDavid du Colombier return;
1527dd7cddfSDavid du Colombier
1537dd7cddfSDavid du Colombier case Qwa:
154cdf9e71cSDavid du Colombier if (drive->mmctype != Mmcnone &&
155cdf9e71cSDavid du Colombier drive->mmctype != Mmccd) {
156436f307dSDavid du Colombier respond(r, "audio supported only on cd");
157436f307dSDavid du Colombier return;
158436f307dSDavid du Colombier }
1597dd7cddfSDavid du Colombier type = TypeAudio;
1607dd7cddfSDavid du Colombier break;
1617dd7cddfSDavid du Colombier
1627dd7cddfSDavid du Colombier case Qwd:
1637dd7cddfSDavid du Colombier type = TypeData;
1647dd7cddfSDavid du Colombier break;
1657dd7cddfSDavid du Colombier }
1667dd7cddfSDavid du Colombier
1677dd7cddfSDavid du Colombier if((drive->cap & Cwrite) == 0) {
1687dd7cddfSDavid du Colombier respond(r, "drive does not write");
1697dd7cddfSDavid du Colombier return;
1707dd7cddfSDavid du Colombier }
1717dd7cddfSDavid du Colombier
1727dd7cddfSDavid du Colombier o = drive->create(drive, type);
1737dd7cddfSDavid du Colombier if(o == nil) {
1747dd7cddfSDavid du Colombier respond(r, geterrstr());
1757dd7cddfSDavid du Colombier return;
1767dd7cddfSDavid du Colombier }
1777dd7cddfSDavid du Colombier drive->nchange = -1;
1787dd7cddfSDavid du Colombier checktoc(drive); /* update directory info */
1797dd7cddfSDavid du Colombier o->nref = 1;
1809a747e4fSDavid du Colombier ((Aux*)fid->aux)->o = o;
1817dd7cddfSDavid du Colombier
1829a747e4fSDavid du Colombier fid->qid = (Qid){Qtrack+(o->track - drive->track), drive->nchange, 0};
1839a747e4fSDavid du Colombier r->ofcall.qid = fid->qid;
1847dd7cddfSDavid du Colombier respond(r, nil);
1857dd7cddfSDavid du Colombier }
1867dd7cddfSDavid du Colombier
1877dd7cddfSDavid du Colombier static void
fsremove(Req * r)1889a747e4fSDavid du Colombier fsremove(Req *r)
1897dd7cddfSDavid du Colombier {
1909a747e4fSDavid du Colombier switch((ulong)r->fid->qid.path){
1917dd7cddfSDavid du Colombier case Qwa:
1927dd7cddfSDavid du Colombier case Qwd:
1937dd7cddfSDavid du Colombier if(drive->fixate(drive) < 0)
1947dd7cddfSDavid du Colombier respond(r, geterrstr());
19560ba15acSDavid du Colombier // let us see if it can figure this out: drive->writeok = No;
1967dd7cddfSDavid du Colombier else
1977dd7cddfSDavid du Colombier respond(r, nil);
1987dd7cddfSDavid du Colombier checktoc(drive);
1997dd7cddfSDavid du Colombier break;
2007dd7cddfSDavid du Colombier default:
2017dd7cddfSDavid du Colombier respond(r, "permission denied");
2027dd7cddfSDavid du Colombier break;
2037dd7cddfSDavid du Colombier }
2047dd7cddfSDavid du Colombier }
2057dd7cddfSDavid du Colombier
2062d8b52e8SDavid du Colombier /* result is one word, so it can be used as a uid in Dir structs */
2072112d02cSDavid du Colombier char *
disctype(Drive * drive)208079e489fSDavid du Colombier disctype(Drive *drive)
209079e489fSDavid du Colombier {
210*889a2622SDavid du Colombier char *type, *rw, *laysfx;
211079e489fSDavid du Colombier
212*889a2622SDavid du Colombier rw = laysfx = "";
213079e489fSDavid du Colombier switch (drive->mmctype) {
214079e489fSDavid du Colombier case Mmccd:
215079e489fSDavid du Colombier type = "cd-";
216079e489fSDavid du Colombier break;
217079e489fSDavid du Colombier case Mmcdvdminus:
218079e489fSDavid du Colombier case Mmcdvdplus:
219079e489fSDavid du Colombier type = drive->dvdtype;
220079e489fSDavid du Colombier break;
221079e489fSDavid du Colombier case Mmcbd:
222079e489fSDavid du Colombier type = "bd-";
223*889a2622SDavid du Colombier if (drive->laysfx)
224*889a2622SDavid du Colombier laysfx = drive->laysfx;
225079e489fSDavid du Colombier break;
226079e489fSDavid du Colombier case Mmcnone:
2272d8b52e8SDavid du Colombier type = "no-disc";
228079e489fSDavid du Colombier break;
229079e489fSDavid du Colombier default:
230079e489fSDavid du Colombier type = "**GOK**"; /* traditional */
231079e489fSDavid du Colombier break;
232079e489fSDavid du Colombier }
233079e489fSDavid du Colombier if (drive->mmctype != Mmcnone && drive->dvdtype == nil)
23460ba15acSDavid du Colombier if (drive->erasable == Yes)
23588a5d610SDavid du Colombier rw = drive->mmctype == Mmcbd? "re": "rw";
23660ba15acSDavid du Colombier else if (drive->recordable == Yes)
237079e489fSDavid du Colombier rw = "r";
238079e489fSDavid du Colombier else
239079e489fSDavid du Colombier rw = "rom";
240*889a2622SDavid du Colombier return smprint("%s%s%s", type, rw, laysfx);
241079e489fSDavid du Colombier }
242079e489fSDavid du Colombier
2437dd7cddfSDavid du Colombier int
fillstat(ulong qid,Dir * d)2449a747e4fSDavid du Colombier fillstat(ulong qid, Dir *d)
2457dd7cddfSDavid du Colombier {
246079e489fSDavid du Colombier char *ty;
2477dd7cddfSDavid du Colombier Track *t;
248079e489fSDavid du Colombier static char buf[32];
2497dd7cddfSDavid du Colombier
250e67f3b95SDavid du Colombier nulldir(d);
251e67f3b95SDavid du Colombier d->type = L'M';
252e67f3b95SDavid du Colombier d->dev = 1;
253e67f3b95SDavid du Colombier d->length = 0;
254079e489fSDavid du Colombier ty = disctype(drive);
255079e489fSDavid du Colombier strncpy(buf, ty, sizeof buf);
256079e489fSDavid du Colombier free(ty);
257079e489fSDavid du Colombier d->uid = d->gid = buf;
2589a747e4fSDavid du Colombier d->muid = "";
2599a747e4fSDavid du Colombier d->qid = (Qid){qid, drive->nchange, 0};
2607dd7cddfSDavid du Colombier d->atime = time(0);
261e67f3b95SDavid du Colombier d->mtime = drive->changetime;
2627dd7cddfSDavid du Colombier
2637dd7cddfSDavid du Colombier switch(qid){
2647dd7cddfSDavid du Colombier case Qdir:
2659a747e4fSDavid du Colombier d->name = "/";
2669a747e4fSDavid du Colombier d->qid.type = QTDIR;
2679a747e4fSDavid du Colombier d->mode = DMDIR|0777;
2687dd7cddfSDavid du Colombier break;
2697dd7cddfSDavid du Colombier
2707dd7cddfSDavid du Colombier case Qctl:
2719a747e4fSDavid du Colombier d->name = "ctl";
2727dd7cddfSDavid du Colombier d->mode = 0666;
2737dd7cddfSDavid du Colombier break;
2747dd7cddfSDavid du Colombier
2757dd7cddfSDavid du Colombier case Qwa:
27660ba15acSDavid du Colombier if(drive->writeok == No ||
277cdf9e71cSDavid du Colombier drive->mmctype != Mmcnone &&
278cdf9e71cSDavid du Colombier drive->mmctype != Mmccd)
2797dd7cddfSDavid du Colombier return 0;
2809a747e4fSDavid du Colombier d->name = "wa";
2819a747e4fSDavid du Colombier d->qid.type = QTDIR;
2829a747e4fSDavid du Colombier d->mode = DMDIR|0777;
2837dd7cddfSDavid du Colombier break;
2847dd7cddfSDavid du Colombier
2857dd7cddfSDavid du Colombier case Qwd:
28660ba15acSDavid du Colombier if(drive->writeok == No)
2877dd7cddfSDavid du Colombier return 0;
2889a747e4fSDavid du Colombier d->name = "wd";
2899a747e4fSDavid du Colombier d->qid.type = QTDIR;
2909a747e4fSDavid du Colombier d->mode = DMDIR|0777;
2917dd7cddfSDavid du Colombier break;
2927dd7cddfSDavid du Colombier
2937dd7cddfSDavid du Colombier default:
2947dd7cddfSDavid du Colombier if(qid-Qtrack >= drive->ntrack)
2957dd7cddfSDavid du Colombier return 0;
2967dd7cddfSDavid du Colombier t = &drive->track[qid-Qtrack];
2977dd7cddfSDavid du Colombier if(strcmp(t->name, "") == 0)
2987dd7cddfSDavid du Colombier return 0;
2999a747e4fSDavid du Colombier d->name = t->name;
3007dd7cddfSDavid du Colombier d->mode = t->mode;
3017dd7cddfSDavid du Colombier d->length = t->size;
3027dd7cddfSDavid du Colombier break;
3037dd7cddfSDavid du Colombier }
3047dd7cddfSDavid du Colombier return 1;
3057dd7cddfSDavid du Colombier }
3067dd7cddfSDavid du Colombier
3079a747e4fSDavid du Colombier static ulong
cddb_sum(int n)3089a747e4fSDavid du Colombier cddb_sum(int n)
3097dd7cddfSDavid du Colombier {
3109a747e4fSDavid du Colombier int ret;
3119a747e4fSDavid du Colombier ret = 0;
3129a747e4fSDavid du Colombier while(n > 0) {
3139a747e4fSDavid du Colombier ret += n%10;
3149a747e4fSDavid du Colombier n /= 10;
3159a747e4fSDavid du Colombier }
3169a747e4fSDavid du Colombier return ret;
3179a747e4fSDavid du Colombier }
3189a747e4fSDavid du Colombier
3199a747e4fSDavid du Colombier static ulong
diskid(Drive * d)3209a747e4fSDavid du Colombier diskid(Drive *d)
3219a747e4fSDavid du Colombier {
3229a747e4fSDavid du Colombier int i, n;
3239a747e4fSDavid du Colombier ulong tmp;
3249a747e4fSDavid du Colombier Msf *ms, *me;
3259a747e4fSDavid du Colombier
3269a747e4fSDavid du Colombier n = 0;
3279a747e4fSDavid du Colombier for(i=0; i < d->ntrack; i++)
3289a747e4fSDavid du Colombier n += cddb_sum(d->track[i].mbeg.m*60+d->track[i].mbeg.s);
3299a747e4fSDavid du Colombier
3309a747e4fSDavid du Colombier ms = &d->track[0].mbeg;
3319a747e4fSDavid du Colombier me = &d->track[d->ntrack].mbeg;
3329a747e4fSDavid du Colombier tmp = (me->m*60+me->s) - (ms->m*60+ms->s);
3339a747e4fSDavid du Colombier
3349a747e4fSDavid du Colombier /*
3358ad6bb6aSDavid du Colombier * the spec says n%0xFF rather than n&0xFF. it's unclear which is
3368ad6bb6aSDavid du Colombier * correct. most CDs are in the database under both entries.
3379a747e4fSDavid du Colombier */
3389a747e4fSDavid du Colombier return ((n % 0xFF) << 24 | (tmp << 8) | d->ntrack);
3397dd7cddfSDavid du Colombier }
3407dd7cddfSDavid du Colombier
3417dd7cddfSDavid du Colombier static void
readctl(Req * r)3429a747e4fSDavid du Colombier readctl(Req *r)
3437dd7cddfSDavid du Colombier {
3449a747e4fSDavid du Colombier int i, isaudio;
345801be386SDavid du Colombier ulong nwa;
346079e489fSDavid du Colombier char *p, *e, *ty;
3479a747e4fSDavid du Colombier char s[1024];
3489a747e4fSDavid du Colombier Msf *m;
3497dd7cddfSDavid du Colombier
3509a747e4fSDavid du Colombier isaudio = 0;
3519a747e4fSDavid du Colombier for(i=0; i<drive->ntrack; i++)
3529a747e4fSDavid du Colombier if(drive->track[i].type == TypeAudio)
3539a747e4fSDavid du Colombier isaudio = 1;
3549a747e4fSDavid du Colombier
3558ad6bb6aSDavid du Colombier p = s;
3568ad6bb6aSDavid du Colombier e = s + sizeof s;
3578ad6bb6aSDavid du Colombier *p = '\0';
3589a747e4fSDavid du Colombier if(isaudio){
3598ad6bb6aSDavid du Colombier p = seprint(p, e, "aux/cddb query %8.8lux %d", diskid(drive),
3608ad6bb6aSDavid du Colombier drive->ntrack);
3619a747e4fSDavid du Colombier for(i=0; i<drive->ntrack; i++){
3629a747e4fSDavid du Colombier m = &drive->track[i].mbeg;
3638ad6bb6aSDavid du Colombier p = seprint(p, e, " %d", (m->m*60 + m->s)*75 + m->f);
3649a747e4fSDavid du Colombier }
3659a747e4fSDavid du Colombier m = &drive->track[drive->ntrack].mbeg;
3668ad6bb6aSDavid du Colombier p = seprint(p, e, " %d\n", m->m*60 + m->s);
3679a747e4fSDavid du Colombier }
3689a747e4fSDavid du Colombier
3699a747e4fSDavid du Colombier if(drive->readspeed == drive->writespeed)
3708ad6bb6aSDavid du Colombier p = seprint(p, e, "speed %d\n", drive->readspeed);
3719a747e4fSDavid du Colombier else
3728ad6bb6aSDavid du Colombier p = seprint(p, e, "speed read %d write %d\n",
373cdf9e71cSDavid du Colombier drive->readspeed, drive->writespeed);
3748ad6bb6aSDavid du Colombier p = seprint(p, e, "maxspeed read %d write %d\n",
375cdf9e71cSDavid du Colombier drive->maxreadspeed, drive->maxwritespeed);
3768ad6bb6aSDavid du Colombier
3778ad6bb6aSDavid du Colombier if (drive->Scsi.changetime != 0 && drive->ntrack != 0) { /* have disc? */
378079e489fSDavid du Colombier ty = disctype(drive);
379079e489fSDavid du Colombier p = seprint(p, e, "%s", ty);
380079e489fSDavid du Colombier free(ty);
381801be386SDavid du Colombier if (drive->mmctype != Mmcnone) {
382801be386SDavid du Colombier nwa = getnwa(drive);
383801be386SDavid du Colombier p = seprint(p, e, " next writable sector ");
384801be386SDavid du Colombier if (nwa == ~0ul)
385801be386SDavid du Colombier p = seprint(p, e, "none; disc full");
386801be386SDavid du Colombier else
387801be386SDavid du Colombier p = seprint(p, e, "%lud", nwa);
388801be386SDavid du Colombier }
3898ad6bb6aSDavid du Colombier seprint(p, e, "\n");
3908ad6bb6aSDavid du Colombier }
3919a747e4fSDavid du Colombier readstr(r, s);
3929a747e4fSDavid du Colombier }
3939a747e4fSDavid du Colombier
3949a747e4fSDavid du Colombier static void
fsread(Req * r)3959a747e4fSDavid du Colombier fsread(Req *r)
3969a747e4fSDavid du Colombier {
3979a747e4fSDavid du Colombier int j, n, m;
3989a747e4fSDavid du Colombier uchar *p, *ep;
3999a747e4fSDavid du Colombier Dir d;
4009a747e4fSDavid du Colombier Fid *fid;
4019a747e4fSDavid du Colombier Otrack *o;
4029a747e4fSDavid du Colombier vlong offset;
4039a747e4fSDavid du Colombier void *buf;
4049a747e4fSDavid du Colombier long count;
4059a747e4fSDavid du Colombier Aux *a;
4069a747e4fSDavid du Colombier
4079a747e4fSDavid du Colombier fid = r->fid;
4089a747e4fSDavid du Colombier offset = r->ifcall.offset;
4099a747e4fSDavid du Colombier buf = r->ofcall.data;
4109a747e4fSDavid du Colombier count = r->ifcall.count;
4119a747e4fSDavid du Colombier
4129a747e4fSDavid du Colombier switch((ulong)fid->qid.path) {
4137dd7cddfSDavid du Colombier case Qdir:
4147dd7cddfSDavid du Colombier checktoc(drive);
4157dd7cddfSDavid du Colombier p = buf;
4169a747e4fSDavid du Colombier ep = p+count;
4177dd7cddfSDavid du Colombier m = Qtrack+drive->ntrack;
4189a747e4fSDavid du Colombier a = fid->aux;
4199a747e4fSDavid du Colombier if(offset == 0)
4209a747e4fSDavid du Colombier a->doff = 1; /* skip root */
4219a747e4fSDavid du Colombier
4229a747e4fSDavid du Colombier for(j=a->doff; j<m; j++) {
4237dd7cddfSDavid du Colombier if(fillstat(j, &d)) {
4249a747e4fSDavid du Colombier if((n = convD2M(&d, p, ep-p)) <= BIT16SZ)
4259a747e4fSDavid du Colombier break;
4269a747e4fSDavid du Colombier p += n;
4277dd7cddfSDavid du Colombier }
4287dd7cddfSDavid du Colombier }
4299a747e4fSDavid du Colombier a->doff = j;
4309a747e4fSDavid du Colombier
4319a747e4fSDavid du Colombier r->ofcall.count = p - (uchar*)buf;
432cdf9e71cSDavid du Colombier break;
4337dd7cddfSDavid du Colombier case Qwa:
4347dd7cddfSDavid du Colombier case Qwd:
4359a747e4fSDavid du Colombier r->ofcall.count = 0;
436cdf9e71cSDavid du Colombier break;
4377dd7cddfSDavid du Colombier case Qctl:
4389a747e4fSDavid du Colombier readctl(r);
439cdf9e71cSDavid du Colombier break;
440cdf9e71cSDavid du Colombier default:
4417dd7cddfSDavid du Colombier /* a disk track; we can only call read for whole blocks */
4429a747e4fSDavid du Colombier o = ((Aux*)fid->aux)->o;
443cdf9e71cSDavid du Colombier if((count = o->drive->read(o, buf, count, offset)) < 0) {
4447dd7cddfSDavid du Colombier respond(r, geterrstr());
445cdf9e71cSDavid du Colombier return;
4469a747e4fSDavid du Colombier }
447cdf9e71cSDavid du Colombier r->ofcall.count = count;
448cdf9e71cSDavid du Colombier break;
449cdf9e71cSDavid du Colombier }
450cdf9e71cSDavid du Colombier respond(r, nil);
4517dd7cddfSDavid du Colombier }
4527dd7cddfSDavid du Colombier
453055c7668SDavid du Colombier static char Ebadmsg[] = "bad cdfs control message";
454c038c065SDavid du Colombier
4557dd7cddfSDavid du Colombier static char*
writectl(void * v,long count)4567dd7cddfSDavid du Colombier writectl(void *v, long count)
4577dd7cddfSDavid du Colombier {
4587dd7cddfSDavid du Colombier char buf[256];
4599a747e4fSDavid du Colombier char *f[10], *p;
4609a747e4fSDavid du Colombier int i, nf, n, r, w, what;
4617dd7cddfSDavid du Colombier
4627dd7cddfSDavid du Colombier if(count >= sizeof(buf))
4637dd7cddfSDavid du Colombier count = sizeof(buf)-1;
4647dd7cddfSDavid du Colombier memmove(buf, v, count);
4657dd7cddfSDavid du Colombier buf[count] = '\0';
4667dd7cddfSDavid du Colombier
4677dd7cddfSDavid du Colombier nf = tokenize(buf, f, nelem(f));
4689a747e4fSDavid du Colombier if(nf == 0)
4699a747e4fSDavid du Colombier return Ebadmsg;
4709a747e4fSDavid du Colombier
4719a747e4fSDavid du Colombier if(strcmp(f[0], "speed") == 0){
4729a747e4fSDavid du Colombier what = 0;
4739a747e4fSDavid du Colombier r = w = -1;
4749a747e4fSDavid du Colombier if(nf == 1)
4759a747e4fSDavid du Colombier return Ebadmsg;
4769a747e4fSDavid du Colombier for(i=1; i<nf; i++){
4779a747e4fSDavid du Colombier if(strcmp(f[i], "read") == 0 || strcmp(f[i], "write") == 0){
4789a747e4fSDavid du Colombier if(what!=0 && what!='?')
4799a747e4fSDavid du Colombier return Ebadmsg;
4809a747e4fSDavid du Colombier what = f[i][0];
4819a747e4fSDavid du Colombier }else{
482055c7668SDavid du Colombier if (strcmp(f[i], "best") == 0)
483055c7668SDavid du Colombier n = (1<<16) - 1;
484055c7668SDavid du Colombier else {
4859a747e4fSDavid du Colombier n = strtol(f[i], &p, 0);
4869a747e4fSDavid du Colombier if(*p != '\0' || n <= 0)
4879a747e4fSDavid du Colombier return Ebadmsg;
488055c7668SDavid du Colombier }
4899a747e4fSDavid du Colombier switch(what){
4909a747e4fSDavid du Colombier case 0:
4919a747e4fSDavid du Colombier if(r >= 0 || w >= 0)
4929a747e4fSDavid du Colombier return Ebadmsg;
4939a747e4fSDavid du Colombier r = w = n;
4949a747e4fSDavid du Colombier break;
4959a747e4fSDavid du Colombier case 'r':
4969a747e4fSDavid du Colombier if(r >= 0)
4979a747e4fSDavid du Colombier return Ebadmsg;
4989a747e4fSDavid du Colombier r = n;
4999a747e4fSDavid du Colombier break;
5009a747e4fSDavid du Colombier case 'w':
5019a747e4fSDavid du Colombier if(w >= 0)
5029a747e4fSDavid du Colombier return Ebadmsg;
5039a747e4fSDavid du Colombier w = n;
5049a747e4fSDavid du Colombier break;
5059a747e4fSDavid du Colombier default:
5069a747e4fSDavid du Colombier return Ebadmsg;
5079a747e4fSDavid du Colombier }
508cdf9e71cSDavid du Colombier what = '?';
5099a747e4fSDavid du Colombier }
5109a747e4fSDavid du Colombier }
5119a747e4fSDavid du Colombier if(what != '?')
5129a747e4fSDavid du Colombier return Ebadmsg;
5139a747e4fSDavid du Colombier return drive->setspeed(drive, r, w);
5149a747e4fSDavid du Colombier }
5157dd7cddfSDavid du Colombier return drive->ctl(drive, nf, f);
5167dd7cddfSDavid du Colombier }
5177dd7cddfSDavid du Colombier
5187dd7cddfSDavid du Colombier static void
fswrite(Req * r)5199a747e4fSDavid du Colombier fswrite(Req *r)
5207dd7cddfSDavid du Colombier {
5217dd7cddfSDavid du Colombier Otrack *o;
5229a747e4fSDavid du Colombier Fid *fid;
5237dd7cddfSDavid du Colombier
5249a747e4fSDavid du Colombier fid = r->fid;
5259a747e4fSDavid du Colombier r->ofcall.count = r->ifcall.count;
5267dd7cddfSDavid du Colombier if(fid->qid.path == Qctl) {
5279a747e4fSDavid du Colombier respond(r, writectl(r->ifcall.data, r->ifcall.count));
5287dd7cddfSDavid du Colombier return;
5297dd7cddfSDavid du Colombier }
5307dd7cddfSDavid du Colombier
5319a747e4fSDavid du Colombier if((o = ((Aux*)fid->aux)->o) == nil || o->omode != OWRITE) {
5327dd7cddfSDavid du Colombier respond(r, "permission denied");
5337dd7cddfSDavid du Colombier return;
5347dd7cddfSDavid du Colombier }
5357dd7cddfSDavid du Colombier
5369a747e4fSDavid du Colombier if(o->drive->write(o, r->ifcall.data, r->ifcall.count) < 0)
5377dd7cddfSDavid du Colombier respond(r, geterrstr());
5387dd7cddfSDavid du Colombier else
5397dd7cddfSDavid du Colombier respond(r, nil);
5407dd7cddfSDavid du Colombier }
5417dd7cddfSDavid du Colombier
5427dd7cddfSDavid du Colombier static void
fsstat(Req * r)5439a747e4fSDavid du Colombier fsstat(Req *r)
5447dd7cddfSDavid du Colombier {
5459a747e4fSDavid du Colombier fillstat((ulong)r->fid->qid.path, &r->d);
5469a747e4fSDavid du Colombier r->d.name = estrdup9p(r->d.name);
5479a747e4fSDavid du Colombier r->d.uid = estrdup9p(r->d.uid);
5489a747e4fSDavid du Colombier r->d.gid = estrdup9p(r->d.gid);
5499a747e4fSDavid du Colombier r->d.muid = estrdup9p(r->d.muid);
5507dd7cddfSDavid du Colombier respond(r, nil);
5517dd7cddfSDavid du Colombier }
5527dd7cddfSDavid du Colombier
5537dd7cddfSDavid du Colombier static void
fsopen(Req * r)5549a747e4fSDavid du Colombier fsopen(Req *r)
5557dd7cddfSDavid du Colombier {
5569a747e4fSDavid du Colombier int omode;
5579a747e4fSDavid du Colombier Fid *fid;
5587dd7cddfSDavid du Colombier Otrack *o;
5597dd7cddfSDavid du Colombier
5609a747e4fSDavid du Colombier fid = r->fid;
5619a747e4fSDavid du Colombier omode = r->ifcall.mode;
5627dd7cddfSDavid du Colombier checktoc(drive);
5639a747e4fSDavid du Colombier r->ofcall.qid = (Qid){fid->qid.path, drive->nchange, fid->qid.vers};
5647dd7cddfSDavid du Colombier
5659a747e4fSDavid du Colombier switch((ulong)fid->qid.path){
5667dd7cddfSDavid du Colombier case Qdir:
5677dd7cddfSDavid du Colombier case Qwa:
5687dd7cddfSDavid du Colombier case Qwd:
569cdf9e71cSDavid du Colombier if(omode != OREAD) {
5707dd7cddfSDavid du Colombier respond(r, "permission denied");
5717dd7cddfSDavid du Colombier return;
572cdf9e71cSDavid du Colombier }
573cdf9e71cSDavid du Colombier break;
5747dd7cddfSDavid du Colombier case Qctl:
575cdf9e71cSDavid du Colombier if(omode & ~(OTRUNC|OREAD|OWRITE|ORDWR)) {
5767dd7cddfSDavid du Colombier respond(r, "permission denied");
5777dd7cddfSDavid du Colombier return;
578cdf9e71cSDavid du Colombier }
579cdf9e71cSDavid du Colombier break;
5807dd7cddfSDavid du Colombier default:
5817dd7cddfSDavid du Colombier if(fid->qid.path >= Qtrack+drive->ntrack) {
5827dd7cddfSDavid du Colombier respond(r, "file no longer exists");
5837dd7cddfSDavid du Colombier return;
5847dd7cddfSDavid du Colombier }
5857dd7cddfSDavid du Colombier
586c038c065SDavid du Colombier /*
587c038c065SDavid du Colombier * allow the open with OWRITE or ORDWR if the
588c038c065SDavid du Colombier * drive and disc are both capable?
589c038c065SDavid du Colombier */
590c038c065SDavid du Colombier if(omode != OREAD ||
591c038c065SDavid du Colombier (o = drive->openrd(drive, fid->qid.path-Qtrack)) == nil) {
5927dd7cddfSDavid du Colombier respond(r, "permission denied");
5937dd7cddfSDavid du Colombier return;
5947dd7cddfSDavid du Colombier }
5957dd7cddfSDavid du Colombier
5967dd7cddfSDavid du Colombier o->nref = 1;
5979a747e4fSDavid du Colombier ((Aux*)fid->aux)->o = o;
598c038c065SDavid du Colombier break;
5997dd7cddfSDavid du Colombier }
600cdf9e71cSDavid du Colombier respond(r, nil);
6017dd7cddfSDavid du Colombier }
6027dd7cddfSDavid du Colombier
6037dd7cddfSDavid du Colombier static void
fsdestroyfid(Fid * fid)6049a747e4fSDavid du Colombier fsdestroyfid(Fid *fid)
6057dd7cddfSDavid du Colombier {
6069a747e4fSDavid du Colombier Aux *aux;
6077dd7cddfSDavid du Colombier Otrack *o;
6087dd7cddfSDavid du Colombier
6099a747e4fSDavid du Colombier aux = fid->aux;
6109a747e4fSDavid du Colombier if(aux == nil)
6119a747e4fSDavid du Colombier return;
6129a747e4fSDavid du Colombier o = aux->o;
6137dd7cddfSDavid du Colombier if(o && --o->nref == 0) {
6147dd7cddfSDavid du Colombier bterm(o->buf);
6157dd7cddfSDavid du Colombier drive->close(o);
6167dd7cddfSDavid du Colombier checktoc(drive);
6177dd7cddfSDavid du Colombier }
6187dd7cddfSDavid du Colombier }
6197dd7cddfSDavid du Colombier
6207dd7cddfSDavid du Colombier static void
checktoc(Drive * drive)6217dd7cddfSDavid du Colombier checktoc(Drive *drive)
6227dd7cddfSDavid du Colombier {
6237dd7cddfSDavid du Colombier int i;
6247dd7cddfSDavid du Colombier Track *t;
6257dd7cddfSDavid du Colombier
6267dd7cddfSDavid du Colombier drive->gettoc(drive);
6277dd7cddfSDavid du Colombier if(drive->nameok)
6287dd7cddfSDavid du Colombier return;
6297dd7cddfSDavid du Colombier
6307dd7cddfSDavid du Colombier for(i=0; i<drive->ntrack; i++) {
6317dd7cddfSDavid du Colombier t = &drive->track[i];
6327dd7cddfSDavid du Colombier if(t->size == 0) /* being created */
6337dd7cddfSDavid du Colombier t->mode = 0;
6347dd7cddfSDavid du Colombier else
6357dd7cddfSDavid du Colombier t->mode = 0444;
6367dd7cddfSDavid du Colombier sprint(t->name, "?%.3d", i);
6377dd7cddfSDavid du Colombier switch(t->type){
6387dd7cddfSDavid du Colombier case TypeNone:
6397dd7cddfSDavid du Colombier t->name[0] = 'u';
640e67f3b95SDavid du Colombier // t->mode = 0;
6417dd7cddfSDavid du Colombier break;
6427dd7cddfSDavid du Colombier case TypeData:
6437dd7cddfSDavid du Colombier t->name[0] = 'd';
6447dd7cddfSDavid du Colombier break;
6457dd7cddfSDavid du Colombier case TypeAudio:
6467dd7cddfSDavid du Colombier t->name[0] = 'a';
6477dd7cddfSDavid du Colombier break;
6487dd7cddfSDavid du Colombier case TypeBlank:
6497dd7cddfSDavid du Colombier t->name[0] = '\0';
6507dd7cddfSDavid du Colombier break;
6517dd7cddfSDavid du Colombier default:
652079e489fSDavid du Colombier print("unknown track type %d\n", t->type);
6537dd7cddfSDavid du Colombier break;
6547dd7cddfSDavid du Colombier }
6557dd7cddfSDavid du Colombier }
6567dd7cddfSDavid du Colombier
6577dd7cddfSDavid du Colombier drive->nameok = 1;
6587dd7cddfSDavid du Colombier }
6597dd7cddfSDavid du Colombier
6607dd7cddfSDavid du Colombier long
bufread(Otrack * t,void * v,long n,vlong off)661dd12a5c6SDavid du Colombier bufread(Otrack *t, void *v, long n, vlong off)
6627dd7cddfSDavid du Colombier {
6637dd7cddfSDavid du Colombier return bread(t->buf, v, n, off);
6647dd7cddfSDavid du Colombier }
6657dd7cddfSDavid du Colombier
6667dd7cddfSDavid du Colombier long
bufwrite(Otrack * t,void * v,long n)6677dd7cddfSDavid du Colombier bufwrite(Otrack *t, void *v, long n)
6687dd7cddfSDavid du Colombier {
6697dd7cddfSDavid du Colombier return bwrite(t->buf, v, n);
6707dd7cddfSDavid du Colombier }
6717dd7cddfSDavid du Colombier
6729a747e4fSDavid du Colombier Srv fs = {
6739a747e4fSDavid du Colombier .attach= fsattach,
6749a747e4fSDavid du Colombier .destroyfid= fsdestroyfid,
6759a747e4fSDavid du Colombier .clone= fsclone,
6769a747e4fSDavid du Colombier .walk1= fswalk1,
6779a747e4fSDavid du Colombier .open= fsopen,
6789a747e4fSDavid du Colombier .read= fsread,
6799a747e4fSDavid du Colombier .write= fswrite,
6809a747e4fSDavid du Colombier .create= fscreate,
6819a747e4fSDavid du Colombier .remove= fsremove,
6829a747e4fSDavid du Colombier .stat= fsstat,
6837dd7cddfSDavid du Colombier };
6847dd7cddfSDavid du Colombier
6857dd7cddfSDavid du Colombier void
usage(void)6867dd7cddfSDavid du Colombier usage(void)
6877dd7cddfSDavid du Colombier {
6889a747e4fSDavid du Colombier fprint(2, "usage: cdfs [-Dv] [-d /dev/sdC0] [-m mtpt]\n");
6897dd7cddfSDavid du Colombier exits("usage");
6907dd7cddfSDavid du Colombier }
6917dd7cddfSDavid du Colombier
6927dd7cddfSDavid du Colombier void
main(int argc,char ** argv)6937dd7cddfSDavid du Colombier main(int argc, char **argv)
6947dd7cddfSDavid du Colombier {
6957dd7cddfSDavid du Colombier Scsi *s;
6967dd7cddfSDavid du Colombier int fd;
6977dd7cddfSDavid du Colombier char *dev, *mtpt;
6987dd7cddfSDavid du Colombier
6997dd7cddfSDavid du Colombier dev = "/dev/sdD0";
7007dd7cddfSDavid du Colombier mtpt = "/mnt/cd";
7017dd7cddfSDavid du Colombier
7027dd7cddfSDavid du Colombier ARGBEGIN{
7039a747e4fSDavid du Colombier case 'D':
7049a747e4fSDavid du Colombier chatty9p++;
7059a747e4fSDavid du Colombier break;
7067dd7cddfSDavid du Colombier case 'd':
707e67f3b95SDavid du Colombier dev = EARGF(usage());
7087dd7cddfSDavid du Colombier break;
7097dd7cddfSDavid du Colombier case 'm':
710e67f3b95SDavid du Colombier mtpt = EARGF(usage());
7117dd7cddfSDavid du Colombier break;
7127dd7cddfSDavid du Colombier case 'v':
7137dd7cddfSDavid du Colombier if((fd = create("/tmp/cdfs.log", OWRITE, 0666)) >= 0) {
7147dd7cddfSDavid du Colombier dup(fd, 2);
7157dd7cddfSDavid du Colombier dup(fd, 1);
7167dd7cddfSDavid du Colombier if(fd != 1 && fd != 2)
7177dd7cddfSDavid du Colombier close(fd);
7187dd7cddfSDavid du Colombier vflag++;
719436f307dSDavid du Colombier scsiverbose = 2; /* verbose but no Readtoc errs */
720*889a2622SDavid du Colombier } else
721*889a2622SDavid du Colombier fprint(2, "%s: can't open /tmp/cdfs.log: %r\n", argv0);
7227dd7cddfSDavid du Colombier break;
7237dd7cddfSDavid du Colombier default:
7247dd7cddfSDavid du Colombier usage();
7257dd7cddfSDavid du Colombier }ARGEND
7267dd7cddfSDavid du Colombier
7277dd7cddfSDavid du Colombier if(dev == nil || mtpt == nil || argc > 0)
7287dd7cddfSDavid du Colombier usage();
7297dd7cddfSDavid du Colombier
7302112d02cSDavid du Colombier werrstr("");
731c038c065SDavid du Colombier if((s = openscsi(dev)) == nil)
732c038c065SDavid du Colombier sysfatal("openscsi '%s': %r", dev);
733c038c065SDavid du Colombier if((drive = mmcprobe(s)) == nil)
734c038c065SDavid du Colombier sysfatal("mmcprobe '%s': %r", dev);
7357dd7cddfSDavid du Colombier checktoc(drive);
7367dd7cddfSDavid du Colombier
7379a747e4fSDavid du Colombier postmountsrv(&fs, nil, mtpt, MREPL|MCREATE);
73880ee5cbfSDavid du Colombier exits(nil);
7397dd7cddfSDavid du Colombier }
740