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

📄 vacfs.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include "stdinc.h"#include <auth.h>#include <fcall.h>#include "vac.h"typedef struct Fid Fid;typedef struct DirBuf DirBuf;enum{	OPERM	= 0x3,		/* mask of all permission types in open mode */};enum{	DirBufSize = 20,};struct Fid{	short busy;	short open;	int fid;	char *user;	Qid qid;	VacFile *file;	DirBuf *db;	Fid	*next;};struct DirBuf{	VacDirEnum *vde;	VacDir buf[DirBufSize];	int i, n;	int eof;};enum{	Pexec =		1,	Pwrite = 	2,	Pread = 	4,	Pother = 	1,	Pgroup = 	8,	Powner =	64,};Fid	*fids;uchar	*data;int	mfd[2];char	*user;uchar	mdata[8192+IOHDRSZ];int messagesize = sizeof mdata;Fcall	rhdr;Fcall	thdr;VacFS	*fs;VtSession *session;int	noperm;Fid *	newfid(int);void	error(char*);void	io(void);void	shutdown(void);void	usage(void);int	perm(Fid*, int);int	permf(VacFile*, char*, int);ulong	getl(void *p);void	init(char*, char*, long, int);DirBuf	*dirBufAlloc(VacFile*);VacDir	*dirBufGet(DirBuf*);int	dirBufUnget(DirBuf*);void	dirBufFree(DirBuf*);int	vacdirread(Fid *f, char *p, long off, long cnt);int	vdStat(VacDir *vd, uchar *p, int np);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,	[Tattach]	rattach,	[Tauth]		rauth,	[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	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";char	Erdonly[] = 	"read only file system";char	Eio[] = 	"i/o error";char	Eempty[] = 	"directory is not empty";char	Emode[] =	"illegal mode";int dflag;voidnotifyf(void *a, char *s){	USED(a);	if(strncmp(s, "interrupt", 9) == 0)		noted(NCONT);	noted(NDFLT);}voidmain(int argc, char *argv[]){	char *defmnt, *defsrv, *srv;	int p[2];	char buf[12];	int fd;	int stdio = 0;	char *host = nil;	long ncache = 1000;	int readOnly = 1;	defmnt = "/n/vac";	defsrv = "vacfs";	ARGBEGIN{	case 'd':		fmtinstall('F', fcallfmt);		dflag = 1;		break;	case 'c':		ncache = atoi(ARGF());		break;	case 'i':		defmnt = nil;		stdio = 1;		mfd[0] = 0;		mfd[1] = 1;		break;	case 'h':		host = ARGF();		break;	case 'S':		defsrv = ARGF();		/*FALLTHROUGH*/	case 's':		defmnt = nil;		break;	case 'p':		noperm = 1;		break;	case 'm':		defmnt = ARGF();		break;	default:		usage();	}ARGEND	if(argc != 1)		usage();	vtAttach();	init(argv[0], host, ncache, readOnly);	if(pipe(p) < 0)		sysfatal("pipe failed: %r");	if(!stdio){		mfd[0] = p[0];		mfd[1] = p[0];		if(defmnt == 0){			srv = smprint("/srv/%s", defsrv);			fd = create(srv, OWRITE, 0666);			if(fd < 0)				sysfatal("create of %s failed: %r", srv);			sprint(buf, "%d", p[1]);			if(write(fd, buf, strlen(buf)) < 0)				sysfatal("writing %s: %r", srv);			free(srv);		}	}	switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){	case -1:		sysfatal("fork: %r");	case 0:		vtAttach();		close(p[1]);		io();		shutdown();		break;	default:		close(p[0]);	/* don't deadlock if child fails */		if(defmnt && mount(p[1], -1, defmnt, MREPL|MCREATE, "") < 0)			sysfatal("mount failed: %r");	}	vtDetach();	exits(0);}voidusage(void){	fprint(2, "usage: %s [-dips]"		" [-c ncache]"		" [-h host]"		" [-m mountpoint]"		" [-S srvname]"		" vacfile\n", argv0);	exits("usage");}char*rversion(Fid *unused){	Fid *f;	USED(unused);	for(f = fids; f; f = f->next)		if(f->busy)			rclunk(f);	if(rhdr.msize < 256)		return "version: message size too small";	messagesize = rhdr.msize;	if(messagesize > sizeof mdata)		messagesize = sizeof mdata;	thdr.msize = messagesize;	if(strncmp(rhdr.version, "9P2000", 6) != 0)		return "unrecognized 9P version";	thdr.version = "9P2000";	return nil;}char*rflush(Fid *f){	USED(f);	return 0;}char*rauth(Fid *f){	USED(f);	return "vacfs: authentication not required";}char*rattach(Fid *f){	/* no authentication for the momment */	VacFile *file;	file = vfsGetRoot(fs);	if(file == nil)		return vtGetError();	f->busy = 1;	f->file = file;	f->qid = (Qid){vfGetId(f->file), 0, QTDIR};	thdr.qid = f->qid;	if(rhdr.uname[0])		f->user = vtStrDup(rhdr.uname);	else		f->user = "none";	return 0;}VacFile*_vfWalk(VacFile *file, char *name){	VacFile *n;	n = vfWalk(file, name);	if(n)		return n;	if(strcmp(name, "SLASH") == 0)		return vfWalk(file, "/");	return nil;}char*rwalk(Fid *f){	VacFile *file, *nfile;	Fid *nf;	int nqid, nwname;	Qid qid;	if(f->busy == 0)		return Enotexist;	nf = nil;	if(rhdr.fid != rhdr.newfid){		if(f->open)			return Eisopen;		if(f->busy == 0)			return Enotexist;		nf = newfid(rhdr.newfid);		if(nf->busy)			return Eisopen;		nf->busy = 1;		nf->open = 0;		nf->qid = f->qid;		nf->file = vfIncRef(f->file);		nf->user = vtStrDup(f->user);		f = nf;	}	nwname = rhdr.nwname;	/* easy case */	if(nwname == 0) {		thdr.nwqid = 0;		return 0;	}	file = f->file;	vfIncRef(file);	qid = f->qid;	for(nqid = 0; nqid < nwname; nqid++){		if((qid.type & QTDIR) == 0){			vtSetError(Enotdir);			break;		}		if(!permf(file, f->user, Pexec)) {			vtSetError(Eperm);			break;		}		nfile = _vfWalk(file, rhdr.wname[nqid]);		if(nfile == nil)			break;		vfDecRef(file);		file = nfile;		qid.type = QTFILE;		if(vfIsDir(file))			qid.type = QTDIR;		qid.vers = vfGetMcount(file);		qid.path = vfGetId(file);		thdr.wqid[nqid] = qid;	}	thdr.nwqid = nqid;	if(nqid == nwname){		/* success */		f->qid = thdr.wqid[nqid-1];		vfDecRef(f->file);		f->file = file;		return 0;	}	vfDecRef(file);	if(nf != nil)		rclunk(nf);	/* only error on the first element */	if(nqid == 0)		return vtGetError();	return 0;}char *ropen(Fid *f){	int mode, trunc;	if(f->open)		return Eisopen;	if(!f->busy)		return Enotexist;	mode = rhdr.mode;	thdr.iounit = messagesize - IOHDRSZ;	if(f->qid.type & QTDIR){		if(mode != OREAD)			return Eperm;		if(!perm(f, Pread))			return Eperm;		thdr.qid = f->qid;		f->db = nil;		f->open = 1;		return 0;	}	if(mode & ORCLOSE)		return Erdonly;	trunc = mode & OTRUNC;	mode &= OPERM;	if(mode==OWRITE || mode==ORDWR || trunc)		if(!perm(f, Pwrite))			return Eperm;	if(mode==OREAD || mode==ORDWR)		if(!perm(f, Pread))			return Eperm;	if(mode==OEXEC)		if(!perm(f, Pexec))			return Eperm;	thdr.qid = f->qid;	thdr.iounit = messagesize - IOHDRSZ;	f->open = 1;	return 0;}char*rcreate(Fid* fid){	VacFile *vf;	ulong mode;	if(fid->open)		return Eisopen;	if(!fid->busy)		return Enotexist;	if(vfsIsReadOnly(fs))		return Erdonly;	vf = fid->file;	if(!vfIsDir(vf))		return Enotdir;	if(!permf(vf, fid->user, Pwrite))		return Eperm;	mode = rhdr.perm & 0777;	if(rhdr.perm & DMDIR){		if((rhdr.mode & OTRUNC) || (rhdr.perm & DMAPPEND))			return Emode;		switch(rhdr.mode & OPERM){		default:			return Emode;		case OEXEC:		case OREAD:			break;		case OWRITE:		case ORDWR:			return Eperm;		}		mode |= ModeDir;	}	vf = vfCreate(vf, rhdr.name, mode, "none");	if(vf == nil)		return vtGetError();	vfDecRef(fid->file);	fid->file = vf;	fid->qid.type = QTFILE;	if(vfIsDir(vf))		fid->qid.type = QTDIR;	fid->qid.vers = vfGetMcount(vf);	fid->qid.path = vfGetId(vf);	thdr.qid = fid->qid;	thdr.iounit = messagesize - IOHDRSZ;	return 0;}char*rread(Fid *f){	char *buf;	vlong off;	int cnt;	VacFile *vf;	char *err;	int n;	if(!f->busy)		return Enotexist;	vf = f->file;	thdr.count = 0;	off = rhdr.offset;	buf = thdr.data;	cnt = rhdr.count;	if(f->qid.type & QTDIR)		n = vacdirread(f, buf, off, cnt);	else		n = vfRead(vf, buf, cnt, off);	if(n < 0) {		err = vtGetError();		if(err == nil)			err = "unknown error!";		return err;	}	thdr.count = n;	return 0;}char*rwrite(Fid *f){	char *buf;	vlong off;	int cnt;	VacFile *vf;	if(!f->busy)		return Enotexist;	vf = f->file;	thdr.count = 0;	off = rhdr.offset;	buf = rhdr.data;	cnt = rhdr.count;	if(f->qid.type & QTDIR)		return "file is a directory";	cnt = vfWrite(vf, buf, cnt, off, "none");	if(cnt < 0) {fprint(2, "write failed: %s\n", vtGetError());		return vtGetError();	}	thdr.count = cnt;	return 0;}char *rclunk(Fid *f){	f->busy = 0;	f->open = 0;	vtMemFree(f->user);	f->user = nil;	vfDecRef(f->file);	f->file = nil;	dirBufFree(f->db);	f->db = nil;	return 0;}char *rremove(Fid *f){	VacFile *vf, *vfp;	char *err = nil;	if(!f->busy)		return Enotexist;	vf = f->file;	vfp = vfGetParent(vf);	if(!permf(vfp, f->user, Pwrite)) {		err = Eperm;		goto Exit;	}	if(!vfRemove(vf, "none")) {print("vfRemove failed\n");		err = vtGetError();	}Exit:	vfDecRef(vfp);	rclunk(f);	return err;}char *rstat(Fid *f){	VacDir dir;	static uchar statbuf[1024];	if(!f->busy)		return Enotexist;	vfGetDir(f->file, &dir);	thdr.stat = statbuf;	thdr.nstat = vdStat(&dir, thdr.stat, sizeof statbuf);	vdCleanup(&dir);	return 0;}char *rwstat(Fid *f){	if(!f->busy)		return Enotexist;	return Erdonly;}intvdStat(VacDir *vd, uchar *p, int np){	Dir dir;	memset(&dir, 0, sizeof(dir));	/*	 * Where do path and version come from	 */	dir.qid.path = vd->qid;	dir.qid.vers = vd->mcount;	dir.mode = vd->mode & 0777;	if(vd->mode & ModeAppend){		dir.qid.type |= QTAPPEND;		dir.mode |= DMAPPEND;	}	if(vd->mode & ModeExclusive){		dir.qid.type |= QTEXCL;		dir.mode |= DMEXCL;	}	if(vd->mode & ModeDir){		dir.qid.type |= QTDIR;		dir.mode |= DMDIR;	}	dir.atime = vd->atime;	dir.mtime = vd->mtime;	dir.length = vd->size;	dir.name = vd->elem;	dir.uid = vd->uid;	dir.gid = vd->gid;	dir.muid = vd->mid;	return convD2M(&dir, p, np);}DirBuf*dirBufAlloc(VacFile *vf){	DirBuf *db;	db = vtMemAllocZ(sizeof(DirBuf));	db->vde = vfDirEnum(vf);	return db;}VacDir *dirBufGet(DirBuf *db){	VacDir *vd;	int n;	if(db->eof)		return nil;	if(db->i >= db->n) {		n = vdeRead(db->vde, db->buf, DirBufSize);		if(n < 0)			return nil;		db->i = 0;		db->n = n;		if(n == 0) {			db->eof = 1;			return nil;		}	}	vd = db->buf + db->i;	db->i++;	return vd;}intdirBufUnget(DirBuf *db){	assert(db->i > 0);	db->i--;	return 1;}voiddirBufFree(DirBuf *db){	int i;	if(db == nil)		return;	for(i=db->i; i<db->n; i++)		vdCleanup(db->buf + i);	vdeFree(db->vde);	vtMemFree(db);}intvacdirread(Fid *f, char *p, long off, long cnt){	int n, nb;	VacDir *vd;	/*	 * special case of rewinding a directory	 * otherwise ignore the offset	 */	if(off == 0 && f->db) {		dirBufFree(f->db);		f->db = nil;	}	if(f->db == nil)		f->db = dirBufAlloc(f->file);	for(nb = 0; nb < cnt; nb += n) {		vd = dirBufGet(f->db);		if(vd == nil) {			if(!f->db->eof)				return -1;			break;		}		n = vdStat(vd, (uchar*)p, cnt-nb);		if(n <= BIT16SZ) {			dirBufUnget(f->db);			break;		}		vdCleanup(vd);		p += n;	}	return nb;}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;		return ff;	}	f = vtMemAllocZ(sizeof *f);	f->fid = fid;	f->next = fids;	fids = f;	return f;}voidio(void){	char *err;	int n;	for(;;){		/*		 * 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)			break;		if(convM2S(mdata, n, &rhdr) != n)			sysfatal("convM2S conversion error");		if(dflag)			fprint(2, "vacfs:<-%F\n", &rhdr);		thdr.data = (char*)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;		if(dflag)			fprint(2, "vacfs:->%F\n", &thdr);		n = convS2M(&thdr, mdata, messagesize);		if(write(mfd[1], mdata, n) != n)			sysfatal("mount write: %r");	}}intpermf(VacFile *vf, char *user, int p){	int ok = 1;	VacDir dir;	ulong perm;	if(!vfGetDir(vf, &dir))		return 0;	perm = dir.mode & 0777;	if(noperm)		goto Good;	if((p*Pother) & perm)		goto Good;	if(strcmp(user, dir.gid)==0 && ((p*Pgroup) & perm))		goto Good;	if(strcmp(user, dir.uid)==0 && ((p*Powner) & perm))		goto Good;	ok = 0;Good:	vdCleanup(&dir);	return ok;}intperm(Fid *f, int p){	return permf(f->file, f->user, p);}voidinit(char *file, char *host, long ncache, int readOnly){	notify(notifyf);	user = getuser();	fmtinstall('V', vtScoreFmt);	fmtinstall('R', vtErrFmt);	session = vtDial(host, 0);	if(session == nil)		vtFatal("could not connect to server: %s", vtGetError());	if(!vtConnect(session, 0))		vtFatal("vtConnect: %s", vtGetError());	fs = vfsOpen(session, file, readOnly, ncache);	if(fs == nil)		vtFatal("vfsOpen: %s", vtGetError());}voidshutdown(void){	Fid *f;	for(f = fids; f; f = f->next) {		if(!f->busy)			continue;fprint(2, "open fid: %d\n", f->fid);		rclunk(f);	}	vfsClose(fs);	vtClose(session);}

⌨️ 快捷键说明

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