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