Allow generating OTA package from non-sparse images.

Test: build OTA package in cuttlefish

Bug: 120041578
Bug: 113175337
Change-Id: I246c38e08376c837b7f126aa19cb8c1d73ed1e26
Merged-In: I246c38e08376c837b7f126aa19cb8c1d73ed1e26
This commit is contained in:
Yifan Hong
2019-04-04 15:37:57 -07:00
parent 508850e298
commit 50db54519e
4 changed files with 210 additions and 26 deletions

View File

@@ -187,6 +187,78 @@ class DataImage(Image):
fd.write(data)
class FileImage(Image):
"""An image wrapped around a raw image file."""
def __init__(self, path, hashtree_info_generator=None):
self.path = path
self.blocksize = 4096
self._file_size = os.path.getsize(self.path)
self._file = open(self.path, 'r')
if self._file_size % self.blocksize != 0:
raise ValueError("Size of file %s must be multiple of %d bytes, but is %d"
% self.path, self.blocksize, self._file_size)
self.total_blocks = self._file_size / self.blocksize
self.care_map = RangeSet(data=(0, self.total_blocks))
self.clobbered_blocks = RangeSet()
self.extended = RangeSet()
self.hashtree_info = None
if hashtree_info_generator:
self.hashtree_info = hashtree_info_generator.Generate(self)
zero_blocks = []
nonzero_blocks = []
reference = '\0' * self.blocksize
for i in range(self.total_blocks):
d = self._file.read(self.blocksize)
if d == reference:
zero_blocks.append(i)
zero_blocks.append(i+1)
else:
nonzero_blocks.append(i)
nonzero_blocks.append(i+1)
assert zero_blocks or nonzero_blocks
self.file_map = {}
if zero_blocks:
self.file_map["__ZERO"] = RangeSet(data=zero_blocks)
if nonzero_blocks:
self.file_map["__NONZERO"] = RangeSet(data=nonzero_blocks)
if self.hashtree_info:
self.file_map["__HASHTREE"] = self.hashtree_info.hashtree_range
def __del__(self):
self._file.close()
def _GetRangeData(self, ranges):
for s, e in ranges:
self._file.seek(s * self.blocksize)
for _ in range(s, e):
yield self._file.read(self.blocksize)
def RangeSha1(self, ranges):
h = sha1()
for data in self._GetRangeData(ranges): # pylint: disable=not-an-iterable
h.update(data)
return h.hexdigest()
def ReadRangeSet(self, ranges):
return list(self._GetRangeData(ranges))
def TotalSha1(self, include_clobbered_blocks=False):
assert not self.clobbered_blocks
return self.RangeSha1(self.care_map)
def WriteRangeDataToFd(self, ranges, fd):
for data in self._GetRangeData(ranges): # pylint: disable=not-an-iterable
fd.write(data)
class Transfer(object):
def __init__(self, tgt_name, src_name, tgt_ranges, src_ranges, tgt_sha1,
src_sha1, style, by_id):