RemoteDrawingEngine: Reduce RP_READ_BITMAP result timeout.
[haiku.git] / src / bin / bfs_tools / bfsinfo.cpp
bloba1013567de45286cd98b874f5a3b36b5b9e0c050
1 /*
2 * Copyright 2001-2010 pinc Software. All Rights Reserved.
3 */
6 //! Dumps various information about BFS volumes.
9 #include "Disk.h"
10 #include "BPlusTree.h"
11 #include "Inode.h"
12 #include "dump.h"
14 #include <stdio.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <ctype.h>
20 void
21 dump_bplustree(Disk &disk, BPositionIO *file, off_t size, bool hexDump)
23 uint8 *buffer = (uint8 *)malloc(size);
24 if (buffer == NULL) {
25 puts("no buffer");
26 return;
29 if (file->ReadAt(0, buffer, size) != size) {
30 puts("couldn't read whole file");
31 return;
34 bplustree_header *header = (bplustree_header *)buffer;
35 int32 nodeSize = header->node_size;
37 dump_bplustree_header(header);
39 bplustree_node *node = (bplustree_node *)(buffer + nodeSize);
40 while ((addr_t)node < (addr_t)buffer + size) {
41 printf("\n\n-------------------\n"
42 "** node at offset: %" B_PRIuADDR "\n** used: %" B_PRId32 " bytes"
43 "\n", (addr_t)node - (addr_t)buffer, node->Used());
44 dump_bplustree_node(node, header, &disk);
46 if (hexDump) {
47 putchar('\n');
48 dump_block((char *)node, header->node_size, 0);
51 node = (bplustree_node *)((addr_t)node + nodeSize);
56 void
57 dump_indirect_stream(Disk &disk, bfs_inode *node, bool showOffsets)
59 if (node->data.max_indirect_range == 0)
60 return;
62 int32 bytes = node->data.indirect.length * disk.BlockSize();
63 int32 count = bytes / sizeof(block_run);
64 block_run runs[count];
66 off_t offset = node->data.max_direct_range;
68 ssize_t bytesRead = disk.ReadAt(disk.ToOffset(node->data.indirect),
69 (uint8 *)runs, bytes);
70 if (bytesRead < bytes) {
71 fprintf(stderr, "couldn't read indirect runs: %s\n",
72 strerror(bytesRead));
73 return;
76 puts("indirect stream:");
78 for (int32 i = 0; i < count; i++) {
79 if (runs[i].IsZero())
80 return;
82 printf(" indirect[%04" B_PRId32 "] = ", i);
84 char buffer[256];
85 if (showOffsets)
86 snprintf(buffer, sizeof(buffer), " %16" B_PRIdOFF, offset);
87 else
88 buffer[0] = '\0';
90 dump_block_run("", runs[i], buffer);
92 offset += runs[i].length * disk.BlockSize();
97 void
98 dump_double_indirect_stream(Disk& disk, bfs_inode* node, bool showOffsets)
100 if (node->data.max_double_indirect_range == 0)
101 return;
103 int32 bytes = node->data.double_indirect.length * disk.BlockSize();
104 int32 count = bytes / sizeof(block_run);
105 block_run runs[count];
107 off_t offset = node->data.max_indirect_range;
109 ssize_t bytesRead = disk.ReadAt(disk.ToOffset(node->data.double_indirect),
110 (uint8*)runs, bytes);
111 if (bytesRead < bytes) {
112 fprintf(stderr, "couldn't read double indirect runs: %s\n",
113 strerror(bytesRead));
114 return;
117 puts("double indirect stream:");
119 for (int32 i = 0; i < count; i++) {
120 if (runs[i].IsZero())
121 return;
123 printf(" double_indirect[%02" B_PRId32 "] = ", i);
125 dump_block_run("", runs[i], "");
127 int32 indirectBytes = runs[i].length * disk.BlockSize();
128 int32 indirectCount = indirectBytes / sizeof(block_run);
129 block_run indirectRuns[indirectCount];
131 bytesRead = disk.ReadAt(disk.ToOffset(runs[i]), (uint8*)indirectRuns,
132 indirectBytes);
133 if (bytesRead < indirectBytes) {
134 fprintf(stderr, "couldn't read double indirect runs: %s\n",
135 strerror(bytesRead));
136 continue;
139 for (int32 j = 0; j < indirectCount; j++) {
140 if (indirectRuns[j].IsZero())
141 break;
143 printf(" [%04" B_PRId32 "] = ", j);
145 char buffer[256];
146 if (showOffsets)
147 snprintf(buffer, sizeof(buffer), " %16" B_PRIdOFF, offset);
148 else
149 buffer[0] = '\0';
151 dump_block_run("", indirectRuns[j], buffer);
153 offset += indirectRuns[j].length * disk.BlockSize();
159 void
160 list_bplustree(Disk& disk, Directory* directory, off_t size)
162 directory->Rewind();
164 char name[B_FILE_NAME_LENGTH];
165 char buffer[512];
166 uint64 count = 0;
167 block_run run;
168 while (directory->GetNextEntry(name, &run) == B_OK) {
169 snprintf(buffer, sizeof(buffer), " %s", name);
170 dump_block_run("", run, buffer);
171 count++;
174 printf("--\n%lld items.\n", count);
178 void
179 count_bplustree(Disk& disk, Directory* directory, off_t size)
181 directory->Rewind();
183 char name[B_FILE_NAME_LENGTH];
184 uint64 count = 0;
185 block_run run;
186 while (directory->GetNextEntry(name, &run) == B_OK)
187 count++;
189 printf("%lld items.\n", count);
193 block_run
194 parseBlockRun(Disk &disk, char *first, char *last)
196 char *comma;
198 if (last) {
199 return block_run::Run(atol(first), atol(last), 1);
200 } else if ((comma = strchr(first, ',')) != NULL) {
201 *comma++ = '\0';
202 return block_run::Run(atol(first), atol(comma));
205 return disk.ToBlockRun(atoll(first));
210 main(int argc, char **argv)
212 puts("Copyright (c) 2001-2010 pinc Software.");
214 if (argc < 2 || !strcmp(argv[1], "--help")) {
215 char *filename = strrchr(argv[0],'/');
216 fprintf(stderr,"usage: %s [-srib] <device> [allocation_group start]\n"
217 "\t-s\tdump superblock\n"
218 "\t-r\tdump root node\n"
219 " the following options need the allocation_group/start "
220 "parameters:\n"
221 "\t-i\tdump inode\n"
222 "\t-b\tdump b+tree\n"
223 "\t-c\tlist b+tree leaves\n"
224 "\t-c\tcount b+tree leaves\n"
225 "\t-v\tvalidate b+tree\n"
226 "\t-h\thexdump\n"
227 "\t-o\tshow disk offsets\n",
228 filename ? filename + 1 : argv[0]);
229 return -1;
232 bool dumpRootNode = false;
233 bool dumpInode = false;
234 bool dumpSuperBlock = false;
235 bool dumpBTree = false;
236 bool listBTree = false;
237 bool countBTree = false;
238 bool validateBTree = false;
239 bool dumpHex = false;
240 bool showOffsets = false;
242 while (*++argv) {
243 char *arg = *argv;
244 if (*arg == '-') {
245 while (*++arg && isalpha(*arg)) {
246 switch (*arg) {
247 case 's':
248 dumpSuperBlock = true;
249 break;
250 case 'r':
251 dumpRootNode = true;
252 break;
253 case 'i':
254 dumpInode = true;
255 break;
256 case 'b':
257 dumpBTree = true;
258 break;
259 case 'l':
260 listBTree = true;
261 break;
262 case 'c':
263 countBTree = true;
264 break;
265 case 'v':
266 validateBTree = true;
267 break;
268 case 'h':
269 dumpHex = true;
270 break;
271 case 'o':
272 showOffsets = true;
273 break;
276 } else
277 break;
280 Disk disk(argv[0]);
281 if (disk.InitCheck() < B_OK)
283 fprintf(stderr, "Could not open device or file: %s\n", strerror(disk.InitCheck()));
284 return -1;
286 putchar('\n');
288 if (!dumpSuperBlock && !dumpRootNode && !dumpInode && !dumpBTree
289 && !dumpHex && !listBTree && !countBTree) {
290 printf(" Name:\t\t\t\"%s\"\n", disk.SuperBlock()->name);
291 printf(" (disk is %s)\n\n",
292 disk.ValidateSuperBlock() == B_OK ? "valid" : "invalid!!");
293 printf(" Block Size:\t\t%" B_PRIu32 " bytes\n", disk.BlockSize());
294 printf(" Number of Blocks:\t%12" B_PRIdOFF "\t%10g MB\n",
295 disk.NumBlocks(), disk.NumBlocks() * disk.BlockSize()
296 / (1024.0*1024));
297 if (disk.BlockBitmap() != NULL) {
298 printf(" Used Blocks:\t\t%12" B_PRIdOFF "\t%10g MB\n",
299 disk.BlockBitmap()->UsedBlocks(),
300 disk.BlockBitmap()->UsedBlocks() * disk.BlockSize()
301 / (1024.0*1024));
302 printf(" Free Blocks:\t\t%12" B_PRIdOFF "\t%10g MB\n",
303 disk.BlockBitmap()->FreeBlocks(),
304 disk.BlockBitmap()->FreeBlocks() * disk.BlockSize()
305 / (1024.0*1024));
307 int32 size
308 = (disk.AllocationGroups() * disk.SuperBlock()->blocks_per_ag);
309 printf(" Bitmap Size:\t\t%" B_PRIu32 " bytes (%" B_PRId32 " blocks, %"
310 B_PRId32 " per allocation group)\n", disk.BlockSize() * size, size,
311 disk.SuperBlock()->blocks_per_ag);
312 printf(" Allocation Groups:\t%" B_PRIu32 "\n\n",
313 disk.AllocationGroups());
314 dump_block_run(" Log:\t\t\t", disk.Log());
315 printf(" (was %s)\n\n", disk.SuperBlock()->flags == SUPER_BLOCK_CLEAN
316 ? "cleanly unmounted" : "not unmounted cleanly!");
317 dump_block_run(" Root Directory:\t", disk.Root());
318 putchar('\n');
319 } else if (dumpSuperBlock) {
320 dump_super_block(disk.SuperBlock());
321 putchar('\n');
324 if (disk.ValidateSuperBlock() < B_OK) {
325 fprintf(stderr, "The disk's superblock is corrupt (or it's not a BFS "
326 "device)!\n");
327 return 0;
330 if (dumpRootNode) {
331 bfs_inode inode;
332 if (disk.ReadAt(disk.ToOffset(disk.Root()), (void *)&inode,
333 sizeof(bfs_inode)) < B_OK) {
334 fprintf(stderr,"Could not read root node from disk!\n");
335 } else {
336 puts("Root node:\n-----------------------------------------");
337 dump_inode(NULL, &inode, showOffsets);
338 dump_indirect_stream(disk, &inode, showOffsets);
339 putchar('\n');
343 char buffer[disk.BlockSize()];
344 bfs_inode* bfsInode = (bfs_inode*)buffer;
345 block_run run;
346 Inode *inode = NULL;
348 if (dumpInode || dumpBTree || dumpHex || validateBTree || listBTree
349 || countBTree) {
350 // Set the block_run to the right value (as specified on the command
351 // line)
352 if (!argv[1]) {
353 fprintf(stderr, "The -i/b/f options need the allocation group and "
354 "starting offset (or the block number) of the node to dump!\n");
355 return -1;
357 run = parseBlockRun(disk, argv[1], argv[2]);
359 if (disk.ReadAt(disk.ToOffset(run), buffer, disk.BlockSize()) <= 0) {
360 fprintf(stderr,"Could not read node from disk!\n");
361 return -1;
364 inode = Inode::Factory(&disk, bfsInode, false);
365 if (inode == NULL || inode->InitCheck() < B_OK) {
366 fprintf(stderr,"Not a valid inode!\n");
367 delete inode;
368 inode = NULL;
372 if (dumpInode) {
373 printf("Inode at block %" B_PRIdOFF ":\n------------------------------"
374 "-----------\n", disk.ToBlock(run));
375 dump_inode(inode, bfsInode, showOffsets);
376 dump_indirect_stream(disk, bfsInode, showOffsets);
377 dump_double_indirect_stream(disk, bfsInode, showOffsets);
378 dump_small_data(inode);
379 putchar('\n');
382 if (dumpBTree && inode != NULL) {
383 printf("B+Tree at block %" B_PRIdOFF ":\n-----------------------------"
384 "------------\n", disk.ToBlock(run));
385 if (inode->IsDirectory() || inode->IsAttributeDirectory()) {
386 dump_bplustree(disk, (Directory*)inode, inode->Size(), dumpHex);
387 putchar('\n');
388 } else
389 fprintf(stderr, "Inode is not a directory!\n");
392 if (listBTree && inode != NULL) {
393 printf("Directory contents: ------------------------------------------\n");
394 if (inode->IsDirectory() || inode->IsAttributeDirectory()) {
395 list_bplustree(disk, (Directory*)inode, inode->Size());
396 putchar('\n');
397 } else
398 fprintf(stderr, "Inode is not a directory!\n");
401 if (countBTree && inode != NULL) {
402 printf("Count contents: ------------------------------------------\n");
403 if (inode->IsDirectory() || inode->IsAttributeDirectory()) {
404 count_bplustree(disk, (Directory*)inode, inode->Size());
405 putchar('\n');
406 } else
407 fprintf(stderr, "Inode is not a directory!\n");
410 if (validateBTree && inode != NULL) {
411 printf("Validating B+Tree at block %" B_PRIdOFF ":\n------------------"
412 "-----------------------\n", disk.ToBlock(run));
413 if (inode->IsDirectory() || inode->IsAttributeDirectory()) {
414 BPlusTree *tree;
415 if (((Directory *)inode)->GetTree(&tree) == B_OK) {
416 if (tree->Validate(true) < B_OK)
417 puts("B+Tree is corrupt!");
418 else
419 puts("B+Tree seems to be okay.");
421 } else
422 fprintf(stderr, "Inode is not a directory!\n");
425 if (dumpHex) {
426 printf("Hexdump from inode at block %" B_PRIdOFF ":\n-----------------"
427 "------------------------\n", disk.ToBlock(run));
428 dump_block(buffer, disk.BlockSize());
429 putchar('\n');
432 delete inode;
434 return 0;