blob: 3974247fdc0aa30913f6608d8481b30ee0346f2f [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/storage/blobfs/iterator/block_iterator.h"
#include <lib/syslog/cpp/macros.h>
#include <stdint.h>
#include <zircon/types.h>
#include <algorithm>
#include <safemath/safe_conversions.h>
#include "src/storage/blobfs/format.h"
namespace blobfs {
BlockIterator::BlockIterator(std::unique_ptr<ExtentIterator> iterator)
: iterator_(std::move(iterator)) {}
bool BlockIterator::Done() const { return blocks_left_ == 0 && iterator_->Done(); }
uint64_t BlockIterator::BlockIndex() const { return iterator_->BlockIndex() - blocks_left_; }
zx_status_t BlockIterator::Next(uint64_t length, uint64_t* out_length, uint64_t* out_start) {
ZX_DEBUG_ASSERT(!Done());
// If there are no blocks left, refill the extent.
if (!blocks_left_) {
auto extent_or = iterator_->Next();
if (extent_or.is_error()) {
return extent_or.status_value();
}
extent_ = extent_or.value();
blocks_left_ = extent_->Length();
}
// Return as many blocks as possible within this current extent.
ZX_DEBUG_ASSERT(extent_ != nullptr);
*out_length = std::min(blocks_left_, length);
*out_start = (extent_->Start() + extent_->Length()) - blocks_left_;
blocks_left_ -= *out_length;
return ZX_OK;
}
zx_status_t IterateToBlock(BlockIterator* iter, uint64_t block_num) {
while (!iter->Done() && block_num > iter->BlockIndex()) {
uint64_t out_length = 0;
uint64_t out_start = 0;
uint64_t blocks_to_iterate_over = block_num - iter->BlockIndex();
zx_status_t status = iter->Next(blocks_to_iterate_over, &out_length, &out_start);
if (status != ZX_OK) {
return status;
}
}
if (iter->Done()) {
return ZX_ERR_INVALID_ARGS;
}
return ZX_OK;
}
zx_status_t StreamBlocks(BlockIterator* iterator, uint64_t block_count, StreamFn stream) {
while (block_count > 0) {
if (iterator->Done()) {
FX_LOGS(ERROR) << "Failed to access data (early exit)";
return ZX_ERR_IO_DATA_INTEGRITY;
}
uint64_t local_offset = iterator->BlockIndex();
uint64_t actual_length;
uint64_t dev_offset;
zx_status_t status = iterator->Next(block_count, &actual_length, &dev_offset);
if (status != ZX_OK) {
FX_LOGS(ERROR) << "Failed to iterate over blocks: " << status;
return status;
}
status = stream(local_offset, dev_offset, actual_length);
if (status != ZX_OK) {
FX_LOGS(ERROR) << "Failed to enqueue blocks: " << status;
return status;
}
block_count -= actual_length;
}
return ZX_OK;
}
} // namespace blobfs