use std::os::fd::AsFd;
use std::os::unix::io::AsRawFd;
use std::sync::Arc;
use std::sync::Weak;
use log::error;
use crate::dev_fuse::DevFuse;
use crate::ll::ioctl::fuse_backing_map;
use crate::ll::ioctl::fuse_dev_ioc_backing_close;
use crate::ll::ioctl::fuse_dev_ioc_backing_open;
#[derive(Debug)]
pub struct BackingId {
pub(crate) channel: Weak<DevFuse>,
pub(crate) backing_id: u32,
}
impl BackingId {
pub fn create_raw(fuse_dev: impl AsFd, fd: impl AsFd) -> std::io::Result<u32> {
if !cfg!(target_os = "linux") {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
"backing IDs are only supported on Linux",
));
}
let map = fuse_backing_map {
fd: fd.as_fd().as_raw_fd() as u32,
flags: 0,
padding: 0,
};
let id = unsafe { fuse_dev_ioc_backing_open(fuse_dev.as_fd().as_raw_fd(), &map) }?;
Ok(id as u32)
}
pub(crate) fn create(channel: &Arc<DevFuse>, fd: impl AsFd) -> std::io::Result<Self> {
Ok(Self {
channel: Arc::downgrade(channel),
backing_id: Self::create_raw(channel, fd)?,
})
}
pub(crate) unsafe fn wrap_raw(channel: &Arc<DevFuse>, id: u32) -> Self {
Self {
channel: Arc::downgrade(channel),
backing_id: id,
}
}
pub fn into_raw(mut self) -> u32 {
let id = self.backing_id;
drop(std::mem::take(&mut self.channel));
std::mem::forget(self);
id
}
}
impl Drop for BackingId {
fn drop(&mut self) {
if let Some(ch) = self.channel.upgrade() {
if let Err(e) = unsafe { fuse_dev_ioc_backing_close(ch.as_raw_fd(), &self.backing_id) }
{
error!("Failed to close backing fd: {e}");
}
}
}
}