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 kZipBufSize = 8192;
25 static const int kBaseYear = 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_HILOGD(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_HILOGD(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 return false;
84 }
85
86 zipItems_.insert(zipItems_.end(), zipItems.begin(), zipItems.end());
87
88 bool ret = FlushItems(notify);
89 DUMPER_HILOGD(MODULE_COMMON, "Write debug|FlushItems, ret=%{public}d", ret);
90
91 if (ret) {
92 ret = Close();
93 }
94
95 DUMPER_HILOGD(MODULE_COMMON, "Write leave|ret=%{public}d", ret);
96 return ret;
97 }
98
FlushItems(const ZipTickNotify notify)99 bool ZipWriter::FlushItems(const ZipTickNotify notify)
100 {
101 DUMPER_HILOGD(MODULE_COMMON, "FlushItems enter|");
102
103 std::vector<std::pair<std::string, std::string>> zipItems;
104 zipItems.assign(zipItems_.begin(), zipItems_.end());
105 zipItems_.clear();
106
107 bool ret = true;
108 for (size_t i = 0; i < zipItems.size(); i++) {
109 if ((notify != nullptr) && (notify(((PROCENT100 * i) / zipItems.size()), UNSET_PROGRESS))) {
110 DUMPER_HILOGE(MODULE_COMMON, "FlushItems error|notify");
111 ret = false;
112 break;
113 }
114
115 auto item = zipItems[i];
116 std::string absolutePath = item.first; // first:absolutePath
117 std::string relativePath = item.second; // second:relativePath
118 DUMPER_HILOGD(MODULE_COMMON, "FlushItems debug|relativePath=[%{public}s], absolutePath=[%{public}s]",
119 relativePath.c_str(), absolutePath.c_str());
120
121 if (!AddFileEntryToZip(zipFile_, relativePath, absolutePath)) {
122 DUMPER_HILOGE(MODULE_COMMON, "FlushItems error|false, failed to write file");
123 ret = false;
124 break;
125 }
126 }
127
128 DUMPER_HILOGD(MODULE_COMMON, "FlushItems leave|ret=%{public}d", ret);
129 return ret;
130 }
131
SetTimeToZipFileInfo(zip_fileinfo & zipInfo)132 bool ZipWriter::SetTimeToZipFileInfo(zip_fileinfo &zipInfo)
133 {
134 auto nowTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
135 struct tm localTime = {0};
136 if (localtime_r(&nowTime, &localTime) == nullptr) {
137 DUMPER_HILOGE(MODULE_COMMON, "SetTimeToZipFileInfo error|nullptr");
138 return false;
139 }
140
141 zipInfo.tmz_date.tm_year = static_cast<uInt>(localTime.tm_year + kBaseYear);
142 zipInfo.tmz_date.tm_mon = static_cast<uInt>(localTime.tm_mon);
143 zipInfo.tmz_date.tm_mday = static_cast<uInt>(localTime.tm_mday);
144 zipInfo.tmz_date.tm_hour = static_cast<uInt>(localTime.tm_hour);
145 zipInfo.tmz_date.tm_min = static_cast<uInt>(localTime.tm_min);
146 zipInfo.tmz_date.tm_sec = static_cast<uInt>(localTime.tm_sec);
147 return true;
148 }
149
OpenForZipping(const std::string & fileName,int append)150 zipFile ZipWriter::OpenForZipping(const std::string &fileName, int append)
151 {
152 return zipOpen2(fileName.c_str(), append, nullptr, nullptr);
153 }
154
ZipOpenNewFileInZip(zipFile zip_file,const std::string & strPath)155 bool ZipWriter::ZipOpenNewFileInZip(zipFile zip_file, const std::string &strPath)
156 {
157 DUMPER_HILOGD(MODULE_COMMON, "ZipOpenNewFileInZip enter|strPath=[%{public}s]", strPath.c_str());
158
159 zip_fileinfo fileInfo = {};
160 SetTimeToZipFileInfo(fileInfo);
161
162 int res = zipOpenNewFileInZip4(zip_file, strPath.c_str(), &fileInfo,
163 nullptr, 0u, nullptr, 0u, nullptr, Z_DEFLATED, Z_DEFAULT_COMPRESSION,
164 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, nullptr, 0, 0, LANGUAGE_ENCODING_FLAG);
165
166 bool ret = (res == ZIP_OK);
167
168 DUMPER_HILOGD(MODULE_COMMON, "ZipOpenNewFileInZip leave|ret=%{public}d, res=%{public}d", ret, res);
169 return ret;
170 }
171
AddFileContentToZip(zipFile zip_file,std::string & file_path)172 bool ZipWriter::AddFileContentToZip(zipFile zip_file, std::string &file_path)
173 {
174 DUMPER_HILOGD(MODULE_COMMON, "AddFileContentToZip enter|file_path=[%{public}s]", file_path.c_str());
175
176 if (!DumpUtils::PathIsValid(file_path)) {
177 DUMPER_HILOGE(MODULE_COMMON, "AddFileContentToZip leave|false, PathIsValid");
178 return false;
179 }
180
181 auto fp = fopen(file_path.c_str(), "rb");
182 if (fp == nullptr) {
183 DUMPER_HILOGE(MODULE_COMMON, "AddFileContentToZip leave|false, fopen");
184 return false;
185 }
186
187 bool ret = true;
188 char buf[kZipBufSize];
189 while (!feof(fp)) {
190 size_t readSum = fread(buf, 1, kZipBufSize, fp);
191 if (readSum < 1) {
192 continue;
193 }
194
195 if (zipWriteInFileInZip(zip_file, buf, readSum) != ZIP_OK) {
196 DUMPER_HILOGE(MODULE_COMMON, "AddFileContentToZip error|could not write data to zip");
197 ret = false;
198 break;
199 }
200 }
201
202 (void)fclose(fp);
203 fp = nullptr;
204
205 DUMPER_HILOGD(MODULE_COMMON, "AddFileContentToZip leave|ret=%{public}d", ret);
206 return ret;
207 }
208
OpenNewFileEntry(zipFile zip_file,std::string & path)209 bool ZipWriter::OpenNewFileEntry(zipFile zip_file, std::string &path)
210 {
211 DUMPER_HILOGD(MODULE_COMMON, "OpenNewFileEntry enter|path=[%{public}s]", path.c_str());
212
213 bool ret = ZipOpenNewFileInZip(zip_file, path);
214
215 DUMPER_HILOGD(MODULE_COMMON, "OpenNewFileEntry leave|ret=%{public}d", ret);
216 return ret;
217 }
218
CloseNewFileEntry(zipFile zip_file)219 bool ZipWriter::CloseNewFileEntry(zipFile zip_file)
220 {
221 DUMPER_HILOGD(MODULE_COMMON, "CloseNewFileEntry enter|");
222
223 int res = zipCloseFileInZip(zip_file);
224 bool ret = (res == ZIP_OK);
225
226 DUMPER_HILOGD(MODULE_COMMON, "CloseNewFileEntry leave|ret=%{public}d, res=%{public}d", ret, res);
227 return ret;
228 }
229
AddFileEntryToZip(zipFile zip_file,std::string & relativePath,std::string & absolutePath)230 bool ZipWriter::AddFileEntryToZip(zipFile zip_file, std::string &relativePath, std::string &absolutePath)
231 {
232 DUMPER_HILOGD(MODULE_COMMON, "AddFileEntryToZip enter|relativePath=[%{public}s], absolutePath=[%{public}s]",
233 relativePath.c_str(), absolutePath.c_str());
234
235 if (!OpenNewFileEntry(zip_file, relativePath)) {
236 DUMPER_HILOGD(MODULE_COMMON, "AddFileEntryToZip leave|false, open");
237 return false;
238 }
239
240 bool ret = AddFileContentToZip(zip_file, absolutePath);
241
242 if (!CloseNewFileEntry(zip_file)) {
243 DUMPER_HILOGD(MODULE_COMMON, "AddFileEntryToZip leave|false, close");
244 return false;
245 }
246
247 DUMPER_HILOGD(MODULE_COMMON, "AddFileEntryToZip leave|ret=%{public}d", ret);
248 return ret;
249 }
250 } // namespace HiviewDFX
251 } // namespace OHOS
252