add tests for truncated files
authorPhilipp Gesang <philipp.gesang@intra2net.com>
Thu, 31 Aug 2017 09:41:50 +0000 (11:41 +0200)
committerThomas Jarosch <thomas.jarosch@intra2net.com>
Mon, 2 Apr 2018 11:34:09 +0000 (13:34 +0200)
deltatar/crypto.py
runtests.py
testing/test_recover.py

index 676fa18..e19894f 100755 (executable)
@@ -635,6 +635,7 @@ def try_decrypt (ifd, off, hdr, secret, ofd=-1):
 
     try:
         os.lseek (ifd, pos, os.SEEK_SET)
+        pt = b""
         while ctleft > 0:
             cnksiz = min (ctleft, PDTCRYPT_BLOCKSIZE)
             cnk    = os.read (ifd, cnksiz)
index 457bcb0..d98a10f 100755 (executable)
@@ -35,6 +35,9 @@ from testing.test_recover import \
     , RecoverCorruptHeaderGZMultiTest \
     , RecoverCorruptHeaderGZAESSingleTest \
     , RecoverCorruptHeaderGZAESMultiTest \
+    , RecoverCorruptTruncateTest \
+    , RecoverCorruptTruncateGZTest \
+    , RecoverCorruptTruncateGZAESTest \
     , RescueCorruptHeaderCTSizeGZAESTest \
     , RecoverCorruptEntireHeaderSingleTest \
     , RecoverCorruptEntireHeaderMultiTest \
@@ -56,6 +59,9 @@ from testing.test_recover import \
     , RecoverCorruptHoleTest \
     , RecoverCorruptHoleGZTest \
     , RecoverCorruptHoleGZAESTest \
+    , RescueCorruptTruncateTest \
+    , RescueCorruptTruncateGZTest \
+    , RescueCorruptTruncateGZAESTest \
     , RescueCorruptHoleTest \
     , RescueCorruptHoleGZTest \
     , RescueCorruptHoleGZAESTest \
@@ -65,6 +71,9 @@ from testing.test_recover import \
     , GenIndexIntactMultiTest \
     , GenIndexIntactMultiGZTest \
     , GenIndexIntactMultiGZAESTest \
+    , GenIndexCorruptTruncateTest \
+    , GenIndexCorruptTruncateGZTest \
+    , GenIndexCorruptTruncateGZAESTest \
     , GenIndexCorruptHoleTest \
     , GenIndexCorruptHoleGZTest \
     , GenIndexCorruptHoleGZAESTest \
@@ -119,6 +128,9 @@ if __name__ == "__main__":
                          , RecoverCorruptHeaderGZMultiTest
                          , RecoverCorruptHeaderGZAESSingleTest
                          , RecoverCorruptHeaderGZAESMultiTest
+                         , RecoverCorruptTruncateTest
+                         , RecoverCorruptTruncateGZTest
+                         , RecoverCorruptTruncateGZAESTest
                          , RescueCorruptHeaderCTSizeGZAESTest
                          , RecoverCorruptEntireHeaderSingleTest
                          , RecoverCorruptEntireHeaderMultiTest
@@ -139,6 +151,9 @@ if __name__ == "__main__":
                          , RecoverCorruptHoleTest
                          , RecoverCorruptHoleGZTest
                          , RecoverCorruptHoleGZAESTest
+                         , RescueCorruptTruncateTest
+                         , RescueCorruptTruncateGZTest
+                         , RescueCorruptTruncateGZAESTest
                          , RescueCorruptHoleTest
                          , RescueCorruptHoleGZTest
                          , RescueCorruptHoleGZAESTest
@@ -148,6 +163,9 @@ if __name__ == "__main__":
                          , GenIndexIntactMultiTest
                          , GenIndexIntactMultiGZTest
                          , GenIndexIntactMultiGZAESTest
+                         , GenIndexCorruptTruncateTest
+                         , GenIndexCorruptTruncateGZTest
+                         , GenIndexCorruptTruncateGZAESTest
                          , GenIndexCorruptHoleTest
                          , GenIndexCorruptHoleGZTest
                          , GenIndexCorruptHoleGZAESTest
index a8ebc55..9edea9d 100644 (file)
@@ -16,6 +16,12 @@ communicated upward by throwing.
       compressed data, the two byte magic is altered, for uncompressed
       archives, the tar header checksum field.
 
+    - corrupt_truncate ():
+      Drop the file’s content after two thirds, causing extraction of later
+      objects to fail. Since the operation preserves the offsets of objects
+      before the cutoff, this yields the same results regardless of whether
+      restore or rescue mode is used.
+
     - corrupt_ctsize ():
       Modify the *ctsize* field of a PDTCRYPT header. The goal is to have
       decryption continue past the end of the object, causing data
@@ -173,6 +179,17 @@ def corrupt_header (_, fname, compress, encrypt):
         flip_bits (fname, 100 + 8 + 8 + 8 + 12 + 12 + 1)
 
 
+def corrupt_truncate (_, fname, _compress, _encrypt):
+    """
+    Shorten file by one third.
+    """
+    fd   = os.open (fname, os.O_WRONLY)
+    size = os.lseek (fd, 0, os.SEEK_END)
+    os.ftruncate (fd, 2 * size // 3)
+    os.fsync (fd)
+    os.close (fd)
+
+
 def corrupt_ctsize (_, fname, compress, encrypt):
     """
     Blow up the size of an object so as to cause its apparent payload to leak
@@ -701,6 +718,28 @@ class RecoverCorruptHeaderGZAESMultiTest (RecoverCorruptHeaderGZAESTestBase):
     VOLUMES     = 3
 
 
+class RecoverCorruptTruncateTestBase (RecoverTest):
+    COMPRESSION = None
+    PASSWORD    = None
+    FAILURES    = 0
+    CORRUPT     = corrupt_truncate
+    MISMATCHES  = 0
+
+class RecoverCorruptTruncateTest (RecoverCorruptTruncateTestBase):
+    pass
+
+class RecoverCorruptTruncateGZTest (RecoverCorruptTruncateTestBase):
+    """Two files that failed missing."""
+    COMPRESSION = "#gz"
+    FAILURES    = 2
+
+class RecoverCorruptTruncateGZAESTest (RecoverCorruptTruncateTestBase):
+    """Two files that failed missing."""
+    COMPRESSION = "#gz"
+    PASSWORD    = TEST_PASSWORD
+    FAILURES    = 2
+
+
 class RecoverCorruptEntireHeaderTestBase (RecoverTest):
     COMPRESSION = None
     PASSWORD    = None
@@ -850,6 +889,28 @@ class RecoverCorruptHoleGZAESTest (RecoverCorruptHoleBaseTest):
 # rescue
 ###############################################################################
 
+class RescueCorruptTruncateTestBase (RescueTest):
+    COMPRESSION = None
+    PASSWORD    = None
+    FAILURES    = 0
+    CORRUPT     = corrupt_truncate
+    MISMATCHES  = 0
+
+class RescueCorruptTruncateTest (RescueCorruptTruncateTestBase):
+    pass
+
+class RescueCorruptTruncateGZTest (RescueCorruptTruncateTestBase):
+    """Two files that failed missing."""
+    COMPRESSION = "#gz"
+    MISSING     = 2
+
+class RescueCorruptTruncateGZAESTest (RescueCorruptTruncateTestBase):
+    """Two files missing but didn’t fail on account of their absence."""
+    COMPRESSION = "#gz"
+    PASSWORD    = TEST_PASSWORD
+    MISSING     = 2
+
+
 @unittest.skipIf(sys.version_info < (3, 4), "requires recent os library")
 class RescueCorruptHoleBaseTest (RescueTest):
     """
@@ -956,6 +1017,27 @@ class GenIndexIntactMultiGZAESTest (GenIndexIntactBaseTest):
     MISSING     = 2
 
 
+class GenIndexCorruptTruncateBaseTest (GenIndexTest):
+    """
+    Recreate index from file that lacks the latter portion.
+    """
+    COMPRESSION = None
+    PASSWORD    = None
+    FAILURES    = 0
+    CORRUPT     = corrupt_truncate
+    MISSING     = 2
+
+class GenIndexCorruptTruncateTest (GenIndexCorruptTruncateBaseTest):
+    pass
+
+class GenIndexCorruptTruncateGZTest (GenIndexCorruptTruncateBaseTest):
+    COMPRESSION = "#gz"
+
+class GenIndexCorruptTruncateGZAESTest (GenIndexCorruptTruncateBaseTest):
+    COMPRESSION = "#gz"
+    PASSWORD    = TEST_PASSWORD
+
+
 class GenIndexCorruptHoleBaseTest (GenIndexTest):
     """
     Recreate index from file with hole.
@@ -980,7 +1062,6 @@ class GenIndexCorruptHoleGZAESTest (GenIndexCorruptHoleBaseTest):
     MISSING     = 2
 
 
-
 class GenIndexCorruptEntireHeaderBaseTest (GenIndexTest):
     """
     Recreate index from file with hole.