// 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,!hurd,!linux,!netbsd,!openbsd,!solaris package os import ( "io" "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 { 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 request = 1024 names, err1 := fd.Readdirnames(request) // 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() for _, name := range names { err1 := RemoveAll(path + string(PathSeparator) + name) if err == nil { err = err1 } } if err1 == io.EOF { break } // If Readdirnames returned an error, use it. if err == nil { err = err1 } 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) < request { 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 err == nil { err = err1 } return err }