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