[bmap-tools] [PATCH 06/14] Filemap: implement the FilemapSeek class

Artem Bityutskiy dedekind1 at gmail.com
Tue Jan 21 12:34:27 EST 2014


From: Artem Bityutskiy <artem.bityutskiy at intel.com>

Change-Id: Idf8bf086ead16affede86a1839f29536b8e90bbd
Signed-off-by: Artem Bityutskiy <artem.bityutskiy at intel.com>
---
 bmaptools/Filemap.py | 61 ++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 57 insertions(+), 4 deletions(-)

diff --git a/bmaptools/Filemap.py b/bmaptools/Filemap.py
index 76d2a5f..8104ff0 100644
--- a/bmaptools/Filemap.py
+++ b/bmaptools/Filemap.py
@@ -28,6 +28,7 @@ import array
 import fcntl
 from bmaptools import BmapHelpers
 
+
 class Error(Exception):
     """
     A class for exceptions generated by this module. We currently support only
@@ -36,6 +37,7 @@ class Error(Exception):
     """
     pass
 
+
 class _FilemapBase:
     """
     This is a base class for a couple of other classes in this module. This
@@ -140,6 +142,10 @@ class _FilemapBase:
 
         raise Error("the method is not implemented")
 
+# The 'SEEK_HOLE' and 'SEEK_DATA' options of the file seek system call
+_SEEK_DATA = 3
+_SEEK_HOLE = 4
+
 class FilemapSeek(_FilemapBase):
     """
     This class uses the 'SEEK_HOLE' and 'SEEK_DATA' to find file block mapping.
@@ -151,21 +157,67 @@ class FilemapSeek(_FilemapBase):
         # Call the base class constructor first
         _FilemapBase.__init__(self, image)
 
+    def _lseek(self, file_obj, offset, whence):
+        """This is a helper function which invokes 'os.lseek' for file object
+        'file_obj' and with specified 'offset' and 'whence'. The 'whence'
+        argument is supposed to be either '_SEEK_DATA' or '_SEEK_HOLE'. When
+        there is no more data or hole starting from 'offset', this function
+        returns '-1'.  Otherwise the data or hole position is returned."""
+
+        try:
+            return os.lseek(file_obj.fileno(), offset, whence)
+        except OSError as err:
+            # The 'lseek' system call returns the ENXIO if there is no data or
+            # hole starting from the specified offset.
+            if err.errno == os.errno.ENXIO:
+                return -1
+            else:
+                raise
+
     def block_is_mapped(self, block):
         """Refer the '_FilemapBase' class for the documentation."""
-        raise Error("Not implemented")
+        offs = self._lseek(self._f_image, block * self.block_size, _SEEK_DATA)
+        if offs == -1:
+            return False
+
+        return offs / self.block_size == block
 
     def block_is_unmapped(self, block):
         """Refer the '_FilemapBase' class for the documentation."""
-        raise Error("Not implemented")
+        return not self.block_is_mapped(block)
+
+    def _get_ranges(self, start, count, whence1, whence2):
+        """
+        This function implements 'get_mapped_ranges()' and
+        'get_unmapped_ranges()' depending on what is passed in the 'whence1'
+        and 'whence2' arguments.
+        """
+
+        assert whence1 != whence2
+        end = start * self.block_size
+        limit = end + count * self.block_size
+
+        while True:
+            start = self._lseek(self._f_image, end, whence1)
+            if start == -1 or start >= limit or start == self.image_size:
+                break
+
+            end = self._lseek(self._f_image, start, whence2)
+            if end == -1 or end == self.image_size:
+                end = self.blocks_cnt * self.block_size
+            if end > limit:
+                end = limit
+
+            yield (start / self.block_size, end / self.block_size - 1)
 
     def get_mapped_ranges(self, start, count):
         """Refer the '_FilemapBase' class for the documentation."""
-        raise Error("Not implemented")
+        return self._get_ranges(start, count, _SEEK_DATA, _SEEK_HOLE)
 
     def get_unmapped_ranges(self, start, count):
         """Refer the '_FilemapBase' class for the documentation."""
-        raise Error("Not implemented")
+        return self._get_ranges(start, count, _SEEK_HOLE, _SEEK_DATA)
+
 
 # Below goes the FIEMAP ioctl implementation, which is not very readable
 # because it deals with the rather complex FIEMAP ioctl. To understand the
@@ -352,6 +404,7 @@ class FilemapFiemap(_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
-- 
1.8.3.1




More information about the Bmap-tools mailing list