Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 38 additions & 16 deletions library/std/src/sys/fs/common.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![allow(dead_code)] // not used on all platforms
use alloc_crate::collections::VecDeque;

use crate::io::{self, Error, ErrorKind};
use crate::path::{Path, PathBuf};
Expand Down Expand Up @@ -29,27 +30,48 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {

pub fn remove_dir_all(path: &Path) -> io::Result<()> {
let filetype = fs::symlink_metadata(path)?.file_type();
if filetype.is_symlink() { fs::remove_file(path) } else { remove_dir_all_recursive(path) }
if filetype.is_symlink() { fs::remove_file(path) } else { remove_dir_all_iterative(path) }
}

fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
for child in fs::read_dir(path)? {
let result: io::Result<()> = try {
let child = child?;
if child.file_type()?.is_dir() {
remove_dir_all_recursive(&child.path())?;
} else {
fs::remove_file(&child.path())?;
fn remove_dir_all_iterative(path: &Path) -> io::Result<()> {
// In unix/windows/solid/hermit/motor/uefi implementation of ReadDir struct, there is a field
// called `root` that contains the directory path that we are reading directory entries
// from. This makes holding a PathBuf in this tuple redundant since we only need this to remove
// the directory when we have exhausted the ReadDir iterator; if we can expose that field
// in the ReadDir struct through a method that return &Path, we can reduce memory usage
// allocated to this VecDeque.

let mut directories = VecDeque::new();
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, noting that this could use the std library LinkedList implementation if the resizing cost from VecDeque is undesirable.

directories.push_front((path.to_path_buf(), fs::read_dir(path)?));

while !directories.is_empty() {
let (parent_path, read_dir) = &mut directories[0];
let child = read_dir.next();
if let Some(child) = child {
let result: io::Result<()> = try {
let child = child?;
let child_path = child.path();
if child.file_type()?.is_dir() {
let child_readdir = fs::read_dir(&child_path)?;
directories.push_front((child_path, child_readdir));
} else {
fs::remove_file(&child_path)?;
}
};

// ignore internal NotFound errors to prevent race conditions
if let Err(err) = &result
&& err.kind() != io::ErrorKind::NotFound
{
return result;
}
};
// ignore internal NotFound errors to prevent race conditions
if let Err(err) = &result
&& err.kind() != io::ErrorKind::NotFound
{
return result;
} else {
ignore_notfound(fs::remove_dir(parent_path))?;
directories.pop_front();
}
}
ignore_notfound(fs::remove_dir(path))

Ok(())
}

pub fn exists(path: &Path) -> io::Result<bool> {
Expand Down
Loading