1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00
moby--moby/daemon/graphdriver/lcow/remotefs_pathdriver.go
Akash Gupta 7a7357dae1 LCOW: Implemented support for docker cp + build
This enables docker cp and ADD/COPY docker build support for LCOW.
Originally, the graphdriver.Get() interface returned a local path
to the container root filesystem. This does not work for LCOW, so
the Get() method now returns an interface that LCOW implements to
support copying to and from the container.

Signed-off-by: Akash Gupta <akagup@microsoft.com>
2017-09-14 12:07:52 -07:00

212 lines
4.5 KiB
Go

// +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)
}