mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-27 15:32:10 +08:00
Add FileWriteMode::kCreateOrFail
BUG=crashpad:63 TEST=crashpad_util_test FileIO.OpenFileForWrite R=scottmg@chromium.org Review URL: https://codereview.chromium.org/1390023002 .
This commit is contained in:
parent
5f7eda87a6
commit
2d8a0498ab
@ -14,12 +14,11 @@
|
||||
|
||||
#include "client/crash_report_database.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "build/build_config.h"
|
||||
#include "client/settings.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "test/errors.h"
|
||||
#include "test/file.h"
|
||||
#include "test/scoped_temp_dir.h"
|
||||
#include "util/file/file_io.h"
|
||||
|
||||
@ -27,18 +26,6 @@ namespace crashpad {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
bool FileExistsAtPath(const base::FilePath& path) {
|
||||
#if defined(OS_POSIX)
|
||||
struct stat st;
|
||||
return lstat(path.value().c_str(), &st) == 0;
|
||||
#elif defined(OS_WIN)
|
||||
struct _stat st;
|
||||
return _wstat(path.value().c_str(), &st) == 0;
|
||||
#else
|
||||
#error "Not implemented"
|
||||
#endif
|
||||
}
|
||||
|
||||
class CrashReportDatabaseTest : public testing::Test {
|
||||
public:
|
||||
CrashReportDatabaseTest() {
|
||||
@ -74,7 +61,7 @@ class CrashReportDatabaseTest : public testing::Test {
|
||||
EXPECT_EQ(CrashReportDatabase::kNoError,
|
||||
db_->LookUpCrashReport(uuid, report));
|
||||
ExpectPreparedCrashReport(*report);
|
||||
ASSERT_TRUE(FileExistsAtPath(report->file_path));
|
||||
ASSERT_TRUE(FileExists(report->file_path));
|
||||
}
|
||||
|
||||
void UploadReport(const UUID& uuid, bool successful, const std::string& id) {
|
||||
@ -92,7 +79,7 @@ class CrashReportDatabaseTest : public testing::Test {
|
||||
db_->GetReportForUploading(uuid, &report));
|
||||
EXPECT_NE(UUID(), report->uuid);
|
||||
EXPECT_FALSE(report->file_path.empty());
|
||||
EXPECT_TRUE(FileExistsAtPath(report->file_path))
|
||||
EXPECT_TRUE(FileExists(report->file_path))
|
||||
<< report->file_path.value();
|
||||
EXPECT_GT(report->creation_time, 0);
|
||||
EXPECT_EQ(CrashReportDatabase::kNoError,
|
||||
@ -110,7 +97,7 @@ class CrashReportDatabaseTest : public testing::Test {
|
||||
void ExpectPreparedCrashReport(const CrashReportDatabase::Report& report) {
|
||||
EXPECT_NE(UUID(), report.uuid);
|
||||
EXPECT_FALSE(report.file_path.empty());
|
||||
EXPECT_TRUE(FileExistsAtPath(report.file_path)) << report.file_path.value();
|
||||
EXPECT_TRUE(FileExists(report.file_path)) << report.file_path.value();
|
||||
EXPECT_TRUE(report.id.empty());
|
||||
EXPECT_GT(report.creation_time, 0);
|
||||
EXPECT_FALSE(report.uploaded);
|
||||
@ -180,7 +167,7 @@ TEST_F(CrashReportDatabaseTest, NewCrashReport) {
|
||||
EXPECT_EQ(CrashReportDatabase::kNoError,
|
||||
db()->PrepareNewCrashReport(&new_report));
|
||||
UUID expect_uuid = new_report->uuid;
|
||||
EXPECT_TRUE(FileExistsAtPath(new_report->path)) << new_report->path.value();
|
||||
EXPECT_TRUE(FileExists(new_report->path)) << new_report->path.value();
|
||||
UUID uuid;
|
||||
EXPECT_EQ(CrashReportDatabase::kNoError,
|
||||
db()->FinishedWritingCrashReport(new_report, &uuid));
|
||||
@ -208,10 +195,10 @@ TEST_F(CrashReportDatabaseTest, ErrorWritingCrashReport) {
|
||||
ASSERT_EQ(CrashReportDatabase::kNoError,
|
||||
db()->PrepareNewCrashReport(&new_report));
|
||||
base::FilePath new_report_path = new_report->path;
|
||||
EXPECT_TRUE(FileExistsAtPath(new_report_path)) << new_report_path.value();
|
||||
EXPECT_TRUE(FileExists(new_report_path)) << new_report_path.value();
|
||||
EXPECT_EQ(CrashReportDatabase::kNoError,
|
||||
db()->ErrorWritingCrashReport(new_report));
|
||||
EXPECT_FALSE(FileExistsAtPath(new_report_path)) << new_report_path.value();
|
||||
EXPECT_FALSE(FileExists(new_report_path)) << new_report_path.value();
|
||||
}
|
||||
|
||||
TEST_F(CrashReportDatabaseTest, LookUpCrashReport) {
|
||||
@ -488,7 +475,7 @@ TEST_F(CrashReportDatabaseTest, MoveDatabase) {
|
||||
CrashReportDatabase::NewReport* new_report;
|
||||
EXPECT_EQ(CrashReportDatabase::kNoError,
|
||||
db()->PrepareNewCrashReport(&new_report));
|
||||
EXPECT_TRUE(FileExistsAtPath(new_report->path)) << new_report->path.value();
|
||||
EXPECT_TRUE(FileExists(new_report->path)) << new_report->path.value();
|
||||
UUID uuid;
|
||||
EXPECT_EQ(CrashReportDatabase::kNoError,
|
||||
db()->FinishedWritingCrashReport(new_report, &uuid));
|
||||
@ -499,14 +486,14 @@ TEST_F(CrashReportDatabaseTest, MoveDatabase) {
|
||||
EXPECT_EQ(CrashReportDatabase::kNoError,
|
||||
db()->LookUpCrashReport(uuid, &report));
|
||||
ExpectPreparedCrashReport(report);
|
||||
EXPECT_TRUE(FileExistsAtPath(report.file_path)) << report.file_path.value();
|
||||
EXPECT_TRUE(FileExists(report.file_path)) << report.file_path.value();
|
||||
}
|
||||
|
||||
TEST_F(CrashReportDatabaseTest, ReportRemoved) {
|
||||
CrashReportDatabase::NewReport* new_report;
|
||||
EXPECT_EQ(CrashReportDatabase::kNoError,
|
||||
db()->PrepareNewCrashReport(&new_report));
|
||||
EXPECT_TRUE(FileExistsAtPath(new_report->path)) << new_report->path.value();
|
||||
EXPECT_TRUE(FileExists(new_report->path)) << new_report->path.value();
|
||||
UUID uuid;
|
||||
EXPECT_EQ(CrashReportDatabase::kNoError,
|
||||
db()->FinishedWritingCrashReport(new_report, &uuid));
|
||||
|
66
test/file.cc
Normal file
66
test/file.cc
Normal file
@ -0,0 +1,66 @@
|
||||
// Copyright 2015 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "test/file.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "test/errors.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
|
||||
bool FileExists(const base::FilePath& path) {
|
||||
#if defined(OS_POSIX)
|
||||
struct stat st;
|
||||
int rv = lstat(path.value().c_str(), &st);
|
||||
const char stat_function[] = "lstat";
|
||||
#elif defined(OS_WIN)
|
||||
struct _stat st;
|
||||
int rv = _wstat(path.value().c_str(), &st);
|
||||
const char stat_function[] = "_wstat";
|
||||
#else
|
||||
#error "Not implemented"
|
||||
#endif
|
||||
if (rv < 0) {
|
||||
EXPECT_EQ(ENOENT, errno) << ErrnoMessage(stat_function) << " "
|
||||
<< path.value();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
FileOffset FileSize(const base::FilePath& path) {
|
||||
#if defined(OS_POSIX)
|
||||
struct stat st;
|
||||
int rv = lstat(path.value().c_str(), &st);
|
||||
const char stat_function[] = "lstat";
|
||||
#elif defined(OS_WIN)
|
||||
struct _stati64 st;
|
||||
int rv = _wstati64(path.value().c_str(), &st);
|
||||
const char stat_function[] = "_wstati64";
|
||||
#else
|
||||
#error "Not implemented"
|
||||
#endif
|
||||
if (rv < 0) {
|
||||
ADD_FAILURE() << ErrnoMessage(stat_function) << " " << path.value();
|
||||
return -1;
|
||||
}
|
||||
return st.st_size;
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
45
test/file.h
Normal file
45
test/file.h
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright 2015 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CRASHPAD_TEST_FILE_H_
|
||||
#define CRASHPAD_TEST_FILE_H_
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "util/file/file_io.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
|
||||
//! \brief Determines whether a file exists.
|
||||
//!
|
||||
//! \param[in] path The path to check for existence.
|
||||
//!
|
||||
//! \return `true` if \a path exists. `false` if it does not exist. If an error
|
||||
//! other than “file not found” occurs when searching for \a path, returns
|
||||
//! `false` with a gtest failure added.
|
||||
bool FileExists(const base::FilePath& path);
|
||||
|
||||
//! \brief Determines the size of a file.
|
||||
//!
|
||||
//! \param[in] path The path of the file to check. The file must exist.
|
||||
//!
|
||||
//! \return The size of the file at \a path. If the file does not exist, or an
|
||||
//! error occurs when attempting to determine its size, returns `-1` with a
|
||||
//! gtest failure added.
|
||||
FileOffset FileSize(const base::FilePath& path);
|
||||
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_TEST_FILE_H_
|
@ -14,15 +14,14 @@
|
||||
|
||||
#include "test/scoped_temp_dir.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "base/posix/eintr_wrapper.h"
|
||||
#include "build/build_config.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "test/errors.h"
|
||||
#include "test/file.h"
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#include <unistd.h>
|
||||
@ -35,26 +34,6 @@ namespace crashpad {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
bool FileExists(const base::FilePath& path) {
|
||||
#if defined(OS_POSIX)
|
||||
struct stat st;
|
||||
int rv = lstat(path.value().c_str(), &st);
|
||||
const char stat_function[] = "lstat";
|
||||
#elif defined(OS_WIN)
|
||||
struct _stat st;
|
||||
int rv = _wstat(path.value().c_str(), &st);
|
||||
const char stat_function[] = "_wstat";
|
||||
#else
|
||||
#error "Not implemented"
|
||||
#endif
|
||||
if (rv < 0) {
|
||||
EXPECT_EQ(ENOENT, errno) << ErrnoMessage(stat_function) << " "
|
||||
<< path.value();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CreateFile(const base::FilePath& path) {
|
||||
#if defined(OS_POSIX)
|
||||
int fd = HANDLE_EINTR(creat(path.value().c_str(), 0644));
|
||||
|
@ -32,6 +32,8 @@
|
||||
'sources': [
|
||||
'errors.cc',
|
||||
'errors.h',
|
||||
'file.cc',
|
||||
'file.h',
|
||||
'gtest_death_check.h',
|
||||
'mac/dyld.h',
|
||||
'mac/mach_errors.cc',
|
||||
|
@ -79,6 +79,9 @@ const FileHandle kInvalidFileHandle = INVALID_HANDLE_VALUE;
|
||||
|
||||
//! \brief Determines the mode that LoggingOpenFileForWrite() uses.
|
||||
enum class FileWriteMode {
|
||||
//! \brief Opens the file if it exists, or fails if it does not.
|
||||
kReuseOrFail,
|
||||
|
||||
//! \brief Opens the file if it exists, or creates a new file.
|
||||
kReuseOrCreate,
|
||||
|
||||
|
@ -75,12 +75,22 @@ FileHandle LoggingOpenFileForOutput(int rdwr_or_wronly,
|
||||
const base::FilePath& path,
|
||||
FileWriteMode mode,
|
||||
FilePermissions permissions) {
|
||||
int flags = rdwr_or_wronly | O_CREAT;
|
||||
// kReuseOrCreate does not need any additional flags.
|
||||
if (mode == FileWriteMode::kTruncateOrCreate)
|
||||
flags |= O_TRUNC;
|
||||
else if (mode == FileWriteMode::kCreateOrFail)
|
||||
flags |= O_EXCL;
|
||||
int flags = rdwr_or_wronly & (O_RDWR | O_WRONLY);
|
||||
DCHECK_NE(flags, 0);
|
||||
|
||||
switch (mode) {
|
||||
case FileWriteMode::kReuseOrFail:
|
||||
break;
|
||||
case FileWriteMode::kReuseOrCreate:
|
||||
flags |= O_CREAT;
|
||||
break;
|
||||
case FileWriteMode::kTruncateOrCreate:
|
||||
flags |= O_CREAT | O_TRUNC;
|
||||
break;
|
||||
case FileWriteMode::kCreateOrFail:
|
||||
flags |= O_CREAT | O_EXCL;
|
||||
break;
|
||||
}
|
||||
|
||||
int fd = HANDLE_EINTR(
|
||||
open(path.value().c_str(),
|
||||
|
@ -19,13 +19,100 @@
|
||||
#include "base/files/file_path.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "test/errors.h"
|
||||
#include "test/file.h"
|
||||
#include "test/scoped_temp_dir.h"
|
||||
#include "util/misc/implicit_cast.h"
|
||||
#include "util/thread/thread.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
TEST(FileIO, OpenFileForWrite) {
|
||||
ScopedTempDir temp_dir;
|
||||
base::FilePath file_path_1 =
|
||||
temp_dir.path().Append(FILE_PATH_LITERAL("file_1"));
|
||||
ASSERT_FALSE(FileExists(file_path_1));
|
||||
|
||||
ScopedFileHandle
|
||||
file_handle(LoggingOpenFileForWrite(file_path_1,
|
||||
FileWriteMode::kReuseOrFail,
|
||||
FilePermissions::kWorldReadable));
|
||||
EXPECT_EQ(kInvalidFileHandle, file_handle);
|
||||
EXPECT_FALSE(FileExists(file_path_1));
|
||||
|
||||
file_handle.reset(LoggingOpenFileForWrite(file_path_1,
|
||||
FileWriteMode::kCreateOrFail,
|
||||
FilePermissions::kWorldReadable));
|
||||
EXPECT_NE(kInvalidFileHandle, file_handle);
|
||||
EXPECT_TRUE(FileExists(file_path_1));
|
||||
EXPECT_EQ(0, FileSize(file_path_1));
|
||||
|
||||
file_handle.reset(LoggingOpenFileForWrite(file_path_1,
|
||||
FileWriteMode::kReuseOrCreate,
|
||||
FilePermissions::kWorldReadable));
|
||||
EXPECT_NE(kInvalidFileHandle, file_handle);
|
||||
EXPECT_TRUE(FileExists(file_path_1));
|
||||
EXPECT_EQ(0, FileSize(file_path_1));
|
||||
|
||||
const char data = '%';
|
||||
EXPECT_TRUE(LoggingWriteFile(file_handle.get(), &data, sizeof(data)));
|
||||
|
||||
// Close file_handle to ensure that the write is flushed to disk.
|
||||
file_handle.reset();
|
||||
EXPECT_EQ(implicit_cast<FileOffset>(sizeof(data)), FileSize(file_path_1));
|
||||
|
||||
file_handle.reset(LoggingOpenFileForWrite(file_path_1,
|
||||
FileWriteMode::kReuseOrCreate,
|
||||
FilePermissions::kWorldReadable));
|
||||
EXPECT_NE(kInvalidFileHandle, file_handle);
|
||||
EXPECT_TRUE(FileExists(file_path_1));
|
||||
EXPECT_EQ(implicit_cast<FileOffset>(sizeof(data)), FileSize(file_path_1));
|
||||
|
||||
file_handle.reset(LoggingOpenFileForWrite(file_path_1,
|
||||
FileWriteMode::kCreateOrFail,
|
||||
FilePermissions::kWorldReadable));
|
||||
EXPECT_EQ(kInvalidFileHandle, file_handle);
|
||||
EXPECT_TRUE(FileExists(file_path_1));
|
||||
EXPECT_EQ(implicit_cast<FileOffset>(sizeof(data)), FileSize(file_path_1));
|
||||
|
||||
file_handle.reset(LoggingOpenFileForWrite(file_path_1,
|
||||
FileWriteMode::kReuseOrFail,
|
||||
FilePermissions::kWorldReadable));
|
||||
EXPECT_NE(kInvalidFileHandle, file_handle);
|
||||
EXPECT_TRUE(FileExists(file_path_1));
|
||||
EXPECT_EQ(implicit_cast<FileOffset>(sizeof(data)), FileSize(file_path_1));
|
||||
|
||||
file_handle.reset(LoggingOpenFileForWrite(file_path_1,
|
||||
FileWriteMode::kTruncateOrCreate,
|
||||
FilePermissions::kWorldReadable));
|
||||
EXPECT_NE(kInvalidFileHandle, file_handle);
|
||||
EXPECT_TRUE(FileExists(file_path_1));
|
||||
EXPECT_EQ(0, FileSize(file_path_1));
|
||||
|
||||
base::FilePath file_path_2 =
|
||||
temp_dir.path().Append(FILE_PATH_LITERAL("file_2"));
|
||||
ASSERT_FALSE(FileExists(file_path_2));
|
||||
|
||||
file_handle.reset(LoggingOpenFileForWrite(file_path_2,
|
||||
FileWriteMode::kTruncateOrCreate,
|
||||
FilePermissions::kWorldReadable));
|
||||
EXPECT_NE(kInvalidFileHandle, file_handle);
|
||||
EXPECT_TRUE(FileExists(file_path_2));
|
||||
EXPECT_EQ(0, FileSize(file_path_2));
|
||||
|
||||
base::FilePath file_path_3 =
|
||||
temp_dir.path().Append(FILE_PATH_LITERAL("file_3"));
|
||||
ASSERT_FALSE(FileExists(file_path_3));
|
||||
|
||||
file_handle.reset(LoggingOpenFileForWrite(file_path_3,
|
||||
FileWriteMode::kReuseOrCreate,
|
||||
FilePermissions::kWorldReadable));
|
||||
EXPECT_NE(kInvalidFileHandle, file_handle);
|
||||
EXPECT_TRUE(FileExists(file_path_3));
|
||||
EXPECT_EQ(0, FileSize(file_path_3));
|
||||
}
|
||||
|
||||
enum class ReadOrWrite : bool {
|
||||
kRead,
|
||||
kWrite,
|
||||
|
@ -43,6 +43,9 @@ FileHandle LoggingOpenFileForOutput(DWORD access,
|
||||
FilePermissions permissions) {
|
||||
DWORD disposition = 0;
|
||||
switch (mode) {
|
||||
case FileWriteMode::kReuseOrFail:
|
||||
disposition = OPEN_EXISTING;
|
||||
break;
|
||||
case FileWriteMode::kReuseOrCreate:
|
||||
disposition = OPEN_ALWAYS;
|
||||
break;
|
||||
|
Loading…
x
Reference in New Issue
Block a user