diff --git a/btrfs/Cargo.toml b/btrfs/Cargo.toml index 41cb102..e0f7550 100644 --- a/btrfs/Cargo.toml +++ b/btrfs/Cargo.toml @@ -21,6 +21,7 @@ zerocopy = "0.6.1" crc = "3.0.1" thiserror = { version = "1.0", package = "thiserror-core", default-features = false } num_enum = {version = "0.5.11", default-features = false} +replace_with = "0.1.7" [dev-dependencies] env_logger = "*" diff --git a/btrfs/src/v2/tree.rs b/btrfs/src/v2/tree.rs index 285c8bb..ff25d1c 100644 --- a/btrfs/src/v2/tree.rs +++ b/btrfs/src/v2/tree.rs @@ -60,10 +60,12 @@ type BoxedNode = Rc; #[derive(Debug, Clone, PartialEq, Eq)] pub struct NodeHandle { + parents: Vec<(BoxedNode, u32)>, node: BoxedNode, idx: u32, } +#[derive(Debug)] pub struct Range { volume: Rc>, parents: Vec, @@ -271,6 +273,65 @@ impl RootOrEdge { .clone() } + pub fn into_next_leaf_any( + self, + volume: &super::volume::Volume, + f: F, + ) -> core::result::Result + where + F: Fn( + NodeHandle, + &super::volume::Volume, + ) -> core::result::Result, + R: super::Read, + { + let mut node = match self { + RootOrEdge::Root(root) => { + // use self if is leaf already, otherwise forward to next leaf + if root.node.inner.is_leaf() { + return Ok(Self::Edge(root)); + } else { + root + } + } + RootOrEdge::Edge(edge) => edge, + }; + + let leaf = loop { + match f(node, volume) { + Ok(next) => { + if next.node.inner.is_leaf() { + break Ok(next); + } else { + node = next; + } + } + Err(last) => { + break Err(Self::Edge(last)); + } + } + }; + + // turn leaf into Self::Edge + leaf.map(|leaf| Self::Edge(leaf)) + } + + /// returns the next RootOrEdge, or the end of the tree as Err + pub fn into_next_leaf( + self, + volume: &super::volume::Volume, + ) -> core::result::Result { + self.into_next_leaf_any(volume, NodeHandle::into_next) + } + + /// returns the next RootOrEdge, or the end of the tree as Err, in reverse direction + pub fn into_next_back_leaf( + self, + volume: &super::volume::Volume, + ) -> core::result::Result { + self.into_next_leaf_any(volume, NodeHandle::into_next_back) + } + pub fn as_handle(&self) -> &NodeHandle { match self { RootOrEdge::Root(handle) => handle, @@ -320,6 +381,7 @@ impl Node { } } + // TODO: move this to nodehandle pub fn find_key + PartialOrd>(self: &Rc, key: &K) -> SearchResult { match &self.inner { BTreeNode::Internal(node) => { @@ -327,12 +389,14 @@ impl Node { match key.partial_cmp(&child.key) { Some(core::cmp::Ordering::Less) => { return SearchResult::Edge(NodeHandle { + parents: Default::default(), node: self.clone(), idx: if i == 0 { 0 } else { i as u32 - 1 }, }); } Some(core::cmp::Ordering::Equal) | None => { return SearchResult::Edge(NodeHandle { + parents: Default::default(), node: self.clone(), idx: i as u32, }); @@ -342,6 +406,7 @@ impl Node { } SearchResult::Edge(NodeHandle { + parents: Default::default(), node: self.clone(), idx: node.children.len() as u32 - 1, }) @@ -356,6 +421,7 @@ impl Node { // } else if key.eq(&child.key) { return SearchResult::Leaf(NodeHandle { + parents: Default::default(), node: self.clone(), idx: i as u32, }); @@ -364,6 +430,7 @@ impl Node { log::debug!("key definitely not found!"); SearchResult::Edge(NodeHandle { + parents: Default::default(), node: self.clone(), idx: node.items.len() as u32 - 1, }) @@ -484,29 +551,53 @@ where type Item = (Item, TreeItem); fn next(&mut self) -> Option { - let handle = match &self.start { - RootOrEdge::Root(_) => { - self.init_start().expect("error"); - match &self.start.node.inner { - BTreeNode::Internal(_) => None, - BTreeNode::Leaf(_) => Some(self.start.into_handle()), + if !self.is_empty() { + replace_with::replace_with_or_abort(&mut self.start, |start| { + match start.into_next_leaf(&self.volume) { + Ok(next) => next, + Err(next) => next, } - } - RootOrEdge::Edge(_) => self - .advance() - .expect("cant advance range") - .map(|_| self.start.into_handle()), - }; + }); - handle - .map(|handle| handle.parse_item())? - .expect("failed to parse item") + let item = self.start.as_handle().parse_item().expect("range item"); + + item + } else { + None + } + } +} + +impl DoubleEndedIterator for Range +where + R: super::Read, +{ + fn next_back(&mut self) -> Option { + if !self.is_empty() { + replace_with::replace_with_or_abort(&mut self.end, |end| { + match end.into_next_back_leaf(&self.volume) { + Ok(next) => next, + Err(next) => next, + } + }); + + let item = self.start.as_handle().parse_item().expect("range item"); + + item + } else { + None + } } } impl NodeHandle { pub fn start(node: BoxedNode) -> Self { - Self { node, idx: 0 } + let parents = Vec::with_capacity(node.inner.header().level as usize); + Self { + node, + parents, + idx: 0, + } } pub fn parse_item(&self) -> Result> { @@ -528,6 +619,123 @@ impl NodeHandle { } } + // needs reference to volume to be able to read children key_ptrs + // this is a live reference so if in the future I want to have a &mut to something in Volume + // greppable: volume ref + pub fn into_next_back( + self, + volume: &super::volume::Volume, + ) -> core::result::Result { + let Self { + mut parents, + node, + idx, + } = self; + + if idx < 1 { + // go up + match parents.pop() { + Some((node, idx)) => Self { node, idx, parents }.into_next_back(volume), + None => Err(Self { node, idx, parents }), + } + } else { + match &node.inner { + BTreeNode::Internal(internal) => { + let child_ptr = *internal + .children + .get(idx as usize) + .expect("no children in node"); + let node = match volume + .read_keyptr(&child_ptr) + .and_then(|bytes| Node::from_bytes(bytes)) + .map(|node| Rc::new(node)) + { + Ok(child) => { + parents.push((node, idx)); + Ok(Self { + parents, + idx: child.inner.header().nritems.get() - 1, + node: child, + }) + } + Err(_) => Err(Self { parents, node, idx }), + }; + + // TODO: better error or panic here? this would return self, indicating the end of the tree, even though we simply failed to retrieve the next node + node + } + + BTreeNode::Leaf(_) => Ok(Self { + idx: idx - 1, + parents, + node, + }), + } + } + } + + // needs reference to volume to be able to read children key_ptrs + // this is a live reference so if in the future I want to have a &mut to something in Volume + // greppable: volume ref + /// returns Ok(next) or Err(self) if self is already the last node + pub fn into_next( + self, + volume: &super::volume::Volume, + ) -> core::result::Result { + let Self { + mut parents, + node, + idx, + } = self; + + let header = node.inner.header(); + + if idx + 1 >= header.nritems.get() { + // go up + match parents.pop() { + Some((node, idx)) => Self { + node, + idx: idx + 1, + parents, + } + .into_next(volume), + None => Err(Self { node, idx, parents }), + } + } else { + match &node.inner { + BTreeNode::Internal(internal) => { + let child_ptr = *internal + .children + .get(idx as usize) + .expect("no children in node"); + let node = match volume + .read_keyptr(&child_ptr) + .and_then(|bytes| Node::from_bytes(bytes)) + .map(|node| Rc::new(node)) + { + Ok(child) => { + parents.push((node, idx)); + Ok(Self { + parents, + idx: 0, + node: child, + }) + } + Err(_) => Err(Self { parents, node, idx }), + }; + + // TODO: better error or panic here? this would return self, indicating the end of the tree, even though we simply failed to retrieve the next node + node + } + BTreeNode::Leaf(_) => Ok(Self { + idx: idx + 1, + parents, + node, + }), + } + } + } + // returns the next node in ascending sequential order pub fn advance_down(self) -> NodeHandleAdvanceResult { let header = self.node.inner.header(); @@ -548,7 +756,9 @@ impl NodeHandle { } pub fn end(node: BoxedNode) -> Self { + let parents = Vec::with_capacity(node.inner.header().level as usize); Self { + parents, idx: node.inner.header().nritems.get() - 1, node, } diff --git a/btrfs/src/v2/volume.rs b/btrfs/src/v2/volume.rs index a826892..33183b6 100644 --- a/btrfs/src/v2/volume.rs +++ b/btrfs/src/v2/volume.rs @@ -117,6 +117,7 @@ impl Volume { } fn parse_chunk_tree(mut self) -> Result { + log::debug!("parsing chunk tree"); let this = Rc::new(self); let chunk_tree = @@ -124,9 +125,12 @@ impl Volume { let chunks = chunk_tree .iter() - .filter_map(|(item, v)| match v { - TreeItem::Chunk(chunk) => Some((item, chunk)), - _ => None, + .filter_map(|(item, v)| { + log::debug!("{:?}", item); + match v { + TreeItem::Chunk(chunk) => Some((item, chunk)), + _ => None, + } }) .collect::>(); @@ -366,6 +370,7 @@ mod tests { let vol = Volume::new(file).expect("volume"); let v2 = vol.into_volume2().expect("volume2"); + log::info!("roots:"); for (id, v) in v2.roots.iter() { log::info!("[{id:?}] {v:#?}"); } @@ -378,8 +383,12 @@ mod tests { let v2 = vol.into_volume2().expect("volume2"); let fs = v2.default_subvolume().expect("default subvol"); - for (id, entry) in fs.fs_root.iter() { - log::info!("[{id:?}] {entry:#?}"); + log::info!("fs_root:"); + for (_id, entry) in fs.fs_root.iter() { + if let Some(dir) = entry.as_dir_index() { + log::info!("{}", dir.name_as_string_lossy()); + } + // log::info!("[{id:?}] {entry:#?}"); } } }