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