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