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 5package os 6 7import ( 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. 19func 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]. 73func RemoveAll(path string) error { 74 return removeAll(path) 75} 76 77// endsWithDot reports whether the final component of path is ".". 78func 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