| //===-- 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_ |