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 _type: u32,
851 _pid: u32,
852 ) -> Result<ReplyLock> {
853 Err(libc::ENOSYS.into())
854 }
855
856 #[allow(clippy::too_many_arguments)]
857 async fn setlk(
858 &self,
859 _req: Request,
860 _inode: Inode,
861 _fh: u64,
862 _lock_owner: u64,
863 _start: u64,
864 _end: u64,
865 _type: u32,
866 _pid: u32,
867 _block: bool,
868 ) -> Result<()> {
869 Err(libc::ENOSYS.into())
870 }
871 async fn access(&self, req: Request, inode: Inode, mask: u32) -> Result<()> {
875 let node = self.lookup_node(req, inode, "").await?;
876
877 if node.whiteout.load(Ordering::Relaxed) {
878 return Err(Error::from_raw_os_error(libc::ENOENT).into());
879 }
880
881 let (layer, real_inode) = self.find_real_inode(inode).await?;
882 layer.access(req, real_inode, mask).await
883 }
884
885 async fn create(
902 &self,
903 req: Request,
904 parent: Inode,
905 name: &OsStr,
906 mode: u32,
907 flags: u32,
908 ) -> Result<ReplyCreated> {
909 let pnode = self.lookup_node(req, parent, "").await?;
911 if pnode.whiteout.load(Ordering::Relaxed) {
912 return Err(Error::from_raw_os_error(libc::ENOENT).into());
913 }
914
915 let mut flags: i32 = flags as i32;
916 flags |= libc::O_NOFOLLOW;
917 #[cfg(target_os = "linux")]
918 {
919 flags &= !libc::O_DIRECT;
920 }
921 if self.config.writeback {
922 if flags & libc::O_ACCMODE == libc::O_WRONLY {
923 flags &= !libc::O_ACCMODE;
924 flags |= libc::O_RDWR;
925 }
926
927 if flags & libc::O_APPEND != 0 {
928 flags &= !libc::O_APPEND;
929 }
930 }
931
932 let final_handle = self
933 .do_create(req, &pnode, name, mode, flags.try_into().unwrap())
934 .await?;
935 let entry = self.do_lookup(req, parent, name.to_str().unwrap()).await?;
936 let fh = final_handle
937 .ok_or_else(|| std::io::Error::new(ErrorKind::NotFound, "Handle not found"))?;
938
939 let mut opts = OpenOptions::empty();
940 match self.config.cache_policy {
941 CachePolicy::Never => opts |= OpenOptions::DIRECT_IO,
942 CachePolicy::Always => opts |= OpenOptions::KEEP_CACHE,
943 _ => {}
944 }
945
946 Ok(ReplyCreated {
947 ttl: entry.ttl,
948 attr: entry.attr,
949 generation: entry.generation,
950 fh,
951 flags: opts.bits(),
952 })
953 }
954
955 async fn batch_forget(&self, _req: Request, inodes: &[(Inode, u64)]) {
957 for inode in inodes {
958 self.forget_one(inode.0, inode.1).await;
959 }
960 }
961
962 async fn fallocate(
969 &self,
970 req: Request,
971 inode: Inode,
972 fh: u64,
973 offset: u64,
974 length: u64,
975 mode: u32,
976 ) -> Result<()> {
977 let data = self
979 .get_data(req, Some(fh), inode, libc::O_RDONLY as u32)
980 .await?;
981
982 match data.real_handle {
983 None => Err(Error::from_raw_os_error(libc::ENOENT).into()),
984 Some(ref rhd) => {
985 if !rhd.in_upper_layer {
986 return Err(Error::from_raw_os_error(libc::EROFS).into());
988 }
989 rhd.layer
990 .fallocate(
991 req,
992 rhd.inode,
993 rhd.handle.load(Ordering::Relaxed),
994 offset,
995 length,
996 mode,
997 )
998 .await
999 }
1000 }
1001 }
1002
1003 async fn lseek(
1005 &self,
1006 req: Request,
1007 inode: Inode,
1008 fh: u64,
1009 offset: u64,
1010 whence: u32,
1011 ) -> Result<ReplyLSeek> {
1012 let node = self.lookup_node(req, inode, "").await?;
1013
1014 if node.whiteout.load(Ordering::Relaxed) {
1015 return Err(Error::from_raw_os_error(libc::ENOENT).into());
1016 }
1017
1018 let st = node.stat64(req).await?;
1019 if utils::is_dir(&st.attr.kind) {
1020 let (layer, real_inode, real_handle) = self.find_real_info_from_handle(fh).await?;
1023
1024 let handle_stat = match layer.getattr(req, real_inode, Some(real_handle), 0).await {
1026 Ok(s) => s,
1027 Err(_) => return Err(Error::from_raw_os_error(libc::EBADF).into()),
1028 };
1029
1030 if !utils::is_dir(&handle_stat.attr.kind) {
1031 return Err(Error::from_raw_os_error(libc::ENOTDIR).into());
1032 }
1033
1034 match whence {
1037 x if x == libc::SEEK_SET as u32 => {
1039 if offset > i64::MAX as u64 {
1042 return Err(Error::from_raw_os_error(libc::EINVAL).into());
1043 }
1044
1045 layer
1048 .lseek(req, real_inode, real_handle, offset, whence)
1049 .await
1050 }
1051 x if x == libc::SEEK_CUR as u32 => {
1053 let current = match layer
1056 .lseek(req, real_inode, real_handle, 0, libc::SEEK_CUR as u32)
1057 .await
1058 {
1059 Ok(r) => r.offset,
1060 Err(_) => return Err(Error::from_raw_os_error(libc::EINVAL).into()),
1061 };
1062
1063 if let Some(new_offset) = current.checked_add(offset) {
1066 if new_offset > i64::MAX as u64 {
1068 return Err(Error::from_raw_os_error(libc::EINVAL).into());
1069 }
1070
1071 match layer
1074 .lseek(
1075 req,
1076 real_inode,
1077 real_handle,
1078 new_offset,
1079 libc::SEEK_SET as u32,
1080 )
1081 .await
1082 {
1083 Ok(_) => Ok(ReplyLSeek { offset: new_offset }),
1084 Err(_) => Err(Error::from_raw_os_error(libc::EINVAL).into()),
1085 }
1086 } else {
1087 Err(Error::from_raw_os_error(libc::EINVAL).into())
1088 }
1089 }
1090 _ => Err(Error::from_raw_os_error(libc::EINVAL).into()),
1092 }
1093 } else {
1094 let (layer, real_inode, real_handle) = self.find_real_info_from_handle(fh).await?;
1097 layer
1098 .lseek(req, real_inode, real_handle, offset, whence)
1099 .await
1100 }
1101 }
1102
1103 async fn interrupt(&self, _req: Request, _unique: u64) -> Result<()> {
1104 Ok(())
1105 }
1106}
1107
1108#[cfg(test)]
1109mod tests {
1110 use std::{ffi::OsString, path::PathBuf, sync::Arc};
1111
1112 use rfuse3::{MountOptions, raw::Session};
1113 use tokio::signal;
1114 use tracing_subscriber::EnvFilter;
1115
1116 use crate::unionfs::BoxedLayer;
1117 use crate::{
1118 passthrough::{PassthroughArgs, new_passthroughfs_layer},
1119 unionfs::{OverlayFs, config::Config},
1120 };
1121 use rfuse3::raw::logfs::LoggingFileSystem;
1122
1123 #[tokio::test]
1124 #[ignore]
1125 async fn test_a_ovlfs() {
1126 let _ = tracing_subscriber::fmt()
1127 .with_env_filter(EnvFilter::from_default_env().add_directive("trace".parse().unwrap()))
1128 .try_init();
1129
1130 let mountpoint = PathBuf::from("/home/luxian/megatest/true_temp");
1132 let lowerdir = vec![PathBuf::from("/home/luxian/github/buck2-rust-third-party")];
1133 let upperdir = PathBuf::from("/home/luxian/upper");
1134
1135 let mut lower_layers: Vec<Arc<BoxedLayer>> = Vec::new();
1137 for lower in &lowerdir {
1138 let layer = new_passthroughfs_layer(PassthroughArgs {
1139 root_dir: lower.clone(),
1140 mapping: None::<&str>,
1141 })
1142 .await
1143 .unwrap();
1144 lower_layers.push(Arc::new(layer) as Arc<BoxedLayer>);
1145 }
1146 let upper_layer: Arc<BoxedLayer> = Arc::new(
1148 new_passthroughfs_layer(PassthroughArgs {
1149 root_dir: upperdir,
1150 mapping: None::<&str>,
1151 })
1152 .await
1153 .unwrap(),
1154 );
1155 let config = Config {
1157 mountpoint: mountpoint.clone(),
1158 do_import: true,
1159 ..Default::default()
1160 };
1161
1162 let overlayfs = OverlayFs::new(Some(upper_layer), lower_layers, config, 1).unwrap();
1163
1164 let logfs = LoggingFileSystem::new(overlayfs);
1165
1166 let mount_path: OsString = OsString::from(mountpoint);
1167
1168 let uid = unsafe { libc::getuid() };
1169 let gid = unsafe { libc::getgid() };
1170
1171 let not_unprivileged = false;
1172
1173 let mut mount_options = MountOptions::default();
1174 mount_options.force_readdir_plus(true).uid(uid).gid(gid);
1176
1177 let mut mount_handle: rfuse3::raw::MountHandle = if !not_unprivileged {
1178 Session::new(mount_options)
1179 .mount_with_unprivileged(logfs, mount_path)
1180 .await
1181 .unwrap()
1182 } else {
1183 Session::new(mount_options)
1184 .mount(logfs, mount_path)
1185 .await
1186 .unwrap()
1187 };
1188
1189 let handle = &mut mount_handle;
1190
1191 tokio::select! {
1192 res = handle => res.unwrap(),
1193 _ = signal::ctrl_c() => {
1194 mount_handle.unmount().await.unwrap()
1195 }
1196 }
1197 }
1198}