1 //
2 // Copyright (C) 2020 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include "snapshot_reader.h"
18
19 #include <android-base/file.h>
20 #include <android-base/logging.h>
21 #include <ext4_utils/ext4_utils.h>
22
23 namespace android {
24 namespace snapshot {
25
26 using android::base::borrowed_fd;
27
28 // Not supported.
Open(const char *,int,mode_t)29 bool ReadOnlyFileDescriptor::Open(const char*, int, mode_t) {
30 errno = EINVAL;
31 return false;
32 }
33
Open(const char *,int)34 bool ReadOnlyFileDescriptor::Open(const char*, int) {
35 errno = EINVAL;
36 return false;
37 }
38
Write(const void *,size_t)39 ssize_t ReadOnlyFileDescriptor::Write(const void*, size_t) {
40 errno = EINVAL;
41 return false;
42 }
43
BlkIoctl(int,uint64_t,uint64_t,int *)44 bool ReadOnlyFileDescriptor::BlkIoctl(int, uint64_t, uint64_t, int*) {
45 errno = EINVAL;
46 return false;
47 }
48
ReadFdFileDescriptor(android::base::unique_fd && fd)49 ReadFdFileDescriptor::ReadFdFileDescriptor(android::base::unique_fd&& fd) : fd_(std::move(fd)) {}
50
Read(void * buf,size_t count)51 ssize_t ReadFdFileDescriptor::Read(void* buf, size_t count) {
52 return read(fd_.get(), buf, count);
53 }
54
Seek(off64_t offset,int whence)55 off64_t ReadFdFileDescriptor::Seek(off64_t offset, int whence) {
56 return lseek(fd_.get(), offset, whence);
57 }
58
BlockDevSize()59 uint64_t ReadFdFileDescriptor::BlockDevSize() {
60 return get_block_device_size(fd_.get());
61 }
62
Close()63 bool ReadFdFileDescriptor::Close() {
64 fd_ = {};
65 return true;
66 }
67
IsSettingErrno()68 bool ReadFdFileDescriptor::IsSettingErrno() {
69 return true;
70 }
71
IsOpen()72 bool ReadFdFileDescriptor::IsOpen() {
73 return fd_ >= 0;
74 }
75
Flush()76 bool ReadFdFileDescriptor::Flush() {
77 return true;
78 }
79
SetCow(std::unique_ptr<CowReader> && cow)80 bool CompressedSnapshotReader::SetCow(std::unique_ptr<CowReader>&& cow) {
81 cow_ = std::move(cow);
82
83 CowHeader header;
84 if (!cow_->GetHeader(&header)) {
85 return false;
86 }
87 block_size_ = header.block_size;
88
89 // Populate the operation map.
90 op_iter_ = cow_->GetOpIter();
91 while (!op_iter_->Done()) {
92 const CowOperation* op = &op_iter_->Get();
93 if (IsMetadataOp(*op)) {
94 op_iter_->Next();
95 continue;
96 }
97 if (op->new_block >= ops_.size()) {
98 ops_.resize(op->new_block + 1, nullptr);
99 }
100 ops_[op->new_block] = op;
101 op_iter_->Next();
102 }
103
104 return true;
105 }
106
SetSourceDevice(const std::string & source_device)107 void CompressedSnapshotReader::SetSourceDevice(const std::string& source_device) {
108 source_device_ = {source_device};
109 }
110
SetBlockDeviceSize(uint64_t block_device_size)111 void CompressedSnapshotReader::SetBlockDeviceSize(uint64_t block_device_size) {
112 block_device_size_ = block_device_size;
113 }
114
GetSourceFd()115 borrowed_fd CompressedSnapshotReader::GetSourceFd() {
116 if (source_fd_ < 0) {
117 if (!source_device_) {
118 LOG(ERROR) << "CompressedSnapshotReader needs source device, but none was set";
119 errno = EINVAL;
120 return {-1};
121 }
122 source_fd_.reset(open(source_device_->c_str(), O_RDONLY | O_CLOEXEC));
123 if (source_fd_ < 0) {
124 PLOG(ERROR) << "open " << *source_device_;
125 return {-1};
126 }
127 }
128 return source_fd_;
129 }
130
131 class MemoryByteSink : public IByteSink {
132 public:
MemoryByteSink(void * buf,size_t count)133 MemoryByteSink(void* buf, size_t count) {
134 buf_ = reinterpret_cast<uint8_t*>(buf);
135 pos_ = buf_;
136 end_ = buf_ + count;
137 }
138
GetBuffer(size_t requested,size_t * actual)139 void* GetBuffer(size_t requested, size_t* actual) override {
140 *actual = std::min(remaining(), requested);
141 if (!*actual) {
142 return nullptr;
143 }
144
145 uint8_t* start = pos_;
146 pos_ += *actual;
147 return start;
148 }
149
ReturnData(void *,size_t)150 bool ReturnData(void*, size_t) override { return true; }
151
buf() const152 uint8_t* buf() const { return buf_; }
pos() const153 uint8_t* pos() const { return pos_; }
remaining() const154 size_t remaining() const { return end_ - pos_; }
155
156 private:
157 uint8_t* buf_;
158 uint8_t* pos_;
159 uint8_t* end_;
160 };
161
Read(void * buf,size_t count)162 ssize_t CompressedSnapshotReader::Read(void* buf, size_t count) {
163 // Find the start and end chunks, inclusive.
164 uint64_t start_chunk = offset_ / block_size_;
165 uint64_t end_chunk = (offset_ + count - 1) / block_size_;
166
167 // Chop off the first N bytes if the position is not block-aligned.
168 size_t start_offset = offset_ % block_size_;
169
170 MemoryByteSink sink(buf, count);
171
172 size_t initial_bytes = std::min(block_size_ - start_offset, sink.remaining());
173 ssize_t rv = ReadBlock(start_chunk, &sink, start_offset, initial_bytes);
174 if (rv < 0) {
175 return -1;
176 }
177 offset_ += rv;
178
179 for (uint64_t chunk = start_chunk + 1; chunk < end_chunk; chunk++) {
180 ssize_t rv = ReadBlock(chunk, &sink, 0);
181 if (rv < 0) {
182 return -1;
183 }
184 offset_ += rv;
185 }
186
187 if (sink.remaining()) {
188 ssize_t rv = ReadBlock(end_chunk, &sink, 0, {sink.remaining()});
189 if (rv < 0) {
190 return -1;
191 }
192 offset_ += rv;
193 }
194
195 errno = 0;
196
197 DCHECK(sink.pos() - sink.buf() == count);
198 return count;
199 }
200
201 // Discard the first N bytes of a sink request, or any excess bytes.
202 class PartialSink : public MemoryByteSink {
203 public:
PartialSink(void * buffer,size_t size,size_t ignore_start)204 PartialSink(void* buffer, size_t size, size_t ignore_start)
205 : MemoryByteSink(buffer, size), ignore_start_(ignore_start) {}
206
GetBuffer(size_t requested,size_t * actual)207 void* GetBuffer(size_t requested, size_t* actual) override {
208 // Throw away the first N bytes if needed.
209 if (ignore_start_) {
210 *actual = std::min({requested, ignore_start_, sizeof(discard_)});
211 ignore_start_ -= *actual;
212 return discard_;
213 }
214 // Throw away any excess bytes if needed.
215 if (remaining() == 0) {
216 *actual = std::min(requested, sizeof(discard_));
217 return discard_;
218 }
219 return MemoryByteSink::GetBuffer(requested, actual);
220 }
221
222 private:
223 size_t ignore_start_;
224 char discard_[4096];
225 };
226
ReadBlock(uint64_t chunk,IByteSink * sink,size_t start_offset,const std::optional<uint64_t> & max_bytes)227 ssize_t CompressedSnapshotReader::ReadBlock(uint64_t chunk, IByteSink* sink, size_t start_offset,
228 const std::optional<uint64_t>& max_bytes) {
229 size_t bytes_to_read = block_size_;
230 if (max_bytes) {
231 bytes_to_read = *max_bytes;
232 }
233
234 // The offset is relative to the chunk; we should be reading no more than
235 // one chunk.
236 CHECK(start_offset + bytes_to_read <= block_size_);
237
238 const CowOperation* op = nullptr;
239 if (chunk < ops_.size()) {
240 op = ops_[chunk];
241 }
242
243 size_t actual;
244 void* buffer = sink->GetBuffer(bytes_to_read, &actual);
245 if (!buffer || actual < bytes_to_read) {
246 // This should never happen unless we calculated the read size wrong
247 // somewhere. MemoryByteSink always fulfills the entire requested
248 // region unless there's not enough buffer remaining.
249 LOG(ERROR) << "Asked for buffer of size " << bytes_to_read << ", got " << actual;
250 errno = EINVAL;
251 return -1;
252 }
253
254 if (!op || op->type == kCowCopyOp) {
255 borrowed_fd fd = GetSourceFd();
256 if (fd < 0) {
257 // GetSourceFd sets errno.
258 return -1;
259 }
260
261 if (op) {
262 chunk = op->source;
263 }
264
265 off64_t offset = (chunk * block_size_) + start_offset;
266 if (!android::base::ReadFullyAtOffset(fd, buffer, bytes_to_read, offset)) {
267 PLOG(ERROR) << "read " << *source_device_;
268 // ReadFullyAtOffset sets errno.
269 return -1;
270 }
271 } else if (op->type == kCowZeroOp) {
272 memset(buffer, 0, bytes_to_read);
273 } else if (op->type == kCowReplaceOp) {
274 PartialSink partial_sink(buffer, bytes_to_read, start_offset);
275 if (!cow_->ReadData(*op, &partial_sink)) {
276 LOG(ERROR) << "CompressedSnapshotReader failed to read replace op";
277 errno = EIO;
278 return -1;
279 }
280 } else {
281 LOG(ERROR) << "CompressedSnapshotReader unknown op type: " << uint32_t(op->type);
282 errno = EINVAL;
283 return -1;
284 }
285
286 // MemoryByteSink doesn't do anything in ReturnBuffer, so don't bother calling it.
287 return bytes_to_read;
288 }
289
Seek(off64_t offset,int whence)290 off64_t CompressedSnapshotReader::Seek(off64_t offset, int whence) {
291 switch (whence) {
292 case SEEK_SET:
293 offset_ = offset;
294 break;
295 case SEEK_END:
296 offset_ = static_cast<off64_t>(block_device_size_) + offset;
297 break;
298 case SEEK_CUR:
299 offset_ += offset;
300 break;
301 default:
302 LOG(ERROR) << "Unrecognized seek whence: " << whence;
303 errno = EINVAL;
304 return -1;
305 }
306 return offset_;
307 }
308
BlockDevSize()309 uint64_t CompressedSnapshotReader::BlockDevSize() {
310 return block_device_size_;
311 }
312
Close()313 bool CompressedSnapshotReader::Close() {
314 cow_ = nullptr;
315 source_fd_ = {};
316 return true;
317 }
318
IsSettingErrno()319 bool CompressedSnapshotReader::IsSettingErrno() {
320 return true;
321 }
322
IsOpen()323 bool CompressedSnapshotReader::IsOpen() {
324 return cow_ != nullptr;
325 }
326
Flush()327 bool CompressedSnapshotReader::Flush() {
328 return true;
329 }
330
331 } // namespace snapshot
332 } // namespace android
333