authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-04-20 16:30:27-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-04-20 16:30:27-07:00
loga86759984c734d34a36bccda73baf60b19f1a633
tree5c3b7434f8d03fee85e18a3a705802cf48fa99f2
parent8674418454e4d530303aecceee5f86c725a150cf
parent8c79559748b9828d2ad6a5bff89db4da0283d6b2
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #15316 from xEgoist/fileDisposition

windows: use NtSetInformationFile in DeleteFile.

2 files changed, 49 insertions(+), 7 deletions(-)

lib/std/fs/test.zig+20-4
......@@ -488,10 +488,7 @@ test "deleteDir" {
488488 dir.close();
489489
490490 // deleting a non-empty directory
491 // TODO: Re-enable this check on Windows, see https://github.com/ziglang/zig/issues/5537
492 if (builtin.os.tag != .windows) {
493 try testing.expectError(error.DirNotEmpty, tmp_dir.dir.deleteDir("test_dir"));
494 }
491 try testing.expectError(error.DirNotEmpty, tmp_dir.dir.deleteDir("test_dir"));
495492
496493 dir = try tmp_dir.dir.openDir("test_dir", .{});
497494 try dir.deleteFile("test_file");
......@@ -1418,3 +1415,22 @@ test "File.PermissionsUnix" {
14181415 try testing.expect(permissions_unix.unixHas(.user, .execute));
14191416 try testing.expect(!permissions_unix.unixHas(.other, .execute));
14201417}
1418
1419test "delete a read-only file on windows" {
1420 if (builtin.os.tag != .windows) return error.SkipZigTest;
1421
1422 var tmp = tmpDir(.{});
1423 defer tmp.cleanup();
1424 const file = try tmp.dir.createFile("test_file", .{ .read = true });
1425 // Create a file and make it read-only
1426 const metadata = try file.metadata();
1427 var permissions = metadata.permissions();
1428 permissions.setReadOnly(true);
1429 try file.setPermissions(permissions);
1430 try testing.expectError(error.AccessDenied, tmp.dir.deleteFile("test_file"));
1431 // Now make the file not read-only
1432 permissions.setReadOnly(false);
1433 try file.setPermissions(permissions);
1434 file.close();
1435 try tmp.dir.deleteFile("test_file");
1436}
lib/std/os/windows.zig+29-3
......@@ -870,6 +870,7 @@ pub const DeleteFileError = error{
870870 Unexpected,
871871 NotDir,
872872 IsDir,
873 DirNotEmpty,
873874};
874875
875876pub const DeleteFileOptions = struct {
......@@ -879,9 +880,9 @@ pub const DeleteFileOptions = struct {
879880
880881pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFileError!void {
881882 const create_options_flags: ULONG = if (options.remove_dir)
882 FILE_DELETE_ON_CLOSE | FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT
883 FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT
883884 else
884 FILE_DELETE_ON_CLOSE | FILE_NON_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT; // would we ever want to delete the target instead?
885 FILE_NON_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT; // would we ever want to delete the target instead?
885886
886887 const path_len_bytes = @intCast(u16, sub_path_w.len * 2);
887888 var nt_name = UNICODE_STRING{
......@@ -924,7 +925,7 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
924925 0,
925926 );
926927 switch (rc) {
927 .SUCCESS => return CloseHandle(tmp_handle),
928 .SUCCESS => {},
928929 .OBJECT_NAME_INVALID => unreachable,
929930 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
930931 .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
......@@ -932,7 +933,28 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
932933 .FILE_IS_A_DIRECTORY => return error.IsDir,
933934 .NOT_A_DIRECTORY => return error.NotDir,
934935 .SHARING_VIOLATION => return error.FileBusy,
936 .ACCESS_DENIED => return error.AccessDenied,
937 .DELETE_PENDING => return,
938 else => return unexpectedStatus(rc),
939 }
940 var file_dispo = FILE_DISPOSITION_INFORMATION{
941 .DeleteFile = TRUE,
942 };
943 rc = ntdll.NtSetInformationFile(
944 tmp_handle,
945 &io,
946 &file_dispo,
947 @sizeOf(FILE_DISPOSITION_INFORMATION),
948 .FileDispositionInformation,
949 );
950 CloseHandle(tmp_handle);
951 switch (rc) {
952 .SUCCESS => return,
953 .DIRECTORY_NOT_EMPTY => return error.DirNotEmpty,
954 .INVALID_PARAMETER => unreachable,
935955 .CANNOT_DELETE => return error.AccessDenied,
956 .MEDIA_WRITE_PROTECTED => return error.AccessDenied,
957 .ACCESS_DENIED => return error.AccessDenied,
936958 else => return unexpectedStatus(rc),
937959 }
938960}
......@@ -2470,6 +2492,10 @@ pub const FILE_INFORMATION_CLASS = enum(c_int) {
24702492 FileMaximumInformation,
24712493};
24722494
2495pub const FILE_DISPOSITION_INFORMATION = extern struct {
2496 DeleteFile: BOOLEAN,
2497};
2498
24732499pub const FILE_FS_DEVICE_INFORMATION = extern struct {
24742500 DeviceType: DEVICE_TYPE,
24752501 Characteristics: ULONG,