790 lines · 13.4 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. */ #include <u.h>#include <libc.h>#include <bio.h>#include <auth.h>#include <fcall.h>#include <String.h>#include <libsec.h> enum{	OPERM	= 0x3,		/* mask of all permission types in open mode */	Maxsize	= 512*1024*1024,	Maxfdata	= 8192,	NAMELEN = 28,}; typedef struct Fid Fid;struct Fid{	short	busy;	int	fid;	Fid	*next;	char	*user;	String	*path;		/* complete path */ 	int	fd;		/* set on open or create */	Qid	qid;		/* set on open or create */	int	attach;		/* this is an attach fd */ 	ulong	diroff;		/* directory offset */	Dir	*dir;		/* directory entries */	int	ndir;		/* number of directory entries */}; Fid	*fids;int	mfd[2];char	*user;uchar	mdata[IOHDRSZ+Maxfdata];uchar	rdata[Maxfdata];	/* buffer for data in reply */uchar	statbuf[STATMAX];Fcall	thdr;Fcall	rhdr;int	messagesize = sizeof mdata;int	readonly;char	*srvname;int	debug; Fid *	newfid(int);void	io(void);void	*erealloc(void*, ulong);void	*emalloc(ulong);char	*estrdup(char*);void	usage(void);void	fidqid(Fid*, Qid*);char*	short2long(char*);char*	long2short(char*, int);void	readnames(void);void	post(char*, int); char	*rflush(Fid*), *rversion(Fid*), *rauth(Fid*),	*rattach(Fid*), *rwalk(Fid*),	*ropen(Fid*), *rcreate(Fid*),	*rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),	*rremove(Fid*), *rstat(Fid*), *rwstat(Fid*); char 	*(*fcalls[])(Fid*) = {	[Tversion]	rversion,	[Tflush]	rflush,	[Tauth]	rauth,	[Tattach]	rattach,	[Twalk]		rwalk,	[Topen]		ropen,	[Tcreate]	rcreate,	[Tread]		rread,	[Twrite]	rwrite,	[Tclunk]	rclunk,	[Tremove]	rremove,	[Tstat]		rstat,	[Twstat]	rwstat,}; char	Eperm[] =	"permission denied";char	Enotdir[] =	"not a directory";char	Enoauth[] =	"lnfs: authentication not required";char	Enotexist[] =	"file does not exist";char	Einuse[] =	"file in use";char	Eexist[] =	"file exists";char	Eisdir[] =	"file is a directory";char	Enotowner[] =	"not owner";char	Eisopen[] = 	"file already open for I/O";char	Excl[] = 	"exclusive use file already open";char	Ename[] = 	"illegal name";char	Eversion[] =	"unknown 9P version"; voidusage(void){	fprint(2, "usage: %s [-r] [-s srvname] mountpoint\n", argv0);	exits("usage");} voidnotifyf(void *a, char *s){	USED(a);	if(strncmp(s, "interrupt", 9) == 0)		noted(NCONT);	noted(NDFLT);} voidmain(int argc, char *argv[]){	char *defmnt;	int p[2];	Dir *d; 	ARGBEGIN{	case 'r':		readonly = 1;		break;	case 'd':		debug = 1;		break;	case 's':		srvname = ARGF();		if(srvname == nil)			usage();		break;	default:		usage();	}ARGEND 	if(argc < 1)		usage();	defmnt = argv[0];	d = dirstat(defmnt);	if(d == nil || !(d->qid.type & QTDIR))		sysfatal("mountpoint must be an accessible directory");	free(d); 	if(pipe(p) < 0)		sysfatal("pipe failed");	mfd[0] = p[0];	mfd[1] = p[0]; 	user = getuser();	notify(notifyf); 	if(srvname != nil)		post(srvname, p[1]); 	if(debug)		fmtinstall('F', fcallfmt);	switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){	case -1:		sysfatal("fork: %r");	case 0:		close(p[1]);		chdir(defmnt);		io();		break;	default:		close(p[0]);	/* don't deadlock if child fails */		if(mount(p[1], -1, defmnt, MREPL|MCREATE, "") < 0)			sysfatal("mount failed: %r");	}	exits(0);} voidpost(char *srvname, int pfd){	char name[128];	int fd; 	snprint(name, sizeof name, "#s/%s", srvname);	fd = create(name, OWRITE, 0666);	if(fd < 0)		sysfatal("create of %s failed: %r", srvname);	sprint(name, "%d", pfd);	if(write(fd, name, strlen(name)) < 0)		sysfatal("writing %s: %r", srvname);}char*rversion(Fid*){	Fid *f; 	for(f = fids; f; f = f->next)		if(f->busy)			rclunk(f);	if(thdr.msize > sizeof mdata)		rhdr.msize = sizeof mdata;	else		rhdr.msize = thdr.msize;	messagesize = rhdr.msize;	if(strncmp(thdr.version, "9P2000", 6) != 0)		return Eversion;	rhdr.version = "9P2000";	return nil;} char*rauth(Fid*){	return Enoauth;} char*rflush(Fid *f){	USED(f);	return nil;} char*rattach(Fid *f){	/* no authentication! */	f->busy = 1;	if(thdr.uname[0])		f->user = estrdup(thdr.uname);	else		f->user = "none";	if(strcmp(user, "none") == 0)		user = f->user;	if(f->path)		s_free(f->path);	f->path = s_copy(".");	fidqid(f, &rhdr.qid);	f->attach = 1;	return nil;} char*clone(Fid *f, Fid **nf){	if(f->fd >= 0)		return Eisopen;	*nf = newfid(thdr.newfid);	(*nf)->busy = 1;	if((*nf)->path)		s_free((*nf)->path);	(*nf)->path = s_clone(f->path);	(*nf)->fd = -1;	(*nf)->user = f->user;	(*nf)->attach = 0;	return nil;} char*rwalk(Fid *f){	char *name;	Fid *nf;	char *err;	int i;	String *npath;	Dir *d;	char *cp;	Qid qid; 	err = nil;	nf = nil;	rhdr.nwqid = 0;	if(rhdr.newfid != rhdr.fid){		err = clone(f, &nf);		if(err)			return err;		f = nf;	/* walk the new fid */	}	readnames();	npath = s_clone(f->path);	if(thdr.nwname > 0){		for(i=0; i<thdr.nwname && i<MAXWELEM; i++){			name = long2short(thdr.wname[i], 0);			if(strcmp(name, ".") == 0){				;			} else if(strcmp(name, "..") == 0){				cp = strrchr(s_to_c(npath), '/');				if(cp != nil){					*cp = 0;					npath->ptr = cp;				}			} else {				s_append(npath, "/");				s_append(npath, name);			}			d = dirstat(s_to_c(npath));			if(d == nil)				break;			rhdr.nwqid++;			qid = d->qid;			rhdr.wqid[i] = qid;			free(d);		}		if(i==0 && err == nil)			err = Enotexist;	} 	/* if there was an error and we cloned, get rid of the new fid */	if(nf != nil && (err!=nil || rhdr.nwqid<thdr.nwname)){		f->busy = 0;		s_free(npath);	} 	/* update the fid after a successful walk */	if(rhdr.nwqid == thdr.nwname){		s_free(f->path);		f->path = npath;	}	return err;} static char*passerror(void){	static char err[256]; 	rerrstr(err, sizeof err);	return err;} char*ropen(Fid *f){	if(readonly && (thdr.mode & 3))		return Eperm;	if(f->fd >= 0)		return Eisopen;	f->fd = open(s_to_c(f->path), thdr.mode);	if(f->fd < 0)		return passerror();	fidqid(f, &rhdr.qid);	f->qid = rhdr.qid;	rhdr.iounit = messagesize-IOHDRSZ;	return nil;} char*rcreate(Fid *f){	char *name; 	if(readonly)		return Eperm;	readnames();	name = long2short(thdr.name, 1);	if(f->fd >= 0)		return Eisopen;	s_append(f->path, "/");	s_append(f->path, name);	f->fd = create(s_to_c(f->path), thdr.mode, thdr.perm);	if(f->fd < 0)		return passerror();	fidqid(f, &rhdr.qid);	f->qid = rhdr.qid;	rhdr.iounit = messagesize-IOHDRSZ;	return nil;} char*rreaddir(Fid *f){	int i;	int n; 	/* reread the directory */	if(thdr.offset == 0){		if(f->dir)			free(f->dir);		f->dir = nil;		if(f->diroff != 0)			seek(f->fd, 0, 0);		f->ndir = dirreadall(f->fd, &f->dir);		f->diroff = 0;		if(f->ndir < 0)			return passerror();		readnames();		for(i = 0; i < f->ndir; i++)			f->dir[i].name = short2long(f->dir[i].name);	} 	/* copy in as many directory entries as possible */	for(n = 0; f->diroff < f->ndir; n += i){		i = convD2M(&f->dir[f->diroff], rdata+n, thdr.count - n);		if(i <= BIT16SZ)			break;		f->diroff++;	}	rhdr.data = (char*)rdata;	rhdr.count = n;	return nil;} char*rread(Fid *f){	long n; 	if(f->fd < 0)		return Enotexist;	if(thdr.count > messagesize-IOHDRSZ)		thdr.count = messagesize-IOHDRSZ;	if(f->qid.type & QTDIR)		return rreaddir(f);	n = pread(f->fd, rdata, thdr.count, thdr.offset);	if(n < 0)		return passerror();	rhdr.data = (char*)rdata;	rhdr.count = n;	return nil;} char*rwrite(Fid *f){	long n; 	if(readonly || (f->qid.type & QTDIR))		return Eperm;	if(f->fd < 0)		return Enotexist;	if(thdr.count > messagesize-IOHDRSZ)	/* shouldn't happen, anyway */		thdr.count = messagesize-IOHDRSZ;	n = pwrite(f->fd, thdr.data, thdr.count, thdr.offset);	if(n < 0)		return passerror();	rhdr.count = n;	return nil;} char*rclunk(Fid *f){	f->busy = 0;	close(f->fd);	f->fd = -1;	f->path = s_reset(f->path);	if(f->attach){		free(f->user);		f->user = nil;	}	f->attach = 0;	if(f->dir != nil){		free(f->dir);		f->dir = nil;	}	f->diroff = f->ndir = 0;	return nil;} char*rremove(Fid *f){	if(remove(s_to_c(f->path)) < 0)		return passerror();	return nil;} char*rstat(Fid *f){	int n;	Dir *d; 	d = dirstat(s_to_c(f->path));	if(d == nil)		return passerror();	d->name = short2long(d->name);	n = convD2M(d, statbuf, sizeof statbuf);	free(d);	if(n <= BIT16SZ)		return passerror();	rhdr.nstat = n;	rhdr.stat = statbuf;	return nil;} char*rwstat(Fid *f){	int n;	Dir d; 	if(readonly)		return Eperm;	convM2D(thdr.stat, thdr.nstat, &d, (char*)rdata);	d.name = long2short(d.name, 1);	n = dirwstat(s_to_c(f->path), &d);

Lines 1–500 of 790.