1
2 /*
3 * Copyright (c) 2022 Huawei Device Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "zip_writer.h"
17
18 #include <stdio.h>
19
20 #include "app_log_wrapper.h"
21 #include "contrib/minizip/zip.h"
22 #include "directory_ex.h"
23 #include "zip_internal.h"
24
25 using namespace OHOS::AppExecFwk;
26
27 namespace OHOS {
28 namespace AppExecFwk {
29 namespace LIBZIP {
30 namespace {
31 // Numbers of pending entries that trigger writting them to the ZIP file.
32 constexpr size_t g_MaxPendingEntriesCount = 50;
33 const std::string SEPARATOR = "/";
34 std::mutex g_mutex;;
35
AddFileContentToZip(zipFile zip_file,FilePath & file_path)36 bool AddFileContentToZip(zipFile zip_file, FilePath &file_path)
37 {
38 APP_LOGI("%{public}s called", __func__);
39 char buf[kZipBufSize];
40 if (!FilePathCheckValid(file_path.Value())) {
41 APP_LOGI(
42 "%{public}s called, filePath is invalid!!! file_path=%{public}s", __func__, file_path.Value().c_str());
43 return false;
44 }
45 if (!FilePath::PathIsValid(file_path)) {
46 APP_LOGI("!!! %{public}s called PathIsValid returns false !!!", __func__);
47 return false;
48 }
49
50 FILE *fp = fopen(file_path.Value().c_str(), "rb");
51 if (fp == nullptr) {
52 APP_LOGI("%{public}s called, filePath to realPath failed! filePath:%{private}s ",
53 __func__,
54 file_path.Value().c_str());
55 return false;
56 }
57
58 uint32_t num_bytes;
59 while (!feof(fp)) {
60 num_bytes = fread(buf, 1, kZipBufSize, fp);
61 if (num_bytes > 0) {
62 if (zipWriteInFileInZip(zip_file, buf, num_bytes) != ZIP_OK) {
63 APP_LOGI("%{public}s called, Could not write data to zip for path:%{private}s ",
64 __func__, file_path.Value().c_str());
65 fclose(fp);
66 fp = nullptr;
67 return false;
68 }
69 } else {
70 break;
71 }
72 }
73 fclose(fp);
74 fp = nullptr;
75 return true;
76 }
77
OpenNewFileEntry(zipFile zip_file,FilePath & path,bool isDirectory,struct tm * lastModified,const OPTIONS & options)78 bool OpenNewFileEntry(
79 zipFile zip_file, FilePath &path, bool isDirectory, struct tm *lastModified, const OPTIONS &options)
80 {
81 APP_LOGI("%{public}s called", __func__);
82 std::string strPath = path.Value();
83
84 if (isDirectory) {
85 strPath += SEPARATOR;
86 }
87
88 return ZipOpenNewFileInZip(zip_file, strPath, options, lastModified);
89 }
90
CloseNewFileEntry(zipFile zip_file)91 bool CloseNewFileEntry(zipFile zip_file)
92 {
93 APP_LOGI("%{public}s called", __func__);
94 return zipCloseFileInZip(zip_file) == ZIP_OK;
95 }
96
AddFileEntryToZip(zipFile zip_file,FilePath & relativePath,FilePath & absolutePath,const OPTIONS & options)97 bool AddFileEntryToZip(zipFile zip_file, FilePath &relativePath, FilePath &absolutePath, const OPTIONS &options)
98 {
99 APP_LOGI("%{public}s called", __func__);
100
101 struct tm *lastModified = GetCurrentSystemTime();
102 if (lastModified == nullptr) {
103 return false;
104 }
105 if (!OpenNewFileEntry(zip_file, relativePath, false, lastModified, options)) {
106 return false;
107 }
108 bool success = AddFileContentToZip(zip_file, absolutePath);
109 if (!CloseNewFileEntry(zip_file)) {
110 APP_LOGI("!!! CloseNewFileEntry returnValule is false !!!");
111 return false;
112 }
113 return success;
114 }
115
AddDirectoryEntryToZip(zipFile zip_file,FilePath & path,struct tm * lastModified,const OPTIONS & options)116 bool AddDirectoryEntryToZip(zipFile zip_file, FilePath &path, struct tm *lastModified, const OPTIONS &options)
117 {
118 APP_LOGI("%{public}s called", __func__);
119 return OpenNewFileEntry(zip_file, path, true, lastModified, options) && CloseNewFileEntry(zip_file);
120 }
121
122 } // namespace
123
InitZipFileWithFd(PlatformFile zipFilefd)124 zipFile ZipWriter::InitZipFileWithFd(PlatformFile zipFilefd)
125 {
126 std::lock_guard<std::mutex> lock(g_mutex);
127 if (zipFilefd == kInvalidPlatformFile) {
128 return nullptr;
129 }
130
131 zipFile zip_file = OpenFdForZipping(zipFilefd, APPEND_STATUS_CREATE);
132 if (!zip_file) {
133 APP_LOGI("%{public}s called, Couldn't create ZIP file for FD", __func__);
134 return nullptr;
135 }
136 return zip_file;
137 }
138
InitZipFileWithFile(const FilePath & zip_file_path)139 zipFile ZipWriter::InitZipFileWithFile(const FilePath &zip_file_path)
140 {
141 std::lock_guard<std::mutex> lock(g_mutex);
142 FilePath zipFilePath = zip_file_path;
143 APP_LOGI("%{public}s called", __func__);
144 if (zipFilePath.Value().empty()) {
145 APP_LOGI("%{public}s called, Path is empty", __func__);
146 return nullptr;
147 }
148
149 zipFile zip_file = OpenForZipping(zipFilePath.Value(), APPEND_STATUS_CREATE);
150 if (!zip_file) {
151 APP_LOGI("%{public}s called, Couldn't create ZIP file at path", __func__);
152 return nullptr;
153 }
154 return zip_file;
155 }
156
ZipWriter(zipFile zip_file,const FilePath & rootDir)157 ZipWriter::ZipWriter(zipFile zip_file, const FilePath &rootDir) : zipFile_(zip_file), rootDir_(rootDir)
158 {}
159
~ZipWriter()160 ZipWriter::~ZipWriter()
161 {
162 pendingEntries_.clear();
163 }
164
WriteEntries(const std::vector<FilePath> & paths,const OPTIONS & options)165 bool ZipWriter::WriteEntries(const std::vector<FilePath> &paths, const OPTIONS &options)
166 {
167 APP_LOGI("%{public}s called", __func__);
168 return AddEntries(paths, options) && Close(options);
169 }
170
AddEntries(const std::vector<FilePath> & paths,const OPTIONS & options)171 bool ZipWriter::AddEntries(const std::vector<FilePath> &paths, const OPTIONS &options)
172 {
173 if (!zipFile_) {
174 return false;
175 }
176 pendingEntries_.insert(pendingEntries_.end(), paths.begin(), paths.end());
177 return FlushEntriesIfNeeded(false, options);
178 }
179
Close(const OPTIONS & options)180 bool ZipWriter::Close(const OPTIONS &options)
181 {
182 bool success = FlushEntriesIfNeeded(true, options) && zipClose(zipFile_, nullptr) == ZIP_OK;
183 zipFile_ = nullptr;
184 return success;
185 }
186
FlushEntriesIfNeeded(bool force,const OPTIONS & options)187 bool ZipWriter::FlushEntriesIfNeeded(bool force, const OPTIONS &options)
188 {
189 if (pendingEntries_.size() < g_MaxPendingEntriesCount && !force) {
190 return true;
191 }
192 while (pendingEntries_.size() >= g_MaxPendingEntriesCount || (force && !pendingEntries_.empty())) {
193
194 size_t entry_count = std::min(pendingEntries_.size(), g_MaxPendingEntriesCount);
195 std::vector<FilePath> relativePaths;
196 std::vector<FilePath> absolutePaths;
197
198 relativePaths.insert(relativePaths.begin(), pendingEntries_.begin(), pendingEntries_.begin() + entry_count);
199 for (auto iter = pendingEntries_.begin(); iter != pendingEntries_.begin() + entry_count; ++iter) {
200 // The FileAccessor requires absolute paths.
201 if (FilePath::IsDir(rootDir_)) {
202 absolutePaths.push_back(FilePath(rootDir_.Value() + iter->Value()));
203 } else {
204 absolutePaths.push_back(FilePath(rootDir_.Value()));
205 }
206 }
207 pendingEntries_.erase(pendingEntries_.begin(), pendingEntries_.begin() + entry_count);
208 for (size_t i = 0; i < absolutePaths.size(); i++) {
209 FilePath &relativePath = relativePaths[i];
210 FilePath &absolutePath = absolutePaths[i];
211 bool isValid = FilePath::PathIsValid(absolutePath);
212 bool isDir = FilePath::IsDir(absolutePath);
213 if (isValid && !isDir) {
214 if (!AddFileEntryToZip(zipFile_, relativePath, absolutePath, options)) {
215 APP_LOGI("%{public}s called, Failed to write file", __func__);
216 return false;
217 }
218 } else {
219 // Missing file or directory case.
220 struct tm *last_modified = GetCurrentSystemTime();
221 if (!AddDirectoryEntryToZip(zipFile_, relativePath, last_modified, options)) {
222 APP_LOGI("%{public}s called, Failed to write directory", __func__);
223 return false;
224 }
225 }
226 }
227 }
228 return true;
229 }
230
231 } // namespace LIBZIP
232 } // namespace AppExecFwk
233 } // namespace OHOS
234