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(char * zipPath,const char * hnpSrcPath,HnpCfgInfo * hnpCfg)29 static int AddHnpCfgFileToZip(char *zipPath, 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(zipPath, hnpCfgFile, buff, strlen(buff) + 1);
59 free(buff);
60 if (ret != 0) {
61 HNP_LOGE("add file to zip failed.zip=%{public}s, file=%{public}s", zipPath, 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文件 */
85 ret = HnpZip(hnpSrcPath, hnp_file_path);
86 if (ret != 0) {
87 HNP_LOGE("zip dir unsuccess! srcPath=%{public}s, hnpName=%{public}s, hnpVer=%{public}s, hnpDstPath=%{public}s"
88 "ret=%{public}d", hnpSrcPath, hnpCfg->name, hnpCfg->version, hnpDstPath, ret);
89 return HNP_ERRNO_PACK_ZIP_DIR_FAILED;
90 }
91
92 /* 如果软件包中不存在hnp.json文件,则需要在hnp压缩文件中添加 */
93 if (hnpPack->hnpCfgExist == 0) {
94 ret = AddHnpCfgFileToZip(hnp_file_path, hnpSrcPath, &hnpPack->cfgInfo);
95 if (ret != 0) {
96 HNP_LOGE("add file to zip failed ret=%d. zip=%s, src=%s",
97 ret, hnp_file_path, hnpSrcPath);
98 return ret;
99 }
100 }
101
102 HNP_LOGI("PackHnp end. srcPath=%{public}s, hnpName=%{public}s, hnpVer=%{public}s, hnpDstPath=%{public}s,"
103 "linkNum=%{public}d, ret=%{public}d", hnpSrcPath, hnpCfg->name, hnpCfg->version, hnpDstPath, hnpCfg->linkNum,
104 ret);
105
106 return ret;
107 }
108
GetHnpCfgInfo(const char * hnpCfgPath,const char * sourcePath,HnpCfgInfo * hnpCfg)109 static int GetHnpCfgInfo(const char *hnpCfgPath, const char *sourcePath, HnpCfgInfo *hnpCfg)
110 {
111 NativeBinLink *linkArr = NULL;
112 char linksource[MAX_FILE_PATH_LEN] = {0};
113
114 int ret = ParseHnpCfgFile(hnpCfgPath, hnpCfg);
115 if (ret != 0) {
116 HNP_LOGE("parse hnp cfg[%{public}s] unsuccess! ret=%{public}d", hnpCfgPath, ret);
117 return ret;
118 }
119 /* 校验软连接的source文件是否存在 */
120 linkArr = hnpCfg->links;
121 for (unsigned int i = 0; i < hnpCfg->linkNum; i++, linkArr++) {
122 ret = sprintf_s(linksource, MAX_FILE_PATH_LEN, "%s/%s", sourcePath, linkArr->source);
123 if (ret < 0) {
124 free(hnpCfg->links);
125 hnpCfg->links = NULL;
126 HNP_LOGE("sprintf unsuccess.");
127 return HNP_ERRNO_BASE_SPRINTF_FAILED;
128 }
129 if (access(linksource, F_OK) != 0) {
130 free(hnpCfg->links);
131 hnpCfg->links = NULL;
132 HNP_LOGE("links source[%{public}s] not exist.", linksource);
133 return HNP_ERRNO_PACK_GET_REALPATH_FAILED;
134 }
135 }
136 return 0;
137 }
138
ParsePackArgs(HnpPackArgv * packArgv,HnpPackInfo * packInfo)139 static int ParsePackArgs(HnpPackArgv *packArgv, HnpPackInfo *packInfo)
140 {
141 char cfgPath[MAX_FILE_PATH_LEN];
142
143 if (packArgv->source == NULL) {
144 HNP_LOGE("source dir is null.");
145 return HNP_ERRNO_OPERATOR_ARGV_MISS;
146 }
147 if (GetRealPath(packArgv->source, packInfo->source) != 0) {
148 HNP_LOGE("source dir path=%{public}s is invalid.", packArgv->source);
149 return HNP_ERRNO_PACK_GET_REALPATH_FAILED;
150 }
151 if (packArgv->output == NULL) {
152 packArgv->output = ".";
153 }
154
155 if (GetRealPath(packArgv->output, packInfo->output) != 0) {
156 HNP_LOGE("output dir path=%{public}s is invalid.", packArgv->output);
157 return HNP_ERRNO_PACK_GET_REALPATH_FAILED;
158 }
159 /* 确认hnp.json文件是否存在,存在则对hnp.json文件进行解析并校验内容是否正确 */
160 int ret = sprintf_s(cfgPath, MAX_FILE_PATH_LEN, "%s%c"HNP_CFG_FILE_NAME, packInfo->source, DIR_SPLIT_SYMBOL);
161 if (ret < 0) {
162 HNP_LOGE("sprintf unsuccess.");
163 return HNP_ERRNO_BASE_SPRINTF_FAILED;
164 }
165 if (access(cfgPath, F_OK) != 0) {
166 /* hnp.json文件不存在则要求用户传入name和version信息 */
167 if ((packArgv->name == NULL) || (packArgv->version == NULL)) {
168 HNP_LOGE("name or version argv is miss.");
169 return HNP_ERRNO_OPERATOR_ARGV_MISS;
170 }
171 if (strcpy_s(packInfo->cfgInfo.name, MAX_FILE_PATH_LEN, packArgv->name) != EOK) {
172 HNP_LOGE("strcpy name argv unsuccess.");
173 return HNP_ERRNO_BASE_COPY_FAILED;
174 }
175 if (strcpy_s(packInfo->cfgInfo.version, HNP_VERSION_LEN, packArgv->version) != EOK) {
176 HNP_LOGE("strcpy version argv unsuccess.");
177 return HNP_ERRNO_BASE_COPY_FAILED;
178 }
179 packInfo->hnpCfgExist = 0;
180 } else {
181 ret = GetHnpCfgInfo(cfgPath, packInfo->source, &packInfo->cfgInfo);
182 if (ret != 0) {
183 return ret;
184 }
185 packInfo->hnpCfgExist = 1;
186 }
187 return 0;
188 }
189
HnpCmdPack(int argc,char * argv[])190 int HnpCmdPack(int argc, char *argv[])
191 {
192 HnpPackArgv packArgv = {0};
193 HnpPackInfo packInfo = {0};
194 int opt;
195
196 optind = 1; // 从头开始遍历参数
197 while ((opt = getopt_long(argc, argv, "hi:o:n:v:", NULL, NULL)) != -1) {
198 switch (opt) {
199 case 'h' :
200 return HNP_ERRNO_OPERATOR_ARGV_MISS;
201 case 'i' :
202 packArgv.source = optarg;
203 break;
204 case 'o' :
205 packArgv.output = optarg;
206 break;
207 case 'n' :
208 packArgv.name = optarg;
209 break;
210 case 'v' :
211 packArgv.version = optarg;
212 break;
213 default:
214 break;
215 }
216 }
217
218 // 解析参数并生成打包信息
219 int ret = ParsePackArgs(&packArgv, &packInfo);
220 if (ret != 0) {
221 return ret;
222 }
223
224 // 根据打包信息进行打包操作
225 ret = PackHnp(packInfo.source, packInfo.output, &packInfo);
226
227 // 释放软链接占用的内存
228 if (packInfo.cfgInfo.links != NULL) {
229 free(packInfo.cfgInfo.links);
230 packInfo.cfgInfo.links = NULL;
231 }
232
233 return ret;
234 }
235
236 #ifdef __cplusplus
237 }
238 #endif