A small CLI/TUI utility for MS-DOS (8086, real mode) that images floppies, fixed disks, system RAM and ROM/BIOS to files, restores them back, spans an image across multiple smaller media, compresses on the fly, and high-level formats FAT12/16/32.
Built with Open Watcom V2 (large memory model, 8086 target).
DIMG targets 16-bit real-mode DOS, which no mainstream 2020s compiler emits.
Open Watcom V2 is the actively-maintained toolchain that still does, and it
cross-compiles: you build DIMG.EXE on Windows or Linux and run it under DOS.
Project links (verified current):
- Repo / wiki: https://github.com/open-watcom/open-watcom-v2
- Releases: https://github.com/open-watcom/open-watcom-v2/releases
- Rolling "Current-build" (freshest installers): https://github.com/open-watcom/open-watcom-v2/releases/tag/Current-build
- Landing page: https://open-watcom.github.io/
The release pages host one installer per host OS. Filenames follow the pattern
open-watcom-2_0-c-<host>... (e.g. a Windows .exe, a Linux x64 binary, an
OS/2 build). Asset names shift release to release, so pick the one whose host
matches your machine rather than a hard-coded filename.
From the Current-build release, download the Windows installer (
.exe).Run it. Accept the defaults; when asked, let it install the 16-bit DOS target and let it update environment variables. Default install dir is
C:\WATCOM.Open a new Command Prompt (so the new env vars are loaded) and verify:
wcc -? rem 16-bit C compiler should print its banner wmake /?If they aren't found, set the environment manually (adjust the drive/path):
set WATCOM=C:\WATCOM set PATH=%WATCOM%\BINNT;%WATCOM%\BINW;%PATH% set INCLUDE=%WATCOM%\H set EDPATH=%WATCOM%\EDDAT(
BINNT= Win32-hosted tools,BINW= 16-bit tools;H= C headers.)Build:
cd dimg wmake rem uses the provided Makefile -> DIMG.EXE rem or the one-shot driver: build.bat
From the Current-build release, download the Linux x64 installer binary.
Install (it self-extracts;
/opt/watcomis a common target):chmod +x open-watcom-2_0-c-linux-x64* ./open-watcom-2_0-c-linux-x64* # follow prompts, choose a dirSet the environment (the installer also drops a
setvars/owsetenvscript in the install root you cansourceinstead):export WATCOM=/opt/watcom export PATH=$WATCOM/binl64:$WATCOM/binl:$PATH export INCLUDE=$WATCOM/h export EDPATH=$WATCOM/eddatBuild (the compile+link driver line is host-agnostic):
cd dimg wmake # or, without the makefile: wcl -ml -0 -bcl=dos -os -zq -zp1 -fe=dimg.exe \ main.c args.c disk.c memdev.c comp.c container.c fatfmt.c tui.cCopy the resulting
DIMG.EXEonto a DOS disk / image and run it there.
-ml large memory model · -0 8086 code · -bcl=dos build+link a DOS
executable · -os optimise for size · -zq quiet · -zp1 pack structs on
1-byte boundaries (required — the INT 13h DAP and EDD buffers must be
byte-exact). wlink system dos in the Makefile produces the same DOS target.
DIMG.EXE needs a DOS environment: real hardware, DOSBox
(https://www.dosbox.com/) / DOSBox-X (https://dosbox-x.com/), or an emulator
like 86Box / PCem / qemu. See the DOSBox testing tips below.
wmake # or: build.bat (Windows) / the wcl line (Linux)
Output: DIMG.EXE. Runs on real DOS, DOSBox, 86Box/PCem, qemu, etc.
dimg <command> [flags] - run dimg help for the command list and
dimg help <command> (or dimg <command> --help) for that command's
flags. Bare dimg opens the interactive menu. The older spelling
(dimg image ...) still works everywhere.
list image restore verify compare copy
clone browse view info extract import
format fixfat pt-backup pt-restore parity parity-repair
tui
| Task | Command |
|---|---|
| Image a floppy, compressed | dimg image --source fd0 --dest a:boot --compress=9 |
| Image only used space on a Zip | dimg image --source dosD --dest a:zip --used-only --compress |
| Rip a CD to a mountable ISO | dimg image --source cd0 --dest disc.iso --raw |
| Continue an interrupted image | same command + --resume |
| Image just the first track | dimg image --source fd0 --dest trk0 --start 0 --count 18 |
| Verify an image internally | dimg verify --source a:boot |
| Compare an image to media | dimg verify --source a:boot --dest fd0 |
| Inspect an image | dimg info --source a:boot |
| Browse sectors (media or image) | dimg view --source hd0 --lba 63 |
| Pull a file out of an image | dimg extract --source disk.edi --path DOCS\PLAN.TXT --dest plan.txt |
| Put a file into a raw image | dimg import --source plan.txt --dest disk.img --path PLAN.TXT |
| Browse files (any source) | dimg browse --source hd0p1 |
| Copy disk to disk | dimg copy --source hd0 --dest hd1 --verify-write |
| Clone a floppy with ONE drive | dimg copy --source fd0 --dest fd0 (RAM-buffered swap passes) |
| Unpack a container to a raw image | dimg copy --source disk.edi --dest disk.img |
| Check / repair the FAT copies | dimg fixfat --dest dosC then add --yes |
| Back up MBR/GPT + EBR chain | dimg pt-backup --source hd0 --dest a:\tables.bin |
| Put the tables back | dimg restore-pt --source a:\tables.bin --dest hd0 |
| Tag an image | --comment "office PC 1997, C: before reinstall" |
| Protect a set with parity | dimg image ... --parity or later dimg parity --source a:boot |
| Rebuild a lost/rotten volume | dimg parity-repair --source a:boot |
| Fight weak media harder | --retries 5 (extra per-sector rounds) |
| No flags at all | dimg opens the interactive menu |
| Format a device | dimg format --dest fd0 --fs 12 --label WORK |
| Create a blank formatted image | dimg format --dest new.img --sectors 2880 --fs 12 |
--view, --extract and --info work on real devices, raw image files and
DIMG containers alike; on a --used-only container, sectors that were never
stored show as [NOT IN IMAGE] in the viewer and read as zeros.
--import works on devices and raw images only. A compressed container
cannot be edited in place: restore it, add the file, re-image.
--list parses the MBR (including the extended/EBR logical chain) and GPT
on every fixed disk and exposes each partition as a device of its own:
hd0p1, hd0p2, ... Every operation - image, restore, verify, view,
browse, extract, format - accepts a partition device; the LBA offset is
applied underneath, so imaging hd0p1 gives an image of just that
filesystem. GPT headers are CRC-checked before being trusted; entries past
the 32-bit LBA horizon (2 TB) are reported and skipped, which is no loss in
real mode. --backup-pt saves the table sectors themselves (boot sector +
every EBR, or protective MBR + both GPT headers + both entry arrays) into a
small file that --restore-pt writes back - the classic "fdisk /mbr ate my
disk" insurance.
dimg browse --source <anything> opens a full-screen file manager over
any FAT volume: a drive letter, a partition, a raw image, or a DIMG
container (read-only there). Enter descends, .. goes up, Ins marks.
| Key | Action |
|---|---|
| F3 | hex view of the file under the cursor |
| F5 | export file(s) to a DOS path (marked files batch) |
| F6 | import a local file into the current directory |
| F7 | make directory |
| F8 | delete (directories only when empty) |
| R | rename (8.3, same directory) |
| Ins | mark / unmark |
| ESC | quit |
--copy builds the largest pass buffer it can, in this order:
| Tier | Backend | Typical size | 1.44 MB clone |
|---|---|---|---|
| 1 | XMS (HIMEM, 286+) | megabytes | 1 swap cycle |
| 2 | EMS 3.2+ (EMM386, or a real board on an XT) | megabytes | 1 swap cycle |
| 3 | conventional RAM (up to twenty 32 KB far chunks) | ~450-580 KB | 3-4 swap cycles |
| 4 | static 2 KB fallback | - | two-device copy only |
A pass reads everything, then writes everything, so device-to-device
copies stop ping-ponging the heads, and when source and destination are
the SAME removable device (--copy --source fd0 --dest fd0) it becomes
DISKCOPY: fill the buffer from the source disk, swap on prompt, drain to
the target, swap back. With XMS or EMS present the whole floppy fits and
one swap does it. XMS/EMS data moves through a 32 KB conventional bounce
because INT 13h cannot target extended memory. Whichever single tier is
largest wins (conventional and extended are not combined - the extra
complexity would save at most one swap on driverless 640 KB machines).
This is not a reversal of the "no XMS/EMS for compression" rule: the LZ77 window needs random access, which a 64 KB page frame turns into mapping thrash, while a copy pass is strictly sequential - the one workload expanded memory is perfect for.
Where the big buffer is used: --copy (all forms) and --raw dumps
(32 KB reads instead of 2 KB when RAM allows). Where it deliberately is
not: compressed imaging (sequential + codec-bound), restore and verify
(sequential decode, no seek alternation to remove).
--copy --source hd0 --dest hd1 is a raw sector clone: MBR, partition
tables, boot code, everything, with the same retry/step-down and
--verify-write options. Partition-to-partition works too
(hd0p1 -> hd1p1), destination capacity permitting. One DOS-era caveat:
if SMARTDRV runs with write-back caching, flush it (smartdrv /c) or
start clean before cloning the volume DOS is writing to - DIMG reads the
disk, not the cache.
Every screen renders through the same window system: menus, dialogs, forms, pickers and the file selector; operation progress and the block map (a window over the desktop, restored on ESC); the device list, image details, FAT reports and parity results (scrollable text windows); the FAT file browser and the sector hex viewer (full-height windows whose row counts scale with the 25/43/50-line mode - a 512-byte sector fits on one viewer page at 50 lines). Nothing writes to the screen outside ui.c and the operation renderer, nothing drops to DOS output, and the desktop underneath any window comes back exactly as it was.
Every CHS transfer is split so it never crosses a track boundary (real BIOSes reject a multi-track read/write with error 04 or 02 - "sector not found" / "address mark not found" - even though emulators tolerate it) and never crosses a 64 KB physical DMA page (error 09). A single sector that would straddle a DMA line is copied through a 64 KB-aligned bounce buffer. This is what makes imaging a 1.2 MB or 1.44 MB floppy reliable on metal.
A global DOS critical-error handler is installed for the whole run, so a write-protected or not-ready disk can never raise "Abort, Retry, Fail?" over the interface - the DOS call fails normally and the app reports it. BIOS-level errors are decoded by status (write-protected, not ready, CRC, seek...) and shown in the message; write-protect fails immediately instead of burning retries that cannot succeed.
Tools > Settings stores preferences in a small YAML file: screen mode (25/43/50 lines), default compression on/off and level, and verify-writes. The file location resolves in this order:
| Priority | Source |
|---|---|
| 1 | --config C:\PATH\dimg.yaml (or a directory, then dimg.yaml is appended) |
| 2 | the DIMGCONF environment variable (SET DIMGCONF=C:\DIMG\ in AUTOEXEC) |
| 3 | dimg.yaml beside DIMG.EXE |
| 4 | dimg.yaml in the current directory |
Unknown keys are preserved on save, so a newer version's settings survive an older binary. Missing file = built-in defaults; the file is created on the first Settings save.
50-line mode (via ANSI.SYS or the built-in mode switch) is honoured: set
video_lines: 50 and the desktop, dialogs and lists use the full height.
Earentir's Disk Image containers use the extensions .edi (first volume), .e01/.e02/... (continuation volumes) and .edp (parity). For everything else the raw paths are the bridge, in both directions:
| Want | Command |
|---|---|
| A floppy image WinImage / 86Box / DOSBox / mtools open | dimg image --source fd0 --dest disk.ima --raw |
| The same from an existing DIMG container | dimg copy --source x.edi --dest x.ima |
| A real ISO from a CD | dimg image --source cd0 --dest cd.iso --raw |
| Write a WinImage/emulator image to a real disk | dimg copy --source disk.ima --dest fd0 |
A raw dump IS the .IMA/.IMG format those tools use - a sector-for-sector
file with no header - so nothing needs converting. WinImage's compressed
.IMZ is a ZIP archive and is not read directly; extract it first.
Formatting with an empty label writes NO NAME to the BPB and creates
no root label entry, exactly as MS-DOS FORMAT does.
--parity writes <base>.edp: the XOR of every volume in the set, padded
to the largest. If any ONE volume later goes missing or fails its CRC -
floppies rot - --repair-vol rebuilds it byte-exactly from the survivors
plus the parity file, then re-verifies its CRC. Two casualties are beyond
XOR and it refuses rather than fabricate. Parity is built while the set is
still together on one path, so create it before scattering volumes across
floppies; the parity disk becomes disk N+1 of the set. Cost: one extra
volume-sized file, no compression-ratio impact.
The Format dialog offers a Method: Quick writes a fresh filesystem (boot sector, FATs, root directory) - the usual DOS FORMAT. Full, on a floppy, physically rewrites every track's sector marks first (an INT 13h low-level format) and then lays down the filesystem; use it for a disk that quick-format cannot write or that has marginal media. On a hard disk the two are identical (DIMG never low-level-formats a fixed disk), and the dialog says so.
Styled after Central Point Anti-Virus and the Norton utilities: a dithered blue desktop with a clock, a pulldown menu bar (F9 opens it, Alt+highlighted-letter jumps straight to a menu, F1 shows the keys, ESC backs out of everything), shadowed cyan dialogs with classic half-block button shadows, scrollable list pickers for devices, forms with text fields and [X] toggles, and a DOS file selector that filters to the file type being asked for (*.edi for images) and walks directories. Text output - the device list, image details, FAT-check reports, parity results - appears in scrollable windows inside the TUI; nothing drops back to the DOS prompt. The Create-image dialog prefills the file name from the disk's own volume label. The menus:
| Menu | Entries |
|---|---|
| Image | Create, Restore, Verify, Compare, Details, Parity create/rebuild, Exit |
| Disk | Copy, Single-drive clone, Format, Fix FAT, Table backup/restore, List devices |
| Tools | Browse files, Sector viewer |
| Help | About, Keys |
Every entry assembles the same request structure the flag parser builds and feeds the same dispatch, so the TUI, the subcommands and the legacy flags cannot behave differently.
The screen has three fixed zones: the menu bar (top row), the footer (bottom row), and the workspace between them. Dialogs and operation windows own the workspace; the dithered desktop and its device/memory panels are decoration drawn beneath and repainted whenever a window closes. An operation fills the entire workspace - full width, full height in whatever video mode is active (25/43/50 lines) - and stays open showing its result until you press ESC.
Modeled on SpeedDisk / the Norton utilities: the operation window shows a grid of blocks filling the workspace, with two boxes beneath it - Status on the left (current cluster, percent, rate) and Legend on the right - and two free status lines at the very bottom. The grid's row count scales with the video mode, and each block represents as many clusters as needed for the whole disk to fit ("1 block = N clusters", shown in the legend); on a small floppy that is 1:1, on a hard disk or CD each block covers many.
Legacy note: the older
During image, restore, verify, compare and copy the full-screen view is a SpeedDisk-style grid - 1110 cells, each standing for N sectors (the legend says how many) - painted live as the operation touches them:
| Cell | Meaning |
|---|---|
| dim block | pending |
r (cyan) | being read |
W (yellow) | being written |
| bright block | done |
| green block | verified |
B on red | bad sector in this cell (sticky - never painted over) |
| small dot | skipped (free cluster / hole) |
Below the grid: the percent/KB/s/ETA line and a phase note ("pass 2 of
3: writing + verify"). A whole 1.44 MB floppy maps at ~3 sectors per
cell, so individual bad sectors are visible the moment the retry logic
gives up on them. With --no-tui the map is skipped and the plain
progress line carries on.
--fixfat reads both FAT copies, scores each (media byte, end-of-chain
marker, count of impossible cluster pointers), reports the differences and
- with
--yes- copies the healthier one over the other. That also resurrects a zeroed-out second FAT. It is a mirror repair, not a full chkdsk: crosslinks and lost chains are out of scope.
Container version 3. An image stores a stream of sectors: the whole
device normally, only [0,dataStart) plus allocated clusters with
--used-only, or a --start/--count range. Each volume file carries a
52-byte header (device geometry, codec parameters, which slice of the
stream it holds, payload CRC32) so any volume identifies itself, --info
and --resume need only headers, and a smaller machine can always decode
what a larger one wrote. Volume 0 additionally carries the cluster bitmap
for used-only images, and every volume appends the LBAs of sectors that
would not read (zero-filled in the payload, listed for forensics).
--raw writes no header at all: a plain sector dump. That is what makes
--source cd0 --dest disc.iso --raw produce a real, mountable ISO 9660
file. Raw output excludes --split, --used-only and --resume.
Wire method 3 stores an all-zero block in 5 bytes with no codec time spent,
so blank regions of formatted media cost effectively nothing even without
--used-only.
DIMG uses its own LZ77 codec with an optional canonical-Huffman stage. Every
block is priced three ways and the smallest wins, so a block is never larger
than stored + 5 bytes:
| Method | Wire | When it wins |
|---|---|---|
| 0 stored | raw bytes | already-compressed data (ZIPs, JPEGs, random) |
| 1 LZ77 tokens | flag bits, 1-byte literal, 3-byte match | short blocks where a Huffman header would not pay for itself |
| 2 LZ77 + Huffman | canonical codes, deflate-style length/distance extra bits | almost everything else |
Measured on a synthetic 520 000-byte FAT floppy image (boot sector, FATs, directory, text files, a 60 000-byte incompressible blob, and free space). The incompressible blob puts a hard floor at 11.54 %:
| Config | Bytes | Ratio |
|---|---|---|
| 2 KB window, LZ only | 73 695 | 14.17 % |
| 4 KB window, LZ only | 70 223 | 13.50 % |
| 4 KB window, LZ+Huffman | 67 720 | 13.02 % |
| 8 KB window, LZ+Huffman | 64 617 | 12.43 % |
| 16 KB window, LZ+Huffman | 63 280 | 12.17 % |
16 KB window, LZ+Huffman, --solid | 62 660 | 12.05 % |
| gzip -9, 32 KB window (reference) | 62 184 | 11.96 % |
Two things worth knowing. Window size mattered more than Huffman coding on
disk-like data (6.5 % versus 3.6 % at a 4 KB window). And --solid bought only
0.2 points, which is why it is off by default: carrying the match history
across blocks means a single corrupted block poisons every block after it in
that volume. History is always reset at a volume boundary, so each volume
still decodes independently.
The window is capped at 16 KB. That is not a memory-budget decision — the
match buffer spans window + block bytes, and no real-mode object may reach
64 KB.
Extended memory (XMS) is not directly addressable in real mode; every byte
must be copied down through the driver's block-move call. LZ77 does many random
reads per input byte while searching for matches, so an XMS-resident window
would be orders of magnitude slower for a few percent of ratio. Worse, XMS
requires HIMEM/HIMEMX to be loaded, and that driver hooks INT 15h and reports
zero extended memory — which would break the mem device's full RAM dump.
EMS could technically host a dictionary through its 64 KB page frame, but hash
chain traversal is random, so it would thrash the page map, and the frame sits
in the C000–EFFF region that the rom device dumps.
So DIMG keeps everything in conventional memory, where it is directly addressable, and spends the RAM on a bigger window instead.
DIMG asks the far heap how much it can actually get, subtracts a 20 KB reserve
for DOS, the C runtime, FILE buffers, the stack and the TUI, and then picks the
largest window that fits. --window KB caps it manually; --low-mem pins the
smallest tier.
| Tier | Window | Block | Encoder RAM | Decoder RAM |
|---|---|---|---|---|
| micro | 2 KB | 2 KB | ~13 KB | 2 KB |
| tiny | 4 KB | 4 KB | ~25 KB | 4 KB |
| small | 8 KB | 8 KB | ~41 KB | 8 KB |
| medium | 16 KB | 16 KB | ~74 KB | 16 KB |
Below the micro tier DIMG does not give up: it falls back to storing 2 KB
blocks verbatim, which needs one buffer and nothing else. If the plan cannot
afford --solid, solid mode is dropped before the window is shrunk, because
the window is worth more.
Decoding is always cheaper than encoding. A decoder needs only
window + block bytes — never the hash and chain tables — so a machine with
400 KB free (or far less) can always restore an image that a larger machine
wrote. The window size and codec flags travel in the volume header.
The TUI shows the chosen tier, window, codec and buffer breakdown, and a live line counting how many blocks ended up stored, LZ or Huffman.
--list shows optical drives as cd0, cd1… and DOS logical volumes as
dosD, dosE… These are two different access paths:
| Path | Reaches | Sees | Writable |
|---|---|---|---|
INT 13h (fd0, hd0) | BIOS-visible drives | whole physical medium, incl. MBR | yes |
MSCDEX (cd0) | CD/DVD drives | 2048-byte data sectors | no |
INT 25h/26h (dosD) | any driver-mounted volume | the mounted partition only | yes |
LS-120 / SuperDisk, Zip 100, Zip 250. Whether these work, and through which path, depends on how the drive attaches:
| Drive | Typical exposure | DIMG device |
|---|---|---|
| ATAPI LS-120, BIOS with ARMD support | INT 13h drive (floppy or 0x80+) | fd* / hd*, whole medium |
| ATAPI Zip, BIOS with ARMD support | INT 13h removable drive | hd*, whole medium |
| Parallel-port Zip (GUEST.EXE / PALMZIP) | DOS drive letter only | dosD, volume only |
| SCSI Zip via ASPI driver | DOS drive letter only | dosD, volume only |
| LS-120 on a controller without ARMD BIOS | DOS drive letter only | dosD, volume only |
So the answer is yes for all three, but a driver-only drive gives you the
mounted volume without its partition table. If the BIOS enumerates the unit,
prefer the fd/hd device and you get a byte-exact whole-medium image.
Reads go whole-run first; a failing run is retried sector by sector (each
attempt with BIOS retry + controller reset), so one weak sector costs one
sector, not a 16 KB block. Unreadable sectors are zero-filled and their
LBAs recorded in the volume (see --info). ESC aborts any long operation;
with --resume the image continues where it stopped.
| Feature | Status | Notes |
|---|---|---|
| Floppy image/restore (INT 13h) | full | CHS path; 3 retries + reset |
| Fixed disk image/restore | full | LBA (AH=42/43) when present, else CHS |
Device enumeration (--list) | full | INT 13h AH=08/15/41/48 + BDA |
| Conventional + UMA RAM dump | full | far-pointer copy, 0–1 MB |
Extended RAM dump (mem) | works | INT 15h AH=87h block move; unreadable ranges zero-filled |
| ROM / option-ROM / BIOS dump | full | C0000h–FFFFFh window |
| LZ77+Huffman compression, levels 1–9 | full | per-block method selection; on-the-fly |
Multi-volume spanning (--split) | full | whole-block packing, disk-swap prompts on restore |
CRC32 integrity (--verify) | full | per-volume |
| TUI progress bar (direct B800) | full | --no-tui for plain output |
Modern --long flags | full | --flag=val and --flag val |
| FAT12/16/32 high-level format | works | BPB, 2 FATs, root dir, FAT32 FSInfo + backup boot |
Physical floppy format (--lowlevel) | full | INT 13h AH=18h/05h, track-by-track CHRN |
CD/DVD imaging to ISO (cd0) | works | MSCDEX INT 2Fh AX=1508h, 2048-byte sectors, read-only |
DOS logical volumes (dosD…) | works | INT 25h/26h; reaches Zip / LS-120 / driver-only media |
| Adaptive memory tiers | full | 2–16 KB window chosen from free RAM; stored-only fallback |
| Optical writing / burning | none | out of scope: needs ASPI/MMC, TAO/DAO, lead-in/out |
DIMG runs on FreeDOS the same as on MS-DOS — it only uses the BIOS (INT 13h,
INT 15h, INT 10h/16h) and INT 21h file I/O, all of which FreeDOS implements.
Disk imaging, restore, verify, FAT format and --lowlevel behave identically.
Open Watcom's DOS target is plain 16-bit DOS, so the same DIMG.EXE is used.
One real caveat, on the mem device:
- An XMS driver (
HIMEM.SYS, or FreeDOSHIMEMX/HIMEMSX/JEMMEX) hooks INT 15h and, once active, reports 0 KB of extended memory to everything else — so DIMG can only reach the first 1 MB while an XMM is loaded. - DIMG detects this:
--listwill showext HIDDEN by XMS driverformem. - For a full physical RAM dump, boot FreeDOS without an XMM: comment out the
DEVICE=…HIMEMX.EXEline inFDCONFIG.SYS(or pick a no-driver boot menu entry). Thenmemreports the true extended size and images all of it via INT 15h/87h. - The
romdevice (C000:0–F000:FFFF) is unaffected and always works.
Everything else — fd*, hd*, --format, --split onto floppies — needs no
special configuration on FreeDOS.
| Area | Limitation |
|---|---|
| Optical | Read-only (no burning); 2048-byte cooked sectors only, no raw 2352-byte or audio rips (MSCDEX cannot serve them) |
| Optical | UDF-only or multisession discs may report no size; pass --sectors N |
--used-only | FAT12/16/32 only, up to 262144 clusters (32 KB bitmap); anything else falls back to a full image automatically |
--import | 8.3 names only (no VFAT long names), parent directory must exist, no directory growth, refuses DIMG containers |
--extract | Reads the 8.3 name; a file stored with an LFN is reachable via its short alias |
| Viewer | On a --solid image, seeking backwards replays the volume from its start - correct but slow; non-solid images seek instantly |
| FAT32 | FSInfo free-count is invalidated (set unknown) after import rather than maintained; DOS recomputes it |
| Sectors | FAT operations assume 512-byte sectors (DOS does too) |
| Restore | Refuses mem, rom and optical destinations by design |
| Resume | Continues at the last complete volume boundary; a truncated trailing volume is rewritten |
| Partitions | Exposed read/write, but DIMG does not create or resize partitions - table backup/restore is byte-exact only |
| GPT | Entries beyond 2 TB listed but not exposed; CRC-bad primary header is not auto-recovered from the backup (restore your --backup-pt file instead) |
| --fixfat | Mirrors the healthier FAT copy; it does not rebuild chains or fix crosslinks |
| Browser | 128 entries per directory shown; 8.3 names (LFNs appear as their short alias) |
| Parity | Protects against ONE lost/corrupt volume per set; needs all volumes on one path at creation time |
| Network | No network imaging; out of scope (mTCP integration cannot be validated here honestly) |
Development happens on a Linux host; Open Watcom targets 8086 real mode. What that means for trust, per component:
| Component | Status |
|---|---|
| Codec (comp.c) | Tested on host: round-trips over 6 data profiles x windows 2-16K x levels x solid x decode-only, under ASan+UBSan; width-exact typedefs so 16-bit wraparound is modeled |
| FAT layer (fat.c, fatfmt.c) | Tested on host, end-to-end: format -> import (incl. overwrite, duplicate refusal, zero-length) -> extract -> byte-compare, on FAT12/16/32; bitmap consistency (used+free == clusters) |
| imgio (imgio.c) | Tested on host: random access into real v3 containers - non-solid multi-volume, solid with backward seeks, used-only hole mapping, stored containers, raw files |
| Extract from compressed image | Tested on host: FAT12 image containerized with the real codec, mounted through imgio, files extracted byte-identical |
| Container walk logic | Stream mapping and header pack/unpack exercised by the imgio tests (same format); the DOS-side loop (device reads, volume prompts) is syntax-checked only |
| DOS-only code (disk, dosdrv, optical, memdev, tui, view) | Syntax-checked with stub headers; not executed. INT 13h/25h/26h/7305h/440Dh/MSCDEX paths need real DOS or DOSBox-X/86Box to validate |
| 7305h + 440Dh | Register usage follows RBIL; untested against a live Win9x DOS |
| Partition parser (part.c) | Tested on host: synthetic MBR with extended/EBR chain (4 partitions incl. 2 logical), GPT with CRC-valid header and a >2 TB entry correctly skipped; table backup -> wipe -> restore -> rescan round-trip for both |
| FAT repair (fatfix.c) | Tested on host: corrupt FAT2 detected and mirrored from FAT1, and the reverse (zeroed FAT1 header restored from FAT2) |
| fat write ops | Tested on host: mkdir (nested), import into subdirectory, rename (incl. clash refusal), delete (file, empty dir, non-empty refusal), listing, bitmap consistency after all of it |
| Zero-block method | Tested on host: 4 KB zero block -> 5 wire bytes, decode verified, mixed blocks after zero history verified |
| --copy (chunked passes) | Tested on host: 5000-sector multi-pass copy with odd tail, verify-write path, sub-chunk copy - all byte-identical, on BOTH the extended-memory pass path and the forced-conventional path |
| spill layer (spill.c) | Host backend tested via the copy suite; the XMS entry-point calls and EMS page mapping are DOS-side, written to spec (RBIL), untested on real drivers |
| walk() verify/restore engine | Tested on host: healthy 2-volume compressed set verifies clean; a single flipped payload bit is caught by CRC; container unpacked to raw via --copy matches expected content sector-for-sector |
| TUI (desktop, menus, dialogs, pickers, file selector) | Ran in DOSBox 0.74-3 (Watcom-built exe): desktop + clock, both pulldowns with separators/shadows/hotkeys, device picker listing a BIOS-mounted floppy, the Create-image form, the file selector, and clean exit through its own dialog |
| Block map | Ran in DOSBox: live cell fill with the read frontier during a real fd0 image, VERIFY pass in green, legend and ETA correct; a stats-row collision with the map was found this way and fixed (stats now row 21) |
| Image -> verify end-to-end | Ran in DOSBox: 1.44 MB of random data read via INT 13h, compressed, containerized, then CRC-verified clean - the first full hardware-path round trip |
| TUI usability round 2 | Ran in DOSBox after real-use feedback: F9/Alt+letter/F1 keys, in-TUI output windows, TV button shadows, label prefill (WORKDISK read off a formatted image), filtered file selector picking T2.000 straight into a verify run, floppy size re-probe at operation time |
| Volume-0 naming | Fixed: a picked file with an extension opens as given (honest "not a DIMG volume" errors); bare stems keep the .000 convention - host walk/copy suites re-run green |
| DGROUP budget | Watcom caught a 64 KB near-data overflow the gcc sweep cannot see; new TUI buffers moved to the far heap |
| Single-drive swap flow, browser | Syntax-checked + host-tested logic; the interactive swap prompts still await a two-image DOSBox session |
| Keyboard polling | Uses intr()/REGPACK with INTR_ZF throughout - Watcom's int86() only reports carry in cflag and never fills a flags field, a bug found and fixed on real DOS |
| Parity (parity.c) | Tested on host: create -> delete a volume -> rebuild -> byte-identical; same for an in-place corrupted volume; healthy-set no-op; two-casualty refusal |
The honest summary: everything that can run on the host has been run on the host under sanitizers; everything that needs an 8086 and real interrupts is written carefully and awaits a smoke test in 86Box/DOSBox-X.
mount c .
imgmount a floppy.img -t floppy
c:
dimg list
dimg image --source fd0 --dest c:test --compress
DOSBox exposes mounted imgmount media to INT 13h, so fd0/hd0 appear in
--list. For raw hardware access use real DOS or 86Box/PCem.
Note: --lowlevel drives the physical floppy controller (INT 13h AH=05h). It
is only meaningful on a real floppy drive (or an emulator with true FDC
emulation such as 86Box); plain DOSBox treats a track format as a no-op.
| File | Role |
|---|---|
dimg.h | shared types, device kinds, v3 volume header |
main.c | mode dispatch |
args.c/h | long-flag parser, usage text |
disk.c/h | INT 13h I/O, device enumeration, low-level floppy format |
dosdrv.c/h | DOS volume I/O: INT 25h/26h, INT 21h 7305h (FAT32), 440Dh geometry |
optical.c/h | MSCDEX CD/DVD reads, ISO 9660 size probe |
memdev.c/h | RAM/ROM reads incl. INT 15h/87h above 1 MB |
imgio.c/h | one sector API over devices, raw images and DIMG containers |
fat.c/h | FAT12/16/32: lookup, extract, import, used-cluster bitmap |
fatfmt.c/h | FAT formatter over imgio (devices and image files) |
container.c/h | image/restore/verify/compare/info, volumes, resume, bad list |
comp.c/h | LZ77 + canonical-Huffman codec |
memplan.c/h | memory-tier planner |
xalloc.c/h | far-heap allocation helpers |
view.c/h | interactive hex sector viewer |
fsext.c/h | --extract / --import command glue |
part.c/h | MBR/EBR/GPT scan, hdNpN pseudo-devices, table backup/restore |
fatfix.c/h | FAT copy check and mirror repair |
browse.c/h | full-screen file manager |
parity.c/h | XOR parity volume: create and rebuild |
menu.c/h | interactive menu shell (bare dimg) |
spill.c/h | XMS/EMS bulk pass storage for the copy buffer |
tui.c/h | text UI, progress + ETA, ESC abort, INT 28h idle |