Without a preserve flag, cp -r gave every directory it created the
source's mode unmasked, so a 777 source directory became 777 regardless
of the umask, while regular files in the same copy were masked correctly.
The final permission pass defaulted a freshly-created directory to
preserving the source mode. Apply the umask in that defaulted case, as
GNU does, while a real preserve (-p/-a) and --no-preserve=mode are
unchanged.
Fixes#14549
Signed-off-by: nagendramohan <nagendramohan1990@gmail.com>
test_suppress_duplicates and test_od_options_after_filename dump
multi-byte units (-x, -O, -t x2) and compare the result against
little-endian expected output without selecting a byte order. They
fail on big-endian hosts, where od correctly defaults to the native
order:
expected: " 1c68 fdbb\n"
actual: " 681c bbfd\n"
Pass --endian=little like the other tests in this file do. In
test_od_options_after_filename the option goes after the file name, in
keeping with what that test exercises.
Found on FreeBSD/powerpc64.
translate! hands Fluent a number whenever the argument parses as one,
so the error for -d 1e9 showed '1000000000', -d -0 showed '0', and
-d 9. showed '9'. Use translate_text! for the invalid-date and
missing-plus messages, which echo what the user typed.
Fixes#14669. Fixes#14670.
`from_obsolete_args` built `Signum::Positive(args.num)` unconditionally, while
`parse_num` — behind `-n +N` / `-c +N` — maps zero to `PlusZero`. So `+0`,
`+00`, `+0c` and `+0l` produced `Positive(0)`, which misses `unbounded_tail`'s
`PlusZero | Positive(1)` arms and underflows at `*count - 1`. Release wrapped
to `u64::MAX` and printed nothing, exiting 0 where GNU prints the whole input;
overflow-checks aborted. `bounded_tail` guards with `count > &1`, so only stdin
or a file at or below the block size is affected.
Obsolete `-0`/`-0c` now give `MinusZero` like `-n 0`, taking the existing
`-[nc]0` early exit: `tail -0 <missing>` exits 0 silently instead of 1,
matching GNU.
Fixes#14660
* generalize the mv code for ln, cp
replace links atomically instead of unlinking first
Forced replacement was unlink(dst) then create. The gap lets another user
claim dst in a directory they can write to -- including a name the sticky
bit forbids them to remove -- so a privileged ln hands them a trusted name.
* ln: don't leave the temp behind when the rename is a no-op
Renaming the temp onto a destination that is already a link to the same
inode does nothing and returns success, so the temp name survived:
`ln -f a b` with b already hard-linked to a left a stray Cu* file.
Unlink the temp after the rename either way; on the normal path it is
already gone.
It created a regular file whatever the source was, so a FIFO got the wrong
type and then blocked forever in File::open(source) during the xattr copy.
Dispatch on the source's type via the existing copy_fifo/copy_socket/copy_node
helpers, and require a regular source before using the fd-based xattr path.
Matches GNU for -a, -R --attributes-only and -a --attributes-only.
When verifying a checksum file, the BLAKE2b output length was inferred
from the digest found in the file and handed to the hasher unchecked. A
digest longer than the 64 bytes BLAKE2b maximum made blake2b_simd fail
its own length assertion and abort the process, instead of the line
being reported as malformed.
Route that inferred length through parse_blake_length, like the --length
and tagged-line paths already do, and treat a rejected length as an
improperly formatted line. This matches GNU, which skips such a line and
exits 1 with "no properly formatted checksum lines found".
HashLength::from_bytes loses its last caller with this change, so drop
it.
Fixes#14487
When stat() failed on an entry coming from read_dir(), PathData::metadata()
discarded the error: `ls -l` printed the unknown-metadata row, wrote nothing
to stderr and exited 0. GNU prints a diagnostic and exits 1.
Route the cached DirEntry metadata through the same error handling as the
non-cached path, so the failure is reported and the exit status is set.
While at it:
- do not print a second diagnostic when readlink() fails for an entry whose
metadata could not be read either; GNU prints only one.
- stat() failures are reported as "cannot access X: Permission denied", the
GNU wording, instead of "cannot open file X: Permission denied" (that
message was only ever reachable from stat()/readlink() failures).
Reported by Hongkai Chen of SEFCOM Lab at Arizona State University.
safe_remove_dir_recursive_impl recursed once per directory level, so
`rm -rf` on a hierarchy tens of thousands of levels deep overflowed the
stack and died with SIGSEGV, leaving the tree in place.
Walk the tree with an explicit stack instead. Only the deepest 16 levels
keep their directory descriptor open; the others get theirs back through
".." on the way up, checked against the recorded device and inode so a
directory swapped in mid-walk cannot redirect the removal. Depth is then
bounded by memory rather than by the stack or the descriptor limit.
Keep the current path in one byte buffer, stepping into an entry and back
out by appending and truncating rather than building a fresh PathBuf per
entry, which a long path makes expensive. That is 7% fewer instructions
than the recursive version on the rm_recursive_tree benchmark.
Ask whether a directory is empty through its parent's descriptor too. The
path-based check fails past PATH_MAX and a failure counts as non-empty,
so `rm -ri` prompted before descending into an empty directory that deep,
and left it behind when the prompt was declined.
https://bugs.launchpad.net/bugs/2167206https://github.com/uutils/coreutils/issues/2949
* link: add tests for zero args and existing destination
* link: fix rustfmt formatting for test_link_dest_exists
Split the chained method call onto separate lines to match rustfmt's
expected formatting.
* link: fix test_link_dest_exists for cross-platform error message
The EEXIST error message varies by OS: Linux/macOS reports "File exists"
while OpenBSD reports "Already exists". Broaden the match to "exists"
to cover all platforms.
* link: fix test_link_no_arguments and rustfmt on test_link_dest_exists
- test_link_no_arguments: clap emits "the following required arguments
were not provided" (not "2 values required") when zero args are
given; drop the stderr assertion and keep only .fails().
- test_link_dest_exists: collapse the method chain to one line to
satisfy rustfmt.
`ln -f A B` unlinked B before attempting the link, so a link that failed
for any reason other than the destination already existing (a missing
source, a directory source, a dangling symlink with -L) left B deleted.
Attempt the link first and remove an existing destination only after the
link reports EEXIST, matching GNU, so a failed link never destroys the
destination.
Fixes#14550
Signed-off-by: nagendramohan <nagendramohan1990@gmail.com>