aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/src/os/file.zig
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-05-07 18:29:21 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-05-07 18:29:21 +0300
commitdcfe11a7588fcd42471159453810abc9b7720a57 (patch)
treec32a77266028e73ca2382b96c96f8438a5fcd621 /vendor/libghostty-vt/src/os/file.zig
parent2dfed860103c4e4505ac7f25def9fe37da1e1e6a (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.zig103
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));
}