2 * Copyright (c) 2002-2009 pinc Software. All Rights Reserved.
3 * Released under the terms of the MIT license.
6 //! Finds out to which file(s) a particular block belongs
12 #include "Hashtable.h"
13 #include "BPlusTree.h"
26 void scanNodes(Disk
& disk
, Directory
* directory
, const char* name
,
27 const block_run
& checkForRun
);
30 char gEscape
[3] = {0x1b, '[', 0};
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
)
47 checkNode(Disk
&disk
, Inode
*inode
, block_run checkForRun
)
49 // check the inode space itself
50 if (checkForBlockRunIntersection(inode
->BlockRun(), checkForRun
))
53 // the data stream of symlinks is no real data stream
54 if (inode
->IsSymlink() && (inode
->Flags() & INODE_LONG_SYMLINK
) == 0)
59 const data_stream
* data
= &inode
->InodeBuffer()->data
;
61 if (data
->max_direct_range
== 0)
64 for (int32 i
= 0; i
< NUM_DIRECT_BLOCKS
; i
++) {
65 if (data
->direct
[i
].IsZero())
68 if (checkForBlockRunIntersection(data
->direct
[i
], checkForRun
))
74 if (data
->max_indirect_range
== 0 || data
->indirect
.IsZero())
77 if (checkForBlockRunIntersection(data
->indirect
, checkForRun
))
80 DataStream
*stream
= dynamic_cast<DataStream
*>(inode
);
84 // load indirect blocks
85 int32 bytes
= data
->indirect
.length
<< disk
.BlockShift();
86 block_run
* indirect
= (block_run
*)malloc(bytes
);
89 if (disk
.ReadAt(disk
.ToOffset(data
->indirect
), indirect
, bytes
) <= 0)
92 int32 runs
= bytes
/ sizeof(block_run
);
93 for (int32 i
= 0; i
< runs
; i
++) {
94 if (indirect
[i
].IsZero())
97 if (checkForBlockRunIntersection(indirect
[i
], checkForRun
))
102 // double indirect blocks
104 if (data
->max_double_indirect_range
== 0 || data
->double_indirect
.IsZero())
107 if (checkForBlockRunIntersection(data
->double_indirect
, checkForRun
))
110 // TODO: to be implemented...
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
) {
131 dynamic_cast<Directory
*>(attributeDirectory
), "(attr-dir)",
135 delete attributeDirectory
;
141 scanNodes(Disk
& disk
, Directory
* directory
, const char* directoryName
,
142 const block_run
& checkForRun
)
144 if (directory
== NULL
)
147 scanNode(disk
, directory
, directoryName
, checkForRun
);
150 char name
[B_FILE_NAME_LENGTH
];
152 while (directory
->GetNextEntry(name
, &run
) == B_OK
) {
153 if (!strcmp(name
, ".") || !strcmp(name
, ".."))
156 if (++gCount
% 50 == 0)
157 printf(" %7Ld%s1A\n", gCount
, gEscape
);
159 Inode
*inode
= Inode::Factory(&disk
, run
);
162 if (inode
->IsDirectory()) {
163 scanNodes(disk
, static_cast<Directory
*>(inode
), name
,
166 scanNode(disk
, inode
, name
, checkForRun
);
170 printf(" Directory \"%s\" (%ld, %d) points to corrupt inode \"%s\" "
171 "(%ld, %d)\n", directory
->Name(),
172 directory
->BlockRun().allocation_group
,directory
174 name
, run
.allocation_group
, run
.start
);
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");
192 scanNodes(disk
, root
, "(root)", checkForRun
);
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
);
206 printf(" %7Ld nodes found.\n", gCount
);
211 testBitmap(Disk
& disk
, const block_run
& run
)
214 status_t status
= bitmap
.SetTo(&disk
);
215 if (status
!= B_OK
) {
216 fprintf(stderr
, "Bitmap initialization failed: %s\n", strerror(status
));
220 printf("Block bitmap sees block %Ld as %s.\n", disk
.ToBlock(run
),
221 bitmap
.UsedAt(disk
.ToBlock(run
)) ? "used" : "free");
226 parseBlockRun(Disk
& disk
, char* first
, char* last
)
231 return block_run::Run(atol(first
), atol(last
), 1);
233 if ((comma
= strchr(first
, ',')) != NULL
) {
235 return block_run::Run(atol(first
), atol(comma
));
238 return disk
.ToBlockRun(atoll(first
));
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
);
262 bool scanAll
= false;
267 while (*++arg
&& isalpha(*arg
)) {
273 printUsage(toolName
);
282 status_t status
= disk
.InitCheck();
284 fprintf(stderr
, "Could not open device or file \"%s\": %s\n",
285 argv
[0], strerror(status
));
289 if (disk
.ValidateSuperBlock() != B_OK
) {
290 fprintf(stderr
, "The disk's superblock is corrupt!\n");
294 // Set the block_run to the right value (as specified on the command line)
296 fprintf(stderr
, "Need the allocation group and starting offset (or the "
297 "block number) of the block to search for!\n");
300 block_run run
= parseBlockRun(disk
, argv
[1], argv
[2]);
301 off_t block
= disk
.ToBlock(run
);
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
,
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,
316 scanNodes(disk
, run
, scanAll
);