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