15ffd83dbSDimitry Andric //===-- FileSystem.cpp ----------------------------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #include "lldb/Host/FileSystem.h"
10*0b57cec5SDimitry Andric 
1181ad6265SDimitry Andric #include "lldb/Utility/DataBufferLLVM.h"
12*0b57cec5SDimitry Andric #include "lldb/Utility/LLDBAssert.h"
13*0b57cec5SDimitry Andric #include "lldb/Utility/TildeExpressionResolver.h"
14*0b57cec5SDimitry Andric 
15*0b57cec5SDimitry Andric #include "llvm/Support/Errc.h"
16*0b57cec5SDimitry Andric #include "llvm/Support/Errno.h"
17*0b57cec5SDimitry Andric #include "llvm/Support/Error.h"
18*0b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
19*0b57cec5SDimitry Andric #include "llvm/Support/Path.h"
20*0b57cec5SDimitry Andric #include "llvm/Support/Program.h"
21*0b57cec5SDimitry Andric #include "llvm/Support/Threading.h"
22*0b57cec5SDimitry Andric 
23fe6060f1SDimitry Andric #include <cerrno>
24fe6060f1SDimitry Andric #include <climits>
25fe6060f1SDimitry Andric #include <cstdarg>
26fe6060f1SDimitry Andric #include <cstdio>
27*0b57cec5SDimitry Andric #include <fcntl.h>
28*0b57cec5SDimitry Andric 
29*0b57cec5SDimitry Andric #ifdef _WIN32
30*0b57cec5SDimitry Andric #include "lldb/Host/windows/windows.h"
31*0b57cec5SDimitry Andric #else
32*0b57cec5SDimitry Andric #include <sys/ioctl.h>
33*0b57cec5SDimitry Andric #include <sys/stat.h>
34*0b57cec5SDimitry Andric #include <termios.h>
35*0b57cec5SDimitry Andric #include <unistd.h>
36*0b57cec5SDimitry Andric #endif
37*0b57cec5SDimitry Andric 
38*0b57cec5SDimitry Andric #include <algorithm>
39*0b57cec5SDimitry Andric #include <fstream>
40bdd1243dSDimitry Andric #include <optional>
41*0b57cec5SDimitry Andric #include <vector>
42*0b57cec5SDimitry Andric 
43*0b57cec5SDimitry Andric using namespace lldb;
44*0b57cec5SDimitry Andric using namespace lldb_private;
45*0b57cec5SDimitry Andric using namespace llvm;
46*0b57cec5SDimitry Andric 
47*0b57cec5SDimitry Andric FileSystem &FileSystem::Instance() { return *InstanceImpl(); }
48*0b57cec5SDimitry Andric 
49*0b57cec5SDimitry Andric void FileSystem::Initialize() {
50*0b57cec5SDimitry Andric   lldbassert(!InstanceImpl() && "Already initialized.");
51*0b57cec5SDimitry Andric   InstanceImpl().emplace();
52*0b57cec5SDimitry Andric }
53*0b57cec5SDimitry Andric 
54*0b57cec5SDimitry Andric void FileSystem::Initialize(IntrusiveRefCntPtr<vfs::FileSystem> fs) {
55*0b57cec5SDimitry Andric   lldbassert(!InstanceImpl() && "Already initialized.");
56*0b57cec5SDimitry Andric   InstanceImpl().emplace(fs);
57*0b57cec5SDimitry Andric }
58*0b57cec5SDimitry Andric 
59*0b57cec5SDimitry Andric void FileSystem::Terminate() {
60*0b57cec5SDimitry Andric   lldbassert(InstanceImpl() && "Already terminated.");
61*0b57cec5SDimitry Andric   InstanceImpl().reset();
62*0b57cec5SDimitry Andric }
63*0b57cec5SDimitry Andric 
64bdd1243dSDimitry Andric std::optional<FileSystem> &FileSystem::InstanceImpl() {
65bdd1243dSDimitry Andric   static std::optional<FileSystem> g_fs;
66*0b57cec5SDimitry Andric   return g_fs;
67*0b57cec5SDimitry Andric }
68*0b57cec5SDimitry Andric 
69*0b57cec5SDimitry Andric vfs::directory_iterator FileSystem::DirBegin(const FileSpec &file_spec,
70*0b57cec5SDimitry Andric                                              std::error_code &ec) {
715ffd83dbSDimitry Andric   if (!file_spec) {
725ffd83dbSDimitry Andric     ec = std::error_code(static_cast<int>(errc::no_such_file_or_directory),
735ffd83dbSDimitry Andric                          std::system_category());
745ffd83dbSDimitry Andric     return {};
755ffd83dbSDimitry Andric   }
76*0b57cec5SDimitry Andric   return DirBegin(file_spec.GetPath(), ec);
77*0b57cec5SDimitry Andric }
78*0b57cec5SDimitry Andric 
79*0b57cec5SDimitry Andric vfs::directory_iterator FileSystem::DirBegin(const Twine &dir,
80*0b57cec5SDimitry Andric                                              std::error_code &ec) {
81*0b57cec5SDimitry Andric   return m_fs->dir_begin(dir, ec);
82*0b57cec5SDimitry Andric }
83*0b57cec5SDimitry Andric 
84*0b57cec5SDimitry Andric llvm::ErrorOr<vfs::Status>
85*0b57cec5SDimitry Andric FileSystem::GetStatus(const FileSpec &file_spec) const {
865ffd83dbSDimitry Andric   if (!file_spec)
875ffd83dbSDimitry Andric     return std::error_code(static_cast<int>(errc::no_such_file_or_directory),
885ffd83dbSDimitry Andric                            std::system_category());
89*0b57cec5SDimitry Andric   return GetStatus(file_spec.GetPath());
90*0b57cec5SDimitry Andric }
91*0b57cec5SDimitry Andric 
92*0b57cec5SDimitry Andric llvm::ErrorOr<vfs::Status> FileSystem::GetStatus(const Twine &path) const {
93*0b57cec5SDimitry Andric   return m_fs->status(path);
94*0b57cec5SDimitry Andric }
95*0b57cec5SDimitry Andric 
96*0b57cec5SDimitry Andric sys::TimePoint<>
97*0b57cec5SDimitry Andric FileSystem::GetModificationTime(const FileSpec &file_spec) const {
985ffd83dbSDimitry Andric   if (!file_spec)
995ffd83dbSDimitry Andric     return sys::TimePoint<>();
100*0b57cec5SDimitry Andric   return GetModificationTime(file_spec.GetPath());
101*0b57cec5SDimitry Andric }
102*0b57cec5SDimitry Andric 
103*0b57cec5SDimitry Andric sys::TimePoint<> FileSystem::GetModificationTime(const Twine &path) const {
104*0b57cec5SDimitry Andric   ErrorOr<vfs::Status> status = m_fs->status(path);
105*0b57cec5SDimitry Andric   if (!status)
106*0b57cec5SDimitry Andric     return sys::TimePoint<>();
107*0b57cec5SDimitry Andric   return status->getLastModificationTime();
108*0b57cec5SDimitry Andric }
109*0b57cec5SDimitry Andric 
110*0b57cec5SDimitry Andric uint64_t FileSystem::GetByteSize(const FileSpec &file_spec) const {
1115ffd83dbSDimitry Andric   if (!file_spec)
1125ffd83dbSDimitry Andric     return 0;
113*0b57cec5SDimitry Andric   return GetByteSize(file_spec.GetPath());
114*0b57cec5SDimitry Andric }
115*0b57cec5SDimitry Andric 
116*0b57cec5SDimitry Andric uint64_t FileSystem::GetByteSize(const Twine &path) const {
117*0b57cec5SDimitry Andric   ErrorOr<vfs::Status> status = m_fs->status(path);
118*0b57cec5SDimitry Andric   if (!status)
119*0b57cec5SDimitry Andric     return 0;
120*0b57cec5SDimitry Andric   return status->getSize();
121*0b57cec5SDimitry Andric }
122*0b57cec5SDimitry Andric 
123*0b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const FileSpec &file_spec) const {
124*0b57cec5SDimitry Andric   return GetPermissions(file_spec.GetPath());
125*0b57cec5SDimitry Andric }
126*0b57cec5SDimitry Andric 
127*0b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const FileSpec &file_spec,
128*0b57cec5SDimitry Andric                                     std::error_code &ec) const {
1295ffd83dbSDimitry Andric   if (!file_spec)
1305ffd83dbSDimitry Andric     return sys::fs::perms::perms_not_known;
131*0b57cec5SDimitry Andric   return GetPermissions(file_spec.GetPath(), ec);
132*0b57cec5SDimitry Andric }
133*0b57cec5SDimitry Andric 
134*0b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const Twine &path) const {
135*0b57cec5SDimitry Andric   std::error_code ec;
136*0b57cec5SDimitry Andric   return GetPermissions(path, ec);
137*0b57cec5SDimitry Andric }
138*0b57cec5SDimitry Andric 
139*0b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const Twine &path,
140*0b57cec5SDimitry Andric                                     std::error_code &ec) const {
141*0b57cec5SDimitry Andric   ErrorOr<vfs::Status> status = m_fs->status(path);
142*0b57cec5SDimitry Andric   if (!status) {
143*0b57cec5SDimitry Andric     ec = status.getError();
144*0b57cec5SDimitry Andric     return sys::fs::perms::perms_not_known;
145*0b57cec5SDimitry Andric   }
146*0b57cec5SDimitry Andric   return status->getPermissions();
147*0b57cec5SDimitry Andric }
148*0b57cec5SDimitry Andric 
149*0b57cec5SDimitry Andric bool FileSystem::Exists(const Twine &path) const { return m_fs->exists(path); }
150*0b57cec5SDimitry Andric 
151*0b57cec5SDimitry Andric bool FileSystem::Exists(const FileSpec &file_spec) const {
1525ffd83dbSDimitry Andric   return file_spec && Exists(file_spec.GetPath());
153*0b57cec5SDimitry Andric }
154*0b57cec5SDimitry Andric 
155*0b57cec5SDimitry Andric bool FileSystem::Readable(const Twine &path) const {
156*0b57cec5SDimitry Andric   return GetPermissions(path) & sys::fs::perms::all_read;
157*0b57cec5SDimitry Andric }
158*0b57cec5SDimitry Andric 
159*0b57cec5SDimitry Andric bool FileSystem::Readable(const FileSpec &file_spec) const {
1605ffd83dbSDimitry Andric   return file_spec && Readable(file_spec.GetPath());
161*0b57cec5SDimitry Andric }
162*0b57cec5SDimitry Andric 
163*0b57cec5SDimitry Andric bool FileSystem::IsDirectory(const Twine &path) const {
164*0b57cec5SDimitry Andric   ErrorOr<vfs::Status> status = m_fs->status(path);
165*0b57cec5SDimitry Andric   if (!status)
166*0b57cec5SDimitry Andric     return false;
167*0b57cec5SDimitry Andric   return status->isDirectory();
168*0b57cec5SDimitry Andric }
169*0b57cec5SDimitry Andric 
170*0b57cec5SDimitry Andric bool FileSystem::IsDirectory(const FileSpec &file_spec) const {
1715ffd83dbSDimitry Andric   return file_spec && IsDirectory(file_spec.GetPath());
172*0b57cec5SDimitry Andric }
173*0b57cec5SDimitry Andric 
174*0b57cec5SDimitry Andric bool FileSystem::IsLocal(const Twine &path) const {
175*0b57cec5SDimitry Andric   bool b = false;
176*0b57cec5SDimitry Andric   m_fs->isLocal(path, b);
177*0b57cec5SDimitry Andric   return b;
178*0b57cec5SDimitry Andric }
179*0b57cec5SDimitry Andric 
180*0b57cec5SDimitry Andric bool FileSystem::IsLocal(const FileSpec &file_spec) const {
1815ffd83dbSDimitry Andric   return file_spec && IsLocal(file_spec.GetPath());
182*0b57cec5SDimitry Andric }
183*0b57cec5SDimitry Andric 
184*0b57cec5SDimitry Andric void FileSystem::EnumerateDirectory(Twine path, bool find_directories,
185*0b57cec5SDimitry Andric                                     bool find_files, bool find_other,
186*0b57cec5SDimitry Andric                                     EnumerateDirectoryCallbackType callback,
187*0b57cec5SDimitry Andric                                     void *callback_baton) {
188*0b57cec5SDimitry Andric   std::error_code EC;
189*0b57cec5SDimitry Andric   vfs::recursive_directory_iterator Iter(*m_fs, path, EC);
190*0b57cec5SDimitry Andric   vfs::recursive_directory_iterator End;
191*0b57cec5SDimitry Andric   for (; Iter != End && !EC; Iter.increment(EC)) {
192*0b57cec5SDimitry Andric     const auto &Item = *Iter;
193*0b57cec5SDimitry Andric     ErrorOr<vfs::Status> Status = m_fs->status(Item.path());
194*0b57cec5SDimitry Andric     if (!Status)
195*0b57cec5SDimitry Andric       break;
196*0b57cec5SDimitry Andric     if (!find_files && Status->isRegularFile())
197*0b57cec5SDimitry Andric       continue;
198*0b57cec5SDimitry Andric     if (!find_directories && Status->isDirectory())
199*0b57cec5SDimitry Andric       continue;
200*0b57cec5SDimitry Andric     if (!find_other && Status->isOther())
201*0b57cec5SDimitry Andric       continue;
202*0b57cec5SDimitry Andric 
203*0b57cec5SDimitry Andric     auto Result = callback(callback_baton, Status->getType(), Item.path());
204*0b57cec5SDimitry Andric     if (Result == eEnumerateDirectoryResultQuit)
205*0b57cec5SDimitry Andric       return;
206*0b57cec5SDimitry Andric     if (Result == eEnumerateDirectoryResultNext) {
207*0b57cec5SDimitry Andric       // Default behavior is to recurse. Opt out if the callback doesn't want
208*0b57cec5SDimitry Andric       // this behavior.
209*0b57cec5SDimitry Andric       Iter.no_push();
210*0b57cec5SDimitry Andric     }
211*0b57cec5SDimitry Andric   }
212*0b57cec5SDimitry Andric }
213*0b57cec5SDimitry Andric 
214*0b57cec5SDimitry Andric std::error_code FileSystem::MakeAbsolute(SmallVectorImpl<char> &path) const {
215*0b57cec5SDimitry Andric   return m_fs->makeAbsolute(path);
216*0b57cec5SDimitry Andric }
217*0b57cec5SDimitry Andric 
218*0b57cec5SDimitry Andric std::error_code FileSystem::MakeAbsolute(FileSpec &file_spec) const {
219*0b57cec5SDimitry Andric   SmallString<128> path;
220*0b57cec5SDimitry Andric   file_spec.GetPath(path, false);
221*0b57cec5SDimitry Andric 
222*0b57cec5SDimitry Andric   auto EC = MakeAbsolute(path);
223*0b57cec5SDimitry Andric   if (EC)
224*0b57cec5SDimitry Andric     return EC;
225*0b57cec5SDimitry Andric 
226*0b57cec5SDimitry Andric   FileSpec new_file_spec(path, file_spec.GetPathStyle());
227*0b57cec5SDimitry Andric   file_spec = new_file_spec;
228*0b57cec5SDimitry Andric   return {};
229*0b57cec5SDimitry Andric }
230*0b57cec5SDimitry Andric 
231*0b57cec5SDimitry Andric std::error_code FileSystem::GetRealPath(const Twine &path,
232*0b57cec5SDimitry Andric                                         SmallVectorImpl<char> &output) const {
233*0b57cec5SDimitry Andric   return m_fs->getRealPath(path, output);
234*0b57cec5SDimitry Andric }
235*0b57cec5SDimitry Andric 
236*0b57cec5SDimitry Andric void FileSystem::Resolve(SmallVectorImpl<char> &path) {
237*0b57cec5SDimitry Andric   if (path.empty())
238*0b57cec5SDimitry Andric     return;
239*0b57cec5SDimitry Andric 
240*0b57cec5SDimitry Andric   // Resolve tilde in path.
241*0b57cec5SDimitry Andric   SmallString<128> resolved(path.begin(), path.end());
242*0b57cec5SDimitry Andric   StandardTildeExpressionResolver Resolver;
243*0b57cec5SDimitry Andric   Resolver.ResolveFullPath(llvm::StringRef(path.begin(), path.size()),
244*0b57cec5SDimitry Andric                            resolved);
245*0b57cec5SDimitry Andric 
246*0b57cec5SDimitry Andric   // Try making the path absolute if it exists.
247*0b57cec5SDimitry Andric   SmallString<128> absolute(resolved.begin(), resolved.end());
248*0b57cec5SDimitry Andric   MakeAbsolute(absolute);
249*0b57cec5SDimitry Andric 
250*0b57cec5SDimitry Andric   path.clear();
251*0b57cec5SDimitry Andric   if (Exists(absolute)) {
252*0b57cec5SDimitry Andric     path.append(absolute.begin(), absolute.end());
253*0b57cec5SDimitry Andric   } else {
254*0b57cec5SDimitry Andric     path.append(resolved.begin(), resolved.end());
255*0b57cec5SDimitry Andric   }
256*0b57cec5SDimitry Andric }
257*0b57cec5SDimitry Andric 
258*0b57cec5SDimitry Andric void FileSystem::Resolve(FileSpec &file_spec) {
2595ffd83dbSDimitry Andric   if (!file_spec)
2605ffd83dbSDimitry Andric     return;
2615ffd83dbSDimitry Andric 
262*0b57cec5SDimitry Andric   // Extract path from the FileSpec.
263*0b57cec5SDimitry Andric   SmallString<128> path;
264*0b57cec5SDimitry Andric   file_spec.GetPath(path);
265*0b57cec5SDimitry Andric 
266*0b57cec5SDimitry Andric   // Resolve the path.
267*0b57cec5SDimitry Andric   Resolve(path);
268*0b57cec5SDimitry Andric 
269*0b57cec5SDimitry Andric   // Update the FileSpec with the resolved path.
270*0b57cec5SDimitry Andric   if (file_spec.GetFilename().IsEmpty())
271bdd1243dSDimitry Andric     file_spec.SetDirectory(path);
272*0b57cec5SDimitry Andric   else
273*0b57cec5SDimitry Andric     file_spec.SetPath(path);
274*0b57cec5SDimitry Andric   file_spec.SetIsResolved(true);
275*0b57cec5SDimitry Andric }
276*0b57cec5SDimitry Andric 
27781ad6265SDimitry Andric template <typename T>
27881ad6265SDimitry Andric static std::unique_ptr<T> GetMemoryBuffer(const llvm::Twine &path,
27981ad6265SDimitry Andric                                           uint64_t size, uint64_t offset,
28081ad6265SDimitry Andric                                           bool is_volatile) {
28181ad6265SDimitry Andric   std::unique_ptr<T> buffer;
282*0b57cec5SDimitry Andric   if (size == 0) {
28381ad6265SDimitry Andric     auto buffer_or_error = T::getFile(path, is_volatile);
284*0b57cec5SDimitry Andric     if (!buffer_or_error)
285*0b57cec5SDimitry Andric       return nullptr;
286*0b57cec5SDimitry Andric     buffer = std::move(*buffer_or_error);
287*0b57cec5SDimitry Andric   } else {
28881ad6265SDimitry Andric     auto buffer_or_error = T::getFileSlice(path, size, offset, is_volatile);
289*0b57cec5SDimitry Andric     if (!buffer_or_error)
290*0b57cec5SDimitry Andric       return nullptr;
291*0b57cec5SDimitry Andric     buffer = std::move(*buffer_or_error);
292*0b57cec5SDimitry Andric   }
29381ad6265SDimitry Andric   return buffer;
29481ad6265SDimitry Andric }
29581ad6265SDimitry Andric 
29681ad6265SDimitry Andric std::shared_ptr<WritableDataBuffer>
29781ad6265SDimitry Andric FileSystem::CreateWritableDataBuffer(const llvm::Twine &path, uint64_t size,
29881ad6265SDimitry Andric                                      uint64_t offset) {
29981ad6265SDimitry Andric   const bool is_volatile = !IsLocal(path);
30081ad6265SDimitry Andric   auto buffer = GetMemoryBuffer<llvm::WritableMemoryBuffer>(path, size, offset,
30181ad6265SDimitry Andric                                                             is_volatile);
30281ad6265SDimitry Andric   if (!buffer)
30381ad6265SDimitry Andric     return {};
30481ad6265SDimitry Andric   return std::shared_ptr<WritableDataBufferLLVM>(
30581ad6265SDimitry Andric       new WritableDataBufferLLVM(std::move(buffer)));
30681ad6265SDimitry Andric }
30781ad6265SDimitry Andric 
30881ad6265SDimitry Andric std::shared_ptr<DataBuffer>
30981ad6265SDimitry Andric FileSystem::CreateDataBuffer(const llvm::Twine &path, uint64_t size,
31081ad6265SDimitry Andric                              uint64_t offset) {
31181ad6265SDimitry Andric   const bool is_volatile = !IsLocal(path);
31281ad6265SDimitry Andric   auto buffer =
31381ad6265SDimitry Andric       GetMemoryBuffer<llvm::MemoryBuffer>(path, size, offset, is_volatile);
31481ad6265SDimitry Andric   if (!buffer)
31581ad6265SDimitry Andric     return {};
316*0b57cec5SDimitry Andric   return std::shared_ptr<DataBufferLLVM>(new DataBufferLLVM(std::move(buffer)));
317*0b57cec5SDimitry Andric }
318*0b57cec5SDimitry Andric 
31981ad6265SDimitry Andric std::shared_ptr<WritableDataBuffer>
32081ad6265SDimitry Andric FileSystem::CreateWritableDataBuffer(const FileSpec &file_spec, uint64_t size,
32181ad6265SDimitry Andric                                      uint64_t offset) {
32281ad6265SDimitry Andric   return CreateWritableDataBuffer(file_spec.GetPath(), size, offset);
32381ad6265SDimitry Andric }
32481ad6265SDimitry Andric 
32581ad6265SDimitry Andric std::shared_ptr<DataBuffer>
326*0b57cec5SDimitry Andric FileSystem::CreateDataBuffer(const FileSpec &file_spec, uint64_t size,
327*0b57cec5SDimitry Andric                              uint64_t offset) {
328*0b57cec5SDimitry Andric   return CreateDataBuffer(file_spec.GetPath(), size, offset);
329*0b57cec5SDimitry Andric }
330*0b57cec5SDimitry Andric 
331*0b57cec5SDimitry Andric bool FileSystem::ResolveExecutableLocation(FileSpec &file_spec) {
332*0b57cec5SDimitry Andric   // If the directory is set there's nothing to do.
333*0b57cec5SDimitry Andric   ConstString directory = file_spec.GetDirectory();
334*0b57cec5SDimitry Andric   if (directory)
335*0b57cec5SDimitry Andric     return false;
336*0b57cec5SDimitry Andric 
337*0b57cec5SDimitry Andric   // We cannot look for a file if there's no file name.
338*0b57cec5SDimitry Andric   ConstString filename = file_spec.GetFilename();
339*0b57cec5SDimitry Andric   if (!filename)
340*0b57cec5SDimitry Andric     return false;
341*0b57cec5SDimitry Andric 
342*0b57cec5SDimitry Andric   // Search for the file on the host.
343*0b57cec5SDimitry Andric   const std::string filename_str(filename.GetCString());
344*0b57cec5SDimitry Andric   llvm::ErrorOr<std::string> error_or_path =
345*0b57cec5SDimitry Andric       llvm::sys::findProgramByName(filename_str);
346*0b57cec5SDimitry Andric   if (!error_or_path)
347*0b57cec5SDimitry Andric     return false;
348*0b57cec5SDimitry Andric 
349*0b57cec5SDimitry Andric   // findProgramByName returns "." if it can't find the file.
350*0b57cec5SDimitry Andric   llvm::StringRef path = *error_or_path;
351*0b57cec5SDimitry Andric   llvm::StringRef parent = llvm::sys::path::parent_path(path);
352*0b57cec5SDimitry Andric   if (parent.empty() || parent == ".")
353*0b57cec5SDimitry Andric     return false;
354*0b57cec5SDimitry Andric 
355*0b57cec5SDimitry Andric   // Make sure that the result exists.
356*0b57cec5SDimitry Andric   FileSpec result(*error_or_path);
357*0b57cec5SDimitry Andric   if (!Exists(result))
358*0b57cec5SDimitry Andric     return false;
359*0b57cec5SDimitry Andric 
360*0b57cec5SDimitry Andric   file_spec = result;
361*0b57cec5SDimitry Andric   return true;
362*0b57cec5SDimitry Andric }
363*0b57cec5SDimitry Andric 
364e8d8bef9SDimitry Andric bool FileSystem::GetHomeDirectory(SmallVectorImpl<char> &path) const {
365e8d8bef9SDimitry Andric   if (!m_home_directory.empty()) {
366e8d8bef9SDimitry Andric     path.assign(m_home_directory.begin(), m_home_directory.end());
367e8d8bef9SDimitry Andric     return true;
368e8d8bef9SDimitry Andric   }
369e8d8bef9SDimitry Andric   return llvm::sys::path::home_directory(path);
370e8d8bef9SDimitry Andric }
371e8d8bef9SDimitry Andric 
372e8d8bef9SDimitry Andric bool FileSystem::GetHomeDirectory(FileSpec &file_spec) const {
373e8d8bef9SDimitry Andric   SmallString<128> home_dir;
374e8d8bef9SDimitry Andric   if (!GetHomeDirectory(home_dir))
375e8d8bef9SDimitry Andric     return false;
376e8d8bef9SDimitry Andric   file_spec.SetPath(home_dir);
377e8d8bef9SDimitry Andric   return true;
378e8d8bef9SDimitry Andric }
379e8d8bef9SDimitry Andric 
380*0b57cec5SDimitry Andric static int OpenWithFS(const FileSystem &fs, const char *path, int flags,
381*0b57cec5SDimitry Andric                       int mode) {
382*0b57cec5SDimitry Andric   return const_cast<FileSystem &>(fs).Open(path, flags, mode);
383*0b57cec5SDimitry Andric }
384*0b57cec5SDimitry Andric 
385349cc55cSDimitry Andric static int GetOpenFlags(File::OpenOptions options) {
386*0b57cec5SDimitry Andric   int open_flags = 0;
387349cc55cSDimitry Andric   File::OpenOptions rw =
388349cc55cSDimitry Andric       options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |
389349cc55cSDimitry Andric                  File::eOpenOptionReadWrite);
390349cc55cSDimitry Andric   if (rw == File::eOpenOptionWriteOnly || rw == File::eOpenOptionReadWrite) {
391349cc55cSDimitry Andric     if (rw == File::eOpenOptionReadWrite)
392*0b57cec5SDimitry Andric       open_flags |= O_RDWR;
393*0b57cec5SDimitry Andric     else
394*0b57cec5SDimitry Andric       open_flags |= O_WRONLY;
395*0b57cec5SDimitry Andric 
396*0b57cec5SDimitry Andric     if (options & File::eOpenOptionAppend)
397*0b57cec5SDimitry Andric       open_flags |= O_APPEND;
398*0b57cec5SDimitry Andric 
399*0b57cec5SDimitry Andric     if (options & File::eOpenOptionTruncate)
400*0b57cec5SDimitry Andric       open_flags |= O_TRUNC;
401*0b57cec5SDimitry Andric 
402*0b57cec5SDimitry Andric     if (options & File::eOpenOptionCanCreate)
403*0b57cec5SDimitry Andric       open_flags |= O_CREAT;
404*0b57cec5SDimitry Andric 
405*0b57cec5SDimitry Andric     if (options & File::eOpenOptionCanCreateNewOnly)
406*0b57cec5SDimitry Andric       open_flags |= O_CREAT | O_EXCL;
407349cc55cSDimitry Andric   } else if (rw == File::eOpenOptionReadOnly) {
408*0b57cec5SDimitry Andric     open_flags |= O_RDONLY;
409*0b57cec5SDimitry Andric 
410*0b57cec5SDimitry Andric #ifndef _WIN32
411*0b57cec5SDimitry Andric     if (options & File::eOpenOptionDontFollowSymlinks)
412*0b57cec5SDimitry Andric       open_flags |= O_NOFOLLOW;
413*0b57cec5SDimitry Andric #endif
414*0b57cec5SDimitry Andric   }
415*0b57cec5SDimitry Andric 
416*0b57cec5SDimitry Andric #ifndef _WIN32
417*0b57cec5SDimitry Andric   if (options & File::eOpenOptionNonBlocking)
418*0b57cec5SDimitry Andric     open_flags |= O_NONBLOCK;
419*0b57cec5SDimitry Andric   if (options & File::eOpenOptionCloseOnExec)
420*0b57cec5SDimitry Andric     open_flags |= O_CLOEXEC;
421*0b57cec5SDimitry Andric #else
422*0b57cec5SDimitry Andric   open_flags |= O_BINARY;
423*0b57cec5SDimitry Andric #endif
424*0b57cec5SDimitry Andric 
425*0b57cec5SDimitry Andric   return open_flags;
426*0b57cec5SDimitry Andric }
427*0b57cec5SDimitry Andric 
428*0b57cec5SDimitry Andric static mode_t GetOpenMode(uint32_t permissions) {
429*0b57cec5SDimitry Andric   mode_t mode = 0;
430*0b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsUserRead)
431*0b57cec5SDimitry Andric     mode |= S_IRUSR;
432*0b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsUserWrite)
433*0b57cec5SDimitry Andric     mode |= S_IWUSR;
434*0b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsUserExecute)
435*0b57cec5SDimitry Andric     mode |= S_IXUSR;
436*0b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsGroupRead)
437*0b57cec5SDimitry Andric     mode |= S_IRGRP;
438*0b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsGroupWrite)
439*0b57cec5SDimitry Andric     mode |= S_IWGRP;
440*0b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsGroupExecute)
441*0b57cec5SDimitry Andric     mode |= S_IXGRP;
442*0b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsWorldRead)
443*0b57cec5SDimitry Andric     mode |= S_IROTH;
444*0b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsWorldWrite)
445*0b57cec5SDimitry Andric     mode |= S_IWOTH;
446*0b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsWorldExecute)
447*0b57cec5SDimitry Andric     mode |= S_IXOTH;
448*0b57cec5SDimitry Andric   return mode;
449*0b57cec5SDimitry Andric }
450*0b57cec5SDimitry Andric 
4519dba64beSDimitry Andric Expected<FileUP> FileSystem::Open(const FileSpec &file_spec,
4529dba64beSDimitry Andric                                   File::OpenOptions options,
453*0b57cec5SDimitry Andric                                   uint32_t permissions, bool should_close_fd) {
454*0b57cec5SDimitry Andric   const int open_flags = GetOpenFlags(options);
455*0b57cec5SDimitry Andric   const mode_t open_mode =
456*0b57cec5SDimitry Andric       (open_flags & O_CREAT) ? GetOpenMode(permissions) : 0;
457*0b57cec5SDimitry Andric 
45881ad6265SDimitry Andric   auto path = file_spec.GetPath();
459*0b57cec5SDimitry Andric 
460*0b57cec5SDimitry Andric   int descriptor = llvm::sys::RetryAfterSignal(
46181ad6265SDimitry Andric       -1, OpenWithFS, *this, path.c_str(), open_flags, open_mode);
462*0b57cec5SDimitry Andric 
4639dba64beSDimitry Andric   if (!File::DescriptorIsValid(descriptor))
4649dba64beSDimitry Andric     return llvm::errorCodeToError(
4659dba64beSDimitry Andric         std::error_code(errno, std::system_category()));
4669dba64beSDimitry Andric 
4679dba64beSDimitry Andric   auto file = std::unique_ptr<File>(
4689dba64beSDimitry Andric       new NativeFile(descriptor, options, should_close_fd));
4699dba64beSDimitry Andric   assert(file->IsValid());
4709dba64beSDimitry Andric   return std::move(file);
471*0b57cec5SDimitry Andric }
472*0b57cec5SDimitry Andric 
473e8d8bef9SDimitry Andric void FileSystem::SetHomeDirectory(std::string home_directory) {
474e8d8bef9SDimitry Andric   m_home_directory = std::move(home_directory);
475e8d8bef9SDimitry Andric }
4760eae32dcSDimitry Andric 
4770eae32dcSDimitry Andric Status FileSystem::RemoveFile(const FileSpec &file_spec) {
4780eae32dcSDimitry Andric   return RemoveFile(file_spec.GetPath());
4790eae32dcSDimitry Andric }
4800eae32dcSDimitry Andric 
4810eae32dcSDimitry Andric Status FileSystem::RemoveFile(const llvm::Twine &path) {
4820eae32dcSDimitry Andric   return Status(llvm::sys::fs::remove(path));
4830eae32dcSDimitry Andric }
484