vendor tsgo

This commit is contained in:
2026-07-09 16:50:43 -04:00
parent c06ea2e5a4
commit 98978e4930
5804 changed files with 1556156 additions and 101 deletions

View File

@@ -0,0 +1,70 @@
package nativepath
import (
"os"
"path/filepath"
"strconv"
"sync"
"golang.org/x/sys/unix"
)
// On Linux, we use the O_PATH + /proc/self/fd trick to resolve the canonical
// path in O(1) syscalls (open + readlink + close) instead of Go's
// filepath.EvalSymlinks which does an lstat per path component — O(depth).
//
// This is the approach libuv/Node.js could use, though libuv currently just
// calls C realpath(3) which itself does a readlink per component. On the Go
// side, the per-component approach is even more expensive because each
// os.Lstat call involves goroutine scheduling overhead (entersyscall /
// exitsyscall).
//
// How it works:
// - open(path, O_PATH|O_CLOEXEC) gives us a lightweight fd that follows all
// symlinks to the final target. O_PATH requires only search permission on
// directories (same as lstat), and works for both files and directories.
// - readlink("/proc/self/fd/<fd>") returns the fully resolved canonical path
// that the kernel computed during the open.
//
// Falls back to filepath.EvalSymlinks if /proc is not available (e.g. containers
// or chroots without procfs mounted).
const _procSelfFD = "/proc/self/fd/"
var hasProcSelfFD = sync.OnceValue(func() bool {
var stat unix.Stat_t
return unix.Stat(_procSelfFD, &stat) == nil
})
func Realpath(path string) (string, error) {
if !hasProcSelfFD() {
return filepath.EvalSymlinks(path)
}
fd, err := ignoringEINTR(func() (int, error) {
return unix.Open(path, unix.O_CLOEXEC|unix.O_PATH, 0)
})
if err != nil {
return "", &os.PathError{Op: "open", Path: path, Err: err}
}
defer unix.Close(fd)
var procBuf [len(_procSelfFD) + 20]byte // 20 digits is enough for any int64 fd
n := copy(procBuf[:], _procSelfFD)
n += copy(procBuf[n:], strconv.Itoa(fd))
procPath := string(procBuf[:n])
buf := make([]byte, 256)
for {
nn, err := ignoringEINTR(func() (int, error) {
return unix.Readlink(procPath, buf)
})
if err != nil {
return "", &os.PathError{Op: "readlink", Path: path, Err: err}
}
if nn < len(buf) {
return string(buf[:nn]), nil
}
buf = make([]byte, len(buf)*2)
}
}