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_utils.h"
16#ifdef _WIN32
17#include <windows.h>
18#else
19#include <climits>
20#include <sys/mman.h>
21#endif
22#include <cstring>
23#include <fcntl.h>
24#include <sys/stat.h>
25#include <unistd.h>
26#include "utils.h"
27
28namespace Hpackage {
29#ifdef _WIN32
30#undef ERROR
31#endif
32
33#ifdef __APPLE__
34#define MAP_POPULATE 0x08000
35#endif
36
37constexpr int32_t MIN_YEAR = 80;
38constexpr uint32_t TM_YEAR_BITS = 9;
39constexpr uint32_t TM_MON_BITS = 5;
40constexpr uint32_t TM_MIN_BITS = 5;
41constexpr uint32_t TM_HOUR_BITS = 11;
42constexpr uint32_t BYTE_SIZE = 8;
43constexpr uint32_t SECOND_BUFFER = 2;
44constexpr uint32_t THIRD_BUFFER = 3;
45constexpr uint8_t SHIFT_RIGHT_FOUR_BITS = 4;
46
47using namespace Updater::Utils;
48
49std::string GetFilePath(const std::string &fileName)
50{
51    std::size_t pos = fileName.find_last_of('/');
52    if (pos == std::string::npos) {
53        pos = fileName.find_last_of('\\');
54    }
55    return fileName.substr(0, pos + 1);
56}
57
58size_t GetFileSize(const std::string &fileName)
59{
60    char realPath[PATH_MAX] = { 0 };
61#ifdef _WIN32
62    if (_fullpath(realPath, fileName.c_str(), PATH_MAX) == nullptr) {
63#else
64    if (realpath(fileName.c_str(), realPath) == nullptr) {
65#endif
66        PKG_LOGE("realPath is null");
67        return 0;
68    }
69    FILE *fp = fopen(realPath, "r");
70    if (fp == nullptr) {
71        PKG_LOGE("Invalid file %s", fileName.c_str());
72        return 0;
73    }
74
75    if (fseek(fp, 0, SEEK_END) < 0) {
76        PKG_LOGE("return value of fseek < 0");
77        fclose(fp);
78        return 0;
79    }
80    long size = ftell(fp);
81    if (size < 0) {
82        PKG_LOGE("return value of ftell < 0");
83        fclose(fp);
84        return 0;
85    }
86    fclose(fp);
87    // return file size in bytes
88    return static_cast<size_t>(size);
89}
90
91std::string GetName(const std::string &filePath)
92{
93    return filePath.substr(filePath.find_last_of("/") + 1);
94}
95
96int32_t CreatDirectory(const std::string &path, mode_t mode)
97{
98    size_t slashPos = 0;
99    struct stat info {};
100    while (true) {
101        slashPos = path.find_first_of("/", slashPos);
102        if (slashPos == std::string::npos) {
103            break;
104        }
105        if (slashPos == 0) {
106            slashPos++;
107            continue;
108        }
109        if (slashPos > PATH_MAX) {
110            PKG_LOGE("path too long");
111            return -1;
112        }
113        auto subDir = path.substr(0, slashPos);
114        if (stat(subDir.c_str(), &info) != 0) {
115#ifdef __WIN32
116            int ret = mkdir(subDir.c_str());
117#else
118            int ret = mkdir(subDir.c_str(), mode);
119#endif
120            if (ret && errno != EEXIST) {
121                return ret;
122            }
123        }
124        slashPos++;
125    }
126#ifdef __WIN32
127    int ret = mkdir(path.c_str());
128#else
129    int ret = mkdir(path.c_str(), mode);
130#endif
131    if (ret && errno != EEXIST) {
132        return ret;
133    }
134    return 0;
135}
136
137int32_t CheckFile(const std::string &fileName, int type)
138{
139    // Check if the directory of @fileName is exist or has write permission
140    // If not, Create the directory first.
141    std::string path = GetFilePath(fileName);
142    if (path.empty()) {
143        return PKG_SUCCESS;
144    }
145    if (access(path.c_str(), F_OK) == -1) {
146        CreatDirectory(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
147    }
148    int ret = -1;
149    if (type == PkgStream::PkgStreamType_Read) {
150        ret = access(path.c_str(), R_OK);
151    } else {
152        ret = access(path.c_str(), R_OK | W_OK);
153    }
154    if (ret == -1) {
155        PKG_LOGE("file %s no permission ", fileName.c_str());
156        return PKG_NONE_PERMISSION;
157    }
158    return PKG_SUCCESS;
159}
160
161uint8_t *AnonymousMap(const std::string &fileName, size_t size)
162{
163    void *mappedData = nullptr;
164    // Map memory for file
165    mappedData = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_POPULATE | MAP_ANON, -1, 0);
166    if (mappedData == MAP_FAILED) {
167        PKG_LOGE("Failed to alloc memory for file %s ", fileName.c_str());
168        return nullptr;
169    }
170    return static_cast<uint8_t *>(mappedData);
171}
172
173uint8_t *FileMap(const std::string &path)
174{
175    if (access(path.c_str(), 0) != 0) {
176        PKG_LOGE("Path not exist %s", path.c_str());
177        return nullptr;
178    }
179    int fd = open(path.c_str(), O_RDONLY);
180    if (fd < 0) {
181        PKG_LOGE("Failed to open file");
182        return nullptr;
183    }
184    size_t size = GetFileSize(path);
185    void *mappedData = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0);
186    if (mappedData == MAP_FAILED) {
187        close(fd);
188        PKG_LOGE("Failed to mmap file");
189        return nullptr;
190    }
191    close(fd);
192    return static_cast<uint8_t *>(mappedData);
193}
194
195void ReleaseMemory(uint8_t *memMap, size_t size)
196{
197    if (size <= 0 || memMap == nullptr) {
198        PKG_LOGE("Size must > 0");
199        return;
200    }
201    // Flush memory and release memory.
202    msync(static_cast<void *>(memMap), size, MS_ASYNC);
203    munmap(memMap, size);
204}
205
206std::string GetCurrPath()
207{
208    std::string path;
209    char *buffer = getcwd(nullptr, 0);
210    if (buffer == nullptr) {
211        PKG_LOGE("getcwd error");
212        return "./";
213    }
214    path.assign(buffer);
215    free(buffer);
216    return path + "/";
217}
218
219void ExtraTimeAndDate(time_t when, uint16_t &date, uint16_t &time)
220{
221    when = static_cast<time_t>((static_cast<unsigned long>(when) + 1) & (~1));
222    struct tm nowTime {};
223#ifdef __WIN32
224    localtime_s(&nowTime, &when);
225#else
226    localtime_r(&when, &nowTime);
227#endif
228    int year = nowTime.tm_year;
229    if (year < MIN_YEAR) {
230        year = MIN_YEAR;
231    }
232    date = static_cast<uint16_t>(static_cast<uint16_t>(year - MIN_YEAR) << TM_YEAR_BITS);
233    date |= static_cast<uint16_t>(static_cast<uint16_t>(nowTime.tm_mon + 1) << TM_MON_BITS);
234    date |= static_cast<uint16_t>(nowTime.tm_mday);
235    time = static_cast<uint16_t>(static_cast<uint16_t>(nowTime.tm_hour) << TM_HOUR_BITS);
236    time |= static_cast<uint16_t>(static_cast<uint16_t>(nowTime.tm_min) << TM_MIN_BITS);
237    time |= static_cast<uint16_t>(static_cast<uint16_t>(nowTime.tm_sec) >> 1);
238}
239
240uint32_t ReadLE32(const uint8_t *buff)
241{
242    if (buff == nullptr) {
243        PKG_LOGE("buff is null");
244        return 0;
245    }
246    size_t offset = 0;
247    uint32_t value32 = buff[0];
248    offset += BYTE_SIZE;
249    value32 += static_cast<uint32_t>(static_cast<uint32_t>(buff[1]) << offset);
250    offset +=  BYTE_SIZE;
251    value32 += static_cast<uint32_t>(static_cast<uint32_t>(buff[SECOND_BUFFER]) << offset);
252    offset += BYTE_SIZE;
253    value32 += static_cast<uint32_t>(static_cast<uint32_t>(buff[THIRD_BUFFER]) << offset);
254    return value32;
255}
256
257uint64_t ReadLE64(const uint8_t *buff)
258{
259    if (buff == nullptr) {
260        PKG_LOGE("buff is null");
261        return 0;
262    }
263    uint32_t low = ReadLE32(buff);
264    uint32_t high = ReadLE32(buff + sizeof(uint32_t));
265    uint64_t value = ((static_cast<uint64_t>(high)) << (BYTE_SIZE * sizeof(uint32_t))) | low;
266    return value;
267}
268
269void WriteLE32(uint8_t *buff, uint32_t value)
270{
271    if (buff == nullptr) {
272        PKG_LOGE("buff is null");
273        return;
274    }
275    size_t offset = 0;
276    buff[0] = static_cast<uint8_t>(value);
277    offset += BYTE_SIZE;
278    buff[1] = static_cast<uint8_t>(value >> offset);
279    offset += BYTE_SIZE;
280    buff[SECOND_BUFFER] = static_cast<uint8_t>(value >> offset);
281    offset += BYTE_SIZE;
282    buff[THIRD_BUFFER] = static_cast<uint8_t>(value >> offset);
283}
284
285uint16_t ReadLE16(const uint8_t *buff)
286{
287    if (buff == nullptr) {
288        PKG_LOGE("buff is null");
289        return 0;
290    }
291    uint16_t value16 = buff[0];
292    value16 += static_cast<uint16_t>(buff[1] << BYTE_SIZE);
293    return value16;
294}
295
296void WriteLE16(uint8_t *buff, uint16_t value)
297{
298    if (buff == nullptr) {
299        PKG_LOGE("buff is null");
300        return;
301    }
302    buff[0] = static_cast<uint8_t>(value);
303    buff[1] = static_cast<uint8_t>(value >> BYTE_SIZE);
304}
305
306std::string ConvertShaHex(const std::vector<uint8_t> &shaDigest)
307{
308    const std::string hexChars = "0123456789abcdef";
309    std::string haxSha256 = "";
310    unsigned int c;
311    for (size_t i = 0; i < shaDigest.size(); ++i) {
312        auto d = shaDigest[i];
313        c = (d >> SHIFT_RIGHT_FOUR_BITS) & 0xf;     // last 4 bits
314        haxSha256.push_back(hexChars[c]);
315        haxSha256.push_back(hexChars[d & 0xf]);
316    }
317    return haxSha256;
318}
319} // namespace Hpackage
320
321#ifdef _WIN32
322void *mmap([[maybe_unused]] void *addr, [[maybe_unused]] size_t length,
323    [[maybe_unused]] int prot, [[maybe_unused]] int flags, int fd, [[maybe_unused]] size_t offset)
324{
325    HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
326    if (FileHandle == INVALID_HANDLE_VALUE) {
327        return MAP_FAILED;
328    }
329    HANDLE FileMappingHandle = ::CreateFileMappingW(FileHandle, 0, PAGE_READONLY, 0, 0, 0);
330    if (FileMappingHandle == nullptr) {
331        PKG_LOGE("CreateFileMappingW Failed");
332        return MAP_FAILED;
333    }
334    void *mapAddr = ::MapViewOfFile(FileMappingHandle, FILE_MAP_READ, 0, 0, 0);
335    if (mapAddr == nullptr) {
336        PKG_LOGE("MapViewOfFile Failed");
337        ::CloseHandle(FileMappingHandle);
338        return MAP_FAILED;
339    }
340    ::CloseHandle(FileMappingHandle);
341    return mapAddr;
342}
343
344int msync(void *addr, size_t len, [[maybe_unused]] int flags)
345{
346    return FlushViewOfFile(addr, len);
347}
348
349int munmap(void *addr, [[maybe_unused]] size_t len)
350{
351    return !UnmapViewOfFile(addr);
352}
353#endif
354