The FILE_FLAG_DELETE_ON_CLOSE flag applies to the handle, also known as the file object, which is not the same as the file


A customer was having trouble with the FILE_FLAG_DELETE_ON_CLOSE flag. "We create a file that we want to be deleted automatically when we're finished with it. Whenever we open the file, we ask for GENERIC_READ | GENERIC_WRITE, and we allow all sharing (including FILE_SHARE_DELETE), and we pass FILE_FLAG_DELETE_ON_CLOSE. We can open the file multiple times in this manner, but as soon as we close any of the handles, we can't open any new ones."

Yup, that's right.

The FILE_FLAG_DELETE_ON_CLOSE flag means that the file will be deleted when the last handle to the file object is closed. This is not the same as closing the last handle to the file, however. Each call to Create­File creates a new file object. You can create multiple handles to the same file object by calling Duplicate­Handle. (We saw this when we discussed the effect of handle duplication on the file pointer.)

When the last handle to a file object is closed, the file object deletes the underlying file. Existing file objects will still refer to the file, but no new ones are allowed. When there are no more file objects, then the directory entry is removed. (Removing the directory entry is what most people think of when they talk about "deleting a file", but it's actually just the last step in the process.)

Going back to the customer's problem: It looks like they really want the file to remain valid (including allowing further Create­File calls to succeed) for as long as any open handle continues to refer to the file. Fortunately, the customer needed the handle only to create a memory-mapped view. The file pointer was not important. Therefore, the customer could use Duplicate­Handle instead of Create­File to get additional handles to the file. Since all of the handles refer to the same file object, the file object will not delete the file until all of the handles are closed.

Comments (11)
  1. Karellen says:

    The problem appears to be the extra level of indirection between the handle and the file, which most people probably don't include in their mental model. Even for those that know about the existence of file objects, the objects may not (normally) be present when they try to reason about their code.

    "It looks like they really want the file to remain valid (including allowing further Create­File calls to succeed) for as long as any open handle continues to refer to the file."

    It looks like you've skipped a level of indirection there, helping to perpetuate the incorrect model that handles refer to files. Shouldn't that be "It looks like they really want the file to remain valid for as long as any open handle continues to refer to a file object that refers to the file."?

    Maybe we should try solving the problem with another level of indirection? :-)

    1. Neil says:

      > Maybe we should try solving the problem with another level of indirection? :-)

      Either that or a FILE_FLAG_DELETE_ON_LAST_CLOSE_MEANWHILE_ALLOWING_ADDITIONAL_OPENS flag.

  2. kantos says:

    it appears your cross post link is dead

    1. EMB says:

      As is the link "Archives" on the right below the book image and the "Basics" inscription. So use the links Archives below looking for the date and the number of the post in the link. In this case "2014/07/11/10541475.aspx"

  3. Cesar says:

    Let's see if I understood this correctly: as soon as the first object with FILE_FLAG_DELETE_ON_CLOSE is closed, the file is *still* visible in the directory (that is, FindFirstFile/FindNextFile can still see it), but opening it fails with a mysterious error? No wonder the programmer got confused; their mental model was probably "as long as it's still in the directory, it can be opened (if the ACLs allow, of course)".

    Contrast with the equivalent trick on Unix (open the file followed by unlinking it from the directory, that is, an open()/unlink() pair), in which the file immediately disappears from the directory. That leads to a better mental model ("as soon as it's gone from the directory, I can't open it anymore; before that, I can still open it"), which in turn leads the programmer to the correct solution (duplicate the handle you have, since you can't get a new one from open()).

    My guess would be that Win32's behavior is yet another leftover from the FAT filesystem, which doesn't have the directory entry/inode distinction or equivalent (the Unix way removes the directory entry immediately on unlink() but keeps the inode until the last open handle to the file is closed).

  4. Joshua says:

    This bit me once long ago, and took a rather herculean effort to overcome. We were using FILE_FLAG_DELETE_ON_CLOSE to ensure temp files go away, and one of them needed to be passed to another program. Guess what happened if that program passed the file name to yet another program?

    One of these days it's going to be in a place hard to fix. Maybe the model itself needs to be changed. As Cesar says, it's completely non-intuitive; and in this case it's pretty obviously wrong. FILE_SHARE_DELETE really should allow opening these files until they're actually gone.

  5. > When there are no more file objects, then the directory entry is removed

    so if the file object were removed, but not the directory entry... how would that be handled by Explorer? same as a corrupt file, automatically deleted silently, or something else?

    1. Darran Rowe says:

      If the final file object was deleted and the directory entry wasn't removed, then I would say you have much more to worry about.
      The way the delete on close flag works is that as soon as you use CloseHandle to close the file, it will try to delete the file. If there are other open handles to the file then instead of actually deleting the file, it will mark it as delete pending in the file system.
      So when you close the last handle, which in turn deletes the last file object, the file system driver should then check the file to see if it has been set to be deleted, and then finally delete the file from the file system.
      The only way for this not to function properly is if you are having driver or hardware issues.

      1. skSdnW says:

        There is one more thing to keep in mind. The NT API has a delete pending flag you can turn on and off on a handle and this flag is not stored in the same place as the win32 delete on close flag...

        1. sense says:

          "delete on close" is not a win32 flag, it is a nt kernel feature.
          But I've not heard about the "delete pending" flag (with on/off feature) you describe. Can you elaborate?

          1. skSdnW says:

            FILE_FLAG_DELETE_ON_CLOSE is a documented parameter for a documented function that is part of the Win32 API so I'll consider it to be a Win32 thing even though it does not work on Win9x. Where the flag is actually stored in memory is an implementation detail.

            The other flag was only accessible by one of the undocumented Nt* functions in the old days but now we have SetFileInformationByHandle, a documented thin layer on top of some of the NT stuff.

            There is an old thread somewhere on the OSR mailing list that talks about how to undo both of these flags in a kernel driver...

Comments are closed.

Skip to main content