• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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