July 22nd, 2024

Organizing the five creation dispositions of the Create­File function

The Create­File function has five different creation disposition values. Let’s organize them.

If a file of the requested name doesn’t already exist, you have two choices: You can fail the operation, or you can create a new file.

If a file of the requested name already exists, you have three choices: You can fail the operation, you can open the existing file and preserve the existing data, or you can open the existing file but set the file length back to zero (truncate), discarding any existing file contents.

Now that we see the possibilities, we can make our table.

If file exists If file doesn’t exist
Fail Create
Fail   CREATE_NEW
Open OPEN_EXISTING OPEN_ALWAYS
Truncate TRUNCATE_EXISTING CREATE_ALWAYS

“Hey, wait, I found a hole in your API. You missed a case: The upper left box is empty!”

That’s right, but the upper left box is “Fail if the file exists, and fail if the file doesn’t exist.” If we had to give that box a name, it would be something like FAIL_ALWAYS.

Which isn’t particularly useful.

If it’s that important to you, I guess you can simulate it yourself:

HANDLE CreateFileFailAlways()
{
    SetLastError(ERROR_OPEN_FAILED);
    return INVALID_HANDLE_VALUE;
}
Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

9 comments

Discussion is closed. Login to edit/delete existing comments.

  • John Elliott

    +3DOS on the Spectrum +3 has two different parameters to its file open call: one for what to do if the file doesn’t exist { fail / create new file } and one if it does { fail / open file / truncate file / rename existing file to .BAK and create new file }

  • Kevin Norris

    Unix equivalent:

    CREATE_NEW is O_CREAT | O_EXCL.
    OPEN_EXISTING is the default (no flags required, except as noted below).
    OPEN_ALWAYS is O_CREAT
    TRUNCATE_EXISTING is O_TRUNC
    CREATE_ALWAYS is O_CREAT | O_TRUNC
    FAIL_ALWAYS does not exist, but on systems where O_EXEC != O_SEARCH, it can be emulated with O_DIRECTORY | O_EXEC (it's not legal to execute a directory). Note that O_TRUNC | O_RDONLY is not a standards-compliant emulation, because the standard says that's UB.

    These must be combined with exactly...

    Read more
    • Jan Ringoš

      I like Windows variation more. It’s way more readable.

  • Yuri Khan

    It would stand to reason if those values were organized as two bit fields, like one bit for the disposition for the “does not exist” case and two for “exists”, but no. They are defined as 1..5 in somewhat arbitrary order.

    “Hey, wait, I found a hole in the API that might plug that other hole. Let’s define FAIL_ALWAYS as 0!”

    But that would probably fail with the wrong reason, setting last error not to ERROR_OPEN_FAILED but...

    Read more
    • Kalle Niemitalo

      The MS-DOS Extended Open/Create function INT 21h AX=6C00h does take those as two bit fields. Is that older or newer than CreateFile?

      • Kalle Niemitalo

        MS OS/2 apparently has DosOpen and DosOpen2; in both of them, the bit fields of the OpenFlag parameter are identical to what Extended Open/Create takes in MS-DOS 4.

      • Me Gusta

        Almost certainly older than CreateFile, but it depends on whether CreateFile was part of the OS/2 API.

    • Joshua Hudson

      Hey I actually had that phantom sixth disposition come up once. I worked around it by calling CreateFile immediately followed by CloseHandle.

      Your simulation doesn’t work. I needed to know wither it’s ERROR_FILE_EXISTS, ERROR_ALREADY_EXISTS (there’s a directory by that name…), ERROR_FILE_NOT_FOUND or ERROR_PATH_NOT_FOUND.

      • Me Gusta

        FindFirstFile should handle all of those.