• 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(F2FS_BLKSIZE, 1);
47 	ASSERT(nat_block);
48 	node_block = (struct f2fs_node *)calloc(F2FS_BLKSIZE, 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(F2FS_NODE_FOOTER(node_block)->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(F2FS_NODE_FOOTER(node_block)->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_folder_contents(struct f2fs_sb_info * sbi,u8 * bitmap,struct f2fs_dir_entry * dentry,__u8 (* filenames)[F2FS_SLOT_LEN],int max)250 static void dump_folder_contents(struct f2fs_sb_info *sbi, u8 *bitmap,
251 				struct f2fs_dir_entry *dentry,
252 				__u8 (*filenames)[F2FS_SLOT_LEN], int max)
253 {
254 	int i;
255 	int name_len;
256 
257 	for (i = 0; i < max; i++) {
258 		if (test_bit_le(i, bitmap) == 0)
259 			continue;
260 		name_len = le16_to_cpu(dentry[i].name_len);
261 		if (name_len == 1 && filenames[i][0] == '.')
262 			continue;
263 		if (name_len == 2 && filenames[i][0] == '.' && filenames[i][1] == '.')
264 			continue;
265 		dump_node(sbi, le32_to_cpu(dentry[i].ino), 1, NULL, 0, 1);
266 	}
267 }
268 
dump_data_blk(struct f2fs_sb_info * sbi,__u64 offset,u32 blkaddr,bool is_folder)269 static void dump_data_blk(struct f2fs_sb_info *sbi, __u64 offset, u32 blkaddr, bool is_folder)
270 {
271 	char buf[F2FS_BLKSIZE];
272 
273 	if (c.show_file_map) {
274 		if (c.show_file_map_max_offset < offset) {
275 			ASSERT(blkaddr == NULL_ADDR);
276 			return;
277 		}
278 		if (!is_valid_data_blkaddr(blkaddr)) {
279 			print_extent(false);
280 			dump_extent.blk = 0;
281 			dump_extent.len = 1;
282 			print_extent(false);
283 		} else if (dump_extent.len == 0) {
284 			dump_extent.blk = blkaddr;
285 			dump_extent.len = 1;
286 		} else if (dump_extent.blk + dump_extent.len == blkaddr) {
287 			dump_extent.len++;
288 		} else {
289 			print_extent(false);
290 			dump_extent.blk = blkaddr;
291 			dump_extent.len = 1;
292 		}
293 		return;
294 	}
295 
296 	if (blkaddr == NULL_ADDR)
297 		return;
298 
299 	/* get data */
300 	if (blkaddr == NEW_ADDR ||
301 			!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC)) {
302 		memset(buf, 0, F2FS_BLKSIZE);
303 	} else {
304 		int ret;
305 
306 		ret = dev_read_block(buf, blkaddr);
307 		ASSERT(ret >= 0);
308 	}
309 
310 	if (is_folder) {
311 		struct f2fs_dentry_block *d = (struct f2fs_dentry_block *) buf;
312 
313 		dump_folder_contents(sbi, d->dentry_bitmap, F2FS_DENTRY_BLOCK_DENTRIES(d),
314 					F2FS_DENTRY_BLOCK_FILENAMES(d), NR_DENTRY_IN_BLOCK);
315 	} else {
316 		/* write blkaddr */
317 		dev_write_dump(buf, offset, F2FS_BLKSIZE);
318 	}
319 }
320 
dump_node_blk(struct f2fs_sb_info * sbi,int ntype,u32 nid,u32 addr_per_block,u64 * ofs,int is_dir)321 static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype,
322 				u32 nid, u32 addr_per_block, u64 *ofs, int is_dir)
323 {
324 	struct node_info ni;
325 	struct f2fs_node *node_blk;
326 	u32 skip = 0;
327 	u32 i, idx = 0;
328 
329 	switch (ntype) {
330 	case TYPE_DIRECT_NODE:
331 		skip = idx = addr_per_block;
332 		break;
333 	case TYPE_INDIRECT_NODE:
334 		idx = NIDS_PER_BLOCK;
335 		skip = idx * addr_per_block;
336 		break;
337 	case TYPE_DOUBLE_INDIRECT_NODE:
338 		skip = 0;
339 		idx = NIDS_PER_BLOCK;
340 		break;
341 	}
342 
343 	if (nid == 0) {
344 		*ofs += skip;
345 		return;
346 	}
347 
348 	get_node_info(sbi, nid, &ni);
349 
350 	node_blk = calloc(F2FS_BLKSIZE, 1);
351 	ASSERT(node_blk);
352 
353 	dev_read_block(node_blk, ni.blk_addr);
354 
355 	for (i = 0; i < idx; i++) {
356 		switch (ntype) {
357 		case TYPE_DIRECT_NODE:
358 			dump_data_blk(sbi, *ofs * F2FS_BLKSIZE,
359 					le32_to_cpu(node_blk->dn.addr[i]), is_dir);
360 			(*ofs)++;
361 			break;
362 		case TYPE_INDIRECT_NODE:
363 			dump_node_blk(sbi, TYPE_DIRECT_NODE,
364 					le32_to_cpu(node_blk->in.nid[i]),
365 					addr_per_block,
366 					ofs, is_dir);
367 			break;
368 		case TYPE_DOUBLE_INDIRECT_NODE:
369 			dump_node_blk(sbi, TYPE_INDIRECT_NODE,
370 					le32_to_cpu(node_blk->in.nid[i]),
371 					addr_per_block,
372 					ofs, is_dir);
373 			break;
374 		}
375 	}
376 	free(node_blk);
377 }
378 
379 #ifdef HAVE_FSETXATTR
dump_xattr(struct f2fs_sb_info * sbi,struct f2fs_node * node_blk,int is_dir)380 static void dump_xattr(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk, int is_dir)
381 {
382 	void *xattr;
383 	void *last_base_addr;
384 	struct f2fs_xattr_entry *ent;
385 	char xattr_name[F2FS_NAME_LEN] = {0};
386 	int ret;
387 
388 	xattr = read_all_xattrs(sbi, node_blk, true);
389 	if (!xattr)
390 		return;
391 
392 	last_base_addr = (void *)xattr + XATTR_SIZE(&node_blk->i);
393 
394 	list_for_each_xattr(ent, xattr) {
395 		char *name = strndup(ent->e_name, ent->e_name_len);
396 		void *value = ent->e_name + ent->e_name_len;
397 
398 		if ((void *)(ent) + sizeof(__u32) > last_base_addr ||
399 			(void *)XATTR_NEXT_ENTRY(ent) > last_base_addr) {
400 			MSG(0, "xattr entry crosses the end of xattr space\n");
401 			break;
402 		}
403 
404 		if (!name)
405 			continue;
406 
407 		switch (ent->e_name_index) {
408 		case F2FS_XATTR_INDEX_USER:
409 			ret = snprintf(xattr_name, F2FS_NAME_LEN, "%s%s",
410 				       XATTR_USER_PREFIX, name);
411 			break;
412 
413 		case F2FS_XATTR_INDEX_SECURITY:
414 			ret = snprintf(xattr_name, F2FS_NAME_LEN, "%s%s",
415 				       XATTR_SECURITY_PREFIX, name);
416 			break;
417 		case F2FS_XATTR_INDEX_TRUSTED:
418 			ret = snprintf(xattr_name, F2FS_NAME_LEN, "%s%s",
419 				       XATTR_TRUSTED_PREFIX, name);
420 			break;
421 		default:
422 			MSG(0, "Unknown xattr index 0x%x\n", ent->e_name_index);
423 			free(name);
424 			continue;
425 		}
426 		if (ret >= F2FS_NAME_LEN) {
427 			MSG(0, "XATTR index 0x%x name too long\n", ent->e_name_index);
428 			free(name);
429 			continue;
430 		}
431 
432 		DBG(1, "fd %d xattr_name %s\n", c.dump_fd, xattr_name);
433 #if defined(__linux__)
434 		if (is_dir) {
435 			ret = setxattr(".", xattr_name, value,
436 							le16_to_cpu(ent->e_value_size), 0);
437 		} else {
438 			ret = fsetxattr(c.dump_fd, xattr_name, value,
439 							le16_to_cpu(ent->e_value_size), 0);
440 		}
441 
442 #elif defined(__APPLE__)
443 		if (is_dir) {
444 			ret = setxattr(".", xattr_name, value,
445 					le16_to_cpu(ent->e_value_size), 0,
446 					XATTR_CREATE);
447 		} else {
448 			ret = fsetxattr(c.dump_fd, xattr_name, value,
449 					le16_to_cpu(ent->e_value_size), 0,
450 					XATTR_CREATE);
451 		}
452 #endif
453 		if (ret)
454 			MSG(0, "XATTR index 0x%x set xattr failed error %d\n",
455 			    ent->e_name_index, errno);
456 
457 		free(name);
458 	}
459 
460 	free(xattr);
461 }
462 #else
dump_xattr(struct f2fs_sb_info * UNUSED (sbi),struct f2fs_node * UNUSED (node_blk),int UNUSED (is_dir))463 static void dump_xattr(struct f2fs_sb_info *UNUSED(sbi),
464 				struct f2fs_node *UNUSED(node_blk), int UNUSED(is_dir))
465 {
466 	MSG(0, "XATTR does not support\n");
467 }
468 #endif
469 
dump_inode_blk(struct f2fs_sb_info * sbi,u32 nid,struct f2fs_node * node_blk)470 static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
471 					struct f2fs_node *node_blk)
472 {
473 	u32 i = 0;
474 	u64 ofs = 0;
475 	u32 addr_per_block;
476 	bool is_dir = S_ISDIR(le16_to_cpu(node_blk->i.i_mode));
477 	int ret = 0;
478 
479 	if ((node_blk->i.i_inline & F2FS_INLINE_DATA)) {
480 		DBG(3, "ino[0x%x] has inline data!\n", nid);
481 		/* recover from inline data */
482 		dev_write_dump(((unsigned char *)node_blk) + INLINE_DATA_OFFSET,
483 						0, MAX_INLINE_DATA(node_blk));
484 		ret = -1;
485 		goto dump_xattr;
486 	}
487 
488 	if ((node_blk->i.i_inline & F2FS_INLINE_DENTRY)) {
489 		void *inline_dentry = inline_data_addr(node_blk);
490 		struct f2fs_dentry_ptr d;
491 
492 		make_dentry_ptr(&d, node_blk, inline_dentry, 2);
493 
494 		DBG(3, "ino[0x%x] has inline dentries!\n", nid);
495 		/* recover from inline dentry */
496 		dump_folder_contents(sbi, d.bitmap, d.dentry, d.filename, d.max);
497 		ret = -1;
498 		goto dump_xattr;
499 	}
500 
501 	c.show_file_map_max_offset = f2fs_max_file_offset(&node_blk->i);
502 	addr_per_block = ADDRS_PER_BLOCK(&node_blk->i);
503 
504 	/* check data blocks in inode */
505 	for (i = 0; i < ADDRS_PER_INODE(&node_blk->i); i++, ofs++)
506 		dump_data_blk(sbi, ofs * F2FS_BLKSIZE, le32_to_cpu(
507 			node_blk->i.i_addr[get_extra_isize(node_blk) + i]), is_dir);
508 
509 	/* check node blocks in inode */
510 	for (i = 0; i < 5; i++) {
511 		if (i == 0 || i == 1)
512 			dump_node_blk(sbi, TYPE_DIRECT_NODE,
513 					le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)),
514 					addr_per_block,
515 					&ofs,
516 					is_dir);
517 		else if (i == 2 || i == 3)
518 			dump_node_blk(sbi, TYPE_INDIRECT_NODE,
519 					le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)),
520 					addr_per_block,
521 					&ofs,
522 					is_dir);
523 		else if (i == 4)
524 			dump_node_blk(sbi, TYPE_DOUBLE_INDIRECT_NODE,
525 					le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)),
526 					addr_per_block,
527 					&ofs,
528 					is_dir);
529 		else
530 			ASSERT(0);
531 	}
532 	/* last block in extent cache */
533 	print_extent(true);
534 dump_xattr:
535 	dump_xattr(sbi, node_blk, is_dir);
536 	return ret;
537 }
538 
dump_file(struct f2fs_sb_info * sbi,struct node_info * ni,struct f2fs_node * node_blk,char * path)539 static void dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
540 				struct f2fs_node *node_blk, char *path)
541 {
542 	struct f2fs_inode *inode = &node_blk->i;
543 	int ret;
544 
545 	c.dump_fd = open(path, O_TRUNC|O_CREAT|O_RDWR, 0666);
546 	ASSERT(c.dump_fd >= 0);
547 
548 	/* dump file's data */
549 	dump_inode_blk(sbi, ni->ino, node_blk);
550 
551 	/* adjust file size */
552 	ret = ftruncate(c.dump_fd, le32_to_cpu(inode->i_size));
553 	ASSERT(ret >= 0);
554 
555 	close(c.dump_fd);
556 }
557 
dump_folder(struct f2fs_sb_info * sbi,struct node_info * ni,struct f2fs_node * node_blk,char * path,int is_root)558 static void dump_folder(struct f2fs_sb_info *sbi, struct node_info *ni,
559 				struct f2fs_node *node_blk, char *path, int is_root)
560 {
561 	if (!is_root) {
562 #if defined(__MINGW32__)
563 		if (mkdir(path) < 0 && errno != EEXIST) {
564 			MSG(0, "Failed to create directory %s\n", path);
565 			return;
566 		}
567 #else
568 		if (mkdir(path, 0777) < 0 && errno != EEXIST) {
569 			MSG(0, "Failed to create directory %s\n", path);
570 			return;
571 		}
572 #endif
573 		ASSERT(chdir(path) == 0);
574 	}
575 	/* dump folder data */
576 	dump_inode_blk(sbi, ni->ino, node_blk);
577 	if (!is_root)
578 		ASSERT(chdir("..") == 0);
579 }
580 
dump_filesystem(struct f2fs_sb_info * sbi,struct node_info * ni,struct f2fs_node * node_blk,int force,char * base_path,bool is_base,bool allow_folder)581 static int dump_filesystem(struct f2fs_sb_info *sbi, struct node_info *ni,
582 				struct f2fs_node *node_blk, int force, char *base_path,
583 				bool is_base, bool allow_folder)
584 {
585 	struct f2fs_inode *inode = &node_blk->i;
586 	u32 imode = le16_to_cpu(inode->i_mode);
587 	u32 namelen = le32_to_cpu(inode->i_namelen);
588 	char name[F2FS_NAME_LEN + 1] = {0};
589 	char path[1024] = {0};
590 	char ans[255] = {0};
591 	int is_encrypted = file_is_encrypt(inode);
592 	int is_root = sbi->root_ino_num == ni->nid;
593 	int ret;
594 
595 	if (is_encrypted) {
596 		MSG(force, "File is encrypted\n");
597 		return -1;
598 	}
599 
600 	if ((!S_ISREG(imode) && !S_ISLNK(imode) && !(S_ISDIR(imode) && allow_folder))) {
601 		MSG(force, "Not a valid file type\n\n");
602 		return -1;
603 	}
604 	if (!is_root && (namelen == 0 || namelen > F2FS_NAME_LEN)) {
605 		MSG(force, "Wrong name info\n\n");
606 		return -1;
607 	}
608 	base_path = base_path ?: "./lost_found";
609 	if (force)
610 		goto dump;
611 
612 	/* dump file's data */
613 	if (c.show_file_map)
614 		return dump_inode_blk(sbi, ni->ino, node_blk);
615 
616 	printf("Do you want to dump this %s into %s/? [Y/N] ",
617 			S_ISREG(imode) || S_ISLNK(imode) ? "file" : "folder",
618 			base_path);
619 	ret = scanf("%s", ans);
620 	ASSERT(ret >= 0);
621 
622 	if (!strcasecmp(ans, "y")) {
623 dump:
624 		if (is_base) {
625 			ASSERT(getcwd(path, sizeof(path)) != NULL);
626 #if defined(__MINGW32__)
627 			ret = mkdir(base_path);
628 #else
629 			ret = mkdir(base_path, 0777);
630 #endif
631 
632 			ASSERT(ret == 0 || errno == EEXIST);
633 			ASSERT(chdir(base_path) == 0);
634 		}
635 
636 		/* make a file */
637 		if (!is_root) {
638 			strncpy(name, (const char *)inode->i_name, namelen);
639 			name[namelen] = 0;
640 		}
641 
642 		if (S_ISREG(imode) || S_ISLNK(imode)) {
643 			dump_file(sbi, ni, node_blk, name);
644 		} else {
645 			dump_folder(sbi, ni, node_blk, name, is_root);
646 		}
647 
648 #if !defined(__MINGW32__)
649 		/* fix up mode/owner */
650 		if (c.preserve_perms) {
651 			if (is_root)
652 				strncpy(name, ".", 2);
653 			ASSERT(chmod(name, imode) == 0);
654 			ASSERT(chown(name, inode->i_uid, inode->i_gid) == 0);
655 		}
656 #endif
657 		if (is_base)
658 			ASSERT(chdir(path) == 0);
659 	}
660 	return 0;
661 }
662 
is_sit_bitmap_set(struct f2fs_sb_info * sbi,u32 blk_addr)663 static bool is_sit_bitmap_set(struct f2fs_sb_info *sbi, u32 blk_addr)
664 {
665 	struct seg_entry *se;
666 	u32 offset;
667 
668 	se = get_seg_entry(sbi, GET_SEGNO(sbi, blk_addr));
669 	offset = OFFSET_IN_SEG(sbi, blk_addr);
670 
671 	return f2fs_test_bit(offset,
672 			(const char *)se->cur_valid_map) != 0;
673 }
674 
dump_node_scan_disk(struct f2fs_sb_info * sbi,nid_t nid)675 void dump_node_scan_disk(struct f2fs_sb_info *sbi, nid_t nid)
676 {
677 	struct f2fs_node *node_blk;
678 	pgoff_t blkaddr;
679 	int ret;
680 	pgoff_t start_blkaddr = SM_I(sbi)->main_blkaddr;
681 	pgoff_t end_blkaddr = start_blkaddr +
682 		(SM_I(sbi)->main_segments << sbi->log_blocks_per_seg);
683 
684 	node_blk = calloc(F2FS_BLKSIZE, 1);
685 	ASSERT(node_blk);
686 	MSG(0, "Info: scan all nid: %u from block_addr [%lu: %lu]\n",
687 			nid, start_blkaddr, end_blkaddr);
688 
689 	for (blkaddr = start_blkaddr; blkaddr < end_blkaddr; blkaddr++) {
690 		struct seg_entry *se = get_seg_entry(sbi, GET_SEGNO(sbi, blkaddr));
691 		if (se->type < CURSEG_HOT_NODE)
692 			continue;
693 
694 		ret = dev_read_block(node_blk, blkaddr);
695 		ASSERT(ret >= 0);
696 		if (le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino) != nid ||
697 				le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->nid) != nid)
698 			continue;
699 		MSG(0, "Info: nid: %u, blkaddr: %lu\n", nid, blkaddr);
700 		MSG(0, "node_blk.footer.flag [0x%x]\n", le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->flag));
701 		MSG(0, "node_blk.footer.cp_ver [%x]\n", (u32)(cpver_of_node(node_blk)));
702 		print_inode_info(sbi, node_blk, 0);
703 	}
704 
705 	free(node_blk);
706 }
707 
dump_node(struct f2fs_sb_info * sbi,nid_t nid,int force,char * base_path,int base,int allow_folder)708 int dump_node(struct f2fs_sb_info *sbi, nid_t nid, int force, char *base_path, int base, int allow_folder)
709 {
710 	struct node_info ni;
711 	struct f2fs_node *node_blk;
712 	int ret = 0;
713 
714 	get_node_info(sbi, nid, &ni);
715 
716 	node_blk = calloc(F2FS_BLKSIZE, 1);
717 	ASSERT(node_blk);
718 
719 	DBG(1, "Node ID               [0x%x]\n", nid);
720 	DBG(1, "nat_entry.block_addr  [0x%x]\n", ni.blk_addr);
721 	DBG(1, "nat_entry.version     [0x%x]\n", ni.version);
722 	DBG(1, "nat_entry.ino         [0x%x]\n", ni.ino);
723 
724 	if (!f2fs_is_valid_blkaddr(sbi, ni.blk_addr, DATA_GENERIC)) {
725 		MSG(force, "Invalid node blkaddr: %u\n\n", ni.blk_addr);
726 		goto out;
727 	}
728 
729 	dev_read_block(node_blk, ni.blk_addr);
730 
731 	if (!is_sit_bitmap_set(sbi, ni.blk_addr))
732 		MSG(force, "Invalid sit bitmap, %u\n\n", ni.blk_addr);
733 
734 	DBG(1, "node_blk.footer.ino [0x%x]\n", le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino));
735 	DBG(1, "node_blk.footer.nid [0x%x]\n", le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->nid));
736 
737 	if (le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino) == ni.ino &&
738 			le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->nid) == ni.nid) {
739 		if (!c.show_file_map)
740 			print_node_info(sbi, node_blk, force);
741 
742 		if (ni.ino == ni.nid)
743 			ret = dump_filesystem(sbi, &ni, node_blk, force, base_path, base, allow_folder);
744 	} else {
745 		print_node_info(sbi, node_blk, force);
746 		MSG(force, "Invalid (i)node block\n\n");
747 	}
748 out:
749 	free(node_blk);
750 	return ret;
751 }
752 
dump_node_from_blkaddr(struct f2fs_sb_info * sbi,u32 blk_addr)753 static void dump_node_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr)
754 {
755 	struct f2fs_node *node_blk;
756 	int ret;
757 
758 	node_blk = calloc(F2FS_BLKSIZE, 1);
759 	ASSERT(node_blk);
760 
761 	ret = dev_read_block(node_blk, blk_addr);
762 	ASSERT(ret >= 0);
763 
764 	if (c.dbg_lv > 0)
765 		print_node_info(sbi, node_blk, 0);
766 	else
767 		print_inode_info(sbi, node_blk, 1);
768 
769 	free(node_blk);
770 }
771 
start_bidx_of_node(unsigned int node_ofs,struct f2fs_node * node_blk)772 unsigned int start_bidx_of_node(unsigned int node_ofs,
773 					struct f2fs_node *node_blk)
774 {
775 	unsigned int indirect_blks = 2 * NIDS_PER_BLOCK + 4;
776 	unsigned int bidx;
777 
778 	if (node_ofs == 0)
779 		return 0;
780 
781 	if (node_ofs <= 2) {
782 		bidx = node_ofs - 1;
783 	} else if (node_ofs <= indirect_blks) {
784 		int dec = (node_ofs - 4) / (NIDS_PER_BLOCK + 1);
785 		bidx = node_ofs - 2 - dec;
786 	} else {
787 		int dec = (node_ofs - indirect_blks - 3) / (NIDS_PER_BLOCK + 1);
788 		bidx = node_ofs - 5 - dec;
789 	}
790 	return bidx * ADDRS_PER_BLOCK(&node_blk->i) +
791 				ADDRS_PER_INODE(&node_blk->i);
792 }
793 
dump_data_offset(u32 blk_addr,int ofs_in_node)794 static void dump_data_offset(u32 blk_addr, int ofs_in_node)
795 {
796 	struct f2fs_node *node_blk;
797 	unsigned int bidx;
798 	unsigned int node_ofs;
799 	int ret;
800 
801 	node_blk = calloc(F2FS_BLKSIZE, 1);
802 	ASSERT(node_blk);
803 
804 	ret = dev_read_block(node_blk, blk_addr);
805 	ASSERT(ret >= 0);
806 
807 	node_ofs = ofs_of_node(node_blk);
808 
809 	bidx = start_bidx_of_node(node_ofs, node_blk);
810 	bidx +=  ofs_in_node;
811 
812 	setlocale(LC_ALL, "");
813 	MSG(0, " - Data offset       : 0x%x (BLOCK), %'u (bytes)\n",
814 				bidx, bidx * F2FS_BLKSIZE);
815 	free(node_blk);
816 }
817 
dump_node_offset(u32 blk_addr)818 static void dump_node_offset(u32 blk_addr)
819 {
820 	struct f2fs_node *node_blk;
821 	int ret;
822 
823 	node_blk = calloc(F2FS_BLKSIZE, 1);
824 	ASSERT(node_blk);
825 
826 	ret = dev_read_block(node_blk, blk_addr);
827 	ASSERT(ret >= 0);
828 
829 	MSG(0, " - Node offset       : 0x%x\n", ofs_of_node(node_blk));
830 	free(node_blk);
831 }
832 
has_dirent(u32 blk_addr,int is_inline,int * enc_name)833 static int has_dirent(u32 blk_addr, int is_inline, int *enc_name)
834 {
835 	struct f2fs_node *node_blk;
836 	int ret, is_dentry = 0;
837 
838 	node_blk = calloc(F2FS_BLKSIZE, 1);
839 	ASSERT(node_blk);
840 
841 	ret = dev_read_block(node_blk, blk_addr);
842 	ASSERT(ret >= 0);
843 
844 	if (IS_INODE(node_blk) && S_ISDIR(le16_to_cpu(node_blk->i.i_mode)))
845 		is_dentry = 1;
846 
847 	if (is_inline && !(node_blk->i.i_inline & F2FS_INLINE_DENTRY))
848 		is_dentry = 0;
849 
850 	*enc_name = file_is_encrypt(&node_blk->i);
851 
852 	free(node_blk);
853 
854 	return is_dentry;
855 }
856 
dump_dirent(u32 blk_addr,int is_inline,int enc_name)857 static void dump_dirent(u32 blk_addr, int is_inline, int enc_name)
858 {
859 	struct f2fs_dentry_ptr d;
860 	void *inline_dentry, *blk;
861 	int ret, i = 0;
862 
863 	blk = calloc(F2FS_BLKSIZE, 1);
864 	ASSERT(blk);
865 
866 	ret = dev_read_block(blk, blk_addr);
867 	ASSERT(ret >= 0);
868 
869 	if (is_inline) {
870 		inline_dentry = inline_data_addr((struct f2fs_node *)blk);
871 		make_dentry_ptr(&d, blk, inline_dentry, 2);
872 	} else {
873 		make_dentry_ptr(&d, NULL, blk, 1);
874 	}
875 
876 	DBG(1, "%sDentry block:\n", is_inline ? "Inline " : "");
877 
878 	while (i < d.max) {
879 		struct f2fs_dir_entry *de;
880 		char en[F2FS_PRINT_NAMELEN];
881 		u16 name_len;
882 		int enc;
883 
884 		if (!test_bit_le(i, d.bitmap)) {
885 			i++;
886 			continue;
887 		}
888 
889 		de = &d.dentry[i];
890 
891 		if (!de->name_len) {
892 			i++;
893 			continue;
894 		}
895 
896 		name_len = le16_to_cpu(de->name_len);
897 		enc = enc_name;
898 
899 		if (de->file_type == F2FS_FT_DIR) {
900 			if ((d.filename[i][0] == '.' && name_len == 1) ||
901 				(d.filename[i][0] == '.' &&
902 				d.filename[i][1] == '.' && name_len == 2)) {
903 				enc = 0;
904 			}
905 		}
906 
907 		pretty_print_filename(d.filename[i], name_len, en, enc);
908 
909 		DBG(1, "bitmap pos[0x%x] name[%s] len[0x%x] hash[0x%x] ino[0x%x] type[0x%x]\n",
910 				i, en,
911 				name_len,
912 				le32_to_cpu(de->hash_code),
913 				le32_to_cpu(de->ino),
914 				de->file_type);
915 
916 		i += GET_DENTRY_SLOTS(name_len);
917 	}
918 
919 	free(blk);
920 }
921 
dump_info_from_blkaddr(struct f2fs_sb_info * sbi,u32 blk_addr)922 int dump_info_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr)
923 {
924 	nid_t nid;
925 	int type;
926 	struct f2fs_summary sum_entry;
927 	struct node_info ni, ino_ni;
928 	int enc_name;
929 	int ret = 0;
930 
931 	MSG(0, "\n== Dump data from block address ==\n\n");
932 
933 	if (blk_addr < SM_I(sbi)->seg0_blkaddr) {
934 		MSG(0, "\nFS Reserved Area for SEG #0: ");
935 		ret = -EINVAL;
936 	} else if (blk_addr < SIT_I(sbi)->sit_base_addr) {
937 		MSG(0, "\nFS Metadata Area: ");
938 		ret = -EINVAL;
939 	} else if (blk_addr < NM_I(sbi)->nat_blkaddr) {
940 		MSG(0, "\nFS SIT Area: ");
941 		ret = -EINVAL;
942 	} else if (blk_addr < SM_I(sbi)->ssa_blkaddr) {
943 		MSG(0, "\nFS NAT Area: ");
944 		ret = -EINVAL;
945 	} else if (blk_addr < SM_I(sbi)->main_blkaddr) {
946 		MSG(0, "\nFS SSA Area: ");
947 		ret = -EINVAL;
948 	} else if (blk_addr > __end_block_addr(sbi)) {
949 		MSG(0, "\nOut of address space: ");
950 		ret = -EINVAL;
951 	}
952 
953 	if (ret) {
954 		MSG(0, "User data is from 0x%x to 0x%x\n\n",
955 			SM_I(sbi)->main_blkaddr,
956 			__end_block_addr(sbi));
957 		return ret;
958 	}
959 
960 	if (!is_sit_bitmap_set(sbi, blk_addr))
961 		MSG(0, "\nblkaddr is not valid\n");
962 
963 	type = get_sum_entry(sbi, blk_addr, &sum_entry);
964 	nid = le32_to_cpu(sum_entry.nid);
965 
966 	get_node_info(sbi, nid, &ni);
967 
968 	DBG(1, "Note: blkaddr = main_blkaddr + segno * 512 + offset\n");
969 	DBG(1, "Block_addr            [0x%x]\n", blk_addr);
970 	DBG(1, " - Segno              [0x%x]\n", GET_SEGNO(sbi, blk_addr));
971 	DBG(1, " - Offset             [0x%x]\n", OFFSET_IN_SEG(sbi, blk_addr));
972 	DBG(1, "SUM.nid               [0x%x]\n", nid);
973 	DBG(1, "SUM.type              [%s]\n", type >= 0 ?
974 						seg_type_name[type] :
975 						"Broken");
976 	DBG(1, "SUM.version           [%d]\n", sum_entry.version);
977 	DBG(1, "SUM.ofs_in_node       [0x%x]\n", sum_entry.ofs_in_node);
978 	DBG(1, "NAT.blkaddr           [0x%x]\n", ni.blk_addr);
979 	DBG(1, "NAT.ino               [0x%x]\n", ni.ino);
980 
981 	get_node_info(sbi, ni.ino, &ino_ni);
982 
983 	/* inode block address */
984 	if (ni.blk_addr == NULL_ADDR || ino_ni.blk_addr == NULL_ADDR) {
985 		MSG(0, "FS Userdata Area: Obsolete block from 0x%x\n",
986 			blk_addr);
987 		return -EINVAL;
988 	}
989 
990 	/* print inode */
991 	if (c.dbg_lv > 0)
992 		dump_node_from_blkaddr(sbi, ino_ni.blk_addr);
993 
994 	if (type == SEG_TYPE_CUR_DATA || type == SEG_TYPE_DATA) {
995 		MSG(0, "FS Userdata Area: Data block from 0x%x\n", blk_addr);
996 		MSG(0, " - Direct node block : id = 0x%x from 0x%x\n",
997 					nid, ni.blk_addr);
998 		MSG(0, " - Inode block       : id = 0x%x from 0x%x\n",
999 					ni.ino, ino_ni.blk_addr);
1000 		dump_node_from_blkaddr(sbi, ino_ni.blk_addr);
1001 		dump_data_offset(ni.blk_addr,
1002 			le16_to_cpu(sum_entry.ofs_in_node));
1003 
1004 		if (has_dirent(ino_ni.blk_addr, 0, &enc_name))
1005 			dump_dirent(blk_addr, 0, enc_name);
1006 	} else {
1007 		MSG(0, "FS Userdata Area: Node block from 0x%x\n", blk_addr);
1008 		if (ni.ino == ni.nid) {
1009 			MSG(0, " - Inode block       : id = 0x%x from 0x%x\n",
1010 					ni.ino, ino_ni.blk_addr);
1011 			dump_node_from_blkaddr(sbi, ino_ni.blk_addr);
1012 
1013 			if (has_dirent(ino_ni.blk_addr, 1, &enc_name))
1014 				dump_dirent(blk_addr, 1, enc_name);
1015 		} else {
1016 			MSG(0, " - Node block        : id = 0x%x from 0x%x\n",
1017 					nid, ni.blk_addr);
1018 			MSG(0, " - Inode block       : id = 0x%x from 0x%x\n",
1019 					ni.ino, ino_ni.blk_addr);
1020 			dump_node_from_blkaddr(sbi, ino_ni.blk_addr);
1021 			dump_node_offset(ni.blk_addr);
1022 		}
1023 	}
1024 
1025 	return 0;
1026 }
1027