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 8.9 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  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 <utility>
  23. #include "./securec.h"
  24. #include "utils/ms_utils.h"
  25. #include "minddata/dataset/util/log_adapter.h"
  26. namespace mindspore {
  27. namespace dataset {
  28. #if defined(_WIN32) || defined(_WIN64)
  29. char Path::separator_ = '\\';
  30. #else
  31. char Path::separator_ = '/';
  32. #endif
  33. Path::Path(const std::string &s) : path_(s) {}
  34. Path::Path(const char *p) : path_(p) {}
  35. Path::Path(const Path &p) : path_(p.path_) {}
  36. Path &Path::operator=(const Path &p) {
  37. if (&p != this) {
  38. this->path_ = p.path_;
  39. }
  40. return *this;
  41. }
  42. Path &Path::operator=(Path &&p) noexcept {
  43. if (&p != this) {
  44. this->path_ = std::move(p.path_);
  45. }
  46. return *this;
  47. }
  48. Path::Path(Path &&p) noexcept { this->path_ = std::move(p.path_); }
  49. Path Path::operator+(const Path &p) {
  50. std::string q = path_ + p.toString();
  51. return Path(q);
  52. }
  53. Path Path::operator+(const std::string &p) {
  54. std::string q = path_ + p;
  55. return Path(q);
  56. }
  57. Path Path::operator+(const char *p) {
  58. std::string q = path_ + p;
  59. return Path(q);
  60. }
  61. Path &Path::operator+=(const Path &rhs) {
  62. path_ += rhs.toString();
  63. return *this;
  64. }
  65. Path &Path::operator+=(const std::string &p) {
  66. path_ += p;
  67. return *this;
  68. }
  69. Path &Path::operator+=(const char *p) {
  70. path_ += p;
  71. return *this;
  72. }
  73. Path Path::operator/(const Path &p) {
  74. std::string q = path_ + separator_ + p.toString();
  75. return Path(q);
  76. }
  77. Path Path::operator/(const std::string &p) {
  78. std::string q = path_ + separator_ + p;
  79. return Path(q);
  80. }
  81. Path Path::operator/(const char *p) {
  82. std::string q = path_ + separator_ + p;
  83. return Path(q);
  84. }
  85. std::string Path::Extension() const {
  86. std::size_t found = path_.find_last_of('.');
  87. if (found != std::string::npos) {
  88. return path_.substr(found);
  89. } else {
  90. return std::string("");
  91. }
  92. }
  93. bool Path::Exists() {
  94. struct stat sb;
  95. int rc = stat(common::SafeCStr(path_), &sb);
  96. if (rc == -1 && errno != ENOENT) {
  97. MS_LOG(WARNING) << "Unable to query the status of " << path_ << ". Errno = " << errno << ".";
  98. }
  99. return (rc == 0);
  100. }
  101. bool Path::IsDirectory() {
  102. struct stat sb;
  103. int rc = stat(common::SafeCStr(path_), &sb);
  104. if (rc == 0) {
  105. return S_ISDIR(sb.st_mode);
  106. } else {
  107. return false;
  108. }
  109. }
  110. Status Path::CreateDirectory(bool is_common_dir) {
  111. if (!Exists()) {
  112. #if defined(_WIN32) || defined(_WIN64)
  113. int rc = mkdir(common::SafeCStr(path_));
  114. #else
  115. int rc = mkdir(common::SafeCStr(path_), S_IRUSR | S_IWUSR | S_IXUSR);
  116. if (rc == 0 && is_common_dir) {
  117. rc = chmod(common::SafeCStr(path_), S_IRWXU | S_IRWXG | S_IRWXO);
  118. }
  119. #endif
  120. if (rc) {
  121. std::ostringstream oss;
  122. oss << "Unable to create directory " << path_ << ". Errno = " << errno;
  123. RETURN_STATUS_UNEXPECTED(oss.str());
  124. }
  125. return Status::OK();
  126. } else {
  127. if (IsDirectory()) {
  128. return Status::OK();
  129. } else {
  130. std::ostringstream oss;
  131. oss << "Unable to create directory " << path_ << ". It exists but is not a directory";
  132. RETURN_STATUS_UNEXPECTED(oss.str());
  133. }
  134. }
  135. }
  136. std::string Path::ParentPath() {
  137. std::string r("");
  138. std::size_t found = path_.find_last_of(separator_);
  139. if (found != std::string::npos) {
  140. if (found == 0) {
  141. r += separator_;
  142. } else {
  143. r = std::string(path_.substr(0, found));
  144. }
  145. }
  146. return r;
  147. }
  148. Status Path::CreateDirectories(bool is_common_dir) {
  149. if (IsDirectory()) {
  150. MS_LOG(DEBUG) << "Directory " << toString() << " already exists.";
  151. return Status::OK();
  152. } else {
  153. MS_LOG(DEBUG) << "Creating directory " << toString() << ".";
  154. std::string parent = ParentPath();
  155. if (!parent.empty()) {
  156. if (Path(parent).CreateDirectories(is_common_dir)) {
  157. return CreateDirectory(is_common_dir);
  158. }
  159. } else {
  160. return CreateDirectory(is_common_dir);
  161. }
  162. }
  163. return Status::OK();
  164. }
  165. Status Path::CreateCommonDirectories() { return CreateDirectories(true); }
  166. Status Path::Remove() {
  167. if (Exists()) {
  168. if (IsDirectory()) {
  169. errno_t err = rmdir(common::SafeCStr(path_));
  170. if (err == -1) {
  171. std::ostringstream oss;
  172. oss << "Unable to delete directory " << path_ << ". Errno = " << errno;
  173. RETURN_STATUS_UNEXPECTED(oss.str());
  174. }
  175. } else {
  176. errno_t err = unlink(common::SafeCStr(path_));
  177. if (err == -1) {
  178. std::ostringstream oss;
  179. oss << "Unable to delete file " << path_ << ". Errno = " << errno;
  180. RETURN_STATUS_UNEXPECTED(oss.str());
  181. }
  182. }
  183. }
  184. return Status::OK();
  185. }
  186. Status Path::CreateFile(int *file_descriptor) { return OpenFile(file_descriptor, true); }
  187. Status Path::OpenFile(int *file_descriptor, bool create) {
  188. int fd;
  189. if (file_descriptor == nullptr) {
  190. RETURN_STATUS_UNEXPECTED("null pointer");
  191. }
  192. if (IsDirectory()) {
  193. std::ostringstream oss;
  194. oss << "Unable to create file " << path_ << " which is a directory.";
  195. RETURN_STATUS_UNEXPECTED(oss.str());
  196. }
  197. // Convert to canonical form.
  198. if (strlen(common::SafeCStr(path_)) > PATH_MAX) {
  199. RETURN_STATUS_UNEXPECTED(strerror(errno));
  200. }
  201. char canonical_path[PATH_MAX + 1] = {0x00};
  202. #if defined(_WIN32) || defined(_WIN64)
  203. auto err = _fullpath(canonical_path, common::SafeCStr(path_), PATH_MAX);
  204. #else
  205. auto err = realpath(common::SafeCStr(path_), canonical_path);
  206. #endif
  207. if (err == nullptr) {
  208. if (errno == ENOENT && create) {
  209. // File doesn't exist and we are to create it. Let's break it down.
  210. auto file_part = Basename();
  211. auto parent_part = ParentPath();
  212. #if defined(_WIN32) || defined(_WIN64)
  213. auto parent_err = _fullpath(canonical_path, common::SafeCStr(parent_part), PATH_MAX);
  214. #else
  215. auto parent_err = realpath(common::SafeCStr(parent_part), canonical_path);
  216. #endif
  217. if (parent_err == nullptr) {
  218. RETURN_STATUS_UNEXPECTED(strerror(errno));
  219. }
  220. auto cur_inx = strlen(canonical_path);
  221. if ((cur_inx + file_part.length() + 1) > PATH_MAX) {
  222. RETURN_STATUS_UNEXPECTED(strerror(errno));
  223. }
  224. canonical_path[cur_inx++] = separator_;
  225. if (strncpy_s(canonical_path + cur_inx, PATH_MAX - cur_inx, common::SafeCStr(file_part), file_part.length()) !=
  226. EOK) {
  227. RETURN_STATUS_UNEXPECTED(strerror(errno));
  228. }
  229. } else {
  230. RETURN_STATUS_UNEXPECTED(strerror(errno));
  231. }
  232. }
  233. if (create) {
  234. fd = open(canonical_path, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
  235. } else {
  236. fd = open(canonical_path, O_RDWR);
  237. }
  238. if (fd == -1) {
  239. RETURN_STATUS_UNEXPECTED(strerror(errno));
  240. }
  241. *file_descriptor = fd;
  242. return Status::OK();
  243. }
  244. Status Path::CloseFile(int fd) const {
  245. if (close(fd) < 0) {
  246. RETURN_STATUS_UNEXPECTED(strerror(errno));
  247. }
  248. return Status::OK();
  249. }
  250. Status Path::TruncateFile(int fd) const {
  251. int rc;
  252. rc = ftruncate(fd, 0);
  253. if (rc == 0) {
  254. return Status::OK();
  255. } else {
  256. RETURN_STATUS_UNEXPECTED(strerror(errno));
  257. }
  258. }
  259. std::string Path::Basename() {
  260. std::size_t found = path_.find_last_of(separator_);
  261. if (found != std::string::npos) {
  262. return path_.substr(found + 1);
  263. } else {
  264. return path_;
  265. }
  266. }
  267. std::shared_ptr<Path::DirIterator> Path::DirIterator::OpenDirectory(Path *f) {
  268. auto it = new (std::nothrow) DirIterator(f);
  269. if (it == nullptr) {
  270. return nullptr;
  271. }
  272. if (it->dp_) {
  273. return std::shared_ptr<DirIterator>(it);
  274. } else {
  275. delete it;
  276. return nullptr;
  277. }
  278. }
  279. Path::DirIterator::~DirIterator() {
  280. if (dp_) {
  281. (void)closedir(dp_);
  282. }
  283. dp_ = nullptr;
  284. dir_ = nullptr;
  285. entry_ = nullptr;
  286. }
  287. Path::DirIterator::DirIterator(Path *f) : dir_(f), dp_(nullptr), entry_(nullptr) {
  288. MS_LOG(DEBUG) << "Open directory " << f->toString() << ".";
  289. dp_ = opendir(f->toString().c_str());
  290. }
  291. bool Path::DirIterator::hasNext() {
  292. do {
  293. entry_ = readdir(dp_);
  294. if (entry_) {
  295. if (strcmp(entry_->d_name, ".") == 0 || strcmp(entry_->d_name, "..") == 0) {
  296. continue;
  297. }
  298. }
  299. break;
  300. } while (true);
  301. return (entry_ != nullptr);
  302. }
  303. Path Path::DirIterator::next() { return (*(this->dir_) / Path(entry_->d_name)); }
  304. std::ostream &operator<<(std::ostream &os, const Path &s) {
  305. os << s.path_;
  306. return os;
  307. }
  308. } // namespace dataset
  309. } // namespace mindspore