summaryrefslogtreecommitdiffstats
path: root/tools/releasetools/sparse_img.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/releasetools/sparse_img.py')
-rw-r--r--tools/releasetools/sparse_img.py50
1 files changed, 36 insertions, 14 deletions
diff --git a/tools/releasetools/sparse_img.py b/tools/releasetools/sparse_img.py
index 78f3057..7019f00 100644
--- a/tools/releasetools/sparse_img.py
+++ b/tools/releasetools/sparse_img.py
@@ -21,10 +21,17 @@ import rangelib
class SparseImage(object):
- """Wraps a sparse image file (and optional file map) into an image
- object suitable for passing to BlockImageDiff."""
+ """Wraps a sparse image file into an image object.
- def __init__(self, simg_fn, file_map_fn=None):
+ Wraps a sparse image file (and optional file map and clobbered_blocks) into
+ an image object suitable for passing to BlockImageDiff. file_map contains
+ the mapping between files and their blocks. clobbered_blocks contains the set
+ of blocks that should be always written to the target regardless of the old
+ contents (i.e. copying instead of patching). clobbered_blocks should be in
+ the form of a string like "0" or "0 1-5 8".
+ """
+
+ def __init__(self, simg_fn, file_map_fn=None, clobbered_blocks=None):
self.simg_f = f = open(simg_fn, "rb")
header_bin = f.read(28)
@@ -57,6 +64,7 @@ class SparseImage(object):
pos = 0 # in blocks
care_data = []
self.offset_map = offset_map = []
+ self.clobbered_blocks = rangelib.RangeSet(data=clobbered_blocks)
for i in range(total_chunks):
header_bin = f.read(12)
@@ -103,17 +111,23 @@ class SparseImage(object):
self.offset_index = [i[0] for i in offset_map]
if file_map_fn:
- self.LoadFileBlockMap(file_map_fn)
+ self.LoadFileBlockMap(file_map_fn, self.clobbered_blocks)
else:
self.file_map = {"__DATA": self.care_map}
def ReadRangeSet(self, ranges):
return [d for d in self._GetRangeData(ranges)]
- def TotalSha1(self):
- """Return the SHA-1 hash of all data in the 'care' regions of this image."""
+ def TotalSha1(self, include_clobbered_blocks=False):
+ """Return the SHA-1 hash of all data in the 'care' regions.
+
+ If include_clobbered_blocks is True, it returns the hash including the
+ clobbered_blocks."""
+ ranges = self.care_map
+ if not include_clobbered_blocks:
+ ranges = ranges.subtract(self.clobbered_blocks)
h = sha1()
- for d in self._GetRangeData(self.care_map):
+ for d in self._GetRangeData(ranges):
h.update(d)
return h.hexdigest()
@@ -156,7 +170,7 @@ class SparseImage(object):
yield fill_data * (this_read * (self.blocksize >> 2))
to_read -= this_read
- def LoadFileBlockMap(self, fn):
+ def LoadFileBlockMap(self, fn, clobbered_blocks):
remaining = self.care_map
self.file_map = out = {}
@@ -166,14 +180,20 @@ class SparseImage(object):
ranges = rangelib.RangeSet.parse(ranges)
out[fn] = ranges
assert ranges.size() == ranges.intersect(remaining).size()
+
+ # Currently we assume that blocks in clobbered_blocks are not part of
+ # any file.
+ assert not clobbered_blocks.overlaps(ranges)
remaining = remaining.subtract(ranges)
+ remaining = remaining.subtract(clobbered_blocks)
+
# For all the remaining blocks in the care_map (ie, those that
- # aren't part of the data for any file), divide them into blocks
- # that are all zero and blocks that aren't. (Zero blocks are
- # handled specially because (1) there are usually a lot of them
- # and (2) bsdiff handles files with long sequences of repeated
- # bytes especially poorly.)
+ # aren't part of the data for any file nor part of the clobbered_blocks),
+ # divide them into blocks that are all zero and blocks that aren't.
+ # (Zero blocks are handled specially because (1) there are usually
+ # a lot of them and (2) bsdiff handles files with long sequences of
+ # repeated bytes especially poorly.)
zero_blocks = []
nonzero_blocks = []
@@ -201,12 +221,14 @@ class SparseImage(object):
nonzero_blocks.append(b)
nonzero_blocks.append(b+1)
- assert zero_blocks or nonzero_blocks
+ assert zero_blocks or nonzero_blocks or clobbered_blocks
if zero_blocks:
out["__ZERO"] = rangelib.RangeSet(data=zero_blocks)
if nonzero_blocks:
out["__NONZERO"] = rangelib.RangeSet(data=nonzero_blocks)
+ if clobbered_blocks:
+ out["__COPY"] = clobbered_blocks
def ResetFileMap(self):
"""Throw away the file map and treat the entire image as