getting files by relative path to other inode

This commit is contained in:
Janis 2023-04-03 17:01:56 +02:00
parent 578861c4fa
commit de79b77940

View file

@ -387,6 +387,56 @@ impl<R: super::Read> Fs<R> {
Ok(children)
}
pub fn get_inode_parent(&self, inode: &INode) -> Result<INode> {
if let Some((inode_ref, _)) = self.find_inode_ref(inode.id)? {
Ok(INode {
id: inode_ref.key.offset.get(),
path: inode
.path
.iter()
.take(inode.path.len() - 1)
.cloned()
.collect(),
})
} else {
Err(Error::INodeNotFound)
}
}
pub fn get_inode_by_relative_path<P>(&self, inode: INode, path: P) -> Result<INode>
where
P: Path,
{
if path.is_absolute() {
// stuff
self.get_inode_by_path(path)
} else {
let path = path.normalize().into_iter();
let mut inode = inode;
for segment in path {
match segment {
crate::path::Segment::ParentDir => {
inode = self.get_inode_parent(&inode)?;
}
crate::path::Segment::File(child_name) => {
inode = self
.get_inode_children(&inode)?
.iter()
.find(|child| {
child.path.last().map(|bytes| bytes.as_slice()) == Some(child_name)
})
.ok_or(Error::INodeNotFound)?
.clone()
}
_ => unreachable!(),
}
}
Ok(inode)
}
}
pub fn get_inode_by_path<P>(&self, path: P) -> Result<INode>
where
P: Path,
@ -446,7 +496,7 @@ impl<R: super::Read> Fs<R> {
}
}
fn get_inode_extents(&self, inode_id: u64) -> Result<Option<Vec<ExtentData>>> {
fn get_inode_extents(&self, inode_id: u64) -> Result<Option<Vec<(u64, ExtentData)>>> {
if let Some(dir_entry) = self.get_inode_dir_index(inode_id)? {
if dir_entry.item().ty() == DirItemType::RegFile {
let key =
@ -455,7 +505,12 @@ impl<R: super::Read> Fs<R> {
let extents = self.fs_root.find_range(&key)?;
let extents = extents
.map(|(_, item)| item.as_extent_data().expect("extent data").clone())
.map(|(key, item)| {
(
key.key.offset.get(),
item.as_extent_data().expect("extent data").clone(),
)
})
.collect::<Vec<_>>();
return Ok(Some(extents));
@ -589,80 +644,7 @@ mod tests {
let vol = Volume::new(file).expect("volume");
let v2 = vol.into_volume2().expect("volume2");
let root_tree =
Tree::from_logical_offset(v2.inner.clone(), v2.inner.superblock().root.get())?;
// we are looking for the root tree directory (?)
// this is a DIR_ITEM entry in the root tree, with the name "default",
// and the crc32 of "default" as its offset
let key = Key::new(
KnownObjectId::Custom(v2.inner.superblock().root_dir_objectid.get()),
ObjectType::DirItem,
0x8dbfc2d2, // crc of "default"
);
let subvol_root = root_tree
.find_key(&key)?
.ok_or(Error::NoDefaultSubvolRoot)?;
// if we found the dir entry of the "default subvol" (mharmstone nomenclature)
// we then look for the root fs tree in the root tree with the ID found
// in the `.location` of the dir_item only (from mharmstone)
let subvol_id = subvol_root
.1
.as_dir_item()
.expect("dir item")
.first()
.expect("dir item entry")
.item()
.location
.id();
log::info!("subvol_id: {subvol_id:?}");
let search_key = PartialKey::new(Some(subvol_id), None, None);
for (key, v) in root_tree.iter() {
if search_key.eq(&key.key) {
log::info!("[{key:?}] {v:#?}");
}
}
let fs = v2.default_subvolume().expect("default subvol");
// so we go from root_item.dirid as inode number
// to (dir_id, dir_index, ?) which is all the files in the directory
// generally, (<inode_number>, dir_index, idx) will give us all indices in the directory
// walking the entire tree for this seems quite slow though...
// so we would want a function here that can find a range and a way to
// define a range with a partial key.
// that would look something like limiting the range to everything equal
// to the id or type, if present, in that order. ofc if the id is
// missing, the range cannot be restricted at all.
let search_key = PartialKey::new(
Some(fs.root_item.root_dirid.get().into()),
Some(ObjectType::DirIndex),
None,
);
log::info!("iter:");
for (key, v) in fs.fs_root.iter() {
if search_key.eq(&key.key) {
log::info!("[{key:?}] {v:#?}");
}
}
log::info!("iter: [end]");
// with range
log::info!("range:");
for (key, v) in fs.fs_root.find_range(&search_key)? {
log::info!("[{key:?}] {v:#?}");
}
log::info!("range: [end]");
let fs = v2.default_subvolume().expect("subvol");
Ok(())
}
@ -693,7 +675,7 @@ mod tests {
let extents = fs.get_inode_extents(inode_id)?;
if let Some(extents) = extents {
for extent in extents {
for (_, extent) in extents {
match extent {
ExtentData::Inline { header, data } => {
log::info!("{header:?}\n{}", String::from_utf8_lossy(&data));
@ -723,11 +705,14 @@ mod tests {
let children = fs.get_inode_children(&home)?;
log::info!("chidlren: {:?}", children);
let home = fs.get_inode_by_path(b"/home/user/hii.txt")?;
let extents = fs.get_inode_extents(home.id)?;
let hii = fs.get_inode_by_path(b"/home/user/hii.txt")?;
let hii2 = fs.get_inode_by_relative_path(home, b"./hii.txt")?;
let extents = fs.get_inode_extents(hii.id)?;
assert_eq!(hii, hii2);
if let Some(extents) = extents {
for extent in extents {
for (_offset, extent) in extents {
match extent {
ExtentData::Inline { header, data } => {
log::info!("{header:?}\n{}", String::from_utf8_lossy(&data));
@ -745,12 +730,25 @@ mod tests {
let extents = fs.get_inode_extents(home.id)?;
if let Some(extents) = extents {
for extent in extents {
for (offset, extent) in extents {
log::info!("extent {:x}..", offset);
match extent {
ExtentData::Inline { header, data } => {
log::info!("{header:?}\n{}", String::from_utf8_lossy(&data));
}
_ => {}
ExtentData::Other(extent) => {
let address = extent.address() + extent.offset();
let data = fs
.volume
.inner
.read_range(address..address + extent.num_bytes())
.expect("bytes");
log::info!(
"{:?}\n{}",
extent.extent_data1(),
String::from_utf8_lossy(&data)
);
}
}
}
}
@ -765,12 +763,22 @@ mod tests {
let v2 = vol.into_volume2().expect("volume2");
let fs = v2.default_subvolume().expect("default subvol");
log::info!("fs_root:");
log::info!("files 1:");
let now = std::time::Instant::now();
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!("{}", dir.name_as_string_lossy());
}
// log::info!("[{id:?}] {entry:#?}");
}
log::info!("files 1: [took {}ms]", now.elapsed().as_millis());
log::info!("files 2:");
let now = std::time::Instant::now();
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!("files 2: [took {}ms]", now.elapsed().as_millis());
}
}