]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
split: adjust recent --number changes
authorPádraig Brady <P@draigBrady.com>
Sat, 13 Feb 2016 04:15:51 +0000 (20:15 -0800)
committerPádraig Brady <P@draigBrady.com>
Tue, 16 Feb 2016 06:03:15 +0000 (22:03 -0800)
* src/split.c (lines_rr): Reinstate the conditional
setting of the WROTE boolean, as otherwise split -n r/1 would
consume all input when all --filter commands are stopped.
There was a test in place to check for this, but
it was incorrect as detailed below.
(input_file_size): Immediately disallow --number with
non seekable inputs, as such an invocation is not currently
generally supported and will fail as the data overflows
the internal buffer.
* tests/split/l-chunk.sh: Adjust to again disallow -n /dev/zero.
Also change all '&& fail=1' checks to use the 'returns_ 1' form.
* tests/split/filter.sh: Change the no longer supported /dev/zero
case to a regular $OFF_T_MAX file (supported on XFS for example).
Also fix the timeout(1) commands so they're not subject to
pipefail issues.

src/split.c
tests/split/filter.sh
tests/split/l-chunk.sh

index 0b10600cde08b6fe64ffb9ab9aa8d5ee4fce4173..676aa2e0227f07fcd95d9e99d7ab3157a0cdc3e6 100644 (file)
@@ -278,6 +278,14 @@ CHUNKS may be:\n\
 static off_t
 input_file_size (int fd, struct stat const *st, char *buf, size_t bufsize)
 {
+  off_t cur = lseek (fd, 0, SEEK_CUR);
+  if (cur < 0)
+    {
+      if (errno == ESPIPE)
+        errno = 0; /* Suppress confusing seek error.  */
+      return -1;
+    }
+
   off_t size = 0;
   do
     {
@@ -290,19 +298,20 @@ input_file_size (int fd, struct stat const *st, char *buf, size_t bufsize)
     }
   while (size < bufsize);
 
-  /* The file contains at least BUFSIZE bytes.  Infer its size via
-     st->st_size if this seems reliable, or via lseek if not.  */
-  off_t cur = lseek (fd, 0, SEEK_CUR);
-  off_t end;
-  if (cur < 0)
-    return -1;
-  if (cur < size)
+  /* Note we check st_size _after_ the read() above
+     because /proc files on GNU/Linux are seekable
+     but have st_size == 0.  */
+  if (st->st_size == 0)
     {
-      /* E.g., /dev/zero on GNU/Linux, where CUR is zero and SIZE == BUFSIZE.
-         Assume there is no limit to the file size.  */
+      /* We've filled the buffer, from a seekable file,
+         which has an st_size==0, E.g., /dev/zero on GNU/Linux.
+         Assume there is no limit to file size.  */
       errno = EOVERFLOW;
       return -1;
     }
+
+  cur += size;
+  off_t end;
   if (usable_st_size (st) && cur <= st->st_size)
     end = st->st_size;
   else
@@ -1197,7 +1206,8 @@ lines_rr (uintmax_t k, uintmax_t n, char *buf, size_t bufsize)
                          quotef (files[i_file].of_name));
                 }
 
-              wrote = true;
+              if (! ignorable (errno))
+                wrote = true;
 
               if (file_limit)
                 {
@@ -1558,8 +1568,7 @@ main (int argc, char **argv)
   char *buf = ptr_align (b, page_size);
   size_t initial_read = SIZE_MAX;
 
-  if ((split_type == type_chunk_bytes || split_type == type_chunk_lines)
-      && n_units != 1)
+  if (split_type == type_chunk_bytes || split_type == type_chunk_lines)
     {
       file_size = input_file_size (STDIN_FILENO, &in_stat_buf,
                                    buf, in_blk_size);
index e4e4dca3b51890dfb7bd64bd69eabd3b2bb0fde5..a93008bb764cdbc85014c5fc850f893cf6fcb37f 100755 (executable)
@@ -18,6 +18,8 @@
 
 . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
 print_ver_ split
+require_sparse_support_ # for 'truncate --size=$OFF_T_MAX'
+eval $(getlimits) # for OFF_T limits
 xz --version || skip_ "xz (better than gzip/bzip2) required"
 
 for total_n_lines in 5 3000 20000; do
@@ -41,7 +43,7 @@ done
 # split does not run the command (and effectively elides the file)
 # only when the output to that command would have been empty.
 split -e -n 10 --filter='xz > $FILE.xz' /dev/null || fail=1
-stat x?? 2>/dev/null && fail=1
+returns_ 1 stat x?? 2>/dev/null || fail=1
 
 # Ensure this invalid combination is flagged
 returns_ 1 split -n 1/2 --filter='true' /dev/null 2>&1 || fail=1
@@ -50,8 +52,10 @@ returns_ 1 split -n 1/2 --filter='true' /dev/null 2>&1 || 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
+# Ensure that "endless" input is ignored when all filters finish
+timeout 10 sh -c 'yes | split --filter="head -c1 >/dev/null" -n r/1' || fail=1
+if truncate -s$OFF_T_MAX zero.in; then
+  timeout 10 sh -c 'split --filter="head -c1 >/dev/null" -n 1 zero.in' || fail=1
+fi
 
 Exit $fail
index 38297dea1046390894143ae1eddfcdc1d3594bf5..a7a9395ca646a24d1600e431c7eb96e36296b5fb 100755 (executable)
@@ -21,12 +21,12 @@ print_ver_ split
 
 # invalid number of chunks
 echo "split: invalid number of chunks: '1o'" > exp
-split -n l/1o 2>err && fail=1
+returns_ 1 split -n l/1o 2>err || fail=1
 compare exp err || fail=1
 
-echo > exp
-echo | split -n l/1 || fail=1
-compare exp xaa || fail=1
+echo "split: -: cannot determine file size" > exp
+: | returns_ 1 split -n l/1 2>err || fail=1
+compare exp err || fail=1
 
 # N can be greater than the file size
 # in which case no data is extracted, or empty files are written
@@ -45,7 +45,7 @@ rm x??
 
 # Ensure --elide-empty-files is honored
 split -e -n l/10 /dev/null || fail=1
-stat x?? 2>/dev/null && fail=1
+returns_ 1 stat x?? 2>/dev/null || fail=1
 
 # 80 bytes. ~ transformed to \n below
 lines=\
@@ -79,7 +79,7 @@ for ELIDE_EMPTY in '' '-e'; do
 
       if test -z "$ELIDE_EMPTY"; then
         split ---io-blksize=$IO_BLKSIZE -n l/2/$N in > chunk.k
-        stat x* 2>/dev/null && fail=1
+        returns_ 1 stat x* 2>/dev/null || fail=1
       fi
 
       split ---io-blksize=$IO_BLKSIZE $ELIDE_EMPTY -n l/$N in