Line data Source code
1 : /**
2 : * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 :
11 : #include "file_utils.h"
12 : #include <cctype>
13 : #include "log/adx_log.h"
14 : #include "ide_os_type.h"
15 : namespace Adx {
16 : static const std::string MAPPING_FILE_NAME = "mapping.csv";
17 :
18 : /**
19 : * @brief Write data to file
20 : * @param [in] fileName: File path
21 : * @param [in] data : Data to be written
22 : * @param [in] len : The length of data that needs to be written
23 : * @param [in] offset : File offset
24 : * @return
25 : * IDE_DAEMON_NONE_ERROR: Write data to file success
26 : * Other: failed, check for IdeErrorCode
27 : */
28 9 : IdeErrorT FileUtils::WriteFile(const std::string &fileName, IdeSendBuffT data, uint32_t len, int64_t offset)
29 : {
30 9 : IDE_CTRL_VALUE_FAILED(!fileName.empty(), return IDE_DAEMON_INVALID_PARAM_ERROR, "fileName is nullptr");
31 7 : IDE_CTRL_VALUE_FAILED(data != nullptr, return IDE_DAEMON_INVALID_PARAM_ERROR, "data is nullptr");
32 6 : std::string wrFile = fileName;
33 6 : int32_t fd = mmOpen2(wrFile.c_str(), O_APPEND | M_RDWR | M_CREAT, M_IREAD | M_IWRITE);
34 6 : if (fd < 0 && mmGetErrorCode() != ENAMETOOLONG) {
35 1 : char errBuf[MAX_ERRSTR_LEN + 1] = {0};
36 1 : IDE_LOGE("Open file %s failed , exception %s", fileName.c_str(),
37 : mmGetErrorFormatMessage(mmGetErrorCode(), errBuf, MAX_ERRSTR_LEN));
38 1 : return IDE_DAEMON_INVALID_PATH_ERROR;
39 5 : } else if (fd < 0) {
40 1 : std::string wrPath = GetFileDir(wrFile);
41 1 : IDE_CTRL_VALUE_FAILED(!wrPath.empty(), return IDE_DAEMON_INVALID_PATH_ERROR, "file path error");
42 :
43 1 : std::string hashValue = std::to_string(std::hash<std::string>{}(fileName));
44 1 : if (AddMappingFileItem(fileName, hashValue) != IDE_DAEMON_NONE_ERROR) {
45 0 : IDE_LOGE("add mapping item [ %s ] failed", hashValue.c_str());
46 : }
47 1 : wrFile = wrPath + OS_SPLIT_STR + hashValue;
48 1 : IDE_LOGW("file name [ %s ] too long rename as [ %s ] and the mapping record in mapping.csv",
49 : fileName.c_str(), wrFile.c_str());
50 1 : fd = mmOpen2(wrFile.c_str(), O_APPEND | M_RDWR | M_CREAT, M_IREAD | M_IWRITE);
51 1 : IDE_CTRL_VALUE_FAILED(fd >= 0, return IDE_DAEMON_INVALID_PATH_ERROR, "file path error");
52 2 : }
53 :
54 4 : if (offset != -1) {
55 3 : long err = mmLseek(fd, offset, SEEK_SET);
56 3 : if (err < 0) {
57 1 : IDE_LOGE("invalid param, fd %d, offset %ld", fd, offset);
58 1 : FILE_MMCLOSE_AND_SET_INVALID(fd);
59 1 : return IDE_DAEMON_UNKNOW_ERROR;
60 : }
61 : }
62 :
63 3 : IdeU8Pt wrData = static_cast<IdeU8Pt>(const_cast<IdeBuffT>(data));
64 3 : uint32_t reserve = len;
65 : do {
66 3 : mmSsize_t writeLen = mmWrite(fd, wrData + (len - reserve), reserve);
67 3 : if (writeLen < 0) {
68 1 : char errBuf[MAX_ERRSTR_LEN + 1] = {0};
69 1 : IDE_LOGE("Write failed, info: %s, write ratio: %u/%u",
70 : mmGetErrorFormatMessage(mmGetErrorCode(), errBuf, MAX_ERRSTR_LEN), len - reserve, len);
71 1 : FILE_MMCLOSE_AND_SET_INVALID(fd);
72 1 : return IDE_DAEMON_NO_SPACE_ERROR;
73 : }
74 2 : reserve -= writeLen;
75 2 : } while (reserve != 0);
76 :
77 2 : FILE_MMCLOSE_AND_SET_INVALID(fd);
78 2 : return IDE_DAEMON_NONE_ERROR;
79 6 : }
80 :
81 : /**
82 : * @brief Add map item into mapping.csv
83 : * @param [in] filePath: file path
84 : * @param [in] hashValue: hash value of filePath
85 : * @return
86 : * IDE_DAEMON_NONE_ERROR: add mapping item success
87 : * Other: failed, check for IdeErrorCode
88 : */
89 6 : IdeErrorT FileUtils::AddMappingFileItem(const std::string &filePath, const std::string &hashValue)
90 : {
91 6 : IDE_CTRL_VALUE_FAILED(!filePath.empty(), return IDE_DAEMON_INVALID_PARAM_ERROR, "filePath is nullptr");
92 5 : IDE_CTRL_VALUE_FAILED(!hashValue.empty(), return IDE_DAEMON_INVALID_PARAM_ERROR, "hashValue is null");
93 :
94 4 : std::string dir = GetFileDir(filePath);
95 4 : IDE_CTRL_VALUE_FAILED(!dir.empty(), return IDE_DAEMON_INVALID_PATH_ERROR, "file path error");
96 4 : std::string mappingFile = dir + OS_SPLIT_STR + MAPPING_FILE_NAME;
97 4 : int32_t fd = mmOpen2(mappingFile.c_str(), O_APPEND | M_RDWR | M_CREAT, M_IRUSR | M_IWRITE);
98 4 : IDE_CTRL_VALUE_FAILED(fd >= 0, return IDE_DAEMON_INVALID_PATH_ERROR, "the path of mapping.csv error");
99 :
100 3 : long err = mmLseek(fd, 0, SEEK_END);
101 3 : if (err < 0) {
102 1 : IDE_LOGE("fd %d, set the current pos at the end of mapping.csv failed", fd);
103 1 : FILE_MMCLOSE_AND_SET_INVALID(fd);
104 1 : return IDE_DAEMON_UNKNOW_ERROR;
105 : }
106 :
107 2 : std::string filename;
108 2 : if (GetFileName(filePath, filename) != IDE_DAEMON_NONE_ERROR) {
109 0 : IDE_LOGE("invalid filepath [ %s ]", filePath.c_str());
110 0 : FILE_MMCLOSE_AND_SET_INVALID(fd);
111 0 : return IDE_DAEMON_INVALID_PATH_ERROR;
112 : }
113 :
114 2 : std::string mapItem = hashValue + ',' + filename + '\n';
115 2 : uint32_t mapItemDataLen = mapItem.length();
116 2 : uint32_t residLen = mapItemDataLen;
117 : do {
118 2 : mmSsize_t writeLen = mmWrite(fd, const_cast<IdeStringBuffer>(mapItem.c_str()) +
119 2 : (mapItemDataLen - residLen), residLen);
120 2 : if (writeLen < 0) {
121 1 : char errBuf[MAX_ERRSTR_LEN + 1] = {0};
122 1 : IDE_LOGE("Write failed, info: %s, write ratio: %u/%u",
123 : mmGetErrorFormatMessage(mmGetErrorCode(), errBuf, MAX_ERRSTR_LEN),
124 : mapItemDataLen - residLen, mapItemDataLen);
125 1 : FILE_MMCLOSE_AND_SET_INVALID(fd);
126 1 : return IDE_DAEMON_NO_SPACE_ERROR;
127 : }
128 1 : if (residLen >= static_cast<uint32_t>(writeLen)) {
129 1 : residLen -= writeLen;
130 : } else {
131 0 : char errBuf[MAX_ERRSTR_LEN + 1] = {0};
132 0 : IDE_LOGE("Write failed, info : %s, writeLen larger than residLen",
133 : mmGetErrorFormatMessage(mmGetErrorCode(), errBuf, MAX_ERRSTR_LEN));
134 0 : FILE_MMCLOSE_AND_SET_INVALID(fd);
135 0 : return IDE_DAEMON_UNKNOW_ERROR;
136 : }
137 1 : } while (residLen != 0);
138 :
139 1 : FILE_MMCLOSE_AND_SET_INVALID(fd);
140 1 : return IDE_DAEMON_NONE_ERROR;
141 4 : }
142 :
143 : /**
144 : * @brief Check file is exist
145 : * @param [in] path: file path
146 : * @return
147 : * true: file exists
148 : * false: file not exist
149 : */
150 17 : bool FileUtils::IsFileExist(const std::string &path)
151 : {
152 17 : if (path.empty()) {
153 1 : return false;
154 : }
155 :
156 16 : if (::mmAccess(path.c_str()) == EN_OK) {
157 15 : return true;
158 : }
159 :
160 1 : return false;
161 : }
162 :
163 : /**
164 : * @brief Create dir
165 : * @param [in] path: file path
166 : * @return
167 : * IDE_DAEMON_NONE_ERROR: Exist or Mkdir success
168 : * IDE_DAEMON_INVALID_PATH_ERROR: Invalid path
169 : * IDE_DAEMON_MKDIR_ERROR: Mkdir failed
170 : */
171 8 : IdeErrorT FileUtils::CreateDir(const std::string &path)
172 : {
173 8 : std::string curr = path;
174 8 : IdeErrorT ret = IDE_DAEMON_UNKNOW_ERROR;
175 :
176 8 : if (curr.empty()) {
177 1 : IDE_LOGE("create dir input empty");
178 1 : return IDE_DAEMON_INVALID_PATH_ERROR;
179 : }
180 :
181 7 : if (IsFileExist(curr)) {
182 3 : return IDE_DAEMON_NONE_ERROR;
183 : } else {
184 4 : std::string dir = GetFileDir(curr);
185 4 : IDE_CTRL_VALUE_FAILED(!dir.empty(), return ret, "Get file dir failed, ret: %d", ret);
186 :
187 4 : ret = CreateDir(dir);
188 4 : IDE_CTRL_VALUE_FAILED(ret == IDE_DAEMON_NONE_ERROR, return ret, "Create dir failed, ret: %d", ret);
189 4 : }
190 :
191 4 : if (!IsFileExist(path)) {
192 1 : if (mmMkdir(path.c_str(), (mmMode_t)DEFAULT_PATH_MODE) != EN_OK && errno != EEXIST) {
193 1 : char errBuf[MAX_ERRSTR_LEN + 1] = {0};
194 1 : IDE_LOGE("mkdir %s failed, errorstr: %s", path.c_str(),
195 : mmGetErrorFormatMessage(mmGetErrorCode(), errBuf, MAX_ERRSTR_LEN));
196 1 : return IDE_DAEMON_MKDIR_ERROR;
197 : }
198 : }
199 :
200 3 : return IDE_DAEMON_NONE_ERROR;
201 8 : }
202 :
203 : /**
204 : * @brief Get the path part of the path
205 : * @param [in] path: file path
206 : * @param [out] dir: the path part of path
207 : * @return
208 : * IDE_DAEMON_NONE_ERROR: Dump start Success
209 : * IDE_DAEMON_INVALID_PATH_ERROR: Invalid path
210 : */
211 43 : std::string FileUtils::GetFileDir(const std::string &path)
212 : {
213 43 : std::string dir;
214 43 : size_t pos = path.find_last_of(OS_SPLIT_CHAR);
215 43 : if (pos != std::string::npos) {
216 30 : dir = path.substr(0, pos);
217 30 : if (dir.empty()) {
218 1 : dir += OS_SPLIT_STR;
219 : }
220 30 : return dir;
221 : }
222 :
223 13 : return dir;
224 0 : }
225 :
226 : /**
227 : * @brief Check if the path has sufficient disk space
228 : * @param [in] path: file path
229 : * @param [in] size: The amount of disk space required
230 : * @return
231 : * true: the path has sufficient disk space
232 : * false: invalid path or the path does not have sufficient disk space
233 : */
234 7 : bool FileUtils::IsDiskFull(const std::string &path, uint64_t size)
235 : {
236 7 : IDE_CTRL_VALUE_FAILED(!path.empty(), return false, "path is empty");
237 :
238 : mmDiskSize diskSize;
239 6 : (void)memset_s(&diskSize, sizeof(diskSize), 0, sizeof(diskSize));
240 6 : int32_t ret = mmGetDiskFreeSpace(path.c_str(), &diskSize);
241 6 : IDE_CTRL_VALUE_FAILED(ret == EN_OK, return true, "get disk free space fail");
242 5 : IDE_CTRL_VALUE_FAILED(diskSize.freeSize > DISK_RESERVED_SPACE, return true,
243 : "the %s more than disk reserved space(1Mb)", path.c_str());
244 4 : IDE_CTRL_VALUE_FAILED(size < diskSize.freeSize, return true, "the %s is full", path.c_str());
245 3 : return false;
246 : }
247 :
248 : /**
249 : * @brief Get the name part of the path
250 : * @param [in] path: file path
251 : * @param [out] dir: the name part of path
252 : * @return
253 : * IDE_DAEMON_NONE_ERROR: Dump start Success
254 : * IDE_DAEMON_INVALID_PATH_ERROR: Invalid path
255 : */
256 5 : IdeErrorT FileUtils::GetFileName(const std::string &path, std::string &name)
257 : {
258 5 : size_t pos = path.find_last_of(OS_SPLIT_CHAR);
259 5 : if (pos != std::string::npos) {
260 4 : name = path.substr(pos + 1);
261 4 : if (name.empty()) {
262 1 : return IDE_DAEMON_INVALID_PATH_ERROR;
263 : }
264 3 : return IDE_DAEMON_NONE_ERROR;
265 : }
266 1 : name = path;
267 1 : return IDE_DAEMON_NONE_ERROR;
268 : }
269 :
270 : /**
271 : * @brief Check file path exit cross path
272 : * @param [in] path: file path
273 : * @return
274 : * true : file not exists cross path
275 : * false : file exists cross path
276 : */
277 30 : bool FileUtils::CheckNonCrossPath(const std::string &path)
278 : {
279 30 : if (path.empty() || path.length() > MMPA_MAX_PATH) {
280 1 : return false;
281 : }
282 :
283 29 : size_t pos = path.find("..");
284 29 : if (pos == 0) {
285 2 : return false;
286 : }
287 :
288 47 : if (path.find("/..") != std::string::npos ||
289 20 : path.find("/\\.\\.") != std::string::npos) {
290 8 : return false;
291 : }
292 :
293 19 : return true;
294 : }
295 :
296 : /**
297 : * @brief jugde the file_path is realpath
298 : * @param [in] file_path: file path
299 : * @param [out] resolved_path: return path
300 : *
301 : * @return
302 : * IDE_DAEMON_OK: succ
303 : * IDE_DAEMON_ERROR: failed
304 : */
305 33 : int32_t FileUtils::FilePathIsReal(const std::string &filePath, std::string &resultPath)
306 : {
307 33 : if (filePath.empty()) {
308 0 : return IDE_DAEMON_ERROR;
309 : }
310 :
311 33 : char resolvedPath[MMPA_MAX_PATH] = {0};
312 :
313 33 : int32_t ret = mmRealPath(filePath.c_str(), resolvedPath, MMPA_MAX_PATH);
314 33 : if (ret != EN_OK) {
315 25 : return IDE_DAEMON_ERROR;
316 : }
317 8 : resultPath = resolvedPath;
318 8 : return IDE_DAEMON_OK;
319 : }
320 :
321 : /**
322 : * @brief jugde the file path with filename is realpath
323 : * @param file_path: file path
324 : * @param resolved_path: return path
325 : * @param path_len: the max length of resolved_path buffer
326 : *
327 : * @return
328 : * IDE_DAEMON_OK: succ
329 : * IDE_DAEMON_ERROR: failed
330 : */
331 31 : int32_t FileUtils::FileNameIsReal(const std::string &file, std::string &resultPath)
332 : {
333 31 : int32_t ret = 0;
334 31 : if (file.empty()) {
335 0 : return IDE_DAEMON_ERROR;
336 : }
337 :
338 31 : size_t pos = file.find_last_of(OS_SPLIT_CHAR);
339 31 : if (pos != std::string::npos) {
340 31 : std::string path = file.substr(0, pos + 1);
341 31 : ret = FilePathIsReal(path, resultPath);
342 31 : if (ret != IDE_DAEMON_OK) {
343 24 : IDE_LOGE("path %s does not exist", file.c_str());
344 24 : return IDE_DAEMON_ERROR;
345 : }
346 31 : }
347 7 : resultPath = file;
348 7 : return IDE_DAEMON_OK;
349 : }
350 :
351 : /**
352 : * @brief Check if characters of the dir are all valid
353 : * @param [in] path: file path
354 : * @return
355 : * true: characters of the dir are all valid
356 : * false: characters of the dir are not all valid
357 : */
358 12 : bool FileUtils::IsValidDirChar(const std::string &path)
359 : {
360 12 : if (path.empty()) {
361 1 : IDE_LOGE("invalid parameter");
362 1 : return false;
363 : }
364 :
365 11 : const std::string pathWhiteList = "-=[];\\,./!@#$%^&*()_+{}:?";
366 11 : size_t len = path.length();
367 91 : for (size_t i = 0; i < len; i++) {
368 109 : if (!islower(path[i]) && !isupper(path[i]) && !isdigit(path[i]) &&
369 25 : pathWhiteList.find(path[i]) == std::string::npos) {
370 4 : IDE_LOGW("invalid path [%s] in char : [%c] at location %zu", path.c_str(), path[i], i);
371 4 : return false;
372 : }
373 : }
374 :
375 7 : return true;
376 11 : }
377 :
378 1 : std::string FileUtils::ReplaceAll(std::string &base, const std::string &src, const std::string &dst)
379 : {
380 1 : size_t pos = 0;
381 1 : std::string targetStr = dst;
382 3 : while ((pos = base.find(src, pos)) != std::string::npos) {
383 2 : base.replace(pos, src.size(), targetStr);
384 2 : pos += targetStr.size();
385 : }
386 2 : return base;
387 1 : }
388 :
389 11 : bool FileUtils::IsAbsolutePath(const std::string &path)
390 : {
391 : #if (OS_TYPE == LINUX)
392 11 : return path.front() == OS_SPLIT_CHAR;
393 : #else
394 : if (path.length() < WIN_PATH_MIN_LENGTH) {
395 : return false;
396 : }
397 : return (path[1] == COLON) &&
398 : ((path[0] >= 'a' && path[0] <= 'z') ||
399 : (path[0] >= 'A' && path[0] <= 'Z'));
400 : #endif
401 : }
402 :
403 0 : bool FileUtils::IsPathHasPermission(const std::string &path, std::string &errorMsg) {
404 0 : std::string trustedPath;
405 0 : int32_t ret = FilePathIsReal(path, trustedPath);
406 0 : if (ret != IDE_DAEMON_OK) {
407 0 : errorMsg = "The dump_path " + path + " is not a real path.";
408 0 : IDE_LOGE("%s", errorMsg.c_str());
409 0 : return false;
410 : }
411 0 : constexpr uint32_t accessMode = static_cast<uint32_t>(M_R_OK) | static_cast<uint32_t>(M_W_OK);
412 0 : if (mmAccess2(trustedPath.c_str(), static_cast<INT32>(accessMode)) != EN_OK) {
413 0 : errorMsg = "The path " + trustedPath + " does not have read and write permission";
414 0 : IDE_LOGE("%s", errorMsg.c_str());
415 0 : return false;
416 : }
417 0 : errorMsg.clear();
418 0 : return true;
419 0 : }
420 : }
|