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

📄 fs.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include <u.h>#include <libc.h>#include <thread.h>#include <bio.h>#include <fcall.h>#include "object.h"extern int debug;extern int mfd[];enum {	DbgFs = 0x1000};typedef struct Fid Fid;enum {	Busy =	0x01,	Open =	0x02,	Endf =	0x04,};struct Fid{	QLock;	Qid	qid;	int	fid;	ushort	flags;	vlong	offset;		// offset of data[0]	Fid	*next;};Fcall	thdr;Fcall	rhdr;enum {	/* Files making up an object */	Qchildren,		/* Each of these must be in dirtab */	Qdigest,	Qfiles,	Qfulltext,	Qkey,	Qminiparentage,	Qparent,	Qparentage,	Qtext,	Qtype,	/* Other files */	Qtop,	/* Must follow Qtype */	Qclassical,	Qdir,	Qroot,	Qctl,};#define PATH(id, f)	(((id)<<8) | (f))#define FILE(p)		((p) & 0xff)#define NUM(p)		((p) >> 8)char *dirtab[] ={[Qchildren]	"children",[Qdigest]	"digest",[Qdir]		".",[Qfiles]	"files",[Qfulltext]	"fulltext",[Qkey]		"key",[Qminiparentage]"miniparentage",[Qparent]	"parent",[Qparentage]	"parentage",[Qtext]		"text",[Qtype]		"type",[Qtop]		nil,};char	*rflush(Fid*), *rauth(Fid*),	*rattach(Fid*), *rwalk(Fid*),	*ropen(Fid*), *rcreate(Fid*),	*rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),	*rremove(Fid*), *rstat(Fid*), *rwstat(Fid*),	*rversion(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,};int	messagesize = 8*1024+IOHDRSZ;uchar	mdata[8*1024+IOHDRSZ];uchar	mbuf[8*1024+IOHDRSZ];char	bigbuf[1<<23];	/* 8 megabytes */Fid	*fids;char	Eperm[] =	"permission denied";char	Enotdir[] =	"not a directory";char	Enoauth[] =	"no authentication 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";char	Ebadctl[] =	"unknown control message";Fid *newfid(int fid);static intlookup(char *cmd, char *list[]){	int i;	for (i = 0; list[i] != nil; i++)		if (strcmp(cmd, list[i]) == 0)			return i;	return -1;}char*rversion(Fid *){	Fid *f;	if(thdr.msize < 256)		return "max messagesize too small";	if(thdr.msize < messagesize)		messagesize = thdr.msize;	rhdr.msize = messagesize;	if(strncmp(thdr.version, "9P2000", 6) != 0)		return "unknown 9P version";	else		rhdr.version = "9P2000";	for(f = fids; f; f = f->next)		if(f->flags & Busy)			rclunk(f);	return nil;}char*rauth(Fid*){	return Enoauth;}char*rflush(Fid *){	return 0;}char*rattach(Fid *f){	f->flags |= Busy;	f->qid.type = QTDIR;	f->qid.vers = 0;	f->qid.path = PATH(0, Qtop);	rhdr.qid = f->qid;	return 0;}static Fid*doclone(Fid *f, int nfid){	Fid *nf;	nf = newfid(nfid);	nf->qid = f->qid;	if(nf->flags & Busy)		return nil;	nf->flags |= Busy;	nf->flags &= ~Open;	return nf;}char*dowalk(Fid *f, char *name){	int t, n, m;	char *rv, *p;	t = FILE(f->qid.path);	/* Type */	rv = Enotexist;	if(strcmp(name, ".") == 0 && f->qid.type == QTDIR)		return nil;	if(strcmp(name, "..") == 0){		switch(t){		case Qtop:		case Qclassical:			f->qid.path = PATH(0, Qtop);			f->qid.type = QTDIR;			f->qid.vers = 0;			rv = nil;			break;		case Qdir:		case Qroot:			f->qid.path = PATH(0, Qclassical);			f->qid.type = QTDIR;			f->qid.vers = 0;			rv = nil;			break;		}		return rv;	}	switch(t){	case Qtop:		/* Contains classical */		if(strcmp(name, "juke") == 0){			f->qid.path = PATH(root->tabno, Qclassical);			f->qid.type = QTDIR;			f->qid.vers = 0;			rv = nil;			break;		}		break;	case Qclassical:		/* main dir, contains `root' and object dirs */		if(strcmp(name, "root") == 0){			f->qid.path = PATH(root->tabno, Qroot);			f->qid.type = QTDIR;			f->qid.vers = 0;			rv = nil;			break;		}		if(strcmp(name, "ctl") == 0){			f->qid.path = PATH(root->tabno, Qctl);			f->qid.type = QTFILE;			f->qid.vers = 0;			rv = nil;			break;		}		n = strtol(name, &p, 0);		if(*p)			break;	/* Not a number */		if(n < 0 || n >= notab)			break;	/* Outside range */		if(otab[n] == nil)			break;	/* Not in object table */		f->qid.path = PATH(n, Qdir);		f->qid.type = QTDIR;		f->qid.vers = 0;		rv = nil;		break;	case Qroot:	/* Root of the object hierarchy */	case Qdir:	/* Object directory */		if((m = lookup(name, dirtab)) < 0)			break;		n = NUM(f->qid.path);		f->qid.path = PATH(n, m);		f->qid.type = QTFILE;		f->qid.vers = 0;		rv = nil;		break;	}	return rv;}char*rwalk(Fid *f){	Fid *nf;	char *rv;	int i;	if(f->flags & Open)		return Eisopen;	rhdr.nwqid = 0;	nf = nil;	/* clone if requested */	if(thdr.newfid != thdr.fid){		nf = doclone(f, thdr.newfid);		if(nf == nil)			return "new fid in use";		f = nf;	}	/* if it's just a clone, return */	if(thdr.nwname == 0 && nf != nil)		return nil;	/* walk each element */	rv = nil;	for(i = 0; i < thdr.nwname; i++){		rv = dowalk(f, thdr.wname[i]);		if(rv != nil){			if(nf != nil)					rclunk(nf);			break;		}		rhdr.wqid[i] = f->qid;	}	rhdr.nwqid = i;	/* we only error out if no walk  */	if(i > 0)		rv = nil;	return rv;}char *ropen(Fid *f){	if(f->flags & Open)		return Eisopen;	if(thdr.mode != OREAD && FILE(f->qid.path) != Qctl)		return Eperm;	rhdr.iounit = 0;	rhdr.qid = f->qid;	f->flags |= Open;	f->flags &= ~Endf;	return nil;}char *rcreate(Fid*){	return Eperm;}static longfileinfo(char *buf, int bufsize, int onum, int t){	long n;	n = 0;	switch(t){	case Qchildren:		n = printchildren(buf, bufsize, otab[onum]);		break;	case Qdigest:		n = printdigest(buf, bufsize, otab[onum]);		break;	case Qfulltext:		n = printfulltext(buf, bufsize, otab[onum]);		break;	case Qkey:		n = printkey(buf, bufsize, otab[onum]);		break;	case Qparent:		n = printparent(buf, bufsize, otab[onum]);		break;	case Qtext:		n = printtext(buf, bufsize, otab[onum]);		break;	case Qtype:		n = printtype(buf, bufsize, otab[onum]);		break;	case Qfiles:		n = printfiles(buf, bufsize, otab[onum]);		break;	case Qparentage:		n = printparentage(buf, bufsize, otab[onum]);		break;	case Qminiparentage:		n = printminiparentage(buf, bufsize, otab[onum]);		break;	default:		sysfatal("rread: %d", t);	}	return n;}static voidmkstat(Dir *d, int n, int t){	static char buf[16];	d->uid = user;	d->gid = user;	d->muid = user;	d->qid.vers = 0;	d->qid.type = QTFILE;	d->type = 0;	d->dev = 0;	d->atime = time(0);	d->mtime = d->atime;	switch(t){	case Qtop:		d->name = ".";		d->mode = DMDIR|0555;		d->atime = d->mtime = time(0);		d->length = 0;		d->qid.path = PATH(0, Qtop);		d->qid.type = QTDIR;		break;	case Qclassical:		d->name = "juke";		d->mode = DMDIR|0555;		d->atime = d->mtime = time(0);		d->length = 0;		d->qid.path = PATH(0, Qclassical);		d->qid.type = QTDIR;		break;	case Qdir:		snprint(buf, sizeof buf, "%d", n);		d->name = buf;		d->mode = DMDIR|0555;		d->length = 0;		d->qid.path = PATH(n, Qdir);		d->qid.type = QTDIR;		break;	case Qroot:		d->name = "root";		d->mode = DMDIR|0555;		d->length = 0;		d->qid.path = PATH(0, Qroot);		d->qid.type = QTDIR;		break;	case Qctl:		d->name = "ctl";		d->mode = 0666;		d->length = 0;		d->qid.path = PATH(0, Qctl);		break;		d->name = "ctl";		d->mode = 0666;		d->length = 0;		d->qid.path = PATH(0, Qctl);		break;	case Qchildren:	case Qdigest:	case Qfiles:	case Qfulltext:	case Qkey:	case Qminiparentage:	case Qparent:	case Qparentage:	case Qtext:	case Qtype:		d->name = dirtab[t];		d->mode = 0444;		d->length = fileinfo(bigbuf, sizeof bigbuf, n, t);		d->qid.path = PATH(n, t);		break;	default:		sysfatal("mkstat: %d", t);	}}intreadtopdir(Fid*, uchar *buf, long off, int cnt, int blen){	int m, n;	Dir d;	n = 0;	mkstat(&d, 0, Qclassical);	m = convD2M(&d, &buf[n], blen);	if(off <= 0){		if(m <= BIT16SZ || m > cnt)			return n;		n += m;	}	return n;}intreadclasdir(Fid*, uchar *buf, long off, int cnt, int blen){	int m, n;	long pos;	Dir d;	Fid *fid;	n = 0;	pos = 0;	mkstat(&d, 0, Qctl);	m = convD2M(&d, &buf[n], blen);	if(off <= pos){		if(m <= BIT16SZ || m > cnt)			return 0;		n += m;		cnt -= m;	}	pos += m;	mkstat(&d, 0, Qroot);	m = convD2M(&d, &buf[n], blen);	if(off <= pos){		if(m <= BIT16SZ || m > cnt)			return n;		n += m;		cnt -= m;	}	pos += m;	for (fid = fids; fid; fid = fid->next){		if(FILE(fid->qid.path) != Qdir)			continue;		mkstat(&d, NUM(fid->qid.path), Qdir);		m = convD2M(&d, &buf[n], blen-n);		if(off <= pos){			if(m <= BIT16SZ || m > cnt)				break;			n += m;			cnt -= m;		}		pos += m;	}	return n;}intreaddir(Fid *f, uchar *buf, long off, int cnt, int blen){	int i, m, n;	long pos;	Dir d;	n = 0;	pos = 0;	for (i = 0; i < Qtop; i++){		mkstat(&d, NUM(f->qid.path), i);		m = convD2M(&d, &buf[n], blen-n);		if(off <= pos){			if(m <= BIT16SZ || m > cnt)				break;			n += m;			cnt -= m;		}		pos += m;	}	return n;}voidreadbuf(char *s, long n){	rhdr.count = thdr.count;	if(thdr.offset >= n){		rhdr.count = 0;		return;	}	if(thdr.offset+rhdr.count > n)		rhdr.count = n - thdr.offset;	rhdr.data = s + thdr.offset;}char*rread(Fid *f){	long off;	int n, cnt, t;	rhdr.count = 0;	off = thdr.offset;	cnt = thdr.count;	if(cnt > messagesize - IOHDRSZ)		cnt = messagesize - IOHDRSZ;	rhdr.data = (char*)mbuf;	n = 0;	t = FILE(f->qid.path);	switch(t){	case Qtop:		n = readtopdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);		rhdr.count = n;		return nil;	case Qclassical:		n = readclasdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);		rhdr.count = n;		return nil;	case Qdir:	case Qroot:		n = readdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);		rhdr.count = n;		return nil;	case Qctl:		snprint(bigbuf, sizeof bigbuf, "%d objects in tree (%d holes)\n", notab, hotab);		break;	case Qchildren:	case Qdigest:	case Qfiles:	case Qfulltext:	case Qkey:	case Qminiparentage:	case Qparent:	case Qparentage:	case Qtext:	case Qtype:		n = fileinfo(bigbuf, sizeof bigbuf, NUM(f->qid.path), t);		break;	default:		sysfatal("rread: %d", t);	}	readbuf(bigbuf, n);	return nil;}char*rwrite(Fid *f){	long cnt;	char *p;	if(FILE(f->qid.path) != Qctl)		return Eperm;	rhdr.count = 0;	cnt = thdr.count;	if(p = strchr(thdr.data, '\n'))		*p = '\0';	if(strncmp(thdr.data, "quit", cnt) == 0)		threadexitsall(nil);	else if(strncmp(thdr.data, "reread", cnt) == 0)		reread();	else		return "illegal command";	rhdr.count = thdr.count;	return nil;}char *rclunk(Fid *f){	f->flags &= ~(Open|Busy);	return 0;}char *rremove(Fid *){	return Eperm;}char *rstat(Fid *f){	Dir d;	mkstat(&d, NUM(f->qid.path), FILE(f->qid.path));	rhdr.nstat = convD2M(&d, mbuf, messagesize - IOHDRSZ);	rhdr.stat = mbuf;	return 0;}char *rwstat(Fid*){	return Eperm;}Fid *newfid(int fid){	Fid *f, *ff;	ff = nil;	for(f = fids; f; f = f->next)		if(f->fid == fid){			return f;		}else if(ff == nil && (f->flags & Busy) == 0)			ff = f;	if(ff == nil){		ff = malloc(sizeof *ff);		if (ff == nil)			sysfatal("malloc: %r");		memset(ff, 0, sizeof *ff);		ff->next = fids;		fids = ff;	}	ff->fid = fid;	return ff;}voidio(void *){	char *err, e[32];	int n;	extern int p[];	Fid *f;	threadsetname("file server");	close(p[1]);	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, messagesize);		if(n == 0)			continue;		if(n < 0){			rerrstr(e, sizeof e);			if (strcmp(e, "interrupted") == 0){				if (debug & DbgFs) fprint(2, "read9pmsg interrupted\n");				continue;			}			return;		}		if(convM2S(mdata, n, &thdr) == 0)			continue;		if(debug & DbgFs)			fprint(2, "io:<-%F\n", &thdr);		rhdr.data = (char*)mbuf;		if(!fcalls[thdr.type])			err = "bad fcall type";		else {			f = newfid(thdr.fid);			err = (*fcalls[thdr.type])(f);		}		if(err){			rhdr.type = Rerror;			rhdr.ename = err;		}else{			rhdr.type = thdr.type + 1;			rhdr.fid = thdr.fid;		}		rhdr.tag = thdr.tag;		if(debug & DbgFs)			fprint(2, "io:->%F\n", &rhdr);/**/		n = convS2M(&rhdr, mdata, messagesize);		if(write(mfd[1], mdata, n) != n)			sysfatal("mount write");	}	threadexitsall("die yankee pig dog");}intnewid(void){	int rv;	static int id;	static Lock idlock;	lock(&idlock);	rv = ++id;	unlock(&idlock);	return rv;}

⌨️ 快捷键说明

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