std.windows: use posix semantics to delete files, if available

Justification: When a file is deleted on Windows, it may not be
immediately removed from the directory. This can cause problems
with future scans of that directory, which will see the partially
deleted file. Under some workloads and system configurations,
Windows files may appear to be deleted immediately.

This is the PR with requested fixup. Thanks to @SpexGuy for the
original PR.
This commit is contained in:
Martin Wickham 2022-06-04 17:34:21 -05:00 committed by Jan Philipp Hafer
parent e963793e37
commit 0f0f005e92

View File

@ -937,25 +937,50 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
.DELETE_PENDING => return,
else => return unexpectedStatus(rc),
}
var file_dispo = FILE_DISPOSITION_INFORMATION{
.DeleteFile = TRUE,
};
rc = ntdll.NtSetInformationFile(
tmp_handle,
&io,
&file_dispo,
@sizeOf(FILE_DISPOSITION_INFORMATION),
.FileDispositionInformation,
);
CloseHandle(tmp_handle);
switch (rc) {
.SUCCESS => return,
.DIRECTORY_NOT_EMPTY => return error.DirNotEmpty,
.INVALID_PARAMETER => unreachable,
.CANNOT_DELETE => return error.AccessDenied,
.MEDIA_WRITE_PROTECTED => return error.AccessDenied,
.ACCESS_DENIED => return error.AccessDenied,
else => return unexpectedStatus(rc),
defer CloseHandle(tmp_handle);
if (comptime builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs1)) {
// Deletion with posix semantics.
var info = FILE_DISPOSITION_INFORMATION_EX{
.Flags = FILE_DISPOSITION_DELETE |
FILE_DISPOSITION_POSIX_SEMANTICS |
FILE_DISPOSITION_ON_CLOSE |
FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE,
};
rc = ntdll.NtSetInformationFile(
tmp_handle,
&io,
&info,
@sizeOf(FILE_DISPOSITION_INFORMATION_EX),
.FileDispositionInformationEx,
);
switch (rc) {
.SUCCESS => {},
.CANNOT_DELETE => return error.FileBusy, // file is currently mapped
else => return unexpectedStatus(rc),
}
} else {
// Deletion with file pending semantics, which requires waiting or moving
// files to get them removed (from here).
var file_dispo = FILE_DISPOSITION_INFORMATION{
.DeleteFile = TRUE,
};
rc = ntdll.NtSetInformationFile(
tmp_handle,
&io,
&file_dispo,
@sizeOf(FILE_DISPOSITION_INFORMATION),
.FileDispositionInformation,
);
switch (rc) {
.SUCCESS => {},
.DIRECTORY_NOT_EMPTY => return error.DirNotEmpty,
.INVALID_PARAMETER => unreachable,
.CANNOT_DELETE => return error.AccessDenied,
.MEDIA_WRITE_PROTECTED => return error.AccessDenied,
.ACCESS_DENIED => return error.AccessDenied,
else => return unexpectedStatus(rc),
}
}
}
@ -2397,6 +2422,18 @@ pub const FILE_NAME_INFORMATION = extern struct {
FileName: [1]WCHAR,
};
pub const FILE_DISPOSITION_INFORMATION_EX = extern struct {
/// combination of FILE_DISPOSITION_* flags
Flags: ULONG,
};
const FILE_DISPOSITION_DO_NOT_DELETE: ULONG = 0x00000000;
const FILE_DISPOSITION_DELETE: ULONG = 0x00000001;
const FILE_DISPOSITION_POSIX_SEMANTICS: ULONG = 0x00000002;
const FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK: ULONG = 0x00000004;
const FILE_DISPOSITION_ON_CLOSE: ULONG = 0x00000008;
const FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE: ULONG = 0x00000010;
pub const FILE_RENAME_INFORMATION = extern struct {
ReplaceIfExists: BOOLEAN,
RootDirectory: ?HANDLE,