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