DOS INT 21h AH=68h: Commit File Buffers Without Closing the Handle
Use DOS function 68h to request a file-handle commit, check carry and AX errors, and understand why it is not a power-loss guarantee.
DOS INT 21h function AH=68h, usually called Commit File, asks DOS to flush buffered data associated with an open file handle without closing that handle. It is useful when an application wants to commit data at deliberate checkpoints while keeping a file open. It is not a database transaction, a multi-file atomic update, or a universal guarantee that every storage device has physically persisted the bits through sudden power loss. A correct program checks the function’s error result and still treats device, driver, and network semantics as part of the reliability model.
The call interface
The documented interface is small: set AH=68h, put the open file handle in BX, and call INT 21h. On return, a clear carry flag indicates success; a set carry flag indicates failure and AX contains the DOS error code.
mov ah, 68h
mov bx, file_handle
int 21h
jc commit_failed
; DOS reported that the handle's buffered data was committed
The handle must have been obtained from a successful file-open or file-create operation and remain valid. Do not pass a file descriptor from a C runtime unless the runtime’s documentation confirms that it is the DOS handle expected by the API. Some libraries wrap handles or maintain additional buffering above DOS; flush the language runtime’s own stream buffers before calling the DOS function.
Function 68h is documented in MS-DOS 3.3-era references. Availability should not be assumed on older DOS versions or arbitrary clones. A DOS version query can inform compatibility decisions but does not prove that every redirector or driver supports the operation. The robust procedure is to use the function only when the target contract supports it, check carry/AX on every call, and provide a defined error path.
Why commit without close?
DOS can retain data in internal file buffers to reduce the number of device operations. A normal close updates the file’s metadata and releases the handle, but closing and reopening just to force data out can interrupt program state, fail if no handle is available, or affect shared/network access. Commit File requests the flush while preserving the caller’s open handle, which is useful for long-running programs that periodically checkpoint a log or work file.
The call is file-handle scoped. It should not be confused with a command that globally flushes every dirty buffer on every volume. If an application has written to two files, committing one handle does not automatically prove the other is committed. Likewise, writing a temporary file and renaming it later involves directory operations that have their own failure and ordering behavior.
If a handle refers to a character device rather than a regular file, the MS-DOS Encyclopedia notes that Commit File can report success while having no effect. A successful carry result must therefore be interpreted in context: it means the DOS service accepted the request under its contract, not that a character device has stored a durable file.
Place commit calls at meaningful checkpoints
Calling commit after every tiny write can impose unnecessary I/O and reduce performance. Calling it only at program exit may not protect important intermediate progress. Choose checkpoints that correspond to recoverable units of work: after writing a complete record group, after writing a journal segment, or before telling the user that an export is finished. Keep the checkpoint data self-describing so a restart can distinguish a complete record from a partially written tail.
A typical sequence is:
- Open or create the data file with the desired access mode.
- Write a complete logical unit and check the write result and byte count.
- Flush any higher-level C or library buffers to DOS.
- Call AH=68h with the valid DOS handle and check carry/AX.
- Continue only if the commit succeeded; otherwise preserve an error report and do not claim durable completion.
- Close the handle normally when finished and check the close result too.
The commit request does not make steps 2 through 4 atomic. If the system fails halfway through a multi-call update, the file can contain a prefix of the intended data or inconsistent application-level structures. Applications that need crash recovery require a format-level journal, checksums, sequence numbers, or another recovery design.
What “written to disk” does and does not establish
Historical DOS documentation describes the function as flushing DOS’s buffered file data and updating directory/FAT information associated with the file. That is the DOS-level guarantee. Between DOS and physical media may be a block driver, BIOS, controller cache, USB bridge, network redirector, or device firmware. The API does not define a universal command that forces every layer’s volatile write cache onto nonvolatile storage.
The distinction is especially important on modern virtualized or bridged storage. A guest DOS kernel may report success after a host filesystem accepted a write; the host may in turn buffer it. A network redirector may map the call to a server operation with its own semantics. A disk controller can acknowledge writes before media programming completes. Do not promise power-loss durability from AH=68h alone unless the full system’s documentation and tests support that claim.
Commit is also not the same as verification. It requests that data be committed; it does not calculate a digest and reread every byte for comparison. A successful commit can still leave an undetected media error or a logically incorrect application record. Use a separate read-back and checksum when integrity is a requirement.
Error handling and compatibility
When carry is set, capture AX immediately before making another DOS call. Use the documented DOS error-code map for the target kernel and report the failing operation. Do not loop forever retrying a commit: repeated retries can hide a broken device path, and some errors require user action such as replacing media or correcting a sharing conflict.
If function 68h is unsupported, behavior may differ among old DOS versions and clones. A program that must support earlier DOS releases can use its documented close/reopen or duplicate-handle compatibility strategy where appropriate, but these alternatives have their own failure modes. Closing a duplicate handle may trigger a flush only under the relevant DOS behavior; it can consume a handle and alter sharing state. Do not silently fall back to a sequence that changes the application’s semantics.
In network environments, preserving the open handle can be more effective than close-and-reopen because the latter may lose the original sharing or locking context. Still, confirm the redirector’s behavior. A return code from the local DOS interface cannot attest to remote server replication, backup, or power protection.
Keep handle and file lifecycle correct
Function 68h does not close the handle, release it, or update the application’s in-memory state. Continue to use the same handle for subsequent operations, and close it when the file is no longer needed. A leaked handle can exhaust a DOS process’s handle table. If the program terminates unexpectedly, DOS eventually closes open handles, but that is not a substitute for a planned commit and close sequence.
Programs should also account for the distinction between DOS handles and higher-level language streams. fprintf or a similar buffered library call may leave bytes in a process buffer that DOS has not yet seen. Calling AH=68h before the runtime flush sends only what DOS already received. Flush the language runtime first, check its result, then commit through the matching DOS handle if the runtime exposes it.
If the application maintains multiple related files, define ordering explicitly. For example, write and commit the new data record before updating a separate index, then commit the index, while still designing recovery for either failure point. There is no all-files commit transaction in the single-handle AH=68h operation. A recovery process should be able to detect an incomplete update rather than assuming all handles succeeded together.
Controlled validation plan
Test a DOS program in a disposable VM image with a scratch file. Write a known record, flush any language-level buffer, invoke AH=68h, check carry and error code, then close the handle and compare the file with the expected bytes from a separate test harness. Repeat with an invalid or closed handle only in a throwaway environment to confirm the program’s error path; do not provoke invalid calls on a production database.
Record the DOS kernel, filesystem, controller, emulator, and redirector versions. If power-loss behavior is in scope, a clean shutdown is not a sufficient test; use the platform vendor’s controlled fault-injection method on a disposable system and verify recovery. Do not physically cut power to a real storage device as a casual test. The accepted claim should be no stronger than the evidence: “DOS reported commit success” is not identical to “the data survived sudden loss of power.”
Acceptance criteria
A correct AH=68h call uses a valid DOS file handle in BX, checks carry and captures AX on failure, flushes any user-space buffering first, and keeps the handle open until normal close. The application has explicit behavior for unsupported services and errors, and its durability claims account for the filesystem, controller, device cache, and any network or virtualization layer. Where byte integrity matters, it also performs independent validation.
Related:
- DOS File Handles: Open, Read, Inherit, and Redirect I/O
- FreeDOS Disk Buffers: BUFFERS=, Dirty Metadata, and Cache Tuning
Sources: