authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-23 11:37:11-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-07-23 11:37:11-07:00
logb35874a4292526b3d6ab33b24b8fbd0d1596e216
tree3c4cbab05d69d56d71eb94280acec7959a285d9e
parent1bf16b1723445ba307ca556dc050d6d13bb0ebff
parent21ecb1ba0fabe471476df9ca328c8aa14767af24
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #16499 from squeek502/posix-semantics-2

windows.DeleteFile: Use FileDispositionInformationEx if possible, but fallback if not

2 files changed, 32 insertions(+), 27 deletions(-)

lib/std/fs/test.zig+18-25
......@@ -1416,34 +1416,13 @@ test "File.PermissionsUnix" {
14161416 try testing.expect(!permissions_unix.unixHas(.other, .execute));
14171417}
14181418
1419test "delete a read-only file on windows with file pending semantics" {
1420 if (builtin.os.tag != .windows or builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs1))
1419test "delete a read-only file on windows" {
1420 if (builtin.os.tag != .windows)
14211421 return error.SkipZigTest;
14221422
1423 var tmp = tmpDir(.{});
1423 var tmp = testing.tmpDir(.{});
14241424 defer tmp.cleanup();
1425 {
1426 const file = try tmp.dir.createFile("test_file", .{ .read = true });
1427 defer file.close();
1428 // Create a file and make it read-only
1429 const metadata = try file.metadata();
1430 var permissions = metadata.permissions();
1431 permissions.setReadOnly(true);
1432 try file.setPermissions(permissions);
1433 try testing.expectError(error.AccessDenied, tmp.dir.deleteFile("test_file"));
1434 // Now make the file not read-only
1435 permissions.setReadOnly(false);
1436 try file.setPermissions(permissions);
1437 }
1438 try tmp.dir.deleteFile("test_file");
1439}
1440
1441test "delete a read-only file on windows with posix semantis" {
1442 if (builtin.os.tag != .windows or !builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs1))
1443 return error.SkipZigTest;
14441425
1445 var tmp = tmpDir(.{});
1446 defer tmp.cleanup();
14471426 const file = try tmp.dir.createFile("test_file", .{ .read = true });
14481427 defer file.close();
14491428 // Create a file and make it read-only
......@@ -1451,7 +1430,21 @@ test "delete a read-only file on windows with posix semantis" {
14511430 var permissions = metadata.permissions();
14521431 permissions.setReadOnly(true);
14531432 try file.setPermissions(permissions);
1454 try tmp.dir.deleteFile("test_file"); // file is unmapped and deleted once last handle closed
1433
1434 // If the OS and filesystem support it, POSIX_SEMANTICS and IGNORE_READONLY_ATTRIBUTE
1435 // is used meaning that the deletion of a read-only file will succeed.
1436 // Otherwise, this delete will fail and the read-only flag must be unset before it's
1437 // able to be deleted.
1438 const delete_result = tmp.dir.deleteFile("test_file");
1439 if (delete_result) {
1440 try testing.expectError(error.FileNotFound, tmp.dir.deleteFile("test_file"));
1441 } else |err| {
1442 try testing.expectEqual(@as(anyerror, error.AccessDenied), err);
1443 // Now make the file not read-only
1444 permissions.setReadOnly(false);
1445 try file.setPermissions(permissions);
1446 try tmp.dir.deleteFile("test_file");
1447 }
14551448}
14561449
14571450test "delete a setAsCwd directory on Windows" {
lib/std/os/windows.zig+14-2
......@@ -940,8 +940,13 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
940940 }
941941 defer CloseHandle(tmp_handle);
942942
943 // FileDispositionInformationEx (and therefore FILE_DISPOSITION_POSIX_SEMANTICS and FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE)
944 // are only supported on NTFS filesystems, so the version check on its own is only a partial solution. To support non-NTFS filesystems
945 // like FAT32, we need to fallback to FileDispositionInformation if the usage of FileDispositionInformationEx gives
946 // us INVALID_PARAMETER.
947 var need_fallback = true;
943948 if (comptime builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs1)) {
944 // Deletion with posix semantics.
949 // Deletion with posix semantics if the filesystem supports it.
945950 var info = FILE_DISPOSITION_INFORMATION_EX{
946951 .Flags = FILE_DISPOSITION_DELETE |
947952 FILE_DISPOSITION_POSIX_SEMANTICS |
......@@ -955,7 +960,14 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
955960 @sizeOf(FILE_DISPOSITION_INFORMATION_EX),
956961 .FileDispositionInformationEx,
957962 );
958 } else {
963 switch (rc) {
964 // INVALID_PARAMETER here means that the filesystem does not support FileDispositionInformationEx
965 .INVALID_PARAMETER => {},
966 // For all other statuses, fall down to the switch below to handle them.
967 else => need_fallback = false,
968 }
969 }
970 if (need_fallback) {
959971 // Deletion with file pending semantics, which requires waiting or moving
960972 // files to get them removed (from here).
961973 var file_dispo = FILE_DISPOSITION_INFORMATION{