You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

path.go 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package util
  5. import (
  6. "errors"
  7. "net/url"
  8. "os"
  9. "path"
  10. "path/filepath"
  11. "regexp"
  12. "runtime"
  13. "strings"
  14. )
  15. // EnsureAbsolutePath ensure that a path is absolute, making it
  16. // relative to absoluteBase if necessary
  17. func EnsureAbsolutePath(path string, absoluteBase string) string {
  18. if filepath.IsAbs(path) {
  19. return path
  20. }
  21. return filepath.Join(absoluteBase, path)
  22. }
  23. const notRegularFileMode os.FileMode = os.ModeDir | os.ModeSymlink | os.ModeNamedPipe | os.ModeSocket | os.ModeDevice | os.ModeCharDevice | os.ModeIrregular
  24. // GetDirectorySize returns the dumb disk consumption for a given path
  25. func GetDirectorySize(path string) (int64, error) {
  26. var size int64
  27. err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
  28. if info != nil && (info.Mode()&notRegularFileMode) == 0 {
  29. size += info.Size()
  30. }
  31. return err
  32. })
  33. return size, err
  34. }
  35. // IsDir returns true if given path is a directory,
  36. // or returns false when it's a file or does not exist.
  37. func IsDir(dir string) (bool, error) {
  38. f, err := os.Stat(dir)
  39. if err == nil {
  40. return f.IsDir(), nil
  41. }
  42. if os.IsNotExist(err) {
  43. return false, nil
  44. }
  45. return false, err
  46. }
  47. // IsFile returns true if given path is a file,
  48. // or returns false when it's a directory or does not exist.
  49. func IsFile(filePath string) (bool, error) {
  50. f, err := os.Stat(filePath)
  51. if err == nil {
  52. return !f.IsDir(), nil
  53. }
  54. if os.IsNotExist(err) {
  55. return false, nil
  56. }
  57. return false, err
  58. }
  59. // IsExist checks whether a file or directory exists.
  60. // It returns false when the file or directory does not exist.
  61. func IsExist(path string) (bool, error) {
  62. _, err := os.Stat(path)
  63. if err == nil || os.IsExist(err) {
  64. return true, nil
  65. }
  66. if os.IsNotExist(err) {
  67. return false, nil
  68. }
  69. return false, err
  70. }
  71. func statDir(dirPath, recPath string, includeDir, isDirOnly, followSymlinks bool) ([]string, error) {
  72. dir, err := os.Open(dirPath)
  73. if err != nil {
  74. return nil, err
  75. }
  76. defer dir.Close()
  77. fis, err := dir.Readdir(0)
  78. if err != nil {
  79. return nil, err
  80. }
  81. statList := make([]string, 0)
  82. for _, fi := range fis {
  83. if strings.Contains(fi.Name(), ".DS_Store") {
  84. continue
  85. }
  86. relPath := path.Join(recPath, fi.Name())
  87. curPath := path.Join(dirPath, fi.Name())
  88. if fi.IsDir() {
  89. if includeDir {
  90. statList = append(statList, relPath+"/")
  91. }
  92. s, err := statDir(curPath, relPath, includeDir, isDirOnly, followSymlinks)
  93. if err != nil {
  94. return nil, err
  95. }
  96. statList = append(statList, s...)
  97. } else if !isDirOnly {
  98. statList = append(statList, relPath)
  99. } else if followSymlinks && fi.Mode()&os.ModeSymlink != 0 {
  100. link, err := os.Readlink(curPath)
  101. if err != nil {
  102. return nil, err
  103. }
  104. isDir, err := IsDir(link)
  105. if err != nil {
  106. return nil, err
  107. }
  108. if isDir {
  109. if includeDir {
  110. statList = append(statList, relPath+"/")
  111. }
  112. s, err := statDir(curPath, relPath, includeDir, isDirOnly, followSymlinks)
  113. if err != nil {
  114. return nil, err
  115. }
  116. statList = append(statList, s...)
  117. }
  118. }
  119. }
  120. return statList, nil
  121. }
  122. // StatDir gathers information of given directory by depth-first.
  123. // It returns slice of file list and includes subdirectories if enabled;
  124. // it returns error and nil slice when error occurs in underlying functions,
  125. // or given path is not a directory or does not exist.
  126. //
  127. // Slice does not include given path itself.
  128. // If subdirectories is enabled, they will have suffix '/'.
  129. func StatDir(rootPath string, includeDir ...bool) ([]string, error) {
  130. if isDir, err := IsDir(rootPath); err != nil {
  131. return nil, err
  132. } else if !isDir {
  133. return nil, errors.New("not a directory or does not exist: " + rootPath)
  134. }
  135. isIncludeDir := false
  136. if len(includeDir) != 0 {
  137. isIncludeDir = includeDir[0]
  138. }
  139. return statDir(rootPath, "", isIncludeDir, false, false)
  140. }
  141. // FileURLToPath extracts the path informations from a file://... url.
  142. func FileURLToPath(u *url.URL) (string, error) {
  143. if u.Scheme != "file" {
  144. return "", errors.New("URL scheme is not 'file': " + u.String())
  145. }
  146. path := u.Path
  147. if runtime.GOOS != "windows" {
  148. return path, nil
  149. }
  150. // If it looks like there's a Windows drive letter at the beginning, strip off the leading slash.
  151. re := regexp.MustCompile("/[A-Za-z]:/")
  152. if re.MatchString(path) {
  153. return path[1:], nil
  154. }
  155. return path, nil
  156. }