LCOV - code coverage report
Current view: top level - adcore/common - file_utils.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 87.1 % 201 175
Test Date: 2026-07-28 10:54:24 Functions: 92.9 % 14 13

            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              : }
        

Generated by: LCOV version 2.0-1