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,const char * zipPath)223 static int ZipDir(const char *sourcePath, int offset, const char *zipPath)
224 {
225 int ret;
226 char transPath[MAX_FILE_PATH_LEN];
227
228 zipFile zf = zipOpen(zipPath, APPEND_STATUS_CREATE);
229 if (zf == NULL) {
230 HNP_LOGE("open zip=%{public}s unsuccess ", zipPath);
231 return HNP_ERRNO_BASE_CREATE_ZIP_FAILED;
232 }
233
234 TransPath(sourcePath, transPath);
235
236 // 将外层文件夹信息保存到zip文件中
237 ret = zipOpenNewFileInZip3(zf, transPath + offset, NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_BEST_COMPRESSION,
238 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0);
239 if (ret != ZIP_OK) {
240 HNP_LOGE("open new file[%{public}s] in zip unsuccess ", sourcePath + offset);
241 zipClose(zf, NULL);
242 return HNP_ERRNO_BASE_CREATE_ZIP_FAILED;
243 }
244 zipCloseFileInZip(zf);
245 ret = ZipAddDir(sourcePath, offset, zf);
246
247 zipClose(zf, NULL);
248
249 return ret;
250 }
251
HnpZip(const char * inputDir,const char * outputFile)252 int HnpZip(const char *inputDir, const char *outputFile)
253 {
254 int ret;
255 char *strPtr;
256 int offset;
257 char sourcePath[MAX_FILE_PATH_LEN];
258
259 HNP_LOGI("HnpZip dir=%{public}s, output=%{public}s ", inputDir, outputFile);
260
261 // zip压缩文件内只保存相对路径,不保存绝对路径信息,偏移到压缩文件夹位置
262 strPtr = strrchr(inputDir, DIR_SPLIT_SYMBOL);
263 if (strPtr == NULL) {
264 offset = 0;
265 } else {
266 offset = strPtr - inputDir + 1;
267 }
268
269 // zip函数根据后缀是否'/'区分目录还是文件
270 ret = sprintf_s(sourcePath, MAX_FILE_PATH_LEN, "%s%c", inputDir, DIR_SPLIT_SYMBOL);
271 if (ret < 0) {
272 HNP_LOGE("sprintf unsuccess.");
273 return HNP_ERRNO_BASE_SPRINTF_FAILED;
274 }
275
276 ret = ZipDir(sourcePath, offset, outputFile);
277
278 return ret;
279 }
280
HnpAddFileToZip(char * zipfile,char * filename,char * buff,int size)281 int HnpAddFileToZip(char *zipfile, char *filename, char *buff, int size)
282 {
283 zipFile zf;
284 int ret;
285 char transPath[MAX_FILE_PATH_LEN];
286
287 zf = zipOpen(zipfile, APPEND_STATUS_ADDINZIP);
288 if (zf == NULL) {
289 HNP_LOGE("open zip=%{public}s unsuccess ", zipfile);
290 return HNP_ERRNO_BASE_CREATE_ZIP_FAILED;
291 }
292
293 TransPath(filename, transPath);
294
295 // 将外层文件夹信息保存到zip文件中
296 ret = zipOpenNewFileInZip3(zf, transPath, NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_BEST_COMPRESSION,
297 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0);
298 if (ret != ZIP_OK) {
299 HNP_LOGE("open new file[%{public}s] in zip unsuccess ", filename);
300 zipClose(zf, NULL);
301 return HNP_ERRNO_BASE_CREATE_ZIP_FAILED;
302 }
303 zipWriteInFileInZip(zf, buff, size);
304 zipCloseFileInZip(zf);
305 zipClose(zf, NULL);
306
307 return 0;
308 }
309
HnpUnZipForFile(const char * filePath,unzFile zipFile,unz_file_info fileInfo)310 static int HnpUnZipForFile(const char *filePath, unzFile zipFile, unz_file_info fileInfo)
311 {
312 #ifdef _WIN32
313 return 0;
314 #else
315 int ret;
316 mode_t mode = (fileInfo.external_fa >> ZIP_EXTERNAL_FA_OFFSET) & 0xFFFF;
317
318 /* 如果解压缩的是目录 */
319 if (filePath[strlen(filePath) - 1] == '/') {
320 mkdir(filePath, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
321 } else {
322 FILE *outFile = fopen(filePath, "wb");
323 if (outFile == NULL) {
324 HNP_LOGE("unzip open file:%{public}s unsuccess!", filePath);
325 return HNP_ERRNO_BASE_FILE_OPEN_FAILED;
326 }
327 unzOpenCurrentFile(zipFile);
328 int readSize = 0;
329 do {
330 char buffer[BUFFER_SIZE];
331 readSize = unzReadCurrentFile(zipFile, buffer, sizeof(buffer));
332 if (readSize < 0) {
333 HNP_LOGE("unzip read zip:%{public}s file unsuccess", (char *)zipFile);
334 fclose(outFile);
335 unzCloseCurrentFile(zipFile);
336 return HNP_ERRNO_BASE_UNZIP_READ_FAILED;
337 }
338
339 fwrite(buffer, readSize, sizeof(char), outFile);
340 } while (readSize > 0);
341
342 fclose(outFile);
343 unzCloseCurrentFile(zipFile);
344 /* 如果其他人有可执行权限,那么将解压后的权限设置成755,否则为744 */
345 if ((mode & S_IXOTH) != 0) {
346 ret = chmod(filePath, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
347 } else {
348 ret = chmod(filePath, S_IRWXU | S_IRGRP | S_IROTH);
349 }
350 if (ret != 0) {
351 HNP_LOGE("hnp install chmod unsuccess, src:%{public}s, errno:%{public}d", filePath, errno);
352 return HNP_ERRNO_BASE_CHMOD_FAILED;
353 }
354 }
355 return 0;
356 #endif
357 }
358
HnpELFFileCheck(const char * path)359 static bool HnpELFFileCheck(const char *path)
360 {
361 FILE *fp;
362 char buff[HNP_ELF_FILE_CHECK_HEAD_LEN];
363
364 fp = fopen(path, "rb");
365 if (fp == NULL) {
366 return false;
367 }
368
369 size_t readLen = fread(buff, sizeof(char), HNP_ELF_FILE_CHECK_HEAD_LEN, fp);
370 if (readLen != HNP_ELF_FILE_CHECK_HEAD_LEN) {
371 (void)fclose(fp);
372 return false;
373 }
374
375 if (buff[HNP_INDEX_0] == 0x7F && buff[HNP_INDEX_1] == 'E' && buff[HNP_INDEX_2] == 'L' && buff[HNP_INDEX_3] == 'F') {
376 (void)fclose(fp);
377 return true;
378 }
379
380 (void)fclose(fp);
381 return false;
382 }
383
HnpInstallAddSignMap(const char * hnpSignKeyPrefix,const char * key,const char * value,HnpSignMapInfo * hnpSignMapInfos,int * count)384 static int HnpInstallAddSignMap(const char* hnpSignKeyPrefix, const char *key, const char *value,
385 HnpSignMapInfo *hnpSignMapInfos, int *count)
386 {
387 int ret;
388 int sum = *count;
389
390 if (HnpELFFileCheck(value) == false) {
391 return 0;
392 }
393
394 ret = sprintf_s(hnpSignMapInfos[sum].key, MAX_FILE_PATH_LEN, "%s!/%s", hnpSignKeyPrefix, key);
395 if (ret < 0) {
396 HNP_LOGE("add sign map sprintf unsuccess.");
397 return HNP_ERRNO_BASE_SPRINTF_FAILED;
398 }
399
400 ret = strcpy_s(hnpSignMapInfos[sum].value, MAX_FILE_PATH_LEN, value);
401 if (ret != EOK) {
402 HNP_LOGE("add sign map strcpy[%{public}s] unsuccess.", value);
403 return HNP_ERRNO_BASE_COPY_FAILED;
404 }
405
406 *count = sum + 1;
407 return 0;
408 }
409
HnpFileCountGet(const char * path,int * count)410 int HnpFileCountGet(const char *path, int *count)
411 {
412 int sum = 0;
413
414 unzFile zipFile = unzOpen(path);
415 if (zipFile == NULL) {
416 HNP_LOGE("unzip open hnp:%{public}s unsuccess!", path);
417 return HNP_ERRNO_BASE_UNZIP_OPEN_FAILED;
418 }
419
420 int ret = unzGoToFirstFile(zipFile);
421 while (ret == UNZ_OK) {
422 if (sum == INT_MAX) {
423 unzClose(zipFile);
424 return HNP_ERRNO_BASE_FILE_COUNT_OVER;
425 }
426 sum++;
427 ret = unzGetCurrentFileInfo(zipFile, NULL, NULL, 0, NULL, 0, NULL, 0);
428 if (ret != UNZ_OK) {
429 HNP_LOGE("unzip get zip:%{public}s info unsuccess!", path);
430 unzClose(zipFile);
431 return HNP_ERRNO_BASE_UNZIP_GET_INFO_FAILED;
432 }
433
434 ret = unzGoToNextFile(zipFile);
435 }
436
437 unzClose(zipFile);
438 if (INT_MAX - sum < *count) {
439 return HNP_ERRNO_BASE_FILE_COUNT_OVER;
440 }
441 *count += sum;
442 return 0;
443 }
444
HnpUnZip(const char * inputFile,const char * outputDir,const char * hnpSignKeyPrefix,HnpSignMapInfo * hnpSignMapInfos,int * count)445 int HnpUnZip(const char *inputFile, const char *outputDir, const char *hnpSignKeyPrefix,
446 HnpSignMapInfo *hnpSignMapInfos, int *count)
447 {
448 char fileName[MAX_FILE_PATH_LEN];
449 unz_file_info fileInfo;
450 char filePath[MAX_FILE_PATH_LEN];
451
452 HNP_LOGI("HnpUnZip zip=%{public}s, output=%{public}s", inputFile, outputDir);
453
454 unzFile zipFile = unzOpen(inputFile);
455 if (zipFile == NULL) {
456 HNP_LOGE("unzip open hnp:%{public}s unsuccess!", inputFile);
457 return HNP_ERRNO_BASE_UNZIP_OPEN_FAILED;
458 }
459
460 int result = unzGoToFirstFile(zipFile);
461 while (result == UNZ_OK) {
462 result = unzGetCurrentFileInfo(zipFile, &fileInfo, fileName, sizeof(fileName), NULL, 0, NULL, 0);
463 if (result != UNZ_OK) {
464 HNP_LOGE("unzip get zip:%{public}s info unsuccess!", inputFile);
465 unzClose(zipFile);
466 return HNP_ERRNO_BASE_UNZIP_GET_INFO_FAILED;
467 }
468 if (strstr(fileName, "../")) {
469 unzClose(zipFile);
470 return HNP_ERRNO_BASE_UNZIP_GET_INFO_FAILED;
471 }
472 char *slash = strchr(fileName, '/');
473 if (slash != NULL) {
474 slash++;
475 } else {
476 slash = fileName;
477 }
478
479 result = sprintf_s(filePath, MAX_FILE_PATH_LEN, "%s/%s", outputDir, slash);
480 if (result < 0) {
481 HNP_LOGE("sprintf unsuccess.");
482 unzClose(zipFile);
483 return HNP_ERRNO_BASE_SPRINTF_FAILED;
484 }
485
486 result = HnpUnZipForFile(filePath, zipFile, fileInfo);
487 if (result != 0) {
488 HNP_LOGE("unzip for file:%{public}s unsuccess", filePath);
489 unzClose(zipFile);
490 return result;
491 }
492 result = HnpInstallAddSignMap(hnpSignKeyPrefix, fileName, filePath, hnpSignMapInfos, count);
493 if (result != 0) {
494 unzClose(zipFile);
495 return result;
496 }
497 result = unzGoToNextFile(zipFile);
498 }
499
500 unzClose(zipFile);
501 return 0;
502 }
503
HnpCfgGetFromZip(const char * inputFile,HnpCfgInfo * hnpCfg)504 int HnpCfgGetFromZip(const char *inputFile, HnpCfgInfo *hnpCfg)
505 {
506 char fileName[MAX_FILE_PATH_LEN];
507 unz_file_info fileInfo;
508 char *cfgStream = NULL;
509
510 unzFile zipFile = unzOpen(inputFile);
511 if (zipFile == NULL) {
512 HNP_LOGE("unzip open hnp:%{public}s unsuccess!", inputFile);
513 return HNP_ERRNO_BASE_UNZIP_OPEN_FAILED;
514 }
515
516 int ret = unzGoToFirstFile(zipFile);
517 while (ret == UNZ_OK) {
518 ret = unzGetCurrentFileInfo(zipFile, &fileInfo, fileName, sizeof(fileName), NULL, 0, NULL, 0);
519 if (ret != UNZ_OK) {
520 HNP_LOGE("unzip get zip:%{public}s info unsuccess!", inputFile);
521 unzClose(zipFile);
522 return HNP_ERRNO_BASE_UNZIP_GET_INFO_FAILED;
523 }
524 char *fileNameTmp = strrchr(fileName, DIR_SPLIT_SYMBOL);
525 if (fileNameTmp == NULL) {
526 fileNameTmp = fileName;
527 } else {
528 fileNameTmp++;
529 }
530 if (strcmp(fileNameTmp, HNP_CFG_FILE_NAME) != 0) {
531 ret = unzGoToNextFile(zipFile);
532 continue;
533 }
534
535 unzOpenCurrentFile(zipFile);
536 cfgStream = malloc(fileInfo.uncompressed_size);
537 if (cfgStream == NULL) {
538 HNP_LOGE("malloc unsuccess. size=%{public}lu, errno=%{public}d", fileInfo.uncompressed_size, errno);
539 unzClose(zipFile);
540 return HNP_ERRNO_NOMEM;
541 }
542 int readSize = unzReadCurrentFile(zipFile, cfgStream, fileInfo.uncompressed_size);
543 if (readSize < 0 || (uLong)readSize != fileInfo.uncompressed_size) {
544 free(cfgStream);
545 unzClose(zipFile);
546 HNP_LOGE("unzip read zip:%{public}s info size[%{public}lu]=>[%{public}d] error!", inputFile,
547 fileInfo.uncompressed_size, readSize);
548 return HNP_ERRNO_BASE_FILE_READ_FAILED;
549 }
550 break;
551 }
552 unzClose(zipFile);
553 ret = HnpCfgGetFromSteam(cfgStream, hnpCfg);
554 free(cfgStream);
555 return ret;
556 }
557
558 #ifdef __cplusplus
559 }
560 #endif
561