• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright (c) 2021 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 #include <stdio.h>
18 #include "zip_internal.h"
19 #include "hilog_wrapper.h"
20 #include "directory_ex.h"
21 #include "contrib/minizip/zip.h"
22 
23 namespace OHOS {
24 namespace AAFwk {
25 namespace LIBZIP {
26 namespace {
27 // Numbers of pending entries that trigger writting them to the ZIP file.
28 constexpr size_t kMaxPendingEntriesCount = 50;
29 const std::string SEPARATOR = "/";
30 
31 #define CALLING_CALL_BACK(callback, result) \
32     if (callback != nullptr) {              \
33         callback(result);                   \
34     }
35 
AddFileContentToZip(zipFile zip_file,FilePath & file_path)36 bool AddFileContentToZip(zipFile zip_file, FilePath &file_path)
37 {
38     HILOG_INFO("%{public}s called", __func__);
39     int num_bytes;
40     char buf[kZipBufSize];
41     if (!FilePathCheckValid(file_path.Value())) {
42         HILOG_INFO(
43             "%{public}s called, filePath is invalid!!! file_path=%{public}s", __func__, file_path.Value().c_str());
44         return false;
45     }
46 
47     if (!FilePath::PathIsValid(file_path)) {
48         return false;
49     }
50 
51     FILE *fp = fopen(file_path.Value().c_str(), "rb");
52     if (fp == nullptr) {
53         HILOG_INFO("%{public}s called, filePath to realPath failed! filePath:%{private}s ",
54             __func__,
55             file_path.Value().c_str());
56         return false;
57     }
58 
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                 HILOG_INFO("%{public}s called, Could not write data to zip for path:%{public}s ",
64                     __func__,
65                     file_path.Value().c_str());
66                 fclose(fp);
67                 fp = nullptr;
68                 return false;
69             }
70         }
71     }
72     fclose(fp);
73     fp = nullptr;
74     return true;
75 }
76 
OpenNewFileEntry(zipFile zip_file,FilePath & path,bool is_directory,struct tm * last_modified,const OPTIONS & options)77 bool OpenNewFileEntry(
78     zipFile zip_file, FilePath &path, bool is_directory, struct tm *last_modified, const OPTIONS &options)
79 {
80     HILOG_INFO("%{public}s called", __func__);
81     std::string strPath = path.Value();
82     return ZipOpenNewFileInZip(zip_file, strPath, options, last_modified);
83 }
84 
CloseNewFileEntry(zipFile zip_file)85 bool CloseNewFileEntry(zipFile zip_file)
86 {
87     HILOG_INFO("%{public}s called", __func__);
88     return zipCloseFileInZip(zip_file) == ZIP_OK;
89 }
90 
AddFileEntryToZip(zipFile zip_file,FilePath & relativePath,FilePath & absolutePath,const OPTIONS & options)91 bool AddFileEntryToZip(zipFile zip_file, FilePath &relativePath, FilePath &absolutePath, const OPTIONS &options)
92 {
93     HILOG_INFO("%{public}s called", __func__);
94 
95     struct tm *lastModified = GetCurrentSystemTime();
96     if (lastModified == nullptr) {
97         return false;
98     }
99     if (!OpenNewFileEntry(zip_file, relativePath, false, lastModified, options)) {
100         return false;
101     }
102     bool success = AddFileContentToZip(zip_file, absolutePath);
103     if (!CloseNewFileEntry(zip_file)) {
104         return false;
105     }
106 
107     return success;
108 }
109 
AddDirectoryEntryToZip(zipFile zip_file,FilePath & path,struct tm * lastModified,const OPTIONS & options)110 bool AddDirectoryEntryToZip(zipFile zip_file, FilePath &path, struct tm *lastModified, const OPTIONS &options)
111 {
112     HILOG_INFO("%{public}s called", __func__);
113     return OpenNewFileEntry(zip_file, path, true, lastModified, options) && CloseNewFileEntry(zip_file);
114 }
115 
116 }  // namespace
117 
CreateWithFd(PlatformFile zipFilefd,const FilePath & rootDir)118 std::unique_ptr<ZipWriter> ZipWriter::CreateWithFd(PlatformFile zipFilefd, const FilePath &rootDir)
119 {
120     HILOG_INFO("%{public}s called", __func__);
121     if (zipFilefd == kInvalidPlatformFile) {
122         return nullptr;
123     }
124 
125     zipFile zip_file = OpenFdForZipping(zipFilefd, APPEND_STATUS_CREATE);
126     if (!zip_file) {
127         HILOG_INFO("%{public}s called, Couldn't create ZIP file for FD", __func__);
128         return nullptr;
129     }
130     return std::unique_ptr<ZipWriter>(new ZipWriter(zip_file, rootDir));
131 }
132 
133 // static
Create(const FilePath & zip_file_path,const FilePath & rootDir)134 std::unique_ptr<ZipWriter> ZipWriter::Create(const FilePath &zip_file_path, const FilePath &rootDir)
135 {
136     FilePath zipFilePath = zip_file_path;
137     HILOG_INFO("%{public}s called", __func__);
138     if (zipFilePath.Value().empty()) {
139         HILOG_INFO("%{public}s called, Path is empty", __func__);
140         return nullptr;
141     }
142 
143     zipFile zip_file = OpenForZipping(zipFilePath.Value(), APPEND_STATUS_CREATE);
144     if (!zip_file) {
145         HILOG_INFO("%{public}s called, Couldn't create ZIP file at path", __func__);
146         return nullptr;
147     }
148     return std::unique_ptr<ZipWriter>(new (std::nothrow) ZipWriter(zip_file, rootDir));
149 }
150 
ZipWriter(zipFile zip_file,const FilePath & rootDir)151 ZipWriter::ZipWriter(zipFile zip_file, const FilePath &rootDir) : zipFile_(zip_file), rootDir_(rootDir)
152 {}
153 
~ZipWriter()154 ZipWriter::~ZipWriter()
155 {
156     pendingEntries_.clear();
157 }
158 
WriteEntries(const std::vector<FilePath> & paths,const OPTIONS & options,CALLBACK callback)159 bool ZipWriter::WriteEntries(const std::vector<FilePath> &paths, const OPTIONS &options, CALLBACK callback)
160 {
161     HILOG_INFO("%{public}s called", __func__);
162     return AddEntries(paths, options, callback) && Close(options, callback);
163 }
164 
AddEntries(const std::vector<FilePath> & paths,const OPTIONS & options,CALLBACK callback)165 bool ZipWriter::AddEntries(const std::vector<FilePath> &paths, const OPTIONS &options, CALLBACK callback)
166 {
167     if (!zipFile_) {
168         return false;
169     }
170     pendingEntries_.insert(pendingEntries_.end(), paths.begin(), paths.end());
171     return FlushEntriesIfNeeded(false, options, callback);
172 }
173 
Close(const OPTIONS & options,CALLBACK callback)174 bool ZipWriter::Close(const OPTIONS &options, CALLBACK callback)
175 {
176     bool success = FlushEntriesIfNeeded(true, options, callback) && zipClose(zipFile_, nullptr) == ZIP_OK;
177     zipFile_ = nullptr;
178     return success;
179 }
180 
FlushEntriesIfNeeded(bool force,const OPTIONS & options,CALLBACK callback)181 bool ZipWriter::FlushEntriesIfNeeded(bool force, const OPTIONS &options, CALLBACK callback)
182 {
183     if (pendingEntries_.size() < kMaxPendingEntriesCount && !force) {
184         return true;
185     }
186 
187     std::string rootDir = rootDir_.Value();
188     if (EndsWith(rootDir_.Value(), SEPARATOR)) {
189         rootDir = rootDir.substr(0, rootDir.size() - 1);
190     }
191     while (pendingEntries_.size() >= kMaxPendingEntriesCount || (force && !pendingEntries_.empty())) {
192 
193         size_t entry_count = std::min(pendingEntries_.size(), kMaxPendingEntriesCount);
194         std::vector<FilePath> relativePaths;
195         std::vector<FilePath> absolutePaths;
196 
197         relativePaths.insert(relativePaths.begin(), pendingEntries_.begin(), pendingEntries_.begin() + entry_count);
198         for (auto iter = pendingEntries_.begin(); iter != pendingEntries_.begin() + entry_count; ++iter) {
199             // The FileAccessor requires absolute paths.
200             absolutePaths.push_back(FilePath(rootDir_.Value() + iter->Value()));
201         }
202         pendingEntries_.erase(pendingEntries_.begin(), pendingEntries_.begin() + entry_count);
203 
204         // We don't know which paths are files and which ones are directories, and
205         // we want to avoid making a call to file_accessor_ for each entry. Open the
206         // files instead, invalid files are returned for directories.
207 
208         for (size_t i = 0; i < absolutePaths.size(); i++) {
209             FilePath &relativePath = relativePaths[i];
210             FilePath &absolutePath = absolutePaths[i];
211             if (FilePath::PathIsValid(absolutePath)) {
212                 if (!AddFileEntryToZip(zipFile_, relativePath, absolutePath, options)) {
213                     CALLING_CALL_BACK(callback, ERROR_CODE_ERRNO)
214                     HILOG_INFO("%{public}s called, Failed to write file", __func__);
215                     return false;
216                 }
217             } else {
218                 // Missing file or directory case.
219                 struct tm *last_modified = GetCurrentSystemTime();
220                 if (!AddDirectoryEntryToZip(zipFile_, relativePath, last_modified, options)) {
221                     CALLING_CALL_BACK(callback, ERROR_CODE_ERRNO)
222                     HILOG_INFO("%{public}s called, Failed to write directory", __func__);
223                     return false;
224                 }
225             }
226         }
227     }
228     CALLING_CALL_BACK(callback, ERROR_CODE_OK)
229     return true;
230 }
231 
232 }  // namespace LIBZIP
233 }  // namespace AAFwk
234 }  // namespace OHOS
235