xref: /haiku/src/bin/bfs_tools/lib/Disk.cpp (revision 8f087d87f9d334aaf43de5fec4a6253918332eae)
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:
CacheableBlockRun(block_run run,uint8 * data)36 		CacheableBlockRun(block_run run,uint8 *data)
37 			:
38 			fRun(run),
39 			fData(data)
40 		{
41 		}
42 
~CacheableBlockRun()43 		virtual ~CacheableBlockRun()
44 		{
45 			free(fData);
46 		}
47 
Equals(block_run run)48 		virtual bool Equals(block_run run)
49 		{
50 			return run == fRun;
51 		}
52 
SetData(uint8 * data)53 		void SetData(uint8 *data)
54 		{
55 			fData = data;
56 		}
57 
Data()58 		uint8 *Data()
59 		{
60 			return fData;
61 		}
62 
63 	protected:
64 		block_run	fRun;
65 		uint8		*fData;
66 };
67 
68 
BlockRunCache(Disk * disk)69 BlockRunCache::BlockRunCache(Disk *disk)
70 	: Cache<block_run>(),
71 	fDisk(disk)
72 {
73 }
74 
75 
NewCacheable(block_run run)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 
Disk(const char * deviceName,bool rawMode,off_t start,off_t stop)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 
~Disk()174 Disk::~Disk()
175 {
176 	delete fBufferedFile;
177 }
178 
179 
InitCheck()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 
ToBlockRun(off_t start,int16 length) const190 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 
LogSize() const201 off_t Disk::LogSize() const
202 {
203 	if (fSuperBlock.num_blocks >= 4096)
204 		return 2048;
205 
206 	return 512;
207 }
208 
209 
ReadBlockRun(block_run run)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
DumpBootBlockToFile()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
ScanForSuperBlock(off_t start,off_t stop)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
ValidateSuperBlock(disk_super_block & superBlock)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
ValidateSuperBlock()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
RecreateSuperBlock()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
DetermineBlockSize()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
GetNextSpecialInode(char * buffer,off_t * _offset,off_t end,bool skipAfterValidInode=false)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
SaveInode(bfs_inode * inode,bool * indices,bfs_inode * indexDir,bool * root,bfs_inode * rootDir)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
ScanForIndexAndRoot(bfs_inode * indexDir,bfs_inode * rootDir)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
Read(void * buffer,size_t size)722 Disk::Read(void *buffer, size_t size)
723 {
724 	return fBufferedFile->Read(buffer, size);
725 }
726 
727 
728 ssize_t
Write(const void * buffer,size_t size)729 Disk::Write(const void *buffer, size_t size)
730 {
731 	return fBufferedFile->Write(buffer, size);
732 }
733 
734 
735 ssize_t
ReadAt(off_t pos,void * buffer,size_t size)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
WriteAt(off_t pos,const void * buffer,size_t size)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
Seek(off_t position,uint32 seekMode)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
Position() const760 Disk::Position() const
761 {
762 	return fBufferedFile->Position() - fRawDiskOffset;
763 }
764 
765 
766 status_t
SetSize(off_t)767 Disk::SetSize(off_t /*size*/)
768 {
769 	// SetSize() is not supported
770 	return B_ERROR;
771 }
772 
773