split: exit when we can no longer write to a --filter
authorPádraig Brady <P@draigBrady.com>
Fri, 20 May 2011 00:26:41 +0000 (01:26 +0100)
committerPádraig Brady <P@draigBrady.com>
Wed, 25 May 2011 23:12:05 +0000 (00:12 +0100)
* src/split.c (bytes_split): Stop reading when we
can no longer write to a child process.
(lines_rr): Likewise.
(lines_bytes_split): No change is made here since
input is bounded by the original file size.
* test/split/filter: Add test cases.

src/split.c
tests/split/filter

index 3f92538..5e203f1 100644 (file)
@@ -462,6 +462,12 @@ bytes_split (uintmax_t n_bytes, char *buf, size_t bufsize, uintmax_t max_files)
               cwrite (new_file_flag, bp_out, w);
               opened += new_file_flag;
               new_file_flag = !max_files || (opened < max_files);
+              if (!new_file_flag && ignorable (errno))
+                {
+                  /* If filter no longer accepting input, stop reading.  */
+                  n_read = 0;
+                  break;
+                }
               bp_out += w;
               to_read -= w;
               to_write = n_bytes;
@@ -817,6 +823,7 @@ static void
 lines_rr (uintmax_t k, uintmax_t n, char *buf, size_t bufsize)
 {
   bool wrapped = false;
+  bool wrote = false;
   bool file_limit;
   size_t i_file;
   of_t *files IF_LINT (= NULL);
@@ -903,6 +910,9 @@ lines_rr (uintmax_t k, uintmax_t n, char *buf, size_t bufsize)
               else if (fwrite (bp, to_write, 1, files[i_file].ofile) != 1
                        && ! ignorable (errno))
                 error (EXIT_FAILURE, errno, "%s", files[i_file].of_name);
+              if (! ignorable (errno))
+                wrote = true;
+
               if (file_limit)
                 {
                   if (fclose (files[i_file].ofile) != 0 && ! ignorable (errno))
@@ -913,6 +923,10 @@ lines_rr (uintmax_t k, uintmax_t n, char *buf, size_t bufsize)
               if (next && ++i_file == n)
                 {
                   wrapped = true;
+                  /* If no filters are accepting input, stop reading.  */
+                  if (! wrote)
+                    goto no_filters;
+                  wrote = false;
                   i_file = 0;
                 }
             }
@@ -921,6 +935,7 @@ lines_rr (uintmax_t k, uintmax_t n, char *buf, size_t bufsize)
         }
     }
 
+no_filters:
   /* Ensure all files created, so that any existing files are truncated,
      and to signal any waiting fifo consumers.
      Also, close any open file descriptors.
index 0614841..a42c553 100755 (executable)
@@ -47,4 +47,8 @@ stat x?? 2>/dev/null && fail=1
 # where they would result in a non zero exit from split.
 yes | head -n200K | split -b1G --filter='head -c1 >/dev/null' || fail=1
 
+# Ensure that endless input is ignored when all filters finish
+timeout 10 yes | split --filter="head -c1 >/dev/null" -n r/1 || fail=1
+timeout 10 split --filter="head -c1 >/dev/null" -n 1 /dev/zero || fail=1
+
 Exit $fail