| author | |
| committer | |
| log | 07c1dd3d1d6c9a1c4fec931621dfd93328bad1e4 |
| tree | 6d3365d931b58a4335e30d6be31e478153634e67 |
| parent | a23ab331a28d865e3ea636c9033db4de345f8653 |
Encountered in a recent CI run on an aarch64-windows dev kit.
Pretty sure I disabled the virus scanner but it looks like it turned
itself back on with a Windows Update.
Rather than marking the new error code as unreachable in the places
where it is unexpected, this commit makes it return `error.Unexpected`.6 files changed, 88 insertions(+), 48 deletions(-)
lib/std/child_process.zig+8-7| ... | ... | @@ -668,13 +668,14 @@ pub const ChildProcess = struct { |
| 668 | 668 | .sa = &saAttr, |
| 669 | 669 | .creation = windows.OPEN_EXISTING, |
| 670 | 670 | }) catch |err| switch (err) { |
| 671 | error.PathAlreadyExists => unreachable, // not possible for "NUL" | |
| 672 | error.PipeBusy => unreachable, // not possible for "NUL" | |
| 673 | error.FileNotFound => unreachable, // not possible for "NUL" | |
| 674 | error.AccessDenied => unreachable, // not possible for "NUL" | |
| 675 | error.NameTooLong => unreachable, // not possible for "NUL" | |
| 676 | error.WouldBlock => unreachable, // not possible for "NUL" | |
| 677 | error.NetworkNotFound => unreachable, // not possible for "NUL" | |
| 671 | error.PathAlreadyExists => return error.Unexpected, // not possible for "NUL" | |
| 672 | error.PipeBusy => return error.Unexpected, // not possible for "NUL" | |
| 673 | error.FileNotFound => return error.Unexpected, // not possible for "NUL" | |
| 674 | error.AccessDenied => return error.Unexpected, // not possible for "NUL" | |
| 675 | error.NameTooLong => return error.Unexpected, // not possible for "NUL" | |
| 676 | error.WouldBlock => return error.Unexpected, // not possible for "NUL" | |
| 677 | error.NetworkNotFound => return error.Unexpected, // not possible for "NUL" | |
| 678 | error.AntivirusInterference => return error.Unexpected, // not possible for "NUL" | |
| 678 | 679 | else => |e| return e, |
| 679 | 680 | } |
| 680 | 681 | else |
lib/std/fs/Dir.zig+27-19| ... | ... | @@ -1179,6 +1179,8 @@ pub fn makeOpenPath(self: Dir, sub_path: []const u8, open_dir_options: OpenDirOp |
| 1179 | 1179 | }; |
| 1180 | 1180 | } |
| 1181 | 1181 | |
| 1182 | pub const RealPathError = posix.RealPathError; | |
| 1183 | ||
| 1182 | 1184 | /// This function returns the canonicalized absolute pathname of |
| 1183 | 1185 | /// `pathname` relative to this `Dir`. If `pathname` is absolute, ignores this |
| 1184 | 1186 | /// `Dir` handle and returns the canonicalized absolute pathname of `pathname` |
| ... | ... | @@ -1186,7 +1188,7 @@ pub fn makeOpenPath(self: Dir, sub_path: []const u8, open_dir_options: OpenDirOp |
| 1186 | 1188 | /// This function is not universally supported by all platforms. |
| 1187 | 1189 | /// Currently supported hosts are: Linux, macOS, and Windows. |
| 1188 | 1190 | /// See also `Dir.realpathZ`, `Dir.realpathW`, and `Dir.realpathAlloc`. |
| 1189 | pub fn realpath(self: Dir, pathname: []const u8, out_buffer: []u8) ![]u8 { | |
| 1191 | pub fn realpath(self: Dir, pathname: []const u8, out_buffer: []u8) RealPathError![]u8 { | |
| 1190 | 1192 | if (builtin.os.tag == .wasi) { |
| 1191 | 1193 | @compileError("realpath is not available on WASI"); |
| 1192 | 1194 | } |
| ... | ... | @@ -1200,7 +1202,7 @@ pub fn realpath(self: Dir, pathname: []const u8, out_buffer: []u8) ![]u8 { |
| 1200 | 1202 | |
| 1201 | 1203 | /// Same as `Dir.realpath` except `pathname` is null-terminated. |
| 1202 | 1204 | /// See also `Dir.realpath`, `realpathZ`. |
| 1203 | pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) ![]u8 { | |
| 1205 | pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) RealPathError![]u8 { | |
| 1204 | 1206 | if (builtin.os.tag == .windows) { |
| 1205 | 1207 | const pathname_w = try posix.windows.cStrToPrefixedFileW(self.fd, pathname); |
| 1206 | 1208 | return self.realpathW(pathname_w.span(), out_buffer); |
| ... | ... | @@ -1219,7 +1221,9 @@ pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) ![]u8 { |
| 1219 | 1221 | }; |
| 1220 | 1222 | |
| 1221 | 1223 | const fd = posix.openatZ(self.fd, pathname, flags, 0) catch |err| switch (err) { |
| 1222 | error.FileLocksNotSupported => unreachable, | |
| 1224 | error.FileLocksNotSupported => return error.Unexpected, | |
| 1225 | error.FileBusy => return error.Unexpected, | |
| 1226 | error.WouldBlock => return error.Unexpected, | |
| 1223 | 1227 | else => |e| return e, |
| 1224 | 1228 | }; |
| 1225 | 1229 | defer posix.close(fd); |
| ... | ... | @@ -1244,7 +1248,7 @@ pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) ![]u8 { |
| 1244 | 1248 | |
| 1245 | 1249 | /// Windows-only. Same as `Dir.realpath` except `pathname` is WTF16 encoded. |
| 1246 | 1250 | /// See also `Dir.realpath`, `realpathW`. |
| 1247 | pub fn realpathW(self: Dir, pathname: []const u16, out_buffer: []u8) ![]u8 { | |
| 1251 | pub fn realpathW(self: Dir, pathname: []const u16, out_buffer: []u8) RealPathError![]u8 { | |
| 1248 | 1252 | const w = std.os.windows; |
| 1249 | 1253 | |
| 1250 | 1254 | const access_mask = w.GENERIC_READ | w.SYNCHRONIZE; |
| ... | ... | @@ -1265,27 +1269,31 @@ pub fn realpathW(self: Dir, pathname: []const u16, out_buffer: []u8) ![]u8 { |
| 1265 | 1269 | }; |
| 1266 | 1270 | defer w.CloseHandle(h_file); |
| 1267 | 1271 | |
| 1268 | // Use of MAX_PATH_BYTES here is valid as the realpath function does not | |
| 1269 | // have a variant that takes an arbitrary-size buffer. | |
| 1270 | // TODO(#4812): Consider reimplementing realpath or using the POSIX.1-2008 | |
| 1271 | // NULL out parameter (GNU's canonicalize_file_name) to handle overelong | |
| 1272 | // paths. musl supports passing NULL but restricts the output to PATH_MAX | |
| 1273 | // anyway. | |
| 1274 | var buffer: [fs.MAX_PATH_BYTES]u8 = undefined; | |
| 1275 | const out_path = try posix.getFdPath(h_file, &buffer); | |
| 1276 | ||
| 1277 | if (out_path.len > out_buffer.len) { | |
| 1272 | var wide_buf: [w.PATH_MAX_WIDE]u16 = undefined; | |
| 1273 | const wide_slice = try w.GetFinalPathNameByHandle(h_file, .{}, &wide_buf); | |
| 1274 | var big_out_buf: [fs.MAX_PATH_BYTES]u8 = undefined; | |
| 1275 | const end_index = std.unicode.utf16leToUtf8(&big_out_buf, wide_slice) catch |e| switch (e) { | |
| 1276 | // TODO: Windows file paths can be arbitrary arrays of u16 values and | |
| 1277 | // must not fail with InvalidUtf8. | |
| 1278 | error.DanglingSurrogateHalf, | |
| 1279 | error.ExpectedSecondSurrogateHalf, | |
| 1280 | error.UnexpectedSecondSurrogateHalf, | |
| 1281 | error.CodepointTooLarge, | |
| 1282 | error.Utf8CannotEncodeSurrogateHalf, | |
| 1283 | => return error.InvalidUtf8, | |
| 1284 | }; | |
| 1285 | if (end_index > out_buffer.len) | |
| 1278 | 1286 | return error.NameTooLong; |
| 1279 | } | |
| 1280 | ||
| 1281 | const result = out_buffer[0..out_path.len]; | |
| 1282 | @memcpy(result, out_path); | |
| 1287 | const result = out_buffer[0..end_index]; | |
| 1288 | @memcpy(result, big_out_buf[0..end_index]); | |
| 1283 | 1289 | return result; |
| 1284 | 1290 | } |
| 1285 | 1291 | |
| 1292 | pub const RealPathAllocError = RealPathError || Allocator.Error; | |
| 1293 | ||
| 1286 | 1294 | /// Same as `Dir.realpath` except caller must free the returned memory. |
| 1287 | 1295 | /// See also `Dir.realpath`. |
| 1288 | pub fn realpathAlloc(self: Dir, allocator: Allocator, pathname: []const u8) ![]u8 { | |
| 1296 | pub fn realpathAlloc(self: Dir, allocator: Allocator, pathname: []const u8) RealPathAllocError![]u8 { | |
| 1289 | 1297 | // Use of MAX_PATH_BYTES here is valid as the realpath function does not |
| 1290 | 1298 | // have a variant that takes an arbitrary-size buffer. |
| 1291 | 1299 | // TODO(#4812): Consider reimplementing realpath or using the POSIX.1-2008 |
lib/std/fs/File.zig+6| ... | ... | @@ -48,6 +48,12 @@ pub const OpenError = error{ |
| 48 | 48 | Unexpected, |
| 49 | 49 | /// On Windows, `\\server` or `\\server\share` was not found. |
| 50 | 50 | NetworkNotFound, |
| 51 | /// On Windows, antivirus software is enabled by default. It can be | |
| 52 | /// disabled, but Windows Update sometimes ignores the user's preference | |
| 53 | /// and re-enables it. When enabled, antivirus software on Windows | |
| 54 | /// intercepts file system operations and makes them significantly slower | |
| 55 | /// in addition to possibly failing with this error code. | |
| 56 | AntivirusInterference, | |
| 51 | 57 | } || posix.OpenError || posix.FlockError; |
| 52 | 58 | |
| 53 | 59 | pub const OpenMode = enum { |
lib/std/os.zig+30-11| ... | ... | @@ -2602,6 +2602,12 @@ pub const RenameError = error{ |
| 2602 | 2602 | PipeBusy, |
| 2603 | 2603 | /// On Windows, `\\server` or `\\server\share` was not found. |
| 2604 | 2604 | NetworkNotFound, |
| 2605 | /// On Windows, antivirus software is enabled by default. It can be | |
| 2606 | /// disabled, but Windows Update sometimes ignores the user's preference | |
| 2607 | /// and re-enables it. When enabled, antivirus software on Windows | |
| 2608 | /// intercepts file system operations and makes them significantly slower | |
| 2609 | /// in addition to possibly failing with this error code. | |
| 2610 | AntivirusInterference, | |
| 2605 | 2611 | } || UnexpectedError; |
| 2606 | 2612 | |
| 2607 | 2613 | /// Change the name or location of a file. |
| ... | ... | @@ -2927,9 +2933,10 @@ pub fn mkdiratW(dir_fd: fd_t, sub_path_w: []const u16, mode: u32) MakeDirError!v |
| 2927 | 2933 | .creation = windows.FILE_CREATE, |
| 2928 | 2934 | .filter = .dir_only, |
| 2929 | 2935 | }) catch |err| switch (err) { |
| 2930 | error.IsDir => unreachable, | |
| 2931 | error.PipeBusy => unreachable, | |
| 2932 | error.WouldBlock => unreachable, | |
| 2936 | error.IsDir => return error.Unexpected, | |
| 2937 | error.PipeBusy => return error.Unexpected, | |
| 2938 | error.WouldBlock => return error.Unexpected, | |
| 2939 | error.AntivirusInterference => return error.Unexpected, | |
| 2933 | 2940 | else => |e| return e, |
| 2934 | 2941 | }; |
| 2935 | 2942 | windows.CloseHandle(sub_dir_handle); |
| ... | ... | @@ -3006,9 +3013,10 @@ pub fn mkdirW(dir_path_w: []const u16, mode: u32) MakeDirError!void { |
| 3006 | 3013 | .creation = windows.FILE_CREATE, |
| 3007 | 3014 | .filter = .dir_only, |
| 3008 | 3015 | }) catch |err| switch (err) { |
| 3009 | error.IsDir => unreachable, | |
| 3010 | error.PipeBusy => unreachable, | |
| 3011 | error.WouldBlock => unreachable, | |
| 3016 | error.IsDir => return error.Unexpected, | |
| 3017 | error.PipeBusy => return error.Unexpected, | |
| 3018 | error.WouldBlock => return error.Unexpected, | |
| 3019 | error.AntivirusInterference => return error.Unexpected, | |
| 3012 | 3020 | else => |e| return e, |
| 3013 | 3021 | }; |
| 3014 | 3022 | windows.CloseHandle(sub_dir_handle); |
| ... | ... | @@ -5347,6 +5355,13 @@ pub const RealPathError = error{ |
| 5347 | 5355 | NetworkNotFound, |
| 5348 | 5356 | |
| 5349 | 5357 | PathAlreadyExists, |
| 5358 | ||
| 5359 | /// On Windows, antivirus software is enabled by default. It can be | |
| 5360 | /// disabled, but Windows Update sometimes ignores the user's preference | |
| 5361 | /// and re-enables it. When enabled, antivirus software on Windows | |
| 5362 | /// intercepts file system operations and makes them significantly slower | |
| 5363 | /// in addition to possibly failing with this error code. | |
| 5364 | AntivirusInterference, | |
| 5350 | 5365 | } || UnexpectedError; |
| 5351 | 5366 | |
| 5352 | 5367 | /// Return the canonicalized absolute pathname. |
| ... | ... | @@ -5441,15 +5456,17 @@ pub fn realpathW(pathname: []const u16, out_buffer: *[MAX_PATH_BYTES]u8) RealPat |
| 5441 | 5456 | |
| 5442 | 5457 | pub fn isGetFdPathSupportedOnTarget(os: std.Target.Os) bool { |
| 5443 | 5458 | return switch (os.tag) { |
| 5444 | // zig fmt: off | |
| 5445 | 5459 | .windows, |
| 5446 | .macos, .ios, .watchos, .tvos, | |
| 5460 | .macos, | |
| 5461 | .ios, | |
| 5462 | .watchos, | |
| 5463 | .tvos, | |
| 5447 | 5464 | .linux, |
| 5448 | 5465 | .solaris, |
| 5449 | 5466 | .illumos, |
| 5450 | 5467 | .freebsd, |
| 5451 | 5468 | => true, |
| 5452 | // zig fmt: on | |
| 5469 | ||
| 5453 | 5470 | .dragonfly => os.version_range.semver.max.order(.{ .major = 6, .minor = 0, .patch = 0 }) != .lt, |
| 5454 | 5471 | .netbsd => os.version_range.semver.max.order(.{ .major = 10, .minor = 0, .patch = 0 }) != .lt, |
| 5455 | 5472 | else => false, |
| ... | ... | @@ -5469,8 +5486,10 @@ pub fn getFdPath(fd: fd_t, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { |
| 5469 | 5486 | var wide_buf: [windows.PATH_MAX_WIDE]u16 = undefined; |
| 5470 | 5487 | const wide_slice = try windows.GetFinalPathNameByHandle(fd, .{}, wide_buf[0..]); |
| 5471 | 5488 | |
| 5472 | // Trust that Windows gives us valid UTF-16LE. | |
| 5473 | const end_index = std.unicode.utf16leToUtf8(out_buffer, wide_slice) catch unreachable; | |
| 5489 | // TODO: Windows file paths can be arbitrary arrays of u16 values | |
| 5490 | // and must not fail with InvalidUtf8. | |
| 5491 | const end_index = std.unicode.utf16leToUtf8(out_buffer, wide_slice) catch | |
| 5492 | return error.InvalidUtf8; | |
| 5474 | 5493 | return out_buffer[0..end_index]; |
| 5475 | 5494 | }, |
| 5476 | 5495 | .macos, .ios, .watchos, .tvos => { |
lib/std/os/windows.zig+15-11| ... | ... | @@ -41,6 +41,7 @@ pub const OpenError = error{ |
| 41 | 41 | NameTooLong, |
| 42 | 42 | WouldBlock, |
| 43 | 43 | NetworkNotFound, |
| 44 | AntivirusInterference, | |
| 44 | 45 | }; |
| 45 | 46 | |
| 46 | 47 | pub const OpenFileOptions = struct { |
| ... | ... | @@ -145,6 +146,7 @@ pub fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!HAN |
| 145 | 146 | std.time.sleep(std.time.ns_per_ms); |
| 146 | 147 | continue; |
| 147 | 148 | }, |
| 149 | .VIRUS_INFECTED, .VIRUS_DELETED => return error.AntivirusInterference, | |
| 148 | 150 | else => return unexpectedStatus(rc), |
| 149 | 151 | } |
| 150 | 152 | } |
| ... | ... | @@ -637,9 +639,10 @@ pub fn CreateSymbolicLink( |
| 637 | 639 | .filter = if (is_directory) .dir_only else .file_only, |
| 638 | 640 | }) catch |err| switch (err) { |
| 639 | 641 | error.IsDir => return error.PathAlreadyExists, |
| 640 | error.NotDir => unreachable, | |
| 641 | error.WouldBlock => unreachable, | |
| 642 | error.PipeBusy => unreachable, | |
| 642 | error.NotDir => return error.Unexpected, | |
| 643 | error.WouldBlock => return error.Unexpected, | |
| 644 | error.PipeBusy => return error.Unexpected, | |
| 645 | error.AntivirusInterference => return error.Unexpected, | |
| 643 | 646 | else => |e| return e, |
| 644 | 647 | }; |
| 645 | 648 | defer CloseHandle(symlink_handle); |
| ... | ... | @@ -1158,14 +1161,15 @@ pub fn GetFinalPathNameByHandle( |
| 1158 | 1161 | .share_access = FILE_SHARE_READ | FILE_SHARE_WRITE, |
| 1159 | 1162 | .creation = FILE_OPEN, |
| 1160 | 1163 | }) catch |err| switch (err) { |
| 1161 | error.IsDir => unreachable, | |
| 1162 | error.NotDir => unreachable, | |
| 1163 | error.NoDevice => unreachable, | |
| 1164 | error.AccessDenied => unreachable, | |
| 1165 | error.PipeBusy => unreachable, | |
| 1166 | error.PathAlreadyExists => unreachable, | |
| 1167 | error.WouldBlock => unreachable, | |
| 1168 | error.NetworkNotFound => unreachable, | |
| 1164 | error.IsDir => return error.Unexpected, | |
| 1165 | error.NotDir => return error.Unexpected, | |
| 1166 | error.NoDevice => return error.Unexpected, | |
| 1167 | error.AccessDenied => return error.Unexpected, | |
| 1168 | error.PipeBusy => return error.Unexpected, | |
| 1169 | error.PathAlreadyExists => return error.Unexpected, | |
| 1170 | error.WouldBlock => return error.Unexpected, | |
| 1171 | error.NetworkNotFound => return error.Unexpected, | |
| 1172 | error.AntivirusInterference => return error.Unexpected, | |
| 1169 | 1173 | else => |e| return e, |
| 1170 | 1174 | }; |
| 1171 | 1175 | defer CloseHandle(mgmt_handle); |
lib/std/zig/system.zig+2| ... | ... | @@ -766,6 +766,7 @@ fn glibcVerFromRPath(rpath: []const u8) !std.SemanticVersion { |
| 766 | 766 | error.PipeBusy => unreachable, // Windows-only |
| 767 | 767 | error.SharingViolation => unreachable, // Windows-only |
| 768 | 768 | error.NetworkNotFound => unreachable, // Windows-only |
| 769 | error.AntivirusInterference => unreachable, // Windows-only | |
| 769 | 770 | error.FileLocksNotSupported => unreachable, // No lock requested. |
| 770 | 771 | error.NoSpaceLeft => unreachable, // read-only |
| 771 | 772 | error.PathAlreadyExists => unreachable, // read-only |
| ... | ... | @@ -1003,6 +1004,7 @@ fn detectAbiAndDynamicLinker( |
| 1003 | 1004 | error.FileLocksNotSupported => unreachable, |
| 1004 | 1005 | error.WouldBlock => unreachable, |
| 1005 | 1006 | error.FileBusy => unreachable, // opened without write permissions |
| 1007 | error.AntivirusInterference => unreachable, // Windows-only error | |
| 1006 | 1008 | |
| 1007 | 1009 | error.IsDir, |
| 1008 | 1010 | error.NotDir, |