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