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

     1  // +build windows
     2  
     3  package lcow // import "github.com/docker/docker/daemon/graphdriver/lcow"
     4  
     5  import (
     6  	"bytes"
     7  	"fmt"
     8  	"io"
     9  	"runtime"
    10  	"strings"
    11  	"sync"
    12  
    13  	"github.com/Microsoft/hcsshim"
    14  	"github.com/Microsoft/opengcs/service/gcsutils/remotefs"
    15  	"github.com/docker/docker/pkg/archive"
    16  	"github.com/docker/docker/pkg/containerfs"
    17  	"github.com/sirupsen/logrus"
    18  )
    19  
    20  type lcowfs struct {
    21  	root        string
    22  	d           *Driver
    23  	mappedDisks []hcsshim.MappedVirtualDisk
    24  	vmID        string
    25  	currentSVM  *serviceVM
    26  	sync.Mutex
    27  }
    28  
    29  var _ containerfs.ContainerFS = &lcowfs{}
    30  
    31  // ErrNotSupported is an error for unsupported operations in the remotefs
    32  var ErrNotSupported = fmt.Errorf("not supported")
    33  
    34  // Functions to implement the ContainerFS interface
    35  func (l *lcowfs) Path() string {
    36  	return l.root
    37  }
    38  
    39  func (l *lcowfs) ResolveScopedPath(path string, rawPath bool) (string, error) {
    40  	logrus.Debugf("remotefs.resolvescopedpath inputs: %s %s ", path, l.root)
    41  
    42  	arg1 := l.Join(l.root, path)
    43  	if !rawPath {
    44  		// The l.Join("/", path) will make path an absolute path and then clean it
    45  		// so if path = ../../X, it will become /X.
    46  		arg1 = l.Join(l.root, l.Join("/", path))
    47  	}
    48  	arg2 := l.root
    49  
    50  	output := &bytes.Buffer{}
    51  	if err := l.runRemoteFSProcess(nil, output, remotefs.ResolvePathCmd, arg1, arg2); err != nil {
    52  		return "", err
    53  	}
    54  
    55  	logrus.Debugf("remotefs.resolvescopedpath success. Output: %s\n", output.String())
    56  	return output.String(), nil
    57  }
    58  
    59  func (l *lcowfs) OS() string {
    60  	return "linux"
    61  }
    62  
    63  func (l *lcowfs) Architecture() string {
    64  	return runtime.GOARCH
    65  }
    66  
    67  // Other functions that are used by docker like the daemon Archiver/Extractor
    68  func (l *lcowfs) ExtractArchive(src io.Reader, dst string, opts *archive.TarOptions) error {
    69  	logrus.Debugf("remotefs.ExtractArchve inputs: %s %+v", dst, opts)
    70  
    71  	tarBuf := &bytes.Buffer{}
    72  	if err := remotefs.WriteTarOptions(tarBuf, opts); err != nil {
    73  		return fmt.Errorf("failed to marshall tar opts: %s", err)
    74  	}
    75  
    76  	input := io.MultiReader(tarBuf, src)
    77  	if err := l.runRemoteFSProcess(input, nil, remotefs.ExtractArchiveCmd, dst); err != nil {
    78  		return fmt.Errorf("failed to extract archive to %s: %s", dst, err)
    79  	}
    80  	return nil
    81  }
    82  
    83  func (l *lcowfs) ArchivePath(src string, opts *archive.TarOptions) (io.ReadCloser, error) {
    84  	logrus.Debugf("remotefs.ArchivePath: %s %+v", src, opts)
    85  
    86  	tarBuf := &bytes.Buffer{}
    87  	if err := remotefs.WriteTarOptions(tarBuf, opts); err != nil {
    88  		return nil, fmt.Errorf("failed to marshall tar opts: %s", err)
    89  	}
    90  
    91  	r, w := io.Pipe()
    92  	go func() {
    93  		defer w.Close()
    94  		if err := l.runRemoteFSProcess(tarBuf, w, remotefs.ArchivePathCmd, src); err != nil {
    95  			logrus.Debugf("REMOTEFS: Failed to extract archive: %s %+v %s", src, opts, err)
    96  		}
    97  	}()
    98  	return r, nil
    99  }
   100  
   101  // Helper functions
   102  func (l *lcowfs) startVM() error {
   103  	l.Lock()
   104  	defer l.Unlock()
   105  	if l.currentSVM != nil {
   106  		return nil
   107  	}
   108  
   109  	svm, err := l.d.startServiceVMIfNotRunning(l.vmID, l.mappedDisks, fmt.Sprintf("lcowfs.startVM"))
   110  	if err != nil {
   111  		return err
   112  	}
   113  
   114  	if err = svm.createUnionMount(l.root, l.mappedDisks...); err != nil {
   115  		return err
   116  	}
   117  	l.currentSVM = svm
   118  	return nil
   119  }
   120  
   121  func (l *lcowfs) runRemoteFSProcess(stdin io.Reader, stdout io.Writer, args ...string) error {
   122  	if err := l.startVM(); err != nil {
   123  		return err
   124  	}
   125  
   126  	// Append remotefs prefix and setup as a command line string
   127  	cmd := fmt.Sprintf("%s %s", remotefs.RemotefsCmd, strings.Join(args, " "))
   128  	stderr := &bytes.Buffer{}
   129  	if err := l.currentSVM.runProcess(cmd, stdin, stdout, stderr); err != nil {
   130  		return err
   131  	}
   132  
   133  	eerr, err := remotefs.ReadError(stderr)
   134  	if eerr != nil {
   135  		// Process returned an error so return that.
   136  		return remotefs.ExportedToError(eerr)
   137  	}
   138  	return err
   139  }