diff --git a/src/Command.zig b/src/Command.zig index 5daa2bcfe..b9d282aa7 100644 --- a/src/Command.zig +++ b/src/Command.zig @@ -223,8 +223,6 @@ pub fn getData(self: Command, comptime DT: type) ?*DT { /// Search for "cmd" in the PATH and return the absolute path. This will /// always allocate if there is a non-null result. The caller must free the /// resulting value. -/// -/// TODO: windows pub fn expandPath(alloc: Allocator, cmd: []const u8) !?[]u8 { // If the command already contains a slash, then we return it as-is // because it is assumed to be absolute or relative. @@ -232,9 +230,18 @@ pub fn expandPath(alloc: Allocator, cmd: []const u8) !?[]u8 { return try alloc.dupe(u8, cmd); } - const PATH = os.getenvZ("PATH") orelse return null; + const PATH = switch (builtin.os.tag) { + .windows => blk: { + const win_path = os.getenvW(std.unicode.utf8ToUtf16LeStringLiteral("PATH")) orelse return null; + const path = try std.unicode.utf16leToUtf8Alloc(alloc, win_path); + break :blk path; + }, + else => os.getenvZ("PATH") orelse return null, + }; + defer if (builtin.os.tag == .windows) alloc.free(PATH); + var path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; - var it = std.mem.tokenize(u8, PATH, ":"); + var it = std.mem.tokenize(u8, PATH, &[_]u8{std.fs.path.delimiter}); var seen_eacces = false; while (it.next()) |search_path| { // We need enough space in our path buffer to store this @@ -243,7 +250,7 @@ pub fn expandPath(alloc: Allocator, cmd: []const u8) !?[]u8 { // Copy in the full path mem.copy(u8, &path_buf, search_path); - path_buf[search_path.len] = '/'; + path_buf[search_path.len] = std.fs.path.sep; mem.copy(u8, path_buf[search_path.len + 1 ..], cmd); path_buf[path_len] = 0; const full_path = path_buf[0..path_len :0]; @@ -276,10 +283,12 @@ fn isExecutable(mode: std.fs.File.Mode) bool { return mode & 0o0111 != 0; } -test "expandPath: env" { - const path = (try expandPath(testing.allocator, "env")).?; +// `hostname` is present on both *nix and windows +test "expandPath: hostname" { + const executable = if (builtin.os.tag == .windows) "hostname.exe" else "hostname"; + const path = (try expandPath(testing.allocator, executable)).?; defer testing.allocator.free(path); - try testing.expect(path.len > 0); + try testing.expect(path.len > executable.len); } test "expandPath: does not exist" { diff --git a/src/os/TempDir.zig b/src/os/TempDir.zig index 0422a2cef..7c1354bae 100644 --- a/src/os/TempDir.zig +++ b/src/os/TempDir.zig @@ -61,8 +61,9 @@ pub fn name(self: *TempDir) []const u8 { } /// Finish with the temporary directory. This deletes all contents in the -/// directory. This is safe to call multiple times. +/// directory. pub fn deinit(self: *TempDir) void { + self.dir.close(); self.parent.deleteTree(self.name()) catch |err| log.err("error deleting temp dir err={}", .{err}); } @@ -78,13 +79,14 @@ const b64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345 test { var td = try init(); - defer td.deinit(); + errdefer td.deinit(); const nameval = td.name(); try testing.expect(nameval.len > 0); // Can open a new handle to it proves it exists. - _ = try td.parent.openDir(nameval, .{}); + var dir = try td.parent.openDir(nameval, .{}); + dir.close(); // Should be deleted after we deinit td.deinit(); diff --git a/src/os/file.zig b/src/os/file.zig index 7e54909b3..fba9f9289 100644 --- a/src/os/file.zig +++ b/src/os/file.zig @@ -53,6 +53,20 @@ pub fn fixMaxFiles() void { /// Return the recommended path for temporary files. pub fn tmpDir() ?[]const u8 { + if (builtin.os.tag == .windows) { + // TODO: what is a good fallback path on windows? + const v = std.os.getenvW(std.unicode.utf8ToUtf16LeStringLiteral("TMP")) orelse return null; + // MAX_PATH is very likely sufficient, but it's theoretically possible for someone to + // configure their os to allow paths as big as std.os.windows.PATH_MAX_WIDE, which is MUCH + // larger. Even if they did that, though, it's very unlikey that their Temp dir will use + // such a long path. We can switch if we see any issues, though it seems fairly unlikely. + var buf = [_]u8{0} ** std.os.windows.MAX_PATH; + const len = std.unicode.utf16leToUtf8(buf[0..], v[0..v.len]) catch |e| { + log.warn("failed to convert temp dir path from windows string: {}", .{e}); + return null; + }; + return buf[0..len]; + } if (std.os.getenv("TMPDIR")) |v| return v; if (std.os.getenv("TMP")) |v| return v; return "/tmp"; diff --git a/src/os/homedir.zig b/src/os/homedir.zig index d73405c09..548f137e7 100644 --- a/src/os/homedir.zig +++ b/src/os/homedir.zig @@ -84,8 +84,7 @@ fn homeWindows(buf: []u8) !?[]u8 { const fba = fba_instance.allocator(); const drive = std.process.getEnvVarOwned(fba, "HOMEDRIVE") catch |err| switch (err) { error.OutOfMemory => return Error.BufferTooSmall, - error.InvalidUtf8, - error.EnvironmentVariableNotFound => return null, + error.InvalidUtf8, error.EnvironmentVariableNotFound => return null, }; // could shift the contents if this ever happens if (drive.ptr != buf.ptr) @panic("codebug"); @@ -98,8 +97,7 @@ fn homeWindows(buf: []u8) !?[]u8 { const fba = fba_instance.allocator(); const homepath = std.process.getEnvVarOwned(fba, "HOMEPATH") catch |err| switch (err) { error.OutOfMemory => return Error.BufferTooSmall, - error.InvalidUtf8, - error.EnvironmentVariableNotFound => return null, + error.InvalidUtf8, error.EnvironmentVariableNotFound => return null, }; // could shift the contents if this ever happens if (homepath.ptr != path_buf.ptr) @panic("codebug");