⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fs.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include <u.h>#include <libc.h>#include <authsrv.h>#include <fcall.h>#include "tapefs.h"Fid	*fids;Ram	*ram;int	mfd[2];char	*user;uchar	mdata[Maxbuf+IOHDRSZ];int	messagesize = Maxbuf+IOHDRSZ;Fcall	rhdr;Fcall	thdr;ulong	path;Idmap	*uidmap;Idmap	*gidmap;int	replete;int	blocksize;		/* for 32v */int	verbose;int	newtap;		/* tap with time in sec */int	blocksize;Fid *	newfid(int);int	ramstat(Ram*, uchar*, int);void	io(void);void	usage(void);int	perm(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*) = {	[Tflush]	rflush,	[Tversion]		rversion,	[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[] =	"tapefs: authentication not required";char	Enotexist[] =	"file does not exist";char	Einuse[] =	"file in use";char	Eexist[] =	"file exists";char	Enotowner[] =	"not owner";char	Eisopen[] = 	"file already open for I/O";char	Excl[] = 	"exclusive use file already open";char	Ename[] = 	"illegal name";voidnotifyf(void *a, char *s){	USED(a);	if(strncmp(s, "interrupt", 9) == 0)		noted(NCONT);	noted(NDFLT);}voidmain(int argc, char *argv[]){	Ram *r;	char *defmnt;	int p[2];	char buf[TICKREQLEN];	fmtinstall('F', fcallfmt);	defmnt = "/n/tapefs";	ARGBEGIN{	case 'm':		defmnt = EARGF(usage());		break;	case 'p':			/* password file */		uidmap = getpass(EARGF(usage()));		break;	case 'g':			/* group file */		gidmap = getpass(EARGF(usage()));		break;	case 'v':		verbose++;		break;	case 'n':		newtap++;		break;	case 'b':		blocksize = atoi(EARGF(usage()));		break;	default:		usage();	}ARGEND	if(argc==0)		error("no file to mount");	user = getuser();	if(user == nil)		user = "dmr";	ram = r = (Ram *)emalloc(sizeof(Ram));	r->busy = 1;	r->data = 0;	r->ndata = 0;	r->perm = DMDIR | 0775;	r->qid.path = 0;	r->qid.vers = 0;	r->qid.type = QTDIR;	r->parent = 0;	r->child = 0;	r->next = 0;	r->user = user;	r->group = user;	r->atime = time(0);	r->mtime = r->atime;	r->replete = 0;	r->name = estrdup(".");	populate(argv[0]);	r->replete |= replete;	if(pipe(p) < 0)		error("pipe failed");	mfd[0] = mfd[1] = p[0];	notify(notifyf);	switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){	case -1:		error("fork");	case 0:		close(p[1]);		notify(notifyf);		io();		break;	default:		close(p[0]);	/* don't deadlock if child fails */		if(mount(p[1], -1, defmnt, MREPL|MCREATE, "") < 0) {			sprint(buf, "mount on `%s' failed", defmnt);			error(buf);		}	}	exits(0);}char*rversion(Fid *unused){	Fid *f;	USED(unused);	if(rhdr.msize < 256)		return "version: message too small";	if(rhdr.msize > messagesize)		rhdr.msize = messagesize;	else		messagesize = rhdr.msize;	thdr.msize = messagesize;	if(strncmp(rhdr.version, "9P2000", 6) != 0)		return "unrecognized 9P version";	thdr.version = "9P2000";	for(f = fids; f; f = f->next)		if(f->busy)			rclunk(f);	return 0;}char*rauth(Fid *unused){	USED(unused);	return Enoauth;}char*rflush(Fid *f){	USED(f);	return 0;}char*rattach(Fid *f){	/* no authentication! */	f->busy = 1;	f->rclose = 0;	f->ram = ram;	thdr.qid = f->ram->qid;	if(rhdr.uname[0])		f->user = strdup(rhdr.uname);	else		f->user = "none";	return 0;}char*rwalk(Fid *f){	Fid *nf;	Ram *r;	char *err;	char *name;	Ram *dir;	int i;	nf = nil;	if(f->ram->busy == 0)		return Enotexist;	if(f->open)		return Eisopen;	if(rhdr.newfid != rhdr.fid){		nf = newfid(rhdr.newfid);		nf->busy = 1;		nf->open = 0;		nf->rclose = 0;		nf->ram = f->ram;		nf->user = f->user;	/* no ref count; the leakage is minor */		f = nf;	}	thdr.nwqid = 0;	err = nil;	r = f->ram;	if(rhdr.nwname > 0){		for(i=0; i<rhdr.nwname; i++){			if((r->qid.type & QTDIR) == 0){				err = Enotdir;				break;			}			if(r->busy == 0){				err = Enotexist;				break;			}			r->atime = time(0);			name = rhdr.wname[i];			dir = r;			if(!perm(Pexec)){				err = Eperm;				break;			}			if(strcmp(name, "..") == 0){				r = dir->parent;   Accept:				if(i == MAXWELEM){					err = "name too long";					break;				} 				thdr.wqid[thdr.nwqid++] = r->qid;				continue;			}			if(!dir->replete)				popdir(dir);			for(r=dir->child; r; r=r->next)				if(r->busy && strcmp(name, r->name)==0)					goto Accept;			break;	/* file not found */		}		if(i==0 && err == nil)			err = Enotexist;	}	if(err!=nil || thdr.nwqid<rhdr.nwname){		if(nf){			nf->busy = 0;			nf->open = 0;			nf->ram = 0;		}	}else if(thdr.nwqid  == rhdr.nwname)		f->ram = r;	return err;}char *ropen(Fid *f){	Ram *r;	int mode, trunc;	if(f->open)		return Eisopen;	r = f->ram;	if(r->busy == 0)		return Enotexist;	if(r->perm & DMEXCL)		if(r->open)			return Excl;	mode = rhdr.mode;	if(r->qid.type & QTDIR){		if(mode != OREAD)			return Eperm;		thdr.qid = r->qid;		return 0;	}	if(mode & ORCLOSE)		return Eperm;	trunc = mode & OTRUNC;	mode &= OPERM;	if(mode==OWRITE || mode==ORDWR || trunc)		if(!perm(Pwrite))			return Eperm;	if(mode==OREAD || mode==ORDWR)		if(!perm(Pread))			return Eperm;	if(mode==OEXEC)		if(!perm(Pexec))			return Eperm;	if(trunc && (r->perm&DMAPPEND)==0){		r->ndata = 0;		dotrunc(r);		r->qid.vers++;	}	thdr.qid = r->qid;	thdr.iounit = messagesize-IOHDRSZ;	f->open = 1;	r->open++;	return 0;}char *rcreate(Fid *f){	USED(f);	return Eperm;}char*rread(Fid *f){	int i, len;	Ram *r;	char *buf;	uvlong off, end;	int n, cnt;	if(f->ram->busy == 0)		return Enotexist;	n = 0;	thdr.count = 0;	off = rhdr.offset;	end = rhdr.offset + rhdr.count;	cnt = rhdr.count;	if(cnt > messagesize-IOHDRSZ)		cnt = messagesize-IOHDRSZ;	buf = thdr.data;	if(f->ram->qid.type & QTDIR){		if(!f->ram->replete)			popdir(f->ram);		for(i=0,r=f->ram->child; r!=nil && i<end; r=r->next){			if(!r->busy)				continue;			len = ramstat(r, (uchar*)buf+n, cnt-n);			if(len <= BIT16SZ)				break;			if(i >= off)				n += len;			i += len;		}		thdr.count = n;		return 0;	}	r = f->ram;	if(off >= r->ndata)		return 0;	r->atime = time(0);	n = cnt;	if(off+n > r->ndata)		n = r->ndata - off;	thdr.data = doread(r, off, n);	thdr.count = n;	return 0;}char*rwrite(Fid *f){	Ram *r;	ulong off;	int cnt;	r = f->ram;	if(dopermw(f->ram)==0)		return Eperm;	if(r->busy == 0)		return Enotexist;	off = rhdr.offset;	if(r->perm & DMAPPEND)		off = r->ndata;	cnt = rhdr.count;	if(r->qid.type & QTDIR)		return "file is a directory";	if(off > 100*1024*1024)		/* sanity check */		return "write too big";	dowrite(r, rhdr.data, off, cnt);	r->qid.vers++;	r->mtime = time(0);	thdr.count = cnt;	return 0;}char *rclunk(Fid *f){	if(f->open)		f->ram->open--;	f->busy = 0;	f->open = 0;	f->ram = 0;	return 0;}char *rremove(Fid *f){	USED(f);	return Eperm;}char *rstat(Fid *f){	if(f->ram->busy == 0)		return Enotexist;	thdr.nstat = ramstat(f->ram, thdr.stat, messagesize-IOHDRSZ);	return 0;}char *rwstat(Fid *f){	if(f->ram->busy == 0)		return Enotexist;	return Eperm;}intramstat(Ram *r, uchar *buf, int nbuf){	Dir dir;	dir.name = r->name;	dir.qid = r->qid;	dir.mode = r->perm;	dir.length = r->ndata;	dir.uid = r->user;	dir.gid = r->group;	dir.muid = r->user;	dir.atime = r->atime;	dir.mtime = r->mtime;	return convD2M(&dir, buf, nbuf);}Fid *newfid(int fid){	Fid *f, *ff;	ff = 0;	for(f = fids; f; f = f->next)		if(f->fid == fid)			return f;		else if(!ff && !f->busy)			ff = f;	if(ff){		ff->fid = fid;		ff->open = 0;		ff->busy = 1;	}	f = emalloc(sizeof *f);	f->ram = 0;	f->fid = fid;	f->busy = 1;	f->open = 0;	f->next = fids;	fids = f;	return f;}voidio(void){	char *err;	int n, nerr;	char buf[ERRMAX];	errstr(buf, sizeof buf);	for(nerr=0, buf[0]='\0'; nerr<100; nerr++){		/*		 * reading from a pipe or a network device		 * will give an error after a few eof reads		 * however, we cannot tell the difference		 * between a zero-length read and an interrupt		 * on the processes writing to us,		 * so we wait for the error		 */		n = read9pmsg(mfd[0], mdata, sizeof mdata);		if(n==0)			continue;		if(n < 0){			if(buf[0]=='\0')				errstr(buf, sizeof buf);			continue;		}		nerr = 0;		buf[0] = '\0';		if(convM2S(mdata, n, &rhdr) != n)			error("convert error in convM2S");		if(verbose)			fprint(2, "tapefs: <=%F\n", &rhdr);/**/		thdr.data = (char*)mdata + IOHDRSZ;		thdr.stat = mdata + IOHDRSZ;		if(!fcalls[rhdr.type])			err = "bad fcall type";		else			err = (*fcalls[rhdr.type])(newfid(rhdr.fid));		if(err){			thdr.type = Rerror;			thdr.ename = err;		}else{			thdr.type = rhdr.type + 1;			thdr.fid = rhdr.fid;		}		thdr.tag = rhdr.tag;		n = convS2M(&thdr, mdata, messagesize);		if(n <= 0)			error("convert error in convS2M");		if(verbose)			fprint(2, "tapefs: =>%F\n", &thdr);/**/		if(write(mfd[1], mdata, n) != n)			error("mount write");	}	if(buf[0]=='\0' || strstr(buf, "hungup"))		exits("");	fprint(2, "%s: mount read: %s\n", argv0, buf);	exits(buf);}intperm(int p){	if(p==Pwrite)		return 0;	return 1;}voiderror(char *s){	fprint(2, "%s: %s: ", argv0, s);	perror("");	exits(s);}char*estrdup(char *s){	char *t;	t = emalloc(strlen(s)+1);	strcpy(t, s);	return t;}void *emalloc(ulong n){	void *p;	p = mallocz(n, 1);	if(!p)		error("out of memory");	return p;}void *erealloc(void *p, ulong n){	p = realloc(p, n);	if(!p)		error("out of memory");	return p;}voidusage(void){	fprint(2, "usage: %s [-s] [-m mountpoint]\n", argv0);	exits("usage");}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -