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 29 : Path &Path::operator = (const std::string &path)
43 : {
44 29 : path_ = path;
45 29 : return *this;
46 : }
47 :
48 0 : bool Path::operator == (const Path &other) const
49 : {
50 0 : return this->path_ == other.GetString();
51 : }
52 :
53 3 : Path &Path::operator += (const std::string &path)
54 : {
55 3 : return Append(path);
56 : }
57 :
58 3 : Path &Path::Assign(const std::string &path)
59 : {
60 3 : path_ = path;
61 3 : return *this;
62 : }
63 :
64 636 : Path &Path::Append(const std::string &path)
65 : {
66 636 : AddSeperator();
67 636 : AppendPath(path);
68 636 : AddSeperator();
69 636 : return *this;
70 : }
71 :
72 373 : Path &Path::Concat(const std::string &path)
73 : {
74 373 : AddSeperator();
75 373 : AppendPath(path);
76 373 : return *this;
77 : }
78 :
79 13 : Path &Path::AddExtension(const std::string &extension)
80 : {
81 13 : std::string ext = StrUtils::Trim(extension);
82 13 : if (path_.empty() || ext.empty() || GetExtension() == ext) {
83 3 : return *this;
84 : }
85 :
86 10 : if (ext.front() != FILE_EXTENSION_CHAR) {
87 3 : path_ += FILE_EXTENSION_CHAR;
88 : }
89 10 : path_.append(ext);
90 10 : return *this;
91 13 : }
92 :
93 25 : std::string Path::GetExtension() const
94 : {
95 25 : std::string file = GetFileName();
96 25 : const auto pos = file.rfind(FILE_EXTENSION_CHAR);
97 63 : return pos != std::string::npos ? file.substr(pos) : "";
98 25 : }
99 :
100 281 : std::string Path::GetFileName() const
101 : {
102 281 : const auto pos = path_.find_last_of(DIRECTORY_SEPARATOR);
103 281 : return pos != std::string::npos ? path_.substr(pos + 1) : path_;
104 : }
105 :
106 471 : bool Path::Empty() const
107 : {
108 471 : return path_.empty();
109 : }
110 :
111 67 : bool Path::Exist() const
112 : {
113 67 : return Asccess(F_OK);
114 : }
115 :
116 573 : bool Path::Asccess(mmMode_t mode) const
117 : {
118 573 : return !path_.empty() && mmAccess2(path_.c_str(), mode) == EN_OK;
119 : }
120 :
121 979 : bool Path::IsDirectory() const
122 : {
123 979 : return mmIsDir(path_.c_str()) == EN_OK;
124 : }
125 :
126 139807 : bool Path::RealPath()
127 : {
128 139807 : if (path_.empty()) {
129 3 : return false;
130 : }
131 :
132 139854 : char realPath[MMPA_MAX_PATH] = {0};
133 139854 : const int32_t ret = mmRealPath(path_.c_str(), realPath, MMPA_MAX_PATH);
134 139679 : if (ret != EN_OK) {
135 68 : return false;
136 : }
137 139611 : path_ = realPath;
138 139650 : return true;
139 : }
140 :
141 : /*
142 : * @brief: Get parent path
143 : * /path/to/file -> /path/to
144 : * / -> /
145 : * /file -> /
146 : * file -> ""
147 : */
148 473 : Path Path::ParentPath() const
149 : {
150 473 : if (path_.length() == 1 && path_[0] == DIRECTORY_SEPARATOR) {
151 3 : return Path(path_);
152 : }
153 :
154 470 : const size_t pos = path_.find_last_of(DIRECTORY_SEPARATOR);
155 470 : std::string parentPath = pos != std::string::npos ?
156 476 : (pos == 0 ? std::string(&DIRECTORY_SEPARATOR, 1) : path_.substr(0, pos)) : "";
157 470 : return Path(parentPath);
158 470 : }
159 :
160 425 : bool Path::CreateDirectory(bool recursion) const
161 : {
162 425 : if (path_.empty() || path_.length() > MMPA_MAX_PATH) {
163 3 : IDE_LOGW("Directory path is empty or overlength, path: %s", path_.c_str());
164 3 : return false;
165 : }
166 :
167 422 : if (IsDirectory()) {
168 202 : return true;
169 : }
170 :
171 220 : if (recursion) {
172 214 : Path parentPath = ParentPath();
173 214 : if (!parentPath.Empty() && !parentPath.CreateDirectory(recursion)) {
174 0 : return false;
175 : }
176 214 : }
177 :
178 220 : const int32_t ret = mmMkdir(path_.c_str(), DEFAULT_DIR_MODE);
179 220 : if (ret != 0 && errno != EEXIST) {
180 3 : IDE_LOGW("Can not mkdir %s, mode: %d, errno: %s", path_.c_str(), DEFAULT_DIR_MODE, strerror(errno));
181 3 : return false;
182 : }
183 217 : return true;
184 : }
185 :
186 139779 : std::string Path::GetString() const
187 : {
188 139779 : return path_;
189 : }
190 :
191 344 : const char *Path::GetCString() const
192 : {
193 344 : return path_.c_str();
194 : }
195 :
196 60 : bool Path::BuildFullPathUnderRoot(const std::string &rootPath, const std::string &relativeFile,
197 : std::string &canonicalFile)
198 : {
199 60 : if (rootPath.empty() || relativeFile.empty()) {
200 18 : IDE_LOGE("rootPath or relativeFile is empty.");
201 18 : return false;
202 : }
203 :
204 42 : if (HasParentDirSegment(relativeFile)) {
205 3 : IDE_LOGE("relativeFile[%s] contains '..' segment.", relativeFile.c_str());
206 3 : return false;
207 : }
208 :
209 39 : const std::string filePath = Path(rootPath).Concat(relativeFile).GetString();
210 39 : const std::string baseName = Path(filePath).GetFileName();
211 :
212 39 : Path dirPath = Path(filePath).ParentPath();
213 39 : if (!dirPath.CreateDirectory(true)) {
214 0 : IDE_LOGE("create directory failed, dirPath=%s.", dirPath.GetCString());
215 0 : return false;
216 : }
217 :
218 39 : if (!dirPath.RealPath()) {
219 0 : IDE_LOGE("get real path failed, dirPath=%s.", dirPath.GetCString());
220 0 : return false;
221 : }
222 :
223 39 : if (!dirPath.IsDirectory()) {
224 0 : IDE_LOGE("path is not a directory, dirPath=%s", dirPath.GetCString());
225 0 : return false;
226 : }
227 :
228 39 : Path realRootPath(rootPath);
229 39 : if (!realRootPath.RealPath()) {
230 0 : IDE_LOGE("get real path failed, rootPath=%s.", realRootPath.GetCString());
231 0 : return false;
232 : }
233 :
234 39 : if (!IsUnderDirectory(realRootPath.GetString(), dirPath.GetString())) {
235 3 : IDE_LOGE("resolved dirPath=%s escapes rootPath=%s.", dirPath.GetCString(), realRootPath.GetCString());
236 3 : return false;
237 : }
238 :
239 36 : canonicalFile = dirPath.GetString() + DIRECTORY_SEPARATOR + baseName;
240 36 : return true;
241 39 : }
242 :
243 75 : bool Path::IsUnderDirectory(const std::string &realDirPath, const std::string &realSubPath)
244 : {
245 75 : if (realDirPath.empty() || realSubPath.empty()) {
246 6 : return false;
247 : }
248 :
249 : // Both paths are already canonical, so a segment-aware prefix match is sufficient.
250 69 : std::string prefix = realDirPath;
251 69 : if (prefix.back() != DIRECTORY_SEPARATOR) {
252 54 : prefix += DIRECTORY_SEPARATOR;
253 : }
254 :
255 69 : std::string target = realSubPath;
256 69 : if (target.back() != DIRECTORY_SEPARATOR) {
257 66 : target += DIRECTORY_SEPARATOR;
258 : }
259 :
260 69 : return target.compare(0, prefix.size(), prefix) == 0;
261 69 : }
262 :
263 1009 : void Path::AppendPath(const std::string &path)
264 : {
265 1009 : std::string newPath = StrUtils::Trim(path);
266 1009 : (void)newPath.erase(newPath.begin(),
267 1182 : std::find_if(newPath.begin(), newPath.end(), [](uint8_t ch) { return ch != DIRECTORY_SEPARATOR; }));
268 1009 : (void)newPath.erase(std::find_if(newPath.rbegin(), newPath.rend(),
269 1123 : [](uint8_t ch) {
270 1123 : return ch != DIRECTORY_SEPARATOR;
271 : }).base(),
272 : newPath.end());
273 1009 : path_ += newPath;
274 1009 : }
275 :
276 1645 : void Path::AddSeperator()
277 : {
278 1645 : if (!path_.empty() && path_.back() != DIRECTORY_SEPARATOR) {
279 1337 : path_ += DIRECTORY_SEPARATOR;
280 : }
281 1645 : }
282 : } // namespace Adx
|