• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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