use super::*;
pub struct SubvolInfo(pub(super) btrfs_ioctl_get_subvol_info_args);
impl SubvolInfo {
pub const fn treeid(&self) -> u64 {
self.0.treeid
}
pub fn name_as_str(&self) -> Result<&str, std::str::Utf8Error> {
unsafe { CStr::from_ptr(self.0.name.as_ptr().cast()).to_str() }
}
pub fn name_as_bytes(&self) -> &[u8] {
unsafe { CStr::from_ptr(self.0.name.as_ptr()).to_bytes() }
}
pub fn parent_id(&self) -> u64 {
self.0.parent_id
}
pub fn dirid(&self) -> u64 {
self.0.dirid
}
pub fn generation(&self) -> u64 {
self.0.generation
}
pub fn flags(&self) -> u64 {
self.0.flags
}
pub fn readonly(&self) -> bool {
self.0.flags & BTRFS_SUBVOL_RDONLY != 0
}
pub fn uuid(&self) -> Uuid {
Uuid::from_bytes(self.0.uuid)
}
pub fn parent_uuid(&self) -> Uuid {
Uuid::from_bytes(self.0.parent_uuid)
}
pub fn received_uuid(&self) -> Uuid {
Uuid::from_bytes(self.0.received_uuid)
}
pub fn ctransid(&self) -> u64 {
self.0.ctransid
}
pub fn otransid(&self) -> u64 {
self.0.otransid
}
pub fn stransid(&self) -> u64 {
self.0.stransid
}
pub fn rtransid(&self) -> u64 {
self.0.rtransid
}
pub fn ctime(&self) -> &Timespec {
&self.0.ctime
}
pub fn otime(&self) -> &Timespec {
&self.0.otime
}
pub fn stime(&self) -> &Timespec {
&self.0.stime
}
pub fn rtime(&self) -> &Timespec {
&self.0.rtime
}
}
pub fn get_info<P: AsRef<Path>>(pathname: P) -> io::Result<SubvolInfo> {
let fd = File::open(pathname)?;
fd::get_info(fd.as_raw_fd())
}
pub fn get_info_by_id<P: AsRef<Path>>(treeid: u64, fs: P) -> io::Result<SubvolInfo> {
let fd = File::open(fs)?;
fd::get_info_by_id(treeid, fd.as_raw_fd())
}
pub mod fd {
use super::*;
use crate::{
bindings::{
btrfs_root_ref, BTRFS_FS_TREE_OBJECTID, BTRFS_ROOT_BACKREF_KEY, BTRFS_ROOT_ITEM_KEY,
},
util::root_item_to_subvol_info_args,
};
use std::{mem::MaybeUninit as Uninit, os::unix::io::RawFd, ptr::addr_of_mut};
pub fn get_info(fd: RawFd) -> io::Result<SubvolInfo> {
let mut args = btrfs_ioctl_get_subvol_info_args::default();
btrfs_ioctl(fd, BTRFS_IOC_GET_SUBVOL_INFO, &mut args)?;
Ok(SubvolInfo(args))
}
pub fn get_info_by_id(treeid: u64, fd: RawFd) -> io::Result<SubvolInfo> {
let mut info_args = Uninit::<btrfs_ioctl_get_subvol_info_args>::uninit();
let mut got_root_ref = treeid == BTRFS_FS_TREE_OBJECTID;
let mut got_root_item = false;
let mut ts = TreeSearch::new(fd, |key| {
key.tree_id = BTRFS_ROOT_TREE_OBJECTID;
key.min_objectid = treeid;
key.max_objectid = treeid;
key.min_type = BTRFS_ROOT_ITEM_KEY;
key.max_type = if got_root_ref {
BTRFS_ROOT_ITEM_KEY
} else {
BTRFS_ROOT_BACKREF_KEY
};
});
let p = info_args.as_mut_ptr();
if let Some(items) = ts.search()? {
for item in items {
match item.key() {
BTRFS_ROOT_ITEM_KEY => {
root_item_to_subvol_info_args(p, item.get());
got_root_item = true;
}
BTRFS_ROOT_BACKREF_KEY => {
let rr = item.get::<&btrfs_root_ref>();
let name = item.name_as_ibytes(rr);
unsafe {
let pname = (*p).name.as_mut_ptr();
name.as_ptr().copy_to_nonoverlapping(pname, name.len());
pname.add(name.len()).write(0);
addr_of_mut!((*p).dirid).write(u64::from_le(rr.dirid));
addr_of_mut!((*p).parent_id).write(item.offset());
}
got_root_ref = true;
}
_ => {}
}
if got_root_ref && got_root_item {
unsafe {
addr_of_mut!((*p).reserved).write([0; 8]);
addr_of_mut!((*p).treeid).write(treeid);
return Ok(SubvolInfo(info_args.assume_init()));
}
}
}
}
error!(NotFound)
}
}