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 async fn statfs(&self, req: Request, inode: Inode) -> Result<ReplyStatFs> {
510 self.do_statvfs(req, inode).await.map_err(|e| e.into())
511 }
512
513 async fn release(
521 &self,
522 req: Request,
523 _inode: Inode,
524 fh: u64,
525 flags: u32,
526 lock_owner: u64,
527 flush: bool,
528 ) -> Result<()> {
529 if self.no_open.load(Ordering::Relaxed) {
530 info!("fuse: release is not supported.");
531 return Err(Error::from_raw_os_error(libc::ENOSYS).into());
532 }
533
534 if let Some(hd) = self.handles.lock().await.get(&fh) {
535 let rh = if let Some(ref h) = hd.real_handle {
536 h
537 } else {
538 return Err(
539 Error::other(format!("no real handle found for file handle {fh}")).into(),
540 );
541 };
542 let real_handle = rh.handle.load(Ordering::Relaxed);
543 let real_inode = rh.inode;
544 rh.layer
545 .release(req, real_inode, real_handle, flags, lock_owner, flush)
546 .await?;
547 }
548
549 self.handles.lock().await.remove(&fh);
550
551 Ok(())
552 }
553
554 async fn fsync(&self, req: Request, inode: Inode, fh: u64, datasync: bool) -> Result<()> {
557 self.do_fsync(req, inode, datasync, fh, false)
558 .await
559 .map_err(|e| e.into())
560 }
561
562 async fn setxattr(
564 &self,
565 req: Request,
566 inode: Inode,
567 name: &OsStr,
568 value: &[u8],
569 flags: u32,
570 position: u32,
571 ) -> Result<()> {
572 let node = self.lookup_node(req, inode, "").await?;
573
574 if node.whiteout.load(Ordering::Relaxed) {
575 return Err(Error::from_raw_os_error(libc::ENOENT).into());
576 }
577
578 if !node.in_upper_layer().await {
579 self.copy_node_up(req, node.clone()).await?;
581 }
582
583 let (layer, _, real_inode) = node.first_layer_inode().await;
584
585 layer
586 .setxattr(req, real_inode, name, value, flags, position)
587 .await
588 }
589
590 async fn getxattr(
594 &self,
595 req: Request,
596 inode: Inode,
597 name: &OsStr,
598 size: u32,
599 ) -> Result<ReplyXAttr> {
600 let node = self.lookup_node(req, inode, "").await?;
601
602 if node.whiteout.load(Ordering::Relaxed) {
603 return Err(Error::from_raw_os_error(libc::ENOENT).into());
604 }
605
606 let (layer, real_inode) = self.find_real_inode(inode).await?;
607
608 layer.getxattr(req, real_inode, name, size).await
609 }
610
611 async fn listxattr(&self, req: Request, inode: Inode, size: u32) -> Result<ReplyXAttr> {
616 let node = self.lookup_node(req, inode, "").await?;
617 if node.whiteout.load(Ordering::Relaxed) {
618 return Err(Error::from_raw_os_error(libc::ENOENT).into());
619 }
620 let (layer, real_inode) = self.find_real_inode(inode).await?;
621 layer.listxattr(req, real_inode, size).await
622 }
623
624 async fn removexattr(&self, req: Request, inode: Inode, name: &OsStr) -> Result<()> {
626 let node = self.lookup_node(req, inode, "").await?;
627
628 if node.whiteout.load(Ordering::Relaxed) {
629 return Err(Error::from_raw_os_error(libc::ENOENT).into());
630 }
631
632 if !node.in_upper_layer().await {
633 self.copy_node_up(req, node.clone()).await?;
635 }
636
637 let (layer, _, ino) = node.first_layer_inode().await;
638 layer.removexattr(req, ino, name).await
639
640 }
642
643 async fn flush(&self, req: Request, inode: Inode, fh: u64, lock_owner: u64) -> Result<()> {
656 if self.no_open.load(Ordering::Relaxed) {
657 return Err(Error::from_raw_os_error(libc::ENOSYS).into());
658 }
659
660 let node = self.lookup_node(req, inode, "").await;
661 match node {
662 Ok(n) => {
663 if n.whiteout.load(Ordering::Relaxed) {
664 return Err(Error::from_raw_os_error(libc::ENOENT).into());
665 }
666 }
667 Err(e) => {
668 if e.raw_os_error() == Some(libc::ENOENT) {
669 trace!("flush: inode {inode} is stale");
670 } else {
671 return Err(e.into());
672 }
673 }
674 }
675
676 let (layer, real_inode, real_handle) = self.find_real_info_from_handle(fh).await?;
677
678 if inode
680 != self
681 .handles
682 .lock()
683 .await
684 .get(&fh)
685 .map(|h| h.node.inode)
686 .unwrap_or(0)
687 {
688 return Err(Error::other("inode does not match handle").into());
689 }
690
691 trace!("flushing, real_inode: {real_inode}, real_handle: {real_handle}");
692 layer.flush(req, real_inode, real_handle, lock_owner).await
693 }
694
695 async fn opendir(&self, req: Request, inode: Inode, flags: u32) -> Result<ReplyOpen> {
703 if self.no_opendir.load(Ordering::Relaxed) {
704 info!("fuse: opendir is not supported.");
705 return Err(Error::from_raw_os_error(libc::ENOSYS).into());
706 }
707
708 let node = self.lookup_node(req, inode, ".").await?;
710
711 if node.whiteout.load(Ordering::Relaxed) {
712 return Err(Error::from_raw_os_error(libc::ENOENT).into());
713 }
714
715 let st = node.stat64(req).await?;
716 if !utils::is_dir(&st.attr.kind) {
717 return Err(Error::from_raw_os_error(libc::ENOTDIR).into());
718 }
719
720 let handle = self.next_handle.fetch_add(1, Ordering::Relaxed);
721 let (layer, in_upper_layer, real_inode) = node.first_layer_inode().await;
723 let reply = layer.opendir(req, real_inode, flags).await?;
724
725 self.handles.lock().await.insert(
726 handle,
727 Arc::new(HandleData {
728 node: Arc::clone(&node),
729 real_handle: Some(RealHandle {
730 layer,
731 in_upper_layer,
732 inode: real_inode,
733 handle: AtomicU64::new(reply.fh),
734 }),
735 dir_snapshot: Mutex::new(None),
736 }),
737 );
738
739 Ok(ReplyOpen { fh: handle, flags })
740 }
741
742 async fn readdir<'a>(
746 &'a self,
747 req: Request,
748 parent: Inode,
749 fh: u64,
750 offset: i64,
751 ) -> Result<
752 ReplyDirectory<
753 impl futures_util::stream::Stream<Item = Result<DirectoryEntry>> + Send + 'a,
754 >,
755 > {
756 if self.config.no_readdir {
757 info!("fuse: readdir is not supported.");
758 return Err(Error::from_raw_os_error(libc::ENOTDIR).into());
759 }
760 let entries = self
761 .do_readdir(req, parent, fh, offset.try_into().unwrap())
762 .await?;
763 Ok(ReplyDirectory { entries })
764 }
765
766 async fn readdirplus<'a>(
769 &'a self,
770 req: Request,
771 parent: Inode,
772 fh: u64,
773 offset: u64,
774 _lock_owner: u64,
775 ) -> Result<
776 ReplyDirectoryPlus<
777 impl futures_util::stream::Stream<Item = Result<DirectoryEntryPlus>> + Send + 'a,
778 >,
779 > {
780 if self.config.no_readdir {
781 info!("fuse: readdir is not supported.");
782 return Err(Error::from_raw_os_error(libc::ENOTDIR).into());
783 }
784 trace!("readdirplus: parent: {parent}, fh: {fh}, offset: {offset}");
785 let entries = self.do_readdirplus(req, parent, fh, offset).await?;
786 match self.handles.lock().await.get(&fh) {
787 Some(h) => {
788 trace!(
789 "after readdirplus: found handle, seeing real_handle: {}",
790 h.real_handle.is_some()
791 );
792 }
793 None => trace!("after readdirplus: no handle found: {fh}"),
794 }
795 Ok(ReplyDirectoryPlus { entries })
796 }
797 async fn releasedir(&self, req: Request, _inode: Inode, fh: u64, flags: u32) -> Result<()> {
802 if self.no_opendir.load(Ordering::Relaxed) {
803 info!("fuse: releasedir is not supported.");
804 return Err(Error::from_raw_os_error(libc::ENOSYS).into());
805 }
806
807 if let Some(hd) = self.handles.lock().await.get(&fh) {
808 let rh = if let Some(ref h) = hd.real_handle {
809 h
810 } else {
811 return Err(
812 Error::other(format!("no real handle found for file handle {fh}")).into(),
813 );
814 };
815 let real_handle = rh.handle.load(Ordering::Relaxed);
816 let real_inode = rh.inode;
817 rh.layer
818 .releasedir(req, real_inode, real_handle, flags)
819 .await?;
820 }
821
822 self.handles.lock().await.remove(&fh);
823 Ok(())
824 }
825
826 async fn fsyncdir(&self, req: Request, inode: Inode, fh: u64, datasync: bool) -> Result<()> {
831 self.do_fsync(req, inode, datasync, fh, true)
832 .await
833 .map_err(|e| e.into())
834 }
835 async fn access(&self, req: Request, inode: Inode, mask: u32) -> Result<()> {
839 let node = self.lookup_node(req, inode, "").await?;
840
841 if node.whiteout.load(Ordering::Relaxed) {
842 return Err(Error::from_raw_os_error(libc::ENOENT).into());
843 }
844
845 let (layer, real_inode) = self.find_real_inode(inode).await?;
846 layer.access(req, real_inode, mask).await
847 }
848
849 async fn create(
866 &self,
867 req: Request,
868 parent: Inode,
869 name: &OsStr,
870 mode: u32,
871 flags: u32,
872 ) -> Result<ReplyCreated> {
873 let pnode = self.lookup_node(req, parent, "").await?;
875 if pnode.whiteout.load(Ordering::Relaxed) {
876 return Err(Error::from_raw_os_error(libc::ENOENT).into());
877 }
878
879 let mut flags: i32 = flags as i32;
880 flags |= libc::O_NOFOLLOW;
881 flags &= !libc::O_DIRECT;
882 if self.config.writeback {
883 if flags & libc::O_ACCMODE == libc::O_WRONLY {
884 flags &= !libc::O_ACCMODE;
885 flags |= libc::O_RDWR;
886 }
887
888 if flags & libc::O_APPEND != 0 {
889 flags &= !libc::O_APPEND;
890 }
891 }
892
893 let final_handle = self
894 .do_create(req, &pnode, name, mode, flags.try_into().unwrap())
895 .await?;
896 let entry = self.do_lookup(req, parent, name.to_str().unwrap()).await?;
897 let fh = final_handle
898 .ok_or_else(|| std::io::Error::new(ErrorKind::NotFound, "Handle not found"))?;
899
900 let mut opts = OpenOptions::empty();
901 match self.config.cache_policy {
902 CachePolicy::Never => opts |= OpenOptions::DIRECT_IO,
903 CachePolicy::Always => opts |= OpenOptions::KEEP_CACHE,
904 _ => {}
905 }
906
907 Ok(ReplyCreated {
908 ttl: entry.ttl,
909 attr: entry.attr,
910 generation: entry.generation,
911 fh,
912 flags: opts.bits(),
913 })
914 }
915
916 async fn batch_forget(&self, _req: Request, inodes: &[(Inode, u64)]) {
918 for inode in inodes {
919 self.forget_one(inode.0, inode.1).await;
920 }
921 }
922
923 async fn fallocate(
930 &self,
931 req: Request,
932 inode: Inode,
933 fh: u64,
934 offset: u64,
935 length: u64,
936 mode: u32,
937 ) -> Result<()> {
938 let data = self
940 .get_data(req, Some(fh), inode, libc::O_RDONLY as u32)
941 .await?;
942
943 match data.real_handle {
944 None => Err(Error::from_raw_os_error(libc::ENOENT).into()),
945 Some(ref rhd) => {
946 if !rhd.in_upper_layer {
947 return Err(Error::from_raw_os_error(libc::EROFS).into());
949 }
950 rhd.layer
951 .fallocate(
952 req,
953 rhd.inode,
954 rhd.handle.load(Ordering::Relaxed),
955 offset,
956 length,
957 mode,
958 )
959 .await
960 }
961 }
962 }
963
964 async fn lseek(
966 &self,
967 req: Request,
968 inode: Inode,
969 fh: u64,
970 offset: u64,
971 whence: u32,
972 ) -> Result<ReplyLSeek> {
973 let node = self.lookup_node(req, inode, "").await?;
974
975 if node.whiteout.load(Ordering::Relaxed) {
976 return Err(Error::from_raw_os_error(libc::ENOENT).into());
977 }
978
979 let st = node.stat64(req).await?;
980 if utils::is_dir(&st.attr.kind) {
981 let (layer, real_inode, real_handle) = self.find_real_info_from_handle(fh).await?;
984
985 let handle_stat = match layer.getattr(req, real_inode, Some(real_handle), 0).await {
987 Ok(s) => s,
988 Err(_) => return Err(Error::from_raw_os_error(libc::EBADF).into()),
989 };
990
991 if !utils::is_dir(&handle_stat.attr.kind) {
992 return Err(Error::from_raw_os_error(libc::ENOTDIR).into());
993 }
994
995 match whence {
998 x if x == libc::SEEK_SET as u32 => {
1000 if offset > i64::MAX as u64 {
1003 return Err(Error::from_raw_os_error(libc::EINVAL).into());
1004 }
1005
1006 layer
1009 .lseek(req, real_inode, real_handle, offset, whence)
1010 .await
1011 }
1012 x if x == libc::SEEK_CUR as u32 => {
1014 let current = match layer
1017 .lseek(req, real_inode, real_handle, 0, libc::SEEK_CUR as u32)
1018 .await
1019 {
1020 Ok(r) => r.offset,
1021 Err(_) => return Err(Error::from_raw_os_error(libc::EINVAL).into()),
1022 };
1023
1024 if let Some(new_offset) = current.checked_add(offset) {
1027 if new_offset > i64::MAX as u64 {
1029 return Err(Error::from_raw_os_error(libc::EINVAL).into());
1030 }
1031
1032 match layer
1035 .lseek(
1036 req,
1037 real_inode,
1038 real_handle,
1039 new_offset,
1040 libc::SEEK_SET as u32,
1041 )
1042 .await
1043 {
1044 Ok(_) => Ok(ReplyLSeek { offset: new_offset }),
1045 Err(_) => Err(Error::from_raw_os_error(libc::EINVAL).into()),
1046 }
1047 } else {
1048 Err(Error::from_raw_os_error(libc::EINVAL).into())
1049 }
1050 }
1051 _ => Err(Error::from_raw_os_error(libc::EINVAL).into()),
1053 }
1054 } else {
1055 let (layer, real_inode, real_handle) = self.find_real_info_from_handle(fh).await?;
1058 layer
1059 .lseek(req, real_inode, real_handle, offset, whence)
1060 .await
1061 }
1062 }
1063}
1064#[cfg(test)]
1065mod tests {
1066 use std::{ffi::OsString, path::PathBuf, sync::Arc};
1067
1068 use rfuse3::{MountOptions, raw::Session};
1069 use tokio::signal;
1070 use tracing_subscriber::EnvFilter;
1071
1072 use crate::{
1073 overlayfs::{OverlayFs, config::Config},
1074 passthrough::{PassthroughArgs, new_passthroughfs_layer, newlogfs::LoggingFileSystem},
1075 };
1076
1077 #[tokio::test]
1078 #[ignore]
1079 async fn test_a_ovlfs() {
1080 let _ = tracing_subscriber::fmt()
1081 .with_env_filter(EnvFilter::from_default_env().add_directive("trace".parse().unwrap()))
1082 .try_init();
1083
1084 let mountpoint = PathBuf::from("/home/luxian/megatest/true_temp");
1086 let lowerdir = vec![PathBuf::from("/home/luxian/github/buck2-rust-third-party")];
1087 let upperdir = PathBuf::from("/home/luxian/upper");
1088
1089 let mut lower_layers = Vec::new();
1091 for lower in &lowerdir {
1092 let layer = new_passthroughfs_layer(PassthroughArgs {
1093 root_dir: lower.clone(),
1094 mapping: None::<&str>,
1095 })
1096 .await
1097 .unwrap();
1098 lower_layers.push(Arc::new(layer));
1099 }
1100 let upper_layer = Arc::new(
1102 new_passthroughfs_layer(PassthroughArgs {
1103 root_dir: upperdir,
1104 mapping: None::<&str>,
1105 })
1106 .await
1107 .unwrap(),
1108 );
1109 let config = Config {
1111 mountpoint: mountpoint.clone(),
1112 do_import: true,
1113 ..Default::default()
1114 };
1115
1116 let overlayfs = OverlayFs::new(Some(upper_layer), lower_layers, config, 1).unwrap();
1117
1118 let logfs = LoggingFileSystem::new(overlayfs);
1119
1120 let mount_path: OsString = OsString::from(mountpoint);
1121
1122 let uid = unsafe { libc::getuid() };
1123 let gid = unsafe { libc::getgid() };
1124
1125 let not_unprivileged = false;
1126
1127 let mut mount_options = MountOptions::default();
1128 mount_options.force_readdir_plus(true).uid(uid).gid(gid);
1130
1131 let mut mount_handle: rfuse3::raw::MountHandle = if !not_unprivileged {
1132 Session::new(mount_options)
1133 .mount_with_unprivileged(logfs, mount_path)
1134 .await
1135 .unwrap()
1136 } else {
1137 Session::new(mount_options)
1138 .mount(logfs, mount_path)
1139 .await
1140 .unwrap()
1141 };
1142
1143 let handle = &mut mount_handle;
1144
1145 tokio::select! {
1146 res = handle => res.unwrap(),
1147 _ = signal::ctrl_c() => {
1148 mount_handle.unmount().await.unwrap()
1149 }
1150 }
1151 }
1152}