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