| author | |
| committer | |
| log | 7594d2c0977497c81db0c394f775832689bad492 |
| tree | b1088f40e4272f1da6633f9cd01b02948b3941ab |
| parent | be50dbf1ce03f5dc5deef86882ab3505363b683a |
2 files changed, 38 insertions(+), 22 deletions(-)
lib/std/fs/test.zig+27-8| ... | @@ -1416,23 +1416,42 @@ test "File.PermissionsUnix" { | ... | @@ -1416,23 +1416,42 @@ test "File.PermissionsUnix" { |
| 1416 | try testing.expect(!permissions_unix.unixHas(.other, .execute)); | 1416 | try testing.expect(!permissions_unix.unixHas(.other, .execute)); |
| 1417 | } | 1417 | } |
| 1418 | 1418 | ||
| 1419 | test "delete a read-only file on windows" { | 1419 | test "delete a read-only file on windows with file pending semantics" { |
| 1420 | if (builtin.os.tag != .windows) return error.SkipZigTest; | 1420 | if (builtin.os.tag != .windows or builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs1)) |
| 1421 | return error.SkipZigTest; | ||
| 1422 | |||
| 1423 | var tmp = tmpDir(.{}); | ||
| 1424 | 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 | |||
| 1441 | test "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; | ||
| 1421 | 1444 | ||
| 1422 | var tmp = tmpDir(.{}); | 1445 | var tmp = tmpDir(.{}); |
| 1423 | defer tmp.cleanup(); | 1446 | defer tmp.cleanup(); |
| 1424 | const file = try tmp.dir.createFile("test_file", .{ .read = true }); | 1447 | const file = try tmp.dir.createFile("test_file", .{ .read = true }); |
| 1448 | defer file.close(); | ||
| 1425 | // Create a file and make it read-only | 1449 | // Create a file and make it read-only |
| 1426 | const metadata = try file.metadata(); | 1450 | const metadata = try file.metadata(); |
| 1427 | var permissions = metadata.permissions(); | 1451 | var permissions = metadata.permissions(); |
| 1428 | permissions.setReadOnly(true); | 1452 | permissions.setReadOnly(true); |
| 1429 | try file.setPermissions(permissions); | 1453 | try file.setPermissions(permissions); |
| 1430 | try testing.expectError(error.AccessDenied, tmp.dir.deleteFile("test_file")); | 1454 | try tmp.dir.deleteFile("test_file"); // file is unmapped and deleted once last handle closed |
| 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 | } | 1455 | } |
| 1437 | 1456 | ||
| 1438 | test "delete a setAsCwd directory on Windows" { | 1457 | test "delete a setAsCwd directory on Windows" { |
lib/std/os/windows.zig+11-14| ... | @@ -938,6 +938,7 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil | ... | @@ -938,6 +938,7 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil |
| 938 | else => return unexpectedStatus(rc), | 938 | else => return unexpectedStatus(rc), |
| 939 | } | 939 | } |
| 940 | defer CloseHandle(tmp_handle); | 940 | defer CloseHandle(tmp_handle); |
| 941 | |||
| 941 | if (comptime builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs1)) { | 942 | if (comptime builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs1)) { |
| 942 | // Deletion with posix semantics. | 943 | // Deletion with posix semantics. |
| 943 | var info = FILE_DISPOSITION_INFORMATION_EX{ | 944 | var info = FILE_DISPOSITION_INFORMATION_EX{ |
| ... | @@ -953,17 +954,13 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil | ... | @@ -953,17 +954,13 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil |
| 953 | @sizeOf(FILE_DISPOSITION_INFORMATION_EX), | 954 | @sizeOf(FILE_DISPOSITION_INFORMATION_EX), |
| 954 | .FileDispositionInformationEx, | 955 | .FileDispositionInformationEx, |
| 955 | ); | 956 | ); |
| 956 | switch (rc) { | ||
| 957 | .SUCCESS => {}, | ||
| 958 | .CANNOT_DELETE => return error.FileBusy, // file is currently mapped | ||
| 959 | else => return unexpectedStatus(rc), | ||
| 960 | } | ||
| 961 | } else { | 957 | } else { |
| 962 | // Deletion with file pending semantics, which requires waiting or moving | 958 | // Deletion with file pending semantics, which requires waiting or moving |
| 963 | // files to get them removed (from here). | 959 | // files to get them removed (from here). |
| 964 | var file_dispo = FILE_DISPOSITION_INFORMATION{ | 960 | var file_dispo = FILE_DISPOSITION_INFORMATION{ |
| 965 | .DeleteFile = TRUE, | 961 | .DeleteFile = TRUE, |
| 966 | }; | 962 | }; |
| 963 | |||
| 967 | rc = ntdll.NtSetInformationFile( | 964 | rc = ntdll.NtSetInformationFile( |
| 968 | tmp_handle, | 965 | tmp_handle, |
| 969 | &io, | 966 | &io, |
| ... | @@ -971,15 +968,15 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil | ... | @@ -971,15 +968,15 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil |
| 971 | @sizeOf(FILE_DISPOSITION_INFORMATION), | 968 | @sizeOf(FILE_DISPOSITION_INFORMATION), |
| 972 | .FileDispositionInformation, | 969 | .FileDispositionInformation, |
| 973 | ); | 970 | ); |
| 974 | switch (rc) { | 971 | } |
| 975 | .SUCCESS => {}, | 972 | switch (rc) { |
| 976 | .DIRECTORY_NOT_EMPTY => return error.DirNotEmpty, | 973 | .SUCCESS => {}, |
| 977 | .INVALID_PARAMETER => unreachable, | 974 | .DIRECTORY_NOT_EMPTY => return error.DirNotEmpty, |
| 978 | .CANNOT_DELETE => return error.AccessDenied, | 975 | .INVALID_PARAMETER => unreachable, |
| 979 | .MEDIA_WRITE_PROTECTED => return error.AccessDenied, | 976 | .CANNOT_DELETE => return error.AccessDenied, |
| 980 | .ACCESS_DENIED => return error.AccessDenied, | 977 | .MEDIA_WRITE_PROTECTED => return error.AccessDenied, |
| 981 | else => return unexpectedStatus(rc), | 978 | .ACCESS_DENIED => return error.AccessDenied, |
| 982 | } | 979 | else => return unexpectedStatus(rc), |
| 983 | } | 980 | } |
| 984 | } | 981 | } |
| 985 | 982 |