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 */ 47struct 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 */ 59static const char FILE_MODE[] = { 0x31, 0x30, 0x30, 0x36, 0x36, 0x36, 0x20, 0 }; 60 61/* tar file haeder UID and GID date */ 62static const char ID_BYTE[] = { 63 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x00, 64}; 65 66static 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 */ 80static 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 */ 129static 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 166CLOSE_FD: 167 close(fileFd); 168} 169 170static 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 204static 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 221static 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 */ 250void 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 288GZ_CLOSE: 289 gzclose(out); 290 return; 291} 292