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