On 04/04/2014 06:49 PM, Paul Eggert wrote:
>> +  else if (S_ISREG (st.st_mode))
>> +    {
>> +      off_t fsize = st.st_size;
>> +      if (fsize > 0 && fsize < ST_BLKSIZE (st) && size > fsize)
>> +        i_size = fsize;
>> +    }
> 
> This can be simplified.  There's no need to worry about checking whether 
> st.st_size == 0 since the code would do the right thing if that test were 
> removed.

> (Or are you worried about st.st_size < 0?  If so, that check should be 
> hoisted out of the previous 'if' and done on all regular files.)

This was the case I was thinking about.
Yes hoisting the check is better.
Always better to validate earlier, so as to simplify later code.

> We generally prefer "<" and "<=" for size comparisons, as it makes code 
> easier to visualize.  Something like this, perhaps:
> 
>    else if (S_ISREG (st.st_mode)
>             && st.st_size < MIN (ST_BLKSIZE (st), size))
>      i_size = st.st_size;

Yes I used that.
I adjusted as per the attached and pushed.

Thanks for the review!
Pádraig.

diff --git a/src/shred.c b/src/shred.c
index 187446f..2793843 100644
--- a/src/shred.c
+++ b/src/shred.c
@@ -519,7 +519,7 @@ dopass (int fd, struct stat const *st, char const *qname, off_t *sizep,
                      at all on some (file) systems, or with the current size.
                      I.E. a specified --size that is not aligned, or when
                      dealing with slop at the end of a file with --exact.  */
-                  if (k == 1 && !try_without_directio && errno == EINVAL)
+                  if (! try_without_directio && errno == EINVAL)
                     {
                       direct_mode (fd, false);
                       ssize = 0;
@@ -870,6 +870,11 @@ do_wipefd (int fd, char const *qname, struct randint_source *s,
       error (0, 0, _("%s: invalid file type"), qname);
       return false;
     }
+  else if (S_ISREG (st.st_mode) && st.st_size < 0)
+    {
+      error (0, 0, _("%s: file has negative size"), qname);
+      return false;
+    }
 
   /* Allocate pass array */
   passarray = xnmalloc (flags->n_iterations, sizeof *passarray);
@@ -880,12 +885,6 @@ do_wipefd (int fd, char const *qname, struct randint_source *s,
       if (S_ISREG (st.st_mode))
         {
           size = st.st_size;
-          if (size < 0)
-            {
-              ok = false;
-              error (0, 0, _("%s: file has negative size"), qname);
-              goto wipefd_out;
-            }
 
           if (! flags->exact)
             {
@@ -914,12 +913,9 @@ do_wipefd (int fd, char const *qname, struct randint_source *s,
             }
         }
     }
-  else if (S_ISREG (st.st_mode))
-    {
-      off_t fsize = st.st_size;
-      if (fsize > 0 && fsize < ST_BLKSIZE (st) && size > fsize)
-        i_size = fsize;
-    }
+  else if (S_ISREG (st.st_mode)
+           && st.st_size < MIN (ST_BLKSIZE (st), size))
+    i_size = st.st_size;
 
   /* Schedule the passes in random order. */
   genpattern (passarray, flags->n_iterations, s);
diff --git a/tests/misc/shred-exact.sh b/tests/misc/shred-exact.sh
index 5f2848e..5434229 100755
--- a/tests/misc/shred-exact.sh
+++ b/tests/misc/shred-exact.sh
@@ -40,6 +40,10 @@ done
 # (i.e. we want to test failed writes not at the start).
 truncate -s1MiB file.slop || framework_failure_
 truncate -s+1 file.slop || framework_failure_
-shred --exact -n1 file.slop || fail=1
+shred --exact -n2 file.slop || fail=1
+
+# make sure direct I/O is handled appropriately at start of file
+truncate -s1 file.slop || framework_failure_
+shred --exact -n2 file.slop || fail=1
 
 Exit $fail

Reply via email to