Chromium Code Reviews| Index: minidump/minidump_file_writer.cc |
| diff --git a/minidump/minidump_file_writer.cc b/minidump/minidump_file_writer.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..54490ba948f84cdaded7738d4e528ae5652312a6 |
| --- /dev/null |
| +++ b/minidump/minidump_file_writer.cc |
| @@ -0,0 +1,163 @@ |
| +// 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 "minidump/minidump_file_writer.h" |
| + |
| +#include "base/logging.h" |
| +#include "minidump/minidump_writer_util.h" |
| +#include "util/numeric/safe_assignment.h" |
| + |
| +namespace crashpad { |
| + |
| +MinidumpFileWriter::MinidumpFileWriter() |
| + : MinidumpWritable(), header_(), streams_(), stream_types_() { |
| + // Don’t set the signature field right away. Leave it set to 0, so that a |
| + // partially-written minidump file isn’t confused for a complete and valid |
| + // one. The header will be rewritten in WriteToFile(). |
| + header_.Signature = 0; |
| + |
| + header_.Version = MINIDUMP_VERSION; |
| + header_.CheckSum = 0; |
| + header_.Flags = MiniDumpNormal; |
| +} |
| + |
| +MinidumpFileWriter::~MinidumpFileWriter() { |
| +} |
| + |
| +void MinidumpFileWriter::SetTimestamp(time_t timestamp) { |
| + DCHECK_EQ(state(), kStateMutable); |
| + |
| + internal::MinidumpWriterUtil::AssignTimeT(&header_.TimeDateStamp, timestamp); |
| +} |
| + |
| +void MinidumpFileWriter::AddStream(internal::MinidumpStreamWriter* stream) { |
| + DCHECK_EQ(state(), kStateMutable); |
| + |
| + MinidumpStreamType stream_type = stream->StreamType(); |
| + |
| + auto rv = stream_types_.insert(stream_type); |
| + CHECK(rv.second) << "stream_type " << stream_type << " already present"; |
| + |
| + streams_.push_back(stream); |
| + |
| + DCHECK_EQ(streams_.size(), stream_types_.size()); |
| +} |
| + |
| +bool MinidumpFileWriter::WriteEverything(FileWriterInterface* file_writer) { |
| + DCHECK_EQ(state(), kStateMutable); |
| + |
| + off_t start_offset = file_writer->Seek(0, SEEK_CUR); |
| + if (start_offset < 0) { |
| + return false; |
| + } |
| + |
| + if (!MinidumpWritable::WriteEverything(file_writer)) { |
| + return false; |
| + } |
| + |
| + off_t end_offset = file_writer->Seek(0, SEEK_CUR); |
| + if (end_offset < 0) { |
| + return false; |
| + } |
| + |
| + // Now that the entire minidump file has been completely written, go back to |
| + // the beginning and rewrite the header with the correct signature to identify |
| + // it as a valid minidump file. |
| + header_.Signature = MINIDUMP_SIGNATURE; |
| + |
| + if (file_writer->Seek(start_offset, SEEK_SET) != 0) { |
| + return false; |
| + } |
| + |
| + if (!file_writer->Write(&header_, sizeof(header_))) { |
| + return false; |
| + } |
| + |
| + // Seek back to the end of the file, in case some non-minidump content will be |
| + // written to the file after the minidump content. |
| + return file_writer->Seek(end_offset, SEEK_SET); |
| +} |
| + |
| +bool MinidumpFileWriter::Freeze() { |
| + DCHECK_EQ(state(), kStateMutable); |
| + |
| + if (!MinidumpWritable::Freeze()) { |
| + return false; |
| + } |
| + |
| + size_t stream_count = streams_.size(); |
| + CHECK_EQ(stream_count, stream_types_.size()); |
| + |
| + if (!AssignIfInRange(&header_.NumberOfStreams, stream_count)) { |
| + LOG(ERROR) << "stream_count " << stream_count << " out of range"; |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +size_t MinidumpFileWriter::SizeOfObject() { |
| + DCHECK_GE(state(), kStateFrozen); |
| + DCHECK_EQ(streams_.size(), stream_types_.size()); |
| + |
| + return sizeof(header_) + streams_.size() * sizeof(MINIDUMP_DIRECTORY); |
| +} |
| + |
| +std::vector<internal::MinidumpWritable*> MinidumpFileWriter::Children() { |
| + DCHECK_GE(state(), kStateFrozen); |
| + DCHECK_EQ(streams_.size(), stream_types_.size()); |
| + |
| + std::vector<MinidumpWritable*> children; |
|
Robert Sesek
2014/08/03 15:19:59
You're building a vector<MinidumpWritable*> yet th
Mark Mentovai
2014/08/03 20:14:10
rsesek wrote:
Robert Sesek
2014/08/03 21:20:55
Ack. I misread streams_ as MinidumpWritable* inste
|
| + for (internal::MinidumpStreamWriter* stream : streams_) { |
| + children.push_back(stream); |
| + } |
| + |
| + return children; |
| +} |
| + |
| +bool MinidumpFileWriter::WillWriteAtOffsetImpl(off_t offset) { |
| + DCHECK_EQ(state(), kStateFrozen); |
| + DCHECK_EQ(offset, 0); |
| + DCHECK_EQ(streams_.size(), stream_types_.size()); |
| + |
| + auto directory_offset = streams_.empty() ? 0 : offset + sizeof(header_); |
| + if (!AssignIfInRange(&header_.StreamDirectoryRva, directory_offset)) { |
| + LOG(ERROR) << "offset " << directory_offset << " out of range"; |
| + return false; |
| + } |
| + |
| + return MinidumpWritable::WillWriteAtOffsetImpl(offset); |
| +} |
| + |
| +bool MinidumpFileWriter::WriteObject(FileWriterInterface* file_writer) { |
| + DCHECK_EQ(state(), kStateWritable); |
| + DCHECK_EQ(streams_.size(), stream_types_.size()); |
| + |
| + WritableIoVec iov; |
| + iov.iov_base = &header_; |
| + iov.iov_len = sizeof(header_); |
| + std::vector<WritableIoVec> iovecs(1, iov); |
| + |
| + if (!streams_.empty()) { |
| + iov.iov_len = sizeof(MINIDUMP_DIRECTORY); |
|
Robert Sesek
2014/08/03 15:19:59
If you moved this into the loop body, you could re
|
| + for (internal::MinidumpStreamWriter* stream : streams_) { |
| + iov.iov_base = stream->DirectoryListEntry(); |
| + iovecs.push_back(iov); |
| + } |
| + } |
| + |
| + return file_writer->WriteIoVec(&iovecs); |
| +} |
| + |
| +} // namespace crashpad |