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  }