authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2025-12-18 18:32:25-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-23 22:15:10-08:00
logf078c7138f0dfbab95d8963e6c067515c6a54460
tree23fc317aad23768a35d8027cc03b5a96861755d0
parent1edae601a1d35caa78eddc4b18f7d613c4af70f9

std: Update/fix some usages/implementations of std.Io APIs


5 files changed, 172 insertions(+), 180 deletions(-)

lib/std/Io/Terminal.zig+2-2
...@@ -56,7 +56,7 @@ pub const Mode = union(enum) {...@@ -56,7 +56,7 @@ pub const Mode = union(enum) {
56 error.NotTerminalDevice, error.Unexpected => {},56 error.NotTerminalDevice, error.Unexpected => {},
57 }57 }
5858
59 if (is_windows and file.isTty(io)) {59 if (is_windows and try file.isTty(io)) {
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) {
...@@ -74,7 +74,7 @@ pub const Mode = union(enum) {...@@ -74,7 +74,7 @@ pub const Mode = union(enum) {
7474
75pub const SetColorError = std.os.windows.SetConsoleTextAttributeError || Io.Writer.Error;75pub const SetColorError = std.os.windows.SetConsoleTextAttributeError || Io.Writer.Error;
7676
77pub fn setColor(t: Terminal, color: Color) Io.Writer.Error!void {77pub fn setColor(t: Terminal, color: Color) SetColorError!void {
78 switch (t.mode) {78 switch (t.mode) {
79 .no_color => return,79 .no_color => return,
80 .escape_codes => {80 .escape_codes => {
lib/std/Io/Threaded.zig+84-102
...@@ -1744,7 +1744,7 @@ fn dirMakeOpenPathWindows(...@@ -1744,7 +1744,7 @@ fn dirMakeOpenPathWindows(
1744 // stat the file and return an error if it's not a directory1744 // stat the file and return an error if it's not a directory
1745 // this is important because otherwise a dangling symlink1745 // this is important because otherwise a dangling symlink
1746 // could cause an infinite loop1746 // could cause an infinite loop
1747 const fstat = dirStatFileWindows(t, dir, component.path, .{1747 const fstat = try dirStatFileWindows(t, dir, component.path, .{
1748 .follow_symlinks = options.follow_symlinks,1748 .follow_symlinks = options.follow_symlinks,
1749 });1749 });
1750 if (fstat.kind != .directory) return error.NotDir;1750 if (fstat.kind != .directory) return error.NotDir;
...@@ -2146,7 +2146,7 @@ fn fileStatWindows(userdata: ?*anyopaque, file: File) File.StatError!File.Stat {...@@ -2146,7 +2146,7 @@ fn fileStatWindows(userdata: ?*anyopaque, file: File) File.StatError!File.Stat {
2146 return .{2146 return .{
2147 .inode = info.InternalInformation.IndexNumber,2147 .inode = info.InternalInformation.IndexNumber,
2148 .size = @as(u64, @bitCast(info.StandardInformation.EndOfFile)),2148 .size = @as(u64, @bitCast(info.StandardInformation.EndOfFile)),
2149 .mode = 0,2149 .permissions = .default_file,
2150 .kind = if (info.BasicInformation.FileAttributes.REPARSE_POINT) reparse_point: {2150 .kind = if (info.BasicInformation.FileAttributes.REPARSE_POINT) reparse_point: {
2151 var tag_info: windows.FILE.ATTRIBUTE_TAG_INFO = undefined;2151 var tag_info: windows.FILE.ATTRIBUTE_TAG_INFO = undefined;
2152 const tag_rc = windows.ntdll.NtQueryInformationFile(file.handle, &io_status_block, &tag_info, @sizeOf(windows.FILE.ATTRIBUTE_TAG_INFO), .AttributeTag);2152 const tag_rc = windows.ntdll.NtQueryInformationFile(file.handle, &io_status_block, &tag_info, @sizeOf(windows.FILE.ATTRIBUTE_TAG_INFO), .AttributeTag);
...@@ -2168,6 +2168,7 @@ fn fileStatWindows(userdata: ?*anyopaque, file: File) File.StatError!File.Stat {...@@ -2168,6 +2168,7 @@ fn fileStatWindows(userdata: ?*anyopaque, file: File) File.StatError!File.Stat {
2168 .atime = windows.fromSysTime(info.BasicInformation.LastAccessTime),2168 .atime = windows.fromSysTime(info.BasicInformation.LastAccessTime),
2169 .mtime = windows.fromSysTime(info.BasicInformation.LastWriteTime),2169 .mtime = windows.fromSysTime(info.BasicInformation.LastWriteTime),
2170 .ctime = windows.fromSysTime(info.BasicInformation.ChangeTime),2170 .ctime = windows.fromSysTime(info.BasicInformation.ChangeTime),
2171 .nlink = {},
2171 };2172 };
2172}2173}
21732174
...@@ -2584,26 +2585,33 @@ fn dirCreateFileWindows(...@@ -2584,26 +2585,33 @@ fn dirCreateFileWindows(
2584 .OPEN_IF,2585 .OPEN_IF,
2585 });2586 });
2586 errdefer w.CloseHandle(handle);2587 errdefer w.CloseHandle(handle);
2588
2587 var io_status_block: w.IO_STATUS_BLOCK = undefined;2589 var io_status_block: w.IO_STATUS_BLOCK = undefined;
2588 const range_off: w.LARGE_INTEGER = 0;
2589 const range_len: w.LARGE_INTEGER = 1;
2590 const exclusive = switch (flags.lock) {2590 const exclusive = switch (flags.lock) {
2591 .none => return .{ .handle = handle },2591 .none => return .{ .handle = handle },
2592 .shared => false,2592 .shared => false,
2593 .exclusive => true,2593 .exclusive => true,
2594 };2594 };
2595 try w.LockFile(2595 const status = w.ntdll.NtLockFile(
2596 handle,2596 handle,
2597 null,2597 null,
2598 null,2598 null,
2599 null,2599 null,
2600 &io_status_block,2600 &io_status_block,
2601 &range_off,2601 &windows_lock_range_off,
2602 &range_len,2602 &windows_lock_range_len,
2603 null,2603 null,
2604 @intFromBool(flags.lock_nonblocking),2604 @intFromBool(flags.lock_nonblocking),
2605 @intFromBool(exclusive),2605 @intFromBool(exclusive),
2606 );2606 );
2607 switch (status) {
2608 .SUCCESS => {},
2609 .INSUFFICIENT_RESOURCES => return error.SystemResources,
2610 .LOCK_NOT_GRANTED => return error.WouldBlock,
2611 .ACCESS_VIOLATION => |err| return windows.statusBug(err), // bad io_status_block pointer
2612 else => return windows.unexpectedStatus(status),
2613 }
2614
2607 return .{ .handle = handle };2615 return .{ .handle = handle };
2608}2616}
26092617
...@@ -2992,25 +3000,30 @@ pub fn dirOpenFileWtf16(...@@ -2992,25 +3000,30 @@ pub fn dirOpenFileWtf16(
2992 };3000 };
2993 errdefer w.CloseHandle(handle);3001 errdefer w.CloseHandle(handle);
29943002
2995 const range_off: w.LARGE_INTEGER = 0;
2996 const range_len: w.LARGE_INTEGER = 1;
2997 const exclusive = switch (flags.lock) {3003 const exclusive = switch (flags.lock) {
2998 .none => return .{ .handle = handle },3004 .none => return .{ .handle = handle },
2999 .shared => false,3005 .shared => false,
3000 .exclusive => true,3006 .exclusive => true,
3001 };3007 };
3002 try w.LockFile(3008 const status = w.ntdll.NtLockFile(
3003 handle,3009 handle,
3004 null,3010 null,
3005 null,3011 null,
3006 null,3012 null,
3007 &io_status_block,3013 &io_status_block,
3008 &range_off,3014 &windows_lock_range_off,
3009 &range_len,3015 &windows_lock_range_len,
3010 null,3016 null,
3011 @intFromBool(flags.lock_nonblocking),3017 @intFromBool(flags.lock_nonblocking),
3012 @intFromBool(exclusive),3018 @intFromBool(exclusive),
3013 );3019 );
3020 switch (status) {
3021 .SUCCESS => {},
3022 .INSUFFICIENT_RESOURCES => return error.SystemResources,
3023 .LOCK_NOT_GRANTED => return error.WouldBlock,
3024 .ACCESS_VIOLATION => |err| return windows.statusBug(err), // bad io_status_block pointer
3025 else => return windows.unexpectedStatus(status),
3026 }
3014 return .{ .handle = handle };3027 return .{ .handle = handle };
3015}3028}
30163029
...@@ -3750,7 +3763,7 @@ fn dirReadWindows(userdata: ?*anyopaque, dr: *Dir.Reader, buffer: []Dir.Entry) D...@@ -3750,7 +3763,7 @@ fn dirReadWindows(userdata: ?*anyopaque, dr: *Dir.Reader, buffer: []Dir.Entry) D
3750 null,3763 null,
3751 &io_status_block,3764 &io_status_block,
3752 unreserved_buffer.ptr,3765 unreserved_buffer.ptr,
3753 unreserved_buffer.len,3766 std.math.cast(w.ULONG, unreserved_buffer.len) orelse std.math.maxInt(w.ULONG),
3754 .BothDirectory,3767 .BothDirectory,
3755 w.FALSE,3768 w.FALSE,
3756 null,3769 null,
...@@ -3849,15 +3862,14 @@ fn dirRealPathWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, out...@@ -3849,15 +3862,14 @@ fn dirRealPathWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, out
38493862
3850 var path_name_w = try w.sliceToPrefixedFileW(dir.handle, sub_path);3863 var path_name_w = try w.sliceToPrefixedFileW(dir.handle, sub_path);
38513864
3852 const access_mask = w.GENERIC_READ | w.SYNCHRONIZE;
3853 const share_access = w.FILE_SHARE_READ | w.FILE_SHARE_WRITE | w.FILE_SHARE_DELETE;
3854 const creation = w.FILE_OPEN;
3855 const h_file = blk: {3865 const h_file = blk: {
3856 const res = w.OpenFile(path_name_w.span(), .{3866 const res = w.OpenFile(path_name_w.span(), .{
3857 .dir = dir.handle,3867 .dir = dir.handle,
3858 .access_mask = access_mask,3868 .access_mask = .{
3859 .share_access = share_access,3869 .GENERIC = .{ .READ = true },
3860 .creation = creation,3870 .STANDARD = .{ .SYNCHRONIZE = true },
3871 },
3872 .creation = .OPEN,
3861 .filter = .any,3873 .filter = .any,
3862 }) catch |err| switch (err) {3874 }) catch |err| switch (err) {
3863 error.WouldBlock => unreachable,3875 error.WouldBlock => unreachable,
...@@ -4220,7 +4232,8 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov...@@ -4220,7 +4232,8 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov
42204232
4221 try current_thread.checkCancel();4233 try current_thread.checkCancel();
42224234
4223 const sub_path_w = try w.sliceToPrefixedFileW(dir.handle, sub_path);4235 const sub_path_w_buf = try w.sliceToPrefixedFileW(dir.handle, sub_path);
4236 const sub_path_w = sub_path_w_buf.span();
42244237
4225 const path_len_bytes = @as(u16, @intCast(sub_path_w.len * 2));4238 const path_len_bytes = @as(u16, @intCast(sub_path_w.len * 2));
4226 var nt_name: w.UNICODE_STRING = .{4239 var nt_name: w.UNICODE_STRING = .{
...@@ -4239,31 +4252,32 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov...@@ -4239,31 +4252,32 @@ fn dirDeleteWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, remov
4239 return error.FileBusy;4252 return error.FileBusy;
4240 }4253 }
42414254
4242 const create_options_flags: w.ULONG = if (remove_dir)
4243 w.FILE_DIRECTORY_FILE | w.FILE_OPEN_REPARSE_POINT
4244 else
4245 w.FILE_NON_DIRECTORY_FILE | w.FILE_OPEN_REPARSE_POINT;
4246
4247 var attr: w.OBJECT_ATTRIBUTES = .{
4248 .Length = @sizeOf(w.OBJECT_ATTRIBUTES),
4249 .RootDirectory = if (std.fs.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle,
4250 .Attributes = w.OBJ_CASE_INSENSITIVE,
4251 .ObjectName = &nt_name,
4252 .SecurityDescriptor = null,
4253 .SecurityQualityOfService = null,
4254 };
4255 var io_status_block: w.IO_STATUS_BLOCK = undefined;4255 var io_status_block: w.IO_STATUS_BLOCK = undefined;
4256 var tmp_handle: w.HANDLE = undefined;4256 var tmp_handle: w.HANDLE = undefined;
4257 var rc = w.ntdll.NtCreateFile(4257 var rc = w.ntdll.NtCreateFile(
4258 &tmp_handle,4258 &tmp_handle,
4259 w.SYNCHRONIZE | w.DELETE,4259 .{ .STANDARD = .{
4260 &attr,4260 .RIGHTS = .{ .DELETE = true },
4261 .SYNCHRONIZE = true,
4262 } },
4263 &.{
4264 .Length = @sizeOf(w.OBJECT_ATTRIBUTES),
4265 .RootDirectory = if (std.fs.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle,
4266 .Attributes = .{},
4267 .ObjectName = &nt_name,
4268 .SecurityDescriptor = null,
4269 .SecurityQualityOfService = null,
4270 },
4261 &io_status_block,4271 &io_status_block,
4262 null,4272 null,
4263 0,4273 .{},
4264 w.FILE_SHARE_READ | w.FILE_SHARE_WRITE | w.FILE_SHARE_DELETE,4274 .VALID_FLAGS,
4265 w.FILE_OPEN,4275 .OPEN,
4266 create_options_flags,4276 .{
4277 .DIRECTORY_FILE = remove_dir,
4278 .NON_DIRECTORY_FILE = !remove_dir,
4279 .OPEN_REPARSE_POINT = true, // would we ever want to delete the target instead?
4280 },
4267 null,4281 null,
4268 0,4282 0,
4269 );4283 );
...@@ -4463,16 +4477,24 @@ fn dirRenameWindows(...@@ -4463,16 +4477,24 @@ fn dirRenameWindows(
4463 const t: *Threaded = @ptrCast(@alignCast(userdata));4477 const t: *Threaded = @ptrCast(@alignCast(userdata));
4464 const current_thread = Thread.getCurrent(t);4478 const current_thread = Thread.getCurrent(t);
44654479
4466 const old_path_w = try windows.sliceToPrefixedFileW(old_dir.handle, old_sub_path);4480 const old_path_w_buf = try windows.sliceToPrefixedFileW(old_dir.handle, old_sub_path);
4467 const new_path_w = try windows.sliceToPrefixedFileW(new_dir.handle, new_sub_path);4481 const old_path_w = old_path_w_buf.span();
4482 const new_path_w_buf = try windows.sliceToPrefixedFileW(new_dir.handle, new_sub_path);
4483 const new_path_w = new_path_w_buf.span();
4468 const replace_if_exists = true;4484 const replace_if_exists = true;
44694485
4470 try current_thread.checkCancel();4486 try current_thread.checkCancel();
44714487
4472 const src_fd = w.OpenFile(old_path_w, .{4488 const src_fd = w.OpenFile(old_path_w, .{
4473 .dir = old_dir.handle,4489 .dir = old_dir.handle,
4474 .access_mask = w.SYNCHRONIZE | w.GENERIC_WRITE | w.DELETE,4490 .access_mask = .{
4475 .creation = w.FILE_OPEN,4491 .GENERIC = .{ .WRITE = true },
4492 .STANDARD = .{
4493 .RIGHTS = .{ .DELETE = true },
4494 .SYNCHRONIZE = true,
4495 },
4496 },
4497 .creation = .OPEN,
4476 .filter = .any, // This function is supposed to rename both files and directories.4498 .filter = .any, // This function is supposed to rename both files and directories.
4477 .follow_symlinks = false,4499 .follow_symlinks = false,
4478 }) catch |err| switch (err) {4500 }) catch |err| switch (err) {
...@@ -4729,9 +4751,12 @@ fn dirSymLinkWindows(...@@ -4729,9 +4751,12 @@ fn dirSymLinkWindows(
4729 };4751 };
47304752
4731 const symlink_handle = w.OpenFile(sym_link_path_w.span(), .{4753 const symlink_handle = w.OpenFile(sym_link_path_w.span(), .{
4732 .access_mask = w.SYNCHRONIZE | w.GENERIC_READ | w.GENERIC_WRITE,4754 .access_mask = .{
4755 .GENERIC = .{ .READ = true, .WRITE = true },
4756 .STANDARD = .{ .SYNCHRONIZE = true },
4757 },
4733 .dir = dir,4758 .dir = dir,
4734 .creation = w.FILE_CREATE,4759 .creation = .CREATE,
4735 .filter = if (flags.is_directory) .dir_only else .non_directory_only,4760 .filter = if (flags.is_directory) .dir_only else .non_directory_only,
4736 }) catch |err| switch (err) {4761 }) catch |err| switch (err) {
4737 error.IsDir => return error.PathAlreadyExists,4762 error.IsDir => return error.PathAlreadyExists,
...@@ -4913,55 +4938,14 @@ fn dirReadLinkWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, buf...@@ -4913,55 +4938,14 @@ fn dirReadLinkWindows(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, buf
49134938
4914 try current_thread.checkCancel();4939 try current_thread.checkCancel();
49154940
4916 var sub_path_w = try windows.sliceToPrefixedFileW(dir.handle, sub_path);4941 var sub_path_w_buf = try windows.sliceToPrefixedFileW(dir.handle, sub_path);
49174942
4918 const result_handle = w.OpenFile(sub_path_w.span(), .{4943 const result_w = try w.ReadLink(dir.handle, sub_path_w_buf.span(), &sub_path_w_buf.data);
4919 .access_mask = w.FILE_READ_ATTRIBUTES | w.SYNCHRONIZE,
4920 .dir = dir,
4921 .creation = w.FILE_OPEN,
4922 .follow_symlinks = false,
4923 .filter = .any,
4924 }) catch |err| switch (err) {
4925 error.IsDir, error.NotDir => return error.Unexpected, // filter = .any
4926 error.PathAlreadyExists => return error.Unexpected, // FILE_OPEN
4927 error.WouldBlock => return error.Unexpected,
4928 error.NoDevice => return error.FileNotFound,
4929 error.PipeBusy => return error.AccessDenied,
4930 else => |e| return e,
4931 };
4932 defer w.CloseHandle(result_handle);
4933
4934 var reparse_buf: [w.MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 align(@alignOf(w.REPARSE_DATA_BUFFER)) = undefined;
4935 _ = w.DeviceIoControl(result_handle, w.FSCTL_GET_REPARSE_POINT, null, reparse_buf[0..]) catch |err| switch (err) {
4936 error.AccessDenied => return error.Unexpected,
4937 error.UnrecognizedVolume => return error.Unexpected,
4938 else => |e| return e,
4939 };
4940
4941 const reparse_struct: *const w.REPARSE_DATA_BUFFER = @ptrCast(@alignCast(&reparse_buf[0]));
4942 const wide_result = switch (reparse_struct.ReparseTag) {
4943 w.IO_REPARSE_TAG_SYMLINK => r: {
4944 const buf: *const w.SYMBOLIC_LINK_REPARSE_BUFFER = @ptrCast(@alignCast(&reparse_struct.DataBuffer[0]));
4945 const offset = buf.SubstituteNameOffset >> 1;
4946 const len = buf.SubstituteNameLength >> 1;
4947 const path_buf: [*]const u16 = &buf.PathBuffer;
4948 const is_relative = buf.Flags & w.SYMLINK_FLAG_RELATIVE != 0;
4949 break :r try w.parseReadLinkPath(path_buf[offset..][0..len], is_relative, buffer);
4950 },
4951 w.IO_REPARSE_TAG_MOUNT_POINT => r: {
4952 const buf: *const w.MOUNT_POINT_REPARSE_BUFFER = @ptrCast(@alignCast(&reparse_struct.DataBuffer[0]));
4953 const offset = buf.SubstituteNameOffset >> 1;
4954 const len = buf.SubstituteNameLength >> 1;
4955 const path_buf: [*]const u16 = &buf.PathBuffer;
4956 break :r try w.parseReadLinkPath(path_buf[offset..][0..len], false, buffer);
4957 },
4958 else => return error.UnsupportedReparsePointType,
4959 };
49604944
4961 const len = std.unicode.calcWtf8Len(wide_result);4945 const len = std.unicode.calcWtf8Len(result_w);
4962 if (len > buffer.len) return error.NameTooLong;4946 if (len > buffer.len) return error.NameTooLong;
49634947
4964 return std.unicode.wtf16LeToWtf8(buffer, wide_result);4948 return std.unicode.wtf16LeToWtf8(buffer, result_w);
4965}4949}
49664950
4967fn dirReadLinkWasi(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLinkError!usize {4951fn dirReadLinkWasi(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLinkError!usize {
...@@ -6061,10 +6045,9 @@ fn fileTryLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockErro...@@ -6061,10 +6045,9 @@ fn fileTryLock(userdata: ?*anyopaque, file: File, lock: File.Lock) File.LockErro
60616045
6062fn fileUnlock(userdata: ?*anyopaque, file: File) void {6046fn fileUnlock(userdata: ?*anyopaque, file: File) void {
6063 const t: *Threaded = @ptrCast(@alignCast(userdata));6047 const t: *Threaded = @ptrCast(@alignCast(userdata));
6064 const current_thread = Thread.getCurrent(t);6048 _ = t;
60656049
6066 if (is_windows) {6050 if (is_windows) {
6067 try current_thread.checkCancel();
6068 var io_status_block: windows.IO_STATUS_BLOCK = undefined;6051 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
6069 const status = windows.ntdll.NtUnlockFile(6052 const status = windows.ntdll.NtUnlockFile(
6070 file.handle,6053 file.handle,
...@@ -6131,7 +6114,7 @@ fn fileDowngradeLock(userdata: ?*anyopaque, file: File) File.DowngradeLockError!...@@ -6131,7 +6114,7 @@ fn fileDowngradeLock(userdata: ?*anyopaque, file: File) File.DowngradeLockError!
6131 &io_status_block,6114 &io_status_block,
6132 &windows_lock_range_off,6115 &windows_lock_range_off,
6133 &windows_lock_range_len,6116 &windows_lock_range_len,
6134 null,6117 0,
6135 );6118 );
6136 if (is_debug) switch (status) {6119 if (is_debug) switch (status) {
6137 .SUCCESS => {},6120 .SUCCESS => {},
...@@ -6841,17 +6824,16 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) std.process.Ex...@@ -6841,17 +6824,16 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) std.process.Ex
6841 // If ImagePathName is a symlink, then it will contain the path of the6824 // If ImagePathName is a symlink, then it will contain the path of the
6842 // symlink, not the path that the symlink points to. We want the path6825 // symlink, not the path that the symlink points to. We want the path
6843 // that the symlink points to, though, so we need to get the realpath.6826 // that the symlink points to, though, so we need to get the realpath.
6844 var path_name_w = try w.wToPrefixedFileW(null, image_path_name);6827 var path_name_w_buf = try w.wToPrefixedFileW(null, image_path_name);
68456828
6846 const access_mask = w.GENERIC_READ | w.SYNCHRONIZE;
6847 const share_access = w.FILE_SHARE_READ | w.FILE_SHARE_WRITE | w.FILE_SHARE_DELETE;
6848 const creation = w.FILE_OPEN;
6849 const h_file = blk: {6829 const h_file = blk: {
6850 const res = w.OpenFile(path_name_w.span(), .{6830 const res = w.OpenFile(path_name_w_buf.span(), .{
6851 .dir = null,6831 .dir = null,
6852 .access_mask = access_mask,6832 .access_mask = .{
6853 .share_access = share_access,6833 .GENERIC = .{ .READ = true },
6854 .creation = creation,6834 .STANDARD = .{ .SYNCHRONIZE = true },
6835 },
6836 .creation = .OPEN,
6855 .filter = .any,6837 .filter = .any,
6856 }) catch |err| switch (err) {6838 }) catch |err| switch (err) {
6857 error.WouldBlock => unreachable,6839 error.WouldBlock => unreachable,
...@@ -6861,7 +6843,7 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) std.process.Ex...@@ -6861,7 +6843,7 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) std.process.Ex
6861 };6843 };
6862 defer w.CloseHandle(h_file);6844 defer w.CloseHandle(h_file);
68636845
6864 const wide_slice = w.GetFinalPathNameByHandle(h_file, .{}, out_buffer);6846 const wide_slice = try w.GetFinalPathNameByHandle(h_file, .{}, &path_name_w_buf.data);
68656847
6866 const len = std.unicode.calcWtf8Len(wide_slice);6848 const len = std.unicode.calcWtf8Len(wide_slice);
6867 if (len > out_buffer.len)6849 if (len > out_buffer.len)
lib/std/debug/SelfInfo/Windows.zig+1-2
...@@ -222,7 +222,7 @@ const Module = struct {...@@ -222,7 +222,7 @@ const Module = struct {
222 pdb.file_reader.file.close(io);222 pdb.file_reader.file.close(io);
223 pdb.deinit();223 pdb.deinit();
224 }224 }
225 if (di.mapped_file) |*mf| mf.deinit();225 if (di.mapped_file) |*mf| mf.deinit(io);
226226
227 var arena = di.arena.promote(gpa);227 var arena = di.arena.promote(gpa);
228 arena.deinit();228 arena.deinit();
...@@ -331,7 +331,6 @@ const Module = struct {...@@ -331,7 +331,6 @@ const Module = struct {
331 error.SystemResources,331 error.SystemResources,
332 error.WouldBlock,332 error.WouldBlock,
333 error.AccessDenied,333 error.AccessDenied,
334 error.ProcessNotFound,
335 error.PermissionDenied,334 error.PermissionDenied,
336 error.NoSpaceLeft,335 error.NoSpaceLeft,
337 error.DeviceBusy,336 error.DeviceBusy,
lib/std/fs/test.zig+82-71
...@@ -27,7 +27,7 @@ const PathType = enum {...@@ -27,7 +27,7 @@ const PathType = enum {
27 pub fn isSupported(self: PathType, target_os: std.Target.Os) bool {27 pub fn isSupported(self: PathType, target_os: std.Target.Os) bool {
28 return switch (self) {28 return switch (self) {
29 .relative => true,29 .relative => true,
30 .absolute => std.os.isGetFdPathSupportedOnTarget(target_os),30 .absolute => target_os.tag == .windows, // TODO: implement getPathForHandle for other targets
31 .unc => target_os.tag == .windows,31 .unc => target_os.tag == .windows,
32 };32 };
33 }33 }
...@@ -49,7 +49,7 @@ const PathType = enum {...@@ -49,7 +49,7 @@ const PathType = enum {
49 // The final path may not actually exist which would cause realpath to fail.49 // The final path may not actually exist which would cause realpath to fail.
50 // So instead, we get the path of the dir and join it with the relative path.50 // So instead, we get the path of the dir and join it with the relative path.
51 var fd_path_buf: [Dir.max_path_bytes]u8 = undefined;51 var fd_path_buf: [Dir.max_path_bytes]u8 = undefined;
52 const dir_path = try std.os.getFdPath(dir.handle, &fd_path_buf);52 const dir_path = try getPathForHandle(dir.handle, &fd_path_buf);
53 return Dir.path.joinZ(allocator, &.{ dir_path, relative_path });53 return Dir.path.joinZ(allocator, &.{ dir_path, relative_path });
54 }54 }
55 }.transform,55 }.transform,
...@@ -58,7 +58,7 @@ const PathType = enum {...@@ -58,7 +58,7 @@ const PathType = enum {
58 // Any drive absolute path (C:\foo) can be converted into a UNC path by58 // Any drive absolute path (C:\foo) can be converted into a UNC path by
59 // using '127.0.0.1' as the server name and '<drive letter>$' as the share name.59 // using '127.0.0.1' as the server name and '<drive letter>$' as the share name.
60 var fd_path_buf: [Dir.max_path_bytes]u8 = undefined;60 var fd_path_buf: [Dir.max_path_bytes]u8 = undefined;
61 const dir_path = try std.os.getFdPath(dir.handle, &fd_path_buf);61 const dir_path = try getPathForHandle(dir.handle, &fd_path_buf);
62 const windows_path_type = windows.getWin32PathType(u8, dir_path);62 const windows_path_type = windows.getWin32PathType(u8, dir_path);
63 switch (windows_path_type) {63 switch (windows_path_type) {
64 .unc_absolute => return Dir.path.joinZ(allocator, &.{ dir_path, relative_path }),64 .unc_absolute => return Dir.path.joinZ(allocator, &.{ dir_path, relative_path }),
...@@ -77,6 +77,19 @@ const PathType = enum {...@@ -77,6 +77,19 @@ const PathType = enum {
77 }77 }
78};78};
7979
80fn getPathForHandle(handle: File.Handle, out_buffer: *[Dir.max_path_bytes]u8) ![]u8 {
81 switch (native_os) {
82 .windows => {
83 var wide_buf: [windows.PATH_MAX_WIDE]u16 = undefined;
84 const wide_slice = try windows.GetFinalPathNameByHandle(handle, .{}, wide_buf[0..]);
85
86 const end_index = std.unicode.wtf16LeToWtf8(out_buffer, wide_slice);
87 return out_buffer[0..end_index];
88 },
89 else => @compileError("TODO or unsupported"),
90 }
91}
92
80const TestContext = struct {93const TestContext = struct {
81 io: Io,94 io: Io,
82 path_type: PathType,95 path_type: PathType,
...@@ -488,16 +501,16 @@ test "Dir.Iterator" {...@@ -488,16 +501,16 @@ test "Dir.Iterator" {
488501
489 // Create iterator.502 // Create iterator.
490 var iter = tmp_dir.dir.iterate();503 var iter = tmp_dir.dir.iterate();
491 while (try iter.next()) |entry| {504 while (try iter.next(io)) |entry| {
492 // We cannot just store `entry` as on Windows, we're re-using the name buffer505 // We cannot just store `entry` as on Windows, we're re-using the name buffer
493 // which means we'll actually share the `name` pointer between entries!506 // which means we'll actually share the `name` pointer between entries!
494 const name = try allocator.dupe(u8, entry.name);507 const name = try allocator.dupe(u8, entry.name);
495 try entries.append(Dir.Entry{ .name = name, .kind = entry.kind });508 try entries.append(Dir.Entry{ .name = name, .kind = entry.kind, .inode = 0 });
496 }509 }
497510
498 try expectEqual(@as(usize, 2), entries.items.len); // note that the Iterator skips '.' and '..'511 try expectEqual(@as(usize, 2), entries.items.len); // note that the Iterator skips '.' and '..'
499 try expect(contains(&entries, .{ .name = "some_file", .kind = .file }));512 try expect(contains(&entries, .{ .name = "some_file", .kind = .file, .inode = 0 }));
500 try expect(contains(&entries, .{ .name = "some_dir", .kind = .directory }));513 try expect(contains(&entries, .{ .name = "some_dir", .kind = .directory, .inode = 0 }));
501}514}
502515
503test "Dir.Iterator many entries" {516test "Dir.Iterator many entries" {
...@@ -523,17 +536,17 @@ test "Dir.Iterator many entries" {...@@ -523,17 +536,17 @@ test "Dir.Iterator many entries" {
523536
524 // Create iterator.537 // Create iterator.
525 var iter = tmp_dir.dir.iterate();538 var iter = tmp_dir.dir.iterate();
526 while (try iter.next()) |entry| {539 while (try iter.next(io)) |entry| {
527 // We cannot just store `entry` as on Windows, we're re-using the name buffer540 // We cannot just store `entry` as on Windows, we're re-using the name buffer
528 // which means we'll actually share the `name` pointer between entries!541 // which means we'll actually share the `name` pointer between entries!
529 const name = try allocator.dupe(u8, entry.name);542 const name = try allocator.dupe(u8, entry.name);
530 try entries.append(.{ .name = name, .kind = entry.kind });543 try entries.append(.{ .name = name, .kind = entry.kind, .inode = 0 });
531 }544 }
532545
533 i = 0;546 i = 0;
534 while (i < num) : (i += 1) {547 while (i < num) : (i += 1) {
535 const name = try std.fmt.bufPrint(&buf, "{}", .{i});548 const name = try std.fmt.bufPrint(&buf, "{}", .{i});
536 try expect(contains(&entries, .{ .name = name, .kind = .file }));549 try expect(contains(&entries, .{ .name = name, .kind = .file, .inode = 0 }));
537 }550 }
538}551}
539552
...@@ -559,16 +572,16 @@ test "Dir.Iterator twice" {...@@ -559,16 +572,16 @@ test "Dir.Iterator twice" {
559572
560 // Create iterator.573 // Create iterator.
561 var iter = tmp_dir.dir.iterate();574 var iter = tmp_dir.dir.iterate();
562 while (try iter.next()) |entry| {575 while (try iter.next(io)) |entry| {
563 // We cannot just store `entry` as on Windows, we're re-using the name buffer576 // We cannot just store `entry` as on Windows, we're re-using the name buffer
564 // which means we'll actually share the `name` pointer between entries!577 // which means we'll actually share the `name` pointer between entries!
565 const name = try allocator.dupe(u8, entry.name);578 const name = try allocator.dupe(u8, entry.name);
566 try entries.append(Dir.Entry{ .name = name, .kind = entry.kind });579 try entries.append(Dir.Entry{ .name = name, .kind = entry.kind, .inode = 0 });
567 }580 }
568581
569 try expectEqual(@as(usize, 2), entries.items.len); // note that the Iterator skips '.' and '..'582 try expectEqual(@as(usize, 2), entries.items.len); // note that the Iterator skips '.' and '..'
570 try expect(contains(&entries, .{ .name = "some_file", .kind = .file }));583 try expect(contains(&entries, .{ .name = "some_file", .kind = .file, .inode = 0 }));
571 try expect(contains(&entries, .{ .name = "some_dir", .kind = .directory }));584 try expect(contains(&entries, .{ .name = "some_dir", .kind = .directory, .inode = 0 }));
572 }585 }
573}586}
574587
...@@ -595,18 +608,18 @@ test "Dir.Iterator reset" {...@@ -595,18 +608,18 @@ test "Dir.Iterator reset" {
595 while (i < 2) : (i += 1) {608 while (i < 2) : (i += 1) {
596 var entries = std.array_list.Managed(Dir.Entry).init(allocator);609 var entries = std.array_list.Managed(Dir.Entry).init(allocator);
597610
598 while (try iter.next()) |entry| {611 while (try iter.next(io)) |entry| {
599 // We cannot just store `entry` as on Windows, we're re-using the name buffer612 // We cannot just store `entry` as on Windows, we're re-using the name buffer
600 // which means we'll actually share the `name` pointer between entries!613 // which means we'll actually share the `name` pointer between entries!
601 const name = try allocator.dupe(u8, entry.name);614 const name = try allocator.dupe(u8, entry.name);
602 try entries.append(.{ .name = name, .kind = entry.kind });615 try entries.append(.{ .name = name, .kind = entry.kind, .inode = 0 });
603 }616 }
604617
605 try expectEqual(@as(usize, 2), entries.items.len); // note that the Iterator skips '.' and '..'618 try expectEqual(@as(usize, 2), entries.items.len); // note that the Iterator skips '.' and '..'
606 try expect(contains(&entries, .{ .name = "some_file", .kind = .file }));619 try expect(contains(&entries, .{ .name = "some_file", .kind = .file, .inode = 0 }));
607 try expect(contains(&entries, .{ .name = "some_dir", .kind = .directory }));620 try expect(contains(&entries, .{ .name = "some_dir", .kind = .directory, .inode = 0 }));
608621
609 iter.reset();622 iter.reader.reset();
610 }623 }
611}624}
612625
...@@ -617,7 +630,7 @@ test "Dir.Iterator but dir is deleted during iteration" {...@@ -617,7 +630,7 @@ test "Dir.Iterator but dir is deleted during iteration" {
617 defer tmp.cleanup();630 defer tmp.cleanup();
618631
619 // Create directory and setup an iterator for it632 // Create directory and setup an iterator for it
620 var subdir = try tmp.dir.makeOpenPath(io, "subdir", .{ .iterate = true });633 var subdir = try tmp.dir.makeOpenPath(io, "subdir", .{ .open_options = .{ .iterate = true } });
621 defer subdir.close(io);634 defer subdir.close(io);
622635
623 var iterator = subdir.iterate();636 var iterator = subdir.iterate();
...@@ -632,8 +645,8 @@ test "Dir.Iterator but dir is deleted during iteration" {...@@ -632,8 +645,8 @@ test "Dir.Iterator but dir is deleted during iteration" {
632 tmp.dir.deleteTree(io, "subdir") catch return error.SkipZigTest;645 tmp.dir.deleteTree(io, "subdir") catch return error.SkipZigTest;
633646
634 // Now, when we try to iterate, the next call should return null immediately.647 // Now, when we try to iterate, the next call should return null immediately.
635 const entry = try iterator.next();648 const entry = try iterator.next(io);
636 try std.expect(entry == null);649 try testing.expect(entry == null);
637650
638 // On Linux, we can opt-in to receiving a more specific error by calling `nextLinux`651 // On Linux, we can opt-in to receiving a more specific error by calling `nextLinux`
639 if (native_os == .linux) {652 if (native_os == .linux) {
...@@ -652,8 +665,8 @@ fn contains(entries: *const std.array_list.Managed(Dir.Entry), el: Dir.Entry) bo...@@ -652,8 +665,8 @@ fn contains(entries: *const std.array_list.Managed(Dir.Entry), el: Dir.Entry) bo
652 return false;665 return false;
653}666}
654667
655test "Dir.realpath smoke test" {668test "Dir.realPath smoke test" {
656 if (!comptime std.os.isGetFdPathSupportedOnTarget(builtin.os)) return error.SkipZigTest;669 if (native_os == .wasi) return error.SkipZigTest;
657670
658 try testWithAllSupportedPathTypes(struct {671 try testWithAllSupportedPathTypes(struct {
659 fn impl(ctx: *TestContext) !void {672 fn impl(ctx: *TestContext) !void {
...@@ -686,10 +699,10 @@ test "Dir.realpath smoke test" {...@@ -686,10 +699,10 @@ test "Dir.realpath smoke test" {
686699
687 // First, test non-alloc version700 // First, test non-alloc version
688 {701 {
689 const file_path = try ctx.dir.realpath(test_file_path, &buf);702 const file_path = try ctx.dir.realPath(io, test_file_path, &buf);
690 try expectEqualStrings(expected_file_path, file_path);703 try expectEqualStrings(expected_file_path, file_path);
691704
692 const dir_path = try ctx.dir.realpath(test_dir_path, &buf);705 const dir_path = try ctx.dir.realPath(io, test_dir_path, &buf);
693 try expectEqualStrings(expected_dir_path, dir_path);706 try expectEqualStrings(expected_dir_path, dir_path);
694 }707 }
695708
...@@ -769,7 +782,7 @@ test "Dir.statFile" {...@@ -769,7 +782,7 @@ test "Dir.statFile" {
769782
770 try expectError(error.FileNotFound, ctx.dir.statFile(io, test_dir_name, .{}));783 try expectError(error.FileNotFound, ctx.dir.statFile(io, test_dir_name, .{}));
771784
772 try ctx.dir.makeDir(io, test_dir_name);785 try ctx.dir.makeDir(io, test_dir_name, .default_dir);
773786
774 const stat = try ctx.dir.statFile(io, test_dir_name, .{});787 const stat = try ctx.dir.statFile(io, test_dir_name, .{});
775 try expectEqual(.directory, stat.kind);788 try expectEqual(.directory, stat.kind);
...@@ -1148,7 +1161,7 @@ test "openExecutable" {...@@ -1148,7 +1161,7 @@ test "openExecutable" {
11481161
1149 const io = testing.io;1162 const io = testing.io;
11501163
1151 const self_exe_file = try std.fs.openExecutable(.{});1164 const self_exe_file = try std.process.openExecutable(io, .{});
1152 self_exe_file.close(io);1165 self_exe_file.close(io);
1153}1166}
11541167
...@@ -1157,7 +1170,8 @@ test "executablePath" {...@@ -1157,7 +1170,8 @@ test "executablePath" {
11571170
1158 const io = testing.io;1171 const io = testing.io;
1159 var buf: [Dir.max_path_bytes]u8 = undefined;1172 var buf: [Dir.max_path_bytes]u8 = undefined;
1160 const buf_self_exe_path = try std.process.executablePath(io, &buf);1173 const len = try std.process.executablePath(io, &buf);
1174 const buf_self_exe_path = buf[0..len];
1161 const alloc_self_exe_path = try std.process.executablePathAlloc(io, testing.allocator);1175 const alloc_self_exe_path = try std.process.executablePathAlloc(io, testing.allocator);
1162 defer testing.allocator.free(alloc_self_exe_path);1176 defer testing.allocator.free(alloc_self_exe_path);
1163 try expectEqualSlices(u8, buf_self_exe_path, alloc_self_exe_path);1177 try expectEqualSlices(u8, buf_self_exe_path, alloc_self_exe_path);
...@@ -1246,7 +1260,7 @@ test "makePath, put some files in it, deleteTreeMinStackSize" {...@@ -1246,7 +1260,7 @@ test "makePath, put some files in it, deleteTreeMinStackSize" {
1246 .data = "blah",1260 .data = "blah",
1247 });1261 });
12481262
1249 try ctx.dir.deleteTreeMinStackSize(dir_path);1263 try ctx.dir.deleteTreeMinStackSize(io, dir_path);
1250 try expectError(error.FileNotFound, ctx.dir.openDir(io, dir_path, .{}));1264 try expectError(error.FileNotFound, ctx.dir.openDir(io, dir_path, .{}));
1251 }1265 }
1252 }.impl);1266 }.impl);
...@@ -1395,7 +1409,7 @@ fn testFilenameLimits(io: Io, iterable_dir: Dir, maxed_filename: []const u8) !vo...@@ -1395,7 +1409,7 @@ fn testFilenameLimits(io: Io, iterable_dir: Dir, maxed_filename: []const u8) !vo
1395 defer walker.deinit();1409 defer walker.deinit();
13961410
1397 var count: usize = 0;1411 var count: usize = 0;
1398 while (try walker.next()) |entry| {1412 while (try walker.next(io)) |entry| {
1399 try expectEqualStrings(maxed_filename, entry.basename);1413 try expectEqualStrings(maxed_filename, entry.basename);
1400 count += 1;1414 count += 1;
1401 }1415 }
...@@ -1452,7 +1466,7 @@ test "writev, readv" {...@@ -1452,7 +1466,7 @@ test "writev, readv" {
1452 try writer.interface.flush();1466 try writer.interface.flush();
1453 try expectEqual(@as(u64, line1.len + line2.len), try src_file.length(io));1467 try expectEqual(@as(u64, line1.len + line2.len), try src_file.length(io));
14541468
1455 var reader = writer.moveToReader(io);1469 var reader = writer.moveToReader();
1456 try reader.seekTo(0);1470 try reader.seekTo(0);
1457 try reader.interface.readVecAll(&read_vecs);1471 try reader.interface.readVecAll(&read_vecs);
1458 try expectEqualStrings(&buf1, "line2\n");1472 try expectEqualStrings(&buf1, "line2\n");
...@@ -1483,7 +1497,7 @@ test "pwritev, preadv" {...@@ -1483,7 +1497,7 @@ test "pwritev, preadv" {
1483 try writer.interface.flush();1497 try writer.interface.flush();
1484 try expectEqual(@as(u64, 16 + line1.len + line2.len), try src_file.length(io));1498 try expectEqual(@as(u64, 16 + line1.len + line2.len), try src_file.length(io));
14851499
1486 var reader = writer.moveToReader(io);1500 var reader = writer.moveToReader();
1487 try reader.seekTo(16);1501 try reader.seekTo(16);
1488 try reader.interface.readVecAll(&read_vecs);1502 try reader.interface.readVecAll(&read_vecs);
1489 try expectEqualStrings(&buf1, "line2\n");1503 try expectEqualStrings(&buf1, "line2\n");
...@@ -1549,7 +1563,7 @@ test "sendfile" {...@@ -1549,7 +1563,7 @@ test "sendfile" {
1549 try expectEqual(10, try file_writer.interface.sendFileAll(&file_reader, .limited(10)));1563 try expectEqual(10, try file_writer.interface.sendFileAll(&file_reader, .limited(10)));
1550 try file_writer.interface.writeVecAll(&trailers);1564 try file_writer.interface.writeVecAll(&trailers);
1551 try file_writer.interface.flush();1565 try file_writer.interface.flush();
1552 var fr = file_writer.moveToReader(io);1566 var fr = file_writer.moveToReader();
1553 try fr.seekTo(0);1567 try fr.seekTo(0);
1554 const amt = try fr.interface.readSliceShort(&written_buf);1568 const amt = try fr.interface.readSliceShort(&written_buf);
1555 try expectEqualStrings("header1\nsecond header\nine1\nsecontrailer1\nsecond trailer\n", written_buf[0..amt]);1569 try expectEqualStrings("header1\nsecond header\nine1\nsecontrailer1\nsecond trailer\n", written_buf[0..amt]);
...@@ -1586,7 +1600,7 @@ test "sendfile with buffered data" {...@@ -1586,7 +1600,7 @@ test "sendfile with buffered data" {
1586 try expectEqual(4, try file_writer.interface.sendFileAll(&file_reader, .limited(4)));1600 try expectEqual(4, try file_writer.interface.sendFileAll(&file_reader, .limited(4)));
15871601
1588 var written_buf: [8]u8 = undefined;1602 var written_buf: [8]u8 = undefined;
1589 var fr = file_writer.moveToReader(io);1603 var fr = file_writer.moveToReader();
1590 try fr.seekTo(0);1604 try fr.seekTo(0);
1591 const amt = try fr.interface.readSliceShort(&written_buf);1605 const amt = try fr.interface.readSliceShort(&written_buf);
15921606
...@@ -1609,7 +1623,7 @@ test "copyFile" {...@@ -1609,7 +1623,7 @@ test "copyFile" {
1609 try ctx.dir.copyFile(src_file, ctx.dir, dest_file, io, .{});1623 try ctx.dir.copyFile(src_file, ctx.dir, dest_file, io, .{});
1610 defer ctx.dir.deleteFile(io, dest_file) catch {};1624 defer ctx.dir.deleteFile(io, dest_file) catch {};
16111625
1612 try ctx.dir.copyFile(src_file, ctx.dir, dest_file2, io, .{ .permissions = File.default_mode });1626 try ctx.dir.copyFile(src_file, ctx.dir, dest_file2, io, .{ .permissions = .default_file });
1613 defer ctx.dir.deleteFile(io, dest_file2) catch {};1627 defer ctx.dir.deleteFile(io, dest_file2) catch {};
16141628
1615 try expectFileContents(io, ctx.dir, dest_file, data);1629 try expectFileContents(io, ctx.dir, dest_file, data);
...@@ -1714,12 +1728,12 @@ test "open file with exclusive lock twice, make sure second lock waits" {...@@ -1714,12 +1728,12 @@ test "open file with exclusive lock twice, make sure second lock waits" {
1714 errdefer file.close(io);1728 errdefer file.close(io);
17151729
1716 const S = struct {1730 const S = struct {
1717 fn checkFn(dir: *Dir, path: []const u8, started: *std.Thread.ResetEvent, locked: *std.Thread.ResetEvent) !void {1731 fn checkFn(inner_ctx: *TestContext, path: []const u8, started: *std.Thread.ResetEvent, locked: *std.Thread.ResetEvent) !void {
1718 started.set();1732 started.set();
1719 const file1 = try dir.createFile(io, path, .{ .lock = .exclusive });1733 const file1 = try inner_ctx.dir.createFile(inner_ctx.io, path, .{ .lock = .exclusive });
17201734
1721 locked.set();1735 locked.set();
1722 file1.close(io);1736 file1.close(inner_ctx.io);
1723 }1737 }
1724 };1738 };
17251739
...@@ -1727,7 +1741,7 @@ test "open file with exclusive lock twice, make sure second lock waits" {...@@ -1727,7 +1741,7 @@ test "open file with exclusive lock twice, make sure second lock waits" {
1727 var locked: std.Thread.ResetEvent = .unset;1741 var locked: std.Thread.ResetEvent = .unset;
17281742
1729 const t = try std.Thread.spawn(.{}, S.checkFn, .{1743 const t = try std.Thread.spawn(.{}, S.checkFn, .{
1730 &ctx.dir,1744 ctx,
1731 filename,1745 filename,
1732 &started,1746 &started,
1733 &locked,1747 &locked,
...@@ -1848,7 +1862,7 @@ test "walker" {...@@ -1848,7 +1862,7 @@ test "walker" {
1848 defer walker.deinit();1862 defer walker.deinit();
18491863
1850 var num_walked: usize = 0;1864 var num_walked: usize = 0;
1851 while (try walker.next()) |entry| {1865 while (try walker.next(io)) |entry| {
1852 expect(expected_basenames.has(entry.basename)) catch |err| {1866 expect(expected_basenames.has(entry.basename)) catch |err| {
1853 std.debug.print("found unexpected basename: {f}\n", .{std.ascii.hexEscape(entry.basename, .lower)});1867 std.debug.print("found unexpected basename: {f}\n", .{std.ascii.hexEscape(entry.basename, .lower)});
1854 return err;1868 return err;
...@@ -1910,10 +1924,10 @@ test "selective walker, skip entries that start with ." {...@@ -1910,10 +1924,10 @@ test "selective walker, skip entries that start with ." {
1910 defer walker.deinit();1924 defer walker.deinit();
19111925
1912 var num_walked: usize = 0;1926 var num_walked: usize = 0;
1913 while (try walker.next()) |entry| {1927 while (try walker.next(io)) |entry| {
1914 if (entry.basename[0] == '.') continue;1928 if (entry.basename[0] == '.') continue;
1915 if (entry.kind == .directory) {1929 if (entry.kind == .directory) {
1916 try walker.enter(entry);1930 try walker.enter(io, entry);
1917 }1931 }
19181932
1919 expect(expected_basenames.has(entry.basename)) catch |err| {1933 expect(expected_basenames.has(entry.basename)) catch |err| {
...@@ -1953,7 +1967,7 @@ test "walker without fully iterating" {...@@ -1953,7 +1967,7 @@ test "walker without fully iterating" {
1953 try tmp.dir.makePath(io, "b");1967 try tmp.dir.makePath(io, "b");
19541968
1955 var num_walked: usize = 0;1969 var num_walked: usize = 0;
1956 while (try walker.next()) |_| {1970 while (try walker.next(io)) |_| {
1957 num_walked += 1;1971 num_walked += 1;
1958 break;1972 break;
1959 }1973 }
...@@ -2093,48 +2107,42 @@ test "invalid UTF-8/WTF-8 paths" {...@@ -2093,48 +2107,42 @@ test "invalid UTF-8/WTF-8 paths" {
2093 // This is both invalid UTF-8 and WTF-8, since \xFF is an invalid start byte2107 // This is both invalid UTF-8 and WTF-8, since \xFF is an invalid start byte
2094 const invalid_path = try ctx.transformPath("\xFF");2108 const invalid_path = try ctx.transformPath("\xFF");
20952109
2096 try expectError(expected_err, ctx.dir.openFile(invalid_path, .{}));2110 try expectError(expected_err, ctx.dir.openFile(io, invalid_path, .{}));
20972111
2098 try expectError(expected_err, ctx.dir.createFile(invalid_path, .{}));2112 try expectError(expected_err, ctx.dir.createFile(io, invalid_path, .{}));
20992113
2100 try expectError(expected_err, ctx.dir.makeDir(invalid_path, .default_dir));2114 try expectError(expected_err, ctx.dir.makeDir(io, invalid_path, .default_dir));
21012115
2102 try expectError(expected_err, ctx.dir.makePath(invalid_path));2116 try expectError(expected_err, ctx.dir.makePath(io, invalid_path));
2103 try expectError(expected_err, ctx.dir.makeOpenPath(invalid_path, .{}));2117 try expectError(expected_err, ctx.dir.makeOpenPath(io, invalid_path, .{}));
21042118
2105 try expectError(expected_err, ctx.dir.openDir(invalid_path, .{}));2119 try expectError(expected_err, ctx.dir.openDir(io, invalid_path, .{}));
21062120
2107 try expectError(expected_err, ctx.dir.deleteFile(invalid_path));2121 try expectError(expected_err, ctx.dir.deleteFile(io, invalid_path));
21082122
2109 try expectError(expected_err, ctx.dir.deleteDir(io, invalid_path));2123 try expectError(expected_err, ctx.dir.deleteDir(io, invalid_path));
21102124
2111 try expectError(expected_err, ctx.dir.rename(invalid_path, ctx.dir, invalid_path, io));2125 try expectError(expected_err, ctx.dir.rename(invalid_path, ctx.dir, invalid_path, io));
21122126
2113 try expectError(expected_err, ctx.dir.symLink(io, invalid_path, invalid_path, .{}));2127 try expectError(expected_err, ctx.dir.symLink(io, invalid_path, invalid_path, .{}));
2114 if (native_os == .wasi) {
2115 try expectError(expected_err, ctx.dir.symLinkWasi(invalid_path, invalid_path, .{}));
2116 }
21172128
2118 try expectError(expected_err, ctx.dir.readLink(io, invalid_path, &[_]u8{}));2129 try expectError(expected_err, ctx.dir.readLink(io, invalid_path, &[_]u8{}));
2119 if (native_os == .wasi) {
2120 try expectError(expected_err, ctx.dir.readLinkWasi(invalid_path, &[_]u8{}));
2121 }
21222130
2123 try expectError(expected_err, ctx.dir.readFile(invalid_path, &[_]u8{}));2131 try expectError(expected_err, ctx.dir.readFile(io, invalid_path, &[_]u8{}));
2124 try expectError(expected_err, ctx.dir.readFileAlloc(invalid_path, testing.allocator, .limited(0)));2132 try expectError(expected_err, ctx.dir.readFileAlloc(io, invalid_path, testing.allocator, .limited(0)));
21252133
2126 try expectError(expected_err, ctx.dir.deleteTree(io, invalid_path));2134 try expectError(expected_err, ctx.dir.deleteTree(io, invalid_path));
2127 try expectError(expected_err, ctx.dir.deleteTreeMinStackSize(invalid_path));2135 try expectError(expected_err, ctx.dir.deleteTreeMinStackSize(io, invalid_path));
21282136
2129 try expectError(expected_err, ctx.dir.writeFile(io, .{ .sub_path = invalid_path, .data = "" }));2137 try expectError(expected_err, ctx.dir.writeFile(io, .{ .sub_path = invalid_path, .data = "" }));
21302138
2131 try expectError(expected_err, ctx.dir.access(invalid_path, .{}));2139 try expectError(expected_err, ctx.dir.access(io, invalid_path, .{}));
21322140
2133 var dir = ctx.dir;2141 var dir = ctx.dir;
2134 try expectError(expected_err, dir.updateFile(io, invalid_path, dir, invalid_path, .{}));2142 try expectError(expected_err, dir.updateFile(io, invalid_path, dir, invalid_path, .{}));
2135 try expectError(expected_err, ctx.dir.copyFile(invalid_path, ctx.dir, invalid_path, io, .{}));2143 try expectError(expected_err, ctx.dir.copyFile(invalid_path, ctx.dir, invalid_path, io, .{}));
21362144
2137 try expectError(expected_err, ctx.dir.statFile(invalid_path));2145 try expectError(expected_err, ctx.dir.statFile(io, invalid_path, .{}));
21382146
2139 if (native_os != .wasi) {2147 if (native_os != .wasi) {
2140 try expectError(expected_err, ctx.dir.realPath(io, invalid_path, &[_]u8{}));2148 try expectError(expected_err, ctx.dir.realPath(io, invalid_path, &[_]u8{}));
...@@ -2146,17 +2154,17 @@ test "invalid UTF-8/WTF-8 paths" {...@@ -2146,17 +2154,17 @@ test "invalid UTF-8/WTF-8 paths" {
2146 if (native_os != .wasi and ctx.path_type != .relative) {2154 if (native_os != .wasi and ctx.path_type != .relative) {
2147 try expectError(expected_err, Dir.copyFileAbsolute(invalid_path, invalid_path, io, .{}));2155 try expectError(expected_err, Dir.copyFileAbsolute(invalid_path, invalid_path, io, .{}));
2148 try expectError(expected_err, Dir.makeDirAbsolute(io, invalid_path, .default_dir));2156 try expectError(expected_err, Dir.makeDirAbsolute(io, invalid_path, .default_dir));
2149 try expectError(expected_err, Dir.deleteDirAbsolute(invalid_path));2157 try expectError(expected_err, Dir.deleteDirAbsolute(io, invalid_path));
2150 try expectError(expected_err, Dir.renameAbsolute(invalid_path, invalid_path, io));2158 try expectError(expected_err, Dir.renameAbsolute(invalid_path, invalid_path, io));
2151 try expectError(expected_err, Dir.openDirAbsolute(io, invalid_path, .{}));2159 try expectError(expected_err, Dir.openDirAbsolute(io, invalid_path, .{}));
2152 try expectError(expected_err, Dir.openFileAbsolute(io, invalid_path, .{}));2160 try expectError(expected_err, Dir.openFileAbsolute(io, invalid_path, .{}));
2153 try expectError(expected_err, Dir.accessAbsolute(invalid_path, .{}));2161 try expectError(expected_err, Dir.accessAbsolute(io, invalid_path, .{}));
2154 try expectError(expected_err, Dir.createFileAbsolute(invalid_path, .{}));2162 try expectError(expected_err, Dir.createFileAbsolute(io, invalid_path, .{}));
2155 try expectError(expected_err, Dir.deleteFileAbsolute(invalid_path));2163 try expectError(expected_err, Dir.deleteFileAbsolute(io, invalid_path));
2156 var readlink_buf: [Dir.max_path_bytes]u8 = undefined;2164 var readlink_buf: [Dir.max_path_bytes]u8 = undefined;
2157 try expectError(expected_err, Dir.readLinkAbsolute(invalid_path, &readlink_buf));2165 try expectError(expected_err, Dir.readLinkAbsolute(io, invalid_path, &readlink_buf));
2158 try expectError(expected_err, Dir.symLinkAbsolute(invalid_path, invalid_path, .{}));2166 try expectError(expected_err, Dir.symLinkAbsolute(io, invalid_path, invalid_path, .{}));
2159 try expectError(expected_err, Dir.realPathAlloc(io, invalid_path, testing.allocator));2167 try expectError(expected_err, Dir.realPathAbsoluteAlloc(io, invalid_path, testing.allocator));
2160 }2168 }
2161 }2169 }
2162 }.impl);2170 }.impl);
...@@ -2327,7 +2335,8 @@ test "readlink on Windows" {...@@ -2327,7 +2335,8 @@ test "readlink on Windows" {
23272335
2328fn testReadLinkWindows(io: Io, target_path: []const u8, symlink_path: []const u8) !void {2336fn testReadLinkWindows(io: Io, target_path: []const u8, symlink_path: []const u8) !void {
2329 var buffer: [Dir.max_path_bytes]u8 = undefined;2337 var buffer: [Dir.max_path_bytes]u8 = undefined;
2330 const given = try Dir.readLinkAbsolute(io, symlink_path, &buffer);2338 const len = try Dir.readLinkAbsolute(io, symlink_path, &buffer);
2339 const given = buffer[0..len];
2331 try expect(mem.eql(u8, target_path, given));2340 try expect(mem.eql(u8, target_path, given));
2332}2341}
23332342
...@@ -2495,7 +2504,7 @@ test "access smoke test" {...@@ -2495,7 +2504,7 @@ test "access smoke test" {
24952504
2496 {2505 {
2497 // Create some directory2506 // Create some directory
2498 try tmp.dir.makeDir(io, "some_dir", .default_file);2507 try tmp.dir.makeDir(io, "some_dir", .default_dir);
2499 }2508 }
25002509
2501 {2510 {
...@@ -2563,6 +2572,8 @@ test "open smoke test" {...@@ -2563,6 +2572,8 @@ test "open smoke test" {
2563}2572}
25642573
2565test "hard link with different directories" {2574test "hard link with different directories" {
2575 if (native_os == .wasi or native_os == .windows) return error.SkipZigTest;
2576
2566 const io = testing.io;2577 const io = testing.io;
25672578
2568 var tmp = tmpDir(.{});2579 var tmp = tmpDir(.{});
lib/std/os/windows.zig+3-3
...@@ -3582,7 +3582,7 @@ test QueryObjectName {...@@ -3582,7 +3582,7 @@ test QueryObjectName {
3582 //any file will do; canonicalization works on NTFS junctions and symlinks, hardlinks remain separate paths.3582 //any file will do; canonicalization works on NTFS junctions and symlinks, hardlinks remain separate paths.
3583 var tmp = std.testing.tmpDir(.{});3583 var tmp = std.testing.tmpDir(.{});
3584 defer tmp.cleanup();3584 defer tmp.cleanup();
3585 const handle = tmp.dir.fd;3585 const handle = tmp.dir.handle;
3586 var out_buffer: [PATH_MAX_WIDE]u16 = undefined;3586 var out_buffer: [PATH_MAX_WIDE]u16 = undefined;
35873587
3588 const result_path = try QueryObjectName(handle, &out_buffer);3588 const result_path = try QueryObjectName(handle, &out_buffer);
...@@ -3845,7 +3845,7 @@ test GetFinalPathNameByHandle {...@@ -3845,7 +3845,7 @@ test GetFinalPathNameByHandle {
3845 //any file will do3845 //any file will do
3846 var tmp = std.testing.tmpDir(.{});3846 var tmp = std.testing.tmpDir(.{});
3847 defer tmp.cleanup();3847 defer tmp.cleanup();
3848 const handle = tmp.dir.fd;3848 const handle = tmp.dir.handle;
3849 var buffer: [PATH_MAX_WIDE]u16 = undefined;3849 var buffer: [PATH_MAX_WIDE]u16 = undefined;
38503850
3851 //check with sufficient size3851 //check with sufficient size
...@@ -4638,7 +4638,7 @@ pub fn wToPrefixedFileW(dir: ?HANDLE, path: [:0]const u16) Wtf16ToPrefixedFileWE...@@ -4638,7 +4638,7 @@ pub fn wToPrefixedFileW(dir: ?HANDLE, path: [:0]const u16) Wtf16ToPrefixedFileWE
4638 }4638 }
4639 // We can also skip GetFinalPathNameByHandle if the handle matches4639 // We can also skip GetFinalPathNameByHandle if the handle matches
4640 // the handle returned by Io.Dir.cwd()4640 // the handle returned by Io.Dir.cwd()
4641 if (dir.? == Io.Dir.cwd().fd) {4641 if (dir.? == Io.Dir.cwd().handle) {
4642 break :path_to_get path;4642 break :path_to_get path;
4643 }4643 }
4644 // At this point, we know we have a relative path that had too many4644 // At this point, we know we have a relative path that had too many