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 <blobfs/format.h>
8 #include <blobfs/iterator/allocated-extent-iterator.h>
9 #include <blobfs/iterator/extent-iterator.h>
10 #include <zircon/types.h>
11 
12 namespace blobfs {
13 
AllocatedExtentIterator(NodeFinder * finder,uint32_t node_index)14 AllocatedExtentIterator::AllocatedExtentIterator(NodeFinder* finder, uint32_t node_index)
15     : finder_(finder), inode_(finder_->GetNode(node_index)), node_index_(node_index),
16       extent_node_(nullptr) {}
17 
Done() const18 bool AllocatedExtentIterator::Done() const {
19     return extent_index_ == inode_->extent_count;
20 }
21 
Next(const Extent ** out)22 zx_status_t AllocatedExtentIterator::Next(const Extent** out) {
23     ZX_DEBUG_ASSERT(!Done());
24     zx_status_t status = ValidateExtentCount();
25     if (status != ZX_OK) {
26         return status;
27     }
28 
29     const Extent* extent = GetExtent();
30     UpdateIndices(*extent);
31     if (!Done() && local_index_ == (IsInode() ? kInlineMaxExtents : extent_node_->extent_count)) {
32         zx_status_t status = NextContainer();
33         if (status != ZX_OK) {
34             return status;
35         }
36     }
37 
38     *out = extent;
39     return ZX_OK;
40 }
41 
BlockIndex() const42 uint64_t AllocatedExtentIterator::BlockIndex() const {
43     return block_index_;
44 }
45 
ExtentIndex() const46 uint32_t AllocatedExtentIterator::ExtentIndex() const {
47     return extent_index_;
48 }
49 
NodeIndex() const50 uint32_t AllocatedExtentIterator::NodeIndex() const {
51     ZX_DEBUG_ASSERT(!Done());
52     return node_index_;
53 }
54 
IsInode() const55 bool AllocatedExtentIterator::IsInode() const {
56     return extent_node_ == nullptr;
57 }
58 
ValidateExtentCount() const59 zx_status_t AllocatedExtentIterator::ValidateExtentCount() const {
60     ZX_DEBUG_ASSERT(local_index_ < (IsInode() ? kInlineMaxExtents : kContainerMaxExtents));
61     if (!IsInode() && local_index_ > extent_node_->extent_count) {
62         // This container doesn't recognize this extent as valid.
63         return ZX_ERR_IO_DATA_INTEGRITY;
64     }
65     return ZX_OK;
66 }
67 
UpdateIndices(const Extent & extent)68 void AllocatedExtentIterator::UpdateIndices(const Extent& extent) {
69     block_index_ += extent.Length();
70     local_index_++;
71     extent_index_++;
72 }
73 
GetExtent() const74 const Extent* AllocatedExtentIterator::GetExtent() const {
75     if (IsInode()) {
76         return &inode_->extents[local_index_];
77     } else {
78         return &extent_node_->extents[local_index_];
79     }
80 }
81 
GetNextNode() const82 uint32_t AllocatedExtentIterator::GetNextNode() const {
83     if (IsInode()) {
84         return inode_->header.next_node;
85     } else {
86         return extent_node_->header.next_node;
87     }
88 }
89 
NextContainer()90 zx_status_t AllocatedExtentIterator::NextContainer() {
91     ZX_DEBUG_ASSERT(!Done());
92     uint32_t node_index = GetNextNode();
93 
94     local_index_ = 0;
95     extent_node_ = finder_->GetNode(node_index)->AsExtentContainer();
96     node_index_ = node_index;
97 
98     ZX_DEBUG_ASSERT(extent_node_ != nullptr);
99     bool is_container = extent_node_->header.IsAllocated() &&
100                         extent_node_->header.IsExtentContainer();
101     if (!is_container) {
102         return ZX_ERR_IO_DATA_INTEGRITY;
103     }
104     return ZX_OK;
105 }
106 
107 } // namespace blobfs
108