Commit a2074c1ec3

Loris Cro <kappaloris@gmail.com>
2020-10-02 17:06:29
fix symlink path not being resolved in darwin
Signed-off-by: Loris Cro <kappaloris@gmail.com>
1 parent e9434ff
Changed files (2)
lib
lib/std/fs.zig
@@ -2162,7 +2162,7 @@ pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File {
     return openFileAbsoluteZ(buf[0..self_exe_path.len :0].ptr, flags);
 }
 
-pub const SelfExePathError = os.ReadLinkError || os.SysCtlError;
+pub const SelfExePathError = os.ReadLinkError || os.SysCtlError || os.RealPathError;
 
 /// `selfExePath` except allocates the result on the heap.
 /// Caller owns returned memory.
@@ -2190,10 +2190,18 @@ pub fn selfExePathAlloc(allocator: *Allocator) ![]u8 {
 /// TODO make the return type of this a null terminated pointer
 pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 {
     if (is_darwin) {
-        var u32_len: u32 = @intCast(u32, math.min(out_buffer.len, math.maxInt(u32)));
-        const rc = std.c._NSGetExecutablePath(out_buffer.ptr, &u32_len);
+        // Note that _NSGetExecutablePath() will return "a path" to
+        // the executable not a "real path" to the executable.
+        var symlink_path_buf: [MAX_PATH_BYTES]u8 = undefined;
+        var u32_len: u32 = MAX_PATH_BYTES;
+        const rc = std.c._NSGetExecutablePath(&symlink_path_buf, &u32_len);
         if (rc != 0) return error.NameTooLong;
-        return mem.spanZ(@ptrCast([*:0]u8, out_buffer));
+
+        var real_path_buf: [MAX_PATH_BYTES]u8 = undefined;
+        const real_path = try std.os.realpathZ(@ptrCast([*:0]u8, &symlink_path_buf), &real_path_buf);
+        if (real_path.len > out_buffer.len) return error.NameTooLong;
+        std.mem.copy(u8, out_buffer, real_path);
+        return out_buffer[0..real_path.len];
     }
     switch (builtin.os.tag) {
         .linux => return os.readlinkZ("/proc/self/exe", out_buffer),
lib/std/os.zig
@@ -3993,7 +3993,7 @@ pub const RealPathError = error{
 /// Expands all symbolic links and resolves references to `.`, `..`, and
 /// extra `/` characters in `pathname`.
 /// The return value is a slice of `out_buffer`, but not necessarily from the beginning.
-/// See also `realpathC` and `realpathW`.
+/// See also `realpathZ` and `realpathW`.
 pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
     if (builtin.os.tag == .windows) {
         const pathname_w = try windows.sliceToPrefixedFileW(pathname);