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