You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

path.cc 9.8 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. /**
  2. * Copyright 2019 Huawei Technologies Co., Ltd
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "minddata/dataset/util/path.h"
  17. #include <sys/stat.h>
  18. #include <fcntl.h>
  19. #include <unistd.h>
  20. #include <new>
  21. #include <sstream>
  22. #include "./securec.h"
  23. #include "utils/ms_utils.h"
  24. #include "minddata/dataset/util/log_adapter.h"
  25. namespace mindspore {
  26. namespace dataset {
  27. #if defined(_WIN32) || defined(_WIN64)
  28. char Path::separator_ = '\\';
  29. #else
  30. char Path::separator_ = '/';
  31. #endif
  32. Path::Path(const std::string &s) : path_(s) {}
  33. Path::Path(const char *p) : path_(p) {}
  34. Path::Path(const Path &p) : path_(p.path_) {}
  35. Path &Path::operator=(const Path &p) {
  36. if (&p != this) {
  37. this->path_ = p.path_;
  38. }
  39. return *this;
  40. }
  41. Path &Path::operator=(Path &&p) noexcept {
  42. if (&p != this) {
  43. this->path_ = std::move(p.path_);
  44. }
  45. return *this;
  46. }
  47. Path::Path(Path &&p) noexcept { this->path_ = std::move(p.path_); }
  48. Path Path::operator+(const Path &p) {
  49. std::string q = path_ + p.ToString();
  50. return Path(q);
  51. }
  52. Path Path::operator+(const std::string &p) {
  53. std::string q = path_ + p;
  54. return Path(q);
  55. }
  56. Path Path::operator+(const char *p) {
  57. std::string q = path_ + p;
  58. return Path(q);
  59. }
  60. Path &Path::operator+=(const Path &rhs) {
  61. path_ += rhs.ToString();
  62. return *this;
  63. }
  64. Path &Path::operator+=(const std::string &p) {
  65. path_ += p;
  66. return *this;
  67. }
  68. Path &Path::operator+=(const char *p) {
  69. path_ += p;
  70. return *this;
  71. }
  72. Path Path::operator/(const Path &p) {
  73. std::string q = path_ + separator_ + p.ToString();
  74. return Path(q);
  75. }
  76. Path Path::operator/(const std::string &p) {
  77. std::string q = path_ + separator_ + p;
  78. return Path(q);
  79. }
  80. Path Path::operator/(const char *p) {
  81. std::string q = path_ + separator_ + p;
  82. return Path(q);
  83. }
  84. std::string Path::Extension() const {
  85. std::size_t found = path_.find_last_of('.');
  86. if (found != std::string::npos) {
  87. return path_.substr(found);
  88. } else {
  89. return std::string("");
  90. }
  91. }
  92. bool Path::Exists() {
  93. struct stat sb;
  94. int rc = stat(common::SafeCStr(path_), &sb);
  95. if (rc == -1 && errno != ENOENT) {
  96. MS_LOG(WARNING) << "Unable to query the status of " << path_ << ". Errno = " << errno << ".";
  97. }
  98. return (rc == 0);
  99. }
  100. bool Path::IsDirectory() {
  101. struct stat sb;
  102. int rc = stat(common::SafeCStr(path_), &sb);
  103. if (rc == 0) {
  104. return S_ISDIR(sb.st_mode);
  105. } else {
  106. return false;
  107. }
  108. }
  109. Status Path::CreateDirectory(bool is_common_dir) {
  110. if (!Exists()) {
  111. #if defined(_WIN32) || defined(_WIN64)
  112. int rc = mkdir(common::SafeCStr(path_));
  113. #else
  114. int rc = mkdir(common::SafeCStr(path_), S_IRUSR | S_IWUSR | S_IXUSR);
  115. if (rc == 0 && is_common_dir) {
  116. rc = chmod(common::SafeCStr(path_), S_IRWXU | S_IRWXG | S_IRWXO);
  117. }
  118. #endif
  119. if (rc) {
  120. std::ostringstream oss;
  121. oss << "Unable to create directory " << path_ << ". Errno = " << errno;
  122. RETURN_STATUS_UNEXPECTED(oss.str());
  123. }
  124. return Status::OK();
  125. } else {
  126. if (IsDirectory()) {
  127. return Status::OK();
  128. } else {
  129. std::ostringstream oss;
  130. oss << "Unable to create directory " << path_ << ". It exists but is not a directory";
  131. RETURN_STATUS_UNEXPECTED(oss.str());
  132. }
  133. }
  134. }
  135. std::string Path::ParentPath() {
  136. std::string r("");
  137. std::size_t found = path_.find_last_of(separator_);
  138. if (found != std::string::npos) {
  139. if (found == 0) {
  140. r += separator_;
  141. } else {
  142. r = std::string(path_.substr(0, found));
  143. }
  144. }
  145. return r;
  146. }
  147. Status Path::CreateDirectories(bool is_common_dir) {
  148. if (IsDirectory()) {
  149. MS_LOG(DEBUG) << "Directory " << ToString() << " already exists.";
  150. return Status::OK();
  151. } else {
  152. MS_LOG(DEBUG) << "Creating directory " << ToString() << ".";
  153. std::string parent = ParentPath();
  154. if (!parent.empty()) {
  155. if (Path(parent).CreateDirectories(is_common_dir)) {
  156. return CreateDirectory(is_common_dir);
  157. }
  158. } else {
  159. return CreateDirectory(is_common_dir);
  160. }
  161. }
  162. return Status::OK();
  163. }
  164. Status Path::CreateCommonDirectories() { return CreateDirectories(true); }
  165. Status Path::Remove() {
  166. if (Exists()) {
  167. if (IsDirectory()) {
  168. errno_t err = rmdir(common::SafeCStr(path_));
  169. if (err == -1) {
  170. std::ostringstream oss;
  171. oss << "Unable to delete directory " << path_ << ". Errno = " << errno;
  172. RETURN_STATUS_UNEXPECTED(oss.str());
  173. }
  174. } else {
  175. errno_t err = unlink(common::SafeCStr(path_));
  176. if (err == -1) {
  177. std::ostringstream oss;
  178. oss << "Unable to delete file " << path_ << ". Errno = " << errno;
  179. RETURN_STATUS_UNEXPECTED(oss.str());
  180. }
  181. }
  182. }
  183. return Status::OK();
  184. }
  185. Status Path::CreateFile(int *file_descriptor) { return OpenFile(file_descriptor, true); }
  186. Status Path::OpenFile(int *file_descriptor, bool create) {
  187. int fd;
  188. if (file_descriptor == nullptr) {
  189. RETURN_STATUS_UNEXPECTED("null pointer");
  190. }
  191. if (IsDirectory()) {
  192. std::ostringstream oss;
  193. oss << "Unable to create file " << path_ << " which is a directory.";
  194. RETURN_STATUS_UNEXPECTED(oss.str());
  195. }
  196. // Convert to canonical form.
  197. if (strlen(common::SafeCStr(path_)) >= PATH_MAX) {
  198. RETURN_STATUS_UNEXPECTED(strerror(errno));
  199. }
  200. char canonical_path[PATH_MAX] = {0x00};
  201. #if defined(_WIN32) || defined(_WIN64)
  202. auto err = _fullpath(canonical_path, common::SafeCStr(path_), PATH_MAX);
  203. #else
  204. auto err = realpath(common::SafeCStr(path_), canonical_path);
  205. #endif
  206. if (err == nullptr) {
  207. if (errno == ENOENT && create) {
  208. // File doesn't exist and we are to create it. Let's break it down.
  209. auto file_part = Basename();
  210. auto parent_part = ParentPath();
  211. #if defined(_WIN32) || defined(_WIN64)
  212. auto parent_err = _fullpath(canonical_path, common::SafeCStr(parent_part), PATH_MAX);
  213. #else
  214. auto parent_err = realpath(common::SafeCStr(parent_part), canonical_path);
  215. #endif
  216. if (parent_err == nullptr) {
  217. RETURN_STATUS_UNEXPECTED(strerror(errno));
  218. }
  219. auto cur_inx = strlen(canonical_path);
  220. if (cur_inx + file_part.length() >= PATH_MAX) {
  221. RETURN_STATUS_UNEXPECTED(strerror(errno));
  222. }
  223. canonical_path[cur_inx++] = separator_;
  224. if (strncpy_s(canonical_path + cur_inx, PATH_MAX - cur_inx, common::SafeCStr(file_part), file_part.length()) !=
  225. EOK) {
  226. RETURN_STATUS_UNEXPECTED(strerror(errno));
  227. }
  228. } else {
  229. RETURN_STATUS_UNEXPECTED(strerror(errno));
  230. }
  231. }
  232. if (create) {
  233. fd = open(canonical_path, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
  234. } else {
  235. fd = open(canonical_path, O_RDWR);
  236. }
  237. if (fd == -1) {
  238. RETURN_STATUS_UNEXPECTED(strerror(errno));
  239. }
  240. *file_descriptor = fd;
  241. return Status::OK();
  242. }
  243. Status Path::CloseFile(int fd) const {
  244. if (close(fd) < 0) {
  245. RETURN_STATUS_UNEXPECTED(strerror(errno));
  246. }
  247. return Status::OK();
  248. }
  249. Status Path::TruncateFile(int fd) const {
  250. int rc = ftruncate(fd, 0);
  251. if (rc == 0) {
  252. return Status::OK();
  253. } else {
  254. RETURN_STATUS_UNEXPECTED(strerror(errno));
  255. }
  256. }
  257. std::string Path::Basename() {
  258. std::size_t found = path_.find_last_of(separator_);
  259. if (found != std::string::npos) {
  260. return path_.substr(found + 1);
  261. } else {
  262. return path_;
  263. }
  264. }
  265. std::shared_ptr<Path::DirIterator> Path::DirIterator::OpenDirectory(Path *f) {
  266. auto it = new (std::nothrow) DirIterator(f);
  267. if (it == nullptr) {
  268. return nullptr;
  269. }
  270. if (it->dp_) {
  271. return std::shared_ptr<DirIterator>(it);
  272. } else {
  273. delete it;
  274. return nullptr;
  275. }
  276. }
  277. Path::DirIterator::~DirIterator() {
  278. if (dp_) {
  279. (void)closedir(dp_);
  280. }
  281. dp_ = nullptr;
  282. dir_ = nullptr;
  283. entry_ = nullptr;
  284. }
  285. Path::DirIterator::DirIterator(Path *f) : dir_(f), dp_(nullptr), entry_(nullptr) {
  286. MS_LOG(DEBUG) << "Open directory " << f->ToString() << ".";
  287. dp_ = opendir(f->ToString().c_str());
  288. }
  289. bool Path::DirIterator::HasNext() {
  290. do {
  291. entry_ = readdir(dp_);
  292. if (entry_) {
  293. if (strcmp(entry_->d_name, ".") == 0 || strcmp(entry_->d_name, "..") == 0) {
  294. continue;
  295. }
  296. }
  297. break;
  298. } while (true);
  299. return (entry_ != nullptr);
  300. }
  301. Path Path::DirIterator::Next() { return (*(this->dir_) / Path(entry_->d_name)); }
  302. Status Path::RealPath(const std::string &path, std::string &realpath_str) {
  303. char real_path[PATH_MAX] = {0};
  304. // input_path is only file_name
  305. #if defined(_WIN32) || defined(_WIN64)
  306. CHECK_FAIL_RETURN_UNEXPECTED(path.length() < PATH_MAX,
  307. "The length of path: " + path + " exceeds limit: " + std::to_string(PATH_MAX));
  308. auto ret = _fullpath(real_path, common::SafeCStr(path), PATH_MAX);
  309. CHECK_FAIL_RETURN_UNEXPECTED(ret != nullptr, "The file " + path + " does not exist.");
  310. #else
  311. CHECK_FAIL_RETURN_UNEXPECTED(path.length() < NAME_MAX,
  312. "The length of path: " + path + " exceeds limit: " + std::to_string(NAME_MAX));
  313. auto ret = realpath(common::SafeCStr(path), real_path);
  314. CHECK_FAIL_RETURN_UNEXPECTED(ret != nullptr, "The file " + path + " does not exist.");
  315. #endif
  316. realpath_str = std::string(real_path);
  317. return Status::OK();
  318. }
  319. std::ostream &operator<<(std::ostream &os, const Path &s) {
  320. os << s.path_;
  321. return os;
  322. }
  323. } // namespace dataset
  324. } // namespace mindspore