Skip to main content

fuser_ng/
types.rs

1// Public types exported by FuserNG.
2//
3// Copyright (c) 2016-2022 by William R. Fraser, 2026 by François NT
4//
5
6use crate::KernelConfig;
7use std::ffi::{OsStr, OsString};
8use std::ops::Deref;
9use std::path::{Path, PathBuf};
10use std::sync::Arc;
11use std::time::{Duration, SystemTime};
12
13pub type Inode = u64;
14
15/// Info about a request.
16#[derive(Clone, Copy, Debug)]
17pub struct RequestInfo {
18    /// The unique ID assigned to this request by FUSE.
19    pub unique: u64,
20    /// The user ID of the process making the request.
21    pub uid: u32,
22    /// The group ID of the process making the request.
23    pub gid: u32,
24    /// The process ID of the process making the request.
25    pub pid: u32,
26}
27
28/// A directory entry.
29#[derive(Clone, Debug)]
30pub struct DirectoryEntry {
31    /// Name of the entry
32    pub name: OsString,
33    /// Kind of file (directory, file, pipe, etc.)
34    pub kind: crate::FileType,
35}
36
37/// Filesystem statistics.
38#[derive(Clone, Copy, Debug)]
39pub struct Statfs {
40    /// Total data blocks in the filesystem
41    pub blocks: u64,
42    /// Free blocks in filesystem
43    pub bfree: u64,
44    /// Free blocks available to unprivileged user
45    pub bavail: u64,
46    /// Total file nodes in filesystem
47    pub files: u64,
48    /// Free file nodes in filesystem
49    pub ffree: u64,
50    /// Optimal transfer block size
51    pub bsize: u32,
52    /// Maximum length of filenames
53    pub namelen: u32,
54    /// Fragment size
55    pub frsize: u32,
56}
57
58/// File attributes.
59#[derive(Clone, Copy, Debug)]
60pub struct FileAttr {
61    /// Size in bytes
62    pub size: u64,
63    /// Size in blocks
64    pub blocks: u64,
65    /// Time of last access
66    pub atime: SystemTime,
67    /// Time of last modification
68    pub mtime: SystemTime,
69    /// Time of last metadata change
70    pub ctime: SystemTime,
71    /// Time of creation (macOS only)
72    pub crtime: SystemTime,
73    /// Kind of file (directory, file, pipe, etc.)
74    pub kind: crate::FileType,
75    /// Permissions
76    pub perm: u16,
77    /// Number of hard links
78    pub nlink: u32,
79    /// User ID
80    pub uid: u32,
81    /// Group ID
82    pub gid: u32,
83    /// Device ID (if special file)
84    pub rdev: u32,
85    /// block size
86    pub blksize: u32,
87    /// Flags (macOS only; see chflags(2))
88    pub flags: u32,
89}
90
91/// The return value for `create`: contains info on the newly-created file, as well as a handle to
92/// the opened file.
93#[derive(Clone, Debug)]
94pub struct CreatedEntry {
95    /// Entry cache time-to-live.
96    pub ttl: Duration,
97    /// Attributes returned for the created file.
98    pub attr: FileAttr,
99    /// File handle returned for the opened file.
100    pub fh: u64,
101    /// Open response flags returned to fuser.
102    pub flags: u32,
103}
104
105/// Represents the return value from the `listxattr` and `getxattr` calls, which can be either a
106/// size or contain data, depending on how they are called.
107#[derive(Clone, Debug)]
108pub enum Xattr {
109    /// Size needed to read the attribute value or name list.
110    Size(u32),
111    /// Attribute data or null-terminated attribute name list.
112    Data(Vec<u8>),
113}
114
115#[cfg(target_os = "macos")]
116#[derive(Clone, Debug)]
117pub struct XTimes {
118    pub bkuptime: SystemTime,
119    pub crtime: SystemTime,
120}
121
122pub type ResultEmpty = std::io::Result<()>;
123pub type ResultEntry = std::io::Result<(Duration, FileAttr)>;
124pub type ResultOpen = std::io::Result<(u64, u32)>;
125pub type ResultReaddir = std::io::Result<Vec<DirectoryEntry>>;
126pub type ResultData = std::io::Result<Vec<u8>>;
127pub type ResultSlice<'a> = std::io::Result<&'a [u8]>;
128pub type ResultWrite = std::io::Result<u32>;
129pub type ResultStatfs = std::io::Result<Statfs>;
130pub type ResultCreate = std::io::Result<CreatedEntry>;
131pub type ResultXattr = std::io::Result<Xattr>;
132
133#[cfg(target_os = "macos")]
134pub type ResultXTimes = std::io::Result<XTimes>;
135
136/// Dummy struct returned by the callback in the `read()` method. Cannot be constructed outside
137/// this crate, `read()` requires you to return it, thus ensuring that you don't forget to call the
138/// callback.
139pub struct CallbackResult {
140    pub(crate) _private: std::marker::PhantomData<()>,
141}
142
143/// Path resolved from an inode with the current inode number attached.
144#[derive(Debug, Clone)]
145pub struct ResolvedPath {
146    parent: Arc<PathBuf>,
147    name: Arc<OsStr>,
148    ino: Inode,
149}
150
151impl ResolvedPath {
152    /// Returns the full path by joining the parent path and entry name.
153    pub fn full_path(&self) -> PathBuf {
154        self.parent.join(self.name.as_ref())
155    }
156    /// Returns the final path component.
157    pub fn name(&self) -> &OsStr {
158        &self.name
159    }
160    /// Returns the inode associated with this resolved path.
161    pub fn ino(&self) -> Inode {
162        self.ino
163    }
164    /// Returns the parent directory path.
165    pub fn parent_path(&self) -> Arc<PathBuf> {
166        self.parent.clone()
167    }
168}
169
170/// Entry name resolved relative to a parent directory path.
171#[derive(Debug, Clone)]
172pub struct EntryName {
173    parent: Arc<PathBuf>,
174    //parent_ino: Inode,
175    name: Arc<OsStr>,
176}
177
178impl EntryName {
179    /// Attaches an inode to this entry name.
180    pub(crate) fn with(self, ino: Inode) -> ResolvedPath {
181        ResolvedPath {
182            parent: self.parent,
183            name: self.name,
184            ino,
185        }
186    }
187    /// Creates an entry name from a parent folder path and child name.
188    pub(crate) fn new(parent: FolderPath, name: Arc<OsStr>) -> Self {
189        Self {
190            parent: parent.0,
191            name,
192        }
193    }
194    /// Returns the full path by joining the parent path and entry name.
195    pub fn full_path(&self) -> PathBuf {
196        self.parent.join(self.name.as_ref())
197    }
198    /// Returns the final path component.
199    pub fn name(&self) -> &OsStr {
200        &self.name
201    }
202
203    /// Returns the parent directory path.
204    pub fn parent_path(&self) -> Arc<PathBuf> {
205        self.parent.clone()
206    }
207}
208
209/// Entry path passed to callbacks that may run before or after inode resolution.
210///
211/// Lookup is used while resolving a parent/name pair before an inode is attached.
212/// Resolved is used when the inode table already has an inode for the entry.
213#[derive(Debug, Clone)]
214pub enum EntryRef {
215    Lookup(EntryName),
216    Resolved(ResolvedPath),
217}
218
219impl EntryRef {
220    /// Returns the full path by joining the parent path and entry name.
221    pub fn full_path(&self) -> PathBuf {
222        match self {
223            EntryRef::Lookup(this) => this.full_path(),
224            EntryRef::Resolved(this) => this.full_path(),
225        }
226    }
227    /// Returns the final path component.
228    pub fn name(&self) -> &OsStr {
229        match self {
230            EntryRef::Lookup(this) => this.name(),
231            EntryRef::Resolved(this) => this.name(),
232        }
233    }
234    /// Returns the parent directory path.
235    pub fn parent_path(&self) -> Arc<PathBuf> {
236        match self {
237            EntryRef::Lookup(this) => this.parent_path(),
238            EntryRef::Resolved(this) => this.parent_path(),
239        }
240    }
241}
242
243/// Shared path for a directory entry in the inode table.
244#[repr(transparent)]
245#[derive(Debug)]
246pub(crate) struct FolderPath(Arc<PathBuf>);
247
248impl From<Arc<PathBuf>> for FolderPath {
249    fn from(value: Arc<PathBuf>) -> Self {
250        Self(value)
251    }
252}
253
254impl From<&OsStr> for FolderPath {
255    fn from(value: &OsStr) -> Self {
256        Self(Arc::new(value.into()))
257    }
258}
259
260impl Deref for FolderPath {
261    type Target = Arc<PathBuf>;
262    fn deref(&self) -> &Self::Target {
263        &self.0
264    }
265}
266
267fn enosys_error<T>() -> std::io::Result<T> {
268    Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
269}
270
271/// This trait must be implemented to implement a filesystem with FuserNG.
272///
273/// Methods have default ENOSYS implementations, so a filesystem can implement only the operations
274/// it supports.
275///
276/// ```no_run
277/// use std::io;
278/// use std::time::{Duration, SystemTime};
279///
280/// use fuser_ng::{EntryRef, FileAttr, FileType, Filesystem, RequestInfo, ResultEntry};
281///
282/// struct RootOnly;
283///
284/// impl Filesystem for RootOnly {
285///     fn getattr(&self, _req: RequestInfo, path: &EntryRef, _fh: Option<u64>) -> ResultEntry {
286///         if path.full_path() != std::path::Path::new("/") {
287///             return Err(io::Error::from_raw_os_error(libc::ENOENT));
288///         }
289///
290///         let now = SystemTime::now();
291///
292///         Ok((
293///             Duration::from_secs(1),
294///             FileAttr {
295///                 size: 0,
296///                 blocks: 0,
297///                 atime: now,
298///                 mtime: now,
299///                 ctime: now,
300///                 crtime: now,
301///                 kind: FileType::Directory,
302///                 perm: 0o755,
303///                 nlink: 2,
304///                 uid: 0,
305///                 gid: 0,
306///                 rdev: 0,
307///                 blksize: 512,
308///                 flags: 0,
309///             },
310///         ))
311///     }
312/// }
313/// ```
314#[allow(unused_variables)]
315pub trait Filesystem {
316    /// Called on mount, before any other function.
317    fn init(&self, req: RequestInfo, config: &mut KernelConfig) -> ResultEmpty {
318        Ok(())
319    }
320
321    /// Called on filesystem unmount.
322    fn destroy(&self) {
323        // Nothing.
324    }
325
326    /// Get the attributes of a filesystem entry.
327    ///
328    /// * `fh`: a file handle if this is called on an open file.
329    fn getattr(&self, req: RequestInfo, path: &EntryRef, fh: Option<u64>) -> ResultEntry {
330        enosys_error()
331    }
332
333    // The following operations in the FUSE C API are all one kernel call: setattr
334    // We split them out to match the C API's behavior.
335
336    /// Change the mode of a filesystem entry.
337    ///
338    /// * `fh`: a file handle if this is called on an open file.
339    /// * `mode`: the mode to change the file to.
340    fn chmod(
341        &self,
342        req: RequestInfo,
343        path: &ResolvedPath,
344        fh: Option<u64>,
345        mode: u32,
346    ) -> ResultEmpty {
347        enosys_error()
348    }
349
350    /// Change the owner UID and/or group GID of a filesystem entry.
351    ///
352    /// * `fh`: a file handle if this is called on an open file.
353    /// * `uid`: user ID to change the file's owner to. If `None`, leave the UID unchanged.
354    /// * `gid`: group ID to change the file's group to. If `None`, leave the GID unchanged.
355    fn chown(
356        &self,
357        req: RequestInfo,
358        path: &ResolvedPath,
359        fh: Option<u64>,
360        uid: Option<u32>,
361        gid: Option<u32>,
362    ) -> ResultEmpty {
363        enosys_error()
364    }
365
366    /// Set the length of a file.
367    ///
368    /// * `fh`: a file handle if this is called on an open file.
369    /// * `size`: size in bytes to set as the file's length.
370    fn truncate(
371        &self,
372        req: RequestInfo,
373        path: &ResolvedPath,
374        fh: Option<u64>,
375        size: u64,
376    ) -> ResultEmpty {
377        enosys_error()
378    }
379
380    /// Set timestamps of a filesystem entry.
381    ///
382    /// * `fh`: a file handle if this is called on an open file.
383    /// * `atime`: the time of last access.
384    /// * `mtime`: the time of last modification.
385    fn utimens(
386        &self,
387        req: RequestInfo,
388        path: &ResolvedPath,
389        fh: Option<u64>,
390        atime: Option<SystemTime>,
391        mtime: Option<SystemTime>,
392    ) -> ResultEmpty {
393        enosys_error()
394    }
395
396    /// Set timestamps of a filesystem entry (with extra options only used on MacOS).
397    #[allow(clippy::too_many_arguments)]
398    fn utimens_macos(
399        &self,
400        req: RequestInfo,
401        path: &ResolvedPath,
402        fh: Option<u64>,
403        crtime: Option<SystemTime>,
404        chgtime: Option<SystemTime>,
405        bkuptime: Option<SystemTime>,
406        flags: Option<u32>,
407    ) -> ResultEmpty {
408        enosys_error()
409    }
410
411    // END OF SETATTR FUNCTIONS
412
413    /// Read a symbolic link.
414    fn readlink(&self, req: RequestInfo, path: &ResolvedPath) -> ResultData {
415        enosys_error()
416    }
417
418    /// Create a special file.
419    ///
420    /// * `parent`: path to the directory to make the entry under.
421    /// * `name`: name of the entry.
422    /// * `mode`: mode for the new entry.
423    /// * `rdev`: if mode has the bits `S_IFCHR` or `S_IFBLK` set, this is the major and minor numbers for the device file. Otherwise it should be ignored.
424    fn mknod(&self, req: RequestInfo, entry: &EntryName, mode: u32, rdev: u32) -> ResultEntry {
425        enosys_error()
426    }
427
428    /// Create a directory.
429    ///
430    /// * `parent`: path to the directory to make the directory under.
431    /// * `name`: name of the directory.
432    /// * `mode`: permissions for the new directory.
433    fn mkdir(&self, req: RequestInfo, entry: &EntryName, mode: u32) -> ResultEntry {
434        enosys_error()
435    }
436
437    /// Remove a file.
438    ///
439    /// * `parent`: path to the directory containing the file to delete.
440    /// * `name`: name of the file to delete.
441    fn unlink(&self, req: RequestInfo, entry: &EntryName) -> ResultEmpty {
442        enosys_error()
443    }
444
445    /// Remove a directory.
446    ///
447    /// * `parent`: path to the directory containing the directory to delete.
448    /// * `name`: name of the directory to delete.
449    fn rmdir(&self, req: RequestInfo, entry: &EntryName) -> ResultEmpty {
450        enosys_error()
451    }
452
453    /// Create a symbolic link.
454    ///
455    /// * `parent`: path to the directory to make the link in.
456    /// * `name`: name of the symbolic link.
457    /// * `target`: path (may be relative or absolute) to the target of the link.
458    fn symlink(&self, req: RequestInfo, entry: &EntryName, target: &Path) -> ResultEntry {
459        enosys_error()
460    }
461
462    /// Rename a filesystem entry.
463    ///
464    /// * `parent`: path to the directory containing the existing entry.
465    /// * `name`: name of the existing entry.
466    /// * `newparent`: path to the directory it should be renamed into (may be the same as `parent`).
467    /// * `newname`: name of the new entry.
468    fn rename(&self, req: RequestInfo, entry: &EntryName, new_entry: &EntryName) -> ResultEmpty {
469        enosys_error()
470    }
471
472    /// Create a hard link.
473    ///
474    /// * `path`: path to an existing file.
475    /// * `newparent`: path to the directory for the new link.
476    /// * `newname`: name for the new link.
477    fn link(&self, req: RequestInfo, path: &ResolvedPath, new_entry: &EntryName) -> ResultEntry {
478        enosys_error()
479    }
480
481    /// Open a file.
482    ///
483    /// * `path`: path to the file.
484    /// * `flags`: one of `O_RDONLY`, `O_WRONLY`, or `O_RDWR`, plus maybe additional flags.
485    ///
486    /// Return a tuple of (file handle, flags). The file handle will be passed to any subsequent
487    /// calls that operate on the file, and can be any value you choose, though it should allow
488    /// your filesystem to identify the file opened even without any path info.
489    fn open(&self, req: RequestInfo, path: &ResolvedPath, flags: u32) -> ResultOpen {
490        enosys_error()
491    }
492
493    /// Read from a file.
494    ///
495    /// Note that it is not an error for this call to request to read past the end of the file, and
496    /// you should only return data up to the end of the file (i.e. the number of bytes returned
497    /// will be fewer than requested; possibly even zero). Do not extend the file in this case.
498    ///
499    /// * `path`: path to the file.
500    /// * `fh`: file handle returned from the `open` call.
501    /// * `offset`: offset into the file to start reading.
502    /// * `size`: number of bytes to read.
503    /// * `callback`: a callback that must be invoked to return the result of the operation: either
504    ///   the result data as a slice, or an error code.
505    ///
506    /// Return the return value from the `callback` function.
507    fn read(
508        &self,
509        req: RequestInfo,
510        path: &ResolvedPath,
511        fh: u64,
512        offset: u64,
513        size: u32,
514        callback: impl FnOnce(ResultSlice<'_>) -> CallbackResult,
515    ) -> CallbackResult {
516        callback(enosys_error())
517    }
518
519    /// Write to a file.
520    ///
521    /// * `path`: path to the file.
522    /// * `fh`: file handle returned from the `open` call.
523    /// * `offset`: offset into the file to start writing.
524    /// * `data`: the data to write
525    /// * `flags`:
526    ///
527    /// Return the number of bytes written.
528    fn write(
529        &self,
530        req: RequestInfo,
531        path: &ResolvedPath,
532        fh: u64,
533        offset: u64,
534        data: Vec<u8>,
535        flags: u32,
536    ) -> ResultWrite {
537        enosys_error()
538    }
539
540    /// Called each time a program calls `close` on an open file.
541    ///
542    /// Note that because file descriptors can be duplicated (by `dup`, `dup2`, `fork`) this may be
543    /// called multiple times for a given file handle. The main use of this function is if the
544    /// filesystem would like to return an error to the `close` call. Note that most programs
545    /// ignore the return value of `close`, though.
546    ///
547    /// * `path`: path to the file.
548    /// * `fh`: file handle returned from the `open` call.
549    /// * `lock_owner`: if the filesystem supports locking (`setlk`, `getlk`), remove all locks
550    ///   belonging to this lock owner.
551    fn flush(
552        &self,
553        req: RequestInfo,
554        path: &ResolvedPath,
555        fh: u64,
556        lock_owner: u64,
557    ) -> ResultEmpty {
558        enosys_error()
559    }
560
561    /// Called when an open file is closed.
562    ///
563    /// There will be one of these for each `open` call. After `release`, no more calls will be
564    /// made with the given file handle.
565    ///
566    /// * `path`: path to the file.
567    /// * `fh`: file handle returned from the `open` call.
568    /// * `flags`: the flags passed when the file was opened.
569    /// * `lock_owner`: if the filesystem supports locking (`setlk`, `getlk`), remove all locks
570    ///   belonging to this lock owner.
571    /// * `flush`: whether pending data must be flushed or not.
572    fn release(
573        &self,
574        req: RequestInfo,
575        path: &ResolvedPath,
576        fh: u64,
577        flags: u32,
578        lock_owner: u64,
579        flush: bool,
580    ) -> ResultEmpty {
581        enosys_error()
582    }
583
584    /// Write out any pending changes of a file.
585    ///
586    /// When this returns, data should be written to persistent storage.
587    ///
588    /// * `path`: path to the file.
589    /// * `fh`: file handle returned from the `open` call.
590    /// * `datasync`: if `false`, also write metadata, otherwise just write file data.
591    fn fsync(&self, req: RequestInfo, path: &ResolvedPath, fh: u64, datasync: bool) -> ResultEmpty {
592        enosys_error()
593    }
594
595    /// Open a directory.
596    ///
597    /// Analogous to the `opend` call.
598    ///
599    /// * `path`: path to the directory.
600    /// * `flags`: file access flags. Will contain `O_DIRECTORY` at least.
601    ///
602    /// Return a tuple of (file handle, flags). The file handle will be passed to any subsequent
603    /// calls that operate on the directory, and can be any value you choose, though it should
604    /// allow your filesystem to identify the directory opened even without any path info.
605    fn opendir(&self, req: RequestInfo, path: &ResolvedPath, flags: u32) -> ResultOpen {
606        enosys_error()
607    }
608
609    /// Get the entries of a directory.
610    ///
611    /// * `path`: path to the directory.
612    /// * `fh`: file handle returned from the `opendir` call.
613    ///
614    /// Return all the entries of the directory.
615    fn readdir(&self, req: RequestInfo, path: &ResolvedPath, fh: u64) -> ResultReaddir {
616        enosys_error()
617    }
618
619    /// Close an open directory.
620    ///
621    /// This will be called exactly once for each `opendir` call.
622    ///
623    /// * `path`: path to the directory.
624    /// * `fh`: file handle returned from the `opendir` call.
625    /// * `flags`: the file access flags passed to the `opendir` call.
626    fn releasedir(
627        &self,
628        req: RequestInfo,
629        path: &ResolvedPath,
630        fh: u64,
631        flags: u32,
632    ) -> ResultEmpty {
633        enosys_error()
634    }
635
636    /// Write out any pending changes to a directory.
637    ///
638    /// Analogous to the `fsync` call.
639    fn fsyncdir(
640        &self,
641        req: RequestInfo,
642        path: &ResolvedPath,
643        fh: u64,
644        datasync: bool,
645    ) -> ResultEmpty {
646        enosys_error()
647    }
648
649    /// Get filesystem statistics.
650    ///
651    /// * `path`: path to some folder in the filesystem.
652    ///
653    /// See the `Statfs` struct for more details.
654    fn statfs(&self, req: RequestInfo, path: &ResolvedPath) -> ResultStatfs {
655        enosys_error()
656    }
657
658    /// Set a file extended attribute.
659    ///
660    /// * `path`: path to the file.
661    /// * `name`: attribute name.
662    /// * `value`: the data to set the value to.
663    /// * `flags`: can be either `XATTR_CREATE` or `XATTR_REPLACE`.
664    /// * `position`: offset into the attribute value to write data.
665    fn setxattr(
666        &self,
667        req: RequestInfo,
668        path: &ResolvedPath,
669        name: &OsStr,
670        value: &[u8],
671        flags: u32,
672        position: u32,
673    ) -> ResultEmpty {
674        enosys_error()
675    }
676
677    /// Get a file extended attribute.
678    ///
679    /// * `path`: path to the file
680    /// * `name`: attribute name.
681    /// * `size`: the maximum number of bytes to read.
682    ///
683    /// If `size` is 0, return `Xattr::Size(n)` where `n` is the size of the attribute data.
684    /// Otherwise, return `Xattr::Data(data)` with the requested data.
685    fn getxattr(
686        &self,
687        req: RequestInfo,
688        path: &ResolvedPath,
689        name: &OsStr,
690        size: u32,
691    ) -> ResultXattr {
692        enosys_error()
693    }
694
695    /// List extended attributes for a file.
696    ///
697    /// * `path`: path to the file.
698    /// * `size`: maximum number of bytes to return.
699    ///
700    /// If `size` is 0, return `Xattr::Size(n)` where `n` is the size required for the list of
701    /// attribute names.
702    /// Otherwise, return `Xattr::Data(data)` where `data` is all the null-terminated attribute
703    /// names.
704    fn listxattr(&self, req: RequestInfo, path: &ResolvedPath, size: u32) -> ResultXattr {
705        enosys_error()
706    }
707
708    /// Remove an extended attribute for a file.
709    ///
710    /// * `path`: path to the file.
711    /// * `name`: name of the attribute to remove.
712    fn removexattr(&self, req: RequestInfo, path: &ResolvedPath, name: &OsStr) -> ResultEmpty {
713        enosys_error()
714    }
715
716    /// Check for access to a file.
717    ///
718    /// * `path`: path to the file.
719    /// * `mask`: mode bits to check for access to.
720    ///
721    /// Return `Ok(())` if all requested permissions are allowed, otherwise return `Err(EACCES)`
722    /// or other error code as appropriate (e.g. `ENOENT` if the file doesn't exist).
723    fn access(&self, req: RequestInfo, path: &ResolvedPath, mask: u32) -> ResultEmpty {
724        enosys_error()
725    }
726
727    /// Create and open a new file.
728    ///
729    /// * `parent`: path to the directory to create the file in.
730    /// * `name`: name of the file to be created.
731    /// * `mode`: the mode to set on the new file.
732    /// * `flags`: flags like would be passed to `open`.
733    ///
734    /// Return a `CreatedEntry` (which contains the new file's attributes as well as a file handle
735    /// -- see documentation on `open` for more info on that).
736    fn create(&self, req: RequestInfo, path: &ResolvedPath, mode: u32, flags: u32) -> ResultCreate {
737        enosys_error()
738    }
739
740    // getlk
741
742    // setlk
743
744    // bmap
745
746    /// macOS only: Rename the volume.
747    ///
748    /// * `name`: new name for the volume
749    #[cfg(target_os = "macos")]
750    fn setvolname(&self, req: RequestInfo, name: &OsStr) -> ResultEmpty {
751        enosys_error()
752    }
753
754    // exchange (macOS only, undocumented)
755
756    /// macOS only: Query extended times (bkuptime and crtime).
757    ///
758    /// * `path`: path to the file to get the times for.
759    ///
760    /// Return an `XTimes` struct with the times, or other error code as appropriate.
761    #[cfg(target_os = "macos")]
762    fn getxtimes(&self, req: RequestInfo, path: &ResolvedPath) -> ResultXTimes {
763        Err(libc::ENOSYS)
764    }
765}