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