// Copyright 2014 The Crashpad Authors // // 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/check_op.h" #include "base/logging.h" #include "base/numerics/safe_conversions.h" namespace crashpad { namespace { class FileIOReadExactly final : public internal::ReadExactlyInternal { public: explicit FileIOReadExactly(FileHandle file) : ReadExactlyInternal(), file_(file) {} FileIOReadExactly(const FileIOReadExactly&) = delete; FileIOReadExactly& operator=(const FileIOReadExactly&) = delete; ~FileIOReadExactly() {} private: // ReadExactlyInternal: FileOperationResult Read(void* buffer, size_t size, bool can_log) override { FileOperationResult rv = ReadFile(file_, buffer, size); if (rv < 0) { PLOG_IF(ERROR, can_log) << internal::kNativeReadFunctionName; return -1; } return rv; } FileHandle file_; }; class FileIOWriteAll final : public internal::WriteAllInternal { public: explicit FileIOWriteAll(FileHandle file) : WriteAllInternal(), file_(file) {} FileIOWriteAll(const FileIOWriteAll&) = delete; FileIOWriteAll& operator=(const FileIOWriteAll&) = delete; ~FileIOWriteAll() {} private: // WriteAllInternal: FileOperationResult Write(const void* buffer, size_t size) override { return internal::NativeWriteFile(file_, buffer, size); } FileHandle file_; }; } // namespace namespace internal { bool ReadExactlyInternal::ReadExactly(void* buffer, size_t size, bool can_log) { uintptr_t buffer_int = reinterpret_cast(buffer); size_t total_bytes = 0; size_t remaining = size; while (remaining > 0) { FileOperationResult bytes_read = Read(reinterpret_cast(buffer_int), remaining, can_log); if (bytes_read < 0) { return false; } DCHECK_LE(static_cast(bytes_read), remaining); if (bytes_read == 0) { break; } buffer_int += bytes_read; remaining -= bytes_read; total_bytes += bytes_read; } if (total_bytes != size) { LOG_IF(ERROR, can_log) << "ReadExactly: expected " << size << ", observed " << total_bytes; return false; } return true; } bool WriteAllInternal::WriteAll(const void* buffer, size_t size) { uintptr_t buffer_int = reinterpret_cast(buffer); while (size > 0) { FileOperationResult bytes_written = Write(reinterpret_cast(buffer_int), size); if (bytes_written < 0) { return false; } DCHECK_NE(bytes_written, 0); buffer_int += bytes_written; size -= bytes_written; } return true; } } // namespace internal bool ReadFileExactly(FileHandle file, void* buffer, size_t size) { FileIOReadExactly read_exactly(file); return read_exactly.ReadExactly(buffer, size, false); } bool LoggingReadFileExactly(FileHandle file, void* buffer, size_t size) { FileIOReadExactly read_exactly(file); return read_exactly.ReadExactly(buffer, size, true); } bool WriteFile(FileHandle file, const void* buffer, size_t size) { FileIOWriteAll write_all(file); return write_all.WriteAll(buffer, size); } bool LoggingWriteFile(FileHandle file, const void* buffer, size_t size) { if (!WriteFile(file, buffer, size)) { PLOG(ERROR) << internal::kNativeWriteFunctionName; return false; } return true; } void CheckedReadFileExactly(FileHandle file, void* buffer, size_t size) { CHECK(LoggingReadFileExactly(file, buffer, size)); } void CheckedWriteFile(FileHandle file, const void* buffer, size_t size) { CHECK(LoggingWriteFile(file, buffer, size)); } void CheckedReadFileAtEOF(FileHandle file) { char c; FileOperationResult rv = ReadFile(file, &c, 1); if (rv < 0) { PCHECK(rv == 0) << internal::kNativeReadFunctionName; } else { CHECK_EQ(rv, 0) << internal::kNativeReadFunctionName; } } bool LoggingReadToEOF(FileHandle file, std::string* contents) { char buffer[4096]; FileOperationResult rv; std::string local_contents; while ((rv = ReadFile(file, buffer, sizeof(buffer))) > 0) { DCHECK_LE(static_cast(rv), sizeof(buffer)); local_contents.append(buffer, rv); } if (rv < 0) { PLOG(ERROR) << internal::kNativeReadFunctionName; return false; } contents->swap(local_contents); return true; } bool LoggingReadEntireFile(const base::FilePath& path, std::string* contents) { ScopedFileHandle handle(LoggingOpenFileForRead(path)); if (!handle.is_valid()) { return false; } return LoggingReadToEOF(handle.get(), contents); } void CheckedCloseFile(FileHandle file) { CHECK(LoggingCloseFile(file)); } } // namespace crashpad