diff options
Diffstat (limited to 'tools/releasetools/blockimgdiff.py')
-rw-r--r-- | tools/releasetools/blockimgdiff.py | 44 |
1 files changed, 36 insertions, 8 deletions
diff --git a/tools/releasetools/blockimgdiff.py b/tools/releasetools/blockimgdiff.py index d549f70..3402572 100644 --- a/tools/releasetools/blockimgdiff.py +++ b/tools/releasetools/blockimgdiff.py @@ -74,7 +74,7 @@ class Image(object): def ReadRangeSet(self, ranges): raise NotImplementedError - def TotalSha1(self): + def TotalSha1(self, include_clobbered_blocks=False): raise NotImplementedError @@ -82,11 +82,15 @@ class EmptyImage(Image): """A zero-length image.""" blocksize = 4096 care_map = RangeSet() + clobbered_blocks = RangeSet() total_blocks = 0 file_map = {} def ReadRangeSet(self, ranges): return () - def TotalSha1(self): + def TotalSha1(self, include_clobbered_blocks=False): + # EmptyImage always carries empty clobbered_blocks, so + # include_clobbered_blocks can be ignored. + assert self.clobbered_blocks.size() == 0 return sha1().hexdigest() @@ -114,6 +118,7 @@ class DataImage(Image): self.total_blocks = len(self.data) / self.blocksize self.care_map = RangeSet(data=(0, self.total_blocks)) + self.clobbered_blocks = RangeSet() zero_blocks = [] nonzero_blocks = [] @@ -134,7 +139,10 @@ class DataImage(Image): def ReadRangeSet(self, ranges): return [self.data[s*self.blocksize:e*self.blocksize] for (s, e) in ranges] - def TotalSha1(self): + def TotalSha1(self, include_clobbered_blocks=False): + # DataImage always carries empty clobbered_blocks, so + # include_clobbered_blocks can be ignored. + assert self.clobbered_blocks.size() == 0 return sha1(self.data).hexdigest() @@ -184,6 +192,10 @@ class Transfer(object): # (Typically a domain is a file, and the key in file_map is the # pathname.) # +# clobbered_blocks: a RangeSet containing which blocks contain data +# but may be altered by the FS. They need to be excluded when +# verifying the partition integrity. +# # ReadRangeSet(): a function that takes a RangeSet and returns the # data contained in the image blocks of that RangeSet. The data # is returned as a list or tuple of strings; concatenating the @@ -193,14 +205,15 @@ class Transfer(object): # # TotalSha1(): a function that returns (as a hex string) the SHA-1 # hash of all the data in the image (ie, all the blocks in the -# care_map) +# care_map minus clobbered_blocks, or including the clobbered +# blocks if include_clobbered_blocks is True). # # When creating a BlockImageDiff, the src image may be None, in which # case the list of transfers produced will never read from the # original image. class BlockImageDiff(object): - def __init__(self, tgt, src=None, threads=None, version=2): + def __init__(self, tgt, src=None, threads=None, version=3): if threads is None: threads = multiprocessing.cpu_count() // 2 if threads == 0: @@ -211,7 +224,7 @@ class BlockImageDiff(object): self.src_basenames = {} self.src_numpatterns = {} - assert version in (1, 2) + assert version in (1, 2, 3) self.tgt = tgt if src is None: @@ -295,7 +308,15 @@ class BlockImageDiff(object): next_stash_id += 1 stashes[s] = sid stashed_blocks += sr.size() - out.append("stash %d %s\n" % (sid, sr.to_string_raw())) + if self.version == 2: + out.append("stash %d %s\n" % (sid, sr.to_string_raw())) + else: + sh = self.HashBlocks(self.src, sr) + if sh in stashes: + stashes[sh] += 1 + else: + stashes[sh] = 1 + out.append("stash %s %s\n" % (sh, sr.to_string_raw())) if stashed_blocks > max_stashed_blocks: max_stashed_blocks = stashed_blocks @@ -321,6 +342,7 @@ class BlockImageDiff(object): sid = stashes.pop(s) stashed_blocks -= sr.size() unstashed_src_ranges = unstashed_src_ranges.subtract(sr) + sh = self.HashBlocks(self.src, sr) sr = xf.src_ranges.map_within(sr) mapped_stashes.append(sr) if self.version == 2: @@ -347,7 +369,7 @@ class BlockImageDiff(object): src_str = " ".join(src_str) - # both versions: + # all versions: # zero <rangeset> # new <rangeset> # erase <rangeset> @@ -835,6 +857,12 @@ class BlockImageDiff(object): "zero", self.transfers) continue + elif tgt_fn == "__COPY": + # "__COPY" domain includes all the blocks not contained in any + # file and that need to be copied unconditionally to the target. + Transfer(tgt_fn, None, tgt_ranges, empty, "new", self.transfers) + continue + elif tgt_fn in self.src.file_map: # Look for an exact pathname match in the source. Transfer(tgt_fn, tgt_fn, tgt_ranges, self.src.file_map[tgt_fn], |