aboutsummaryrefslogtreecommitdiff
path: root/src/puffpatch.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/puffpatch.cc')
-rw-r--r--src/puffpatch.cc112
1 files changed, 88 insertions, 24 deletions
diff --git a/src/puffpatch.cc b/src/puffpatch.cc
index 0b4ffcb..e9e4a32 100644
--- a/src/puffpatch.cc
+++ b/src/puffpatch.cc
@@ -14,12 +14,16 @@
#include "bsdiff/bspatch.h"
#include "bsdiff/file_interface.h"
+#include "zucchini/patch_reader.h"
+#include "zucchini/zucchini.h"
+#include "puffin/src/include/puffin/brotli_util.h"
#include "puffin/src/include/puffin/common.h"
#include "puffin/src/include/puffin/huffer.h"
#include "puffin/src/include/puffin/puffer.h"
#include "puffin/src/include/puffin/stream.h"
#include "puffin/src/logging.h"
+#include "puffin/memory_stream.h"
#include "puffin/src/puffin.pb.h"
#include "puffin/src/puffin_stream.h"
@@ -92,8 +96,6 @@ class BsdiffStream : public bsdiff::FileInterface {
DISALLOW_COPY_AND_ASSIGN(BsdiffStream);
};
-} // namespace
-
bool DecodePatch(const uint8_t* patch,
size_t patch_length,
size_t* bsdiff_patch_offset,
@@ -103,7 +105,8 @@ bool DecodePatch(const uint8_t* patch,
vector<ByteExtent>* src_puffs,
vector<ByteExtent>* dst_puffs,
uint64_t* src_puff_size,
- uint64_t* dst_puff_size) {
+ uint64_t* dst_puff_size,
+ metadata::PatchHeader_PatchType* patch_type) {
size_t offset = 0;
uint32_t header_size;
TEST_AND_RETURN_FALSE(patch_length >= (kMagicLength + sizeof(header_size)));
@@ -135,43 +138,104 @@ bool DecodePatch(const uint8_t* patch,
*bsdiff_patch_offset = offset;
*bsdiff_patch_size = patch_length - offset;
+
+ *patch_type = header.type();
+ return true;
+}
+
+bool ApplyZucchiniPatch(UniqueStreamPtr src_stream,
+ size_t src_size,
+ const uint8_t* patch_start,
+ size_t patch_size,
+ UniqueStreamPtr dst_stream) {
+ // Read the source data
+ Buffer puffed_src(src_size);
+ Buffer buffer(1024 * 1024);
+ uint64_t bytes_wrote = 0;
+ while (bytes_wrote < src_size) {
+ auto write_size =
+ std::min(static_cast<uint64_t>(buffer.size()), src_size - bytes_wrote);
+ TEST_AND_RETURN_FALSE(src_stream->Read(buffer.data(), write_size));
+ std::copy(buffer.data(), buffer.data() + write_size,
+ puffed_src.data() + bytes_wrote);
+ bytes_wrote += write_size;
+ }
+ // Read the patch
+ Buffer zucchini_patch;
+ TEST_AND_RETURN_FALSE(BrotliDecode(patch_start, patch_size, &zucchini_patch));
+ auto patch_reader = zucchini::EnsemblePatchReader::Create(
+ {zucchini_patch.data(), zucchini_patch.size()});
+ if (!patch_reader.has_value()) {
+ LOG(ERROR) << "Failed to parse the zucchini patch.";
+ return false;
+ }
+
+ // TODO(197361113) Stream the patched result once zucchini supports it. So we
+ // can save some memory when applying patch on device.
+ Buffer patched_data(patch_reader->header().new_size);
+ auto status = zucchini::ApplyBuffer(
+ {puffed_src.data(), puffed_src.size()}, *patch_reader,
+ {patched_data.data(), patched_data.size()});
+ if (status != zucchini::status::kStatusSuccess) {
+ LOG(ERROR) << "Failed to parse the zucchini patch: " << status;
+ return false;
+ }
+
+ TEST_AND_RETURN_FALSE(
+ dst_stream->Write(patched_data.data(), patched_data.size()));
return true;
}
+} // namespace
+
bool PuffPatch(UniqueStreamPtr src,
UniqueStreamPtr dst,
const uint8_t* patch,
size_t patch_length,
size_t max_cache_size) {
- size_t bsdiff_patch_offset; // bsdiff offset in |patch|.
- size_t bsdiff_patch_size = 0;
+ size_t patch_offset; // raw patch offset in puffin |patch|.
+ size_t raw_patch_size = 0;
vector<BitExtent> src_deflates, dst_deflates;
vector<ByteExtent> src_puffs, dst_puffs;
uint64_t src_puff_size, dst_puff_size;
- // Decode the patch and get the bsdiff_patch.
- TEST_AND_RETURN_FALSE(DecodePatch(patch, patch_length, &bsdiff_patch_offset,
- &bsdiff_patch_size, &src_deflates,
- &dst_deflates, &src_puffs, &dst_puffs,
- &src_puff_size, &dst_puff_size));
+ metadata::PatchHeader_PatchType patch_type;
+
+ // Decode the patch and get the raw patch (e.g. bsdiff, zucchini).
+ TEST_AND_RETURN_FALSE(
+ DecodePatch(patch, patch_length, &patch_offset, &raw_patch_size,
+ &src_deflates, &dst_deflates, &src_puffs, &dst_puffs,
+ &src_puff_size, &dst_puff_size, &patch_type));
auto puffer = std::make_shared<Puffer>();
auto huffer = std::make_shared<Huffer>();
- // For reading from source.
- auto reader = BsdiffStream::Create(
+ auto src_stream =
PuffinStream::CreateForPuff(std::move(src), puffer, src_puff_size,
- src_deflates, src_puffs, max_cache_size));
- TEST_AND_RETURN_FALSE(reader);
-
- // For writing into destination.
- auto writer = BsdiffStream::Create(PuffinStream::CreateForHuff(
- std::move(dst), huffer, dst_puff_size, dst_deflates, dst_puffs));
- TEST_AND_RETURN_FALSE(writer);
-
- // Running bspatch itself.
- TEST_AND_RETURN_FALSE(0 == bspatch(reader, writer,
- &patch[bsdiff_patch_offset],
- bsdiff_patch_size));
+ src_deflates, src_puffs, max_cache_size);
+ TEST_AND_RETURN_FALSE(src_stream);
+ auto dst_stream = PuffinStream::CreateForHuff(
+ std::move(dst), huffer, dst_puff_size, dst_deflates, dst_puffs);
+ TEST_AND_RETURN_FALSE(dst_stream);
+
+ if (patch_type == metadata::PatchHeader_PatchType_BSDIFF) {
+ // For reading from source.
+ auto reader = BsdiffStream::Create(std::move(src_stream));
+ TEST_AND_RETURN_FALSE(reader);
+ // For writing into destination.
+ auto writer = BsdiffStream::Create(std::move(dst_stream));
+ TEST_AND_RETURN_FALSE(writer);
+
+ // Running bspatch itself.
+ TEST_AND_RETURN_FALSE(
+ 0 == bspatch(reader, writer, &patch[patch_offset], raw_patch_size));
+ } else if (patch_type == metadata::PatchHeader_PatchType_ZUCCHINI) {
+ TEST_AND_RETURN_FALSE(ApplyZucchiniPatch(
+ std::move(src_stream), src_puff_size, patch + patch_offset,
+ raw_patch_size, std::move(dst_stream)));
+ } else {
+ LOG(ERROR) << "Unsupported patch type " << patch_type;
+ return false;
+ }
return true;
}