...
Run Format

Source file src/os/path.go

Documentation: os

     1  // Copyright 2009 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  package os
     6  
     7  import (
     8  	"io"
     9  	"syscall"
    10  )
    11  
    12  // MkdirAll creates a directory named path,
    13  // along with any necessary parents, and returns nil,
    14  // or else returns an error.
    15  // The permission bits perm (before umask) are used for all
    16  // directories that MkdirAll creates.
    17  // If path is already a directory, MkdirAll does nothing
    18  // and returns nil.
    19  func MkdirAll(path string, perm FileMode) error {
    20  	// Fast path: if we can tell whether path is a directory or file, stop with success or error.
    21  	dir, err := Stat(path)
    22  	if err == nil {
    23  		if dir.IsDir() {
    24  			return nil
    25  		}
    26  		return &PathError{"mkdir", path, syscall.ENOTDIR}
    27  	}
    28  
    29  	// Slow path: make sure parent exists and then call Mkdir for path.
    30  	i := len(path)
    31  	for i > 0 && IsPathSeparator(path[i-1]) { // Skip trailing path separator.
    32  		i--
    33  	}
    34  
    35  	j := i
    36  	for j > 0 && !IsPathSeparator(path[j-1]) { // Scan backward over element.
    37  		j--
    38  	}
    39  
    40  	if j > 1 {
    41  		// Create parent.
    42  		err = MkdirAll(fixRootDirectory(path[:j-1]), perm)
    43  		if err != nil {
    44  			return err
    45  		}
    46  	}
    47  
    48  	// Parent now exists; invoke Mkdir and use its result.
    49  	err = Mkdir(path, perm)
    50  	if err != nil {
    51  		// Handle arguments like "foo/." by
    52  		// double-checking that directory doesn't exist.
    53  		dir, err1 := Lstat(path)
    54  		if err1 == nil && dir.IsDir() {
    55  			return nil
    56  		}
    57  		return err
    58  	}
    59  	return nil
    60  }
    61  
    62  // RemoveAll removes path and any children it contains.
    63  // It removes everything it can but returns the first error
    64  // it encounters. If the path does not exist, RemoveAll
    65  // returns nil (no error).
    66  func RemoveAll(path string) error {
    67  	// Simple case: if Remove works, we're done.
    68  	err := Remove(path)
    69  	if err == nil || IsNotExist(err) {
    70  		return nil
    71  	}
    72  
    73  	// Otherwise, is this a directory we need to recurse into?
    74  	dir, serr := Lstat(path)
    75  	if serr != nil {
    76  		if serr, ok := serr.(*PathError); ok && (IsNotExist(serr.Err) || serr.Err == syscall.ENOTDIR) {
    77  			return nil
    78  		}
    79  		return serr
    80  	}
    81  	if !dir.IsDir() {
    82  		// Not a directory; return the error from Remove.
    83  		return err
    84  	}
    85  
    86  	// Remove contents & return first error.
    87  	err = nil
    88  	for {
    89  		fd, err := Open(path)
    90  		if err != nil {
    91  			if IsNotExist(err) {
    92  				// Already deleted by someone else.
    93  				return nil
    94  			}
    95  			return err
    96  		}
    97  
    98  		const request = 1024
    99  		names, err1 := fd.Readdirnames(request)
   100  
   101  		// Removing files from the directory may have caused
   102  		// the OS to reshuffle it. Simply calling Readdirnames
   103  		// again may skip some entries. The only reliable way
   104  		// to avoid this is to close and re-open the
   105  		// directory. See issue 20841.
   106  		fd.Close()
   107  
   108  		for _, name := range names {
   109  			err1 := RemoveAll(path + string(PathSeparator) + name)
   110  			if err == nil {
   111  				err = err1
   112  			}
   113  		}
   114  
   115  		if err1 == io.EOF {
   116  			break
   117  		}
   118  		// If Readdirnames returned an error, use it.
   119  		if err == nil {
   120  			err = err1
   121  		}
   122  		if len(names) == 0 {
   123  			break
   124  		}
   125  
   126  		// We don't want to re-open unnecessarily, so if we
   127  		// got fewer than request names from Readdirnames, try
   128  		// simply removing the directory now. If that
   129  		// succeeds, we are done.
   130  		if len(names) < request {
   131  			err1 := Remove(path)
   132  			if err1 == nil || IsNotExist(err1) {
   133  				return nil
   134  			}
   135  
   136  			if err != nil {
   137  				// We got some error removing the
   138  				// directory contents, and since we
   139  				// read fewer names than we requested
   140  				// there probably aren't more files to
   141  				// remove. Don't loop around to read
   142  				// the directory again. We'll probably
   143  				// just get the same error.
   144  				return err
   145  			}
   146  		}
   147  	}
   148  
   149  	// Remove directory.
   150  	err1 := Remove(path)
   151  	if err1 == nil || IsNotExist(err1) {
   152  		return nil
   153  	}
   154  	if err == nil {
   155  		err = err1
   156  	}
   157  	return err
   158  }
   159  

View as plain text