URI:
       tunvac.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tunvac.c (6517B)
       ---
            1 #include "stdinc.h"
            2 #include <fcall.h>        /* dirmodefmt */
            3 #include "vac.h"
            4 
            5 #ifndef PLAN9PORT
            6 #pragma varargck type "t" ulong
            7 #endif
            8 
            9 VacFs *fs;
           10 int tostdout;
           11 int diff;
           12 int nwant;
           13 char **want;
           14 int *found;
           15 int chatty;
           16 VtConn *conn;
           17 int errors;
           18 int settimes;
           19 int table;
           20 
           21 int mtimefmt(Fmt*);
           22 void unvac(VacFile*, char*, VacDir*);
           23 
           24 void
           25 usage(void)
           26 {
           27         fprint(2, "usage: unvac [-TVcdtv] [-h host] file.vac [file ...]\n");
           28         threadexitsall("usage");
           29 }
           30 
           31 struct
           32 {
           33         vlong data;
           34         vlong skipdata;
           35 } stats;
           36 
           37 void
           38 threadmain(int argc, char *argv[])
           39 {
           40         int i, printstats;
           41         char *host;
           42         VacFile *f;
           43 
           44         fmtinstall('H', encodefmt);
           45         fmtinstall('V', vtscorefmt);
           46         fmtinstall('F', vtfcallfmt);
           47         fmtinstall('t', mtimefmt);
           48         fmtinstall('M', dirmodefmt);
           49 
           50         host = nil;
           51         printstats = 0;
           52 
           53         ARGBEGIN{
           54         case 'T':
           55                 settimes = 1;
           56                 break;
           57         case 'V':
           58                 chattyventi = 1;
           59                 break;
           60         case 'c':
           61                 tostdout++;
           62                 break;
           63         case 'd':
           64                 diff++;
           65                 break;
           66         case 'h':
           67                 host = EARGF(usage());
           68                 break;
           69         case 's':
           70                 printstats++;
           71                 break;
           72         case 't':
           73                 table++;
           74                 break;
           75         case 'v':
           76                 chatty++;
           77                 break;
           78         default:
           79                 usage();
           80         }ARGEND
           81 
           82         if(argc < 1)
           83                 usage();
           84 
           85         if(tostdout && diff){
           86                 fprint(2, "cannot use -c with -d\n");
           87                 usage();
           88         }
           89 
           90         conn = vtdial(host);
           91         if(conn == nil)
           92                 sysfatal("could not connect to server: %r");
           93 
           94         if(vtconnect(conn) < 0)
           95                 sysfatal("vtconnect: %r");
           96 
           97         fs = vacfsopen(conn, argv[0], VtOREAD, 128<<20);
           98         if(fs == nil)
           99                 sysfatal("vacfsopen: %r");
          100 
          101         nwant = argc-1;
          102         want = argv+1;
          103         found = vtmallocz(nwant*sizeof found[0]);
          104 
          105         if((f = vacfsgetroot(fs)) == nil)
          106                 sysfatal("vacfsgetroot: %r");
          107 
          108         unvac(f, nil, nil);
          109         for(i=0; i<nwant; i++){
          110                 if(want[i] && !found[i]){
          111                         fprint(2, "warning: didn't find %s\n", want[i]);
          112                         errors++;
          113                 }
          114         }
          115         if(errors)
          116                 threadexitsall("errors");
          117         if(printstats)
          118                 fprint(2, "%lld bytes read, %lld bytes skipped\n",
          119                         stats.data, stats.skipdata);
          120         threadexitsall(0);
          121 }
          122 
          123 int
          124 writen(int fd, char *buf, int n)
          125 {
          126         int m;
          127         int oldn;
          128 
          129         oldn = n;
          130         while(n > 0){
          131                 m = write(fd, buf, n);
          132                 if(m <= 0)
          133                         return -1;
          134                 buf += m;
          135                 n -= m;
          136         }
          137         return oldn;
          138 }
          139 
          140 int
          141 wantfile(char *name)
          142 {
          143         int i, namelen, n;
          144 
          145         if(nwant == 0)
          146                 return 1;
          147 
          148         namelen = strlen(name);
          149         for(i=0; i<nwant; i++){
          150                 if(want[i] == nil)
          151                         continue;
          152                 n = strlen(want[i]);
          153                 if(n < namelen && name[n] == '/' && memcmp(name, want[i], n) == 0)
          154                         return 1;
          155                 if(namelen < n && want[i][namelen] == '/' && memcmp(want[i], name, namelen) == 0)
          156                         return 1;
          157                 if(n == namelen && memcmp(name, want[i], n) == 0){
          158                         found[i] = 1;
          159                         return 1;
          160                 }
          161         }
          162         return 0;
          163 }
          164 
          165 void
          166 unvac(VacFile *f, char *name, VacDir *vdir)
          167 {
          168         static char buf[65536];
          169         int fd, n, m,  bsize;
          170         ulong mode, mode9;
          171         char *newname;
          172         char *what;
          173         vlong off;
          174         Dir d, *dp;
          175         VacDirEnum *vde;
          176         VacDir newvdir;
          177         VacFile *newf;
          178 
          179         if(vdir)
          180                 mode = vdir->mode;
          181         else
          182                 mode = vacfilegetmode(f);
          183 
          184         if(vdir){
          185                 if(table){
          186                         if(chatty){
          187                                 mode9 = vdir->mode&0777;
          188                                 if(mode&ModeDir)
          189                                         mode9 |= DMDIR;
          190                                 if(mode&ModeAppend)
          191                                         mode9 |= DMAPPEND;
          192                                 if(mode&ModeExclusive)
          193                                         mode9 |= DMEXCL;
          194 #ifdef PLAN9PORT
          195                                 if(mode&ModeLink)
          196                                         mode9 |= DMSYMLINK;
          197                                 if(mode&ModeNamedPipe)
          198                                         mode9 |= DMNAMEDPIPE;
          199                                 if(mode&ModeSetUid)
          200                                         mode9 |= DMSETUID;
          201                                 if(mode&ModeSetGid)
          202                                         mode9 |= DMSETGID;
          203                                 if(mode&ModeDevice)
          204                                         mode9 |= DMDEVICE;
          205 #endif
          206                                 print("%M %-10s %-10s %11lld %t %s\n",
          207                                         mode9, vdir->uid, vdir->gid, vdir->size,
          208                                         vdir->mtime, name);
          209                         }else
          210                                 print("%s%s\n", name, (mode&ModeDir) ? "/" : "");
          211                 }
          212                 else if(chatty)
          213                         fprint(2, "%s%s\n", name, (mode&ModeDir) ? "/" : "");
          214         }
          215 
          216         if(mode&(ModeDevice|ModeLink|ModeNamedPipe|ModeExclusive)){
          217                 if(table)
          218                         return;
          219                 if(mode&ModeDevice)
          220                         what = "device";
          221                 else if(mode&ModeLink)
          222                         what = "link";
          223                 else if(mode&ModeNamedPipe)
          224                         what = "named pipe";
          225                 else if(mode&ModeExclusive)
          226                         what = "lock";
          227                 else
          228                         what = "unknown type of file";
          229                 fprint(2, "warning: ignoring %s %s\n", what, name);
          230                 return;
          231         }
          232 
          233         if(mode&ModeDir){
          234                 if((vde = vdeopen(f)) == nil){
          235                         fprint(2, "vdeopen %s: %r", name);
          236                         errors++;
          237                         return;
          238                 }
          239                 if(!table && !tostdout && vdir){
          240                         // create directory
          241                         if((dp = dirstat(name)) == nil){
          242                                 if((fd = create(name, OREAD, DMDIR|0700|(mode&0777))) < 0){
          243                                         fprint(2, "mkdir %s: %r\n", name);
          244                                         vdeclose(vde);
          245                                 }
          246                                 close(fd);
          247                         }else{
          248                                 if(!(dp->mode&DMDIR)){
          249                                         fprint(2, "%s already exists and is not a directory\n", name);
          250                                         errors++;
          251                                         free(dp);
          252                                         vdeclose(vde);
          253                                         return;
          254                                 }
          255                                 free(dp);
          256                         }
          257                 }
          258                 while(vderead(vde, &newvdir) > 0){
          259                         if(name == nil)
          260                                 newname = newvdir.elem;
          261                         else
          262                                 newname = smprint("%s/%s", name, newvdir.elem);
          263                         if(wantfile(newname)){
          264                                 if((newf = vacfilewalk(f, newvdir.elem)) == nil){
          265                                         fprint(2, "walk %s: %r\n", name);
          266                                         errors++;
          267                                 }else if(newf == f){
          268                                         fprint(2, "walk loop: %s\n", newname);
          269                                         vacfiledecref(newf);
          270                                 }else{
          271                                         unvac(newf, newname, &newvdir);
          272                                         vacfiledecref(newf);
          273                                 }
          274                         }
          275                         if(newname != newvdir.elem)
          276                                 free(newname);
          277                         vdcleanup(&newvdir);
          278                 }
          279                 vdeclose(vde);
          280         }else{
          281                 if(!table){
          282                         off = 0;
          283                         if(tostdout)
          284                                 fd = dup(1, -1);
          285                         else if(diff && (fd = open(name, ORDWR)) >= 0){
          286                                 bsize = vacfiledsize(f);
          287                                 while((n = readn(fd, buf, bsize)) > 0){
          288                                         if(sha1matches(f, off/bsize, (uchar*)buf, n)){
          289                                                 off += n;
          290                                                 stats.skipdata += n;
          291                                                 continue;
          292                                         }
          293                                         seek(fd, off, 0);
          294                                         if((m = vacfileread(f, buf, n, off)) < 0)
          295                                                 break;
          296                                         if(writen(fd, buf, m) != m){
          297                                                 fprint(2, "write %s: %r\n", name);
          298                                                 goto Err;
          299                                         }
          300                                         off += m;
          301                                         stats.data += m;
          302                                         if(m < n){
          303                                                 nulldir(&d);
          304                                                 d.length = off;
          305                                                 if(dirfwstat(fd, &d) < 0){
          306                                                         fprint(2, "dirfwstat %s: %r\n", name);
          307                                                         goto Err;
          308                                                 }
          309                                                 break;
          310                                         }
          311                                 }
          312                         }
          313                         else if((fd = create(name, OWRITE, mode&0777)) < 0){
          314                                 fprint(2, "create %s: %r\n", name);
          315                                 errors++;
          316                                 return;
          317                         }
          318                         while((n = vacfileread(f, buf, sizeof buf, off)) > 0){
          319                                 if(writen(fd, buf, n) != n){
          320                                         fprint(2, "write %s: %r\n", name);
          321                                 Err:
          322                                         errors++;
          323                                         close(fd);
          324                                         remove(name);
          325                                         return;
          326                                 }
          327                                 off += n;
          328                                 stats.data += n;
          329                         }
          330                         close(fd);
          331                 }
          332         }
          333         if(vdir && settimes && !tostdout){
          334                 nulldir(&d);
          335                 d.mtime = vdir->mtime;
          336                 if(dirwstat(name, &d) < 0)
          337                         fprint(2, "warning: setting mtime on %s: %r", name);
          338         }
          339 }
          340 
          341 int
          342 mtimefmt(Fmt *f)
          343 {
          344         Tm *tm;
          345 
          346         tm = localtime(va_arg(f->args, ulong));
          347         fmtprint(f, "%04d-%02d-%02d %02d:%02d",
          348                 tm->year+1900, tm->mon+1, tm->mday,
          349                 tm->hour, tm->min);
          350         return 0;
          351 }