• 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     if (srcStart + srcLen > param.oldSize) {
46         PATCH_LOGE("error, srcStart: %zu srcLen: %zu , param.oldSize: %zu, patchOffset: %zu",
47             srcStart, srcLen, param.oldSize, patchOffset);
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 
StartReadHeader(const PatchParam & param,PatchHeader & header,size_t & offset)88 int32_t CompressedImagePatch::StartReadHeader(const PatchParam &param, PatchHeader &header, size_t &offset)
89 {
90     int32_t ret = ReadHeader(param, header, offset);
91     if (ret != 0) {
92         PATCH_LOGE("Failed to read header");
93         return -1;
94     }
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     if (header.srcStart + header.srcLength > param.oldSize) {
98         PATCH_LOGE("Failed to check patch");
99         return -1;
100     }
101     return 0;
102 }
103 
ApplyImagePatch(const PatchParam & param,size_t & startOffset)104 int32_t CompressedImagePatch::ApplyImagePatch(const PatchParam &param, size_t &startOffset)
105 {
106     size_t offset = startOffset;
107     // read header
108     PatchHeader header {};
109     if (StartReadHeader(param, header, offset) != 0) {
110         return -1;
111     }
112     // decompress old data
113     Hpackage::PkgManager::PkgManagerPtr pkgManager = Hpackage::PkgManager::CreatePackageInstance();
114     Hpackage::PkgManager::StreamPtr stream = nullptr;
115     BlockBuffer oldData = { param.oldBuff + header.srcStart, header.srcLength };
116     if (DecompressData(pkgManager, oldData, stream, true, header.expandedLen) != 0) {
117         PATCH_LOGE("Failed to decompress data");
118         Hpackage::PkgManager::ReleasePackageInstance(pkgManager);
119         return -1;
120     }
121     // prepare new data
122     std::unique_ptr<Hpackage::FileInfo> info = GetFileInfo();
123     if (info == nullptr) {
124         PATCH_LOGE("Failed to get file info");
125         Hpackage::PkgManager::ReleasePackageInstance(pkgManager);
126         return -1;
127     }
128     info->packedSize = header.targetSize;
129     info->unpackedSize = header.expandedLen;
130     std::unique_ptr<CompressedFileRestore> zipWriter = std::make_unique<CompressedFileRestore>(info.get(), writer_);
131     if (zipWriter == nullptr || zipWriter->Init() != 0) {
132         PATCH_LOGE("Failed to create zip writer");
133         Hpackage::PkgManager::ReleasePackageInstance(pkgManager);
134         return -1;
135     }
136     // apply patch
137     PatchBuffer patchInfo = {param.patch, header.patchOffset, param.patchSize};
138     if (UpdateApplyPatch::ApplyBlockPatch(patchInfo, stream, zipWriter.get()) != 0) {
139         PATCH_LOGE("Failed to apply bsdiff patch");
140         Hpackage::PkgManager::ReleasePackageInstance(pkgManager);
141         return -1;
142     }
143     // compress new data
144     size_t originalSize = 0;
145     size_t compressSize = 0;
146     zipWriter->CompressData(originalSize, compressSize);
147     PATCH_LOGI("ApplyImagePatch unpackedSize %zu %zu", originalSize, compressSize);
148     if (originalSize != header.targetSize) {
149         PATCH_LOGE("Failed to apply bsdiff patch");
150         Hpackage::PkgManager::ReleasePackageInstance(pkgManager);
151         return -1;
152     }
153     startOffset = offset;
154     Hpackage::PkgManager::ReleasePackageInstance(pkgManager);
155     return 0;
156 }
157 
DecompressData(Hpackage::PkgManager::PkgManagerPtr & pkgManager,PkgBuffer buffer,Hpackage::PkgManager::StreamPtr & stream,bool memory,size_t expandedLen) const158 int32_t CompressedImagePatch::DecompressData(Hpackage::PkgManager::PkgManagerPtr &pkgManager, PkgBuffer buffer,
159     Hpackage::PkgManager::StreamPtr &stream, bool memory, size_t expandedLen) const
160 {
161     if (expandedLen == 0) {
162         PATCH_LOGE("Decompress data is null");
163         return 0;
164     }
165     std::unique_ptr<Hpackage::FileInfo> info = GetFileInfo();
166     if (pkgManager == nullptr || info == nullptr) {
167         PATCH_LOGE("Failed to get pkg manager or file info");
168         return -1;
169     }
170 
171     info->packedSize = buffer.length;
172     info->unpackedSize = expandedLen;
173     info->identity = std::to_string(g_tmpFileId++);
174 
175     // 申请内存stream,用于解压老文件
176     int32_t ret = pkgManager->CreatePkgStream(stream, info->identity,
177         expandedLen, memory ? PkgStream::PkgStreamType_MemoryMap : PkgStream::PkgStreamType_Write);
178     if (stream == nullptr) {
179         PATCH_LOGE("Failed to create stream");
180         return -1;
181     }
182 
183     ret = pkgManager->DecompressBuffer(info.get(), buffer, stream);
184     if (ret != 0) {
185         pkgManager->ClosePkgStream(stream);
186         PATCH_LOGE("Can not decompress buff");
187         return -1;
188     }
189 
190     if (bonusData_.size() == 0) {
191         return 0;
192     }
193     if (info->unpackedSize > (expandedLen - bonusData_.size())) {
194         PATCH_LOGE("Source inflation short");
195         return -1;
196     }
197     if (memory) { // not support for none memory
198         PkgBuffer memBuffer;
199         if (stream->GetBuffer(memBuffer) != 0) {
200             pkgManager->ClosePkgStream(stream);
201             PATCH_LOGE("Can not get memory buff");
202             return -1;
203         }
204         ret = memcpy_s(memBuffer.buffer + info->unpackedSize,
205             expandedLen - info->unpackedSize, bonusData_.data(), bonusData_.size());
206     }
207     return ret;
208 }
209 
ReadHeader(const PatchParam & param,PatchHeader & header,size_t & offset)210 int32_t ZipImagePatch::ReadHeader(const PatchParam &param, PatchHeader &header, size_t &offset)
211 {
212     if (offset + PATCH_DEFLATE_MIN_HEADER_LEN > param.patchSize) {
213         PATCH_LOGE("Failed to check datalen");
214         return -1;
215     }
216     header.srcStart = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
217     offset += sizeof(uint64_t);
218     header.srcLength = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
219     offset += sizeof(uint64_t);
220     header.patchOffset = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
221     offset += sizeof(uint64_t);
222     header.expandedLen = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
223     offset += sizeof(uint64_t);
224     header.targetSize = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
225     offset += sizeof(uint64_t);
226 
227     level_ = ReadLE<int32_t>(param.patch + offset);
228     offset += sizeof(int32_t);
229     method_ = ReadLE<int32_t>(param.patch + offset);
230     offset += sizeof(int32_t);
231     windowBits_ = ReadLE<int32_t>(param.patch + offset);
232     offset += sizeof(int32_t);
233     memLevel_ = ReadLE<int32_t>(param.patch + offset);
234     offset += sizeof(int32_t);
235     strategy_ = ReadLE<int32_t>(param.patch + offset);
236     offset += sizeof(int32_t);
237 
238     PATCH_LOGI("ZipImagePatch::ReadHeader level_:%d method_:%d windowBits_:%d memLevel_:%d strategy_:%d",
239         level_, method_, windowBits_, memLevel_, strategy_);
240     return 0;
241 }
242 
GetFileInfo() const243 std::unique_ptr<Hpackage::FileInfo> ZipImagePatch::GetFileInfo() const
244 {
245     Hpackage::ZipFileInfo *fileInfo = new(std::nothrow) ZipFileInfo;
246     if (fileInfo == nullptr) {
247         PATCH_LOGE("Failed to new file info");
248         return nullptr;
249     }
250     fileInfo->fileInfo.packMethod = PKG_COMPRESS_METHOD_ZIP;
251     fileInfo->fileInfo.digestMethod = PKG_DIGEST_TYPE_NONE;
252     fileInfo->fileInfo.packedSize = 0;
253     fileInfo->fileInfo.unpackedSize = 0;
254     fileInfo->fileInfo.identity = std::to_string(g_tmpFileId++);
255     fileInfo->level = level_;
256     fileInfo->method = method_;
257     fileInfo->windowBits = windowBits_;
258     fileInfo->memLevel = memLevel_;
259     fileInfo->strategy = strategy_;
260     return std::unique_ptr<Hpackage::FileInfo>((FileInfo *)fileInfo);
261 }
262 
ReadHeader(const PatchParam & param,PatchHeader & header,size_t & offset)263 int32_t Lz4ImagePatch::ReadHeader(const PatchParam &param, PatchHeader &header, size_t &offset)
264 {
265     if (offset + PATCH_LZ4_MIN_HEADER_LEN > param.patchSize) {
266         PATCH_LOGE("Failed to check datalen");
267         return -1;
268     }
269     header.srcStart = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
270     offset += sizeof(uint64_t);
271     header.srcLength = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
272     offset += sizeof(uint64_t);
273     header.patchOffset = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
274     offset += sizeof(uint64_t);
275     header.expandedLen = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
276     offset += sizeof(uint64_t);
277     header.targetSize = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
278     offset += sizeof(uint64_t);
279 
280     compressionLevel_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
281     offset += sizeof(int32_t);
282     method_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
283     offset += sizeof(int32_t);
284     blockIndependence_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
285     offset += sizeof(int32_t);
286     contentChecksumFlag_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
287     offset += sizeof(int32_t);
288     blockSizeID_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
289     offset += sizeof(int32_t);
290     autoFlush_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
291     offset += sizeof(int32_t);
292     PATCH_LOGI("ReadHeader BLOCK_LZ4 level_:%d method_:%d %d contentChecksumFlag_:%d blockSizeID_:%d %d",
293         compressionLevel_, method_, blockIndependence_, contentChecksumFlag_, blockSizeID_, autoFlush_);
294     return 0;
295 }
296 
GetFileInfo() const297 std::unique_ptr<Hpackage::FileInfo> Lz4ImagePatch::GetFileInfo() const
298 {
299     Hpackage::Lz4FileInfo *fileInfo = new(std::nothrow) Lz4FileInfo;
300     if (fileInfo == nullptr) {
301         PATCH_LOGE("Failed to new file info");
302         return nullptr;
303     }
304     fileInfo->fileInfo.packMethod = (method_ == LZ4B_MAGIC) ? PKG_COMPRESS_METHOD_LZ4_BLOCK : PKG_COMPRESS_METHOD_LZ4;
305     fileInfo->fileInfo.digestMethod = PKG_DIGEST_TYPE_NONE;
306     fileInfo->fileInfo.packedSize = 0;
307     fileInfo->fileInfo.unpackedSize = 0;
308     fileInfo->fileInfo.identity = std::to_string(g_tmpFileId++);
309     fileInfo->compressionLevel = static_cast<int8_t>(compressionLevel_);
310     fileInfo->blockIndependence = static_cast<int8_t>(blockIndependence_);
311     fileInfo->contentChecksumFlag = static_cast<int8_t>(contentChecksumFlag_);
312     fileInfo->blockSizeID = static_cast<int8_t>(blockSizeID_);
313     fileInfo->autoFlush = static_cast<int8_t>(autoFlush_);
314     return std::unique_ptr<Hpackage::FileInfo>((FileInfo *)fileInfo);
315 }
316 
Init()317 int32_t CompressedFileRestore::Init()
318 {
319     SHA256_Init(&sha256Ctx_);
320     if (fileInfo_->packMethod == PKG_COMPRESS_METHOD_ZIP) {
321         deflateAdapter_.reset(new ZipAdapter(writer_, 0, fileInfo_));
322     } else if (fileInfo_->packMethod == PKG_COMPRESS_METHOD_LZ4) {
323         deflateAdapter_.reset(new Lz4FrameAdapter(writer_, 0, fileInfo_));
324     } else if (fileInfo_->packMethod == PKG_COMPRESS_METHOD_LZ4_BLOCK) {
325         deflateAdapter_.reset(new Lz4BlockAdapter(writer_, 0, fileInfo_));
326     }
327     if (deflateAdapter_ == nullptr) {
328         PATCH_LOGE("Failed to create zip adapter");
329         return -1;
330     }
331     return deflateAdapter_->Open();
332 }
333 
Write(size_t start,const BlockBuffer & buffer,size_t size)334 int32_t CompressedFileRestore::Write(size_t start, const BlockBuffer &buffer, size_t size)
335 {
336     if (size == 0) {
337         return 0;
338     }
339     dataSize_ += size;
340     SHA256_Update(&sha256Ctx_, buffer.buffer, size);
341     BlockBuffer data = { buffer.buffer, size };
342     return deflateAdapter_->WriteData(data);
343 }
344 
CompressData(size_t & originalSize,size_t & compressSize)345 int32_t CompressedFileRestore::CompressData(size_t &originalSize, size_t &compressSize)
346 {
347     int32_t ret = deflateAdapter_->FlushData(compressSize);
348     if (ret != 0) {
349         PATCH_LOGE("Failed to flush data");
350         return -1;
351     }
352     originalSize = dataSize_;
353 
354     std::vector<uint8_t> digest(SHA256_DIGEST_LENGTH);
355     SHA256_Final(digest.data(), &sha256Ctx_);
356     BlockBuffer buffer = { digest.data(), digest.size() };
357     std::string hexDigest = ConvertSha256Hex(buffer);
358     PATCH_LOGI("CompressedFileRestore hash %zu %s ", dataSize_, hexDigest.c_str());
359     return 0;
360 }
361 } // namespace UpdatePatch
362