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
})