Add non-logging OpenFileForWrite() and OpenFileForReadAndWrite()

BUG=crashpad:63
TEST=crashpad_util_test FileIO.*OpenFileFor*
R=scottmg@chromium.org

Review URL: https://codereview.chromium.org/1395543002 .
This commit is contained in:
Mark Mentovai 2015-10-07 11:40:02 -04:00
parent 2d8a0498ab
commit 78592537bc
4 changed files with 176 additions and 81 deletions

View File

@ -202,15 +202,17 @@ void CheckedWriteFile(FileHandle file, const void* buffer, size_t size);
void CheckedReadFileAtEOF(FileHandle file); void CheckedReadFileAtEOF(FileHandle file);
//! \brief Wraps `open()` or `CreateFile()`, opening an existing file for //! \brief Wraps `open()` or `CreateFile()`, opening an existing file for
//! reading. Logs an error if the operation fails. //! reading.
//! //!
//! \return The newly opened FileHandle, or an invalid FileHandle on failure. //! \return The newly opened FileHandle, or an invalid FileHandle on failure.
//! //!
//! \sa ScopedFileHandle //! \sa ScopedFileHandle
FileHandle LoggingOpenFileForRead(const base::FilePath& path); //! \sa OpenFileForWrite
//! \sa OpenFileForReadAndWrite
//! \sa LoggingOpenFileForRead
FileHandle OpenFileForRead(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.
//! an error if the operation fails.
//! //!
//! \a mode determines the style (truncate, reuse, etc.) that is used to open //! \a mode determines the style (truncate, reuse, etc.) that is used to open
//! the file. On POSIX, \a permissions determines the value that is passed as //! the file. On POSIX, \a permissions determines the value that is passed as
@ -220,27 +222,61 @@ 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 FilePermissions
//! \sa ScopedFileHandle //! \sa ScopedFileHandle
//! \sa OpenFileForRead
//! \sa OpenFileForReadAndWrite
//! \sa LoggingOpenFileForWrite
FileHandle OpenFileForWrite(const base::FilePath& path,
FileWriteMode mode,
FilePermissions permissions);
//! \brief Wraps `open()` or `CreateFile()`, creating a file for both input and
//! output.
//!
//! \a mode determines the style (truncate, reuse, etc.) that is used to open
//! the file. On POSIX, \a permissions determines the value that is passed as
//! `mode` to `open()`. On Windows, the file is always opened in binary mode
//! (that is, no CRLF translation). On Windows, the file is opened for sharing,
//! see LoggingLockFile() and LoggingUnlockFile() to control concurrent access.
//!
//! \return The newly opened FileHandle, or an invalid FileHandle on failure.
//!
//! \sa ScopedFileHandle
//! \sa OpenFileForRead
//! \sa OpenFileForWrite
//! \sa LoggingOpenFileForReadAndWrite
FileHandle OpenFileForReadAndWrite(const base::FilePath& path,
FileWriteMode mode,
FilePermissions permissions);
//! \brief Wraps OpenFileForRead(), logging an error if the operation fails.
//!
//! \return The newly opened FileHandle, or an invalid FileHandle on failure.
//!
//! \sa ScopedFileHandle
//! \sa LoggingOpenFileForWrite
//! \sa LoggingOpenFileForReadAndWrite
FileHandle LoggingOpenFileForRead(const base::FilePath& path);
//! \brief Wraps OpenFileForWrite(), logging an error if the operation fails.
//!
//! \return The newly opened FileHandle, or an invalid FileHandle on failure.
//!
//! \sa ScopedFileHandle
//! \sa LoggingOpenFileForRead
//! \sa LoggingOpenFileForReadAndWrite
FileHandle LoggingOpenFileForWrite(const base::FilePath& path, FileHandle LoggingOpenFileForWrite(const base::FilePath& path,
FileWriteMode mode, FileWriteMode mode,
FilePermissions permissions); FilePermissions permissions);
//! \brief Wraps `open()` or `CreateFile()`, creating a file for both input and //! \brief Wraps OpenFileForReadAndWrite(), logging an error if the operation
//! output. Logs an error if the operation fails. //! fails.
//!
//! \a mode determines the style (truncate, reuse, etc.) that is used to open
//! the file. On POSIX, \a permissions determines the value that is passed as
//! `mode` to `open()`. On Windows, the file is always opened in binary mode
//! (that is, no CRLF translation). On Windows, the file is opened for sharing,
//! see LoggingLockFile() and LoggingUnlockFile() to control concurrent access.
//! //!
//! \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 FilePermissions
//! \sa ScopedFileHandle //! \sa ScopedFileHandle
//! \sa LoggingOpenFileForRead
//! \sa LoggingOpenFileForWrite
FileHandle LoggingOpenFileForReadAndWrite(const base::FilePath& path, FileHandle LoggingOpenFileForReadAndWrite(const base::FilePath& path,
FileWriteMode mode, FileWriteMode mode,
FilePermissions permissions); FilePermissions permissions);

View File

@ -71,12 +71,14 @@ namespace crashpad {
namespace { namespace {
FileHandle LoggingOpenFileForOutput(int rdwr_or_wronly, FileHandle OpenFileForOutput(int rdwr_or_wronly,
const base::FilePath& path, const base::FilePath& path,
FileWriteMode mode, FileWriteMode mode,
FilePermissions permissions) { FilePermissions permissions) {
int flags = rdwr_or_wronly & (O_RDWR | O_WRONLY); DCHECK(rdwr_or_wronly & (O_RDWR | O_WRONLY));
DCHECK_NE(flags, 0); DCHECK_EQ(rdwr_or_wronly & ~(O_RDWR | O_WRONLY), 0);
int flags = rdwr_or_wronly;
switch (mode) { switch (mode) {
case FileWriteMode::kReuseOrFail: case FileWriteMode::kReuseOrFail:
@ -92,12 +94,10 @@ FileHandle LoggingOpenFileForOutput(int rdwr_or_wronly,
break; break;
} }
int fd = HANDLE_EINTR( return HANDLE_EINTR(
open(path.value().c_str(), open(path.value().c_str(),
flags, flags,
permissions == FilePermissions::kWorldReadable ? 0644 : 0600)); permissions == FilePermissions::kWorldReadable ? 0644 : 0600));
PLOG_IF(ERROR, fd < 0) << "open " << path.value();
return fd;
} }
} // namespace } // namespace
@ -110,8 +110,24 @@ ssize_t WriteFile(FileHandle file, const void* buffer, size_t size) {
return ReadOrWrite<WriteTraits>(file, buffer, size); return ReadOrWrite<WriteTraits>(file, buffer, size);
} }
FileHandle OpenFileForRead(const base::FilePath& path) {
return HANDLE_EINTR(open(path.value().c_str(), O_RDONLY));
}
FileHandle OpenFileForWrite(const base::FilePath& path,
FileWriteMode mode,
FilePermissions permissions) {
return OpenFileForOutput(O_WRONLY, path, mode, permissions);
}
FileHandle OpenFileForReadAndWrite(const base::FilePath& path,
FileWriteMode mode,
FilePermissions permissions) {
return OpenFileForOutput(O_RDWR, path, mode, permissions);
}
FileHandle LoggingOpenFileForRead(const base::FilePath& path) { FileHandle LoggingOpenFileForRead(const base::FilePath& path) {
int fd = HANDLE_EINTR(open(path.value().c_str(), O_RDONLY)); FileHandle fd = OpenFileForRead(path);
PLOG_IF(ERROR, fd < 0) << "open " << path.value(); PLOG_IF(ERROR, fd < 0) << "open " << path.value();
return fd; return fd;
} }
@ -119,13 +135,17 @@ FileHandle LoggingOpenFileForRead(const base::FilePath& path) {
FileHandle LoggingOpenFileForWrite(const base::FilePath& path, FileHandle LoggingOpenFileForWrite(const base::FilePath& path,
FileWriteMode mode, FileWriteMode mode,
FilePermissions permissions) { FilePermissions permissions) {
return LoggingOpenFileForOutput(O_WRONLY, path, mode, permissions); FileHandle fd = OpenFileForWrite(path, mode, permissions);
PLOG_IF(ERROR, fd < 0) << "open " << path.value();
return fd;
} }
FileHandle LoggingOpenFileForReadAndWrite(const base::FilePath& path, FileHandle LoggingOpenFileForReadAndWrite(const base::FilePath& path,
FileWriteMode mode, FileWriteMode mode,
FilePermissions permissions) { FilePermissions permissions) {
return LoggingOpenFileForOutput(O_RDWR, path, mode, permissions); FileHandle fd = OpenFileForReadAndWrite(path, mode, permissions);
PLOG_IF(ERROR, fd < 0) << "open " << path.value();
return fd;
} }
bool LoggingLockFile(FileHandle file, FileLocking locking) { bool LoggingLockFile(FileHandle file, FileLocking locking) {

View File

@ -28,29 +28,30 @@ namespace crashpad {
namespace test { namespace test {
namespace { namespace {
TEST(FileIO, OpenFileForWrite) { void TestOpenFileForWrite(FileHandle (*opener)(const base::FilePath&,
FileWriteMode,
FilePermissions)) {
ScopedTempDir temp_dir; ScopedTempDir temp_dir;
base::FilePath file_path_1 = base::FilePath file_path_1 =
temp_dir.path().Append(FILE_PATH_LITERAL("file_1")); temp_dir.path().Append(FILE_PATH_LITERAL("file_1"));
ASSERT_FALSE(FileExists(file_path_1)); ASSERT_FALSE(FileExists(file_path_1));
ScopedFileHandle ScopedFileHandle file_handle(opener(file_path_1,
file_handle(LoggingOpenFileForWrite(file_path_1, FileWriteMode::kReuseOrFail,
FileWriteMode::kReuseOrFail, FilePermissions::kWorldReadable));
FilePermissions::kWorldReadable));
EXPECT_EQ(kInvalidFileHandle, file_handle); EXPECT_EQ(kInvalidFileHandle, file_handle);
EXPECT_FALSE(FileExists(file_path_1)); EXPECT_FALSE(FileExists(file_path_1));
file_handle.reset(LoggingOpenFileForWrite(file_path_1, file_handle.reset(opener(file_path_1,
FileWriteMode::kCreateOrFail, FileWriteMode::kCreateOrFail,
FilePermissions::kWorldReadable)); FilePermissions::kWorldReadable));
EXPECT_NE(kInvalidFileHandle, file_handle); EXPECT_NE(kInvalidFileHandle, file_handle);
EXPECT_TRUE(FileExists(file_path_1)); EXPECT_TRUE(FileExists(file_path_1));
EXPECT_EQ(0, FileSize(file_path_1)); EXPECT_EQ(0, FileSize(file_path_1));
file_handle.reset(LoggingOpenFileForWrite(file_path_1, file_handle.reset(opener(file_path_1,
FileWriteMode::kReuseOrCreate, FileWriteMode::kReuseOrCreate,
FilePermissions::kWorldReadable)); FilePermissions::kWorldReadable));
EXPECT_NE(kInvalidFileHandle, file_handle); EXPECT_NE(kInvalidFileHandle, file_handle);
EXPECT_TRUE(FileExists(file_path_1)); EXPECT_TRUE(FileExists(file_path_1));
EXPECT_EQ(0, FileSize(file_path_1)); EXPECT_EQ(0, FileSize(file_path_1));
@ -62,30 +63,30 @@ TEST(FileIO, OpenFileForWrite) {
file_handle.reset(); file_handle.reset();
EXPECT_EQ(implicit_cast<FileOffset>(sizeof(data)), FileSize(file_path_1)); EXPECT_EQ(implicit_cast<FileOffset>(sizeof(data)), FileSize(file_path_1));
file_handle.reset(LoggingOpenFileForWrite(file_path_1, file_handle.reset(opener(file_path_1,
FileWriteMode::kReuseOrCreate, FileWriteMode::kReuseOrCreate,
FilePermissions::kWorldReadable)); FilePermissions::kWorldReadable));
EXPECT_NE(kInvalidFileHandle, file_handle); EXPECT_NE(kInvalidFileHandle, file_handle);
EXPECT_TRUE(FileExists(file_path_1)); EXPECT_TRUE(FileExists(file_path_1));
EXPECT_EQ(implicit_cast<FileOffset>(sizeof(data)), FileSize(file_path_1)); EXPECT_EQ(implicit_cast<FileOffset>(sizeof(data)), FileSize(file_path_1));
file_handle.reset(LoggingOpenFileForWrite(file_path_1, file_handle.reset(opener(file_path_1,
FileWriteMode::kCreateOrFail, FileWriteMode::kCreateOrFail,
FilePermissions::kWorldReadable)); FilePermissions::kWorldReadable));
EXPECT_EQ(kInvalidFileHandle, file_handle); EXPECT_EQ(kInvalidFileHandle, file_handle);
EXPECT_TRUE(FileExists(file_path_1)); EXPECT_TRUE(FileExists(file_path_1));
EXPECT_EQ(implicit_cast<FileOffset>(sizeof(data)), FileSize(file_path_1)); EXPECT_EQ(implicit_cast<FileOffset>(sizeof(data)), FileSize(file_path_1));
file_handle.reset(LoggingOpenFileForWrite(file_path_1, file_handle.reset(opener(file_path_1,
FileWriteMode::kReuseOrFail, FileWriteMode::kReuseOrFail,
FilePermissions::kWorldReadable)); FilePermissions::kWorldReadable));
EXPECT_NE(kInvalidFileHandle, file_handle); EXPECT_NE(kInvalidFileHandle, file_handle);
EXPECT_TRUE(FileExists(file_path_1)); EXPECT_TRUE(FileExists(file_path_1));
EXPECT_EQ(implicit_cast<FileOffset>(sizeof(data)), FileSize(file_path_1)); EXPECT_EQ(implicit_cast<FileOffset>(sizeof(data)), FileSize(file_path_1));
file_handle.reset(LoggingOpenFileForWrite(file_path_1, file_handle.reset(opener(file_path_1,
FileWriteMode::kTruncateOrCreate, FileWriteMode::kTruncateOrCreate,
FilePermissions::kWorldReadable)); FilePermissions::kWorldReadable));
EXPECT_NE(kInvalidFileHandle, file_handle); EXPECT_NE(kInvalidFileHandle, file_handle);
EXPECT_TRUE(FileExists(file_path_1)); EXPECT_TRUE(FileExists(file_path_1));
EXPECT_EQ(0, FileSize(file_path_1)); EXPECT_EQ(0, FileSize(file_path_1));
@ -94,9 +95,9 @@ TEST(FileIO, OpenFileForWrite) {
temp_dir.path().Append(FILE_PATH_LITERAL("file_2")); temp_dir.path().Append(FILE_PATH_LITERAL("file_2"));
ASSERT_FALSE(FileExists(file_path_2)); ASSERT_FALSE(FileExists(file_path_2));
file_handle.reset(LoggingOpenFileForWrite(file_path_2, file_handle.reset(opener(file_path_2,
FileWriteMode::kTruncateOrCreate, FileWriteMode::kTruncateOrCreate,
FilePermissions::kWorldReadable)); FilePermissions::kWorldReadable));
EXPECT_NE(kInvalidFileHandle, file_handle); EXPECT_NE(kInvalidFileHandle, file_handle);
EXPECT_TRUE(FileExists(file_path_2)); EXPECT_TRUE(FileExists(file_path_2));
EXPECT_EQ(0, FileSize(file_path_2)); EXPECT_EQ(0, FileSize(file_path_2));
@ -105,14 +106,30 @@ TEST(FileIO, OpenFileForWrite) {
temp_dir.path().Append(FILE_PATH_LITERAL("file_3")); temp_dir.path().Append(FILE_PATH_LITERAL("file_3"));
ASSERT_FALSE(FileExists(file_path_3)); ASSERT_FALSE(FileExists(file_path_3));
file_handle.reset(LoggingOpenFileForWrite(file_path_3, file_handle.reset(opener(file_path_3,
FileWriteMode::kReuseOrCreate, FileWriteMode::kReuseOrCreate,
FilePermissions::kWorldReadable)); FilePermissions::kWorldReadable));
EXPECT_NE(kInvalidFileHandle, file_handle); EXPECT_NE(kInvalidFileHandle, file_handle);
EXPECT_TRUE(FileExists(file_path_3)); EXPECT_TRUE(FileExists(file_path_3));
EXPECT_EQ(0, FileSize(file_path_3)); EXPECT_EQ(0, FileSize(file_path_3));
} }
TEST(FileIO, OpenFileForWrite) {
TestOpenFileForWrite(OpenFileForWrite);
}
TEST(FileIO, OpenFileForReadAndWrite) {
TestOpenFileForWrite(OpenFileForReadAndWrite);
}
TEST(FileIO, LoggingOpenFileForWrite) {
TestOpenFileForWrite(LoggingOpenFileForWrite);
}
TEST(FileIO, LoggingOpenFileForReadAndWrite) {
TestOpenFileForWrite(LoggingOpenFileForReadAndWrite);
}
enum class ReadOrWrite : bool { enum class ReadOrWrite : bool {
kRead, kRead,
kWrite, kWrite,

View File

@ -37,10 +37,13 @@ namespace crashpad {
namespace { namespace {
FileHandle LoggingOpenFileForOutput(DWORD access, FileHandle OpenFileForOutput(DWORD access,
const base::FilePath& path, const base::FilePath& path,
FileWriteMode mode, FileWriteMode mode,
FilePermissions permissions) { FilePermissions permissions) {
DCHECK(access & GENERIC_WRITE);
DCHECK_EQ(access & ~(GENERIC_READ | GENERIC_WRITE), 0u);
DWORD disposition = 0; DWORD disposition = 0;
switch (mode) { switch (mode) {
case FileWriteMode::kReuseOrFail: case FileWriteMode::kReuseOrFail:
@ -56,16 +59,13 @@ FileHandle LoggingOpenFileForOutput(DWORD access,
disposition = CREATE_NEW; disposition = CREATE_NEW;
break; break;
} }
HANDLE file = CreateFile(path.value().c_str(), return CreateFile(path.value().c_str(),
access, access,
FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
nullptr, nullptr,
disposition, disposition,
FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_NORMAL,
nullptr); nullptr);
PLOG_IF(ERROR, file == INVALID_HANDLE_VALUE)
<< "CreateFile " << base::UTF16ToUTF8(path.value());
return file;
} }
} // namespace } // namespace
@ -115,14 +115,31 @@ ssize_t WriteFile(FileHandle file, const void* buffer, size_t size) {
return bytes_written; return bytes_written;
} }
FileHandle OpenFileForRead(const base::FilePath& path) {
return CreateFile(path.value().c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
nullptr,
OPEN_EXISTING,
0,
nullptr);
}
FileHandle OpenFileForWrite(const base::FilePath& path,
FileWriteMode mode,
FilePermissions permissions) {
return OpenFileForOutput(GENERIC_WRITE, path, mode, permissions);
}
FileHandle OpenFileForReadAndWrite(const base::FilePath& path,
FileWriteMode mode,
FilePermissions permissions) {
return OpenFileForOutput(
GENERIC_READ | GENERIC_WRITE, path, mode, permissions);
}
FileHandle LoggingOpenFileForRead(const base::FilePath& path) { FileHandle LoggingOpenFileForRead(const base::FilePath& path) {
HANDLE file = CreateFile(path.value().c_str(), FileHandle file = OpenFileForRead(path);
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
nullptr,
OPEN_EXISTING,
0,
nullptr);
PLOG_IF(ERROR, file == INVALID_HANDLE_VALUE) PLOG_IF(ERROR, file == INVALID_HANDLE_VALUE)
<< "CreateFile " << base::UTF16ToUTF8(path.value()); << "CreateFile " << base::UTF16ToUTF8(path.value());
return file; return file;
@ -131,14 +148,19 @@ FileHandle LoggingOpenFileForRead(const base::FilePath& path) {
FileHandle LoggingOpenFileForWrite(const base::FilePath& path, FileHandle LoggingOpenFileForWrite(const base::FilePath& path,
FileWriteMode mode, FileWriteMode mode,
FilePermissions permissions) { FilePermissions permissions) {
return LoggingOpenFileForOutput(GENERIC_WRITE, path, mode, permissions); FileHandle file = OpenFileForWrite(path, mode, permissions);
PLOG_IF(ERROR, file == INVALID_HANDLE_VALUE)
<< "CreateFile " << base::UTF16ToUTF8(path.value());
return file;
} }
FileHandle LoggingOpenFileForReadAndWrite(const base::FilePath& path, FileHandle LoggingOpenFileForReadAndWrite(const base::FilePath& path,
FileWriteMode mode, FileWriteMode mode,
FilePermissions permissions) { FilePermissions permissions) {
return LoggingOpenFileForOutput( FileHandle file = OpenFileForReadAndWrite(path, mode, permissions);
GENERIC_READ | GENERIC_WRITE, path, mode, permissions); PLOG_IF(ERROR, file == INVALID_HANDLE_VALUE)
<< "CreateFile " << base::UTF16ToUTF8(path.value());
return file;
} }
bool LoggingLockFile(FileHandle file, FileLocking locking) { bool LoggingLockFile(FileHandle file, FileLocking locking) {