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