Charles.Forsyth20060303a828770d19 years agoHistory
365 lines · 5.9 KB · C
RawDownload
/* * Plan 9 file system interface */#include	"dat.h"#include	"fns.h"#include	"error.h" typedef struct Fsinfo Fsinfo;struct Fsinfo{	int	fd;	QLock;		/* serialise access to offset */	ulong	offset;	/* offset used only for directory reads */	Cname*	name;	/* Plan 9's name for file */	Qid	rootqid;		/* Plan 9's qid for Inferno's root */	char*	root;		/* prefix to strip from all names in diagnostics */};#define	FS(c)	((Fsinfo*)((c)->aux)) char	rootdir[MAXROOT] = ROOT; static voidfserr(Fsinfo *f){	int n;	char *p; 	oserrstr(up->env->errstr, ERRMAX);	if(f != nil && *up->env->errstr == '\'' && (n = strlen(f->root)) > 1){		/* don't reveal full names */		if(strncmp(up->env->errstr+1, f->root, n-1) == 0){			p = up->env->errstr+1+n;			memmove(up->env->errstr+1, p, strlen(p)+1);		}	}	error(up->env->errstr);} static voidfsfree(Chan *c){	cnameclose(FS(c)->name);	free(c->aux);} Chan*fsattach(char *spec){	Chan *c;	Dir *d;	char *root;	Qid rootqid;	static int devno;	static Lock l; 	if(!emptystr(spec)){		if(strcmp(spec, "*") != 0)			error(Ebadspec);		root = "/";	}else		root = rootdir; 	d = dirstat(root);	if(d == nil)		fserr(nil);	rootqid = d->qid;	free(d); 	c = devattach('U', spec);	lock(&l);	c->dev = devno++;	c->qid = rootqid;	unlock(&l);	c->aux = smalloc(sizeof(Fsinfo));	FS(c)->name = newcname(root);	FS(c)->rootqid = rootqid;	FS(c)->fd = -1;	FS(c)->root = root; 	return c;} Walkqid*fswalk(Chan *c, Chan *nc, char **name, int nname){	int j, alloc;	Walkqid *wq;	Dir *dir;	char *n;	Cname *current, *next;	Qid rootqid; 	if(nname > 0)		isdir(c);	/* do we need this? */ 	alloc = 0;	current = nil;	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));	if(waserror()){		if(alloc && wq->clone!=nil)			cclose(wq->clone);		cnameclose(current);		free(wq);		return nil;	}	if(nc == nil){		nc = devclone(c);		nc->type = 0;		alloc = 1;	}	wq->clone = nc; 	rootqid = FS(c)->rootqid;	current = FS(c)->name;	if(current != nil)		incref(&current->r);	for(j=0; j<nname; j++){		if(!(nc->qid.type&QTDIR)){			if(j==0)				error(Enotdir);			break;		}		n = name[j];		if(strcmp(n, ".") != 0 && !(isdotdot(n) && nc->qid.path == rootqid.path)){	/* TO DO: underlying qids aliased */			//print("** ufs walk '%s' -> %s\n", current->s, n);			next = current;			incref(&next->r);			next = addelem(current, n);			dir = dirstat(next->s);			if(dir == nil){				cnameclose(next);				if(j == 0)					error(Enonexist);				strcpy(up->env->errstr, Enonexist);				break;			}			nc->qid = dir->qid;			free(dir);			cnameclose(current);			current = next;		}		wq->qid[wq->nqid++] = nc->qid;	}//	print("** ufs walk '%s'\n", current->s); 	poperror();	if(wq->nqid < nname){		cnameclose(current);		if(alloc)			cclose(wq->clone);		wq->clone = nil;	}else if(wq->clone){		/* now attach to our device */		nc->aux = smalloc(sizeof(Fsinfo));		nc->type = c->type;		FS(nc)->rootqid = FS(c)->rootqid;		FS(nc)->name = current;		FS(nc)->fd = -1;		FS(nc)->root = FS(c)->root;	}else		panic("fswalk: can't happen");	return wq;} intfsstat(Chan *c, uchar *dp, int n){	if(FS(c)->fd >= 0)		n = fstat(FS(c)->fd, dp, n);	else		n = stat(FS(c)->name->s, dp, n);	if(n < 0)		fserr(FS(c));	/* TO DO: change name to / if rootqid */	return n;} Chan*fsopen(Chan *c, int mode){	osenter();	FS(c)->fd = open(FS(c)->name->s, mode);	osleave();	if(FS(c)->fd < 0)		fserr(FS(c));	c->mode = openmode(mode);	c->offset = 0;	FS(c)->offset = 0;	c->flag |= COPEN;	return c;} voidfscreate(Chan *c, char *name, int mode, ulong perm){	Dir *d;	Cname *n; 	if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)		error(Efilename);	n = addelem(newcname(FS(c)->name->s), name);	osenter();	FS(c)->fd = create(n->s, mode, perm);	osleave();	if(FS(c)->fd < 0) {		cnameclose(n);		fserr(FS(c));	}	d = dirfstat(FS(c)->fd);	if(d == nil) {		cnameclose(n);		close(FS(c)->fd);		FS(c)->fd = -1;		fserr(FS(c));	}	c->qid = d->qid;	free(d); 	cnameclose(FS(c)->name);	FS(c)->name = n; 	c->mode = openmode(mode);	c->offset = 0;	FS(c)->offset = 0;	c->flag |= COPEN;} voidfsclose(Chan *c){	if(c->flag & COPEN){		osenter();		close(FS(c)->fd);		osleave();	}	/* don't need to check for CRCLOSE, because Plan 9 itself implements ORCLOSE */	fsfree(c);} static longfsdirread(Chan *c, void *va, long count, vlong offset){	long n, r;	static char slop[16384]; 	if(FS(c)->offset != offset){		seek(FS(c)->fd, 0, 0);		for(n=0; n<offset;) {			r = offset - n;			if(r > sizeof(slop))				r = sizeof(slop);			osenter();			r = read(FS(c)->fd, slop, r);			osleave();			if(r <= 0){				FS(c)->offset = n;				return 0;			}			n += r;		}		FS(c)->offset = offset;	}	osenter();	r = read(FS(c)->fd, va, count);	osleave();	if(r < 0)		return r;	FS(c)->offset = offset+r;	return r;} longfsread(Chan *c, void *va, long n, vlong offset){	int r; 	if(c->qid.type & QTDIR){	/* need to maintain offset only for directories */		qlock(FS(c));		if(waserror()){			qunlock(FS(c));			nexterror();		}		r = fsdirread(c, va, n, offset);		poperror();		qunlock(FS(c));	}else{		osenter();		r = pread(FS(c)->fd, va, n, offset);		osleave();	}	if(r < 0)		fserr(FS(c));	return r;} longfswrite(Chan *c, void *va, long n, vlong offset){	int r; 	osenter();	r = pwrite(FS(c)->fd, va, n, offset);	osleave();	if(r < 0)		fserr(FS(c));	return r;} voidfsremove(Chan *c){	int r; 	if(waserror()){		fsfree(c);		nexterror();	}	osenter();	r = remove(FS(c)->name->s);	osleave();	if(r < 0)		fserr(FS(c));	poperror();	fsfree(c);} intfswstat(Chan *c, uchar *dp, int n){	osenter();	if(FS(c)->fd >= 0)		n = fwstat(FS(c)->fd, dp, n);	else		n = wstat(FS(c)->name->s, dp, n);	osleave();	if(n < 0)		fserr(FS(c));	return n;} voidsetid(char *name, int owner){	if(!owner || iseve())		kstrdup(&up->env->user, name);} Dev fsdevtab = {	'U',	"fs", 	devinit,	fsattach,	fswalk,	fsstat,	fsopen,	fscreate,	fsclose,	fsread,	devbread,	fswrite,	devbwrite,	fsremove,	fswstat};