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
26 extern "C" {
27 #endif
28
AddHnpCfgFileToZip(zipFile zf,const char * hnpSrcPath,HnpCfgInfo * hnpCfg)29 static 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
PackHnp(const char * hnpSrcPath,const char * hnpDstPath,HnpPackInfo * hnpPack)68 static 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
GetHnpCfgInfo(const char * hnpCfgPath,const char * sourcePath,HnpCfgInfo * hnpCfg)121 static 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
ParsePackArgs(HnpPackArgv * packArgv,HnpPackInfo * packInfo)151 static 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
HnpCmdPack(int argc,char * argv[])202 int 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