Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PATCH 1.0

A directory-level patch utility for MS-DOS, written in 8086 assembly for MASM 1.25.

PATCH compares two directories and writes a single .DIF file that turns the first into the second, byte for byte. Applying that file restores the second directory exactly, including files that were added or deleted. Files that are identical in both directories never enter the patch and are never touched on apply.

The .DIF file is readable by eye but processed as raw bytes, so it does not depend on the encoding of the files, on their line terminators, or on whether they are text or binary at all.

  • Target: DOS 2.0 or later. Only DOS 2.0 calls are used (3Ch, 3Dh, 3Eh, 3Fh, 40h, 41h, 42h, 43h, 48h, 4Ah, 56h).
  • Memory: about 40 KB. Tested on a 128 KB machine.
  • No file is ever read into memory in full, not even the .DIF itself, so patch and file size are limited only by the file system. A 1.8 MB patch has been built and applied on a 640 KB machine, and a 600 KB file processed there.
  • Checksums are CRC-32 with polynomial EDB88320h, the same one used by PKZIP and zlib.crc32, so a patch can be verified from outside DOS.

See docs/FORMAT.md for the .DIF grammar and the internals.

Quick start

A compiled binary is in bin/PATCH.COM. Copy it anywhere on your DOS path and run it without arguments to see the usage banner.

PATCH MAKE  <olddir> <newdir> <file.DIF>    build a patch
PATCH APPLY [dir] <file.DIF>                apply it in place
PATCH TEST  [dir] <file.DIF>                rehearse, changing nothing

Typical use, distributing a change to a source tree:

C:\> PATCH MAKE SRC.OLD SRC CHANGES.DIF
21 files, 4 changed

C:\> PATCH TEST SRC.OLD CHANGES.DIF
checking source checksums
trial run, nothing is changed
test passed

C:\> PATCH APPLY SRC.OLD CHANGES.DIF
checking source checksums
applying patch
applied

For APPLY and TEST the directory is optional; without it the current directory is used. There is no output directory: APPLY edits files where they lie.

Exit code Meaning
0 Everything matched
1 Bad command line
2 File operation failed
3 Checksum or parse mismatch

How APPLY works

  1. First pass (checking source checksums) reads the whole patch and verifies the length and CRC-32 of every source file it mentions. Nothing is modified. A file that already matches its target state is reported already patched and skipped on the second pass. A file matching neither the source nor the target state stops the run with exit code 3.
  2. If nothing is left to do, the second pass does not start at all: nothing to do, exit code 0.
  3. Second pass (applying patch) rebuilds each file into a temporary PATCH$$$.TMP, verifies its length and checksum, and only then puts it in place of the original.
  4. On any error the temporary file is removed. The utility leaves no debris behind.

TEST is the same second pass, except the rebuilt file is deleted after its checksum is verified and the originals are never touched.

MAKE validates the hunk layout of every file before writing it, but does not rehearse the finished patch. Run TEST separately if you want that.

The .DIF file

PATCH 1.0
;
FILE PATCH BOOT.ASM
OLD 37469 F5ABDE5F
NEW 37527 7533887B
@ 1195
- 7
TILE_01
+ 6
SYSINI
END BOOT.ASM
;
END PATCH 1

Service lines are ASCII and end with CRLF; hunk bodies are raw bytes counted by a byte counter, not by lines. The full grammar, the hunk-building algorithm, and the memory design are in docs/FORMAT.md.

Repository layout

bin/PATCH.COM      the compiled utility, ready to run
src/               the seven modules, PATCH.INC and MAKEIT.BAT
tools/masm/        MASM 1.25: MASM.EXE, LINK.EXE, EXE2BIN.EXE
build/             scratch directory the build happens in, ignored by git
BUILD.BAT          copies the sources and the assembler into build/ and builds
docs/FORMAT.md     the .DIF format and the internals

Building from source

The sources are written for MASM 1.25 and the build is verified with it. Later assemblers have not been tested. The assembler is in the repository, so a clone has everything the build needs.

1. Clone the repository

git clone https://github.com/rustequal/patch.git

Keep the path short and free of spaces: DOSBox exposes 8.3 filenames only. Everything inside the repository is already 8.3.

2. Point DOSBox at the clone

DOSBox or DOSBox-X is enough; real hardware, 86Box and PCem work equally well. Open the configuration file (OptionsConfiguration in the shell, or dosbox.conf next to the executable) and put the clone on drive C:

[cpu]
core=auto
cycles=auto

[autoexec]
mount c D:\patch
c:

On Linux and macOS the mount line reads mount c /home/you/patch.

3. Build

C:\> BUILD.BAT

BUILD.BAT changes into BUILD\, copies the sources out of SRC\ and the assembler out of TOOLS\MASM\, and runs MAKEIT.BAT there. Nothing is written outside BUILD\, which git ignores, so the tree stays clean and a rebuild needs no cleanup.

MAKEIT.BAT assembles the seven modules, links them in a fixed order, converts the result with EXE2BIN and removes the intermediates. The link order matters: PATEND.OBJ must be last, because it carries the CRC table, the stack and the end-of-image marker that the memory setup measures against.

masm PATCH,,NUL;
...
link PATCH+PATTXT+PATIO+PATWR+PATMAK+PATAPL+PATEND,PATCH,NUL;
exe2bin PATCH.EXE PATCH.COM

4. Try the result

C:\BUILD> PATCH
PATCH 1.0 - source tree patcher, (c) 2026 rustequal, MIT License

PATCH MAKE  <olddir> <newdir> <file.DIF>
PATCH APPLY [dir] <file.DIF>
PATCH TEST  [dir] <file.DIF>

A fuller check takes about a minute: copy SRC\ twice, change one file in the second copy, then PATCH MAKE a patch between the two, PATCH TEST it against the first copy and PATCH APPLY it.

Modules

File Contents
PATCH.ASM Entry point, command line, directory walk, MAKE driver
PATTXT.ASM Screen output, numbers, strings
PATIO.ASM Files, streams, memory, CRC-32
PATWR.ASM Writing text into the .DIF
PATMAK.ASM Sliding window over a file, comparison, hunk building
PATAPL.ASM .DIF parsing and application
PATEND.ASM CRC table, stack, end of image
PATCH.INC Shared constants and structure offsets

Two environment traps worth knowing before you edit anything:

  • MASM 1.25 does not tolerate data placed below code. Forward references to DB and DW that it has not seen yet are sized its own way in pass one and it falls apart in a cascade of Phase error. Each module keeps its data at the top.
  • DOS sets SP for a .COM program to the top of the whole allocated block. If the program hands memory back with function 4Ah, the stack ends up outside the shrunken block and the first large read overwrites it. The utility moves SP to its own stack inside the image as its first act.

Limits

  • One directory level. Subdirectories are not descended into and do not enter the patch.
  • All files are taken, hidden and system included; directories are filtered out.
  • No limit on the number of files or hunks. The directory listing is not stored at all, and the hunk list lives in a memory block obtained from DOS.
  • An edit longer than MAXD = 600 bytes is not found by the resynchronisation search and the record degrades to REPLACE, meaning the whole file is written out. This does not happen on assembly listings; it does happen on binary data.
  • File attributes (hidden, system, read-only) are cleared before editing and restored after.
  • A .DIF service line is limited to 200 bytes. Hunk bodies are not, since they are read by a byte counter.
  • Creation timestamps are not preserved.
  • Volumes that DOS does not expose through FindFirst are not supported.

Verifying the release binary

bin/PATCH.COM
size    25859 bytes
CRC-32  C31574BF
SHA-256 6fd729608f1f8882d038133b362e2008f462e73c6407b47b5afbb1fe2e11e254

License

MIT, see LICENSE. It covers the PATCH sources and binary. The three files in tools/masm/ are Microsoft's and carry their own terms; see tools/masm/README.md.

The copyright line is compiled into the binary at label MUSAGE in PATCH.ASM. If you fork this and ship your own build, change it there.

About

A directory-level patch utility for MS-DOS, written in 8086 assembly for MASM 1.25

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages