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

📄 fs.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
/* * Web file system.  Conventionally mounted at /mnt/web * *	ctl				send control messages (might go away) *	cookies			list of cookies, editable *	clone			open and read to obtain new connection *	n				connection directory *		ctl				control messages (like get url) *		body				retrieved data *		content-type		mime content-type of body *		postbody			data to be posted *		parsed			parsed version of url * 			url				entire url *			scheme			http, ftp, etc. *			host				hostname *			path				path on host *			query			query after path *			fragment			#foo anchor reference *			user				user name (ftp) *			password			password (ftp) *			ftptype			transfer mode (ftp) */#include <u.h>#include <libc.h>#include <bio.h>#include <ip.h>#include <plumb.h>#include <thread.h>#include <fcall.h>#include <9p.h>#include "dat.h"#include "fns.h"int fsdebug;enum{	Qroot,	Qrootctl,	Qclone,	Qcookies,	Qclient,	Qctl,	Qbody,	Qbodyext,	Qcontenttype,	Qpostbody,	Qparsed,	Qurl,	Qscheme,	Qschemedata,	Quser,	Qpasswd,	Qhost,	Qport,	Qpath,	Qquery,	Qfragment,	Qftptype,	Qend,};#define PATH(type, n)	((type)|((n)<<8))#define TYPE(path)		((int)(path) & 0xFF)#define NUM(path)		((uint)(path)>>8)Channel *creq;Channel *creqwait;Channel *cclunk;Channel *cclunkwait;typedef struct Tab Tab;struct Tab{	char *name;	ulong mode;	int offset;};Tab tab[] ={	"/",			DMDIR|0555,		0,	"ctl",			0666,			0,	"clone",		0666,			0,	"cookies",		0666,			0,	"XXX",		DMDIR|0555,		0,	"ctl",			0666,			0,	"body",		0444,			0,	"XXX",		0444,			0,	"contenttype",	0444,			0,	"postbody",	0666,			0,	"parsed",		DMDIR|0555,		0,	"url",			0444,			offsetof(Url, url),	"scheme",		0444,			offsetof(Url, scheme),	"schemedata",	0444,			offsetof(Url, schemedata),	"user",		0444,			offsetof(Url, user),	"passwd",		0444,			offsetof(Url, passwd),	"host",		0444,			offsetof(Url, host),	"port",		0444,			offsetof(Url, port),	"path",		0444,			offsetof(Url, path),	"query",		0444,			offsetof(Url, query),	"fragment",	0444,			offsetof(Url, fragment),	"ftptype",		0444,			offsetof(Url, ftp.type),};ulong time0;static voidfillstat(Dir *d, uvlong path, ulong length, char *ext){	Tab *t;	int type;	char buf[32];	memset(d, 0, sizeof(*d));	d->uid = estrdup("web");	d->gid = estrdup("web");	d->qid.path = path;	d->atime = d->mtime = time0;	d->length = length;	type = TYPE(path);	t = &tab[type];	if(type == Qbodyext) {		snprint(buf, sizeof buf, "body.%s", ext == nil ? "xxx" : ext);		d->name = estrdup(buf);	}	else if(t->name)		d->name = estrdup(t->name);	else{	/* client directory */		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, 0, nil);	respond(r, nil);}static introotgen(int i, Dir *d, void*){	char buf[32];	i += Qroot+1;	if(i < Qclient){		fillstat(d, i, 0, nil);		return 0;	}	i -= Qclient;	if(i < nclient){		fillstat(d, PATH(Qclient, i), 0, nil);		snprint(buf, sizeof buf, "%d", i);		free(d->name);		d->name = estrdup(buf);		return 0;	}	return -1;}static intclientgen(int i, Dir *d, void *aux){	Client *c;	c = aux;	i += Qclient+1;	if(i <= Qparsed){		fillstat(d, PATH(i, c->num), 0, c->ext);		return 0;	}	return -1;}static intparsedgen(int i, Dir *d, void *aux){	Client *c;	c = aux;	i += Qparsed+1;	if(i < Qend){		fillstat(d, PATH(i, c->num), 0, nil);		return 0;	}	return -1;}static voidfsread(Req *r){	char *s;	char e[ERRMAX];	Client *c;	ulong path;	path = r->fid->qid.path;	switch(TYPE(path)){	default:		snprint(e, sizeof e, "bug in webfs path=%lux\n", path);		respond(r, e);		break;	case Qroot:		dirread9p(r, rootgen, nil);		respond(r, nil);		break;	case Qrootctl:		globalctlread(r);		break;	case Qcookies:		cookieread(r);		break;	case Qclient:		dirread9p(r, clientgen, client[NUM(path)]);		respond(r, nil);		break;	case Qctl:		ctlread(r, client[NUM(path)]);		break;	case Qcontenttype:		c = client[NUM(path)];		if(c->contenttype == nil)			r->ofcall.count = 0;		else			readstr(r, c->contenttype);		respond(r, nil);		break;	case Qpostbody:		c = client[NUM(path)];		readbuf(r, c->postbody, c->npostbody);		respond(r, nil);		break;			case Qbody:	case Qbodyext:		c = client[NUM(path)];		if(c->iobusy){			respond(r, "already have i/o pending");			break;		}		c->iobusy = 1;		sendp(c->creq, r);		break;	case Qparsed:		dirread9p(r, parsedgen, client[NUM(path)]);		respond(r, nil);		break;	case Qurl:	case Qscheme:	case Qschemedata:	case Quser:	case Qpasswd:	case Qhost:	case Qport:	case Qpath:	case Qquery:	case Qfragment:	case Qftptype:		c = client[NUM(path)];		r->ofcall.count = 0;		if(c->url != nil		&& (s = *(char**)((uintptr)c->url+tab[TYPE(path)].offset)) != nil)			readstr(r, s);		respond(r, nil);		break;	}}static voidfswrite(Req *r){	int m;	ulong path;	char e[ERRMAX], *buf, *cmd, *arg;	Client *c;	path = r->fid->qid.path;	switch(TYPE(path)){	default:		snprint(e, sizeof e, "bug in webfs path=%lux\n", path);		respond(r, e);		break;	case Qcookies:		cookiewrite(r);		break;	case Qrootctl:	case Qctl:		if(r->ifcall.count >= 1024){			respond(r, "ctl message too long");			return;		}		buf = estredup(r->ifcall.data, (char*)r->ifcall.data+r->ifcall.count);		cmd = buf;		arg = strpbrk(cmd, "\t ");		if(arg){			*arg++ = '\0';			arg += strspn(arg, "\t ");		}else			arg = "";		r->ofcall.count = r->ifcall.count;		if(TYPE(path)==Qrootctl){			if(!ctlwrite(r, &globalctl, cmd, arg)			&& !globalctlwrite(r, cmd, arg))				respond(r, "unknown control command");		}else{			c = client[NUM(path)];			if(!ctlwrite(r, &c->ctl, cmd, arg)			&& !clientctlwrite(r, c, cmd, arg))				respond(r, "unknown control command");		}		free(buf);		break;	case Qpostbody:		c = client[NUM(path)];		if(c->bodyopened){			respond(r, "cannot write postbody after opening body");			break;		}		if(r->ifcall.offset >= 128*1024*1024){	/* >128MB is probably a mistake */			respond(r, "offset too large");			break;		}		m = r->ifcall.offset + r->ifcall.count;		if(c->npostbody < m){			c->postbody = erealloc(c->postbody, m);			memset(c->postbody+c->npostbody, 0, m-c->npostbody);			c->npostbody = m;		}		memmove(c->postbody+r->ifcall.offset, r->ifcall.data, r->ifcall.count);		r->ofcall.count = r->ifcall.count;		respond(r, nil);		break;	}}static voidfsopen(Req *r){	static int need[4] = { 4, 2, 6, 1 };	ulong path;	int n;	Client *c;	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 Qcookies:		cookieopen(r);		break;	case Qpostbody:		c = client[NUM(path)];		c->havepostbody++;		c->ref++;		respond(r, nil);		break;	case Qbody:	case Qbodyext:		c = client[NUM(path)];		if(c->url == nil){			respond(r, "url is not yet set");			break;		}		c->bodyopened = 1;		c->ref++;		sendp(c->creq, r);		break;	case Qclone:		n = newclient(0);		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 >= Qclient)			client[NUM(path)]->ref++;		respond(r, nil);		break;	}}static voidfsdestroyfid(Fid *fid){	sendp(cclunk, fid);	recvp(cclunkwait);}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){	int i, n;	ulong path;	char buf[32], *ext;	path = fid->qid.path;	if(!(fid->qid.type&QTDIR))		return "walk in non-directory";	if(strcmp(name, "..") == 0){		switch(TYPE(path)){		case Qparsed:			qid->path = PATH(Qclient, NUM(path));			qid->type = tab[Qclient].mode>>24;			return nil;		case Qclient:		case Qroot:			qid->path = PATH(Qroot, 0);			qid->type = tab[Qroot].mode>>24;			return nil;		default:			return "bug in fswalk1";		}	}	i = TYPE(path)+1;	for(; i<nelem(tab); i++){		if(i==Qclient){			n = atoi(name);			snprint(buf, sizeof buf, "%d", n);			if(n < nclient && strcmp(buf, name) == 0){				qid->path = PATH(i, n);				qid->type = tab[i].mode>>24;				return nil;			}			break;		}		if(i==Qbodyext){			ext = client[NUM(path)]->ext;			snprint(buf, sizeof buf, "body.%s", ext == nil ? "xxx" : ext);			if(strcmp(buf, name) == 0){				qid->path = PATH(i, NUM(path));				qid->type = tab[i].mode>>24;				return nil;			}		}		else if(strcmp(name, tab[i].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 voidfsflush(Req *r){	Req *or;	int t;	Client *c;	ulong path;	or=r;	while(or->ifcall.type==Tflush)		or = or->oldreq;	if(or->ifcall.type != Tread && or->ifcall.type != Topen)		abort();	path = or->fid->qid.path;	t = TYPE(path);	if(t != Qbody && t != Qbodyext)		abort();	c = client[NUM(path)];	sendp(c->creq, r);	iointerrupt(c->io);}static voidfsthread(void*){	ulong path;	Alt a[3];	Fid *fid;	Req *r;	threadsetname("fsthread");	plumbstart();	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(TYPE(path)==Qcookies)				cookieclunk(fid);			if(fid->omode != -1 && TYPE(path) >= Qclient)				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 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);}voidtakedown(Srv*){	closecookies();	threadexitsall("done");}Srv fs = {.attach=		fssend,.destroyfid=	fsdestroyfid,.walk1=		fswalk1,.open=		fssend,.read=		fssend,.write=		fssend,.stat=		fssend,.flush=		fssend,.end=		takedown,};

⌨️ 快捷键说明

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