os: in RemoveAll, try Remove first
Otherwise we can fail to remove a unreadable empty directory.
Fixes #29178
Change-Id: I43d5c89fce57a86626abe2a1c2bbf145716e087b
Reviewed-on: https://go-review.googlesource.com/c/153720
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/src/os/removeall_at.go b/src/os/removeall_at.go
index c42319a..f0fed6d 100644
--- a/src/os/removeall_at.go
+++ b/src/os/removeall_at.go
@@ -25,6 +25,12 @@
return &PathError{"RemoveAll", path, syscall.EINVAL}
}
+ // Simple case: if Remove works, we're done.
+ err := Remove(path)
+ if err == nil || IsNotExist(err) {
+ return nil
+ }
+
// RemoveAll recurses by deleting the path base from
// its parent directory
parentDir, base := splitPath(path)
diff --git a/src/os/removeall_test.go b/src/os/removeall_test.go
index 1c9f163..0f7dce0 100644
--- a/src/os/removeall_test.go
+++ b/src/os/removeall_test.go
@@ -264,3 +264,31 @@
}
}
}
+
+// Issue #29178.
+func TestRemoveReadOnlyDir(t *testing.T) {
+ t.Parallel()
+
+ tempDir, err := ioutil.TempDir("", "TestRemoveReadOnlyDir-")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer RemoveAll(tempDir)
+
+ subdir := filepath.Join(tempDir, "x")
+ if err := Mkdir(subdir, 0); err != nil {
+ t.Fatal(err)
+ }
+
+ // If an error occurs make it more likely that removing the
+ // temporary directory will succeed.
+ defer Chmod(subdir, 0777)
+
+ if err := RemoveAll(subdir); err != nil {
+ t.Fatal(err)
+ }
+
+ if _, err := Stat(subdir); err == nil {
+ t.Error("subdirectory was not removed")
+ }
+}