📄 chan.c
字号:
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 + -