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

📄 fsys.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <u.h>#include <libc.h>#include <bio.h>#include <regexp.h>#include <thread.h>#include <auth.h>#include <fcall.h>#include <plumb.h>#include "plumber.h"enum{	Stack = 8*1024};typedef struct Dirtab Dirtab;typedef struct Fid Fid;typedef struct Holdq Holdq;typedef struct Readreq Readreq;typedef struct Sendreq Sendreq;struct Dirtab{	char		*name;	uchar	type;	uint		qid;	uint		perm;	int		nopen;		/* #fids open on this port */	Fid		*fopen;	Holdq	*holdq;	Readreq	*readq;	Sendreq	*sendq;};struct Fid{	int		fid;	int		busy;	int		open;	int		mode;	Qid		qid;	Dirtab	*dir;	long		offset;		/* zeroed at beginning of each message, read or write */	char		*writebuf;		/* partial message written so far; offset tells how much */	Fid		*next;	Fid		*nextopen;};struct Readreq{	Fid		*fid;	Fcall		*fcall;	uchar	*buf;	Readreq	*next;};struct Sendreq{	int			nfid;		/* number of fids that should receive this message */	int			nleft;		/* number left that haven't received it */	Fid			**fid;	/* fid[nfid] */	Plumbmsg	*msg;	char			*pack;	/* plumbpack()ed message */	int			npack;	/* length of pack */	Sendreq		*next;};struct Holdq{	Plumbmsg	*msg;	Holdq		*next;};struct	/* needed because incref() doesn't return value */{	Lock;	int			ref;} rulesref;enum{	DEBUG	= 0,	NDIR	= 50,	Nhash	= 16,	Qdir		= 0,	Qrules	= 1,	Qsend	= 2,	Qport	= 3,	NQID	= Qport};static Dirtab dir[NDIR] ={	{ ".",			QTDIR,	Qdir,			0500|DMDIR },	{ "rules",		QTFILE,	Qrules,		0600 },	{ "send",		QTFILE,	Qsend,		0200 },};static int	ndir = NQID;static int		srvfd;static int		srvclosefd;			/* rock for end of pipe to close */static int		clockfd;static int		clock;static Fid		*fids[Nhash];static QLock	readlock;static QLock	queue;static char	srvfile[128];static int		messagesize = 8192+IOHDRSZ;	/* good start */static void	fsysproc(void*);static void fsysrespond(Fcall*, uchar*, char*);static Fid*	newfid(int);static Fcall* fsysflush(Fcall*, uchar*, Fid*);static Fcall* fsysversion(Fcall*, uchar*, Fid*);static Fcall* fsysauth(Fcall*, uchar*, Fid*);static Fcall* fsysattach(Fcall*, uchar*, Fid*);static Fcall* fsyswalk(Fcall*, uchar*, Fid*);static Fcall* fsysopen(Fcall*, uchar*, Fid*);static Fcall* fsyscreate(Fcall*, uchar*, Fid*);static Fcall* fsysread(Fcall*, uchar*, Fid*);static Fcall* fsyswrite(Fcall*, uchar*, Fid*);static Fcall* fsysclunk(Fcall*, uchar*, Fid*);static Fcall* fsysremove(Fcall*, uchar*, Fid*);static Fcall* fsysstat(Fcall*, uchar*, Fid*);static Fcall* fsyswstat(Fcall*, uchar*, Fid*);Fcall* 	(*fcall[Tmax])(Fcall*, uchar*, Fid*) ={	[Tflush]	= fsysflush,	[Tversion]	= fsysversion,	[Tauth]	= fsysauth,	[Tattach]	= fsysattach,	[Twalk]	= fsyswalk,	[Topen]	= fsysopen,	[Tcreate]	= fsyscreate,	[Tread]	= fsysread,	[Twrite]	= fsyswrite,	[Tclunk]	= fsysclunk,	[Tremove]= fsysremove,	[Tstat]	= fsysstat,	[Twstat]	= fsyswstat,};char	Ebadfcall[] =	"bad fcall type";char	Eperm[] = 	"permission denied";char	Enomem[] =	"malloc failed for buffer";char	Enotdir[] =	"not a directory";char	Enoexist[] =	"plumb file does not exist";char	Eisdir[] =		"file is a directory";char	Ebadmsg[] =	"bad plumb message format";char Enosuchport[] ="no such plumb port";char Enoport[] =	"couldn't find destination for message";char	Einuse[] = 	"file already open";/* * Add new port.  A no-op if port already exists or is the null string */voidaddport(char *port){	int i;	if(port == nil)		return;	for(i=NQID; i<ndir; i++)		if(strcmp(port, dir[i].name) == 0)			return;	if(i == NDIR){		fprint(2, "plumb: too many ports; max %d\n", NDIR);		return;	}	ndir++;	dir[i].name = estrdup(port);	dir[i].qid = i;	dir[i].perm = 0400;	nports++;	ports = erealloc(ports, nports*sizeof(char*));	ports[nports-1] = dir[i].name;}static ulonggetclock(void){	char buf[32];	seek(clockfd, 0, 0);	read(clockfd, buf, sizeof buf);	return atoi(buf);}voidstartfsys(void){	int p[2], fd;	fmtinstall('F', fcallfmt);	clockfd = open("/dev/time", OREAD|OCEXEC);	clock = getclock();	if(pipe(p) < 0)		error("can't create pipe: %r");	/* 0 will be server end, 1 will be client end */	srvfd = p[0];	srvclosefd = p[1];	sprint(srvfile, "/srv/plumb.%s.%d", user, getpid());	if(putenv("plumbsrv", srvfile) < 0)		error("can't write $plumbsrv: %r");	fd = create(srvfile, OWRITE|OCEXEC|ORCLOSE, 0600);	if(fd < 0)		error("can't create /srv file: %r");	if(fprint(fd, "%d", p[1]) <= 0)		error("can't write /srv/file: %r");	/* leave fd open; ORCLOSE will take care of it */	procrfork(fsysproc, nil, Stack, RFFDG);	close(p[0]);	if(mount(p[1], -1, "/mnt/plumb", MREPL, "") < 0)		error("can't mount /mnt/plumb: %r");	close(p[1]);}static voidfsysproc(void*){	int n;	Fcall *t;	Fid *f;	uchar *buf;	close(srvclosefd);	srvclosefd = -1;	t = nil;	for(;;){		buf = malloc(messagesize);	/* avoid memset of emalloc */		if(buf == nil)			error("malloc failed: %r");		qlock(&readlock);		n = read9pmsg(srvfd, buf, messagesize);		if(n <= 0){			if(n < 0)				error("i/o error on server channel");			threadexitsall("unmounted");		}		if(readlock.head == nil)	/* no other processes waiting to read; start one */			proccreate(fsysproc, nil, Stack);		qunlock(&readlock);		if(t == nil)			t = emalloc(sizeof(Fcall));		if(convM2S(buf, n, t) != n)			error("convert error in convM2S");		if(DEBUG)			fprint(2, "<= %F\n", t);		if(fcall[t->type] == nil)			fsysrespond(t, buf, Ebadfcall);		else{			if(t->type==Tversion || t->type==Tauth)				f = nil;			else				f = newfid(t->fid);			t = (*fcall[t->type])(t, buf, f);		}	}}static voidfsysrespond(Fcall *t, uchar *buf, char *err){	int n;	if(err){		t->type = Rerror;		t->ename = err;	}else		t->type++;	if(buf == nil)		buf = emalloc(messagesize);	n = convS2M(t, buf, messagesize);	if(n < 0)		error("convert error in convS2M");	if(write(srvfd, buf, n) != n)		error("write error in respond");	if(DEBUG)		fprint(2, "=> %F\n", t);	free(buf);}staticFid*newfid(int fid){	Fid *f, *ff, **fh;	qlock(&queue);	ff = nil;	fh = &fids[fid&(Nhash-1)];	for(f=*fh; f; f=f->next)		if(f->fid == fid)			goto Return;		else if(ff==nil && !f->busy)			ff = f;	if(ff){		ff->fid = fid;		f = ff;		goto Return;	}	f = emalloc(sizeof *f);	f->fid = fid;	f->next = *fh;	*fh = f;    Return:	qunlock(&queue);	return f;}static uintdostat(Dirtab *dir, uchar *buf, uint nbuf, uint clock){	Dir d;	d.qid.type = dir->type;	d.qid.path = dir->qid;	d.qid.vers = 0;	d.mode = dir->perm;	d.length = 0;	/* would be nice to do better */	d.name = dir->name;	d.uid = user;	d.gid = user;	d.muid = user;	d.atime = clock;	d.mtime = clock;	return convD2M(&d, buf, nbuf);}static voidqueuesend(Dirtab *d, Plumbmsg *m){	Sendreq *s, *t;	Fid *f;	int i;	s = emalloc(sizeof(Sendreq));	s->nfid = d->nopen;	s->nleft = s->nfid;	s->fid = emalloc(s->nfid*sizeof(Fid*));	i = 0;	/* build array of fids open on this channel */	for(f=d->fopen; f!=nil; f=f->nextopen)		s->fid[i++] = f;	s->msg = m;	s->next = nil;	/* link to end of queue; drainqueue() searches in sender order so this implements a FIFO */	for(t=d->sendq; t!=nil; t=t->next)		if(t->next == nil)			break;	if(t == nil)		d->sendq = s;	else		t->next = s;}static voidqueueread(Dirtab *d, Fcall *t, uchar *buf, Fid *f){	Readreq *r;	r = emalloc(sizeof(Readreq));	r->fcall = t;	r->buf = buf;	r->fid = f;	r->next = d->readq;	d->readq = r;}static voiddrainqueue(Dirtab *d){	Readreq *r, *nextr, *prevr;	Sendreq *s, *nexts, *prevs;	int i, n;	prevs = nil;	for(s=d->sendq; s!=nil; s=nexts){		nexts = s->next;		for(i=0; i<s->nfid; i++){			prevr = nil;			for(r=d->readq; r!=nil; r=nextr){				nextr = r->next;				if(r->fid == s->fid[i]){					/* pack the message if necessary */					if(s->pack == nil)						s->pack = plumbpack(s->msg, &s->npack);					/* exchange the stuff... */					r->fcall->data = s->pack+r->fid->offset;					n = s->npack - r->fid->offset;					if(n > messagesize-IOHDRSZ)						n = messagesize-IOHDRSZ;					if(n > r->fcall->count)						n = r->fcall->count;					r->fcall->count = n;					fsysrespond(r->fcall, r->buf, nil);					r->fid->offset += n;					if(r->fid->offset >= s->npack){						/* message transferred; delete this fid from send queue */						r->fid->offset = 0;						s->fid[i] = nil;						s->nleft--;					}					/* delete read request from queue */					if(prevr)						prevr->next = r->next;					else						d->readq = r->next;					free(r->fcall);					free(r);					break;				}else					prevr = r;			}		}		/* if no fids left, delete this send from queue */		if(s->nleft == 0){			free(s->fid);			plumbfree(s->msg);			free(s->pack);			if(prevs)				prevs->next = s->next;			else				d->sendq = s->next;			free(s);		}else			prevs = s;	}}/* can't flush a send because they are always answered synchronously */static voidflushqueue(Dirtab *d, int oldtag){	Readreq *r, *prevr;	prevr = nil;	for(r=d->readq; r!=nil; r=r->next){		if(oldtag == r->fcall->tag){			/* delete read request from queue */			if(prevr)				prevr->next = r->next;			else				d->readq = r->next;			free(r->fcall);			free(r->buf);			free(r);			return;		}		prevr = r;	}}/* remove messages awaiting delivery to now-closing fid */static voidremovesenders(Dirtab *d, Fid *fid){	Sendreq *s, *nexts, *prevs;	int i;	prevs = nil;	for(s=d->sendq; s!=nil; s=nexts){		nexts = s->next;		for(i=0; i<s->nfid; i++)			if(fid == s->fid[i]){				/* delete this fid from send queue */				s->fid[i] = nil;				s->nleft--;				break;			}		/* if no fids left, delete this send from queue */		if(s->nleft == 0){			free(s->fid);			plumbfree(s->msg);			free(s->pack);			if(prevs)				prevs->next = s->next;			else				d->sendq = s->next;			free(s);		}else			prevs = s;

⌨️ 快捷键说明

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