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