blob: 690d4e3f02024771b51e7809e1d9989b21c99898 [file] [log] [blame]
Andrew de los Reyes0cca4212010-04-29 14:00:58 -07001// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "update_engine/split_file_writer.h"
6#include <algorithm>
7
8using std::min;
9
10namespace chromeos_update_engine {
11
12int SplitFileWriter::Open(const char* path, int flags, mode_t mode) {
13 int first_result = first_file_writer_->Open(first_path_,
14 first_flags_,
15 first_mode_);
16 if (first_result < 0) {
17 LOG(ERROR) << "Error opening first file " << first_path_;
18 return first_result;
19 }
20 int second_result = second_file_writer_->Open(path, flags, mode);
21 if (second_result < 0) {
22 LOG(ERROR) << "Error opening second file " << path;
23 first_file_writer_->Close();
24 return second_result;
25 }
26 return second_result;
27}
28
29namespace {
30ssize_t PerformWrite(FileWriter* writer, const void* bytes, size_t count) {
31 int rc = writer->Write(bytes, count);
32 if (rc < 0) {
33 LOG(ERROR) << "Write failed to file.";
34 return rc;
35 }
36 if (rc != static_cast<int>(count)) {
37 LOG(ERROR) << "Not all bytes successfully written to file.";
38 return -EIO;
39 }
40 return rc;
41}
42}
43
44ssize_t SplitFileWriter::Write(const void* bytes, size_t count) {
45 const size_t original_count = count;
46
47 // This first block is trying to read the first sizeof(uint64_t)
48 // bytes, which are the number of bytes that should be written
49 // to the first FileWriter.
50 if (bytes_received_ < static_cast<off_t>(sizeof(uint64_t))) {
51 // Write more to the initial buffer
Andrew de los Reyesf9185172010-05-03 11:07:05 -070052 size_t bytes_to_copy = min(static_cast<off_t>(count),
53 static_cast<off_t>(sizeof(first_length_buf_)) -
54 bytes_received_);
Andrew de los Reyes0cca4212010-04-29 14:00:58 -070055 memcpy(&first_length_buf_[bytes_received_], bytes, bytes_to_copy);
56 bytes_received_ += bytes_to_copy;
57 count -= bytes_to_copy;
58 bytes = static_cast<const void*>(
59 static_cast<const char*>(bytes) + bytes_to_copy);
60
61 // See if we have all we need
62 if (bytes_received_ == sizeof(first_length_buf_)) {
63 // Parse first number
64 uint64_t big_endian_first_length;
65 memcpy(&big_endian_first_length, first_length_buf_,
66 sizeof(big_endian_first_length));
67 first_length_ = be64toh(big_endian_first_length);
68 }
69 if (count == 0)
70 return original_count;
71 }
72 CHECK_GE(bytes_received_, static_cast<off_t>(sizeof(uint64_t)));
73
74 // This block of code is writing to the first FileWriter.
75 if (bytes_received_ - static_cast<off_t>(sizeof(uint64_t)) < first_length_) {
76 // Write to first FileWriter
77 size_t bytes_to_write = min(
78 first_length_ -
79 (bytes_received_ - static_cast<off_t>(sizeof(uint64_t))),
80 static_cast<off_t>(count));
81
82 int rc = PerformWrite(first_file_writer_, bytes, bytes_to_write);
83 if (rc != static_cast<int>(bytes_to_write))
84 return rc;
85
86 bytes_received_ += bytes_to_write;
87 count -= bytes_to_write;
88 bytes = static_cast<const void*>(
89 static_cast<const char*>(bytes) + bytes_to_write);
90 if (count == 0)
91 return original_count;
92 }
93
94 CHECK_GE(static_cast<off_t>(bytes_received_),
95 first_length_ + static_cast<off_t>(sizeof(uint64_t)));
96 // Write to second FileWriter
97 int rc = PerformWrite(second_file_writer_, bytes, count);
98 if (rc != static_cast<int>(count))
99 return rc;
100 return original_count;
101}
102
103int SplitFileWriter::Close() {
104 int first_result = first_file_writer_->Close();
105 if (first_result < 0)
106 LOG(ERROR) << "Error Close()ing first file.";
107 int second_result = second_file_writer_->Close();
108 if (second_result < 0)
109 LOG(ERROR) << "Error Close()ing second file.";
110 // Return error if either had returned error.
111 return second_result < 0 ? second_result : first_result;
112}
113
114} // namespace chromeos_update_engine