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 "update_diff.h"
17 #include <cstdlib>
18 #include <memory>
19 #include "image_diff.h"
20 #include "pkg_manager.h"
21
22 using namespace Hpackage;
23
24 namespace UpdatePatch {
25 #ifdef __WIN32
26 #undef ERROR
27 #endif
28
~ImageParser()29 ImageParser::~ImageParser()
30 {
31 Hpackage::PkgManager::ReleasePackageInstance(pkgManager_);
32 pkgManager_ = nullptr;
33 }
34
GetPkgBuffer(BlockBuffer & buffer) const35 int32_t ImageParser::GetPkgBuffer(BlockBuffer &buffer) const
36 {
37 int32_t ret = -1;
38 Hpackage::PkgBuffer pkgBuffer {};
39 if (stream_ != nullptr) {
40 ret = stream_->GetBuffer(pkgBuffer);
41 buffer.buffer = pkgBuffer.buffer;
42 buffer.length = pkgBuffer.length;
43 }
44 return ret;
45 }
46
GetFileInfo(const std::string & fileName) const47 const Hpackage::FileInfo *ImageParser::GetFileInfo(const std::string &fileName) const
48 {
49 if (pkgManager_ != nullptr) {
50 return pkgManager_->GetFileInfo(fileName);
51 }
52 return nullptr;
53 }
54
Parse(const std::string & packageName)55 int32_t ImageParser::Parse(const std::string &packageName)
56 {
57 pkgManager_ = Hpackage::PkgManager::CreatePackageInstance();
58 if (pkgManager_ == nullptr) {
59 PATCH_LOGE("Failed to get pkg manager");
60 return PATCH_INVALID_PARAM;
61 }
62 int32_t ret = PatchMapFile(packageName, memMap_);
63 if (ret != 0) {
64 PATCH_LOGE("Failed to read file");
65 return -1;
66 }
67
68 PkgBuffer buffer {memMap_.memory, memMap_.length};
69 ret = pkgManager_->CreatePkgStream(stream_, packageName, buffer);
70 if (ret != 0) {
71 PATCH_LOGE("Failed to create pkg stream");
72 return -1;
73 }
74
75 // parse img and get image type
76 type_ = PKG_PACK_TYPE_ZIP;
77 ret = pkgManager_->ParsePackage(stream_, fileIds_, type_);
78 if (ret == 0) {
79 return 0;
80 }
81 type_ = PKG_PACK_TYPE_LZ4;
82 ret = pkgManager_->ParsePackage(stream_, fileIds_, type_);
83 if (ret == 0) {
84 return 0;
85 }
86 type_ = PKG_PACK_TYPE_GZIP;
87 ret = pkgManager_->ParsePackage(stream_, fileIds_, type_);
88 if (ret == 0) {
89 return 0;
90 }
91 type_ = PKG_PACK_TYPE_NONE;
92 return 0;
93 }
94
Extract(const std::string & fileName,std::vector<uint8_t> & buffer)95 int32_t ImageParser::Extract(const std::string &fileName, std::vector<uint8_t> &buffer)
96 {
97 PATCH_DEBUG("ImageParser::Extract %s", fileName.c_str());
98 if (pkgManager_ == nullptr) {
99 PATCH_LOGE("Failed to get pkg manager");
100 return PATCH_INVALID_PARAM;
101 }
102 size_t bufferSize = 0;
103 Hpackage::PkgManager::StreamPtr outStream = nullptr;
104 int32_t ret = pkgManager_->CreatePkgStream(outStream, fileName,
105 [&buffer, &bufferSize](const PkgBuffer &data, size_t size,
106 size_t start, bool isFinish, const void *context) ->int {
107 if (isFinish) {
108 return 0;
109 }
110 bufferSize += size;
111 if ((start + bufferSize) > buffer.size()) {
112 buffer.resize(IGMDIFF_LIMIT_UNIT * ((start + bufferSize) / IGMDIFF_LIMIT_UNIT + 1));
113 }
114 return memcpy_s(buffer.data() + start, buffer.size(), data.buffer, size);
115 }, nullptr);
116 if (ret != 0) {
117 PATCH_LOGE("Failed to extract data");
118 return -1;
119 }
120
121 ret = pkgManager_->ExtractFile(fileName, outStream);
122 pkgManager_->ClosePkgStream(outStream);
123
124 const FileInfo *fileInfo = pkgManager_->GetFileInfo(fileName);
125 if (fileInfo == nullptr) {
126 PATCH_LOGE("Failed to get file info");
127 return -1;
128 }
129 if (fileInfo->unpackedSize != bufferSize) {
130 PATCH_LOGE("Failed to check uncompress data size %zu %zu", fileInfo->unpackedSize, bufferSize);
131 return -1;
132 }
133 return ret;
134 }
135
MakePatch(const std::string & oldFileName,const std::string & newFileName,const std::string & patchFileName)136 int32_t UpdateDiff::MakePatch(const std::string &oldFileName,
137 const std::string &newFileName, const std::string &patchFileName)
138 {
139 if (blockDiff_) {
140 return BlocksDiff::MakePatch(oldFileName, newFileName, patchFileName);
141 }
142
143 newParser_.reset(new ImageParser());
144 oldParser_.reset(new ImageParser());
145 if (newParser_ == nullptr || oldParser_ == nullptr) {
146 PATCH_LOGE("Failed to create parser");
147 return -1;
148 }
149
150 if (newParser_->Parse(newFileName) != 0 || oldParser_->Parse(oldFileName) != 0) {
151 PATCH_LOGE("Failed to parse image");
152 return -1;
153 }
154 std::unique_ptr<ImageDiff> imageDiff = nullptr;
155 PATCH_DEBUG("UpdateDiff::MakePatch type: %d %d", newParser_->GetType(), oldParser_->GetType());
156 if (newParser_->GetType() != oldParser_->GetType()) {
157 imageDiff.reset(new ImageDiff(limit_, newParser_.get(), oldParser_.get()));
158 if (imageDiff == nullptr) {
159 PATCH_LOGE("Failed to diff file");
160 return -1;
161 }
162 return imageDiff->MakePatch(patchFileName);
163 }
164
165 switch (newParser_->GetType()) {
166 case PKG_PACK_TYPE_ZIP:
167 imageDiff.reset(new ZipImageDiff(limit_, newParser_.get(), oldParser_.get()));
168 break;
169 case PKG_PACK_TYPE_LZ4:
170 imageDiff.reset(new Lz4ImageDiff(limit_, newParser_.get(), oldParser_.get()));
171 break;
172 case PKG_PACK_TYPE_GZIP:
173 imageDiff.reset(new GZipImageDiff(limit_, newParser_.get(), oldParser_.get()));
174 break;
175 default:
176 imageDiff.reset(new ImageDiff(limit_, newParser_.get(), oldParser_.get()));
177 break;
178 }
179 if (imageDiff == nullptr) {
180 PATCH_LOGE("Failed to diff file");
181 return -1;
182 }
183 return imageDiff->MakePatch(patchFileName);
184 }
185
DiffImage(size_t limit,const std::string & oldFileName,const std::string & newFileName,const std::string & patchFileName)186 int32_t UpdateDiff::DiffImage(size_t limit, const std::string &oldFileName,
187 const std::string &newFileName, const std::string &patchFileName)
188 {
189 auto updateDiff = std::make_unique<UpdateDiff>(limit, false);
190 if (updateDiff == nullptr) {
191 PATCH_LOGE("Failed to create update diff");
192 return -1;
193 }
194 return updateDiff->MakePatch(oldFileName, newFileName, patchFileName);
195 }
196
DiffBlock(const std::string & oldFileName,const std::string & newFileName,const std::string & patchFileName)197 int32_t UpdateDiff::DiffBlock(const std::string &oldFileName,
198 const std::string &newFileName, const std::string &patchFileName)
199 {
200 auto updateDiff = std::make_unique<UpdateDiff>(0, true);
201 if (updateDiff == nullptr) {
202 PATCH_LOGE("Failed to create update diff");
203 return -1;
204 }
205 return updateDiff->MakePatch(oldFileName, newFileName, patchFileName);
206 }
207 } // namespace UpdatePatch
208