Blame SOURCES/scrub-2.6.1-extentonly.patch

6c3643
diff -up scrub-2.6.1/libscrub/Makefile.am.extent-only scrub-2.6.1/libscrub/Makefile.am
6c3643
--- scrub-2.6.1/libscrub/Makefile.am.extent-only	2014-08-20 17:33:43.000000000 -0400
6c3643
+++ scrub-2.6.1/libscrub/Makefile.am	2021-02-22 14:24:32.439635010 -0500
6c3643
@@ -13,6 +13,7 @@ libscrub_la_SOURCES = \
6c3643
 	libscrub.c \
6c3643
 	scrub.h \
6c3643
 	../src/aes.c \
6c3643
+	../src/fextent_apply.c \
6c3643
 	../src/filldentry.c \
6c3643
 	../src/fillfile.c \
6c3643
 	../src/genrand.c \
6c3643
diff -up scrub-2.6.1/man/scrub.1.in.extent-only scrub-2.6.1/man/scrub.1.in
6c3643
--- scrub-2.6.1/man/scrub.1.in.extent-only	2014-08-20 17:33:43.000000000 -0400
6c3643
+++ scrub-2.6.1/man/scrub.1.in	2021-02-22 14:24:32.439635010 -0500
6c3643
@@ -110,6 +110,13 @@ Do everything but write to targets.
6c3643
 .TP
6c3643
 \fI-h\fR, \fI--help\fR
6c3643
 Print a summary of command line options on stderr.
6c3643
+.TP
6c3643
+\fI-E\fR, \fI--extent-only\fR
6c3643
+When scrubbing regular files, scrub only the file extents. This option is
6c3643
+useful in combination with large sparse files. If used, scrub will skip
6c3643
+the holes in the sparse file. Use this option with caution, the result may not
6c3643
+be compliant with cited standards and information about the actual on-disk
6c3643
+data allocation may leak since only the allocated parts will be scrubbed.
6c3643
 .SH SCRUB METHODS
6c3643
 .TP
6c3643
 .I "nnsa"
6c3643
diff -up scrub-2.6.1/src/fextent_apply.c.extent-only scrub-2.6.1/src/fextent_apply.c
6c3643
--- scrub-2.6.1/src/fextent_apply.c.extent-only	2021-02-22 14:24:32.439635010 -0500
6c3643
+++ scrub-2.6.1/src/fextent_apply.c	2021-02-22 14:25:20.590843156 -0500
6c3643
@@ -0,0 +1,142 @@
6c3643
+/*
6c3643
+ * Copyright 2021 Red Hat, Inc.
6c3643
+ * All Rights Reserved.
6c3643
+ *
6c3643
+ * This program is free software; you can redistribute it and/or
6c3643
+ * modify it under the terms of the GNU General Public License
6c3643
+ * as published by the Free Software Foundation; either version
6c3643
+ * 2 of the License, or (at your option) any later version.
6c3643
+ *
6c3643
+ * This program is distributed in the hope that it will be useful,
6c3643
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
6c3643
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
6c3643
+ * General Public License for more details.
6c3643
+ *
6c3643
+ * You should have received a copy of the GNU General Public License
6c3643
+ * along with this program.  If not, see:
6c3643
+ * <https://www.gnu.org/licenses/>.
6c3643
+ *
6c3643
+ * Authors:
6c3643
+ *      Daniel Kopecek <dkopecek@redhat.com>
6c3643
+ */
6c3643
+#include <stdio.h>
6c3643
+#include <stdint.h>
6c3643
+#include <stdlib.h>
6c3643
+#include <string.h>
6c3643
+#include <unistd.h>
6c3643
+#include <errno.h>
6c3643
+
6c3643
+#include <sys/types.h>
6c3643
+#include <sys/stat.h>
6c3643
+#include <sys/ioctl.h>
6c3643
+#include <sys/file.h>
6c3643
+
6c3643
+#include <linux/fs.h>
6c3643
+#include <linux/fiemap.h>
6c3643
+
6c3643
+#ifndef NDEBUG
6c3643
+# define dP(...)                               \
6c3643
+    do { int  __tmp_errno = errno;             \
6c3643
+       fprintf(stderr, "DEBUG: "__VA_ARGS__);  \
6c3643
+       errno = __tmp_errno;                    \
6c3643
+    } while(0)
6c3643
+#else
6c3643
+# define dP(...) while(0)
6c3643
+#endif
6c3643
+
6c3643
+int fextent_apply(int fd, int (*function)(int, struct fiemap_extent *, void *), void *arg)
6c3643
+{
6c3643
+    int ret = -1;
6c3643
+    struct stat st;
6c3643
+    struct fiemap *em;
6c3643
+    uint32_t extent_count, i;
6c3643
+
6c3643
+    // lock, sync, stat
6c3643
+    if (flock(fd, LOCK_EX) != 0) {
6c3643
+       dP("flock(%d, LOCK_EX) failed: %s, %d.\n", fd, strerror(errno), errno);
6c3643
+       return -1;
6c3643
+    }
6c3643
+    if (fsync(fd) != 0) {
6c3643
+       dP("fsync(%d) failed: %s, %d.\n", fd, strerror(errno), errno);
6c3643
+       goto exit_1;
6c3643
+    }
6c3643
+    if (fstat(fd, &st) != 0) {
6c3643
+       dP("fstat(%d) failed: %s, %d.\n", fd, strerror(errno), errno);
6c3643
+       goto exit_1;
6c3643
+    }
6c3643
+
6c3643
+    /*
6c3643
+     * fiemap => get extent count
6c3643
+     */
6c3643
+    em = malloc(sizeof(struct fiemap));
6c3643
+
6c3643
+    if (em == NULL) {
6c3643
+       dP("malloc(%zu) returned NULL!\n", sizeof(struct fiemap));
6c3643
+       goto exit_1;
6c3643
+    }
6c3643
+
6c3643
+    memset(em, 0, sizeof(struct fiemap));
6c3643
+
6c3643
+    em->fm_start = 0;
6c3643
+    em->fm_length = st.st_size;
6c3643
+    em->fm_extent_count = 0;
6c3643
+    em->fm_mapped_extents = 0;
6c3643
+    em->fm_flags = 0;
6c3643
+
6c3643
+    if (ioctl(fd, FS_IOC_FIEMAP, em) != 0) {
6c3643
+       dP("FS_IOC_FIEMAP: %s, %d.\n", strerror(errno), errno);
6c3643
+       goto exit_0;
6c3643
+    }
6c3643
+
6c3643
+    extent_count = em->fm_mapped_extents;
6c3643
+    free(em);
6c3643
+
6c3643
+    /*
6c3643
+     * fiemap => get extents
6c3643
+     */
6c3643
+    em = malloc (sizeof(struct fiemap)
6c3643
+                + (sizeof(struct fiemap_extent) * extent_count));
6c3643
+
6c3643
+    if (em == NULL) {
6c3643
+       dP("malloc(%zu) returned NULL!\n", sizeof(struct fiemap)
6c3643
+          + (sizeof (struct fiemap_extent) * extent_count));
6c3643
+       goto exit_0;
6c3643
+    }
6c3643
+
6c3643
+    memset(em, 0, sizeof(struct fiemap)
6c3643
+          + (sizeof(struct fiemap_extent) * extent_count));
6c3643
+
6c3643
+    em[0].fm_start = 0;
6c3643
+    em[0].fm_length = st.st_size;
6c3643
+    em[0].fm_extent_count = extent_count;
6c3643
+    em[0].fm_flags = 0;
6c3643
+
6c3643
+    if (ioctl(fd, FS_IOC_FIEMAP, em) != 0) {
6c3643
+       dP("FS_IOC_FIEMAP: %s, %d.\n", strerror(errno), errno);
6c3643
+       goto exit_0;
6c3643
+    }
6c3643
+
6c3643
+    for (i = 0; i < extent_count; ++i) {
6c3643
+       // seek to extent start
6c3643
+       if (lseek(fd, em->fm_extents[i].fe_logical, SEEK_SET) == (off_t)-1) {
6c3643
+           dP("lseek(%d, %llu, SET) failed: %s, %d.\n",
6c3643
+              fd, em->fm_extents[i].fe_logical, strerror(errno), errno);
6c3643
+           goto exit_0;
6c3643
+       }
6c3643
+
6c3643
+       ret = function(fd, em->fm_extents + i, arg);
6c3643
+       if (ret != 0)
6c3643
+           goto exit_0;
6c3643
+    }
6c3643
+
6c3643
+    ret = 0;
6c3643
+  exit_0:
6c3643
+    // release resources
6c3643
+    free (em);
6c3643
+  exit_1:
6c3643
+    // unlock
6c3643
+    if (flock(fd, LOCK_UN) != 0)
6c3643
+       ret = -1;
6c3643
+
6c3643
+    return ret;
6c3643
+}
6c3643
diff -up scrub-2.6.1/src/fextent_apply.h.extent-only scrub-2.6.1/src/fextent_apply.h
6c3643
--- scrub-2.6.1/src/fextent_apply.h.extent-only	2021-02-22 14:24:32.439635010 -0500
6c3643
+++ scrub-2.6.1/src/fextent_apply.h	2021-02-22 14:24:32.439635010 -0500
6c3643
@@ -0,0 +1,30 @@
6c3643
+/*
6c3643
+ * Copyright 2021 Red Hat, Inc.
6c3643
+ * All Rights Reserved.
6c3643
+ *
6c3643
+ * This program is free software; you can redistribute it and/or
6c3643
+ * modify it under the terms of the GNU General Public License
6c3643
+ * as published by the Free Software Foundation; either version
6c3643
+ * 2 of the License, or (at your option) any later version.
6c3643
+ *
6c3643
+ * This program is distributed in the hope that it will be useful,
6c3643
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
6c3643
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
6c3643
+ * General Public License for more details.
6c3643
+ *
6c3643
+ * You should have received a copy of the GNU General Public License
6c3643
+ * along with this program.  If not, see:
6c3643
+ * <https://www.gnu.org/licenses/>.
6c3643
+ *
6c3643
+ * Authors:
6c3643
+ *      Daniel Kopecek <dkopecek@redhat.com>
6c3643
+ */
6c3643
+#ifndef FEXTENT_APPLY_H
6c3643
+#define FEXTENT_APPLY_H
6c3643
+
6c3643
+#include <linux/fs.h>
6c3643
+#include <linux/fiemap.h>
6c3643
+
6c3643
+int fextent_apply(int fd, int (*function)(int, struct fiemap_extent *, void *), void *arg);
6c3643
+
6c3643
+#endif /* FEXTENT_APPLY_H */
6c3643
diff -up scrub-2.6.1/src/fillfile.c.extent-only scrub-2.6.1/src/fillfile.c
6c3643
--- scrub-2.6.1/src/fillfile.c.extent-only	2014-08-20 17:33:43.000000000 -0400
6c3643
+++ scrub-2.6.1/src/fillfile.c	2021-02-22 14:24:32.439635010 -0500
6c3643
@@ -41,6 +41,7 @@
6c3643
 
6c3643
 #include "util.h"
6c3643
 #include "fillfile.h"
6c3643
+#include "fextent_apply.h"
6c3643
 
6c3643
 static int no_threads = 0;
6c3643
 
6c3643
@@ -56,6 +57,20 @@ struct memstruct {
6c3643
 
6c3643
 extern char *prog;
6c3643
 
6c3643
+struct fillfile_args {
6c3643
+    char *path;
6c3643
+    off_t filesize;
6c3643
+    unsigned char *mem;
6c3643
+    int memsize;
6c3643
+    progress_t progress;
6c3643
+    void *arg;
6c3643
+    refill_t refill;
6c3643
+    unsigned char *buf;
6c3643
+};
6c3643
+
6c3643
+int fillextent(int fd, struct fiemap_extent *extent, void *pa);
6c3643
+int checkextent(int fd, struct fiemap_extent *extent, void *pa);
6c3643
+
6c3643
 #if defined(O_DIRECT) && (defined(HAVE_POSIX_MEMALIGN) || defined(HAVE_MEMALIGN))
6c3643
 # define MY_O_DIRECT O_DIRECT
6c3643
 #else
6c3643
@@ -154,11 +169,12 @@ refill_fini(struct memstruct *mp)
6c3643
  * If 'sparse' is true, only scrub first and last blocks (for testing).
6c3643
  * The number of bytes written is returned.
6c3643
  * If 'creat' is true, open with O_CREAT and allow ENOSPC to be non-fatal.
6c3643
+ * If 'extentonly' is true, fill only file extents with the given pattern.
6c3643
  */
6c3643
 off_t
6c3643
 fillfile(char *path, off_t filesize, unsigned char *mem, int memsize,
6c3643
          progress_t progress, void *arg, refill_t refill, 
6c3643
-         bool sparse, bool creat)
6c3643
+         bool sparse, bool creat, bool extentonly)
6c3643
 {
6c3643
     int fd = -1;
6c3643
     off_t n;
6c3643
@@ -178,34 +194,52 @@ fillfile(char *path, off_t filesize, uns
6c3643
     }
6c3643
     if (fd < 0)
6c3643
         goto error;
6c3643
-    do {
6c3643
-        if (written + memsize > filesize)
6c3643
-            memsize = filesize - written;
6c3643
-        if (refill && !sparse) {
6c3643
-            if (!mp)
6c3643
-                if (refill_init(&mp, refill, memsize) < 0)
6c3643
-                    goto error;
6c3643
-            if (refill_memcpy(mp, mem, memsize, filesize, written) < 0)
6c3643
-                goto error;
6c3643
-        }
6c3643
-        if (sparse && !(written == 0) && !(written + memsize == filesize)) {
6c3643
-            if (lseek(fd, memsize, SEEK_CUR) < 0)
6c3643
-                goto error;
6c3643
-            written += memsize;
6c3643
-        } else {
6c3643
-            n = write_all(fd, mem, memsize);
6c3643
-            if (creat && n < 0 && errno == ENOSPC)
6c3643
-                break;
6c3643
-            if (n == 0) {
6c3643
-                errno = EINVAL; /* write past end of device? */
6c3643
-                goto error;
6c3643
-            } else if (n < 0)
6c3643
-                goto error;
6c3643
-            written += n;
6c3643
+
6c3643
+    if (extentonly) {
6c3643
+        struct fillfile_args fa;
6c3643
+
6c3643
+        fa.path = path;
6c3643
+        fa.filesize = filesize;
6c3643
+        fa.mem = mem;
6c3643
+        fa.memsize = memsize;
6c3643
+        fa.progress = progress;
6c3643
+        fa.refill = refill;
6c3643
+        fa.arg = arg;
6c3643
+
6c3643
+        if (fextent_apply(fd, fillextent, &fa) == 0) {
6c3643
+            written = filesize;
6c3643
         }
6c3643
-        if (progress)
6c3643
-            progress(arg, (double)written/filesize);
6c3643
-    } while (written < filesize);
6c3643
+    } else {
6c3643
+        do {
6c3643
+            if (written + memsize > filesize)
6c3643
+                memsize = filesize - written;
6c3643
+            if (refill && !sparse) {
6c3643
+                if (!mp)
6c3643
+                    if (refill_init(&mp, refill, memsize) < 0)
6c3643
+                        goto error;
6c3643
+                if (refill_memcpy(mp, mem, memsize, filesize, written) < 0)
6c3643
+                    goto error;
6c3643
+            }
6c3643
+            if (sparse && !(written == 0) && !(written + memsize == filesize)) {
6c3643
+                if (lseek(fd, memsize, SEEK_CUR) < 0)
6c3643
+                    goto error;
6c3643
+                written += memsize;
6c3643
+            } else {
6c3643
+                n = write_all(fd, mem, memsize);
6c3643
+                if (creat && n < 0 && errno == ENOSPC)
6c3643
+                    break;
6c3643
+                if (n == 0) {
6c3643
+                    errno = EINVAL; /* write past end of device? */
6c3643
+                    goto error;
6c3643
+                } else if (n < 0)
6c3643
+                    goto error;
6c3643
+                written += n;
6c3643
+            }
6c3643
+            if (progress)
6c3643
+                progress(arg, (double)written/filesize);
6c3643
+        } while (written < filesize);
6c3643
+    }
6c3643
+
6c3643
     if (fsync(fd) < 0) {
6c3643
         if (errno != EINVAL)
6c3643
             goto error;
6c3643
@@ -232,7 +266,7 @@ error:
6c3643
  */
6c3643
 off_t
6c3643
 checkfile(char *path, off_t filesize, unsigned char *mem, int memsize,
6c3643
-          progress_t progress, void *arg, bool sparse)
6c3643
+          progress_t progress, void *arg, bool sparse, bool extentonly)
6c3643
 {
6c3643
     int fd = -1;
6c3643
     off_t n;
6c3643
@@ -240,8 +274,6 @@ checkfile(char *path, off_t filesize, un
6c3643
     unsigned char *buf = NULL;
6c3643
     int openflags = O_RDONLY;
6c3643
 
6c3643
-    if (!(buf = alloc_buffer(memsize)))
6c3643
-        goto nomem;
6c3643
     if (filetype(path) != FILE_CHAR)
6c3643
         openflags |= MY_O_DIRECT;
6c3643
     fd = open(path, openflags);
6c3643
@@ -252,32 +284,58 @@ checkfile(char *path, off_t filesize, un
6c3643
     }
6c3643
     if (fd < 0)
6c3643
         goto error;
6c3643
-    do {
6c3643
-        if (verified + memsize > filesize)
6c3643
-            memsize = filesize - verified;
6c3643
-        if (sparse && !(verified == 0) && !(verified + memsize == filesize)) {
6c3643
-            if (lseek(fd, memsize, SEEK_CUR) < 0)
6c3643
-                goto error;
6c3643
-            verified += memsize;
6c3643
-        } else {
6c3643
-            n = read_all(fd, buf, memsize);
6c3643
-            if (n < 0)
6c3643
-                goto error;
6c3643
-            if (n == 0) {
6c3643
-                errno = EINVAL; /* early EOF */
6c3643
-                goto error;
6c3643
-            }
6c3643
-            if (memcmp(mem, buf, memsize) != 0) {
6c3643
-                break; /* return < filesize means verification failure */
6c3643
-            }
6c3643
-            verified += n;
6c3643
+    if (extentonly) {
6c3643
+        struct fillfile_args fa;
6c3643
+
6c3643
+        fa.path = path;
6c3643
+        fa.filesize = filesize;
6c3643
+        fa.mem = mem;
6c3643
+        fa.memsize = memsize;
6c3643
+        fa.progress = progress;
6c3643
+        fa.arg = arg;
6c3643
+        fa.buf = alloc_buffer(memsize);
6c3643
+
6c3643
+        if (fa.buf == NULL) {
6c3643
+            goto nomem;
6c3643
         }
6c3643
-        if (progress)
6c3643
-            progress(arg, (double)verified/filesize);
6c3643
-    } while (verified < filesize);
6c3643
+
6c3643
+        if (fextent_apply(fd, checkextent, &fa) == 0)
6c3643
+            verified = filesize;
6c3643
+
6c3643
+        free(fa.buf);
6c3643
+    } else {
6c3643
+        if (!(buf = alloc_buffer(memsize)))
6c3643
+            goto nomem;
6c3643
+        do {
6c3643
+            if (verified + memsize > filesize)
6c3643
+                memsize = filesize - verified;
6c3643
+            if (sparse && !(verified == 0) && !(verified + memsize == filesize)) {
6c3643
+                if (lseek(fd, memsize, SEEK_CUR) < 0)
6c3643
+                    goto error;
6c3643
+                verified += memsize;
6c3643
+            } else {
6c3643
+                n = read_all(fd, buf, memsize);
6c3643
+                if (n < 0)
6c3643
+                    goto error;
6c3643
+                if (n == 0) {
6c3643
+                    errno = EINVAL; /* early EOF */
6c3643
+                    goto error;
6c3643
+                }
6c3643
+                if (memcmp(mem, buf, memsize) != 0) {
6c3643
+                    break; /* return < filesize means verification failure */
6c3643
+                }
6c3643
+                verified += n;
6c3643
+            }
6c3643
+            if (progress)
6c3643
+                progress(arg, (double)verified/filesize);
6c3643
+        } while (verified < filesize);
6c3643
+    }
6c3643
+
6c3643
     if (close(fd) < 0)
6c3643
         goto error;
6c3643
-    free(buf);
6c3643
+    if (buf != NULL) {
6c3643
+        free(buf);
6c3643
+    }
6c3643
     return verified;
6c3643
 nomem:
6c3643
     errno = ENOMEM;
6c3643
@@ -295,6 +353,63 @@ disable_threads(void)
6c3643
     no_threads = 1;
6c3643
 }
6c3643
 
6c3643
+int fillextent(int fd, struct fiemap_extent *extent, void *pa)
6c3643
+{
6c3643
+    off_t n;
6c3643
+    off_t written = 0LL;
6c3643
+    struct fillfile_args args = *(struct fillfile_args *)(pa);
6c3643
+    
6c3643
+    do {
6c3643
+        if (args.refill)
6c3643
+            args.refill(args.mem, args.memsize);
6c3643
+
6c3643
+        if (written + args.memsize > extent->fe_length)
6c3643
+            args.memsize = extent->fe_length - written;
6c3643
+
6c3643
+        n = write_all(fd, args.mem, args.memsize);
6c3643
+
6c3643
+        if (n < 0) {
6c3643
+            fprintf(stderr, "%s: write %s: %s\n", prog, args.path, strerror(errno));
6c3643
+            exit(1);
6c3643
+        }
6c3643
+        written += n;
6c3643
+
6c3643
+        if (args.progress)
6c3643
+            args.progress(args.arg, (double)(extent->fe_logical + written)/args.filesize);
6c3643
+    } while (written < extent->fe_length);
6c3643
+
6c3643
+    return 0;
6c3643
+}
6c3643
+
6c3643
+int checkextent(int fd, struct fiemap_extent *extent, void *pa)
6c3643
+{
6c3643
+    off_t n;
6c3643
+    off_t verified = 0LL;
6c3643
+    struct fillfile_args args = *(struct fillfile_args *)(pa);
6c3643
+
6c3643
+    do {
6c3643
+        if (verified + args.memsize > extent->fe_length)
6c3643
+            args.memsize = extent->fe_length - verified;
6c3643
+
6c3643
+        n = read_all(fd, args.buf, args.memsize);
6c3643
+        if (n < 0) {
6c3643
+            return -1;
6c3643
+        }
6c3643
+        if (n == 0) {
6c3643
+            errno = EINVAL;
6c3643
+            return -1;
6c3643
+        }
6c3643
+        if (memcmp(args.mem, args.buf, args.memsize) != 0) {
6c3643
+            break;
6c3643
+        }
6c3643
+        verified += n;
6c3643
+        if (args.progress)
6c3643
+            args.progress(args.arg, (double)(extent->fe_logical+verified)/args.filesize);
6c3643
+    } while (verified < extent->fe_length);
6c3643
+
6c3643
+    return 0;
6c3643
+}
6c3643
+
6c3643
 /*
6c3643
  * vi:tabstop=4 shiftwidth=4 expandtab
6c3643
  */
6c3643
diff -up scrub-2.6.1/src/fillfile.h.extent-only scrub-2.6.1/src/fillfile.h
6c3643
--- scrub-2.6.1/src/fillfile.h.extent-only	2014-08-20 17:33:43.000000000 -0400
6c3643
+++ scrub-2.6.1/src/fillfile.h	2021-02-22 14:24:32.440635014 -0500
6c3643
@@ -3,9 +3,9 @@ typedef void (*refill_t) (unsigned char
6c3643
 
6c3643
 off_t fillfile(char *path, off_t filesize, unsigned char *mem, int memsize,
6c3643
         progress_t progress, void *arg, refill_t refill, 
6c3643
-        bool sparse, bool creat);
6c3643
+        bool sparse, bool creat, bool extentonly);
6c3643
 off_t checkfile(char *path, off_t filesize, unsigned char *mem, int memsize,
6c3643
-        progress_t progress, void *arg, bool sparse);
6c3643
+        progress_t progress, void *arg, bool sparse, bool extentonly);
6c3643
 void  disable_threads(void);
6c3643
 
6c3643
 /*
6c3643
diff -up scrub-2.6.1/src/Makefile.am.extent-only scrub-2.6.1/src/Makefile.am
6c3643
--- scrub-2.6.1/src/Makefile.am.extent-only	2021-02-22 14:24:32.438635006 -0500
6c3643
+++ scrub-2.6.1/src/Makefile.am	2021-02-22 14:24:32.440635014 -0500
6c3643
@@ -1,6 +1,8 @@
6c3643
 bin_PROGRAMS = scrub
6c3643
 
6c3643
 scrub_SOURCES = \
6c3643
+	fextent_apply.c \
6c3643
+	fextent_apply.h \
6c3643
 	filldentry.c \
6c3643
 	filldentry.h \
6c3643
 	fillfile.c \
6c3643
diff -up scrub-2.6.1/src/scrub.c.extent-only scrub-2.6.1/src/scrub.c
6c3643
--- scrub-2.6.1/src/scrub.c.extent-only	2021-02-22 14:24:32.438635006 -0500
6c3643
+++ scrub-2.6.1/src/scrub.c	2021-02-22 14:24:32.440635014 -0500
6c3643
@@ -68,10 +68,11 @@ struct opt_struct {
6c3643
     bool nofollow;
6c3643
     bool nohwrand;
6c3643
     bool nothreads;
6c3643
+    bool extentonly;
6c3643
 };
6c3643
 
6c3643
 static bool       scrub(char *path, off_t size, const sequence_t *seq,
6c3643
-                      int bufsize, bool nosig, bool sparse, bool enospc);
6c3643
+                      int bufsize, bool nosig, bool sparse, bool enospc, bool extentonly);
6c3643
 static void       scrub_free(char *path, const struct opt_struct *opt);
6c3643
 static void       scrub_dirent(char *path, const struct opt_struct *opt);
6c3643
 static void       scrub_file(char *path, const struct opt_struct *opt);
6c3643
@@ -82,7 +83,7 @@ static void       scrub_disk(char *path,
6c3643
 static int        scrub_object(char *path, const struct opt_struct *opt,
6c3643
                                bool noexec, bool dryrun);
6c3643
 
6c3643
-#define OPTIONS "p:D:Xb:s:fSrvTLRthn"
6c3643
+#define OPTIONS "p:D:Xb:s:fSrvTELRthn"
6c3643
 #if HAVE_GETOPT_LONG
6c3643
 #define GETOPT(ac,av,opt,lopt) getopt_long(ac,av,opt,lopt,NULL)
6c3643
 static struct option longopts[] = {
6c3643
@@ -96,6 +97,7 @@ static struct option longopts[] = {
6c3643
     {"remove",           no_argument,        0, 'r'},
6c3643
     {"version",          no_argument,        0, 'v'},
6c3643
     {"test-sparse",      no_argument,        0, 'T'},
6c3643
+    {"extent-only",      no_argument,        0, 'E'},
6c3643
     {"no-link",          no_argument,        0, 'L'},
6c3643
     {"no-hwrand",        no_argument,        0, 'R'},
6c3643
     {"no-threads",       no_argument,        0, 't'},
6c3643
@@ -123,6 +125,7 @@ usage(void)
6c3643
 "  -f, --force             scrub despite signature from previous scrub\n"
6c3643
 "  -S, --no-signature      do not write scrub signature after scrub\n"
6c3643
 "  -r, --remove            remove file after scrub\n"
6c3643
+"  -E, --extent-only       scrub only file extents\n"
6c3643
 "  -L, --no-link           do not scrub link target\n"
6c3643
 "  -R, --no-hwrand         do not use a hardware random number generator\n"
6c3643
 "  -t, --no-threads        do not compute random data in a parallel thread\n"
6c3643
@@ -212,6 +215,9 @@ main(int argc, char *argv[])
6c3643
         case 'T':   /* --test-sparse */
6c3643
             opt.sparse = true;
6c3643
             break;
6c3643
+        case 'E':   /* --extent-only */
6c3643
+            opt.extentonly = true;
6c3643
+            break;
6c3643
         case 'L':   /* --no-link */
6c3643
             opt.nofollow = true;
6c3643
             break;
6c3643
@@ -430,14 +436,14 @@ static int progress_col (const sequence_
6c3643
  */
6c3643
 static bool
6c3643
 scrub(char *path, off_t size, const sequence_t *seq, int bufsize, 
6c3643
-      bool nosig, bool sparse, bool enospc)
6c3643
+      bool nosig, bool sparse, bool enospc, bool extentonly)
6c3643
 {
6c3643
     unsigned char *buf;
6c3643
     int i;
6c3643
     prog_t p;
6c3643
     char sizestr[80];
6c3643
     bool isfull = false;
6c3643
-    off_t written, checked;
6c3643
+    off_t written = (off_t)-1, checked = (off_t)-1;
6c3643
     int pcol = progress_col(seq);
6c3643
 
6c3643
     if (!(buf = alloc_buffer(bufsize))) {
6c3643
@@ -468,7 +474,7 @@ scrub(char *path, off_t size, const sequ
6c3643
 #endif /* HAVE_LIBGCRYPT. */
6c3643
                 written = fillfile(path, size, buf, bufsize, 
6c3643
                                    (progress_t)progress_update, p, 
6c3643
-                                   (refill_t)genrand, sparse, enospc);
6c3643
+                                   (refill_t)genrand, sparse, enospc, extentonly);
6c3643
                 if (written == (off_t)-1) {
6c3643
                     fprintf(stderr, "%s: %s: %s\n", prog, path,
6c3643
                              strerror(errno));
6c3643
@@ -482,7 +488,7 @@ scrub(char *path, off_t size, const sequ
6c3643
                 memset_pat(buf, seq->pat[i], bufsize);
6c3643
                 written = fillfile(path, size, buf, bufsize, 
6c3643
                                    (progress_t)progress_update, p, 
6c3643
-                                   NULL, sparse, enospc);
6c3643
+                                   NULL, sparse, enospc, extentonly);
6c3643
                 if (written == (off_t)-1) {
6c3643
                     fprintf(stderr, "%s: %s: %s\n", prog, path,
6c3643
                              strerror(errno));
6c3643
@@ -496,7 +502,7 @@ scrub(char *path, off_t size, const sequ
6c3643
                 memset_pat(buf, seq->pat[i], bufsize);
6c3643
                 written = fillfile(path, size, buf, bufsize, 
6c3643
                                    (progress_t)progress_update, p, 
6c3643
-                                   NULL, sparse, enospc);
6c3643
+                                   NULL, sparse, enospc, extentonly);
6c3643
                 if (written == (off_t)-1) {
6c3643
                     fprintf(stderr, "%s: %s: %s\n", prog, path,
6c3643
                              strerror(errno));
6c3643
@@ -506,7 +512,7 @@ scrub(char *path, off_t size, const sequ
6c3643
                 printf("%s: %-8s", prog, "verify");
6c3643
                 progress_create(&p, pcol);
6c3643
                 checked = checkfile(path, written, buf, bufsize, 
6c3643
-                                    (progress_t)progress_update, p, sparse);
6c3643
+                                    (progress_t)progress_update, p, sparse, extentonly);
6c3643
                 if (checked == (off_t)-1) {
6c3643
                     fprintf(stderr, "%s: %s: %s\n", prog, path,
6c3643
                              strerror(errno));
6c3643
@@ -600,7 +606,7 @@ scrub_free(char *dirpath, const struct o
6c3643
     do {
6c3643
         snprintf(path, sizeof(path), "%s/scrub.%.3d", dirpath, fileno++);
6c3643
         isfull = scrub(path, size, opt->seq, opt->blocksize, opt->nosig,
6c3643
-                       false, true);
6c3643
+                       false, true, false);
6c3643
     } while (!isfull);
6c3643
     while (--fileno >= 0) {
6c3643
         snprintf(path, sizeof(path), "%s/scrub.%.3d", dirpath, fileno);
6c3643
@@ -678,7 +684,7 @@ scrub_file(char *path, const struct opt_
6c3643
                     prog, path, (int)(size - sb.st_size)); 
6c3643
         }
6c3643
     }
6c3643
-    scrub(path, size, opt->seq, opt->blocksize, opt->nosig, opt->sparse, false);
6c3643
+    scrub(path, size, opt->seq, opt->blocksize, opt->nosig, opt->sparse, false, opt->extentonly);
6c3643
 }
6c3643
 
6c3643
 /* Scrub apple resource fork component of file.
6c3643
@@ -706,7 +712,7 @@ scrub_resfork(char *path, const struct o
6c3643
         printf("%s: padding %s with %d bytes to fill last fs block\n", 
6c3643
                         prog, rpath, (int)(rsize - rsb.st_size)); 
6c3643
     }
6c3643
-    scrub(rpath, rsize, opt->seq, opt->blocksize, false, false, false);
6c3643
+    scrub(rpath, rsize, opt->seq, opt->blocksize, false, false, false, false);
6c3643
 }
6c3643
 #endif
6c3643
 
6c3643
@@ -728,7 +734,7 @@ scrub_disk(char *path, const struct opt_
6c3643
         printf("%s: please verify that device size below is correct!\n", prog);
6c3643
     }
6c3643
     scrub(path, devsize, opt->seq, opt->blocksize, opt->nosig, opt->sparse,
6c3643
-          false);
6c3643
+          false, false);
6c3643
 }
6c3643
 
6c3643
 /*