Source file src/os/path.go

     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  	"internal/filepathlite"
     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{Op: "mkdir", Path: path, Err: syscall.ENOTDIR}
    27  	}
    28  
    29  	// Slow path: make sure parent exists and then call Mkdir for path.
    30  
    31  	// Extract the parent folder from path by first removing any trailing
    32  	// path separator and then scanning backward until finding a path
    33  	// separator or reaching the beginning of the string.
    34  	i := len(path) - 1
    35  	for i >= 0 && IsPathSeparator(path[i]) {
    36  		i--
    37  	}
    38  	for i >= 0 && !IsPathSeparator(path[i]) {
    39  		i--
    40  	}
    41  	if i < 0 {
    42  		i = 0
    43  	}
    44  
    45  	// If there is a parent directory, and it is not the volume name,
    46  	// recurse to ensure parent directory exists.
    47  	if parent := path[:i]; len(parent) > len(filepathlite.VolumeName(path)) {
    48  		err = MkdirAll(parent, perm)
    49  		if err != nil {
    50  			return err
    51  		}
    52  	}
    53  
    54  	// Parent now exists; invoke Mkdir and use its result.
    55  	err = Mkdir(path, perm)
    56  	if err != nil {
    57  		// Handle arguments like "foo/." by
    58  		// double-checking that directory doesn't exist.
    59  		dir, err1 := Lstat(path)
    60  		if err1 == nil && dir.IsDir() {
    61  			return nil
    62  		}
    63  		return err
    64  	}
    65  	return nil
    66  }
    67  
    68  // RemoveAll removes path and any children it contains.
    69  // It removes everything it can but returns the first error
    70  // it encounters. If the path does not exist, RemoveAll
    71  // returns nil (no error).
    72  // If there is an error, it will be of type [*PathError].
    73  func RemoveAll(path string) error {
    74  	return removeAll(path)
    75  }
    76  
    77  // endsWithDot reports whether the final component of path is ".".
    78  func endsWithDot(path string) bool {
    79  	if path == "." {
    80  		return true
    81  	}
    82  	if len(path) >= 2 && path[len(path)-1] == '.' && IsPathSeparator(path[len(path)-2]) {
    83  		return true
    84  	}
    85  	return false
    86  }
    87  

View as plain text