• 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 #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