commit e3736baddb8ecff90f0594be9f604c7484ce9aa2 (tree)
parent 8d0a8c28596985b1a308160b2f1b84df2b3a8a8b
Author: Andrew Kelley <andrew@ziglang.org>
Date: Sat, 17 Jun 2023 14:21:15 -0700
Merge pull request #15501 from matu3ba/win_rmwithposix
std.windows: use posix semantics to delete files, if available
Diffstat:
2 files changed, 72 insertions(+), 20 deletions(-)
diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig
@@ -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" {
diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig
@@ -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,