Filemap: introduce a FilemapSeek class
authorArtem Bityutskiy <artem.bityutskiy@intel.com>
Sat, 18 Jan 2014 12:30:26 +0000 (14:30 +0200)
committerArtem Bityutskiy <artem.bityutskiy@intel.com>
Mon, 20 Jan 2014 07:16:32 +0000 (09:16 +0200)
This patch introduce a so far dummy FilemapSeek class which sill be an
alternative to FilemapFiemap. It also introduces the 'Filemap' function which
automatically selects which class will be used for getting block map. The
FIEMAP method is preferred as it is supposedly faster (at least for large
enough files).

This patch also converts all places where we creant an instance of 'Fiemap'
class to use the 'Filemap' function.

Change-Id: Ic0fcb060b5262e0314582ef3b6dc5f464e4c39a5
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@intel.com>
bmaptools/BmapCreate.py
bmaptools/Filemap.py
tests/test_api_base.py
tests/test_filemap.py

index e1447d4781f734fea6a2ebfcdee6bb6cfa218aa5..e562a537bfbc4bae7eeb8cddb7970d25b715fd10 100644 (file)
@@ -165,7 +165,7 @@ class BmapCreate:
             self._bmap_path = bmap
             self._open_bmap_file()
 
-        self.filemap = Filemap.Fiemap(self._f_image)
+        self.filemap = Filemap.filemap(self._f_image)
 
         self.image_size = self.filemap.image_size
         self.image_size_human = human_size(self.image_size)
index 83d741281131a96ee9490e6f6d0ecc24c4540703..76d2a5f64299810b475da6aab1e76ff550098744 100644 (file)
 # General Public License for more details.
 
 """
-This module implements python API for the FIEMAP ioctl. The FIEMAP ioctl
-allows to find holes and mapped areas in a file.
+This module implements python implements a way to get file block. Two methods
+are supported - the FIEMAP ioctl and the 'SEEK_HOLE / SEEK_DATA' features of
+the file seek syscall. The former is implemented by the 'FilemapFiemap' class,
+the latter is implemented by the 'FilemapSeek' class. Both classes provide the
+same API. The 'filemap' function automatically selects which class can be used
+and returns an instance of the class.
 """
 
-# Note, a lot of code in this module is not very readable, because it deals
-# with the rather complex FIEMAP ioctl. To understand the code, you need to
-# know the FIEMAP interface, which is documented in the
-# Documentation/filesystems/fiemap.txt file in the Linux kernel sources.
-
 # Disable the following pylint recommendations:
 #   * Too many instance attributes (R0902)
 # pylint: disable=R0902
@@ -141,6 +140,37 @@ class _FilemapBase:
 
         raise Error("the method is not implemented")
 
+class FilemapSeek(_FilemapBase):
+    """
+    This class uses the 'SEEK_HOLE' and 'SEEK_DATA' to find file block mapping.
+    """
+
+    def __init__(self, image):
+        """Refer the '_FilemapBase' class for the documentation."""
+
+        # Call the base class constructor first
+        _FilemapBase.__init__(self, image)
+
+    def block_is_mapped(self, block):
+        """Refer the '_FilemapBase' class for the documentation."""
+        raise Error("Not implemented")
+
+    def block_is_unmapped(self, block):
+        """Refer the '_FilemapBase' class for the documentation."""
+        raise Error("Not implemented")
+
+    def get_mapped_ranges(self, start, count):
+        """Refer the '_FilemapBase' class for the documentation."""
+        raise Error("Not implemented")
+
+    def get_unmapped_ranges(self, start, count):
+        """Refer the '_FilemapBase' class for the documentation."""
+        raise Error("Not implemented")
+
+# Below goes the FIEMAP ioctl implementation, which is not very readable
+# because it deals with the rather complex FIEMAP ioctl. To understand the
+# code, you need to know the FIEMAP interface, which is documented in the
+# "Documentation/filesystems/fiemap.txt" file in the Linux kernel sources.
 
 # Format string for 'struct fiemap'
 _FIEMAP_FORMAT = "=QQLLLL"
@@ -160,7 +190,7 @@ _FIEMAP_FLAG_SYNC = 0x00000001
 # FIEMAP ioctl will be invoked.
 _FIEMAP_BUFFER_SIZE = 256 * 1024
 
-class Fiemap(_FilemapBase):
+class FilemapFiemap(_FilemapBase):
     """
     This class provides API to the FIEMAP ioctl. Namely, it allows to iterate
     over all mapped blocks and over all holes.
@@ -321,3 +351,18 @@ class Fiemap(_FilemapBase):
 
         if hole_first < start + count:
             yield (hole_first, start + count - 1)
+
+def filemap(image):
+    """
+    Create and return an instance of a Filemap class - 'FilemapFiemap' or
+    'FilemapSeek', depending on what the system we run on supports. If the
+    FIEMAP ioctl is supported, an instance of the 'FilemapFiemap' class is
+    returned. Otherwise, if 'SEEK_HOLE' is supported an instance of the
+    'FilemapSeek' class is returned. If none of these are supported, the
+    function generates an 'Error' type exception.
+    """
+
+    try:
+        return FilemapFiemap(image)
+    except Error:
+        return FilemapSeek(image)
index c073205bb94c8e8342bd4616c7d21177e73b66cc..2a81f8dbfed4c7af3aa7f2ea773333558a7367a6 100644 (file)
@@ -51,8 +51,8 @@ def _compare_holes(file1, file2):
     The 'file1' and 'file2' arguments may be full file paths or file objects.
     """
 
-    filemap1 = Filemap.Fiemap(file1)
-    filemap2 = Filemap.Fiemap(file2)
+    filemap1 = Filemap.filemap(file1)
+    filemap2 = Filemap.filemap(file2)
 
     iterator1 = filemap1.get_unmapped_ranges(0, filemap1.blocks_cnt)
     iterator2 = filemap2.get_unmapped_ranges(0, filemap2.blocks_cnt)
index 6919e53b1c15764fe9a7cb78b26653104381c821..a9d3cef941004be3fd221565177281555720ddc1 100644 (file)
@@ -97,7 +97,7 @@ def _do_test(f_image, mapped, unmapped):
 
     # Make sure that 'Filemap' module's 'get_mapped_ranges()' returns the same
     # ranges as we have in the 'mapped' list.
-    filemap = Filemap.Fiemap(f_image)
+    filemap = Filemap.filemap(f_image)
 
     # Check both 'get_mapped_ranges()' and 'get_unmapped_ranges()' for the
     # entire file.