/* * Occasionally, pathnames are created that look like .../x/../y * Any of the 'x/..' sequences within the name can be eliminated. * (but only if 'x' is not a symbolic link!!) */ void remove_dotdot(char *path) { char *end, *from, *to, **cp; char *components[ MAXFILES ], newpath[ BUFSIZ ]; boolean component_copied; /* * slice path up into components. */ to = newpath; if (*path == '/') *to++ = '/'; *to = '\0'; cp = components; for (from=end=path; *end; end++) if (*end == '/') { while (*end == '/') *end++ = '\0'; if (*from) *cp++ = from; from = end; } *cp++ = from; *cp = NULL; /* * Recursively remove all 'x/..' component pairs. */ cp = components; while(*cp) { if (!isdot(*cp) && !isdotdot(*cp) && isdotdot(*(cp+1)) && !issymbolic(newpath, *cp)) { char **fp = cp + 2; char **tp = cp; do { *tp++ = *fp; /* move all the pointers down */ } while (*fp++); if (cp != components) cp--; /* go back and check for nested ".." */ } else { cp++; } } /* * Concatenate the remaining path elements. */ cp = components; component_copied = FALSE; while(*cp) { if (component_copied) *to++ = '/'; component_copied = TRUE; for (from = *cp; *from; ) *to++ = *from++; *to = '\0'; cp++; } *to++ = '\0'; /* * copy the reconstituted path back to our pointer. */ strcpy(path, newpath); }
static int vnop_lookup_9p(struct vnop_lookup_args *ap) { struct componentname *cnp; node_9p *dnp; vnode_t *vpp, dvp; fid_9p fid; qid_9p qid; int e; TRACE(); dvp = ap->a_dvp; vpp = ap->a_vpp; cnp = ap->a_cnp; dnp = NTO9P(dvp); if(!vnode_isdir(dvp)) return ENOTDIR; if (isdotdot(cnp) && vnode_isvroot(dvp)) return EIO; if (islastcn(cnp) && !isop(cnp, LOOKUP) && vnode_vfsisrdonly(dvp)) return EROFS; if (isdot(cnp)) { if (islastcn(cnp) && isop(cnp, RENAME)) return EISDIR; if ((e=vnode_get(dvp))) return e; *vpp = dvp; return 0; } if (isdotdot(cnp)) { *vpp = vnode_getparent(dvp); if (*vpp == NULL) return ENOENT; return 0; } e = cache_lookup(dvp, vpp, cnp); if (e == -1) /* found */ return 0; if (e != 0) /* errno */ return e; /* not in cache */ nlock_9p(dnp, NODE_LCK_EXCLUSIVE); e = walk_9p(dnp->nmp, dnp->fid, cnp->cn_nameptr, cnp->cn_namelen, &fid, &qid); if (e) { if (islastcn(cnp)) { if (isop(cnp, CREATE) || isop(cnp, RENAME)) e = EJUSTRETURN; else if (ismkentry(cnp) && dnp->dir.qid.vers!=0) cache_enter(dvp, NULL, cnp); } goto error; } e = nget_9p(dnp->nmp, fid, qid, dvp, vpp, cnp, ap->a_context); if (e || *vpp==NULL || NTO9P(*vpp)->fid!=fid) clunk_9p(dnp->nmp, fid); if (*vpp) nunlock_9p(NTO9P(*vpp)); error: nunlock_9p(dnp); return e; }
Walkqid* fswalk(Chan *c, Chan *nc, char **name, int nname) { int j, alloc; Walkqid *wq; Dir *dir; char *n; Cname *current, *next; Qid rootqid; if(nname > 0) isdir(c); /* do we need this? */ alloc = 0; current = nil; wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); if(waserror()){ if(alloc && wq->clone!=nil) cclose(wq->clone); cnameclose(current); free(wq); return nil; } if(nc == nil){ nc = devclone(c); nc->type = 0; alloc = 1; } wq->clone = nc; rootqid = FS(c)->rootqid; current = FS(c)->name; if(current != nil) incref(¤t->r); for(j=0; j<nname; j++){ if(!(nc->qid.type&QTDIR)){ if(j==0) error(Enotdir); break; } n = name[j]; if(strcmp(n, ".") != 0 && !(isdotdot(n) && nc->qid.path == rootqid.path)){ /* TO DO: underlying qids aliased */ //print("** ufs walk '%s' -> %s\n", current->s, n); next = current; incref(&next->r); next = addelem(current, n); dir = dirstat(next->s); if(dir == nil){ cnameclose(next); if(j == 0) error(Enonexist); strcpy(up->env->errstr, Enonexist); break; } nc->qid = dir->qid; free(dir); cnameclose(current); current = next; } wq->qid[wq->nqid++] = nc->qid; } // print("** ufs walk '%s'\n", current->s); poperror(); if(wq->nqid < nname){ cnameclose(current); if(alloc) cclose(wq->clone); wq->clone = nil; }else if(wq->clone){ /* now attach to our device */ nc->aux = smalloc(sizeof(Fsinfo)); nc->type = c->type; FS(nc)->rootqid = FS(c)->rootqid; FS(nc)->name = current; FS(nc)->fd = -1; FS(nc)->root = FS(c)->root; }else panic("fswalk: can't happen"); return wq; }