--- /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. Load more
--- /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;