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

📄 fs.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
#include "common.h"#include <auth.h>#include <fcall.h>#include <libsec.h>#include <ctype.h>#include "dat.h"enum{	OPERM	= 0x3,		// mask of all permission types in open mode};typedef struct Fid Fid;struct Fid{	Qid	qid;	short	busy;	short	open;	int	fid;	Fid	*next;	Mailbox	*mb;	Message	*m;	Message *mtop;		// top level message	//finger pointers to speed up reads of large directories	long	foff;	// offset/DIRLEN of finger	Message	*fptr;	// pointer to message at off	int	fvers;	// mailbox version when finger was saved};ulong	path;		// incremented for each new fileFid	*fids;int	mfd[2];char	user[Elemlen];int	messagesize = 4*1024*IOHDRSZ;uchar	mdata[8*1024*IOHDRSZ];uchar	mbuf[8*1024*IOHDRSZ];Fcall	thdr;Fcall	rhdr;int	fflg;char	*mntpt;int	biffing;int	plumbing = 1;QLock	mbllock;Mailbox	*mbl;Fid		*newfid(int);void		error(char*);void		io(void);void		*erealloc(void*, ulong);void		*emalloc(ulong);void		usage(void);void		reader(void);int		readheader(Message*, char*, int, int);int		cistrncmp(char*, char*, int);int		tokenconvert(String*, char*, int);String*		stringconvert(String*, char*, int);void		post(char*, char*, int);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,};char	Eperm[] =	"permission denied";char	Enotdir[] =	"not a directory";char	Enoauth[] =	"upas/fs: 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";char	Ebadctl[] =	"unknown control message";char *dirtab[] ={[Qdir]		".",[Qbody]		"body",[Qbcc]		"bcc",[Qcc]		"cc",[Qdate]		"date",[Qdigest]	"digest",[Qdisposition]	"disposition",[Qfilename]	"filename",[Qfrom]		"from",[Qheader]	"header",[Qinfo]		"info",[Qinreplyto]	"inreplyto",[Qlines]	"lines",[Qmimeheader]	"mimeheader",[Qmessageid]	"messageid",[Qraw]		"raw",[Qrawunix]	"rawunix",[Qrawbody]	"rawbody",[Qrawheader]	"rawheader",[Qreplyto]	"replyto",[Qsender]	"sender",[Qsubject]	"subject",[Qto]		"to",[Qtype]		"type",[Qunixdate]	"unixdate",[Qunixheader]	"unixheader",[Qctl]		"ctl",[Qmboxctl]	"ctl",};enum{	Hsize=	1277,};Hash	*htab[Hsize];int	debug;int	fflag;int	logging;voidusage(void){	fprint(2, "usage: upas/fs [-bdlnps] [-f mboxfile] [-m mountpoint]\n");	exits("usage");}voidnotifyf(void *a, char *s){	USED(a);	if(strncmp(s, "interrupt", 9) == 0)		noted(NCONT);	noted(NDFLT);}voidmain(int argc, char *argv[]){	int p[2], std, nodflt;	char maildir[128];	char mbox[128];	char *mboxfile, *err;	char srvfile[64];	int srvpost;	rfork(RFNOTEG);	mntpt = nil;	fflag = 0;	mboxfile = nil;	std = 0;	nodflt = 0;	srvpost = 0;	ARGBEGIN{	case 'b':		biffing = 1;		break;	case 'f':		fflag = 1;		mboxfile = EARGF(usage());		break;	case 'm':		mntpt = EARGF(usage());		break;	case 'd':		debug = 1;		break;	case 'p':		plumbing = 0;		break;	case 's':		srvpost = 1;		break;	case 'l':		logging = 1;		break;	case 'n':		nodflt = 1;		break;	default:		usage();	}ARGEND	if(argc)		usage();	if(pipe(p) < 0)		error("pipe failed");	mfd[0] = p[0];	mfd[1] = p[0];	notify(notifyf);	strcpy(user, getuser());	if(mntpt == nil){		snprint(maildir, sizeof(maildir), "/mail/fs");		mntpt = maildir;	}	if(mboxfile == nil && !nodflt){		snprint(mbox, sizeof(mbox), "/mail/box/%s/mbox", user);		mboxfile = mbox;		std = 1;	}	if(debug)		fmtinstall('F', fcallfmt);	if(mboxfile != nil){		err = newmbox(mboxfile, "mbox", std);		if(err != nil)			sysfatal("opening mailbox: %s", err);	}	switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG|RFREND)){	case -1:		error("fork");	case 0:		henter(PATH(0, Qtop), dirtab[Qctl],			(Qid){PATH(0, Qctl), 0, QTFILE}, nil, nil);		close(p[1]);		io();		postnote(PNGROUP, getpid(), "die yankee pig dog");		break;	default:		close(p[0]);	/* don't deadlock if child fails */		if(srvpost){			sprint(srvfile, "/srv/upasfs.%s", user);			post(srvfile, "upasfs", p[1]);		} else {			if(mount(p[1], -1, mntpt, MREPL, "") < 0)				error("mount failed");		}	}	exits(0);}static intfileinfo(Message *m, int t, char **pp){	char *p;	int len;	p = "";	len = 0;	switch(t){	case Qbody:		p = m->body;		len = m->bend - m->body;		break;	case Qbcc:		if(m->bcc822){			p = s_to_c(m->bcc822);			len = strlen(p);		}		break;	case Qcc:		if(m->cc822){			p = s_to_c(m->cc822);			len = strlen(p);		}		break;	case Qdisposition:		switch(m->disposition){		case Dinline:			p = "inline";			break;		case Dfile:			p = "file";			break;		}		len = strlen(p);		break;	case Qdate:		if(m->date822){			p = s_to_c(m->date822);			len = strlen(p);		} else if(m->unixdate != nil){			p = s_to_c(m->unixdate);			len = strlen(p);		}		break;	case Qfilename:		if(m->filename){			p = s_to_c(m->filename);			len = strlen(p);		}		break;	case Qinreplyto:		if(m->inreplyto822){			p = s_to_c(m->inreplyto822);			len = strlen(p);		}		break;	case Qmessageid:		if(m->messageid822){			p = s_to_c(m->messageid822);			len = strlen(p);		}		break;	case Qfrom:		if(m->from822){			p = s_to_c(m->from822);			len = strlen(p);		} else if(m->unixfrom != nil){			p = s_to_c(m->unixfrom);			len = strlen(p);		}		break;	case Qheader:		p = m->header;		len = headerlen(m);		break;	case Qlines:		p = m->lines;		if(*p == 0)			countlines(m);		len = strlen(m->lines);		break;	case Qraw:		p = m->start;		if(strncmp(m->start, "From ", 5) == 0){			p = strchr(p, '\n');			if(p == nil)				p = m->start;			else				p++;		}		len = m->end - p;		break;	case Qrawunix:		p = m->start;		len = m->end - p;		break;	case Qrawbody:		p = m->rbody;		len = m->rbend - p;		break;	case Qrawheader:		p = m->header;		len = m->hend - p;		break;	case Qmimeheader:		p = m->mheader;		len = m->mhend - p;		break;	case Qreplyto:		p = nil;		if(m->replyto822 != nil){			p = s_to_c(m->replyto822);			len = strlen(p);		} else if(m->from822 != nil){			p = s_to_c(m->from822);			len = strlen(p);		} else if(m->sender822 != nil){			p = s_to_c(m->sender822);			len = strlen(p);		} else if(m->unixfrom != nil){			p = s_to_c(m->unixfrom);			len = strlen(p);		}		break;	case Qsender:		if(m->sender822){			p = s_to_c(m->sender822);			len = strlen(p);		}		break;	case Qsubject:		p = nil;		if(m->subject822){			p = s_to_c(m->subject822);			len = strlen(p);		}		break;	case Qto:		if(m->to822){			p = s_to_c(m->to822);			len = strlen(p);		}		break;	case Qtype:		if(m->type){			p = s_to_c(m->type);			len = strlen(p);		}		break;	case Qunixdate:		if(m->unixdate){			p = s_to_c(m->unixdate);			len = strlen(p);		}		break;	case Qunixheader:		if(m->unixheader){			p = s_to_c(m->unixheader);			len = s_len(m->unixheader);		}		break;	case Qdigest:		if(m->sdigest){			p = s_to_c(m->sdigest);			len = strlen(p);		}		break;	}	*pp = p;	return len;}int infofields[] = {	Qfrom,	Qto,	Qcc,	Qreplyto,	Qunixdate,	Qsubject,	Qtype,	Qdisposition,	Qfilename,	Qdigest,	Qbcc,	Qinreplyto,	Qdate,	Qsender,	Qmessageid,	Qlines,	-1,};static intreadinfo(Message *m, char *buf, long off, int count){	char *p;	int len, i, n;	String *s;	s = s_new();	len = 0;	for(i = 0; len < count && infofields[i] >= 0; i++){		n = fileinfo(m, infofields[i], &p);		s = stringconvert(s, p, n);		s_append(s, "\n");		p = s_to_c(s);		n = strlen(p);		if(off > 0){			if(off >= n){				off -= n;				continue;			}			p += off;			n -= off;			off = 0;		}		if(n > count - len)			n = count - len;		if(buf)			memmove(buf+len, p, n);		len += n;	}	s_free(s);	return len;}static voidmkstat(Dir *d, Mailbox *mb, Message *m, int t){	char *p;	d->uid = user;	d->gid = user;	d->muid = user;	d->mode = 0444;	d->qid.vers = 0;	d->qid.type = QTFILE;	d->type = 0;	d->dev = 0;	if(mb != nil && mb->d != nil){		d->atime = mb->d->atime;		d->mtime = mb->d->mtime;	} else {		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 Qmbox:		d->name = mb->name;		d->mode = DMDIR|0555;		d->length = 0;		d->qid.path = PATH(mb->id, Qmbox);		d->qid.type = QTDIR;		d->qid.vers = mb->vers;		break;	case Qdir:		d->name = m->name;		d->mode = DMDIR|0555;		d->length = 0;		d->qid.path = PATH(m->id, Qdir);		d->qid.type = QTDIR;		break;	case Qctl:		d->name = dirtab[t];		d->mode = 0666;		d->atime = d->mtime = time(0);		d->length = 0;		d->qid.path = PATH(0, Qctl);		break;	case Qmboxctl:		d->name = dirtab[t];		d->mode = 0222;		d->atime = d->mtime = time(0);		d->length = 0;		d->qid.path = PATH(mb->id, Qmboxctl);		break;	case Qinfo:		d->name = dirtab[t];		d->length = readinfo(m, nil, 0, 1<<30);		d->qid.path = PATH(m->id, t);		break;	default:		d->name = dirtab[t];		d->length = fileinfo(m, t, &p);		d->qid.path = PATH(m->id, t);		break;	}}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->busy)			rclunk(f);	return nil;}char*rauth(Fid*){	return Enoauth;}char*rflush(Fid *f){	USED(f);	return 0;}char*rattach(Fid *f){	f->busy = 1;	f->m = nil;	f->mb = nil;	f->qid.path = PATH(0, Qtop);	f->qid.type = QTDIR;	f->qid.vers = 0;	rhdr.qid = f->qid;	if(strcmp(thdr.uname, user) != 0)		return Eperm;	return 0;}static Fid*doclone(Fid *f, int nfid){	Fid *nf;	nf = newfid(nfid);	if(nf->busy)		return nil;	nf->busy = 1;	nf->open = 0;	nf->m = f->m;	nf->mtop = f->mtop;	nf->mb = f->mb;	if(f->mb != nil)		mboxincref(f->mb);	if(f->mtop != nil){		qlock(f->mb);		msgincref(f->mtop);		qunlock(f->mb);	}	nf->qid = f->qid;	return nf;}char*dowalk(Fid *f, char *name){	int t;	Mailbox *omb, *mb;	char *rv, *p;	Hash *h;	t = FILE(f->qid.path);	rv = Enotexist;	omb = f->mb;	if(omb)		qlock(omb);	else		qlock(&mbllock);	// this must catch everything except . and ..retry:	h = hlook(f->qid.path, name);	if(h != nil){		f->mb = h->mb;		f->m = h->m;		switch(t){		case Qtop:			if(f->mb != nil)				mboxincref(f->mb);			break;		case Qmbox:			if(f->m){				msgincref(f->m);				f->mtop = f->m;			}			break;		}		f->qid = h->qid;		rv = nil;	} else if((p = strchr(name, '.')) != nil && *name != '.'){		*p = 0;		goto retry;	}	if(omb)		qunlock(omb);	else		qunlock(&mbllock);	if(rv == nil)		return rv;	if(strcmp(name, ".") == 0)		return nil;	if(f->qid.type != QTDIR)		return Enotdir;	if(strcmp(name, "..") == 0){		switch(t){		case Qtop:			f->qid.path = PATH(0, Qtop);			f->qid.type = QTDIR;			f->qid.vers = 0;			break;		case Qmbox:			f->qid.path = PATH(0, Qtop);			f->qid.type = QTDIR;			f->qid.vers = 0;			qlock(&mbllock);			mb = f->mb;			f->mb = nil;			mboxdecref(mb);			qunlock(&mbllock);			break;		case Qdir:			qlock(f->mb);			if(f->m->whole == f->mb->root){				f->qid.path = PATH(f->mb->id, Qmbox);				f->qid.type = QTDIR;				f->qid.vers = f->mb->d->qid.vers;				msgdecref(f->mb, f->mtop);				f->m = f->mtop = nil;			} else {				f->m = f->m->whole;				f->qid.path = PATH(f->m->id, Qdir);				f->qid.type = QTDIR;			}			qunlock(f->mb);			break;		}		rv = nil;	}	return rv;}char*rwalk(Fid *f){	Fid *nf;	char *rv;	int i;	if(f->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){	int file;	if(f->open)		return Eisopen;	file = FILE(f->qid.path);	if(thdr.mode != OREAD)		if(file != Qctl && file != Qmboxctl)			return Eperm;	// make sure we've decoded	if(file == Qbody){		if(f->m->decoded == 0)			decode(f->m);		if(f->m->converted == 0)			convert(f->m);	}	rhdr.iounit = 0;	rhdr.qid = f->qid;	f->open = 1;	return 0;}char *rcreate(Fid*){	return Eperm;}intreadtopdir(Fid*, uchar *buf, long off, int cnt, int blen){	Dir d;	int m, n;	long pos;	Mailbox *mb;	n = 0;	pos = 0;	mkstat(&d, nil, nil, Qctl);	m = convD2M(&d, &buf[n], blen);	if(off <= pos){		if(m <= BIT16SZ || m > cnt)			return 0;		n += m;		cnt -= m;	}	pos += m;			for(mb = mbl; mb != nil; mb = mb->next){		mkstat(&d, mb, nil, Qmbox);		m = convD2M(&d, &buf[n], blen-n);		if(off <= pos){			if(m <= BIT16SZ || m > cnt)				break;			n += m;			cnt -= m;		}

⌨️ 快捷键说明

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