URI: 
       tcopy.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
       ---
       tcopy.c (5587B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <venti.h>
            4 #include <libsec.h>
            5 #include <thread.h>
            6 #include <avl.h>
            7 #include <bin.h>
            8 
            9 enum
           10 {
           11         // XXX What to do here?
           12         VtMaxLumpSize = 65535,
           13 };
           14 
           15 int changes;
           16 int rewrite;
           17 int ignoreerrors;
           18 int fast;
           19 int verbose;
           20 int nskip;
           21 int nwrite;
           22 
           23 VtConn *zsrc, *zdst;
           24 uchar zeroscore[VtScoreSize];        /* all zeros */
           25 
           26 typedef struct ScoreTree ScoreTree;
           27 struct ScoreTree
           28 {
           29         Avl avl;
           30         uchar score[VtScoreSize];
           31         int type;
           32 };
           33 
           34 Avltree *scoretree;
           35 Bin *scorebin;
           36 
           37 static int
           38 scoretreecmp(Avl *va, Avl *vb)
           39 {
           40         ScoreTree *a, *b;
           41         int i;
           42 
           43         a = (ScoreTree*)va;
           44         b = (ScoreTree*)vb;
           45 
           46         i = memcmp(a->score, b->score, VtScoreSize);
           47         if(i != 0)
           48                 return i;
           49         return a->type - b->type;
           50 }
           51 
           52 static int
           53 havevisited(uchar score[VtScoreSize], int type)
           54 {
           55         ScoreTree a;
           56 
           57         if(scoretree == nil)
           58                 return 0;
           59         memmove(a.score, score, VtScoreSize);
           60         a.type = type;
           61         return lookupavl(scoretree, &a.avl) != nil;
           62 }
           63 
           64 static void
           65 markvisited(uchar score[VtScoreSize], int type)
           66 {
           67         ScoreTree *a;
           68         Avl *old;
           69 
           70         if(scoretree == nil)
           71                 return;
           72         a = binalloc(&scorebin, sizeof *a, 1);
           73         memmove(a->score, score, VtScoreSize);
           74         a->type = type;
           75         insertavl(scoretree, &a->avl, &old);
           76 }
           77 
           78 void
           79 usage(void)
           80 {
           81         fprint(2, "usage: copy [-fimrVv] [-t type] srchost dsthost score\n");
           82         threadexitsall("usage");
           83 }
           84 
           85 void
           86 walk(uchar score[VtScoreSize], uint type, int base, int depth)
           87 {
           88         int i, n;
           89         uchar *buf;
           90         uchar nscore[VtScoreSize];
           91         VtEntry e;
           92         VtRoot root;
           93 
           94         if(verbose){
           95                 for(i = 0; i < depth; i++)
           96                         fprint(2, " ");
           97                 fprint(2, "-> %d %d %d %V\n", depth, type, base, score);
           98         }
           99 
          100         if(memcmp(score, vtzeroscore, VtScoreSize) == 0 || memcmp(score, zeroscore, VtScoreSize) == 0)
          101                 return;
          102 
          103         if(havevisited(score, type)){
          104                 nskip++;
          105                 return;
          106         }
          107 
          108         buf = vtmallocz(VtMaxLumpSize);
          109         if(fast && vtread(zdst, score, type, buf, VtMaxLumpSize) >= 0){
          110                 if(verbose)
          111                         fprint(2, "skip %V\n", score);
          112                 free(buf);
          113                 return;
          114         }
          115 
          116         n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
          117         if(n < 0){
          118                 if(rewrite){
          119                         changes++;
          120                         memmove(score, vtzeroscore, VtScoreSize);
          121                 }else if(!ignoreerrors)
          122                         sysfatal("reading block %V (type %d): %r", score, type);
          123                 return;
          124         }
          125 
          126         switch(type){
          127         case VtRootType:
          128                 if(vtrootunpack(&root, buf) < 0){
          129                         fprint(2, "warning: could not unpack root in %V %d\n", score, type);
          130                         break;
          131                 }
          132                 walk(root.prev, VtRootType, 0, depth+1);
          133                 walk(root.score, VtDirType, 0, depth+1);
          134                 if(rewrite)
          135                         vtrootpack(&root, buf);        /* walk might have changed score */
          136                 break;
          137 
          138         case VtDirType:
          139                 for(i=0; i*VtEntrySize < n; i++){
          140                         if(vtentryunpack(&e, buf, i) < 0){
          141                                 fprint(2, "warning: could not unpack entry #%d in %V %d\n", i, score, type);
          142                                 continue;
          143                         }
          144                         if(!(e.flags & VtEntryActive))
          145                                 continue;
          146                         walk(e.score, e.type, e.type&VtTypeBaseMask, depth+1);
          147                         /*
          148                          * Don't repack unless we're rewriting -- some old
          149                          * vac files have psize==0 and dsize==0, and these
          150                          * get rewritten by vtentryunpack to have less strange
          151                          * block sizes.  So vtentryunpack; vtentrypack does not
          152                          * guarantee to preserve the exact bytes in buf.
          153                          */
          154                         if(rewrite)
          155                                 vtentrypack(&e, buf, i);
          156                 }
          157                 break;
          158 
          159         case VtDataType:
          160                 break;
          161 
          162         default:        /* pointers */
          163                 for(i=0; i<n; i+=VtScoreSize)
          164                         if(memcmp(buf+i, vtzeroscore, VtScoreSize) != 0)
          165                                 walk(buf+i, type-1, base, depth+1);
          166                 break;
          167         }
          168 
          169         nwrite++;
          170         if(vtwrite(zdst, nscore, type, buf, n) < 0){
          171                 /* figure out score for better error message */
          172                 /* can't use input argument - might have changed contents */
          173                 n = vtzerotruncate(type, buf, n);
          174                 sha1(buf, n, score, nil);
          175                 sysfatal("writing block %V (type %d): %r", score, type);
          176         }
          177         if(!rewrite && memcmp(score, nscore, VtScoreSize) != 0)
          178                 sysfatal("not rewriting: wrote %V got %V", score, nscore);
          179 
          180         if((type !=0 || base !=0) && verbose){
          181                 n = vtzerotruncate(type, buf, n);
          182                 sha1(buf, n, score, nil);
          183 
          184                 for(i = 0; i < depth; i++)
          185                         fprint(2, " ");
          186                 fprint(2, "<- %V\n", score);
          187         }
          188 
          189         markvisited(score, type);
          190         free(buf);
          191 }
          192 
          193 void
          194 threadmain(int argc, char *argv[])
          195 {
          196         int type, n;
          197         uchar score[VtScoreSize];
          198         uchar *buf;
          199         char *prefix;
          200 
          201         fmtinstall('F', vtfcallfmt);
          202         fmtinstall('V', vtscorefmt);
          203 
          204         type = -1;
          205         ARGBEGIN{
          206         case 'V':
          207                 chattyventi++;
          208                 break;
          209         case 'f':
          210                 fast = 1;
          211                 break;
          212         case 'i':
          213                 if(rewrite)
          214                         usage();
          215                 ignoreerrors = 1;
          216                 break;
          217         case 'm':
          218                 scoretree = mkavltree(scoretreecmp);
          219                 break;
          220         case 'r':
          221                 if(ignoreerrors)
          222                         usage();
          223                 rewrite = 1;
          224                 break;
          225         case 't':
          226                 type = atoi(EARGF(usage()));
          227                 break;
          228         case 'v':
          229                 verbose = 1;
          230                 break;
          231         default:
          232                 usage();
          233                 break;
          234         }ARGEND
          235 
          236         if(argc != 3)
          237                 usage();
          238 
          239         if(vtparsescore(argv[2], &prefix, score) < 0)
          240                 sysfatal("could not parse score: %r");
          241 
          242         buf = vtmallocz(VtMaxLumpSize);
          243 
          244         zsrc = vtdial(argv[0]);
          245         if(zsrc == nil)
          246                 sysfatal("could not dial src server: %r");
          247         if(vtconnect(zsrc) < 0)
          248                 sysfatal("vtconnect src: %r");
          249 
          250         zdst = vtdial(argv[1]);
          251         if(zdst == nil)
          252                 sysfatal("could not dial dst server: %r");
          253         if(vtconnect(zdst) < 0)
          254                 sysfatal("vtconnect dst: %r");
          255 
          256         if(type != -1){
          257                 n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
          258                 if(n < 0)
          259                         sysfatal("could not read block: %r");
          260         }else{
          261                 for(type=0; type<VtMaxType; type++){
          262                         n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
          263                         if(n >= 0)
          264                                 break;
          265                 }
          266                 if(type == VtMaxType)
          267                         sysfatal("could not find block %V of any type", score);
          268         }
          269 
          270         walk(score, type, VtDirType, 0);
          271         if(changes)
          272                 print("%s:%V (%d pointers rewritten)\n", prefix, score, changes);
          273 
          274         if(verbose)
          275                 print("%d skipped, %d written\n", nskip, nwrite);
          276 
          277         if(vtsync(zdst) < 0)
          278                 sysfatal("could not sync dst server: %r");
          279 
          280         threadexitsall(0);
          281 }