• 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 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 
nat_dump(struct f2fs_sb_info * sbi,nid_t start_nat,nid_t end_nat)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 
sit_dump(struct f2fs_sb_info * sbi,unsigned int start_sit,unsigned int end_sit)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 
ssa_dump(struct f2fs_sb_info * sbi,int start_ssa,int end_ssa)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 
dump_data_blk(struct f2fs_sb_info * sbi,__u64 offset,u32 blkaddr)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 
dump_node_blk(struct f2fs_sb_info * sbi,int ntype,u32 nid,u64 * ofs)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 = 0;
257 
258 	get_node_info(sbi, nid, &ni);
259 
260 	node_blk = calloc(BLOCK_SZ, 1);
261 	ASSERT(node_blk);
262 
263 	dev_read_block(node_blk, ni.blk_addr);
264 
265 	switch (ntype) {
266 	case TYPE_DIRECT_NODE:
267 		skip = idx = ADDRS_PER_BLOCK(&node_blk->i);
268 		break;
269 	case TYPE_INDIRECT_NODE:
270 		idx = NIDS_PER_BLOCK;
271 		skip = idx * ADDRS_PER_BLOCK(&node_blk->i);
272 		break;
273 	case TYPE_DOUBLE_INDIRECT_NODE:
274 		skip = 0;
275 		idx = NIDS_PER_BLOCK;
276 		break;
277 	}
278 
279 	if (nid == 0) {
280 		*ofs += skip;
281 		goto out;
282 	}
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 out:
301 	free(node_blk);
302 }
303 
304 #ifdef HAVE_FSETXATTR
dump_xattr(struct f2fs_sb_info * sbi,struct f2fs_node * node_blk)305 static void dump_xattr(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk)
306 {
307 	void *xattr;
308 	struct f2fs_xattr_entry *ent;
309 	char xattr_name[F2FS_NAME_LEN] = {0};
310 	int ret;
311 
312 	xattr = read_all_xattrs(sbi, node_blk);
313 	if (!xattr)
314 		return;
315 
316 	list_for_each_xattr(ent, xattr) {
317 		char *name = strndup(ent->e_name, ent->e_name_len);
318 		void *value = ent->e_name + ent->e_name_len;
319 
320 		if (!name)
321 			continue;
322 
323 		switch (ent->e_name_index) {
324 		case F2FS_XATTR_INDEX_USER:
325 			ret = snprintf(xattr_name, F2FS_NAME_LEN, "%s%s",
326 				       XATTR_USER_PREFIX, name);
327 			break;
328 
329 		case F2FS_XATTR_INDEX_SECURITY:
330 			ret = snprintf(xattr_name, F2FS_NAME_LEN, "%s%s",
331 				       XATTR_SECURITY_PREFIX, name);
332 			break;
333 		case F2FS_XATTR_INDEX_TRUSTED:
334 			ret = snprintf(xattr_name, F2FS_NAME_LEN, "%s%s",
335 				       XATTR_TRUSTED_PREFIX, name);
336 			break;
337 		default:
338 			MSG(0, "Unknown xattr index 0x%x\n", ent->e_name_index);
339 			free(name);
340 			continue;
341 		}
342 		if (ret >= F2FS_NAME_LEN) {
343 			MSG(0, "XATTR index 0x%x name too long\n", ent->e_name_index);
344 			free(name);
345 			continue;
346 		}
347 
348 		DBG(1, "fd %d xattr_name %s\n", c.dump_fd, xattr_name);
349 #if defined(__linux__)
350 		ret = fsetxattr(c.dump_fd, xattr_name, value,
351 				le16_to_cpu(ent->e_value_size), 0);
352 #elif defined(__APPLE__)
353 		ret = fsetxattr(c.dump_fd, xattr_name, value,
354 				le16_to_cpu(ent->e_value_size), 0,
355 				XATTR_CREATE);
356 #endif
357 		if (ret)
358 			MSG(0, "XATTR index 0x%x set xattr failed error %d\n",
359 			    ent->e_name_index, errno);
360 
361 		free(name);
362 	}
363 
364 	free(xattr);
365 }
366 #else
dump_xattr(struct f2fs_sb_info * UNUSED (sbi),struct f2fs_node * UNUSED (node_blk))367 static void dump_xattr(struct f2fs_sb_info *UNUSED(sbi),
368 				struct f2fs_node *UNUSED(node_blk))
369 {
370 	MSG(0, "XATTR does not support\n");
371 }
372 #endif
373 
dump_inode_blk(struct f2fs_sb_info * sbi,u32 nid,struct f2fs_node * node_blk)374 static void dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
375 					struct f2fs_node *node_blk)
376 {
377 	u32 i = 0;
378 	u64 ofs = 0;
379 
380 	if((node_blk->i.i_inline & F2FS_INLINE_DATA)) {
381 		DBG(3, "ino[0x%x] has inline data!\n", nid);
382 		/* recover from inline data */
383 		dev_write_dump(((unsigned char *)node_blk) + INLINE_DATA_OFFSET,
384 						0, MAX_INLINE_DATA(node_blk));
385 		return;
386 	}
387 
388 	/* check data blocks in inode */
389 	for (i = 0; i < ADDRS_PER_INODE(&node_blk->i); i++, ofs++)
390 		dump_data_blk(sbi, ofs * F2FS_BLKSIZE, le32_to_cpu(
391 			node_blk->i.i_addr[get_extra_isize(node_blk) + i]));
392 
393 	/* check node blocks in inode */
394 	for (i = 0; i < 5; i++) {
395 		if (i == 0 || i == 1)
396 			dump_node_blk(sbi, TYPE_DIRECT_NODE,
397 					le32_to_cpu(node_blk->i.i_nid[i]), &ofs);
398 		else if (i == 2 || i == 3)
399 			dump_node_blk(sbi, TYPE_INDIRECT_NODE,
400 					le32_to_cpu(node_blk->i.i_nid[i]), &ofs);
401 		else if (i == 4)
402 			dump_node_blk(sbi, TYPE_DOUBLE_INDIRECT_NODE,
403 					le32_to_cpu(node_blk->i.i_nid[i]), &ofs);
404 		else
405 			ASSERT(0);
406 	}
407 
408 	dump_xattr(sbi, node_blk);
409 }
410 
dump_file(struct f2fs_sb_info * sbi,struct node_info * ni,struct f2fs_node * node_blk,int force)411 static void dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
412 				struct f2fs_node *node_blk, int force)
413 {
414 	struct f2fs_inode *inode = &node_blk->i;
415 	u32 imode = le16_to_cpu(inode->i_mode);
416 	u32 namelen = le32_to_cpu(inode->i_namelen);
417 	char name[F2FS_NAME_LEN + 1] = {0};
418 	char path[1024] = {0};
419 	char ans[255] = {0};
420 	int is_encrypted = file_is_encrypt(inode);
421 	int ret;
422 
423 	if (is_encrypted) {
424 		MSG(force, "File is encrypted\n");
425 		return;
426 	}
427 
428 	if ((!S_ISREG(imode) && !S_ISLNK(imode)) ||
429 				namelen == 0 || namelen > F2FS_NAME_LEN) {
430 		MSG(force, "Not a regular file or wrong name info\n\n");
431 		return;
432 	}
433 	if (force)
434 		goto dump;
435 
436 	printf("Do you want to dump this file into ./lost_found/? [Y/N] ");
437 	ret = scanf("%s", ans);
438 	ASSERT(ret >= 0);
439 
440 	if (!strcasecmp(ans, "y")) {
441 dump:
442 		ret = system("mkdir -p ./lost_found");
443 		ASSERT(ret >= 0);
444 
445 		/* make a file */
446 		strncpy(name, (const char *)inode->i_name, namelen);
447 		name[namelen] = 0;
448 		sprintf(path, "./lost_found/%s", name);
449 
450 		c.dump_fd = open(path, O_TRUNC|O_CREAT|O_RDWR, 0666);
451 		ASSERT(c.dump_fd >= 0);
452 
453 		/* dump file's data */
454 		dump_inode_blk(sbi, ni->ino, node_blk);
455 
456 		/* adjust file size */
457 		ret = ftruncate(c.dump_fd, le32_to_cpu(inode->i_size));
458 		ASSERT(ret >= 0);
459 
460 		close(c.dump_fd);
461 	}
462 }
463 
is_sit_bitmap_set(struct f2fs_sb_info * sbi,u32 blk_addr)464 static bool is_sit_bitmap_set(struct f2fs_sb_info *sbi, u32 blk_addr)
465 {
466 	struct seg_entry *se;
467 	u32 offset;
468 
469 	se = get_seg_entry(sbi, GET_SEGNO(sbi, blk_addr));
470 	offset = OFFSET_IN_SEG(sbi, blk_addr);
471 
472 	return f2fs_test_bit(offset,
473 			(const char *)se->cur_valid_map) != 0;
474 }
475 
dump_node(struct f2fs_sb_info * sbi,nid_t nid,int force)476 void dump_node(struct f2fs_sb_info *sbi, nid_t nid, int force)
477 {
478 	struct node_info ni;
479 	struct f2fs_node *node_blk;
480 
481 	get_node_info(sbi, nid, &ni);
482 
483 	node_blk = calloc(BLOCK_SZ, 1);
484 	ASSERT(node_blk);
485 
486 	DBG(1, "Node ID               [0x%x]\n", nid);
487 	DBG(1, "nat_entry.block_addr  [0x%x]\n", ni.blk_addr);
488 	DBG(1, "nat_entry.version     [0x%x]\n", ni.version);
489 	DBG(1, "nat_entry.ino         [0x%x]\n", ni.ino);
490 
491 	if (!IS_VALID_BLK_ADDR(sbi, ni.blk_addr)) {
492 		MSG(force, "Invalid node blkaddr: %u\n\n", ni.blk_addr);
493 		goto out;
494 	}
495 
496 	dev_read_block(node_blk, ni.blk_addr);
497 
498 	if (ni.blk_addr == 0x0)
499 		MSG(force, "Invalid nat entry\n\n");
500 	else if (!is_sit_bitmap_set(sbi, ni.blk_addr))
501 		MSG(force, "Invalid sit bitmap, %u\n\n", ni.blk_addr);
502 
503 	DBG(1, "node_blk.footer.ino [0x%x]\n", le32_to_cpu(node_blk->footer.ino));
504 	DBG(1, "node_blk.footer.nid [0x%x]\n", le32_to_cpu(node_blk->footer.nid));
505 
506 	if (le32_to_cpu(node_blk->footer.ino) == ni.ino &&
507 			le32_to_cpu(node_blk->footer.nid) == ni.nid) {
508 		print_node_info(sbi, node_blk, force);
509 
510 		if (ni.ino == ni.nid)
511 			dump_file(sbi, &ni, node_blk, force);
512 	} else {
513 		print_node_info(sbi, node_blk, force);
514 		MSG(force, "Invalid (i)node block\n\n");
515 	}
516 out:
517 	free(node_blk);
518 }
519 
dump_node_from_blkaddr(struct f2fs_sb_info * sbi,u32 blk_addr)520 static void dump_node_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr)
521 {
522 	struct f2fs_node *node_blk;
523 	int ret;
524 
525 	node_blk = calloc(BLOCK_SZ, 1);
526 	ASSERT(node_blk);
527 
528 	ret = dev_read_block(node_blk, blk_addr);
529 	ASSERT(ret >= 0);
530 
531 	if (c.dbg_lv > 0)
532 		print_node_info(sbi, node_blk, 0);
533 	else
534 		print_inode_info(sbi, node_blk, 1);
535 
536 	free(node_blk);
537 }
538 
start_bidx_of_node(unsigned int node_ofs,struct f2fs_node * node_blk)539 unsigned int start_bidx_of_node(unsigned int node_ofs,
540 					struct f2fs_node *node_blk)
541 {
542 	unsigned int indirect_blks = 2 * NIDS_PER_BLOCK + 4;
543 	unsigned int bidx;
544 
545 	if (node_ofs == 0)
546 		return 0;
547 
548 	if (node_ofs <= 2) {
549 		bidx = node_ofs - 1;
550 	} else if (node_ofs <= indirect_blks) {
551 		int dec = (node_ofs - 4) / (NIDS_PER_BLOCK + 1);
552 		bidx = node_ofs - 2 - dec;
553 	} else {
554 		int dec = (node_ofs - indirect_blks - 3) / (NIDS_PER_BLOCK + 1);
555 		bidx = node_ofs - 5 - dec;
556 	}
557 	return bidx * ADDRS_PER_BLOCK(&node_blk->i) +
558 				ADDRS_PER_INODE(&node_blk->i);
559 }
560 
dump_data_offset(u32 blk_addr,int ofs_in_node)561 static void dump_data_offset(u32 blk_addr, int ofs_in_node)
562 {
563 	struct f2fs_node *node_blk;
564 	unsigned int bidx;
565 	unsigned int node_ofs;
566 	int ret;
567 
568 	node_blk = calloc(BLOCK_SZ, 1);
569 	ASSERT(node_blk);
570 
571 	ret = dev_read_block(node_blk, blk_addr);
572 	ASSERT(ret >= 0);
573 
574 	node_ofs = ofs_of_node(node_blk);
575 
576 	bidx = start_bidx_of_node(node_ofs, node_blk);
577 	bidx +=  ofs_in_node;
578 
579 	setlocale(LC_ALL, "");
580 	MSG(0, " - Data offset       : 0x%x (4KB), %'u (bytes)\n",
581 				bidx, bidx * 4096);
582 	free(node_blk);
583 }
584 
dump_node_offset(u32 blk_addr)585 static void dump_node_offset(u32 blk_addr)
586 {
587 	struct f2fs_node *node_blk;
588 	int ret;
589 
590 	node_blk = calloc(BLOCK_SZ, 1);
591 	ASSERT(node_blk);
592 
593 	ret = dev_read_block(node_blk, blk_addr);
594 	ASSERT(ret >= 0);
595 
596 	MSG(0, " - Node offset       : 0x%x\n", ofs_of_node(node_blk));
597 	free(node_blk);
598 }
599 
has_dirent(u32 blk_addr,int is_inline,int * enc_name)600 static int has_dirent(u32 blk_addr, int is_inline, int *enc_name)
601 {
602 	struct f2fs_node *node_blk;
603 	int ret, is_dentry = 0;
604 
605 	node_blk = calloc(BLOCK_SZ, 1);
606 	ASSERT(node_blk);
607 
608 	ret = dev_read_block(node_blk, blk_addr);
609 	ASSERT(ret >= 0);
610 
611 	if (IS_INODE(node_blk) && S_ISDIR(le16_to_cpu(node_blk->i.i_mode)))
612 		is_dentry = 1;
613 
614 	if (is_inline && !(node_blk->i.i_inline & F2FS_INLINE_DENTRY))
615 		is_dentry = 0;
616 
617 	*enc_name = file_is_encrypt(&node_blk->i);
618 
619 	free(node_blk);
620 
621 	return is_dentry;
622 }
623 
dump_dirent(u32 blk_addr,int is_inline,int enc_name)624 static void dump_dirent(u32 blk_addr, int is_inline, int enc_name)
625 {
626 	struct f2fs_dentry_ptr d;
627 	void *inline_dentry, *blk;
628 	int ret, i = 0;
629 
630 	blk = calloc(BLOCK_SZ, 1);
631 	ASSERT(blk);
632 
633 	ret = dev_read_block(blk, blk_addr);
634 	ASSERT(ret >= 0);
635 
636 	if (is_inline) {
637 		inline_dentry = inline_data_addr((struct f2fs_node *)blk);
638 		make_dentry_ptr(&d, blk, inline_dentry, 2);
639 	} else {
640 		make_dentry_ptr(&d, NULL, blk, 1);
641 	}
642 
643 	DBG(1, "%sDentry block:\n", is_inline ? "Inline " : "");
644 
645 	while (i < d.max) {
646 		struct f2fs_dir_entry *de;
647 		char en[F2FS_PRINT_NAMELEN];
648 		u16 name_len;
649 		int enc;
650 
651 		if (!test_bit_le(i, d.bitmap)) {
652 			i++;
653 			continue;
654 		}
655 
656 		de = &d.dentry[i];
657 
658 		if (!de->name_len) {
659 			i++;
660 			continue;
661 		}
662 
663 		name_len = le16_to_cpu(de->name_len);
664 		enc = enc_name;
665 
666 		if (de->file_type == F2FS_FT_DIR) {
667 			if ((d.filename[i][0] == '.' && name_len == 1) ||
668 				(d.filename[i][0] == '.' &&
669 				d.filename[i][1] == '.' && name_len == 2)) {
670 				enc = 0;
671 			}
672 		}
673 
674 		pretty_print_filename(d.filename[i], name_len, en, enc);
675 
676 		DBG(1, "bitmap pos[0x%x] name[%s] len[0x%x] hash[0x%x] ino[0x%x] type[0x%x]\n",
677 				i, en,
678 				name_len,
679 				le32_to_cpu(de->hash_code),
680 				le32_to_cpu(de->ino),
681 				de->file_type);
682 
683 		i += GET_DENTRY_SLOTS(name_len);
684 	}
685 
686 	free(blk);
687 }
688 
dump_info_from_blkaddr(struct f2fs_sb_info * sbi,u32 blk_addr)689 int dump_info_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr)
690 {
691 	nid_t nid;
692 	int type;
693 	struct f2fs_summary sum_entry;
694 	struct node_info ni, ino_ni;
695 	int enc_name;
696 	int ret = 0;
697 
698 	MSG(0, "\n== Dump data from block address ==\n\n");
699 
700 	if (blk_addr < SM_I(sbi)->seg0_blkaddr) {
701 		MSG(0, "\nFS Reserved Area for SEG #0: ");
702 		ret = -EINVAL;
703 	} else if (blk_addr < SIT_I(sbi)->sit_base_addr) {
704 		MSG(0, "\nFS Metadata Area: ");
705 		ret = -EINVAL;
706 	} else if (blk_addr < NM_I(sbi)->nat_blkaddr) {
707 		MSG(0, "\nFS SIT Area: ");
708 		ret = -EINVAL;
709 	} else if (blk_addr < SM_I(sbi)->ssa_blkaddr) {
710 		MSG(0, "\nFS NAT Area: ");
711 		ret = -EINVAL;
712 	} else if (blk_addr < SM_I(sbi)->main_blkaddr) {
713 		MSG(0, "\nFS SSA Area: ");
714 		ret = -EINVAL;
715 	} else if (blk_addr > __end_block_addr(sbi)) {
716 		MSG(0, "\nOut of address space: ");
717 		ret = -EINVAL;
718 	}
719 
720 	if (ret) {
721 		MSG(0, "User data is from 0x%x to 0x%x\n\n",
722 			SM_I(sbi)->main_blkaddr,
723 			__end_block_addr(sbi));
724 		return ret;
725 	}
726 
727 	if (!is_sit_bitmap_set(sbi, blk_addr))
728 		MSG(0, "\nblkaddr is not valid\n");
729 
730 	type = get_sum_entry(sbi, blk_addr, &sum_entry);
731 	nid = le32_to_cpu(sum_entry.nid);
732 
733 	get_node_info(sbi, nid, &ni);
734 
735 	DBG(1, "Note: blkaddr = main_blkaddr + segno * 512 + offset\n");
736 	DBG(1, "Block_addr            [0x%x]\n", blk_addr);
737 	DBG(1, " - Segno              [0x%x]\n", GET_SEGNO(sbi, blk_addr));
738 	DBG(1, " - Offset             [0x%x]\n", OFFSET_IN_SEG(sbi, blk_addr));
739 	DBG(1, "SUM.nid               [0x%x]\n", nid);
740 	DBG(1, "SUM.type              [%s]\n", type >= 0 ?
741 						seg_type_name[type] :
742 						"Broken");
743 	DBG(1, "SUM.version           [%d]\n", sum_entry.version);
744 	DBG(1, "SUM.ofs_in_node       [0x%x]\n", sum_entry.ofs_in_node);
745 	DBG(1, "NAT.blkaddr           [0x%x]\n", ni.blk_addr);
746 	DBG(1, "NAT.ino               [0x%x]\n", ni.ino);
747 
748 	get_node_info(sbi, ni.ino, &ino_ni);
749 
750 	/* inode block address */
751 	if (ni.blk_addr == NULL_ADDR || ino_ni.blk_addr == NULL_ADDR) {
752 		MSG(0, "FS Userdata Area: Obsolete block from 0x%x\n",
753 			blk_addr);
754 		return -EINVAL;
755 	}
756 
757 	/* print inode */
758 	if (c.dbg_lv > 0)
759 		dump_node_from_blkaddr(sbi, ino_ni.blk_addr);
760 
761 	if (type == SEG_TYPE_CUR_DATA || type == SEG_TYPE_DATA) {
762 		MSG(0, "FS Userdata Area: Data block from 0x%x\n", blk_addr);
763 		MSG(0, " - Direct node block : id = 0x%x from 0x%x\n",
764 					nid, ni.blk_addr);
765 		MSG(0, " - Inode block       : id = 0x%x from 0x%x\n",
766 					ni.ino, ino_ni.blk_addr);
767 		dump_node_from_blkaddr(sbi, ino_ni.blk_addr);
768 		dump_data_offset(ni.blk_addr,
769 			le16_to_cpu(sum_entry.ofs_in_node));
770 
771 		if (has_dirent(ino_ni.blk_addr, 0, &enc_name))
772 			dump_dirent(blk_addr, 0, enc_name);
773 	} else {
774 		MSG(0, "FS Userdata Area: Node block from 0x%x\n", blk_addr);
775 		if (ni.ino == ni.nid) {
776 			MSG(0, " - Inode block       : id = 0x%x from 0x%x\n",
777 					ni.ino, ino_ni.blk_addr);
778 			dump_node_from_blkaddr(sbi, ino_ni.blk_addr);
779 
780 			if (has_dirent(ino_ni.blk_addr, 1, &enc_name))
781 				dump_dirent(blk_addr, 1, enc_name);
782 		} else {
783 			MSG(0, " - Node block        : id = 0x%x from 0x%x\n",
784 					nid, ni.blk_addr);
785 			MSG(0, " - Inode block       : id = 0x%x from 0x%x\n",
786 					ni.ino, ino_ni.blk_addr);
787 			dump_node_from_blkaddr(sbi, ino_ni.blk_addr);
788 			dump_node_offset(ni.blk_addr);
789 		}
790 	}
791 
792 	return 0;
793 }
794