plan 9 kernel history: overview | file list | diff list

2001/0820/port/dev.c (diff list | history)

2001/0820/sys/src/9/port/dev.c:1,3902001/0822/sys/src/9/port/dev.c:1,388 (short | long | prev | next)
Bug fix?: save offset for devdirread to handle reads of large direectories.
rsc Fri Mar 4 12:44:25 2005
1990/0227    
#include	"u.h" 
1992/0321    
#include	"../port/lib.h" 
1990/0227    
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
1992/0111    
#include	"../port/error.h" 
1990/0227    
 
1991/1220    
extern ulong	kerndate; 
 
2001/0527    
void 
mkqid(Qid *q, vlong path, ulong vers, int type) 
{ 
	q->type = type; 
	q->vers = vers; 
	q->path = path; 
} 
 
1990/0227    
int 
devno(int c, int user) 
{ 
1992/1217    
	int i; 
1990/0227    
 
1997/0408    
	for(i = 0; devtab[i] != nil; i++) { 
		if(devtab[i]->dc == c) 
1992/1217    
			return i; 
1990/0227    
	} 
1997/0408    
	if(user == 0) 
		panic("devno %C 0x%ux", c, c); 
1992/1217    
 
1997/0408    
	return -1; 
1990/0227    
} 
 
void 
1998/0326    
devdir(Chan *c, Qid qid, char *n, vlong length, char *user, long perm, Dir *db) 
1990/0227    
{ 
2001/0527    
	db->name = n; 
1990/0227    
	db->qid = qid; 
1997/0408    
	db->type = devtab[c->type]->dc; 
1990/0227    
	db->dev = c->dev; 
2001/0527    
	db->mode = perm; 
	db->mode |= qid.type << 24; 
1990/0227    
	db->atime = seconds(); 
1991/1220    
	db->mtime = kerndate; 
1998/0326    
	db->length = length; 
2001/0527    
	db->uid = user; 
	db->gid = eve; 
	db->muid = user; 
1990/0227    
} 
 
2001/0527    
/* 
 * the zeroth element of the table MUST be the directory itself for .. 
*/ 
1990/0227    
int 
2001/0527    
devgen(Chan *c, char*, Dirtab *tab, int ntab, int i, Dir *dp) 
1990/0227    
{ 
2001/0527    
	if(tab == 0) 
1990/0227    
		return -1; 
2001/0527    
	if(i != DEVDOTDOT){ 
		/* skip over the first element, that for . itself */ 
		i++; 
		if(i >= ntab) 
1999/1230    
			return -1; 
		tab += i; 
	} 
1991/1109    
	devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp); 
1990/0227    
	return 1; 
} 
 
1997/0327    
void 
devreset(void) 
{ 
} 
 
void 
devinit(void) 
{ 
} 
 
Chan* 
1990/0227    
devattach(int tc, char *spec) 
{ 
	Chan *c; 
2001/0527    
	char *buf; 
1990/0227    
 
	c = newchan(); 
2001/0527    
	mkqid(&c->qid, 0, 0, QTDIR); 
1990/0227    
	c->type = devno(tc, 0); 
2001/0527    
	if(spec == nil) 
		spec = ""; 
	buf = smalloc(4+strlen(spec)+1); 
	sprint(buf, "#%C%s", tc, spec); 
1999/0629    
	c->name = newcname(buf); 
2001/0527    
	free(buf); 
1990/0227    
	return c; 
} 
 
2001/0527    
 
1997/0327    
Chan* 
2001/0527    
devclone(Chan *c) 
1990/0227    
{ 
2001/0527    
	Chan *nc; 
 
1990/0329    
	if(c->flag & COPEN) 
1997/0408    
		panic("clone of open file type %C\n", devtab[c->type]->dc); 
1993/0501    
 
2001/0527    
	nc = newchan(); 
1993/0501    
 
1990/0227    
	nc->type = c->type; 
1991/0421    
	nc->dev = c->dev; 
1990/0227    
	nc->mode = c->mode; 
	nc->qid = c->qid; 
	nc->offset = c->offset; 
2001/0527    
	nc->umh = nil; 
1991/0427    
	nc->mountid = c->mountid; 
1991/0421    
	nc->aux = c->aux; 
1990/0303    
	nc->mqid = c->mqid; 
1993/1013    
	nc->mcp = c->mcp; 
1990/0227    
	return nc; 
} 
 
2001/0527    
Walkqid* 
devwalk(Chan *c, Chan *nc, char **name, int nname, Dirtab *tab, int ntab, Devgen *gen) 
1990/0227    
{ 
2001/0527    
	int i, j, alloc; 
	Walkqid *wq; 
	char *n; 
1990/0227    
	Dir dir; 
 
2001/0527    
	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; 
1999/1230    
	} 
2001/0527    
	wq->clone = nc; 
 
	for(j=0; j<nname; j++){ 
		isdir(nc); 
		n = name[j]; 
		if(strcmp(n, ".") == 0){ 
    Accept: 
			wq->qid[wq->nqid++] = nc->qid; 
1990/0227    
			continue; 
2001/0527    
		} 
		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); 
				strncpy(up->error, Enonexist, ERRMAX); 
				goto Done; 
			case 0: 
				continue; 
			case 1: 
				if(strcmp(n, dir.name) == 0){ 
					nc->qid = dir.qid; 
					goto Accept; 
				} 
				continue; 
1990/0227    
			} 
		} 
1993/0501    
	} 
2001/0527    
	/* 
	 * 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; 
1991/0411    
} 
 
2001/0527    
int 
devstat(Chan *c, uchar *db, int n, Dirtab *tab, int ntab, Devgen *gen) 
1990/0227    
{ 
	int i; 
	Dir dir; 
1999/0629    
	char *p, *elem; 
1990/0227    
 
1993/0330    
	for(i=0;; i++) 
2001/0527    
		switch((*gen)(c, nil, tab, ntab, i, &dir)){ 
1990/0227    
		case -1: 
2001/0527    
			if(c->qid.type & QTDIR){ 
1999/0629    
				if(c->name == nil) 
					elem = "???"; 
1999/0710    
				else if(strcmp(c->name->s, "/") == 0) 
					elem = "/"; 
1999/0629    
				else 
					for(elem=p=c->name->s; *p; p++) 
1999/0724    
						if(*p == '/') 
1999/0629    
							elem = p+1; 
2001/0527    
				devdir(c, c->qid, elem, 0, eve, DMDIR|0555, &dir); 
				n = convD2M(&dir, db, n); 
				if(n == 0) 
					error(Ebadarg); 
				return n; 
1990/0227    
			} 
2001/0527    
			print("%s %s: devstat %C %llux\n", 
1997/0327    
				up->text, up->user, 
1997/0408    
				devtab[c->type]->dc, c->qid.path); 
1997/0327    
 
1991/0626    
			error(Enonexist); 
1993/0330    
		case 0: 
			break; 
1990/0227    
		case 1: 
1999/0122    
			if(c->qid.path == dir.qid.path) { 
1993/0323    
				if(c->flag&CMSG) 
2001/0527    
					dir.mode |= DMMOUNT; 
				n = convD2M(&dir, db, n); 
				if(n == 0) 
					error(Ebadarg); 
				return n; 
1990/0227    
			} 
			break; 
		} 
2001/0527    
	error(Egreg);	/* not reached? */ 
	return -1; 
1990/0227    
} 
 
long 
devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen) 
{ 
2001/0527    
	long k, m, dsz; 
2001/0822    
	long m, dsz; 
2001/0527    
	struct{ 
		Dir; 
		char slop[100]; 
	}dir; 
1990/0227    
 
2001/0527    
	k = c->offset; 
1993/0501    
	for(m=0; m<n; k++) { 
2001/0527    
		switch((*gen)(c, nil, tab, ntab, k, &dir)){ 
2001/0822    
	for(m=0; m<n; c->dri++) { 
		switch((*gen)(c, nil, tab, ntab, c->dri, &dir)){ 
1990/0227    
		case -1: 
1990/0821    
			return m; 
1990/0227    
 
		case 0: 
2001/0527    
			c->offset++;	/* BUG??? (was DIRLEN: skip entry) */ 
1990/0227    
			break; 
 
		case 1: 
2001/0527    
			dsz = convD2M(&dir, (uchar*)d, n-m); 
			if(dsz <= BIT16SZ){	/* <= not < because this isn't stat; read is stuck */ 
				if(m == 0) 
					return -1; 
				return m; 
			} 
			m += dsz; 
			d += dsz; 
1990/0227    
			break; 
		} 
1993/0501    
	} 
 
1990/0821    
	return m; 
1990/0227    
} 
 
2000/0718    
/* 
 * error(Eperm) if open permission not granted for up->user. 
 */ 
void 
devpermcheck(char *fileuid, ulong perm, int omode) 
{ 
	ulong t; 
	static int access[] = { 0400, 0200, 0600, 0100 }; 
 
	if(strcmp(up->user, fileuid) == 0) 
		perm <<= 0; 
	else 
	if(strcmp(up->user, eve) == 0) 
		perm <<= 3; 
	else 
		perm <<= 6; 
 
	t = access[omode&3]; 
	if((t&perm) != t) 
		error(Eperm); 
} 
 
1997/0327    
Chan* 
1990/0227    
devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen) 
{ 
	int i; 
	Dir dir; 
 
1993/0501    
	for(i=0;; i++) { 
2001/0527    
		switch((*gen)(c, nil, tab, ntab, i, &dir)){ 
1990/0227    
		case -1: 
			goto Return; 
		case 0: 
			break; 
		case 1: 
1999/0122    
			if(c->qid.path == dir.qid.path) { 
2000/0718    
				devpermcheck(dir.uid, dir.mode, omode); 
				goto Return; 
1990/0227    
			} 
			break; 
		} 
1993/0501    
	} 
Return: 
1990/0227    
	c->offset = 0; 
2001/0527    
	if((c->qid.type&QTDIR) && omode!=OREAD) 
1990/11211    
		error(Eperm); 
1990/0227    
	c->mode = openmode(omode); 
	c->flag |= COPEN; 
	return c; 
} 
1995/0108    
 
1998/0512    
void 
1997/0327    
devcreate(Chan*, char*, int, ulong) 
{ 
	error(Eperm); 
} 
 
1995/0108    
Block* 
devbread(Chan *c, long n, ulong offset) 
{ 
	Block *bp; 
 
	bp = allocb(n); 
	if(bp == 0) 
		error(Enomem); 
	if(waserror()) { 
		freeb(bp); 
		nexterror(); 
	} 
1997/0327    
	bp->wp += devtab[c->type]->read(c, bp->wp, n, offset); 
1995/0108    
	poperror(); 
	return bp; 
} 
 
long 
devbwrite(Chan *c, Block *bp, ulong offset) 
{ 
	long n; 
 
2000/0817    
	if(waserror()) { 
		freeb(bp); 
		nexterror(); 
	} 
1997/0327    
	n = devtab[c->type]->write(c, bp->rp, BLEN(bp), offset); 
2000/0817    
	poperror(); 
1995/0108    
	freeb(bp); 
 
1998/0512    
	return n; 
1995/0108    
} 
 
1997/0327    
void 
devremove(Chan*) 
{ 
	error(Eperm); 
} 
 
2001/0527    
int 
devwstat(Chan*, uchar*, int) 
1997/0327    
{ 
	error(Eperm); 
2001/0527    
	return 0; 
1997/0327    
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)