getting files by relative path to other inode
This commit is contained in:
parent
578861c4fa
commit
de79b77940
|
@ -387,6 +387,56 @@ impl<R: super::Read> Fs<R> {
|
||||||
Ok(children)
|
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>
|
pub fn get_inode_by_path<P>(&self, path: P) -> Result<INode>
|
||||||
where
|
where
|
||||||
P: Path,
|
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 let Some(dir_entry) = self.get_inode_dir_index(inode_id)? {
|
||||||
if dir_entry.item().ty() == DirItemType::RegFile {
|
if dir_entry.item().ty() == DirItemType::RegFile {
|
||||||
let key =
|
let key =
|
||||||
|
@ -455,7 +505,12 @@ impl<R: super::Read> Fs<R> {
|
||||||
let extents = self.fs_root.find_range(&key)?;
|
let extents = self.fs_root.find_range(&key)?;
|
||||||
|
|
||||||
let extents = extents
|
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<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
return Ok(Some(extents));
|
return Ok(Some(extents));
|
||||||
|
@ -589,80 +644,7 @@ mod tests {
|
||||||
let vol = Volume::new(file).expect("volume");
|
let vol = Volume::new(file).expect("volume");
|
||||||
let v2 = vol.into_volume2().expect("volume2");
|
let v2 = vol.into_volume2().expect("volume2");
|
||||||
|
|
||||||
let root_tree =
|
let fs = v2.default_subvolume().expect("subvol");
|
||||||
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]");
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -693,7 +675,7 @@ mod tests {
|
||||||
let extents = fs.get_inode_extents(inode_id)?;
|
let extents = fs.get_inode_extents(inode_id)?;
|
||||||
|
|
||||||
if let Some(extents) = extents {
|
if let Some(extents) = extents {
|
||||||
for extent in extents {
|
for (_, extent) in extents {
|
||||||
match extent {
|
match extent {
|
||||||
ExtentData::Inline { header, data } => {
|
ExtentData::Inline { header, data } => {
|
||||||
log::info!("{header:?}\n{}", String::from_utf8_lossy(&data));
|
log::info!("{header:?}\n{}", String::from_utf8_lossy(&data));
|
||||||
|
@ -723,11 +705,14 @@ mod tests {
|
||||||
let children = fs.get_inode_children(&home)?;
|
let children = fs.get_inode_children(&home)?;
|
||||||
log::info!("chidlren: {:?}", children);
|
log::info!("chidlren: {:?}", children);
|
||||||
|
|
||||||
let home = fs.get_inode_by_path(b"/home/user/hii.txt")?;
|
let hii = fs.get_inode_by_path(b"/home/user/hii.txt")?;
|
||||||
let extents = fs.get_inode_extents(home.id)?;
|
|
||||||
|
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 {
|
if let Some(extents) = extents {
|
||||||
for extent in extents {
|
for (_offset, extent) in extents {
|
||||||
match extent {
|
match extent {
|
||||||
ExtentData::Inline { header, data } => {
|
ExtentData::Inline { header, data } => {
|
||||||
log::info!("{header:?}\n{}", String::from_utf8_lossy(&data));
|
log::info!("{header:?}\n{}", String::from_utf8_lossy(&data));
|
||||||
|
@ -745,12 +730,25 @@ mod tests {
|
||||||
let extents = fs.get_inode_extents(home.id)?;
|
let extents = fs.get_inode_extents(home.id)?;
|
||||||
|
|
||||||
if let Some(extents) = extents {
|
if let Some(extents) = extents {
|
||||||
for extent in extents {
|
for (offset, extent) in extents {
|
||||||
|
log::info!("extent {:x}..", offset);
|
||||||
match extent {
|
match extent {
|
||||||
ExtentData::Inline { header, data } => {
|
ExtentData::Inline { header, data } => {
|
||||||
log::info!("{header:?}\n{}", String::from_utf8_lossy(&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 v2 = vol.into_volume2().expect("volume2");
|
||||||
let fs = v2.default_subvolume().expect("default subvol");
|
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() {
|
for (_id, entry) in fs.fs_root.iter() {
|
||||||
if let Some(dir) = entry.as_dir_index() {
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue