xref: /aosp_15_r20/external/f2fs-tools/fsck/dump.c (revision 59bfda1f02d633cd6b8b69f31eee485d40f6eef6)
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	128
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 	struct node_footer *footer;
42 	nid_t nid;
43 	pgoff_t block_addr;
44 	char buf[BUF_SZ];
45 	int fd, ret, pack;
46 
47 	nat_block = (struct f2fs_nat_block *)calloc(F2FS_BLKSIZE, 1);
48 	ASSERT(nat_block);
49 	node_block = (struct f2fs_node *)calloc(F2FS_BLKSIZE, 1);
50 	ASSERT(node_block);
51 	footer = F2FS_NODE_FOOTER(node_block);
52 
53 	fd = open("dump_nat", O_CREAT|O_WRONLY|O_TRUNC, 0666);
54 	ASSERT(fd >= 0);
55 
56 	for (nid = start_nat; nid < end_nat; nid++) {
57 		struct f2fs_nat_entry raw_nat;
58 		struct node_info ni;
59 		int len;
60 		if(nid == 0 || nid == F2FS_NODE_INO(sbi) ||
61 					nid == F2FS_META_INO(sbi))
62 			continue;
63 
64 		ni.nid = nid;
65 		block_addr = current_nat_addr(sbi, nid, &pack);
66 
67 		if (lookup_nat_in_journal(sbi, nid, &raw_nat) >= 0) {
68 			node_info_from_raw_nat(&ni, &raw_nat);
69 			ret = dev_read_block(node_block, ni.blk_addr);
70 			ASSERT(ret >= 0);
71 			if (ni.blk_addr != 0x0) {
72 				len = snprintf(buf, BUF_SZ,
73 					"nid:%5u\tino:%5u\toffset:%5u"
74 					"\tblkaddr:%10u\tpack:%d"
75 					"\tcp_ver:0x%" PRIx64 "\n",
76 					ni.nid, ni.ino,
77 					le32_to_cpu(footer->flag) >> OFFSET_BIT_SHIFT,
78 					ni.blk_addr, pack,
79 					le64_to_cpu(footer->cp_ver));
80 				ret = write(fd, buf, len);
81 				ASSERT(ret >= 0);
82 			}
83 		} else {
84 			ret = dev_read_block(nat_block, block_addr);
85 			ASSERT(ret >= 0);
86 			node_info_from_raw_nat(&ni,
87 					&nat_block->entries[nid % NAT_ENTRY_PER_BLOCK]);
88 			if (ni.blk_addr == 0)
89 				continue;
90 
91 			ret = dev_read_block(node_block, ni.blk_addr);
92 			ASSERT(ret >= 0);
93 			len = snprintf(buf, BUF_SZ,
94 				"nid:%5u\tino:%5u\toffset:%5u"
95 				"\tblkaddr:%10u\tpack:%d"
96 				"\tcp_ver:0x%" PRIx64 "\n",
97 				ni.nid, ni.ino,
98 				le32_to_cpu(footer->flag) >> OFFSET_BIT_SHIFT,
99 				ni.blk_addr, pack,
100 				le64_to_cpu(footer->cp_ver));
101 			ret = write(fd, buf, len);
102 			ASSERT(ret >= 0);
103 		}
104 	}
105 
106 	free(nat_block);
107 	free(node_block);
108 
109 	close(fd);
110 }
111 
sit_dump(struct f2fs_sb_info * sbi,unsigned int start_sit,unsigned int end_sit)112 void sit_dump(struct f2fs_sb_info *sbi, unsigned int start_sit,
113 					unsigned int end_sit)
114 {
115 	struct seg_entry *se;
116 	struct sit_info *sit_i = SIT_I(sbi);
117 	unsigned int segno;
118 	char buf[BUF_SZ];
119 	u32 free_segs = 0;;
120 	u64 valid_blocks = 0;
121 	int ret;
122 	int fd, i;
123 	unsigned int offset;
124 
125 	fd = open("dump_sit", O_CREAT|O_WRONLY|O_TRUNC, 0666);
126 	ASSERT(fd >= 0);
127 
128 	snprintf(buf, BUF_SZ, "segment_type(0:HD, 1:WD, 2:CD, "
129 						"3:HN, 4:WN, 5:CN)\n");
130 	ret = write(fd, buf, strlen(buf));
131 	ASSERT(ret >= 0);
132 
133 	for (segno = start_sit; segno < end_sit; segno++) {
134 		se = get_seg_entry(sbi, segno);
135 		offset = SIT_BLOCK_OFFSET(sit_i, segno);
136 		memset(buf, 0, BUF_SZ);
137 		snprintf(buf, BUF_SZ,
138 		"\nsegno:%8u\tvblocks:%3u\tseg_type:%d\tsit_pack:%d\n\n",
139 			segno, se->valid_blocks, se->type,
140 			f2fs_test_bit(offset, sit_i->sit_bitmap) ? 2 : 1);
141 
142 		ret = write(fd, buf, strlen(buf));
143 		ASSERT(ret >= 0);
144 
145 		if (se->valid_blocks == 0x0) {
146 			free_segs++;
147 			continue;
148 		}
149 
150 		ASSERT(se->valid_blocks <= 512);
151 		valid_blocks += se->valid_blocks;
152 
153 		for (i = 0; i < 64; i++) {
154 			memset(buf, 0, BUF_SZ);
155 			snprintf(buf, BUF_SZ, "  %02x",
156 					*(se->cur_valid_map + i));
157 			ret = write(fd, buf, strlen(buf));
158 			ASSERT(ret >= 0);
159 
160 			if ((i + 1) % 16 == 0) {
161 				snprintf(buf, BUF_SZ, "\n");
162 				ret = write(fd, buf, strlen(buf));
163 				ASSERT(ret >= 0);
164 			}
165 		}
166 	}
167 
168 	memset(buf, 0, BUF_SZ);
169 	snprintf(buf, BUF_SZ,
170 		"valid_blocks:[0x%" PRIx64 "]\tvalid_segs:%d\t free_segs:%d\n",
171 			valid_blocks,
172 			SM_I(sbi)->main_segments - free_segs,
173 			free_segs);
174 	ret = write(fd, buf, strlen(buf));
175 	ASSERT(ret >= 0);
176 
177 	close(fd);
178 }
179 
ssa_dump(struct f2fs_sb_info * sbi,int start_ssa,int end_ssa)180 void ssa_dump(struct f2fs_sb_info *sbi, int start_ssa, int end_ssa)
181 {
182 	struct f2fs_summary_block *sum_blk;
183 	char buf[BUF_SZ];
184 	int segno, type, i, ret;
185 	int fd;
186 
187 	fd = open("dump_ssa", O_CREAT|O_WRONLY|O_TRUNC, 0666);
188 	ASSERT(fd >= 0);
189 
190 	snprintf(buf, BUF_SZ, "Note: dump.f2fs -b blkaddr = 0x%x + segno * "
191 				" 0x200 + offset\n",
192 				sbi->sm_info->main_blkaddr);
193 	ret = write(fd, buf, strlen(buf));
194 	ASSERT(ret >= 0);
195 
196 	for (segno = start_ssa; segno < end_ssa; segno++) {
197 		sum_blk = get_sum_block(sbi, segno, &type);
198 
199 		memset(buf, 0, BUF_SZ);
200 		switch (type) {
201 		case SEG_TYPE_CUR_NODE:
202 			snprintf(buf, BUF_SZ, "\n\nsegno: %x, Current Node\n", segno);
203 			break;
204 		case SEG_TYPE_CUR_DATA:
205 			snprintf(buf, BUF_SZ, "\n\nsegno: %x, Current Data\n", segno);
206 			break;
207 		case SEG_TYPE_NODE:
208 			snprintf(buf, BUF_SZ, "\n\nsegno: %x, Node\n", segno);
209 			break;
210 		case SEG_TYPE_DATA:
211 			snprintf(buf, BUF_SZ, "\n\nsegno: %x, Data\n", segno);
212 			break;
213 		}
214 		ret = write(fd, buf, strlen(buf));
215 		ASSERT(ret >= 0);
216 
217 		for (i = 0; i < ENTRIES_IN_SUM; i++) {
218 			memset(buf, 0, BUF_SZ);
219 			if (i % 10 == 0) {
220 				buf[0] = '\n';
221 				ret = write(fd, buf, strlen(buf));
222 				ASSERT(ret >= 0);
223 			}
224 			snprintf(buf, BUF_SZ, "[%3d: %6x]", i,
225 					le32_to_cpu(sum_blk->entries[i].nid));
226 			ret = write(fd, buf, strlen(buf));
227 			ASSERT(ret >= 0);
228 		}
229 		if (type == SEG_TYPE_NODE || type == SEG_TYPE_DATA ||
230 					type == SEG_TYPE_MAX)
231 			free(sum_blk);
232 	}
233 	close(fd);
234 }
235 
print_extent(bool last)236 static void print_extent(bool last)
237 {
238 	if (dump_extent.len == 0)
239 		goto out;
240 
241 	if (dump_extent.len == 1)
242 		printf(" %d", dump_extent.blk);
243 	else
244 		printf(" %d-%d",
245 			dump_extent.blk,
246 			dump_extent.blk + dump_extent.len - 1);
247 	dump_extent.len = 0;
248 out:
249 	if (last)
250 		printf("\n");
251 }
252 
dump_folder_contents(struct f2fs_sb_info * sbi,u8 * bitmap,struct f2fs_dir_entry * dentry,__u8 (* filenames)[F2FS_SLOT_LEN],int max)253 static void dump_folder_contents(struct f2fs_sb_info *sbi, u8 *bitmap,
254 				struct f2fs_dir_entry *dentry,
255 				__u8 (*filenames)[F2FS_SLOT_LEN], int max)
256 {
257 	int i;
258 	int name_len;
259 	char name[F2FS_NAME_LEN + 1] = {0};
260 
261 	for (i = 0; i < max; i++) {
262 		if (test_bit_le(i, bitmap) == 0)
263 			continue;
264 		name_len = le16_to_cpu(dentry[i].name_len);
265 		if (name_len == 0 || name_len > F2FS_NAME_LEN) {
266 			MSG(c.force, "Wrong name info\n\n");
267 			ASSERT(name_len == 0 || name_len > F2FS_NAME_LEN);
268 		}
269 		if (name_len == 1 && filenames[i][0] == '.')
270 			continue;
271 		if (name_len == 2 && filenames[i][0] == '.' && filenames[i][1] == '.')
272 			continue;
273 		strncpy(name, (const char *)filenames[i], name_len);
274 		name[name_len] = 0;
275 		dump_node(sbi, le32_to_cpu(dentry[i].ino), 1, NULL, 0, 1, name);
276 	}
277 }
278 
dump_data_blk(struct f2fs_sb_info * sbi,__u64 offset,u32 blkaddr,int type)279 static void dump_data_blk(struct f2fs_sb_info *sbi, __u64 offset, u32 blkaddr, int type)
280 {
281 	char buf[F2FS_BLKSIZE];
282 
283 	if (c.show_file_map) {
284 		if (c.show_file_map_max_offset < offset) {
285 			ASSERT(blkaddr == NULL_ADDR);
286 			return;
287 		}
288 		if (!is_valid_data_blkaddr(blkaddr)) {
289 			print_extent(false);
290 			dump_extent.blk = 0;
291 			dump_extent.len = 1;
292 			print_extent(false);
293 		} else if (dump_extent.len == 0) {
294 			dump_extent.blk = blkaddr;
295 			dump_extent.len = 1;
296 		} else if (dump_extent.blk + dump_extent.len == blkaddr) {
297 			dump_extent.len++;
298 		} else {
299 			print_extent(false);
300 			dump_extent.blk = blkaddr;
301 			dump_extent.len = 1;
302 		}
303 		return;
304 	}
305 
306 	if (blkaddr == NULL_ADDR)
307 		return;
308 
309 	/* get data */
310 	if (blkaddr == NEW_ADDR ||
311 			!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC)) {
312 		memset(buf, 0, F2FS_BLKSIZE);
313 	} else {
314 		int ret;
315 
316 		ret = dev_read_block(buf, blkaddr);
317 		ASSERT(ret >= 0);
318 	}
319 
320 	if (S_ISDIR(type)) {
321 		struct f2fs_dentry_block *d = (struct f2fs_dentry_block *) buf;
322 
323 		dump_folder_contents(sbi, d->dentry_bitmap, F2FS_DENTRY_BLOCK_DENTRIES(d),
324 					F2FS_DENTRY_BLOCK_FILENAMES(d), NR_DENTRY_IN_BLOCK);
325 #if !defined(__MINGW32__)
326 	} if (S_ISLNK(type)) {
327 		dev_write_symlink(buf, c.dump_sym_target_len);
328 #endif
329 	} else {
330 		/* write blkaddr */
331 		dev_write_dump(buf, offset, F2FS_BLKSIZE);
332 	}
333 }
334 
dump_node_blk(struct f2fs_sb_info * sbi,int ntype,u32 nid,u32 addr_per_block,u64 * ofs,int type)335 static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype,
336 				u32 nid, u32 addr_per_block, u64 *ofs, int type)
337 {
338 	struct node_info ni;
339 	struct f2fs_node *node_blk;
340 	u32 skip = 0;
341 	u32 i, idx = 0;
342 
343 	switch (ntype) {
344 	case TYPE_DIRECT_NODE:
345 		skip = idx = addr_per_block;
346 		break;
347 	case TYPE_INDIRECT_NODE:
348 		idx = NIDS_PER_BLOCK;
349 		skip = idx * addr_per_block;
350 		break;
351 	case TYPE_DOUBLE_INDIRECT_NODE:
352 		skip = 0;
353 		idx = NIDS_PER_BLOCK;
354 		break;
355 	}
356 
357 	if (nid == 0) {
358 		*ofs += skip;
359 		return;
360 	}
361 
362 	get_node_info(sbi, nid, &ni);
363 
364 	node_blk = calloc(F2FS_BLKSIZE, 1);
365 	ASSERT(node_blk);
366 
367 	dev_read_block(node_blk, ni.blk_addr);
368 
369 	for (i = 0; i < idx; i++) {
370 		switch (ntype) {
371 		case TYPE_DIRECT_NODE:
372 			dump_data_blk(sbi, *ofs * F2FS_BLKSIZE,
373 					le32_to_cpu(node_blk->dn.addr[i]), type);
374 			(*ofs)++;
375 			break;
376 		case TYPE_INDIRECT_NODE:
377 			dump_node_blk(sbi, TYPE_DIRECT_NODE,
378 					le32_to_cpu(node_blk->in.nid[i]),
379 					addr_per_block,
380 					ofs, type);
381 			break;
382 		case TYPE_DOUBLE_INDIRECT_NODE:
383 			dump_node_blk(sbi, TYPE_INDIRECT_NODE,
384 					le32_to_cpu(node_blk->in.nid[i]),
385 					addr_per_block,
386 					ofs, type);
387 			break;
388 		}
389 	}
390 	free(node_blk);
391 }
392 
393 #ifdef HAVE_FSETXATTR
dump_xattr(struct f2fs_sb_info * sbi,struct f2fs_node * node_blk,int type)394 static void dump_xattr(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk, int type)
395 {
396 	void *xattr;
397 	void *last_base_addr;
398 	struct f2fs_xattr_entry *ent;
399 	char xattr_name[F2FS_NAME_LEN] = {0};
400 	int ret;
401 
402 	xattr = read_all_xattrs(sbi, node_blk, true);
403 	if (!xattr)
404 		return;
405 
406 	last_base_addr = (void *)xattr + XATTR_SIZE(&node_blk->i);
407 
408 	list_for_each_xattr(ent, xattr) {
409 		char *name = strndup(ent->e_name, ent->e_name_len);
410 		void *value = ent->e_name + ent->e_name_len;
411 
412 		if ((void *)(ent) + sizeof(__u32) > last_base_addr ||
413 			(void *)XATTR_NEXT_ENTRY(ent) > last_base_addr) {
414 			MSG(0, "xattr entry crosses the end of xattr space\n");
415 			break;
416 		}
417 
418 		if (!name)
419 			continue;
420 
421 		switch (ent->e_name_index) {
422 		case F2FS_XATTR_INDEX_USER:
423 			ret = snprintf(xattr_name, F2FS_NAME_LEN, "%s%s",
424 				       XATTR_USER_PREFIX, name);
425 			break;
426 
427 		case F2FS_XATTR_INDEX_SECURITY:
428 			ret = snprintf(xattr_name, F2FS_NAME_LEN, "%s%s",
429 				       XATTR_SECURITY_PREFIX, name);
430 			break;
431 		case F2FS_XATTR_INDEX_TRUSTED:
432 			ret = snprintf(xattr_name, F2FS_NAME_LEN, "%s%s",
433 				       XATTR_TRUSTED_PREFIX, name);
434 			break;
435 		default:
436 			MSG(0, "Unknown xattr index 0x%x\n", ent->e_name_index);
437 			free(name);
438 			continue;
439 		}
440 		if (ret >= F2FS_NAME_LEN) {
441 			MSG(0, "XATTR index 0x%x name too long\n", ent->e_name_index);
442 			free(name);
443 			continue;
444 		}
445 
446 		DBG(1, "fd %d xattr_name %s\n", c.dump_fd, xattr_name);
447 #if defined(__linux__)
448 		if (S_ISDIR(type)) {
449 			ret = setxattr(".", xattr_name, value,
450 							le16_to_cpu(ent->e_value_size), 0);
451 		} if (S_ISLNK(type) && c.preserve_symlinks) {
452 			ret = lsetxattr(c.dump_symlink, xattr_name, value,
453 							le16_to_cpu(ent->e_value_size), 0);
454 		} else {
455 			ret = fsetxattr(c.dump_fd, xattr_name, value,
456 							le16_to_cpu(ent->e_value_size), 0);
457 		}
458 
459 #elif defined(__APPLE__)
460 		if (S_ISDIR(type)) {
461 			ret = setxattr(".", xattr_name, value,
462 					le16_to_cpu(ent->e_value_size), 0,
463 					XATTR_CREATE);
464 		} if (S_ISLNK(type) && c.preserve_symlinks) {
465 			ret = lsetxattr(c.dump_symlink, xattr_name, value,
466 					le16_to_cpu(ent->e_value_size), 0,
467 					XATTR_CREATE);
468 		} else {
469 			ret = fsetxattr(c.dump_fd, xattr_name, value,
470 					le16_to_cpu(ent->e_value_size), 0,
471 					XATTR_CREATE);
472 		}
473 #endif
474 		if (ret)
475 			MSG(0, "XATTR index 0x%x set xattr failed error %d\n",
476 			    ent->e_name_index, errno);
477 
478 		free(name);
479 	}
480 
481 	free(xattr);
482 }
483 #else
dump_xattr(struct f2fs_sb_info * UNUSED (sbi),struct f2fs_node * UNUSED (node_blk),int UNUSED (is_dir))484 static void dump_xattr(struct f2fs_sb_info *UNUSED(sbi),
485 				struct f2fs_node *UNUSED(node_blk), int UNUSED(is_dir))
486 {
487 	MSG(0, "XATTR does not support\n");
488 }
489 #endif
490 
dump_inode_blk(struct f2fs_sb_info * sbi,u32 nid,struct f2fs_node * node_blk)491 static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
492 					struct f2fs_node *node_blk)
493 {
494 	u32 i = 0;
495 	u64 ofs = 0;
496 	u32 addr_per_block;
497 	u16 type = le16_to_cpu(node_blk->i.i_mode);
498 	int ret = 0;
499 
500 	if ((node_blk->i.i_inline & F2FS_INLINE_DATA)) {
501 		DBG(3, "ino[0x%x] has inline data!\n", nid);
502 		/* recover from inline data */
503 #if !defined(__MINGW32__)
504 		if (S_ISLNK(type) && c.preserve_symlinks) {
505 			dev_write_symlink(inline_data_addr(node_blk), c.dump_sym_target_len);
506 		} else
507 #endif
508 		{
509 			dev_write_dump(inline_data_addr(node_blk),
510 						0, MAX_INLINE_DATA(node_blk));
511 		}
512 		ret = -1;
513 		goto dump_xattr;
514 	}
515 
516 	if ((node_blk->i.i_inline & F2FS_INLINE_DENTRY)) {
517 		void *inline_dentry = inline_data_addr(node_blk);
518 		struct f2fs_dentry_ptr d;
519 
520 		make_dentry_ptr(&d, node_blk, inline_dentry, 2);
521 
522 		DBG(3, "ino[0x%x] has inline dentries!\n", nid);
523 		/* recover from inline dentry */
524 		dump_folder_contents(sbi, d.bitmap, d.dentry, d.filename, d.max);
525 		ret = -1;
526 		goto dump_xattr;
527 	}
528 
529 	c.show_file_map_max_offset = f2fs_max_file_offset(&node_blk->i);
530 
531 	if (IS_DEVICE_ALIASING(&node_blk->i)) {
532 		u32 blkaddr = le32_to_cpu(node_blk->i.i_ext.blk_addr);
533 		u32 len = le32_to_cpu(node_blk->i.i_ext.len);
534 		u32 idx;
535 
536 		for (idx = 0; idx < len; idx++)
537 			dump_data_blk(sbi, idx * F2FS_BLKSIZE, blkaddr++, type);
538 		print_extent(true);
539 
540 		goto dump_xattr;
541 	}
542 
543 	addr_per_block = ADDRS_PER_BLOCK(&node_blk->i);
544 
545 	/* check data blocks in inode */
546 	for (i = 0; i < ADDRS_PER_INODE(&node_blk->i); i++, ofs++)
547 		dump_data_blk(sbi, ofs * F2FS_BLKSIZE, le32_to_cpu(
548 			node_blk->i.i_addr[get_extra_isize(node_blk) + i]), type);
549 
550 	/* check node blocks in inode */
551 	for (i = 0; i < 5; i++) {
552 		if (i == 0 || i == 1)
553 			dump_node_blk(sbi, TYPE_DIRECT_NODE,
554 					le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)),
555 					addr_per_block,
556 					&ofs,
557 					type);
558 		else if (i == 2 || i == 3)
559 			dump_node_blk(sbi, TYPE_INDIRECT_NODE,
560 					le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)),
561 					addr_per_block,
562 					&ofs,
563 					type);
564 		else if (i == 4)
565 			dump_node_blk(sbi, TYPE_DOUBLE_INDIRECT_NODE,
566 					le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)),
567 					addr_per_block,
568 					&ofs,
569 					type);
570 		else
571 			ASSERT(0);
572 	}
573 	/* last block in extent cache */
574 	print_extent(true);
575 dump_xattr:
576 	dump_xattr(sbi, node_blk, type);
577 	return ret;
578 }
579 
dump_file(struct f2fs_sb_info * sbi,struct node_info * ni,struct f2fs_node * node_blk,char * path)580 static void dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
581 				struct f2fs_node *node_blk, char *path)
582 {
583 	struct f2fs_inode *inode = &node_blk->i;
584 	int ret;
585 
586 	c.dump_fd = open(path, O_TRUNC|O_CREAT|O_RDWR, 0666);
587 	ASSERT(c.dump_fd >= 0);
588 
589 	/* dump file's data */
590 	dump_inode_blk(sbi, ni->ino, node_blk);
591 
592 	/* adjust file size */
593 	ret = ftruncate(c.dump_fd, le32_to_cpu(inode->i_size));
594 	ASSERT(ret >= 0);
595 
596 	close(c.dump_fd);
597 }
598 
dump_link(struct f2fs_sb_info * sbi,struct node_info * ni,struct f2fs_node * node_blk,char * name)599 static void dump_link(struct f2fs_sb_info *sbi, struct node_info *ni,
600 				struct f2fs_node *node_blk, char *name)
601 {
602 #if defined(__MINGW32__)
603 	dump_file(sbi, ni, node_blk, name);
604 #else
605 	struct f2fs_inode *inode = &node_blk->i;
606 	int len = le64_to_cpu(inode->i_size);
607 
608 	if (!c.preserve_symlinks)
609 		return dump_file(sbi, ni, node_blk, name);
610 	c.dump_symlink = name;
611 	c.dump_sym_target_len = len + 1;
612 	dump_inode_blk(sbi, ni->ino, node_blk);
613 #endif
614 }
615 
dump_folder(struct f2fs_sb_info * sbi,struct node_info * ni,struct f2fs_node * node_blk,char * path,int is_root)616 static void dump_folder(struct f2fs_sb_info *sbi, struct node_info *ni,
617 				struct f2fs_node *node_blk, char *path, int is_root)
618 {
619 	if (!is_root) {
620 #if defined(__MINGW32__)
621 		if (mkdir(path) < 0 && errno != EEXIST) {
622 			MSG(0, "Failed to create directory %s\n", path);
623 			return;
624 		}
625 #else
626 		if (mkdir(path, 0777) < 0 && errno != EEXIST) {
627 			MSG(0, "Failed to create directory %s\n", path);
628 			return;
629 		}
630 #endif
631 		ASSERT(chdir(path) == 0);
632 	}
633 	/* dump folder data */
634 	dump_inode_blk(sbi, ni->ino, node_blk);
635 	if (!is_root)
636 		ASSERT(chdir("..") == 0);
637 }
638 
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,char * dirent_name)639 static int dump_filesystem(struct f2fs_sb_info *sbi, struct node_info *ni,
640 				struct f2fs_node *node_blk, int force, char *base_path,
641 				bool is_base, bool allow_folder, char *dirent_name)
642 {
643 	struct f2fs_inode *inode = &node_blk->i;
644 	u32 imode = le16_to_cpu(inode->i_mode);
645 	u32 ilinks = le32_to_cpu(inode->i_links);
646 	u32 i_namelen = le32_to_cpu(inode->i_namelen);
647 	char i_name[F2FS_NAME_LEN + 1] = {0};
648 	char *name = NULL;
649 	char path[1024] = {0};
650 	char ans[255] = {0};
651 	int is_encrypted = file_is_encrypt(inode);
652 	int is_root = sbi->root_ino_num == ni->nid;
653 	int ret;
654 
655 	if (!S_ISDIR(imode) && ilinks != 1) {
656 		MSG(force, "Warning: Hard link detected. Dumped files may be duplicated\n");
657 	}
658 
659 	if (is_encrypted) {
660 		MSG(force, "File is encrypted\n");
661 		return -1;
662 	}
663 
664 	if ((!S_ISREG(imode) && !S_ISLNK(imode) && !(S_ISDIR(imode) && allow_folder))) {
665 		MSG(force, "Not a valid file type\n\n");
666 		return -1;
667 	}
668 	if (!is_root && !dirent_name && (i_namelen == 0 || i_namelen > F2FS_NAME_LEN)) {
669 		MSG(force, "Wrong name info\n\n");
670 		return -1;
671 	}
672 	if (le32_to_cpu(inode->i_flags) & F2FS_NODUMP_FL) {
673 		MSG(force, "File has nodump flag\n\n");
674 		return -1;
675 	}
676 	base_path = base_path ?: "./lost_found";
677 	if (force)
678 		goto dump;
679 
680 	/* dump file's data */
681 	if (c.show_file_map)
682 		return dump_inode_blk(sbi, ni->ino, node_blk);
683 
684 	printf("Do you want to dump this %s into %s/? [Y/N] ",
685 			S_ISDIR(imode) ? "folder" : "file",
686 			base_path);
687 	ret = scanf("%s", ans);
688 	ASSERT(ret >= 0);
689 
690 	if (!strcasecmp(ans, "y")) {
691 dump:
692 		if (is_base) {
693 			ASSERT(getcwd(path, sizeof(path)) != NULL);
694 #if defined(__MINGW32__)
695 			ret = mkdir(base_path);
696 #else
697 			ret = mkdir(base_path, 0777);
698 #endif
699 
700 			ASSERT(ret == 0 || errno == EEXIST);
701 			ASSERT(chdir(base_path) == 0);
702 		}
703 
704 		/* make a file */
705 		if (!is_root) {
706 			/* The i_name name may be out of date. Prefer dirent_name */
707 			if (dirent_name) {
708 				name = dirent_name;
709 			} else  {
710 				strncpy(i_name, (const char *)inode->i_name, i_namelen);
711 				i_name[i_namelen] = 0;
712 				name = i_name;
713 			}
714 		}
715 
716 		if (S_ISREG(imode)) {
717 			dump_file(sbi, ni, node_blk, name);
718 		} else if (S_ISDIR(imode)) {
719 			dump_folder(sbi, ni, node_blk, name, is_root);
720 		} else {
721 			dump_link(sbi, ni, node_blk, name);
722 		}
723 
724 #if !defined(__MINGW32__)
725 		/* fix up mode/owner */
726 		if (c.preserve_perms) {
727 			if (is_root) {
728 				name = i_name;
729 				strncpy(name, ".", 2);
730 			}
731 			if (!S_ISLNK(imode))
732 				ASSERT(chmod(name, imode) == 0);
733 			ASSERT(lchown(name, inode->i_uid, inode->i_gid) == 0);
734 		}
735 #endif
736 		if (is_base)
737 			ASSERT(chdir(path) == 0);
738 	}
739 	return 0;
740 }
741 
is_sit_bitmap_set(struct f2fs_sb_info * sbi,u32 blk_addr)742 bool is_sit_bitmap_set(struct f2fs_sb_info *sbi, u32 blk_addr)
743 {
744 	struct seg_entry *se;
745 	u32 offset;
746 
747 	se = get_seg_entry(sbi, GET_SEGNO(sbi, blk_addr));
748 	offset = OFFSET_IN_SEG(sbi, blk_addr);
749 
750 	return f2fs_test_bit(offset,
751 			(const char *)se->cur_valid_map) != 0;
752 }
753 
dump_node_scan_disk(struct f2fs_sb_info * sbi,nid_t nid)754 void dump_node_scan_disk(struct f2fs_sb_info *sbi, nid_t nid)
755 {
756 	struct f2fs_node *node_blk;
757 	pgoff_t blkaddr;
758 	int ret;
759 	pgoff_t start_blkaddr = SM_I(sbi)->main_blkaddr;
760 	pgoff_t end_blkaddr = start_blkaddr +
761 		(SM_I(sbi)->main_segments << sbi->log_blocks_per_seg);
762 
763 	node_blk = calloc(F2FS_BLKSIZE, 1);
764 	ASSERT(node_blk);
765 	MSG(0, "Info: scan all nid: %u from block_addr [%lu: %lu]\n",
766 			nid, start_blkaddr, end_blkaddr);
767 
768 	for (blkaddr = start_blkaddr; blkaddr < end_blkaddr; blkaddr++) {
769 		struct seg_entry *se = get_seg_entry(sbi, GET_SEGNO(sbi, blkaddr));
770 		if (se->type < CURSEG_HOT_NODE)
771 			continue;
772 
773 		ret = dev_read_block(node_blk, blkaddr);
774 		ASSERT(ret >= 0);
775 		if (le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino) != nid ||
776 				le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->nid) != nid)
777 			continue;
778 		MSG(0, "Info: nid: %u, blkaddr: %lu\n", nid, blkaddr);
779 		MSG(0, "node_blk.footer.flag [0x%x]\n", le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->flag));
780 		MSG(0, "node_blk.footer.cp_ver [%x]\n", (u32)(cpver_of_node(node_blk)));
781 		print_inode_info(sbi, node_blk, 0);
782 	}
783 
784 	free(node_blk);
785 }
786 
dump_node(struct f2fs_sb_info * sbi,nid_t nid,int force,char * base_path,int base,int allow_folder,char * dirent_name)787 int dump_node(struct f2fs_sb_info *sbi, nid_t nid, int force, char *base_path, int base, int allow_folder, char *dirent_name)
788 {
789 	struct node_info ni;
790 	struct f2fs_node *node_blk;
791 	int ret = 0;
792 
793 	get_node_info(sbi, nid, &ni);
794 
795 	node_blk = calloc(F2FS_BLKSIZE, 1);
796 	ASSERT(node_blk);
797 
798 	DBG(1, "Node ID               [0x%x]\n", nid);
799 	DBG(1, "nat_entry.block_addr  [0x%x]\n", ni.blk_addr);
800 	DBG(1, "nat_entry.version     [0x%x]\n", ni.version);
801 	DBG(1, "nat_entry.ino         [0x%x]\n", ni.ino);
802 
803 	if (!f2fs_is_valid_blkaddr(sbi, ni.blk_addr, DATA_GENERIC)) {
804 		MSG(force, "Invalid node blkaddr: %u\n\n", ni.blk_addr);
805 		goto out;
806 	}
807 
808 	dev_read_block(node_blk, ni.blk_addr);
809 
810 	if (!is_sit_bitmap_set(sbi, ni.blk_addr))
811 		MSG(force, "Invalid sit bitmap, %u\n\n", ni.blk_addr);
812 
813 	DBG(1, "node_blk.footer.ino [0x%x]\n", le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino));
814 	DBG(1, "node_blk.footer.nid [0x%x]\n", le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->nid));
815 
816 	if (le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino) == ni.ino &&
817 			le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->nid) == ni.nid) {
818 		if (!c.show_file_map)
819 			print_node_info(sbi, node_blk, force);
820 
821 		if (ni.ino == ni.nid)
822 			ret = dump_filesystem(sbi, &ni, node_blk, force, base_path, base, allow_folder, dirent_name);
823 	} else {
824 		print_node_info(sbi, node_blk, force);
825 		MSG(force, "Invalid (i)node block\n\n");
826 	}
827 out:
828 	free(node_blk);
829 	return ret;
830 }
831 
dump_node_from_blkaddr(struct f2fs_sb_info * sbi,u32 blk_addr)832 static void dump_node_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr)
833 {
834 	struct f2fs_node *node_blk;
835 	int ret;
836 
837 	node_blk = calloc(F2FS_BLKSIZE, 1);
838 	ASSERT(node_blk);
839 
840 	ret = dev_read_block(node_blk, blk_addr);
841 	ASSERT(ret >= 0);
842 
843 	if (c.dbg_lv > 0)
844 		print_node_info(sbi, node_blk, 0);
845 	else
846 		print_inode_info(sbi, node_blk, 1);
847 
848 	free(node_blk);
849 }
850 
start_bidx_of_node(unsigned int node_ofs,struct f2fs_node * node_blk)851 unsigned int start_bidx_of_node(unsigned int node_ofs,
852 					struct f2fs_node *node_blk)
853 {
854 	unsigned int indirect_blks = 2 * NIDS_PER_BLOCK + 4;
855 	unsigned int bidx;
856 
857 	if (node_ofs == 0)
858 		return 0;
859 
860 	if (node_ofs <= 2) {
861 		bidx = node_ofs - 1;
862 	} else if (node_ofs <= indirect_blks) {
863 		int dec = (node_ofs - 4) / (NIDS_PER_BLOCK + 1);
864 		bidx = node_ofs - 2 - dec;
865 	} else {
866 		int dec = (node_ofs - indirect_blks - 3) / (NIDS_PER_BLOCK + 1);
867 		bidx = node_ofs - 5 - dec;
868 	}
869 	return bidx * ADDRS_PER_BLOCK(&node_blk->i) +
870 				ADDRS_PER_INODE(&node_blk->i);
871 }
872 
dump_data_offset(u32 blk_addr,int ofs_in_node)873 static void dump_data_offset(u32 blk_addr, int ofs_in_node)
874 {
875 	struct f2fs_node *node_blk;
876 	unsigned int bidx;
877 	unsigned int node_ofs;
878 	int ret;
879 
880 	node_blk = calloc(F2FS_BLKSIZE, 1);
881 	ASSERT(node_blk);
882 
883 	ret = dev_read_block(node_blk, blk_addr);
884 	ASSERT(ret >= 0);
885 
886 	node_ofs = ofs_of_node(node_blk);
887 
888 	bidx = start_bidx_of_node(node_ofs, node_blk);
889 	bidx +=  ofs_in_node;
890 
891 	setlocale(LC_ALL, "");
892 	MSG(0, " - Data offset       : 0x%x (BLOCK), %'u (bytes)\n",
893 				bidx, bidx * F2FS_BLKSIZE);
894 	free(node_blk);
895 }
896 
dump_node_offset(u32 blk_addr)897 static void dump_node_offset(u32 blk_addr)
898 {
899 	struct f2fs_node *node_blk;
900 	int ret;
901 
902 	node_blk = calloc(F2FS_BLKSIZE, 1);
903 	ASSERT(node_blk);
904 
905 	ret = dev_read_block(node_blk, blk_addr);
906 	ASSERT(ret >= 0);
907 
908 	MSG(0, " - Node offset       : 0x%x\n", ofs_of_node(node_blk));
909 	free(node_blk);
910 }
911 
has_dirent(u32 blk_addr,int is_inline,int * enc_name)912 static int has_dirent(u32 blk_addr, int is_inline, int *enc_name)
913 {
914 	struct f2fs_node *node_blk;
915 	int ret, is_dentry = 0;
916 
917 	node_blk = calloc(F2FS_BLKSIZE, 1);
918 	ASSERT(node_blk);
919 
920 	ret = dev_read_block(node_blk, blk_addr);
921 	ASSERT(ret >= 0);
922 
923 	if (IS_INODE(node_blk) && S_ISDIR(le16_to_cpu(node_blk->i.i_mode)))
924 		is_dentry = 1;
925 
926 	if (is_inline && !(node_blk->i.i_inline & F2FS_INLINE_DENTRY))
927 		is_dentry = 0;
928 
929 	*enc_name = file_is_encrypt(&node_blk->i);
930 
931 	free(node_blk);
932 
933 	return is_dentry;
934 }
935 
dump_dirent(u32 blk_addr,int is_inline,int enc_name)936 static void dump_dirent(u32 blk_addr, int is_inline, int enc_name)
937 {
938 	struct f2fs_dentry_ptr d;
939 	void *inline_dentry, *blk;
940 	int ret, i = 0;
941 
942 	blk = calloc(F2FS_BLKSIZE, 1);
943 	ASSERT(blk);
944 
945 	ret = dev_read_block(blk, blk_addr);
946 	ASSERT(ret >= 0);
947 
948 	if (is_inline) {
949 		inline_dentry = inline_data_addr((struct f2fs_node *)blk);
950 		make_dentry_ptr(&d, blk, inline_dentry, 2);
951 	} else {
952 		make_dentry_ptr(&d, NULL, blk, 1);
953 	}
954 
955 	DBG(1, "%sDentry block:\n", is_inline ? "Inline " : "");
956 
957 	while (i < d.max) {
958 		struct f2fs_dir_entry *de;
959 		char en[F2FS_PRINT_NAMELEN];
960 		u16 name_len;
961 		int enc;
962 
963 		if (!test_bit_le(i, d.bitmap)) {
964 			i++;
965 			continue;
966 		}
967 
968 		de = &d.dentry[i];
969 
970 		if (!de->name_len) {
971 			i++;
972 			continue;
973 		}
974 
975 		name_len = le16_to_cpu(de->name_len);
976 		enc = enc_name;
977 
978 		if (de->file_type == F2FS_FT_DIR) {
979 			if ((d.filename[i][0] == '.' && name_len == 1) ||
980 				(d.filename[i][0] == '.' &&
981 				d.filename[i][1] == '.' && name_len == 2)) {
982 				enc = 0;
983 			}
984 		}
985 
986 		pretty_print_filename(d.filename[i], name_len, en, enc);
987 
988 		DBG(1, "bitmap pos[0x%x] name[%s] len[0x%x] hash[0x%x] ino[0x%x] type[0x%x]\n",
989 				i, en,
990 				name_len,
991 				le32_to_cpu(de->hash_code),
992 				le32_to_cpu(de->ino),
993 				de->file_type);
994 
995 		i += GET_DENTRY_SLOTS(name_len);
996 	}
997 
998 	free(blk);
999 }
1000 
dump_info_from_blkaddr(struct f2fs_sb_info * sbi,u32 blk_addr)1001 int dump_info_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr)
1002 {
1003 	nid_t nid;
1004 	int type;
1005 	struct f2fs_summary sum_entry;
1006 	struct node_info ni, ino_ni;
1007 	int enc_name;
1008 	int ret = 0;
1009 
1010 	MSG(0, "\n== Dump data from block address ==\n\n");
1011 
1012 	if (blk_addr < SM_I(sbi)->seg0_blkaddr) {
1013 		MSG(0, "\nFS Reserved Area for SEG #0: ");
1014 		ret = -EINVAL;
1015 	} else if (blk_addr < SIT_I(sbi)->sit_base_addr) {
1016 		MSG(0, "\nFS Metadata Area: ");
1017 		ret = -EINVAL;
1018 	} else if (blk_addr < NM_I(sbi)->nat_blkaddr) {
1019 		MSG(0, "\nFS SIT Area: ");
1020 		ret = -EINVAL;
1021 	} else if (blk_addr < SM_I(sbi)->ssa_blkaddr) {
1022 		MSG(0, "\nFS NAT Area: ");
1023 		ret = -EINVAL;
1024 	} else if (blk_addr < SM_I(sbi)->main_blkaddr) {
1025 		MSG(0, "\nFS SSA Area: ");
1026 		ret = -EINVAL;
1027 	} else if (blk_addr > __end_block_addr(sbi)) {
1028 		MSG(0, "\nOut of address space: ");
1029 		ret = -EINVAL;
1030 	}
1031 
1032 	if (ret) {
1033 		MSG(0, "User data is from 0x%x to 0x%x\n\n",
1034 			SM_I(sbi)->main_blkaddr,
1035 			__end_block_addr(sbi));
1036 		return ret;
1037 	}
1038 
1039 	if (!is_sit_bitmap_set(sbi, blk_addr))
1040 		MSG(0, "\nblkaddr is not valid\n");
1041 
1042 	type = get_sum_entry(sbi, blk_addr, &sum_entry);
1043 	nid = le32_to_cpu(sum_entry.nid);
1044 
1045 	get_node_info(sbi, nid, &ni);
1046 
1047 	DBG(1, "Note: blkaddr = main_blkaddr + segno * 512 + offset\n");
1048 	DBG(1, "Block_addr            [0x%x]\n", blk_addr);
1049 	DBG(1, " - Segno              [0x%x]\n", GET_SEGNO(sbi, blk_addr));
1050 	DBG(1, " - Offset             [0x%x]\n", OFFSET_IN_SEG(sbi, blk_addr));
1051 	DBG(1, "SUM.nid               [0x%x]\n", nid);
1052 	DBG(1, "SUM.type              [%s]\n", type >= 0 ?
1053 						seg_type_name[type] :
1054 						"Broken");
1055 	DBG(1, "SUM.version           [%d]\n", sum_entry.version);
1056 	DBG(1, "SUM.ofs_in_node       [0x%x]\n", sum_entry.ofs_in_node);
1057 	DBG(1, "NAT.blkaddr           [0x%x]\n", ni.blk_addr);
1058 	DBG(1, "NAT.ino               [0x%x]\n", ni.ino);
1059 
1060 	get_node_info(sbi, ni.ino, &ino_ni);
1061 
1062 	/* inode block address */
1063 	if (ni.blk_addr == NULL_ADDR || ino_ni.blk_addr == NULL_ADDR) {
1064 		MSG(0, "FS Userdata Area: Obsolete block from 0x%x\n",
1065 			blk_addr);
1066 		return -EINVAL;
1067 	}
1068 
1069 	/* print inode */
1070 	if (c.dbg_lv > 0)
1071 		dump_node_from_blkaddr(sbi, ino_ni.blk_addr);
1072 
1073 	if (type == SEG_TYPE_CUR_DATA || type == SEG_TYPE_DATA) {
1074 		MSG(0, "FS Userdata Area: Data block from 0x%x\n", blk_addr);
1075 		MSG(0, " - Direct node block : id = 0x%x from 0x%x\n",
1076 					nid, ni.blk_addr);
1077 		MSG(0, " - Inode block       : id = 0x%x from 0x%x\n",
1078 					ni.ino, ino_ni.blk_addr);
1079 		dump_node_from_blkaddr(sbi, ino_ni.blk_addr);
1080 		dump_data_offset(ni.blk_addr,
1081 			le16_to_cpu(sum_entry.ofs_in_node));
1082 
1083 		if (has_dirent(ino_ni.blk_addr, 0, &enc_name))
1084 			dump_dirent(blk_addr, 0, enc_name);
1085 	} else {
1086 		MSG(0, "FS Userdata Area: Node block from 0x%x\n", blk_addr);
1087 		if (ni.ino == ni.nid) {
1088 			MSG(0, " - Inode block       : id = 0x%x from 0x%x\n",
1089 					ni.ino, ino_ni.blk_addr);
1090 			dump_node_from_blkaddr(sbi, ino_ni.blk_addr);
1091 
1092 			if (has_dirent(ino_ni.blk_addr, 1, &enc_name))
1093 				dump_dirent(blk_addr, 1, enc_name);
1094 		} else {
1095 			MSG(0, " - Node block        : id = 0x%x from 0x%x\n",
1096 					nid, ni.blk_addr);
1097 			MSG(0, " - Inode block       : id = 0x%x from 0x%x\n",
1098 					ni.ino, ino_ni.blk_addr);
1099 			dump_node_from_blkaddr(sbi, ino_ni.blk_addr);
1100 			dump_node_offset(ni.blk_addr);
1101 		}
1102 	}
1103 
1104 	return 0;
1105 }
1106