// 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 unixpackage osimport ()func ( 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(, ); != nil {if , := .(*PathError); { .Path = + string(PathSeparator) + .Path = }return }returnnil}func ( *File, string) error { := int(.Fd())// Simple case: if Unlink (aka remove) works, we're done. := ignoringEINTR(func() error {returnunix.Unlinkat(, , 0) })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: } }// Is this a directory we need to recurse into?varsyscall.Stat_t := ignoringEINTR(func() error {returnunix.Fstatat(, , &, unix.AT_SYMLINK_NOFOLLOW) })if != nil {ifIsNotExist() {returnnil }return &PathError{Op: "fstatat", Path: , Err: } }if .Mode&syscall.S_IFMT != syscall.S_IFDIR {// Not a directory; return the error from the unix.Unlinkat.return &PathError{Op: "unlinkat", Path: , Err: } }// Remove the directory's entries.varerrorfor {const = 1024varint// Open the directory to recurse into , := openFdAt(, )if != nil {ifIsNotExist() {returnnil } = &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 { := (, )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. := ignoringEINTR(func() error {returnunix.Unlinkat(, , unix.AT_REMOVEDIR) })if == nil || IsNotExist() {returnnil }if != nil {return }return &PathError{Op: "unlinkat", Path: , Err: }}// openFdAt opens path relative to the directory in fd.// 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 ( int, string) (*File, error) {varintfor {varerror , = unix.Openat(, , O_RDONLY|syscall.O_CLOEXEC, 0)if == nil {break }// See comment in openFileNolog.if == syscall.EINTR {continue }returnnil, }if !supportsCloseOnExec {syscall.CloseOnExec() }// We use kindNoPoll because we know that this is a directory.returnnewFile(, , kindNoPoll), nil}
The pages are generated with Goldsv0.6.7. (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 @Go100and1 (reachable from the left QR code) to get the latest news of Golds.