1*33b1fccfSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0+
2*33b1fccfSAndroid Build Coastguard Worker /*
3*33b1fccfSAndroid Build Coastguard Worker * Copyright (C) 2021-2022 HUAWEI, Inc.
4*33b1fccfSAndroid Build Coastguard Worker * http://www.huawei.com/
5*33b1fccfSAndroid Build Coastguard Worker * Created by Wang Qi <[email protected]>
6*33b1fccfSAndroid Build Coastguard Worker * Guo Xuenan <[email protected]>
7*33b1fccfSAndroid Build Coastguard Worker */
8*33b1fccfSAndroid Build Coastguard Worker #define _GNU_SOURCE
9*33b1fccfSAndroid Build Coastguard Worker #include <stdlib.h>
10*33b1fccfSAndroid Build Coastguard Worker #include <getopt.h>
11*33b1fccfSAndroid Build Coastguard Worker #include <time.h>
12*33b1fccfSAndroid Build Coastguard Worker #include <sys/stat.h>
13*33b1fccfSAndroid Build Coastguard Worker #include "erofs/print.h"
14*33b1fccfSAndroid Build Coastguard Worker #include "erofs/inode.h"
15*33b1fccfSAndroid Build Coastguard Worker #include "erofs/dir.h"
16*33b1fccfSAndroid Build Coastguard Worker #include "erofs/compress.h"
17*33b1fccfSAndroid Build Coastguard Worker #include "erofs/fragments.h"
18*33b1fccfSAndroid Build Coastguard Worker #include "../lib/liberofs_private.h"
19*33b1fccfSAndroid Build Coastguard Worker #include "../lib/liberofs_uuid.h"
20*33b1fccfSAndroid Build Coastguard Worker
21*33b1fccfSAndroid Build Coastguard Worker
22*33b1fccfSAndroid Build Coastguard Worker struct erofsdump_cfg {
23*33b1fccfSAndroid Build Coastguard Worker unsigned int totalshow;
24*33b1fccfSAndroid Build Coastguard Worker bool show_inode;
25*33b1fccfSAndroid Build Coastguard Worker bool show_extent;
26*33b1fccfSAndroid Build Coastguard Worker bool show_superblock;
27*33b1fccfSAndroid Build Coastguard Worker bool show_statistics;
28*33b1fccfSAndroid Build Coastguard Worker bool show_subdirectories;
29*33b1fccfSAndroid Build Coastguard Worker erofs_nid_t nid;
30*33b1fccfSAndroid Build Coastguard Worker const char *inode_path;
31*33b1fccfSAndroid Build Coastguard Worker };
32*33b1fccfSAndroid Build Coastguard Worker static struct erofsdump_cfg dumpcfg;
33*33b1fccfSAndroid Build Coastguard Worker
34*33b1fccfSAndroid Build Coastguard Worker static const char chart_format[] = "%-16s %-11d %8.2f%% |%-50s|\n";
35*33b1fccfSAndroid Build Coastguard Worker static const char header_format[] = "%-16s %11s %16s |%-50s|\n";
36*33b1fccfSAndroid Build Coastguard Worker static char *file_types[] = {
37*33b1fccfSAndroid Build Coastguard Worker ".txt", ".so", ".xml", ".apk",
38*33b1fccfSAndroid Build Coastguard Worker ".odex", ".vdex", ".oat", ".rc",
39*33b1fccfSAndroid Build Coastguard Worker ".otf", "others",
40*33b1fccfSAndroid Build Coastguard Worker };
41*33b1fccfSAndroid Build Coastguard Worker #define OTHERFILETYPE ARRAY_SIZE(file_types)
42*33b1fccfSAndroid Build Coastguard Worker /* (1 << FILE_MAX_SIZE_BITS)KB */
43*33b1fccfSAndroid Build Coastguard Worker #define FILE_MAX_SIZE_BITS 16
44*33b1fccfSAndroid Build Coastguard Worker
45*33b1fccfSAndroid Build Coastguard Worker static const char * const file_category_types[] = {
46*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_UNKNOWN] = "unknown type",
47*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_REG_FILE] = "regular file",
48*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_DIR] = "directory",
49*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_CHRDEV] = "char dev",
50*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_BLKDEV] = "block dev",
51*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_FIFO] = "FIFO file",
52*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_SOCK] = "SOCK file",
53*33b1fccfSAndroid Build Coastguard Worker [EROFS_FT_SYMLINK] = "symlink file",
54*33b1fccfSAndroid Build Coastguard Worker };
55*33b1fccfSAndroid Build Coastguard Worker
56*33b1fccfSAndroid Build Coastguard Worker struct erofs_statistics {
57*33b1fccfSAndroid Build Coastguard Worker unsigned long files;
58*33b1fccfSAndroid Build Coastguard Worker unsigned long compressed_files;
59*33b1fccfSAndroid Build Coastguard Worker unsigned long uncompressed_files;
60*33b1fccfSAndroid Build Coastguard Worker unsigned long files_total_size;
61*33b1fccfSAndroid Build Coastguard Worker unsigned long files_total_origin_size;
62*33b1fccfSAndroid Build Coastguard Worker double compress_rate;
63*33b1fccfSAndroid Build Coastguard Worker
64*33b1fccfSAndroid Build Coastguard Worker /* [statistics] # of files based on inode_info->flags */
65*33b1fccfSAndroid Build Coastguard Worker unsigned long file_category_stat[EROFS_FT_MAX];
66*33b1fccfSAndroid Build Coastguard Worker /* [statistics] # of files based on file name extensions */
67*33b1fccfSAndroid Build Coastguard Worker unsigned int file_type_stat[OTHERFILETYPE];
68*33b1fccfSAndroid Build Coastguard Worker /* [statistics] # of files based on the original size of files */
69*33b1fccfSAndroid Build Coastguard Worker unsigned int file_original_size[FILE_MAX_SIZE_BITS + 1];
70*33b1fccfSAndroid Build Coastguard Worker /* [statistics] # of files based on the compressed size of files */
71*33b1fccfSAndroid Build Coastguard Worker unsigned int file_comp_size[FILE_MAX_SIZE_BITS + 1];
72*33b1fccfSAndroid Build Coastguard Worker };
73*33b1fccfSAndroid Build Coastguard Worker static struct erofs_statistics stats;
74*33b1fccfSAndroid Build Coastguard Worker
75*33b1fccfSAndroid Build Coastguard Worker static struct option long_options[] = {
76*33b1fccfSAndroid Build Coastguard Worker {"version", no_argument, NULL, 'V'},
77*33b1fccfSAndroid Build Coastguard Worker {"help", no_argument, NULL, 'h'},
78*33b1fccfSAndroid Build Coastguard Worker {"nid", required_argument, NULL, 2},
79*33b1fccfSAndroid Build Coastguard Worker {"device", required_argument, NULL, 3},
80*33b1fccfSAndroid Build Coastguard Worker {"path", required_argument, NULL, 4},
81*33b1fccfSAndroid Build Coastguard Worker {"ls", no_argument, NULL, 5},
82*33b1fccfSAndroid Build Coastguard Worker {"offset", required_argument, NULL, 6},
83*33b1fccfSAndroid Build Coastguard Worker {0, 0, 0, 0},
84*33b1fccfSAndroid Build Coastguard Worker };
85*33b1fccfSAndroid Build Coastguard Worker
86*33b1fccfSAndroid Build Coastguard Worker struct erofsdump_feature {
87*33b1fccfSAndroid Build Coastguard Worker bool compat;
88*33b1fccfSAndroid Build Coastguard Worker u32 flag;
89*33b1fccfSAndroid Build Coastguard Worker const char *name;
90*33b1fccfSAndroid Build Coastguard Worker };
91*33b1fccfSAndroid Build Coastguard Worker
92*33b1fccfSAndroid Build Coastguard Worker static struct erofsdump_feature feature_lists[] = {
93*33b1fccfSAndroid Build Coastguard Worker { true, EROFS_FEATURE_COMPAT_SB_CHKSUM, "sb_csum" },
94*33b1fccfSAndroid Build Coastguard Worker { true, EROFS_FEATURE_COMPAT_MTIME, "mtime" },
95*33b1fccfSAndroid Build Coastguard Worker { true, EROFS_FEATURE_COMPAT_XATTR_FILTER, "xattr_filter" },
96*33b1fccfSAndroid Build Coastguard Worker { false, EROFS_FEATURE_INCOMPAT_ZERO_PADDING, "0padding" },
97*33b1fccfSAndroid Build Coastguard Worker { false, EROFS_FEATURE_INCOMPAT_COMPR_CFGS, "compr_cfgs" },
98*33b1fccfSAndroid Build Coastguard Worker { false, EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER, "big_pcluster" },
99*33b1fccfSAndroid Build Coastguard Worker { false, EROFS_FEATURE_INCOMPAT_CHUNKED_FILE, "chunked_file" },
100*33b1fccfSAndroid Build Coastguard Worker { false, EROFS_FEATURE_INCOMPAT_DEVICE_TABLE, "device_table" },
101*33b1fccfSAndroid Build Coastguard Worker { false, EROFS_FEATURE_INCOMPAT_ZTAILPACKING, "ztailpacking" },
102*33b1fccfSAndroid Build Coastguard Worker { false, EROFS_FEATURE_INCOMPAT_FRAGMENTS, "fragments" },
103*33b1fccfSAndroid Build Coastguard Worker { false, EROFS_FEATURE_INCOMPAT_DEDUPE, "dedupe" },
104*33b1fccfSAndroid Build Coastguard Worker { false, EROFS_FEATURE_INCOMPAT_XATTR_PREFIXES, "xattr_prefixes" },
105*33b1fccfSAndroid Build Coastguard Worker };
106*33b1fccfSAndroid Build Coastguard Worker
107*33b1fccfSAndroid Build Coastguard Worker static int erofsdump_readdir(struct erofs_dir_context *ctx);
108*33b1fccfSAndroid Build Coastguard Worker
usage(int argc,char ** argv)109*33b1fccfSAndroid Build Coastguard Worker static void usage(int argc, char **argv)
110*33b1fccfSAndroid Build Coastguard Worker {
111*33b1fccfSAndroid Build Coastguard Worker // " 1 2 3 4 5 6 7 8 "
112*33b1fccfSAndroid Build Coastguard Worker // "12345678901234567890123456789012345678901234567890123456789012345678901234567890\n"
113*33b1fccfSAndroid Build Coastguard Worker printf(
114*33b1fccfSAndroid Build Coastguard Worker "Usage: %s [OPTIONS] IMAGE\n"
115*33b1fccfSAndroid Build Coastguard Worker "Dump erofs layout from IMAGE.\n"
116*33b1fccfSAndroid Build Coastguard Worker "\n"
117*33b1fccfSAndroid Build Coastguard Worker "General options:\n"
118*33b1fccfSAndroid Build Coastguard Worker " -V, --version print the version number of dump.erofs and exit\n"
119*33b1fccfSAndroid Build Coastguard Worker " -h, --help display this help and exit\n"
120*33b1fccfSAndroid Build Coastguard Worker "\n"
121*33b1fccfSAndroid Build Coastguard Worker " -S show statistic information of the image\n"
122*33b1fccfSAndroid Build Coastguard Worker " -e show extent info (INODE required)\n"
123*33b1fccfSAndroid Build Coastguard Worker " -s show information about superblock\n"
124*33b1fccfSAndroid Build Coastguard Worker " --device=X specify an extra device to be used together\n"
125*33b1fccfSAndroid Build Coastguard Worker " --ls show directory contents (INODE required)\n"
126*33b1fccfSAndroid Build Coastguard Worker " --nid=# show the target inode info of nid #\n"
127*33b1fccfSAndroid Build Coastguard Worker " --offset=# skip # bytes at the beginning of IMAGE\n"
128*33b1fccfSAndroid Build Coastguard Worker " --path=X show the target inode info of path X\n",
129*33b1fccfSAndroid Build Coastguard Worker argv[0]);
130*33b1fccfSAndroid Build Coastguard Worker }
131*33b1fccfSAndroid Build Coastguard Worker
erofsdump_print_version(void)132*33b1fccfSAndroid Build Coastguard Worker static void erofsdump_print_version(void)
133*33b1fccfSAndroid Build Coastguard Worker {
134*33b1fccfSAndroid Build Coastguard Worker printf("dump.erofs (erofs-utils) %s\n", cfg.c_version);
135*33b1fccfSAndroid Build Coastguard Worker }
136*33b1fccfSAndroid Build Coastguard Worker
erofsdump_parse_options_cfg(int argc,char ** argv)137*33b1fccfSAndroid Build Coastguard Worker static int erofsdump_parse_options_cfg(int argc, char **argv)
138*33b1fccfSAndroid Build Coastguard Worker {
139*33b1fccfSAndroid Build Coastguard Worker int opt, err;
140*33b1fccfSAndroid Build Coastguard Worker char *endptr;
141*33b1fccfSAndroid Build Coastguard Worker
142*33b1fccfSAndroid Build Coastguard Worker while ((opt = getopt_long(argc, argv, "SVesh",
143*33b1fccfSAndroid Build Coastguard Worker long_options, NULL)) != -1) {
144*33b1fccfSAndroid Build Coastguard Worker switch (opt) {
145*33b1fccfSAndroid Build Coastguard Worker case 'e':
146*33b1fccfSAndroid Build Coastguard Worker dumpcfg.show_extent = true;
147*33b1fccfSAndroid Build Coastguard Worker ++dumpcfg.totalshow;
148*33b1fccfSAndroid Build Coastguard Worker break;
149*33b1fccfSAndroid Build Coastguard Worker case 's':
150*33b1fccfSAndroid Build Coastguard Worker dumpcfg.show_superblock = true;
151*33b1fccfSAndroid Build Coastguard Worker ++dumpcfg.totalshow;
152*33b1fccfSAndroid Build Coastguard Worker break;
153*33b1fccfSAndroid Build Coastguard Worker case 'S':
154*33b1fccfSAndroid Build Coastguard Worker dumpcfg.show_statistics = true;
155*33b1fccfSAndroid Build Coastguard Worker ++dumpcfg.totalshow;
156*33b1fccfSAndroid Build Coastguard Worker break;
157*33b1fccfSAndroid Build Coastguard Worker case 'V':
158*33b1fccfSAndroid Build Coastguard Worker erofsdump_print_version();
159*33b1fccfSAndroid Build Coastguard Worker exit(0);
160*33b1fccfSAndroid Build Coastguard Worker case 2:
161*33b1fccfSAndroid Build Coastguard Worker dumpcfg.show_inode = true;
162*33b1fccfSAndroid Build Coastguard Worker dumpcfg.nid = (erofs_nid_t)atoll(optarg);
163*33b1fccfSAndroid Build Coastguard Worker ++dumpcfg.totalshow;
164*33b1fccfSAndroid Build Coastguard Worker break;
165*33b1fccfSAndroid Build Coastguard Worker case 'h':
166*33b1fccfSAndroid Build Coastguard Worker usage(argc, argv);
167*33b1fccfSAndroid Build Coastguard Worker exit(0);
168*33b1fccfSAndroid Build Coastguard Worker case 3:
169*33b1fccfSAndroid Build Coastguard Worker err = erofs_blob_open_ro(&g_sbi, optarg);
170*33b1fccfSAndroid Build Coastguard Worker if (err)
171*33b1fccfSAndroid Build Coastguard Worker return err;
172*33b1fccfSAndroid Build Coastguard Worker ++g_sbi.extra_devices;
173*33b1fccfSAndroid Build Coastguard Worker break;
174*33b1fccfSAndroid Build Coastguard Worker case 4:
175*33b1fccfSAndroid Build Coastguard Worker dumpcfg.inode_path = optarg;
176*33b1fccfSAndroid Build Coastguard Worker dumpcfg.show_inode = true;
177*33b1fccfSAndroid Build Coastguard Worker ++dumpcfg.totalshow;
178*33b1fccfSAndroid Build Coastguard Worker break;
179*33b1fccfSAndroid Build Coastguard Worker case 5:
180*33b1fccfSAndroid Build Coastguard Worker dumpcfg.show_subdirectories = true;
181*33b1fccfSAndroid Build Coastguard Worker break;
182*33b1fccfSAndroid Build Coastguard Worker case 6:
183*33b1fccfSAndroid Build Coastguard Worker g_sbi.bdev.offset = strtoull(optarg, &endptr, 0);
184*33b1fccfSAndroid Build Coastguard Worker if (*endptr != '\0') {
185*33b1fccfSAndroid Build Coastguard Worker erofs_err("invalid disk offset %s", optarg);
186*33b1fccfSAndroid Build Coastguard Worker return -EINVAL;
187*33b1fccfSAndroid Build Coastguard Worker }
188*33b1fccfSAndroid Build Coastguard Worker break;
189*33b1fccfSAndroid Build Coastguard Worker default:
190*33b1fccfSAndroid Build Coastguard Worker return -EINVAL;
191*33b1fccfSAndroid Build Coastguard Worker }
192*33b1fccfSAndroid Build Coastguard Worker }
193*33b1fccfSAndroid Build Coastguard Worker
194*33b1fccfSAndroid Build Coastguard Worker if (optind >= argc) {
195*33b1fccfSAndroid Build Coastguard Worker erofs_err("missing argument: IMAGE");
196*33b1fccfSAndroid Build Coastguard Worker return -EINVAL;
197*33b1fccfSAndroid Build Coastguard Worker }
198*33b1fccfSAndroid Build Coastguard Worker
199*33b1fccfSAndroid Build Coastguard Worker cfg.c_img_path = strdup(argv[optind++]);
200*33b1fccfSAndroid Build Coastguard Worker if (!cfg.c_img_path)
201*33b1fccfSAndroid Build Coastguard Worker return -ENOMEM;
202*33b1fccfSAndroid Build Coastguard Worker
203*33b1fccfSAndroid Build Coastguard Worker if (optind < argc) {
204*33b1fccfSAndroid Build Coastguard Worker erofs_err("unexpected argument: %s\n", argv[optind]);
205*33b1fccfSAndroid Build Coastguard Worker return -EINVAL;
206*33b1fccfSAndroid Build Coastguard Worker }
207*33b1fccfSAndroid Build Coastguard Worker return 0;
208*33b1fccfSAndroid Build Coastguard Worker }
209*33b1fccfSAndroid Build Coastguard Worker
erofsdump_get_occupied_size(struct erofs_inode * inode,erofs_off_t * size)210*33b1fccfSAndroid Build Coastguard Worker static int erofsdump_get_occupied_size(struct erofs_inode *inode,
211*33b1fccfSAndroid Build Coastguard Worker erofs_off_t *size)
212*33b1fccfSAndroid Build Coastguard Worker {
213*33b1fccfSAndroid Build Coastguard Worker *size = 0;
214*33b1fccfSAndroid Build Coastguard Worker switch (inode->datalayout) {
215*33b1fccfSAndroid Build Coastguard Worker case EROFS_INODE_FLAT_INLINE:
216*33b1fccfSAndroid Build Coastguard Worker case EROFS_INODE_FLAT_PLAIN:
217*33b1fccfSAndroid Build Coastguard Worker case EROFS_INODE_CHUNK_BASED:
218*33b1fccfSAndroid Build Coastguard Worker stats.uncompressed_files++;
219*33b1fccfSAndroid Build Coastguard Worker *size = inode->i_size;
220*33b1fccfSAndroid Build Coastguard Worker break;
221*33b1fccfSAndroid Build Coastguard Worker case EROFS_INODE_COMPRESSED_FULL:
222*33b1fccfSAndroid Build Coastguard Worker case EROFS_INODE_COMPRESSED_COMPACT:
223*33b1fccfSAndroid Build Coastguard Worker stats.compressed_files++;
224*33b1fccfSAndroid Build Coastguard Worker *size = inode->u.i_blocks * erofs_blksiz(inode->sbi);
225*33b1fccfSAndroid Build Coastguard Worker break;
226*33b1fccfSAndroid Build Coastguard Worker default:
227*33b1fccfSAndroid Build Coastguard Worker erofs_err("unknown datalayout");
228*33b1fccfSAndroid Build Coastguard Worker return -ENOTSUP;
229*33b1fccfSAndroid Build Coastguard Worker }
230*33b1fccfSAndroid Build Coastguard Worker return 0;
231*33b1fccfSAndroid Build Coastguard Worker }
232*33b1fccfSAndroid Build Coastguard Worker
inc_file_extension_count(const char * dname,unsigned int len)233*33b1fccfSAndroid Build Coastguard Worker static void inc_file_extension_count(const char *dname, unsigned int len)
234*33b1fccfSAndroid Build Coastguard Worker {
235*33b1fccfSAndroid Build Coastguard Worker char *postfix = memrchr(dname, '.', len);
236*33b1fccfSAndroid Build Coastguard Worker int type;
237*33b1fccfSAndroid Build Coastguard Worker
238*33b1fccfSAndroid Build Coastguard Worker if (!postfix) {
239*33b1fccfSAndroid Build Coastguard Worker type = OTHERFILETYPE - 1;
240*33b1fccfSAndroid Build Coastguard Worker } else {
241*33b1fccfSAndroid Build Coastguard Worker for (type = 0; type < OTHERFILETYPE - 1; ++type)
242*33b1fccfSAndroid Build Coastguard Worker if (!strncmp(postfix, file_types[type],
243*33b1fccfSAndroid Build Coastguard Worker len - (postfix - dname)))
244*33b1fccfSAndroid Build Coastguard Worker break;
245*33b1fccfSAndroid Build Coastguard Worker }
246*33b1fccfSAndroid Build Coastguard Worker ++stats.file_type_stat[type];
247*33b1fccfSAndroid Build Coastguard Worker }
248*33b1fccfSAndroid Build Coastguard Worker
update_file_size_statistics(erofs_off_t size,bool original)249*33b1fccfSAndroid Build Coastguard Worker static void update_file_size_statistics(erofs_off_t size, bool original)
250*33b1fccfSAndroid Build Coastguard Worker {
251*33b1fccfSAndroid Build Coastguard Worker unsigned int *file_size = original ? stats.file_original_size :
252*33b1fccfSAndroid Build Coastguard Worker stats.file_comp_size;
253*33b1fccfSAndroid Build Coastguard Worker int size_mark = 0;
254*33b1fccfSAndroid Build Coastguard Worker
255*33b1fccfSAndroid Build Coastguard Worker size >>= 10;
256*33b1fccfSAndroid Build Coastguard Worker
257*33b1fccfSAndroid Build Coastguard Worker while (size) {
258*33b1fccfSAndroid Build Coastguard Worker size >>= 1;
259*33b1fccfSAndroid Build Coastguard Worker size_mark++;
260*33b1fccfSAndroid Build Coastguard Worker }
261*33b1fccfSAndroid Build Coastguard Worker
262*33b1fccfSAndroid Build Coastguard Worker if (size_mark >= FILE_MAX_SIZE_BITS)
263*33b1fccfSAndroid Build Coastguard Worker file_size[FILE_MAX_SIZE_BITS]++;
264*33b1fccfSAndroid Build Coastguard Worker else
265*33b1fccfSAndroid Build Coastguard Worker file_size[size_mark]++;
266*33b1fccfSAndroid Build Coastguard Worker }
267*33b1fccfSAndroid Build Coastguard Worker
erofsdump_ls_dirent_iter(struct erofs_dir_context * ctx)268*33b1fccfSAndroid Build Coastguard Worker static int erofsdump_ls_dirent_iter(struct erofs_dir_context *ctx)
269*33b1fccfSAndroid Build Coastguard Worker {
270*33b1fccfSAndroid Build Coastguard Worker char fname[EROFS_NAME_LEN + 1];
271*33b1fccfSAndroid Build Coastguard Worker
272*33b1fccfSAndroid Build Coastguard Worker strncpy(fname, ctx->dname, ctx->de_namelen);
273*33b1fccfSAndroid Build Coastguard Worker fname[ctx->de_namelen] = '\0';
274*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "%10llu %u %s\n", ctx->de_nid | 0ULL,
275*33b1fccfSAndroid Build Coastguard Worker ctx->de_ftype, fname);
276*33b1fccfSAndroid Build Coastguard Worker return 0;
277*33b1fccfSAndroid Build Coastguard Worker }
278*33b1fccfSAndroid Build Coastguard Worker
erofsdump_dirent_iter(struct erofs_dir_context * ctx)279*33b1fccfSAndroid Build Coastguard Worker static int erofsdump_dirent_iter(struct erofs_dir_context *ctx)
280*33b1fccfSAndroid Build Coastguard Worker {
281*33b1fccfSAndroid Build Coastguard Worker /* skip "." and ".." dentry */
282*33b1fccfSAndroid Build Coastguard Worker if (ctx->dot_dotdot)
283*33b1fccfSAndroid Build Coastguard Worker return 0;
284*33b1fccfSAndroid Build Coastguard Worker
285*33b1fccfSAndroid Build Coastguard Worker return erofsdump_readdir(ctx);
286*33b1fccfSAndroid Build Coastguard Worker }
287*33b1fccfSAndroid Build Coastguard Worker
erofsdump_read_packed_inode(void)288*33b1fccfSAndroid Build Coastguard Worker static int erofsdump_read_packed_inode(void)
289*33b1fccfSAndroid Build Coastguard Worker {
290*33b1fccfSAndroid Build Coastguard Worker int err;
291*33b1fccfSAndroid Build Coastguard Worker erofs_off_t occupied_size = 0;
292*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode vi = { .sbi = &g_sbi, .nid = g_sbi.packed_nid };
293*33b1fccfSAndroid Build Coastguard Worker
294*33b1fccfSAndroid Build Coastguard Worker if (!(erofs_sb_has_fragments(&g_sbi) && g_sbi.packed_nid > 0))
295*33b1fccfSAndroid Build Coastguard Worker return 0;
296*33b1fccfSAndroid Build Coastguard Worker
297*33b1fccfSAndroid Build Coastguard Worker err = erofs_read_inode_from_disk(&vi);
298*33b1fccfSAndroid Build Coastguard Worker if (err) {
299*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to read packed file inode from disk");
300*33b1fccfSAndroid Build Coastguard Worker return err;
301*33b1fccfSAndroid Build Coastguard Worker }
302*33b1fccfSAndroid Build Coastguard Worker
303*33b1fccfSAndroid Build Coastguard Worker err = erofsdump_get_occupied_size(&vi, &occupied_size);
304*33b1fccfSAndroid Build Coastguard Worker if (err) {
305*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to get the file size of packed inode");
306*33b1fccfSAndroid Build Coastguard Worker return err;
307*33b1fccfSAndroid Build Coastguard Worker }
308*33b1fccfSAndroid Build Coastguard Worker
309*33b1fccfSAndroid Build Coastguard Worker stats.files_total_size += occupied_size;
310*33b1fccfSAndroid Build Coastguard Worker update_file_size_statistics(occupied_size, false);
311*33b1fccfSAndroid Build Coastguard Worker return 0;
312*33b1fccfSAndroid Build Coastguard Worker }
313*33b1fccfSAndroid Build Coastguard Worker
erofsdump_readdir(struct erofs_dir_context * ctx)314*33b1fccfSAndroid Build Coastguard Worker static int erofsdump_readdir(struct erofs_dir_context *ctx)
315*33b1fccfSAndroid Build Coastguard Worker {
316*33b1fccfSAndroid Build Coastguard Worker int err;
317*33b1fccfSAndroid Build Coastguard Worker erofs_off_t occupied_size = 0;
318*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode vi = { .sbi = &g_sbi, .nid = ctx->de_nid };
319*33b1fccfSAndroid Build Coastguard Worker
320*33b1fccfSAndroid Build Coastguard Worker err = erofs_read_inode_from_disk(&vi);
321*33b1fccfSAndroid Build Coastguard Worker if (err) {
322*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to read file inode from disk");
323*33b1fccfSAndroid Build Coastguard Worker return err;
324*33b1fccfSAndroid Build Coastguard Worker }
325*33b1fccfSAndroid Build Coastguard Worker stats.files++;
326*33b1fccfSAndroid Build Coastguard Worker stats.file_category_stat[erofs_mode_to_ftype(vi.i_mode)]++;
327*33b1fccfSAndroid Build Coastguard Worker
328*33b1fccfSAndroid Build Coastguard Worker err = erofsdump_get_occupied_size(&vi, &occupied_size);
329*33b1fccfSAndroid Build Coastguard Worker if (err) {
330*33b1fccfSAndroid Build Coastguard Worker erofs_err("get file size failed");
331*33b1fccfSAndroid Build Coastguard Worker return err;
332*33b1fccfSAndroid Build Coastguard Worker }
333*33b1fccfSAndroid Build Coastguard Worker
334*33b1fccfSAndroid Build Coastguard Worker if (S_ISREG(vi.i_mode)) {
335*33b1fccfSAndroid Build Coastguard Worker stats.files_total_origin_size += vi.i_size;
336*33b1fccfSAndroid Build Coastguard Worker inc_file_extension_count(ctx->dname, ctx->de_namelen);
337*33b1fccfSAndroid Build Coastguard Worker stats.files_total_size += occupied_size;
338*33b1fccfSAndroid Build Coastguard Worker update_file_size_statistics(vi.i_size, true);
339*33b1fccfSAndroid Build Coastguard Worker update_file_size_statistics(occupied_size, false);
340*33b1fccfSAndroid Build Coastguard Worker }
341*33b1fccfSAndroid Build Coastguard Worker
342*33b1fccfSAndroid Build Coastguard Worker /* XXXX: the dir depth should be restricted in order to avoid loops */
343*33b1fccfSAndroid Build Coastguard Worker if (S_ISDIR(vi.i_mode)) {
344*33b1fccfSAndroid Build Coastguard Worker struct erofs_dir_context nctx = {
345*33b1fccfSAndroid Build Coastguard Worker .flags = ctx->dir ? EROFS_READDIR_VALID_PNID : 0,
346*33b1fccfSAndroid Build Coastguard Worker .pnid = ctx->dir ? ctx->dir->nid : 0,
347*33b1fccfSAndroid Build Coastguard Worker .dir = &vi,
348*33b1fccfSAndroid Build Coastguard Worker .cb = erofsdump_dirent_iter,
349*33b1fccfSAndroid Build Coastguard Worker };
350*33b1fccfSAndroid Build Coastguard Worker
351*33b1fccfSAndroid Build Coastguard Worker return erofs_iterate_dir(&nctx, false);
352*33b1fccfSAndroid Build Coastguard Worker }
353*33b1fccfSAndroid Build Coastguard Worker return 0;
354*33b1fccfSAndroid Build Coastguard Worker }
355*33b1fccfSAndroid Build Coastguard Worker
erofsdump_map_blocks(struct erofs_inode * inode,struct erofs_map_blocks * map,int flags)356*33b1fccfSAndroid Build Coastguard Worker static int erofsdump_map_blocks(struct erofs_inode *inode,
357*33b1fccfSAndroid Build Coastguard Worker struct erofs_map_blocks *map, int flags)
358*33b1fccfSAndroid Build Coastguard Worker {
359*33b1fccfSAndroid Build Coastguard Worker if (erofs_inode_is_data_compressed(inode->datalayout))
360*33b1fccfSAndroid Build Coastguard Worker return z_erofs_map_blocks_iter(inode, map, flags);
361*33b1fccfSAndroid Build Coastguard Worker return erofs_map_blocks(inode, map, flags);
362*33b1fccfSAndroid Build Coastguard Worker }
363*33b1fccfSAndroid Build Coastguard Worker
erofsdump_show_fileinfo(bool show_extent)364*33b1fccfSAndroid Build Coastguard Worker static void erofsdump_show_fileinfo(bool show_extent)
365*33b1fccfSAndroid Build Coastguard Worker {
366*33b1fccfSAndroid Build Coastguard Worker const char *ext_fmt[] = {
367*33b1fccfSAndroid Build Coastguard Worker "%4d: %8" PRIu64 "..%8" PRIu64 " | %7" PRIu64 " : %10" PRIu64 "..%10" PRIu64 " | %7" PRIu64 "\n",
368*33b1fccfSAndroid Build Coastguard Worker "%4d: %8" PRIu64 "..%8" PRIu64 " | %7" PRIu64 " : %10" PRIu64 "..%10" PRIu64 " | %7" PRIu64 " # device %u\n"
369*33b1fccfSAndroid Build Coastguard Worker };
370*33b1fccfSAndroid Build Coastguard Worker int err, i;
371*33b1fccfSAndroid Build Coastguard Worker erofs_off_t size;
372*33b1fccfSAndroid Build Coastguard Worker u16 access_mode;
373*33b1fccfSAndroid Build Coastguard Worker struct erofs_inode inode = { .sbi = &g_sbi, .nid = dumpcfg.nid };
374*33b1fccfSAndroid Build Coastguard Worker char path[PATH_MAX];
375*33b1fccfSAndroid Build Coastguard Worker char access_mode_str[] = "rwxrwxrwx";
376*33b1fccfSAndroid Build Coastguard Worker char timebuf[128] = {0};
377*33b1fccfSAndroid Build Coastguard Worker unsigned int extent_count = 0;
378*33b1fccfSAndroid Build Coastguard Worker struct erofs_map_blocks map = {
379*33b1fccfSAndroid Build Coastguard Worker .index = UINT_MAX,
380*33b1fccfSAndroid Build Coastguard Worker .m_la = 0,
381*33b1fccfSAndroid Build Coastguard Worker };
382*33b1fccfSAndroid Build Coastguard Worker
383*33b1fccfSAndroid Build Coastguard Worker if (dumpcfg.inode_path) {
384*33b1fccfSAndroid Build Coastguard Worker err = erofs_ilookup(dumpcfg.inode_path, &inode);
385*33b1fccfSAndroid Build Coastguard Worker if (err) {
386*33b1fccfSAndroid Build Coastguard Worker erofs_err("read inode failed @ %s", dumpcfg.inode_path);
387*33b1fccfSAndroid Build Coastguard Worker return;
388*33b1fccfSAndroid Build Coastguard Worker }
389*33b1fccfSAndroid Build Coastguard Worker } else {
390*33b1fccfSAndroid Build Coastguard Worker err = erofs_read_inode_from_disk(&inode);
391*33b1fccfSAndroid Build Coastguard Worker if (err) {
392*33b1fccfSAndroid Build Coastguard Worker erofs_err("read inode failed @ nid %llu",
393*33b1fccfSAndroid Build Coastguard Worker inode.nid | 0ULL);
394*33b1fccfSAndroid Build Coastguard Worker return;
395*33b1fccfSAndroid Build Coastguard Worker }
396*33b1fccfSAndroid Build Coastguard Worker }
397*33b1fccfSAndroid Build Coastguard Worker
398*33b1fccfSAndroid Build Coastguard Worker err = erofs_get_occupied_size(&inode, &size);
399*33b1fccfSAndroid Build Coastguard Worker if (err) {
400*33b1fccfSAndroid Build Coastguard Worker erofs_err("get file size failed @ nid %llu", inode.nid | 0ULL);
401*33b1fccfSAndroid Build Coastguard Worker return;
402*33b1fccfSAndroid Build Coastguard Worker }
403*33b1fccfSAndroid Build Coastguard Worker
404*33b1fccfSAndroid Build Coastguard Worker err = erofs_get_pathname(inode.sbi, inode.nid, path, sizeof(path));
405*33b1fccfSAndroid Build Coastguard Worker if (err < 0) {
406*33b1fccfSAndroid Build Coastguard Worker strncpy(path, "(not found)", sizeof(path) - 1);
407*33b1fccfSAndroid Build Coastguard Worker path[sizeof(path) - 1] = '\0';
408*33b1fccfSAndroid Build Coastguard Worker }
409*33b1fccfSAndroid Build Coastguard Worker
410*33b1fccfSAndroid Build Coastguard Worker strftime(timebuf, sizeof(timebuf),
411*33b1fccfSAndroid Build Coastguard Worker "%Y-%m-%d %H:%M:%S", localtime((time_t *)&inode.i_mtime));
412*33b1fccfSAndroid Build Coastguard Worker access_mode = inode.i_mode & 0777;
413*33b1fccfSAndroid Build Coastguard Worker for (i = 8; i >= 0; i--)
414*33b1fccfSAndroid Build Coastguard Worker if (((access_mode >> i) & 1) == 0)
415*33b1fccfSAndroid Build Coastguard Worker access_mode_str[8 - i] = '-';
416*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Path : %s\n",
417*33b1fccfSAndroid Build Coastguard Worker erofs_is_packed_inode(&inode) ? "(packed file)" : path);
418*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Size: %" PRIu64" On-disk size: %" PRIu64 " %s\n",
419*33b1fccfSAndroid Build Coastguard Worker inode.i_size, size,
420*33b1fccfSAndroid Build Coastguard Worker file_category_types[erofs_mode_to_ftype(inode.i_mode)]);
421*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "NID: %" PRIu64 " ", inode.nid);
422*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Links: %u ", inode.i_nlink);
423*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Layout: %d Compression ratio: %.2f%%\n",
424*33b1fccfSAndroid Build Coastguard Worker inode.datalayout,
425*33b1fccfSAndroid Build Coastguard Worker (double)(100 * size) / (double)(inode.i_size));
426*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Inode size: %d ", inode.inode_isize);
427*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Xattr size: %u\n", inode.xattr_isize);
428*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Uid: %u Gid: %u ", inode.i_uid, inode.i_gid);
429*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Access: %04o/%s\n", access_mode, access_mode_str);
430*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Timestamp: %s.%09d\n", timebuf, inode.i_mtime_nsec);
431*33b1fccfSAndroid Build Coastguard Worker
432*33b1fccfSAndroid Build Coastguard Worker if (dumpcfg.show_subdirectories) {
433*33b1fccfSAndroid Build Coastguard Worker struct erofs_dir_context ctx = {
434*33b1fccfSAndroid Build Coastguard Worker .flags = EROFS_READDIR_VALID_PNID,
435*33b1fccfSAndroid Build Coastguard Worker .pnid = inode.nid,
436*33b1fccfSAndroid Build Coastguard Worker .dir = &inode,
437*33b1fccfSAndroid Build Coastguard Worker .cb = erofsdump_ls_dirent_iter,
438*33b1fccfSAndroid Build Coastguard Worker .de_nid = 0,
439*33b1fccfSAndroid Build Coastguard Worker .dname = "",
440*33b1fccfSAndroid Build Coastguard Worker .de_namelen = 0,
441*33b1fccfSAndroid Build Coastguard Worker };
442*33b1fccfSAndroid Build Coastguard Worker
443*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "\n NID TYPE FILENAME\n");
444*33b1fccfSAndroid Build Coastguard Worker err = erofs_iterate_dir(&ctx, false);
445*33b1fccfSAndroid Build Coastguard Worker if (err) {
446*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to list directory contents");
447*33b1fccfSAndroid Build Coastguard Worker return;
448*33b1fccfSAndroid Build Coastguard Worker }
449*33b1fccfSAndroid Build Coastguard Worker }
450*33b1fccfSAndroid Build Coastguard Worker
451*33b1fccfSAndroid Build Coastguard Worker if (!dumpcfg.show_extent)
452*33b1fccfSAndroid Build Coastguard Worker return;
453*33b1fccfSAndroid Build Coastguard Worker
454*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "\n Ext: logical offset | length : physical offset | length\n");
455*33b1fccfSAndroid Build Coastguard Worker while (map.m_la < inode.i_size) {
456*33b1fccfSAndroid Build Coastguard Worker struct erofs_map_dev mdev;
457*33b1fccfSAndroid Build Coastguard Worker
458*33b1fccfSAndroid Build Coastguard Worker err = erofsdump_map_blocks(&inode, &map,
459*33b1fccfSAndroid Build Coastguard Worker EROFS_GET_BLOCKS_FIEMAP);
460*33b1fccfSAndroid Build Coastguard Worker if (err) {
461*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to get file blocks range");
462*33b1fccfSAndroid Build Coastguard Worker return;
463*33b1fccfSAndroid Build Coastguard Worker }
464*33b1fccfSAndroid Build Coastguard Worker
465*33b1fccfSAndroid Build Coastguard Worker mdev = (struct erofs_map_dev) {
466*33b1fccfSAndroid Build Coastguard Worker .m_deviceid = map.m_deviceid,
467*33b1fccfSAndroid Build Coastguard Worker .m_pa = map.m_pa,
468*33b1fccfSAndroid Build Coastguard Worker };
469*33b1fccfSAndroid Build Coastguard Worker err = erofs_map_dev(inode.sbi, &mdev);
470*33b1fccfSAndroid Build Coastguard Worker if (err) {
471*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to map device");
472*33b1fccfSAndroid Build Coastguard Worker return;
473*33b1fccfSAndroid Build Coastguard Worker }
474*33b1fccfSAndroid Build Coastguard Worker
475*33b1fccfSAndroid Build Coastguard Worker if (map.m_flags & EROFS_MAP_FRAGMENT)
476*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, ext_fmt[!!mdev.m_deviceid],
477*33b1fccfSAndroid Build Coastguard Worker extent_count++,
478*33b1fccfSAndroid Build Coastguard Worker map.m_la, map.m_la + map.m_llen, map.m_llen,
479*33b1fccfSAndroid Build Coastguard Worker 0, 0, 0, mdev.m_deviceid);
480*33b1fccfSAndroid Build Coastguard Worker else
481*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, ext_fmt[!!mdev.m_deviceid],
482*33b1fccfSAndroid Build Coastguard Worker extent_count++,
483*33b1fccfSAndroid Build Coastguard Worker map.m_la, map.m_la + map.m_llen, map.m_llen,
484*33b1fccfSAndroid Build Coastguard Worker mdev.m_pa, mdev.m_pa + map.m_plen, map.m_plen,
485*33b1fccfSAndroid Build Coastguard Worker mdev.m_deviceid);
486*33b1fccfSAndroid Build Coastguard Worker map.m_la += map.m_llen;
487*33b1fccfSAndroid Build Coastguard Worker }
488*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "%s: %d extents found\n",
489*33b1fccfSAndroid Build Coastguard Worker erofs_is_packed_inode(&inode) ? "(packed file)" : path, extent_count);
490*33b1fccfSAndroid Build Coastguard Worker }
491*33b1fccfSAndroid Build Coastguard Worker
erofsdump_filesize_distribution(const char * title,unsigned int * file_counts,unsigned int len)492*33b1fccfSAndroid Build Coastguard Worker static void erofsdump_filesize_distribution(const char *title,
493*33b1fccfSAndroid Build Coastguard Worker unsigned int *file_counts, unsigned int len)
494*33b1fccfSAndroid Build Coastguard Worker {
495*33b1fccfSAndroid Build Coastguard Worker char col1[30];
496*33b1fccfSAndroid Build Coastguard Worker unsigned int col2, i, lowerbound, upperbound;
497*33b1fccfSAndroid Build Coastguard Worker double col3;
498*33b1fccfSAndroid Build Coastguard Worker char col4[400];
499*33b1fccfSAndroid Build Coastguard Worker
500*33b1fccfSAndroid Build Coastguard Worker lowerbound = 0;
501*33b1fccfSAndroid Build Coastguard Worker upperbound = 1;
502*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "\n%s file size distribution:\n", title);
503*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, header_format, ">=(KB) .. <(KB) ", "count",
504*33b1fccfSAndroid Build Coastguard Worker "ratio", "distribution");
505*33b1fccfSAndroid Build Coastguard Worker for (i = 0; i < len; i++) {
506*33b1fccfSAndroid Build Coastguard Worker memset(col1, 0, sizeof(col1));
507*33b1fccfSAndroid Build Coastguard Worker memset(col4, 0, sizeof(col4));
508*33b1fccfSAndroid Build Coastguard Worker if (i == len - 1)
509*33b1fccfSAndroid Build Coastguard Worker sprintf(col1, "%6d ..", lowerbound);
510*33b1fccfSAndroid Build Coastguard Worker else if (i <= 6)
511*33b1fccfSAndroid Build Coastguard Worker sprintf(col1, "%6d .. %-6d", lowerbound, upperbound);
512*33b1fccfSAndroid Build Coastguard Worker else
513*33b1fccfSAndroid Build Coastguard Worker
514*33b1fccfSAndroid Build Coastguard Worker sprintf(col1, "%6d .. %-6d", lowerbound, upperbound);
515*33b1fccfSAndroid Build Coastguard Worker col2 = file_counts[i];
516*33b1fccfSAndroid Build Coastguard Worker if (stats.file_category_stat[EROFS_FT_REG_FILE])
517*33b1fccfSAndroid Build Coastguard Worker col3 = (double)(100 * col2) /
518*33b1fccfSAndroid Build Coastguard Worker stats.file_category_stat[EROFS_FT_REG_FILE];
519*33b1fccfSAndroid Build Coastguard Worker else
520*33b1fccfSAndroid Build Coastguard Worker col3 = 0.0;
521*33b1fccfSAndroid Build Coastguard Worker memset(col4, '#', col3 / 2);
522*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, chart_format, col1, col2, col3, col4);
523*33b1fccfSAndroid Build Coastguard Worker lowerbound = upperbound;
524*33b1fccfSAndroid Build Coastguard Worker upperbound <<= 1;
525*33b1fccfSAndroid Build Coastguard Worker }
526*33b1fccfSAndroid Build Coastguard Worker }
527*33b1fccfSAndroid Build Coastguard Worker
erofsdump_filetype_distribution(char ** file_types,unsigned int len)528*33b1fccfSAndroid Build Coastguard Worker static void erofsdump_filetype_distribution(char **file_types, unsigned int len)
529*33b1fccfSAndroid Build Coastguard Worker {
530*33b1fccfSAndroid Build Coastguard Worker char col1[30];
531*33b1fccfSAndroid Build Coastguard Worker unsigned int col2, i;
532*33b1fccfSAndroid Build Coastguard Worker double col3;
533*33b1fccfSAndroid Build Coastguard Worker char col4[401];
534*33b1fccfSAndroid Build Coastguard Worker
535*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "\nFile type distribution:\n");
536*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, header_format, "type", "count", "ratio",
537*33b1fccfSAndroid Build Coastguard Worker "distribution");
538*33b1fccfSAndroid Build Coastguard Worker for (i = 0; i < len; i++) {
539*33b1fccfSAndroid Build Coastguard Worker memset(col1, 0, sizeof(col1));
540*33b1fccfSAndroid Build Coastguard Worker memset(col4, 0, sizeof(col4));
541*33b1fccfSAndroid Build Coastguard Worker sprintf(col1, "%-17s", file_types[i]);
542*33b1fccfSAndroid Build Coastguard Worker col2 = stats.file_type_stat[i];
543*33b1fccfSAndroid Build Coastguard Worker if (stats.file_category_stat[EROFS_FT_REG_FILE])
544*33b1fccfSAndroid Build Coastguard Worker col3 = (double)(100 * col2) /
545*33b1fccfSAndroid Build Coastguard Worker stats.file_category_stat[EROFS_FT_REG_FILE];
546*33b1fccfSAndroid Build Coastguard Worker else
547*33b1fccfSAndroid Build Coastguard Worker col3 = 0.0;
548*33b1fccfSAndroid Build Coastguard Worker memset(col4, '#', col3 / 2);
549*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, chart_format, col1, col2, col3, col4);
550*33b1fccfSAndroid Build Coastguard Worker }
551*33b1fccfSAndroid Build Coastguard Worker }
552*33b1fccfSAndroid Build Coastguard Worker
erofsdump_file_statistic(void)553*33b1fccfSAndroid Build Coastguard Worker static void erofsdump_file_statistic(void)
554*33b1fccfSAndroid Build Coastguard Worker {
555*33b1fccfSAndroid Build Coastguard Worker unsigned int i;
556*33b1fccfSAndroid Build Coastguard Worker
557*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Filesystem total file count: %lu\n",
558*33b1fccfSAndroid Build Coastguard Worker stats.files);
559*33b1fccfSAndroid Build Coastguard Worker for (i = 0; i < EROFS_FT_MAX; i++)
560*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Filesystem %s count: %lu\n",
561*33b1fccfSAndroid Build Coastguard Worker file_category_types[i], stats.file_category_stat[i]);
562*33b1fccfSAndroid Build Coastguard Worker
563*33b1fccfSAndroid Build Coastguard Worker stats.compress_rate = (double)(100 * stats.files_total_size) /
564*33b1fccfSAndroid Build Coastguard Worker (double)(stats.files_total_origin_size);
565*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Filesystem compressed files: %lu\n",
566*33b1fccfSAndroid Build Coastguard Worker stats.compressed_files);
567*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Filesystem uncompressed files: %lu\n",
568*33b1fccfSAndroid Build Coastguard Worker stats.uncompressed_files);
569*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Filesystem total original file size: %lu Bytes\n",
570*33b1fccfSAndroid Build Coastguard Worker stats.files_total_origin_size);
571*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Filesystem total file size: %lu Bytes\n",
572*33b1fccfSAndroid Build Coastguard Worker stats.files_total_size);
573*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Filesystem compress rate: %.2f%%\n",
574*33b1fccfSAndroid Build Coastguard Worker stats.compress_rate);
575*33b1fccfSAndroid Build Coastguard Worker }
576*33b1fccfSAndroid Build Coastguard Worker
erofsdump_print_statistic(void)577*33b1fccfSAndroid Build Coastguard Worker static void erofsdump_print_statistic(void)
578*33b1fccfSAndroid Build Coastguard Worker {
579*33b1fccfSAndroid Build Coastguard Worker int err;
580*33b1fccfSAndroid Build Coastguard Worker struct erofs_dir_context ctx = {
581*33b1fccfSAndroid Build Coastguard Worker .flags = 0,
582*33b1fccfSAndroid Build Coastguard Worker .pnid = 0,
583*33b1fccfSAndroid Build Coastguard Worker .dir = NULL,
584*33b1fccfSAndroid Build Coastguard Worker .cb = erofsdump_dirent_iter,
585*33b1fccfSAndroid Build Coastguard Worker .de_nid = g_sbi.root_nid,
586*33b1fccfSAndroid Build Coastguard Worker .dname = "",
587*33b1fccfSAndroid Build Coastguard Worker .de_namelen = 0,
588*33b1fccfSAndroid Build Coastguard Worker };
589*33b1fccfSAndroid Build Coastguard Worker
590*33b1fccfSAndroid Build Coastguard Worker err = erofsdump_readdir(&ctx);
591*33b1fccfSAndroid Build Coastguard Worker if (err) {
592*33b1fccfSAndroid Build Coastguard Worker erofs_err("read dir failed");
593*33b1fccfSAndroid Build Coastguard Worker return;
594*33b1fccfSAndroid Build Coastguard Worker }
595*33b1fccfSAndroid Build Coastguard Worker err = erofsdump_read_packed_inode();
596*33b1fccfSAndroid Build Coastguard Worker if (err) {
597*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to read packed inode");
598*33b1fccfSAndroid Build Coastguard Worker return;
599*33b1fccfSAndroid Build Coastguard Worker }
600*33b1fccfSAndroid Build Coastguard Worker erofsdump_file_statistic();
601*33b1fccfSAndroid Build Coastguard Worker erofsdump_filesize_distribution("Original",
602*33b1fccfSAndroid Build Coastguard Worker stats.file_original_size,
603*33b1fccfSAndroid Build Coastguard Worker ARRAY_SIZE(stats.file_original_size));
604*33b1fccfSAndroid Build Coastguard Worker erofsdump_filesize_distribution("On-disk",
605*33b1fccfSAndroid Build Coastguard Worker stats.file_comp_size,
606*33b1fccfSAndroid Build Coastguard Worker ARRAY_SIZE(stats.file_comp_size));
607*33b1fccfSAndroid Build Coastguard Worker erofsdump_filetype_distribution(file_types, OTHERFILETYPE);
608*33b1fccfSAndroid Build Coastguard Worker }
609*33b1fccfSAndroid Build Coastguard Worker
erofsdump_print_supported_compressors(FILE * f,unsigned int mask)610*33b1fccfSAndroid Build Coastguard Worker static void erofsdump_print_supported_compressors(FILE *f, unsigned int mask)
611*33b1fccfSAndroid Build Coastguard Worker {
612*33b1fccfSAndroid Build Coastguard Worker unsigned int i = 0;
613*33b1fccfSAndroid Build Coastguard Worker bool comma = false;
614*33b1fccfSAndroid Build Coastguard Worker const char *s;
615*33b1fccfSAndroid Build Coastguard Worker
616*33b1fccfSAndroid Build Coastguard Worker while ((s = z_erofs_list_supported_algorithms(i++, &mask)) != NULL) {
617*33b1fccfSAndroid Build Coastguard Worker if (*s == '\0')
618*33b1fccfSAndroid Build Coastguard Worker continue;
619*33b1fccfSAndroid Build Coastguard Worker if (comma)
620*33b1fccfSAndroid Build Coastguard Worker fputs(", ", f);
621*33b1fccfSAndroid Build Coastguard Worker fputs(s, f);
622*33b1fccfSAndroid Build Coastguard Worker comma = true;
623*33b1fccfSAndroid Build Coastguard Worker }
624*33b1fccfSAndroid Build Coastguard Worker fputc('\n', f);
625*33b1fccfSAndroid Build Coastguard Worker }
626*33b1fccfSAndroid Build Coastguard Worker
erofsdump_show_superblock(void)627*33b1fccfSAndroid Build Coastguard Worker static void erofsdump_show_superblock(void)
628*33b1fccfSAndroid Build Coastguard Worker {
629*33b1fccfSAndroid Build Coastguard Worker time_t time = g_sbi.build_time;
630*33b1fccfSAndroid Build Coastguard Worker char uuid_str[37];
631*33b1fccfSAndroid Build Coastguard Worker int i = 0;
632*33b1fccfSAndroid Build Coastguard Worker
633*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Filesystem magic number: 0x%04X\n",
634*33b1fccfSAndroid Build Coastguard Worker EROFS_SUPER_MAGIC_V1);
635*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Filesystem blocksize: %u\n",
636*33b1fccfSAndroid Build Coastguard Worker erofs_blksiz(&g_sbi));
637*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Filesystem blocks: %llu\n",
638*33b1fccfSAndroid Build Coastguard Worker g_sbi.total_blocks | 0ULL);
639*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Filesystem inode metadata start block: %u\n",
640*33b1fccfSAndroid Build Coastguard Worker g_sbi.meta_blkaddr);
641*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Filesystem shared xattr metadata start block: %u\n",
642*33b1fccfSAndroid Build Coastguard Worker g_sbi.xattr_blkaddr);
643*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Filesystem root nid: %llu\n",
644*33b1fccfSAndroid Build Coastguard Worker g_sbi.root_nid | 0ULL);
645*33b1fccfSAndroid Build Coastguard Worker if (erofs_sb_has_fragments(&g_sbi) && g_sbi.packed_nid > 0)
646*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Filesystem packed nid: %llu\n",
647*33b1fccfSAndroid Build Coastguard Worker g_sbi.packed_nid | 0ULL);
648*33b1fccfSAndroid Build Coastguard Worker if (erofs_sb_has_compr_cfgs(&g_sbi)) {
649*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Filesystem compr_algs: ");
650*33b1fccfSAndroid Build Coastguard Worker erofsdump_print_supported_compressors(stdout,
651*33b1fccfSAndroid Build Coastguard Worker g_sbi.available_compr_algs);
652*33b1fccfSAndroid Build Coastguard Worker } else {
653*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Filesystem lz4_max_distance: %u\n",
654*33b1fccfSAndroid Build Coastguard Worker g_sbi.lz4.max_distance | 0U);
655*33b1fccfSAndroid Build Coastguard Worker }
656*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Filesystem sb_size: %u\n",
657*33b1fccfSAndroid Build Coastguard Worker g_sbi.sb_size | 0U);
658*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Filesystem inode count: %llu\n",
659*33b1fccfSAndroid Build Coastguard Worker g_sbi.inos | 0ULL);
660*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Filesystem created: %s",
661*33b1fccfSAndroid Build Coastguard Worker ctime(&time));
662*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "Filesystem features: ");
663*33b1fccfSAndroid Build Coastguard Worker for (; i < ARRAY_SIZE(feature_lists); i++) {
664*33b1fccfSAndroid Build Coastguard Worker u32 feat = le32_to_cpu(feature_lists[i].compat ?
665*33b1fccfSAndroid Build Coastguard Worker g_sbi.feature_compat :
666*33b1fccfSAndroid Build Coastguard Worker g_sbi.feature_incompat);
667*33b1fccfSAndroid Build Coastguard Worker if (feat & feature_lists[i].flag)
668*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "%s ", feature_lists[i].name);
669*33b1fccfSAndroid Build Coastguard Worker }
670*33b1fccfSAndroid Build Coastguard Worker erofs_uuid_unparse_lower(g_sbi.uuid, uuid_str);
671*33b1fccfSAndroid Build Coastguard Worker fprintf(stdout, "\nFilesystem UUID: %s\n",
672*33b1fccfSAndroid Build Coastguard Worker uuid_str);
673*33b1fccfSAndroid Build Coastguard Worker }
674*33b1fccfSAndroid Build Coastguard Worker
main(int argc,char ** argv)675*33b1fccfSAndroid Build Coastguard Worker int main(int argc, char **argv)
676*33b1fccfSAndroid Build Coastguard Worker {
677*33b1fccfSAndroid Build Coastguard Worker int err;
678*33b1fccfSAndroid Build Coastguard Worker
679*33b1fccfSAndroid Build Coastguard Worker erofs_init_configure();
680*33b1fccfSAndroid Build Coastguard Worker err = erofsdump_parse_options_cfg(argc, argv);
681*33b1fccfSAndroid Build Coastguard Worker if (err) {
682*33b1fccfSAndroid Build Coastguard Worker if (err == -EINVAL)
683*33b1fccfSAndroid Build Coastguard Worker fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]);
684*33b1fccfSAndroid Build Coastguard Worker goto exit;
685*33b1fccfSAndroid Build Coastguard Worker }
686*33b1fccfSAndroid Build Coastguard Worker
687*33b1fccfSAndroid Build Coastguard Worker err = erofs_dev_open(&g_sbi, cfg.c_img_path, O_RDONLY | O_TRUNC);
688*33b1fccfSAndroid Build Coastguard Worker if (err) {
689*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to open image file");
690*33b1fccfSAndroid Build Coastguard Worker goto exit;
691*33b1fccfSAndroid Build Coastguard Worker }
692*33b1fccfSAndroid Build Coastguard Worker
693*33b1fccfSAndroid Build Coastguard Worker err = erofs_read_superblock(&g_sbi);
694*33b1fccfSAndroid Build Coastguard Worker if (err) {
695*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to read superblock");
696*33b1fccfSAndroid Build Coastguard Worker goto exit_dev_close;
697*33b1fccfSAndroid Build Coastguard Worker }
698*33b1fccfSAndroid Build Coastguard Worker
699*33b1fccfSAndroid Build Coastguard Worker if (!dumpcfg.totalshow) {
700*33b1fccfSAndroid Build Coastguard Worker dumpcfg.show_superblock = true;
701*33b1fccfSAndroid Build Coastguard Worker dumpcfg.totalshow = 1;
702*33b1fccfSAndroid Build Coastguard Worker }
703*33b1fccfSAndroid Build Coastguard Worker if (dumpcfg.show_superblock)
704*33b1fccfSAndroid Build Coastguard Worker erofsdump_show_superblock();
705*33b1fccfSAndroid Build Coastguard Worker
706*33b1fccfSAndroid Build Coastguard Worker if (dumpcfg.show_statistics)
707*33b1fccfSAndroid Build Coastguard Worker erofsdump_print_statistic();
708*33b1fccfSAndroid Build Coastguard Worker
709*33b1fccfSAndroid Build Coastguard Worker if (dumpcfg.show_extent && !dumpcfg.show_inode) {
710*33b1fccfSAndroid Build Coastguard Worker fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]);
711*33b1fccfSAndroid Build Coastguard Worker goto exit_put_super;
712*33b1fccfSAndroid Build Coastguard Worker }
713*33b1fccfSAndroid Build Coastguard Worker
714*33b1fccfSAndroid Build Coastguard Worker if (dumpcfg.show_inode)
715*33b1fccfSAndroid Build Coastguard Worker erofsdump_show_fileinfo(dumpcfg.show_extent);
716*33b1fccfSAndroid Build Coastguard Worker
717*33b1fccfSAndroid Build Coastguard Worker exit_put_super:
718*33b1fccfSAndroid Build Coastguard Worker erofs_put_super(&g_sbi);
719*33b1fccfSAndroid Build Coastguard Worker exit_dev_close:
720*33b1fccfSAndroid Build Coastguard Worker erofs_dev_close(&g_sbi);
721*33b1fccfSAndroid Build Coastguard Worker exit:
722*33b1fccfSAndroid Build Coastguard Worker erofs_blob_closeall(&g_sbi);
723*33b1fccfSAndroid Build Coastguard Worker erofs_exit_configure();
724*33b1fccfSAndroid Build Coastguard Worker return err;
725*33b1fccfSAndroid Build Coastguard Worker }
726