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

📄 fsys.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include <u.h>#include <libc.h>#include <draw.h>#include <thread.h>#include <cursor.h>#include <mouse.h>#include <keyboard.h>#include <frame.h>#include <fcall.h>#include <plumb.h>#include "dat.h"#include "fns.h"static	int	cfd;static	int	sfd;enum{	Nhash	= 16,	DEBUG	= 0};static	Fid	*fids[Nhash];Fid	*newfid(int);static	Xfid*	fsysflush(Xfid*, Fid*);static	Xfid*	fsysauth(Xfid*, Fid*);static	Xfid*	fsysversion(Xfid*, Fid*);static	Xfid*	fsysattach(Xfid*, Fid*);static	Xfid*	fsyswalk(Xfid*, Fid*);static	Xfid*	fsysopen(Xfid*, Fid*);static	Xfid*	fsyscreate(Xfid*, Fid*);static	Xfid*	fsysread(Xfid*, Fid*);static	Xfid*	fsyswrite(Xfid*, Fid*);static	Xfid*	fsysclunk(Xfid*, Fid*);static	Xfid*	fsysremove(Xfid*, Fid*);static	Xfid*	fsysstat(Xfid*, Fid*);static	Xfid*	fsyswstat(Xfid*, Fid*);Xfid* 	(*fcall[Tmax])(Xfid*, 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 Eperm[] = "permission denied";char Eexist[] = "file does not exist";char Enotdir[] = "not a directory";Dirtab dirtab[]={	{ ".",			QTDIR,	Qdir,		0500|DMDIR },	{ "acme",		QTDIR,	Qacme,	0500|DMDIR },	{ "cons",		QTFILE,	Qcons,	0600 },	{ "consctl",	QTFILE,	Qconsctl,	0000 },	{ "draw",		QTDIR,	Qdraw,	0000|DMDIR },	/* to suppress graphics progs started in acme */	{ "editout",	QTFILE,	Qeditout,	0200 },	{ "index",		QTFILE,	Qindex,	0400 },	{ "label",		QTFILE,	Qlabel,	0600 },	{ "new",		QTDIR,	Qnew,	0500|DMDIR },	{ nil, }};Dirtab dirtabw[]={	{ ".",			QTDIR,		Qdir,			0500|DMDIR },	{ "addr",		QTFILE,		QWaddr,		0600 },	{ "body",		QTAPPEND,	QWbody,		0600|DMAPPEND },	{ "ctl",		QTFILE,		QWctl,		0600 },	{ "data",		QTFILE,		QWdata,		0600 },	{ "editout",	QTFILE,		QWeditout,	0200 },	{ "errors",		QTFILE,		QWerrors,		0200 },	{ "event",		QTFILE,		QWevent,		0600 },	{ "rdsel",		QTFILE,		QWrdsel,		0400 },	{ "wrsel",		QTFILE,		QWwrsel,		0200 },	{ "tag",		QTAPPEND,	QWtag,		0600|DMAPPEND },	{ "xdata",		QTFILE,		QWxdata,		0600 },	{ nil, }};typedef struct Mnt Mnt;struct Mnt{	QLock;	int		id;	Mntdir	*md;};Mnt	mnt;Xfid*	respond(Xfid*, Fcall*, char*);int		dostat(int, Dirtab*, uchar*, int, uint);uint	getclock(void);char	*user = "Wile E. Coyote";int	clockfd;static int closing = 0;int	messagesize = Maxblock+IOHDRSZ;	/* good start */void	fsysproc(void *);voidfsysinit(void){	int p[2];	int n, fd;	char buf[256];	if(pipe(p) < 0)		error("can't create pipe");	cfd = p[0];	sfd = p[1];	fmtinstall('F', fcallfmt);	clockfd = open("/dev/time", OREAD|OCEXEC);	fd = open("/dev/user", OREAD);	if(fd >= 0){		n = read(fd, buf, sizeof buf-1);		if(n > 0){			buf[n] = 0;			user = estrdup(buf);		}		close(fd);	}	proccreate(fsysproc, nil, STACK);}voidfsysproc(void *){	int n;	Xfid *x;	Fid *f;	Fcall t;	uchar *buf;	x = nil;	for(;;){		buf = emalloc(messagesize+UTFmax);	/* overflow for appending partial rune in xfidwrite */		n = read9pmsg(sfd, buf, messagesize);		if(n <= 0){			if(closing)				break;			error("i/o error on server channel");		}		if(x == nil){			sendp(cxfidalloc, nil);			x = recvp(cxfidalloc);		}		x->buf = buf;		if(convM2S(buf, n, x) != n)			error("convert error in convM2S");		if(DEBUG)			fprint(2, "%F\n", &x->Fcall);		if(fcall[x->type] == nil)			x = respond(x, &t, "bad fcall type");		else{			switch(x->type){			case Tversion:			case Tauth:			case Tflush:				f = nil;				break;			case Tattach:				f = newfid(x->fid);				break;			default:				f = newfid(x->fid);				if(!f->busy){					x->f = f;					x = respond(x, &t, "fid not in use");					continue;				}				break;			}			x->f = f;			x  = (*fcall[x->type])(x, f);		}	}}Mntdir*fsysaddid(Rune *dir, int ndir, Rune **incl, int nincl){	Mntdir *m;	int id;	qlock(&mnt);	id = ++mnt.id;	m = emalloc(sizeof *m);	m->id = id;	m->dir =  dir;	m->ref = 1;	/* one for Command, one will be incremented in attach */	m->ndir = ndir;	m->next = mnt.md;	m->incl = incl;	m->nincl = nincl;	mnt.md = m;	qunlock(&mnt);	return m;}voidfsysincid(Mntdir *m){	qlock(&mnt);	m->ref++;	qunlock(&mnt);}voidfsysdelid(Mntdir *idm){	Mntdir *m, *prev;	int i;	char buf[64];	if(idm == nil)		return;	qlock(&mnt);	if(--idm->ref > 0){		qunlock(&mnt);		return;	}	prev = nil;	for(m=mnt.md; m; m=m->next){		if(m == idm){			if(prev)				prev->next = m->next;			else				mnt.md = m->next;			for(i=0; i<m->nincl; i++)				free(m->incl[i]);			free(m->incl);			free(m->dir);			free(m);			qunlock(&mnt);			return;		}		prev = m;	}	qunlock(&mnt);	sprint(buf, "fsysdelid: can't find id %d\n", idm->id);	sendp(cerr, estrdup(buf));}/* * Called only in exec.c:/^run(), from a different FD group */Mntdir*fsysmount(Rune *dir, int ndir, Rune **incl, int nincl){	char buf[256];	Mntdir *m;	/* close server side so don't hang if acme is half-exited */	close(sfd);	m = fsysaddid(dir, ndir, incl, nincl);	sprint(buf, "%d", m->id);	if(mount(cfd, -1, "/mnt/acme", MREPL, buf) < 0){		fsysdelid(m);		return nil;	}	close(cfd);	bind("/mnt/acme", "/mnt/wsys", MREPL);	if(bind("/mnt/acme", "/dev", MBEFORE) < 0){		fsysdelid(m);		return nil;	}	return m;}voidfsysclose(void){	closing = 1;	close(cfd);	close(sfd);}Xfid*respond(Xfid *x, Fcall *t, char *err){	int n;	if(err){		t->type = Rerror;		t->ename = err;	}else		t->type = x->type+1;	t->fid = x->fid;	t->tag = x->tag;	if(x->buf == nil)		x->buf = emalloc(messagesize);	n = convS2M(t, x->buf, messagesize);	if(n <= 0)		error("convert error in convS2M");	if(write(sfd, x->buf, n) != n)		error("write error in respond");	free(x->buf);	x->buf = nil;	if(DEBUG)		fprint(2, "r: %F\n", t);	return x;}staticXfid*fsysversion(Xfid *x, Fid*){	Fcall t;	if(x->msize < 256)		return respond(x, &t, "version: message size too small");	messagesize = x->msize;	t.msize = messagesize;	if(strncmp(x->version, "9P2000", 6) != 0)		return respond(x, &t, "unrecognized 9P version");	t.version = "9P2000";	return respond(x, &t, nil);}staticXfid*fsysauth(Xfid *x, Fid*){	Fcall t;	return respond(x, &t, "acme: authentication not required");}staticXfid*fsysflush(Xfid *x, Fid*){	sendp(x->c, xfidflush);	return nil;}staticXfid*fsysattach(Xfid *x, Fid *f){	Fcall t;	int id;	Mntdir *m;	if(strcmp(x->uname, user) != 0)		return respond(x, &t, Eperm);	f->busy = TRUE;	f->open = FALSE;	f->qid.path = Qdir;	f->qid.type = QTDIR;	f->qid.vers = 0;	f->dir = dirtab;	f->nrpart = 0;	f->w = nil;	t.qid = f->qid;	f->mntdir = nil;	id = atoi(x->aname);	qlock(&mnt);	for(m=mnt.md; m; m=m->next)		if(m->id == id){			f->mntdir = m;			m->ref++;			break;		}	if(m == nil)		sendp(cerr, estrdup("unknown id in attach"));	qunlock(&mnt);	return respond(x, &t, nil);}staticXfid*fsyswalk(Xfid *x, Fid *f){	Fcall t;	int c, i, j, id;	Qid q;	uchar type;	ulong path;	Fid *nf;	Dirtab *d, *dir;	Window *w;	char *err;	nf = nil;	w = nil;	if(f->open)		return respond(x, &t, "walk of open file");	if(x->fid != x->newfid){		nf = newfid(x->newfid);		if(nf->busy)			return respond(x, &t, "newfid already in use");		nf->busy = TRUE;		nf->open = FALSE;		nf->mntdir = f->mntdir;		if(f->mntdir)			f->mntdir->ref++;		nf->dir = f->dir;		nf->qid = f->qid;		nf->w = f->w;		nf->nrpart = 0;	/* not open, so must be zero */		if(nf->w)			incref(nf->w);		f = nf;	/* walk f */	}	t.nwqid = 0;	err = nil;	dir = nil;	id = WIN(f->qid);	q = f->qid;	if(x->nwname > 0){		for(i=0; i<x->nwname; i++){			if((q.type & QTDIR) == 0){				err = Enotdir;				break;			}			if(strcmp(x->wname[i], "..") == 0){				type = QTDIR;				path = Qdir;				id = 0;				if(w){					winclose(w);					w = nil;				}    Accept:				if(i == MAXWELEM){					err = "name too long";					break;				}				q.type = type;				q.vers = 0;				q.path = QID(id, path);				t.wqid[t.nwqid++] = q;				continue;			}			/* is it a numeric name? */			for(j=0; (c=x->wname[i][j]); j++)				if(c<'0' || '9'<c)					goto Regular;			/* yes: it's a directory */			if(w)	/* name has form 27/23; get out before losing w */				break;			id = atoi(x->wname[i]);			qlock(&row);			w = lookid(id, FALSE);			if(w == nil){				qunlock(&row);				break;			}			incref(w);	/* we'll drop reference at end if there's an error */			path = Qdir;			type = QTDIR;			qunlock(&row);			dir = dirtabw;			goto Accept;	    Regular://			if(FILE(f->qid) == Qacme)	/* empty directory *///				break;			if(strcmp(x->wname[i], "new") == 0){				if(w)					error("w set in walk to new");				sendp(cnewwindow, nil);	/* signal newwindowthread */				w = recvp(cnewwindow);	/* receive new window */				incref(w);				type = QTDIR;				path = QID(w->id, Qdir);				id = w->id;				dir = dirtabw;				goto Accept;			}			if(id == 0)				d = dirtab;			else				d = dirtabw;			d++;	/* skip '.' */			for(; d->name; d++)				if(strcmp(x->wname[i], d->name) == 0){					path = d->qid;					type = d->type;					dir = d;					goto Accept;				}			break;	/* file not found */		}		if(i==0 && err == nil)			err = Eexist;	}	if(err!=nil || t.nwqid<x->nwname){		if(nf){			nf->busy = FALSE;			fsysdelid(nf->mntdir);		}	}else if(t.nwqid  == x->nwname){		if(w){			f->w = w;			w = nil;	/* don't drop the reference */		}		if(dir)			f->dir = dir;		f->qid = q;	}	if(w != nil)		winclose(w);	return respond(x, &t, err);}staticXfid*fsysopen(Xfid *x, Fid *f){	Fcall t;	int m;	/* can't truncate anything, so just disregard */	x->mode &= ~(OTRUNC|OCEXEC);	/* can't execute or remove anything */	if(x->mode==OEXEC || (x->mode&ORCLOSE))		goto Deny;	switch(x->mode){	default:		goto Deny;	case OREAD:		m = 0400;		break;	case OWRITE:		m = 0200;		break;	case ORDWR:		m = 0600;		break;	}	if(((f->dir->perm&~(DMDIR|DMAPPEND))&m) != m)		goto Deny;	sendp(x->c, xfidopen);	return nil;    Deny:	return respond(x, &t, Eperm);}staticXfid*fsyscreate(Xfid *x, Fid*){	Fcall t;	return respond(x, &t, Eperm);}staticintidcmp(void *a, void *b){	return *(int*)a - *(int*)b;}staticXfid*fsysread(Xfid *x, Fid *f){	Fcall t;	uchar *b;	int i, id, n, o, e, j, k, *ids, nids;	Dirtab *d, dt;	Column *c;	uint clock, len;	char buf[16];	if(f->qid.type & QTDIR){		if(FILE(f->qid) == Qacme){	/* empty dir */			t.data = nil;			t.count = 0;			respond(x, &t, nil);			return x;		}		o = x->offset;		e = x->offset+x->count;		clock = getclock();		b = emalloc(messagesize);		id = WIN(f->qid);		n = 0;		if(id > 0)			d = dirtabw;		else			d = dirtab;		d++;	/* first entry is '.' */		for(i=0; d->name!=nil && i<e; i+=len){			len = dostat(WIN(x->f->qid), d, b+n, x->count-n, clock);			if(len <= BIT16SZ)				break;			if(i >= o)				n += len;			d++;		}		if(id == 0){			qlock(&row);			nids = 0;			ids = nil;			for(j=0; j<row.ncol; j++){				c = row.col[j];				for(k=0; k<c->nw; k++){					ids = realloc(ids, (nids+1)*sizeof(int));					ids[nids++] = c->w[k]->id;				}			}			qunlock(&row);			qsort(ids, nids, sizeof ids[0], idcmp);			j = 0;			dt.name = buf;			for(; j<nids && i<e; i+=len){				k = ids[j];				sprint(dt.name, "%d", k);				dt.qid = QID(k, Qdir);				dt.type = QTDIR;				dt.perm = DMDIR|0700;				len = dostat(k, &dt, b+n, x->count-n, clock);				if(len == 0)					break;				if(i >= o)					n += len;				j++;			}			free(ids);		}		t.data = (char*)b;		t.count = n;		respond(x, &t, nil);		free(b);		return x;	}	sendp(x->c, xfidread);	return nil;}staticXfid*fsyswrite(Xfid *x, Fid*){	sendp(x->c, xfidwrite);	return nil;}staticXfid*fsysclunk(Xfid *x, Fid *f){	fsysdelid(f->mntdir);	sendp(x->c, xfidclose);	return nil;}staticXfid*fsysremove(Xfid *x, Fid*){	Fcall t;	return respond(x, &t, Eperm);}staticXfid*fsysstat(Xfid *x, Fid *f){	Fcall t;	t.stat = emalloc(messagesize-IOHDRSZ);	t.nstat = dostat(WIN(x->f->qid), f->dir, t.stat, messagesize-IOHDRSZ, getclock());	x = respond(x, &t, nil);	free(t.stat);	return x;}staticXfid*fsyswstat(Xfid *x, Fid*){	Fcall t;	return respond(x, &t, Eperm);}Fid*newfid(int fid){	Fid *f, *ff, **fh;	ff = nil;	fh = &fids[fid&(Nhash-1)];	for(f=*fh; f; f=f->next)		if(f->fid == fid)			return f;		else if(ff==nil && f->busy==FALSE)			ff = f;	if(ff){		ff->fid = fid;		return ff;	}	f = emalloc(sizeof *f);	f->fid = fid;	f->next = *fh;	*fh = f;	return f;}uintgetclock(){	char buf[32];	buf[0] = '\0';	pread(clockfd, buf, sizeof buf, 0);	return atoi(buf);}intdostat(int id, Dirtab *dir, uchar *buf, int nbuf, uint clock){	Dir d;	d.qid.path = QID(id, dir->qid);	d.qid.vers = 0;	d.qid.type = dir->type;	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);}

⌨️ 快捷键说明

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