Skip to content

dosforge 0.9.54

Choose a tag to compare

@github-actions github-actions released this 14 Jun 02:10
· 9 commits to main since this release

dosforge v0.9.54

Fix: "16M means 16M" cap-vs-snap contract for create form

User-reported bug: form auto-fills 16M as the max size for IBM
PC-DOS 3 + XT-IDE + FAT12 (correct), but clicking Create fails
with "PC-DOS 3.x images must not exceed 16 MiB" until the user
drops to 15M.

Root cause

The form's _state_aware_max_mb returns 16 (MiB) for PCDOS3, so
the size field shows "16M". The user submits with size = 16 MiB
= 16,777,216 bytes.

_validate_xtide_request calls _xtide_geometry, which finds the
smallest MartyPC XT-IDE whitelist entry that fits above the
request: (1024, 2, 17) = 34,816 sectors = 17,825,792 bytes
(~17 MiB). It writes that bumped value back to
request.size_bytes and returns.

Then validate_size_for_ibm_dos(17 MiB, PCDOS3) rejects: 17 > 16
MiB cap.

With 15M, the smallest fits-above entry is (306, 4, 26) =
15.54 MiB, which is under the 16 MiB cap. Passes.

Audit -- two paths had this pattern

  1. XT-IDE auto-snap (_xtide_geometry via
    _validate_xtide_request, disk.py:1879) -- the bug above.
  2. Custom payload autosizing
    (_apply_custom_payload_autosizing, disk.py:1968) -- same
    pattern. Combining --custom-payload-path with a cap-tight
    DOS (e.g. PCDOS3 16 MiB, MSDOS33 32 MiB) and a payload >= cap
    silently bumped request.size_bytes past the cap, producing
    an unbootable VHD that the chosen DOS can't read past its
    partition cap.

Other paths checked + confirmed correct:

  • AT-IDE CHS cylinder snap (align_size_for_normal_chs)
    already accepts max_bytes and snaps DOWN when the ceil would
    exceed the cap. No bug.
  • BIOS drive-type preset fails explicitly with a clear
    "preset exceeds cap" message instead of silently bumping.
  • Custom CHS does no snap at all.

Fix

New helper _effective_size_cap_bytes(request) in
src/dosforge/disk.py. Combines per-boot-mode caps (PCDOS3
16 MiB, COMPAQ2 16 MiB, MSDOS33 / MSDOS331 32 MiB,
COMPAQ331 / IBM8088+PCDOS5+MSDOS5 504 MiB, IBM8088+DOS33 32 MiB,
IBM8088+PCDOS3 16 MiB) with the FAT format cap (FAT12 32 MiB,
FAT16 2 GiB, FAT32 2 TiB). Single source of truth on the disk
side, mirrors _state_aware_max_mb on the form side.

_xtide_geometry -- snap-down support: new optional
max_size_bytes parameter. When the smallest fits-above
whitelist entry would exceed max_size_bytes, fall back to the
largest whitelist entry that fits <= max_size_bytes. Only
raises ValidationError when even the smallest whitelist entry
exceeds the cap (i.e. XT-IDE fundamentally can't make a disk that
small for the chosen DOS). Both _resolved_xt_class_geometry
and _validate_xtide_request now pass the cap.

_apply_custom_payload_autosizing -- cap check: after
computing required_size, refuse to bump past
_effective_size_cap_bytes(request). Raises a clear
ValidationError naming the boot mode, cap, and payload size when
the cap is exceeded so users know to either trim the payload or
pick a different DOS.

Verified end-to-end on Windows

Direct repro of the user's bug:

$ dosforge create --path test.vhd --media-type vhd --format fat12 \
    --size 16M --boot-mode pcdos3 --disk-controller xtide
Created and prepared test.vhd
VHD size: 16,294,400 bytes (15.54 MiB)

(Picks the (306, 4, 26) whitelist geometry under the 16 MiB
cap, just like manually entering 15M did pre-fix.)

Tests

  • tests/test_size_cap_snap.py (new) -- 12 tests covering:
    • _effective_size_cap_bytes for PCDOS3 / COMPAQ331 / IBM8088
      (DOS33 + PCDOS5) / FreeDOS.
    • _xtide_geometry snap-down at PCDOS3 cap (the user's bug).
    • _xtide_geometry below-cap input still snaps UP (no
      regression).
    • _xtide_geometry with max_size_bytes=None preserves
      original behavior.
    • Whitelist invariants (at least one entry <= 16 MiB so the
      snap-down can succeed).

All 12 new tests pass + existing
test_disk_validation.py, test_disk_windows_vhd.py,
test_martypc.py, test_formlogic.py regression-free.

Files changed

  • src/dosforge/disk.py -- new _effective_size_cap_bytes,
    _xtide_geometry snap-down logic, _apply_custom_payload_autosizing
    cap check, added FAT12_MAX_BYTES import.
  • tests/test_size_cap_snap.py -- new test file.
  • tests/conftest.py -- registered new test in Windows
    allow-list.
  • pyproject.toml + src/dosforge/__init__.py -- 0.9.53 -> 0.9.54.