Home | History | Annotate | Download | only in fsck
      1 /**
      2  * dump.c
      3  *
      4  * Copyright (c) 2013 Samsung Electronics Co., Ltd.
      5  *             http://www.samsung.com/
      6  *
      7  * This program is free software; you can redistribute it and/or modify
      8  * it under the terms of the GNU General Public License version 2 as
      9  * published by the Free Software Foundation.
     10  */
     11 #include <inttypes.h>
     12 
     13 #include "node.h"
     14 #include "fsck.h"
     15 #include "xattr.h"
     16 #ifdef HAVE_ATTR_XATTR_H
     17 #include <attr/xattr.h>
     18 #endif
     19 #ifdef HAVE_LINUX_XATTR_H
     20 #include <linux/xattr.h>
     21 #endif
     22 #include <locale.h>
     23 
     24 #define BUF_SZ	80
     25 
     26 const char *seg_type_name[SEG_TYPE_MAX + 1] = {
     27 	"SEG_TYPE_DATA",
     28 	"SEG_TYPE_CUR_DATA",
     29 	"SEG_TYPE_NODE",
     30 	"SEG_TYPE_CUR_NODE",
     31 	"SEG_TYPE_NONE",
     32 };
     33 
     34 void nat_dump(struct f2fs_sb_info *sbi, nid_t start_nat, nid_t end_nat)
     35 {
     36 	struct f2fs_nat_block *nat_block;
     37 	struct f2fs_node *node_block;
     38 	nid_t nid;
     39 	pgoff_t block_addr;
     40 	char buf[BUF_SZ];
     41 	int fd, ret, pack;
     42 
     43 	nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1);
     44 	ASSERT(nat_block);
     45 	node_block = (struct f2fs_node *)calloc(BLOCK_SZ, 1);
     46 	ASSERT(node_block);
     47 
     48 	fd = open("dump_nat", O_CREAT|O_WRONLY|O_TRUNC, 0666);
     49 	ASSERT(fd >= 0);
     50 
     51 	for (nid = start_nat; nid < end_nat; nid++) {
     52 		struct f2fs_nat_entry raw_nat;
     53 		struct node_info ni;
     54 		if(nid == 0 || nid == F2FS_NODE_INO(sbi) ||
     55 					nid == F2FS_META_INO(sbi))
     56 			continue;
     57 
     58 		ni.nid = nid;
     59 		block_addr = current_nat_addr(sbi, nid, &pack);
     60 
     61 		if (lookup_nat_in_journal(sbi, nid, &raw_nat) >= 0) {
     62 			node_info_from_raw_nat(&ni, &raw_nat);
     63 			ret = dev_read_block(node_block, ni.blk_addr);
     64 			ASSERT(ret >= 0);
     65 			if (ni.blk_addr != 0x0) {
     66 				memset(buf, 0, BUF_SZ);
     67 				snprintf(buf, BUF_SZ,
     68 					"nid:%5u\tino:%5u\toffset:%5u"
     69 					"\tblkaddr:%10u\tpack:%d\n",
     70 					ni.nid, ni.ino,
     71 					le32_to_cpu(node_block->footer.flag) >>
     72 						OFFSET_BIT_SHIFT,
     73 					ni.blk_addr, pack);
     74 				ret = write(fd, buf, strlen(buf));
     75 				ASSERT(ret >= 0);
     76 			}
     77 		} else {
     78 			ret = dev_read_block(nat_block, block_addr);
     79 			ASSERT(ret >= 0);
     80 			node_info_from_raw_nat(&ni,
     81 					&nat_block->entries[nid % NAT_ENTRY_PER_BLOCK]);
     82 			if (ni.blk_addr == 0)
     83 				continue;
     84 
     85 			ret = dev_read_block(node_block, ni.blk_addr);
     86 			ASSERT(ret >= 0);
     87 			memset(buf, 0, BUF_SZ);
     88 			snprintf(buf, BUF_SZ,
     89 				"nid:%5u\tino:%5u\toffset:%5u"
     90 				"\tblkaddr:%10u\tpack:%d\n",
     91 				ni.nid, ni.ino,
     92 				le32_to_cpu(node_block->footer.flag) >>
     93 					OFFSET_BIT_SHIFT,
     94 				ni.blk_addr, pack);
     95 			ret = write(fd, buf, strlen(buf));
     96 			ASSERT(ret >= 0);
     97 		}
     98 	}
     99 
    100 	free(nat_block);
    101 	free(node_block);
    102 
    103 	close(fd);
    104 }
    105 
    106 void sit_dump(struct f2fs_sb_info *sbi, unsigned int start_sit,
    107 					unsigned int end_sit)
    108 {
    109 	struct seg_entry *se;
    110 	struct sit_info *sit_i = SIT_I(sbi);
    111 	unsigned int segno;
    112 	char buf[BUF_SZ];
    113 	u32 free_segs = 0;;
    114 	u64 valid_blocks = 0;
    115 	int ret;
    116 	int fd, i;
    117 	unsigned int offset;
    118 
    119 	fd = open("dump_sit", O_CREAT|O_WRONLY|O_TRUNC, 0666);
    120 	ASSERT(fd >= 0);
    121 
    122 	snprintf(buf, BUF_SZ, "segment_type(0:HD, 1:WD, 2:CD, "
    123 						"3:HN, 4:WN, 5:CN)\n");
    124 	ret = write(fd, buf, strlen(buf));
    125 	ASSERT(ret >= 0);
    126 
    127 	for (segno = start_sit; segno < end_sit; segno++) {
    128 		se = get_seg_entry(sbi, segno);
    129 		offset = SIT_BLOCK_OFFSET(sit_i, segno);
    130 		memset(buf, 0, BUF_SZ);
    131 		snprintf(buf, BUF_SZ,
    132 		"\nsegno:%8u\tvblocks:%3u\tseg_type:%d\tsit_pack:%d\n\n",
    133 			segno, se->valid_blocks, se->type,
    134 			f2fs_test_bit(offset, sit_i->sit_bitmap) ? 2 : 1);
    135 
    136 		ret = write(fd, buf, strlen(buf));
    137 		ASSERT(ret >= 0);
    138 
    139 		if (se->valid_blocks == 0x0) {
    140 			free_segs++;
    141 			continue;
    142 		}
    143 
    144 		ASSERT(se->valid_blocks <= 512);
    145 		valid_blocks += se->valid_blocks;
    146 
    147 		for (i = 0; i < 64; i++) {
    148 			memset(buf, 0, BUF_SZ);
    149 			snprintf(buf, BUF_SZ, "  %02x",
    150 					*(se->cur_valid_map + i));
    151 			ret = write(fd, buf, strlen(buf));
    152 			ASSERT(ret >= 0);
    153 
    154 			if ((i + 1) % 16 == 0) {
    155 				snprintf(buf, BUF_SZ, "\n");
    156 				ret = write(fd, buf, strlen(buf));
    157 				ASSERT(ret >= 0);
    158 			}
    159 		}
    160 	}
    161 
    162 	memset(buf, 0, BUF_SZ);
    163 	snprintf(buf, BUF_SZ,
    164 		"valid_blocks:[0x%" PRIx64 "]\tvalid_segs:%d\t free_segs:%d\n",
    165 			valid_blocks,
    166 			SM_I(sbi)->main_segments - free_segs,
    167 			free_segs);
    168 	ret = write(fd, buf, strlen(buf));
    169 	ASSERT(ret >= 0);
    170 
    171 	close(fd);
    172 }
    173 
    174 void ssa_dump(struct f2fs_sb_info *sbi, int start_ssa, int end_ssa)
    175 {
    176 	struct f2fs_summary_block *sum_blk;
    177 	char buf[BUF_SZ];
    178 	int segno, type, i, ret;
    179 	int fd;
    180 
    181 	fd = open("dump_ssa", O_CREAT|O_WRONLY|O_TRUNC, 0666);
    182 	ASSERT(fd >= 0);
    183 
    184 	snprintf(buf, BUF_SZ, "Note: dump.f2fs -b blkaddr = 0x%x + segno * "
    185 				" 0x200 + offset\n",
    186 				sbi->sm_info->main_blkaddr);
    187 	ret = write(fd, buf, strlen(buf));
    188 	ASSERT(ret >= 0);
    189 
    190 	for (segno = start_ssa; segno < end_ssa; segno++) {
    191 		sum_blk = get_sum_block(sbi, segno, &type);
    192 
    193 		memset(buf, 0, BUF_SZ);
    194 		switch (type) {
    195 		case SEG_TYPE_CUR_NODE:
    196 			snprintf(buf, BUF_SZ, "\n\nsegno: %x, Current Node\n", segno);
    197 			break;
    198 		case SEG_TYPE_CUR_DATA:
    199 			snprintf(buf, BUF_SZ, "\n\nsegno: %x, Current Data\n", segno);
    200 			break;
    201 		case SEG_TYPE_NODE:
    202 			snprintf(buf, BUF_SZ, "\n\nsegno: %x, Node\n", segno);
    203 			break;
    204 		case SEG_TYPE_DATA:
    205 			snprintf(buf, BUF_SZ, "\n\nsegno: %x, Data\n", segno);
    206 			break;
    207 		}
    208 		ret = write(fd, buf, strlen(buf));
    209 		ASSERT(ret >= 0);
    210 
    211 		for (i = 0; i < ENTRIES_IN_SUM; i++) {
    212 			memset(buf, 0, BUF_SZ);
    213 			if (i % 10 == 0) {
    214 				buf[0] = '\n';
    215 				ret = write(fd, buf, strlen(buf));
    216 				ASSERT(ret >= 0);
    217 			}
    218 			snprintf(buf, BUF_SZ, "[%3d: %6x]", i,
    219 					le32_to_cpu(sum_blk->entries[i].nid));
    220 			ret = write(fd, buf, strlen(buf));
    221 			ASSERT(ret >= 0);
    222 		}
    223 		if (type == SEG_TYPE_NODE || type == SEG_TYPE_DATA ||
    224 					type == SEG_TYPE_MAX)
    225 			free(sum_blk);
    226 	}
    227 	close(fd);
    228 }
    229 
    230 static void dump_data_blk(struct f2fs_sb_info *sbi, __u64 offset, u32 blkaddr)
    231 {
    232 	char buf[F2FS_BLKSIZE];
    233 
    234 	if (blkaddr == NULL_ADDR)
    235 		return;
    236 
    237 	/* get data */
    238 	if (blkaddr == NEW_ADDR || !IS_VALID_BLK_ADDR(sbi, blkaddr)) {
    239 		memset(buf, 0, F2FS_BLKSIZE);
    240 	} else {
    241 		int ret;
    242 		ret = dev_read_block(buf, blkaddr);
    243 		ASSERT(ret >= 0);
    244 	}
    245 
    246 	/* write blkaddr */
    247 	dev_write_dump(buf, offset, F2FS_BLKSIZE);
    248 }
    249 
    250 static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype,
    251 						u32 nid, u64 *ofs)
    252 {
    253 	struct node_info ni;
    254 	struct f2fs_node *node_blk;
    255 	u32 skip = 0;
    256 	u32 i, idx;
    257 
    258 	switch (ntype) {
    259 	case TYPE_DIRECT_NODE:
    260 		skip = idx = ADDRS_PER_BLOCK;
    261 		break;
    262 	case TYPE_INDIRECT_NODE:
    263 		idx = NIDS_PER_BLOCK;
    264 		skip = idx * ADDRS_PER_BLOCK;
    265 		break;
    266 	case TYPE_DOUBLE_INDIRECT_NODE:
    267 		skip = 0;
    268 		idx = NIDS_PER_BLOCK;
    269 		break;
    270 	}
    271 
    272 	if (nid == 0) {
    273 		*ofs += skip;
    274 		return;
    275 	}
    276 
    277 	get_node_info(sbi, nid, &ni);
    278 
    279 	node_blk = calloc(BLOCK_SZ, 1);
    280 	ASSERT(node_blk);
    281 
    282 	dev_read_block(node_blk, ni.blk_addr);
    283 
    284 	for (i = 0; i < idx; i++, (*ofs)++) {
    285 		switch (ntype) {
    286 		case TYPE_DIRECT_NODE:
    287 			dump_data_blk(sbi, *ofs * F2FS_BLKSIZE,
    288 					le32_to_cpu(node_blk->dn.addr[i]));
    289 			break;
    290 		case TYPE_INDIRECT_NODE:
    291 			dump_node_blk(sbi, TYPE_DIRECT_NODE,
    292 					le32_to_cpu(node_blk->in.nid[i]), ofs);
    293 			break;
    294 		case TYPE_DOUBLE_INDIRECT_NODE:
    295 			dump_node_blk(sbi, TYPE_INDIRECT_NODE,
    296 					le32_to_cpu(node_blk->in.nid[i]), ofs);
    297 			break;
    298 		}
    299 	}
    300 	free(node_blk);
    301 }
    302 
    303 #ifdef HAVE_FSETXATTR
    304 static void dump_xattr(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk)
    305 {
    306 	void *xattr;
    307 	struct f2fs_xattr_entry *ent;
    308 	char xattr_name[F2FS_NAME_LEN] = {0};
    309 	int ret;
    310 
    311 	xattr = read_all_xattrs(sbi, node_blk);
    312 
    313 	list_for_each_xattr(ent, xattr) {
    314 		char *name = strndup(ent->e_name, ent->e_name_len);
    315 		void *value = ent->e_name + ent->e_name_len;
    316 
    317 		if (!name)
    318 			continue;
    319 
    320 		switch (ent->e_name_index) {
    321 		case F2FS_XATTR_INDEX_USER:
    322 			ret = snprintf(xattr_name, F2FS_NAME_LEN, "%s%s",
    323 				       XATTR_USER_PREFIX, name);
    324 			break;
    325 
    326 		case F2FS_XATTR_INDEX_SECURITY:
    327 			ret = snprintf(xattr_name, F2FS_NAME_LEN, "%s%s",
    328 				       XATTR_SECURITY_PREFIX, name);
    329 			break;
    330 		case F2FS_XATTR_INDEX_TRUSTED:
    331 			ret = snprintf(xattr_name, F2FS_NAME_LEN, "%s%s",
    332 				       XATTR_TRUSTED_PREFIX, name);
    333 			break;
    334 		default:
    335 			MSG(0, "Unknown xattr index 0x%x\n", ent->e_name_index);
    336 			free(name);
    337 			continue;
    338 		}
    339 		if (ret >= F2FS_NAME_LEN) {
    340 			MSG(0, "XATTR index 0x%x name too long\n", ent->e_name_index);
    341 			free(name);
    342 			continue;
    343 		}
    344 
    345 		DBG(1, "fd %d xattr_name %s\n", c.dump_fd, xattr_name);
    346 #if defined(__linux__)
    347 		ret = fsetxattr(c.dump_fd, xattr_name, value,
    348 				le16_to_cpu(ent->e_value_size), 0);
    349 #elif defined(__APPLE__)
    350 		ret = fsetxattr(c.dump_fd, xattr_name, value,
    351 				le16_to_cpu(ent->e_value_size), 0,
    352 				XATTR_CREATE);
    353 #endif
    354 		if (ret)
    355 			MSG(0, "XATTR index 0x%x set xattr failed error %d\n",
    356 			    ent->e_name_index, errno);
    357 
    358 		free(name);
    359 	}
    360 
    361 	free(xattr);
    362 }
    363 #else
    364 static void dump_xattr(struct f2fs_sb_info *UNUSED(sbi),
    365 				struct f2fs_node *UNUSED(node_blk))
    366 {
    367 	MSG(0, "XATTR does not support\n");
    368 }
    369 #endif
    370 
    371 static void dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
    372 					struct f2fs_node *node_blk)
    373 {
    374 	u32 i = 0;
    375 	u64 ofs = 0;
    376 
    377 	if((node_blk->i.i_inline & F2FS_INLINE_DATA)) {
    378 		DBG(3, "ino[0x%x] has inline data!\n", nid);
    379 		/* recover from inline data */
    380 		dev_write_dump(((unsigned char *)node_blk) + INLINE_DATA_OFFSET,
    381 						0, MAX_INLINE_DATA(node_blk));
    382 		return;
    383 	}
    384 
    385 	/* check data blocks in inode */
    386 	for (i = 0; i < ADDRS_PER_INODE(&node_blk->i); i++, ofs++)
    387 		dump_data_blk(sbi, ofs * F2FS_BLKSIZE, le32_to_cpu(
    388 			node_blk->i.i_addr[get_extra_isize(node_blk) + i]));
    389 
    390 	/* check node blocks in inode */
    391 	for (i = 0; i < 5; i++) {
    392 		if (i == 0 || i == 1)
    393 			dump_node_blk(sbi, TYPE_DIRECT_NODE,
    394 					le32_to_cpu(node_blk->i.i_nid[i]), &ofs);
    395 		else if (i == 2 || i == 3)
    396 			dump_node_blk(sbi, TYPE_INDIRECT_NODE,
    397 					le32_to_cpu(node_blk->i.i_nid[i]), &ofs);
    398 		else if (i == 4)
    399 			dump_node_blk(sbi, TYPE_DOUBLE_INDIRECT_NODE,
    400 					le32_to_cpu(node_blk->i.i_nid[i]), &ofs);
    401 		else
    402 			ASSERT(0);
    403 	}
    404 
    405 	dump_xattr(sbi, node_blk);
    406 }
    407 
    408 static void dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
    409 				struct f2fs_node *node_blk, int force)
    410 {
    411 	struct f2fs_inode *inode = &node_blk->i;
    412 	u32 imode = le16_to_cpu(inode->i_mode);
    413 	u32 namelen = le32_to_cpu(inode->i_namelen);
    414 	char name[F2FS_NAME_LEN + 1] = {0};
    415 	char path[1024] = {0};
    416 	char ans[255] = {0};
    417 	int is_encrypted = file_is_encrypt(inode);
    418 	int ret;
    419 
    420 	if (is_encrypted) {
    421 		MSG(force, "File is encrypted\n");
    422 		return;
    423 	}
    424 
    425 	if (!S_ISREG(imode) || namelen == 0 || namelen > F2FS_NAME_LEN) {
    426 		MSG(force, "Not a regular file or wrong name info\n\n");
    427 		return;
    428 	}
    429 	if (force)
    430 		goto dump;
    431 
    432 	printf("Do you want to dump this file into ./lost_found/? [Y/N] ");
    433 	ret = scanf("%s", ans);
    434 	ASSERT(ret >= 0);
    435 
    436 	if (!strcasecmp(ans, "y")) {
    437 dump:
    438 		ret = system("mkdir -p ./lost_found");
    439 		ASSERT(ret >= 0);
    440 
    441 		/* make a file */
    442 		strncpy(name, (const char *)inode->i_name, namelen);
    443 		name[namelen] = 0;
    444 		sprintf(path, "./lost_found/%s", name);
    445 
    446 		c.dump_fd = open(path, O_TRUNC|O_CREAT|O_RDWR, 0666);
    447 		ASSERT(c.dump_fd >= 0);
    448 
    449 		/* dump file's data */
    450 		dump_inode_blk(sbi, ni->ino, node_blk);
    451 
    452 		/* adjust file size */
    453 		ret = ftruncate(c.dump_fd, le32_to_cpu(inode->i_size));
    454 		ASSERT(ret >= 0);
    455 
    456 		close(c.dump_fd);
    457 	}
    458 }
    459 
    460 static bool is_sit_bitmap_set(struct f2fs_sb_info *sbi, u32 blk_addr)
    461 {
    462 	struct seg_entry *se;
    463 	u32 offset;
    464 
    465 	se = get_seg_entry(sbi, GET_SEGNO(sbi, blk_addr));
    466 	offset = OFFSET_IN_SEG(sbi, blk_addr);
    467 
    468 	return f2fs_test_bit(offset,
    469 			(const char *)se->cur_valid_map) != 0;
    470 }
    471 
    472 void dump_node(struct f2fs_sb_info *sbi, nid_t nid, int force)
    473 {
    474 	struct node_info ni;
    475 	struct f2fs_node *node_blk;
    476 
    477 	get_node_info(sbi, nid, &ni);
    478 
    479 	node_blk = calloc(BLOCK_SZ, 1);
    480 	ASSERT(node_blk);
    481 
    482 	dev_read_block(node_blk, ni.blk_addr);
    483 
    484 	DBG(1, "Node ID               [0x%x]\n", nid);
    485 	DBG(1, "nat_entry.block_addr  [0x%x]\n", ni.blk_addr);
    486 	DBG(1, "nat_entry.version     [0x%x]\n", ni.version);
    487 	DBG(1, "nat_entry.ino         [0x%x]\n", ni.ino);
    488 
    489 	if (ni.blk_addr == 0x0)
    490 		MSG(force, "Invalid nat entry\n\n");
    491 	else if (!is_sit_bitmap_set(sbi, ni.blk_addr))
    492 		MSG(force, "Invalid node blk addr\n\n");
    493 
    494 	DBG(1, "node_blk.footer.ino [0x%x]\n", le32_to_cpu(node_blk->footer.ino));
    495 	DBG(1, "node_blk.footer.nid [0x%x]\n", le32_to_cpu(node_blk->footer.nid));
    496 
    497 	if (le32_to_cpu(node_blk->footer.ino) == ni.ino &&
    498 			le32_to_cpu(node_blk->footer.nid) == ni.nid) {
    499 		print_node_info(sbi, node_blk, force);
    500 
    501 		if (ni.ino == ni.nid)
    502 			dump_file(sbi, &ni, node_blk, force);
    503 	} else {
    504 		print_node_info(sbi, node_blk, force);
    505 		MSG(force, "Invalid (i)node block\n\n");
    506 	}
    507 
    508 	free(node_blk);
    509 }
    510 
    511 static void dump_node_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr)
    512 {
    513 	struct f2fs_node *node_blk;
    514 	int ret;
    515 
    516 	node_blk = calloc(BLOCK_SZ, 1);
    517 	ASSERT(node_blk);
    518 
    519 	ret = dev_read_block(node_blk, blk_addr);
    520 	ASSERT(ret >= 0);
    521 
    522 	if (c.dbg_lv > 0)
    523 		print_node_info(sbi, node_blk, 0);
    524 	else
    525 		print_inode_info(sbi, node_blk, 1);
    526 
    527 	free(node_blk);
    528 }
    529 
    530 static void dump_data_offset(u32 blk_addr, int ofs_in_node)
    531 {
    532 	struct f2fs_node *node_blk;
    533 	unsigned int indirect_blks = 2 * NIDS_PER_BLOCK + 4;
    534 	unsigned int bidx = 0;
    535 	unsigned int node_ofs;
    536 	int ret;
    537 
    538 	node_blk = calloc(BLOCK_SZ, 1);
    539 	ASSERT(node_blk);
    540 
    541 	ret = dev_read_block(node_blk, blk_addr);
    542 	ASSERT(ret >= 0);
    543 
    544 	node_ofs = ofs_of_node(node_blk);
    545 
    546 	if (node_ofs == 0)
    547 		goto got_it;
    548 
    549 	if (node_ofs > 0 && node_ofs <= 2) {
    550 		bidx = node_ofs - 1;
    551 	} else if (node_ofs <= indirect_blks) {
    552 		int dec = (node_ofs - 4) / (NIDS_PER_BLOCK + 1);
    553 		bidx = node_ofs - 2 - dec;
    554 	} else {
    555 		int dec = (node_ofs - indirect_blks - 3) / (NIDS_PER_BLOCK + 1);
    556 		bidx = node_ofs - 5 - dec;
    557 	}
    558 	bidx = bidx * ADDRS_PER_BLOCK + ADDRS_PER_INODE(&node_blk->i);
    559 got_it:
    560 	bidx +=  ofs_in_node;
    561 
    562 	setlocale(LC_ALL, "");
    563 	MSG(0, " - Data offset       : 0x%x (4KB), %'u (bytes)\n",
    564 				bidx, bidx * 4096);
    565 	free(node_blk);
    566 }
    567 
    568 static void dump_node_offset(u32 blk_addr)
    569 {
    570 	struct f2fs_node *node_blk;
    571 	int ret;
    572 
    573 	node_blk = calloc(BLOCK_SZ, 1);
    574 	ASSERT(node_blk);
    575 
    576 	ret = dev_read_block(node_blk, blk_addr);
    577 	ASSERT(ret >= 0);
    578 
    579 	MSG(0, " - Node offset       : 0x%x\n", ofs_of_node(node_blk));
    580 	free(node_blk);
    581 }
    582 
    583 static int has_dirent(u32 blk_addr, int is_inline, int *enc_name)
    584 {
    585 	struct f2fs_node *node_blk;
    586 	int ret, is_dentry = 0;
    587 
    588 	node_blk = calloc(BLOCK_SZ, 1);
    589 	ASSERT(node_blk);
    590 
    591 	ret = dev_read_block(node_blk, blk_addr);
    592 	ASSERT(ret >= 0);
    593 
    594 	if (IS_INODE(node_blk) && S_ISDIR(le16_to_cpu(node_blk->i.i_mode)))
    595 		is_dentry = 1;
    596 
    597 	if (is_inline && !(node_blk->i.i_inline & F2FS_INLINE_DENTRY))
    598 		is_dentry = 0;
    599 
    600 	*enc_name = file_is_encrypt(&node_blk->i);
    601 
    602 	free(node_blk);
    603 
    604 	return is_dentry;
    605 }
    606 
    607 static void dump_dirent(u32 blk_addr, int is_inline, int enc_name)
    608 {
    609 	struct f2fs_dentry_ptr d;
    610 	void *inline_dentry, *blk;
    611 	int ret, i = 0;
    612 
    613 	blk = calloc(BLOCK_SZ, 1);
    614 	ASSERT(blk);
    615 
    616 	ret = dev_read_block(blk, blk_addr);
    617 	ASSERT(ret >= 0);
    618 
    619 	if (is_inline) {
    620 		inline_dentry = inline_data_addr((struct f2fs_node *)blk);
    621 		make_dentry_ptr(&d, blk, inline_dentry, 2);
    622 	} else {
    623 		make_dentry_ptr(&d, NULL, blk, 1);
    624 	}
    625 
    626 	DBG(1, "%sDentry block:\n", is_inline ? "Inline " : "");
    627 
    628 	while (i < d.max) {
    629 		struct f2fs_dir_entry *de;
    630 		unsigned char en[F2FS_NAME_LEN + 1];
    631 		u16 en_len, name_len;
    632 		int enc;
    633 
    634 		if (!test_bit_le(i, d.bitmap)) {
    635 			i++;
    636 			continue;
    637 		}
    638 
    639 		de = &d.dentry[i];
    640 
    641 		if (!de->name_len) {
    642 			i++;
    643 			continue;
    644 		}
    645 
    646 		name_len = le16_to_cpu(de->name_len);
    647 		enc = enc_name;
    648 
    649 		if (de->file_type == F2FS_FT_DIR) {
    650 			if ((d.filename[i][0] == '.' && name_len == 1) ||
    651 				(d.filename[i][0] == '.' &&
    652 				d.filename[i][1] == '.' && name_len == 2)) {
    653 				enc = 0;
    654 			}
    655 		}
    656 
    657 		en_len = convert_encrypted_name(d.filename[i],
    658 				le16_to_cpu(de->name_len), en, enc);
    659 		en[en_len] = '\0';
    660 
    661 		DBG(1, "bitmap pos[0x%x] name[%s] len[0x%x] hash[0x%x] ino[0x%x] type[0x%x]\n",
    662 				i, en,
    663 				le16_to_cpu(de->name_len),
    664 				le32_to_cpu(de->hash_code),
    665 				le32_to_cpu(de->ino),
    666 				de->file_type);
    667 
    668 		i += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
    669 	}
    670 
    671 	free(blk);
    672 }
    673 
    674 int dump_info_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr)
    675 {
    676 	nid_t nid;
    677 	int type;
    678 	struct f2fs_summary sum_entry;
    679 	struct node_info ni, ino_ni;
    680 	int enc_name;
    681 	int ret = 0;
    682 
    683 	MSG(0, "\n== Dump data from block address ==\n\n");
    684 
    685 	if (blk_addr < SM_I(sbi)->seg0_blkaddr) {
    686 		MSG(0, "\nFS Reserved Area for SEG #0: ");
    687 		ret = -EINVAL;
    688 	} else if (blk_addr < SIT_I(sbi)->sit_base_addr) {
    689 		MSG(0, "\nFS Metadata Area: ");
    690 		ret = -EINVAL;
    691 	} else if (blk_addr < NM_I(sbi)->nat_blkaddr) {
    692 		MSG(0, "\nFS SIT Area: ");
    693 		ret = -EINVAL;
    694 	} else if (blk_addr < SM_I(sbi)->ssa_blkaddr) {
    695 		MSG(0, "\nFS NAT Area: ");
    696 		ret = -EINVAL;
    697 	} else if (blk_addr < SM_I(sbi)->main_blkaddr) {
    698 		MSG(0, "\nFS SSA Area: ");
    699 		ret = -EINVAL;
    700 	} else if (blk_addr > __end_block_addr(sbi)) {
    701 		MSG(0, "\nOut of address space: ");
    702 		ret = -EINVAL;
    703 	}
    704 
    705 	if (ret) {
    706 		MSG(0, "User data is from 0x%x to 0x%x\n\n",
    707 			SM_I(sbi)->main_blkaddr,
    708 			__end_block_addr(sbi));
    709 		return ret;
    710 	}
    711 
    712 	if (!is_sit_bitmap_set(sbi, blk_addr))
    713 		MSG(0, "\nblkaddr is not valid\n");
    714 
    715 	type = get_sum_entry(sbi, blk_addr, &sum_entry);
    716 	nid = le32_to_cpu(sum_entry.nid);
    717 
    718 	get_node_info(sbi, nid, &ni);
    719 
    720 	DBG(1, "Note: blkaddr = main_blkaddr + segno * 512 + offset\n");
    721 	DBG(1, "Block_addr            [0x%x]\n", blk_addr);
    722 	DBG(1, " - Segno              [0x%x]\n", GET_SEGNO(sbi, blk_addr));
    723 	DBG(1, " - Offset             [0x%x]\n", OFFSET_IN_SEG(sbi, blk_addr));
    724 	DBG(1, "SUM.nid               [0x%x]\n", nid);
    725 	DBG(1, "SUM.type              [%s]\n", type >= 0 ?
    726 						seg_type_name[type] :
    727 						"Broken");
    728 	DBG(1, "SUM.version           [%d]\n", sum_entry.version);
    729 	DBG(1, "SUM.ofs_in_node       [0x%x]\n", sum_entry.ofs_in_node);
    730 	DBG(1, "NAT.blkaddr           [0x%x]\n", ni.blk_addr);
    731 	DBG(1, "NAT.ino               [0x%x]\n", ni.ino);
    732 
    733 	get_node_info(sbi, ni.ino, &ino_ni);
    734 
    735 	/* inode block address */
    736 	if (ni.blk_addr == NULL_ADDR || ino_ni.blk_addr == NULL_ADDR) {
    737 		MSG(0, "FS Userdata Area: Obsolete block from 0x%x\n",
    738 			blk_addr);
    739 		return -EINVAL;
    740 	}
    741 
    742 	/* print inode */
    743 	if (c.dbg_lv > 0)
    744 		dump_node_from_blkaddr(sbi, ino_ni.blk_addr);
    745 
    746 	if (type == SEG_TYPE_CUR_DATA || type == SEG_TYPE_DATA) {
    747 		MSG(0, "FS Userdata Area: Data block from 0x%x\n", blk_addr);
    748 		MSG(0, " - Direct node block : id = 0x%x from 0x%x\n",
    749 					nid, ni.blk_addr);
    750 		MSG(0, " - Inode block       : id = 0x%x from 0x%x\n",
    751 					ni.ino, ino_ni.blk_addr);
    752 		dump_node_from_blkaddr(sbi, ino_ni.blk_addr);
    753 		dump_data_offset(ni.blk_addr,
    754 			le16_to_cpu(sum_entry.ofs_in_node));
    755 
    756 		if (has_dirent(ino_ni.blk_addr, 0, &enc_name))
    757 			dump_dirent(blk_addr, 0, enc_name);
    758 	} else {
    759 		MSG(0, "FS Userdata Area: Node block from 0x%x\n", blk_addr);
    760 		if (ni.ino == ni.nid) {
    761 			MSG(0, " - Inode block       : id = 0x%x from 0x%x\n",
    762 					ni.ino, ino_ni.blk_addr);
    763 			dump_node_from_blkaddr(sbi, ino_ni.blk_addr);
    764 
    765 			if (has_dirent(ino_ni.blk_addr, 1, &enc_name))
    766 				dump_dirent(blk_addr, 1, enc_name);
    767 		} else {
    768 			MSG(0, " - Node block        : id = 0x%x from 0x%x\n",
    769 					nid, ni.blk_addr);
    770 			MSG(0, " - Inode block       : id = 0x%x from 0x%x\n",
    771 					ni.ino, ino_ni.blk_addr);
    772 			dump_node_from_blkaddr(sbi, ino_ni.blk_addr);
    773 			dump_node_offset(ni.blk_addr);
    774 		}
    775 	}
    776 
    777 	return 0;
    778 }
    779