forked from OSchip/llvm-project
433 lines
16 KiB
C++
433 lines
16 KiB
C++
//===-- File.h --------------------------------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef liblldb_File_h_
|
|
#define liblldb_File_h_
|
|
|
|
#include "lldb/Host/PosixApi.h"
|
|
#include "lldb/Utility/IOObject.h"
|
|
#include "lldb/Utility/Status.h"
|
|
#include "lldb/lldb-private.h"
|
|
|
|
#include <mutex>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
|
|
namespace lldb_private {
|
|
|
|
//----------------------------------------------------------------------
|
|
/// \class File File.h "lldb/Host/File.h"
|
|
/// A file class.
|
|
///
|
|
/// A file class that divides abstracts the LLDB core from host file
|
|
/// functionality.
|
|
//----------------------------------------------------------------------
|
|
class File : public IOObject {
|
|
public:
|
|
static int kInvalidDescriptor;
|
|
static FILE *kInvalidStream;
|
|
|
|
// NB this enum is used in the lldb platform gdb-remote packet
|
|
// vFile:open: and existing values cannot be modified.
|
|
enum OpenOptions {
|
|
eOpenOptionRead = (1u << 0), // Open file for reading
|
|
eOpenOptionWrite = (1u << 1), // Open file for writing
|
|
eOpenOptionAppend =
|
|
(1u << 2), // Don't truncate file when opening, append to end of file
|
|
eOpenOptionTruncate = (1u << 3), // Truncate file when opening
|
|
eOpenOptionNonBlocking = (1u << 4), // File reads
|
|
eOpenOptionCanCreate = (1u << 5), // Create file if doesn't already exist
|
|
eOpenOptionCanCreateNewOnly =
|
|
(1u << 6), // Can create file only if it doesn't already exist
|
|
eOpenOptionDontFollowSymlinks = (1u << 7),
|
|
eOpenOptionCloseOnExec =
|
|
(1u << 8) // Close the file when executing a new process
|
|
};
|
|
|
|
static mode_t ConvertOpenOptionsForPOSIXOpen(uint32_t open_options);
|
|
|
|
File()
|
|
: 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),
|
|
m_supports_colors(eLazyBoolCalculate) {}
|
|
|
|
File(FILE *fh, bool transfer_ownership)
|
|
: IOObject(eFDTypeFile, false), m_descriptor(kInvalidDescriptor),
|
|
m_stream(fh), m_options(0), m_own_stream(transfer_ownership),
|
|
m_is_interactive(eLazyBoolCalculate),
|
|
m_is_real_terminal(eLazyBoolCalculate),
|
|
m_supports_colors(eLazyBoolCalculate) {}
|
|
|
|
File(int fd, bool transfer_ownership)
|
|
: IOObject(eFDTypeFile, transfer_ownership), m_descriptor(fd),
|
|
m_stream(kInvalidStream), m_options(0), m_own_stream(false),
|
|
m_is_interactive(eLazyBoolCalculate),
|
|
m_is_real_terminal(eLazyBoolCalculate) {}
|
|
|
|
//------------------------------------------------------------------
|
|
/// Destructor.
|
|
///
|
|
/// The destructor is virtual in case this class is subclassed.
|
|
//------------------------------------------------------------------
|
|
~File() override;
|
|
|
|
bool IsValid() const override {
|
|
return DescriptorIsValid() || StreamIsValid();
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
/// Convert to pointer operator.
|
|
///
|
|
/// This allows code to check a File object to see if it contains anything
|
|
/// valid using code such as:
|
|
///
|
|
/// \code
|
|
/// File file(...);
|
|
/// if (file)
|
|
/// { ...
|
|
/// \endcode
|
|
///
|
|
/// \return
|
|
/// A pointer to this object if either the directory or filename
|
|
/// is valid, nullptr otherwise.
|
|
//------------------------------------------------------------------
|
|
operator bool() const { return DescriptorIsValid() || StreamIsValid(); }
|
|
|
|
//------------------------------------------------------------------
|
|
/// Logical NOT operator.
|
|
///
|
|
/// This allows code to check a File object to see if it is invalid using
|
|
/// code such as:
|
|
///
|
|
/// \code
|
|
/// File file(...);
|
|
/// if (!file)
|
|
/// { ...
|
|
/// \endcode
|
|
///
|
|
/// \return
|
|
/// Returns \b true if the object has an empty directory and
|
|
/// filename, \b false otherwise.
|
|
//------------------------------------------------------------------
|
|
bool operator!() const { return !DescriptorIsValid() && !StreamIsValid(); }
|
|
|
|
//------------------------------------------------------------------
|
|
/// Get the file spec for this file.
|
|
///
|
|
/// \return
|
|
/// A reference to the file specification object.
|
|
//------------------------------------------------------------------
|
|
Status GetFileSpec(FileSpec &file_spec) const;
|
|
|
|
Status Close() override;
|
|
|
|
void Clear();
|
|
|
|
int GetDescriptor() const;
|
|
|
|
WaitableHandle GetWaitableHandle() override;
|
|
|
|
void SetDescriptor(int fd, bool transfer_ownership);
|
|
|
|
FILE *GetStream();
|
|
|
|
void SetStream(FILE *fh, bool transfer_ownership);
|
|
|
|
//------------------------------------------------------------------
|
|
/// Read bytes from a file from the current file position.
|
|
///
|
|
/// NOTE: This function is NOT thread safe. Use the read function
|
|
/// that takes an "off_t &offset" to ensure correct operation in multi-
|
|
/// threaded environments.
|
|
///
|
|
/// \param[in] buf
|
|
/// A buffer where to put the bytes that are read.
|
|
///
|
|
/// \param[in,out] num_bytes
|
|
/// The number of bytes to read form the current file position
|
|
/// which gets modified with the number of bytes that were read.
|
|
///
|
|
/// \return
|
|
/// An error object that indicates success or the reason for
|
|
/// failure.
|
|
//------------------------------------------------------------------
|
|
Status Read(void *buf, size_t &num_bytes) override;
|
|
|
|
//------------------------------------------------------------------
|
|
/// Write bytes to a file at the current file position.
|
|
///
|
|
/// NOTE: This function is NOT thread safe. Use the write function
|
|
/// that takes an "off_t &offset" to ensure correct operation in multi-
|
|
/// threaded environments.
|
|
///
|
|
/// \param[in] buf
|
|
/// A buffer where to put the bytes that are read.
|
|
///
|
|
/// \param[in,out] num_bytes
|
|
/// The number of bytes to write to the current file position
|
|
/// which gets modified with the number of bytes that were
|
|
/// written.
|
|
///
|
|
/// \return
|
|
/// An error object that indicates success or the reason for
|
|
/// failure.
|
|
//------------------------------------------------------------------
|
|
Status Write(const void *buf, size_t &num_bytes) override;
|
|
|
|
//------------------------------------------------------------------
|
|
/// Seek to an offset relative to the beginning of the file.
|
|
///
|
|
/// NOTE: This function is NOT thread safe, other threads that
|
|
/// access this object might also change the current file position. For
|
|
/// thread safe reads and writes see the following functions: @see
|
|
/// File::Read (void *, size_t, off_t &) \see File::Write (const void *,
|
|
/// size_t, off_t &)
|
|
///
|
|
/// \param[in] offset
|
|
/// The offset to seek to within the file relative to the
|
|
/// beginning of the file.
|
|
///
|
|
/// \param[in] error_ptr
|
|
/// A pointer to a lldb_private::Status object that will be
|
|
/// filled in if non-nullptr.
|
|
///
|
|
/// \return
|
|
/// The resulting seek offset, or -1 on error.
|
|
//------------------------------------------------------------------
|
|
off_t SeekFromStart(off_t offset, Status *error_ptr = nullptr);
|
|
|
|
//------------------------------------------------------------------
|
|
/// Seek to an offset relative to the current file position.
|
|
///
|
|
/// NOTE: This function is NOT thread safe, other threads that
|
|
/// access this object might also change the current file position. For
|
|
/// thread safe reads and writes see the following functions: @see
|
|
/// File::Read (void *, size_t, off_t &) \see File::Write (const void *,
|
|
/// size_t, off_t &)
|
|
///
|
|
/// \param[in] offset
|
|
/// The offset to seek to within the file relative to the
|
|
/// current file position.
|
|
///
|
|
/// \param[in] error_ptr
|
|
/// A pointer to a lldb_private::Status object that will be
|
|
/// filled in if non-nullptr.
|
|
///
|
|
/// \return
|
|
/// The resulting seek offset, or -1 on error.
|
|
//------------------------------------------------------------------
|
|
off_t SeekFromCurrent(off_t offset, Status *error_ptr = nullptr);
|
|
|
|
//------------------------------------------------------------------
|
|
/// Seek to an offset relative to the end of the file.
|
|
///
|
|
/// NOTE: This function is NOT thread safe, other threads that
|
|
/// access this object might also change the current file position. For
|
|
/// thread safe reads and writes see the following functions: @see
|
|
/// File::Read (void *, size_t, off_t &) \see File::Write (const void *,
|
|
/// size_t, off_t &)
|
|
///
|
|
/// \param[in,out] offset
|
|
/// The offset to seek to within the file relative to the
|
|
/// end of the file which gets filled in with the resulting
|
|
/// absolute file offset.
|
|
///
|
|
/// \param[in] error_ptr
|
|
/// A pointer to a lldb_private::Status object that will be
|
|
/// filled in if non-nullptr.
|
|
///
|
|
/// \return
|
|
/// The resulting seek offset, or -1 on error.
|
|
//------------------------------------------------------------------
|
|
off_t SeekFromEnd(off_t offset, Status *error_ptr = nullptr);
|
|
|
|
//------------------------------------------------------------------
|
|
/// Read bytes from a file from the specified file offset.
|
|
///
|
|
/// NOTE: This function is thread safe in that clients manager their
|
|
/// own file position markers and reads on other threads won't mess up the
|
|
/// current read.
|
|
///
|
|
/// \param[in] dst
|
|
/// A buffer where to put the bytes that are read.
|
|
///
|
|
/// \param[in,out] num_bytes
|
|
/// The number of bytes to read form the current file position
|
|
/// which gets modified with the number of bytes that were read.
|
|
///
|
|
/// \param[in,out] offset
|
|
/// The offset within the file from which to read \a num_bytes
|
|
/// bytes. This offset gets incremented by the number of bytes
|
|
/// that were read.
|
|
///
|
|
/// \return
|
|
/// An error object that indicates success or the reason for
|
|
/// failure.
|
|
//------------------------------------------------------------------
|
|
Status Read(void *dst, size_t &num_bytes, off_t &offset);
|
|
|
|
//------------------------------------------------------------------
|
|
/// Read bytes from a file from the specified file offset.
|
|
///
|
|
/// NOTE: This function is thread safe in that clients manager their
|
|
/// own file position markers and reads on other threads won't mess up the
|
|
/// current read.
|
|
///
|
|
/// \param[in,out] num_bytes
|
|
/// The number of bytes to read form the current file position
|
|
/// which gets modified with the number of bytes that were read.
|
|
///
|
|
/// \param[in,out] offset
|
|
/// The offset within the file from which to read \a num_bytes
|
|
/// bytes. This offset gets incremented by the number of bytes
|
|
/// that were read.
|
|
///
|
|
/// \param[in] null_terminate
|
|
/// Ensure that the data that is read is terminated with a NULL
|
|
/// character so that the data can be used as a C string.
|
|
///
|
|
/// \param[out] data_buffer_sp
|
|
/// A data buffer to create and fill in that will contain any
|
|
/// data that is read from the file. This buffer will be reset
|
|
/// if an error occurs.
|
|
///
|
|
/// \return
|
|
/// An error object that indicates success or the reason for
|
|
/// failure.
|
|
//------------------------------------------------------------------
|
|
Status Read(size_t &num_bytes, off_t &offset, bool null_terminate,
|
|
lldb::DataBufferSP &data_buffer_sp);
|
|
|
|
//------------------------------------------------------------------
|
|
/// Write bytes to a file at the specified file offset.
|
|
///
|
|
/// NOTE: This function is thread safe in that clients manager their
|
|
/// own file position markers, though clients will need to implement their
|
|
/// own locking externally to avoid multiple people writing to the file at
|
|
/// the same time.
|
|
///
|
|
/// \param[in] src
|
|
/// A buffer containing the bytes to write.
|
|
///
|
|
/// \param[in,out] num_bytes
|
|
/// The number of bytes to write to the file at offset \a offset.
|
|
/// \a num_bytes gets modified with the number of bytes that
|
|
/// were read.
|
|
///
|
|
/// \param[in,out] offset
|
|
/// The offset within the file at which to write \a num_bytes
|
|
/// bytes. This offset gets incremented by the number of bytes
|
|
/// that were written.
|
|
///
|
|
/// \return
|
|
/// An error object that indicates success or the reason for
|
|
/// failure.
|
|
//------------------------------------------------------------------
|
|
Status Write(const void *src, size_t &num_bytes, off_t &offset);
|
|
|
|
//------------------------------------------------------------------
|
|
/// Flush the current stream
|
|
///
|
|
/// \return
|
|
/// An error object that indicates success or the reason for
|
|
/// failure.
|
|
//------------------------------------------------------------------
|
|
Status Flush();
|
|
|
|
//------------------------------------------------------------------
|
|
/// Sync to disk.
|
|
///
|
|
/// \return
|
|
/// An error object that indicates success or the reason for
|
|
/// failure.
|
|
//------------------------------------------------------------------
|
|
Status Sync();
|
|
|
|
//------------------------------------------------------------------
|
|
/// Get the permissions for a this file.
|
|
///
|
|
/// \return
|
|
/// Bits logical OR'ed together from the permission bits defined
|
|
/// in lldb_private::File::Permissions.
|
|
//------------------------------------------------------------------
|
|
uint32_t GetPermissions(Status &error) const;
|
|
|
|
//------------------------------------------------------------------
|
|
/// Return true if this file is interactive.
|
|
///
|
|
/// \return
|
|
/// True if this file is a terminal (tty or pty), false
|
|
/// otherwise.
|
|
//------------------------------------------------------------------
|
|
bool GetIsInteractive();
|
|
|
|
//------------------------------------------------------------------
|
|
/// Return true if this file from a real terminal.
|
|
///
|
|
/// Just knowing a file is a interactive isn't enough, we also need to know
|
|
/// if the terminal has a width and height so we can do cursor movement and
|
|
/// other terminal manipulations by sending escape sequences.
|
|
///
|
|
/// \return
|
|
/// True if this file is a terminal (tty, not a pty) that has
|
|
/// a non-zero width and height, false otherwise.
|
|
//------------------------------------------------------------------
|
|
bool GetIsRealTerminal();
|
|
|
|
bool GetIsTerminalWithColors();
|
|
|
|
//------------------------------------------------------------------
|
|
/// Output printf formatted output to the stream.
|
|
///
|
|
/// Print some formatted output to the stream.
|
|
///
|
|
/// \param[in] format
|
|
/// A printf style format string.
|
|
///
|
|
/// \param[in] ...
|
|
/// Variable arguments that are needed for the printf style
|
|
/// format string \a format.
|
|
//------------------------------------------------------------------
|
|
size_t Printf(const char *format, ...) __attribute__((format(printf, 2, 3)));
|
|
|
|
size_t PrintfVarArg(const char *format, va_list args);
|
|
|
|
void SetOptions(uint32_t options) { m_options = options; }
|
|
|
|
static bool DescriptorIsValid(int descriptor) { return descriptor >= 0; };
|
|
|
|
protected:
|
|
bool DescriptorIsValid() const { return DescriptorIsValid(m_descriptor); }
|
|
|
|
bool StreamIsValid() const { return m_stream != kInvalidStream; }
|
|
|
|
void CalculateInteractiveAndTerminal();
|
|
|
|
//------------------------------------------------------------------
|
|
// Member variables
|
|
//------------------------------------------------------------------
|
|
int m_descriptor;
|
|
FILE *m_stream;
|
|
uint32_t m_options;
|
|
bool m_own_stream;
|
|
LazyBool m_is_interactive;
|
|
LazyBool m_is_real_terminal;
|
|
LazyBool m_supports_colors;
|
|
std::mutex offset_access_mutex;
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(File);
|
|
};
|
|
|
|
} // namespace lldb_private
|
|
|
|
#endif // liblldb_File_h_
|