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 <unistd.h> 19#include <getopt.h> 20 21#include "securec.h" 22 23#include "hnp_pack.h" 24 25#ifdef __cplusplus 26extern "C" { 27#endif 28 29static int AddHnpCfgFileToZip(zipFile zf, const char *hnpSrcPath, HnpCfgInfo *hnpCfg) 30{ 31 int ret; 32 char *strPtr; 33 int offset; 34 char hnpCfgFile[MAX_FILE_PATH_LEN]; 35 char *buff; 36 37 // zip压缩文件内只保存相对路径,不保存绝对路径信息,偏移到压缩文件夹位置 38 strPtr = strrchr(hnpSrcPath, DIR_SPLIT_SYMBOL); 39 if (strPtr == NULL) { 40 offset = 0; 41 } else { 42 offset = strPtr - hnpSrcPath + 1; 43 } 44 45 // zip函数根据后缀是否'/'区分目录还是文件 46 ret = sprintf_s(hnpCfgFile, MAX_FILE_PATH_LEN, "%s%c"HNP_CFG_FILE_NAME, hnpSrcPath + offset, DIR_SPLIT_SYMBOL); 47 if (ret < 0) { 48 HNP_LOGE("sprintf unsuccess."); 49 return HNP_ERRNO_BASE_SPRINTF_FAILED; 50 } 51 // 根据配置信息生成hnp.json内容 52 ret = GetHnpJsonBuff(hnpCfg, &buff); 53 if (ret != 0) { 54 HNP_LOGE("get hnp json content by cfg info unsuccess."); 55 return ret; 56 } 57 // 将hnp.json文件写入到.hnp压缩文件中 58 ret = HnpAddFileToZip(zf, hnpCfgFile, buff, strlen(buff) + 1); 59 free(buff); 60 if (ret != 0) { 61 HNP_LOGE("add file to zip failed, file=%{public}s", hnpCfgFile); 62 return ret; 63 } 64 65 return 0; 66} 67 68static int PackHnp(const char *hnpSrcPath, const char *hnpDstPath, HnpPackInfo *hnpPack) 69{ 70 int ret; 71 char hnp_file_path[MAX_FILE_PATH_LEN]; 72 HnpCfgInfo *hnpCfg = &hnpPack->cfgInfo; 73 74 HNP_LOGI("PackHnp start. srcPath=%{public}s, hnpName=%{public}s, hnpVer=%{public}s, hnpDstPath=%{public}s ", 75 hnpSrcPath, hnpCfg->name, hnpCfg->version, hnpDstPath); 76 77 /* 拼接hnp文件名 */ 78 ret = sprintf_s(hnp_file_path, MAX_FILE_PATH_LEN, "%s%c%s.hnp", hnpDstPath, DIR_SPLIT_SYMBOL, hnpCfg->name); 79 if (ret < 0) { 80 HNP_LOGE("sprintf unsuccess."); 81 return HNP_ERRNO_PACK_GET_HNP_PATH_FAILED; 82 } 83 84 HNP_LOGI("HnpZip dir=%{public}s, output=%{public}s ", hnpSrcPath, hnp_file_path); 85 86 zipFile zf = zipOpen(hnp_file_path, APPEND_STATUS_CREATE); 87 if (zf == NULL) { 88 HNP_LOGE("open zip=%{public}s unsuccess ", hnp_file_path); 89 return HNP_ERRNO_BASE_CREATE_ZIP_FAILED; 90 } 91 92 /* 将软件包压缩成独立的.hnp文件 */ 93 ret = HnpZip(hnpSrcPath, zf); 94 if (ret != 0) { 95 HNP_LOGE("zip dir unsuccess! srcPath=%{public}s, hnpName=%{public}s, hnpVer=%{public}s, hnpDstPath=%{public}s" 96 "ret=%{public}d", hnpSrcPath, hnpCfg->name, hnpCfg->version, hnpDstPath, ret); 97 zipClose(zf, NULL); 98 return HNP_ERRNO_PACK_ZIP_DIR_FAILED; 99 } 100 101 /* 如果软件包中不存在hnp.json文件,则需要在hnp压缩文件中添加 */ 102 if (hnpPack->hnpCfgExist == 0) { 103 ret = AddHnpCfgFileToZip(zf, hnpSrcPath, &hnpPack->cfgInfo); 104 if (ret != 0) { 105 HNP_LOGE("add file to zip failed ret=%d. zip=%s, src=%s", 106 ret, hnp_file_path, hnpSrcPath); 107 zipClose(zf, NULL); 108 return ret; 109 } 110 } 111 112 zipClose(zf, NULL); 113 114 HNP_LOGI("PackHnp end. srcPath=%{public}s, hnpName=%{public}s, hnpVer=%{public}s, hnpDstPath=%{public}s," 115 "linkNum=%{public}d, ret=%{public}d", hnpSrcPath, hnpCfg->name, hnpCfg->version, hnpDstPath, hnpCfg->linkNum, 116 ret); 117 118 return ret; 119} 120 121static int GetHnpCfgInfo(const char *hnpCfgPath, const char *sourcePath, HnpCfgInfo *hnpCfg) 122{ 123 NativeBinLink *linkArr = NULL; 124 char linksource[MAX_FILE_PATH_LEN] = {0}; 125 126 int ret = ParseHnpCfgFile(hnpCfgPath, hnpCfg); 127 if (ret != 0) { 128 HNP_LOGE("parse hnp cfg[%{public}s] unsuccess! ret=%{public}d", hnpCfgPath, ret); 129 return ret; 130 } 131 /* 校验软连接的source文件是否存在 */ 132 linkArr = hnpCfg->links; 133 for (unsigned int i = 0; i < hnpCfg->linkNum; i++, linkArr++) { 134 ret = sprintf_s(linksource, MAX_FILE_PATH_LEN, "%s/%s", sourcePath, linkArr->source); 135 if (ret < 0) { 136 free(hnpCfg->links); 137 hnpCfg->links = NULL; 138 HNP_LOGE("sprintf unsuccess."); 139 return HNP_ERRNO_BASE_SPRINTF_FAILED; 140 } 141 if (access(linksource, F_OK) != 0) { 142 free(hnpCfg->links); 143 hnpCfg->links = NULL; 144 HNP_LOGE("links source[%{public}s] not exist.", linksource); 145 return HNP_ERRNO_PACK_GET_REALPATH_FAILED; 146 } 147 } 148 return 0; 149} 150 151static int ParsePackArgs(HnpPackArgv *packArgv, HnpPackInfo *packInfo) 152{ 153 char cfgPath[MAX_FILE_PATH_LEN]; 154 155 if (packArgv->source == NULL) { 156 HNP_LOGE("source dir is null."); 157 return HNP_ERRNO_OPERATOR_ARGV_MISS; 158 } 159 if (GetRealPath(packArgv->source, packInfo->source) != 0) { 160 HNP_LOGE("source dir path=%{public}s is invalid.", packArgv->source); 161 return HNP_ERRNO_PACK_GET_REALPATH_FAILED; 162 } 163 if (packArgv->output == NULL) { 164 packArgv->output = "."; 165 } 166 167 if (GetRealPath(packArgv->output, packInfo->output) != 0) { 168 HNP_LOGE("output dir path=%{public}s is invalid.", packArgv->output); 169 return HNP_ERRNO_PACK_GET_REALPATH_FAILED; 170 } 171 /* 确认hnp.json文件是否存在,存在则对hnp.json文件进行解析并校验内容是否正确 */ 172 int ret = sprintf_s(cfgPath, MAX_FILE_PATH_LEN, "%s%c"HNP_CFG_FILE_NAME, packInfo->source, DIR_SPLIT_SYMBOL); 173 if (ret < 0) { 174 HNP_LOGE("sprintf unsuccess."); 175 return HNP_ERRNO_BASE_SPRINTF_FAILED; 176 } 177 if (access(cfgPath, F_OK) != 0) { 178 /* hnp.json文件不存在则要求用户传入name和version信息 */ 179 if ((packArgv->name == NULL) || (packArgv->version == NULL)) { 180 HNP_LOGE("name or version argv is miss."); 181 return HNP_ERRNO_OPERATOR_ARGV_MISS; 182 } 183 if (strcpy_s(packInfo->cfgInfo.name, MAX_FILE_PATH_LEN, packArgv->name) != EOK) { 184 HNP_LOGE("strcpy name argv unsuccess."); 185 return HNP_ERRNO_BASE_COPY_FAILED; 186 } 187 if (strcpy_s(packInfo->cfgInfo.version, HNP_VERSION_LEN, packArgv->version) != EOK) { 188 HNP_LOGE("strcpy version argv unsuccess."); 189 return HNP_ERRNO_BASE_COPY_FAILED; 190 } 191 packInfo->hnpCfgExist = 0; 192 } else { 193 ret = GetHnpCfgInfo(cfgPath, packInfo->source, &packInfo->cfgInfo); 194 if (ret != 0) { 195 return ret; 196 } 197 packInfo->hnpCfgExist = 1; 198 } 199 return 0; 200} 201 202int HnpCmdPack(int argc, char *argv[]) 203{ 204 HnpPackArgv packArgv = {0}; 205 HnpPackInfo packInfo = {0}; 206 int opt; 207 208 optind = 1; // 从头开始遍历参数 209 while ((opt = getopt_long(argc, argv, "hi:o:n:v:", NULL, NULL)) != -1) { 210 switch (opt) { 211 case 'h' : 212 return HNP_ERRNO_OPERATOR_ARGV_MISS; 213 case 'i' : 214 packArgv.source = optarg; 215 break; 216 case 'o' : 217 packArgv.output = optarg; 218 break; 219 case 'n' : 220 packArgv.name = optarg; 221 break; 222 case 'v' : 223 packArgv.version = optarg; 224 break; 225 default: 226 break; 227 } 228 } 229 230 // 解析参数并生成打包信息 231 int ret = ParsePackArgs(&packArgv, &packInfo); 232 if (ret != 0) { 233 return ret; 234 } 235 236 // 根据打包信息进行打包操作 237 ret = PackHnp(packInfo.source, packInfo.output, &packInfo); 238 239 // 释放软链接占用的内存 240 if (packInfo.cfgInfo.links != NULL) { 241 free(packInfo.cfgInfo.links); 242 packInfo.cfgInfo.links = NULL; 243 } 244 245 return ret; 246} 247 248#ifdef __cplusplus 249} 250#endif