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 38extern "C" { 39#endif 40 41#define ZIP_EXTERNAL_FA_OFFSET 16 42 43// zipOpenNewFileInZip3只识别带‘/’的路径,需要将路径中‘\’转换成‘/’ 44static 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 59static 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压缩包中添加文件 72static 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// 判断是否为目录 127static 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 149static int ZipAddDir(const char *sourcePath, int offset, zipFile zf); 150 151static 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--压缩文件句柄 172static 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 223static 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 243int 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 270int 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 290static 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 339static 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 364static 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 390int 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 sum++; 403 ret = unzGetCurrentFileInfo(zipFile, NULL, NULL, 0, NULL, 0, NULL, 0); 404 if (ret != UNZ_OK) { 405 HNP_LOGE("unzip get zip:%{public}s info unsuccess!", path); 406 unzClose(zipFile); 407 return HNP_ERRNO_BASE_UNZIP_GET_INFO_FAILED; 408 } 409 410 ret = unzGoToNextFile(zipFile); 411 } 412 413 unzClose(zipFile); 414 *count += sum; 415 return 0; 416} 417 418int HnpUnZip(const char *inputFile, const char *outputDir, const char *hnpSignKeyPrefix, 419 HnpSignMapInfo *hnpSignMapInfos, int *count) 420{ 421 char fileName[MAX_FILE_PATH_LEN]; 422 unz_file_info fileInfo; 423 char filePath[MAX_FILE_PATH_LEN]; 424 425 HNP_LOGI("HnpUnZip zip=%{public}s, output=%{public}s", inputFile, outputDir); 426 427 unzFile zipFile = unzOpen(inputFile); 428 if (zipFile == NULL) { 429 HNP_LOGE("unzip open hnp:%{public}s unsuccess!", inputFile); 430 return HNP_ERRNO_BASE_UNZIP_OPEN_FAILED; 431 } 432 433 int result = unzGoToFirstFile(zipFile); 434 while (result == UNZ_OK) { 435 result = unzGetCurrentFileInfo(zipFile, &fileInfo, fileName, sizeof(fileName), NULL, 0, NULL, 0); 436 if (result != UNZ_OK) { 437 HNP_LOGE("unzip get zip:%{public}s info unsuccess!", inputFile); 438 unzClose(zipFile); 439 return HNP_ERRNO_BASE_UNZIP_GET_INFO_FAILED; 440 } 441 if (strstr(fileName, "../")) { 442 HNP_LOGE("unzip filename[%{public}s],does not allow the use of ../", fileName); 443 unzClose(zipFile); 444 return HNP_ERRNO_BASE_UNZIP_GET_INFO_FAILED; 445 } 446 char *slash = strchr(fileName, '/'); 447 if (slash != NULL) { 448 slash++; 449 } else { 450 slash = fileName; 451 } 452 453 if (sprintf_s(filePath, MAX_FILE_PATH_LEN, "%s/%s", outputDir, slash) < 0) { 454 HNP_LOGE("sprintf unsuccess."); 455 unzClose(zipFile); 456 return HNP_ERRNO_BASE_SPRINTF_FAILED; 457 } 458 459 result = HnpUnZipForFile(filePath, zipFile, fileInfo); 460 if (result != 0) { 461 HNP_LOGE("unzip for file:%{public}s unsuccess", filePath); 462 unzClose(zipFile); 463 return result; 464 } 465 result = HnpInstallAddSignMap(hnpSignKeyPrefix, fileName, filePath, hnpSignMapInfos, count); 466 if (result != 0) { 467 unzClose(zipFile); 468 return result; 469 } 470 result = unzGoToNextFile(zipFile); 471 } 472 473 unzClose(zipFile); 474 return 0; 475} 476 477int HnpCfgGetFromZip(const char *inputFile, HnpCfgInfo *hnpCfg) 478{ 479 char fileName[MAX_FILE_PATH_LEN]; 480 unz_file_info fileInfo; 481 char *cfgStream = NULL; 482 483 unzFile zipFile = unzOpen(inputFile); 484 if (zipFile == NULL) { 485 HNP_LOGE("unzip open hnp:%{public}s unsuccess!", inputFile); 486 return HNP_ERRNO_BASE_UNZIP_OPEN_FAILED; 487 } 488 489 int ret = unzGoToFirstFile(zipFile); 490 while (ret == UNZ_OK) { 491 ret = unzGetCurrentFileInfo(zipFile, &fileInfo, fileName, sizeof(fileName), NULL, 0, NULL, 0); 492 if (ret != UNZ_OK) { 493 HNP_LOGE("unzip get zip:%{public}s info unsuccess!", inputFile); 494 unzClose(zipFile); 495 return HNP_ERRNO_BASE_UNZIP_GET_INFO_FAILED; 496 } 497 char *fileNameTmp = strrchr(fileName, DIR_SPLIT_SYMBOL); 498 if (fileNameTmp == NULL) { 499 fileNameTmp = fileName; 500 } else { 501 fileNameTmp++; 502 } 503 if (strcmp(fileNameTmp, HNP_CFG_FILE_NAME) != 0) { 504 ret = unzGoToNextFile(zipFile); 505 continue; 506 } 507 508 unzOpenCurrentFile(zipFile); 509 cfgStream = malloc(fileInfo.uncompressed_size); 510 if (cfgStream == NULL) { 511 HNP_LOGE("malloc unsuccess. size=%{public}lu, errno=%{public}d", fileInfo.uncompressed_size, errno); 512 unzClose(zipFile); 513 return HNP_ERRNO_NOMEM; 514 } 515 int readSize = unzReadCurrentFile(zipFile, cfgStream, fileInfo.uncompressed_size); 516 if (readSize < 0 || (uLong)readSize != fileInfo.uncompressed_size) { 517 free(cfgStream); 518 unzClose(zipFile); 519 HNP_LOGE("unzip read zip:%{public}s info size[%{public}lu]=>[%{public}d] error!", inputFile, 520 fileInfo.uncompressed_size, readSize); 521 return HNP_ERRNO_BASE_FILE_READ_FAILED; 522 } 523 break; 524 } 525 unzClose(zipFile); 526 ret = HnpCfgGetFromSteam(cfgStream, hnpCfg); 527 free(cfgStream); 528 return ret; 529} 530 531#ifdef __cplusplus 532} 533#endif 534