1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
//
// Copyright (C) 2009 The Android Open Source Project
//
// 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 UPDATE_ENGINE_PAYLOAD_CONSUMER_EXTENT_WRITER_H_
#define UPDATE_ENGINE_PAYLOAD_CONSUMER_EXTENT_WRITER_H_
#include <memory>
#include <utility>
#include <base/logging.h>
#include <brillo/secure_blob.h>
#include "update_engine/common/utils.h"
#include "update_engine/payload_consumer/file_descriptor.h"
#include "update_engine/update_metadata.pb.h"
// ExtentWriter is an abstract class which synchronously writes to a given
// file descriptor at the extents given.
namespace chromeos_update_engine {
class ExtentWriter {
public:
ExtentWriter() = default;
virtual ~ExtentWriter() {
LOG_IF(ERROR, !end_called_) << "End() not called on ExtentWriter.";
}
// Returns true on success.
virtual bool Init(FileDescriptorPtr fd,
const google::protobuf::RepeatedPtrField<Extent>& extents,
uint32_t block_size) = 0;
// Returns true on success.
virtual bool Write(const void* bytes, size_t count) = 0;
// Should be called when all writing is complete. Returns true on success.
// The fd is not closed. Caller is responsible for closing it.
bool End() {
end_called_ = true;
return EndImpl();
}
virtual bool EndImpl() = 0;
private:
bool end_called_{false};
};
// DirectExtentWriter is probably the simplest ExtentWriter implementation.
// It writes the data directly into the extents.
class DirectExtentWriter : public ExtentWriter {
public:
DirectExtentWriter() = default;
~DirectExtentWriter() override = default;
bool Init(FileDescriptorPtr fd,
const google::protobuf::RepeatedPtrField<Extent>& extents,
uint32_t block_size) override {
fd_ = fd;
block_size_ = block_size;
extents_ = extents;
cur_extent_ = extents_.begin();
return true;
}
bool Write(const void* bytes, size_t count) override;
bool EndImpl() override { return true; }
private:
FileDescriptorPtr fd_{nullptr};
size_t block_size_{0};
// Bytes written into |cur_extent_| thus far.
uint64_t extent_bytes_written_{0};
google::protobuf::RepeatedPtrField<Extent> extents_;
// The next call to write should correspond to |cur_extents_|.
google::protobuf::RepeatedPtrField<Extent>::iterator cur_extent_;
};
// Takes an underlying ExtentWriter to which all operations are delegated.
// When End() is called, ZeroPadExtentWriter ensures that the total number
// of bytes written is a multiple of block_size_. If not, it writes zeros
// to pad as needed.
class ZeroPadExtentWriter : public ExtentWriter {
public:
explicit ZeroPadExtentWriter(
std::unique_ptr<ExtentWriter> underlying_extent_writer)
: underlying_extent_writer_(std::move(underlying_extent_writer)) {}
~ZeroPadExtentWriter() override = default;
bool Init(FileDescriptorPtr fd,
const google::protobuf::RepeatedPtrField<Extent>& extents,
uint32_t block_size) override {
block_size_ = block_size;
return underlying_extent_writer_->Init(fd, extents, block_size);
}
bool Write(const void* bytes, size_t count) override {
if (underlying_extent_writer_->Write(bytes, count)) {
bytes_written_mod_block_size_ += count;
bytes_written_mod_block_size_ %= block_size_;
return true;
}
return false;
}
bool EndImpl() override {
if (bytes_written_mod_block_size_) {
const size_t write_size = block_size_ - bytes_written_mod_block_size_;
brillo::Blob zeros(write_size, 0);
TEST_AND_RETURN_FALSE(underlying_extent_writer_->Write(zeros.data(),
write_size));
}
return underlying_extent_writer_->End();
}
private:
std::unique_ptr<ExtentWriter> underlying_extent_writer_;
size_t block_size_{0};
size_t bytes_written_mod_block_size_{0};
};
} // namespace chromeos_update_engine
#endif // UPDATE_ENGINE_PAYLOAD_CONSUMER_EXTENT_WRITER_H_
|