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* 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* 4559cc4ca5SDavid du Colombier emalloc(ulong sz) 4659cc4ca5SDavid du Colombier { 4759cc4ca5SDavid du Colombier void *v; 4859cc4ca5SDavid du Colombier 4959cc4ca5SDavid du Colombier v = malloc(sz); 5059cc4ca5SDavid du Colombier if(v == nil) 5159cc4ca5SDavid du Colombier sysfatal("malloc %lud fails\n", sz); 5259cc4ca5SDavid du Colombier memset(v, 0, sz); 5359cc4ca5SDavid du Colombier return v; 5459cc4ca5SDavid du Colombier } 5559cc4ca5SDavid du Colombier 567dd7cddfSDavid du Colombier static void 579a747e4fSDavid du Colombier fsattach(Req *r) 587dd7cddfSDavid du Colombier { 599a747e4fSDavid du Colombier char *spec; 609a747e4fSDavid du Colombier 619a747e4fSDavid du Colombier spec = r->ifcall.aname; 627dd7cddfSDavid du Colombier if(spec && spec[0]) { 637dd7cddfSDavid du Colombier respond(r, "invalid attach specifier"); 647dd7cddfSDavid du Colombier return; 657dd7cddfSDavid du Colombier } 667dd7cddfSDavid du Colombier 677dd7cddfSDavid du Colombier checktoc(drive); 689a747e4fSDavid du Colombier r->fid->qid = (Qid){Qdir, drive->nchange, QTDIR}; 699a747e4fSDavid du Colombier r->ofcall.qid = r->fid->qid; 709a747e4fSDavid du Colombier r->fid->aux = emalloc(sizeof(Aux)); 717dd7cddfSDavid du Colombier respond(r, nil); 727dd7cddfSDavid du Colombier } 737dd7cddfSDavid du Colombier 749a747e4fSDavid du Colombier static char* 759a747e4fSDavid du Colombier fsclone(Fid *old, Fid *new) 767dd7cddfSDavid du Colombier { 779a747e4fSDavid du Colombier Aux *na; 787dd7cddfSDavid du Colombier 799a747e4fSDavid du Colombier na = emalloc(sizeof(Aux)); 809a747e4fSDavid du Colombier *na = *((Aux*)old->aux); 819a747e4fSDavid du Colombier if(na->o) 829a747e4fSDavid du Colombier na->o->nref++; 839a747e4fSDavid du Colombier new->aux = na; 849a747e4fSDavid du Colombier return nil; 857dd7cddfSDavid du Colombier } 867dd7cddfSDavid du Colombier 879a747e4fSDavid du Colombier static char* 889a747e4fSDavid du Colombier fswalk1(Fid *fid, char *name, Qid *qid) 897dd7cddfSDavid du Colombier { 907dd7cddfSDavid du Colombier int i; 917dd7cddfSDavid du Colombier 927dd7cddfSDavid du Colombier checktoc(drive); 939a747e4fSDavid du Colombier switch((ulong)fid->qid.path) { 947dd7cddfSDavid du Colombier case Qdir: 957dd7cddfSDavid du Colombier if(strcmp(name, "..") == 0) { 969a747e4fSDavid du Colombier *qid = (Qid){Qdir, drive->nchange, QTDIR}; 979a747e4fSDavid du Colombier return nil; 987dd7cddfSDavid du Colombier } 997dd7cddfSDavid du Colombier if(strcmp(name, "ctl") == 0) { 1009a747e4fSDavid du Colombier *qid = (Qid){Qctl, 0, 0}; 1019a747e4fSDavid du Colombier return nil; 1027dd7cddfSDavid du Colombier } 103436f307dSDavid du Colombier if(strcmp(name, "wa") == 0 && drive->writeok && 104cdf9e71cSDavid du Colombier (drive->mmctype == Mmcnone || 105cdf9e71cSDavid du Colombier drive->mmctype == Mmccd)) { 1069a747e4fSDavid du Colombier *qid = (Qid){Qwa, drive->nchange, QTDIR}; 1079a747e4fSDavid du Colombier return nil; 1087dd7cddfSDavid du Colombier } 1097dd7cddfSDavid du Colombier if(strcmp(name, "wd") == 0 && drive->writeok) { 1109a747e4fSDavid du Colombier *qid = (Qid){Qwd, drive->nchange, QTDIR}; 1119a747e4fSDavid du Colombier return nil; 1127dd7cddfSDavid du Colombier } 1137dd7cddfSDavid du Colombier for(i=0; i<drive->ntrack; i++) 1147dd7cddfSDavid du Colombier if(strcmp(drive->track[i].name, name) == 0) 1157dd7cddfSDavid du Colombier break; 1168ad6bb6aSDavid du Colombier if(i == drive->ntrack) 1179a747e4fSDavid du Colombier return "file not found"; 1189a747e4fSDavid du Colombier *qid = (Qid){Qtrack+i, 0, 0}; 1199a747e4fSDavid du Colombier return nil; 1207dd7cddfSDavid du Colombier 1217dd7cddfSDavid du Colombier case Qwa: 1227dd7cddfSDavid du Colombier case Qwd: 1237dd7cddfSDavid du Colombier if(strcmp(name, "..") == 0) { 1249a747e4fSDavid du Colombier *qid = (Qid){Qdir, drive->nchange, QTDIR}; 1259a747e4fSDavid du Colombier return nil; 1267dd7cddfSDavid du Colombier } 1279a747e4fSDavid du Colombier return "file not found"; 1287dd7cddfSDavid du Colombier default: /* bug: lib9p could handle this */ 1299a747e4fSDavid du Colombier return "walk in non-directory"; 1307dd7cddfSDavid du Colombier } 1317dd7cddfSDavid du Colombier } 1327dd7cddfSDavid du Colombier 1337dd7cddfSDavid du Colombier static void 1349a747e4fSDavid du Colombier fscreate(Req *r) 1357dd7cddfSDavid du Colombier { 1369a747e4fSDavid du Colombier int omode, type; 1377dd7cddfSDavid du Colombier Otrack *o; 1389a747e4fSDavid du Colombier Fid *fid; 1399a747e4fSDavid du Colombier 1409a747e4fSDavid du Colombier fid = r->fid; 1419a747e4fSDavid du Colombier omode = r->ifcall.mode; 1427dd7cddfSDavid du Colombier 1437dd7cddfSDavid du Colombier if(omode != OWRITE) { 1447dd7cddfSDavid du Colombier respond(r, "bad mode (use OWRITE)"); 1457dd7cddfSDavid du Colombier return; 1467dd7cddfSDavid du Colombier } 1477dd7cddfSDavid du Colombier 1489a747e4fSDavid du Colombier switch((ulong)fid->qid.path) { 1497dd7cddfSDavid du Colombier case Qdir: 1507dd7cddfSDavid du Colombier default: 1517dd7cddfSDavid du Colombier respond(r, "permission denied"); 1527dd7cddfSDavid du Colombier return; 1537dd7cddfSDavid du Colombier 1547dd7cddfSDavid du Colombier case Qwa: 155cdf9e71cSDavid du Colombier if (drive->mmctype != Mmcnone && 156cdf9e71cSDavid du Colombier drive->mmctype != Mmccd) { 157436f307dSDavid du Colombier respond(r, "audio supported only on cd"); 158436f307dSDavid du Colombier return; 159436f307dSDavid du Colombier } 1607dd7cddfSDavid du Colombier type = TypeAudio; 1617dd7cddfSDavid du Colombier break; 1627dd7cddfSDavid du Colombier 1637dd7cddfSDavid du Colombier case Qwd: 1647dd7cddfSDavid du Colombier type = TypeData; 1657dd7cddfSDavid du Colombier break; 1667dd7cddfSDavid du Colombier } 1677dd7cddfSDavid du Colombier 1687dd7cddfSDavid du Colombier if((drive->cap & Cwrite) == 0) { 1697dd7cddfSDavid du Colombier respond(r, "drive does not write"); 1707dd7cddfSDavid du Colombier return; 1717dd7cddfSDavid du Colombier } 1727dd7cddfSDavid du Colombier 1737dd7cddfSDavid du Colombier o = drive->create(drive, type); 1747dd7cddfSDavid du Colombier if(o == nil) { 1757dd7cddfSDavid du Colombier respond(r, geterrstr()); 1767dd7cddfSDavid du Colombier return; 1777dd7cddfSDavid du Colombier } 1787dd7cddfSDavid du Colombier drive->nchange = -1; 1797dd7cddfSDavid du Colombier checktoc(drive); /* update directory info */ 1807dd7cddfSDavid du Colombier o->nref = 1; 1819a747e4fSDavid du Colombier ((Aux*)fid->aux)->o = o; 1827dd7cddfSDavid du Colombier 1839a747e4fSDavid du Colombier fid->qid = (Qid){Qtrack+(o->track - drive->track), drive->nchange, 0}; 1849a747e4fSDavid du Colombier r->ofcall.qid = fid->qid; 1857dd7cddfSDavid du Colombier respond(r, nil); 1867dd7cddfSDavid du Colombier } 1877dd7cddfSDavid du Colombier 1887dd7cddfSDavid du Colombier static void 1899a747e4fSDavid du Colombier fsremove(Req *r) 1907dd7cddfSDavid du Colombier { 1919a747e4fSDavid du Colombier switch((ulong)r->fid->qid.path){ 1927dd7cddfSDavid du Colombier case Qwa: 1937dd7cddfSDavid du Colombier case Qwd: 1947dd7cddfSDavid du Colombier if(drive->fixate(drive) < 0) 1957dd7cddfSDavid du Colombier respond(r, geterrstr()); 1967dd7cddfSDavid du Colombier // let's see if it can figure this out drive->writeok = 0; 1977dd7cddfSDavid du Colombier else 1987dd7cddfSDavid du Colombier respond(r, nil); 1997dd7cddfSDavid du Colombier checktoc(drive); 2007dd7cddfSDavid du Colombier break; 2017dd7cddfSDavid du Colombier default: 2027dd7cddfSDavid du Colombier respond(r, "permission denied"); 2037dd7cddfSDavid du Colombier break; 2047dd7cddfSDavid du Colombier } 2057dd7cddfSDavid du Colombier } 2067dd7cddfSDavid du Colombier 207*079e489fSDavid du Colombier static char * 208*079e489fSDavid du Colombier disctype(Drive *drive) 209*079e489fSDavid du Colombier { 210*079e489fSDavid du Colombier char *type, *rw; 211*079e489fSDavid du Colombier 212*079e489fSDavid du Colombier switch (drive->mmctype) { 213*079e489fSDavid du Colombier case Mmccd: 214*079e489fSDavid du Colombier type = "cd-"; 215*079e489fSDavid du Colombier break; 216*079e489fSDavid du Colombier case Mmcdvdminus: 217*079e489fSDavid du Colombier case Mmcdvdplus: 218*079e489fSDavid du Colombier type = drive->dvdtype; 219*079e489fSDavid du Colombier break; 220*079e489fSDavid du Colombier case Mmcbd: 221*079e489fSDavid du Colombier type = "bd-"; 222*079e489fSDavid du Colombier break; 223*079e489fSDavid du Colombier case Mmcnone: 224*079e489fSDavid du Colombier type = "no disc"; 225*079e489fSDavid du Colombier break; 226*079e489fSDavid du Colombier default: 227*079e489fSDavid du Colombier type = "**GOK**"; /* traditional */ 228*079e489fSDavid du Colombier break; 229*079e489fSDavid du Colombier } 230*079e489fSDavid du Colombier rw = ""; 231*079e489fSDavid du Colombier if (drive->mmctype != Mmcnone && drive->dvdtype == nil) 232*079e489fSDavid du Colombier if (drive->erasable) 233*079e489fSDavid du Colombier rw = "rw"; 234*079e489fSDavid du Colombier else if (drive->recordable) 235*079e489fSDavid du Colombier rw = "r"; 236*079e489fSDavid du Colombier else 237*079e489fSDavid du Colombier rw = "rom"; 238*079e489fSDavid du Colombier return smprint("%s%s", type, rw); 239*079e489fSDavid du Colombier } 240*079e489fSDavid du Colombier 2417dd7cddfSDavid du Colombier int 2429a747e4fSDavid du Colombier fillstat(ulong qid, Dir *d) 2437dd7cddfSDavid du Colombier { 244*079e489fSDavid du Colombier char *ty; 2457dd7cddfSDavid du Colombier Track *t; 246*079e489fSDavid du Colombier static char buf[32]; 2477dd7cddfSDavid du Colombier 248e67f3b95SDavid du Colombier nulldir(d); 249e67f3b95SDavid du Colombier d->type = L'M'; 250e67f3b95SDavid du Colombier d->dev = 1; 251e67f3b95SDavid du Colombier d->length = 0; 252*079e489fSDavid du Colombier ty = disctype(drive); 253*079e489fSDavid du Colombier strncpy(buf, ty, sizeof buf); 254*079e489fSDavid du Colombier free(ty); 255*079e489fSDavid du Colombier d->uid = d->gid = buf; 2569a747e4fSDavid du Colombier d->muid = ""; 2579a747e4fSDavid du Colombier d->qid = (Qid){qid, drive->nchange, 0}; 2587dd7cddfSDavid du Colombier d->atime = time(0); 259e67f3b95SDavid du Colombier d->mtime = drive->changetime; 2607dd7cddfSDavid du Colombier 2617dd7cddfSDavid du Colombier switch(qid){ 2627dd7cddfSDavid du Colombier case Qdir: 2639a747e4fSDavid du Colombier d->name = "/"; 2649a747e4fSDavid du Colombier d->qid.type = QTDIR; 2659a747e4fSDavid du Colombier d->mode = DMDIR|0777; 2667dd7cddfSDavid du Colombier break; 2677dd7cddfSDavid du Colombier 2687dd7cddfSDavid du Colombier case Qctl: 2699a747e4fSDavid du Colombier d->name = "ctl"; 2707dd7cddfSDavid du Colombier d->mode = 0666; 2717dd7cddfSDavid du Colombier break; 2727dd7cddfSDavid du Colombier 2737dd7cddfSDavid du Colombier case Qwa: 274436f307dSDavid du Colombier if(drive->writeok == 0 || 275cdf9e71cSDavid du Colombier drive->mmctype != Mmcnone && 276cdf9e71cSDavid du Colombier drive->mmctype != Mmccd) 2777dd7cddfSDavid du Colombier return 0; 2789a747e4fSDavid du Colombier d->name = "wa"; 2799a747e4fSDavid du Colombier d->qid.type = QTDIR; 2809a747e4fSDavid du Colombier d->mode = DMDIR|0777; 2817dd7cddfSDavid du Colombier break; 2827dd7cddfSDavid du Colombier 2837dd7cddfSDavid du Colombier case Qwd: 2847dd7cddfSDavid du Colombier if(drive->writeok == 0) 2857dd7cddfSDavid du Colombier return 0; 2869a747e4fSDavid du Colombier d->name = "wd"; 2879a747e4fSDavid du Colombier d->qid.type = QTDIR; 2889a747e4fSDavid du Colombier d->mode = DMDIR|0777; 2897dd7cddfSDavid du Colombier break; 2907dd7cddfSDavid du Colombier 2917dd7cddfSDavid du Colombier default: 2927dd7cddfSDavid du Colombier if(qid-Qtrack >= drive->ntrack) 2937dd7cddfSDavid du Colombier return 0; 2947dd7cddfSDavid du Colombier t = &drive->track[qid-Qtrack]; 2957dd7cddfSDavid du Colombier if(strcmp(t->name, "") == 0) 2967dd7cddfSDavid du Colombier return 0; 2979a747e4fSDavid du Colombier d->name = t->name; 2987dd7cddfSDavid du Colombier d->mode = t->mode; 2997dd7cddfSDavid du Colombier d->length = t->size; 3007dd7cddfSDavid du Colombier break; 3017dd7cddfSDavid du Colombier } 3027dd7cddfSDavid du Colombier return 1; 3037dd7cddfSDavid du Colombier } 3047dd7cddfSDavid du Colombier 3059a747e4fSDavid du Colombier static ulong 3069a747e4fSDavid du Colombier cddb_sum(int n) 3077dd7cddfSDavid du Colombier { 3089a747e4fSDavid du Colombier int ret; 3099a747e4fSDavid du Colombier ret = 0; 3109a747e4fSDavid du Colombier while(n > 0) { 3119a747e4fSDavid du Colombier ret += n%10; 3129a747e4fSDavid du Colombier n /= 10; 3139a747e4fSDavid du Colombier } 3149a747e4fSDavid du Colombier return ret; 3159a747e4fSDavid du Colombier } 3169a747e4fSDavid du Colombier 3179a747e4fSDavid du Colombier static ulong 3189a747e4fSDavid du Colombier diskid(Drive *d) 3199a747e4fSDavid du Colombier { 3209a747e4fSDavid du Colombier int i, n; 3219a747e4fSDavid du Colombier ulong tmp; 3229a747e4fSDavid du Colombier Msf *ms, *me; 3239a747e4fSDavid du Colombier 3249a747e4fSDavid du Colombier n = 0; 3259a747e4fSDavid du Colombier for(i=0; i < d->ntrack; i++) 3269a747e4fSDavid du Colombier n += cddb_sum(d->track[i].mbeg.m*60+d->track[i].mbeg.s); 3279a747e4fSDavid du Colombier 3289a747e4fSDavid du Colombier ms = &d->track[0].mbeg; 3299a747e4fSDavid du Colombier me = &d->track[d->ntrack].mbeg; 3309a747e4fSDavid du Colombier tmp = (me->m*60+me->s) - (ms->m*60+ms->s); 3319a747e4fSDavid du Colombier 3329a747e4fSDavid du Colombier /* 3338ad6bb6aSDavid du Colombier * the spec says n%0xFF rather than n&0xFF. it's unclear which is 3348ad6bb6aSDavid du Colombier * correct. most CDs are in the database under both entries. 3359a747e4fSDavid du Colombier */ 3369a747e4fSDavid du Colombier return ((n % 0xFF) << 24 | (tmp << 8) | d->ntrack); 3377dd7cddfSDavid du Colombier } 3387dd7cddfSDavid du Colombier 3397dd7cddfSDavid du Colombier static void 3409a747e4fSDavid du Colombier readctl(Req *r) 3417dd7cddfSDavid du Colombier { 3429a747e4fSDavid du Colombier int i, isaudio; 343*079e489fSDavid du Colombier char *p, *e, *ty; 3449a747e4fSDavid du Colombier char s[1024]; 3459a747e4fSDavid du Colombier Msf *m; 3467dd7cddfSDavid du Colombier 3479a747e4fSDavid du Colombier isaudio = 0; 3489a747e4fSDavid du Colombier for(i=0; i<drive->ntrack; i++) 3499a747e4fSDavid du Colombier if(drive->track[i].type == TypeAudio) 3509a747e4fSDavid du Colombier isaudio = 1; 3519a747e4fSDavid du Colombier 3528ad6bb6aSDavid du Colombier p = s; 3538ad6bb6aSDavid du Colombier e = s + sizeof s; 3548ad6bb6aSDavid du Colombier *p = '\0'; 3559a747e4fSDavid du Colombier if(isaudio){ 3568ad6bb6aSDavid du Colombier p = seprint(p, e, "aux/cddb query %8.8lux %d", diskid(drive), 3578ad6bb6aSDavid du Colombier drive->ntrack); 3589a747e4fSDavid du Colombier for(i=0; i<drive->ntrack; i++){ 3599a747e4fSDavid du Colombier m = &drive->track[i].mbeg; 3608ad6bb6aSDavid du Colombier p = seprint(p, e, " %d", (m->m*60 + m->s)*75 + m->f); 3619a747e4fSDavid du Colombier } 3629a747e4fSDavid du Colombier m = &drive->track[drive->ntrack].mbeg; 3638ad6bb6aSDavid du Colombier p = seprint(p, e, " %d\n", m->m*60 + m->s); 3649a747e4fSDavid du Colombier } 3659a747e4fSDavid du Colombier 3669a747e4fSDavid du Colombier if(drive->readspeed == drive->writespeed) 3678ad6bb6aSDavid du Colombier p = seprint(p, e, "speed %d\n", drive->readspeed); 3689a747e4fSDavid du Colombier else 3698ad6bb6aSDavid du Colombier p = seprint(p, e, "speed read %d write %d\n", 370cdf9e71cSDavid du Colombier drive->readspeed, drive->writespeed); 3718ad6bb6aSDavid du Colombier p = seprint(p, e, "maxspeed read %d write %d\n", 372cdf9e71cSDavid du Colombier drive->maxreadspeed, drive->maxwritespeed); 3738ad6bb6aSDavid du Colombier 3748ad6bb6aSDavid du Colombier if (drive->Scsi.changetime != 0 && drive->ntrack != 0) { /* have disc? */ 375*079e489fSDavid du Colombier ty = disctype(drive); 376*079e489fSDavid du Colombier p = seprint(p, e, "%s", ty); 377*079e489fSDavid du Colombier free(ty); 378*079e489fSDavid du Colombier if (drive->mmctype != Mmcnone) 3798ad6bb6aSDavid du Colombier p = seprint(p, e, " next writable sector %lud", 3808ad6bb6aSDavid du Colombier getnwa(drive)); 3818ad6bb6aSDavid du Colombier seprint(p, e, "\n"); 3828ad6bb6aSDavid du Colombier } 3839a747e4fSDavid du Colombier readstr(r, s); 3849a747e4fSDavid du Colombier } 3859a747e4fSDavid du Colombier 3869a747e4fSDavid du Colombier static void 3879a747e4fSDavid du Colombier fsread(Req *r) 3889a747e4fSDavid du Colombier { 3899a747e4fSDavid du Colombier int j, n, m; 3909a747e4fSDavid du Colombier uchar *p, *ep; 3919a747e4fSDavid du Colombier Dir d; 3929a747e4fSDavid du Colombier Fid *fid; 3939a747e4fSDavid du Colombier Otrack *o; 3949a747e4fSDavid du Colombier vlong offset; 3959a747e4fSDavid du Colombier void *buf; 3969a747e4fSDavid du Colombier long count; 3979a747e4fSDavid du Colombier Aux *a; 3989a747e4fSDavid du Colombier 3999a747e4fSDavid du Colombier fid = r->fid; 4009a747e4fSDavid du Colombier offset = r->ifcall.offset; 4019a747e4fSDavid du Colombier buf = r->ofcall.data; 4029a747e4fSDavid du Colombier count = r->ifcall.count; 4039a747e4fSDavid du Colombier 4049a747e4fSDavid du Colombier switch((ulong)fid->qid.path) { 4057dd7cddfSDavid du Colombier case Qdir: 4067dd7cddfSDavid du Colombier checktoc(drive); 4077dd7cddfSDavid du Colombier p = buf; 4089a747e4fSDavid du Colombier ep = p+count; 4097dd7cddfSDavid du Colombier m = Qtrack+drive->ntrack; 4109a747e4fSDavid du Colombier a = fid->aux; 4119a747e4fSDavid du Colombier if(offset == 0) 4129a747e4fSDavid du Colombier a->doff = 1; /* skip root */ 4139a747e4fSDavid du Colombier 4149a747e4fSDavid du Colombier for(j=a->doff; j<m; j++) { 4157dd7cddfSDavid du Colombier if(fillstat(j, &d)) { 4169a747e4fSDavid du Colombier if((n = convD2M(&d, p, ep-p)) <= BIT16SZ) 4179a747e4fSDavid du Colombier break; 4189a747e4fSDavid du Colombier p += n; 4197dd7cddfSDavid du Colombier } 4207dd7cddfSDavid du Colombier } 4219a747e4fSDavid du Colombier a->doff = j; 4229a747e4fSDavid du Colombier 4239a747e4fSDavid du Colombier r->ofcall.count = p - (uchar*)buf; 424cdf9e71cSDavid du Colombier break; 4257dd7cddfSDavid du Colombier case Qwa: 4267dd7cddfSDavid du Colombier case Qwd: 4279a747e4fSDavid du Colombier r->ofcall.count = 0; 428cdf9e71cSDavid du Colombier break; 4297dd7cddfSDavid du Colombier case Qctl: 4309a747e4fSDavid du Colombier readctl(r); 431cdf9e71cSDavid du Colombier break; 432cdf9e71cSDavid du Colombier default: 4337dd7cddfSDavid du Colombier /* a disk track; we can only call read for whole blocks */ 4349a747e4fSDavid du Colombier o = ((Aux*)fid->aux)->o; 435cdf9e71cSDavid du Colombier if((count = o->drive->read(o, buf, count, offset)) < 0) { 4367dd7cddfSDavid du Colombier respond(r, geterrstr()); 437cdf9e71cSDavid du Colombier return; 4389a747e4fSDavid du Colombier } 439cdf9e71cSDavid du Colombier r->ofcall.count = count; 440cdf9e71cSDavid du Colombier break; 441cdf9e71cSDavid du Colombier } 442cdf9e71cSDavid du Colombier respond(r, nil); 4437dd7cddfSDavid du Colombier } 4447dd7cddfSDavid du Colombier 4459a747e4fSDavid du Colombier static char *Ebadmsg = "bad cdfs control message"; 446c038c065SDavid du Colombier 4477dd7cddfSDavid du Colombier static char* 4487dd7cddfSDavid du Colombier writectl(void *v, long count) 4497dd7cddfSDavid du Colombier { 4507dd7cddfSDavid du Colombier char buf[256]; 4519a747e4fSDavid du Colombier char *f[10], *p; 4529a747e4fSDavid du Colombier int i, nf, n, r, w, what; 4537dd7cddfSDavid du Colombier 4547dd7cddfSDavid du Colombier if(count >= sizeof(buf)) 4557dd7cddfSDavid du Colombier count = sizeof(buf)-1; 4567dd7cddfSDavid du Colombier memmove(buf, v, count); 4577dd7cddfSDavid du Colombier buf[count] = '\0'; 4587dd7cddfSDavid du Colombier 4597dd7cddfSDavid du Colombier nf = tokenize(buf, f, nelem(f)); 4609a747e4fSDavid du Colombier if(nf == 0) 4619a747e4fSDavid du Colombier return Ebadmsg; 4629a747e4fSDavid du Colombier 4639a747e4fSDavid du Colombier if(strcmp(f[0], "speed") == 0){ 4649a747e4fSDavid du Colombier what = 0; 4659a747e4fSDavid du Colombier r = w = -1; 4669a747e4fSDavid du Colombier if(nf == 1) 4679a747e4fSDavid du Colombier return Ebadmsg; 4689a747e4fSDavid du Colombier for(i=1; i<nf; i++){ 4699a747e4fSDavid du Colombier if(strcmp(f[i], "read") == 0 || strcmp(f[i], "write") == 0){ 4709a747e4fSDavid du Colombier if(what!=0 && what!='?') 4719a747e4fSDavid du Colombier return Ebadmsg; 4729a747e4fSDavid du Colombier what = f[i][0]; 4739a747e4fSDavid du Colombier }else{ 4749a747e4fSDavid du Colombier n = strtol(f[i], &p, 0); 4759a747e4fSDavid du Colombier if(*p != '\0' || n <= 0) 4769a747e4fSDavid du Colombier return Ebadmsg; 4779a747e4fSDavid du Colombier switch(what){ 4789a747e4fSDavid du Colombier case 0: 4799a747e4fSDavid du Colombier if(r >= 0 || w >= 0) 4809a747e4fSDavid du Colombier return Ebadmsg; 4819a747e4fSDavid du Colombier r = w = n; 4829a747e4fSDavid du Colombier break; 4839a747e4fSDavid du Colombier case 'r': 4849a747e4fSDavid du Colombier if(r >= 0) 4859a747e4fSDavid du Colombier return Ebadmsg; 4869a747e4fSDavid du Colombier r = n; 4879a747e4fSDavid du Colombier break; 4889a747e4fSDavid du Colombier case 'w': 4899a747e4fSDavid du Colombier if(w >= 0) 4909a747e4fSDavid du Colombier return Ebadmsg; 4919a747e4fSDavid du Colombier w = n; 4929a747e4fSDavid du Colombier break; 4939a747e4fSDavid du Colombier default: 4949a747e4fSDavid du Colombier return Ebadmsg; 4959a747e4fSDavid du Colombier } 496cdf9e71cSDavid du Colombier what = '?'; 4979a747e4fSDavid du Colombier } 4989a747e4fSDavid du Colombier } 4999a747e4fSDavid du Colombier if(what != '?') 5009a747e4fSDavid du Colombier return Ebadmsg; 5019a747e4fSDavid du Colombier return drive->setspeed(drive, r, w); 5029a747e4fSDavid du Colombier } 5037dd7cddfSDavid du Colombier return drive->ctl(drive, nf, f); 5047dd7cddfSDavid du Colombier } 5057dd7cddfSDavid du Colombier 5067dd7cddfSDavid du Colombier static void 5079a747e4fSDavid du Colombier fswrite(Req *r) 5087dd7cddfSDavid du Colombier { 5097dd7cddfSDavid du Colombier Otrack *o; 5109a747e4fSDavid du Colombier Fid *fid; 5117dd7cddfSDavid du Colombier 5129a747e4fSDavid du Colombier fid = r->fid; 5139a747e4fSDavid du Colombier r->ofcall.count = r->ifcall.count; 5147dd7cddfSDavid du Colombier if(fid->qid.path == Qctl) { 5159a747e4fSDavid du Colombier respond(r, writectl(r->ifcall.data, r->ifcall.count)); 5167dd7cddfSDavid du Colombier return; 5177dd7cddfSDavid du Colombier } 5187dd7cddfSDavid du Colombier 5199a747e4fSDavid du Colombier if((o = ((Aux*)fid->aux)->o) == nil || o->omode != OWRITE) { 5207dd7cddfSDavid du Colombier respond(r, "permission denied"); 5217dd7cddfSDavid du Colombier return; 5227dd7cddfSDavid du Colombier } 5237dd7cddfSDavid du Colombier 5249a747e4fSDavid du Colombier if(o->drive->write(o, r->ifcall.data, r->ifcall.count) < 0) 5257dd7cddfSDavid du Colombier respond(r, geterrstr()); 5267dd7cddfSDavid du Colombier else 5277dd7cddfSDavid du Colombier respond(r, nil); 5287dd7cddfSDavid du Colombier } 5297dd7cddfSDavid du Colombier 5307dd7cddfSDavid du Colombier static void 5319a747e4fSDavid du Colombier fsstat(Req *r) 5327dd7cddfSDavid du Colombier { 5339a747e4fSDavid du Colombier fillstat((ulong)r->fid->qid.path, &r->d); 5349a747e4fSDavid du Colombier r->d.name = estrdup9p(r->d.name); 5359a747e4fSDavid du Colombier r->d.uid = estrdup9p(r->d.uid); 5369a747e4fSDavid du Colombier r->d.gid = estrdup9p(r->d.gid); 5379a747e4fSDavid du Colombier r->d.muid = estrdup9p(r->d.muid); 5387dd7cddfSDavid du Colombier respond(r, nil); 5397dd7cddfSDavid du Colombier } 5407dd7cddfSDavid du Colombier 5417dd7cddfSDavid du Colombier static void 5429a747e4fSDavid du Colombier fsopen(Req *r) 5437dd7cddfSDavid du Colombier { 5449a747e4fSDavid du Colombier int omode; 5459a747e4fSDavid du Colombier Fid *fid; 5467dd7cddfSDavid du Colombier Otrack *o; 5477dd7cddfSDavid du Colombier 5489a747e4fSDavid du Colombier fid = r->fid; 5499a747e4fSDavid du Colombier omode = r->ifcall.mode; 5507dd7cddfSDavid du Colombier checktoc(drive); 5519a747e4fSDavid du Colombier r->ofcall.qid = (Qid){fid->qid.path, drive->nchange, fid->qid.vers}; 5527dd7cddfSDavid du Colombier 5539a747e4fSDavid du Colombier switch((ulong)fid->qid.path){ 5547dd7cddfSDavid du Colombier case Qdir: 5557dd7cddfSDavid du Colombier case Qwa: 5567dd7cddfSDavid du Colombier case Qwd: 557cdf9e71cSDavid du Colombier if(omode != OREAD) { 5587dd7cddfSDavid du Colombier respond(r, "permission denied"); 5597dd7cddfSDavid du Colombier return; 560cdf9e71cSDavid du Colombier } 561cdf9e71cSDavid du Colombier break; 5627dd7cddfSDavid du Colombier case Qctl: 563cdf9e71cSDavid du Colombier if(omode & ~(OTRUNC|OREAD|OWRITE|ORDWR)) { 5647dd7cddfSDavid du Colombier respond(r, "permission denied"); 5657dd7cddfSDavid du Colombier return; 566cdf9e71cSDavid du Colombier } 567cdf9e71cSDavid du Colombier break; 5687dd7cddfSDavid du Colombier default: 5697dd7cddfSDavid du Colombier if(fid->qid.path >= Qtrack+drive->ntrack) { 5707dd7cddfSDavid du Colombier respond(r, "file no longer exists"); 5717dd7cddfSDavid du Colombier return; 5727dd7cddfSDavid du Colombier } 5737dd7cddfSDavid du Colombier 574c038c065SDavid du Colombier /* 575c038c065SDavid du Colombier * allow the open with OWRITE or ORDWR if the 576c038c065SDavid du Colombier * drive and disc are both capable? 577c038c065SDavid du Colombier */ 578c038c065SDavid du Colombier if(omode != OREAD || 579c038c065SDavid du Colombier (o = drive->openrd(drive, fid->qid.path-Qtrack)) == nil) { 5807dd7cddfSDavid du Colombier respond(r, "permission denied"); 5817dd7cddfSDavid du Colombier return; 5827dd7cddfSDavid du Colombier } 5837dd7cddfSDavid du Colombier 5847dd7cddfSDavid du Colombier o->nref = 1; 5859a747e4fSDavid du Colombier ((Aux*)fid->aux)->o = o; 586c038c065SDavid du Colombier break; 5877dd7cddfSDavid du Colombier } 588cdf9e71cSDavid du Colombier respond(r, nil); 5897dd7cddfSDavid du Colombier } 5907dd7cddfSDavid du Colombier 5917dd7cddfSDavid du Colombier static void 5929a747e4fSDavid du Colombier fsdestroyfid(Fid *fid) 5937dd7cddfSDavid du Colombier { 5949a747e4fSDavid du Colombier Aux *aux; 5957dd7cddfSDavid du Colombier Otrack *o; 5967dd7cddfSDavid du Colombier 5979a747e4fSDavid du Colombier aux = fid->aux; 5989a747e4fSDavid du Colombier if(aux == nil) 5999a747e4fSDavid du Colombier return; 6009a747e4fSDavid du Colombier o = aux->o; 6017dd7cddfSDavid du Colombier if(o && --o->nref == 0) { 6027dd7cddfSDavid du Colombier bterm(o->buf); 6037dd7cddfSDavid du Colombier drive->close(o); 6047dd7cddfSDavid du Colombier checktoc(drive); 6057dd7cddfSDavid du Colombier } 6067dd7cddfSDavid du Colombier } 6077dd7cddfSDavid du Colombier 6087dd7cddfSDavid du Colombier static void 6097dd7cddfSDavid du Colombier checktoc(Drive *drive) 6107dd7cddfSDavid du Colombier { 6117dd7cddfSDavid du Colombier int i; 6127dd7cddfSDavid du Colombier Track *t; 6137dd7cddfSDavid du Colombier 6147dd7cddfSDavid du Colombier drive->gettoc(drive); 6157dd7cddfSDavid du Colombier if(drive->nameok) 6167dd7cddfSDavid du Colombier return; 6177dd7cddfSDavid du Colombier 6187dd7cddfSDavid du Colombier for(i=0; i<drive->ntrack; i++) { 6197dd7cddfSDavid du Colombier t = &drive->track[i]; 6207dd7cddfSDavid du Colombier if(t->size == 0) /* being created */ 6217dd7cddfSDavid du Colombier t->mode = 0; 6227dd7cddfSDavid du Colombier else 6237dd7cddfSDavid du Colombier t->mode = 0444; 6247dd7cddfSDavid du Colombier sprint(t->name, "?%.3d", i); 6257dd7cddfSDavid du Colombier switch(t->type){ 6267dd7cddfSDavid du Colombier case TypeNone: 6277dd7cddfSDavid du Colombier t->name[0] = 'u'; 628e67f3b95SDavid du Colombier // t->mode = 0; 6297dd7cddfSDavid du Colombier break; 6307dd7cddfSDavid du Colombier case TypeData: 6317dd7cddfSDavid du Colombier t->name[0] = 'd'; 6327dd7cddfSDavid du Colombier break; 6337dd7cddfSDavid du Colombier case TypeAudio: 6347dd7cddfSDavid du Colombier t->name[0] = 'a'; 6357dd7cddfSDavid du Colombier break; 6367dd7cddfSDavid du Colombier case TypeBlank: 6377dd7cddfSDavid du Colombier t->name[0] = '\0'; 6387dd7cddfSDavid du Colombier break; 6397dd7cddfSDavid du Colombier default: 640*079e489fSDavid du Colombier print("unknown track type %d\n", t->type); 6417dd7cddfSDavid du Colombier break; 6427dd7cddfSDavid du Colombier } 6437dd7cddfSDavid du Colombier } 6447dd7cddfSDavid du Colombier 6457dd7cddfSDavid du Colombier drive->nameok = 1; 6467dd7cddfSDavid du Colombier } 6477dd7cddfSDavid du Colombier 6487dd7cddfSDavid du Colombier long 6497dd7cddfSDavid du Colombier bufread(Otrack *t, void *v, long n, long off) 6507dd7cddfSDavid du Colombier { 6517dd7cddfSDavid du Colombier return bread(t->buf, v, n, off); 6527dd7cddfSDavid du Colombier } 6537dd7cddfSDavid du Colombier 6547dd7cddfSDavid du Colombier long 6557dd7cddfSDavid du Colombier bufwrite(Otrack *t, void *v, long n) 6567dd7cddfSDavid du Colombier { 6577dd7cddfSDavid du Colombier return bwrite(t->buf, v, n); 6587dd7cddfSDavid du Colombier } 6597dd7cddfSDavid du Colombier 6609a747e4fSDavid du Colombier Srv fs = { 6619a747e4fSDavid du Colombier .attach= fsattach, 6629a747e4fSDavid du Colombier .destroyfid= fsdestroyfid, 6639a747e4fSDavid du Colombier .clone= fsclone, 6649a747e4fSDavid du Colombier .walk1= fswalk1, 6659a747e4fSDavid du Colombier .open= fsopen, 6669a747e4fSDavid du Colombier .read= fsread, 6679a747e4fSDavid du Colombier .write= fswrite, 6689a747e4fSDavid du Colombier .create= fscreate, 6699a747e4fSDavid du Colombier .remove= fsremove, 6709a747e4fSDavid du Colombier .stat= fsstat, 6717dd7cddfSDavid du Colombier }; 6727dd7cddfSDavid du Colombier 6737dd7cddfSDavid du Colombier void 6747dd7cddfSDavid du Colombier usage(void) 6757dd7cddfSDavid du Colombier { 6769a747e4fSDavid du Colombier fprint(2, "usage: cdfs [-Dv] [-d /dev/sdC0] [-m mtpt]\n"); 6777dd7cddfSDavid du Colombier exits("usage"); 6787dd7cddfSDavid du Colombier } 6797dd7cddfSDavid du Colombier 6807dd7cddfSDavid du Colombier void 6817dd7cddfSDavid du Colombier main(int argc, char **argv) 6827dd7cddfSDavid du Colombier { 6837dd7cddfSDavid du Colombier Scsi *s; 6847dd7cddfSDavid du Colombier int fd; 6857dd7cddfSDavid du Colombier char *dev, *mtpt; 6867dd7cddfSDavid du Colombier 6877dd7cddfSDavid du Colombier dev = "/dev/sdD0"; 6887dd7cddfSDavid du Colombier mtpt = "/mnt/cd"; 6897dd7cddfSDavid du Colombier 6907dd7cddfSDavid du Colombier ARGBEGIN{ 6919a747e4fSDavid du Colombier case 'D': 6929a747e4fSDavid du Colombier chatty9p++; 6939a747e4fSDavid du Colombier break; 6947dd7cddfSDavid du Colombier case 'd': 695e67f3b95SDavid du Colombier dev = EARGF(usage()); 6967dd7cddfSDavid du Colombier break; 6977dd7cddfSDavid du Colombier case 'm': 698e67f3b95SDavid du Colombier mtpt = EARGF(usage()); 6997dd7cddfSDavid du Colombier break; 7007dd7cddfSDavid du Colombier case 'v': 7017dd7cddfSDavid du Colombier if((fd = create("/tmp/cdfs.log", OWRITE, 0666)) >= 0) { 7027dd7cddfSDavid du Colombier dup(fd, 2); 7037dd7cddfSDavid du Colombier dup(fd, 1); 7047dd7cddfSDavid du Colombier if(fd != 1 && fd != 2) 7057dd7cddfSDavid du Colombier close(fd); 7067dd7cddfSDavid du Colombier vflag++; 707436f307dSDavid du Colombier scsiverbose = 2; /* verbose but no Readtoc errs */ 7087dd7cddfSDavid du Colombier } 7097dd7cddfSDavid du Colombier break; 7107dd7cddfSDavid du Colombier default: 7117dd7cddfSDavid du Colombier usage(); 7127dd7cddfSDavid du Colombier }ARGEND 7137dd7cddfSDavid du Colombier 7147dd7cddfSDavid du Colombier if(dev == nil || mtpt == nil || argc > 0) 7157dd7cddfSDavid du Colombier usage(); 7167dd7cddfSDavid du Colombier 717c038c065SDavid du Colombier if((s = openscsi(dev)) == nil) 718c038c065SDavid du Colombier sysfatal("openscsi '%s': %r", dev); 719c038c065SDavid du Colombier if((drive = mmcprobe(s)) == nil) 720c038c065SDavid du Colombier sysfatal("mmcprobe '%s': %r", dev); 7217dd7cddfSDavid du Colombier checktoc(drive); 7227dd7cddfSDavid du Colombier 7239a747e4fSDavid du Colombier postmountsrv(&fs, nil, mtpt, MREPL|MCREATE); 72480ee5cbfSDavid du Colombier exits(nil); 7257dd7cddfSDavid du Colombier } 726