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 
28 namespace Hpackage {
29 #ifdef _WIN32
30 #undef ERROR
31 #endif
32 
33 #ifdef __APPLE__
34 #define MAP_POPULATE 0x08000
35 #endif
36 
37 constexpr int32_t MIN_YEAR = 80;
38 constexpr uint32_t TM_YEAR_BITS = 9;
39 constexpr uint32_t TM_MON_BITS = 5;
40 constexpr uint32_t TM_MIN_BITS = 5;
41 constexpr uint32_t TM_HOUR_BITS = 11;
42 constexpr uint32_t BYTE_SIZE = 8;
43 constexpr uint32_t SECOND_BUFFER = 2;
44 constexpr uint32_t THIRD_BUFFER = 3;
45 constexpr uint8_t SHIFT_RIGHT_FOUR_BITS = 4;
46 
47 using namespace Updater::Utils;
48 
GetFilePath(const std::string & fileName)49 std::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 
GetFileSize(const std::string & fileName)58 size_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 
91 std::string GetName(const std::string &filePath)
92 {
93     return filePath.substr(filePath.find_last_of("/") + 1);
94 }
95 
96 int32_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 
137 int32_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 
161 uint8_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 
173 uint8_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 
195 void 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 
206 std::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 
219 void 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 
240 uint32_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 
257 uint64_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 
269 void 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 
285 uint16_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 
296 void 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 
306 std::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
322 void *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 
344 int msync(void *addr, size_t len, [[maybe_unused]] int flags)
345 {
346     return FlushViewOfFile(addr, len);
347 }
348 
349 int munmap(void *addr, [[maybe_unused]] size_t len)
350 {
351     return !UnmapViewOfFile(addr);
352 }
353 #endif
354