diff --git a/lib/std/os.zig b/lib/std/os.zig index 096777431..6e57c59c1 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -2312,11 +2312,7 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void { var utf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined; const len = try std.unicode.utf8ToUtf16Le(utf16_dir_path[0..], dir_path); if (len > utf16_dir_path.len) return error.NameTooLong; - - windows.SetCurrentDirectory(utf16_dir_path[0..len]) catch |err| switch (err) { - error.NoDevice => return error.FileSystem, - else => |e| return e, - }; + return chdirW(utf16_dir_path[0..len]); } else { const dir_path_c = try toPosixPath(dir_path); return chdirZ(&dir_path_c); @@ -2328,7 +2324,10 @@ pub const chdirC = @compileError("deprecated: renamed to chdirZ"); /// Same as `chdir` except the parameter is null-terminated. pub fn chdirZ(dir_path: [*:0]const u8) ChangeCurDirError!void { if (builtin.os.tag == .windows) { - return chdir(mem.spanZ(dir_path)); + var utf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined; + const len = try std.unicode.utf8ToUtf16Le(utf16_dir_path[0..], dir_path); + if (len > utf16_dir_path.len) return error.NameTooLong; + return chdirW(utf16_dir_path[0..len]); } switch (errno(system.chdir(dir_path))) { 0 => return, @@ -2344,6 +2343,14 @@ pub fn chdirZ(dir_path: [*:0]const u8) ChangeCurDirError!void { } } +/// Windows-only. Same as `chdir` except the paramter is WTF16 encoded. +pub fn chdirW(dir_path: []const u16) ChangeCurDirError!void { + windows.SetCurrentDirectory(dir_path) catch |err| switch (err) { + error.NoDevice => return error.FileSystem, + else => |e| return e, + }; +} + pub const FchdirError = error{ AccessDenied, NotDir, diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index 4964ef1cd..a7123f9d8 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -25,6 +25,30 @@ const tmpDir = std.testing.tmpDir; const Dir = std.fs.Dir; const ArenaAllocator = std.heap.ArenaAllocator; +test "chdir smoke test" { + if (builtin.os.tag == .wasi) return error.SkipZigTest; + + // Get current working directory path + var old_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined; + const old_cwd = try os.getcwd(old_cwd_buf[0..]); + + { + // Firstly, changing to itself should have no effect + try os.chdir(old_cwd); + var new_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined; + const new_cwd = try os.getcwd(new_cwd_buf[0..]); + expect(mem.eql(u8, old_cwd, new_cwd)); + } + { + // Next, change current working directory to one level above + const parent = fs.path.dirname(old_cwd) orelse unreachable; // old_cwd should be absolute + try os.chdir(parent); + var new_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined; + const new_cwd = try os.getcwd(new_cwd_buf[0..]); + expect(mem.eql(u8, parent, new_cwd)); + } +} + test "open smoke test" { if (builtin.os.tag == .wasi) return error.SkipZigTest;