diff --git a/src/uu/fold/src/fold.rs b/src/uu/fold/src/fold.rs index 2eb97933180..f0a8c005965 100644 --- a/src/uu/fold/src/fold.rs +++ b/src/uu/fold/src/fold.rs @@ -572,41 +572,57 @@ fn fold_file( mode: WidthMode, writer: &mut W, ) -> UResult<()> { - let mut line = Vec::new(); let mut output = Vec::new(); let mut col_count = 0; let mut last_space = None; loop { - if file - .read_until(NL, &mut line) - .map_err_context(|| translate!("fold-error-readline"))? - == 0 - { + let buffer = file + .fill_buf() + .map_err_context(|| translate!("fold-error-read"))?; + + if buffer.is_empty() { break; } - let mut ctx = FoldContext { - spaces, - width, - mode, - writer, - output: &mut output, - col_count: &mut col_count, - last_space: &mut last_space, - }; + let len = buffer.len(); + let mut consume_len = len; - match std::str::from_utf8(&line) { - Ok(s) => process_utf8_line(s, &mut ctx)?, - Err(_) => process_non_utf8_line(&line, &mut ctx)?, + if let Some(pos) = buffer.iter().position(|&b| b == b'\n') { + consume_len = pos + 1; + } else if let Err(e) = std::str::from_utf8(buffer) { + if e.error_len().is_none() { + let valid = e.valid_up_to(); + if valid > 0 { + consume_len = valid; + } + } } - line.clear(); - } + { + let chunk = &buffer[..consume_len]; + + let mut ctx = FoldContext { + spaces, + width, + mode, + writer, + output: &mut output, + col_count: &mut col_count, + last_space: &mut last_space, + }; - if !output.is_empty() { - writer.write_all(&output)?; - output.clear(); + match std::str::from_utf8(chunk) { + Ok(s) => process_utf8_line(s, &mut ctx)?, + Err(_) => process_non_utf8_line(chunk, &mut ctx)?, + } + } + file.consume(consume_len); + + if !output.is_empty() { + writer.write_all(&output)?; + output.clear(); // Keeps capacity, avoiding re-allocation + } } Ok(()) diff --git a/tests/by-util/test_fold.rs b/tests/by-util/test_fold.rs index 9497044c910..7d6c13596c9 100644 --- a/tests/by-util/test_fold.rs +++ b/tests/by-util/test_fold.rs @@ -632,3 +632,13 @@ fn test_fullwidth_characters() { .succeeds() .stdout_is(format!("{e_fullwidth}\n{e_fullwidth}")); } + +#[cfg(unix)] +#[test] +fn test_fold_dev_null() { + new_ucmd!() + .arg("/dev/null") + .succeeds() + .no_stderr() + .stdout_only(""); +}