diff --git a/scripts/common.py b/scripts/common.py index 9984ef8f6..895f047fa 100644 --- a/scripts/common.py +++ b/scripts/common.py @@ -1657,7 +1657,13 @@ def resolve_local_file( if ".zip" in os.path.basename(path): try: composite = md5_composite(path).lower() - if composite in md5_set: + # A zipped_file md5 is the member's: one member of + # another name has the same composite, and Batocera + # looks the member up by name. + if composite in md5_set and ( + not zipped_file + or check_inside_zip(path, zipped_file, composite) == "ok" + ): return path, "md5_composite_exact" except (zipfile.BadZipFile, OSError) as exc: _warn_unreadable_archive(path, exc) diff --git a/tests/test_e2e.py b/tests/test_e2e.py index 2e0b4ed4c..4d0b203cd 100644 --- a/tests/test_e2e.py +++ b/tests/test_e2e.py @@ -5541,6 +5541,40 @@ struct BurnDriver BurnDrvneogeo = { self.assertEqual(local, path) self.assertEqual(status, "name_exact") + def test_217b_zipped_file_composite_needs_the_member(self): + """One member of another name has the zipped_file md5 as composite. + + Batocera looks the member up by name, so the archive is not proof of + the entry: a MAME rename leaves exactly that archive behind. + """ + import hashlib as hl + import tempfile + + from common import resolve_local_file + + rom = b"inner rom bytes" + rom_md5 = hl.md5(rom).hexdigest() + with tempfile.TemporaryDirectory() as tmpdir: + path = os.path.join(tmpdir, "foo.zip") + with zipfile.ZipFile(path, "w") as zf: + zf.writestr("renamed.bin", rom) + db = { + "files": {"sha1z": {"name": "foo.zip", "path": path, "md5": "f" * 32}}, + "indexes": { + "by_md5": {}, "by_name": {"foo.zip": ["sha1z"]}, + "by_crc32": {}, "by_path_suffix": {}, + }, + } + entry = {"name": "foo.zip", "zipped_file": "expected.bin", "md5": rom_md5} + self.assertNotEqual( + resolve_local_file(entry, db)[1], "md5_composite_exact" + ) + with zipfile.ZipFile(path, "w") as zf: + zf.writestr("expected.bin", rom) + self.assertEqual( + resolve_local_file(entry, db), (path, "md5_composite_exact") + ) + def test_215_check_member_hash_inside_zip(self): """zipped_file entries verify the ROM inside the ZIP, not the ZIP.""" import hashlib as hl