Make UEFI boot-platform build again
[haiku.git] / src / bin / bfs_tools / bfswhich.cpp
blob93e63d2619e464442ec56de71ab67321d720798f
1 /*
2 * Copyright (c) 2002-2009 pinc Software. All Rights Reserved.
3 * Released under the terms of the MIT license.
4 */
6 //! Finds out to which file(s) a particular block belongs
9 #include "Bitmap.h"
10 #include "Disk.h"
11 #include "Inode.h"
12 #include "Hashtable.h"
13 #include "BPlusTree.h"
14 #include "dump.h"
16 #include <fs_info.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <ctype.h>
23 #include <errno.h>
26 void scanNodes(Disk& disk, Directory* directory, const char* name,
27 const block_run& checkForRun);
30 char gEscape[3] = {0x1b, '[', 0};
31 off_t gCount = 1;
34 bool
35 checkForBlockRunIntersection(const block_run& check, const block_run& against)
37 if (check.allocation_group == against.allocation_group
38 && check.start + check.length > against.start
39 && check.start < against.start + against.length)
40 return true;
42 return false;
46 bool
47 checkNode(Disk &disk, Inode *inode, block_run checkForRun)
49 // check the inode space itself
50 if (checkForBlockRunIntersection(inode->BlockRun(), checkForRun))
51 return true;
53 // the data stream of symlinks is no real data stream
54 if (inode->IsSymlink() && (inode->Flags() & INODE_LONG_SYMLINK) == 0)
55 return false;
57 // direct blocks
59 const data_stream* data = &inode->InodeBuffer()->data;
61 if (data->max_direct_range == 0)
62 return false;
64 for (int32 i = 0; i < NUM_DIRECT_BLOCKS; i++) {
65 if (data->direct[i].IsZero())
66 break;
68 if (checkForBlockRunIntersection(data->direct[i], checkForRun))
69 return true;
72 // indirect blocks
74 if (data->max_indirect_range == 0 || data->indirect.IsZero())
75 return false;
77 if (checkForBlockRunIntersection(data->indirect, checkForRun))
78 return true;
80 DataStream *stream = dynamic_cast<DataStream *>(inode);
81 if (stream == NULL)
82 return false;
84 // load indirect blocks
85 int32 bytes = data->indirect.length << disk.BlockShift();
86 block_run* indirect = (block_run*)malloc(bytes);
87 if (indirect == NULL)
88 return false;
89 if (disk.ReadAt(disk.ToOffset(data->indirect), indirect, bytes) <= 0)
90 return false;
92 int32 runs = bytes / sizeof(block_run);
93 for (int32 i = 0; i < runs; i++) {
94 if (indirect[i].IsZero())
95 break;
97 if (checkForBlockRunIntersection(indirect[i], checkForRun))
98 return true;
100 free(indirect);
102 // double indirect blocks
104 if (data->max_double_indirect_range == 0 || data->double_indirect.IsZero())
105 return false;
107 if (checkForBlockRunIntersection(data->double_indirect, checkForRun))
108 return true;
110 // TODO: to be implemented...
112 return false;
116 void
117 scanNode(Disk& disk, Inode* inode, const char* name,
118 const block_run& checkForRun)
120 if (checkNode(disk, inode, checkForRun)) {
121 printf("Inode at (%ld, %u, %u) \"%s\" intersects\n",
122 inode->BlockRun().allocation_group, inode->BlockRun().start,
123 inode->BlockRun().length, name);
126 if (!inode->Attributes().IsZero()) {
127 Inode *attributeDirectory = Inode::Factory(&disk,
128 inode->Attributes());
129 if (attributeDirectory != NULL) {
130 scanNodes(disk,
131 dynamic_cast<Directory *>(attributeDirectory), "(attr-dir)",
132 checkForRun);
135 delete attributeDirectory;
140 void
141 scanNodes(Disk& disk, Directory* directory, const char* directoryName,
142 const block_run& checkForRun)
144 if (directory == NULL)
145 return;
147 scanNode(disk, directory, directoryName, checkForRun);
149 directory->Rewind();
150 char name[B_FILE_NAME_LENGTH];
151 block_run run;
152 while (directory->GetNextEntry(name, &run) == B_OK) {
153 if (!strcmp(name, ".") || !strcmp(name, ".."))
154 continue;
156 if (++gCount % 50 == 0)
157 printf(" %7Ld%s1A\n", gCount, gEscape);
159 Inode *inode = Inode::Factory(&disk, run);
160 if (inode != NULL) {
162 if (inode->IsDirectory()) {
163 scanNodes(disk, static_cast<Directory *>(inode), name,
164 checkForRun);
165 } else
166 scanNode(disk, inode, name, checkForRun);
168 delete inode;
169 } else {
170 printf(" Directory \"%s\" (%ld, %d) points to corrupt inode \"%s\" "
171 "(%ld, %d)\n", directory->Name(),
172 directory->BlockRun().allocation_group,directory
173 ->BlockRun().start,
174 name, run.allocation_group, run.start);
180 void
181 scanNodes(Disk& disk, const block_run& checkForRun, bool scanAll)
183 Directory* root = (Directory*)Inode::Factory(&disk, disk.Root());
185 puts("Scanning nodes (this will take some time)...");
187 if (root == NULL || root->InitCheck() != B_OK) {
188 fprintf(stderr," Could not open root directory!\n");
189 return;
192 scanNodes(disk, root, "(root)", checkForRun);
194 delete root;
196 if (scanAll) {
197 Directory* indices = (Directory*)Inode::Factory(&disk, disk.Indices());
199 puts("Scanning index nodes (this will take some time)...");
201 scanNodes(disk, indices, "(indices)", checkForRun);
203 delete indices;
206 printf(" %7Ld nodes found.\n", gCount);
210 void
211 testBitmap(Disk& disk, const block_run& run)
213 Bitmap bitmap;
214 status_t status = bitmap.SetTo(&disk);
215 if (status != B_OK) {
216 fprintf(stderr, "Bitmap initialization failed: %s\n", strerror(status));
217 return;
220 printf("Block bitmap sees block %Ld as %s.\n", disk.ToBlock(run),
221 bitmap.UsedAt(disk.ToBlock(run)) ? "used" : "free");
225 block_run
226 parseBlockRun(Disk& disk, char* first, char* last)
228 char* comma;
230 if (last != NULL)
231 return block_run::Run(atol(first), atol(last), 1);
233 if ((comma = strchr(first, ',')) != NULL) {
234 *comma++ = '\0';
235 return block_run::Run(atol(first), atol(comma));
238 return disk.ToBlockRun(atoll(first));
242 void
243 printUsage(char* tool)
245 char* filename = strrchr(tool, '/');
246 fprintf(stderr, "usage: %s <device> <allocation_group> <start>\n",
247 filename ? filename + 1 : tool);
252 main(int argc, char** argv)
254 puts("Copyright (c) 2001-2009 pinc Software.");
256 char* toolName = argv[0];
257 if (argc < 2 || !strcmp(argv[1], "--help")) {
258 printUsage(toolName);
259 return -1;
262 bool scanAll = false;
264 while (*++argv) {
265 char *arg = *argv;
266 if (*arg == '-') {
267 while (*++arg && isalpha(*arg)) {
268 switch (*arg) {
269 case 'a':
270 scanAll = true;
271 break;
272 default:
273 printUsage(toolName);
274 return -1;
277 } else
278 break;
281 Disk disk(argv[0]);
282 status_t status = disk.InitCheck();
283 if (status < B_OK) {
284 fprintf(stderr, "Could not open device or file \"%s\": %s\n",
285 argv[0], strerror(status));
286 return -1;
289 if (disk.ValidateSuperBlock() != B_OK) {
290 fprintf(stderr, "The disk's superblock is corrupt!\n");
291 return -1;
294 // Set the block_run to the right value (as specified on the command line)
295 if (!argv[1]) {
296 fprintf(stderr, "Need the allocation group and starting offset (or the "
297 "block number) of the block to search for!\n");
298 return -1;
300 block_run run = parseBlockRun(disk, argv[1], argv[2]);
301 off_t block = disk.ToBlock(run);
303 putchar('\n');
304 testBitmap(disk, run);
306 if (checkForBlockRunIntersection(disk.Log(), run)) {
307 printf("Log area (%lu.%u.%u) intersects\n",
308 disk.Log().allocation_group, disk.Log().start,
309 disk.Log().length);
310 } else if (block < 1) {
311 printf("Superblock intersects\n");
312 } else if (block < 1 + disk.BitmapSize()) {
313 printf("Block bitmap intersects (start %d, end %lu)\n", 1,
314 disk.BitmapSize());
315 } else
316 scanNodes(disk, run, scanAll);
318 return 0;