remotefs_pathdriver.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. // +build windows
  2. package lcow
  3. import (
  4. "errors"
  5. "os"
  6. pathpkg "path"
  7. "path/filepath"
  8. "sort"
  9. "strings"
  10. "github.com/containerd/continuity/pathdriver"
  11. )
  12. var _ pathdriver.PathDriver = &lcowfs{}
  13. // Continuity Path functions can be done locally
  14. func (l *lcowfs) Join(path ...string) string {
  15. return pathpkg.Join(path...)
  16. }
  17. func (l *lcowfs) IsAbs(path string) bool {
  18. return pathpkg.IsAbs(path)
  19. }
  20. func sameWord(a, b string) bool {
  21. return a == b
  22. }
  23. // Implementation taken from the Go standard library
  24. func (l *lcowfs) Rel(basepath, targpath string) (string, error) {
  25. baseVol := ""
  26. targVol := ""
  27. base := l.Clean(basepath)
  28. targ := l.Clean(targpath)
  29. if sameWord(targ, base) {
  30. return ".", nil
  31. }
  32. base = base[len(baseVol):]
  33. targ = targ[len(targVol):]
  34. if base == "." {
  35. base = ""
  36. }
  37. // Can't use IsAbs - `\a` and `a` are both relative in Windows.
  38. baseSlashed := len(base) > 0 && base[0] == l.Separator()
  39. targSlashed := len(targ) > 0 && targ[0] == l.Separator()
  40. if baseSlashed != targSlashed || !sameWord(baseVol, targVol) {
  41. return "", errors.New("Rel: can't make " + targpath + " relative to " + basepath)
  42. }
  43. // Position base[b0:bi] and targ[t0:ti] at the first differing elements.
  44. bl := len(base)
  45. tl := len(targ)
  46. var b0, bi, t0, ti int
  47. for {
  48. for bi < bl && base[bi] != l.Separator() {
  49. bi++
  50. }
  51. for ti < tl && targ[ti] != l.Separator() {
  52. ti++
  53. }
  54. if !sameWord(targ[t0:ti], base[b0:bi]) {
  55. break
  56. }
  57. if bi < bl {
  58. bi++
  59. }
  60. if ti < tl {
  61. ti++
  62. }
  63. b0 = bi
  64. t0 = ti
  65. }
  66. if base[b0:bi] == ".." {
  67. return "", errors.New("Rel: can't make " + targpath + " relative to " + basepath)
  68. }
  69. if b0 != bl {
  70. // Base elements left. Must go up before going down.
  71. seps := strings.Count(base[b0:bl], string(l.Separator()))
  72. size := 2 + seps*3
  73. if tl != t0 {
  74. size += 1 + tl - t0
  75. }
  76. buf := make([]byte, size)
  77. n := copy(buf, "..")
  78. for i := 0; i < seps; i++ {
  79. buf[n] = l.Separator()
  80. copy(buf[n+1:], "..")
  81. n += 3
  82. }
  83. if t0 != tl {
  84. buf[n] = l.Separator()
  85. copy(buf[n+1:], targ[t0:])
  86. }
  87. return string(buf), nil
  88. }
  89. return targ[t0:], nil
  90. }
  91. func (l *lcowfs) Base(path string) string {
  92. return pathpkg.Base(path)
  93. }
  94. func (l *lcowfs) Dir(path string) string {
  95. return pathpkg.Dir(path)
  96. }
  97. func (l *lcowfs) Clean(path string) string {
  98. return pathpkg.Clean(path)
  99. }
  100. func (l *lcowfs) Split(path string) (dir, file string) {
  101. return pathpkg.Split(path)
  102. }
  103. func (l *lcowfs) Separator() byte {
  104. return '/'
  105. }
  106. func (l *lcowfs) Abs(path string) (string, error) {
  107. // Abs is supposed to add the current working directory, which is meaningless in lcow.
  108. // So, return an error.
  109. return "", ErrNotSupported
  110. }
  111. // Implementation taken from the Go standard library
  112. func (l *lcowfs) Walk(root string, walkFn filepath.WalkFunc) error {
  113. info, err := l.Lstat(root)
  114. if err != nil {
  115. err = walkFn(root, nil, err)
  116. } else {
  117. err = l.walk(root, info, walkFn)
  118. }
  119. if err == filepath.SkipDir {
  120. return nil
  121. }
  122. return err
  123. }
  124. // walk recursively descends path, calling w.
  125. func (l *lcowfs) walk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error {
  126. err := walkFn(path, info, nil)
  127. if err != nil {
  128. if info.IsDir() && err == filepath.SkipDir {
  129. return nil
  130. }
  131. return err
  132. }
  133. if !info.IsDir() {
  134. return nil
  135. }
  136. names, err := l.readDirNames(path)
  137. if err != nil {
  138. return walkFn(path, info, err)
  139. }
  140. for _, name := range names {
  141. filename := l.Join(path, name)
  142. fileInfo, err := l.Lstat(filename)
  143. if err != nil {
  144. if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
  145. return err
  146. }
  147. } else {
  148. err = l.walk(filename, fileInfo, walkFn)
  149. if err != nil {
  150. if !fileInfo.IsDir() || err != filepath.SkipDir {
  151. return err
  152. }
  153. }
  154. }
  155. }
  156. return nil
  157. }
  158. // readDirNames reads the directory named by dirname and returns
  159. // a sorted list of directory entries.
  160. func (l *lcowfs) readDirNames(dirname string) ([]string, error) {
  161. f, err := l.Open(dirname)
  162. if err != nil {
  163. return nil, err
  164. }
  165. files, err := f.Readdir(-1)
  166. f.Close()
  167. if err != nil {
  168. return nil, err
  169. }
  170. names := make([]string, len(files), len(files))
  171. for i := range files {
  172. names[i] = files[i].Name()
  173. }
  174. sort.Strings(names)
  175. return names, nil
  176. }
  177. // Note that Go's filepath.FromSlash/ToSlash convert between OS paths and '/'. Since the path separator
  178. // for LCOW (and Unix) is '/', they are no-ops.
  179. func (l *lcowfs) FromSlash(path string) string {
  180. return path
  181. }
  182. func (l *lcowfs) ToSlash(path string) string {
  183. return path
  184. }
  185. func (l *lcowfs) Match(pattern, name string) (matched bool, err error) {
  186. return pathpkg.Match(pattern, name)
  187. }