mirror of
https://github.com/dockur/windows.git
synced 2026-07-28 21:53:34 +07:00
Update iso-prototype.py
This commit is contained in:
+98
-39
@@ -577,23 +577,55 @@ def sync_tree(iso, tree: Path, logical_root: PurePosixPath) -> None:
|
||||
add_file_all_namespaces(iso, root_path / name, logical)
|
||||
|
||||
|
||||
def rebuild_windows_eltorito(iso, tree: Path) -> None:
|
||||
def eltorito_platforms(path: Path) -> tuple[bool, bool]:
|
||||
"""Return the BIOS and UEFI platforms present in the source catalog."""
|
||||
_descriptors, catalog_lba = parse_volume_descriptors(path)
|
||||
catalog = parse_boot_catalog(path, catalog_lba)
|
||||
|
||||
if catalog is None:
|
||||
return False, False
|
||||
|
||||
platforms = {
|
||||
entry["platform_id"]
|
||||
for entry in catalog["entries"]
|
||||
if entry["kind"] == "boot_entry"
|
||||
}
|
||||
|
||||
return 0x00 in platforms, 0xEF in platforms
|
||||
|
||||
|
||||
def rebuild_windows_eltorito(
|
||||
iso,
|
||||
tree: Path,
|
||||
*,
|
||||
include_bios: bool,
|
||||
include_uefi: bool,
|
||||
) -> None:
|
||||
"""Replace imported hidden boot entries with complete extracted images.
|
||||
|
||||
Microsoft installation media commonly stores the El Torito boot images as
|
||||
hidden extents. When PyCdlib opens such an ISO, the catalog's 512-byte load
|
||||
hidden extents. When PyCdlib opens such an ISO, the catalog's 512-byte load
|
||||
count is not enough to recover the real size of the hidden UEFI FAT image.
|
||||
Writing the imported entry back can therefore truncate it to one sector.
|
||||
|
||||
Rebuild the catalog from the files extracted by the normal Windows image
|
||||
preparation flow instead. Short root-level ISO9660 names are intentional:
|
||||
the boot images only need stable Directory Records for PyCdlib and do not
|
||||
need to be exposed through the UDF namespace used by Windows Setup.
|
||||
Rebuild only the platforms that existed in the original ISO. This preserves
|
||||
BIOS-only media such as Windows 7 x86 while retaining both BIOS and UEFI on
|
||||
modern hybrid installation media.
|
||||
"""
|
||||
if not include_bios and not include_uefi:
|
||||
return
|
||||
|
||||
bios_source = tree / "boot/etfsboot.com"
|
||||
uefi_source = tree / "efi/microsoft/boot/efisys_noprompt.bin"
|
||||
|
||||
missing = [str(path) for path in (bios_source, uefi_source) if not path.is_file()]
|
||||
missing: list[str] = []
|
||||
|
||||
if include_bios and not bios_source.is_file():
|
||||
missing.append(str(bios_source))
|
||||
|
||||
if include_uefi and not uefi_source.is_file():
|
||||
missing.append(str(uefi_source))
|
||||
|
||||
if missing:
|
||||
raise PrototypeError(
|
||||
"Cannot rebuild Windows El Torito catalog; missing boot image(s): "
|
||||
@@ -604,45 +636,60 @@ def rebuild_windows_eltorito(iso, tree: Path) -> None:
|
||||
uefi_iso_path = "/PYUEFI.BIN;1"
|
||||
|
||||
print("Rebuilding El Torito catalog from extracted boot images:")
|
||||
print(f" BIOS: {bios_source} ({bios_source.stat().st_size} bytes)")
|
||||
print(f" UEFI: {uefi_source} ({uefi_source.stat().st_size} bytes)")
|
||||
|
||||
if include_bios:
|
||||
print(f" BIOS: {bios_source} ({bios_source.stat().st_size} bytes)")
|
||||
|
||||
if include_uefi:
|
||||
print(f" UEFI: {uefi_source} ({uefi_source.stat().st_size} bytes)")
|
||||
|
||||
# These private root-level records avoid depending on the source ISO's very
|
||||
# small ISO9660 tree. The original Microsoft files remain available via UDF.
|
||||
for iso_path in (bios_iso_path, uefi_iso_path):
|
||||
# small ISO9660 tree. The original Microsoft files remain available via UDF.
|
||||
required_records: list[tuple[Path, str]] = []
|
||||
|
||||
if include_bios:
|
||||
required_records.append((bios_source, bios_iso_path))
|
||||
|
||||
if include_uefi:
|
||||
required_records.append((uefi_source, uefi_iso_path))
|
||||
|
||||
for source, iso_path in required_records:
|
||||
try:
|
||||
iso.get_record(iso_path=iso_path)
|
||||
except Exception:
|
||||
continue
|
||||
iso.rm_file(iso_path=iso_path)
|
||||
pass
|
||||
else:
|
||||
iso.rm_file(iso_path=iso_path)
|
||||
|
||||
iso.add_file(str(bios_source), iso_path=bios_iso_path)
|
||||
iso.add_file(str(uefi_source), iso_path=uefi_iso_path)
|
||||
iso.add_file(str(source), iso_path=iso_path)
|
||||
|
||||
# Match the production genisoimage settings: no-emulation BIOS boot, eight
|
||||
# 512-byte sectors loaded, and a boot info table patched into etfsboot.com.
|
||||
iso.add_eltorito(
|
||||
bios_iso_path,
|
||||
boot_load_size=8,
|
||||
platform_id=0x00,
|
||||
boot_info_table=True,
|
||||
media_name="noemul",
|
||||
bootable=True,
|
||||
boot_load_seg=0,
|
||||
)
|
||||
|
||||
# A second add_eltorito() call creates an alternate catalog section. Leaving
|
||||
# boot_load_size unset makes PyCdlib use the complete EFI FAT image rather
|
||||
# than the misleading one-sector count imported from Microsoft media.
|
||||
iso.add_eltorito(
|
||||
uefi_iso_path,
|
||||
platform_id=0xEF,
|
||||
efi=True,
|
||||
media_name="noemul",
|
||||
bootable=True,
|
||||
boot_load_seg=0,
|
||||
)
|
||||
if include_bios:
|
||||
# Match the production genisoimage settings: no-emulation BIOS boot,
|
||||
# eight 512-byte sectors loaded, and a boot info table patched into
|
||||
# etfsboot.com.
|
||||
iso.add_eltorito(
|
||||
bios_iso_path,
|
||||
boot_load_size=8,
|
||||
platform_id=0x00,
|
||||
boot_info_table=True,
|
||||
media_name="noemul",
|
||||
bootable=True,
|
||||
boot_load_seg=0,
|
||||
)
|
||||
|
||||
if include_uefi:
|
||||
# A second add_eltorito() call creates an alternate catalog section.
|
||||
# Leaving boot_load_size unset makes PyCdlib use the complete EFI FAT
|
||||
# image rather than the misleading one-sector count imported from
|
||||
# Microsoft media.
|
||||
iso.add_eltorito(
|
||||
uefi_iso_path,
|
||||
platform_id=0xEF,
|
||||
efi=True,
|
||||
media_name="noemul",
|
||||
bootable=True,
|
||||
boot_load_seg=0,
|
||||
)
|
||||
|
||||
def build_pycdlib(args: argparse.Namespace) -> None:
|
||||
try:
|
||||
@@ -663,6 +710,13 @@ def build_pycdlib(args: argparse.Namespace) -> None:
|
||||
print(f"Opening source ISO: {source}")
|
||||
iso.open(str(source))
|
||||
|
||||
include_bios, include_uefi = eltorito_platforms(source)
|
||||
print(
|
||||
"Imported El Torito platforms:"
|
||||
f" BIOS={'yes' if include_bios else 'no'},"
|
||||
f" UEFI={'yes' if include_uefi else 'no'}"
|
||||
)
|
||||
|
||||
# Microsoft media may import hidden El Torito records with an invalid
|
||||
# index_in_parent. The Dockerfile applies a temporary PyCdlib fix that
|
||||
# recovers the real child index, allowing this removal to succeed.
|
||||
@@ -679,7 +733,12 @@ def build_pycdlib(args: argparse.Namespace) -> None:
|
||||
print(f"Synchronizing tree: {logical}")
|
||||
sync_tree(iso, tree, logical)
|
||||
|
||||
rebuild_windows_eltorito(iso, tree)
|
||||
rebuild_windows_eltorito(
|
||||
iso,
|
||||
tree,
|
||||
include_bios=include_bios,
|
||||
include_uefi=include_uefi,
|
||||
)
|
||||
|
||||
print("Checking PyCdlib consistency...")
|
||||
iso.force_consistency()
|
||||
|
||||
Reference in New Issue
Block a user