1 //===-- FileSystem.cpp ------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/Host/FileSystem.h"
11 
12 #include "lldb/Utility/LLDBAssert.h"
13 #include "lldb/Utility/TildeExpressionResolver.h"
14 
15 #include "llvm/Support/FileSystem.h"
16 #include "llvm/Support/Path.h"
17 #include "llvm/Support/Program.h"
18 #include "llvm/Support/Threading.h"
19 
20 #include <algorithm>
21 #include <fstream>
22 #include <vector>
23 
24 using namespace lldb;
25 using namespace lldb_private;
26 using namespace llvm;
27 
28 FileSystem &FileSystem::Instance() { return *InstanceImpl(); }
29 
30 void FileSystem::Initialize() {
31   lldbassert(!InstanceImpl() && "Already initialized.");
32   InstanceImpl().emplace();
33 }
34 
35 void FileSystem::Initialize(IntrusiveRefCntPtr<vfs::FileSystem> fs) {
36   lldbassert(!InstanceImpl() && "Already initialized.");
37   InstanceImpl().emplace(fs);
38 }
39 
40 void FileSystem::Terminate() {
41   lldbassert(InstanceImpl() && "Already terminated.");
42   InstanceImpl().reset();
43 }
44 
45 Optional<FileSystem> &FileSystem::InstanceImpl() {
46   static Optional<FileSystem> g_fs;
47   return g_fs;
48 }
49 
50 void FileSystem::SetFileSystem(IntrusiveRefCntPtr<vfs::FileSystem> fs) {
51   m_fs = fs;
52 }
53 
54 sys::TimePoint<>
55 FileSystem::GetModificationTime(const FileSpec &file_spec) const {
56   return GetModificationTime(file_spec.GetPath());
57 }
58 
59 sys::TimePoint<> FileSystem::GetModificationTime(const Twine &path) const {
60   ErrorOr<vfs::Status> status = m_fs->status(path);
61   if (!status)
62     return sys::TimePoint<>();
63   return status->getLastModificationTime();
64 }
65 
66 uint64_t FileSystem::GetByteSize(const FileSpec &file_spec) const {
67   return GetByteSize(file_spec.GetPath());
68 }
69 
70 uint64_t FileSystem::GetByteSize(const Twine &path) const {
71   ErrorOr<vfs::Status> status = m_fs->status(path);
72   if (!status)
73     return 0;
74   return status->getSize();
75 }
76 
77 uint32_t FileSystem::GetPermissions(const FileSpec &file_spec) const {
78   return GetPermissions(file_spec.GetPath());
79 }
80 
81 uint32_t FileSystem::GetPermissions(const FileSpec &file_spec,
82                                     std::error_code &ec) const {
83   return GetPermissions(file_spec.GetPath(), ec);
84 }
85 
86 uint32_t FileSystem::GetPermissions(const Twine &path) const {
87   std::error_code ec;
88   return GetPermissions(path, ec);
89 }
90 
91 uint32_t FileSystem::GetPermissions(const Twine &path,
92                                     std::error_code &ec) const {
93   ErrorOr<vfs::Status> status = m_fs->status(path);
94   if (!status) {
95     ec = status.getError();
96     return sys::fs::perms::perms_not_known;
97   }
98   return status->getPermissions();
99 }
100 
101 bool FileSystem::Exists(const Twine &path) const { return m_fs->exists(path); }
102 
103 bool FileSystem::Exists(const FileSpec &file_spec) const {
104   return Exists(file_spec.GetPath());
105 }
106 
107 bool FileSystem::Readable(const Twine &path) const {
108   return GetPermissions(path) & sys::fs::perms::all_read;
109 }
110 
111 bool FileSystem::Readable(const FileSpec &file_spec) const {
112   return Readable(file_spec.GetPath());
113 }
114 
115 void FileSystem::EnumerateDirectory(Twine path, bool find_directories,
116                                     bool find_files, bool find_other,
117                                     EnumerateDirectoryCallbackType callback,
118                                     void *callback_baton) {
119   std::error_code EC;
120   vfs::recursive_directory_iterator Iter(*m_fs, path, EC);
121   vfs::recursive_directory_iterator End;
122   for (; Iter != End && !EC; Iter.increment(EC)) {
123     const auto &Item = *Iter;
124     ErrorOr<vfs::Status> Status = m_fs->status(Item.path());
125     if (!Status)
126       break;
127     if (!find_files && Status->isRegularFile())
128       continue;
129     if (!find_directories && Status->isDirectory())
130       continue;
131     if (!find_other && Status->isOther())
132       continue;
133 
134     auto Result = callback(callback_baton, Status->getType(), Item.path());
135     if (Result == eEnumerateDirectoryResultQuit)
136       return;
137     if (Result == eEnumerateDirectoryResultNext) {
138       // Default behavior is to recurse. Opt out if the callback doesn't want
139       // this behavior.
140       Iter.no_push();
141     }
142   }
143 }
144 
145 std::error_code FileSystem::MakeAbsolute(SmallVectorImpl<char> &path) const {
146   return m_fs->makeAbsolute(path);
147 }
148 
149 std::error_code FileSystem::MakeAbsolute(FileSpec &file_spec) const {
150   SmallString<128> path;
151   file_spec.GetPath(path, false);
152 
153   auto EC = MakeAbsolute(path);
154   if (EC)
155     return EC;
156 
157   FileSpec new_file_spec(path, file_spec.GetPathStyle());
158   file_spec = new_file_spec;
159   return {};
160 }
161 
162 std::error_code FileSystem::GetRealPath(const Twine &path,
163                                         SmallVectorImpl<char> &output) const {
164   return m_fs->getRealPath(path, output);
165 }
166 
167 void FileSystem::Resolve(SmallVectorImpl<char> &path) {
168   if (path.empty())
169     return;
170 
171   // Resolve tilde.
172   SmallString<128> original_path(path.begin(), path.end());
173   StandardTildeExpressionResolver Resolver;
174   Resolver.ResolveFullPath(original_path, path);
175 
176   // Try making the path absolute if it exists.
177   SmallString<128> absolute_path(path.begin(), path.end());
178   MakeAbsolute(path);
179   if (!Exists(path)) {
180     path.clear();
181     path.append(original_path.begin(), original_path.end());
182   }
183 }
184 
185 void FileSystem::Resolve(FileSpec &file_spec) {
186   // Extract path from the FileSpec.
187   SmallString<128> path;
188   file_spec.GetPath(path);
189 
190   // Resolve the path.
191   Resolve(path);
192 
193   // Update the FileSpec with the resolved path.
194   file_spec.SetPath(path);
195   file_spec.SetIsResolved(true);
196 }
197 
198 bool FileSystem::ResolveExecutableLocation(FileSpec &file_spec) {
199   // If the directory is set there's nothing to do.
200   const ConstString &directory = file_spec.GetDirectory();
201   if (directory)
202     return false;
203 
204   // We cannot look for a file if there's no file name.
205   const ConstString &filename = file_spec.GetFilename();
206   if (!filename)
207     return false;
208 
209   // Search for the file on the host.
210   const std::string filename_str(filename.GetCString());
211   llvm::ErrorOr<std::string> error_or_path =
212       llvm::sys::findProgramByName(filename_str);
213   if (!error_or_path)
214     return false;
215 
216   // findProgramByName returns "." if it can't find the file.
217   llvm::StringRef path = *error_or_path;
218   llvm::StringRef parent = llvm::sys::path::parent_path(path);
219   if (parent.empty() || parent == ".")
220     return false;
221 
222   // Make sure that the result exists.
223   FileSpec result(*error_or_path);
224   if (!Exists(result))
225     return false;
226 
227   file_spec = result;
228   return true;
229 }
230