1use super::utils;
2use super::{CachePolicy, HandleData, Inode, OverlayFs, RealHandle};
3use crate::util::open_options::OpenOptions;
4use rfuse3::raw::prelude::*;
5use rfuse3::*;
6use std::ffi::OsStr;
7use std::io::Error;
8use std::io::ErrorKind;
9use std::num::NonZeroU32;
10use std::sync::Arc;
11use std::sync::atomic::{AtomicU64, Ordering};
12use tokio::sync::Mutex;
13use tracing::info;
14use tracing::trace;
15
16impl Filesystem for OverlayFs {
17 async fn init(&self, _req: Request) -> Result<ReplyInit> {
19 if self.config.do_import {
20 self.import().await?;
21 }
22 #[cfg(target_os = "linux")]
23 {
24 for layer in self.lower_layers.iter() {
25 layer.init(_req).await?;
26 }
27 if let Some(upper) = &self.upper_layer {
28 upper.init(_req).await?;
29 }
30 }
31 if !self.config.do_import || self.config.writeback {
32 self.writeback.store(true, Ordering::Relaxed);
33 }
34 if !self.config.do_import || self.config.no_open {
35 self.no_open.store(true, Ordering::Relaxed);
36 }
37 if !self.config.do_import || self.config.no_opendir {
38 self.no_opendir.store(true, Ordering::Relaxed);
39 }
40 if !self.config.do_import || self.config.killpriv_v2 {
41 self.killpriv_v2.store(true, Ordering::Relaxed);
42 }
43 if self.config.perfile_dax {
44 self.perfile_dax.store(true, Ordering::Relaxed);
45 }
46
47 Ok(ReplyInit {
48 max_write: NonZeroU32::new(128 * 1024).unwrap(),
49 })
50 }
51
52 async fn destroy(&self, _req: Request) {}
57
58 async fn lookup(&self, req: Request, parent: Inode, name: &OsStr) -> Result<ReplyEntry> {
60 let tmp = name.to_string_lossy().to_string();
61 let result = self.do_lookup(req, parent, tmp.as_str()).await;
62 match result {
63 Ok(e) => Ok(e),
64 Err(err) => Err(err.into()),
65 }
66 }
67
68 async fn forget(&self, _req: Request, inode: Inode, nlookup: u64) {
78 self.forget_one(inode, nlookup).await;
79 }
80
81 async fn getattr(
83 &self,
84 req: Request,
85 inode: Inode,
86 fh: Option<u64>,
87 flags: u32,
88 ) -> Result<ReplyAttr> {
89 if !self.no_open.load(Ordering::Relaxed)
90 && let Some(h) = fh
91 {
92 let handles = self.handles.lock().await;
93 if let Some(hd) = handles.get(&h)
94 && let Some(ref rh) = hd.real_handle
95 {
96 let mut rep: ReplyAttr = rh
97 .layer
98 .getattr(req, rh.inode, Some(rh.handle.load(Ordering::Relaxed)), 0)
99 .await?;
100 rep.attr.ino = inode;
101 return Ok(rep);
102 }
103 }
104
105 let node: Arc<super::OverlayInode> = self.lookup_node(req, inode, "").await?;
106 let (layer, _, lower_inode) = node.first_layer_inode().await;
107 let mut re = layer.getattr(req, lower_inode, None, flags).await?;
108 re.attr.ino = inode;
109 Ok(re)
110 }
111
112 async fn setattr(
114 &self,
115 req: Request,
116 inode: Inode,
117 fh: Option<u64>,
118 set_attr: SetAttr,
119 ) -> Result<ReplyAttr> {
120 self.upper_layer
122 .as_ref()
123 .cloned()
124 .ok_or_else(|| Error::from_raw_os_error(libc::EROFS))?;
125
126 if !self.no_open.load(Ordering::Relaxed)
128 && let Some(h) = fh
129 {
130 let handles = self.handles.lock().await;
131 if let Some(hd) = handles.get(&h)
132 && let Some(ref rhd) = hd.real_handle
133 {
134 if rhd.in_upper_layer {
136 let mut rep = rhd
137 .layer
138 .setattr(
139 req,
140 rhd.inode,
141 Some(rhd.handle.load(Ordering::Relaxed)),
142 set_attr,
143 )
144 .await?;
145 rep.attr.ino = inode;
146 return Ok(rep);
147 }
148 }
149 }
150
151 let mut node = self.lookup_node(req, inode, "").await?;
152
153 if !node.in_upper_layer().await {
154 node = self.copy_node_up(req, node.clone()).await?
155 }
156
157 let (layer, _, real_inode) = node.first_layer_inode().await;
158 let mut rep = layer.setattr(req, real_inode, None, set_attr).await?;
160 rep.attr.ino = inode;
161 Ok(rep)
162 }
163
164 async fn readlink(&self, req: Request, inode: Inode) -> Result<ReplyData> {
166 trace!("READLINK: inode: {inode}\n");
167
168 let node = self.lookup_node(req, inode, "").await?;
169
170 if node.whiteout.load(Ordering::Relaxed) {
171 return Err(Error::from_raw_os_error(libc::ENOENT).into());
172 }
173
174 let (layer, _, inode) = node.first_layer_inode().await;
175 layer.readlink(req, inode).await
176 }
177
178 async fn symlink(
180 &self,
181 req: Request,
182 parent: Inode,
183 name: &OsStr,
184 link: &OsStr,
185 ) -> Result<ReplyEntry> {
186 let sname = name.to_string_lossy().into_owned().to_owned();
188 let slinkname = link.to_string_lossy().into_owned().to_owned();
189
190 let pnode = self.lookup_node(req, parent, "").await?;
191 self.do_symlink(req, slinkname.as_str(), &pnode, sname.as_str())
192 .await?;
193
194 self.do_lookup(req, parent, sname.as_str())
195 .await
196 .map_err(|e| e.into())
197 }
198
199 async fn mknod(
203 &self,
204 req: Request,
205 parent: Inode,
206 name: &OsStr,
207 mode: u32,
208 rdev: u32,
209 ) -> Result<ReplyEntry> {
210 let sname = name.to_string_lossy().to_string();
211
212 let pnode = self.lookup_node(req, parent, "").await?;
214 if pnode.whiteout.load(Ordering::Relaxed) {
215 return Err(Error::from_raw_os_error(libc::ENOENT).into());
216 }
217
218 self.do_mknod(req, &pnode, sname.as_str(), mode, rdev, 0)
219 .await?;
220 self.do_lookup(req, parent, sname.as_str())
221 .await
222 .map_err(|e| e.into())
223 }
224
225 async fn mkdir(
227 &self,
228 req: Request,
229 parent: Inode,
230 name: &OsStr,
231 mode: u32,
232 umask: u32,
233 ) -> Result<ReplyEntry> {
234 let sname = name.to_string_lossy().to_string();
235
236 let pnode = self.lookup_node(req, parent, "").await?;
238 if pnode.whiteout.load(Ordering::Relaxed) {
239 return Err(Error::from_raw_os_error(libc::ENOENT).into());
240 }
241
242 self.do_mkdir(req, pnode, sname.as_str(), mode, umask)
243 .await?;
244 self.do_lookup(req, parent, sname.as_str())
245 .await
246 .map_err(|e| e.into())
247 }
248
249 async fn unlink(&self, req: Request, parent: Inode, name: &OsStr) -> Result<()> {
251 self.do_rm(req, parent, name, false)
252 .await
253 .map_err(|e| e.into())
254 }
255
256 async fn rmdir(&self, req: Request, parent: Inode, name: &OsStr) -> Result<()> {
258 self.do_rm(req, parent, name, true)
259 .await
260 .map_err(|e| e.into())
261 }
262
263 async fn rename(
265 &self,
266 req: Request,
267 parent: Inode,
268 name: &OsStr,
269 new_parent: Inode,
270 new_name: &OsStr,
271 ) -> Result<()> {
272 self.do_rename(req, parent, name, new_parent, new_name)
273 .await
274 .map_err(|e| e.into())
275 }
276
277 async fn link(
279 &self,
280 req: Request,
281 inode: Inode,
282 new_parent: Inode,
283 new_name: &OsStr,
284 ) -> Result<ReplyEntry> {
285 let node = self.lookup_node(req, inode, "").await?;
286 if node.whiteout.load(Ordering::Relaxed) {
287 return Err(Error::from_raw_os_error(libc::ENOENT).into());
288 }
289
290 let newpnode = self.lookup_node(req, new_parent, "").await?;
291 if newpnode.whiteout.load(Ordering::Relaxed) {
292 return Err(Error::from_raw_os_error(libc::ENOENT).into());
293 }
294 let new_name = new_name.to_str().unwrap();
295 self.do_link(req, &node, &newpnode, new_name).await?;
300 self.do_lookup(req, new_parent, new_name)
302 .await
303 .map_err(|e| e.into())
304 }
305
306 async fn open(&self, req: Request, inode: Inode, flags: u32) -> Result<ReplyOpen> {
321 if self.no_open.load(Ordering::Relaxed) {
322 info!("fuse: open is not supported.");
323 return Err(Error::from_raw_os_error(libc::ENOSYS).into());
324 }
325
326 let readonly: bool = flags
327 & (libc::O_APPEND | libc::O_CREAT | libc::O_TRUNC | libc::O_RDWR | libc::O_WRONLY)
328 as u32
329 == 0;
330 let mut flags: i32 = flags as i32;
332
333 flags |= libc::O_NOFOLLOW;
334
335 if self.config.writeback {
336 if flags & libc::O_ACCMODE == libc::O_WRONLY {
337 flags &= !libc::O_ACCMODE;
338 flags |= libc::O_RDWR;
339 }
340
341 if flags & libc::O_APPEND != 0 {
342 flags &= !libc::O_APPEND;
343 }
344 }
345 let node = self.lookup_node(req, inode, "").await?;
347
348 if node.whiteout.load(Ordering::Relaxed) {
350 return Err(Error::from_raw_os_error(libc::ENOENT).into());
351 }
352
353 if !readonly {
354 self.copy_node_up(req, node.clone()).await?;
356 }
357
358 let (_l, h) = node.open(req, flags as u32, 0).await?;
360
361 let hd = self.next_handle.fetch_add(1, Ordering::Relaxed);
362 let (layer, in_upper_layer, inode) = node.first_layer_inode().await;
363 let handle_data = HandleData {
364 node: node.clone(),
365 real_handle: Some(RealHandle {
366 layer,
367 in_upper_layer,
368 inode,
369 handle: AtomicU64::new(h.fh),
370 }),
371 dir_snapshot: Mutex::new(None),
372 };
373
374 self.handles.lock().await.insert(hd, Arc::new(handle_data));
375
376 let mut opts = OpenOptions::empty();
377 match self.config.cache_policy {
378 CachePolicy::Never => opts |= OpenOptions::DIRECT_IO,
379 CachePolicy::Always => opts |= OpenOptions::KEEP_CACHE,
380 _ => {}
381 }
382 Ok(ReplyOpen {
385 fh: hd,
386 flags: opts.bits(),
387 })
388 }
389
390 async fn read(
396 &self,
397 req: Request,
398 inode: Inode,
399 fh: u64,
400 offset: u64,
401 size: u32,
402 ) -> Result<ReplyData> {
403 let data = self.get_data(req, Some(fh), inode, 0).await?;
404
405 match data.real_handle {
406 None => Err(Error::from_raw_os_error(libc::ENOENT).into()),
407 Some(ref hd) => {
408 hd.layer
409 .read(
410 req,
411 hd.inode,
412 hd.handle.load(Ordering::Relaxed),
413 offset,
414 size,
415 )
416 .await
417 }
418 }
419 }
420
421 #[allow(clippy::too_many_arguments)]
429 async fn write(
430 &self,
431 req: Request,
432 inode: Inode,
433 fh: u64,
434 offset: u64,
435 data: &[u8],
436 write_flags: u32,
437 flags: u32,
438 ) -> Result<ReplyWrite> {
439 let handle_data: Arc<HandleData> = self.get_data(req, Some(fh), inode, flags).await?;
440
441 match handle_data.real_handle {
442 None => Err(Error::from_raw_os_error(libc::ENOENT).into()),
443 Some(ref hd) => {
444 hd.layer
445 .write(
446 req,
447 hd.inode,
448 hd.handle.load(Ordering::Relaxed),
449 offset,
450 data,
451 write_flags,
452 flags,
453 )
454 .await
455 }
456 }
457 }
458
459 #[allow(clippy::too_many_arguments)]
464 async fn copy_file_range(
465 &self,
466 req: Request,
467 inode_in: Inode,
468 fh_in: u64,
469 offset_in: u64,
470 inode_out: Inode,
471 fh_out: u64,
472 offset_out: u64,
473 length: u64,
474 flags: u64,
475 ) -> Result<ReplyCopyFileRange> {
476 let data_in = self.get_data(req, Some(fh_in), inode_in, 0).await?;
478 let handle_in = match data_in.real_handle {
479 None => return Err(Error::from_raw_os_error(libc::ENOENT).into()),
480 Some(ref hd) => hd,
481 };
482
483 let data_out = self.get_data(req, Some(fh_out), inode_out, 0).await?;
485 let handle_out = match data_out.real_handle {
486 None => return Err(Error::from_raw_os_error(libc::ENOENT).into()),
487 Some(ref hd) => hd,
488 };
489
490 if !Arc::ptr_eq(&handle_in.layer, &handle_out.layer) {
492 return Err(Error::from_raw_os_error(libc::EXDEV).into());
494 }
495
496 handle_in
498 .layer
499 .copy_file_range(
500 req,
501 handle_in.inode,
502 handle_in.handle.load(Ordering::Relaxed),
503 offset_in,
504 handle_out.inode,
505 handle_out.handle.load(Ordering::Relaxed),
506 offset_out,
507 length,
508 flags,
509 )
510 .await
511 }
512
513 async fn statfs(&self, req: Request, inode: Inode) -> Result<ReplyStatFs> {
515 self.do_statvfs(req, inode).await.map_err(|e| e.into())
516 }
517
518 async fn release(
526 &self,
527 req: Request,
528 _inode: Inode,
529 fh: u64,
530 flags: u32,
531 lock_owner: u64,
532 flush: bool,
533 ) -> Result<()> {
534 if self.no_open.load(Ordering::Relaxed) {
535 info!("fuse: release is not supported.");
536 return Err(Error::from_raw_os_error(libc::ENOSYS).into());
537 }
538
539 if let Some(hd) = self.handles.lock().await.get(&fh) {
540 let rh = if let Some(ref h) = hd.real_handle {
541 h
542 } else {
543 return Err(
544 Error::other(format!("no real handle found for file handle {fh}")).into(),
545 );
546 };
547 let real_handle = rh.handle.load(Ordering::Relaxed);
548 let real_inode = rh.inode;
549 rh.layer
550 .release(req, real_inode, real_handle, flags, lock_owner, flush)
551 .await?;
552 }
553
554 self.handles.lock().await.remove(&fh);
555
556 Ok(())
557 }
558
559 async fn fsync(&self, req: Request, inode: Inode, fh: u64, datasync: bool) -> Result<()> {
562 self.do_fsync(req, inode, datasync, fh, false)
563 .await
564 .map_err(|e| e.into())
565 }
566
567 async fn setxattr(
569 &self,
570 req: Request,
571 inode: Inode,
572 name: &OsStr,
573 value: &[u8],
574 flags: u32,
575 position: u32,
576 ) -> Result<()> {
577 let node = self.lookup_node(req, inode, "").await?;
578
579 if node.whiteout.load(Ordering::Relaxed) {
580 return Err(Error::from_raw_os_error(libc::ENOENT).into());
581 }
582
583 if !node.in_upper_layer().await {
584 self.copy_node_up(req, node.clone()).await?;
586 }
587
588 let (layer, _, real_inode) = node.first_layer_inode().await;
589
590 layer
591 .setxattr(req, real_inode, name, value, flags, position)
592 .await
593 }
594
595 async fn getxattr(
599 &self,
600 req: Request,
601 inode: Inode,
602 name: &OsStr,
603 size: u32,
604 ) -> Result<ReplyXAttr> {
605 let node = self.lookup_node(req, inode, "").await?;
606
607 if node.whiteout.load(Ordering::Relaxed) {
608 return Err(Error::from_raw_os_error(libc::ENOENT).into());
609 }
610
611 let (layer, real_inode) = self.find_real_inode(inode).await?;
612
613 layer.getxattr(req, real_inode, name, size).await
614 }
615
616 async fn listxattr(&self, req: Request, inode: Inode, size: u32) -> Result<ReplyXAttr> {
621 let node = self.lookup_node(req, inode, "").await?;
622 if node.whiteout.load(Ordering::Relaxed) {
623 return Err(Error::from_raw_os_error(libc::ENOENT).into());
624 }
625 let (layer, real_inode) = self.find_real_inode(inode).await?;
626 layer.listxattr(req, real_inode, size).await
627 }
628
629 async fn removexattr(&self, req: Request, inode: Inode, name: &OsStr) -> Result<()> {
631 let node = self.lookup_node(req, inode, "").await?;
632
633 if node.whiteout.load(Ordering::Relaxed) {
634 return Err(Error::from_raw_os_error(libc::ENOENT).into());
635 }
636
637 if !node.in_upper_layer().await {
638 self.copy_node_up(req, node.clone()).await?;
640 }
641
642 let (layer, _, ino) = node.first_layer_inode().await;
643 layer.removexattr(req, ino, name).await
644
645 }
647
648 async fn flush(&self, req: Request, inode: Inode, fh: u64, lock_owner: u64) -> Result<()> {
661 if self.no_open.load(Ordering::Relaxed) {
662 return Err(Error::from_raw_os_error(libc::ENOSYS).into());
663 }
664
665 let node = self.lookup_node(req, inode, "").await;
666 match node {
667 Ok(n) => {
668 if n.whiteout.load(Ordering::Relaxed) {
669 return Err(Error::from_raw_os_error(libc::ENOENT).into());
670 }
671 }
672 Err(e) => {
673 if e.raw_os_error() == Some(libc::ENOENT) {
674 trace!("flush: inode {inode} is stale");
675 } else {
676 return Err(e.into());
677 }
678 }
679 }
680
681 let (layer, real_inode, real_handle) = self.find_real_info_from_handle(fh).await?;
682
683 if inode
685 != self
686 .handles
687 .lock()
688 .await
689 .get(&fh)
690 .map(|h| h.node.inode)
691 .unwrap_or(0)
692 {
693 return Err(Error::other("inode does not match handle").into());
694 }
695
696 trace!("flushing, real_inode: {real_inode}, real_handle: {real_handle}");
697 layer.flush(req, real_inode, real_handle, lock_owner).await
698 }
699
700 async fn opendir(&self, req: Request, inode: Inode, flags: u32) -> Result<ReplyOpen> {
708 if self.no_opendir.load(Ordering::Relaxed) {
709 info!("fuse: opendir is not supported.");
710 return Err(Error::from_raw_os_error(libc::ENOSYS).into());
711 }
712
713 let node = self.lookup_node(req, inode, ".").await?;
715
716 if node.whiteout.load(Ordering::Relaxed) {
717 return Err(Error::from_raw_os_error(libc::ENOENT).into());
718 }
719
720 let st = node.stat64(req).await?;
721 if !utils::is_dir(&st.attr.kind) {
722 return Err(Error::from_raw_os_error(libc::ENOTDIR).into());
723 }
724
725 let handle = self.next_handle.fetch_add(1, Ordering::Relaxed);
726 let (layer, in_upper_layer, real_inode) = node.first_layer_inode().await;
728 let reply = layer.opendir(req, real_inode, flags).await?;
729
730 self.handles.lock().await.insert(
731 handle,
732 Arc::new(HandleData {
733 node: Arc::clone(&node),
734 real_handle: Some(RealHandle {
735 layer,
736 in_upper_layer,
737 inode: real_inode,
738 handle: AtomicU64::new(reply.fh),
739 }),
740 dir_snapshot: Mutex::new(None),
741 }),
742 );
743
744 Ok(ReplyOpen { fh: handle, flags })
745 }
746
747 async fn readdir<'a>(
751 &'a self,
752 req: Request,
753 parent: Inode,
754 fh: u64,
755 offset: i64,
756 ) -> Result<
757 ReplyDirectory<
758 impl futures_util::stream::Stream<Item = Result<DirectoryEntry>> + Send + 'a,
759 >,
760 > {
761 if self.config.no_readdir {
762 info!("fuse: readdir is not supported.");
763 return Err(Error::from_raw_os_error(libc::ENOTDIR).into());
764 }
765 let entries = self
766 .do_readdir(req, parent, fh, offset.try_into().unwrap())
767 .await?;
768 Ok(ReplyDirectory { entries })
769 }
770
771 async fn readdirplus<'a>(
774 &'a self,
775 req: Request,
776 parent: Inode,
777 fh: u64,
778 offset: u64,
779 _lock_owner: u64,
780 ) -> Result<
781 ReplyDirectoryPlus<
782 impl futures_util::stream::Stream<Item = Result<DirectoryEntryPlus>> + Send + 'a,
783 >,
784 > {
785 if self.config.no_readdir {
786 info!("fuse: readdir is not supported.");
787 return Err(Error::from_raw_os_error(libc::ENOTDIR).into());
788 }
789 trace!("readdirplus: parent: {parent}, fh: {fh}, offset: {offset}");
790 let entries = self.do_readdirplus(req, parent, fh, offset).await?;
791 match self.handles.lock().await.get(&fh) {
792 Some(h) => {
793 trace!(
794 "after readdirplus: found handle, seeing real_handle: {}",
795 h.real_handle.is_some()
796 );
797 }
798 None => trace!("after readdirplus: no handle found: {fh}"),
799 }
800 Ok(ReplyDirectoryPlus { entries })
801 }
802 async fn releasedir(&self, req: Request, _inode: Inode, fh: u64, flags: u32) -> Result<()> {
807 if self.no_opendir.load(Ordering::Relaxed) {
808 info!("fuse: releasedir is not supported.");
809 return Err(Error::from_raw_os_error(libc::ENOSYS).into());
810 }
811
812 if let Some(hd) = self.handles.lock().await.get(&fh) {
813 let rh = if let Some(ref h) = hd.real_handle {
814 h
815 } else {
816 return Err(
817 Error::other(format!("no real handle found for file handle {fh}")).into(),
818 );
819 };
820 let real_handle = rh.handle.load(Ordering::Relaxed);
821 let real_inode = rh.inode;
822 rh.layer
823 .releasedir(req, real_inode, real_handle, flags)
824 .await?;
825 }
826
827 self.handles.lock().await.remove(&fh);
828 Ok(())
829 }
830
831 async fn fsyncdir(&self, req: Request, inode: Inode, fh: u64, datasync: bool) -> Result<()> {
836 self.do_fsync(req, inode, datasync, fh, true)
837 .await
838 .map_err(|e| e.into())
839 }
840
841 #[allow(clippy::too_many_arguments)]
842 async fn getlk(
843 &self,
844 req: Request,
845 _inode: Inode,
846 fh: u64,
847 lock_owner: u64,
848 start: u64,
849 end: u64,
850 r#type: u32,
851 pid: u32,
852 ) -> Result<ReplyLock> {
853 if !self.no_open.load(Ordering::Relaxed) {
854 let handles = self.handles.lock().await;
855 if let Some(hd) = handles.get(&fh)
856 && let Some(ref rh) = hd.real_handle
857 {
858 match rh
859 .layer
860 .getlk(
861 req,
862 rh.inode,
863 rh.handle.load(Ordering::Relaxed),
864 lock_owner,
865 start,
866 end,
867 r#type,
868 pid,
869 )
870 .await
871 {
872 Ok(reply) => return Ok(reply),
873 Err(e) => {
874 let errno: i32 = e.into();
876 if errno != libc::ENOSYS {
877 return Err(errno.into());
878 }
879 }
880 }
881 }
882 }
883
884 Ok(ReplyLock {
886 start: 0,
887 end: 0,
888 r#type: libc::F_UNLCK as u32,
889 pid: 0,
890 })
891 }
892
893 #[allow(clippy::too_many_arguments)]
894 async fn setlk(
895 &self,
896 req: Request,
897 _inode: Inode,
898 fh: u64,
899 lock_owner: u64,
900 start: u64,
901 end: u64,
902 r#type: u32,
903 pid: u32,
904 block: bool,
905 ) -> Result<()> {
906 if !self.no_open.load(Ordering::Relaxed) {
907 let handles = self.handles.lock().await;
908 if let Some(hd) = handles.get(&fh)
909 && let Some(ref rh) = hd.real_handle
910 {
911 match rh
912 .layer
913 .setlk(
914 req,
915 rh.inode,
916 rh.handle.load(Ordering::Relaxed),
917 lock_owner,
918 start,
919 end,
920 r#type,
921 pid,
922 block,
923 )
924 .await
925 {
926 Ok(()) => return Ok(()),
927 Err(e) => {
928 let errno: i32 = e.into();
930 if errno != libc::ENOSYS {
931 return Err(errno.into());
932 }
933 }
934 }
935 }
936 }
937
938 Ok(())
940 }
941 async fn access(&self, req: Request, inode: Inode, mask: u32) -> Result<()> {
945 let node = self.lookup_node(req, inode, "").await?;
946
947 if node.whiteout.load(Ordering::Relaxed) {
948 return Err(Error::from_raw_os_error(libc::ENOENT).into());
949 }
950
951 let (layer, real_inode) = self.find_real_inode(inode).await?;
952 layer.access(req, real_inode, mask).await
953 }
954
955 async fn create(
972 &self,
973 req: Request,
974 parent: Inode,
975 name: &OsStr,
976 mode: u32,
977 flags: u32,
978 ) -> Result<ReplyCreated> {
979 let pnode = self.lookup_node(req, parent, "").await?;
981 if pnode.whiteout.load(Ordering::Relaxed) {
982 return Err(Error::from_raw_os_error(libc::ENOENT).into());
983 }
984
985 let mut flags: i32 = flags as i32;
986 flags |= libc::O_NOFOLLOW;
987 #[cfg(target_os = "linux")]
988 {
989 flags &= !libc::O_DIRECT;
990 }
991 if self.config.writeback {
992 if flags & libc::O_ACCMODE == libc::O_WRONLY {
993 flags &= !libc::O_ACCMODE;
994 flags |= libc::O_RDWR;
995 }
996
997 if flags & libc::O_APPEND != 0 {
998 flags &= !libc::O_APPEND;
999 }
1000 }
1001
1002 let final_handle = self
1003 .do_create(req, &pnode, name, mode, flags.try_into().unwrap())
1004 .await?;
1005 let entry = self.do_lookup(req, parent, name.to_str().unwrap()).await?;
1006 let fh = final_handle
1007 .ok_or_else(|| std::io::Error::new(ErrorKind::NotFound, "Handle not found"))?;
1008
1009 let mut opts = OpenOptions::empty();
1010 match self.config.cache_policy {
1011 CachePolicy::Never => opts |= OpenOptions::DIRECT_IO,
1012 CachePolicy::Always => opts |= OpenOptions::KEEP_CACHE,
1013 _ => {}
1014 }
1015
1016 Ok(ReplyCreated {
1017 ttl: entry.ttl,
1018 attr: entry.attr,
1019 generation: entry.generation,
1020 fh,
1021 flags: opts.bits(),
1022 })
1023 }
1024
1025 async fn batch_forget(&self, _req: Request, inodes: &[(Inode, u64)]) {
1027 for inode in inodes {
1028 self.forget_one(inode.0, inode.1).await;
1029 }
1030 }
1031
1032 async fn fallocate(
1039 &self,
1040 req: Request,
1041 inode: Inode,
1042 fh: u64,
1043 offset: u64,
1044 length: u64,
1045 mode: u32,
1046 ) -> Result<()> {
1047 let data = self
1049 .get_data(req, Some(fh), inode, libc::O_RDONLY as u32)
1050 .await?;
1051
1052 match data.real_handle {
1053 None => Err(Error::from_raw_os_error(libc::ENOENT).into()),
1054 Some(ref rhd) => {
1055 if !rhd.in_upper_layer {
1056 return Err(Error::from_raw_os_error(libc::EROFS).into());
1058 }
1059 rhd.layer
1060 .fallocate(
1061 req,
1062 rhd.inode,
1063 rhd.handle.load(Ordering::Relaxed),
1064 offset,
1065 length,
1066 mode,
1067 )
1068 .await
1069 }
1070 }
1071 }
1072
1073 async fn lseek(
1075 &self,
1076 req: Request,
1077 inode: Inode,
1078 fh: u64,
1079 offset: u64,
1080 whence: u32,
1081 ) -> Result<ReplyLSeek> {
1082 let node = self.lookup_node(req, inode, "").await?;
1083
1084 if node.whiteout.load(Ordering::Relaxed) {
1085 return Err(Error::from_raw_os_error(libc::ENOENT).into());
1086 }
1087
1088 let st = node.stat64(req).await?;
1089 if utils::is_dir(&st.attr.kind) {
1090 let (layer, real_inode, real_handle) = self.find_real_info_from_handle(fh).await?;
1093
1094 let handle_stat = match layer.getattr(req, real_inode, Some(real_handle), 0).await {
1096 Ok(s) => s,
1097 Err(_) => return Err(Error::from_raw_os_error(libc::EBADF).into()),
1098 };
1099
1100 if !utils::is_dir(&handle_stat.attr.kind) {
1101 return Err(Error::from_raw_os_error(libc::ENOTDIR).into());
1102 }
1103
1104 match whence {
1107 x if x == libc::SEEK_SET as u32 => {
1109 if offset > i64::MAX as u64 {
1112 return Err(Error::from_raw_os_error(libc::EINVAL).into());
1113 }
1114
1115 layer
1118 .lseek(req, real_inode, real_handle, offset, whence)
1119 .await
1120 }
1121 x if x == libc::SEEK_CUR as u32 => {
1123 let current = match layer
1126 .lseek(req, real_inode, real_handle, 0, libc::SEEK_CUR as u32)
1127 .await
1128 {
1129 Ok(r) => r.offset,
1130 Err(_) => return Err(Error::from_raw_os_error(libc::EINVAL).into()),
1131 };
1132
1133 if let Some(new_offset) = current.checked_add(offset) {
1136 if new_offset > i64::MAX as u64 {
1138 return Err(Error::from_raw_os_error(libc::EINVAL).into());
1139 }
1140
1141 match layer
1144 .lseek(
1145 req,
1146 real_inode,
1147 real_handle,
1148 new_offset,
1149 libc::SEEK_SET as u32,
1150 )
1151 .await
1152 {
1153 Ok(_) => Ok(ReplyLSeek { offset: new_offset }),
1154 Err(_) => Err(Error::from_raw_os_error(libc::EINVAL).into()),
1155 }
1156 } else {
1157 Err(Error::from_raw_os_error(libc::EINVAL).into())
1158 }
1159 }
1160 _ => Err(Error::from_raw_os_error(libc::EINVAL).into()),
1162 }
1163 } else {
1164 let (layer, real_inode, real_handle) = self.find_real_info_from_handle(fh).await?;
1167 layer
1168 .lseek(req, real_inode, real_handle, offset, whence)
1169 .await
1170 }
1171 }
1172
1173 async fn interrupt(&self, _req: Request, _unique: u64) -> Result<()> {
1174 Ok(())
1175 }
1176}
1177
1178#[cfg(test)]
1179mod tests {
1180 use std::{ffi::OsString, path::PathBuf, sync::Arc};
1181
1182 use rfuse3::{MountOptions, raw::Session};
1183 use tokio::signal;
1184 use tracing_subscriber::EnvFilter;
1185
1186 use crate::unionfs::BoxedLayer;
1187 use crate::{
1188 passthrough::{PassthroughArgs, new_passthroughfs_layer},
1189 unionfs::{OverlayFs, config::Config},
1190 };
1191 use rfuse3::raw::logfs::LoggingFileSystem;
1192
1193 #[tokio::test]
1194 #[ignore]
1195 async fn test_a_ovlfs() {
1196 let _ = tracing_subscriber::fmt()
1197 .with_env_filter(EnvFilter::from_default_env().add_directive("trace".parse().unwrap()))
1198 .try_init();
1199
1200 let mountpoint = PathBuf::from("/home/luxian/megatest/true_temp");
1202 let lowerdir = vec![PathBuf::from("/home/luxian/github/buck2-rust-third-party")];
1203 let upperdir = PathBuf::from("/home/luxian/upper");
1204
1205 let mut lower_layers: Vec<Arc<BoxedLayer>> = Vec::new();
1207 for lower in &lowerdir {
1208 let layer = new_passthroughfs_layer(PassthroughArgs {
1209 root_dir: lower.clone(),
1210 mapping: None::<&str>,
1211 })
1212 .await
1213 .unwrap();
1214 lower_layers.push(Arc::new(layer) as Arc<BoxedLayer>);
1215 }
1216 let upper_layer: Arc<BoxedLayer> = Arc::new(
1218 new_passthroughfs_layer(PassthroughArgs {
1219 root_dir: upperdir,
1220 mapping: None::<&str>,
1221 })
1222 .await
1223 .unwrap(),
1224 );
1225 let config = Config {
1227 mountpoint: mountpoint.clone(),
1228 do_import: true,
1229 ..Default::default()
1230 };
1231
1232 let overlayfs = OverlayFs::new(Some(upper_layer), lower_layers, config, 1).unwrap();
1233
1234 let logfs = LoggingFileSystem::new(overlayfs);
1235
1236 let mount_path: OsString = OsString::from(mountpoint);
1237
1238 let uid = unsafe { libc::getuid() };
1239 let gid = unsafe { libc::getgid() };
1240
1241 let not_unprivileged = false;
1242
1243 let mut mount_options = MountOptions::default();
1244 mount_options.force_readdir_plus(true).uid(uid).gid(gid);
1246
1247 let mut mount_handle: rfuse3::raw::MountHandle = if !not_unprivileged {
1248 Session::new(mount_options)
1249 .mount_with_unprivileged(logfs, mount_path)
1250 .await
1251 .unwrap()
1252 } else {
1253 Session::new(mount_options)
1254 .mount(logfs, mount_path)
1255 .await
1256 .unwrap()
1257 };
1258
1259 let handle = &mut mount_handle;
1260
1261 tokio::select! {
1262 res = handle => res.unwrap(),
1263 _ = signal::ctrl_c() => {
1264 mount_handle.unmount().await.unwrap()
1265 }
1266 }
1267 }
1268}