DOS INT 21h AH=6Ch: Extended Open/Create Actions and FreeDOS Limits
Understand the DOS extended open/create call, its action result and compatibility caveats, including FreeDOS kernel flags that remain incomplete.
INT 21h function AH=6Ch is the DOS extended open/create interface. It combines a caller-selected policy for an existing or missing file with open-mode and attribute inputs, instead of forcing an application to make a separate existence check and then choose a basic open or create call. That is useful for reducing race windows in ordinary single-task DOS programs, but it is not a transactional filesystem primitive and it does not guarantee identical behavior across every DOS kernel, redirector, or FreeDOS release.
The version-four MS-DOS programmer reference identifies function 6Ch as Extended Open/Create. In FreeDOS, the current kernel source contains an implementation comment that says it is “not fully functional” for bits 4, 5, and 6 of BH. That warning should shape application design: do not depend on those sharing-related flag bits without testing the exact kernel and file system where the program will run.
Call structure and return contract
The conventional call uses AX=6C00h, with the low byte selecting the extended-open operation. The documented interface supplies an open mode in BX, file attributes for creation in CX, action-control flags in DX, and a zero-terminated pathname at DS:SI. On success, Carry Flag is clear, AX contains the returned file handle, and CX reports which action was performed. On failure, Carry Flag is set and AX contains a DOS error code.
The action result is operationally important. A caller that requests “open if present, create if absent” should be able to distinguish opening a preexisting file from creating one. A request that replaces an existing file has a more destructive outcome and should not be confused with a simple open. Read the manual for the exact bit meanings used by the target DOS version; do not copy register values from an unrelated sample without checking the action policy.
; Interface sketch only. Initialize DS and verify the target DOS contract.
mov ax, 6C00h ; extended open/create
mov bx, open_mode ; access/share mode documented for target DOS
mov cx, attributes ; attributes if a new file is created
mov dx, action ; explicit open/create/replace policy
mov si, offset path ; ASCIIZ path in DS
int 21h
jc dos_error
mov [handle], ax
mov [action_done], cx
The snippet deliberately names action and mode fields rather than assigning a magic value. This function’s policy bits are easy to get wrong and a single mistaken replace bit can truncate useful data. Build the action from named constants in the application, document it in one place, and test on a disposable directory containing both an existing file and an absent filename.
Avoid a check-then-act design when the API contract fits
A fragile pattern is to search for a name, observe that it is absent, and then create it with a separate call. Another program or redirector can change the directory between the search and the creation. DOS is usually a single-task environment, but TSRs, network redirectors, and nested program execution can still make assumptions about exclusive state unsafe. Extended open lets the caller express an open/create action in one DOS request, which is preferable when the target implementation supports the needed semantics.
This does not mean AH=6Ch guarantees atomicity across every remote filesystem or compatibility layer. The DOS function can be mediated by a redirector, and network semantics depend on that redirector and server. If the application requires a strong no-clobber guarantee, test with the real redirector or use the documented exclusive-create mechanism available in that environment. Compare AH=6Ch with the basic create-new call and the application’s required fallback policy; do not infer POSIX O_EXCL behavior from the word “extended.”
AH=6Ch is also distinct from the program’s file-handle lifecycle. The caller still owns a handle after a successful open and must close it, inspect errors, and avoid leaking handles. A failed close, disk-full condition, or delayed write failure is separate from the initial open decision. If durability matters, follow the correct write and commit/close protocol supported by the target system.
FreeDOS implementation boundary
FreeDOS’s kernel source labels the AH=6Ch implementation as not fully functional for BH bits 4 through 6. Those bits are part of the higher-order byte of the BX input. The source then validates action bits from DL and routes the call through the kernel’s open implementation. This is concrete evidence that source-level support exists, but it is also a warning that a generic description of DOS open modes should not be treated as a blanket FreeDOS guarantee.
Applications should define a tested compatibility subset. If the program needs only a conventional access mode and an explicit basic open/create decision, test that path against the released FreeDOS kernel and any redirector in scope. If it needs sharing behavior encoded in those BH bits, verify the relevant kernel version’s source and run an interoperability test with two processes or clients. A unit test on local FAT alone cannot prove server-side sharing behavior.
Do not overstate what the source proves: an implementation comment is not a formal compatibility promise. Kernel source can evolve, and a third-party FreeCOM build or clone may differ. Record the kernel version reported by the test system, archive the exact binary or package, and re-run the test when upgrading the kernel or redirector.
Choose fallback APIs consciously
Basic DOS APIs such as open-existing and create/truncate have simpler contracts but separate decisions. They can be appropriate for legacy targets if the application handles the gap and errors intentionally. The “create new” API can fail when a file already exists; that is often safer than silently replacing it. A temporary-file API can help generate a unique name, but its behavior must be validated separately and it does not automatically create a secure, durable deployment transaction.
Fallback logic must not turn an error into permission to overwrite. For example, if AH=6Ch fails because the target path is invalid, retrying with a destructive create call can erase the distinction between “missing” and “not writable.” Classify expected DOS error codes, preserve the original result for diagnostics, and abort on unrecognized failures. Use extended-error information only when it is available and documented for the relevant DOS version.
Test matrix for a file-open policy
Use a disposable directory and test at least these states:
- The target file exists and contains a known sentinel.
- The target file does not exist.
- The parent directory does not exist.
- The target is read-only or has a protected attribute.
- The volume is full or write-protected, if that can be simulated safely.
- A redirector or network path is active, if the program supports one.
For each state, record Carry Flag, AX, returned handle, CX action result, whether the sentinel changed, and any subsequent close/write status. Confirm that every success path closes its handle and every error path leaves data in the documented state. Run the test against a fresh copy each time; once an overwrite case has modified the fixture, it no longer represents the original state.
AH=6Ch is valuable because it makes open/create intent explicit in one API request. Its value depends on precise action flags and tested implementation behavior. In FreeDOS, the source’s partial-functionality comment is a concrete compatibility caveat, especially for applications relying on BH sharing bits. Use the narrowest mode that satisfies the program, prefer non-destructive failure over accidental replacement, and treat every cross-version or redirected-filesystem behavior as something to verify rather than assume.
Related:
- DOS INT 21h File Creation: Temporary Names and No-Clobber Semantics
- DOS INT 21h Function 59h: Read Extended Error Diagnostics
Sources: