confuse 0.1.0

A fuser-compatible filesystem API facade using Dokan on Windows and fuser elsewhere.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
#[cfg(feature = "serializable")]
use serde::Deserialize;
#[cfg(feature = "serializable")]
use serde::Serialize;
use std::fmt;
use std::num::NonZeroI32;
use std::time::Duration;
use std::time::SystemTime;

use bitflags::bitflags;

macro_rules! u64_newtype {
    ($name:ident) => {
        #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
        #[cfg_attr(feature = "serializable", derive(Serialize, Deserialize))]
        pub struct $name(pub u64);

        impl From<$name> for u64 {
            fn from(value: $name) -> Self {
                value.0
            }
        }

        impl fmt::Display for $name {
            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                fmt::Display::fmt(&self.0, f)
            }
        }
    };
    ($name:ident, no_hash) => {
        #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
        #[cfg_attr(feature = "serializable", derive(Serialize, Deserialize))]
        pub struct $name(pub u64);

        impl fmt::Display for $name {
            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                fmt::Display::fmt(&self.0, f)
            }
        }
    };
}

u64_newtype!(INodeNo);
u64_newtype!(FileHandle);
u64_newtype!(LockOwner, no_hash);

#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Generation(pub u64);

impl From<Generation> for u64 {
    fn from(value: Generation) -> Self {
        value.0
    }
}

impl INodeNo {
    pub const ROOT: Self = Self(1);
}

bitflags! {
    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
    pub struct InitFlags: u64 {
        const FUSE_ASYNC_READ = 1 << 0;
        const FUSE_POSIX_LOCKS = 1 << 1;
        const FUSE_FILE_OPS = 1 << 2;
        const FUSE_ATOMIC_O_TRUNC = 1 << 3;
        const FUSE_EXPORT_SUPPORT = 1 << 4;
        const FUSE_BIG_WRITES = 1 << 5;
        const FUSE_DONT_MASK = 1 << 6;
        const FUSE_SPLICE_WRITE = 1 << 7;
        const FUSE_SPLICE_MOVE = 1 << 8;
        const FUSE_SPLICE_READ = 1 << 9;
        const FUSE_FLOCK_LOCKS = 1 << 10;
        const FUSE_HAS_IOCTL_DIR = 1 << 11;
        const FUSE_AUTO_INVAL_DATA = 1 << 12;
        const FUSE_DO_READDIRPLUS = 1 << 13;
        const FUSE_READDIRPLUS_AUTO = 1 << 14;
        const FUSE_ASYNC_DIO = 1 << 15;
        const FUSE_WRITEBACK_CACHE = 1 << 16;
        const FUSE_NO_OPEN_SUPPORT = 1 << 17;
        const FUSE_PARALLEL_DIROPS = 1 << 18;
        const FUSE_HANDLE_KILLPRIV = 1 << 19;
        const FUSE_POSIX_ACL = 1 << 20;
        const FUSE_ABORT_ERROR = 1 << 21;
        const FUSE_MAX_PAGES = 1 << 22;
        const FUSE_CACHE_SYMLINKS = 1 << 23;
        const FUSE_NO_OPENDIR_SUPPORT = 1 << 24;
        const FUSE_EXPLICIT_INVAL_DATA = 1 << 25;
        const FUSE_MAP_ALIGNMENT = 1 << 26;
        const FUSE_SUBMOUNTS = 1 << 27;
        const FUSE_HANDLE_KILLPRIV_V2 = 1 << 28;
        const FUSE_SETXATTR_EXT = 1 << 29;
        const FUSE_INIT_EXT = 1 << 30;
        const FUSE_INIT_RESERVED = 1 << 31;
        const FUSE_SECURITY_CTX = 1 << 32;
        const FUSE_HAS_INODE_DAX = 1 << 33;
        const FUSE_CREATE_SUPP_GROUP = 1 << 34;
        const FUSE_HAS_EXPIRE_ONLY = 1 << 35;
        const FUSE_DIRECT_IO_ALLOW_MMAP = 1 << 36;
        const FUSE_PASSTHROUGH = 1 << 37;
        const FUSE_NO_EXPORT_SUPPORT = 1 << 38;
        const FUSE_HAS_RESEND = 1 << 39;
        const FUSE_ALLOW_IDMAP = 1 << 40;
        const FUSE_OVER_IO_URING = 1 << 41;
        const FUSE_REQUEST_TIMEOUT = 1 << 42;
        #[cfg(feature = "macos-api")]
        const FUSE_ALLOCATE = 1 << 27;
        #[cfg(feature = "macos-api")]
        const FUSE_EXCHANGE_DATA = 1 << 28;
        #[cfg(feature = "macos-api")]
        const FUSE_CASE_INSENSITIVE = 1 << 29;
        #[cfg(feature = "macos-api")]
        const FUSE_VOL_RENAME = 1 << 30;
        #[cfg(feature = "macos-api")]
        const FUSE_XTIMES = 1 << 31;
    }

    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
    pub struct FopenFlags: u32 {
        const FOPEN_DIRECT_IO = 1 << 0;
        const FOPEN_KEEP_CACHE = 1 << 1;
        const FOPEN_NONSEEKABLE = 1 << 2;
        const FOPEN_CACHE_DIR = 1 << 3;
        const FOPEN_STREAM = 1 << 4;
        const FOPEN_NOFLUSH = 1 << 5;
        const FOPEN_PARALLEL_DIRECT_WRITES = 1 << 6;
        const FOPEN_PASSTHROUGH = 1 << 7;
        #[cfg(feature = "macos-api")]
        const FOPEN_PURGE_ATTR = 1 << 30;
        #[cfg(feature = "macos-api")]
        const FOPEN_PURGE_UBC = 1 << 31;
    }

    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
    pub struct WriteFlags: u32 {
        const FUSE_WRITE_CACHE = 1 << 0;
        const FUSE_WRITE_LOCKOWNER = 1 << 1;
        const FUSE_WRITE_KILL_SUIDGID = 1 << 2;
    }

    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
    pub struct RenameFlags: u32 {
        #[cfg(target_os = "linux")]
        const RENAME_NOREPLACE = libc::RENAME_NOREPLACE;
        #[cfg(target_os = "linux")]
        const RENAME_EXCHANGE = libc::RENAME_EXCHANGE;
        #[cfg(target_os = "linux")]
        const RENAME_WHITEOUT = libc::RENAME_WHITEOUT;
    }

    #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
    pub struct AccessFlags: i32 {
        const F_OK = 0;
        const R_OK = 4;
        const W_OK = 2;
        const X_OK = 1;
    }

    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
    pub struct IoctlFlags: u32 {
        const FUSE_IOCTL_COMPAT = 1 << 0;
        const FUSE_IOCTL_UNRESTRICTED = 1 << 1;
        const FUSE_IOCTL_RETRY = 1 << 2;
        const FUSE_IOCTL_32BIT = 1 << 3;
        const FUSE_IOCTL_DIR = 1 << 4;
        const FUSE_IOCTL_COMPAT_X32 = 1 << 5;
    }

    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
    pub struct PollFlags: u32 {
        const FUSE_POLL_SCHEDULE_NOTIFY = 1 << 0;
    }

    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
    pub struct PollEvents: u32 {
        const POLLIN = 0x0001;
        const POLLPRI = 0x0002;
        const POLLOUT = 0x0004;
        const POLLERR = 0x0008;
        const POLLHUP = 0x0010;
        const POLLNVAL = 0x0020;
        const POLLRDNORM = 0x0040;
        const POLLRDBAND = 0x0080;
        const POLLWRNORM = 0x0100;
        const POLLWRBAND = 0x0200;
    }

    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
    pub struct CopyFileRangeFlags: u64 {}

    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
    pub struct BsdFileFlags: u32 {
        #[cfg(feature = "macos-api")]
        const UF_NODUMP = 0x0000_0001;
        #[cfg(feature = "macos-api")]
        const UF_IMMUTABLE = 0x0000_0002;
        #[cfg(feature = "macos-api")]
        const UF_APPEND = 0x0000_0004;
        #[cfg(feature = "macos-api")]
        const UF_OPAQUE = 0x0000_0008;
        #[cfg(feature = "macos-api")]
        const UF_HIDDEN = 0x0000_8000;
        #[cfg(feature = "macos-api")]
        const SF_ARCHIVED = 0x0001_0000;
        #[cfg(feature = "macos-api")]
        const SF_IMMUTABLE = 0x0002_0000;
        #[cfg(feature = "macos-api")]
        const SF_APPEND = 0x0004_0000;
    }
}

impl fmt::Display for AccessFlags {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.bits(), f)
    }
}

impl fmt::Display for RenameFlags {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.bits(), f)
    }
}

impl fmt::Display for PollEvents {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.bits(), f)
    }
}

#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[repr(i32)]
pub enum OpenAccMode {
    O_RDONLY = libc::O_RDONLY,
    O_WRONLY = libc::O_WRONLY,
    O_RDWR = libc::O_RDWR,
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct OpenFlags(pub i32);

impl OpenFlags {
    pub fn acc_mode(self) -> OpenAccMode {
        const O_ACCMODE: i32 = libc::O_RDONLY | libc::O_WRONLY | libc::O_RDWR;
        match self.0 & O_ACCMODE {
            libc::O_WRONLY => OpenAccMode::O_WRONLY,
            libc::O_RDWR => OpenAccMode::O_RDWR,
            _ => OpenAccMode::O_RDONLY,
        }
    }
}

impl std::fmt::LowerHex for OpenFlags {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        std::fmt::LowerHex::fmt(&self.0, f)
    }
}

impl std::fmt::UpperHex for OpenFlags {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        std::fmt::UpperHex::fmt(&self.0, f)
    }
}

#[derive(Clone, Copy, Debug)]
pub struct Errno(NonZeroI32);

impl Errno {
    pub const EPERM: Self = Self::from_raw_os_error(libc::EPERM);
    pub const ENOENT: Self = Self::from_raw_os_error(libc::ENOENT);
    pub const ESRCH: Self = Self::from_raw_os_error(libc::ESRCH);
    pub const EINTR: Self = Self::from_raw_os_error(libc::EINTR);
    pub const EIO: Self = Self::from_raw_os_error(libc::EIO);
    pub const ENXIO: Self = Self::from_raw_os_error(libc::ENXIO);
    pub const E2BIG: Self = Self::from_raw_os_error(libc::E2BIG);
    pub const ENOEXEC: Self = Self::from_raw_os_error(libc::ENOEXEC);
    pub const EBADF: Self = Self::from_raw_os_error(libc::EBADF);
    pub const ECHILD: Self = Self::from_raw_os_error(libc::ECHILD);
    pub const EAGAIN: Self = Self::from_raw_os_error(libc::EAGAIN);
    pub const ENOMEM: Self = Self::from_raw_os_error(libc::ENOMEM);
    pub const EACCES: Self = Self::from_raw_os_error(libc::EACCES);
    pub const EFAULT: Self = Self::from_raw_os_error(libc::EFAULT);
    pub const ENOTBLK: Self = Self::from_raw_os_error(15);
    pub const EBUSY: Self = Self::from_raw_os_error(libc::EBUSY);
    pub const EEXIST: Self = Self::from_raw_os_error(libc::EEXIST);
    pub const EXDEV: Self = Self::from_raw_os_error(libc::EXDEV);
    pub const ENODEV: Self = Self::from_raw_os_error(libc::ENODEV);
    pub const ENOTDIR: Self = Self::from_raw_os_error(libc::ENOTDIR);
    pub const EISDIR: Self = Self::from_raw_os_error(libc::EISDIR);
    pub const EINVAL: Self = Self::from_raw_os_error(libc::EINVAL);
    pub const ENFILE: Self = Self::from_raw_os_error(libc::ENFILE);
    pub const EMFILE: Self = Self::from_raw_os_error(libc::EMFILE);
    pub const ENOTTY: Self = Self::from_raw_os_error(libc::ENOTTY);
    pub const ETXTBSY: Self = Self::from_raw_os_error(libc::ETXTBSY);
    pub const EFBIG: Self = Self::from_raw_os_error(libc::EFBIG);
    pub const ENOSPC: Self = Self::from_raw_os_error(libc::ENOSPC);
    pub const ESPIPE: Self = Self::from_raw_os_error(libc::ESPIPE);
    pub const EROFS: Self = Self::from_raw_os_error(libc::EROFS);
    pub const EMLINK: Self = Self::from_raw_os_error(libc::EMLINK);
    pub const EPIPE: Self = Self::from_raw_os_error(libc::EPIPE);
    pub const EDOM: Self = Self::from_raw_os_error(libc::EDOM);
    pub const ERANGE: Self = Self::from_raw_os_error(libc::ERANGE);
    pub const EDEADLK: Self = Self::from_raw_os_error(libc::EDEADLK);
    pub const ENAMETOOLONG: Self = Self::from_raw_os_error(libc::ENAMETOOLONG);
    pub const ENOLCK: Self = Self::from_raw_os_error(libc::ENOLCK);
    pub const ENOSYS: Self = Self::from_raw_os_error(libc::ENOSYS);
    pub const ENOTEMPTY: Self = Self::from_raw_os_error(libc::ENOTEMPTY);
    pub const ELOOP: Self = Self::from_raw_os_error(libc::ELOOP);
    pub const EWOULDBLOCK: Self = Self::from_raw_os_error(libc::EWOULDBLOCK);
    pub const ENOMSG: Self = Self::from_raw_os_error(libc::ENOMSG);
    pub const EIDRM: Self = Self::from_raw_os_error(libc::EIDRM);
    pub const EREMOTE: Self = Self::from_raw_os_error(66);
    pub const ENOLINK: Self = Self::from_raw_os_error(libc::ENOLINK);
    pub const EPROTO: Self = Self::from_raw_os_error(libc::EPROTO);
    pub const EMULTIHOP: Self = Self::from_raw_os_error(72);
    pub const EBADMSG: Self = Self::from_raw_os_error(libc::EBADMSG);
    pub const EOVERFLOW: Self = Self::from_raw_os_error(libc::EOVERFLOW);
    pub const EILSEQ: Self = Self::from_raw_os_error(libc::EILSEQ);
    pub const EUSERS: Self = Self::from_raw_os_error(87);
    pub const ENOTSOCK: Self = Self::from_raw_os_error(libc::ENOTSOCK);
    pub const EDESTADDRREQ: Self = Self::from_raw_os_error(libc::EDESTADDRREQ);
    pub const EMSGSIZE: Self = Self::from_raw_os_error(libc::EMSGSIZE);
    pub const EPROTOTYPE: Self = Self::from_raw_os_error(libc::EPROTOTYPE);
    pub const ENOPROTOOPT: Self = Self::from_raw_os_error(libc::ENOPROTOOPT);
    pub const EPROTONOSUPPORT: Self = Self::from_raw_os_error(libc::EPROTONOSUPPORT);
    pub const ESOCKTNOSUPPORT: Self = Self::from_raw_os_error(94);
    pub const EOPNOTSUPP: Self = Self::from_raw_os_error(libc::EOPNOTSUPP);
    pub const EPFNOSUPPORT: Self = Self::from_raw_os_error(96);
    pub const EAFNOSUPPORT: Self = Self::from_raw_os_error(libc::EAFNOSUPPORT);
    pub const EADDRINUSE: Self = Self::from_raw_os_error(libc::EADDRINUSE);
    pub const EADDRNOTAVAIL: Self = Self::from_raw_os_error(libc::EADDRNOTAVAIL);
    pub const ENETDOWN: Self = Self::from_raw_os_error(libc::ENETDOWN);
    pub const ENETUNREACH: Self = Self::from_raw_os_error(libc::ENETUNREACH);
    pub const ENETRESET: Self = Self::from_raw_os_error(libc::ENETRESET);
    pub const ECONNABORTED: Self = Self::from_raw_os_error(libc::ECONNABORTED);
    pub const ECONNRESET: Self = Self::from_raw_os_error(libc::ECONNRESET);
    pub const ENOBUFS: Self = Self::from_raw_os_error(libc::ENOBUFS);
    pub const EISCONN: Self = Self::from_raw_os_error(libc::EISCONN);
    pub const ENOTCONN: Self = Self::from_raw_os_error(libc::ENOTCONN);
    pub const ESHUTDOWN: Self = Self::from_raw_os_error(108);
    pub const ETOOMANYREFS: Self = Self::from_raw_os_error(109);
    pub const ETIMEDOUT: Self = Self::from_raw_os_error(libc::ETIMEDOUT);
    pub const ECONNREFUSED: Self = Self::from_raw_os_error(libc::ECONNREFUSED);
    pub const EHOSTDOWN: Self = Self::from_raw_os_error(112);
    pub const EHOSTUNREACH: Self = Self::from_raw_os_error(libc::EHOSTUNREACH);
    pub const EALREADY: Self = Self::from_raw_os_error(libc::EALREADY);
    pub const EINPROGRESS: Self = Self::from_raw_os_error(libc::EINPROGRESS);
    pub const ESTALE: Self = Self::from_raw_os_error(116);
    pub const EDQUOT: Self = Self::from_raw_os_error(122);
    pub const ECANCELED: Self = Self::from_raw_os_error(libc::ECANCELED);
    pub const EOWNERDEAD: Self = Self::from_raw_os_error(libc::EOWNERDEAD);
    pub const ENOTRECOVERABLE: Self = Self::from_raw_os_error(libc::ENOTRECOVERABLE);
    pub const ENOTSUP: Self = Self::from_raw_os_error(libc::ENOTSUP);
    pub const EFTYPE: Self = Self::from_raw_os_error(79);
    pub const ENODATA: Self = Self::from_raw_os_error(libc::ENODATA);
    #[cfg(feature = "macos-api")]
    pub const ENOATTR: Self = Self::from_raw_os_error(93);
    #[cfg(feature = "macos-api")]
    pub const NO_XATTR: Self = Self::ENOATTR;
    #[cfg(not(feature = "macos-api"))]
    pub const NO_XATTR: Self = Self::ENODATA;

    pub const fn from_raw_os_error(error: i32) -> Self {
        match NonZeroI32::new(error) {
            Some(value) => Self(value),
            None => panic!("errno must be non-zero"),
        }
    }

    pub fn from_i32(error: i32) -> Self {
        NonZeroI32::new(error)
            .filter(|error| error.get() > 0)
            .map(Self)
            .unwrap_or(Self::EIO)
    }

    pub const fn code(self) -> i32 {
        self.0.get()
    }

    pub const fn raw_os_error(self) -> i32 {
        self.code()
    }
}

impl From<std::io::Error> for Errno {
    fn from(value: std::io::Error) -> Self {
        value
            .raw_os_error()
            .map(Self::from_i32)
            .unwrap_or(Self::EIO)
    }
}

impl From<std::io::ErrorKind> for Errno {
    fn from(value: std::io::ErrorKind) -> Self {
        std::io::Error::from(value).into()
    }
}

impl From<Errno> for i32 {
    fn from(value: Errno) -> Self {
        value.raw_os_error()
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serializable", derive(Serialize, Deserialize))]
pub struct RequestId(pub u64);

impl From<RequestId> for u64 {
    fn from(value: RequestId) -> Self {
        value.0
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serializable", derive(Serialize, Deserialize))]
pub struct Version(pub u32, pub u32);

impl fmt::Display for Version {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}.{}", self.0, self.1)
    }
}

#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)]
pub enum SessionACL {
    All,
    RootAndOwner,
    #[default]
    Owner,
}

#[derive(Debug, Clone, Default, Eq, PartialEq)]
#[non_exhaustive]
pub struct Config {
    pub mount_options: Vec<MountOption>,
    pub acl: SessionACL,
    pub n_threads: Option<usize>,
    pub clone_fd: bool,
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serializable", derive(Serialize, Deserialize))]
pub enum FileType {
    NamedPipe,
    CharDevice,
    BlockDevice,
    Directory,
    RegularFile,
    Symlink,
    Socket,
}

impl FileType {
    pub fn from_std(file_type: std::fs::FileType) -> Option<Self> {
        if file_type.is_file() {
            Some(Self::RegularFile)
        } else if file_type.is_dir() {
            Some(Self::Directory)
        } else if file_type.is_symlink() {
            Some(Self::Symlink)
        } else {
            None
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serializable", derive(Serialize, Deserialize))]
pub struct FileAttr {
    pub ino: INodeNo,
    pub size: u64,
    pub blocks: u64,
    pub atime: SystemTime,
    pub mtime: SystemTime,
    pub ctime: SystemTime,
    pub crtime: SystemTime,
    pub kind: FileType,
    pub perm: u16,
    pub nlink: u32,
    pub uid: u32,
    pub gid: u32,
    pub rdev: u32,
    pub blksize: u32,
    pub flags: u32,
}

#[derive(Debug)]
pub struct KernelConfig {
    pub(crate) max_write: u32,
    pub(crate) max_readahead: u32,
    pub(crate) max_max_readahead: u32,
    pub(crate) capabilities: InitFlags,
    pub(crate) requested: InitFlags,
    pub(crate) max_background: u16,
    pub(crate) congestion_threshold: Option<u16>,
    pub(crate) time_gran: Duration,
    pub(crate) max_stack_depth: u32,
    pub(crate) kernel_abi: Version,
}

impl KernelConfig {
    pub fn set_max_stack_depth(&mut self, value: u32) -> Result<u32, u32> {
        const FILESYSTEM_MAX_STACK_DEPTH: u32 = 2;
        if value > FILESYSTEM_MAX_STACK_DEPTH {
            return Err(FILESYSTEM_MAX_STACK_DEPTH);
        }
        let previous = self.max_stack_depth;
        self.max_stack_depth = value;
        Ok(previous)
    }

    pub fn set_max_write(&mut self, value: u32) -> Result<u32, u32> {
        if value == 0 {
            return Err(1);
        }
        const MAX_WRITE_SIZE: u32 = 16 * 1024 * 1024;
        if value > MAX_WRITE_SIZE {
            return Err(MAX_WRITE_SIZE);
        }
        let previous = self.max_write;
        self.max_write = value;
        Ok(previous)
    }

    pub fn set_max_readahead(&mut self, value: u32) -> Result<u32, u32> {
        if value == 0 {
            return Err(1);
        }
        if value > self.max_max_readahead {
            return Err(self.max_max_readahead);
        }
        let previous = self.max_readahead;
        self.max_readahead = value;
        Ok(previous)
    }

    pub fn capabilities(&self) -> InitFlags {
        self.capabilities & !InitFlags::FUSE_INIT_EXT
    }

    pub fn kernel_abi(&self) -> Version {
        self.kernel_abi
    }

    pub fn add_capabilities(&mut self, capabilities_to_add: InitFlags) -> Result<(), InitFlags> {
        if !self.capabilities.contains(capabilities_to_add) {
            return Err(capabilities_to_add & !self.capabilities);
        }
        self.requested |= capabilities_to_add;
        Ok(())
    }

    pub fn set_max_background(&mut self, value: u16) -> Result<u16, u16> {
        if value == 0 {
            return Err(1);
        }
        let previous = self.max_background;
        self.max_background = value;
        Ok(previous)
    }

    pub fn set_congestion_threshold(&mut self, value: u16) -> Result<u16, u16> {
        if value == 0 {
            return Err(1);
        }
        let previous = self
            .congestion_threshold
            .unwrap_or_else(|| (u32::from(self.max_background) * 3 / 4) as u16)
            .min(self.max_background);
        self.congestion_threshold = Some(value);
        Ok(previous)
    }

    pub fn set_time_granularity(&mut self, value: Duration) -> Result<Duration, Duration> {
        if value.as_nanos() == 0 {
            return Err(Duration::new(0, 1));
        }
        if value.as_secs() > 1 || (value.as_secs() == 1 && value.subsec_nanos() > 0) {
            return Err(Duration::new(1, 0));
        }
        let mut power_of_10: u128 = 1;
        let nanos = value.as_nanos();
        while power_of_10 < nanos {
            if nanos < power_of_10 * 10 {
                return Err(Duration::new(0, power_of_10 as u32));
            }
            power_of_10 *= 10;
        }
        let previous = self.time_gran;
        self.time_gran = value;
        Ok(previous)
    }
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum MountOption {
    FSName(String),
    Subtype(String),
    CUSTOM(String),
    AutoUnmount,
    DefaultPermissions,
    Dev,
    NoDev,
    Suid,
    NoSuid,
    RO,
    RW,
    Exec,
    NoExec,
    Atime,
    NoAtime,
    DirSync,
    Sync,
    Async,
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum TimeOrNow {
    SpecificTime(SystemTime),
    Now,
}

// ---------------------------------------------------------------------------
// Unit tests
// ---------------------------------------------------------------------------

#[cfg(test)]
mod tests;