xref: /aosp_15_r20/system/update_engine/lz4diff/lz4patch.cc (revision 5a9231315b4521097b8dc3750bc806fcafe0c72f)
1*5a923131SAndroid Build Coastguard Worker //
2*5a923131SAndroid Build Coastguard Worker // Copyright (C) 2021 The Android Open Source Project
3*5a923131SAndroid Build Coastguard Worker //
4*5a923131SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
5*5a923131SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
6*5a923131SAndroid Build Coastguard Worker // You may obtain a copy of the License at
7*5a923131SAndroid Build Coastguard Worker //
8*5a923131SAndroid Build Coastguard Worker //      http://www.apache.org/licenses/LICENSE-2.0
9*5a923131SAndroid Build Coastguard Worker //
10*5a923131SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
11*5a923131SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
12*5a923131SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*5a923131SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
14*5a923131SAndroid Build Coastguard Worker // limitations under the License.
15*5a923131SAndroid Build Coastguard Worker //
16*5a923131SAndroid Build Coastguard Worker 
17*5a923131SAndroid Build Coastguard Worker #include "lz4patch.h"
18*5a923131SAndroid Build Coastguard Worker 
19*5a923131SAndroid Build Coastguard Worker #include <endian.h>
20*5a923131SAndroid Build Coastguard Worker #include <unistd.h>
21*5a923131SAndroid Build Coastguard Worker #include <fcntl.h>
22*5a923131SAndroid Build Coastguard Worker 
23*5a923131SAndroid Build Coastguard Worker #include <algorithm>
24*5a923131SAndroid Build Coastguard Worker #include <string_view>
25*5a923131SAndroid Build Coastguard Worker 
26*5a923131SAndroid Build Coastguard Worker #include <bsdiff/bspatch.h>
27*5a923131SAndroid Build Coastguard Worker #include <bsdiff/memory_file.h>
28*5a923131SAndroid Build Coastguard Worker #include <bsdiff/file.h>
29*5a923131SAndroid Build Coastguard Worker #include <puffin/memory_stream.h>
30*5a923131SAndroid Build Coastguard Worker 
31*5a923131SAndroid Build Coastguard Worker #include "android-base/strings.h"
32*5a923131SAndroid Build Coastguard Worker #include "lz4diff/lz4diff.h"
33*5a923131SAndroid Build Coastguard Worker #include "lz4diff/lz4diff.pb.h"
34*5a923131SAndroid Build Coastguard Worker #include "lz4diff_compress.h"
35*5a923131SAndroid Build Coastguard Worker #include "lz4diff_format.h"
36*5a923131SAndroid Build Coastguard Worker #include "puffin/puffpatch.h"
37*5a923131SAndroid Build Coastguard Worker #include "update_engine/common/hash_calculator.h"
38*5a923131SAndroid Build Coastguard Worker #include "update_engine/common/utils.h"
39*5a923131SAndroid Build Coastguard Worker 
40*5a923131SAndroid Build Coastguard Worker namespace chromeos_update_engine {
41*5a923131SAndroid Build Coastguard Worker 
42*5a923131SAndroid Build Coastguard Worker namespace {
43*5a923131SAndroid Build Coastguard Worker 
44*5a923131SAndroid Build Coastguard Worker template <typename T>
BigEndianToHost(T & t)45*5a923131SAndroid Build Coastguard Worker constexpr void BigEndianToHost(T& t) {
46*5a923131SAndroid Build Coastguard Worker   static_assert(std::is_integral_v<T>);
47*5a923131SAndroid Build Coastguard Worker   static_assert(sizeof(t) == 4 || sizeof(t) == 8 || sizeof(t) == 2);
48*5a923131SAndroid Build Coastguard Worker   if constexpr (sizeof(t) == 4) {
49*5a923131SAndroid Build Coastguard Worker     t = be32toh(t);
50*5a923131SAndroid Build Coastguard Worker   } else if constexpr (sizeof(t) == 8) {
51*5a923131SAndroid Build Coastguard Worker     t = be64toh(t);
52*5a923131SAndroid Build Coastguard Worker   } else if constexpr (sizeof(t) == 2) {
53*5a923131SAndroid Build Coastguard Worker     t = be16toh(t);
54*5a923131SAndroid Build Coastguard Worker   }
55*5a923131SAndroid Build Coastguard Worker }
56*5a923131SAndroid Build Coastguard Worker 
57*5a923131SAndroid Build Coastguard Worker // In memory representation of an LZ4Diff patch, it's not marked as packed
58*5a923131SAndroid Build Coastguard Worker // because parsing isn't as simple as reinterpret_cast<> any way.
59*5a923131SAndroid Build Coastguard Worker struct Lz4diffPatch {
60*5a923131SAndroid Build Coastguard Worker   char magic[kLz4diffMagic.size()];
61*5a923131SAndroid Build Coastguard Worker   uint32_t version;
62*5a923131SAndroid Build Coastguard Worker   uint32_t pb_header_size;  // size of protobuf message
63*5a923131SAndroid Build Coastguard Worker   Lz4diffHeader pb_header;
64*5a923131SAndroid Build Coastguard Worker   std::string_view inner_patch;
65*5a923131SAndroid Build Coastguard Worker };
66*5a923131SAndroid Build Coastguard Worker 
67*5a923131SAndroid Build Coastguard Worker // Utility class to interact with puffin API. C++ does not have standard
68*5a923131SAndroid Build Coastguard Worker // Read/Write trait. So everybody invent their own file descriptor wrapper.
69*5a923131SAndroid Build Coastguard Worker class StringViewStream : public puffin::StreamInterface {
70*5a923131SAndroid Build Coastguard Worker  public:
71*5a923131SAndroid Build Coastguard Worker   ~StringViewStream() override = default;
72*5a923131SAndroid Build Coastguard Worker 
GetSize(uint64_t * size) const73*5a923131SAndroid Build Coastguard Worker   bool GetSize(uint64_t* size) const override {
74*5a923131SAndroid Build Coastguard Worker     *size = read_memory_.size();
75*5a923131SAndroid Build Coastguard Worker     return true;
76*5a923131SAndroid Build Coastguard Worker   }
77*5a923131SAndroid Build Coastguard Worker 
GetOffset(uint64_t * offset) const78*5a923131SAndroid Build Coastguard Worker   bool GetOffset(uint64_t* offset) const override {
79*5a923131SAndroid Build Coastguard Worker     *offset = offset_;
80*5a923131SAndroid Build Coastguard Worker     return true;
81*5a923131SAndroid Build Coastguard Worker   }
82*5a923131SAndroid Build Coastguard Worker 
Seek(uint64_t offset)83*5a923131SAndroid Build Coastguard Worker   bool Seek(uint64_t offset) override {
84*5a923131SAndroid Build Coastguard Worker     TEST_AND_RETURN_FALSE(open_);
85*5a923131SAndroid Build Coastguard Worker     uint64_t size;
86*5a923131SAndroid Build Coastguard Worker     GetSize(&size);
87*5a923131SAndroid Build Coastguard Worker     TEST_AND_RETURN_FALSE(offset <= size);
88*5a923131SAndroid Build Coastguard Worker     offset_ = offset;
89*5a923131SAndroid Build Coastguard Worker     return true;
90*5a923131SAndroid Build Coastguard Worker   }
91*5a923131SAndroid Build Coastguard Worker 
Read(void * buffer,size_t length)92*5a923131SAndroid Build Coastguard Worker   bool Read(void* buffer, size_t length) override {
93*5a923131SAndroid Build Coastguard Worker     TEST_AND_RETURN_FALSE(open_);
94*5a923131SAndroid Build Coastguard Worker     TEST_AND_RETURN_FALSE(offset_ + length <= read_memory_.size());
95*5a923131SAndroid Build Coastguard Worker     memcpy(buffer, read_memory_.data() + offset_, length);
96*5a923131SAndroid Build Coastguard Worker     offset_ += length;
97*5a923131SAndroid Build Coastguard Worker     return true;
98*5a923131SAndroid Build Coastguard Worker   }
99*5a923131SAndroid Build Coastguard Worker 
Write(const void * buffer,size_t length)100*5a923131SAndroid Build Coastguard Worker   bool Write(const void* buffer, size_t length) override {
101*5a923131SAndroid Build Coastguard Worker     LOG(ERROR) << "Unsupported operation " << __FUNCTION__;
102*5a923131SAndroid Build Coastguard Worker     return false;
103*5a923131SAndroid Build Coastguard Worker   }
104*5a923131SAndroid Build Coastguard Worker 
Close()105*5a923131SAndroid Build Coastguard Worker   bool Close() override {
106*5a923131SAndroid Build Coastguard Worker     open_ = false;
107*5a923131SAndroid Build Coastguard Worker     return true;
108*5a923131SAndroid Build Coastguard Worker   }
109*5a923131SAndroid Build Coastguard Worker 
StringViewStream(std::string_view read_memory)110*5a923131SAndroid Build Coastguard Worker   constexpr StringViewStream(std::string_view read_memory)
111*5a923131SAndroid Build Coastguard Worker       : read_memory_(read_memory) {
112*5a923131SAndroid Build Coastguard Worker     CHECK(!read_memory.empty());
113*5a923131SAndroid Build Coastguard Worker   }
114*5a923131SAndroid Build Coastguard Worker 
115*5a923131SAndroid Build Coastguard Worker  private:
116*5a923131SAndroid Build Coastguard Worker   // The memory buffer for reading.
117*5a923131SAndroid Build Coastguard Worker   std::string_view read_memory_;
118*5a923131SAndroid Build Coastguard Worker 
119*5a923131SAndroid Build Coastguard Worker   // The current offset.
120*5a923131SAndroid Build Coastguard Worker   uint64_t offset_{};
121*5a923131SAndroid Build Coastguard Worker   bool open_{true};
122*5a923131SAndroid Build Coastguard Worker };
123*5a923131SAndroid Build Coastguard Worker 
ParseLz4DifffPatch(std::string_view patch_data,Lz4diffPatch * output)124*5a923131SAndroid Build Coastguard Worker bool ParseLz4DifffPatch(std::string_view patch_data, Lz4diffPatch* output) {
125*5a923131SAndroid Build Coastguard Worker   CHECK_NE(output, nullptr);
126*5a923131SAndroid Build Coastguard Worker   if (!android::base::StartsWith(patch_data, kLz4diffMagic)) {
127*5a923131SAndroid Build Coastguard Worker     LOG(ERROR) << "Invalid lz4diff magic: "
128*5a923131SAndroid Build Coastguard Worker                << HexEncode(patch_data.substr(0, kLz4diffMagic.size()))
129*5a923131SAndroid Build Coastguard Worker                << ", expected: " << HexEncode(kLz4diffMagic);
130*5a923131SAndroid Build Coastguard Worker     return false;
131*5a923131SAndroid Build Coastguard Worker   }
132*5a923131SAndroid Build Coastguard Worker   Lz4diffPatch& patch = *output;
133*5a923131SAndroid Build Coastguard Worker   std::memcpy(patch.magic, patch_data.data(), kLz4diffMagic.size());
134*5a923131SAndroid Build Coastguard Worker   std::memcpy(&patch.version,
135*5a923131SAndroid Build Coastguard Worker               patch_data.data() + kLz4diffMagic.size(),
136*5a923131SAndroid Build Coastguard Worker               sizeof(patch.version));
137*5a923131SAndroid Build Coastguard Worker   BigEndianToHost(patch.version);
138*5a923131SAndroid Build Coastguard Worker   if (patch.version != kLz4diffVersion) {
139*5a923131SAndroid Build Coastguard Worker     LOG(ERROR) << "Unsupported lz4diff version: " << patch.version
140*5a923131SAndroid Build Coastguard Worker                << ", supported version: " << kLz4diffVersion;
141*5a923131SAndroid Build Coastguard Worker     return false;
142*5a923131SAndroid Build Coastguard Worker   }
143*5a923131SAndroid Build Coastguard Worker   std::memcpy(&patch.pb_header_size,
144*5a923131SAndroid Build Coastguard Worker               patch_data.data() + kLz4diffMagic.size() + sizeof(patch.version),
145*5a923131SAndroid Build Coastguard Worker               sizeof(patch.pb_header_size));
146*5a923131SAndroid Build Coastguard Worker   BigEndianToHost(patch.pb_header_size);
147*5a923131SAndroid Build Coastguard Worker   TEST_AND_RETURN_FALSE(patch.pb_header.ParseFromArray(
148*5a923131SAndroid Build Coastguard Worker       patch_data.data() + kLz4diffHeaderSize, patch.pb_header_size));
149*5a923131SAndroid Build Coastguard Worker   patch.inner_patch =
150*5a923131SAndroid Build Coastguard Worker       patch_data.substr(kLz4diffHeaderSize + patch.pb_header_size);
151*5a923131SAndroid Build Coastguard Worker   return true;
152*5a923131SAndroid Build Coastguard Worker }
153*5a923131SAndroid Build Coastguard Worker 
bspatch(std::string_view input_data,std::string_view patch_data,Blob * output)154*5a923131SAndroid Build Coastguard Worker bool bspatch(std::string_view input_data,
155*5a923131SAndroid Build Coastguard Worker              std::string_view patch_data,
156*5a923131SAndroid Build Coastguard Worker              Blob* output) {
157*5a923131SAndroid Build Coastguard Worker   CHECK_NE(output, nullptr);
158*5a923131SAndroid Build Coastguard Worker   output->clear();
159*5a923131SAndroid Build Coastguard Worker   CHECK_GT(patch_data.size(), 0UL);
160*5a923131SAndroid Build Coastguard Worker   int err =
161*5a923131SAndroid Build Coastguard Worker       bsdiff::bspatch(reinterpret_cast<const uint8_t*>(input_data.data()),
162*5a923131SAndroid Build Coastguard Worker                       input_data.size(),
163*5a923131SAndroid Build Coastguard Worker                       reinterpret_cast<const uint8_t*>(patch_data.data()),
164*5a923131SAndroid Build Coastguard Worker                       patch_data.size(),
165*5a923131SAndroid Build Coastguard Worker                       [output](const uint8_t* data, size_t size) -> size_t {
166*5a923131SAndroid Build Coastguard Worker                         output->insert(output->end(), data, data + size);
167*5a923131SAndroid Build Coastguard Worker                         return size;
168*5a923131SAndroid Build Coastguard Worker                       });
169*5a923131SAndroid Build Coastguard Worker   return err == 0;
170*5a923131SAndroid Build Coastguard Worker }
171*5a923131SAndroid Build Coastguard Worker 
puffpatch(std::string_view input_data,std::string_view patch_data,Blob * output)172*5a923131SAndroid Build Coastguard Worker bool puffpatch(std::string_view input_data,
173*5a923131SAndroid Build Coastguard Worker                std::string_view patch_data,
174*5a923131SAndroid Build Coastguard Worker                Blob* output) {
175*5a923131SAndroid Build Coastguard Worker   // Cache size has a big impact on speed of puffpatch, use a default of 5MB to
176*5a923131SAndroid Build Coastguard Worker   // match update_engine behavior.
177*5a923131SAndroid Build Coastguard Worker   static constexpr size_t kPuffPatchCacheSize = 5 * 1024 * 1024;
178*5a923131SAndroid Build Coastguard Worker   return puffin::PuffPatch(std::make_unique<StringViewStream>(input_data),
179*5a923131SAndroid Build Coastguard Worker                            puffin::MemoryStream::CreateForWrite(output),
180*5a923131SAndroid Build Coastguard Worker                            reinterpret_cast<const uint8_t*>(patch_data.data()),
181*5a923131SAndroid Build Coastguard Worker                            patch_data.size(),
182*5a923131SAndroid Build Coastguard Worker                            kPuffPatchCacheSize);
183*5a923131SAndroid Build Coastguard Worker }
184*5a923131SAndroid Build Coastguard Worker 
ToCompressedBlockVec(const google::protobuf::RepeatedPtrField<CompressedBlockInfo> & rpf)185*5a923131SAndroid Build Coastguard Worker std::vector<CompressedBlock> ToCompressedBlockVec(
186*5a923131SAndroid Build Coastguard Worker     const google::protobuf::RepeatedPtrField<CompressedBlockInfo>& rpf) {
187*5a923131SAndroid Build Coastguard Worker   std::vector<CompressedBlock> ret;
188*5a923131SAndroid Build Coastguard Worker   ret.reserve(rpf.size());
189*5a923131SAndroid Build Coastguard Worker   for (const auto& block : rpf) {
190*5a923131SAndroid Build Coastguard Worker     auto& info = ret.emplace_back();
191*5a923131SAndroid Build Coastguard Worker     info.compressed_length = block.compressed_length();
192*5a923131SAndroid Build Coastguard Worker     info.uncompressed_length = block.uncompressed_length();
193*5a923131SAndroid Build Coastguard Worker     info.uncompressed_offset = block.uncompressed_offset();
194*5a923131SAndroid Build Coastguard Worker   }
195*5a923131SAndroid Build Coastguard Worker   return ret;
196*5a923131SAndroid Build Coastguard Worker }
197*5a923131SAndroid Build Coastguard Worker 
HasPosfixPatches(const Lz4diffPatch & patch)198*5a923131SAndroid Build Coastguard Worker bool HasPosfixPatches(const Lz4diffPatch& patch) {
199*5a923131SAndroid Build Coastguard Worker   for (const auto& info : patch.pb_header.dst_info().block_info()) {
200*5a923131SAndroid Build Coastguard Worker     if (!info.postfix_bspatch().empty()) {
201*5a923131SAndroid Build Coastguard Worker       return true;
202*5a923131SAndroid Build Coastguard Worker     }
203*5a923131SAndroid Build Coastguard Worker   }
204*5a923131SAndroid Build Coastguard Worker   return false;
205*5a923131SAndroid Build Coastguard Worker }
206*5a923131SAndroid Build Coastguard Worker 
GetCompressedSize(const google::protobuf::RepeatedPtrField<CompressedBlockInfo> & info)207*5a923131SAndroid Build Coastguard Worker size_t GetCompressedSize(
208*5a923131SAndroid Build Coastguard Worker     const google::protobuf::RepeatedPtrField<CompressedBlockInfo>& info) {
209*5a923131SAndroid Build Coastguard Worker   size_t compressed_size = 0;
210*5a923131SAndroid Build Coastguard Worker   for (const auto& block : info) {
211*5a923131SAndroid Build Coastguard Worker     compressed_size += block.compressed_length();
212*5a923131SAndroid Build Coastguard Worker   }
213*5a923131SAndroid Build Coastguard Worker   return compressed_size;
214*5a923131SAndroid Build Coastguard Worker }
215*5a923131SAndroid Build Coastguard Worker 
GetDecompressedSize(const google::protobuf::RepeatedPtrField<CompressedBlockInfo> & info)216*5a923131SAndroid Build Coastguard Worker size_t GetDecompressedSize(
217*5a923131SAndroid Build Coastguard Worker     const google::protobuf::RepeatedPtrField<CompressedBlockInfo>& info) {
218*5a923131SAndroid Build Coastguard Worker   size_t decompressed_size = 0;
219*5a923131SAndroid Build Coastguard Worker   for (const auto& block : info) {
220*5a923131SAndroid Build Coastguard Worker     decompressed_size += block.uncompressed_length();
221*5a923131SAndroid Build Coastguard Worker   }
222*5a923131SAndroid Build Coastguard Worker   return decompressed_size;
223*5a923131SAndroid Build Coastguard Worker }
224*5a923131SAndroid Build Coastguard Worker 
ApplyInnerPatch(Blob decompressed_src,const Lz4diffPatch & patch,Blob * decompressed_dst)225*5a923131SAndroid Build Coastguard Worker bool ApplyInnerPatch(Blob decompressed_src,
226*5a923131SAndroid Build Coastguard Worker                      const Lz4diffPatch& patch,
227*5a923131SAndroid Build Coastguard Worker                      Blob* decompressed_dst) {
228*5a923131SAndroid Build Coastguard Worker   switch (patch.pb_header.inner_type()) {
229*5a923131SAndroid Build Coastguard Worker     case InnerPatchType::BSDIFF:
230*5a923131SAndroid Build Coastguard Worker       TEST_AND_RETURN_FALSE(bspatch(
231*5a923131SAndroid Build Coastguard Worker           ToStringView(decompressed_src), patch.inner_patch, decompressed_dst));
232*5a923131SAndroid Build Coastguard Worker       break;
233*5a923131SAndroid Build Coastguard Worker     case InnerPatchType::PUFFDIFF:
234*5a923131SAndroid Build Coastguard Worker       TEST_AND_RETURN_FALSE(puffpatch(
235*5a923131SAndroid Build Coastguard Worker           ToStringView(decompressed_src), patch.inner_patch, decompressed_dst));
236*5a923131SAndroid Build Coastguard Worker       break;
237*5a923131SAndroid Build Coastguard Worker     default:
238*5a923131SAndroid Build Coastguard Worker       LOG(ERROR) << "Unsupported patch type: " << patch.pb_header.inner_type();
239*5a923131SAndroid Build Coastguard Worker       return false;
240*5a923131SAndroid Build Coastguard Worker   }
241*5a923131SAndroid Build Coastguard Worker   return true;
242*5a923131SAndroid Build Coastguard Worker }
243*5a923131SAndroid Build Coastguard Worker 
244*5a923131SAndroid Build Coastguard Worker // TODO(zhangkelvin) Rewrite this in C++ 20 coroutine once that's available.
245*5a923131SAndroid Build Coastguard Worker // Hand coding CPS is not fun.
Lz4Patch(std::string_view src_data,const Lz4diffPatch & patch,const SinkFunc & sink)246*5a923131SAndroid Build Coastguard Worker bool Lz4Patch(std::string_view src_data,
247*5a923131SAndroid Build Coastguard Worker               const Lz4diffPatch& patch,
248*5a923131SAndroid Build Coastguard Worker               const SinkFunc& sink) {
249*5a923131SAndroid Build Coastguard Worker   auto decompressed_src = TryDecompressBlob(
250*5a923131SAndroid Build Coastguard Worker       src_data,
251*5a923131SAndroid Build Coastguard Worker       ToCompressedBlockVec(patch.pb_header.src_info().block_info()),
252*5a923131SAndroid Build Coastguard Worker       patch.pb_header.src_info().zero_padding_enabled());
253*5a923131SAndroid Build Coastguard Worker   TEST_AND_RETURN_FALSE(!decompressed_src.empty());
254*5a923131SAndroid Build Coastguard Worker   Blob decompressed_dst;
255*5a923131SAndroid Build Coastguard Worker   const auto decompressed_dst_size =
256*5a923131SAndroid Build Coastguard Worker       GetDecompressedSize(patch.pb_header.dst_info().block_info());
257*5a923131SAndroid Build Coastguard Worker   decompressed_dst.reserve(decompressed_dst_size);
258*5a923131SAndroid Build Coastguard Worker 
259*5a923131SAndroid Build Coastguard Worker   ApplyInnerPatch(std::move(decompressed_src), patch, &decompressed_dst);
260*5a923131SAndroid Build Coastguard Worker 
261*5a923131SAndroid Build Coastguard Worker   if (!HasPosfixPatches(patch)) {
262*5a923131SAndroid Build Coastguard Worker     return TryCompressBlob(
263*5a923131SAndroid Build Coastguard Worker         ToStringView(decompressed_dst),
264*5a923131SAndroid Build Coastguard Worker         ToCompressedBlockVec(patch.pb_header.dst_info().block_info()),
265*5a923131SAndroid Build Coastguard Worker         patch.pb_header.dst_info().zero_padding_enabled(),
266*5a923131SAndroid Build Coastguard Worker         patch.pb_header.dst_info().algo(),
267*5a923131SAndroid Build Coastguard Worker         sink);
268*5a923131SAndroid Build Coastguard Worker   }
269*5a923131SAndroid Build Coastguard Worker   auto postfix_patcher =
270*5a923131SAndroid Build Coastguard Worker       [&sink,
271*5a923131SAndroid Build Coastguard Worker        block_idx = 0,
272*5a923131SAndroid Build Coastguard Worker        &dst_block_info = patch.pb_header.dst_info().block_info()](
273*5a923131SAndroid Build Coastguard Worker           const uint8_t* data, size_t size) mutable -> size_t {
274*5a923131SAndroid Build Coastguard Worker     if (block_idx >= dst_block_info.size()) {
275*5a923131SAndroid Build Coastguard Worker       return sink(data, size);
276*5a923131SAndroid Build Coastguard Worker     }
277*5a923131SAndroid Build Coastguard Worker     const auto& block_info = dst_block_info[block_idx];
278*5a923131SAndroid Build Coastguard Worker     TEST_EQ(size, block_info.compressed_length());
279*5a923131SAndroid Build Coastguard Worker     DEFER { block_idx++; };
280*5a923131SAndroid Build Coastguard Worker     if (block_info.postfix_bspatch().empty()) {
281*5a923131SAndroid Build Coastguard Worker       return sink(data, size);
282*5a923131SAndroid Build Coastguard Worker     }
283*5a923131SAndroid Build Coastguard Worker     if (!block_info.sha256_hash().empty()) {
284*5a923131SAndroid Build Coastguard Worker       Blob actual_hash;
285*5a923131SAndroid Build Coastguard Worker       TEST_AND_RETURN_FALSE(
286*5a923131SAndroid Build Coastguard Worker           HashCalculator::RawHashOfBytes(data, size, &actual_hash));
287*5a923131SAndroid Build Coastguard Worker       if (ToStringView(actual_hash) != block_info.sha256_hash()) {
288*5a923131SAndroid Build Coastguard Worker         LOG(ERROR) << "Block " << block_info
289*5a923131SAndroid Build Coastguard Worker                    << " is corrupted. This usually means the patch generator "
290*5a923131SAndroid Build Coastguard Worker                       "used a different version of LZ4, or an incompatible LZ4 "
291*5a923131SAndroid Build Coastguard Worker                       "patch generator was used, or LZ4 produces different "
292*5a923131SAndroid Build Coastguard Worker                       "output on different platforms. Expected hash: "
293*5a923131SAndroid Build Coastguard Worker                    << HexEncode(block_info.sha256_hash())
294*5a923131SAndroid Build Coastguard Worker                    << ", actual hash: " << HexEncode(actual_hash);
295*5a923131SAndroid Build Coastguard Worker         return 0;
296*5a923131SAndroid Build Coastguard Worker       }
297*5a923131SAndroid Build Coastguard Worker     }
298*5a923131SAndroid Build Coastguard Worker     Blob fixed_block;
299*5a923131SAndroid Build Coastguard Worker     TEST_AND_RETURN_FALSE(
300*5a923131SAndroid Build Coastguard Worker         bspatch(std::string_view(reinterpret_cast<const char*>(data), size),
301*5a923131SAndroid Build Coastguard Worker                 block_info.postfix_bspatch(),
302*5a923131SAndroid Build Coastguard Worker                 &fixed_block));
303*5a923131SAndroid Build Coastguard Worker     return sink(fixed_block.data(), fixed_block.size());
304*5a923131SAndroid Build Coastguard Worker   };
305*5a923131SAndroid Build Coastguard Worker 
306*5a923131SAndroid Build Coastguard Worker   return TryCompressBlob(
307*5a923131SAndroid Build Coastguard Worker       ToStringView(decompressed_dst),
308*5a923131SAndroid Build Coastguard Worker       ToCompressedBlockVec(patch.pb_header.dst_info().block_info()),
309*5a923131SAndroid Build Coastguard Worker       patch.pb_header.dst_info().zero_padding_enabled(),
310*5a923131SAndroid Build Coastguard Worker       patch.pb_header.dst_info().algo(),
311*5a923131SAndroid Build Coastguard Worker       postfix_patcher);
312*5a923131SAndroid Build Coastguard Worker }
313*5a923131SAndroid Build Coastguard Worker 
Lz4Patch(std::string_view src_data,const Lz4diffPatch & patch,Blob * output)314*5a923131SAndroid Build Coastguard Worker bool Lz4Patch(std::string_view src_data,
315*5a923131SAndroid Build Coastguard Worker               const Lz4diffPatch& patch,
316*5a923131SAndroid Build Coastguard Worker               Blob* output) {
317*5a923131SAndroid Build Coastguard Worker   Blob blob;
318*5a923131SAndroid Build Coastguard Worker   const auto output_size =
319*5a923131SAndroid Build Coastguard Worker       GetCompressedSize(patch.pb_header.dst_info().block_info());
320*5a923131SAndroid Build Coastguard Worker   blob.reserve(output_size);
321*5a923131SAndroid Build Coastguard Worker   TEST_AND_RETURN_FALSE(Lz4Patch(
322*5a923131SAndroid Build Coastguard Worker       src_data, patch, [&blob](const uint8_t* data, size_t size) -> size_t {
323*5a923131SAndroid Build Coastguard Worker         blob.insert(blob.end(), data, data + size);
324*5a923131SAndroid Build Coastguard Worker         return size;
325*5a923131SAndroid Build Coastguard Worker       }));
326*5a923131SAndroid Build Coastguard Worker   *output = std::move(blob);
327*5a923131SAndroid Build Coastguard Worker   return true;
328*5a923131SAndroid Build Coastguard Worker }
329*5a923131SAndroid Build Coastguard Worker 
330*5a923131SAndroid Build Coastguard Worker }  // namespace
331*5a923131SAndroid Build Coastguard Worker 
Lz4Patch(std::string_view src_data,std::string_view patch_data,Blob * output)332*5a923131SAndroid Build Coastguard Worker bool Lz4Patch(std::string_view src_data,
333*5a923131SAndroid Build Coastguard Worker               std::string_view patch_data,
334*5a923131SAndroid Build Coastguard Worker               Blob* output) {
335*5a923131SAndroid Build Coastguard Worker   Lz4diffPatch patch;
336*5a923131SAndroid Build Coastguard Worker   TEST_AND_RETURN_FALSE(ParseLz4DifffPatch(patch_data, &patch));
337*5a923131SAndroid Build Coastguard Worker   return Lz4Patch(src_data, patch, output);
338*5a923131SAndroid Build Coastguard Worker }
339*5a923131SAndroid Build Coastguard Worker 
Lz4Patch(std::string_view src_data,std::string_view patch_data,const SinkFunc & sink)340*5a923131SAndroid Build Coastguard Worker bool Lz4Patch(std::string_view src_data,
341*5a923131SAndroid Build Coastguard Worker               std::string_view patch_data,
342*5a923131SAndroid Build Coastguard Worker               const SinkFunc& sink) {
343*5a923131SAndroid Build Coastguard Worker   Lz4diffPatch patch;
344*5a923131SAndroid Build Coastguard Worker   TEST_AND_RETURN_FALSE(ParseLz4DifffPatch(patch_data, &patch));
345*5a923131SAndroid Build Coastguard Worker   return Lz4Patch(src_data, patch, sink);
346*5a923131SAndroid Build Coastguard Worker }
347*5a923131SAndroid Build Coastguard Worker 
Lz4Patch(const Blob & src_data,const Blob & patch_data,Blob * output)348*5a923131SAndroid Build Coastguard Worker bool Lz4Patch(const Blob& src_data, const Blob& patch_data, Blob* output) {
349*5a923131SAndroid Build Coastguard Worker   return Lz4Patch(ToStringView(src_data), ToStringView(patch_data), output);
350*5a923131SAndroid Build Coastguard Worker }
351*5a923131SAndroid Build Coastguard Worker 
operator <<(std::ostream & out,const CompressionAlgorithm & info)352*5a923131SAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& out, const CompressionAlgorithm& info) {
353*5a923131SAndroid Build Coastguard Worker   out << "Algo {type: " << info.Type_Name(info.type());
354*5a923131SAndroid Build Coastguard Worker   if (info.level() != 0) {
355*5a923131SAndroid Build Coastguard Worker     out << ", level: " << info.level();
356*5a923131SAndroid Build Coastguard Worker   }
357*5a923131SAndroid Build Coastguard Worker   out << "}";
358*5a923131SAndroid Build Coastguard Worker 
359*5a923131SAndroid Build Coastguard Worker   return out;
360*5a923131SAndroid Build Coastguard Worker }
361*5a923131SAndroid Build Coastguard Worker 
operator <<(std::ostream & out,const CompressionInfo & info)362*5a923131SAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& out, const CompressionInfo& info) {
363*5a923131SAndroid Build Coastguard Worker   out << "CompressionInfo {block_info: " << info.block_info()
364*5a923131SAndroid Build Coastguard Worker       << ", algo: " << info.algo() << "}";
365*5a923131SAndroid Build Coastguard Worker   return out;
366*5a923131SAndroid Build Coastguard Worker }
367*5a923131SAndroid Build Coastguard Worker 
operator <<(std::ostream & out,const Lz4diffHeader & header)368*5a923131SAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& out, const Lz4diffHeader& header) {
369*5a923131SAndroid Build Coastguard Worker   out << "Lz4diffHeader {src_info: " << header.src_info()
370*5a923131SAndroid Build Coastguard Worker       << ", dst_info: " << header.dst_info() << "}";
371*5a923131SAndroid Build Coastguard Worker   return out;
372*5a923131SAndroid Build Coastguard Worker }
373*5a923131SAndroid Build Coastguard Worker 
374*5a923131SAndroid Build Coastguard Worker }  // namespace chromeos_update_engine
375