char* rread(Fid *f) { char *buf; int64_t off; int cnt; VacFile *vf; char err[80]; int n; if(!f->busy) return vtstrdup(Enotexist); vf = f->file; thdr.count = 0; off = rhdr.offset; buf = thdr.data; cnt = rhdr.count; if(f->qid.type & QTDIR) n = vacdirread(f, buf, off, cnt); else if(vacfilegetmode(f->file)&ModeDevice) return vtstrdup("device"); else if(vacfilegetmode(f->file)&ModeLink) return vtstrdup("symbolic link"); else if(vacfilegetmode(f->file)&ModeNamedPipe) return vtstrdup("named pipe"); else n = vacfileread(vf, buf, cnt, off); if(n < 0) { rerrstr(err, sizeof err); return vtstrdup(err); } thdr.count = n; return 0; }
void unvac(VacFile *f, char *name, VacDir *vdir) { static char buf[65536]; int fd, n, m, bsize; ulong mode, mode9; char *newname; char *what; vlong off; Dir d, *dp; VacDirEnum *vde; VacDir newvdir; VacFile *newf; if(vdir) mode = vdir->mode; else mode = vacfilegetmode(f); if(vdir){ if(table){ if(chatty){ mode9 = vdir->mode&0777; if(mode&ModeDir) mode9 |= DMDIR; if(mode&ModeAppend) mode9 |= DMAPPEND; if(mode&ModeExclusive) mode9 |= DMEXCL; print("%M %-10s %-10s %11lld %t %s\n", mode9, vdir->uid, vdir->gid, vdir->size, vdir->mtime, name); }else print("%s%s\n", name, (mode&ModeDir) ? "/" : ""); } else if(chatty) fprint(2, "%s%s\n", name, (mode&ModeDir) ? "/" : ""); } if(mode&(ModeDevice|ModeLink|ModeNamedPipe|ModeExclusive)){ if(table) return; if(mode&ModeDevice) what = "device"; else if(mode&ModeLink) what = "link"; else if(mode&ModeNamedPipe) what = "named pipe"; else if(mode&ModeExclusive) what = "lock"; else what = "unknown type of file"; fprint(2, "warning: ignoring %s %s\n", what, name); return; } if(mode&ModeDir){ if((vde = vdeopen(f)) == nil){ fprint(2, "vdeopen %s: %r", name); errors++; return; } if(!table && !tostdout && vdir){ // create directory if((dp = dirstat(name)) == nil){ if((fd = create(name, OREAD, DMDIR|(mode&0777))) < 0){ fprint(2, "mkdir %s: %r\n", name); vdeclose(vde); } close(fd); }else{ if(!(dp->mode&DMDIR)){ fprint(2, "%s already exists and is not a directory\n", name); errors++; free(dp); vdeclose(vde); return; } free(dp); } } while(vderead(vde, &newvdir) > 0){ if(name == nil) newname = newvdir.elem; else newname = smprint("%s/%s", name, newvdir.elem); if(wantfile(newname)){ if((newf = vacfilewalk(f, newvdir.elem)) == nil){ fprint(2, "walk %s: %r\n", name); errors++; }else if(newf == f){ fprint(2, "walk loop: %s\n", newname); vacfiledecref(newf); }else{ unvac(newf, newname, &newvdir); vacfiledecref(newf); } } if(newname != newvdir.elem) free(newname); vdcleanup(&newvdir); } vdeclose(vde); }else{ if(!table){ off = 0; if(tostdout) fd = dup(1, -1); else if(diff && (fd = open(name, ORDWR)) >= 0){ bsize = vacfiledsize(f); while((n = readn(fd, buf, bsize)) > 0){ if(sha1matches(f, off/bsize, (uchar*)buf, n)){ off += n; stats.skipdata += n; continue; } seek(fd, off, 0); if((m = vacfileread(f, buf, n, off)) < 0) break; if(writen(fd, buf, m) != m){ fprint(2, "write %s: %r\n", name); goto Err; } off += m; stats.data += m; if(m < n){ nulldir(&d); d.length = off; if(dirfwstat(fd, &d) < 0){ fprint(2, "dirfwstat %s: %r\n", name); goto Err; } break; } } } else if((fd = create(name, OWRITE, mode&0777)) < 0){ fprint(2, "create %s: %r\n", name); errors++; return; } while((n = vacfileread(f, buf, sizeof buf, off)) > 0){ if(writen(fd, buf, n) != n){ fprint(2, "write %s: %r\n", name); Err: errors++; close(fd); remove(name); return; } off += n; stats.data += n; } close(fd); } } if(vdir && settimes && !tostdout){ nulldir(&d); d.mtime = vdir->mtime; if(dirwstat(name, &d) < 0) fprint(2, "warning: setting mtime on %s: %r", name); } }
char* rwalk(Fid *f) { VacFile *file, *nfile; Fid *nf; int nqid, nwname; Qid qid; char *err = nil; if(f->busy == 0) return Enotexist; nf = nil; if(rhdr.fid != rhdr.newfid){ if(f->open) return vtstrdup(Eisopen); if(f->busy == 0) return vtstrdup(Enotexist); nf = newfid(rhdr.newfid); if(nf->busy) return vtstrdup(Eisopen); nf->busy = 1; nf->open = 0; nf->qid = f->qid; nf->file = vacfileincref(f->file); nf->user = vtstrdup(f->user); f = nf; } nwname = rhdr.nwname; /* easy case */ if(nwname == 0) { thdr.nwqid = 0; return 0; } file = f->file; vacfileincref(file); qid = f->qid; for(nqid = 0; nqid < nwname; nqid++){ if((qid.type & QTDIR) == 0){ err = Enotdir; break; } if(!permf(file, f->user, Pexec)) { err = Eperm; break; } nfile = vacfilewalk(file, rhdr.wname[nqid]); if(nfile == nil) break; vacfiledecref(file); file = nfile; qid.type = QTFILE; if(vacfileisdir(file)) qid.type = QTDIR; #ifdef PLAN9PORT if(vacfilegetmode(file)&ModeLink) qid.type = QTSYMLINK; #endif qid.vers = vacfilegetmcount(file); qid.path = vacfilegetid(file); thdr.wqid[nqid] = qid; } thdr.nwqid = nqid; if(nqid == nwname){ /* success */ f->qid = thdr.wqid[nqid-1]; vacfiledecref(f->file); f->file = file; return 0; } vacfiledecref(file); if(nf != nil) rclunk(nf); /* only error on the first element */ if(nqid == 0) return vtstrdup(err); return 0; }