1#![warn(
8 missing_docs,
9 missing_debug_implementations,
10 rust_2018_idioms,
11 unreachable_pub
12)]
13
14use std::cmp::max;
15use std::cmp::min;
16use std::convert::AsRef;
17use std::ffi::OsStr;
18use std::io;
19use std::os::unix::fs::FileTypeExt;
20use std::path::Path;
21use std::time::Duration;
22use std::time::SystemTime;
23
24use log::warn;
25#[cfg(target_os = "macos")]
26pub use reply::ReplyXTimes;
27#[cfg(feature = "serializable")]
28use serde::Deserialize;
29#[cfg(feature = "serializable")]
30use serde::Serialize;
31
32pub use crate::access_flags::AccessFlags;
33pub use crate::bsd_file_flags::BsdFileFlags;
34use crate::forget_one::ForgetOne;
35#[cfg(feature = "async")]
36pub use crate::lib_async::{AsyncFilesystem, mount_async};
37pub use crate::ll::Errno;
38pub use crate::ll::Generation;
39pub use crate::ll::RequestId;
40pub use crate::ll::TimeOrNow;
41pub use crate::ll::flags::copy_file_range_flags::CopyFileRangeFlags;
42pub use crate::ll::flags::fopen_flags::FopenFlags;
43pub use crate::ll::flags::init_flags::InitFlags;
44pub use crate::ll::flags::ioctl_flags::IoctlFlags;
45pub use crate::ll::flags::poll_flags::PollFlags;
46pub use crate::ll::flags::write_flags::WriteFlags;
47pub use crate::ll::fuse_abi::consts;
48#[cfg(feature = "async")]
49pub use crate::ll::reply_async;
50pub use crate::ll::request::FileHandle;
51pub use crate::ll::request::INodeNo;
52pub use crate::ll::request::LockOwner;
53pub use crate::ll::request::Version;
54pub use crate::mnt::mount_options::Config;
55pub use crate::mnt::mount_options::MountOption;
56pub use crate::notify::Notifier;
57pub use crate::notify::PollHandle;
58pub use crate::notify::PollNotifier;
59pub use crate::open_flags::OpenAccMode;
60pub use crate::open_flags::OpenFlags;
61pub use crate::passthrough::BackingId;
62pub use crate::poll_events::PollEvents;
63pub use crate::rename_flags::RenameFlags;
64pub use crate::reply::ReplyAttr;
65pub use crate::reply::ReplyBmap;
66pub use crate::reply::ReplyCreate;
67pub use crate::reply::ReplyData;
68pub use crate::reply::ReplyDirectory;
69pub use crate::reply::ReplyDirectoryPlus;
70pub use crate::reply::ReplyEmpty;
71pub use crate::reply::ReplyEntry;
72pub use crate::reply::ReplyIoctl;
73pub use crate::reply::ReplyLock;
74pub use crate::reply::ReplyLseek;
75pub use crate::reply::ReplyOpen;
76pub use crate::reply::ReplyPoll;
77pub use crate::reply::ReplyStatfs;
78pub use crate::reply::ReplyWrite;
79pub use crate::reply::ReplyXattr;
80pub use crate::request_param::Request;
81pub use crate::session::BackgroundSession;
82use crate::session::MAX_WRITE_SIZE;
83pub use crate::session::Session;
84pub use crate::session::SessionACL;
85pub use crate::session::SessionUnmounter;
86#[cfg(feature = "async")]
87pub use crate::session_async::{AsyncSession, AsyncSessionBuilder};
88
89mod access_flags;
90mod bsd_file_flags;
91mod channel;
92#[cfg(feature = "async")]
93mod channel_async;
94mod dev_fuse;
95#[cfg(feature = "async")]
96mod dev_fuse_async;
97#[cfg(feature = "experimental")]
98pub mod experimental;
99mod forget_one;
100#[cfg(feature = "async")]
101pub mod lib_async;
102mod ll;
103mod mnt;
104mod notify;
105mod open_flags;
106mod passthrough;
107mod poll_events;
108mod read_buf;
109mod rename_flags;
110mod reply;
111mod request;
112mod request_param;
113mod session;
114#[cfg(feature = "async")]
115mod session_async;
116mod time;
117
118#[cfg(not(target_os = "macos"))]
120const INIT_FLAGS: InitFlags = InitFlags::FUSE_ASYNC_READ.union(InitFlags::FUSE_BIG_WRITES);
121#[cfg(target_os = "macos")]
126const INIT_FLAGS: InitFlags = InitFlags::FUSE_ASYNC_READ
127 .union(InitFlags::FUSE_CASE_INSENSITIVE)
128 .union(InitFlags::FUSE_VOL_RENAME)
129 .union(InitFlags::FUSE_XTIMES);
130fn default_init_flags(capabilities: InitFlags) -> InitFlags {
133 let mut flags = INIT_FLAGS;
134 if capabilities.contains(InitFlags::FUSE_MAX_PAGES) {
135 flags |= InitFlags::FUSE_MAX_PAGES;
136 }
137 flags
138}
139
140#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
142#[cfg_attr(feature = "serializable", derive(Serialize, Deserialize))]
143pub enum FileType {
144 NamedPipe,
146 CharDevice,
148 BlockDevice,
150 Directory,
152 RegularFile,
154 Symlink,
156 Socket,
158}
159
160impl FileType {
161 pub fn from_std(file_type: std::fs::FileType) -> Option<Self> {
163 if file_type.is_file() {
164 Some(FileType::RegularFile)
165 } else if file_type.is_dir() {
166 Some(FileType::Directory)
167 } else if file_type.is_symlink() {
168 Some(FileType::Symlink)
169 } else if file_type.is_fifo() {
170 Some(FileType::NamedPipe)
171 } else if file_type.is_socket() {
172 Some(FileType::Socket)
173 } else if file_type.is_char_device() {
174 Some(FileType::CharDevice)
175 } else if file_type.is_block_device() {
176 Some(FileType::BlockDevice)
177 } else {
178 None
179 }
180 }
181}
182
183#[derive(Clone, Copy, Debug, Eq, PartialEq)]
185#[cfg_attr(feature = "serializable", derive(Serialize, Deserialize))]
186pub struct FileAttr {
187 pub ino: INodeNo,
189 pub size: u64,
191 pub blocks: u64,
194 pub atime: SystemTime,
196 pub mtime: SystemTime,
198 pub ctime: SystemTime,
200 pub crtime: SystemTime,
202 pub kind: FileType,
204 pub perm: u16,
206 pub nlink: u32,
208 pub uid: u32,
210 pub gid: u32,
212 pub rdev: u32,
214 pub blksize: u32,
216 pub flags: u32,
218}
219
220#[derive(Debug)]
222pub struct KernelConfig {
223 capabilities: InitFlags,
224 requested: InitFlags,
225 max_readahead: u32,
226 max_max_readahead: u32,
227 max_background: u16,
228 congestion_threshold: Option<u16>,
229 max_write: u32,
230 time_gran: Duration,
231 max_stack_depth: u32,
232 kernel_abi: Version,
233}
234
235impl KernelConfig {
236 fn new(capabilities: InitFlags, max_readahead: u32, kernel_abi: Version) -> Self {
237 Self {
238 capabilities,
239 requested: default_init_flags(capabilities),
240 max_readahead,
241 max_max_readahead: max_readahead,
242 max_background: 16,
243 congestion_threshold: None,
244 max_write: MAX_WRITE_SIZE as u32,
246 time_gran: Duration::new(0, 1),
248 max_stack_depth: 0,
249 kernel_abi,
250 }
251 }
252
253 pub fn set_max_stack_depth(&mut self, value: u32) -> Result<u32, u32> {
268 const FILESYSTEM_MAX_STACK_DEPTH: u32 = 2;
270
271 if value > FILESYSTEM_MAX_STACK_DEPTH {
272 return Err(FILESYSTEM_MAX_STACK_DEPTH);
273 }
274
275 let previous = self.max_stack_depth;
276 self.max_stack_depth = value;
277 Ok(previous)
278 }
279
280 pub fn set_time_granularity(&mut self, value: Duration) -> Result<Duration, Duration> {
288 if value.as_nanos() == 0 {
289 return Err(Duration::new(0, 1));
290 }
291 if value.as_secs() > 1 || (value.as_secs() == 1 && value.subsec_nanos() > 0) {
292 return Err(Duration::new(1, 0));
293 }
294 let mut power_of_10 = 1;
295 while power_of_10 < value.as_nanos() {
296 if value.as_nanos() < power_of_10 * 10 {
297 return Err(Duration::new(0, power_of_10 as u32));
299 }
300 power_of_10 *= 10;
301 }
302 let previous = self.time_gran;
303 self.time_gran = value;
304 Ok(previous)
305 }
306
307 pub fn set_max_write(&mut self, value: u32) -> Result<u32, u32> {
313 if value == 0 {
314 return Err(1);
315 }
316 if value > MAX_WRITE_SIZE as u32 {
317 return Err(MAX_WRITE_SIZE as u32);
318 }
319 let previous = self.max_write;
320 self.max_write = value;
321 Ok(previous)
322 }
323
324 pub fn set_max_readahead(&mut self, value: u32) -> Result<u32, u32> {
330 if value == 0 {
331 return Err(1);
332 }
333 if value > self.max_max_readahead {
334 return Err(self.max_max_readahead);
335 }
336 let previous = self.max_readahead;
337 self.max_readahead = value;
338 Ok(previous)
339 }
340
341 pub fn capabilities(&self) -> InitFlags {
343 self.capabilities & !InitFlags::FUSE_INIT_EXT
344 }
345
346 pub fn kernel_abi(&self) -> Version {
348 self.kernel_abi
349 }
350
351 pub fn add_capabilities(&mut self, capabilities_to_add: InitFlags) -> Result<(), InitFlags> {
356 if !self.capabilities.contains(capabilities_to_add) {
357 let unsupported = capabilities_to_add & !self.capabilities;
358 return Err(unsupported);
359 }
360 self.requested |= capabilities_to_add;
361 Ok(())
362 }
363
364 pub fn set_max_background(&mut self, value: u16) -> Result<u16, u16> {
370 if value == 0 {
371 return Err(1);
372 }
373 let previous = self.max_background;
374 self.max_background = value;
375 Ok(previous)
376 }
377
378 pub fn set_congestion_threshold(&mut self, value: u16) -> Result<u16, u16> {
385 if value == 0 {
386 return Err(1);
387 }
388 let previous = self.congestion_threshold();
389 self.congestion_threshold = Some(value);
390 Ok(previous)
391 }
392
393 fn congestion_threshold(&self) -> u16 {
394 match self.congestion_threshold {
395 None => (u32::from(self.max_background) * 3 / 4) as u16,
397 Some(value) => min(value, self.max_background),
398 }
399 }
400
401 fn max_pages(&self) -> u16 {
402 ((max(self.max_write, self.max_readahead) - 1) / page_size::get() as u32) as u16 + 1
403 }
404}
405
406#[allow(clippy::too_many_arguments)]
413pub trait Filesystem: Send + Sync + 'static {
414 fn init(&mut self, _req: &Request, _config: &mut KernelConfig) -> io::Result<()> {
418 Ok(())
419 }
420
421 fn destroy(&mut self) {}
424
425 fn lookup(&self, _req: &Request, parent: INodeNo, name: &OsStr, reply: ReplyEntry) {
427 warn!("[Not Implemented] lookup(parent: {parent:#x?}, name {name:?})");
428 reply.error(Errno::ENOSYS);
429 }
430
431 fn forget(&self, _req: &Request, _ino: INodeNo, _nlookup: u64) {}
439
440 fn batch_forget(&self, req: &Request, nodes: &[ForgetOne]) {
443 for node in nodes {
444 self.forget(req, node.nodeid(), node.nlookup());
445 }
446 }
447
448 fn getattr(&self, _req: &Request, ino: INodeNo, fh: Option<FileHandle>, reply: ReplyAttr) {
450 warn!("[Not Implemented] getattr(ino: {ino:#x?}, fh: {fh:#x?})");
451 reply.error(Errno::ENOSYS);
452 }
453
454 fn setattr(
456 &self,
457 _req: &Request,
458 ino: INodeNo,
459 mode: Option<u32>,
460 uid: Option<u32>,
461 gid: Option<u32>,
462 size: Option<u64>,
463 _atime: Option<TimeOrNow>,
464 _mtime: Option<TimeOrNow>,
465 _ctime: Option<SystemTime>,
466 fh: Option<FileHandle>,
467 _crtime: Option<SystemTime>,
468 _chgtime: Option<SystemTime>,
469 _bkuptime: Option<SystemTime>,
470 flags: Option<BsdFileFlags>,
471 reply: ReplyAttr,
472 ) {
473 warn!(
474 "[Not Implemented] setattr(ino: {ino:#x?}, mode: {mode:?}, uid: {uid:?}, \
475 gid: {gid:?}, size: {size:?}, fh: {fh:?}, flags: {flags:?})"
476 );
477 reply.error(Errno::ENOSYS);
478 }
479
480 fn readlink(&self, _req: &Request, ino: INodeNo, reply: ReplyData) {
482 warn!("[Not Implemented] readlink(ino: {ino:#x?})");
483 reply.error(Errno::ENOSYS);
484 }
485
486 fn mknod(
489 &self,
490 _req: &Request,
491 parent: INodeNo,
492 name: &OsStr,
493 mode: u32,
494 umask: u32,
495 rdev: u32,
496 reply: ReplyEntry,
497 ) {
498 warn!(
499 "[Not Implemented] mknod(parent: {parent:#x?}, name: {name:?}, \
500 mode: {mode}, umask: {umask:#x?}, rdev: {rdev})"
501 );
502 reply.error(Errno::ENOSYS);
503 }
504
505 fn mkdir(
507 &self,
508 _req: &Request,
509 parent: INodeNo,
510 name: &OsStr,
511 mode: u32,
512 umask: u32,
513 reply: ReplyEntry,
514 ) {
515 warn!(
516 "[Not Implemented] mkdir(parent: {parent:#x?}, name: {name:?}, mode: {mode}, umask: {umask:#x?})"
517 );
518 reply.error(Errno::ENOSYS);
519 }
520
521 fn unlink(&self, _req: &Request, parent: INodeNo, name: &OsStr, reply: ReplyEmpty) {
523 warn!("[Not Implemented] unlink(parent: {parent:#x?}, name: {name:?})",);
524 reply.error(Errno::ENOSYS);
525 }
526
527 fn rmdir(&self, _req: &Request, parent: INodeNo, name: &OsStr, reply: ReplyEmpty) {
529 warn!("[Not Implemented] rmdir(parent: {parent:#x?}, name: {name:?})",);
530 reply.error(Errno::ENOSYS);
531 }
532
533 fn symlink(
535 &self,
536 _req: &Request,
537 parent: INodeNo,
538 link_name: &OsStr,
539 target: &Path,
540 reply: ReplyEntry,
541 ) {
542 warn!(
543 "[Not Implemented] symlink(parent: {parent:#x?}, link_name: {link_name:?}, target: {target:?})",
544 );
545 reply.error(Errno::EPERM);
546 }
547
548 fn rename(
550 &self,
551 _req: &Request,
552 parent: INodeNo,
553 name: &OsStr,
554 newparent: INodeNo,
555 newname: &OsStr,
556 flags: RenameFlags,
557 reply: ReplyEmpty,
558 ) {
559 warn!(
560 "[Not Implemented] rename(parent: {parent:#x?}, name: {name:?}, \
561 newparent: {newparent:#x?}, newname: {newname:?}, flags: {flags})",
562 );
563 reply.error(Errno::ENOSYS);
564 }
565
566 fn link(
568 &self,
569 _req: &Request,
570 ino: INodeNo,
571 newparent: INodeNo,
572 newname: &OsStr,
573 reply: ReplyEntry,
574 ) {
575 warn!(
576 "[Not Implemented] link(ino: {ino:#x?}, newparent: {newparent:#x?}, newname: {newname:?})"
577 );
578 reply.error(Errno::EPERM);
579 }
580
581 fn open(&self, _req: &Request, _ino: INodeNo, _flags: OpenFlags, reply: ReplyOpen) {
590 reply.opened(FileHandle(0), FopenFlags::empty());
591 }
592
593 fn read(
604 &self,
605 _req: &Request,
606 ino: INodeNo,
607 fh: FileHandle,
608 offset: u64,
609 size: u32,
610 flags: OpenFlags,
611 lock_owner: Option<LockOwner>,
612 reply: ReplyData,
613 ) {
614 warn!(
615 "[Not Implemented] read(ino: {ino:#x?}, fh: {fh}, offset: {offset}, \
616 size: {size}, flags: {flags:#x?}, lock_owner: {lock_owner:?})"
617 );
618 reply.error(Errno::ENOSYS);
619 }
620
621 fn write(
634 &self,
635 _req: &Request,
636 ino: INodeNo,
637 fh: FileHandle,
638 offset: u64,
639 data: &[u8],
640 write_flags: WriteFlags,
641 flags: OpenFlags,
642 lock_owner: Option<LockOwner>,
643 reply: ReplyWrite,
644 ) {
645 warn!(
646 "[Not Implemented] write(ino: {ino:#x?}, fh: {fh}, offset: {offset}, \
647 data.len(): {}, write_flags: {write_flags:#x?}, flags: {flags:#x?}, \
648 lock_owner: {lock_owner:?})",
649 data.len()
650 );
651 reply.error(Errno::ENOSYS);
652 }
653
654 fn flush(
665 &self,
666 _req: &Request,
667 ino: INodeNo,
668 fh: FileHandle,
669 lock_owner: LockOwner,
670 reply: ReplyEmpty,
671 ) {
672 warn!("[Not Implemented] flush(ino: {ino:#x?}, fh: {fh}, lock_owner: {lock_owner:?})");
673 reply.error(Errno::ENOSYS);
674 }
675
676 fn release(
685 &self,
686 _req: &Request,
687 _ino: INodeNo,
688 _fh: FileHandle,
689 _flags: OpenFlags,
690 _lock_owner: Option<LockOwner>,
691 _flush: bool,
692 reply: ReplyEmpty,
693 ) {
694 reply.ok();
695 }
696
697 fn fsync(
701 &self,
702 _req: &Request,
703 ino: INodeNo,
704 fh: FileHandle,
705 datasync: bool,
706 reply: ReplyEmpty,
707 ) {
708 warn!("[Not Implemented] fsync(ino: {ino:#x?}, fh: {fh}, datasync: {datasync})");
709 reply.error(Errno::ENOSYS);
710 }
711
712 fn opendir(&self, _req: &Request, _ino: INodeNo, _flags: OpenFlags, reply: ReplyOpen) {
720 reply.opened(FileHandle(0), FopenFlags::empty());
721 }
722
723 fn readdir(
729 &self,
730 _req: &Request,
731 ino: INodeNo,
732 fh: FileHandle,
733 offset: u64,
734 reply: ReplyDirectory,
735 ) {
736 warn!("[Not Implemented] readdir(ino: {ino:#x?}, fh: {fh}, offset: {offset})");
737 reply.error(Errno::ENOSYS);
738 }
739
740 fn readdirplus(
746 &self,
747 _req: &Request,
748 ino: INodeNo,
749 fh: FileHandle,
750 offset: u64,
751 reply: ReplyDirectoryPlus,
752 ) {
753 warn!("[Not Implemented] readdirplus(ino: {ino:#x?}, fh: {fh}, offset: {offset})");
754 reply.error(Errno::ENOSYS);
755 }
756
757 fn releasedir(
762 &self,
763 _req: &Request,
764 _ino: INodeNo,
765 _fh: FileHandle,
766 _flags: OpenFlags,
767 reply: ReplyEmpty,
768 ) {
769 reply.ok();
770 }
771
772 fn fsyncdir(
777 &self,
778 _req: &Request,
779 ino: INodeNo,
780 fh: FileHandle,
781 datasync: bool,
782 reply: ReplyEmpty,
783 ) {
784 warn!("[Not Implemented] fsyncdir(ino: {ino:#x?}, fh: {fh}, datasync: {datasync})");
785 reply.error(Errno::ENOSYS);
786 }
787
788 fn statfs(&self, _req: &Request, _ino: INodeNo, reply: ReplyStatfs) {
790 reply.statfs(0, 0, 0, 0, 0, 512, 255, 0);
791 }
792
793 fn setxattr(
795 &self,
796 _req: &Request,
797 ino: INodeNo,
798 name: &OsStr,
799 _value: &[u8],
800 flags: i32,
801 position: u32,
802 reply: ReplyEmpty,
803 ) {
804 warn!(
805 "[Not Implemented] setxattr(ino: {ino:#x?}, name: {name:?}, \
806 flags: {flags:#x?}, position: {position})"
807 );
808 reply.error(Errno::ENOSYS);
809 }
810
811 fn getxattr(&self, _req: &Request, ino: INodeNo, name: &OsStr, size: u32, reply: ReplyXattr) {
816 warn!("[Not Implemented] getxattr(ino: {ino:#x?}, name: {name:?}, size: {size})");
817 reply.error(Errno::ENOSYS);
818 }
819
820 fn listxattr(&self, _req: &Request, ino: INodeNo, size: u32, reply: ReplyXattr) {
825 warn!("[Not Implemented] listxattr(ino: {ino:#x?}, size: {size})");
826 reply.error(Errno::ENOSYS);
827 }
828
829 fn removexattr(&self, _req: &Request, ino: INodeNo, name: &OsStr, reply: ReplyEmpty) {
831 warn!("[Not Implemented] removexattr(ino: {ino:#x?}, name: {name:?})");
832 reply.error(Errno::ENOSYS);
833 }
834
835 fn access(&self, _req: &Request, ino: INodeNo, mask: AccessFlags, reply: ReplyEmpty) {
840 warn!("[Not Implemented] access(ino: {ino:#x?}, mask: {mask})");
841 reply.error(Errno::ENOSYS);
842 }
843
844 fn create(
855 &self,
856 _req: &Request,
857 parent: INodeNo,
858 name: &OsStr,
859 mode: u32,
860 umask: u32,
861 flags: i32,
862 reply: ReplyCreate,
863 ) {
864 warn!(
865 "[Not Implemented] create(parent: {parent:#x?}, name: {name:?}, mode: {mode}, \
866 umask: {umask:#x?}, flags: {flags:#x?})"
867 );
868 reply.error(Errno::ENOSYS);
869 }
870
871 fn getlk(
873 &self,
874 _req: &Request,
875 ino: INodeNo,
876 fh: FileHandle,
877 lock_owner: LockOwner,
878 start: u64,
879 end: u64,
880 typ: i32,
881 pid: u32,
882 reply: ReplyLock,
883 ) {
884 warn!(
885 "[Not Implemented] getlk(ino: {ino:#x?}, fh: {fh}, lock_owner: {lock_owner}, \
886 start: {start}, end: {end}, typ: {typ}, pid: {pid})"
887 );
888 reply.error(Errno::ENOSYS);
889 }
890
891 fn setlk(
899 &self,
900 _req: &Request,
901 ino: INodeNo,
902 fh: FileHandle,
903 lock_owner: LockOwner,
904 start: u64,
905 end: u64,
906 typ: i32,
907 pid: u32,
908 sleep: bool,
909 reply: ReplyEmpty,
910 ) {
911 warn!(
912 "[Not Implemented] setlk(ino: {ino:#x?}, fh: {fh}, lock_owner: {lock_owner}, \
913 start: {start}, end: {end}, typ: {typ}, pid: {pid}, sleep: {sleep})"
914 );
915 reply.error(Errno::ENOSYS);
916 }
917
918 fn bmap(&self, _req: &Request, ino: INodeNo, blocksize: u32, idx: u64, reply: ReplyBmap) {
922 warn!("[Not Implemented] bmap(ino: {ino:#x?}, blocksize: {blocksize}, idx: {idx})",);
923 reply.error(Errno::ENOSYS);
924 }
925
926 fn ioctl(
928 &self,
929 _req: &Request,
930 ino: INodeNo,
931 fh: FileHandle,
932 flags: IoctlFlags,
933 cmd: u32,
934 in_data: &[u8],
935 out_size: u32,
936 reply: ReplyIoctl,
937 ) {
938 warn!(
939 "[Not Implemented] ioctl(ino: {ino:#x?}, fh: {fh}, flags: {flags}, \
940 cmd: {cmd}, in_data.len(): {}, out_size: {out_size})",
941 in_data.len()
942 );
943 reply.error(Errno::ENOSYS);
944 }
945
946 fn poll(
948 &self,
949 _req: &Request,
950 ino: INodeNo,
951 fh: FileHandle,
952 ph: PollNotifier,
953 events: PollEvents,
954 flags: PollFlags,
955 reply: ReplyPoll,
956 ) {
957 warn!(
958 "[Not Implemented] poll(ino: {ino:#x?}, fh: {fh}, \
959 ph: {ph:?}, events: {events}, flags: {flags})"
960 );
961 reply.error(Errno::ENOSYS);
962 }
963
964 fn fallocate(
966 &self,
967 _req: &Request,
968 ino: INodeNo,
969 fh: FileHandle,
970 offset: u64,
971 length: u64,
972 mode: i32,
973 reply: ReplyEmpty,
974 ) {
975 warn!(
976 "[Not Implemented] fallocate(ino: {ino:#x?}, fh: {fh}, \
977 offset: {offset}, length: {length}, mode: {mode})"
978 );
979 reply.error(Errno::ENOSYS);
980 }
981
982 fn lseek(
984 &self,
985 _req: &Request,
986 ino: INodeNo,
987 fh: FileHandle,
988 offset: i64,
989 whence: i32,
990 reply: ReplyLseek,
991 ) {
992 warn!(
993 "[Not Implemented] lseek(ino: {ino:#x?}, fh: {fh}, \
994 offset: {offset}, whence: {whence})"
995 );
996 reply.error(Errno::ENOSYS);
997 }
998
999 fn copy_file_range(
1001 &self,
1002 _req: &Request,
1003 ino_in: INodeNo,
1004 fh_in: FileHandle,
1005 offset_in: u64,
1006 ino_out: INodeNo,
1007 fh_out: FileHandle,
1008 offset_out: u64,
1009 len: u64,
1010 flags: CopyFileRangeFlags,
1011 reply: ReplyWrite,
1012 ) {
1013 warn!(
1014 "[Not Implemented] copy_file_range(ino_in: {ino_in:#x?}, fh_in: {fh_in}, \
1015 offset_in: {offset_in}, ino_out: {ino_out:#x?}, fh_out: {fh_out}, \
1016 offset_out: {offset_out}, len: {len}, flags: {flags:?})"
1017 );
1018 reply.error(Errno::ENOSYS);
1019 }
1020
1021 #[cfg(target_os = "macos")]
1024 fn setvolname(&self, _req: &Request, name: &OsStr, reply: ReplyEmpty) {
1025 warn!("[Not Implemented] setvolname(name: {name:?})");
1026 reply.error(Errno::ENOSYS);
1027 }
1028
1029 #[cfg(target_os = "macos")]
1031 fn exchange(
1032 &self,
1033 _req: &Request,
1034 parent: INodeNo,
1035 name: &OsStr,
1036 newparent: INodeNo,
1037 newname: &OsStr,
1038 options: u64,
1039 reply: ReplyEmpty,
1040 ) {
1041 warn!(
1042 "[Not Implemented] exchange(parent: {parent:#x?}, name: {name:?}, \
1043 newparent: {newparent:#x?}, newname: {newname:?}, options: {options})"
1044 );
1045 reply.error(Errno::ENOSYS);
1046 }
1047
1048 #[cfg(target_os = "macos")]
1051 fn getxtimes(&self, _req: &Request, ino: INodeNo, reply: ReplyXTimes) {
1052 warn!("[Not Implemented] getxtimes(ino: {ino:#x?})");
1053 reply.error(Errno::ENOSYS);
1054 }
1055}
1056
1057pub fn mount<FS: Filesystem, P: AsRef<Path>>(
1065 filesystem: FS,
1066 mountpoint: P,
1067 options: &Config,
1068) -> io::Result<()> {
1069 Session::new(filesystem, mountpoint.as_ref(), options).and_then(session::Session::run)
1070}
1071
1072pub fn spawn_mount<'a, FS: Filesystem + Send + 'static + 'a, P: AsRef<Path>>(
1082 filesystem: FS,
1083 mountpoint: P,
1084 options: &Config,
1085) -> io::Result<BackgroundSession> {
1086 Session::new(filesystem, mountpoint.as_ref(), options).and_then(session::Session::spawn)
1087}