libbtrfs 0.0.20

Rust library for working with the btrfs filesystem
Documentation
use crate::bindings::{
    btrfs_ioctl_get_subvol_info_args, btrfs_root_item, BTRFS_PATH_NAME_MAX, BTRFS_SUBVOL_NAME_MAX,
};
use std::{
    io,
    path::{Component, MAIN_SEPARATOR},
    ptr::addr_of_mut,
};

/// Copies bytes `$b` to an c_char array of length `$len` and returns the array
macro_rules! copy_bytes_to_c_char_array {
    ($b:expr, $len:expr) => {{
        let mut uninit = ::std::mem::MaybeUninit::<[::libc::c_char; $len]>::uninit();
        let p = uninit.as_mut_ptr().cast::<::libc::c_char>();
        unsafe {
            $b.as_ptr().copy_to_nonoverlapping(p.cast(), $b.len());
            p.add($b.len()).write(0);

            uninit.assume_init()
        }
    }};
}

/// Fills the name field in the btrfs_ioctl_vol_args struct with `bytes`
pub(crate) fn vol_args_name_from_bytes(bytes: &[u8]) -> [libc::c_char; BTRFS_PATH_NAME_MAX + 1] {
    copy_bytes_to_c_char_array!(bytes, BTRFS_PATH_NAME_MAX + 1)
}

/// Fills the name field in the btrfs_ioctl_vol_args_v2 struct with `bytes`
pub(crate) fn vol_args_v2_name_from_bytes(
    bytes: &[u8],
) -> [libc::c_char; BTRFS_SUBVOL_NAME_MAX as usize + 1] {
    copy_bytes_to_c_char_array!(bytes, BTRFS_SUBVOL_NAME_MAX as usize + 1)
}

/// Fill the name field for btrfs_ioctl_vol_args_v2 after checking if name is valid
pub(crate) fn vol_args_v2_name_from_str_checked(
    name: &str,
) -> io::Result<[libc::c_char; BTRFS_SUBVOL_NAME_MAX as usize + 1]> {
    if name == Component::CurDir.as_os_str() || name == Component::ParentDir.as_os_str() {
        error!(AlreadyExists)
    } else if name.is_empty() || name.contains(MAIN_SEPARATOR) {
        error!(InvalidInput)
    }

    Ok(vol_args_v2_name_from_bytes(name.as_bytes()))
}

/// Copy common fields from `btrfs_root_item` struct to `btrfs_ioctl_get_subvol_info_args` struct
pub(crate) fn root_item_to_subvol_info_args(
    dest: *mut btrfs_ioctl_get_subvol_info_args,
    src: &btrfs_root_item,
) {
    unsafe {
        addr_of_mut!((*dest).generation).write(u64::from_le(src.generation));
        addr_of_mut!((*dest).flags).write(u64::from_le(src.flags));
        addr_of_mut!((*dest).uuid).write(src.uuid);
        addr_of_mut!((*dest).parent_uuid).write(src.parent_uuid);
        addr_of_mut!((*dest).received_uuid).write(src.received_uuid);
        addr_of_mut!((*dest).ctransid).write(u64::from_le(src.ctransid));
        addr_of_mut!((*dest).otransid).write(u64::from_le(src.otransid));
        addr_of_mut!((*dest).stransid).write(u64::from_le(src.stransid));
        addr_of_mut!((*dest).rtransid).write(u64::from_le(src.rtransid));
        addr_of_mut!((*dest).ctime.sec).write(u64::from_le(src.ctime.sec));
        addr_of_mut!((*dest).ctime.nsec).write(u32::from_le(src.ctime.nsec));
        addr_of_mut!((*dest).otime.sec).write(u64::from_le(src.otime.sec));
        addr_of_mut!((*dest).otime.nsec).write(u32::from_le(src.otime.nsec));
        addr_of_mut!((*dest).stime.sec).write(u64::from_le(src.stime.sec));
        addr_of_mut!((*dest).stime.nsec).write(u32::from_le(src.stime.nsec));
        addr_of_mut!((*dest).rtime.sec).write(u64::from_le(src.rtime.sec));
        addr_of_mut!((*dest).rtime.nsec).write(u32::from_le(src.rtime.nsec));
    }
}