int checkIndex(Disk &disk,char *attribute,block_run &run,bool collect) { Directory *index = (Directory *)Inode::Factory(&disk,run); status_t status; if (index == NULL || (status = index->InitCheck()) < B_OK) { fprintf(stderr," Could not get index directory for \"%s\": %s!\n",attribute,index ? strerror(status) : "not found/corrupted"); return -1; } printf("\nCheck \"%s\" index's on-disk structure...\n",attribute); //dump_inode(index->InodeBuffer()); BPlusTree *tree; if (index->GetTree(&tree) < B_OK || tree->Validate(true) < B_OK) { fprintf(stderr," B+Tree of index \"%s\" seems to be corrupt!\n",attribute); //return -1; } if (collect && (!gDoNotCheckIndex || !gDoNotCheckForFiles)) collectFiles(disk); if (!gDoNotCheckIndex) { printf("Check for non-existing files in index \"%s\"...\n",attribute); checkIndexForNonExistingFiles(disk,*tree); } if (!gDoNotCheckForFiles) { printf("Check for files not in index \"%s\" (this may take even more time)...\n",attribute); checkFiles(disk,*tree,attribute); } return 0; }
int main(int argc,char **argv) { puts("Copyright (c) 2001-2008 pinc Software."); char *toolName = argv[0]; if (argc < 2 || !strcmp(argv[1],"--help")) { printUsage(toolName); return -1; } while (*++argv) { char *arg = *argv; if (*arg == '-') { while (*++arg && isalpha(*arg)) { switch (*arg) { case 'i': gDoNotCheckIndex = true; break; case 'f': gDoNotCheckForFiles = true; break; case 'a': gCheckAll = true; break; } } } else break; } char *attribute = argv[0]; if (!gCheckAll && attribute == NULL) { printUsage(toolName); return -1; } dev_t device = dev_for_path("."); if (device < B_OK) { fprintf(stderr,"Could not find device for current location: %s\n",strerror(device)); return -1; } fs_info info; if (fs_stat_dev(device,&info) < B_OK) { fprintf(stderr,"Could not get stats for device: %s\n",strerror(errno)); return -1; } Disk disk(info.device_name); status_t status; if ((status = disk.InitCheck()) < B_OK) { fprintf(stderr,"Could not open device or file \"%s\": %s\n",info.device_name,strerror(status)); return -1; } if (disk.ValidateSuperBlock() < B_OK) { fprintf(stderr,"The disk's superblock is corrupt!\n"); return -1; } Directory *indices = (Directory *)Inode::Factory(&disk,disk.Indices()); if (indices == NULL || (status = indices->InitCheck()) < B_OK) { fprintf(stderr," Could not get indices directory: %s!\n",indices ? strerror(status) : "not found/corrupted"); delete indices; return -1; } BPlusTree *tree; if (indices->GetTree(&tree) < B_OK || tree->Validate() < B_OK) { fprintf(stderr," Indices B+Tree seems to be corrupt!\n"); delete indices; return -1; } block_run run; if (gCheckAll) { putchar('\n'); collectFiles(disk); char name[B_FILE_NAME_LENGTH]; while (indices->GetNextEntry(name,&run) >= B_OK) checkIndex(disk,name,run,false); } else if (indices->FindEntry(attribute,&run) == B_OK) checkIndex(disk,attribute,run,true); else fprintf(stderr," Could not find index directory for \"%s\"!\n",attribute); delete indices; gHashtable.MakeEmpty(HASH_EMPTY_NONE,HASH_EMPTY_FREE); return 0; }
void checkFiles(Disk &disk,BPlusTree &tree,char *attribute) { block_run *runs = (block_run *)malloc(gCount * sizeof(block_run)); if (runs == NULL) { fprintf(stderr," Not enough memory!\n"); return; } // copy hashtable to array block_run *run = NULL; int32 index = 0; gHashtable.Rewind(); while (gHashtable.GetNextEntry((void **)&run) == B_OK) { runs[index++] = *run; } // sort array to speed up disk access qsort(runs,index,sizeof(block_run),(int (*)(const void *,const void *))compareBlockRuns); bool sizeIndex = !strcmp(attribute,"size"); bool nameIndex = !strcmp(attribute,"name"); bool modifiedIndex = !strcmp(attribute,"last_modified"); char key[B_FILE_NAME_LENGTH]; uint16 keyLength = 0; Inode *inode = NULL; for (int32 i = 0;i < index;i++) { if (i % 50 == 0) printf(" %7ld%s1A\n",i,gEscape); delete inode; inode = Inode::Factory(&disk,runs[i]); if (inode == NULL || inode->InitCheck() < B_OK) { fprintf(stderr," inode at (%ld, %d) is corrupt!\n",runs[i].allocation_group,runs[i].start); delete inode; continue; } // check indices not based on standard attributes if (sizeIndex) { if (inode->IsDirectory()) continue; memcpy(key,&inode->InodeBuffer()->data.size,sizeof(off_t)); keyLength = sizeof(off_t); } else if (nameIndex) { strcpy(key,inode->Name()); keyLength = strlen(key); } else if (modifiedIndex) { if (inode->IsDirectory()) continue; memcpy(key,&inode->InodeBuffer()->last_modified_time,sizeof(off_t)); keyLength = sizeof(off_t); } else // iterate through all attributes to find the right one (damn slow, sorry...) { inode->RewindAttributes(); char name[B_FILE_NAME_LENGTH]; uint32 type; void *data; size_t length; bool found = false; while (inode->GetNextAttribute(name,&type,&data,&length) == B_OK) { if (!strcmp(name,attribute)) { strncpy(key,(char *)data,B_FILE_NAME_LENGTH - 1); key[B_FILE_NAME_LENGTH - 1] = '\0'; keyLength = length > B_FILE_NAME_LENGTH ? B_FILE_NAME_LENGTH : length; found = true; break; } } if (!found) continue; } off_t value; if (tree.Find((uint8 *)key,keyLength,&value) < B_OK) { if (*inode->Name()) fprintf(stderr," inode at (%ld, %d) name \"%s\" is not in index!\n",runs[i].allocation_group,runs[i].start,inode->Name()); else { // inode is obviously deleted! block_run parent = inode->Parent(); Directory *directory = (Directory *)Inode::Factory(&disk,parent); if (directory != NULL && directory->InitCheck() == B_OK) { BPlusTree *parentTree; if (directory->GetTree(&parentTree) == B_OK) { char name[B_FILE_NAME_LENGTH]; uint16 length; off_t offset,searchOffset = disk.ToBlock(runs[i]); bool found = false; while (parentTree->GetNextEntry(name,&length,B_FILE_NAME_LENGTH,&offset) == B_OK) { if (offset == searchOffset) { fprintf(stderr," inode at (%ld, %d) name \"%s\" was obviously deleted, but the parent \"%s\" still contains it!\n",runs[i].allocation_group,runs[i].start,name,directory->Name()); found = true; break; } } if (!found) fprintf(stderr," inode at (%ld, %d) was obviously deleted, and the parent \"%s\" obviously doesn't contain it anymore!\n",runs[i].allocation_group,runs[i].start,directory->Name()); } else fprintf(stderr," inode at (%ld, %d) was obviously deleted, but the parent \"%s\" is invalid and still contains it!\n",runs[i].allocation_group,runs[i].start,directory->Name()); } else { // not that this would be really possible... - but who knows fprintf(stderr," inode at (%ld, %d) is not in index and has invalid parent!\n",runs[i].allocation_group,runs[i].start); } delete directory; } } else { if (bplustree_node::LinkType(value) == BPLUSTREE_NODE) { if (disk.ToBlockRun(value) != runs[i]) fprintf(stderr," offset in index and inode offset doesn't match for inode \"%s\" at (%ld, %d)\n",inode->Name(),runs[i].allocation_group,runs[i].start); } else { // search duplicates char name[B_FILE_NAME_LENGTH]; uint16 length; off_t offset; bool found = false,duplicates = false; //puts("++"); tree.Rewind(); while (tree.GetNextEntry(name,&length,B_FILE_NAME_LENGTH,&offset) == B_OK) { //printf("search for = %ld, key = %ld -> value = %Ld (%ld, %d)\n",*(int32 *)&key,*(int32 *)&name,offset,disk.ToBlockRun(offset).allocation_group,disk.ToBlockRun(offset).start); if (keyLength == length && !memcmp(key,name,keyLength)) { duplicates = true; if (disk.ToBlockRun(offset) == runs[i]) { found = true; break; } } //else if (duplicates) // break; } if (!found) { printf(" inode \"%s\" at (%ld, %d) not found in duplicates!\n",inode->Name(),runs[i].allocation_group,runs[i].start); // return; } } } } delete inode; printf(" %7Ld files processed.\n",gCount); }