File: remotefs.go

package info (click to toggle)
docker.io 20.10.24%2Bdfsg1-1%2Bdeb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bookworm-proposed-updates
  • size: 60,824 kB
  • sloc: sh: 5,621; makefile: 593; ansic: 179; python: 162; asm: 7
file content (140 lines) | stat: -rw-r--r-- 3,698 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//go:build windows
// +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
}