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