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

📄 sysfile.c

📁 在x86平台上运行不可信任代码的sandbox。
💻 C
📖 第 1 页 / 共 2 页
字号:
#include	"u.h"#include	"lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"error.h"/* * The sys*() routines needn't poperror() as they return directly to syscall(). */static voidunlockfgrp(Fgrp *f){	int ex;	ex = f->exceed;	f->exceed = 0;	unlock(&f->ref.lk);	if(ex)		pprint("warning: process exceeds %d file descriptors\n", ex);}intgrowfd(Fgrp *f, int fd)	/* fd is always >= 0 */{	Chan **newfd, **oldfd;	if(fd < f->nfd)		return 0;	if(fd >= f->nfd+DELTAFD)		return -1;	/* out of range */	/*	 * Unbounded allocation is unwise; besides, there are only 16 bits	 * of fid in 9P	 */	if(f->nfd >= 5000){    Exhausted:		print("no free file descriptors\n");		return -1;	}	newfd = malloc((f->nfd+DELTAFD)*sizeof(Chan*));	if(newfd == 0)		goto Exhausted;	oldfd = f->fd;	memmove(newfd, oldfd, f->nfd*sizeof(Chan*));	f->fd = newfd;	free(oldfd);	f->nfd += DELTAFD;	if(fd > f->maxfd){		if(fd/100 > f->maxfd/100)			f->exceed = (fd/100)*100;		f->maxfd = fd;	}	return 1;}/* *  this assumes that the fgrp is locked */intfindfreefd(Fgrp *f, int start){	int fd;	for(fd=start; fd<f->nfd; fd++)		if(f->fd[fd] == 0)			break;	if(fd >= f->nfd && growfd(f, fd) < 0)		return -1;	return fd;}intnewfd(Chan *c){	int fd;	Fgrp *f;	f = up->fgrp;	lock(&f->ref.lk);	fd = findfreefd(f, 0);	if(fd < 0){		unlockfgrp(f);		return -1;	}	if(fd > f->maxfd)		f->maxfd = fd;	f->fd[fd] = c;	unlockfgrp(f);	return fd;}intnewfd2(int fd[2], Chan *c[2]){	Fgrp *f;	f = up->fgrp;	lock(&f->ref.lk);	fd[0] = findfreefd(f, 0);	if(fd[0] < 0){		unlockfgrp(f);		return -1;	}	fd[1] = findfreefd(f, fd[0]+1);	if(fd[1] < 0){		unlockfgrp(f);		return -1;	}	if(fd[1] > f->maxfd)		f->maxfd = fd[1];	f->fd[fd[0]] = c[0];	f->fd[fd[1]] = c[1];	unlockfgrp(f);	return 0;}Chan*fdtochan(int fd, int mode, int chkmnt, int iref){	Chan *c;	Fgrp *f;	c = 0;	f = up->fgrp;	lock(&f->ref.lk);	if(fd<0 || f->nfd<=fd || (c = f->fd[fd])==0) {		unlock(&f->ref.lk);		error(Ebadfd);	}	if(iref)		incref(&c->ref);	unlock(&f->ref.lk);	if(chkmnt && (c->flag&CMSG)) {		if(iref)			cclose(c);		error(Ebadusefd);	}	if(mode<0 || c->mode==ORDWR)		return c;	if((mode&OTRUNC) && c->mode==OREAD) {		if(iref)			cclose(c);		error(Ebadusefd);	}	if((mode&~OTRUNC) != c->mode) {		if(iref)			cclose(c);		error(Ebadusefd);	}	return c;}intopenmode(ulong o){	o &= ~(OTRUNC|OCEXEC|ORCLOSE);	if(o > OEXEC)		error(Ebadarg);	if(o == OEXEC)		return OREAD;	return o;}longsysfd2path(ulong *arg){	Chan *c;	char *buf;		buf = uvalidaddr(arg[1], arg[2], 1);	c = fdtochan(arg[0], -1, 0, 1);	snprint(buf, arg[2], "%s", chanpath(c));	cclose(c);	return 0;}longsyspipe(ulong *arg){	int fd[2];	Chan *c[2];	Dev *d;	static char *datastr[] = {"data", "data1"};	long *ufd;		ufd = uvalidaddr(arg[0], 2*BY2WD, 1);	evenaddr(arg[0]);	d = devtab[devno('|', 0)];	c[0] = namec("#|", Atodir, 0, 0);	c[1] = 0;	fd[0] = -1;	fd[1] = -1;	if(waserror()){		cclose(c[0]);		if(c[1])			cclose(c[1]);		nexterror();	}	c[1] = cclone(c[0]);	if(walk(&c[0], datastr+0, 1, 1, nil) < 0)		error(Egreg);	if(walk(&c[1], datastr+1, 1, 1, nil) < 0)		error(Egreg);	c[0] = d->open(c[0], ORDWR);	c[1] = d->open(c[1], ORDWR);	if(newfd2(fd, c) < 0)		error(Enofd);	poperror();	ufd[0] = fd[0];	ufd[1] = fd[1];	return 0;}longsysdup(ulong *arg){	int fd;	Chan *c, *oc;	Fgrp *f = up->fgrp;	/*	 * Close after dup'ing, so date > #d/1 works	 */	c = fdtochan(arg[0], -1, 0, 1);	fd = arg[1];	if(fd != -1){		lock(&f->ref.lk);		if(fd<0 || growfd(f, fd)<0) {			unlockfgrp(f);			cclose(c);			error(Ebadfd);		}		if(fd > f->maxfd)			f->maxfd = fd;		oc = f->fd[fd];		f->fd[fd] = c;		unlockfgrp(f);		if(oc)			cclose(oc);	}else{		if(waserror()) {			cclose(c);			nexterror();		}		fd = newfd(c);		if(fd < 0)			error(Enofd);		poperror();	}	return fd;}longsysopen(ulong *arg){	int fd;	Chan *c = 0;	char *name;	openmode(arg[1]);	/* error check only */	name = uvalidaddr(arg[0], 1, 0);	c = namec(name, Aopen, arg[1], 0);	if(waserror()){		cclose(c);		nexterror();	}	fd = newfd(c);	if(fd < 0)		error(Enofd);	poperror();	return fd;}voidfdclose(int fd, int flag){	int i;	Chan *c;	Fgrp *f = up->fgrp;	lock(&f->ref.lk);	c = f->fd[fd];	if(c == 0){		/* can happen for users with shared fd tables */		unlock(&f->ref.lk);		return;	}	if(flag){		if(c==0 || !(c->flag&flag)){			unlock(&f->ref.lk);			return;		}	}	f->fd[fd] = 0;	if(fd == f->maxfd)		for(i=fd; --i>=0 && f->fd[i]==0; )			f->maxfd = i;	unlock(&f->ref.lk);	cclose(c);}longsysclose(ulong *arg){	fdtochan(arg[0], -1, 0, 0);	fdclose(arg[0], 0);	return 0;}longunionread(Chan *c, void *va, long n){	int i;	long nr;	Mhead *m;	Mount *mount;	qlock(&c->umqlock);	m = c->umh;	rlock(&m->lock);	mount = m->mount;	/* bring mount in sync with c->uri and c->umc */	for(i = 0; mount != nil && i < c->uri; i++)		mount = mount->next;	nr = 0;	while(mount != nil){		/* Error causes component of union to be skipped */		if(mount->to && !waserror()){			if(c->umc == nil){				c->umc = cclone(mount->to);				c->umc = devtab[c->umc->type]->open(c->umc, OREAD);			}				nr = devtab[c->umc->type]->read(c->umc, va, n, c->umc->offset);			c->umc->offset += nr;			poperror();		}		if(nr > 0)			break;		/* Advance to next element */		c->uri++;		if(c->umc){			cclose(c->umc);			c->umc = nil;		}		mount = mount->next;	}	runlock(&m->lock);	qunlock(&c->umqlock);	return nr;}static voidunionrewind(Chan *c){	qlock(&c->umqlock);	c->uri = 0;	if(c->umc){		cclose(c->umc);		c->umc = nil;	}	qunlock(&c->umqlock);}static intdirfixed(uchar *p, uchar *e, Dir *d){	int len;	len = GBIT16(p)+BIT16SZ;	if(p + len > e)		return -1;	p += BIT16SZ;	/* ignore size */	d->type = devno(GBIT16(p), 1);	p += BIT16SZ;	d->dev = GBIT32(p);	p += BIT32SZ;	d->qid.type = GBIT8(p);	p += BIT8SZ;	d->qid.vers = GBIT32(p);	p += BIT32SZ;	d->qid.path = GBIT64(p);	p += BIT64SZ;	d->mode = GBIT32(p);	p += BIT32SZ;	d->atime = GBIT32(p);	p += BIT32SZ;	d->mtime = GBIT32(p);	p += BIT32SZ;	d->length = GBIT64(p);	return len;}static char*dirname(uchar *p, int *n){	p += BIT16SZ+BIT16SZ+BIT32SZ+BIT8SZ+BIT32SZ+BIT64SZ		+ BIT32SZ+BIT32SZ+BIT32SZ+BIT64SZ;	*n = GBIT16(p);	return (char*)p+BIT16SZ;}static longdirsetname(char *name, int len, uchar *p, long n, long maxn){	char *oname;	int olen;	long nn;	if(n == BIT16SZ)		return BIT16SZ;	oname = dirname(p, &olen);	nn = n+len-olen;	PBIT16(p, nn-BIT16SZ);	if(nn > maxn)		return BIT16SZ;	if(len != olen)		memmove(oname+len, oname+olen, p+n-(uchar*)(oname+olen));	PBIT16((uchar*)(oname-2), len);	memmove(oname, name, len);	return nn;}/* * Mountfix might have caused the fixed results of the directory read * to overflow the buffer.  Catch the overflow in c->dirrock. */static voidmountrock(Chan *c, uchar *p, uchar **pe){	uchar *e, *r;	int len, n;	e = *pe;	/* find last directory entry */	for(;;){		len = BIT16SZ+GBIT16(p);		if(p+len >= e)			break;		p += len;	}	/* save it away */	qlock(&c->rockqlock);	if(c->nrock+len > c->mrock){		n = ROUND(c->nrock+len, 1024);		r = smalloc(n);		memmove(r, c->dirrock, c->nrock);		free(c->dirrock);		c->dirrock = r;		c->mrock = n;	}	memmove(c->dirrock+c->nrock, p, len);	c->nrock += len;	qunlock(&c->rockqlock);	/* drop it */	*pe = p;}/* * Satisfy a directory read with the results saved in c->dirrock. */static intmountrockread(Chan *c, uchar *op, long n, long *nn){	long dirlen;	uchar *rp, *erp, *ep, *p;	/* common case */	if(c->nrock == 0)		return 0;	/* copy out what we can */	qlock(&c->rockqlock);	rp = c->dirrock;	erp = rp+c->nrock;	p = op;	ep = p+n;	while(rp+BIT16SZ <= erp){		dirlen = BIT16SZ+GBIT16(rp);		if(p+dirlen > ep)			break;		memmove(p, rp, dirlen);		p += dirlen;		rp += dirlen;	}	if(p == op){		qunlock(&c->rockqlock);		return 0;	}	/* shift the rest */	if(rp != erp)		memmove(c->dirrock, rp, erp-rp);	c->nrock = erp - rp;	*nn = p - op;	qunlock(&c->rockqlock);	return 1;}static voidmountrewind(Chan *c){	c->nrock = 0;}/* * Rewrite the results of a directory read to reflect current  * name space bindings and mounts.  Specifically, replace * directory entries for bind and mount points with the results * of statting what is mounted there.  Except leave the old names. */static longmountfix(Chan *c, uchar *op, long n, long maxn){	char *name;	int nbuf, nname;	Chan *nc;	Mhead *mh;	Mount *m;	uchar *p;	int dirlen, rest;	long l;	uchar *buf, *e;	Dir d;	p = op;	buf = nil;	nbuf = 0;	for(e=&p[n]; p+BIT16SZ<e; p+=dirlen){		dirlen = dirfixed(p, e, &d);		if(dirlen < 0)			break;		nc = nil;		mh = nil;		if(findmount(&nc, &mh, d.type, d.dev, d.qid)){			/*			 * If it's a union directory and the original is			 * in the union, don't rewrite anything.			 */			for(m=mh->mount; m; m=m->next)				if(eqchantdqid(m->to, d.type, d.dev, d.qid, 1))					goto Norewrite;			name = dirname(p, &nname);			/*			 * Do the stat but fix the name.  If it fails, leave old entry.			 * BUG: If it fails because there isn't room for the entry,			 * what can we do?  Nothing, really.  Might as well skip it.			 */			if(buf == nil){				buf = smalloc(4096);				nbuf = 4096;			}			if(waserror())				goto Norewrite;			l = devtab[nc->type]->stat(nc, buf, nbuf);			l = dirsetname(name, nname, buf, l, nbuf);			if(l == BIT16SZ)				error("dirsetname");			poperror();			/*			 * Shift data in buffer to accomodate new entry,			 * possibly overflowing into rock.			 */			rest = e - (p+dirlen);			if(l > dirlen){				while(p+l+rest > op+maxn){					mountrock(c, p, &e);					if(e == p){						dirlen = 0;						goto Norewrite;					}					rest = e - (p+dirlen);				}			}			if(l != dirlen){				memmove(p+l, p+dirlen, rest);				dirlen = l;				e = p+dirlen+rest;			}			/*			 * Rewrite directory entry.			 */			memmove(p, buf, l);		    Norewrite:			cclose(nc);			putmhead(mh);		}	}	if(buf)		free(buf);	if(p != e)		error("oops in rockfix");	return e-op;}static longdoread(ulong *arg, vlong *offp){	int dir;	long n, nn, nnn;	uchar *p;	Chan *c;	vlong off;	n = arg[2];	p = uvalidaddr(arg[1], n, 1);	c = fdtochan(arg[0], OREAD, 1, 1);	if(waserror()){		cclose(c);		nexterror();	}	/*	 * The offset is passed through on directories, normally.	 * Sysseek complains, but pread is used by servers like exportfs,	 * that shouldn't need to worry about this issue.	 *	 * Notice that c->devoffset is the offset that c's dev is seeing.	 * The number of bytes read on this fd (c->offset) may be different	 * due to rewritings in rockfix.	 */	if(offp == nil)	/* use and maintain channel's offset */		off = c->offset;	else		off = *offp;	if(off < 0)		error(Enegoff);	if(off == 0){	/* rewind to the beginning of the directory */		if(offp == nil){			c->offset = 0;			c->devoffset = 0;		}		mountrewind(c);		unionrewind(c);	}	dir = c->qid.type&QTDIR;	if(dir && mountrockread(c, p, n, &nn)){		/* do nothing: mountrockread filled buffer */	}else{		if(dir && c->umh)			nn = unionread(c, p, n);		else			nn = devtab[c->type]->read(c, p, n, off);	}	if(dir)		nnn = mountfix(c, p, nn, n);	else		nnn = nn;

⌨️ 快捷键说明

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