Skip to content

Log hfs volume identifier#386

Merged
superg merged 15 commits into
superg:mainfrom
Didrole:log-hfs-volume-identifier
Jun 10, 2026
Merged

Log hfs volume identifier#386
superg merged 15 commits into
superg:mainfrom
Didrole:log-hfs-volume-identifier

Conversation

@Didrole

@Didrole Didrole commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

This PR adds basic HFS partition support to log the volume name.

It also includes the following groundwork :

  • An emulated sector size image reader, because HFS (and APM) use 512 byte sectors.
  • Basic Apple Parition Map parsing.
  • A Pascal string to std::string helper.
  • A Mac OS Roman to UTF-8 converter.

Produced output example:

*** INFO (time check: 0s)

CD-ROM [PKW744AF-CD.bin]:
  sectors count: 20638
  mode1 sectors: 20638

  REDUMP.ORG errors: 0

ISO9660 [PKW744AF-CD.bin]:
  volume identifier: T_TARTE
  PVD:
0320 : 20 20 20 20 20 20 20 20  20 20 20 20 20 32 30 30                200
0330 : 30 30 39 32 37 31 33 34  34 35 36 30 30 00 32 30   0092713445600.20
0340 : 30 30 30 39 32 37 31 33  34 35 35 35 30 30 00 00   00092713455500..
0350 : 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0360 : 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
0370 : 00 01 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
  joliet volume identifier: Têtarte

HFS [PKW744AF-CD.bin]:
  volume identifier: Têtarte

*** END (time check: 0s)

Summary by CodeRabbit

  • New Features
    • Apple Partition Map (APM) detection and partition listing
    • HFS filesystem support with volume identification (shows volume name)
    • Disk image emulation layer for sector-size translation
    • Image-based disk reader and automatic reader selection for disk-type inputs
    • System types expanded to include disk-based formats
    • Pascal-string utilities and Mac Roman → UTF-8 conversion utilities

@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6866db7b-5540-4fdd-addf-b56f81c6f889

📥 Commits

Reviewing files that changed from the base of the PR and between b36f113 and 4e915bc.

📒 Files selected for processing (3)
  • filesystem/apm/apm_browser.ixx
  • readers/emulated_sector_reader.ixx
  • utils/strings.ixx
🚧 Files skipped from review as they are similar to previous changes (3)
  • utils/strings.ixx
  • filesystem/apm/apm_browser.ixx
  • readers/emulated_sector_reader.ixx

📝 Walkthrough

Walkthrough

Adds Apple HFS support: APM partition parsing, HFS on-disk definitions, sector-size emulation reader (512B specialization), MacRoman/Pascal string helpers, System::Type::DISK and SystemHFS, and wiring in build and info to choose the correct reader per system type.

Changes

HFS File System Support Implementation

Layer / File(s) Summary
APM partition definitions and browser
filesystem/apm/apm_defs.ixx, filesystem/apm/apm.ixx, filesystem/apm/apm_browser.ixx
Exports APM constants and structs (DriveDescriptor, PartitionMapEntry) and Browser::getPartitions(DataReader*) to read and filter partition entries.
HFS file system structures and constants
filesystem/hfs/hfs.ixx, filesystem/hfs/hfs_defs.ixx
Defines HFS/HFS+ signatures, MDB_OFFSET, and packed on-disk structs including MasterDirectoryBlock and extent descriptors.
Disk sector emulation layer & alias
readers/emulated_sector_reader.ixx, readers/image_disk_reader.ixx
Implements Emulated_Sector_Reader<S> to remap emulated↔source sectors, exposes geometry accessors and sampleOffset, and defines Image_Disk_Reader = Emulated_Sector_Reader<512>.
Mac Roman and Pascal string utilities
utils/strings.ixx
Adds pascal_string<M>, from_pascal_string(), and mac_roman_to_utf8() conversion utilities using a lookup table and std::wstring_convert.
System type enum and HFS system implementation
systems/system.hh, systems/s_hfs.ixx, systems/systems.ixx
Adds System::Type::DISK; implements SystemHFS to enumerate APM partitions, read/validate MDB, convert volume name, and print volume identifier; registers SystemHFS.
Build configuration and reader selection
CMakeLists.txt, info.ixx
Adds APM/HFS modules and readers/image_disk_reader.ixx to build; imports Image_Disk_Reader in info.ixx and selects readers by System::Type (ISO→form1, DISK→Image_Disk_Reader, else→raw).

Sequence Diagram

sequenceDiagram
  participant SystemHFS
  participant APM_Browser
  participant DataReader
  participant StringUtils
  SystemHFS->>APM_Browser: getPartitions(data_reader)
  APM_Browser->>DataReader: read DriveDescriptor and partition entries
  DataReader-->>APM_Browser: partition map bytes
  APM_Browser-->>SystemHFS: Apple HFS partition entries
  SystemHFS->>DataReader: read MDB at partition_start + MDB_OFFSET
  DataReader-->>SystemHFS: MDB bytes
  SystemHFS->>SystemHFS: validate signature (endian-swap)
  SystemHFS->>StringUtils: mac_roman_to_utf8(pascal_volume_name)
  StringUtils-->>SystemHFS: UTF-8 volume name
  SystemHFS->>SystemHFS: print volume identifier
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • superg/redumper#268: Adds bool verbose parameter to System::printInfo(...) signature, which SystemHFS::printInfo() implements.

Suggested reviewers

  • superg

Poem

🐰 In apple orchards of sectors and maps I hop,
Reading Pascal names where old volume names stop,
I stitch Mac‑Roman to UTF with a whisker and cheer,
Emulate sectors, find HFS volumes here —
A tiny rabbit, bringing clarity to floppy crop. 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding HFS volume identifier logging. It directly aligns with the primary objective of enabling HFS partition support to log volume names.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@filesystem/apm/apm_browser.ixx`:
- Line 19: The method Browser::getPartitions has clang-format style violations;
fix the formatting inside the Browser class (and the related lines referenced)
so the declaration/definition and access specifier follow the project's
clang-format rules (spacing, brace placement, indentation). Run clang-format on
filesystem/apm/apm_browser.ixx and update the Browser::getPartitions
implementation (and nearby public: sections) to match the formatter output so CI
passes.
- Around line 34-40: The partition entry reads use PARTITION_MAP_OFFSET +
entry_index directly which ignores the data_reader base; update the read offset
to include data_reader->sectorsBase() (e.g. use data_reader->sectorsBase() +
PARTITION_MAP_OFFSET + entry_index) when calling data_reader->read so
partition_map_entry reads respect the reader base. Edit the block around
partition_map_entry, data_reader, PARTITION_MAP_OFFSET and the loop that checks
endian_swap(partition_map_entry.entry_count) to use the base-adjusted offset and
keep the existing signature check with
to_string_view(partition_map_entry.signature).

In `@filesystem/apm/apm_defs.ixx`:
- Line 87: The file has a clang-format style violation on the declaration of the
variable additional_driver_descriptors; run clang-format (or your repo's format
tool) on filesystem/apm/apm_defs.ixx to reformat the file and commit the updated
file so the declaration of uint8_t additional_driver_descriptors[484]; (and any
nearby lines) conform to project formatting rules and unblock CI.

In `@filesystem/apm/apm.ixx`:
- Line 4: The module export line "export import :defs;" in
filesystem/apm/apm.ixx violates clang-format; run the project's
clang-format/style tool on that file, remove any trailing whitespace, ensure the
line matches the repository's module export style (correct spacing and a single
newline at EOF), and commit the reformatted file so CI formatting checks pass.

In `@filesystem/hfs/hfs_defs.ixx`:
- Line 2: Clang-format flagged the include line; edit hfs_defs.ixx so the single
line '`#include` <cstdint>' is properly formatted with a trailing newline (ensure
the file ends with a newline and no extraneous whitespace or blank lines around
the include), then run clang-format (or save with your editor's format hook) to
verify the violation is resolved.
- Around line 34-68: Add a compile-time check that sizeof(MasterDirectoryBlock)
equals 512 bytes by inserting a static assertion referencing
MasterDirectoryBlock (e.g., a static_assert that sizeof(MasterDirectoryBlock) ==
512 with a clear message) immediately after the struct definition so the binary
contract is explicit; if the assertion fails, adjust fields/padding in
MasterDirectoryBlock (or packing) until the size is 512.

In `@filesystem/hfs/hfs.ixx`:
- Line 3: The module export line "export import :defs;" is violating
clang-format; run clang-format (or adjust whitespace) so the export appears on
its own properly formatted line and ensure a terminating newline/EOF;
specifically update the "export import :defs;" line to match the project's
clang-format rules (or reformat the file) so CI formatting checks pass.

In `@info.ixx`:
- Around line 68-80: The code currently constructs emulated_disk_reader =
std::make_shared<Image_Disk_Reader>(form1_reader) unconditionally which can
dereference a null form1_reader; change it to only construct Image_Disk_Reader
when form1_reader is valid (e.g., if (form1_reader) emulated_disk_reader =
std::make_shared<Image_Disk_Reader>(form1_reader); else leave
emulated_disk_reader null) and update the selection logic in the loop that picks
reader for System::Type::DISK to fall back to raw_reader when
emulated_disk_reader is null so you never dereference form1_reader inside
Image_Disk_Reader.

In `@readers/emulated_sector_reader.ixx`:
- Around line 64-72: The sectorsBase() and sectorsCount() implementations
incorrectly divide by _emulated_sectors_per_source; since the wrapper exposes
smaller sectors the visible LBA space must expand, so change both to multiply by
_emulated_sectors_per_source (i.e., return _source->sectorsBase() *
_emulated_sectors_per_source and return _source->sectorsCount() *
_emulated_sectors_per_source), keeping the same return types and using the
existing _source and _emulated_sectors_per_source symbols.
- Around line 51-55: The current copy length (emulated_sectors_to_copy) ignores
the starting offset (data_offset) and can read past source_sectors; compute an
offset-adjusted available count by subtracting the number of emulated sectors
consumed by data_offset (i.e., data_offset / S) from emulated_sectors_available,
clamp that with 0, then use emulated_sectors_to_copy = std::min(count,
adjusted_available); finally only call memcpy when emulated_sectors_to_copy > 0.
Update the logic around emulated_sectors_available, data_offset,
emulated_sectors_to_copy and the memcpy call accordingly.

In `@utils/strings.ixx`:
- Around line 357-360: from_pascal_string reads length from on-disk
pascal_string<M> without validation, so if string.length > M it can read past
data; fix by clamping the length to at most the template capacity M before
constructing the std::string (e.g., compute effective_len =
std::min(string.length, M) and use that when building the std::string),
referencing the from_pascal_string function and pascal_string<M> type.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0f71c669-8847-4101-bf5f-7aeb3a6646fa

📥 Commits

Reviewing files that changed from the base of the PR and between d4fcfe1 and 836d3fe.

📒 Files selected for processing (13)
  • CMakeLists.txt
  • filesystem/apm/apm.ixx
  • filesystem/apm/apm_browser.ixx
  • filesystem/apm/apm_defs.ixx
  • filesystem/hfs/hfs.ixx
  • filesystem/hfs/hfs_defs.ixx
  • info.ixx
  • readers/emulated_sector_reader.ixx
  • readers/image_disk_reader.ixx
  • systems/s_hfs.ixx
  • systems/system.hh
  • systems/systems.ixx
  • utils/strings.ixx

Comment thread filesystem/apm/apm_browser.ixx
Comment thread filesystem/apm/apm_browser.ixx Outdated
Comment thread filesystem/apm/apm_defs.ixx
Comment thread filesystem/apm/apm.ixx Outdated
Comment thread filesystem/hfs/hfs_defs.ixx Outdated
Comment thread filesystem/hfs/hfs.ixx Outdated
Comment thread info.ixx Outdated
Comment thread readers/emulated_sector_reader.ixx Outdated
Comment thread readers/emulated_sector_reader.ixx
Comment thread utils/strings.ixx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
filesystem/apm/apm_browser.ixx (1)

33-33: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Partition entry reads ignore sectorsBase(), causing wrong offsets.

Line 33 reads partition map entries from PARTITION_MAP_OFFSET + entry_index without including data_reader->sectorsBase(), while Line 25 correctly uses the base offset. This inconsistency breaks parsing when the reader base is non-zero, causing the parser to read from incorrect sector addresses.

🛠️ Proposed fix
-                    if(data_reader->read((uint8_t *)&partition_map_entry, PARTITION_MAP_OFFSET + entry_index, 1) != 1)
+                    if(data_reader->read((uint8_t *)&partition_map_entry, data_reader->sectorsBase() + PARTITION_MAP_OFFSET + entry_index, 1) != 1)
                         break;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@filesystem/apm/apm_browser.ixx` at line 33, The partition map entry read uses
an absolute offset and omits the reader base: update the call to
data_reader->read that reads partition_map_entry (using PARTITION_MAP_OFFSET +
entry_index) to include data_reader->sectorsBase() just like the earlier read
(i.e. add the sectorsBase() value to the offset), so the read uses
data_reader->sectorsBase() + PARTITION_MAP_OFFSET + entry_index and remains
consistent with the reader's base.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@filesystem/apm/apm_browser.ixx`:
- Line 38: The do/while loop using ++entry_index <
endian_swap(partition_map_entry.entry_count) can spin unbounded if
partition_map_entry.entry_count is corrupted; add a sanity limit and validate
the count before/inside the loop: compute uint32_t count =
endian_swap(partition_map_entry.entry_count), reject or clamp obviously bogus
values (e.g., zero or > MAX_APM_ENTRIES), and change the loop condition to also
break when entry_index >= count or entry_index >= MAX_APM_ENTRIES (define a
named constant like MAX_APM_ENTRIES) so the parser cannot iterate millions of
times on malformed images.

---

Duplicate comments:
In `@filesystem/apm/apm_browser.ixx`:
- Line 33: The partition map entry read uses an absolute offset and omits the
reader base: update the call to data_reader->read that reads partition_map_entry
(using PARTITION_MAP_OFFSET + entry_index) to include data_reader->sectorsBase()
just like the earlier read (i.e. add the sectorsBase() value to the offset), so
the read uses data_reader->sectorsBase() + PARTITION_MAP_OFFSET + entry_index
and remains consistent with the reader's base.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 34aa0f08-35c2-4a69-a751-87b7431bd29a

📥 Commits

Reviewing files that changed from the base of the PR and between 836d3fe and 42511a5.

📒 Files selected for processing (5)
  • filesystem/apm/apm.ixx
  • filesystem/apm/apm_browser.ixx
  • filesystem/apm/apm_defs.ixx
  • filesystem/hfs/hfs.ixx
  • filesystem/hfs/hfs_defs.ixx
💤 Files with no reviewable changes (1)
  • filesystem/apm/apm_defs.ixx
✅ Files skipped from review due to trivial changes (1)
  • filesystem/apm/apm.ixx
🚧 Files skipped from review as they are similar to previous changes (2)
  • filesystem/hfs/hfs.ixx
  • filesystem/hfs/hfs_defs.ixx

Comment thread filesystem/apm/apm_browser.ixx Outdated

@superg superg left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's substantial work, just couple nit comments but overall looking good!

Comment thread readers/emulated_sector_reader.ixx
Comment thread systems/s_hfs.ixx
@superg superg merged commit d8baf3d into superg:main Jun 10, 2026
11 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Jun 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants