1 /*
2 * Copyright (C) 2021 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 "util/zip/zip_writer.h"
16 #include <chrono>
17 #include "directory_ex.h"
18 #include "dump_utils.h"
19 #include "hilog_wrapper.h"
20 namespace OHOS {
21 namespace HiviewDFX {
22 namespace {
23 static const int PROCENT100 = 100;
24 static const int ZIP_BUF_SIZE = 8192;
25 static const int BASE_YEAR = 1900;
26 static const uLong LANGUAGE_ENCODING_FLAG = 0x1 << 11;
27 } // namespace
28
ZipWriter(const std::string & zipFilePath)29 ZipWriter::ZipWriter(const std::string &zipFilePath) : zipFilePath_(zipFilePath), zipFile_(nullptr)
30 {
31 DUMPER_HILOGD(MODULE_COMMON, "create|zipFilePath=[%{public}s]", zipFilePath_.c_str());
32 }
33
~ZipWriter()34 ZipWriter::~ZipWriter()
35 {
36 DUMPER_HILOGD(MODULE_COMMON, "release|");
37 zipItems_.clear();
38 Close();
39 }
40
Open()41 bool ZipWriter::Open()
42 {
43 DUMPER_HILOGD(MODULE_COMMON, "Open enter|zipFilePath=[%{public}s]", zipFilePath_.c_str());
44
45 if (zipFilePath_.empty()) {
46 DUMPER_HILOGE(MODULE_COMMON, "Open leave|false, path is empty");
47 return false;
48 }
49
50 DUMPER_HILOGD(MODULE_COMMON, "Open debug|");
51 zipFile_ = OpenForZipping(zipFilePath_, APPEND_STATUS_CREATE);
52 if (zipFile_ == nullptr) {
53 DUMPER_HILOGE(MODULE_COMMON, "Open leave|false, couldn't create ZIP file");
54 return false;
55 }
56
57 DUMPER_HILOGD(MODULE_COMMON, "Open leave|true, create ZIP file");
58 return true;
59 }
60
Close()61 bool ZipWriter::Close()
62 {
63 DUMPER_HILOGD(MODULE_COMMON, "Close enter|");
64
65 int res = ZIP_OK;
66
67 if (zipFile_ != nullptr) {
68 res = zipClose(zipFile_, nullptr);
69 }
70 zipFile_ = nullptr;
71
72 bool ret = (res == ZIP_OK);
73
74 DUMPER_HILOGD(MODULE_COMMON, "Close leave|ret=%{public}d, res=%{public}d", ret, res);
75 return ret;
76 }
77
Write(const std::vector<std::pair<std::string,std::string>> & zipItems,const ZipTickNotify notify)78 bool ZipWriter::Write(const std::vector<std::pair<std::string, std::string>> &zipItems, const ZipTickNotify notify)
79 {
80 DUMPER_HILOGD(MODULE_COMMON, "Write enter|");
81
82 if (zipFile_ == nullptr) {
83 DUMPER_HILOGE(MODULE_COMMON, "Write failed, zipFile_ is nullptr");
84 return false;
85 }
86
87 zipItems_.insert(zipItems_.end(), zipItems.begin(), zipItems.end());
88
89 bool ret = FlushItems(notify);
90 DUMPER_HILOGD(MODULE_COMMON, "Write debug|FlushItems, ret=%{public}d", ret);
91
92 if (ret) {
93 ret = Close();
94 }
95
96 DUMPER_HILOGD(MODULE_COMMON, "Write leave|ret=%{public}d", ret);
97 return ret;
98 }
99
FlushItems(const ZipTickNotify notify)100 bool ZipWriter::FlushItems(const ZipTickNotify notify)
101 {
102 DUMPER_HILOGD(MODULE_COMMON, "FlushItems enter|");
103
104 std::vector<std::pair<std::string, std::string>> zipItems;
105 zipItems.assign(zipItems_.begin(), zipItems_.end());
106 zipItems_.clear();
107
108 bool ret = true;
109 for (size_t i = 0; i < zipItems.size(); i++) {
110 if ((notify != nullptr) && (notify(((PROCENT100 * i) / zipItems.size()), UNSET_PROGRESS))) {
111 DUMPER_HILOGE(MODULE_COMMON, "FlushItems error|notify");
112 ret = false;
113 break;
114 }
115
116 auto item = zipItems[i];
117 std::string absolutePath = item.first; // first:absolutePath
118 std::string relativePath = item.second; // second:relativePath
119 DUMPER_HILOGD(MODULE_COMMON, "FlushItems debug|relativePath=[%{public}s], absolutePath=[%{public}s]",
120 relativePath.c_str(), absolutePath.c_str());
121
122 if (!AddFileEntryToZip(zipFile_, relativePath, absolutePath)) {
123 DUMPER_HILOGE(MODULE_COMMON, "FlushItems error|false, failed to write file");
124 ret = false;
125 break;
126 }
127 }
128
129 DUMPER_HILOGD(MODULE_COMMON, "FlushItems leave|ret=%{public}d", ret);
130 return ret;
131 }
132
SetTimeToZipFileInfo(zip_fileinfo & zipInfo)133 bool ZipWriter::SetTimeToZipFileInfo(zip_fileinfo &zipInfo)
134 {
135 auto nowTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
136 struct tm localTime = {0};
137 if (localtime_r(&nowTime, &localTime) == nullptr) {
138 DUMPER_HILOGE(MODULE_COMMON, "SetTimeToZipFileInfo error|nullptr");
139 return false;
140 }
141
142 zipInfo.tmz_date.tm_year = static_cast<uInt>(localTime.tm_year + BASE_YEAR);
143 zipInfo.tmz_date.tm_mon = static_cast<uInt>(localTime.tm_mon);
144 zipInfo.tmz_date.tm_mday = static_cast<uInt>(localTime.tm_mday);
145 zipInfo.tmz_date.tm_hour = static_cast<uInt>(localTime.tm_hour);
146 zipInfo.tmz_date.tm_min = static_cast<uInt>(localTime.tm_min);
147 zipInfo.tmz_date.tm_sec = static_cast<uInt>(localTime.tm_sec);
148 return true;
149 }
150
OpenForZipping(const std::string & fileName,int append)151 zipFile ZipWriter::OpenForZipping(const std::string &fileName, int append)
152 {
153 return zipOpen2(fileName.c_str(), append, nullptr, nullptr);
154 }
155
ZipOpenNewFileInZip(zipFile zip_file,const std::string & strPath)156 bool ZipWriter::ZipOpenNewFileInZip(zipFile zip_file, const std::string &strPath)
157 {
158 DUMPER_HILOGD(MODULE_COMMON, "ZipOpenNewFileInZip enter|strPath=[%{public}s]", strPath.c_str());
159
160 zip_fileinfo fileInfo = {};
161 SetTimeToZipFileInfo(fileInfo);
162
163 int res = zipOpenNewFileInZip4(zip_file, strPath.c_str(), &fileInfo,
164 nullptr, 0u, nullptr, 0u, nullptr, Z_DEFLATED, Z_DEFAULT_COMPRESSION,
165 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, nullptr, 0, 0, LANGUAGE_ENCODING_FLAG);
166
167 bool ret = (res == ZIP_OK);
168
169 DUMPER_HILOGD(MODULE_COMMON, "ZipOpenNewFileInZip leave|ret=%{public}d, res=%{public}d", ret, res);
170 return ret;
171 }
172
AddFileContentToZip(zipFile zip_file,std::string & file_path)173 bool ZipWriter::AddFileContentToZip(zipFile zip_file, std::string &file_path)
174 {
175 DUMPER_HILOGD(MODULE_COMMON, "AddFileContentToZip enter|file_path=[%{public}s]", file_path.c_str());
176
177 if (!DumpUtils::PathIsValid(file_path)) {
178 DUMPER_HILOGE(MODULE_COMMON, "AddFileContentToZip leave|false, PathIsValid");
179 return false;
180 }
181
182 auto fp = fopen(file_path.c_str(), "rb");
183 if (fp == nullptr) {
184 DUMPER_HILOGE(MODULE_COMMON, "AddFileContentToZip leave|false, fopen");
185 return false;
186 }
187
188 bool ret = true;
189 char buf[ZIP_BUF_SIZE];
190 while (!feof(fp)) {
191 size_t readSum = fread(buf, 1, ZIP_BUF_SIZE, fp);
192 if (readSum < 1) {
193 continue;
194 }
195
196 if (zipWriteInFileInZip(zip_file, buf, readSum) != ZIP_OK) {
197 DUMPER_HILOGE(MODULE_COMMON, "AddFileContentToZip error|could not write data to zip");
198 ret = false;
199 break;
200 }
201 }
202
203 (void)fclose(fp);
204 fp = nullptr;
205
206 DUMPER_HILOGD(MODULE_COMMON, "AddFileContentToZip leave|ret=%{public}d", ret);
207 return ret;
208 }
209
OpenNewFileEntry(zipFile zip_file,std::string & path)210 bool ZipWriter::OpenNewFileEntry(zipFile zip_file, std::string &path)
211 {
212 DUMPER_HILOGD(MODULE_COMMON, "OpenNewFileEntry enter|path=[%{public}s]", path.c_str());
213
214 bool ret = ZipOpenNewFileInZip(zip_file, path);
215
216 DUMPER_HILOGD(MODULE_COMMON, "OpenNewFileEntry leave|ret=%{public}d", ret);
217 return ret;
218 }
219
CloseNewFileEntry(zipFile zip_file)220 bool ZipWriter::CloseNewFileEntry(zipFile zip_file)
221 {
222 DUMPER_HILOGD(MODULE_COMMON, "CloseNewFileEntry enter|");
223
224 int res = zipCloseFileInZip(zip_file);
225 bool ret = (res == ZIP_OK);
226
227 DUMPER_HILOGD(MODULE_COMMON, "CloseNewFileEntry leave|ret=%{public}d, res=%{public}d", ret, res);
228 return ret;
229 }
230
AddFileEntryToZip(zipFile zip_file,std::string & relativePath,std::string & absolutePath)231 bool ZipWriter::AddFileEntryToZip(zipFile zip_file, std::string &relativePath, std::string &absolutePath)
232 {
233 DUMPER_HILOGD(MODULE_COMMON, "AddFileEntryToZip enter|relativePath=[%{public}s], absolutePath=[%{public}s]",
234 relativePath.c_str(), absolutePath.c_str());
235
236 if (!OpenNewFileEntry(zip_file, relativePath)) {
237 DUMPER_HILOGE(MODULE_COMMON, "AddFileEntryToZip leave|false, open");
238 return false;
239 }
240
241 bool ret = AddFileContentToZip(zip_file, absolutePath);
242
243 if (!CloseNewFileEntry(zip_file)) {
244 DUMPER_HILOGE(MODULE_COMMON, "AddFileEntryToZip leave|false, close");
245 return false;
246 }
247
248 DUMPER_HILOGD(MODULE_COMMON, "AddFileEntryToZip leave|ret=%{public}d", ret);
249 return ret;
250 }
251 } // namespace HiviewDFX
252 } // namespace OHOS
253