Skip to content
Open
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion src/uu/rm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ path = "src/rm.rs"
thiserror = { workspace = true }
clap = { workspace = true }
uucore = { workspace = true, features = ["fs", "parser", "safe-traversal"] }
fluent = { workspace = true }
indicatif = { workspace = true }
fluent = { workspace = true }

[target.'cfg(unix)'.dependencies]
libc = { workspace = true }
Expand Down
7 changes: 4 additions & 3 deletions src/uu/rm/locales/en-US.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ rm-help-prompt-once = prompt once before removing more than three files, or when
rm-help-interactive = prompt according to WHEN: never, once (-I), or always (-i). Without WHEN,
prompts always
rm-help-one-file-system = when removing a hierarchy recursively, skip any directory that is on a file
system different from that of the corresponding command line argument (NOT
IMPLEMENTED)
system different from that of the corresponding command line argument
rm-help-no-preserve-root = do not treat '/' specially
rm-help-preserve-root = do not remove '/' (default)
rm-help-recursive = remove directories and their contents recursively
Expand All @@ -41,7 +40,9 @@ rm-error-cannot-remove-permission-denied = cannot remove {$file}: Permission den
rm-error-cannot-remove-is-directory = cannot remove {$file}: Is a directory
rm-error-dangerous-recursive-operation = it is dangerous to operate recursively on '/'
rm-error-use-no-preserve-root = use --no-preserve-root to override this failsafe
rm-error-refusing-to-remove-directory = refusing to remove '.' or '..' directory: skipping {$path}
rm-error-refusing-to-remove-directory = refusing to remove '.' or '..' directory: skipping '{$path}'
rm-error-skipping-directory-on-different-device = skipping '{$path}', since it's on a different device
Copy link
Contributor

Choose a reason for hiding this comment

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

this isn't in the french file

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added

rm-error-preserve-root-all = and --preserve-root=all is in effect
rm-error-cannot-remove = cannot remove {$file}

# Verbose messages
Expand Down
7 changes: 4 additions & 3 deletions src/uu/rm/locales/fr-FR.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ rm-help-prompt-once = demander une fois avant de supprimer plus de trois fichier
rm-help-interactive = demander selon QUAND : never, once (-I), ou always (-i). Sans QUAND,
demande toujours
rm-help-one-file-system = lors de la suppression récursive d'une hiérarchie, ignorer tout répertoire situé sur un
système de fichiers différent de celui de l'argument de ligne de commande correspondant (NON
IMPLÉMENTÉ)
système de fichiers différent de celui de l'argument de ligne de commande correspondant
rm-help-no-preserve-root = ne pas traiter '/' spécialement
rm-help-preserve-root = ne pas supprimer '/' (par défaut)
rm-help-recursive = supprimer les répertoires et leur contenu récursivement
Expand All @@ -41,7 +40,9 @@ rm-error-cannot-remove-permission-denied = impossible de supprimer {$file} : Per
rm-error-cannot-remove-is-directory = impossible de supprimer {$file} : C'est un répertoire
rm-error-dangerous-recursive-operation = il est dangereux d'opérer récursivement sur '/'
rm-error-use-no-preserve-root = utilisez --no-preserve-root pour outrepasser cette protection
rm-error-refusing-to-remove-directory = refus de supprimer le répertoire '.' ou '..' : ignorer {$path}
rm-error-refusing-to-remove-directory = refus de supprimer le répertoire '.' ou '..' : ignorer '{$path}'
rm-error-skipping-directory-on-different-device = ignorer '{$path}', car il se trouve sur un périphérique différent
rm-error-preserve-root-all = et --preserve-root=all est actif
rm-error-cannot-remove = impossible de supprimer {$file}

# Messages verbeux
Expand Down
55 changes: 50 additions & 5 deletions src/uu/rm/src/platform/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
use indicatif::ProgressBar;
use std::ffi::OsStr;
use std::fs;
#[cfg(unix)]
use std::os::unix::fs::MetadataExt;

use std::io::{IsTerminal, stdin};
use std::os::unix::fs::PermissionsExt;
use std::path::Path;
Expand All @@ -22,8 +25,8 @@ use uucore::translate;

use super::super::{
InteractiveMode, Options, is_dir_empty, is_readable_metadata, prompt_descend, remove_file,
show_permission_denied_error, show_removal_error, verbose_removed_directory,
verbose_removed_file,
should_skip_different_device_with_dev, show_permission_denied_error, show_removal_error,
verbose_removed_directory, verbose_removed_file,
};

#[inline]
Expand Down Expand Up @@ -276,6 +279,7 @@ pub fn safe_remove_dir_recursive(
path: &Path,
options: &Options,
progress_bar: Option<&ProgressBar>,
current_dev_id: Option<u64>,
) -> bool {
// Base case 1: this is a file or a symbolic link.
// Use lstat to avoid race condition between check and use
Expand All @@ -289,6 +293,16 @@ pub fn safe_remove_dir_recursive(
}
};

let check_device = options.one_fs || options.preserve_root_all;
#[cfg(unix)]
let current_dev_id = if check_device {
current_dev_id.or_else(|| path.symlink_metadata().ok().map(|m| m.dev()))
} else {
None
};
#[cfg(not(unix))]
let current_dev_id: Option<u64> = None;

// Try to open the directory using DirFd for secure traversal
let dir_fd = match DirFd::open(path) {
Ok(fd) => fd,
Expand All @@ -309,7 +323,12 @@ pub fn safe_remove_dir_recursive(
}
};

let error = safe_remove_dir_recursive_impl(path, &dir_fd, options);
let error = safe_remove_dir_recursive_impl(
path,
&dir_fd,
options,
if check_device { current_dev_id } else { None },
);

// After processing all children, remove the directory itself
if error {
Expand Down Expand Up @@ -345,7 +364,12 @@ pub fn safe_remove_dir_recursive(
}
}

pub fn safe_remove_dir_recursive_impl(path: &Path, dir_fd: &DirFd, options: &Options) -> bool {
pub fn safe_remove_dir_recursive_impl(
path: &Path,
dir_fd: &DirFd,
options: &Options,
parent_dev_id: Option<u64>,
) -> bool {
// Read directory entries using safe traversal
let entries = match dir_fd.read_dir() {
Ok(entries) => entries,
Expand All @@ -361,6 +385,7 @@ pub fn safe_remove_dir_recursive_impl(path: &Path, dir_fd: &DirFd, options: &Opt
};

let mut error = false;
let check_device = options.one_fs || options.preserve_root_all;

// Process each entry
for entry_name in entries {
Expand All @@ -379,6 +404,17 @@ pub fn safe_remove_dir_recursive_impl(path: &Path, dir_fd: &DirFd, options: &Opt
let is_dir = (entry_stat.st_mode & libc::S_IFMT) == libc::S_IFDIR;

if is_dir {
if check_device
&& should_skip_different_device_with_dev(
parent_dev_id,
entry_stat.st_dev,
options,
&entry_path,
)
{
error = true;
continue;
}
// Ask user if they want to descend into this directory
if options.interactive == InteractiveMode::Always
&& !is_dir_empty(&entry_path)
Expand Down Expand Up @@ -407,7 +443,16 @@ pub fn safe_remove_dir_recursive_impl(path: &Path, dir_fd: &DirFd, options: &Opt
}
};

let child_error = safe_remove_dir_recursive_impl(&entry_path, &child_dir_fd, options);
let child_error = safe_remove_dir_recursive_impl(
&entry_path,
&child_dir_fd,
options,
if check_device {
Some(entry_stat.st_dev)
} else {
None
},
);
error = error || child_error;

// Ask user permission if needed for this subdirectory
Expand Down
Loading
Loading