Commit a6a69227 authored by Ian Lance Taylor's avatar Ian Lance Taylor

os: when looping in RemoveAll, close and re-open directory

On some systems removing files can cause a directory to be re-shuffled,
so simply continuing to read files can cause us to miss some.
Close and re-open the directory when looping, to avoid that.

Read more files each time through the loop, to reduce the chance of
having to re-open.

Fixes #20841

Change-Id: I98a14774ca63786ad05ba5000cbdb01ad2884332
Reviewed-on: https://go-review.googlesource.com/121255
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 83092a40
...@@ -6,7 +6,6 @@ package os ...@@ -6,7 +6,6 @@ package os
import ( import (
"io" "io"
"runtime"
"syscall" "syscall"
) )
...@@ -84,32 +83,35 @@ func RemoveAll(path string) error { ...@@ -84,32 +83,35 @@ func RemoveAll(path string) error {
return err return err
} }
// Directory. // Remove contents & return first error.
err = nil
for {
fd, err := Open(path) fd, err := Open(path)
if err != nil { if err != nil {
if IsNotExist(err) { if IsNotExist(err) {
// Race. It was deleted between the Lstat and Open. // Already deleted by someone else.
// Return nil per RemoveAll's docs.
return nil return nil
} }
return err return err
} }
// Remove contents & return first error. const request = 1024
err = nil names, err1 := fd.Readdirnames(request)
for {
if err == nil && (runtime.GOOS == "plan9" || runtime.GOOS == "nacl") { // Removing files from the directory may have caused
// Reset read offset after removing directory entries. // the OS to reshuffle it. Simply calling Readdirnames
// See golang.org/issue/22572. // again may skip some entries. The only reliable way
fd.Seek(0, 0) // to avoid this is to close and re-open the
} // directory. See issue 20841.
names, err1 := fd.Readdirnames(100) fd.Close()
for _, name := range names { for _, name := range names {
err1 := RemoveAll(path + string(PathSeparator) + name) err1 := RemoveAll(path + string(PathSeparator) + name)
if err == nil { if err == nil {
err = err1 err = err1
} }
} }
if err1 == io.EOF { if err1 == io.EOF {
break break
} }
...@@ -120,10 +122,29 @@ func RemoveAll(path string) error { ...@@ -120,10 +122,29 @@ func RemoveAll(path string) error {
if len(names) == 0 { if len(names) == 0 {
break break
} }
// We don't want to re-open unnecessarily, so if we
// got fewer than request names from Readdirnames, try
// simply removing the directory now. If that
// succeeds, we are done.
if len(names) < request {
err1 := Remove(path)
if err1 == nil || IsNotExist(err1) {
return nil
} }
// Close directory, because windows won't remove opened directory. if err != nil {
fd.Close() // We got some error removing the
// directory contents, and since we
// read fewer names than we requested
// there probably aren't more files to
// remove. Don't loop around to read
// the directory again. We'll probably
// just get the same error.
return err
}
}
}
// Remove directory. // Remove directory.
err1 := Remove(path) err1 := Remove(path)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment