146 Commits
Author SHA1 Message Date
xtqqczze 36715a4cf7 clippy: fix single_char_pattern lint
https://rust-lang.github.io/rust-clippy/master/#single_char_pattern
2026-10-10 16:18:43 +02:00
Sylvestre Ledru 7c53fd09b5 find: render expression errors under UUTILS_DIAG
Underline the offending argument through `uucore::diagnostics` when
stderr is a terminal or `UUTILS_DIAG=always`. The plain line still
leads, and captured output stays the single GNU line.

The report heading comes from uucore's `util_name()`, which keeps the
`.exe` on Windows; the plain line keeps `program_name()` like every
other message.
2026-10-10 16:07:55 +02:00
Sylvestre Ledru 95ebdf6334 find: match GNU's wording for expression errors
Quote the predicate or operator as GNU 4.10.0 does, report an operator
cut off by ')' and an unmatched ')' with GNU's messages, and name a
binary operator as spelled.
2026-10-10 16:07:55 +02:00
youdie006 a3c1335b2f find: cover the sticky bit in the -ls test 2026-10-06 11:19:18 +02:00
youdie006 4d3f0b182e find: show the file type and special bits in -ls
The -ls formatter only knew directories and regular files and ignored
setuid, setgid and sticky bits. Use uucore::fs::display_permissions, as
-printf %M already does.
2026-10-06 11:19:18 +02:00
Sichen f0b2ee9302 find: print a trailing backslash in -printf 2026-09-28 06:54:51 -04:00
Alessio Attilio 015dc1f58a locate, updatedb: use platform-dependent default database path and platform path delimiter 2026-09-26 23:10:20 +02:00
wtcpython 42143b5260 test(printf): align multibyte directive/escape assertions with GNU warning behavior 2026-09-25 15:18:07 +02:00
weili ca78e35ccf find: -printf: advance past a full char in advance_one to avoid a panic
advance_one read a full `char` via front() but then dropped it by slicing one
byte (`&self.string[1..]`). When that char is multibyte (e.g. a `€` after a `%`
conversion, a `\` escape, or a `%A`/`%C`/`%T` time directive), byte index 1 is
not a char boundary and the slice panics. Advance by the char's UTF-8 length so
multibyte input routes through the normal handling instead of aborting.
2026-09-21 14:24:19 +02:00
wtcpython fda8855b73 xargs: reject quotes spanning input lines 2026-09-10 13:47:41 +02:00
Coro 2928b0258a find: reject the deprecated -perm +MODE octal form to match GNU 2026-09-09 15:02:13 +02:00
Jorge Polanco 5df29e0124 test(find): add integration test for -mindepth exceeding -maxdepth
Signed-off-by: Jorge Polanco <55784702+Jorge-Polanco-Roque@users.noreply.github.com>
2026-09-09 14:20:44 +02:00
abhinavmir 3de01a07c1 locate, updatedb, xargs: avoid panic on a non-UTF-8 argument
These three entry points collected their arguments with std::env::args,
which panics when an argument is not valid Unicode. An argument that is
not valid UTF-8 therefore aborted the process with exit code 101 before
any work started.

Collect the arguments with args_os instead, and report the first invalid
argument on stderr with exit code 1, as find already does.
2026-08-25 09:21:50 +02:00
Coro 955282deb6 find: do not double the find: prefix on an invalid -type list 2026-08-21 10:23:01 +02:00
Coro 42ddfb1ea2 find: parse ISO 8601 dates in -newerXt to match GNU 2026-08-20 07:32:48 +02:00
Coro f5f0f64a33 find: reject a signed -maxdepth/-mindepth value to match GNU
convert_arg_to_number parsed the depth with Rust's usize parser, which accepts a
leading '+', so "-maxdepth +1" was silently accepted. GNU find rejects a signed
value there. Only accept plain decimal digits. Adds a test_find.rs test.
2026-08-19 22:42:41 +02:00
amoghsingh130 1acf40a64b find: handle -fprintf write errors without panicking 2026-08-18 21:15:55 +02:00
Coro e1927ac792 find: avoid panic on a non-UTF-8 argument
std::env::args panics on a non-UTF-8 argument. Read the arguments with args_os
and report the first invalid one with a clean error and exit 1, instead of
aborting (#816). Adds a helper unit test and a test_find.rs test.
2026-08-18 21:15:05 +02:00
Sylvestre Ledru d1580035c1 find: reject -files0-from - combined with -ok/-okdir
The starting points and the answers to the prompts would both be read
from standard input, so they compete for the same bytes and the result
depends on buffering. GNU find rejects the combination up front; we
accepted it and prompted, consuming input meant for the caller. The bfs
tests gnu/files0_from_stdin_ok and gnu/ok_files0_from_stdin now pass, and
the former no longer hangs on the testsuite's stdin.

Reading the starting points from a file leaves stdin free for the
prompts, so that combination stays allowed.
2026-08-18 19:20:00 +02:00
Sylvestre Ledru 1e9679cecc find: refuse -execdir/-okdir when $PATH has a relative entry
Both actions run the command after changing into the directory being
scanned, so a relative $PATH entry -- including the empty string and ".",
which mean the current directory -- would be looked up inside a directory
somebody else may be able to write to. GNU find rejects this at parse
time; we ran the command anyway, and for -okdir we first prompted, which
meant reading the answer from whatever stdin happened to be. In the bfs
testsuite that is the harness's own stdin, so gnu/okdir_path_empty hung
and reported no result at all instead of failing (bfs gnu/okdir_path_*
and gnu/execdir_path_* now pass).

An unset $PATH is left alone: the command is then looked up in the
system default path.
2026-08-18 19:20:00 +02:00
Coro 6e4a7fbe90 find: reject a non-numeric prefix in the -size argument (#834)
The -size argument was parsed with an un-anchored regex, so "x5c" or "abc5c"
silently matched the "5c" in the middle. Anchor the regex and allow only the
one extra '+' GNU accepts after the comparison sign, so "++5c"/"-+5c" stay valid
while the junk-prefix and invalid-sign forms are rejected. Adds a test_find.rs
test.
2026-08-18 12:48:46 +02:00
MsfPablo 9e778f12fc -printf: warn on unrecognized directives/escapes instead of dropping or erroring (#818)
Two divergences from GNU find:

- An unrecognized %X directive silently dropped the '%' and printed
  only the following character.
- An unrecognized \X escape was a hard parse error (exit 1) instead of
  a warning.

Both now print a "find: warning: ..." message to stderr and emit the
directive/escape literally (with its '%' or '\' prefix), matching GNU
find's behavior and exit code (0).

Also fixes advance_one(), which sliced the remaining format string at
a fixed 1-byte offset and panicked on multibyte characters (e.g. '€')
immediately after '%' or '\' — using char::len_utf8() instead.

Fixes #815
2026-08-16 21:10:17 +02:00
MsfPabloandPablo Garcia 906427c159 find: stream -files0-from input instead of slurping it (#831)
-files0-from read the whole input into memory with read_to_end before
splitting on NUL, so an endless source such as /dev/urandom or /dev/zero
exhausted memory and produced no output. Read the starting points
incrementally with read_until(0) and walk each one as it is parsed.

Fixes #779

Co-authored-by: Pablo Garcia <pablito@MacBook-Neo-de-Pablo.local>
2026-08-16 21:01:41 +02:00
Kevin BurkeandClaude Opus 5 c4fdf2b233 xargs: don't emit an empty argument for a trailing blank (#829)
When input ended with a blank immediately before its final newline,
xargs passed one extra empty argument to the command:

    $ printf 'aaa \nbbb \n' | xargs printf '[%s]'
    [aaa][bbb][]        # was
    [aaa][bbb]          # GNU findutils 4.10.0, and now

WhitespaceDelimitedArgumentReader::next used one `result.is_empty()`
check to answer two different questions. The whitespace branch broke out
of the loop only if `result` was non-empty, so a delimiter seen before
any token was skipped -- correct for blanks, but it left "we are
mid-token" indistinguishable from "we have not started one". The EOF
branch then used `i == 0` as a proxy for "nothing was consumed", which
is false for a final call that consumes only the trailing newline, so it
flushed a zero-length token. Input ending without a newline happened to
work because nothing was left to consume.

Track that state explicitly with an `in_argument` flag, mirroring
`seen_arg` in GNU's read_line, and test `result.is_empty()` at EOF. A
delimiter now ends an argument only when we are inside one, and EOF
flushes only a non-empty buffer.

This also fixes a second symptom of the same conflation: quoted empty
arguments were dropped mid-stream, since quotes start an argument
without contributing any bytes. `printf '"" x\n'` gave [x] and now gives
[][x], again matching GNU. An unterminated `x ''` at end of input still
yields just [x], as GNU's `if (p == linebuf) return -1` does.

-I/-i is unaffected: with a replace string and no explicit delimiter,
xargs uses the newline-delimited reader instead.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-16 20:57:31 +02:00
✿ Fleur de Blue 7ac06f1df3 fix: make --version output consistent across utilities (#838)
* fix: make --version output consistent across utilities

* Handle `DisplayHelp/DisplayVersion` explicitly

* Add tests
2026-08-16 20:53:19 +02:00