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