LCOV - code coverage report
Current view: top level - adump/common - path.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 92.6 % 135 125
Test Date: 2026-08-31 10:09:28 Functions: 96.0 % 25 24

            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 "path.h"
      12              : #include <algorithm>
      13              : #include "str_utils.h"
      14              : #include "log/hdc_log.h"
      15              : 
      16              : namespace Adx {
      17              : namespace {
      18              : constexpr char DIRECTORY_SEPARATOR = '/';
      19              : constexpr char FILE_EXTENSION_CHAR = '.';
      20              : constexpr const char* PARENT_DIR = "..";
      21              : 
      22              : constexpr mmMode_t DEFAULT_DIR_MODE = M_IRUSR | M_IWUSR | M_IXUSR;
      23              : } // namespace
      24              : 
      25          126 : bool Path::HasParentDirSegment(const std::string& path)
      26              : {
      27          126 :     size_t begin = 0;
      28          162 :     while (begin <= path.size()) {
      29          162 :         const size_t end = path.find(DIRECTORY_SEPARATOR, begin);
      30          162 :         const size_t len = (end == std::string::npos ? path.size() : end) - begin;
      31          162 :         if (path.compare(begin, len, PARENT_DIR) == 0) {
      32           21 :             return true;
      33              :         }
      34          141 :         if (end == std::string::npos) {
      35          105 :             break;
      36              :         }
      37           36 :         begin = end + 1;
      38              :     }
      39          105 :     return false;
      40              : }
      41              : 
      42           32 : Path& Path::operator=(const std::string& path)
      43              : {
      44           32 :     path_ = path;
      45           32 :     return *this;
      46              : }
      47              : 
      48            0 : bool Path::operator==(const Path& other) const { return this->path_ == other.GetString(); }
      49              : 
      50            3 : Path& Path::operator+=(const std::string& path) { return Append(path); }
      51              : 
      52            3 : Path& Path::Assign(const std::string& path)
      53              : {
      54            3 :     path_ = path;
      55            3 :     return *this;
      56              : }
      57              : 
      58          680 : Path& Path::Append(const std::string& path)
      59              : {
      60          680 :     AddSeperator();
      61          680 :     AppendPath(path);
      62          680 :     AddSeperator();
      63          680 :     return *this;
      64              : }
      65              : 
      66          350 : Path& Path::Concat(const std::string& path)
      67              : {
      68          350 :     AddSeperator();
      69          350 :     AppendPath(path);
      70          350 :     return *this;
      71              : }
      72              : 
      73           13 : Path& Path::AddExtension(const std::string& extension)
      74              : {
      75           13 :     std::string ext = StrUtils::Trim(extension);
      76           13 :     if (path_.empty() || ext.empty() || GetExtension() == ext) {
      77            3 :         return *this;
      78              :     }
      79              : 
      80           10 :     if (ext.front() != FILE_EXTENSION_CHAR) {
      81            3 :         path_ += FILE_EXTENSION_CHAR;
      82              :     }
      83           10 :     path_.append(ext);
      84           10 :     return *this;
      85           13 : }
      86              : 
      87           25 : std::string Path::GetExtension() const
      88              : {
      89           25 :     std::string file = GetFileName();
      90           25 :     const auto pos = file.rfind(FILE_EXTENSION_CHAR);
      91           63 :     return pos != std::string::npos ? file.substr(pos) : "";
      92           25 : }
      93              : 
      94          277 : std::string Path::GetFileName() const
      95              : {
      96          277 :     const auto pos = path_.find_last_of(DIRECTORY_SEPARATOR);
      97          277 :     return pos != std::string::npos ? path_.substr(pos + 1) : path_;
      98              : }
      99              : 
     100          515 : bool Path::Empty() const { return path_.empty(); }
     101              : 
     102           35 : bool Path::Exist() const { return Asccess(F_OK); }
     103              : 
     104          541 : bool Path::Asccess(mmMode_t mode) const { return !path_.empty() && mmAccess2(path_.c_str(), mode) == EN_OK; }
     105              : 
     106         1042 : bool Path::IsDirectory() const { return mmIsDir(path_.c_str()) == EN_OK; }
     107              : 
     108       134077 : bool Path::RealPath()
     109              : {
     110       134077 :     if (path_.empty()) {
     111            3 :         return false;
     112              :     }
     113              : 
     114       133997 :     char realPath[MMPA_MAX_PATH] = {0};
     115       133997 :     const int32_t ret = mmRealPath(path_.c_str(), realPath, MMPA_MAX_PATH);
     116       134354 :     if (ret != EN_OK) {
     117           80 :         return false;
     118              :     }
     119       134274 :     path_ = realPath;
     120       133893 :     return true;
     121              : }
     122              : 
     123              : /*
     124              :  * @brief: Get parent path
     125              :  *         /path/to/file -> /path/to
     126              :  *         / -> /
     127              :  *         /file -> /
     128              :  *         file -> ""
     129              :  */
     130          524 : Path Path::ParentPath() const
     131              : {
     132          524 :     if (path_.length() == 1 && path_[0] == DIRECTORY_SEPARATOR) {
     133            3 :         return Path(path_);
     134              :     }
     135              : 
     136          521 :     const size_t pos = path_.find_last_of(DIRECTORY_SEPARATOR);
     137              :     std::string parentPath =
     138          527 :         pos != std::string::npos ? (pos == 0 ? std::string(&DIRECTORY_SEPARATOR, 1) : path_.substr(0, pos)) : "";
     139          521 :     return Path(parentPath);
     140          521 : }
     141              : 
     142          488 : bool Path::CreateDirectory(bool recursion) const
     143              : {
     144          488 :     if (path_.empty() || path_.length() > MMPA_MAX_PATH) {
     145            3 :         IDE_LOGW("Directory path is empty or overlength, path: %s", path_.c_str());
     146            3 :         return false;
     147              :     }
     148              : 
     149          485 :     if (IsDirectory()) {
     150          213 :         return true;
     151              :     }
     152              : 
     153          272 :     if (recursion) {
     154          266 :         Path parentPath = ParentPath();
     155          266 :         if (!parentPath.Empty() && !parentPath.CreateDirectory(recursion)) {
     156            0 :             return false;
     157              :         }
     158          266 :     }
     159              : 
     160          272 :     const int32_t ret = mmMkdir(path_.c_str(), DEFAULT_DIR_MODE);
     161          272 :     if (ret != 0 && errno != EEXIST) {
     162            3 :         IDE_LOGW("Can not mkdir %s, mode: %d, errno: %s", path_.c_str(), DEFAULT_DIR_MODE, strerror(errno));
     163            3 :         return false;
     164              :     }
     165          269 :     return true;
     166              : }
     167              : 
     168       134197 : std::string Path::GetString() const { return path_; }
     169              : 
     170          268 : const char* Path::GetCString() const { return path_.c_str(); }
     171              : 
     172           60 : bool Path::BuildFullPathUnderRoot(
     173              :     const std::string& rootPath, const std::string& relativeFile, std::string& canonicalFile)
     174              : {
     175           60 :     if (rootPath.empty() || relativeFile.empty()) {
     176           18 :         IDE_LOGE("rootPath or relativeFile is empty.");
     177           18 :         return false;
     178              :     }
     179              : 
     180           42 :     if (HasParentDirSegment(relativeFile)) {
     181            3 :         IDE_LOGE("relativeFile[%s] contains '..' segment.", relativeFile.c_str());
     182            3 :         return false;
     183              :     }
     184              : 
     185           39 :     const std::string filePath = Path(rootPath).Concat(relativeFile).GetString();
     186           39 :     const std::string baseName = Path(filePath).GetFileName();
     187              : 
     188           39 :     Path dirPath = Path(filePath).ParentPath();
     189           39 :     if (!dirPath.CreateDirectory(true)) {
     190            0 :         IDE_LOGE("create directory failed, dirPath=%s.", dirPath.GetCString());
     191            0 :         return false;
     192              :     }
     193              : 
     194           39 :     if (!dirPath.RealPath()) {
     195            0 :         IDE_LOGE("get real path failed, dirPath=%s.", dirPath.GetCString());
     196            0 :         return false;
     197              :     }
     198              : 
     199           39 :     if (!dirPath.IsDirectory()) {
     200            0 :         IDE_LOGE("path is not a directory, dirPath=%s", dirPath.GetCString());
     201            0 :         return false;
     202              :     }
     203              : 
     204           39 :     Path realRootPath(rootPath);
     205           39 :     if (!realRootPath.RealPath()) {
     206            0 :         IDE_LOGE("get real path failed, rootPath=%s.", realRootPath.GetCString());
     207            0 :         return false;
     208              :     }
     209              : 
     210           39 :     if (!IsUnderDirectory(realRootPath.GetString(), dirPath.GetString())) {
     211            3 :         IDE_LOGE("resolved dirPath=%s escapes rootPath=%s.", dirPath.GetCString(), realRootPath.GetCString());
     212            3 :         return false;
     213              :     }
     214              : 
     215           36 :     canonicalFile = dirPath.GetString() + DIRECTORY_SEPARATOR + baseName;
     216           36 :     return true;
     217           39 : }
     218              : 
     219           75 : bool Path::IsUnderDirectory(const std::string& realDirPath, const std::string& realSubPath)
     220              : {
     221           75 :     if (realDirPath.empty() || realSubPath.empty()) {
     222            6 :         return false;
     223              :     }
     224              : 
     225              :     // Both paths are already canonical, so a segment-aware prefix match is sufficient.
     226           69 :     std::string prefix = realDirPath;
     227           69 :     if (prefix.back() != DIRECTORY_SEPARATOR) {
     228           54 :         prefix += DIRECTORY_SEPARATOR;
     229              :     }
     230              : 
     231           69 :     std::string target = realSubPath;
     232           69 :     if (target.back() != DIRECTORY_SEPARATOR) {
     233           66 :         target += DIRECTORY_SEPARATOR;
     234              :     }
     235              : 
     236           69 :     return target.compare(0, prefix.size(), prefix) == 0;
     237           69 : }
     238              : 
     239         1030 : void Path::AppendPath(const std::string& path)
     240              : {
     241         1030 :     std::string newPath = StrUtils::Trim(path);
     242         1030 :     (void)newPath.erase(newPath.begin(), std::find_if(newPath.begin(), newPath.end(), [](uint8_t ch) {
     243         1214 :                             return ch != DIRECTORY_SEPARATOR;
     244              :                         }));
     245         2060 :     (void)newPath.erase(
     246         2185 :         std::find_if(newPath.rbegin(), newPath.rend(), [](uint8_t ch) { return ch != DIRECTORY_SEPARATOR; }).base(),
     247              :         newPath.end());
     248         1030 :     path_ += newPath;
     249         1030 : }
     250              : 
     251         1710 : void Path::AddSeperator()
     252              : {
     253         1710 :     if (!path_.empty() && path_.back() != DIRECTORY_SEPARATOR) {
     254         1388 :         path_ += DIRECTORY_SEPARATOR;
     255              :     }
     256         1710 : }
     257              : } // namespace Adx
        

Generated by: LCOV version 2.0-1