1use super::*;
5use std::ffi::CStr;
6use std::io::Result;
7
8use std::sync::atomic::{AtomicU64, Ordering};
9use std::sync::Arc;
10use std::time::Duration;
11
12use crate::abi::fuse_abi::{stat64, statvfs64, CreateIn};
13use crate::api::filesystem::{
14 Context, DirEntry, Entry, FileSystem, FsOptions, GetxattrReply, ListxattrReply, OpenOptions,
15 SetattrValid, ZeroCopyReader, ZeroCopyWriter,
16};
17
18use libc;
19use std::io::{Error, ErrorKind};
20
21impl FileSystem for OverlayFs {
22 type Inode = Inode;
23 type Handle = Handle;
24
25 fn init(&self, capable: FsOptions) -> Result<FsOptions> {
26 let mut opts = FsOptions::DO_READDIRPLUS | FsOptions::READDIRPLUS_AUTO;
29
30 if self.config.do_import {
31 self.import()?;
32 }
33
34 if (!self.config.do_import || self.config.writeback)
35 && capable.contains(FsOptions::WRITEBACK_CACHE)
36 {
37 opts |= FsOptions::WRITEBACK_CACHE;
38 self.writeback.store(true, Ordering::Relaxed);
39 }
40
41 if (!self.config.do_import || self.config.no_open)
42 && capable.contains(FsOptions::ZERO_MESSAGE_OPEN)
43 {
44 opts |= FsOptions::ZERO_MESSAGE_OPEN;
45 opts.remove(FsOptions::ATOMIC_O_TRUNC);
46 self.no_open.store(true, Ordering::Relaxed);
47 }
48
49 if (!self.config.do_import || self.config.no_opendir)
50 && capable.contains(FsOptions::ZERO_MESSAGE_OPENDIR)
51 {
52 opts |= FsOptions::ZERO_MESSAGE_OPENDIR;
53 self.no_opendir.store(true, Ordering::Relaxed);
54 }
55
56 if (!self.config.do_import || self.config.killpriv_v2)
57 && capable.contains(FsOptions::HANDLE_KILLPRIV_V2)
58 {
59 opts |= FsOptions::HANDLE_KILLPRIV_V2;
60 self.killpriv_v2.store(true, Ordering::Relaxed);
61 }
62
63 if self.config.perfile_dax && capable.contains(FsOptions::PERFILE_DAX) {
64 opts |= FsOptions::PERFILE_DAX;
65 self.perfile_dax.store(true, Ordering::Relaxed);
66 }
67
68 Ok(opts)
69 }
70
71 fn destroy(&self) {}
72
73 fn statfs(&self, ctx: &Context, inode: Inode) -> Result<statvfs64> {
74 trace!("STATFS: inode: {}\n", inode);
75 self.do_statvfs(ctx, inode)
76 }
77
78 fn lookup(&self, ctx: &Context, parent: Inode, name: &CStr) -> Result<Entry> {
79 let tmp = name.to_string_lossy().to_string();
80 trace!("LOOKUP: parent: {}, name: {}\n", parent, tmp);
81 let result = self.do_lookup(ctx, parent, tmp.as_str());
82 if result.is_ok() {
83 trace!("LOOKUP result: {:?}", result.as_ref().unwrap());
84 }
85 result
87 }
88
89 fn forget(&self, _ctx: &Context, inode: Inode, count: u64) {
90 trace!("FORGET: inode: {}, count: {}\n", inode, count);
91 self.forget_one(inode, count);
92 }
94
95 fn batch_forget(&self, _ctx: &Context, requests: Vec<(Inode, u64)>) {
96 trace!("BATCH_FORGET: requests: {:?}\n", requests);
97 for (inode, count) in requests {
98 self.forget_one(inode, count);
99 }
100 }
101
102 fn opendir(
103 &self,
104 ctx: &Context,
105 inode: Inode,
106 _flags: u32,
107 ) -> Result<(Option<Handle>, OpenOptions)> {
108 trace!("OPENDIR: inode: {}\n", inode);
109 if self.no_opendir.load(Ordering::Relaxed) {
110 info!("fuse: opendir is not supported.");
111 return Err(Error::from_raw_os_error(libc::ENOSYS));
112 }
113
114 let mut opts = OpenOptions::empty();
115
116 if let CachePolicy::Always = self.config.cache_policy {
117 opts |= OpenOptions::KEEP_CACHE;
118 }
119
120 let node = self.lookup_node(ctx, inode, ".")?;
122
123 if node.whiteout.load(Ordering::Relaxed) {
124 return Err(Error::from_raw_os_error(libc::ENOENT));
125 }
126
127 let st = node.stat64(ctx)?;
128 if !utils::is_dir(st) {
129 return Err(Error::from_raw_os_error(libc::ENOTDIR));
130 }
131
132 let handle = self.next_handle.fetch_add(1, Ordering::Relaxed);
133
134 self.handles.lock().unwrap().insert(
135 handle,
136 Arc::new(HandleData {
137 node: Arc::clone(&node),
138 real_handle: None,
139 }),
140 );
141
142 Ok((Some(handle), opts))
143 }
144
145 fn releasedir(&self, _ctx: &Context, inode: Inode, _flags: u32, handle: Handle) -> Result<()> {
146 trace!("RELEASEDIR: inode: {}, handle: {}\n", inode, handle);
147 if self.no_opendir.load(Ordering::Relaxed) {
148 info!("fuse: releasedir is not supported.");
149 return Err(Error::from_raw_os_error(libc::ENOSYS));
150 }
151
152 self.handles.lock().unwrap().remove(&handle);
153
154 Ok(())
155 }
156
157 fn mkdir(
162 &self,
163 ctx: &Context,
164 parent: Inode,
165 name: &CStr,
166 mode: u32,
167 umask: u32,
168 ) -> Result<Entry> {
169 let sname = name.to_string_lossy().to_string();
170
171 trace!("MKDIR: parent: {}, name: {}\n", parent, sname);
172
173 let pnode = self.lookup_node(ctx, parent, "")?;
175 if pnode.whiteout.load(Ordering::Relaxed) {
176 return Err(Error::from_raw_os_error(libc::ENOENT));
177 }
178
179 self.do_mkdir(ctx, &pnode, sname.as_str(), mode, umask)?;
180 let entry = self.do_lookup(ctx, parent, sname.as_str());
181 entry
182 }
183
184 fn rmdir(&self, ctx: &Context, parent: Inode, name: &CStr) -> Result<()> {
185 trace!(
186 "RMDIR: parent: {}, name: {}\n",
187 parent,
188 name.to_string_lossy()
189 );
190 self.do_rm(ctx, parent, name, true)
191 }
192
193 fn readdir(
194 &self,
195 ctx: &Context,
196 inode: Inode,
197 handle: Handle,
198 size: u32,
199 offset: u64,
200 add_entry: &mut dyn FnMut(DirEntry) -> Result<usize>,
201 ) -> Result<()> {
202 trace!("READDIR: inode: {}, handle: {}\n", inode, handle);
203 if self.config.no_readdir {
204 info!("fuse: readdir is not supported.");
205 return Ok(());
206 }
207 self.do_readdir(ctx, inode, handle, size, offset, false, &mut |dir_entry,
208 _|
209 -> Result<
210 usize,
211 > {
212 add_entry(dir_entry)
213 })
214 }
215
216 fn readdirplus(
217 &self,
218 ctx: &Context,
219 inode: Inode,
220 handle: Handle,
221 size: u32,
222 offset: u64,
223 add_entry: &mut dyn FnMut(DirEntry, Entry) -> Result<usize>,
224 ) -> Result<()> {
225 trace!("READDIRPLUS: inode: {}, handle: {}\n", inode, handle);
226 if self.config.no_readdir {
227 info!("fuse: readdirplus is not supported.");
228 return Ok(());
229 }
230 self.do_readdir(ctx, inode, handle, size, offset, true, &mut |dir_entry,
231 entry|
232 -> Result<
233 usize,
234 > {
235 match entry {
236 Some(e) => add_entry(dir_entry, e),
237 None => Err(Error::from_raw_os_error(libc::ENOENT)),
238 }
239 })
240 }
241
242 fn open(
243 &self,
244 ctx: &Context,
245 inode: Inode,
246 flags: u32,
247 fuse_flags: u32,
248 ) -> Result<(Option<Handle>, OpenOptions, Option<u32>)> {
249 trace!("OPEN: inode: {}, flags: {}\n", inode, flags);
251 if self.no_open.load(Ordering::Relaxed) {
252 info!("fuse: open is not supported.");
253 return Err(Error::from_raw_os_error(libc::ENOSYS));
254 }
255
256 let readonly: bool = flags
257 & (libc::O_APPEND | libc::O_CREAT | libc::O_TRUNC | libc::O_RDWR | libc::O_WRONLY)
258 as u32
259 == 0;
260 let mut flags: i32 = flags as i32;
262
263 flags |= libc::O_NOFOLLOW;
264
265 if self.config.writeback {
266 if flags & libc::O_ACCMODE == libc::O_WRONLY {
267 flags &= !libc::O_ACCMODE;
268 flags |= libc::O_RDWR;
269 }
270
271 if flags & libc::O_APPEND != 0 {
272 flags &= !libc::O_APPEND;
273 }
274 }
275 let node = self.lookup_node(ctx, inode, "")?;
277
278 if node.whiteout.load(Ordering::Relaxed) {
280 return Err(Error::from_raw_os_error(libc::ENOENT));
281 }
282
283 if !readonly {
284 self.copy_node_up(ctx, Arc::clone(&node))?;
286 }
287
288 let (_l, h, _) = node.open(ctx, flags as u32, fuse_flags)?;
290 match h {
291 None => Err(Error::from_raw_os_error(libc::ENOENT)),
292 Some(handle) => {
293 let hd = self.next_handle.fetch_add(1, Ordering::Relaxed);
294 let (layer, in_upper_layer, inode) = node.first_layer_inode();
295 let handle_data = HandleData {
296 node: Arc::clone(&node),
297 real_handle: Some(RealHandle {
298 layer,
299 in_upper_layer,
300 inode,
301 handle: AtomicU64::new(handle),
302 }),
303 };
304
305 self.handles
306 .lock()
307 .unwrap()
308 .insert(hd, Arc::new(handle_data));
309
310 let mut opts = OpenOptions::empty();
311 match self.config.cache_policy {
312 CachePolicy::Never => opts |= OpenOptions::DIRECT_IO,
313 CachePolicy::Always => opts |= OpenOptions::KEEP_CACHE,
314 _ => {}
315 }
316
317 trace!("OPEN: returning handle: {}", hd);
318
319 Ok((Some(hd), opts, None))
320 }
321 }
322 }
323
324 fn release(
325 &self,
326 ctx: &Context,
327 _inode: Inode,
328 flags: u32,
329 handle: Handle,
330 flush: bool,
331 flock_release: bool,
332 lock_owner: Option<u64>,
333 ) -> Result<()> {
334 trace!(
335 "RELEASE: inode: {}, flags: {}, handle: {}, flush: {}, flock_release: {}, lock_owner: {:?}\n",
336 _inode,
337 flags,
338 handle,
339 flush,
340 flock_release,
341 lock_owner
342 );
343
344 if self.no_open.load(Ordering::Relaxed) {
345 info!("fuse: release is not supported.");
346 return Err(Error::from_raw_os_error(libc::ENOSYS));
347 }
348
349 if let Some(hd) = self.handles.lock().unwrap().get(&handle) {
350 let rh = if let Some(ref h) = hd.real_handle {
351 h
352 } else {
353 return Err(Error::new(ErrorKind::Other, "no handle"));
354 };
355 let real_handle = rh.handle.load(Ordering::Relaxed);
356 let real_inode = rh.inode;
357 rh.layer.release(
358 ctx,
359 real_inode,
360 flags,
361 real_handle,
362 flush,
363 flock_release,
364 lock_owner,
365 )?;
366 }
367
368 self.handles.lock().unwrap().remove(&handle);
369
370 Ok(())
371 }
372
373 fn create(
374 &self,
375 ctx: &Context,
376 parent: Inode,
377 name: &CStr,
378 args: CreateIn,
379 ) -> Result<(Entry, Option<Handle>, OpenOptions, Option<u32>)> {
380 let sname = name.to_string_lossy().to_string();
381 trace!("CREATE: parent: {}, name: {}\n", parent, sname);
382
383 let pnode = self.lookup_node(ctx, parent, "")?;
385 if pnode.whiteout.load(Ordering::Relaxed) {
386 return Err(Error::from_raw_os_error(libc::ENOENT));
387 }
388
389 let mut hargs = args;
390 let mut flags: i32 = args.flags as i32;
391 flags |= libc::O_NOFOLLOW;
392 flags &= !libc::O_DIRECT;
393 if self.config.writeback {
394 if flags & libc::O_ACCMODE == libc::O_WRONLY {
395 flags &= !libc::O_ACCMODE;
396 flags |= libc::O_RDWR;
397 }
398
399 if flags & libc::O_APPEND != 0 {
400 flags &= !libc::O_APPEND;
401 }
402 }
403 hargs.flags = flags as u32;
404
405 let final_handle = self.do_create(ctx, &pnode, sname.as_str(), hargs)?;
406 let entry = self.do_lookup(ctx, parent, sname.as_str())?;
407
408 let mut opts = OpenOptions::empty();
409 match self.config.cache_policy {
410 CachePolicy::Never => opts |= OpenOptions::DIRECT_IO,
411 CachePolicy::Always => opts |= OpenOptions::KEEP_CACHE,
412 _ => {}
413 }
414
415 Ok((entry, final_handle, opts, None))
416 }
417
418 fn unlink(&self, ctx: &Context, parent: Inode, name: &CStr) -> Result<()> {
419 trace!(
420 "UNLINK: parent: {}, name: {}\n",
421 parent,
422 name.to_string_lossy()
423 );
424 self.do_rm(ctx, parent, name, false)
425 }
426
427 fn read(
428 &self,
429 ctx: &Context,
430 inode: Inode,
431 handle: Handle,
432 w: &mut dyn ZeroCopyWriter,
433 size: u32,
434 offset: u64,
435 lock_owner: Option<u64>,
436 flags: u32,
437 ) -> Result<usize> {
438 trace!(
439 "READ: inode: {}, handle: {}, size: {}, offset: {}, lock_owner: {:?}, flags: {}\n",
440 inode,
441 handle,
442 size,
443 offset,
444 lock_owner,
445 flags
446 );
447
448 let data = self.get_data(ctx, Some(handle), inode, flags)?;
449
450 match data.real_handle {
451 None => Err(Error::from_raw_os_error(libc::ENOENT)),
452 Some(ref hd) => hd.layer.read(
453 ctx,
454 hd.inode,
455 hd.handle.load(Ordering::Relaxed),
456 w,
457 size,
458 offset,
459 lock_owner,
460 flags,
461 ),
462 }
463 }
464
465 fn write(
466 &self,
467 ctx: &Context,
468 inode: Inode,
469 handle: Handle,
470 r: &mut dyn ZeroCopyReader,
471 size: u32,
472 offset: u64,
473 lock_owner: Option<u64>,
474 delayed_write: bool,
475 flags: u32,
476 fuse_flags: u32,
477 ) -> Result<usize> {
478 trace!(
479 "WRITE: inode: {}, handle: {}, size: {}, offset: {}, lock_owner: {:?}, delayed_write: {}, flags: {}, fuse_flags: {}\n",
480 inode,
481 handle,
482 size,
483 offset,
484 lock_owner,
485 delayed_write,
486 flags,
487 fuse_flags
488 );
489
490 let data = self.get_data(ctx, Some(handle), inode, flags)?;
491
492 match data.real_handle {
493 None => Err(Error::from_raw_os_error(libc::ENOENT)),
494 Some(ref hd) => hd.layer.write(
495 ctx,
496 hd.inode,
497 hd.handle.load(Ordering::Relaxed),
498 r,
499 size,
500 offset,
501 lock_owner,
502 delayed_write,
503 flags,
504 fuse_flags,
505 ),
506 }
507 }
508
509 fn getattr(
510 &self,
511 ctx: &Context,
512 inode: Inode,
513 handle: Option<Handle>,
514 ) -> Result<(stat64, Duration)> {
515 trace!(
516 "GETATTR: inode: {}, handle: {}\n",
517 inode,
518 handle.unwrap_or_default()
519 );
520
521 if !self.no_open.load(Ordering::Relaxed) {
522 if let Some(h) = handle {
523 if let Some(hd) = self.handles.lock().unwrap().get(&h) {
524 if let Some(ref rh) = hd.real_handle {
525 let (st, _d) = rh.layer.getattr(
526 ctx,
527 rh.inode,
528 Some(rh.handle.load(Ordering::Relaxed)),
529 )?;
530 return Ok((st, self.config.attr_timeout));
531 }
532 }
533 }
534 }
535
536 let node = self.lookup_node(ctx, inode, "")?;
537 let (layer, _, inode) = node.first_layer_inode();
538 let (st, _) = layer.getattr(ctx, inode, None)?;
539 Ok((st, self.config.attr_timeout))
540 }
541
542 fn setattr(
543 &self,
544 ctx: &Context,
545 inode: Inode,
546 attr: stat64,
547 handle: Option<Handle>,
548 valid: SetattrValid,
549 ) -> Result<(stat64, Duration)> {
550 trace!("SETATTR: inode: {}\n", inode);
551
552 self.upper_layer
554 .as_ref()
555 .cloned()
556 .ok_or_else(|| Error::from_raw_os_error(libc::EROFS))?;
557
558 if !self.no_open.load(Ordering::Relaxed) {
560 if let Some(h) = handle {
561 if let Some(hd) = self.handles.lock().unwrap().get(&h) {
562 if let Some(ref rhd) = hd.real_handle {
563 if rhd.in_upper_layer {
565 let (st, _d) = rhd.layer.setattr(
566 ctx,
567 rhd.inode,
568 attr,
569 Some(rhd.handle.load(Ordering::Relaxed)),
570 valid,
571 )?;
572
573 return Ok((st, self.config.attr_timeout));
574 }
575 }
576 }
577 }
578 }
579
580 let mut node = self.lookup_node(ctx, inode, "")?;
581
582 if !node.in_upper_layer() {
583 node = self.copy_node_up(ctx, Arc::clone(&node))?
584 }
585
586 let (layer, _, real_inode) = node.first_layer_inode();
587 let (st, _d) = layer.setattr(ctx, real_inode, attr, None, valid)?;
588 Ok((st, self.config.attr_timeout))
589 }
590
591 fn rename(
592 &self,
593 _ctx: &Context,
594 _olddir: Inode,
595 _odlname: &CStr,
596 _newdir: Inode,
597 _newname: &CStr,
598 _flags: u32,
599 ) -> Result<()> {
600 trace!(
602 "RENAME: olddir: {}, oldname: {}, newdir: {}, newname: {}, flags: {}\n",
603 _olddir,
604 _odlname.to_string_lossy(),
605 _newdir,
606 _newname.to_string_lossy(),
607 _flags
608 );
609 Err(Error::from_raw_os_error(libc::EXDEV))
610 }
611
612 fn mknod(
613 &self,
614 ctx: &Context,
615 parent: Inode,
616 name: &CStr,
617 mode: u32,
618 rdev: u32,
619 umask: u32,
620 ) -> Result<Entry> {
621 let sname = name.to_string_lossy().to_string();
622 trace!("MKNOD: parent: {}, name: {}\n", parent, sname);
623
624 let pnode = self.lookup_node(ctx, parent, "")?;
626 if pnode.whiteout.load(Ordering::Relaxed) {
627 return Err(Error::from_raw_os_error(libc::ENOENT));
628 }
629
630 self.do_mknod(ctx, &pnode, sname.as_str(), mode, rdev, umask)?;
631 let entry = self.do_lookup(ctx, parent, sname.as_str());
632 entry
633 }
634
635 fn link(&self, ctx: &Context, inode: Inode, newparent: Inode, name: &CStr) -> Result<Entry> {
636 let sname = name.to_string_lossy().to_string();
637 trace!(
638 "LINK: inode: {}, newparent: {}, name: {}\n",
639 inode,
640 newparent,
641 sname.as_str()
642 );
643
644 let node = self.lookup_node(ctx, inode, "")?;
645 if node.whiteout.load(Ordering::Relaxed) {
646 return Err(Error::from_raw_os_error(libc::ENOENT));
647 }
648
649 let newpnode = self.lookup_node(ctx, newparent, "")?;
650 if newpnode.whiteout.load(Ordering::Relaxed) {
651 return Err(Error::from_raw_os_error(libc::ENOENT));
652 }
653
654 self.do_link(ctx, &node, &newpnode, sname.as_str())?;
655 let entry = self.do_lookup(ctx, newparent, sname.as_str());
656 entry
657 }
658
659 fn symlink(&self, ctx: &Context, linkname: &CStr, parent: Inode, name: &CStr) -> Result<Entry> {
660 let sname = name.to_string_lossy().into_owned().to_owned();
662 let slinkname = linkname.to_string_lossy().into_owned().to_owned();
663 trace!(
664 "SYMLINK: linkname: {}, parent: {}, name: {}\n",
665 linkname.to_string_lossy(),
666 parent,
667 sname.as_str()
668 );
669
670 let pnode = self.lookup_node(ctx, parent, "")?;
671 self.do_symlink(ctx, slinkname.as_str(), &pnode, sname.as_str())?;
672
673 let entry = self.do_lookup(ctx, parent, sname.as_str());
674 entry
675 }
676
677 fn readlink(&self, ctx: &Context, inode: Inode) -> Result<Vec<u8>> {
678 trace!("READLINK: inode: {}\n", inode);
679
680 let node = self.lookup_node(ctx, inode, "")?;
681
682 if node.whiteout.load(Ordering::Relaxed) {
683 return Err(Error::from_raw_os_error(libc::ENOENT));
684 }
685
686 let (layer, _, inode) = node.first_layer_inode();
687 layer.readlink(ctx, inode)
688 }
689
690 fn flush(&self, ctx: &Context, inode: Inode, handle: Handle, lock_owner: u64) -> Result<()> {
691 trace!(
692 "FLUSH: inode: {}, handle: {}, lock_owner: {}\n",
693 inode,
694 handle,
695 lock_owner
696 );
697
698 if self.no_open.load(Ordering::Relaxed) {
699 return Err(Error::from_raw_os_error(libc::ENOSYS));
700 }
701
702 let node = self.lookup_node(ctx, inode, "")?;
703
704 if node.whiteout.load(Ordering::Relaxed) {
705 return Err(Error::from_raw_os_error(libc::ENOENT));
706 }
707
708 let (layer, real_inode, real_handle) = self.find_real_info_from_handle(handle)?;
709
710 layer.flush(ctx, real_inode, real_handle, lock_owner)
713 }
714
715 fn fsync(&self, ctx: &Context, inode: Inode, datasync: bool, handle: Handle) -> Result<()> {
716 trace!(
717 "FSYNC: inode: {}, datasync: {}, handle: {}\n",
718 inode,
719 datasync,
720 handle
721 );
722
723 self.do_fsync(ctx, inode, datasync, handle, false)
724 }
725
726 fn fsyncdir(&self, ctx: &Context, inode: Inode, datasync: bool, handle: Handle) -> Result<()> {
727 trace!(
728 "FSYNCDIR: inode: {}, datasync: {}, handle: {}\n",
729 inode,
730 datasync,
731 handle
732 );
733
734 self.do_fsync(ctx, inode, datasync, handle, true)
735 }
736
737 fn access(&self, ctx: &Context, inode: Inode, mask: u32) -> Result<()> {
738 trace!("ACCESS: inode: {}, mask: {}\n", inode, mask);
739 let node = self.lookup_node(ctx, inode, "")?;
740
741 if node.whiteout.load(Ordering::Relaxed) {
742 return Err(Error::from_raw_os_error(libc::ENOENT));
743 }
744
745 let (layer, real_inode) = self.find_real_inode(inode)?;
746 layer.access(ctx, real_inode, mask)
747 }
748
749 fn setxattr(
750 &self,
751 ctx: &Context,
752 inode: Inode,
753 name: &CStr,
754 value: &[u8],
755 flags: u32,
756 ) -> Result<()> {
757 trace!(
758 "SETXATTR: inode: {}, name: {}, value: {:?}, flags: {}\n",
759 inode,
760 name.to_string_lossy(),
761 value,
762 flags
763 );
764 let node = self.lookup_node(ctx, inode, "")?;
765
766 if node.whiteout.load(Ordering::Relaxed) {
767 return Err(Error::from_raw_os_error(libc::ENOENT));
768 }
769
770 if !node.in_upper_layer() {
771 self.copy_node_up(ctx, Arc::clone(&node))?;
773 }
774
775 let (layer, _, real_inode) = node.first_layer_inode();
776
777 layer.setxattr(ctx, real_inode, name, value, flags)
778
779 }
781
782 fn getxattr(
783 &self,
784 ctx: &Context,
785 inode: Inode,
786 name: &CStr,
787 size: u32,
788 ) -> Result<GetxattrReply> {
789 trace!(
790 "GETXATTR: inode: {}, name: {}, size: {}\n",
791 inode,
792 name.to_string_lossy(),
793 size
794 );
795 let node = self.lookup_node(ctx, inode, "")?;
796
797 if node.whiteout.load(Ordering::Relaxed) {
798 return Err(Error::from_raw_os_error(libc::ENOENT));
799 }
800
801 let (layer, real_inode) = self.find_real_inode(inode)?;
802
803 layer.getxattr(ctx, real_inode, name, size)
804 }
805
806 fn listxattr(&self, ctx: &Context, inode: Inode, size: u32) -> Result<ListxattrReply> {
807 trace!("LISTXATTR: inode: {}, size: {}\n", inode, size);
808 let node = self.lookup_node(ctx, inode, "")?;
809
810 if node.whiteout.load(Ordering::Relaxed) {
811 return Err(Error::from_raw_os_error(libc::ENOENT));
812 }
813
814 let (layer, real_inode) = self.find_real_inode(inode)?;
815
816 layer.listxattr(ctx, real_inode, size)
817 }
818
819 fn removexattr(&self, ctx: &Context, inode: Inode, name: &CStr) -> Result<()> {
820 trace!(
821 "REMOVEXATTR: inode: {}, name: {}\n",
822 inode,
823 name.to_string_lossy()
824 );
825 let node = self.lookup_node(ctx, inode, "")?;
826
827 if node.whiteout.load(Ordering::Relaxed) {
828 return Err(Error::from_raw_os_error(libc::ENOENT));
829 }
830
831 if !node.in_upper_layer() {
832 self.copy_node_up(ctx, Arc::clone(&node))?;
834 }
835
836 let (layer, _, ino) = node.first_layer_inode();
837 layer.removexattr(ctx, ino, name)
838
839 }
841
842 fn fallocate(
843 &self,
844 ctx: &Context,
845 inode: Inode,
846 handle: Handle,
847 mode: u32,
848 offset: u64,
849 length: u64,
850 ) -> Result<()> {
851 trace!(
852 "FALLOCATE: inode: {}, handle: {}, mode: {}, offset: {}, length: {}\n",
853 inode,
854 handle,
855 mode,
856 offset,
857 length
858 );
859 let data = self.get_data(ctx, Some(handle), inode, libc::O_RDONLY as u32)?;
861
862 match data.real_handle {
863 None => Err(Error::from_raw_os_error(libc::ENOENT)),
864 Some(ref rhd) => {
865 if !rhd.in_upper_layer {
866 return Err(Error::from_raw_os_error(libc::EROFS));
868 }
869 rhd.layer.fallocate(
870 ctx,
871 rhd.inode,
872 rhd.handle.load(Ordering::Relaxed),
873 mode,
874 offset,
875 length,
876 )
877 }
878 }
879 }
880
881 fn lseek(
882 &self,
883 ctx: &Context,
884 inode: Inode,
885 handle: Handle,
886 offset: u64,
887 whence: u32,
888 ) -> Result<u64> {
889 trace!(
890 "LSEEK: inode: {}, handle: {}, offset: {}, whence: {}\n",
891 inode,
892 handle,
893 offset,
894 whence
895 );
896 let node = self.lookup_node(ctx, inode, "")?;
899
900 if node.whiteout.load(Ordering::Relaxed) {
901 return Err(Error::from_raw_os_error(libc::ENOENT));
902 }
903
904 let st = node.stat64(ctx)?;
905 if utils::is_dir(st) {
906 error!("lseek on directory");
907 return Err(Error::from_raw_os_error(libc::EINVAL));
908 }
909
910 let (layer, real_inode, real_handle) = self.find_real_info_from_handle(handle)?;
911 layer.lseek(ctx, real_inode, real_handle, offset, whence)
912 }
913}