/* * Copyright (C) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "util/zip/zip_writer.h" #include <chrono> #include "directory_ex.h" #include "dump_utils.h" #include "hilog_wrapper.h" namespace OHOS { namespace HiviewDFX { namespace { static const int PROCENT100 = 100; static const int ZIP_BUF_SIZE = 8192; static const int BASE_YEAR = 1900; static const uLong LANGUAGE_ENCODING_FLAG = 0x1 << 11; } // namespace ZipWriter::ZipWriter(const std::string &zipFilePath) : zipFilePath_(zipFilePath), zipFile_(nullptr) { DUMPER_HILOGD(MODULE_COMMON, "create|zipFilePath=[%{public}s]", zipFilePath_.c_str()); } ZipWriter::~ZipWriter() { DUMPER_HILOGD(MODULE_COMMON, "release|"); zipItems_.clear(); Close(); } bool ZipWriter::Open() { DUMPER_HILOGD(MODULE_COMMON, "Open enter|zipFilePath=[%{public}s]", zipFilePath_.c_str()); if (zipFilePath_.empty()) { DUMPER_HILOGE(MODULE_COMMON, "Open leave|false, path is empty"); return false; } DUMPER_HILOGD(MODULE_COMMON, "Open debug|"); zipFile_ = OpenForZipping(zipFilePath_, APPEND_STATUS_CREATE); if (zipFile_ == nullptr) { DUMPER_HILOGE(MODULE_COMMON, "Open leave|false, couldn't create ZIP file"); return false; } DUMPER_HILOGD(MODULE_COMMON, "Open leave|true, create ZIP file"); return true; } bool ZipWriter::Close() { DUMPER_HILOGD(MODULE_COMMON, "Close enter|"); int res = ZIP_OK; if (zipFile_ != nullptr) { res = zipClose(zipFile_, nullptr); } zipFile_ = nullptr; bool ret = (res == ZIP_OK); DUMPER_HILOGD(MODULE_COMMON, "Close leave|ret=%{public}d, res=%{public}d", ret, res); return ret; } bool ZipWriter::Write(const std::vector<std::pair<std::string, std::string>> &zipItems, const ZipTickNotify notify) { DUMPER_HILOGD(MODULE_COMMON, "Write enter|"); if (zipFile_ == nullptr) { DUMPER_HILOGE(MODULE_COMMON, "Write failed, zipFile_ is nullptr"); return false; } zipItems_.insert(zipItems_.end(), zipItems.begin(), zipItems.end()); bool ret = FlushItems(notify); DUMPER_HILOGD(MODULE_COMMON, "Write debug|FlushItems, ret=%{public}d", ret); if (ret) { ret = Close(); } DUMPER_HILOGD(MODULE_COMMON, "Write leave|ret=%{public}d", ret); return ret; } bool ZipWriter::FlushItems(const ZipTickNotify notify) { DUMPER_HILOGD(MODULE_COMMON, "FlushItems enter|"); std::vector<std::pair<std::string, std::string>> zipItems; zipItems.assign(zipItems_.begin(), zipItems_.end()); zipItems_.clear(); bool ret = true; for (size_t i = 0; i < zipItems.size(); i++) { if ((notify != nullptr) && (notify(((PROCENT100 * i) / zipItems.size()), UNSET_PROGRESS))) { DUMPER_HILOGE(MODULE_COMMON, "FlushItems error|notify"); ret = false; break; } auto item = zipItems[i]; std::string absolutePath = item.first; // first:absolutePath std::string relativePath = item.second; // second:relativePath DUMPER_HILOGD(MODULE_COMMON, "FlushItems debug|relativePath=[%{public}s], absolutePath=[%{public}s]", relativePath.c_str(), absolutePath.c_str()); if (!AddFileEntryToZip(zipFile_, relativePath, absolutePath)) { DUMPER_HILOGE(MODULE_COMMON, "FlushItems error|false, failed to write file"); ret = false; break; } } DUMPER_HILOGD(MODULE_COMMON, "FlushItems leave|ret=%{public}d", ret); return ret; } bool ZipWriter::SetTimeToZipFileInfo(zip_fileinfo &zipInfo) { auto nowTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); struct tm localTime = {0}; if (localtime_r(&nowTime, &localTime) == nullptr) { DUMPER_HILOGE(MODULE_COMMON, "SetTimeToZipFileInfo error|nullptr"); return false; } zipInfo.tmz_date.tm_year = static_cast<uInt>(localTime.tm_year + BASE_YEAR); zipInfo.tmz_date.tm_mon = static_cast<uInt>(localTime.tm_mon); zipInfo.tmz_date.tm_mday = static_cast<uInt>(localTime.tm_mday); zipInfo.tmz_date.tm_hour = static_cast<uInt>(localTime.tm_hour); zipInfo.tmz_date.tm_min = static_cast<uInt>(localTime.tm_min); zipInfo.tmz_date.tm_sec = static_cast<uInt>(localTime.tm_sec); return true; } zipFile ZipWriter::OpenForZipping(const std::string &fileName, int append) { return zipOpen2(fileName.c_str(), append, nullptr, nullptr); } bool ZipWriter::ZipOpenNewFileInZip(zipFile zip_file, const std::string &strPath) { DUMPER_HILOGD(MODULE_COMMON, "ZipOpenNewFileInZip enter|strPath=[%{public}s]", strPath.c_str()); zip_fileinfo fileInfo = {}; SetTimeToZipFileInfo(fileInfo); int res = zipOpenNewFileInZip4(zip_file, strPath.c_str(), &fileInfo, nullptr, 0u, nullptr, 0u, nullptr, Z_DEFLATED, Z_DEFAULT_COMPRESSION, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, nullptr, 0, 0, LANGUAGE_ENCODING_FLAG); bool ret = (res == ZIP_OK); DUMPER_HILOGD(MODULE_COMMON, "ZipOpenNewFileInZip leave|ret=%{public}d, res=%{public}d", ret, res); return ret; } bool ZipWriter::AddFileContentToZip(zipFile zip_file, std::string &file_path) { DUMPER_HILOGD(MODULE_COMMON, "AddFileContentToZip enter|file_path=[%{public}s]", file_path.c_str()); if (!DumpUtils::PathIsValid(file_path)) { DUMPER_HILOGE(MODULE_COMMON, "AddFileContentToZip leave|false, PathIsValid"); return false; } auto fp = fopen(file_path.c_str(), "rb"); if (fp == nullptr) { DUMPER_HILOGE(MODULE_COMMON, "AddFileContentToZip leave|false, fopen"); return false; } bool ret = true; char buf[ZIP_BUF_SIZE]; while (!feof(fp)) { size_t readSum = fread(buf, 1, ZIP_BUF_SIZE, fp); if (readSum < 1) { continue; } if (zipWriteInFileInZip(zip_file, buf, readSum) != ZIP_OK) { DUMPER_HILOGE(MODULE_COMMON, "AddFileContentToZip error|could not write data to zip"); ret = false; break; } } (void)fclose(fp); fp = nullptr; DUMPER_HILOGD(MODULE_COMMON, "AddFileContentToZip leave|ret=%{public}d", ret); return ret; } bool ZipWriter::OpenNewFileEntry(zipFile zip_file, std::string &path) { DUMPER_HILOGD(MODULE_COMMON, "OpenNewFileEntry enter|path=[%{public}s]", path.c_str()); bool ret = ZipOpenNewFileInZip(zip_file, path); DUMPER_HILOGD(MODULE_COMMON, "OpenNewFileEntry leave|ret=%{public}d", ret); return ret; } bool ZipWriter::CloseNewFileEntry(zipFile zip_file) { DUMPER_HILOGD(MODULE_COMMON, "CloseNewFileEntry enter|"); int res = zipCloseFileInZip(zip_file); bool ret = (res == ZIP_OK); DUMPER_HILOGD(MODULE_COMMON, "CloseNewFileEntry leave|ret=%{public}d, res=%{public}d", ret, res); return ret; } bool ZipWriter::AddFileEntryToZip(zipFile zip_file, std::string &relativePath, std::string &absolutePath) { DUMPER_HILOGD(MODULE_COMMON, "AddFileEntryToZip enter|relativePath=[%{public}s], absolutePath=[%{public}s]", relativePath.c_str(), absolutePath.c_str()); if (!OpenNewFileEntry(zip_file, relativePath)) { DUMPER_HILOGE(MODULE_COMMON, "AddFileEntryToZip leave|false, open"); return false; } bool ret = AddFileContentToZip(zip_file, absolutePath); if (!CloseNewFileEntry(zip_file)) { DUMPER_HILOGE(MODULE_COMMON, "AddFileEntryToZip leave|false, close"); return false; } DUMPER_HILOGD(MODULE_COMMON, "AddFileEntryToZip leave|ret=%{public}d", ret); return ret; } } // namespace HiviewDFX } // namespace OHOS