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_zipfile.h"
16 #include <ctime>
17 #include <limits>
18 #include "dump.h"
19 #include "pkg_algorithm.h"
20 #include "pkg_manager.h"
21 #include "pkg_stream.h"
22 #include "zip_pkg_parse.h"
23 #include "zlib.h"
24
25 namespace Hpackage {
26 constexpr uint32_t TM_YEAR_BITS = 9;
27 constexpr uint32_t TM_MON_BITS = 5;
28 constexpr uint32_t TM_MIN_BITS = 5;
29 constexpr uint32_t TM_HOUR_BITS = 11;
30 constexpr uint32_t BIG_SIZE_HEADER = 20;
31 constexpr uint32_t START_YEAR = 1900;
32 constexpr uint32_t MAX_FILE_NAME = 256;
33 constexpr uint32_t LOCAL_HEADER_SIGNATURE = 0x04034b50;
34 constexpr uint32_t CENTRAL_SIGNATURE = 0x02014b50;
35 constexpr uint32_t END_CENTRAL_SIGNATURE = 0x06054b50;
36 constexpr uint32_t DATA_DESC_SIGNATURE = 0x08074b50;
37 constexpr uint32_t MAX_BUFFER_SIZE = 1024 * 64;
38 // mask value that signifies that the entry has a DD
39 constexpr uint32_t GPBDD_FLAG_MASK = 0x0008;
40 constexpr uint32_t ZIP_PKG_ALIGNMENT_DEF = 1;
41 constexpr int32_t DEF_MEM_LEVEL = 8;
42 constexpr int32_t Z_STORED = 0;
43
AddEntry(const PkgManager::FileInfoPtr file,const PkgStreamPtr inStream)44 int32_t ZipPkgFile::AddEntry(const PkgManager::FileInfoPtr file, const PkgStreamPtr inStream)
45 {
46 if (!CheckState({PKG_FILE_STATE_IDLE, PKG_FILE_STATE_WORKING}, PKG_FILE_STATE_WORKING)) {
47 PKG_LOGE("Error state curr %d ", state_);
48 return PKG_INVALID_STATE;
49 }
50 if (file == nullptr || inStream == nullptr) {
51 PKG_LOGE("AddEntry failed, invalid param");
52 return PKG_INVALID_PARAM;
53 }
54 PKG_LOGI("ZipPkgFile::AddEntry %s ", file->identity.c_str());
55
56 int32_t ret = PKG_SUCCESS;
57 ZipFileEntry* entry = (ZipFileEntry*)AddPkgEntry(file->identity);
58 if (entry == nullptr) {
59 PKG_LOGE("Failed to create pkg node for %s", file->identity.c_str());
60 return PKG_NONE_MEMORY;
61 }
62 entry->Init(file, inStream);
63
64 size_t encodeLen = 0;
65 ret = entry->EncodeHeader(inStream, currentOffset_, encodeLen);
66 if (ret != PKG_SUCCESS) {
67 PKG_LOGE("Failed to encode for %s", file->identity.c_str());
68 return ret;
69 }
70 currentOffset_ += encodeLen;
71 ret = entry->Pack(inStream, currentOffset_, encodeLen);
72 if (ret != PKG_SUCCESS) {
73 PKG_LOGE("Failed to pack for %s", file->identity.c_str());
74 return ret;
75 }
76 currentOffset_ += encodeLen;
77 return PKG_SUCCESS;
78 }
79
SavePackage(size_t & signOffset)80 int32_t ZipPkgFile::SavePackage(size_t &signOffset)
81 {
82 UNUSED(signOffset);
83 if (!CheckState({PKG_FILE_STATE_WORKING}, PKG_FILE_STATE_CLOSE)) {
84 PKG_LOGE("error state curr %d ", state_);
85 return PKG_INVALID_STATE;
86 }
87 int32_t ret = PKG_SUCCESS;
88 size_t offset = currentOffset_;
89 for (auto &it : pkgEntryMapId_) {
90 ZipFileEntry* entry = (ZipFileEntry*)it.second;
91 if (entry == nullptr) {
92 PKG_LOGE("Failed to write CentralDirEntry");
93 return PKG_INVALID_PARAM;
94 }
95 size_t encodeLen = 0;
96 entry->EncodeCentralDirEntry(pkgStream_, offset, encodeLen);
97 offset += encodeLen;
98 }
99
100 std::vector<uint8_t> buff(sizeof(EndCentralDir));
101 WriteLE32(buff.data() + offsetof(EndCentralDir, signature), END_CENTRAL_SIGNATURE);
102 WriteLE16(buff.data() + offsetof(EndCentralDir, numDisk), 0);
103 WriteLE16(buff.data() + offsetof(EndCentralDir, startDiskOfCentralDir), 0);
104 WriteLE16(buff.data() + offsetof(EndCentralDir, totalEntriesInThisDisk), pkgEntryMapId_.size());
105 WriteLE16(buff.data() + offsetof(EndCentralDir, totalEntries), pkgEntryMapId_.size());
106 WriteLE32(buff.data() + offsetof(EndCentralDir, sizeOfCentralDir), offset - currentOffset_);
107 WriteLE32(buff.data() + offsetof(EndCentralDir, offset), currentOffset_);
108 WriteLE16(buff.data() + offsetof(EndCentralDir, commentLen), 0);
109 PkgBuffer buffer(buff);
110 ret = pkgStream_->Write(buffer, sizeof(EndCentralDir), offset);
111 if (ret != PKG_SUCCESS) {
112 PKG_LOGE("Failed to write CentralDirEntry for %s", pkgStream_->GetFileName().c_str());
113 return ret;
114 }
115 currentOffset_ = offset + sizeof(EndCentralDir);
116 pkgStream_->Flush(currentOffset_);
117 return PKG_SUCCESS;
118 }
119
LoadPackage(std::vector<std::string> & fileNames,PkgBuffer & buffer,uint32_t endDirLen,size_t endDirPos,size_t & readLen)120 int32_t ZipPkgFile::LoadPackage(std::vector<std::string> &fileNames, PkgBuffer &buffer,
121 uint32_t endDirLen, size_t endDirPos, size_t &readLen)
122 {
123 size_t fileLen = pkgStream_->GetFileLength();
124 EndCentralDir endDir;
125 endDir.signature = ReadLE32(buffer.buffer + offsetof(EndCentralDir, signature));
126 endDir.numDisk = ReadLE16(buffer.buffer + offsetof(EndCentralDir, numDisk));
127 endDir.startDiskOfCentralDir = ReadLE16(buffer.buffer + offsetof(EndCentralDir, startDiskOfCentralDir));
128 endDir.totalEntriesInThisDisk = ReadLE16(buffer.buffer + offsetof(EndCentralDir, totalEntriesInThisDisk));
129 endDir.totalEntries = ReadLE16(buffer.buffer + offsetof(EndCentralDir, totalEntries));
130 endDir.sizeOfCentralDir = ReadLE32(buffer.buffer + offsetof(EndCentralDir, sizeOfCentralDir));
131 endDir.offset = ReadLE32(buffer.buffer + offsetof(EndCentralDir, offset));
132 endDir.commentLen = ReadLE16(buffer.buffer + offsetof(EndCentralDir, commentLen));
133 if ((endDir.numDisk != 0) || (endDir.signature != END_CENTRAL_SIGNATURE) ||
134 (endDir.startDiskOfCentralDir != 0)
135 #ifndef UPDATER_UT
136 || (endDir.offset >= fileLen) || (endDir.totalEntriesInThisDisk != endDir.totalEntries) ||
137 ((endDir.offset + endDir.sizeOfCentralDir + endDirLen) > fileLen)
138 #endif
139 ) {
140 PKG_LOGE("end dir format error %s", pkgStream_->GetFileName().c_str());
141 UPDATER_LAST_WORD(PKG_INVALID_PKG_FORMAT);
142 return PKG_INVALID_PKG_FORMAT;
143 }
144 size_t currentPos = endDir.offset;
145 if (endDir.offset == UINT_MAX) {
146 int32_t ret = pkgStream_->Read(buffer, endDirPos - sizeof(Zip64EndCentralDirLocator),
147 sizeof(Zip64EndCentralDirLocator), readLen);
148 uint32_t signature = ReadLE32(buffer.buffer + offsetof(Zip64EndCentralDirLocator, signature));
149 if (ret != PKG_SUCCESS || signature != 0x07064b50) {
150 return ParseFileEntries(fileNames, endDir, currentPos, fileLen);
151 }
152 currentPos = ReadLE64(buffer.buffer + offsetof(Zip64EndCentralDirLocator, endOfCentralDirectoryRecord));
153 ret = pkgStream_->Read(buffer, currentPos, sizeof(Zip64EndCentralDirRecord), readLen);
154 signature = ReadLE32(buffer.buffer + offsetof(Zip64EndCentralDirRecord, signature));
155 if (ret == PKG_SUCCESS && signature == 0x06064b50) {
156 currentPos = ReadLE64(buffer.buffer + offsetof(Zip64EndCentralDirRecord, offset));
157 }
158 }
159 return ParseFileEntries(fileNames, endDir, currentPos, fileLen);
160 }
161
GetFileLength(size_t & fileLen)162 int32_t ZipPkgFile::GetFileLength(size_t &fileLen)
163 {
164 if (!CheckState({PKG_FILE_STATE_IDLE}, PKG_FILE_STATE_WORKING)) {
165 PKG_LOGE("Error state curr %d ", state_);
166 return PKG_INVALID_STATE;
167 }
168 // 先从文件尾部获取 EndCentralDir
169 fileLen = pkgStream_->GetFileLength();
170 if (fileLen == 0) {
171 PKG_LOGE("invalid file to load");
172 return PKG_INVALID_STATE;
173 }
174 if (fileLen > SIZE_MAX) {
175 PKG_LOGE("Invalid file len %zu to load %s", fileLen, pkgStream_->GetFileName().c_str());
176 return PKG_INVALID_FILE;
177 }
178 if (fileLen < static_cast<size_t>(sizeof(EndCentralDir))) {
179 PKG_LOGE("Too small to be zip %s", pkgStream_->GetFileName().c_str());
180 return PKG_INVALID_FILE;
181 }
182 return PKG_SUCCESS;
183 }
184
LoadPackage(std::vector<std::string> & fileNames,VerifyFunction verifier)185 int32_t ZipPkgFile::LoadPackage(std::vector<std::string>& fileNames, VerifyFunction verifier)
186 {
187 UNUSED(verifier);
188 PKG_LOGI("LoadPackage %s :%zu", pkgStream_->GetFileName().c_str(), pkgStream_->GetFileLength());
189
190 // 检查最后面是签名信息还是EndCentralDir
191 size_t fileLen = 0;
192 int32_t ret = GetFileLength(fileLen);
193 if (ret != PKG_SUCCESS) {
194 PKG_LOGE("GetFileLength FAIL");
195 UPDATER_LAST_WORD(ret);
196 return ret;
197 }
198 size_t buffSize = sizeof(EndCentralDir);
199 if (buffSize < sizeof(Zip64EndCentralDirRecord)) {
200 buffSize = sizeof(Zip64EndCentralDirRecord);
201 }
202
203 size_t signatureLen = 0;
204 uint32_t magic = 0;
205 uint32_t endDirLen = sizeof(EndCentralDir);
206 size_t endDirPos = fileLen - endDirLen;
207 size_t readLen = 0;
208 PkgBuffer buffer(nullptr, buffSize);
209 ret = pkgStream_->Read(buffer, endDirPos, sizeof(EndCentralDir), readLen);
210 if (ret != PKG_SUCCESS) {
211 PKG_LOGE("read EOCD struct failed %s", pkgStream_->GetFileName().c_str());
212 UPDATER_LAST_WORD(ret);
213 return ret;
214 }
215 magic = ReadLE32(buffer.buffer);
216 if (magic != END_CENTRAL_SIGNATURE) { // 按签名处理
217 ZipPkgParse zipParse;
218 PkgSignComment pkgSignComment {};
219 ret = zipParse.ParseZipPkg(pkgStream_, pkgSignComment);
220 signatureLen = pkgSignComment.signCommentTotalLen;
221 if (ret != PKG_SUCCESS) {
222 PKG_LOGE("Parse zip package signature failed");
223 UPDATER_LAST_WORD(ret);
224 return ret;
225 }
226
227 endDirPos -= signatureLen;
228 ret = pkgStream_->Read(buffer, endDirPos, sizeof(EndCentralDir), readLen);
229 if (ret != PKG_SUCCESS) {
230 PKG_LOGE("read EOCD struct failed %s", pkgStream_->GetFileName().c_str());
231 UPDATER_LAST_WORD(ret);
232 return ret;
233 }
234 }
235
236 return LoadPackage(fileNames, buffer, endDirLen, endDirPos, readLen);
237 }
238
ParseFileEntries(std::vector<std::string> & fileNames,const EndCentralDir & endDir,size_t currentPos,size_t fileLen)239 int32_t ZipPkgFile::ParseFileEntries(std::vector<std::string> &fileNames,
240 const EndCentralDir &endDir, size_t currentPos, size_t fileLen)
241 {
242 Updater::UPDATER_INIT_RECORD;
243 int32_t ret = PKG_SUCCESS;
244 size_t buffLen = MAX_FILE_NAME + sizeof(LocalFileHeader) + sizeof(DataDescriptor)
245 + sizeof(CentralDirEntry) + BIG_SIZE_HEADER;
246 PkgBuffer buffer(buffLen);
247
248 for (int32_t i = 0; i < endDir.totalEntries; i++) {
249 if (fileLen <= currentPos) {
250 PKG_LOGE("too small to be zip");
251 UPDATER_LAST_WORD(PKG_INVALID_FILE);
252 return PKG_INVALID_FILE;
253 }
254
255 ZipFileEntry* entry = new ZipFileEntry(this, nodeId_++);
256 if (entry == nullptr) {
257 PKG_LOGE("Failed to create zip node for %s", pkgStream_->GetFileName().c_str());
258 UPDATER_LAST_WORD(PKG_NONE_MEMORY);
259 return PKG_NONE_MEMORY;
260 }
261
262 // 从文件中解析出文件头信息,保存在entry中
263 size_t decodeLen = 0;
264 ret = entry->DecodeHeader(buffer, currentPos, 0, decodeLen);
265 if (ret != PKG_SUCCESS) {
266 PKG_LOGE("DecodeHeader failed");
267 delete entry;
268 UPDATER_LAST_WORD(ret);
269 return ret;
270 }
271
272 // 保存entry文件
273 pkgEntryMapId_.insert(std::pair<uint32_t, PkgEntryPtr>(entry->GetNodeId(), (PkgEntryPtr)entry));
274 pkgEntryMapFileName_.insert(std::pair<std::string, PkgEntryPtr>(entry->GetFileName(), (PkgEntryPtr)entry));
275 fileNames.push_back(entry->GetFileName());
276
277 currentPos += decodeLen;
278 }
279 return ret;
280 }
281
EncodeHeader(PkgStreamPtr inStream,size_t startOffset,size_t & encodeLen)282 int32_t ZipFileEntry::EncodeHeader(PkgStreamPtr inStream, size_t startOffset, size_t &encodeLen)
283 {
284 // 对zip包,数据和数据头信息在连续位置,使用一个打包
285 encodeLen = 0;
286 fileInfo_.fileInfo.headerOffset = startOffset;
287 return PKG_SUCCESS;
288 }
289
PackStream(PkgStreamPtr inStream,size_t startOffset,size_t & encodeLen,const PkgAlgorithm::PkgAlgorithmPtr algorithm,const PkgStreamPtr outStream)290 int32_t ZipFileEntry::PackStream(PkgStreamPtr inStream, size_t startOffset, size_t &encodeLen,
291 const PkgAlgorithm::PkgAlgorithmPtr algorithm, const PkgStreamPtr outStream)
292 {
293 // 为header申请一个buff,先处理到内存,后面在写入文件
294 std::vector<uint8_t> buff(MAX_FILE_NAME + sizeof(LocalFileHeader) + ZIP_PKG_ALIGNMENT_DEF);
295 size_t nameLen = 0;
296 PkgFileImpl::ConvertStringToBuffer(fileInfo_.fileInfo.identity, {
297 buff.data() + sizeof(LocalFileHeader), buff.capacity()
298 }, nameLen);
299
300 size_t headerLen = nameLen + sizeof(LocalFileHeader);
301 bool hasDataDesc = true;
302 if (fileInfo_.method == Z_DEFLATED) {
303 #ifndef UPDATER_UT
304 hasDataDesc = false;
305 #endif
306 }
307
308 fileInfo_.fileInfo.dataOffset = startOffset + headerLen;
309 PkgAlgorithmContext context = {
310 {0, startOffset + headerLen},
311 {fileInfo_.fileInfo.packedSize, fileInfo_.fileInfo.unpackedSize},
312 0, fileInfo_.fileInfo.digestMethod
313 };
314 int32_t ret = algorithm->Pack(inStream, outStream, context);
315 if (ret != PKG_SUCCESS) {
316 PKG_LOGE("Failed to compress for %s", fileInfo_.fileInfo.identity.c_str());
317 return ret;
318 }
319 // 填充file信息,压缩后的长度和crc
320 fileInfo_.fileInfo.packedSize = context.packedSize;
321 crc32_ = context.crc;
322
323 // 构建文件头信息,从startOffset开始
324 ret = EncodeLocalFileHeader(buff.data(), sizeof(LocalFileHeader), hasDataDesc, nameLen);
325 if (ret != PKG_SUCCESS) {
326 PKG_LOGE("Failed to encodeFileHeader for %s", fileInfo_.fileInfo.identity.c_str());
327 return ret;
328 }
329 PkgBuffer buffer(buff);
330 ret = outStream->Write(buffer, headerLen, startOffset);
331 if (ret != PKG_SUCCESS) {
332 PKG_LOGE("Failed to write header for %s", fileInfo_.fileInfo.identity.c_str());
333 return ret;
334 }
335
336 if (hasDataDesc) { // 数据描述部分
337 uint32_t encodeDataDescLen = 0;
338 ret = EncodeDataDescriptor(outStream,
339 startOffset + headerLen + fileInfo_.fileInfo.packedSize, encodeDataDescLen);
340 if (ret != PKG_SUCCESS) {
341 PKG_LOGE("Failed to encodeDataDescriptor for %s", fileInfo_.fileInfo.identity.c_str());
342 return ret;
343 }
344 headerLen += encodeDataDescLen;
345 }
346 encodeLen = headerLen + fileInfo_.fileInfo.packedSize;
347 PKG_LOGI("Pack packedSize:%zu unpackedSize: %zu offset: %zu %zu", fileInfo_.fileInfo.packedSize,
348 fileInfo_.fileInfo.unpackedSize, fileInfo_.fileInfo.headerOffset, fileInfo_.fileInfo.dataOffset);
349 return PKG_SUCCESS;
350 }
351
Pack(PkgStreamPtr inStream,size_t startOffset,size_t & encodeLen)352 int32_t ZipFileEntry::Pack(PkgStreamPtr inStream, size_t startOffset, size_t &encodeLen)
353 {
354 PkgAlgorithm::PkgAlgorithmPtr algorithm = PkgAlgorithmFactory::GetAlgorithm(&fileInfo_.fileInfo);
355 PkgStreamPtr outStream = pkgFile_->GetPkgStream();
356 if (fileInfo_.fileInfo.headerOffset != startOffset) {
357 PKG_LOGE("Offset error %zu %zu %s", fileInfo_.fileInfo.headerOffset,
358 startOffset, fileInfo_.fileInfo.identity.c_str());
359 return PKG_INVALID_PARAM;
360 }
361 if (algorithm == nullptr || outStream == nullptr || inStream == nullptr) {
362 PKG_LOGE("outStream or inStream null for %s", fileInfo_.fileInfo.identity.c_str());
363 return PKG_INVALID_PARAM;
364 }
365 return PackStream(inStream, startOffset, encodeLen, algorithm, outStream);
366 }
367
EncodeCentralDirEntry(const PkgStreamPtr stream,size_t startOffset,size_t & encodeLen)368 int32_t ZipFileEntry::EncodeCentralDirEntry(const PkgStreamPtr stream, size_t startOffset, size_t &encodeLen)
369 {
370 std::vector<uint8_t> buff(sizeof(CentralDirEntry) + MAX_FILE_NAME);
371 size_t realLen = 0;
372 PkgFileImpl::ConvertStringToBuffer(fileInfo_.fileInfo.identity, {
373 buff.data() + sizeof(CentralDirEntry), buff.capacity()
374 }, realLen);
375
376 CentralDirEntry* centralDir = reinterpret_cast<CentralDirEntry*>(buff.data());
377 centralDir->signature = CENTRAL_SIGNATURE;
378 centralDir->versionMade = 0;
379 centralDir->versionNeeded = 0;
380 if (fileInfo_.method == Z_DEFLATED) {
381 centralDir->flags |= GPBDD_FLAG_MASK;
382 }
383 centralDir->compressionMethod = static_cast<uint16_t>(fileInfo_.method);
384 centralDir->crc = crc32_;
385 uint16_t date;
386 uint16_t time;
387 ExtraTimeAndDate(fileInfo_.fileInfo.modifiedTime, date, time);
388 centralDir->modifiedDate = date;
389 centralDir->modifiedTime = time;
390 centralDir->compressedSize = fileInfo_.fileInfo.packedSize;
391 centralDir->uncompressedSize = fileInfo_.fileInfo.unpackedSize;
392 centralDir->nameSize = realLen;
393 centralDir->extraSize = 0;
394 centralDir->commentSize = 0;
395 centralDir->diskNumStart = 0;
396 centralDir->internalAttr = 0;
397 centralDir->externalAttr = 0;
398 centralDir->localHeaderOffset = fileInfo_.fileInfo.headerOffset;
399 PkgBuffer buffer(buff);
400 int32_t ret = stream->Write(buffer, sizeof(CentralDirEntry) + realLen, startOffset);
401 if (ret != PKG_SUCCESS) {
402 PKG_LOGE("Failed to write CentralDirEntry for %s", fileInfo_.fileInfo.identity.c_str());
403 return ret;
404 }
405 encodeLen = sizeof(CentralDirEntry) + realLen;
406 return PKG_SUCCESS;
407 }
408
EncodeLocalFileHeader(uint8_t * buffer,size_t bufferLen,bool hasDataDesc,size_t nameLen)409 int32_t ZipFileEntry::EncodeLocalFileHeader(uint8_t *buffer, size_t bufferLen, bool hasDataDesc,
410 size_t nameLen)
411 {
412 if (bufferLen < sizeof(LocalFileHeader)) {
413 PKG_LOGE("invalid buffer for decode");
414 return PKG_INVALID_PARAM;
415 }
416
417 LocalFileHeader* header = reinterpret_cast<LocalFileHeader*>(buffer);
418 header->signature = LOCAL_HEADER_SIGNATURE;
419 header->versionNeeded = 0;
420 header->flags = 0;
421 header->compressionMethod = static_cast<uint16_t>(fileInfo_.method);
422 uint16_t date;
423 uint16_t time;
424 ExtraTimeAndDate(fileInfo_.fileInfo.modifiedTime, date, time);
425 header->modifiedDate = date;
426 header->modifiedTime = time;
427 header->crc = crc32_;
428 header->compressedSize = fileInfo_.fileInfo.packedSize;
429 header->uncompressedSize = fileInfo_.fileInfo.unpackedSize;
430 header->nameSize = nameLen;
431 header->extraSize = 0;
432 if (hasDataDesc) {
433 header->flags |= GPBDD_FLAG_MASK;
434 header->compressedSize = 0u;
435 header->uncompressedSize = 0u;
436 header->crc = 0u;
437 }
438 return PKG_SUCCESS;
439 }
440
EncodeDataDescriptor(const PkgStreamPtr stream,size_t startOffset,uint32_t & encodeLen) const441 int32_t ZipFileEntry::EncodeDataDescriptor(const PkgStreamPtr stream, size_t startOffset,
442 uint32_t &encodeLen) const
443 {
444 int32_t ret = PKG_SUCCESS;
445 size_t offset = startOffset;
446 DataDescriptor dataDesc = {};
447 dataDesc.signature = DATA_DESC_SIGNATURE;
448 dataDesc.crc = crc32_;
449 dataDesc.compressedSize = fileInfo_.fileInfo.packedSize;
450 dataDesc.uncompressedSize = fileInfo_.fileInfo.unpackedSize;
451 PkgBuffer buffer((uint8_t *)&dataDesc, sizeof(dataDesc));
452 ret = stream->Write(buffer, sizeof(dataDesc), offset);
453 if (ret != PKG_SUCCESS) {
454 PKG_LOGE("Failed to write DataDescriptor for %s", fileInfo_.fileInfo.identity.c_str());
455 return ret;
456 }
457 offset += sizeof(dataDesc);
458 encodeLen = offset - startOffset;
459 return ret;
460 }
461
DoDecodeCentralDirEntry(PkgBuffer & buffer,size_t & decodeLen,size_t currLen,uint16_t nameSize,uint16_t extraSize)462 int32_t ZipFileEntry::DoDecodeCentralDirEntry(PkgBuffer &buffer, size_t &decodeLen,
463 size_t currLen, uint16_t nameSize, uint16_t extraSize)
464 {
465 fileInfo_.method = static_cast<int32_t>(ReadLE16(buffer.buffer + offsetof(CentralDirEntry, compressionMethod)));
466 uint16_t modifiedTime = ReadLE16(buffer.buffer + offsetof(CentralDirEntry, modifiedTime));
467 uint16_t modifiedDate = ReadLE16(buffer.buffer + offsetof(CentralDirEntry, modifiedDate));
468 CombineTimeAndDate(fileInfo_.fileInfo.modifiedTime, modifiedTime, modifiedDate);
469 crc32_ = ReadLE32(buffer.buffer + offsetof(CentralDirEntry, crc));
470 fileInfo_.fileInfo.packedSize = ReadLE32(buffer.buffer + offsetof(CentralDirEntry, compressedSize));
471 fileInfo_.fileInfo.unpackedSize = ReadLE32(buffer.buffer + offsetof(CentralDirEntry, uncompressedSize));
472 fileInfo_.fileInfo.headerOffset = ReadLE32(buffer.buffer + offsetof(CentralDirEntry, localHeaderOffset));
473 // 对于zip64,需要解析extra field
474 decodeLen = currLen;
475 if (extraSize <= 0) {
476 return PKG_SUCCESS;
477 }
478 uint8_t* extraData = buffer.buffer + nameSize + sizeof(CentralDirEntry);
479 uint16_t headerId = ReadLE16(extraData);
480 if (headerId != 1) { // zip64 扩展
481 return PKG_SUCCESS;
482 }
483 size_t unpackedSize = ReadLE64(extraData + sizeof(uint32_t));
484 size_t packedSize = ReadLE64(extraData + sizeof(uint32_t) + sizeof(uint64_t));
485 if (fileInfo_.fileInfo.packedSize == UINT_MAX || fileInfo_.fileInfo.unpackedSize == UINT_MAX) {
486 fileInfo_.fileInfo.unpackedSize =
487 (fileInfo_.fileInfo.unpackedSize == UINT_MAX) ? unpackedSize : fileInfo_.fileInfo.unpackedSize;
488 fileInfo_.fileInfo.packedSize =
489 (fileInfo_.fileInfo.packedSize == UINT_MAX) ? packedSize : fileInfo_.fileInfo.packedSize;
490 fileInfo_.fileInfo.headerOffset = (fileInfo_.fileInfo.headerOffset == UINT_MAX) ?
491 ReadLE64(extraData + BIG_SIZE_HEADER) : fileInfo_.fileInfo.headerOffset;
492 } else if (fileInfo_.fileInfo.headerOffset == UINT_MAX) {
493 fileInfo_.fileInfo.headerOffset = unpackedSize;
494 }
495
496 return PKG_SUCCESS;
497 }
498
499 /*
500 0x0001 2 bytes Tag for this "extra" block type
501 Size 2 bytes Size of this "extra" block
502 Original
503 Size 8 bytes Original uncompressed file size
504 Compressed
505 Size 8 bytes Size of compressed data
506 Relative Header
507 Offset 8 bytes Offset of local header record
508 Disk Start
509 Number 4 bytes Number of the disk on which
510 this file starts
511 */
DecodeCentralDirEntry(PkgStreamPtr inStream,PkgBuffer & buffer,size_t currentPos,size_t & decodeLen)512 int32_t ZipFileEntry::DecodeCentralDirEntry(PkgStreamPtr inStream, PkgBuffer &buffer, size_t currentPos,
513 size_t &decodeLen)
514 {
515 size_t readLen = buffer.length;
516 if (readLen < sizeof(CentralDirEntry)) {
517 PKG_LOGE("data not not enough %zu", readLen);
518 return PKG_INVALID_PKG_FORMAT;
519 }
520 uint32_t signature = ReadLE32(buffer.buffer + offsetof(CentralDirEntry, signature));
521 if (signature != CENTRAL_SIGNATURE) {
522 PKG_LOGE("Check centralDir signature failed 0x%x", signature);
523 return PKG_INVALID_PKG_FORMAT;
524 }
525 uint16_t nameSize = ReadLE16(buffer.buffer + offsetof(CentralDirEntry, nameSize));
526 uint16_t extraSize = ReadLE16(buffer.buffer + offsetof(CentralDirEntry, extraSize));
527 uint16_t commentSize = ReadLE16(buffer.buffer + offsetof(CentralDirEntry, commentSize));
528 size_t currLen = sizeof(CentralDirEntry) + nameSize + extraSize + commentSize;
529 if (currentPos >= (std::numeric_limits<size_t>::max() - currLen)) {
530 PKG_LOGE("check centralDir len failed");
531 return PKG_INVALID_PKG_FORMAT;
532 }
533 size_t fileNameLength = nameSize;
534 if (nameSize >= MAX_FILE_NAME) {
535 PKG_LOGE("file name size too longer %d", nameSize);
536 fileNameLength = MAX_FILE_NAME - 1;
537 }
538 if (readLen < sizeof(CentralDirEntry) + fileNameLength) {
539 PKG_LOGE("data not not enough %zu", readLen);
540 return PKG_INVALID_PKG_FORMAT;
541 }
542 fileInfo_.fileInfo.identity.assign(reinterpret_cast<char*>(buffer.buffer + sizeof(CentralDirEntry)),
543 fileNameLength);
544 return DoDecodeCentralDirEntry(buffer, decodeLen, currLen, nameSize, extraSize);
545 }
546
DecodeLocalFileHeaderCheck(PkgStreamPtr inStream,PkgBuffer & data,size_t currentPos)547 int32_t ZipFileEntry::DecodeLocalFileHeaderCheck(PkgStreamPtr inStream, PkgBuffer &data,
548 size_t currentPos)
549 {
550 uint16_t flags = ReadLE16(data.buffer + offsetof(LocalFileHeader, flags));
551 uint32_t crc32 = ReadLE32(data.buffer + offsetof(LocalFileHeader, crc));
552 uint32_t packedSize = ReadLE32(data.buffer + offsetof(LocalFileHeader, compressedSize));
553 uint32_t unpackedSize = ReadLE32(data.buffer + offsetof(LocalFileHeader, uncompressedSize));
554 size_t readLen = 0;
555 if ((flags & GPBDD_FLAG_MASK) == GPBDD_FLAG_MASK) {
556 currentPos += fileInfo_.fileInfo.packedSize;
557 int ret = inStream->Read(data, currentPos, data.length, readLen);
558 if (ret != PKG_SUCCESS) {
559 PKG_LOGE("parse entry read centralDir failed");
560 return ret;
561 }
562 if (readLen < sizeof(DataDescriptor)) {
563 PKG_LOGE("data not not enough %zu", readLen);
564 return PKG_INVALID_PKG_FORMAT;
565 }
566
567 uint32_t signature = ReadLE32(data.buffer + offsetof(DataDescriptor, signature));
568 if (signature != DATA_DESC_SIGNATURE) {
569 PKG_LOGE("check DataDescriptor signature failed");
570 return PKG_INVALID_PKG_FORMAT;
571 }
572 crc32 = ReadLE32(data.buffer + offsetof(DataDescriptor, crc));
573 packedSize = ReadLE32(data.buffer + offsetof(DataDescriptor, compressedSize));
574 unpackedSize = ReadLE32(data.buffer + offsetof(DataDescriptor, uncompressedSize));
575 }
576 PKG_LOGI("DecodeLocalFileHeaderCheck: packedSize: %zu unpackedSize: %zu", packedSize, unpackedSize);
577 if (crc32_ != crc32) {
578 PKG_LOGE("check crc %u %u failed", crc32_, crc32);
579 return PKG_INVALID_PKG_FORMAT;
580 }
581 return PKG_SUCCESS;
582 }
583
DecodeLocalFileHeader(PkgStreamPtr inStream,PkgBuffer & data,size_t currentPos,size_t & decodeLen)584 int32_t ZipFileEntry::DecodeLocalFileHeader(PkgStreamPtr inStream, PkgBuffer &data, size_t currentPos,
585 size_t &decodeLen)
586 {
587 size_t readLen = 0;
588 int32_t ret = inStream->Read(data, currentPos, data.length, readLen);
589 if (ret != PKG_SUCCESS) {
590 PKG_LOGE("parse entry read centralDir failed");
591 return ret;
592 }
593 if (readLen < sizeof(LocalFileHeader)) {
594 PKG_LOGE("data not not enough %zu", readLen);
595 return PKG_INVALID_PKG_FORMAT;
596 }
597 uint32_t signature = ReadLE32(data.buffer + offsetof(LocalFileHeader, signature));
598 if (signature != LOCAL_HEADER_SIGNATURE) {
599 PKG_LOGE("check localHeader signature failed");
600 return PKG_INVALID_PKG_FORMAT;
601 }
602
603 uint16_t nameSize = ReadLE16(data.buffer + offsetof(LocalFileHeader, nameSize));
604 uint16_t extraSize = ReadLE16(data.buffer + offsetof(LocalFileHeader, extraSize));
605 size_t currLen = sizeof(LocalFileHeader) + nameSize + extraSize;
606 if (currentPos >= (std::numeric_limits<size_t>::max() - currLen)) {
607 PKG_LOGE("check centralDir len failed");
608 return PKG_INVALID_PKG_FORMAT;
609 }
610 size_t fileNameLength = (nameSize >= MAX_FILE_NAME) ? MAX_FILE_NAME - 1 : nameSize;
611 if (readLen < sizeof(LocalFileHeader) + fileNameLength) {
612 PKG_LOGE("data not not enough %zu", readLen);
613 return PKG_INVALID_PKG_FORMAT;
614 }
615 std::string fileName(reinterpret_cast<char*>(data.buffer + sizeof(LocalFileHeader)), fileNameLength);
616 uint16_t compressionMethod = ReadLE16(data.buffer + offsetof(LocalFileHeader, compressionMethod));
617 fileInfo_.method = static_cast<int32_t>(compressionMethod);
618 fileInfo_.level = Z_BEST_COMPRESSION;
619 fileInfo_.windowBits = -MAX_WBITS;
620 fileInfo_.memLevel = DEF_MEM_LEVEL;
621 fileInfo_.strategy = Z_DEFAULT_STRATEGY;
622 if (fileInfo_.fileInfo.identity.compare(fileName)) {
623 PKG_LOGE("check file name %s %s failed", fileInfo_.fileInfo.identity.c_str(), fileName.c_str());
624 return PKG_INVALID_PKG_FORMAT;
625 }
626 fileName_.assign(fileInfo_.fileInfo.identity);
627 decodeLen = currLen;
628
629 // 检查解析的是否正确
630 ret = DecodeLocalFileHeaderCheck(inStream, data, currentPos + currLen);
631 if (ret != PKG_SUCCESS) {
632 return ret;
633 }
634 return PKG_SUCCESS;
635 }
636
Stored(const PkgStreamPtr inStream,const PkgStreamPtr outStream,PkgAlgorithmContext & context)637 int32_t ZipFileEntry::Stored(const PkgStreamPtr inStream, const PkgStreamPtr outStream,
638 PkgAlgorithmContext &context)
639 {
640 size_t start = 0;
641 size_t startWrite = 0;
642 size_t remainSize = context.packedSize;
643 while (remainSize > 0) {
644 PkgBuffer buffer(MAX_BUFFER_SIZE);
645 size_t readLen = (remainSize > buffer.length) ? buffer.length : remainSize;
646 int32_t ret = inStream->Read(buffer, context.srcOffset, readLen, start);
647 if (ret != PKG_SUCCESS) {
648 PKG_LOGE("read buffer from inStream failed");
649 return ret;
650 }
651 ret = outStream->Write(buffer, readLen, startWrite);
652 if (ret != PKG_SUCCESS) {
653 PKG_LOGE("write buffer in outStream failed");
654 return ret;
655 }
656 startWrite += readLen;
657 remainSize -= readLen;
658 }
659 return PKG_SUCCESS;
660 }
661
Unpack(PkgStreamPtr outStream)662 int32_t ZipFileEntry::Unpack(PkgStreamPtr outStream)
663 {
664 PkgAlgorithm::PkgAlgorithmPtr algorithm = PkgAlgorithmFactory::GetAlgorithm(&fileInfo_.fileInfo);
665 if (algorithm == nullptr) {
666 PKG_LOGE("ZipFileEntry::Unpack : can not algorithm for %s", fileInfo_.fileInfo.identity.c_str());
667 return PKG_INVALID_PARAM;
668 }
669
670 PkgStreamPtr inStream = pkgFile_->GetPkgStream();
671 if (outStream == nullptr || inStream == nullptr) {
672 PKG_LOGE("ZipFileEntry::Unpack : outStream or inStream null for %s", fileInfo_.fileInfo.identity.c_str());
673 return PKG_INVALID_PARAM;
674 }
675 PkgAlgorithmContext context = {
676 {this->fileInfo_.fileInfo.dataOffset, 0},
677 {fileInfo_.fileInfo.packedSize, fileInfo_.fileInfo.unpackedSize},
678 crc32_, fileInfo_.fileInfo.digestMethod
679 };
680 int32_t ret = PKG_SUCCESS;
681 switch (fileInfo_.method) {
682 case Z_DEFLATED:
683 ret = algorithm->Unpack(inStream, outStream, context);
684 break;
685 case Z_STORED:
686 ret = Stored(inStream, outStream, context);
687 break;
688 default:
689 ret = PKG_INVALID_PARAM;
690 break;
691 }
692 if (ret != PKG_SUCCESS) {
693 PKG_LOGE("Failed to decompress for %s", fileInfo_.fileInfo.identity.c_str());
694 return ret;
695 }
696 PKG_LOGI("packedSize: %zu unpackedSize: %zu offset header: %zu data: %zu", fileInfo_.fileInfo.packedSize,
697 fileInfo_.fileInfo.unpackedSize, fileInfo_.fileInfo.headerOffset, fileInfo_.fileInfo.dataOffset);
698 ret = outStream->Flush(fileInfo_.fileInfo.unpackedSize);
699 if (ret != PKG_SUCCESS) {
700 PKG_LOGE("Failed to Flush for %s", fileInfo_.fileInfo.identity.c_str());
701 return ret;
702 }
703 algorithm->UpdateFileInfo(&fileInfo_.fileInfo);
704 return PKG_SUCCESS;
705 }
706
CombineTimeAndDate(time_t & time,uint16_t modifiedTime,uint16_t modifiedDate) const707 void ZipFileEntry::CombineTimeAndDate(time_t &time, uint16_t modifiedTime, uint16_t modifiedDate) const
708 {
709 struct tm newTime;
710 newTime.tm_year = ((modifiedDate >> TM_YEAR_BITS) & 0x7f) + START_YEAR; // 年,tm_year为int临时变量减去1900。
711 newTime.tm_mon = (modifiedDate >> TM_MON_BITS) & 0xf; // 月,tm_mon为int临时变量减去1。
712 newTime.tm_mday = modifiedDate & 0x1f; // 日。
713 newTime.tm_hour = (modifiedTime >> TM_HOUR_BITS) & 0x1f; // 时。
714 newTime.tm_min = (modifiedTime >> TM_MIN_BITS) & 0x2f; // 分。
715 newTime.tm_sec = (modifiedTime << 1) & 0x1f; // 秒。
716 newTime.tm_isdst = 0; // 非夏令时。
717 time = mktime(&newTime); // 将tm结构体转换成time_t格式。
718 }
719
DecodeHeader(PkgBuffer & buffer,size_t headerOffset,size_t dataOffset,size_t & decodeLen)720 int32_t ZipFileEntry::DecodeHeader(PkgBuffer &buffer, size_t headerOffset, size_t dataOffset,
721 size_t &decodeLen)
722 {
723 PkgStreamPtr inStream = pkgFile_->GetPkgStream();
724 if (inStream == nullptr) {
725 PKG_LOGE("outStream or inStream null for %s", fileInfo_.fileInfo.identity.c_str());
726 return PKG_INVALID_PARAM;
727 }
728
729 if (headerOffset >= (std::numeric_limits<size_t>::max() - buffer.length)) {
730 PKG_LOGE("check centralDir len failed");
731 return PKG_INVALID_PKG_FORMAT;
732 }
733 size_t readLen = 0;
734 int32_t ret = inStream->Read(buffer, headerOffset, buffer.length, readLen);
735 if (ret != PKG_SUCCESS) {
736 PKG_LOGE("parse entry read centralDir failed");
737 return ret;
738 }
739 PkgBuffer centralBuff(buffer.buffer, readLen);
740 ret = DecodeCentralDirEntry(inStream, centralBuff, headerOffset, decodeLen);
741 if (ret != PKG_SUCCESS) {
742 PKG_LOGE("decode CentralDir failed");
743 return ret;
744 }
745
746 size_t headerLen = 0;
747 ret = DecodeLocalFileHeader(inStream, buffer, fileInfo_.fileInfo.headerOffset, headerLen);
748 if (ret != PKG_SUCCESS) {
749 PKG_LOGE("decode LocalFileHeader failed");
750 return ret;
751 }
752 fileInfo_.fileInfo.packMethod = PKG_COMPRESS_METHOD_ZIP;
753 fileInfo_.fileInfo.digestMethod = PKG_DIGEST_TYPE_CRC;
754 fileInfo_.fileInfo.dataOffset = fileInfo_.fileInfo.headerOffset + headerLen;
755 PKG_LOGI("packedSize: %zu unpackedSize: %zu offset header: %zu data: %zu %s",
756 fileInfo_.fileInfo.packedSize, fileInfo_.fileInfo.unpackedSize,
757 fileInfo_.fileInfo.headerOffset, fileInfo_.fileInfo.dataOffset, fileInfo_.fileInfo.identity.c_str());
758 return PKG_SUCCESS;
759 }
760
Init(const PkgManager::FileInfoPtr fileInfo,PkgStreamPtr inStream)761 int32_t ZipFileEntry::Init(const PkgManager::FileInfoPtr fileInfo, PkgStreamPtr inStream)
762 {
763 fileInfo_.level = Z_BEST_COMPRESSION;
764 fileInfo_.method = Z_DEFLATED;
765 fileInfo_.windowBits = -MAX_WBITS;
766 fileInfo_.memLevel = DEF_MEM_LEVEL;
767 fileInfo_.strategy = Z_DEFAULT_STRATEGY;
768 int32_t ret = PkgEntry::Init(&fileInfo_.fileInfo, fileInfo, inStream);
769 if (ret != PKG_SUCCESS) {
770 PKG_LOGE("Failed to check input param");
771 return PKG_INVALID_PARAM;
772 }
773 ZipFileInfo* info = (ZipFileInfo*)fileInfo;
774 if (info != nullptr && info->method != -1) {
775 fileInfo_.level = info->level;
776 fileInfo_.memLevel = info->memLevel;
777 fileInfo_.method = info->method;
778 fileInfo_.strategy = info->strategy;
779 fileInfo_.windowBits = info->windowBits;
780 }
781 return PKG_SUCCESS;
782 }
783 } // namespace Hpackage
784