Merge "Zero out blocks if BLKSECDISCARD fails" into nyc-mr1-dev
diff --git a/secdiscard.cpp b/secdiscard.cpp
index 5c12cdd..fe51990 100644
--- a/secdiscard.cpp
+++ b/secdiscard.cpp
@@ -43,11 +43,12 @@
 
 bool read_command_line(int argc, const char * const argv[], Options &options);
 void usage(const char *progname);
-int secdiscard_path(const std::string &path);
+bool secdiscard_path(const std::string &path);
 std::unique_ptr<struct fiemap> path_fiemap(const std::string &path, uint32_t extent_count);
 bool check_fiemap(const struct fiemap &fiemap, const std::string &path);
 std::unique_ptr<struct fiemap> alloc_fiemap(uint32_t extent_count);
 std::string block_device_for_path(const std::string &path);
+bool overwrite_with_zeros(int fd, off64_t start, off64_t length);
 
 }
 
@@ -58,9 +59,11 @@
         usage(argv[0]);
         return -1;
     }
-    for (auto target: options.targets) {
+    for (auto const &target: options.targets) {
         LOG(DEBUG) << "Securely discarding '" << target << "' unlink=" << options.unlink;
-        secdiscard_path(target);
+        if (!secdiscard_path(target)) {
+            LOG(ERROR) << "Secure discard failed for: " << target;
+        }
         if (options.unlink) {
             if (unlink(target.c_str()) != 0 && errno != ENOENT) {
                 PLOG(ERROR) << "Unable to unlink: " << target;
@@ -95,19 +98,19 @@
 }
 
 // BLKSECDISCARD all content in "path", if it's small enough.
-int secdiscard_path(const std::string &path) {
+bool secdiscard_path(const std::string &path) {
     auto fiemap = path_fiemap(path, max_extents);
     if (!fiemap || !check_fiemap(*fiemap, path)) {
-        return -1;
+        return false;
     }
     auto block_device = block_device_for_path(path);
     if (block_device.empty()) {
-        return -1;
+        return false;
     }
     AutoCloseFD fs_fd(block_device, O_RDWR | O_LARGEFILE);
     if (!fs_fd) {
         PLOG(ERROR) << "Failed to open device " << block_device;
-        return -1;
+        return false;
     }
     for (uint32_t i = 0; i < fiemap->fm_mapped_extents; i++) {
         uint64_t range[2];
@@ -115,10 +118,11 @@
         range[1] = fiemap->fm_extents[i].fe_length;
         if (ioctl(fs_fd.get(), BLKSECDISCARD, range) == -1) {
             PLOG(ERROR) << "Unable to BLKSECDISCARD " << path;
-            return -1;
+            if (!overwrite_with_zeros(fs_fd.get(), range[0], range[1])) return false;
+            LOG(DEBUG) << "Used zero overwrite";
         }
     }
-    return 0;
+    return true;
 }
 
 // Read the file's FIEMAP
@@ -206,4 +210,23 @@
     return result;
 }
 
+bool overwrite_with_zeros(int fd, off64_t start, off64_t length) {
+    if (lseek64(fd, start, SEEK_SET) != start) {
+        PLOG(ERROR) << "Seek failed for zero overwrite";
+        return false;
+    }
+    char buf[BUFSIZ];
+    memset(buf, 0, sizeof(buf));
+    while (length > 0) {
+        size_t wlen = static_cast<size_t>(std::min(static_cast<off64_t>(sizeof(buf)), length));
+        auto written = write(fd, buf, wlen);
+        if (written < 1) {
+            PLOG(ERROR) << "Write of zeroes failed";
+            return false;
+        }
+        length -= written;
+    }
+    return true;
+}
+
 }