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

📄 fs.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
/* * ``Exec'' network device.  Mounted on net, provides /net/exec. * *	exec				protocol directory *		n 				connection directory *			ctl				control messages (like connect) *			data				data *			err				errors *			local				local address (pid of command) *			remote			remote address (command) *			status			status */#include <u.h>#include <libc.h>#include <fcall.h>#include <thread.h>#include <9p.h>#include "dat.h"int fsdebug;enum{	Qroot,	Qexec,	Qclone,	Qn,	Qctl,	Qdata,	Qlocal,	Qremote,	Qstatus,};#define PATH(type, n)	((type)|((n)<<8))#define TYPE(path)		((int)(path) & 0xFF)#define NUM(path)		((uint)(path)>>8)typedef struct Tab Tab;struct Tab{	char *name;	ulong mode;};Tab tab[] ={	"/",		DMDIR|0555,	"exec",	DMDIR|0555,	"clone",	0666,	nil,		DMDIR|0555,	"ctl",		0666,	"data",	0666,	"local",	0444,	"remote",	0444,	"status",	0444,};voidsetexecname(char *s){	tab[Qexec].name = s;}ulong time0;static voidfillstat(Dir *d, ulong path){	Tab *t;	int type;	char buf[32];	memset(d, 0, sizeof(*d));	d->uid = estrdup("exec");	d->gid = estrdup("exec");	d->qid.path = path;	d->atime = d->mtime = time0;	d->length = 0;	type = TYPE(path);	t = &tab[type];	if(t->name)		d->name = estrdup(t->name);	else{		snprint(buf, sizeof buf, "%ud", NUM(path));		d->name = estrdup(buf);	}	d->qid.type = t->mode>>24;	d->mode = t->mode;}static voidfsstat(Req *r){	fillstat(&r->d, r->fid->qid.path);	respond(r, nil);}static introotgen(int i, Dir *d, void*){	if(i < 1){		fillstat(d, PATH(Qexec, 0));		return 0;	}	return -1;}static intexecgen(int i, Dir *d, void*){	if(i < 1){		fillstat(d, PATH(Qclone, 0));		return 0;	}	i -= 1;	if(i < nclient){		fillstat(d, PATH(Qn, i));		return 0;	}	return -1;}static intconngen(int i, Dir *d, void *aux){	Client *c;	c = aux;	i += Qn+1;	if(i <= Qstatus){		fillstat(d, PATH(i, c->num));		return 0;	}	return -1;}char *statusstr[] = {	"Closed",	"Exec",	"Established",	"Hangup",};static voidfsread(Req *r){	char e[ERRMAX], *s;	ulong path;	path = r->fid->qid.path;	switch(TYPE(path)){	default:		snprint(e, sizeof e, "bug in execnet path=%lux", path);		respond(r, e);		break;	case Qroot:		dirread9p(r, rootgen, nil);		respond(r, nil);		break;	case Qexec:		dirread9p(r, execgen, nil);		respond(r, nil);		break;	case Qn:		dirread9p(r, conngen, client[NUM(path)]);		respond(r, nil);		break;	case Qctl:		snprint(e, sizeof e, "%ud", NUM(path));		readstr(r, e);		respond(r, nil);		break;	case Qdata:		dataread(r, client[NUM(path)]);		break;	case Qlocal:		snprint(e, sizeof e, "%d", client[NUM(path)]->pid);		readstr(r, e);		respond(r, nil);		break;	case Qremote:		s = client[NUM(path)]->cmd;		if(strlen(s) >= 5)	/* "exec " */			readstr(r, s+5);		else			readstr(r, s);		respond(r, nil);		break;	case Qstatus:		readstr(r, statusstr[client[NUM(path)]->status]);		respond(r, nil);		break;	}}static voidfswrite(Req *r){	char e[ERRMAX];	ulong path;	path = r->fid->qid.path;	switch(TYPE(path)){	default:		snprint(e, sizeof e, "bug in execnet path=%lux", path);		respond(r, e);		break;	case Qctl:		ctlwrite(r, client[NUM(path)]);		break;	case Qdata:		datawrite(r, client[NUM(path)]);		break;	}}static voidfsflush(Req *r){	ulong path;	Req *or;	for(or=r; or->ifcall.type==Tflush; or=or->oldreq)		;	if(or->ifcall.type != Tread && or->ifcall.type != Twrite)		abort();	path = or->fid->qid.path;	if(TYPE(path) != Qdata)		abort();	clientflush(or, client[NUM(path)]);	respond(r, nil);}static voidfsattach(Req *r){	if(r->ifcall.aname && r->ifcall.aname[0]){		respond(r, "invalid attach specifier");		return;	}	r->fid->qid.path = PATH(Qroot, 0);	r->fid->qid.type = QTDIR;	r->fid->qid.vers = 0;	r->ofcall.qid = r->fid->qid;	respond(r, nil);}static char*fswalk1(Fid *fid, char *name, Qid *qid){	char buf[32];	int i, n;	ulong path;	if(!(fid->qid.type&QTDIR))		return "walk in non-directory";	path = fid->qid.path;	if(strcmp(name, "..") == 0){		switch(TYPE(path)){		case Qn:			qid->path = PATH(Qexec, 0);			qid->type = QTDIR;			return nil;		case Qroot:		case Qexec:			qid->path = PATH(Qroot, 0);			qid->type = QTDIR;			return nil;		default:			return "bug in fswalk1";		}	}	i = TYPE(path)+1;	for(; i<nelem(tab); i++){		if(i==Qn){			n = atoi(name);			snprint(buf, sizeof buf, "%d", n);			if(n < nclient && strcmp(buf, name) == 0){				qid->path = PATH(Qn, n);				qid->type = QTDIR;				return nil;			}			break;		}		if(strcmp(tab[i].name, name) == 0){			qid->path = PATH(i, NUM(path));			qid->type = tab[i].mode>>24;			return nil;		}		if(tab[i].mode&DMDIR)			break;	}	return "directory entry not found";}static voidfsopen(Req *r){	static int need[4] = { 4, 2, 6, 1 };	ulong path;	int n;	Tab *t;	/*	 * lib9p already handles the blatantly obvious.	 * we just have to enforce the permissions we have set.	 */	path = r->fid->qid.path;	t = &tab[TYPE(path)];	n = need[r->ifcall.mode&3];	if((n&t->mode) != n){		respond(r, "permission denied");		return;	}	switch(TYPE(path)){	case Qclone:		n = newclient();		path = PATH(Qctl, n);		r->fid->qid.path = path;		r->ofcall.qid.path = path;		if(fsdebug)			fprint(2, "open clone => path=%lux\n", path);		t = &tab[Qctl];		/* fall through */	default:		if(t-tab >= Qn)			client[NUM(path)]->ref++;		respond(r, nil);		break;	}}Channel *cclunk;Channel *cclunkwait;Channel *creq;Channel *creqwait;static voidfsthread(void*){	ulong path;	Alt a[3];	Fid *fid;	Req *r;	threadsetname("fsthread");	a[0].op = CHANRCV;	a[0].c = cclunk;	a[0].v = &fid;	a[1].op = CHANRCV;	a[1].c = creq;	a[1].v = &r;	a[2].op = CHANEND;	for(;;){		switch(alt(a)){		case 0:			path = fid->qid.path;			if(fid->omode != -1 && TYPE(path) >= Qn)				closeclient(client[NUM(path)]);			sendp(cclunkwait, nil);			break;		case 1:			switch(r->ifcall.type){			case Tattach:				fsattach(r);				break;			case Topen:				fsopen(r);				break;			case Tread:				fsread(r);				break;			case Twrite:				fswrite(r);				break;			case Tstat:				fsstat(r);				break;			case Tflush:				fsflush(r);				break;			default:				respond(r, "bug in fsthread");				break;			}			sendp(creqwait, 0);			break;		}	}}static voidfsdestroyfid(Fid *fid){	sendp(cclunk, fid);	recvp(cclunkwait);}static voidfssend(Req *r){	sendp(creq, r);	recvp(creqwait);	/* avoids need to deal with spurious flushes */}voidinitfs(void){	time0 = time(0);	creq = chancreate(sizeof(void*), 0);	creqwait = chancreate(sizeof(void*), 0);	cclunk = chancreate(sizeof(void*), 0);	cclunkwait = chancreate(sizeof(void*), 0);	procrfork(fsthread, nil, STACK, RFNAMEG);}Srv fs = {.attach=		fssend,.destroyfid=	fsdestroyfid,.walk1=		fswalk1,.open=		fssend,.read=		fssend,.write=		fssend,.stat=		fssend,.flush=		fssend,};

⌨️ 快捷键说明

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