Skip to content
Commits on Source (8)
......@@ -81,10 +81,10 @@ class ApkContainer(Archive):
current_dir.insert(0, relpath)
continue
relpath = abspath[len(self._unpacked)+1:]
relpath = abspath[len(self._unpacked) + 1:]
if filename == 'AndroidManifest.xml':
containing_dir = root[len(self._unpacked)+1:]
containing_dir = root[len(self._unpacked) + 1:]
if containing_dir == 'original':
self._andmanifest_orig = relpath
if containing_dir == '':
......@@ -160,7 +160,7 @@ class ApkFile(File):
def compare_details(self, other, source=None):
zipinfo_difference = Difference.from_command(Zipinfo, self.path, other.path) or \
Difference.from_command(ZipinfoVerbose, self.path, other.path)
Difference.from_command(ZipinfoVerbose, self.path, other.path)
return [zipinfo_difference]
......
......@@ -46,7 +46,8 @@ class ArContainer(LibarchiveContainer):
filtered_out = [p for p in members if p[0] in known_ignores]
if filtered_out:
for k, v in filtered_out:
logger.debug("ignored ar member '%s' because %s", k, known_ignores[k])
logger.debug("ignored ar member '%s' because %s",
k, known_ignores[k])
return [p for p in members if p[0] not in known_ignores]
......
......@@ -37,7 +37,8 @@ logger = logging.getLogger(__name__)
class CbfsListing(Command):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._header_re = re.compile(r'^.*: ([^,]+, bootblocksize [0-9]+, romsize [0-9]+, offset 0x[0-9A-Fa-f]+)$')
self._header_re = re.compile(
r'^.*: ([^,]+, bootblocksize [0-9]+, romsize [0-9]+, offset 0x[0-9A-Fa-f]+)$')
@tool_required('cbfstool')
def cmdline(self):
......@@ -75,9 +76,11 @@ class CbfsContainer(Archive):
@tool_required('cbfstool')
def extract(self, member_name, dest_dir):
dest_path = os.path.join(dest_dir, os.path.basename(member_name))
cmd = ['cbfstool', self.source.path, 'extract', '-n', member_name, '-f', dest_path]
cmd = ['cbfstool', self.source.path, 'extract',
'-n', member_name, '-f', dest_path]
logger.debug("cbfstool extract %s to %s", member_name, dest_path)
subprocess.check_call(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
subprocess.check_call(
cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
return dest_path
......@@ -91,7 +94,8 @@ CBFS_MAXIMUM_FILE_SIZE = 24 * 2 ** 20 # 24 MiB
def is_header_valid(buf, size, offset=0):
magic, version, romsize, bootblocksize, align, cbfs_offset, architecture, pad = struct.unpack_from('!IIIIIIII', buf, offset)
magic, version, romsize, bootblocksize, align, cbfs_offset, architecture, pad = struct.unpack_from(
'!IIIIIIII', buf, offset)
return magic == CBFS_HEADER_MAGIC and \
(version == CBFS_HEADER_VERSION1 or version == CBFS_HEADER_VERSION2) and \
(romsize <= size) and \
......@@ -122,7 +126,8 @@ class CbfsFile(File):
elif not file.name.endswith('.rom'):
return False
else:
logger.debug('CBFS relative offset seems wrong, scanning whole image')
logger.debug(
'CBFS relative offset seems wrong, scanning whole image')
f.seek(0, io.SEEK_SET)
offset = 0
buf = f.read(CBFS_HEADER_SIZE)
......
......@@ -108,7 +108,8 @@ class DebFile(File):
def md5sums(self):
if not hasattr(self, '_md5sums'):
control_tar = self.as_container.control_tar
md5sums_file = control_tar.as_container.lookup_file('./md5sums') if control_tar else None
md5sums_file = control_tar.as_container.lookup_file(
'./md5sums') if control_tar else None
if md5sums_file:
self._md5sums = md5sums_file.parse()
else:
......@@ -122,7 +123,8 @@ class DebFile(File):
return None
if not hasattr(self, '_control'):
control_file = self.as_container.control_tar.as_container.lookup_file('./control')
control_file = self.as_container.control_tar.as_container.lookup_file(
'./control')
if control_file:
with open(control_file.path, 'rb') as f:
self._control = deb822.Deb822(f)
......@@ -139,11 +141,12 @@ class Md5sumsFile(File):
@classmethod
def recognizes(cls, file):
return isinstance(file, ArchiveMember) and \
file.name == './md5sums' and \
isinstance(file.container.source, ArchiveMember) and \
isinstance(file.container.source.container.source, ArchiveMember) and \
DebContainer.RE_CONTROL_TAR.match(file.container.source.container.source.name) and \
isinstance(file.container.source.container.source.container.source, DebFile)
file.name == './md5sums' and \
isinstance(file.container.source, ArchiveMember) and \
isinstance(file.container.source.container.source, ArchiveMember) and \
DebContainer.RE_CONTROL_TAR.match(file.container.source.container.source.name) and \
isinstance(
file.container.source.container.source.container.source, DebFile)
def parse(self):
try:
......@@ -193,9 +196,9 @@ class DebDataTarFile(File):
@classmethod
def recognizes(cls, file):
return isinstance(file, ArchiveMember) and \
isinstance(file.container.source, ArchiveMember) and \
DebContainer.RE_DATA_TAR.match(file.container.source.name) and \
isinstance(file.container.source.container.source, DebFile)
isinstance(file.container.source, ArchiveMember) and \
DebContainer.RE_DATA_TAR.match(file.container.source.name) and \
isinstance(file.container.source.container.source, DebFile)
def compare_details(self, other, source=None):
return [Difference.from_text_readers(list_libarchive(self.path),
......
......@@ -27,7 +27,8 @@ class DotChangesFile(TextFile):
difference = super().compare(other, *args, **kwargs)
if not difference:
return None
difference.add_comment('Unable to find Python debian module. Falling back to text comparison.')
difference.add_comment(
'Unable to find Python debian module. Falling back to text comparison.')
return difference
......@@ -38,7 +39,8 @@ class DotDscFile(TextFile):
difference = super().compare(other, *args, **kwargs)
if not difference:
return None
difference.add_comment('Unable to find Python debian module. Falling back to text comparison.')
difference.add_comment(
'Unable to find Python debian module. Falling back to text comparison.')
return difference
......@@ -49,5 +51,6 @@ class DotBuildinfoFile(TextFile):
difference = super().compare(other, *args, **kwargs)
if not difference:
return None
difference.add_comment('Unable to find Python debian module. Falling back to text comparison.')
difference.add_comment(
'Unable to find Python debian module. Falling back to text comparison.')
return difference
......@@ -71,7 +71,7 @@ class Device(File):
def compare(self, other, source=None):
with open(self.path) as my_content, \
open(other.path) as other_content:
open(other.path) as other_content:
return Difference.from_text_readers(my_content, other_content, self.name, other.name, source=source, comment="device")
......
......@@ -41,8 +41,10 @@ def list_files(path):
path = os.path.realpath(path)
all_files = []
for root, dirs, names in os.walk(path):
all_files.extend([os.path.join(root[len(path) + 1:], dir) for dir in dirs])
all_files.extend([os.path.join(root[len(path) + 1:], name) for name in names])
all_files.extend([os.path.join(root[len(path) + 1:], dir)
for dir in dirs])
all_files.extend([os.path.join(root[len(path) + 1:], name)
for name in names])
all_files.sort()
return all_files
......@@ -120,7 +122,8 @@ def xattr(path1, path2):
try:
get_all = xattr_.get_all
except AttributeError:
get_all = lambda x: xattr_.xattr(x).items()
def get_all(x):
return xattr_.xattr(x).items()
def fn(x):
return '\n'.join('{}: {}'.format(
......@@ -135,7 +138,8 @@ def xattr(path1, path2):
def compare_meta(path1, path2):
if Config().exclude_directory_metadata:
logger.debug("Excluding directory metadata for paths (%s, %s)", path1, path2)
logger.debug(
"Excluding directory metadata for paths (%s, %s)", path1, path2)
return []
logger.debug('compare_meta(%s, %s)', path1, path2)
......@@ -154,7 +158,8 @@ def compare_meta(path1, path2):
try:
differences.append(Difference.from_command(Getfacl, path1, path2))
except RequiredToolNotFound:
logger.warning("Unable to find 'getfacl', some directory metadata differences might not be noticed.")
logger.warning(
"Unable to find 'getfacl', some directory metadata differences might not be noticed.")
try:
lsattr1 = lsattr(path1)
lsattr2 = lsattr(path2)
......@@ -166,10 +171,12 @@ def compare_meta(path1, path2):
source='lsattr',
))
except RequiredToolNotFound:
logger.info("Unable to find 'lsattr', some directory metadata differences might not be noticed.")
logger.info(
"Unable to find 'lsattr', some directory metadata differences might not be noticed.")
differences.append(xattr(path1, path2))
return [d for d in differences if d is not None]
def compare_directories(path1, path2, source=None):
return FilesystemDirectory(path1).compare(FilesystemDirectory(path2))
......@@ -255,8 +262,10 @@ class DirectoryContainer(Container):
def comparisons(self, other):
my_members = collections.OrderedDict(self.get_adjusted_members_sizes())
other_members = collections.OrderedDict(other.get_adjusted_members_sizes())
total_size = sum(x[1] for x in my_members.values()) + sum(x[1] for x in other_members.values())
other_members = collections.OrderedDict(
other.get_adjusted_members_sizes())
total_size = sum(x[1] for x in my_members.values()) + \
sum(x[1] for x in other_members.values())
to_compare = set(my_members.keys()).intersection(other_members.keys())
with Progress(total_size) as p:
......
......@@ -376,7 +376,8 @@ def get_build_id(path):
logger.debug("Unable to get Build ID for %s: %s", path, e)
return None
m = re.search(r'^\s+Build ID: ([0-9a-f]+)$', output.decode('utf-8'), flags=re.MULTILINE)
m = re.search(r'^\s+Build ID: ([0-9a-f]+)$',
output.decode('utf-8'), flags=re.MULTILINE)
if not m:
return None
......@@ -394,7 +395,8 @@ def get_debug_link(path):
logger.debug("Unable to get Build Id for %s: %s", path, e)
return None
m = re.search(r'^\s+\[\s+0\]\s+(\S+)$', output.decode('utf-8', errors='replace'), flags=re.MULTILINE)
m = re.search(r'^\s+\[\s+0\]\s+(\S+)$', output.decode('utf-8',
errors='replace'), flags=re.MULTILINE)
if not m:
return None
......@@ -415,8 +417,10 @@ class ElfContainer(Container):
super().__init__(*args, **kwargs)
logger.debug("Creating ElfContainer for %s", self.source.path)
cmd = [get_tool_name('readelf'), '--wide', '--section-headers', self.source.path]
output = subprocess.check_output(cmd, shell=False, stderr=subprocess.DEVNULL)
cmd = [get_tool_name('readelf'), '--wide',
'--section-headers', self.source.path]
output = subprocess.check_output(
cmd, shell=False, stderr=subprocess.DEVNULL)
has_debug_symbols = False
try:
......@@ -448,7 +452,8 @@ class ElfContainer(Container):
for x in flags if x in ElfContainer.SECTION_FLAG_MAPPING
][0]
logger.debug("Adding section %s (%s) as %s", name, type, elf_class)
logger.debug("Adding section %s (%s) as %s",
name, type, elf_class)
self._sections[name] = elf_class(self, name)
except Exception as e:
......@@ -492,7 +497,8 @@ class ElfContainer(Container):
deb.container.dbgsym_build_id_map = get_build_id_map(deb.container)
if build_id not in deb.container.dbgsym_build_id_map:
logger.debug('Unable to find a matching debug package for Build Id %s', build_id)
logger.debug(
'Unable to find a matching debug package for Build Id %s', build_id)
return
dbgsym_package = deb.container.dbgsym_build_id_map[build_id]
......@@ -500,9 +506,11 @@ class ElfContainer(Container):
build_id[:2],
build_id[2:],
)
debug_file = dbgsym_package.as_container.data_tar.as_container.lookup_file(debug_file_path)
debug_file = dbgsym_package.as_container.data_tar.as_container.lookup_file(
debug_file_path)
if not debug_file:
logger.debug('Unable to find the matching debug file %s in %s', debug_file_path, dbgsym_package)
logger.debug('Unable to find the matching debug file %s in %s',
debug_file_path, dbgsym_package)
return
# Create a .debug directory and link the debug symbols there with the
......@@ -529,7 +537,8 @@ class ElfContainer(Container):
prefix='{}.debuglink.'.format(self.source.path),
).name
objcopy('--only-section=.gnu_debuglink', self.source.path, debuglink_path)
objcopy('--only-section=.gnu_debuglink',
self.source.path, debuglink_path)
# 2. Monkey-patch the ElfSection object created for the .gnu_debuglink
# to change the path to point to this new file
......
......@@ -46,7 +46,8 @@ class Msgunfmt(Command):
if not self._encoding:
self._header.write(line)
if line == b'\n':
logger.debug("unable to determine PO encoding, let's hope it's utf-8")
logger.debug(
"unable to determine PO encoding, let's hope it's utf-8")
self._encoding = 'utf-8'
return self._header.getvalue()
found = Msgunfmt.CHARSET_RE.match(line)
......
......@@ -47,5 +47,5 @@ class LlvmBitCodeFile(File):
FILE_TYPE_RE = re.compile(r'^LLVM IR bitcode')
def compare_details(self, other, source=None):
return [Difference.from_command(LlvmBcAnalyzer, self.path, other.path),
return [Difference.from_command(LlvmBcAnalyzer, self.path, other.path),
Difference.from_command(LlvmBcDisassembler, self.path, other.path)]
......@@ -72,15 +72,18 @@ class OtoolDisassembleInternal(Otool):
class MachoFile(File):
DESCRIPTION = "MacOS binaries"
FILE_TYPE_RE = re.compile(r'^Mach-O ')
RE_EXTRACT_ARCHS = re.compile(r'^(?:Architectures in the fat file: .* are|Non-fat file: .* is architecture): (.*)$')
RE_EXTRACT_ARCHS = re.compile(
r'^(?:Architectures in the fat file: .* are|Non-fat file: .* is architecture): (.*)$')
@staticmethod
@tool_required('lipo')
def get_arch_from_macho(path):
lipo_output = subprocess.check_output(['lipo', '-info', path]).decode('utf-8')
lipo_output = subprocess.check_output(
['lipo', '-info', path]).decode('utf-8')
lipo_match = MachoFile.RE_EXTRACT_ARCHS.match(lipo_output)
if lipo_match is None:
raise ValueError('lipo -info on Mach-O file %s did not produce expected output. Output was: %s' % path, lipo_output)
raise ValueError(
'lipo -info on Mach-O file %s did not produce expected output. Output was: %s' % path, lipo_output)
return lipo_match.group(1).split()
def compare_details(self, other, source=None):
......
......@@ -46,7 +46,8 @@ class PngFile(File):
FILE_TYPE_RE = re.compile(r'^PNG image data\b')
def compare_details(self, other, source=None):
sng_diff = Difference.from_command(Sng, self.path, other.path, source='sng')
sng_diff = Difference.from_command(
Sng, self.path, other.path, source='sng')
differences = [sng_diff]
if sng_diff is not None and Config().compute_visual_diffs and \
......
......@@ -73,7 +73,8 @@ class PpuFile(File):
if not hasattr(PpuFile, 'ppu_version'):
try:
with profile('command', 'ppudump'):
subprocess.check_output(['ppudump', '-vh', file.path], shell=False, stderr=subprocess.STDOUT)
subprocess.check_output(
['ppudump', '-vh', file.path], shell=False, stderr=subprocess.STDOUT)
PpuFile.ppu_version = ppu_version
except subprocess.CalledProcessError as e:
error = e.output.decode('utf-8', errors='ignore')
......
......@@ -99,7 +99,8 @@ class RpmContainer(Archive):
dest_path = os.path.join(dest_dir, 'content')
cmd = ['rpm2cpio', self.source.path]
with open(dest_path, 'wb') as dest:
subprocess.check_call(cmd, shell=False, stdout=dest, stderr=subprocess.PIPE)
subprocess.check_call(
cmd, shell=False, stdout=dest, stderr=subprocess.PIPE)
return dest_path
......
......@@ -31,5 +31,6 @@ class RpmFile(AbstractRpmFile):
difference = self.compare_bytes(other)
if not difference:
return None
difference.add_comment('Unable to import Python rpm module. Falling back to binary comparison.')
difference.add_comment(
'Unable to import Python rpm module. Falling back to binary comparison.')
return difference
......@@ -51,7 +51,8 @@ class RustObjectContainer(Archive):
with open(dest_path, 'wb') as fpw, open(self.source.path, 'rb') as fpr:
raw_deflate = fpr.read()[RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET:]
# decompressobj() ignores the (non-existent) checksum; a zlib.decompress() would error
raw_inflate = zlib.decompressobj().decompress(ZLIB_DEFAULT_COMPRESSION + raw_deflate)
raw_inflate = zlib.decompressobj().decompress(
ZLIB_DEFAULT_COMPRESSION + raw_deflate)
fpw.write(raw_inflate)
return dest_path
......
......@@ -89,7 +89,8 @@ class SquashfsMember(ArchiveMember):
class SquashfsRegularFile(SquashfsMember):
# Example line:
# -rw-r--r-- user/group 446 2015-06-24 14:49 squashfs-root/text
LINE_RE = re.compile(r'^\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+(?P<member_name>.*)$')
LINE_RE = re.compile(
r'^\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+(?P<member_name>.*)$')
@staticmethod
def parse(line):
......@@ -105,7 +106,8 @@ class SquashfsRegularFile(SquashfsMember):
class SquashfsDirectory(Directory, SquashfsMember):
# Example line:
# drwxr-xr-x user/group 51 2015-06-24 14:47 squashfs-root
LINE_RE = re.compile(r'^\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+(?P<member_name>.*)$')
LINE_RE = re.compile(
r'^\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+(?P<member_name>.*)$')
@staticmethod
def parse(line):
......@@ -125,7 +127,8 @@ class SquashfsDirectory(Directory, SquashfsMember):
@property
def path(self):
raise NotImplementedError("SquashfsDirectory is not meant to be extracted.")
raise NotImplementedError(
"SquashfsDirectory is not meant to be extracted.")
def is_directory(self):
return True
......@@ -186,7 +189,8 @@ class SquashfsDevice(Device, SquashfsMember):
d['mode'] = SquashfsDevice.KIND_MAP[d['kind']]
del d['kind']
except KeyError:
raise SquashfsInvalidLineFormat("unknown device kind %s" % d['kind'])
raise SquashfsInvalidLineFormat(
"unknown device kind %s" % d['kind'])
try:
d['major'] = int(d['major'])
......
......@@ -62,5 +62,5 @@ class Symlink(File):
def compare(self, other, source=None):
with open(self.path) as my_content, \
open(other.path) as other_content:
open(other.path) as other_content:
return Difference.from_text_readers(my_content, other_content, self.name, other.name, source=source, comment="symlink")
......@@ -50,15 +50,18 @@ class TextFile(File):
other_encoding = other.encoding or 'utf-8'
try:
with codecs.open(self.path, 'r', encoding=my_encoding) as my_content, \
codecs.open(other.path, 'r', encoding=other_encoding) as other_content:
difference = Difference.from_text_readers(my_content, other_content, self.name, other.name, source)
codecs.open(other.path, 'r', encoding=other_encoding) as other_content:
difference = Difference.from_text_readers(
my_content, other_content, self.name, other.name, source)
# Check if difference is only in line order.
if difference and order_only_difference(difference.unified_diff):
difference.add_comment("ordering differences only")
if my_encoding != other_encoding:
if difference is None:
difference = Difference(None, self.path, other.path, source)
difference.add_details([Difference.from_text(my_encoding, other_encoding, None, None, source='encoding')])
difference = Difference(
None, self.path, other.path, source)
difference.add_details([Difference.from_text(
my_encoding, other_encoding, None, None, source='encoding')])
return difference
except (LookupError, UnicodeDecodeError):
# unknown or misdetected encoding
......
......@@ -90,11 +90,13 @@ class ArchiveMember(File):
@property
def path(self):
if self._path is None:
logger.debug("Unpacking %s from %s", self._name, self.container.source.name)
logger.debug("Unpacking %s from %s", self._name,
self.container.source.name)
assert self._temp_dir is None
self._temp_dir = get_temporary_directory()
with profile('container_extract', self.container):
self._path = self.container.extract(self._name, self._temp_dir.name)
self._path = self.container.extract(
self._name, self._temp_dir.name)
return self._path
def cleanup(self):
......