2 * logdump.c --- dump the contents of the journal out to a file
4 * Author: Stephen C. Tweedie, 2001 <sct@redhat.com>
5 * Copyright (C) 2001 Red Hat, Inc.
6 * Based on portions Copyright (C) 1994 Theodore Ts'o.
8 * This file may be redistributed under the terms of the GNU Public
22 #include <sys/types.h>
34 #include "blkid/blkid.h"
36 #if __GNUC_PREREQ (4, 6)
37 #pragma GCC diagnostic push
38 #pragma GCC diagnostic ignored "-Wunused-function"
40 #include "ext2fs/fast_commit.h"
41 #if __GNUC_PREREQ (4, 6)
42 #pragma GCC diagnostic pop
44 #include <uuid/uuid.h>
46 enum journal_location
{JOURNAL_IS_INTERNAL
, JOURNAL_IS_EXTERNAL
};
48 #define ANY_BLOCK ((blk64_t) -1)
50 static int dump_all
, dump_super
, dump_old
, dump_contents
, dump_descriptors
;
51 static int64_t dump_counts
;
52 static blk64_t block_to_dump
, bitmap_to_dump
, inode_block_to_dump
;
53 static unsigned int group_to_dump
, inode_offset_to_dump
;
54 static ext2_ino_t inode_to_dump
;
55 static bool wrapped_flag
;
59 enum journal_location where
;
64 static void dump_journal(char *, FILE *, struct journal_source
*);
66 static void dump_descriptor_block(FILE *, struct journal_source
*,
67 char *, journal_superblock_t
*,
68 unsigned int *, unsigned int, __u32
, tid_t
);
70 static void dump_revoke_block(FILE *, char *, journal_superblock_t
*,
71 unsigned int, unsigned int, tid_t
);
73 static void dump_metadata_block(FILE *, struct journal_source
*,
74 journal_superblock_t
*,
75 unsigned int, unsigned int, unsigned int,
78 static void dump_fc_block(FILE *out_file
, char *buf
, int blocksize
,
79 tid_t transaction
, int *fc_done
);
81 static void do_hexdump (FILE *, char *, int);
83 #define WRAP(jsb, blocknr, maxlen) \
84 if (blocknr >= (maxlen)) { \
85 blocknr -= (maxlen - be32_to_cpu((jsb)->s_first)); \
86 wrapped_flag = true; \
89 void do_logdump(int argc
, ss_argv_t argv
, int sci_idx
EXT2FS_ATTR((unused
)),
90 void *infop
EXT2FS_ATTR((unused
)))
97 char *inode_spec
= NULL
;
98 char *journal_fn
= NULL
;
101 ext2_ino_t journal_inum
;
102 struct ext2_inode journal_inode
;
103 ext2_file_t journal_file
= NULL
;
105 struct journal_source journal_source
;
106 struct ext2_super_block
*es
= NULL
;
108 journal_source
.where
= JOURNAL_IS_INTERNAL
;
109 journal_source
.fd
= 0;
110 journal_source
.file
= 0;
115 dump_descriptors
= 1;
116 block_to_dump
= ANY_BLOCK
;
118 inode_block_to_dump
= ANY_BLOCK
;
121 wrapped_flag
= false;
124 while ((c
= getopt (argc
, argv
, "ab:ci:f:OsSn:")) != EOF
) {
130 block_to_dump
= strtoul(optarg
, &tmp
, 0);
133 "Bad block number - %s", optarg
);
136 dump_descriptors
= 0;
146 dump_descriptors
= 0;
158 dump_counts
= strtol(optarg
, &tmp
, 10);
161 "Bad log counts number - %s", optarg
);
169 if (optind
!= argc
&& optind
!= argc
-1) {
174 int inode_group
, group_offset
, inodes_per_block
;
176 if (check_fs_open(argv
[0]))
179 inode_to_dump
= string_to_inode(inode_spec
);
183 es
= current_fs
->super
;
184 inode_group
= ((inode_to_dump
- 1)
185 / es
->s_inodes_per_group
);
186 group_offset
= ((inode_to_dump
- 1)
187 % es
->s_inodes_per_group
);
188 inodes_per_block
= (current_fs
->blocksize
189 / sizeof(struct ext2_inode
));
191 inode_block_to_dump
=
192 ext2fs_inode_table_loc(current_fs
, inode_group
) +
193 (group_offset
/ inodes_per_block
);
194 inode_offset_to_dump
= ((group_offset
% inodes_per_block
)
195 * sizeof(struct ext2_inode
));
196 printf("Inode %u is at group %u, block %llu, offset %u\n",
197 inode_to_dump
, inode_group
,
198 (unsigned long long) inode_block_to_dump
,
199 inode_offset_to_dump
);
202 if (optind
== argc
) {
205 out_fn
= argv
[optind
];
206 out_file
= fopen(out_fn
, "w");
208 com_err(argv
[0], errno
, "while opening %s for logdump",
214 if (block_to_dump
!= ANY_BLOCK
) {
215 if (check_fs_open(argv
[0]))
217 es
= current_fs
->super
;
218 group_to_dump
= ((block_to_dump
-
219 es
->s_first_data_block
)
220 / es
->s_blocks_per_group
);
221 bitmap_to_dump
= ext2fs_block_bitmap_loc(current_fs
, group_to_dump
);
225 /* Set up to read journal from a regular file somewhere */
226 journal_fd
= open(journal_fn
, O_RDONLY
, 0);
227 if (journal_fd
< 0) {
228 com_err(argv
[0], errno
, "while opening %s for logdump",
232 journal_source
.where
= JOURNAL_IS_EXTERNAL
;
233 journal_source
.fd
= journal_fd
;
234 dump_journal(argv
[0], out_file
, &journal_source
);
238 if (check_fs_open(argv
[0]))
240 es
= current_fs
->super
;
242 if ((journal_inum
= es
->s_journal_inum
)) {
244 if (es
->s_jnl_backup_type
!= EXT3_JNL_BACKUP_BLOCKS
) {
246 "no journal backup in super block\n");
249 memset(&journal_inode
, 0, sizeof(struct ext2_inode
));
250 memcpy(&journal_inode
.i_block
[0], es
->s_jnl_blocks
,
252 journal_inode
.i_size_high
= es
->s_jnl_blocks
[15];
253 journal_inode
.i_size
= es
->s_jnl_blocks
[16];
254 journal_inode
.i_links_count
= 1;
255 journal_inode
.i_mode
= LINUX_S_IFREG
| 0600;
257 if (debugfs_read_inode(journal_inum
, &journal_inode
,
262 retval
= ext2fs_file_open2(current_fs
, journal_inum
,
263 &journal_inode
, 0, &journal_file
);
265 com_err(argv
[0], retval
, "while opening ext2 file");
268 journal_source
.where
= JOURNAL_IS_INTERNAL
;
269 journal_source
.file
= journal_file
;
273 uuid_unparse(es
->s_journal_uuid
, uuid
);
274 journal_fn
= blkid_get_devname(NULL
, "UUID", uuid
);
276 journal_fn
= blkid_devno_to_devname(es
->s_journal_dev
);
278 com_err(argv
[0], 0, "filesystem has no journal");
281 journal_fd
= open(journal_fn
, O_RDONLY
, 0);
282 if (journal_fd
< 0) {
283 com_err(argv
[0], errno
, "while opening %s for logdump",
288 fprintf(out_file
, "Using external journal found at %s\n",
291 journal_source
.where
= JOURNAL_IS_EXTERNAL
;
292 journal_source
.fd
= journal_fd
;
294 dump_journal(argv
[0], out_file
, &journal_source
);
299 ext2fs_file_close(journal_file
);
300 if (out_file
&& (out_file
!= stdout
))
306 fprintf(stderr
, "%s: Usage: logdump [-acsOS] [-n<num_trans>] [-b<block>] [-i<filespec>]\n\t"
307 "[-f<journal_file>] [output_file]\n", argv
[0]);
311 static int read_journal_block(const char *cmd
, struct journal_source
*source
,
312 ext2_loff_t offset
, char *buf
, unsigned int size
)
317 if (source
->where
== JOURNAL_IS_EXTERNAL
) {
318 if (lseek(source
->fd
, offset
, SEEK_SET
) < 0) {
322 retval
= read(source
->fd
, buf
, size
);
330 retval
= ext2fs_file_llseek(source
->file
, offset
,
331 EXT2_SEEK_SET
, NULL
);
334 com_err(cmd
, retval
, "while seeking in reading journal");
337 retval
= ext2fs_file_read(source
->file
, buf
, size
, &got
);
340 com_err(cmd
, retval
, "while reading journal");
345 com_err(cmd
, 0, "short read (read %u, expected %u) "
346 "while reading journal", got
, size
);
352 static const char *type_to_name(int btype
)
355 case JBD2_DESCRIPTOR_BLOCK
:
356 return "descriptor block";
357 case JBD2_COMMIT_BLOCK
:
358 return "commit block";
359 case JBD2_SUPERBLOCK_V1
:
360 return "V1 superblock";
361 case JBD2_SUPERBLOCK_V2
:
362 return "V2 superblock";
363 case JBD2_REVOKE_BLOCK
:
364 return "revoke table";
366 return "unrecognised type";
370 static void dump_journal(char *cmdname
, FILE *out_file
,
371 struct journal_source
*source
)
373 struct ext2_super_block
*sb
;
374 char jsb_buffer
[1024];
375 char buf
[EXT2_MAX_BLOCK_SIZE
];
376 journal_superblock_t
*jsb
;
377 unsigned int blocksize
= 1024;
379 __u32 magic
, sequence
, blocktype
;
380 journal_header_t
*header
;
382 unsigned int blocknr
= 0;
383 unsigned int first_transaction_blocknr
;
387 int64_t cur_counts
= 0;
388 bool exist_no_magic
= false;
390 /* First, check to see if there's an ext2 superblock header */
391 retval
= read_journal_block(cmdname
, source
, 0, buf
, 2048);
395 jsb
= (journal_superblock_t
*) buf
;
396 sb
= (struct ext2_super_block
*) (buf
+1024);
397 #ifdef WORDS_BIGENDIAN
398 if (sb
->s_magic
== ext2fs_swab16(EXT2_SUPER_MAGIC
))
399 ext2fs_swap_super(sb
);
402 if ((be32_to_cpu(jsb
->s_header
.h_magic
) != JBD2_MAGIC_NUMBER
) &&
403 (sb
->s_magic
== EXT2_SUPER_MAGIC
) &&
404 ext2fs_has_feature_journal_dev(sb
)) {
405 blocksize
= EXT2_BLOCK_SIZE(sb
);
406 blocknr
= (blocksize
== 1024) ? 2 : 1;
407 uuid_unparse(sb
->s_uuid
, jsb_buffer
);
408 fprintf(out_file
, "Ext2 superblock header found.\n");
410 fprintf(out_file
, "\tuuid=%s\n", jsb_buffer
);
411 fprintf(out_file
, "\tblocksize=%d\n", blocksize
);
412 fprintf(out_file
, "\tjournal data size %lu\n",
413 (unsigned long) ext2fs_blocks_count(sb
));
417 /* Next, read the journal superblock */
418 retval
= read_journal_block(cmdname
, source
,
419 ((ext2_loff_t
) blocknr
) * blocksize
,
425 e2p_list_journal_super(out_file
, jsb_buffer
,
426 current_fs
->blocksize
, 0);
427 fputc('\n', out_file
);
430 jsb
= (journal_superblock_t
*) jsb_buffer
;
431 if (be32_to_cpu(jsb
->s_header
.h_magic
) != JBD2_MAGIC_NUMBER
) {
433 "Journal superblock magic number invalid!\n");
436 blocksize
= be32_to_cpu(jsb
->s_blocksize
);
437 if ((current_fs
&& (blocksize
!= current_fs
->blocksize
)) ||
438 (!current_fs
&& (!blocksize
|| (blocksize
& (blocksize
- 1)) ||
439 (blocksize
> EXT2_MAX_BLOCK_SIZE
)))) {
441 "Journal block size invalid: %u (%u)\n",
442 be32_to_cpu(jsb
->s_blocksize
), blocksize
);
445 transaction
= be32_to_cpu(jsb
->s_sequence
);
446 blocknr
= be32_to_cpu(jsb
->s_start
);
447 if (source
->where
== JOURNAL_IS_INTERNAL
) {
448 retval
= ext2fs_file_get_lsize(source
->file
, &total_len
);
451 com_err("dump_journal", retval
,
452 "while getting journal inode size");
455 total_len
/= blocksize
;
459 if (fstat(source
->fd
, &st
) < 0)
461 total_len
= st
.st_size
/ blocksize
;
463 maxlen
= be32_to_cpu(jsb
->s_maxlen
);
464 if (maxlen
> total_len
)
467 fprintf(out_file
, "Journal starts at block %u, transaction %u\n",
468 blocknr
, transaction
);
471 /* Empty journal, nothing to do. */
478 first_transaction_blocknr
= blocknr
;
481 if (dump_old
&& (dump_counts
!= -1) && (cur_counts
>= dump_counts
))
484 if ((blocknr
== first_transaction_blocknr
) && dump_old
&& wrapped_flag
) {
485 fprintf(out_file
, "Dump all %lld journal records.\n",
486 (long long) cur_counts
);
490 retval
= read_journal_block(cmdname
, source
,
491 ((ext2_loff_t
) blocknr
) * blocksize
,
496 header
= (journal_header_t
*) buf
;
498 magic
= be32_to_cpu(header
->h_magic
);
499 sequence
= be32_to_cpu(header
->h_sequence
);
500 blocktype
= be32_to_cpu(header
->h_blocktype
);
502 if (magic
!= JBD2_MAGIC_NUMBER
) {
503 if (exist_no_magic
== false) {
504 exist_no_magic
= true;
505 fprintf(out_file
, "No magic number at block %u: "
506 "end of journal.\n", blocknr
);
508 if (dump_old
&& (dump_counts
!= -1)) {
510 WRAP(jsb
, blocknr
, maxlen
);
516 if (sequence
!= transaction
) {
517 fprintf (out_file
, "Found sequence %u (not %u) at "
518 "block %u: end of journal.\n",
519 sequence
, transaction
, blocknr
);
524 if (dump_descriptors
) {
525 fprintf (out_file
, "Found expected sequence %u, "
526 "type %u (%s) at block %u\n",
528 type_to_name(blocktype
), blocknr
);
532 case JBD2_DESCRIPTOR_BLOCK
:
533 dump_descriptor_block(out_file
, source
, buf
, jsb
,
534 &blocknr
, blocksize
, maxlen
,
538 case JBD2_COMMIT_BLOCK
:
542 WRAP(jsb
, blocknr
, maxlen
);
545 case JBD2_REVOKE_BLOCK
:
546 dump_revoke_block(out_file
, buf
, jsb
,
550 WRAP(jsb
, blocknr
, maxlen
);
554 fprintf (out_file
, "Unexpected block type %u at "
555 "block %u.\n", blocktype
, blocknr
);
561 blocknr
= maxlen
- jbd2_journal_get_num_fc_blks(jsb
) + 1;
562 while (blocknr
<= maxlen
) {
563 retval
= read_journal_block(cmdname
, source
,
564 ((ext2_loff_t
) blocknr
) * blocksize
,
569 dump_fc_block(out_file
, buf
, blocksize
, transaction
, &fc_done
);
570 if (!dump_old
&& fc_done
)
576 static inline size_t journal_super_tag_bytes(journal_superblock_t
*jsb
)
580 if (JSB_HAS_INCOMPAT_FEATURE(jsb
, JBD2_FEATURE_INCOMPAT_CSUM_V3
))
581 return sizeof(journal_block_tag3_t
);
583 sz
= sizeof(journal_block_tag_t
);
585 if (JSB_HAS_INCOMPAT_FEATURE(jsb
, JBD2_FEATURE_INCOMPAT_CSUM_V2
))
588 if (JSB_HAS_INCOMPAT_FEATURE(jsb
, JBD2_FEATURE_INCOMPAT_64BIT
))
591 return sz
- sizeof(__u32
);
594 static void dump_fc_block(FILE *out_file
, char *buf
, int blocksize
,
595 tid_t transaction
, int *fc_done
)
597 struct ext4_fc_tl tl
;
598 struct ext4_fc_head
*head
;
599 struct ext4_fc_add_range
*add_range
;
600 struct ext4_fc_del_range
*del_range
;
601 struct ext4_fc_dentry_info
*dentry_info
;
602 struct ext4_fc_tail
*tail
;
603 struct ext3_extent
*ex
;
607 for (cur
= (__u8
*)buf
; cur
< (__u8
*)buf
+ blocksize
;
608 cur
= cur
+ sizeof(tl
) + le16_to_cpu(tl
.fc_len
)) {
609 memcpy(&tl
, cur
, sizeof(tl
));
610 val
= cur
+ sizeof(tl
);
612 switch (le16_to_cpu(tl
.fc_tag
)) {
613 case EXT4_FC_TAG_ADD_RANGE
:
614 add_range
= (struct ext4_fc_add_range
*)val
;
615 ex
= (struct ext3_extent
*)add_range
->fc_ex
;
617 "tag %s, inode %d, lblk %u, pblk %llu, len %lu\n",
619 le32_to_cpu(add_range
->fc_ino
),
620 le32_to_cpu(ex
->ee_block
),
621 le32_to_cpu(ex
->ee_start
) +
622 (((unsigned long long) le16_to_cpu(ex
->ee_start_hi
)) << 32),
623 le16_to_cpu(ex
->ee_len
) > EXT_INIT_MAX_LEN
?
624 le16_to_cpu(ex
->ee_len
) - EXT_INIT_MAX_LEN
:
625 le16_to_cpu(ex
->ee_len
));
627 case EXT4_FC_TAG_DEL_RANGE
:
628 del_range
= (struct ext4_fc_del_range
*)val
;
629 fprintf(out_file
, "tag %s, inode %d, lblk %d, len %d\n",
631 le32_to_cpu(del_range
->fc_ino
),
632 le32_to_cpu(del_range
->fc_lblk
),
633 le32_to_cpu(del_range
->fc_len
));
635 case EXT4_FC_TAG_LINK
:
636 case EXT4_FC_TAG_UNLINK
:
637 case EXT4_FC_TAG_CREAT
:
638 dentry_info
= (struct ext4_fc_dentry_info
*)val
;
640 "tag %s, parent %d, ino %d, name \"%s\"\n",
642 le32_to_cpu(dentry_info
->fc_parent_ino
),
643 le32_to_cpu(dentry_info
->fc_ino
),
644 dentry_info
->fc_dname
);
646 case EXT4_FC_TAG_INODE
:
647 fprintf(out_file
, "tag %s, inode %d\n",
649 le32_to_cpu(((struct ext4_fc_inode
*)val
)->fc_ino
));
651 case EXT4_FC_TAG_PAD
:
652 fprintf(out_file
, "tag %s\n", tag2str(tl
.fc_tag
));
654 case EXT4_FC_TAG_TAIL
:
655 tail
= (struct ext4_fc_tail
*)val
;
656 fprintf(out_file
, "tag %s, tid %d\n",
658 le32_to_cpu(tail
->fc_tid
));
660 le32_to_cpu(tail
->fc_tid
) < transaction
) {
665 case EXT4_FC_TAG_HEAD
:
666 fprintf(out_file
, "\n*** Fast Commit Area ***\n");
667 head
= (struct ext4_fc_head
*)val
;
668 fprintf(out_file
, "tag %s, features 0x%x, tid %d\n",
670 le32_to_cpu(head
->fc_features
),
671 le32_to_cpu(head
->fc_tid
));
673 le32_to_cpu(head
->fc_tid
) < transaction
) {
685 static void dump_descriptor_block(FILE *out_file
,
686 struct journal_source
*source
,
688 journal_superblock_t
*jsb
,
689 unsigned int *blockp
, unsigned blocksize
,
693 unsigned offset
, tag_size
, csum_size
= 0;
695 journal_block_tag_t
*tag
;
696 unsigned int blocknr
;
700 tag_size
= journal_super_tag_bytes(jsb
);
701 offset
= sizeof(journal_header_t
);
704 if (JSB_HAS_INCOMPAT_FEATURE(jsb
, JBD2_FEATURE_INCOMPAT_CSUM_V3
) ||
705 JSB_HAS_INCOMPAT_FEATURE(jsb
, JBD2_FEATURE_INCOMPAT_CSUM_V2
))
706 csum_size
= sizeof(struct jbd2_journal_block_tail
);
709 fprintf(out_file
, "Dumping descriptor block, sequence %u, at "
710 "block %u:\n", transaction
, blocknr
);
713 WRAP(jsb
, blocknr
, maxlen
);
716 /* Work out the location of the current tag, and skip to
719 tag
= (journal_block_tag_t
*) tagp
;
722 /* ... and if we have gone too far, then we've reached the
723 end of this block. */
724 if (offset
> blocksize
- csum_size
)
727 tag_block
= be32_to_cpu(tag
->t_blocknr
);
728 tag_flags
= be16_to_cpu(tag
->t_flags
);
730 if (!(tag_flags
& JBD2_FLAG_SAME_UUID
))
733 dump_metadata_block(out_file
, source
, jsb
,
734 blocknr
, tag_block
, tag_flags
, blocksize
,
738 WRAP(jsb
, blocknr
, maxlen
);
740 } while (!(tag_flags
& JBD2_FLAG_LAST_TAG
));
746 static void dump_revoke_block(FILE *out_file
, char *buf
,
747 journal_superblock_t
*jsb
EXT2FS_ATTR((unused
)),
748 unsigned int blocknr
,
749 unsigned int blocksize
,
752 unsigned int offset
, max
;
753 jbd2_journal_revoke_header_t
*header
;
754 unsigned long long rblock
;
755 int tag_size
= sizeof(__u32
);
758 fprintf(out_file
, "Dumping revoke block, sequence %u, at "
759 "block %u:\n", transaction
, blocknr
);
761 if (be32_to_cpu(jsb
->s_feature_incompat
) & JBD2_FEATURE_INCOMPAT_64BIT
)
762 tag_size
= sizeof(__u64
);
764 header
= (jbd2_journal_revoke_header_t
*) buf
;
765 offset
= sizeof(jbd2_journal_revoke_header_t
);
766 max
= be32_to_cpu(header
->r_count
);
767 if (max
> blocksize
) {
768 fprintf(out_file
, "Revoke block's r_count invalid: %u\b",
773 while (offset
< max
) {
774 if (tag_size
== sizeof(__u32
)) {
775 __u32
*entry
= (__u32
*) (buf
+ offset
);
776 rblock
= be32_to_cpu(*entry
);
778 __u64
*entry
= (__u64
*) (buf
+ offset
);
779 rblock
= ext2fs_be64_to_cpu(*entry
);
781 if (dump_all
|| rblock
== block_to_dump
) {
782 fprintf(out_file
, " Revoke FS block %llu",
783 (unsigned long long) rblock
);
785 fprintf(out_file
, "\n");
787 fprintf(out_file
," at block %u, sequence %u\n",
788 blocknr
, transaction
);
795 static void show_extent(FILE *out_file
, int start_extent
, int end_extent
,
798 if (start_extent
>= 0 && first_block
!= 0)
799 fprintf(out_file
, "(%d+%u): %u ",
800 start_extent
, end_extent
-start_extent
, first_block
);
803 static void show_indirect(FILE *out_file
, const char *name
, __u32 where
)
806 fprintf(out_file
, "(%s): %u ", name
, where
);
810 static void dump_metadata_block(FILE *out_file
, struct journal_source
*source
,
811 journal_superblock_t
*jsb
EXT2FS_ATTR((unused
)),
812 unsigned int log_blocknr
,
813 unsigned int fs_blocknr
,
814 unsigned int log_tag_flags
,
815 unsigned int blocksize
,
819 char buf
[EXT2_MAX_BLOCK_SIZE
];
822 || (fs_blocknr
== block_to_dump
)
823 || (fs_blocknr
== inode_block_to_dump
)
824 || (fs_blocknr
== bitmap_to_dump
)))
827 fprintf(out_file
, " FS block %u logged at ", fs_blocknr
);
829 fprintf(out_file
, "sequence %u, ", transaction
);
830 fprintf(out_file
, "journal block %u (flags 0x%x)\n", log_blocknr
,
833 /* There are two major special cases to parse:
835 * If this block is a block
836 * bitmap block, we need to give it special treatment so that we
837 * can log any allocates and deallocates which affect the
838 * block_to_dump query block.
840 * If the block is an inode block for the inode being searched
841 * for, then we need to dump the contents of that inode
842 * structure symbolically.
845 if (!(dump_contents
&& dump_all
)
846 && fs_blocknr
!= block_to_dump
847 && fs_blocknr
!= bitmap_to_dump
848 && fs_blocknr
!= inode_block_to_dump
)
851 retval
= read_journal_block("logdump", source
,
852 ((ext2_loff_t
) log_blocknr
) * blocksize
,
857 if (fs_blocknr
== bitmap_to_dump
) {
858 struct ext2_super_block
*super
;
861 super
= current_fs
->super
;
862 offset
= ((block_to_dump
- super
->s_first_data_block
) %
863 super
->s_blocks_per_group
);
865 fprintf(out_file
, " (block bitmap for block %llu: "
867 (unsigned long long) block_to_dump
,
868 ext2fs_test_bit(offset
, buf
) ? "SET" : "CLEAR");
871 if (fs_blocknr
== inode_block_to_dump
) {
872 struct ext2_inode
*inode
;
873 int first
, prev
, this, start_extent
, i
;
875 fprintf(out_file
, " (inode block for inode %u):\n",
878 inode
= (struct ext2_inode
*) (buf
+ inode_offset_to_dump
);
879 internal_dump_inode(out_file
, " ", inode_to_dump
, inode
, 0);
881 /* Dump out the direct/indirect blocks here:
882 * internal_dump_inode can only dump them from the main
883 * on-disk inode, not from the journaled copy of the
886 fprintf (out_file
, " Blocks: ");
887 first
= prev
= start_extent
= -1;
889 for (i
=0; i
<EXT2_NDIR_BLOCKS
; i
++) {
890 this = inode
->i_block
[i
];
891 if (start_extent
>= 0 && this == prev
+1) {
895 show_extent(out_file
, start_extent
, i
, first
);
900 show_extent(out_file
, start_extent
, i
, first
);
901 show_indirect(out_file
, "IND", inode
->i_block
[i
++]);
902 show_indirect(out_file
, "DIND", inode
->i_block
[i
++]);
903 show_indirect(out_file
, "TIND", inode
->i_block
[i
++]);
905 fprintf(out_file
, "\n");
909 do_hexdump(out_file
, buf
, blocksize
);
913 static void do_hexdump (FILE *out_file
, char *buf
, int blocksize
)
921 charp
= (char *) buf
;
923 for (i
=0; i
<blocksize
; i
+=16) {
924 fprintf(out_file
, " %04x: ", i
);
925 for (j
=0; j
<16; j
+=4)
926 fprintf(out_file
, "%08x ", *intp
++);
927 for (j
=0; j
<16; j
++) {
929 if (c
< ' ' || c
>= 127)
931 fprintf(out_file
, "%c", c
);
933 fprintf(out_file
, "\n");