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

📄 devmnt.c

📁 在x86平台上运行不可信任代码的sandbox。
💻 C
📖 第 1 页 / 共 2 页
字号:
	mntalloc.mntfree = m;	q = m->q;	unlock(&mntalloc.lk);	qfree(q);}static voidmntclose(Chan *c){	mntclunk(c, Tclunk);}static voidmntremove(Chan *c){	mntclunk(c, Tremove);}static intmntwstat(Chan *c, uchar *dp, int n){	Mnt *m;	Mntrpc *r;	m = mntchk(c);	r = mntralloc(c, m->msize);	if(waserror()) {		mntfree(r);		nexterror();	}	r->request.type = Twstat;	r->request.fid = c->fid;	r->request.nstat = n;	r->request.stat = dp;	mountrpc(m, r);	poperror();	mntfree(r);	return n;}static longmntread(Chan *c, void *buf, long n, vlong off){	uchar *p, *e;	int nc, cache, isdir, dirlen;	isdir = 0;	cache = c->flag & CCACHE;	if(c->qid.type & QTDIR) {		cache = 0;		isdir = 1;	}	p = buf;	if(cache) {		nc = cread(c, buf, n, off);		if(nc > 0) {			n -= nc;			if(n == 0)				return nc;			p += nc;			off += nc;		}		n = mntrdwr(Tread, c, p, n, off);		cupdate(c, p, n, off);		return n + nc;	}	n = mntrdwr(Tread, c, buf, n, off);	if(isdir) {		for(e = &p[n]; p+BIT16SZ < e; p += dirlen){			dirlen = BIT16SZ+GBIT16(p);			if(p+dirlen > e)				break;			validstat(p, dirlen);			mntdirfix(p, c);		}		if(p != e)			error(Esbadstat);	}	return n;}static longmntwrite(Chan *c, void *buf, long n, vlong off){	return mntrdwr(Twrite, c, buf, n, off);}longmntrdwr(int type, Chan *c, void *buf, long n, vlong off){	Mnt *m; 	Mntrpc *r;	char *uba;	int cache;	ulong cnt, nr, nreq;	m = mntchk(c);	uba = buf;	cnt = 0;	cache = c->flag & CCACHE;	if(c->qid.type & QTDIR)		cache = 0;	for(;;) {		r = mntralloc(c, m->msize);		if(waserror()) {			mntfree(r);			nexterror();		}		r->request.type = type;		r->request.fid = c->fid;		r->request.offset = off;		r->request.data = uba;		nr = n;		if(nr > m->msize-IOHDRSZ)			nr = m->msize-IOHDRSZ;		r->request.count = nr;		mountrpc(m, r);		nreq = r->request.count;		nr = r->reply.count;		if(nr > nreq)			nr = nreq;		if(type == Tread)			r->b = bl2mem((uchar*)uba, r->b, nr);		else if(cache)			cwrite(c, (uchar*)uba, nr, off);		poperror();		mntfree(r);		off += nr;		uba += nr;		cnt += nr;		n -= nr;		if(nr != nreq || n == 0 || up->nnote)			break;	}	return cnt;}voidmountrpc(Mnt *m, Mntrpc *r){	char *sn, *cn;	int t;	r->reply.tag = 0;	r->reply.type = Tmax;	/* can't ever be a valid message type */	mountio(m, r);	t = r->reply.type;	switch(t) {	case Rerror:		error(r->reply.ename);	case Rflush:		error(Eintr);	default:		if(t == r->request.type+1)			break;		sn = "?";		if(m->c->path != nil)			sn = m->c->path->s;		cn = "?";		if(r->c != nil && r->c->path != nil)			cn = r->c->path->s;		print("mnt: proc %s %lud: mismatch from %s %s rep 0x%lux tag %d fid %d T%d R%d rp %d\n",			up->text, up->pid, sn, cn,			r, r->request.tag, r->request.fid, r->request.type,			r->reply.type, r->reply.tag);		error(Emountrpc);	}}voidmountio(Mnt *m, Mntrpc *r){	int n;	while(waserror()) {		if(m->rip == up)			mntgate(m);		if(strcmp(up->errstr, Eintr) != 0){			mntflushfree(m, r);			nexterror();		}		r = mntflushalloc(r, m->msize);	}	lock(&m->lk);	r->m = m;	r->list = m->queue;	m->queue = r;	unlock(&m->lk);	/* Transmit a file system rpc */	if(m->msize == 0)		panic("msize");	n = convS2M(&r->request, r->rpc, m->msize);	if(n < 0)		panic("bad message type in mountio");	if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)		error(Emountrpc);	r->stime = fastticks(nil);	r->reqlen = n;	/* Gate readers onto the mount point one at a time */	for(;;) {		lock(&m->lk);		if(m->rip == 0)			break;		unlock(&m->lk);		sleep(&r->r, rpcattn, r);		if(r->done){			poperror();			mntflushfree(m, r);			return;		}	}	m->rip = up;	unlock(&m->lk);	while(r->done == 0) {		if(mntrpcread(m, r) < 0)			error(Emountrpc);		mountmux(m, r);	}	mntgate(m);	poperror();	mntflushfree(m, r);}static intdoread(Mnt *m, int len){	Block *b;	while(qlen(m->q) < len){		b = devtab[m->c->type]->bread(m->c, m->msize, 0);		if(b == nil)			return -1;		if(blocklen(b) == 0){			freeblist(b);			return -1;		}		qaddlist(m->q, b);	}	return 0;}intmntrpcread(Mnt *m, Mntrpc *r){	int i, t, len, hlen;	Block *b, **l, *nb;	r->reply.type = 0;	r->reply.tag = 0;	/* read at least length, type, and tag and pullup to a single block */	if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0)		return -1;	nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ);	/* read in the rest of the message, avoid ridiculous (for now) message sizes */	len = GBIT32(nb->rp);	if(len > m->msize){		qdiscard(m->q, qlen(m->q));		return -1;	}	if(doread(m, len) < 0)		return -1;	/* pullup the header (i.e. everything except data) */	t = nb->rp[BIT32SZ];	switch(t){	case Rread:		hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ;		break;	default:		hlen = len;		break;	}	nb = pullupqueue(m->q, hlen);	if(convM2S(nb->rp, len, &r->reply) <= 0){		/* bad message, dump it */		print("mntrpcread: convM2S failed\n");		qdiscard(m->q, len);		return -1;	}	/* hang the data off of the fcall struct */	l = &r->b;	*l = nil;	do {		b = qremove(m->q);		if(hlen > 0){			b->rp += hlen;			len -= hlen;			hlen = 0;		}		i = BLEN(b);		if(i <= len){			len -= i;			*l = b;			l = &(b->next);		} else {			/* split block and put unused bit back */			nb = allocb(i-len);			memmove(nb->wp, b->rp+len, i-len);			b->wp = b->rp+len;			nb->wp += i-len;			qputback(m->q, nb);			*l = b;			return 0;		}	}while(len > 0);	return 0;}voidmntgate(Mnt *m){	Mntrpc *q;	lock(&m->lk);	m->rip = 0;	for(q = m->queue; q; q = q->list) {		if(q->done == 0)		if(wakeup(&q->r))			break;	}	unlock(&m->lk);}voidmountmux(Mnt *m, Mntrpc *r){	Mntrpc **l, *q;	lock(&m->lk);	l = &m->queue;	for(q = *l; q; q = q->list) {		/* look for a reply to a message */		if(q->request.tag == r->reply.tag) {			*l = q->list;			if(q != r) {				/*				 * Completed someone else.				 * Trade pointers to receive buffer.				 */				q->reply = r->reply;				q->b = r->b;				r->b = nil;			}			q->done = 1;			unlock(&m->lk);			if(mntstats != nil)				(*mntstats)(q->request.type,					m->c, q->stime,					q->reqlen + r->replen);			if(q != r)				wakeup(&q->r);			return;		}		l = &q->list;	}	unlock(&m->lk);	print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);}/* * Create a new flush request and chain the previous * requests from it */Mntrpc*mntflushalloc(Mntrpc *r, ulong iounit){	Mntrpc *fr;	fr = mntralloc(0, iounit);	fr->request.type = Tflush;	if(r->request.type == Tflush)		fr->request.oldtag = r->request.oldtag;	else		fr->request.oldtag = r->request.tag;	fr->flushed = r;	return fr;}/* *  Free a chain of flushes.  Remove each unanswered *  flush and the original message from the unanswered *  request queue.  Mark the original message as done *  and if it hasn't been answered set the reply to to *  Rflush. */voidmntflushfree(Mnt *m, Mntrpc *r){	Mntrpc *fr;	while(r){		fr = r->flushed;		if(!r->done){			r->reply.type = Rflush;			mntqrm(m, r);		}		if(fr)			mntfree(r);		r = fr;	}}intalloctag(void){	int i, j;	ulong v;	for(i = 0; i < NMASK; i++){		v = mntalloc.tagmask[i];		if(v == ~0UL)			continue;		for(j = 0; j < 1<<TAGSHIFT; j++)			if((v & (1<<j)) == 0){				mntalloc.tagmask[i] |= 1<<j;				return (i<<TAGSHIFT) + j;			}	}	panic("no friggin tags left");	return NOTAG;}voidfreetag(int t){	mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));}Mntrpc*mntralloc(Chan *c, ulong msize){	Mntrpc *new;	lock(&mntalloc.lk);	new = mntalloc.rpcfree;	if(new == nil){		new = malloc(sizeof(Mntrpc));		if(new == nil) {			unlock(&mntalloc.lk);			exhausted("mount rpc header");		}		/*		 * The header is split from the data buffer as		 * mountmux may swap the buffer with another header.		 */		new->rpc = mallocz(msize, 0);		if(new->rpc == nil){			free(new);			unlock(&mntalloc.lk);			exhausted("mount rpc buffer");		}		new->rpclen = msize;		new->request.tag = alloctag();	}	else {		mntalloc.rpcfree = new->list;		mntalloc.nrpcfree--;		if(new->rpclen < msize){			free(new->rpc);			new->rpc = mallocz(msize, 0);			if(new->rpc == nil){				free(new);				mntalloc.nrpcused--;				unlock(&mntalloc.lk);				exhausted("mount rpc buffer");			}			new->rpclen = msize;		}	}	mntalloc.nrpcused++;	unlock(&mntalloc.lk);	new->c = c;	new->done = 0;	new->flushed = nil;	new->b = nil;	return new;}voidmntfree(Mntrpc *r){	if(r->b != nil)		freeblist(r->b);	lock(&mntalloc.lk);	if(mntalloc.nrpcfree >= 10){		free(r->rpc);		free(r);		freetag(r->request.tag);	}	else{		r->list = mntalloc.rpcfree;		mntalloc.rpcfree = r;		mntalloc.nrpcfree++;	}	mntalloc.nrpcused--;	unlock(&mntalloc.lk);}voidmntqrm(Mnt *m, Mntrpc *r){	Mntrpc **l, *f;	lock(&m->lk);	r->done = 1;	l = &m->queue;	for(f = *l; f; f = f->list) {		if(f == r) {			*l = r->list;			break;		}		l = &f->list;	}	unlock(&m->lk);}Mnt*mntchk(Chan *c){	Mnt *m;	/* This routine is mostly vestiges of prior lives; now it's just sanity checking */	if(c->mchan == nil)		panic("mntchk 1: nil mchan c %s\n", chanpath(c));	m = c->mchan->mux;	if(m == nil)		print("mntchk 2: nil mux c %s c->mchan %s \n", chanpath(c), chanpath(c->mchan));	/*	 * Was it closed and reused (was error(Eshutdown); now, it cannot happen)	 */	if(m->id == 0 || m->id >= c->dev)		panic("mntchk 3: can't happen");	return m;}/* * Rewrite channel type and dev for in-flight data to * reflect local values.  These entries are known to be * the first two in the Dir encoding after the count. */voidmntdirfix(uchar *dirbuf, Chan *c){	uint r;	r = devtab[c->type]->dc;	dirbuf += BIT16SZ;	/* skip count */	PBIT16(dirbuf, r);	dirbuf += BIT16SZ;	PBIT32(dirbuf, c->dev);}intrpcattn(void *v){	Mntrpc *r;	r = v;	return r->done || r->m->rip == 0;}Dev mntdevtab = {	'M',	"mnt",	mntreset,	devinit,	devshutdown,	mntattach,	mntwalk,	mntstat,	mntopen,	mntcreate,	mntclose,	mntread,	devbread,	mntwrite,	devbwrite,	mntremove,	mntwstat,};

⌨️ 快捷键说明

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