Skip to content

Commit aac80e3

Browse files
committed
Adding sed example for overriding the LD when not the same function is used
1 parent 67ede85 commit aac80e3

4 files changed

Lines changed: 40 additions & 1 deletion

File tree

src/uu/rm/locales/en-US.ftl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ rm-error-dangerous-recursive-operation = it is dangerous to operate recursively
4343
rm-error-use-no-preserve-root = use --no-preserve-root to override this failsafe
4444
rm-error-refusing-to-remove-directory = refusing to remove '.' or '..' directory: skipping '{$path}'
4545
rm-error-cannot-remove = cannot remove {$file}
46+
rm-error-traversal-failed = traversal failed: {$path}
4647
4748
# Verbose messages
4849
rm-verbose-removed = removed {$file}

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use std::fs;
1313
use std::path::Path;
1414
use uucore::display::Quotable;
1515
use uucore::error::FromIo;
16-
use uucore::safe_traversal::DirFd;
16+
use uucore::safe_traversal::{DirFd, clear_errno, take_errno};
1717
use uucore::show_error;
1818
use uucore::translate;
1919

@@ -258,6 +258,7 @@ pub fn safe_remove_dir_recursive(
258258

259259
pub fn safe_remove_dir_recursive_impl(path: &Path, dir_fd: &DirFd, options: &Options) -> bool {
260260
// Read directory entries using safe traversal
261+
clear_errno();
261262
let entries = match dir_fd.read_dir() {
262263
Ok(entries) => entries,
263264
Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => {
@@ -271,6 +272,14 @@ pub fn safe_remove_dir_recursive_impl(path: &Path, dir_fd: &DirFd, options: &Opt
271272
}
272273
};
273274

275+
// Check if readdir failed partway through (partial read)
276+
if let Some(err) = take_errno() {
277+
if !entries.is_empty() {
278+
show_error!("{}: {}", translate!("rm-error-traversal-failed", "path" => path.display()), err);
279+
return true;
280+
}
281+
}
282+
274283
let mut error = false;
275284

276285
// Process each entry

src/uucore/src/lib/features/safe_traversal.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd};
2121
use std::path::Path;
2222

2323
use nix::dir::Dir;
24+
use nix::errno::Errno;
2425
use nix::fcntl::{OFlag, openat};
2526
use nix::libc;
2627
use nix::sys::stat::{FchmodatFlags, FileStat, Mode, fchmodat, fstatat};
@@ -78,6 +79,19 @@ impl From<SafeTraversalError> for io::Error {
7879
}
7980
}
8081

82+
/// Clear errno and return any error that was set after an operation
83+
/// This is used because the nix library does not propogate folder reading errors correctly
84+
pub fn take_errno() -> Option<io::Error> {
85+
let errno = Errno::last();
86+
Errno::clear();
87+
(errno != Errno::from_raw(0)).then(|| io::Error::from_raw_os_error(errno as i32))
88+
}
89+
90+
/// Clear errno before an operation, required to read error messages not propogated by nix from reading folders
91+
pub fn clear_errno() {
92+
Errno::clear();
93+
}
94+
8195
// Helper function to read directory entries using nix
8296
fn read_dir_entries(fd: &OwnedFd) -> io::Result<Vec<OsString>> {
8397
let mut entries = Vec::new();

util/build-gnu.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,3 +361,18 @@ test \$n_stat1 -ge \$n_stat2 \\' tests/ls/stat-free-color.sh
361361
# * the selinux crate is handling errors
362362
# * the test says "maybe we should not fail when no context available"
363363
"${SED}" -i -e "s|returns_ 1||g" tests/cp/no-ctx.sh
364+
365+
# The rm-readdir-fail.sh test hooks readdir() but uutils rm uses nix library which calls readdir64_r().
366+
# readdir64_r has a different signature: int readdir64_r(DIR*, struct dirent64*, struct dirent64**)
367+
"${SED}" -i \
368+
-e 's/struct dirent \*readdir (DIR \*dirp)/int readdir64_r(DIR *dirp, struct dirent64 *entry, struct dirent64 **result)/' \
369+
-e 's/struct dirent \*(\*real_readdir)(DIR \*dirp)/int (*real_func)(DIR *, struct dirent64 *, struct dirent64 **)/' \
370+
-e 's/real_readdir/real_func/g' \
371+
-e 's/dlsym (RTLD_NEXT, "readdir")/dlsym(RTLD_NEXT, "readdir64_r")/' \
372+
-e 's/struct dirent\* d;/int ret;/' \
373+
-e 's/! (d = real_func (dirp))/(ret = real_func(dirp, entry, result)) != 0 || !*result/' \
374+
-e 's/d->d_name/entry->d_name/g' \
375+
-e 's/d->d_namlen/entry->d_namlen/g' \
376+
-e 's/return d;/return 0;/' \
377+
-e 's/return NULL;/*result = NULL; return EIO;/' \
378+
tests/rm/rm-readdir-fail.sh

0 commit comments

Comments
 (0)