authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2025-12-19 03:25:28-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-23 22:15:11-08:00
log3431f4503116e06b542eedf9c9bad6f769af3ebc
treed99949140dded4c58050445ac65223debda48521
parent1136d36362f87ebad83007ea31d88c8427c0a019

std: Enough fixes to get things compiling on Windows


5 files changed, 144 insertions(+), 86 deletions(-)

lib/std/Io/Dir.zig+2
...@@ -1028,6 +1028,8 @@ pub const SymLinkError = error{...@@ -1028,6 +1028,8 @@ pub const SymLinkError = error{
1028 FileNotFound,1028 FileNotFound,
1029 SystemResources,1029 SystemResources,
1030 NoSpaceLeft,1030 NoSpaceLeft,
1031 /// On Windows, `\\server` or `\\server\share` was not found.
1032 NetworkNotFound,
1031 ReadOnlyFileSystem,1033 ReadOnlyFileSystem,
1032 NotDir,1034 NotDir,
1033} || PathNameError || Io.Cancelable || Io.UnexpectedError;1035} || PathNameError || Io.Cancelable || Io.UnexpectedError;
lib/std/Io/File.zig+2-2
...@@ -401,8 +401,8 @@ pub const Permissions = std.options.FilePermissions orelse if (is_windows) enum(...@@ -401,8 +401,8 @@ pub const Permissions = std.options.FilePermissions orelse if (is_windows) enum(
401401
402 const windows = std.os.windows;402 const windows = std.os.windows;
403403
404 pub fn toAttributes(self: @This()) windows.DWORD {404 pub fn toAttributes(self: @This()) windows.FILE.ATTRIBUTE {
405 return @intFromEnum(self);405 return @bitCast(@intFromEnum(self));
406 }406 }
407407
408 pub fn readOnly(self: @This()) bool {408 pub fn readOnly(self: @This()) bool {
lib/std/Io/Terminal.zig+1-1
...@@ -60,7 +60,7 @@ pub const Mode = union(enum) {...@@ -60,7 +60,7 @@ pub const Mode = union(enum) {
60 const windows = std.os.windows;60 const windows = std.os.windows;
61 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;61 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
62 if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != 0) {62 if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != 0) {
63 return .{ .terminal_winapi = .{63 return .{ .windows_api = .{
64 .handle = file.handle,64 .handle = file.handle,
65 .reset_attributes = info.wAttributes,65 .reset_attributes = info.wAttributes,
66 } };66 } };
lib/std/Io/Threaded.zig+138-82
...@@ -3889,9 +3889,10 @@ fn dirRealPathFileWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8,...@@ -3889,9 +3889,10 @@ fn dirRealPathFileWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8,
3889 return realPathWindows(current_thread, h_file, out_buffer);3889 return realPathWindows(current_thread, h_file, out_buffer);
3890}3890}
38913891
3892fn realPathWindows(current_thread: *Thread, h_file: windows.HANDLE, out_buffer: []u8) Dir.RealPathFileError {3892fn realPathWindows(current_thread: *Thread, h_file: windows.HANDLE, out_buffer: []u8) File.RealPathError!usize {
3893 _ = current_thread; // TODO move GetFinalPathNameByHandle logic into std.Io.Threaded and add cancel checks3893 _ = current_thread; // TODO move GetFinalPathNameByHandle logic into std.Io.Threaded and add cancel checks
3894 const wide_slice = windows.GetFinalPathNameByHandle(h_file, .{}, out_buffer);3894 var wide_buf: [windows.PATH_MAX_WIDE]u16 = undefined;
3895 const wide_slice = try windows.GetFinalPathNameByHandle(h_file, .{}, &wide_buf);
38953896
3896 const len = std.unicode.calcWtf8Len(wide_slice);3897 const len = std.unicode.calcWtf8Len(wide_slice);
3897 if (len > out_buffer.len)3898 if (len > out_buffer.len)
...@@ -3981,7 +3982,19 @@ fn dirRealPathWindows(userdata: ?*anyopaque, dir: Dir, out_buffer: []u8) Dir.Rea...@@ -3981,7 +3982,19 @@ fn dirRealPathWindows(userdata: ?*anyopaque, dir: Dir, out_buffer: []u8) Dir.Rea
3981 return realPathWindows(current_thread, dir.handle, out_buffer);3982 return realPathWindows(current_thread, dir.handle, out_buffer);
3982}3983}
39833984
3984fn fileRealPath(userdata: ?*anyopaque, file: File, out_buffer: []u8) File.RealPathError!usize {3985const fileRealPath = switch (native_os) {
3986 .windows => fileRealPathWindows,
3987 else => fileRealPathPosix,
3988};
3989
3990fn fileRealPathWindows(userdata: ?*anyopaque, file: File, out_buffer: []u8) File.RealPathError!usize {
3991 if (native_os == .wasi) return error.OperationUnsupported;
3992 const t: *Threaded = @ptrCast(@alignCast(userdata));
3993 const current_thread = Thread.getCurrent(t);
3994 return realPathWindows(current_thread, file.handle, out_buffer);
3995}
3996
3997fn fileRealPathPosix(userdata: ?*anyopaque, file: File, out_buffer: []u8) File.RealPathError!usize {
3985 if (native_os == .wasi) return error.OperationUnsupported;3998 if (native_os == .wasi) return error.OperationUnsupported;
3986 const t: *Threaded = @ptrCast(@alignCast(userdata));3999 const t: *Threaded = @ptrCast(@alignCast(userdata));
3987 const current_thread = Thread.getCurrent(t);4000 const current_thread = Thread.getCurrent(t);
...@@ -4128,7 +4141,10 @@ const dirDeleteFile = switch (native_os) {...@@ -4128,7 +4141,10 @@ const dirDeleteFile = switch (native_os) {
4128};4141};
41294142
4130fn dirDeleteFileWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir.DeleteFileError!void {4143fn dirDeleteFileWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir.DeleteFileError!void {
4131 return dirDeleteWindows(userdata, dir, sub_path, false);4144 return dirDeleteWindows(userdata, dir, sub_path, false) catch |err| switch (err) {
4145 error.DirNotEmpty => unreachable,
4146 else => |e| return e,
4147 };
4132}4148}
41334149
4134fn dirDeleteFileWasi(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir.DeleteFileError!void {4150fn dirDeleteFileWasi(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir.DeleteFileError!void {
...@@ -4261,10 +4277,13 @@ const dirDeleteDir = switch (native_os) {...@@ -4261,10 +4277,13 @@ const dirDeleteDir = switch (native_os) {
4261};4277};
42624278
4263fn dirDeleteDirWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir.DeleteDirError!void {4279fn dirDeleteDirWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8) Dir.DeleteDirError!void {
4264 return dirDeleteWindows(userdata, dir, sub_path, true);4280 return dirDeleteWindows(userdata, dir, sub_path, true) catch |err| switch (err) {
4281 error.IsDir => unreachable,
4282 else => |e| return e,
4283 };
4265}4284}
42664285
4267fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remove_dir: bool) Dir.DeleteFileError!void {4286fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remove_dir: bool) (Dir.DeleteDirError || Dir.DeleteFileError)!void {
4268 const t: *Threaded = @ptrCast(@alignCast(userdata));4287 const t: *Threaded = @ptrCast(@alignCast(userdata));
4269 const current_thread = Thread.getCurrent(t);4288 const current_thread = Thread.getCurrent(t);
4270 const w = windows;4289 const w = windows;
...@@ -4352,18 +4371,18 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov...@@ -4352,18 +4371,18 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov
4352 try current_thread.checkCancel();4371 try current_thread.checkCancel();
43534372
4354 // Deletion with posix semantics if the filesystem supports it.4373 // Deletion with posix semantics if the filesystem supports it.
4355 var info: w.FILE_DISPOSITION_INFORMATION_EX = .{4374 const info: w.FILE.DISPOSITION.INFORMATION.EX = .{ .Flags = .{
4356 .Flags = w.FILE_DISPOSITION_DELETE |4375 .DELETE = true,
4357 w.FILE_DISPOSITION_POSIX_SEMANTICS |4376 .POSIX_SEMANTICS = true,
4358 w.FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE,4377 .IGNORE_READONLY_ATTRIBUTE = true,
4359 };4378 } };
43604379
4361 rc = w.ntdll.NtSetInformationFile(4380 rc = w.ntdll.NtSetInformationFile(
4362 tmp_handle,4381 tmp_handle,
4363 &io_status_block,4382 &io_status_block,
4364 &info,4383 &info,
4365 @sizeOf(w.FILE_DISPOSITION_INFORMATION_EX),4384 @sizeOf(w.FILE.DISPOSITION.INFORMATION.EX),
4366 .FileDispositionInformationEx,4385 .DispositionEx,
4367 );4386 );
4368 switch (rc) {4387 switch (rc) {
4369 .SUCCESS => return,4388 .SUCCESS => return,
...@@ -4384,7 +4403,7 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov...@@ -4384,7 +4403,7 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov
43844403
4385 // Deletion with file pending semantics, which requires waiting or moving4404 // Deletion with file pending semantics, which requires waiting or moving
4386 // files to get them removed (from here).4405 // files to get them removed (from here).
4387 var file_dispo: w.FILE_DISPOSITION_INFORMATION = .{4406 const file_dispo: w.FILE.DISPOSITION.INFORMATION = .{
4388 .DeleteFile = w.TRUE,4407 .DeleteFile = w.TRUE,
4389 };4408 };
43904409
...@@ -4392,8 +4411,8 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov...@@ -4392,8 +4411,8 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov
4392 tmp_handle,4411 tmp_handle,
4393 &io_status_block,4412 &io_status_block,
4394 &file_dispo,4413 &file_dispo,
4395 @sizeOf(w.FILE_DISPOSITION_INFORMATION),4414 @sizeOf(w.FILE.DISPOSITION.INFORMATION),
4396 .FileDispositionInformation,4415 .Disposition,
4397 );4416 );
4398 }4417 }
4399 switch (rc) {4418 switch (rc) {
...@@ -4555,29 +4574,23 @@ fn dirRenameWindows(...@@ -4555,29 +4574,23 @@ fn dirRenameWindows(
4555 // The strategy here is just to try using FileRenameInformationEx and fall back to4574 // The strategy here is just to try using FileRenameInformationEx and fall back to
4556 // FileRenameInformation if the return value lets us know that some aspect of it is not supported.4575 // FileRenameInformation if the return value lets us know that some aspect of it is not supported.
4557 const need_fallback = need_fallback: {4576 const need_fallback = need_fallback: {
4558 const struct_buf_len = @sizeOf(w.FILE_RENAME_INFORMATION_EX) + (w.PATH_MAX_WIDE * 2);4577 const rename_info: w.FILE.RENAME_INFORMATION = .init(.{
4559 var rename_info_buf: [struct_buf_len]u8 align(@alignOf(w.FILE_RENAME_INFORMATION_EX)) = undefined;4578 .Flags = .{
4560 const struct_len = @sizeOf(w.FILE_RENAME_INFORMATION_EX) + new_path_w.len * 2;4579 .REPLACE_IF_EXISTS = replace_if_exists,
4561 if (struct_len > struct_buf_len) return error.NameTooLong;4580 .POSIX_SEMANTICS = true,
45624581 .IGNORE_READONLY_ATTRIBUTE = true,
4563 const rename_info: *w.FILE_RENAME_INFORMATION_EX = @ptrCast(&rename_info_buf);4582 },
4564 var io_status_block: w.IO_STATUS_BLOCK = undefined;
4565
4566 var flags: w.ULONG = w.FILE_RENAME_POSIX_SEMANTICS | w.FILE_RENAME_IGNORE_READONLY_ATTRIBUTE;
4567 if (replace_if_exists) flags |= w.FILE_RENAME_REPLACE_IF_EXISTS;
4568 rename_info.* = .{
4569 .Flags = flags,
4570 .RootDirectory = if (std.fs.path.isAbsoluteWindowsWtf16(new_path_w)) null else new_dir.handle,4583 .RootDirectory = if (std.fs.path.isAbsoluteWindowsWtf16(new_path_w)) null else new_dir.handle,
4571 .FileNameLength = @intCast(new_path_w.len * 2), // already checked error.NameTooLong4584 .FileName = new_path_w,
4572 .FileName = undefined,4585 });
4573 };4586 var io_status_block: w.IO_STATUS_BLOCK = undefined;
4574 @memcpy((&rename_info.FileName).ptr, new_path_w);4587 const rename_info_buf = rename_info.toBuffer();
4575 rc = w.ntdll.NtSetInformationFile(4588 rc = w.ntdll.NtSetInformationFile(
4576 src_fd,4589 src_fd,
4577 &io_status_block,4590 &io_status_block,
4578 rename_info,4591 rename_info_buf.ptr,
4579 @intCast(struct_len), // already checked for error.NameTooLong4592 @intCast(rename_info_buf.len),
4580 .FileRenameInformationEx,4593 .RenameEx,
4581 );4594 );
4582 switch (rc) {4595 switch (rc) {
4583 .SUCCESS => return,4596 .SUCCESS => return,
...@@ -4594,28 +4607,19 @@ fn dirRenameWindows(...@@ -4594,28 +4607,19 @@ fn dirRenameWindows(
4594 };4607 };
45954608
4596 if (need_fallback) {4609 if (need_fallback) {
4597 const struct_buf_len = @sizeOf(w.FILE_RENAME_INFORMATION) + (w.PATH_MAX_WIDE * 2);4610 const rename_info: w.FILE.RENAME_INFORMATION = .init(.{
4598 var rename_info_buf: [struct_buf_len]u8 align(@alignOf(w.FILE_RENAME_INFORMATION)) = undefined;4611 .Flags = .{ .REPLACE_IF_EXISTS = replace_if_exists },
4599 const struct_len = @sizeOf(w.FILE_RENAME_INFORMATION) + new_path_w.len * 2;
4600 if (struct_len > struct_buf_len) return error.NameTooLong;
4601
4602 const rename_info: *w.FILE_RENAME_INFORMATION = @ptrCast(&rename_info_buf);
4603 var io_status_block: w.IO_STATUS_BLOCK = undefined;
4604
4605 rename_info.* = .{
4606 .Flags = @intFromBool(replace_if_exists),
4607 .RootDirectory = if (std.fs.path.isAbsoluteWindowsWtf16(new_path_w)) null else new_dir.handle,4612 .RootDirectory = if (std.fs.path.isAbsoluteWindowsWtf16(new_path_w)) null else new_dir.handle,
4608 .FileNameLength = @intCast(new_path_w.len * 2), // already checked error.NameTooLong4613 .FileName = new_path_w,
4609 .FileName = undefined,4614 });
4610 };4615 var io_status_block: w.IO_STATUS_BLOCK = undefined;
4611 @memcpy((&rename_info.FileName).ptr, new_path_w);4616 const rename_info_buf = rename_info.toBuffer();
4612
4613 rc = w.ntdll.NtSetInformationFile(4617 rc = w.ntdll.NtSetInformationFile(
4614 src_fd,4618 src_fd,
4615 &io_status_block,4619 &io_status_block,
4616 rename_info,4620 rename_info_buf.ptr,
4617 @intCast(struct_len), // already checked for error.NameTooLong4621 @intCast(rename_info_buf.len),
4618 .FileRenameInformation,4622 .Rename,
4619 );4623 );
4620 }4624 }
46214625
...@@ -4779,7 +4783,7 @@ fn dirSymLinkWindows(...@@ -4779,7 +4783,7 @@ fn dirSymLinkWindows(
4779 const sym_link_path_w = try w.sliceToPrefixedFileW(dir.handle, sym_link_path);4783 const sym_link_path_w = try w.sliceToPrefixedFileW(dir.handle, sym_link_path);
47804784
4781 const SYMLINK_DATA = extern struct {4785 const SYMLINK_DATA = extern struct {
4782 ReparseTag: w.ULONG,4786 ReparseTag: w.IO_REPARSE_TAG,
4783 ReparseDataLength: w.USHORT,4787 ReparseDataLength: w.USHORT,
4784 Reserved: w.USHORT,4788 Reserved: w.USHORT,
4785 SubstituteNameOffset: w.USHORT,4789 SubstituteNameOffset: w.USHORT,
...@@ -4794,7 +4798,7 @@ fn dirSymLinkWindows(...@@ -4794,7 +4798,7 @@ fn dirSymLinkWindows(
4794 .GENERIC = .{ .READ = true, .WRITE = true },4798 .GENERIC = .{ .READ = true, .WRITE = true },
4795 .STANDARD = .{ .SYNCHRONIZE = true },4799 .STANDARD = .{ .SYNCHRONIZE = true },
4796 },4800 },
4797 .dir = dir,4801 .dir = dir.handle,
4798 .creation = .CREATE,4802 .creation = .CREATE,
4799 .filter = if (flags.is_directory) .dir_only else .non_directory_only,4803 .filter = if (flags.is_directory) .dir_only else .non_directory_only,
4800 }) catch |err| switch (err) {4804 }) catch |err| switch (err) {
...@@ -4818,11 +4822,11 @@ fn dirSymLinkWindows(...@@ -4818,11 +4822,11 @@ fn dirSymLinkWindows(
4818 // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw4822 // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw
4819 var is_target_absolute = false;4823 var is_target_absolute = false;
4820 const final_target_path = target_path: {4824 const final_target_path = target_path: {
4821 if (w.hasCommonNtPrefix(u16, target_path)) {4825 if (w.hasCommonNtPrefix(u16, target_path_w.span())) {
4822 // Already an NT path, no need to do anything to it4826 // Already an NT path, no need to do anything to it
4823 break :target_path target_path;4827 break :target_path target_path_w.span();
4824 } else {4828 } else {
4825 switch (w.getWin32PathType(u16, target_path)) {4829 switch (w.getWin32PathType(u16, target_path_w.span())) {
4826 // Rooted paths need to avoid getting put through wToPrefixedFileW4830 // Rooted paths need to avoid getting put through wToPrefixedFileW
4827 // (and they are treated as relative in this context)4831 // (and they are treated as relative in this context)
4828 // Note: It seems that rooted paths in symbolic links are relative to4832 // Note: It seems that rooted paths in symbolic links are relative to
...@@ -4830,13 +4834,13 @@ fn dirSymLinkWindows(...@@ -4830,13 +4834,13 @@ fn dirSymLinkWindows(
4830 // So, if the symlink is on C:\ and the CWD is on D:\,4834 // So, if the symlink is on C:\ and the CWD is on D:\,
4831 // it will still resolve the path relative to the root of4835 // it will still resolve the path relative to the root of
4832 // the C:\ drive.4836 // the C:\ drive.
4833 .rooted => break :target_path target_path,4837 .rooted => break :target_path target_path_w.span(),
4834 // Keep relative paths relative, but anything else needs to get NT-prefixed.4838 // Keep relative paths relative, but anything else needs to get NT-prefixed.
4835 else => if (!std.fs.path.isAbsoluteWindowsWtf16(target_path))4839 else => if (!std.fs.path.isAbsoluteWindowsWtf16(target_path_w.span()))
4836 break :target_path target_path,4840 break :target_path target_path_w.span(),
4837 }4841 }
4838 }4842 }
4839 var prefixed_target_path = try w.wToPrefixedFileW(dir, target_path);4843 var prefixed_target_path = try w.wToPrefixedFileW(dir.handle, target_path_w.span());
4840 // We do this after prefixing to ensure that drive-relative paths are treated as absolute4844 // We do this after prefixing to ensure that drive-relative paths are treated as absolute
4841 is_target_absolute = std.fs.path.isAbsoluteWindowsWtf16(prefixed_target_path.span());4845 is_target_absolute = std.fs.path.isAbsoluteWindowsWtf16(prefixed_target_path.span());
4842 break :target_path prefixed_target_path.span();4846 break :target_path prefixed_target_path.span();
...@@ -4848,7 +4852,7 @@ fn dirSymLinkWindows(...@@ -4848,7 +4852,7 @@ fn dirSymLinkWindows(
4848 const header_len = @sizeOf(w.ULONG) + @sizeOf(w.USHORT) * 2;4852 const header_len = @sizeOf(w.ULONG) + @sizeOf(w.USHORT) * 2;
4849 const target_is_absolute = std.fs.path.isAbsoluteWindowsWtf16(final_target_path);4853 const target_is_absolute = std.fs.path.isAbsoluteWindowsWtf16(final_target_path);
4850 const symlink_data = SYMLINK_DATA{4854 const symlink_data = SYMLINK_DATA{
4851 .ReparseTag = w.IO_REPARSE_TAG_SYMLINK,4855 .ReparseTag = .SYMLINK,
4852 .ReparseDataLength = @intCast(buf_len - header_len),4856 .ReparseDataLength = @intCast(buf_len - header_len),
4853 .Reserved = 0,4857 .Reserved = 0,
4854 .SubstituteNameOffset = @intCast(final_target_path.len * 2),4858 .SubstituteNameOffset = @intCast(final_target_path.len * 2),
...@@ -4862,7 +4866,14 @@ fn dirSymLinkWindows(...@@ -4862,7 +4866,14 @@ fn dirSymLinkWindows(
4862 @memcpy(buffer[@sizeOf(SYMLINK_DATA)..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path)));4866 @memcpy(buffer[@sizeOf(SYMLINK_DATA)..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path)));
4863 const paths_start = @sizeOf(SYMLINK_DATA) + final_target_path.len * 2;4867 const paths_start = @sizeOf(SYMLINK_DATA) + final_target_path.len * 2;
4864 @memcpy(buffer[paths_start..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path)));4868 @memcpy(buffer[paths_start..][0 .. final_target_path.len * 2], @as([*]const u8, @ptrCast(final_target_path)));
4865 _ = try w.DeviceIoControl(symlink_handle, w.FSCTL_SET_REPARSE_POINT, buffer[0..buf_len], null);4869 _ = w.DeviceIoControl(symlink_handle, w.FSCTL.SET_REPARSE_POINT, .{ .in = buffer[0..buf_len] }) catch |err| switch (err) {
4870 error.PipeClosing => unreachable,
4871 error.PipeAlreadyConnected => unreachable,
4872 error.PipeAlreadyListening => unreachable,
4873 error.Pending => unreachable,
4874 error.UnrecognizedVolume => unreachable,
4875 else => |e| return e,
4876 };
4866}4877}
48674878
4868fn dirSymLinkWasi(4879fn dirSymLinkWasi(
...@@ -5503,16 +5514,22 @@ fn isCygwinPty(current_thread: *Thread, file: File) Io.Cancelable!bool {...@@ -5503,16 +5514,22 @@ fn isCygwinPty(current_thread: *Thread, file: File) Io.Cancelable!bool {
5503 {5514 {
5504 try current_thread.checkCancel();5515 try current_thread.checkCancel();
5505 var io_status: windows.IO_STATUS_BLOCK = undefined;5516 var io_status: windows.IO_STATUS_BLOCK = undefined;
5506 var device_info: windows.FILE_FS_DEVICE_INFORMATION = undefined;5517 var device_info: windows.FILE.FS_DEVICE_INFORMATION = undefined;
5507 const rc = windows.ntdll.NtQueryVolumeInformationFile(handle, &io_status, &device_info, @sizeOf(windows.FILE_FS_DEVICE_INFORMATION), .FileFsDeviceInformation);5518 const rc = windows.ntdll.NtQueryVolumeInformationFile(
5519 handle,
5520 &io_status,
5521 &device_info,
5522 @sizeOf(windows.FILE.FS_DEVICE_INFORMATION),
5523 .Device,
5524 );
5508 switch (rc) {5525 switch (rc) {
5509 .SUCCESS => {},5526 .SUCCESS => {},
5510 else => return false,5527 else => return false,
5511 }5528 }
5512 if (device_info.DeviceType != windows.FILE_DEVICE_NAMED_PIPE) return false;5529 if (device_info.DeviceType.FileDevice != .NAMED_PIPE) return false;
5513 }5530 }
55145531
5515 const name_bytes_offset = @offsetOf(windows.FILE_NAME_INFO, "FileName");5532 const name_bytes_offset = @offsetOf(windows.FILE.NAME_INFORMATION, "FileName");
5516 // `NAME_MAX` UTF-16 code units (2 bytes each)5533 // `NAME_MAX` UTF-16 code units (2 bytes each)
5517 // This buffer may not be long enough to handle *all* possible paths5534 // This buffer may not be long enough to handle *all* possible paths
5518 // (PATH_MAX_WIDE would be necessary for that), but because we only care5535 // (PATH_MAX_WIDE would be necessary for that), but because we only care
...@@ -5520,11 +5537,17 @@ fn isCygwinPty(current_thread: *Thread, file: File) Io.Cancelable!bool {...@@ -5520,11 +5537,17 @@ fn isCygwinPty(current_thread: *Thread, file: File) Io.Cancelable!bool {
5520 // we can use this smaller buffer and just return false on any error from5537 // we can use this smaller buffer and just return false on any error from
5521 // NtQueryInformationFile.5538 // NtQueryInformationFile.
5522 const num_name_bytes = windows.MAX_PATH * 2;5539 const num_name_bytes = windows.MAX_PATH * 2;
5523 var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = [_]u8{0} ** (name_bytes_offset + num_name_bytes);5540 var name_info_bytes align(@alignOf(windows.FILE.NAME_INFORMATION)) = [_]u8{0} ** (name_bytes_offset + num_name_bytes);
55245541
5525 var io_status_block: windows.IO_STATUS_BLOCK = undefined;5542 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
5526 try current_thread.checkCancel();5543 try current_thread.checkCancel();
5527 const rc = windows.ntdll.NtQueryInformationFile(handle, &io_status_block, &name_info_bytes, @intCast(name_info_bytes.len), .FileNameInformation);5544 const rc = windows.ntdll.NtQueryInformationFile(
5545 handle,
5546 &io_status_block,
5547 &name_info_bytes,
5548 @intCast(name_info_bytes.len),
5549 .Name,
5550 );
5528 switch (rc) {5551 switch (rc) {
5529 .SUCCESS => {},5552 .SUCCESS => {},
5530 .INVALID_PARAMETER => unreachable,5553 .INVALID_PARAMETER => unreachable,
...@@ -5551,7 +5574,7 @@ fn fileSetLength(userdata: ?*anyopaque, file: File, length: u64) File.SetLengthE...@@ -5551,7 +5574,7 @@ fn fileSetLength(userdata: ?*anyopaque, file: File, length: u64) File.SetLengthE
5551 try current_thread.checkCancel();5574 try current_thread.checkCancel();
55525575
5553 var io_status_block: windows.IO_STATUS_BLOCK = undefined;5576 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
5554 var eof_info: windows.FILE_END_OF_FILE_INFORMATION = .{5577 const eof_info: windows.FILE.END_OF_FILE_INFORMATION = .{
5555 .EndOfFile = signed_len,5578 .EndOfFile = signed_len,
5556 };5579 };
55575580
...@@ -5559,8 +5582,8 @@ fn fileSetLength(userdata: ?*anyopaque, file: File, length: u64) File.SetLengthE...@@ -5559,8 +5582,8 @@ fn fileSetLength(userdata: ?*anyopaque, file: File, length: u64) File.SetLengthE
5559 file.handle,5582 file.handle,
5560 &io_status_block,5583 &io_status_block,
5561 &eof_info,5584 &eof_info,
5562 @sizeOf(windows.FILE_END_OF_FILE_INFORMATION),5585 @sizeOf(windows.FILE.END_OF_FILE_INFORMATION),
5563 .FileEndOfFileInformation,5586 .EndOfFile,
5564 );5587 );
5565 switch (status) {5588 switch (status) {
5566 .SUCCESS => return,5589 .SUCCESS => return,
...@@ -5643,19 +5666,19 @@ fn fileSetPermissions(userdata: ?*anyopaque, file: File, permissions: File.Permi...@@ -5643,19 +5666,19 @@ fn fileSetPermissions(userdata: ?*anyopaque, file: File, permissions: File.Permi
5643 .windows => {5666 .windows => {
5644 try current_thread.checkCancel();5667 try current_thread.checkCancel();
5645 var io_status_block: windows.IO_STATUS_BLOCK = undefined;5668 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
5646 var info: windows.FILE_BASIC_INFORMATION = .{5669 const info: windows.FILE.BASIC_INFORMATION = .{
5647 .CreationTime = 0,5670 .CreationTime = 0,
5648 .LastAccessTime = 0,5671 .LastAccessTime = 0,
5649 .LastWriteTime = 0,5672 .LastWriteTime = 0,
5650 .ChangeTime = 0,5673 .ChangeTime = 0,
5651 .FileAttributes = permissions.inner.attributes,5674 .FileAttributes = permissions.toAttributes(),
5652 };5675 };
5653 const status = windows.ntdll.NtSetInformationFile(5676 const status = windows.ntdll.NtSetInformationFile(
5654 file.handle,5677 file.handle,
5655 &io_status_block,5678 &io_status_block,
5656 &info,5679 &info,
5657 @sizeOf(windows.FILE_BASIC_INFORMATION),5680 @sizeOf(windows.FILE.BASIC_INFORMATION),
5658 .FileBasicInformation,5681 .Basic,
5659 );5682 );
5660 switch (status) {5683 switch (status) {
5661 .SUCCESS => return,5684 .SUCCESS => return,
...@@ -5813,8 +5836,8 @@ fn fileSetTimestamps(...@@ -5813,8 +5836,8 @@ fn fileSetTimestamps(
5813 if (is_windows) {5836 if (is_windows) {
5814 try current_thread.checkCancel();5837 try current_thread.checkCancel();
58155838
5816 const atime_ft = windows.nanoSecondsToFileTime(last_accessed.toNanoseconds());5839 const atime_ft = windows.nanoSecondsToFileTime(last_accessed);
5817 const mtime_ft = windows.nanoSecondsToFileTime(last_modified.toNanoseconds());5840 const mtime_ft = windows.nanoSecondsToFileTime(last_modified);
58185841
5819 // https://github.com/ziglang/zig/issues/18405842 // https://github.com/ziglang/zig/issues/1840
5820 const rc = windows.kernel32.SetFileTime(file.handle, null, &atime_ft, &mtime_ft);5843 const rc = windows.kernel32.SetFileTime(file.handle, null, &atime_ft, &mtime_ft);
...@@ -5958,7 +5981,24 @@ fn fileLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockError!v...@@ -5958,7 +5981,24 @@ fn fileLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockError!v
59585981
5959 if (is_windows) {5982 if (is_windows) {
5960 const exclusive = switch (lock) {5983 const exclusive = switch (lock) {
5961 .none => return,5984 .none => {
5985 // To match the non-Windows behavior, unlock
5986 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
5987 const status = windows.ntdll.NtUnlockFile(
5988 file.handle,
5989 &io_status_block,
5990 &windows_lock_range_off,
5991 &windows_lock_range_len,
5992 0,
5993 );
5994 switch (status) {
5995 .SUCCESS => {},
5996 .RANGE_NOT_LOCKED => {},
5997 .ACCESS_VIOLATION => |err| return windows.statusBug(err), // bad io_status_block pointer
5998 else => return windows.unexpectedStatus(status),
5999 }
6000 return;
6001 },
5962 .shared => false,6002 .shared => false,
5963 .exclusive => true,6003 .exclusive => true,
5964 };6004 };
...@@ -6020,7 +6060,23 @@ fn fileTryLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockErro...@@ -6020,7 +6060,23 @@ fn fileTryLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockErro
60206060
6021 if (is_windows) {6061 if (is_windows) {
6022 const exclusive = switch (lock) {6062 const exclusive = switch (lock) {
6023 .none => return,6063 .none => {
6064 // To match the non-Windows behavior, unlock
6065 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
6066 const status = windows.ntdll.NtUnlockFile(
6067 file.handle,
6068 &io_status_block,
6069 &windows_lock_range_off,
6070 &windows_lock_range_len,
6071 0,
6072 );
6073 switch (status) {
6074 .SUCCESS => return true,
6075 .RANGE_NOT_LOCKED => return false,
6076 .ACCESS_VIOLATION => |err| return windows.statusBug(err), // bad io_status_block pointer
6077 else => return windows.unexpectedStatus(status),
6078 }
6079 },
6024 .shared => false,6080 .shared => false,
6025 .exclusive => true,6081 .exclusive => true,
6026 };6082 };
...@@ -6093,7 +6149,7 @@ fn fileUnlock(userdata: ?*anyopaque, file: File) void {...@@ -6093,7 +6149,7 @@ fn fileUnlock(userdata: ?*anyopaque, file: File) void {
6093 &io_status_block,6149 &io_status_block,
6094 &windows_lock_range_off,6150 &windows_lock_range_off,
6095 &windows_lock_range_len,6151 &windows_lock_range_len,
6096 null,6152 0,
6097 );6153 );
6098 if (is_debug) switch (status) {6154 if (is_debug) switch (status) {
6099 .SUCCESS => {},6155 .SUCCESS => {},
lib/std/posix/test.zig+1-1
...@@ -326,7 +326,7 @@ test "sync" {...@@ -326,7 +326,7 @@ test "sync" {
326326
327test "fsync" {327test "fsync" {
328 switch (native_os) {328 switch (native_os) {
329 .linux, .windows, .illumos => {},329 .linux, .illumos => {},
330 else => return error.SkipZigTest,330 else => return error.SkipZigTest,
331 }331 }
332332