895 lines · 19.6 KB · Text
RawDownload
--- /sys/src/9/port/chan.c	Sun Dec 17 12:32:54 2017+++ ../frontmods/port/chan.c	Fri Dec 22 02:26:47 2017@@ -753,6 +753,128 @@ 	return nm->mountid; } +/* This and the other modified copies of existing functions use p- as a prefix */+/* They are mostly identical but take an additional parameter */+/* The additional parameter is a pointer to the process to be modified */++int+pcmount(Chan **newp, Chan *old, int flag, char *spec, Proc *targp)+{+	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 %#p\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 = targp->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(old, 0, 0);+	}+	wlock(&m->lock);+	if(waserror()){+		wunlock(&m->lock);+		nexterror();+	}+	wunlock(&pg->ns);++	nm = newmount(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(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;+}+ void cunmount(Chan *mnt, Chan *mounted) {@@ -823,6 +945,76 @@ 	error(Eunion); } +void+pcunmount(Chan *mnt, Chan *mounted, Proc *targp)+{+	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 = targp->pgrp;+	wlock(&pg->ns);++	l = &MOUNTH(pg, mnt->qid);+	for(m = *l; m != nil; m = m->hash){+		if(eqchan(m->from, mnt, 1))+			break;+		l = &m->hash;+	}++	if(m == nil){+		wunlock(&pg->ns);+		error(Eunmount);+	}++	wlock(&m->lock);+	f = m->mount;+	if(mounted == nil){+		*l = m->hash;+		m->mount = nil;+		wunlock(&m->lock);+		wunlock(&pg->ns);+		mountfree(f);+		putmhead(m);+		return;+	}+	for(p = &m->mount; f != nil; f = f->next){+		if(eqchan(f->to, mounted, 1) ||+		  (f->to->mchan != nil && eqchan(f->to->mchan, mounted, 1))){+			*p = f->next;+			f->next = nil;+			if(m->mount == nil){+				*l = m->hash;+				wunlock(&m->lock);+				wunlock(&pg->ns);+				mountfree(f);+				putmhead(m);+				return;+			}+			wunlock(&m->lock);+			wunlock(&pg->ns);+			mountfree(f);+			return;+		}+		p = &f->next;+	}+	wunlock(&m->lock);+	wunlock(&pg->ns);+	error(Eunion);+}+ Chan* cclone(Chan *c) {@@ -874,6 +1066,38 @@ 	return 0; } +int+pfindmount(Chan **cp, Mhead **mp, int type, int dev, Qid qid, Proc *targp)+{+	Chan *to;+	Pgrp *pg;+	Mhead *m;++	pg = targp->pgrp;+	rlock(&pg->ns);+	for(m = MOUNTH(pg, qid); m != nil; m = m->hash){+		if(eqchantdqid(m->from, type, dev, qid, 1)){+			rlock(&m->lock);+			runlock(&pg->ns);+			if(mp != nil)+				incref(m);+			to = m->mount->to;+			incref(to);+			runlock(&m->lock);+			if(mp != nil){+				putmhead(*mp);+				*mp = m;+			}+			if(*cp != nil)+				cclose(*cp);+			*cp = to;+			return 1;+		}+	}+	runlock(&pg->ns);+	return 0;+}+ /*  * Calls findmount but also updates path.  */@@ -904,6 +1128,33 @@ 	return 1; } +static int+pdomount(Chan **cp, Mhead **mp, Path **path, Proc *targp)+{+	Chan **lc, *from;+	Path *p;++	if(pfindmount(cp, mp, (*cp)->type, (*cp)->dev, (*cp)->qid, targp) == 0)+		return 0;++	if(path != nil){+		p = *path;+		p = uniquepath(p);+		if(p->mlen <= 0)+			print("pdomount: path %s has mlen==%d\n", p->s, p->mlen);+		else{+			from = (*mp)->from;+			incref(from);+			lc = &p->mtpt[p->mlen-1];+			if(*lc != nil)+				cclose(*lc);+			*lc = 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,@@ -1112,50 +1363,221 @@ 	return 0; } -/*- * c is a mounted non-creatable directory.  find a creatable one.- */-Chan*-createdir(Chan *c, Mhead *m)+int+pwalk(Chan **cp, char **names, int nnames, int nomount, int *nerror, Proc *targp) {-	Chan *nc;+	int dev, didmount, dotdot, i, n, nhave, ntry, type;+	Chan *c, *nc, *mtpt;+	Path *path;+	Mhead *mh, *nmh; 	Mount *f;+	Walkqid *wq; -	rlock(&m->lock);-	if(waserror()){-		runlock(&m->lock);-		nexterror();-	}-	for(f = m->mount; f != nil; f = f->next){-		if((f->mflag&MCREATE) != 0){-			nc = cclone(f->to);-			runlock(&m->lock);-			poperror();+	c = *cp;+	incref(c);+	path = c->path;+	incref(path);+	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);-			return nc;+			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;+			} 		}-	}-	error(Enocreate);-	return 0;-}--void-saveregisters(void)-{-} -static void-growparse(Elemlist *e)-{-	char **new;-	int *inew;-	enum { Delta = 8 };+		if(!dotdot && !nomount && !didmount)+			pdomount(&c, &mh, &path, targp);+		+		type = c->type;+		dev = c->dev; -	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;+		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(pfindmount(&nc, &nmh, type, dev, wq->qid[i], targp)){+						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!=nil)+					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;

Lines 1–500 of 895.