forsyth20121205-174063a80cc13 years agoHistory
432 lines · 7.0 KB · C
RawDownload
#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"../port/error.h" extern ulong	kerndate; voidmkqid(Qid *q, vlong path, ulong vers, int type){	q->type = type;	q->vers = vers;	q->path = path;} intdevno(int c, int user){	int i; 	for(i = 0; devtab[i] != nil; i++) {		if(devtab[i]->dc == c)			return i;	}	if(user == 0)		panic("devno %C 0x%ux", c, c); 	return -1;} voiddevdir(Chan *c, Qid qid, char *n, vlong length, char *user, long perm, Dir *db){	db->name = n;	if(c->flag&CMSG)		qid.type |= QTMOUNT;	db->qid = qid;	db->type = devtab[c->type]->dc;	db->dev = c->dev;	db->mode = perm;	db->mode |= qid.type << 24;	db->atime = seconds();	db->mtime = kerndate;	db->length = length;	db->uid = user;	db->gid = eve;	db->muid = user;} /* * the zeroth element of the table MUST be the directory itself for ..*/intdevgen(Chan *c, char*, Dirtab *tab, int ntab, int i, Dir *dp){	if(tab == 0)		return -1;	if(i != DEVDOTDOT){		/* skip over the first element, that for . itself */		i++;		if(i >= ntab)			return -1;		tab += i;	}	devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);	return 1;} voiddevreset(void){} voiddevinit(void){} voiddevshutdown(void){} Chan*devattach(int tc, char *spec){	Chan *c;	char *buf; 	c = newchan();	mkqid(&c->qid, 0, 0, QTDIR);	c->type = devno(tc, 0);	if(spec == nil)		spec = "";	buf = smalloc(4+strlen(spec)+1);	sprint(buf, "#%C%s", tc, spec);	c->name = newcname(buf);	free(buf);	return c;}  Chan*devclone(Chan *c){	Chan *nc; 	if(c->flag & COPEN)		panic("clone of open file type %C\n", devtab[c->type]->dc); 	nc = newchan(); 	nc->type = c->type;	nc->dev = c->dev;	nc->mode = c->mode;	nc->qid = c->qid;	nc->offset = c->offset;	nc->umh = nil;	nc->mountid = c->mountid;	nc->aux = c->aux;	nc->mqid = c->mqid;	nc->mcp = c->mcp;	return nc;} Walkqid*devwalk(Chan *c, Chan *nc, char **name, int nname, Dirtab *tab, int ntab, Devgen *gen){	int i, j, alloc;	Walkqid *wq;	char *n;	Dir dir; 	if(nname > 0)		isdir(c); 	alloc = 0;	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));	if(waserror()){		if(alloc && wq->clone!=nil)			cclose(wq->clone);		free(wq);		return nil;	}	if(nc == nil){		nc = devclone(c);		nc->type = 0;	/* device doesn't know about this channel yet */		alloc = 1;	}	wq->clone = nc; 	for(j=0; j<nname; j++){		if(!(nc->qid.type&QTDIR)){			if(j==0)				error(Enotdir);			goto Done;		}		n = name[j];		if(strcmp(n, ".") == 0){    Accept:			wq->qid[wq->nqid++] = nc->qid;			continue;		}		if(strcmp(n, "..") == 0){			(*gen)(nc, nil, tab, ntab, DEVDOTDOT, &dir);			nc->qid = dir.qid;			goto Accept;		}		/*		 * Ugly problem: If we're using devgen, make sure we're		 * walking the directory itself, represented by the first		 * entry in the table, and not trying to step into a sub-		 * directory of the table, e.g. /net/net. Devgen itself		 * should take care of the problem, but it doesn't have		 * the necessary information (that we're doing a walk).		 */		if(gen==devgen && nc->qid.path!=tab[0].qid.path)			goto Notfound;		for(i=0;; i++) {			switch((*gen)(nc, n, tab, ntab, i, &dir)){			case -1:			Notfound:				if(j == 0)					error(Enonexist);				kstrcpy(up->env->errstr, Enonexist, ERRMAX);				goto Done;			case 0:				continue;			case 1:				if(strcmp(n, dir.name) == 0){					nc->qid = dir.qid;					goto Accept;				}				continue;			}		}	}	/*	 * We processed at least one name, so will return some data.	 * If we didn't process all nname entries succesfully, we drop	 * the cloned channel and return just the Qids of the walks.	 */Done:	poperror();	if(wq->nqid < nname){		if(alloc)			cclose(wq->clone);		wq->clone = nil;	}else if(wq->clone){		/* attach cloned channel to same device */		wq->clone->type = c->type;	}	return wq;} intdevstat(Chan *c, uchar *db, int n, Dirtab *tab, int ntab, Devgen *gen){	int i;	Dir dir;	char *p, *elem; 	for(i=0;; i++)		switch((*gen)(c, nil, tab, ntab, i, &dir)){		case -1:			if(c->qid.type & QTDIR){				if(c->name == nil)					elem = "???";				else if(strcmp(c->name->s, "/") == 0)					elem = "/";				else					for(elem=p=c->name->s; *p; p++)						if(*p == '/')							elem = p+1;				devdir(c, c->qid, elem, 0, eve, DMDIR|0555, &dir);				n = convD2M(&dir, db, n);				if(n == 0)					error(Ebadarg);				return n;			}			print("%s %s: devstat %C %llux\n",				up->text, up->env->user,				devtab[c->type]->dc, c->qid.path); 			error(Enonexist);		case 0:			break;		case 1:			if(c->qid.path == dir.qid.path) {				if(c->flag&CMSG)					dir.mode |= DMMOUNT;				n = convD2M(&dir, db, n);				if(n == 0)					error(Ebadarg);				return n;			}			break;		}} longdevdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen){	long m, dsz;	struct{		Dir;		char slop[100];	}dir; 	for(m=0; m<n; c->dri++) {		switch((*gen)(c, nil, tab, ntab, c->dri, &dir)){		case -1:			return m; 		case 0:			break; 		case 1:			dsz = convD2M(&dir, (uchar*)d, n-m);			if(dsz <= BIT16SZ){	/* <= not < because this isn't stat; read is stuck */				if(m == 0)					error(Eshort);				return m;			}			m += dsz;			d += dsz;			break;		}	} 	return m;} /* * error(Eperm) if open permission not granted for up->env->user. */voiddevpermcheck(char *fileuid, ulong perm, int omode){	ulong t;	static int access[] = { 0400, 0200, 0600, 0100 }; 	if(strcmp(up->env->user, fileuid) == 0)		perm <<= 0;	else	if(strcmp(up->env->user, eve) == 0)		perm <<= 3;	else		perm <<= 6; 	t = access[omode&3];	if((t&perm) != t)		error(Eperm);} Chan*devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen){	int i;	Dir dir; 	for(i=0;; i++) {		switch((*gen)(c, nil, tab, ntab, i, &dir)){		case -1:			goto Return;		case 0:			break;		case 1:			if(c->qid.path == dir.qid.path) {				devpermcheck(dir.uid, dir.mode, omode);				goto Return;			}			break;		}	}Return:	c->offset = 0;	if((c->qid.type&QTDIR) && omode!=OREAD)		error(Eperm);	c->mode = openmode(omode);	c->flag |= COPEN;	return c;} voiddevcreate(Chan*, char*, int, ulong){	error(Eperm);} Block*devbread(Chan *c, long n, ulong offset){	Block *bp; 	bp = allocb(n);	if(bp == 0)		error(Enomem);	if(waserror()) {		freeb(bp);		nexterror();	}	bp->wp += devtab[c->type]->read(c, bp->wp, n, offset);	poperror();	return bp;} longdevbwrite(Chan *c, Block *bp, ulong offset){	long n; 	if(waserror()) {		freeb(bp);		nexterror();	}	n = devtab[c->type]->write(c, bp->rp, BLEN(bp), offset);	poperror();	freeb(bp); 	return n;} voiddevremove(Chan*){	error(Eperm);} intdevwstat(Chan*, uchar*, int){	error(Eperm);	return 0;} voiddevpower(int){	error(Eperm);} intdevconfig(int, char *, DevConf *){	error(Eperm);	return 0;} /* * check that the name in a wstat is plausible */voidvalidwstatname(char *name){	validname(name, 0);	if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)		error(Efilename);} Dev*devbyname(char *name){	int i; 	for(i = 0; devtab[i] != nil; i++)		if(strcmp(devtab[i]->name, name) == 0)			return devtab[i];	return nil;}