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}