|  | // Copyright 2018 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. | 
|  |  | 
|  | // +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris | 
|  |  | 
|  | package os | 
|  |  | 
|  | import ( | 
|  | "io" | 
|  | "runtime" | 
|  | "syscall" | 
|  | ) | 
|  |  | 
|  | func removeAll(path string) error { | 
|  | if path == "" { | 
|  | // fail silently to retain compatibility with previous behavior | 
|  | // of RemoveAll. See issue 28830. | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // The rmdir system call permits removing "." on Plan 9, | 
|  | // so we don't permit it to remain consistent with the | 
|  | // "at" implementation of RemoveAll. | 
|  | if endsWithDot(path) { | 
|  | return &PathError{"RemoveAll", path, syscall.EINVAL} | 
|  | } | 
|  |  | 
|  | // Simple case: if Remove works, we're done. | 
|  | err := Remove(path) | 
|  | if err == nil || IsNotExist(err) { | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // Otherwise, is this a directory we need to recurse into? | 
|  | dir, serr := Lstat(path) | 
|  | if serr != nil { | 
|  | if serr, ok := serr.(*PathError); ok && (IsNotExist(serr.Err) || serr.Err == syscall.ENOTDIR) { | 
|  | return nil | 
|  | } | 
|  | return serr | 
|  | } | 
|  | if !dir.IsDir() { | 
|  | // Not a directory; return the error from Remove. | 
|  | return err | 
|  | } | 
|  |  | 
|  | // Remove contents & return first error. | 
|  | err = nil | 
|  | for { | 
|  | fd, err := Open(path) | 
|  | if err != nil { | 
|  | if IsNotExist(err) { | 
|  | // Already deleted by someone else. | 
|  | return nil | 
|  | } | 
|  | return err | 
|  | } | 
|  |  | 
|  | const reqSize = 1024 | 
|  | var names []string | 
|  | var readErr error | 
|  |  | 
|  | for { | 
|  | numErr := 0 | 
|  | names, readErr = fd.Readdirnames(reqSize) | 
|  |  | 
|  | for _, name := range names { | 
|  | err1 := RemoveAll(path + string(PathSeparator) + name) | 
|  | if err == nil { | 
|  | err = err1 | 
|  | } | 
|  | if err1 != nil { | 
|  | numErr++ | 
|  | } | 
|  | } | 
|  |  | 
|  | // If we can delete any entry, break to start new iteration. | 
|  | // Otherwise, we discard current names, get next entries and try deleting them. | 
|  | if numErr != reqSize { | 
|  | break | 
|  | } | 
|  | } | 
|  |  | 
|  | // Removing files from the directory may have caused | 
|  | // the OS to reshuffle it. Simply calling Readdirnames | 
|  | // again may skip some entries. The only reliable way | 
|  | // to avoid this is to close and re-open the | 
|  | // directory. See issue 20841. | 
|  | fd.Close() | 
|  |  | 
|  | if readErr == io.EOF { | 
|  | break | 
|  | } | 
|  | // If Readdirnames returned an error, use it. | 
|  | if err == nil { | 
|  | err = readErr | 
|  | } | 
|  | if len(names) == 0 { | 
|  | 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) < reqSize { | 
|  | err1 := Remove(path) | 
|  | if err1 == nil || IsNotExist(err1) { | 
|  | return nil | 
|  | } | 
|  |  | 
|  | if err != nil { | 
|  | // 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. | 
|  | err1 := Remove(path) | 
|  | if err1 == nil || IsNotExist(err1) { | 
|  | return nil | 
|  | } | 
|  | if runtime.GOOS == "windows" && IsPermission(err1) { | 
|  | if fs, err := Stat(path); err == nil { | 
|  | if err = Chmod(path, FileMode(0200|int(fs.Mode()))); err == nil { | 
|  | err1 = Remove(path) | 
|  | } | 
|  | } | 
|  | } | 
|  | if err == nil { | 
|  | err = err1 | 
|  | } | 
|  | return err | 
|  | } |