21229 Commits
Author SHA1 Message Date
Daniel Syauqi ca3e965d68 touch: simplify Unix access error check 2026-10-08 22:09:09 +02:00
Daniel Syauqi cb4392c25e touch: accept Unix permission errors in test 2026-10-08 22:09:09 +02:00
Daniel Syauqi b43c45a9fa touch: address permission error review feedback 2026-10-08 22:09:09 +02:00
Daniel Syauqi 43915e4c01 touch: report access errors as cannot touch 2026-10-08 22:09:09 +02:00
Eduardo Rodrigues fd094e3e57 tests(wasi): increase integration coverage for wasip1 2026-10-08 22:08:31 +02:00
Zhiwei Liang 8f6a838481 test: remove env::set_var from df and mkdir tests
`test_mkdir_environment_expansion` set TEST_VAR in the test process, so
mkdir never saw it; pass it to the child with `.env()` instead. The
POSIXLY_CORRECT part of df's `test_default_block_size` is already
covered by the test_df integration tests, so remove it.

Signed-off-by: Zhiwei Liang <zhiwei.liang@zliang.me>
2026-10-08 15:15:49 +02:00
Zhiwei Liang 48b4093d63 test: fix flaky test_chown_no_dereference_symlink_to_dir
On the Android emulator, the link's ctime did not change between its
creation and `chown -h`, because the file system clock had not ticked.
Sleep 100 ms before `chown`, as test_ls_order_time does.

Signed-off-by: Zhiwei Liang <zhiwei.liang@zliang.me>
2026-10-08 15:03:28 +02:00
NdekoCode db40b66b7f join: report a bad file number and a missing or extra operand as GNU does
`-a 3` and `-v x` were rejected by clap, as "invalid value '3' for
'-a <FILENUM>'", before the parser that says "invalid file number:
'3'" could see them. A missing operand came out as clap's "the
following required arguments were not provided", an extra one as
"unexpected argument 'c' found".

Let any value reach the file number parser, and count the operands
after parsing: "missing operand", "missing operand after 'a'" and
"extra operand 'c'", each followed by the help hint, exit status 1.
2026-10-08 13:01:59 +02:00
Zhiwei Liang 0d4a305644 cksum: reject tagged lines with a legacy algorithm in --check
`cksum --check` accepted lines such as `CRC (f) = 3015617425` and read
the decimal digest as hex. The legacy algorithms have no tagged format,
so report these lines as improperly formatted.

Signed-off-by: Zhiwei Liang <zhiwei.liang@zliang.me>
2026-10-08 11:05:03 +02:00
oech3 3c22cdfb0e GnuTests: patch tee/short-write.sh to fire read/write code path 2026-10-08 08:24:12 +02:00
Zhiwei Liang 5469493e9b cksum: prefix --debug lines with the utility name
GNU prints the `cksum --debug` hardware lines with the program name,
for example "cksum: using avx2 hardware support". Print them with
show_error!, as tail --debug does.

Signed-off-by: Zhiwei Liang <zhiwei.liang@zliang.me>
2026-10-08 08:20:40 +02:00
darkraider01 8460811736 tests: borrow WASI environment keys and values 2026-10-07 23:39:42 +02:00
darkraider01 7f6c6d4ec6 tests: preserve environment overrides in WASI 2026-10-07 23:39:42 +02:00
darkraider01 81a6494d9a tests: record WASI environment override behavior 2026-10-07 23:39:42 +02:00
Daniel Hofstetter 8edf72539d fold: support non-UTF8 paths 2026-10-07 23:37:12 +02:00
xtqqczze a5bc606e4f ci: update permissions to allow writing issues in audit workflow 2026-10-07 18:42:02 +02:00
Zhiwei Liang fe26d56ed9 cksum: report vmull support only when the CPU has PMULL
On aarch64, `cksum --debug` used the ASIMD check for the vmull line,
but the vmull path needs PMULL. Check PMULL at runtime, as GNU does.

Signed-off-by: Zhiwei Liang <zhiwei.liang@zliang.me>
2026-10-07 09:56:53 +02:00
Jake Abendroth 4e2be1c9e6 uucore: build safe_traversal on AIX and Hurd
The only thing keeping it off them was the stat time fields, which they
expose as timespecs (st_atim and so on). Read those there, and gate
safe_traversal and its users on Redox alone, so chmod, du, install and
rm walk trees through descriptors there too. The path-based chmod
helpers that only AIX still used are gone, as are the target-specific
safe-traversal features of chmod, chown and install, which already get
it through perms.

Redox stays excluded: nix has none of the *at calls there.
2026-10-07 08:58:12 +02:00
Eduardo Rodrigues 229d4d075a date: fix wasi clock resolution and system datetime support
date implements get_clock_resolution via libc::clock_getres (rustix's
excludes WASI) and set_system_datetime for WASI, the latter reporting
"not supported" since the sandbox has no wall-clock-set syscall.
2026-10-07 08:32:02 +02:00
Jake Abendroth 2c545f6d55 tee: replace the pipe a failed output used
tee duplicates its input through two pipes on Linux. When splicing from
one of them to an output failed part-way, for example with ENOSPC or
EFBIG, the bytes the output did not take stayed in the pipe, and the
remaining outputs got them in front of their next chunk.

Replace the pipe with an empty one after a failed output. The old pipe
is closed first, so that this also works at the open file limit. A new
pipe gets the larger size only if the 2nd pipe got it at the start, so
that the 2nd is never smaller than the 1st. If no new pipe can be made,
tee fails with the error.
2026-10-07 08:22:19 +02:00
renovate[bot] 9c5ab16578 chore(deps): update rust crate jiff-tzdb to v0.1.9 2026-10-07 07:01:35 +02:00
renovate[bot] 8da2b176ef chore(deps): update rust crate jiff to v0.2.38 2026-10-07 07:00:15 +02:00
Socialpranker 8cf2e4f4ab numfmt: test rounding that carries into the next suffix 2026-10-06 22:23:27 +02:00
Socialpranker 8a5ed27f46 numfmt: honor --round for an explicit --format precision of 0
With --to=<scale>, a "%.0f" precision took the div_round path, which keeps
one fractional digit below the next base and then rounds that to nearest,
so 1234567 printed 1M instead of GNU's 2M under the default from-zero
rounding. An explicitly given precision now rounds the scaled value with
the selected method.
2026-10-06 22:23:27 +02:00
xtqqczze 9019055dcf perf: mark error handling functions as cold and non-inlineable
Error construction is infrequently executed compared with the normal success paths. Mark these functions with `#[cold]` so the compiler can treat them as unlikely code paths and keep cold code separate from hot code.

Use `#[inline(never)]` to prevent error-handling code from being inlined into their callers, avoiding unnecessary code-size growth and keeping the normal execution paths smaller.
2026-10-06 22:20:42 +02:00
xtqqczze 99ceba1f17 style: reorder attributes and documentation comments 2026-10-06 22:20:42 +02:00
Jake Abendroth d027897a2c tests: dd: ignore SIGXFSZ in the child instead of the test process
Add UCommand::ignore_sigxfsz, which ignores SIGXFSZ in the child's
pre_exec, so a test can push a utility past an Fsize limit and see the
failed write.

test_dd's two Fsize tests did this with a guard that changed SIGXFSZ for
the whole test process. Under cargo test they run in parallel in one
binary, and one test restoring the default could get the other's dd
killed before it printed its stats. Use the new method instead.
2026-10-06 18:37:33 +02:00
Aakarshit Verma b8a42fef66 uucore: look up the locales directory once in setup_localization 2026-10-06 17:08:13 +02:00
Aakarshit Verma 198bc77c77 uucore: cache every leaked locale resource, swap localizer on success
Switching utilities rebuilds bundles, and the on-disk and WASI paths
leaked a freshly parsed resource each time. Cache all of them per source
instead, so each file is parsed and leaked at most once.

Overwrite the localizer only after the new one was built, instead of
clearing it first: a failed setup now keeps the previous utility's
strings, matching LOCALIZED_UTIL. This also drops the "already
initialized" error, which can no longer happen.

Replace the thread-based test, which also passed before this change,
with one checking that bundles reuse cached resources.
2026-10-06 17:08:13 +02:00
Aakarshit Verma e5db1dd1fa uucore: keep the current utility for names without strings
The help template sets up localization with the invoked name, e.g. dir,
vdir or a prefixed binary name. Those have no strings of their own, so
switching to them replaced the utility's strings with nothing.
2026-10-06 17:08:13 +02:00
Aakarshit Verma 694a80251b uucore: allow localizing several utilities in one process
setup_localization() only ever kept the first utility: the per-thread
localizer could not be replaced and the embedded utility resource was a
single process-wide OnceLock. Hosts that run several utilities, such as
nushell, then printed raw message ids for every utility after the first.

Make the thread-local localizer replaceable when a different utility is
set up, and cache embedded utility resources per utility.
2026-10-06 17:08:13 +02:00
pre-commit-ci[bot] 4cb771dc83 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/streetsidesoftware/cspell-cli: v10.2.0 → v10.3.0](https://github.com/streetsidesoftware/cspell-cli/compare/v10.2.0...v10.3.0)
2026-10-06 15:15:30 +02:00
Sichen f29e3086dd *sum: accept blanks around '=' when checking tagged lines
GNU accepts any blanks, or none, on either side of the '=' of a
tagged line, with or without a space before the '(': "MD5(f) = D",
"MD5 (f)= D", "MD5 (f) =D" and "MD5 (f)<TAB>=<TAB>D" are all
checked. uutils only accepted "MD5 (f) = D" and "MD5(f)= D", and
reported the other lines as improperly formatted.

End the file name at the last ')' and skip the blanks around the
'='. If the text before the '(' is all hex digits, keep the exact
separators: "<HEX DIGEST> (a)= b" is an untagged line with a single
space, and must still be read as one.

Update the parser tests that expected such lines to be rejected,
and add tests for these lines, for lines that must stay rejected
as in GNU (a form feed or carriage return next to the '=', two
spaces or a tab before the '('), and for the hex digest case.
2026-10-06 10:06:56 +02:00
Sichen 968853a909 timeout: accept a command and arguments that are not valid UTF-8
COMMAND and its arguments were read as String, so argument parsing
failed when any value was not valid UTF-8. Read them as OsString so
they reach the child unchanged, as they do with GNU timeout.

DURATION, --signal and --kill-after remain text values. A non-UTF-8
value there still exits 125.
2026-10-06 09:37:15 +02:00
oech3 ded92e1fb1 CICD.yml: merge use_libc test to a matrix 2026-10-06 09:10:28 +02:00
xtqqczze 77a53d309f refactor(mkdir): simplify create_dir 2026-10-06 09:00:57 +02:00
oech3 2c42e7fce3 CICD.yml: drop already fixed todo 2026-10-06 08:48:44 +02:00
xtqqczze 072331e88c Revert "tail: stop reading past the original end of file"
This reverts commit 781ddfc58c.
2026-10-06 07:51:19 +02:00
Jake Abendroth 50b4911bb2 tests: cp: skip the --link mode test on Android 2026-10-06 07:47:31 +02:00
Sylvestre Ledru 9768800eb4 ci: test with rustix libc backend on Linux 2026-10-05 23:29:24 +02:00
Sylvestre Ledru a185142fda timeout: exit with 128+9 when the timeout signal is KILL
identified here https://efraingaray.com/en/blog/rust-coreutils-contra-gnu/
2026-10-05 23:27:43 +02:00
Jake Abendroth 065068a1e3 cp: don't change the source's mode with --link
After creating a hard link, cp -l still ran the final chmod meant for newly
copied files on the destination. Since the link shares the source's inode,
this changed the mode of the source file: under umask 077 a 755 source became
700, and with -f over an existing file the source took the old destination's
mode. GNU cp leaves the linked file untouched. Skip that chmod in link mode.
2026-10-05 23:17:10 +02:00
Jake Abendroth 471cc8a692 tail: read the first block of files sized a multiple of 64 KiB
When reading a regular file backwards for `tail -n`, the block closest
to the start of the file was sized as `size % BLOCK_SIZE`, which is 0
when the file size is an exact multiple of 65536 bytes. That block was
then never scanned: a 65536-byte file gave no output for `tail -n 1`,
and larger files lost their first 64 KiB whenever the requested lines
reached into it.

Size the first block as whatever remains after the full blocks, so a
zero remainder means a full block.
2026-10-05 23:14:02 +02:00
Zhaoqi Xu b98fb04f4d uucore: print "Operation not permitted" for EPERM
Rust maps both EACCES and EPERM to ErrorKind::PermissionDenied, so
UIoError always said "Permission denied". GNU uses "Operation not
permitted" for EPERM (e.g. touch on a writable file owned by someone
else). On unix, prefer the raw errno when it is EPERM.

Add a uucore unit test, an integration test for `touch -d` on a
root-owned file, and accept "Operation not permitted" in the unlink
directory test for macOS/BSD.

Fixes #15020
2026-10-05 22:22:44 +02:00
Charly Morgand-Poyac 4bbc649919 tr: write to stdout without line buffering
Stdout is line buffered: every chunk was searched for its last newline,
and the bytes after it cost an extra write. Write to the file
descriptor directly, as cat and tee do.

Keep write_output out of line: once inlined into the per-byte loop of
translate_input, it made the translator state go to memory on every
byte, doubling the time of tr -s.

Give test_broken_pipe_no_error more than a pipe buffer to write: it
only hit the broken pipe when the output came late, which was already
racy on main (1 failure in 60 runs) and became frequent here.

Mean of 30 paired runs on a pinned core, 100 MB input:

                          before     after
  tr -d '\n'   (text)   36.23 ms  32.64 ms
  tr -d '\r\n' (CSV)    35.66 ms  31.94 ms
2026-10-05 22:18:45 +02:00
Charly Morgand-Poyac 063673c173 tr: write unchanged chunks as they are
When deleting or replacing a single byte, a chunk without it was still
copied to the output buffer before being written. ChunkProcessor now
returns the bytes to write, so such a chunk is written from the input.

Mean of 30 paired runs on a pinned core, 100 MB of text without CR:

                   before   after
  tr -d '\r'      8.54 ms  7.67 ms
  tr '\r' '\n'    8.84 ms  7.97 ms
2026-10-05 22:18:45 +02:00
Charly Morgand-Poyac 58b7c5a5e2 tr: find the single byte to delete or replace once
The single byte to delete or replace was looked up in the whole table,
with a Vec allocation, on every read. Do it once when building the
operation.

About 1,300 fewer instructions per 32 KiB read: up to 3% faster when
nothing is deleted, 7% fewer instructions on the single byte replace
benchmark, noise otherwise.
2026-10-05 22:18:45 +02:00
Charly Morgand-Poyac 0821f40108 tr: speed up deleting bytes
Deleting filtered bytes with a branch per byte, which mispredicts on
real data. Store every byte in a small block and only advance past the
kept ones. After a block that kept almost nothing, go back to the
branch: it is then well predicted and stores less. When the single
byte to delete is rare, copy the runs between its occurrences instead.

Add a benchmark for deleting a single byte.

Mean of 40 runs in ms, 100 MB input unless noted (Ryzen 9 9950X,
GNU 9.12, pinned core, hyperfine -N):

                                GNU   trunk   opti
  tr -d ,  (CSV)               90.1    87.0   33.7
  tr -d ' '                   118.0   109.2   33.8
  tr -d '\n'                   47.8    57.8   37.0
  tr -d '\r'  (CRLF, 16 MB)     7.4     8.9    5.7
  tr -d aeiou                 272.4   261.0   32.9
  tr -cd 'a-z\n'              130.5   137.9   32.9
  tr -cd '[:print:]' (binary) 332.0   317.6   35.0
2026-10-05 22:18:45 +02:00
xtqqczze 9caa727a54 refactor: update path checks to use as_os_str().is_empty() 2026-10-05 18:51:17 +02:00
Daniel Hofstetter de6f937835 Bump yoke-derive from 0.8.3 to 0.8.4
because 0.8.3 got yanked
2026-10-05 18:50:48 +02:00