• 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.h"
16 
17 #include <fcntl.h>
18 #include <list>
19 #include <stdio.h>
20 #include <string>
21 #include <unistd.h>
22 #include <vector>
23 
24 #include "app_log_wrapper.h"
25 #include "appexecfwk_errors.h"
26 #include "bundle_errors.h"
27 #include "directory_ex.h"
28 #include "event_handler.h"
29 #include "file_path.h"
30 #include "zip_internal.h"
31 #include "zip_reader.h"
32 #include "zip_writer.h"
33 
34 using namespace OHOS::AppExecFwk;
35 
36 namespace OHOS {
37 namespace AppExecFwk {
38 namespace LIBZIP {
39 namespace {
40 using FilterCallback = std::function<bool(const FilePath &)>;
41 using DirectoryCreator = std::function<bool(FilePath &, FilePath &)>;
42 using WriterFactory = std::function<std::unique_ptr<WriterDelegate>(FilePath &, FilePath &)>;
43 
44 const std::string SEPARATOR = "/";
45 const char HIDDEN_SEPARATOR = '.';
46 const std::string ZIP = ".zip";
47 
48 struct UnzipParam {
49     FilterCallback filterCB = nullptr;
50     bool logSkippedFiles = false;
51 };
IsHiddenFile(const FilePath & filePath)52 bool IsHiddenFile(const FilePath &filePath)
53 {
54     FilePath localFilePath = filePath;
55     if (!localFilePath.Value().empty()) {
56         return localFilePath.Value().c_str()[0] == HIDDEN_SEPARATOR;
57     } else {
58         return false;
59     }
60 }
ExcludeNoFilesFilter(const FilePath & filePath)61 bool ExcludeNoFilesFilter(const FilePath &filePath)
62 {
63     return true;
64 }
65 
ExcludeHiddenFilesFilter(const FilePath & filePath)66 bool ExcludeHiddenFilesFilter(const FilePath &filePath)
67 {
68     return !IsHiddenFile(filePath);
69 }
70 
ListDirectoryContent(const FilePath & filePath,bool & isSuccess)71 std::vector<FileAccessor::DirectoryContentEntry> ListDirectoryContent(const FilePath &filePath, bool& isSuccess)
72 {
73     FilePath curPath = filePath;
74     std::vector<FileAccessor::DirectoryContentEntry> fileDirectoryVector;
75     std::vector<std::string> filelist;
76     isSuccess = FilePath::GetZipAllDirFiles(curPath.Value(), filelist);
77     if (isSuccess) {
78         APP_LOGI("ListDirectoryContent filelist =====filelist.size=%{public}zu====", filelist.size());
79         for (size_t i = 0; i < filelist.size(); i++) {
80             std::string str(filelist[i]);
81             if (!str.empty()) {
82                 fileDirectoryVector.push_back(
83                     FileAccessor::DirectoryContentEntry(FilePath(str), FilePath::DirectoryExists(FilePath(str))));
84             }
85         }
86     }
87     return fileDirectoryVector;
88 }
89 
90 // Creates a directory at |extractDir|/|entryPath|, including any parents.
CreateDirectory(FilePath & extractDir,FilePath & entryPath)91 bool CreateDirectory(FilePath &extractDir, FilePath &entryPath)
92 {
93     std::string path = extractDir.Value();
94     if (EndsWith(path, SEPARATOR)) {
95         return FilePath::CreateDirectory(FilePath(extractDir.Value() + entryPath.Value()));
96     } else {
97         return FilePath::CreateDirectory(FilePath(extractDir.Value() + "/" + entryPath.Value()));
98     }
99 }
100 
101 // Creates a WriterDelegate that can write a file at |extractDir|/|entryPath|.
CreateFilePathWriterDelegate(FilePath & extractDir,FilePath entryPath)102 std::unique_ptr<WriterDelegate> CreateFilePathWriterDelegate(FilePath &extractDir, FilePath entryPath)
103 {
104     if (EndsWith(extractDir.Value(), SEPARATOR)) {
105         return std::make_unique<FilePathWriterDelegate>(FilePath(extractDir.Value() + entryPath.Value()));
106     } else {
107         return std::make_unique<FilePathWriterDelegate>(FilePath(extractDir.Value() + "/" + entryPath.Value()));
108     }
109 }
110 }  // namespace
111 
ZipParams(const FilePath & srcDir,const FilePath & destFile)112 ZipParams::ZipParams(const FilePath &srcDir, const FilePath &destFile) : srcDir_(srcDir), destFile_(destFile)
113 {}
114 
115 // Does not take ownership of |fd|.
ZipParams(const FilePath & srcDir,int destFd)116 ZipParams::ZipParams(const FilePath &srcDir, int destFd) : srcDir_(srcDir), destFd_(destFd)
117 {}
118 
FilePathEndIsSeparator(FilePath paramPath)119 FilePath FilePathEndIsSeparator(FilePath paramPath)
120 {
121     bool endIsSeparator = EndsWith(paramPath.Value(), SEPARATOR);
122     if (FilePath::IsDir(paramPath)) {
123         if (!endIsSeparator) {
124             paramPath.AppendSeparator();
125         }
126     }
127     return paramPath;
128 }
129 
Zip(const ZipParams & params,const OPTIONS & options)130 bool Zip(const ZipParams &params, const OPTIONS &options)
131 {
132     const std::vector<FilePath> *filesToAdd = &params.GetFilesTozip();
133     std::vector<FilePath> allRelativeFiles;
134     FilePath paramPath = FilePathEndIsSeparator(params.SrcDir());
135     if (filesToAdd->empty()) {
136         filesToAdd = &allRelativeFiles;
137         std::list<FileAccessor::DirectoryContentEntry> entries;
138         if (EndsWith(paramPath.Value(), SEPARATOR)) {
139             entries.push_back(FileAccessor::DirectoryContentEntry(params.SrcDir(), true));
140             FilterCallback filterCallback = params.GetFilterCallback();
141             for (auto iter = entries.begin(); iter != entries.end(); ++iter) {
142                 if (iter != entries.begin() && ((!params.GetIncludeHiddenFiles() && IsHiddenFile(iter->path)) ||
143                     (filterCallback && !filterCallback(iter->path)))) {
144                     continue;
145                 }
146                 if (iter != entries.begin()) {
147                     FilePath relativePath;
148                     FilePath paramsSrcPath = params.SrcDir();
149                     if (paramsSrcPath.AppendRelativePath(iter->path, &relativePath)) {
150                         allRelativeFiles.push_back(relativePath);
151                     }
152                 }
153                 if (iter->isDirectory) {
154                     bool isSuccess = false;
155                     std::vector<FileAccessor::DirectoryContentEntry> subEntries =
156                         ListDirectoryContent(iter->path, isSuccess);
157                     entries.insert(entries.end(), subEntries.begin(), subEntries.end());
158                 }
159             }
160         } else {
161             allRelativeFiles.push_back(paramPath.BaseName());
162         }
163     }
164     std::unique_ptr<ZipWriter> zipWriter = nullptr;
165     if (params.DestFd() != kInvalidPlatformFile) {
166         zipWriter = std::make_unique<ZipWriter>(ZipWriter::InitZipFileWithFd(params.DestFd()), paramPath);
167     } else {
168         zipWriter = std::make_unique<ZipWriter>(ZipWriter::InitZipFileWithFile(params.DestFile()), paramPath);
169     }
170     if (zipWriter == nullptr) {
171         APP_LOGE("Init zipWriter failed!");
172         return false;
173     }
174     return zipWriter->WriteEntries(*filesToAdd, options);
175 }
176 
UnzipWithFilterAndWriters(const PlatformFile & srcFile,FilePath & destDir,WriterFactory writerFactory,DirectoryCreator directoryCreator,UnzipParam & unzipParam)177 ErrCode UnzipWithFilterAndWriters(const PlatformFile &srcFile, FilePath &destDir, WriterFactory writerFactory,
178     DirectoryCreator directoryCreator, UnzipParam &unzipParam)
179 {
180     APP_LOGI("%{public}s called, destDir=%{private}s", __func__, destDir.Value().c_str());
181     ZipReader reader;
182     if (!reader.OpenFromPlatformFile(srcFile)) {
183         APP_LOGI("%{public}s called, Failed to open srcFile.", __func__);
184         return ERR_ZLIB_SRC_FILE_FORMAT_ERROR;
185     }
186     while (reader.HasMore()) {
187         if (!reader.OpenCurrentEntryInZip()) {
188             APP_LOGI("%{public}s called, Failed to open the current file in zip.", __func__);
189             return ERR_ZLIB_SERVICE_DISABLED;
190         }
191         const FilePath &constEntryPath = reader.CurrentEntryInfo()->GetFilePath();
192         FilePath entryPath = constEntryPath;
193         if (reader.CurrentEntryInfo()->IsUnsafe()) {
194             APP_LOGI("%{public}s called, Found an unsafe file in zip.", __func__);
195             return ERR_ZLIB_SERVICE_DISABLED;
196         }
197         // callback
198         if (unzipParam.filterCB(entryPath)) {
199             if (reader.CurrentEntryInfo()->IsDirectory()) {
200                 if (!directoryCreator(destDir, entryPath)) {
201                     APP_LOGI("!!!directory_creator(%{private}s) Failed!!!.", entryPath.Value().c_str());
202                     return ERR_ZLIB_DEST_FILE_DISABLED;
203                 }
204 
205             } else {
206                 std::unique_ptr<WriterDelegate> writer = writerFactory(destDir, entryPath);
207                 if (!reader.ExtractCurrentEntry(writer.get(), std::numeric_limits<uint64_t>::max())) {
208                     APP_LOGI("%{public}s called, Failed to extract.", __func__);
209                     return ERR_ZLIB_SERVICE_DISABLED;
210                 }
211             }
212         } else if (unzipParam.logSkippedFiles) {
213             APP_LOGI("%{public}s called, Skipped file.", __func__);
214         }
215 
216         if (!reader.AdvanceToNextEntry()) {
217             APP_LOGI("%{public}s called, Failed to advance to the next file.", __func__);
218             return ERR_ZLIB_SERVICE_DISABLED;
219         }
220     }
221     return ERR_OK;
222 }
223 
UnzipWithFilterCallback(const FilePath & srcFile,const FilePath & destDir,const OPTIONS & options,UnzipParam & unzipParam)224 ErrCode UnzipWithFilterCallback(
225     const FilePath &srcFile, const FilePath &destDir, const OPTIONS &options, UnzipParam &unzipParam)
226 {
227     FilePath src = srcFile;
228     if (!FilePathCheckValid(src.Value())) {
229         APP_LOGI("%{public}s called, FilePathCheckValid returnValue is false.", __func__);
230         return ERR_ZLIB_SRC_FILE_DISABLED;
231     }
232 
233     FilePath dest = destDir;
234 
235     APP_LOGI("%{public}s called,  srcFile=%{private}s, destFile=%{private}s",
236         __func__,
237         src.Value().c_str(),
238         dest.Value().c_str());
239 
240     if (!FilePath::PathIsValid(srcFile)) {
241         APP_LOGI("%{public}s called,PathIsValid return value is false.", __func__);
242         return ERR_ZLIB_SRC_FILE_DISABLED;
243     }
244 
245     PlatformFile zipFd = open(src.Value().c_str(), S_IREAD, O_CREAT);
246     if (zipFd == kInvalidPlatformFile) {
247         APP_LOGI("%{public}s called, Failed to open.", __func__);
248         return ERR_ZLIB_SRC_FILE_DISABLED;
249     }
250     ErrCode ret = UnzipWithFilterAndWriters(zipFd,
251         dest,
252         std::bind(&CreateFilePathWriterDelegate, std::placeholders::_1, std::placeholders::_2),
253         std::bind(&CreateDirectory, std::placeholders::_1, std::placeholders::_2),
254         unzipParam);
255     close(zipFd);
256     return ret;
257 }
258 
Unzip(const std::string & srcFile,const std::string & destFile,OPTIONS options,std::shared_ptr<ZlibCallbackInfo> zlibCallbackInfo)259 bool Unzip(const std::string &srcFile, const std::string &destFile, OPTIONS options,
260     std::shared_ptr<ZlibCallbackInfo> zlibCallbackInfo)
261 {
262     if (zlibCallbackInfo == nullptr) {
263         APP_LOGE("zlibCallbackInfo is nullptr!");
264         return false;
265     }
266     FilePath srcFileDir(srcFile);
267     FilePath destDir(destFile);
268     if (destDir.Value().size() == 0) {
269         zlibCallbackInfo->OnZipUnZipFinish(ERR_ZLIB_DEST_FILE_DISABLED);
270         return false;
271     }
272     if (srcFileDir.Value().size() == 0) {
273         APP_LOGI("%{public}s called fail, srcFile isn't Exist.", __func__);
274         zlibCallbackInfo->OnZipUnZipFinish(ERR_ZLIB_SRC_FILE_DISABLED);
275         return false;
276     }
277     if (!FilePath::PathIsValid(srcFileDir)) {
278         APP_LOGI("%{public}s called fail, srcFile isn't Exist.", __func__);
279         zlibCallbackInfo->OnZipUnZipFinish(ERR_ZLIB_SRC_FILE_DISABLED);
280         return false;
281     }
282     if (FilePath::DirectoryExists(destDir)) {
283         if (!FilePath::PathIsValid(destDir)) {
284             APP_LOGI("%{public}s called, FilePath::PathIsValid(destDir) fail.", __func__);
285             zlibCallbackInfo->OnZipUnZipFinish(ERR_ZLIB_DEST_FILE_DISABLED);
286         }
287     } else {
288         APP_LOGI("%{public}s called fail, destDir isn't path.", __func__);
289         zlibCallbackInfo->OnZipUnZipFinish(ERR_ZLIB_DEST_FILE_DISABLED);
290         return false;
291     }
292     auto innerTask = [srcFileDir, destDir, options, zlibCallbackInfo]() {
293         UnzipParam unzipParam {
294             .filterCB = ExcludeNoFilesFilter,
295             .logSkippedFiles = true
296         };
297         ErrCode err = UnzipWithFilterCallback(srcFileDir, destDir, options, unzipParam);
298         if (zlibCallbackInfo != nullptr) {
299             zlibCallbackInfo->OnZipUnZipFinish(err);
300         }
301     };
302     PostTask(innerTask);
303     return true;
304 }
305 
ZipWithFilterCallback(const FilePath & srcDir,const FilePath & destFile,const OPTIONS & options,FilterCallback filterCB)306 ErrCode ZipWithFilterCallback(const FilePath &srcDir, const FilePath &destFile,
307     const OPTIONS &options, FilterCallback filterCB)
308 {
309     FilePath destPath = destFile;
310     if (FilePath::DirectoryExists(destFile)) {
311         if (!FilePath::PathIsValid(destFile)) {
312             APP_LOGI("%{public}s called fail, destFile isn't Exist.", __func__);
313             return ERR_ZLIB_DEST_FILE_DISABLED;
314         }
315     } else if (!FilePath::PathIsValid(destPath.DirName())) {
316         APP_LOGI("%{public}s called fail, The path where destFile is located doesn't exist.", __func__);
317         return ERR_ZLIB_DEST_FILE_DISABLED;
318     }
319 
320     if (FilePath::DirectoryExists(srcDir)) {
321         if (!FilePath::PathIsValid(srcDir)) {
322             APP_LOGI("%{public}s called fail, srcDir isn't Exist.", __func__);
323             return ERR_ZLIB_SRC_FILE_DISABLED;
324         }
325     } else if (!FilePath::PathIsValid(srcDir)) {
326         APP_LOGI("%{public}s called fail, The path where srcDir is located doesn't exist.", __func__);
327         return ERR_ZLIB_SRC_FILE_DISABLED;
328     }
329 
330     ZipParams params(srcDir, FilePath(destPath.CheckDestDirTail()));
331     params.SetFilterCallback(filterCB);
332     bool result = Zip(params, options);
333     if (result) {
334         return ERR_OK;
335     } else {
336         return ERR_ZLIB_SERVICE_DISABLED;
337     }
338 }
339 
Zip(const std::string & srcPath,const std::string & destPath,bool includeHiddenFiles,std::shared_ptr<ZlibCallbackInfo> zlibCallbackInfo)340 bool Zip(const std::string &srcPath, const std::string &destPath,
341     bool includeHiddenFiles, std::shared_ptr<ZlibCallbackInfo> zlibCallbackInfo)
342 {
343     if (zlibCallbackInfo == nullptr) {
344         return false;
345     }
346     FilePath srcDir(srcPath);
347     FilePath destFile(destPath);
348     APP_LOGI("%{public}s called,  srcDir=%{private}s, destFile=%{private}s", __func__,
349         srcDir.Value().c_str(), destFile.Value().c_str());
350 
351     if (srcDir.Value().size() == 0) {
352         zlibCallbackInfo->OnZipUnZipFinish(ERR_ZLIB_SRC_FILE_DISABLED);
353         return false;
354     }
355     if (destFile.Value().size() == 0) {
356         zlibCallbackInfo->OnZipUnZipFinish(ERR_ZLIB_DEST_FILE_DISABLED);
357         return false;
358     }
359 
360     auto innerTask = [srcDir, destFile, includeHiddenFiles, zlibCallbackInfo]() {
361         OPTIONS options;
362         if (includeHiddenFiles) {
363             ErrCode err = ZipWithFilterCallback(srcDir, destFile, options, ExcludeNoFilesFilter);
364             if (zlibCallbackInfo != nullptr) {
365                 zlibCallbackInfo->OnZipUnZipFinish(err);
366             }
367         } else {
368             ErrCode err = ZipWithFilterCallback(srcDir, destFile, options, ExcludeHiddenFilesFilter);
369             if (zlibCallbackInfo != nullptr) {
370                 zlibCallbackInfo->OnZipUnZipFinish(err);
371             }
372         }
373     };
374 
375     PostTask(innerTask);
376     return true;
377 }
378 }  // namespace LIBZIP
379 }  // namespace AppExecFwk
380 }  // namespace OHOS
381