From 3b6aa03c127ac9600ed17bd27ae94088b741846e Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Thu, 30 May 2024 14:00:40 -0700 Subject: [PATCH] os: RemoveAll: fix error returned When unlink fails, it is not yet known if the argument is a directory or not. Since CL 588495, we figure out if it's a directory when trying to open it (and, for a directory, return the original unlink error). The (very minor) issue is, in case of a symlink, a different error is returned -- usually it's ELOOP, but some systems use other values. Let's account for that error code, too. This is a followup to CL 588495. Change-Id: I4ee10fe9b57f045fbca02f13e5c9ea16972803bc Reviewed-on: https://go-review.googlesource.com/c/go/+/589376 Reviewed-by: Michael Pratt Run-TryBot: Kirill Kolyshkin Auto-Submit: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI TryBot-Result: Gopher Robot Reviewed-by: Ian Lance Taylor --- src/internal/syscall/unix/constants.go | 5 +++++ src/internal/syscall/unix/nofollow_bsd.go | 14 +++++++++++++ src/internal/syscall/unix/nofollow_netbsd.go | 10 +++++++++ src/internal/syscall/unix/nofollow_posix.go | 22 ++++++++++++++++++++ src/os/removeall_at.go | 2 +- 5 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 src/internal/syscall/unix/nofollow_bsd.go create mode 100644 src/internal/syscall/unix/nofollow_netbsd.go create mode 100644 src/internal/syscall/unix/nofollow_posix.go diff --git a/src/internal/syscall/unix/constants.go b/src/internal/syscall/unix/constants.go index e324589705..28092c2ddf 100644 --- a/src/internal/syscall/unix/constants.go +++ b/src/internal/syscall/unix/constants.go @@ -10,4 +10,9 @@ const ( R_OK = 0x4 W_OK = 0x2 X_OK = 0x1 + + // NoFollowErrno is the error returned from open/openat called with + // O_NOFOLLOW flag, when the trailing component (basename) of the path + // is a symbolic link. + NoFollowErrno = noFollowErrno ) diff --git a/src/internal/syscall/unix/nofollow_bsd.go b/src/internal/syscall/unix/nofollow_bsd.go new file mode 100644 index 0000000000..32c4de1190 --- /dev/null +++ b/src/internal/syscall/unix/nofollow_bsd.go @@ -0,0 +1,14 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build dragonfly || freebsd + +package unix + +import "syscall" + +// References: +// - https://man.freebsd.org/cgi/man.cgi?open(2) +// - https://man.dragonflybsd.org/?command=open§ion=2 +const noFollowErrno = syscall.EMLINK diff --git a/src/internal/syscall/unix/nofollow_netbsd.go b/src/internal/syscall/unix/nofollow_netbsd.go new file mode 100644 index 0000000000..3ae91e79cd --- /dev/null +++ b/src/internal/syscall/unix/nofollow_netbsd.go @@ -0,0 +1,10 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix + +import "syscall" + +// Reference: https://man.netbsd.org/open.2 +const noFollowErrno = syscall.EFTYPE diff --git a/src/internal/syscall/unix/nofollow_posix.go b/src/internal/syscall/unix/nofollow_posix.go new file mode 100644 index 0000000000..de2ea14fc8 --- /dev/null +++ b/src/internal/syscall/unix/nofollow_posix.go @@ -0,0 +1,22 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix && !dragonfly && !freebsd && !netbsd + +package unix + +import "syscall" + +// POSIX.1-2008 says it's ELOOP. Most platforms follow: +// +// - aix: O_NOFOLLOW not documented (https://www.ibm.com/docs/ssw_aix_73/o_bostechref/open.html), assuming ELOOP +// - android: see linux +// - darwin: https://github.com/apple/darwin-xnu/blob/main/bsd/man/man2/open.2 +// - hurd: who knows if it works at all (https://www.gnu.org/software/hurd/open_issues/open_symlink.html) +// - illumos: https://illumos.org/man/2/open +// - ios: see darwin +// - linux: https://man7.org/linux/man-pages/man2/openat.2.html +// - openbsd: https://man.openbsd.org/open.2 +// - solaris: https://docs.oracle.com/cd/E23824_01/html/821-1463/open-2.html +const noFollowErrno = syscall.ELOOP diff --git a/src/os/removeall_at.go b/src/os/removeall_at.go index 2a12add7a2..cc254e0043 100644 --- a/src/os/removeall_at.go +++ b/src/os/removeall_at.go @@ -88,7 +88,7 @@ func removeAllFrom(parent *File, base string) error { if IsNotExist(err) { return nil } - if err == syscall.ENOTDIR { + if err == syscall.ENOTDIR || err == unix.NoFollowErrno { // Not a directory; return the error from the unix.Unlinkat. return &PathError{Op: "unlinkat", Path: base, Err: uErr} }