[PATCH] Add --skip option similar to dd skip=N option

Eric Seifert seiferteric at gmail.com
Fri Feb 27 16:33:49 PST 2015


This will skip N bytes from the input file when writing the output file.
This is useful if splitting images (say by partition). As an example, if you
have a disk image sda.img and a bmap sda.img.bmap and you want to extract
the first partition sda1, you can run this command:

bmaptool copy --skip 1048576 --bmap sda.img.bmap sda.img sda1.img

Where 1048576 bytes is the offset into the disk where to first
partition is (2048 * 512 byte sectors).
---
 .gitignore            |  1 +
 bmaptool              |  6 +++++-
 bmaptools/BmapCopy.py | 35 +++++++++++++++++++++++++----------
 3 files changed, 31 insertions(+), 11 deletions(-)
 create mode 100644 .gitignore

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0d20b64
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/bmaptool b/bmaptool
index 9f6b50d..650ca25 100755
--- a/bmaptool
+++ b/bmaptool
@@ -485,7 +485,7 @@ def copy_command(args, log):
 
     try:
         try:
-            writer.copy(False, not args.no_verify)
+            writer.copy(False, not args.no_verify, args.skip or 0)
         except (BmapCopy.Error, TransRead.Error) as err:
             log.error(str(err))
             raise SystemExit(1)
@@ -648,6 +648,10 @@ def parse_arguments():
     text = "do not verify the data checksum while writing"
     parser_copy.add_argument("--no-verify", action="store_true", help=text)
 
+    # The --skip option
+    text = "Skip N bytes of the input file"
+    parser_copy.add_argument("--skip", type=int, help=text)
+
     return parser.parse_args()
 
 def setup_logger(loglevel):
diff --git a/bmaptools/BmapCopy.py b/bmaptools/BmapCopy.py
index eedeafe..a7e1561 100644
--- a/bmaptools/BmapCopy.py
+++ b/bmaptools/BmapCopy.py
@@ -532,7 +532,7 @@ class BmapCopy(object):
 
         self._batch_queue.put(None)
 
-    def copy(self, sync=True, verify=True):
+    def copy(self, sync=True, verify=True, skip=0):
         """
         Copy the image to the destination file using bmap. The 'sync' argument
         defines whether the destination file has to be synchronized upon
@@ -546,6 +546,8 @@ class BmapCopy(object):
         thread.start_new_thread(self._get_data, (verify, ))
 
         blocks_written = 0
+        blocks_skipped = 0
+        mapped_blocks_skipped = 0
         bytes_written = 0
         fsync_last = 0
 
@@ -567,11 +569,25 @@ class BmapCopy(object):
                 raise exc_info[0], exc_info[1], exc_info[2]
 
             (start, end, buf) = batch[1:4]
-
             assert len(buf) <= (end - start + 1) * self.block_size
             assert len(buf) > (end - start) * self.block_size
 
-            self._f_dest.seek(start * self.block_size)
+            bytes_left_to_skip = 0
+            if ((end+1)*self.block_size) <= skip:
+                #Skip writing whole batch
+                blocks_skipped = end
+                mapped_blocks_skipped += (end - start + 1)
+                continue
+            else:
+                if start*self.block_size <= skip:
+                    #Skipping ends somewhere between start and end, possibly mid block.
+                    bytes_left_to_skip = skip - start*self.block_size
+                    buf = buf[bytes_left_to_skip:]
+                    blocks_skipped = start + int(bytes_left_to_skip / self.block_size)
+                    mapped_blocks_skipped += int(bytes_left_to_skip / self.block_size)
+                else:
+                    #We are done skipping, write whole batch
+                    self._f_dest.seek(start * self.block_size - skip)
 
             # Synchronize the destination file if we reached the watermark
             if self._dest_fsync_watermark:
@@ -586,10 +602,9 @@ class BmapCopy(object):
                             % (start, end, self._dest_path, err))
 
             self._batch_queue.task_done()
-            blocks_written += (end - start + 1)
+            blocks_written += (end - start + 1 - int(bytes_left_to_skip / self.block_size))
             bytes_written += len(buf)
-
-            self._update_progress(blocks_written)
+            self._update_progress(blocks_written + mapped_blocks_skipped)
 
         if not self.image_size:
             # The image size was unknown up until now, set it
@@ -597,17 +612,17 @@ class BmapCopy(object):
 
         # This is just a sanity check - we should have written exactly
         # 'mapped_cnt' blocks.
-        if blocks_written != self.mapped_cnt:
+        if blocks_written + mapped_blocks_skipped != self.mapped_cnt:
             raise Error("wrote %u blocks from image '%s' to '%s', but should "
                         "have %u - bmap file '%s' does not belong to this "
                         "image"
-                        % (blocks_written, self._image_path, self._dest_path,
+                        % (blocks_written + mapped_blocks_skipped, self._image_path, self._dest_path,
                            self.mapped_cnt, self._bmap_path))
 
-        if self._dest_is_regfile:
+        if self._dest_is_regfile and (self.image_size - skip) > 0:
             # Make sure the destination file has the same size as the image
             try:
-                os.ftruncate(self._f_dest.fileno(), self.image_size)
+                os.ftruncate(self._f_dest.fileno(), self.image_size - skip)
             except OSError as err:
                 raise Error("cannot truncate file '%s': %s"
                             % (self._dest_path, err))
-- 
2.3.0




More information about the Bmap-tools mailing list