xref: /plan9/sys/src/9/port/dev.c (revision 567483c891f7c54442ce1d593e764767ee5fcaf7)
13e12c5d1SDavid du Colombier #include	"u.h"
23e12c5d1SDavid du Colombier #include	"../port/lib.h"
33e12c5d1SDavid du Colombier #include	"mem.h"
43e12c5d1SDavid du Colombier #include	"dat.h"
53e12c5d1SDavid du Colombier #include	"fns.h"
63e12c5d1SDavid du Colombier #include	"../port/error.h"
73e12c5d1SDavid du Colombier 
83e12c5d1SDavid du Colombier extern ulong	kerndate;
93e12c5d1SDavid du Colombier 
109a747e4fSDavid du Colombier void
mkqid(Qid * q,vlong path,ulong vers,int type)119a747e4fSDavid du Colombier mkqid(Qid *q, vlong path, ulong vers, int type)
129a747e4fSDavid du Colombier {
139a747e4fSDavid du Colombier 	q->type = type;
149a747e4fSDavid du Colombier 	q->vers = vers;
159a747e4fSDavid du Colombier 	q->path = path;
169a747e4fSDavid du Colombier }
179a747e4fSDavid du Colombier 
183e12c5d1SDavid du Colombier int
devno(int c,int user)193e12c5d1SDavid du Colombier devno(int c, int user)
203e12c5d1SDavid du Colombier {
21bd389b36SDavid du Colombier 	int i;
223e12c5d1SDavid du Colombier 
237dd7cddfSDavid du Colombier 	for(i = 0; devtab[i] != nil; i++) {
247dd7cddfSDavid du Colombier 		if(devtab[i]->dc == c)
25bd389b36SDavid du Colombier 			return i;
26bd389b36SDavid du Colombier 	}
277dd7cddfSDavid du Colombier 	if(user == 0)
28*567483c8SDavid du Colombier 		panic("devno %C %#ux", c, c);
297dd7cddfSDavid du Colombier 
307dd7cddfSDavid du Colombier 	return -1;
313e12c5d1SDavid du Colombier }
323e12c5d1SDavid du Colombier 
333e12c5d1SDavid du Colombier void
devdir(Chan * c,Qid qid,char * n,vlong length,char * user,long perm,Dir * db)347dd7cddfSDavid du Colombier devdir(Chan *c, Qid qid, char *n, vlong length, char *user, long perm, Dir *db)
353e12c5d1SDavid du Colombier {
369a747e4fSDavid du Colombier 	db->name = n;
379a747e4fSDavid du Colombier 	if(c->flag&CMSG)
389a747e4fSDavid du Colombier 		qid.type |= QTMOUNT;
393e12c5d1SDavid du Colombier 	db->qid = qid;
407dd7cddfSDavid du Colombier 	db->type = devtab[c->type]->dc;
413e12c5d1SDavid du Colombier 	db->dev = c->dev;
423e12c5d1SDavid du Colombier 	db->mode = perm;
439a747e4fSDavid du Colombier 	db->mode |= qid.type << 24;
443e12c5d1SDavid du Colombier 	db->atime = seconds();
453e12c5d1SDavid du Colombier 	db->mtime = kerndate;
463e12c5d1SDavid du Colombier 	db->length = length;
479a747e4fSDavid du Colombier 	db->uid = user;
489a747e4fSDavid du Colombier 	db->gid = eve;
499a747e4fSDavid du Colombier 	db->muid = user;
503e12c5d1SDavid du Colombier }
513e12c5d1SDavid du Colombier 
529a747e4fSDavid du Colombier /*
535e96a66cSDavid du Colombier  * (here, Devgen is the prototype; devgen is the function in dev.c.)
545e96a66cSDavid du Colombier  *
555e96a66cSDavid du Colombier  * a Devgen is expected to return the directory entry for ".."
565e96a66cSDavid du Colombier  * if you pass it s==DEVDOTDOT (-1).  otherwise...
575e96a66cSDavid du Colombier  *
585e96a66cSDavid du Colombier  * there are two contradictory rules.
595e96a66cSDavid du Colombier  *
605e96a66cSDavid du Colombier  * (i) if c is a directory, a Devgen is expected to list its children
615e96a66cSDavid du Colombier  * as you iterate s.
625e96a66cSDavid du Colombier  *
635e96a66cSDavid du Colombier  * (ii) whether or not c is a directory, a Devgen is expected to list
645e96a66cSDavid du Colombier  * its siblings as you iterate s.
655e96a66cSDavid du Colombier  *
665e96a66cSDavid du Colombier  * devgen always returns the list of children in the root
675e96a66cSDavid du Colombier  * directory.  thus it follows (i) when c is the root and (ii) otherwise.
685e96a66cSDavid du Colombier  * many other Devgens follow (i) when c is a directory and (ii) otherwise.
695e96a66cSDavid du Colombier  *
705e96a66cSDavid du Colombier  * devwalk assumes (i).  it knows that devgen breaks (i)
715e96a66cSDavid du Colombier  * for children that are themselves directories, and explicitly catches them.
725e96a66cSDavid du Colombier  *
735e96a66cSDavid du Colombier  * devstat assumes (ii).  if the Devgen in question follows (i)
745e96a66cSDavid du Colombier  * for this particular c, devstat will not find the necessary info.
755e96a66cSDavid du Colombier  * with our particular Devgen functions, this happens only for
765e96a66cSDavid du Colombier  * directories, so devstat makes something up, assuming
775e96a66cSDavid du Colombier  * c->name, c->qid, eve, DMDIR|0555.
785e96a66cSDavid du Colombier  *
795e96a66cSDavid du Colombier  * devdirread assumes (i).  the callers have to make sure
805e96a66cSDavid du Colombier  * that the Devgen satisfies (i) for the chan being read.
815e96a66cSDavid du Colombier  */
825e96a66cSDavid du Colombier /*
839a747e4fSDavid du Colombier  * the zeroth element of the table MUST be the directory itself for ..
849a747e4fSDavid du Colombier */
853e12c5d1SDavid du Colombier int
devgen(Chan * c,char * name,Dirtab * tab,int ntab,int i,Dir * dp)86fb7f0c93SDavid du Colombier devgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
873e12c5d1SDavid du Colombier {
887dd7cddfSDavid du Colombier 	if(tab == 0)
897dd7cddfSDavid du Colombier 		return -1;
90fb7f0c93SDavid du Colombier 	if(i == DEVDOTDOT){
91fb7f0c93SDavid du Colombier 		/* nothing */
92fb7f0c93SDavid du Colombier 	}else if(name){
93fb7f0c93SDavid du Colombier 		for(i=1; i<ntab; i++)
94fb7f0c93SDavid du Colombier 			if(strcmp(tab[i].name, name) == 0)
95fb7f0c93SDavid du Colombier 				break;
96fb7f0c93SDavid du Colombier 		if(i==ntab)
97fb7f0c93SDavid du Colombier 			return -1;
98fb7f0c93SDavid du Colombier 		tab += i;
99fb7f0c93SDavid du Colombier 	}else{
1009a747e4fSDavid du Colombier 		/* skip over the first element, that for . itself */
1019a747e4fSDavid du Colombier 		i++;
1027dd7cddfSDavid du Colombier 		if(i >= ntab)
1033e12c5d1SDavid du Colombier 			return -1;
1043e12c5d1SDavid du Colombier 		tab += i;
1057dd7cddfSDavid du Colombier 	}
1063e12c5d1SDavid du Colombier 	devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
1073e12c5d1SDavid du Colombier 	return 1;
1083e12c5d1SDavid du Colombier }
1093e12c5d1SDavid du Colombier 
1107dd7cddfSDavid du Colombier void
devreset(void)1117dd7cddfSDavid du Colombier devreset(void)
1127dd7cddfSDavid du Colombier {
1137dd7cddfSDavid du Colombier }
1147dd7cddfSDavid du Colombier 
1157dd7cddfSDavid du Colombier void
devinit(void)1167dd7cddfSDavid du Colombier devinit(void)
1177dd7cddfSDavid du Colombier {
1187dd7cddfSDavid du Colombier }
1197dd7cddfSDavid du Colombier 
1209a747e4fSDavid du Colombier void
devshutdown(void)1219a747e4fSDavid du Colombier devshutdown(void)
1229a747e4fSDavid du Colombier {
1239a747e4fSDavid du Colombier }
1249a747e4fSDavid du Colombier 
1253e12c5d1SDavid du Colombier Chan*
devattach(int tc,char * spec)1263e12c5d1SDavid du Colombier devattach(int tc, char *spec)
1273e12c5d1SDavid du Colombier {
128cdf9e71cSDavid du Colombier 	int n;
1293e12c5d1SDavid du Colombier 	Chan *c;
1309a747e4fSDavid du Colombier 	char *buf;
1313e12c5d1SDavid du Colombier 
1323e12c5d1SDavid du Colombier 	c = newchan();
1339a747e4fSDavid du Colombier 	mkqid(&c->qid, 0, 0, QTDIR);
1343e12c5d1SDavid du Colombier 	c->type = devno(tc, 0);
1359a747e4fSDavid du Colombier 	if(spec == nil)
1369a747e4fSDavid du Colombier 		spec = "";
137cdf9e71cSDavid du Colombier 	n = 1+UTFmax+strlen(spec)+1;
138cdf9e71cSDavid du Colombier 	buf = smalloc(n);
139cdf9e71cSDavid du Colombier 	snprint(buf, n, "#%C%s", tc, spec);
1404afe124fSDavid du Colombier 	c->path = newpath(buf);
1419a747e4fSDavid du Colombier 	free(buf);
1423e12c5d1SDavid du Colombier 	return c;
1433e12c5d1SDavid du Colombier }
1443e12c5d1SDavid du Colombier 
1459a747e4fSDavid du Colombier 
1463e12c5d1SDavid du Colombier Chan*
devclone(Chan * c)1479a747e4fSDavid du Colombier devclone(Chan *c)
1483e12c5d1SDavid du Colombier {
1499a747e4fSDavid du Colombier 	Chan *nc;
1509a747e4fSDavid du Colombier 
1513e12c5d1SDavid du Colombier 	if(c->flag & COPEN)
1527dd7cddfSDavid du Colombier 		panic("clone of open file type %C\n", devtab[c->type]->dc);
1537dd7cddfSDavid du Colombier 
1543e12c5d1SDavid du Colombier 	nc = newchan();
1557dd7cddfSDavid du Colombier 
1563e12c5d1SDavid du Colombier 	nc->type = c->type;
1573e12c5d1SDavid du Colombier 	nc->dev = c->dev;
1583e12c5d1SDavid du Colombier 	nc->mode = c->mode;
1593e12c5d1SDavid du Colombier 	nc->qid = c->qid;
1603e12c5d1SDavid du Colombier 	nc->offset = c->offset;
1619a747e4fSDavid du Colombier 	nc->umh = nil;
1623e12c5d1SDavid du Colombier 	nc->aux = c->aux;
1633e12c5d1SDavid du Colombier 	nc->mqid = c->mqid;
1647dd7cddfSDavid du Colombier 	nc->mcp = c->mcp;
1653e12c5d1SDavid du Colombier 	return nc;
1663e12c5d1SDavid du Colombier }
1673e12c5d1SDavid du Colombier 
1689a747e4fSDavid du Colombier Walkqid*
devwalk(Chan * c,Chan * nc,char ** name,int nname,Dirtab * tab,int ntab,Devgen * gen)1699a747e4fSDavid du Colombier devwalk(Chan *c, Chan *nc, char **name, int nname, Dirtab *tab, int ntab, Devgen *gen)
1703e12c5d1SDavid du Colombier {
1719a747e4fSDavid du Colombier 	int i, j, alloc;
1729a747e4fSDavid du Colombier 	Walkqid *wq;
1739a747e4fSDavid du Colombier 	char *n;
1743e12c5d1SDavid du Colombier 	Dir dir;
1753e12c5d1SDavid du Colombier 
1769a747e4fSDavid du Colombier 	if(nname > 0)
1773e12c5d1SDavid du Colombier 		isdir(c);
1789a747e4fSDavid du Colombier 
1799a747e4fSDavid du Colombier 	alloc = 0;
1809a747e4fSDavid du Colombier 	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
1819a747e4fSDavid du Colombier 	if(waserror()){
1829a747e4fSDavid du Colombier 		if(alloc && wq->clone!=nil)
1839a747e4fSDavid du Colombier 			cclose(wq->clone);
1849a747e4fSDavid du Colombier 		free(wq);
1859a747e4fSDavid du Colombier 		return nil;
1867dd7cddfSDavid du Colombier 	}
1879a747e4fSDavid du Colombier 	if(nc == nil){
1889a747e4fSDavid du Colombier 		nc = devclone(c);
1899a747e4fSDavid du Colombier 		nc->type = 0;	/* device doesn't know about this channel yet */
1909a747e4fSDavid du Colombier 		alloc = 1;
1919a747e4fSDavid du Colombier 	}
1929a747e4fSDavid du Colombier 	wq->clone = nc;
1939a747e4fSDavid du Colombier 
1949a747e4fSDavid du Colombier 	for(j=0; j<nname; j++){
1959a747e4fSDavid du Colombier 		if(!(nc->qid.type&QTDIR)){
1969a747e4fSDavid du Colombier 			if(j==0)
1979a747e4fSDavid du Colombier 				error(Enotdir);
1989a747e4fSDavid du Colombier 			goto Done;
1999a747e4fSDavid du Colombier 		}
2009a747e4fSDavid du Colombier 		n = name[j];
2019a747e4fSDavid du Colombier 		if(strcmp(n, ".") == 0){
2029a747e4fSDavid du Colombier     Accept:
2039a747e4fSDavid du Colombier 			wq->qid[wq->nqid++] = nc->qid;
2049a747e4fSDavid du Colombier 			continue;
2059a747e4fSDavid du Colombier 		}
2069a747e4fSDavid du Colombier 		if(strcmp(n, "..") == 0){
2077abd426fSDavid du Colombier 			if((*gen)(nc, nil, tab, ntab, DEVDOTDOT, &dir) != 1){
2087abd426fSDavid du Colombier 				print("devgen walk .. in dev%s %llux broken\n",
2097abd426fSDavid du Colombier 					devtab[nc->type]->name, nc->qid.path);
2107abd426fSDavid du Colombier 				error("broken devgen");
2117abd426fSDavid du Colombier 			}
2129a747e4fSDavid du Colombier 			nc->qid = dir.qid;
2139a747e4fSDavid du Colombier 			goto Accept;
2149a747e4fSDavid du Colombier 		}
2159a747e4fSDavid du Colombier 		/*
2169a747e4fSDavid du Colombier 		 * Ugly problem: If we're using devgen, make sure we're
2179a747e4fSDavid du Colombier 		 * walking the directory itself, represented by the first
2189a747e4fSDavid du Colombier 		 * entry in the table, and not trying to step into a sub-
2199a747e4fSDavid du Colombier 		 * directory of the table, e.g. /net/net. Devgen itself
2209a747e4fSDavid du Colombier 		 * should take care of the problem, but it doesn't have
2219a747e4fSDavid du Colombier 		 * the necessary information (that we're doing a walk).
2229a747e4fSDavid du Colombier 		 */
2239a747e4fSDavid du Colombier 		if(gen==devgen && nc->qid.path!=tab[0].qid.path)
2249a747e4fSDavid du Colombier 			goto Notfound;
2257dd7cddfSDavid du Colombier 		for(i=0;; i++) {
2269a747e4fSDavid du Colombier 			switch((*gen)(nc, n, tab, ntab, i, &dir)){
2273e12c5d1SDavid du Colombier 			case -1:
2289a747e4fSDavid du Colombier 			Notfound:
2299a747e4fSDavid du Colombier 				if(j == 0)
2309a747e4fSDavid du Colombier 					error(Enonexist);
2319a747e4fSDavid du Colombier 				kstrcpy(up->errstr, Enonexist, ERRMAX);
2329a747e4fSDavid du Colombier 				goto Done;
2333e12c5d1SDavid du Colombier 			case 0:
2343e12c5d1SDavid du Colombier 				continue;
2353e12c5d1SDavid du Colombier 			case 1:
2369a747e4fSDavid du Colombier 				if(strcmp(n, dir.name) == 0){
2379a747e4fSDavid du Colombier 					nc->qid = dir.qid;
2389a747e4fSDavid du Colombier 					goto Accept;
2393e12c5d1SDavid du Colombier 				}
2403e12c5d1SDavid du Colombier 				continue;
2413e12c5d1SDavid du Colombier 			}
2427dd7cddfSDavid du Colombier 		}
2439a747e4fSDavid du Colombier 	}
2449a747e4fSDavid du Colombier 	/*
2459a747e4fSDavid du Colombier 	 * We processed at least one name, so will return some data.
2469a747e4fSDavid du Colombier 	 * If we didn't process all nname entries succesfully, we drop
2479a747e4fSDavid du Colombier 	 * the cloned channel and return just the Qids of the walks.
2489a747e4fSDavid du Colombier 	 */
2499a747e4fSDavid du Colombier Done:
2509a747e4fSDavid du Colombier 	poperror();
2519a747e4fSDavid du Colombier 	if(wq->nqid < nname){
2529a747e4fSDavid du Colombier 		if(alloc)
2539a747e4fSDavid du Colombier 			cclose(wq->clone);
2549a747e4fSDavid du Colombier 		wq->clone = nil;
2559a747e4fSDavid du Colombier 	}else if(wq->clone){
2569a747e4fSDavid du Colombier 		/* attach cloned channel to same device */
2579a747e4fSDavid du Colombier 		wq->clone->type = c->type;
2589a747e4fSDavid du Colombier 	}
2599a747e4fSDavid du Colombier 	return wq;
2603e12c5d1SDavid du Colombier }
2613e12c5d1SDavid du Colombier 
2629a747e4fSDavid du Colombier int
devstat(Chan * c,uchar * db,int n,Dirtab * tab,int ntab,Devgen * gen)2639a747e4fSDavid du Colombier devstat(Chan *c, uchar *db, int n, Dirtab *tab, int ntab, Devgen *gen)
2643e12c5d1SDavid du Colombier {
2653e12c5d1SDavid du Colombier 	int i;
2663e12c5d1SDavid du Colombier 	Dir dir;
2677dd7cddfSDavid du Colombier 	char *p, *elem;
2683e12c5d1SDavid du Colombier 
2699acf0835SDavid du Colombier 	for(i=0;; i++){
2709a747e4fSDavid du Colombier 		switch((*gen)(c, nil, tab, ntab, i, &dir)){
2713e12c5d1SDavid du Colombier 		case -1:
2729a747e4fSDavid du Colombier 			if(c->qid.type & QTDIR){
2734afe124fSDavid du Colombier 				if(c->path == nil)
2747dd7cddfSDavid du Colombier 					elem = "???";
2754afe124fSDavid du Colombier 				else if(strcmp(c->path->s, "/") == 0)
2767dd7cddfSDavid du Colombier 					elem = "/";
2777dd7cddfSDavid du Colombier 				else
2784afe124fSDavid du Colombier 					for(elem=p=c->path->s; *p; p++)
2797dd7cddfSDavid du Colombier 						if(*p == '/')
2807dd7cddfSDavid du Colombier 							elem = p+1;
2819a747e4fSDavid du Colombier 				devdir(c, c->qid, elem, 0, eve, DMDIR|0555, &dir);
2829a747e4fSDavid du Colombier 				n = convD2M(&dir, db, n);
2839a747e4fSDavid du Colombier 				if(n == 0)
2849a747e4fSDavid du Colombier 					error(Ebadarg);
2859a747e4fSDavid du Colombier 				return n;
2863e12c5d1SDavid du Colombier 			}
2877dd7cddfSDavid du Colombier 
2883e12c5d1SDavid du Colombier 			error(Enonexist);
2893e12c5d1SDavid du Colombier 		case 0:
2903e12c5d1SDavid du Colombier 			break;
2913e12c5d1SDavid du Colombier 		case 1:
2927dd7cddfSDavid du Colombier 			if(c->qid.path == dir.qid.path) {
293219b2ee8SDavid du Colombier 				if(c->flag&CMSG)
2949a747e4fSDavid du Colombier 					dir.mode |= DMMOUNT;
2959a747e4fSDavid du Colombier 				n = convD2M(&dir, db, n);
2969a747e4fSDavid du Colombier 				if(n == 0)
2979a747e4fSDavid du Colombier 					error(Ebadarg);
2989a747e4fSDavid du Colombier 				return n;
2993e12c5d1SDavid du Colombier 			}
3003e12c5d1SDavid du Colombier 			break;
3013e12c5d1SDavid du Colombier 		}
3029acf0835SDavid du Colombier 	}
3033e12c5d1SDavid du Colombier }
3043e12c5d1SDavid du Colombier 
3053e12c5d1SDavid du Colombier long
devdirread(Chan * c,char * d,long n,Dirtab * tab,int ntab,Devgen * gen)3063e12c5d1SDavid du Colombier devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen)
3073e12c5d1SDavid du Colombier {
3089a747e4fSDavid du Colombier 	long m, dsz;
309e288d156SDavid du Colombier 	Dir dir;
3103e12c5d1SDavid du Colombier 
3119a747e4fSDavid du Colombier 	for(m=0; m<n; c->dri++) {
3129a747e4fSDavid du Colombier 		switch((*gen)(c, nil, tab, ntab, c->dri, &dir)){
3133e12c5d1SDavid du Colombier 		case -1:
3143e12c5d1SDavid du Colombier 			return m;
3153e12c5d1SDavid du Colombier 
3163e12c5d1SDavid du Colombier 		case 0:
3173e12c5d1SDavid du Colombier 			break;
3183e12c5d1SDavid du Colombier 
3193e12c5d1SDavid du Colombier 		case 1:
3209a747e4fSDavid du Colombier 			dsz = convD2M(&dir, (uchar*)d, n-m);
3219a747e4fSDavid du Colombier 			if(dsz <= BIT16SZ){	/* <= not < because this isn't stat; read is stuck */
3229a747e4fSDavid du Colombier 				if(m == 0)
3233ff48bf5SDavid du Colombier 					error(Eshort);
3249a747e4fSDavid du Colombier 				return m;
3259a747e4fSDavid du Colombier 			}
3269a747e4fSDavid du Colombier 			m += dsz;
3279a747e4fSDavid du Colombier 			d += dsz;
3283e12c5d1SDavid du Colombier 			break;
3293e12c5d1SDavid du Colombier 		}
3307dd7cddfSDavid du Colombier 	}
3317dd7cddfSDavid du Colombier 
3323e12c5d1SDavid du Colombier 	return m;
3333e12c5d1SDavid du Colombier }
3343e12c5d1SDavid du Colombier 
33559cc4ca5SDavid du Colombier /*
33659cc4ca5SDavid du Colombier  * error(Eperm) if open permission not granted for up->user.
33759cc4ca5SDavid du Colombier  */
33859cc4ca5SDavid du Colombier void
devpermcheck(char * fileuid,ulong perm,int omode)33959cc4ca5SDavid du Colombier devpermcheck(char *fileuid, ulong perm, int omode)
34059cc4ca5SDavid du Colombier {
34159cc4ca5SDavid du Colombier 	ulong t;
34259cc4ca5SDavid du Colombier 	static int access[] = { 0400, 0200, 0600, 0100 };
34359cc4ca5SDavid du Colombier 
34459cc4ca5SDavid du Colombier 	if(strcmp(up->user, fileuid) == 0)
34559cc4ca5SDavid du Colombier 		perm <<= 0;
34659cc4ca5SDavid du Colombier 	else
34759cc4ca5SDavid du Colombier 	if(strcmp(up->user, eve) == 0)
34859cc4ca5SDavid du Colombier 		perm <<= 3;
34959cc4ca5SDavid du Colombier 	else
35059cc4ca5SDavid du Colombier 		perm <<= 6;
35159cc4ca5SDavid du Colombier 
35259cc4ca5SDavid du Colombier 	t = access[omode&3];
35359cc4ca5SDavid du Colombier 	if((t&perm) != t)
35459cc4ca5SDavid du Colombier 		error(Eperm);
35559cc4ca5SDavid du Colombier }
35659cc4ca5SDavid du Colombier 
3573e12c5d1SDavid du Colombier Chan*
devopen(Chan * c,int omode,Dirtab * tab,int ntab,Devgen * gen)3583e12c5d1SDavid du Colombier devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen)
3593e12c5d1SDavid du Colombier {
3603e12c5d1SDavid du Colombier 	int i;
3613e12c5d1SDavid du Colombier 	Dir dir;
3623e12c5d1SDavid du Colombier 
3637dd7cddfSDavid du Colombier 	for(i=0;; i++) {
3649a747e4fSDavid du Colombier 		switch((*gen)(c, nil, tab, ntab, i, &dir)){
3653e12c5d1SDavid du Colombier 		case -1:
3663e12c5d1SDavid du Colombier 			goto Return;
3673e12c5d1SDavid du Colombier 		case 0:
3683e12c5d1SDavid du Colombier 			break;
3693e12c5d1SDavid du Colombier 		case 1:
3707dd7cddfSDavid du Colombier 			if(c->qid.path == dir.qid.path) {
37159cc4ca5SDavid du Colombier 				devpermcheck(dir.uid, dir.mode, omode);
3723e12c5d1SDavid du Colombier 				goto Return;
3733e12c5d1SDavid du Colombier 			}
3743e12c5d1SDavid du Colombier 			break;
3753e12c5d1SDavid du Colombier 		}
3767dd7cddfSDavid du Colombier 	}
3773e12c5d1SDavid du Colombier Return:
3783e12c5d1SDavid du Colombier 	c->offset = 0;
3799a747e4fSDavid du Colombier 	if((c->qid.type&QTDIR) && omode!=OREAD)
3803e12c5d1SDavid du Colombier 		error(Eperm);
3813e12c5d1SDavid du Colombier 	c->mode = openmode(omode);
3823e12c5d1SDavid du Colombier 	c->flag |= COPEN;
3833e12c5d1SDavid du Colombier 	return c;
3843e12c5d1SDavid du Colombier }
3857dd7cddfSDavid du Colombier 
3867dd7cddfSDavid du Colombier void
devcreate(Chan *,char *,int,ulong)3877dd7cddfSDavid du Colombier devcreate(Chan*, char*, int, ulong)
3887dd7cddfSDavid du Colombier {
3897dd7cddfSDavid du Colombier 	error(Eperm);
3907dd7cddfSDavid du Colombier }
3917dd7cddfSDavid du Colombier 
3927dd7cddfSDavid du Colombier Block*
devbread(Chan * c,long n,ulong offset)3937dd7cddfSDavid du Colombier devbread(Chan *c, long n, ulong offset)
3947dd7cddfSDavid du Colombier {
3957dd7cddfSDavid du Colombier 	Block *bp;
3967dd7cddfSDavid du Colombier 
3977dd7cddfSDavid du Colombier 	bp = allocb(n);
3987dd7cddfSDavid du Colombier 	if(bp == 0)
3997dd7cddfSDavid du Colombier 		error(Enomem);
4007dd7cddfSDavid du Colombier 	if(waserror()) {
4017dd7cddfSDavid du Colombier 		freeb(bp);
4027dd7cddfSDavid du Colombier 		nexterror();
4037dd7cddfSDavid du Colombier 	}
4047dd7cddfSDavid du Colombier 	bp->wp += devtab[c->type]->read(c, bp->wp, n, offset);
4057dd7cddfSDavid du Colombier 	poperror();
4067dd7cddfSDavid du Colombier 	return bp;
4077dd7cddfSDavid du Colombier }
4087dd7cddfSDavid du Colombier 
4097dd7cddfSDavid du Colombier long
devbwrite(Chan * c,Block * bp,ulong offset)4107dd7cddfSDavid du Colombier devbwrite(Chan *c, Block *bp, ulong offset)
4117dd7cddfSDavid du Colombier {
4127dd7cddfSDavid du Colombier 	long n;
4137dd7cddfSDavid du Colombier 
41459cc4ca5SDavid du Colombier 	if(waserror()) {
41559cc4ca5SDavid du Colombier 		freeb(bp);
41659cc4ca5SDavid du Colombier 		nexterror();
41759cc4ca5SDavid du Colombier 	}
4187dd7cddfSDavid du Colombier 	n = devtab[c->type]->write(c, bp->rp, BLEN(bp), offset);
41959cc4ca5SDavid du Colombier 	poperror();
4207dd7cddfSDavid du Colombier 	freeb(bp);
4217dd7cddfSDavid du Colombier 
4227dd7cddfSDavid du Colombier 	return n;
4237dd7cddfSDavid du Colombier }
4247dd7cddfSDavid du Colombier 
4257dd7cddfSDavid du Colombier void
devremove(Chan *)4267dd7cddfSDavid du Colombier devremove(Chan*)
4277dd7cddfSDavid du Colombier {
4287dd7cddfSDavid du Colombier 	error(Eperm);
4297dd7cddfSDavid du Colombier }
4307dd7cddfSDavid du Colombier 
4319a747e4fSDavid du Colombier int
devwstat(Chan *,uchar *,int)4329a747e4fSDavid du Colombier devwstat(Chan*, uchar*, int)
4337dd7cddfSDavid du Colombier {
4347dd7cddfSDavid du Colombier 	error(Eperm);
4359a747e4fSDavid du Colombier 	return 0;
4369a747e4fSDavid du Colombier }
4379a747e4fSDavid du Colombier 
4389a747e4fSDavid du Colombier void
devpower(int)4399a747e4fSDavid du Colombier devpower(int)
4409a747e4fSDavid du Colombier {
4419a747e4fSDavid du Colombier 	error(Eperm);
4429a747e4fSDavid du Colombier }
4439a747e4fSDavid du Colombier 
4449a747e4fSDavid du Colombier int
devconfig(int,char *,DevConf *)4459a747e4fSDavid du Colombier devconfig(int, char *, DevConf *)
4469a747e4fSDavid du Colombier {
4479a747e4fSDavid du Colombier 	error(Eperm);
4489a747e4fSDavid du Colombier 	return 0;
4497dd7cddfSDavid du Colombier }
450