There are two things about this patch that I am unsure about.
When we receive a write error, should we attempt to restore the
default terminal colors? The write to standard output will almost
certainly not work, but is it worth a shot anyways?
Second, I am not really sure of a test case to add for this. Doing
'ls -R $HOME' or 'ls -R /' should take long enough, but I would rather
not access anything outside of the checkout or $TMPDIR in the test suite.
Any ideas?
--- 8< ---
This is most noticeable when using 'ls -1 --sort=none' to list a
directory containing many files:
$ mkdir -p tmp && cd tmp
$ seq 10000000 | parallel -m 'truncate -s 0 {}'
$ env time --quiet --format=%E ls -1 --sort=none > /dev/full
ls: write error: No space left on device
0:03.28
$ env time --quiet --format=%E ../src/ls -1 --sort=none > /dev/full
ls: write error: No space left on device
0:00.00
It is also noticeable when listing many directories, e.g., when
operating recursively, and when information from 'stat' is needed:
$ mkdir -p tmp && cd tmp
$ parallel 'mkdir -p {}; cd {}; truncate -s 0 $(seq 10000)' \
::: {1..100}
$ env time --quiet --format=%E ls -Rl > /dev/full
ls: write error: No space left on device
4:18.65
$ env time --quiet --format=%E ../src/ls -Rl > /dev/full
ls: write error: No space left on device
0:00.02
$ env time --quiet --format=%E ls -RC > /dev/full
ls: write error: No space left on device
0:09.51
$ env time --quiet --format=%E ../src/ls -RC > /dev/full
ls: write error: No space left on device
0:00.09
$ env time --quiet --format=%E ls -Rx > /dev/full
ls: write error: No space left on device
0:08.65
$ env time --quiet --format=%E ../src/ls -Rx > /dev/full
ls: write error: No space left on device
0:00.08
$ env time --quiet --format=%E ls -Rm > /dev/full
ls: write error: No space left on device
0:08.19
$ env time --quiet --format=%E ../src/ls -Rm > /dev/full
ls: write error: No space left on device
0:00.08
* src/ls.c (print_dir, print_long_format, print_file_name_and_frills):
Check if standard output has it's error flag set after printing
information for each file.
* NEWS: Mention the improvement.
---
NEWS | 3 +++
src/ls.c | 14 ++++++++++++++
2 files changed, 17 insertions(+)
diff --git a/NEWS b/NEWS
index 7bd3c9b34..a24c0c261 100644
--- a/NEWS
+++ b/NEWS
@@ -81,6 +81,9 @@ GNU coreutils NEWS -*-
outline -*-
'du' now processes directories with 10,000 or more entries up to 9 times
faster on the Lustre file system.
+ 'ls' now exit promptly upon receiving a write errors, which is significant
+ when listing many directories (e.g., 'ls -R').
+
'pinky' will now exit immediately upon receiving a write error, which is
significant when reading large plan or project files.
diff --git a/src/ls.c b/src/ls.c
index b349c74dc..183623500 100644
--- a/src/ls.c
+++ b/src/ls.c
@@ -3019,6 +3019,10 @@ print_dir (char const *name, char const *realname, bool
command_line_arg)
free (absolute_name);
dired_outstring (":\n");
+
+ /* Check for an output error here, otherwise errno will be clobbered. */
+ if (ferror (stdout))
+ write_error ();
}
/* Read the directory entries, and insert the subfiles into the 'cwd_file'
@@ -4438,6 +4442,11 @@ print_long_format (const struct fileinfo *f)
}
else if (indicator_style != none)
print_type_indicator (f->stat_ok, f->stat.st_mode, f->filetype);
+
+ /* Check for write errors after each file. Otherwise we may spend a lot of
+ time doing pointless writes when a directory contains many entries. */
+ if (ferror (stdout))
+ write_error ();
}
/* Write to *BUF a quoted representation of the file name NAME, if non-null,
@@ -4838,6 +4847,11 @@ print_file_name_and_frills (const struct fileinfo *f,
size_t start_col)
if (indicator_style != none)
width += print_type_indicator (f->stat_ok, f->stat.st_mode, f->filetype);
+ /* Check for write errors after each file. Otherwise we may spend a lot of
+ time doing pointless writes when a directory contains many entries. */
+ if (ferror (stdout))
+ write_error ();
+
return width;
}
--
2.52.0