aboutsummaryrefslogtreecommitdiff
path: root/src/os/root_unix.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/os/root_unix.go')
-rw-r--r--src/os/root_unix.go14
1 files changed, 12 insertions, 2 deletions
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
})