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