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