• 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_gzipfile.h"
16 #include "dump.h"
17 
18 using namespace std;
19 
20 namespace Hpackage {
21 /* gzip flag byte */
22 constexpr uint16_t HEADER_CRC = 0x02; /* bit 1 set: CRC16 for the gzip header */
23 constexpr uint16_t EXTRA_FIELD = 0x04; /* bit 2 set: extra field present */
24 constexpr uint16_t ORIG_NAME = 0x08; /* bit 3 set: original file name present */
25 constexpr uint16_t COMMENT = 0x10; /* bit 4 set: file comment present */
26 constexpr uint16_t ENCRYPTED = 0x20; /* bit 5 set: file is encrypted */
27 constexpr int32_t DEF_MEM_LEVEL = 8;
28 constexpr uint16_t GZIP_MAGIC = 0x8b1f;
29 constexpr int32_t BUFFER_SIZE = 1024;
30 #ifdef SUPPORT_EXTRA_FIELD
31 constexpr int32_t EXTRA_FIELD_LEN = 20;
32 #endif
33 constexpr int32_t BLOCK_SIZE = 8;
34 
35 /*
36     Each member has the following structure:
37      +---+---+---+---+---+---+---+---+---+---+
38      |ID1|ID2|CM |FLG|     MTIME     |XFL|OS | (more-->)
39      +---+---+---+---+---+---+---+---+---+---+
40 
41     (if FLG.FEXTRA set)
42 
43      +---+---+=================================+
44      | XLEN  |...XLEN bytes of "extra field"...| (more-->)
45      +---+---+=================================+
46 
47     (if FLG.FNAME set)
48 
49      +=========================================+
50      |...original file name, zero-terminated...| (more-->)
51      +=========================================+
52 
53     (if FLG.FCOMMENT set)
54 
55      +===================================+
56      |...file comment, zero-terminated...| (more-->)
57      +===================================+
58 
59     (if FLG.FHCRC set)
60 
61      +---+---+
62      | CRC16 |
63      +---+---+
64  */
GetUpGradeCompInfo(size_t & offset,PkgBuffer & buffer)65 void GZipFileEntry::GetUpGradeCompInfo(size_t &offset, PkgBuffer &buffer)
66 {
67     GZipHeader *header = (GZipHeader *)buffer.buffer;
68     header->magic = GZIP_MAGIC;
69     header->method = Z_DEFLATED;
70     header->flags = 0;
71     header->mtime = fileInfo_.fileInfo.modifiedTime;
72     offset += sizeof(GZipHeader);
73 #ifdef SUPPORT_EXTRA_FIELD
74     header->flags |= EXTRA_FIELD;
75     {
76         WriteLE16(buffer.buffer + offset, EXTRA_FIELD_LEN);
77         offset += sizeof(uint16_t) + EXTRA_FIELD_LEN;
78     }
79 #endif
80     header->flags |= ORIG_NAME;
81     {
82         size_t fileNameLen = 0;
83         PkgFileImpl::ConvertStringToBuffer(
84             fileInfo_.fileInfo.identity, {buffer.buffer + offset, buffer.length - offset}, fileNameLen);
85         offset += fileNameLen;
86         buffer.buffer[offset] = 0;
87         offset += 1;
88     }
89 #ifdef SUPPORT_EXTRA_FIELD
90     header->flags |= COMMENT;
91     {
92         size_t fileNameLen = 0;
93         PkgFileImpl::ConvertStringToBuffer(
94             fileInfo_.fileInfo.identity, {buffer.buffer + offset, buffer.length - offset}, fileNameLen);
95         offset += fileNameLen;
96         buffer.buffer[offset] = 0;
97         offset += 1;
98     }
99 #endif
100     return ;
101 }
102 
EncodeHeader(PkgStreamPtr inStream,size_t startOffset,size_t & encodeLen)103 int32_t GZipFileEntry::EncodeHeader(PkgStreamPtr inStream, size_t startOffset, size_t &encodeLen)
104 {
105     PkgStreamPtr outStream = pkgFile_->GetPkgStream();
106     if (outStream == nullptr) {
107         PKG_LOGE("Check outstream fail %s", fileInfo_.fileInfo.identity.c_str());
108         return PKG_INVALID_PARAM;
109     }
110     size_t offset = 0;
111     PkgBuffer buffer(BUFFER_SIZE);
112 
113     GetUpGradeCompInfo(offset, buffer);
114 
115     fileInfo_.fileInfo.headerOffset = startOffset;
116     fileInfo_.fileInfo.dataOffset = startOffset + offset;
117     int32_t ret = outStream->Write(buffer, offset, startOffset);
118     if (ret != PKG_SUCCESS) {
119         PKG_LOGE("Fail write header for %s", fileInfo_.fileInfo.identity.c_str());
120         return ret;
121     }
122     encodeLen = offset;
123     return PKG_SUCCESS;
124 }
125 
Pack(PkgStreamPtr inStream,size_t startOffset,size_t & encodeLen)126 int32_t GZipFileEntry::Pack(PkgStreamPtr inStream, size_t startOffset, size_t &encodeLen)
127 {
128     PkgAlgorithm::PkgAlgorithmPtr algorithm = PkgAlgorithmFactory::GetAlgorithm(&fileInfo_.fileInfo);
129     PkgStreamPtr outStream = pkgFile_->GetPkgStream();
130     if (fileInfo_.fileInfo.dataOffset != startOffset) {
131         PKG_LOGE("start offset error for %s", fileInfo_.fileInfo.identity.c_str());
132         return PKG_INVALID_PARAM;
133     }
134     if (algorithm == nullptr || outStream == nullptr || inStream == nullptr) {
135         PKG_LOGE("outStream or inStream null for %s", fileInfo_.fileInfo.identity.c_str());
136         return PKG_INVALID_PARAM;
137     }
138     fileInfo_.fileInfo.dataOffset = startOffset;
139     PkgAlgorithmContext context = {
140         {0, startOffset},
141         {fileInfo_.fileInfo.packedSize, fileInfo_.fileInfo.unpackedSize},
142         0, fileInfo_.fileInfo.digestMethod
143     };
144     int32_t ret = algorithm->Pack(inStream, outStream, context);
145     if (ret != PKG_SUCCESS) {
146         PKG_LOGE("Fail Compress for %s", fileInfo_.fileInfo.identity.c_str());
147         return ret;
148     }
149     fileInfo_.fileInfo.packedSize = context.packedSize;
150 
151     /*
152     0   1   2   3   4   5   6   7
153     +---+---+---+---+---+---+---+---+
154     |     CRC32     |     ISIZE     |
155     +---+---+---+---+---+---+---+---+
156     */
157     PkgBuffer buffer(BLOCK_SIZE);
158     WriteLE32(buffer.buffer, context.crc);
159     WriteLE32(buffer.buffer + sizeof(uint32_t), fileInfo_.fileInfo.unpackedSize);
160     ret = outStream->Write(buffer, BLOCK_SIZE, fileInfo_.fileInfo.dataOffset + fileInfo_.fileInfo.packedSize);
161     if (ret != PKG_SUCCESS) {
162         PKG_LOGE("Fail write header for %s", fileInfo_.fileInfo.identity.c_str());
163         return ret;
164     }
165     encodeLen = fileInfo_.fileInfo.packedSize + BLOCK_SIZE;
166     PKG_LOGI("Pack packedSize:%zu unpackedSize: %zu offset: %zu %zu", fileInfo_.fileInfo.packedSize,
167         fileInfo_.fileInfo.unpackedSize, fileInfo_.fileInfo.headerOffset, fileInfo_.fileInfo.dataOffset);
168     return PKG_SUCCESS;
169 }
170 
CheckFileInfo(PkgAlgorithmContext context,PkgStreamPtr inStream)171 int32_t GZipFileEntry::CheckFileInfo(PkgAlgorithmContext context, PkgStreamPtr inStream)
172 {
173     size_t readLen = 0;
174     fileInfo_.fileInfo.packedSize = context.packedSize;
175     PkgBuffer buffer(BLOCK_SIZE); // Read last 8 bytes at the end of package
176     int32_t ret = inStream->Read(buffer, context.packedSize + fileInfo_.fileInfo.dataOffset, BLOCK_SIZE, readLen);
177     if (ret != PKG_SUCCESS) {
178         PKG_LOGE("Fail to read file %s", inStream->GetFileName().c_str());
179         return ret;
180     }
181     crc32_ = ReadLE32(buffer.buffer);
182     fileInfo_.fileInfo.unpackedSize = ReadLE32(buffer.buffer + sizeof(uint32_t));
183     if (crc32_ != context.crc) {
184         PKG_LOGE("Crc error %u %u", crc32_, context.crc);
185         return PKG_VERIFY_FAIL;
186     }
187 
188     if (fileInfo_.fileInfo.unpackedSize != context.unpackedSize) {
189         PKG_LOGE("Crc error %u %u", crc32_, context.crc);
190         return PKG_VERIFY_FAIL;
191     }
192     return PKG_SUCCESS;
193 }
194 
Unpack(PkgStreamPtr outStream)195 int32_t GZipFileEntry::Unpack(PkgStreamPtr outStream)
196 {
197     PkgAlgorithm::PkgAlgorithmPtr algorithm = PkgAlgorithmFactory::GetAlgorithm(&fileInfo_.fileInfo);
198     if (algorithm == nullptr) {
199         PKG_LOGE("can not algorithm for %s", fileInfo_.fileInfo.identity.c_str());
200         return PKG_INVALID_PARAM;
201     }
202 
203     PKG_LOGI("packedSize: %zu unpackedSize: %zu  offset header: %zu data: %zu", fileInfo_.fileInfo.packedSize,
204         fileInfo_.fileInfo.unpackedSize, fileInfo_.fileInfo.headerOffset, fileInfo_.fileInfo.dataOffset);
205 
206     PkgStreamPtr inStream = pkgFile_->GetPkgStream();
207     if (outStream == nullptr || inStream == nullptr) {
208         PKG_LOGE("outStream or inStream null for %s", fileInfo_.fileInfo.identity.c_str());
209         return PKG_INVALID_PARAM;
210     }
211 
212     PkgAlgorithmContext context = {
213         {fileInfo_.fileInfo.dataOffset, 0},
214         {fileInfo_.fileInfo.packedSize, fileInfo_.fileInfo.unpackedSize},
215         0, fileInfo_.fileInfo.digestMethod
216     };
217     int32_t ret = algorithm->Unpack(inStream, outStream, context);
218     if (ret != PKG_SUCCESS) {
219         PKG_LOGE("Fail Decompress for %s", fileInfo_.fileInfo.identity.c_str());
220         return ret;
221     }
222 
223     ret = CheckFileInfo(context, inStream);
224     if (ret != PKG_SUCCESS) {
225         PKG_LOGE("unpack failed ret is %d", ret);
226         return ret;
227     }
228 
229     PKG_LOGI("packedSize: %zu unpackedSize: %zu  offset header: %zu data: %zu", fileInfo_.fileInfo.packedSize,
230         fileInfo_.fileInfo.unpackedSize, fileInfo_.fileInfo.headerOffset, fileInfo_.fileInfo.dataOffset);
231     outStream->Flush(fileInfo_.fileInfo.unpackedSize);
232     algorithm->UpdateFileInfo(&fileInfo_.fileInfo);
233     return PKG_SUCCESS;
234 }
235 
DecodeHeaderCalOffset(uint8_t flags,const PkgBuffer & buffer,size_t & offset,std::string & fileName) const236 void GZipFileEntry::DecodeHeaderCalOffset(uint8_t flags, const PkgBuffer &buffer, size_t &offset,
237     std::string &fileName) const
238 {
239     if (flags & EXTRA_FIELD) {
240         uint16_t extLen = ReadLE16(buffer.buffer + offset);
241         offset += sizeof(uint16_t) + extLen;
242     }
243     if (flags & ORIG_NAME) {
244         PkgFileImpl::ConvertBufferToString(fileName, {buffer.buffer + offset, buffer.length - offset});
245         offset += fileName.size() + 1;
246     }
247     if (flags & COMMENT) {
248         std::string comment;
249         PkgFileImpl::ConvertBufferToString(comment, {buffer.buffer + offset, buffer.length - offset});
250         offset += comment.size() + 1;
251     }
252     if (flags & HEADER_CRC) { // Skip CRC
253         offset += sizeof(uint16_t);
254     }
255     return;
256 }
257 
DecodeHeader(PkgBuffer & buffer,size_t headerOffset,size_t dataOffset,size_t & decodeLen)258 int32_t GZipFileEntry::DecodeHeader(PkgBuffer &buffer, size_t headerOffset, size_t dataOffset,
259     size_t &decodeLen)
260 {
261     Updater::UPDATER_INIT_RECORD;
262     PkgStreamPtr inStream = pkgFile_->GetPkgStream();
263     if (inStream == nullptr || buffer.buffer == nullptr) {
264         PKG_LOGE("outStream or inStream null for %s", fileInfo_.fileInfo.identity.c_str());
265         UPDATER_LAST_WORD(PKG_INVALID_PARAM);
266         return PKG_INVALID_PARAM;
267     }
268     size_t offset = sizeof(GZipHeader);
269 
270     uint8_t flags = *(buffer.buffer + offsetof(GZipHeader, flags));
271 
272     DecodeHeaderCalOffset(flags, buffer, offset, fileName_);
273     if (fileName_.empty()) {
274         fileInfo_.fileInfo.identity = "gzip_";
275         fileInfo_.fileInfo.identity.append(std::to_string(nodeId_));
276         fileName_ = fileInfo_.fileInfo.identity;
277     } else {
278         fileInfo_.fileInfo.identity = fileName_;
279     }
280     fileInfo_.fileInfo.digestMethod = PKG_DIGEST_TYPE_CRC;
281     fileInfo_.fileInfo.packMethod = PKG_COMPRESS_METHOD_GZIP;
282     fileInfo_.level = Z_BEST_COMPRESSION;
283     fileInfo_.method = Z_DEFLATED;
284     fileInfo_.windowBits = -MAX_WBITS;
285     fileInfo_.memLevel = DEF_MEM_LEVEL;
286     fileInfo_.strategy = Z_DEFAULT_STRATEGY;
287 
288     fileInfo_.fileInfo.headerOffset = headerOffset;
289     fileInfo_.fileInfo.dataOffset = headerOffset + offset;
290     // Read data length here.
291     // The length read here maybe incorrect, so should adjust it
292     // when unpack.
293     size_t readLen = 0;
294     size_t blockOffset = inStream->GetFileLength() - BLOCK_SIZE;
295     int32_t ret = inStream->Read(buffer, blockOffset, buffer.length, readLen);
296     if (ret != PKG_SUCCESS) {
297         PKG_LOGE("Fail to read file %s", inStream->GetFileName().c_str());
298         UPDATER_LAST_WORD(ret);
299         return ret;
300     }
301     fileInfo_.fileInfo.unpackedSize = ReadLE32(buffer.buffer + sizeof(uint32_t));
302     fileInfo_.fileInfo.packedSize = blockOffset - fileInfo_.fileInfo.dataOffset;
303     PKG_LOGI("GZipFileEntry::DecodeHeader dataOffset %zu, packedSize: %zu %zu", fileInfo_.fileInfo.dataOffset,
304         fileInfo_.fileInfo.packedSize, fileInfo_.fileInfo.unpackedSize);
305     decodeLen = offset;
306     return PKG_SUCCESS;
307 }
308 
AddEntry(const PkgManager::FileInfoPtr file,const PkgStreamPtr inStream)309 int32_t GZipPkgFile::AddEntry(const PkgManager::FileInfoPtr file, const PkgStreamPtr inStream)
310 {
311     if (file == nullptr || inStream == nullptr) {
312         PKG_LOGE("Fail to check input param");
313         return PKG_INVALID_PARAM;
314     }
315     if (!CheckState({PKG_FILE_STATE_IDLE, PKG_FILE_STATE_WORKING}, PKG_FILE_STATE_CLOSE)) {
316         PKG_LOGE("error state curr %d ", state_);
317         return PKG_INVALID_STATE;
318     }
319     PKG_LOGI("Add file %s to package", file->identity.c_str());
320 
321     GZipFileEntry *entry = static_cast<GZipFileEntry *>(AddPkgEntry(file->identity));
322     if (entry == nullptr) {
323         PKG_LOGE("Fail create pkg node for %s", file->identity.c_str());
324         return PKG_NONE_MEMORY;
325     }
326     int32_t ret = entry->Init(file, inStream);
327     if (ret != PKG_SUCCESS) {
328         PKG_LOGE("Fail init entry for %s", file->identity.c_str());
329         return ret;
330     }
331 
332     size_t encodeLen = 0;
333     ret = entry->EncodeHeader(inStream, currentOffset_, encodeLen);
334     if (ret != PKG_SUCCESS) {
335         PKG_LOGE("Fail encode header for %s", file->identity.c_str());
336         return ret;
337     }
338     currentOffset_ += encodeLen;
339     ret = entry->Pack(inStream, currentOffset_, encodeLen);
340     if (ret != PKG_SUCCESS) {
341         PKG_LOGE("Fail Pack for %s", file->identity.c_str());
342         return ret;
343     }
344     currentOffset_ += encodeLen;
345     pkgStream_->Flush(currentOffset_);
346     return PKG_SUCCESS;
347 }
348 
SavePackage(size_t & offset)349 int32_t GZipPkgFile::SavePackage(size_t &offset)
350 {
351     AddSignData(pkgInfo_.digestMethod, currentOffset_, offset);
352     return PKG_SUCCESS;
353 }
354 
LoadPackage(std::vector<std::string> & fileNames,VerifyFunction verifier)355 int32_t GZipPkgFile::LoadPackage(std::vector<std::string> &fileNames, VerifyFunction verifier)
356 {
357     UNUSED(verifier);
358     if (!CheckState({ PKG_FILE_STATE_IDLE }, PKG_FILE_STATE_WORKING)) {
359         PKG_LOGE("error state curr %d ", state_);
360         UPDATER_LAST_WORD(PKG_INVALID_STATE);
361         return PKG_INVALID_STATE;
362     }
363     PKG_LOGI("LoadPackage %s ", pkgStream_->GetFileName().c_str());
364     size_t srcOffset = 0;
365     size_t readLen = 0;
366     PkgBuffer buffer(nullptr, BUFFER_SIZE);
367     int32_t ret = pkgStream_->Read(buffer, srcOffset, buffer.length, readLen);
368     if (ret != PKG_SUCCESS) {
369         PKG_LOGE("Fail to read file %s", pkgStream_->GetFileName().c_str());
370         UPDATER_LAST_WORD(ret);
371         return ret;
372     }
373 
374     GZipHeader *header = (GZipHeader *)buffer.buffer;
375     // Check magic number
376     if (header->magic != GZIP_MAGIC) {
377         PKG_LOGE("Invalid gzip file %s", pkgStream_->GetFileName().c_str());
378         UPDATER_LAST_WORD(PKG_INVALID_STATE);
379         return PKG_INVALID_FILE;
380     }
381     // Does not support encryption
382     if ((header->flags & ENCRYPTED) != 0) {
383         PKG_LOGE("Not support encrypted ");
384         UPDATER_LAST_WORD(PKG_INVALID_STATE);
385         return PKG_INVALID_FILE;
386     }
387 
388     GZipFileEntry *entry = new GZipFileEntry(this, nodeId_++);
389     if (entry == nullptr) {
390         PKG_LOGE("Fail create gzip node for %s", pkgStream_->GetFileName().c_str());
391         UPDATER_LAST_WORD(PKG_INVALID_STATE);
392         return PKG_LZ4_FINISH;
393     }
394     ret = entry->DecodeHeader(buffer, srcOffset, srcOffset, readLen);
395     srcOffset += readLen;
396 
397     // Save entry
398     pkgEntryMapId_.insert(std::pair<uint32_t, PkgEntryPtr>(entry->GetNodeId(), entry));
399     pkgEntryMapFileName_.insert(std::pair<std::string, PkgEntryPtr>(entry->GetFileName(), entry));
400     fileNames.push_back(entry->GetFileName());
401     return ret;
402 }
403 } // namespace Hpackage
404