43 lines
1.3 KiB
Go
43 lines
1.3 KiB
Go
//go:build darwin
|
|
|
|
package main
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
// mcpOpenRegular opens path for reading only if what it names, after any
|
|
// symlinks, is a regular file, without ever opening anything else. macOS has
|
|
// no O_PATH, so the links are resolved first, the resolved path is required
|
|
// to be a regular file, and it is then opened with O_NOFOLLOW_ANY: a link
|
|
// put in its place since the look makes the open fail rather than lead
|
|
// somewhere new, and a device can only sit in devfs, which the look already
|
|
// refused. The opened file must be the one looked at.
|
|
func mcpOpenRegular(path string) (*os.File, string, error) {
|
|
resolved, err := filepath.EvalSymlinks(path)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
lst, err := os.Lstat(resolved)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
if !lst.Mode().IsRegular() {
|
|
return nil, "", errMCPNotRegular
|
|
}
|
|
fd, err := unix.Open(resolved, unix.O_RDONLY|unix.O_CLOEXEC|unix.O_NOCTTY|unix.O_NONBLOCK|unix.O_NOFOLLOW_ANY, 0)
|
|
if err != nil {
|
|
return nil, "", &os.PathError{Op: "open", Path: path, Err: err}
|
|
}
|
|
f := os.NewFile(uintptr(fd), path)
|
|
fi, err := f.Stat()
|
|
if err != nil || !fi.Mode().IsRegular() || !os.SameFile(fi, lst) {
|
|
f.Close()
|
|
return nil, "", errMCPNotRegular
|
|
}
|
|
return f, mcpFileOwner(fi), nil
|
|
}
|