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,
18 FuseDirEntryChildrenLevel, LockDepWriteGuard, 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(&self, _: &CurrentTask, _: &DirEntry) -> Result<bool, Errno> {
72 Ok(true)
73 }
74}
75
76atomic_bitflags! {
77 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
78 pub struct DirEntryFlags: u8 {
79 const IS_DEAD = 1 << 0;
81
82 const HAS_MOUNTS = 1 << 1;
84 }
85}
86
87pub struct DefaultDirEntryOps;
88
89impl DirEntryOps for DefaultDirEntryOps {}
90
91pub struct DirEntry {
103 pub node: FsNodeHandle,
108
109 ops: Box<dyn DirEntryOps>,
114
115 parent: RcuOptionArc<DirEntry>,
122
123 flags: AtomicDirEntryFlags,
125
126 local_name: RcuString,
135
136 children: DynamicLockDepRwLock<DirEntryChildren>,
146}
147type DirEntryChildren = BTreeMap<FsString, Weak<DirEntry>>;
148
149pub type DirEntryHandle = Arc<DirEntry>;
150
151impl DirEntry {
152 #[allow(clippy::let_and_return)]
153 pub fn new_uncached(
154 node: FsNodeHandle,
155 parent: Option<DirEntryHandle>,
156 local_name: FsString,
157 ) -> DirEntryHandle {
158 let ops = node.create_dir_entry_ops();
159 let fs_lockdep_type = node.fs().fs_lockdep_type();
160 let result = Arc::new(DirEntry {
161 node,
162 ops,
163 parent: RcuOptionArc::new(parent),
164 flags: Default::default(),
165 local_name: local_name.into(),
166 children: match fs_lockdep_type {
167 FsLockDepType::Normal => {
168 DynamicLockDepRwLock::new::<DirEntryChildrenLevel>(Default::default())
169 }
170 FsLockDepType::Recursive => {
171 DynamicLockDepRwLock::new::<DirEntryChildrenRecursiveLevel>(Default::default())
172 }
173 FsLockDepType::Fuse => {
174 DynamicLockDepRwLock::new::<FuseDirEntryChildrenLevel>(Default::default())
175 }
176 },
177 });
178 #[cfg(any(test, debug_assertions))]
179 {
180 let _token = allow_subclass();
183 let _l1 = result.children.read();
184 }
185 result
186 }
187
188 pub fn new(
189 node: FsNodeHandle,
190 parent: Option<DirEntryHandle>,
191 local_name: FsString,
192 ) -> DirEntryHandle {
193 let result = Self::new_uncached(node, parent, local_name);
194 result.node.fs().did_create_dir_entry(&result);
195 result
196 }
197
198 pub fn new_unrooted(node: FsNodeHandle) -> DirEntryHandle {
201 Self::new_uncached(node, None, FsString::default())
202 }
203
204 pub fn new_deleted(
206 node: FsNodeHandle,
207 parent: Option<DirEntryHandle>,
208 local_name: FsString,
209 ) -> DirEntryHandle {
210 let entry = DirEntry::new_uncached(node, parent, local_name);
211 entry.raise_flags(DirEntryFlags::IS_DEAD);
212 entry
213 }
214
215 pub fn open_anonymous(
217 self: &DirEntryHandle,
218 current_task: &CurrentTask,
219 flags: OpenFlags,
220 ) -> Result<FileHandle, Errno> {
221 let ops = self.node.create_file_ops(current_task, flags)?;
222 FileObject::new(current_task, ops, NamespaceNode::new_anonymous(self.clone()), flags)
223 }
224
225 pub fn set_children(self: &DirEntryHandle, children: BTreeMap<FsString, DirEntryHandle>) {
228 let mut dir_entry_children = self.lock_children();
229 assert!(dir_entry_children.children.is_empty());
230 for (name, child) in children.into_iter() {
231 child.set_parent(self.clone());
232 dir_entry_children.children.insert(name, Arc::downgrade(&child));
233 }
234 }
235
236 fn lock_children<'a>(self: &'a DirEntryHandle) -> DirEntryLockedChildren<'a> {
237 DirEntryLockedChildren { entry: self, children: self.children.write() }
238 }
239
240 pub fn parent(&self) -> Option<DirEntryHandle> {
242 self.parent.to_option_arc()
243 }
244
245 pub fn parent_ref<'a>(&'a self, scope: &'a RcuReadScope) -> Option<&'a DirEntry> {
249 self.parent.as_ref(scope)
250 }
251
252 pub fn set_parent(&self, parent: DirEntryHandle) {
254 self.parent.update(Some(parent));
255 }
256
257 pub fn parent_or_self(self: &DirEntryHandle) -> DirEntryHandle {
267 self.parent().unwrap_or_else(|| self.clone())
268 }
269
270 pub fn local_name<'a>(&self, scope: &'a RcuReadScope) -> &'a FsStr {
274 self.local_name.read(scope)
275 }
276
277 pub fn is_reserved_name(name: &FsStr) -> bool {
282 name.is_empty() || name == "." || name == ".."
283 }
284
285 pub fn flags(&self) -> DirEntryFlags {
287 self.flags.load(Ordering::Acquire)
288 }
289
290 pub fn raise_flags(&self, flags: DirEntryFlags) -> DirEntryFlags {
294 self.flags.fetch_or(flags, Ordering::AcqRel)
295 }
296
297 pub fn lower_flags(&self, flags: DirEntryFlags) -> DirEntryFlags {
301 self.flags.fetch_and(!flags, Ordering::AcqRel)
302 }
303
304 pub fn is_dead(&self) -> bool {
306 self.flags().contains(DirEntryFlags::IS_DEAD)
307 }
308
309 pub fn component_lookup(
312 self: &DirEntryHandle,
313 current_task: &CurrentTask,
314 mount: &MountInfo,
315 name: &FsStr,
316 ) -> Result<DirEntryHandle, Errno> {
317 let (node, _) = self.get_or_create_child(current_task, mount, name, |d, mount, name| {
318 d.lookup(current_task, mount, name)
319 })?;
320 Ok(node)
321 }
322
323 pub fn get_children_pipelined(
324 self: &DirEntryHandle,
325 current_task: &CurrentTask,
326 mount: &MountInfo,
327 names: &[&FsStr],
328 ) -> LookupVec<Result<DirEntryHandle, Errno>> {
329 let mut nodes = LookupVec::new();
330 let mut results = LookupVec::new();
331 let mut current_parent = self.clone();
332 for i in 0..names.len() {
333 let next_node = nodes.pop();
334 match current_parent.get_or_create_child(
335 current_task,
336 mount,
337 names[i],
338 |parent_node, _mount, _name| {
339 if let Some(node) = next_node {
340 return node;
341 }
342 nodes =
343 parent_node.ops().lookup_pipelined(parent_node, current_task, &names[i..]);
344 nodes.reverse();
345 nodes.pop().unwrap()
346 },
347 ) {
348 Ok((entry, _)) => {
349 results.push(Ok(entry.clone()));
350 current_parent = entry;
351 }
352 Err(e) => {
353 results.push(Err(e));
354 break;
355 }
356 }
357 }
358 results
359 }
360
361 pub fn create_entry(
369 self: &DirEntryHandle,
370 current_task: &CurrentTask,
371 mount: &MountInfo,
372 name: &FsStr,
373 create_node_fn: impl FnOnce(&FsNodeHandle, &MountInfo, &FsStr) -> Result<FsNodeHandle, Errno>,
374 ) -> Result<DirEntryHandle, Errno> {
375 let (entry, exists) =
376 self.create_entry_internal(current_task, mount, name, create_node_fn)?;
377 if exists {
378 return error!(EEXIST);
379 }
380 Ok(entry)
381 }
382
383 pub fn get_or_create_entry(
386 self: &DirEntryHandle,
387 current_task: &CurrentTask,
388 mount: &MountInfo,
389 name: &FsStr,
390 create_node_fn: impl FnOnce(&FsNodeHandle, &MountInfo, &FsStr) -> Result<FsNodeHandle, Errno>,
391 ) -> Result<DirEntryHandle, Errno> {
392 let (entry, _exists) =
393 self.create_entry_internal(current_task, mount, name, create_node_fn)?;
394 Ok(entry)
395 }
396
397 fn create_entry_internal(
398 self: &DirEntryHandle,
399 current_task: &CurrentTask,
400 mount: &MountInfo,
401 name: &FsStr,
402 create_node_fn: impl FnOnce(&FsNodeHandle, &MountInfo, &FsStr) -> Result<FsNodeHandle, Errno>,
403 ) -> Result<(DirEntryHandle, bool), Errno> {
404 if DirEntry::is_reserved_name(name) {
405 return error!(EEXIST);
406 }
407 if name.len() > NAME_MAX as usize {
409 return error!(ENAMETOOLONG);
410 }
411 if name.contains(&path::SEPARATOR) {
412 return error!(EINVAL);
413 }
414 let (entry, exists) =
415 self.get_or_create_child(current_task, mount, name, create_node_fn)?;
416 if !exists {
417 self.node.update_ctime_mtime();
419 entry.notify_creation();
420 }
421 Ok((entry, exists))
422 }
423
424 #[cfg(test)]
427 pub fn create_dir(
428 self: &DirEntryHandle,
429 current_task: &CurrentTask,
430 name: &FsStr,
431 ) -> Result<DirEntryHandle, Errno> {
432 self.create_dir_for_testing(current_task, name)
433 }
434
435 pub fn create_dir_for_testing(
438 self: &DirEntryHandle,
439 current_task: &CurrentTask,
440 name: &FsStr,
441 ) -> Result<DirEntryHandle, Errno> {
442 self.create_entry(current_task, &MountInfo::detached(), name, |dir, mount, name| {
444 dir.create_node(
445 current_task,
446 mount,
447 name,
448 starnix_uapi::file_mode::mode!(IFDIR, 0o777),
449 starnix_uapi::device_id::DeviceId::NONE,
450 FsCred::root(),
451 )
452 })
453 }
454
455 pub fn create_tmpfile(
461 self: &DirEntryHandle,
462 current_task: &CurrentTask,
463 mount: &MountInfo,
464 mode: FileMode,
465 owner: FsCred,
466 flags: OpenFlags,
467 ) -> Result<DirEntryHandle, Errno> {
468 if !self.node.is_dir() {
470 return error!(ENOTDIR);
471 }
472 assert!(mode.is_reg());
473
474 let link_behavior = if flags.contains(OpenFlags::EXCL) {
482 FsNodeLinkBehavior::Disallowed
483 } else {
484 FsNodeLinkBehavior::Allowed
485 };
486
487 let node = self.node.create_tmpfile(current_task, mount, mode, owner, link_behavior)?;
488 let local_name = format!("#{}", node.ino).into();
489 Ok(DirEntry::new_deleted(node, Some(self.clone()), local_name))
490 }
491
492 pub fn unlink(
493 self: &DirEntryHandle,
494 current_task: &CurrentTask,
495 mount: &MountInfo,
496 name: &FsStr,
497 kind: UnlinkKind,
498 must_be_directory: bool,
499 ) -> Result<(), Errno> {
500 assert!(!DirEntry::is_reserved_name(name));
501
502 let child_to_unlink;
504
505 let mut self_children = self.lock_children();
506 child_to_unlink = self_children.component_lookup(current_task, mount, name)?;
507 child_to_unlink.require_no_mounts(mount)?;
508
509 if must_be_directory && !child_to_unlink.node.is_dir() {
516 return error!(ENOTDIR);
517 }
518
519 match kind {
520 UnlinkKind::Directory => {
521 if !child_to_unlink.node.is_dir() {
522 return error!(ENOTDIR);
523 }
524 }
525 UnlinkKind::NonDirectory => {
526 if child_to_unlink.node.is_dir() {
527 return error!(EISDIR);
528 }
529 }
530 }
531
532 self.node.unlink(current_task, mount, name, &child_to_unlink.node)?;
533 self_children.children.remove(name);
534
535 std::mem::drop(self_children);
536 child_to_unlink.destroy(¤t_task.kernel().mounts);
537
538 Ok(())
539 }
540
541 fn destroy(self: DirEntryHandle, mounts: &Mounts) {
545 let was_already_dead =
546 self.raise_flags(DirEntryFlags::IS_DEAD).contains(DirEntryFlags::IS_DEAD);
547 if was_already_dead {
548 return;
549 }
550 let unmount =
551 self.lower_flags(DirEntryFlags::HAS_MOUNTS).contains(DirEntryFlags::HAS_MOUNTS);
552 self.node.fs().will_destroy_dir_entry(&self);
553 if unmount {
554 mounts.unmount(&self);
555 }
556 self.notify_deletion();
557 }
558
559 pub fn is_descendant_of(self: &DirEntryHandle, other: &DirEntryHandle) -> bool {
561 let scope = RcuReadScope::new();
562 let mut current = self.deref();
563 loop {
564 if std::ptr::eq(current, other.deref()) {
565 return true;
567 }
568 if let Some(parent) = current.parent_ref(&scope) {
569 current = parent;
570 } else {
571 return false;
573 }
574 }
575 }
576
577 pub fn rename(
582 current_task: &CurrentTask,
583 old_parent: &DirEntryHandle,
584 old_mount: &MountInfo,
585 old_basename: &FsStr,
586 new_parent: &DirEntryHandle,
587 new_mount: &MountInfo,
588 new_basename: &FsStr,
589 flags: RenameFlags,
590 ) -> Result<(), Errno> {
591 if old_mount != new_mount {
593 return error!(EXDEV);
594 }
595
596 let mount = old_mount;
598
599 if DirEntry::is_reserved_name(old_basename) || DirEntry::is_reserved_name(new_basename) {
602 if flags.contains(RenameFlags::NOREPLACE) {
603 return error!(EEXIST);
604 }
605 return error!(EBUSY);
606 }
607
608 if Arc::ptr_eq(&old_parent.node, &new_parent.node) && old_basename == new_basename {
611 return Ok(());
612 }
613
614 old_parent.node.check_access(
616 current_task,
617 mount,
618 Access::WRITE,
619 CheckAccessReason::InternalPermissionChecks,
620 old_parent,
621 )?;
622 new_parent.node.check_access(
623 current_task,
624 mount,
625 Access::WRITE,
626 CheckAccessReason::InternalPermissionChecks,
627 new_parent,
628 )?;
629
630 let fs = old_parent.node.fs();
633
634 let renamed;
637 let mut maybe_replaced = None;
638
639 {
640 let _lock = fs.rename_mutex.lock();
650
651 let mut state = RenameGuard::lock(old_parent, new_parent);
656
657 renamed =
660 state.old_parent_children().component_lookup(current_task, mount, old_basename)?;
661
662 let lookup_replaced =
667 state.new_parent_children().component_lookup(current_task, mount, new_basename);
668
669 if let Ok(replaced) = &lookup_replaced {
678 if old_parent.is_descendant_of(replaced) {
679 if flags.contains(RenameFlags::EXCHANGE) {
680 return error!(EINVAL);
681 } else {
682 return error!(ENOTEMPTY);
683 }
684 }
685 }
686
687 let mut state =
690 state.lock_info(old_parent, new_parent, &renamed, lookup_replaced.as_ref().ok());
691
692 if new_parent.is_descendant_of(&renamed) {
695 return error!(EINVAL);
696 }
697
698 {
701 let _token = allow_subclass();
705 old_parent.node.check_sticky_bit(
706 current_task,
707 &renamed.node,
708 state.old_parent_info(),
709 )?;
710 }
711
712 renamed.require_no_mounts(mount)?;
717
718 match &lookup_replaced {
723 Ok(replaced) => {
724 let replaced = maybe_replaced.insert(replaced.clone());
726
727 if flags.contains(RenameFlags::NOREPLACE) {
728 return error!(EEXIST);
729 }
730
731 if Arc::ptr_eq(&renamed.node, &replaced.node) {
737 return Ok(());
738 }
739
740 if state.replaced_is_dir() {
745 replaced.require_no_mounts(mount)?;
750 }
751
752 if !flags.intersects(RenameFlags::EXCHANGE | RenameFlags::REPLACE_ANY) {
753 let renamed_is_dir = state.renamed_is_dir();
754 let replaced_is_dir = state.replaced_is_dir();
755 if renamed_is_dir && !replaced_is_dir {
756 return error!(ENOTDIR);
757 } else if !renamed_is_dir && replaced_is_dir {
758 return error!(EISDIR);
759 }
760 }
761 }
762 Err(errno) if *errno == ENOENT => {
764 if flags.contains(RenameFlags::EXCHANGE) {
765 return error!(ENOENT);
766 }
767 }
768 Err(e) => return Err(e.clone()),
770 }
771
772 security::check_fs_node_rename_access(
773 current_task,
774 &old_parent.node,
775 &renamed.node,
776 &new_parent.node,
777 maybe_replaced.as_ref().map(|dir_entry| dir_entry.node.deref().as_ref()),
778 old_basename,
779 new_basename,
780 )?;
781
782 if let Some(replaced) = maybe_replaced.as_ref() {
783 let _token = allow_subclass();
787 new_parent.node.check_sticky_bit(
788 current_task,
789 &replaced.node,
790 state.new_parent_info().unwrap_or_else(|| state.old_parent_info()),
791 )?;
792 }
793
794 if flags.contains(RenameFlags::EXCHANGE) {
801 fs.exchange(current_task, &mut state, old_basename, new_basename)?;
802 } else {
803 fs.rename(current_task, &mut state, old_basename, new_basename)?;
804 }
805
806 renamed.set_parent(new_parent.clone());
809 renamed.local_name.update(new_basename.to_owned());
810
811 state
815 .new_parent_children()
816 .children
817 .insert(new_basename.into(), Arc::downgrade(&renamed));
818
819 unsafe {
828 renamed.children.reset_dependencies();
829 renamed.node.info_lock().reset_dependencies();
830 old_parent.children.reset_dependencies();
831 old_parent.node.info_lock().reset_dependencies();
832 new_parent.children.reset_dependencies();
833 new_parent.node.info_lock().reset_dependencies();
834 }
835
836 if flags.contains(RenameFlags::EXCHANGE) {
837 let replaced =
839 maybe_replaced.as_ref().expect("replaced expected with RENAME_EXCHANGE");
840 replaced.set_parent(old_parent.clone());
841 replaced.local_name.update(old_basename.to_owned());
842 state
843 .old_parent_children()
844 .children
845 .insert(old_basename.into(), Arc::downgrade(replaced));
846
847 unsafe {
851 replaced.children.reset_dependencies();
852 replaced.node.info_lock().reset_dependencies();
853 }
854 } else {
855 state.old_parent_children().children.remove(old_basename);
857 }
858 };
859
860 fs.purge_old_entries();
861
862 if let Some(replaced) = maybe_replaced {
863 if !flags.contains(RenameFlags::EXCHANGE) {
864 replaced.destroy(¤t_task.kernel().mounts);
865 }
866 }
867
868 renamed.node.update_ctime();
870
871 let mode = renamed.node.info().mode;
872 if let Some(hook) =
873 current_task.kernel().expando.peek::<Arc<dyn inotify_hook::NotifyHook>>()
874 {
875 let cookie = hook.get_next_cookie();
876 old_parent.node.notify(InotifyMask::MOVE_FROM, cookie, old_basename, mode, false);
877 new_parent.node.notify(InotifyMask::MOVE_TO, cookie, new_basename, mode, false);
878 renamed.node.notify(InotifyMask::MOVE_SELF, 0, Default::default(), mode, false);
879 }
880
881 Ok(())
882 }
883
884 pub fn get_children<F, T>(&self, callback: F) -> T
885 where
886 F: FnOnce(&DirEntryChildren) -> T,
887 {
888 let children = self.children.read();
889 callback(&children)
890 }
891
892 pub fn remove_child(&self, name: &FsStr, mounts: &Mounts) {
895 let mut children = self.children.write();
896 let child = children.get(name).and_then(Weak::upgrade);
897 if let Some(child) = child {
898 children.remove(name);
899 std::mem::drop(children);
900 child.destroy(mounts);
901 }
902 }
903
904 fn get_or_create_child(
905 self: &DirEntryHandle,
906 current_task: &CurrentTask,
907 mount: &MountInfo,
908 name: &FsStr,
909 create_fn: impl FnOnce(&FsNodeHandle, &MountInfo, &FsStr) -> Result<FsNodeHandle, Errno>,
910 ) -> Result<(DirEntryHandle, bool), Errno> {
911 assert!(!DirEntry::is_reserved_name(name));
912 if !self.node.is_dir() {
914 return error!(ENOTDIR);
915 }
916 self.node.check_access(
918 current_task,
919 mount,
920 Access::EXEC,
921 CheckAccessReason::InternalPermissionChecks,
922 self,
923 )?;
924
925 let child = self.children.read().get(name).and_then(Weak::upgrade);
928 let (child, create_result) = if let Some(child) = child {
929 if self.node.fail_if_locked(current_task, &self.node.info()).is_ok() {
931 child.node.fs().did_access_dir_entry(&child);
932 }
933 (child, CreationResult::Existed { create_fn })
934 } else {
935 let (child, create_result) =
936 self.lock_children().get_or_create_child(current_task, mount, name, create_fn)?;
937 child.node.fs().purge_old_entries();
938 (child, create_result)
939 };
940
941 let (child, exists) = match create_result {
942 CreationResult::Created => (child, false),
943 CreationResult::Existed { create_fn } => {
944 if child.ops.revalidate(current_task, &child)? {
945 (child, true)
946 } else {
947 self.internal_remove_child(&child);
948 child.destroy(¤t_task.kernel().mounts);
949
950 let (child, create_result) = self.lock_children().get_or_create_child(
951 current_task,
952 mount,
953 name,
954 create_fn,
955 )?;
956 child.node.fs().purge_old_entries();
957 (child, matches!(create_result, CreationResult::Existed { .. }))
958 }
959 }
960 };
961
962 Ok((child, exists))
963 }
964
965 #[cfg(test)]
973 pub fn copy_child_names(&self) -> Vec<FsString> {
974 let scope = RcuReadScope::new();
975 self.children
976 .read()
977 .values()
978 .filter_map(|child| Weak::upgrade(child).map(|c| c.local_name.read(&scope).to_owned()))
979 .collect()
980 }
981
982 fn internal_remove_child(&self, child: &DirEntry) {
983 let mut children = self.children.write();
984 let scope = RcuReadScope::new();
985 let local_name = child.local_name.read(&scope);
986 if let Some(weak_child) = children.get(local_name) {
987 if std::ptr::eq(weak_child.as_ptr(), child) {
991 children.remove(local_name);
992 }
993 }
994 }
995
996 pub fn notify(&self, event_mask: InotifyMask) {
998 self.notify_watchers(event_mask, self.is_dead());
999 }
1000
1001 pub fn notify_ignoring_excl_unlink(&self, event_mask: InotifyMask) {
1005 self.notify_watchers(event_mask, false);
1007 }
1008
1009 fn notify_watchers(&self, event_mask: InotifyMask, is_dead: bool) {
1010 let mode = self.node.info().mode;
1011 {
1012 let scope = RcuReadScope::new();
1013 if let Some(parent) = self.parent_ref(&scope) {
1014 let local_name = self.local_name.read(&scope);
1015 parent.node.notify(event_mask, 0, local_name, mode, is_dead);
1016 }
1017 }
1018 self.node.notify(event_mask, 0, Default::default(), mode, is_dead);
1019 }
1020
1021 fn notify_creation(&self) {
1023 let mode = self.node.info().mode;
1024 if Arc::strong_count(&self.node) > 1 {
1025 self.node.notify(InotifyMask::ATTRIB, 0, Default::default(), mode, false);
1027 }
1028 let scope = RcuReadScope::new();
1029 if let Some(parent) = self.parent_ref(&scope) {
1030 let local_name = self.local_name.read(&scope);
1031 parent.node.notify(InotifyMask::CREATE, 0, local_name, mode, false);
1032 }
1033 }
1034
1035 fn notify_deletion(&self) {
1039 let mode = self.node.info().mode;
1040 if !mode.is_dir() {
1041 self.node.notify(InotifyMask::ATTRIB, 0, Default::default(), mode, false);
1043 }
1044
1045 if Arc::strong_count(&self.node) == 1 {
1048 self.node.notify(InotifyMask::DELETE_SELF, 0, Default::default(), mode, false);
1049 }
1050
1051 let scope = RcuReadScope::new();
1052 if let Some(parent) = self.parent_ref(&scope) {
1053 let local_name = self.local_name.read(&scope);
1054 parent.node.notify(InotifyMask::DELETE, 0, local_name, mode, false);
1055 }
1056 }
1057
1058 pub fn has_mounts(&self) -> bool {
1060 self.flags().contains(DirEntryFlags::HAS_MOUNTS)
1061 }
1062
1063 pub fn set_has_mounts(&self, v: bool) {
1065 if v {
1066 self.raise_flags(DirEntryFlags::HAS_MOUNTS);
1067 } else {
1068 self.lower_flags(DirEntryFlags::HAS_MOUNTS);
1069 }
1070 }
1071
1072 fn require_no_mounts(self: &Arc<Self>, parent_mount: &MountInfo) -> Result<(), Errno> {
1074 if self.has_mounts() {
1075 if let Some(mount) = parent_mount.as_ref() {
1076 if mount.has_submount(self) {
1077 return error!(EBUSY);
1078 }
1079 }
1080 }
1081 Ok(())
1082 }
1083}
1084
1085struct DirEntryLockedChildren<'a> {
1086 entry: &'a DirEntryHandle,
1087 children: LockDepWriteGuard<'a, DirEntryChildren>,
1088}
1089
1090enum CreationResult<F> {
1091 Created,
1092 Existed { create_fn: F },
1093}
1094
1095impl<'a> DirEntryLockedChildren<'a> {
1096 fn component_lookup(
1097 &mut self,
1098 current_task: &CurrentTask,
1099 mount: &MountInfo,
1100 name: &FsStr,
1101 ) -> Result<DirEntryHandle, Errno> {
1102 assert!(!DirEntry::is_reserved_name(name));
1103 let (node, _) =
1104 self.get_or_create_child(current_task, mount, name, |_, _, _| error!(ENOENT))?;
1105 Ok(node)
1106 }
1107
1108 fn get_or_create_child<
1109 F: FnOnce(&FsNodeHandle, &MountInfo, &FsStr) -> Result<FsNodeHandle, Errno>,
1110 >(
1111 &mut self,
1112 current_task: &CurrentTask,
1113 mount: &MountInfo,
1114 name: &FsStr,
1115 create_fn: F,
1116 ) -> Result<(DirEntryHandle, CreationResult<F>), Errno> {
1117 let create_child = |create_fn: F| {
1118 let (node, create_result) = match self.entry.node.lookup(current_task, mount, name) {
1120 Ok(node) => (node, CreationResult::Existed { create_fn }),
1121 Err(e) if e == ENOENT => {
1122 (create_fn(&self.entry.node, mount, name)?, CreationResult::Created)
1123 }
1124 Err(e) => return Err(e),
1125 };
1126
1127 assert!(
1128 node.info().mode & FileMode::IFMT != FileMode::EMPTY,
1129 "FsNode initialization did not populate the FileMode in FsNodeInfo."
1130 );
1131
1132 let entry = DirEntry::new(node, Some(self.entry.clone()), name.to_owned());
1133
1134 if let Err(err) = security::fs_node_init_with_dentry(current_task, &entry) {
1135 entry.parent.update(None);
1138 return Err(err);
1139 }
1140
1141 Ok((entry, create_result))
1142 };
1143
1144 let (child, create_result) = match self.children.entry(name.to_owned()) {
1145 Entry::Vacant(entry) => {
1146 let (child, create_result) = create_child(create_fn)?;
1147 if self.entry.node.fail_if_locked(current_task, &self.entry.node.info()).is_ok() {
1149 entry.insert(Arc::downgrade(&child));
1150 }
1151 (child, create_result)
1152 }
1153 Entry::Occupied(mut entry) => {
1154 if let Some(child) = Weak::upgrade(entry.get()) {
1158 if self.entry.node.fail_if_locked(current_task, &self.entry.node.info()).is_ok()
1160 {
1161 child.node.fs().did_access_dir_entry(&child);
1162 }
1163 return Ok((child, CreationResult::Existed { create_fn }));
1164 }
1165 let (child, create_result) = create_child(create_fn)?;
1166 if self.entry.node.fail_if_locked(current_task, &self.entry.node.info()).is_ok() {
1168 entry.insert(Arc::downgrade(&child));
1169 }
1170 (child, create_result)
1171 }
1172 };
1173
1174 Ok((child, create_result))
1175 }
1176}
1177
1178impl fmt::Debug for DirEntry {
1179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1180 let scope = RcuReadScope::new();
1181 let mut parents = vec![];
1182 let mut maybe_parent = self.parent_ref(&scope);
1183 while let Some(parent) = maybe_parent {
1184 parents.push(parent.local_name.read(&scope));
1185 maybe_parent = parent.parent_ref(&scope);
1186 }
1187 let mut builder = f.debug_struct("DirEntry");
1188 builder.field("id", &(self as *const DirEntry));
1189 builder.field("local_name", &self.local_name.read(&scope).to_owned());
1190 if !parents.is_empty() {
1191 builder.field("parents", &parents);
1192 }
1193 builder.finish()
1194 }
1195}
1196
1197#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1198enum RenameRelationship {
1199 Same,
1200 NewIsDescendant,
1201 OldIsDescendant,
1202 Independent,
1203}
1204
1205struct RenameGuard<'a> {
1206 old_parent_guard: DirEntryLockedChildren<'a>,
1207 new_parent_guard: Option<DirEntryLockedChildren<'a>>,
1208 relationship: RenameRelationship,
1209}
1210
1211impl<'a> RenameGuard<'a> {
1212 fn lock(old_parent: &'a DirEntryHandle, new_parent: &'a DirEntryHandle) -> Self {
1213 if Arc::ptr_eq(old_parent, new_parent) {
1214 let old_parent_guard = old_parent.lock_children();
1215 Self {
1216 old_parent_guard,
1217 new_parent_guard: None,
1218 relationship: RenameRelationship::Same,
1219 }
1220 } else if new_parent.is_descendant_of(old_parent) {
1221 let old_parent_guard = old_parent.lock_children();
1222 let _token = allow_subclass();
1223 let new_parent_guard = new_parent.lock_children();
1224 Self {
1225 old_parent_guard,
1226 new_parent_guard: Some(new_parent_guard),
1227 relationship: RenameRelationship::NewIsDescendant,
1228 }
1229 } else if old_parent.is_descendant_of(new_parent) {
1230 let new_parent_guard = new_parent.lock_children();
1231 let _token = allow_subclass();
1232 let old_parent_guard = old_parent.lock_children();
1233 Self {
1234 old_parent_guard,
1235 new_parent_guard: Some(new_parent_guard),
1236 relationship: RenameRelationship::OldIsDescendant,
1237 }
1238 } else {
1239 let (g1, g2) =
1241 starnix_sync::ordered_write_lock(&old_parent.children, &new_parent.children);
1242 let old_parent_guard = DirEntryLockedChildren { entry: old_parent, children: g1 };
1243 let new_parent_guard = DirEntryLockedChildren { entry: new_parent, children: g2 };
1244 Self {
1245 old_parent_guard,
1246 new_parent_guard: Some(new_parent_guard),
1247 relationship: RenameRelationship::Independent,
1248 }
1249 }
1250 }
1251
1252 fn lock_info(
1256 self,
1257 old_parent: &'a DirEntryHandle,
1258 new_parent: &'a DirEntryHandle,
1259 renamed: &'a DirEntryHandle,
1260 replaced: Option<&'a DirEntryHandle>,
1261 ) -> RenameContext<'a> {
1262 let (g1, g2) = match self.relationship {
1263 RenameRelationship::Same => (old_parent.node.info_lock().write(), None),
1264 RenameRelationship::NewIsDescendant => {
1265 let g1 = old_parent.node.info_lock().write();
1266 let _token = allow_subclass();
1267 let g2 = new_parent.node.info_lock().write();
1268 (g1, Some(g2))
1269 }
1270 RenameRelationship::OldIsDescendant => {
1271 let g2 = new_parent.node.info_lock().write();
1272 let _token = allow_subclass();
1273 let g1 = old_parent.node.info_lock().write();
1274 (g1, Some(g2))
1275 }
1276 RenameRelationship::Independent => {
1277 let (g1, g2) = starnix_sync::ordered_write_lock(
1278 old_parent.node.info_lock(),
1279 new_parent.node.info_lock(),
1280 );
1281 (g1, Some(g2))
1282 }
1283 };
1284
1285 RenameContext {
1286 renamed,
1287 replaced,
1288 old_parent_guard: self.old_parent_guard,
1289 new_parent_guard: self.new_parent_guard,
1290 old_parent_info_guard: g1,
1291 new_parent_info_guard: g2,
1292 }
1293 }
1294
1295 fn old_parent_children(&mut self) -> &mut DirEntryLockedChildren<'a> {
1296 &mut self.old_parent_guard
1297 }
1298
1299 fn new_parent_children(&mut self) -> &mut DirEntryLockedChildren<'a> {
1300 if let Some(new_guard) = self.new_parent_guard.as_mut() {
1301 new_guard
1302 } else {
1303 &mut self.old_parent_guard
1304 }
1305 }
1306}
1307
1308pub struct RenameContext<'a> {
1321 pub renamed: &'a DirEntryHandle,
1322 pub replaced: Option<&'a DirEntryHandle>,
1323 old_parent_guard: DirEntryLockedChildren<'a>,
1324 new_parent_guard: Option<DirEntryLockedChildren<'a>>,
1325 old_parent_info_guard: LockDepWriteGuard<'a, crate::vfs::FsNodeInfo>,
1326 new_parent_info_guard: Option<LockDepWriteGuard<'a, crate::vfs::FsNodeInfo>>,
1327}
1328
1329impl<'a> RenameContext<'a> {
1330 pub fn renamed_is_dir(&self) -> bool {
1337 self.is_dir(&self.renamed.node)
1338 }
1339
1340 pub fn replaced_is_dir(&self) -> bool {
1349 self.replaced.map(|r| self.is_dir(&r.node)).unwrap_or(false)
1350 }
1351
1352 pub fn old_parent(&self) -> &DirEntryHandle {
1357 self.old_parent_guard.entry
1358 }
1359
1360 pub fn new_parent(&self) -> &DirEntryHandle {
1365 self.new_parent_guard.as_ref().map(|g| g.entry).unwrap_or(self.old_parent_guard.entry)
1366 }
1367
1368 pub fn parent_infos_mut(
1377 &mut self,
1378 ) -> (&mut crate::vfs::FsNodeInfo, Option<&mut crate::vfs::FsNodeInfo>) {
1379 let old = &mut *self.old_parent_info_guard;
1380 let new = self.new_parent_info_guard.as_mut().map(|g| &mut **g);
1381 (old, new)
1382 }
1383
1384 pub fn old_parent_info(&self) -> &crate::vfs::FsNodeInfo {
1387 &self.old_parent_info_guard
1388 }
1389 pub fn new_parent_info(&self) -> Option<&crate::vfs::FsNodeInfo> {
1394 self.new_parent_info_guard.as_deref()
1395 }
1396
1397 fn new_parent_children(&mut self) -> &mut DirEntryLockedChildren<'a> {
1398 self.new_parent_guard.as_mut().unwrap_or(&mut self.old_parent_guard)
1399 }
1400
1401 fn old_parent_children(&mut self) -> &mut DirEntryLockedChildren<'a> {
1402 &mut self.old_parent_guard
1403 }
1404
1405 fn is_dir(&self, node: &FsNodeHandle) -> bool {
1406 if Arc::ptr_eq(node, &self.old_parent().node) {
1407 self.old_parent_info_guard.mode.is_dir()
1408 } else if Arc::ptr_eq(node, &self.new_parent().node) {
1409 self.new_parent_info_guard
1410 .as_ref()
1411 .map(|g| g.mode.is_dir())
1412 .unwrap_or_else(|| self.old_parent_info_guard.mode.is_dir())
1413 } else {
1414 let _token = allow_subclass();
1415 node.is_dir()
1416 }
1417 }
1418}
1419
1420impl Drop for DirEntry {
1424 fn drop(&mut self) {
1425 let maybe_parent = self.parent();
1426 self.parent.update(None);
1427 if let Some(parent) = maybe_parent {
1428 parent.internal_remove_child(self);
1429 }
1430 }
1431}