1 /* 2 * Copyright (c) 2001-2008 pinc Software. All Rights Reserved. 3 */ 4 5 //! Handles BFS superblock, disk access etc. 6 7 #include "Disk.h" 8 #include "dump.h" 9 10 #include <Drivers.h> 11 #include <File.h> 12 #include <Entry.h> 13 #include <List.h> 14 #include <fs_info.h> 15 16 #include <stdlib.h> 17 #include <stdio.h> 18 #include <string.h> 19 #include <unistd.h> 20 #include <ctype.h> 21 22 23 #define MIN_BLOCK_SIZE_INODES 50 24 #define MAX_BLOCK_SIZE_INODES 500 25 26 27 struct bfs_disk_info { 28 off_t offset; 29 disk_super_block super_block; 30 }; 31 32 33 class CacheableBlockRun : public BlockRunCache::Cacheable { 34 public: 35 CacheableBlockRun(block_run run,uint8 *data) 36 : 37 fRun(run), 38 fData(data) 39 { 40 } 41 42 virtual ~CacheableBlockRun() 43 { 44 free(fData); 45 } 46 47 virtual bool Equals(block_run run) 48 { 49 return run == fRun; 50 } 51 52 void SetData(uint8 *data) 53 { 54 fData = data; 55 } 56 57 uint8 *Data() 58 { 59 return fData; 60 } 61 62 protected: 63 block_run fRun; 64 uint8 *fData; 65 }; 66 67 68 BlockRunCache::BlockRunCache(Disk *disk) 69 : Cache<block_run>(), 70 fDisk(disk) 71 { 72 } 73 74 75 Cache<block_run>::Cacheable *BlockRunCache::NewCacheable(block_run run) 76 { 77 ssize_t length = (int32)run.length << fDisk->BlockShift(); 78 79 void *buffer = malloc(length); 80 if (buffer == NULL) 81 return NULL; 82 83 ssize_t read = fDisk->ReadAt(fDisk->ToOffset(run),buffer,length); 84 if (read < length) { 85 free(buffer); 86 return NULL; 87 } 88 89 return new CacheableBlockRun(run,(uint8 *)buffer); 90 } 91 92 93 // #pragma mark - 94 95 96 Disk::Disk(const char *deviceName, bool rawMode, off_t start, off_t stop) 97 : 98 fBufferedFile(NULL), 99 fRawDiskOffset(0), 100 fSize(0LL), 101 fCache(this), 102 fRawMode(rawMode) 103 { 104 BEntry entry(deviceName); 105 fPath.SetTo(deviceName); 106 107 if (entry.IsDirectory()) { 108 dev_t on = dev_for_path(deviceName); 109 fs_info info; 110 if (fs_stat_dev(on, &info) != B_OK) 111 return; 112 113 fPath.SetTo(info.device_name); 114 deviceName = fPath.Path(); 115 } 116 117 if (!rawMode && !strncmp(deviceName, "/dev/", 5) 118 && !strcmp(deviceName + strlen(deviceName) - 3, "raw")) 119 fprintf(stderr, "Raw mode not selected, but raw device specified.\n"); 120 121 if (fFile.SetTo(deviceName, B_READ_WRITE) < B_OK) { 122 //fprintf(stderr,"Could not open file: %s\n",strerror(fFile.InitCheck())); 123 return; 124 } 125 fBufferedFile = new BBufferIO(&fFile, 1024 * 1024, false); 126 127 int device = open(deviceName, O_RDONLY); 128 if (device < B_OK) { 129 //fprintf(stderr,"Could not open device\n"); 130 return; 131 } 132 133 partition_info partitionInfo; 134 device_geometry geometry; 135 if (ioctl(device, B_GET_PARTITION_INFO, &partitionInfo, 136 sizeof(partition_info)) == 0) { 137 //if (gDumpPartitionInfo) 138 // dump_partition_info(&partitionInfo); 139 fSize = partitionInfo.size; 140 } else if (ioctl(device, B_GET_GEOMETRY, &geometry, sizeof(device_geometry)) 141 == 0) { 142 fSize = (off_t)geometry.cylinder_count * geometry.sectors_per_track 143 * geometry.head_count * geometry.bytes_per_sector; 144 } else { 145 fprintf(stderr,"Disk: Could not get partition info.\n Use file size as partition size\n"); 146 fFile.GetSize(&fSize); 147 } 148 close(device); 149 150 if (fSize == 0LL) { 151 fprintf(stderr,"Disk: Invalid file size (%" B_PRIdOFF " bytes)!\n", 152 fSize); 153 } 154 155 if (rawMode && ScanForSuperBlock(start, stop) < B_OK) { 156 fFile.Unset(); 157 return; 158 } 159 160 if (fBufferedFile->ReadAt(512 + fRawDiskOffset, &fSuperBlock, 161 sizeof(disk_super_block)) < 1) 162 fprintf(stderr,"Disk: Could not read superblock\n"); 163 164 //dump_super_block(&fSuperBlock); 165 } 166 167 168 Disk::~Disk() 169 { 170 delete fBufferedFile; 171 } 172 173 174 status_t Disk::InitCheck() 175 { 176 status_t status = fFile.InitCheck(); 177 if (status == B_OK) 178 return fSize == 0LL ? B_ERROR : B_OK; 179 180 return status; 181 } 182 183 184 block_run Disk::ToBlockRun(off_t start, int16 length) const 185 { 186 block_run run; 187 run.allocation_group = start >> fSuperBlock.ag_shift; 188 run.start = start & ((1UL << fSuperBlock.ag_shift) - 1); 189 run.length = length; 190 191 return run; 192 } 193 194 195 off_t Disk::LogSize() const 196 { 197 if (fSuperBlock.num_blocks >= 4096) 198 return 2048; 199 200 return 512; 201 } 202 203 204 uint8 *Disk::ReadBlockRun(block_run run) 205 { 206 CacheableBlockRun *entry = (CacheableBlockRun *)fCache.Get(run); 207 if (entry) 208 return entry->Data(); 209 210 return NULL; 211 } 212 213 214 status_t 215 Disk::DumpBootBlockToFile() 216 { 217 BFile file("/boot/home/bootblock.old", B_READ_WRITE | B_CREATE_FILE); 218 if (file.InitCheck() < B_OK) 219 return file.InitCheck(); 220 221 char buffer[BlockSize()]; 222 ssize_t bytes = ReadAt(0, buffer, BlockSize()); 223 if (bytes < (int32)BlockSize()) 224 return bytes < B_OK ? bytes : B_ERROR; 225 226 file.Write(buffer, BlockSize()); 227 228 // initialize buffer 229 memset(buffer, 0, BlockSize()); 230 memcpy(buffer + 512, &fSuperBlock, sizeof(disk_super_block)); 231 232 // write buffer to disk 233 WriteAt(0, buffer, BlockSize()); 234 235 return B_OK; 236 } 237 238 239 // #pragma mark - Superblock recovery methods 240 241 242 status_t 243 Disk::ScanForSuperBlock(off_t start, off_t stop) 244 { 245 printf("Disk size %" B_PRIdOFF " bytes, %.2f GB\n", fSize, 1.0 * fSize 246 / (1024*1024*1024)); 247 248 uint32 blockSize = 4096; 249 char buffer[blockSize + 1024]; 250 251 if (stop == -1) 252 stop = fSize; 253 254 char escape[3] = {0x1b, '[', 0}; 255 256 BList superBlocks; 257 258 printf("Scanning Disk from %" B_PRIdOFF " to %" B_PRIdOFF "\n", start, 259 stop); 260 261 for (off_t offset = start; offset < stop; offset += blockSize) 262 { 263 if (((offset-start) % (blockSize * 100)) == 0) { 264 printf(" %12" B_PRIdOFF ", %.2f GB %s1A\n", offset, 265 1.0 * offset / (1024*1024*1024),escape); 266 } 267 268 ssize_t bytes = fBufferedFile->ReadAt(offset, buffer, blockSize + 1024); 269 if (bytes < B_OK) 270 { 271 fprintf(stderr,"Could not read from device: %s\n", strerror(bytes)); 272 return -1; 273 } 274 275 for (uint32 i = 0;i < blockSize - 2;i++) 276 { 277 disk_super_block *super = (disk_super_block *)&buffer[i]; 278 279 if (super->magic1 == (int32)SUPER_BLOCK_MAGIC1 280 && super->magic2 == (int32)SUPER_BLOCK_MAGIC2 281 && super->magic3 == (int32)SUPER_BLOCK_MAGIC3) 282 { 283 printf("\n(%" B_PRId32 ") *** BFS superblock found at: %" 284 B_PRIdOFF "\n", superBlocks.CountItems() + 1, offset); 285 dump_super_block(super); 286 287 // add a copy of the superblock to the list 288 bfs_disk_info *info = (bfs_disk_info *)malloc(sizeof(bfs_disk_info)); 289 if (info == NULL) 290 return B_NO_MEMORY; 291 292 memcpy(&info->super_block, super, sizeof(disk_super_block)); 293 info->offset = offset + i - 512; 294 /* location off the BFS superblock is 512 bytes after the partition start */ 295 superBlocks.AddItem(info); 296 } 297 } 298 } 299 300 if (superBlocks.CountItems() == 0) { 301 puts("\nCouldn't find any BFS superblocks!"); 302 return B_ENTRY_NOT_FOUND; 303 } 304 305 // Let the user decide which block to use 306 307 puts("\n\nThe following disks were found:"); 308 309 for (int32 i = 0; i < superBlocks.CountItems(); i++) { 310 bfs_disk_info *info = (bfs_disk_info *)superBlocks.ItemAt(i); 311 312 printf("%" B_PRId32 ") %s, offset %" B_PRIdOFF ", size %g GB (%svalid)" 313 "\n", i + 1, info->super_block.name, info->offset, 314 1.0 * info->super_block.num_blocks * info->super_block.block_size 315 / (1024*1024*1024), 316 ValidateSuperBlock(info->super_block) < B_OK ? "in" : ""); 317 } 318 319 char answer[16]; 320 printf("\nChoose one (by number): "); 321 fflush(stdout); 322 323 fgets(answer, 15, stdin); 324 int32 index = atol(answer); 325 326 if (index > superBlocks.CountItems() || index < 1) { 327 puts("No disk there... exiting."); 328 return B_BAD_VALUE; 329 } 330 331 bfs_disk_info *info = (bfs_disk_info *)superBlocks.ItemAt(index - 1); 332 333 // ToDo: free the other disk infos 334 335 fRawDiskOffset = info->offset; 336 fBufferedFile->Seek(fRawDiskOffset, SEEK_SET); 337 338 if (ValidateSuperBlock(info->super_block)) 339 fSize = info->super_block.block_size * info->super_block.block_size; 340 else { 341 // just make it open-end 342 fSize -= fRawDiskOffset; 343 } 344 345 return B_OK; 346 } 347 348 349 status_t 350 Disk::ValidateSuperBlock(disk_super_block &superBlock) 351 { 352 if (superBlock.magic1 != (int32)SUPER_BLOCK_MAGIC1 353 || superBlock.magic2 != (int32)SUPER_BLOCK_MAGIC2 354 || superBlock.magic3 != (int32)SUPER_BLOCK_MAGIC3 355 || (int32)superBlock.block_size != superBlock.inode_size 356 || superBlock.fs_byte_order != SUPER_BLOCK_FS_LENDIAN 357 || (1UL << superBlock.block_shift) != superBlock.block_size 358 || superBlock.num_ags < 1 359 || superBlock.ag_shift < 1 360 || superBlock.blocks_per_ag < 1 361 || superBlock.num_blocks < 10 362 || superBlock.used_blocks > superBlock.num_blocks 363 || superBlock.num_ags != divide_roundup(superBlock.num_blocks, 364 1L << superBlock.ag_shift)) 365 return B_ERROR; 366 367 return B_OK; 368 } 369 370 371 status_t 372 Disk::ValidateSuperBlock() 373 { 374 if (ValidateSuperBlock(fSuperBlock) < B_OK) 375 return B_ERROR; 376 377 fBitmap.SetTo(this); 378 379 return B_OK; 380 } 381 382 383 status_t 384 Disk::RecreateSuperBlock() 385 { 386 memset(&fSuperBlock, 0, sizeof(disk_super_block)); 387 388 puts("\n*** Determine block size"); 389 390 status_t status = DetermineBlockSize(); 391 if (status < B_OK) 392 return status; 393 394 printf("\tblock size = %" B_PRId32 "\n", BlockSize()); 395 396 strcpy(fSuperBlock.name,"recovered"); 397 fSuperBlock.magic1 = SUPER_BLOCK_MAGIC1; 398 fSuperBlock.fs_byte_order = SUPER_BLOCK_FS_LENDIAN; 399 fSuperBlock.block_shift = get_shift(BlockSize()); 400 fSuperBlock.num_blocks = fSize / BlockSize(); // only full blocks 401 fSuperBlock.inode_size = BlockSize(); 402 fSuperBlock.magic2 = SUPER_BLOCK_MAGIC2; 403 404 fSuperBlock.flags = SUPER_BLOCK_CLEAN; 405 406 // size of the block bitmap + root block 407 fLogStart = 1 + divide_roundup(fSuperBlock.num_blocks,BlockSize() * 8); 408 409 // set it anywhere in the log 410 fSuperBlock.log_start = fLogStart + (LogSize() >> 1); 411 fSuperBlock.log_end = fSuperBlock.log_start; 412 413 // 414 // scan for indices and root inode 415 // 416 417 puts("\n*** Scanning for indices and root node..."); 418 fValidOffset = 0LL; 419 bfs_inode indexDir; 420 bfs_inode rootDir; 421 if (ScanForIndexAndRoot(&indexDir,&rootDir) < B_OK) { 422 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"); 423 rootDir.inode_num.allocation_group = 8; 424 rootDir.inode_num.start = 0; 425 rootDir.inode_num.length = 1; 426 //gErrors++; 427 } 428 if (fValidOffset == 0LL) { 429 printf("No valid inode found so far - perform search.\n"); 430 431 off_t offset = 8LL * 65536 * BlockSize(); 432 char buffer[1024]; 433 GetNextSpecialInode(buffer,&offset,offset + 32LL * 65536 * BlockSize(),true); 434 435 if (fValidOffset == 0LL) 436 { 437 fprintf(stderr,"FATAL ERROR: Could not find valid inode!\n"); 438 return B_ERROR; 439 } 440 } 441 442 // calculate allocation group size 443 444 int32 allocationGroupSize = (fValidOffset - fValidBlockRun.start 445 * BlockSize() 446 + BlockSize() - 1) / (BlockSize() * fValidBlockRun.allocation_group); 447 448 fSuperBlock.blocks_per_ag = allocationGroupSize / (BlockSize() << 3); 449 fSuperBlock.ag_shift = get_shift(allocationGroupSize); 450 fSuperBlock.num_ags = divide_roundup(fSuperBlock.num_blocks,allocationGroupSize); 451 452 // calculate rest of log area 453 454 fSuperBlock.log_blocks.allocation_group = fLogStart / allocationGroupSize; 455 fSuperBlock.log_blocks.start = fLogStart - fSuperBlock.log_blocks.allocation_group * allocationGroupSize; 456 fSuperBlock.log_blocks.length = LogSize(); // assumed length of 2048 blocks 457 458 if (fLogStart != ((indexDir.inode_num.allocation_group 459 << fSuperBlock.ag_shift) + indexDir.inode_num.start - LogSize())) { 460 fprintf(stderr,"ERROR: start of logging area doesn't fit assumed value " 461 "(%" B_PRIdOFF " blocks before indices)!\n", LogSize()); 462 //gErrors++; 463 } 464 465 fSuperBlock.magic3 = SUPER_BLOCK_MAGIC3; 466 fSuperBlock.root_dir = rootDir.inode_num; 467 fSuperBlock.indices = indexDir.inode_num; 468 469 // calculate used blocks (from block bitmap) 470 471 fBitmap.SetTo(this); 472 if (fBitmap.UsedBlocks()) 473 fSuperBlock.used_blocks = fBitmap.UsedBlocks(); 474 else { 475 fprintf(stderr,"ERROR: couldn't calculate number of used blocks, marking all blocks as used!\n"); 476 fSuperBlock.used_blocks = fSuperBlock.num_blocks; 477 //gErrors++; 478 } 479 480 return B_OK; 481 } 482 483 484 status_t 485 Disk::DetermineBlockSize() 486 { 487 // scan for about 500 inodes to determine the disk's block size 488 489 // min. block bitmap size (in bytes, rounded to a 1024 boundary) 490 // root_block_size + (num_blocks / bits_per_block) * block_size 491 off_t offset = 1024 + divide_roundup(fSize / 1024,8 * 1024) * 1024; 492 493 off_t inodesFound = 0; 494 char buffer[1024]; 495 bfs_inode *inode = (bfs_inode *)buffer; 496 // valid block sizes from 1024 to 32768 bytes 497 int32 blockSizeCounter[6] = {0}; 498 status_t status = B_OK; 499 500 // read a quarter of the drive at maximum 501 for (; offset < (fSize >> 2); offset += 1024) { 502 if (fBufferedFile->ReadAt(offset, buffer, sizeof(buffer)) < B_OK) { 503 fprintf(stderr, "could not read from device (offset = %" B_PRIdOFF 504 ", size = %ld)!\n", offset, sizeof(buffer)); 505 status = B_IO_ERROR; 506 break; 507 } 508 509 if (inode->magic1 != INODE_MAGIC1 510 || inode->inode_size != 1024 511 && inode->inode_size != 2048 512 && inode->inode_size != 4096 513 && inode->inode_size != 8192) 514 continue; 515 516 inodesFound++; 517 518 // update block size counter 519 for (int i = 0;i < 6;i++) 520 if ((1 << (i + 10)) == inode->inode_size) 521 blockSizeCounter[i]++; 522 523 int32 count = 0; 524 for (int32 i = 0;i < 6;i++) 525 if (blockSizeCounter[i]) 526 count++; 527 528 // do we have a clear winner at 100 inodes? 529 // if not, break at 500 inodes 530 if (inodesFound >= MAX_BLOCK_SIZE_INODES 531 || (inodesFound >= MIN_BLOCK_SIZE_INODES && count == 1)) 532 break; 533 } 534 535 // find the safest bet 536 int32 maxCounter = -1; 537 int32 maxIndex = 0; 538 for (int32 i = 0; i < 6; i++) { 539 if (maxCounter < blockSizeCounter[i]) { 540 maxIndex = i; 541 maxCounter = blockSizeCounter[i]; 542 } 543 } 544 fSuperBlock.block_size = (1 << (maxIndex + 10)); 545 546 return status; 547 } 548 549 550 status_t 551 Disk::GetNextSpecialInode(char *buffer, off_t *_offset, off_t end, 552 bool skipAfterValidInode = false) 553 { 554 off_t offset = *_offset; 555 if (end == offset) 556 end++; 557 558 bfs_inode *inode = (bfs_inode *)buffer; 559 560 for (; offset < end; offset += BlockSize()) { 561 if (fBufferedFile->ReadAt(offset, buffer, 1024) < B_OK) { 562 fprintf(stderr,"could not read from device (offset = %" B_PRIdOFF 563 ", size = %d)!\n", offset, 1024); 564 *_offset = offset; 565 return B_IO_ERROR; 566 } 567 568 if (inode->magic1 != INODE_MAGIC1 569 || inode->inode_size != fSuperBlock.inode_size) 570 continue; 571 572 // can compute allocation group only for inodes which are 573 // a) not in the first allocation group 574 // b) not in the log area 575 576 if (inode->inode_num.allocation_group > 0 577 && offset >= (BlockSize() * (fLogStart + LogSize()))) { 578 fValidBlockRun = inode->inode_num; 579 fValidOffset = offset; 580 581 if (skipAfterValidInode) 582 return B_OK; 583 } 584 585 // is the inode a special root inode (parent == self)? 586 587 if (!memcmp(&inode->parent, &inode->inode_num, sizeof(inode_addr))) { 588 printf("\t special inode found at %" B_PRIdOFF "\n", offset); 589 590 *_offset = offset; 591 return B_OK; 592 } 593 } 594 *_offset = offset; 595 return B_ENTRY_NOT_FOUND; 596 } 597 598 599 void 600 Disk::SaveInode(bfs_inode *inode, bool *indices, bfs_inode *indexDir, 601 bool *root, bfs_inode *rootDir) 602 { 603 if ((inode->mode & S_INDEX_DIR) == 0) { 604 *root = true; 605 printf("\troot node found!\n"); 606 if (inode->inode_num.allocation_group != 8 607 || inode->inode_num.start != 0 608 || inode->inode_num.length != 1) { 609 printf("WARNING: root node has unexpected position: (ag = %" 610 B_PRId32 ", start = %d, length = %d)\n", 611 inode->inode_num.allocation_group, 612 inode->inode_num.start, inode->inode_num.length); 613 } 614 if (rootDir) 615 memcpy(rootDir, inode, sizeof(bfs_inode)); 616 } else if (inode->mode & S_INDEX_DIR) { 617 *indices = true; 618 printf("\tindices node found!\n"); 619 if (indexDir) 620 memcpy(indexDir, inode, sizeof(bfs_inode)); 621 } 622 // if (gDumpIndexRootNode) 623 // dump_inode(inode); 624 } 625 626 627 status_t 628 Disk::ScanForIndexAndRoot(bfs_inode *indexDir,bfs_inode *rootDir) 629 { 630 memset(rootDir,0,sizeof(bfs_inode)); 631 memset(indexDir,0,sizeof(bfs_inode)); 632 633 bool indices = false,root = false; 634 char buffer[1024]; 635 bfs_inode *inode = (bfs_inode *)buffer; 636 637 // The problem here is that we don't want to find copies of the 638 // inodes in the log. 639 // The first offset where a root node can be is therefore the 640 // first allocation group with a block size of 1024, and 16384 641 // blocks per ag; that should be relatively save. 642 643 // search for the indices inode, start reading from log size + boot block size 644 off_t offset = (fLogStart + LogSize()) * BlockSize(); 645 if (GetNextSpecialInode(buffer,&offset,offset + 65536LL * BlockSize()) == B_OK) 646 SaveInode(inode,&indices,indexDir,&root,rootDir); 647 648 if (!indices) { 649 fputs("ERROR: no indices node found!\n",stderr); 650 //gErrors++; 651 } 652 653 // search common places for root node, iterating from allocation group 654 // size from 1024 to 65536 655 for (off_t start = 8LL * 1024 * BlockSize();start <= 8LL * 65536 * BlockSize();start <<= 1) { 656 if (start < fLogStart) 657 continue; 658 659 off_t commonOffset = start; 660 if (GetNextSpecialInode(buffer, &commonOffset, commonOffset) == B_OK) { 661 SaveInode(inode, &indices, indexDir, &root, rootDir); 662 if (root) 663 break; 664 } 665 } 666 667 if (!root) { 668 printf("WARNING: Could not find root node at common places!\n"); 669 printf("\tScanning log area for root node\n"); 670 671 off_t logOffset = ToOffset(fSuperBlock.log_blocks); 672 if (GetNextSpecialInode(buffer,&logOffset,logOffset + LogSize() * BlockSize()) == B_OK) 673 { 674 SaveInode(inode,&indices,indexDir,&root,rootDir); 675 676 printf("root node at: 0x%" B_PRIxOFF " (DiskProbe)\n", 677 logOffset / 512); 678 //fBufferedFile->ReadAt(logOffset + BlockSize(),buffer,1024); 679 //if (*(uint32 *)buffer == BPLUSTREE_MAGIC) 680 //{ 681 // puts("\t\tnext block in log contains a bplustree!"); 682 //} 683 } 684 } 685 686 /*if (!root) 687 { 688 char txt[64]; 689 printf("Should I perform a deeper search (that will take some time) (Y/N) [N]? "); 690 gets(txt); 691 692 if (!strcasecmp("y",txt)) 693 { 694 // search not so common places for the root node (all places) 695 696 if (indices) 697 offset += BlockSize(); // the block after the indices inode 698 else 699 offset = (fLogStart + 1) * BlockSize(); 700 701 if (GetNextSpecialInode(buffer,&offset,65536LL * 16 * BlockSize()) == B_OK) 702 SaveInode(inode,&indices,indexDir,&root,rootDir); 703 } 704 }*/ 705 if (root) 706 return B_OK; 707 708 return B_ERROR; 709 } 710 711 712 // #pragma mark - BPositionIO methods 713 714 715 ssize_t 716 Disk::Read(void *buffer, size_t size) 717 { 718 return fBufferedFile->Read(buffer, size); 719 } 720 721 722 ssize_t 723 Disk::Write(const void *buffer, size_t size) 724 { 725 return fBufferedFile->Write(buffer, size); 726 } 727 728 729 ssize_t 730 Disk::ReadAt(off_t pos, void *buffer, size_t size) 731 { 732 return fBufferedFile->ReadAt(pos + fRawDiskOffset, buffer, size); 733 } 734 735 736 ssize_t 737 Disk::WriteAt(off_t pos, const void *buffer, size_t size) 738 { 739 return fBufferedFile->WriteAt(pos + fRawDiskOffset, buffer, size); 740 } 741 742 743 off_t 744 Disk::Seek(off_t position, uint32 seekMode) 745 { 746 // ToDo: only correct for seekMode == SEEK_SET, right?? 747 if (seekMode != SEEK_SET) 748 puts("OH NO, I AM BROKEN!"); 749 return fBufferedFile->Seek(position + fRawDiskOffset, seekMode); 750 } 751 752 753 off_t 754 Disk::Position() const 755 { 756 return fBufferedFile->Position() - fRawDiskOffset; 757 } 758 759 760 status_t 761 Disk::SetSize(off_t /*size*/) 762 { 763 // SetSize() is not supported 764 return B_ERROR; 765 } 766 767