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 25namespace Hpackage { 26constexpr uint32_t TM_YEAR_BITS = 9; 27constexpr uint32_t TM_MON_BITS = 5; 28constexpr uint32_t TM_MIN_BITS = 5; 29constexpr uint32_t TM_HOUR_BITS = 11; 30constexpr uint32_t BIG_SIZE_HEADER = 20; 31constexpr uint32_t START_YEAR = 1900; 32constexpr uint32_t MAX_FILE_NAME = 256; 33constexpr uint32_t LOCAL_HEADER_SIGNATURE = 0x04034b50; 34constexpr uint32_t CENTRAL_SIGNATURE = 0x02014b50; 35constexpr uint32_t END_CENTRAL_SIGNATURE = 0x06054b50; 36constexpr uint32_t DATA_DESC_SIGNATURE = 0x08074b50; 37constexpr uint32_t MAX_BUFFER_SIZE = 1024 * 64; 38// mask value that signifies that the entry has a DD 39constexpr uint32_t GPBDD_FLAG_MASK = 0x0008; 40constexpr uint32_t ZIP_PKG_ALIGNMENT_DEF = 1; 41constexpr int32_t DEF_MEM_LEVEL = 8; 42constexpr int32_t Z_STORED = 0; 43 44int32_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 80int32_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 120int32_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 162int32_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 185int32_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 239int32_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 282int32_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 290int32_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 352int32_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 368int32_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 409int32_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 441int32_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 462int32_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*/ 512int32_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 547int32_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 584int32_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 637int32_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 662int32_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 707void 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 720int32_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 761int32_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