Home | History | Annotate | Download | only in f2fs_utils
      1 #define _LARGEFILE64_SOURCE
      2 
      3 #define LOG_TAG "f2fs_sparseblock"
      4 
      5 
      6 #include <cutils/log.h>
      7 #include <fcntl.h>
      8 #include <f2fs_fs.h>
      9 #include <linux/types.h>
     10 #include <sys/stat.h>
     11 #include "f2fs_sparseblock.h"
     12 
     13 
     14 #define D_DISP_u32(ptr, member)           \
     15   do {                \
     16     SLOGD("%-30s" "\t\t[0x%#08x : %u]\n",    \
     17       #member, le32_to_cpu((ptr)->member), le32_to_cpu((ptr)->member) );  \
     18   } while (0);
     19 
     20 #define D_DISP_u64(ptr, member)           \
     21   do {                \
     22     SLOGD("%-30s" "\t\t[0x%#016llx : %llu]\n",    \
     23       #member, le64_to_cpu((ptr)->member), le64_to_cpu((ptr)->member) );  \
     24   } while (0);
     25 
     26 #define segno_in_journal(sum, i)    (sum->sit_j.entries[i].segno)
     27 
     28 #define sit_in_journal(sum, i)      (sum->sit_j.entries[i].se)
     29 
     30 static void dbg_print_raw_sb_info(struct f2fs_super_block *sb)
     31 {
     32     SLOGD("\n");
     33     SLOGD("+--------------------------------------------------------+\n");
     34     SLOGD("| Super block                                            |\n");
     35     SLOGD("+--------------------------------------------------------+\n");
     36 
     37     D_DISP_u32(sb, magic);
     38     D_DISP_u32(sb, major_ver);
     39     D_DISP_u32(sb, minor_ver);
     40     D_DISP_u32(sb, log_sectorsize);
     41     D_DISP_u32(sb, log_sectors_per_block);
     42 
     43     D_DISP_u32(sb, log_blocksize);
     44     D_DISP_u32(sb, log_blocks_per_seg);
     45     D_DISP_u32(sb, segs_per_sec);
     46     D_DISP_u32(sb, secs_per_zone);
     47     D_DISP_u32(sb, checksum_offset);
     48     D_DISP_u64(sb, block_count);
     49 
     50     D_DISP_u32(sb, section_count);
     51     D_DISP_u32(sb, segment_count);
     52     D_DISP_u32(sb, segment_count_ckpt);
     53     D_DISP_u32(sb, segment_count_sit);
     54     D_DISP_u32(sb, segment_count_nat);
     55 
     56     D_DISP_u32(sb, segment_count_ssa);
     57     D_DISP_u32(sb, segment_count_main);
     58     D_DISP_u32(sb, segment0_blkaddr);
     59 
     60     D_DISP_u32(sb, cp_blkaddr);
     61     D_DISP_u32(sb, sit_blkaddr);
     62     D_DISP_u32(sb, nat_blkaddr);
     63     D_DISP_u32(sb, ssa_blkaddr);
     64     D_DISP_u32(sb, main_blkaddr);
     65 
     66     D_DISP_u32(sb, root_ino);
     67     D_DISP_u32(sb, node_ino);
     68     D_DISP_u32(sb, meta_ino);
     69     D_DISP_u32(sb, cp_payload);
     70     SLOGD("\n");
     71 }
     72 static void dbg_print_raw_ckpt_struct(struct f2fs_checkpoint *cp)
     73 {
     74     SLOGD("\n");
     75     SLOGD("+--------------------------------------------------------+\n");
     76     SLOGD("| Checkpoint                                             |\n");
     77     SLOGD("+--------------------------------------------------------+\n");
     78 
     79     D_DISP_u64(cp, checkpoint_ver);
     80     D_DISP_u64(cp, user_block_count);
     81     D_DISP_u64(cp, valid_block_count);
     82     D_DISP_u32(cp, rsvd_segment_count);
     83     D_DISP_u32(cp, overprov_segment_count);
     84     D_DISP_u32(cp, free_segment_count);
     85 
     86     D_DISP_u32(cp, alloc_type[CURSEG_HOT_NODE]);
     87     D_DISP_u32(cp, alloc_type[CURSEG_WARM_NODE]);
     88     D_DISP_u32(cp, alloc_type[CURSEG_COLD_NODE]);
     89     D_DISP_u32(cp, cur_node_segno[0]);
     90     D_DISP_u32(cp, cur_node_segno[1]);
     91     D_DISP_u32(cp, cur_node_segno[2]);
     92 
     93     D_DISP_u32(cp, cur_node_blkoff[0]);
     94     D_DISP_u32(cp, cur_node_blkoff[1]);
     95     D_DISP_u32(cp, cur_node_blkoff[2]);
     96 
     97 
     98     D_DISP_u32(cp, alloc_type[CURSEG_HOT_DATA]);
     99     D_DISP_u32(cp, alloc_type[CURSEG_WARM_DATA]);
    100     D_DISP_u32(cp, alloc_type[CURSEG_COLD_DATA]);
    101     D_DISP_u32(cp, cur_data_segno[0]);
    102     D_DISP_u32(cp, cur_data_segno[1]);
    103     D_DISP_u32(cp, cur_data_segno[2]);
    104 
    105     D_DISP_u32(cp, cur_data_blkoff[0]);
    106     D_DISP_u32(cp, cur_data_blkoff[1]);
    107     D_DISP_u32(cp, cur_data_blkoff[2]);
    108 
    109     D_DISP_u32(cp, ckpt_flags);
    110     D_DISP_u32(cp, cp_pack_total_block_count);
    111     D_DISP_u32(cp, cp_pack_start_sum);
    112     D_DISP_u32(cp, valid_node_count);
    113     D_DISP_u32(cp, valid_inode_count);
    114     D_DISP_u32(cp, next_free_nid);
    115     D_DISP_u32(cp, sit_ver_bitmap_bytesize);
    116     D_DISP_u32(cp, nat_ver_bitmap_bytesize);
    117     D_DISP_u32(cp, checksum_offset);
    118     D_DISP_u64(cp, elapsed_time);
    119 
    120     D_DISP_u32(cp, sit_nat_version_bitmap[0]);
    121     SLOGD("\n\n");
    122 }
    123 
    124 static void dbg_print_info_struct(struct f2fs_info *info)
    125 {
    126     SLOGD("\n");
    127     SLOGD("+--------------------------------------------------------+\n");
    128     SLOGD("| F2FS_INFO                                              |\n");
    129     SLOGD("+--------------------------------------------------------+\n");
    130     SLOGD("blocks_per_segment: %"PRIu64, info->blocks_per_segment);
    131     SLOGD("block_size: %d", info->block_size);
    132     SLOGD("sit_bmp loc: %p", info->sit_bmp);
    133     SLOGD("sit_bmp_size: %d", info->sit_bmp_size);
    134     SLOGD("blocks_per_sit: %"PRIu64, info->blocks_per_sit);
    135     SLOGD("sit_blocks loc: %p", info->sit_blocks);
    136     SLOGD("sit_sums loc: %p", info->sit_sums);
    137     SLOGD("sit_sums num: %d", le16_to_cpu(info->sit_sums->n_sits));
    138     unsigned int i;
    139     for(i = 0; i < (le16_to_cpu(info->sit_sums->n_sits)); i++) {
    140         SLOGD("entry %d in journal entries is for segment %d",i, le32_to_cpu(segno_in_journal(info->sit_sums, i)));
    141     }
    142 
    143     SLOGD("cp_blkaddr: %"PRIu64, info->cp_blkaddr);
    144     SLOGD("cp_valid_cp_blkaddr: %"PRIu64, info->cp_valid_cp_blkaddr);
    145     SLOGD("sit_blkaddr: %"PRIu64, info->sit_blkaddr);
    146     SLOGD("nat_blkaddr: %"PRIu64, info->nat_blkaddr);
    147     SLOGD("ssa_blkaddr: %"PRIu64, info->ssa_blkaddr);
    148     SLOGD("main_blkaddr: %"PRIu64, info->main_blkaddr);
    149     SLOGD("total_user_used: %"PRIu64, info->total_user_used);
    150     SLOGD("total_blocks: %"PRIu64, info->total_blocks);
    151     SLOGD("\n\n");
    152 }
    153 
    154 
    155 /* read blocks */
    156 static int read_structure(int fd, unsigned long long start, void *buf, ssize_t len)
    157 {
    158     off64_t ret;
    159 
    160     ret = lseek64(fd, start, SEEK_SET);
    161     if (ret < 0) {
    162         SLOGE("failed to seek\n");
    163         return ret;
    164     }
    165 
    166     ret = read(fd, buf, len);
    167     if (ret < 0) {
    168         SLOGE("failed to read\n");
    169         return ret;
    170     }
    171     if (ret != len) {
    172         SLOGE("failed to read all\n");
    173         return -1;
    174     }
    175     return 0;
    176 }
    177 
    178 static int read_structure_blk(int fd, unsigned long long start_blk, void *buf, size_t len)
    179 {
    180     return read_structure(fd, F2FS_BLKSIZE*start_blk, buf, F2FS_BLKSIZE * len);
    181 }
    182 
    183 static int read_f2fs_sb(int fd, struct f2fs_super_block *sb)
    184 {
    185     int rc;
    186     rc = read_structure(fd, F2FS_SUPER_OFFSET, sb, sizeof(*sb));
    187     if (le32_to_cpu(sb->magic) != F2FS_SUPER_MAGIC) {
    188         SLOGE("Not a valid F2FS super block. Magic:%#08x != %#08x",
    189                                   le32_to_cpu(sb->magic), F2FS_SUPER_MAGIC);
    190         return -1;
    191     }
    192     return 0;
    193 }
    194 
    195 unsigned int get_f2fs_filesystem_size_sec(char *dev)
    196 {
    197     int fd;
    198     if ((fd = open(dev, O_RDONLY)) < 0) {
    199         SLOGE("Cannot open device to get filesystem size ");
    200         return 0;
    201     }
    202     struct f2fs_super_block sb;
    203     if(read_f2fs_sb(fd, &sb))
    204         return 0;
    205     return (unsigned int)(le64_to_cpu(sb.block_count)*F2FS_BLKSIZE/DEFAULT_SECTOR_SIZE);
    206 }
    207 
    208 static struct f2fs_checkpoint *validate_checkpoint(block_t cp_addr,
    209                                                    unsigned long long *version, int fd)
    210 {
    211     unsigned char *cp_block_1, *cp_block_2;
    212     struct f2fs_checkpoint *cp_block, *cp_ret;
    213     u64 cp1_version = 0, cp2_version = 0;
    214 
    215     cp_block_1 = malloc(F2FS_BLKSIZE);
    216     if (!cp_block_1)
    217         return NULL;
    218 
    219     /* Read the 1st cp block in this CP pack */
    220     if (read_structure_blk(fd, cp_addr, cp_block_1, 1))
    221         goto invalid_cp1;
    222 
    223     /* get the version number */
    224     cp_block = (struct f2fs_checkpoint *)cp_block_1;
    225 
    226     cp1_version = le64_to_cpu(cp_block->checkpoint_ver);
    227 
    228     cp_block_2 = malloc(F2FS_BLKSIZE);
    229     if (!cp_block_2) {
    230         goto invalid_cp1;
    231     }
    232     /* Read the 2nd cp block in this CP pack */
    233     cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1;
    234     if (read_structure_blk(fd, cp_addr, cp_block_2, 1)) {
    235         goto invalid_cp2;
    236     }
    237 
    238     cp_block = (struct f2fs_checkpoint *)cp_block_2;
    239 
    240     cp2_version = le64_to_cpu(cp_block->checkpoint_ver);
    241 
    242     if (cp2_version == cp1_version) {
    243         *version = cp2_version;
    244         free(cp_block_2);
    245         return (struct f2fs_checkpoint *)cp_block_1;
    246     }
    247 
    248     /* There must be something wrong with this checkpoint */
    249 invalid_cp2:
    250     free(cp_block_2);
    251 invalid_cp1:
    252     free(cp_block_1);
    253     return NULL;
    254 }
    255 
    256 int get_valid_checkpoint_info(int fd, struct f2fs_super_block *sb, struct f2fs_checkpoint **cp,  struct f2fs_info *info)
    257 {
    258     struct f2fs_checkpoint *cp_block;
    259 
    260     struct f2fs_checkpoint *cp1, *cp2, *cur_cp;
    261     int cur_cp_no;
    262     unsigned long blk_size;// = 1<<le32_to_cpu(info->sb->log_blocksize);
    263     unsigned long long cp1_version = 0, cp2_version = 0;
    264     unsigned long long cp1_start_blk_no;
    265     unsigned long long cp2_start_blk_no;
    266     u32 bmp_size;
    267 
    268     blk_size = 1U<<le32_to_cpu(sb->log_blocksize);
    269 
    270     /*
    271      * Find valid cp by reading both packs and finding most recent one.
    272      */
    273     cp1_start_blk_no = le32_to_cpu(sb->cp_blkaddr);
    274     cp1 = validate_checkpoint(cp1_start_blk_no, &cp1_version, fd);
    275 
    276     /* The second checkpoint pack should start at the next segment */
    277     cp2_start_blk_no = cp1_start_blk_no + (1 << le32_to_cpu(sb->log_blocks_per_seg));
    278     cp2 = validate_checkpoint(cp2_start_blk_no, &cp2_version, fd);
    279 
    280     if (cp1 && cp2) {
    281         if (ver_after(cp2_version, cp1_version)) {
    282             cur_cp = cp2;
    283             info->cp_valid_cp_blkaddr = cp2_start_blk_no;
    284             free(cp1);
    285         } else {
    286             cur_cp = cp1;
    287             info->cp_valid_cp_blkaddr = cp1_start_blk_no;
    288             free(cp2);
    289         }
    290     } else if (cp1) {
    291         cur_cp = cp1;
    292         info->cp_valid_cp_blkaddr = cp1_start_blk_no;
    293     } else if (cp2) {
    294         cur_cp = cp2;
    295         info->cp_valid_cp_blkaddr = cp2_start_blk_no;
    296     } else {
    297         goto fail_no_cp;
    298     }
    299 
    300     *cp = cur_cp;
    301 
    302     return 0;
    303 
    304 fail_no_cp:
    305     SLOGE("Valid Checkpoint not found!!");
    306     return -EINVAL;
    307 }
    308 
    309 static int gather_sit_info(int fd, struct f2fs_info *info)
    310 {
    311     u64 num_segments = (info->total_blocks - info->main_blkaddr
    312             + info->blocks_per_segment - 1) / info->blocks_per_segment;
    313     u64 num_sit_blocks = (num_segments + SIT_ENTRY_PER_BLOCK - 1) / SIT_ENTRY_PER_BLOCK;
    314     u64 sit_block;
    315 
    316     info->sit_blocks = malloc(num_sit_blocks * sizeof(struct f2fs_sit_block));
    317     if (!info->sit_blocks)
    318         return -1;
    319 
    320     for(sit_block = 0; sit_block<num_sit_blocks; sit_block++) {
    321         off64_t address = info->sit_blkaddr + sit_block;
    322 
    323         if (f2fs_test_bit(sit_block, info->sit_bmp))
    324             address += info->blocks_per_sit;
    325 
    326         SLOGD("Reading cache block starting at block %"PRIu64, address);
    327         if (read_structure(fd, address * F2FS_BLKSIZE, &info->sit_blocks[sit_block], sizeof(struct f2fs_sit_block))) {
    328             SLOGE("Could not read sit block at block %"PRIu64, address);
    329             free(info->sit_blocks);
    330             return -1;
    331         }
    332     }
    333     return 0;
    334 }
    335 
    336 static inline int is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
    337 {
    338     unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags);
    339     return !!(ckpt_flags & f);
    340 }
    341 
    342 static inline u64 sum_blk_addr(struct f2fs_checkpoint *cp, struct f2fs_info *info, int base, int type)
    343 {
    344     return info->cp_valid_cp_blkaddr + le32_to_cpu(cp->cp_pack_total_block_count)
    345                 - (base + 1) + type;
    346 }
    347 
    348 static int get_sit_summary(int fd, struct f2fs_info *info, struct f2fs_checkpoint *cp)
    349 {
    350     char buffer[F2FS_BLKSIZE];
    351 
    352     info->sit_sums = calloc(1, sizeof(struct f2fs_summary_block));
    353     if (!info->sit_sums)
    354         return -1;
    355 
    356     /* CURSEG_COLD_DATA where the journaled SIT entries are. */
    357     if (is_set_ckpt_flags(cp, CP_COMPACT_SUM_FLAG)) {
    358         if (read_structure_blk(fd, info->cp_valid_cp_blkaddr + le32_to_cpu(cp->cp_pack_start_sum), buffer, 1))
    359             return -1;
    360         memcpy(&info->sit_sums->n_sits, &buffer[SUM_JOURNAL_SIZE], SUM_JOURNAL_SIZE);
    361     } else {
    362         u64 blk_addr;
    363         if (is_set_ckpt_flags(cp, CP_UMOUNT_FLAG))
    364             blk_addr = sum_blk_addr(cp, info, NR_CURSEG_TYPE, CURSEG_COLD_DATA);
    365         else
    366             blk_addr = sum_blk_addr(cp, info, NR_CURSEG_DATA_TYPE, CURSEG_COLD_DATA);
    367 
    368         if (read_structure_blk(fd, blk_addr, buffer, 1))
    369             return -1;
    370 
    371         memcpy(info->sit_sums, buffer, sizeof(struct f2fs_summary_block));
    372     }
    373     return 0;
    374 }
    375 
    376 struct f2fs_info *generate_f2fs_info(int fd)
    377 {
    378     struct f2fs_super_block *sb = NULL;
    379     struct f2fs_checkpoint *cp = NULL;
    380     struct f2fs_info *info;
    381 
    382     info = calloc(1, sizeof(*info));
    383     if (!info) {
    384         SLOGE("Out of memory!");
    385         return NULL;
    386     }
    387 
    388     sb = malloc(sizeof(*sb));
    389     if(!sb) {
    390         SLOGE("Out of memory!");
    391         free(info);
    392         return NULL;
    393     }
    394     if (read_f2fs_sb(fd, sb)) {
    395         SLOGE("Failed to read superblock");
    396         free(info);
    397         free(sb);
    398         return NULL;
    399     }
    400     dbg_print_raw_sb_info(sb);
    401 
    402     info->cp_blkaddr = le32_to_cpu(sb->cp_blkaddr);
    403     info->sit_blkaddr = le32_to_cpu(sb->sit_blkaddr);
    404     info->nat_blkaddr = le32_to_cpu(sb->nat_blkaddr);
    405     info->ssa_blkaddr = le32_to_cpu(sb->ssa_blkaddr);
    406     info->main_blkaddr = le32_to_cpu(sb->main_blkaddr);
    407     info->block_size = F2FS_BLKSIZE;
    408     info->total_blocks = sb->block_count;
    409     info->blocks_per_sit = (le32_to_cpu(sb->segment_count_sit) >> 1) << le32_to_cpu(sb->log_blocks_per_seg);
    410     info->blocks_per_segment = 1U << le32_to_cpu(sb->log_blocks_per_seg);
    411 
    412     if (get_valid_checkpoint_info(fd, sb, &cp, info))
    413         goto error;
    414     dbg_print_raw_ckpt_struct(cp);
    415 
    416     info->total_user_used = le32_to_cpu(cp->valid_block_count);
    417 
    418     u32 bmp_size = le32_to_cpu(cp->sit_ver_bitmap_bytesize);
    419 
    420     /* get sit validity bitmap */
    421     info->sit_bmp = malloc(bmp_size);
    422     if(!info->sit_bmp) {
    423         SLOGE("Out of memory!");
    424         goto error;
    425     }
    426 
    427     info->sit_bmp_size = bmp_size;
    428     if (read_structure(fd, info->cp_valid_cp_blkaddr * F2FS_BLKSIZE
    429                    + offsetof(struct f2fs_checkpoint, sit_nat_version_bitmap),
    430                    info->sit_bmp, bmp_size)) {
    431         SLOGE("Error getting SIT validity bitmap");
    432         goto error;
    433     }
    434 
    435     if (gather_sit_info(fd , info)) {
    436         SLOGE("Error getting SIT information");
    437         goto error;
    438     }
    439     if (get_sit_summary(fd, info, cp)) {
    440         SLOGE("Error getting SIT entries in summary area");
    441         goto error;
    442     }
    443     dbg_print_info_struct(info);
    444     return info;
    445 error:
    446     free(sb);
    447     free(cp);
    448     free_f2fs_info(info);
    449     return NULL;
    450 }
    451 
    452 void free_f2fs_info(struct f2fs_info *info)
    453 {
    454     if (info) {
    455         free(info->sit_blocks);
    456         info->sit_blocks = NULL;
    457 
    458         free(info->sit_bmp);
    459         info->sit_bmp = NULL;
    460 
    461         free(info->sit_sums);
    462         info->sit_sums = NULL;
    463     }
    464     free(info);
    465 }
    466 
    467 u64 get_num_blocks_used(struct f2fs_info *info)
    468 {
    469     return info->main_blkaddr + info->total_user_used;
    470 }
    471 
    472 int f2fs_test_bit(unsigned int nr, const char *p)
    473 {
    474     int mask;
    475     char *addr = (char *)p;
    476 
    477     addr += (nr >> 3);
    478     mask = 1 << (7 - (nr & 0x07));
    479     return (mask & *addr) != 0;
    480 }
    481 
    482 int run_on_used_blocks(u64 startblock, struct f2fs_info *info, int (*func)(u64 pos, void *data), void *data) {
    483     struct f2fs_sit_block sit_block_cache;
    484     struct f2fs_sit_entry * sit_entry;
    485     u64 sit_block_num_cur = 0, segnum = 0, block_offset;
    486     u64 block;
    487     unsigned int used, found, started = 0, i;
    488 
    489     for (block=startblock; block<info->total_blocks; block++) {
    490         /* TODO: Save only relevant portions of metadata */
    491         if (block < info->main_blkaddr) {
    492             if (func(block, data)) {
    493                 SLOGI("func error");
    494                 return -1;
    495             }
    496         } else {
    497             /* Main Section */
    498             segnum = (block - info->main_blkaddr)/info->blocks_per_segment;
    499 
    500             /* check the SIT entries in the journal */
    501             found = 0;
    502             for(i = 0; i < le16_to_cpu(info->sit_sums->n_sits); i++) {
    503                 if (le32_to_cpu(segno_in_journal(info->sit_sums, i)) == segnum) {
    504                     sit_entry = &sit_in_journal(info->sit_sums, i);
    505                     found = 1;
    506                     break;
    507                 }
    508             }
    509 
    510             /* get SIT entry from SIT section */
    511             if (!found) {
    512                 sit_block_num_cur = segnum/SIT_ENTRY_PER_BLOCK;
    513                 sit_entry = &info->sit_blocks[sit_block_num_cur].entries[segnum % SIT_ENTRY_PER_BLOCK];
    514             }
    515 
    516             block_offset = (block - info->main_blkaddr) % info->blocks_per_segment;
    517 
    518             used = f2fs_test_bit(block_offset, (char *)sit_entry->valid_map);
    519             if(used)
    520                 if (func(block, data))
    521                     return -1;
    522         }
    523     }
    524     return 0;
    525 }
    526 
    527 struct privdata
    528 {
    529     int count;
    530     int infd;
    531     int outfd;
    532     char* buf;
    533     char *zbuf;
    534     int done;
    535     struct f2fs_info *info;
    536 };
    537 
    538 
    539 /*
    540  * This is a simple test program. It performs a block to block copy of a
    541  * filesystem, replacing blocks identified as unused with 0's.
    542  */
    543 
    544 int copy_used(u64 pos, void *data)
    545 {
    546     struct privdata *d = data;
    547     char *buf;
    548     int pdone = (pos*100)/d->info->total_blocks;
    549     if (pdone > d->done) {
    550         d->done = pdone;
    551         printf("Done with %d percent\n", d->done);
    552     }
    553 
    554     d->count++;
    555     buf = d->buf;
    556     if(read_structure_blk(d->infd, (unsigned long long)pos, d->buf, 1)) {
    557         printf("Error reading!!!\n");
    558         return -1;
    559     }
    560 
    561     off64_t ret;
    562     ret = lseek64(d->outfd, pos*F2FS_BLKSIZE, SEEK_SET);
    563     if (ret < 0) {
    564         SLOGE("failed to seek\n");
    565         return ret;
    566     }
    567 
    568     ret = write(d->outfd, d->buf, F2FS_BLKSIZE);
    569     if (ret < 0) {
    570         SLOGE("failed to write\n");
    571         return ret;
    572     }
    573     if (ret != F2FS_BLKSIZE) {
    574         SLOGE("failed to read all\n");
    575         return -1;
    576     }
    577     return 0;
    578 }
    579 
    580 int main(int argc, char **argv)
    581 {
    582     if (argc != 3)
    583         printf("Usage: %s fs_file_in fs_file_out\n", argv[0]);
    584     char *in = argv[1];
    585     char *out = argv[2];
    586     int infd, outfd;
    587 
    588     if ((infd = open(in, O_RDONLY)) < 0) {
    589         SLOGE("Cannot open device");
    590         return 0;
    591     }
    592     if ((outfd = open(out, O_WRONLY|O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
    593         SLOGE("Cannot open output");
    594         return 0;
    595     }
    596 
    597     struct privdata d;
    598     d.infd = infd;
    599     d.outfd = outfd;
    600     d.count = 0;
    601     struct f2fs_info *info = generate_f2fs_info(infd);
    602     if (!info) {
    603         printf("Failed to generate info!");
    604         return -1;
    605     }
    606     char *buf = malloc(F2FS_BLKSIZE);
    607     char *zbuf = calloc(1, F2FS_BLKSIZE);
    608     d.buf = buf;
    609     d.zbuf = zbuf;
    610     d.done = 0;
    611     d.info = info;
    612     int expected_count = get_num_blocks_used(info);
    613     run_on_used_blocks(0, info, &copy_used, &d);
    614     printf("Copied %d blocks. Expected to copy %d\n", d.count, expected_count);
    615     ftruncate64(outfd, info->total_blocks * F2FS_BLKSIZE);
    616     free_f2fs_info(info);
    617     free(buf);
    618     free(zbuf);
    619     close(infd);
    620     close(outfd);
    621     return 0;
    622 }
    623