748 lines · 12.9 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* cdfs - CD, DVD and BD reader and writer file system */#include <u.h>#include <libc.h>#include <auth.h>#include <fcall.h>#include <thread.h>#include <9p.h>#include <disk.h>#include "dat.h"#include "fns.h" typedef struct Aux Aux;struct Aux {	int	doff;	Otrack	*o;}; ulong	getnwa(Drive *); static void checktoc(Drive*); int vflag; static Drive *drive;static int nchange; enum {	Qdir = 0,	Qctl = 1,	Qwa = 2,	Qwd = 3,	Qtrack = 4,}; char*geterrstr(void){	static char errbuf[ERRMAX]; 	rerrstr(errbuf, sizeof errbuf);	return errbuf;} void*emalloc(ulong sz){	void *v; 	v = mallocz(sz, 1);	if(v == nil)		sysfatal("malloc %lud fails", sz);	return v;} static voidfsattach(Req *r){	char *spec; 	spec = r->ifcall.aname;	if(spec && spec[0]) {		respond(r, "invalid attach specifier");		return;	} 	checktoc(drive);	r->fid->qid = (Qid){Qdir, drive->nchange, QTDIR};	r->ofcall.qid = r->fid->qid;	r->fid->aux = emalloc(sizeof(Aux));	respond(r, nil);} static char*fsclone(Fid *old, Fid *new){	Aux *na; 	na = emalloc(sizeof(Aux));	*na = *((Aux*)old->aux);	if(na->o)		na->o->nref++;	new->aux = na;	return nil;} static char*fswalk1(Fid *fid, char *name, Qid *qid){	int i; 	checktoc(drive);	switch((ulong)fid->qid.path) {	case Qdir:		if(strcmp(name, "..") == 0) {			*qid = (Qid){Qdir, drive->nchange, QTDIR};			return nil;		}		if(strcmp(name, "ctl") == 0) {			*qid = (Qid){Qctl, 0, 0};			return nil;		}		if(strcmp(name, "wa") == 0 && drive->writeok &&		    (drive->mmctype == Mmcnone ||		     drive->mmctype == Mmccd)) {			*qid = (Qid){Qwa, drive->nchange, QTDIR};			return nil;		}		if(strcmp(name, "wd") == 0 && drive->writeok) {			*qid = (Qid){Qwd, drive->nchange, QTDIR};			return nil;		}		for(i=0; i<drive->ntrack; i++)			if(strcmp(drive->track[i].name, name) == 0)				break;		if(i == drive->ntrack)			return "file not found";		*qid = (Qid){Qtrack+i, 0, 0};		return nil; 	case Qwa:	case Qwd:		if(strcmp(name, "..") == 0) {			*qid = (Qid){Qdir, drive->nchange, QTDIR};			return nil;		}		return "file not found";	default:	/* bug: lib9p could handle this */		return "walk in non-directory";	}} static voidfscreate(Req *r){	int omode, type;	Otrack *o;	Fid *fid; 	fid = r->fid;	omode = r->ifcall.mode;		if(omode != OWRITE) {		respond(r, "bad mode (use OWRITE)");		return;	} 	switch((ulong)fid->qid.path) {	case Qdir:	default:		respond(r, "permission denied");		return; 	case Qwa:		if (drive->mmctype != Mmcnone &&		    drive->mmctype != Mmccd) {			respond(r, "audio supported only on cd");			return;		}		type = TypeAudio;		break; 	case Qwd:		type = TypeData;		break;	} 	if((drive->cap & Cwrite) == 0) {		respond(r, "drive does not write");		return;	} 	o = drive->create(drive, type);	if(o == nil) {		respond(r, geterrstr());		return;	}	drive->nchange = -1;	checktoc(drive);	/* update directory info */	o->nref = 1;	((Aux*)fid->aux)->o = o; 	fid->qid = (Qid){Qtrack+(o->track - drive->track), drive->nchange, 0};	r->ofcall.qid = fid->qid;	respond(r, nil);} static voidfsremove(Req *r){	switch((ulong)r->fid->qid.path){	case Qwa:	case Qwd:		if(drive->fixate(drive) < 0)			respond(r, geterrstr());// let us see if it can figure this out:	drive->writeok = No;			else			respond(r, nil);		checktoc(drive);		break;	default:		respond(r, "permission denied");		break;	}} /* result is one word, so it can be used as a uid in Dir structs */char *disctype(Drive *drive){	char *type, *rw, *laysfx; 	rw = laysfx = "";	switch (drive->mmctype) {	case Mmccd:		type = "cd-";		break;	case Mmcdvdminus:	case Mmcdvdplus:		type = drive->dvdtype;		break;	case Mmcbd:		type = "bd-";		if (drive->laysfx)			laysfx = drive->laysfx;		break;	case Mmcnone:		type = "no-disc";		break;	default:		type = "**GOK**";		/* traditional */		break;	}	if (drive->mmctype != Mmcnone && drive->dvdtype == nil)		if (drive->erasable == Yes)			rw = drive->mmctype == Mmcbd? "re": "rw";		else if (drive->recordable == Yes)			rw = "r";		else			rw = "rom";	return smprint("%s%s%s", type, rw, laysfx);} intfillstat(ulong qid, Dir *d){	char *ty;	Track *t;	static char buf[32]; 	nulldir(d);	d->type = L'M';	d->dev = 1;	d->length = 0;	ty = disctype(drive);	strncpy(buf, ty, sizeof buf);	free(ty);	d->uid = d->gid = buf;	d->muid = "";	d->qid = (Qid){qid, drive->nchange, 0};	d->atime = time(0);	d->mtime = drive->changetime; 	switch(qid){	case Qdir:		d->name = "/";		d->qid.type = QTDIR;		d->mode = DMDIR|0777;		break; 	case Qctl:		d->name = "ctl";		d->mode = 0666;		break; 	case Qwa:		if(drive->writeok == No ||		    drive->mmctype != Mmcnone &&		    drive->mmctype != Mmccd)			return 0;		d->name = "wa";		d->qid.type = QTDIR;		d->mode = DMDIR|0777;		break; 	case Qwd:		if(drive->writeok == No)			return 0;		d->name = "wd";		d->qid.type = QTDIR;		d->mode = DMDIR|0777;		break; 	default:		if(qid-Qtrack >= drive->ntrack)			return 0;		t = &drive->track[qid-Qtrack];		if(strcmp(t->name, "") == 0)			return 0;		d->name = t->name;		d->mode = t->mode;		d->length = t->size;		break;	}	return 1;} static ulong cddb_sum(int n){	int ret;	ret = 0;	while(n > 0) {		ret += n%10;		n /= 10;	}	return ret;} static ulongdiskid(Drive *d){	int i, n;	ulong tmp;	Msf *ms, *me; 	n = 0;	for(i=0; i < d->ntrack; i++)		n += cddb_sum(d->track[i].mbeg.m*60+d->track[i].mbeg.s); 	ms = &d->track[0].mbeg;	me = &d->track[d->ntrack].mbeg;	tmp = (me->m*60+me->s) - (ms->m*60+ms->s); 	/*	 * the spec says n%0xFF rather than n&0xFF.  it's unclear which is	 * correct.  most CDs are in the database under both entries.	 */	return ((n % 0xFF) << 24 | (tmp << 8) | d->ntrack);} static voidreadctl(Req *r){	int i, isaudio;	ulong nwa;	char *p, *e, *ty;	char s[1024];	Msf *m; 	isaudio = 0;	for(i=0; i<drive->ntrack; i++)		if(drive->track[i].type == TypeAudio)			isaudio = 1; 	p = s;	e = s + sizeof s;	*p = '\0';	if(isaudio){		p = seprint(p, e, "aux/cddb query %8.8lux %d", diskid(drive),			drive->ntrack);		for(i=0; i<drive->ntrack; i++){			m = &drive->track[i].mbeg;			p = seprint(p, e, " %d", (m->m*60 + m->s)*75 + m->f);		}		m = &drive->track[drive->ntrack].mbeg;		p = seprint(p, e, " %d\n", m->m*60 + m->s);	} 	if(drive->readspeed == drive->writespeed)		p = seprint(p, e, "speed %d\n", drive->readspeed);	else		p = seprint(p, e, "speed read %d write %d\n",			drive->readspeed, drive->writespeed);	p = seprint(p, e, "maxspeed read %d write %d\n",		drive->maxreadspeed, drive->maxwritespeed); 	if (drive->Scsi.changetime != 0 && drive->ntrack != 0) { /* have disc? */		ty = disctype(drive);		p = seprint(p, e, "%s", ty);		free(ty);		if (drive->mmctype != Mmcnone) {			nwa = getnwa(drive);			p = seprint(p, e, " next writable sector ");			if (nwa == ~0ul)				p = seprint(p, e, "none; disc full");			else				p = seprint(p, e, "%lud", nwa);		}		seprint(p, e, "\n");	}	readstr(r, s);} static voidfsread(Req *r){	int j, n, m;	uchar *p, *ep;	Dir d;	Fid *fid;	Otrack *o;	vlong offset;	void *buf;	long count;	Aux *a; 	fid = r->fid;	offset = r->ifcall.offset;	buf = r->ofcall.data;	count = r->ifcall.count; 	switch((ulong)fid->qid.path) {	case Qdir:		checktoc(drive);		p = buf;		ep = p+count;		m = Qtrack+drive->ntrack;		a = fid->aux;		if(offset == 0)			a->doff = 1;	/* skip root */ 		for(j=a->doff; j<m; j++) {			if(fillstat(j, &d)) {				if((n = convD2M(&d, p, ep-p)) <= BIT16SZ)					break;				p += n;			}		}		a->doff = j; 		r->ofcall.count = p - (uchar*)buf;		break;	case Qwa:	case Qwd:		r->ofcall.count = 0;		break;	case Qctl:		readctl(r);		break;	default:		/* a disk track; we can only call read for whole blocks */		o = ((Aux*)fid->aux)->o;		if((count = o->drive->read(o, buf, count, offset)) < 0) {			respond(r, geterrstr());			return;		}		r->ofcall.count = count;		break;	}	respond(r, nil);} static char Ebadmsg[] = "bad cdfs control message"; static char*writectl(void *v, long count){	char buf[256];	char *f[10], *p;	int i, nf, n, r, w, what; 	if(count >= sizeof(buf))		count = sizeof(buf)-1;	memmove(buf, v, count);	buf[count] = '\0'; 	nf = tokenize(buf, f, nelem(f));	if(nf == 0)		return Ebadmsg; 	if(strcmp(f[0], "speed") == 0){		what = 0;		r = w = -1;		if(nf == 1)			return Ebadmsg;		for(i=1; i<nf; i++){			if(strcmp(f[i], "read") == 0 || strcmp(f[i], "write") == 0){				if(what!=0 && what!='?')					return Ebadmsg;				what = f[i][0];			}else{				if (strcmp(f[i], "best") == 0)					n = (1<<16) - 1;				else {					n = strtol(f[i], &p, 0);					if(*p != '\0' || n <= 0)						return Ebadmsg;				}				switch(what){				case 0:					if(r >= 0 || w >= 0)

Lines 1–500 of 748.