diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-07 18:29:21 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-07 18:29:21 +0300 |
| commit | dcfe11a7588fcd42471159453810abc9b7720a57 (patch) | |
| tree | c32a77266028e73ca2382b96c96f8438a5fcd621 /vendor/libghostty-vt/src/os/file.zig | |
| parent | 2dfed860103c4e4505ac7f25def9fe37da1e1e6a (diff) | |
build: update libghostty-vt vendor
vendor ghostty 063ac3e and remove the musl libc++ link workaround.
expose the new selection formatter and hyperlink uri apis for follow-up rendering work.
add manual artifact validation for static linux builds.
Diffstat (limited to 'vendor/libghostty-vt/src/os/file.zig')
| -rw-r--r-- | vendor/libghostty-vt/src/os/file.zig | 103 |
1 files changed, 86 insertions, 17 deletions
diff --git a/vendor/libghostty-vt/src/os/file.zig b/vendor/libghostty-vt/src/os/file.zig index 240c936e..6007ae49 100644 --- a/vendor/libghostty-vt/src/os/file.zig +++ b/vendor/libghostty-vt/src/os/file.zig @@ -1,6 +1,7 @@ const std = @import("std"); const builtin = @import("builtin"); const posix = std.posix; +const windows = @import("windows.zig"); const log = std.log.scoped(.os); @@ -53,27 +54,95 @@ pub fn restoreMaxFiles(lim: rlimit) void { posix.setrlimit(.NOFILE, lim) catch {}; } -/// Return the recommended path for temporary files. -/// This may not actually allocate memory, use freeTmpDir to properly -/// free the memory when applicable. -pub fn allocTmpDir(allocator: std.mem.Allocator) ?[]const u8 { +/// Return the recommended path for temporary files. Any trailing +/// path separator is stripped so callers can safely join with their +/// own separator (e.g. `"{tmp}/{name}"`). +/// +/// On Windows this calls `GetTempPathW` and allocates a UTF-8 copy +/// (or duplicates a hard-fallback string if the syscall fails). On +/// POSIX this returns `$TMPDIR`/`$TMP` (or `"/tmp"` as a fallback) +/// without allocating. Always pair with `freeTmpDir` to release any +/// allocation. +pub fn allocTmpDir(allocator: std.mem.Allocator) std.mem.Allocator.Error![]const u8 { if (builtin.os.tag == .windows) { - // TODO: what is a good fallback path on windows? - const v = std.process.getenvW(std.unicode.utf8ToUtf16LeStringLiteral("TMP")) orelse return null; - return std.unicode.utf16LeToUtf8Alloc(allocator, v) catch |e| { - log.warn("failed to convert temp dir path from windows string: {}", .{e}); - return null; - }; + // GetTempPathW guarantees the result fits in MAX_PATH+1. + var buf: [windows.MAX_PATH + 1:0]u16 = undefined; + const len = windows.exp.kernel32.GetTempPathW(buf.len, &buf); + if (len > 0) { + // Trim the UTF-16 string before encoding as UT8-8 so that the + // returned slice's length matches its underlying allocation. + const trimmed = std.mem.trimEnd(u16, buf[0..len], &.{std.fs.path.sep}); + if (std.unicode.utf16LeToUtf8Alloc(allocator, trimmed)) |utf8| { + return utf8; + } else |e| switch (e) { + error.OutOfMemory => return error.OutOfMemory, + else => log.warn("failed to convert temp dir path from windows string: {}", .{e}), + } + } + return allocator.dupe(u8, "C:\\Windows\\Temp"); } - if (posix.getenv("TMPDIR")) |v| return v; - if (posix.getenv("TMP")) |v| return v; - return "/tmp"; + const tmpdir = posix.getenv("TMPDIR") orelse posix.getenv("TMP") orelse return "/tmp"; + return std.mem.trimEnd(u8, tmpdir, &.{std.fs.path.sep}); } -/// Free a path returned by tmpDir if it allocated memory. -/// This is a "no-op" for all platforms except windows. +/// Free a path returned by `allocTmpDir` if it allocated memory. +/// This is a no-op on POSIX. pub fn freeTmpDir(allocator: std.mem.Allocator, dir: []const u8) void { - if (builtin.os.tag == .windows) { - allocator.free(dir); + if (builtin.os.tag != .windows) return; + allocator.free(dir); +} + +const random_basename_bytes = 16; +const b64_encoder = std.base64.url_safe_no_pad.Encoder; + +pub const RandomBasenameError = error{BufferTooSmall}; + +/// Length of the basename produced by `randomBasename`. +pub const random_basename_len = b64_encoder.calcSize(random_basename_bytes); + +/// Write a random filesystem-safe base64 basename of length +/// `random_basename_len` into `buf` and return a slice over the +/// written bytes. Returns `error.BufferTooSmall` if `buf` is too +/// short. +pub fn randomBasename(buf: []u8) RandomBasenameError![]const u8 { + if (buf.len < random_basename_len) return error.BufferTooSmall; + var rand_buf: [random_basename_bytes]u8 = undefined; + std.crypto.random.bytes(&rand_buf); + return b64_encoder.encode(buf[0..random_basename_len], &rand_buf); +} + +/// Return a freshly-allocated path of the form `{TMPDIR}/{prefix}{random}`. +/// The caller owns the returned slice and must free it with `allocator`. +/// +/// Nothing is created on disk; this only builds the path string. Useful +/// for one-shot temporary file/socket paths where a full `TempDir` is +/// overkill. +pub fn randomTmpPath( + allocator: std.mem.Allocator, + prefix: []const u8, +) std.mem.Allocator.Error![]u8 { + const tmp_dir = try allocTmpDir(allocator); + defer freeTmpDir(allocator, tmp_dir); + var name_buf: [random_basename_len]u8 = undefined; + const basename = randomBasename(&name_buf) catch unreachable; + return std.fmt.allocPrint( + allocator, + "{s}{c}{s}{s}", + .{ tmp_dir, std.fs.path.sep, prefix, basename }, + ); +} + +test randomBasename { + const testing = std.testing; + + var buf: [random_basename_len]u8 = undefined; + const name = try randomBasename(&buf); + try testing.expectEqual(random_basename_len, name.len); + for (name) |c| { + const ok = std.ascii.isAlphanumeric(c) or c == '-' or c == '_'; + try testing.expect(ok); } + + var small: [random_basename_len - 1]u8 = undefined; + try testing.expectError(error.BufferTooSmall, randomBasename(&small)); } |
