Repository navigation
dosforge 0.9.54
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
- XT-IDE auto-snap (
_xtide_geometryvia
_validate_xtide_request,disk.py:1879) -- the bug above. - Custom payload autosizing
(_apply_custom_payload_autosizing,disk.py:1968) -- same
pattern. Combining--custom-payload-pathwith a cap-tight
DOS (e.g. PCDOS3 16 MiB, MSDOS33 32 MiB) and a payload >= cap
silently bumpedrequest.size_bytespast 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 acceptsmax_bytesand 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_bytesfor PCDOS3 / COMPAQ331 / IBM8088
(DOS33 + PCDOS5) / FreeDOS._xtide_geometrysnap-down at PCDOS3 cap (the user's bug)._xtide_geometrybelow-cap input still snaps UP (no
regression)._xtide_geometrywithmax_size_bytes=Nonepreserves
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_geometrysnap-down logic,_apply_custom_payload_autosizing
cap check, addedFAT12_MAX_BYTESimport.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.