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