1/* 2 * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved. 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 16#include "file.h" 17#include <cerrno> 18#include <fcntl.h> 19#include <fstream> 20#include <iostream> 21#include <sys/stat.h> 22#include <unistd.h> 23 24#include "log.h" 25#if defined(_WIN32) 26#include <direct.h> 27#include <io.h> 28#include <windows.h> 29#endif 30#if defined(is_linux) || defined(_WIN32) 31#include <filesystem> 32#endif 33#include "zlib.h" 34#include "contrib/minizip/zip.h" 35#include "contrib/minizip/unzip.h" 36 37namespace SysTuning { 38namespace base { 39static TraceParserStatus g_status = TRACE_PARSER_ABNORMAL; 40 41void SetAnalysisResult(TraceParserStatus stat) 42{ 43 g_status = stat; 44} 45TraceParserStatus GetAnalysisResult() 46{ 47 return g_status; 48} 49 50ssize_t Read(int32_t fd, uint8_t *dst, size_t dstSize) 51{ 52#if defined(_WIN32) 53 return _read(fd, dst, static_cast<unsigned>(dstSize)); 54#else 55 ssize_t ret = -1; 56 do { 57 ret = read(fd, dst, dstSize); 58 } while (ret == -1 && errno == EINTR); 59 return ret; 60#endif 61} 62int32_t OpenFile(const std::string &path, int32_t flags, uint32_t mode) 63{ 64 TS_ASSERT((flags & O_CREAT) == 0 || mode != K_FILE_MODE_INVALID); 65#if defined(_WIN32) 66 int32_t fd(_open(path.c_str(), flags | O_BINARY, mode)); 67#else 68 int32_t fd(open(path.c_str(), flags | O_CLOEXEC, mode)); 69#endif 70 return fd; 71} 72 73std::string GetExecutionDirectoryPath() 74{ 75 char currPath[1024] = {0}; 76#if defined(_WIN32) 77 ::GetModuleFileNameA(NULL, currPath, MAX_PATH); 78 (strrchr(currPath, '\\'))[1] = 0; 79#else 80 (void)readlink("/proc/self/exe", currPath, sizeof(currPath) - 1); 81#endif 82 std::string str(currPath); 83 return str.substr(0, str.find_last_of('/')); 84} 85#if defined(is_linux) || defined(_WIN32) 86std::vector<std::string> GetFilesNameFromDir(const std::string &path, bool onlyFileName) 87{ 88 std::vector<std::string> soFiles; 89 90 std::filesystem::path dirPath(path); 91 // 检查文件是否存在 92 if (!std::filesystem::exists(dirPath)) { 93 TS_LOGI("!std::filesystem::exists(dirPath), dirPath: %s\n", path.data()); 94 return soFiles; 95 } 96 // 遍历目录 97 for (const auto &entry : std::filesystem::recursive_directory_iterator(dirPath)) { 98 if (entry.is_directory()) { 99 continue; 100 } 101 soFiles.emplace_back(onlyFileName ? entry.path().filename().string() : entry.path().string()); 102 } 103 return soFiles; 104} 105#endif 106 107bool UnZipFile(const std::string &zipFile, std::string &traceFile) 108{ 109 std::filesystem::path stdZipFile(zipFile); 110 // 检查文件是否存在 111 if (!std::filesystem::exists(stdZipFile)) { 112 TS_LOGI("!std::filesystem::exists(dirPath), dirPath: %s\n", zipFile.data()); 113 return false; 114 } 115 std::ifstream zipIfstream(stdZipFile); 116 char buf[2]; 117 zipIfstream.read(buf, 2); 118 if (buf[0] != 'P' || buf[1] != 'K') { 119 // 不是zip文件, 返回true走正常解析流程 120 return true; 121 } else { 122 auto unzipDirPath = stdZipFile.parent_path().append("tmp").string(); 123 LocalUnzip(zipFile, unzipDirPath); 124 auto files = GetFilesNameFromDir(unzipDirPath, false); 125 if (files.size() == 1) { 126 traceFile = files[0]; 127 return true; 128 } 129 return false; 130 } 131} 132 133bool LocalUnzip(const std::string &zipFile, const std::string &dstDir) 134{ 135 int err = 0; 136 void *buf; 137 uInt size_buf; 138 // 创建 dstDir 139 if (std::filesystem::exists(dstDir)) { 140 std::filesystem::remove_all(dstDir); 141 std::filesystem::create_directories(dstDir); 142 } 143 144 // 打开zip文件 145 unzFile uf = unzOpen(zipFile.c_str()); 146 if (uf == NULL) { 147 std::cout << "unzOpen error." << std::endl; 148 return false; 149 } 150 151 // 获取zip文件信息 152 unz_global_info gi; 153 err = unzGetGlobalInfo(uf, &gi); 154 if (err != UNZ_OK) { 155 std::cout << "unzGetGlobalInfo error." << std::endl; 156 return false; 157 } 158 159 size_buf = 512000000; 160 buf = (void *)malloc(size_buf); 161 162 // 遍历zip 163 for (int i = 0; i < gi.number_entry; i++) { 164 char filename_inzip[256]; 165 unz_file_info file_info; 166 uLong ratio = 0; 167 const char *string_method = ""; 168 char charCrypt = ' '; 169 err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0); 170 if (err != UNZ_OK) { 171 std::cout << "error " << err << " with zipfile in unzGetCurrentFileInfo." << std::endl; 172 break; 173 } 174 std::string isdir; 175 std::string filename = filename_inzip; 176 if (filename.back() == '/' || filename.back() == '\\') { 177 //* 是目录,则创建目录 178 isdir = " is directory"; 179 std::string dir = dstDir + "/" + filename; 180 if (!std::filesystem::exists(dir)) { 181 std::filesystem::create_directories(dir); 182 } 183 } else { 184 //* 是文件,打开 -> 读取 -> 写入解压文件 -> 关闭 185 isdir = " is file"; 186 187 err = unzOpenCurrentFile(uf); 188 if (err != UNZ_OK) { 189 std::cout << "error " << err << " with zipfile in unzOpenCurrentFile." << std::endl; 190 } else { 191 std::string writefile = dstDir + "/" + filename; 192 std::filesystem::path fpath(writefile); 193 std::string par = fpath.parent_path().string(); 194 if (!fpath.parent_path().empty() && !std::filesystem::exists(fpath.parent_path())) { 195 std::filesystem::create_directories(fpath.parent_path()); 196 } 197 err = unzReadCurrentFile(uf, buf, size_buf); 198 if (err < 0) { 199 std::cout << "error " << err << " with zipfile in unzReadCurrentFile." << std::endl; 200 break; 201 } 202 if (err > 0) { 203 FILE *fout = fopen(writefile.c_str(), "wb"); 204 if (fwrite(buf, (unsigned)err, 1, fout) != 1) { 205 std::cout << "error in writing extracted filee." << std::endl; 206 err = UNZ_ERRNO; 207 break; 208 } 209 fclose(fout); 210 } 211 unzCloseCurrentFile(uf); 212 } 213 } 214 215 if ((i + 1) < gi.number_entry) { 216 err = unzGoToNextFile(uf); 217 if (err != UNZ_OK) { 218 std::cout << "error " << err << " with zipfile in unzGoToNextFile." << std::endl; 219 break; 220 } 221 } 222 } 223 224 unzClose(uf); 225 226 return true; 227} 228} // namespace base 229} // namespace SysTuning 230