• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
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 
16 #include "image_patch.h"
17 #include <memory>
18 #include <string>
19 #include <vector>
20 #include "diffpatch.h"
21 #include "lz4_adapter.h"
22 #include "openssl/sha.h"
23 #include "securec.h"
24 #include "zip_adapter.h"
25 
26 using namespace Hpackage;
27 
28 namespace UpdatePatch {
29 uint32_t g_tmpFileId = 0;
30 
ApplyImagePatch(const PatchParam & param,size_t & startOffset)31 int32_t NormalImagePatch::ApplyImagePatch(const PatchParam &param, size_t &startOffset)
32 {
33     size_t offset = startOffset;
34     if (offset + PATCH_NORMAL_MIN_HEADER_LEN > param.patchSize) {
35         PATCH_LOGE("Failed to check datalen");
36         return -1;
37     }
38 
39     size_t srcStart = static_cast<size_t>(ReadLE<int64_t>(param.patch + offset));
40     offset += sizeof(int64_t);
41     size_t srcLen = static_cast<size_t>(ReadLE<int64_t>(param.patch + offset));
42     offset += sizeof(int64_t);
43     size_t patchOffset = static_cast<size_t>(ReadLE<int64_t>(param.patch + offset));
44     offset += sizeof(int64_t);
45     PATCH_LOGI("ApplyImagePatch srcStart %zu srcLen %zu patchOffset: %zu", srcStart, srcLen, patchOffset);
46     if (srcStart + srcLen > param.oldSize) {
47         PATCH_LOGE("Failed to check datalen");
48         return -1;
49     }
50 
51     PatchBuffer patchInfo = {param.patch, patchOffset, param.patchSize};
52     BlockBuffer oldInfo = {param.oldBuff + srcStart, srcLen};
53     int32_t ret = UpdateApplyPatch::ApplyBlockPatch(patchInfo, oldInfo, writer_);
54     if (ret != 0) {
55         PATCH_LOGE("Failed to apply bsdiff patch");
56         return -1;
57     }
58     startOffset = offset;
59     return 0;
60 }
61 
ApplyImagePatch(const PatchParam & param,size_t & startOffset)62 int32_t RowImagePatch::ApplyImagePatch(const PatchParam &param, size_t &startOffset)
63 {
64     size_t offset = startOffset;
65     if (offset + sizeof(int32_t) > param.patchSize) {
66         PATCH_LOGE("Failed to check datalen");
67         return -1;
68     }
69     size_t dataLen = static_cast<size_t>(ReadLE<uint32_t>(param.patch + offset));
70     if (offset + dataLen > param.patchSize) {
71         PATCH_LOGE("Failed to check datalen");
72         return -1;
73     }
74     offset += sizeof(uint32_t);
75 
76     BlockBuffer data = {param.patch + offset, dataLen};
77     int32_t ret = writer_->Write(0, data, dataLen);
78     if (ret != 0) {
79         PATCH_LOGE("Failed to write chunk");
80         return -1;
81     }
82     PATCH_LOGI("RowImagePatch startOffset %zu dataLen %zu", startOffset, dataLen);
83     PATCH_DEBUG("ApplyImagePatch hash %zu %s",  dataLen, GeneraterBufferHash(data).c_str());
84     startOffset = offset + dataLen;
85     return 0;
86 }
87 
ApplyImagePatch(const PatchParam & param,size_t & startOffset)88 int32_t CompressedImagePatch::ApplyImagePatch(const PatchParam &param, size_t &startOffset)
89 {
90     size_t offset = startOffset;
91     // read header
92     PatchHeader header {};
93     int32_t ret = ReadHeader(param, header, offset);
94     PATCH_CHECK(ret == 0, return -1, "failed to read header");
95     PATCH_LOGI("ApplyImagePatch srcStart %zu srcLen %zu patchOffset: %zu expandedLen:%zu %zu",
96         header.srcStart, header.srcLength, header.patchOffset, header.expandedLen, header.targetSize);
97     PATCH_CHECK(header.srcStart + header.srcLength <= param.oldSize, return -1, "Failed to check patch");
98 
99     // decompress old data
100     Hpackage::PkgManager::StreamPtr stream = nullptr;
101     BlockBuffer oldData = { param.oldBuff + header.srcStart, header.srcLength };
102     ret = DecompressData(oldData, stream, true, header.expandedLen);
103     PATCH_CHECK(ret == 0, return -1, "Failed to decompress data");
104 
105     // prepare new data
106     std::unique_ptr<Hpackage::FileInfo> info = GetFileInfo();
107     PATCH_CHECK(info != nullptr, return -1, "Failed to get file info");
108     info->packedSize = header.targetSize;
109     info->unpackedSize = header.expandedLen;
110     std::unique_ptr<CompressedFileRestore> zipWriter = std::make_unique<CompressedFileRestore>(info.get(), writer_);
111     PATCH_CHECK(zipWriter != nullptr, return -1, "Failed to create zip writer");
112     PATCH_CHECK(zipWriter->Init() == 0, return -1, "Failed to create zip writer");
113 
114     // apply patch
115     PatchBuffer patchInfo = {param.patch, header.patchOffset, param.patchSize};
116     ret = UpdateApplyPatch::ApplyBlockPatch(patchInfo, stream, zipWriter.get());
117     PATCH_CHECK(ret == 0, return -1, "Failed to apply bsdiff patch");
118 
119     // compress new data
120     size_t originalSize = 0;
121     size_t compressSize = 0;
122     zipWriter->CompressData(originalSize, compressSize);
123     PATCH_LOGI("ApplyImagePatch unpackedSize %zu %zu", originalSize, compressSize);
124     PATCH_CHECK(originalSize == header.targetSize, return -1, "Failed to apply bsdiff patch");
125     startOffset = offset;
126     return 0;
127 }
128 
DecompressData(PkgBuffer buffer,Hpackage::PkgManager::StreamPtr & stream,bool memory,size_t expandedLen) const129 int32_t CompressedImagePatch::DecompressData(PkgBuffer buffer,
130     Hpackage::PkgManager::StreamPtr &stream, bool memory, size_t expandedLen) const
131 {
132     PATCH_CHECK(expandedLen > 0, return 0, "Decompress data is null");
133     int32_t ret = 0;
134     PkgManager* pkgManager = Hpackage::PkgManager::GetPackageInstance();
135     PATCH_CHECK(pkgManager != nullptr, return -1, "Failed to get pkg manager");
136 
137     std::unique_ptr<Hpackage::FileInfo> info = GetFileInfo();
138     PATCH_CHECK(info != nullptr, return -1, "Failed to get file info");
139 
140     info->packedSize = buffer.length;
141     info->unpackedSize = expandedLen;
142     info->identity = std::to_string(g_tmpFileId++);
143 
144     // 申请内存stream,用于解压老文件
145     ret = pkgManager->CreatePkgStream(stream, info->identity,
146         expandedLen, memory ? PkgStream::PkgStreamType_MemoryMap : PkgStream::PkgStreamType_Write);
147     PATCH_CHECK(stream != nullptr, return -1, "Failed to create stream");
148 
149     ret = pkgManager->DecompressBuffer(info.get(), buffer, stream);
150     PATCH_CHECK(ret == 0, pkgManager->ClosePkgStream(stream); return -1, "Can not decompress buff");
151 
152     if (bonusData_.size() == 0) {
153         return 0;
154     }
155     PATCH_CHECK(info->unpackedSize <= (expandedLen - bonusData_.size()), return -1, "Source inflation short");
156     if (memory) { // not support for none memory
157         PkgBuffer memBuffer;
158         ret = stream->GetBuffer(memBuffer);
159         PATCH_CHECK(ret == 0, pkgManager->ClosePkgStream(stream); return -1, "Can not get memory buff");
160         ret = memcpy_s(memBuffer.buffer + info->unpackedSize,
161             expandedLen - info->unpackedSize, bonusData_.data(), bonusData_.size());
162     }
163     return ret;
164 }
165 
ReadHeader(const PatchParam & param,PatchHeader & header,size_t & offset)166 int32_t ZipImagePatch::ReadHeader(const PatchParam &param, PatchHeader &header, size_t &offset)
167 {
168     if (offset + PATCH_DEFLATE_MIN_HEADER_LEN > param.patchSize) {
169         PATCH_LOGE("Failed to check datalen");
170         return -1;
171     }
172     header.srcStart = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
173     offset += sizeof(uint64_t);
174     header.srcLength = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
175     offset += sizeof(uint64_t);
176     header.patchOffset = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
177     offset += sizeof(uint64_t);
178     header.expandedLen = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
179     offset += sizeof(uint64_t);
180     header.targetSize = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
181     offset += sizeof(uint64_t);
182 
183     level_ = ReadLE<int32_t>(param.patch + offset);
184     offset += sizeof(int32_t);
185     method_ = ReadLE<int32_t>(param.patch + offset);
186     offset += sizeof(int32_t);
187     windowBits_ = ReadLE<int32_t>(param.patch + offset);
188     offset += sizeof(int32_t);
189     memLevel_ = ReadLE<int32_t>(param.patch + offset);
190     offset += sizeof(int32_t);
191     strategy_ = ReadLE<int32_t>(param.patch + offset);
192     offset += sizeof(int32_t);
193 
194     PATCH_LOGI("ZipImagePatch::ReadHeader level_:%d method_:%d windowBits_:%d memLevel_:%d strategy_:%d",
195         level_, method_, windowBits_, memLevel_, strategy_);
196     return 0;
197 }
198 
GetFileInfo() const199 std::unique_ptr<Hpackage::FileInfo> ZipImagePatch::GetFileInfo() const
200 {
201     Hpackage::ZipFileInfo *fileInfo = new(std::nothrow) ZipFileInfo;
202     if (fileInfo == nullptr) {
203         PATCH_LOGE("Failed to new file info");
204         return nullptr;
205     }
206     fileInfo->fileInfo.packMethod = PKG_COMPRESS_METHOD_ZIP;
207     fileInfo->fileInfo.digestMethod = PKG_DIGEST_TYPE_NONE;
208     fileInfo->fileInfo.packedSize = 0;
209     fileInfo->fileInfo.unpackedSize = 0;
210     fileInfo->fileInfo.identity = std::to_string(g_tmpFileId++);
211     fileInfo->level = level_;
212     fileInfo->method = method_;
213     fileInfo->windowBits = windowBits_;
214     fileInfo->memLevel = memLevel_;
215     fileInfo->strategy = strategy_;
216     return std::unique_ptr<Hpackage::FileInfo>((FileInfo *)fileInfo);
217 }
218 
ReadHeader(const PatchParam & param,PatchHeader & header,size_t & offset)219 int32_t Lz4ImagePatch::ReadHeader(const PatchParam &param, PatchHeader &header, size_t &offset)
220 {
221     if (offset + PATCH_LZ4_MIN_HEADER_LEN > param.patchSize) {
222         PATCH_LOGE("Failed to check datalen");
223         return -1;
224     }
225     header.srcStart = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
226     offset += sizeof(uint64_t);
227     header.srcLength = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
228     offset += sizeof(uint64_t);
229     header.patchOffset = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
230     offset += sizeof(uint64_t);
231     header.expandedLen = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
232     offset += sizeof(uint64_t);
233     header.targetSize = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
234     offset += sizeof(uint64_t);
235 
236     compressionLevel_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
237     offset += sizeof(int32_t);
238     method_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
239     offset += sizeof(int32_t);
240     blockIndependence_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
241     offset += sizeof(int32_t);
242     contentChecksumFlag_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
243     offset += sizeof(int32_t);
244     blockSizeID_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
245     offset += sizeof(int32_t);
246     autoFlush_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
247     offset += sizeof(int32_t);
248     PATCH_LOGI("ReadHeader BLOCK_LZ4 level_:%d method_:%d %d contentChecksumFlag_:%d blockSizeID_:%d %d",
249         compressionLevel_, method_, blockIndependence_, contentChecksumFlag_, blockSizeID_, autoFlush_);
250     return 0;
251 }
252 
GetFileInfo() const253 std::unique_ptr<Hpackage::FileInfo> Lz4ImagePatch::GetFileInfo() const
254 {
255     Hpackage::Lz4FileInfo *fileInfo = new(std::nothrow) Lz4FileInfo;
256     if (fileInfo == nullptr) {
257         PATCH_LOGE("Failed to new file info");
258         return nullptr;
259     }
260     fileInfo->fileInfo.packMethod = (method_ == LZ4B_MAGIC) ? PKG_COMPRESS_METHOD_LZ4_BLOCK : PKG_COMPRESS_METHOD_LZ4;
261     fileInfo->fileInfo.digestMethod = PKG_DIGEST_TYPE_NONE;
262     fileInfo->fileInfo.packedSize = 0;
263     fileInfo->fileInfo.unpackedSize = 0;
264     fileInfo->fileInfo.identity = std::to_string(g_tmpFileId++);
265     fileInfo->compressionLevel = static_cast<int8_t>(compressionLevel_);
266     fileInfo->blockIndependence = static_cast<int8_t>(blockIndependence_);
267     fileInfo->contentChecksumFlag = static_cast<int8_t>(contentChecksumFlag_);
268     fileInfo->blockSizeID = static_cast<int8_t>(blockSizeID_);
269     fileInfo->autoFlush = static_cast<int8_t>(autoFlush_);
270     return std::unique_ptr<Hpackage::FileInfo>((FileInfo *)fileInfo);
271 }
272 
Init()273 int32_t CompressedFileRestore::Init()
274 {
275     SHA256_Init(&sha256Ctx_);
276     if (fileInfo_->packMethod == PKG_COMPRESS_METHOD_ZIP) {
277         deflateAdapter_.reset(new ZipAdapter(writer_, 0, fileInfo_));
278     } else if (fileInfo_->packMethod == PKG_COMPRESS_METHOD_LZ4) {
279         deflateAdapter_.reset(new Lz4FrameAdapter(writer_, 0, fileInfo_));
280     } else if (fileInfo_->packMethod == PKG_COMPRESS_METHOD_LZ4_BLOCK) {
281         deflateAdapter_.reset(new Lz4BlockAdapter(writer_, 0, fileInfo_));
282     }
283     if (deflateAdapter_ == nullptr) {
284         PATCH_LOGE("Failed to create zip adapter");
285         return -1;
286     }
287     return deflateAdapter_->Open();
288 }
289 
Write(size_t start,const BlockBuffer & buffer,size_t size)290 int32_t CompressedFileRestore::Write(size_t start, const BlockBuffer &buffer, size_t size)
291 {
292     if (size == 0) {
293         return 0;
294     }
295     dataSize_ += size;
296     SHA256_Update(&sha256Ctx_, buffer.buffer, size);
297     BlockBuffer data = { buffer.buffer, size };
298     return deflateAdapter_->WriteData(data);
299 }
300 
CompressData(size_t & originalSize,size_t & compressSize)301 int32_t CompressedFileRestore::CompressData(size_t &originalSize, size_t &compressSize)
302 {
303     int32_t ret = deflateAdapter_->FlushData(compressSize);
304     if (ret != 0) {
305         PATCH_LOGE("Failed to flush data");
306         return -1;
307     }
308     originalSize = dataSize_;
309 
310     std::vector<uint8_t> digest(SHA256_DIGEST_LENGTH);
311     SHA256_Final(digest.data(), &sha256Ctx_);
312     BlockBuffer buffer = { digest.data(), digest.size() };
313     std::string hexDigest = ConvertSha256Hex(buffer);
314     PATCH_LOGI("CompressedFileRestore hash %zu %s ", dataSize_, hexDigest.c_str());
315     return 0;
316 }
317 } // namespace UpdatePatch
318