diff options
Diffstat (limited to 'fsck/dump.c')
-rw-r--r-- | fsck/dump.c | 170 |
1 files changed, 160 insertions, 10 deletions
diff --git a/fsck/dump.c b/fsck/dump.c index 765e9db..4bb906f 100644 --- a/fsck/dump.c +++ b/fsck/dump.c @@ -8,6 +8,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include <inttypes.h> + #include "fsck.h" #define BUF_SZ 80 @@ -57,7 +59,7 @@ void sit_dump(struct f2fs_sb_info *sbi, int start_sit, int end_sit) ASSERT(ret >= 0); close(fd); - DBG(1, "Blocks [0x%lx] Free Segs [0x%x]\n", valid_blocks, free_segs); + DBG(1, "Blocks [0x%" PRIx64 "] Free Segs [0x%x]\n", valid_blocks, free_segs); } void ssa_dump(struct f2fs_sb_info *sbi, int start_ssa, int end_ssa) @@ -113,15 +115,164 @@ void ssa_dump(struct f2fs_sb_info *sbi, int start_ssa, int end_ssa) close(fd); } -int dump_node(struct f2fs_sb_info *sbi, nid_t nid) +static void dump_data_blk(__u64 offset, u32 blkaddr) +{ + char buf[F2FS_BLKSIZE]; + + if (blkaddr == NULL_ADDR) + return; + + /* get data */ + if (blkaddr == NEW_ADDR) { + memset(buf, 0, F2FS_BLKSIZE); + } else { + int ret; + ret = dev_read_block(buf, blkaddr); + ASSERT(ret >= 0); + } + + /* write blkaddr */ + dev_write_dump(buf, offset, F2FS_BLKSIZE); +} + +static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype, + u32 nid, u64 *ofs) { struct node_info ni; struct f2fs_node *node_blk; + u32 skip = 0; + u32 i, idx; + + switch (ntype) { + case TYPE_DIRECT_NODE: + skip = idx = ADDRS_PER_BLOCK; + break; + case TYPE_INDIRECT_NODE: + idx = NIDS_PER_BLOCK; + skip = idx * ADDRS_PER_BLOCK; + break; + case TYPE_DOUBLE_INDIRECT_NODE: + skip = 0; + idx = NIDS_PER_BLOCK; + break; + } + + if (nid == 0) { + *ofs += skip; + return; + } + + get_node_info(sbi, nid, &ni); + + node_blk = calloc(BLOCK_SZ, 1); + dev_read_block(node_blk, ni.blk_addr); + + for (i = 0; i < idx; i++, (*ofs)++) { + switch (ntype) { + case TYPE_DIRECT_NODE: + dump_data_blk(*ofs * F2FS_BLKSIZE, + le32_to_cpu(node_blk->dn.addr[i])); + break; + case TYPE_INDIRECT_NODE: + dump_node_blk(sbi, TYPE_DIRECT_NODE, + le32_to_cpu(node_blk->in.nid[i]), ofs); + break; + case TYPE_DOUBLE_INDIRECT_NODE: + dump_node_blk(sbi, TYPE_INDIRECT_NODE, + le32_to_cpu(node_blk->in.nid[i]), ofs); + break; + } + } + free(node_blk); +} + +static void dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid, + struct f2fs_node *node_blk) +{ + u32 i = 0; + u64 ofs = 0; + + /* TODO: need to dump xattr */ + + if((node_blk->i.i_inline & F2FS_INLINE_DATA)){ + DBG(3, "ino[0x%x] has inline data!\n", nid); + /* recover from inline data */ + dev_write_dump(((unsigned char *)node_blk) + INLINE_DATA_OFFSET, + 0, MAX_INLINE_DATA); + return; + } + + /* check data blocks in inode */ + for (i = 0; i < ADDRS_PER_INODE(&node_blk->i); i++, ofs++) + dump_data_blk(ofs * F2FS_BLKSIZE, + le32_to_cpu(node_blk->i.i_addr[i])); + + /* check node blocks in inode */ + for (i = 0; i < 5; i++) { + if (i == 0 || i == 1) + dump_node_blk(sbi, TYPE_DIRECT_NODE, + node_blk->i.i_nid[i], &ofs); + else if (i == 2 || i == 3) + dump_node_blk(sbi, TYPE_INDIRECT_NODE, + node_blk->i.i_nid[i], &ofs); + else if (i == 4) + dump_node_blk(sbi, TYPE_DOUBLE_INDIRECT_NODE, + node_blk->i.i_nid[i], &ofs); + else + ASSERT(0); + } +} + +void dump_file(struct f2fs_sb_info *sbi, struct node_info *ni, + struct f2fs_node *node_blk) +{ + struct f2fs_inode *inode = &node_blk->i; + u32 imode = le32_to_cpu(inode->i_mode); + char name[255] = {0}; + char path[1024] = {0}; + char ans[255] = {0}; int ret; - ret = get_node_info(sbi, nid, &ni); + if (!S_ISREG(imode)) { + MSG(0, "Not a regular file\n\n"); + return; + } + + printf("Do you want to dump this file into ./lost_found/? [Y/N] "); + ret = scanf("%s", ans); ASSERT(ret >= 0); + if (!strcasecmp(ans, "y")) { + ret = system("mkdir -p ./lost_found"); + ASSERT(ret >= 0); + + /* make a file */ + strncpy(name, (const char *)inode->i_name, + le32_to_cpu(inode->i_namelen)); + name[le32_to_cpu(inode->i_namelen)] = 0; + sprintf(path, "./lost_found/%s", name); + + config.dump_fd = open(path, O_TRUNC|O_CREAT|O_RDWR, 0666); + ASSERT(config.dump_fd >= 0); + + /* dump file's data */ + dump_inode_blk(sbi, ni->ino, node_blk); + + /* adjust file size */ + ret = ftruncate(config.dump_fd, le32_to_cpu(inode->i_size)); + ASSERT(ret >= 0); + + close(config.dump_fd); + } +} + +void dump_node(struct f2fs_sb_info *sbi, nid_t nid) +{ + struct node_info ni; + struct f2fs_node *node_blk; + + get_node_info(sbi, nid, &ni); + node_blk = calloc(BLOCK_SZ, 1); dev_read_block(node_blk, ni.blk_addr); @@ -130,9 +281,8 @@ int dump_node(struct f2fs_sb_info *sbi, nid_t nid) DBG(1, "nat_entry.version [0x%x]\n", ni.version); DBG(1, "nat_entry.ino [0x%x]\n", ni.ino); - if (ni.blk_addr == 0x0) { + if (ni.blk_addr == 0x0) MSG(0, "Invalid nat entry\n\n"); - } DBG(1, "node_blk.footer.ino [0x%x]\n", le32_to_cpu(node_blk->footer.ino)); DBG(1, "node_blk.footer.nid [0x%x]\n", le32_to_cpu(node_blk->footer.nid)); @@ -140,12 +290,12 @@ int dump_node(struct f2fs_sb_info *sbi, nid_t nid) if (le32_to_cpu(node_blk->footer.ino) == ni.ino && le32_to_cpu(node_blk->footer.nid) == ni.nid) { print_node_info(node_blk); + dump_file(sbi, &ni, node_blk); } else { MSG(0, "Invalid node block\n\n"); } free(node_blk); - return 0; } int dump_inode_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr) @@ -159,8 +309,7 @@ int dump_inode_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr) type = get_sum_entry(sbi, blk_addr, &sum_entry); nid = le32_to_cpu(sum_entry.nid); - ret = get_node_info(sbi, nid, &ni); - ASSERT(ret >= 0); + get_node_info(sbi, nid, &ni); DBG(1, "Note: blkaddr = main_blkaddr + segno * 512 + offset\n"); DBG(1, "Block_addr [0x%x]\n", blk_addr); @@ -176,7 +325,8 @@ int dump_inode_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr) node_blk = calloc(BLOCK_SZ, 1); read_node_blk: - dev_read_block(node_blk, blk_addr); + ret = dev_read_block(node_blk, blk_addr); + ASSERT(ret >= 0); ino = le32_to_cpu(node_blk->footer.ino); nid = le32_to_cpu(node_blk->footer.nid); @@ -184,7 +334,7 @@ read_node_blk: if (ino == nid) { print_node_info(node_blk); } else { - ret = get_node_info(sbi, ino, &ni); + get_node_info(sbi, ino, &ni); goto read_node_blk; } |