mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
tac: use temp file for stdin to respect TMPDIR and handle disk-full errors (#10094)
This commit is contained in:
@@ -215,3 +215,4 @@ TUNABLES
|
||||
tunables
|
||||
VMULL
|
||||
vmull
|
||||
tmpfs
|
||||
|
||||
Generated
+1
@@ -3968,6 +3968,7 @@ dependencies = [
|
||||
"memchr",
|
||||
"memmap2",
|
||||
"regex",
|
||||
"tempfile",
|
||||
"thiserror 2.0.17",
|
||||
"uucore",
|
||||
]
|
||||
|
||||
Generated
+36
-53
@@ -103,9 +103,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bigdecimal"
|
||||
version = "0.4.9"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "560f42649de9fa436b73517378a147ec21f6c997a546581df4b4b31677828934"
|
||||
checksum = "4d6867f1565b3aad85681f1015055b087fcfd840d6aeee6eee7f2da317603695"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"libm",
|
||||
@@ -184,9 +184,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.19.0"
|
||||
version = "3.19.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
||||
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
|
||||
|
||||
[[package]]
|
||||
name = "bytecount"
|
||||
@@ -196,9 +196,9 @@ checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.48"
|
||||
version = "1.2.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c481bdbf0ed3b892f6f806287d72acd515b352a4ec27a208489b8c1bc839633a"
|
||||
checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"jobserver",
|
||||
@@ -231,18 +231,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.53"
|
||||
version = "4.5.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8"
|
||||
checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.53"
|
||||
version = "4.5.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00"
|
||||
checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -323,30 +323,13 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d"
|
||||
dependencies = [
|
||||
"crc-catalog",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc-catalog"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
|
||||
|
||||
[[package]]
|
||||
name = "crc-fast"
|
||||
version = "1.8.0"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2f7c8d397a6353ef0c1d6217ab91b3ddb5431daf57fd013f506b967dcf44458"
|
||||
checksum = "e75b2483e97a5a7da73ac68a05b629f9c53cff58d8ed1c77866079e18b00dba5"
|
||||
dependencies = [
|
||||
"crc",
|
||||
"digest",
|
||||
"rustversion",
|
||||
"spin",
|
||||
]
|
||||
|
||||
@@ -515,9 +498,9 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.5"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844"
|
||||
checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
@@ -753,9 +736,9 @@ checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties"
|
||||
version = "2.1.1"
|
||||
version = "2.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99"
|
||||
checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
|
||||
dependencies = [
|
||||
"icu_collections",
|
||||
"icu_locale_core",
|
||||
@@ -767,9 +750,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties_data"
|
||||
version = "2.1.1"
|
||||
version = "2.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899"
|
||||
checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
|
||||
|
||||
[[package]]
|
||||
name = "icu_provider"
|
||||
@@ -850,9 +833,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "jiff-tzdb"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1283705eb0a21404d2bfd6eef2a7593d240bc42a0bdb39db0ad6fa2ec026524"
|
||||
checksum = "68971ebff725b9e2ca27a601c5eb38a4c5d64422c4cbab0c535f248087eda5c2"
|
||||
|
||||
[[package]]
|
||||
name = "jiff-tzdb-platform"
|
||||
@@ -1119,9 +1102,9 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.11.1"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
|
||||
checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic-util"
|
||||
@@ -1154,9 +1137,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.103"
|
||||
version = "1.0.105"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
|
||||
checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -1187,9 +1170,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.42"
|
||||
version = "1.0.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
|
||||
checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -1273,9 +1256,9 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
|
||||
checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
@@ -1292,9 +1275,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||
|
||||
[[package]]
|
||||
name = "self_cell"
|
||||
version = "1.2.1"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16c2f82143577edb4921b71ede051dac62ca3c16084e918bf7b40c96ae10eb33"
|
||||
checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
@@ -1366,9 +1349,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.7"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||
checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
|
||||
|
||||
[[package]]
|
||||
name = "similar"
|
||||
@@ -1417,9 +1400,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.111"
|
||||
version = "2.0.113"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
|
||||
checksum = "678faa00651c9eb72dd2020cbdf275d92eccb2400d568e419efdd64838145cb4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1439,9 +1422,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.23.0"
|
||||
version = "3.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16"
|
||||
checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.3.4",
|
||||
|
||||
@@ -27,6 +27,7 @@ clap = { workspace = true }
|
||||
uucore = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
fluent = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "tac"
|
||||
|
||||
+40
-7
@@ -13,6 +13,7 @@ use std::ffi::OsString;
|
||||
use std::io::{BufWriter, Read, Write, stdin, stdout};
|
||||
use std::{
|
||||
fs::{File, read},
|
||||
io::copy,
|
||||
path::Path,
|
||||
};
|
||||
use uucore::error::UError;
|
||||
@@ -241,14 +242,22 @@ fn tac(filenames: &[OsString], before: bool, regex: bool, separator: &str) -> UR
|
||||
mmap = mmap1;
|
||||
&mmap
|
||||
} else {
|
||||
let mut buf1 = Vec::new();
|
||||
if let Err(e) = stdin().read_to_end(&mut buf1) {
|
||||
let e: Box<dyn UError> = TacError::ReadError(OsString::from("stdin"), e).into();
|
||||
show!(e);
|
||||
continue;
|
||||
// Copy stdin to a temp file (respects TMPDIR), then mmap it.
|
||||
// Falls back to Vec buffer if temp file creation fails (e.g., bad TMPDIR).
|
||||
match buffer_stdin() {
|
||||
Ok(StdinData::Mmap(mmap1)) => {
|
||||
mmap = mmap1;
|
||||
&mmap
|
||||
}
|
||||
Ok(StdinData::Vec(buf1)) => {
|
||||
buf = buf1;
|
||||
&buf
|
||||
}
|
||||
Err(e) => {
|
||||
show!(TacError::ReadError(OsString::from("stdin"), e));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
buf = buf1;
|
||||
&buf
|
||||
}
|
||||
} else {
|
||||
let path = Path::new(filename);
|
||||
@@ -304,6 +313,30 @@ fn try_mmap_stdin() -> Option<Mmap> {
|
||||
unsafe { Mmap::map(&stdin()).ok() }
|
||||
}
|
||||
|
||||
enum StdinData {
|
||||
Mmap(Mmap),
|
||||
Vec(Vec<u8>),
|
||||
}
|
||||
|
||||
/// Copy stdin to a temp file, then memory-map it.
|
||||
/// Falls back to reading directly into memory if temp file creation fails.
|
||||
fn buffer_stdin() -> std::io::Result<StdinData> {
|
||||
// Try to create a temp file (respects TMPDIR)
|
||||
if let Ok(mut tmp) = tempfile::tempfile() {
|
||||
// Temp file created - copy stdin to it, then read back
|
||||
copy(&mut stdin(), &mut tmp)?;
|
||||
// SAFETY: If the file is truncated while we map it, SIGBUS will be raised
|
||||
// and our process will be terminated, thus preventing access of invalid memory.
|
||||
let mmap = unsafe { Mmap::map(&tmp)? };
|
||||
Ok(StdinData::Mmap(mmap))
|
||||
} else {
|
||||
// Fall back to reading directly into memory (e.g., bad TMPDIR)
|
||||
let mut buf = Vec::new();
|
||||
stdin().read_to_end(&mut buf)?;
|
||||
Ok(StdinData::Vec(buf))
|
||||
}
|
||||
}
|
||||
|
||||
fn try_mmap_path(path: &Path) -> Option<Mmap> {
|
||||
let file = File::open(path).ok()?;
|
||||
|
||||
|
||||
@@ -335,3 +335,15 @@ fn test_failed_write_is_reported() {
|
||||
.fails()
|
||||
.stderr_is("tac: failed to write to stdout: No space left on device (os error 28)\n");
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[test]
|
||||
fn test_stdin_bad_tmpdir_fallback() {
|
||||
// When TMPDIR is invalid, tac falls back to reading stdin directly into memory
|
||||
new_ucmd!()
|
||||
.env("TMPDIR", "/nonexistent/dir")
|
||||
.arg("-")
|
||||
.pipe_in("a\nb\nc\n")
|
||||
.succeeds()
|
||||
.stdout_is("c\nb\na\n");
|
||||
}
|
||||
|
||||
@@ -12,3 +12,6 @@ curl -L ${repo}/raw/refs/heads/master/tests/csplit/csplit-io-err.sh > tests/cspl
|
||||
curl -L ${repo}/raw/refs/heads/master/tests/stty/bad-speed.sh > tests/stty/bad-speed.sh
|
||||
# Avoid incorrect PASS
|
||||
curl -L ${repo}/raw/refs/heads/master/tests/runcon/runcon-compute.sh > tests/runcon/runcon-compute.sh
|
||||
curl -L ${repo}/raw/refs/heads/master/tests/tac/tac-continue.sh > tests/tac/tac-continue.sh
|
||||
# Add tac-continue.sh to root tests (it requires root to mount tmpfs)
|
||||
sed -i 's|tests/split/l-chunk-root.sh.*|tests/split/l-chunk-root.sh\t\t\t\\\n tests/tac/tac-continue.sh\t\t\t\\|' tests/local.mk
|
||||
|
||||
Reference in New Issue
Block a user