Skip to content

Commit 160a612

Browse files
committed
rdb: support multiple 0x76 partitions on Emu68-style MBR images
When an Emu68-style MBR image contains more than one partition of type 0x76 (Amiga RDB), only the first one is examined. Both open_rdisk() and BlockDeviceBackend.open() iterate over 0x76 entries but return as soon as the first valid RDB is found, making all Amiga partitions in subsequent 0x76 slots invisible to inspect and unmountable. Add find_partition_mbr_index() which searches every 0x76 MBR partition for a named Amiga partition and returns its index. Use it in get_partition_info(), extract_embedded_driver(), HandlerBridge and BootstrapAllocator so that mounting a partition like ADH0 that lives in the second 0x76 slot works transparently. Update cmd_inspect() and the standalone rdb_inspect main() to iterate over all 0x76 partitions, printing the MBR table once followed by a section for each RDB with its partitions and filesystem drivers. JSON output returns an array when multiple RDBs are present. Closes: #4
1 parent be0f8e2 commit 160a612

File tree

3 files changed

+236
-74
lines changed

3 files changed

+236
-74
lines changed

amifuse/bootstrap.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,23 @@ def get_num_blocks(self):
5050

5151

5252
class BootstrapAllocator:
53-
def __init__(self, vh, image_path: Path, block_size=512, partition=None, adf_info: Optional[ADFInfo] = None):
53+
def __init__(self, vh, image_path: Path, block_size=512, partition=None, adf_info: Optional[ADFInfo] = None, mbr_partition_index=None):
5454
self.vh = vh
5555
self.alloc = vh.alloc
5656
self.mem = vh.alloc.get_mem()
5757
self.image_path = image_path
5858
self.block_size = block_size
5959
self.partition = partition # name, index, or None for first
6060
self.adf_info = adf_info # Pre-detected ADF info, if any
61+
self.mbr_partition_index = mbr_partition_index # For MBR disks with multiple 0x76 partitions
6162

6263
def _read_partition_env(self):
6364
from .rdb_inspect import open_rdisk
6465

65-
blk, rd, mbr_ctx = open_rdisk(self.image_path, block_size=self.block_size)
66+
blk, rd, mbr_ctx = open_rdisk(
67+
self.image_path, block_size=self.block_size,
68+
mbr_partition_index=self.mbr_partition_index,
69+
)
6670
if self.partition is None:
6771
part = rd.get_partition(0)
6872
else:

amifuse/fuse_fs.py

Lines changed: 91 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,15 @@ def __init__(
7979
self._lock = threading.RLock() # Reentrant lock for thread safety
8080
self._debug = debug
8181
self._adf_info = adf_info
82-
self.backend = BlockDeviceBackend(image, block_size=block_size, read_only=read_only, adf_info=adf_info)
82+
# For MBR images with multiple 0x76 partitions, find the right one
83+
mbr_idx = None
84+
if partition and adf_info is None:
85+
from .rdb_inspect import find_partition_mbr_index
86+
mbr_idx = find_partition_mbr_index(image, block_size, partition)
87+
self.backend = BlockDeviceBackend(
88+
image, block_size=block_size, read_only=read_only, adf_info=adf_info,
89+
mbr_partition_index=mbr_idx,
90+
)
8391
self.backend.open()
8492
self.vh = VamosHandlerRuntime()
8593
# Use 68020 CPU for compatibility with SFS and other modern handlers
@@ -89,7 +97,10 @@ def __init__(
8997
self.mem = self.vh.alloc.get_mem()
9098
seg_baddr = self.vh.load_handler(driver)
9199
# Build DeviceNode/FSSM using seglist bptr
92-
ba = BootstrapAllocator(self.vh, image, partition=partition, adf_info=adf_info)
100+
ba = BootstrapAllocator(
101+
self.vh, image, partition=partition, adf_info=adf_info,
102+
mbr_partition_index=mbr_idx,
103+
)
93104
handler_name = "DF0:" if adf_info else "DH0:"
94105
boot = ba.alloc_all(handler_seglist_baddr=seg_baddr, handler_seglist_bptr=seg_baddr, handler_name=handler_name)
95106
self._partition_index = boot["part"].num if boot.get("part") else 0
@@ -1661,8 +1672,9 @@ def destroy(self, path):
16611672

16621673
def get_partition_info(image: Path, block_size: Optional[int], partition: Optional[str]) -> dict:
16631674
"""Get partition name and dostype from RDB."""
1664-
from .rdb_inspect import open_rdisk
1665-
blkdev, rdisk, _mbr_ctx = open_rdisk(image, block_size=block_size)
1675+
from .rdb_inspect import open_rdisk, find_partition_mbr_index
1676+
mbr_idx = find_partition_mbr_index(image, block_size, partition) if partition else None
1677+
blkdev, rdisk, _mbr_ctx = open_rdisk(image, block_size=block_size, mbr_partition_index=mbr_idx)
16661678
try:
16671679
if partition is None:
16681680
part = rdisk.get_partition(0)
@@ -1691,9 +1703,10 @@ def extract_embedded_driver(image: Path, block_size: Optional[int], partition: O
16911703
"""
16921704
import tempfile
16931705
import amitools.fs.DosType as DosType
1694-
from .rdb_inspect import open_rdisk
1706+
from .rdb_inspect import open_rdisk, find_partition_mbr_index
16951707

1696-
blkdev, rdisk, _mbr_ctx = open_rdisk(image, block_size=block_size)
1708+
mbr_idx = find_partition_mbr_index(image, block_size, partition) if partition else None
1709+
blkdev, rdisk, _mbr_ctx = open_rdisk(image, block_size=block_size, mbr_partition_index=mbr_idx)
16971710
try:
16981711
# Get the partition and its dostype
16991712
if partition is None:
@@ -1881,10 +1894,29 @@ def _unmount_mountpoint():
18811894
__version__ = "v0.2.0"
18821895

18831896

1897+
def _inspect_rdisk(rdisk, full=False):
1898+
"""Print RDB info, filesystem drivers, and warnings for a single RDisk."""
1899+
from .rdb_inspect import format_fs_summary
1900+
for line in rdisk.get_info(full=full):
1901+
print(line)
1902+
fs_lines = format_fs_summary(rdisk)
1903+
if fs_lines:
1904+
print("\nFilesystem drivers:")
1905+
for line in fs_lines:
1906+
print(" ", line)
1907+
warnings = getattr(rdisk, 'rdb_warnings', [])
1908+
if warnings:
1909+
print("\nWarnings:")
1910+
for w in warnings:
1911+
print(f" {w}")
1912+
1913+
18841914
def cmd_inspect(args):
18851915
"""Handle the 'inspect' subcommand."""
18861916
import amitools.fs.DosType as DosType
1887-
from .rdb_inspect import open_rdisk, format_fs_summary, format_mbr_info, detect_adf
1917+
from .rdb_inspect import (
1918+
open_rdisk, format_mbr_info, detect_adf, detect_mbr, MBR_TYPE_AMIGA_RDB,
1919+
)
18881920

18891921
# First check for ADF
18901922
adf_info = detect_adf(args.image)
@@ -1901,39 +1933,62 @@ def cmd_inspect(args):
19011933
print("Use --driver to specify a filesystem handler when mounting.")
19021934
return
19031935

1904-
blkdev = None
1905-
rdisk = None
1906-
mbr_ctx = None
1907-
try:
1936+
# Detect if MBR with multiple 0x76 partitions
1937+
mbr_info = detect_mbr(args.image)
1938+
multi_rdb = False
1939+
amiga_parts = []
1940+
if mbr_info and mbr_info.has_amiga_partitions:
1941+
amiga_parts = [p for p in mbr_info.partitions if p.partition_type == MBR_TYPE_AMIGA_RDB]
1942+
if len(amiga_parts) > 1:
1943+
multi_rdb = True
1944+
1945+
if multi_rdb:
1946+
# Show MBR table once using first partition's context
19081947
try:
1909-
blkdev, rdisk, mbr_ctx = open_rdisk(args.image, block_size=args.block_size)
1948+
blkdev, rdisk, mbr_ctx = open_rdisk(args.image, block_size=args.block_size, mbr_partition_index=0)
19101949
except IOError as e:
19111950
raise SystemExit(f"Error: {e}")
1912-
1913-
# Show MBR info if present
1914-
if mbr_ctx is not None:
1915-
for line in format_mbr_info(mbr_ctx):
1916-
print(line)
1917-
print()
1918-
1919-
for line in rdisk.get_info(full=args.full):
1951+
for line in format_mbr_info(mbr_ctx):
19201952
print(line)
1921-
fs_lines = format_fs_summary(rdisk)
1922-
if fs_lines:
1923-
print("\nFilesystem drivers:")
1924-
for line in fs_lines:
1925-
print(" ", line)
1926-
1927-
warnings = getattr(rdisk, 'rdb_warnings', [])
1928-
if warnings:
1929-
print("\nWarnings:")
1930-
for w in warnings:
1931-
print(f" {w}")
1932-
finally:
1933-
if rdisk is not None:
1934-
rdisk.close()
1935-
if blkdev is not None:
1936-
blkdev.close()
1953+
rdisk.close()
1954+
blkdev.close()
1955+
1956+
# Show each RDB
1957+
for rdb_idx in range(len(amiga_parts)):
1958+
try:
1959+
blkdev, rdisk, mbr_ctx = open_rdisk(
1960+
args.image, block_size=args.block_size, mbr_partition_index=rdb_idx
1961+
)
1962+
except IOError as e:
1963+
print(f"\nMBR partition [{amiga_parts[rdb_idx].index}]: Error: {e}")
1964+
continue
1965+
try:
1966+
print(f"\n=== Amiga RDB in MBR partition [{mbr_ctx.mbr_partition.index}]"
1967+
f" (offset: {mbr_ctx.offset_blocks} sectors) ===\n")
1968+
_inspect_rdisk(rdisk, full=args.full)
1969+
finally:
1970+
rdisk.close()
1971+
blkdev.close()
1972+
else:
1973+
# Single RDB (or non-MBR): existing behavior
1974+
blkdev = None
1975+
rdisk = None
1976+
mbr_ctx = None
1977+
try:
1978+
try:
1979+
blkdev, rdisk, mbr_ctx = open_rdisk(args.image, block_size=args.block_size)
1980+
except IOError as e:
1981+
raise SystemExit(f"Error: {e}")
1982+
if mbr_ctx is not None:
1983+
for line in format_mbr_info(mbr_ctx):
1984+
print(line)
1985+
print()
1986+
_inspect_rdisk(rdisk, full=args.full)
1987+
finally:
1988+
if rdisk is not None:
1989+
rdisk.close()
1990+
if blkdev is not None:
1991+
blkdev.close()
19371992

19381993

19391994
def cmd_mount(args):

0 commit comments

Comments
 (0)