URI: 
       tflfmt.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
       ---
       tflfmt.c (10680B)
       ---
            1 #include "stdinc.h"
            2 #include "dat.h"
            3 #include "fns.h"
            4 #include "flfmt9660.h"
            5 
            6 #define blockWrite _blockWrite        /* hack */
            7 
            8 static void usage(void);
            9 static u64int fdsize(int fd);
           10 static void partition(int fd, int bsize, Header *h);
           11 static u64int unittoull(char *s);
           12 static u32int blockAlloc(int type, u32int tag);
           13 static void blockRead(int part, u32int addr);
           14 static void blockWrite(int part, u32int addr);
           15 static void superInit(char *label, u32int root, uchar[VtScoreSize]);
           16 static void rootMetaInit(Entry *e);
           17 static u32int rootInit(Entry *e);
           18 static void topLevel(char *name);
           19 static int parseScore(uchar[VtScoreSize], char*);
           20 static u32int ventiRoot(char*, char*);
           21 static VtConn *z;
           22 
           23 #define TWID64        ((u64int)~(u64int)0)
           24 
           25 Disk *disk;
           26 Fs *fs;
           27 uchar *buf;
           28 int bsize = 8*1024;
           29 u64int qid = 1;
           30 int iso9660off;
           31 char *iso9660file;
           32 
           33 int
           34 confirm(char *msg)
           35 {
           36         char buf[100];
           37         int n;
           38 
           39         fprint(2, "%s [y/n]: ", msg);
           40         n = read(0, buf, sizeof buf - 1);
           41         if(n <= 0)
           42                 return 0;
           43         if(buf[0] == 'y')
           44                 return 1;
           45         return 0;
           46 }
           47 
           48 void
           49 threadmain(int argc, char *argv[])
           50 {
           51         int fd, force;
           52         Header h;
           53         ulong bn;
           54         Entry e;
           55         char *label = "vfs";
           56         char *host = nil;
           57         char *score = nil;
           58         u32int root;
           59         Dir *d;
           60 
           61         force = 0;
           62         ARGBEGIN{
           63         default:
           64                 usage();
           65         case 'b':
           66                 bsize = unittoull(EARGF(usage()));
           67                 if(bsize == ~0)
           68                         usage();
           69                 break;
           70         case 'h':
           71                 host = EARGF(usage());
           72                 break;
           73         case 'i':
           74                 iso9660file = EARGF(usage());
           75                 iso9660off = atoi(EARGF(usage()));
           76                 break;
           77         case 'l':
           78                 label = EARGF(usage());
           79                 break;
           80         case 'v':
           81                 score = EARGF(usage());
           82                 break;
           83 
           84         /*
           85          * This is -y instead of -f because flchk has a
           86          * (frequently used) -f option.  I type flfmt instead
           87          * of flchk all the time, and want to make it hard
           88          * to reformat my file system accidentally.
           89          */
           90         case 'y':
           91                 force = 1;
           92                 break;
           93         }ARGEND
           94 
           95         if(argc != 1)
           96                 usage();
           97 
           98         if(iso9660file && score)
           99                 sysfatal("cannot use -i with -v");
          100 
          101         fmtinstall('V', scoreFmt);
          102         fmtinstall('L', labelFmt);
          103 
          104         fd = open(argv[0], ORDWR);
          105         if(fd < 0)
          106                 sysfatal("could not open file: %s: %r", argv[0]);
          107 
          108         buf = vtmallocz(bsize);
          109         if(pread(fd, buf, bsize, HeaderOffset) != bsize)
          110                 sysfatal("could not read fs header block: %r");
          111 
          112         if(headerUnpack(&h, buf) && !force
          113         && !confirm("fs header block already exists; are you sure?"))
          114                 goto Out;
          115 
          116         if((d = dirfstat(fd)) == nil)
          117                 sysfatal("dirfstat: %r");
          118 
          119         if(d->type == 'M' && !force
          120         && !confirm("fs file is mounted via devmnt (is not a kernel device); are you sure?"))
          121                 goto Out;
          122 
          123         partition(fd, bsize, &h);
          124         headerPack(&h, buf);
          125         if(pwrite(fd, buf, bsize, HeaderOffset) < bsize)
          126                 sysfatal("could not write fs header: %r");
          127 
          128         disk = diskAlloc(fd);
          129         if(disk == nil)
          130                 sysfatal("could not open disk: %r");
          131 
          132         if(iso9660file)
          133                 iso9660init(fd, &h, iso9660file, iso9660off);
          134 
          135         /* zero labels */
          136         memset(buf, 0, bsize);
          137         for(bn = 0; bn < diskSize(disk, PartLabel); bn++)
          138                 blockWrite(PartLabel, bn);
          139 
          140         if(iso9660file)
          141                 iso9660labels(disk, buf, blockWrite);
          142 
          143         if(score)
          144                 root = ventiRoot(host, score);
          145         else{
          146                 rootMetaInit(&e);
          147                 root = rootInit(&e);
          148         }
          149 
          150         superInit(label, root, vtzeroscore);
          151         diskFree(disk);
          152 
          153         if(score == nil)
          154                 topLevel(argv[0]);
          155 
          156 Out:
          157         threadexitsall(0);
          158 }
          159 
          160 static u64int
          161 fdsize(int fd)
          162 {
          163         Dir *dir;
          164         u64int size;
          165 
          166         dir = dirfstat(fd);
          167         if(dir == nil)
          168                 sysfatal("could not stat file: %r");
          169         size = dir->length;
          170         free(dir);
          171         return size;
          172 }
          173 
          174 static void
          175 usage(void)
          176 {
          177         fprint(2, "usage: %s [-b blocksize] [-h host] [-i file offset] "
          178                 "[-l label] [-v score] [-y] file\n", argv0);
          179         threadexitsall("usage");
          180 }
          181 
          182 static void
          183 partition(int fd, int bsize, Header *h)
          184 {
          185         ulong nblock, ndata, nlabel;
          186         ulong lpb;
          187 
          188         if(bsize % 512 != 0)
          189                 sysfatal("block size must be a multiple of 512 bytes");
          190         if(bsize > VtMaxLumpSize)
          191                 sysfatal("block size must be less than %d", VtMaxLumpSize);
          192 
          193         memset(h, 0, sizeof(*h));
          194         h->blockSize = bsize;
          195 
          196         lpb = bsize/LabelSize;
          197 
          198         nblock = fdsize(fd)/bsize;
          199 
          200         /* sanity check */
          201         if(nblock < (HeaderOffset*10)/bsize)
          202                 sysfatal("file too small");
          203 
          204         h->super = (HeaderOffset + 2*bsize)/bsize;
          205         h->label = h->super + 1;
          206         ndata = ((u64int)lpb)*(nblock - h->label)/(lpb+1);
          207         nlabel = (ndata + lpb - 1)/lpb;
          208         h->data = h->label + nlabel;
          209         h->end = h->data + ndata;
          210 
          211 }
          212 
          213 static u32int
          214 tagGen(void)
          215 {
          216         u32int tag;
          217 
          218         for(;;){
          219                 tag = lrand();
          220                 if(tag > RootTag)
          221                         break;
          222         }
          223         return tag;
          224 }
          225 
          226 static void
          227 entryInit(Entry *e)
          228 {
          229         e->gen = 0;
          230         e->dsize = bsize;
          231         e->psize = bsize/VtEntrySize*VtEntrySize;
          232         e->flags = VtEntryActive;
          233         e->depth = 0;
          234         e->size = 0;
          235         memmove(e->score, vtzeroscore, VtScoreSize);
          236         e->tag = tagGen();
          237         e->snap = 0;
          238         e->archive = 0;
          239 }
          240 
          241 static void
          242 rootMetaInit(Entry *e)
          243 {
          244         u32int addr;
          245         u32int tag;
          246         DirEntry de;
          247         MetaBlock mb;
          248         MetaEntry me;
          249 
          250         memset(&de, 0, sizeof(de));
          251         de.elem = vtstrdup("root");
          252         de.entry = 0;
          253         de.gen = 0;
          254         de.mentry = 1;
          255         de.mgen = 0;
          256         de.size = 0;
          257         de.qid = qid++;
          258         de.uid = vtstrdup("adm");
          259         de.gid = vtstrdup("adm");
          260         de.mid = vtstrdup("adm");
          261         de.mtime = time(0);
          262         de.mcount = 0;
          263         de.ctime = time(0);
          264         de.atime = time(0);
          265         de.mode = ModeDir | 0555;
          266 
          267         tag = tagGen();
          268         addr = blockAlloc(BtData, tag);
          269 
          270         /* build up meta block */
          271         memset(buf, 0, bsize);
          272         mbInit(&mb, buf, bsize, bsize/100);
          273         me.size = deSize(&de);
          274         me.p = mbAlloc(&mb, me.size);
          275         assert(me.p != nil);
          276         dePack(&de, &me);
          277         mbInsert(&mb, 0, &me);
          278         mbPack(&mb);
          279         blockWrite(PartData, addr);
          280         deCleanup(&de);
          281 
          282         /* build up entry for meta block */
          283         entryInit(e);
          284         e->flags |= VtEntryLocal;
          285          e->size = bsize;
          286         e->tag = tag;
          287         localToGlobal(addr, e->score);
          288 }
          289 
          290 static u32int
          291 rootInit(Entry *e)
          292 {
          293         ulong addr;
          294         u32int tag;
          295 
          296         tag = tagGen();
          297 
          298         addr = blockAlloc(BtDir, tag);
          299         memset(buf, 0, bsize);
          300 
          301         /* root meta data is in the third entry */
          302         entryPack(e, buf, 2);
          303 
          304         entryInit(e);
          305         e->flags |= _VtEntryDir;
          306         entryPack(e, buf, 0);
          307 
          308         entryInit(e);
          309         entryPack(e, buf, 1);
          310 
          311         blockWrite(PartData, addr);
          312 
          313         entryInit(e);
          314         e->flags |= VtEntryLocal|_VtEntryDir;
          315          e->size = VtEntrySize*3;
          316         e->tag = tag;
          317         localToGlobal(addr, e->score);
          318 
          319         addr = blockAlloc(BtDir, RootTag);
          320         memset(buf, 0, bsize);
          321         entryPack(e, buf, 0);
          322 
          323         blockWrite(PartData, addr);
          324 
          325         return addr;
          326 }
          327 
          328 
          329 static u32int
          330 blockAlloc(int type, u32int tag)
          331 {
          332         static u32int addr;
          333         Label l;
          334         int lpb;
          335 
          336         lpb = bsize/LabelSize;
          337 
          338         blockRead(PartLabel, addr/lpb);
          339         if(!labelUnpack(&l, buf, addr % lpb))
          340                 sysfatal("bad label: %r");
          341         if(l.state != BsFree)
          342                 sysfatal("want to allocate block already in use");
          343         l.epoch = 1;
          344         l.epochClose = ~(u32int)0;
          345         l.type = type;
          346         l.state = BsAlloc;
          347         l.tag = tag;
          348         labelPack(&l, buf, addr % lpb);
          349         blockWrite(PartLabel, addr/lpb);
          350         return addr++;
          351 }
          352 
          353 static void
          354 superInit(char *label, u32int root, uchar score[VtScoreSize])
          355 {
          356         Super s;
          357 
          358         memset(buf, 0, bsize);
          359         memset(&s, 0, sizeof(s));
          360         s.version = SuperVersion;
          361         s.epochLow = 1;
          362         s.epochHigh = 1;
          363         s.qid = qid;
          364         s.active = root;
          365         s.next = NilBlock;
          366         s.current = NilBlock;
          367         strecpy(s.name, s.name+sizeof(s.name), label);
          368         memmove(s.last, score, VtScoreSize);
          369 
          370         superPack(&s, buf);
          371         blockWrite(PartSuper, 0);
          372 }
          373 
          374 static u64int
          375 unittoull(char *s)
          376 {
          377         char *es;
          378         u64int n;
          379 
          380         if(s == nil)
          381                 return TWID64;
          382         n = strtoul(s, &es, 0);
          383         if(*es == 'k' || *es == 'K'){
          384                 n *= 1024;
          385                 es++;
          386         }else if(*es == 'm' || *es == 'M'){
          387                 n *= 1024*1024;
          388                 es++;
          389         }else if(*es == 'g' || *es == 'G'){
          390                 n *= 1024*1024*1024;
          391                 es++;
          392         }
          393         if(*es != '\0')
          394                 return TWID64;
          395         return n;
          396 }
          397 
          398 static void
          399 blockRead(int part, u32int addr)
          400 {
          401         if(!diskReadRaw(disk, part, addr, buf))
          402                 sysfatal("read failed: %r");
          403 }
          404 
          405 static void
          406 blockWrite(int part, u32int addr)
          407 {
          408         if(!diskWriteRaw(disk, part, addr, buf))
          409                 sysfatal("write failed: %r");
          410 }
          411 
          412 static void
          413 addFile(File *root, char *name, uint mode)
          414 {
          415         File *f;
          416 
          417         f = fileCreate(root, name, mode | ModeDir, "adm");
          418         if(f == nil)
          419                 sysfatal("could not create file: %s: %r", name);
          420         fileDecRef(f);
          421 }
          422 
          423 static void
          424 topLevel(char *name)
          425 {
          426         Fs *fs;
          427         File *root;
          428 
          429         /* ok, now we can open as a fs */
          430         fs = fsOpen(name, z, 100, OReadWrite);
          431         if(fs == nil)
          432                 sysfatal("could not open file system: %r");
          433         rlock(&fs->elk);
          434         root = fsGetRoot(fs);
          435         if(root == nil)
          436                 sysfatal("could not open root: %r");
          437         addFile(root, "active", 0555);
          438         addFile(root, "archive", 0555);
          439         addFile(root, "snapshot", 0555);
          440         fileDecRef(root);
          441         if(iso9660file)
          442                 iso9660copy(fs);
          443         runlock(&fs->elk);
          444         fsClose(fs);
          445 }
          446 
          447 static int
          448 ventiRead(uchar score[VtScoreSize], int type)
          449 {
          450         int n;
          451 
          452         n = vtread(z, score, type, buf, bsize);
          453         if(n < 0)
          454                 sysfatal("ventiRead %V (%d) failed: %r", score, type);
          455         vtzeroextend(type, buf, n, bsize);
          456         return n;
          457 }
          458 
          459 static u32int
          460 ventiRoot(char *host, char *s)
          461 {
          462         int i, n;
          463         uchar score[VtScoreSize];
          464         u32int addr, tag;
          465         DirEntry de;
          466         MetaBlock mb;
          467         MetaEntry me;
          468         Entry e;
          469         VtRoot root;
          470 
          471         if(!parseScore(score, s))
          472                 sysfatal("bad score '%s'", s);
          473 
          474         if((z = vtdial(host)) == nil
          475         || vtconnect(z) < 0)
          476                 sysfatal("connect to venti: %r");
          477 
          478         tag = tagGen();
          479         addr = blockAlloc(BtDir, tag);
          480 
          481         ventiRead(score, VtRootType);
          482         if(vtrootunpack(&root, buf) < 0)
          483                 sysfatal("corrupted root: vtrootunpack");
          484         n = ventiRead(root.score, VtDirType);
          485 
          486         /*
          487          * Fossil's vac archives start with an extra layer of source,
          488          * but vac's don't.
          489          */
          490         if(n <= 2*VtEntrySize){
          491                 if(!entryUnpack(&e, buf, 0))
          492                         sysfatal("bad root: top entry");
          493                 n = ventiRead(e.score, VtDirType);
          494         }
          495 
          496         /*
          497          * There should be three root sources (and nothing else) here.
          498          */
          499         for(i=0; i<3; i++){
          500                 if(!entryUnpack(&e, buf, i)
          501                 || !(e.flags&VtEntryActive)
          502                 || e.psize < 256
          503                 || e.dsize < 256)
          504                         sysfatal("bad root: entry %d", i);
          505                 fprint(2, "%V\n", e.score);
          506         }
          507         if(n > 3*VtEntrySize)
          508                 sysfatal("bad root: entry count");
          509 
          510         blockWrite(PartData, addr);
          511 
          512         /*
          513          * Maximum qid is recorded in root's msource, entry #2 (conveniently in e).
          514          */
          515         ventiRead(e.score, VtDataType);
          516         if(!mbUnpack(&mb, buf, bsize))
          517                 sysfatal("bad root: mbUnpack");
          518         meUnpack(&me, &mb, 0);
          519         if(!deUnpack(&de, &me))
          520                 sysfatal("bad root: dirUnpack");
          521         if(!de.qidSpace)
          522                 sysfatal("bad root: no qidSpace");
          523         qid = de.qidMax;
          524 
          525         /*
          526          * Recreate the top layer of source.
          527          */
          528         entryInit(&e);
          529         e.flags |= VtEntryLocal|_VtEntryDir;
          530         e.size = VtEntrySize*3;
          531         e.tag = tag;
          532         localToGlobal(addr, e.score);
          533 
          534         addr = blockAlloc(BtDir, RootTag);
          535         memset(buf, 0, bsize);
          536         entryPack(&e, buf, 0);
          537         blockWrite(PartData, addr);
          538 
          539         return addr;
          540 }
          541 
          542 static int
          543 parseScore(uchar *score, char *buf)
          544 {
          545         int i, c;
          546 
          547         memset(score, 0, VtScoreSize);
          548 
          549         if(strlen(buf) < VtScoreSize*2)
          550                 return 0;
          551         for(i=0; i<VtScoreSize*2; i++){
          552                 if(buf[i] >= '0' && buf[i] <= '9')
          553                         c = buf[i] - '0';
          554                 else if(buf[i] >= 'a' && buf[i] <= 'f')
          555                         c = buf[i] - 'a' + 10;
          556                 else if(buf[i] >= 'A' && buf[i] <= 'F')
          557                         c = buf[i] - 'A' + 10;
          558                 else
          559                         return 0;
          560 
          561                 if((i & 1) == 0)
          562                         c <<= 4;
          563 
          564                 score[i>>1] |= c;
          565         }
          566         return 1;
          567 }