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; 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; }
int vacstat(VacFile *parent, VacDir *vd, uchar *p, int np) { int ret; Dir dir; #ifdef PLAN9PORT int n; VacFile *vf; uvlong size; char *ext = nil; #endif memset(&dir, 0, sizeof(dir)); dir.qid.path = vd->qid + vacfilegetqidoffset(parent); if(vd->qidspace) dir.qid.path += vd->qidoffset; dir.qid.vers = vd->mcount; dir.mode = vd->mode & 0777; if(vd->mode & ModeAppend){ dir.qid.type |= QTAPPEND; dir.mode |= DMAPPEND; } if(vd->mode & ModeExclusive){ dir.qid.type |= QTEXCL; dir.mode |= DMEXCL; } if(vd->mode & ModeDir){ dir.qid.type |= QTDIR; dir.mode |= DMDIR; } #ifdef PLAN9PORT if(vd->mode & (ModeLink|ModeDevice|ModeNamedPipe)){ vf = vacfilewalk(parent, vd->elem); if(vf == nil) return 0; vacfilegetsize(vf, &size); ext = malloc(size+1); if(ext == nil) return 0; n = vacfileread(vf, ext, size, 0); USED(n); ext[size] = 0; vacfiledecref(vf); if(vd->mode & ModeLink){ dir.qid.type |= QTSYMLINK; dir.mode |= DMSYMLINK; } if(vd->mode & ModeDevice) dir.mode |= DMDEVICE; if(vd->mode & ModeNamedPipe) dir.mode |= DMNAMEDPIPE; } #endif dir.atime = vd->atime; dir.mtime = vd->mtime; dir.length = vd->size; dir.name = vd->elem; dir.uid = vd->uid; dir.gid = vd->gid; dir.muid = vd->mid; ret = convD2M(&dir, p, np); #ifdef PLAN9PORT free(ext); #endif return ret; }