Skip to content

Commit 971a8bd

Browse files
committed
fix: prevent file descriptor buildup in recursive rm on Linux
Drop the main directory file descriptor early in `safe_remove_dir_recursive_impl` and open fresh parent FDs per entry unlink to avoid accumulating open file descriptors during recursive directory removal. This resolves potential FD exhaustion issues when removing large directory trees.
1 parent fbb0fd9 commit 971a8bd

File tree

1 file changed

+26
-5
lines changed

1 file changed

+26
-5
lines changed

src/uu/rm/src/platform/linux.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ pub fn safe_remove_dir_recursive_impl(
343343
}
344344
};
345345

346-
// Collect names and stat data
346+
// Collect names and stat data, then drop fd to avoid FD buildup
347347
let mut collected = Vec::with_capacity(entries.len());
348348
for entry_name in entries {
349349
match dir_fd.stat_at(&entry_name, false) {
@@ -356,6 +356,7 @@ pub fn safe_remove_dir_recursive_impl(
356356
}
357357
}
358358
}
359+
drop(dir_fd);
359360

360361
let mut error = false;
361362

@@ -385,15 +386,35 @@ pub fn safe_remove_dir_recursive_impl(
385386
if let Some(pb) = progress_bar {
386387
pb.inc(1);
387388
}
388-
error = handle_unlink(&dir_fd, entry_name.as_ref(), &entry_path, true, options)
389-
|| error;
389+
match DirFd::open(path) {
390+
Ok(parent_fd) => {
391+
error = handle_unlink(
392+
&parent_fd,
393+
entry_name.as_ref(),
394+
&entry_path,
395+
true,
396+
options,
397+
) || error;
398+
}
399+
Err(e) => {
400+
error = handle_error_with_force(e, &entry_path, options) || error;
401+
}
402+
}
390403
}
391404
} else if prompt_file_with_stat(&entry_path, &entry_stat, options) {
392405
if let Some(pb) = progress_bar {
393406
pb.inc(1);
394407
}
395-
error =
396-
handle_unlink(&dir_fd, entry_name.as_ref(), &entry_path, false, options) || error;
408+
match DirFd::open(path) {
409+
Ok(parent_fd) => {
410+
error =
411+
handle_unlink(&parent_fd, entry_name.as_ref(), &entry_path, false, options)
412+
|| error;
413+
}
414+
Err(e) => {
415+
error = handle_error_with_force(e, &entry_path, options) || error;
416+
}
417+
}
397418
}
398419
}
399420

0 commit comments

Comments
 (0)