1*0b57cec5SDimitry Andric //===-- FileSystem.cpp ------------------------------------------*- C++ -*-===//
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 
11*0b57cec5SDimitry Andric #include "lldb/Utility/LLDBAssert.h"
12*0b57cec5SDimitry Andric #include "lldb/Utility/TildeExpressionResolver.h"
13*0b57cec5SDimitry Andric 
14*0b57cec5SDimitry Andric #include "llvm/Support/Errc.h"
15*0b57cec5SDimitry Andric #include "llvm/Support/Errno.h"
16*0b57cec5SDimitry Andric #include "llvm/Support/Error.h"
17*0b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
18*0b57cec5SDimitry Andric #include "llvm/Support/Path.h"
19*0b57cec5SDimitry Andric #include "llvm/Support/Program.h"
20*0b57cec5SDimitry Andric #include "llvm/Support/Threading.h"
21*0b57cec5SDimitry Andric 
22*0b57cec5SDimitry Andric #include <errno.h>
23*0b57cec5SDimitry Andric #include <fcntl.h>
24*0b57cec5SDimitry Andric #include <limits.h>
25*0b57cec5SDimitry Andric #include <stdarg.h>
26*0b57cec5SDimitry Andric #include <stdio.h>
27*0b57cec5SDimitry Andric 
28*0b57cec5SDimitry Andric #ifdef _WIN32
29*0b57cec5SDimitry Andric #include "lldb/Host/windows/windows.h"
30*0b57cec5SDimitry Andric #else
31*0b57cec5SDimitry Andric #include <sys/ioctl.h>
32*0b57cec5SDimitry Andric #include <sys/stat.h>
33*0b57cec5SDimitry Andric #include <termios.h>
34*0b57cec5SDimitry Andric #include <unistd.h>
35*0b57cec5SDimitry Andric #endif
36*0b57cec5SDimitry Andric 
37*0b57cec5SDimitry Andric #include <algorithm>
38*0b57cec5SDimitry Andric #include <fstream>
39*0b57cec5SDimitry Andric #include <vector>
40*0b57cec5SDimitry Andric 
41*0b57cec5SDimitry Andric using namespace lldb;
42*0b57cec5SDimitry Andric using namespace lldb_private;
43*0b57cec5SDimitry Andric using namespace llvm;
44*0b57cec5SDimitry Andric 
45*0b57cec5SDimitry Andric FileSystem &FileSystem::Instance() { return *InstanceImpl(); }
46*0b57cec5SDimitry Andric 
47*0b57cec5SDimitry Andric void FileSystem::Initialize() {
48*0b57cec5SDimitry Andric   lldbassert(!InstanceImpl() && "Already initialized.");
49*0b57cec5SDimitry Andric   InstanceImpl().emplace();
50*0b57cec5SDimitry Andric }
51*0b57cec5SDimitry Andric 
529dba64beSDimitry Andric void FileSystem::Initialize(std::shared_ptr<FileCollector> collector) {
53*0b57cec5SDimitry Andric   lldbassert(!InstanceImpl() && "Already initialized.");
54*0b57cec5SDimitry Andric   InstanceImpl().emplace(collector);
55*0b57cec5SDimitry Andric }
56*0b57cec5SDimitry Andric 
57*0b57cec5SDimitry Andric llvm::Error FileSystem::Initialize(const FileSpec &mapping) {
58*0b57cec5SDimitry Andric   lldbassert(!InstanceImpl() && "Already initialized.");
59*0b57cec5SDimitry Andric 
60*0b57cec5SDimitry Andric   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer =
61*0b57cec5SDimitry Andric       llvm::vfs::getRealFileSystem()->getBufferForFile(mapping.GetPath());
62*0b57cec5SDimitry Andric 
63*0b57cec5SDimitry Andric   if (!buffer)
64*0b57cec5SDimitry Andric     return llvm::errorCodeToError(buffer.getError());
65*0b57cec5SDimitry Andric 
66*0b57cec5SDimitry Andric   InstanceImpl().emplace(llvm::vfs::getVFSFromYAML(std::move(buffer.get()),
67*0b57cec5SDimitry Andric                                                    nullptr, mapping.GetPath()),
68*0b57cec5SDimitry Andric                          true);
69*0b57cec5SDimitry Andric 
70*0b57cec5SDimitry Andric   return llvm::Error::success();
71*0b57cec5SDimitry Andric }
72*0b57cec5SDimitry Andric 
73*0b57cec5SDimitry Andric void FileSystem::Initialize(IntrusiveRefCntPtr<vfs::FileSystem> fs) {
74*0b57cec5SDimitry Andric   lldbassert(!InstanceImpl() && "Already initialized.");
75*0b57cec5SDimitry Andric   InstanceImpl().emplace(fs);
76*0b57cec5SDimitry Andric }
77*0b57cec5SDimitry Andric 
78*0b57cec5SDimitry Andric void FileSystem::Terminate() {
79*0b57cec5SDimitry Andric   lldbassert(InstanceImpl() && "Already terminated.");
80*0b57cec5SDimitry Andric   InstanceImpl().reset();
81*0b57cec5SDimitry Andric }
82*0b57cec5SDimitry Andric 
83*0b57cec5SDimitry Andric Optional<FileSystem> &FileSystem::InstanceImpl() {
84*0b57cec5SDimitry Andric   static Optional<FileSystem> g_fs;
85*0b57cec5SDimitry Andric   return g_fs;
86*0b57cec5SDimitry Andric }
87*0b57cec5SDimitry Andric 
88*0b57cec5SDimitry Andric vfs::directory_iterator FileSystem::DirBegin(const FileSpec &file_spec,
89*0b57cec5SDimitry Andric                                              std::error_code &ec) {
90*0b57cec5SDimitry Andric   return DirBegin(file_spec.GetPath(), ec);
91*0b57cec5SDimitry Andric }
92*0b57cec5SDimitry Andric 
93*0b57cec5SDimitry Andric vfs::directory_iterator FileSystem::DirBegin(const Twine &dir,
94*0b57cec5SDimitry Andric                                              std::error_code &ec) {
95*0b57cec5SDimitry Andric   return m_fs->dir_begin(dir, ec);
96*0b57cec5SDimitry Andric }
97*0b57cec5SDimitry Andric 
98*0b57cec5SDimitry Andric llvm::ErrorOr<vfs::Status>
99*0b57cec5SDimitry Andric FileSystem::GetStatus(const FileSpec &file_spec) const {
100*0b57cec5SDimitry Andric   return GetStatus(file_spec.GetPath());
101*0b57cec5SDimitry Andric }
102*0b57cec5SDimitry Andric 
103*0b57cec5SDimitry Andric llvm::ErrorOr<vfs::Status> FileSystem::GetStatus(const Twine &path) const {
104*0b57cec5SDimitry Andric   return m_fs->status(path);
105*0b57cec5SDimitry Andric }
106*0b57cec5SDimitry Andric 
107*0b57cec5SDimitry Andric sys::TimePoint<>
108*0b57cec5SDimitry Andric FileSystem::GetModificationTime(const FileSpec &file_spec) const {
109*0b57cec5SDimitry Andric   return GetModificationTime(file_spec.GetPath());
110*0b57cec5SDimitry Andric }
111*0b57cec5SDimitry Andric 
112*0b57cec5SDimitry Andric sys::TimePoint<> FileSystem::GetModificationTime(const Twine &path) const {
113*0b57cec5SDimitry Andric   ErrorOr<vfs::Status> status = m_fs->status(path);
114*0b57cec5SDimitry Andric   if (!status)
115*0b57cec5SDimitry Andric     return sys::TimePoint<>();
116*0b57cec5SDimitry Andric   return status->getLastModificationTime();
117*0b57cec5SDimitry Andric }
118*0b57cec5SDimitry Andric 
119*0b57cec5SDimitry Andric uint64_t FileSystem::GetByteSize(const FileSpec &file_spec) const {
120*0b57cec5SDimitry Andric   return GetByteSize(file_spec.GetPath());
121*0b57cec5SDimitry Andric }
122*0b57cec5SDimitry Andric 
123*0b57cec5SDimitry Andric uint64_t FileSystem::GetByteSize(const Twine &path) const {
124*0b57cec5SDimitry Andric   ErrorOr<vfs::Status> status = m_fs->status(path);
125*0b57cec5SDimitry Andric   if (!status)
126*0b57cec5SDimitry Andric     return 0;
127*0b57cec5SDimitry Andric   return status->getSize();
128*0b57cec5SDimitry Andric }
129*0b57cec5SDimitry Andric 
130*0b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const FileSpec &file_spec) const {
131*0b57cec5SDimitry Andric   return GetPermissions(file_spec.GetPath());
132*0b57cec5SDimitry Andric }
133*0b57cec5SDimitry Andric 
134*0b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const FileSpec &file_spec,
135*0b57cec5SDimitry Andric                                     std::error_code &ec) const {
136*0b57cec5SDimitry Andric   return GetPermissions(file_spec.GetPath(), ec);
137*0b57cec5SDimitry Andric }
138*0b57cec5SDimitry Andric 
139*0b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const Twine &path) const {
140*0b57cec5SDimitry Andric   std::error_code ec;
141*0b57cec5SDimitry Andric   return GetPermissions(path, ec);
142*0b57cec5SDimitry Andric }
143*0b57cec5SDimitry Andric 
144*0b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const Twine &path,
145*0b57cec5SDimitry Andric                                     std::error_code &ec) const {
146*0b57cec5SDimitry Andric   ErrorOr<vfs::Status> status = m_fs->status(path);
147*0b57cec5SDimitry Andric   if (!status) {
148*0b57cec5SDimitry Andric     ec = status.getError();
149*0b57cec5SDimitry Andric     return sys::fs::perms::perms_not_known;
150*0b57cec5SDimitry Andric   }
151*0b57cec5SDimitry Andric   return status->getPermissions();
152*0b57cec5SDimitry Andric }
153*0b57cec5SDimitry Andric 
154*0b57cec5SDimitry Andric bool FileSystem::Exists(const Twine &path) const { return m_fs->exists(path); }
155*0b57cec5SDimitry Andric 
156*0b57cec5SDimitry Andric bool FileSystem::Exists(const FileSpec &file_spec) const {
157*0b57cec5SDimitry Andric   return Exists(file_spec.GetPath());
158*0b57cec5SDimitry Andric }
159*0b57cec5SDimitry Andric 
160*0b57cec5SDimitry Andric bool FileSystem::Readable(const Twine &path) const {
161*0b57cec5SDimitry Andric   return GetPermissions(path) & sys::fs::perms::all_read;
162*0b57cec5SDimitry Andric }
163*0b57cec5SDimitry Andric 
164*0b57cec5SDimitry Andric bool FileSystem::Readable(const FileSpec &file_spec) const {
165*0b57cec5SDimitry Andric   return Readable(file_spec.GetPath());
166*0b57cec5SDimitry Andric }
167*0b57cec5SDimitry Andric 
168*0b57cec5SDimitry Andric bool FileSystem::IsDirectory(const Twine &path) const {
169*0b57cec5SDimitry Andric   ErrorOr<vfs::Status> status = m_fs->status(path);
170*0b57cec5SDimitry Andric   if (!status)
171*0b57cec5SDimitry Andric     return false;
172*0b57cec5SDimitry Andric   return status->isDirectory();
173*0b57cec5SDimitry Andric }
174*0b57cec5SDimitry Andric 
175*0b57cec5SDimitry Andric bool FileSystem::IsDirectory(const FileSpec &file_spec) const {
176*0b57cec5SDimitry Andric   return IsDirectory(file_spec.GetPath());
177*0b57cec5SDimitry Andric }
178*0b57cec5SDimitry Andric 
179*0b57cec5SDimitry Andric bool FileSystem::IsLocal(const Twine &path) const {
180*0b57cec5SDimitry Andric   bool b = false;
181*0b57cec5SDimitry Andric   m_fs->isLocal(path, b);
182*0b57cec5SDimitry Andric   return b;
183*0b57cec5SDimitry Andric }
184*0b57cec5SDimitry Andric 
185*0b57cec5SDimitry Andric bool FileSystem::IsLocal(const FileSpec &file_spec) const {
186*0b57cec5SDimitry Andric   return IsLocal(file_spec.GetPath());
187*0b57cec5SDimitry Andric }
188*0b57cec5SDimitry Andric 
189*0b57cec5SDimitry Andric void FileSystem::EnumerateDirectory(Twine path, bool find_directories,
190*0b57cec5SDimitry Andric                                     bool find_files, bool find_other,
191*0b57cec5SDimitry Andric                                     EnumerateDirectoryCallbackType callback,
192*0b57cec5SDimitry Andric                                     void *callback_baton) {
193*0b57cec5SDimitry Andric   std::error_code EC;
194*0b57cec5SDimitry Andric   vfs::recursive_directory_iterator Iter(*m_fs, path, EC);
195*0b57cec5SDimitry Andric   vfs::recursive_directory_iterator End;
196*0b57cec5SDimitry Andric   for (; Iter != End && !EC; Iter.increment(EC)) {
197*0b57cec5SDimitry Andric     const auto &Item = *Iter;
198*0b57cec5SDimitry Andric     ErrorOr<vfs::Status> Status = m_fs->status(Item.path());
199*0b57cec5SDimitry Andric     if (!Status)
200*0b57cec5SDimitry Andric       break;
201*0b57cec5SDimitry Andric     if (!find_files && Status->isRegularFile())
202*0b57cec5SDimitry Andric       continue;
203*0b57cec5SDimitry Andric     if (!find_directories && Status->isDirectory())
204*0b57cec5SDimitry Andric       continue;
205*0b57cec5SDimitry Andric     if (!find_other && Status->isOther())
206*0b57cec5SDimitry Andric       continue;
207*0b57cec5SDimitry Andric 
208*0b57cec5SDimitry Andric     auto Result = callback(callback_baton, Status->getType(), Item.path());
209*0b57cec5SDimitry Andric     if (Result == eEnumerateDirectoryResultQuit)
210*0b57cec5SDimitry Andric       return;
211*0b57cec5SDimitry Andric     if (Result == eEnumerateDirectoryResultNext) {
212*0b57cec5SDimitry Andric       // Default behavior is to recurse. Opt out if the callback doesn't want
213*0b57cec5SDimitry Andric       // this behavior.
214*0b57cec5SDimitry Andric       Iter.no_push();
215*0b57cec5SDimitry Andric     }
216*0b57cec5SDimitry Andric   }
217*0b57cec5SDimitry Andric }
218*0b57cec5SDimitry Andric 
219*0b57cec5SDimitry Andric std::error_code FileSystem::MakeAbsolute(SmallVectorImpl<char> &path) const {
220*0b57cec5SDimitry Andric   return m_fs->makeAbsolute(path);
221*0b57cec5SDimitry Andric }
222*0b57cec5SDimitry Andric 
223*0b57cec5SDimitry Andric std::error_code FileSystem::MakeAbsolute(FileSpec &file_spec) const {
224*0b57cec5SDimitry Andric   SmallString<128> path;
225*0b57cec5SDimitry Andric   file_spec.GetPath(path, false);
226*0b57cec5SDimitry Andric 
227*0b57cec5SDimitry Andric   auto EC = MakeAbsolute(path);
228*0b57cec5SDimitry Andric   if (EC)
229*0b57cec5SDimitry Andric     return EC;
230*0b57cec5SDimitry Andric 
231*0b57cec5SDimitry Andric   FileSpec new_file_spec(path, file_spec.GetPathStyle());
232*0b57cec5SDimitry Andric   file_spec = new_file_spec;
233*0b57cec5SDimitry Andric   return {};
234*0b57cec5SDimitry Andric }
235*0b57cec5SDimitry Andric 
236*0b57cec5SDimitry Andric std::error_code FileSystem::GetRealPath(const Twine &path,
237*0b57cec5SDimitry Andric                                         SmallVectorImpl<char> &output) const {
238*0b57cec5SDimitry Andric   return m_fs->getRealPath(path, output);
239*0b57cec5SDimitry Andric }
240*0b57cec5SDimitry Andric 
241*0b57cec5SDimitry Andric void FileSystem::Resolve(SmallVectorImpl<char> &path) {
242*0b57cec5SDimitry Andric   if (path.empty())
243*0b57cec5SDimitry Andric     return;
244*0b57cec5SDimitry Andric 
245*0b57cec5SDimitry Andric   // Resolve tilde in path.
246*0b57cec5SDimitry Andric   SmallString<128> resolved(path.begin(), path.end());
247*0b57cec5SDimitry Andric   StandardTildeExpressionResolver Resolver;
248*0b57cec5SDimitry Andric   Resolver.ResolveFullPath(llvm::StringRef(path.begin(), path.size()),
249*0b57cec5SDimitry Andric                            resolved);
250*0b57cec5SDimitry Andric 
251*0b57cec5SDimitry Andric   // Try making the path absolute if it exists.
252*0b57cec5SDimitry Andric   SmallString<128> absolute(resolved.begin(), resolved.end());
253*0b57cec5SDimitry Andric   MakeAbsolute(absolute);
254*0b57cec5SDimitry Andric 
255*0b57cec5SDimitry Andric   path.clear();
256*0b57cec5SDimitry Andric   if (Exists(absolute)) {
257*0b57cec5SDimitry Andric     path.append(absolute.begin(), absolute.end());
258*0b57cec5SDimitry Andric   } else {
259*0b57cec5SDimitry Andric     path.append(resolved.begin(), resolved.end());
260*0b57cec5SDimitry Andric   }
261*0b57cec5SDimitry Andric }
262*0b57cec5SDimitry Andric 
263*0b57cec5SDimitry Andric void FileSystem::Resolve(FileSpec &file_spec) {
264*0b57cec5SDimitry Andric   // Extract path from the FileSpec.
265*0b57cec5SDimitry Andric   SmallString<128> path;
266*0b57cec5SDimitry Andric   file_spec.GetPath(path);
267*0b57cec5SDimitry Andric 
268*0b57cec5SDimitry Andric   // Resolve the path.
269*0b57cec5SDimitry Andric   Resolve(path);
270*0b57cec5SDimitry Andric 
271*0b57cec5SDimitry Andric   // Update the FileSpec with the resolved path.
272*0b57cec5SDimitry Andric   if (file_spec.GetFilename().IsEmpty())
273*0b57cec5SDimitry Andric     file_spec.GetDirectory().SetString(path);
274*0b57cec5SDimitry Andric   else
275*0b57cec5SDimitry Andric     file_spec.SetPath(path);
276*0b57cec5SDimitry Andric   file_spec.SetIsResolved(true);
277*0b57cec5SDimitry Andric }
278*0b57cec5SDimitry Andric 
279*0b57cec5SDimitry Andric std::shared_ptr<DataBufferLLVM>
280*0b57cec5SDimitry Andric FileSystem::CreateDataBuffer(const llvm::Twine &path, uint64_t size,
281*0b57cec5SDimitry Andric                              uint64_t offset) {
282*0b57cec5SDimitry Andric   if (m_collector)
2839dba64beSDimitry Andric     m_collector->addFile(path);
284*0b57cec5SDimitry Andric 
285*0b57cec5SDimitry Andric   const bool is_volatile = !IsLocal(path);
286*0b57cec5SDimitry Andric   const ErrorOr<std::string> external_path = GetExternalPath(path);
287*0b57cec5SDimitry Andric 
288*0b57cec5SDimitry Andric   if (!external_path)
289*0b57cec5SDimitry Andric     return nullptr;
290*0b57cec5SDimitry Andric 
291*0b57cec5SDimitry Andric   std::unique_ptr<llvm::WritableMemoryBuffer> buffer;
292*0b57cec5SDimitry Andric   if (size == 0) {
293*0b57cec5SDimitry Andric     auto buffer_or_error =
294*0b57cec5SDimitry Andric         llvm::WritableMemoryBuffer::getFile(*external_path, -1, is_volatile);
295*0b57cec5SDimitry Andric     if (!buffer_or_error)
296*0b57cec5SDimitry Andric       return nullptr;
297*0b57cec5SDimitry Andric     buffer = std::move(*buffer_or_error);
298*0b57cec5SDimitry Andric   } else {
299*0b57cec5SDimitry Andric     auto buffer_or_error = llvm::WritableMemoryBuffer::getFileSlice(
300*0b57cec5SDimitry Andric         *external_path, size, offset, is_volatile);
301*0b57cec5SDimitry Andric     if (!buffer_or_error)
302*0b57cec5SDimitry Andric       return nullptr;
303*0b57cec5SDimitry Andric     buffer = std::move(*buffer_or_error);
304*0b57cec5SDimitry Andric   }
305*0b57cec5SDimitry Andric   return std::shared_ptr<DataBufferLLVM>(new DataBufferLLVM(std::move(buffer)));
306*0b57cec5SDimitry Andric }
307*0b57cec5SDimitry Andric 
308*0b57cec5SDimitry Andric std::shared_ptr<DataBufferLLVM>
309*0b57cec5SDimitry Andric FileSystem::CreateDataBuffer(const FileSpec &file_spec, uint64_t size,
310*0b57cec5SDimitry Andric                              uint64_t offset) {
311*0b57cec5SDimitry Andric   return CreateDataBuffer(file_spec.GetPath(), size, offset);
312*0b57cec5SDimitry Andric }
313*0b57cec5SDimitry Andric 
314*0b57cec5SDimitry Andric bool FileSystem::ResolveExecutableLocation(FileSpec &file_spec) {
315*0b57cec5SDimitry Andric   // If the directory is set there's nothing to do.
316*0b57cec5SDimitry Andric   ConstString directory = file_spec.GetDirectory();
317*0b57cec5SDimitry Andric   if (directory)
318*0b57cec5SDimitry Andric     return false;
319*0b57cec5SDimitry Andric 
320*0b57cec5SDimitry Andric   // We cannot look for a file if there's no file name.
321*0b57cec5SDimitry Andric   ConstString filename = file_spec.GetFilename();
322*0b57cec5SDimitry Andric   if (!filename)
323*0b57cec5SDimitry Andric     return false;
324*0b57cec5SDimitry Andric 
325*0b57cec5SDimitry Andric   // Search for the file on the host.
326*0b57cec5SDimitry Andric   const std::string filename_str(filename.GetCString());
327*0b57cec5SDimitry Andric   llvm::ErrorOr<std::string> error_or_path =
328*0b57cec5SDimitry Andric       llvm::sys::findProgramByName(filename_str);
329*0b57cec5SDimitry Andric   if (!error_or_path)
330*0b57cec5SDimitry Andric     return false;
331*0b57cec5SDimitry Andric 
332*0b57cec5SDimitry Andric   // findProgramByName returns "." if it can't find the file.
333*0b57cec5SDimitry Andric   llvm::StringRef path = *error_or_path;
334*0b57cec5SDimitry Andric   llvm::StringRef parent = llvm::sys::path::parent_path(path);
335*0b57cec5SDimitry Andric   if (parent.empty() || parent == ".")
336*0b57cec5SDimitry Andric     return false;
337*0b57cec5SDimitry Andric 
338*0b57cec5SDimitry Andric   // Make sure that the result exists.
339*0b57cec5SDimitry Andric   FileSpec result(*error_or_path);
340*0b57cec5SDimitry Andric   if (!Exists(result))
341*0b57cec5SDimitry Andric     return false;
342*0b57cec5SDimitry Andric 
343*0b57cec5SDimitry Andric   file_spec = result;
344*0b57cec5SDimitry Andric   return true;
345*0b57cec5SDimitry Andric }
346*0b57cec5SDimitry Andric 
347*0b57cec5SDimitry Andric static int OpenWithFS(const FileSystem &fs, const char *path, int flags,
348*0b57cec5SDimitry Andric                       int mode) {
349*0b57cec5SDimitry Andric   return const_cast<FileSystem &>(fs).Open(path, flags, mode);
350*0b57cec5SDimitry Andric }
351*0b57cec5SDimitry Andric 
352*0b57cec5SDimitry Andric static int GetOpenFlags(uint32_t options) {
353*0b57cec5SDimitry Andric   const bool read = options & File::eOpenOptionRead;
354*0b57cec5SDimitry Andric   const bool write = options & File::eOpenOptionWrite;
355*0b57cec5SDimitry Andric 
356*0b57cec5SDimitry Andric   int open_flags = 0;
357*0b57cec5SDimitry Andric   if (write) {
358*0b57cec5SDimitry Andric     if (read)
359*0b57cec5SDimitry Andric       open_flags |= O_RDWR;
360*0b57cec5SDimitry Andric     else
361*0b57cec5SDimitry Andric       open_flags |= O_WRONLY;
362*0b57cec5SDimitry Andric 
363*0b57cec5SDimitry Andric     if (options & File::eOpenOptionAppend)
364*0b57cec5SDimitry Andric       open_flags |= O_APPEND;
365*0b57cec5SDimitry Andric 
366*0b57cec5SDimitry Andric     if (options & File::eOpenOptionTruncate)
367*0b57cec5SDimitry Andric       open_flags |= O_TRUNC;
368*0b57cec5SDimitry Andric 
369*0b57cec5SDimitry Andric     if (options & File::eOpenOptionCanCreate)
370*0b57cec5SDimitry Andric       open_flags |= O_CREAT;
371*0b57cec5SDimitry Andric 
372*0b57cec5SDimitry Andric     if (options & File::eOpenOptionCanCreateNewOnly)
373*0b57cec5SDimitry Andric       open_flags |= O_CREAT | O_EXCL;
374*0b57cec5SDimitry Andric   } else if (read) {
375*0b57cec5SDimitry Andric     open_flags |= O_RDONLY;
376*0b57cec5SDimitry Andric 
377*0b57cec5SDimitry Andric #ifndef _WIN32
378*0b57cec5SDimitry Andric     if (options & File::eOpenOptionDontFollowSymlinks)
379*0b57cec5SDimitry Andric       open_flags |= O_NOFOLLOW;
380*0b57cec5SDimitry Andric #endif
381*0b57cec5SDimitry Andric   }
382*0b57cec5SDimitry Andric 
383*0b57cec5SDimitry Andric #ifndef _WIN32
384*0b57cec5SDimitry Andric   if (options & File::eOpenOptionNonBlocking)
385*0b57cec5SDimitry Andric     open_flags |= O_NONBLOCK;
386*0b57cec5SDimitry Andric   if (options & File::eOpenOptionCloseOnExec)
387*0b57cec5SDimitry Andric     open_flags |= O_CLOEXEC;
388*0b57cec5SDimitry Andric #else
389*0b57cec5SDimitry Andric   open_flags |= O_BINARY;
390*0b57cec5SDimitry Andric #endif
391*0b57cec5SDimitry Andric 
392*0b57cec5SDimitry Andric   return open_flags;
393*0b57cec5SDimitry Andric }
394*0b57cec5SDimitry Andric 
395*0b57cec5SDimitry Andric static mode_t GetOpenMode(uint32_t permissions) {
396*0b57cec5SDimitry Andric   mode_t mode = 0;
397*0b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsUserRead)
398*0b57cec5SDimitry Andric     mode |= S_IRUSR;
399*0b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsUserWrite)
400*0b57cec5SDimitry Andric     mode |= S_IWUSR;
401*0b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsUserExecute)
402*0b57cec5SDimitry Andric     mode |= S_IXUSR;
403*0b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsGroupRead)
404*0b57cec5SDimitry Andric     mode |= S_IRGRP;
405*0b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsGroupWrite)
406*0b57cec5SDimitry Andric     mode |= S_IWGRP;
407*0b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsGroupExecute)
408*0b57cec5SDimitry Andric     mode |= S_IXGRP;
409*0b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsWorldRead)
410*0b57cec5SDimitry Andric     mode |= S_IROTH;
411*0b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsWorldWrite)
412*0b57cec5SDimitry Andric     mode |= S_IWOTH;
413*0b57cec5SDimitry Andric   if (permissions & lldb::eFilePermissionsWorldExecute)
414*0b57cec5SDimitry Andric     mode |= S_IXOTH;
415*0b57cec5SDimitry Andric   return mode;
416*0b57cec5SDimitry Andric }
417*0b57cec5SDimitry Andric 
4189dba64beSDimitry Andric Expected<FileUP> FileSystem::Open(const FileSpec &file_spec,
4199dba64beSDimitry Andric                                   File::OpenOptions options,
420*0b57cec5SDimitry Andric                                   uint32_t permissions, bool should_close_fd) {
421*0b57cec5SDimitry Andric   if (m_collector)
4229dba64beSDimitry Andric     m_collector->addFile(file_spec.GetPath());
423*0b57cec5SDimitry Andric 
424*0b57cec5SDimitry Andric   const int open_flags = GetOpenFlags(options);
425*0b57cec5SDimitry Andric   const mode_t open_mode =
426*0b57cec5SDimitry Andric       (open_flags & O_CREAT) ? GetOpenMode(permissions) : 0;
427*0b57cec5SDimitry Andric 
428*0b57cec5SDimitry Andric   auto path = GetExternalPath(file_spec);
429*0b57cec5SDimitry Andric   if (!path)
4309dba64beSDimitry Andric     return errorCodeToError(path.getError());
431*0b57cec5SDimitry Andric 
432*0b57cec5SDimitry Andric   int descriptor = llvm::sys::RetryAfterSignal(
433*0b57cec5SDimitry Andric       -1, OpenWithFS, *this, path->c_str(), open_flags, open_mode);
434*0b57cec5SDimitry Andric 
4359dba64beSDimitry Andric   if (!File::DescriptorIsValid(descriptor))
4369dba64beSDimitry Andric     return llvm::errorCodeToError(
4379dba64beSDimitry Andric         std::error_code(errno, std::system_category()));
4389dba64beSDimitry Andric 
4399dba64beSDimitry Andric   auto file = std::unique_ptr<File>(
4409dba64beSDimitry Andric       new NativeFile(descriptor, options, should_close_fd));
4419dba64beSDimitry Andric   assert(file->IsValid());
4429dba64beSDimitry Andric   return std::move(file);
443*0b57cec5SDimitry Andric }
444*0b57cec5SDimitry Andric 
445*0b57cec5SDimitry Andric ErrorOr<std::string> FileSystem::GetExternalPath(const llvm::Twine &path) {
446*0b57cec5SDimitry Andric   if (!m_mapped)
447*0b57cec5SDimitry Andric     return path.str();
448*0b57cec5SDimitry Andric 
449*0b57cec5SDimitry Andric   // If VFS mapped we know the underlying FS is a RedirectingFileSystem.
450*0b57cec5SDimitry Andric   ErrorOr<vfs::RedirectingFileSystem::Entry *> E =
451*0b57cec5SDimitry Andric       static_cast<vfs::RedirectingFileSystem &>(*m_fs).lookupPath(path);
452*0b57cec5SDimitry Andric   if (!E) {
453*0b57cec5SDimitry Andric     if (E.getError() == llvm::errc::no_such_file_or_directory) {
454*0b57cec5SDimitry Andric       return path.str();
455*0b57cec5SDimitry Andric     }
456*0b57cec5SDimitry Andric     return E.getError();
457*0b57cec5SDimitry Andric   }
458*0b57cec5SDimitry Andric 
459*0b57cec5SDimitry Andric   auto *F = dyn_cast<vfs::RedirectingFileSystem::RedirectingFileEntry>(*E);
460*0b57cec5SDimitry Andric   if (!F)
461*0b57cec5SDimitry Andric     return make_error_code(llvm::errc::not_supported);
462*0b57cec5SDimitry Andric 
463*0b57cec5SDimitry Andric   return F->getExternalContentsPath().str();
464*0b57cec5SDimitry Andric }
465*0b57cec5SDimitry Andric 
466*0b57cec5SDimitry Andric ErrorOr<std::string> FileSystem::GetExternalPath(const FileSpec &file_spec) {
467*0b57cec5SDimitry Andric   return GetExternalPath(file_spec.GetPath());
468*0b57cec5SDimitry Andric }
469