diff --git a/scripts/runner.node.mjs b/scripts/runner.node.mjs index 451610a630..b680f87294 100755 --- a/scripts/runner.node.mjs +++ b/scripts/runner.node.mjs @@ -1128,6 +1128,7 @@ async function spawnBun(execPath, { args, cwd, timeout, env, stdout, stderr }) { ...process.env, PATH: path, TMPDIR: tmpdirPath, + BUN_TMPDIR: tmpdirPath, USER: username, HOME: homedir, SHELL: shellPath, diff --git a/src/OutputFile.zig b/src/OutputFile.zig index c3eb50a015..1eb0fb90d2 100644 --- a/src/OutputFile.zig +++ b/src/OutputFile.zig @@ -74,7 +74,7 @@ pub const FileOperation = struct { pub fn getPathname(file: *const FileOperation) string { if (file.is_tmpdir) { - return resolve_path.joinAbs(@TypeOf(Fs.FileSystem.instance.fs).tmpdir_path, .auto, file.pathname); + return resolve_path.joinAbs(Fs.FileSystem.RealFS.tmpdirPath(), .auto, file.pathname); } else { return file.pathname; } diff --git a/src/StandaloneModuleGraph.zig b/src/StandaloneModuleGraph.zig index 6d8ab7784e..25af9694dc 100644 --- a/src/StandaloneModuleGraph.zig +++ b/src/StandaloneModuleGraph.zig @@ -670,7 +670,7 @@ pub const StandaloneModuleGraph = struct { if (!tried_changing_abs_dir) { tried_changing_abs_dir = true; const zname_z = bun.strings.concat(bun.default_allocator, &.{ - bun.fs.FileSystem.instance.fs.tmpdirPath(), + bun.fs.FileSystem.RealFS.tmpdirPath(), std.fs.path.sep_str, zname, &.{0}, diff --git a/src/bun.js/ModuleLoader.zig b/src/bun.js/ModuleLoader.zig index 0ea84ff9b3..ac65cbc4b7 100644 --- a/src/bun.js/ModuleLoader.zig +++ b/src/bun.js/ModuleLoader.zig @@ -92,7 +92,7 @@ pub fn resolveEmbeddedFile(vm: *VirtualMachine, path_buf: *bun.PathBuffer, linux }, else => {}, } - return bun.path.joinAbsStringBuf(bun.fs.FileSystem.instance.fs.tmpdirPath(), path_buf, &[_]string{tmpfilename}, .auto); + return bun.path.joinAbsStringBuf(bun.fs.FileSystem.RealFS.tmpdirPath(), path_buf, &[_]string{tmpfilename}, .auto); } pub export fn Bun__getDefaultLoader(global: *JSGlobalObject, str: *const bun.String) api.Loader { diff --git a/src/bun.js/RuntimeTranspilerCache.zig b/src/bun.js/RuntimeTranspilerCache.zig index ed5f9996d8..3f8125de1a 100644 --- a/src/bun.js/RuntimeTranspilerCache.zig +++ b/src/bun.js/RuntimeTranspilerCache.zig @@ -423,7 +423,7 @@ pub const RuntimeTranspilerCache = struct { } { - const parts = &[_][]const u8{ bun.fs.FileSystem.instance.fs.tmpdirPath(), "bun", "@t@" }; + const parts = &[_][]const u8{ bun.fs.FileSystem.RealFS.tmpdirPath(), "bun", "@t@" }; return bun.fs.FileSystem.instance.absBufZ(parts, buf); } } diff --git a/src/env_var.zig b/src/env_var.zig index 13fea31056..b97ed0a7bf 100644 --- a/src/env_var.zig +++ b/src/env_var.zig @@ -109,11 +109,11 @@ pub const SHELL = PlatformSpecificNew(kind.string, "SHELL", null, .{}); /// C:\Windows, for example. /// Note: Do not use this variable directly -- use os.zig's implementation instead. pub const SYSTEMROOT = PlatformSpecificNew(kind.string, null, "SYSTEMROOT", .{}); -pub const TEMP = PlatformSpecificNew(kind.string, null, "TEMP", .{}); +pub const TEMP = PlatformSpecificNew(kind.string, "TEMP", "TEMP", .{}); pub const TERM = New(kind.string, "TERM", .{}); pub const TERM_PROGRAM = New(kind.string, "TERM_PROGRAM", .{}); -pub const TMP = PlatformSpecificNew(kind.string, null, "TMP", .{}); -pub const TMPDIR = PlatformSpecificNew(kind.string, "TMPDIR", null, .{}); +pub const TMP = PlatformSpecificNew(kind.string, "TMP", "TMP", .{}); +pub const TMPDIR = PlatformSpecificNew(kind.string, "TMPDIR", "TMPDIR", .{}); pub const TMUX = New(kind.string, "TMUX", .{}); pub const TODIUM = New(kind.string, "TODIUM", .{}); pub const USER = PlatformSpecificNew(kind.string, "USER", "USERNAME", .{}); @@ -601,6 +601,16 @@ fn PlatformSpecificNew( return null; } + pub fn getNotEmpty() ReturnType { + if (Self.get()) |v| { + if (v.len == 0) { + return null; + } + return v; + } + return null; + } + /// Retrieve the value of the environment variable, loading it if necessary. /// Fails if the current platform is unsupported. pub fn get() ReturnType { diff --git a/src/fs.zig b/src/fs.zig index e9e3a1048d..8faf21810c 100644 --- a/src/fs.zig +++ b/src/fs.zig @@ -530,69 +530,69 @@ pub const FileSystem = struct { file_limit: usize = 32, file_quota: usize = 32, - pub var win_tempdir_cache: ?[]const u8 = undefined; + fn #platformTempDir() []const u8 { + // Try TMPDIR, TMP, and TEMP in that order, matching Node.js. + // https://github.com/nodejs/node/blob/e172be269890702bf2ad06252f2f152e7604d76c/src/node_credentials.cc#L132 + if (bun.env_var.TMPDIR.getNotEmpty() orelse + bun.env_var.TMP.getNotEmpty() orelse + bun.env_var.TEMP.getNotEmpty()) |dir| + { + if (dir.len > 1 and dir[dir.len - 1] == std.fs.path.sep) { + return dir[0 .. dir.len - 1]; + } + + return dir; + } - pub fn platformTempDir() []const u8 { return switch (Environment.os) { // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppathw#remarks - .windows => win_tempdir_cache orelse { - const value = bun.env_var.TEMP.get() orelse bun.env_var.TMP.get() orelse brk: { - if (bun.env_var.SYSTEMROOT.get() orelse bun.env_var.WINDIR.get()) |windir| { - break :brk std.fmt.allocPrint( - bun.default_allocator, - "{s}\\Temp", - .{strings.withoutTrailingSlash(windir)}, - ) catch |err| bun.handleOom(err); - } - - if (bun.env_var.HOME.get()) |profile| { - var buf: bun.PathBuffer = undefined; - var parts = [_]string{"AppData\\Local\\Temp"}; - const out = bun.path.joinAbsStringBuf(profile, &buf, &parts, .loose); - break :brk bun.handleOom(bun.default_allocator.dupe(u8, out)); - } - - var tmp_buf: bun.PathBuffer = undefined; - const cwd = std.posix.getcwd(&tmp_buf) catch @panic("Failed to get cwd for platformTempDir"); - const root = bun.path.windowsFilesystemRoot(cwd); - break :brk std.fmt.allocPrint( + .windows => { + if (bun.env_var.SYSTEMROOT.get() orelse bun.env_var.WINDIR.get()) |windir| { + return std.fmt.allocPrint( bun.default_allocator, - "{s}\\Windows\\Temp", - .{strings.withoutTrailingSlash(root)}, + "{s}\\Temp", + .{strings.withoutTrailingSlash(windir)}, ) catch |err| bun.handleOom(err); - }; - win_tempdir_cache = value; - return value; + } + + if (bun.env_var.HOME.get()) |profile| { + var buf: bun.PathBuffer = undefined; + var parts = [_]string{"AppData\\Local\\Temp"}; + const out = bun.path.joinAbsStringBuf(profile, &buf, &parts, .loose); + return bun.handleOom(bun.default_allocator.dupe(u8, out)); + } + + var tmp_buf: bun.PathBuffer = undefined; + const cwd = std.posix.getcwd(&tmp_buf) catch @panic("Failed to get cwd for platformTempDir"); + const root = bun.path.windowsFilesystemRoot(cwd); + return std.fmt.allocPrint( + bun.default_allocator, + "{s}\\Windows\\Temp", + .{strings.withoutTrailingSlash(root)}, + ) catch |err| bun.handleOom(err); }, .mac => "/private/tmp", else => "/tmp", }; } + var get_platform_tempdir = bun.once(#platformTempDir); + pub fn platformTempDir() []const u8 { + return get_platform_tempdir.call(.{}); + } + pub const Tmpfile = switch (Environment.os) { .windows => TmpfileWindows, else => TmpfilePosix, }; - pub var tmpdir_path: []const u8 = undefined; - pub var tmpdir_path_set = false; - pub fn tmpdirPath(_: *const @This()) []const u8 { - if (!tmpdir_path_set) { - tmpdir_path = bun.env_var.BUN_TMPDIR.get() orelse platformTempDir(); - tmpdir_path_set = true; - } - - return tmpdir_path; + pub fn tmpdirPath() []const u8 { + return bun.env_var.BUN_TMPDIR.getNotEmpty() orelse platformTempDir(); } pub fn openTmpDir(_: *const RealFS) !std.fs.Dir { - if (!tmpdir_path_set) { - tmpdir_path = bun.env_var.BUN_TMPDIR.get() orelse platformTempDir(); - tmpdir_path_set = true; - } - if (comptime Environment.isWindows) { - return (try bun.sys.openDirAtWindowsA(bun.invalid_fd, tmpdir_path, .{ + return (try bun.sys.openDirAtWindowsA(bun.invalid_fd, tmpdirPath(), .{ .iterable = true, // we will not delete the temp directory .can_rename_or_delete = false, @@ -600,7 +600,7 @@ pub const FileSystem = struct { }).unwrap()).stdDir(); } - return try bun.openDirAbsolute(tmpdir_path); + return try bun.openDirAbsolute(tmpdirPath()); } pub fn entriesAt(this: *RealFS, index: allocators.IndexType, generation: bun.Generation) ?*EntriesOption { @@ -639,11 +639,6 @@ pub const FileSystem = struct { return bun.env_var.BUN_TMPDIR.get() orelse platformTempDir(); } - pub fn setTempdir(path: ?string) void { - tmpdir_path = path orelse getDefaultTempDir(); - tmpdir_path_set = true; - } - pub const TmpfilePosix = struct { fd: bun.FileDescriptor = bun.invalid_fd, dir_fd: bun.FileDescriptor = bun.invalid_fd,