• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Init(FileDescriptorPtr fd,const RepeatedPtrField<Extent> & extents,uint32_t block_size)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 
Seek(uint64_t offset)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 
Read(void * buffer,size_t count)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