| ... | @@ -2044,26 +2044,97 @@ fn dirOpenFileWindows( | ... | @@ -2044,26 +2044,97 @@ fn dirOpenFileWindows( |
| 2044 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 2044 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2045 | const sub_path_w_array = try windows.sliceToPrefixedFileW(dir.handle, sub_path); | 2045 | const sub_path_w_array = try windows.sliceToPrefixedFileW(dir.handle, sub_path); |
| 2046 | const sub_path_w = sub_path_w_array.span(); | 2046 | const sub_path_w = sub_path_w_array.span(); |
| 2047 | return dirOpenFileWindowsInner(t, dir, sub_path_w, flags); | 2047 | const dir_handle = if (std.fs.path.isAbsoluteWindowsWtf16(sub_path_w)) null else dir.handle; |
| | 2048 | return dirOpenFileWindowsInner(t, dir_handle, sub_path_w, flags); |
| 2048 | } | 2049 | } |
| 2049 | | 2050 | |
| 2050 | fn dirOpenFileWindowsInner( | 2051 | fn dirOpenFileWindowsInner( |
| 2051 | t: *Threaded, | 2052 | t: *Threaded, |
| 2052 | dir: Io.Dir, | 2053 | dir_handle: ?windows.HANDLE, |
| 2053 | sub_path_w: [:0]const u16, | 2054 | sub_path_w: [:0]const u16, |
| 2054 | flags: Io.File.OpenFlags, | 2055 | flags: Io.File.OpenFlags, |
| 2055 | ) Io.File.OpenError!Io.File { | 2056 | ) Io.File.OpenError!Io.File { |
| 2056 | try t.checkCancel(); | 2057 | if (std.mem.eql(u16, sub_path_w, &.{'.'})) return error.IsDir; |
| | 2058 | if (std.mem.eql(u16, sub_path_w, &.{ '.', '.' })) return error.IsDir; |
| | 2059 | const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong; |
| | 2060 | |
| 2057 | const w = windows; | 2061 | const w = windows; |
| 2058 | const handle = try w.OpenFile(sub_path_w, .{ | 2062 | |
| 2059 | .dir = dir.handle, | 2063 | var nt_name: w.UNICODE_STRING = .{ |
| 2060 | .access_mask = w.SYNCHRONIZE | | 2064 | .Length = path_len_bytes, |
| 2061 | (if (flags.isRead()) @as(u32, w.GENERIC_READ) else 0) | | 2065 | .MaximumLength = path_len_bytes, |
| 2062 | (if (flags.isWrite()) @as(u32, w.GENERIC_WRITE) else 0), | 2066 | .Buffer = @constCast(sub_path_w.ptr), |
| 2063 | .creation = w.FILE_OPEN, | 2067 | }; |
| 2064 | }); | 2068 | var attr: w.OBJECT_ATTRIBUTES = .{ |
| 2065 | errdefer w.CloseHandle(handle); | 2069 | .Length = @sizeOf(w.OBJECT_ATTRIBUTES), |
| | 2070 | .RootDirectory = dir_handle, |
| | 2071 | .Attributes = 0, |
| | 2072 | .ObjectName = &nt_name, |
| | 2073 | .SecurityDescriptor = null, |
| | 2074 | .SecurityQualityOfService = null, |
| | 2075 | }; |
| 2066 | var io_status_block: w.IO_STATUS_BLOCK = undefined; | 2076 | var io_status_block: w.IO_STATUS_BLOCK = undefined; |
| | 2077 | const blocking_flag: w.ULONG = w.FILE_SYNCHRONOUS_IO_NONALERT; |
| | 2078 | const file_or_dir_flag: w.ULONG = w.FILE_NON_DIRECTORY_FILE; |
| | 2079 | // If we're not following symlinks, we need to ensure we don't pass in any |
| | 2080 | // synchronization flags such as FILE_SYNCHRONOUS_IO_NONALERT. |
| | 2081 | const create_file_flags: w.ULONG = file_or_dir_flag | |
| | 2082 | if (flags.follow_symlinks) blocking_flag else w.FILE_OPEN_REPARSE_POINT; |
| | 2083 | |
| | 2084 | const handle = while (true) { |
| | 2085 | try t.checkCancel(); |
| | 2086 | |
| | 2087 | var result: w.HANDLE = undefined; |
| | 2088 | const rc = w.ntdll.NtCreateFile( |
| | 2089 | &result, |
| | 2090 | w.SYNCHRONIZE | |
| | 2091 | (if (flags.isRead()) @as(u32, w.GENERIC_READ) else 0) | |
| | 2092 | (if (flags.isWrite()) @as(u32, w.GENERIC_WRITE) else 0), |
| | 2093 | &attr, |
| | 2094 | &io_status_block, |
| | 2095 | null, |
| | 2096 | w.FILE_ATTRIBUTE_NORMAL, |
| | 2097 | w.FILE_SHARE_WRITE | w.FILE_SHARE_READ | w.FILE_SHARE_DELETE, |
| | 2098 | w.FILE_OPEN, |
| | 2099 | create_file_flags, |
| | 2100 | null, |
| | 2101 | 0, |
| | 2102 | ); |
| | 2103 | switch (rc) { |
| | 2104 | .SUCCESS => break result, |
| | 2105 | .OBJECT_NAME_INVALID => return error.BadPathName, |
| | 2106 | .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, |
| | 2107 | .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, |
| | 2108 | .BAD_NETWORK_PATH => return error.NetworkNotFound, // \\server was not found |
| | 2109 | .BAD_NETWORK_NAME => return error.NetworkNotFound, // \\server was found but \\server\share wasn't |
| | 2110 | .NO_MEDIA_IN_DEVICE => return error.NoDevice, |
| | 2111 | .INVALID_PARAMETER => |err| return w.statusBug(err), |
| | 2112 | .SHARING_VIOLATION => return error.AccessDenied, |
| | 2113 | .ACCESS_DENIED => return error.AccessDenied, |
| | 2114 | .PIPE_BUSY => return error.PipeBusy, |
| | 2115 | .PIPE_NOT_AVAILABLE => return error.NoDevice, |
| | 2116 | .OBJECT_PATH_SYNTAX_BAD => |err| return w.statusBug(err), |
| | 2117 | .OBJECT_NAME_COLLISION => return error.PathAlreadyExists, |
| | 2118 | .FILE_IS_A_DIRECTORY => return error.IsDir, |
| | 2119 | .NOT_A_DIRECTORY => return error.NotDir, |
| | 2120 | .USER_MAPPED_FILE => return error.AccessDenied, |
| | 2121 | .INVALID_HANDLE => |err| return w.statusBug(err), |
| | 2122 | .DELETE_PENDING => { |
| | 2123 | // This error means that there *was* a file in this location on |
| | 2124 | // the file system, but it was deleted. However, the OS is not |
| | 2125 | // finished with the deletion operation, and so this CreateFile |
| | 2126 | // call has failed. There is not really a sane way to handle |
| | 2127 | // this other than retrying the creation after the OS finishes |
| | 2128 | // the deletion. |
| | 2129 | _ = w.kernel32.SleepEx(1, w.FALSE); |
| | 2130 | continue; |
| | 2131 | }, |
| | 2132 | .VIRUS_INFECTED, .VIRUS_DELETED => return error.AntivirusInterference, |
| | 2133 | else => return w.unexpectedStatus(rc), |
| | 2134 | } |
| | 2135 | }; |
| | 2136 | errdefer w.CloseHandle(handle); |
| | 2137 | |
| 2067 | const range_off: w.LARGE_INTEGER = 0; | 2138 | const range_off: w.LARGE_INTEGER = 0; |
| 2068 | const range_len: w.LARGE_INTEGER = 1; | 2139 | const range_len: w.LARGE_INTEGER = 1; |
| 2069 | const exclusive = switch (flags.lock) { | 2140 | const exclusive = switch (flags.lock) { |
| ... | @@ -2691,20 +2762,19 @@ fn fileSeekTo(userdata: ?*anyopaque, file: Io.File, offset: u64) Io.File.SeekErr | ... | @@ -2691,20 +2762,19 @@ fn fileSeekTo(userdata: ?*anyopaque, file: Io.File, offset: u64) Io.File.SeekErr |
| 2691 | | 2762 | |
| 2692 | fn openSelfExe(userdata: ?*anyopaque, flags: Io.File.OpenFlags) Io.File.OpenSelfExeError!Io.File { | 2763 | fn openSelfExe(userdata: ?*anyopaque, flags: Io.File.OpenFlags) Io.File.OpenSelfExeError!Io.File { |
| 2693 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 2764 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2694 | if (native_os == .linux or native_os == .serenity) { | 2765 | switch (native_os) { |
| 2695 | return dirOpenFilePosix(t, .{ .handle = posix.AT.FDCWD }, "/proc/self/exe", flags); | 2766 | .linux, .serenity => return dirOpenFilePosix(t, .{ .handle = posix.AT.FDCWD }, "/proc/self/exe", flags), |
| 2696 | } | 2767 | .windows => { |
| 2697 | if (is_windows) { | 2768 | // If ImagePathName is a symlink, then it will contain the path of the symlink, |
| 2698 | // If ImagePathName is a symlink, then it will contain the path of the symlink, | 2769 | // not the path that the symlink points to. However, because we are opening |
| 2699 | // not the path that the symlink points to. However, because we are opening | 2770 | // the file, we can let the openFileW call follow the symlink for us. |
| 2700 | // the file, we can let the openFileW call follow the symlink for us. | 2771 | const image_path_unicode_string = &windows.peb().ProcessParameters.ImagePathName; |
| 2701 | const image_path_unicode_string = &windows.peb().ProcessParameters.ImagePathName; | 2772 | const image_path_name = image_path_unicode_string.Buffer.?[0 .. image_path_unicode_string.Length / 2 :0]; |
| 2702 | const image_path_name = image_path_unicode_string.Buffer.?[0 .. image_path_unicode_string.Length / 2 :0]; | 2773 | const prefixed_path_w = try windows.wToPrefixedFileW(null, image_path_name); |
| 2703 | const cwd_handle = std.os.windows.peb().ProcessParameters.CurrentDirectory.Handle; | 2774 | return dirOpenFileWindowsInner(t, null, prefixed_path_w.span(), flags); |
| 2704 | | 2775 | }, |
| 2705 | return dirOpenFileWindowsInner(t, .{ .handle = cwd_handle }, image_path_name, flags); | 2776 | else => @panic("TODO implement openSelfExe"), |
| 2706 | } | 2777 | } |
| 2707 | @panic("TODO implement openSelfExe"); | | |
| 2708 | } | 2778 | } |
| 2709 | | 2779 | |
| 2710 | fn fileWritePositional( | 2780 | fn fileWritePositional( |
| ... | @@ -2823,7 +2893,8 @@ fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { | ... | @@ -2823,7 +2893,8 @@ fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { |
| 2823 | break :ms std.math.maxInt(windows.DWORD); | 2893 | break :ms std.math.maxInt(windows.DWORD); |
| 2824 | break :ms std.math.lossyCast(windows.DWORD, d.raw.toMilliseconds()); | 2894 | break :ms std.math.lossyCast(windows.DWORD, d.raw.toMilliseconds()); |
| 2825 | }; | 2895 | }; |
| 2826 | windows.kernel32.Sleep(ms); | 2896 | // TODO: alertable true with checkCancel in a loop plus deadline |
| | 2897 | _ = windows.kernel32.SleepEx(ms, windows.FALSE); |
| 2827 | } | 2898 | } |
| 2828 | | 2899 | |
| 2829 | fn sleepWasi(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { | 2900 | fn sleepWasi(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { |