1use std::ffi::{OsStr, OsString};
7use std::path::{Path, PathBuf};
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.get_path(ino).unwrap_or_else(|| {
221 EntryName::new(
222 Arc::new(PathBuf::from(OsStr::new(""))).into(),
223 OsString::from("[unknown]").into(),
224 )
225 });
226 debug!(
227 "forget: inode {} ({:?}) now at {} lookups",
228 ino, path, lookups
229 );
230 }
231
232 fn getattr(
233 &self,
234 req: &fuser::Request,
235 ino: INodeNo,
236 fh: Option<fuser::FileHandle>,
237 reply: fuser::ReplyAttr,
238 ) {
239 let path = get_entry_name!(self, ino, reply);
240 debug!("getattr: {:?}", path);
241 match self.target.getattr(req.info(), &path, fh.map(|fh| fh.0)) {
242 Ok((ttl, attr)) => reply.attr(&ttl, &fuse_fileattr(attr, ino)),
243 Err(e) => reply.error(e.into()),
244 }
245 }
246
247 fn setattr(
248 &self,
249 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,
264 ) {
265 let path = get_resolved_path!(self, ino, reply);
266 debug!("setattr: {:?}", path);
267
268 debug!("\tino:\t{:?}", ino);
269 debug!("\tmode:\t{:?}", mode);
270 debug!("\tuid:\t{:?}", uid);
271 debug!("\tgid:\t{:?}", gid);
272 debug!("\tsize:\t{:?}", size);
273 debug!("\tatime:\t{:?}", atime);
274 debug!("\tmtime:\t{:?}", mtime);
275 debug!("\tfh:\t{:?}", fh);
276
277 if let Some(mode) = mode
280 && let Err(e) = self
281 .target
282 .chmod(req.info(), &path, fh.map(|fh| fh.0), mode)
283 {
284 reply.error(e.into());
285 return;
286 }
287
288 if (uid.is_some() || gid.is_some())
289 && let Err(e) = self
290 .target
291 .chown(req.info(), &path, fh.map(|fh| fh.0), uid, gid)
292 {
293 reply.error(e.into());
294 return;
295 }
296
297 if let Some(size) = size
298 && let Err(e) = self
299 .target
300 .truncate(req.info(), &path, fh.map(|fh| fh.0), size)
301 {
302 reply.error(e.into());
303 return;
304 }
305
306 if atime.is_some() || mtime.is_some() {
307 let atime = atime.map(TimeOrNowExt::time);
308 let mtime = mtime.map(TimeOrNowExt::time);
309 if let Err(e) = self
310 .target
311 .utimens(req.info(), &path, fh.map(|fh| fh.0), atime, mtime)
312 {
313 reply.error(e.into());
314 return;
315 }
316 }
317
318 if (crtime.is_some() || chgtime.is_some() || bkuptime.is_some() || flags.is_some())
319 && let Err(e) = self.target.utimens_macos(
320 req.info(),
321 &path,
322 fh.map(|fh| fh.0),
323 crtime,
324 chgtime,
325 bkuptime,
326 flags.map(|flags| flags.bits()),
327 )
328 {
329 reply.error(e.into());
330 return;
331 }
332
333 match self
334 .target
335 .getattr(req.info(), &path.entry_name(), fh.map(|fh| fh.0))
336 {
337 Ok((ttl, attr)) => reply.attr(&ttl, &fuse_fileattr(attr, ino)),
338 Err(e) => reply.error(e.into()),
339 }
340 }
341
342 fn readlink(&self, req: &fuser::Request, ino: INodeNo, reply: fuser::ReplyData) {
343 let path = get_resolved_path!(self, ino, reply);
344 debug!("readlink: {:?}", path);
345 match self.target.readlink(req.info(), &path) {
346 Ok(data) => reply.data(&data),
347 Err(e) => reply.error(e.into()),
348 }
349 }
350
351 fn mknod(
352 &self,
353 req: &fuser::Request,
354 parent: INodeNo,
355 name: &OsStr,
356 mode: u32,
357 _umask: u32, rdev: u32,
359 reply: fuser::ReplyEntry,
360 ) {
361 let entry = resolve_from_parent!(self, parent, name, reply);
362 debug!("mknod: {:?}", entry);
363 match self.target.mknod(req.info(), &entry, mode, rdev) {
364 Ok((ttl, attr)) => {
365 if let Some((ino, generation)) = self.add_leaf(parent, name) {
366 reply.entry(
367 &ttl,
368 &fuse_fileattr(attr, INodeNo(ino)),
369 Generation(generation),
370 )
371 } else {
372 reply.error(Errno::from_i32(libc::EINVAL))
373 }
374 }
375 Err(e) => reply.error(e.into()),
376 }
377 }
378
379 fn mkdir(
380 &self,
381 req: &fuser::Request,
382 parent: INodeNo,
383 name: &OsStr,
384 mode: u32,
385 _umask: u32, reply: fuser::ReplyEntry,
387 ) {
388 let entry = resolve_from_parent!(self, parent, name, reply);
389 debug!("mkdir: {:?} (mode={:#o})", entry, mode);
390 match self.target.mkdir(req.info(), &entry, mode) {
391 Ok((ttl, attr)) => {
392 if let Some((ino, generation)) = self.add_dir(parent, name) {
393 reply.entry(
394 &ttl,
395 &fuse_fileattr(attr, INodeNo(ino)),
396 Generation(generation),
397 )
398 } else {
399 reply.error(Errno::from_i32(libc::EINVAL))
400 }
401 }
402 Err(e) => reply.error(e.into()),
403 }
404 }
405
406 fn unlink(
407 &self,
408 req: &fuser::Request,
409 parent: INodeNo,
410 name: &OsStr,
411 reply: fuser::ReplyEmpty,
412 ) {
413 let entry = resolve_from_parent!(self, parent, name, reply);
414 debug!("unlink: {:?}", entry);
415 match self.target.unlink(req.info(), &entry) {
416 Ok(()) => {
417 self.inode_unlink(parent, name);
418 reply.ok()
419 }
420 Err(e) => reply.error(e.into()),
421 }
422 }
423
424 fn rmdir(&self, req: &fuser::Request, parent: INodeNo, name: &OsStr, reply: fuser::ReplyEmpty) {
425 let entry = resolve_from_parent!(self, parent, name, reply);
426 debug!("rmdir: {:?}", entry);
427 match self.target.rmdir(req.info(), &entry) {
428 Ok(()) => {
429 self.inode_unlink(parent, name);
430 reply.ok()
431 }
432 Err(e) => reply.error(e.into()),
433 }
434 }
435
436 fn symlink(
437 &self,
438 req: &fuser::Request,
439 parent: INodeNo,
440 name: &OsStr,
441 link: &Path,
442 reply: fuser::ReplyEntry,
443 ) {
444 let entry = resolve_from_parent!(self, parent, name, reply);
445 debug!("symlink: {:?} -> {:?}", entry, link);
446 match self.target.symlink(req.info(), &entry, link) {
447 Ok((ttl, attr)) => {
448 if let Some((ino, generation)) = self.add_leaf(parent, name) {
449 reply.entry(
450 &ttl,
451 &fuse_fileattr(attr, INodeNo(ino)),
452 Generation(generation),
453 )
454 } else {
455 reply.error(Errno::EINVAL)
456 }
457 }
458 Err(e) => reply.error(e.into()),
459 }
460 }
461
462 fn rename(
463 &self,
464 req: &fuser::Request,
465 parent: INodeNo,
466 name: &OsStr,
467 newparent: INodeNo,
468 newname: &OsStr,
469 _flags: RenameFlags, reply: fuser::ReplyEmpty,
471 ) {
472 let entry = resolve_from_parent!(self, parent, name, reply);
473 let new_entry = resolve_from_parent!(self, newparent, newname, reply);
474 debug!("rename: {:?} -> {:?}", entry, new_entry);
475 match self.target.rename(req.info(), &entry, &new_entry) {
476 Ok(()) => {
477 self.inode_rename(parent, name, newparent, newname);
478 reply.ok()
479 }
480 Err(e) => reply.error(e.into()),
481 }
482 }
483
484 fn link(
485 &self,
486 req: &fuser::Request,
487 ino: INodeNo,
488 newparent: INodeNo,
489 newname: &OsStr,
490 reply: fuser::ReplyEntry,
491 ) {
492 let path = get_resolved_path!(self, ino, reply);
493 let new_entry = resolve_from_parent!(self, newparent, newname, reply);
494 debug!("link: {:?} -> {:?}", path, new_entry);
495 match self.target.link(req.info(), &path, &new_entry) {
496 Ok((ttl, attr)) => {
497 if let Some((new_ino, generation)) = self.add_leaf(newparent, newname) {
500 reply.entry(
501 &ttl,
502 &fuse_fileattr(attr, INodeNo(new_ino)),
503 Generation(generation),
504 );
505 } else {
506 reply.error(Errno::EINVAL);
507 }
508 }
509 Err(e) => reply.error(e.into()),
510 }
511 }
512
513 fn open(&self, req: &fuser::Request, ino: INodeNo, flags: OpenFlags, reply: fuser::ReplyOpen) {
514 let path = get_resolved_path!(self, ino, reply);
515 debug!("open: {:?}", path);
516 match self.target.open(req.info(), &path, flags.0 as u32) {
517 Ok((fh, flags)) => reply.opened(FileHandle(fh), FopenFlags::from_bits_retain(flags)),
519 Err(e) => reply.error(e.into()),
520 }
521 }
522
523 fn read(
524 &self,
525 req: &fuser::Request,
526 ino: INodeNo,
527 fh: FileHandle,
528 offset: u64,
529 size: u32,
530 _flags: OpenFlags, _lock_owner: Option<LockOwner>, reply: fuser::ReplyData,
533 ) {
534 let path = get_resolved_path!(self, ino, reply);
535 debug!("read: {:?} {:#x} @ {:#x}", path, size, offset);
536 self.target
537 .read(req.info(), &path, fh.0, offset, size, |result| {
538 match result {
539 Ok(data) => reply.data(data),
540 Err(e) => reply.error(e.into()),
541 }
542 CallbackResult {
543 _private: std::marker::PhantomData {},
544 }
545 });
546 }
547
548 fn write(
549 &self,
550 req: &fuser::Request,
551 ino: INodeNo,
552 fh: FileHandle,
553 offset: u64,
554 data: &[u8],
555 _write_flags: WriteFlags, flags: OpenFlags,
557 _lock_owner: Option<LockOwner>, reply: fuser::ReplyWrite,
559 ) {
560 let path = get_resolved_path!(self, ino, reply);
561 debug!("write: {:?} {:#x} @ {:#x}", path, data.len(), offset);
562 let data_buf = Vec::from(data);
564 match self
565 .target
566 .write(req.info(), &path, fh.0, offset, data_buf, flags.0 as u32)
567 {
568 Ok(written) => reply.written(written),
569 Err(e) => reply.error(e.into()),
570 }
571 }
572
573 fn flush(
574 &self,
575 req: &fuser::Request,
576 ino: INodeNo,
577 fh: FileHandle,
578 lock_owner: LockOwner,
579 reply: fuser::ReplyEmpty,
580 ) {
581 let path = get_resolved_path!(self, ino, reply);
582 debug!("flush: {:?}", path);
583 match self.target.flush(req.info(), &path, fh.0, lock_owner.0) {
584 Ok(()) => reply.ok(),
585 Err(e) => reply.error(e.into()),
586 }
587 }
588
589 fn release(
590 &self,
591 req: &fuser::Request,
592 ino: INodeNo,
593 fh: FileHandle,
594 flags: OpenFlags,
595 lock_owner: Option<LockOwner>,
596 flush: bool,
597 reply: fuser::ReplyEmpty,
598 ) {
599 let path = get_resolved_path!(self, ino, reply);
600 debug!("release: {:?}", path);
601 match self.target.release(
602 req.info(),
603 &path,
604 fh.0,
605 flags.0 as u32,
606 lock_owner.map(|owner| owner.0).unwrap_or(0), flush,
608 ) {
609 Ok(()) => reply.ok(),
610 Err(e) => reply.error(e.into()),
611 }
612 }
613
614 fn fsync(
615 &self,
616 req: &fuser::Request,
617 ino: INodeNo,
618 fh: FileHandle,
619 datasync: bool,
620 reply: fuser::ReplyEmpty,
621 ) {
622 let path = get_resolved_path!(self, ino, reply);
623 debug!("fsync: {:?}", path);
624 match self.target.fsync(req.info(), &path, fh.0, datasync) {
625 Ok(()) => reply.ok(),
626 Err(e) => reply.error(e.into()),
627 }
628 }
629
630 fn opendir(
631 &self,
632 req: &fuser::Request,
633 ino: INodeNo,
634 flags: OpenFlags,
635 reply: fuser::ReplyOpen,
636 ) {
637 let path = get_resolved_path!(self, ino, reply);
638 debug!("opendir: {:?}", path);
639 match self.target.opendir(req.info(), &path, flags.0 as u32) {
640 Ok((fh, flags)) => {
641 let dcache_key = self.directory_cache.write().unwrap().new_entry(fh);
642 reply.opened(FileHandle(dcache_key), FopenFlags::from_bits_retain(flags));
643 }
644 Err(e) => reply.error(e.into()),
645 }
646 }
647
648 fn readdir(
649 &self,
650 req: &fuser::Request,
651 ino: INodeNo,
652 fh: FileHandle,
653 offset: u64,
654 mut reply: fuser::ReplyDirectory,
655 ) {
656 let path = get_resolved_path!(self, ino, reply);
657 debug!("readdir: {:?} @ {}", path, offset);
658
659 let parent_inode = if ino == INodeNo::ROOT {
660 ino
661 } else {
662 match self.get_parent_inode(ino) {
663 Some(inode) => INodeNo(inode),
664 None => {
665 error!("readdir: unable to get parent inode for {:?}", &path);
666 reply.error(Errno::EIO);
667 return;
668 }
669 }
670 };
671
672 let cached_entries = {
673 self.directory_cache
674 .write()
675 .unwrap()
676 .get_mut(fh.0)
677 .entries
678 .clone()
679 };
680
681 let entries = match cached_entries {
682 Some(entries) => entries,
683 None => {
684 let real_fh = self.directory_cache.read().unwrap().real_fh(fh.0);
685 debug!("entries not yet fetched; requesting with fh {}", real_fh);
686 match self.target.readdir(req.info(), &path, real_fh) {
687 Ok(entries) => {
688 self.directory_cache.write().unwrap().get_mut(fh.0).entries =
689 Some(entries.clone());
690 entries
691 }
692 Err(e) => {
693 reply.error(e.into());
694 return;
695 }
696 }
697 }
698 };
699
700 debug!("directory has {} entries", entries.len());
701
702 for (index, entry) in entries.iter().skip(offset as usize).enumerate() {
703 let entry_inode = if entry.name == Path::new(".") {
704 ino
705 } else if entry.name == Path::new("..") {
706 parent_inode
707 } else {
708 INodeNo(!1u64)
712 };
713
714 debug!(
715 "readdir: adding entry #{}, {:?}",
716 offset + index as u64,
717 entry.name
718 );
719
720 let buffer_full: bool = reply.add(
721 entry_inode,
722 offset + index as u64 + 1,
723 entry.kind,
724 entry.name.as_os_str(),
725 );
726
727 if buffer_full {
728 debug!("readdir: reply buffer is full");
729 break;
730 }
731 }
732
733 reply.ok();
734 }
735
736 fn releasedir(
737 &self,
738 req: &fuser::Request,
739 ino: INodeNo,
740 fh: FileHandle,
741 flags: OpenFlags,
742 reply: fuser::ReplyEmpty,
743 ) {
744 let path = get_resolved_path!(self, ino, reply);
745 debug!("releasedir: {:?}", path);
746 let real_fh = self.directory_cache.read().unwrap().real_fh(fh.0);
747 match self
748 .target
749 .releasedir(req.info(), &path, real_fh, flags.0 as u32)
750 {
751 Ok(()) => reply.ok(),
752 Err(e) => reply.error(e.into()),
753 }
754 self.directory_cache.write().unwrap().delete(fh.0);
755 }
756
757 fn fsyncdir(
758 &self,
759 req: &fuser::Request,
760 ino: INodeNo,
761 fh: FileHandle,
762 datasync: bool,
763 reply: fuser::ReplyEmpty,
764 ) {
765 let path = get_resolved_path!(self, ino, reply);
766 debug!("fsyncdir: {:?} (datasync: {:?})", path, datasync);
767 let real_fh = self.directory_cache.read().unwrap().real_fh(fh.0);
768 match self.target.fsyncdir(req.info(), &path, real_fh, datasync) {
769 Ok(()) => reply.ok(),
770 Err(e) => reply.error(e.into()),
771 }
772 }
773
774 fn statfs(&self, req: &fuser::Request, ino: INodeNo, reply: fuser::ReplyStatfs) {
775 let path = get_resolved_path!(self, ino, reply);
776 debug!("statfs: {:?}", path);
777 match self.target.statfs(req.info(), &path) {
778 Ok(statfs) => reply.statfs(
779 statfs.blocks,
780 statfs.bfree,
781 statfs.bavail,
782 statfs.files,
783 statfs.ffree,
784 statfs.bsize,
785 statfs.namelen,
786 statfs.frsize,
787 ),
788 Err(e) => reply.error(e.into()),
789 }
790 }
791
792 fn setxattr(
793 &self,
794 req: &fuser::Request,
795 ino: INodeNo,
796 name: &OsStr,
797 value: &[u8],
798 flags: i32,
799 position: u32,
800 reply: fuser::ReplyEmpty,
801 ) {
802 let path = get_resolved_path!(self, ino, reply);
803 debug!(
804 "setxattr: {:?} {:?} ({} bytes, flags={:#x}, pos={:#x}",
805 path,
806 name,
807 value.len(),
808 flags,
809 position
810 );
811 match self
812 .target
813 .setxattr(req.info(), &path, name, value, flags as u32, position)
814 {
815 Ok(()) => reply.ok(),
816 Err(e) => reply.error(e.into()),
817 }
818 }
819
820 fn getxattr(
821 &self,
822 req: &fuser::Request,
823 ino: INodeNo,
824 name: &OsStr,
825 size: u32,
826 reply: fuser::ReplyXattr,
827 ) {
828 let path = get_resolved_path!(self, ino, reply);
829 debug!("getxattr: {:?} {:?}", path, name);
830 match self.target.getxattr(req.info(), &path, name, size) {
831 Ok(Xattr::Size(size)) => {
832 debug!("getxattr: sending size {}", size);
833 reply.size(size)
834 }
835 Ok(Xattr::Data(vec)) => {
836 debug!("getxattr: sending {} bytes", vec.len());
837 reply.data(&vec)
838 }
839 Err(e) => {
840 debug!("getxattr: error {}", e);
841 reply.error(e.into())
842 }
843 }
844 }
845
846 fn listxattr(&self, req: &fuser::Request, ino: INodeNo, size: u32, reply: fuser::ReplyXattr) {
847 let path = get_resolved_path!(self, ino, reply);
848 debug!("listxattr: {:?}", path);
849 match self.target.listxattr(req.info(), &path, size) {
850 Ok(Xattr::Size(size)) => {
851 debug!("listxattr: sending size {}", size);
852 reply.size(size)
853 }
854 Ok(Xattr::Data(vec)) => {
855 debug!("listxattr: sending {} bytes", vec.len());
856 reply.data(&vec)
857 }
858 Err(e) => reply.error(e.into()),
859 }
860 }
861
862 fn removexattr(
863 &self,
864 req: &fuser::Request,
865 ino: INodeNo,
866 name: &OsStr,
867 reply: fuser::ReplyEmpty,
868 ) {
869 let path = get_resolved_path!(self, ino, reply);
870 debug!("removexattr: {:?}, {:?}", path, name);
871 match self.target.removexattr(req.info(), &path, name) {
872 Ok(()) => reply.ok(),
873 Err(e) => reply.error(e.into()),
874 }
875 }
876
877 fn access(
878 &self,
879 req: &fuser::Request,
880 ino: INodeNo,
881 mask: AccessFlags,
882 reply: fuser::ReplyEmpty,
883 ) {
884 let path = get_resolved_path!(self, ino, reply);
885 debug!("access: {:?}, mask={:#o}", path, mask.bits());
886 match self.target.access(req.info(), &path, mask.bits() as u32) {
887 Ok(()) => reply.ok(),
888 Err(e) => reply.error(e.into()),
889 }
890 }
891
892 fn create(
893 &self,
894 req: &fuser::Request,
895 parent: INodeNo,
896 name: &OsStr,
897 mode: u32,
898 _umask: u32, flags: i32,
900 reply: fuser::ReplyCreate,
901 ) {
902 let entry = resolve_from_parent!(self, parent, name, reply);
903 debug!("create: {:?} (mode={:#o}, flags={:#x})", entry, mode, flags);
904 match self.target.create(req.info(), &entry, mode, flags as u32) {
905 Ok(create) => {
906 if let Some((ino, generation)) = self.add_leaf(parent, name) {
907 let attr = fuse_fileattr(create.attr, INodeNo(ino));
908 reply.created(
909 &create.ttl,
910 &attr,
911 Generation(generation),
912 FileHandle(create.fh),
913 FopenFlags::from_bits_retain(create.flags),
914 );
915 } else {
916 reply.error(Errno::EINVAL);
917 }
918 }
919 Err(e) => reply.error(e.into()),
920 }
921 }
922
923 #[cfg(target_os = "macos")]
930 fn setvolname(&self, req: &fuser::Request, name: &OsStr, reply: fuser::ReplyEmpty) {
931 debug!("setvolname: {:?}", name);
932 match self.target.setvolname(req.info(), name) {
933 Ok(()) => reply.ok(),
934 Err(e) => reply.error(e.into()),
935 }
936 }
937
938 #[cfg(target_os = "macos")]
941 fn getxtimes(&self, req: &fuser::Request, ino: INodeNo, reply: fuser::ReplyXTimes) {
942 let path = get_resolved_path!(self, ino, reply);
943 debug!("getxtimes: {:?}", path);
944 match self.target.getxtimes(req.info(), &path) {
945 Ok(xtimes) => {
946 reply.xtimes(xtimes.bkuptime, xtimes.crtime);
947 }
948 Err(e) => reply.error(e.into()),
949 }
950 }
951}