summaryrefslogtreecommitdiffstats
path: root/source/Host/common/File.cpp
diff options
context:
space:
mode:
authoremaste <emaste@FreeBSD.org>2013-08-23 17:46:38 +0000
committeremaste <emaste@FreeBSD.org>2013-08-23 17:46:38 +0000
commitdcd15f81789e389c1cb27d264fcdddfd0a6002bd (patch)
treef561dabc721ad515599172c16da3a4400b7f4aec /source/Host/common/File.cpp
downloadFreeBSD-src-dcd15f81789e389c1cb27d264fcdddfd0a6002bd.zip
FreeBSD-src-dcd15f81789e389c1cb27d264fcdddfd0a6002bd.tar.gz
Import lldb as of SVN r188801
(A number of files not required for the FreeBSD build have been removed.) Sponsored by: DARPA, AFRL
Diffstat (limited to 'source/Host/common/File.cpp')
-rw-r--r--source/Host/common/File.cpp716
1 files changed, 716 insertions, 0 deletions
diff --git a/source/Host/common/File.cpp b/source/Host/common/File.cpp
new file mode 100644
index 0000000..c0d3c29
--- /dev/null
+++ b/source/Host/common/File.cpp
@@ -0,0 +1,716 @@
+//===-- FileSpec.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "lldb/Host/File.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Host/Config.h"
+#include "lldb/Host/FileSpec.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static const char *
+GetStreamOpenModeFromOptions (uint32_t options)
+{
+ if (options & File::eOpenOptionAppend)
+ {
+ if (options & File::eOpenOptionRead)
+ {
+ if (options & File::eOpenOptionCanCreateNewOnly)
+ return "a+x";
+ else
+ return "a+";
+ }
+ else if (options & File::eOpenOptionWrite)
+ {
+ if (options & File::eOpenOptionCanCreateNewOnly)
+ return "ax";
+ else
+ return "a";
+ }
+ }
+ else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite)
+ {
+ if (options & File::eOpenOptionCanCreate)
+ {
+ if (options & File::eOpenOptionCanCreateNewOnly)
+ return "w+x";
+ else
+ return "w+";
+ }
+ else
+ return "r+";
+ }
+ else if (options & File::eOpenOptionRead)
+ {
+ return "r";
+ }
+ else if (options & File::eOpenOptionWrite)
+ {
+ return "w";
+ }
+ return NULL;
+}
+
+int File::kInvalidDescriptor = -1;
+FILE * File::kInvalidStream = NULL;
+
+File::File(const char *path, uint32_t options, uint32_t permissions) :
+ m_descriptor (kInvalidDescriptor),
+ m_stream (kInvalidStream),
+ m_options (0),
+ m_owned (false)
+{
+ Open (path, options, permissions);
+}
+
+File::File (const File &rhs) :
+ m_descriptor (kInvalidDescriptor),
+ m_stream (kInvalidStream),
+ m_options (0),
+ m_owned (false)
+{
+ Duplicate (rhs);
+}
+
+
+File &
+File::operator = (const File &rhs)
+{
+ if (this != &rhs)
+ Duplicate (rhs);
+ return *this;
+}
+
+File::~File()
+{
+ Close ();
+}
+
+
+int
+File::GetDescriptor() const
+{
+ if (DescriptorIsValid())
+ return m_descriptor;
+
+ // Don't open the file descriptor if we don't need to, just get it from the
+ // stream if we have one.
+ if (StreamIsValid())
+ return fileno (m_stream);
+
+ // Invalid descriptor and invalid stream, return invalid descriptor.
+ return kInvalidDescriptor;
+}
+
+void
+File::SetDescriptor (int fd, bool transfer_ownership)
+{
+ if (IsValid())
+ Close();
+ m_descriptor = fd;
+ m_owned = transfer_ownership;
+}
+
+
+FILE *
+File::GetStream ()
+{
+ if (!StreamIsValid())
+ {
+ if (DescriptorIsValid())
+ {
+ const char *mode = GetStreamOpenModeFromOptions (m_options);
+ if (mode)
+ {
+ do
+ {
+ m_stream = ::fdopen (m_descriptor, mode);
+ } while (m_stream == NULL && errno == EINTR);
+ }
+ }
+ }
+ return m_stream;
+}
+
+
+void
+File::SetStream (FILE *fh, bool transfer_ownership)
+{
+ if (IsValid())
+ Close();
+ m_stream = fh;
+ m_owned = transfer_ownership;
+}
+
+Error
+File::Duplicate (const File &rhs)
+{
+ Error error;
+ if (IsValid ())
+ Close();
+
+ if (rhs.DescriptorIsValid())
+ {
+ m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD);
+ if (!DescriptorIsValid())
+ error.SetErrorToErrno();
+ else
+ {
+ m_options = rhs.m_options;
+ m_owned = true;
+ }
+ }
+ else
+ {
+ error.SetErrorString ("invalid file to duplicate");
+ }
+ return error;
+}
+
+Error
+File::Open (const char *path, uint32_t options, uint32_t permissions)
+{
+ Error error;
+ if (IsValid())
+ Close ();
+
+ int oflag = 0;
+ const bool read = options & eOpenOptionRead;
+ const bool write = options & eOpenOptionWrite;
+ if (write)
+ {
+ if (read)
+ oflag |= O_RDWR;
+ else
+ oflag |= O_WRONLY;
+
+ if (options & eOpenOptionAppend)
+ oflag |= O_APPEND;
+
+ if (options & eOpenOptionTruncate)
+ oflag |= O_TRUNC;
+
+ if (options & eOpenOptionCanCreate)
+ oflag |= O_CREAT;
+
+ if (options & eOpenOptionCanCreateNewOnly)
+ oflag |= O_CREAT | O_EXCL;
+ }
+ else if (read)
+ {
+ oflag |= O_RDONLY;
+ }
+
+ if (options & eOpenOptionNonBlocking)
+ oflag |= O_NONBLOCK;
+
+ mode_t mode = 0;
+ if (oflag & O_CREAT)
+ {
+ if (permissions & ePermissionsUserRead) mode |= S_IRUSR;
+ if (permissions & ePermissionsUserWrite) mode |= S_IWUSR;
+ if (permissions & ePermissionsUserExecute) mode |= S_IXUSR;
+ if (permissions & ePermissionsGroupRead) mode |= S_IRGRP;
+ if (permissions & ePermissionsGroupWrite) mode |= S_IWGRP;
+ if (permissions & ePermissionsGroupExecute) mode |= S_IXGRP;
+ if (permissions & ePermissionsWorldRead) mode |= S_IROTH;
+ if (permissions & ePermissionsWorldWrite) mode |= S_IWOTH;
+ if (permissions & ePermissionsWorldExecute) mode |= S_IXOTH;
+ }
+
+ do
+ {
+ m_descriptor = ::open(path, oflag, mode);
+ } while (m_descriptor < 0 && errno == EINTR);
+
+ if (!DescriptorIsValid())
+ error.SetErrorToErrno();
+ else
+ m_owned = true;
+
+ return error;
+}
+
+Error
+File::Close ()
+{
+ Error error;
+ if (IsValid ())
+ {
+ if (m_owned)
+ {
+ if (StreamIsValid())
+ {
+ if (::fclose (m_stream) == EOF)
+ error.SetErrorToErrno();
+ }
+
+ if (DescriptorIsValid())
+ {
+ if (::close (m_descriptor) != 0)
+ error.SetErrorToErrno();
+ }
+ }
+ m_descriptor = kInvalidDescriptor;
+ m_stream = kInvalidStream;
+ m_options = 0;
+ m_owned = false;
+ }
+ return error;
+}
+
+
+Error
+File::GetFileSpec (FileSpec &file_spec) const
+{
+ Error error;
+#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
+ if (IsValid ())
+ {
+ char path[PATH_MAX];
+ if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
+ error.SetErrorToErrno();
+ else
+ file_spec.SetFile (path, false);
+ }
+ else
+ {
+ error.SetErrorString("invalid file handle");
+ }
+#elif defined(__linux__)
+ char proc[64];
+ char path[PATH_MAX];
+ if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
+ error.SetErrorString ("cannot resolve file descriptor");
+ else
+ {
+ ssize_t len;
+ if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
+ error.SetErrorToErrno();
+ else
+ {
+ path[len] = '\0';
+ file_spec.SetFile (path, false);
+ }
+ }
+#else
+ error.SetErrorString ("File::GetFileSpec is not supported on this platform");
+#endif
+
+ if (error.Fail())
+ file_spec.Clear();
+ return error;
+}
+
+off_t
+File::SeekFromStart (off_t offset, Error *error_ptr)
+{
+ off_t result = 0;
+ if (DescriptorIsValid())
+ {
+ result = ::lseek (m_descriptor, offset, SEEK_SET);
+
+ if (error_ptr)
+ {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ }
+ else if (StreamIsValid ())
+ {
+ result = ::fseek(m_stream, offset, SEEK_SET);
+
+ if (error_ptr)
+ {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ }
+ else if (error_ptr)
+ {
+ error_ptr->SetErrorString("invalid file handle");
+ }
+ return result;
+}
+
+off_t
+File::SeekFromCurrent (off_t offset, Error *error_ptr)
+{
+ off_t result = -1;
+ if (DescriptorIsValid())
+ {
+ result = ::lseek (m_descriptor, offset, SEEK_CUR);
+
+ if (error_ptr)
+ {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ }
+ else if (StreamIsValid ())
+ {
+ result = ::fseek(m_stream, offset, SEEK_CUR);
+
+ if (error_ptr)
+ {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ }
+ else if (error_ptr)
+ {
+ error_ptr->SetErrorString("invalid file handle");
+ }
+ return result;
+}
+
+off_t
+File::SeekFromEnd (off_t offset, Error *error_ptr)
+{
+ off_t result = -1;
+ if (DescriptorIsValid())
+ {
+ result = ::lseek (m_descriptor, offset, SEEK_END);
+
+ if (error_ptr)
+ {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ }
+ else if (StreamIsValid ())
+ {
+ result = ::fseek(m_stream, offset, SEEK_END);
+
+ if (error_ptr)
+ {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ }
+ else if (error_ptr)
+ {
+ error_ptr->SetErrorString("invalid file handle");
+ }
+ return result;
+}
+
+Error
+File::Flush ()
+{
+ Error error;
+ if (StreamIsValid())
+ {
+ int err = 0;
+ do
+ {
+ err = ::fflush (m_stream);
+ } while (err == EOF && errno == EINTR);
+
+ if (err == EOF)
+ error.SetErrorToErrno();
+ }
+ else if (!DescriptorIsValid())
+ {
+ error.SetErrorString("invalid file handle");
+ }
+ return error;
+}
+
+
+Error
+File::Sync ()
+{
+ Error error;
+ if (DescriptorIsValid())
+ {
+ int err = 0;
+ do
+ {
+ err = ::fsync (m_descriptor);
+ } while (err == -1 && errno == EINTR);
+
+ if (err == -1)
+ error.SetErrorToErrno();
+ }
+ else
+ {
+ error.SetErrorString("invalid file handle");
+ }
+ return error;
+}
+
+Error
+File::Read (void *buf, size_t &num_bytes)
+{
+ Error error;
+ ssize_t bytes_read = -1;
+ if (DescriptorIsValid())
+ {
+ do
+ {
+ bytes_read = ::read (m_descriptor, buf, num_bytes);
+ } while (bytes_read < 0 && errno == EINTR);
+
+ if (bytes_read == -1)
+ {
+ error.SetErrorToErrno();
+ num_bytes = 0;
+ }
+ else
+ num_bytes = bytes_read;
+ }
+ else if (StreamIsValid())
+ {
+ bytes_read = ::fread (buf, 1, num_bytes, m_stream);
+
+ if (bytes_read == 0)
+ {
+ if (::feof(m_stream))
+ error.SetErrorString ("feof");
+ else if (::ferror (m_stream))
+ error.SetErrorString ("ferror");
+ num_bytes = 0;
+ }
+ else
+ num_bytes = bytes_read;
+ }
+ else
+ {
+ num_bytes = 0;
+ error.SetErrorString("invalid file handle");
+ }
+ return error;
+}
+
+Error
+File::Write (const void *buf, size_t &num_bytes)
+{
+ Error error;
+ ssize_t bytes_written = -1;
+ if (DescriptorIsValid())
+ {
+ do
+ {
+ bytes_written = ::write (m_descriptor, buf, num_bytes);
+ } while (bytes_written < 0 && errno == EINTR);
+
+ if (bytes_written == -1)
+ {
+ error.SetErrorToErrno();
+ num_bytes = 0;
+ }
+ else
+ num_bytes = bytes_written;
+ }
+ else if (StreamIsValid())
+ {
+ bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
+
+ if (bytes_written == 0)
+ {
+ if (::feof(m_stream))
+ error.SetErrorString ("feof");
+ else if (::ferror (m_stream))
+ error.SetErrorString ("ferror");
+ num_bytes = 0;
+ }
+ else
+ num_bytes = bytes_written;
+
+ }
+ else
+ {
+ num_bytes = 0;
+ error.SetErrorString("invalid file handle");
+ }
+ return error;
+}
+
+
+Error
+File::Read (void *buf, size_t &num_bytes, off_t &offset)
+{
+ Error error;
+ int fd = GetDescriptor();
+ if (fd != kInvalidDescriptor)
+ {
+ ssize_t bytes_read = -1;
+ do
+ {
+ bytes_read = ::pread (fd, buf, num_bytes, offset);
+ } while (bytes_read < 0 && errno == EINTR);
+
+ if (bytes_read < 0)
+ {
+ num_bytes = 0;
+ error.SetErrorToErrno();
+ }
+ else
+ {
+ offset += bytes_read;
+ num_bytes = bytes_read;
+ }
+ }
+ else
+ {
+ num_bytes = 0;
+ error.SetErrorString("invalid file handle");
+ }
+ return error;
+}
+
+Error
+File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp)
+{
+ Error error;
+
+ if (num_bytes > 0)
+ {
+ int fd = GetDescriptor();
+ if (fd != kInvalidDescriptor)
+ {
+ struct stat file_stats;
+ if (::fstat (fd, &file_stats) == 0)
+ {
+ if (file_stats.st_size > offset)
+ {
+ const size_t bytes_left = file_stats.st_size - offset;
+ if (num_bytes > bytes_left)
+ num_bytes = bytes_left;
+
+ std::unique_ptr<DataBufferHeap> data_heap_ap;
+ data_heap_ap.reset(new DataBufferHeap(num_bytes + (null_terminate ? 1 : 0), '\0'));
+
+ if (data_heap_ap.get())
+ {
+ error = Read (data_heap_ap->GetBytes(), num_bytes, offset);
+ if (error.Success())
+ {
+ // Make sure we read exactly what we asked for and if we got
+ // less, adjust the array
+ if (num_bytes < data_heap_ap->GetByteSize())
+ data_heap_ap->SetByteSize(num_bytes);
+ data_buffer_sp.reset(data_heap_ap.release());
+ return error;
+ }
+ }
+ }
+ else
+ error.SetErrorString("file is empty");
+ }
+ else
+ error.SetErrorToErrno();
+ }
+ else
+ error.SetErrorString("invalid file handle");
+ }
+ else
+ error.SetErrorString("invalid file handle");
+
+ num_bytes = 0;
+ data_buffer_sp.reset();
+ return error;
+}
+
+Error
+File::Write (const void *buf, size_t &num_bytes, off_t &offset)
+{
+ Error error;
+ int fd = GetDescriptor();
+ if (fd != kInvalidDescriptor)
+ {
+ ssize_t bytes_written = -1;
+ do
+ {
+ bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
+ } while (bytes_written < 0 && errno == EINTR);
+
+ if (bytes_written < 0)
+ {
+ num_bytes = 0;
+ error.SetErrorToErrno();
+ }
+ else
+ {
+ offset += bytes_written;
+ num_bytes = bytes_written;
+ }
+ }
+ else
+ {
+ num_bytes = 0;
+ error.SetErrorString("invalid file handle");
+ }
+ return error;
+}
+
+//------------------------------------------------------------------
+// Print some formatted output to the stream.
+//------------------------------------------------------------------
+size_t
+File::Printf (const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ size_t result = PrintfVarArg (format, args);
+ va_end (args);
+ return result;
+}
+
+//------------------------------------------------------------------
+// Print some formatted output to the stream.
+//------------------------------------------------------------------
+size_t
+File::PrintfVarArg (const char *format, va_list args)
+{
+ size_t result = 0;
+ if (DescriptorIsValid())
+ {
+ char *s = NULL;
+ result = vasprintf(&s, format, args);
+ if (s != NULL)
+ {
+ if (result > 0)
+ {
+ size_t s_len = result;
+ Write (s, s_len);
+ result = s_len;
+ }
+ free (s);
+ }
+ }
+ else if (StreamIsValid())
+ {
+ result = ::vfprintf (m_stream, format, args);
+ }
+ return result;
+}
OpenPOWER on IntegriCloud