Boost C++ Libraries Home Libraries People FAQ More


I thought on Windows it is impossible to delete a file which is still open for use. How does AFIO achieve this?

On POSIX you are allowed to call unlink() on a file which is open for use — indeed this is a very convenient way of creating an anonymous private temporary file whose storage will be deallocated on the last file handle close. Ordinarily Windows does not permit deletion or renaming of files still in use, but if all open handles to that file were opened with FILE_SHARE_DELETE then it can permit renames and deletions of open files.

There are however some gotchas with this, and it is worth listing them here. Firstly, Windows never allows you to really delete an open file, rather it is flagged as delete pending and its entry in its directory remains visible (though no new file handles may be opened to it) and when the very last open handle to the file in the system is closed, only then is it truly deleted. Well, actually only sort of truly deleted, because Windows only appears to remove the file entry from the directory, but in fact that entry is merely hidden and actually still exists and attempting to create a file with the same name will return an access denied error. How long it silently exists for depends on a range of factors, but put it this way: if your code loops creating and deleting the same file name as you might when operating a lock file, you're going to see lots of random spurious access denied errors and truly dismal lock file performance compared to POSIX.

Note that this lazy file deletion is different from file tunnelling whereby a file created with the same name as a recently deleted file silently inherits its creation time and other metadata. I mention this because this feature also gets in the way of POSIX file semantics, but for other reasons.

AFIO works around these un-POSIX file semantics by taking a dual step to deleting files. Firstly, it renames the file to a 128 bit cryptographically strong random name prefixed by .afiod into as high up the directory hierarchy as it is able to, and only then does it request the deletion of the file. As AFIO always opens files with FILE_SHARE_DELETE permission enabled, with that flag Windows permits renaming and deletion, and because the name was changed to a very random name somewhere not in its origin directory before deletion, you don't see those unexpected and random errors when creating files with the same name as a recently deleted file as you do anywhere else on Windows. Because the file is probably not in its original containing directory any more, deletions of that directory will not fail with directory not empty as they otherwise normally would and indeed do in most Windows programs. Handy eh?

Unfortunately, there are additional problems with deleting directories caused by AFIO's caching of directory handles in a central table — this happens by default for all directories opened without write permissions and without the file_flags::unique_directory_handle flag. Explicit close handle requests for these cached directories are ignored by AFIO, and therefore AFIO may hold into existence a directory longer than might otherwise be anticipated with the only way of forcing actual deletion being the destruction of any reference to that directory, something difficult to achieve in larger more complex codebases. Nevertheless, as it is the system which does the deletion, you are guaranteed by Windows that the directory will eventually be cleaned up some day, possibly in weeks or months on a long lived system. If you don't want this, open directories with write permissions or the unique directory handle flag.