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/TildeExpressionResolver.h"
13 
14 #include "llvm/Support/FileSystem.h"
15 #include "llvm/Support/Threading.h"
16 
17 #include <algorithm>
18 #include <fstream>
19 #include <vector>
20 
21 using namespace lldb;
22 using namespace lldb_private;
23 using namespace llvm;
24 
25 FileSystem &FileSystem::Instance() { return *InstanceImpl(); }
26 
27 void FileSystem::Initialize() {
28   assert(!InstanceImpl());
29   InstanceImpl().emplace();
30 }
31 
32 void FileSystem::Initialize(IntrusiveRefCntPtr<vfs::FileSystem> fs) {
33   assert(!InstanceImpl());
34   InstanceImpl().emplace(fs);
35 }
36 
37 void FileSystem::Terminate() {
38   assert(InstanceImpl());
39   InstanceImpl().reset();
40 }
41 
42 Optional<FileSystem> &FileSystem::InstanceImpl() {
43   static Optional<FileSystem> g_fs;
44   return g_fs;
45 }
46 
47 void FileSystem::SetFileSystem(IntrusiveRefCntPtr<vfs::FileSystem> fs) {
48   m_fs = fs;
49 }
50 
51 sys::TimePoint<>
52 FileSystem::GetModificationTime(const FileSpec &file_spec) const {
53   return GetModificationTime(file_spec.GetPath());
54 }
55 
56 sys::TimePoint<> FileSystem::GetModificationTime(const Twine &path) const {
57   ErrorOr<vfs::Status> status = m_fs->status(path);
58   if (!status)
59     return sys::TimePoint<>();
60   return status->getLastModificationTime();
61 }
62 
63 uint64_t FileSystem::GetByteSize(const FileSpec &file_spec) const {
64   return GetByteSize(file_spec.GetPath());
65 }
66 
67 uint64_t FileSystem::GetByteSize(const Twine &path) const {
68   ErrorOr<vfs::Status> status = m_fs->status(path);
69   if (!status)
70     return 0;
71   return status->getSize();
72 }
73 
74 uint32_t FileSystem::GetPermissions(const FileSpec &file_spec) const {
75   return GetPermissions(file_spec.GetPath());
76 }
77 
78 uint32_t FileSystem::GetPermissions(const Twine &path) const {
79   ErrorOr<vfs::Status> status = m_fs->status(path);
80   if (!status)
81     return sys::fs::perms::perms_not_known;
82   return status->getPermissions();
83 }
84 
85 bool FileSystem::Exists(const Twine &path) const { return m_fs->exists(path); }
86 
87 bool FileSystem::Exists(const FileSpec &file_spec) const {
88   return Exists(file_spec.GetPath());
89 }
90 
91 bool FileSystem::Readable(const Twine &path) const {
92   return GetPermissions(path) & sys::fs::perms::all_read;
93 }
94 
95 bool FileSystem::Readable(const FileSpec &file_spec) const {
96   return Readable(file_spec.GetPath());
97 }
98 
99 void FileSystem::EnumerateDirectory(Twine path, bool find_directories,
100                                     bool find_files, bool find_other,
101                                     EnumerateDirectoryCallbackType callback,
102                                     void *callback_baton) {
103   std::error_code EC;
104   vfs::recursive_directory_iterator Iter(*m_fs, path, EC);
105   vfs::recursive_directory_iterator End;
106   for (; Iter != End && !EC; Iter.increment(EC)) {
107     const auto &Item = *Iter;
108     ErrorOr<vfs::Status> Status = m_fs->status(Item.path());
109     if (!Status)
110       break;
111     if (!find_files && Status->isRegularFile())
112       continue;
113     if (!find_directories && Status->isDirectory())
114       continue;
115     if (!find_other && Status->isOther())
116       continue;
117 
118     auto Result = callback(callback_baton, Status->getType(), Item.path());
119     if (Result == eEnumerateDirectoryResultQuit)
120       return;
121     if (Result == eEnumerateDirectoryResultNext) {
122       // Default behavior is to recurse. Opt out if the callback doesn't want
123       // this behavior.
124       Iter.no_push();
125     }
126   }
127 }
128 
129 std::error_code FileSystem::MakeAbsolute(SmallVectorImpl<char> &path) const {
130   return m_fs->makeAbsolute(path);
131 }
132 
133 std::error_code FileSystem::MakeAbsolute(FileSpec &file_spec) const {
134   SmallString<128> path;
135   file_spec.GetPath(path, false);
136 
137   auto EC = MakeAbsolute(path);
138   if (EC)
139     return EC;
140 
141   FileSpec new_file_spec(path, false, file_spec.GetPathStyle());
142   file_spec = new_file_spec;
143   return {};
144 }
145 
146 std::error_code FileSystem::GetRealPath(const Twine &path,
147                                         SmallVectorImpl<char> &output) const {
148   return m_fs->getRealPath(path, output);
149 }
150 
151 void FileSystem::Resolve(SmallVectorImpl<char> &path) {
152   if (path.empty())
153     return;
154 
155   // Resolve tilde.
156   SmallString<128> original_path(path.begin(), path.end());
157   StandardTildeExpressionResolver Resolver;
158   Resolver.ResolveFullPath(original_path, path);
159 
160   // Try making the path absolute if it exists.
161   SmallString<128> absolute_path(path.begin(), path.end());
162   MakeAbsolute(path);
163   if (!Exists(path)) {
164     path.clear();
165     path.append(original_path.begin(), original_path.end());
166   }
167 }
168 
169 void FileSystem::Resolve(FileSpec &file_spec) {
170   // Extract path from the FileSpec.
171   SmallString<128> path;
172   file_spec.GetPath(path);
173 
174   // Resolve the path.
175   Resolve(path);
176 
177   // Update the FileSpec with the resolved path.
178   file_spec.SetPath(path);
179 }
180