github.com/kdevb0x/go@v0.0.0-20180115030120-39687051e9e7/src/os/path.go (about) 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 "runtime" 10 "syscall" 11 ) 12 13 // MkdirAll creates a directory named path, 14 // along with any necessary parents, and returns nil, 15 // or else returns an error. 16 // The permission bits perm (before umask) are used for all 17 // directories that MkdirAll creates. 18 // If path is already a directory, MkdirAll does nothing 19 // and returns nil. 20 func MkdirAll(path string, perm FileMode) error { 21 // Fast path: if we can tell whether path is a directory or file, stop with success or error. 22 dir, err := Stat(path) 23 if err == nil { 24 if dir.IsDir() { 25 return nil 26 } 27 return &PathError{"mkdir", path, syscall.ENOTDIR} 28 } 29 30 // Slow path: make sure parent exists and then call Mkdir for path. 31 i := len(path) 32 for i > 0 && IsPathSeparator(path[i-1]) { // Skip trailing path separator. 33 i-- 34 } 35 36 j := i 37 for j > 0 && !IsPathSeparator(path[j-1]) { // Scan backward over element. 38 j-- 39 } 40 41 if j > 1 { 42 // Create parent 43 err = MkdirAll(path[0:j-1], perm) 44 if err != nil { 45 return err 46 } 47 } 48 49 // Parent now exists; invoke Mkdir and use its result. 50 err = Mkdir(path, perm) 51 if err != nil { 52 // Handle arguments like "foo/." by 53 // double-checking that directory doesn't exist. 54 dir, err1 := Lstat(path) 55 if err1 == nil && dir.IsDir() { 56 return nil 57 } 58 return err 59 } 60 return nil 61 } 62 63 // RemoveAll removes path and any children it contains. 64 // It removes everything it can but returns the first error 65 // it encounters. If the path does not exist, RemoveAll 66 // returns nil (no error). 67 func RemoveAll(path string) error { 68 // Simple case: if Remove works, we're done. 69 err := Remove(path) 70 if err == nil || IsNotExist(err) { 71 return nil 72 } 73 74 // Otherwise, is this a directory we need to recurse into? 75 dir, serr := Lstat(path) 76 if serr != nil { 77 if serr, ok := serr.(*PathError); ok && (IsNotExist(serr.Err) || serr.Err == syscall.ENOTDIR) { 78 return nil 79 } 80 return serr 81 } 82 if !dir.IsDir() { 83 // Not a directory; return the error from Remove. 84 return err 85 } 86 87 // Directory. 88 fd, err := Open(path) 89 if err != nil { 90 if IsNotExist(err) { 91 // Race. It was deleted between the Lstat and Open. 92 // Return nil per RemoveAll's docs. 93 return nil 94 } 95 return err 96 } 97 98 // Remove contents & return first error. 99 err = nil 100 for { 101 if err == nil && (runtime.GOOS == "plan9" || runtime.GOOS == "nacl") { 102 // Reset read offset after removing directory entries. 103 // See golang.org/issue/22572. 104 fd.Seek(0, 0) 105 } 106 names, err1 := fd.Readdirnames(100) 107 for _, name := range names { 108 err1 := RemoveAll(path + string(PathSeparator) + name) 109 if err == nil { 110 err = err1 111 } 112 } 113 if err1 == io.EOF { 114 break 115 } 116 // If Readdirnames returned an error, use it. 117 if err == nil { 118 err = err1 119 } 120 if len(names) == 0 { 121 break 122 } 123 } 124 125 // Close directory, because windows won't remove opened directory. 126 fd.Close() 127 128 // Remove directory. 129 err1 := Remove(path) 130 if err1 == nil || IsNotExist(err1) { 131 return nil 132 } 133 if err == nil { 134 err = err1 135 } 136 return err 137 }