| // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "update_engine/split_file_writer.h" |
| #include <algorithm> |
| |
| using std::min; |
| |
| namespace chromeos_update_engine { |
| |
| int SplitFileWriter::Open(const char* path, int flags, mode_t mode) { |
| int first_result = first_file_writer_->Open(first_path_, |
| first_flags_, |
| first_mode_); |
| if (first_result < 0) { |
| LOG(ERROR) << "Error opening first file " << first_path_; |
| return first_result; |
| } |
| int second_result = second_file_writer_->Open(path, flags, mode); |
| if (second_result < 0) { |
| LOG(ERROR) << "Error opening second file " << path; |
| first_file_writer_->Close(); |
| return second_result; |
| } |
| return second_result; |
| } |
| |
| namespace { |
| ssize_t PerformWrite(FileWriter* writer, const void* bytes, size_t count) { |
| int rc = writer->Write(bytes, count); |
| if (rc < 0) { |
| LOG(ERROR) << "Write failed to file."; |
| return rc; |
| } |
| if (rc != static_cast<int>(count)) { |
| LOG(ERROR) << "Not all bytes successfully written to file."; |
| return -EIO; |
| } |
| return rc; |
| } |
| } |
| |
| ssize_t SplitFileWriter::Write(const void* bytes, size_t count) { |
| const size_t original_count = count; |
| |
| // This first block is trying to read the first sizeof(uint64_t) |
| // bytes, which are the number of bytes that should be written |
| // to the first FileWriter. |
| if (bytes_received_ < static_cast<off_t>(sizeof(uint64_t))) { |
| // Write more to the initial buffer |
| size_t bytes_to_copy = min(static_cast<off_t>(count), |
| static_cast<off_t>(sizeof(first_length_buf_)) - |
| bytes_received_); |
| memcpy(&first_length_buf_[bytes_received_], bytes, bytes_to_copy); |
| bytes_received_ += bytes_to_copy; |
| count -= bytes_to_copy; |
| bytes = static_cast<const void*>( |
| static_cast<const char*>(bytes) + bytes_to_copy); |
| |
| // See if we have all we need |
| if (bytes_received_ == sizeof(first_length_buf_)) { |
| // Parse first number |
| uint64_t big_endian_first_length; |
| memcpy(&big_endian_first_length, first_length_buf_, |
| sizeof(big_endian_first_length)); |
| first_length_ = be64toh(big_endian_first_length); |
| } |
| if (count == 0) |
| return original_count; |
| } |
| CHECK_GE(bytes_received_, static_cast<off_t>(sizeof(uint64_t))); |
| |
| // This block of code is writing to the first FileWriter. |
| if (bytes_received_ - static_cast<off_t>(sizeof(uint64_t)) < first_length_) { |
| // Write to first FileWriter |
| size_t bytes_to_write = min( |
| first_length_ - |
| (bytes_received_ - static_cast<off_t>(sizeof(uint64_t))), |
| static_cast<off_t>(count)); |
| |
| int rc = PerformWrite(first_file_writer_, bytes, bytes_to_write); |
| if (rc != static_cast<int>(bytes_to_write)) |
| return rc; |
| |
| bytes_received_ += bytes_to_write; |
| count -= bytes_to_write; |
| bytes = static_cast<const void*>( |
| static_cast<const char*>(bytes) + bytes_to_write); |
| if (count == 0) |
| return original_count; |
| } |
| |
| CHECK_GE(static_cast<off_t>(bytes_received_), |
| first_length_ + static_cast<off_t>(sizeof(uint64_t))); |
| // Write to second FileWriter |
| int rc = PerformWrite(second_file_writer_, bytes, count); |
| if (rc != static_cast<int>(count)) |
| return rc; |
| return original_count; |
| } |
| |
| int SplitFileWriter::Close() { |
| int first_result = first_file_writer_->Close(); |
| if (first_result < 0) |
| LOG(ERROR) << "Error Close()ing first file."; |
| int second_result = second_file_writer_->Close(); |
| if (second_result < 0) |
| LOG(ERROR) << "Error Close()ing second file."; |
| // Return error if either had returned error. |
| return second_result < 0 ? second_result : first_result; |
| } |
| |
| } // namespace chromeos_update_engine |