• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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