[FileSystem] Open File instances through the FileSystem.

This patch modifies how we open File instances in LLDB. Rather than
passing a path or FileSpec to the constructor, we now go through the
virtual file system. This is needed in order to make things work with
the VFS in the future.

Differential revision: https://reviews.llvm.org/D54020

llvm-svn: 346049
This commit is contained in:
Jonas Devlieghere 2018-11-02 22:34:51 +00:00
parent d1932dcdd3
commit 50bc1ed290
19 changed files with 199 additions and 220 deletions

View File

@ -64,50 +64,6 @@ public:
m_is_real_terminal(eLazyBoolCalculate),
m_supports_colors(eLazyBoolCalculate) {}
//------------------------------------------------------------------
/// Constructor with path.
///
/// Takes a path to a file which can be just a filename, or a full path. If
/// \a path is not nullptr or empty, this function will call File::Open
/// (const char *path, uint32_t options, uint32_t permissions).
///
/// @param[in] path
/// The full or partial path to a file.
///
/// @param[in] options
/// Options to use when opening (see File::OpenOptions)
///
/// @param[in] permissions
/// Options to use when opening (see File::Permissions)
///
/// @see File::Open (const char *path, uint32_t options, uint32_t
/// permissions)
//------------------------------------------------------------------
File(const char *path, uint32_t options,
uint32_t permissions = lldb::eFilePermissionsFileDefault);
//------------------------------------------------------------------
/// Constructor with FileSpec.
///
/// Takes a FileSpec pointing to a file which can be just a filename, or a
/// full path. If \a path is not nullptr or empty, this function will call
/// File::Open (const char *path, uint32_t options, uint32_t permissions).
///
/// @param[in] filespec
/// The FileSpec for this file.
///
/// @param[in] options
/// Options to use when opening (see File::OpenOptions)
///
/// @param[in] permissions
/// Options to use when opening (see File::Permissions)
///
/// @see File::Open (const char *path, uint32_t options, uint32_t
/// permissions)
//------------------------------------------------------------------
File(const FileSpec &filespec, uint32_t options,
uint32_t permissions = lldb::eFilePermissionsFileDefault);
File(int fd, bool transfer_ownership)
: IOObject(eFDTypeFile, transfer_ownership), m_descriptor(fd),
m_stream(kInvalidStream), m_options(0), m_own_stream(false),
@ -169,23 +125,6 @@ public:
//------------------------------------------------------------------
Status GetFileSpec(FileSpec &file_spec) const;
//------------------------------------------------------------------
/// Open a file for read/writing with the specified options.
///
/// Takes a path to a file which can be just a filename, or a full path.
///
/// @param[in] path
/// The full or partial path to a file.
///
/// @param[in] options
/// Options to use when opening (see File::OpenOptions)
///
/// @param[in] permissions
/// Options to use when opening (see File::Permissions)
//------------------------------------------------------------------
Status Open(const char *path, uint32_t options,
uint32_t permissions = lldb::eFilePermissionsFileDefault);
Status Close() override;
void Clear();
@ -461,8 +400,10 @@ public:
void SetOptions(uint32_t options) { m_options = options; }
static bool DescriptorIsValid(int descriptor) { return descriptor >= 0; };
protected:
bool DescriptorIsValid() const { return m_descriptor >= 0; }
bool DescriptorIsValid() const { return DescriptorIsValid(m_descriptor); }
bool StreamIsValid() const { return m_stream != kInvalidStream; }

View File

@ -10,6 +10,7 @@
#ifndef liblldb_Host_FileSystem_h
#define liblldb_Host_FileSystem_h
#include "lldb/Host/File.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/Status.h"
@ -49,6 +50,9 @@ public:
/// Wraps ::open in a platform-independent way.
int Open(const char *path, int flags, int mode);
Status Open(File &File, const FileSpec &file_spec, uint32_t options,
uint32_t permissions = lldb::eFilePermissionsFileDefault);
/// Returns the modification time of the given file.
/// @{
llvm::sys::TimePoint<> GetModificationTime(const FileSpec &file_spec) const;

View File

@ -10,6 +10,7 @@
#include "lldb/API/SBStream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/StreamString.h"
@ -70,9 +71,9 @@ void SBStream::RedirectToFile(const char *path, bool append) {
open_options |= File::eOpenOptionAppend;
else
open_options |= File::eOpenOptionTruncate;
stream_file->GetFile().Open(path, open_options,
lldb::eFilePermissionsFileDefault);
FileSystem::Instance().Open(stream_file->GetFile(), FileSpec(path),
open_options);
m_opaque_ap.reset(stream_file);
if (m_opaque_ap.get()) {

View File

@ -72,8 +72,6 @@ protected:
const FileSpec &outfile_spec =
m_outfile_options.GetFile().GetCurrentValue();
if (outfile_spec) {
char path[PATH_MAX];
outfile_spec.GetPath(path, sizeof(path));
uint32_t open_options =
File::eOpenOptionWrite | File::eOpenOptionCanCreate |
@ -84,10 +82,13 @@ protected:
open_options |= File::eOpenOptionTruncate;
StreamFileSP outfile_stream = std::make_shared<StreamFile>();
Status error = outfile_stream->GetFile().Open(path, open_options);
File &file = outfile_stream->GetFile();
Status error =
FileSystem::Instance().Open(file, outfile_spec, open_options);
if (error.Fail()) {
auto path = outfile_spec.GetPath();
result.AppendErrorWithFormat("Failed to open file '%s' for %s: %s\n",
path, append ? "append" : "write",
path.c_str(), append ? "append" : "write",
error.AsCString());
result.SetStatus(eReturnStatusFailed);
return false;

View File

@ -762,9 +762,9 @@ protected:
Stream *output_stream = nullptr;
const FileSpec &outfile_spec =
m_outfile_options.GetFile().GetCurrentValue();
std::string path = outfile_spec.GetPath();
if (outfile_spec) {
char path[PATH_MAX];
outfile_spec.GetPath(path, sizeof(path));
uint32_t open_options =
File::eOpenOptionWrite | File::eOpenOptionCanCreate;
@ -772,19 +772,21 @@ protected:
if (append)
open_options |= File::eOpenOptionAppend;
if (outfile_stream.GetFile().Open(path, open_options).Success()) {
Status error = FileSystem::Instance().Open(outfile_stream.GetFile(),
outfile_spec, open_options);
if (error.Success()) {
if (m_memory_options.m_output_as_binary) {
const size_t bytes_written =
outfile_stream.Write(data_sp->GetBytes(), bytes_read);
if (bytes_written > 0) {
result.GetOutputStream().Printf(
"%zi bytes %s to '%s'\n", bytes_written,
append ? "appended" : "written", path);
append ? "appended" : "written", path.c_str());
return true;
} else {
result.AppendErrorWithFormat("Failed to write %" PRIu64
" bytes to '%s'.\n",
(uint64_t)bytes_read, path);
(uint64_t)bytes_read, path.c_str());
result.SetStatus(eReturnStatusFailed);
return false;
}
@ -794,8 +796,8 @@ protected:
output_stream = &outfile_stream;
}
} else {
result.AppendErrorWithFormat("Failed to open file '%s' for %s.\n", path,
append ? "append" : "write");
result.AppendErrorWithFormat("Failed to open file '%s' for %s.\n",
path.c_str(), append ? "append" : "write");
result.SetStatus(eReturnStatusFailed);
return false;
}

View File

@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/Core/StreamFile.h"
#include "lldb/Host/FileSystem.h"
#include <stdio.h>
@ -28,14 +29,18 @@ StreamFile::StreamFile(int fd, bool transfer_ownership)
StreamFile::StreamFile(FILE *fh, bool transfer_ownership)
: Stream(), m_file(fh, transfer_ownership) {}
StreamFile::StreamFile(const char *path)
: Stream(),
m_file(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate |
File::eOpenOptionCloseOnExec,
lldb::eFilePermissionsFileDefault) {}
StreamFile::StreamFile(const char *path) : Stream(), m_file() {
FileSystem::Instance().Open(m_file, FileSpec(path),
File::eOpenOptionWrite |
File::eOpenOptionCanCreate |
File::eOpenOptionCloseOnExec);
}
StreamFile::StreamFile(const char *path, uint32_t options, uint32_t permissions)
: Stream(), m_file(path, options, permissions) {}
: Stream(), m_file() {
FileSystem::Instance().Open(m_file, FileSpec(path), options, permissions);
}
StreamFile::~StreamFile() {}

View File

@ -416,7 +416,8 @@ void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) {
// Update our code on disk
if (!m_repl_source_path.empty()) {
lldb_private::File file(m_repl_source_path.c_str(),
lldb_private::File file;
FileSystem::Instance().Open(file, FileSpec(m_repl_source_path),
File::eOpenOptionWrite |
File::eOpenOptionTruncate |
File::eOpenOptionCanCreate,

View File

@ -72,26 +72,6 @@ static const char *GetStreamOpenModeFromOptions(uint32_t options) {
int File::kInvalidDescriptor = -1;
FILE *File::kInvalidStream = NULL;
File::File(const char *path, uint32_t options, uint32_t permissions)
: IOObject(eFDTypeFile, false), m_descriptor(kInvalidDescriptor),
m_stream(kInvalidStream), m_options(), m_own_stream(false),
m_is_interactive(eLazyBoolCalculate),
m_is_real_terminal(eLazyBoolCalculate) {
Open(path, options, permissions);
}
File::File(const FileSpec &filespec, uint32_t options, uint32_t permissions)
: IOObject(eFDTypeFile, false), m_descriptor(kInvalidDescriptor),
m_stream(kInvalidStream), m_options(0), m_own_stream(false),
m_is_interactive(eLazyBoolCalculate),
m_is_real_terminal(eLazyBoolCalculate)
{
if (filespec) {
Open(filespec.GetPath().c_str(), options, permissions);
}
}
File::~File() { Close(); }
int File::GetDescriptor() const {
@ -160,86 +140,6 @@ void File::SetStream(FILE *fh, bool transfer_ownership) {
m_own_stream = transfer_ownership;
}
static int DoOpen(const char *path, int flags, int mode) {
return FileSystem::Instance().Open(path, flags, mode);
}
Status File::Open(const char *path, uint32_t options, uint32_t permissions) {
Status error;
if (IsValid())
Close();
int oflag = 0;
const bool read = options & eOpenOptionRead;
const bool write = options & eOpenOptionWrite;
if (write) {
if (read)
oflag |= O_RDWR;
else
oflag |= O_WRONLY;
if (options & eOpenOptionAppend)
oflag |= O_APPEND;
if (options & eOpenOptionTruncate)
oflag |= O_TRUNC;
if (options & eOpenOptionCanCreate)
oflag |= O_CREAT;
if (options & eOpenOptionCanCreateNewOnly)
oflag |= O_CREAT | O_EXCL;
} else if (read) {
oflag |= O_RDONLY;
#ifndef _WIN32
if (options & eOpenOptionDontFollowSymlinks)
oflag |= O_NOFOLLOW;
#endif
}
#ifndef _WIN32
if (options & eOpenOptionNonBlocking)
oflag |= O_NONBLOCK;
if (options & eOpenOptionCloseOnExec)
oflag |= O_CLOEXEC;
#else
oflag |= O_BINARY;
#endif
mode_t mode = 0;
if (oflag & O_CREAT) {
if (permissions & lldb::eFilePermissionsUserRead)
mode |= S_IRUSR;
if (permissions & lldb::eFilePermissionsUserWrite)
mode |= S_IWUSR;
if (permissions & lldb::eFilePermissionsUserExecute)
mode |= S_IXUSR;
if (permissions & lldb::eFilePermissionsGroupRead)
mode |= S_IRGRP;
if (permissions & lldb::eFilePermissionsGroupWrite)
mode |= S_IWGRP;
if (permissions & lldb::eFilePermissionsGroupExecute)
mode |= S_IXGRP;
if (permissions & lldb::eFilePermissionsWorldRead)
mode |= S_IROTH;
if (permissions & lldb::eFilePermissionsWorldWrite)
mode |= S_IWOTH;
if (permissions & lldb::eFilePermissionsWorldExecute)
mode |= S_IXOTH;
}
m_descriptor = llvm::sys::RetryAfterSignal(-1, DoOpen, path, oflag, mode);
if (!DescriptorIsValid())
error.SetErrorToErrno();
else {
m_should_close_fd = true;
m_options = options;
}
return error;
}
uint32_t File::GetPermissions(Status &error) const {
int fd = GetDescriptor();
if (fd != kInvalidDescriptor) {

View File

@ -10,6 +10,7 @@
#include "lldb/Host/FileCache.h"
#include "lldb/Host/File.h"
#include "lldb/Host/FileSystem.h"
using namespace lldb;
using namespace lldb_private;
@ -25,13 +26,12 @@ FileCache &FileCache::GetInstance() {
lldb::user_id_t FileCache::OpenFile(const FileSpec &file_spec, uint32_t flags,
uint32_t mode, Status &error) {
std::string path(file_spec.GetPath());
if (path.empty()) {
if (!file_spec) {
error.SetErrorString("empty path");
return UINT64_MAX;
}
FileSP file_sp(new File());
error = file_sp->Open(path.c_str(), flags, mode);
error = FileSystem::Instance().Open(*file_sp, file_spec, flags, mode);
if (file_sp->IsValid() == false)
return UINT64_MAX;
lldb::user_id_t fd = file_sp->GetDescriptor();

View File

@ -12,11 +12,27 @@
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/TildeExpressionResolver.h"
#include "llvm/Support/Errno.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Threading.h"
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#ifdef _WIN32
#include "lldb/Host/windows/windows.h"
#else
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <termios.h>
#include <unistd.h>
#endif
#include <algorithm>
#include <fstream>
#include <vector>
@ -223,3 +239,98 @@ bool FileSystem::ResolveExecutableLocation(FileSpec &file_spec) {
file_spec = result;
return true;
}
static int OpenWithFS(const FileSystem &fs, const char *path, int flags,
int mode) {
return const_cast<FileSystem &>(fs).Open(path, flags, mode);
}
static int GetOpenFlags(uint32_t options) {
const bool read = options & File::eOpenOptionRead;
const bool write = options & File::eOpenOptionWrite;
int open_flags = 0;
if (write) {
if (read)
open_flags |= O_RDWR;
else
open_flags |= O_WRONLY;
if (options & File::eOpenOptionAppend)
open_flags |= O_APPEND;
if (options & File::eOpenOptionTruncate)
open_flags |= O_TRUNC;
if (options & File::eOpenOptionCanCreate)
open_flags |= O_CREAT;
if (options & File::eOpenOptionCanCreateNewOnly)
open_flags |= O_CREAT | O_EXCL;
} else if (read) {
open_flags |= O_RDONLY;
#ifndef _WIN32
if (options & File::eOpenOptionDontFollowSymlinks)
open_flags |= O_NOFOLLOW;
#endif
}
#ifndef _WIN32
if (options & File::eOpenOptionNonBlocking)
open_flags |= O_NONBLOCK;
if (options & File::eOpenOptionCloseOnExec)
open_flags |= O_CLOEXEC;
#else
open_flags |= O_BINARY;
#endif
return open_flags;
}
static mode_t GetOpenMode(uint32_t permissions) {
mode_t mode = 0;
if (permissions & lldb::eFilePermissionsUserRead)
mode |= S_IRUSR;
if (permissions & lldb::eFilePermissionsUserWrite)
mode |= S_IWUSR;
if (permissions & lldb::eFilePermissionsUserExecute)
mode |= S_IXUSR;
if (permissions & lldb::eFilePermissionsGroupRead)
mode |= S_IRGRP;
if (permissions & lldb::eFilePermissionsGroupWrite)
mode |= S_IWGRP;
if (permissions & lldb::eFilePermissionsGroupExecute)
mode |= S_IXGRP;
if (permissions & lldb::eFilePermissionsWorldRead)
mode |= S_IROTH;
if (permissions & lldb::eFilePermissionsWorldWrite)
mode |= S_IWOTH;
if (permissions & lldb::eFilePermissionsWorldExecute)
mode |= S_IXOTH;
return mode;
}
Status FileSystem::Open(File &File, const FileSpec &file_spec, uint32_t options,
uint32_t permissions) {
if (File.IsValid())
File.Close();
const int open_flags = GetOpenFlags(options);
const mode_t open_mode =
(open_flags & O_CREAT) ? GetOpenMode(permissions) : 0;
const std::string path = file_spec.GetPath();
int descriptor = llvm::sys::RetryAfterSignal(
-1, OpenWithFS, *this, path.c_str(), open_flags, open_mode);
Status error;
if (!File::DescriptorIsValid(descriptor)) {
File.SetDescriptor(descriptor, false);
error.SetErrorToErrno();
} else {
File.SetDescriptor(descriptor, true);
File.SetOptions(options);
}
return error;
}

View File

@ -430,7 +430,6 @@ void CommandInterpreter::Initialize() {
AddAlias("var", cmd_obj_sp);
AddAlias("vo", cmd_obj_sp, "--object-description");
}
}
void CommandInterpreter::Clear() {
@ -2357,9 +2356,8 @@ void CommandInterpreter::HandleCommandsFromFile(
StreamFileSP input_file_sp(new StreamFile());
std::string cmd_file_path = cmd_file.GetPath();
Status error = input_file_sp->GetFile().Open(cmd_file_path.c_str(),
File::eOpenOptionRead);
Status error = FileSystem::Instance().Open(input_file_sp->GetFile(),
cmd_file, File::eOpenOptionRead);
if (error.Success()) {
Debugger &debugger = GetDebugger();

View File

@ -2756,8 +2756,12 @@ bool RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id,
// Check we can create writable file
FileSpec file_spec(path);
FileSystem::Instance().Resolve(file_spec);
File file(file_spec, File::eOpenOptionWrite | File::eOpenOptionCanCreate |
File file;
FileSystem::Instance().Open(file, file_spec,
File::eOpenOptionWrite |
File::eOpenOptionCanCreate |
File::eOpenOptionTruncate);
if (!file) {
strm.Printf("Error: Failed to open '%s' for writing", path);
strm.EOL();
@ -4710,16 +4714,17 @@ public:
m_options.m_outfile; // Dump allocation to file instead
if (outfile_spec) {
// Open output file
char path[256];
outfile_spec.GetPath(path, sizeof(path));
if (outfile_stream.GetFile()
.Open(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate)
.Success()) {
std::string path = outfile_spec.GetPath();
auto error = FileSystem::Instance().Open(
outfile_stream.GetFile(), outfile_spec,
File::eOpenOptionWrite | File::eOpenOptionCanCreate);
if (error.Success()) {
output_strm = &outfile_stream;
result.GetOutputStream().Printf("Results written to '%s'", path);
result.GetOutputStream().Printf("Results written to '%s'",
path.c_str());
result.GetOutputStream().EOL();
} else {
result.AppendErrorWithFormat("Couldn't open file '%s'", path);
result.AppendErrorWithFormat("Couldn't open file '%s'", path.c_str());
result.SetStatus(eReturnStatusFailed);
return false;
}

View File

@ -6324,7 +6324,7 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp,
File core_file;
std::string core_file_path(outfile.GetPath());
error = core_file.Open(core_file_path.c_str(),
error = FileSystem::Instance().Open(core_file, outfile,
File::eOpenOptionWrite |
File::eOpenOptionTruncate |
File::eOpenOptionCanCreate);

View File

@ -101,8 +101,9 @@ namespace lldb {
// and get the packet history dumped to a file.
void DumpProcessGDBRemotePacketHistory(void *p, const char *path) {
StreamFile strm;
Status error(strm.GetFile().Open(path, File::eOpenOptionWrite |
File::eOpenOptionCanCreate));
Status error = FileSystem::Instance().Open(strm.GetFile(), FileSpec(path),
File::eOpenOptionWrite |
File::eOpenOptionCanCreate);
if (error.Success())
((ProcessGDBRemote *)p)->GetGDBRemote().DumpHistory(strm);
}

View File

@ -939,7 +939,8 @@ PythonFile::PythonFile() : PythonObject() {}
PythonFile::PythonFile(File &file, const char *mode) { Reset(file, mode); }
PythonFile::PythonFile(const char *path, const char *mode) {
lldb_private::File file(path, GetOptionsFromMode(mode));
lldb_private::File file;
FileSystem::Instance().Open(file, FileSpec(path), GetOptionsFromMode(mode));
Reset(file, mode);
}

View File

@ -829,11 +829,15 @@ bool ScriptInterpreterPython::ExecuteOneLine(
error_file_sp);
} else {
input_file_sp.reset(new StreamFile());
input_file_sp->GetFile().Open(FileSystem::DEV_NULL,
FileSystem::Instance().Open(input_file_sp->GetFile(),
FileSpec(FileSystem::DEV_NULL),
File::eOpenOptionRead);
output_file_sp.reset(new StreamFile());
output_file_sp->GetFile().Open(FileSystem::DEV_NULL,
FileSystem::Instance().Open(output_file_sp->GetFile(),
FileSpec(FileSystem::DEV_NULL),
File::eOpenOptionWrite);
error_file_sp = output_file_sp;
}

View File

@ -159,7 +159,8 @@ ModuleLock::ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid,
return;
m_file_spec = JoinPath(lock_dir_spec, uuid.GetAsString().c_str());
m_file.Open(m_file_spec.GetCString(), File::eOpenOptionWrite |
FileSystem::Instance().Open(m_file, m_file_spec,
File::eOpenOptionWrite |
File::eOpenOptionCanCreate |
File::eOpenOptionCloseOnExec);
if (!m_file) {

View File

@ -1280,8 +1280,9 @@ Status Platform::PutFile(const FileSpec &source, const FileSpec &destination,
if (fs::is_symlink_file(source.GetPath()))
source_open_options |= File::eOpenOptionDontFollowSymlinks;
File source_file(source, source_open_options, lldb::eFilePermissionsUserRW);
Status error;
File source_file;
Status error = FileSystem::Instance().Open(
source_file, source, source_open_options, lldb::eFilePermissionsUserRW);
uint32_t permissions = source_file.GetPermissions(error);
if (permissions == 0)
permissions = lldb::eFilePermissionsFileDefault;

View File

@ -557,7 +557,9 @@ TEST_F(PythonDataObjectsTest, TestPythonCallableInvoke) {
}
TEST_F(PythonDataObjectsTest, TestPythonFile) {
File file(FileSystem::DEV_NULL, File::eOpenOptionRead);
File file;
FileSystem::Instance().Open(file, FileSpec(FileSystem::DEV_NULL),
File::eOpenOptionRead);
PythonFile py_file(file, "r");
EXPECT_TRUE(PythonFile::Check(py_file.get()));
}