RemoteDrawingEngine: Reduce RP_READ_BITMAP result timeout.
[haiku.git] / src / bin / bfs_tools / recover.cpp
blob1988a3d14c2fdf94b6522b0151cd592fa0816e50
1 /*
2 * Copyright (c) 2001-2008 pinc Software. All Rights Reserved.
3 */
5 //! recovers corrupt BFS disks
8 #include <set>
10 #include "Disk.h"
11 #include "Inode.h"
12 #include "Hashtable.h"
13 #include "BPlusTree.h"
14 #include "dump.h"
16 #include <String.h>
17 #include <fs_info.h>
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <ctype.h>
26 extern const char *__progname;
27 static const char *kProgramName = __progname;
29 bool gCreateIndices = false;
30 bool gDumpMissingInodes = false;
31 bool gRawMode = false;
32 bool gVerbose = false;
35 // TODO: add a cache for all inodes
36 typedef std::set<block_run> RunSet;
39 class InodeHashtable {
40 public:
41 InodeHashtable(int capacity)
43 fHashtable(capacity),
44 fLastChecked(0)
46 fHashtable.SetHashFunction((uint32 (*)(const void *))BlockRunHash);
47 fHashtable.SetCompareFunction((bool (*)(const void *, const void *))
48 BlockRunCompare);
51 Inode* Acquire(Inode* inode)
53 if (inode == NULL)
54 return NULL;
56 status_t status = inode->AcquireBuffer();
57 if (status != B_OK) {
58 fprintf(stderr, "Could not retrieve buffer for inode %"
59 B_PRIdOFF ": %s\n", inode->Offset(), strerror(status));
60 return NULL;
62 return inode;
65 void Release(Inode* inode)
67 inode->ReleaseBuffer();
70 Inode* Get(block_run run)
72 return Acquire((Inode *)fHashtable.GetValue(&run));
75 bool Insert(Inode* inode)
77 bool success = fHashtable.Put(&inode->BlockRun(), inode);
78 if (success)
79 inode->ReleaseBuffer();
81 return success;
84 bool Contains(block_run *key)
86 return fHashtable.ContainsKey(key);
89 Inode* Remove(block_run *key)
91 return Acquire((Inode*)fHashtable.Remove(key));
94 status_t GetNextEntry(Inode **_inode)
96 status_t status = fHashtable.GetNextEntry((void**)_inode);
97 if (status == B_OK) {
98 if (Acquire(*_inode) == NULL)
99 return B_NO_MEMORY;
102 return status;
105 void Rewind()
107 fHashtable.Rewind();
110 bool IsEmpty() const
112 return fHashtable.IsEmpty();
115 void MakeEmpty()
117 fHashtable.MakeEmpty(HASH_EMPTY_NONE, HASH_EMPTY_DELETE);
120 static uint32 BlockRunHash(const block_run *run)
122 return (run->allocation_group << 16) | run->start;
125 static bool BlockRunCompare(const block_run *runA, const block_run *runB)
127 return *runA == *runB;
130 private:
131 Hashtable fHashtable;
132 bigtime_t fLastChecked;
133 uint32 fPercentUsed;
137 class InodeGetter {
138 public:
139 InodeGetter(Disk& disk, block_run run)
141 fInode = Inode::Factory(&disk, run);
142 if (fInode != NULL)
143 fInode->AcquireBuffer();
146 ~InodeGetter()
148 if (fInode != NULL)
149 fInode->ReleaseBuffer();
152 Inode* Node() const
154 return fInode;
157 void Detach()
159 fInode = NULL;
162 private:
163 Inode* fInode;
167 RunSet gMainInodes;
168 // contains all inodes found on disk in the general data area
169 InodeHashtable gLogged(50);
170 // contains all inodes found in the log area
171 InodeHashtable gMissing(50);
172 InodeHashtable gMissingEmpty(25);
175 class HashtableInodeSource : public Inode::Source {
176 public:
177 HashtableInodeSource(Disk& disk)
179 fDisk(disk)
183 virtual Inode *InodeAt(block_run run)
185 Inode *inode;
186 if ((inode = gLogged.Get(run)) != NULL)
187 return inode;
189 if ((inode = gMissing.Get(run)) != NULL)
190 return inode;
192 if (gMainInodes.find(run) == gMainInodes.end())
193 return NULL;
195 return Inode::Factory(&fDisk, run);
198 private:
199 Disk& fDisk;
203 bool
204 operator<(const block_run& a, const block_run& b)
206 return a.allocation_group < b.allocation_group
207 || (a.allocation_group == b.allocation_group && a.start < b.start);
211 void
212 collectInodes(Disk& disk, RunSet* set, InodeHashtable* hashTable, off_t start,
213 off_t end)
215 char buffer[8192];
216 Inode inode(&disk, (bfs_inode *)buffer, false);
218 off_t directories = 0LL;
219 off_t directorySize = 0LL;
220 off_t files = 0LL;
221 off_t fileSize = 0LL;
222 off_t symlinks = 0LL;
223 off_t count = 0LL;
225 off_t position = start;
226 bigtime_t lastUpdate = system_time();
228 for (off_t offset = start; offset < end; offset += sizeof(buffer)) {
229 if (disk.ReadAt(offset, buffer, sizeof(buffer)) < B_OK) {
230 fprintf(stderr, "could not read from device!\n");
231 break;
234 //if ((offset % (disk.BlockSize() << disk.SuperBlock()->ag_shift)) == 0)
235 // printf("reading block %Ld, allocation group %Ld, %Ld inodes...\33[1A\n", offset / disk.BlockSize(),offset / (disk.BlockSize() << disk.SuperBlock()->ag_shift), count);
237 for (uint32 i = 0; i < sizeof(buffer); i += disk.BlockSize()) {
238 inode.SetTo((bfs_inode *)(buffer + i));
239 if (inode.InitCheck() == B_OK) {
240 if (inode.Flags() & INODE_DELETED)
241 continue;
243 Inode *node = Inode::Factory(&disk, &inode);
244 if (node != NULL) {
245 if (gVerbose)
246 printf(" node: %" B_PRIdOFF " \"%s\"\n", position,
247 node->Name());
249 if (set != NULL)
250 set->insert(node->BlockRun());
251 else
252 hashTable->Insert(node);
254 if (node->IsDirectory()) {
255 directories++;
256 directorySize += node->Size();
257 } else if (node->IsFile()) {
258 files++;
259 fileSize += node->Size();
260 } else if (node->IsSymlink()) {
261 symlinks++;
263 count++;
264 } else if (gVerbose) {
265 printf("\nunrecognized inode:");
266 dump_inode(&inode, inode.InodeBuffer());
269 position += disk.BlockSize();
271 if (system_time() - lastUpdate > 500000) {
272 printf(" block %" B_PRIdOFF " (%" B_PRIdOFF "%%), %" B_PRIdOFF
273 " inodes\33[1A\n", offset,
274 100 * (offset - start) / (end - start), count);
275 lastUpdate = system_time();
278 printf("\n%" B_PRIdOFF " inodes found.\n", count);
280 printf("\n%20" B_PRIdOFF " directories found (total of %" B_PRIdOFF
281 " bytes)\n%20" B_PRIdOFF " files found (total of %" B_PRIdOFF
282 " bytes)\n%20" B_PRIdOFF " symlinks found\n"
283 "--------------------\n"
284 "%20" B_PRIdOFF " inodes total found.\n",
285 directories, directorySize, files, fileSize, symlinks, count);
289 void
290 collectLogInodes(Disk &disk)
292 // scan log area
293 off_t offset = disk.ToOffset(disk.Log());
294 off_t end = offset + (disk.Log().length << disk.BlockShift());
296 printf("\nsearching from %" B_PRIdOFF " to %" B_PRIdOFF " (log area)\n",
297 offset, end);
299 collectInodes(disk, NULL, &gLogged, offset, end);
303 void
304 collectRealInodes(Disk &disk)
306 // first block after bootblock, bitmap, and log
307 off_t offset = disk.ToOffset(disk.Log()) + (disk.Log().length
308 << disk.BlockShift());
309 off_t end = (off_t)disk.NumBlocks() << disk.BlockShift();
311 printf("\nsearching from %" B_PRIdOFF " to %" B_PRIdOFF " (main area)\n",
312 offset, end);
314 collectInodes(disk, &gMainInodes, NULL, offset, end);
318 Directory *
319 getNameIndex(Disk &disk)
321 InodeGetter getter(disk, disk.Indices());
322 Directory *indices = dynamic_cast<Directory *>(getter.Node());
324 block_run run;
325 if (indices != NULL && indices->FindEntry("name", &run) == B_OK) {
326 InodeGetter getter(disk, run);
327 Inode* node = getter.Node();
328 getter.Detach();
329 return dynamic_cast<Directory *>(node);
332 // search name index
334 RunSet::iterator iterator = gMainInodes.begin();
335 for (; iterator != gMainInodes.end(); iterator++) {
336 InodeGetter getter(disk, *iterator);
337 Inode* node = getter.Node();
339 if (!node || !node->IsIndex() || node->Name() == NULL)
340 continue;
341 if (!strcmp(node->Name(), "name") && node->Mode() & S_STR_INDEX)
342 return dynamic_cast<Directory *>(node);
345 return NULL;
349 void
350 checkDirectoryContents(Disk& disk, Directory *dir)
352 dir->Rewind();
354 char name[B_FILE_NAME_LENGTH];
355 block_run run;
357 while (dir->GetNextEntry(name, &run) == B_OK) {
358 if (run == dir->BlockRun() || run == dir->Parent()
359 || gMainInodes.find(run) != gMainInodes.end())
360 continue;
362 Inode *missing = gMissing.Get(run);
363 if (missing != NULL) {
364 if (missing->SetName(name) < B_OK) {
365 fprintf(stderr, "setting name of missing node to "
366 "\"%s\" failed!", name);
368 if (gVerbose) {
369 printf("Set name of missing node (%" B_PRId32
370 ", %d) to \"%s\" (%s)\n",
371 run.allocation_group, run.start, missing->Name(), name);
374 missing->SetParent(dir->BlockRun());
376 // if (node->Mode() & S_INDEX_DIR)
377 // {
378 // if (node->Mode() & S_STR_INDEX)
379 // 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);
380 // else
381 // 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);
382 // }
383 else {
384 // missing inode has not been found
385 if (gVerbose) {
386 printf("directory \"%s\" (%" B_PRId32 ", %d): node \"%s\" is "
387 "missing (%" B_PRId32 ", %d, %d)\n", dir->Name(),
388 dir->BlockRun().allocation_group,
389 dir->BlockRun().start, name,
390 run.allocation_group, run.start, run.length);
393 if ((missing = (Inode *)gLogged.Remove(&run)) != NULL) {
394 // missing inode is in the log
395 if (gVerbose)
396 printf("found missing entry in log!\n");
397 if (missing->InodeBuffer()->parent != dir->BlockRun()) {
398 if (gVerbose)
399 puts("\tparent directories differ (may be an old "
400 "version of it), reseting parent.");
401 missing->SetParent(dir->BlockRun());
403 if (!gMissing.Insert(missing))
404 delete missing;
405 } else if (!gMissingEmpty.Contains(&run)) {
406 // not known at all yet
407 Inode *empty = Inode::EmptyInode(&disk, name, 0);
408 if (empty) {
409 empty->SetBlockRun(run);
410 empty->SetParent(dir->BlockRun());
411 if (gVerbose)
412 printf("\tname = %s\n", empty->Name());
414 if (!gMissingEmpty.Insert(empty))
415 delete empty;
423 void
424 checkStructure(Disk &disk)
426 off_t count = 0;
427 Inode* node;
429 RunSet::iterator iterator = gMainInodes.begin();
430 for (; iterator != gMainInodes.end(); iterator++) {
431 InodeGetter getter(disk, *iterator);
432 node = getter.Node();
434 count++;
435 if ((count % 50) == 0)
436 fprintf(stderr, "%" B_PRIdOFF " inodes processed...\33[1A\n", count);
438 if (node == NULL)
439 continue;
441 if (node->IsDirectory() && !node->IsIndex()) {
442 // check if all entries are in the hashtable
443 Directory* directory = dynamic_cast<Directory*>(node);
444 if (directory != NULL)
445 checkDirectoryContents(disk, directory);
446 else {
447 printf("Node \"%s\" at %" B_PRId32
448 ",%d looks like a directory, but isn't.\n",
449 node->Name(), node->BlockRun().allocation_group,
450 node->BlockRun().start);
454 // check for the parent directory
456 block_run run = node->Parent();
457 InodeGetter parentGetter(disk, run);
458 Inode *parentNode = parentGetter.Node();
460 Directory *dir = dynamic_cast<Directory *>(parentNode);
461 if (dir || (parentNode && (node->Mode() & S_ATTR_DIR))) {
462 // entry has a valid parent directory, so it's assumed to be a valid entry
463 disk.BlockBitmap()->BackupSet(node, true);
464 } else if (node->Mode() & S_ATTR) {
465 if (gVerbose) {
466 printf("attribute \"%s\" at %" B_PRId32 ",%d misses its parent.\n",
467 node->Name(), node->BlockRun().allocation_group,
468 node->BlockRun().start);
469 puts("\thandling not yet implemented...");
471 } else /*if ((node->Flags() & INODE_DELETED) == 0)*/ {
472 Inode* missing = gMissing.Get(run);
473 dir = dynamic_cast<Directory *>(missing);
475 if (missing == NULL) {
476 if (gVerbose) {
477 printf("%s \"%s\" (%" B_PRId32 ", %d, mode = %10" B_PRIo32
478 "): parent directory is missing (%" B_PRId32
479 ", %d, %d), may be deleted!\n",
480 node->IsFile() ? "file" : "node", node->Name(),
481 node->BlockRun().allocation_group,
482 node->BlockRun().start,
483 node->Mode(), run.allocation_group, run.start,
484 run.length);
487 if ((dir = dynamic_cast<Directory *>((Inode *)gLogged.Remove(
488 &run))) != NULL) {
489 if (gVerbose) {
490 printf("found directory \"%s\" in log:\n", dir->Name());
491 if (dir->Size() > 0)
492 dump_inode(dir, dir->InodeBuffer());
493 else
494 puts("\tempty inode.");
496 } else {
497 if (gVerbose)
498 puts("\tcreate parent missing entry");
500 Inode *nameNode = (Inode *)gMissingEmpty.Remove(&run);
501 if (nameNode != NULL) {
502 nameNode->SetMode(S_IFDIR);
503 if (gVerbose)
504 printf("found missing name!\n");
505 } else {
506 BString parentName;
507 parentName << "__directory " << run.allocation_group
508 << ":" << (int32)run.start;
510 nameNode = Inode::EmptyInode(&disk, parentName.String(),
511 S_IFDIR);
512 if (nameNode) {
513 nameNode->SetBlockRun(run);
514 nameNode->SetParent(disk.Root());
518 if (nameNode) {
519 dir = new Directory(*nameNode);
520 if (dir->CopyBuffer() < B_OK)
521 puts("could not copy buffer!");
522 else
523 delete nameNode;
526 if (dir) {
527 dir->AcquireBuffer();
529 if (!gMissing.Insert(dir)) {
530 printf("could not add dir!!\n");
531 delete dir;
532 dir = NULL;
535 } else if (missing != NULL && dir == NULL && gVerbose) {
536 printf("%s \"%s\" (%" B_PRId32 ", %d, mode = %10" B_PRIo32
537 "): parent directory found in missing list (%" B_PRId32
538 ", %d, %d), but it's not a dir!\n",
539 node->IsFile() ? "file" : "node", node->Name(),
540 node->BlockRun().allocation_group, node->BlockRun().start,
541 node->Mode(), run.allocation_group, run.start, run.length);
542 } else if (gVerbose) {
543 printf("%s \"%s\" (%" B_PRId32 ", %d, mode = %10" B_PRIo32
544 "): parent directory found in missing list (%" B_PRId32
545 ", %d, %d)!\n",
546 node->IsFile() ? "file" : "node", node->Name(),
547 node->BlockRun().allocation_group, node->BlockRun().start,
548 node->Mode(), run.allocation_group, run.start, run.length);
551 if (dir) {
552 dir->AddEntry(node);
553 dir->ReleaseBuffer();
556 // else
557 // {
558 // printf("node %s\n", node->Name());
559 // status_t status = dir->Contains(node);
560 // if (status == B_ENTRY_NOT_FOUND)
561 // printf("node \"%s\": parent directory \"%s\" contains no link to this node!\n",node->Name(),dir->Name());
562 // else if (status != B_OK)
563 // printf("node \"%s\": parent directory \"%s\" error: %s\n",node->Name(),dir->Name(),strerror(status));
564 // }
566 // check for attributes
568 run = node->Attributes();
569 if (!run.IsZero()) {
570 //printf("node \"%s\" (%ld, %d, mode = %010lo): has attribute dir!\n",node->Name(),node->BlockRun().allocation_group,node->BlockRun().start,node->Mode());
572 if (gMainInodes.find(run) == gMainInodes.end()) {
573 if (gVerbose) {
574 printf("node \"%s\": attributes are missing (%" B_PRId32
575 ", %d, %d)\n", node->Name(), run.allocation_group,
576 run.start, run.length);
579 if ((dir = (Directory *)gMissing.Get(run)) != NULL) {
580 if (gVerbose)
581 puts("\tfound in missing");
582 dir->SetMode(dir->Mode() | S_ATTR_DIR);
583 dir->SetParent(node->BlockRun());
584 } else {
585 if (gVerbose)
586 puts("\tcreate new!");
588 Inode *empty = Inode::EmptyInode(&disk, NULL,
589 S_IFDIR | S_ATTR_DIR);
590 if (empty) {
591 empty->SetBlockRun(run);
592 empty->SetParent(node->BlockRun());
594 dir = new Directory(*empty);
595 if (dir->CopyBuffer() < B_OK)
596 puts("could not copy buffer!");
597 else
598 delete empty;
600 if (!gMissing.Insert(dir)) {
601 puts("\tcould not add attribute dir");
602 delete dir;
609 printf("%" B_PRIdOFF " inodes processed.\n", count);
611 Directory *directory = getNameIndex(disk);
612 if (directory != NULL) {
613 puts("\n*** Search names of missing inodes in the name index");
615 BPlusTree *tree;
616 if (directory->GetTree(&tree) == B_OK && tree->Validate(gVerbose) == B_OK) {
617 char name[B_FILE_NAME_LENGTH];
618 block_run run;
619 directory->Rewind();
620 while (directory->GetNextEntry(name, &run) >= B_OK) {
621 if ((node = gMissing.Get(run)) == NULL)
622 continue;
624 if (gVerbose) {
625 printf(" Node found: %" B_PRId32 ":%d\n",
626 run.allocation_group, run.start);
628 if (node->Name() == NULL || strcmp(node->Name(), name)) {
629 if (gVerbose) {
630 printf("\tnames differ: %s -> %s (indices)\n",
631 node->Name(), name);
633 node->SetName(name);
636 } else
637 printf("\tname index is corrupt!\n");
639 directory->ReleaseBuffer();
640 } else
641 printf("*** Name index corrupt or not existent!\n");
643 if (!gVerbose)
644 return;
646 if (!gMissing.IsEmpty())
647 puts("\n*** Missing inodes:");
649 gMissing.Rewind();
650 while (gMissing.GetNextEntry(&node) == B_OK) {
651 if (gDumpMissingInodes)
652 dump_inode(node, node->InodeBuffer());
654 Directory *dir = dynamic_cast<Directory *>(node);
655 if (dir) {
656 printf("\ndirectory \"%s\" (%" B_PRId32 ", %d) contents:\n",
657 node->Name(), node->BlockRun().allocation_group,
658 node->BlockRun().start);
660 dir->Rewind();
662 char name[B_FILE_NAME_LENGTH];
663 block_run run;
664 while (dir->GetNextEntry(name, &run) == B_OK) {
665 printf("\t\"%s\" (%" B_PRId32 ", %d, %d)\n", name,
666 run.allocation_group, run.start, run.length);
669 BPlusTree *tree;
670 if (dir->GetTree(&tree) < B_OK)
671 continue;
673 uint16 length;
674 off_t offset;
676 while (tree->GetNextEntry(name, &length, B_FILE_NAME_LENGTH,
677 &offset) == B_OK) {
678 name[length] = 0;
680 run = disk.ToBlockRun(offset);
681 printf("%s: block_run == (%5" B_PRId32 ",%5d,%5d), \"%s\"\n",
682 dir->Name(), run.allocation_group, run.start, run.length,
683 name);
686 //tree->WriteTo(dir);
687 //disk.WriteAt(dir->Offset(),dir->InodeBuffer(),disk.BlockSize());
690 gMissing.Release(node);
695 void
696 copyInodes(Disk& disk, const char* copyTo)
698 if (copyTo == NULL)
699 return;
701 HashtableInodeSource source(disk);
702 Inode *node;
704 int32 count = 0;
706 RunSet::iterator iterator = gMainInodes.begin();
707 for (; iterator != gMainInodes.end(); iterator++) {
708 InodeGetter getter(disk, *iterator);
709 Inode* node = getter.Node();
711 if (node && !node->IsIndex() && !node->IsAttributeDirectory())
712 node->CopyTo(copyTo, true, &source);
714 if ((++count % 500) == 0)
715 fprintf(stderr, "copied %" B_PRId32 " files...\n", count);
718 gMissing.Rewind();
719 while (gMissing.GetNextEntry(&node) == B_OK) {
720 if (!node->IsIndex() && !node->IsAttributeDirectory())
721 node->CopyTo(copyTo, true, &source);
723 gMissing.Release(node);
728 void
729 usage(char *name)
731 fprintf(stderr,"usage: %s [-idv] [-r [start-offset] [end-offset]] <device> [recover-to-path]\n"
732 "\t-i\trecreate indices on target disk\n"
733 "\t-d\tdump missing and recreated i-nodes\n"
734 "\t-r\tdisk access in raw mode (use only if the partition table is invalid)\n"
735 "\t-s\trecreate superblock and exit (for experts only, don't use this\n"
736 "\t\tif you don't know what you're doing)\n"
737 "\t-v\tverbose output\n", name);
738 exit(-1);
743 main(int argc, char **argv)
745 char *fileName = strrchr(argv[0], '/');
746 fileName = fileName ? fileName + 1 : argv[0];
747 bool recreateSuperBlockOnly = false;
749 off_t startOffset = 0, endOffset = -1;
751 puts("Copyright (c) 2001-2008 pinc Software.");
753 if (argc < 2 || !strcmp(argv[1], "--help"))
754 usage(fileName);
756 while (*++argv) {
757 char *arg = *argv;
758 if (*arg == '-') {
759 while (*++arg && isalpha(*arg)) {
760 switch (arg[0]) {
761 case 'r':
763 gRawMode = true;
765 if (argv[1] && isdigit((argv[1])[0])) {
766 argv++;
767 arg = *argv;
769 startOffset = atoll(arg);
771 if (argv[1] && isdigit((argv[1])[0])) {
772 argv++;
773 arg = *argv;
775 endOffset = atoll(arg);
777 if (endOffset != -1 && endOffset < startOffset)
778 usage(fileName);
779 break;
781 case 'v':
782 gVerbose = true;
783 break;
784 case 'i':
785 gCreateIndices = true;
786 break;
787 case 'd':
788 gDumpMissingInodes = true;
789 break;
790 case 's':
791 recreateSuperBlockOnly = true;
792 break;
795 } else
796 break;
799 Disk disk(argv[0], gRawMode, startOffset, endOffset);
800 if (disk.InitCheck() < B_OK) {
801 fprintf(stderr,"Could not open device or file: %s\n",
802 strerror(disk.InitCheck()));
803 return -1;
806 if (argv[1] != NULL) {
807 dev_t device = dev_for_path(argv[1]);
808 fs_info info;
809 if (fs_stat_dev(device, &info) == B_OK) {
810 if (!strcmp(info.device_name, disk.Path().Path())) {
811 fprintf(stderr,"The source and target device are identical, "
812 "you currently need\n"
813 "to have another disk to recover to, sorry!\n");
814 return -1;
816 if ((info.flags & (B_FS_IS_PERSISTENT | B_FS_HAS_ATTR))
817 != (B_FS_IS_PERSISTENT | B_FS_HAS_ATTR)) {
818 fprintf(stderr, "%s: The target file system (%s) does not have "
819 "the required\n"
820 "\tfunctionality in order to restore all information.\n",
821 kProgramName, info.fsh_name);
822 return -1;
827 bool recreatedSuperBlock = false;
829 if (disk.ValidateSuperBlock() < B_OK) {
830 fprintf(stderr, "The disk's superblock is corrupt!\n");
831 if (disk.RecreateSuperBlock() < B_OK) {
832 fprintf(stderr, "Can't recreate the disk's superblock, sorry!\n");
833 return -1;
835 recreatedSuperBlock = true;
837 if (gVerbose) {
838 puts("\n*** The superblock:\n");
839 dump_super_block(disk.SuperBlock());
842 if (recreateSuperBlockOnly) {
843 if (!recreatedSuperBlock) {
844 printf("Superblock was valid, no changes made.\n");
845 return 0;
848 status_t status = disk.WriteAt(512, disk.SuperBlock(),
849 sizeof(disk_super_block));
850 if (status < B_OK) {
851 fprintf(stderr, "Could not write superblock: %s!\n",
852 strerror(status));
853 return 1;
855 return 0;
858 puts("\n*** Collecting inodes...");
860 collectLogInodes(disk);
861 collectRealInodes(disk);
863 puts("\n*** Checking Disk Structure Integrity...");
865 checkStructure(disk);
867 if (argv[1])
868 copyInodes(disk, argv[1]);
870 //disk.WriteBootBlock();
871 //disk.BlockBitmap()->CompareWithBackup();
873 gMissing.MakeEmpty();
874 gLogged.MakeEmpty();
876 return 0;