1 // Copyright 2017 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "puffin/src/include/puffin/puffpatch.h" 6 7 #include <endian.h> 8 #include <inttypes.h> 9 #include <unistd.h> 10 11 #include <algorithm> 12 #include <string> 13 #include <vector> 14 15 #include "bsdiff/bspatch.h" 16 #include "bsdiff/file_interface.h" 17 18 #include "puffin/src/include/puffin/common.h" 19 #include "puffin/src/include/puffin/huffer.h" 20 #include "puffin/src/include/puffin/puffer.h" 21 #include "puffin/src/include/puffin/stream.h" 22 #include "puffin/src/puffin.pb.h" 23 #include "puffin/src/puffin_stream.h" 24 #include "puffin/src/set_errors.h" 25 26 namespace puffin { 27 28 using std::string; 29 using std::vector; 30 31 const char kMagic[] = "PUF1"; 32 const size_t kMagicLength = 4; 33 34 namespace { 35 36 template <typename T> 37 void CopyRpfToVector( 38 const google::protobuf::RepeatedPtrField<metadata::BitExtent>& from, 39 T* to, 40 size_t coef) { 41 to->reserve(from.size()); 42 for (const auto& ext : from) { 43 to->emplace_back(ext.offset() / coef, ext.length() / coef); 44 } 45 } 46 47 bool DecodePatch(const uint8_t* patch, 48 size_t patch_length, 49 size_t* bsdiff_patch_offset, 50 size_t* bsdiff_patch_size, 51 vector<BitExtent>* src_deflates, 52 vector<BitExtent>* dst_deflates, 53 vector<ByteExtent>* src_puffs, 54 vector<ByteExtent>* dst_puffs, 55 uint64_t* src_puff_size, 56 uint64_t* dst_puff_size) { 57 size_t offset = 0; 58 uint32_t header_size; 59 TEST_AND_RETURN_FALSE(patch_length >= (kMagicLength + sizeof(header_size))); 60 61 string patch_magic(reinterpret_cast<const char*>(patch), kMagicLength); 62 if (patch_magic != kMagic) { 63 LOG(ERROR) << "Magic number for Puffin patch is incorrect: " << patch_magic; 64 return false; 65 } 66 offset += kMagicLength; 67 68 // Read the header size from big-endian mode. 69 memcpy(&header_size, patch + offset, sizeof(header_size)); 70 header_size = be32toh(header_size); 71 offset += sizeof(header_size); 72 TEST_AND_RETURN_FALSE(header_size <= (patch_length - offset)); 73 74 metadata::PatchHeader header; 75 TEST_AND_RETURN_FALSE(header.ParseFromArray(patch + offset, header_size)); 76 offset += header_size; 77 78 CopyRpfToVector(header.src().deflates(), src_deflates, 1); 79 CopyRpfToVector(header.dst().deflates(), dst_deflates, 1); 80 CopyRpfToVector(header.src().puffs(), src_puffs, 8); 81 CopyRpfToVector(header.dst().puffs(), dst_puffs, 8); 82 83 *src_puff_size = header.src().puff_length(); 84 *dst_puff_size = header.dst().puff_length(); 85 86 *bsdiff_patch_offset = offset; 87 *bsdiff_patch_size = patch_length - offset; 88 return true; 89 } 90 91 class BsdiffStream : public bsdiff::FileInterface { 92 public: 93 explicit BsdiffStream(UniqueStreamPtr stream) : stream_(std::move(stream)) {} 94 ~BsdiffStream() override = default; 95 96 bool Read(void* buf, size_t count, size_t* bytes_read) override { 97 *bytes_read = 0; 98 if (stream_->Read(buf, count)) { 99 *bytes_read = count; 100 return true; 101 } 102 return false; 103 } 104 105 bool Write(const void* buf, size_t count, size_t* bytes_written) override { 106 *bytes_written = 0; 107 if (stream_->Write(buf, count)) { 108 *bytes_written = count; 109 return true; 110 } 111 return false; 112 } 113 114 bool Seek(off_t pos) override { return stream_->Seek(pos); } 115 116 bool Close() override { return stream_->Close(); } 117 118 bool GetSize(uint64_t* size) override { 119 uint64_t my_size; 120 TEST_AND_RETURN_FALSE(stream_->GetSize(&my_size)); 121 *size = my_size; 122 return true; 123 } 124 125 private: 126 UniqueStreamPtr stream_; 127 128 DISALLOW_COPY_AND_ASSIGN(BsdiffStream); 129 }; 130 131 } // namespace 132 133 bool PuffPatch(UniqueStreamPtr src, 134 UniqueStreamPtr dst, 135 const uint8_t* patch, 136 size_t patch_length, 137 size_t max_cache_size) { 138 size_t bsdiff_patch_offset; // bsdiff offset in |patch|. 139 size_t bsdiff_patch_size = 0; 140 vector<BitExtent> src_deflates, dst_deflates; 141 vector<ByteExtent> src_puffs, dst_puffs; 142 uint64_t src_puff_size, dst_puff_size; 143 144 // Decode the patch and get the bsdiff_patch. 145 TEST_AND_RETURN_FALSE(DecodePatch(patch, patch_length, &bsdiff_patch_offset, 146 &bsdiff_patch_size, &src_deflates, 147 &dst_deflates, &src_puffs, &dst_puffs, 148 &src_puff_size, &dst_puff_size)); 149 auto puffer = std::make_shared<Puffer>(); 150 auto huffer = std::make_shared<Huffer>(); 151 152 // For reading from source. 153 std::unique_ptr<bsdiff::FileInterface> reader(new BsdiffStream( 154 PuffinStream::CreateForPuff(std::move(src), puffer, src_puff_size, 155 src_deflates, src_puffs, max_cache_size))); 156 157 // For writing into destination. 158 std::unique_ptr<bsdiff::FileInterface> writer( 159 new BsdiffStream(PuffinStream::CreateForHuff( 160 std::move(dst), huffer, dst_puff_size, dst_deflates, dst_puffs))); 161 162 // Running bspatch itself. 163 TEST_AND_RETURN_FALSE( 164 0 == 165 bspatch(reader, writer, &patch[bsdiff_patch_offset], bsdiff_patch_size)); 166 return true; 167 } 168 169 } // namespace puffin 170