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 ¶ms, const OPTIONS &options)
131 {
132 const std::vector<FilePath> *filesToAdd = ¶ms.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