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