1 // 2 // Copyright (C) 2017 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 "update_engine/payload_consumer/extent_reader.h" 18 19 #include <sys/types.h> 20 #include <unistd.h> 21 22 #include "update_engine/common/utils.h" 23 #include "update_engine/payload_consumer/payload_constants.h" 24 25 using google::protobuf::RepeatedPtrField; 26 27 namespace chromeos_update_engine { 28 29 bool DirectExtentReader::Init(FileDescriptorPtr fd, 30 const RepeatedPtrField<Extent>& extents, 31 uint32_t block_size) { 32 fd_ = fd; 33 extents_ = extents; 34 block_size_ = block_size; 35 cur_extent_ = extents_.begin(); 36 37 extents_upper_bounds_.reserve(extents_.size() + 1); 38 // We add this pad as the first element to not bother with boundary checks 39 // later. 40 extents_upper_bounds_.emplace_back(0); 41 for (const auto& extent : extents_) { 42 total_size_ += extent.num_blocks() * block_size_; 43 extents_upper_bounds_.emplace_back(total_size_); 44 } 45 return true; 46 } 47 48 bool DirectExtentReader::Seek(uint64_t offset) { 49 TEST_AND_RETURN_FALSE(offset <= total_size_); 50 if (offset_ == offset) { 51 return true; 52 } 53 // The first item is zero and upper_bound never returns it because it always 54 // return the item which is greater than the given value. 55 auto extent_idx = std::upper_bound( 56 extents_upper_bounds_.begin(), extents_upper_bounds_.end(), offset) - 57 extents_upper_bounds_.begin() - 1; 58 cur_extent_ = std::next(extents_.begin(), extent_idx); 59 offset_ = offset; 60 cur_extent_bytes_read_ = offset_ - extents_upper_bounds_[extent_idx]; 61 return true; 62 } 63 64 bool DirectExtentReader::Read(void* buffer, size_t count) { 65 auto bytes = reinterpret_cast<uint8_t*>(buffer); 66 uint64_t bytes_read = 0; 67 while (bytes_read < count) { 68 if (cur_extent_ == extents_.end()) { 69 TEST_AND_RETURN_FALSE(bytes_read == count); 70 } 71 uint64_t cur_extent_bytes_left = 72 cur_extent_->num_blocks() * block_size_ - cur_extent_bytes_read_; 73 uint64_t bytes_to_read = 74 std::min(count - bytes_read, cur_extent_bytes_left); 75 76 ssize_t out_bytes_read; 77 TEST_AND_RETURN_FALSE(utils::PReadAll( 78 fd_, 79 bytes + bytes_read, 80 bytes_to_read, 81 cur_extent_->start_block() * block_size_ + cur_extent_bytes_read_, 82 &out_bytes_read)); 83 TEST_AND_RETURN_FALSE(out_bytes_read == 84 static_cast<ssize_t>(bytes_to_read)); 85 86 bytes_read += bytes_to_read; 87 cur_extent_bytes_read_ += bytes_to_read; 88 offset_ += bytes_to_read; 89 if (cur_extent_bytes_read_ == cur_extent_->num_blocks() * block_size_) { 90 // We have to advance the cur_extent_; 91 cur_extent_++; 92 cur_extent_bytes_read_ = 0; 93 } 94 } 95 return true; 96 } 97 98 } // namespace chromeos_update_engine 99