blob: 29f15fd24cf66830d2d05786ead8be9179f80f6b [file] [log] [blame]
// +build windows
package lcow // import "github.com/docker/docker/daemon/graphdriver/lcow"
import (
"bytes"
"fmt"
"io"
"runtime"
"strings"
"sync"
"github.com/Microsoft/hcsshim"
"github.com/Microsoft/opengcs/service/gcsutils/remotefs"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/containerfs"
"github.com/sirupsen/logrus"
)
type lcowfs struct {
root string
d *Driver
mappedDisks []hcsshim.MappedVirtualDisk
vmID string
currentSVM *serviceVM
sync.Mutex
}
var _ containerfs.ContainerFS = &lcowfs{}
// ErrNotSupported is an error for unsupported operations in the remotefs
var ErrNotSupported = fmt.Errorf("not supported")
// Functions to implement the ContainerFS interface
func (l *lcowfs) Path() string {
return l.root
}
func (l *lcowfs) ResolveScopedPath(path string, rawPath bool) (string, error) {
logrus.Debugf("remotefs.resolvescopedpath inputs: %s %s ", path, l.root)
arg1 := l.Join(l.root, path)
if !rawPath {
// The l.Join("/", path) will make path an absolute path and then clean it
// so if path = ../../X, it will become /X.
arg1 = l.Join(l.root, l.Join("/", path))
}
arg2 := l.root
output := &bytes.Buffer{}
if err := l.runRemoteFSProcess(nil, output, remotefs.ResolvePathCmd, arg1, arg2); err != nil {
return "", err
}
logrus.Debugf("remotefs.resolvescopedpath success. Output: %s\n", output.String())
return output.String(), nil
}
func (l *lcowfs) OS() string {
return "linux"
}
func (l *lcowfs) Architecture() string {
return runtime.GOARCH
}
// Other functions that are used by docker like the daemon Archiver/Extractor
func (l *lcowfs) ExtractArchive(src io.Reader, dst string, opts *archive.TarOptions) error {
logrus.Debugf("remotefs.ExtractArchve inputs: %s %+v", dst, opts)
tarBuf := &bytes.Buffer{}
if err := remotefs.WriteTarOptions(tarBuf, opts); err != nil {
return fmt.Errorf("failed to marshall tar opts: %s", err)
}
input := io.MultiReader(tarBuf, src)
if err := l.runRemoteFSProcess(input, nil, remotefs.ExtractArchiveCmd, dst); err != nil {
return fmt.Errorf("failed to extract archive to %s: %s", dst, err)
}
return nil
}
func (l *lcowfs) ArchivePath(src string, opts *archive.TarOptions) (io.ReadCloser, error) {
logrus.Debugf("remotefs.ArchivePath: %s %+v", src, opts)
tarBuf := &bytes.Buffer{}
if err := remotefs.WriteTarOptions(tarBuf, opts); err != nil {
return nil, fmt.Errorf("failed to marshall tar opts: %s", err)
}
r, w := io.Pipe()
go func() {
defer w.Close()
if err := l.runRemoteFSProcess(tarBuf, w, remotefs.ArchivePathCmd, src); err != nil {
logrus.Debugf("REMOTEFS: Failed to extract archive: %s %+v %s", src, opts, err)
}
}()
return r, nil
}
// Helper functions
func (l *lcowfs) startVM() error {
l.Lock()
defer l.Unlock()
if l.currentSVM != nil {
return nil
}
svm, err := l.d.startServiceVMIfNotRunning(l.vmID, l.mappedDisks, fmt.Sprintf("lcowfs.startVM"))
if err != nil {
return err
}
if err = svm.createUnionMount(l.root, l.mappedDisks...); err != nil {
return err
}
l.currentSVM = svm
return nil
}
func (l *lcowfs) runRemoteFSProcess(stdin io.Reader, stdout io.Writer, args ...string) error {
if err := l.startVM(); err != nil {
return err
}
// Append remotefs prefix and setup as a command line string
cmd := fmt.Sprintf("%s %s", remotefs.RemotefsCmd, strings.Join(args, " "))
stderr := &bytes.Buffer{}
if err := l.currentSVM.runProcess(cmd, stdin, stdout, stderr); err != nil {
return err
}
eerr, err := remotefs.ReadError(stderr)
if eerr != nil {
// Process returned an error so return that.
return remotefs.ExportedToError(eerr)
}
return err
}