1 // Copyright (C) 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #pragma once
16
17 #include <stdint.h>
18
19 #include <memory>
20 #include <optional>
21 #include <unordered_map>
22 #include <vector>
23
24 #include <android-base/unique_fd.h>
25 #include <libsnapshot/cow_format.h>
26
27 namespace chromeos_update_engine {
28 class FileDescriptor;
29 } // namespace chromeos_update_engine
30
31 namespace android {
32 namespace snapshot {
33
34 class ICowOpIter;
35
36 // Interface for reading from a snapuserd COW.
37 class ICowReader {
38 public:
39 using FileDescriptor = chromeos_update_engine::FileDescriptor;
40
~ICowReader()41 virtual ~ICowReader() {}
42
43 // Return the file header.
44 virtual CowHeader& GetHeader() = 0;
45
46 // Return the file footer.
47 virtual bool GetFooter(CowFooter* footer) = 0;
48 virtual bool VerifyMergeOps() = 0;
49
50 // Return the last valid label
51 virtual bool GetLastLabel(uint64_t* label) = 0;
52
53 // Return an iterator for retrieving CowOperation entries.
54 virtual std::unique_ptr<ICowOpIter> GetOpIter(bool merge_progress) = 0;
55
56 // Return an iterator for retrieving CowOperation entries in reverse merge order
57 virtual std::unique_ptr<ICowOpIter> GetRevMergeOpIter(bool ignore_progress) = 0;
58
59 // Return an iterator for retrieving CowOperation entries in merge order
60 virtual std::unique_ptr<ICowOpIter> GetMergeOpIter(bool ignore_progress) = 0;
61
62 // Get decoded bytes from the data section, handling any decompression.
63 //
64 // If ignore_bytes is non-zero, it specifies the initial number of bytes
65 // to skip writing to |buffer|.
66 //
67 // Returns the number of bytes written to |buffer|, or -1 on failure.
68 // errno is NOT set.
69 //
70 // Partial reads are not possible unless |buffer_size| is less than the
71 // operation block size.
72 //
73 // The operation pointer must derive from ICowOpIter::Get().
74 virtual ssize_t ReadData(const CowOperation* op, void* buffer, size_t buffer_size,
75 size_t ignore_bytes = 0) = 0;
76
77 // Get the absolute source offset, in bytes, of a CowOperation. Returns
78 // false if the operation does not read from source partitions.
79 virtual bool GetSourceOffset(const CowOperation* op, uint64_t* source_offset) = 0;
80 };
81
GetBlockFromOffset(const CowHeader & header,uint64_t offset)82 static constexpr uint64_t GetBlockFromOffset(const CowHeader& header, uint64_t offset) {
83 return offset / header.block_size;
84 }
85
GetBlockRelativeOffset(const CowHeader & header,uint64_t offset)86 static constexpr uint64_t GetBlockRelativeOffset(const CowHeader& header, uint64_t offset) {
87 return offset % header.block_size;
88 }
89
90 // Iterate over a sequence of COW operations. The iterator is bidirectional.
91 class ICowOpIter {
92 public:
~ICowOpIter()93 virtual ~ICowOpIter() {}
94
95 // Returns true if the iterator is at the end of the operation list.
96 // If true, Get() and Next() must not be called.
97 virtual bool AtEnd() = 0;
98
99 // Read the current operation.
100 virtual const CowOperation* Get() = 0;
101
102 // Advance to the next item.
103 virtual void Next() = 0;
104
105 // Returns true if the iterator is at the beginning of the operation list.
106 // If true, Prev() must not be called; Get() however will be valid if
107 // AtEnd() is not true.
108 virtual bool AtBegin() = 0;
109
110 // Advance to the previous item.
111 virtual void Prev() = 0;
112 };
113
114 class CowReader final : public ICowReader {
115 public:
116 enum class ReaderFlags {
117 DEFAULT = 0,
118 USERSPACE_MERGE = 1,
119 };
120
121 CowReader(ReaderFlags reader_flag = ReaderFlags::DEFAULT, bool is_merge = false);
~CowReader()122 ~CowReader() { owned_fd_ = {}; }
123
124 // Parse the COW, optionally, up to the given label. If no label is
125 // specified, the COW must have an intact footer.
126 bool Parse(android::base::unique_fd&& fd, std::optional<uint64_t> label = {});
127 bool Parse(android::base::borrowed_fd fd, std::optional<uint64_t> label = {});
128
129 bool InitForMerge(android::base::unique_fd&& fd);
130
131 bool VerifyMergeOps() override;
132 bool GetFooter(CowFooter* footer) override;
133 bool GetLastLabel(uint64_t* label) override;
134 bool GetSourceOffset(const CowOperation* op, uint64_t* source_offset) override;
135
136 // Create a CowOpIter object which contains footer_.num_ops
137 // CowOperation objects. Get() returns a unique CowOperation object
138 // whose lifetime depends on the CowOpIter object; the return
139 // value of these will never be null.
140 std::unique_ptr<ICowOpIter> GetOpIter(bool merge_progress = false) override;
141 std::unique_ptr<ICowOpIter> GetRevMergeOpIter(bool ignore_progress = false) override;
142 std::unique_ptr<ICowOpIter> GetMergeOpIter(bool ignore_progress = false) override;
143
144 ssize_t ReadData(const CowOperation* op, void* buffer, size_t buffer_size,
145 size_t ignore_bytes = 0) override;
146
GetHeader()147 CowHeader& GetHeader() override { return header_; }
header_v3()148 const CowHeaderV3& header_v3() const { return header_; }
149
150 bool GetRawBytes(const CowOperation* op, void* buffer, size_t len, size_t* read);
151 bool GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read);
152
153 // Returns the total number of data ops that should be merged. This is the
154 // count of the merge sequence before removing already-merged operations.
155 // It may be different than the actual data op count, for example, if there
156 // are duplicate ops in the stream.
get_num_total_data_ops()157 uint64_t get_num_total_data_ops() { return num_total_data_ops_; }
158
get_num_ordered_ops_to_merge()159 uint64_t get_num_ordered_ops_to_merge() { return num_ordered_ops_to_merge_; }
160
CloseCowFd()161 void CloseCowFd() { owned_fd_ = {}; }
162
163 // Creates a clone of the current CowReader without the file handlers
164 std::unique_ptr<CowReader> CloneCowReader();
165
166 // Get the max compression size
167 uint32_t GetMaxCompressionSize();
168
UpdateMergeOpsCompleted(int num_merge_ops)169 void UpdateMergeOpsCompleted(int num_merge_ops) { header_.num_merge_ops += num_merge_ops; }
170
171 private:
172 bool ParseV2(android::base::borrowed_fd fd, std::optional<uint64_t> label);
173 bool PrepMergeOps();
174 // sequence data is stored as an operation with actual data residing in the data offset.
175 bool GetSequenceDataV2(std::vector<uint32_t>* merge_op_blocks, std::vector<int>* other_ops,
176 std::unordered_map<uint32_t, int>* block_map);
177 // v3 of the cow writes sequence data within its own separate sequence buffer.
178 bool GetSequenceData(std::vector<uint32_t>* merge_op_blocks, std::vector<int>* other_ops,
179 std::unordered_map<uint32_t, int>* block_map);
180 uint64_t FindNumCopyops();
181 uint8_t GetCompressionType();
182
183 android::base::unique_fd owned_fd_;
184 android::base::borrowed_fd fd_;
185 CowHeaderV3 header_;
186 std::optional<CowFooter> footer_;
187 uint64_t fd_size_;
188 std::optional<uint64_t> last_label_;
189 std::shared_ptr<std::vector<CowOperation>> ops_;
190 uint64_t merge_op_start_{};
191 std::shared_ptr<std::vector<int>> block_pos_index_;
192 uint64_t num_total_data_ops_{};
193 uint64_t num_ordered_ops_to_merge_{};
194 bool has_seq_ops_{};
195 std::shared_ptr<std::unordered_map<uint64_t, uint64_t>> xor_data_loc_;
196 ReaderFlags reader_flag_;
197 bool is_merge_{};
198 };
199
200 // Though this function takes in a CowHeaderV3, the struct could be populated as a v1/v2 CowHeader.
201 // The extra fields will just be filled as 0. V3 header is strictly a superset of v1/v2 header and
202 // contains all of the latter's field
203 bool ReadCowHeader(android::base::borrowed_fd fd, CowHeaderV3* header);
204 } // namespace snapshot
205 } // namespace android
206