The many many benefits include: 1 - Input/Output/Error streams are now handled as real streams not a push style input 2 - auto completion in python embedded interpreter 3 - multi-line input for "script" and "expression" commands now allow you to edit previous/next lines using up and down arrow keys and this makes multi-line input actually a viable thing to use 4 - it is now possible to use curses to drive LLDB (please try the "gui" command) We will need to deal with and fix any buildbot failures and tests and arise now that input/output and error are correctly hooked up in all cases. llvm-svn: 200263
869 lines
20 KiB
C++
869 lines
20 KiB
C++
//===-- File.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>
|
|
|
|
#ifdef _WIN32
|
|
#include "lldb/Host/windows/windows.h"
|
|
#endif
|
|
|
|
#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 (),
|
|
m_own_stream (false),
|
|
m_own_descriptor (false)
|
|
{
|
|
Open (path, options, permissions);
|
|
}
|
|
|
|
File::File (const FileSpec& filespec,
|
|
uint32_t options,
|
|
uint32_t permissions) :
|
|
m_descriptor (kInvalidDescriptor),
|
|
m_stream (kInvalidStream),
|
|
m_options (0),
|
|
m_own_stream (false),
|
|
m_own_descriptor (false)
|
|
{
|
|
if (filespec)
|
|
{
|
|
Open (filespec.GetPath().c_str(), options, permissions);
|
|
}
|
|
}
|
|
|
|
File::File (const File &rhs) :
|
|
m_descriptor (kInvalidDescriptor),
|
|
m_stream (kInvalidStream),
|
|
m_options (0),
|
|
m_own_stream (false),
|
|
m_own_descriptor (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_own_descriptor = transfer_ownership;
|
|
}
|
|
|
|
|
|
FILE *
|
|
File::GetStream ()
|
|
{
|
|
if (!StreamIsValid())
|
|
{
|
|
if (DescriptorIsValid())
|
|
{
|
|
const char *mode = GetStreamOpenModeFromOptions (m_options);
|
|
if (mode)
|
|
{
|
|
if (!m_own_descriptor)
|
|
{
|
|
// We must duplicate the file descriptor if we don't own it because
|
|
// when you call fdopen, the stream will own the fd
|
|
#ifdef _WIN32
|
|
m_descriptor = ::_dup(GetDescriptor());
|
|
#else
|
|
m_descriptor = ::fcntl(GetDescriptor(), F_DUPFD);
|
|
#endif
|
|
m_own_descriptor = true;
|
|
}
|
|
|
|
do
|
|
{
|
|
m_stream = ::fdopen (m_descriptor, mode);
|
|
} while (m_stream == NULL && errno == EINTR);
|
|
|
|
// If we got a stream, then we own the stream and should no
|
|
// longer own the descriptor because fclose() will close it for us
|
|
|
|
if (m_stream)
|
|
{
|
|
m_own_stream = true;
|
|
m_own_descriptor = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return m_stream;
|
|
}
|
|
|
|
|
|
void
|
|
File::SetStream (FILE *fh, bool transfer_ownership)
|
|
{
|
|
if (IsValid())
|
|
Close();
|
|
m_stream = fh;
|
|
m_own_stream = transfer_ownership;
|
|
}
|
|
|
|
Error
|
|
File::Duplicate (const File &rhs)
|
|
{
|
|
Error error;
|
|
if (IsValid ())
|
|
Close();
|
|
|
|
if (rhs.DescriptorIsValid())
|
|
{
|
|
#ifdef _WIN32
|
|
m_descriptor = ::_dup(rhs.GetDescriptor());
|
|
#else
|
|
m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD);
|
|
#endif
|
|
if (!DescriptorIsValid())
|
|
error.SetErrorToErrno();
|
|
else
|
|
{
|
|
m_options = rhs.m_options;
|
|
m_own_descriptor = 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;
|
|
|
|
#ifndef _WIN32
|
|
if (options & eOpenoptionDontFollowSymlinks)
|
|
oflag |= O_NOFOLLOW;
|
|
#endif
|
|
}
|
|
|
|
#ifndef _WIN32
|
|
if (options & eOpenOptionNonBlocking)
|
|
oflag |= O_NONBLOCK;
|
|
#else
|
|
oflag |= O_BINARY;
|
|
#endif
|
|
|
|
mode_t mode = 0;
|
|
if (oflag & O_CREAT)
|
|
{
|
|
if (permissions & lldb::eFilePermissionsUserRead) mode |= S_IRUSR;
|
|
if (permissions & lldb::eFilePermissionsUserWrite) mode |= S_IWUSR;
|
|
if (permissions & lldb::eFilePermissionsUserExecute) mode |= S_IXUSR;
|
|
if (permissions & lldb::eFilePermissionsGroupRead) mode |= S_IRGRP;
|
|
if (permissions & lldb::eFilePermissionsGroupWrite) mode |= S_IWGRP;
|
|
if (permissions & lldb::eFilePermissionsGroupExecute) mode |= S_IXGRP;
|
|
if (permissions & lldb::eFilePermissionsWorldRead) mode |= S_IROTH;
|
|
if (permissions & lldb::eFilePermissionsWorldWrite) mode |= S_IWOTH;
|
|
if (permissions & lldb::eFilePermissionsWorldExecute) mode |= S_IXOTH;
|
|
}
|
|
|
|
do
|
|
{
|
|
m_descriptor = ::open(path, oflag, mode);
|
|
} while (m_descriptor < 0 && errno == EINTR);
|
|
|
|
if (!DescriptorIsValid())
|
|
error.SetErrorToErrno();
|
|
else
|
|
{
|
|
m_own_descriptor = true;
|
|
m_options = options;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
uint32_t
|
|
File::GetPermissions (const char *path, Error &error)
|
|
{
|
|
if (path && path[0])
|
|
{
|
|
struct stat file_stats;
|
|
if (::stat (path, &file_stats) == -1)
|
|
error.SetErrorToErrno();
|
|
else
|
|
{
|
|
error.Clear();
|
|
return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (path)
|
|
error.SetErrorString ("invalid path");
|
|
else
|
|
error.SetErrorString ("empty path");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint32_t
|
|
File::GetPermissions(Error &error) const
|
|
{
|
|
int fd = GetDescriptor();
|
|
if (fd != kInvalidDescriptor)
|
|
{
|
|
struct stat file_stats;
|
|
if (::fstat (fd, &file_stats) == -1)
|
|
error.SetErrorToErrno();
|
|
else
|
|
{
|
|
error.Clear();
|
|
return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
error.SetErrorString ("invalid file descriptor");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
Error
|
|
File::Close ()
|
|
{
|
|
Error error;
|
|
if (StreamIsValid() && m_own_stream)
|
|
{
|
|
if (::fclose (m_stream) == EOF)
|
|
error.SetErrorToErrno();
|
|
}
|
|
|
|
if (DescriptorIsValid() && m_own_descriptor)
|
|
{
|
|
if (::close (m_descriptor) != 0)
|
|
error.SetErrorToErrno();
|
|
}
|
|
m_descriptor = kInvalidDescriptor;
|
|
m_stream = kInvalidStream;
|
|
m_options = 0;
|
|
m_own_stream = false;
|
|
m_own_descriptor = 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())
|
|
{
|
|
#ifdef _WIN32
|
|
int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
|
|
if (err == 0)
|
|
error.SetErrorToGenericError();
|
|
#else
|
|
int err = 0;
|
|
do
|
|
{
|
|
err = ::fsync (m_descriptor);
|
|
} while (err == -1 && errno == EINTR);
|
|
|
|
if (err == -1)
|
|
error.SetErrorToErrno();
|
|
#endif
|
|
}
|
|
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)
|
|
{
|
|
#ifndef _WIN32
|
|
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;
|
|
#else
|
|
long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
|
|
SeekFromStart(offset);
|
|
Error error = Read(buf, num_bytes);
|
|
if (!error.Fail())
|
|
SeekFromStart(cur);
|
|
return error;
|
|
#endif
|
|
}
|
|
|
|
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)
|
|
{
|
|
#ifndef _WIN32
|
|
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
|
|
long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
|
|
error = Write(buf, num_bytes);
|
|
long after = ::lseek(m_descriptor, 0, SEEK_CUR);
|
|
|
|
if (!error.Fail())
|
|
SeekFromStart(cur);
|
|
|
|
ssize_t bytes_written = after - cur;
|
|
offset = after;
|
|
#endif
|
|
}
|
|
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;
|
|
}
|
|
|
|
mode_t
|
|
File::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options)
|
|
{
|
|
mode_t mode = 0;
|
|
if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
|
|
mode |= O_RDWR;
|
|
else if (open_options & eOpenOptionWrite)
|
|
mode |= O_WRONLY;
|
|
|
|
if (open_options & eOpenOptionAppend)
|
|
mode |= O_APPEND;
|
|
|
|
if (open_options & eOpenOptionTruncate)
|
|
mode |= O_TRUNC;
|
|
|
|
if (open_options & eOpenOptionNonBlocking)
|
|
mode |= O_NONBLOCK;
|
|
|
|
if (open_options & eOpenOptionCanCreateNewOnly)
|
|
mode |= O_CREAT | O_EXCL;
|
|
else if (open_options & eOpenOptionCanCreate)
|
|
mode |= O_CREAT;
|
|
|
|
return mode;
|
|
}
|