1#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
8
9use libc::{ENOSYS, EPERM, c_int};
10use log::warn;
11use mnt::mount_options::parse_options_from_args;
12#[cfg(feature = "serializable")]
13use serde::{Deserialize, Serialize};
14use std::ffi::OsStr;
15use std::io;
16use std::path::Path;
17#[cfg(feature = "abi-7-23")]
18use std::time::Duration;
19use std::time::SystemTime;
20use std::{convert::AsRef, io::ErrorKind};
21
22pub use crate::ll::fuse_abi::FUSE_ROOT_ID;
23use crate::ll::fuse_abi::consts::*;
24pub use crate::ll::{TimeOrNow, fuse_abi::consts};
25use crate::mnt::mount_options::check_option_conflicts;
26use crate::session::MAX_WRITE_SIZE;
27pub use ll::fuse_abi::fuse_forget_one;
28pub use mnt::mount_options::MountOption;
29pub use notify::{Notifier, PollHandle};
30#[cfg(feature = "abi-7-40")]
31pub use passthrough::BackingId;
32pub use reply::ReplyPoll;
33#[cfg(target_os = "macos")]
34pub use reply::ReplyXTimes;
35pub use reply::ReplyXattr;
36pub use reply::{Reply, ReplyAttr, ReplyData, ReplyEmpty, ReplyEntry, ReplyOpen};
37pub use reply::{
38 ReplyBmap, ReplyCreate, ReplyDirectory, ReplyDirectoryPlus, ReplyIoctl, ReplyLock, ReplyLseek,
39 ReplyStatfs, ReplyWrite,
40};
41pub use request::Request;
42pub use session::{BackgroundSession, Session, SessionACL, SessionUnmounter};
43#[cfg(feature = "abi-7-28")]
44use std::cmp::max;
45use std::cmp::min;
46
47mod channel;
48mod ll;
49mod mnt;
50mod notify;
51#[cfg(feature = "abi-7-40")]
52mod passthrough;
53mod reply;
54mod request;
55mod session;
56
57#[cfg(not(target_os = "macos"))]
59const INIT_FLAGS: u64 = FUSE_ASYNC_READ | FUSE_BIG_WRITES;
60#[cfg(target_os = "macos")]
65const INIT_FLAGS: u64 = FUSE_ASYNC_READ | FUSE_CASE_INSENSITIVE | FUSE_VOL_RENAME | FUSE_XTIMES;
66const fn default_init_flags(#[allow(unused_variables)] capabilities: u64) -> u64 {
69 #[cfg(not(feature = "abi-7-28"))]
70 {
71 INIT_FLAGS
72 }
73
74 #[cfg(feature = "abi-7-28")]
75 {
76 let mut flags = INIT_FLAGS;
77 if capabilities & FUSE_MAX_PAGES != 0 {
78 flags |= FUSE_MAX_PAGES;
79 }
80 flags
81 }
82}
83
84#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
86#[cfg_attr(feature = "serializable", derive(Serialize, Deserialize))]
87pub enum FileType {
88 NamedPipe,
90 CharDevice,
92 BlockDevice,
94 Directory,
96 RegularFile,
98 Symlink,
100 Socket,
102}
103
104#[derive(Clone, Copy, Debug, Eq, PartialEq)]
106#[cfg_attr(feature = "serializable", derive(Serialize, Deserialize))]
107pub struct FileAttr {
108 pub ino: u64,
110 pub size: u64,
112 pub blocks: u64,
114 pub atime: SystemTime,
116 pub mtime: SystemTime,
118 pub ctime: SystemTime,
120 pub crtime: SystemTime,
122 pub kind: FileType,
124 pub perm: u16,
126 pub nlink: u32,
128 pub uid: u32,
130 pub gid: u32,
132 pub rdev: u32,
134 pub blksize: u32,
136 pub flags: u32,
138}
139
140#[derive(Debug)]
142pub struct KernelConfig {
143 capabilities: u64,
144 requested: u64,
145 max_readahead: u32,
146 max_max_readahead: u32,
147 max_background: u16,
148 congestion_threshold: Option<u16>,
149 max_write: u32,
150 #[cfg(feature = "abi-7-23")]
151 time_gran: Duration,
152 #[cfg(feature = "abi-7-40")]
153 max_stack_depth: u32,
154}
155
156impl KernelConfig {
157 fn new(capabilities: u64, max_readahead: u32) -> Self {
158 Self {
159 capabilities,
160 requested: default_init_flags(capabilities),
161 max_readahead,
162 max_max_readahead: max_readahead,
163 max_background: 16,
164 congestion_threshold: None,
165 max_write: MAX_WRITE_SIZE as u32,
167 #[cfg(feature = "abi-7-23")]
169 time_gran: Duration::new(0, 1),
170 #[cfg(feature = "abi-7-40")]
171 max_stack_depth: 0,
172 }
173 }
174
175 #[cfg(feature = "abi-7-40")]
188 pub fn set_max_stack_depth(&mut self, value: u32) -> Result<u32, u32> {
189 const FILESYSTEM_MAX_STACK_DEPTH: u32 = 2;
191
192 if value > FILESYSTEM_MAX_STACK_DEPTH {
193 return Err(FILESYSTEM_MAX_STACK_DEPTH);
194 }
195
196 let previous = self.max_stack_depth;
197 self.max_stack_depth = value;
198 Ok(previous)
199 }
200
201 #[cfg(feature = "abi-7-23")]
207 pub fn set_time_granularity(&mut self, value: Duration) -> Result<Duration, Duration> {
208 if value.as_nanos() == 0 {
209 return Err(Duration::new(0, 1));
210 }
211 if value.as_secs() > 1 || (value.as_secs() == 1 && value.subsec_nanos() > 0) {
212 return Err(Duration::new(1, 0));
213 }
214 let mut power_of_10 = 1;
215 while power_of_10 < value.as_nanos() {
216 if value.as_nanos() < power_of_10 * 10 {
217 return Err(Duration::new(0, power_of_10 as u32));
219 }
220 power_of_10 *= 10;
221 }
222 let previous = self.time_gran;
223 self.time_gran = value;
224 Ok(previous)
225 }
226
227 pub fn set_max_write(&mut self, value: u32) -> Result<u32, u32> {
231 if value == 0 {
232 return Err(1);
233 }
234 if value > MAX_WRITE_SIZE as u32 {
235 return Err(MAX_WRITE_SIZE as u32);
236 }
237 let previous = self.max_write;
238 self.max_write = value;
239 Ok(previous)
240 }
241
242 pub fn set_max_readahead(&mut self, value: u32) -> Result<u32, u32> {
246 if value == 0 {
247 return Err(1);
248 }
249 if value > self.max_max_readahead {
250 return Err(self.max_max_readahead);
251 }
252 let previous = self.max_readahead;
253 self.max_readahead = value;
254 Ok(previous)
255 }
256
257 pub fn add_capabilities(&mut self, capabilities_to_add: u64) -> Result<(), u64> {
261 if capabilities_to_add & self.capabilities != capabilities_to_add {
262 return Err(capabilities_to_add - (capabilities_to_add & self.capabilities));
263 }
264 self.requested |= capabilities_to_add;
265 Ok(())
266 }
267
268 pub fn set_max_background(&mut self, value: u16) -> Result<u16, u16> {
272 if value == 0 {
273 return Err(1);
274 }
275 let previous = self.max_background;
276 self.max_background = value;
277 Ok(previous)
278 }
279
280 pub fn set_congestion_threshold(&mut self, value: u16) -> Result<u16, u16> {
285 if value == 0 {
286 return Err(1);
287 }
288 let previous = self.congestion_threshold();
289 self.congestion_threshold = Some(value);
290 Ok(previous)
291 }
292
293 fn congestion_threshold(&self) -> u16 {
294 match self.congestion_threshold {
295 None => (self.max_background as u32 * 3 / 4) as u16,
297 Some(value) => min(value, self.max_background),
298 }
299 }
300
301 #[cfg(feature = "abi-7-28")]
302 fn max_pages(&self) -> u16 {
303 ((max(self.max_write, self.max_readahead) - 1) / page_size::get() as u32) as u16 + 1
304 }
305}
306
307#[allow(clippy::too_many_arguments)]
314pub trait Filesystem {
315 fn init(&mut self, _req: &Request<'_>, _config: &mut KernelConfig) -> Result<(), c_int> {
319 Ok(())
320 }
321
322 fn destroy(&mut self) {}
325
326 fn lookup(&mut self, _req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEntry) {
328 warn!("[Not Implemented] lookup(parent: {parent:#x?}, name {name:?})");
329 reply.error(ENOSYS);
330 }
331
332 fn forget(&mut self, _req: &Request<'_>, _ino: u64, _nlookup: u64) {}
340
341 fn batch_forget(&mut self, req: &Request<'_>, nodes: &[fuse_forget_one]) {
344 for node in nodes {
345 self.forget(req, node.nodeid, node.nlookup);
346 }
347 }
348
349 fn getattr(&mut self, _req: &Request<'_>, ino: u64, fh: Option<u64>, reply: ReplyAttr) {
351 warn!("[Not Implemented] getattr(ino: {ino:#x?}, fh: {fh:#x?})");
352 reply.error(ENOSYS);
353 }
354
355 fn setattr(
357 &mut self,
358 _req: &Request<'_>,
359 ino: u64,
360 mode: Option<u32>,
361 uid: Option<u32>,
362 gid: Option<u32>,
363 size: Option<u64>,
364 _atime: Option<TimeOrNow>,
365 _mtime: Option<TimeOrNow>,
366 _ctime: Option<SystemTime>,
367 fh: Option<u64>,
368 _crtime: Option<SystemTime>,
369 _chgtime: Option<SystemTime>,
370 _bkuptime: Option<SystemTime>,
371 flags: Option<u32>,
372 reply: ReplyAttr,
373 ) {
374 warn!(
375 "[Not Implemented] setattr(ino: {ino:#x?}, mode: {mode:?}, uid: {uid:?}, \
376 gid: {gid:?}, size: {size:?}, fh: {fh:?}, flags: {flags:?})"
377 );
378 reply.error(ENOSYS);
379 }
380
381 fn readlink(&mut self, _req: &Request<'_>, ino: u64, reply: ReplyData) {
383 warn!("[Not Implemented] readlink(ino: {ino:#x?})");
384 reply.error(ENOSYS);
385 }
386
387 fn mknod(
390 &mut self,
391 _req: &Request<'_>,
392 parent: u64,
393 name: &OsStr,
394 mode: u32,
395 umask: u32,
396 rdev: u32,
397 reply: ReplyEntry,
398 ) {
399 warn!(
400 "[Not Implemented] mknod(parent: {parent:#x?}, name: {name:?}, \
401 mode: {mode}, umask: {umask:#x?}, rdev: {rdev})"
402 );
403 reply.error(ENOSYS);
404 }
405
406 fn mkdir(
408 &mut self,
409 _req: &Request<'_>,
410 parent: u64,
411 name: &OsStr,
412 mode: u32,
413 umask: u32,
414 reply: ReplyEntry,
415 ) {
416 warn!(
417 "[Not Implemented] mkdir(parent: {parent:#x?}, name: {name:?}, mode: {mode}, umask: {umask:#x?})"
418 );
419 reply.error(ENOSYS);
420 }
421
422 fn unlink(&mut self, _req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEmpty) {
424 warn!("[Not Implemented] unlink(parent: {parent:#x?}, name: {name:?})",);
425 reply.error(ENOSYS);
426 }
427
428 fn rmdir(&mut self, _req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEmpty) {
430 warn!("[Not Implemented] rmdir(parent: {parent:#x?}, name: {name:?})",);
431 reply.error(ENOSYS);
432 }
433
434 fn symlink(
436 &mut self,
437 _req: &Request<'_>,
438 parent: u64,
439 link_name: &OsStr,
440 target: &Path,
441 reply: ReplyEntry,
442 ) {
443 warn!(
444 "[Not Implemented] symlink(parent: {parent:#x?}, link_name: {link_name:?}, target: {target:?})",
445 );
446 reply.error(EPERM);
447 }
448
449 fn rename(
451 &mut self,
452 _req: &Request<'_>,
453 parent: u64,
454 name: &OsStr,
455 newparent: u64,
456 newname: &OsStr,
457 flags: u32,
458 reply: ReplyEmpty,
459 ) {
460 warn!(
461 "[Not Implemented] rename(parent: {parent:#x?}, name: {name:?}, \
462 newparent: {newparent:#x?}, newname: {newname:?}, flags: {flags})",
463 );
464 reply.error(ENOSYS);
465 }
466
467 fn link(
469 &mut self,
470 _req: &Request<'_>,
471 ino: u64,
472 newparent: u64,
473 newname: &OsStr,
474 reply: ReplyEntry,
475 ) {
476 warn!(
477 "[Not Implemented] link(ino: {ino:#x?}, newparent: {newparent:#x?}, newname: {newname:?})"
478 );
479 reply.error(EPERM);
480 }
481
482 fn open(&mut self, _req: &Request<'_>, _ino: u64, _flags: i32, reply: ReplyOpen) {
491 reply.opened(0, 0);
492 }
493
494 fn read(
505 &mut self,
506 _req: &Request<'_>,
507 ino: u64,
508 fh: u64,
509 offset: i64,
510 size: u32,
511 flags: i32,
512 lock_owner: Option<u64>,
513 reply: ReplyData,
514 ) {
515 warn!(
516 "[Not Implemented] read(ino: {ino:#x?}, fh: {fh}, offset: {offset}, \
517 size: {size}, flags: {flags:#x?}, lock_owner: {lock_owner:?})"
518 );
519 reply.error(ENOSYS);
520 }
521
522 fn write(
535 &mut self,
536 _req: &Request<'_>,
537 ino: u64,
538 fh: u64,
539 offset: i64,
540 data: &[u8],
541 write_flags: u32,
542 flags: i32,
543 lock_owner: Option<u64>,
544 reply: ReplyWrite,
545 ) {
546 warn!(
547 "[Not Implemented] write(ino: {ino:#x?}, fh: {fh}, offset: {offset}, \
548 data.len(): {}, write_flags: {write_flags:#x?}, flags: {flags:#x?}, \
549 lock_owner: {lock_owner:?})",
550 data.len()
551 );
552 reply.error(ENOSYS);
553 }
554
555 fn flush(&mut self, _req: &Request<'_>, ino: u64, fh: u64, lock_owner: u64, reply: ReplyEmpty) {
566 warn!("[Not Implemented] flush(ino: {ino:#x?}, fh: {fh}, lock_owner: {lock_owner:?})");
567 reply.error(ENOSYS);
568 }
569
570 fn release(
579 &mut self,
580 _req: &Request<'_>,
581 _ino: u64,
582 _fh: u64,
583 _flags: i32,
584 _lock_owner: Option<u64>,
585 _flush: bool,
586 reply: ReplyEmpty,
587 ) {
588 reply.ok();
589 }
590
591 fn fsync(&mut self, _req: &Request<'_>, ino: u64, fh: u64, datasync: bool, reply: ReplyEmpty) {
595 warn!("[Not Implemented] fsync(ino: {ino:#x?}, fh: {fh}, datasync: {datasync})");
596 reply.error(ENOSYS);
597 }
598
599 fn opendir(&mut self, _req: &Request<'_>, _ino: u64, _flags: i32, reply: ReplyOpen) {
607 reply.opened(0, 0);
608 }
609
610 fn readdir(
616 &mut self,
617 _req: &Request<'_>,
618 ino: u64,
619 fh: u64,
620 offset: i64,
621 reply: ReplyDirectory,
622 ) {
623 warn!("[Not Implemented] readdir(ino: {ino:#x?}, fh: {fh}, offset: {offset})");
624 reply.error(ENOSYS);
625 }
626
627 fn readdirplus(
633 &mut self,
634 _req: &Request<'_>,
635 ino: u64,
636 fh: u64,
637 offset: i64,
638 reply: ReplyDirectoryPlus,
639 ) {
640 warn!("[Not Implemented] readdirplus(ino: {ino:#x?}, fh: {fh}, offset: {offset})");
641 reply.error(ENOSYS);
642 }
643
644 fn releasedir(
649 &mut self,
650 _req: &Request<'_>,
651 _ino: u64,
652 _fh: u64,
653 _flags: i32,
654 reply: ReplyEmpty,
655 ) {
656 reply.ok();
657 }
658
659 fn fsyncdir(
664 &mut self,
665 _req: &Request<'_>,
666 ino: u64,
667 fh: u64,
668 datasync: bool,
669 reply: ReplyEmpty,
670 ) {
671 warn!("[Not Implemented] fsyncdir(ino: {ino:#x?}, fh: {fh}, datasync: {datasync})");
672 reply.error(ENOSYS);
673 }
674
675 fn statfs(&mut self, _req: &Request<'_>, _ino: u64, reply: ReplyStatfs) {
677 reply.statfs(0, 0, 0, 0, 0, 512, 255, 0);
678 }
679
680 fn setxattr(
682 &mut self,
683 _req: &Request<'_>,
684 ino: u64,
685 name: &OsStr,
686 _value: &[u8],
687 flags: i32,
688 position: u32,
689 reply: ReplyEmpty,
690 ) {
691 warn!(
692 "[Not Implemented] setxattr(ino: {ino:#x?}, name: {name:?}, \
693 flags: {flags:#x?}, position: {position})"
694 );
695 reply.error(ENOSYS);
696 }
697
698 fn getxattr(
703 &mut self,
704 _req: &Request<'_>,
705 ino: u64,
706 name: &OsStr,
707 size: u32,
708 reply: ReplyXattr,
709 ) {
710 warn!("[Not Implemented] getxattr(ino: {ino:#x?}, name: {name:?}, size: {size})");
711 reply.error(ENOSYS);
712 }
713
714 fn listxattr(&mut self, _req: &Request<'_>, ino: u64, size: u32, reply: ReplyXattr) {
719 warn!("[Not Implemented] listxattr(ino: {ino:#x?}, size: {size})");
720 reply.error(ENOSYS);
721 }
722
723 fn removexattr(&mut self, _req: &Request<'_>, ino: u64, name: &OsStr, reply: ReplyEmpty) {
725 warn!("[Not Implemented] removexattr(ino: {ino:#x?}, name: {name:?})");
726 reply.error(ENOSYS);
727 }
728
729 fn access(&mut self, _req: &Request<'_>, ino: u64, mask: i32, reply: ReplyEmpty) {
734 warn!("[Not Implemented] access(ino: {ino:#x?}, mask: {mask})");
735 reply.error(ENOSYS);
736 }
737
738 fn create(
749 &mut self,
750 _req: &Request<'_>,
751 parent: u64,
752 name: &OsStr,
753 mode: u32,
754 umask: u32,
755 flags: i32,
756 reply: ReplyCreate,
757 ) {
758 warn!(
759 "[Not Implemented] create(parent: {parent:#x?}, name: {name:?}, mode: {mode}, \
760 umask: {umask:#x?}, flags: {flags:#x?})"
761 );
762 reply.error(ENOSYS);
763 }
764
765 fn getlk(
767 &mut self,
768 _req: &Request<'_>,
769 ino: u64,
770 fh: u64,
771 lock_owner: u64,
772 start: u64,
773 end: u64,
774 typ: i32,
775 pid: u32,
776 reply: ReplyLock,
777 ) {
778 warn!(
779 "[Not Implemented] getlk(ino: {ino:#x?}, fh: {fh}, lock_owner: {lock_owner}, \
780 start: {start}, end: {end}, typ: {typ}, pid: {pid})"
781 );
782 reply.error(ENOSYS);
783 }
784
785 fn setlk(
793 &mut self,
794 _req: &Request<'_>,
795 ino: u64,
796 fh: u64,
797 lock_owner: u64,
798 start: u64,
799 end: u64,
800 typ: i32,
801 pid: u32,
802 sleep: bool,
803 reply: ReplyEmpty,
804 ) {
805 warn!(
806 "[Not Implemented] setlk(ino: {ino:#x?}, fh: {fh}, lock_owner: {lock_owner}, \
807 start: {start}, end: {end}, typ: {typ}, pid: {pid}, sleep: {sleep})"
808 );
809 reply.error(ENOSYS);
810 }
811
812 fn bmap(&mut self, _req: &Request<'_>, ino: u64, blocksize: u32, idx: u64, reply: ReplyBmap) {
816 warn!("[Not Implemented] bmap(ino: {ino:#x?}, blocksize: {blocksize}, idx: {idx})",);
817 reply.error(ENOSYS);
818 }
819
820 fn ioctl(
822 &mut self,
823 _req: &Request<'_>,
824 ino: u64,
825 fh: u64,
826 flags: u32,
827 cmd: u32,
828 in_data: &[u8],
829 out_size: u32,
830 reply: ReplyIoctl,
831 ) {
832 warn!(
833 "[Not Implemented] ioctl(ino: {ino:#x?}, fh: {fh}, flags: {flags}, \
834 cmd: {cmd}, in_data.len(): {}, out_size: {out_size})",
835 in_data.len()
836 );
837 reply.error(ENOSYS);
838 }
839
840 fn poll(
842 &mut self,
843 _req: &Request<'_>,
844 ino: u64,
845 fh: u64,
846 ph: PollHandle,
847 events: u32,
848 flags: u32,
849 reply: ReplyPoll,
850 ) {
851 warn!(
852 "[Not Implemented] poll(ino: {ino:#x?}, fh: {fh}, \
853 ph: {ph:?}, events: {events}, flags: {flags})"
854 );
855 reply.error(ENOSYS);
856 }
857
858 fn fallocate(
860 &mut self,
861 _req: &Request<'_>,
862 ino: u64,
863 fh: u64,
864 offset: i64,
865 length: i64,
866 mode: i32,
867 reply: ReplyEmpty,
868 ) {
869 warn!(
870 "[Not Implemented] fallocate(ino: {ino:#x?}, fh: {fh}, \
871 offset: {offset}, length: {length}, mode: {mode})"
872 );
873 reply.error(ENOSYS);
874 }
875
876 fn lseek(
878 &mut self,
879 _req: &Request<'_>,
880 ino: u64,
881 fh: u64,
882 offset: i64,
883 whence: i32,
884 reply: ReplyLseek,
885 ) {
886 warn!(
887 "[Not Implemented] lseek(ino: {ino:#x?}, fh: {fh}, \
888 offset: {offset}, whence: {whence})"
889 );
890 reply.error(ENOSYS);
891 }
892
893 fn copy_file_range(
895 &mut self,
896 _req: &Request<'_>,
897 ino_in: u64,
898 fh_in: u64,
899 offset_in: i64,
900 ino_out: u64,
901 fh_out: u64,
902 offset_out: i64,
903 len: u64,
904 flags: u32,
905 reply: ReplyWrite,
906 ) {
907 warn!(
908 "[Not Implemented] copy_file_range(ino_in: {ino_in:#x?}, fh_in: {fh_in}, \
909 offset_in: {offset_in}, ino_out: {ino_out:#x?}, fh_out: {fh_out}, \
910 offset_out: {offset_out}, len: {len}, flags: {flags})"
911 );
912 reply.error(ENOSYS);
913 }
914
915 #[cfg(target_os = "macos")]
918 fn setvolname(&mut self, _req: &Request<'_>, name: &OsStr, reply: ReplyEmpty) {
919 warn!("[Not Implemented] setvolname(name: {name:?})");
920 reply.error(ENOSYS);
921 }
922
923 #[cfg(target_os = "macos")]
925 fn exchange(
926 &mut self,
927 _req: &Request<'_>,
928 parent: u64,
929 name: &OsStr,
930 newparent: u64,
931 newname: &OsStr,
932 options: u64,
933 reply: ReplyEmpty,
934 ) {
935 warn!(
936 "[Not Implemented] exchange(parent: {parent:#x?}, name: {name:?}, \
937 newparent: {newparent:#x?}, newname: {newname:?}, options: {options})"
938 );
939 reply.error(ENOSYS);
940 }
941
942 #[cfg(target_os = "macos")]
945 fn getxtimes(&mut self, _req: &Request<'_>, ino: u64, reply: ReplyXTimes) {
946 warn!("[Not Implemented] getxtimes(ino: {ino:#x?})");
947 reply.error(ENOSYS);
948 }
949}
950
951#[deprecated(note = "use mount2() instead")]
956pub fn mount<FS: Filesystem, P: AsRef<Path>>(
957 filesystem: FS,
958 mountpoint: P,
959 options: &[&OsStr],
960) -> io::Result<()> {
961 let options = parse_options_from_args(options)?;
962 mount2(filesystem, mountpoint, options.as_ref())
963}
964
965pub fn mount2<FS: Filesystem, P: AsRef<Path>>(
970 filesystem: FS,
971 mountpoint: P,
972 options: &[MountOption],
973) -> io::Result<()> {
974 check_option_conflicts(options)?;
975 Session::new(filesystem, mountpoint.as_ref(), options).and_then(|mut se| se.run())
976}
977
978#[deprecated(note = "use spawn_mount2() instead")]
984pub fn spawn_mount<'a, FS: Filesystem + Send + 'static + 'a, P: AsRef<Path>>(
985 filesystem: FS,
986 mountpoint: P,
987 options: &[&OsStr],
988) -> io::Result<BackgroundSession> {
989 let options: Option<Vec<_>> = options
990 .iter()
991 .map(|x| Some(MountOption::from_str(x.to_str()?)))
992 .collect();
993 let options = options.ok_or(ErrorKind::InvalidData)?;
994 Session::new(filesystem, mountpoint.as_ref(), options.as_ref()).and_then(|se| se.spawn())
995}
996
997pub fn spawn_mount2<'a, FS: Filesystem + Send + 'static + 'a, P: AsRef<Path>>(
1005 filesystem: FS,
1006 mountpoint: P,
1007 options: &[MountOption],
1008) -> io::Result<BackgroundSession> {
1009 check_option_conflicts(options)?;
1010 Session::new(filesystem, mountpoint.as_ref(), options).and_then(|se| se.spawn())
1011}