Switch [String]FileWriter to use new file_io.h functions/types

Also add ScopedFileHandle as cross-platform version of ScopedFD/ScopedFileHANDLE.

R=mark@chromium.org
BUG=crashpad:1

Review URL: https://codereview.chromium.org/815053004
This commit is contained in:
Scott Graham 2014-12-19 13:33:01 -08:00
parent 25c3afaac5
commit 5f5e342584
7 changed files with 82 additions and 68 deletions

View File

@ -152,8 +152,8 @@ int GenerateDumpMain(int argc, char* argv[]) {
FileWriter file_writer; FileWriter file_writer;
if (!file_writer.Open(base::FilePath(options.dump_path), if (!file_writer.Open(base::FilePath(options.dump_path),
O_WRONLY | O_CREAT | O_TRUNC, FileWriteMode::kTruncateOrCreate,
0644)) { true)) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }

View File

@ -19,8 +19,11 @@
#include "build/build_config.h" #include "build/build_config.h"
#if defined(OS_WIN) #if defined(OS_POSIX)
#include "base/files/scoped_file.h"
#elif defined(OS_WIN)
#include <windows.h> #include <windows.h>
#include "util/win/scoped_handle.h"
#endif #endif
namespace base { namespace base {
@ -37,10 +40,14 @@ using FileHandle = int;
//! \brief Platform-specific alias for a position in an open file. //! \brief Platform-specific alias for a position in an open file.
using FileOffset = off_t; using FileOffset = off_t;
//! \brief Scoped wrapper of a FileHandle.
using ScopedFileHandle = base::ScopedFD;
#elif defined(OS_WIN) #elif defined(OS_WIN)
using FileHandle = HANDLE; using FileHandle = HANDLE;
using FileOffset = LONGLONG; using FileOffset = LONGLONG;
using ScopedFileHandle = ScopedFileHANDLE;
#endif #endif
@ -152,8 +159,7 @@ void CheckedReadFileAtEOF(FileHandle file);
//! //!
//! \return The newly opened FileHandle, or an invalid FileHandle on failure. //! \return The newly opened FileHandle, or an invalid FileHandle on failure.
//! //!
//! \sa ScopedFD //! \sa ScopedFileHandle
//! \sa ScopedFileHANDLE
FileHandle LoggingOpenFileForRead(const base::FilePath& path); FileHandle LoggingOpenFileForRead(const base::FilePath& path);
//! \brief Wraps `open()` or `CreateFile()`, creating a file for output. Logs //! \brief Wraps `open()` or `CreateFile()`, creating a file for output. Logs
@ -168,8 +174,7 @@ FileHandle LoggingOpenFileForRead(const base::FilePath& path);
//! \return The newly opened FileHandle, or an invalid FileHandle on failure. //! \return The newly opened FileHandle, or an invalid FileHandle on failure.
//! //!
//! \sa FileWriteMode //! \sa FileWriteMode
//! \sa ScopedFD //! \sa ScopedFileHandle
//! \sa ScopedFileHANDLE
FileHandle LoggingOpenFileForWrite(const base::FilePath& path, FileHandle LoggingOpenFileForWrite(const base::FilePath& path,
FileWriteMode write_mode, FileWriteMode write_mode,
bool world_readable); bool world_readable);

View File

@ -19,49 +19,49 @@
#include <limits.h> #include <limits.h>
#include "base/logging.h" #include "base/logging.h"
#if defined(OS_POSIX)
#include <sys/uio.h>
#include <unistd.h>
#include "base/posix/eintr_wrapper.h" #include "base/posix/eintr_wrapper.h"
#include "util/file/file_io.h" #endif // OS_POSIX
namespace crashpad { namespace crashpad {
#if defined(OS_POSIX)
// Ensure type compatibility between WritableIoVec and iovec. // Ensure type compatibility between WritableIoVec and iovec.
static_assert(sizeof(WritableIoVec) == sizeof(iovec), "WritableIoVec size"); static_assert(sizeof(WritableIoVec) == sizeof(iovec), "WritableIoVec size");
static_assert(offsetof(WritableIoVec, iov_base) == offsetof(iovec, iov_base), static_assert(offsetof(WritableIoVec, iov_base) == offsetof(iovec, iov_base),
"WritableIoVec base offset"); "WritableIoVec base offset");
static_assert(offsetof(WritableIoVec, iov_len) == offsetof(iovec, iov_len), static_assert(offsetof(WritableIoVec, iov_len) == offsetof(iovec, iov_len),
"WritableIoVec len offset"); "WritableIoVec len offset");
#endif // OS_POSIX
FileWriter::FileWriter() : fd_() { FileWriter::FileWriter() : file_() {
} }
FileWriter::~FileWriter() { FileWriter::~FileWriter() {
} }
bool FileWriter::Open(const base::FilePath& path, int oflag, mode_t mode) { bool FileWriter::Open(const base::FilePath& path,
CHECK(!fd_.is_valid()); FileWriteMode write_mode,
bool world_readable) {
DCHECK((oflag & O_WRONLY) || (oflag & O_RDWR)); CHECK(!file_.is_valid());
file_.reset(LoggingOpenFileForWrite(path, write_mode, world_readable));
fd_.reset(HANDLE_EINTR(open(path.value().c_str(), oflag, mode))); return file_.is_valid();
if (!fd_.is_valid()) {
PLOG(ERROR) << "open " << path.value();
return false;
}
return true;
} }
void FileWriter::Close() { void FileWriter::Close() {
CHECK(fd_.is_valid()); CHECK(file_.is_valid());
fd_.reset(); file_.reset();
} }
bool FileWriter::Write(const void* data, size_t size) { bool FileWriter::Write(const void* data, size_t size) {
DCHECK(fd_.is_valid()); DCHECK(file_.is_valid());
// TODO(mark): Write no more than SSIZE_MAX bytes in a single call. // TODO(mark): Write no more than SSIZE_MAX bytes in a single call.
ssize_t written = WriteFile(fd_.get(), data, size); ssize_t written = WriteFile(file_.get(), data, size);
if (written < 0) { if (written < 0) {
PLOG(ERROR) << "write"; PLOG(ERROR) << "write";
return false; return false;
@ -74,7 +74,9 @@ bool FileWriter::Write(const void* data, size_t size) {
} }
bool FileWriter::WriteIoVec(std::vector<WritableIoVec>* iovecs) { bool FileWriter::WriteIoVec(std::vector<WritableIoVec>* iovecs) {
DCHECK(fd_.is_valid()); DCHECK(file_.is_valid());
#if defined(OS_POSIX)
ssize_t size = 0; ssize_t size = 0;
for (const WritableIoVec& iov : *iovecs) { for (const WritableIoVec& iov : *iovecs) {
@ -94,7 +96,8 @@ bool FileWriter::WriteIoVec(std::vector<WritableIoVec>* iovecs) {
while (size > 0) { while (size > 0) {
size_t writev_iovec_count = size_t writev_iovec_count =
std::min(remaining_iovecs, implicit_cast<size_t>(IOV_MAX)); std::min(remaining_iovecs, implicit_cast<size_t>(IOV_MAX));
ssize_t written = HANDLE_EINTR(writev(fd_.get(), iov, writev_iovec_count)); ssize_t written =
HANDLE_EINTR(writev(file_.get(), iov, writev_iovec_count));
if (written < 0) { if (written < 0) {
PLOG(ERROR) << "writev"; PLOG(ERROR) << "writev";
return false; return false;
@ -128,6 +131,15 @@ bool FileWriter::WriteIoVec(std::vector<WritableIoVec>* iovecs) {
DCHECK_EQ(remaining_iovecs, 0u); DCHECK_EQ(remaining_iovecs, 0u);
#else // !OS_POSIX
for (const WritableIoVec& iov : *iovecs) {
if (!Write(iov.iov_base, iov.iov_len))
return false;
}
#endif // OS_POSIX
#ifndef NDEBUG #ifndef NDEBUG
// The interface says that |iovecs| is not sacred, so scramble it to make sure // The interface says that |iovecs| is not sacred, so scramble it to make sure
// that nobody depends on it. // that nobody depends on it.
@ -137,15 +149,9 @@ bool FileWriter::WriteIoVec(std::vector<WritableIoVec>* iovecs) {
return true; return true;
} }
off_t FileWriter::Seek(off_t offset, int whence) { FileOffset FileWriter::Seek(FileOffset offset, int whence) {
DCHECK(fd_.is_valid()); DCHECK(file_.is_valid());
return LoggingSeekFile(file_.get(), offset, whence);
off_t rv = lseek(fd_.get(), offset, whence);
if (rv < 0) {
PLOG(ERROR) << "lseek";
}
return rv;
} }
} // namespace crashpad } // namespace crashpad

View File

@ -17,15 +17,14 @@
#include <fcntl.h> #include <fcntl.h>
#include <stddef.h> #include <stddef.h>
#include <sys/uio.h>
#include <unistd.h>
#include <string> #include <string>
#include <vector> #include <vector>
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/files/scoped_file.h" #include "build/build_config.h"
#include "util/file/file_io.h"
namespace crashpad { namespace crashpad {
@ -43,21 +42,21 @@ struct WritableIoVec {
size_t iov_len; size_t iov_len;
}; };
//! \brief An interface to write to files and other file-like objects with POSIX //! \brief An interface to write to files and other file-like objects with
//! semantics. //! semantics matching the underlying platform (POSIX or Windows).
class FileWriterInterface { class FileWriterInterface {
public: public:
//! \brief Wraps `write()` or provides an alternate implementation with //! \brief Wraps WriteFile(), or provides an implementation with identical
//! identical semantics. This method will write the entire buffer, //! semantics.
//! continuing after a short write or after being interrupted.
//! //!
//! \return `true` if the operation succeeded, `false` if it failed, with an //! \return `true` if the operation succeeded, `false` if it failed, with an
//! error message logged. //! error message logged.
virtual bool Write(const void* data, size_t size) = 0; virtual bool Write(const void* data, size_t size) = 0;
//! \brief Wraps `writev()` or provides an alternate implementation with //! \brief Wraps `writev()` on POSIX or provides an alternate implementation
//! identical semantics. This method will write the entire buffer, //! with identical semantics. This method will write entire buffers,
//! continuing after a short write or after being interrupted. //! continuing after a short write or after being interrupted. On
//! non-POSIX this is a simple wrapper around Write().
//! //!
//! \return `true` if the operation succeeded, `false` if it failed, with an //! \return `true` if the operation succeeded, `false` if it failed, with an
//! error message logged. //! error message logged.
@ -65,34 +64,36 @@ class FileWriterInterface {
//! \note The contents of \a iovecs are undefined when this method returns. //! \note The contents of \a iovecs are undefined when this method returns.
virtual bool WriteIoVec(std::vector<WritableIoVec>* iovecs) = 0; virtual bool WriteIoVec(std::vector<WritableIoVec>* iovecs) = 0;
//! \brief Wraps `lseek()` or provides an alternate implementation with //! \brief Wraps LoggingFileSeek() or provides an alternate implementation
//! identical semantics. //! with identical semantics.
//! //!
//! \return The return value of `lseek()`. `-1` on failure, with an error //! \return The return value of LoggingFileSeek(). `-1` on failure,
//! message logged. //! with an error message logged.
virtual off_t Seek(off_t offset, int whence) = 0; virtual FileOffset Seek(FileOffset offset, int whence) = 0;
protected: protected:
~FileWriterInterface() {} ~FileWriterInterface() {}
}; };
//! \brief A file writer implementation that wraps traditional POSIX file //! \brief A file writer implementation that wraps traditional system file
//! operations on files accessed through the filesystem. //! operations on files accessed through the filesystem.
class FileWriter : public FileWriterInterface { class FileWriter : public FileWriterInterface {
public: public:
FileWriter(); FileWriter();
~FileWriter(); ~FileWriter();
//! \brief Wraps `open()`. //! \brief Wraps LoggingOpenFileForWrite().
//! //!
//! \return `true` if the operation succeeded, `false` if it failed, with an //! \return `true` if the operation succeeded, `false` if it failed, with an
//! error message logged. //! error message logged.
//! //!
//! \note After a successful call, this method cannot be called again until //! \note After a successful call, this method cannot be called again until
//! after Close(). //! after Close().
bool Open(const base::FilePath& path, int oflag, mode_t mode); bool Open(const base::FilePath& path,
FileWriteMode write_mode,
bool world_readable);
//! \brief Wraps `close().` //! \brief Wraps CheckedCloseHandle().
//! //!
//! \note It is only valid to call this method on an object that has had a //! \note It is only valid to call this method on an object that has had a
//! successful Open() that has not yet been matched by a subsequent call //! successful Open() that has not yet been matched by a subsequent call
@ -117,10 +118,10 @@ class FileWriter : public FileWriterInterface {
//! //!
//! \note It is only valid to call this method between a successful Open() and //! \note It is only valid to call this method between a successful Open() and
//! a Close(). //! a Close().
off_t Seek(off_t offset, int whence) override; FileOffset Seek(FileOffset offset, int whence) override;
private: private:
base::ScopedFD fd_; ScopedFileHandle file_;
DISALLOW_COPY_AND_ASSIGN(FileWriter); DISALLOW_COPY_AND_ASSIGN(FileWriter);
}; };

View File

@ -87,7 +87,7 @@ bool StringFileWriter::WriteIoVec(std::vector<WritableIoVec>* iovecs) {
return true; return true;
} }
off_t StringFileWriter::Seek(off_t offset, int whence) { FileOffset StringFileWriter::Seek(FileOffset offset, int whence) {
DCHECK(offset_.IsValid()); DCHECK(offset_.IsValid());
size_t base_offset; size_t base_offset;
@ -110,21 +110,22 @@ off_t StringFileWriter::Seek(off_t offset, int whence) {
return -1; return -1;
} }
off_t base_offset_offt; FileOffset base_offset_fileoffset;
if (!AssignIfInRange(&base_offset_offt, base_offset)) { if (!AssignIfInRange(&base_offset_fileoffset, base_offset)) {
LOG(ERROR) << "Seek(): base_offset " << base_offset << " invalid for off_t"; LOG(ERROR) << "Seek(): base_offset " << base_offset
<< " invalid for FileOffset";
return -1; return -1;
} }
base::CheckedNumeric<off_t> new_offset(base_offset_offt); base::CheckedNumeric<FileOffset> new_offset(base_offset_fileoffset);
new_offset += offset; new_offset += offset;
if (!new_offset.IsValid()) { if (!new_offset.IsValid()) {
LOG(ERROR) << "Seek(): new_offset invalid"; LOG(ERROR) << "Seek(): new_offset invalid";
return -1; return -1;
} }
off_t new_offset_offt = new_offset.ValueOrDie(); FileOffset new_offset_fileoffset = new_offset.ValueOrDie();
size_t new_offset_sizet; size_t new_offset_sizet;
if (!AssignIfInRange(&new_offset_sizet, new_offset_offt)) { if (!AssignIfInRange(&new_offset_sizet, new_offset_fileoffset)) {
LOG(ERROR) << "Seek(): new_offset " << new_offset_offt LOG(ERROR) << "Seek(): new_offset " << new_offset_fileoffset
<< " invalid for size_t"; << " invalid for size_t";
return -1; return -1;
} }

View File

@ -47,7 +47,7 @@ class StringFileWriter : public FileWriterInterface {
// FileWriterInterface: // FileWriterInterface:
bool Write(const void* data, size_t size) override; bool Write(const void* data, size_t size) override;
bool WriteIoVec(std::vector<WritableIoVec>* iovecs) override; bool WriteIoVec(std::vector<WritableIoVec>* iovecs) override;
off_t Seek(off_t offset, int whence) override; FileOffset Seek(FileOffset offset, int whence) override;
private: private:
//! \brief The virtual files contents. //! \brief The virtual files contents.

View File

@ -15,12 +15,13 @@
#include "util/win/scoped_handle.h" #include "util/win/scoped_handle.h"
#include "base/logging.h" #include "base/logging.h"
#include "util/file/file_io.h"
namespace crashpad { namespace crashpad {
namespace internal { namespace internal {
void ScopedFileHANDLECloseTraits::Free(HANDLE handle) { void ScopedFileHANDLECloseTraits::Free(HANDLE handle) {
PCHECK(CloseHandle(handle)); CheckedCloseFile(handle);
} }
void ScopedKernelHANDLECloseTraits::Free(HANDLE handle) { void ScopedKernelHANDLECloseTraits::Free(HANDLE handle) {