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