1use std::ffi::{OsStr, OsString};
7use std::path::Path;
8use std::sync::{Arc, RwLock};
9use std::time::SystemTime;
10
11use fuser::{
12 AccessFlags, Errno, FileHandle, FopenFlags, Generation, INodeNo, LockOwner, OpenFlags,
13 RenameFlags, TimeOrNow, WriteFlags,
14};
15
16use crate::FileType;
17use crate::directory_cache::*;
18use crate::inode_table::{InodeTable, InodeToPath};
19use crate::types::*;
20
21trait IntoRequestInfo {
22 fn info(&self) -> RequestInfo;
23}
24
25impl IntoRequestInfo for fuser::Request {
26 fn info(&self) -> RequestInfo {
27 RequestInfo {
28 unique: self.unique().0,
29 uid: self.uid(),
30 gid: self.gid(),
31 pid: self.pid(),
32 }
33 }
34}
35
36fn fuse_fileattr(attr: FileAttr, ino: INodeNo) -> fuser::FileAttr {
37 fuser::FileAttr {
38 ino,
39 size: attr.size,
40 blocks: attr.blocks,
41 atime: attr.atime,
42 mtime: attr.mtime,
43 ctime: attr.ctime,
44 crtime: attr.crtime,
45 kind: attr.kind,
46 perm: attr.perm,
47 nlink: attr.nlink,
48 uid: attr.uid,
49 gid: attr.gid,
50 rdev: attr.rdev,
51 blksize: attr.blksize,
52 flags: attr.flags,
53 }
54}
55
56trait TimeOrNowExt {
57 fn time(self) -> SystemTime;
58}
59
60impl TimeOrNowExt for TimeOrNow {
61 fn time(self) -> SystemTime {
62 match self {
63 TimeOrNow::SpecificTime(t) => t,
64 TimeOrNow::Now => SystemTime::now(),
65 }
66 }
67}
68
69#[derive(Debug)]
89pub struct FuserNG<T> {
90 target: Arc<T>,
91 table: InodeTable,
92 directory_cache: RwLock<DirectoryCache>,
93}
94
95impl<T: Filesystem + Sync + Send + 'static> FuserNG<T> {
96 pub fn new(target_fs: T) -> FuserNG<T> {
98 FuserNG {
99 target: Arc::new(target_fs),
100 table: InodeTable::new(),
101 directory_cache: DirectoryCache::new().into(),
102 }
103 }
104 fn get_path(&self, ino: INodeNo) -> Option<EntryName> {
105 self.table.get_path(ino.0)
106 }
107 fn add_or_get_dir(&self, parent: INodeNo, name: &OsStr) -> Option<(u64, u64)> {
108 self.table.add_or_get_dir(parent.0, name)
109 }
110 fn add_or_get_leaf(&self, parent: INodeNo, name: &OsStr) -> Option<(u64, u64)> {
111 self.table.add_or_get_leaf(parent.0, name)
112 }
113 fn lookup(&self, ino: u64) {
114 self.table.lookup(ino);
115 }
116 fn forget(&self, ino: INodeNo, n: u64) -> u64 {
117 self.table.forget(ino.0, n)
118 }
119 fn add_leaf(&self, parent: INodeNo, name: &OsStr) -> Option<(u64, u64)> {
120 self.table.add_leaf(parent.0, name)
121 }
122 fn add_dir(&self, parent: INodeNo, name: &OsStr) -> Option<(u64, u64)> {
123 self.table.add_dir(parent.0, name)
124 }
125 fn inode_unlink(&self, parent: INodeNo, name: &OsStr) {
126 self.table.unlink(parent.0, name)
127 }
128 fn get_parent_inode(&self, ino: INodeNo) -> Option<u64> {
129 self.table.get_parent_inode(ino.0)
130 }
131 fn inode_rename(
132 &self,
133 oldparent: INodeNo,
134 oldname: &OsStr,
135 newparent: INodeNo,
136 newname: &OsStr,
137 ) -> Option<()> {
138 self.table
139 .rename(oldparent.0, oldname, newparent.0, newname)
140 }
141}
142
143macro_rules! get_entry_name {
144 ($s:expr, $ino:expr, $reply:expr) => {
145 if let Some(path) = $s.get_path($ino) {
146 path
147 } else {
148 $reply.error(Errno::EINVAL);
149 return;
150 }
151 };
152}
153
154macro_rules! resolve_from_parent {
155 ($s:expr, $ino:expr, $name:expr, $reply:expr) => {
156 if let Some(path) = $s.table.resolve_from_parent($ino.0, $name.into()) {
157 path
158 } else {
159 $reply.error(Errno::EINVAL);
160 return;
161 }
162 };
163}
164
165macro_rules! get_resolved_path {
166 ($s:expr, $ino:expr, $reply:expr) => {{ get_entry_name!($s, $ino, $reply).with($ino.0) }};
167}
168
169impl<T: Filesystem + Sync + Send + 'static> fuser::Filesystem for FuserNG<T> {
170 fn init(
171 &mut self,
172 req: &fuser::Request,
173 config: &mut fuser::KernelConfig,
174 ) -> Result<(), std::io::Error> {
175 debug!("init");
176 self.target.init(req.info(), config)
177 }
178
179 fn destroy(&mut self) {
180 debug!("destroy");
181 self.target.destroy();
182 }
183
184 fn lookup(
185 &self,
186 req: &fuser::Request,
187 parent: INodeNo,
188 name: &OsStr,
189 reply: fuser::ReplyEntry,
190 ) {
191 let path = resolve_from_parent!(self, parent, name, reply);
192 debug!("lookup: {:?}", path);
193 match self.target.getattr(req.info(), &path, None) {
197 Ok((ttl, attr)) => {
198 let value = if attr.kind == FileType::Directory {
199 self.add_or_get_dir(parent, name)
200 } else {
201 self.add_or_get_leaf(parent, name)
202 };
203 if let Some((ino, generation)) = value {
204 self.lookup(ino);
205 reply.entry(
206 &ttl,
207 &fuse_fileattr(attr, INodeNo(ino)),
208 Generation(generation),
209 );
210 } else {
211 reply.error(Errno::EINVAL)
212 }
213 }
214 Err(e) => reply.error(e.into()),
215 }
216 }
217
218 fn forget(&self, _req: &fuser::Request, ino: INodeNo, nlookup: u64) {
219 let lookups = self.forget(ino, nlookup);
220 let path = self
221 .get_path(ino)
222 .unwrap_or_else(|| EntryName::new(OsStr::new("").into(), OsString::from("[unknown]")));
223 debug!(
224 "forget: inode {} ({:?}) now at {} lookups",
225 ino, path, lookups
226 );
227 }
228
229 fn getattr(
230 &self,
231 req: &fuser::Request,
232 ino: INodeNo,
233 fh: Option<fuser::FileHandle>,
234 reply: fuser::ReplyAttr,
235 ) {
236 let path = get_entry_name!(self, ino, reply);
237 debug!("getattr: {:?}", path);
238 match self.target.getattr(req.info(), &path, fh.map(|fh| fh.0)) {
239 Ok((ttl, attr)) => reply.attr(&ttl, &fuse_fileattr(attr, ino)),
240 Err(e) => reply.error(e.into()),
241 }
242 }
243
244 fn setattr(
245 &self,
246 req: &fuser::Request, ino: INodeNo, mode: Option<u32>, uid: Option<u32>, gid: Option<u32>, size: Option<u64>, atime: Option<TimeOrNow>, mtime: Option<TimeOrNow>, _ctime: Option<SystemTime>, fh: Option<fuser::FileHandle>, crtime: Option<SystemTime>, chgtime: Option<SystemTime>, bkuptime: Option<SystemTime>, flags: Option<fuser::BsdFileFlags>, reply: fuser::ReplyAttr,
261 ) {
262 let path = get_resolved_path!(self, ino, reply);
263 debug!("setattr: {:?}", path);
264
265 debug!("\tino:\t{:?}", ino);
266 debug!("\tmode:\t{:?}", mode);
267 debug!("\tuid:\t{:?}", uid);
268 debug!("\tgid:\t{:?}", gid);
269 debug!("\tsize:\t{:?}", size);
270 debug!("\tatime:\t{:?}", atime);
271 debug!("\tmtime:\t{:?}", mtime);
272 debug!("\tfh:\t{:?}", fh);
273
274 if let Some(mode) = mode
277 && let Err(e) = self
278 .target
279 .chmod(req.info(), &path, fh.map(|fh| fh.0), mode)
280 {
281 reply.error(e.into());
282 return;
283 }
284
285 if (uid.is_some() || gid.is_some())
286 && let Err(e) = self
287 .target
288 .chown(req.info(), &path, fh.map(|fh| fh.0), uid, gid)
289 {
290 reply.error(e.into());
291 return;
292 }
293
294 if let Some(size) = size
295 && let Err(e) = self
296 .target
297 .truncate(req.info(), &path, fh.map(|fh| fh.0), size)
298 {
299 reply.error(e.into());
300 return;
301 }
302
303 if atime.is_some() || mtime.is_some() {
304 let atime = atime.map(TimeOrNowExt::time);
305 let mtime = mtime.map(TimeOrNowExt::time);
306 if let Err(e) = self
307 .target
308 .utimens(req.info(), &path, fh.map(|fh| fh.0), atime, mtime)
309 {
310 reply.error(e.into());
311 return;
312 }
313 }
314
315 if (crtime.is_some() || chgtime.is_some() || bkuptime.is_some() || flags.is_some())
316 && let Err(e) = self.target.utimens_macos(
317 req.info(),
318 &path,
319 fh.map(|fh| fh.0),
320 crtime,
321 chgtime,
322 bkuptime,
323 flags.map(|flags| flags.bits()),
324 )
325 {
326 reply.error(e.into());
327 return;
328 }
329
330 match self
331 .target
332 .getattr(req.info(), &path.entry_name(), fh.map(|fh| fh.0))
333 {
334 Ok((ttl, attr)) => reply.attr(&ttl, &fuse_fileattr(attr, ino)),
335 Err(e) => reply.error(e.into()),
336 }
337 }
338
339 fn readlink(&self, req: &fuser::Request, ino: INodeNo, reply: fuser::ReplyData) {
340 let path = get_resolved_path!(self, ino, reply);
341 debug!("readlink: {:?}", path);
342 match self.target.readlink(req.info(), &path) {
343 Ok(data) => reply.data(&data),
344 Err(e) => reply.error(e.into()),
345 }
346 }
347
348 fn mknod(
349 &self,
350 req: &fuser::Request,
351 parent: INodeNo,
352 name: &OsStr,
353 mode: u32,
354 _umask: u32, rdev: u32,
356 reply: fuser::ReplyEntry,
357 ) {
358 let entry = resolve_from_parent!(self, parent, name, reply);
359 debug!("mknod: {:?}", entry);
360 match self.target.mknod(req.info(), &entry, mode, rdev) {
361 Ok((ttl, attr)) => {
362 if let Some((ino, generation)) = self.add_leaf(parent, name) {
363 reply.entry(
364 &ttl,
365 &fuse_fileattr(attr, INodeNo(ino)),
366 Generation(generation),
367 )
368 } else {
369 reply.error(Errno::from_i32(libc::EINVAL))
370 }
371 }
372 Err(e) => reply.error(e.into()),
373 }
374 }
375
376 fn mkdir(
377 &self,
378 req: &fuser::Request,
379 parent: INodeNo,
380 name: &OsStr,
381 mode: u32,
382 _umask: u32, reply: fuser::ReplyEntry,
384 ) {
385 let entry = resolve_from_parent!(self, parent, name, reply);
386 debug!("mkdir: {:?} (mode={:#o})", entry, mode);
387 match self.target.mkdir(req.info(), &entry, mode) {
388 Ok((ttl, attr)) => {
389 if let Some((ino, generation)) = self.add_dir(parent, name) {
390 reply.entry(
391 &ttl,
392 &fuse_fileattr(attr, INodeNo(ino)),
393 Generation(generation),
394 )
395 } else {
396 reply.error(Errno::from_i32(libc::EINVAL))
397 }
398 }
399 Err(e) => reply.error(e.into()),
400 }
401 }
402
403 fn unlink(
404 &self,
405 req: &fuser::Request,
406 parent: INodeNo,
407 name: &OsStr,
408 reply: fuser::ReplyEmpty,
409 ) {
410 let entry = resolve_from_parent!(self, parent, name, reply);
411 debug!("unlink: {:?}", entry);
412 match self.target.unlink(req.info(), &entry) {
413 Ok(()) => {
414 self.inode_unlink(parent, name);
415 reply.ok()
416 }
417 Err(e) => reply.error(e.into()),
418 }
419 }
420
421 fn rmdir(&self, req: &fuser::Request, parent: INodeNo, name: &OsStr, reply: fuser::ReplyEmpty) {
422 let entry = resolve_from_parent!(self, parent, name, reply);
423 debug!("rmdir: {:?}", entry);
424 match self.target.rmdir(req.info(), &entry) {
425 Ok(()) => {
426 self.inode_unlink(parent, name);
427 reply.ok()
428 }
429 Err(e) => reply.error(e.into()),
430 }
431 }
432
433 fn symlink(
434 &self,
435 req: &fuser::Request,
436 parent: INodeNo,
437 name: &OsStr,
438 link: &Path,
439 reply: fuser::ReplyEntry,
440 ) {
441 let entry = resolve_from_parent!(self, parent, name, reply);
442 debug!("symlink: {:?} -> {:?}", entry, link);
443 match self.target.symlink(req.info(), &entry, link) {
444 Ok((ttl, attr)) => {
445 if let Some((ino, generation)) = self.add_leaf(parent, name) {
446 reply.entry(
447 &ttl,
448 &fuse_fileattr(attr, INodeNo(ino)),
449 Generation(generation),
450 )
451 } else {
452 reply.error(Errno::EINVAL)
453 }
454 }
455 Err(e) => reply.error(e.into()),
456 }
457 }
458
459 fn rename(
460 &self,
461 req: &fuser::Request,
462 parent: INodeNo,
463 name: &OsStr,
464 newparent: INodeNo,
465 newname: &OsStr,
466 _flags: RenameFlags, reply: fuser::ReplyEmpty,
468 ) {
469 let entry = resolve_from_parent!(self, parent, name, reply);
470 let new_entry = resolve_from_parent!(self, newparent, newname, reply);
471 debug!("rename: {:?} -> {:?}", entry, new_entry);
472 match self.target.rename(req.info(), &entry, &new_entry) {
473 Ok(()) => {
474 self.inode_rename(parent, name, newparent, newname);
475 reply.ok()
476 }
477 Err(e) => reply.error(e.into()),
478 }
479 }
480
481 fn link(
482 &self,
483 req: &fuser::Request,
484 ino: INodeNo,
485 newparent: INodeNo,
486 newname: &OsStr,
487 reply: fuser::ReplyEntry,
488 ) {
489 let path = get_resolved_path!(self, ino, reply);
490 let new_entry = resolve_from_parent!(self, newparent, newname, reply);
491 debug!("link: {:?} -> {:?}", path, new_entry);
492 match self.target.link(req.info(), &path, &new_entry) {
493 Ok((ttl, attr)) => {
494 if let Some((new_ino, generation)) = self.add_leaf(newparent, newname) {
497 reply.entry(
498 &ttl,
499 &fuse_fileattr(attr, INodeNo(new_ino)),
500 Generation(generation),
501 );
502 } else {
503 reply.error(Errno::EINVAL);
504 }
505 }
506 Err(e) => reply.error(e.into()),
507 }
508 }
509
510 fn open(&self, req: &fuser::Request, ino: INodeNo, flags: OpenFlags, reply: fuser::ReplyOpen) {
511 let path = get_resolved_path!(self, ino, reply);
512 debug!("open: {:?}", path);
513 match self.target.open(req.info(), &path, flags.0 as u32) {
514 Ok((fh, flags)) => reply.opened(FileHandle(fh), FopenFlags::from_bits_retain(flags)),
516 Err(e) => reply.error(e.into()),
517 }
518 }
519
520 fn read(
521 &self,
522 req: &fuser::Request,
523 ino: INodeNo,
524 fh: FileHandle,
525 offset: u64,
526 size: u32,
527 _flags: OpenFlags, _lock_owner: Option<LockOwner>, reply: fuser::ReplyData,
530 ) {
531 let path = get_resolved_path!(self, ino, reply);
532 debug!("read: {:?} {:#x} @ {:#x}", path, size, offset);
533 self.target
534 .read(req.info(), &path, fh.0, offset, size, |result| {
535 match result {
536 Ok(data) => reply.data(data),
537 Err(e) => reply.error(e.into()),
538 }
539 CallbackResult {
540 _private: std::marker::PhantomData {},
541 }
542 });
543 }
544
545 fn write(
546 &self,
547 req: &fuser::Request,
548 ino: INodeNo,
549 fh: FileHandle,
550 offset: u64,
551 data: &[u8],
552 _write_flags: WriteFlags, flags: OpenFlags,
554 _lock_owner: Option<LockOwner>, reply: fuser::ReplyWrite,
556 ) {
557 let path = get_resolved_path!(self, ino, reply);
558 debug!("write: {:?} {:#x} @ {:#x}", path, data.len(), offset);
559 let data_buf = Vec::from(data);
561 match self
562 .target
563 .write(req.info(), &path, fh.0, offset, data_buf, flags.0 as u32)
564 {
565 Ok(written) => reply.written(written),
566 Err(e) => reply.error(e.into()),
567 }
568 }
569
570 fn flush(
571 &self,
572 req: &fuser::Request,
573 ino: INodeNo,
574 fh: FileHandle,
575 lock_owner: LockOwner,
576 reply: fuser::ReplyEmpty,
577 ) {
578 let path = get_resolved_path!(self, ino, reply);
579 debug!("flush: {:?}", path);
580 match self.target.flush(req.info(), &path, fh.0, lock_owner.0) {
581 Ok(()) => reply.ok(),
582 Err(e) => reply.error(e.into()),
583 }
584 }
585
586 fn release(
587 &self,
588 req: &fuser::Request,
589 ino: INodeNo,
590 fh: FileHandle,
591 flags: OpenFlags,
592 lock_owner: Option<LockOwner>,
593 flush: bool,
594 reply: fuser::ReplyEmpty,
595 ) {
596 let path = get_resolved_path!(self, ino, reply);
597 debug!("release: {:?}", path);
598 match self.target.release(
599 req.info(),
600 &path,
601 fh.0,
602 flags.0 as u32,
603 lock_owner.map(|owner| owner.0).unwrap_or(0), flush,
605 ) {
606 Ok(()) => reply.ok(),
607 Err(e) => reply.error(e.into()),
608 }
609 }
610
611 fn fsync(
612 &self,
613 req: &fuser::Request,
614 ino: INodeNo,
615 fh: FileHandle,
616 datasync: bool,
617 reply: fuser::ReplyEmpty,
618 ) {
619 let path = get_resolved_path!(self, ino, reply);
620 debug!("fsync: {:?}", path);
621 match self.target.fsync(req.info(), &path, fh.0, datasync) {
622 Ok(()) => reply.ok(),
623 Err(e) => reply.error(e.into()),
624 }
625 }
626
627 fn opendir(
628 &self,
629 req: &fuser::Request,
630 ino: INodeNo,
631 flags: OpenFlags,
632 reply: fuser::ReplyOpen,
633 ) {
634 let path = get_resolved_path!(self, ino, reply);
635 debug!("opendir: {:?}", path);
636 match self.target.opendir(req.info(), &path, flags.0 as u32) {
637 Ok((fh, flags)) => {
638 let dcache_key = self.directory_cache.write().unwrap().new_entry(fh);
639 reply.opened(FileHandle(dcache_key), FopenFlags::from_bits_retain(flags));
640 }
641 Err(e) => reply.error(e.into()),
642 }
643 }
644
645 fn readdir(
646 &self,
647 req: &fuser::Request,
648 ino: INodeNo,
649 fh: FileHandle,
650 offset: u64,
651 mut reply: fuser::ReplyDirectory,
652 ) {
653 let path = get_resolved_path!(self, ino, reply);
654 debug!("readdir: {:?} @ {}", path, offset);
655
656 let parent_inode = if ino == INodeNo::ROOT {
657 ino
658 } else {
659 match self.get_parent_inode(ino) {
660 Some(inode) => INodeNo(inode),
661 None => {
662 error!("readdir: unable to get parent inode for {:?}", &path);
663 reply.error(Errno::EIO);
664 return;
665 }
666 }
667 };
668
669 let cached_entries = {
670 self.directory_cache
671 .write()
672 .unwrap()
673 .get_mut(fh.0)
674 .entries
675 .clone()
676 };
677
678 let entries = match cached_entries {
679 Some(entries) => entries,
680 None => {
681 let real_fh = self.directory_cache.read().unwrap().real_fh(fh.0);
682 debug!("entries not yet fetched; requesting with fh {}", real_fh);
683 match self.target.readdir(req.info(), &path, real_fh) {
684 Ok(entries) => {
685 self.directory_cache.write().unwrap().get_mut(fh.0).entries =
686 Some(entries.clone());
687 entries
688 }
689 Err(e) => {
690 reply.error(e.into());
691 return;
692 }
693 }
694 }
695 };
696
697 debug!("directory has {} entries", entries.len());
698
699 for (index, entry) in entries.iter().skip(offset as usize).enumerate() {
700 let entry_inode = if entry.name == Path::new(".") {
701 ino
702 } else if entry.name == Path::new("..") {
703 parent_inode
704 } else {
705 INodeNo(!1u64)
709 };
710
711 debug!(
712 "readdir: adding entry #{}, {:?}",
713 offset + index as u64,
714 entry.name
715 );
716
717 let buffer_full: bool = reply.add(
718 entry_inode,
719 offset + index as u64 + 1,
720 entry.kind,
721 entry.name.as_os_str(),
722 );
723
724 if buffer_full {
725 debug!("readdir: reply buffer is full");
726 break;
727 }
728 }
729
730 reply.ok();
731 }
732
733 fn releasedir(
734 &self,
735 req: &fuser::Request,
736 ino: INodeNo,
737 fh: FileHandle,
738 flags: OpenFlags,
739 reply: fuser::ReplyEmpty,
740 ) {
741 let path = get_resolved_path!(self, ino, reply);
742 debug!("releasedir: {:?}", path);
743 let real_fh = self.directory_cache.read().unwrap().real_fh(fh.0);
744 match self
745 .target
746 .releasedir(req.info(), &path, real_fh, flags.0 as u32)
747 {
748 Ok(()) => reply.ok(),
749 Err(e) => reply.error(e.into()),
750 }
751 self.directory_cache.write().unwrap().delete(fh.0);
752 }
753
754 fn fsyncdir(
755 &self,
756 req: &fuser::Request,
757 ino: INodeNo,
758 fh: FileHandle,
759 datasync: bool,
760 reply: fuser::ReplyEmpty,
761 ) {
762 let path = get_resolved_path!(self, ino, reply);
763 debug!("fsyncdir: {:?} (datasync: {:?})", path, datasync);
764 let real_fh = self.directory_cache.read().unwrap().real_fh(fh.0);
765 match self.target.fsyncdir(req.info(), &path, real_fh, datasync) {
766 Ok(()) => reply.ok(),
767 Err(e) => reply.error(e.into()),
768 }
769 }
770
771 fn statfs(&self, req: &fuser::Request, ino: INodeNo, reply: fuser::ReplyStatfs) {
772 let path = get_resolved_path!(self, ino, reply);
773 debug!("statfs: {:?}", path);
774 match self.target.statfs(req.info(), &path) {
775 Ok(statfs) => reply.statfs(
776 statfs.blocks,
777 statfs.bfree,
778 statfs.bavail,
779 statfs.files,
780 statfs.ffree,
781 statfs.bsize,
782 statfs.namelen,
783 statfs.frsize,
784 ),
785 Err(e) => reply.error(e.into()),
786 }
787 }
788
789 fn setxattr(
790 &self,
791 req: &fuser::Request,
792 ino: INodeNo,
793 name: &OsStr,
794 value: &[u8],
795 flags: i32,
796 position: u32,
797 reply: fuser::ReplyEmpty,
798 ) {
799 let path = get_resolved_path!(self, ino, reply);
800 debug!(
801 "setxattr: {:?} {:?} ({} bytes, flags={:#x}, pos={:#x}",
802 path,
803 name,
804 value.len(),
805 flags,
806 position
807 );
808 match self
809 .target
810 .setxattr(req.info(), &path, name, value, flags as u32, position)
811 {
812 Ok(()) => reply.ok(),
813 Err(e) => reply.error(e.into()),
814 }
815 }
816
817 fn getxattr(
818 &self,
819 req: &fuser::Request,
820 ino: INodeNo,
821 name: &OsStr,
822 size: u32,
823 reply: fuser::ReplyXattr,
824 ) {
825 let path = get_resolved_path!(self, ino, reply);
826 debug!("getxattr: {:?} {:?}", path, name);
827 match self.target.getxattr(req.info(), &path, name, size) {
828 Ok(Xattr::Size(size)) => {
829 debug!("getxattr: sending size {}", size);
830 reply.size(size)
831 }
832 Ok(Xattr::Data(vec)) => {
833 debug!("getxattr: sending {} bytes", vec.len());
834 reply.data(&vec)
835 }
836 Err(e) => {
837 debug!("getxattr: error {}", e);
838 reply.error(e.into())
839 }
840 }
841 }
842
843 fn listxattr(&self, req: &fuser::Request, ino: INodeNo, size: u32, reply: fuser::ReplyXattr) {
844 let path = get_resolved_path!(self, ino, reply);
845 debug!("listxattr: {:?}", path);
846 match self.target.listxattr(req.info(), &path, size) {
847 Ok(Xattr::Size(size)) => {
848 debug!("listxattr: sending size {}", size);
849 reply.size(size)
850 }
851 Ok(Xattr::Data(vec)) => {
852 debug!("listxattr: sending {} bytes", vec.len());
853 reply.data(&vec)
854 }
855 Err(e) => reply.error(e.into()),
856 }
857 }
858
859 fn removexattr(
860 &self,
861 req: &fuser::Request,
862 ino: INodeNo,
863 name: &OsStr,
864 reply: fuser::ReplyEmpty,
865 ) {
866 let path = get_resolved_path!(self, ino, reply);
867 debug!("removexattr: {:?}, {:?}", path, name);
868 match self.target.removexattr(req.info(), &path, name) {
869 Ok(()) => reply.ok(),
870 Err(e) => reply.error(e.into()),
871 }
872 }
873
874 fn access(
875 &self,
876 req: &fuser::Request,
877 ino: INodeNo,
878 mask: AccessFlags,
879 reply: fuser::ReplyEmpty,
880 ) {
881 let path = get_resolved_path!(self, ino, reply);
882 debug!("access: {:?}, mask={:#o}", path, mask.bits());
883 match self.target.access(req.info(), &path, mask.bits() as u32) {
884 Ok(()) => reply.ok(),
885 Err(e) => reply.error(e.into()),
886 }
887 }
888
889 fn create(
890 &self,
891 req: &fuser::Request,
892 parent: INodeNo,
893 name: &OsStr,
894 mode: u32,
895 _umask: u32, flags: i32,
897 reply: fuser::ReplyCreate,
898 ) {
899 let entry = resolve_from_parent!(self, parent, name, reply);
900 debug!("create: {:?} (mode={:#o}, flags={:#x})", entry, mode, flags);
901 match self.target.create(req.info(), &entry, mode, flags as u32) {
902 Ok(create) => {
903 if let Some((ino, generation)) = self.add_leaf(parent, name) {
904 let attr = fuse_fileattr(create.attr, INodeNo(ino));
905 reply.created(
906 &create.ttl,
907 &attr,
908 Generation(generation),
909 FileHandle(create.fh),
910 FopenFlags::from_bits_retain(create.flags),
911 );
912 } else {
913 reply.error(Errno::EINVAL);
914 }
915 }
916 Err(e) => reply.error(e.into()),
917 }
918 }
919
920 #[cfg(target_os = "macos")]
927 fn setvolname(&self, req: &fuser::Request, name: &OsStr, reply: fuser::ReplyEmpty) {
928 debug!("setvolname: {:?}", name);
929 match self.target.setvolname(req.info(), name) {
930 Ok(()) => reply.ok(),
931 Err(e) => reply.error(e.into()),
932 }
933 }
934
935 #[cfg(target_os = "macos")]
938 fn getxtimes(&self, req: &fuser::Request, ino: INodeNo, reply: fuser::ReplyXTimes) {
939 let path = get_resolved_path!(self, ino, reply);
940 debug!("getxtimes: {:?}", path);
941 match self.target.getxtimes(req.info(), &path) {
942 Ok(xtimes) => {
943 reply.xtimes(xtimes.bkuptime, xtimes.crtime);
944 }
945 Err(e) => reply.error(e.into()),
946 }
947 }
948}