[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