DeleteFile and RemoveDirectory, “delete” the file/directory by setting FILE_DISPOSITION_INFORMATION.DeleteFile to 1. This is done by calling NtSetInformationFile with FILE_INFORMATION_CLASS parameter set to FileDispositionInformation. This marks the file/directory for deletion and the file gets deleted after last handle is closed. This is very important and easy to overlook. DeleteFile success does not mean that file is deleted from the file system5 6.
A file deletion typically means (a) operating on the parent directory and removing the entry for the file in the directory (b) releasing the clusters used by the file into free space available. The latter can only happen after the hard link count goes to zero.
DeleteFile/RemoveDirectory do not delete reparse point/symbolic link targets7. You have to use option 3 for achieving that.
So then what is NtDeleteFile for if it is not used by DeleteFile ? Hmm… Perhaps another post is in order here ?
1 empty directory or a junction to an empty/non-empty directory
2 DeleteFile calls NtOpenFile in Vista like thus –
ntStat = NtOpenFile (&FileHandle, //FileHandle DELETE|FILE_READ_ATTRIBUTES //DesiredAccess &oa, //ObjectAttributes &iosb,//IoStatusBlock FILE_SHARE_READ| FILE_SHARE_WRITE| FILE_SHARE_DELETE,//ShareAccess FILE_OPEN_REPARSE_POINT| FILE_OPEN_FOR_BACKUP_INTENT| FILE_NON_DIRECTORY_FILE);//OpenOptions
3 RemoveDirectory opens the directory in Vista like thus –
ntStat = NtOpenFile (&FileHandle, //FileHandle SYNCHRONIZE|DELETE|FILE_READ_ATTRIBUTES //DesiredAccess &oa, //ObjectAttributes &iosb,//IoStatusBlock FILE_SHARE_READ| FILE_SHARE_WRITE| FILE_SHARE_DELETE,//ShareAccess FILE_OPEN_REPARSE_POINT| FILE_OPEN_FOR_BACKUP_INTENT| FILE_SYNCHRONOUS_IO_NONALERT| FILE_DIRECTORY_FILE);//OpenOptions
4which makes a little bit more sense than ERROR_ACCESS_DENIED from DeleteFile.
5Directories that have files cannot be deleted. Therefore if software is removing a directory and its sub-directories recursively, based on the assumption that DeleteFile takes immediate effect, there may be directory removal errors because they are not empty yet. This makes it tricky to delete a directory recursively.
6In fact documentation suggests (which I have not verified) that fresh creates on a file marked for delete – may succeed as long as FILE_SHARE_DELETE flag is passed.
7That is because FILE_OPEN_REPARSE_POINT flag suppresses reparse point processing when opening the file via NtOpenFile.
- 1 2