LCOV - code coverage report
Current view: top level - adcore/common - file_utils.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 86.9 % 199 173
Test Date: 2026-08-12 11:04:53 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(
      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
        

Generated by: LCOV version 2.0-1