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 */ 27struct extent_info dump_extent; 28 29const 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 37void 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 109void 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 177void 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 233static 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; 245out: 246 if (last) 247 printf("\n"); 248} 249 250static 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 294static 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 353static void dump_xattr(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk) 354{ 355 void *xattr; 356 struct f2fs_xattr_entry *ent; 357 char xattr_name[F2FS_NAME_LEN] = {0}; 358 int ret; 359 360 xattr = read_all_xattrs(sbi, node_blk); 361 if (!xattr) 362 return; 363 364 list_for_each_xattr(ent, xattr) { 365 char *name = strndup(ent->e_name, ent->e_name_len); 366 void *value = ent->e_name + ent->e_name_len; 367 368 if (!name) 369 continue; 370 371 switch (ent->e_name_index) { 372 case F2FS_XATTR_INDEX_USER: 373 ret = snprintf(xattr_name, F2FS_NAME_LEN, "%s%s", 374 XATTR_USER_PREFIX, name); 375 break; 376 377 case F2FS_XATTR_INDEX_SECURITY: 378 ret = snprintf(xattr_name, F2FS_NAME_LEN, "%s%s", 379 XATTR_SECURITY_PREFIX, name); 380 break; 381 case F2FS_XATTR_INDEX_TRUSTED: 382 ret = snprintf(xattr_name, F2FS_NAME_LEN, "%s%s", 383 XATTR_TRUSTED_PREFIX, name); 384 break; 385 default: 386 MSG(0, "Unknown xattr index 0x%x\n", ent->e_name_index); 387 free(name); 388 continue; 389 } 390 if (ret >= F2FS_NAME_LEN) { 391 MSG(0, "XATTR index 0x%x name too long\n", ent->e_name_index); 392 free(name); 393 continue; 394 } 395 396 DBG(1, "fd %d xattr_name %s\n", c.dump_fd, xattr_name); 397#if defined(__linux__) 398 ret = fsetxattr(c.dump_fd, xattr_name, value, 399 le16_to_cpu(ent->e_value_size), 0); 400#elif defined(__APPLE__) 401 ret = fsetxattr(c.dump_fd, xattr_name, value, 402 le16_to_cpu(ent->e_value_size), 0, 403 XATTR_CREATE); 404#endif 405 if (ret) 406 MSG(0, "XATTR index 0x%x set xattr failed error %d\n", 407 ent->e_name_index, errno); 408 409 free(name); 410 } 411 412 free(xattr); 413} 414#else 415static void dump_xattr(struct f2fs_sb_info *UNUSED(sbi), 416 struct f2fs_node *UNUSED(node_blk)) 417{ 418 MSG(0, "XATTR does not support\n"); 419} 420#endif 421 422static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid, 423 struct f2fs_node *node_blk) 424{ 425 u32 i = 0; 426 u64 ofs = 0; 427 u32 addr_per_block; 428 429 if((node_blk->i.i_inline & F2FS_INLINE_DATA)) { 430 DBG(3, "ino[0x%x] has inline data!\n", nid); 431 /* recover from inline data */ 432 dev_write_dump(((unsigned char *)node_blk) + INLINE_DATA_OFFSET, 433 0, MAX_INLINE_DATA(node_blk)); 434 return -1; 435 } 436 437 c.show_file_map_max_offset = f2fs_max_file_offset(&node_blk->i); 438 addr_per_block = ADDRS_PER_BLOCK(&node_blk->i); 439 440 /* check data blocks in inode */ 441 for (i = 0; i < ADDRS_PER_INODE(&node_blk->i); i++, ofs++) 442 dump_data_blk(sbi, ofs * F2FS_BLKSIZE, le32_to_cpu( 443 node_blk->i.i_addr[get_extra_isize(node_blk) + i])); 444 445 /* check node blocks in inode */ 446 for (i = 0; i < 5; i++) { 447 if (i == 0 || i == 1) 448 dump_node_blk(sbi, TYPE_DIRECT_NODE, 449 le32_to_cpu(node_blk->i.i_nid[i]), 450 addr_per_block, 451 &ofs); 452 else if (i == 2 || i == 3) 453 dump_node_blk(sbi, TYPE_INDIRECT_NODE, 454 le32_to_cpu(node_blk->i.i_nid[i]), 455 addr_per_block, 456 &ofs); 457 else if (i == 4) 458 dump_node_blk(sbi, TYPE_DOUBLE_INDIRECT_NODE, 459 le32_to_cpu(node_blk->i.i_nid[i]), 460 addr_per_block, 461 &ofs); 462 else 463 ASSERT(0); 464 } 465 /* last block in extent cache */ 466 print_extent(true); 467 468 dump_xattr(sbi, node_blk); 469 return 0; 470} 471 472static int dump_file(struct f2fs_sb_info *sbi, struct node_info *ni, 473 struct f2fs_node *node_blk, int force) 474{ 475 struct f2fs_inode *inode = &node_blk->i; 476 u32 imode = le16_to_cpu(inode->i_mode); 477 u32 namelen = le32_to_cpu(inode->i_namelen); 478 char name[F2FS_NAME_LEN + 1] = {0}; 479 char path[1024] = {0}; 480 char ans[255] = {0}; 481 int is_encrypted = file_is_encrypt(inode); 482 int ret; 483 484 if (is_encrypted) { 485 MSG(force, "File is encrypted\n"); 486 return -1; 487 } 488 489 if ((!S_ISREG(imode) && !S_ISLNK(imode)) || 490 namelen == 0 || namelen > F2FS_NAME_LEN) { 491 MSG(force, "Not a regular file or wrong name info\n\n"); 492 return -1; 493 } 494 if (force) 495 goto dump; 496 497 /* dump file's data */ 498 if (c.show_file_map) 499 return dump_inode_blk(sbi, ni->ino, node_blk); 500 501 printf("Do you want to dump this file into ./lost_found/? [Y/N] "); 502 ret = scanf("%s", ans); 503 ASSERT(ret >= 0); 504 505 if (!strcasecmp(ans, "y")) { 506dump: 507 ret = system("mkdir -p ./lost_found"); 508 ASSERT(ret >= 0); 509 510 /* make a file */ 511 strncpy(name, (const char *)inode->i_name, namelen); 512 name[namelen] = 0; 513 sprintf(path, "./lost_found/%s", name); 514 515 c.dump_fd = open(path, O_TRUNC|O_CREAT|O_RDWR, 0666); 516 ASSERT(c.dump_fd >= 0); 517 518 /* dump file's data */ 519 dump_inode_blk(sbi, ni->ino, node_blk); 520 521 /* adjust file size */ 522 ret = ftruncate(c.dump_fd, le32_to_cpu(inode->i_size)); 523 ASSERT(ret >= 0); 524 525 close(c.dump_fd); 526 } 527 return 0; 528} 529 530static bool is_sit_bitmap_set(struct f2fs_sb_info *sbi, u32 blk_addr) 531{ 532 struct seg_entry *se; 533 u32 offset; 534 535 se = get_seg_entry(sbi, GET_SEGNO(sbi, blk_addr)); 536 offset = OFFSET_IN_SEG(sbi, blk_addr); 537 538 return f2fs_test_bit(offset, 539 (const char *)se->cur_valid_map) != 0; 540} 541 542void dump_node_scan_disk(struct f2fs_sb_info *sbi, nid_t nid) 543{ 544 struct f2fs_node *node_blk; 545 pgoff_t blkaddr; 546 int ret; 547 pgoff_t start_blkaddr = SM_I(sbi)->main_blkaddr; 548 pgoff_t end_blkaddr = start_blkaddr + 549 (SM_I(sbi)->main_segments << sbi->log_blocks_per_seg); 550 551 node_blk = calloc(BLOCK_SZ, 1); 552 ASSERT(node_blk); 553 MSG(0, "Info: scan all nid: %u from block_addr [%lu: %lu]\n", 554 nid, start_blkaddr, end_blkaddr); 555 556 for (blkaddr = start_blkaddr; blkaddr < end_blkaddr; blkaddr++) { 557 struct seg_entry *se = get_seg_entry(sbi, GET_SEGNO(sbi, blkaddr)); 558 if (se->type < CURSEG_HOT_NODE) 559 continue; 560 561 ret = dev_read_block(node_blk, blkaddr); 562 ASSERT(ret >= 0); 563 if (le32_to_cpu(node_blk->footer.ino) != nid || 564 le32_to_cpu(node_blk->footer.nid) != nid) 565 continue; 566 MSG(0, "Info: nid: %u, blkaddr: %lu\n", nid, blkaddr); 567 MSG(0, "node_blk.footer.flag [0x%x]\n", le32_to_cpu(node_blk->footer.flag)); 568 MSG(0, "node_blk.footer.cp_ver [%x]\n", (u32)(cpver_of_node(node_blk))); 569 print_inode_info(sbi, node_blk, 0); 570 } 571 572 free(node_blk); 573} 574 575int dump_node(struct f2fs_sb_info *sbi, nid_t nid, int force) 576{ 577 struct node_info ni; 578 struct f2fs_node *node_blk; 579 int ret = 0; 580 581 get_node_info(sbi, nid, &ni); 582 583 node_blk = calloc(BLOCK_SZ, 1); 584 ASSERT(node_blk); 585 586 DBG(1, "Node ID [0x%x]\n", nid); 587 DBG(1, "nat_entry.block_addr [0x%x]\n", ni.blk_addr); 588 DBG(1, "nat_entry.version [0x%x]\n", ni.version); 589 DBG(1, "nat_entry.ino [0x%x]\n", ni.ino); 590 591 if (!IS_VALID_BLK_ADDR(sbi, ni.blk_addr)) { 592 MSG(force, "Invalid node blkaddr: %u\n\n", ni.blk_addr); 593 goto out; 594 } 595 596 dev_read_block(node_blk, ni.blk_addr); 597 598 if (ni.blk_addr == 0x0) 599 MSG(force, "Invalid nat entry\n\n"); 600 else if (!is_sit_bitmap_set(sbi, ni.blk_addr)) 601 MSG(force, "Invalid sit bitmap, %u\n\n", ni.blk_addr); 602 603 DBG(1, "node_blk.footer.ino [0x%x]\n", le32_to_cpu(node_blk->footer.ino)); 604 DBG(1, "node_blk.footer.nid [0x%x]\n", le32_to_cpu(node_blk->footer.nid)); 605 606 if (le32_to_cpu(node_blk->footer.ino) == ni.ino && 607 le32_to_cpu(node_blk->footer.nid) == ni.nid) { 608 if (!c.show_file_map) 609 print_node_info(sbi, node_blk, force); 610 611 if (ni.ino == ni.nid) 612 ret = dump_file(sbi, &ni, node_blk, force); 613 } else { 614 print_node_info(sbi, node_blk, force); 615 MSG(force, "Invalid (i)node block\n\n"); 616 } 617out: 618 free(node_blk); 619 return ret; 620} 621 622static void dump_node_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr) 623{ 624 struct f2fs_node *node_blk; 625 int ret; 626 627 node_blk = calloc(BLOCK_SZ, 1); 628 ASSERT(node_blk); 629 630 ret = dev_read_block(node_blk, blk_addr); 631 ASSERT(ret >= 0); 632 633 if (c.dbg_lv > 0) 634 print_node_info(sbi, node_blk, 0); 635 else 636 print_inode_info(sbi, node_blk, 1); 637 638 free(node_blk); 639} 640 641unsigned int start_bidx_of_node(unsigned int node_ofs, 642 struct f2fs_node *node_blk) 643{ 644 unsigned int indirect_blks = 2 * NIDS_PER_BLOCK + 4; 645 unsigned int bidx; 646 647 if (node_ofs == 0) 648 return 0; 649 650 if (node_ofs <= 2) { 651 bidx = node_ofs - 1; 652 } else if (node_ofs <= indirect_blks) { 653 int dec = (node_ofs - 4) / (NIDS_PER_BLOCK + 1); 654 bidx = node_ofs - 2 - dec; 655 } else { 656 int dec = (node_ofs - indirect_blks - 3) / (NIDS_PER_BLOCK + 1); 657 bidx = node_ofs - 5 - dec; 658 } 659 return bidx * ADDRS_PER_BLOCK(&node_blk->i) + 660 ADDRS_PER_INODE(&node_blk->i); 661} 662 663static void dump_data_offset(u32 blk_addr, int ofs_in_node) 664{ 665 struct f2fs_node *node_blk; 666 unsigned int bidx; 667 unsigned int node_ofs; 668 int ret; 669 670 node_blk = calloc(BLOCK_SZ, 1); 671 ASSERT(node_blk); 672 673 ret = dev_read_block(node_blk, blk_addr); 674 ASSERT(ret >= 0); 675 676 node_ofs = ofs_of_node(node_blk); 677 678 bidx = start_bidx_of_node(node_ofs, node_blk); 679 bidx += ofs_in_node; 680 681 setlocale(LC_ALL, ""); 682 MSG(0, " - Data offset : 0x%x (4KB), %'u (bytes)\n", 683 bidx, bidx * 4096); 684 free(node_blk); 685} 686 687static void dump_node_offset(u32 blk_addr) 688{ 689 struct f2fs_node *node_blk; 690 int ret; 691 692 node_blk = calloc(BLOCK_SZ, 1); 693 ASSERT(node_blk); 694 695 ret = dev_read_block(node_blk, blk_addr); 696 ASSERT(ret >= 0); 697 698 MSG(0, " - Node offset : 0x%x\n", ofs_of_node(node_blk)); 699 free(node_blk); 700} 701 702static int has_dirent(u32 blk_addr, int is_inline, int *enc_name) 703{ 704 struct f2fs_node *node_blk; 705 int ret, is_dentry = 0; 706 707 node_blk = calloc(BLOCK_SZ, 1); 708 ASSERT(node_blk); 709 710 ret = dev_read_block(node_blk, blk_addr); 711 ASSERT(ret >= 0); 712 713 if (IS_INODE(node_blk) && S_ISDIR(le16_to_cpu(node_blk->i.i_mode))) 714 is_dentry = 1; 715 716 if (is_inline && !(node_blk->i.i_inline & F2FS_INLINE_DENTRY)) 717 is_dentry = 0; 718 719 *enc_name = file_is_encrypt(&node_blk->i); 720 721 free(node_blk); 722 723 return is_dentry; 724} 725 726static void dump_dirent(u32 blk_addr, int is_inline, int enc_name) 727{ 728 struct f2fs_dentry_ptr d; 729 void *inline_dentry, *blk; 730 int ret, i = 0; 731 732 blk = calloc(BLOCK_SZ, 1); 733 ASSERT(blk); 734 735 ret = dev_read_block(blk, blk_addr); 736 ASSERT(ret >= 0); 737 738 if (is_inline) { 739 inline_dentry = inline_data_addr((struct f2fs_node *)blk); 740 make_dentry_ptr(&d, blk, inline_dentry, 2); 741 } else { 742 make_dentry_ptr(&d, NULL, blk, 1); 743 } 744 745 DBG(1, "%sDentry block:\n", is_inline ? "Inline " : ""); 746 747 while (i < d.max) { 748 struct f2fs_dir_entry *de; 749 char en[F2FS_PRINT_NAMELEN]; 750 u16 name_len; 751 int enc; 752 753 if (!test_bit_le(i, d.bitmap)) { 754 i++; 755 continue; 756 } 757 758 de = &d.dentry[i]; 759 760 if (!de->name_len) { 761 i++; 762 continue; 763 } 764 765 name_len = le16_to_cpu(de->name_len); 766 enc = enc_name; 767 768 if (de->file_type == F2FS_FT_DIR) { 769 if ((d.filename[i][0] == '.' && name_len == 1) || 770 (d.filename[i][0] == '.' && 771 d.filename[i][1] == '.' && name_len == 2)) { 772 enc = 0; 773 } 774 } 775 776 pretty_print_filename(d.filename[i], name_len, en, enc); 777 778 DBG(1, "bitmap pos[0x%x] name[%s] len[0x%x] hash[0x%x] ino[0x%x] type[0x%x]\n", 779 i, en, 780 name_len, 781 le32_to_cpu(de->hash_code), 782 le32_to_cpu(de->ino), 783 de->file_type); 784 785 i += GET_DENTRY_SLOTS(name_len); 786 } 787 788 free(blk); 789} 790 791int dump_info_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr) 792{ 793 nid_t nid; 794 int type; 795 struct f2fs_summary sum_entry; 796 struct node_info ni, ino_ni; 797 int enc_name; 798 int ret = 0; 799 800 MSG(0, "\n== Dump data from block address ==\n\n"); 801 802 if (blk_addr < SM_I(sbi)->seg0_blkaddr) { 803 MSG(0, "\nFS Reserved Area for SEG #0: "); 804 ret = -EINVAL; 805 } else if (blk_addr < SIT_I(sbi)->sit_base_addr) { 806 MSG(0, "\nFS Metadata Area: "); 807 ret = -EINVAL; 808 } else if (blk_addr < NM_I(sbi)->nat_blkaddr) { 809 MSG(0, "\nFS SIT Area: "); 810 ret = -EINVAL; 811 } else if (blk_addr < SM_I(sbi)->ssa_blkaddr) { 812 MSG(0, "\nFS NAT Area: "); 813 ret = -EINVAL; 814 } else if (blk_addr < SM_I(sbi)->main_blkaddr) { 815 MSG(0, "\nFS SSA Area: "); 816 ret = -EINVAL; 817 } else if (blk_addr > __end_block_addr(sbi)) { 818 MSG(0, "\nOut of address space: "); 819 ret = -EINVAL; 820 } 821 822 if (ret) { 823 MSG(0, "User data is from 0x%x to 0x%x\n\n", 824 SM_I(sbi)->main_blkaddr, 825 __end_block_addr(sbi)); 826 return ret; 827 } 828 829 if (!is_sit_bitmap_set(sbi, blk_addr)) 830 MSG(0, "\nblkaddr is not valid\n"); 831 832 type = get_sum_entry(sbi, blk_addr, &sum_entry); 833 nid = le32_to_cpu(sum_entry.nid); 834 835 get_node_info(sbi, nid, &ni); 836 837 DBG(1, "Note: blkaddr = main_blkaddr + segno * 512 + offset\n"); 838 DBG(1, "Block_addr [0x%x]\n", blk_addr); 839 DBG(1, " - Segno [0x%x]\n", GET_SEGNO(sbi, blk_addr)); 840 DBG(1, " - Offset [0x%x]\n", OFFSET_IN_SEG(sbi, blk_addr)); 841 DBG(1, "SUM.nid [0x%x]\n", nid); 842 DBG(1, "SUM.type [%s]\n", type >= 0 ? 843 seg_type_name[type] : 844 "Broken"); 845 DBG(1, "SUM.version [%d]\n", sum_entry.version); 846 DBG(1, "SUM.ofs_in_node [0x%x]\n", sum_entry.ofs_in_node); 847 DBG(1, "NAT.blkaddr [0x%x]\n", ni.blk_addr); 848 DBG(1, "NAT.ino [0x%x]\n", ni.ino); 849 850 get_node_info(sbi, ni.ino, &ino_ni); 851 852 /* inode block address */ 853 if (ni.blk_addr == NULL_ADDR || ino_ni.blk_addr == NULL_ADDR) { 854 MSG(0, "FS Userdata Area: Obsolete block from 0x%x\n", 855 blk_addr); 856 return -EINVAL; 857 } 858 859 /* print inode */ 860 if (c.dbg_lv > 0) 861 dump_node_from_blkaddr(sbi, ino_ni.blk_addr); 862 863 if (type == SEG_TYPE_CUR_DATA || type == SEG_TYPE_DATA) { 864 MSG(0, "FS Userdata Area: Data block from 0x%x\n", blk_addr); 865 MSG(0, " - Direct node block : id = 0x%x from 0x%x\n", 866 nid, ni.blk_addr); 867 MSG(0, " - Inode block : id = 0x%x from 0x%x\n", 868 ni.ino, ino_ni.blk_addr); 869 dump_node_from_blkaddr(sbi, ino_ni.blk_addr); 870 dump_data_offset(ni.blk_addr, 871 le16_to_cpu(sum_entry.ofs_in_node)); 872 873 if (has_dirent(ino_ni.blk_addr, 0, &enc_name)) 874 dump_dirent(blk_addr, 0, enc_name); 875 } else { 876 MSG(0, "FS Userdata Area: Node block from 0x%x\n", blk_addr); 877 if (ni.ino == ni.nid) { 878 MSG(0, " - Inode block : id = 0x%x from 0x%x\n", 879 ni.ino, ino_ni.blk_addr); 880 dump_node_from_blkaddr(sbi, ino_ni.blk_addr); 881 882 if (has_dirent(ino_ni.blk_addr, 1, &enc_name)) 883 dump_dirent(blk_addr, 1, enc_name); 884 } else { 885 MSG(0, " - Node block : id = 0x%x from 0x%x\n", 886 nid, ni.blk_addr); 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 dump_node_offset(ni.blk_addr); 891 } 892 } 893 894 return 0; 895} 896