File.h   [plain text]


//===-- File.h --------------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef liblldb_File_h_
#define liblldb_File_h_
#if defined(__cplusplus)

#include <stdio.h>

#include "lldb/lldb-private.h"

namespace lldb_private {

//----------------------------------------------------------------------
/// @class File File.h "lldb/Host/File.h"
/// @brief A file class.
///
/// A file class that divides abstracts the LLDB core from host file
/// functionality.
//----------------------------------------------------------------------
class File
{
public:
    static int kInvalidDescriptor;
    static FILE * kInvalidStream;

    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
    };
    
    enum Permissions
    {
        ePermissionsUserRead        = (1u << 0),
        ePermissionsUserWrite       = (1u << 1),
        ePermissionsUserExecute     = (1u << 2),
        ePermissionsGroupRead       = (1u << 3),
        ePermissionsGroupWrite      = (1u << 4),
        ePermissionsGroupExecute    = (1u << 5),
        ePermissionsWorldRead       = (1u << 6),
        ePermissionsWorldWrite      = (1u << 7),
        ePermissionsWorldExecute    = (1u << 8),

        ePermissionsUserRW      = (ePermissionsUserRead    | ePermissionsUserWrite    | 0                        ),
        ePermissionsUserRX      = (ePermissionsUserRead    | 0                        | ePermissionsUserExecute  ),
        ePermissionsUserRWX     = (ePermissionsUserRead    | ePermissionsUserWrite    | ePermissionsUserExecute  ),

        ePermissionsGroupRW     = (ePermissionsGroupRead   | ePermissionsGroupWrite   | 0                        ),
        ePermissionsGroupRX     = (ePermissionsGroupRead   | 0                        | ePermissionsGroupExecute ),
        ePermissionsGroupRWX    = (ePermissionsGroupRead   | ePermissionsGroupWrite   | ePermissionsGroupExecute ),

        ePermissionsWorldRW     = (ePermissionsWorldRead   | ePermissionsWorldWrite   | 0                        ),
        ePermissionsWorldRX     = (ePermissionsWorldRead   | 0                        | ePermissionsWorldExecute ),
        ePermissionsWorldRWX    = (ePermissionsWorldRead   | ePermissionsWorldWrite   | ePermissionsWorldExecute ),

        ePermissionsEveryoneR   = (ePermissionsUserRead    | ePermissionsGroupRead    | ePermissionsWorldRead    ),
        ePermissionsEveryoneW   = (ePermissionsUserWrite   | ePermissionsGroupWrite   | ePermissionsWorldWrite   ),
        ePermissionsEveryoneX   = (ePermissionsUserExecute | ePermissionsGroupExecute | ePermissionsWorldExecute ),

        ePermissionsEveryoneRW  = (ePermissionsEveryoneR   | ePermissionsEveryoneW    | 0                        ),
        ePermissionsEveryoneRX  = (ePermissionsEveryoneR   | 0                        | ePermissionsEveryoneX    ),
        ePermissionsEveryoneRWX = (ePermissionsEveryoneR   | ePermissionsEveryoneW    | ePermissionsEveryoneX    ),
        ePermissionsDefault     = (ePermissionsUserRW      | ePermissionsGroupRead)
    };

    File() : 
        m_descriptor (kInvalidDescriptor),
        m_stream (kInvalidStream),
        m_options (0),
        m_owned (false)
    {
    }
    
    File (FILE *fh, bool transfer_ownership) :
        m_descriptor (kInvalidDescriptor),
        m_stream (fh),
        m_options (0),
        m_owned (transfer_ownership)
    {
    }

    File (const File &rhs);
    
    File &
    operator= (const File &rhs);
    //------------------------------------------------------------------
    /// Constructor with path.
    ///
    /// Takes a path to a file which can be just a filename, or a full
    /// path. If \a path is not NULL 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 = ePermissionsDefault);

    
    File (int fd, bool tranfer_ownership) : 
        m_descriptor (fd),
        m_stream (kInvalidStream),
        m_options (0),
        m_owned (tranfer_ownership)
    {
    }
    //------------------------------------------------------------------
    /// Destructor.
    ///
    /// The destructor is virtual in case this class is subclassed.
    //------------------------------------------------------------------
    virtual
    ~File ();

    bool
    IsValid () const
    {
        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, NULL 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.
    //------------------------------------------------------------------
    Error
    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)
    //------------------------------------------------------------------
    Error
    Open (const char *path,
          uint32_t options,
          uint32_t permissions = ePermissionsDefault);

    Error
    Close ();
    
    Error
    Duplicate (const File &rhs);

    int
    GetDescriptor() const;

    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.
    //------------------------------------------------------------------
    Error
    Read (void *buf, size_t &num_bytes);
          
    //------------------------------------------------------------------
    /// 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.
    //------------------------------------------------------------------
    Error
    Write (const void *buf, size_t &num_bytes);

    //------------------------------------------------------------------
    /// 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/out] offset
    ///     The offset to seek to within the file relative to the 
    ///     beginning of the file which gets filled in the the resulting
    ///     absolute file offset.
    ///
    /// @return
    ///     An error object that indicates success or the reason for 
    ///     failure.
    //------------------------------------------------------------------
    Error
    SeekFromStart (off_t& offset);
    
    //------------------------------------------------------------------
    /// 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/out] offset
    ///     The offset to seek to within the file relative to the 
    ///     current file position. On return this parameter gets filled 
    ///     in the the resulting absolute file offset.
    ///
    /// @return
    ///     An error object that indicates success or the reason for 
    ///     failure.
    //------------------------------------------------------------------
    Error
    SeekFromCurrent (off_t& offset);
    
    //------------------------------------------------------------------
    /// 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 the the resulting
    ///     absolute file offset.
    ///
    /// @return
    ///     An error object that indicates success or the reason for 
    ///     failure.
    //------------------------------------------------------------------
    Error
    SeekFromEnd (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] 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.
    ///
    /// @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.
    //------------------------------------------------------------------
    Error
    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.
    //------------------------------------------------------------------
    Error
    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] buf
    ///     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.
    //------------------------------------------------------------------
    Error
    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.
    //------------------------------------------------------------------
    Error
    Flush ();
    
    //------------------------------------------------------------------
    /// Sync to disk.
    ///
    /// @return
    ///     An error object that indicates success or the reason for 
    ///     failure.
    //------------------------------------------------------------------
    Error
    Sync ();

    //------------------------------------------------------------------
    /// 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.
    //------------------------------------------------------------------
    int
    Printf (const char *format, ...)  __attribute__ ((format (printf, 2, 3)));
    
    int
    PrintfVarArg(const char *format, va_list args);

protected:
    
    
    bool
    DescriptorIsValid () const
    {
        return m_descriptor >= 0;
    }

    bool
    StreamIsValid () const
    {
        return m_stream != kInvalidStream;
    }
    
    //------------------------------------------------------------------
    // Member variables
    //------------------------------------------------------------------
    int m_descriptor;
    FILE *m_stream;
    uint32_t m_options;
    bool m_owned;
};

} // namespace lldb_private

#endif  // #if defined(__cplusplus)
#endif  // liblldb_File_h_