1 // Copyright 2018 The Fuchsia 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 <stdint.h>
6
7 #include <algorithm>
8
9 #include <blobfs/format.h>
10 #include <blobfs/iterator/block-iterator.h>
11 #include <blobfs/iterator/extent-iterator.h>
12 #include <zircon/types.h>
13
14 namespace blobfs {
15
BlockIterator(ExtentIterator * iterator)16 BlockIterator::BlockIterator(ExtentIterator* iterator) : iterator_(iterator) {}
17
Done() const18 bool BlockIterator::Done() const {
19 return blocks_left_ == 0 && iterator_->Done();
20 }
21
BlockIndex() const22 uint64_t BlockIterator::BlockIndex() const {
23 return iterator_->BlockIndex() - blocks_left_;
24 }
25
Next(uint32_t length,uint32_t * out_length,uint64_t * out_start)26 zx_status_t BlockIterator::Next(uint32_t length, uint32_t* out_length, uint64_t* out_start) {
27 ZX_DEBUG_ASSERT(!Done());
28
29 // If there are no blocks left, refill the extent.
30 if (!blocks_left_) {
31 zx_status_t status = iterator_->Next(&extent_);
32 if (status != ZX_OK) {
33 return status;
34 }
35 blocks_left_ = extent_->Length();
36 }
37
38 // Return as many blocks as possible within this current extent.
39 ZX_DEBUG_ASSERT(extent_ != nullptr);
40 *out_length = std::min(blocks_left_, length);
41 *out_start = (extent_->Start() + extent_->Length()) - blocks_left_;
42 blocks_left_ -= *out_length;
43 return ZX_OK;
44 }
45
StreamBlocks(BlockIterator * iterator,uint32_t block_count,StreamFn stream)46 zx_status_t StreamBlocks(BlockIterator* iterator, uint32_t block_count, StreamFn stream) {
47 while (block_count > 0) {
48 if (iterator->Done()) {
49 FS_TRACE_ERROR("Failed to access data (early exit)\n");
50 return ZX_ERR_IO_DATA_INTEGRITY;
51 }
52 uint64_t local_offset = iterator->BlockIndex();
53 uint32_t actual_length;
54 uint64_t dev_offset;
55 zx_status_t status = iterator->Next(block_count, &actual_length, &dev_offset);
56 if (status != ZX_OK) {
57 FS_TRACE_ERROR("Failed to iterate over blocks: %d\n", status);
58 return status;
59 }
60 status = stream(local_offset, dev_offset, actual_length);
61 if (status != ZX_OK) {
62 FS_TRACE_ERROR("Failed to enqueue blocks: %d\n", status);
63 return status;
64 }
65 block_count -= actual_length;
66 }
67 return ZX_OK;
68 }
69
70 } // namespace blobfs
71