• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2025 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 "ffrt.h"
30 #include "file_path.h"
31 #include "zip_internal.h"
32 #include "zip_reader.h"
33 #include "zip_writer.h"
34 
35 using namespace OHOS::AppExecFwk;
36 
37 namespace OHOS {
38 namespace AppExecFwk {
39 namespace LIBZIP {
40 namespace {
41 using FilterCallback = std::function<bool(const FilePath &)>;
42 using DirectoryCreator = std::function<bool(FilePath &, FilePath &)>;
43 using WriterFactory = std::function<std::unique_ptr<WriterDelegate>(FilePath &, FilePath &)>;
44 
45 const std::string SEPARATOR = "/";
46 const char HIDDEN_SEPARATOR = '.';
47 const std::string ZIP = ".zip";
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()[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_LOGD("f.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 std::vector<FilePath> & srcDir,const FilePath & destFile)113 ZipParams::ZipParams(const std::vector<FilePath>& srcDir, const FilePath& destFile)
114     : srcDir_(srcDir), destFile_(destFile)
115 {}
116 
117 // Does not take ownership of |fd|.
ZipParams(const std::vector<FilePath> & srcDir,int destFd)118 ZipParams::ZipParams(const std::vector<FilePath> &srcDir, int destFd) : srcDir_(srcDir), destFd_(destFd)
119 {}
120 
FilePathEndIsSeparator(FilePath paramPath)121 FilePath FilePathEndIsSeparator(FilePath paramPath)
122 {
123     bool endIsSeparator = EndsWith(paramPath.Value(), SEPARATOR);
124     if (FilePath::IsDir(paramPath)) {
125         if (!endIsSeparator) {
126             paramPath.AppendSeparator();
127         }
128     }
129     return paramPath;
130 }
131 
Zip(const ZipParams & params,const OPTIONS & options)132 bool Zip(const ZipParams &params, const OPTIONS &options)
133 {
134     const std::vector<std::pair<FilePath, FilePath>> *filesToAdd = &params.GetFilesTozip();
135     std::vector<std::pair<FilePath, FilePath>> allRelativeFiles;
136     FilePath srcDir = params.SrcDir().front();
137     FilePath paramPath = FilePathEndIsSeparator(srcDir);
138     if (filesToAdd->empty()) {
139         filesToAdd = &allRelativeFiles;
140         std::list<FileAccessor::DirectoryContentEntry> entries;
141         if (EndsWith(paramPath.Value(), SEPARATOR)) {
142             entries.push_back(FileAccessor::DirectoryContentEntry(srcDir, true));
143             FilterCallback filterCallback = params.GetFilterCallback();
144             for (auto iter = entries.begin(); iter != entries.end(); ++iter) {
145                 if (iter != entries.begin() && ((!params.GetIncludeHiddenFiles() && IsHiddenFile(iter->path)) ||
146                     (filterCallback && !filterCallback(iter->path)))) {
147                     continue;
148                 }
149                 if (iter != entries.begin()) {
150                     FilePath relativePath;
151                     FilePath paramsSrcPath = srcDir;
152                     if (paramsSrcPath.AppendRelativePath(iter->path, &relativePath)) {
153                         allRelativeFiles.push_back(std::make_pair(relativePath, iter->path));
154                     }
155                 }
156                 if (iter->isDirectory) {
157                     bool isSuccess = false;
158                     std::vector<FileAccessor::DirectoryContentEntry> subEntries =
159                         ListDirectoryContent(iter->path, isSuccess);
160                     entries.insert(entries.end(), subEntries.begin(), subEntries.end());
161                 }
162             }
163         } else {
164             allRelativeFiles.push_back(std::make_pair(paramPath.BaseName(), paramPath));
165         }
166     }
167     std::unique_ptr<ZipWriter> zipWriter = nullptr;
168     if (params.DestFd() != kInvalidPlatformFile) {
169         zipWriter = std::make_unique<ZipWriter>(ZipWriter::InitZipFileWithFd(params.DestFd()));
170     } else {
171         zipWriter = std::make_unique<ZipWriter>(ZipWriter::InitZipFileWithFile(params.DestFile()));
172     }
173     if (zipWriter == nullptr) {
174         APP_LOGE("Init zipWriter failed");
175         return false;
176     }
177     return zipWriter->WriteEntries(*filesToAdd, options);
178 }
179 
GetZipsAllRelativeFilesInner(const ZipParams & params,const FilePath & iterPath,std::list<FileAccessor::DirectoryContentEntry> & entries,std::vector<std::pair<FilePath,FilePath>> & allRelativeFiles)180 void GetZipsAllRelativeFilesInner(const ZipParams &params, const FilePath &iterPath,
181     std::list<FileAccessor::DirectoryContentEntry> &entries,
182     std::vector<std::pair<FilePath, FilePath>> &allRelativeFiles)
183 {
184     FilterCallback filterCallback = params.GetFilterCallback();
185     for (auto iter = entries.begin(); iter != entries.end(); ++iter) {
186         if (iter != entries.begin() && ((!params.GetIncludeHiddenFiles() && IsHiddenFile(iter->path)) ||
187             (filterCallback && !filterCallback(iter->path)))) {
188             continue;
189         }
190         if (iter != entries.begin()) {
191             FilePath relativePath;
192             FilePath paramsSrcPath = iterPath;
193             if (paramsSrcPath.AppendRelativePath(iter->path, &relativePath)) {
194                 allRelativeFiles.push_back(std::make_pair(relativePath, iter->path));
195             }
196         }
197         if (iter->isDirectory) {
198             bool isSuccess = false;
199             std::vector<FileAccessor::DirectoryContentEntry> subEntries = ListDirectoryContent(iter->path, isSuccess);
200             entries.insert(entries.end(), subEntries.begin(), subEntries.end());
201         }
202     }
203 }
204 
GetZipsAllRelativeFiles(const ZipParams & params,std::vector<std::pair<FilePath,FilePath>> & allRelativeFiles,std::vector<FilePath> & srcFiles)205 void GetZipsAllRelativeFiles(const ZipParams &params, std::vector<std::pair<FilePath, FilePath>> &allRelativeFiles,
206     std::vector<FilePath> &srcFiles)
207 {
208     std::list<FileAccessor::DirectoryContentEntry> entries;
209     for (auto iterPath = srcFiles.begin(); iterPath != srcFiles.end(); ++iterPath) {
210         FilePath paramPath = FilePathEndIsSeparator(*iterPath);
211         if (!EndsWith(paramPath.Value(), SEPARATOR)) {
212             allRelativeFiles.push_back(std::make_pair(paramPath.BaseName(), paramPath));
213             continue;
214         }
215         entries.clear();
216         entries.push_back(FileAccessor::DirectoryContentEntry(*iterPath, true));
217         GetZipsAllRelativeFilesInner(params, *iterPath, entries, allRelativeFiles);
218     }
219 }
220 
Zips(const ZipParams & params,const OPTIONS & options)221 bool Zips(const ZipParams &params, const OPTIONS &options)
222 {
223     const std::vector<std::pair<FilePath, FilePath>> *filesToAdd = &params.GetFilesTozip();
224     std::vector<std::pair<FilePath, FilePath>> allRelativeFiles;
225     std::vector<FilePath> srcFiles = params.SrcDir();
226     if (filesToAdd->empty()) {
227         filesToAdd = &allRelativeFiles;
228         GetZipsAllRelativeFiles(params, allRelativeFiles, srcFiles);
229     }
230     std::unique_ptr<ZipWriter> zipWriter = nullptr;
231     if (params.DestFd() != kInvalidPlatformFile) {
232         zipWriter = std::make_unique<ZipWriter>(ZipWriter::InitZipFileWithFd(params.DestFd()));
233     } else {
234         zipWriter = std::make_unique<ZipWriter>(ZipWriter::InitZipFileWithFile(params.DestFile()));
235     }
236     if (zipWriter == nullptr) {
237         APP_LOGE("Init zipWriter failed");
238         return false;
239     }
240     return zipWriter->WriteEntries(*filesToAdd, options);
241 }
242 
UnzipWithFilterAndWriters(const PlatformFile & srcFile,FilePath & destDir,WriterFactory writerFactory,DirectoryCreator directoryCreator,UnzipParam & unzipParam)243 ErrCode UnzipWithFilterAndWriters(const PlatformFile &srcFile, FilePath &destDir, WriterFactory writerFactory,
244     DirectoryCreator directoryCreator, UnzipParam &unzipParam)
245 {
246     APP_LOGD("destDir=%{private}s", destDir.Value().c_str());
247     ZipReader reader;
248     if (!reader.OpenFromPlatformFile(srcFile)) {
249         APP_LOGI("Failed to open srcFile");
250         return ERR_ZLIB_SRC_FILE_FORMAT_ERROR;
251     }
252     while (reader.HasMore()) {
253         if (!reader.OpenCurrentEntryInZip()) {
254             APP_LOGI("Failed to open the current file in zip");
255             return ERR_ZLIB_SRC_FILE_FORMAT_ERROR;
256         }
257         const FilePath &constEntryPath = reader.CurrentEntryInfo()->GetFilePath();
258         FilePath entryPath = constEntryPath;
259         if (reader.CurrentEntryInfo()->IsUnsafe()) {
260             APP_LOGI("Found an unsafe file in zip");
261             return ERR_ZLIB_SRC_FILE_FORMAT_ERROR;
262         }
263         // callback
264         if (unzipParam.filterCB(entryPath)) {
265             if (reader.CurrentEntryInfo()->IsDirectory()) {
266                 if (!directoryCreator(destDir, entryPath)) {
267                     APP_LOGI("directory_creator(%{private}s) Failed", entryPath.Value().c_str());
268                     return ERR_ZLIB_DEST_FILE_DISABLED;
269                 }
270             } else {
271                 std::unique_ptr<WriterDelegate> writer = writerFactory(destDir, entryPath);
272                 if (!writer->PrepareOutput()) {
273                     APP_LOGE("PrepareOutput err");
274                     return ERR_ZLIB_DEST_FILE_DISABLED;
275                 }
276                 if (!reader.ExtractCurrentEntry(writer.get(), std::numeric_limits<uint64_t>::max())) {
277                     APP_LOGI("Failed to extract");
278                     return ERR_ZLIB_SRC_FILE_FORMAT_ERROR;
279                 }
280             }
281         } else if (unzipParam.logSkippedFiles) {
282             APP_LOGI("Skipped file");
283         }
284 
285         if (!reader.AdvanceToNextEntry()) {
286             APP_LOGI("Failed to advance to the next file");
287             return ERR_ZLIB_SRC_FILE_FORMAT_ERROR;
288         }
289     }
290     return ERR_OK;
291 }
292 
UnzipWithFilterAndWritersParallel(const FilePath & srcFile,FilePath & destDir,WriterFactory writerFactory,DirectoryCreator directoryCreator,UnzipParam & unzipParam)293 ErrCode UnzipWithFilterAndWritersParallel(const FilePath &srcFile, FilePath &destDir, WriterFactory writerFactory,
294     DirectoryCreator directoryCreator, UnzipParam &unzipParam)
295 {
296     APP_LOGD("destDir=%{private}s", destDir.Value().c_str());
297     ZipParallelReader reader;
298     FilePath src = srcFile;
299 
300     if (!reader.Open(src)) {
301         APP_LOGI("Failed to open srcFile");
302         return ERR_ZLIB_SRC_FILE_FORMAT_ERROR;
303     }
304     ErrCode ret = ERR_OK;
305     std::vector<ffrt::dependence> handles;
306     for (int32_t i = 0; i < reader.num_entries(); i++) {
307         if (!reader.OpenCurrentEntryInZip()) {
308             APP_LOGI("Failed to open the current file in zip");
309             return ERR_ZLIB_SRC_FILE_FORMAT_ERROR;
310         }
311         const FilePath &constEntryPath = reader.CurrentEntryInfo()->GetFilePath();
312         if (reader.CurrentEntryInfo()->IsUnsafe()) {
313             APP_LOGI("Found an unsafe file in zip");
314             return ERR_ZLIB_SRC_FILE_FORMAT_ERROR;
315         }
316         unz_file_pos position = {};
317         if (!reader.GetCurrentEntryPos(position)) {
318             return ERR_ZLIB_SRC_FILE_FORMAT_ERROR;
319         }
320         bool isDirectory = reader.CurrentEntryInfo()->IsDirectory();
321         ffrt::task_handle handle = ffrt::submit_h([&, position, isDirectory, constEntryPath] () {
322             if (ret != ERR_OK) {
323                 return;
324             }
325             int resourceId = sched_getcpu();
326             unzFile zipFile = reader.GetZipHandler(resourceId);
327             if (!reader.GotoEntry(zipFile, position)) {
328                 APP_LOGI("Failed to go to entry");
329                 ret = ERR_ZLIB_SRC_FILE_FORMAT_ERROR;
330                 return;
331             }
332             FilePath entryPath = constEntryPath;
333             if (unzipParam.filterCB(entryPath)) {
334                 if (isDirectory) {
335                     if (!directoryCreator(destDir, entryPath)) {
336                         APP_LOGI("directory_creator(%{private}s) Failed", entryPath.Value().c_str());
337                         reader.ReleaseZipHandler(resourceId);
338                         ret = ERR_ZLIB_DEST_FILE_DISABLED;
339                         return;
340                     }
341                 } else {
342                     std::unique_ptr<WriterDelegate> writer = writerFactory(destDir, entryPath);
343                     if (!writer->PrepareOutput()) {
344                         APP_LOGE("PrepareOutput err");
345                         reader.ReleaseZipHandler(resourceId);
346                         ret = ERR_ZLIB_DEST_FILE_DISABLED;
347                         return;
348                     }
349                     if (!reader.ExtractEntry(writer.get(), zipFile, std::numeric_limits<uint64_t>::max())) {
350                         APP_LOGI("Failed to extract");
351                         reader.ReleaseZipHandler(resourceId);
352                         ret = ERR_ZLIB_SRC_FILE_FORMAT_ERROR;
353                         return;
354                     }
355                 }
356             } else if (unzipParam.logSkippedFiles) {
357                 APP_LOGI("Skipped file");
358             }
359             reader.ReleaseZipHandler(resourceId);
360             }, {}, {});
361         handles.push_back(std::move(handle));
362         if (!reader.AdvanceToNextEntry()) {
363             APP_LOGI("Failed to advance to the next file");
364             return ERR_ZLIB_SRC_FILE_FORMAT_ERROR;
365         }
366     }
367     ffrt::wait(handles);
368     return ERR_OK;
369 }
370 
UnzipWithFilterCallback(const FilePath & srcFile,const FilePath & destDir,const OPTIONS & options,UnzipParam & unzipParam)371 ErrCode UnzipWithFilterCallback(
372     const FilePath &srcFile, const FilePath &destDir, const OPTIONS &options, UnzipParam &unzipParam)
373 {
374     FilePath src = srcFile;
375     if (!FilePathCheckValid(src.Value())) {
376         APP_LOGI("FilePathCheckValid returnValue is false");
377         return ERR_ZLIB_SRC_FILE_DISABLED;
378     }
379 
380     FilePath dest = destDir;
381 
382     APP_LOGD("srcFile=%{private}s, destFile=%{private}s", src.Value().c_str(), dest.Value().c_str());
383 
384     if (!FilePath::PathIsValid(srcFile)) {
385         APP_LOGI("PathIsValid return value is false");
386         return ERR_ZLIB_SRC_FILE_DISABLED;
387     }
388 
389     ErrCode ret = ERR_OK;
390     if (options.parallel == PARALLEL_STRATEGY_PARALLEL_DECOMPRESSION) {
391         ret = UnzipWithFilterAndWritersParallel(src,
392             dest,
393             std::bind(&CreateFilePathWriterDelegate, std::placeholders::_1, std::placeholders::_2),
394             std::bind(&CreateDirectory, std::placeholders::_1, std::placeholders::_2),
395             unzipParam);
396     } else {
397         PlatformFile zipFd = open(src.Value().c_str(), S_IREAD, O_CREAT);
398         if (zipFd == kInvalidPlatformFile) {
399             APP_LOGE("Failed to open");
400             return ERR_ZLIB_SRC_FILE_DISABLED;
401         }
402         ret = UnzipWithFilterAndWriters(zipFd,
403             dest,
404             std::bind(&CreateFilePathWriterDelegate, std::placeholders::_1, std::placeholders::_2),
405             std::bind(&CreateDirectory, std::placeholders::_1, std::placeholders::_2),
406             unzipParam);
407         close(zipFd);
408     }
409     return ret;
410 }
411 
Unzip(const std::string & srcFile,const std::string & destFile,OPTIONS options,std::shared_ptr<ZlibCallbackInfoBase> zlibCallbackInfo)412 bool Unzip(const std::string &srcFile, const std::string &destFile, OPTIONS options,
413     std::shared_ptr<ZlibCallbackInfoBase> zlibCallbackInfo)
414 {
415     if (zlibCallbackInfo == nullptr) {
416         APP_LOGE("zlibCallbackInfo is nullptr");
417         return false;
418     }
419     FilePath srcFileDir(srcFile);
420     FilePath destDir(destFile);
421     if ((destDir.Value().size() == 0) || FilePath::HasRelativePathBaseOnAPIVersion(destFile)) {
422         zlibCallbackInfo->OnZipUnZipFinish(ERR_ZLIB_DEST_FILE_DISABLED);
423         return false;
424     }
425     if ((srcFileDir.Value().size() == 0) || FilePath::HasRelativePathBaseOnAPIVersion(srcFile)) {
426         APP_LOGI("srcFile isn't Exist");
427         zlibCallbackInfo->OnZipUnZipFinish(ERR_ZLIB_SRC_FILE_DISABLED);
428         return false;
429     }
430     if (!FilePath::PathIsValid(srcFileDir)) {
431         APP_LOGI("srcFile invalid");
432         zlibCallbackInfo->OnZipUnZipFinish(ERR_ZLIB_SRC_FILE_DISABLED);
433         return false;
434     }
435     if (FilePath::DirectoryExists(destDir)) {
436         if (!FilePath::PathIsWriteable(destDir)) {
437             APP_LOGI("FilePath::PathIsWriteable(destDir) fail");
438             zlibCallbackInfo->OnZipUnZipFinish(ERR_ZLIB_DEST_FILE_DISABLED);
439             return false;
440         }
441     } else {
442         APP_LOGI("destDir isn't path");
443         zlibCallbackInfo->OnZipUnZipFinish(ERR_ZLIB_DEST_FILE_DISABLED);
444         return false;
445     }
446     auto innerTask = [srcFileDir, destDir, options, zlibCallbackInfo]() {
447         UnzipParam unzipParam {
448             .filterCB = ExcludeNoFilesFilter,
449             .logSkippedFiles = true
450         };
451         ErrCode err = UnzipWithFilterCallback(srcFileDir, destDir, options, unzipParam);
452         if (zlibCallbackInfo != nullptr) {
453             zlibCallbackInfo->OnZipUnZipFinish(err);
454         }
455     };
456     zlibCallbackInfo->DoTask(innerTask);
457     return true;
458 }
459 
ZipWithFilterCallback(const FilePath & srcDir,const FilePath & destFile,const OPTIONS & options,FilterCallback filterCB)460 ErrCode ZipWithFilterCallback(const FilePath &srcDir, const FilePath &destFile,
461     const OPTIONS &options, FilterCallback filterCB)
462 {
463     FilePath destPath = destFile;
464     if (!FilePath::DirectoryExists(destPath.DirName())) {
465         APP_LOGE("The destPath not exist");
466         return ERR_ZLIB_DEST_FILE_DISABLED;
467     }
468     if (!FilePath::PathIsWriteable(destPath.DirName())) {
469         APP_LOGE("The destPath not writeable");
470         return ERR_ZLIB_DEST_FILE_DISABLED;
471     }
472 
473     if (!FilePath::PathIsValid(srcDir)) {
474         APP_LOGI("srcDir isn't Exist");
475         return ERR_ZLIB_SRC_FILE_DISABLED;
476     } else {
477         if (!FilePath::PathIsReadable(srcDir)) {
478             APP_LOGI("srcDir not readable");
479             return ERR_ZLIB_SRC_FILE_DISABLED;
480         }
481     }
482 
483     std::vector<FilePath> srcFile = {srcDir};
484     ZipParams params(srcFile, FilePath(destPath.CheckDestDirTail()));
485     params.SetFilterCallback(filterCB);
486     bool result = Zip(params, options);
487     if (result) {
488         return ERR_OK;
489     } else {
490         return ERR_ZLIB_DEST_FILE_DISABLED;
491     }
492 }
493 
ZipsWithFilterCallback(const std::vector<FilePath> & srcFiles,const FilePath & destFile,const OPTIONS & options,FilterCallback filterCB)494 ErrCode ZipsWithFilterCallback(const std::vector<FilePath> &srcFiles, const FilePath &destFile,
495     const OPTIONS &options, FilterCallback filterCB)
496 {
497     FilePath destPath = destFile;
498     if (!FilePath::DirectoryExists(destPath.DirName())) {
499         APP_LOGE("The destPath not exist");
500         return ERR_ZLIB_DEST_FILE_DISABLED;
501     }
502     if (!FilePath::PathIsWriteable(destPath.DirName())) {
503         APP_LOGE("The destPath not writeable");
504         return ERR_ZLIB_DEST_FILE_DISABLED;
505     }
506 
507     for (auto iter = srcFiles.begin(); iter != srcFiles.end(); ++iter) {
508         if (!FilePath::PathIsValid(*iter)) {
509             APP_LOGI("srcDir isn't Exist");
510             return ERR_ZLIB_SRC_FILE_DISABLED;
511         } else {
512             if (!FilePath::PathIsReadable(*iter)) {
513                 APP_LOGI("srcDir not readable");
514                 return ERR_ZLIB_SRC_FILE_DISABLED;
515             }
516         }
517     }
518 
519     ZipParams params(srcFiles, FilePath(destPath.CheckDestDirTail()));
520     params.SetFilterCallback(filterCB);
521     bool result = Zips(params, options);
522     if (result) {
523         return ERR_OK;
524     } else {
525         return ERR_ZLIB_DEST_FILE_DISABLED;
526     }
527 }
528 
Zip(const std::string & srcPath,const std::string & destPath,const OPTIONS & options,bool includeHiddenFiles,std::shared_ptr<ZlibCallbackInfoBase> zlibCallbackInfo)529 bool Zip(const std::string &srcPath, const std::string &destPath, const OPTIONS &options,
530     bool includeHiddenFiles, std::shared_ptr<ZlibCallbackInfoBase> zlibCallbackInfo)
531 {
532     if (zlibCallbackInfo == nullptr) {
533         return false;
534     }
535     FilePath srcDir(srcPath);
536     FilePath destFile(destPath);
537     APP_LOGD("srcDir=%{private}s, destFile=%{private}s", srcDir.Value().c_str(), destFile.Value().c_str());
538 
539     if ((srcDir.Value().size() == 0) || FilePath::HasRelativePathBaseOnAPIVersion(srcPath)) {
540         zlibCallbackInfo->OnZipUnZipFinish(ERR_ZLIB_SRC_FILE_DISABLED);
541         return false;
542     }
543     if ((destFile.Value().size() == 0) || FilePath::HasRelativePathBaseOnAPIVersion(destPath)) {
544         zlibCallbackInfo->OnZipUnZipFinish(ERR_ZLIB_DEST_FILE_DISABLED);
545         return false;
546     }
547 
548     auto innerTask = [srcDir, destFile, includeHiddenFiles, zlibCallbackInfo, options]() {
549         if (includeHiddenFiles) {
550             ErrCode err = ZipWithFilterCallback(srcDir, destFile, options, ExcludeNoFilesFilter);
551             if (zlibCallbackInfo != nullptr) {
552                 zlibCallbackInfo->OnZipUnZipFinish(err);
553             }
554         } else {
555             ErrCode err = ZipWithFilterCallback(srcDir, destFile, options, ExcludeHiddenFilesFilter);
556             if (zlibCallbackInfo != nullptr) {
557                 zlibCallbackInfo->OnZipUnZipFinish(err);
558             }
559         }
560     };
561 
562     zlibCallbackInfo->DoTask(innerTask);
563     return true;
564 }
565 
ZipFileIsValid(const std::string & srcFile)566 bool ZipFileIsValid(const std::string &srcFile)
567 {
568     if ((srcFile.size() == 0) || FilePath::HasRelativePathBaseOnAPIVersion(srcFile)) {
569         APP_LOGE("srcFile len is 0 or ../");
570         return false;
571     }
572     if (!FilePathCheckValid(srcFile)) {
573         APP_LOGE("FilePathCheckValid return false");
574         return false;
575     }
576     FilePath srcFileDir(srcFile);
577     if (!FilePath::PathIsValid(srcFileDir)) {
578         APP_LOGE("PathIsValid return false");
579         return false;
580     }
581     if (!FilePath::PathIsReadable(srcFileDir)) {
582         APP_LOGE("PathIsReadable return false");
583         return false;
584     }
585     return true;
586 }
587 
GetOriginalSize(PlatformFile zipFd,int64_t & originalSize)588 ErrCode GetOriginalSize(PlatformFile zipFd, int64_t &originalSize)
589 {
590     ZipReader reader;
591     if (!reader.OpenFromPlatformFile(zipFd)) {
592         APP_LOGE("Failed to open, not ZIP format or damaged");
593         return ERR_ZLIB_SRC_FILE_FORMAT_ERROR;
594     }
595     int64_t totalSize = 0;
596     while (reader.HasMore()) {
597         if (!reader.OpenCurrentEntryInZip()) {
598             APP_LOGE("Failed to open the current file in zip");
599             return ERR_ZLIB_SRC_FILE_FORMAT_ERROR;
600         }
601         const FilePath &constEntryPath = reader.CurrentEntryInfo()->GetFilePath();
602         FilePath entryPath = constEntryPath;
603         if (reader.CurrentEntryInfo()->IsUnsafe()) {
604             APP_LOGE("Found an unsafe file in zip");
605             return ERR_ZLIB_SRC_FILE_FORMAT_ERROR;
606         }
607         totalSize += reader.CurrentEntryInfo()->GetOriginalSize();
608         if (!reader.AdvanceToNextEntry()) {
609             APP_LOGE("Failed to advance to the next file");
610             return ERR_ZLIB_SRC_FILE_FORMAT_ERROR;
611         }
612     }
613     originalSize = totalSize;
614     return ERR_OK;
615 }
616 
GetOriginalSize(const std::string & srcFile,int64_t & originalSize)617 ErrCode GetOriginalSize(const std::string &srcFile, int64_t &originalSize)
618 {
619     if (!ZipFileIsValid(srcFile)) {
620         return ERR_ZLIB_SRC_FILE_DISABLED;
621     }
622     PlatformFile zipFd = open(srcFile.c_str(), S_IREAD, O_CREAT);
623     if (zipFd == kInvalidPlatformFile) {
624         APP_LOGE("Failed to open file, errno: %{public}d, %{public}s", errno, strerror(errno));
625         return ERR_ZLIB_SRC_FILE_DISABLED;
626     }
627     ErrCode ret = GetOriginalSize(zipFd, originalSize);
628     close(zipFd);
629     return ret;
630 }
631 
Zips(const std::vector<std::string> & srcFiles,const std::string & destPath,const OPTIONS & options,bool includeHiddenFiles,std::shared_ptr<ZlibCallbackInfoBase> zlibCallbackInfo)632 bool Zips(const std::vector<std::string> &srcFiles, const std::string &destPath, const OPTIONS &options,
633     bool includeHiddenFiles, std::shared_ptr<ZlibCallbackInfoBase> zlibCallbackInfo)
634 {
635     if (zlibCallbackInfo == nullptr) {
636         return false;
637     }
638     if (FilePath::HasRelativePathBaseOnAPIVersion(srcFiles)) {
639         zlibCallbackInfo->OnZipUnZipFinish(ERR_ZLIB_SRC_FILE_DISABLED);
640         return false;
641     }
642     std::vector<FilePath> srcFilesPath;
643     for (auto iter = srcFiles.begin(); iter != srcFiles.end(); ++iter) {
644         FilePath srcFile(*iter);
645         if (srcFile.Value().size() == 0) {
646             zlibCallbackInfo->OnZipUnZipFinish(ERR_ZLIB_SRC_FILE_DISABLED);
647             return false;
648         }
649         srcFilesPath.push_back(srcFile);
650     }
651     FilePath destFile(destPath);
652     if ((destFile.Value().size() == 0) || FilePath::HasRelativePathBaseOnAPIVersion(destPath)) {
653         zlibCallbackInfo->OnZipUnZipFinish(ERR_ZLIB_DEST_FILE_DISABLED);
654         return false;
655     }
656 
657     auto innerTask = [srcFilesPath, destFile, includeHiddenFiles, zlibCallbackInfo, options]() {
658         if (includeHiddenFiles) {
659             ErrCode err = ZipsWithFilterCallback(srcFilesPath, destFile, options, ExcludeNoFilesFilter);
660             if (zlibCallbackInfo != nullptr) {
661                 zlibCallbackInfo->OnZipUnZipFinish(err);
662             }
663         } else {
664             ErrCode err = ZipsWithFilterCallback(srcFilesPath, destFile, options, ExcludeHiddenFilesFilter);
665             if (zlibCallbackInfo != nullptr) {
666                 zlibCallbackInfo->OnZipUnZipFinish(err);
667             }
668         }
669     };
670 
671     zlibCallbackInfo->DoTask(innerTask);
672     return true;
673 }
674 }  // namespace LIBZIP
675 }  // namespace AppExecFwk
676 }  // namespace OHOS
677