Subject: bug#17149: shred - tape data

From: Pádraig Brady <[email-masked]>
Date: Fri, 04 Apr 2014 05:40:50 +0100

On 04/03/2014 05:44 PM, Paul Eggert wrote:
> I found a glitch in that previous patch, and installed the attached fixup.

Actually we shouldn't be doing a data pass for empty files at all.
The original version of this utility didn't do that, nor do
I see a reason for doing that. So for correctness/consistency reasons,
I'm applying the attached.

thanks,
Pádraig.
>From 217618e8bf10a09270291b9825f3181ed2f83dbf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <[email-masked]>
Date: Thu, 3 Apr 2014 13:47:48 +0100
Subject: [PATCH] shred: avoid a data pass on empty files

* src/shred.c (do_wipefd): Don't increase the size written
for an empty file up to a full block.  Also increase the size
to OFF_T_MAX in the edge case where we do overflow.
* NEWS: Mention the shred improvements from recent changes.
* tests/misc/shred-passes.sh: Adjust as we no longer
write a BLKSIZE of data for empty files.
---
 NEWS                       |    3 +++
 src/shred.c                |   10 +++++-----
 tests/misc/shred-passes.sh |   10 +++++-----
 3 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/NEWS b/NEWS
index d6aa885..c6451b2 100644
--- a/NEWS
+++ b/NEWS
@@ -57,6 +57,9 @@ GNU coreutils NEWS                                    -*- outline -*-
   causing name look-up errors.  Also look-ups are first done outside the chroot,
   in case the look-up within the chroot fails due to library conflicts etc.
 
+  shred now supports multiple passes on GNU/Linux tape devices by rewinding
+  the tape before each pass.  Also redundant writes to empty files are avoided.
+
   split avoids unnecessary input buffering, immediately writing input to output
   which is significant with --filter or when writing to fifos or stdout etc.
 
diff --git a/src/shred.c b/src/shred.c
index 732d3af..ed37051 100644
--- a/src/shred.c
+++ b/src/shred.c
@@ -428,7 +428,7 @@ dopass (int fd, struct stat const *st, char const *qname, off_t *sizep,
   size_t soff;			/* Offset into buffer for next write */
   ssize_t ssize;		/* Return value from write */
 
-  /* Do nothing for --size=0 or regular empty files with --exact.  */
+  /* Do nothing for --size=0 or regular empty files.  */
   if (size == 0)
     return 0;
 
@@ -887,15 +887,15 @@ do_wipefd (int fd, char const *qname, struct randint_source *s,
 
           if (! flags->exact)
             {
-              /* Round up to the nearest blocksize.  If the file is
-                 empty output a block anyway, in case the file system
-                 stores small files in the inode.  */
+              /* Round up to the nearest blocksize to clear slack space.  */
               off_t remainder = size % ST_BLKSIZE (st);
-              if (remainder != 0 || size == 0)
+              if (remainder != 0)
                 {
                   off_t size_incr = ST_BLKSIZE (st) - remainder;
                   if (! INT_ADD_OVERFLOW (size, size_incr))
                     size += size_incr;
+                  else
+                    size = OFF_T_MAX;
                 }
             }
         }
diff --git a/tests/misc/shred-passes.sh b/tests/misc/shred-passes.sh
index bbd1288..268af95 100755
--- a/tests/misc/shred-passes.sh
+++ b/tests/misc/shred-passes.sh
@@ -20,9 +20,9 @@
 print_ver_ shred

-# shred a single letter, zero length file which should result in
+# shred a single letter, which should result in
 # 3 random passes and a single rename.
-touch f || framework_failure_
+printf 1 > f || framework_failure_
 echo "\
 shred: f: pass 1/3 (random)...
 shred: f: pass 2/3 (random)...
@@ -35,15 +35,15 @@ shred -v -u f 2>out || fail=1
 
 compare exp out || fail=1
 
-# Likewise but with --exact to bypass the
-# data passes for the zero length file
+# Likewise but for a zero length file
+# to bypass the data passes
 touch f || framework_failure_
 echo "\
 shred: f: removing
 shred: f: renamed to 0
 shred: f: removed" > exp || framework_failure_
 
-shred -x -v -u f 2>out || fail=1
+shred -v -u f 2>out || fail=1
 
 compare exp out || fail=1
 
-- 
1.7.7.6