xref: /aosp_15_r20/system/incremental_delivery/incfs/incfsdump/dump.cpp (revision 9190c2a8bd3622b7aa9bd7bfe4b3aec77820f478)
1*9190c2a8SAndroid Build Coastguard Worker /*
2*9190c2a8SAndroid Build Coastguard Worker  * Copyright (C) 2020 The Android Open Source Project
3*9190c2a8SAndroid Build Coastguard Worker  *
4*9190c2a8SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*9190c2a8SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*9190c2a8SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*9190c2a8SAndroid Build Coastguard Worker  *
8*9190c2a8SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*9190c2a8SAndroid Build Coastguard Worker  *
10*9190c2a8SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*9190c2a8SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*9190c2a8SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*9190c2a8SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*9190c2a8SAndroid Build Coastguard Worker  * limitations under the License.
15*9190c2a8SAndroid Build Coastguard Worker  */
16*9190c2a8SAndroid Build Coastguard Worker #include "dump.h"
17*9190c2a8SAndroid Build Coastguard Worker 
18*9190c2a8SAndroid Build Coastguard Worker #include <android-base/file.h>
19*9190c2a8SAndroid Build Coastguard Worker #include <android-base/logging.h>
20*9190c2a8SAndroid Build Coastguard Worker #include <android-base/parsebool.h>
21*9190c2a8SAndroid Build Coastguard Worker #include <android-base/properties.h>
22*9190c2a8SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
23*9190c2a8SAndroid Build Coastguard Worker #include <android-base/strings.h>
24*9190c2a8SAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
25*9190c2a8SAndroid Build Coastguard Worker #include <dirent.h>
26*9190c2a8SAndroid Build Coastguard Worker #include <errno.h>
27*9190c2a8SAndroid Build Coastguard Worker #include <libgen.h>
28*9190c2a8SAndroid Build Coastguard Worker #include <openssl/sha.h>
29*9190c2a8SAndroid Build Coastguard Worker #include <selinux/android.h>
30*9190c2a8SAndroid Build Coastguard Worker #include <selinux/selinux.h>
31*9190c2a8SAndroid Build Coastguard Worker #include <sys/mount.h>
32*9190c2a8SAndroid Build Coastguard Worker #include <sys/poll.h>
33*9190c2a8SAndroid Build Coastguard Worker #include <sys/stat.h>
34*9190c2a8SAndroid Build Coastguard Worker #include <sys/syscall.h>
35*9190c2a8SAndroid Build Coastguard Worker #include <sys/types.h>
36*9190c2a8SAndroid Build Coastguard Worker #include <sys/vfs.h>
37*9190c2a8SAndroid Build Coastguard Worker #include <sys/xattr.h>
38*9190c2a8SAndroid Build Coastguard Worker #include <unistd.h>
39*9190c2a8SAndroid Build Coastguard Worker 
40*9190c2a8SAndroid Build Coastguard Worker #include <chrono>
41*9190c2a8SAndroid Build Coastguard Worker #include <fstream>
42*9190c2a8SAndroid Build Coastguard Worker #include <iomanip>
43*9190c2a8SAndroid Build Coastguard Worker #include <iostream>
44*9190c2a8SAndroid Build Coastguard Worker #include <iterator>
45*9190c2a8SAndroid Build Coastguard Worker #include <optional>
46*9190c2a8SAndroid Build Coastguard Worker #include <sstream>
47*9190c2a8SAndroid Build Coastguard Worker #include <string_view>
48*9190c2a8SAndroid Build Coastguard Worker 
49*9190c2a8SAndroid Build Coastguard Worker #include "linux/incrementalfs.h"
50*9190c2a8SAndroid Build Coastguard Worker 
51*9190c2a8SAndroid Build Coastguard Worker using namespace std::literals;
52*9190c2a8SAndroid Build Coastguard Worker 
53*9190c2a8SAndroid Build Coastguard Worker namespace {
54*9190c2a8SAndroid Build Coastguard Worker 
55*9190c2a8SAndroid Build Coastguard Worker // stuff from the internal incfs implementation
56*9190c2a8SAndroid Build Coastguard Worker 
57*9190c2a8SAndroid Build Coastguard Worker #ifndef __packed
58*9190c2a8SAndroid Build Coastguard Worker #define __packed __attribute__((packed))
59*9190c2a8SAndroid Build Coastguard Worker #endif
60*9190c2a8SAndroid Build Coastguard Worker 
61*9190c2a8SAndroid Build Coastguard Worker struct mem_range {
62*9190c2a8SAndroid Build Coastguard Worker     char* data;
63*9190c2a8SAndroid Build Coastguard Worker     size_t len;
64*9190c2a8SAndroid Build Coastguard Worker };
65*9190c2a8SAndroid Build Coastguard Worker 
66*9190c2a8SAndroid Build Coastguard Worker #define INCFS_MAX_NAME_LEN 255
67*9190c2a8SAndroid Build Coastguard Worker #define INCFS_FORMAT_V1 1
68*9190c2a8SAndroid Build Coastguard Worker #define INCFS_FORMAT_CURRENT_VER INCFS_FORMAT_V1
69*9190c2a8SAndroid Build Coastguard Worker 
70*9190c2a8SAndroid Build Coastguard Worker enum incfs_metadata_type {
71*9190c2a8SAndroid Build Coastguard Worker     INCFS_MD_NONE = 0,
72*9190c2a8SAndroid Build Coastguard Worker     INCFS_MD_BLOCK_MAP = 1,
73*9190c2a8SAndroid Build Coastguard Worker     INCFS_MD_FILE_ATTR = 2,
74*9190c2a8SAndroid Build Coastguard Worker     INCFS_MD_SIGNATURE = 3,
75*9190c2a8SAndroid Build Coastguard Worker     INCFS_MD_STATUS = 4,
76*9190c2a8SAndroid Build Coastguard Worker     INCFS_MD_VERITY_SIGNATURE = 5,
77*9190c2a8SAndroid Build Coastguard Worker };
78*9190c2a8SAndroid Build Coastguard Worker 
79*9190c2a8SAndroid Build Coastguard Worker enum incfs_file_header_flags {
80*9190c2a8SAndroid Build Coastguard Worker     INCFS_FILE_MAPPED = 1 << 1,
81*9190c2a8SAndroid Build Coastguard Worker };
82*9190c2a8SAndroid Build Coastguard Worker 
83*9190c2a8SAndroid Build Coastguard Worker /* Header included at the beginning of all metadata records on the disk. */
84*9190c2a8SAndroid Build Coastguard Worker struct incfs_md_header {
85*9190c2a8SAndroid Build Coastguard Worker     uint8_t h_md_entry_type;
86*9190c2a8SAndroid Build Coastguard Worker 
87*9190c2a8SAndroid Build Coastguard Worker     /*
88*9190c2a8SAndroid Build Coastguard Worker      * Size of the metadata record.
89*9190c2a8SAndroid Build Coastguard Worker      * (e.g. inode, dir entry etc) not just this struct.
90*9190c2a8SAndroid Build Coastguard Worker      */
91*9190c2a8SAndroid Build Coastguard Worker     int16_t h_record_size;
92*9190c2a8SAndroid Build Coastguard Worker 
93*9190c2a8SAndroid Build Coastguard Worker     /*
94*9190c2a8SAndroid Build Coastguard Worker      * CRC32 of the metadata record.
95*9190c2a8SAndroid Build Coastguard Worker      * (e.g. inode, dir entry etc) not just this struct.
96*9190c2a8SAndroid Build Coastguard Worker      */
97*9190c2a8SAndroid Build Coastguard Worker     int32_t h_unused1;
98*9190c2a8SAndroid Build Coastguard Worker 
99*9190c2a8SAndroid Build Coastguard Worker     /* Offset of the next metadata entry if any */
100*9190c2a8SAndroid Build Coastguard Worker     int64_t h_next_md_offset;
101*9190c2a8SAndroid Build Coastguard Worker 
102*9190c2a8SAndroid Build Coastguard Worker     /* Offset of the previous metadata entry if any */
103*9190c2a8SAndroid Build Coastguard Worker     int64_t h_unused2;
104*9190c2a8SAndroid Build Coastguard Worker 
105*9190c2a8SAndroid Build Coastguard Worker } __packed;
106*9190c2a8SAndroid Build Coastguard Worker 
107*9190c2a8SAndroid Build Coastguard Worker /* Backing file header */
108*9190c2a8SAndroid Build Coastguard Worker struct incfs_file_header {
109*9190c2a8SAndroid Build Coastguard Worker     /* Magic number: INCFS_MAGIC_NUMBER */
110*9190c2a8SAndroid Build Coastguard Worker     __le64 fh_magic;
111*9190c2a8SAndroid Build Coastguard Worker 
112*9190c2a8SAndroid Build Coastguard Worker     /* Format version: INCFS_FORMAT_CURRENT_VER */
113*9190c2a8SAndroid Build Coastguard Worker     __le64 fh_version;
114*9190c2a8SAndroid Build Coastguard Worker 
115*9190c2a8SAndroid Build Coastguard Worker     /* sizeof(incfs_file_header) */
116*9190c2a8SAndroid Build Coastguard Worker     __le16 fh_header_size;
117*9190c2a8SAndroid Build Coastguard Worker 
118*9190c2a8SAndroid Build Coastguard Worker     /* INCFS_DATA_FILE_BLOCK_SIZE */
119*9190c2a8SAndroid Build Coastguard Worker     __le16 fh_data_block_size;
120*9190c2a8SAndroid Build Coastguard Worker 
121*9190c2a8SAndroid Build Coastguard Worker     /* File flags, from incfs_file_header_flags */
122*9190c2a8SAndroid Build Coastguard Worker     __le32 fh_flags;
123*9190c2a8SAndroid Build Coastguard Worker 
124*9190c2a8SAndroid Build Coastguard Worker     union {
125*9190c2a8SAndroid Build Coastguard Worker         /* Standard incfs file */
126*9190c2a8SAndroid Build Coastguard Worker         struct {
127*9190c2a8SAndroid Build Coastguard Worker             /* Offset of the first metadata record */
128*9190c2a8SAndroid Build Coastguard Worker             __le64 fh_first_md_offset;
129*9190c2a8SAndroid Build Coastguard Worker 
130*9190c2a8SAndroid Build Coastguard Worker             /* Full size of the file's content */
131*9190c2a8SAndroid Build Coastguard Worker             __le64 fh_file_size;
132*9190c2a8SAndroid Build Coastguard Worker 
133*9190c2a8SAndroid Build Coastguard Worker             /* File uuid */
134*9190c2a8SAndroid Build Coastguard Worker             incfs_uuid_t fh_uuid;
135*9190c2a8SAndroid Build Coastguard Worker         };
136*9190c2a8SAndroid Build Coastguard Worker 
137*9190c2a8SAndroid Build Coastguard Worker         /* Mapped file - INCFS_FILE_MAPPED set in fh_flags */
138*9190c2a8SAndroid Build Coastguard Worker         struct {
139*9190c2a8SAndroid Build Coastguard Worker             /* Offset in original file */
140*9190c2a8SAndroid Build Coastguard Worker             __le64 fh_original_offset;
141*9190c2a8SAndroid Build Coastguard Worker 
142*9190c2a8SAndroid Build Coastguard Worker             /* Full size of the file's content */
143*9190c2a8SAndroid Build Coastguard Worker             __le64 fh_mapped_file_size;
144*9190c2a8SAndroid Build Coastguard Worker 
145*9190c2a8SAndroid Build Coastguard Worker             /* Original file's uuid */
146*9190c2a8SAndroid Build Coastguard Worker             incfs_uuid_t fh_original_uuid;
147*9190c2a8SAndroid Build Coastguard Worker         };
148*9190c2a8SAndroid Build Coastguard Worker     };
149*9190c2a8SAndroid Build Coastguard Worker } __packed;
150*9190c2a8SAndroid Build Coastguard Worker 
151*9190c2a8SAndroid Build Coastguard Worker enum incfs_block_map_entry_flags {
152*9190c2a8SAndroid Build Coastguard Worker     INCFS_BLOCK_COMPRESSED_LZ4 = 1,
153*9190c2a8SAndroid Build Coastguard Worker     INCFS_BLOCK_COMPRESSED_ZSTD = 2,
154*9190c2a8SAndroid Build Coastguard Worker 
155*9190c2a8SAndroid Build Coastguard Worker     /* Reserve 3 bits for compression alg */
156*9190c2a8SAndroid Build Coastguard Worker     INCFS_BLOCK_COMPRESSED_MASK = 7,
157*9190c2a8SAndroid Build Coastguard Worker };
158*9190c2a8SAndroid Build Coastguard Worker 
159*9190c2a8SAndroid Build Coastguard Worker /* Block map entry pointing to an actual location of the data block. */
160*9190c2a8SAndroid Build Coastguard Worker struct incfs_blockmap_entry {
161*9190c2a8SAndroid Build Coastguard Worker     /* Offset of the actual data block. Lower 32 bits */
162*9190c2a8SAndroid Build Coastguard Worker     int32_t me_data_offset_lo;
163*9190c2a8SAndroid Build Coastguard Worker 
164*9190c2a8SAndroid Build Coastguard Worker     /* Offset of the actual data block. Higher 16 bits */
165*9190c2a8SAndroid Build Coastguard Worker     int16_t me_data_offset_hi;
166*9190c2a8SAndroid Build Coastguard Worker 
167*9190c2a8SAndroid Build Coastguard Worker     /* How many bytes the data actually occupies in the backing file */
168*9190c2a8SAndroid Build Coastguard Worker     int16_t me_data_size;
169*9190c2a8SAndroid Build Coastguard Worker 
170*9190c2a8SAndroid Build Coastguard Worker     /* Block flags from incfs_block_map_entry_flags */
171*9190c2a8SAndroid Build Coastguard Worker     int16_t me_flags;
172*9190c2a8SAndroid Build Coastguard Worker } __packed;
173*9190c2a8SAndroid Build Coastguard Worker 
174*9190c2a8SAndroid Build Coastguard Worker /* Metadata record for locations of file blocks. Type = INCFS_MD_BLOCK_MAP */
175*9190c2a8SAndroid Build Coastguard Worker struct incfs_blockmap {
176*9190c2a8SAndroid Build Coastguard Worker     struct incfs_md_header m_header;
177*9190c2a8SAndroid Build Coastguard Worker 
178*9190c2a8SAndroid Build Coastguard Worker     /* Base offset of the array of incfs_blockmap_entry */
179*9190c2a8SAndroid Build Coastguard Worker     int64_t m_base_offset;
180*9190c2a8SAndroid Build Coastguard Worker 
181*9190c2a8SAndroid Build Coastguard Worker     /* Size of the map entry array in blocks */
182*9190c2a8SAndroid Build Coastguard Worker     int32_t m_block_count;
183*9190c2a8SAndroid Build Coastguard Worker } __packed;
184*9190c2a8SAndroid Build Coastguard Worker 
185*9190c2a8SAndroid Build Coastguard Worker /* Metadata record for file signature. Type = INCFS_MD_SIGNATURE */
186*9190c2a8SAndroid Build Coastguard Worker struct incfs_file_signature {
187*9190c2a8SAndroid Build Coastguard Worker     struct incfs_md_header sg_header;
188*9190c2a8SAndroid Build Coastguard Worker 
189*9190c2a8SAndroid Build Coastguard Worker     int32_t sg_sig_size; /* The size of the signature. */
190*9190c2a8SAndroid Build Coastguard Worker 
191*9190c2a8SAndroid Build Coastguard Worker     int64_t sg_sig_offset; /* Signature's offset in the backing file */
192*9190c2a8SAndroid Build Coastguard Worker 
193*9190c2a8SAndroid Build Coastguard Worker     int32_t sg_hash_tree_size; /* The size of the hash tree. */
194*9190c2a8SAndroid Build Coastguard Worker 
195*9190c2a8SAndroid Build Coastguard Worker     int64_t sg_hash_tree_offset; /* Hash tree offset in the backing file */
196*9190c2a8SAndroid Build Coastguard Worker } __packed;
197*9190c2a8SAndroid Build Coastguard Worker 
198*9190c2a8SAndroid Build Coastguard Worker struct incfs_status {
199*9190c2a8SAndroid Build Coastguard Worker     struct incfs_md_header is_header;
200*9190c2a8SAndroid Build Coastguard Worker 
201*9190c2a8SAndroid Build Coastguard Worker     __le32 is_data_blocks_written; /* Number of data blocks written */
202*9190c2a8SAndroid Build Coastguard Worker 
203*9190c2a8SAndroid Build Coastguard Worker     __le32 is_hash_blocks_written; /* Number of hash blocks written */
204*9190c2a8SAndroid Build Coastguard Worker 
205*9190c2a8SAndroid Build Coastguard Worker     __le32 is_dummy[6]; /* Spare fields */
206*9190c2a8SAndroid Build Coastguard Worker } __packed;
207*9190c2a8SAndroid Build Coastguard Worker 
208*9190c2a8SAndroid Build Coastguard Worker /*
209*9190c2a8SAndroid Build Coastguard Worker  * Metadata record for verity signature. Type = INCFS_MD_VERITY_SIGNATURE
210*9190c2a8SAndroid Build Coastguard Worker  *
211*9190c2a8SAndroid Build Coastguard Worker  * This record will only exist for verity-enabled files with signatures. Verity
212*9190c2a8SAndroid Build Coastguard Worker  * enabled files without signatures do not have this record. This signature is
213*9190c2a8SAndroid Build Coastguard Worker  * checked by fs-verity identically to any other fs-verity signature.
214*9190c2a8SAndroid Build Coastguard Worker  */
215*9190c2a8SAndroid Build Coastguard Worker struct incfs_file_verity_signature {
216*9190c2a8SAndroid Build Coastguard Worker     struct incfs_md_header vs_header;
217*9190c2a8SAndroid Build Coastguard Worker 
218*9190c2a8SAndroid Build Coastguard Worker     /* The size of the signature */
219*9190c2a8SAndroid Build Coastguard Worker     __le32 vs_size;
220*9190c2a8SAndroid Build Coastguard Worker 
221*9190c2a8SAndroid Build Coastguard Worker     /* Signature's offset in the backing file */
222*9190c2a8SAndroid Build Coastguard Worker     __le64 vs_offset;
223*9190c2a8SAndroid Build Coastguard Worker } __packed;
224*9190c2a8SAndroid Build Coastguard Worker 
225*9190c2a8SAndroid Build Coastguard Worker typedef union {
226*9190c2a8SAndroid Build Coastguard Worker     struct incfs_md_header md_header;
227*9190c2a8SAndroid Build Coastguard Worker     struct incfs_blockmap blockmap;
228*9190c2a8SAndroid Build Coastguard Worker     struct incfs_file_signature signature;
229*9190c2a8SAndroid Build Coastguard Worker     struct incfs_status status;
230*9190c2a8SAndroid Build Coastguard Worker     struct incfs_file_verity_signature verity_signature;
231*9190c2a8SAndroid Build Coastguard Worker } md_buffer;
232*9190c2a8SAndroid Build Coastguard Worker 
233*9190c2a8SAndroid Build Coastguard Worker #define INCFS_MAX_METADATA_RECORD_SIZE sizeof(md_buffer)
234*9190c2a8SAndroid Build Coastguard Worker 
235*9190c2a8SAndroid Build Coastguard Worker class Dump {
236*9190c2a8SAndroid Build Coastguard Worker public:
Dump(std::string_view backingFile)237*9190c2a8SAndroid Build Coastguard Worker     Dump(std::string_view backingFile)
238*9190c2a8SAndroid Build Coastguard Worker           : mBackingFile(android::base::Basename(backingFile)) {
239*9190c2a8SAndroid Build Coastguard Worker             std::string backingFileStr(backingFile);
240*9190c2a8SAndroid Build Coastguard Worker               mIn.open(backingFileStr);
241*9190c2a8SAndroid Build Coastguard Worker     }
242*9190c2a8SAndroid Build Coastguard Worker 
run()243*9190c2a8SAndroid Build Coastguard Worker     void run() {
244*9190c2a8SAndroid Build Coastguard Worker         if (!mIn) {
245*9190c2a8SAndroid Build Coastguard Worker             err() << "bad input file name " << mBackingFile;
246*9190c2a8SAndroid Build Coastguard Worker             return;
247*9190c2a8SAndroid Build Coastguard Worker         }
248*9190c2a8SAndroid Build Coastguard Worker 
249*9190c2a8SAndroid Build Coastguard Worker         auto header = read<incfs_file_header>();
250*9190c2a8SAndroid Build Coastguard Worker         out() << "header: " << hex(header.fh_magic) << ", " << header.fh_version << ", "
251*9190c2a8SAndroid Build Coastguard Worker               << hex(header.fh_data_block_size) << ", " << header.fh_header_size << ", "
252*9190c2a8SAndroid Build Coastguard Worker               << header.fh_file_size;
253*9190c2a8SAndroid Build Coastguard Worker         if (header.fh_magic != INCFS_MAGIC_NUMBER) {
254*9190c2a8SAndroid Build Coastguard Worker             err() << "bad magic, expected: " << hex(INCFS_MAGIC_NUMBER);
255*9190c2a8SAndroid Build Coastguard Worker         }
256*9190c2a8SAndroid Build Coastguard Worker         if (header.fh_version != INCFS_FORMAT_CURRENT_VER) {
257*9190c2a8SAndroid Build Coastguard Worker             err() << "bad version, expected: " << INCFS_FORMAT_CURRENT_VER;
258*9190c2a8SAndroid Build Coastguard Worker         }
259*9190c2a8SAndroid Build Coastguard Worker         if (header.fh_data_block_size != INCFS_DATA_FILE_BLOCK_SIZE) {
260*9190c2a8SAndroid Build Coastguard Worker             err() << "bad data block size, expected: " << hex(INCFS_DATA_FILE_BLOCK_SIZE);
261*9190c2a8SAndroid Build Coastguard Worker         }
262*9190c2a8SAndroid Build Coastguard Worker         if (header.fh_header_size != sizeof(header)) {
263*9190c2a8SAndroid Build Coastguard Worker             err() << "bad header size, expected: " << sizeof(header);
264*9190c2a8SAndroid Build Coastguard Worker         }
265*9190c2a8SAndroid Build Coastguard Worker         {
266*9190c2a8SAndroid Build Coastguard Worker             auto ostream = out() << "flags: " << hex(header.fh_flags);
267*9190c2a8SAndroid Build Coastguard Worker             if (header.fh_flags & INCFS_FILE_MAPPED) {
268*9190c2a8SAndroid Build Coastguard Worker                 ostream << " (mapped file)";
269*9190c2a8SAndroid Build Coastguard Worker             }
270*9190c2a8SAndroid Build Coastguard Worker         }
271*9190c2a8SAndroid Build Coastguard Worker 
272*9190c2a8SAndroid Build Coastguard Worker         if (header.fh_flags & INCFS_FILE_MAPPED) {
273*9190c2a8SAndroid Build Coastguard Worker             out() << "source " << toString(header.fh_original_uuid);
274*9190c2a8SAndroid Build Coastguard Worker             out() << "size " << header.fh_mapped_file_size << " @ "
275*9190c2a8SAndroid Build Coastguard Worker                   << hex(header.fh_original_offset);
276*9190c2a8SAndroid Build Coastguard Worker         } else {
277*9190c2a8SAndroid Build Coastguard Worker             out() << "uuid " << toString(header.fh_uuid);
278*9190c2a8SAndroid Build Coastguard Worker             out() << "size " << header.fh_file_size;
279*9190c2a8SAndroid Build Coastguard Worker             out() << "first md offset " << hex(header.fh_first_md_offset);
280*9190c2a8SAndroid Build Coastguard Worker 
281*9190c2a8SAndroid Build Coastguard Worker             int64_t metadataOffset = header.fh_first_md_offset;
282*9190c2a8SAndroid Build Coastguard Worker             if (metadataOffset >= mIn.tellg()) {
283*9190c2a8SAndroid Build Coastguard Worker                 if (metadataOffset > mIn.tellg()) {
284*9190c2a8SAndroid Build Coastguard Worker                     out() << "gap of " << metadataOffset - mIn.tellg()
285*9190c2a8SAndroid Build Coastguard Worker                           << " bytes to the first metadata record";
286*9190c2a8SAndroid Build Coastguard Worker                 }
287*9190c2a8SAndroid Build Coastguard Worker                 incfs_md_header prevMd = {};
288*9190c2a8SAndroid Build Coastguard Worker                 do {
289*9190c2a8SAndroid Build Coastguard Worker                     dumpMd(metadataOffset, prevMd);
290*9190c2a8SAndroid Build Coastguard Worker                 } while (metadataOffset != 0);
291*9190c2a8SAndroid Build Coastguard Worker             }
292*9190c2a8SAndroid Build Coastguard Worker         }
293*9190c2a8SAndroid Build Coastguard Worker         out() << "finished" << (mIn ? "" : " with read errors");
294*9190c2a8SAndroid Build Coastguard Worker     }
295*9190c2a8SAndroid Build Coastguard Worker 
296*9190c2a8SAndroid Build Coastguard Worker private:
scopedNesting()297*9190c2a8SAndroid Build Coastguard Worker     auto scopedNesting() {
298*9190c2a8SAndroid Build Coastguard Worker         ++mNesting;
299*9190c2a8SAndroid Build Coastguard Worker         auto undoNesting = [this](auto) { --mNesting; };
300*9190c2a8SAndroid Build Coastguard Worker         return std::unique_ptr<Dump, decltype(undoNesting)>(this, std::move(undoNesting));
301*9190c2a8SAndroid Build Coastguard Worker     }
302*9190c2a8SAndroid Build Coastguard Worker 
mdType(int type)303*9190c2a8SAndroid Build Coastguard Worker     const char* mdType(int type) {
304*9190c2a8SAndroid Build Coastguard Worker         switch (type) {
305*9190c2a8SAndroid Build Coastguard Worker             case INCFS_MD_NONE:
306*9190c2a8SAndroid Build Coastguard Worker                 return "none";
307*9190c2a8SAndroid Build Coastguard Worker             case INCFS_MD_BLOCK_MAP:
308*9190c2a8SAndroid Build Coastguard Worker                 return "block map";
309*9190c2a8SAndroid Build Coastguard Worker             case INCFS_MD_STATUS:
310*9190c2a8SAndroid Build Coastguard Worker                 return "status";
311*9190c2a8SAndroid Build Coastguard Worker             case INCFS_MD_SIGNATURE:
312*9190c2a8SAndroid Build Coastguard Worker                 return "signature";
313*9190c2a8SAndroid Build Coastguard Worker             case INCFS_MD_VERITY_SIGNATURE:
314*9190c2a8SAndroid Build Coastguard Worker                 return "verity signature";
315*9190c2a8SAndroid Build Coastguard Worker             default:
316*9190c2a8SAndroid Build Coastguard Worker                 return "unknown";
317*9190c2a8SAndroid Build Coastguard Worker         }
318*9190c2a8SAndroid Build Coastguard Worker     }
319*9190c2a8SAndroid Build Coastguard Worker 
blockFlags(int flags)320*9190c2a8SAndroid Build Coastguard Worker     std::string blockFlags(int flags) {
321*9190c2a8SAndroid Build Coastguard Worker         if (!flags) {
322*9190c2a8SAndroid Build Coastguard Worker             return {};
323*9190c2a8SAndroid Build Coastguard Worker         }
324*9190c2a8SAndroid Build Coastguard Worker         std::string res = "(";
325*9190c2a8SAndroid Build Coastguard Worker         auto compression = flags & INCFS_BLOCK_COMPRESSED_MASK;
326*9190c2a8SAndroid Build Coastguard Worker         if (compression == INCFS_BLOCK_COMPRESSED_LZ4) {
327*9190c2a8SAndroid Build Coastguard Worker             res += "|lz4-compressed|";
328*9190c2a8SAndroid Build Coastguard Worker         } else if (flags == INCFS_BLOCK_COMPRESSED_ZSTD) {
329*9190c2a8SAndroid Build Coastguard Worker             res += "|zstd-compressed|";
330*9190c2a8SAndroid Build Coastguard Worker         }
331*9190c2a8SAndroid Build Coastguard Worker         res += ")";
332*9190c2a8SAndroid Build Coastguard Worker         return res;
333*9190c2a8SAndroid Build Coastguard Worker     }
334*9190c2a8SAndroid Build Coastguard Worker 
dumpBlockmap(int64_t offset,int64_t count)335*9190c2a8SAndroid Build Coastguard Worker     void dumpBlockmap(int64_t offset, int64_t count) {
336*9190c2a8SAndroid Build Coastguard Worker         auto nesting = scopedNesting();
337*9190c2a8SAndroid Build Coastguard Worker         mIn.seekg(offset);
338*9190c2a8SAndroid Build Coastguard Worker         for (int64_t i = 0; i != count; ++i) {
339*9190c2a8SAndroid Build Coastguard Worker             auto ostream = out() << i << " @ " << hex(mIn.tellg()) << ": [ ";
340*9190c2a8SAndroid Build Coastguard Worker 
341*9190c2a8SAndroid Build Coastguard Worker             auto block = read<incfs_blockmap_entry>();
342*9190c2a8SAndroid Build Coastguard Worker             auto blockOffset =
343*9190c2a8SAndroid Build Coastguard Worker                     uint64_t(block.me_data_offset_lo) | (uint64_t(block.me_data_offset_hi) << 32);
344*9190c2a8SAndroid Build Coastguard Worker             if (blockOffset) {
345*9190c2a8SAndroid Build Coastguard Worker                 ostream << block.me_data_size << " @ " << hex(blockOffset);
346*9190c2a8SAndroid Build Coastguard Worker             } else {
347*9190c2a8SAndroid Build Coastguard Worker                 ostream << "missing";
348*9190c2a8SAndroid Build Coastguard Worker             }
349*9190c2a8SAndroid Build Coastguard Worker             ostream << " ], flags = " << block.me_flags << blockFlags(block.me_flags);
350*9190c2a8SAndroid Build Coastguard Worker         }
351*9190c2a8SAndroid Build Coastguard Worker     }
352*9190c2a8SAndroid Build Coastguard Worker 
dumpTree(int64_t offset,int64_t size)353*9190c2a8SAndroid Build Coastguard Worker     void dumpTree(int64_t offset, int64_t size) {
354*9190c2a8SAndroid Build Coastguard Worker         auto nesting = scopedNesting();
355*9190c2a8SAndroid Build Coastguard Worker         out() << "tree " << offset << " " << size;
356*9190c2a8SAndroid Build Coastguard Worker     }
357*9190c2a8SAndroid Build Coastguard Worker 
dumpMd(int64_t & offset,incfs_md_header & prevMd)358*9190c2a8SAndroid Build Coastguard Worker     void dumpMd(int64_t& offset, incfs_md_header& prevMd) {
359*9190c2a8SAndroid Build Coastguard Worker         md_buffer mdBuf = {};
360*9190c2a8SAndroid Build Coastguard Worker         auto& md = mdBuf.md_header;
361*9190c2a8SAndroid Build Coastguard Worker         md = readAt<incfs_md_header>(offset);
362*9190c2a8SAndroid Build Coastguard Worker         out() << "metadata: " << mdType(md.h_md_entry_type) << "(" << int(md.h_md_entry_type)
363*9190c2a8SAndroid Build Coastguard Worker               << ")";
364*9190c2a8SAndroid Build Coastguard Worker 
365*9190c2a8SAndroid Build Coastguard Worker         auto nesting = scopedNesting();
366*9190c2a8SAndroid Build Coastguard Worker         out() << "record size: " << md.h_record_size;
367*9190c2a8SAndroid Build Coastguard Worker         out() << "next md offset: " << hex(md.h_next_md_offset);
368*9190c2a8SAndroid Build Coastguard Worker 
369*9190c2a8SAndroid Build Coastguard Worker         {
370*9190c2a8SAndroid Build Coastguard Worker             switch (md.h_md_entry_type) {
371*9190c2a8SAndroid Build Coastguard Worker                 case INCFS_MD_NONE:
372*9190c2a8SAndroid Build Coastguard Worker                     out() << "nothing here";
373*9190c2a8SAndroid Build Coastguard Worker                     break;
374*9190c2a8SAndroid Build Coastguard Worker                 case INCFS_MD_BLOCK_MAP: {
375*9190c2a8SAndroid Build Coastguard Worker                     auto& bm = mdBuf.blockmap;
376*9190c2a8SAndroid Build Coastguard Worker                     bm = readAt<decltype(bm)>(offset);
377*9190c2a8SAndroid Build Coastguard Worker                     out() << "offset:      " << hex(bm.m_base_offset);
378*9190c2a8SAndroid Build Coastguard Worker                     out() << "block count: " << bm.m_block_count;
379*9190c2a8SAndroid Build Coastguard Worker                     dumpBlockmap(bm.m_base_offset, bm.m_block_count);
380*9190c2a8SAndroid Build Coastguard Worker                     break;
381*9190c2a8SAndroid Build Coastguard Worker                 }
382*9190c2a8SAndroid Build Coastguard Worker                 case INCFS_MD_SIGNATURE: {
383*9190c2a8SAndroid Build Coastguard Worker                     auto& sig = mdBuf.signature;
384*9190c2a8SAndroid Build Coastguard Worker                     sig = readAt<decltype(sig)>(offset);
385*9190c2a8SAndroid Build Coastguard Worker                     out() << "signature size:   " << sig.sg_sig_size;
386*9190c2a8SAndroid Build Coastguard Worker                     out() << "signature offset: " << hex(sig.sg_sig_offset);
387*9190c2a8SAndroid Build Coastguard Worker                     out() << "hash tree size:   " << sig.sg_hash_tree_size;
388*9190c2a8SAndroid Build Coastguard Worker                     out() << "hash tree offset: " << hex(sig.sg_hash_tree_offset);
389*9190c2a8SAndroid Build Coastguard Worker                     dumpTree(sig.sg_hash_tree_offset, sig.sg_hash_tree_size);
390*9190c2a8SAndroid Build Coastguard Worker                     break;
391*9190c2a8SAndroid Build Coastguard Worker                 }
392*9190c2a8SAndroid Build Coastguard Worker                 case INCFS_MD_STATUS: {
393*9190c2a8SAndroid Build Coastguard Worker                     auto& st = mdBuf.status;
394*9190c2a8SAndroid Build Coastguard Worker                     st = readAt<decltype(st)>(offset);
395*9190c2a8SAndroid Build Coastguard Worker                     out() << "data blocks written: " << st.is_data_blocks_written;
396*9190c2a8SAndroid Build Coastguard Worker                     out() << "hash blocks written: " << st.is_hash_blocks_written;
397*9190c2a8SAndroid Build Coastguard Worker                     break;
398*9190c2a8SAndroid Build Coastguard Worker                 }
399*9190c2a8SAndroid Build Coastguard Worker                 case INCFS_MD_VERITY_SIGNATURE: {
400*9190c2a8SAndroid Build Coastguard Worker                     auto& vs = mdBuf.verity_signature;
401*9190c2a8SAndroid Build Coastguard Worker                     vs = readAt<decltype(vs)>(offset);
402*9190c2a8SAndroid Build Coastguard Worker                     out() << "verity signature size:   " << vs.vs_size;
403*9190c2a8SAndroid Build Coastguard Worker                     out() << "verity signature offset: " << hex(vs.vs_offset);
404*9190c2a8SAndroid Build Coastguard Worker                     break;
405*9190c2a8SAndroid Build Coastguard Worker                 }
406*9190c2a8SAndroid Build Coastguard Worker                 default:
407*9190c2a8SAndroid Build Coastguard Worker                     out() << "don't know how to handle it";
408*9190c2a8SAndroid Build Coastguard Worker                     break;
409*9190c2a8SAndroid Build Coastguard Worker             }
410*9190c2a8SAndroid Build Coastguard Worker         }
411*9190c2a8SAndroid Build Coastguard Worker 
412*9190c2a8SAndroid Build Coastguard Worker         updateMaxPos();
413*9190c2a8SAndroid Build Coastguard Worker         prevMd = md;
414*9190c2a8SAndroid Build Coastguard Worker         offset = md.h_next_md_offset;
415*9190c2a8SAndroid Build Coastguard Worker     }
416*9190c2a8SAndroid Build Coastguard Worker 
417*9190c2a8SAndroid Build Coastguard Worker     struct OstreamWrapper {
OstreamWrapper__anon5e30740e0111::Dump::OstreamWrapper418*9190c2a8SAndroid Build Coastguard Worker         explicit OstreamWrapper(std::ostream& wrapped) : mWrapped(&wrapped) {}
OstreamWrapper__anon5e30740e0111::Dump::OstreamWrapper419*9190c2a8SAndroid Build Coastguard Worker         OstreamWrapper(OstreamWrapper&& other) noexcept
420*9190c2a8SAndroid Build Coastguard Worker               : mWrapped(std::exchange(other.mWrapped, nullptr)) {}
421*9190c2a8SAndroid Build Coastguard Worker 
~OstreamWrapper__anon5e30740e0111::Dump::OstreamWrapper422*9190c2a8SAndroid Build Coastguard Worker         ~OstreamWrapper() {
423*9190c2a8SAndroid Build Coastguard Worker             if (mWrapped) {
424*9190c2a8SAndroid Build Coastguard Worker                 *mWrapped << '\n';
425*9190c2a8SAndroid Build Coastguard Worker             }
426*9190c2a8SAndroid Build Coastguard Worker         }
427*9190c2a8SAndroid Build Coastguard Worker 
428*9190c2a8SAndroid Build Coastguard Worker         template <class T>
operator <<__anon5e30740e0111::Dump::OstreamWrapper429*9190c2a8SAndroid Build Coastguard Worker         OstreamWrapper& operator<<(const T& t) & {
430*9190c2a8SAndroid Build Coastguard Worker             *mWrapped << t;
431*9190c2a8SAndroid Build Coastguard Worker             return *this;
432*9190c2a8SAndroid Build Coastguard Worker         }
433*9190c2a8SAndroid Build Coastguard Worker         template <class T>
operator <<__anon5e30740e0111::Dump::OstreamWrapper434*9190c2a8SAndroid Build Coastguard Worker         OstreamWrapper&& operator<<(const T& t) && {
435*9190c2a8SAndroid Build Coastguard Worker             *this << t;
436*9190c2a8SAndroid Build Coastguard Worker             return std::move(*this);
437*9190c2a8SAndroid Build Coastguard Worker         }
438*9190c2a8SAndroid Build Coastguard Worker 
439*9190c2a8SAndroid Build Coastguard Worker     private:
440*9190c2a8SAndroid Build Coastguard Worker         std::ostream* mWrapped;
441*9190c2a8SAndroid Build Coastguard Worker     };
442*9190c2a8SAndroid Build Coastguard Worker 
hex(uint64_t t)443*9190c2a8SAndroid Build Coastguard Worker     static std::string hex(uint64_t t) {
444*9190c2a8SAndroid Build Coastguard Worker         char buf[32] = {};
445*9190c2a8SAndroid Build Coastguard Worker         snprintf(buf, std::size(buf) - 1, "0x%llx", (unsigned long long)t);
446*9190c2a8SAndroid Build Coastguard Worker         return buf;
447*9190c2a8SAndroid Build Coastguard Worker     }
448*9190c2a8SAndroid Build Coastguard Worker 
toString(incfs_uuid_t uuid)449*9190c2a8SAndroid Build Coastguard Worker     static std::string toString(incfs_uuid_t uuid) {
450*9190c2a8SAndroid Build Coastguard Worker         std::stringstream res;
451*9190c2a8SAndroid Build Coastguard Worker         res << std::hex;
452*9190c2a8SAndroid Build Coastguard Worker         for (unsigned char b : uuid.bytes) {
453*9190c2a8SAndroid Build Coastguard Worker             res << std::setfill('0') << std::setw(2) << (unsigned int)b;
454*9190c2a8SAndroid Build Coastguard Worker         }
455*9190c2a8SAndroid Build Coastguard Worker         return res.str();
456*9190c2a8SAndroid Build Coastguard Worker     }
457*9190c2a8SAndroid Build Coastguard Worker 
out() const458*9190c2a8SAndroid Build Coastguard Worker     OstreamWrapper out() const {
459*9190c2a8SAndroid Build Coastguard Worker         nesting(std::cout);
460*9190c2a8SAndroid Build Coastguard Worker         std::cout << "[" << mBackingFile << "] ";
461*9190c2a8SAndroid Build Coastguard Worker         return OstreamWrapper(std::cout);
462*9190c2a8SAndroid Build Coastguard Worker     }
463*9190c2a8SAndroid Build Coastguard Worker 
err() const464*9190c2a8SAndroid Build Coastguard Worker     OstreamWrapper err() const {
465*9190c2a8SAndroid Build Coastguard Worker         nesting(std::cerr);
466*9190c2a8SAndroid Build Coastguard Worker         std::cerr << "[" << mBackingFile << "] ";
467*9190c2a8SAndroid Build Coastguard Worker         return OstreamWrapper(std::cerr);
468*9190c2a8SAndroid Build Coastguard Worker     }
469*9190c2a8SAndroid Build Coastguard Worker 
nesting(std::ostream & out) const470*9190c2a8SAndroid Build Coastguard Worker     void nesting(std::ostream& out) const {
471*9190c2a8SAndroid Build Coastguard Worker         for (int i = 0; i < mNesting; ++i) {
472*9190c2a8SAndroid Build Coastguard Worker             out << "   ";
473*9190c2a8SAndroid Build Coastguard Worker         }
474*9190c2a8SAndroid Build Coastguard Worker     }
475*9190c2a8SAndroid Build Coastguard Worker 
476*9190c2a8SAndroid Build Coastguard Worker     template <class T>
read()477*9190c2a8SAndroid Build Coastguard Worker     std::remove_reference_t<T> read() {
478*9190c2a8SAndroid Build Coastguard Worker         std::remove_reference_t<T> res;
479*9190c2a8SAndroid Build Coastguard Worker         mIn.read((char*)&res, sizeof(res));
480*9190c2a8SAndroid Build Coastguard Worker         return res;
481*9190c2a8SAndroid Build Coastguard Worker     }
482*9190c2a8SAndroid Build Coastguard Worker 
483*9190c2a8SAndroid Build Coastguard Worker     template <class T>
readAt(int64_t pos)484*9190c2a8SAndroid Build Coastguard Worker     std::remove_reference_t<T> readAt(int64_t pos) {
485*9190c2a8SAndroid Build Coastguard Worker         mIn.seekg(pos);
486*9190c2a8SAndroid Build Coastguard Worker         return read<T>();
487*9190c2a8SAndroid Build Coastguard Worker     }
488*9190c2a8SAndroid Build Coastguard Worker 
skip(int64_t count)489*9190c2a8SAndroid Build Coastguard Worker     void skip(int64_t count) { mIn.seekg(count, std::ios_base::cur); }
490*9190c2a8SAndroid Build Coastguard Worker 
updateMaxPos()491*9190c2a8SAndroid Build Coastguard Worker     void updateMaxPos() { mMaxDumpedPos = std::max<int64_t>(mMaxDumpedPos, mIn.tellg()); }
492*9190c2a8SAndroid Build Coastguard Worker 
493*9190c2a8SAndroid Build Coastguard Worker     std::string mBackingFile;
494*9190c2a8SAndroid Build Coastguard Worker     std::ifstream mIn;
495*9190c2a8SAndroid Build Coastguard Worker     int mNesting = 0;
496*9190c2a8SAndroid Build Coastguard Worker     int64_t mMaxDumpedPos = 0;
497*9190c2a8SAndroid Build Coastguard Worker };
498*9190c2a8SAndroid Build Coastguard Worker 
499*9190c2a8SAndroid Build Coastguard Worker } // namespace
500*9190c2a8SAndroid Build Coastguard Worker 
501*9190c2a8SAndroid Build Coastguard Worker namespace android::incfs {
502*9190c2a8SAndroid Build Coastguard Worker 
dump(std::string_view backingFile)503*9190c2a8SAndroid Build Coastguard Worker void dump(std::string_view backingFile) {
504*9190c2a8SAndroid Build Coastguard Worker     Dump(backingFile).run();
505*9190c2a8SAndroid Build Coastguard Worker }
506*9190c2a8SAndroid Build Coastguard Worker 
507*9190c2a8SAndroid Build Coastguard Worker } // namespace android::incfs
508