Skip to content

Latest commit

History

28 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Earentir's Disk Image (DIMG) — 16-bit real-mode DOS disk & memory imager

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).

Installing Open Watcom V2 and building DIMG

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):

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.

Windows host (simplest)

  1. From the Current-build release, download the Windows installer (.exe).

  2. 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.

  3. 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.)

  4. Build:

    cd dimg
    wmake rem uses the provided Makefile -> DIMG.EXE
    rem or the one-shot driver:
    build.bat
    

Linux host (cross-compile, then copy to DOS)

  1. From the Current-build release, download the Linux x64 installer binary.

  2. Install (it self-extracts; /opt/watcom is a common target):

    chmod +x open-watcom-2_0-c-linux-x64*
    ./open-watcom-2_0-c-linux-x64* # follow prompts, choose a dir
    
  3. Set the environment (the installer also drops a setvars/owsetenv script in the install root you can source instead):

    export WATCOM=/opt/watcom
    export PATH=$WATCOM/binl64:$WATCOM/binl:$PATH
    export INCLUDE=$WATCOM/h
    export EDPATH=$WATCOM/eddat
    
  4. Build (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.c
    
  5. Copy the resulting DIMG.EXE onto a DOS disk / image and run it there.

Flag reference used above

-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.

Running it

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.

Build (quick reference)

wmake # or: build.bat (Windows) / the wcl line (Linux)

Output: DIMG.EXE. Runs on real DOS, DOSBox, 86Box/PCem, qemu, etc.

Usage

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
TaskCommand
Image a floppy, compresseddimg image --source fd0 --dest a:boot --compress=9
Image only used space on a Zipdimg image --source dosD --dest a:zip --used-only --compress
Rip a CD to a mountable ISOdimg image --source cd0 --dest disc.iso --raw
Continue an interrupted imagesame command + --resume
Image just the first trackdimg image --source fd0 --dest trk0 --start 0 --count 18
Verify an image internallydimg verify --source a:boot
Compare an image to mediadimg verify --source a:boot --dest fd0
Inspect an imagedimg info --source a:boot
Browse sectors (media or image)dimg view --source hd0 --lba 63
Pull a file out of an imagedimg extract --source disk.edi --path DOCS\PLAN.TXT --dest plan.txt
Put a file into a raw imagedimg import --source plan.txt --dest disk.img --path PLAN.TXT
Browse files (any source)dimg browse --source hd0p1
Copy disk to diskdimg copy --source hd0 --dest hd1 --verify-write
Clone a floppy with ONE drivedimg copy --source fd0 --dest fd0 (RAM-buffered swap passes)
Unpack a container to a raw imagedimg copy --source disk.edi --dest disk.img
Check / repair the FAT copiesdimg fixfat --dest dosC then add --yes
Back up MBR/GPT + EBR chaindimg pt-backup --source hd0 --dest a:\tables.bin
Put the tables backdimg restore-pt --source a:\tables.bin --dest hd0
Tag an image--comment "office PC 1997, C: before reinstall"
Protect a set with paritydimg image ... --parity or later dimg parity --source a:boot
Rebuild a lost/rotten volumedimg parity-repair --source a:boot
Fight weak media harder--retries 5 (extra per-sector rounds)
No flags at alldimg opens the interactive menu
Format a devicedimg format --dest fd0 --fs 12 --label WORK
Create a blank formatted imagedimg 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.

Partitions

--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.

The file browser

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.

KeyAction
F3hex view of the file under the cursor
F5export file(s) to a DOS path (marked files batch)
F6import a local file into the current directory
F7make directory
F8delete (directories only when empty)
Rrename (8.3, same directory)
Insmark / unmark
ESCquit

Copy buffering, XMS/EMS, and single-drive cloning

--copy builds the largest pass buffer it can, in this order:

TierBackendTypical size1.44 MB clone
1XMS (HIMEM, 286+)megabytes1 swap cycle
2EMS 3.2+ (EMM386, or a real board on an XT)megabytes1 swap cycle
3conventional RAM (up to twenty 32 KB far chunks)~450-580 KB3-4 swap cycles
4static 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).

Disk-to-disk cloning

--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.

One interface

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.

Real floppy hardware: track and DMA boundaries

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.

Read-only and misbehaving media

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.

Settings and dimg.yaml

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:

PrioritySource
1--config C:\PATH\dimg.yaml (or a directory, then dimg.yaml is appended)
2the DIMGCONF environment variable (SET DIMGCONF=C:\DIMG\ in AUTOEXEC)
3dimg.yaml beside DIMG.EXE
4dimg.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.

Interchange with other tools

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:

WantCommand
A floppy image WinImage / 86Box / DOSBox / mtools opendimg image --source fd0 --dest disk.ima --raw
The same from an existing DIMG containerdimg copy --source x.edi --dest x.ima
A real ISO from a CDdimg image --source cd0 --dest cd.iso --raw
Write a WinImage/emulator image to a real diskdimg 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: surviving a dead volume

--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.

Format: quick vs full

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.

The full-screen interface (dimg tui)

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:

MenuEntries
ImageCreate, Restore, Verify, Compare, Details, Parity create/rebuild, Exit
DiskCopy, Single-drive clone, Format, Fix FAT, Table backup/restore, List devices
ToolsBrowse files, Sector viewer
HelpAbout, 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.

Workspace model

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.

The block map

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:

CellMeaning
dim blockpending
r (cyan)being read
W (yellow)being written
bright blockdone
green blockverified
B on redbad sector in this cell (sticky - never painted over)
small dotskipped (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.

FAT repair

--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.

Image / volume format

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.

Compression

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:

MethodWireWhen it wins
0 storedraw bytesalready-compressed data (ZIPs, JPEGs, random)
1 LZ77 tokensflag bits, 1-byte literal, 3-byte matchshort blocks where a Huffman header would not pay for itself
2 LZ77 + Huffmancanonical codes, deflate-style length/distance extra bitsalmost 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 %:

ConfigBytesRatio
2 KB window, LZ only73 69514.17 %
4 KB window, LZ only70 22313.50 %
4 KB window, LZ+Huffman67 72013.02 %
8 KB window, LZ+Huffman64 61712.43 %
16 KB window, LZ+Huffman63 28012.17 %
16 KB window, LZ+Huffman, --solid62 66012.05 %
gzip -9, 32 KB window (reference)62 18411.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.

No XMS, no EMS — on purpose

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.

Memory budget

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.

TierWindowBlockEncoder RAMDecoder RAM
micro2 KB2 KB~13 KB2 KB
tiny4 KB4 KB~25 KB4 KB
small8 KB8 KB~41 KB8 KB
medium16 KB16 KB~74 KB16 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.

Optical media and superfloppies

--list shows optical drives as cd0, cd1… and DOS logical volumes as dosD, dosE… These are two different access paths:

PathReachesSeesWritable
INT 13h (fd0, hd0)BIOS-visible driveswhole physical medium, incl. MBRyes
MSCDEX (cd0)CD/DVD drives2048-byte data sectorsno
INT 25h/26h (dosD)any driver-mounted volumethe mounted partition onlyyes

LS-120 / SuperDisk, Zip 100, Zip 250. Whether these work, and through which path, depends on how the drive attaches:

DriveTypical exposureDIMG device
ATAPI LS-120, BIOS with ARMD supportINT 13h drive (floppy or 0x80+)fd* / hd*, whole medium
ATAPI Zip, BIOS with ARMD supportINT 13h removable drivehd*, whole medium
Parallel-port Zip (GUEST.EXE / PALMZIP)DOS drive letter onlydosD, volume only
SCSI Zip via ASPI driverDOS drive letter onlydosD, volume only
LS-120 on a controller without ARMD BIOSDOS drive letter onlydosD, 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.

Reading damaged media

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.

Capability matrix

FeatureStatusNotes
Floppy image/restore (INT 13h)fullCHS path; 3 retries + reset
Fixed disk image/restorefullLBA (AH=42/43) when present, else CHS
Device enumeration (--list)fullINT 13h AH=08/15/41/48 + BDA
Conventional + UMA RAM dumpfullfar-pointer copy, 0–1 MB
Extended RAM dump (mem)worksINT 15h AH=87h block move; unreadable ranges zero-filled
ROM / option-ROM / BIOS dumpfullC0000h–FFFFFh window
LZ77+Huffman compression, levels 1–9fullper-block method selection; on-the-fly
Multi-volume spanning (--split)fullwhole-block packing, disk-swap prompts on restore
CRC32 integrity (--verify)fullper-volume
TUI progress bar (direct B800)full--no-tui for plain output
Modern --long flagsfull--flag=val and --flag val
FAT12/16/32 high-level formatworksBPB, 2 FATs, root dir, FAT32 FSInfo + backup boot
Physical floppy format (--lowlevel)fullINT 13h AH=18h/05h, track-by-track CHRN
CD/DVD imaging to ISO (cd0)worksMSCDEX INT 2Fh AX=1508h, 2048-byte sectors, read-only
DOS logical volumes (dosD…)worksINT 25h/26h; reaches Zip / LS-120 / driver-only media
Adaptive memory tiersfull2–16 KB window chosen from free RAM; stored-only fallback
Optical writing / burningnoneout of scope: needs ASPI/MMC, TAO/DAO, lead-in/out

FreeDOS notes

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 FreeDOS HIMEMX / 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: --list will show ext HIDDEN by XMS driver for mem.
  • For a full physical RAM dump, boot FreeDOS without an XMM: comment out the DEVICE=…HIMEMX.EXE line in FDCONFIG.SYS (or pick a no-driver boot menu entry). Then mem reports the true extended size and images all of it via INT 15h/87h.
  • The rom device (C000:0–F000:FFFF) is unaffected and always works.

Everything else — fd*, hd*, --format, --split onto floppies — needs no special configuration on FreeDOS.

Known limitations (honest list)

AreaLimitation
OpticalRead-only (no burning); 2048-byte cooked sectors only, no raw 2352-byte or audio rips (MSCDEX cannot serve them)
OpticalUDF-only or multisession discs may report no size; pass --sectors N
--used-onlyFAT12/16/32 only, up to 262144 clusters (32 KB bitmap); anything else falls back to a full image automatically
--import8.3 names only (no VFAT long names), parent directory must exist, no directory growth, refuses DIMG containers
--extractReads the 8.3 name; a file stored with an LFN is reachable via its short alias
ViewerOn a --solid image, seeking backwards replays the volume from its start - correct but slow; non-solid images seek instantly
FAT32FSInfo free-count is invalidated (set unknown) after import rather than maintained; DOS recomputes it
SectorsFAT operations assume 512-byte sectors (DOS does too)
RestoreRefuses mem, rom and optical destinations by design
ResumeContinues at the last complete volume boundary; a truncated trailing volume is rewritten
PartitionsExposed read/write, but DIMG does not create or resize partitions - table backup/restore is byte-exact only
GPTEntries beyond 2 TB listed but not exposed; CRC-bad primary header is not auto-recovered from the backup (restore your --backup-pt file instead)
--fixfatMirrors the healthier FAT copy; it does not rebuild chains or fix crosslinks
Browser128 entries per directory shown; 8.3 names (LFNs appear as their short alias)
ParityProtects against ONE lost/corrupt volume per set; needs all volumes on one path at creation time
NetworkNo network imaging; out of scope (mTCP integration cannot be validated here honestly)

Verification status

Development happens on a Linux host; Open Watcom targets 8086 real mode. What that means for trust, per component:

ComponentStatus
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 imageTested on host: FAT12 image containerized with the real codec, mounted through imgio, files extracted byte-identical
Container walk logicStream 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 + 440DhRegister 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 opsTested 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 methodTested 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 engineTested 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 mapRan 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-endRan 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 2Ran 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 namingFixed: 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 budgetWatcom caught a 64 KB near-data overflow the gcc sweep cannot see; new TUI buffers moved to the far heap
Single-drive swap flow, browserSyntax-checked + host-tested logic; the interactive swap prompts still await a two-image DOSBox session
Keyboard pollingUses 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.

Testing tips (DOSBox)

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.

Files

FileRole
dimg.hshared types, device kinds, v3 volume header
main.cmode dispatch
args.c/hlong-flag parser, usage text
disk.c/hINT 13h I/O, device enumeration, low-level floppy format
dosdrv.c/hDOS volume I/O: INT 25h/26h, INT 21h 7305h (FAT32), 440Dh geometry
optical.c/hMSCDEX CD/DVD reads, ISO 9660 size probe
memdev.c/hRAM/ROM reads incl. INT 15h/87h above 1 MB
imgio.c/hone sector API over devices, raw images and DIMG containers
fat.c/hFAT12/16/32: lookup, extract, import, used-cluster bitmap
fatfmt.c/hFAT formatter over imgio (devices and image files)
container.c/himage/restore/verify/compare/info, volumes, resume, bad list
comp.c/hLZ77 + canonical-Huffman codec
memplan.c/hmemory-tier planner
xalloc.c/hfar-heap allocation helpers
view.c/hinteractive hex sector viewer
fsext.c/h--extract / --import command glue
part.c/hMBR/EBR/GPT scan, hdNpN pseudo-devices, table backup/restore
fatfix.c/hFAT copy check and mirror repair
browse.c/hfull-screen file manager
parity.c/hXOR parity volume: create and rebuild
menu.c/hinteractive menu shell (bare dimg)
spill.c/hXMS/EMS bulk pass storage for the copy buffer
tui.c/htext UI, progress + ETA, ESC abort, INT 28h idle

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages