github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/daemon/graphdriver/lcow/remotefs_pathdriver.go (about)

     1  // +build windows
     2  
     3  package lcow // import "github.com/docker/docker/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  }