From de79b77940dde723c81e2e2f94c78eeffeeb03ad Mon Sep 17 00:00:00 2001 From: Janis Date: Mon, 3 Apr 2023 17:01:56 +0200 Subject: [PATCH] getting files by relative path to other inode --- btrfs/src/v2/volume.rs | 178 +++++++++++++++++++++-------------------- 1 file changed, 93 insertions(+), 85 deletions(-) diff --git a/btrfs/src/v2/volume.rs b/btrfs/src/v2/volume.rs index d69fdba..95f8334 100644 --- a/btrfs/src/v2/volume.rs +++ b/btrfs/src/v2/volume.rs @@ -387,6 +387,56 @@ impl Fs { Ok(children) } + pub fn get_inode_parent(&self, inode: &INode) -> Result { + 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

(&self, inode: INode, path: P) -> Result + 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

(&self, path: P) -> Result where P: Path, @@ -446,7 +496,7 @@ impl Fs { } } - fn get_inode_extents(&self, inode_id: u64) -> Result>> { + fn get_inode_extents(&self, inode_id: u64) -> Result>> { 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 Fs { 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::>(); 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, (, 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()); } }