1 /*
2 * Copyright (c) 2024 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
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <sys/stat.h>
20 #include <errno.h>
21 #include <unistd.h>
22
23 #include <dirent.h>
24 #ifdef _WIN32
25 #include <windows.h>
26
27 #endif
28
29 #include "zlib.h"
30 #include "contrib/minizip/zip.h"
31 #include "contrib/minizip/unzip.h"
32
33 #include "securec.h"
34
35 #include "hnp_base.h"
36
37 #ifdef __cplusplus
38 extern "C" {
39 #endif
40
41 #define ZIP_EXTERNAL_FA_OFFSET 16
42
43 // zipOpenNewFileInZip3只识别带‘/’的路径,需要将路径中‘\’转换成‘/’
TransPath(const char * input,char * output)44 static void TransPath(const char *input, char *output)
45 {
46 int len = strlen(input);
47 for (int i = 0; i < len; i++) {
48 if (input[i] == '\\') {
49 output[i] = '/';
50 } else {
51 output[i] = input[i];
52 }
53 }
54 output[len] = '\0';
55 }
56
57 #ifdef _WIN32
58 // 转换char路径字符串为wchar_t宽字符串,支持路径字符串长度超过260
TransWidePath(const char * inPath,wchar_t * outPath)59 static bool TransWidePath(const char *inPath, wchar_t *outPath)
60 {
61 wchar_t tmpPath[MAX_FILE_PATH_LEN] = {0};
62 MultiByteToWideChar(CP_ACP, 0, inPath, -1, tmpPath, MAX_FILE_PATH_LEN);
63 if (swprintf_s(outPath, MAX_FILE_PATH_LEN, L"\\\\?\\%ls", tmpPath) < 0) {
64 HNP_LOGE("swprintf unsuccess.");
65 return false;
66 }
67 return true;
68 }
69 #endif
70
71 // 向zip压缩包中添加文件
ZipAddFile(const char * file,int offset,zipFile zf)72 static int ZipAddFile(const char* file, int offset, zipFile zf)
73 {
74 int err;
75 char buf[1024];
76 char transPath[MAX_FILE_PATH_LEN];
77 size_t len;
78 FILE *f;
79 zip_fileinfo fileInfo = {0};
80
81 #ifdef _WIN32
82 struct _stat buffer = {0};
83 // 使用wchar_t支持处理字符串长度超过260的路径字符串
84 wchar_t wideFullPath[MAX_FILE_PATH_LEN] = {0};
85 if (!TransWidePath(file, wideFullPath)) {
86 return HNP_ERRNO_BASE_STAT_FAILED;
87 }
88 if (_wstat(wideFullPath, &buffer) != 0) {
89 HNP_LOGE("get filefile[%{public}s] stat fail.", file);
90 return HNP_ERRNO_BASE_STAT_FAILED;
91 }
92 buffer.st_mode |= S_IXOTH;
93 #else
94 struct stat buffer = {0};
95 if (stat(file, &buffer) != 0) {
96 HNP_LOGE("get filefile[%{public}s] stat fail.", file);
97 return HNP_ERRNO_BASE_STAT_FAILED;
98 }
99 #endif
100 fileInfo.external_fa = (buffer.st_mode & 0xFFFF) << ZIP_EXTERNAL_FA_OFFSET;
101 TransPath(file, transPath);
102 err = zipOpenNewFileInZip3(zf, transPath + offset, &fileInfo, NULL, 0, NULL, 0, NULL, Z_DEFLATED,
103 Z_BEST_COMPRESSION, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0);
104 if (err != ZIP_OK) {
105 HNP_LOGE("open new file[%{public}s] in zip unsuccess ", file);
106 return HNP_ERRNO_BASE_CREATE_ZIP_FAILED;
107 }
108 #ifdef _WIN32
109 f = _wfopen(wideFullPath, L"rb");
110 #else
111 f = fopen(file, "rb");
112 #endif
113 if (f == NULL) {
114 HNP_LOGE("open file[%{public}s] unsuccess ", file);
115 return HNP_ERRNO_BASE_FILE_OPEN_FAILED;
116 }
117
118 while ((len = fread(buf, 1, sizeof(buf), f)) > 0) {
119 zipWriteInFileInZip(zf, buf, len);
120 }
121 (void)fclose(f);
122 zipCloseFileInZip(zf);
123 return 0;
124 }
125
126 // 判断是否为目录
IsDirPath(struct dirent * entry,char * fullPath,int * isDir)127 static int IsDirPath(struct dirent *entry, char *fullPath, int *isDir)
128 {
129 #ifdef _WIN32
130 // 使用wchar_t支持处理字符串长度超过260的路径字符串
131 wchar_t wideFullPath[MAX_FILE_PATH_LEN] = {0};
132 if (!TransWidePath(fullPath, wideFullPath)) {
133 return HNP_ERRNO_GET_FILE_ATTR_FAILED;
134 }
135 DWORD fileAttr = GetFileAttributesW(wideFullPath);
136 if (fileAttr == INVALID_FILE_ATTRIBUTES) {
137 DWORD err = GetLastError();
138 HNP_LOGE("get file[%{public}s] attr unsuccess, errno[%{public}lu].", fullPath, err);
139 return HNP_ERRNO_GET_FILE_ATTR_FAILED;
140 }
141 *isDir = (int)(fileAttr & FILE_ATTRIBUTE_DIRECTORY);
142 #else
143 *isDir = (int)(entry->d_type == DT_DIR);
144 #endif
145
146 return 0;
147 }
148
149 static int ZipAddDir(const char *sourcePath, int offset, zipFile zf);
150
ZipHandleDir(char * fullPath,int offset,zipFile zf)151 static int ZipHandleDir(char *fullPath, int offset, zipFile zf)
152 {
153 int ret;
154 char transPath[MAX_FILE_PATH_LEN];
155 TransPath(fullPath, transPath);
156 if (zipOpenNewFileInZip3(zf, transPath + offset, NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED,
157 Z_BEST_COMPRESSION, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
158 NULL, 0) != ZIP_OK) {
159 HNP_LOGE("open new file[%{public}s] in zip unsuccess ", fullPath);
160 return HNP_ERRNO_BASE_CREATE_ZIP_FAILED;
161 }
162 zipCloseFileInZip(zf);
163 ret = ZipAddDir(fullPath, offset, zf);
164 if (ret != 0) {
165 HNP_LOGE("zip add dir[%{public}s] unsuccess ", fullPath);
166 return ret;
167 }
168 return 0;
169 }
170
171 // sourcePath--文件夹路径 zf--压缩文件句柄
ZipAddDir(const char * sourcePath,int offset,zipFile zf)172 static int ZipAddDir(const char *sourcePath, int offset, zipFile zf)
173 {
174 struct dirent *entry;
175 char fullPath[MAX_FILE_PATH_LEN];
176 int isDir;
177
178 DIR *dir = opendir(sourcePath);
179 if (dir == NULL) {
180 HNP_LOGE("open dir=%{public}s unsuccess ", sourcePath);
181 return HNP_ERRNO_BASE_DIR_OPEN_FAILED;
182 }
183
184 while ((entry = readdir(dir)) != NULL) {
185 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
186 continue;
187 }
188 if (sprintf_s(fullPath, MAX_FILE_PATH_LEN, "%s%s", sourcePath, entry->d_name) < 0) {
189 HNP_LOGE("sprintf unsuccess.");
190 closedir(dir);
191 return HNP_ERRNO_BASE_SPRINTF_FAILED;
192 }
193 int ret = IsDirPath(entry, fullPath, &isDir);
194 if (ret != 0) {
195 closedir(dir);
196 return ret;
197 }
198 if (isDir) {
199 int endPos = strlen(fullPath);
200 if (endPos + 1 < MAX_FILE_PATH_LEN) {
201 fullPath[endPos] = DIR_SPLIT_SYMBOL;
202 fullPath[endPos + 1] = '\0';
203 } else {
204 closedir(dir);
205 return HNP_ERRNO_BASE_STRING_LEN_OVER_LIMIT;
206 }
207 ret = ZipHandleDir(fullPath, offset, zf);
208 if (ret != 0) {
209 closedir(dir);
210 return ret;
211 }
212 } else if ((ret = ZipAddFile(fullPath, offset, zf)) != 0) {
213 HNP_LOGE("zip add file[%{public}s] unsuccess ", fullPath);
214 closedir(dir);
215 return ret;
216 }
217 }
218 closedir(dir);
219
220 return 0;
221 }
222
ZipDir(const char * sourcePath,int offset,zipFile zf)223 static int ZipDir(const char *sourcePath, int offset, zipFile zf)
224 {
225 int ret;
226 char transPath[MAX_FILE_PATH_LEN];
227
228 TransPath(sourcePath, transPath);
229
230 // 将外层文件夹信息保存到zip文件中
231 ret = zipOpenNewFileInZip3(zf, transPath + offset, NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_BEST_COMPRESSION,
232 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0);
233 if (ret != ZIP_OK) {
234 HNP_LOGE("open new file[%{public}s] in zip unsuccess ", sourcePath + offset);
235 return HNP_ERRNO_BASE_CREATE_ZIP_FAILED;
236 }
237 zipCloseFileInZip(zf);
238 ret = ZipAddDir(sourcePath, offset, zf);
239
240 return ret;
241 }
242
HnpZip(const char * inputDir,zipFile zf)243 int HnpZip(const char *inputDir, zipFile zf)
244 {
245 int ret;
246 char *strPtr;
247 int offset;
248 char sourcePath[MAX_FILE_PATH_LEN];
249
250 // zip压缩文件内只保存相对路径,不保存绝对路径信息,偏移到压缩文件夹位置
251 strPtr = strrchr(inputDir, DIR_SPLIT_SYMBOL);
252 if (strPtr == NULL) {
253 offset = 0;
254 } else {
255 offset = strPtr - inputDir + 1;
256 }
257
258 // zip函数根据后缀是否'/'区分目录还是文件
259 ret = sprintf_s(sourcePath, MAX_FILE_PATH_LEN, "%s%c", inputDir, DIR_SPLIT_SYMBOL);
260 if (ret < 0) {
261 HNP_LOGE("sprintf unsuccess.");
262 return HNP_ERRNO_BASE_SPRINTF_FAILED;
263 }
264
265 ret = ZipDir(sourcePath, offset, zf);
266
267 return ret;
268 }
269
HnpAddFileToZip(zipFile zf,char * filename,char * buff,int size)270 int HnpAddFileToZip(zipFile zf, char *filename, char *buff, int size)
271 {
272 int ret;
273 char transPath[MAX_FILE_PATH_LEN];
274
275 TransPath(filename, transPath);
276
277 // 将外层文件夹信息保存到zip文件中
278 ret = zipOpenNewFileInZip3(zf, transPath, NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_BEST_COMPRESSION,
279 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0);
280 if (ret != ZIP_OK) {
281 HNP_LOGE("open new file[%{public}s] in zip unsuccess ", filename);
282 return HNP_ERRNO_BASE_CREATE_ZIP_FAILED;
283 }
284 zipWriteInFileInZip(zf, buff, size);
285 zipCloseFileInZip(zf);
286
287 return 0;
288 }
289
HnpUnZipForFile(const char * filePath,unzFile zipFile,unz_file_info fileInfo)290 static int HnpUnZipForFile(const char *filePath, unzFile zipFile, unz_file_info fileInfo)
291 {
292 #ifdef _WIN32
293 return 0;
294 #else
295 int ret;
296 mode_t mode = (fileInfo.external_fa >> ZIP_EXTERNAL_FA_OFFSET) & 0xFFFF;
297
298 /* 如果解压缩的是目录 */
299 if (filePath[strlen(filePath) - 1] == '/') {
300 mkdir(filePath, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
301 } else {
302 FILE *outFile = fopen(filePath, "wb");
303 if (outFile == NULL) {
304 HNP_LOGE("unzip open file:%{public}s unsuccess!", filePath);
305 return HNP_ERRNO_BASE_FILE_OPEN_FAILED;
306 }
307 unzOpenCurrentFile(zipFile);
308 int readSize = 0;
309 do {
310 char buffer[BUFFER_SIZE];
311 readSize = unzReadCurrentFile(zipFile, buffer, sizeof(buffer));
312 if (readSize < 0) {
313 HNP_LOGE("unzip read zip:%{public}s file unsuccess", (char *)zipFile);
314 fclose(outFile);
315 unzCloseCurrentFile(zipFile);
316 return HNP_ERRNO_BASE_UNZIP_READ_FAILED;
317 }
318
319 fwrite(buffer, readSize, sizeof(char), outFile);
320 } while (readSize > 0);
321
322 fclose(outFile);
323 unzCloseCurrentFile(zipFile);
324 /* 如果其他人有可执行权限,那么将解压后的权限设置成755,否则为744 */
325 if ((mode & S_IXOTH) != 0) {
326 ret = chmod(filePath, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
327 } else {
328 ret = chmod(filePath, S_IRWXU | S_IRGRP | S_IROTH);
329 }
330 if (ret != 0) {
331 HNP_LOGE("hnp install chmod unsuccess, src:%{public}s, errno:%{public}d", filePath, errno);
332 return HNP_ERRNO_BASE_CHMOD_FAILED;
333 }
334 }
335 return 0;
336 #endif
337 }
338
HnpELFFileCheck(const char * path)339 static bool HnpELFFileCheck(const char *path)
340 {
341 FILE *fp;
342 char buff[HNP_ELF_FILE_CHECK_HEAD_LEN];
343
344 fp = fopen(path, "rb");
345 if (fp == NULL) {
346 return false;
347 }
348
349 size_t readLen = fread(buff, sizeof(char), HNP_ELF_FILE_CHECK_HEAD_LEN, fp);
350 if (readLen != HNP_ELF_FILE_CHECK_HEAD_LEN) {
351 (void)fclose(fp);
352 return false;
353 }
354
355 if (buff[HNP_INDEX_0] == 0x7F && buff[HNP_INDEX_1] == 'E' && buff[HNP_INDEX_2] == 'L' && buff[HNP_INDEX_3] == 'F') {
356 (void)fclose(fp);
357 return true;
358 }
359
360 (void)fclose(fp);
361 return false;
362 }
363
HnpInstallAddSignMap(const char * hnpSignKeyPrefix,const char * key,const char * value,HnpSignMapInfo * hnpSignMapInfos,int * count)364 static int HnpInstallAddSignMap(const char* hnpSignKeyPrefix, const char *key, const char *value,
365 HnpSignMapInfo *hnpSignMapInfos, int *count)
366 {
367 int ret;
368 int sum = *count;
369
370 if (HnpELFFileCheck(value) == false) {
371 return 0;
372 }
373
374 ret = sprintf_s(hnpSignMapInfos[sum].key, MAX_FILE_PATH_LEN, "%s!/%s", hnpSignKeyPrefix, key);
375 if (ret < 0) {
376 HNP_LOGE("add sign map sprintf unsuccess.");
377 return HNP_ERRNO_BASE_SPRINTF_FAILED;
378 }
379
380 ret = strcpy_s(hnpSignMapInfos[sum].value, MAX_FILE_PATH_LEN, value);
381 if (ret != EOK) {
382 HNP_LOGE("add sign map strcpy[%{public}s] unsuccess.", value);
383 return HNP_ERRNO_BASE_COPY_FAILED;
384 }
385
386 *count = sum + 1;
387 return 0;
388 }
389
HnpFileCountGet(const char * path,int * count)390 int HnpFileCountGet(const char *path, int *count)
391 {
392 int sum = 0;
393
394 unzFile zipFile = unzOpen(path);
395 if (zipFile == NULL) {
396 HNP_LOGE("unzip open hnp:%{public}s unsuccess!", path);
397 return HNP_ERRNO_BASE_UNZIP_OPEN_FAILED;
398 }
399
400 int ret = unzGoToFirstFile(zipFile);
401 while (ret == UNZ_OK) {
402 if (sum == INT_MAX) {
403 unzClose(zipFile);
404 return HNP_ERRNO_BASE_FILE_COUNT_OVER;
405 }
406 sum++;
407 ret = unzGetCurrentFileInfo(zipFile, NULL, NULL, 0, NULL, 0, NULL, 0);
408 if (ret != UNZ_OK) {
409 HNP_LOGE("unzip get zip:%{public}s info unsuccess!", path);
410 unzClose(zipFile);
411 return HNP_ERRNO_BASE_UNZIP_GET_INFO_FAILED;
412 }
413
414 ret = unzGoToNextFile(zipFile);
415 }
416
417 unzClose(zipFile);
418 if (INT_MAX - sum < *count) {
419 return HNP_ERRNO_BASE_FILE_COUNT_OVER;
420 }
421 *count += sum;
422 return 0;
423 }
424
HnpUnZip(const char * inputFile,const char * outputDir,const char * hnpSignKeyPrefix,HnpSignMapInfo * hnpSignMapInfos,int * count)425 int HnpUnZip(const char *inputFile, const char *outputDir, const char *hnpSignKeyPrefix,
426 HnpSignMapInfo *hnpSignMapInfos, int *count)
427 {
428 char fileName[MAX_FILE_PATH_LEN];
429 unz_file_info fileInfo;
430 char filePath[MAX_FILE_PATH_LEN];
431
432 HNP_LOGI("HnpUnZip zip=%{public}s, output=%{public}s", inputFile, outputDir);
433
434 unzFile zipFile = unzOpen(inputFile);
435 if (zipFile == NULL) {
436 HNP_LOGE("unzip open hnp:%{public}s unsuccess!", inputFile);
437 return HNP_ERRNO_BASE_UNZIP_OPEN_FAILED;
438 }
439
440 int result = unzGoToFirstFile(zipFile);
441 while (result == UNZ_OK) {
442 result = unzGetCurrentFileInfo(zipFile, &fileInfo, fileName, sizeof(fileName), NULL, 0, NULL, 0);
443 if (result != UNZ_OK) {
444 HNP_LOGE("unzip get zip:%{public}s info unsuccess!", inputFile);
445 unzClose(zipFile);
446 return HNP_ERRNO_BASE_UNZIP_GET_INFO_FAILED;
447 }
448 if (strstr(fileName, "..")) {
449 HNP_LOGE("unzip filename[%{public}s],does not allow the use of ..", fileName);
450 unzClose(zipFile);
451 return HNP_ERRNO_BASE_UNZIP_GET_INFO_FAILED;
452 }
453 char *slash = strchr(fileName, '/');
454 if (slash != NULL) {
455 slash++;
456 } else {
457 slash = fileName;
458 }
459
460 if (sprintf_s(filePath, MAX_FILE_PATH_LEN, "%s/%s", outputDir, slash) < 0) {
461 HNP_LOGE("sprintf unsuccess.");
462 unzClose(zipFile);
463 return HNP_ERRNO_BASE_SPRINTF_FAILED;
464 }
465
466 result = HnpUnZipForFile(filePath, zipFile, fileInfo);
467 if (result != 0) {
468 HNP_LOGE("unzip for file:%{public}s unsuccess", filePath);
469 unzClose(zipFile);
470 return result;
471 }
472 result = HnpInstallAddSignMap(hnpSignKeyPrefix, fileName, filePath, hnpSignMapInfos, count);
473 if (result != 0) {
474 unzClose(zipFile);
475 return result;
476 }
477 result = unzGoToNextFile(zipFile);
478 }
479
480 unzClose(zipFile);
481 return 0;
482 }
483
HnpCfgGetFromZip(const char * inputFile,HnpCfgInfo * hnpCfg)484 int HnpCfgGetFromZip(const char *inputFile, HnpCfgInfo *hnpCfg)
485 {
486 char fileName[MAX_FILE_PATH_LEN];
487 unz_file_info fileInfo;
488 char *cfgStream = NULL;
489
490 unzFile zipFile = unzOpen(inputFile);
491 if (zipFile == NULL) {
492 HNP_LOGE("unzip open hnp:%{public}s unsuccess!", inputFile);
493 return HNP_ERRNO_BASE_UNZIP_OPEN_FAILED;
494 }
495
496 int ret = unzGoToFirstFile(zipFile);
497 while (ret == UNZ_OK) {
498 ret = unzGetCurrentFileInfo(zipFile, &fileInfo, fileName, sizeof(fileName), NULL, 0, NULL, 0);
499 if (ret != UNZ_OK) {
500 HNP_LOGE("unzip get zip:%{public}s info unsuccess!", inputFile);
501 unzClose(zipFile);
502 return HNP_ERRNO_BASE_UNZIP_GET_INFO_FAILED;
503 }
504 char *fileNameTmp = strrchr(fileName, DIR_SPLIT_SYMBOL);
505 if (fileNameTmp == NULL) {
506 fileNameTmp = fileName;
507 } else {
508 fileNameTmp++;
509 }
510 if (strcmp(fileNameTmp, HNP_CFG_FILE_NAME) != 0) {
511 ret = unzGoToNextFile(zipFile);
512 continue;
513 }
514
515 unzOpenCurrentFile(zipFile);
516 cfgStream = malloc(fileInfo.uncompressed_size);
517 if (cfgStream == NULL) {
518 HNP_LOGE("malloc unsuccess. size=%{public}lu, errno=%{public}d", fileInfo.uncompressed_size, errno);
519 unzClose(zipFile);
520 return HNP_ERRNO_NOMEM;
521 }
522 int readSize = unzReadCurrentFile(zipFile, cfgStream, fileInfo.uncompressed_size);
523 if (readSize < 0 || (uLong)readSize != fileInfo.uncompressed_size) {
524 free(cfgStream);
525 unzClose(zipFile);
526 HNP_LOGE("unzip read zip:%{public}s info size[%{public}lu]=>[%{public}d] error!", inputFile,
527 fileInfo.uncompressed_size, readSize);
528 return HNP_ERRNO_BASE_FILE_READ_FAILED;
529 }
530 break;
531 }
532 unzClose(zipFile);
533 ret = HnpCfgGetFromSteam(cfgStream, hnpCfg);
534 free(cfgStream);
535 return ret;
536 }
537
538 #ifdef __cplusplus
539 }
540 #endif
541