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