Skip to content

Commit

Permalink
windows.DeleteFile: Use FileDispositionInformationEx if possible, but…
Browse files Browse the repository at this point in the history
… 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
  • Loading branch information
squeek502 committed Jul 23, 2023
1 parent 1bf16b1 commit 1ae378e
Showing 1 changed file with 14 additions and 2 deletions.
16 changes: 14 additions & 2 deletions lib/std/os/windows.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand All @@ -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{
Expand Down

0 comments on commit 1ae378e

Please sign in to comment.