pxar: Refactor fuse and remove unused code.
By ambiguously using the Decoder::read_directory_entry() the code is simplified and reading of the DirectoryEntry is concentrated into Context::run_in_context(). Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
This commit is contained in:
		
				
					committed by
					
						
						Dietmar Maurer
					
				
			
			
				
	
			
			
			
						parent
						
							95c9460c4a
						
					
				
				
					commit
					2bbbade367
				
			@ -327,65 +327,6 @@ impl Decoder {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get attributes for the archive item located at `offset`.
 | 
			
		||||
    ///
 | 
			
		||||
    /// Returns the entry, attributes and the payload size for the item.
 | 
			
		||||
    /// For regular archive itmes a `PXAR_FILENAME` or a `PXAR_ENTRY` header is
 | 
			
		||||
    /// expected at `offset`.
 | 
			
		||||
    /// For directories, `offset` might also (but not necessarily) point at the
 | 
			
		||||
    /// directories `PXAR_GOODBYE_TAIL_MARKER`. This is not mandatory and it can
 | 
			
		||||
    /// also directly point to its `PXAR_FILENAME` or `PXAR_ENTRY`, thereby
 | 
			
		||||
    /// avoiding an additional seek.
 | 
			
		||||
    pub fn attributes(&mut self, offset: u64) -> Result<(OsString, PxarEntry, PxarAttributes, u64), Error> {
 | 
			
		||||
        self.seek(SeekFrom::Start(offset))?;
 | 
			
		||||
 | 
			
		||||
        let mut marker: u64 = self.inner.read_item()?;
 | 
			
		||||
        if marker == PXAR_GOODBYE_TAIL_MARKER {
 | 
			
		||||
            let dir_offset: u64 = self.inner.read_item()?;
 | 
			
		||||
            let gb_size: u64 = self.inner.read_item()?;
 | 
			
		||||
            let distance = i64::try_from(dir_offset + gb_size)?;
 | 
			
		||||
            self.seek(SeekFrom::Current(0 - distance))?;
 | 
			
		||||
            marker = self.inner.read_item()?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let filename = if marker == PXAR_FILENAME {
 | 
			
		||||
            let size: u64 = self.inner.read_item()?;
 | 
			
		||||
            let filename = self.inner.read_filename(size)?;
 | 
			
		||||
            marker = self.inner.read_item()?;
 | 
			
		||||
            filename
 | 
			
		||||
        } else {
 | 
			
		||||
            OsString::new()
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if marker == PXAR_FORMAT_HARDLINK {
 | 
			
		||||
            let size: u64 = self.inner.read_item()?;
 | 
			
		||||
            let (_, diff) = self.inner.read_hardlink(size)?;
 | 
			
		||||
            // Make sure to return the original filename,
 | 
			
		||||
            // not the one read from the hardlink.
 | 
			
		||||
            let (_, entry, xattr, file_size) = self.attributes(offset - diff)?;
 | 
			
		||||
            return Ok((filename, entry, xattr, file_size));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if marker != PXAR_ENTRY {
 | 
			
		||||
            bail!("Expected PXAR_ENTRY, found 0x{:x?}", marker);
 | 
			
		||||
        }
 | 
			
		||||
        let _size: u64 = self.inner.read_item()?;
 | 
			
		||||
        let entry: PxarEntry = self.inner.read_item()?;
 | 
			
		||||
        let (header, xattr) = self.inner.read_attributes()?;
 | 
			
		||||
        let file_size = match header.htype {
 | 
			
		||||
            PXAR_PAYLOAD => header.size - HEADER_SIZE,
 | 
			
		||||
            _ => 0,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Ok((filename, entry, xattr, file_size))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Opens the file by validating the given `offset` and returning its attrs,
 | 
			
		||||
    /// xattrs and size.
 | 
			
		||||
    pub fn open(&mut self, offset: u64) -> Result<(OsString, PxarEntry, PxarAttributes, u64), Error> {
 | 
			
		||||
        self.attributes(offset)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Read the payload of the file given by `offset`.
 | 
			
		||||
    ///
 | 
			
		||||
    /// This will read the file by first seeking to `offset` within the archive,
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ use libc::{c_char, c_int, c_void, size_t};
 | 
			
		||||
 | 
			
		||||
use super::binary_search_tree::search_binary_tree_by;
 | 
			
		||||
use super::decoder::{Decoder, DirectoryEntry};
 | 
			
		||||
use super::format_definition::{PxarEntry, PxarGoodbyeItem};
 | 
			
		||||
use super::format_definition::PxarEntry;
 | 
			
		||||
 | 
			
		||||
/// Node ID of the root i-node
 | 
			
		||||
///
 | 
			
		||||
@ -30,8 +30,6 @@ use super::format_definition::{PxarEntry, PxarGoodbyeItem};
 | 
			
		||||
/// required.
 | 
			
		||||
const FUSE_ROOT_ID: u64 = 1;
 | 
			
		||||
 | 
			
		||||
const GOODBYE_ITEM_SIZE: u64 = std::mem::size_of::<PxarGoodbyeItem>() as u64;
 | 
			
		||||
 | 
			
		||||
type Offset = u64;
 | 
			
		||||
/// FFI types for easier readability
 | 
			
		||||
type Request = *mut c_void;
 | 
			
		||||
@ -84,6 +82,8 @@ struct Context {
 | 
			
		||||
    /// DirectoryEntry via the Decoder as well as the parent, in order
 | 
			
		||||
    /// to be able to include the parent directory on readdirplus calls.
 | 
			
		||||
    start_end_parent: HashMap<u64, (u64, u64)>,
 | 
			
		||||
    /// Hold the DirectoryEntry for the current inode
 | 
			
		||||
    entry: DirectoryEntry,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Context {
 | 
			
		||||
@ -225,9 +225,10 @@ impl Session  {
 | 
			
		||||
    /// default signal handlers.
 | 
			
		||||
    /// Options have to be provided as comma separated OsStr, e.g.
 | 
			
		||||
    /// ("ro,default_permissions").
 | 
			
		||||
    pub fn new(decoder: Decoder, options: &OsStr, verbose: bool) -> Result<Self, Error> {
 | 
			
		||||
    pub fn new(mut decoder: Decoder, options: &OsStr, verbose: bool) -> Result<Self, Error> {
 | 
			
		||||
        let args = Self::setup_args(options, verbose)?;
 | 
			
		||||
        let oprs = Self::setup_callbacks();
 | 
			
		||||
        let entry = decoder.root()?;
 | 
			
		||||
        let mut map = HashMap::new();
 | 
			
		||||
        // Insert entry for the root directory, with itself as parent.
 | 
			
		||||
        map.insert(0, (decoder.root_end_offset(), 0));
 | 
			
		||||
@ -236,6 +237,7 @@ impl Session  {
 | 
			
		||||
            decoder,
 | 
			
		||||
            ino_offset: 0,
 | 
			
		||||
            start_end_parent: map,
 | 
			
		||||
            entry,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let session_ctx = Box::new(Mutex::new(ctx));
 | 
			
		||||
@ -365,10 +367,18 @@ impl Session  {
 | 
			
		||||
        let result = boxed_ctx
 | 
			
		||||
            .lock()
 | 
			
		||||
            .map(|mut ctx| {
 | 
			
		||||
                ctx.ino_offset = match inode {
 | 
			
		||||
                    FUSE_ROOT_ID => 0,
 | 
			
		||||
                    _ => inode,
 | 
			
		||||
                let (ino_offset, entry) = match inode {
 | 
			
		||||
                    FUSE_ROOT_ID => (0, ctx.decoder.root().map_err(|_| libc::EIO)?),
 | 
			
		||||
                    _ => {
 | 
			
		||||
                        let (end, _) = *ctx.start_end_parent.get(&inode).unwrap();
 | 
			
		||||
                        let entry = ctx.decoder
 | 
			
		||||
                            .read_directory_entry(inode, end)
 | 
			
		||||
                            .map_err(|_| libc::EIO)?;
 | 
			
		||||
                        (inode, entry)
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
                ctx.entry = entry;
 | 
			
		||||
                ctx.ino_offset = ino_offset;
 | 
			
		||||
                code(&mut ctx)
 | 
			
		||||
            })
 | 
			
		||||
            .unwrap_or(Err(libc::EIO));
 | 
			
		||||
@ -422,11 +432,7 @@ impl Session  {
 | 
			
		||||
 | 
			
		||||
    extern "C" fn getattr(req: Request, inode: u64, _fileinfo: MutPtr) {
 | 
			
		||||
        Self::run_in_context(req, inode, |ctx| {
 | 
			
		||||
            let (_, entry, _, payload_size) = ctx
 | 
			
		||||
                .decoder
 | 
			
		||||
                .attributes(ctx.ino_offset)
 | 
			
		||||
                .map_err(|_| libc::EIO)?;
 | 
			
		||||
            let attr = stat(inode, &entry, payload_size)?;
 | 
			
		||||
            let attr = stat(inode, &ctx.entry.entry, ctx.entry.size)?;
 | 
			
		||||
            let _res = unsafe {
 | 
			
		||||
                // Since fs is read-only, the timeout can be max.
 | 
			
		||||
                let timeout = std::f64::MAX;
 | 
			
		||||
@ -451,8 +457,7 @@ impl Session  {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    extern "C" fn open(req: Request, inode: u64, fileinfo: MutPtr) {
 | 
			
		||||
        Self::run_in_context(req, inode, |ctx| {
 | 
			
		||||
            ctx.decoder.open(ctx.ino_offset).map_err(|_| libc::ENOENT)?;
 | 
			
		||||
        Self::run_in_context(req, inode, |_ctx| {
 | 
			
		||||
            let _ret = unsafe { fuse_reply_open(req, fileinfo) };
 | 
			
		||||
 | 
			
		||||
            Ok(())
 | 
			
		||||
@ -532,21 +537,11 @@ impl Session  {
 | 
			
		||||
 | 
			
		||||
            // Add current directory entry "."
 | 
			
		||||
            if offset <= n_entries {
 | 
			
		||||
                let entry = if ctx.ino_offset == 0 {
 | 
			
		||||
                    ctx.decoder
 | 
			
		||||
                        .root()
 | 
			
		||||
                        .map_err(|_| libc::EIO)?
 | 
			
		||||
                } else {
 | 
			
		||||
                    ctx.decoder
 | 
			
		||||
                        .read_directory_entry(ctx.ino_offset, end)
 | 
			
		||||
                        .map_err(|_| libc::EIO)?
 | 
			
		||||
                };
 | 
			
		||||
                // No need to calculate i-node for current dir, since it is given as parameter
 | 
			
		||||
                let name = CString::new(".").unwrap();
 | 
			
		||||
                let attr = EntryParam {
 | 
			
		||||
                    inode: inode,
 | 
			
		||||
                    generation: 1,
 | 
			
		||||
                    attr: stat(inode, &entry.entry, entry.size).map_err(|_| libc::EIO)?,
 | 
			
		||||
                    attr: stat(inode, &ctx.entry.entry, ctx.entry.size).map_err(|_| libc::EIO)?,
 | 
			
		||||
                    attr_timeout: std::f64::MAX,
 | 
			
		||||
                    entry_timeout: std::f64::MAX,
 | 
			
		||||
                };
 | 
			
		||||
@ -605,19 +600,15 @@ impl Session  {
 | 
			
		||||
        let name = unsafe { CStr::from_ptr(name) };
 | 
			
		||||
 | 
			
		||||
        Self::run_in_context(req, inode, |ctx| {
 | 
			
		||||
            let (_, _, xattrs, _) = ctx
 | 
			
		||||
                .decoder
 | 
			
		||||
                .attributes(ctx.ino_offset)
 | 
			
		||||
                .map_err(|_| libc::EIO)?;
 | 
			
		||||
            // security.capability is stored separately, check it first
 | 
			
		||||
            if name.to_bytes() == b"security.capability" {
 | 
			
		||||
                match xattrs.fcaps {
 | 
			
		||||
                match &mut ctx.entry.xattr.fcaps {
 | 
			
		||||
                    None => return Err(libc::ENODATA),
 | 
			
		||||
                    Some(mut fcaps) => return Self::xattr_reply_value(req, &mut fcaps.data, size),
 | 
			
		||||
                    Some(fcaps) => return Self::xattr_reply_value(req, &mut fcaps.data, size),
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            for mut xattr in xattrs.xattrs {
 | 
			
		||||
            for xattr in &mut ctx.entry.xattr.xattrs {
 | 
			
		||||
                if name.to_bytes() == xattr.name.as_slice() {
 | 
			
		||||
                    return Self::xattr_reply_value(req, &mut xattr.value, size);
 | 
			
		||||
                }
 | 
			
		||||
@ -630,15 +621,11 @@ impl Session  {
 | 
			
		||||
    /// Get a list of the extended attribute of `inode`.
 | 
			
		||||
    extern "C" fn listxattr(req: Request, inode: u64, size: size_t) {
 | 
			
		||||
        Self::run_in_context(req, inode, |ctx| {
 | 
			
		||||
            let (_, _, xattrs, _) = ctx
 | 
			
		||||
                .decoder
 | 
			
		||||
                .attributes(ctx.ino_offset)
 | 
			
		||||
                .map_err(|_| libc::EIO)?;
 | 
			
		||||
            let mut buffer = Vec::new();
 | 
			
		||||
            if xattrs.fcaps.is_some() {
 | 
			
		||||
            if ctx.entry.xattr.fcaps.is_some() {
 | 
			
		||||
                buffer.extend_from_slice(b"security.capability\0");
 | 
			
		||||
            }
 | 
			
		||||
            for mut xattr in xattrs.xattrs {
 | 
			
		||||
            for xattr in &mut ctx.entry.xattr.xattrs {
 | 
			
		||||
                buffer.append(&mut xattr.name);
 | 
			
		||||
                buffer.push(b'\0');
 | 
			
		||||
            }
 | 
			
		||||
@ -679,33 +666,6 @@ impl Drop for Session {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Return the correct offset for the item based on its `PxarEntry` mode
 | 
			
		||||
///
 | 
			
		||||
/// For directories, the offset for the corresponding `GOODBYE_TAIL_MARKER`
 | 
			
		||||
/// is returned.
 | 
			
		||||
/// If it is not a directory, the start offset is returned.
 | 
			
		||||
fn find_offset(entry: &PxarEntry, start: u64, end: u64) -> u64 {
 | 
			
		||||
    if (entry.mode as u32 & libc::S_IFMT) == libc::S_IFDIR {
 | 
			
		||||
        end - GOODBYE_ITEM_SIZE
 | 
			
		||||
    } else {
 | 
			
		||||
        start
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Calculate the i-node based on the given `offset`
 | 
			
		||||
///
 | 
			
		||||
/// This maps the `offset` to the correct i-node, which is simply the offset.
 | 
			
		||||
/// The root directory is an exception, as it has per definition `FUSE_ROOT_ID`.
 | 
			
		||||
/// `root_end` is the end offset of the root directory (archive end).
 | 
			
		||||
fn calculate_inode(offset: u64, root_end: u64) -> u64 {
 | 
			
		||||
    // check for root offset which has to be mapped to `FUSE_ROOT_ID`
 | 
			
		||||
    if offset == root_end - GOODBYE_ITEM_SIZE {
 | 
			
		||||
        FUSE_ROOT_ID
 | 
			
		||||
    } else {
 | 
			
		||||
        offset
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// FUSE entry for fuse_reply_entry in lookup callback
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
struct EntryParam {
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user