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


Reply via email to