cap_primitives/rustix/fs/
remove_open_dir_by_searching.rs

1use crate::fs::{errors, is_root_dir, read_dir_unchecked, FollowSymlinks, Metadata};
2use std::path::Component;
3use std::{fs, io};
4
5/// Delete the directory referenced by the given handle by searching for it in
6/// its `..`. This requires search permission in `..`, but that's usually
7/// available.
8pub(crate) fn remove_open_dir_by_searching(dir: fs::File) -> io::Result<()> {
9    let metadata = Metadata::from_file(&dir)?;
10    let mut iter = read_dir_unchecked(&dir, Component::ParentDir.as_ref(), FollowSymlinks::No)?;
11    while let Some(child) = iter.next() {
12        let child = child?;
13
14        // Test if the child we found by iteration matches the directory we're
15        // looking for. Ignore `NotFound` errors, which can happen if another
16        // process removes a different directory in the same parent.
17        let same = match child.is_same_file(&metadata) {
18            Ok(same) => same,
19            Err(err) if err.kind() == std::io::ErrorKind::NotFound => false,
20            Err(err) => Err(err)?,
21        };
22
23        if same {
24            return child.remove_dir();
25        }
26    }
27
28    // We didn't find the directory among its parent's children. Check for the
29    // root directory and handle it specially -- removal will probably fail, so
30    // we'll get the appropriate error code.
31    if is_root_dir(&dir, &iter)? {
32        fs::remove_dir(Component::RootDir.as_os_str())
33    } else {
34        Err(errors::no_such_file_or_directory())
35    }
36}