diff --git a/src/os/root_unix.go b/src/os/root_unix.go index af963f472d..ed21afffb5 100644 --- a/src/os/root_unix.go +++ b/src/os/root_unix.go @@ -83,8 +83,18 @@ func rootOpenFileNolog(root *Root, name string, flag int, perm FileMode) (*File, fd, err := doInRoot(root, name, nil, func(parent int, name string) (fd int, err error) { ignoringEINTR(func() error { fd, err = unix.Openat(parent, name, syscall.O_NOFOLLOW|syscall.O_CLOEXEC|flag, uint32(perm)) - if isNoFollowErr(err) || err == syscall.ENOTDIR { - err = checkSymlink(parent, name, err) + if err != nil { + // Never follow symlinks when O_CREATE|O_EXCL, no matter + // what error the OS returns. + isCreateExcl := flag&(O_CREATE|O_EXCL) == (O_CREATE | O_EXCL) + if !isCreateExcl && (isNoFollowErr(err) || err == syscall.ENOTDIR) { + err = checkSymlink(parent, name, err) + } + // AIX returns ELOOP instead of EEXIST for a dangling symlink. + // Convert this to EEXIST so it matches ErrExists. + if isCreateExcl && err == syscall.ELOOP { + err = syscall.EEXIST + } } return err })