// 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.//go:build unix || wasip1 || windowspackage osimport ()func removeAll( string) error {if == "" {// fail silently to retain compatibility with previous behavior // of RemoveAll. See issue 28830.returnnil }// The rmdir system call does not permit removing ".", // so we don't permit it either.ifendsWithDot() {return &PathError{Op: "RemoveAll", Path: , Err: syscall.EINVAL} }// Simple case: if Remove works, we're done. := Remove()if == nil || IsNotExist() {returnnil }// RemoveAll recurses by deleting the path base from // its parent directory , := splitPath() , := Open()ifIsNotExist() {// If parent does not exist, base cannot exist. Fail silentlyreturnnil }if != nil {return }defer .Close()if := removeAllFrom(sysfdType(.Fd()), ); != nil {if , := .(*PathError); { .Path = + string(PathSeparator) + .Path = }return }returnnil}func removeAllFrom( sysfdType, string) error {// Simple case: if Unlink (aka remove) works, we're done. := removefileat(, )if == nil || IsNotExist() {returnnil }// 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 != syscall.EISDIR && != syscall.EPERM && != syscall.EACCES {return &PathError{Op: "unlinkat", Path: , Err: } } := // Remove the directory's entries.varerrorfor {const = 1024varint// Open the directory to recurse into. , := openDirAt(, )if != nil {ifIsNotExist() {returnnil }if == syscall.ENOTDIR || isErrNoFollow() {// Not a directory; return the error from the unix.Unlinkat.return &PathError{Op: "unlinkat", Path: , Err: } } = &PathError{Op: "openfdat", Path: , Err: }break }for { := 0 , := .Readdirnames()// Errors other than EOF should stop us from continuing.if != nil && != io.EOF { .Close()ifIsNotExist() {returnnil }return &PathError{Op: "readdirnames", Path: , Err: } } = len()for , := range { := (sysfdType(.Fd()), )if != nil {if , := .(*PathError); { .Path = + string(PathSeparator) + .Path } ++if == nil { = } } }// If we can delete any entry, break to start new iteration. // Otherwise, we discard current names, get next entries and try deleting them.if != {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. .Close()// Finish when the end of the directory is reachedif < {break } }// Remove the directory itself. := removedirat(, )if == nil || IsNotExist() {returnnil }if != nil {return }return &PathError{Op: "unlinkat", Path: , Err: }}// openDirAt opens a directory name relative to the directory referred to by// the file descriptor dirfd. If name is anything but a directory (this// includes a symlink to one), it should return an error. 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 openDirAt( sysfdType, string) (*File, error) { , := rootOpenDir(, )if != nil {returnnil, }returnnewDirFile(, )}
The pages are generated with Goldsv0.7.7-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.