1use crate::security;
6use crate::task::CurrentTask;
7use crate::vfs::{
8 CheckAccessReason, FileHandle, FileObject, FsLockDepType, FsNodeHandle, FsNodeLinkBehavior,
9 FsStr, FsString, LookupVec, MountInfo, Mounts, NamespaceNode, UnlinkKind, inotify_hook, path,
10};
11use atomic_bitflags::atomic_bitflags;
12use bitflags::bitflags;
13use fuchsia_rcu::{RcuOptionArc, RcuReadScope};
14use fuchsia_sync::ResetDependencies;
15use starnix_rcu::RcuString;
16use starnix_sync::{
17 DirEntryChildrenLevel, DirEntryChildrenRecursiveLevel, DynamicLockDepRwLock, FileOpsCore,
18 FuseDirEntryChildrenLevel, LockDepWriteGuard, LockEqualOrBefore, Locked, allow_subclass,
19};
20use starnix_uapi::auth::FsCred;
21use starnix_uapi::errors::{ENOENT, Errno};
22use starnix_uapi::file_mode::{Access, FileMode};
23use starnix_uapi::inotify_mask::InotifyMask;
24use starnix_uapi::open_flags::OpenFlags;
25use starnix_uapi::{NAME_MAX, RENAME_EXCHANGE, RENAME_NOREPLACE, RENAME_WHITEOUT, error};
26use std::collections::BTreeMap;
27use std::collections::btree_map::Entry;
28use std::fmt;
29use std::ops::Deref;
30use std::sync::atomic::Ordering;
31use std::sync::{Arc, Weak};
32
33bitflags! {
34 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
35 pub struct RenameFlags: u32 {
36 const EXCHANGE = RENAME_EXCHANGE;
38
39 const NOREPLACE = RENAME_NOREPLACE;
41
42 const WHITEOUT = RENAME_WHITEOUT;
44
45 const REPLACE_ANY = 1 << 31;
48
49 const INTERNAL = Self::REPLACE_ANY.bits();
51 }
52}
53
54pub trait DirEntryOps: Send + Sync + 'static {
55 fn revalidate(
72 &self,
73 _locked: &mut Locked<FileOpsCore>,
74 _: &CurrentTask,
75 _: &DirEntry,
76 ) -> Result<bool, Errno> {
77 Ok(true)
78 }
79}
80
81atomic_bitflags! {
82 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
83 pub struct DirEntryFlags: u8 {
84 const IS_DEAD = 1 << 0;
86
87 const HAS_MOUNTS = 1 << 1;
89 }
90}
91
92pub struct DefaultDirEntryOps;
93
94impl DirEntryOps for DefaultDirEntryOps {}
95
96pub struct DirEntry {
108 pub node: FsNodeHandle,
113
114 ops: Box<dyn DirEntryOps>,
119
120 parent: RcuOptionArc<DirEntry>,
127
128 flags: AtomicDirEntryFlags,
130
131 local_name: RcuString,
140
141 children: DynamicLockDepRwLock<DirEntryChildren>,
151}
152type DirEntryChildren = BTreeMap<FsString, Weak<DirEntry>>;
153
154pub type DirEntryHandle = Arc<DirEntry>;
155
156impl DirEntry {
157 #[allow(clippy::let_and_return)]
158 pub fn new_uncached(
159 node: FsNodeHandle,
160 parent: Option<DirEntryHandle>,
161 local_name: FsString,
162 ) -> DirEntryHandle {
163 let ops = node.create_dir_entry_ops();
164 let fs_lockdep_type = node.fs().fs_lockdep_type();
165 let result = Arc::new(DirEntry {
166 node,
167 ops,
168 parent: RcuOptionArc::new(parent),
169 flags: Default::default(),
170 local_name: local_name.into(),
171 children: match fs_lockdep_type {
172 FsLockDepType::Normal => {
173 DynamicLockDepRwLock::new::<DirEntryChildrenLevel>(Default::default())
174 }
175 FsLockDepType::Recursive => {
176 DynamicLockDepRwLock::new::<DirEntryChildrenRecursiveLevel>(Default::default())
177 }
178 FsLockDepType::Fuse => {
179 DynamicLockDepRwLock::new::<FuseDirEntryChildrenLevel>(Default::default())
180 }
181 },
182 });
183 #[cfg(any(test, debug_assertions))]
184 {
185 let _token = allow_subclass();
188 let _l1 = result.children.read();
189 }
190 result
191 }
192
193 pub fn new(
194 node: FsNodeHandle,
195 parent: Option<DirEntryHandle>,
196 local_name: FsString,
197 ) -> DirEntryHandle {
198 let result = Self::new_uncached(node, parent, local_name);
199 result.node.fs().did_create_dir_entry(&result);
200 result
201 }
202
203 pub fn new_unrooted(node: FsNodeHandle) -> DirEntryHandle {
206 Self::new_uncached(node, None, FsString::default())
207 }
208
209 pub fn new_deleted(
211 node: FsNodeHandle,
212 parent: Option<DirEntryHandle>,
213 local_name: FsString,
214 ) -> DirEntryHandle {
215 let entry = DirEntry::new_uncached(node, parent, local_name);
216 entry.raise_flags(DirEntryFlags::IS_DEAD);
217 entry
218 }
219
220 pub fn open_anonymous<L>(
222 self: &DirEntryHandle,
223 locked: &mut Locked<L>,
224 current_task: &CurrentTask,
225 flags: OpenFlags,
226 ) -> Result<FileHandle, Errno>
227 where
228 L: LockEqualOrBefore<FileOpsCore>,
229 {
230 let ops = self.node.create_file_ops(locked, current_task, flags)?;
231 FileObject::new(
232 locked,
233 current_task,
234 ops,
235 NamespaceNode::new_anonymous(self.clone()),
236 flags,
237 )
238 }
239
240 pub fn set_children(self: &DirEntryHandle, children: BTreeMap<FsString, DirEntryHandle>) {
243 let mut dir_entry_children = self.lock_children();
244 assert!(dir_entry_children.children.is_empty());
245 for (name, child) in children.into_iter() {
246 child.set_parent(self.clone());
247 dir_entry_children.children.insert(name, Arc::downgrade(&child));
248 }
249 }
250
251 fn lock_children<'a>(self: &'a DirEntryHandle) -> DirEntryLockedChildren<'a> {
252 DirEntryLockedChildren { entry: self, children: self.children.write() }
253 }
254
255 pub fn parent(&self) -> Option<DirEntryHandle> {
257 self.parent.to_option_arc()
258 }
259
260 pub fn parent_ref<'a>(&'a self, scope: &'a RcuReadScope) -> Option<&'a DirEntry> {
264 self.parent.as_ref(scope)
265 }
266
267 pub fn set_parent(&self, parent: DirEntryHandle) {
269 self.parent.update(Some(parent));
270 }
271
272 pub fn parent_or_self(self: &DirEntryHandle) -> DirEntryHandle {
282 self.parent().unwrap_or_else(|| self.clone())
283 }
284
285 pub fn local_name<'a>(&self, scope: &'a RcuReadScope) -> &'a FsStr {
289 self.local_name.read(scope)
290 }
291
292 pub fn is_reserved_name(name: &FsStr) -> bool {
297 name.is_empty() || name == "." || name == ".."
298 }
299
300 pub fn flags(&self) -> DirEntryFlags {
302 self.flags.load(Ordering::Acquire)
303 }
304
305 pub fn raise_flags(&self, flags: DirEntryFlags) -> DirEntryFlags {
309 self.flags.fetch_or(flags, Ordering::AcqRel)
310 }
311
312 pub fn lower_flags(&self, flags: DirEntryFlags) -> DirEntryFlags {
316 self.flags.fetch_and(!flags, Ordering::AcqRel)
317 }
318
319 pub fn is_dead(&self) -> bool {
321 self.flags().contains(DirEntryFlags::IS_DEAD)
322 }
323
324 pub fn component_lookup<L>(
327 self: &DirEntryHandle,
328 locked: &mut Locked<L>,
329 current_task: &CurrentTask,
330 mount: &MountInfo,
331 name: &FsStr,
332 ) -> Result<DirEntryHandle, Errno>
333 where
334 L: LockEqualOrBefore<FileOpsCore>,
335 {
336 let (node, _) = self.get_or_create_child(
337 locked,
338 current_task,
339 mount,
340 name,
341 |locked, d, mount, name| d.lookup(locked, current_task, mount, name),
342 )?;
343 Ok(node)
344 }
345
346 pub fn get_children_pipelined<L>(
347 self: &DirEntryHandle,
348 locked: &mut Locked<L>,
349 current_task: &CurrentTask,
350 mount: &MountInfo,
351 names: &[&FsStr],
352 ) -> LookupVec<Result<DirEntryHandle, Errno>>
353 where
354 L: LockEqualOrBefore<FileOpsCore>,
355 {
356 let locked = locked.cast_locked::<FileOpsCore>();
357
358 let mut nodes = LookupVec::new();
359 let mut results = LookupVec::new();
360 let mut current_parent = self.clone();
361 for i in 0..names.len() {
362 let next_node = nodes.pop();
363 match current_parent.get_or_create_child(
364 locked,
365 current_task,
366 mount,
367 names[i],
368 |locked, parent_node, _mount, _name| {
369 if let Some(node) = next_node {
370 return node;
371 }
372 nodes = parent_node.ops().lookup_pipelined(
373 locked,
374 parent_node,
375 current_task,
376 &names[i..],
377 );
378 nodes.reverse();
379 nodes.pop().unwrap()
380 },
381 ) {
382 Ok((entry, _)) => {
383 results.push(Ok(entry.clone()));
384 current_parent = entry;
385 }
386 Err(e) => {
387 results.push(Err(e));
388 break;
389 }
390 }
391 }
392 results
393 }
394
395 pub fn create_entry<L>(
403 self: &DirEntryHandle,
404 locked: &mut Locked<L>,
405 current_task: &CurrentTask,
406 mount: &MountInfo,
407 name: &FsStr,
408 create_node_fn: impl FnOnce(
409 &mut Locked<L>,
410 &FsNodeHandle,
411 &MountInfo,
412 &FsStr,
413 ) -> Result<FsNodeHandle, Errno>,
414 ) -> Result<DirEntryHandle, Errno>
415 where
416 L: LockEqualOrBefore<FileOpsCore>,
417 {
418 let (entry, exists) =
419 self.create_entry_internal(locked, current_task, mount, name, create_node_fn)?;
420 if exists {
421 return error!(EEXIST);
422 }
423 Ok(entry)
424 }
425
426 pub fn get_or_create_entry<L>(
429 self: &DirEntryHandle,
430 locked: &mut Locked<L>,
431 current_task: &CurrentTask,
432 mount: &MountInfo,
433 name: &FsStr,
434 create_node_fn: impl FnOnce(
435 &mut Locked<L>,
436 &FsNodeHandle,
437 &MountInfo,
438 &FsStr,
439 ) -> Result<FsNodeHandle, Errno>,
440 ) -> Result<DirEntryHandle, Errno>
441 where
442 L: LockEqualOrBefore<FileOpsCore>,
443 {
444 let (entry, _exists) =
445 self.create_entry_internal(locked, current_task, mount, name, create_node_fn)?;
446 Ok(entry)
447 }
448
449 fn create_entry_internal<L>(
450 self: &DirEntryHandle,
451 locked: &mut Locked<L>,
452 current_task: &CurrentTask,
453 mount: &MountInfo,
454 name: &FsStr,
455 create_node_fn: impl FnOnce(
456 &mut Locked<L>,
457 &FsNodeHandle,
458 &MountInfo,
459 &FsStr,
460 ) -> Result<FsNodeHandle, Errno>,
461 ) -> Result<(DirEntryHandle, bool), Errno>
462 where
463 L: LockEqualOrBefore<FileOpsCore>,
464 {
465 if DirEntry::is_reserved_name(name) {
466 return error!(EEXIST);
467 }
468 if name.len() > NAME_MAX as usize {
470 return error!(ENAMETOOLONG);
471 }
472 if name.contains(&path::SEPARATOR) {
473 return error!(EINVAL);
474 }
475 let (entry, exists) =
476 self.get_or_create_child(locked, current_task, mount, name, create_node_fn)?;
477 if !exists {
478 self.node.update_ctime_mtime();
480 entry.notify_creation();
481 }
482 Ok((entry, exists))
483 }
484
485 #[cfg(test)]
488 pub fn create_dir<L>(
489 self: &DirEntryHandle,
490 locked: &mut starnix_sync::Locked<L>,
491 current_task: &CurrentTask,
492 name: &FsStr,
493 ) -> Result<DirEntryHandle, Errno>
494 where
495 L: LockEqualOrBefore<FileOpsCore>,
496 {
497 self.create_dir_for_testing(locked, current_task, name)
498 }
499
500 pub fn create_dir_for_testing<L>(
503 self: &DirEntryHandle,
504 locked: &mut Locked<L>,
505 current_task: &CurrentTask,
506 name: &FsStr,
507 ) -> Result<DirEntryHandle, Errno>
508 where
509 L: LockEqualOrBefore<FileOpsCore>,
510 {
511 self.create_entry(
513 locked,
514 current_task,
515 &MountInfo::detached(),
516 name,
517 |locked, dir, mount, name| {
518 dir.create_node(
519 locked,
520 current_task,
521 mount,
522 name,
523 starnix_uapi::file_mode::mode!(IFDIR, 0o777),
524 starnix_uapi::device_id::DeviceId::NONE,
525 FsCred::root(),
526 )
527 },
528 )
529 }
530
531 pub fn create_tmpfile<L>(
537 self: &DirEntryHandle,
538 locked: &mut Locked<L>,
539 current_task: &CurrentTask,
540 mount: &MountInfo,
541 mode: FileMode,
542 owner: FsCred,
543 flags: OpenFlags,
544 ) -> Result<DirEntryHandle, Errno>
545 where
546 L: LockEqualOrBefore<FileOpsCore>,
547 {
548 if !self.node.is_dir() {
550 return error!(ENOTDIR);
551 }
552 assert!(mode.is_reg());
553
554 let link_behavior = if flags.contains(OpenFlags::EXCL) {
562 FsNodeLinkBehavior::Disallowed
563 } else {
564 FsNodeLinkBehavior::Allowed
565 };
566
567 let node =
568 self.node.create_tmpfile(locked, current_task, mount, mode, owner, link_behavior)?;
569 let local_name = format!("#{}", node.ino).into();
570 Ok(DirEntry::new_deleted(node, Some(self.clone()), local_name))
571 }
572
573 pub fn unlink<L>(
574 self: &DirEntryHandle,
575 locked: &mut Locked<L>,
576 current_task: &CurrentTask,
577 mount: &MountInfo,
578 name: &FsStr,
579 kind: UnlinkKind,
580 must_be_directory: bool,
581 ) -> Result<(), Errno>
582 where
583 L: LockEqualOrBefore<FileOpsCore>,
584 {
585 assert!(!DirEntry::is_reserved_name(name));
586
587 let child_to_unlink;
589
590 let mut self_children = self.lock_children();
591 child_to_unlink = self_children.component_lookup(locked, current_task, mount, name)?;
592 child_to_unlink.require_no_mounts(mount)?;
593
594 if must_be_directory && !child_to_unlink.node.is_dir() {
601 return error!(ENOTDIR);
602 }
603
604 match kind {
605 UnlinkKind::Directory => {
606 if !child_to_unlink.node.is_dir() {
607 return error!(ENOTDIR);
608 }
609 }
610 UnlinkKind::NonDirectory => {
611 if child_to_unlink.node.is_dir() {
612 return error!(EISDIR);
613 }
614 }
615 }
616
617 self.node.unlink(locked, current_task, mount, name, &child_to_unlink.node)?;
618 self_children.children.remove(name);
619
620 std::mem::drop(self_children);
621 child_to_unlink.destroy(¤t_task.kernel().mounts);
622
623 Ok(())
624 }
625
626 fn destroy(self: DirEntryHandle, mounts: &Mounts) {
630 let was_already_dead =
631 self.raise_flags(DirEntryFlags::IS_DEAD).contains(DirEntryFlags::IS_DEAD);
632 if was_already_dead {
633 return;
634 }
635 let unmount =
636 self.lower_flags(DirEntryFlags::HAS_MOUNTS).contains(DirEntryFlags::HAS_MOUNTS);
637 self.node.fs().will_destroy_dir_entry(&self);
638 if unmount {
639 mounts.unmount(&self);
640 }
641 self.notify_deletion();
642 }
643
644 pub fn is_descendant_of(self: &DirEntryHandle, other: &DirEntryHandle) -> bool {
646 let scope = RcuReadScope::new();
647 let mut current = self.deref();
648 loop {
649 if std::ptr::eq(current, other.deref()) {
650 return true;
652 }
653 if let Some(parent) = current.parent_ref(&scope) {
654 current = parent;
655 } else {
656 return false;
658 }
659 }
660 }
661
662 pub fn rename<L>(
667 locked: &mut Locked<L>,
668 current_task: &CurrentTask,
669 old_parent: &DirEntryHandle,
670 old_mount: &MountInfo,
671 old_basename: &FsStr,
672 new_parent: &DirEntryHandle,
673 new_mount: &MountInfo,
674 new_basename: &FsStr,
675 flags: RenameFlags,
676 ) -> Result<(), Errno>
677 where
678 L: LockEqualOrBefore<FileOpsCore>,
679 {
680 if old_mount != new_mount {
682 return error!(EXDEV);
683 }
684
685 let mount = old_mount;
687
688 if DirEntry::is_reserved_name(old_basename) || DirEntry::is_reserved_name(new_basename) {
691 if flags.contains(RenameFlags::NOREPLACE) {
692 return error!(EEXIST);
693 }
694 return error!(EBUSY);
695 }
696
697 if Arc::ptr_eq(&old_parent.node, &new_parent.node) && old_basename == new_basename {
700 return Ok(());
701 }
702
703 old_parent.node.check_access(
705 locked,
706 current_task,
707 mount,
708 Access::WRITE,
709 CheckAccessReason::InternalPermissionChecks,
710 old_parent,
711 )?;
712 new_parent.node.check_access(
713 locked,
714 current_task,
715 mount,
716 Access::WRITE,
717 CheckAccessReason::InternalPermissionChecks,
718 new_parent,
719 )?;
720
721 let fs = old_parent.node.fs();
724
725 let renamed;
728 let mut maybe_replaced = None;
729
730 {
731 let _lock = fs.rename_mutex.lock();
741
742 let mut state = RenameGuard::lock(old_parent, new_parent);
747
748 renamed = state.old_parent_children().component_lookup(
751 locked,
752 current_task,
753 mount,
754 old_basename,
755 )?;
756
757 let lookup_replaced = state.new_parent_children().component_lookup(
762 locked,
763 current_task,
764 mount,
765 new_basename,
766 );
767
768 if let Ok(replaced) = &lookup_replaced {
777 if old_parent.is_descendant_of(replaced) {
778 if flags.contains(RenameFlags::EXCHANGE) {
779 return error!(EINVAL);
780 } else {
781 return error!(ENOTEMPTY);
782 }
783 }
784 }
785
786 let mut state =
789 state.lock_info(old_parent, new_parent, &renamed, lookup_replaced.as_ref().ok());
790
791 if new_parent.is_descendant_of(&renamed) {
794 return error!(EINVAL);
795 }
796
797 {
800 let _token = allow_subclass();
804 old_parent.node.check_sticky_bit(
805 current_task,
806 &renamed.node,
807 state.old_parent_info(),
808 )?;
809 }
810
811 renamed.require_no_mounts(mount)?;
816
817 match &lookup_replaced {
822 Ok(replaced) => {
823 let replaced = maybe_replaced.insert(replaced.clone());
825
826 if flags.contains(RenameFlags::NOREPLACE) {
827 return error!(EEXIST);
828 }
829
830 if Arc::ptr_eq(&renamed.node, &replaced.node) {
836 return Ok(());
837 }
838
839 if state.replaced_is_dir() {
844 replaced.require_no_mounts(mount)?;
849 }
850
851 if !flags.intersects(RenameFlags::EXCHANGE | RenameFlags::REPLACE_ANY) {
852 let renamed_is_dir = state.renamed_is_dir();
853 let replaced_is_dir = state.replaced_is_dir();
854 if renamed_is_dir && !replaced_is_dir {
855 return error!(ENOTDIR);
856 } else if !renamed_is_dir && replaced_is_dir {
857 return error!(EISDIR);
858 }
859 }
860 }
861 Err(errno) if *errno == ENOENT => {
863 if flags.contains(RenameFlags::EXCHANGE) {
864 return error!(ENOENT);
865 }
866 }
867 Err(e) => return Err(e.clone()),
869 }
870
871 security::check_fs_node_rename_access(
872 current_task,
873 &old_parent.node,
874 &renamed.node,
875 &new_parent.node,
876 maybe_replaced.as_ref().map(|dir_entry| dir_entry.node.deref().as_ref()),
877 old_basename,
878 new_basename,
879 )?;
880
881 if let Some(replaced) = maybe_replaced.as_ref() {
882 let _token = allow_subclass();
886 new_parent.node.check_sticky_bit(
887 current_task,
888 &replaced.node,
889 state.new_parent_info().unwrap_or_else(|| state.old_parent_info()),
890 )?;
891 }
892
893 if flags.contains(RenameFlags::EXCHANGE) {
900 fs.exchange(current_task, &mut state, old_basename, new_basename)?;
901 } else {
902 fs.rename(locked, current_task, &mut state, old_basename, new_basename)?;
903 }
904
905 renamed.set_parent(new_parent.clone());
908 renamed.local_name.update(new_basename.to_owned());
909
910 state
914 .new_parent_children()
915 .children
916 .insert(new_basename.into(), Arc::downgrade(&renamed));
917
918 unsafe {
927 renamed.children.reset_dependencies();
928 renamed.node.info_lock().reset_dependencies();
929 old_parent.children.reset_dependencies();
930 old_parent.node.info_lock().reset_dependencies();
931 new_parent.children.reset_dependencies();
932 new_parent.node.info_lock().reset_dependencies();
933 }
934
935 if flags.contains(RenameFlags::EXCHANGE) {
936 let replaced =
938 maybe_replaced.as_ref().expect("replaced expected with RENAME_EXCHANGE");
939 replaced.set_parent(old_parent.clone());
940 replaced.local_name.update(old_basename.to_owned());
941 state
942 .old_parent_children()
943 .children
944 .insert(old_basename.into(), Arc::downgrade(replaced));
945
946 unsafe {
950 replaced.children.reset_dependencies();
951 replaced.node.info_lock().reset_dependencies();
952 }
953 } else {
954 state.old_parent_children().children.remove(old_basename);
956 }
957 };
958
959 fs.purge_old_entries();
960
961 if let Some(replaced) = maybe_replaced {
962 if !flags.contains(RenameFlags::EXCHANGE) {
963 replaced.destroy(¤t_task.kernel().mounts);
964 }
965 }
966
967 renamed.node.update_ctime();
969
970 let mode = renamed.node.info().mode;
971 if let Some(hook) =
972 current_task.kernel().expando.peek::<Arc<dyn inotify_hook::NotifyHook>>()
973 {
974 let cookie = hook.get_next_cookie();
975 old_parent.node.notify(InotifyMask::MOVE_FROM, cookie, old_basename, mode, false);
976 new_parent.node.notify(InotifyMask::MOVE_TO, cookie, new_basename, mode, false);
977 renamed.node.notify(InotifyMask::MOVE_SELF, 0, Default::default(), mode, false);
978 }
979
980 Ok(())
981 }
982
983 pub fn get_children<F, T>(&self, callback: F) -> T
984 where
985 F: FnOnce(&DirEntryChildren) -> T,
986 {
987 let children = self.children.read();
988 callback(&children)
989 }
990
991 pub fn remove_child(&self, name: &FsStr, mounts: &Mounts) {
994 let mut children = self.children.write();
995 let child = children.get(name).and_then(Weak::upgrade);
996 if let Some(child) = child {
997 children.remove(name);
998 std::mem::drop(children);
999 child.destroy(mounts);
1000 }
1001 }
1002
1003 fn get_or_create_child<L>(
1004 self: &DirEntryHandle,
1005 locked: &mut Locked<L>,
1006 current_task: &CurrentTask,
1007 mount: &MountInfo,
1008 name: &FsStr,
1009 create_fn: impl FnOnce(
1010 &mut Locked<L>,
1011 &FsNodeHandle,
1012 &MountInfo,
1013 &FsStr,
1014 ) -> Result<FsNodeHandle, Errno>,
1015 ) -> Result<(DirEntryHandle, bool), Errno>
1016 where
1017 L: LockEqualOrBefore<FileOpsCore>,
1018 {
1019 assert!(!DirEntry::is_reserved_name(name));
1020 if !self.node.is_dir() {
1022 return error!(ENOTDIR);
1023 }
1024 self.node.check_access(
1026 locked,
1027 current_task,
1028 mount,
1029 Access::EXEC,
1030 CheckAccessReason::InternalPermissionChecks,
1031 self,
1032 )?;
1033
1034 let child = self.children.read().get(name).and_then(Weak::upgrade);
1037 let (child, create_result) = if let Some(child) = child {
1038 if self.node.fail_if_locked(current_task, &self.node.info()).is_ok() {
1040 child.node.fs().did_access_dir_entry(&child);
1041 }
1042 (child, CreationResult::Existed { create_fn })
1043 } else {
1044 let (child, create_result) = self.lock_children().get_or_create_child(
1045 locked,
1046 current_task,
1047 mount,
1048 name,
1049 create_fn,
1050 )?;
1051 child.node.fs().purge_old_entries();
1052 (child, create_result)
1053 };
1054
1055 let (child, exists) = match create_result {
1056 CreationResult::Created => (child, false),
1057 CreationResult::Existed { create_fn } => {
1058 if child.ops.revalidate(
1059 locked.cast_locked::<FileOpsCore>(),
1060 current_task,
1061 &child,
1062 )? {
1063 (child, true)
1064 } else {
1065 self.internal_remove_child(&child);
1066 child.destroy(¤t_task.kernel().mounts);
1067
1068 let (child, create_result) = self.lock_children().get_or_create_child(
1069 locked,
1070 current_task,
1071 mount,
1072 name,
1073 create_fn,
1074 )?;
1075 child.node.fs().purge_old_entries();
1076 (child, matches!(create_result, CreationResult::Existed { .. }))
1077 }
1078 }
1079 };
1080
1081 Ok((child, exists))
1082 }
1083
1084 #[cfg(test)]
1092 pub fn copy_child_names(&self) -> Vec<FsString> {
1093 let scope = RcuReadScope::new();
1094 self.children
1095 .read()
1096 .values()
1097 .filter_map(|child| Weak::upgrade(child).map(|c| c.local_name.read(&scope).to_owned()))
1098 .collect()
1099 }
1100
1101 fn internal_remove_child(&self, child: &DirEntry) {
1102 let mut children = self.children.write();
1103 let scope = RcuReadScope::new();
1104 let local_name = child.local_name.read(&scope);
1105 if let Some(weak_child) = children.get(local_name) {
1106 if std::ptr::eq(weak_child.as_ptr(), child) {
1110 children.remove(local_name);
1111 }
1112 }
1113 }
1114
1115 pub fn notify(&self, event_mask: InotifyMask) {
1117 self.notify_watchers(event_mask, self.is_dead());
1118 }
1119
1120 pub fn notify_ignoring_excl_unlink(&self, event_mask: InotifyMask) {
1124 self.notify_watchers(event_mask, false);
1126 }
1127
1128 fn notify_watchers(&self, event_mask: InotifyMask, is_dead: bool) {
1129 let mode = self.node.info().mode;
1130 {
1131 let scope = RcuReadScope::new();
1132 if let Some(parent) = self.parent_ref(&scope) {
1133 let local_name = self.local_name.read(&scope);
1134 parent.node.notify(event_mask, 0, local_name, mode, is_dead);
1135 }
1136 }
1137 self.node.notify(event_mask, 0, Default::default(), mode, is_dead);
1138 }
1139
1140 fn notify_creation(&self) {
1142 let mode = self.node.info().mode;
1143 if Arc::strong_count(&self.node) > 1 {
1144 self.node.notify(InotifyMask::ATTRIB, 0, Default::default(), mode, false);
1146 }
1147 let scope = RcuReadScope::new();
1148 if let Some(parent) = self.parent_ref(&scope) {
1149 let local_name = self.local_name.read(&scope);
1150 parent.node.notify(InotifyMask::CREATE, 0, local_name, mode, false);
1151 }
1152 }
1153
1154 fn notify_deletion(&self) {
1158 let mode = self.node.info().mode;
1159 if !mode.is_dir() {
1160 self.node.notify(InotifyMask::ATTRIB, 0, Default::default(), mode, false);
1162 }
1163
1164 if Arc::strong_count(&self.node) == 1 {
1167 self.node.notify(InotifyMask::DELETE_SELF, 0, Default::default(), mode, false);
1168 }
1169
1170 let scope = RcuReadScope::new();
1171 if let Some(parent) = self.parent_ref(&scope) {
1172 let local_name = self.local_name.read(&scope);
1173 parent.node.notify(InotifyMask::DELETE, 0, local_name, mode, false);
1174 }
1175 }
1176
1177 pub fn has_mounts(&self) -> bool {
1179 self.flags().contains(DirEntryFlags::HAS_MOUNTS)
1180 }
1181
1182 pub fn set_has_mounts(&self, v: bool) {
1184 if v {
1185 self.raise_flags(DirEntryFlags::HAS_MOUNTS);
1186 } else {
1187 self.lower_flags(DirEntryFlags::HAS_MOUNTS);
1188 }
1189 }
1190
1191 fn require_no_mounts(self: &Arc<Self>, parent_mount: &MountInfo) -> Result<(), Errno> {
1193 if self.has_mounts() {
1194 if let Some(mount) = parent_mount.as_ref() {
1195 if mount.has_submount(self) {
1196 return error!(EBUSY);
1197 }
1198 }
1199 }
1200 Ok(())
1201 }
1202}
1203
1204struct DirEntryLockedChildren<'a> {
1205 entry: &'a DirEntryHandle,
1206 children: LockDepWriteGuard<'a, DirEntryChildren>,
1207}
1208
1209enum CreationResult<F> {
1210 Created,
1211 Existed { create_fn: F },
1212}
1213
1214impl<'a> DirEntryLockedChildren<'a> {
1215 fn component_lookup<L>(
1216 &mut self,
1217 locked: &mut Locked<L>,
1218 current_task: &CurrentTask,
1219 mount: &MountInfo,
1220 name: &FsStr,
1221 ) -> Result<DirEntryHandle, Errno>
1222 where
1223 L: LockEqualOrBefore<FileOpsCore>,
1224 {
1225 assert!(!DirEntry::is_reserved_name(name));
1226 let (node, _) =
1227 self.get_or_create_child(locked, current_task, mount, name, |_, _, _, _| {
1228 error!(ENOENT)
1229 })?;
1230 Ok(node)
1231 }
1232
1233 fn get_or_create_child<
1234 L,
1235 F: FnOnce(&mut Locked<L>, &FsNodeHandle, &MountInfo, &FsStr) -> Result<FsNodeHandle, Errno>,
1236 >(
1237 &mut self,
1238 locked: &mut Locked<L>,
1239 current_task: &CurrentTask,
1240 mount: &MountInfo,
1241 name: &FsStr,
1242 create_fn: F,
1243 ) -> Result<(DirEntryHandle, CreationResult<F>), Errno>
1244 where
1245 L: LockEqualOrBefore<FileOpsCore>,
1246 {
1247 let create_child = |locked: &mut Locked<L>, create_fn: F| {
1248 let (node, create_result) =
1250 match self.entry.node.lookup(locked, current_task, mount, name) {
1251 Ok(node) => (node, CreationResult::Existed { create_fn }),
1252 Err(e) if e == ENOENT => {
1253 (create_fn(locked, &self.entry.node, mount, name)?, CreationResult::Created)
1254 }
1255 Err(e) => return Err(e),
1256 };
1257
1258 assert!(
1259 node.info().mode & FileMode::IFMT != FileMode::EMPTY,
1260 "FsNode initialization did not populate the FileMode in FsNodeInfo."
1261 );
1262
1263 let entry = DirEntry::new(node, Some(self.entry.clone()), name.to_owned());
1264
1265 if let Err(err) = security::fs_node_init_with_dentry(locked, current_task, &entry) {
1266 entry.parent.update(None);
1269 return Err(err);
1270 }
1271
1272 Ok((entry, create_result))
1273 };
1274
1275 let (child, create_result) = match self.children.entry(name.to_owned()) {
1276 Entry::Vacant(entry) => {
1277 let (child, create_result) = create_child(locked, create_fn)?;
1278 if self.entry.node.fail_if_locked(current_task, &self.entry.node.info()).is_ok() {
1280 entry.insert(Arc::downgrade(&child));
1281 }
1282 (child, create_result)
1283 }
1284 Entry::Occupied(mut entry) => {
1285 if let Some(child) = Weak::upgrade(entry.get()) {
1289 if self.entry.node.fail_if_locked(current_task, &self.entry.node.info()).is_ok()
1291 {
1292 child.node.fs().did_access_dir_entry(&child);
1293 }
1294 return Ok((child, CreationResult::Existed { create_fn }));
1295 }
1296 let (child, create_result) = create_child(locked, create_fn)?;
1297 if self.entry.node.fail_if_locked(current_task, &self.entry.node.info()).is_ok() {
1299 entry.insert(Arc::downgrade(&child));
1300 }
1301 (child, create_result)
1302 }
1303 };
1304
1305 Ok((child, create_result))
1306 }
1307}
1308
1309impl fmt::Debug for DirEntry {
1310 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1311 let scope = RcuReadScope::new();
1312 let mut parents = vec![];
1313 let mut maybe_parent = self.parent_ref(&scope);
1314 while let Some(parent) = maybe_parent {
1315 parents.push(parent.local_name.read(&scope));
1316 maybe_parent = parent.parent_ref(&scope);
1317 }
1318 let mut builder = f.debug_struct("DirEntry");
1319 builder.field("id", &(self as *const DirEntry));
1320 builder.field("local_name", &self.local_name.read(&scope).to_owned());
1321 if !parents.is_empty() {
1322 builder.field("parents", &parents);
1323 }
1324 builder.finish()
1325 }
1326}
1327
1328#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1329enum RenameRelationship {
1330 Same,
1331 NewIsDescendant,
1332 OldIsDescendant,
1333 Independent,
1334}
1335
1336struct RenameGuard<'a> {
1337 old_parent_guard: DirEntryLockedChildren<'a>,
1338 new_parent_guard: Option<DirEntryLockedChildren<'a>>,
1339 relationship: RenameRelationship,
1340}
1341
1342impl<'a> RenameGuard<'a> {
1343 fn lock(old_parent: &'a DirEntryHandle, new_parent: &'a DirEntryHandle) -> Self {
1344 if Arc::ptr_eq(old_parent, new_parent) {
1345 let old_parent_guard = old_parent.lock_children();
1346 Self {
1347 old_parent_guard,
1348 new_parent_guard: None,
1349 relationship: RenameRelationship::Same,
1350 }
1351 } else if new_parent.is_descendant_of(old_parent) {
1352 let old_parent_guard = old_parent.lock_children();
1353 let _token = allow_subclass();
1354 let new_parent_guard = new_parent.lock_children();
1355 Self {
1356 old_parent_guard,
1357 new_parent_guard: Some(new_parent_guard),
1358 relationship: RenameRelationship::NewIsDescendant,
1359 }
1360 } else if old_parent.is_descendant_of(new_parent) {
1361 let new_parent_guard = new_parent.lock_children();
1362 let _token = allow_subclass();
1363 let old_parent_guard = old_parent.lock_children();
1364 Self {
1365 old_parent_guard,
1366 new_parent_guard: Some(new_parent_guard),
1367 relationship: RenameRelationship::OldIsDescendant,
1368 }
1369 } else {
1370 let (g1, g2) =
1372 starnix_sync::ordered_write_lock(&old_parent.children, &new_parent.children);
1373 let old_parent_guard = DirEntryLockedChildren { entry: old_parent, children: g1 };
1374 let new_parent_guard = DirEntryLockedChildren { entry: new_parent, children: g2 };
1375 Self {
1376 old_parent_guard,
1377 new_parent_guard: Some(new_parent_guard),
1378 relationship: RenameRelationship::Independent,
1379 }
1380 }
1381 }
1382
1383 fn lock_info(
1387 self,
1388 old_parent: &'a DirEntryHandle,
1389 new_parent: &'a DirEntryHandle,
1390 renamed: &'a DirEntryHandle,
1391 replaced: Option<&'a DirEntryHandle>,
1392 ) -> RenameContext<'a> {
1393 let (g1, g2) = match self.relationship {
1394 RenameRelationship::Same => (old_parent.node.info_lock().write(), None),
1395 RenameRelationship::NewIsDescendant => {
1396 let g1 = old_parent.node.info_lock().write();
1397 let _token = allow_subclass();
1398 let g2 = new_parent.node.info_lock().write();
1399 (g1, Some(g2))
1400 }
1401 RenameRelationship::OldIsDescendant => {
1402 let g2 = new_parent.node.info_lock().write();
1403 let _token = allow_subclass();
1404 let g1 = old_parent.node.info_lock().write();
1405 (g1, Some(g2))
1406 }
1407 RenameRelationship::Independent => {
1408 let (g1, g2) = starnix_sync::ordered_write_lock(
1409 old_parent.node.info_lock(),
1410 new_parent.node.info_lock(),
1411 );
1412 (g1, Some(g2))
1413 }
1414 };
1415
1416 RenameContext {
1417 renamed,
1418 replaced,
1419 old_parent_guard: self.old_parent_guard,
1420 new_parent_guard: self.new_parent_guard,
1421 old_parent_info_guard: g1,
1422 new_parent_info_guard: g2,
1423 }
1424 }
1425
1426 fn old_parent_children(&mut self) -> &mut DirEntryLockedChildren<'a> {
1427 &mut self.old_parent_guard
1428 }
1429
1430 fn new_parent_children(&mut self) -> &mut DirEntryLockedChildren<'a> {
1431 if let Some(new_guard) = self.new_parent_guard.as_mut() {
1432 new_guard
1433 } else {
1434 &mut self.old_parent_guard
1435 }
1436 }
1437}
1438
1439pub struct RenameContext<'a> {
1452 pub renamed: &'a DirEntryHandle,
1453 pub replaced: Option<&'a DirEntryHandle>,
1454 old_parent_guard: DirEntryLockedChildren<'a>,
1455 new_parent_guard: Option<DirEntryLockedChildren<'a>>,
1456 old_parent_info_guard: LockDepWriteGuard<'a, crate::vfs::FsNodeInfo>,
1457 new_parent_info_guard: Option<LockDepWriteGuard<'a, crate::vfs::FsNodeInfo>>,
1458}
1459
1460impl<'a> RenameContext<'a> {
1461 pub fn renamed_is_dir(&self) -> bool {
1468 self.is_dir(&self.renamed.node)
1469 }
1470
1471 pub fn replaced_is_dir(&self) -> bool {
1480 self.replaced.map(|r| self.is_dir(&r.node)).unwrap_or(false)
1481 }
1482
1483 pub fn old_parent(&self) -> &DirEntryHandle {
1488 self.old_parent_guard.entry
1489 }
1490
1491 pub fn new_parent(&self) -> &DirEntryHandle {
1496 self.new_parent_guard.as_ref().map(|g| g.entry).unwrap_or(self.old_parent_guard.entry)
1497 }
1498
1499 pub fn parent_infos_mut(
1508 &mut self,
1509 ) -> (&mut crate::vfs::FsNodeInfo, Option<&mut crate::vfs::FsNodeInfo>) {
1510 let old = &mut *self.old_parent_info_guard;
1511 let new = self.new_parent_info_guard.as_mut().map(|g| &mut **g);
1512 (old, new)
1513 }
1514
1515 pub fn old_parent_info(&self) -> &crate::vfs::FsNodeInfo {
1518 &self.old_parent_info_guard
1519 }
1520 pub fn new_parent_info(&self) -> Option<&crate::vfs::FsNodeInfo> {
1525 self.new_parent_info_guard.as_deref()
1526 }
1527
1528 fn new_parent_children(&mut self) -> &mut DirEntryLockedChildren<'a> {
1529 self.new_parent_guard.as_mut().unwrap_or(&mut self.old_parent_guard)
1530 }
1531
1532 fn old_parent_children(&mut self) -> &mut DirEntryLockedChildren<'a> {
1533 &mut self.old_parent_guard
1534 }
1535
1536 fn is_dir(&self, node: &FsNodeHandle) -> bool {
1537 if Arc::ptr_eq(node, &self.old_parent().node) {
1538 self.old_parent_info_guard.mode.is_dir()
1539 } else if Arc::ptr_eq(node, &self.new_parent().node) {
1540 self.new_parent_info_guard
1541 .as_ref()
1542 .map(|g| g.mode.is_dir())
1543 .unwrap_or_else(|| self.old_parent_info_guard.mode.is_dir())
1544 } else {
1545 let _token = allow_subclass();
1546 node.is_dir()
1547 }
1548 }
1549}
1550
1551impl Drop for DirEntry {
1555 fn drop(&mut self) {
1556 let maybe_parent = self.parent();
1557 self.parent.update(None);
1558 if let Some(parent) = maybe_parent {
1559 parent.internal_remove_child(self);
1560 }
1561 }
1562}