1use crate::security;
6use crate::task::CurrentTask;
7use crate::vfs::{
8 CheckAccessReason, FileHandle, FileObject, FsNodeHandle, FsNodeLinkBehavior, FsStr, FsString,
9 LookupVec, MountInfo, Mounts, NamespaceNode, UnlinkKind, path,
10};
11use atomic_bitflags::atomic_bitflags;
12use bitflags::bitflags;
13use fuchsia_rcu::{RcuOptionArc, RcuReadScope};
14use starnix_rcu::RcuString;
15use starnix_sync::{FileOpsCore, LockEqualOrBefore, Locked, RwLock, RwLockWriteGuard};
16use starnix_uapi::auth::FsCred;
17use starnix_uapi::errors::{ENOENT, Errno};
18use starnix_uapi::file_mode::{Access, FileMode};
19use starnix_uapi::inotify_mask::InotifyMask;
20use starnix_uapi::open_flags::OpenFlags;
21use starnix_uapi::{NAME_MAX, RENAME_EXCHANGE, RENAME_NOREPLACE, RENAME_WHITEOUT, errno, error};
22use std::collections::BTreeMap;
23use std::collections::btree_map::Entry;
24use std::fmt;
25use std::ops::Deref;
26use std::sync::atomic::Ordering;
27use std::sync::{Arc, Weak};
28#[cfg(detect_lock_cycles)]
29use tracing_mutex::util;
30
31bitflags! {
32 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
33 pub struct RenameFlags: u32 {
34 const EXCHANGE = RENAME_EXCHANGE;
36
37 const NOREPLACE = RENAME_NOREPLACE;
39
40 const WHITEOUT = RENAME_WHITEOUT;
42
43 const REPLACE_ANY = 0x80000000;
46
47 const INTERNAL = Self::REPLACE_ANY.bits();
49 }
50}
51
52pub trait DirEntryOps: Send + Sync + 'static {
53 fn revalidate(
70 &self,
71 _locked: &mut Locked<FileOpsCore>,
72 _: &CurrentTask,
73 _: &DirEntry,
74 ) -> Result<bool, Errno> {
75 Ok(true)
76 }
77}
78
79atomic_bitflags! {
80 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
81 pub struct DirEntryFlags: u8 {
82 const IS_DEAD = 1 << 0;
84
85 const HAS_MOUNTS = 1 << 1;
87 }
88}
89
90pub struct DefaultDirEntryOps;
91
92impl DirEntryOps for DefaultDirEntryOps {}
93
94pub struct DirEntry {
106 pub node: FsNodeHandle,
111
112 ops: Box<dyn DirEntryOps>,
117
118 parent: RcuOptionArc<DirEntry>,
125
126 flags: AtomicDirEntryFlags,
128
129 local_name: RcuString,
138
139 children: RwLock<DirEntryChildren>,
149}
150type DirEntryChildren = BTreeMap<FsString, Weak<DirEntry>>;
151
152pub type DirEntryHandle = Arc<DirEntry>;
153
154impl DirEntry {
155 #[allow(clippy::let_and_return)]
156 pub fn new_uncached(
157 node: FsNodeHandle,
158 parent: Option<DirEntryHandle>,
159 local_name: FsString,
160 ) -> DirEntryHandle {
161 let ops = node.create_dir_entry_ops();
162 let result = Arc::new(DirEntry {
163 node,
164 ops,
165 parent: RcuOptionArc::new(parent),
166 flags: Default::default(),
167 local_name: local_name.into(),
168 children: Default::default(),
169 });
170 #[cfg(any(test, debug_assertions))]
171 {
172 let _l1 = result.children.read();
175 }
176 result
177 }
178
179 pub fn new(
180 node: FsNodeHandle,
181 parent: Option<DirEntryHandle>,
182 local_name: FsString,
183 ) -> DirEntryHandle {
184 let result = Self::new_uncached(node, parent, local_name);
185 result.node.fs().did_create_dir_entry(&result);
186 result
187 }
188
189 pub fn new_unrooted(node: FsNodeHandle) -> DirEntryHandle {
192 Self::new_uncached(node, None, FsString::default())
193 }
194
195 pub fn new_deleted(
197 node: FsNodeHandle,
198 parent: Option<DirEntryHandle>,
199 local_name: FsString,
200 ) -> DirEntryHandle {
201 let entry = DirEntry::new_uncached(node, parent, local_name);
202 entry.raise_flags(DirEntryFlags::IS_DEAD);
203 entry
204 }
205
206 pub fn open_anonymous<L>(
208 self: &DirEntryHandle,
209 locked: &mut Locked<L>,
210 current_task: &CurrentTask,
211 flags: OpenFlags,
212 ) -> Result<FileHandle, Errno>
213 where
214 L: LockEqualOrBefore<FileOpsCore>,
215 {
216 let ops = self.node.create_file_ops(locked, current_task, flags)?;
217 FileObject::new(
218 locked,
219 current_task,
220 ops,
221 NamespaceNode::new_anonymous(self.clone()),
222 flags,
223 )
224 }
225
226 pub fn set_children(self: &DirEntryHandle, children: BTreeMap<FsString, DirEntryHandle>) {
229 let mut dir_entry_children = self.lock_children();
230 assert!(dir_entry_children.children.is_empty());
231 for (name, child) in children.into_iter() {
232 child.set_parent(self.clone());
233 dir_entry_children.children.insert(name, Arc::downgrade(&child));
234 }
235 }
236
237 fn lock_children<'a>(self: &'a DirEntryHandle) -> DirEntryLockedChildren<'a> {
238 DirEntryLockedChildren { entry: self, children: self.children.write() }
239 }
240
241 pub fn parent(&self) -> Option<DirEntryHandle> {
243 self.parent.to_option_arc()
244 }
245
246 pub fn parent_ref<'a>(&'a self, scope: &'a RcuReadScope) -> Option<&'a DirEntry> {
250 self.parent.as_ref(scope)
251 }
252
253 pub fn set_parent(&self, parent: DirEntryHandle) {
255 self.parent.update(Some(parent));
256 }
257
258 pub fn parent_or_self(self: &DirEntryHandle) -> DirEntryHandle {
268 self.parent().unwrap_or_else(|| self.clone())
269 }
270
271 pub fn local_name<'a>(&self, scope: &'a RcuReadScope) -> &'a FsStr {
275 self.local_name.read(scope)
276 }
277
278 pub fn is_reserved_name(name: &FsStr) -> bool {
283 name.is_empty() || name == "." || name == ".."
284 }
285
286 pub fn flags(&self) -> DirEntryFlags {
288 self.flags.load(Ordering::Acquire)
289 }
290
291 pub fn raise_flags(&self, flags: DirEntryFlags) -> DirEntryFlags {
295 self.flags.fetch_or(flags, Ordering::AcqRel)
296 }
297
298 pub fn lower_flags(&self, flags: DirEntryFlags) -> DirEntryFlags {
302 self.flags.fetch_and(!flags, Ordering::AcqRel)
303 }
304
305 pub fn is_dead(&self) -> bool {
307 self.flags().contains(DirEntryFlags::IS_DEAD)
308 }
309
310 pub fn component_lookup<L>(
313 self: &DirEntryHandle,
314 locked: &mut Locked<L>,
315 current_task: &CurrentTask,
316 mount: &MountInfo,
317 name: &FsStr,
318 ) -> Result<DirEntryHandle, Errno>
319 where
320 L: LockEqualOrBefore<FileOpsCore>,
321 {
322 let (node, _) = self.get_or_create_child(
323 locked,
324 current_task,
325 mount,
326 name,
327 |locked, d, mount, name| d.lookup(locked, current_task, mount, name),
328 )?;
329 Ok(node)
330 }
331
332 pub fn get_children_pipelined<L>(
333 self: &DirEntryHandle,
334 locked: &mut Locked<L>,
335 current_task: &CurrentTask,
336 mount: &MountInfo,
337 names: &[&FsStr],
338 ) -> LookupVec<Result<DirEntryHandle, Errno>>
339 where
340 L: LockEqualOrBefore<FileOpsCore>,
341 {
342 let locked = locked.cast_locked::<FileOpsCore>();
343
344 let mut nodes = LookupVec::new();
345 let mut results = LookupVec::new();
346 let mut current_parent = self.clone();
347 for i in 0..names.len() {
348 let next_node = nodes.pop();
349 match current_parent.get_or_create_child(
350 locked,
351 current_task,
352 mount,
353 names[i],
354 |locked, parent_node, _mount, _name| {
355 if let Some(node) = next_node {
356 return node;
357 }
358 nodes = parent_node.ops().lookup_pipelined(
359 locked,
360 parent_node,
361 current_task,
362 &names[i..],
363 );
364 nodes.reverse();
365 nodes.pop().unwrap()
366 },
367 ) {
368 Ok((entry, _)) => {
369 results.push(Ok(entry.clone()));
370 current_parent = entry;
371 }
372 Err(e) => {
373 results.push(Err(e));
374 break;
375 }
376 }
377 }
378 results
379 }
380
381 pub fn create_entry<L>(
389 self: &DirEntryHandle,
390 locked: &mut Locked<L>,
391 current_task: &CurrentTask,
392 mount: &MountInfo,
393 name: &FsStr,
394 create_node_fn: impl FnOnce(
395 &mut Locked<L>,
396 &FsNodeHandle,
397 &MountInfo,
398 &FsStr,
399 ) -> Result<FsNodeHandle, Errno>,
400 ) -> Result<DirEntryHandle, Errno>
401 where
402 L: LockEqualOrBefore<FileOpsCore>,
403 {
404 let (entry, exists) =
405 self.create_entry_internal(locked, current_task, mount, name, create_node_fn)?;
406 if exists {
407 return error!(EEXIST);
408 }
409 Ok(entry)
410 }
411
412 pub fn get_or_create_entry<L>(
415 self: &DirEntryHandle,
416 locked: &mut Locked<L>,
417 current_task: &CurrentTask,
418 mount: &MountInfo,
419 name: &FsStr,
420 create_node_fn: impl FnOnce(
421 &mut Locked<L>,
422 &FsNodeHandle,
423 &MountInfo,
424 &FsStr,
425 ) -> Result<FsNodeHandle, Errno>,
426 ) -> Result<DirEntryHandle, Errno>
427 where
428 L: LockEqualOrBefore<FileOpsCore>,
429 {
430 let (entry, _exists) =
431 self.create_entry_internal(locked, current_task, mount, name, create_node_fn)?;
432 Ok(entry)
433 }
434
435 fn create_entry_internal<L>(
436 self: &DirEntryHandle,
437 locked: &mut Locked<L>,
438 current_task: &CurrentTask,
439 mount: &MountInfo,
440 name: &FsStr,
441 create_node_fn: impl FnOnce(
442 &mut Locked<L>,
443 &FsNodeHandle,
444 &MountInfo,
445 &FsStr,
446 ) -> Result<FsNodeHandle, Errno>,
447 ) -> Result<(DirEntryHandle, bool), Errno>
448 where
449 L: LockEqualOrBefore<FileOpsCore>,
450 {
451 if DirEntry::is_reserved_name(name) {
452 return error!(EEXIST);
453 }
454 if name.len() > NAME_MAX as usize {
456 return error!(ENAMETOOLONG);
457 }
458 if name.contains(&path::SEPARATOR) {
459 return error!(EINVAL);
460 }
461 let (entry, exists) =
462 self.get_or_create_child(locked, current_task, mount, name, create_node_fn)?;
463 if !exists {
464 self.node.update_ctime_mtime();
466 entry.notify_creation();
467 }
468 Ok((entry, exists))
469 }
470
471 #[cfg(test)]
474 pub fn create_dir<L>(
475 self: &DirEntryHandle,
476 locked: &mut starnix_sync::Locked<L>,
477 current_task: &CurrentTask,
478 name: &FsStr,
479 ) -> Result<DirEntryHandle, Errno>
480 where
481 L: LockEqualOrBefore<FileOpsCore>,
482 {
483 self.create_dir_for_testing(locked, current_task, name)
484 }
485
486 pub fn create_dir_for_testing<L>(
489 self: &DirEntryHandle,
490 locked: &mut Locked<L>,
491 current_task: &CurrentTask,
492 name: &FsStr,
493 ) -> Result<DirEntryHandle, Errno>
494 where
495 L: LockEqualOrBefore<FileOpsCore>,
496 {
497 self.create_entry(
499 locked,
500 current_task,
501 &MountInfo::detached(),
502 name,
503 |locked, dir, mount, name| {
504 dir.create_node(
505 locked,
506 current_task,
507 mount,
508 name,
509 starnix_uapi::file_mode::mode!(IFDIR, 0o777),
510 starnix_uapi::device_id::DeviceId::NONE,
511 FsCred::root(),
512 )
513 },
514 )
515 }
516
517 pub fn create_tmpfile<L>(
523 self: &DirEntryHandle,
524 locked: &mut Locked<L>,
525 current_task: &CurrentTask,
526 mount: &MountInfo,
527 mode: FileMode,
528 owner: FsCred,
529 flags: OpenFlags,
530 ) -> Result<DirEntryHandle, Errno>
531 where
532 L: LockEqualOrBefore<FileOpsCore>,
533 {
534 if !self.node.is_dir() {
536 return error!(ENOTDIR);
537 }
538 assert!(mode.is_reg());
539
540 let link_behavior = if flags.contains(OpenFlags::EXCL) {
548 FsNodeLinkBehavior::Disallowed
549 } else {
550 FsNodeLinkBehavior::Allowed
551 };
552
553 let node =
554 self.node.create_tmpfile(locked, current_task, mount, mode, owner, link_behavior)?;
555 let local_name = format!("#{}", node.ino).into();
556 Ok(DirEntry::new_deleted(node, Some(self.clone()), local_name))
557 }
558
559 pub fn unlink<L>(
560 self: &DirEntryHandle,
561 locked: &mut Locked<L>,
562 current_task: &CurrentTask,
563 mount: &MountInfo,
564 name: &FsStr,
565 kind: UnlinkKind,
566 must_be_directory: bool,
567 ) -> Result<(), Errno>
568 where
569 L: LockEqualOrBefore<FileOpsCore>,
570 {
571 assert!(!DirEntry::is_reserved_name(name));
572
573 let child_to_unlink;
575
576 let mut self_children = self.lock_children();
577 child_to_unlink = self_children.component_lookup(locked, current_task, mount, name)?;
578 child_to_unlink.require_no_mounts(mount)?;
579
580 if must_be_directory && !child_to_unlink.node.is_dir() {
587 return error!(ENOTDIR);
588 }
589
590 match kind {
591 UnlinkKind::Directory => {
592 if !child_to_unlink.node.is_dir() {
593 return error!(ENOTDIR);
594 }
595 }
596 UnlinkKind::NonDirectory => {
597 if child_to_unlink.node.is_dir() {
598 return error!(EISDIR);
599 }
600 }
601 }
602
603 self.node.unlink(locked, current_task, mount, name, &child_to_unlink.node)?;
604 self_children.children.remove(name);
605
606 std::mem::drop(self_children);
607 child_to_unlink.destroy(¤t_task.kernel().mounts);
608
609 Ok(())
610 }
611
612 fn destroy(self: DirEntryHandle, mounts: &Mounts) {
616 let was_already_dead =
617 self.raise_flags(DirEntryFlags::IS_DEAD).contains(DirEntryFlags::IS_DEAD);
618 if was_already_dead {
619 return;
620 }
621 let unmount =
622 self.lower_flags(DirEntryFlags::HAS_MOUNTS).contains(DirEntryFlags::HAS_MOUNTS);
623 self.node.fs().will_destroy_dir_entry(&self);
624 if unmount {
625 mounts.unmount(&self);
626 }
627 self.notify_deletion();
628 }
629
630 pub fn is_descendant_of(self: &DirEntryHandle, other: &DirEntryHandle) -> bool {
632 let scope = RcuReadScope::new();
633 let mut current = self.deref();
634 loop {
635 if std::ptr::eq(current, other.deref()) {
636 return true;
638 }
639 if let Some(parent) = current.parent_ref(&scope) {
640 current = parent;
641 } else {
642 return false;
644 }
645 }
646 }
647
648 pub fn rename<L>(
653 locked: &mut Locked<L>,
654 current_task: &CurrentTask,
655 old_parent: &DirEntryHandle,
656 old_mount: &MountInfo,
657 old_basename: &FsStr,
658 new_parent: &DirEntryHandle,
659 new_mount: &MountInfo,
660 new_basename: &FsStr,
661 flags: RenameFlags,
662 ) -> Result<(), Errno>
663 where
664 L: LockEqualOrBefore<FileOpsCore>,
665 {
666 if old_mount != new_mount {
668 return error!(EXDEV);
669 }
670 let mount = old_mount;
672
673 if DirEntry::is_reserved_name(old_basename) || DirEntry::is_reserved_name(new_basename) {
676 if flags.contains(RenameFlags::NOREPLACE) {
677 return error!(EEXIST);
678 }
679 return error!(EBUSY);
680 }
681
682 if Arc::ptr_eq(&old_parent.node, &new_parent.node) && old_basename == new_basename {
685 return Ok(());
686 }
687
688 old_parent.node.check_access(
690 locked,
691 current_task,
692 mount,
693 Access::WRITE,
694 CheckAccessReason::InternalPermissionChecks,
695 old_parent,
696 )?;
697 new_parent.node.check_access(
698 locked,
699 current_task,
700 mount,
701 Access::WRITE,
702 CheckAccessReason::InternalPermissionChecks,
703 new_parent,
704 )?;
705
706 let fs = old_parent.node.fs();
709
710 let renamed;
713 let mut maybe_replaced = None;
714
715 {
716 let _lock = fs.rename_mutex.lock();
726
727 let mut new_parent_ancestor_list = Vec::<DirEntryHandle>::new();
734 {
735 let mut current = Some(new_parent.clone());
736 while let Some(entry) = current {
737 current = entry.parent();
738 new_parent_ancestor_list.push(entry);
739 }
740 }
741
742 let mut state = RenameGuard::lock(old_parent, new_parent);
747
748 renamed =
751 state.old_parent().component_lookup(locked, current_task, mount, old_basename)?;
752
753 old_parent.node.check_sticky_bit(current_task, &renamed.node)?;
756
757 if new_parent_ancestor_list.into_iter().any(|entry| Arc::ptr_eq(&entry, &renamed)) {
760 return error!(EINVAL);
761 }
762
763 renamed.require_no_mounts(mount)?;
768
769 match state.new_parent().component_lookup(locked, current_task, mount, new_basename) {
773 Ok(replaced) => {
774 let replaced = maybe_replaced.insert(replaced);
776
777 if flags.contains(RenameFlags::NOREPLACE) {
778 return error!(EEXIST);
779 }
780
781 if Arc::ptr_eq(&renamed.node, &replaced.node) {
787 return Ok(());
788 }
789
790 if replaced.node.is_dir() {
795 replaced.require_no_mounts(mount)?;
800 }
801
802 if !flags.intersects(RenameFlags::EXCHANGE | RenameFlags::REPLACE_ANY) {
803 if renamed.node.is_dir() && !replaced.node.is_dir() {
804 return error!(ENOTDIR);
805 } else if !renamed.node.is_dir() && replaced.node.is_dir() {
806 return error!(EISDIR);
807 }
808 }
809 }
810 Err(errno) if errno == ENOENT => {}
812 Err(e) => return Err(e),
814 }
815
816 security::check_fs_node_rename_access(
817 current_task,
818 &old_parent.node,
819 &renamed.node,
820 &new_parent.node,
821 maybe_replaced.as_ref().map(|dir_entry| dir_entry.node.deref().as_ref()),
822 old_basename,
823 new_basename,
824 )?;
825
826 if flags.contains(RenameFlags::EXCHANGE) {
833 let replaced = maybe_replaced.as_ref().ok_or_else(|| errno!(ENOENT))?;
834 fs.exchange(
835 current_task,
836 &renamed.node,
837 &old_parent.node,
838 old_basename,
839 &replaced.node,
840 &new_parent.node,
841 new_basename,
842 )?;
843 } else {
844 fs.rename(
845 locked,
846 current_task,
847 &old_parent.node,
848 old_basename,
849 &new_parent.node,
850 new_basename,
851 &renamed.node,
852 maybe_replaced.as_ref().map(|replaced| &replaced.node),
853 )?;
854 }
855
856 renamed.set_parent(new_parent.clone());
859 renamed.local_name.update(new_basename.to_owned());
860
861 state.new_parent().children.insert(new_basename.into(), Arc::downgrade(&renamed));
865
866 #[cfg(detect_lock_cycles)]
867 unsafe {
868 util::reset_dependencies(renamed.children.raw());
871 }
872
873 if flags.contains(RenameFlags::EXCHANGE) {
874 let replaced =
876 maybe_replaced.as_ref().expect("replaced expected with RENAME_EXCHANGE");
877 replaced.set_parent(old_parent.clone());
878 replaced.local_name.update(old_basename.to_owned());
879 state.old_parent().children.insert(old_basename.into(), Arc::downgrade(replaced));
880
881 #[cfg(detect_lock_cycles)]
882 unsafe {
883 util::reset_dependencies(replaced.children.raw());
886 }
887 } else {
888 state.old_parent().children.remove(old_basename);
890 }
891 };
892
893 fs.purge_old_entries();
894
895 if let Some(replaced) = maybe_replaced {
896 if !flags.contains(RenameFlags::EXCHANGE) {
897 replaced.destroy(¤t_task.kernel().mounts);
898 }
899 }
900
901 renamed.node.update_ctime();
903
904 let mode = renamed.node.info().mode;
905 let cookie = current_task.kernel().get_next_inotify_cookie();
906 old_parent.node.notify(InotifyMask::MOVE_FROM, cookie, old_basename, mode, false);
907 new_parent.node.notify(InotifyMask::MOVE_TO, cookie, new_basename, mode, false);
908 renamed.node.notify(InotifyMask::MOVE_SELF, 0, Default::default(), mode, false);
909
910 Ok(())
911 }
912
913 pub fn get_children<F, T>(&self, callback: F) -> T
914 where
915 F: FnOnce(&DirEntryChildren) -> T,
916 {
917 let children = self.children.read();
918 callback(&children)
919 }
920
921 pub fn remove_child(&self, name: &FsStr, mounts: &Mounts) {
924 let mut children = self.children.write();
925 let child = children.get(name).and_then(Weak::upgrade);
926 if let Some(child) = child {
927 children.remove(name);
928 std::mem::drop(children);
929 child.destroy(mounts);
930 }
931 }
932
933 fn get_or_create_child<L>(
934 self: &DirEntryHandle,
935 locked: &mut Locked<L>,
936 current_task: &CurrentTask,
937 mount: &MountInfo,
938 name: &FsStr,
939 create_fn: impl FnOnce(
940 &mut Locked<L>,
941 &FsNodeHandle,
942 &MountInfo,
943 &FsStr,
944 ) -> Result<FsNodeHandle, Errno>,
945 ) -> Result<(DirEntryHandle, bool), Errno>
946 where
947 L: LockEqualOrBefore<FileOpsCore>,
948 {
949 assert!(!DirEntry::is_reserved_name(name));
950 if !self.node.is_dir() {
952 return error!(ENOTDIR);
953 }
954 self.node.check_access(
956 locked,
957 current_task,
958 mount,
959 Access::EXEC,
960 CheckAccessReason::InternalPermissionChecks,
961 self,
962 )?;
963
964 let child = self.children.read().get(name).and_then(Weak::upgrade);
967 let (child, create_result) = if let Some(child) = child {
968 if self.node.fail_if_locked(current_task).is_ok() {
970 child.node.fs().did_access_dir_entry(&child);
971 }
972 (child, CreationResult::Existed { create_fn })
973 } else {
974 let (child, create_result) = self.lock_children().get_or_create_child(
975 locked,
976 current_task,
977 mount,
978 name,
979 create_fn,
980 )?;
981 child.node.fs().purge_old_entries();
982 (child, create_result)
983 };
984
985 let (child, exists) = match create_result {
986 CreationResult::Created => (child, false),
987 CreationResult::Existed { create_fn } => {
988 if child.ops.revalidate(
989 locked.cast_locked::<FileOpsCore>(),
990 current_task,
991 &child,
992 )? {
993 (child, true)
994 } else {
995 self.internal_remove_child(&child);
996 child.destroy(¤t_task.kernel().mounts);
997
998 let (child, create_result) = self.lock_children().get_or_create_child(
999 locked,
1000 current_task,
1001 mount,
1002 name,
1003 create_fn,
1004 )?;
1005 child.node.fs().purge_old_entries();
1006 (child, matches!(create_result, CreationResult::Existed { .. }))
1007 }
1008 }
1009 };
1010
1011 Ok((child, exists))
1012 }
1013
1014 #[cfg(test)]
1022 pub fn copy_child_names(&self) -> Vec<FsString> {
1023 let scope = RcuReadScope::new();
1024 self.children
1025 .read()
1026 .values()
1027 .filter_map(|child| Weak::upgrade(child).map(|c| c.local_name.read(&scope).to_owned()))
1028 .collect()
1029 }
1030
1031 fn internal_remove_child(&self, child: &DirEntry) {
1032 let mut children = self.children.write();
1033 let scope = RcuReadScope::new();
1034 let local_name = child.local_name.read(&scope);
1035 if let Some(weak_child) = children.get(local_name) {
1036 if std::ptr::eq(weak_child.as_ptr(), child) {
1040 children.remove(local_name);
1041 }
1042 }
1043 }
1044
1045 pub fn notify(&self, event_mask: InotifyMask) {
1047 self.notify_watchers(event_mask, self.is_dead());
1048 }
1049
1050 pub fn notify_ignoring_excl_unlink(&self, event_mask: InotifyMask) {
1054 self.notify_watchers(event_mask, false);
1056 }
1057
1058 fn notify_watchers(&self, event_mask: InotifyMask, is_dead: bool) {
1059 let mode = self.node.info().mode;
1060 {
1061 let scope = RcuReadScope::new();
1062 if let Some(parent) = self.parent_ref(&scope) {
1063 let local_name = self.local_name.read(&scope);
1064 parent.node.notify(event_mask, 0, local_name, mode, is_dead);
1065 }
1066 }
1067 self.node.notify(event_mask, 0, Default::default(), mode, is_dead);
1068 }
1069
1070 fn notify_creation(&self) {
1072 let mode = self.node.info().mode;
1073 if Arc::strong_count(&self.node) > 1 {
1074 self.node.notify(InotifyMask::ATTRIB, 0, Default::default(), mode, false);
1076 }
1077 let scope = RcuReadScope::new();
1078 if let Some(parent) = self.parent_ref(&scope) {
1079 let local_name = self.local_name.read(&scope);
1080 parent.node.notify(InotifyMask::CREATE, 0, local_name, mode, false);
1081 }
1082 }
1083
1084 fn notify_deletion(&self) {
1088 let mode = self.node.info().mode;
1089 if !mode.is_dir() {
1090 self.node.notify(InotifyMask::ATTRIB, 0, Default::default(), mode, false);
1092 }
1093
1094 let scope = RcuReadScope::new();
1095 if let Some(parent) = self.parent_ref(&scope) {
1096 let local_name = self.local_name.read(&scope);
1097 parent.node.notify(InotifyMask::DELETE, 0, local_name, mode, false);
1098 }
1099
1100 if Arc::strong_count(&self.node) == 1 {
1103 self.node.notify(InotifyMask::DELETE_SELF, 0, Default::default(), mode, false);
1104 }
1105 }
1106
1107 pub fn has_mounts(&self) -> bool {
1109 self.flags().contains(DirEntryFlags::HAS_MOUNTS)
1110 }
1111
1112 pub fn set_has_mounts(&self, v: bool) {
1114 if v {
1115 self.raise_flags(DirEntryFlags::HAS_MOUNTS);
1116 } else {
1117 self.lower_flags(DirEntryFlags::HAS_MOUNTS);
1118 }
1119 }
1120
1121 fn require_no_mounts(self: &Arc<Self>, parent_mount: &MountInfo) -> Result<(), Errno> {
1123 if self.has_mounts() {
1124 if let Some(mount) = parent_mount.as_ref() {
1125 if mount.read().has_submount(self) {
1126 return error!(EBUSY);
1127 }
1128 }
1129 }
1130 Ok(())
1131 }
1132}
1133
1134struct DirEntryLockedChildren<'a> {
1135 entry: &'a DirEntryHandle,
1136 children: RwLockWriteGuard<'a, DirEntryChildren>,
1137}
1138
1139enum CreationResult<F> {
1140 Created,
1141 Existed { create_fn: F },
1142}
1143
1144impl<'a> DirEntryLockedChildren<'a> {
1145 fn component_lookup<L>(
1146 &mut self,
1147 locked: &mut Locked<L>,
1148 current_task: &CurrentTask,
1149 mount: &MountInfo,
1150 name: &FsStr,
1151 ) -> Result<DirEntryHandle, Errno>
1152 where
1153 L: LockEqualOrBefore<FileOpsCore>,
1154 {
1155 assert!(!DirEntry::is_reserved_name(name));
1156 let (node, _) =
1157 self.get_or_create_child(locked, current_task, mount, name, |_, _, _, _| {
1158 error!(ENOENT)
1159 })?;
1160 Ok(node)
1161 }
1162
1163 fn get_or_create_child<
1164 L,
1165 F: FnOnce(&mut Locked<L>, &FsNodeHandle, &MountInfo, &FsStr) -> Result<FsNodeHandle, Errno>,
1166 >(
1167 &mut self,
1168 locked: &mut Locked<L>,
1169 current_task: &CurrentTask,
1170 mount: &MountInfo,
1171 name: &FsStr,
1172 create_fn: F,
1173 ) -> Result<(DirEntryHandle, CreationResult<F>), Errno>
1174 where
1175 L: LockEqualOrBefore<FileOpsCore>,
1176 {
1177 let create_child = |locked: &mut Locked<L>, create_fn: F| {
1178 let (node, create_result) =
1180 match self.entry.node.lookup(locked, current_task, mount, name) {
1181 Ok(node) => (node, CreationResult::Existed { create_fn }),
1182 Err(e) if e == ENOENT => {
1183 (create_fn(locked, &self.entry.node, mount, name)?, CreationResult::Created)
1184 }
1185 Err(e) => return Err(e),
1186 };
1187
1188 assert!(
1189 node.info().mode & FileMode::IFMT != FileMode::EMPTY,
1190 "FsNode initialization did not populate the FileMode in FsNodeInfo."
1191 );
1192
1193 let entry = DirEntry::new(node, Some(self.entry.clone()), name.to_owned());
1194 Ok((entry, create_result))
1195 };
1196
1197 let (child, create_result) = match self.children.entry(name.to_owned()) {
1198 Entry::Vacant(entry) => {
1199 let (child, create_result) = create_child(locked, create_fn)?;
1200 if self.entry.node.fail_if_locked(current_task).is_ok() {
1202 entry.insert(Arc::downgrade(&child));
1203 }
1204 (child, create_result)
1205 }
1206 Entry::Occupied(mut entry) => {
1207 if let Some(child) = Weak::upgrade(entry.get()) {
1211 if self.entry.node.fail_if_locked(current_task).is_ok() {
1213 child.node.fs().did_access_dir_entry(&child);
1214 }
1215 return Ok((child, CreationResult::Existed { create_fn }));
1216 }
1217 let (child, create_result) = create_child(locked, create_fn)?;
1218 if self.entry.node.fail_if_locked(current_task).is_ok() {
1220 entry.insert(Arc::downgrade(&child));
1221 }
1222 (child, create_result)
1223 }
1224 };
1225
1226 security::fs_node_init_with_dentry(locked, current_task, &child)?;
1227
1228 Ok((child, create_result))
1229 }
1230}
1231
1232impl fmt::Debug for DirEntry {
1233 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1234 let scope = RcuReadScope::new();
1235 let mut parents = vec![];
1236 let mut maybe_parent = self.parent_ref(&scope);
1237 while let Some(parent) = maybe_parent {
1238 parents.push(parent.local_name.read(&scope));
1239 maybe_parent = parent.parent_ref(&scope);
1240 }
1241 let mut builder = f.debug_struct("DirEntry");
1242 builder.field("id", &(self as *const DirEntry));
1243 builder.field("local_name", &self.local_name.read(&scope).to_owned());
1244 if !parents.is_empty() {
1245 builder.field("parents", &parents);
1246 }
1247 builder.finish()
1248 }
1249}
1250
1251struct RenameGuard<'a> {
1252 old_parent_guard: DirEntryLockedChildren<'a>,
1253 new_parent_guard: Option<DirEntryLockedChildren<'a>>,
1254}
1255
1256impl<'a> RenameGuard<'a> {
1257 fn lock(old_parent: &'a DirEntryHandle, new_parent: &'a DirEntryHandle) -> Self {
1258 if Arc::ptr_eq(old_parent, new_parent) {
1259 Self { old_parent_guard: old_parent.lock_children(), new_parent_guard: None }
1260 } else {
1261 if new_parent.is_descendant_of(old_parent)
1265 || (!old_parent.is_descendant_of(new_parent)
1266 && old_parent.node.node_key() < new_parent.node.node_key())
1267 {
1268 let old_parent_guard = old_parent.lock_children();
1269 let new_parent_guard = new_parent.lock_children();
1270 Self { old_parent_guard, new_parent_guard: Some(new_parent_guard) }
1271 } else {
1272 let new_parent_guard = new_parent.lock_children();
1273 let old_parent_guard = old_parent.lock_children();
1274 Self { old_parent_guard, new_parent_guard: Some(new_parent_guard) }
1275 }
1276 }
1277 }
1278
1279 fn old_parent(&mut self) -> &mut DirEntryLockedChildren<'a> {
1280 &mut self.old_parent_guard
1281 }
1282
1283 fn new_parent(&mut self) -> &mut DirEntryLockedChildren<'a> {
1284 if let Some(new_guard) = self.new_parent_guard.as_mut() {
1285 new_guard
1286 } else {
1287 &mut self.old_parent_guard
1288 }
1289 }
1290}
1291
1292impl Drop for DirEntry {
1296 fn drop(&mut self) {
1297 let scope = RcuReadScope::new();
1298 let maybe_parent = self.parent_ref(&scope);
1299 self.parent.update(None);
1300 if let Some(parent) = maybe_parent {
1301 parent.internal_remove_child(self);
1302 }
1303 }
1304}