libbtrfs 0.0.20

Rust library for working with the btrfs filesystem
Documentation
//! Btrfs filesystem lookups
//!
//! This module provides wrappers for The btrfs lookup ioctl, enabling varias types of lookups
//! including path lookups for both priviliged and unprivileged processes.
//!
use crate::{
    bindings::{btrfs_ioctl_ino_lookup_args, btrfs_ioctl_ino_lookup_user_args},
    util::btrfs_ioctl,
};
use std::{ffi::CStr, fs::File, io, os::unix::io::AsRawFd, path::Path};

/// Lookup the treeid for a subvolume given a path
pub fn treeid<P: AsRef<Path>>(pathname: P) -> io::Result<u64> {
    let fd = File::open(pathname)?;

    fd::treeid(fd.as_raw_fd())
}

/// Lookup path from an inode to a subvolume root
///
/// This function retrurns a lookup path as a string slice to `objectid` which is the inode of a
/// file or directory which must be containded in the subvolume referenced by `treeid`. The returned
/// path is relative to the subvolume referenced by `treeid`. `objectid` and `treeid` must both be
/// within the btrfs filesystem referenced by `fs`.
///
/// # Errors
///
/// * [`io::ErrorKind::InvalidData`]
///
/// The path to be returned contained invalid UTF-8.
///
/// # Notes
///
/// **Requires CAP_SYS_ADMIN capabilities**
///
pub fn path_as_str<'a, P: AsRef<Path>>(fs: P, objectid: u64, treeid: u64) -> io::Result<&'a str> {
    let fd = File::open(fs)?;

    fd::path_as_str(fd.as_raw_fd(), objectid, treeid)
}

/// Lookup path from an inode to a subvolume root
///
/// This function retrurns a lookup path as a byte slice to `objectid` which is the inode of a
/// file or directory which must be containded in the subvolume referenced by `treeid`. The returned
/// path is relative to the subvolume referenced by `treeid`. `objectid` and `treeid` must both be
/// within the btrfs filesystem referenced by `fs`.
///
/// # Notes
///
/// **Requires CAP_SYS_ADMIN capabilities**
///
pub fn path_as_bytes<'a, P: AsRef<Path>>(
    fs: P,
    objectid: u64,
    treeid: u64,
) -> io::Result<&'a [u8]> {
    let fd = File::open(fs)?;

    fd::path_as_bytes(fd.as_raw_fd(), objectid, treeid)
}

/// Lookup the path from a subvolume root
///
/// This function returns a tuple containing the lookup path and name for the subvolume referenced by
/// `treeid` as a string slice. The lookup path is relative to `pathname` which is a path to a file
/// or directory located in the parent subvolume referenced by `treeid`. `dirid` is the inode of the
/// directory that contains the subvolume referenced by `treeid`.
///
/// # Errors
///
/// * [`io::ErrorKind::InvalidData`]
///
/// Either the subvolume name or the lookup path to be returned contained invalid UTF-8.
///
pub fn user_path_as_str<'a, P: AsRef<Path>>(
    pathname: P,
    dirid: u64,
    treeid: u64,
) -> io::Result<(&'a str, &'a str)> {
    let fd = File::open(pathname)?;

    fd::user_path_as_str(fd.as_raw_fd(), dirid, treeid)
}

/// Lookup the path from a subvolume root
///
/// This function returns a tuple containing the lookup path and name for the subvolume referenced
/// by `treeid` as a byte slice. The lookup path is relative to `pathname` which is a path to a file
/// or directory located in the parent subvolume referenced by `treeid`. `dirid` is the inode of the
/// directory that contains the subvolume referenced by `treeid`.
///
pub fn user_path_as_bytes<'a, P: AsRef<Path>>(
    pathname: P,
    dirid: u64,
    treeid: u64,
) -> io::Result<(&'a [u8], &'a [u8])> {
    let fd = File::open(pathname)?;

    fd::user_path_as_bytes(fd.as_raw_fd(), dirid, treeid)
}

pub mod fd {
    use super::*;
    use crate::bindings::{
        BTRFS_FIRST_FREE_OBJECTID, BTRFS_IOC_INO_LOOKUP, BTRFS_IOC_INO_LOOKUP_USER,
    };
    use std::{
        io::{Error, ErrorKind},
        os::unix::io::RawFd,
    };

    /// See [super::treeid()]
    pub fn treeid(fd: RawFd) -> io::Result<u64> {
        let mut args = btrfs_ioctl_ino_lookup_args {
            objectid: BTRFS_FIRST_FREE_OBJECTID,
            ..Default::default()
        };
        btrfs_ioctl(fd, BTRFS_IOC_INO_LOOKUP, &mut args)?;

        Ok(args.treeid)
    }

    /// See [super::user_path_as_str()]
    pub fn user_path_as_str<'a>(
        fd: RawFd,
        dirid: u64,
        treeid: u64,
    ) -> io::Result<(&'a str, &'a str)> {
        let mut args = btrfs_ioctl_ino_lookup_user_args {
            dirid,
            treeid,
            ..Default::default()
        };
        btrfs_ioctl(fd, BTRFS_IOC_INO_LOOKUP_USER, &mut args)?;
        unsafe {
            Ok((
                match CStr::from_ptr(args.path.as_ptr().cast()).to_str() {
                    Ok(s) => s,
                    Err(_) => error!(InvalidData;),
                },
                match CStr::from_ptr(args.name.as_ptr().cast()).to_str() {
                    Ok(s) => s,
                    Err(_) => error!(InvalidData;),
                },
            ))
        }
    }

    /// See [super::user_path_as_bytes()]
    pub fn user_path_as_bytes<'a>(
        fd: RawFd,
        dirid: u64,
        treeid: u64,
    ) -> io::Result<(&'a [u8], &'a [u8])> {
        let mut args = btrfs_ioctl_ino_lookup_user_args {
            dirid,
            treeid,
            ..Default::default()
        };
        btrfs_ioctl(fd, BTRFS_IOC_INO_LOOKUP_USER, &mut args)?;
        unsafe {
            Ok((
                CStr::from_ptr(args.path.as_ptr().cast()).to_bytes(),
                CStr::from_ptr(args.name.as_ptr().cast()).to_bytes(),
            ))
        }
    }

    /// See [super::path_as_str()]
    pub fn path_as_str<'a>(fd: RawFd, objectid: u64, treeid: u64) -> io::Result<&'a str> {
        let mut args = btrfs_ioctl_ino_lookup_args {
            treeid,
            objectid,
            ..Default::default()
        };
        btrfs_ioctl(fd, BTRFS_IOC_INO_LOOKUP, &mut args)?;
        unsafe {
            CStr::from_ptr(args.name.as_ptr().cast())
                .to_str()
                .or(Err(Error::from(ErrorKind::InvalidData)))
        }
    }

    /// See [super::path_as_bytes()]
    pub fn path_as_bytes<'a>(fd: RawFd, objectid: u64, treeid: u64) -> io::Result<&'a [u8]> {
        let mut args = btrfs_ioctl_ino_lookup_args {
            treeid,
            objectid,
            ..Default::default()
        };
        btrfs_ioctl(fd, BTRFS_IOC_INO_LOOKUP, &mut args)?;

        unsafe { Ok(CStr::from_ptr(args.name.as_ptr().cast()).to_bytes()) }
    }
}