1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 
16 #include <sys/stat.h>
17 #include <algorithm>
18 #include <deque>
19 
20 #include "tensorflow/core/lib/core/errors.h"
21 #include "tensorflow/core/lib/io/path.h"
22 #include "tensorflow/core/lib/strings/str_util.h"
23 #include "tensorflow/core/lib/strings/strcat.h"
24 #include "tensorflow/core/platform/env.h"
25 #include "tensorflow/core/platform/file_system.h"
26 #include "tensorflow/core/platform/platform.h"
27 
28 namespace tensorflow {
29 
~FileSystem()30 FileSystem::~FileSystem() {}
31 
TranslateName(const string & name) const32 string FileSystem::TranslateName(const string& name) const {
33   // If the name is empty, CleanPath returns "." which is incorrect and
34   // we should return the empty path instead.
35   if (name.empty()) return name;
36   return io::CleanPath(name);
37 }
38 
IsDirectory(const string & name)39 Status FileSystem::IsDirectory(const string& name) {
40   // Check if path exists.
41   TF_RETURN_IF_ERROR(FileExists(name));
42   FileStatistics stat;
43   TF_RETURN_IF_ERROR(Stat(name, &stat));
44   if (stat.is_directory) {
45     return Status::OK();
46   }
47   return Status(tensorflow::error::FAILED_PRECONDITION, "Not a directory");
48 }
49 
FlushCaches()50 void FileSystem::FlushCaches() {}
51 
~RandomAccessFile()52 RandomAccessFile::~RandomAccessFile() {}
53 
~WritableFile()54 WritableFile::~WritableFile() {}
55 
~FileSystemRegistry()56 FileSystemRegistry::~FileSystemRegistry() {}
57 
FilesExist(const std::vector<string> & files,std::vector<Status> * status)58 bool FileSystem::FilesExist(const std::vector<string>& files,
59                             std::vector<Status>* status) {
60   bool result = true;
61   for (const auto& file : files) {
62     Status s = FileExists(file);
63     result &= s.ok();
64     if (status != nullptr) {
65       status->push_back(s);
66     } else if (!result) {
67       // Return early since there is no need to check other files.
68       return false;
69     }
70   }
71   return result;
72 }
73 
DeleteRecursively(const string & dirname,int64 * undeleted_files,int64 * undeleted_dirs)74 Status FileSystem::DeleteRecursively(const string& dirname,
75                                      int64* undeleted_files,
76                                      int64* undeleted_dirs) {
77   CHECK_NOTNULL(undeleted_files);
78   CHECK_NOTNULL(undeleted_dirs);
79 
80   *undeleted_files = 0;
81   *undeleted_dirs = 0;
82   // Make sure that dirname exists;
83   Status exists_status = FileExists(dirname);
84   if (!exists_status.ok()) {
85     (*undeleted_dirs)++;
86     return exists_status;
87   }
88   std::deque<string> dir_q;      // Queue for the BFS
89   std::vector<string> dir_list;  // List of all dirs discovered
90   dir_q.push_back(dirname);
91   Status ret;  // Status to be returned.
92   // Do a BFS on the directory to discover all the sub-directories. Remove all
93   // children that are files along the way. Then cleanup and remove the
94   // directories in reverse order.;
95   while (!dir_q.empty()) {
96     string dir = dir_q.front();
97     dir_q.pop_front();
98     dir_list.push_back(dir);
99     std::vector<string> children;
100     // GetChildren might fail if we don't have appropriate permissions.
101     Status s = GetChildren(dir, &children);
102     ret.Update(s);
103     if (!s.ok()) {
104       (*undeleted_dirs)++;
105       continue;
106     }
107     for (const string& child : children) {
108       const string child_path = io::JoinPath(dir, child);
109       // If the child is a directory add it to the queue, otherwise delete it.
110       if (IsDirectory(child_path).ok()) {
111         dir_q.push_back(child_path);
112       } else {
113         // Delete file might fail because of permissions issues or might be
114         // unimplemented.
115         Status del_status = DeleteFile(child_path);
116         ret.Update(del_status);
117         if (!del_status.ok()) {
118           (*undeleted_files)++;
119         }
120       }
121     }
122   }
123   // Now reverse the list of directories and delete them. The BFS ensures that
124   // we can delete the directories in this order.
125   std::reverse(dir_list.begin(), dir_list.end());
126   for (const string& dir : dir_list) {
127     // Delete dir might fail because of permissions issues or might be
128     // unimplemented.
129     Status s = DeleteDir(dir);
130     ret.Update(s);
131     if (!s.ok()) {
132       (*undeleted_dirs)++;
133     }
134   }
135   return ret;
136 }
137 
RecursivelyCreateDir(const string & dirname)138 Status FileSystem::RecursivelyCreateDir(const string& dirname) {
139   StringPiece scheme, host, remaining_dir;
140   io::ParseURI(dirname, &scheme, &host, &remaining_dir);
141   std::vector<StringPiece> sub_dirs;
142   while (!remaining_dir.empty()) {
143     Status status = FileExists(io::CreateURI(scheme, host, remaining_dir));
144     if (status.ok()) {
145       break;
146     }
147     if (status.code() != error::Code::NOT_FOUND) {
148       return status;
149     }
150     // Basename returns "" for / ending dirs.
151     if (!str_util::EndsWith(remaining_dir, "/")) {
152       sub_dirs.push_back(io::Basename(remaining_dir));
153     }
154     remaining_dir = io::Dirname(remaining_dir);
155   }
156 
157   // sub_dirs contains all the dirs to be created but in reverse order.
158   std::reverse(sub_dirs.begin(), sub_dirs.end());
159 
160   // Now create the directories.
161   string built_path(remaining_dir);
162   for (const StringPiece sub_dir : sub_dirs) {
163     built_path = io::JoinPath(built_path, sub_dir);
164     Status status = CreateDir(io::CreateURI(scheme, host, built_path));
165     if (!status.ok() && status.code() != tensorflow::error::ALREADY_EXISTS) {
166       return status;
167     }
168   }
169   return Status::OK();
170 }
171 
CopyFile(const string & src,const string & target)172 Status FileSystem::CopyFile(const string& src, const string& target) {
173   return FileSystemCopyFile(this, src, this, target);
174 }
175 
176 }  // namespace tensorflow
177