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