diff --git a/src/uu/base32/src/base_common.rs b/src/uu/base32/src/base_common.rs index 79f6435eb46..5694696db42 100644 --- a/src/uu/base32/src/base_common.rs +++ b/src/uu/base32/src/base_common.rs @@ -8,7 +8,7 @@ use clap::{Arg, ArgAction, Command}; use std::ffi::OsString; use std::fs::File; -use std::io::{self, BufRead, BufReader, Write}; +use std::io::{self, BufRead, BufReader, BufWriter, Write}; use std::path::{Path, PathBuf}; use uucore::display::Quotable; use uucore::encoding::{ @@ -29,8 +29,7 @@ pub const BASE_CMD_PARSE_ERROR: i32 = 1; /// This default is only used if no "-w"/"--wrap" argument is passed pub const WRAP_DEFAULT: usize = 76; -// Fixed to 8 KiB (equivalent to `std::sys::io::DEFAULT_BUF_SIZE` on most targets) -pub const DEFAULT_BUF_SIZE: usize = 8 * 1024; +pub const DEFAULT_BUF_SIZE: usize = 32 * 1024; pub struct Config { pub decode: bool, @@ -194,6 +193,22 @@ pub fn handle_input(input: &mut R, format: Format, config: Config) - supports_fast_decode_and_encode_ref, config.ignore_garbage, ), + // Batch Base16's small encoded chunks to reduce write syscalls. + (Format::Base16, false) => { + let mut output = BufWriter::with_capacity(DEFAULT_BUF_SIZE, &mut stdout_lock); + let result = fast_encode::fast_encode_stream( + input, + &mut output, + supports_fast_decode_and_encode_ref, + config.wrap_cols, + ); + + match (result, output.flush()) { + (res, Ok(())) => res, + (Ok(_), Err(err)) => Err(err.into()), + (Err(original), Err(_)) => Err(original), + } + } (_, false) => fast_encode::fast_encode_stream( input, &mut stdout_lock, diff --git a/tests/by-util/test_basenc.rs b/tests/by-util/test_basenc.rs index ff3b7f43335..af4f9e070ab 100644 --- a/tests/by-util/test_basenc.rs +++ b/tests/by-util/test_basenc.rs @@ -188,6 +188,19 @@ fn test_base16() { .stdout_only("48656C6C6F2C20576F726C6421\n"); } +// This test fails if the Base16 output buffer is not explicitly flushed. +#[test] +#[cfg(target_os = "linux")] +#[cfg_attr(wasi_runner, ignore = "WASI sandbox: host paths not visible")] +fn test_base16_write_error_is_reported() { + new_ucmd!() + .arg("--base16") + .pipe_in("Hello, World!") + .set_stdout(std::fs::File::create("/dev/full").unwrap()) + .fails() + .stderr_is("basenc: No space left on device\n"); +} + #[test] fn test_base16_decode() { new_ucmd!()