authorgravatar for leecannon@leecannon.xyzLee Cannon <leecannon@leecannon.xyz> 2020-11-06 23:57:54+00:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-11-18 15:37:44+01:00
log80b1e82b1b8706b7654560013751dd4a6fc8ae2a
tree0522d7b8579c846441685b105e88f2dd9f1443ef
parenta6470088c6629e91edad8390f3f2930f1d7c92b1

Implement chdir and chdirZ for Windows


3 files changed, 35 insertions(+), 4 deletions(-)

lib/std/os.zig+7-4
......@@ -2305,8 +2305,12 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {
23052305 if (builtin.os.tag == .wasi) {
23062306 @compileError("chdir is not supported in WASI");
23072307 } else if (builtin.os.tag == .windows) {
2308 const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);
2309 @compileError("TODO implement chdir for Windows");
2308 windows.SetCurrentDirectory(dir_path) catch |err| switch (err) {
2309 error.PathNotFound, error.InvalidName, error.InvalidUtf8 => return error.FileNotFound,
2310 error.NameTooLong => return error.NameTooLong,
2311 error.NotDir => return error.NotDir,
2312 error.Unexpected => return error.Unexpected,
2313 };
23102314 } else {
23112315 const dir_path_c = try toPosixPath(dir_path);
23122316 return chdirZ(&dir_path_c);
......@@ -2318,8 +2322,7 @@ pub const chdirC = @compileError("deprecated: renamed to chdirZ");
23182322/// Same as `chdir` except the parameter is null-terminated.
23192323pub fn chdirZ(dir_path: [*:0]const u8) ChangeCurDirError!void {
23202324 if (builtin.os.tag == .windows) {
2321 const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);
2322 @compileError("TODO implement chdir for Windows");
2325 return chdir(mem.spanZ(dir_path));
23232326 }
23242327 switch (errno(system.chdir(dir_path))) {
23252328 0 => return,
lib/std/os/windows.zig+27
......@@ -555,6 +555,33 @@ pub fn WriteFile(
555555 }
556556}
557557
558pub const SetCurrentDirectoryError = error{
559 PathNotFound,
560 InvalidName,
561 InvalidUtf8,
562 NameTooLong,
563 NotDir,
564 Unexpected,
565};
566
567pub 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 if (path_name.len >= PATH_MAX_WIDE - 1) return error.NameTooLong;
570
571 var utf16le_buf: [PATH_MAX_WIDE]u16 = undefined;
572 const end = try std.unicode.utf8ToUtf16Le(utf16le_buf[0..], path_name);
573 utf16le_buf[end] = 0;
574
575 if (kernel32.SetCurrentDirectoryW(@ptrCast([*:0]const u16, &utf16le_buf)) == 0) {
576 switch (kernel32.GetLastError()) {
577 .PATH_NOT_FOUND, .FILE_NOT_FOUND => return error.PathNotFound,
578 .DIRECTORY => return error.NotDir,
579 .INVALID_NAME => return error.InvalidName,
580 else => |err| return unexpectedError(err),
581 }
582 }
583}
584
558585pub const GetCurrentDirectoryError = error{
559586 NameTooLong,
560587 Unexpected,
lib/std/os/windows/kernel32.zig+1
......@@ -93,6 +93,7 @@ pub extern "kernel32" fn FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCh
9393pub extern "kernel32" fn FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: DWORD, dwWriteCoord: COORD, lpNumberOfAttrsWritten: LPDWORD) callconv(.Stdcall) BOOL;
9494pub extern "kernel32" fn SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) callconv(.Stdcall) BOOL;
9595
96pub extern "kernel32" fn SetCurrentDirectoryW(lpPathName: [*:0]const u16) callconv(.Stdcall) BOOL;
9697pub extern "kernel32" fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: ?[*]WCHAR) callconv(.Stdcall) DWORD;
9798
9899pub extern "kernel32" fn GetCurrentThread() callconv(.Stdcall) HANDLE;