| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438 |
- //===-- 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 LLDB_HOST_FILE_H
- #define LLDB_HOST_FILE_H
- #include "lldb/Host/PosixApi.h"
- #include "lldb/Utility/IOObject.h"
- #include "lldb/Utility/Status.h"
- #include "lldb/lldb-private.h"
- #include "llvm/ADT/BitmaskEnum.h"
- #include <cstdarg>
- #include <cstdio>
- #include <mutex>
- #include <sys/types.h>
- namespace lldb_private {
- LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
- /// \class File File.h "lldb/Host/File.h"
- /// An abstract base class for files.
- ///
- /// 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;
- static FILE *kInvalidStream;
- // NB this enum is used in the lldb platform gdb-remote packet
- // vFile:open: and existing values cannot be modified.
- //
- // 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 =
- (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
- LLVM_MARK_AS_BITMASK_ENUM(/* largest_value= */ eOpenOptionCloseOnExec)
- };
- 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), m_is_interactive(eLazyBoolCalculate),
- m_is_real_terminal(eLazyBoolCalculate),
- m_supports_colors(eLazyBoolCalculate){};
- /// Read bytes from a file from the current file position into buf.
- ///
- /// 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,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
- /// success, ENOTSUP, or another error.
- Status Read(void *buf, size_t &num_bytes) override;
- /// Write bytes from buf 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,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
- /// success, ENOTSUP, or another error.
- Status Write(const void *buf, size_t &num_bytes) override;
- /// IsValid
- ///
- /// \return
- /// 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;
- /// 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;
- /// Get the file specification for this file, if possible.
- ///
- /// \param[out] file_spec
- /// the file specification.
- /// \return
- /// ENOTSUP, success, or another error.
- virtual Status GetFileSpec(FileSpec &file_spec) const;
- /// 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.
- ///
- /// \return
- /// a valid file descriptor for this file or kInvalidDescriptor
- virtual int GetDescriptor() const;
- /// Get the underlying libc stream for this file, or NULL.
- ///
- /// 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
- /// a valid stream or NULL;
- virtual FILE *GetStream();
- /// 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.
- virtual 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.
- virtual 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.
- virtual 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.
- virtual Status Read(void *dst, size_t &num_bytes, off_t &offset);
- /// 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.
- 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.
- virtual Status Flush();
- /// Sync to disk.
- ///
- /// \return
- /// An error object that indicates success or the reason for
- /// failure.
- 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.
- ///
- /// \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();
- /// Return true if this file is a terminal which supports colors.
- ///
- /// \return
- /// True iff this is a terminal and it supports colors.
- bool GetIsTerminalWithColors();
- operator bool() const { return IsValid(); };
- bool operator!() const { return !IsValid(); };
- static char ID;
- virtual bool isA(const void *classID) const { return classID == &ID; }
- static bool classof(const File *file) { return file->isA(&ID); }
- protected:
- LazyBool m_is_interactive;
- LazyBool m_is_real_terminal;
- LazyBool m_supports_colors;
- void CalculateInteractiveAndTerminal();
- private:
- File(const File &) = delete;
- const File &operator=(const File &) = delete;
- };
- 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;
- OpenOptions m_options;
- bool m_own_stream;
- std::mutex offset_access_mutex;
- private:
- NativeFile(const NativeFile &) = delete;
- const NativeFile &operator=(const NativeFile &) = delete;
- };
- } // namespace lldb_private
- #endif // LLDB_HOST_FILE_H
|