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