path.go 2.9 KB

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