use super::*;
use crate::util::{KernelStr, OptionFd};
use std::ffi::CStr;
use uuid::Uuid;
#[repr(transparent)]
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_str(&self) -> KernelStr<'_>
{
CStr::from_bytes_until_nul(&self.0.path)
.unwrap()
.to_string_lossy()
}
pub fn path_bytes(&self) -> &[u8]
{
CStr::from_bytes_until_nul(&self.0.path).unwrap().to_bytes()
}
pub fn fsid(&self) -> Uuid
{
Uuid::from_bytes(self.0.fsid)
}
}
pub fn info<P: AsRef<Path>>(devid: u64, fs: P) -> IoResult<DevInfo>
{
File::open(fs).and_then(|f| io::info(devid, f))
}
pub fn boxed_info<P: AsRef<Path>>(devid: u64, fs: P) -> IoResult<Box<DevInfo>>
{
File::open(fs).and_then(|f| io::boxed_info(devid, f))
}
pub fn iter<P: AsRef<Path>>(
fs: P,
) -> IoResult<impl Iterator<Item = IoResult<DevInfo>> + ExactSizeIterator>
{
File::open(fs).and_then(|f| Iter::new_internal(OptionFd::Owned(f.into())))
}
pub(super) mod io
{
use super::*;
use std::os::fd::{AsFd, BorrowedFd};
pub fn info<R: AsFd>(devid: u64, resource: R) -> IoResult<DevInfo>
{
let mut info_args: DevInfo = unsafe { MaybeUninit::zeroed().assume_init() };
info_args.0.devid = devid;
btrfs_ioctl(resource, BTRFS_IOC_DEV_INFO, &mut info_args).map(|_| info_args)
}
pub fn boxed_info<R: AsFd>(devid: u64, resource: R) -> IoResult<Box<DevInfo>>
{
let mut info_args: Box<DevInfo> = unsafe { Box::new_zeroed().assume_init() };
info_args.0.devid = devid;
btrfs_ioctl(resource, BTRFS_IOC_DEV_INFO, info_args.as_mut()).map(|_| info_args)
}
pub fn iter<'a>(
fd: BorrowedFd<'a>,
) -> IoResult<impl Iterator<Item = IoResult<DevInfo>> + ExactSizeIterator + use<'a>>
{
Iter::new_internal(OptionFd::Borrowed(fd))
}
}
struct Iter<'r>
{
fs: OptionFd<'r>,
num_devices: u64,
max_id: u64,
found_devices: u64,
last_id: u64,
}
impl<'r> Iter<'r>
{
fn new_internal(fs: OptionFd<'r>) -> IoResult<Self>
{
crate::fs::io::info(fs.as_fd(), crate::Flags::NONE).map(|fs_info| Iter {
fs,
max_id: fs_info.max_id(),
num_devices: fs_info.num_devices(),
found_devices: 0,
last_id: 0,
})
}
}
impl ExactSizeIterator for Iter<'_> {}
impl Iterator for Iter<'_>
{
type Item = IoResult<DevInfo>;
fn next(&mut self) -> Option<Self::Item>
{
if self.last_id >= self.max_id {
return if self.found_devices != self.num_devices {
Some(Err(ErrorKind::InvalidData.into()))
} else {
None
};
}
let mut args: DevInfo = unsafe { MaybeUninit::zeroed().assume_init() };
for id in 1 + self.last_id.. {
args.0.devid = id;
if let Err(e) = btrfs_ioctl(self.fs.as_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.found_devices += 1;
if self.found_devices > self.num_devices {
return Some(Err(ErrorKind::InvalidData.into()));
}
break;
}
Some(Ok(args))
}
fn size_hint(&self) -> (usize, Option<usize>)
{
let hint = (self.num_devices - self.found_devices) as usize;
(hint, Some(hint))
}
}