use alloc::vec::Vec;
use crate::{
block_read::BlockRead,
btree::find_first_ge,
chunk_tree::ChunkMap,
error::{Error, Result},
format::{
constants::DIR_INDEX_KEY,
repr::{DirEntry as DiskDirEntry, DiskKey},
},
};
#[derive(Debug, Clone)]
pub struct DirEntry {
pub name: Vec<u8>,
pub inode_number: u64,
pub kind_byte: u8,
}
pub(crate) fn read_dir<R: BlockRead>(
reader: &mut R,
chunk_map: &ChunkMap,
nodesize: u32,
fs_tree_root: u64,
parent_inode: u64,
) -> Result<Vec<DirEntry>> {
let mut out = Vec::new();
let mut next_target = DiskKey {
objectid: parent_inode,
item_type: DIR_INDEX_KEY,
offset: 0,
};
loop {
let location = find_first_ge(reader, chunk_map, nodesize, fs_tree_root, &next_target)?;
let Some((leaf, mut idx)) = location else {
break;
};
let nritems = leaf.header.nritems;
let mut last_seen: Option<DiskKey> = None;
while idx < nritems {
let item = leaf.leaf_item(idx)?;
if item.key.objectid != parent_inode || item.key.item_type != DIR_INDEX_KEY {
return Ok(out);
}
let data = leaf.leaf_item_data(item)?;
let (entry, _) = DiskDirEntry::parse(data, 0).ok_or(Error::CorruptBtree {
token: "dir_index_short",
logical: leaf.header.bytenr,
})?;
out.push(DirEntry {
name: entry.name.to_vec(),
inode_number: entry.location.objectid,
kind_byte: entry.ty,
});
last_seen = Some(item.key);
idx += 1;
}
let Some(last) = last_seen else { break };
next_target = match last.offset.checked_add(1) {
Some(o) => DiskKey {
objectid: last.objectid,
item_type: last.item_type,
offset: o,
},
None => break,
};
}
Ok(out)
}