package nativepath import ( "path/filepath" "sync" "unsafe" "golang.org/x/sys/unix" ) // On macOS, we use open + fcntl(F_GETPATH) to resolve the canonical path in // O(1) syscalls instead of Go's filepath.EvalSymlinks which does an lstat per // path component — O(depth). // // How it works: // - open(path, O_EVTONLY|O_NONBLOCK|O_CLOEXEC) follows all symlinks and gives // us a lightweight fd. O_EVTONLY is macOS's event-only descriptor — it // doesn't require read permission (similar to Linux's O_PATH) but still // references the vnode. O_NONBLOCK prevents blocking on FIFOs. // - fcntl(fd, F_GETPATH, buf) asks the kernel for the canonical path of the // open file descriptor, written into a MAXPATHLEN buffer. // // unix.FcntlInt takes an int arg, so call it through a uintptr-escaping wrapper // to keep the buffer pointer valid until fcntl returns. var hasFGetPath = sync.OnceValue(func() bool { // Verify that F_GETPATH is supported by this kernel version. var buf [unix.PathMax]byte fd, err := unix.Open(".", unix.O_EVTONLY|unix.O_NONBLOCK|unix.O_CLOEXEC, 0) if err != nil { return false } defer unix.Close(fd) _, err = fcntlGetPath(fd, &buf) return err == nil }) func fcntlGetPath(fd int, buf *[unix.PathMax]byte) (int, error) { return ignoringEINTR(func() (int, error) { return fcntlGetPathPtr(uintptr(fd), uintptr(unsafe.Pointer(&buf[0]))) }) } //go:uintptrescapes func fcntlGetPathPtr(fd uintptr, buf uintptr) (int, error) { return unix.FcntlInt(fd, unix.F_GETPATH, int(buf)) } func Realpath(path string) (string, error) { if !hasFGetPath() { return filepath.EvalSymlinks(path) } fd, err := unix.Open(path, unix.O_EVTONLY|unix.O_NONBLOCK|unix.O_CLOEXEC, 0) if err != nil { return "", err } defer unix.Close(fd) var buf [unix.PathMax]byte if _, err := fcntlGetPath(fd, &buf); err != nil { return "", err } return unix.ByteSliceToString(buf[:]), nil }