Skip to main content

async_fuser/ll/
mod.rs

1//! Low-level kernel communication.
2
3mod argument;
4pub(crate) mod flags;
5pub(crate) mod fuse_abi;
6pub(crate) mod ioctl;
7pub(crate) mod ioslice_concat;
8pub(crate) mod notify;
9pub(crate) mod reply;
10#[cfg(feature = "async")]
11pub mod reply_async;
12pub(crate) mod request;
13#[cfg(feature = "async")]
14pub(crate) mod request_async;
15
16use std::num::NonZeroI32;
17use std::time::SystemTime;
18
19pub(crate) use reply::ResponseData;
20pub(crate) use reply::ResponseEmpty;
21pub(crate) use reply::ResponseErrno;
22pub(crate) use reply::ResponseIoctl;
23pub(crate) use reply::ResponseSlice;
24pub(crate) use reply::ResponseStruct;
25pub(crate) use request::AnyRequest;
26pub(crate) use request::FileHandle;
27pub(crate) use request::INodeNo;
28pub(crate) use request::Lock;
29pub(crate) use request::Operation;
30pub use request::RequestId;
31pub(crate) use request::Version;
32
33#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
34/// Possible input arguments for atime & mtime, which can either be set to a specified time,
35/// or to the current time
36pub enum TimeOrNow {
37    /// Specific time provided
38    SpecificTime(SystemTime),
39    /// Current time
40    Now,
41}
42
43macro_rules! errno {
44    ($x:expr) => {
45        Errno(match NonZeroI32::new($x) {
46            Some(x) => x,
47            None => panic!(),
48        })
49    };
50}
51
52macro_rules! no_xattr_doc {
53    () => {"Use this as an error return from getxattr/removexattr to indicate that the xattr doesn't exist.  This resolves to the appropriate platform-specific error code."}
54}
55
56/// Represents an error code to be returned to the caller
57#[derive(Debug, Copy, Clone)]
58pub struct Errno(
59    /// Positive value.
60    NonZeroI32,
61);
62impl Errno {
63    /// Operation not permitted
64    pub const EPERM: Errno = errno!(libc::EPERM);
65    /// No such file or directory
66    pub const ENOENT: Errno = errno!(libc::ENOENT);
67    /// No such process
68    pub const ESRCH: Errno = errno!(libc::ESRCH);
69    /// Interrupted system call
70    pub const EINTR: Errno = errno!(libc::EINTR);
71    /// Input/output error
72    pub const EIO: Errno = errno!(libc::EIO);
73    /// No such device or address
74    pub const ENXIO: Errno = errno!(libc::ENXIO);
75    /// Argument list too long
76    pub const E2BIG: Errno = errno!(libc::E2BIG);
77    /// Exec format error
78    pub const ENOEXEC: Errno = errno!(libc::ENOEXEC);
79    /// Bad file descriptor
80    pub const EBADF: Errno = errno!(libc::EBADF);
81    /// No child processes
82    pub const ECHILD: Errno = errno!(libc::ECHILD);
83    /// Resource temporarily unavailable
84    pub const EAGAIN: Errno = errno!(libc::EAGAIN);
85    /// Cannot allocate memory
86    pub const ENOMEM: Errno = errno!(libc::ENOMEM);
87    /// Permission denied
88    pub const EACCES: Errno = errno!(libc::EACCES);
89    /// Bad address
90    pub const EFAULT: Errno = errno!(libc::EFAULT);
91    /// Block device required
92    pub const ENOTBLK: Errno = errno!(libc::ENOTBLK);
93    /// Device or resource busy
94    pub const EBUSY: Errno = errno!(libc::EBUSY);
95    /// File exists
96    pub const EEXIST: Errno = errno!(libc::EEXIST);
97    /// Invalid cross-device link
98    pub const EXDEV: Errno = errno!(libc::EXDEV);
99    /// No such device
100    pub const ENODEV: Errno = errno!(libc::ENODEV);
101    /// Not a directory
102    pub const ENOTDIR: Errno = errno!(libc::ENOTDIR);
103    /// Is a directory
104    pub const EISDIR: Errno = errno!(libc::EISDIR);
105    /// Invalid argument
106    pub const EINVAL: Errno = errno!(libc::EINVAL);
107    /// Too many open files in system
108    pub const ENFILE: Errno = errno!(libc::ENFILE);
109    /// Too many open files
110    pub const EMFILE: Errno = errno!(libc::EMFILE);
111    /// Inappropriate ioctl for device
112    pub const ENOTTY: Errno = errno!(libc::ENOTTY);
113    /// Text file busy
114    pub const ETXTBSY: Errno = errno!(libc::ETXTBSY);
115    /// File too large
116    pub const EFBIG: Errno = errno!(libc::EFBIG);
117    /// No space left on device
118    pub const ENOSPC: Errno = errno!(libc::ENOSPC);
119    /// Illegal seek
120    pub const ESPIPE: Errno = errno!(libc::ESPIPE);
121    /// Read-only file system
122    pub const EROFS: Errno = errno!(libc::EROFS);
123    /// Too many links
124    pub const EMLINK: Errno = errno!(libc::EMLINK);
125    /// Broken pipe
126    pub const EPIPE: Errno = errno!(libc::EPIPE);
127    /// Numerical argument out of domain
128    pub const EDOM: Errno = errno!(libc::EDOM);
129    /// Numerical result out of range
130    pub const ERANGE: Errno = errno!(libc::ERANGE);
131    /// Resource deadlock avoided
132    pub const EDEADLK: Errno = errno!(libc::EDEADLK);
133    /// File name too long
134    pub const ENAMETOOLONG: Errno = errno!(libc::ENAMETOOLONG);
135    /// No locks available
136    pub const ENOLCK: Errno = errno!(libc::ENOLCK);
137    /// Function not implemented
138    pub const ENOSYS: Errno = errno!(libc::ENOSYS);
139    /// Directory not empty
140    pub const ENOTEMPTY: Errno = errno!(libc::ENOTEMPTY);
141    /// Too many levels of symbolic links
142    pub const ELOOP: Errno = errno!(libc::ELOOP);
143    /// Resource temporarily unavailable
144    pub const EWOULDBLOCK: Errno = errno!(libc::EWOULDBLOCK);
145    /// No message of desired type
146    pub const ENOMSG: Errno = errno!(libc::ENOMSG);
147    /// Identifier removed
148    pub const EIDRM: Errno = errno!(libc::EIDRM);
149    /// Object is remote
150    pub const EREMOTE: Errno = errno!(libc::EREMOTE);
151    /// Link has been severed
152    pub const ENOLINK: Errno = errno!(libc::ENOLINK);
153    /// Protocol error
154    pub const EPROTO: Errno = errno!(libc::EPROTO);
155    /// Multihop attempted
156    pub const EMULTIHOP: Errno = errno!(libc::EMULTIHOP);
157    /// Bad message
158    pub const EBADMSG: Errno = errno!(libc::EBADMSG);
159    /// Value too large for defined data type
160    pub const EOVERFLOW: Errno = errno!(libc::EOVERFLOW);
161    /// Invalid or incomplete multibyte or wide character
162    pub const EILSEQ: Errno = errno!(libc::EILSEQ);
163    /// Too many users
164    pub const EUSERS: Errno = errno!(libc::EUSERS);
165    /// Socket operation on non-socket
166    pub const ENOTSOCK: Errno = errno!(libc::ENOTSOCK);
167    /// Destination address required
168    pub const EDESTADDRREQ: Errno = errno!(libc::EDESTADDRREQ);
169    /// Message too long
170    pub const EMSGSIZE: Errno = errno!(libc::EMSGSIZE);
171    /// Protocol wrong type for socket
172    pub const EPROTOTYPE: Errno = errno!(libc::EPROTOTYPE);
173    /// Protocol not available
174    pub const ENOPROTOOPT: Errno = errno!(libc::ENOPROTOOPT);
175    /// Protocol not supported
176    pub const EPROTONOSUPPORT: Errno = errno!(libc::EPROTONOSUPPORT);
177    /// Socket type not supported
178    pub const ESOCKTNOSUPPORT: Errno = errno!(libc::ESOCKTNOSUPPORT);
179    /// Operation not supported
180    pub const EOPNOTSUPP: Errno = errno!(libc::EOPNOTSUPP);
181    /// Protocol family not supported
182    pub const EPFNOSUPPORT: Errno = errno!(libc::EPFNOSUPPORT);
183    /// Address family not supported by protocol
184    pub const EAFNOSUPPORT: Errno = errno!(libc::EAFNOSUPPORT);
185    /// Address already in use
186    pub const EADDRINUSE: Errno = errno!(libc::EADDRINUSE);
187    /// Cannot assign requested address
188    pub const EADDRNOTAVAIL: Errno = errno!(libc::EADDRNOTAVAIL);
189    /// Network is down
190    pub const ENETDOWN: Errno = errno!(libc::ENETDOWN);
191    /// Network is unreachable
192    pub const ENETUNREACH: Errno = errno!(libc::ENETUNREACH);
193    /// Network dropped connection on reset
194    pub const ENETRESET: Errno = errno!(libc::ENETRESET);
195    /// Software caused connection abort
196    pub const ECONNABORTED: Errno = errno!(libc::ECONNABORTED);
197    /// Connection reset by peer
198    pub const ECONNRESET: Errno = errno!(libc::ECONNRESET);
199    /// No buffer space available
200    pub const ENOBUFS: Errno = errno!(libc::ENOBUFS);
201    /// Transport endpoint is already connected
202    pub const EISCONN: Errno = errno!(libc::EISCONN);
203    /// Transport endpoint is not connected
204    pub const ENOTCONN: Errno = errno!(libc::ENOTCONN);
205    /// Cannot send after transport endpoint shutdown
206    pub const ESHUTDOWN: Errno = errno!(libc::ESHUTDOWN);
207    /// Too many references: cannot splice
208    pub const ETOOMANYREFS: Errno = errno!(libc::ETOOMANYREFS);
209    /// Connection timed out
210    pub const ETIMEDOUT: Errno = errno!(libc::ETIMEDOUT);
211    /// Connection refused
212    pub const ECONNREFUSED: Errno = errno!(libc::ECONNREFUSED);
213    /// Host is down
214    pub const EHOSTDOWN: Errno = errno!(libc::EHOSTDOWN);
215    /// No route to host
216    pub const EHOSTUNREACH: Errno = errno!(libc::EHOSTUNREACH);
217    /// Operation already in progress
218    pub const EALREADY: Errno = errno!(libc::EALREADY);
219    /// Operation now in progress
220    pub const EINPROGRESS: Errno = errno!(libc::EINPROGRESS);
221    /// Stale file handle
222    pub const ESTALE: Errno = errno!(libc::ESTALE);
223    /// Disk quota exceeded
224    pub const EDQUOT: Errno = errno!(libc::EDQUOT);
225    /// Operation cancelled
226    pub const ECANCELED: Errno = errno!(libc::ECANCELED);
227    /// Owner died
228    pub const EOWNERDEAD: Errno = errno!(libc::EOWNERDEAD);
229    /// State not recoverable
230    pub const ENOTRECOVERABLE: Errno = errno!(libc::ENOTRECOVERABLE);
231    /// Operation not supported
232    pub const ENOTSUP: Errno = errno!(libc::ENOTSUP);
233    /// Wrong file type.
234    #[cfg(any(target_os = "freebsd", target_os = "macos"))]
235    pub const EFTYPE: Errno = errno!(libc::EFTYPE);
236
237    /// No data available
238    #[cfg(target_os = "linux")]
239    pub const ENODATA: Errno = errno!(libc::ENODATA);
240    #[doc = no_xattr_doc!()]
241    #[cfg(target_os = "linux")]
242    pub const NO_XATTR: Errno = Self::ENODATA;
243
244    /// Attribute not found
245    #[cfg(not(target_os = "linux"))]
246    pub const ENOATTR: Errno = errno!(libc::ENOATTR);
247    #[doc = no_xattr_doc!()]
248    #[cfg(not(target_os = "linux"))]
249    pub const NO_XATTR: Errno = Self::ENOATTR;
250
251    /// Make errno from `i32`, defaulting to `EIO` if it is not positive.
252    pub fn from_i32(err: i32) -> Errno {
253        NonZeroI32::new(err)
254            .filter(|err| err.get() > 0)
255            .map(Errno)
256            .unwrap_or(Errno::EIO)
257    }
258
259    /// Errno value.
260    pub fn code(self) -> i32 {
261        self.0.get()
262    }
263}
264impl From<std::io::Error> for Errno {
265    fn from(err: std::io::Error) -> Self {
266        let errno = err.raw_os_error().unwrap_or(0);
267        Errno::from_i32(errno)
268    }
269}
270impl From<nix::errno::Errno> for Errno {
271    fn from(err: nix::errno::Errno) -> Self {
272        Errno::from_i32(err as i32)
273    }
274}
275impl From<std::io::ErrorKind> for Errno {
276    fn from(x: std::io::ErrorKind) -> Self {
277        let err: std::io::Error = x.into();
278        err.into()
279    }
280}
281impl From<Errno> for i32 {
282    fn from(x: Errno) -> Self {
283        x.0.get()
284    }
285}
286
287/// A newtype for generation numbers
288///
289/// If the file system will be exported over NFS, the (ino, generation) pairs
290/// need to be unique over the file system's lifetime (rather than just the
291/// mount time). So if the file system reuses an inode after it has been
292/// deleted, it must assign a new, previously unused generation number to the
293/// inode at the same time.
294#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
295pub struct Generation(pub u64);
296impl From<Generation> for u64 {
297    fn from(fh: Generation) -> Self {
298        fh.0
299    }
300}
301
302#[cfg(test)]
303mod test {
304    use std::io::IoSlice;
305    use std::ops::Deref;
306    use std::ops::DerefMut;
307    /// If we want to be able to cast bytes to our fuse C struct types we need it
308    /// to be aligned.  This struct helps getting &[u8]s which are 8 byte aligned.
309    #[cfg(test)]
310    #[repr(align(8))]
311    pub(crate) struct AlignedData<T>(pub T);
312    impl<T> Deref for AlignedData<T> {
313        type Target = T;
314
315        fn deref(&self) -> &Self::Target {
316            &self.0
317        }
318    }
319    impl<T> DerefMut for AlignedData<T> {
320        fn deref_mut(&mut self) -> &mut Self::Target {
321            &mut self.0
322        }
323    }
324
325    pub(crate) fn ioslice_to_vec(s: &[IoSlice<'_>]) -> Vec<u8> {
326        let mut v = Vec::with_capacity(s.iter().map(|x| x.len()).sum());
327        for x in s {
328            v.extend_from_slice(x);
329        }
330        v
331    }
332}