521 lines · 8.7 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 "ratfs.h" /* *	9P protocol interface */ enum {	RELOAD = 0,		/* commands written to ctl file */	RDEBUG,	RNODEBUG,	RNONE,}; static void	rflush(Fcall*),		rnop(Fcall*),		rauth(Fcall*),	rattach(Fcall*),		rclone(Fcall*),		rwalk(Fcall*),		rclwalk(Fcall*),	ropen(Fcall*),		rcreate(Fcall*),	rread(Fcall*),		rwrite(Fcall*),		rclunk(Fcall*),		rremove(Fcall*),	rstat(Fcall*),		rwstat(Fcall*),	rversion(Fcall*); static	Fid*	newfid(int);static	void	reply(Fcall*, char*); static	void 	(*fcalls[])(Fcall*) = {	[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,};  static	Keyword cmds[] = {	"reload",		RELOAD,	"debug",		RDEBUG,	"nodebug",		RNODEBUG,	0,			RNONE,}; /* *	Main protocol loop */voidio(void){	Fcall	rhdr;	int n;		for(;;){		n = read9pmsg(srvfd, rbuf, sizeof rbuf-1);		if(n <= 0)			fatal("mount read");		if(convM2S(rbuf, n, &rhdr) == 0){			if(debugfd >= 0)				fprint(2, "%s: malformed message\n", argv0);			continue;		}				if(debugfd >= 0)			fprint(debugfd, "<-%F\n", &rhdr);/**/ 		if(!fcalls[rhdr.type])			reply(&rhdr, "bad fcall type");		else			(*fcalls[rhdr.type])(&rhdr);	}} /* *	write a protocol reply to the client */static voidreply(Fcall *r, char *error){	int n; 	if(error == nil)		r->type++;	else {		r->type = Rerror;		r->ename = error;	}	if(debugfd >= 0)		fprint(debugfd, "->%F\n", r);/**/	n = convS2M(r, rbuf, sizeof rbuf);	if(n == 0)		sysfatal("convS2M: %r");	if(write(srvfd, rbuf, n) < 0)		sysfatal("reply: %r");}  /* *  lookup a fid. if not found, create a new one. */ static Fid*newfid(int fid){	Fid *f, *ff; 	static Fid *fids; 	ff = 0;	for(f = fids; f; f = f->next){		if(f->fid == fid){			if(!f->busy)				f->node = 0;			return f;		} else if(!ff && !f->busy)			ff = f;	}	if(ff == 0){		ff = mallocz(sizeof(*f), 1);		ff->next = fids;		fids = ff;	}	ff->node = 0;	ff->fid = fid;	return ff;} static voidrversion(Fcall *f){	f->version = "9P2000";	if(f->msize > MAXRPC)		f->msize = MAXRPC;	reply(f, 0);} static voidrauth(Fcall *f){	reply(f, "ratfs: authentication not required");} static voidrflush(Fcall *f){	reply(f, 0);} static voidrattach(Fcall *f){	Fid *fidp;	Dir *d; 	if((d=dirstat(conffile)) != nil && d->mtime > lastconftime)		getconf();	free(d);	if((d=dirstat(ctlfile)) != nil && d->mtime > lastctltime)		reload();	free(d);	cleantrusted(); 	fidp = newfid(f->fid);	fidp->busy = 1;	fidp->node = root;	fidp->name = root->d.name;	fidp->uid = atom(f->uname);	f->qid = root->d.qid;	reply(f,0);} static voidrclone(Fcall *f){	Fid *fidp, *nf; 	fidp = newfid(f->fid);	if(fidp->node && fidp->node->d.type == Dummynode){		reply(f, "can't clone an address");		return;	}	nf = newfid(f->newfid);	nf->busy = 1;	nf->node = fidp->node;	nf->uid = fidp->uid;	nf->name = fidp->name;	if(debugfd >= 0)		printfid(nf);	reply(f,0);} static voidrwalk(Fcall *f){	int i, j;	Fcall r;	Fid *fidp, *nf;	char *err; 	fidp = newfid(f->fid);	if(fidp->node && fidp->node->d.type == Dummynode){		reply(f, "can't walk an address node");		return;	}	if(f->fid == f->newfid)		nf = fidp;	else{		nf = newfid(f->newfid);		nf->busy = 1;		nf->node = fidp->node;		nf->uid = fidp->uid;		nf->name = fidp->name;		if(debugfd >= 0)			printfid(nf);	} 	err = nil;	for(i=0; i<f->nwname; i++){		err = walk(f->wname[i], nf);		if(err)			break;		r.wqid[i] = nf->node->d.qid;	}	 	if(i < f->nwname && f->fid != f->newfid){		nf->busy = 0;		nf->node = 0;		nf->name = 0;		nf->uid = 0;	}	if(i > 0 && i < f->nwname && f->fid == f->newfid){		/*		 * try to put things back;		 * we never get this sort of call from the kernel		 */		for(j=0; j<i; j++)			walk("..", nf);	}	memmove(f->wqid, r.wqid, sizeof f->wqid);	f->nwqid = i;	if(err && i==0)		reply(f, err);	else		reply(f, 0);} /* *	We don't have to do full permission checking because most files *	have restricted semantics: *		The ctl file is only writable *		All others, including directories, are only readable */static voidropen(Fcall *f){	Fid *fidp;	int mode; 	fidp = newfid(f->fid); 	if(debugfd >= 0)		printfid(fidp); 	mode = f->mode&(OREAD|OWRITE|ORDWR);	if(fidp->node->d.type == Ctlfile) {		if(mode != OWRITE) {				reply(f, "permission denied");			return;		}	} else	if (mode != OREAD) {		reply(f, "permission denied or operation not supported");		return;	} 	f->qid = fidp->node->d.qid;	fidp->open = 1;	reply(f, 0);} static intpermitted(Fid *fp, Node *np, int mask){	int mode; 	mode = np->d.mode;	return (fp->uid==np->d.uid && (mode&(mask<<6)))		|| (fp->uid==np->d.gid && (mode&(mask<<3)))		|| (mode&mask);} /* *	creates are only allowed in the "trusted" subdirectory *	we also assume that the groupid == the uid */static voidrcreate(Fcall *f){	Fid *fidp;	Node *np; 	fidp = newfid(f->fid);	np = fidp->node;	if((np->d.mode&DMDIR) == 0){		reply(f, "not a directory");		return;	} 	if(!permitted(fidp, np, AWRITE)) {		reply(f, "permission denied");		return;	} 	/* Ignore the supplied mode and force it to be non-writable */ 	np = newnode(np, f->name, Trustedtemp, 0444, trustedqid++);	if(trustedqid >= Qaddrfile)			/* wrap QIDs */		trustedqid = Qtrustedfile;	cidrparse(&np->ip, f->name);	f->qid = np->d.qid;	np->d.uid = fidp->uid;	np->d.gid = np->d.uid;	np->d.muid = np->d.muid;	fidp->node = np;	fidp->open = 1;	reply(f, 0);	return;} /* *	only directories can be read.  everthing else returns EOF. */static voidrread(Fcall *f){	long cnt;	Fid *fidp; 	cnt = f->count;	f->count = 0;	fidp = newfid(f->fid);	f->data = (char*)rbuf+IOHDRSZ;	if(fidp->open == 0) {		reply(f, "file not open");		return;	}	if ((fidp->node->d.mode&DMDIR) == 0){		reply(f, 0);				/*EOF*/		return;	}	if(cnt > MAXRPC)		cnt = MAXRPC; 	if(f->offset == 0)		fidp->dirindex = 0; 	switch(fidp->node->d.type) {	case Directory:	case Addrdir:	case Trusted:		f->count = dread(fidp, cnt);		break;	case IPaddr:	case Acctaddr:		f->count = hread(fidp, cnt);		break;	default:		reply(f, "can't read this type of file");		return;	}	reply(f, 0);}  /* * 	only the 'ctl' file in the top level directory is writable */ static voidrwrite(Fcall *f){	Fid *fidp;	int n;	char *err, *argv[10]; 	fidp = newfid(f->fid);	if(fidp->node->d.mode & DMDIR){		reply(f, "directories are not writable");		return;	}	if(fidp->open == 0) {		reply(f, "file not open");		return;	} 	if (!permitted(fidp, fidp->node, AWRITE)) {		reply(f, "permission denied");		return;	} 	f->data[f->count] = 0;			/* the extra byte in rbuf leaves room */	n = tokenize(f->data, argv, 10);	err = 0;	switch(findkey(argv[0], cmds)){	case RELOAD:		getconf();		reload();		break;	case RDEBUG:		if(n > 1){			debugfd = create(argv[1], OWRITE, 0666);			if(debugfd < 0)				err = "create failed";		} else			debugfd = 2;		break;	case RNODEBUG:		if(debugfd >= 0)			close(debugfd);		debugfd = -1;		break;	default:		err = "unknown command";		break;	}	reply(f, err);} static voidrclunk(Fcall *f){	Fid *fidp; 	fidp = newfid(f->fid);	fidp->open = 0;	fidp->busy = 0;	fidp->node = 0;	fidp->name = 0;	fidp->uid = 0;	reply(f, 0);} /* *  no files or directories are removable; this becomes clunk; */static voidrremove(Fcall *f){	Fid *fidp;	Node *dir, *np; 	fidp = newfid(f->fid);		/*	 * only trusted temporary files can be removed	 * and only by their owner.	 */	if(fidp->node->d.type != Trustedtemp){		reply(f, "can't be removed");		return;	}	if(fidp->uid != fidp->node->d.uid){		reply(f, "permission denied");		return;	}	dir = fidp->node->parent;	for(np = dir->children; np; np = np->sibs)		if(np->sibs == fidp->node)			break;	if(np)		np->sibs = fidp->node->sibs;	else		dir->children = fidp->node->sibs;	dir->count--;	free(fidp->node);	fidp->node = 0;	fidp->open = 0;	fidp->busy = 0;	fidp->name = 0;	fidp->uid = 0;	reply(f, 0);} static voidrstat(Fcall *f)

Lines 1–500 of 521.