diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2019-02-26 01:00:39 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2019-02-26 01:00:39 +0000 |
commit | 99e20ba51d5b0785c7e98244d2901853d9fb3b41 (patch) | |
tree | d86fa5d601b8bc3629b3820df4d5e7042853453f /libgo/go/os | |
parent | e5e9b91bc61da0bdb58c6577c319e61a3ed04b17 (diff) | |
download | gcc-99e20ba51d5b0785c7e98244d2901853d9fb3b41.zip gcc-99e20ba51d5b0785c7e98244d2901853d9fb3b41.tar.gz gcc-99e20ba51d5b0785c7e98244d2901853d9fb3b41.tar.bz2 |
libgo: update to Go1.12rc1
Reviewed-on: https://go-review.googlesource.com/c/162881
From-SVN: r269202
Diffstat (limited to 'libgo/go/os')
-rw-r--r-- | libgo/go/os/file_unix.go | 1 | ||||
-rw-r--r-- | libgo/go/os/path.go | 8 | ||||
-rw-r--r-- | libgo/go/os/removeall_at.go | 50 | ||||
-rw-r--r-- | libgo/go/os/removeall_noat.go | 6 | ||||
-rw-r--r-- | libgo/go/os/removeall_test.go | 80 |
5 files changed, 128 insertions, 17 deletions
diff --git a/libgo/go/os/file_unix.go b/libgo/go/os/file_unix.go index 5f7ab30..912ba5a 100644 --- a/libgo/go/os/file_unix.go +++ b/libgo/go/os/file_unix.go @@ -192,6 +192,7 @@ func epipecheck(file *File, e error) { const DevNull = "/dev/null" // openFileNolog is the Unix implementation of OpenFile. +// Changes here should be reflected in openFdAt, if relevant. func openFileNolog(name string, flag int, perm FileMode) (*File, error) { setSticky := false if !supportsCreateWithStickyBit && flag&O_CREATE != 0 && perm&ModeSticky != 0 { diff --git a/libgo/go/os/path.go b/libgo/go/os/path.go index 30cc6c8..104b7ce 100644 --- a/libgo/go/os/path.go +++ b/libgo/go/os/path.go @@ -58,6 +58,14 @@ func MkdirAll(path string, perm FileMode) error { return nil } +// RemoveAll removes path and any children it contains. +// It removes everything it can but returns the first error +// it encounters. If the path does not exist, RemoveAll +// returns nil (no error). +func RemoveAll(path string) error { + return removeAll(path) +} + // endsWithDot reports whether the final component of path is ".". func endsWithDot(path string) bool { if path == "." { diff --git a/libgo/go/os/removeall_at.go b/libgo/go/os/removeall_at.go index 5128de7..d1210ee 100644 --- a/libgo/go/os/removeall_at.go +++ b/libgo/go/os/removeall_at.go @@ -9,10 +9,11 @@ package os import ( "internal/syscall/unix" "io" + "runtime" "syscall" ) -func RemoveAll(path string) error { +func removeAll(path string) error { if path == "" { // fail silently to retain compatibility with previous behavior // of RemoveAll. See issue 28830. @@ -56,8 +57,13 @@ func removeAllFrom(parent *File, path string) error { return nil } - // If not a "is directory" error, we have a problem - if err != syscall.EISDIR && err != syscall.EPERM { + // EISDIR means that we have a directory, and we need to + // remove its contents. + // EPERM or EACCES means that we don't have write permission on + // the parent directory, but this entry might still be a directory + // whose contents need to be removed. + // Otherwise just return the error. + if err != syscall.EISDIR && err != syscall.EPERM && err != syscall.EACCES { return err } @@ -68,11 +74,11 @@ func removeAllFrom(parent *File, path string) error { return statErr } if statInfo.Mode&syscall.S_IFMT != syscall.S_IFDIR { - // Not a directory; return the error from the Remove + // Not a directory; return the error from the Remove. return err } - // Remove the directory's entries + // Remove the directory's entries. var recurseErr error for { const request = 1024 @@ -87,7 +93,7 @@ func removeAllFrom(parent *File, path string) error { } names, readErr := file.Readdirnames(request) - // Errors other than EOF should stop us from continuing + // Errors other than EOF should stop us from continuing. if readErr != nil && readErr != io.EOF { file.Close() if IsNotExist(readErr) { @@ -116,7 +122,7 @@ func removeAllFrom(parent *File, path string) error { } } - // Remove the directory itself + // Remove the directory itself. unlinkError := unix.Unlinkat(parentFd, path, unix.AT_REMOVEDIR) if unlinkError == nil || IsNotExist(unlinkError) { return nil @@ -128,11 +134,31 @@ func removeAllFrom(parent *File, path string) error { return unlinkError } -func openFdAt(fd int, path string) (*File, error) { - fd, err := unix.Openat(fd, path, O_RDONLY, 0) - if err != nil { - return nil, err +// openFdAt opens path relative to the directory in fd. +// Other than that this should act like openFileNolog. +// This acts like openFileNolog rather than OpenFile because +// we are going to (try to) remove the file. +// The contents of this file are not relevant for test caching. +func openFdAt(dirfd int, name string) (*File, error) { + var r int + for { + var e error + r, e = unix.Openat(dirfd, name, O_RDONLY, 0) + if e == nil { + break + } + + // See comment in openFileNolog. + if runtime.GOOS == "darwin" && e == syscall.EINTR { + continue + } + + return nil, &PathError{"openat", name, e} + } + + if !supportsCloseOnExec { + syscall.CloseOnExec(r) } - return NewFile(uintptr(fd), path), nil + return newFile(uintptr(r), name, kindOpenFile), nil } diff --git a/libgo/go/os/removeall_noat.go b/libgo/go/os/removeall_noat.go index 47fff42..7d9f73e 100644 --- a/libgo/go/os/removeall_noat.go +++ b/libgo/go/os/removeall_noat.go @@ -11,11 +11,7 @@ import ( "syscall" ) -// RemoveAll removes path and any children it contains. -// It removes everything it can but returns the first error -// it encounters. If the path does not exist, RemoveAll -// returns nil (no error). -func RemoveAll(path string) error { +func removeAll(path string) error { if path == "" { // fail silently to retain compatibility with previous behavior // of RemoveAll. See issue 28830. diff --git a/libgo/go/os/removeall_test.go b/libgo/go/os/removeall_test.go index 0f7dce0..9dab0d4 100644 --- a/libgo/go/os/removeall_test.go +++ b/libgo/go/os/removeall_test.go @@ -292,3 +292,83 @@ func TestRemoveReadOnlyDir(t *testing.T) { t.Error("subdirectory was not removed") } } + +// Issue #29983. +func TestRemoveAllButReadOnly(t *testing.T) { + switch runtime.GOOS { + case "nacl", "js", "windows": + t.Skipf("skipping test on %s", runtime.GOOS) + } + + if Getuid() == 0 { + t.Skip("skipping test when running as root") + } + + t.Parallel() + + tempDir, err := ioutil.TempDir("", "TestRemoveAllButReadOnly-") + if err != nil { + t.Fatal(err) + } + defer RemoveAll(tempDir) + + dirs := []string{ + "a", + "a/x", + "a/x/1", + "b", + "b/y", + "b/y/2", + "c", + "c/z", + "c/z/3", + } + readonly := []string{ + "b", + } + inReadonly := func(d string) bool { + for _, ro := range readonly { + if d == ro { + return true + } + dd, _ := filepath.Split(d) + if filepath.Clean(dd) == ro { + return true + } + } + return false + } + + for _, dir := range dirs { + if err := Mkdir(filepath.Join(tempDir, dir), 0777); err != nil { + t.Fatal(err) + } + } + for _, dir := range readonly { + d := filepath.Join(tempDir, dir) + if err := Chmod(d, 0555); err != nil { + t.Fatal(err) + } + + // Defer changing the mode back so that the deferred + // RemoveAll(tempDir) can succeed. + defer Chmod(d, 0777) + } + + if err := RemoveAll(tempDir); err == nil { + t.Fatal("RemoveAll succeeded unexpectedly") + } + + for _, dir := range dirs { + _, err := Stat(filepath.Join(tempDir, dir)) + if inReadonly(dir) { + if err != nil { + t.Errorf("file %q was deleted but should still exist", dir) + } + } else { + if err == nil { + t.Errorf("file %q still exists but should have been deleted", dir) + } + } + } +} |