1#![cfg(target_os = "linux")]
5#![expect(unsafe_code)]
7
8use super::Fuse;
9use crate::reply::ReplySender;
10use crate::request::*;
11use crate::session::Session;
12use crate::util;
13use std::ffi;
14use std::fs;
15use std::io::Read;
16use std::io::Write;
17use std::io::{self};
18use std::os::unix::prelude::*;
19use std::path::Path;
20
21pub struct Connection {
26 fuse_dev: fs::File,
27}
28
29impl Connection {
30 pub fn mount(mount_point: impl AsRef<Path>) -> lx::Result<Self> {
32 let fuse_dev = fs::OpenOptions::new()
34 .read(true)
35 .write(true)
36 .open("/dev/fuse")?;
37
38 let options = format!(
40 "fd={},rootmode=40000,user_id=0,group_id=0",
41 fuse_dev.as_raw_fd()
42 );
43
44 let options = util::create_cstr(options)?;
46 let target = util::create_cstr(mount_point.as_ref().as_os_str().as_bytes())?;
47
48 unsafe {
50 check_lx_errno(libc::mount(
51 util::create_cstr("none")?.as_ptr(),
52 target.as_ptr(),
53 util::create_cstr("fuse.test")?.as_ptr(),
54 0,
55 options.as_ptr().cast::<ffi::c_void>(),
56 ))?;
57 }
58
59 Ok(Self { fuse_dev })
60 }
61
62 pub fn unmount(mount_point: impl AsRef<Path>, flags: i32) -> lx::Result<()> {
64 unsafe {
66 check_lx_errno(libc::umount2(
67 util::create_cstr(mount_point.as_ref().as_os_str().as_bytes())?.as_ptr(),
68 flags,
69 ))?;
70 }
71
72 Ok(())
73 }
74
75 pub fn run<T: 'static + Fuse + Send + Sync>(&mut self, fs: T) -> lx::Result<()> {
77 let mut buffer = vec![0u8; 1028 * 1024];
79 let session = Session::new(fs);
80
81 let mut size = self.read(&mut buffer);
82 while size > 0 {
83 let request = Request::new(&buffer[..size])?;
84 session.dispatch(request, self, None);
85
86 size = self.read(&mut buffer);
87 }
88
89 session.destroy();
90 Ok(())
91 }
92
93 fn read(&mut self, buffer: &mut [u8]) -> usize {
96 match self.fuse_dev.read(buffer) {
97 Ok(size) => size,
98 Err(e) => {
99 tracing::warn!(
100 len = buffer.len(),
101 error = &e as &dyn std::error::Error,
102 "/dev/fuse read failed",
103 );
104 0
105 }
106 }
107 }
108}
109
110impl ReplySender for Connection {
111 fn send(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<()> {
112 let size = self.fuse_dev.write_vectored(bufs)?;
113 if size < bufs.iter().map(|s| s.len()).sum() {
114 return Err(io::Error::other("Failed to write all data"));
115 }
116
117 Ok(())
118 }
119}
120
121fn check_lx_errno<T: PartialOrd<T> + Default>(result: T) -> lx::Result<T> {
123 if result < Default::default() {
124 Err(lx::Error::last_os_error())
125 } else {
126 Ok(result)
127 }
128}