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 ¶ms, const OPTIONS &options)
133 {
134 const std::vector<std::pair<FilePath, FilePath>> *filesToAdd = ¶ms.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 ¶ms, 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 ¶ms, 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 ¶ms, const OPTIONS &options)
222 {
223 const std::vector<std::pair<FilePath, FilePath>> *filesToAdd = ¶ms.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