123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- // +build windows
- package lcow
- import (
- "errors"
- "os"
- pathpkg "path"
- "path/filepath"
- "sort"
- "strings"
- "github.com/containerd/continuity/pathdriver"
- )
- var _ pathdriver.PathDriver = &lcowfs{}
- // Continuity Path functions can be done locally
- func (l *lcowfs) Join(path ...string) string {
- return pathpkg.Join(path...)
- }
- func (l *lcowfs) IsAbs(path string) bool {
- return pathpkg.IsAbs(path)
- }
- func sameWord(a, b string) bool {
- return a == b
- }
- // Implementation taken from the Go standard library
- func (l *lcowfs) Rel(basepath, targpath string) (string, error) {
- baseVol := ""
- targVol := ""
- base := l.Clean(basepath)
- targ := l.Clean(targpath)
- if sameWord(targ, base) {
- return ".", nil
- }
- base = base[len(baseVol):]
- targ = targ[len(targVol):]
- if base == "." {
- base = ""
- }
- // Can't use IsAbs - `\a` and `a` are both relative in Windows.
- baseSlashed := len(base) > 0 && base[0] == l.Separator()
- targSlashed := len(targ) > 0 && targ[0] == l.Separator()
- if baseSlashed != targSlashed || !sameWord(baseVol, targVol) {
- return "", errors.New("Rel: can't make " + targpath + " relative to " + basepath)
- }
- // Position base[b0:bi] and targ[t0:ti] at the first differing elements.
- bl := len(base)
- tl := len(targ)
- var b0, bi, t0, ti int
- for {
- for bi < bl && base[bi] != l.Separator() {
- bi++
- }
- for ti < tl && targ[ti] != l.Separator() {
- ti++
- }
- if !sameWord(targ[t0:ti], base[b0:bi]) {
- break
- }
- if bi < bl {
- bi++
- }
- if ti < tl {
- ti++
- }
- b0 = bi
- t0 = ti
- }
- if base[b0:bi] == ".." {
- return "", errors.New("Rel: can't make " + targpath + " relative to " + basepath)
- }
- if b0 != bl {
- // Base elements left. Must go up before going down.
- seps := strings.Count(base[b0:bl], string(l.Separator()))
- size := 2 + seps*3
- if tl != t0 {
- size += 1 + tl - t0
- }
- buf := make([]byte, size)
- n := copy(buf, "..")
- for i := 0; i < seps; i++ {
- buf[n] = l.Separator()
- copy(buf[n+1:], "..")
- n += 3
- }
- if t0 != tl {
- buf[n] = l.Separator()
- copy(buf[n+1:], targ[t0:])
- }
- return string(buf), nil
- }
- return targ[t0:], nil
- }
- func (l *lcowfs) Base(path string) string {
- return pathpkg.Base(path)
- }
- func (l *lcowfs) Dir(path string) string {
- return pathpkg.Dir(path)
- }
- func (l *lcowfs) Clean(path string) string {
- return pathpkg.Clean(path)
- }
- func (l *lcowfs) Split(path string) (dir, file string) {
- return pathpkg.Split(path)
- }
- func (l *lcowfs) Separator() byte {
- return '/'
- }
- func (l *lcowfs) Abs(path string) (string, error) {
- // Abs is supposed to add the current working directory, which is meaningless in lcow.
- // So, return an error.
- return "", ErrNotSupported
- }
- // Implementation taken from the Go standard library
- func (l *lcowfs) Walk(root string, walkFn filepath.WalkFunc) error {
- info, err := l.Lstat(root)
- if err != nil {
- err = walkFn(root, nil, err)
- } else {
- err = l.walk(root, info, walkFn)
- }
- if err == filepath.SkipDir {
- return nil
- }
- return err
- }
- // walk recursively descends path, calling w.
- func (l *lcowfs) walk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error {
- err := walkFn(path, info, nil)
- if err != nil {
- if info.IsDir() && err == filepath.SkipDir {
- return nil
- }
- return err
- }
- if !info.IsDir() {
- return nil
- }
- names, err := l.readDirNames(path)
- if err != nil {
- return walkFn(path, info, err)
- }
- for _, name := range names {
- filename := l.Join(path, name)
- fileInfo, err := l.Lstat(filename)
- if err != nil {
- if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
- return err
- }
- } else {
- err = l.walk(filename, fileInfo, walkFn)
- if err != nil {
- if !fileInfo.IsDir() || err != filepath.SkipDir {
- return err
- }
- }
- }
- }
- return nil
- }
- // readDirNames reads the directory named by dirname and returns
- // a sorted list of directory entries.
- func (l *lcowfs) readDirNames(dirname string) ([]string, error) {
- f, err := l.Open(dirname)
- if err != nil {
- return nil, err
- }
- files, err := f.Readdir(-1)
- f.Close()
- if err != nil {
- return nil, err
- }
- names := make([]string, len(files), len(files))
- for i := range files {
- names[i] = files[i].Name()
- }
- sort.Strings(names)
- return names, nil
- }
- // Note that Go's filepath.FromSlash/ToSlash convert between OS paths and '/'. Since the path separator
- // for LCOW (and Unix) is '/', they are no-ops.
- func (l *lcowfs) FromSlash(path string) string {
- return path
- }
- func (l *lcowfs) ToSlash(path string) string {
- return path
- }
- func (l *lcowfs) Match(pattern, name string) (matched bool, err error) {
- return pathpkg.Match(pattern, name)
- }
|