windows.DeleteFile: Use FileDispositionInformationEx if possible, but fallback if not

Using FileDispositionInformationEx (and therefore flags like FILE_DISPOSITION_POSIX_SEMANTICS and FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE) is only supported on NTFS, so the comptime Windows version range check is not enough to determine whether or not the NtSetInformationFile will succeed.

This commit makes DeleteFile always try using FileDispositionInformationEx first, but if INVALID_PARAMETER is received (which is the status that occurs when the filesystem doesn't support FileDispositionInformationEx), then it will fallback and try calling NtSetInformationFile with FileDispositionInformation.

This keeps NTFS as fast as it was before, since it will do at most 1 NtSetInformationFile call, but on non-NTFS filesystems (e.g. FAT32), DeleteFile may need to do 2 NtSetInformationFile calls.

Closes #16497
This commit is contained in:
Ryan Liptak 2023-07-22 23:27:11 -07:00
parent 1bf16b1723
commit 1ae378e7a2

View File

@ -940,8 +940,13 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
}
defer CloseHandle(tmp_handle);
// FileDispositionInformationEx (and therefore FILE_DISPOSITION_POSIX_SEMANTICS and FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE)
// are only supported on NTFS filesystems, so the version check on its own is only a partial solution. To support non-NTFS filesystems
// like FAT32, we need to fallback to FileDispositionInformation if the usage of FileDispositionInformationEx gives
// us INVALID_PARAMETER.
var need_fallback = true;
if (comptime builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs1)) {
// Deletion with posix semantics.
// Deletion with posix semantics if the filesystem supports it.
var info = FILE_DISPOSITION_INFORMATION_EX{
.Flags = FILE_DISPOSITION_DELETE |
FILE_DISPOSITION_POSIX_SEMANTICS |
@ -955,7 +960,14 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
@sizeOf(FILE_DISPOSITION_INFORMATION_EX),
.FileDispositionInformationEx,
);
} else {
switch (rc) {
// INVALID_PARAMETER here means that the filesystem does not support FileDispositionInformationEx
.INVALID_PARAMETER => {},
// For all other statuses, fall down to the switch below to handle them.
else => need_fallback = false,
}
}
if (need_fallback) {
// Deletion with file pending semantics, which requires waiting or moving
// files to get them removed (from here).
var file_dispo = FILE_DISPOSITION_INFORMATION{