123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- #include "stdinc.h"
- #include <fcall.h> /* dirmodefmt */
- #include "vac.h"
- #pragma varargck type "t" ulong
- VacFs *fs;
- int tostdout;
- int diff;
- int nwant;
- char **want;
- int *found;
- int chatty;
- VtConn *conn;
- int errors;
- int settimes;
- int table;
- int mtimefmt(Fmt*);
- void unvac(VacFile*, char*, VacDir*);
- void
- usage(void)
- {
- fprint(2, "usage: unvac [-TVcdtv] [-h host] file.vac [file ...]\n");
- threadexitsall("usage");
- }
- struct
- {
- vlong data;
- vlong skipdata;
- } stats;
- void
- threadmain(int argc, char *argv[])
- {
- int i, printstats;
- char *host;
- VacFile *f;
- fmtinstall('H', encodefmt);
- fmtinstall('V', vtscorefmt);
- fmtinstall('F', vtfcallfmt);
- fmtinstall('t', mtimefmt);
- fmtinstall('M', dirmodefmt);
-
- host = nil;
- printstats = 0;
- ARGBEGIN{
- case 'T':
- settimes = 1;
- break;
- case 'V':
- chattyventi = 1;
- break;
- case 'c':
- tostdout++;
- break;
- case 'd':
- diff++;
- break;
- case 'h':
- host = EARGF(usage());
- break;
- case 's':
- printstats++;
- break;
- case 't':
- table++;
- break;
- case 'v':
- chatty++;
- break;
- default:
- usage();
- }ARGEND
- if(argc < 1)
- usage();
- if(tostdout && diff){
- fprint(2, "cannot use -c with -d\n");
- usage();
- }
- conn = vtdial(host);
- if(conn == nil)
- sysfatal("could not connect to server: %r");
- if(vtconnect(conn) < 0)
- sysfatal("vtconnect: %r");
- fs = vacfsopen(conn, argv[0], VtOREAD, 128);
- if(fs == nil)
- sysfatal("vacfsopen: %r");
- nwant = argc-1;
- want = argv+1;
- found = vtmallocz(nwant*sizeof found[0]);
- if((f = vacfsgetroot(fs)) == nil)
- sysfatal("vacfsgetroot: %r");
-
- unvac(f, nil, nil);
- for(i=0; i<nwant; i++){
- if(want[i] && !found[i]){
- fprint(2, "warning: didn't find %s\n", want[i]);
- errors++;
- }
- }
- if(errors)
- threadexitsall("errors");
- if(printstats)
- fprint(2, "%lld bytes read, %lld bytes skipped\n",
- stats.data, stats.skipdata);
- threadexitsall(0);
- }
- int
- writen(int fd, char *buf, int n)
- {
- int m;
- int oldn;
-
- oldn = n;
- while(n > 0){
- m = write(fd, buf, n);
- if(m <= 0)
- return -1;
- buf += m;
- n -= m;
- }
- return oldn;
- }
- int
- wantfile(char *name)
- {
- int i, namelen, n;
-
- if(nwant == 0)
- return 1;
- namelen = strlen(name);
- for(i=0; i<nwant; i++){
- if(want[i] == nil)
- continue;
- n = strlen(want[i]);
- if(n < namelen && name[n] == '/' && memcmp(name, want[i], n) == 0)
- return 1;
- if(namelen < n && want[i][namelen] == '/' && memcmp(want[i], name, namelen) == 0)
- return 1;
- if(n == namelen && memcmp(name, want[i], n) == 0){
- found[i] = 1;
- return 1;
- }
- }
- 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);
- }
- }
- int
- mtimefmt(Fmt *f)
- {
- Tm *tm;
-
- tm = localtime(va_arg(f->args, ulong));
- fmtprint(f, "%04d-%02d-%02d %02d:%02d",
- tm->year+1900, tm->mon+1, tm->mday,
- tm->hour, tm->min);
- return 0;
- }
|