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