source: mainline/uspace/app/ext2info/ext2info.c@ a8e1aae

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a8e1aae was a8e1aae, checked in by Martin Sucha <sucha14@…>, 15 years ago

Add support for reading directories to libext2

  • Property mode set to 100644
File size: 14.2 KB
Line 
1/*
2 * Copyright (c) 2011 Martin Sucha
3 * Copyright (c) 2010 Jiri Svoboda
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup fs
31 * @{
32 */
33
34/**
35 * @file ext2info.c
36 * @brief Tool for displaying information about ext2 filesystem
37 *
38 */
39
40#include <stdio.h>
41#include <stdlib.h>
42#include <libblock.h>
43#include <mem.h>
44#include <devmap.h>
45#include <byteorder.h>
46#include <sys/types.h>
47#include <sys/typefmt.h>
48#include <inttypes.h>
49#include <errno.h>
50#include <libext2.h>
51
52#define NAME "ext2info"
53
54static void syntax_print(void);
55static void print_superblock(ext2_superblock_t *);
56static void print_block_groups(ext2_filesystem_t *);
57static void print_block_group(ext2_block_group_t *);
58static void print_inode_by_number(ext2_filesystem_t *, uint32_t, bool, uint32_t,
59 bool);
60static void print_data(unsigned char *, size_t);
61static void print_inode(ext2_filesystem_t *, ext2_inode_t *);
62static void print_inode_data(ext2_filesystem_t *, ext2_inode_t *, uint32_t);
63static void print_directory_contents(ext2_filesystem_t *, ext2_inode_ref_t *);
64
65#define ARG_SUPERBLOCK 1
66#define ARG_BLOCK_GROUPS 2
67#define ARG_INODE 4
68#define ARG_STRICT_CHECK 8
69#define ARG_INODE_DATA 16
70#define ARG_INODE_LIST 32
71#define ARG_COMMON (ARG_SUPERBLOCK | ARG_BLOCK_GROUPS)
72#define ARG_ALL (ARG_COMMON | ARG_INODE)
73
74
75int main(int argc, char **argv)
76{
77
78 int rc;
79 char *endptr;
80 char *dev_path;
81 devmap_handle_t handle;
82 ext2_filesystem_t filesystem;
83 int arg_flags;
84 uint32_t inode = 0;
85 uint32_t inode_data = 0;
86
87 arg_flags = 0;
88
89 if (argc < 2) {
90 printf(NAME ": Error, argument missing.\n");
91 syntax_print();
92 return 1;
93 }
94
95 // Skip program name
96 --argc; ++argv;
97
98 if (str_cmp(*argv, "--strict-check") == 0) {
99 --argc; ++argv;
100 arg_flags |= ARG_STRICT_CHECK;
101 }
102
103 if (str_cmp(*argv, "--superblock") == 0) {
104 --argc; ++argv;
105 arg_flags |= ARG_SUPERBLOCK;
106 }
107
108 if (str_cmp(*argv, "--block-groups") == 0) {
109 --argc; ++argv;
110 arg_flags |= ARG_BLOCK_GROUPS;
111 }
112
113 if (str_cmp(*argv, "--inode") == 0) {
114 --argc; ++argv;
115 if (argc == 0) {
116 printf(NAME ": Argument expected for --inode\n");
117 return 2;
118 }
119
120 inode = strtol(*argv, &endptr, 10);
121 if (*endptr != '\0') {
122 printf(NAME ": Error, invalid argument for --inode.\n");
123 syntax_print();
124 return 1;
125 }
126
127 arg_flags |= ARG_INODE;
128 --argc; ++argv;
129
130 if (str_cmp(*argv, "--inode-data") == 0) {
131 --argc; ++argv;
132 if (argc == 0) {
133 printf(NAME ": Argument expected for --inode-data\n");
134 return 2;
135 }
136
137 inode_data = strtol(*argv, &endptr, 10);
138 if (*endptr != '\0') {
139 printf(NAME ": Error, invalid argument for --inode-data.\n");
140 syntax_print();
141 return 1;
142 }
143
144 arg_flags |= ARG_INODE_DATA;
145 --argc; ++argv;
146 }
147
148 if (str_cmp(*argv, "--list") == 0) {
149 --argc; ++argv;
150 arg_flags |= ARG_INODE_LIST;
151 }
152 }
153
154 if (argc != 1) {
155 printf(NAME ": Error, unexpected argument.\n");
156 syntax_print();
157 return 1;
158 }
159
160 // Display common things by default
161 if ((arg_flags & ARG_ALL) == 0) {
162 arg_flags = ARG_COMMON;
163 }
164
165 dev_path = *argv;
166
167 rc = devmap_device_get_handle(dev_path, &handle, 0);
168 if (rc != EOK) {
169 printf(NAME ": Error resolving device `%s'.\n", dev_path);
170 return 2;
171 }
172
173 rc = ext2_filesystem_init(&filesystem, handle);
174 if (rc != EOK) {
175 printf(NAME ": Error initializing libext2.\n");
176 return 3;
177 }
178
179 rc = ext2_filesystem_check_sanity(&filesystem);
180 if (rc != EOK) {
181 printf(NAME ": Filesystem did not pass sanity check.\n");
182 if (arg_flags & ARG_STRICT_CHECK) {
183 return 3;
184 }
185 }
186
187 if (arg_flags & ARG_SUPERBLOCK) {
188 print_superblock(filesystem.superblock);
189 }
190
191 if (arg_flags & ARG_BLOCK_GROUPS) {
192 print_block_groups(&filesystem);
193 }
194
195 if (arg_flags & ARG_INODE) {
196 print_inode_by_number(&filesystem, inode, arg_flags & ARG_INODE_DATA,
197 inode_data, arg_flags & ARG_INODE_LIST);
198 }
199
200 ext2_filesystem_fini(&filesystem);
201
202 return 0;
203}
204
205
206static void syntax_print(void)
207{
208 printf("syntax: ext2info [--strict-check] [--superblock] [--block-groups] "
209 "[--inode <i-number> [--inode-data <block-number>] [--list]] <device_name>\n");
210}
211
212static void print_superblock(ext2_superblock_t *superblock)
213{
214 uint16_t magic;
215 uint32_t first_block;
216 uint32_t block_size;
217 uint32_t fragment_size;
218 uint32_t blocks_per_group;
219 uint32_t fragments_per_group;
220 uint32_t rev_major;
221 uint16_t rev_minor;
222 uint16_t state;
223 uint32_t first_inode;
224 uint16_t inode_size;
225 uint32_t total_blocks;
226 uint32_t reserved_blocks;
227 uint32_t free_blocks;
228 uint32_t total_inodes;
229 uint32_t free_inodes;
230 uint32_t os;
231
232 int pos;
233 unsigned char c;
234
235 magic = ext2_superblock_get_magic(superblock);
236 first_block = ext2_superblock_get_first_block(superblock);
237 block_size = ext2_superblock_get_block_size(superblock);
238 fragment_size = ext2_superblock_get_fragment_size(superblock);
239 blocks_per_group = ext2_superblock_get_blocks_per_group(superblock);
240 fragments_per_group = ext2_superblock_get_fragments_per_group(superblock);
241 rev_major = ext2_superblock_get_rev_major(superblock);
242 rev_minor = ext2_superblock_get_rev_minor(superblock);
243 state = ext2_superblock_get_state(superblock);
244 first_inode = ext2_superblock_get_first_inode(superblock);
245 inode_size = ext2_superblock_get_inode_size(superblock);
246 total_blocks = ext2_superblock_get_total_block_count(superblock);
247 reserved_blocks = ext2_superblock_get_reserved_block_count(superblock);
248 free_blocks = ext2_superblock_get_free_block_count(superblock);
249 total_inodes = ext2_superblock_get_total_inode_count(superblock);
250 free_inodes = ext2_superblock_get_free_inode_count(superblock);
251 os = ext2_superblock_get_os(superblock);
252
253 printf("Superblock:\n");
254
255 if (magic == EXT2_SUPERBLOCK_MAGIC) {
256 printf(" Magic value: %X (correct)\n", magic);
257 }
258 else {
259 printf(" Magic value: %X (incorrect)\n", magic);
260 }
261
262 printf(" Revision: %u.%hu\n", rev_major, rev_minor);
263 printf(" State: %hu\n", state);
264 printf(" Creator OS: %u\n", os);
265 printf(" First block: %u\n", first_block);
266 printf(" Block size: %u bytes (%u KiB)\n", block_size, block_size/1024);
267 printf(" Blocks per group: %u\n", blocks_per_group);
268 printf(" Total blocks: %u\n", total_blocks);
269 printf(" Reserved blocks: %u\n", reserved_blocks);
270 printf(" Free blocks: %u\n", free_blocks);
271 printf(" Fragment size: %u bytes (%u KiB)\n", fragment_size,
272 fragment_size/1024);
273 printf(" Fragments per group: %u\n", fragments_per_group);
274 printf(" First inode: %u\n", first_inode);
275 printf(" Inode size: %hu bytes\n", inode_size);
276 printf(" Total inodes: %u\n", total_inodes);
277 printf(" Free inodes: %u\n", free_inodes);
278
279
280 if (rev_major == 1) {
281 printf(" UUID: ");
282 for (pos = 0; pos < 16; pos++) {
283 printf("%02x", superblock->uuid[pos]);
284 }
285 printf("\n");
286
287 printf(" Volume label: ");
288 for (pos = 0; pos < 16; pos++) {
289 c = superblock->volume_name[pos];
290 if (c >= 32 && c < 128) {
291 putchar(c);
292 }
293 else {
294 putchar(' ');
295 }
296 }
297 printf("\n");
298 }
299
300}
301
302void print_block_groups(ext2_filesystem_t *filesystem)
303{
304 uint32_t block_group_count;
305 uint32_t i;
306 ext2_block_group_ref_t *block_group_ref;
307 int rc;
308
309 printf("Block groups:\n");
310
311 block_group_count = ext2_superblock_get_block_group_count(
312 filesystem->superblock);
313
314 for (i = 0; i < block_group_count; i++) {
315 printf(" Block group %u\n", i);
316 rc = ext2_filesystem_get_block_group_ref(filesystem, i, &block_group_ref);
317 if (rc != EOK) {
318 printf(" Failed reading block group\n");
319 continue;
320 }
321
322 print_block_group(block_group_ref->block_group);
323
324 rc = ext2_filesystem_put_block_group_ref(block_group_ref);
325 if (rc != EOK) {
326 printf(" Failed freeing block group\n");
327 }
328 }
329
330}
331
332void print_block_group(ext2_block_group_t *bg)
333{
334 uint32_t block_bitmap_block;
335 uint32_t inode_bitmap_block;
336 uint32_t inode_table_first_block;
337 uint16_t free_block_count;
338 uint16_t free_inode_count;
339 uint16_t directory_inode_count;
340
341 block_bitmap_block = ext2_block_group_get_block_bitmap_block(bg);
342 inode_bitmap_block = ext2_block_group_get_inode_bitmap_block(bg);
343 inode_table_first_block = ext2_block_group_get_inode_table_first_block(bg);
344 free_block_count = ext2_block_group_get_free_block_count(bg);
345 free_inode_count = ext2_block_group_get_free_inode_count(bg);
346 directory_inode_count = ext2_block_group_get_directory_inode_count(bg);
347
348 printf(" Block bitmap block: %u\n", block_bitmap_block);
349 printf(" Inode bitmap block: %u\n", inode_bitmap_block);
350 printf(" Inode table's first block: %u\n", inode_table_first_block);
351 printf(" Free blocks: %u\n", free_block_count);
352 printf(" Free inodes: %u\n", free_inode_count);
353 printf(" Directory inodes: %u\n", directory_inode_count);
354}
355
356void print_inode_by_number(ext2_filesystem_t *fs, uint32_t inode,
357 bool print_data, uint32_t data, bool list)
358{
359 int rc;
360 ext2_inode_ref_t *inode_ref;
361
362 printf("Inode %u\n", inode);
363
364 rc = ext2_filesystem_get_inode_ref(fs, inode, &inode_ref);
365 if (rc != EOK) {
366 printf(" Failed getting inode ref\n");
367 return;
368 }
369
370 print_inode(fs, inode_ref->inode);
371 if (print_data) {
372 print_inode_data(fs, inode_ref->inode, data);
373 }
374
375 if (list && ext2_inode_is_type(fs->superblock, inode_ref->inode,
376 EXT2_INODE_MODE_DIRECTORY)) {
377 print_directory_contents(fs, inode_ref);
378 }
379
380 rc = ext2_filesystem_put_inode_ref(inode_ref);
381 if (rc != EOK) {
382 printf(" Failed putting inode ref\n");
383 }
384}
385
386void print_inode(ext2_filesystem_t *fs, ext2_inode_t *inode)
387{
388 uint32_t mode;
389 uint32_t mode_type;
390 uint32_t user_id;
391 uint32_t group_id;
392 uint64_t size;
393 uint16_t usage_count;
394 uint32_t flags;
395 uint16_t access;
396 const char *type;
397 uint32_t block;
398 uint32_t total_blocks;
399 int i;
400 bool all_blocks = false;
401
402 mode = ext2_inode_get_mode(fs->superblock, inode);
403 mode_type = mode & EXT2_INODE_MODE_TYPE_MASK;
404 user_id = ext2_inode_get_user_id(fs->superblock, inode);
405 group_id = ext2_inode_get_group_id(fs->superblock, inode);
406 size = ext2_inode_get_size(fs->superblock, inode);
407 usage_count = ext2_inode_get_usage_count(inode);
408 flags = ext2_inode_get_flags(inode);
409 total_blocks = ext2_inode_get_reserved_blocks(fs->superblock, inode);
410
411 type = "Unknown";
412 if (mode_type == EXT2_INODE_MODE_BLOCKDEV) {
413 type = "Block device";
414 }
415 else if (mode_type == EXT2_INODE_MODE_FIFO) {
416 type = "Fifo (pipe)";
417 }
418 else if (mode_type == EXT2_INODE_MODE_CHARDEV) {
419 type = "Character device";
420 }
421 else if (mode_type == EXT2_INODE_MODE_DIRECTORY) {
422 type = "Directory";
423 }
424 else if (mode_type == EXT2_INODE_MODE_FILE) {
425 type = "File";
426 }
427 else if (mode_type == EXT2_INODE_MODE_SOFTLINK) {
428 type = "Soft link";
429 }
430 else if (mode_type == EXT2_INODE_MODE_SOCKET) {
431 type = "Socket";
432 }
433
434 access = mode & EXT2_INODE_MODE_ACCESS_MASK;
435
436
437 printf(" Mode: %08x (Type: %s, Access bits: %04ho)\n", mode, type, access);
438 printf(" User ID: %u\n", user_id);
439 printf(" Group ID: %u\n", group_id);
440 printf(" Size: %" PRIu64 "\n", size);
441 printf(" Usage (link) count: %u\n", usage_count);
442 printf(" Flags: %u\n", flags);
443 printf(" Total allocated blocks: %u\n", total_blocks);
444 printf(" Block list: ");
445 for (i = 0; i < 12; i++) {
446 block = ext2_inode_get_direct_block(inode, i);
447 if (block == 0) {
448 all_blocks = true;
449 break;
450 }
451 printf("%u ", block);
452 }
453 all_blocks = all_blocks || ext2_inode_get_indirect_block(inode, 0) == 0;
454 if (!all_blocks) {
455 printf(" and more...");
456 }
457 printf("\n");
458}
459
460void print_data(unsigned char *data, size_t size)
461{
462 unsigned char c;
463 size_t i;
464
465 for (i = 0; i < size; i++) {
466 c = data[i];
467 if (c >= 32 && c < 127) {
468 putchar(c);
469 }
470 else {
471 putchar('.');
472 }
473 }
474}
475
476void print_inode_data(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t data)
477{
478 int rc;
479 uint32_t data_block_index;
480 block_t *block;
481
482 rc = ext2_filesystem_get_inode_data_block_index(fs, inode, data,
483 &data_block_index);
484
485 if (rc != EOK) {
486 printf("Failed getting data block #%u\n", data);
487 return;
488 }
489
490 printf("Data for inode contents block #%u is located in filesystem "
491 "block %u\n", data, data_block_index);
492
493 printf("Data preview (only printable characters):\n");
494
495 rc = block_get(&block, fs->device, data_block_index, 0);
496 if (rc != EOK) {
497 printf("Failed reading filesystem block %u\n", data_block_index);
498 return;
499 }
500
501 print_data(block->data, block->size);
502 printf("\n");
503
504 rc = block_put(block);
505 if (rc != EOK) {
506 printf("Failed putting filesystem block\n");
507 }
508
509}
510
511void print_directory_contents(ext2_filesystem_t *fs,
512 ext2_inode_ref_t *inode_ref)
513{
514 int rc;
515 ext2_directory_iterator_t it;
516 size_t name_size;
517
518 printf(" Directory contents:\n");
519
520 rc = ext2_directory_iterator_init(&it, fs, inode_ref);
521 if (rc != EOK) {
522 printf("Failed initializing directory iterator\n");
523 return;
524 }
525
526 while (it.current != NULL) {
527 name_size = ext2_directory_entry_ll_get_name_length(fs->superblock,
528 it.current);
529 printf(" ");
530 print_data(&it.current->name, name_size);
531 printf(" --> %u\n", it.current->inode);
532
533 rc = ext2_directory_iterator_next(&it);
534 if (rc != EOK) {
535 printf("Failed reading directory contents\n");
536 goto cleanup;
537 }
538 }
539
540cleanup:
541 rc = ext2_directory_iterator_fini(&it);
542 if (rc != EOK) {
543 printf("Failed cleaning-up directory iterator\n");
544 }
545
546}
547
548/**
549 * @}
550 */
Note: See TracBrowser for help on using the repository browser.