• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2009 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_generator/extent_utils.h"
18 
19 #include <inttypes.h>
20 
21 #include <string>
22 #include <utility>
23 #include <vector>
24 
25 #include <base/logging.h>
26 #include <base/macros.h>
27 #include <base/strings/stringprintf.h>
28 
29 #include "update_engine/common/utils.h"
30 #include "update_engine/payload_consumer/payload_constants.h"
31 #include "update_engine/payload_generator/annotated_operation.h"
32 #include "update_engine/payload_generator/extent_ranges.h"
33 
34 using std::string;
35 using std::vector;
36 
37 namespace chromeos_update_engine {
38 
AppendBlockToExtents(vector<Extent> * extents,uint64_t block)39 void AppendBlockToExtents(vector<Extent>* extents, uint64_t block) {
40   // First try to extend the last extent in |extents|, if any.
41   if (!extents->empty()) {
42     Extent& extent = extents->back();
43     uint64_t next_block = extent.start_block() == kSparseHole
44                               ? kSparseHole
45                               : extent.start_block() + extent.num_blocks();
46     if (next_block == block) {
47       extent.set_num_blocks(extent.num_blocks() + 1);
48       return;
49     }
50   }
51   // If unable to extend the last extent, append a new single-block extent.
52   Extent new_extent;
53   new_extent.set_start_block(block);
54   new_extent.set_num_blocks(1);
55   extents->push_back(new_extent);
56 }
57 
ExtendExtents(google::protobuf::RepeatedPtrField<Extent> * extents,const google::protobuf::RepeatedPtrField<Extent> & extents_to_add)58 void ExtendExtents(
59     google::protobuf::RepeatedPtrField<Extent>* extents,
60     const google::protobuf::RepeatedPtrField<Extent>& extents_to_add) {
61   vector<Extent> extents_vector;
62   vector<Extent> extents_to_add_vector;
63   ExtentsToVector(*extents, &extents_vector);
64   ExtentsToVector(extents_to_add, &extents_to_add_vector);
65   extents_vector.insert(extents_vector.end(),
66                         extents_to_add_vector.begin(),
67                         extents_to_add_vector.end());
68   NormalizeExtents(&extents_vector);
69   extents->Clear();
70   StoreExtents(extents_vector, extents);
71 }
72 
73 // Stores all Extents in 'extents' into 'out'.
StoreExtents(const vector<Extent> & extents,google::protobuf::RepeatedPtrField<Extent> * out)74 void StoreExtents(const vector<Extent>& extents,
75                   google::protobuf::RepeatedPtrField<Extent>* out) {
76   for (const Extent& extent : extents) {
77     Extent* new_extent = out->Add();
78     *new_extent = extent;
79   }
80 }
81 
82 // Stores all extents in |extents| into |out_vector|.
ExtentsToVector(const google::protobuf::RepeatedPtrField<Extent> & extents,vector<Extent> * out_vector)83 void ExtentsToVector(const google::protobuf::RepeatedPtrField<Extent>& extents,
84                      vector<Extent>* out_vector) {
85   out_vector->clear();
86   for (int i = 0; i < extents.size(); i++) {
87     out_vector->push_back(extents.Get(i));
88   }
89 }
90 
91 template <typename Container>
ExtentsToStringTemplate(const Container & extents)92 string ExtentsToStringTemplate(const Container& extents) {
93   string ext_str;
94   for (const Extent& e : extents)
95     ext_str += base::StringPrintf("[%" PRIu64 ", %" PRIu64 "] ",
96                                   static_cast<uint64_t>(e.start_block()),
97                                   static_cast<uint64_t>(e.num_blocks()));
98   return ext_str;
99 }
100 
ExtentsToString(const std::vector<Extent> & extents)101 std::string ExtentsToString(const std::vector<Extent>& extents) {
102   return ExtentsToStringTemplate(extents);
103 }
104 
ExtentsToString(const google::protobuf::RepeatedPtrField<Extent> & extents)105 std::string ExtentsToString(
106     const google::protobuf::RepeatedPtrField<Extent>& extents) {
107   return ExtentsToStringTemplate(extents);
108 }
109 
NormalizeExtents(vector<Extent> * extents)110 void NormalizeExtents(vector<Extent>* extents) {
111   vector<Extent> new_extents;
112   for (const Extent& curr_ext : *extents) {
113     if (new_extents.empty()) {
114       new_extents.push_back(curr_ext);
115       continue;
116     }
117     Extent& last_ext = new_extents.back();
118     if (last_ext.start_block() + last_ext.num_blocks() ==
119         curr_ext.start_block()) {
120       // If the extents are touching, we want to combine them.
121       last_ext.set_num_blocks(last_ext.num_blocks() + curr_ext.num_blocks());
122     } else {
123       // Otherwise just include the extent as is.
124       new_extents.push_back(curr_ext);
125     }
126   }
127   *extents = new_extents;
128 }
129 
ExtentsSublist(const vector<Extent> & extents,uint64_t block_offset,uint64_t block_count)130 vector<Extent> ExtentsSublist(const vector<Extent>& extents,
131                               uint64_t block_offset,
132                               uint64_t block_count) {
133   vector<Extent> result;
134   uint64_t scanned_blocks = 0;
135   if (block_count == 0)
136     return result;
137   uint64_t end_block_offset = block_offset + block_count;
138   for (const Extent& extent : extents) {
139     // The loop invariant is that if |extents| has enough blocks, there's
140     // still some extent to add to |result|. This implies that at the beginning
141     // of the loop scanned_blocks < block_offset + block_count.
142     if (scanned_blocks + extent.num_blocks() > block_offset) {
143       // This case implies that |extent| has some overlapping with the requested
144       // subsequence.
145       uint64_t new_start = extent.start_block();
146       uint64_t new_num_blocks = extent.num_blocks();
147       if (scanned_blocks + new_num_blocks > end_block_offset) {
148         // Cut the end part of the extent.
149         new_num_blocks = end_block_offset - scanned_blocks;
150       }
151       if (block_offset > scanned_blocks) {
152         // Cut the begin part of the extent.
153         new_num_blocks -= block_offset - scanned_blocks;
154         new_start += block_offset - scanned_blocks;
155       }
156       result.push_back(ExtentForRange(new_start, new_num_blocks));
157     }
158     scanned_blocks += extent.num_blocks();
159     if (scanned_blocks >= end_block_offset)
160       break;
161   }
162   return result;
163 }
164 
operator ==(const Extent & a,const Extent & b)165 bool operator==(const Extent& a, const Extent& b) noexcept {
166   return a.start_block() == b.start_block() && a.num_blocks() == b.num_blocks();
167 }
168 
operator !=(const Extent & a,const Extent & b)169 bool operator!=(const Extent& a, const Extent& b) noexcept {
170   return !(a == b);
171 }
172 
operator <<(std::ostream & out,const Extent & extent)173 std::ostream& operator<<(std::ostream& out, const Extent& extent) {
174   out << "[" << extent.start_block() << " - "
175       << extent.start_block() + extent.num_blocks() - 1 << "]";
176   return out;
177 }
178 
179 template <typename T>
PrintExtents(std::ostream & out,const T & extents)180 std::ostream& PrintExtents(std::ostream& out, const T& extents) {
181   if (extents.begin() == extents.end()) {
182     out << "{}";
183     return out;
184   }
185   out << "{";
186   auto begin = extents.begin();
187   out << *begin;
188   for (const auto& ext : Range{++begin, extents.end()}) {
189     out << ", " << ext;
190   }
191   out << "}";
192   return out;
193 }
194 
operator <<(std::ostream & out,const std::vector<Extent> & extents)195 std::ostream& operator<<(std::ostream& out,
196                          const std::vector<Extent>& extents) {
197   return PrintExtents(out, extents);
198 }
operator <<(std::ostream & out,const google::protobuf::RepeatedPtrField<Extent> & extents)199 std::ostream& operator<<(
200     std::ostream& out,
201     const google::protobuf::RepeatedPtrField<Extent>& extents) {
202   return PrintExtents(out, extents);
203 }
204 
205 }  // namespace chromeos_update_engine
206