Blame SOURCES/dmpd-thin_repair-cache_repair-Check-input-file-exists-earlier.patch

5bcb98
 base/file_utils.cc                          |  4 ++--
5bcb98
 base/file_utils.h                           |  2 +-
5bcb98
 caching/cache_repair.cc                     |  8 +++++++-
5bcb98
 functional-tests/cache-functional-tests.scm | 32 ++++++++++++++++++++++++++---
5bcb98
 functional-tests/era-functional-tests.scm   |  4 ++--
5bcb98
 functional-tests/functional-tests.scm       |  4 ++--
5bcb98
 functional-tests/thin-functional-tests.scm  | 27 ++++++++++++++++++++++--
5bcb98
 thin-provisioning/thin_repair.cc            |  8 +++++++-
5bcb98
 8 files changed, 75 insertions(+), 14 deletions(-)
5bcb98
5bcb98
diff --git a/base/file_utils.cc b/base/file_utils.cc
5bcb98
index ba8957c..7883cfe 100644
5bcb98
--- a/base/file_utils.cc
5bcb98
+++ b/base/file_utils.cc
5bcb98
@@ -66,13 +66,13 @@ file_utils::file_exists(string const &path) {
5bcb98
 }
5bcb98
 
5bcb98
 void
5bcb98
-file_utils::check_file_exists(string const &file) {
5bcb98
+file_utils::check_file_exists(string const &file, bool must_be_regular_file) {
5bcb98
 	struct stat info;
5bcb98
 	int r = ::stat(file.c_str(), &info;;
5bcb98
 	if (r)
5bcb98
 		throw runtime_error("Couldn't stat file");
5bcb98
 
5bcb98
-	if (!S_ISREG(info.st_mode))
5bcb98
+	if (must_be_regular_file && !S_ISREG(info.st_mode))
5bcb98
 		throw runtime_error("Not a regular file");
5bcb98
 }
5bcb98
 
5bcb98
diff --git a/base/file_utils.h b/base/file_utils.h
5bcb98
index 2ee20ab..3edcc9e 100644
5bcb98
--- a/base/file_utils.h
5bcb98
+++ b/base/file_utils.h
5bcb98
@@ -10,7 +10,7 @@
5bcb98
 namespace file_utils {
5bcb98
 	int open_file(std::string const &path, int flags);
5bcb98
 	bool file_exists(std::string const &path);
5bcb98
-	void check_file_exists(std::string const &file;;
5bcb98
+	void check_file_exists(std::string const &file, bool must_be_regular_file = true);
5bcb98
 	int create_block_file(std::string const &path, off_t file_size);
5bcb98
 	int open_block_file(std::string const &path, off_t min_size, bool writeable, bool excl = true);
5bcb98
 	uint64_t get_file_length(std::string const &file;;
5bcb98
diff --git a/caching/cache_repair.cc b/caching/cache_repair.cc
5bcb98
index 9587d5f..8a837a8 100644
5bcb98
--- a/caching/cache_repair.cc
5bcb98
+++ b/caching/cache_repair.cc
5bcb98
@@ -2,6 +2,7 @@
5bcb98
 #include <getopt.h>
5bcb98
 #include <libgen.h>
5bcb98
 
5bcb98
+#include "base/file_utils.h"
5bcb98
 #include "base/output_file_requirements.h"
5bcb98
 #include "caching/commands.h"
5bcb98
 #include "caching/metadata.h"
5bcb98
@@ -29,12 +30,17 @@ namespace {
5bcb98
 	}
5bcb98
 
5bcb98
 	int repair(string const &old_path, string const &new_path) {
5bcb98
+		bool metadata_touched = false;
5bcb98
 		try {
5bcb98
+			file_utils::check_file_exists(new_path, false);
5bcb98
+			metadata_touched = true;
5bcb98
 			metadata_dump(open_metadata_for_read(old_path),
5bcb98
 				      output_emitter(new_path),
5bcb98
 				      true);
5bcb98
 
5bcb98
 		} catch (std::exception &e) {
5bcb98
+			if (metadata_touched)
5bcb98
+				file_utils::zero_superblock(new_path);
5bcb98
 			cerr << e.what() << endl;
5bcb98
 			return 1;
5bcb98
 		}
5bcb98
@@ -110,7 +116,7 @@ cache_repair_cmd::run(int argc, char **argv)
5bcb98
 		check_output_file_requirements(*output_path);
5bcb98
 
5bcb98
 	else {
5bcb98
-		cerr << "no output file provided" << endl;
5bcb98
+		cerr << "No output file provided." << endl;
5bcb98
 		usage(cerr);
5bcb98
 		return 1;
5bcb98
 	}
5bcb98
diff --git a/functional-tests/cache-functional-tests.scm b/functional-tests/cache-functional-tests.scm
5bcb98
index 0e70b94..9b3a203 100644
5bcb98
--- a/functional-tests/cache-functional-tests.scm
5bcb98
+++ b/functional-tests/cache-functional-tests.scm
5bcb98
@@ -15,6 +15,7 @@
5bcb98
   (define-tool cache-dump)
5bcb98
   (define-tool cache-restore)
5bcb98
   (define-tool cache-metadata-size)
5bcb98
+  (define-tool cache-repair)
5bcb98
 
5bcb98
   (define-syntax with-cache-xml
5bcb98
     (syntax-rules ()
5bcb98
@@ -35,7 +36,8 @@
5bcb98
     (syntax-rules ()
5bcb98
       ((_ (md) b1 b2 ...)
5bcb98
        (with-temp-file-sized ((md "cache.bin" (to-bytes (meg 4))))
5bcb98
-         b1 b2 ...))))
5bcb98
+         (system (fmt #f "dd if=/usr/bin/ls of=" md " bs=4096 > /dev/null 2>&1"))
5bcb98
+           b1 b2 ...))))
5bcb98
 
5bcb98
   (define-syntax with-empty-metadata
5bcb98
     (syntax-rules ()
5bcb98
@@ -180,7 +182,7 @@
5bcb98
     "the input file can't be found"
5bcb98
     (with-empty-metadata (md)
5bcb98
       (run-fail-rcv (_ stderr) (cache-restore "-i no-such-file -o" md)
5bcb98
-        (assert-superblock-untouched md)
5bcb98
+        (assert-superblock-all-zeroes md)
5bcb98
         (assert-starts-with "Couldn't stat file" stderr))))
5bcb98
 
5bcb98
   (define-scenario (cache-restore garbage-input-file)
5bcb98
@@ -188,7 +190,7 @@
5bcb98
     (with-empty-metadata (md)
5bcb98
       (with-temp-file-sized ((xml "cache.xml" 4096))
5bcb98
         (run-fail-rcv (_ stderr) (cache-restore "-i" xml "-o" md)
5bcb98
-          (assert-superblock-untouched md)))))
5bcb98
+          (assert-superblock-all-zeroes md)))))
5bcb98
 
5bcb98
   (define-scenario (cache-restore missing-output-file)
5bcb98
     "the output file can't be found"
5bcb98
@@ -354,4 +356,28 @@
5bcb98
     (run-ok-rcv (stdout stderr) (cache-metadata-size "--nr-blocks 67108864")
5bcb98
       (assert-equal "3678208 sectors" stdout)
5bcb98
       (assert-eof stderr)))
5bcb98
+
5bcb98
+  ;;;-----------------------------------------------------------
5bcb98
+  ;;; cache_repair scenarios
5bcb98
+  ;;;-----------------------------------------------------------
5bcb98
+  (define-scenario (cache-repair missing-input-file)
5bcb98
+    "the input file can't be found"
5bcb98
+    (with-empty-metadata (md)
5bcb98
+      (run-fail-rcv (_ stderr) (cache-repair "-i no-such-file -o" md)
5bcb98
+        (assert-superblock-all-zeroes md)
5bcb98
+        (assert-starts-with "Couldn't stat path" stderr))))
5bcb98
+
5bcb98
+  (define-scenario (cache-repair garbage-input-file)
5bcb98
+    "the input file is just zeroes"
5bcb98
+    (with-empty-metadata (md1)
5bcb98
+      (with-corrupt-metadata (md2)
5bcb98
+        (run-fail-rcv (_ stderr) (cache-repair "-i" md1 "-o" md2)
5bcb98
+          (assert-superblock-all-zeroes md2)))))
5bcb98
+
5bcb98
+  (define-scenario (cache-repair missing-output-file)
5bcb98
+    "the output file can't be found"
5bcb98
+    (with-cache-xml (xml)
5bcb98
+      (run-fail-rcv (_ stderr) (cache-repair "-i" xml)
5bcb98
+        (assert-starts-with "No output file provided." stderr))))
5bcb98
+
5bcb98
 )
5bcb98
diff --git a/functional-tests/era-functional-tests.scm b/functional-tests/era-functional-tests.scm
5bcb98
index 373fe34..890f0ff 100644
5bcb98
--- a/functional-tests/era-functional-tests.scm
5bcb98
+++ b/functional-tests/era-functional-tests.scm
5bcb98
@@ -153,7 +153,7 @@
5bcb98
     "the input file can't be found"
5bcb98
     (with-empty-metadata (md)
5bcb98
       (run-fail-rcv (_ stderr) (era-restore "-i no-such-file -o" md)
5bcb98
-        (assert-superblock-untouched md)
5bcb98
+        (assert-superblock-all-zeroes md)
5bcb98
         (assert-starts-with "Couldn't stat file" stderr))))
5bcb98
 
5bcb98
   (define-scenario (era-restore garbage-input-file)
5bcb98
@@ -161,7 +161,7 @@
5bcb98
     (with-empty-metadata (md)
5bcb98
       (with-temp-file-sized ((xml "era.xml" 4096))
5bcb98
         (run-fail-rcv (_ stderr) (era-restore "-i " xml "-o" md)
5bcb98
-          (assert-superblock-untouched md)))))
5bcb98
+          (assert-superblock-all-zeroes md)))))
5bcb98
 
5bcb98
   (define-scenario (era-restore output-unspecified)
5bcb98
     "Fails if no metadata dev specified"
5bcb98
diff --git a/functional-tests/functional-tests.scm b/functional-tests/functional-tests.scm
5bcb98
index aa5b95c..758498e 100644
5bcb98
--- a/functional-tests/functional-tests.scm
5bcb98
+++ b/functional-tests/functional-tests.scm
5bcb98
@@ -21,7 +21,7 @@
5bcb98
     assert-eof
5bcb98
     assert-starts-with
5bcb98
     assert-matches
5bcb98
-    assert-superblock-untouched
5bcb98
+    assert-superblock-all-zeroes
5bcb98
     assert-member?
5bcb98
     assert-raises-thunk
5bcb98
     assert-raises
5bcb98
@@ -259,7 +259,7 @@
5bcb98
               (loop (+ i 1))
5bcb98
               #f)))))
5bcb98
 
5bcb98
-  (define (assert-superblock-untouched md)
5bcb98
+  (define (assert-superblock-all-zeroes md)
5bcb98
     (with-bcache (cache md 1)
5bcb98
       (with-block (b cache 0 (get-flags))
5bcb98
         (unless (all-zeroes? (block-data b) 4096)
5bcb98
diff --git a/functional-tests/thin-functional-tests.scm b/functional-tests/thin-functional-tests.scm
5bcb98
index d096b78..6bb7d24 100644
5bcb98
--- a/functional-tests/thin-functional-tests.scm
5bcb98
+++ b/functional-tests/thin-functional-tests.scm
5bcb98
@@ -37,10 +37,12 @@
5bcb98
            b1 b2 ...)))))
5bcb98
 
5bcb98
   ;;; It would be nice if the metadata was at least similar to valid data.
5bcb98
+  ;;; Here I'm just using the start of the ls binary as 'random' data.
5bcb98
   (define-syntax with-corrupt-metadata
5bcb98
     (syntax-rules ()
5bcb98
       ((_ (md) b1 b2 ...)
5bcb98
        (with-temp-file-sized ((md "thin.bin" (meg 4)))
5bcb98
+         (system (fmt #f "dd if=/usr/bin/ls of=" md " bs=4096 > /dev/null 2>&1"))
5bcb98
          b1 b2 ...))))
5bcb98
 
5bcb98
   (define-syntax with-empty-metadata
5bcb98
@@ -167,7 +169,7 @@
5bcb98
     "the input file can't be found"
5bcb98
     (with-empty-metadata (md)
5bcb98
       (run-fail-rcv (_ stderr) (thin-restore "-i no-such-file -o" md)
5bcb98
-        (assert-superblock-untouched md)
5bcb98
+        (assert-superblock-all-zeroes md)
5bcb98
         (assert-starts-with "Couldn't stat file" stderr))))
5bcb98
 
5bcb98
   (define-scenario (thin-restore garbage-input-file)
5bcb98
@@ -175,7 +177,7 @@
5bcb98
     (with-empty-metadata (md)
5bcb98
       (with-temp-file-sized ((xml "thin.xml" 4096))
5bcb98
         (run-fail-rcv (_ stderr) (thin-restore "-i " xml "-o" md)
5bcb98
-          (assert-superblock-untouched md)))))
5bcb98
+          (assert-superblock-all-zeroes md)))))
5bcb98
 
5bcb98
   (define-scenario (thin-restore missing-output-file)
5bcb98
     "the output file can't be found"
5bcb98
@@ -333,4 +335,25 @@
5bcb98
       (with-empty-metadata (md)
5bcb98
         (run-fail-rcv (_ stderr) (thin-repair "-i" xml "-o" md)
5bcb98
           #t))))
5bcb98
+
5bcb98
+  (define-scenario (thin-repair missing-input-file)
5bcb98
+    "the input file can't be found"
5bcb98
+    (with-empty-metadata (md)
5bcb98
+      (run-fail-rcv (_ stderr) (thin-repair "-i no-such-file -o" md)
5bcb98
+        (assert-superblock-all-zeroes md)
5bcb98
+        (assert-starts-with "Couldn't stat file" stderr))))
5bcb98
+
5bcb98
+  (define-scenario (thin-repair garbage-input-file)
5bcb98
+    "the input file is just zeroes"
5bcb98
+    (with-empty-metadata (md1)
5bcb98
+      (with-corrupt-metadata (md2)
5bcb98
+        (run-fail-rcv (_ stderr) (thin-repair "-i " md1 "-o" md2)
5bcb98
+          (assert-superblock-all-zeroes md2)))))
5bcb98
+
5bcb98
+  (define-scenario (thin-repair missing-output-file)
5bcb98
+    "the output file can't be found"
5bcb98
+    (with-thin-xml (xml)
5bcb98
+      (run-fail-rcv (_ stderr) (thin-repair "-i " xml)
5bcb98
+        (assert-starts-with "No output file provided." stderr))))
5bcb98
+
5bcb98
   )
5bcb98
diff --git a/thin-provisioning/thin_repair.cc b/thin-provisioning/thin_repair.cc
5bcb98
index e22b193..0673753 100644
5bcb98
--- a/thin-provisioning/thin_repair.cc
5bcb98
+++ b/thin-provisioning/thin_repair.cc
5bcb98
@@ -2,6 +2,7 @@
5bcb98
 #include <getopt.h>
5bcb98
 #include <libgen.h>
5bcb98
 
5bcb98
+#include "base/file_utils.h"
5bcb98
 #include "base/output_file_requirements.h"
5bcb98
 #include "persistent-data/file_utils.h"
5bcb98
 #include "thin-provisioning/commands.h"
5bcb98
@@ -17,15 +18,20 @@ using namespace thin_provisioning;
5bcb98
 
5bcb98
 namespace {
5bcb98
 	int repair(string const &old_path, string const &new_path) {
5bcb98
+		bool metadata_touched = false;
5bcb98
 		try {
5bcb98
 			// block size gets updated by the restorer
5bcb98
 			block_manager<>::ptr new_bm = open_bm(new_path, block_manager<>::READ_WRITE);
5bcb98
+			file_utils::check_file_exists(old_path, false);
5bcb98
+			metadata_touched = true;
5bcb98
 			metadata::ptr new_md(new metadata(new_bm, metadata::CREATE, 128, 0));
5bcb98
 			emitter::ptr e = create_restore_emitter(new_md);
5bcb98
 			block_manager<>::ptr old_bm = open_bm(old_path, block_manager<>::READ_ONLY);
5bcb98
 			metadata_repair(old_bm, e);
5bcb98
 
5bcb98
 		} catch (std::exception &e) {
5bcb98
+			if (metadata_touched)
5bcb98
+				file_utils::zero_superblock(new_path);
5bcb98
 			cerr << e.what() << endl;
5bcb98
 			return 1;
5bcb98
 		}
5bcb98
@@ -101,7 +107,7 @@ thin_repair_cmd::run(int argc, char **argv)
5bcb98
 		check_output_file_requirements(*output_path);
5bcb98
 
5bcb98
 	else {
5bcb98
-		cerr << "no output file provided" << endl;
5bcb98
+		cerr << "No output file provided." << endl;
5bcb98
 		usage(cerr);
5bcb98
 		return 1;
5bcb98
 	}