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

📄 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 "dat.h"#include "fns.h"char Eperm[] = "permission denied";char Eexist[] = "file does not exist";char Enotdir[] = "not a directory";char	Ebadfcall[] = "bad fcall type";char	Eoffset[] = "illegal offset";int	messagesize = 8192+IOHDRSZ;	/* good start */enum{	DEBUG = 0};Dirtab dirtab[]={	{ ".",			QTDIR,	Qdir,			0500|DMDIR },	{ "cons",		QTFILE,	Qcons,		0600 },	{ "cursor",		QTFILE,	Qcursor,		0600 },	{ "consctl",	QTFILE,	Qconsctl,		0200 },	{ "winid",		QTFILE,	Qwinid,		0400 },	{ "winname",	QTFILE,	Qwinname,	0400 },	{ "kbdin",		QTFILE,	Qkbdin,		0200 },	{ "label",		QTFILE,	Qlabel,		0600 },	{ "mouse",	QTFILE,	Qmouse,		0600 },	{ "screen",		QTFILE,	Qscreen,		0400 },	{ "snarf",		QTFILE,	Qsnarf,		0600 },	{ "text",		QTFILE,	Qtext,		0400 },	{ "wdir",		QTFILE,	Qwdir,		0600 },	{ "wctl",		QTFILE,	Qwctl,		0600 },	{ "window",	QTFILE,	Qwindow,		0400 },	{ "wsys",		QTDIR,	Qwsys,		0500|DMDIR },	{ nil, }};static uint		getclock(void);static void		filsysproc(void*);static Fid*		newfid(Filsys*, int);static int		dostat(Filsys*, int, Dirtab*, uchar*, int, uint);int	clockfd;int	firstmessage = 1;char	srvpipe[64];char	srvwctl[64];static	Xfid*	filsysflush(Filsys*, Xfid*, Fid*);static	Xfid*	filsysversion(Filsys*, Xfid*, Fid*);static	Xfid*	filsysauth(Filsys*, Xfid*, Fid*);static	Xfid*	filsysnop(Filsys*, Xfid*, Fid*);static	Xfid*	filsysattach(Filsys*, Xfid*, Fid*);static	Xfid*	filsyswalk(Filsys*, Xfid*, Fid*);static	Xfid*	filsysopen(Filsys*, Xfid*, Fid*);static	Xfid*	filsyscreate(Filsys*, Xfid*, Fid*);static	Xfid*	filsysread(Filsys*, Xfid*, Fid*);static	Xfid*	filsyswrite(Filsys*, Xfid*, Fid*);static	Xfid*	filsysclunk(Filsys*, Xfid*, Fid*);static	Xfid*	filsysremove(Filsys*, Xfid*, Fid*);static	Xfid*	filsysstat(Filsys*, Xfid*, Fid*);static	Xfid*	filsyswstat(Filsys*, Xfid*, Fid*);Xfid* 	(*fcall[Tmax])(Filsys*, Xfid*, Fid*) ={	[Tflush]	= filsysflush,	[Tversion]	= filsysversion,	[Tauth]	= filsysauth,	[Tattach]	= filsysattach,	[Twalk]	= filsyswalk,	[Topen]	= filsysopen,	[Tcreate]	= filsyscreate,	[Tread]	= filsysread,	[Twrite]	= filsyswrite,	[Tclunk]	= filsysclunk,	[Tremove]= filsysremove,	[Tstat]	= filsysstat,	[Twstat]	= filsyswstat,};voidpost(char *name, char *envname, int srvfd){	int fd;	char buf[32];	fd = create(name, OWRITE|ORCLOSE|OCEXEC, 0600);	if(fd < 0)		error(name);	sprint(buf, "%d",srvfd);	if(write(fd, buf, strlen(buf)) != strlen(buf))		error("srv write");	putenv(envname, name);}/* * Build pipe with OCEXEC set on second fd. * Can't put it on both because we want to post one in /srv. */intcexecpipe(int *p0, int *p1){	/* pipe the hard way to get close on exec */	if(bind("#|", "/mnt/temp", MREPL) < 0)		return -1;	*p0 = open("/mnt/temp/data", ORDWR);	*p1 = open("/mnt/temp/data1", ORDWR|OCEXEC);	unmount(nil, "/mnt/temp");	if(*p0<0 || *p1<0)		return -1;	return 0;}Filsys*filsysinit(Channel *cxfidalloc){	int n, fd, pid, p0;	Filsys *fs;	Channel *c;	char buf[128];	fs = emalloc(sizeof(Filsys));	if(cexecpipe(&fs->cfd, &fs->sfd) < 0)		goto Rescue;	fmtinstall('F', fcallfmt);	clockfd = open("/dev/time", OREAD|OCEXEC);	fd = open("/dev/user", OREAD);	strcpy(buf, "Jean-Paul_Belmondo");	if(fd >= 0){		n = read(fd, buf, sizeof buf-1);		if(n > 0)			buf[n] = 0;		close(fd);	}	fs->user = estrdup(buf);	fs->cxfidalloc = cxfidalloc;	pid = getpid();	/*	 * Create and post wctl pipe	 */	if(cexecpipe(&p0, &wctlfd) < 0)		goto Rescue;	sprint(srvwctl, "/srv/riowctl.%s.%d", fs->user, pid);	post(srvwctl, "wctl", p0);	close(p0);	/*	 * Start server processes	 */	c = chancreate(sizeof(char*), 0);	if(c == nil)		error("wctl channel");	proccreate(wctlproc, c, 4096);	threadcreate(wctlthread, c, 4096);	proccreate(filsysproc, fs, 10000);	/*	 * Post srv pipe	 */	sprint(srvpipe, "/srv/rio.%s.%d", fs->user, pid);	post(srvpipe, "wsys", fs->cfd);	return fs;Rescue:	free(fs);	return nil;}staticvoidfilsysproc(void *arg){	int n;	Xfid *x;	Fid *f;	Fcall t;	uchar *buf;	Filsys *fs;	threadsetname("FILSYSPROC");	fs = arg;	fs->pid = getpid();	x = nil;	for(;;){		buf = emalloc(messagesize+UTFmax);	/* UTFmax for appending partial rune in xfidwrite */		n = read9pmsg(fs->sfd, buf, messagesize);		if(n <= 0){			yield();	/* if threadexitsall'ing, will not return */			fprint(2, "rio: %d: read9pmsg: %d %r\n", getpid(), n);			errorshouldabort = 0;			error("eof or i/o error on server channel");		}		if(x == nil){			send(fs->cxfidalloc, nil);			recv(fs->cxfidalloc, &x);			x->fs = fs;		}		x->buf = buf;		if(convM2S(buf, n, x) != n)			error("convert error in convM2S");		if(DEBUG)			fprint(2, "rio:<-%F\n", &x->Fcall);		if(fcall[x->type] == nil)			x = filsysrespond(fs, x, &t, Ebadfcall);		else{			if(x->type==Tversion || x->type==Tauth)				f = nil;			else				f = newfid(fs, x->fid);			x->f = f;			x  = (*fcall[x->type])(fs, x, f);		}		firstmessage = 0;	}}/* * Called only from a different FD group */intfilsysmount(Filsys *fs, int id){	char buf[32];	close(fs->sfd);	/* close server end so mount won't hang if exiting */	sprint(buf, "%d", id);	if(mount(fs->cfd, -1, "/mnt/wsys", MREPL, buf) < 0){		fprint(2, "mount failed: %r\n");		return -1;	}	if(bind("/mnt/wsys", "/dev", MBEFORE) < 0){		fprint(2, "bind failed: %r\n");		return -1;	}	return 0;}Xfid*filsysrespond(Filsys *fs, 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 = malloc(messagesize);	n = convS2M(t, x->buf, messagesize);	if(n <= 0)		error("convert error in convS2M");	if(write(fs->sfd, x->buf, n) != n)		error("write error in respond");	if(DEBUG)		fprint(2, "rio:->%F\n", t);	free(x->buf);	x->buf = nil;	return x;}voidfilsyscancel(Xfid *x){	if(x->buf){		free(x->buf);		x->buf = nil;	}}staticXfid*filsysversion(Filsys *fs, Xfid *x, Fid*){	Fcall t;	if(!firstmessage)		return filsysrespond(x->fs, x, &t, "version request not first message");	if(x->msize < 256)		return filsysrespond(x->fs, x, &t, "version: message size too small");	messagesize = x->msize;	t.msize = messagesize;	if(strncmp(x->version, "9P2000", 6) != 0)		return filsysrespond(x->fs, x, &t, "unrecognized 9P version");	t.version = "9P2000";	return filsysrespond(fs, x, &t, nil);}staticXfid*filsysauth(Filsys *fs, Xfid *x, Fid*){	Fcall t;		return filsysrespond(fs, x, &t, "rio: authentication not required");}staticXfid*filsysflush(Filsys*, Xfid *x, Fid*){	sendp(x->c, xfidflush);	return nil;}staticXfid*filsysattach(Filsys *, Xfid *x, Fid *f){	Fcall t;	if(strcmp(x->uname, x->fs->user) != 0)		return filsysrespond(x->fs, 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;	sendp(x->c, xfidattach);	return nil;}staticintnumeric(char *s){	for(; *s!='\0'; s++)		if(*s<'0' || '9'<*s)			return 0;	return 1;}staticXfid*filsyswalk(Filsys *fs, Xfid *x, Fid *f){	Fcall t;	Fid *nf;	int i, id;	uchar type;	ulong path;	Dirtab *d, *dir;	Window *w;	char *err;	Qid qid;	if(f->open)		return filsysrespond(fs, x, &t, "walk of open file");	nf = nil;	if(x->fid  != x->newfid){		/* BUG: check exists */		nf = newfid(fs, x->newfid);		if(nf->busy)			return filsysrespond(fs, x, &t, "clone to busy fid");		nf->busy = TRUE;		nf->open = FALSE;		nf->dir = f->dir;		nf->qid = f->qid;		nf->w = f->w;		incref(f->w);		nf->nrpart = 0;	/* not open, so must be zero */		f = nf;	/* walk f */	}	t.nwqid = 0;	err = nil;	/* update f->qid, f->dir only if walk completes */	qid = f->qid;	dir = f->dir;	if(x->nwname > 0){		for(i=0; i<x->nwname; i++){			if((qid.type & QTDIR) == 0){				err = Enotdir;				break;			}			if(strcmp(x->wname[i], "..") == 0){				type = QTDIR;				path = Qdir;				dir = dirtab;				if(FILE(qid) == Qwsysdir)					path = Qwsys;				id = 0;    Accept:				if(i == MAXWELEM){					err = "name too long";					break;				}				qid.type = type;				qid.vers = 0;				qid.path = QID(id, path);				t.wqid[t.nwqid++] = qid;				continue;			}			if(qid.path == Qwsys){				/* is it a numeric name? */				if(!numeric(x->wname[i]))					break;				/* yes: it's a directory */				id = atoi(x->wname[i]);				qlock(&all);				w = wlookid(id);				if(w == nil){					qunlock(&all);					break;				}				path = Qwsysdir;				type = QTDIR;				qunlock(&all);				incref(w);				sendp(winclosechan, f->w);				f->w = w;				dir = dirtab;				goto Accept;			}					if(snarffd>=0 && strcmp(x->wname[i], "snarf")==0)				break;	/* don't serve /dev/snarf if it's provided in the environment */			id = WIN(f->qid);			d = dirtab;			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){			if(nf->w)				sendp(winclosechan, nf->w);			nf->open = FALSE;			nf->busy = FALSE;		}	}else if(t.nwqid == x->nwname){		f->dir = dir;		f->qid = qid;	}	return filsysrespond(fs, x, &t, err);}staticXfid*filsysopen(Filsys *fs, 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 filsysrespond(fs, x, &t, Eperm);}staticXfid*filsyscreate(Filsys *fs, Xfid *x, Fid*){	Fcall t;	return filsysrespond(fs, x, &t, Eperm);}staticintidcmp(void *a, void *b){	return *(int*)a - *(int*)b;}staticXfid*filsysread(Filsys *fs, Xfid *x, Fid *f){	Fcall t;	uchar *b;	int i, n, o, e, len, j, k, *ids;	Dirtab *d, dt;	uint clock;	char buf[16];	if((f->qid.type & QTDIR) == 0){		sendp(x->c, xfidread);		return nil;	}	o = x->offset;	e = x->offset+x->count;	clock = getclock();	b = malloc(messagesize-IOHDRSZ);	/* avoid memset of emalloc */	if(b == nil)		return filsysrespond(fs, x, &t, "out of memory");	n = 0;	switch(FILE(f->qid)){	case Qdir:	case Qwsysdir:		d = dirtab;		d++;	/* first entry is '.' */		for(i=0; d->name!=nil && i<e; i+=len){			len = dostat(fs, WIN(x->f->qid), d, b+n, x->count-n, clock);			if(len <= BIT16SZ)				break;			if(i >= o)				n += len;			d++;		}		break;	case Qwsys:		qlock(&all);		ids = emalloc(nwindow*sizeof(int));		for(j=0; j<nwindow; j++)			ids[j] = window[j]->id;		qunlock(&all);		qsort(ids, nwindow, sizeof ids[0], idcmp);		dt.name = buf;		for(i=0, j=0; j<nwindow && 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(fs, k, &dt, b+n, x->count-n, clock);			if(len == 0)				break;			if(i >= o)				n += len;			j++;		}		free(ids);		break;	}	t.data = (char*)b;	t.count = n;	filsysrespond(fs, x, &t, nil);	free(b);	return x;}staticXfid*filsyswrite(Filsys*, Xfid *x, Fid*){	sendp(x->c, xfidwrite);	return nil;}staticXfid*filsysclunk(Filsys *fs, Xfid *x, Fid *f){	Fcall t;	if(f->open){		f->busy = FALSE;		f->open = FALSE;		sendp(x->c, xfidclose);		return nil;	}	if(f->w)		sendp(winclosechan, f->w);	f->busy = FALSE;	f->open = FALSE;	return filsysrespond(fs, x, &t, nil);}staticXfid*filsysremove(Filsys *fs, Xfid *x, Fid*){	Fcall t;	return filsysrespond(fs, x, &t, Eperm);}staticXfid*filsysstat(Filsys *fs, Xfid *x, Fid *f){	Fcall t;	t.stat = emalloc(messagesize-IOHDRSZ);	t.nstat = dostat(fs, WIN(x->f->qid), f->dir, t.stat, messagesize-IOHDRSZ, getclock());	x = filsysrespond(fs, x, &t, nil);	free(t.stat);	return x;}staticXfid*filsyswstat(Filsys *fs, Xfid *x, Fid*){	Fcall t;	return filsysrespond(fs, x, &t, Eperm);}staticFid*newfid(Filsys *fs, int fid){	Fid *f, *ff, **fh;	ff = nil;	fh = &fs->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;}staticuintgetclock(void){	char buf[32];	seek(clockfd, 0, 0);	read(clockfd, buf, sizeof buf);	return atoi(buf);}staticintdostat(Filsys *fs, int id, Dirtab *dir, uchar *buf, int nbuf, uint clock){	Dir d;	d.qid.path = QID(id, dir->qid);	if(dir->qid == Qsnarf)		d.qid.vers = snarfversion;	else		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 = fs->user;	d.gid = fs->user;	d.muid = fs->user;	d.atime = clock;	d.mtime = clock;	return convD2M(&d, buf, nbuf);}

⌨️ 快捷键说明

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