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 "package/package.h"
16#include <cstdio>
17#include <cstdlib>
18#include <iostream>
19#include <memory>
20#include "log/log.h"
21#include "package/pkg_manager.h"
22#include "securec.h"
23
24using namespace Updater;
25using namespace Hpackage;
26constexpr uint32_t VERIFY_FINSH_PERCENT = 100;
27constexpr uint32_t MAX_ENTRY_COUNT = 4096;
28
29namespace {
30int32_t GetUpgradePkgInfo(UpgradePkgInfo *upgradePackageInfo,
31    std::vector<std::pair<std::string, ComponentInfo>> &files,
32    const UpgradePkgInfoExt *pkgInfoExt,
33    std::vector<ComponentInfoExt> &compInfo)
34{
35    if (pkgInfoExt->entryCount > MAX_ENTRY_COUNT) {
36        LOG(ERROR) << "entry count oversized " << pkgInfoExt->entryCount << ", " << MAX_ENTRY_COUNT;
37        return PKG_INVALID_PARAM;
38    }
39
40    upgradePackageInfo->updateFileVersion = pkgInfoExt->updateFileVersion;
41    if (pkgInfoExt->softwareVersion != nullptr) {
42        upgradePackageInfo->softwareVersion = pkgInfoExt->softwareVersion;
43    }
44    if (pkgInfoExt->productUpdateId != nullptr) {
45        upgradePackageInfo->productUpdateId = pkgInfoExt->productUpdateId;
46    }
47    if (pkgInfoExt->descriptPackageId != nullptr) {
48        upgradePackageInfo->descriptPackageId = pkgInfoExt->descriptPackageId;
49    }
50    if (pkgInfoExt->time != nullptr) {
51        upgradePackageInfo->time = pkgInfoExt->time;
52    }
53    if (pkgInfoExt->date != nullptr) {
54        upgradePackageInfo->date = pkgInfoExt->date;
55    }
56    upgradePackageInfo->pkgInfo.digestMethod = pkgInfoExt->digestMethod;
57    upgradePackageInfo->pkgInfo.signMethod = pkgInfoExt->signMethod;
58    upgradePackageInfo->pkgInfo.entryCount = pkgInfoExt->entryCount;
59    upgradePackageInfo->pkgInfo.pkgType = PKG_PACK_TYPE_UPGRADE;
60    files.resize(pkgInfoExt->entryCount);
61    for (uint32_t i = 0; i < pkgInfoExt->entryCount; i++) {
62        files[i].first.assign(compInfo[i].filePath);
63        ComponentInfo* info = &files[i].second;
64        if (memcpy_s(info->digest, sizeof(info->digest), compInfo[i].digest, sizeof(info->digest)) != EOK) {
65            LOG(ERROR) << "GetUpgradePkgInfo memcpy failed";
66            return PKG_NONE_MEMORY;
67        }
68        info->fileInfo.identity.assign(compInfo[i].componentAddr);
69        info->fileInfo.unpackedSize = compInfo[i].size;
70        info->fileInfo.packedSize = compInfo[i].size;
71        info->fileInfo.packMethod = PKG_COMPRESS_METHOD_NONE;
72        info->fileInfo.digestMethod = pkgInfoExt->digestMethod;
73        info->version.assign(compInfo[i].version);
74        info->id = compInfo[i].id;
75        info->resType = compInfo[i].resType;
76        info->type = compInfo[i].type;
77        info->originalSize = compInfo[i].originalSize;
78        info->compFlags = compInfo[i].flags;
79    }
80    return PKG_SUCCESS;
81}
82
83int32_t GetZipPkgInfo(PkgManager::PkgInfoPtr pkgInfo,
84    std::vector<std::pair<std::string, ZipFileInfo>> &files,
85    const UpgradePkgInfoExt *pkgInfoExt,
86    std::vector<ComponentInfoExt> &compInfo)
87{
88    if (pkgInfoExt->entryCount > MAX_ENTRY_COUNT) {
89        LOG(ERROR) << "entry count oversized " << pkgInfoExt->entryCount << ", " << MAX_ENTRY_COUNT;
90        return PKG_INVALID_PARAM;
91    }
92
93    pkgInfo->signMethod = pkgInfoExt->signMethod;
94    pkgInfo->digestMethod  = pkgInfoExt->digestMethod;
95    pkgInfo->entryCount = pkgInfoExt->entryCount;
96    pkgInfo->pkgType = pkgInfoExt->pkgType;
97    files.resize(pkgInfoExt->entryCount);
98    for (uint32_t i = 0; i < pkgInfo->entryCount; i++) {
99        files[i].first.assign(compInfo[i].filePath);
100        ZipFileInfo* info = &files[i].second;
101        info->fileInfo.identity.assign(compInfo[i].componentAddr);
102        info->fileInfo.packMethod = PKG_COMPRESS_METHOD_ZIP;
103        info->fileInfo.digestMethod = PKG_DIGEST_TYPE_CRC;
104    }
105    return PKG_SUCCESS;
106}
107
108int32_t GetLz4PkgInfo(PkgManager::PkgInfoPtr pkgInfo,
109    std::vector<std::pair<std::string, Lz4FileInfo>> &files,
110    const UpgradePkgInfoExt *pkgInfoExt,
111    std::vector<ComponentInfoExt> &compInfo)
112{
113    if (pkgInfoExt->entryCount > MAX_ENTRY_COUNT) {
114        LOG(ERROR) << "entry count oversized " << pkgInfoExt->entryCount << ", " << MAX_ENTRY_COUNT;
115        return PKG_INVALID_PARAM;
116    }
117
118    pkgInfo->signMethod = pkgInfoExt->signMethod;
119    pkgInfo->digestMethod  = pkgInfoExt->digestMethod;
120    pkgInfo->entryCount = pkgInfoExt->entryCount;
121    pkgInfo->pkgType = PKG_PACK_TYPE_LZ4;
122    files.resize(pkgInfoExt->entryCount);
123    for (uint32_t i = 0; i < pkgInfoExt->entryCount; i++) {
124        files[i].first.assign(compInfo[i].filePath);
125        Lz4FileInfo* info = &files[i].second;
126        info->fileInfo.identity.assign(compInfo[i].componentAddr);
127        info->fileInfo.packMethod = PKG_COMPRESS_METHOD_LZ4;
128        info->fileInfo.digestMethod = PKG_DIGEST_TYPE_CRC;
129        info->compressionLevel = MID_COMPRESS_LEVEL;
130        info->blockSizeID = 0;
131        info->contentChecksumFlag = 0;
132        info->blockIndependence = 0;
133    }
134    return PKG_SUCCESS;
135}
136}
137
138int32_t CreatePackage(const UpgradePkgInfoExt *pkgInfoExt,
139    std::vector<ComponentInfoExt> &compInfo,
140    const char *path,
141    const char *keyPath)
142{
143    if (pkgInfoExt == nullptr || path == nullptr || keyPath == nullptr || pkgInfoExt->entryCount > compInfo.size()) {
144        LOG(ERROR) << "Check param fail ";
145        return PKG_INVALID_PARAM;
146    }
147    PkgManager::PkgManagerPtr manager = PkgManager::CreatePackageInstance();
148    if (manager == nullptr) {
149        LOG(ERROR) << "CreatePackageInstance fail ";
150        return PKG_INVALID_PARAM;
151    }
152
153    int32_t ret = PKG_SUCCESS;
154    switch (pkgInfoExt->pkgType) {
155        case PKG_PACK_TYPE_UPGRADE: {
156            UpgradePkgInfo upgradePackageInfo;
157            std::vector<std::pair<std::string, ComponentInfo>> files;
158            ret = GetUpgradePkgInfo(&upgradePackageInfo, files, pkgInfoExt, compInfo);
159            if (ret == PKG_SUCCESS) {
160                ret = manager->CreatePackage(path, keyPath, &upgradePackageInfo.pkgInfo, files);
161            }
162            break;
163        }
164        case PKG_PACK_TYPE_ZIP:
165        case PKG_PACK_TYPE_GZIP: {
166            PkgInfo info;
167            std::vector<std::pair<std::string, ZipFileInfo>> files;
168            ret = GetZipPkgInfo(&info, files, pkgInfoExt, compInfo);
169            if (ret == PKG_SUCCESS) {
170                ret = manager->CreatePackage(path, keyPath, &info, files);
171            }
172            break;
173        }
174        case PKG_PACK_TYPE_LZ4: {
175            PkgInfo info;
176            std::vector<std::pair<std::string, Lz4FileInfo>> files;
177            ret = GetLz4PkgInfo(&info, files, pkgInfoExt, compInfo);
178            if (ret == PKG_SUCCESS) {
179                ret = manager->CreatePackage(path, keyPath, &info, files);
180            }
181            break;
182        }
183        default:
184            ret = PKG_INVALID_PARAM;
185            break;
186    }
187    PkgManager::ReleasePackageInstance(manager);
188    return ret;
189}
190
191int32_t VerifyPackage(const char *packagePath,
192    const char *keyPath,
193    const char *version,
194    const uint8_t *digest,
195    size_t size)
196{
197    if (packagePath == nullptr || keyPath == nullptr || version == nullptr) {
198        LOG(ERROR) << "Check param fail";
199        return PKG_INVALID_PARAM;
200    }
201    PkgManager::PkgManagerPtr manager = PkgManager::CreatePackageInstance();
202    if (manager == nullptr) {
203        LOG(ERROR) << "CreatePackageInstance fail";
204        return PKG_INVALID_PARAM;
205    }
206
207    PkgBuffer digestBuffer(const_cast<uint8_t*>(digest), size);
208    int32_t ret = manager->VerifyPackage(packagePath, keyPath, version, digestBuffer,
209        [](int32_t result, uint32_t percent) {});
210    PkgManager::ReleasePackageInstance(manager);
211    return ret;
212}
213
214int32_t VerifyPackageWithCallback(const std::string &packagePath,
215    const std::string &keyPath, std::function<void(int32_t result, uint32_t percent)> cb)
216{
217    if (packagePath.empty() || keyPath.empty() || cb == nullptr) {
218        return PKG_INVALID_PARAM;
219    }
220
221    PkgManager *manager = PkgManager::CreatePackageInstance();
222    if (manager == nullptr) {
223        LOG(ERROR) << "CreatePackageInstance fail";
224        return PKG_INVALID_PARAM;
225    }
226    PkgBuffer digestBuffer {};
227    std::string version {};
228    int32_t ret = manager->VerifyPackage(packagePath, keyPath, version, digestBuffer, cb);
229    if (ret != 0) {
230        cb(ret, VERIFY_FINSH_PERCENT);
231    }
232    PkgManager::ReleasePackageInstance(manager);
233    return ret;
234}
235
236int32_t ExtraPackageDir(const char *packagePath, [[maybe_unused]] const char *keyPath, const char *dir,
237    const char *outPath)
238{
239    if (packagePath == nullptr || outPath == nullptr) {
240        LOG(ERROR) << "Check param fail ";
241        return PKG_INVALID_PARAM;
242    }
243    PkgManager::PkgManagerPtr manager = PkgManager::CreatePackageInstance();
244    if (manager == nullptr) {
245        LOG(ERROR) << "CreatePackageInstance fail ";
246        return PKG_INVALID_PARAM;
247    }
248
249    std::vector<std::string> components;
250    int32_t ret = manager->LoadPackageWithoutUnPack(std::string(packagePath), components);
251    if (ret != PKG_SUCCESS) {
252        LOG(ERROR) << "LoadPackageWithoutUnPack fail";
253        PkgManager::ReleasePackageInstance(manager);
254        return ret;
255    }
256
257    for (size_t i = 0; i < components.size(); i++) {
258        if (dir != nullptr && components[i].compare(0, strlen(dir), dir) != 0) {
259            continue;
260        }
261        PkgManager::StreamPtr outStream = nullptr;
262        manager->CreatePkgStream(outStream, std::string(outPath) + components[i], 0, PkgStream::PkgStreamType_Write);
263        if (outStream == nullptr) {
264            LOG(ERROR) << "CreatePkgStream fail";
265            PkgManager::ReleasePackageInstance(manager);
266            return PKG_INVALID_STREAM;
267        }
268        manager->ExtractFile(components[i], outStream);
269        manager->ClosePkgStream(outStream);
270    }
271    PkgManager::ReleasePackageInstance(manager);
272    return PKG_SUCCESS;
273}
274
275int32_t ExtraPackageFile(const char *packagePath, [[maybe_unused]] const char *keyPath, const char *file,
276    const char *outPath)
277{
278    if (packagePath == nullptr || outPath == nullptr || file == nullptr) {
279        LOG(ERROR) << "Check param fail ";
280        return PKG_INVALID_PARAM;
281    }
282
283    PkgManager::PkgManagerPtr manager = PkgManager::CreatePackageInstance();
284    if (manager == nullptr) {
285        LOG(ERROR) << "Check param fail ";
286        return PKG_INVALID_PARAM;
287    }
288
289    std::vector<std::string> components;
290    int32_t ret = manager->LoadPackageWithoutUnPack(std::string(packagePath), components);
291    if (ret != PKG_SUCCESS) {
292        LOG(ERROR) << "LoadPackageWithoutUnPack fail";
293        PkgManager::ReleasePackageInstance(manager);
294        return ret;
295    }
296
297    PkgManager::StreamPtr outStream = nullptr;
298    manager->CreatePkgStream(outStream, std::string(outPath) + file, 0, PkgStream::PkgStreamType_Write);
299    if (outStream == nullptr) {
300        LOG(ERROR) << "CreatePkgStream fail";
301        PkgManager::ReleasePackageInstance(manager);
302        return PKG_INVALID_STREAM;
303    }
304    manager->ExtractFile(file, outStream);
305
306    manager->ClosePkgStream(outStream);
307    PkgManager::ReleasePackageInstance(manager);
308    return PKG_SUCCESS;
309}
310