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 #include "pkg_algo_deflate.h"
16 #include <unistd.h>
17 #include "pkg_stream.h"
18 #include "pkg_utils.h"
19 #include "securec.h"
20 #include "zlib.h"
21
22 namespace Hpackage {
23 constexpr uint32_t DEFLATE_IN_BUFFER_SIZE = 1024 * 64;
24 constexpr uint32_t DEFLATE_OUT_BUFFER_SIZE = 1024 * 32;
25 constexpr uint32_t INFLATE_IN_BUFFER_SIZE = 100 * 1024 * 1024;
26 constexpr uint32_t INFLATE_OUT_BUFFER_SIZE = 1024 * 1024;
27 constexpr uint32_t INFLATE_IN_BUFFER_SIZE_NORMAL_MODE = 10 * 1024 * 1024;
28
DeflateData(const PkgStreamPtr outStream,z_stream & zstream,int32_t flush,PkgBuffer & outBuffer,size_t & destOffset) const29 int32_t PkgAlgoDeflate::DeflateData(const PkgStreamPtr outStream, z_stream &zstream, int32_t flush,
30 PkgBuffer &outBuffer, size_t &destOffset) const
31 {
32 int32_t ret = Z_OK;
33 do {
34 size_t deflateLen = 0;
35 ret = deflate(&zstream, flush);
36 if (ret < Z_OK) {
37 PKG_LOGE("deflate finish error ret1 %d", ret);
38 return PKG_NOT_EXIST_ALGORITHM;
39 }
40 deflateLen += outBuffer.length - zstream.avail_out;
41 if (deflateLen > 0) {
42 int32_t ret1 = outStream->Write(outBuffer, deflateLen, destOffset);
43 if (ret1 != PKG_SUCCESS) {
44 PKG_LOGE("error write data deflateLen: %zu", deflateLen);
45 break;
46 }
47 destOffset += deflateLen;
48 zstream.next_out = outBuffer.buffer;
49 zstream.avail_out = outBuffer.length;
50 }
51 if (flush == Z_NO_FLUSH) {
52 break;
53 }
54 } while (ret == Z_OK && flush == Z_FINISH);
55 return PKG_SUCCESS;
56 }
57
PackCalculate(PkgAlgorithmContext & context,const PkgStreamPtr inStream,const PkgStreamPtr outStream,const DigestAlgorithm::DigestAlgorithmPtr algorithm)58 int32_t PkgAlgoDeflate::PackCalculate(PkgAlgorithmContext &context, const PkgStreamPtr inStream,
59 const PkgStreamPtr outStream, const DigestAlgorithm::DigestAlgorithmPtr algorithm)
60 {
61 PkgBuffer inBuffer = {};
62 PkgBuffer outBuffer = {};
63 z_stream zstream;
64 int32_t ret = InitStream(zstream, true, inBuffer, outBuffer);
65 if (ret != PKG_SUCCESS) {
66 PKG_LOGE("fail InitStream");
67 return ret;
68 }
69 size_t remainSize = context.unpackedSize;
70 uint32_t crc = 0;
71 size_t srcOffset = context.srcOffset;
72 size_t destOffset = context.destOffset;
73 PkgBuffer crcResult((uint8_t *)&crc, sizeof(crc));
74
75 while ((remainSize > 0) || (zstream.avail_in > 0)) {
76 size_t readLen = 0;
77 if (zstream.avail_in == 0) {
78 ret = ReadData(inStream, srcOffset, inBuffer, remainSize, readLen);
79 if (ret != PKG_SUCCESS) {
80 PKG_LOGE("Read data fail!");
81 break;
82 }
83 zstream.next_in = reinterpret_cast<unsigned char *>(inBuffer.buffer);
84 zstream.avail_in = readLen;
85 srcOffset += readLen;
86 // Calculate CRC of original file
87 algorithm->Calculate(crcResult, inBuffer, readLen);
88 }
89 ret = DeflateData(outStream, zstream, ((remainSize == 0) ? Z_FINISH : Z_NO_FLUSH), outBuffer, destOffset);
90 if (ret != PKG_SUCCESS) {
91 PKG_LOGE("error write data deflateLen: %zu", destOffset);
92 break;
93 }
94 }
95 ReleaseStream(zstream, true);
96 if (ret != PKG_SUCCESS) {
97 PKG_LOGE("error write data");
98 return ret;
99 }
100 if (srcOffset != context.unpackedSize) {
101 PKG_LOGE("original size error %zu %zu", srcOffset, context.unpackedSize);
102 return PKG_INVALID_PKG_FORMAT;
103 }
104 context.crc = crc;
105 context.packedSize = destOffset - context.destOffset;
106 return ret;
107 }
108
Pack(const PkgStreamPtr inStream,const PkgStreamPtr outStream,PkgAlgorithmContext & context)109 int32_t PkgAlgoDeflate::Pack(const PkgStreamPtr inStream, const PkgStreamPtr outStream,
110 PkgAlgorithmContext &context)
111 {
112 if (inStream == nullptr || outStream == nullptr) {
113 PKG_LOGE("Param context null!");
114 return PKG_INVALID_PARAM;
115 }
116 DigestAlgorithm::DigestAlgorithmPtr algorithm = PkgAlgorithmFactory::GetDigestAlgorithm(context.digestMethod);
117 if (algorithm == nullptr) {
118 PKG_LOGE("Can not get digest algor");
119 return PKG_NOT_EXIST_ALGORITHM;
120 }
121 return PackCalculate(context, inStream, outStream, algorithm);
122 }
123
ReadUnpackData(const PkgStreamPtr inStream,PkgBuffer & inBuffer,z_stream & zstream,PkgAlgorithmContext & context,size_t & readLen)124 int32_t PkgAlgoDeflate::ReadUnpackData(const PkgStreamPtr inStream, PkgBuffer &inBuffer,
125 z_stream &zstream, PkgAlgorithmContext &context, size_t &readLen)
126 {
127 if (zstream.avail_in == 0) {
128 int32_t ret = ReadData(inStream, context.srcOffset, inBuffer, context.packedSize, readLen);
129 if (ret != PKG_SUCCESS) {
130 PKG_LOGE("Read data fail!");
131 return ret;
132 }
133 zstream.next_in = reinterpret_cast<uint8_t *>(inBuffer.buffer);
134 zstream.avail_in = readLen;
135 context.srcOffset += readLen;
136 }
137 return PKG_SUCCESS;
138 }
139
CalculateUnpackData(z_stream & zstream,uint32_t & crc,int32_t & ret,PkgAlgorithmContext & context,PkgAlgorithmContext & unpackContext)140 int32_t PkgAlgoDeflate::CalculateUnpackData(z_stream &zstream, uint32_t &crc, int32_t &ret,
141 PkgAlgorithmContext &context, PkgAlgorithmContext &unpackContext)
142 {
143 ReleaseStream(zstream, false);
144 context.packedSize = context.packedSize - zstream.avail_in - unpackContext.packedSize;
145 context.unpackedSize = unpackContext.destOffset - context.destOffset;
146 if (context.crc != 0 && context.crc != crc) {
147 PKG_LOGE("crc fail %u %u!", crc, context.crc);
148 return PKG_VERIFY_FAIL;
149 }
150 context.crc = crc;
151 return (ret == Z_STREAM_END) ? PKG_SUCCESS : ret;
152 }
153
UnpackCalculate(PkgAlgorithmContext & context,const PkgStreamPtr inStream,const PkgStreamPtr outStream,DigestAlgorithm::DigestAlgorithmPtr algorithm)154 int32_t PkgAlgoDeflate::UnpackCalculate(PkgAlgorithmContext &context, const PkgStreamPtr inStream,
155 const PkgStreamPtr outStream, DigestAlgorithm::DigestAlgorithmPtr algorithm)
156 {
157 z_stream zstream;
158 PkgBuffer inBuffer = {};
159 PkgBuffer outBuffer = {};
160 int32_t ret = InitStream(zstream, false, inBuffer, outBuffer);
161 if (ret != PKG_SUCCESS) {
162 PKG_LOGE("fail InitStream ");
163 return ret;
164 }
165 size_t inflateLen = 0;
166 uint32_t crc = 0;
167
168 PkgBuffer crcResult((uint8_t *)&crc, sizeof(crc));
169 PkgAlgorithmContext unpackContext = context;
170 size_t readLen = 0;
171 int32_t unpackRet = Z_OK;
172 while ((unpackContext.packedSize > 0) || (unpackRet != Z_STREAM_END)) {
173 if (ReadUnpackData(inStream, inBuffer, zstream, unpackContext, readLen) != PKG_SUCCESS) {
174 break;
175 }
176 unpackRet = inflate(&zstream, Z_SYNC_FLUSH);
177 if (unpackRet < Z_OK) {
178 PKG_LOGE("fail inflate ret:%d, error is %s", unpackRet,
179 (zstream.msg == nullptr ? "no error" : zstream.msg));
180 break;
181 }
182
183 if (zstream.avail_out == 0 || (unpackRet == Z_STREAM_END && zstream.avail_out != INFLATE_OUT_BUFFER_SIZE)) {
184 inflateLen = outBuffer.length - zstream.avail_out;
185 ret = outStream->Write(outBuffer, inflateLen, unpackContext.destOffset);
186 if (ret != PKG_SUCCESS) {
187 PKG_LOGE("write data is fail!");
188 break;
189 }
190 unpackContext.destOffset += inflateLen;
191 zstream.next_out = outBuffer.buffer;
192 zstream.avail_out = outBuffer.length;
193
194 algorithm->Calculate(crcResult, outBuffer, inflateLen);
195 }
196 }
197 return CalculateUnpackData(zstream, crc, unpackRet, context, unpackContext);
198 }
199
Unpack(const PkgStreamPtr inStream,const PkgStreamPtr outStream,PkgAlgorithmContext & context)200 int32_t PkgAlgoDeflate::Unpack(const PkgStreamPtr inStream, const PkgStreamPtr outStream,
201 PkgAlgorithmContext &context)
202 {
203 DigestAlgorithm::DigestAlgorithmPtr algorithm = PkgAlgorithmFactory::GetDigestAlgorithm(context.digestMethod);
204 if (algorithm == nullptr) {
205 PKG_LOGE("Can not get digest algor");
206 return PKG_NOT_EXIST_ALGORITHM;
207 }
208 if (inStream == nullptr || outStream == nullptr) {
209 PKG_LOGE("Param context null!");
210 return PKG_INVALID_PARAM;
211 }
212
213 return UnpackCalculate(context, inStream, outStream, algorithm);
214 }
215
InitStream(z_stream & zstream,bool zip,PkgBuffer & inBuffer,PkgBuffer & outBuffer)216 int32_t PkgAlgoDeflate::InitStream(z_stream &zstream, bool zip, PkgBuffer &inBuffer, PkgBuffer &outBuffer)
217 {
218 int32_t ret = PKG_SUCCESS;
219 // init zlib stream
220 if (memset_s(&zstream, sizeof(z_stream), 0, sizeof(z_stream)) != EOK) {
221 PKG_LOGE("memset fail");
222 return PKG_NONE_MEMORY;
223 }
224 if (zip) {
225 PKG_LOGI("InitStream level_:%d method_:%d windowBits_:%d memLevel_:%d strategy_:%d",
226 level_, method_, windowBits_, memLevel_, strategy_);
227 ret = deflateInit2(&zstream, level_, method_, windowBits_, memLevel_, strategy_);
228 if (ret != Z_OK) {
229 PKG_LOGE("fail deflateInit2 ret %d", ret);
230 return PKG_NOT_EXIST_ALGORITHM;
231 }
232 inBuffer.length = DEFLATE_IN_BUFFER_SIZE;
233 outBuffer.length = DEFLATE_OUT_BUFFER_SIZE;
234 } else {
235 ret = inflateInit2(&zstream, windowBits_);
236 if (ret != Z_OK) {
237 PKG_LOGE("fail deflateInit2");
238 return PKG_NOT_EXIST_ALGORITHM;
239 }
240 inBuffer.length = (access("/bin/updater", 0) == 0) ?
241 INFLATE_IN_BUFFER_SIZE : INFLATE_IN_BUFFER_SIZE_NORMAL_MODE;
242 outBuffer.length = INFLATE_OUT_BUFFER_SIZE;
243 }
244
245 outBuffer.data.resize(outBuffer.length);
246 outBuffer.buffer = reinterpret_cast<uint8_t *>(outBuffer.data.data());
247 zstream.next_out = outBuffer.buffer;
248 zstream.avail_out = outBuffer.length;
249 return PKG_SUCCESS;
250 }
251
ReleaseStream(z_stream & zstream,bool zip) const252 void PkgAlgoDeflate::ReleaseStream(z_stream &zstream, bool zip) const
253 {
254 int32_t ret = Z_OK;
255 if (zip) {
256 ret = deflateEnd(&zstream);
257 if (ret != Z_OK) {
258 PKG_LOGE("fail deflateEnd %d", ret);
259 return;
260 }
261 } else {
262 ret = inflateEnd(&zstream);
263 if (ret != Z_OK) {
264 PKG_LOGE("fail inflateEnd %d", ret);
265 return;
266 }
267 }
268 }
269 } // namespace Hpackage
270