1 /*
2 * Copyright (c) 2021 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 #include "zip_internal.h"
16 #include <unistd.h>
17 #include <stddef.h>
18 #include <algorithm>
19 #include "zip_utils.h"
20 #include "securec.h"
21 #include "hilog_wrapper.h"
22
23 namespace OHOS {
24 namespace AAFwk {
25 namespace LIBZIP {
26
GetTmDataFromTickts(int64_t sec)27 struct tm GetTmDataFromTickts(int64_t sec)
28 {
29 time_t second = (time_t)sec;
30 struct tm now {
31 .tm_year = 0,
32 .tm_mon = 0,
33 .tm_mday = 0,
34 .tm_hour = 0,
35 .tm_min = 0,
36 .tm_sec = 0,
37 };
38 struct tm *tmNow = localtime(&second);
39 if (tmNow == nullptr) {
40 return now;
41 }
42 int baseYeaar = 1900;
43 now = *tmNow;
44 now.tm_year += baseYeaar;
45 now.tm_mon += 1;
46 return now;
47 }
48
49 // Callback function for zlib that opens a file stream from a file descriptor.
50 // Since we do not own the file descriptor, dup it so that we can fdopen/fclose
51 // a file stream.
FdOpenFileFunc(void * opaque,const char * filename,int mode)52 void *FdOpenFileFunc(void *opaque, const char *filename, int mode)
53 {
54 FILE *file = NULL;
55 const char *mode_fopen = NULL;
56 uint32_t modeInner = static_cast<uint32_t>(mode);
57 if ((modeInner & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ)
58 mode_fopen = "rb";
59 else if (modeInner & ZLIB_FILEFUNC_MODE_EXISTING)
60 mode_fopen = "r+b";
61 else if (modeInner & ZLIB_FILEFUNC_MODE_CREATE)
62 mode_fopen = "wb";
63
64 if ((filename != NULL) && (mode_fopen != NULL)) {
65 int fd = dup(*static_cast<int *>(opaque));
66 if (fd != -1)
67 file = fdopen(fd, mode_fopen);
68 }
69
70 return file;
71 }
72
FdCloseFileFunc(void * opaque,void * stream)73 int FdCloseFileFunc(void *opaque, void *stream)
74 {
75 fclose(static_cast<FILE *>(stream));
76 free(opaque); // malloc'ed in FillFdOpenFileFunc()
77 return 0;
78 }
79
80 // Fills |pzlib_filecunc_def| appropriately to handle the zip file
81 // referred to by |fd|.
FillFdOpenFileFunc(zlib_filefunc_def * pzlibFilefuncDef,PlatformFile fd)82 void FillFdOpenFileFunc(zlib_filefunc_def *pzlibFilefuncDef, PlatformFile fd)
83 {
84 fill_fopen_filefunc(pzlibFilefuncDef);
85 pzlibFilefuncDef->zopen_file = FdOpenFileFunc;
86 pzlibFilefuncDef->zclose_file = FdCloseFileFunc;
87 int *ptrFd = static_cast<int *>(malloc(sizeof(fd)));
88 if (ptrFd == nullptr) {
89 return;
90 }
91 *ptrFd = fd;
92 pzlibFilefuncDef->opaque = ptrFd;
93 }
94
95 // A struct that contains data required for zlib functions to extract files from
96 // a zip archive stored in memory directly. The following I/O API functions
97 // expect their opaque parameters refer to this struct.
98 struct ZipBuffer {
99 const char *data;
100 size_t length;
101 size_t offset;
102 };
103
104 // Opens the specified file. When this function returns a non-NULL pointer, zlib
105 // uses this pointer as a stream parameter while compressing or uncompressing
106 // data. (Returning NULL represents an error.) This function initializes the
107 // given opaque parameter and returns it because this parameter stores all
108 // information needed for uncompressing data. (This function does not support
109 // writing compressed data and it returns NULL for this case.)
OpenZipBuffer(void * opaque,const char *,int mode)110 void *OpenZipBuffer(void *opaque, const char *, int mode)
111 {
112 uint32_t modeInner = static_cast<uint32_t>(mode);
113 if ((modeInner & ZLIB_FILEFUNC_MODE_READWRITEFILTER) != ZLIB_FILEFUNC_MODE_READ) {
114 HILOG_INFO("%{public}s called, mode is not ZLIB_FILEFUNC_MODE_READ.", __func__);
115 return NULL;
116 }
117 ZipBuffer *buffer = static_cast<ZipBuffer *>(opaque);
118 if (!buffer || !buffer->data || !buffer->length) {
119 return NULL;
120 }
121 buffer->offset = 0;
122 return opaque;
123 }
124
125 // Reads compressed data from the specified stream. This function copies data
126 // refered by the opaque parameter and returns the size actually copied.
ReadZipBuffer(void * opaque,void *,void * buf,uLong size)127 uLong ReadZipBuffer(void *opaque, void *, void *buf, uLong size)
128 {
129 ZipBuffer *buffer = static_cast<ZipBuffer *>(opaque);
130 if (buffer == nullptr) {
131 HILOG_INFO("%{public}s called, buffer = nullptr.", __func__);
132 return 0;
133 }
134 if (buffer->offset > buffer->length) {
135 HILOG_INFO("%{public}s called, buffer->offset > buffer->length.", __func__);
136 return 0;
137 }
138
139 size_t remaining_bytes = buffer->length - buffer->offset;
140 if (!buffer || !buffer->data || !remaining_bytes) {
141 return 0;
142 }
143 size = std::min(size, static_cast<uLong>(remaining_bytes));
144 if (memcpy_s(buf, size, &buffer->data[buffer->offset], size) != EOK) {
145 return 0;
146 }
147 buffer->offset += size;
148 return size;
149 }
150
151 // Writes compressed data to the stream. This function always returns zero
152 // because this implementation is only for reading compressed data.
WriteZipBuffer(void * opaque,void * stream,const void * buf,uLong)153 uLong WriteZipBuffer(void *opaque, void *stream, const void *buf, uLong)
154 {
155 HILOG_INFO("%{public}s called. opaque=%p, stream=%p, buf=%p", __func__, opaque, stream, buf);
156 return 0;
157 }
158
159 // Returns the offset from the beginning of the data.
GetOffsetOfZipBuffer(void * opaque,void *)160 long GetOffsetOfZipBuffer(void *opaque, void *)
161 {
162 ZipBuffer *buffer = static_cast<ZipBuffer *>(opaque);
163 if (!buffer) {
164 return -1;
165 }
166 return static_cast<long>(buffer->offset);
167 }
168
169 // Moves the current offset to the specified position.
SeekZipBuffer(void * opaque,void *,uLong offset,int origin)170 long SeekZipBuffer(void *opaque, void *, uLong offset, int origin)
171 {
172 ZipBuffer *buffer = static_cast<ZipBuffer *>(opaque);
173 if (!buffer) {
174 return -1;
175 }
176 if (origin == ZLIB_FILEFUNC_SEEK_CUR) {
177 buffer->offset = std::min(buffer->offset + static_cast<size_t>(offset), buffer->length);
178 return 0;
179 }
180 if (origin == ZLIB_FILEFUNC_SEEK_END) {
181 buffer->offset = (buffer->length > offset) ? buffer->length - offset : 0;
182 return 0;
183 }
184 if (origin == ZLIB_FILEFUNC_SEEK_SET) {
185 buffer->offset = std::min(buffer->length, static_cast<size_t>(offset));
186 return 0;
187 }
188 HILOG_INFO("%{public}s called. origin is not supported.", __func__);
189 return -1;
190 }
191
192 // Closes the input offset and deletes all resources used for compressing or
193 // uncompressing data. This function deletes the ZipBuffer object referred by
194 // the opaque parameter since zlib deletes the unzFile object and it does not
195 // use this object any longer.
CloseZipBuffer(void * opaque,void *)196 int CloseZipBuffer(void *opaque, void *)
197 {
198 if (opaque) {
199 free(opaque);
200 }
201 return 0;
202 }
203
204 // Returns the last error happened when reading or writing data. This function
205 // always returns zero, which means there are not any errors.
GetErrorOfZipBuffer(void *,void *)206 int GetErrorOfZipBuffer(void *, void *)
207 {
208 return 0;
209 }
210
TimeToZipFileInfo(const struct tm * fileTime,zip_fileinfo & zipInfo)211 bool TimeToZipFileInfo(const struct tm *fileTime, zip_fileinfo &zipInfo)
212 {
213 if (fileTime == nullptr) {
214 return false;
215 }
216
217 zipInfo.tmz_date.tm_year = (int)fileTime->tm_year + 1900;
218 zipInfo.tmz_date.tm_mon = (int)fileTime->tm_mon + 1;
219 zipInfo.tmz_date.tm_mday = (int)fileTime->tm_mday;
220 zipInfo.tmz_date.tm_hour = (int)fileTime->tm_hour;
221 zipInfo.tmz_date.tm_min = (int)fileTime->tm_min;
222 zipInfo.tmz_date.tm_sec = (int)fileTime->tm_sec;
223 return true;
224 }
225
OpenForUnzipping(std::string & fileNameUtf8)226 unzFile OpenForUnzipping(std::string &fileNameUtf8)
227 {
228 zlib_filefunc_def *zipFuncPtrs = nullptr;
229 return unzOpen2(fileNameUtf8.c_str(), zipFuncPtrs);
230 }
231
OpenFdForUnzipping(int zipFD)232 unzFile OpenFdForUnzipping(int zipFD)
233 {
234 zlib_filefunc_def zipFuncs;
235 FillFdOpenFileFunc(&zipFuncs, zipFD);
236 return unzOpen2("fd", &zipFuncs);
237 }
238
239 // static
PrepareMemoryForUnzipping(const std::string & data)240 unzFile PrepareMemoryForUnzipping(const std::string &data)
241 {
242 if (data.empty()) {
243 return NULL;
244 }
245 ZipBuffer *buffer = static_cast<ZipBuffer *>(malloc(sizeof(ZipBuffer)));
246 if (!buffer) {
247 return NULL;
248 }
249 buffer->data = data.data();
250 buffer->length = data.length();
251 buffer->offset = 0;
252
253 zlib_filefunc_def zipFunctions;
254 zipFunctions.zopen_file = OpenZipBuffer;
255 zipFunctions.zread_file = ReadZipBuffer;
256 zipFunctions.zwrite_file = WriteZipBuffer;
257 zipFunctions.ztell_file = GetOffsetOfZipBuffer;
258 zipFunctions.zseek_file = SeekZipBuffer;
259 zipFunctions.zclose_file = CloseZipBuffer;
260 zipFunctions.zerror_file = GetErrorOfZipBuffer;
261 zipFunctions.opaque = static_cast<void *>(buffer);
262 return unzOpen2(NULL, &zipFunctions);
263 }
264
OpenForZipping(const std::string & fileNameUtf8,int appendFlag)265 zipFile OpenForZipping(const std::string &fileNameUtf8, int appendFlag)
266 {
267 zlib_filefunc_def *zipFuncPtrs = NULL;
268 return zipOpen2(fileNameUtf8.c_str(),
269 appendFlag,
270 NULL,
271 zipFuncPtrs);
272 }
273
OpenFdForZipping(PlatformFile zipFd,int appendFlag)274 zipFile OpenFdForZipping(PlatformFile zipFd, int appendFlag)
275 {
276 zlib_filefunc_def zipFuncs;
277 FillFdOpenFileFunc(&zipFuncs, zipFd);
278 // Passing dummy "fd" filename to zlib.
279 return zipOpen2("fd", appendFlag, NULL, &zipFuncs);
280 }
281
ZipOpenNewFileInZip(zipFile zipFile,const std::string & strPath,const OPTIONS & options,const struct tm * lastModifiedTime)282 bool ZipOpenNewFileInZip(
283 zipFile zipFile, const std::string &strPath, const OPTIONS &options, const struct tm *lastModifiedTime)
284 {
285 const uLong LANGUAGE_ENCODING_FLAG = 0x1 << 11;
286
287 zip_fileinfo fileInfo = {};
288 TimeToZipFileInfo(lastModifiedTime, fileInfo);
289 if (ZIP_OK != zipOpenNewFileInZip4(zipFile, // file
290 strPath.c_str(), // filename
291 &fileInfo, // zip_fileinfo
292 NULL, // extrafield_local,
293 0u, // size_extrafield_local
294 NULL, // extrafield_global
295 0u, // size_extrafield_global
296 NULL, // comment
297 Z_DEFLATED, // method
298 (int)options.level, // level:default Z_DEFAULT_COMPRESSION
299 0, // raw
300 -MAX_WBITS, // windowBits
301 (int)options.memLevel, // memLevel: default DEF_MEM_LEVEL
302 (int)options.strategy, // strategy:default Z_DEFAULT_STRATEGY
303 NULL, // password
304 0, // crcForCrypting
305 0, // versionMadeBy
306 LANGUAGE_ENCODING_FLAG)) { // flagBase
307 return false;
308 }
309 return true;
310 }
311
312 } // namespace LIBZIP
313 } // namespace AAFwk
314 } // namespace OHOS
315