• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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