15ffd83dbSDimitry Andric //===-- FileSystem.cpp ----------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "lldb/Host/FileSystem.h"
100b57cec5SDimitry Andric
110b57cec5SDimitry Andric #include "lldb/Utility/LLDBAssert.h"
120b57cec5SDimitry Andric #include "lldb/Utility/TildeExpressionResolver.h"
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "llvm/Support/Errc.h"
150b57cec5SDimitry Andric #include "llvm/Support/Errno.h"
160b57cec5SDimitry Andric #include "llvm/Support/Error.h"
170b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
180b57cec5SDimitry Andric #include "llvm/Support/Path.h"
190b57cec5SDimitry Andric #include "llvm/Support/Program.h"
200b57cec5SDimitry Andric #include "llvm/Support/Threading.h"
210b57cec5SDimitry Andric
22*5f7ddb14SDimitry Andric #include <cerrno>
23*5f7ddb14SDimitry Andric #include <climits>
24*5f7ddb14SDimitry Andric #include <cstdarg>
25*5f7ddb14SDimitry Andric #include <cstdio>
260b57cec5SDimitry Andric #include <fcntl.h>
270b57cec5SDimitry Andric
280b57cec5SDimitry Andric #ifdef _WIN32
290b57cec5SDimitry Andric #include "lldb/Host/windows/windows.h"
300b57cec5SDimitry Andric #else
310b57cec5SDimitry Andric #include <sys/ioctl.h>
320b57cec5SDimitry Andric #include <sys/stat.h>
330b57cec5SDimitry Andric #include <termios.h>
340b57cec5SDimitry Andric #include <unistd.h>
350b57cec5SDimitry Andric #endif
360b57cec5SDimitry Andric
370b57cec5SDimitry Andric #include <algorithm>
380b57cec5SDimitry Andric #include <fstream>
390b57cec5SDimitry Andric #include <vector>
400b57cec5SDimitry Andric
410b57cec5SDimitry Andric using namespace lldb;
420b57cec5SDimitry Andric using namespace lldb_private;
430b57cec5SDimitry Andric using namespace llvm;
440b57cec5SDimitry Andric
Instance()450b57cec5SDimitry Andric FileSystem &FileSystem::Instance() { return *InstanceImpl(); }
460b57cec5SDimitry Andric
Initialize()470b57cec5SDimitry Andric void FileSystem::Initialize() {
480b57cec5SDimitry Andric lldbassert(!InstanceImpl() && "Already initialized.");
490b57cec5SDimitry Andric InstanceImpl().emplace();
500b57cec5SDimitry Andric }
510b57cec5SDimitry Andric
Initialize(std::shared_ptr<FileCollectorBase> collector)52af732203SDimitry Andric void FileSystem::Initialize(std::shared_ptr<FileCollectorBase> collector) {
530b57cec5SDimitry Andric lldbassert(!InstanceImpl() && "Already initialized.");
540b57cec5SDimitry Andric InstanceImpl().emplace(collector);
550b57cec5SDimitry Andric }
560b57cec5SDimitry Andric
Initialize(const FileSpec & mapping)570b57cec5SDimitry Andric llvm::Error FileSystem::Initialize(const FileSpec &mapping) {
580b57cec5SDimitry Andric lldbassert(!InstanceImpl() && "Already initialized.");
590b57cec5SDimitry Andric
600b57cec5SDimitry Andric llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer =
610b57cec5SDimitry Andric llvm::vfs::getRealFileSystem()->getBufferForFile(mapping.GetPath());
620b57cec5SDimitry Andric
630b57cec5SDimitry Andric if (!buffer)
640b57cec5SDimitry Andric return llvm::errorCodeToError(buffer.getError());
650b57cec5SDimitry Andric
660b57cec5SDimitry Andric InstanceImpl().emplace(llvm::vfs::getVFSFromYAML(std::move(buffer.get()),
670b57cec5SDimitry Andric nullptr, mapping.GetPath()),
680b57cec5SDimitry Andric true);
690b57cec5SDimitry Andric
700b57cec5SDimitry Andric return llvm::Error::success();
710b57cec5SDimitry Andric }
720b57cec5SDimitry Andric
Initialize(IntrusiveRefCntPtr<vfs::FileSystem> fs)730b57cec5SDimitry Andric void FileSystem::Initialize(IntrusiveRefCntPtr<vfs::FileSystem> fs) {
740b57cec5SDimitry Andric lldbassert(!InstanceImpl() && "Already initialized.");
750b57cec5SDimitry Andric InstanceImpl().emplace(fs);
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric
Terminate()780b57cec5SDimitry Andric void FileSystem::Terminate() {
790b57cec5SDimitry Andric lldbassert(InstanceImpl() && "Already terminated.");
800b57cec5SDimitry Andric InstanceImpl().reset();
810b57cec5SDimitry Andric }
820b57cec5SDimitry Andric
InstanceImpl()830b57cec5SDimitry Andric Optional<FileSystem> &FileSystem::InstanceImpl() {
840b57cec5SDimitry Andric static Optional<FileSystem> g_fs;
850b57cec5SDimitry Andric return g_fs;
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric
DirBegin(const FileSpec & file_spec,std::error_code & ec)880b57cec5SDimitry Andric vfs::directory_iterator FileSystem::DirBegin(const FileSpec &file_spec,
890b57cec5SDimitry Andric std::error_code &ec) {
905ffd83dbSDimitry Andric if (!file_spec) {
915ffd83dbSDimitry Andric ec = std::error_code(static_cast<int>(errc::no_such_file_or_directory),
925ffd83dbSDimitry Andric std::system_category());
935ffd83dbSDimitry Andric return {};
945ffd83dbSDimitry Andric }
950b57cec5SDimitry Andric return DirBegin(file_spec.GetPath(), ec);
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric
DirBegin(const Twine & dir,std::error_code & ec)980b57cec5SDimitry Andric vfs::directory_iterator FileSystem::DirBegin(const Twine &dir,
990b57cec5SDimitry Andric std::error_code &ec) {
1000b57cec5SDimitry Andric return m_fs->dir_begin(dir, ec);
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric
1030b57cec5SDimitry Andric llvm::ErrorOr<vfs::Status>
GetStatus(const FileSpec & file_spec) const1040b57cec5SDimitry Andric FileSystem::GetStatus(const FileSpec &file_spec) const {
1055ffd83dbSDimitry Andric if (!file_spec)
1065ffd83dbSDimitry Andric return std::error_code(static_cast<int>(errc::no_such_file_or_directory),
1075ffd83dbSDimitry Andric std::system_category());
1080b57cec5SDimitry Andric return GetStatus(file_spec.GetPath());
1090b57cec5SDimitry Andric }
1100b57cec5SDimitry Andric
GetStatus(const Twine & path) const1110b57cec5SDimitry Andric llvm::ErrorOr<vfs::Status> FileSystem::GetStatus(const Twine &path) const {
1120b57cec5SDimitry Andric return m_fs->status(path);
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric
1150b57cec5SDimitry Andric sys::TimePoint<>
GetModificationTime(const FileSpec & file_spec) const1160b57cec5SDimitry Andric FileSystem::GetModificationTime(const FileSpec &file_spec) const {
1175ffd83dbSDimitry Andric if (!file_spec)
1185ffd83dbSDimitry Andric return sys::TimePoint<>();
1190b57cec5SDimitry Andric return GetModificationTime(file_spec.GetPath());
1200b57cec5SDimitry Andric }
1210b57cec5SDimitry Andric
GetModificationTime(const Twine & path) const1220b57cec5SDimitry Andric sys::TimePoint<> FileSystem::GetModificationTime(const Twine &path) const {
1230b57cec5SDimitry Andric ErrorOr<vfs::Status> status = m_fs->status(path);
1240b57cec5SDimitry Andric if (!status)
1250b57cec5SDimitry Andric return sys::TimePoint<>();
1260b57cec5SDimitry Andric return status->getLastModificationTime();
1270b57cec5SDimitry Andric }
1280b57cec5SDimitry Andric
GetByteSize(const FileSpec & file_spec) const1290b57cec5SDimitry Andric uint64_t FileSystem::GetByteSize(const FileSpec &file_spec) const {
1305ffd83dbSDimitry Andric if (!file_spec)
1315ffd83dbSDimitry Andric return 0;
1320b57cec5SDimitry Andric return GetByteSize(file_spec.GetPath());
1330b57cec5SDimitry Andric }
1340b57cec5SDimitry Andric
GetByteSize(const Twine & path) const1350b57cec5SDimitry Andric uint64_t FileSystem::GetByteSize(const Twine &path) const {
1360b57cec5SDimitry Andric ErrorOr<vfs::Status> status = m_fs->status(path);
1370b57cec5SDimitry Andric if (!status)
1380b57cec5SDimitry Andric return 0;
1390b57cec5SDimitry Andric return status->getSize();
1400b57cec5SDimitry Andric }
1410b57cec5SDimitry Andric
GetPermissions(const FileSpec & file_spec) const1420b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const FileSpec &file_spec) const {
1430b57cec5SDimitry Andric return GetPermissions(file_spec.GetPath());
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric
GetPermissions(const FileSpec & file_spec,std::error_code & ec) const1460b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const FileSpec &file_spec,
1470b57cec5SDimitry Andric std::error_code &ec) const {
1485ffd83dbSDimitry Andric if (!file_spec)
1495ffd83dbSDimitry Andric return sys::fs::perms::perms_not_known;
1500b57cec5SDimitry Andric return GetPermissions(file_spec.GetPath(), ec);
1510b57cec5SDimitry Andric }
1520b57cec5SDimitry Andric
GetPermissions(const Twine & path) const1530b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const Twine &path) const {
1540b57cec5SDimitry Andric std::error_code ec;
1550b57cec5SDimitry Andric return GetPermissions(path, ec);
1560b57cec5SDimitry Andric }
1570b57cec5SDimitry Andric
GetPermissions(const Twine & path,std::error_code & ec) const1580b57cec5SDimitry Andric uint32_t FileSystem::GetPermissions(const Twine &path,
1590b57cec5SDimitry Andric std::error_code &ec) const {
1600b57cec5SDimitry Andric ErrorOr<vfs::Status> status = m_fs->status(path);
1610b57cec5SDimitry Andric if (!status) {
1620b57cec5SDimitry Andric ec = status.getError();
1630b57cec5SDimitry Andric return sys::fs::perms::perms_not_known;
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric return status->getPermissions();
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric
Exists(const Twine & path) const1680b57cec5SDimitry Andric bool FileSystem::Exists(const Twine &path) const { return m_fs->exists(path); }
1690b57cec5SDimitry Andric
Exists(const FileSpec & file_spec) const1700b57cec5SDimitry Andric bool FileSystem::Exists(const FileSpec &file_spec) const {
1715ffd83dbSDimitry Andric return file_spec && Exists(file_spec.GetPath());
1720b57cec5SDimitry Andric }
1730b57cec5SDimitry Andric
Readable(const Twine & path) const1740b57cec5SDimitry Andric bool FileSystem::Readable(const Twine &path) const {
1750b57cec5SDimitry Andric return GetPermissions(path) & sys::fs::perms::all_read;
1760b57cec5SDimitry Andric }
1770b57cec5SDimitry Andric
Readable(const FileSpec & file_spec) const1780b57cec5SDimitry Andric bool FileSystem::Readable(const FileSpec &file_spec) const {
1795ffd83dbSDimitry Andric return file_spec && Readable(file_spec.GetPath());
1800b57cec5SDimitry Andric }
1810b57cec5SDimitry Andric
IsDirectory(const Twine & path) const1820b57cec5SDimitry Andric bool FileSystem::IsDirectory(const Twine &path) const {
1830b57cec5SDimitry Andric ErrorOr<vfs::Status> status = m_fs->status(path);
1840b57cec5SDimitry Andric if (!status)
1850b57cec5SDimitry Andric return false;
1860b57cec5SDimitry Andric return status->isDirectory();
1870b57cec5SDimitry Andric }
1880b57cec5SDimitry Andric
IsDirectory(const FileSpec & file_spec) const1890b57cec5SDimitry Andric bool FileSystem::IsDirectory(const FileSpec &file_spec) const {
1905ffd83dbSDimitry Andric return file_spec && IsDirectory(file_spec.GetPath());
1910b57cec5SDimitry Andric }
1920b57cec5SDimitry Andric
IsLocal(const Twine & path) const1930b57cec5SDimitry Andric bool FileSystem::IsLocal(const Twine &path) const {
1940b57cec5SDimitry Andric bool b = false;
1950b57cec5SDimitry Andric m_fs->isLocal(path, b);
1960b57cec5SDimitry Andric return b;
1970b57cec5SDimitry Andric }
1980b57cec5SDimitry Andric
IsLocal(const FileSpec & file_spec) const1990b57cec5SDimitry Andric bool FileSystem::IsLocal(const FileSpec &file_spec) const {
2005ffd83dbSDimitry Andric return file_spec && IsLocal(file_spec.GetPath());
2010b57cec5SDimitry Andric }
2020b57cec5SDimitry Andric
EnumerateDirectory(Twine path,bool find_directories,bool find_files,bool find_other,EnumerateDirectoryCallbackType callback,void * callback_baton)2030b57cec5SDimitry Andric void FileSystem::EnumerateDirectory(Twine path, bool find_directories,
2040b57cec5SDimitry Andric bool find_files, bool find_other,
2050b57cec5SDimitry Andric EnumerateDirectoryCallbackType callback,
2060b57cec5SDimitry Andric void *callback_baton) {
2070b57cec5SDimitry Andric std::error_code EC;
2080b57cec5SDimitry Andric vfs::recursive_directory_iterator Iter(*m_fs, path, EC);
2090b57cec5SDimitry Andric vfs::recursive_directory_iterator End;
2100b57cec5SDimitry Andric for (; Iter != End && !EC; Iter.increment(EC)) {
2110b57cec5SDimitry Andric const auto &Item = *Iter;
2120b57cec5SDimitry Andric ErrorOr<vfs::Status> Status = m_fs->status(Item.path());
2130b57cec5SDimitry Andric if (!Status)
2140b57cec5SDimitry Andric break;
2150b57cec5SDimitry Andric if (!find_files && Status->isRegularFile())
2160b57cec5SDimitry Andric continue;
2170b57cec5SDimitry Andric if (!find_directories && Status->isDirectory())
2180b57cec5SDimitry Andric continue;
2190b57cec5SDimitry Andric if (!find_other && Status->isOther())
2200b57cec5SDimitry Andric continue;
2210b57cec5SDimitry Andric
2220b57cec5SDimitry Andric auto Result = callback(callback_baton, Status->getType(), Item.path());
2230b57cec5SDimitry Andric if (Result == eEnumerateDirectoryResultQuit)
2240b57cec5SDimitry Andric return;
2250b57cec5SDimitry Andric if (Result == eEnumerateDirectoryResultNext) {
2260b57cec5SDimitry Andric // Default behavior is to recurse. Opt out if the callback doesn't want
2270b57cec5SDimitry Andric // this behavior.
2280b57cec5SDimitry Andric Iter.no_push();
2290b57cec5SDimitry Andric }
2300b57cec5SDimitry Andric }
2310b57cec5SDimitry Andric }
2320b57cec5SDimitry Andric
MakeAbsolute(SmallVectorImpl<char> & path) const2330b57cec5SDimitry Andric std::error_code FileSystem::MakeAbsolute(SmallVectorImpl<char> &path) const {
2340b57cec5SDimitry Andric return m_fs->makeAbsolute(path);
2350b57cec5SDimitry Andric }
2360b57cec5SDimitry Andric
MakeAbsolute(FileSpec & file_spec) const2370b57cec5SDimitry Andric std::error_code FileSystem::MakeAbsolute(FileSpec &file_spec) const {
2380b57cec5SDimitry Andric SmallString<128> path;
2390b57cec5SDimitry Andric file_spec.GetPath(path, false);
2400b57cec5SDimitry Andric
2410b57cec5SDimitry Andric auto EC = MakeAbsolute(path);
2420b57cec5SDimitry Andric if (EC)
2430b57cec5SDimitry Andric return EC;
2440b57cec5SDimitry Andric
2450b57cec5SDimitry Andric FileSpec new_file_spec(path, file_spec.GetPathStyle());
2460b57cec5SDimitry Andric file_spec = new_file_spec;
2470b57cec5SDimitry Andric return {};
2480b57cec5SDimitry Andric }
2490b57cec5SDimitry Andric
GetRealPath(const Twine & path,SmallVectorImpl<char> & output) const2500b57cec5SDimitry Andric std::error_code FileSystem::GetRealPath(const Twine &path,
2510b57cec5SDimitry Andric SmallVectorImpl<char> &output) const {
2520b57cec5SDimitry Andric return m_fs->getRealPath(path, output);
2530b57cec5SDimitry Andric }
2540b57cec5SDimitry Andric
Resolve(SmallVectorImpl<char> & path)2550b57cec5SDimitry Andric void FileSystem::Resolve(SmallVectorImpl<char> &path) {
2560b57cec5SDimitry Andric if (path.empty())
2570b57cec5SDimitry Andric return;
2580b57cec5SDimitry Andric
2590b57cec5SDimitry Andric // Resolve tilde in path.
2600b57cec5SDimitry Andric SmallString<128> resolved(path.begin(), path.end());
2610b57cec5SDimitry Andric StandardTildeExpressionResolver Resolver;
2620b57cec5SDimitry Andric Resolver.ResolveFullPath(llvm::StringRef(path.begin(), path.size()),
2630b57cec5SDimitry Andric resolved);
2640b57cec5SDimitry Andric
2650b57cec5SDimitry Andric // Try making the path absolute if it exists.
2660b57cec5SDimitry Andric SmallString<128> absolute(resolved.begin(), resolved.end());
2670b57cec5SDimitry Andric MakeAbsolute(absolute);
2680b57cec5SDimitry Andric
2690b57cec5SDimitry Andric path.clear();
2700b57cec5SDimitry Andric if (Exists(absolute)) {
2710b57cec5SDimitry Andric path.append(absolute.begin(), absolute.end());
2720b57cec5SDimitry Andric } else {
2730b57cec5SDimitry Andric path.append(resolved.begin(), resolved.end());
2740b57cec5SDimitry Andric }
2750b57cec5SDimitry Andric }
2760b57cec5SDimitry Andric
Resolve(FileSpec & file_spec)2770b57cec5SDimitry Andric void FileSystem::Resolve(FileSpec &file_spec) {
2785ffd83dbSDimitry Andric if (!file_spec)
2795ffd83dbSDimitry Andric return;
2805ffd83dbSDimitry Andric
2810b57cec5SDimitry Andric // Extract path from the FileSpec.
2820b57cec5SDimitry Andric SmallString<128> path;
2830b57cec5SDimitry Andric file_spec.GetPath(path);
2840b57cec5SDimitry Andric
2850b57cec5SDimitry Andric // Resolve the path.
2860b57cec5SDimitry Andric Resolve(path);
2870b57cec5SDimitry Andric
2880b57cec5SDimitry Andric // Update the FileSpec with the resolved path.
2890b57cec5SDimitry Andric if (file_spec.GetFilename().IsEmpty())
2900b57cec5SDimitry Andric file_spec.GetDirectory().SetString(path);
2910b57cec5SDimitry Andric else
2920b57cec5SDimitry Andric file_spec.SetPath(path);
2930b57cec5SDimitry Andric file_spec.SetIsResolved(true);
2940b57cec5SDimitry Andric }
2950b57cec5SDimitry Andric
2960b57cec5SDimitry Andric std::shared_ptr<DataBufferLLVM>
CreateDataBuffer(const llvm::Twine & path,uint64_t size,uint64_t offset)2970b57cec5SDimitry Andric FileSystem::CreateDataBuffer(const llvm::Twine &path, uint64_t size,
2980b57cec5SDimitry Andric uint64_t offset) {
2995ffd83dbSDimitry Andric Collect(path);
3000b57cec5SDimitry Andric
3010b57cec5SDimitry Andric const bool is_volatile = !IsLocal(path);
3020b57cec5SDimitry Andric const ErrorOr<std::string> external_path = GetExternalPath(path);
3030b57cec5SDimitry Andric
3040b57cec5SDimitry Andric if (!external_path)
3050b57cec5SDimitry Andric return nullptr;
3060b57cec5SDimitry Andric
3070b57cec5SDimitry Andric std::unique_ptr<llvm::WritableMemoryBuffer> buffer;
3080b57cec5SDimitry Andric if (size == 0) {
3090b57cec5SDimitry Andric auto buffer_or_error =
310*5f7ddb14SDimitry Andric llvm::WritableMemoryBuffer::getFile(*external_path, is_volatile);
3110b57cec5SDimitry Andric if (!buffer_or_error)
3120b57cec5SDimitry Andric return nullptr;
3130b57cec5SDimitry Andric buffer = std::move(*buffer_or_error);
3140b57cec5SDimitry Andric } else {
3150b57cec5SDimitry Andric auto buffer_or_error = llvm::WritableMemoryBuffer::getFileSlice(
3160b57cec5SDimitry Andric *external_path, size, offset, is_volatile);
3170b57cec5SDimitry Andric if (!buffer_or_error)
3180b57cec5SDimitry Andric return nullptr;
3190b57cec5SDimitry Andric buffer = std::move(*buffer_or_error);
3200b57cec5SDimitry Andric }
3210b57cec5SDimitry Andric return std::shared_ptr<DataBufferLLVM>(new DataBufferLLVM(std::move(buffer)));
3220b57cec5SDimitry Andric }
3230b57cec5SDimitry Andric
3240b57cec5SDimitry Andric std::shared_ptr<DataBufferLLVM>
CreateDataBuffer(const FileSpec & file_spec,uint64_t size,uint64_t offset)3250b57cec5SDimitry Andric FileSystem::CreateDataBuffer(const FileSpec &file_spec, uint64_t size,
3260b57cec5SDimitry Andric uint64_t offset) {
3270b57cec5SDimitry Andric return CreateDataBuffer(file_spec.GetPath(), size, offset);
3280b57cec5SDimitry Andric }
3290b57cec5SDimitry Andric
ResolveExecutableLocation(FileSpec & file_spec)3300b57cec5SDimitry Andric bool FileSystem::ResolveExecutableLocation(FileSpec &file_spec) {
3310b57cec5SDimitry Andric // If the directory is set there's nothing to do.
3320b57cec5SDimitry Andric ConstString directory = file_spec.GetDirectory();
3330b57cec5SDimitry Andric if (directory)
3340b57cec5SDimitry Andric return false;
3350b57cec5SDimitry Andric
3360b57cec5SDimitry Andric // We cannot look for a file if there's no file name.
3370b57cec5SDimitry Andric ConstString filename = file_spec.GetFilename();
3380b57cec5SDimitry Andric if (!filename)
3390b57cec5SDimitry Andric return false;
3400b57cec5SDimitry Andric
3410b57cec5SDimitry Andric // Search for the file on the host.
3420b57cec5SDimitry Andric const std::string filename_str(filename.GetCString());
3430b57cec5SDimitry Andric llvm::ErrorOr<std::string> error_or_path =
3440b57cec5SDimitry Andric llvm::sys::findProgramByName(filename_str);
3450b57cec5SDimitry Andric if (!error_or_path)
3460b57cec5SDimitry Andric return false;
3470b57cec5SDimitry Andric
3480b57cec5SDimitry Andric // findProgramByName returns "." if it can't find the file.
3490b57cec5SDimitry Andric llvm::StringRef path = *error_or_path;
3500b57cec5SDimitry Andric llvm::StringRef parent = llvm::sys::path::parent_path(path);
3510b57cec5SDimitry Andric if (parent.empty() || parent == ".")
3520b57cec5SDimitry Andric return false;
3530b57cec5SDimitry Andric
3540b57cec5SDimitry Andric // Make sure that the result exists.
3550b57cec5SDimitry Andric FileSpec result(*error_or_path);
3560b57cec5SDimitry Andric if (!Exists(result))
3570b57cec5SDimitry Andric return false;
3580b57cec5SDimitry Andric
3590b57cec5SDimitry Andric file_spec = result;
3600b57cec5SDimitry Andric return true;
3610b57cec5SDimitry Andric }
3620b57cec5SDimitry Andric
GetHomeDirectory(SmallVectorImpl<char> & path) const363af732203SDimitry Andric bool FileSystem::GetHomeDirectory(SmallVectorImpl<char> &path) const {
364af732203SDimitry Andric if (!m_home_directory.empty()) {
365af732203SDimitry Andric path.assign(m_home_directory.begin(), m_home_directory.end());
366af732203SDimitry Andric return true;
367af732203SDimitry Andric }
368af732203SDimitry Andric return llvm::sys::path::home_directory(path);
369af732203SDimitry Andric }
370af732203SDimitry Andric
GetHomeDirectory(FileSpec & file_spec) const371af732203SDimitry Andric bool FileSystem::GetHomeDirectory(FileSpec &file_spec) const {
372af732203SDimitry Andric SmallString<128> home_dir;
373af732203SDimitry Andric if (!GetHomeDirectory(home_dir))
374af732203SDimitry Andric return false;
375af732203SDimitry Andric file_spec.SetPath(home_dir);
376af732203SDimitry Andric return true;
377af732203SDimitry Andric }
378af732203SDimitry Andric
OpenWithFS(const FileSystem & fs,const char * path,int flags,int mode)3790b57cec5SDimitry Andric static int OpenWithFS(const FileSystem &fs, const char *path, int flags,
3800b57cec5SDimitry Andric int mode) {
3810b57cec5SDimitry Andric return const_cast<FileSystem &>(fs).Open(path, flags, mode);
3820b57cec5SDimitry Andric }
3830b57cec5SDimitry Andric
GetOpenFlags(uint32_t options)3840b57cec5SDimitry Andric static int GetOpenFlags(uint32_t options) {
3850b57cec5SDimitry Andric const bool read = options & File::eOpenOptionRead;
3860b57cec5SDimitry Andric const bool write = options & File::eOpenOptionWrite;
3870b57cec5SDimitry Andric
3880b57cec5SDimitry Andric int open_flags = 0;
3890b57cec5SDimitry Andric if (write) {
3900b57cec5SDimitry Andric if (read)
3910b57cec5SDimitry Andric open_flags |= O_RDWR;
3920b57cec5SDimitry Andric else
3930b57cec5SDimitry Andric open_flags |= O_WRONLY;
3940b57cec5SDimitry Andric
3950b57cec5SDimitry Andric if (options & File::eOpenOptionAppend)
3960b57cec5SDimitry Andric open_flags |= O_APPEND;
3970b57cec5SDimitry Andric
3980b57cec5SDimitry Andric if (options & File::eOpenOptionTruncate)
3990b57cec5SDimitry Andric open_flags |= O_TRUNC;
4000b57cec5SDimitry Andric
4010b57cec5SDimitry Andric if (options & File::eOpenOptionCanCreate)
4020b57cec5SDimitry Andric open_flags |= O_CREAT;
4030b57cec5SDimitry Andric
4040b57cec5SDimitry Andric if (options & File::eOpenOptionCanCreateNewOnly)
4050b57cec5SDimitry Andric open_flags |= O_CREAT | O_EXCL;
4060b57cec5SDimitry Andric } else if (read) {
4070b57cec5SDimitry Andric open_flags |= O_RDONLY;
4080b57cec5SDimitry Andric
4090b57cec5SDimitry Andric #ifndef _WIN32
4100b57cec5SDimitry Andric if (options & File::eOpenOptionDontFollowSymlinks)
4110b57cec5SDimitry Andric open_flags |= O_NOFOLLOW;
4120b57cec5SDimitry Andric #endif
4130b57cec5SDimitry Andric }
4140b57cec5SDimitry Andric
4150b57cec5SDimitry Andric #ifndef _WIN32
4160b57cec5SDimitry Andric if (options & File::eOpenOptionNonBlocking)
4170b57cec5SDimitry Andric open_flags |= O_NONBLOCK;
4180b57cec5SDimitry Andric if (options & File::eOpenOptionCloseOnExec)
4190b57cec5SDimitry Andric open_flags |= O_CLOEXEC;
4200b57cec5SDimitry Andric #else
4210b57cec5SDimitry Andric open_flags |= O_BINARY;
4220b57cec5SDimitry Andric #endif
4230b57cec5SDimitry Andric
4240b57cec5SDimitry Andric return open_flags;
4250b57cec5SDimitry Andric }
4260b57cec5SDimitry Andric
GetOpenMode(uint32_t permissions)4270b57cec5SDimitry Andric static mode_t GetOpenMode(uint32_t permissions) {
4280b57cec5SDimitry Andric mode_t mode = 0;
4290b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsUserRead)
4300b57cec5SDimitry Andric mode |= S_IRUSR;
4310b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsUserWrite)
4320b57cec5SDimitry Andric mode |= S_IWUSR;
4330b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsUserExecute)
4340b57cec5SDimitry Andric mode |= S_IXUSR;
4350b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsGroupRead)
4360b57cec5SDimitry Andric mode |= S_IRGRP;
4370b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsGroupWrite)
4380b57cec5SDimitry Andric mode |= S_IWGRP;
4390b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsGroupExecute)
4400b57cec5SDimitry Andric mode |= S_IXGRP;
4410b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsWorldRead)
4420b57cec5SDimitry Andric mode |= S_IROTH;
4430b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsWorldWrite)
4440b57cec5SDimitry Andric mode |= S_IWOTH;
4450b57cec5SDimitry Andric if (permissions & lldb::eFilePermissionsWorldExecute)
4460b57cec5SDimitry Andric mode |= S_IXOTH;
4470b57cec5SDimitry Andric return mode;
4480b57cec5SDimitry Andric }
4490b57cec5SDimitry Andric
Open(const FileSpec & file_spec,File::OpenOptions options,uint32_t permissions,bool should_close_fd)4509dba64beSDimitry Andric Expected<FileUP> FileSystem::Open(const FileSpec &file_spec,
4519dba64beSDimitry Andric File::OpenOptions options,
4520b57cec5SDimitry Andric uint32_t permissions, bool should_close_fd) {
4535ffd83dbSDimitry Andric Collect(file_spec.GetPath());
4540b57cec5SDimitry Andric
4550b57cec5SDimitry Andric const int open_flags = GetOpenFlags(options);
4560b57cec5SDimitry Andric const mode_t open_mode =
4570b57cec5SDimitry Andric (open_flags & O_CREAT) ? GetOpenMode(permissions) : 0;
4580b57cec5SDimitry Andric
4590b57cec5SDimitry Andric auto path = GetExternalPath(file_spec);
4600b57cec5SDimitry Andric if (!path)
4619dba64beSDimitry Andric return errorCodeToError(path.getError());
4620b57cec5SDimitry Andric
4630b57cec5SDimitry Andric int descriptor = llvm::sys::RetryAfterSignal(
4640b57cec5SDimitry Andric -1, OpenWithFS, *this, path->c_str(), open_flags, open_mode);
4650b57cec5SDimitry Andric
4669dba64beSDimitry Andric if (!File::DescriptorIsValid(descriptor))
4679dba64beSDimitry Andric return llvm::errorCodeToError(
4689dba64beSDimitry Andric std::error_code(errno, std::system_category()));
4699dba64beSDimitry Andric
4709dba64beSDimitry Andric auto file = std::unique_ptr<File>(
4719dba64beSDimitry Andric new NativeFile(descriptor, options, should_close_fd));
4729dba64beSDimitry Andric assert(file->IsValid());
4739dba64beSDimitry Andric return std::move(file);
4740b57cec5SDimitry Andric }
4750b57cec5SDimitry Andric
GetExternalPath(const llvm::Twine & path)4760b57cec5SDimitry Andric ErrorOr<std::string> FileSystem::GetExternalPath(const llvm::Twine &path) {
4770b57cec5SDimitry Andric if (!m_mapped)
4780b57cec5SDimitry Andric return path.str();
4790b57cec5SDimitry Andric
4800b57cec5SDimitry Andric // If VFS mapped we know the underlying FS is a RedirectingFileSystem.
481*5f7ddb14SDimitry Andric ErrorOr<vfs::RedirectingFileSystem::LookupResult> Result =
482af732203SDimitry Andric static_cast<vfs::RedirectingFileSystem &>(*m_fs).lookupPath(path.str());
483*5f7ddb14SDimitry Andric if (!Result) {
484*5f7ddb14SDimitry Andric if (Result.getError() == llvm::errc::no_such_file_or_directory) {
4850b57cec5SDimitry Andric return path.str();
4860b57cec5SDimitry Andric }
487*5f7ddb14SDimitry Andric return Result.getError();
4880b57cec5SDimitry Andric }
4890b57cec5SDimitry Andric
490*5f7ddb14SDimitry Andric if (Optional<StringRef> ExtRedirect = Result->getExternalRedirect())
491*5f7ddb14SDimitry Andric return std::string(*ExtRedirect);
4920b57cec5SDimitry Andric return make_error_code(llvm::errc::not_supported);
4930b57cec5SDimitry Andric }
4940b57cec5SDimitry Andric
GetExternalPath(const FileSpec & file_spec)4950b57cec5SDimitry Andric ErrorOr<std::string> FileSystem::GetExternalPath(const FileSpec &file_spec) {
4960b57cec5SDimitry Andric return GetExternalPath(file_spec.GetPath());
4970b57cec5SDimitry Andric }
4985ffd83dbSDimitry Andric
Collect(const FileSpec & file_spec)4995ffd83dbSDimitry Andric void FileSystem::Collect(const FileSpec &file_spec) {
5005ffd83dbSDimitry Andric Collect(file_spec.GetPath());
5015ffd83dbSDimitry Andric }
5025ffd83dbSDimitry Andric
Collect(const llvm::Twine & file)5035ffd83dbSDimitry Andric void FileSystem::Collect(const llvm::Twine &file) {
5045ffd83dbSDimitry Andric if (!m_collector)
5055ffd83dbSDimitry Andric return;
5065ffd83dbSDimitry Andric
5075ffd83dbSDimitry Andric if (llvm::sys::fs::is_directory(file))
5085ffd83dbSDimitry Andric m_collector->addDirectory(file);
5095ffd83dbSDimitry Andric else
5105ffd83dbSDimitry Andric m_collector->addFile(file);
5115ffd83dbSDimitry Andric }
512af732203SDimitry Andric
SetHomeDirectory(std::string home_directory)513af732203SDimitry Andric void FileSystem::SetHomeDirectory(std::string home_directory) {
514af732203SDimitry Andric m_home_directory = std::move(home_directory);
515af732203SDimitry Andric }
516