void fsclunk(Fs *fs, Request *r, Fid *f) { if(f->attached == 0){ fsreply(fs, r, Enofid); return; } if(f->fd >= 0){ close(f->fd); f->fd = -1; } if((f->qid.type & QTDIR) == 0) closetar(f->df, f->dp); releasedf(f->df); f->df = nil; free(f->dir); f->dir = nil; fsreply(fs, r, nil); fsputfid(fs, f); }
void fswalk(Fs *fs, Request *r, Fid *f) { Fid *nf; char *name, *tmp; int i, nqid, nwname; char errbuf[ERRMAX], *err; Qid qid[MAXWELEM]; Dfile *lastdf; char *path, *npath; Dir *d; Symbol *dp; if(f->attached == 0){ fsreply(fs, r, Eexist); return; } if(f->fd >= 0 || f->open) fatal("walk of an open file"); nf = nil; if(r->f.newfid != r->f.fid){ nf = fsgetfid(fs, r->f.newfid); nf->attached = 1; nf->open = f->open; nf->path = strdup(f->path); nf->qid = f->qid; nf->dp = f->dp; nf->fd = f->fd; nf->df = f->df; if(nf->df){ lock(nf->df); nf->df->use++; unlock(nf->df); } if(r->f.nwname == 0){ r->f.nwqid = 0; fsreply(fs, r, nil); return; } f = nf; } err = nil; path = strdup(f->path); if(path == nil) fatal(mallocerr); nqid = 0; nwname = r->f.nwname; lastdf = f->df; if(nwname > 0){ for(; nqid<nwname; nqid++){ name = r->f.wname[nqid]; if(strcmp(name, ".") == 0){ Noop: if(nqid == 0) qid[nqid] = f->qid; else qid[nqid] = qid[nqid-1]; continue; } if(strcmp(name, "..") == 0){ name = strrchr(path, '/'); if(name){ if(name == path) /* at root */ goto Noop; *name = '\0'; } d = dirstat(path); if(d == nil){ *name = '/'; errstr(errbuf, sizeof errbuf); err = errbuf; break; } Directory: qid[nqid] = d->qid; free(d); releasedf(lastdf); lastdf = getdf(mkpath(path, ".depend")); continue; } npath = mkpath(path, name); free(path); path = npath; d = dirstat(path); if(d !=nil && (d->qid.type & QTDIR)) goto Directory; free(d); qid[nqid].type = QTFILE; qid[nqid].path = 0; qid[nqid].vers = 0; dp = dfsearch(lastdf, name); if(dp == nil){ tmp = strdup(name); if(tmp == nil) fatal("mallocerr"); i = strlen(tmp); if(i > 4 && strcmp(&tmp[i-4], ".tar") == 0){ tmp[i-4] = 0; dp = dfsearch(lastdf, tmp); } free(tmp); } if(dp == nil){ err = Eexist; break; } qid[nqid].path = (uvlong)dp; qid[nqid].vers = 0; } if(nqid == 0 && err == nil) err = "file does not exist"; } /* for error or partial success, put the cloned fid back*/ if(nf!=nil && (err != nil || nqid < nwname)){ releasedf(nf->df); nf->df = nil; fsputfid(fs, nf); } if(err == nil){ /* return (possibly short) list of qids */ for(i=0; i<nqid; i++) r->f.wqid[i] = qid[i]; r->f.nwqid = nqid; /* for full success, advance f */ if(nqid > 0 && nqid == nwname){ free(f->path); f->path = path; path = nil; f->qid = qid[nqid-1]; f->dp = (Symbol*)f->qid.path; if(f->df != lastdf){ releasedf(f->df); f->df = lastdf; lastdf = nil; } } } releasedf(lastdf); free(path); fsreply(fs, r, err); }
void fswalk(Fs *fs, Request *r, Fid *f) { char *name; int i; Dir d; char errbuf[ERRLEN]; char *path; Symbol *dp; if(f->attached == 0){ fsreply(fs, r, Enofid); return; } if(f->fd >= 0 || f->open) fatal("walk of an open file"); name = r->f.name; if(strcmp(name, ".") == 0){ fsreply(fs, r, nil); return; } if(strcmp(name, "..") == 0){ name = strrchr(f->path, '/'); if(name){ if(name == f->path){ fsreply(fs, r, nil); return; } *name = 0; } if(dirstat(f->path, &d) < 0){ *name = '/'; errstr(errbuf); fsreply(fs, r, errbuf); return; } r->f.qid = f->qid = d.qid; releasedf(f->df); f->df = getdf(mkpath(f->path, ".depend")); fsreply(fs, r, nil); return; } path = mkpath(f->path, name); if(dirstat(path, &d) < 0 || (d.qid.path & CHDIR) == 0){ dp = dfsearch(f->df, name); if(dp == nil){ i = strlen(name); if(i > 4 && strcmp(&name[i-4], ".tar") == 0){ name[i-4] = 0; dp = dfsearch(f->df, name); } } if(dp == nil){ fsreply(fs, r, Eexist); free(path); return; } f->dp = dp; d.qid.path = (uint)dp; d.qid.vers = 0; } free(f->path); f->path = path; if(d.qid.path & CHDIR){ releasedf(f->df); f->df = getdf(mkpath(f->path, ".depend")); } r->f.qid = f->qid = d.qid; fsreply(fs, r, nil); }
/* * Problem is that 9P doesn't allow seeking into a directory. So we * maintain a list of active fids for any given directory. They * start living at the first read and exist either until the directory * is closed or until they reach the end. */ int puffs9p_node_readdir(struct puffs_usermount *pu, void *opc, struct dirent *dent, off_t *readoff, size_t *reslen, const struct puffs_cred *pcr, int *eofflag, off_t *cookies, size_t *ncookies) { AUTOVAR(pu); struct puffs_node *pn = opc; struct p9pnode *p9n = pn->pn_data; struct vattr va; struct dirfid *dfp; char *name; uint32_t count; uint16_t statsize; rv = getdfwithoffset(pu, p9n, *readoff, &dfp); if (rv) goto out; tag = NEXTTAG(p9p); p9pbuf_put_1(pb, P9PROTO_T_READ); p9pbuf_put_2(pb, tag); p9pbuf_put_4(pb, dfp->fid); p9pbuf_put_8(pb, *readoff); p9pbuf_put_4(pb, *reslen); /* XXX */ GETRESPONSE(pb); p9pbuf_get_4(pb, &count); /* * if count is 0, assume we at end-of-dir. dfp is no longer * useful, so nuke it */ if (count == 0) { *eofflag = 1; releasedf(pu, dfp); goto out; } while (count > 0) { if ((rv = proto_getstat(pb, &va, &name, &statsize))) { /* * If there was an error, it's unlikely we'll be * coming back, so just nuke the dfp. If we do * come back for some strange reason, we'll just * regen it. */ releasedf(pu, dfp); goto out; } puffs_nextdent(&dent, name, va.va_fileid, puffs_vtype2dt(va.va_type), reslen); count -= statsize; *readoff += statsize; dfp->seekoff += statsize; free(name); } storedf(p9n, dfp); out: RETURN(rv); }