aboutsummaryrefslogtreecommitdiffstats
path: root/fsck/dump.c
diff options
context:
space:
mode:
Diffstat (limited to 'fsck/dump.c')
-rw-r--r--fsck/dump.c170
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;
}