1use crate::mutable_state::{state_accessor, state_implementation};
6use crate::security;
7use crate::task::CurrentTask;
8use crate::vfs::{
9 CheckAccessReason, FileHandle, FileObject, FsNodeHandle, FsNodeLinkBehavior, FsStr, FsString,
10 MountInfo, Mounts, NamespaceNode, UnlinkKind, path,
11};
12use bitflags::bitflags;
13use macro_rules_attribute::apply;
14use starnix_sync::{FileOpsCore, LockEqualOrBefore, Locked, RwLock, RwLockWriteGuard};
15use starnix_uapi::auth::FsCred;
16use starnix_uapi::errors::{ENOENT, Errno};
17use starnix_uapi::file_mode::{Access, FileMode};
18use starnix_uapi::inotify_mask::InotifyMask;
19use starnix_uapi::open_flags::OpenFlags;
20use starnix_uapi::{NAME_MAX, RENAME_EXCHANGE, RENAME_NOREPLACE, RENAME_WHITEOUT, errno, error};
21use std::collections::BTreeMap;
22use std::collections::btree_map::Entry;
23use std::fmt;
24use std::ops::Deref;
25use std::sync::{Arc, Weak};
26#[cfg(detect_lock_cycles)]
27use tracing_mutex::util;
28
29bitflags! {
30 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
31 pub struct RenameFlags: u32 {
32 const EXCHANGE = RENAME_EXCHANGE;
34
35 const NOREPLACE = RENAME_NOREPLACE;
37
38 const WHITEOUT = RENAME_WHITEOUT;
40
41 const REPLACE_ANY = 0x80000000;
44
45 const INTERNAL = Self::REPLACE_ANY.bits();
47 }
48}
49
50pub struct DirEntryState {
51 parent: Option<DirEntryHandle>,
58
59 local_name: FsString,
68
69 is_dead: bool,
71
72 has_mounts: bool,
74}
75
76#[apply(state_implementation!)]
77impl DirEntryState<Base = DirEntry> {
78 pub fn local_name(&self) -> &FsStr {
79 self.local_name.as_ref()
80 }
81
82 pub fn parent(&self) -> &Option<DirEntryHandle> {
83 &self.parent
84 }
85
86 pub fn is_dead(&self) -> bool {
88 self.is_dead
89 }
90}
91
92pub trait DirEntryOps: Send + Sync + 'static {
93 fn revalidate(
110 &self,
111 _locked: &mut Locked<FileOpsCore>,
112 _: &CurrentTask,
113 _: &DirEntry,
114 ) -> Result<bool, Errno> {
115 Ok(true)
116 }
117}
118
119pub struct DefaultDirEntryOps;
120
121impl DirEntryOps for DefaultDirEntryOps {}
122
123pub struct DirEntry {
135 pub node: FsNodeHandle,
140
141 ops: Box<dyn DirEntryOps>,
146
147 state: RwLock<DirEntryState>,
151
152 children: RwLock<DirEntryChildren>,
165}
166type DirEntryChildren = BTreeMap<FsString, Weak<DirEntry>>;
167
168pub type DirEntryHandle = Arc<DirEntry>;
169
170impl DirEntry {
171 state_accessor!(DirEntry, state);
172
173 #[allow(clippy::let_and_return)]
174 pub fn new_uncached(
175 node: FsNodeHandle,
176 parent: Option<DirEntryHandle>,
177 local_name: FsString,
178 ) -> DirEntryHandle {
179 let ops = node.create_dir_entry_ops();
180 let result = Arc::new(DirEntry {
181 node,
182 ops,
183 state: RwLock::new(DirEntryState {
184 parent,
185 local_name,
186 is_dead: false,
187 has_mounts: false,
188 }),
189 children: Default::default(),
190 });
191 #[cfg(any(test, debug_assertions))]
192 {
193 let _l1 = result.children.read();
194 let _l2 = result.state.read();
195 }
196 result
197 }
198
199 pub fn new(
200 node: FsNodeHandle,
201 parent: Option<DirEntryHandle>,
202 local_name: FsString,
203 ) -> DirEntryHandle {
204 let result = Self::new_uncached(node, parent, local_name);
205 result.node.fs().did_create_dir_entry(&result);
206 result
207 }
208
209 pub fn new_unrooted(node: FsNodeHandle) -> DirEntryHandle {
212 Self::new_uncached(node, None, FsString::default())
213 }
214
215 pub fn new_deleted(
217 node: FsNodeHandle,
218 parent: Option<DirEntryHandle>,
219 local_name: FsString,
220 ) -> DirEntryHandle {
221 let entry = DirEntry::new_uncached(node, parent, local_name);
222 entry.state.write().is_dead = true;
223 entry
224 }
225
226 pub fn open_anonymous<L>(
228 self: &DirEntryHandle,
229 locked: &mut Locked<L>,
230 current_task: &CurrentTask,
231 flags: OpenFlags,
232 ) -> Result<FileHandle, Errno>
233 where
234 L: LockEqualOrBefore<FileOpsCore>,
235 {
236 let ops = self.node.create_file_ops(locked, current_task, flags)?;
237 FileObject::new(
238 locked,
239 current_task,
240 ops,
241 NamespaceNode::new_anonymous(self.clone()),
242 flags,
243 )
244 }
245
246 pub fn set_children(self: &DirEntryHandle, children: BTreeMap<FsString, DirEntryHandle>) {
249 let mut dir_entry_children = self.lock_children();
250 assert!(dir_entry_children.children.is_empty());
251 for (name, child) in children.into_iter() {
252 let mut state = child.state.write();
253 state.parent = Some(self.clone());
254 dir_entry_children.children.insert(name, Arc::downgrade(&child));
255 }
256 }
257
258 fn lock_children<'a>(self: &'a DirEntryHandle) -> DirEntryLockedChildren<'a> {
259 DirEntryLockedChildren { entry: self, children: self.children.write() }
260 }
261
262 pub fn parent_or_self(self: &DirEntryHandle) -> DirEntryHandle {
272 self.read().parent().as_ref().unwrap_or(self).clone()
273 }
274
275 pub fn is_reserved_name(name: &FsStr) -> bool {
280 name.is_empty() || name == "." || name == ".."
281 }
282
283 pub fn component_lookup<L>(
286 self: &DirEntryHandle,
287 locked: &mut Locked<L>,
288 current_task: &CurrentTask,
289 mount: &MountInfo,
290 name: &FsStr,
291 ) -> Result<DirEntryHandle, Errno>
292 where
293 L: LockEqualOrBefore<FileOpsCore>,
294 {
295 let (node, _) = self.get_or_create_child(
296 locked,
297 current_task,
298 mount,
299 name,
300 |locked, d, mount, name| d.lookup(locked, current_task, mount, name),
301 )?;
302 Ok(node)
303 }
304
305 pub fn create_entry<L>(
313 self: &DirEntryHandle,
314 locked: &mut Locked<L>,
315 current_task: &CurrentTask,
316 mount: &MountInfo,
317 name: &FsStr,
318 create_node_fn: impl FnOnce(
319 &mut Locked<L>,
320 &FsNodeHandle,
321 &MountInfo,
322 &FsStr,
323 ) -> Result<FsNodeHandle, Errno>,
324 ) -> Result<DirEntryHandle, Errno>
325 where
326 L: LockEqualOrBefore<FileOpsCore>,
327 {
328 let (entry, exists) =
329 self.create_entry_internal(locked, current_task, mount, name, create_node_fn)?;
330 if exists {
331 return error!(EEXIST);
332 }
333 Ok(entry)
334 }
335
336 pub fn get_or_create_entry<L>(
339 self: &DirEntryHandle,
340 locked: &mut Locked<L>,
341 current_task: &CurrentTask,
342 mount: &MountInfo,
343 name: &FsStr,
344 create_node_fn: impl FnOnce(
345 &mut Locked<L>,
346 &FsNodeHandle,
347 &MountInfo,
348 &FsStr,
349 ) -> Result<FsNodeHandle, Errno>,
350 ) -> Result<DirEntryHandle, Errno>
351 where
352 L: LockEqualOrBefore<FileOpsCore>,
353 {
354 let (entry, _exists) =
355 self.create_entry_internal(locked, current_task, mount, name, create_node_fn)?;
356 Ok(entry)
357 }
358
359 fn create_entry_internal<L>(
360 self: &DirEntryHandle,
361 locked: &mut Locked<L>,
362 current_task: &CurrentTask,
363 mount: &MountInfo,
364 name: &FsStr,
365 create_node_fn: impl FnOnce(
366 &mut Locked<L>,
367 &FsNodeHandle,
368 &MountInfo,
369 &FsStr,
370 ) -> Result<FsNodeHandle, Errno>,
371 ) -> Result<(DirEntryHandle, bool), Errno>
372 where
373 L: LockEqualOrBefore<FileOpsCore>,
374 {
375 if DirEntry::is_reserved_name(name) {
376 return error!(EEXIST);
377 }
378 if name.len() > NAME_MAX as usize {
380 return error!(ENAMETOOLONG);
381 }
382 if name.contains(&path::SEPARATOR) {
383 return error!(EINVAL);
384 }
385 let (entry, exists) =
386 self.get_or_create_child(locked, current_task, mount, name, create_node_fn)?;
387 if !exists {
388 self.node.update_ctime_mtime();
390 entry.notify_creation();
391 }
392 Ok((entry, exists))
393 }
394
395 #[cfg(test)]
398 pub fn create_dir<L>(
399 self: &DirEntryHandle,
400 locked: &mut starnix_sync::Locked<L>,
401 current_task: &CurrentTask,
402 name: &FsStr,
403 ) -> Result<DirEntryHandle, Errno>
404 where
405 L: LockEqualOrBefore<FileOpsCore>,
406 {
407 self.create_dir_for_testing(locked, current_task, name)
408 }
409
410 pub fn create_dir_for_testing<L>(
413 self: &DirEntryHandle,
414 locked: &mut Locked<L>,
415 current_task: &CurrentTask,
416 name: &FsStr,
417 ) -> Result<DirEntryHandle, Errno>
418 where
419 L: LockEqualOrBefore<FileOpsCore>,
420 {
421 self.create_entry(
423 locked,
424 current_task,
425 &MountInfo::detached(),
426 name,
427 |locked, dir, mount, name| {
428 dir.create_node(
429 locked,
430 current_task,
431 mount,
432 name,
433 starnix_uapi::file_mode::mode!(IFDIR, 0o777),
434 starnix_uapi::device_type::DeviceType::NONE,
435 FsCred::root(),
436 )
437 },
438 )
439 }
440
441 pub fn create_tmpfile<L>(
447 self: &DirEntryHandle,
448 locked: &mut Locked<L>,
449 current_task: &CurrentTask,
450 mount: &MountInfo,
451 mode: FileMode,
452 owner: FsCred,
453 flags: OpenFlags,
454 ) -> Result<DirEntryHandle, Errno>
455 where
456 L: LockEqualOrBefore<FileOpsCore>,
457 {
458 if !self.node.is_dir() {
460 return error!(ENOTDIR);
461 }
462 assert!(mode.is_reg());
463
464 let link_behavior = if flags.contains(OpenFlags::EXCL) {
472 FsNodeLinkBehavior::Disallowed
473 } else {
474 FsNodeLinkBehavior::Allowed
475 };
476
477 let node =
478 self.node.create_tmpfile(locked, current_task, mount, mode, owner, link_behavior)?;
479 let local_name = format!("#{}", node.ino).into();
480 Ok(DirEntry::new_deleted(node, Some(self.clone()), local_name))
481 }
482
483 pub fn unlink<L>(
484 self: &DirEntryHandle,
485 locked: &mut Locked<L>,
486 current_task: &CurrentTask,
487 mount: &MountInfo,
488 name: &FsStr,
489 kind: UnlinkKind,
490 must_be_directory: bool,
491 ) -> Result<(), Errno>
492 where
493 L: LockEqualOrBefore<FileOpsCore>,
494 {
495 assert!(!DirEntry::is_reserved_name(name));
496
497 let child_to_unlink;
499
500 let mut self_children = self.lock_children();
501 child_to_unlink = self_children.component_lookup(locked, current_task, mount, name)?;
502 child_to_unlink.require_no_mounts(mount)?;
503
504 if must_be_directory && !child_to_unlink.node.is_dir() {
511 return error!(ENOTDIR);
512 }
513
514 match kind {
515 UnlinkKind::Directory => {
516 if !child_to_unlink.node.is_dir() {
517 return error!(ENOTDIR);
518 }
519 }
520 UnlinkKind::NonDirectory => {
521 if child_to_unlink.node.is_dir() {
522 return error!(EISDIR);
523 }
524 }
525 }
526
527 self.node.unlink(locked, current_task, mount, name, &child_to_unlink.node)?;
528 self_children.children.remove(name);
529
530 std::mem::drop(self_children);
531 child_to_unlink.destroy(¤t_task.kernel().mounts);
532
533 Ok(())
534 }
535
536 fn destroy(self: DirEntryHandle, mounts: &Mounts) {
540 let unmount = {
541 let mut state = self.state.write();
542 if state.is_dead {
543 return;
544 }
545 state.is_dead = true;
546 std::mem::replace(&mut state.has_mounts, false)
547 };
548 self.node.fs().will_destroy_dir_entry(&self);
549 if unmount {
550 mounts.unmount(&self);
551 }
552 self.notify_deletion();
553 }
554
555 pub fn is_descendant_of(self: &DirEntryHandle, other: &DirEntryHandle) -> bool {
557 let mut current = self.clone();
558 loop {
559 if Arc::ptr_eq(¤t, other) {
560 return true;
562 }
563 let parent = current.read().parent().clone();
564 if let Some(next) = parent {
565 current = next;
566 } else {
567 return false;
569 }
570 }
571 }
572
573 pub fn rename<L>(
578 locked: &mut Locked<L>,
579 current_task: &CurrentTask,
580 old_parent: &DirEntryHandle,
581 old_mount: &MountInfo,
582 old_basename: &FsStr,
583 new_parent: &DirEntryHandle,
584 new_mount: &MountInfo,
585 new_basename: &FsStr,
586 flags: RenameFlags,
587 ) -> Result<(), Errno>
588 where
589 L: LockEqualOrBefore<FileOpsCore>,
590 {
591 if old_mount != new_mount {
593 return error!(EXDEV);
594 }
595 let mount = old_mount;
597
598 if DirEntry::is_reserved_name(old_basename) || DirEntry::is_reserved_name(new_basename) {
601 if flags.contains(RenameFlags::NOREPLACE) {
602 return error!(EEXIST);
603 }
604 return error!(EBUSY);
605 }
606
607 if Arc::ptr_eq(&old_parent.node, &new_parent.node) && old_basename == new_basename {
610 return Ok(());
611 }
612
613 old_parent.node.check_access(
615 locked,
616 current_task,
617 mount,
618 Access::WRITE,
619 CheckAccessReason::InternalPermissionChecks,
620 old_parent,
621 )?;
622 new_parent.node.check_access(
623 locked,
624 current_task,
625 mount,
626 Access::WRITE,
627 CheckAccessReason::InternalPermissionChecks,
628 new_parent,
629 )?;
630
631 let fs = old_parent.node.fs();
634
635 let renamed;
638 let mut maybe_replaced = None;
639
640 {
641 let _lock = fs.rename_mutex.lock();
651
652 let mut new_parent_ancestor_list = Vec::<DirEntryHandle>::new();
656 {
657 let mut current = Some(new_parent.clone());
658 while let Some(entry) = current {
659 current = entry.read().parent().clone();
660 new_parent_ancestor_list.push(entry);
661 }
662 }
663
664 let mut state = RenameGuard::lock(old_parent, new_parent);
669
670 renamed =
673 state.old_parent().component_lookup(locked, current_task, mount, old_basename)?;
674
675 old_parent.node.check_sticky_bit(current_task, &renamed.node)?;
678
679 if new_parent_ancestor_list.into_iter().any(|entry| Arc::ptr_eq(&entry, &renamed)) {
682 return error!(EINVAL);
683 }
684
685 renamed.require_no_mounts(mount)?;
690
691 match state.new_parent().component_lookup(locked, current_task, mount, new_basename) {
695 Ok(replaced) => {
696 let replaced = maybe_replaced.insert(replaced);
698
699 if flags.contains(RenameFlags::NOREPLACE) {
700 return error!(EEXIST);
701 }
702
703 if Arc::ptr_eq(&renamed.node, &replaced.node) {
709 return Ok(());
710 }
711
712 if replaced.node.is_dir() {
717 replaced.require_no_mounts(mount)?;
722 }
723
724 if !flags.intersects(RenameFlags::EXCHANGE | RenameFlags::REPLACE_ANY) {
725 if renamed.node.is_dir() && !replaced.node.is_dir() {
726 return error!(ENOTDIR);
727 } else if !renamed.node.is_dir() && replaced.node.is_dir() {
728 return error!(EISDIR);
729 }
730 }
731 }
732 Err(errno) if errno == ENOENT => {}
734 Err(e) => return Err(e),
736 }
737
738 security::check_fs_node_rename_access(
739 current_task,
740 &old_parent.node,
741 &renamed.node,
742 &new_parent.node,
743 maybe_replaced.as_ref().map(|dir_entry| dir_entry.node.deref().as_ref()),
744 old_basename,
745 new_basename,
746 )?;
747
748 if flags.contains(RenameFlags::EXCHANGE) {
755 let replaced = maybe_replaced.as_ref().ok_or_else(|| errno!(ENOENT))?;
756 fs.exchange(
757 current_task,
758 &renamed.node,
759 &old_parent.node,
760 old_basename,
761 &replaced.node,
762 &new_parent.node,
763 new_basename,
764 )?;
765 } else {
766 fs.rename(
767 locked,
768 current_task,
769 &old_parent.node,
770 old_basename,
771 &new_parent.node,
772 new_basename,
773 &renamed.node,
774 maybe_replaced.as_ref().map(|replaced| &replaced.node),
775 )?;
776 }
777
778 {
779 let mut renamed_state = renamed.state.write();
782 renamed_state.parent = Some(new_parent.clone());
783 renamed_state.local_name = new_basename.into();
784 }
785 state.new_parent().children.insert(new_basename.into(), Arc::downgrade(&renamed));
789
790 #[cfg(detect_lock_cycles)]
791 unsafe {
792 util::reset_dependencies(renamed.children.raw());
795 }
796
797 if flags.contains(RenameFlags::EXCHANGE) {
798 let replaced =
800 maybe_replaced.as_ref().expect("replaced expected with RENAME_EXCHANGE");
801 {
802 let mut replaced_state = replaced.state.write();
803 replaced_state.parent = Some(old_parent.clone());
804 replaced_state.local_name = old_basename.into();
805 }
806 state.old_parent().children.insert(old_basename.into(), Arc::downgrade(replaced));
807
808 #[cfg(detect_lock_cycles)]
809 unsafe {
810 util::reset_dependencies(replaced.children.raw());
813 }
814 } else {
815 state.old_parent().children.remove(old_basename);
817 }
818 };
819
820 fs.purge_old_entries();
821
822 if let Some(replaced) = maybe_replaced {
823 if !flags.contains(RenameFlags::EXCHANGE) {
824 replaced.destroy(¤t_task.kernel().mounts);
825 }
826 }
827
828 renamed.node.update_ctime();
830
831 let mode = renamed.node.info().mode;
832 let cookie = current_task.kernel().get_next_inotify_cookie();
833 old_parent.node.notify(InotifyMask::MOVE_FROM, cookie, old_basename, mode, false);
834 new_parent.node.notify(InotifyMask::MOVE_TO, cookie, new_basename, mode, false);
835 renamed.node.notify(InotifyMask::MOVE_SELF, 0, Default::default(), mode, false);
836
837 Ok(())
838 }
839
840 pub fn get_children<F, T>(&self, callback: F) -> T
841 where
842 F: FnOnce(&DirEntryChildren) -> T,
843 {
844 let children = self.children.read();
845 callback(&children)
846 }
847
848 pub fn remove_child(&self, name: &FsStr, mounts: &Mounts) {
851 let mut children = self.children.write();
852 let child = children.get(name).and_then(Weak::upgrade);
853 if let Some(child) = child {
854 children.remove(name);
855 std::mem::drop(children);
856 child.destroy(mounts);
857 }
858 }
859
860 fn get_or_create_child<L>(
861 self: &DirEntryHandle,
862 locked: &mut Locked<L>,
863 current_task: &CurrentTask,
864 mount: &MountInfo,
865 name: &FsStr,
866 create_fn: impl FnOnce(
867 &mut Locked<L>,
868 &FsNodeHandle,
869 &MountInfo,
870 &FsStr,
871 ) -> Result<FsNodeHandle, Errno>,
872 ) -> Result<(DirEntryHandle, bool), Errno>
873 where
874 L: LockEqualOrBefore<FileOpsCore>,
875 {
876 assert!(!DirEntry::is_reserved_name(name));
877 if !self.node.is_dir() {
879 return error!(ENOTDIR);
880 }
881 self.node.check_access(
883 locked,
884 current_task,
885 mount,
886 Access::EXEC,
887 CheckAccessReason::InternalPermissionChecks,
888 self,
889 )?;
890
891 let child = self.children.read().get(name).and_then(Weak::upgrade);
894 let (child, create_result) = if let Some(child) = child {
895 if self.node.fail_if_locked(current_task).is_ok() {
897 child.node.fs().did_access_dir_entry(&child);
898 }
899 (child, CreationResult::Existed { create_fn })
900 } else {
901 let (child, create_result) = self.lock_children().get_or_create_child(
902 locked,
903 current_task,
904 mount,
905 name,
906 create_fn,
907 )?;
908 child.node.fs().purge_old_entries();
909 (child, create_result)
910 };
911
912 let (child, exists) = match create_result {
913 CreationResult::Created => (child, false),
914 CreationResult::Existed { create_fn } => {
915 if child.ops.revalidate(
916 locked.cast_locked::<FileOpsCore>(),
917 current_task,
918 &child,
919 )? {
920 (child, true)
921 } else {
922 self.internal_remove_child(&child);
923 child.destroy(¤t_task.kernel().mounts);
924
925 let (child, create_result) = self.lock_children().get_or_create_child(
926 locked,
927 current_task,
928 mount,
929 name,
930 create_fn,
931 )?;
932 child.node.fs().purge_old_entries();
933 (child, matches!(create_result, CreationResult::Existed { .. }))
934 }
935 }
936 };
937
938 Ok((child, exists))
939 }
940
941 #[cfg(test)]
949 pub fn copy_child_names(&self) -> Vec<FsString> {
950 self.children
951 .read()
952 .values()
953 .filter_map(|child| Weak::upgrade(child).map(|c| c.read().local_name().to_owned()))
954 .collect()
955 }
956
957 fn internal_remove_child(&self, child: &DirEntry) {
958 let mut children = self.children.write();
959 let state = child.read();
960 let local_name = state.local_name();
961 if let Some(weak_child) = children.get(local_name) {
962 if std::ptr::eq(weak_child.as_ptr(), child) {
966 children.remove(local_name);
967 }
968 }
969 }
970
971 pub fn notify(&self, event_mask: InotifyMask) {
973 let is_dead = self.read().is_dead();
974 self.notify_watchers(event_mask, is_dead);
975 }
976
977 pub fn notify_ignoring_excl_unlink(&self, event_mask: InotifyMask) {
981 self.notify_watchers(event_mask, false);
983 }
984
985 fn notify_watchers(&self, event_mask: InotifyMask, is_dead: bool) {
986 let mode = self.node.info().mode;
987 {
988 let state = self.read();
989 if let Some(parent) = state.parent() {
990 parent.node.notify(event_mask, 0, state.local_name(), mode, is_dead);
991 }
992 }
993 self.node.notify(event_mask, 0, Default::default(), mode, is_dead);
994 }
995
996 fn notify_creation(&self) {
998 let mode = self.node.info().mode;
999 if Arc::strong_count(&self.node) > 1 {
1000 self.node.notify(InotifyMask::ATTRIB, 0, Default::default(), mode, false);
1002 }
1003 let state = self.read();
1004 if let Some(parent) = state.parent() {
1005 parent.node.notify(InotifyMask::CREATE, 0, state.local_name(), mode, false);
1006 }
1007 }
1008
1009 fn notify_deletion(&self) {
1013 let mode = self.node.info().mode;
1014 if !mode.is_dir() {
1015 self.node.notify(InotifyMask::ATTRIB, 0, Default::default(), mode, false);
1017 }
1018
1019 let state = self.read();
1020 if let Some(parent) = state.parent() {
1021 parent.node.notify(InotifyMask::DELETE, 0, state.local_name(), mode, false);
1022 }
1023
1024 if Arc::strong_count(&self.node) == 1 {
1027 self.node.notify(InotifyMask::DELETE_SELF, 0, Default::default(), mode, false);
1028 }
1029 }
1030
1031 pub fn has_mounts(&self) -> bool {
1033 self.state.read().has_mounts
1034 }
1035
1036 pub fn set_has_mounts(&self, v: bool) {
1038 self.state.write().has_mounts = v;
1039 }
1040
1041 fn require_no_mounts(self: &Arc<Self>, parent_mount: &MountInfo) -> Result<(), Errno> {
1043 if self.state.read().has_mounts {
1044 if let Some(mount) = parent_mount.as_ref() {
1045 if mount.has_submount(self) {
1046 return error!(EBUSY);
1047 }
1048 }
1049 }
1050 Ok(())
1051 }
1052}
1053
1054struct DirEntryLockedChildren<'a> {
1055 entry: &'a DirEntryHandle,
1056 children: RwLockWriteGuard<'a, DirEntryChildren>,
1057}
1058
1059enum CreationResult<F> {
1060 Created,
1061 Existed { create_fn: F },
1062}
1063
1064impl<'a> DirEntryLockedChildren<'a> {
1065 fn component_lookup<L>(
1066 &mut self,
1067 locked: &mut Locked<L>,
1068 current_task: &CurrentTask,
1069 mount: &MountInfo,
1070 name: &FsStr,
1071 ) -> Result<DirEntryHandle, Errno>
1072 where
1073 L: LockEqualOrBefore<FileOpsCore>,
1074 {
1075 assert!(!DirEntry::is_reserved_name(name));
1076 let (node, _) =
1077 self.get_or_create_child(locked, current_task, mount, name, |_, _, _, _| {
1078 error!(ENOENT)
1079 })?;
1080 Ok(node)
1081 }
1082
1083 fn get_or_create_child<
1084 L,
1085 F: FnOnce(&mut Locked<L>, &FsNodeHandle, &MountInfo, &FsStr) -> Result<FsNodeHandle, Errno>,
1086 >(
1087 &mut self,
1088 locked: &mut Locked<L>,
1089 current_task: &CurrentTask,
1090 mount: &MountInfo,
1091 name: &FsStr,
1092 create_fn: F,
1093 ) -> Result<(DirEntryHandle, CreationResult<F>), Errno>
1094 where
1095 L: LockEqualOrBefore<FileOpsCore>,
1096 {
1097 let create_child = |locked: &mut Locked<L>, create_fn: F| {
1098 let (node, create_result) =
1100 match self.entry.node.lookup(locked, current_task, mount, name) {
1101 Ok(node) => (node, CreationResult::Existed { create_fn }),
1102 Err(e) if e == ENOENT => {
1103 (create_fn(locked, &self.entry.node, mount, name)?, CreationResult::Created)
1104 }
1105 Err(e) => return Err(e),
1106 };
1107
1108 assert!(
1109 node.info().mode & FileMode::IFMT != FileMode::EMPTY,
1110 "FsNode initialization did not populate the FileMode in FsNodeInfo."
1111 );
1112
1113 let entry = DirEntry::new(node, Some(self.entry.clone()), name.to_owned());
1114 #[cfg(any(test, debug_assertions))]
1115 {
1116 let _l1 = entry.state.read();
1119 }
1120 Ok((entry, create_result))
1121 };
1122
1123 let (child, create_result) = match self.children.entry(name.to_owned()) {
1124 Entry::Vacant(entry) => {
1125 let (child, create_result) = create_child(locked, create_fn)?;
1126 if self.entry.node.fail_if_locked(current_task).is_ok() {
1128 entry.insert(Arc::downgrade(&child));
1129 }
1130 (child, create_result)
1131 }
1132 Entry::Occupied(mut entry) => {
1133 if let Some(child) = Weak::upgrade(entry.get()) {
1137 if self.entry.node.fail_if_locked(current_task).is_ok() {
1139 child.node.fs().did_access_dir_entry(&child);
1140 }
1141 return Ok((child, CreationResult::Existed { create_fn }));
1142 }
1143 let (child, create_result) = create_child(locked, create_fn)?;
1144 if self.entry.node.fail_if_locked(current_task).is_ok() {
1146 entry.insert(Arc::downgrade(&child));
1147 }
1148 (child, create_result)
1149 }
1150 };
1151
1152 security::fs_node_init_with_dentry(locked, current_task, &child)?;
1153
1154 Ok((child, create_result))
1155 }
1156}
1157
1158impl fmt::Debug for DirEntry {
1159 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1160 let mut parents = vec![];
1161 let mut maybe_parent = self.read().parent().clone();
1162 while let Some(parent) = maybe_parent {
1163 parents.push(parent.read().local_name().to_string());
1164 maybe_parent = parent.read().parent().clone();
1165 }
1166 let mut builder = f.debug_struct("DirEntry");
1167 builder.field("id", &(self as *const DirEntry));
1168 builder.field("local_name", &self.read().local_name().to_string());
1169 if !parents.is_empty() {
1170 builder.field("parents", &parents);
1171 }
1172 builder.finish()
1173 }
1174}
1175
1176struct RenameGuard<'a> {
1177 old_parent_guard: DirEntryLockedChildren<'a>,
1178 new_parent_guard: Option<DirEntryLockedChildren<'a>>,
1179}
1180
1181impl<'a> RenameGuard<'a> {
1182 fn lock(old_parent: &'a DirEntryHandle, new_parent: &'a DirEntryHandle) -> Self {
1183 if Arc::ptr_eq(old_parent, new_parent) {
1184 Self { old_parent_guard: old_parent.lock_children(), new_parent_guard: None }
1185 } else {
1186 if new_parent.is_descendant_of(old_parent)
1190 || (!old_parent.is_descendant_of(new_parent)
1191 && old_parent.node.node_key() < new_parent.node.node_key())
1192 {
1193 let old_parent_guard = old_parent.lock_children();
1194 let new_parent_guard = new_parent.lock_children();
1195 Self { old_parent_guard, new_parent_guard: Some(new_parent_guard) }
1196 } else {
1197 let new_parent_guard = new_parent.lock_children();
1198 let old_parent_guard = old_parent.lock_children();
1199 Self { old_parent_guard, new_parent_guard: Some(new_parent_guard) }
1200 }
1201 }
1202 }
1203
1204 fn old_parent(&mut self) -> &mut DirEntryLockedChildren<'a> {
1205 &mut self.old_parent_guard
1206 }
1207
1208 fn new_parent(&mut self) -> &mut DirEntryLockedChildren<'a> {
1209 if let Some(new_guard) = self.new_parent_guard.as_mut() {
1210 new_guard
1211 } else {
1212 &mut self.old_parent_guard
1213 }
1214 }
1215}
1216
1217impl Drop for DirEntry {
1221 fn drop(&mut self) {
1222 let maybe_parent = self.state.write().parent.take();
1223 if let Some(parent) = maybe_parent {
1224 parent.internal_remove_child(self);
1225 }
1226 }
1227}