use super::*;
use crate::{
bindings::{
btrfs_dev_item, btrfs_ioctl_search_header, BTRFS_CHUNK_TREE_OBJECTID,
BTRFS_DEV_ITEMS_OBJECTID, BTRFS_DEV_ITEM_KEY, BTRFS_SEARCH_ARGS_BUFSIZE,
},
tree_search::fd::TreeSearch,
util::OptionFd,
};
use std::mem::size_of;
use uuid::Uuid;
pub struct DevItem<'a>(&'a btrfs_dev_item);
impl DevItem<'_> {
pub fn device_id(&self) -> u64 {
u64::from_le(self.0.devid)
}
pub fn total_bytes(&self) -> u64 {
u64::from_le(self.0.total_bytes)
}
pub fn bytes_used(&self) -> u64 {
u64::from_le(self.0.bytes_used)
}
pub fn io_align(&self) -> u32 {
u32::from_le(self.0.io_align)
}
pub fn io_width(&self) -> u32 {
u32::from_le(self.0.io_width)
}
pub fn sector_size(&self) -> u32 {
u32::from_le(self.0.sector_size)
}
pub fn device_type(&self) -> u64 {
u64::from_le(self.0.type_)
}
pub fn generation(&self) -> u64 {
u64::from_le(self.0.generation)
}
pub fn start_offset(&self) -> u64 {
u64::from_le(self.0.start_offset)
}
pub fn dev_group(&self) -> u32 {
u32::from_le(self.0.dev_group)
}
pub fn seek_speed(&self) -> u8 {
self.0.seek_speed
}
pub fn bandwidth(&self) -> u8 {
self.0.bandwidth
}
pub fn uuid(&self) -> Uuid {
Uuid::from_bytes(self.0.uuid)
}
pub fn fsid(&self) -> Uuid {
Uuid::from_bytes(self.0.fsid)
}
}
pub struct ItemIter<'a>(Vec<DevItem<'a>>);
impl ItemIter<'_> {
fn new_internal(fd: OptionFd) -> io::Result<Self> {
let mut max_items = BTRFS_SEARCH_ARGS_BUFSIZE
/ (size_of::<btrfs_ioctl_search_header>() + size_of::<btrfs_dev_item>());
let mut ts = TreeSearch::new(fd.as_raw_fd(), |key| {
key.tree_id = BTRFS_CHUNK_TREE_OBJECTID;
key.min_objectid = BTRFS_DEV_ITEMS_OBJECTID;
key.max_objectid = BTRFS_DEV_ITEMS_OBJECTID;
key.min_type = BTRFS_DEV_ITEM_KEY;
key.max_type = BTRFS_DEV_ITEM_KEY;
key.nr_items = max_items as u32;
key.min_offset = 1;
});
let mut buf: Vec<DevItem> = Vec::new();
while let Some(items) = ts.search()? {
buf.extend(items.map(|item| DevItem(item.get())));
if max_items != buf.len() {
break;
}
ts.min_offset(buf.last().unwrap().device_id() + 1);
max_items <<= 1;
}
Ok(Self(buf))
}
}
impl<'a> IntoIterator for ItemIter<'a> {
type Item = DevItem<'a>;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
pub fn item_iter<'a, P: AsRef<Path>>(fs: P) -> io::Result<ItemIter<'a>> {
let fd = File::open(fs)?;
ItemIter::new_internal(OptionFd::File(fd))
}
pub(super) mod fd {
use super::*;
use std::os::unix::io::RawFd;
pub fn item_iter<'a>(fd: RawFd) -> io::Result<ItemIter<'a>> {
ItemIter::new_internal(OptionFd::Raw(fd))
}
}