...

Source file src/pkg/os/removeall_noat.go

     1	// Copyright 2018 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris
     6	
     7	package os
     8	
     9	import (
    10		"io"
    11		"syscall"
    12	)
    13	
    14	func removeAll(path string) error {
    15		if path == "" {
    16			// fail silently to retain compatibility with previous behavior
    17			// of RemoveAll. See issue 28830.
    18			return nil
    19		}
    20	
    21		// The rmdir system call permits removing "." on Plan 9,
    22		// so we don't permit it to remain consistent with the
    23		// "at" implementation of RemoveAll.
    24		if endsWithDot(path) {
    25			return &PathError{"RemoveAll", path, syscall.EINVAL}
    26		}
    27	
    28		// Simple case: if Remove works, we're done.
    29		err := Remove(path)
    30		if err == nil || IsNotExist(err) {
    31			return nil
    32		}
    33	
    34		// Otherwise, is this a directory we need to recurse into?
    35		dir, serr := Lstat(path)
    36		if serr != nil {
    37			if serr, ok := serr.(*PathError); ok && (IsNotExist(serr.Err) || serr.Err == syscall.ENOTDIR) {
    38				return nil
    39			}
    40			return serr
    41		}
    42		if !dir.IsDir() {
    43			// Not a directory; return the error from Remove.
    44			return err
    45		}
    46	
    47		// Remove contents & return first error.
    48		err = nil
    49		for {
    50			fd, err := Open(path)
    51			if err != nil {
    52				if IsNotExist(err) {
    53					// Already deleted by someone else.
    54					return nil
    55				}
    56				return err
    57			}
    58	
    59			const reqSize = 1024
    60			var names []string
    61			var readErr error
    62	
    63			for {
    64				numErr := 0
    65				names, readErr = fd.Readdirnames(reqSize)
    66	
    67				for _, name := range names {
    68					err1 := RemoveAll(path + string(PathSeparator) + name)
    69					if err == nil {
    70						err = err1
    71					}
    72					if err1 != nil {
    73						numErr++
    74					}
    75				}
    76	
    77				// If we can delete any entry, break to start new iteration.
    78				// Otherwise, we discard current names, get next entries and try deleting them.
    79				if numErr != reqSize {
    80					break
    81				}
    82			}
    83	
    84			// Removing files from the directory may have caused
    85			// the OS to reshuffle it. Simply calling Readdirnames
    86			// again may skip some entries. The only reliable way
    87			// to avoid this is to close and re-open the
    88			// directory. See issue 20841.
    89			fd.Close()
    90	
    91			if readErr == io.EOF {
    92				break
    93			}
    94			// If Readdirnames returned an error, use it.
    95			if err == nil {
    96				err = readErr
    97			}
    98			if len(names) == 0 {
    99				break
   100			}
   101	
   102			// We don't want to re-open unnecessarily, so if we
   103			// got fewer than request names from Readdirnames, try
   104			// simply removing the directory now. If that
   105			// succeeds, we are done.
   106			if len(names) < reqSize {
   107				err1 := Remove(path)
   108				if err1 == nil || IsNotExist(err1) {
   109					return nil
   110				}
   111	
   112				if err != nil {
   113					// We got some error removing the
   114					// directory contents, and since we
   115					// read fewer names than we requested
   116					// there probably aren't more files to
   117					// remove. Don't loop around to read
   118					// the directory again. We'll probably
   119					// just get the same error.
   120					return err
   121				}
   122			}
   123		}
   124	
   125		// Remove directory.
   126		err1 := Remove(path)
   127		err1 = removeAllTestHook(err1)
   128		if err1 == nil || IsNotExist(err1) {
   129			return nil
   130		}
   131		if err == nil {
   132			err = err1
   133		}
   134		return err
   135	}
   136	

View as plain text