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,
|
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
|
/// `Session` stores a pointer to the session context and is used to mount the
|
||||||
/// archive to the given mountpoint.
|
/// archive to the given mountpoint.
|
||||||
pub struct Session {
|
pub struct Session {
|
||||||
|
@ -352,7 +419,7 @@ impl Session {
|
||||||
Self::run_in_context(req, parent, |mut ctx| {
|
Self::run_in_context(req, parent, |mut ctx| {
|
||||||
// find_ goodbye_entry() will also update the goodbye cache
|
// find_ goodbye_entry() will also update the goodbye cache
|
||||||
let (child_offset, entry, attr, payload_size) =
|
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));
|
ctx.attr_cache = Some((child_offset, attr));
|
||||||
let child_inode = calculate_inode(child_offset, ctx.decoder.root_end_offset());
|
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) {
|
extern "C" fn readdir(req: Request, inode: u64, size: size_t, offset: c_int, _fileinfo: MutPtr) {
|
||||||
let offset = offset as usize;
|
let offset = offset as usize;
|
||||||
|
|
||||||
Self::run_in_context(req, inode, |mut ctx| {
|
Self::run_in_context(req, inode, |ctx| {
|
||||||
update_goodbye_cache(&mut ctx)?;
|
ctx.update_goodbye_cache()?;
|
||||||
let gb_table = &ctx.goodbye_cache.as_ref().unwrap().1;
|
let gb_table = &ctx.goodbye_cache.as_ref().unwrap().1;
|
||||||
let n_entries = gb_table.len();
|
let n_entries = gb_table.len();
|
||||||
let mut buf = ReplyBuf::new(req, size, offset);
|
let mut buf = ReplyBuf::new(req, size, offset);
|
||||||
|
@ -574,72 +641,6 @@ struct EntryParam {
|
||||||
entry_timeout: f64,
|
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
|
/// 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> {
|
fn stat(inode: u64, entry: &PxarEntry, payload_size: u64) -> Result<libc::stat, i32> {
|
||||||
let nlink = match (entry.mode as u32) & libc::S_IFMT {
|
let nlink = match (entry.mode as u32) & libc::S_IFMT {
|
||||||
|
|
Loading…
Reference in New Issue