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