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