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