1 /*
2 * Copyright (C) 2022 Huawei Technologies Co., Ltd.
3 * Licensed under the Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 * http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9 * PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 */
12 #include "tarzip.h"
13
14 #include <stdio.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <stdbool.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20 #include <zlib.h>
21 #include <dirent.h>
22 #include <sys/stat.h>
23 #include <pwd.h>
24 #include <errno.h>
25 #include <securec.h>
26
27 #include "tee_log.h"
28 #include "tlogcat.h"
29
30 #ifdef LOG_TAG
31 #undef LOG_TAG
32 #endif
33 #define LOG_TAG "tlogcat"
34
35 #define HEADER_NUM 512
36 #define CHECK_SUM_APPEND 256
37 #define NAME_LEN 100U
38 #define FILE_MODE_LEN 8U
39 #define UID_LEN 8U
40 #define GID_LEN 8U
41 #define FILE_SIZE 12U
42 #define UNIX_TIME_LEN 12U
43 #define CHECK_SUM_LEN 8U
44 #define HEADER_RESVD_LEN 356U
45
46 /* tar file header struct */
47 struct TagHeader { /* byte offset */
48 char name[NAME_LEN]; /* 0 */
49 char mode[FILE_MODE_LEN]; /* 100 */
50 char uid[UID_LEN]; /* 108 */
51 char gid[GID_LEN]; /* 116 */
52 char size[FILE_SIZE]; /* 124 */
53 char unixTime[UNIX_TIME_LEN]; /* 136 */
54 char checkSum[CHECK_SUM_LEN]; /* 148 */
55 char reserved[HEADER_RESVD_LEN]; /* 156 */
56 };
57
58 /* tar file header mode permissions data */
59 static const char FILE_MODE[] = { 0x31, 0x30, 0x30, 0x36, 0x36, 0x36, 0x20, 0 };
60
61 /* tar file haeder UID and GID date */
62 static const char ID_BYTE[] = {
63 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x00,
64 };
65
WriteOneUint(size_t startIndex,size_t unitLen,const char * input,char * ouput)66 static int32_t WriteOneUint(size_t startIndex, size_t unitLen, const char *input, char *ouput)
67 {
68 size_t i;
69 int32_t sum = 0;
70
71 for (i = 0; i < unitLen; ++i) {
72 ouput[i + startIndex] = input[i];
73 sum += (int32_t)input[i];
74 }
75
76 return sum;
77 }
78
79 /* write the tar file harder to header struct */
WriteHeader(struct TagHeader * header,const char * fileName,long fileSize)80 static void WriteHeader(struct TagHeader *header, const char *fileName, long fileSize)
81 {
82 int32_t sumAppend = 0;
83 size_t nameLen;
84 size_t i;
85 size_t j = 0;
86 char *index = (char *)header;
87 char buf[FILE_SIZE] = {0};
88 errno_t rc;
89
90 if (fileName == NULL || fileSize == 0) {
91 return;
92 }
93
94 nameLen = strlen(fileName);
95 nameLen = ((nameLen >= NAME_LEN) ? (NAME_LEN - 1) : nameLen);
96
97 sumAppend += WriteOneUint(j, nameLen, fileName, index);
98 j += NAME_LEN;
99
100 sumAppend += WriteOneUint(j, FILE_MODE_LEN, FILE_MODE, index);
101 j += FILE_MODE_LEN;
102
103 sumAppend += WriteOneUint(j, (UID_LEN + GID_LEN), ID_BYTE, index);
104 j += (UID_LEN + GID_LEN);
105
106 rc = snprintf_s(buf, FILE_SIZE, FILE_SIZE - 1, "%o", (unsigned int)fileSize);
107 if (rc == -1) {
108 tloge("snprintf_s failed: %d\n", rc);
109 return;
110 }
111
112 sumAppend += WriteOneUint(j, FILE_SIZE, buf, index);
113 j += (FILE_SIZE + UNIX_TIME_LEN);
114
115 sumAppend += CHECK_SUM_APPEND;
116 rc = snprintf_s(buf, FILE_SIZE, FILE_SIZE - 1, "%o", sumAppend);
117 if (rc == -1) {
118 tloge("snprintf_s failed: %d\n", rc);
119 return;
120 }
121 for (i = 0; i < CHECK_SUM_LEN; ++i) {
122 index[j + i] = buf[i];
123 }
124 }
125
126 #define ZIP_OPEN_MODE 0400U
127
128 /* write file content to tar zip file */
WriteZipContent(gzFile gzFd,const char * fileName,long fileSize)129 static void WriteZipContent(gzFile gzFd, const char *fileName, long fileSize)
130 {
131 char buf[HEADER_NUM];
132 ssize_t ret;
133 int32_t iret;
134 long temFileSize = fileSize;
135 bool cond = (gzFd == NULL || fileName == NULL || fileSize == 0);
136
137 if (cond) {
138 tloge("fd or fileName or fileSize invalid\n");
139 return;
140 }
141
142 int32_t fileFd = open(fileName, O_CREAT | O_RDWR, ZIP_OPEN_MODE);
143 if (fileFd < 0) {
144 return;
145 }
146 while (temFileSize > 0) {
147 (void)memset_s(buf, HEADER_NUM, 0, HEADER_NUM);
148 ret = read(fileFd, buf, HEADER_NUM);
149 if (ret < 0) {
150 tloge("read failed\n");
151 goto CLOSE_FD;
152 }
153
154 iret = gzwrite(gzFd, buf, HEADER_NUM);
155 if (iret < 0) {
156 tloge("gzwrite failed\n");
157 goto CLOSE_FD;
158 } else if (iret < HEADER_NUM) {
159 tloge("incomplete gzwrite\n");
160 goto CLOSE_FD;
161 }
162
163 temFileSize -= HEADER_NUM;
164 }
165
166 CLOSE_FD:
167 close(fileFd);
168 }
169
OpenZipFile(const char * outputName,gzFile * outFile,gid_t pathGroup)170 static int32_t OpenZipFile(const char *outputName, gzFile *outFile, gid_t pathGroup)
171 {
172 int32_t ret;
173
174 *outFile = NULL;
175
176 int32_t fd = open(outputName, O_CREAT | O_WRONLY, ZIP_OPEN_MODE);
177 if (fd < 0) {
178 tloge("open file failed\n");
179 return -1;
180 }
181 gzFile out = gzdopen(fd, "w");
182 if (out == NULL) {
183 tloge("change fd to file failed\n");
184 close(fd);
185 return -1;
186 }
187 ret = fchown(fd, (uid_t)-1, pathGroup);
188 if (ret < 0) {
189 tloge("chown failed\n");
190 gzclose(out);
191 return -1;
192 }
193 ret = fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP);
194 if (ret < 0) {
195 tloge("chmod failed\n");
196 gzclose(out);
197 return -1;
198 }
199
200 *outFile = out;
201 return 0;
202 }
203
JudgeFileValidite(const char * index,struct stat * fileAttr)204 static bool JudgeFileValidite(const char *index, struct stat *fileAttr)
205 {
206 if (index == NULL) {
207 return false;
208 }
209
210 if (lstat(index, fileAttr) < 0) {
211 return false;
212 }
213
214 if (!S_ISREG(fileAttr->st_mode)) {
215 return false;
216 }
217 return true;
218 }
219
220 #define FILE_NAME_INVALID_LEN 8U
WriteSingleFile(const char * fileName,gzFile out)221 static int32_t WriteSingleFile(const char *fileName, gzFile out)
222 {
223 struct stat fileAttr = {0};
224 struct TagHeader header;
225 char *s1 = NULL;
226 int32_t ret;
227
228 if (!JudgeFileValidite(fileName, &fileAttr)) {
229 return 0;
230 }
231
232 /* fileName contain file path and file name, search for the file name from fileName. */
233 s1 = strrchr(fileName, '/');
234 if (s1 == NULL || strlen(s1) < FILE_NAME_INVALID_LEN) {
235 return -1;
236 }
237
238 (void)memset_s(&header, sizeof(header), 0, sizeof(header));
239 WriteHeader(&header, (const char *)(s1 + 1), fileAttr.st_size);
240 ret = gzwrite(out, &header, sizeof(struct TagHeader));
241 if (ret < 0) {
242 tloge("gzwrite failed\n");
243 return -1;
244 }
245 WriteZipContent(out, fileName, fileAttr.st_size);
246 return 0;
247 }
248
249 /* tar and zip input files to output file */
TarZipFiles(uint32_t nameCount,const char ** inputNames,const char * outputName,gid_t pathGroup)250 void TarZipFiles(uint32_t nameCount, const char **inputNames, const char *outputName, gid_t pathGroup)
251 {
252 gzFile out = NULL;
253 int32_t ret;
254 struct TagHeader endHeader;
255 const char **fileName = NULL;
256 uint32_t i;
257 bool cond = (inputNames == NULL || outputName == NULL || nameCount != LOG_FILE_INDEX_MAX);
258
259 if (cond) {
260 return;
261 }
262
263 ret = OpenZipFile(outputName, &out, pathGroup);
264 if (ret != 0) {
265 return;
266 }
267
268 fileName = inputNames;
269 for (i = 0; i < nameCount; ++i) {
270 if (*fileName == NULL) {
271 ++fileName;
272 continue;
273 }
274 ret = WriteSingleFile(*fileName, out);
275 if (ret != 0) {
276 goto GZ_CLOSE;
277 }
278
279 ++fileName;
280 }
281
282 (void)memset_s(&endHeader, sizeof(endHeader), 0, sizeof(endHeader));
283 ret = gzwrite(out, &endHeader, sizeof(endHeader));
284 if (ret < 0) {
285 tloge("gzwrite failed\n");
286 }
287
288 GZ_CLOSE:
289 gzclose(out);
290 return;
291 }
292