mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
Cross platform low level file IO wrappers
Rename fd_io to file_io, and ReadFD to ReadFile, etc. file_io.cc is the higher level versions that call the basic ReadFile/WriteFile and then file_io_posix.cc and file_io_win.cc are the implementations of those functions. The Windows path is as yet untested, lacking the ability to link the test binary. R=cpu@chromium.org, mark@chromium.org BUG=crashpad:1 Review URL: https://codereview.chromium.org/811823003
This commit is contained in:
parent
3d84a738d0
commit
10165ce449
@ -30,7 +30,7 @@
|
|||||||
#include "client/simple_string_dictionary.h"
|
#include "client/simple_string_dictionary.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "snapshot/mac/process_reader.h"
|
#include "snapshot/mac/process_reader.h"
|
||||||
#include "util/file/fd_io.h"
|
#include "util/file/file_io.h"
|
||||||
#include "util/mac/mac_util.h"
|
#include "util/mac/mac_util.h"
|
||||||
#include "util/mach/exc_server_variants.h"
|
#include "util/mach/exc_server_variants.h"
|
||||||
#include "util/mach/exception_ports.h"
|
#include "util/mach/exception_ports.h"
|
||||||
@ -193,7 +193,7 @@ class TestMachOImageAnnotationsReader final
|
|||||||
// Wait for the child process to indicate that it’s done setting up its
|
// Wait for the child process to indicate that it’s done setting up its
|
||||||
// annotations via the CrashpadInfo interface.
|
// annotations via the CrashpadInfo interface.
|
||||||
char c;
|
char c;
|
||||||
CheckedReadFD(ReadPipeFD(), &c, sizeof(c));
|
CheckedReadFile(ReadPipeFD(), &c, sizeof(c));
|
||||||
|
|
||||||
// Verify the “simple map” annotations set via the CrashpadInfo interface.
|
// Verify the “simple map” annotations set via the CrashpadInfo interface.
|
||||||
const std::vector<ProcessReader::Module>& modules =
|
const std::vector<ProcessReader::Module>& modules =
|
||||||
@ -216,7 +216,7 @@ class TestMachOImageAnnotationsReader final
|
|||||||
EXPECT_EQ("", all_annotations_simple_map["#TEST# empty_value"]);
|
EXPECT_EQ("", all_annotations_simple_map["#TEST# empty_value"]);
|
||||||
|
|
||||||
// Tell the child process that it’s permitted to crash.
|
// Tell the child process that it’s permitted to crash.
|
||||||
CheckedWriteFD(WritePipeFD(), &c, sizeof(c));
|
CheckedWriteFile(WritePipeFD(), &c, sizeof(c));
|
||||||
|
|
||||||
if (test_type_ != kDontCrash) {
|
if (test_type_ != kDontCrash) {
|
||||||
// Handle the child’s crash. Further validation will be done in
|
// Handle the child’s crash. Further validation will be done in
|
||||||
@ -268,10 +268,10 @@ class TestMachOImageAnnotationsReader final
|
|||||||
|
|
||||||
// Tell the parent that the environment has been set up.
|
// Tell the parent that the environment has been set up.
|
||||||
char c = '\0';
|
char c = '\0';
|
||||||
CheckedWriteFD(WritePipeFD(), &c, sizeof(c));
|
CheckedWriteFile(WritePipeFD(), &c, sizeof(c));
|
||||||
|
|
||||||
// Wait for the parent to indicate that it’s safe to crash.
|
// Wait for the parent to indicate that it’s safe to crash.
|
||||||
CheckedReadFD(ReadPipeFD(), &c, sizeof(c));
|
CheckedReadFile(ReadPipeFD(), &c, sizeof(c));
|
||||||
|
|
||||||
// Direct an exception message to the exception server running in the
|
// Direct an exception message to the exception server running in the
|
||||||
// parent.
|
// parent.
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
#include "build/build_config.h"
|
#include "build/build_config.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "snapshot/mac/mach_o_image_reader.h"
|
#include "snapshot/mac/mach_o_image_reader.h"
|
||||||
#include "util/file/fd_io.h"
|
#include "util/file/file_io.h"
|
||||||
#include "util/mach/mach_extensions.h"
|
#include "util/mach/mach_extensions.h"
|
||||||
#include "util/stdlib/pointer_container.h"
|
#include "util/stdlib/pointer_container.h"
|
||||||
#include "util/synchronization/semaphore.h"
|
#include "util/synchronization/semaphore.h"
|
||||||
@ -91,7 +91,7 @@ class ProcessReaderChild final : public MachMultiprocess {
|
|||||||
int read_fd = ReadPipeFD();
|
int read_fd = ReadPipeFD();
|
||||||
|
|
||||||
mach_vm_address_t address;
|
mach_vm_address_t address;
|
||||||
CheckedReadFD(read_fd, &address, sizeof(address));
|
CheckedReadFile(read_fd, &address, sizeof(address));
|
||||||
|
|
||||||
std::string read_string;
|
std::string read_string;
|
||||||
ASSERT_TRUE(process_reader.Memory()->ReadCString(address, &read_string));
|
ASSERT_TRUE(process_reader.Memory()->ReadCString(address, &read_string));
|
||||||
@ -103,11 +103,11 @@ class ProcessReaderChild final : public MachMultiprocess {
|
|||||||
|
|
||||||
mach_vm_address_t address =
|
mach_vm_address_t address =
|
||||||
reinterpret_cast<mach_vm_address_t>(kTestMemory);
|
reinterpret_cast<mach_vm_address_t>(kTestMemory);
|
||||||
CheckedWriteFD(write_fd, &address, sizeof(address));
|
CheckedWriteFile(write_fd, &address, sizeof(address));
|
||||||
|
|
||||||
// Wait for the parent to signal that it’s OK to exit by closing its end of
|
// Wait for the parent to signal that it’s OK to exit by closing its end of
|
||||||
// the pipe.
|
// the pipe.
|
||||||
CheckedReadFDAtEOF(ReadPipeFD());
|
CheckedReadFileAtEOF(ReadPipeFD());
|
||||||
}
|
}
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(ProcessReaderChild);
|
DISALLOW_COPY_AND_ASSIGN(ProcessReaderChild);
|
||||||
@ -434,15 +434,15 @@ class ProcessReaderThreadedChild final : public MachMultiprocess {
|
|||||||
thread_index < thread_count_ + 1;
|
thread_index < thread_count_ + 1;
|
||||||
++thread_index) {
|
++thread_index) {
|
||||||
uint64_t thread_id;
|
uint64_t thread_id;
|
||||||
CheckedReadFD(read_fd, &thread_id, sizeof(thread_id));
|
CheckedReadFile(read_fd, &thread_id, sizeof(thread_id));
|
||||||
|
|
||||||
TestThreadPool::ThreadExpectation expectation;
|
TestThreadPool::ThreadExpectation expectation;
|
||||||
CheckedReadFD(read_fd,
|
CheckedReadFile(read_fd,
|
||||||
&expectation.stack_address,
|
&expectation.stack_address,
|
||||||
sizeof(expectation.stack_address));
|
sizeof(expectation.stack_address));
|
||||||
CheckedReadFD(read_fd,
|
CheckedReadFile(read_fd,
|
||||||
&expectation.suspend_count,
|
&expectation.suspend_count,
|
||||||
sizeof(expectation.suspend_count));
|
sizeof(expectation.suspend_count));
|
||||||
|
|
||||||
// There can’t be any duplicate thread IDs.
|
// There can’t be any duplicate thread IDs.
|
||||||
EXPECT_EQ(0u, thread_map.count(thread_id));
|
EXPECT_EQ(0u, thread_map.count(thread_id));
|
||||||
@ -467,18 +467,18 @@ class ProcessReaderThreadedChild final : public MachMultiprocess {
|
|||||||
// to inspect it. Write an entry for it.
|
// to inspect it. Write an entry for it.
|
||||||
uint64_t thread_id = PthreadToThreadID(pthread_self());
|
uint64_t thread_id = PthreadToThreadID(pthread_self());
|
||||||
|
|
||||||
CheckedWriteFD(write_fd, &thread_id, sizeof(thread_id));
|
CheckedWriteFile(write_fd, &thread_id, sizeof(thread_id));
|
||||||
|
|
||||||
TestThreadPool::ThreadExpectation expectation;
|
TestThreadPool::ThreadExpectation expectation;
|
||||||
expectation.stack_address = reinterpret_cast<mach_vm_address_t>(&thread_id);
|
expectation.stack_address = reinterpret_cast<mach_vm_address_t>(&thread_id);
|
||||||
expectation.suspend_count = 0;
|
expectation.suspend_count = 0;
|
||||||
|
|
||||||
CheckedWriteFD(write_fd,
|
CheckedWriteFile(write_fd,
|
||||||
&expectation.stack_address,
|
&expectation.stack_address,
|
||||||
sizeof(expectation.stack_address));
|
sizeof(expectation.stack_address));
|
||||||
CheckedWriteFD(write_fd,
|
CheckedWriteFile(write_fd,
|
||||||
&expectation.suspend_count,
|
&expectation.suspend_count,
|
||||||
sizeof(expectation.suspend_count));
|
sizeof(expectation.suspend_count));
|
||||||
|
|
||||||
// Write an entry for everything in the thread pool.
|
// Write an entry for everything in the thread pool.
|
||||||
for (size_t thread_index = 0;
|
for (size_t thread_index = 0;
|
||||||
@ -487,18 +487,18 @@ class ProcessReaderThreadedChild final : public MachMultiprocess {
|
|||||||
uint64_t thread_id =
|
uint64_t thread_id =
|
||||||
thread_pool.GetThreadInfo(thread_index, &expectation);
|
thread_pool.GetThreadInfo(thread_index, &expectation);
|
||||||
|
|
||||||
CheckedWriteFD(write_fd, &thread_id, sizeof(thread_id));
|
CheckedWriteFile(write_fd, &thread_id, sizeof(thread_id));
|
||||||
CheckedWriteFD(write_fd,
|
CheckedWriteFile(write_fd,
|
||||||
&expectation.stack_address,
|
&expectation.stack_address,
|
||||||
sizeof(expectation.stack_address));
|
sizeof(expectation.stack_address));
|
||||||
CheckedWriteFD(write_fd,
|
CheckedWriteFile(write_fd,
|
||||||
&expectation.suspend_count,
|
&expectation.suspend_count,
|
||||||
sizeof(expectation.suspend_count));
|
sizeof(expectation.suspend_count));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for the parent to signal that it’s OK to exit by closing its end of
|
// Wait for the parent to signal that it’s OK to exit by closing its end of
|
||||||
// the pipe.
|
// the pipe.
|
||||||
CheckedReadFDAtEOF(ReadPipeFD());
|
CheckedReadFileAtEOF(ReadPipeFD());
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t thread_count_;
|
size_t thread_count_;
|
||||||
@ -597,7 +597,7 @@ class ProcessReaderModulesChild final : public MachMultiprocess {
|
|||||||
int read_fd = ReadPipeFD();
|
int read_fd = ReadPipeFD();
|
||||||
|
|
||||||
uint32_t expect_modules;
|
uint32_t expect_modules;
|
||||||
CheckedReadFD(read_fd, &expect_modules, sizeof(expect_modules));
|
CheckedReadFile(read_fd, &expect_modules, sizeof(expect_modules));
|
||||||
|
|
||||||
ASSERT_EQ(expect_modules, modules.size());
|
ASSERT_EQ(expect_modules, modules.size());
|
||||||
|
|
||||||
@ -606,16 +606,16 @@ class ProcessReaderModulesChild final : public MachMultiprocess {
|
|||||||
"index %zu, name %s", index, modules[index].name.c_str()));
|
"index %zu, name %s", index, modules[index].name.c_str()));
|
||||||
|
|
||||||
uint32_t expect_name_length;
|
uint32_t expect_name_length;
|
||||||
CheckedReadFD(
|
CheckedReadFile(
|
||||||
read_fd, &expect_name_length, sizeof(expect_name_length));
|
read_fd, &expect_name_length, sizeof(expect_name_length));
|
||||||
|
|
||||||
// The NUL terminator is not read.
|
// The NUL terminator is not read.
|
||||||
std::string expect_name(expect_name_length, '\0');
|
std::string expect_name(expect_name_length, '\0');
|
||||||
CheckedReadFD(read_fd, &expect_name[0], expect_name_length);
|
CheckedReadFile(read_fd, &expect_name[0], expect_name_length);
|
||||||
EXPECT_EQ(expect_name, modules[index].name);
|
EXPECT_EQ(expect_name, modules[index].name);
|
||||||
|
|
||||||
mach_vm_address_t expect_address;
|
mach_vm_address_t expect_address;
|
||||||
CheckedReadFD(read_fd, &expect_address, sizeof(expect_address));
|
CheckedReadFile(read_fd, &expect_address, sizeof(expect_address));
|
||||||
EXPECT_EQ(expect_address, modules[index].reader->Address());
|
EXPECT_EQ(expect_address, modules[index].reader->Address());
|
||||||
|
|
||||||
if (index == 0 || index == modules.size() - 1) {
|
if (index == 0 || index == modules.size() - 1) {
|
||||||
@ -648,7 +648,7 @@ class ProcessReaderModulesChild final : public MachMultiprocess {
|
|||||||
++write_image_count;
|
++write_image_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckedWriteFD(write_fd, &write_image_count, sizeof(write_image_count));
|
CheckedWriteFile(write_fd, &write_image_count, sizeof(write_image_count));
|
||||||
|
|
||||||
for (size_t index = 0; index < write_image_count; ++index) {
|
for (size_t index = 0; index < write_image_count; ++index) {
|
||||||
const char* dyld_image_name;
|
const char* dyld_image_name;
|
||||||
@ -665,18 +665,19 @@ class ProcessReaderModulesChild final : public MachMultiprocess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t dyld_image_name_length = strlen(dyld_image_name);
|
uint32_t dyld_image_name_length = strlen(dyld_image_name);
|
||||||
CheckedWriteFD(
|
CheckedWriteFile(
|
||||||
write_fd, &dyld_image_name_length, sizeof(dyld_image_name_length));
|
write_fd, &dyld_image_name_length, sizeof(dyld_image_name_length));
|
||||||
|
|
||||||
// The NUL terminator is not written.
|
// The NUL terminator is not written.
|
||||||
CheckedWriteFD(write_fd, dyld_image_name, dyld_image_name_length);
|
CheckedWriteFile(write_fd, dyld_image_name, dyld_image_name_length);
|
||||||
|
|
||||||
CheckedWriteFD(write_fd, &dyld_image_address, sizeof(dyld_image_address));
|
CheckedWriteFile(
|
||||||
|
write_fd, &dyld_image_address, sizeof(dyld_image_address));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for the parent to signal that it’s OK to exit by closing its end of
|
// Wait for the parent to signal that it’s OK to exit by closing its end of
|
||||||
// the pipe.
|
// the pipe.
|
||||||
CheckedReadFDAtEOF(ReadPipeFD());
|
CheckedReadFileAtEOF(ReadPipeFD());
|
||||||
}
|
}
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(ProcessReaderModulesChild);
|
DISALLOW_COPY_AND_ASSIGN(ProcessReaderModulesChild);
|
||||||
|
@ -1,125 +0,0 @@
|
|||||||
// Copyright 2014 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_UTIL_FILE_FD_IO_H_
|
|
||||||
#define CRASHPAD_UTIL_FILE_FD_IO_H_
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
namespace crashpad {
|
|
||||||
|
|
||||||
//! \brief Wraps `read()`, retrying when interrupted or following a short read.
|
|
||||||
//!
|
|
||||||
//! This function reads into \a buffer, stopping only when \a size bytes have
|
|
||||||
//! been read or when `read()` returns 0, indicating that end-of-file has been
|
|
||||||
//! reached.
|
|
||||||
//!
|
|
||||||
//! \return The number of bytes read and placed into \a buffer, or `-1` on
|
|
||||||
//! error, with `errno` set appropriately. On error, a portion of \a fd may
|
|
||||||
//! have been read into \a buffer.
|
|
||||||
//!
|
|
||||||
//! \sa WriteFD
|
|
||||||
//! \sa LoggingReadFD
|
|
||||||
//! \sa CheckedReadFD
|
|
||||||
//! \sa CheckedReadFDAtEOF
|
|
||||||
ssize_t ReadFD(int fd, void* buffer, size_t size);
|
|
||||||
|
|
||||||
//! \brief Wraps `write()`, retrying when interrupted or following a short
|
|
||||||
//! write.
|
|
||||||
//!
|
|
||||||
//! This function writes to \a fd, stopping only when \a size bytes have been
|
|
||||||
//! written.
|
|
||||||
//!
|
|
||||||
//! \return The number of bytes written from \a buffer, or `-1` on error, with
|
|
||||||
//! `errno` set appropriately. On error, a portion of \a buffer may have
|
|
||||||
//! been written to \a fd.
|
|
||||||
//!
|
|
||||||
//! \sa ReadFD
|
|
||||||
//! \sa LoggingWriteFD
|
|
||||||
//! \sa CheckedWriteFD
|
|
||||||
ssize_t WriteFD(int fd, const void* buffer, size_t size);
|
|
||||||
|
|
||||||
//! \brief Wraps ReadFD(), ensuring that exactly \a size bytes are read.
|
|
||||||
//!
|
|
||||||
//! \return `true` on success. If \a size is out of the range of possible
|
|
||||||
//! `read()` return values, if the underlying ReadFD() fails, or if other
|
|
||||||
//! than \a size bytes were read, this function logs a message and returns
|
|
||||||
//! `false`.
|
|
||||||
//!
|
|
||||||
//! \sa LoggingWriteFD
|
|
||||||
//! \sa ReadFD
|
|
||||||
//! \sa CheckedReadFD
|
|
||||||
//! \sa CheckedReadFDAtEOF
|
|
||||||
bool LoggingReadFD(int fd, void* buffer, size_t size);
|
|
||||||
|
|
||||||
//! \brief Wraps WriteFD(), ensuring that exactly \a size bytes are written.
|
|
||||||
//!
|
|
||||||
//! \return `true` on success. If \a size is out of the range of possible
|
|
||||||
//! `write()` return values, if the underlying WriteFD() fails, or if other
|
|
||||||
//! than \a size bytes were written, this function logs a message and
|
|
||||||
//! returns `false`.
|
|
||||||
//!
|
|
||||||
//! \sa LoggingReadFD
|
|
||||||
//! \sa WriteFD
|
|
||||||
//! \sa CheckedWriteFD
|
|
||||||
bool LoggingWriteFD(int fd, const void* buffer, size_t size);
|
|
||||||
|
|
||||||
//! \brief Wraps ReadFD(), ensuring that exactly \a size bytes are read.
|
|
||||||
//!
|
|
||||||
//! If \a size is out of the range of possible `read()` return values, if the
|
|
||||||
//! underlying ReadFD() fails, or if other than \a size bytes were read, this
|
|
||||||
//! function causes execution to terminate without returning.
|
|
||||||
//!
|
|
||||||
//! \sa CheckedWriteFD
|
|
||||||
//! \sa ReadFD
|
|
||||||
//! \sa LoggingReadFD
|
|
||||||
//! \sa CheckedReadFDAtEOF
|
|
||||||
void CheckedReadFD(int fd, void* buffer, size_t size);
|
|
||||||
|
|
||||||
//! \brief Wraps WriteFD(), ensuring that exactly \a size bytes are written.
|
|
||||||
//!
|
|
||||||
//! If \a size is out of the range of possible `write()` return values, if the
|
|
||||||
//! underlying WriteFD() fails, or if other than \a size bytes were written,
|
|
||||||
//! this function causes execution to terminate without returning.
|
|
||||||
//!
|
|
||||||
//! \sa CheckedReadFD
|
|
||||||
//! \sa WriteFD
|
|
||||||
//! \sa LoggingWriteFD
|
|
||||||
void CheckedWriteFD(int fd, const void* buffer, size_t size);
|
|
||||||
|
|
||||||
//! \brief Wraps ReadFD(), ensuring that it indicates end-of-file.
|
|
||||||
//!
|
|
||||||
//! Attempts to read a single byte from \a fd, expecting no data to be read. If
|
|
||||||
//! the underlying ReadFD() fails, or if a byte actually is read, this function
|
|
||||||
//! causes execution to terminate without returning.
|
|
||||||
//!
|
|
||||||
//! \sa CheckedReadFD
|
|
||||||
//! \sa ReadFD
|
|
||||||
void CheckedReadFDAtEOF(int fd);
|
|
||||||
|
|
||||||
//! \brief Wraps `close()`, logging an error if the operation fails.
|
|
||||||
//!
|
|
||||||
//! \return On success, `true` is returned. On failure, an error is logged and
|
|
||||||
//! `false` is returned.
|
|
||||||
bool LoggingCloseFD(int fd);
|
|
||||||
|
|
||||||
//! \brief Wraps `close()`, ensuring that it succeeds.
|
|
||||||
//!
|
|
||||||
//! If `close()` fails, this function causes execution to terminate without
|
|
||||||
//! returning.
|
|
||||||
void CheckedCloseFD(int fd);
|
|
||||||
|
|
||||||
} // namespace crashpad
|
|
||||||
|
|
||||||
#endif // CRASHPAD_UTIL_FILE_FD_IO_H_
|
|
74
util/file/file_io.cc
Normal file
74
util/file/file_io.cc
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// Copyright 2014 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 "util/file/file_io.h"
|
||||||
|
|
||||||
|
#include "base/logging.h"
|
||||||
|
#include "base/numerics/safe_conversions.h"
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
|
||||||
|
bool LoggingReadFile(FileHandle file, void* buffer, size_t size) {
|
||||||
|
ssize_t expect = base::checked_cast<ssize_t>(size);
|
||||||
|
ssize_t rv = ReadFile(file, buffer, size);
|
||||||
|
if (rv < 0) {
|
||||||
|
PLOG(ERROR) << "read";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (rv != expect) {
|
||||||
|
LOG(ERROR) << "read: expected " << expect << ", observed " << rv;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LoggingWriteFile(FileHandle file, const void* buffer, size_t size) {
|
||||||
|
ssize_t expect = base::checked_cast<ssize_t>(size);
|
||||||
|
ssize_t rv = WriteFile(file, buffer, size);
|
||||||
|
if (rv < 0) {
|
||||||
|
PLOG(ERROR) << "write";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (rv != expect) {
|
||||||
|
LOG(ERROR) << "write: expected " << expect << ", observed " << rv;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckedReadFile(FileHandle file, void* buffer, size_t size) {
|
||||||
|
CHECK(LoggingReadFile(file, buffer, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckedWriteFile(FileHandle file, const void* buffer, size_t size) {
|
||||||
|
CHECK(LoggingWriteFile(file, buffer, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckedReadFileAtEOF(FileHandle file) {
|
||||||
|
char c;
|
||||||
|
ssize_t rv = ReadFile(file, &c, 1);
|
||||||
|
if (rv < 0) {
|
||||||
|
PCHECK(rv == 0) << "read";
|
||||||
|
} else {
|
||||||
|
CHECK_EQ(rv, 0) << "read";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckedCloseFile(FileHandle file) {
|
||||||
|
CHECK(LoggingCloseFile(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace crashpad
|
139
util/file/file_io.h
Normal file
139
util/file/file_io.h
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
// Copyright 2014 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_UTIL_FILE_FILE_IO_H_
|
||||||
|
#define CRASHPAD_UTIL_FILE_FILE_IO_H_
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "build/build_config.h"
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
|
||||||
|
#if defined(OS_POSIX)
|
||||||
|
using FileHandle = int;
|
||||||
|
#elif defined(OS_WIN)
|
||||||
|
using FileHandle = HANDLE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! \brief Reads from a file, retrying when interrupted on POSIX or following a
|
||||||
|
//! short read.
|
||||||
|
//!
|
||||||
|
//! This function reads into \a buffer, stopping only when \a size bytes have
|
||||||
|
//! been read or when end-of-file has been reached. On Windows, reading from
|
||||||
|
//! sockets is not currently supported.
|
||||||
|
//!
|
||||||
|
//! \return The number of bytes read and placed into \a buffer, or `-1` on
|
||||||
|
//! error, with `errno` or `GetLastError()` set appropriately. On error, a
|
||||||
|
//! portion of \a file may have been read into \a buffer.
|
||||||
|
//!
|
||||||
|
//! \sa WriteFile
|
||||||
|
//! \sa LoggingReadFile
|
||||||
|
//! \sa CheckedReadFile
|
||||||
|
//! \sa CheckedReadFileAtEOF
|
||||||
|
ssize_t ReadFile(FileHandle file, void* buffer, size_t size);
|
||||||
|
|
||||||
|
//! \brief Writes to a file, retrying when interrupted or following a short
|
||||||
|
//! write on POSIX.
|
||||||
|
//!
|
||||||
|
//! This function writes to \a file, stopping only when \a size bytes have been
|
||||||
|
//! written.
|
||||||
|
//!
|
||||||
|
//! \return The number of bytes written from \a buffer, or `-1` on error, with
|
||||||
|
//! `errno` or `GetLastError()` set appropriately. On error, a portion of
|
||||||
|
//! \a buffer may have been written to \a file.
|
||||||
|
//!
|
||||||
|
//! \sa ReadFile
|
||||||
|
//! \sa LoggingWriteFile
|
||||||
|
//! \sa CheckedWriteFile
|
||||||
|
ssize_t WriteFile(FileHandle file, const void* buffer, size_t size);
|
||||||
|
|
||||||
|
//! \brief Wraps ReadFile(), ensuring that exactly \a size bytes are read.
|
||||||
|
//!
|
||||||
|
//! \return `true` on success. If \a size is out of the range of possible
|
||||||
|
//! ReadFile() return values, if the underlying ReadFile() fails, or if
|
||||||
|
//! other than \a size bytes were read, this function logs a message and
|
||||||
|
//! returns `false`.
|
||||||
|
//!
|
||||||
|
//! \sa LoggingWriteFile
|
||||||
|
//! \sa ReadFile
|
||||||
|
//! \sa CheckedReadFile
|
||||||
|
//! \sa CheckedReadFileAtEOF
|
||||||
|
bool LoggingReadFile(FileHandle file, void* buffer, size_t size);
|
||||||
|
|
||||||
|
//! \brief Wraps WriteFile(), ensuring that exactly \a size bytes are written.
|
||||||
|
//!
|
||||||
|
//! \return `true` on success. If \a size is out of the range of possible
|
||||||
|
//! WriteFile() return values, if the underlying WriteFile() fails, or if
|
||||||
|
//! other than \a size bytes were written, this function logs a message and
|
||||||
|
//! returns `false`.
|
||||||
|
//!
|
||||||
|
//! \sa LoggingReadFile
|
||||||
|
//! \sa WriteFile
|
||||||
|
//! \sa CheckedWriteFile
|
||||||
|
bool LoggingWriteFile(FileHandle file, const void* buffer, size_t size);
|
||||||
|
|
||||||
|
//! \brief Wraps ReadFile(), ensuring that exactly \a size bytes are read.
|
||||||
|
//!
|
||||||
|
//! If \a size is out of the range of possible ReadFile() return values, if the
|
||||||
|
//! underlying ReadFile() fails, or if other than \a size bytes were read, this
|
||||||
|
//! function causes execution to terminate without returning.
|
||||||
|
//!
|
||||||
|
//! \sa CheckedWriteFile
|
||||||
|
//! \sa ReadFile
|
||||||
|
//! \sa LoggingReadFile
|
||||||
|
//! \sa CheckedReadFileAtEOF
|
||||||
|
void CheckedReadFile(FileHandle file, void* buffer, size_t size);
|
||||||
|
|
||||||
|
//! \brief Wraps WriteFile(), ensuring that exactly \a size bytes are written.
|
||||||
|
//!
|
||||||
|
//! If \a size is out of the range of possible WriteFile() return values, if the
|
||||||
|
//! underlying WriteFile() fails, or if other than \a size bytes were written,
|
||||||
|
//! this function causes execution to terminate without returning.
|
||||||
|
//!
|
||||||
|
//! \sa CheckedReadFile
|
||||||
|
//! \sa WriteFile
|
||||||
|
//! \sa LoggingWriteFile
|
||||||
|
void CheckedWriteFile(FileHandle file, const void* buffer, size_t size);
|
||||||
|
|
||||||
|
//! \brief Wraps ReadFile(), ensuring that it indicates end-of-file.
|
||||||
|
//!
|
||||||
|
//! Attempts to read a single byte from \a file, expecting no data to be read.
|
||||||
|
//! If the underlying ReadFile() fails, or if a byte actually is read, this
|
||||||
|
//! function causes execution to terminate without returning.
|
||||||
|
//!
|
||||||
|
//! \sa CheckedReadFile
|
||||||
|
//! \sa ReadFile
|
||||||
|
void CheckedReadFileAtEOF(FileHandle file);
|
||||||
|
|
||||||
|
//! \brief Wraps `close()` or `CloseHandle()`, logging an error if the operation
|
||||||
|
//! fails.
|
||||||
|
//!
|
||||||
|
//! \return On success, `true` is returned. On failure, an error is logged and
|
||||||
|
//! `false` is returned.
|
||||||
|
bool LoggingCloseFile(FileHandle file);
|
||||||
|
|
||||||
|
//! \brief Wraps `close()` or `CloseHandle()`, ensuring that it succeeds.
|
||||||
|
//!
|
||||||
|
//! If the underlying function fails, this function causes execution to
|
||||||
|
//! terminate without returning.
|
||||||
|
void CheckedCloseFile(FileHandle file);
|
||||||
|
|
||||||
|
} // namespace crashpad
|
||||||
|
|
||||||
|
#endif // CRASHPAD_UTIL_FILE_FILE_IO_H_
|
@ -12,7 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "util/file/fd_io.h"
|
#include "util/file/file_io.h"
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
@ -66,70 +66,18 @@ ssize_t ReadOrWrite(int fd,
|
|||||||
|
|
||||||
namespace crashpad {
|
namespace crashpad {
|
||||||
|
|
||||||
ssize_t ReadFD(int fd, void* buffer, size_t size) {
|
ssize_t ReadFile(FileHandle file, void* buffer, size_t size) {
|
||||||
return ReadOrWrite<ReadTraits>(fd, buffer, size);
|
return ReadOrWrite<ReadTraits>(file, buffer, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t WriteFD(int fd, const void* buffer, size_t size) {
|
ssize_t WriteFile(FileHandle file, const void* buffer, size_t size) {
|
||||||
return ReadOrWrite<WriteTraits>(fd, buffer, size);
|
return ReadOrWrite<WriteTraits>(file, buffer, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoggingReadFD(int fd, void* buffer, size_t size) {
|
bool LoggingCloseFile(FileHandle file) {
|
||||||
ssize_t expect = base::checked_cast<ssize_t>(size);
|
int rv = IGNORE_EINTR(close(file));
|
||||||
ssize_t rv = ReadFD(fd, buffer, size);
|
|
||||||
if (rv < 0) {
|
|
||||||
PLOG(ERROR) << "read";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (rv != expect) {
|
|
||||||
LOG(ERROR) << "read: expected " << expect << ", observed " << rv;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LoggingWriteFD(int fd, const void* buffer, size_t size) {
|
|
||||||
ssize_t expect = base::checked_cast<ssize_t>(size);
|
|
||||||
ssize_t rv = WriteFD(fd, buffer, size);
|
|
||||||
if (rv < 0) {
|
|
||||||
PLOG(ERROR) << "write";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (rv != expect) {
|
|
||||||
LOG(ERROR) << "write: expected " << expect << ", observed " << rv;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CheckedReadFD(int fd, void* buffer, size_t size) {
|
|
||||||
CHECK(LoggingReadFD(fd, buffer, size));
|
|
||||||
}
|
|
||||||
|
|
||||||
void CheckedWriteFD(int fd, const void* buffer, size_t size) {
|
|
||||||
CHECK(LoggingWriteFD(fd, buffer, size));
|
|
||||||
}
|
|
||||||
|
|
||||||
void CheckedReadFDAtEOF(int fd) {
|
|
||||||
char c;
|
|
||||||
ssize_t rv = ReadFD(fd, &c, 1);
|
|
||||||
if (rv < 0) {
|
|
||||||
PCHECK(rv == 0) << "read";
|
|
||||||
} else {
|
|
||||||
CHECK_EQ(rv, 0) << "read";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LoggingCloseFD(int fd) {
|
|
||||||
int rv = IGNORE_EINTR(close(fd));
|
|
||||||
PLOG_IF(ERROR, rv != 0) << "close";
|
PLOG_IF(ERROR, rv != 0) << "close";
|
||||||
return rv == 0;
|
return rv == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckedCloseFD(int fd) {
|
|
||||||
CHECK(LoggingCloseFD(fd));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crashpad
|
} // namespace crashpad
|
81
util/file/file_io_win.cc
Normal file
81
util/file/file_io_win.cc
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// Copyright 2014 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 "util/file/file_io.h"
|
||||||
|
|
||||||
|
#include "base/logging.h"
|
||||||
|
#include "base/numerics/safe_conversions.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool IsSocketHandle(HANDLE file) {
|
||||||
|
if (GetFileType(file) == FILE_TYPE_PIPE) {
|
||||||
|
// FILE_TYPE_PIPE means that it's a socket, a named pipe, or an anonymous
|
||||||
|
// pipe. If we are unable to retrieve the pipe information, we know it's a
|
||||||
|
// socket.
|
||||||
|
return !GetNamedPipeInfo(file, NULL, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
|
||||||
|
// TODO(scottmg): Handle > DWORD sized writes if necessary.
|
||||||
|
|
||||||
|
ssize_t ReadFile(FileHandle file, void* buffer, size_t size) {
|
||||||
|
DCHECK(!IsSocketHandle(file));
|
||||||
|
DWORD size_dword = base::checked_cast<DWORD>(size);
|
||||||
|
DWORD total_read = 0;
|
||||||
|
char* buffer_c = reinterpret_cast<char*>(buffer);
|
||||||
|
while (size_dword > 0) {
|
||||||
|
DWORD bytes_read;
|
||||||
|
BOOL success = ::ReadFile(file, buffer_c, size_dword, &bytes_read, nullptr);
|
||||||
|
if (!success && GetLastError() != ERROR_MORE_DATA) {
|
||||||
|
return -1;
|
||||||
|
} else if (success && bytes_read == 0 &&
|
||||||
|
GetFileType(file) != FILE_TYPE_PIPE) {
|
||||||
|
// Zero bytes read for a file indicates reaching EOF. Zero bytes read from
|
||||||
|
// a pipe indicates only that there was a zero byte WriteFile issued on
|
||||||
|
// the other end, so continue reading.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer_c += bytes_read;
|
||||||
|
size_dword -= bytes_read;
|
||||||
|
total_read += bytes_read;
|
||||||
|
}
|
||||||
|
return total_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t WriteFile(FileHandle file, const void* buffer, size_t size) {
|
||||||
|
// TODO(scottmg): This might need to handle the limit for pipes across a
|
||||||
|
// network in the future.
|
||||||
|
DWORD size_dword = base::checked_cast<DWORD>(size);
|
||||||
|
DWORD bytes_written;
|
||||||
|
BOOL rv = ::WriteFile(file, buffer, size_dword, &bytes_written, nullptr);
|
||||||
|
if (!rv)
|
||||||
|
return -1;
|
||||||
|
CHECK_EQ(bytes_written, size_dword);
|
||||||
|
return bytes_written;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LoggingCloseFile(FileHandle file) {
|
||||||
|
BOOL rv = CloseHandle(file);
|
||||||
|
PLOG_IF(ERROR, !rv) << "CloseHandle";
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace crashpad
|
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
#include "base/posix/eintr_wrapper.h"
|
#include "base/posix/eintr_wrapper.h"
|
||||||
#include "util/file/fd_io.h"
|
#include "util/file/file_io.h"
|
||||||
|
|
||||||
namespace crashpad {
|
namespace crashpad {
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ bool FileWriter::Write(const void* data, size_t size) {
|
|||||||
DCHECK(fd_.is_valid());
|
DCHECK(fd_.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 = WriteFD(fd_.get(), data, size);
|
ssize_t written = WriteFile(fd_.get(), data, size);
|
||||||
if (written < 0) {
|
if (written < 0) {
|
||||||
PLOG(ERROR) << "write";
|
PLOG(ERROR) << "write";
|
||||||
return false;
|
return false;
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
#include "base/posix/eintr_wrapper.h"
|
#include "base/posix/eintr_wrapper.h"
|
||||||
#include "base/rand_util.h"
|
#include "base/rand_util.h"
|
||||||
#include "base/strings/stringprintf.h"
|
#include "base/strings/stringprintf.h"
|
||||||
#include "util/file/fd_io.h"
|
#include "util/file/file_io.h"
|
||||||
#include "util/mach/child_port.h"
|
#include "util/mach/child_port.h"
|
||||||
#include "util/mach/mach_extensions.h"
|
#include "util/mach/mach_extensions.h"
|
||||||
#include "util/mach/mach_message.h"
|
#include "util/mach/mach_message.h"
|
||||||
@ -85,7 +85,7 @@ mach_port_t ChildPortHandshake::RunServer() {
|
|||||||
// Initialize the token and share it with the client via the pipe.
|
// Initialize the token and share it with the client via the pipe.
|
||||||
token_ = base::RandUint64();
|
token_ = base::RandUint64();
|
||||||
int pipe_write = pipe_write_owner.get();
|
int pipe_write = pipe_write_owner.get();
|
||||||
if (!LoggingWriteFD(pipe_write, &token_, sizeof(token_))) {
|
if (!LoggingWriteFile(pipe_write, &token_, sizeof(token_))) {
|
||||||
LOG(WARNING) << "no client check-in";
|
LOG(WARNING) << "no client check-in";
|
||||||
return MACH_PORT_NULL;
|
return MACH_PORT_NULL;
|
||||||
}
|
}
|
||||||
@ -113,13 +113,14 @@ mach_port_t ChildPortHandshake::RunServer() {
|
|||||||
|
|
||||||
// Share the service name with the client via the pipe.
|
// Share the service name with the client via the pipe.
|
||||||
uint32_t service_name_length = service_name.size();
|
uint32_t service_name_length = service_name.size();
|
||||||
if (!LoggingWriteFD(
|
if (!LoggingWriteFile(
|
||||||
pipe_write, &service_name_length, sizeof(service_name_length))) {
|
pipe_write, &service_name_length, sizeof(service_name_length))) {
|
||||||
LOG(WARNING) << "no client check-in";
|
LOG(WARNING) << "no client check-in";
|
||||||
return MACH_PORT_NULL;
|
return MACH_PORT_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!LoggingWriteFD(pipe_write, service_name.c_str(), service_name_length)) {
|
if (!LoggingWriteFile(
|
||||||
|
pipe_write, service_name.c_str(), service_name_length)) {
|
||||||
LOG(WARNING) << "no client check-in";
|
LOG(WARNING) << "no client check-in";
|
||||||
return MACH_PORT_NULL;
|
return MACH_PORT_NULL;
|
||||||
}
|
}
|
||||||
@ -310,17 +311,17 @@ void ChildPortHandshake::RunClientInternal_ReadPipe(int pipe_read,
|
|||||||
child_port_token_t* token,
|
child_port_token_t* token,
|
||||||
std::string* service_name) {
|
std::string* service_name) {
|
||||||
// Read the token from the pipe.
|
// Read the token from the pipe.
|
||||||
CheckedReadFD(pipe_read, token, sizeof(*token));
|
CheckedReadFile(pipe_read, token, sizeof(*token));
|
||||||
|
|
||||||
// Read the service name from the pipe.
|
// Read the service name from the pipe.
|
||||||
uint32_t service_name_length;
|
uint32_t service_name_length;
|
||||||
CheckedReadFD(pipe_read, &service_name_length, sizeof(service_name_length));
|
CheckedReadFile(pipe_read, &service_name_length, sizeof(service_name_length));
|
||||||
DCHECK_LT(service_name_length,
|
DCHECK_LT(service_name_length,
|
||||||
implicit_cast<uint32_t>(BOOTSTRAP_MAX_NAME_LEN));
|
implicit_cast<uint32_t>(BOOTSTRAP_MAX_NAME_LEN));
|
||||||
|
|
||||||
if (service_name_length > 0) {
|
if (service_name_length > 0) {
|
||||||
service_name->resize(service_name_length);
|
service_name->resize(service_name_length);
|
||||||
CheckedReadFD(pipe_read, &(*service_name)[0], service_name_length);
|
CheckedReadFile(pipe_read, &(*service_name)[0], service_name_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
#include "base/mac/scoped_mach_port.h"
|
#include "base/mac/scoped_mach_port.h"
|
||||||
#include "base/strings/stringprintf.h"
|
#include "base/strings/stringprintf.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "util/file/fd_io.h"
|
#include "util/file/file_io.h"
|
||||||
#include "util/mach/exc_server_variants.h"
|
#include "util/mach/exc_server_variants.h"
|
||||||
#include "util/mach/mach_extensions.h"
|
#include "util/mach/mach_extensions.h"
|
||||||
#include "util/mach/mach_message.h"
|
#include "util/mach/mach_message.h"
|
||||||
@ -242,10 +242,10 @@ class TestExceptionPorts : public MachMultiprocess,
|
|||||||
|
|
||||||
// Tell the parent process that everything is set up.
|
// Tell the parent process that everything is set up.
|
||||||
char c = '\0';
|
char c = '\0';
|
||||||
CheckedWriteFD(test_exception_ports_->WritePipeFD(), &c, 1);
|
CheckedWriteFile(test_exception_ports_->WritePipeFD(), &c, 1);
|
||||||
|
|
||||||
// Wait for the parent process to say that its end is set up.
|
// Wait for the parent process to say that its end is set up.
|
||||||
CheckedReadFD(test_exception_ports_->ReadPipeFD(), &c, 1);
|
CheckedReadFile(test_exception_ports_->ReadPipeFD(), &c, 1);
|
||||||
EXPECT_EQ('\0', c);
|
EXPECT_EQ('\0', c);
|
||||||
|
|
||||||
// Regardless of where ExceptionPorts::SetExceptionPort() ran,
|
// Regardless of where ExceptionPorts::SetExceptionPort() ran,
|
||||||
@ -359,7 +359,7 @@ class TestExceptionPorts : public MachMultiprocess,
|
|||||||
// Wait for the child process to be ready. It needs to have all of its
|
// Wait for the child process to be ready. It needs to have all of its
|
||||||
// threads set up before proceeding if in kSetOutOfProcess mode.
|
// threads set up before proceeding if in kSetOutOfProcess mode.
|
||||||
char c;
|
char c;
|
||||||
CheckedReadFD(ReadPipeFD(), &c, 1);
|
CheckedReadFile(ReadPipeFD(), &c, 1);
|
||||||
EXPECT_EQ('\0', c);
|
EXPECT_EQ('\0', c);
|
||||||
|
|
||||||
mach_port_t local_port = LocalPort();
|
mach_port_t local_port = LocalPort();
|
||||||
@ -442,7 +442,7 @@ class TestExceptionPorts : public MachMultiprocess,
|
|||||||
// Let the child process know that everything in the parent process is set
|
// Let the child process know that everything in the parent process is set
|
||||||
// up.
|
// up.
|
||||||
c = '\0';
|
c = '\0';
|
||||||
CheckedWriteFD(WritePipeFD(), &c, 1);
|
CheckedWriteFile(WritePipeFD(), &c, 1);
|
||||||
|
|
||||||
if (who_crashes_ != kNobodyCrashes) {
|
if (who_crashes_ != kNobodyCrashes) {
|
||||||
UniversalMachExcServer universal_mach_exc_server(this);
|
UniversalMachExcServer universal_mach_exc_server(this);
|
||||||
@ -463,7 +463,7 @@ class TestExceptionPorts : public MachMultiprocess,
|
|||||||
// Wait for the child process to exit or terminate, as indicated by it
|
// Wait for the child process to exit or terminate, as indicated by it
|
||||||
// closing its pipe. This keeps LocalPort() alive in the child as
|
// closing its pipe. This keeps LocalPort() alive in the child as
|
||||||
// RemotePort(), for the child’s use in its TestGetExceptionPorts().
|
// RemotePort(), for the child’s use in its TestGetExceptionPorts().
|
||||||
CheckedReadFDAtEOF(ReadPipeFD());
|
CheckedReadFileAtEOF(ReadPipeFD());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MachMultiprocessChild() override {
|
void MachMultiprocessChild() override {
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
#include "base/basictypes.h"
|
#include "base/basictypes.h"
|
||||||
#include "base/mac/scoped_mach_port.h"
|
#include "base/mac/scoped_mach_port.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "util/file/fd_io.h"
|
#include "util/file/file_io.h"
|
||||||
#include "util/mach/mach_extensions.h"
|
#include "util/mach/mach_extensions.h"
|
||||||
#include "util/mach/mach_message.h"
|
#include "util/mach/mach_message.h"
|
||||||
#include "util/test/mac/mach_errors.h"
|
#include "util/test/mac/mach_errors.h"
|
||||||
@ -335,13 +335,13 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
|||||||
if (options_.child_wait_for_parent_pipe_early) {
|
if (options_.child_wait_for_parent_pipe_early) {
|
||||||
// Tell the child to begin sending messages.
|
// Tell the child to begin sending messages.
|
||||||
char c = '\0';
|
char c = '\0';
|
||||||
CheckedWriteFD(WritePipeFD(), &c, 1);
|
CheckedWriteFile(WritePipeFD(), &c, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options_.parent_wait_for_child_pipe) {
|
if (options_.parent_wait_for_child_pipe) {
|
||||||
// Wait until the child is done sending what it’s going to send.
|
// Wait until the child is done sending what it’s going to send.
|
||||||
char c;
|
char c;
|
||||||
CheckedReadFD(ReadPipeFD(), &c, 1);
|
CheckedReadFile(ReadPipeFD(), &c, 1);
|
||||||
EXPECT_EQ('\0', c);
|
EXPECT_EQ('\0', c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,7 +386,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
|||||||
if (options_.child_wait_for_parent_pipe_late) {
|
if (options_.child_wait_for_parent_pipe_late) {
|
||||||
// Let the child know it’s safe to exit.
|
// Let the child know it’s safe to exit.
|
||||||
char c = '\0';
|
char c = '\0';
|
||||||
CheckedWriteFD(WritePipeFD(), &c, 1);
|
CheckedWriteFile(WritePipeFD(), &c, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,7 +394,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
|||||||
if (options_.child_wait_for_parent_pipe_early) {
|
if (options_.child_wait_for_parent_pipe_early) {
|
||||||
// Wait until the parent is done setting things up on its end.
|
// Wait until the parent is done setting things up on its end.
|
||||||
char c;
|
char c;
|
||||||
CheckedReadFD(ReadPipeFD(), &c, 1);
|
CheckedReadFile(ReadPipeFD(), &c, 1);
|
||||||
EXPECT_EQ('\0', c);
|
EXPECT_EQ('\0', c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,7 +428,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
|||||||
|
|
||||||
if (options_.child_wait_for_parent_pipe_late) {
|
if (options_.child_wait_for_parent_pipe_late) {
|
||||||
char c;
|
char c;
|
||||||
CheckedReadFD(ReadPipeFD(), &c, 1);
|
CheckedReadFile(ReadPipeFD(), &c, 1);
|
||||||
ASSERT_EQ('\0', c);
|
ASSERT_EQ('\0', c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -550,7 +550,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
|||||||
// running MachMessageServer() once it’s received.
|
// running MachMessageServer() once it’s received.
|
||||||
void ChildNotifyParentViaPipe() {
|
void ChildNotifyParentViaPipe() {
|
||||||
char c = '\0';
|
char c = '\0';
|
||||||
CheckedWriteFD(WritePipeFD(), &c, 1);
|
CheckedWriteFile(WritePipeFD(), &c, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// In the child process, sends a request message to the server and then
|
// In the child process, sends a request message to the server and then
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
#include <mach/mach.h>
|
#include <mach/mach.h>
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "util/file/fd_io.h"
|
|
||||||
#include "util/test/mac/mach_errors.h"
|
#include "util/test/mac/mach_errors.h"
|
||||||
#include "util/test/mac/mach_multiprocess.h"
|
#include "util/test/mac/mach_multiprocess.h"
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
#include "base/posix/eintr_wrapper.h"
|
#include "base/posix/eintr_wrapper.h"
|
||||||
#include "base/stl_util.h"
|
#include "base/stl_util.h"
|
||||||
#include "util/file/fd_io.h"
|
#include "util/file/file_io.h"
|
||||||
|
|
||||||
namespace crashpad {
|
namespace crashpad {
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ FileHTTPBodyStream::FileHTTPBodyStream(const base::FilePath& path)
|
|||||||
|
|
||||||
FileHTTPBodyStream::~FileHTTPBodyStream() {
|
FileHTTPBodyStream::~FileHTTPBodyStream() {
|
||||||
if (fd_ >= 0) {
|
if (fd_ >= 0) {
|
||||||
LoggingCloseFD(fd_);
|
LoggingCloseFile(fd_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,9 +77,9 @@ ssize_t FileHTTPBodyStream::GetBytesBuffer(uint8_t* buffer, size_t max_len) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t rv = ReadFD(fd_, buffer, max_len);
|
ssize_t rv = ReadFile(fd_, buffer, max_len);
|
||||||
if (rv == 0) {
|
if (rv == 0) {
|
||||||
LoggingCloseFD(fd_);
|
LoggingCloseFile(fd_);
|
||||||
fd_ = kClosedAtEOF;
|
fd_ = kClosedAtEOF;
|
||||||
} else if (rv < 0) {
|
} else if (rv < 0) {
|
||||||
PLOG(ERROR) << "read";
|
PLOG(ERROR) << "read";
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
#include "base/strings/stringprintf.h"
|
#include "base/strings/stringprintf.h"
|
||||||
#include "build/build_config.h"
|
#include "build/build_config.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "util/file/fd_io.h"
|
#include "util/file/file_io.h"
|
||||||
#include "util/net/http_body.h"
|
#include "util/net/http_body.h"
|
||||||
#include "util/net/http_headers.h"
|
#include "util/net/http_headers.h"
|
||||||
#include "util/net/http_multipart_builder.h"
|
#include "util/net/http_multipart_builder.h"
|
||||||
@ -63,12 +63,12 @@ class HTTPTransportTestFixture : public MultiprocessExec {
|
|||||||
// The child will write the HTTP server port number as a packed unsigned
|
// The child will write the HTTP server port number as a packed unsigned
|
||||||
// short to stdout.
|
// short to stdout.
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
ASSERT_TRUE(LoggingReadFD(ReadPipeFD(), &port, sizeof(port)));
|
ASSERT_TRUE(LoggingReadFile(ReadPipeFD(), &port, sizeof(port)));
|
||||||
|
|
||||||
// Then the parent will tell the web server what response code to send
|
// Then the parent will tell the web server what response code to send
|
||||||
// for the HTTP request.
|
// for the HTTP request.
|
||||||
ASSERT_TRUE(
|
ASSERT_TRUE(LoggingWriteFile(
|
||||||
LoggingWriteFD(WritePipeFD(), &response_code_, sizeof(response_code_)));
|
WritePipeFD(), &response_code_, sizeof(response_code_)));
|
||||||
|
|
||||||
// Now execute the HTTP request.
|
// Now execute the HTTP request.
|
||||||
scoped_ptr<HTTPTransport> transport(HTTPTransport::Create());
|
scoped_ptr<HTTPTransport> transport(HTTPTransport::Create());
|
||||||
@ -85,7 +85,7 @@ class HTTPTransportTestFixture : public MultiprocessExec {
|
|||||||
std::string request;
|
std::string request;
|
||||||
char buf[32];
|
char buf[32];
|
||||||
ssize_t bytes_read;
|
ssize_t bytes_read;
|
||||||
while ((bytes_read = ReadFD(ReadPipeFD(), buf, sizeof(buf))) != 0) {
|
while ((bytes_read = ReadFile(ReadPipeFD(), buf, sizeof(buf))) != 0) {
|
||||||
ASSERT_GE(bytes_read, 0);
|
ASSERT_GE(bytes_read, 0);
|
||||||
request.append(buf, bytes_read);
|
request.append(buf, bytes_read);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
#include "base/memory/scoped_ptr.h"
|
#include "base/memory/scoped_ptr.h"
|
||||||
#include "base/rand_util.h"
|
#include "base/rand_util.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "util/file/fd_io.h"
|
#include "util/file/file_io.h"
|
||||||
#include "util/mach/mach_extensions.h"
|
#include "util/mach/mach_extensions.h"
|
||||||
#include "util/misc/scoped_forbid_return.h"
|
#include "util/misc/scoped_forbid_return.h"
|
||||||
#include "util/test/errors.h"
|
#include "util/test/errors.h"
|
||||||
@ -262,7 +262,7 @@ void MachMultiprocess::MultiprocessChild() {
|
|||||||
// Wait for the parent process to close its end of the pipe. The child process
|
// Wait for the parent process to close its end of the pipe. The child process
|
||||||
// needs to remain alive until then because the parent process will attempt to
|
// needs to remain alive until then because the parent process will attempt to
|
||||||
// verify it using the task port it has access to via ChildTask().
|
// verify it using the task port it has access to via ChildTask().
|
||||||
CheckedReadFDAtEOF(ReadPipeFD());
|
CheckedReadFileAtEOF(ReadPipeFD());
|
||||||
|
|
||||||
if (testing::Test::HasFailure()) {
|
if (testing::Test::HasFailure()) {
|
||||||
// Trigger the ScopedForbidReturn destructor.
|
// Trigger the ScopedForbidReturn destructor.
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#include "base/basictypes.h"
|
#include "base/basictypes.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "util/file/fd_io.h"
|
#include "util/file/file_io.h"
|
||||||
#include "util/test/executable_path.h"
|
#include "util/test/executable_path.h"
|
||||||
|
|
||||||
namespace crashpad {
|
namespace crashpad {
|
||||||
@ -37,9 +37,9 @@ class TestMultiprocessExec final : public MultiprocessExec {
|
|||||||
// gracefully with a gtest assertion if the child does not execute properly.
|
// gracefully with a gtest assertion if the child does not execute properly.
|
||||||
|
|
||||||
char c = 'z';
|
char c = 'z';
|
||||||
ASSERT_TRUE(LoggingWriteFD(WritePipeFD(), &c, 1));
|
ASSERT_TRUE(LoggingWriteFile(WritePipeFD(), &c, 1));
|
||||||
|
|
||||||
ASSERT_TRUE(LoggingReadFD(ReadPipeFD(), &c, 1));
|
ASSERT_TRUE(LoggingReadFile(ReadPipeFD(), &c, 1));
|
||||||
EXPECT_EQ('Z', c);
|
EXPECT_EQ('Z', c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
#include "base/basictypes.h"
|
#include "base/basictypes.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "util/file/fd_io.h"
|
#include "util/file/file_io.h"
|
||||||
|
|
||||||
namespace crashpad {
|
namespace crashpad {
|
||||||
namespace test {
|
namespace test {
|
||||||
@ -38,31 +38,31 @@ class TestMultiprocess final : public Multiprocess {
|
|||||||
void MultiprocessParent() override {
|
void MultiprocessParent() override {
|
||||||
int read_fd = ReadPipeFD();
|
int read_fd = ReadPipeFD();
|
||||||
char c;
|
char c;
|
||||||
CheckedReadFD(read_fd, &c, 1);
|
CheckedReadFile(read_fd, &c, 1);
|
||||||
EXPECT_EQ('M', c);
|
EXPECT_EQ('M', c);
|
||||||
|
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
CheckedReadFD(read_fd, &pid, sizeof(pid));
|
CheckedReadFile(read_fd, &pid, sizeof(pid));
|
||||||
EXPECT_EQ(pid, ChildPID());
|
EXPECT_EQ(pid, ChildPID());
|
||||||
|
|
||||||
c = 'm';
|
c = 'm';
|
||||||
CheckedWriteFD(WritePipeFD(), &c, 1);
|
CheckedWriteFile(WritePipeFD(), &c, 1);
|
||||||
|
|
||||||
// The child will close its end of the pipe and exit. Make sure that the
|
// The child will close its end of the pipe and exit. Make sure that the
|
||||||
// parent sees EOF.
|
// parent sees EOF.
|
||||||
CheckedReadFDAtEOF(read_fd);
|
CheckedReadFileAtEOF(read_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MultiprocessChild() override {
|
void MultiprocessChild() override {
|
||||||
int write_fd = WritePipeFD();
|
int write_fd = WritePipeFD();
|
||||||
|
|
||||||
char c = 'M';
|
char c = 'M';
|
||||||
CheckedWriteFD(write_fd, &c, 1);
|
CheckedWriteFile(write_fd, &c, 1);
|
||||||
|
|
||||||
pid_t pid = getpid();
|
pid_t pid = getpid();
|
||||||
CheckedWriteFD(write_fd, &pid, sizeof(pid));
|
CheckedWriteFile(write_fd, &pid, sizeof(pid));
|
||||||
|
|
||||||
CheckedReadFD(ReadPipeFD(), &c, 1);
|
CheckedReadFile(ReadPipeFD(), &c, 1);
|
||||||
EXPECT_EQ('m', c);
|
EXPECT_EQ('m', c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,18 +178,18 @@ class TestMultiprocessClosePipe final : public Multiprocess {
|
|||||||
// the read pipe in this process to show end-of-file.
|
// the read pipe in this process to show end-of-file.
|
||||||
void VerifyPartner() {
|
void VerifyPartner() {
|
||||||
if (what_closes_ == kWriteCloses) {
|
if (what_closes_ == kWriteCloses) {
|
||||||
CheckedReadFDAtEOF(ReadPipeFD());
|
CheckedReadFileAtEOF(ReadPipeFD());
|
||||||
} else if (what_closes_ == kReadAndWriteClose) {
|
} else if (what_closes_ == kReadAndWriteClose) {
|
||||||
CheckedReadFDAtEOF(ReadPipeFD());
|
CheckedReadFileAtEOF(ReadPipeFD());
|
||||||
char c = '\0';
|
char c = '\0';
|
||||||
|
|
||||||
// This will raise SIGPIPE. If fatal (the normal case), that will cause
|
// This will raise SIGPIPE. If fatal (the normal case), that will cause
|
||||||
// process termination. If SIGPIPE is being handled somewhere, the write
|
// process termination. If SIGPIPE is being handled somewhere, the write
|
||||||
// will still fail and set errno to EPIPE, and CheckedWriteFD() will abort
|
// will still fail and set errno to EPIPE, and CheckedWriteFile() will
|
||||||
// execution. Regardless of how SIGPIPE is handled, the process will be
|
// abort execution. Regardless of how SIGPIPE is handled, the process will
|
||||||
// terminated. Because the actual termination mechanism is not known, no
|
// be terminated. Because the actual termination mechanism is not known,
|
||||||
// regex can be specified.
|
// no regex can be specified.
|
||||||
EXPECT_DEATH(CheckedWriteFD(WritePipeFD(), &c, 1), "");
|
EXPECT_DEATH(CheckedWriteFile(WritePipeFD(), &c, 1), "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,8 +26,10 @@
|
|||||||
'<(INTERMEDIATE_DIR)',
|
'<(INTERMEDIATE_DIR)',
|
||||||
],
|
],
|
||||||
'sources': [
|
'sources': [
|
||||||
'file/fd_io.cc',
|
'file/file_io.cc',
|
||||||
'file/fd_io.h',
|
'file/file_io.h',
|
||||||
|
'file/file_io_posix.cc',
|
||||||
|
'file/file_io_win.cc',
|
||||||
'file/file_writer.cc',
|
'file/file_writer.cc',
|
||||||
'file/file_writer.h',
|
'file/file_writer.h',
|
||||||
'file/string_file_writer.cc',
|
'file/string_file_writer.cc',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user