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
|