19483Svlivanov/* 29483Svlivanov * Copyright (c) 2001-2008 pinc Software. All Rights Reserved. 39483Svlivanov */ 49483Svlivanov 59483Svlivanov//! Handles BFS superblock, disk access etc. 69483Svlivanov 79483Svlivanov#include "Disk.h" 89483Svlivanov#include "dump.h" 99483Svlivanov 109483Svlivanov#include <Drivers.h> 119483Svlivanov#include <File.h> 129483Svlivanov#include <Entry.h> 139483Svlivanov#include <List.h> 149483Svlivanov#include <fs_info.h> 159483Svlivanov 169483Svlivanov#include <stdlib.h> 179483Svlivanov#include <stdio.h> 189483Svlivanov#include <string.h> 199483Svlivanov#include <unistd.h> 209483Svlivanov#include <ctype.h> 219483Svlivanov 229483Svlivanov 239483Svlivanov#define MIN_BLOCK_SIZE_INODES 50 249483Svlivanov#define MAX_BLOCK_SIZE_INODES 500 259483Svlivanov 269483Svlivanov 279483Svlivanovstruct bfs_disk_info { 289483Svlivanov off_t offset; 299483Svlivanov disk_super_block super_block; 309483Svlivanov}; 319483Svlivanov 329483Svlivanov 339483Svlivanovclass CacheableBlockRun : public BlockRunCache::Cacheable { 349483Svlivanov public: 359483Svlivanov CacheableBlockRun(block_run run,uint8 *data) 369483Svlivanov : 379483Svlivanov fRun(run), 389483Svlivanov fData(data) 399483Svlivanov { 409483Svlivanov } 419483Svlivanov 429483Svlivanov virtual ~CacheableBlockRun() 439483Svlivanov { 449483Svlivanov free(fData); 459483Svlivanov } 469483Svlivanov 479483Svlivanov virtual bool Equals(block_run run) 489483Svlivanov { 499483Svlivanov return run == fRun; 509483Svlivanov } 519483Svlivanov 529483Svlivanov void SetData(uint8 *data) 539483Svlivanov { 549483Svlivanov fData = data; 559483Svlivanov } 569483Svlivanov 579483Svlivanov uint8 *Data() 589483Svlivanov { 599483Svlivanov return fData; 609483Svlivanov } 619483Svlivanov 629483Svlivanov protected: 639483Svlivanov block_run fRun; 649483Svlivanov uint8 *fData; 659483Svlivanov}; 669483Svlivanov 679483Svlivanov 689483SvlivanovBlockRunCache::BlockRunCache(Disk *disk) 699483Svlivanov : Cache<block_run>(), 709483Svlivanov fDisk(disk) 719483Svlivanov{ 729483Svlivanov} 739483Svlivanov 749483Svlivanov 759483SvlivanovCache<block_run>::Cacheable *BlockRunCache::NewCacheable(block_run run) 7610312Svlivanov{ 779483Svlivanov ssize_t length = (int32)run.length << fDisk->BlockShift(); 789483Svlivanov 799483Svlivanov void *buffer = malloc(length); 809483Svlivanov if (buffer == NULL) 819483Svlivanov return NULL; 829483Svlivanov 839483Svlivanov ssize_t read = fDisk->ReadAt(fDisk->ToOffset(run),buffer,length); 849483Svlivanov if (read < length) { 859483Svlivanov free(buffer); 869483Svlivanov return NULL; 879483Svlivanov } 889483Svlivanov 899483Svlivanov return new CacheableBlockRun(run,(uint8 *)buffer); 909483Svlivanov} 919483Svlivanov 929483Svlivanov 939483Svlivanov// #pragma mark - 949483Svlivanov 959483Svlivanov 969483SvlivanovDisk::Disk(const char *deviceName, bool rawMode, off_t start, off_t stop) 979483Svlivanov : 989483Svlivanov fBufferedFile(NULL), 999483Svlivanov fRawDiskOffset(0), 1009483Svlivanov fSize(0LL), 1019483Svlivanov fCache(this), 1029483Svlivanov fRawMode(rawMode) 1039483Svlivanov{ 1049483Svlivanov BEntry entry(deviceName); 1059483Svlivanov fPath.SetTo(deviceName); 1069483Svlivanov 1079483Svlivanov if (entry.IsDirectory()) { 1089483Svlivanov dev_t on = dev_for_path(deviceName); 1099483Svlivanov fs_info info; 1109483Svlivanov if (fs_stat_dev(on, &info) != B_OK) 1119483Svlivanov return; 1129483Svlivanov 1139483Svlivanov fPath.SetTo(info.device_name); 1149483Svlivanov deviceName = fPath.Path(); 1159483Svlivanov } 1169483Svlivanov 1179483Svlivanov if (!rawMode && !strncmp(deviceName, "/dev/", 5) 1189483Svlivanov && !strcmp(deviceName + strlen(deviceName) - 3, "raw")) 1199483Svlivanov fprintf(stderr, "Raw mode not selected, but raw device specified.\n"); 1209483Svlivanov 1219483Svlivanov if (fFile.SetTo(deviceName, B_READ_WRITE) < B_OK) { 1229483Svlivanov //fprintf(stderr,"Could not open file: %s\n",strerror(fFile.InitCheck())); 1239483Svlivanov return; 1249483Svlivanov } 1259483Svlivanov fBufferedFile = new BBufferIO(&fFile, 1024 * 1024, false); 1269483Svlivanov 1279483Svlivanov int device = open(deviceName, O_RDONLY); 1289483Svlivanov if (device < B_OK) { 1299483Svlivanov //fprintf(stderr,"Could not open device\n"); 1309483Svlivanov return; 1319483Svlivanov } 1329483Svlivanov 1339483Svlivanov partition_info partitionInfo; 1349483Svlivanov device_geometry geometry; 1359483Svlivanov if (ioctl(device, B_GET_PARTITION_INFO, &partitionInfo, 1369483Svlivanov sizeof(partition_info)) == 0) { 1379483Svlivanov //if (gDumpPartitionInfo) 1389483Svlivanov // dump_partition_info(&partitionInfo); 1399483Svlivanov fSize = partitionInfo.size; 1409483Svlivanov } else if (ioctl(device, B_GET_GEOMETRY, &geometry, sizeof(device_geometry)) 1419483Svlivanov == 0) { 1429483Svlivanov fSize = (off_t)geometry.cylinder_count * geometry.sectors_per_track 1439483Svlivanov * geometry.head_count * geometry.bytes_per_sector; 1449483Svlivanov } else { 1459483Svlivanov fprintf(stderr,"Disk: Could not get partition info.\n Use file size as partition size\n"); 1469483Svlivanov fFile.GetSize(&fSize); 1479483Svlivanov } 1489483Svlivanov close(device); 1499483Svlivanov 1509483Svlivanov if (fSize == 0LL) 1519483Svlivanov fprintf(stderr,"Disk: Invalid file size (%Ld bytes)!\n",fSize); 1529483Svlivanov 1539483Svlivanov if (rawMode && ScanForSuperBlock(start, stop) < B_OK) { 1549483Svlivanov fFile.Unset(); 1559483Svlivanov return; 1569483Svlivanov } 1579483Svlivanov 1589483Svlivanov if (fBufferedFile->ReadAt(512 + fRawDiskOffset, &fSuperBlock, 1599483Svlivanov sizeof(disk_super_block)) < 1) 1609483Svlivanov fprintf(stderr,"Disk: Could not read superblock\n"); 1619483Svlivanov 1629483Svlivanov //dump_super_block(&fSuperBlock); 1639483Svlivanov} 1649483Svlivanov 1659483Svlivanov 1669483SvlivanovDisk::~Disk() 1679483Svlivanov{ 1689483Svlivanov delete fBufferedFile; 1699483Svlivanov} 1709483Svlivanov 1719483Svlivanov 1729483Svlivanovstatus_t Disk::InitCheck() 1739483Svlivanov{ 1749483Svlivanov status_t status = fFile.InitCheck(); 1759483Svlivanov if (status == B_OK) 1769483Svlivanov return fSize == 0LL ? B_ERROR : B_OK; 1779483Svlivanov 1789483Svlivanov return status; 1799483Svlivanov} 1809483Svlivanov 1819483Svlivanov 1829483Svlivanovblock_run Disk::ToBlockRun(off_t start, int16 length) const 1839483Svlivanov{ 1849483Svlivanov block_run run; 1859483Svlivanov run.allocation_group = start >> fSuperBlock.ag_shift; 1869483Svlivanov run.start = start & ((1UL << fSuperBlock.ag_shift) - 1); 1879483Svlivanov run.length = length; 1889483Svlivanov 1899483Svlivanov return run; 1909483Svlivanov} 1919483Svlivanov 1929483Svlivanov 1939483Svlivanovoff_t Disk::LogSize() const 1949483Svlivanov{ 1959483Svlivanov if (fSuperBlock.num_blocks >= 4096) 1969483Svlivanov return 2048; 1979483Svlivanov 1989483Svlivanov return 512; 1999483Svlivanov} 2009483Svlivanov 2019483Svlivanov 2029483Svlivanovuint8 *Disk::ReadBlockRun(block_run run) 2039483Svlivanov{ 2049483Svlivanov CacheableBlockRun *entry = (CacheableBlockRun *)fCache.Get(run); 2059483Svlivanov if (entry) 2069483Svlivanov return entry->Data(); 2079483Svlivanov 2089483Svlivanov return NULL; 2099483Svlivanov} 2109483Svlivanov 2119483Svlivanov 2129483Svlivanovstatus_t 2139483SvlivanovDisk::DumpBootBlockToFile() 2149483Svlivanov{ 2159483Svlivanov BFile file("/boot/home/bootblock.old", B_READ_WRITE | B_CREATE_FILE); 2169483Svlivanov if (file.InitCheck() < B_OK) 2179483Svlivanov return file.InitCheck(); 2189483Svlivanov 2199483Svlivanov char buffer[BlockSize()]; 2209483Svlivanov ssize_t bytes = ReadAt(0, buffer, BlockSize()); 2219509Svlivanov if (bytes < (int32)BlockSize()) 2229509Svlivanov return bytes < B_OK ? bytes : B_ERROR; 2239509Svlivanov 2249509Svlivanov file.Write(buffer, BlockSize()); 2259509Svlivanov 2269509Svlivanov // initialize buffer 2279509Svlivanov memset(buffer, 0, BlockSize()); 2289509Svlivanov memcpy(buffer + 512, &fSuperBlock, sizeof(disk_super_block)); 2299509Svlivanov 2309509Svlivanov // write buffer to disk 2319509Svlivanov WriteAt(0, buffer, BlockSize()); 2329509Svlivanov 2339483Svlivanov return B_OK; 2349483Svlivanov} 2359483Svlivanov 2369483Svlivanov 2379483Svlivanov// #pragma mark - Superblock recovery methods 2389483Svlivanov 2399483Svlivanov 2409483Svlivanovstatus_t 2419483SvlivanovDisk::ScanForSuperBlock(off_t start, off_t stop) 2429483Svlivanov{ 2439483Svlivanov printf("Disk size %Ld bytes, %.2f GB\n", fSize, 1.0 * fSize / (1024*1024*1024)); 2449483Svlivanov 2459483Svlivanov uint32 blockSize = 4096; 2469483Svlivanov char buffer[blockSize + 1024]; 2479483Svlivanov 2489483Svlivanov if (stop == -1) 2499483Svlivanov stop = fSize; 2509483Svlivanov 2519483Svlivanov char escape[3] = {0x1b, '[', 0}; 2529483Svlivanov 2539483Svlivanov BList superBlocks; 2549483Svlivanov 2559483Svlivanov printf("Scanning Disk from %Ld to %Ld\n", start, stop); 2569483Svlivanov 2579483Svlivanov for (off_t offset = start; offset < stop; offset += blockSize) 2589483Svlivanov { 2599483Svlivanov if (((offset-start) % (blockSize * 100)) == 0) 2609483Svlivanov printf(" %12Ld, %.2f GB %s1A\n",offset,1.0 * offset / (1024*1024*1024),escape); 2619483Svlivanov 2629483Svlivanov ssize_t bytes = fBufferedFile->ReadAt(offset, buffer, blockSize + 1024); 2639483Svlivanov if (bytes < B_OK) 2649483Svlivanov { 2659483Svlivanov fprintf(stderr,"Could not read from device: %s\n", strerror(bytes)); 2669483Svlivanov return -1; 2679483Svlivanov } 2689483Svlivanov 2699483Svlivanov for (uint32 i = 0;i < blockSize - 2;i++) 2709483Svlivanov { 2719483Svlivanov disk_super_block *super = (disk_super_block *)&buffer[i]; 2729483Svlivanov 2739483Svlivanov if (super->magic1 == (int32)SUPER_BLOCK_MAGIC1 2749483Svlivanov && super->magic2 == (int32)SUPER_BLOCK_MAGIC2 275 && super->magic3 == (int32)SUPER_BLOCK_MAGIC3) 276 { 277 printf("\n(%ld) *** BFS superblock found at: %Ld\n",superBlocks.CountItems() + 1,offset); 278 dump_super_block(super); 279 280 // add a copy of the superblock to the list 281 bfs_disk_info *info = (bfs_disk_info *)malloc(sizeof(bfs_disk_info)); 282 if (info == NULL) 283 return B_NO_MEMORY; 284 285 memcpy(&info->super_block, super, sizeof(disk_super_block)); 286 info->offset = offset + i - 512; 287 /* location off the BFS superblock is 512 bytes after the partition start */ 288 superBlocks.AddItem(info); 289 } 290 } 291 } 292 293 if (superBlocks.CountItems() == 0) { 294 puts("\nCouldn't find any BFS superblocks!"); 295 return B_ENTRY_NOT_FOUND; 296 } 297 298 // Let the user decide which block to use 299 300 puts("\n\nThe following disks were found:"); 301 302 for (int32 i = 0; i < superBlocks.CountItems(); i++) { 303 bfs_disk_info *info = (bfs_disk_info *)superBlocks.ItemAt(i); 304 305 printf("%ld) %s, offset %Ld, size %g GB (%svalid)\n", i + 1, 306 info->super_block.name, info->offset, 307 1.0 * info->super_block.num_blocks * info->super_block.block_size / (1024*1024*1024), 308 ValidateSuperBlock(info->super_block) < B_OK ? "in" : ""); 309 } 310 311 char answer[16]; 312 printf("\nChoose one (by number): "); 313 fflush(stdout); 314 315 fgets(answer, 15, stdin); 316 int32 index = atol(answer); 317 318 if (index > superBlocks.CountItems() || index < 1) { 319 puts("No disk there... exiting."); 320 return B_BAD_VALUE; 321 } 322 323 bfs_disk_info *info = (bfs_disk_info *)superBlocks.ItemAt(index - 1); 324 325 // ToDo: free the other disk infos 326 327 fRawDiskOffset = info->offset; 328 fBufferedFile->Seek(fRawDiskOffset, SEEK_SET); 329 330 if (ValidateSuperBlock(info->super_block)) 331 fSize = info->super_block.block_size * info->super_block.block_size; 332 else { 333 // just make it open-end 334 fSize -= fRawDiskOffset; 335 } 336 337 return B_OK; 338} 339 340 341status_t 342Disk::ValidateSuperBlock(disk_super_block &superBlock) 343{ 344 if (superBlock.magic1 != (int32)SUPER_BLOCK_MAGIC1 345 || superBlock.magic2 != (int32)SUPER_BLOCK_MAGIC2 346 || superBlock.magic3 != (int32)SUPER_BLOCK_MAGIC3 347 || (int32)superBlock.block_size != superBlock.inode_size 348 || superBlock.fs_byte_order != SUPER_BLOCK_FS_LENDIAN 349 || (1UL << superBlock.block_shift) != superBlock.block_size 350 || superBlock.num_ags < 1 351 || superBlock.ag_shift < 1 352 || superBlock.blocks_per_ag < 1 353 || superBlock.num_blocks < 10 354 || superBlock.used_blocks > superBlock.num_blocks 355 || superBlock.num_ags != divide_roundup(superBlock.num_blocks, 356 1L << superBlock.ag_shift)) 357 return B_ERROR; 358 359 return B_OK; 360} 361 362 363status_t 364Disk::ValidateSuperBlock() 365{ 366 if (ValidateSuperBlock(fSuperBlock) < B_OK) 367 return B_ERROR; 368 369 fBitmap.SetTo(this); 370 371 return B_OK; 372} 373 374 375status_t 376Disk::RecreateSuperBlock() 377{ 378 memset(&fSuperBlock,0,sizeof(disk_super_block)); 379 380 puts("\n*** Determine block size"); 381 382 status_t status = DetermineBlockSize(); 383 if (status < B_OK) 384 return status; 385 386 printf("\tblock size = %ld\n",BlockSize()); 387 388 strcpy(fSuperBlock.name,"recovered"); 389 fSuperBlock.magic1 = SUPER_BLOCK_MAGIC1; 390 fSuperBlock.fs_byte_order = SUPER_BLOCK_FS_LENDIAN; 391 fSuperBlock.block_shift = get_shift(BlockSize()); 392 fSuperBlock.num_blocks = fSize / BlockSize(); // only full blocks 393 fSuperBlock.inode_size = BlockSize(); 394 fSuperBlock.magic2 = SUPER_BLOCK_MAGIC2; 395 396 fSuperBlock.flags = SUPER_BLOCK_CLEAN; 397 398 // size of the block bitmap + root block 399 fLogStart = 1 + divide_roundup(fSuperBlock.num_blocks,BlockSize() * 8); 400 401 // set it anywhere in the log 402 fSuperBlock.log_start = fLogStart + (LogSize() >> 1); 403 fSuperBlock.log_end = fSuperBlock.log_start; 404 405 // 406 // scan for indices and root inode 407 // 408 409 puts("\n*** Scanning for indices and root node..."); 410 fValidOffset = 0LL; 411 bfs_inode indexDir; 412 bfs_inode rootDir; 413 if (ScanForIndexAndRoot(&indexDir,&rootDir) < B_OK) { 414 fprintf(stderr,"ERROR: Could not find root directory! Trying to recreate the superblock will have no effect!\n\tSetting standard values for the root dir.\n"); 415 rootDir.inode_num.allocation_group = 8; 416 rootDir.inode_num.start = 0; 417 rootDir.inode_num.length = 1; 418 //gErrors++; 419 } 420 if (fValidOffset == 0LL) { 421 printf("No valid inode found so far - perform search.\n"); 422 423 off_t offset = 8LL * 65536 * BlockSize(); 424 char buffer[1024]; 425 GetNextSpecialInode(buffer,&offset,offset + 32LL * 65536 * BlockSize(),true); 426 427 if (fValidOffset == 0LL) 428 { 429 fprintf(stderr,"FATAL ERROR: Could not find valid inode!\n"); 430 return B_ERROR; 431 } 432 } 433 434 // calculate allocation group size 435 436 int32 allocationGroupSize = (fValidOffset - fValidBlockRun.start 437 * BlockSize() 438 + BlockSize() - 1) / (BlockSize() * fValidBlockRun.allocation_group); 439 440 fSuperBlock.blocks_per_ag = allocationGroupSize / (BlockSize() << 3); 441 fSuperBlock.ag_shift = get_shift(allocationGroupSize); 442 fSuperBlock.num_ags = divide_roundup(fSuperBlock.num_blocks,allocationGroupSize); 443 444 // calculate rest of log area 445 446 fSuperBlock.log_blocks.allocation_group = fLogStart / allocationGroupSize; 447 fSuperBlock.log_blocks.start = fLogStart - fSuperBlock.log_blocks.allocation_group * allocationGroupSize; 448 fSuperBlock.log_blocks.length = LogSize(); // assumed length of 2048 blocks 449 450 if (fLogStart != ((indexDir.inode_num.allocation_group 451 << fSuperBlock.ag_shift) + indexDir.inode_num.start - LogSize())) { 452 fprintf(stderr,"ERROR: start of logging area doesn't fit assumed value " 453 "(%Ld blocks before indices)!\n", LogSize()); 454 //gErrors++; 455 } 456 457 fSuperBlock.magic3 = SUPER_BLOCK_MAGIC3; 458 fSuperBlock.root_dir = rootDir.inode_num; 459 fSuperBlock.indices = indexDir.inode_num; 460 461 // calculate used blocks (from block bitmap) 462 463 fBitmap.SetTo(this); 464 if (fBitmap.UsedBlocks()) 465 fSuperBlock.used_blocks = fBitmap.UsedBlocks(); 466 else { 467 fprintf(stderr,"ERROR: couldn't calculate number of used blocks, marking all blocks as used!\n"); 468 fSuperBlock.used_blocks = fSuperBlock.num_blocks; 469 //gErrors++; 470 } 471 472 return B_OK; 473} 474 475 476status_t 477Disk::DetermineBlockSize() 478{ 479 // scan for about 500 inodes to determine the disk's block size 480 481 // min. block bitmap size (in bytes, rounded to a 1024 boundary) 482 // root_block_size + (num_blocks / bits_per_block) * block_size 483 off_t offset = 1024 + divide_roundup(fSize / 1024,8 * 1024) * 1024; 484 485 off_t inodesFound = 0; 486 char buffer[1024]; 487 bfs_inode *inode = (bfs_inode *)buffer; 488 // valid block sizes from 1024 to 32768 bytes 489 int32 blockSizeCounter[6] = {0}; 490 status_t status = B_OK; 491 492 // read a quarter of the drive at maximum 493 for (; offset < (fSize >> 2); offset += 1024) { 494 if (fBufferedFile->ReadAt(offset, buffer, sizeof(buffer)) < B_OK) { 495 fprintf(stderr, "could not read from device (offset = %Ld, " 496 "size = %ld)!\n", offset, sizeof(buffer)); 497 status = B_IO_ERROR; 498 break; 499 } 500 501 if (inode->magic1 != INODE_MAGIC1 502 || inode->inode_size != 1024 503 && inode->inode_size != 2048 504 && inode->inode_size != 4096 505 && inode->inode_size != 8192) 506 continue; 507 508 inodesFound++; 509 510 // update block size counter 511 for (int i = 0;i < 6;i++) 512 if ((1 << (i + 10)) == inode->inode_size) 513 blockSizeCounter[i]++; 514 515 int32 count = 0; 516 for (int32 i = 0;i < 6;i++) 517 if (blockSizeCounter[i]) 518 count++; 519 520 // do we have a clear winner at 100 inodes? 521 // if not, break at 500 inodes 522 if (inodesFound >= MAX_BLOCK_SIZE_INODES 523 || (inodesFound >= MIN_BLOCK_SIZE_INODES && count == 1)) 524 break; 525 } 526 527 // find the safest bet 528 int32 maxCounter = -1; 529 int32 maxIndex = 0; 530 for (int32 i = 0; i < 6; i++) { 531 if (maxCounter < blockSizeCounter[i]) { 532 maxIndex = i; 533 maxCounter = blockSizeCounter[i]; 534 } 535 } 536 fSuperBlock.block_size = (1 << (maxIndex + 10)); 537 538 return status; 539} 540 541 542status_t 543Disk::GetNextSpecialInode(char *buffer, off_t *_offset, off_t end, 544 bool skipAfterValidInode = false) 545{ 546 off_t offset = *_offset; 547 if (end == offset) 548 end++; 549 550 bfs_inode *inode = (bfs_inode *)buffer; 551 552 for (; offset < end; offset += BlockSize()) { 553 if (fBufferedFile->ReadAt(offset, buffer, 1024) < B_OK) { 554 fprintf(stderr,"could not read from device (offset = %Ld, size = %d)!\n",offset,1024); 555 *_offset = offset; 556 return B_IO_ERROR; 557 } 558 559 if (inode->magic1 != INODE_MAGIC1 560 || inode->inode_size != fSuperBlock.inode_size) 561 continue; 562 563 // can compute allocation group only for inodes which are 564 // a) not in the first allocation group 565 // b) not in the log area 566 567 if (inode->inode_num.allocation_group > 0 568 && offset >= (BlockSize() * (fLogStart + LogSize()))) { 569 fValidBlockRun = inode->inode_num; 570 fValidOffset = offset; 571 572 if (skipAfterValidInode) 573 return B_OK; 574 } 575 576 // is the inode a special root inode (parent == self)? 577 578 if (!memcmp(&inode->parent, &inode->inode_num, sizeof(inode_addr))) { 579 printf("\t special inode found at %Ld\n", offset); 580 581 *_offset = offset; 582 return B_OK; 583 } 584 } 585 *_offset = offset; 586 return B_ENTRY_NOT_FOUND; 587} 588 589 590void 591Disk::SaveInode(bfs_inode *inode, bool *indices, bfs_inode *indexDir, 592 bool *root, bfs_inode *rootDir) 593{ 594 if ((inode->mode & S_INDEX_DIR) == 0) { 595 *root = true; 596 printf("\troot node found!\n"); 597 if (inode->inode_num.allocation_group != 8 598 || inode->inode_num.start != 0 599 || inode->inode_num.length != 1) 600 printf("WARNING: root node has unexpected position: (ag = %ld, " 601 "start = %d, length = %d)\n", inode->inode_num.allocation_group, 602 inode->inode_num.start, inode->inode_num.length); 603 if (rootDir) 604 memcpy(rootDir, inode, sizeof(bfs_inode)); 605 } else if (inode->mode & S_INDEX_DIR) { 606 *indices = true; 607 printf("\tindices node found!\n"); 608 if (indexDir) 609 memcpy(indexDir, inode, sizeof(bfs_inode)); 610 } 611// if (gDumpIndexRootNode) 612// dump_inode(inode); 613} 614 615 616status_t 617Disk::ScanForIndexAndRoot(bfs_inode *indexDir,bfs_inode *rootDir) 618{ 619 memset(rootDir,0,sizeof(bfs_inode)); 620 memset(indexDir,0,sizeof(bfs_inode)); 621 622 bool indices = false,root = false; 623 char buffer[1024]; 624 bfs_inode *inode = (bfs_inode *)buffer; 625 626 // The problem here is that we don't want to find copies of the 627 // inodes in the log. 628 // The first offset where a root node can be is therefore the 629 // first allocation group with a block size of 1024, and 16384 630 // blocks per ag; that should be relatively save. 631 632 // search for the indices inode, start reading from log size + boot block size 633 off_t offset = (fLogStart + LogSize()) * BlockSize(); 634 if (GetNextSpecialInode(buffer,&offset,offset + 65536LL * BlockSize()) == B_OK) 635 SaveInode(inode,&indices,indexDir,&root,rootDir); 636 637 if (!indices) { 638 fputs("ERROR: no indices node found!\n",stderr); 639 //gErrors++; 640 } 641 642 // search common places for root node, iterating from allocation group 643 // size from 1024 to 65536 644 for (off_t start = 8LL * 1024 * BlockSize();start <= 8LL * 65536 * BlockSize();start <<= 1) { 645 if (start < fLogStart) 646 continue; 647 648 off_t commonOffset = start; 649 if (GetNextSpecialInode(buffer, &commonOffset, commonOffset) == B_OK) { 650 SaveInode(inode, &indices, indexDir, &root, rootDir); 651 if (root) 652 break; 653 } 654 } 655 656 if (!root) { 657 printf("WARNING: Could not find root node at common places!\n"); 658 printf("\tScanning log area for root node\n"); 659 660 off_t logOffset = ToOffset(fSuperBlock.log_blocks); 661 if (GetNextSpecialInode(buffer,&logOffset,logOffset + LogSize() * BlockSize()) == B_OK) 662 { 663 SaveInode(inode,&indices,indexDir,&root,rootDir); 664 665 printf("root node at: 0x%Lx (DiskProbe)\n",logOffset / 512); 666 //fBufferedFile->ReadAt(logOffset + BlockSize(),buffer,1024); 667 //if (*(uint32 *)buffer == BPLUSTREE_MAGIC) 668 //{ 669 // puts("\t\tnext block in log contains a bplustree!"); 670 //} 671 } 672 } 673 674 /*if (!root) 675 { 676 char txt[64]; 677 printf("Should I perform a deeper search (that will take some time) (Y/N) [N]? "); 678 gets(txt); 679 680 if (!strcasecmp("y",txt)) 681 { 682 // search not so common places for the root node (all places) 683 684 if (indices) 685 offset += BlockSize(); // the block after the indices inode 686 else 687 offset = (fLogStart + 1) * BlockSize(); 688 689 if (GetNextSpecialInode(buffer,&offset,65536LL * 16 * BlockSize()) == B_OK) 690 SaveInode(inode,&indices,indexDir,&root,rootDir); 691 } 692 }*/ 693 if (root) 694 return B_OK; 695 696 return B_ERROR; 697} 698 699 700// #pragma mark - BPositionIO methods 701 702 703ssize_t 704Disk::Read(void *buffer, size_t size) 705{ 706 return fBufferedFile->Read(buffer, size); 707} 708 709 710ssize_t 711Disk::Write(const void *buffer, size_t size) 712{ 713 return fBufferedFile->Write(buffer, size); 714} 715 716 717ssize_t 718Disk::ReadAt(off_t pos, void *buffer, size_t size) 719{ 720 return fBufferedFile->ReadAt(pos + fRawDiskOffset, buffer, size); 721} 722 723 724ssize_t 725Disk::WriteAt(off_t pos, const void *buffer, size_t size) 726{ 727 return fBufferedFile->WriteAt(pos + fRawDiskOffset, buffer, size); 728} 729 730 731off_t 732Disk::Seek(off_t position, uint32 seekMode) 733{ 734 // ToDo: only correct for seekMode == SEEK_SET, right?? 735 if (seekMode != SEEK_SET) 736 puts("OH NO, I AM BROKEN!"); 737 return fBufferedFile->Seek(position + fRawDiskOffset, seekMode); 738} 739 740 741off_t 742Disk::Position() const 743{ 744 return fBufferedFile->Position() - fRawDiskOffset; 745} 746 747 748status_t 749Disk::SetSize(off_t /*size*/) 750{ 751 // SetSize() is not supported 752 return B_ERROR; 753} 754 755