src/pxar/fuse.rs: add impl Context
This commit is contained in:
parent
eedd1f95eb
commit
2f2b87e659
139
src/pxar/fuse.rs
139
src/pxar/fuse.rs
|
@ -90,6 +90,73 @@ struct Context {
|
|||
ino_offset: Offset,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// Update the goodbye table to the one corresponding to the i-node offset, both
|
||||
/// given in the `Context`.
|
||||
fn update_goodbye_cache(&mut self) -> Result<(), i32> {
|
||||
if let Some((off, _)) = self.goodbye_cache {
|
||||
if off == self.ino_offset {
|
||||
// Cache contains already the correct goodbye table
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
// Inode did not match or cache is empty, need to update the cache
|
||||
let gbt = self.decoder
|
||||
.goodbye_table(None, self.ino_offset + GOODBYE_ITEM_SIZE)
|
||||
.map_err(|_| libc::EIO)?;
|
||||
self.goodbye_cache = Some((self.ino_offset, gbt));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Lookup the goodbye item identified by `filename` and its corresponding `hash`
|
||||
///
|
||||
/// Updates the goodbye table cache to contain the table for the directory given
|
||||
/// by the i-node in the provided `Context`.
|
||||
/// Search the first matching `hash` in the goodbye table, allowing for a fast
|
||||
/// comparison with the items.
|
||||
/// As there could be a hash collision, the found items filename is then compared
|
||||
/// by seek to the corresponding item in the archive and reading its attributes
|
||||
/// (which the lookup callback needs to do anyway).
|
||||
/// If the filename does not match, the function is called recursively with the
|
||||
/// rest of the goodbye table to lookup the next match.
|
||||
/// The matching items archive offset, entry and payload size are returned.
|
||||
/// If there is no entry with matching `filename` and `hash` a `libc::ENOENT` is
|
||||
/// returned.
|
||||
fn find_goodbye_entry(
|
||||
&mut self,
|
||||
filename: &CStr,
|
||||
hash: u64,
|
||||
) -> Result<(u64, PxarEntry, PxarAttributes, u64), i32> {
|
||||
self.update_goodbye_cache()?;
|
||||
if let Some((_, gbt)) = &self.goodbye_cache {
|
||||
let mut iterator = gbt.iter();
|
||||
loop {
|
||||
// Search for the next goodbye entry with matching hash.
|
||||
let (_item, start, end) = iterator.find(|(i, _, _)| i.hash == hash)
|
||||
.ok_or(libc::ENOENT)?;
|
||||
|
||||
// At this point it is not clear if the item is a directory or not, this
|
||||
// has to be decided based on the entry mode.
|
||||
// `Decoder`s attributes function accepts both, offsets pointing to
|
||||
// the start of an item (PXAR_FILENAME) or the GOODBYE_TAIL_MARKER in case
|
||||
// of directories, so the use of start offset is fine for both cases.
|
||||
let (entry_name, entry, attr, payload_size) =
|
||||
self.decoder.attributes(*start).map_err(|_| libc::EIO)?;
|
||||
|
||||
// Possible hash collision, need to check if the found entry is indeed
|
||||
// the filename to lookup.
|
||||
if entry_name.as_bytes() == filename.to_bytes() {
|
||||
let child_offset = find_offset(&entry, *start, *end);
|
||||
return Ok((child_offset, entry, attr, payload_size));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(libc::ENOENT)
|
||||
}
|
||||
}
|
||||
|
||||
/// `Session` stores a pointer to the session context and is used to mount the
|
||||
/// archive to the given mountpoint.
|
||||
pub struct Session {
|
||||
|
@ -352,7 +419,7 @@ impl Session {
|
|||
Self::run_in_context(req, parent, |mut ctx| {
|
||||
// find_ goodbye_entry() will also update the goodbye cache
|
||||
let (child_offset, entry, attr, payload_size) =
|
||||
find_goodbye_entry(&mut ctx, &filename, hash)?;
|
||||
ctx.find_goodbye_entry(&filename, hash)?;
|
||||
ctx.attr_cache = Some((child_offset, attr));
|
||||
let child_inode = calculate_inode(child_offset, ctx.decoder.root_end_offset());
|
||||
|
||||
|
@ -463,8 +530,8 @@ impl Session {
|
|||
extern "C" fn readdir(req: Request, inode: u64, size: size_t, offset: c_int, _fileinfo: MutPtr) {
|
||||
let offset = offset as usize;
|
||||
|
||||
Self::run_in_context(req, inode, |mut ctx| {
|
||||
update_goodbye_cache(&mut ctx)?;
|
||||
Self::run_in_context(req, inode, |ctx| {
|
||||
ctx.update_goodbye_cache()?;
|
||||
let gb_table = &ctx.goodbye_cache.as_ref().unwrap().1;
|
||||
let n_entries = gb_table.len();
|
||||
let mut buf = ReplyBuf::new(req, size, offset);
|
||||
|
@ -574,72 +641,6 @@ struct EntryParam {
|
|||
entry_timeout: f64,
|
||||
}
|
||||
|
||||
/// Update the goodbye table to the one corresponding to the i-node offset, both
|
||||
/// given in the `Context`.
|
||||
fn update_goodbye_cache(mut ctx: &mut Context) -> Result<(), i32> {
|
||||
if let Some((off, _)) = &ctx.goodbye_cache {
|
||||
if *off == ctx.ino_offset {
|
||||
// Cache contains already the correct goodbye table
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
// Inode did not match or cache is empty, need to update the cache
|
||||
let gbt = ctx.decoder
|
||||
.goodbye_table(None, ctx.ino_offset + GOODBYE_ITEM_SIZE)
|
||||
.map_err(|_| libc::EIO)?;
|
||||
ctx.goodbye_cache = Some((ctx.ino_offset, gbt));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Lookup the goodbye item identified by `filename` and its corresponding `hash`
|
||||
///
|
||||
/// Updates the goodbye table cache to contain the table for the directory given
|
||||
/// by the i-node in the provided `Context`.
|
||||
/// Search the first matching `hash` in the goodbye table, allowing for a fast
|
||||
/// comparison with the items.
|
||||
/// As there could be a hash collision, the found items filename is then compared
|
||||
/// by seek to the corresponding item in the archive and reading its attributes
|
||||
/// (which the lookup callback needs to do anyway).
|
||||
/// If the filename does not match, the function is called recursively with the
|
||||
/// rest of the goodbye table to lookup the next match.
|
||||
/// The matching items archive offset, entry and payload size are returned.
|
||||
/// If there is no entry with matching `filename` and `hash` a `libc::ENOENT` is
|
||||
/// returned.
|
||||
fn find_goodbye_entry(
|
||||
mut ctx: &mut Context,
|
||||
filename: &CStr,
|
||||
hash: u64,
|
||||
) -> Result<(u64, PxarEntry, PxarAttributes, u64), i32> {
|
||||
update_goodbye_cache(&mut ctx)?;
|
||||
if let Some((_, gbt)) = &ctx.goodbye_cache {
|
||||
let mut iterator = gbt.iter();
|
||||
loop {
|
||||
// Search for the next goodbye entry with matching hash.
|
||||
let (_item, start, end) = iterator.find(|(i, _, _)| i.hash == hash)
|
||||
.ok_or(libc::ENOENT)?;
|
||||
|
||||
// At this point it is not clear if the item is a directory or not, this
|
||||
// has to be decided based on the entry mode.
|
||||
// `Decoder`s attributes function accepts both, offsets pointing to
|
||||
// the start of an item (PXAR_FILENAME) or the GOODBYE_TAIL_MARKER in case
|
||||
// of directories, so the use of start offset is fine for both cases.
|
||||
let (entry_name, entry, attr, payload_size) =
|
||||
ctx.decoder.attributes(*start).map_err(|_| libc::EIO)?;
|
||||
|
||||
// Possible hash collision, need to check if the found entry is indeed
|
||||
// the filename to lookup.
|
||||
if entry_name.as_bytes() == filename.to_bytes() {
|
||||
let child_offset = find_offset(&entry, *start, *end);
|
||||
return Ok((child_offset, entry, attr, payload_size));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(libc::ENOENT)
|
||||
}
|
||||
|
||||
|
||||
/// Create a `libc::stat` with the provided i-node, entry and payload size
|
||||
fn stat(inode: u64, entry: &PxarEntry, payload_size: u64) -> Result<libc::stat, i32> {
|
||||
let nlink = match (entry.mode as u32) & libc::S_IFMT {
|
||||
|
|
Loading…
Reference in New Issue