Skip to content

Commit b22a782

Browse files
committed
refactor: extract Unix-specific device handling in rm recursive removal
Refactored the `remove` and `remove_dir_recursive` functions in rm to separate Unix-specific logic (device ID checks for --one-file-system and --preserve-root) into conditionally compiled functions, improving code organization and cross-platform maintainability without changing functionality.
1 parent dfc3119 commit b22a782

File tree

1 file changed

+115
-30
lines changed

1 file changed

+115
-30
lines changed

src/uu/rm/src/rm.rs

Lines changed: 115 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -511,11 +511,16 @@ pub fn remove(files: &[&OsStr], options: &Options) -> bool {
511511
} else {
512512
None
513513
};
514-
#[cfg(not(unix))]
515-
let parent_dev_id = None;
516514

517515
if metadata.is_dir() {
518-
handle_dir(file, options, progress_bar.as_ref(), parent_dev_id)
516+
#[cfg(unix)]
517+
{
518+
handle_dir(file, options, progress_bar.as_ref(), parent_dev_id)
519+
}
520+
#[cfg(not(unix))]
521+
{
522+
handle_dir(file, options, progress_bar.as_ref())
523+
}
519524
} else if is_symlink_dir(&metadata) {
520525
remove_dir(file, options, progress_bar.as_ref())
521526
} else {
@@ -604,21 +609,103 @@ fn is_writable(_path: &Path) -> bool {
604609
true
605610
}
606611

612+
#[cfg(unix)]
613+
fn should_skip_different_device(
614+
parent_dev_id: Option<u64>,
615+
metadata: &Metadata,
616+
options: &Options,
617+
path: &Path,
618+
) -> bool {
619+
if let Some(parent_dev_id) = parent_dev_id {
620+
if metadata.dev() != parent_dev_id {
621+
show_error!(
622+
"{}",
623+
RmError::SkippingDirectoryOnDifferentDevice(path.as_os_str().to_os_string())
624+
);
625+
if options.preserve_root_all {
626+
show_error!("{}", RmError::PreserveRootAllInEffect);
627+
}
628+
return true;
629+
}
630+
}
631+
false
632+
}
633+
634+
#[cfg(not(unix))]
635+
fn should_skip_different_device(
636+
_parent_dev_id: Option<u64>,
637+
_metadata: &Metadata,
638+
_options: &Options,
639+
_path: &Path,
640+
) -> bool {
641+
false
642+
}
643+
644+
#[cfg(unix)]
645+
fn compute_next_parent_dev_id(options: &Options, metadata: &Metadata) -> Option<u64> {
646+
if options.one_fs || options.preserve_root_all {
647+
Some(metadata.dev())
648+
} else {
649+
None
650+
}
651+
}
652+
653+
#[cfg(not(unix))]
654+
fn compute_next_parent_dev_id(_options: &Options, _metadata: &Metadata) -> Option<u64> {
655+
None
656+
}
657+
658+
#[cfg(unix)]
659+
fn remove_dir_recursive(
660+
path: &Path,
661+
options: &Options,
662+
progress_bar: Option<&ProgressBar>,
663+
parent_dev_id: Option<u64>,
664+
) -> bool {
665+
remove_dir_recursive_impl(path, options, progress_bar, parent_dev_id)
666+
}
667+
668+
#[cfg(not(unix))]
669+
fn remove_dir_recursive(
670+
path: &Path,
671+
options: &Options,
672+
progress_bar: Option<&ProgressBar>,
673+
) -> bool {
674+
remove_dir_recursive_impl(path, options, progress_bar, None)
675+
}
676+
677+
#[cfg(unix)]
678+
fn remove_dir_recursive_with_parent(
679+
path: &Path,
680+
options: &Options,
681+
progress_bar: Option<&ProgressBar>,
682+
parent_dev_id: Option<u64>,
683+
) -> bool {
684+
remove_dir_recursive(path, options, progress_bar, parent_dev_id)
685+
}
686+
687+
#[cfg(not(unix))]
688+
fn remove_dir_recursive_with_parent(
689+
path: &Path,
690+
options: &Options,
691+
progress_bar: Option<&ProgressBar>,
692+
_parent_dev_id: Option<u64>,
693+
) -> bool {
694+
remove_dir_recursive(path, options, progress_bar)
695+
}
696+
607697
/// Recursively remove the directory tree rooted at the given path.
608698
///
609699
/// If `path` is a file or a symbolic link, just remove it. If it is a
610700
/// directory, remove all of its entries recursively and then remove the
611701
/// directory itself. In case of an error, print the error message to
612702
/// `stderr` and return `true`. If there were no errors, return `false`.
613-
fn remove_dir_recursive(
703+
fn remove_dir_recursive_impl(
614704
path: &Path,
615705
options: &Options,
616706
progress_bar: Option<&ProgressBar>,
617-
_parent_dev_id: Option<u64>,
707+
parent_dev_id: Option<u64>,
618708
) -> bool {
619-
#[cfg(unix)]
620-
let parent_dev_id = _parent_dev_id;
621-
622709
let metadata = match path.symlink_metadata() {
623710
Ok(metadata) => metadata,
624711
Err(e) => return show_removal_error(e, path),
@@ -644,28 +731,11 @@ fn remove_dir_recursive(
644731
}
645732

646733
// Base case 3: this is a directory on a different device
647-
#[cfg(unix)]
648-
if let Some(parent_dev_id) = parent_dev_id {
649-
if metadata.dev() != parent_dev_id {
650-
show_error!(
651-
"{}",
652-
RmError::SkippingDirectoryOnDifferentDevice(path.as_os_str().to_os_string())
653-
);
654-
if options.preserve_root_all {
655-
show_error!("{}", RmError::PreserveRootAllInEffect);
656-
}
657-
return true;
658-
}
734+
if should_skip_different_device(parent_dev_id, &metadata, options, path) {
735+
return true;
659736
}
660737

661-
#[cfg(unix)]
662-
let next_parent_dev_id = if options.one_fs || options.preserve_root_all {
663-
Some(metadata.dev())
664-
} else {
665-
None
666-
};
667-
#[cfg(not(unix))]
668-
let next_parent_dev_id = None;
738+
let next_parent_dev_id = compute_next_parent_dev_id(options, &metadata);
669739

670740
// Use secure traversal on Linux for all recursive directory removals
671741
#[cfg(target_os = "linux")]
@@ -703,7 +773,7 @@ fn remove_dir_recursive(
703773
match entry {
704774
Err(_) => error = true,
705775
Ok(entry) => {
706-
let child_error = remove_dir_recursive(
776+
let child_error = remove_dir_recursive_impl(
707777
&entry.path(),
708778
options,
709779
progress_bar,
@@ -750,11 +820,26 @@ fn remove_dir_recursive(
750820
}
751821
}
752822

823+
#[cfg(unix)]
753824
fn handle_dir(
754825
path: &Path,
755826
options: &Options,
756827
progress_bar: Option<&ProgressBar>,
757828
parent_dev_id: Option<u64>,
829+
) -> bool {
830+
handle_dir_impl(path, options, progress_bar, parent_dev_id)
831+
}
832+
833+
#[cfg(not(unix))]
834+
fn handle_dir(path: &Path, options: &Options, progress_bar: Option<&ProgressBar>) -> bool {
835+
handle_dir_impl(path, options, progress_bar, None)
836+
}
837+
838+
fn handle_dir_impl(
839+
path: &Path,
840+
options: &Options,
841+
progress_bar: Option<&ProgressBar>,
842+
parent_dev_id: Option<u64>,
758843
) -> bool {
759844
let mut had_err = false;
760845

@@ -769,7 +854,7 @@ fn handle_dir(
769854

770855
let is_root = path.has_root() && path.parent().is_none();
771856
if options.recursive && (!is_root || !options.preserve_root) {
772-
had_err = remove_dir_recursive(path, options, progress_bar, parent_dev_id);
857+
had_err = remove_dir_recursive_with_parent(path, options, progress_bar, parent_dev_id);
773858
} else if options.dir && (!is_root || !options.preserve_root) {
774859
had_err = remove_dir(path, options, progress_bar).bitor(had_err);
775860
} else if options.recursive {

0 commit comments

Comments
 (0)