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	"syscall"
9)
10
11// MkdirAll creates a directory named path,
12// along with any necessary parents, and returns nil,
13// or else returns an error.
14// The permission bits perm (before umask) are used for all
15// directories that MkdirAll creates.
16// If path is already a directory, MkdirAll does nothing
17// and returns nil.
18func MkdirAll(path string, perm FileMode) error {
19	// Fast path: if we can tell whether path is a directory or file, stop with success or error.
20	dir, err := Stat(path)
21	if err == nil {
22		if dir.IsDir() {
23			return nil
24		}
25		return &PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR}
26	}
27
28	// Slow path: make sure parent exists and then call Mkdir for path.
29	i := len(path)
30	for i > 0 && IsPathSeparator(path[i-1]) { // Skip trailing path separator.
31		i--
32	}
33
34	j := i
35	for j > 0 && !IsPathSeparator(path[j-1]) { // Scan backward over element.
36		j--
37	}
38
39	if j > 1 {
40		// Create parent.
41		err = MkdirAll(fixRootDirectory(path[:j-1]), perm)
42		if err != nil {
43			return err
44		}
45	}
46
47	// Parent now exists; invoke Mkdir and use its result.
48	err = Mkdir(path, perm)
49	if err != nil {
50		// Handle arguments like "foo/." by
51		// double-checking that directory doesn't exist.
52		dir, err1 := Lstat(path)
53		if err1 == nil && dir.IsDir() {
54			return nil
55		}
56		return err
57	}
58	return nil
59}
60
61// RemoveAll removes path and any children it contains.
62// It removes everything it can but returns the first error
63// it encounters. If the path does not exist, RemoveAll
64// returns nil (no error).
65// If there is an error, it will be of type *PathError.
66func RemoveAll(path string) error {
67	return removeAll(path)
68}
69
70// endsWithDot reports whether the final component of path is ".".
71func endsWithDot(path string) bool {
72	if path == "." {
73		return true
74	}
75	if len(path) >= 2 && path[len(path)-1] == '.' && IsPathSeparator(path[len(path)-2]) {
76		return true
77	}
78	return false
79}
80