use super::*;
use std::ffi::CStr;
use uuid::Uuid;
pub struct DevInfo(btrfs_ioctl_dev_info_args);
impl DevInfo {
pub fn device_id(&self) -> u64 {
self.0.devid
}
pub fn device_uuid(&self) -> Uuid {
Uuid::from_bytes(self.0.uuid)
}
pub fn bytes_used(&self) -> u64 {
self.0.bytes_used
}
pub fn bytes_total(&self) -> u64 {
self.0.total_bytes
}
pub fn path_as_str(&self) -> Result<&str, std::str::Utf8Error> {
CStr::from_bytes_until_nul(&self.0.path).unwrap().to_str()
}
pub fn path_as_bytes(&self) -> &[u8] {
CStr::from_bytes_until_nul(&self.0.path).unwrap().to_bytes()
}
#[cfg(VERSION_6_3)]
pub fn fsid(&self) -> Uuid {
Uuid::from_bytes(self.0.fsid)
}
}
pub struct InfoIter {
fd: OptionFd,
num_devices: u64,
max_id: u64,
device_count: u64,
last_id: u64,
}
impl InfoIter {
fn new_internal(fd: OptionFd) -> io::Result<Self> {
let fs_info = crate::fs::fd::info(fd.as_raw_fd(), crate::Opt::empty())?;
Ok(InfoIter {
fd,
num_devices: fs_info.num_devices(),
max_id: fs_info.max_id(),
device_count: 0,
last_id: 0,
})
}
}
impl Iterator for InfoIter {
type Item = io::Result<super::DevInfo>;
fn next(&mut self) -> Option<Self::Item> {
if self.last_id >= self.max_id {
return if self.device_count != self.num_devices {
Some(Err(io::ErrorKind::InvalidData.into()))
} else {
None
};
}
let mut args = btrfs_ioctl_dev_info_args::default();
for id in 1 + self.last_id.. {
args.devid = id;
if let Err(e) = btrfs_ioctl(self.fd.as_raw_fd(), BTRFS_IOC_DEV_INFO, &mut args) {
if let Some(libc::ENODEV) = e.raw_os_error() {
continue;
}
return Some(Err(e));
}
self.last_id = id;
self.device_count += 1;
if self.device_count > self.num_devices {
return Some(Err(io::ErrorKind::InvalidData.into()));
}
break;
}
Some(Ok(DevInfo(args)))
}
}
pub fn info<P: AsRef<Path>>(devid: u64, fs: P) -> io::Result<DevInfo> {
let fd = File::open(fs)?;
fd::info(devid, fd.as_raw_fd())
}
pub fn info_iter<P: AsRef<Path>>(fs: P) -> io::Result<InfoIter> {
let fd = File::open(fs)?;
InfoIter::new_internal(OptionFd::File(fd))
}
pub(super) mod fd {
use super::*;
use std::os::unix::io::RawFd;
pub fn info(devid: u64, fd: RawFd) -> io::Result<super::DevInfo> {
let mut args = btrfs_ioctl_dev_info_args {
devid,
..Default::default()
};
btrfs_ioctl(fd, BTRFS_IOC_DEV_INFO, &mut args)?;
Ok(super::DevInfo(args))
}
pub fn info_iter(fd: RawFd) -> io::Result<InfoIter> {
InfoIter::new_internal(OptionFd::Raw(fd))
}
}