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