diff options
author | emaste <emaste@FreeBSD.org> | 2013-08-23 17:46:38 +0000 |
---|---|---|
committer | emaste <emaste@FreeBSD.org> | 2013-08-23 17:46:38 +0000 |
commit | dcd15f81789e389c1cb27d264fcdddfd0a6002bd (patch) | |
tree | f561dabc721ad515599172c16da3a4400b7f4aec /source/Host/common/File.cpp | |
download | FreeBSD-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.cpp | 716 |
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; +} |