blown_fuse/
io.rs

1use bytemuck::Zeroable;
2use nix::sys::stat::SFlag;
3
4use std::{
5    convert::Infallible,
6    ffi::OsStr,
7    future::Future,
8    ops::{ControlFlow, FromResidual, Try},
9    time::{SystemTime, UNIX_EPOCH},
10};
11
12use super::{Done, Operation, Reply, Request};
13use crate::{proto, Errno, FuseResult};
14
15#[doc(no_inline)]
16pub use nix::{
17    dir::Type as EntryType,
18    fcntl::OFlag as OpenFlags,
19    sys::stat::Mode,
20    unistd::{AccessFlags, Gid, Pid, Uid},
21};
22
23pub use proto::FsyncFlags;
24
25#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
26pub struct Ino(pub u64);
27
28#[derive(Copy, Clone, Eq, PartialEq)]
29pub struct Ttl {
30    seconds: u64,
31    nanoseconds: u32,
32}
33
34#[derive(Copy, Clone, Default, Eq, PartialEq)]
35pub struct Timestamp {
36    seconds: i64,
37    nanoseconds: u32,
38}
39
40pub enum Interruptible<'o, O: Operation<'o>, T> {
41    Completed(Reply<'o, O>, T),
42    Interrupted(Done<'o>),
43}
44
45pub trait Stat {
46    fn ino(&self) -> Ino;
47    fn inode_type(&self) -> EntryType;
48    fn attrs(&self) -> (Attrs, Ttl);
49}
50
51pub trait Known {
52    type Inode: Stat;
53
54    fn inode(&self) -> &Self::Inode;
55    fn unveil(self);
56}
57
58pub struct Failed<'o, E>(pub Done<'o>, pub E);
59
60pub trait Finish<'o, O: Operation<'o>> {
61    fn finish(&self, reply: Reply<'o, O>) -> Done<'o>;
62}
63
64#[derive(Clone)]
65pub struct Attrs(proto::Attrs);
66
67pub struct Entry<'a, K> {
68    pub offset: u64,
69    pub name: &'a OsStr,
70    pub inode: K,
71    pub ttl: Ttl,
72}
73
74#[derive(Copy, Clone)]
75pub struct FsInfo(proto::StatfsOut);
76
77impl Ino {
78    pub const NULL: Self = Ino(0);
79
80    pub const ROOT: Self = Ino(proto::ROOT_ID);
81
82    pub fn as_raw(self) -> u64 {
83        self.0
84    }
85}
86
87impl std::fmt::Display for Ino {
88    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89        write!(formatter, "{}", self.0)
90    }
91}
92
93impl Ttl {
94    pub const NULL: Self = Ttl {
95        seconds: 0,
96        nanoseconds: 0,
97    };
98
99    pub const MAX: Self = Ttl {
100        seconds: u64::MAX,
101        nanoseconds: u32::MAX,
102    };
103
104    pub fn new(seconds: u64, nanoseconds: u32) -> Ttl {
105        assert!(nanoseconds < 1_000_000_000);
106
107        Ttl {
108            seconds,
109            nanoseconds,
110        }
111    }
112
113    pub fn seconds(self) -> u64 {
114        self.seconds
115    }
116
117    pub fn nanoseconds(self) -> u32 {
118        self.nanoseconds
119    }
120}
121
122impl Timestamp {
123    pub fn new(seconds: i64, nanoseconds: u32) -> Self {
124        Timestamp {
125            seconds,
126            nanoseconds,
127        }
128    }
129}
130
131impl From<SystemTime> for Timestamp {
132    fn from(time: SystemTime) -> Self {
133        let (seconds, nanoseconds) = match time.duration_since(UNIX_EPOCH) {
134            Ok(duration) => {
135                let secs = duration.as_secs().try_into().unwrap();
136                (secs, duration.subsec_nanos())
137            }
138
139            Err(before_epoch) => {
140                let duration = before_epoch.duration();
141                let secs = -i64::try_from(duration.as_secs()).unwrap();
142                (secs, duration.subsec_nanos())
143            }
144        };
145
146        Timestamp {
147            seconds,
148            nanoseconds,
149        }
150    }
151}
152
153impl<'o, E> From<Failed<'o, E>> for Done<'o> {
154    fn from(failed: Failed<'o, E>) -> Done<'o> {
155        failed.0
156    }
157}
158
159impl<'o, O: Operation<'o>> Finish<'o, O> for Errno {
160    fn finish(&self, reply: Reply<'o, O>) -> Done<'o> {
161        reply.fail(*self)
162    }
163}
164
165impl<'o, O: Operation<'o>> Finish<'o, O> for std::io::Error {
166    fn finish(&self, reply: Reply<'o, O>) -> Done<'o> {
167        reply.fail(
168            self.raw_os_error()
169                .map(Errno::from_i32)
170                .unwrap_or(Errno::EIO),
171        )
172    }
173}
174
175impl<'o, O: Operation<'o>> Request<'o, O> {
176    pub fn ino(&self) -> Ino {
177        Ino(self.header.ino)
178    }
179
180    pub fn generation(&self) -> u64 {
181        0
182    }
183
184    pub fn uid(&self) -> Uid {
185        Uid::from_raw(self.header.uid)
186    }
187
188    pub fn gid(&self) -> Gid {
189        Gid::from_raw(self.header.gid)
190    }
191
192    pub fn pid(&self) -> Pid {
193        Pid::from_raw(self.header.pid as i32)
194    }
195}
196
197impl<'o, O: Operation<'o>> Reply<'o, O> {
198    pub async fn interruptible<F, T>(self, f: F) -> Interruptible<'o, O, T>
199    where
200        F: Future<Output = T>,
201    {
202        tokio::pin!(f);
203        let mut rx = self.session.interrupt_rx();
204
205        use Interruptible::*;
206        loop {
207            tokio::select! {
208                output = &mut f => break Completed(self, output),
209
210                result = rx.recv() => match result {
211                    Ok(unique) if unique == self.unique => {
212                        break Interrupted(self.interrupted());
213                    }
214
215                    _ => continue,
216                }
217            }
218        }
219    }
220
221    pub fn and_then<T, E>(self, result: Result<T, E>) -> Result<(Self, T), Failed<'o, E>>
222    where
223        E: Finish<'o, O>,
224    {
225        match result {
226            Ok(t) => Ok((self, t)),
227            Err(error) => {
228                let done = error.finish(self);
229                Err(Failed(done, error))
230            }
231        }
232    }
233
234    pub fn fail(self, errno: Errno) -> Done<'o> {
235        let result = self.session.fail(self.unique, errno as i32);
236        self.finish(result)
237    }
238
239    pub fn not_implemented(self) -> Done<'o> {
240        self.fail(Errno::ENOSYS)
241    }
242
243    pub fn not_permitted(self) -> Done<'o> {
244        self.fail(Errno::EPERM)
245    }
246
247    pub fn io_error(self) -> Done<'o> {
248        self.fail(Errno::EIO)
249    }
250
251    pub fn invalid_argument(self) -> Done<'o> {
252        self.fail(Errno::EINVAL)
253    }
254
255    pub fn interrupted(self) -> Done<'o> {
256        self.fail(Errno::EINTR)
257    }
258
259    pub(crate) fn finish(self, result: FuseResult<()>) -> Done<'o> {
260        if let Err(error) = result {
261            log::error!("Replying to request {}: {}", self.unique, error);
262        }
263
264        Done::new()
265    }
266}
267
268impl<'o, O: Operation<'o>> From<(Reply<'o, O>, Errno)> for Done<'o> {
269    fn from((reply, errno): (Reply<'o, O>, Errno)) -> Done<'o> {
270        reply.fail(errno)
271    }
272}
273
274impl<'o> FromResidual<Done<'o>> for Done<'o> {
275    fn from_residual(residual: Done<'o>) -> Self {
276        residual
277    }
278}
279
280impl<'o, T: Into<Done<'o>>> FromResidual<Result<Infallible, T>> for Done<'o> {
281    fn from_residual(residual: Result<Infallible, T>) -> Self {
282        match residual {
283            Ok(_) => unreachable!(),
284            Err(t) => t.into(),
285        }
286    }
287}
288
289impl<'o, O: Operation<'o>> FromResidual<Interruptible<'o, O, Infallible>> for Done<'o> {
290    fn from_residual(residual: Interruptible<'o, O, Infallible>) -> Self {
291        match residual {
292            Interruptible::Completed(_, _) => unreachable!(),
293            Interruptible::Interrupted(done) => done,
294        }
295    }
296}
297
298impl Try for Done<'_> {
299    type Output = Self;
300    type Residual = Self;
301
302    fn from_output(output: Self::Output) -> Self {
303        output
304    }
305
306    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
307        ControlFlow::Break(self)
308    }
309}
310
311impl<'o, O: Operation<'o>, T> FromResidual<Interruptible<'o, O, Infallible>>
312    for Interruptible<'o, O, T>
313{
314    fn from_residual(residual: Interruptible<'o, O, Infallible>) -> Self {
315        use Interruptible::*;
316
317        match residual {
318            Completed(_, _) => unreachable!(),
319            Interrupted(done) => Interrupted(done),
320        }
321    }
322}
323
324impl<'o, O: Operation<'o>, T> Try for Interruptible<'o, O, T> {
325    type Output = (Reply<'o, O>, T);
326    type Residual = Interruptible<'o, O, Infallible>;
327
328    fn from_output((reply, t): Self::Output) -> Self {
329        Self::Completed(reply, t)
330    }
331
332    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
333        use Interruptible::*;
334
335        match self {
336            Completed(reply, t) => ControlFlow::Continue((reply, t)),
337            Interrupted(done) => ControlFlow::Break(Interrupted(done)),
338        }
339    }
340}
341
342impl Attrs {
343    #[must_use]
344    pub fn size(self, size: u64) -> Self {
345        Attrs(proto::Attrs { size, ..self.0 })
346    }
347
348    #[must_use]
349    pub fn owner(self, uid: Uid, gid: Gid) -> Self {
350        Attrs(proto::Attrs {
351            uid: uid.as_raw(),
352            gid: gid.as_raw(),
353            ..self.0
354        })
355    }
356
357    #[must_use]
358    pub fn mode(self, mode: Mode) -> Self {
359        Attrs(proto::Attrs {
360            mode: mode.bits(),
361            ..self.0
362        })
363    }
364
365    #[must_use]
366    pub fn blocks(self, blocks: u64) -> Self {
367        Attrs(proto::Attrs { blocks, ..self.0 })
368    }
369
370    #[must_use]
371    pub fn block_size(self, block_size: u32) -> Self {
372        Attrs(proto::Attrs {
373            blksize: block_size,
374            ..self.0
375        })
376    }
377
378    #[must_use]
379    pub fn device(self, device: u32) -> Self {
380        Attrs(proto::Attrs {
381            rdev: device,
382            ..self.0
383        })
384    }
385
386    #[must_use]
387    pub fn times(self, access: Timestamp, modify: Timestamp, change: Timestamp) -> Self {
388        Attrs(proto::Attrs {
389            atime: access.seconds as _,
390            mtime: modify.seconds as _,
391            ctime: change.seconds as _,
392            atimensec: access.nanoseconds,
393            mtimensec: modify.nanoseconds,
394            ctimensec: change.nanoseconds,
395            ..self.0
396        })
397    }
398
399    #[must_use]
400    pub fn links(self, links: u32) -> Self {
401        Attrs(proto::Attrs {
402            nlink: links,
403            ..self.0
404        })
405    }
406
407    pub(crate) fn finish(self, inode: &impl Stat) -> proto::Attrs {
408        let Ino(ino) = inode.ino();
409        let inode_type = match inode.inode_type() {
410            EntryType::Fifo => SFlag::S_IFIFO,
411            EntryType::CharacterDevice => SFlag::S_IFCHR,
412            EntryType::Directory => SFlag::S_IFDIR,
413            EntryType::BlockDevice => SFlag::S_IFBLK,
414            EntryType::File => SFlag::S_IFREG,
415            EntryType::Symlink => SFlag::S_IFLNK,
416            EntryType::Socket => SFlag::S_IFSOCK,
417        };
418
419        proto::Attrs {
420            ino,
421            mode: self.0.mode | inode_type.bits(),
422            ..self.0
423        }
424    }
425}
426
427impl Default for Attrs {
428    fn default() -> Self {
429        Attrs(Zeroable::zeroed()).links(1)
430    }
431}
432
433impl FsInfo {
434    #[must_use]
435    pub fn blocks(self, size: u32, total: u64, free: u64, available: u64) -> Self {
436        FsInfo(proto::StatfsOut {
437            bsize: size,
438            blocks: total,
439            bfree: free,
440            bavail: available,
441            ..self.0
442        })
443    }
444
445    #[must_use]
446    pub fn inodes(self, total: u64, free: u64) -> Self {
447        FsInfo(proto::StatfsOut {
448            files: total,
449            ffree: free,
450            ..self.0
451        })
452    }
453
454    #[must_use]
455    pub fn max_filename(self, max: u32) -> Self {
456        FsInfo(proto::StatfsOut {
457            namelen: max,
458            ..self.0
459        })
460    }
461}
462
463impl Default for FsInfo {
464    fn default() -> Self {
465        FsInfo(Zeroable::zeroed())
466    }
467}
468
469impl From<FsInfo> for proto::StatfsOut {
470    fn from(FsInfo(statfs): FsInfo) -> proto::StatfsOut {
471        statfs
472    }
473}