From e0a4a60af52e40e5ee5c7d5f1764150301d3dea9 Mon Sep 17 00:00:00 2001 From: =?utf8?q?P=C3=A1draig=20Brady?=
Date: Sat, 15 Jul 2023 21:23:55 +0100 Subject: [PATCH] cut: promptly diagnose write errors * src/cut.c (cut_bytes): Diagnose errors from fwrite() and putchar(). (cut_fields): Likewise. * tests/misc/write-errors.sh: Enable the test for cut, and augment to cover both cut_bytes() and cut_fields(). * NEWS: Mention the improvement. --- NEWS | 4 ++-- src/cut.c | 32 ++++++++++++++++++++++---------- tests/misc/write-errors.sh | 3 ++- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/NEWS b/NEWS index dc5d21d9b5..8d15f27382 100644 --- a/NEWS +++ b/NEWS @@ -62,8 +62,8 @@ GNU coreutils NEWS -*- outline -*- irrespective of which kernel version coreutils is built against, reinstating that behaviour from coreutils-9.0. - od and uniq will now exit immediately upon receiving a write error, which is - significant when reading large / unbounded inputs. + cut, od, and uniq will now exit immediately upon receiving a write error, + which is significant when reading large / unbounded inputs. split now uses more tuned access patterns for its potentially large input. This was seen to improve throughput by 5% when reading from SSD. diff --git a/src/cut.c b/src/cut.c index 12dfd2299f..476df0943b 100644 --- a/src/cut.c +++ b/src/cut.c @@ -232,7 +232,8 @@ cut_bytes (FILE *stream) if (c == line_delim) { - putchar (c); + if (putchar (c) < 0) + write_error (); byte_idx = 0; print_delimiter = false; current_rp = frp; @@ -252,13 +253,16 @@ cut_bytes (FILE *stream) { if (print_delimiter && is_range_start_index (byte_idx)) { - fwrite (output_delimiter_string, sizeof (char), - output_delimiter_length, stdout); + if (fwrite (output_delimiter_string, sizeof (char), + output_delimiter_length, stdout) + != output_delimiter_length) + write_error (); } print_delimiter = true; } - putchar (c); + if (putchar (c) < 0) + write_error (); } } } @@ -325,7 +329,9 @@ cut_fields (FILE *stream) } else { - fwrite (field_1_buffer, sizeof (char), n_bytes, stdout); + if (fwrite (field_1_buffer, sizeof (char), n_bytes, stdout) + != n_bytes) + write_error (); /* Make sure the output line is newline terminated. */ if (field_1_buffer[n_bytes - 1] != line_delim) putchar (line_delim); @@ -336,7 +342,9 @@ cut_fields (FILE *stream) if (print_kth (1)) { /* Print the field, but not the trailing delimiter. */ - fwrite (field_1_buffer, sizeof (char), n_bytes - 1, stdout); + if (fwrite (field_1_buffer, sizeof (char), n_bytes - 1, stdout) + != n_bytes - 1) + write_error (); /* With -d$'\n' don't treat the last '\n' as a delimiter. */ if (delim == line_delim) @@ -360,14 +368,17 @@ cut_fields (FILE *stream) { if (found_any_selected_field) { - fwrite (output_delimiter_string, sizeof (char), - output_delimiter_length, stdout); + if (fwrite (output_delimiter_string, sizeof (char), + output_delimiter_length, stdout) + != output_delimiter_length) + write_error (); } found_any_selected_field = true; while ((c = getc (stream)) != delim && c != line_delim && c != EOF) { - putchar (c); + if (putchar (c) < 0) + write_error (); prev_c = c; } } @@ -398,7 +409,8 @@ cut_fields (FILE *stream) { if (c == line_delim || prev_c != line_delim || delim == line_delim) - putchar (line_delim); + if (putchar (line_delim) < 0) + write_error (); } if (c == EOF) break; diff --git a/tests/misc/write-errors.sh b/tests/misc/write-errors.sh index 20942e0685..e217c5512b 100755 --- a/tests/misc/write-errors.sh +++ b/tests/misc/write-errors.sh @@ -28,7 +28,8 @@ fi echo "\ cat /dev/zero # TODO: comm -z /dev/zero /dev/zero -# TODO: cut -z -c1- /dev/zero +cut -z -c1- /dev/zero +cut -z -f1- /dev/zero dd if=/dev/zero expand /dev/zero factor --version; yes 1 | factor -- 2.47.2