1 /* 2 * Copyright (c) 2001-2008 pinc Software. All Rights Reserved. 3 */ 4 5 //! recovers corrupt BFS disks 6 7 8 #include "Disk.h" 9 #include "Inode.h" 10 #include "Hashtable.h" 11 #include "BPlusTree.h" 12 #include "dump.h" 13 14 #include <String.h> 15 #include <fs_info.h> 16 17 #include <stdlib.h> 18 #include <stdio.h> 19 #include <string.h> 20 #include <unistd.h> 21 #include <ctype.h> 22 23 24 extern const char *__progname; 25 static const char *kProgramName = __progname; 26 27 bool gCreateIndices = false; 28 bool gDumpMissingInodes = false; 29 bool gRawMode = false; 30 bool gVerbose = false; 31 32 33 class InodeHashtable { 34 public: 35 InodeHashtable(int capacity) 36 : 37 fHashtable(capacity), 38 fLastChecked(0) 39 { 40 fHashtable.SetHashFunction((uint32 (*)(const void *))BlockRunHash); 41 fHashtable.SetCompareFunction((bool (*)(const void *, const void *)) 42 BlockRunCompare); 43 } 44 45 Inode* Acquire(Inode* inode) 46 { 47 if (inode == NULL) 48 return NULL; 49 50 status_t status = inode->AcquireBuffer(); 51 if (status != B_OK) { 52 fprintf(stderr, "Could not retrieve buffer for inode %Ld: %s\n", 53 inode->Offset(), strerror(status)); 54 return NULL; 55 } 56 return inode; 57 } 58 59 void Release(Inode* inode) 60 { 61 inode->ReleaseBuffer(); 62 } 63 64 Inode* Get(block_run run) 65 { 66 return Acquire((Inode *)fHashtable.GetValue(&run)); 67 } 68 69 bool Insert(Inode* inode) 70 { 71 bool success = fHashtable.Put(&inode->BlockRun(), inode); 72 if (success) 73 inode->ReleaseBuffer(); 74 75 return success; 76 } 77 78 bool Contains(block_run *key) 79 { 80 return fHashtable.ContainsKey(key); 81 } 82 83 Inode* Remove(block_run *key) 84 { 85 return Acquire((Inode*)fHashtable.Remove(key)); 86 } 87 88 status_t GetNextEntry(Inode **_inode) 89 { 90 status_t status = fHashtable.GetNextEntry((void**)_inode); 91 if (status == B_OK) { 92 if (Acquire(*_inode) == NULL) 93 return B_NO_MEMORY; 94 } 95 96 return status; 97 } 98 99 void Rewind() 100 { 101 fHashtable.Rewind(); 102 } 103 104 bool IsEmpty() const 105 { 106 return fHashtable.IsEmpty(); 107 } 108 109 void MakeEmpty() 110 { 111 fHashtable.MakeEmpty(HASH_EMPTY_NONE, HASH_EMPTY_DELETE); 112 } 113 114 static uint32 BlockRunHash(const block_run *run) 115 { 116 return run->allocation_group << 16 | run->start; 117 } 118 119 static bool BlockRunCompare(const block_run *runA, const block_run *runB) 120 { 121 return *runA == *runB; 122 } 123 124 private: 125 Hashtable fHashtable; 126 bigtime_t fLastChecked; 127 uint32 fPercentUsed; 128 }; 129 130 class InodeGetter { 131 public: 132 InodeGetter(InodeHashtable& hashtable, block_run run) 133 { 134 fInode = hashtable.Get(run); 135 } 136 137 ~InodeGetter() 138 { 139 if (fInode != NULL) 140 fInode->ReleaseBuffer(); 141 } 142 143 Inode* Node() { return fInode; } 144 145 private: 146 Inode* fInode; 147 }; 148 149 150 InodeHashtable gHashtable(1000); 151 // contains all inodes found on disk in the general data area 152 InodeHashtable gLogged(50); 153 // contains all inodes found in the log area 154 InodeHashtable gMissing(50); 155 InodeHashtable gMissingEmpty(25); 156 157 158 class HashtableInodeSource : public Inode::Source { 159 public: 160 virtual Inode *InodeAt(block_run run) 161 { 162 Inode *inode; 163 if ((inode = gHashtable.Get(run)) != NULL) 164 return inode; 165 166 if ((inode = gLogged.Get(run)) != NULL) 167 return inode; 168 169 if ((inode = gMissing.Get(run)) != NULL) 170 return inode; 171 172 return NULL; 173 } 174 }; 175 176 177 void 178 collectInodes(Disk &disk, InodeHashtable &hashtable, off_t start, off_t end) 179 { 180 char buffer[8192]; 181 Inode inode(&disk, (bfs_inode *)buffer, false); 182 off_t count = 0LL; 183 off_t position = start; 184 185 bigtime_t lastUpdate = system_time(); 186 187 for (off_t offset = start; offset < end; offset += sizeof(buffer)) { 188 if (disk.ReadAt(offset, buffer, sizeof(buffer)) < B_OK) { 189 fprintf(stderr, "could not read from device!\n"); 190 break; 191 } 192 193 //if ((offset % (disk.BlockSize() << disk.SuperBlock()->ag_shift)) == 0) 194 // printf("reading block %Ld, allocation group %Ld, %Ld inodes...\33[1A\n", offset / disk.BlockSize(),offset / (disk.BlockSize() << disk.SuperBlock()->ag_shift), count); 195 196 for (uint32 i = 0; i < sizeof(buffer); i += disk.BlockSize()) { 197 inode.SetTo((bfs_inode *)(buffer + i)); 198 if (inode.InitCheck() == B_OK) { 199 if (inode.Flags() & INODE_DELETED) 200 continue; 201 202 Inode *node = Inode::Factory(&disk, &inode); 203 if (node != NULL) { 204 if (gVerbose) 205 printf(" node: %Ld \"%s\"\n", position, node->Name()); 206 hashtable.Insert(node); 207 count++; 208 } else if (gVerbose) { 209 printf("\nunrecognized inode:"); 210 dump_inode(&inode, inode.InodeBuffer()); 211 } 212 } 213 position += disk.BlockSize(); 214 } 215 if (system_time() - lastUpdate > 500000) { 216 printf(" block %Ld (%Ld%%), %Ld inodes\33[1A\n", offset, 100 * (offset - start) / (end - start), count); 217 lastUpdate = system_time(); 218 } 219 } 220 printf("\n%Ld inodes found.\n", count); 221 222 Inode *node; 223 off_t directories = 0LL; 224 off_t directorySize = 0LL; 225 off_t files = 0LL; 226 off_t fileSize = 0LL; 227 off_t symlinks = 0LL; 228 count = 0LL; 229 230 hashtable.Rewind(); 231 while (hashtable.GetNextEntry(&node) == B_OK) { 232 if (node->IsDirectory()) { 233 directories++; 234 directorySize += node->Size(); 235 } else if (node->IsFile()) { 236 files++; 237 fileSize += node->Size(); 238 } else if (node->IsSymlink()) { 239 symlinks++; 240 } 241 count++; 242 hashtable.Release(node); 243 } 244 245 printf("\n%20Ld directories found (total of %Ld bytes)\n" 246 "%20Ld files found (total of %Ld bytes)\n" 247 "%20Ld symlinks found\n" 248 "--------------------\n" 249 "%20Ld inodes total found in hashtable.\n", 250 directories, directorySize, files, fileSize, symlinks, count); 251 } 252 253 254 void 255 collectLogInodes(Disk &disk) 256 { 257 // scan log area 258 off_t offset = disk.ToOffset(disk.Log()); 259 off_t end = offset + (disk.Log().length << disk.BlockShift()); 260 261 printf("\nsearching from %Ld to %Ld (log area)\n",offset,end); 262 263 collectInodes(disk, gLogged, offset, end); 264 } 265 266 267 void 268 collectRealInodes(Disk &disk) 269 { 270 // first block after bootblock, bitmap, and log 271 off_t offset = disk.ToOffset(disk.Log()) + (disk.Log().length 272 << disk.BlockShift()); 273 off_t end = /*(17LL << disk.SuperBlock()->ag_shift); 274 if (end > disk.NumBlocks()) 275 end = */disk.NumBlocks(); 276 end *= disk.BlockSize(); 277 278 printf("\nsearching from %Ld to %Ld (main area)\n", offset, end); 279 280 collectInodes(disk, gHashtable, offset, end); 281 } 282 283 284 Directory * 285 getNameIndex(Disk &disk) 286 { 287 InodeGetter getter(gHashtable, disk.Indices()); 288 Directory *indices = dynamic_cast<Directory *>(getter.Node()); 289 290 block_run run; 291 if (indices && indices->FindEntry("name", &run) == B_OK) 292 return dynamic_cast<Directory *>(gHashtable.Get(run)); 293 294 // search name index 295 296 Inode *node; 297 298 gHashtable.Rewind(); 299 for (; gHashtable.GetNextEntry(&node) == B_OK; gHashtable.Release(node)) { 300 if (!node->IsIndex() || node->Name() == NULL) 301 continue; 302 if (!strcmp(node->Name(), "name") && node->Mode() & S_STR_INDEX) { 303 return dynamic_cast<Directory *>(node); 304 } 305 } 306 return NULL; 307 } 308 309 310 void 311 checkDirectoryContents(Disk& disk, Directory *dir) 312 { 313 dir->Rewind(); 314 315 char name[B_FILE_NAME_LENGTH]; 316 block_run run; 317 318 while (dir->GetNextEntry(name, &run) == B_OK) { 319 if (run == dir->BlockRun() || run == dir->Parent() 320 || gHashtable.Contains(&run)) 321 continue; 322 323 Inode *missing = gMissing.Get(run); 324 if (missing != NULL) { 325 if (missing->SetName(name) < B_OK) { 326 fprintf(stderr, "setting name of missing node to " 327 "\"%s\" failed!", name); 328 } 329 if (gVerbose) { 330 printf("Set name of missing node (%ld, %d) to \"%s\" (%s)\n", 331 run.allocation_group, run.start, missing->Name(), name); 332 } 333 334 missing->SetParent(dir->BlockRun()); 335 } 336 // if (node->Mode() & S_INDEX_DIR) 337 // { 338 // if (node->Mode() & S_STR_INDEX) 339 // printf("index directory (%ld, %d): \"%s\" is missing (%ld, %d, %d)\n",node->BlockRun().allocation_group,node->BlockRun().start,name,run.allocation_group,run.start,run.length); 340 // else 341 // printf("index directory (%ld, %d): key is missing (%ld, %d, %d)\n",node->BlockRun().allocation_group,node->BlockRun().start,run.allocation_group,run.start,run.length); 342 // } 343 else { 344 // missing inode has not been found 345 if (gVerbose) { 346 printf("directory \"%s\" (%ld, %d): node \"%s\" is " 347 "missing (%ld, %d, %d)\n", dir->Name(), 348 dir->BlockRun().allocation_group, 349 dir->BlockRun().start, name, 350 run.allocation_group, run.start, run.length); 351 } 352 353 if ((missing = (Inode *)gLogged.Remove(&run)) != NULL) { 354 // missing inode is in the log 355 if (gVerbose) 356 printf("found missing entry in log!\n"); 357 if (missing->InodeBuffer()->parent != dir->BlockRun()) { 358 if (gVerbose) 359 puts("\tparent directories differ (may be an old version of it), reseting parent."); 360 missing->SetParent(dir->BlockRun()); 361 } 362 if (!gMissing.Insert(missing)) 363 delete missing; 364 } else if (!gMissingEmpty.Contains(&run)) { 365 // not known at all yet 366 Inode *empty = Inode::EmptyInode(&disk, name, 0); 367 if (empty) { 368 empty->SetBlockRun(run); 369 empty->SetParent(dir->BlockRun()); 370 if (gVerbose) 371 printf("\tname = %s\n", empty->Name()); 372 373 if (!gMissingEmpty.Insert(empty)) 374 delete empty; 375 } 376 } 377 } 378 } 379 } 380 381 382 void 383 checkStructure(Disk &disk) 384 { 385 Inode *node; 386 387 off_t count = 0; 388 gHashtable.Rewind(); 389 while (gHashtable.GetNextEntry(&node) == B_OK) { 390 count++; 391 if ((count % 50) == 0) 392 fprintf(stderr, "%Ld inodes processed...\33[1A\n", count); 393 394 if (node->IsDirectory() && !node->IsIndex()) { 395 // check if all entries are in the hashtable 396 checkDirectoryContents(disk, (Directory*)node); 397 } 398 399 // check for the parent directory 400 401 block_run run = node->Parent(); 402 InodeGetter parentGetter(gHashtable, run); 403 Inode *parentNode = parentGetter.Node(); 404 405 Directory *dir = dynamic_cast<Directory *>(parentNode); 406 if (dir || parentNode && (node->Mode() & S_ATTR_DIR)) { 407 // entry has a valid parent directory, so it's assumed to be a valid entry 408 disk.BlockBitmap()->BackupSet(node, true); 409 } else if (node->Mode() & S_ATTR) { 410 if (gVerbose) { 411 printf("attribute \"%s\" at %ld,%d misses its parent.\n", 412 node->Name(), node->BlockRun().allocation_group, 413 node->BlockRun().start); 414 puts("\thandling not yet implemented..."); 415 } 416 } else /*if ((node->Flags() & INODE_DELETED) == 0)*/ { 417 Inode* missing = gMissing.Get(run); 418 dir = dynamic_cast<Directory *>(missing); 419 420 if (missing == NULL) { 421 if (gVerbose) { 422 printf("%s \"%s\" (%ld, %d, mode = %10lo): parent directory is " 423 "missing (%ld, %d, %d), may be deleted!\n", 424 node->IsFile() ? "file" : "node", node->Name(), 425 node->BlockRun().allocation_group, node->BlockRun().start, 426 node->Mode(),run.allocation_group, run.start, run.length); 427 } 428 429 if ((dir = dynamic_cast<Directory *>((Inode *)gLogged.Remove( 430 &run))) != NULL) { 431 if (gVerbose) { 432 printf("found directory \"%s\" in log:\n", dir->Name()); 433 if (dir->Size() > 0) 434 dump_inode(dir, dir->InodeBuffer()); 435 else 436 puts("\tempty inode."); 437 } 438 } else { 439 if (gVerbose) 440 puts("\tcreate parent missing entry"); 441 442 Inode *nameNode = (Inode *)gMissingEmpty.Remove(&run); 443 if (nameNode != NULL) { 444 nameNode->SetMode(S_IFDIR); 445 if (gVerbose) 446 printf("found missing name!\n"); 447 } else { 448 BString parentName; 449 parentName << "__directory " << run.allocation_group 450 << ":" << (int32)run.start; 451 452 nameNode = Inode::EmptyInode(&disk, parentName.String(), 453 S_IFDIR); 454 if (nameNode) { 455 nameNode->SetBlockRun(run); 456 nameNode->SetParent(disk.Root()); 457 } 458 } 459 460 if (nameNode) { 461 dir = new Directory(*nameNode); 462 if (dir->CopyBuffer() < B_OK) 463 puts("could not copy buffer!"); 464 else 465 delete nameNode; 466 } 467 } 468 if (dir) { 469 dir->AcquireBuffer(); 470 471 if (!gMissing.Insert(dir)) { 472 printf("could not add dir!!\n"); 473 delete dir; 474 dir = NULL; 475 } 476 } 477 } else if (missing != NULL && dir == NULL && gVerbose) { 478 printf("%s \"%s\" (%ld, %d, mode = %10lo): parent directory " 479 "found in missing list (%ld, %d, %d), but it's not a dir!\n", 480 node->IsFile() ? "file" : "node", node->Name(), 481 node->BlockRun().allocation_group, node->BlockRun().start, 482 node->Mode(),run.allocation_group, run.start, run.length); 483 } else if (gVerbose) { 484 printf("%s \"%s\" (%ld, %d, mode = %10lo): parent directory " 485 "found in missing list (%ld, %d, %d)!\n", 486 node->IsFile() ? "file" : "node", node->Name(), 487 node->BlockRun().allocation_group, node->BlockRun().start, 488 node->Mode(),run.allocation_group, run.start, run.length); 489 } 490 491 if (dir) { 492 dir->AddEntry(node); 493 dir->ReleaseBuffer(); 494 } 495 } 496 // else 497 // { 498 // printf("node %s\n",node->Name()); 499 // status_t status = dir->Contains(node); 500 // if (status == B_ENTRY_NOT_FOUND) 501 // printf("node \"%s\": parent directory \"%s\" contains no link to this node!\n",node->Name(),dir->Name()); 502 // else if (status != B_OK) 503 // printf("node \"%s\": parent directory \"%s\" error: %s\n",node->Name(),dir->Name(),strerror(status)); 504 // } 505 506 // check for attributes 507 508 run = node->Attributes(); 509 if (!run.IsZero()) { 510 //printf("node \"%s\" (%ld, %d, mode = %010lo): has attribute dir!\n",node->Name(),node->BlockRun().allocation_group,node->BlockRun().start,node->Mode()); 511 512 if (!gHashtable.Contains(&run)) { 513 if (gVerbose) { 514 printf("node \"%s\": attributes are missing (%ld, %d, %d)\n", 515 node->Name(), run.allocation_group, run.start, run.length); 516 } 517 518 if ((dir = (Directory *)gMissing.Get(run)) != NULL) { 519 if (gVerbose) 520 puts("\tfound in missing"); 521 dir->SetMode(dir->Mode() | S_ATTR_DIR); 522 dir->SetParent(node->BlockRun()); 523 } else { 524 if (gVerbose) 525 puts("\tcreate new!"); 526 527 Inode *empty = Inode::EmptyInode(&disk, NULL, 528 S_IFDIR | S_ATTR_DIR); 529 if (empty) { 530 empty->SetBlockRun(run); 531 empty->SetParent(node->BlockRun()); 532 533 dir = new Directory(*empty); 534 if (dir->CopyBuffer() < B_OK) 535 puts("could not copy buffer!"); 536 else 537 delete empty; 538 539 if (!gMissing.Insert(dir)) { 540 puts("\tcould not add attribute dir"); 541 delete dir; 542 } 543 } 544 } 545 } 546 } 547 } 548 printf("%Ld inodes processed.\n", count); 549 550 Directory *directory = getNameIndex(disk); 551 if (directory != NULL) { 552 puts("\n*** Search names of missing inodes in the name index"); 553 554 BPlusTree *tree; 555 if (directory->GetTree(&tree) == B_OK && tree->Validate(gVerbose) == B_OK) { 556 char name[B_FILE_NAME_LENGTH]; 557 block_run run; 558 directory->Rewind(); 559 while (directory->GetNextEntry(name, &run) >= B_OK) { 560 if ((node = gMissing.Get(run)) == NULL) 561 continue; 562 563 if (gVerbose) { 564 printf(" Node found: %ld:%d\n", run.allocation_group, 565 run.start); 566 } 567 if (node->Name() == NULL || strcmp(node->Name(), name)) { 568 if (gVerbose) { 569 printf("\tnames differ: %s -> %s (indices)\n", 570 node->Name(), name); 571 } 572 node->SetName(name); 573 } 574 } 575 } else 576 printf("\tname index is corrupt!\n"); 577 578 directory->ReleaseBuffer(); 579 } else 580 printf("*** Name index corrupt or not existent!\n"); 581 582 if (!gVerbose) 583 return; 584 585 if (!gMissing.IsEmpty()) 586 puts("\n*** Missing inodes:"); 587 588 gMissing.Rewind(); 589 while (gMissing.GetNextEntry(&node) == B_OK) { 590 if (gDumpMissingInodes) 591 dump_inode(node, node->InodeBuffer()); 592 593 Directory *dir = dynamic_cast<Directory *>(node); 594 if (dir) { 595 printf("\ndirectory \"%s\" (%ld, %d) contents:\n", 596 node->Name(), node->BlockRun().allocation_group, 597 node->BlockRun().start); 598 599 dir->Rewind(); 600 601 char name[B_FILE_NAME_LENGTH]; 602 block_run run; 603 while (dir->GetNextEntry(name, &run) == B_OK) { 604 printf("\t\"%s\" (%ld, %d, %d)\n", name, 605 run.allocation_group, run.start, run.length); 606 } 607 608 BPlusTree *tree; 609 if (dir->GetTree(&tree) < B_OK) 610 continue; 611 612 uint16 length; 613 off_t offset; 614 615 while (tree->GetNextEntry(name, &length, B_FILE_NAME_LENGTH, 616 &offset) == B_OK) { 617 name[length] = 0; 618 619 run = disk.ToBlockRun(offset); 620 printf("%s: block_run == (%5ld,%5d,%5d), \"%s\"\n", dir->Name(), 621 run.allocation_group, run.start, run.length, name); 622 } 623 624 //tree->WriteTo(dir); 625 //disk.WriteAt(dir->Offset(),dir->InodeBuffer(),disk.BlockSize()); 626 } 627 628 gMissing.Release(node); 629 } 630 } 631 632 633 void 634 copyInodes(const char *copyTo) 635 { 636 if (!copyTo) 637 return; 638 639 Inode::Source *source = new HashtableInodeSource; 640 Inode *node; 641 642 int32 count = 0; 643 644 gHashtable.Rewind(); 645 while (gHashtable.GetNextEntry(&node) == B_OK) { 646 if (!node->IsIndex() && !node->IsAttributeDirectory()) 647 node->CopyTo(copyTo, source); 648 649 if ((++count % 500) == 0) 650 fprintf(stderr, "copied %ld files...\n", count); 651 652 gHashtable.Release(node); 653 } 654 655 gMissing.Rewind(); 656 while (gMissing.GetNextEntry(&node) == B_OK) { 657 if (!node->IsIndex() && !node->IsAttributeDirectory()) 658 node->CopyTo(copyTo, source); 659 660 gHashtable.Release(node); 661 } 662 } 663 664 665 void 666 usage(char *name) 667 { 668 fprintf(stderr,"usage: %s [-idv] [-r [start-offset] [end-offset]] <device> [recover-to-path]\n" 669 "\t-i\trecreate indices on target disk\n" 670 "\t-d\tdump missing and recreated i-nodes\n" 671 "\t-r\tdisk access in raw mode (use only if the partition table is invalid)\n" 672 "\t-s\trecreate super block and exit (for experts only, don't use this\n" 673 "\t\tif you don't know what you're doing)\n" 674 "\t-v\tverbose output\n", name); 675 exit(-1); 676 } 677 678 679 int 680 main(int argc, char **argv) 681 { 682 char *fileName = strrchr(argv[0], '/'); 683 fileName = fileName ? fileName + 1 : argv[0]; 684 bool recreateSuperBlockOnly = false; 685 686 off_t startOffset = 0, endOffset = -1; 687 688 puts("Copyright (c) 2001-2008 pinc Software."); 689 690 if (argc < 2 || !strcmp(argv[1], "--help")) 691 usage(fileName); 692 693 while (*++argv) { 694 char *arg = *argv; 695 if (*arg == '-') { 696 while (*++arg && isalpha(*arg)) { 697 switch (arg[0]) { 698 case 'r': 699 { 700 gRawMode = true; 701 702 if (argv[1] && isdigit((argv[1])[0])) { 703 argv++; 704 arg = *argv; 705 706 startOffset = atoll(arg); 707 } 708 if (argv[1] && isdigit((argv[1])[0])) { 709 argv++; 710 arg = *argv; 711 712 endOffset = atoll(arg); 713 } 714 if (endOffset != -1 && endOffset < startOffset) 715 usage(fileName); 716 break; 717 } 718 case 'v': 719 gVerbose = true; 720 break; 721 case 'i': 722 gCreateIndices = true; 723 break; 724 case 'd': 725 gDumpMissingInodes = true; 726 break; 727 case 's': 728 recreateSuperBlockOnly = true; 729 break; 730 } 731 } 732 } else 733 break; 734 } 735 736 Disk disk(argv[0], gRawMode, startOffset, endOffset); 737 if (disk.InitCheck() < B_OK) { 738 fprintf(stderr,"Could not open device or file: %s\n", 739 strerror(disk.InitCheck())); 740 return -1; 741 } 742 743 if (argv[1] != NULL) { 744 dev_t device = dev_for_path(argv[1]); 745 fs_info info; 746 if (fs_stat_dev(device, &info) == B_OK) { 747 if (!strcmp(info.device_name, disk.Path().Path())) { 748 fprintf(stderr,"The source and target device are identical, " 749 "you currently need\n" 750 "to have another disk to recover to, sorry!\n"); 751 return -1; 752 } 753 if ((info.flags & (B_FS_IS_PERSISTENT | B_FS_HAS_ATTR)) 754 != (B_FS_IS_PERSISTENT | B_FS_HAS_ATTR)) { 755 fprintf(stderr, "%s: The target file system (%s) does not have " 756 "the required\n" 757 "\tfunctionality in order to restore all information.\n", 758 kProgramName, info.fsh_name); 759 return -1; 760 } 761 } 762 } 763 764 bool recreatedSuperBlock = false; 765 766 if (disk.ValidateSuperBlock() < B_OK) { 767 fprintf(stderr, "The disk's super block is corrupt!\n"); 768 if (disk.RecreateSuperBlock() < B_OK) { 769 fprintf(stderr, "Can't recreate the disk's super block, sorry!\n"); 770 return -1; 771 } 772 recreatedSuperBlock = true; 773 } 774 if (gVerbose) { 775 puts("\n*** The super block:\n"); 776 dump_super_block(disk.SuperBlock()); 777 } 778 779 if (recreateSuperBlockOnly) { 780 if (!recreatedSuperBlock) { 781 printf("Superblock was valid, no changes made.\n"); 782 return 0; 783 } 784 785 status_t status = disk.WriteAt(512, disk.SuperBlock(), 786 sizeof(disk_super_block)); 787 if (status < B_OK) { 788 fprintf(stderr, "Could not write super block: %s!\n", 789 strerror(status)); 790 return 1; 791 } 792 return 0; 793 } 794 795 puts("\n*** Collecting inodes..."); 796 797 collectLogInodes(disk); 798 collectRealInodes(disk); 799 800 puts("\n*** Checking Disk Structure Integrity..."); 801 802 checkStructure(disk); 803 804 if (argv[1]) 805 copyInodes(argv[1]); 806 807 //disk.WriteBootBlock(); 808 //disk.BlockBitmap()->CompareWithBackup(); 809 810 gHashtable.MakeEmpty(); 811 gMissing.MakeEmpty(); 812 gLogged.MakeEmpty(); 813 814 return 0; 815 } 816 817