xref: /haiku/src/bin/bfs_tools/lib/Disk.cpp (revision b617a7b410c05275effb95f4b2f5608359d9b7b9)
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