mirror of
https://github.com/ziglang/zig.git
synced 2025-12-17 03:33:06 +00:00
Merge pull request #16885 from squeek502/windows-selfExePath-symlink
`fs.selfExePath`: Make the Windows implementation follow symlinks
This commit is contained in:
commit
4c97919e8e
@ -2949,8 +2949,12 @@ pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File {
|
|||||||
return openFileAbsoluteZ("/proc/self/exe", flags);
|
return openFileAbsoluteZ("/proc/self/exe", flags);
|
||||||
}
|
}
|
||||||
if (builtin.os.tag == .windows) {
|
if (builtin.os.tag == .windows) {
|
||||||
const wide_slice = selfExePathW();
|
// If ImagePathName is a symlink, then it will contain the path of the symlink,
|
||||||
const prefixed_path_w = try os.windows.wToPrefixedFileW(null, wide_slice);
|
// not the path that the symlink points to. However, because we are opening
|
||||||
|
// the file, we can let the openFileW call follow the symlink for us.
|
||||||
|
const image_path_unicode_string = &os.windows.peb().ProcessParameters.ImagePathName;
|
||||||
|
const image_path_name = image_path_unicode_string.Buffer[0 .. image_path_unicode_string.Length / 2 :0];
|
||||||
|
const prefixed_path_w = try os.windows.wToPrefixedFileW(null, image_path_name);
|
||||||
return cwd().openFileW(prefixed_path_w.span(), flags);
|
return cwd().openFileW(prefixed_path_w.span(), flags);
|
||||||
}
|
}
|
||||||
// Use of MAX_PATH_BYTES here is valid as the resulting path is immediately
|
// Use of MAX_PATH_BYTES here is valid as the resulting path is immediately
|
||||||
@ -2977,7 +2981,7 @@ pub fn selfExePathAlloc(allocator: Allocator) ![]u8 {
|
|||||||
return allocator.dupe(u8, try selfExePath(&buf));
|
return allocator.dupe(u8, try selfExePath(&buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the path to the current executable.
|
/// Get the path to the current executable. Follows symlinks.
|
||||||
/// If you only need the directory, use selfExeDirPath.
|
/// If you only need the directory, use selfExeDirPath.
|
||||||
/// If you only want an open file handle, use openSelfExe.
|
/// If you only want an open file handle, use openSelfExe.
|
||||||
/// This function may return an error if the current executable
|
/// This function may return an error if the current executable
|
||||||
@ -3060,21 +3064,21 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 {
|
|||||||
return error.FileNotFound;
|
return error.FileNotFound;
|
||||||
},
|
},
|
||||||
.windows => {
|
.windows => {
|
||||||
const utf16le_slice = selfExePathW();
|
const image_path_unicode_string = &os.windows.peb().ProcessParameters.ImagePathName;
|
||||||
// Trust that Windows gives us valid UTF-16LE.
|
const image_path_name = image_path_unicode_string.Buffer[0 .. image_path_unicode_string.Length / 2 :0];
|
||||||
const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
|
|
||||||
return out_buffer[0..end_index];
|
// If ImagePathName is a symlink, then it will contain the path of the
|
||||||
|
// symlink, not the path that the symlink points to. We want the path
|
||||||
|
// that the symlink points to, though, so we need to get the realpath.
|
||||||
|
const pathname_w = try os.windows.wToPrefixedFileW(null, image_path_name);
|
||||||
|
return std.fs.cwd().realpathW(pathname_w.span(), out_buffer);
|
||||||
},
|
},
|
||||||
.wasi => @compileError("std.fs.selfExePath not supported for WASI. Use std.fs.selfExePathAlloc instead."),
|
.wasi => @compileError("std.fs.selfExePath not supported for WASI. Use std.fs.selfExePathAlloc instead."),
|
||||||
else => @compileError("std.fs.selfExePath not supported for this target"),
|
else => @compileError("std.fs.selfExePath not supported for this target"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The result is UTF16LE-encoded.
|
pub const selfExePathW = @compileError("deprecated; use selfExePath instead");
|
||||||
pub fn selfExePathW() [:0]const u16 {
|
|
||||||
const image_path_name = &os.windows.peb().ProcessParameters.ImagePathName;
|
|
||||||
return image_path_name.Buffer[0 .. image_path_name.Length / 2 :0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `selfExeDirPath` except allocates the result on the heap.
|
/// `selfExeDirPath` except allocates the result on the heap.
|
||||||
/// Caller owns returned memory.
|
/// Caller owns returned memory.
|
||||||
|
|||||||
@ -198,6 +198,10 @@ pub const build_cases = [_]BuildCase{
|
|||||||
.build_root = "test/standalone/windows_spawn",
|
.build_root = "test/standalone/windows_spawn",
|
||||||
.import = @import("standalone/windows_spawn/build.zig"),
|
.import = @import("standalone/windows_spawn/build.zig"),
|
||||||
},
|
},
|
||||||
|
.{
|
||||||
|
.build_root = "test/standalone/self_exe_symlink",
|
||||||
|
.import = @import("standalone/self_exe_symlink/build.zig"),
|
||||||
|
},
|
||||||
.{
|
.{
|
||||||
.build_root = "test/standalone/c_compiler",
|
.build_root = "test/standalone/c_compiler",
|
||||||
.import = @import("standalone/c_compiler/build.zig"),
|
.import = @import("standalone/c_compiler/build.zig"),
|
||||||
|
|||||||
43
test/standalone/self_exe_symlink/build.zig
Normal file
43
test/standalone/self_exe_symlink/build.zig
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub const requires_symlinks = true;
|
||||||
|
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
const test_step = b.step("test", "Test it");
|
||||||
|
b.default_step = test_step;
|
||||||
|
|
||||||
|
const optimize: std.builtin.OptimizeMode = .Debug;
|
||||||
|
const target: std.zig.CrossTarget = .{};
|
||||||
|
|
||||||
|
// The test requires getFdPath in order to to get the path of the
|
||||||
|
// File returned by openSelfExe
|
||||||
|
if (!std.os.isGetFdPathSupportedOnTarget(target.getOs())) return;
|
||||||
|
|
||||||
|
const main = b.addExecutable(.{
|
||||||
|
.name = "main",
|
||||||
|
.root_source_file = .{ .path = "main.zig" },
|
||||||
|
.optimize = optimize,
|
||||||
|
.target = target,
|
||||||
|
});
|
||||||
|
|
||||||
|
const create_symlink_exe = b.addExecutable(.{
|
||||||
|
.name = "create-symlink",
|
||||||
|
.root_source_file = .{ .path = "create-symlink.zig" },
|
||||||
|
.optimize = optimize,
|
||||||
|
.target = target,
|
||||||
|
});
|
||||||
|
|
||||||
|
var run_create_symlink = b.addRunArtifact(create_symlink_exe);
|
||||||
|
run_create_symlink.addArtifactArg(main);
|
||||||
|
const symlink_path = run_create_symlink.addOutputFileArg("main-symlink");
|
||||||
|
run_create_symlink.expectExitCode(0);
|
||||||
|
run_create_symlink.skip_foreign_checks = true;
|
||||||
|
|
||||||
|
var run_from_symlink = std.Build.Step.Run.create(b, "run symlink");
|
||||||
|
run_from_symlink.addFileArg(symlink_path);
|
||||||
|
run_from_symlink.expectExitCode(0);
|
||||||
|
run_from_symlink.skip_foreign_checks = true;
|
||||||
|
run_from_symlink.step.dependOn(&run_create_symlink.step);
|
||||||
|
|
||||||
|
test_step.dependOn(&run_from_symlink.step);
|
||||||
|
}
|
||||||
15
test/standalone/self_exe_symlink/create-symlink.zig
Normal file
15
test/standalone/self_exe_symlink/create-symlink.zig
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn main() anyerror!void {
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
defer if (gpa.deinit() == .leak) @panic("found memory leaks");
|
||||||
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
|
var it = try std.process.argsWithAllocator(allocator);
|
||||||
|
defer it.deinit();
|
||||||
|
_ = it.next() orelse unreachable; // skip binary name
|
||||||
|
const exe_path = it.next() orelse unreachable;
|
||||||
|
const symlink_path = it.next() orelse unreachable;
|
||||||
|
|
||||||
|
try std.fs.cwd().symLink(exe_path, symlink_path, .{});
|
||||||
|
}
|
||||||
17
test/standalone/self_exe_symlink/main.zig
Normal file
17
test/standalone/self_exe_symlink/main.zig
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
defer std.debug.assert(gpa.deinit() == .ok);
|
||||||
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
|
const self_path = try std.fs.selfExePathAlloc(allocator);
|
||||||
|
defer allocator.free(self_path);
|
||||||
|
|
||||||
|
var self_exe = try std.fs.openSelfExe(.{});
|
||||||
|
defer self_exe.close();
|
||||||
|
var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
|
const self_exe_path = try std.os.getFdPath(self_exe.handle, &buf);
|
||||||
|
|
||||||
|
try std.testing.expectEqualStrings(self_exe_path, self_path);
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user