Merge pull request #15501 from matu3ba/win_rmwithposix

std.windows: use posix semantics to delete files, if available
This commit is contained in:
Andrew Kelley 2023-06-17 14:21:15 -07:00 committed by GitHub
commit e3736baddb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 72 additions and 20 deletions

View File

@ -1416,23 +1416,42 @@ test "File.PermissionsUnix" {
try testing.expect(!permissions_unix.unixHas(.other, .execute));
}
test "delete a read-only file on windows" {
if (builtin.os.tag != .windows) return error.SkipZigTest;
test "delete a read-only file on windows with file pending semantics" {
if (builtin.os.tag != .windows or builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs1))
return error.SkipZigTest;
var tmp = tmpDir(.{});
defer tmp.cleanup();
{
const file = try tmp.dir.createFile("test_file", .{ .read = true });
defer file.close();
// Create a file and make it read-only
const metadata = try file.metadata();
var permissions = metadata.permissions();
permissions.setReadOnly(true);
try file.setPermissions(permissions);
try testing.expectError(error.AccessDenied, tmp.dir.deleteFile("test_file"));
// Now make the file not read-only
permissions.setReadOnly(false);
try file.setPermissions(permissions);
}
try tmp.dir.deleteFile("test_file");
}
test "delete a read-only file on windows with posix semantis" {
if (builtin.os.tag != .windows or !builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs1))
return error.SkipZigTest;
var tmp = tmpDir(.{});
defer tmp.cleanup();
const file = try tmp.dir.createFile("test_file", .{ .read = true });
defer file.close();
// Create a file and make it read-only
const metadata = try file.metadata();
var permissions = metadata.permissions();
permissions.setReadOnly(true);
try file.setPermissions(permissions);
try testing.expectError(error.AccessDenied, tmp.dir.deleteFile("test_file"));
// Now make the file not read-only
permissions.setReadOnly(false);
try file.setPermissions(permissions);
file.close();
try tmp.dir.deleteFile("test_file");
try tmp.dir.deleteFile("test_file"); // file is unmapped and deleted once last handle closed
}
test "delete a setAsCwd directory on Windows" {

View File

@ -937,19 +937,40 @@ 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);
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_IGNORE_READONLY_ATTRIBUTE,
};
rc = ntdll.NtSetInformationFile(
tmp_handle,
&io,
&info,
@sizeOf(FILE_DISPOSITION_INFORMATION_EX),
.FileDispositionInformationEx,
);
} 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 => return,
.SUCCESS => {},
.DIRECTORY_NOT_EMPTY => return error.DirNotEmpty,
.INVALID_PARAMETER => unreachable,
.CANNOT_DELETE => return error.AccessDenied,
@ -2574,6 +2595,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,