1use super::Inode;
2use super::OverlayFs;
3use super::utils;
4use crate::overlayfs::HandleData;
5use crate::overlayfs::RealHandle;
6use crate::overlayfs::{AtomicU64, CachePolicy};
7use crate::util::open_options::OpenOptions;
8use rfuse3::raw::prelude::*;
9use rfuse3::*;
10use std::ffi::OsStr;
11use std::io::Error;
12use std::io::ErrorKind;
13use std::num::NonZeroU32;
14use std::sync::Arc;
15use std::sync::atomic::Ordering;
16use tokio::sync::Mutex;
17use tracing::info;
18use tracing::trace;
19
20impl Filesystem for OverlayFs {
21 async fn init(&self, _req: Request) -> Result<ReplyInit> {
23 if self.config.do_import {
24 self.import().await?;
25 }
26 if !self.config.do_import || self.config.writeback {
27 self.writeback.store(true, Ordering::Relaxed);
28 }
29 if !self.config.do_import || self.config.no_open {
30 self.no_open.store(true, Ordering::Relaxed);
31 }
32 if !self.config.do_import || self.config.no_opendir {
33 self.no_opendir.store(true, Ordering::Relaxed);
34 }
35 if !self.config.do_import || self.config.killpriv_v2 {
36 self.killpriv_v2.store(true, Ordering::Relaxed);
37 }
38 if self.config.perfile_dax {
39 self.perfile_dax.store(true, Ordering::Relaxed);
40 }
41
42 Ok(ReplyInit {
43 max_write: NonZeroU32::new(128 * 1024).unwrap(),
44 })
45 }
46
47 async fn destroy(&self, _req: Request) {}
52
53 async fn lookup(&self, req: Request, parent: Inode, name: &OsStr) -> Result<ReplyEntry> {
55 let tmp = name.to_string_lossy().to_string();
56 let result = self.do_lookup(req, parent, tmp.as_str()).await;
57 match result {
58 Ok(e) => Ok(e),
59 Err(err) => Err(err.into()),
60 }
61 }
62
63 async fn forget(&self, _req: Request, inode: Inode, nlookup: u64) {
73 self.forget_one(inode, nlookup).await;
74 }
75
76 async fn getattr(
78 &self,
79 req: Request,
80 inode: Inode,
81 fh: Option<u64>,
82 flags: u32,
83 ) -> Result<ReplyAttr> {
84 if !self.no_open.load(Ordering::Relaxed)
85 && let Some(h) = fh
86 {
87 let handles = self.handles.lock().await;
88 if let Some(hd) = handles.get(&h)
89 && let Some(ref rh) = hd.real_handle
90 {
91 let mut rep: ReplyAttr = rh
92 .layer
93 .getattr(req, rh.inode, Some(rh.handle.load(Ordering::Relaxed)), 0)
94 .await?;
95 rep.attr.ino = inode;
96 return Ok(rep);
97 }
98 }
99
100 let node: Arc<super::OverlayInode> = self.lookup_node(req, inode, "").await?;
101 let (layer, _, lower_inode) = node.first_layer_inode().await;
102 let mut re = layer.getattr(req, lower_inode, None, flags).await?;
103 re.attr.ino = inode;
104 Ok(re)
105 }
106
107 async fn setattr(
109 &self,
110 req: Request,
111 inode: Inode,
112 fh: Option<u64>,
113 set_attr: SetAttr,
114 ) -> Result<ReplyAttr> {
115 self.upper_layer
117 .as_ref()
118 .cloned()
119 .ok_or_else(|| Error::from_raw_os_error(libc::EROFS))?;
120
121 if !self.no_open.load(Ordering::Relaxed)
123 && let Some(h) = fh
124 {
125 let handles = self.handles.lock().await;
126 if let Some(hd) = handles.get(&h)
127 && let Some(ref rhd) = hd.real_handle
128 {
129 if rhd.in_upper_layer {
131 let mut rep = rhd
132 .layer
133 .setattr(
134 req,
135 rhd.inode,
136 Some(rhd.handle.load(Ordering::Relaxed)),
137 set_attr,
138 )
139 .await?;
140 rep.attr.ino = inode;
141 return Ok(rep);
142 }
143 }
144 }
145
146 let mut node = self.lookup_node(req, inode, "").await?;
147
148 if !node.in_upper_layer().await {
149 node = self.copy_node_up(req, node.clone()).await?
150 }
151
152 let (layer, _, real_inode) = node.first_layer_inode().await;
153 let mut rep = layer.setattr(req, real_inode, None, set_attr).await?;
155 rep.attr.ino = inode;
156 Ok(rep)
157 }
158
159 async fn readlink(&self, req: Request, inode: Inode) -> Result<ReplyData> {
161 trace!("READLINK: inode: {inode}\n");
162
163 let node = self.lookup_node(req, inode, "").await?;
164
165 if node.whiteout.load(Ordering::Relaxed) {
166 return Err(Error::from_raw_os_error(libc::ENOENT).into());
167 }
168
169 let (layer, _, inode) = node.first_layer_inode().await;
170 layer.readlink(req, inode).await
171 }
172
173 async fn symlink(
175 &self,
176 req: Request,
177 parent: Inode,
178 name: &OsStr,
179 link: &OsStr,
180 ) -> Result<ReplyEntry> {
181 let sname = name.to_string_lossy().into_owned().to_owned();
183 let slinkname = link.to_string_lossy().into_owned().to_owned();
184
185 let pnode = self.lookup_node(req, parent, "").await?;
186 self.do_symlink(req, slinkname.as_str(), &pnode, sname.as_str())
187 .await?;
188
189 self.do_lookup(req, parent, sname.as_str())
190 .await
191 .map_err(|e| e.into())
192 }
193
194 async fn mknod(
198 &self,
199 req: Request,
200 parent: Inode,
201 name: &OsStr,
202 mode: u32,
203 rdev: u32,
204 ) -> Result<ReplyEntry> {
205 let sname = name.to_string_lossy().to_string();
206
207 let pnode = self.lookup_node(req, parent, "").await?;
209 if pnode.whiteout.load(Ordering::Relaxed) {
210 return Err(Error::from_raw_os_error(libc::ENOENT).into());
211 }
212
213 self.do_mknod(req, &pnode, sname.as_str(), mode, rdev, 0)
214 .await?;
215 self.do_lookup(req, parent, sname.as_str())
216 .await
217 .map_err(|e| e.into())
218 }
219
220 async fn mkdir(
222 &self,
223 req: Request,
224 parent: Inode,
225 name: &OsStr,
226 mode: u32,
227 umask: u32,
228 ) -> Result<ReplyEntry> {
229 let sname = name.to_string_lossy().to_string();
230
231 let pnode = self.lookup_node(req, parent, "").await?;
233 if pnode.whiteout.load(Ordering::Relaxed) {
234 return Err(Error::from_raw_os_error(libc::ENOENT).into());
235 }
236
237 self.do_mkdir(req, pnode, sname.as_str(), mode, umask)
238 .await?;
239 self.do_lookup(req, parent, sname.as_str())
240 .await
241 .map_err(|e| e.into())
242 }
243
244 async fn unlink(&self, req: Request, parent: Inode, name: &OsStr) -> Result<()> {
246 self.do_rm(req, parent, name, false)
247 .await
248 .map_err(|e| e.into())
249 }
250
251 async fn rmdir(&self, req: Request, parent: Inode, name: &OsStr) -> Result<()> {
253 self.do_rm(req, parent, name, true)
254 .await
255 .map_err(|e| e.into())
256 }
257
258 async fn rename(
260 &self,
261 req: Request,
262 parent: Inode,
263 name: &OsStr,
264 new_parent: Inode,
265 new_name: &OsStr,
266 ) -> Result<()> {
267 self.do_rename(req, parent, name, new_parent, new_name)
268 .await
269 .map_err(|e| e.into())
270 }
271
272 async fn link(
274 &self,
275 req: Request,
276 inode: Inode,
277 new_parent: Inode,
278 new_name: &OsStr,
279 ) -> Result<ReplyEntry> {
280 let node = self.lookup_node(req, inode, "").await?;
281 if node.whiteout.load(Ordering::Relaxed) {
282 return Err(Error::from_raw_os_error(libc::ENOENT).into());
283 }
284
285 let newpnode = self.lookup_node(req, new_parent, "").await?;
286 if newpnode.whiteout.load(Ordering::Relaxed) {
287 return Err(Error::from_raw_os_error(libc::ENOENT).into());
288 }
289 let new_name = new_name.to_str().unwrap();
290 self.do_link(req, &node, &newpnode, new_name).await?;
295 self.do_lookup(req, new_parent, new_name)
297 .await
298 .map_err(|e| e.into())
299 }
300
301 async fn open(&self, req: Request, inode: Inode, flags: u32) -> Result<ReplyOpen> {
316 if self.no_open.load(Ordering::Relaxed) {
317 info!("fuse: open is not supported.");
318 return Err(Error::from_raw_os_error(libc::ENOSYS).into());
319 }
320
321 let readonly: bool = flags
322 & (libc::O_APPEND | libc::O_CREAT | libc::O_TRUNC | libc::O_RDWR | libc::O_WRONLY)
323 as u32
324 == 0;
325 let mut flags: i32 = flags as i32;
327
328 flags |= libc::O_NOFOLLOW;
329
330 if self.config.writeback {
331 if flags & libc::O_ACCMODE == libc::O_WRONLY {
332 flags &= !libc::O_ACCMODE;
333 flags |= libc::O_RDWR;
334 }
335
336 if flags & libc::O_APPEND != 0 {
337 flags &= !libc::O_APPEND;
338 }
339 }
340 let node = self.lookup_node(req, inode, "").await?;
342
343 if node.whiteout.load(Ordering::Relaxed) {
345 return Err(Error::from_raw_os_error(libc::ENOENT).into());
346 }
347
348 if !readonly {
349 self.copy_node_up(req, node.clone()).await?;
351 }
352
353 let (_l, h) = node.open(req, flags as u32, 0).await?;
355
356 let hd = self.next_handle.fetch_add(1, Ordering::Relaxed);
357 let (layer, in_upper_layer, inode) = node.first_layer_inode().await;
358 let handle_data = HandleData {
359 node: node.clone(),
360 real_handle: Some(RealHandle {
361 layer,
362 in_upper_layer,
363 inode,
364 handle: AtomicU64::new(h.fh),
365 }),
366 dir_snapshot: Mutex::new(None),
367 };
368
369 self.handles.lock().await.insert(hd, Arc::new(handle_data));
370
371 let mut opts = OpenOptions::empty();
372 match self.config.cache_policy {
373 CachePolicy::Never => opts |= OpenOptions::DIRECT_IO,
374 CachePolicy::Always => opts |= OpenOptions::KEEP_CACHE,
375 _ => {}
376 }
377
378 Ok(ReplyOpen {
381 fh: hd,
382 flags: opts.bits(),
383 })
384 }
385
386 async fn read(
392 &self,
393 req: Request,
394 inode: Inode,
395 fh: u64,
396 offset: u64,
397 size: u32,
398 ) -> Result<ReplyData> {
399 let data = self.get_data(req, Some(fh), inode, 0).await?;
400
401 match data.real_handle {
402 None => Err(Error::from_raw_os_error(libc::ENOENT).into()),
403 Some(ref hd) => {
404 hd.layer
405 .read(
406 req,
407 hd.inode,
408 hd.handle.load(Ordering::Relaxed),
409 offset,
410 size,
411 )
412 .await
413 }
414 }
415 }
416
417 #[allow(clippy::too_many_arguments)]
425 async fn write(
426 &self,
427 req: Request,
428 inode: Inode,
429 fh: u64,
430 offset: u64,
431 data: &[u8],
432 write_flags: u32,
433 flags: u32,
434 ) -> Result<ReplyWrite> {
435 let handle_data: Arc<HandleData> = self.get_data(req, Some(fh), inode, flags).await?;
436
437 match handle_data.real_handle {
438 None => Err(Error::from_raw_os_error(libc::ENOENT).into()),
439 Some(ref hd) => {
440 hd.layer
441 .write(
442 req,
443 hd.inode,
444 hd.handle.load(Ordering::Relaxed),
445 offset,
446 data,
447 write_flags,
448 flags,
449 )
450 .await
451 }
452 }
453 }
454
455 #[allow(clippy::too_many_arguments)]
460 async fn copy_file_range(
461 &self,
462 req: Request,
463 inode_in: Inode,
464 fh_in: u64,
465 offset_in: u64,
466 inode_out: Inode,
467 fh_out: u64,
468 offset_out: u64,
469 length: u64,
470 flags: u64,
471 ) -> Result<ReplyCopyFileRange> {
472 let data_in = self.get_data(req, Some(fh_in), inode_in, 0).await?;
474 let handle_in = match data_in.real_handle {
475 None => return Err(Error::from_raw_os_error(libc::ENOENT).into()),
476 Some(ref hd) => hd,
477 };
478
479 let data_out = self.get_data(req, Some(fh_out), inode_out, 0).await?;
481 let handle_out = match data_out.real_handle {
482 None => return Err(Error::from_raw_os_error(libc::ENOENT).into()),
483 Some(ref hd) => hd,
484 };
485
486 if !Arc::ptr_eq(&handle_in.layer, &handle_out.layer) {
488 return Err(Error::from_raw_os_error(libc::EXDEV).into());
490 }
491
492 handle_in
494 .layer
495 .copy_file_range(
496 req,
497 handle_in.inode,
498 handle_in.handle.load(Ordering::Relaxed),
499 offset_in,
500 handle_out.inode,
501 handle_out.handle.load(Ordering::Relaxed),
502 offset_out,
503 length,
504 flags,
505 )
506 .await
507 }
508
509 async fn statfs(&self, req: Request, inode: Inode) -> Result<ReplyStatFs> {
511 self.do_statvfs(req, inode).await.map_err(|e| e.into())
512 }
513
514 async fn release(
522 &self,
523 req: Request,
524 _inode: Inode,
525 fh: u64,
526 flags: u32,
527 lock_owner: u64,
528 flush: bool,
529 ) -> Result<()> {
530 if self.no_open.load(Ordering::Relaxed) {
531 info!("fuse: release is not supported.");
532 return Err(Error::from_raw_os_error(libc::ENOSYS).into());
533 }
534
535 if let Some(hd) = self.handles.lock().await.get(&fh) {
536 let rh = if let Some(ref h) = hd.real_handle {
537 h
538 } else {
539 return Err(
540 Error::other(format!("no real handle found for file handle {fh}")).into(),
541 );
542 };
543 let real_handle = rh.handle.load(Ordering::Relaxed);
544 let real_inode = rh.inode;
545 rh.layer
546 .release(req, real_inode, real_handle, flags, lock_owner, flush)
547 .await?;
548 }
549
550 self.handles.lock().await.remove(&fh);
551
552 Ok(())
553 }
554
555 async fn fsync(&self, req: Request, inode: Inode, fh: u64, datasync: bool) -> Result<()> {
558 self.do_fsync(req, inode, datasync, fh, false)
559 .await
560 .map_err(|e| e.into())
561 }
562
563 async fn setxattr(
565 &self,
566 req: Request,
567 inode: Inode,
568 name: &OsStr,
569 value: &[u8],
570 flags: u32,
571 position: u32,
572 ) -> Result<()> {
573 let node = self.lookup_node(req, inode, "").await?;
574
575 if node.whiteout.load(Ordering::Relaxed) {
576 return Err(Error::from_raw_os_error(libc::ENOENT).into());
577 }
578
579 if !node.in_upper_layer().await {
580 self.copy_node_up(req, node.clone()).await?;
582 }
583
584 let (layer, _, real_inode) = node.first_layer_inode().await;
585
586 layer
587 .setxattr(req, real_inode, name, value, flags, position)
588 .await
589 }
590
591 async fn getxattr(
595 &self,
596 req: Request,
597 inode: Inode,
598 name: &OsStr,
599 size: u32,
600 ) -> Result<ReplyXAttr> {
601 let node = self.lookup_node(req, inode, "").await?;
602
603 if node.whiteout.load(Ordering::Relaxed) {
604 return Err(Error::from_raw_os_error(libc::ENOENT).into());
605 }
606
607 let (layer, real_inode) = self.find_real_inode(inode).await?;
608
609 layer.getxattr(req, real_inode, name, size).await
610 }
611
612 async fn listxattr(&self, req: Request, inode: Inode, size: u32) -> Result<ReplyXAttr> {
617 let node = self.lookup_node(req, inode, "").await?;
618 if node.whiteout.load(Ordering::Relaxed) {
619 return Err(Error::from_raw_os_error(libc::ENOENT).into());
620 }
621 let (layer, real_inode) = self.find_real_inode(inode).await?;
622 layer.listxattr(req, real_inode, size).await
623 }
624
625 async fn removexattr(&self, req: Request, inode: Inode, name: &OsStr) -> Result<()> {
627 let node = self.lookup_node(req, inode, "").await?;
628
629 if node.whiteout.load(Ordering::Relaxed) {
630 return Err(Error::from_raw_os_error(libc::ENOENT).into());
631 }
632
633 if !node.in_upper_layer().await {
634 self.copy_node_up(req, node.clone()).await?;
636 }
637
638 let (layer, _, ino) = node.first_layer_inode().await;
639 layer.removexattr(req, ino, name).await
640
641 }
643
644 async fn flush(&self, req: Request, inode: Inode, fh: u64, lock_owner: u64) -> Result<()> {
657 if self.no_open.load(Ordering::Relaxed) {
658 return Err(Error::from_raw_os_error(libc::ENOSYS).into());
659 }
660
661 let node = self.lookup_node(req, inode, "").await;
662 match node {
663 Ok(n) => {
664 if n.whiteout.load(Ordering::Relaxed) {
665 return Err(Error::from_raw_os_error(libc::ENOENT).into());
666 }
667 }
668 Err(e) => {
669 if e.raw_os_error() == Some(libc::ENOENT) {
670 trace!("flush: inode {inode} is stale");
671 } else {
672 return Err(e.into());
673 }
674 }
675 }
676
677 let (layer, real_inode, real_handle) = self.find_real_info_from_handle(fh).await?;
678
679 if inode
681 != self
682 .handles
683 .lock()
684 .await
685 .get(&fh)
686 .map(|h| h.node.inode)
687 .unwrap_or(0)
688 {
689 return Err(Error::other("inode does not match handle").into());
690 }
691
692 trace!("flushing, real_inode: {real_inode}, real_handle: {real_handle}");
693 layer.flush(req, real_inode, real_handle, lock_owner).await
694 }
695
696 async fn opendir(&self, req: Request, inode: Inode, flags: u32) -> Result<ReplyOpen> {
704 if self.no_opendir.load(Ordering::Relaxed) {
705 info!("fuse: opendir is not supported.");
706 return Err(Error::from_raw_os_error(libc::ENOSYS).into());
707 }
708
709 let node = self.lookup_node(req, inode, ".").await?;
711
712 if node.whiteout.load(Ordering::Relaxed) {
713 return Err(Error::from_raw_os_error(libc::ENOENT).into());
714 }
715
716 let st = node.stat64(req).await?;
717 if !utils::is_dir(&st.attr.kind) {
718 return Err(Error::from_raw_os_error(libc::ENOTDIR).into());
719 }
720
721 let handle = self.next_handle.fetch_add(1, Ordering::Relaxed);
722 let (layer, in_upper_layer, real_inode) = node.first_layer_inode().await;
724 let reply = layer.opendir(req, real_inode, flags).await?;
725
726 self.handles.lock().await.insert(
727 handle,
728 Arc::new(HandleData {
729 node: Arc::clone(&node),
730 real_handle: Some(RealHandle {
731 layer,
732 in_upper_layer,
733 inode: real_inode,
734 handle: AtomicU64::new(reply.fh),
735 }),
736 dir_snapshot: Mutex::new(None),
737 }),
738 );
739
740 Ok(ReplyOpen { fh: handle, flags })
741 }
742
743 async fn readdir<'a>(
747 &'a self,
748 req: Request,
749 parent: Inode,
750 fh: u64,
751 offset: i64,
752 ) -> Result<
753 ReplyDirectory<
754 impl futures_util::stream::Stream<Item = Result<DirectoryEntry>> + Send + 'a,
755 >,
756 > {
757 if self.config.no_readdir {
758 info!("fuse: readdir is not supported.");
759 return Err(Error::from_raw_os_error(libc::ENOTDIR).into());
760 }
761 let entries = self
762 .do_readdir(req, parent, fh, offset.try_into().unwrap())
763 .await?;
764 Ok(ReplyDirectory { entries })
765 }
766
767 async fn readdirplus<'a>(
770 &'a self,
771 req: Request,
772 parent: Inode,
773 fh: u64,
774 offset: u64,
775 _lock_owner: u64,
776 ) -> Result<
777 ReplyDirectoryPlus<
778 impl futures_util::stream::Stream<Item = Result<DirectoryEntryPlus>> + Send + 'a,
779 >,
780 > {
781 if self.config.no_readdir {
782 info!("fuse: readdir is not supported.");
783 return Err(Error::from_raw_os_error(libc::ENOTDIR).into());
784 }
785 trace!("readdirplus: parent: {parent}, fh: {fh}, offset: {offset}");
786 let entries = self.do_readdirplus(req, parent, fh, offset).await?;
787 match self.handles.lock().await.get(&fh) {
788 Some(h) => {
789 trace!(
790 "after readdirplus: found handle, seeing real_handle: {}",
791 h.real_handle.is_some()
792 );
793 }
794 None => trace!("after readdirplus: no handle found: {fh}"),
795 }
796 Ok(ReplyDirectoryPlus { entries })
797 }
798 async fn releasedir(&self, req: Request, _inode: Inode, fh: u64, flags: u32) -> Result<()> {
803 if self.no_opendir.load(Ordering::Relaxed) {
804 info!("fuse: releasedir is not supported.");
805 return Err(Error::from_raw_os_error(libc::ENOSYS).into());
806 }
807
808 if let Some(hd) = self.handles.lock().await.get(&fh) {
809 let rh = if let Some(ref h) = hd.real_handle {
810 h
811 } else {
812 return Err(
813 Error::other(format!("no real handle found for file handle {fh}")).into(),
814 );
815 };
816 let real_handle = rh.handle.load(Ordering::Relaxed);
817 let real_inode = rh.inode;
818 rh.layer
819 .releasedir(req, real_inode, real_handle, flags)
820 .await?;
821 }
822
823 self.handles.lock().await.remove(&fh);
824 Ok(())
825 }
826
827 async fn fsyncdir(&self, req: Request, inode: Inode, fh: u64, datasync: bool) -> Result<()> {
832 self.do_fsync(req, inode, datasync, fh, true)
833 .await
834 .map_err(|e| e.into())
835 }
836 async fn access(&self, req: Request, inode: Inode, mask: u32) -> Result<()> {
840 let node = self.lookup_node(req, inode, "").await?;
841
842 if node.whiteout.load(Ordering::Relaxed) {
843 return Err(Error::from_raw_os_error(libc::ENOENT).into());
844 }
845
846 let (layer, real_inode) = self.find_real_inode(inode).await?;
847 layer.access(req, real_inode, mask).await
848 }
849
850 async fn create(
867 &self,
868 req: Request,
869 parent: Inode,
870 name: &OsStr,
871 mode: u32,
872 flags: u32,
873 ) -> Result<ReplyCreated> {
874 let pnode = self.lookup_node(req, parent, "").await?;
876 if pnode.whiteout.load(Ordering::Relaxed) {
877 return Err(Error::from_raw_os_error(libc::ENOENT).into());
878 }
879
880 let mut flags: i32 = flags as i32;
881 flags |= libc::O_NOFOLLOW;
882 flags &= !libc::O_DIRECT;
883 if self.config.writeback {
884 if flags & libc::O_ACCMODE == libc::O_WRONLY {
885 flags &= !libc::O_ACCMODE;
886 flags |= libc::O_RDWR;
887 }
888
889 if flags & libc::O_APPEND != 0 {
890 flags &= !libc::O_APPEND;
891 }
892 }
893
894 let final_handle = self
895 .do_create(req, &pnode, name, mode, flags.try_into().unwrap())
896 .await?;
897 let entry = self.do_lookup(req, parent, name.to_str().unwrap()).await?;
898 let fh = final_handle
899 .ok_or_else(|| std::io::Error::new(ErrorKind::NotFound, "Handle not found"))?;
900
901 let mut opts = OpenOptions::empty();
902 match self.config.cache_policy {
903 CachePolicy::Never => opts |= OpenOptions::DIRECT_IO,
904 CachePolicy::Always => opts |= OpenOptions::KEEP_CACHE,
905 _ => {}
906 }
907
908 Ok(ReplyCreated {
909 ttl: entry.ttl,
910 attr: entry.attr,
911 generation: entry.generation,
912 fh,
913 flags: opts.bits(),
914 })
915 }
916
917 async fn batch_forget(&self, _req: Request, inodes: &[(Inode, u64)]) {
919 for inode in inodes {
920 self.forget_one(inode.0, inode.1).await;
921 }
922 }
923
924 async fn fallocate(
931 &self,
932 req: Request,
933 inode: Inode,
934 fh: u64,
935 offset: u64,
936 length: u64,
937 mode: u32,
938 ) -> Result<()> {
939 let data = self
941 .get_data(req, Some(fh), inode, libc::O_RDONLY as u32)
942 .await?;
943
944 match data.real_handle {
945 None => Err(Error::from_raw_os_error(libc::ENOENT).into()),
946 Some(ref rhd) => {
947 if !rhd.in_upper_layer {
948 return Err(Error::from_raw_os_error(libc::EROFS).into());
950 }
951 rhd.layer
952 .fallocate(
953 req,
954 rhd.inode,
955 rhd.handle.load(Ordering::Relaxed),
956 offset,
957 length,
958 mode,
959 )
960 .await
961 }
962 }
963 }
964
965 async fn lseek(
967 &self,
968 req: Request,
969 inode: Inode,
970 fh: u64,
971 offset: u64,
972 whence: u32,
973 ) -> Result<ReplyLSeek> {
974 let node = self.lookup_node(req, inode, "").await?;
975
976 if node.whiteout.load(Ordering::Relaxed) {
977 return Err(Error::from_raw_os_error(libc::ENOENT).into());
978 }
979
980 let st = node.stat64(req).await?;
981 if utils::is_dir(&st.attr.kind) {
982 let (layer, real_inode, real_handle) = self.find_real_info_from_handle(fh).await?;
985
986 let handle_stat = match layer.getattr(req, real_inode, Some(real_handle), 0).await {
988 Ok(s) => s,
989 Err(_) => return Err(Error::from_raw_os_error(libc::EBADF).into()),
990 };
991
992 if !utils::is_dir(&handle_stat.attr.kind) {
993 return Err(Error::from_raw_os_error(libc::ENOTDIR).into());
994 }
995
996 match whence {
999 x if x == libc::SEEK_SET as u32 => {
1001 if offset > i64::MAX as u64 {
1004 return Err(Error::from_raw_os_error(libc::EINVAL).into());
1005 }
1006
1007 layer
1010 .lseek(req, real_inode, real_handle, offset, whence)
1011 .await
1012 }
1013 x if x == libc::SEEK_CUR as u32 => {
1015 let current = match layer
1018 .lseek(req, real_inode, real_handle, 0, libc::SEEK_CUR as u32)
1019 .await
1020 {
1021 Ok(r) => r.offset,
1022 Err(_) => return Err(Error::from_raw_os_error(libc::EINVAL).into()),
1023 };
1024
1025 if let Some(new_offset) = current.checked_add(offset) {
1028 if new_offset > i64::MAX as u64 {
1030 return Err(Error::from_raw_os_error(libc::EINVAL).into());
1031 }
1032
1033 match layer
1036 .lseek(
1037 req,
1038 real_inode,
1039 real_handle,
1040 new_offset,
1041 libc::SEEK_SET as u32,
1042 )
1043 .await
1044 {
1045 Ok(_) => Ok(ReplyLSeek { offset: new_offset }),
1046 Err(_) => Err(Error::from_raw_os_error(libc::EINVAL).into()),
1047 }
1048 } else {
1049 Err(Error::from_raw_os_error(libc::EINVAL).into())
1050 }
1051 }
1052 _ => Err(Error::from_raw_os_error(libc::EINVAL).into()),
1054 }
1055 } else {
1056 let (layer, real_inode, real_handle) = self.find_real_info_from_handle(fh).await?;
1059 layer
1060 .lseek(req, real_inode, real_handle, offset, whence)
1061 .await
1062 }
1063 }
1064
1065 async fn interrupt(&self, _req: Request, _unique: u64) -> Result<()> {
1066 Ok(())
1067 }
1068}
1069#[cfg(test)]
1070mod tests {
1071 use std::{ffi::OsString, path::PathBuf, sync::Arc};
1072
1073 use rfuse3::{MountOptions, raw::Session};
1074 use tokio::signal;
1075 use tracing_subscriber::EnvFilter;
1076
1077 use crate::{
1078 overlayfs::{OverlayFs, config::Config},
1079 passthrough::{PassthroughArgs, new_passthroughfs_layer, newlogfs::LoggingFileSystem},
1080 };
1081
1082 #[tokio::test]
1083 #[ignore]
1084 async fn test_a_ovlfs() {
1085 let _ = tracing_subscriber::fmt()
1086 .with_env_filter(EnvFilter::from_default_env().add_directive("trace".parse().unwrap()))
1087 .try_init();
1088
1089 let mountpoint = PathBuf::from("/home/luxian/megatest/true_temp");
1091 let lowerdir = vec![PathBuf::from("/home/luxian/github/buck2-rust-third-party")];
1092 let upperdir = PathBuf::from("/home/luxian/upper");
1093
1094 let mut lower_layers = Vec::new();
1096 for lower in &lowerdir {
1097 let layer = new_passthroughfs_layer(PassthroughArgs {
1098 root_dir: lower.clone(),
1099 mapping: None::<&str>,
1100 })
1101 .await
1102 .unwrap();
1103 lower_layers.push(Arc::new(layer));
1104 }
1105 let upper_layer = Arc::new(
1107 new_passthroughfs_layer(PassthroughArgs {
1108 root_dir: upperdir,
1109 mapping: None::<&str>,
1110 })
1111 .await
1112 .unwrap(),
1113 );
1114 let config = Config {
1116 mountpoint: mountpoint.clone(),
1117 do_import: true,
1118 ..Default::default()
1119 };
1120
1121 let overlayfs = OverlayFs::new(Some(upper_layer), lower_layers, config, 1).unwrap();
1122
1123 let logfs = LoggingFileSystem::new(overlayfs);
1124
1125 let mount_path: OsString = OsString::from(mountpoint);
1126
1127 let uid = unsafe { libc::getuid() };
1128 let gid = unsafe { libc::getgid() };
1129
1130 let not_unprivileged = false;
1131
1132 let mut mount_options = MountOptions::default();
1133 mount_options.force_readdir_plus(true).uid(uid).gid(gid);
1135
1136 let mut mount_handle: rfuse3::raw::MountHandle = if !not_unprivileged {
1137 Session::new(mount_options)
1138 .mount_with_unprivileged(logfs, mount_path)
1139 .await
1140 .unwrap()
1141 } else {
1142 Session::new(mount_options)
1143 .mount(logfs, mount_path)
1144 .await
1145 .unwrap()
1146 };
1147
1148 let handle = &mut mount_handle;
1149
1150 tokio::select! {
1151 res = handle => res.unwrap(),
1152 _ = signal::ctrl_c() => {
1153 mount_handle.unmount().await.unwrap()
1154 }
1155 }
1156 }
1157}