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

📄 chan.c

📁 在x86平台上运行不可信任代码的sandbox。
💻 C
📖 第 1 页 / 共 3 页
字号:
	if(a->dev != b->dev)		return 0;	return 1;}inteqchantdqid(Chan *a, int type, int dev, Qid qid, int skipvers){	if(a->qid.path != qid.path)		return 0;	if(!skipvers && a->qid.vers!=qid.vers)		return 0;	if(a->type != type)		return 0;	if(a->dev != dev)		return 0;	return 1;}Mhead*newmhead(Chan *from){	Mhead *mh;	mh = smalloc(sizeof(Mhead));	mh->ref.ref = 1;	mh->from = from;	incref(&from->ref);	return mh;}intcmount(Chan **newp, Chan *old, int flag, char *spec){	int order, flg;	Chan *new;	Mhead *m, **l, *mh;	Mount *nm, *f, *um, **h;	Pgrp *pg;	if(QTDIR & (old->qid.type^(*newp)->qid.type))		error(Emount);	if(old->umh)		print("cmount: unexpected umh, caller %.8lux\n", getcallerpc(&newp));	order = flag&MORDER;	if((old->qid.type&QTDIR)==0 && order != MREPL)		error(Emount);	new = *newp;	mh = new->umh;	/*	 * Not allowed to bind when the old directory is itself a union. 	 * (Maybe it should be allowed, but I don't see what the semantics	 * would be.)	 *	 * We need to check mh->mount->next to tell unions apart from	 * simple mount points, so that things like	 *	mount -c fd /root	 *	bind -c /root /	 * work.  	 * 	 * The check of mount->mflag allows things like	 *	mount fd /root	 *	bind -c /root /	 * 	 * This is far more complicated than it should be, but I don't	 * see an easier way at the moment.	 */	if((flag&MCREATE) && mh && mh->mount	&& (mh->mount->next || !(mh->mount->mflag&MCREATE)))		error(Emount);	pg = up->pgrp;	wlock(&pg->ns);	l = &MOUNTH(pg, old->qid);	for(m = *l; m; m = m->hash){		if(eqchan(m->from, old, 1))			break;		l = &m->hash;	}	if(m == nil){		/*		 *  nothing mounted here yet.  create a mount		 *  head and add to the hash table.		 */		m = newmhead(old);		*l = m;		/*		 *  if this is a union mount, add the old		 *  node to the mount chain.		 */		if(order != MREPL)			m->mount = newmount(m, old, 0, 0);	}	wlock(&m->lock);	if(waserror()){		wunlock(&m->lock);		nexterror();	}	wunlock(&pg->ns);	nm = newmount(m, new, flag, spec);	if(mh != nil && mh->mount != nil){		/*		 *  copy a union when binding it onto a directory		 */		flg = order;		if(order == MREPL)			flg = MAFTER;		h = &nm->next;		um = mh->mount;		for(um = um->next; um; um = um->next){			f = newmount(m, um->to, flg, um->spec);			*h = f;			h = &f->next;		}	}	if(m->mount && order == MREPL){		mountfree(m->mount);		m->mount = 0;	}	if(flag & MCREATE)		nm->mflag |= MCREATE;	if(m->mount && order == MAFTER){		for(f = m->mount; f->next; f = f->next)			;		f->next = nm;	}else{		for(f = nm; f->next; f = f->next)			;		f->next = m->mount;		m->mount = nm;	}	wunlock(&m->lock);	poperror();	return nm->mountid;}voidcunmount(Chan *mnt, Chan *mounted){	Pgrp *pg;	Mhead *m, **l;	Mount *f, **p;	if(mnt->umh)	/* should not happen */		print("cunmount newp extra umh %p has %p\n", mnt, mnt->umh);	/*	 * It _can_ happen that mounted->umh is non-nil, 	 * because mounted is the result of namec(Aopen)	 * (see sysfile.c:/^sysunmount).	 * If we open a union directory, it will have a umh.	 * Although surprising, this is okay, since the	 * cclose will take care of freeing the umh.	 */	pg = up->pgrp;	wlock(&pg->ns);	l = &MOUNTH(pg, mnt->qid);	for(m = *l; m; m = m->hash){		if(eqchan(m->from, mnt, 1))			break;		l = &m->hash;	}	if(m == 0){		wunlock(&pg->ns);		error(Eunmount);	}	wlock(&m->lock);	if(mounted == 0){		*l = m->hash;		wunlock(&pg->ns);		mountfree(m->mount);		m->mount = nil;		cclose(m->from);		wunlock(&m->lock);		putmhead(m);		return;	}	p = &m->mount;	for(f = *p; f; f = f->next){		/* BUG: Needs to be 2 pass */		if(eqchan(f->to, mounted, 1) ||		  (f->to->mchan && eqchan(f->to->mchan, mounted, 1))){			*p = f->next;			f->next = 0;			mountfree(f);			if(m->mount == nil){				*l = m->hash;				cclose(m->from);				wunlock(&m->lock);				wunlock(&pg->ns);				putmhead(m);				return;			}			wunlock(&m->lock);			wunlock(&pg->ns);			return;		}		p = &f->next;	}	wunlock(&m->lock);	wunlock(&pg->ns);	error(Eunion);}Chan*cclone(Chan *c){	Chan *nc;	Walkqid *wq;	wq = devtab[c->type]->walk(c, nil, nil, 0);	if(wq == nil)		error("clone failed");	nc = wq->clone;	free(wq);	nc->path = c->path;	if(c->path)		incref(&c->path->ref);	return nc;}/* also used by sysfile.c:/^mountfix */intfindmount(Chan **cp, Mhead **mp, int type, int dev, Qid qid){	Pgrp *pg;	Mhead *m;	pg = up->pgrp;	rlock(&pg->ns);	for(m = MOUNTH(pg, qid); m; m = m->hash){		rlock(&m->lock);		if(m->from == nil){			print("m %p m->from 0\n", m);			runlock(&m->lock);			continue;		}		if(eqchantdqid(m->from, type, dev, qid, 1)){			runlock(&pg->ns);			if(mp != nil){				incref(&m->ref);				if(*mp != nil)					putmhead(*mp);				*mp = m;			}			if(*cp != nil)				cclose(*cp);			incref(&m->mount->to->ref);			*cp = m->mount->to;			runlock(&m->lock);			return 1;		}		runlock(&m->lock);	}	runlock(&pg->ns);	return 0;}/* * Calls findmount but also updates path. */static intdomount(Chan **cp, Mhead **mp, Path **path){	Chan **lc;	Path *p;	if(findmount(cp, mp, (*cp)->type, (*cp)->dev, (*cp)->qid) == 0)		return 0;	if(path){		p = *path;		p = uniquepath(p);		if(p->mlen <= 0)			print("domount: path %s has mlen==%d\n", p->s, p->mlen);		else{			lc = &p->mtpt[p->mlen-1];DBG("domount %p %s => add %p (was %p)\n", p, p->s, (*mp)->from, p->mtpt[p->mlen-1]);			incref(&(*mp)->from->ref);			if(*lc)				cclose(*lc);			*lc = (*mp)->from;		}		*path = p;	}	return 1;}/* * If c is the right-hand-side of a mount point, returns the left hand side. * Changes name to reflect the fact that we've uncrossed the mountpoint, * so name had better be ours to change! */static Chan*undomount(Chan *c, Path *path){	Chan *nc;	if(path->ref.ref != 1 || path->mlen == 0)		print("undomount: path %s ref %ld mlen %d caller %lux\n",			path->s, path->ref.ref, path->mlen, getcallerpc(&c));	if(path->mlen>0 && (nc=path->mtpt[path->mlen-1]) != nil){DBG("undomount %p %s => remove %p\n", path, path->s, nc);		cclose(c);		path->mtpt[path->mlen-1] = nil;		c = nc;	}	return c;}/* * Call dev walk but catch errors. */static Walkqid*ewalk(Chan *c, Chan *nc, char **name, int nname){	Walkqid *wq;	if(waserror())		return nil;	wq = devtab[c->type]->walk(c, nc, name, nname);	poperror();	return wq;}/* * Either walks all the way or not at all.  No partial results in *cp. * *nerror is the number of names to display in an error message. */static char Edoesnotexist[] = "does not exist";intwalk(Chan **cp, char **names, int nnames, int nomount, int *nerror){	int dev, didmount, dotdot, i, n, nhave, ntry, type;	Chan *c, *nc, *mtpt;	Path *path;	Mhead *mh, *nmh;	Mount *f;	Walkqid *wq;	c = *cp;	incref(&c->ref);	path = c->path;	incref(&path->ref);	mh = nil;	/*	 * While we haven't gotten all the way down the path:	 *    1. step through a mount point, if any	 *    2. send a walk request for initial dotdot or initial prefix without dotdot	 *    3. move to the first mountpoint along the way.	 *    4. repeat.	 *	 * Each time through the loop:	 *	 *	If didmount==0, c is on the undomount side of the mount point.	 *	If didmount==1, c is on the domount side of the mount point.	 * 	Either way, c's full path is path.	 */	didmount = 0;	for(nhave=0; nhave<nnames; nhave+=n){		if((c->qid.type&QTDIR)==0){			if(nerror)				*nerror = nhave;			pathclose(path);			cclose(c);			strcpy(up->errstr, Enotdir);			if(mh != nil)				putmhead(mh);			return -1;		}		ntry = nnames - nhave;		if(ntry > MAXWELEM)			ntry = MAXWELEM;		dotdot = 0;		for(i=0; i<ntry; i++){			if(isdotdot(names[nhave+i])){				if(i==0){					dotdot = 1;					ntry = 1;				}else					ntry = i;				break;			}		}		if(!dotdot && !nomount && !didmount)			domount(&c, &mh, &path);				type = c->type;		dev = c->dev;		if((wq = ewalk(c, nil, names+nhave, ntry)) == nil){			/* try a union mount, if any */			if(mh && !nomount){				/*				 * mh->mount->to == c, so start at mh->mount->next				 */				rlock(&mh->lock);				for(f = mh->mount->next; f; f = f->next)					if((wq = ewalk(f->to, nil, names+nhave, ntry)) != nil)						break;				runlock(&mh->lock);				if(f != nil){					type = f->to->type;					dev = f->to->dev;				}			}			if(wq == nil){				cclose(c);				pathclose(path);				if(nerror)					*nerror = nhave+1;				if(mh != nil)					putmhead(mh);				return -1;			}		}		didmount = 0;		if(dotdot){			assert(wq->nqid == 1);			assert(wq->clone != nil);			path = addelem(path, "..", nil);			nc = undomount(wq->clone, path);			nmh = nil;			n = 1;		}else{			nc = nil;			nmh = nil;			if(!nomount){				for(i=0; i<wq->nqid && i<ntry-1; i++){					if(findmount(&nc, &nmh, type, dev, wq->qid[i])){						didmount = 1;						break;					}				}			}			if(nc == nil){	/* no mount points along path */				if(wq->clone == nil){					cclose(c);					pathclose(path);					if(wq->nqid==0 || (wq->qid[wq->nqid-1].type&QTDIR)){						if(nerror)							*nerror = nhave+wq->nqid+1;						strcpy(up->errstr, Edoesnotexist);					}else{						if(nerror)							*nerror = nhave+wq->nqid;						strcpy(up->errstr, Enotdir);					}					free(wq);					if(mh != nil)						putmhead(mh);					return -1;				}				n = wq->nqid;				nc = wq->clone;			}else{		/* stopped early, at a mount point */				didmount = 1;				if(wq->clone != nil){					cclose(wq->clone);					wq->clone = nil;				}				n = i+1;			}			for(i=0; i<n; i++){				mtpt = nil;				if(i==n-1 && nmh)					mtpt = nmh->from;				path = addelem(path, names[nhave+i], mtpt);			}		}		cclose(c);		c = nc;		putmhead(mh);		mh = nmh;		free(wq);	}	putmhead(mh);	c = cunique(c);	if(c->umh != nil){	//BUG		print("walk umh\n");		putmhead(c->umh);		c->umh = nil;	}	pathclose(c->path);	c->path = path;	cclose(*cp);	*cp = c;	if(nerror)		*nerror = nhave;	return 0;}/* * c is a mounted non-creatable directory.  find a creatable one. */Chan*createdir(Chan *c, Mhead *m){	Chan *nc;	Mount *f;	rlock(&m->lock);	if(waserror()){		runlock(&m->lock);		nexterror();	}	for(f = m->mount; f; f = f->next){		if(f->mflag&MCREATE){			nc = cclone(f->to);			runlock(&m->lock);			poperror();			cclose(c);			return nc;		}	}	error(Enocreate);	return 0;}voidsaveregisters(void){}static voidgrowparse(Elemlist *e){	char **new;	int *inew;	enum { Delta = 8 };	if(e->nelems % Delta == 0){		new = smalloc((e->nelems+Delta) * sizeof(char*));		memmove(new, e->elems, e->nelems*sizeof(char*));		free(e->elems);		e->elems = new;		inew = smalloc((e->nelems+Delta+1) * sizeof(int));		memmove(inew, e->off, (e->nelems+1)*sizeof(int));		free(e->off);		e->off = inew;	}}/* * The name is known to be valid. * Copy the name so slashes can be overwritten. * An empty string will set nelem=0. * A path ending in / or /. or /.//./ etc. will have * e.mustbedir = 1, so that we correctly * reject, e.g., "/adm/users/." when /adm/users is a file * rather than a directory. */static voidparsename(char *aname, Elemlist *e){	char *name, *slash;	kstrdup(&e->name, aname);	name = e->name;	e->nelems = 0;	e->elems = nil;	e->off = smalloc(sizeof(int));	e->off[0] = skipslash(name) - name;	for(;;){		name = skipslash(name);		if(*name == '\0'){

⌨️ 快捷键说明

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