diff options
Diffstat (limited to 'include/lldb/Host/File.h')
-rw-r--r-- | include/lldb/Host/File.h | 358 |
1 files changed, 203 insertions, 155 deletions
diff --git a/include/lldb/Host/File.h b/include/lldb/Host/File.h index eb28c4ada0e71..0102beb141ee3 100644 --- a/include/lldb/Host/File.h +++ b/include/lldb/Host/File.h @@ -13,6 +13,7 @@ #include "lldb/Utility/IOObject.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-private.h" +#include "llvm/ADT/BitmaskEnum.h" #include <mutex> #include <stdarg.h> @@ -21,11 +22,15 @@ namespace lldb_private { +LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); + /// \class File File.h "lldb/Host/File.h" -/// A file class. +/// An abstract base class for files. /// -/// A file class that divides abstracts the LLDB core from host file -/// functionality. +/// Files will often be NativeFiles, which provides a wrapper +/// around host OS file functionality. But it +/// is also possible to subclass file to provide objects that have file +/// or stream functionality but are not backed by any host OS file. class File : public IOObject { public: static int kInvalidDescriptor; @@ -33,7 +38,12 @@ public: // NB this enum is used in the lldb platform gdb-remote packet // vFile:open: and existing values cannot be modified. - enum OpenOptions { + // + // FIXME + // These values do not match the values used by GDB + // * https://sourceware.org/gdb/onlinedocs/gdb/Open-Flags.html#Open-Flags + // * rdar://problem/46788934 + enum OpenOptions : uint32_t { eOpenOptionRead = (1u << 0), // Open file for reading eOpenOptionWrite = (1u << 1), // Open file for writing eOpenOptionAppend = @@ -45,128 +55,105 @@ public: (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 + (1u << 8), // Close the file when executing a new process + LLVM_MARK_AS_BITMASK_ENUM(/* largest_value= */ eOpenOptionCloseOnExec) }; - static mode_t ConvertOpenOptionsForPOSIXOpen(uint32_t open_options); + static mode_t ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options); + static llvm::Expected<OpenOptions> GetOptionsFromMode(llvm::StringRef mode); + static bool DescriptorIsValid(int descriptor) { return descriptor >= 0; }; + static llvm::Expected<const char *> + GetStreamOpenModeFromOptions(OpenOptions options); File() - : IOObject(eFDTypeFile, false), m_descriptor(kInvalidDescriptor), - m_stream(kInvalidStream), m_options(0), m_own_stream(false), - m_is_interactive(eLazyBoolCalculate), + : IOObject(eFDTypeFile), 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) {} + m_supports_colors(eLazyBoolCalculate){}; - /// Destructor. + /// Read bytes from a file from the current file position into buf. /// - /// The destructor is virtual in case this class is subclassed. - ~File() override; - - bool IsValid() const override { - return DescriptorIsValid() || StreamIsValid(); - } - - /// Convert to pointer operator. + /// 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. /// - /// This allows code to check a File object to see if it contains anything - /// valid using code such as: + /// \param[out] buf /// - /// \code - /// File file(...); - /// if (file) - /// { ... - /// \endcode + /// \param[in,out] num_bytes. + /// Pass in the size of buf. Read will pass out the number + /// of bytes read. Zero bytes read with no error indicates + /// EOF. /// /// \return - /// A pointer to this object if either the directory or filename - /// is valid, nullptr otherwise. - operator bool() const { return DescriptorIsValid() || StreamIsValid(); } + /// success, ENOTSUP, or another error. + Status Read(void *buf, size_t &num_bytes) override; - /// Logical NOT operator. + /// Write bytes from buf to a file at the current file position. /// - /// This allows code to check a File object to see if it is invalid using - /// code such as: + /// 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 /// - /// \code - /// File file(...); - /// if (!file) - /// { ... - /// \endcode + /// \param[in,out] num_bytes + /// Pass in the size of buf. Write will pass out the number + /// of bytes written. Write will attempt write the full number + /// of bytes and will not return early except on error. /// /// \return - /// Returns \b true if the object has an empty directory and - /// filename, \b false otherwise. - bool operator!() const { return !DescriptorIsValid() && !StreamIsValid(); } + /// success, ENOTSUP, or another error. + Status Write(const void *buf, size_t &num_bytes) override; - /// Get the file spec for this file. + /// IsValid /// /// \return - /// A reference to the file specification object. - Status GetFileSpec(FileSpec &file_spec) const; + /// true iff the file is valid. + bool IsValid() const override; + /// Flush any buffers and release any resources owned by the file. + /// After Close() the file will be invalid. + /// + /// \return + /// success or an error. Status Close() override; - void Clear(); - - int GetDescriptor() const; - + /// Get a handle that can be used for OS polling interfaces, such + /// as WaitForMultipleObjects, select, or epoll. This may return + /// IOObject::kInvalidHandleValue if none is available. This will + /// generally be the same as the file descriptor, this function + /// is not interchangeable with GetDescriptor(). A WaitableHandle + /// must only be used for polling, not actual I/O. + /// + /// \return + /// a valid handle or IOObject::kInvalidHandleValue 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. + /// Get the file specification for this file, if possible. /// + /// \param[out] file_spec + /// the file specification. /// \return - /// An error object that indicates success or the reason for - /// failure. - Status Read(void *buf, size_t &num_bytes) override; + /// ENOTSUP, success, or another error. + virtual Status GetFileSpec(FileSpec &file_spec) const; - /// 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. + /// Get underlying OS file descriptor for this file, or kInvalidDescriptor. + /// If the descriptor is valid, then it may be used directly for I/O + /// However, the File may also perform it's own buffering, so avoid using + /// this if it is not necessary, or use Flush() appropriately. /// - /// \param[in] buf - /// A buffer where to put the bytes that are read. + /// \return + /// a valid file descriptor for this file or kInvalidDescriptor + virtual int GetDescriptor() const; + + /// Get the underlying libc stream for this file, or NULL. /// - /// \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. + /// Not all valid files will have a FILE* stream. This should only be + /// used if absolutely necessary, such as to interact with 3rd party + /// libraries that need FILE* streams. /// /// \return - /// An error object that indicates success or the reason for - /// failure. - Status Write(const void *buf, size_t &num_bytes) override; + /// a valid stream or NULL; + virtual FILE *GetStream(); /// Seek to an offset relative to the beginning of the file. /// @@ -186,7 +173,7 @@ public: /// /// \return /// The resulting seek offset, or -1 on error. - off_t SeekFromStart(off_t offset, Status *error_ptr = nullptr); + virtual off_t SeekFromStart(off_t offset, Status *error_ptr = nullptr); /// Seek to an offset relative to the current file position. /// @@ -206,7 +193,7 @@ public: /// /// \return /// The resulting seek offset, or -1 on error. - off_t SeekFromCurrent(off_t offset, Status *error_ptr = nullptr); + virtual off_t SeekFromCurrent(off_t offset, Status *error_ptr = nullptr); /// Seek to an offset relative to the end of the file. /// @@ -227,7 +214,7 @@ public: /// /// \return /// The resulting seek offset, or -1 on error. - off_t SeekFromEnd(off_t offset, Status *error_ptr = nullptr); + virtual off_t SeekFromEnd(off_t offset, Status *error_ptr = nullptr); /// Read bytes from a file from the specified file offset. /// @@ -250,37 +237,7 @@ public: /// \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); + virtual Status Read(void *dst, size_t &num_bytes, off_t &offset); /// Write bytes to a file at the specified file offset. /// @@ -305,21 +262,67 @@ public: /// \return /// An error object that indicates success or the reason for /// failure. - Status Write(const void *src, size_t &num_bytes, off_t &offset); + virtual 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(); + virtual Status Flush(); /// Sync to disk. /// /// \return /// An error object that indicates success or the reason for /// failure. - Status Sync(); + virtual Status Sync(); + + /// Output printf formatted output to the stream. + /// + /// NOTE: this is not virtual, because it just calls the va_list + /// version of the function. + /// + /// 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))); + + /// Output printf formatted output to the stream. + /// + /// Print some formatted output to the stream. + /// + /// \param[in] format + /// A printf style format string. + /// + /// \param[in] args + /// Variable arguments that are needed for the printf style + /// format string \a format. + virtual size_t PrintfVarArg(const char *format, va_list args); + + /// Return the OpenOptions for this file. + /// + /// Some options like eOpenOptionDontFollowSymlinks only make + /// sense when a file is being opened (or not at all) + /// and may not be preserved for this method. But any valid + /// File should return either or both of eOpenOptionRead and + /// eOpenOptionWrite here. + /// + /// \return + /// OpenOptions flags for this file, or an error. + virtual llvm::Expected<OpenOptions> GetOptions() const; + + llvm::Expected<const char *> GetOpenMode() const { + auto opts = GetOptions(); + if (!opts) + return opts.takeError(); + return GetStreamOpenModeFromOptions(opts.get()); + } /// Get the permissions for a this file. /// @@ -346,45 +349,90 @@ public: /// 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. + /// Return true if this file is a terminal which supports colors. /// - /// \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))); + /// \return + /// True iff this is a terminal and it supports colors. + bool GetIsTerminalWithColors(); - size_t PrintfVarArg(const char *format, va_list args); + operator bool() const { return IsValid(); }; - void SetOptions(uint32_t options) { m_options = options; } + bool operator!() const { return !IsValid(); }; - static bool DescriptorIsValid(int descriptor) { return descriptor >= 0; }; + static char ID; + virtual bool isA(const void *classID) const { return classID == &ID; } + static bool classof(const File *file) { return file->isA(&ID); } protected: - bool DescriptorIsValid() const { return DescriptorIsValid(m_descriptor); } - - bool StreamIsValid() const { return m_stream != kInvalidStream; } + LazyBool m_is_interactive; + LazyBool m_is_real_terminal; + LazyBool m_supports_colors; void CalculateInteractiveAndTerminal(); +private: + DISALLOW_COPY_AND_ASSIGN(File); +}; + +class NativeFile : public File { +public: + NativeFile() + : m_descriptor(kInvalidDescriptor), m_own_descriptor(false), + m_stream(kInvalidStream), m_options(), m_own_stream(false) {} + + NativeFile(FILE *fh, bool transfer_ownership) + : m_descriptor(kInvalidDescriptor), m_own_descriptor(false), m_stream(fh), + m_options(), m_own_stream(transfer_ownership) {} + + NativeFile(int fd, OpenOptions options, bool transfer_ownership) + : m_descriptor(fd), m_own_descriptor(transfer_ownership), + m_stream(kInvalidStream), m_options(options), m_own_stream(false) {} + + ~NativeFile() override { Close(); } + + bool IsValid() const override { + return DescriptorIsValid() || StreamIsValid(); + } + + Status Read(void *buf, size_t &num_bytes) override; + Status Write(const void *buf, size_t &num_bytes) override; + Status Close() override; + WaitableHandle GetWaitableHandle() override; + Status GetFileSpec(FileSpec &file_spec) const override; + int GetDescriptor() const override; + FILE *GetStream() override; + off_t SeekFromStart(off_t offset, Status *error_ptr = nullptr) override; + off_t SeekFromCurrent(off_t offset, Status *error_ptr = nullptr) override; + off_t SeekFromEnd(off_t offset, Status *error_ptr = nullptr) override; + Status Read(void *dst, size_t &num_bytes, off_t &offset) override; + Status Write(const void *src, size_t &num_bytes, off_t &offset) override; + Status Flush() override; + Status Sync() override; + size_t PrintfVarArg(const char *format, va_list args) override; + llvm::Expected<OpenOptions> GetOptions() const override; + + static char ID; + virtual bool isA(const void *classID) const override { + return classID == &ID || File::isA(classID); + } + static bool classof(const File *file) { return file->isA(&ID); } + +protected: + bool DescriptorIsValid() const { + return File::DescriptorIsValid(m_descriptor); + } + bool StreamIsValid() const { return m_stream != kInvalidStream; } + // Member variables int m_descriptor; + bool m_own_descriptor; FILE *m_stream; - uint32_t m_options; + OpenOptions 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); + DISALLOW_COPY_AND_ASSIGN(NativeFile); }; } // namespace lldb_private |