| author | |
| committer | |
| log | 32c998e03c38fabfb3f26ad7f88817ec8a8e5f6d |
| tree | a62ddbdf336b426f0bf72764b918461faebe4b25 |
| parent | 80b1e82b1b8706b7654560013751dd4a6fc8ae2a |
4 files changed, 39 insertions(+), 17 deletions(-)
lib/std/os.zig+7-1| ... | @@ -2297,6 +2297,9 @@ pub const ChangeCurDirError = error{ | ... | @@ -2297,6 +2297,9 @@ pub const ChangeCurDirError = error{ |
| 2297 | FileNotFound, | 2297 | FileNotFound, |
| 2298 | SystemResources, | 2298 | SystemResources, |
| 2299 | NotDir, | 2299 | NotDir, |
| 2300 | |||
| 2301 | /// On Windows, file paths must be valid Unicode. | ||
| 2302 | InvalidUtf8, | ||
| 2300 | } || UnexpectedError; | 2303 | } || UnexpectedError; |
| 2301 | 2304 | ||
| 2302 | /// Changes the current working directory of the calling process. | 2305 | /// Changes the current working directory of the calling process. |
| ... | @@ -2306,9 +2309,12 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void { | ... | @@ -2306,9 +2309,12 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void { |
| 2306 | @compileError("chdir is not supported in WASI"); | 2309 | @compileError("chdir is not supported in WASI"); |
| 2307 | } else if (builtin.os.tag == .windows) { | 2310 | } else if (builtin.os.tag == .windows) { |
| 2308 | windows.SetCurrentDirectory(dir_path) catch |err| switch (err) { | 2311 | windows.SetCurrentDirectory(dir_path) catch |err| switch (err) { |
| 2309 | error.PathNotFound, error.InvalidName, error.InvalidUtf8 => return error.FileNotFound, | 2312 | error.InvalidUtf8 => return error.InvalidUtf8, |
| 2310 | error.NameTooLong => return error.NameTooLong, | 2313 | error.NameTooLong => return error.NameTooLong, |
| 2314 | error.FileNotFound => return error.FileNotFound, | ||
| 2311 | error.NotDir => return error.NotDir, | 2315 | error.NotDir => return error.NotDir, |
| 2316 | error.NoDevice => return error.FileSystem, | ||
| 2317 | error.AccessDenied => return error.AccessDenied, | ||
| 2312 | error.Unexpected => return error.Unexpected, | 2318 | error.Unexpected => return error.Unexpected, |
| 2313 | }; | 2319 | }; |
| 2314 | } else { | 2320 | } else { |
lib/std/os/windows.zig+28-15| ... | @@ -556,29 +556,42 @@ pub fn WriteFile( | ... | @@ -556,29 +556,42 @@ pub fn WriteFile( |
| 556 | } | 556 | } |
| 557 | 557 | ||
| 558 | pub const SetCurrentDirectoryError = error{ | 558 | pub const SetCurrentDirectoryError = error{ |
| 559 | PathNotFound, | ||
| 560 | InvalidName, | ||
| 561 | InvalidUtf8, | ||
| 562 | NameTooLong, | 559 | NameTooLong, |
| 560 | InvalidUtf8, | ||
| 561 | FileNotFound, | ||
| 563 | NotDir, | 562 | NotDir, |
| 563 | AccessDenied, | ||
| 564 | NoDevice, | ||
| 564 | Unexpected, | 565 | Unexpected, |
| 565 | }; | 566 | }; |
| 566 | 567 | ||
| 567 | pub fn SetCurrentDirectory(path_name: []const u8) SetCurrentDirectoryError!void { | 568 | pub fn SetCurrentDirectory(path_name: []const u8) SetCurrentDirectoryError!void { |
| 568 | // PATH_MAX_WIDE - 1 as we need to ensure there is space for the null terminator | 569 | var path_space: PathSpace = undefined; |
| 569 | if (path_name.len >= PATH_MAX_WIDE - 1) return error.NameTooLong; | 570 | path_space.len = try std.unicode.utf8ToUtf16Le(path_space.data[0..], path_name); |
| 571 | if (path_space.len > path_space.data.len) return error.NameTooLong; | ||
| 570 | 572 | ||
| 571 | var utf16le_buf: [PATH_MAX_WIDE]u16 = undefined; | 573 | const path_len_bytes = math.cast(u16, path_space.len * 2) catch |err| switch (err) { |
| 572 | const end = try std.unicode.utf8ToUtf16Le(utf16le_buf[0..], path_name); | 574 | error.Overflow => return error.NameTooLong, |
| 573 | utf16le_buf[end] = 0; | 575 | }; |
| 574 | 576 | ||
| 575 | if (kernel32.SetCurrentDirectoryW(@ptrCast([*:0]const u16, &utf16le_buf)) == 0) { | 577 | var nt_name = UNICODE_STRING{ |
| 576 | switch (kernel32.GetLastError()) { | 578 | .Length = path_len_bytes, |
| 577 | .PATH_NOT_FOUND, .FILE_NOT_FOUND => return error.PathNotFound, | 579 | .MaximumLength = path_len_bytes, |
| 578 | .DIRECTORY => return error.NotDir, | 580 | .Buffer = @intToPtr([*]u16, @ptrToInt(&path_space.data)), |
| 579 | .INVALID_NAME => return error.InvalidName, | 581 | }; |
| 580 | else => |err| return unexpectedError(err), | 582 | |
| 581 | } | 583 | const rc = ntdll.RtlSetCurrentDirectory_U(&nt_name); |
| 584 | switch (rc) { | ||
| 585 | .SUCCESS => {}, | ||
| 586 | .OBJECT_NAME_INVALID => unreachable, | ||
| 587 | .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, | ||
| 588 | .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, | ||
| 589 | .NO_MEDIA_IN_DEVICE => return error.NoDevice, | ||
| 590 | .INVALID_PARAMETER => unreachable, | ||
| 591 | .ACCESS_DENIED => return error.AccessDenied, | ||
| 592 | .OBJECT_PATH_SYNTAX_BAD => unreachable, | ||
| 593 | .NOT_A_DIRECTORY => return error.NotDir, | ||
| 594 | else => return unexpectedStatus(rc), | ||
| 582 | } | 595 | } |
| 583 | } | 596 | } |
| 584 | 597 |
lib/std/os/windows/kernel32.zig-1| ... | @@ -93,7 +93,6 @@ pub extern "kernel32" fn FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCh | ... | @@ -93,7 +93,6 @@ pub extern "kernel32" fn FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCh |
| 93 | pub extern "kernel32" fn FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: DWORD, dwWriteCoord: COORD, lpNumberOfAttrsWritten: LPDWORD) callconv(.Stdcall) BOOL; | 93 | pub extern "kernel32" fn FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: DWORD, dwWriteCoord: COORD, lpNumberOfAttrsWritten: LPDWORD) callconv(.Stdcall) BOOL; |
| 94 | pub extern "kernel32" fn SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) callconv(.Stdcall) BOOL; | 94 | pub extern "kernel32" fn SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) callconv(.Stdcall) BOOL; |
| 95 | 95 | ||
| 96 | pub extern "kernel32" fn SetCurrentDirectoryW(lpPathName: [*:0]const u16) callconv(.Stdcall) BOOL; | ||
| 97 | pub extern "kernel32" fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: ?[*]WCHAR) callconv(.Stdcall) DWORD; | 96 | pub extern "kernel32" fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: ?[*]WCHAR) callconv(.Stdcall) DWORD; |
| 98 | 97 | ||
| 99 | pub extern "kernel32" fn GetCurrentThread() callconv(.Stdcall) HANDLE; | 98 | pub extern "kernel32" fn GetCurrentThread() callconv(.Stdcall) HANDLE; |
lib/std/os/windows/ntdll.zig+4| ... | @@ -111,3 +111,7 @@ pub extern "NtDll" fn NtWaitForKeyedEvent( | ... | @@ -111,3 +111,7 @@ pub extern "NtDll" fn NtWaitForKeyedEvent( |
| 111 | Alertable: BOOLEAN, | 111 | Alertable: BOOLEAN, |
| 112 | Timeout: ?*LARGE_INTEGER, | 112 | Timeout: ?*LARGE_INTEGER, |
| 113 | ) callconv(.Stdcall) NTSTATUS; | 113 | ) callconv(.Stdcall) NTSTATUS; |
| 114 | |||
| 115 | pub extern "NtDll" fn RtlSetCurrentDirectory_U( | ||
| 116 | PathName: *UNICODE_STRING | ||
| 117 | ) callconv(.Stdcall) NTSTATUS; |