Commit Graph
5389 Commits
Author SHA1 Message Date
Christoph Böhmwalder e8460fa78e dd: align the read buffer for O_DIRECT (iflag=direct)
The read scratch had no alignment guarantee beyond
`align_of::<u8>() == 1`. Block devices that enforce a strict
`dma_alignment` (e.g. `sd`, `loop`, `virtio_blk`, `nbd`, `zram`, which
all default to 511) reject O_DIRECT reads whose user buffer is below
that alignment with EINVAL.

Wrap the read scratch in `AlignedBuf`, which over-allocates the zeroed
buffer from `alloc_copy_buffer` by one 4 KiB alignment unit and slices
at the first aligned byte, so the pages still arrive zeroed from the
kernel and are not faulted in before the first read. No `unsafe`
involved.

`fill_consecutive` and `fill_blocks` now take `&mut [u8]` and report
the buffer length (read bytes for the former; reads + padding for the
latter) so the caller can slice without `Vec::truncate`. `read_helper`
returns the data slice directly: into `read_buf` for the common path,
or into a separate `Vec` scratch for `conv=block` / `conv=unblock`,
which can change the byte count and so cannot be done in place. This
also removes the truncate-and-regrow cycle that used to re-fault the
buffer after a short read.

Taken over from #12143 by Christoph Böhmwalder: rebased, storage
switched from `#[repr(align)]` pages to over-allocate-and-offset on
top of `alloc_copy_buffer`, and unit tests for `AlignedBuf` plus an
integration test reading a regular file with `iflag=direct` added.

Closes #12143.
Closes #12085.
Fixes https://bugs.launchpad.net/ubuntu/+source/rust-coreutils/+bug/2125968
2026-08-24 21:12:00 +02:00
Sylvestre Ledru f2634b4c26 stdbuf: fix the Windows build and report signalled commands
PathBuf lost its import when the exec() use was removed, and the 0700
tempdir helpers were gated on the feature alone rather than on Unix.
The external-libstdbuf path no longer creates a temp directory it
immediately throws away, and waiting on the child now maps a signal
death to 128+signal so the caller still sees what exec() would have
shown it.
2026-08-25 17:24:00 +02:00
Etienne CordonnierandCursor b96a00f5c6 stdbuf: create embedded libstdbuf with mode 0600 on Unix
Open the injected shared library with an explicit mode so umask 0 cannot
leave a world-writable .so in the private temp directory.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-25 17:24:00 +02:00
Sylvestre Ledru ad2c741680 stdbuf: fix tmpdir leak and world-readable permissions
Two security/correctness issues reported in #13939:

1. Leaked temporary directories: using exec() replaced the stdbuf
   process before TempDir's destructor could run, leaving one
   .tmp* directory per invocation in $TMPDIR forever.
   Fix: use spawn() + wait() so the parent process survives to drop
   the TempDir after the child exits.

2. World-readable temporary directory: the tmpdir was created with
   default permissions, making libstdbuf.so writable by any user on
   a multi-user system (privilege-escalation risk).
   Fix: call set_permissions(0o700) immediately after creation,
   bypassing the umask.

Both fixes apply only when feat_external_libstdbuf is not set
(i.e. the embedded .so path).
2026-08-25 17:24:00 +02:00
Nikola Lukovic 0688cbfc17 df: pin the Windows -i notice in the tests 2026-08-25 16:55:12 +02:00
mtvb 4c565eb5da Fix for Lines fuse if chunk boundary is exactly at EOF #14126 2026-08-25 16:54:46 +02:00
Daniel Hofstetter 87b61f8c61 pr: add --join-lines as long option for -J 2026-08-25 16:53:36 +02:00
Daniel Hofstetter 49042676eb pr: rename "--column" to "--columns" 2026-08-25 16:12:53 +02:00
Devel 357ad44175 tee: show_err instead of writing directly in stderr and strip error 2026-08-25 15:40:07 +02:00
Coro c22ee2421d printf: avoid panic on %s/%c field width above u16::MAX
write_padded padded with write!("{: <padlen$}"), which panics once the
dynamic width exceeds u16::MAX. Write the padding spaces directly as bytes so
that %s and %c field widths above that bound work, resolving the existing TODO
in the string arm. Adds a regression test.

Fixes #12593. Fixes #12900.
2026-08-25 11:01:04 +02:00
Coro 88be4e4f82 numfmt: reject a leading '+' and scientific notation to match GNU
GNU numfmt rejects a number with a leading '+' sign ("+5") as an invalid
number, and rejects scientific notation ("1e-3") as an invalid suffix in
input. Rust's i128 and f64 parsers accept both, so numfmt silently accepted
them and printed a wrong value with exit 0. Reject them in parse_number_part,
mirroring GNU's two distinct diagnostics.
2026-08-25 10:28:22 +02:00
Coro 8eec67be23 pr: make -n/--number-lines argument optional to match GNU
GNU pr treats -n/--number-lines as optional: a bare -n numbers the lines with a
5-wide, tab-separated line number. uutils required a value, so `pr -t -n` failed.
Set num_args(0..=1); the existing fallback supplies the default numbering mode.
2026-08-25 10:11:10 +02:00
mtvb 03178084c6 Split enters endless loop fix #14118 (#14123) 2026-08-25 08:36:40 +02:00
Sylvestre Ledru d989097cf5 dd: point the flag help at the flags, not the commas
An unknown conv=/iflag=/oflag= flag was met with a help line about
separating flags with commas, when the commas were fine and the flag
name was not. Each now labels the span and lists what it accepts.
2026-08-24 22:18:26 +02:00
Sylvestre Ledru 56eccff8ef dd: match GNU's wording for the parse errors
An invalid oflag= flag was reported as an input flag, and the rest read
like debug output: "Unrecognized conv=CONV -> zap" where GNU says
"invalid conversion: 'zap'". The messages now match GNU byte for byte,
usage hint included.
2026-08-24 22:18:26 +02:00
Sylvestre Ledru 7f9b9a6f08 dd: reject a number that does not fit in u64
A size past u64 saturated to u64::MAX instead of failing, so count= and
skip= took a bogus value: dd copied the whole input and exited 0 where
GNU rejects the operand.
2026-08-24 22:18:26 +02:00
oech3 71ebb922b3 chroot: strip errno 2026-08-24 14:47:33 +02:00
Daniel Hofstetter 6c6adf6c95 tests: use convenience fns to ensure empty output 2026-08-24 14:41:05 +02:00
Devel a9b64fcf20 ls: exit with code 2 on write error
ls: add test_write_error
2026-08-24 14:03:39 +02:00
Luan Taraschi 2e48ff5318 pr: stop dropping lines the columns do not divide evenly
to_table_short_file built the table with lines.len() / columns rows, so a
page whose line count is not a multiple of the column count lost the
remainder. `seq 9 | pr -2` dropped the ninth line, and a page holding fewer
lines than it has columns came out empty.

Spread the lines the way GNU pr does instead: every column takes the ceiling
of what is still unplaced over the number of columns left to fill, which
leaves nothing over and keeps the longer columns on the left.

Two things followed from that. The short-file branch was tested before the
across-mode branch, so `pr -a` read a partly filled page downwards, and the
last row of such a page needs its line terminator without a trailing column
separator.
2026-08-24 11:09:14 +02:00
Sylvestre Ledru cb2cf44b7e test: disable test_hard_link_is_same_file on Android
Claude-Session: https://claude.ai/code/session_01YVVa2fkrmpA2bsDQFExEVc
2026-08-24 00:05:12 +02:00
Daniel Hofstetter 1443202935 uptime: disable some tests on Android 2026-08-24 00:05:12 +02:00
Sylvestre Ledru e0d16659be stat: print the format up to a bad directive
GNU interprets the format as it prints, so `stat -c '%d%.3' f` writes the
device number before failing; we parsed the whole format up front and
printed nothing at all. Keep the tokens parsed before the bad directive
and raise the error from the printing loop instead, flushing stdout so the
caret report still follows the output it belongs to.

Fixes #14101
2026-08-23 23:06:01 +02:00
Sylvestre Ledru ff382f5279 id: order groups= by effective gid and -G by real gid, like GNU
GNU heads the two forms with opposite gids: `groups=` with the effective
gid, `-G` with the real gid then the effective one. Both were derived
from the same `gid` local, so only one could be right.

Only observable when the real and effective gids differ, e.g. under
`setpriv --regid=A --egid=B`. `-r` still does not affect `-G`.
2026-08-23 21:10:27 +02:00
Luan Taraschi 36947fc913 sort: refuse a random source shorter than the salt
--random-source exists so a shuffle can be reproduced from a file, but
salt_from_random_source hashed whatever it managed to read and never
checked the length. An empty file, or any file under 16 bytes, produced
a salt the file did not supply and sort shuffled with it, exit 0.

GNU wants the same 128 bits and reports "end of file" with exit 2 below
that, whatever the size of the input. shuf already stops on a short
source; sort was the one that did not.
2026-08-22 16:37:11 +02:00