xref: /aosp_15_r20/external/puffin/src/extent_stream.cc (revision 07fb1d065b7cfb4729786fadd42a612532d2f466)
1*07fb1d06SElliott Hughes // Copyright 2017 The ChromiumOS Authors
2*07fb1d06SElliott Hughes // Use of this source code is governed by a BSD-style license that can be
3*07fb1d06SElliott Hughes // found in the LICENSE file.
4*07fb1d06SElliott Hughes 
5*07fb1d06SElliott Hughes #include "puffin/src/extent_stream.h"
6*07fb1d06SElliott Hughes 
7*07fb1d06SElliott Hughes #include <algorithm>
8*07fb1d06SElliott Hughes #include <utility>
9*07fb1d06SElliott Hughes 
10*07fb1d06SElliott Hughes #include "puffin/src/logging.h"
11*07fb1d06SElliott Hughes 
12*07fb1d06SElliott Hughes using std::vector;
13*07fb1d06SElliott Hughes 
14*07fb1d06SElliott Hughes namespace puffin {
15*07fb1d06SElliott Hughes 
CreateForWrite(UniqueStreamPtr stream,const vector<ByteExtent> & extents)16*07fb1d06SElliott Hughes UniqueStreamPtr ExtentStream::CreateForWrite(
17*07fb1d06SElliott Hughes     UniqueStreamPtr stream, const vector<ByteExtent>& extents) {
18*07fb1d06SElliott Hughes   return UniqueStreamPtr(new ExtentStream(std::move(stream), extents, true));
19*07fb1d06SElliott Hughes }
20*07fb1d06SElliott Hughes 
CreateForRead(UniqueStreamPtr stream,const vector<ByteExtent> & extents)21*07fb1d06SElliott Hughes UniqueStreamPtr ExtentStream::CreateForRead(UniqueStreamPtr stream,
22*07fb1d06SElliott Hughes                                             const vector<ByteExtent>& extents) {
23*07fb1d06SElliott Hughes   return UniqueStreamPtr(new ExtentStream(std::move(stream), extents, false));
24*07fb1d06SElliott Hughes }
25*07fb1d06SElliott Hughes 
ExtentStream(UniqueStreamPtr stream,const vector<ByteExtent> & extents,bool is_for_write)26*07fb1d06SElliott Hughes ExtentStream::ExtentStream(UniqueStreamPtr stream,
27*07fb1d06SElliott Hughes                            const vector<ByteExtent>& extents,
28*07fb1d06SElliott Hughes                            bool is_for_write)
29*07fb1d06SElliott Hughes     : stream_(std::move(stream)),
30*07fb1d06SElliott Hughes       extents_(extents),
31*07fb1d06SElliott Hughes       cur_extent_offset_(0),
32*07fb1d06SElliott Hughes       is_for_write_(is_for_write),
33*07fb1d06SElliott Hughes       offset_(0) {
34*07fb1d06SElliott Hughes   extents_upper_bounds_.reserve(extents_.size() + 1);
35*07fb1d06SElliott Hughes   extents_upper_bounds_.emplace_back(0);
36*07fb1d06SElliott Hughes   uint64_t total_size = 0;
37*07fb1d06SElliott Hughes   uint64_t extent_end = 0;
38*07fb1d06SElliott Hughes   for (const auto& extent : extents_) {
39*07fb1d06SElliott Hughes     total_size += extent.length;
40*07fb1d06SElliott Hughes     extents_upper_bounds_.emplace_back(total_size);
41*07fb1d06SElliott Hughes     extent_end = extent.offset + extent.length;
42*07fb1d06SElliott Hughes   }
43*07fb1d06SElliott Hughes   size_ = total_size;
44*07fb1d06SElliott Hughes 
45*07fb1d06SElliott Hughes   // Adding one extent at the end to avoid doing extra checks in:
46*07fb1d06SElliott Hughes   // - Seek: when seeking to the end of extents
47*07fb1d06SElliott Hughes   // - DoReadOrWrite: when changing the current extent.
48*07fb1d06SElliott Hughes   extents_.emplace_back(extent_end, 0);
49*07fb1d06SElliott Hughes   cur_extent_ = extents_.begin();
50*07fb1d06SElliott Hughes }
51*07fb1d06SElliott Hughes 
GetSize(uint64_t * size) const52*07fb1d06SElliott Hughes bool ExtentStream::GetSize(uint64_t* size) const {
53*07fb1d06SElliott Hughes   *size = size_;
54*07fb1d06SElliott Hughes   return true;
55*07fb1d06SElliott Hughes }
56*07fb1d06SElliott Hughes 
GetOffset(uint64_t * offset) const57*07fb1d06SElliott Hughes bool ExtentStream::GetOffset(uint64_t* offset) const {
58*07fb1d06SElliott Hughes   *offset = offset_;
59*07fb1d06SElliott Hughes   return true;
60*07fb1d06SElliott Hughes }
61*07fb1d06SElliott Hughes 
Seek(uint64_t offset)62*07fb1d06SElliott Hughes bool ExtentStream::Seek(uint64_t offset) {
63*07fb1d06SElliott Hughes   TEST_AND_RETURN_FALSE(offset <= size_);
64*07fb1d06SElliott Hughes 
65*07fb1d06SElliott Hughes   // The first item is zero and upper_bound never returns it because it always
66*07fb1d06SElliott Hughes   // return the item which is greater than the given value.
67*07fb1d06SElliott Hughes   auto extent_idx = std::upper_bound(extents_upper_bounds_.begin(),
68*07fb1d06SElliott Hughes                                      extents_upper_bounds_.end(), offset) -
69*07fb1d06SElliott Hughes                     extents_upper_bounds_.begin() - 1;
70*07fb1d06SElliott Hughes   cur_extent_ = std::next(extents_.begin(), extent_idx);
71*07fb1d06SElliott Hughes   offset_ = offset;
72*07fb1d06SElliott Hughes   cur_extent_offset_ = offset_ - extents_upper_bounds_[extent_idx];
73*07fb1d06SElliott Hughes   TEST_AND_RETURN_FALSE(
74*07fb1d06SElliott Hughes       stream_->Seek(cur_extent_->offset + cur_extent_offset_));
75*07fb1d06SElliott Hughes   return true;
76*07fb1d06SElliott Hughes }
77*07fb1d06SElliott Hughes 
Close()78*07fb1d06SElliott Hughes bool ExtentStream::Close() {
79*07fb1d06SElliott Hughes   return stream_->Close();
80*07fb1d06SElliott Hughes }
81*07fb1d06SElliott Hughes 
Read(void * buffer,size_t length)82*07fb1d06SElliott Hughes bool ExtentStream::Read(void* buffer, size_t length) {
83*07fb1d06SElliott Hughes   TEST_AND_RETURN_FALSE(!is_for_write_);
84*07fb1d06SElliott Hughes   TEST_AND_RETURN_FALSE(DoReadOrWrite(buffer, nullptr, length));
85*07fb1d06SElliott Hughes   return true;
86*07fb1d06SElliott Hughes }
87*07fb1d06SElliott Hughes 
Write(const void * buffer,size_t length)88*07fb1d06SElliott Hughes bool ExtentStream::Write(const void* buffer, size_t length) {
89*07fb1d06SElliott Hughes   TEST_AND_RETURN_FALSE(is_for_write_);
90*07fb1d06SElliott Hughes   TEST_AND_RETURN_FALSE(DoReadOrWrite(nullptr, buffer, length));
91*07fb1d06SElliott Hughes   return true;
92*07fb1d06SElliott Hughes }
93*07fb1d06SElliott Hughes 
DoReadOrWrite(void * read_buffer,const void * write_buffer,size_t length)94*07fb1d06SElliott Hughes bool ExtentStream::DoReadOrWrite(void* read_buffer,
95*07fb1d06SElliott Hughes                                  const void* write_buffer,
96*07fb1d06SElliott Hughes                                  size_t length) {
97*07fb1d06SElliott Hughes   uint64_t bytes_passed = 0;
98*07fb1d06SElliott Hughes   while (bytes_passed < length) {
99*07fb1d06SElliott Hughes     if (cur_extent_ == extents_.end()) {
100*07fb1d06SElliott Hughes       return false;
101*07fb1d06SElliott Hughes     }
102*07fb1d06SElliott Hughes     uint64_t bytes_to_pass = std::min(length - bytes_passed,
103*07fb1d06SElliott Hughes                                       cur_extent_->length - cur_extent_offset_);
104*07fb1d06SElliott Hughes     if (read_buffer != nullptr) {
105*07fb1d06SElliott Hughes       TEST_AND_RETURN_FALSE(
106*07fb1d06SElliott Hughes           stream_->Read(reinterpret_cast<uint8_t*>(read_buffer) + bytes_passed,
107*07fb1d06SElliott Hughes                         bytes_to_pass));
108*07fb1d06SElliott Hughes     } else if (write_buffer != nullptr) {
109*07fb1d06SElliott Hughes       TEST_AND_RETURN_FALSE(stream_->Write(
110*07fb1d06SElliott Hughes           reinterpret_cast<const uint8_t*>(write_buffer) + bytes_passed,
111*07fb1d06SElliott Hughes           bytes_to_pass));
112*07fb1d06SElliott Hughes     } else {
113*07fb1d06SElliott Hughes       LOG(ERROR) << "Either read or write buffer should be given!";
114*07fb1d06SElliott Hughes       return false;
115*07fb1d06SElliott Hughes     }
116*07fb1d06SElliott Hughes 
117*07fb1d06SElliott Hughes     bytes_passed += bytes_to_pass;
118*07fb1d06SElliott Hughes     cur_extent_offset_ += bytes_to_pass;
119*07fb1d06SElliott Hughes     offset_ += bytes_to_pass;
120*07fb1d06SElliott Hughes     if (cur_extent_offset_ == cur_extent_->length) {
121*07fb1d06SElliott Hughes       // We have to advance the cur_extent_;
122*07fb1d06SElliott Hughes       cur_extent_++;
123*07fb1d06SElliott Hughes       cur_extent_offset_ = 0;
124*07fb1d06SElliott Hughes       if (cur_extent_ != extents_.end()) {
125*07fb1d06SElliott Hughes         TEST_AND_RETURN_FALSE(stream_->Seek(cur_extent_->offset));
126*07fb1d06SElliott Hughes       }
127*07fb1d06SElliott Hughes     }
128*07fb1d06SElliott Hughes   }
129*07fb1d06SElliott Hughes   return true;
130*07fb1d06SElliott Hughes }
131*07fb1d06SElliott Hughes 
132*07fb1d06SElliott Hughes }  // namespace puffin
133