split: fix cases where -n l/... creates extraneous files
authorPádraig Brady <P@draigBrady.com>
Tue, 24 May 2011 08:59:08 +0000 (09:59 +0100)
committerPádraig Brady <P@draigBrady.com>
Tue, 24 May 2011 15:29:48 +0000 (16:29 +0100)
* src/split.c (lines_chunk_split): Ensure that data is only
written to stdout when k specified.  Also ensure that
extra files are not created when there is more data available
than reported in the file size.
* tests/misc/split-lchunk: Verify that split -n l/k/n doesn't
generate any files, and that -n l/n always generates n files.
* NEWS: Mention the fix.

NEWS
src/split.c
tests/misc/split-lchunk

diff --git a/NEWS b/NEWS
index a71f832..502a5c6 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,9 @@ GNU coreutils NEWS                                    -*- outline -*-
   printf '%d' '"' no longer accesses out-of-bounds memory in the diagnostic.
   [bug introduced in sh-utils-1.16]
 
+  split --number l/... no longer creates extraneous files in certain cases.
+  [bug introduced in coreutils-8.8]
+
 ** New features
 
   split accepts a new --filter=CMD option.  With it, split filters output
index 05315e6..e09ebce 100644 (file)
@@ -645,7 +645,7 @@ lines_chunk_split (uintmax_t k, uintmax_t n, char *buf, size_t bufsize,
                   && ! ignorable (errno))
                 error (EXIT_FAILURE, errno, "%s", _("write error"));
             }
-          else
+          else if (! k)
             cwrite (new_file_flag, bp, to_write);
           n_written += to_write;
           bp += to_write;
@@ -657,7 +657,15 @@ lines_chunk_split (uintmax_t k, uintmax_t n, char *buf, size_t bufsize,
           while (next || chunk_end <= n_written - 1)
             {
               if (!next && bp == eob)
-                break; /* replenish buf, before going to next chunk.  */
+                {
+                  /* replenish buf, before going to next chunk.  */
+
+                  /* If we're going to stop reading,
+                     then count the current chunk.  */
+                  if (n_written >= file_size)
+                    chunk_no++;
+                  break;
+                }
               chunk_no++;
               if (k && chunk_no > k)
                 return;
@@ -666,7 +674,10 @@ lines_chunk_split (uintmax_t k, uintmax_t n, char *buf, size_t bufsize,
               else
                 chunk_end += chunk_size;
               if (chunk_end <= n_written - 1)
-                cwrite (true, NULL, 0);
+                {
+                  if (! k)
+                    cwrite (true, NULL, 0);
+                }
               else
                 next = false;
             }
index 0f1693b..762138b 100755 (executable)
@@ -34,6 +34,12 @@ split -n l/10 /dev/null || fail=1
 test "$(stat -c %s x* | uniq -c | sed 's/^ *//; s/ /x/')" = "10x0" || fail=1
 rm x??
 
+# Ensure the correct number of files written
+# even if there is more data than the reported file size
+split -n l/2 /dev/zero
+test "$(stat -c %s x* | wc -l)" = '2' || fail=1
+rm x??
+
 # Ensure --elide-empty-files is honored
 split -e -n l/10 /dev/null || fail=1
 stat x?? 2>/dev/null && fail=1
@@ -66,9 +72,19 @@ for ELIDE_EMPTY in '' '-e'; do
     test "$DEBUGGING" && printf "\n---io-blk-size=$IO_BLKSIZE $ELIDE_EMPTY\n"
     for N in 6 8 12 15 22; do
       rm -f x*
+
+      if test -z "$ELIDE_EMPTY"; then
+        split ---io-blksize=$IO_BLKSIZE $ELIDE_EMPTY -n l/2/$N in > chunk.k
+        stat x* >/dev/null 2>/dev/null && fail=1
+      fi
+
       split ---io-blksize=$IO_BLKSIZE $ELIDE_EMPTY -n l/$N in
       echo $(stat -c "%02s" x*) >> out
 
+      if test -z "$ELIDE_EMPTY"; then
+        compare chunk.k xab || fail=1
+      fi
+
       if test "$DEBUGGING"; then
         # Output partition pattern
         size=$(printf "%s" "$lines" | wc -c)