Blob Blame History Raw
From 9be32e97b120d889e41fddb7258fa2928118b01d Mon Sep 17 00:00:00 2001
From: Thomas Waldmann <tw@waldmann-edv.de>
Date: Wed, 15 Jun 2016 12:22:29 +0200
Subject: [PATCH] fix sparse file test, fixes #1170

found out that xfs is doing stuff behind the scenes: it is pre-allocating 16MB
to prevent fragmentation (in my case, value depends on misc factors).

fixed the test so it just checks that the extracted sparse file uses less (not
necessary much less) space than a non-sparse file would use.

another problem showed up when i tried to verify the holes in the sparse file
via SEEK_HOLE, SEEK_DATA:
after the few bytes of real data in the file, there was another 16MB
preallocated space.
So I ended up checking just the hole at the start of the file.

tested on: ext4, xfs, zfs, btrfs
---
 borg/testsuite/archiver.py | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/borg/testsuite/archiver.py b/borg/testsuite/archiver.py
index 6a89213..a454862 100644
--- a/borg/testsuite/archiver.py
+++ b/borg/testsuite/archiver.py
@@ -412,8 +412,21 @@ def test_sparse_file(self):
             self.assert_equal(fd.read(hole_size), b'\0' * hole_size)
         st = os.stat(filename)
         self.assert_equal(st.st_size, total_len)
-        if sparse_support and hasattr(st, 'st_blocks'):
-            self.assert_true(st.st_blocks * 512 < total_len / 9)  # is output sparse?
+        if sparse_support:
+            if hasattr(st, 'st_blocks'):
+                # do only check if it is less, do NOT check if it is much less
+                # as that causes troubles on xfs and zfs:
+                self.assert_true(st.st_blocks * 512 < total_len)
+            if hasattr(os, 'SEEK_HOLE') and hasattr(os, 'SEEK_DATA'):
+                with open(filename, 'rb') as fd:
+                    # only check if the first hole is as expected, because the 2nd hole check
+                    # is problematic on xfs due to its "dynamic speculative EOF preallocation
+                    try:
+                        self.assert_equal(fd.seek(0, os.SEEK_HOLE), 0)
+                        self.assert_equal(fd.seek(0, os.SEEK_DATA), hole_size)
+                    except OSError:
+                        # does not really support SEEK_HOLE/SEEK_DATA
+                        pass
 
     def test_unusual_filenames(self):
         filenames = ['normal', 'with some blanks', '(with_parens)', ]