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 <memory>
22 #include <sys/stat.h>
23 #include <unistd.h>
24 #include <zlib.h>
25
26 #include "log.h"
27 #include "codec_cov.h"
28 #if defined(_WIN32)
29 #include <direct.h>
30 #include <io.h>
31 #include <windows.h>
32 #endif
33
34 namespace SysTuning {
35 namespace base {
36 #define ZLIB_CHUNK_SIZE 65536
37 static TraceParserStatus g_status = TRACE_PARSER_ABNORMAL;
38
SetAnalysisResult(TraceParserStatus stat)39 void SetAnalysisResult(TraceParserStatus stat)
40 {
41 g_status = stat;
42 }
GetAnalysisResult()43 TraceParserStatus GetAnalysisResult()
44 {
45 return g_status;
46 }
47
Read(int32_t fd,uint8_t * dst,size_t dstSize)48 ssize_t Read(int32_t fd, uint8_t *dst, size_t dstSize)
49 {
50 #if defined(_WIN32)
51 return _read(fd, dst, static_cast<unsigned>(dstSize));
52 #else
53 ssize_t ret = -1;
54 do {
55 ret = read(fd, dst, dstSize);
56 } while (ret == -1 && errno == EINTR);
57 return ret;
58 #endif
59 }
OpenFile(const std::string & path,int32_t flags,uint32_t mode)60 int32_t OpenFile(const std::string &path, int32_t flags, uint32_t mode)
61 {
62 TS_ASSERT((flags & O_CREAT) == 0 || mode != K_FILE_MODE_INVALID);
63 #if defined(_WIN32)
64 int32_t fd(_open(path.c_str(), flags | O_BINARY, mode));
65 #else
66 int32_t fd(open(path.c_str(), flags | O_CLOEXEC, mode));
67 #endif
68 return fd;
69 }
70
GetExecutionDirectoryPath()71 std::string GetExecutionDirectoryPath()
72 {
73 char currPath[1024] = {0};
74 #if defined(_WIN32)
75 ::GetModuleFileNameA(NULL, currPath, MAX_PATH);
76 (strrchr(currPath, '\\'))[1] = 0;
77 #else
78 (void)readlink("/proc/self/exe", currPath, sizeof(currPath) - 1);
79 #endif
80 std::string str(currPath);
81 return str.substr(0, str.find_last_of('/'));
82 }
83
GetFilesNameFromDir(const std::string & path,bool onlyFileName)84 std::vector<std::string> GetFilesNameFromDir(const std::string &path, bool onlyFileName)
85 {
86 std::vector<std::string> soFiles;
87
88 std::filesystem::path dirPath(path);
89 // 检查文件是否存在
90 if (!std::filesystem::exists(dirPath)) {
91 TS_LOGI("!std::filesystem::exists(dirPath), dirPath: %s\n", path.data());
92 return soFiles;
93 }
94 // 遍历目录
95 for (const auto &entry : std::filesystem::recursive_directory_iterator(dirPath)) {
96 if (entry.is_directory()) {
97 continue;
98 }
99 soFiles.emplace_back(onlyFileName ? entry.path().filename().string() : entry.path().string());
100 }
101 return soFiles;
102 }
103
UnZipFile(const std::string & zipFile,std::string & traceFile)104 bool UnZipFile(const std::string &zipFile, std::string &traceFile)
105 {
106 LocalZip localZip(zipFile);
107 return localZip.Unzip(traceFile);
108 }
109
UnZlibFile(const std::string & zlibFile,std::string & traceFile)110 bool UnZlibFile(const std::string &zlibFile, std::string &traceFile)
111 {
112 LocalZip localZip(zlibFile);
113 return localZip.Unzlib(traceFile);
114 }
115
LocalZip(const std::string & file)116 LocalZip::LocalZip(const std::string &file) : filePath_(file)
117 {
118 buf_ = std::make_unique<char[]>(bufSize_);
119 tmpDir_ = std::filesystem::path(file).parent_path().append("ts_tmp").string();
120 }
121
122 // 检查文件是否存在
IsFileExist()123 bool LocalZip::IsFileExist()
124 {
125 #ifdef _WIN32
126 std::filesystem::path zipFile(String2WString(filePath_));
127 #else
128 std::filesystem::path zipFile(filePath_);
129 #endif
130 if (!std::filesystem::exists(zipFile)) {
131 TS_LOGE("!std::filesystem::exists(zipFile), filePath: %s\n", filePath_.data());
132 return false;
133 }
134 return true;
135 }
136
137 // 检查是否为zip文件
IsZipFile()138 bool LocalZip::IsZipFile()
139 {
140 std::ifstream zipIfstream(filePath_);
141 char buf[magicNumLen_];
142 zipIfstream.read(buf, magicNumLen_);
143 return buf[0] == 'P' && buf[1] == 'K';
144 }
145
IsZlibFile()146 bool LocalZip::IsZlibFile()
147 {
148 std::ifstream zlibIfstream(filePath_);
149 unsigned char buf[ZLIB_MAGIC_NUM_LEN];
150 zlibIfstream.read(reinterpret_cast<char *>(buf), ZLIB_MAGIC_NUM_LEN);
151 return buf[0] == ZLIB_CMF && buf[1] == ZLIB_FLG;
152 }
153
CreateDir(const std::filesystem::path & dirName,bool del)154 bool LocalZip::CreateDir(const std::filesystem::path &dirName, bool del)
155 {
156 std::filesystem::path dir = dirName;
157 if (dirName.u8string().back() == '/' || dirName.u8string().back() == '\\') {
158 auto tmpStr = dirName.u8string().substr(0, dirName.u8string().size() - 1);
159 #ifdef _WIN32
160 dir = std::filesystem::path(String2WString(tmpStr));
161 #else
162 dir = std::filesystem::path(tmpStr);
163 #endif
164 }
165 if (std::filesystem::exists(dir)) {
166 if (del) {
167 std::filesystem::remove_all(dir);
168 } else {
169 return true;
170 }
171 }
172 return std::filesystem::create_directories(dir);
173 }
174
WriteFile(const unzFile & uzf,const std::filesystem::path & fileName)175 bool LocalZip::WriteFile(const unzFile &uzf, const std::filesystem::path &fileName)
176 {
177 if (unzOpenCurrentFile(uzf) != UNZ_OK) {
178 TS_LOGE("unzOpenCurrentFile error.");
179 } else {
180 auto parentPath = fileName.parent_path();
181 if (!parentPath.empty()) {
182 CreateDir(parentPath);
183 }
184 #ifdef _WIN32
185 FILE *fout = fopen(Utf8ToGbk(fileName.u8string().c_str()).c_str(), "wb");
186 #else
187 FILE *fout = fopen(fileName.c_str(), "wb");
188 #endif
189 if (fout == nullptr) {
190 unzCloseCurrentFile(uzf);
191 return false;
192 }
193 int err = 1;
194 while (err >= 0) {
195 err = unzReadCurrentFile(uzf, buf_.get(), bufSize_);
196 if (fwrite(buf_.get(), (unsigned)err, 1, fout) != 1) {
197 TS_LOGE("error in writing extracted filee.");
198 break;
199 }
200 }
201 fclose(fout);
202 unzCloseCurrentFile(uzf);
203 }
204 return true;
205 }
206
Unzip(std::string & traceFile)207 bool LocalZip::Unzip(std::string &traceFile)
208 {
209 if (!IsFileExist() || !IsZipFile() || !CreateDir(tmpDir_, true)) {
210 return false;
211 }
212 // 打开zip文件
213 unzFile uzf = unzOpen(filePath_.c_str());
214 if (uzf == nullptr) {
215 TS_LOGE("unzOpen error.");
216 return false;
217 }
218 // 获取zip文件信息
219 unz_global_info ugi;
220 if (unzGetGlobalInfo(uzf, &ugi) != UNZ_OK) {
221 TS_LOGE("unzGetGlobalInfo error.");
222 return false;
223 }
224 for (int i = 0; i < ugi.number_entry; i++) {
225 char filenameInZip[256];
226 unz_file_info file_info;
227 if (unzGetCurrentFileInfo(uzf, &file_info, filenameInZip, sizeof(filenameInZip), NULL, 0, NULL, 0) != UNZ_OK) {
228 TS_LOGE("unzGetCurrentFileInfo error.");
229 break;
230 }
231 #ifdef _WIN32
232 auto fileName = std::filesystem::path(tmpDir_).append(String2WString(filenameInZip));
233 #else
234 std::string tempFileName = filenameInZip;
235 if (base::GetCoding(reinterpret_cast<const uint8_t *>(tempFileName.c_str()), tempFileName.length()) !=
236 base::CODING::UTF8) {
237 tempFileName =
238 "temp_" + std::to_string(i) + ((tempFileName.back() == '/' || tempFileName.back() == '\\') ? "/" : "");
239 }
240 auto fileName = std::filesystem::path(tmpDir_).append(tempFileName);
241 #endif
242 // 是目录,则创建目录; 是文件,打开 -> 读取 -> 写入解压文件 -> 关闭
243 auto isDir = fileName.string().back() == '/' || fileName.string().back() == '\\';
244 if (!(isDir ? CreateDir(fileName) : WriteFile(uzf, fileName))) {
245 break;
246 }
247 // uzf迭代
248 if ((i + 1) < ugi.number_entry) {
249 if (unzGoToNextFile(uzf) != UNZ_OK) {
250 TS_LOGE("unzGoToNextFile error.");
251 break;
252 }
253 }
254 }
255 unzClose(uzf);
256 auto files = GetFilesNameFromDir(tmpDir_, false);
257 if (files.size() == 1) {
258 traceFile = files[0];
259 #ifdef _WIN32
260 traceFile = Utf8ToGbk(traceFile.c_str());
261 #endif
262 return true;
263 }
264 return false;
265 }
266
Unzlib(std::string & traceFile)267 bool LocalZip::Unzlib(std::string &traceFile)
268 {
269 if (!IsFileExist() || !IsZlibFile() || !CreateDir(tmpDir_, true)) {
270 return false;
271 }
272 std::ifstream srcFile(filePath_, std::ios::binary);
273 TS_CHECK_TRUE(srcFile.is_open(), false, "Failed to open source file: %s.", filePath_.c_str());
274 auto writeFilePath = std::filesystem::path(tmpDir_).append("unzlib_file.txt");
275 std::ofstream destFile(writeFilePath.string(), std::ios::binary);
276 TS_CHECK_TRUE(destFile.is_open(), false, "Failed to open destination file: %s.", writeFilePath.string().c_str());
277 if (!WriteFile(srcFile, destFile)) {
278 return false;
279 }
280 traceFile = writeFilePath.string();
281 return true;
282 }
283
WriteFile(std::ifstream & srcFile,std::ofstream & destFile)284 bool LocalZip::WriteFile(std::ifstream &srcFile, std::ofstream &destFile)
285 {
286 auto strmDeleterFunc = [](z_stream *strmPtr) {
287 if (strmPtr) {
288 if (inflateEnd(strmPtr) != Z_OK) {
289 TS_LOGE("Error inflateEnd!");
290 }
291 delete strmPtr;
292 strmPtr = nullptr;
293 }
294 };
295 std::unique_ptr<z_stream, decltype(strmDeleterFunc)> strmPtr(new z_stream, strmDeleterFunc);
296 TS_CHECK_TRUE(strmPtr != nullptr, false, "Error construct strmPtr!");
297 strmPtr->zalloc = Z_NULL;
298 strmPtr->zfree = Z_NULL;
299 strmPtr->opaque = Z_NULL;
300 TS_CHECK_TRUE(inflateInit(strmPtr.get()) == Z_OK, false, "inflateInit failed.");
301
302 unsigned char inputBuf[ZLIB_CHUNK_SIZE];
303 unsigned char outBuf[ZLIB_CHUNK_SIZE];
304 int flushFlag = Z_NO_FLUSH;
305 do {
306 srcFile.read(reinterpret_cast<char *>(inputBuf), ZLIB_CHUNK_SIZE);
307 TS_CHECK_TRUE(!srcFile.bad(), false, "Error reading source file!");
308 strmPtr->avail_in = srcFile.gcount();
309 flushFlag = srcFile.eof() ? Z_FINISH : Z_NO_FLUSH;
310 strmPtr->next_in = inputBuf;
311 do {
312 strmPtr->avail_out = ZLIB_CHUNK_SIZE;
313 strmPtr->next_out = outBuf;
314 auto ret = inflate(strmPtr.get(), flushFlag);
315 // Z_BUF_ERROR means that there is still data that needs to be unziped
316 TS_CHECK_TRUE(ret >= Z_OK || ret == Z_BUF_ERROR, false, "Error inflate: %d!", ret);
317 size_t haveUnzlibSize = ZLIB_CHUNK_SIZE - strmPtr->avail_out;
318 destFile.write(reinterpret_cast<char *>(outBuf), haveUnzlibSize);
319 TS_CHECK_TRUE(!destFile.bad(), false, "DestFile error write!");
320 } while (strmPtr->avail_out == 0);
321 } while (flushFlag != Z_FINISH);
322 return true;
323 }
324 } // namespace base
325 } // namespace SysTuning
326