From dd22c71612287c9a4447734342b5f8e71d97efdf Mon Sep 17 00:00:00 2001 From: Dylan Conway <35280289+dylan-conway@users.noreply.github.com> Date: Wed, 19 Jun 2024 23:53:50 -0700 Subject: [PATCH] fix(shell): handle cwd paths with non ascii characters (#11990) Co-authored-by: Jarred Sumner --- src/shell/interpreter.zig | 4 ++-- src/sys.zig | 19 ++++++++++++------- test/js/bun/shell/exec.test.ts | 13 ++++++++++++- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/shell/interpreter.zig b/src/shell/interpreter.zig index 9474882853..55a477e085 100644 --- a/src/shell/interpreter.zig +++ b/src/shell/interpreter.zig @@ -1321,8 +1321,8 @@ pub const Interpreter = struct { }; var pathbuf: bun.PathBuffer = undefined; - const cwd: [:0]const u8 = switch (Syscall.getcwd(&pathbuf)) { - .result => |cwd| cwd.ptr[0..cwd.len :0], + const cwd: [:0]const u8 = switch (Syscall.getcwdZ(&pathbuf)) { + .result => |cwd| cwd, .err => |err| { return .{ .err = .{ .sys = err.toSystemError() } }; }, diff --git a/src/sys.zig b/src/sys.zig index 8873919f82..2f0bd5eb6f 100644 --- a/src/sys.zig +++ b/src/sys.zig @@ -345,18 +345,23 @@ pub fn Maybe(comptime ReturnTypeT: type) type { pub fn getcwd(buf: *bun.PathBuffer) Maybe([]const u8) { const Result = Maybe([]const u8); - buf[0] = 0; - const rc = std.c.getcwd(buf, bun.MAX_PATH_BYTES); - return if (rc != null) - Result{ .result = std.mem.sliceTo(rc.?[0..bun.MAX_PATH_BYTES], 0) } - else - Result.errnoSys(0, .getcwd).?; + return switch (getcwdZ(buf)) { + .err => |err| Result{ .err = err }, + .result => |cwd| Result{ .result = cwd }, + }; } pub fn getcwdZ(buf: *bun.PathBuffer) Maybe([:0]const u8) { const Result = Maybe([:0]const u8); buf[0] = 0; - buf[buf.len - 1] = 0; + + if (comptime Environment.isWindows) { + var wbuf: bun.WPathBuffer = undefined; + const len: windows.DWORD = kernel32.GetCurrentDirectoryW(wbuf.len, &wbuf); + if (Result.errnoSys(len, .getcwd)) |err| return err; + return Result{ .result = bun.strings.fromWPath(buf, wbuf[0..len]) }; + } + const rc: ?[*:0]u8 = @ptrCast(std.c.getcwd(buf, bun.MAX_PATH_BYTES)); return if (rc != null) Result{ .result = rc.?[0..std.mem.len(rc.?) :0] } diff --git a/test/js/bun/shell/exec.test.ts b/test/js/bun/shell/exec.test.ts index 2bf67e29fa..2fb108ddcf 100644 --- a/test/js/bun/shell/exec.test.ts +++ b/test/js/bun/shell/exec.test.ts @@ -2,7 +2,8 @@ import { $ } from "bun"; import { describe, test, expect } from "bun:test"; import { createTestBuilder } from "./test_builder"; const TestBuilder = createTestBuilder(import.meta.path); -import { bunEnv } from "harness"; +import { bunEnv, tmpdirSync } from "harness"; +import { join } from "path"; const BUN = process.argv0; @@ -75,4 +76,14 @@ describe("bun exec", () => { expect(val.stderr.toString()).not.toContain("bun: command not found: bun"); expect(val.stdout.toString()).toContain("Bun is a fast JavaScript runtime"); }); + + test("works with latin1 paths", async () => { + const tempdir = tmpdirSync(); + await Bun.write(join(tempdir, "Í", "hi"), "text"); + const result = await $`bun exec ls` + .env({ ...(bunEnv as any) }) + .cwd(join(tempdir, "Í")) + .quiet(); + expect(result.text()).toBe("hi\n"); + }); });