Merge pull request #44191 from corhere/drop-containerfs-iface
Remove LCOW: pkg/containerfs: drop ContainerFS abstraction
This commit is contained in:
commit
89555e45f2
66 changed files with 376 additions and 897 deletions
|
@ -291,7 +291,7 @@ func (s *snapshotter) Mounts(ctx context.Context, key string) (snapshot.Mountabl
|
|||
return nil, nil, err
|
||||
}
|
||||
return []mount.Mount{{
|
||||
Source: rootfs.Path(),
|
||||
Source: rootfs,
|
||||
Type: "bind",
|
||||
Options: []string{"rbind"},
|
||||
}}, func() error {
|
||||
|
@ -312,7 +312,7 @@ func (s *snapshotter) Mounts(ctx context.Context, key string) (snapshot.Mountabl
|
|||
return nil, nil, err
|
||||
}
|
||||
return []mount.Mount{{
|
||||
Source: rootfs.Path(),
|
||||
Source: rootfs,
|
||||
Type: "bind",
|
||||
Options: []string{"rbind"},
|
||||
}}, func() error {
|
||||
|
|
|
@ -14,7 +14,6 @@ import (
|
|||
containerpkg "github.com/docker/docker/container"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -26,7 +25,7 @@ const (
|
|||
// instructions in the builder.
|
||||
type Source interface {
|
||||
// Root returns root path for accessing source
|
||||
Root() containerfs.ContainerFS
|
||||
Root() string
|
||||
// Close allows to signal that the filesystem tree won't be used anymore.
|
||||
// For Context implementations using a temporary directory, it is recommended to
|
||||
// delete the temporary directory in Close().
|
||||
|
@ -110,6 +109,6 @@ type ROLayer interface {
|
|||
// RWLayer is active layer that can be read/modified
|
||||
type RWLayer interface {
|
||||
Release() error
|
||||
Root() containerfs.ContainerFS
|
||||
Root() string
|
||||
Commit() (ROLayer, error)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package dockerfile // import "github.com/docker/docker/builder/dockerfile"
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime"
|
||||
|
@ -39,14 +38,14 @@ type pathCache interface {
|
|||
// copyInfo is a data object which stores the metadata about each source file in
|
||||
// a copyInstruction
|
||||
type copyInfo struct {
|
||||
root containerfs.ContainerFS
|
||||
root string
|
||||
path string
|
||||
hash string
|
||||
noDecompress bool
|
||||
}
|
||||
|
||||
func (c copyInfo) fullPath() (string, error) {
|
||||
return c.root.ResolveScopedPath(c.path, true)
|
||||
return containerfs.ResolveScopedPath(c.root, c.path)
|
||||
}
|
||||
|
||||
func newCopyInfoFromSource(source builder.Source, path string, hash string) copyInfo {
|
||||
|
@ -160,7 +159,7 @@ func (o *copier) getCopyInfoForSourcePath(orig, dest string) ([]copyInfo, error)
|
|||
}
|
||||
path = unnamedFilename
|
||||
}
|
||||
o.tmpPaths = append(o.tmpPaths, remote.Root().Path())
|
||||
o.tmpPaths = append(o.tmpPaths, remote.Root())
|
||||
|
||||
hash, err := remote.Hash(path)
|
||||
ci := newCopyInfoFromSource(remote, path, hash)
|
||||
|
@ -203,7 +202,7 @@ func (o *copier) calcCopyInfo(origPath string, allowWildcards bool) ([]copyInfo,
|
|||
|
||||
o.source, err = remotecontext.NewLazySource(rwLayer.Root())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to create context for copy from %s", rwLayer.Root().Path())
|
||||
return nil, errors.Wrapf(err, "failed to create context for copy from %s", rwLayer.Root())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -260,7 +259,7 @@ func (o *copier) storeInPathCache(im *imageMount, path string, hash string) {
|
|||
func (o *copier) copyWithWildcards(origPath string) ([]copyInfo, error) {
|
||||
root := o.source.Root()
|
||||
var copyInfos []copyInfo
|
||||
if err := root.Walk(root.Path(), func(path string, info os.FileInfo, err error) error {
|
||||
if err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -272,7 +271,7 @@ func (o *copier) copyWithWildcards(origPath string) ([]copyInfo, error) {
|
|||
if rel == "." {
|
||||
return nil
|
||||
}
|
||||
if match, _ := root.Match(origPath, rel); !match {
|
||||
if match, _ := filepath.Match(origPath, rel); !match {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -318,7 +317,7 @@ func walkSource(source builder.Source, origPath string) ([]string, error) {
|
|||
}
|
||||
// Must be a dir
|
||||
var subfiles []string
|
||||
err = source.Root().Walk(fp, func(path string, info os.FileInfo, err error) error {
|
||||
err = filepath.Walk(fp, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -443,19 +442,14 @@ func downloadSource(output io.Writer, stdout io.Writer, srcURL string) (remote b
|
|||
return
|
||||
}
|
||||
|
||||
lc, err := remotecontext.NewLazySource(containerfs.NewLocalContainerFS(tmpDir))
|
||||
lc, err := remotecontext.NewLazySource(tmpDir)
|
||||
return lc, filename, err
|
||||
}
|
||||
|
||||
type copyFileOptions struct {
|
||||
decompress bool
|
||||
identity *idtools.Identity
|
||||
archiver Archiver
|
||||
}
|
||||
|
||||
type copyEndpoint struct {
|
||||
driver containerfs.Driver
|
||||
path string
|
||||
archiver *archive.Archiver
|
||||
}
|
||||
|
||||
func performCopyForInfo(dest copyInfo, source copyInfo, options copyFileOptions) error {
|
||||
|
@ -471,96 +465,77 @@ func performCopyForInfo(dest copyInfo, source copyInfo, options copyFileOptions)
|
|||
|
||||
archiver := options.archiver
|
||||
|
||||
srcEndpoint := ©Endpoint{driver: source.root, path: srcPath}
|
||||
destEndpoint := ©Endpoint{driver: dest.root, path: destPath}
|
||||
|
||||
src, err := source.root.Stat(srcPath)
|
||||
src, err := os.Stat(srcPath)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "source path not found")
|
||||
}
|
||||
if src.IsDir() {
|
||||
return copyDirectory(archiver, srcEndpoint, destEndpoint, options.identity)
|
||||
return copyDirectory(archiver, srcPath, destPath, options.identity)
|
||||
}
|
||||
if options.decompress && isArchivePath(source.root, srcPath) && !source.noDecompress {
|
||||
if options.decompress && archive.IsArchivePath(srcPath) && !source.noDecompress {
|
||||
return archiver.UntarPath(srcPath, destPath)
|
||||
}
|
||||
|
||||
destExistsAsDir, err := isExistingDirectory(destEndpoint)
|
||||
destExistsAsDir, err := isExistingDirectory(destPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// dest.path must be used because destPath has already been cleaned of any
|
||||
// trailing slash
|
||||
if endsInSlash(dest.root, dest.path) || destExistsAsDir {
|
||||
if endsInSlash(dest.path) || destExistsAsDir {
|
||||
// source.path must be used to get the correct filename when the source
|
||||
// is a symlink
|
||||
destPath = dest.root.Join(destPath, source.root.Base(source.path))
|
||||
destEndpoint = ©Endpoint{driver: dest.root, path: destPath}
|
||||
destPath = filepath.Join(destPath, filepath.Base(source.path))
|
||||
}
|
||||
return copyFile(archiver, srcEndpoint, destEndpoint, options.identity)
|
||||
return copyFile(archiver, srcPath, destPath, options.identity)
|
||||
}
|
||||
|
||||
func isArchivePath(driver containerfs.ContainerFS, path string) bool {
|
||||
file, err := driver.Open(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer file.Close()
|
||||
rdr, err := archive.DecompressStream(file)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
r := tar.NewReader(rdr)
|
||||
_, err = r.Next()
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func copyDirectory(archiver Archiver, source, dest *copyEndpoint, identity *idtools.Identity) error {
|
||||
func copyDirectory(archiver *archive.Archiver, source, dest string, identity *idtools.Identity) error {
|
||||
destExists, err := isExistingDirectory(dest)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to query destination path")
|
||||
}
|
||||
|
||||
if err := archiver.CopyWithTar(source.path, dest.path); err != nil {
|
||||
if err := archiver.CopyWithTar(source, dest); err != nil {
|
||||
return errors.Wrapf(err, "failed to copy directory")
|
||||
}
|
||||
if identity != nil {
|
||||
return fixPermissions(source.path, dest.path, *identity, !destExists)
|
||||
return fixPermissions(source, dest, *identity, !destExists)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyFile(archiver Archiver, source, dest *copyEndpoint, identity *idtools.Identity) error {
|
||||
func copyFile(archiver *archive.Archiver, source, dest string, identity *idtools.Identity) error {
|
||||
if identity == nil {
|
||||
// Use system.MkdirAll here, which is a custom version of os.MkdirAll
|
||||
// modified for use on Windows to handle volume GUID paths. These paths
|
||||
// are of the form \\?\Volume{<GUID>}\<path>. An example would be:
|
||||
// \\?\Volume{dae8d3ac-b9a1-11e9-88eb-e8554b2ba1db}\bin\busybox.exe
|
||||
if err := system.MkdirAll(filepath.Dir(dest.path), 0755); err != nil {
|
||||
if err := system.MkdirAll(filepath.Dir(dest), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := idtools.MkdirAllAndChownNew(filepath.Dir(dest.path), 0755, *identity); err != nil {
|
||||
if err := idtools.MkdirAllAndChownNew(filepath.Dir(dest), 0755, *identity); err != nil {
|
||||
return errors.Wrapf(err, "failed to create new directory")
|
||||
}
|
||||
}
|
||||
|
||||
if err := archiver.CopyFileWithTar(source.path, dest.path); err != nil {
|
||||
if err := archiver.CopyFileWithTar(source, dest); err != nil {
|
||||
return errors.Wrapf(err, "failed to copy file")
|
||||
}
|
||||
if identity != nil {
|
||||
return fixPermissions(source.path, dest.path, *identity, false)
|
||||
return fixPermissions(source, dest, *identity, false)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func endsInSlash(driver containerfs.Driver, path string) bool {
|
||||
return strings.HasSuffix(path, string(driver.Separator()))
|
||||
func endsInSlash(path string) bool {
|
||||
return strings.HasSuffix(path, string(filepath.Separator))
|
||||
}
|
||||
|
||||
// isExistingDirectory returns true if the path exists and is a directory
|
||||
func isExistingDirectory(point *copyEndpoint) (bool, error) {
|
||||
destStat, err := point.driver.Stat(point.path)
|
||||
func isExistingDirectory(path string) (bool, error) {
|
||||
destStat, err := os.Stat(path)
|
||||
switch {
|
||||
case errors.Is(err, os.ErrNotExist):
|
||||
return false, nil
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
"gotest.tools/v3/fs"
|
||||
|
@ -39,7 +38,7 @@ func TestIsExistingDirectory(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, testcase := range testcases {
|
||||
result, err := isExistingDirectory(©Endpoint{driver: containerfs.NewLocalDriver(), path: testcase.path})
|
||||
result, err := isExistingDirectory(testcase.path)
|
||||
if !assert.Check(t, err) {
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
)
|
||||
|
||||
|
@ -19,8 +18,7 @@ func fixPermissions(source, destination string, identity idtools.Identity, overr
|
|||
err error
|
||||
)
|
||||
if !overrideSkip {
|
||||
destEndpoint := ©Endpoint{driver: containerfs.NewLocalDriver(), path: destination}
|
||||
skipChownRoot, err = isExistingDirectory(destEndpoint)
|
||||
skipChownRoot, err = isExistingDirectory(destination)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
|
@ -17,8 +16,6 @@ import (
|
|||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/chrootarchive"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/go-connections/nat"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
|
@ -26,50 +23,8 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Archiver defines an interface for copying files from one destination to
|
||||
// another using Tar/Untar.
|
||||
type Archiver interface {
|
||||
TarUntar(src, dst string) error
|
||||
UntarPath(src, dst string) error
|
||||
CopyWithTar(src, dst string) error
|
||||
CopyFileWithTar(src, dst string) error
|
||||
IdentityMapping() idtools.IdentityMapping
|
||||
}
|
||||
|
||||
// The builder will use the following interfaces if the container fs implements
|
||||
// these for optimized copies to and from the container.
|
||||
type extractor interface {
|
||||
ExtractArchive(src io.Reader, dst string, opts *archive.TarOptions) error
|
||||
}
|
||||
|
||||
type archiver interface {
|
||||
ArchivePath(src string, opts *archive.TarOptions) (io.ReadCloser, error)
|
||||
}
|
||||
|
||||
// helper functions to get tar/untar func
|
||||
func untarFunc(i interface{}) containerfs.UntarFunc {
|
||||
if ea, ok := i.(extractor); ok {
|
||||
return ea.ExtractArchive
|
||||
}
|
||||
return chrootarchive.Untar
|
||||
}
|
||||
|
||||
func tarFunc(i interface{}) containerfs.TarFunc {
|
||||
if ap, ok := i.(archiver); ok {
|
||||
return ap.ArchivePath
|
||||
}
|
||||
return archive.TarWithOptions
|
||||
}
|
||||
|
||||
func (b *Builder) getArchiver(src, dst containerfs.Driver) Archiver {
|
||||
t, u := tarFunc(src), untarFunc(dst)
|
||||
return &containerfs.Archiver{
|
||||
SrcDriver: src,
|
||||
DstDriver: dst,
|
||||
Tar: t,
|
||||
Untar: u,
|
||||
IDMapping: b.idMapping,
|
||||
}
|
||||
func (b *Builder) getArchiver() *archive.Archiver {
|
||||
return chrootarchive.NewArchiver(b.idMapping)
|
||||
}
|
||||
|
||||
func (b *Builder) commit(dispatchState *dispatchState, comment string) error {
|
||||
|
@ -192,7 +147,7 @@ func (b *Builder) performCopy(req dispatchRequest, inst copyInstruction) error {
|
|||
// translated (if necessary because of user namespaces), and replace
|
||||
// the root pair with the chown pair for copy operations
|
||||
if inst.chownStr != "" {
|
||||
identity, err = parseChownFlag(b, state, inst.chownStr, destInfo.root.Path(), b.idMapping)
|
||||
identity, err = parseChownFlag(b, state, inst.chownStr, destInfo.root, b.idMapping)
|
||||
if err != nil {
|
||||
if b.options.Platform != "windows" {
|
||||
return errors.Wrapf(err, "unable to convert uid/gid chown string to host mapping")
|
||||
|
@ -205,7 +160,7 @@ func (b *Builder) performCopy(req dispatchRequest, inst copyInstruction) error {
|
|||
for _, info := range inst.infos {
|
||||
opts := copyFileOptions{
|
||||
decompress: inst.allowLocalDecompression,
|
||||
archiver: b.getArchiver(info.root, destInfo.root),
|
||||
archiver: b.getArchiver(),
|
||||
}
|
||||
if !inst.preserveOwnership {
|
||||
opts.identity = &identity
|
||||
|
|
|
@ -14,7 +14,6 @@ import (
|
|||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"gotest.tools/v3/assert"
|
||||
|
@ -183,8 +182,8 @@ func TestDeepCopyRunConfig(t *testing.T) {
|
|||
|
||||
type MockRWLayer struct{}
|
||||
|
||||
func (l *MockRWLayer) Release() error { return nil }
|
||||
func (l *MockRWLayer) Root() containerfs.ContainerFS { return nil }
|
||||
func (l *MockRWLayer) Release() error { return nil }
|
||||
func (l *MockRWLayer) Root() string { return "" }
|
||||
func (l *MockRWLayer) Commit() (builder.ROLayer, error) {
|
||||
return &MockROLayer{
|
||||
diffID: layer.DiffID(digest.Digest("sha256:1234")),
|
||||
|
|
|
@ -13,7 +13,6 @@ import (
|
|||
containerpkg "github.com/docker/docker/container"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
)
|
||||
|
||||
// MockBackend implements the builder.Backend interface for unit testing
|
||||
|
@ -143,6 +142,6 @@ func (l *mockRWLayer) Commit() (builder.ROLayer, error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func (l *mockRWLayer) Root() containerfs.ContainerFS {
|
||||
return nil
|
||||
func (l *mockRWLayer) Root() string {
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -15,12 +15,12 @@ import (
|
|||
)
|
||||
|
||||
type archiveContext struct {
|
||||
root containerfs.ContainerFS
|
||||
root string
|
||||
sums tarsum.FileInfoSums
|
||||
}
|
||||
|
||||
func (c *archiveContext) Close() error {
|
||||
return c.root.RemoveAll(c.root.Path())
|
||||
return os.RemoveAll(c.root)
|
||||
}
|
||||
|
||||
func convertPathError(err error, cleanpath string) error {
|
||||
|
@ -53,7 +53,7 @@ func FromArchive(tarStream io.Reader) (builder.Source, error) {
|
|||
}
|
||||
|
||||
// Assume local file system. Since it's coming from a tar file.
|
||||
tsc := &archiveContext{root: containerfs.NewLocalContainerFS(root)}
|
||||
tsc := &archiveContext{root: root}
|
||||
|
||||
// Make sure we clean-up upon error. In the happy case the caller
|
||||
// is expected to manage the clean-up
|
||||
|
@ -82,7 +82,7 @@ func FromArchive(tarStream io.Reader) (builder.Source, error) {
|
|||
return tsc, nil
|
||||
}
|
||||
|
||||
func (c *archiveContext) Root() containerfs.ContainerFS {
|
||||
func (c *archiveContext) Root() string {
|
||||
return c.root
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ func (c *archiveContext) Remove(path string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.root.RemoveAll(fullpath)
|
||||
return os.RemoveAll(fullpath)
|
||||
}
|
||||
|
||||
func (c *archiveContext) Hash(path string) (string, error) {
|
||||
|
@ -100,7 +100,7 @@ func (c *archiveContext) Hash(path string) (string, error) {
|
|||
return "", err
|
||||
}
|
||||
|
||||
rel, err := c.root.Rel(c.root.Path(), fullpath)
|
||||
rel, err := filepath.Rel(c.root, fullpath)
|
||||
if err != nil {
|
||||
return "", convertPathError(err, cleanpath)
|
||||
}
|
||||
|
@ -115,9 +115,9 @@ func (c *archiveContext) Hash(path string) (string, error) {
|
|||
return path, nil // backwards compat TODO: see if really needed
|
||||
}
|
||||
|
||||
func normalize(path string, root containerfs.ContainerFS) (cleanPath, fullPath string, err error) {
|
||||
cleanPath = root.Clean(string(root.Separator()) + path)[1:]
|
||||
fullPath, err = root.ResolveScopedPath(path, true)
|
||||
func normalize(path string, root string) (cleanPath, fullPath string, err error) {
|
||||
cleanPath = filepath.Clean(string(filepath.Separator) + path)[1:]
|
||||
fullPath, err = containerfs.ResolveScopedPath(root, path)
|
||||
if err != nil {
|
||||
return "", "", errors.Wrapf(err, "forbidden path outside the build context: %s (%s)", path, cleanPath)
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/docker/docker/builder"
|
||||
"github.com/docker/docker/builder/remotecontext/urlutil"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/pkg/fileutils"
|
||||
"github.com/moby/buildkit/frontend/dockerfile/dockerignore"
|
||||
"github.com/moby/buildkit/frontend/dockerfile/parser"
|
||||
|
@ -161,7 +162,7 @@ func openAt(remote builder.Source, path string) (driver.File, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return remote.Root().Open(fullPath)
|
||||
return os.Open(fullPath)
|
||||
}
|
||||
|
||||
// StatAt is a helper for calling Stat on a path from a source
|
||||
|
@ -170,12 +171,12 @@ func StatAt(remote builder.Source, path string) (os.FileInfo, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return remote.Root().Stat(fullPath)
|
||||
return os.Stat(fullPath)
|
||||
}
|
||||
|
||||
// FullPath is a helper for getting a full path for a path from a source
|
||||
func FullPath(remote builder.Source, path string) (string, error) {
|
||||
fullPath, err := remote.Root().ResolveScopedPath(path, true)
|
||||
fullPath, err := containerfs.ResolveScopedPath(remote.Root(), path)
|
||||
if err != nil {
|
||||
if runtime.GOOS == "windows" {
|
||||
return "", fmt.Errorf("failed to resolve scoped path %s (%s): %s. Possible cause is a forbidden path outside the build context", path, fullPath, err)
|
||||
|
|
|
@ -4,11 +4,11 @@ import (
|
|||
"errors"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/builder"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -52,7 +52,7 @@ func checkDirectory(t *testing.T, dir string, expectedFiles []string) {
|
|||
}
|
||||
|
||||
func executeProcess(t *testing.T, contextDir string) {
|
||||
modifiableCtx := &stubRemote{root: containerfs.NewLocalContainerFS(contextDir)}
|
||||
modifiableCtx := &stubRemote{root: contextDir}
|
||||
|
||||
err := removeDockerfile(modifiableCtx, builder.DefaultDockerfileName)
|
||||
|
||||
|
@ -104,19 +104,19 @@ func TestProcessShouldLeaveAllFiles(t *testing.T) {
|
|||
|
||||
// TODO: remove after moving to a separate pkg
|
||||
type stubRemote struct {
|
||||
root containerfs.ContainerFS
|
||||
root string
|
||||
}
|
||||
|
||||
func (r *stubRemote) Hash(path string) (string, error) {
|
||||
return "", errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (r *stubRemote) Root() containerfs.ContainerFS {
|
||||
func (r *stubRemote) Root() string {
|
||||
return r.root
|
||||
}
|
||||
func (r *stubRemote) Close() error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
func (r *stubRemote) Remove(p string) error {
|
||||
return r.root.Remove(r.root.Join(r.root.Path(), p))
|
||||
return os.Remove(filepath.Join(r.root, p))
|
||||
}
|
||||
|
|
|
@ -3,10 +3,11 @@ package remotecontext // import "github.com/docker/docker/builder/remotecontext"
|
|||
import (
|
||||
"encoding/hex"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/builder"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/pkg/pools"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
@ -14,7 +15,7 @@ import (
|
|||
// NewLazySource creates a new LazyContext. LazyContext defines a hashed build
|
||||
// context based on a root directory. Individual files are hashed first time
|
||||
// they are asked. It is not safe to call methods of LazyContext concurrently.
|
||||
func NewLazySource(root containerfs.ContainerFS) (builder.Source, error) {
|
||||
func NewLazySource(root string) (builder.Source, error) {
|
||||
return &lazySource{
|
||||
root: root,
|
||||
sums: make(map[string]string),
|
||||
|
@ -22,11 +23,11 @@ func NewLazySource(root containerfs.ContainerFS) (builder.Source, error) {
|
|||
}
|
||||
|
||||
type lazySource struct {
|
||||
root containerfs.ContainerFS
|
||||
root string
|
||||
sums map[string]string
|
||||
}
|
||||
|
||||
func (c *lazySource) Root() containerfs.ContainerFS {
|
||||
func (c *lazySource) Root() string {
|
||||
return c.root
|
||||
}
|
||||
|
||||
|
@ -45,7 +46,7 @@ func (c *lazySource) Hash(path string) (string, error) {
|
|||
return "", errors.WithStack(convertPathError(err, cleanPath))
|
||||
}
|
||||
|
||||
fi, err := c.root.Lstat(fullPath)
|
||||
fi, err := os.Lstat(fullPath)
|
||||
if err != nil {
|
||||
// Backwards compatibility: a missing file returns a path as hash.
|
||||
// This is reached in the case of a broken symlink.
|
||||
|
@ -64,13 +65,13 @@ func (c *lazySource) Hash(path string) (string, error) {
|
|||
}
|
||||
|
||||
func (c *lazySource) prepareHash(relPath string, fi os.FileInfo) (string, error) {
|
||||
p := c.root.Join(c.root.Path(), relPath)
|
||||
p := filepath.Join(c.root, relPath)
|
||||
h, err := NewFileHash(p, relPath, fi)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "failed to create hash for %s", relPath)
|
||||
}
|
||||
if fi.Mode().IsRegular() && fi.Size() > 0 {
|
||||
f, err := c.root.Open(p)
|
||||
f, err := os.Open(p)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "failed to open %s", relPath)
|
||||
}
|
||||
|
@ -86,10 +87,10 @@ func (c *lazySource) prepareHash(relPath string, fi os.FileInfo) (string, error)
|
|||
|
||||
// Rel makes a path relative to base path. Same as `filepath.Rel` but can also
|
||||
// handle UUID paths in windows.
|
||||
func Rel(basepath containerfs.ContainerFS, targpath string) (string, error) {
|
||||
func Rel(basepath string, targpath string) (string, error) {
|
||||
// filepath.Rel can't handle UUID paths in windows
|
||||
if basepath.OS() == "windows" {
|
||||
pfx := basepath.Path() + `\`
|
||||
if runtime.GOOS == "windows" {
|
||||
pfx := basepath + `\`
|
||||
if strings.HasPrefix(targpath, pfx) {
|
||||
p := strings.TrimPrefix(targpath, pfx)
|
||||
if p == "" {
|
||||
|
@ -98,5 +99,5 @@ func Rel(basepath containerfs.ContainerFS, targpath string) (string, error) {
|
|||
return p, nil
|
||||
}
|
||||
}
|
||||
return basepath.Rel(basepath.Path(), targpath)
|
||||
return filepath.Rel(basepath, targpath)
|
||||
}
|
||||
|
|
|
@ -2,9 +2,9 @@ package remotecontext // import "github.com/docker/docker/builder/remotecontext"
|
|||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
iradix "github.com/hashicorp/go-immutable-radix"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -18,7 +18,7 @@ type hashed interface {
|
|||
// CachableSource is a source that contains cache records for its contents
|
||||
type CachableSource struct {
|
||||
mu sync.Mutex
|
||||
root containerfs.ContainerFS
|
||||
root string
|
||||
tree *iradix.Tree
|
||||
txn *iradix.Txn
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ type CachableSource struct {
|
|||
func NewCachableSource(root string) *CachableSource {
|
||||
ts := &CachableSource{
|
||||
tree: iradix.New(),
|
||||
root: containerfs.NewLocalContainerFS(root),
|
||||
root: root,
|
||||
}
|
||||
return ts
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ func (cs *CachableSource) Scan() error {
|
|||
return err
|
||||
}
|
||||
txn := iradix.New().Txn()
|
||||
err = cs.root.Walk(cs.root.Path(), func(path string, info os.FileInfo, err error) error {
|
||||
err = filepath.Walk(cs.root, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to walk %s", path)
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ func (cs *CachableSource) Hash(path string) (string, error) {
|
|||
}
|
||||
|
||||
// Root returns a root directory for the source
|
||||
func (cs *CachableSource) Root() containerfs.ContainerFS {
|
||||
func (cs *CachableSource) Root() string {
|
||||
return cs.root
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ func TestCloseRootDirectory(t *testing.T) {
|
|||
t.Fatalf("Error while executing Close: %s", err)
|
||||
}
|
||||
|
||||
_, err = os.Stat(src.Root().Path())
|
||||
_, err = os.Stat(src.Root())
|
||||
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
t.Fatal("Directory should not exist at this point")
|
||||
|
@ -118,7 +118,7 @@ func TestRemoveDirectory(t *testing.T) {
|
|||
|
||||
src := makeTestArchiveContext(t, contextDir)
|
||||
|
||||
_, err = src.Root().Stat(src.Root().Join(src.Root().Path(), relativePath))
|
||||
_, err = os.Stat(filepath.Join(src.Root(), relativePath))
|
||||
if err != nil {
|
||||
t.Fatalf("Statting %s shouldn't fail: %+v", relativePath, err)
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ func TestRemoveDirectory(t *testing.T) {
|
|||
t.Fatalf("Error when executing Remove: %s", err)
|
||||
}
|
||||
|
||||
_, err = src.Root().Stat(src.Root().Join(src.Root().Path(), relativePath))
|
||||
_, err = os.Stat(filepath.Join(src.Root(), relativePath))
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
t.Fatalf("Directory should not exist at this point: %+v ", err)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package container // import "github.com/docker/docker/container"
|
|||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
|
@ -14,24 +15,21 @@ import (
|
|||
// the absolute path to the resource relative to the container's rootfs, and
|
||||
// an error if the path points to outside the container's rootfs.
|
||||
func (container *Container) ResolvePath(path string) (resolvedPath, absPath string, err error) {
|
||||
if container.BaseFS == nil {
|
||||
return "", "", errors.New("ResolvePath: BaseFS of container " + container.ID + " is unexpectedly nil")
|
||||
if container.BaseFS == "" {
|
||||
return "", "", errors.New("ResolvePath: BaseFS of container " + container.ID + " is unexpectedly empty")
|
||||
}
|
||||
// Check if a drive letter supplied, it must be the system drive. No-op except on Windows
|
||||
path, err = system.CheckSystemDriveAndRemoveDriveLetter(path, container.BaseFS)
|
||||
path, err = system.CheckSystemDriveAndRemoveDriveLetter(path)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
// Consider the given path as an absolute path in the container.
|
||||
absPath = archive.PreserveTrailingDotOrSeparator(
|
||||
container.BaseFS.Join(string(container.BaseFS.Separator()), path),
|
||||
path,
|
||||
container.BaseFS.Separator())
|
||||
absPath = archive.PreserveTrailingDotOrSeparator(filepath.Join(string(filepath.Separator), path), path)
|
||||
|
||||
// Split the absPath into its Directory and Base components. We will
|
||||
// resolve the dir in the scope of the container then append the base.
|
||||
dirPath, basePath := container.BaseFS.Split(absPath)
|
||||
dirPath, basePath := filepath.Split(absPath)
|
||||
|
||||
resolvedDirPath, err := container.GetResourcePath(dirPath)
|
||||
if err != nil {
|
||||
|
@ -40,7 +38,7 @@ func (container *Container) ResolvePath(path string) (resolvedPath, absPath stri
|
|||
|
||||
// resolvedDirPath will have been cleaned (no trailing path separators) so
|
||||
// we can manually join it with the base path element.
|
||||
resolvedPath = resolvedDirPath + string(container.BaseFS.Separator()) + basePath
|
||||
resolvedPath = resolvedDirPath + string(filepath.Separator) + basePath
|
||||
return resolvedPath, absPath, nil
|
||||
}
|
||||
|
||||
|
@ -49,12 +47,11 @@ func (container *Container) ResolvePath(path string) (resolvedPath, absPath stri
|
|||
// resolved to a path on the host corresponding to the given absolute path
|
||||
// inside the container.
|
||||
func (container *Container) StatPath(resolvedPath, absPath string) (stat *types.ContainerPathStat, err error) {
|
||||
if container.BaseFS == nil {
|
||||
return nil, errors.New("StatPath: BaseFS of container " + container.ID + " is unexpectedly nil")
|
||||
if container.BaseFS == "" {
|
||||
return nil, errors.New("StatPath: BaseFS of container " + container.ID + " is unexpectedly empty")
|
||||
}
|
||||
driver := container.BaseFS
|
||||
|
||||
lstat, err := driver.Lstat(resolvedPath)
|
||||
lstat, err := os.Lstat(resolvedPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -67,17 +64,17 @@ func (container *Container) StatPath(resolvedPath, absPath string) (stat *types.
|
|||
return nil, err
|
||||
}
|
||||
|
||||
linkTarget, err = driver.Rel(driver.Path(), hostPath)
|
||||
linkTarget, err = filepath.Rel(container.BaseFS, hostPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Make it an absolute path.
|
||||
linkTarget = driver.Join(string(driver.Separator()), linkTarget)
|
||||
linkTarget = filepath.Join(string(filepath.Separator), linkTarget)
|
||||
}
|
||||
|
||||
return &types.ContainerPathStat{
|
||||
Name: driver.Base(absPath),
|
||||
Name: filepath.Base(absPath),
|
||||
Size: lstat.Size(),
|
||||
Mode: lstat.Mode(),
|
||||
Mtime: lstat.ModTime(),
|
||||
|
|
|
@ -61,10 +61,10 @@ type ExitStatus struct {
|
|||
type Container struct {
|
||||
StreamConfig *stream.Config
|
||||
// embed for Container to support states directly.
|
||||
*State `json:"State"` // Needed for Engine API version <= 1.11
|
||||
Root string `json:"-"` // Path to the "home" of the container, including metadata.
|
||||
BaseFS containerfs.ContainerFS `json:"-"` // interface containing graphdriver mount
|
||||
RWLayer layer.RWLayer `json:"-"`
|
||||
*State `json:"State"` // Needed for Engine API version <= 1.11
|
||||
Root string `json:"-"` // Path to the "home" of the container, including metadata.
|
||||
BaseFS string `json:"-"` // Path to the graphdriver mountpoint
|
||||
RWLayer layer.RWLayer `json:"-"`
|
||||
ID string
|
||||
Created time.Time
|
||||
Managed bool
|
||||
|
@ -299,18 +299,18 @@ func (container *Container) SetupWorkingDirectory(rootIdentity idtools.Identity)
|
|||
// symlinking to a different path) between using this method and using the
|
||||
// path. See symlink.FollowSymlinkInScope for more details.
|
||||
func (container *Container) GetResourcePath(path string) (string, error) {
|
||||
if container.BaseFS == nil {
|
||||
return "", errors.New("GetResourcePath: BaseFS of container " + container.ID + " is unexpectedly nil")
|
||||
if container.BaseFS == "" {
|
||||
return "", errors.New("GetResourcePath: BaseFS of container " + container.ID + " is unexpectedly empty")
|
||||
}
|
||||
// IMPORTANT - These are paths on the OS where the daemon is running, hence
|
||||
// any filepath operations must be done in an OS agnostic way.
|
||||
r, e := container.BaseFS.ResolveScopedPath(path, false)
|
||||
r, e := containerfs.ResolveScopedPath(container.BaseFS, containerfs.CleanScopedPath(path))
|
||||
|
||||
// Log this here on the daemon side as there's otherwise no indication apart
|
||||
// from the error being propagated all the way back to the client. This makes
|
||||
// debugging significantly easier and clearly indicates the error comes from the daemon.
|
||||
if e != nil {
|
||||
logrus.Errorf("Failed to ResolveScopedPath BaseFS %s path %s %s\n", container.BaseFS.Path(), path, e)
|
||||
logrus.Errorf("Failed to ResolveScopedPath BaseFS %s path %s %s\n", container.BaseFS, path, e)
|
||||
}
|
||||
return r, e
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package daemon // import "github.com/docker/docker/daemon"
|
|||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
|
@ -20,32 +21,6 @@ import (
|
|||
// path does not refer to a directory.
|
||||
var ErrExtractPointNotDirectory = errors.New("extraction point is not a directory")
|
||||
|
||||
// The daemon will use the following interfaces if the container fs implements
|
||||
// these for optimized copies to and from the container.
|
||||
type extractor interface {
|
||||
ExtractArchive(src io.Reader, dst string, opts *archive.TarOptions) error
|
||||
}
|
||||
|
||||
type archiver interface {
|
||||
ArchivePath(src string, opts *archive.TarOptions) (io.ReadCloser, error)
|
||||
}
|
||||
|
||||
// helper functions to extract or archive
|
||||
func extractArchive(i interface{}, src io.Reader, dst string, opts *archive.TarOptions, root string) error {
|
||||
if ea, ok := i.(extractor); ok {
|
||||
return ea.ExtractArchive(src, dst, opts)
|
||||
}
|
||||
|
||||
return chrootarchive.UntarWithRoot(src, dst, opts, root)
|
||||
}
|
||||
|
||||
func archivePath(i interface{}, src string, opts *archive.TarOptions, root string) (io.ReadCloser, error) {
|
||||
if ap, ok := i.(archiver); ok {
|
||||
return ap.ArchivePath(src, opts)
|
||||
}
|
||||
return chrootarchive.Tar(src, opts, root)
|
||||
}
|
||||
|
||||
// ContainerCopy performs a deprecated operation of archiving the resource at
|
||||
// the specified path in the container identified by the given name.
|
||||
func (daemon *Daemon) ContainerCopy(name string, res string) (io.ReadCloser, error) {
|
||||
|
@ -165,7 +140,7 @@ func (daemon *Daemon) containerStatPath(container *container.Container, path str
|
|||
}
|
||||
|
||||
// Normalize path before sending to rootfs
|
||||
path = container.BaseFS.FromSlash(path)
|
||||
path = filepath.FromSlash(path)
|
||||
|
||||
resolvedPath, absPath, err := container.ResolvePath(path)
|
||||
if err != nil {
|
||||
|
@ -208,7 +183,7 @@ func (daemon *Daemon) containerArchivePath(container *container.Container, path
|
|||
}
|
||||
|
||||
// Normalize path before sending to rootfs
|
||||
path = container.BaseFS.FromSlash(path)
|
||||
path = filepath.FromSlash(path)
|
||||
|
||||
resolvedPath, absPath, err := container.ResolvePath(path)
|
||||
if err != nil {
|
||||
|
@ -228,24 +203,23 @@ func (daemon *Daemon) containerArchivePath(container *container.Container, path
|
|||
// also catches the case when the root directory of the container is
|
||||
// requested: we want the archive entries to start with "/" and not the
|
||||
// container ID.
|
||||
driver := container.BaseFS
|
||||
|
||||
// Get the source and the base paths of the container resolved path in order
|
||||
// to get the proper tar options for the rebase tar.
|
||||
resolvedPath = driver.Clean(resolvedPath)
|
||||
if driver.Base(resolvedPath) == "." {
|
||||
resolvedPath += string(driver.Separator()) + "."
|
||||
resolvedPath = filepath.Clean(resolvedPath)
|
||||
if filepath.Base(resolvedPath) == "." {
|
||||
resolvedPath += string(filepath.Separator) + "."
|
||||
}
|
||||
|
||||
sourceDir := resolvedPath
|
||||
sourceBase := "."
|
||||
|
||||
if stat.Mode&os.ModeDir == 0 { // not dir
|
||||
sourceDir, sourceBase = driver.Split(resolvedPath)
|
||||
sourceDir, sourceBase = filepath.Split(resolvedPath)
|
||||
}
|
||||
opts := archive.TarResourceRebaseOpts(sourceBase, driver.Base(absPath))
|
||||
opts := archive.TarResourceRebaseOpts(sourceBase, filepath.Base(absPath))
|
||||
|
||||
data, err := archivePath(driver, sourceDir, opts, container.BaseFS.Path())
|
||||
data, err := chrootarchive.Tar(sourceDir, opts, container.BaseFS)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -285,11 +259,10 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path
|
|||
}
|
||||
|
||||
// Normalize path before sending to rootfs'
|
||||
path = container.BaseFS.FromSlash(path)
|
||||
driver := container.BaseFS
|
||||
path = filepath.FromSlash(path)
|
||||
|
||||
// Check if a drive letter supplied, it must be the system drive. No-op except on Windows
|
||||
path, err = system.CheckSystemDriveAndRemoveDriveLetter(path, driver)
|
||||
path, err = system.CheckSystemDriveAndRemoveDriveLetter(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -301,10 +274,7 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path
|
|||
// that you can extract an archive to a symlink that points to a directory.
|
||||
|
||||
// Consider the given path as an absolute path in the container.
|
||||
absPath := archive.PreserveTrailingDotOrSeparator(
|
||||
driver.Join(string(driver.Separator()), path),
|
||||
path,
|
||||
driver.Separator())
|
||||
absPath := archive.PreserveTrailingDotOrSeparator(filepath.Join(string(filepath.Separator), path), path)
|
||||
|
||||
// This will evaluate the last path element if it is a symlink.
|
||||
resolvedPath, err := container.GetResourcePath(absPath)
|
||||
|
@ -312,7 +282,7 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path
|
|||
return err
|
||||
}
|
||||
|
||||
stat, err := driver.Lstat(resolvedPath)
|
||||
stat, err := os.Lstat(resolvedPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -335,24 +305,21 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path
|
|||
// a volume file path.
|
||||
var baseRel string
|
||||
if strings.HasPrefix(resolvedPath, `\\?\Volume{`) {
|
||||
if strings.HasPrefix(resolvedPath, driver.Path()) {
|
||||
baseRel = resolvedPath[len(driver.Path()):]
|
||||
if strings.HasPrefix(resolvedPath, container.BaseFS) {
|
||||
baseRel = resolvedPath[len(container.BaseFS):]
|
||||
if baseRel[:1] == `\` {
|
||||
baseRel = baseRel[1:]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
baseRel, err = driver.Rel(driver.Path(), resolvedPath)
|
||||
baseRel, err = filepath.Rel(container.BaseFS, resolvedPath)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Make it an absolute path.
|
||||
absPath = driver.Join(string(driver.Separator()), baseRel)
|
||||
absPath = filepath.Join(string(filepath.Separator), baseRel)
|
||||
|
||||
// @ TODO: gupta-ak: Technically, this works since it no-ops
|
||||
// on Windows and the file system is local anyway on linux.
|
||||
// But eventually, it should be made driver aware.
|
||||
toVolume, err := checkIfPathIsInAVolume(container, absPath)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -374,7 +341,7 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path
|
|||
}
|
||||
}
|
||||
|
||||
if err := extractArchive(driver, content, resolvedPath, options, container.BaseFS.Path()); err != nil {
|
||||
if err := chrootarchive.UntarWithRoot(content, resolvedPath, options, container.BaseFS); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -416,27 +383,26 @@ func (daemon *Daemon) containerCopy(container *container.Container, resource str
|
|||
}
|
||||
|
||||
// Normalize path before sending to rootfs
|
||||
resource = container.BaseFS.FromSlash(resource)
|
||||
driver := container.BaseFS
|
||||
resource = filepath.FromSlash(resource)
|
||||
|
||||
basePath, err := container.GetResourcePath(resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stat, err := driver.Stat(basePath)
|
||||
stat, err := os.Stat(basePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var filter []string
|
||||
if !stat.IsDir() {
|
||||
d, f := driver.Split(basePath)
|
||||
d, f := filepath.Split(basePath)
|
||||
basePath = d
|
||||
filter = []string{f}
|
||||
}
|
||||
archv, err := archivePath(driver, basePath, &archive.TarOptions{
|
||||
archv, err := chrootarchive.Tar(basePath, &archive.TarOptions{
|
||||
Compression: archive.Uncompressed,
|
||||
IncludeFiles: filter,
|
||||
}, container.BaseFS.Path())
|
||||
}, container.BaseFS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -1270,7 +1270,7 @@ func (daemon *Daemon) Mount(container *container.Container) error {
|
|||
}
|
||||
logrus.WithField("container", container.ID).Debugf("container mounted via layerStore: %v", dir)
|
||||
|
||||
if container.BaseFS != nil && container.BaseFS.Path() != dir.Path() {
|
||||
if container.BaseFS != "" && container.BaseFS != dir {
|
||||
// The mount path reported by the graph driver should always be trusted on Windows, since the
|
||||
// volume path for a given mounted layer may change over time. This should only be an error
|
||||
// on non-Windows operating systems.
|
||||
|
|
|
@ -38,7 +38,6 @@ import (
|
|||
"github.com/docker/docker/libnetwork/options"
|
||||
lntypes "github.com/docker/docker/libnetwork/types"
|
||||
"github.com/docker/docker/opts"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
"github.com/docker/docker/pkg/parsers/kernel"
|
||||
|
@ -1072,8 +1071,8 @@ func removeDefaultBridgeInterface() {
|
|||
}
|
||||
}
|
||||
|
||||
func setupInitLayer(idMapping idtools.IdentityMapping) func(containerfs.ContainerFS) error {
|
||||
return func(initPath containerfs.ContainerFS) error {
|
||||
func setupInitLayer(idMapping idtools.IdentityMapping) func(string) error {
|
||||
return func(initPath string) error {
|
||||
return initlayer.Setup(initPath, idMapping.RootPair())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ import (
|
|||
winlibnetwork "github.com/docker/docker/libnetwork/drivers/windows"
|
||||
"github.com/docker/docker/libnetwork/netlabel"
|
||||
"github.com/docker/docker/libnetwork/options"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
"github.com/docker/docker/pkg/parsers/operatingsystem"
|
||||
|
@ -64,7 +63,7 @@ func (daemon *Daemon) parseSecurityOpt(container *container.Container, hostConfi
|
|||
return nil
|
||||
}
|
||||
|
||||
func setupInitLayer(idMapping idtools.IdentityMapping) func(containerfs.ContainerFS) error {
|
||||
func setupInitLayer(idMapping idtools.IdentityMapping) func(string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/chrootarchive"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
)
|
||||
|
||||
|
@ -61,10 +62,10 @@ func (daemon *Daemon) containerExport(container *container.Container) (arch io.R
|
|||
return nil, err
|
||||
}
|
||||
|
||||
archv, err := archivePath(basefs, basefs.Path(), &archive.TarOptions{
|
||||
archv, err := chrootarchive.Tar(basefs, &archive.TarOptions{
|
||||
Compression: archive.Uncompressed,
|
||||
IDMap: daemon.idMapping,
|
||||
}, basefs.Path())
|
||||
}, basefs)
|
||||
if err != nil {
|
||||
rwlayer.Unmount()
|
||||
return nil, err
|
||||
|
|
|
@ -351,12 +351,12 @@ func atomicRemove(source string) error {
|
|||
|
||||
// Get returns the rootfs path for the id.
|
||||
// This will mount the dir at its given path
|
||||
func (a *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
|
||||
func (a *Driver) Get(id, mountLabel string) (string, error) {
|
||||
a.locker.Lock(id)
|
||||
defer a.locker.Unlock(id)
|
||||
parents, err := a.getParentLayerPaths(id)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
a.pathCacheLock.Lock()
|
||||
|
@ -370,21 +370,21 @@ func (a *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
|
|||
}
|
||||
}
|
||||
if count := a.ctr.Increment(m); count > 1 {
|
||||
return containerfs.NewLocalContainerFS(m), nil
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// If a dir does not have a parent ( no layers )do not try to mount
|
||||
// just return the diff path to the data
|
||||
if len(parents) > 0 {
|
||||
if err := a.mount(id, m, mountLabel, parents); err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
a.pathCacheLock.Lock()
|
||||
a.pathCache[id] = m
|
||||
a.pathCacheLock.Unlock()
|
||||
return containerfs.NewLocalContainerFS(m), nil
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Put unmounts and updates list of active mounts.
|
||||
|
|
|
@ -43,14 +43,6 @@ func testInit(dir string, t testing.TB) graphdriver.Driver {
|
|||
return d
|
||||
}
|
||||
|
||||
func driverGet(d *Driver, id string, mntLabel string) (string, error) {
|
||||
mnt, err := d.Get(id, mntLabel)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return mnt.Path(), nil
|
||||
}
|
||||
|
||||
func newDriver(t testing.TB) *Driver {
|
||||
if err := os.MkdirAll(tmp, 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -180,7 +172,7 @@ func TestGetWithoutParent(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
expected := path.Join(tmp, "diff", "1")
|
||||
if diffPath.Path() != expected {
|
||||
if diffPath != expected {
|
||||
t.Fatalf("Expected path %s got %s", expected, diffPath)
|
||||
}
|
||||
}
|
||||
|
@ -257,13 +249,13 @@ func TestMountWithParent(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if mntPath == nil {
|
||||
t.Fatal("mntPath should not be nil")
|
||||
if mntPath == "" {
|
||||
t.Fatal("mntPath should not be empty")
|
||||
}
|
||||
|
||||
expected := path.Join(tmp, "mnt", "2")
|
||||
if mntPath.Path() != expected {
|
||||
t.Fatalf("Expected %s got %s", expected, mntPath.Path())
|
||||
if mntPath != expected {
|
||||
t.Fatalf("Expected %s got %s", expected, mntPath)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -288,8 +280,8 @@ func TestRemoveMountedDir(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if mntPath == nil {
|
||||
t.Fatal("mntPath should not be nil")
|
||||
if mntPath == "" {
|
||||
t.Fatal("mntPath should not be empty")
|
||||
}
|
||||
|
||||
mounted, err := d.mounted(d.pathCache["2"])
|
||||
|
@ -323,7 +315,7 @@ func TestGetDiff(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diffPath, err := driverGet(d, "1", "")
|
||||
diffPath, err := d.Get("1", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -367,7 +359,7 @@ func TestChanges(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
mntPoint, err := driverGet(d, "2", "")
|
||||
mntPoint, err := d.Get("2", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -406,7 +398,7 @@ func TestChanges(t *testing.T) {
|
|||
if err := d.CreateReadWrite("3", "2", nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mntPoint, err = driverGet(d, "3", "")
|
||||
mntPoint, err = d.Get("3", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -452,7 +444,7 @@ func TestDiffSize(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diffPath, err := driverGet(d, "1", "")
|
||||
diffPath, err := d.Get("1", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -494,7 +486,7 @@ func TestChildDiffSize(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diffPath, err := driverGet(d, "1", "")
|
||||
diffPath, err := d.Get("1", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -595,7 +587,7 @@ func TestApplyDiff(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diffPath, err := driverGet(d, "1", "")
|
||||
diffPath, err := d.Get("1", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -630,7 +622,7 @@ func TestApplyDiff(t *testing.T) {
|
|||
|
||||
// Ensure that the file is in the mount point for id 3
|
||||
|
||||
mountPoint, err := driverGet(d, "3", "")
|
||||
mountPoint, err := d.Get("3", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -673,7 +665,7 @@ func testMountMoreThan42Layers(t *testing.T, mountPath string) {
|
|||
err := d.CreateReadWrite(current, parent, nil)
|
||||
assert.NilError(t, err, "current layer %d", i)
|
||||
|
||||
point, err := driverGet(d, current, "")
|
||||
point, err := d.Get(current, "")
|
||||
assert.NilError(t, err, "current layer %d", i)
|
||||
|
||||
f, err := os.Create(path.Join(point, current))
|
||||
|
@ -689,7 +681,7 @@ func testMountMoreThan42Layers(t *testing.T, mountPath string) {
|
|||
}
|
||||
|
||||
// Perform the actual mount for the top most image
|
||||
point, err := driverGet(d, last, "")
|
||||
point, err := d.Get(last, "")
|
||||
assert.NilError(t, err)
|
||||
files, err := os.ReadDir(point)
|
||||
assert.NilError(t, err)
|
||||
|
|
|
@ -627,29 +627,29 @@ func (d *Driver) Remove(id string) error {
|
|||
}
|
||||
|
||||
// Get the requested filesystem id.
|
||||
func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
|
||||
func (d *Driver) Get(id, mountLabel string) (string, error) {
|
||||
dir := d.subvolumesDirID(id)
|
||||
st, err := os.Stat(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
if !st.IsDir() {
|
||||
return nil, fmt.Errorf("%s: not a directory", dir)
|
||||
return "", fmt.Errorf("%s: not a directory", dir)
|
||||
}
|
||||
|
||||
if quota, err := os.ReadFile(d.quotasDirID(id)); err == nil {
|
||||
if size, err := strconv.ParseUint(string(quota), 10, 64); err == nil && size >= d.options.minSpace {
|
||||
if err := d.enableQuota(); err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
if err := subvolLimitQgroup(dir, size); err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return containerfs.NewLocalContainerFS(dir), nil
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
// Put is not implemented for BTRFS as there is no cleanup required for the id.
|
||||
|
|
|
@ -36,14 +36,12 @@ func TestBtrfsSubvolDelete(t *testing.T) {
|
|||
}
|
||||
defer graphtest.PutDriver(t)
|
||||
|
||||
dirFS, err := d.Get("test", "")
|
||||
dir, err := d.Get("test", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer d.Put("test")
|
||||
|
||||
dir := dirFS.Path()
|
||||
|
||||
if err := subvolCreate(dir, "subvoltest"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"strconv"
|
||||
|
||||
"github.com/docker/docker/daemon/graphdriver"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/pkg/devicemapper"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
units "github.com/docker/go-units"
|
||||
|
@ -175,13 +174,13 @@ func (d *Driver) Remove(id string) error {
|
|||
}
|
||||
|
||||
// Get mounts a device with given id into the root filesystem
|
||||
func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
|
||||
func (d *Driver) Get(id, mountLabel string) (string, error) {
|
||||
d.locker.Lock(id)
|
||||
defer d.locker.Unlock(id)
|
||||
mp := path.Join(d.home, "mnt", id)
|
||||
rootFs := path.Join(mp, "rootfs")
|
||||
if count := d.ctr.Increment(mp); count > 1 {
|
||||
return containerfs.NewLocalContainerFS(rootFs), nil
|
||||
return rootFs, nil
|
||||
}
|
||||
|
||||
root := d.idMap.RootPair()
|
||||
|
@ -189,23 +188,23 @@ func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
|
|||
// Create the target directories if they don't exist
|
||||
if err := idtools.MkdirAllAndChown(path.Join(d.home, "mnt"), 0755, root); err != nil {
|
||||
d.ctr.Decrement(mp)
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
if err := idtools.MkdirAndChown(mp, 0755, root); err != nil && !os.IsExist(err) {
|
||||
d.ctr.Decrement(mp)
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Mount the device
|
||||
if err := d.DeviceSet.MountDevice(id, mp, mountLabel); err != nil {
|
||||
d.ctr.Decrement(mp)
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := idtools.MkdirAllAndChown(rootFs, 0755, root); err != nil {
|
||||
d.ctr.Decrement(mp)
|
||||
d.DeviceSet.UnmountDevice(id, mp)
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
idFile := path.Join(mp, "id")
|
||||
|
@ -215,11 +214,11 @@ func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
|
|||
if err := os.WriteFile(idFile, []byte(id), 0600); err != nil {
|
||||
d.ctr.Decrement(mp)
|
||||
d.DeviceSet.UnmountDevice(id, mp)
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
return containerfs.NewLocalContainerFS(rootFs), nil
|
||||
return rootFs, nil
|
||||
}
|
||||
|
||||
// Put unmounts a device and removes it.
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/plugingetter"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -60,7 +59,7 @@ type ProtoDriver interface {
|
|||
// Get returns the mountpoint for the layered filesystem referred
|
||||
// to by this id. You can optionally specify a mountLabel or "".
|
||||
// Returns the absolute path to the mounted layered filesystem.
|
||||
Get(id, mountLabel string) (fs containerfs.ContainerFS, err error)
|
||||
Get(id, mountLabel string) (fs string, err error)
|
||||
// Put releases the system resources for the specified id,
|
||||
// e.g, unmounting layered filesystem.
|
||||
Put(id string) error
|
||||
|
|
|
@ -50,7 +50,7 @@ func (gdw *NaiveDiffDriver) Diff(id, parent string) (arch io.ReadCloser, err err
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
layerFs := layerRootFs.Path()
|
||||
layerFs := layerRootFs
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
|
@ -70,14 +70,12 @@ func (gdw *NaiveDiffDriver) Diff(id, parent string) (arch io.ReadCloser, err err
|
|||
}), nil
|
||||
}
|
||||
|
||||
parentRootFs, err := driver.Get(parent, "")
|
||||
parentFs, err := driver.Get(parent, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer driver.Put(parent)
|
||||
|
||||
parentFs := parentRootFs.Path()
|
||||
|
||||
changes, err := archive.ChangesDirs(layerFs, parentFs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -106,22 +104,20 @@ func (gdw *NaiveDiffDriver) Diff(id, parent string) (arch io.ReadCloser, err err
|
|||
func (gdw *NaiveDiffDriver) Changes(id, parent string) ([]archive.Change, error) {
|
||||
driver := gdw.ProtoDriver
|
||||
|
||||
layerRootFs, err := driver.Get(id, "")
|
||||
layerFs, err := driver.Get(id, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer driver.Put(id)
|
||||
|
||||
layerFs := layerRootFs.Path()
|
||||
parentFs := ""
|
||||
|
||||
if parent != "" {
|
||||
parentRootFs, err := driver.Get(parent, "")
|
||||
parentFs, err = driver.Get(parent, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer driver.Put(parent)
|
||||
parentFs = parentRootFs.Path()
|
||||
}
|
||||
|
||||
return archive.ChangesDirs(layerFs, parentFs)
|
||||
|
@ -140,7 +136,7 @@ func (gdw *NaiveDiffDriver) ApplyDiff(id, parent string, diff io.Reader) (size i
|
|||
}
|
||||
defer driver.Put(id)
|
||||
|
||||
layerFs := layerRootFs.Path()
|
||||
layerFs := layerRootFs
|
||||
options := &archive.TarOptions{IDMap: gdw.idMap}
|
||||
start := time.Now().UTC()
|
||||
logrus.WithField("id", id).Debug("Start untar layer")
|
||||
|
@ -169,5 +165,5 @@ func (gdw *NaiveDiffDriver) DiffSize(id, parent string) (size int64, err error)
|
|||
}
|
||||
defer driver.Put(id)
|
||||
|
||||
return archive.ChangesSize(layerFs.Path(), changes), nil
|
||||
return archive.ChangesSize(layerFs, changes), nil
|
||||
}
|
||||
|
|
|
@ -303,12 +303,12 @@ func (d *Driver) Remove(id string) error {
|
|||
}
|
||||
|
||||
// Get creates and mounts the required file system for the given id and returns the mount path.
|
||||
func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr error) {
|
||||
func (d *Driver) Get(id, mountLabel string) (_ string, retErr error) {
|
||||
d.locker.Lock(id)
|
||||
defer d.locker.Unlock(id)
|
||||
dir := d.dir(id)
|
||||
if _, err := os.Stat(dir); err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
diffDir := path.Join(dir, diffDirName)
|
||||
|
@ -316,14 +316,14 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
|
|||
if err != nil {
|
||||
// If no lower, just return diff directory
|
||||
if os.IsNotExist(err) {
|
||||
return containerfs.NewLocalContainerFS(diffDir), nil
|
||||
return diffDir, nil
|
||||
}
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
mergedDir := path.Join(dir, mergedDirName)
|
||||
if count := d.ctr.Increment(mergedDir); count > 1 {
|
||||
return containerfs.NewLocalContainerFS(mergedDir), nil
|
||||
return mergedDir, nil
|
||||
}
|
||||
defer func() {
|
||||
if retErr != nil {
|
||||
|
@ -351,7 +351,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
|
|||
if _, err := os.Stat(path.Join(dir, "committed")); err == nil {
|
||||
readonly = true
|
||||
} else if !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
var opts string
|
||||
|
@ -365,7 +365,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
|
|||
mountTarget := mergedDir
|
||||
|
||||
if err := idtools.MkdirAndChown(mergedDir, 0700, d.idMap.RootPair()); err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
mountProgram := exec.Command(binary, "-o", mountData, mountTarget)
|
||||
|
@ -377,10 +377,10 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
|
|||
if output == "" {
|
||||
output = "<stderr empty>"
|
||||
}
|
||||
return nil, errors.Wrapf(err, "using mount program %s: %s", binary, output)
|
||||
return "", errors.Wrapf(err, "using mount program %s: %s", binary, output)
|
||||
}
|
||||
|
||||
return containerfs.NewLocalContainerFS(mergedDir), nil
|
||||
return mergedDir, nil
|
||||
}
|
||||
|
||||
// Put unmounts the mount path created for the give id.
|
||||
|
|
|
@ -5,9 +5,10 @@ package graphtest // import "github.com/docker/docker/daemon/graphdriver/graphte
|
|||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
contdriver "github.com/containerd/continuity/driver"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
@ -249,7 +250,7 @@ func DriverBenchDeepLayerRead(b *testing.B, layerCount int, drivername string, d
|
|||
for i := 0; i < b.N; i++ {
|
||||
|
||||
// Read content
|
||||
c, err := contdriver.ReadFile(root, root.Join(root.Path(), "testfile.txt"))
|
||||
c, err := os.ReadFile(filepath.Join(root, "testfile.txt"))
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -96,10 +96,10 @@ func DriverTestCreateEmpty(t testing.TB, drivername string, driverOptions ...str
|
|||
dir, err := driver.Get("empty", "")
|
||||
assert.NilError(t, err)
|
||||
|
||||
verifyFile(t, dir.Path(), 0755|os.ModeDir, 0, 0)
|
||||
verifyFile(t, dir, 0755|os.ModeDir, 0, 0)
|
||||
|
||||
// Verify that the directory is empty
|
||||
fis, err := readDir(dir, dir.Path())
|
||||
fis, err := readDir(dir)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Len(fis, 0))
|
||||
|
||||
|
@ -324,19 +324,19 @@ func DriverTestSetQuota(t *testing.T, drivername string, required bool) {
|
|||
quota := uint64(50 * units.MiB)
|
||||
|
||||
// Try to write a file smaller than quota, and ensure it works
|
||||
err = writeRandomFile(path.Join(mountPath.Path(), "smallfile"), quota/2)
|
||||
err = writeRandomFile(path.Join(mountPath, "smallfile"), quota/2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(path.Join(mountPath.Path(), "smallfile"))
|
||||
defer os.Remove(path.Join(mountPath, "smallfile"))
|
||||
|
||||
// Try to write a file bigger than quota. We've already filled up half the quota, so hitting the limit should be easy
|
||||
err = writeRandomFile(path.Join(mountPath.Path(), "bigfile"), quota)
|
||||
err = writeRandomFile(path.Join(mountPath, "bigfile"), quota)
|
||||
if err == nil {
|
||||
t.Fatalf("expected write to fail(), instead had success")
|
||||
}
|
||||
if pathError, ok := err.(*os.PathError); ok && pathError.Err != unix.EDQUOT && pathError.Err != unix.ENOSPC {
|
||||
os.Remove(path.Join(mountPath.Path(), "bigfile"))
|
||||
os.Remove(path.Join(mountPath, "bigfile"))
|
||||
t.Fatalf("expect write() to fail with %v or %v, got %v", unix.EDQUOT, unix.ENOSPC, pathError.Err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,12 @@ package graphtest // import "github.com/docker/docker/daemon/graphdriver/graphte
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
||||
"github.com/containerd/continuity/driver"
|
||||
"github.com/docker/docker/daemon/graphdriver"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
|
@ -35,17 +36,17 @@ func addFiles(drv graphdriver.Driver, layer string, seed int64) error {
|
|||
}
|
||||
defer drv.Put(layer)
|
||||
|
||||
if err := driver.WriteFile(root, root.Join(root.Path(), "file-a"), randomContent(64, seed), 0755); err != nil {
|
||||
if err := os.WriteFile(filepath.Join(root, "file-a"), randomContent(64, seed), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := root.MkdirAll(root.Join(root.Path(), "dir-b"), 0755); err != nil {
|
||||
if err := os.MkdirAll(filepath.Join(root, "dir-b"), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := driver.WriteFile(root, root.Join(root.Path(), "dir-b", "file-b"), randomContent(128, seed+1), 0755); err != nil {
|
||||
if err := os.WriteFile(filepath.Join(root, "dir-b", "file-b"), randomContent(128, seed+1), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return driver.WriteFile(root, root.Join(root.Path(), "file-c"), randomContent(128*128, seed+2), 0755)
|
||||
return os.WriteFile(filepath.Join(root, "file-c"), randomContent(128*128, seed+2), 0755)
|
||||
}
|
||||
|
||||
func checkFile(drv graphdriver.Driver, layer, filename string, content []byte) error {
|
||||
|
@ -55,7 +56,7 @@ func checkFile(drv graphdriver.Driver, layer, filename string, content []byte) e
|
|||
}
|
||||
defer drv.Put(layer)
|
||||
|
||||
fileContent, err := driver.ReadFile(root, root.Join(root.Path(), filename))
|
||||
fileContent, err := os.ReadFile(filepath.Join(root, filename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -74,7 +75,7 @@ func addFile(drv graphdriver.Driver, layer, filename string, content []byte) err
|
|||
}
|
||||
defer drv.Put(layer)
|
||||
|
||||
return driver.WriteFile(root, root.Join(root.Path(), filename), content, 0755)
|
||||
return os.WriteFile(filepath.Join(root, filename), content, 0755)
|
||||
}
|
||||
|
||||
func addDirectory(drv graphdriver.Driver, layer, dir string) error {
|
||||
|
@ -84,7 +85,7 @@ func addDirectory(drv graphdriver.Driver, layer, dir string) error {
|
|||
}
|
||||
defer drv.Put(layer)
|
||||
|
||||
return root.MkdirAll(root.Join(root.Path(), dir), 0755)
|
||||
return os.MkdirAll(filepath.Join(root, dir), 0755)
|
||||
}
|
||||
|
||||
func removeAll(drv graphdriver.Driver, layer string, names ...string) error {
|
||||
|
@ -95,7 +96,7 @@ func removeAll(drv graphdriver.Driver, layer string, names ...string) error {
|
|||
defer drv.Put(layer)
|
||||
|
||||
for _, filename := range names {
|
||||
if err := root.RemoveAll(root.Join(root.Path(), filename)); err != nil {
|
||||
if err := os.RemoveAll(filepath.Join(root, filename)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -109,8 +110,8 @@ func checkFileRemoved(drv graphdriver.Driver, layer, filename string) error {
|
|||
}
|
||||
defer drv.Put(layer)
|
||||
|
||||
if _, err := root.Stat(root.Join(root.Path(), filename)); err == nil {
|
||||
return fmt.Errorf("file still exists: %s", root.Join(root.Path(), filename))
|
||||
if _, err := os.Stat(filepath.Join(root, filename)); err == nil {
|
||||
return fmt.Errorf("file still exists: %s", filepath.Join(root, filename))
|
||||
} else if !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
@ -126,13 +127,13 @@ func addManyFiles(drv graphdriver.Driver, layer string, count int, seed int64) e
|
|||
defer drv.Put(layer)
|
||||
|
||||
for i := 0; i < count; i += 100 {
|
||||
dir := root.Join(root.Path(), fmt.Sprintf("directory-%d", i))
|
||||
if err := root.MkdirAll(dir, 0755); err != nil {
|
||||
dir := filepath.Join(root, fmt.Sprintf("directory-%d", i))
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
for j := 0; i+j < count && j < 100; j++ {
|
||||
file := root.Join(dir, fmt.Sprintf("file-%d", i+j))
|
||||
if err := driver.WriteFile(root, file, randomContent(64, seed+int64(i+j)), 0755); err != nil {
|
||||
file := filepath.Join(dir, fmt.Sprintf("file-%d", i+j))
|
||||
if err := os.WriteFile(file, randomContent(64, seed+int64(i+j)), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -151,7 +152,7 @@ func changeManyFiles(drv graphdriver.Driver, layer string, count int, seed int64
|
|||
var changes []archive.Change
|
||||
for i := 0; i < count; i += 100 {
|
||||
archiveRoot := fmt.Sprintf("/directory-%d", i)
|
||||
if err := root.MkdirAll(root.Join(root.Path(), archiveRoot), 0755); err != nil {
|
||||
if err := os.MkdirAll(filepath.Join(root, archiveRoot), 0755); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for j := 0; i+j < count && j < 100; j++ {
|
||||
|
@ -165,23 +166,23 @@ func changeManyFiles(drv graphdriver.Driver, layer string, count int, seed int64
|
|||
switch j % 3 {
|
||||
// Update file
|
||||
case 0:
|
||||
change.Path = root.Join(archiveRoot, fmt.Sprintf("file-%d", i+j))
|
||||
change.Path = filepath.Join(archiveRoot, fmt.Sprintf("file-%d", i+j))
|
||||
change.Kind = archive.ChangeModify
|
||||
if err := driver.WriteFile(root, root.Join(root.Path(), change.Path), randomContent(64, seed+int64(i+j)), 0755); err != nil {
|
||||
if err := os.WriteFile(filepath.Join(root, change.Path), randomContent(64, seed+int64(i+j)), 0755); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Add file
|
||||
case 1:
|
||||
change.Path = root.Join(archiveRoot, fmt.Sprintf("file-%d-%d", seed, i+j))
|
||||
change.Path = filepath.Join(archiveRoot, fmt.Sprintf("file-%d-%d", seed, i+j))
|
||||
change.Kind = archive.ChangeAdd
|
||||
if err := driver.WriteFile(root, root.Join(root.Path(), change.Path), randomContent(64, seed+int64(i+j)), 0755); err != nil {
|
||||
if err := os.WriteFile(filepath.Join(root, change.Path), randomContent(64, seed+int64(i+j)), 0755); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Remove file
|
||||
case 2:
|
||||
change.Path = root.Join(archiveRoot, fmt.Sprintf("file-%d", i+j))
|
||||
change.Path = filepath.Join(archiveRoot, fmt.Sprintf("file-%d", i+j))
|
||||
change.Kind = archive.ChangeDelete
|
||||
if err := root.Remove(root.Join(root.Path(), change.Path)); err != nil {
|
||||
if err := os.Remove(filepath.Join(root, change.Path)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
@ -200,10 +201,10 @@ func checkManyFiles(drv graphdriver.Driver, layer string, count int, seed int64)
|
|||
defer drv.Put(layer)
|
||||
|
||||
for i := 0; i < count; i += 100 {
|
||||
dir := root.Join(root.Path(), fmt.Sprintf("directory-%d", i))
|
||||
dir := filepath.Join(root, fmt.Sprintf("directory-%d", i))
|
||||
for j := 0; i+j < count && j < 100; j++ {
|
||||
file := root.Join(dir, fmt.Sprintf("file-%d", i+j))
|
||||
fileContent, err := driver.ReadFile(root, file)
|
||||
file := filepath.Join(dir, fmt.Sprintf("file-%d", i+j))
|
||||
fileContent, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -253,17 +254,17 @@ func addLayerFiles(drv graphdriver.Driver, layer, parent string, i int) error {
|
|||
}
|
||||
defer drv.Put(layer)
|
||||
|
||||
if err := driver.WriteFile(root, root.Join(root.Path(), "top-id"), []byte(layer), 0755); err != nil {
|
||||
if err := os.WriteFile(filepath.Join(root, "top-id"), []byte(layer), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
layerDir := root.Join(root.Path(), fmt.Sprintf("layer-%d", i))
|
||||
if err := root.MkdirAll(layerDir, 0755); err != nil {
|
||||
layerDir := filepath.Join(root, fmt.Sprintf("layer-%d", i))
|
||||
if err := os.MkdirAll(layerDir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := driver.WriteFile(root, root.Join(layerDir, "layer-id"), []byte(layer), 0755); err != nil {
|
||||
if err := os.WriteFile(filepath.Join(layerDir, "layer-id"), []byte(layer), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
return driver.WriteFile(root, root.Join(layerDir, "parent-id"), []byte(parent), 0755)
|
||||
return os.WriteFile(filepath.Join(layerDir, "parent-id"), []byte(parent), 0755)
|
||||
}
|
||||
|
||||
func addManyLayers(drv graphdriver.Driver, baseLayer string, count int) (string, error) {
|
||||
|
@ -290,7 +291,7 @@ func checkManyLayers(drv graphdriver.Driver, layer string, count int) error {
|
|||
}
|
||||
defer drv.Put(layer)
|
||||
|
||||
layerIDBytes, err := driver.ReadFile(root, root.Join(root.Path(), "top-id"))
|
||||
layerIDBytes, err := os.ReadFile(filepath.Join(root, "top-id"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -300,16 +301,16 @@ func checkManyLayers(drv graphdriver.Driver, layer string, count int) error {
|
|||
}
|
||||
|
||||
for i := count; i > 0; i-- {
|
||||
layerDir := root.Join(root.Path(), fmt.Sprintf("layer-%d", i))
|
||||
layerDir := filepath.Join(root, fmt.Sprintf("layer-%d", i))
|
||||
|
||||
thisLayerIDBytes, err := driver.ReadFile(root, root.Join(layerDir, "layer-id"))
|
||||
thisLayerIDBytes, err := os.ReadFile(filepath.Join(layerDir, "layer-id"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(thisLayerIDBytes, layerIDBytes) {
|
||||
return fmt.Errorf("mismatched file content %v, expecting %v", thisLayerIDBytes, layerIDBytes)
|
||||
}
|
||||
layerIDBytes, err = driver.ReadFile(root, root.Join(layerDir, "parent-id"))
|
||||
layerIDBytes, err = os.ReadFile(filepath.Join(layerDir, "parent-id"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -317,11 +318,11 @@ func checkManyLayers(drv graphdriver.Driver, layer string, count int) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// readDir reads a directory just like driver.ReadDir()
|
||||
// readDir reads a directory just like os.ReadDir()
|
||||
// then hides specific files (currently "lost+found")
|
||||
// so the tests don't "see" it
|
||||
func readDir(r driver.Driver, dir string) ([]os.FileInfo, error) {
|
||||
a, err := driver.ReadDir(r, dir)
|
||||
func readDir(dir string) ([]fs.DirEntry, error) {
|
||||
a, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ package graphtest // import "github.com/docker/docker/daemon/graphdriver/graphte
|
|||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
|
@ -44,12 +45,12 @@ func createBase(t testing.TB, driver graphdriver.Driver, name string) {
|
|||
assert.NilError(t, err)
|
||||
defer driver.Put(name)
|
||||
|
||||
subdir := dirFS.Join(dirFS.Path(), "a subdir")
|
||||
assert.NilError(t, dirFS.Mkdir(subdir, 0705|os.ModeSticky))
|
||||
assert.NilError(t, dirFS.Lchown(subdir, 1, 2))
|
||||
subdir := filepath.Join(dirFS, "a subdir")
|
||||
assert.NilError(t, os.Mkdir(subdir, 0705|os.ModeSticky))
|
||||
assert.NilError(t, contdriver.LocalDriver.Lchown(subdir, 1, 2))
|
||||
|
||||
file := dirFS.Join(dirFS.Path(), "a file")
|
||||
err = contdriver.WriteFile(dirFS, file, []byte("Some data"), 0222|os.ModeSetuid)
|
||||
file := filepath.Join(dirFS, "a file")
|
||||
err = os.WriteFile(file, []byte("Some data"), 0222|os.ModeSetuid)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
|
@ -58,13 +59,13 @@ func verifyBase(t testing.TB, driver graphdriver.Driver, name string) {
|
|||
assert.NilError(t, err)
|
||||
defer driver.Put(name)
|
||||
|
||||
subdir := dirFS.Join(dirFS.Path(), "a subdir")
|
||||
subdir := filepath.Join(dirFS, "a subdir")
|
||||
verifyFile(t, subdir, 0705|os.ModeDir|os.ModeSticky, 1, 2)
|
||||
|
||||
file := dirFS.Join(dirFS.Path(), "a file")
|
||||
file := filepath.Join(dirFS, "a file")
|
||||
verifyFile(t, file, 0222|os.ModeSetuid, 0, 0)
|
||||
|
||||
files, err := readDir(dirFS, dirFS.Path())
|
||||
files, err := readDir(dirFS)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Len(files, 2))
|
||||
}
|
||||
|
|
|
@ -339,22 +339,22 @@ func (d *Driver) Remove(id string) error {
|
|||
}
|
||||
|
||||
// Get creates and mounts the required file system for the given id and returns the mount path.
|
||||
func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, err error) {
|
||||
func (d *Driver) Get(id, mountLabel string) (_ string, err error) {
|
||||
d.locker.Lock(id)
|
||||
defer d.locker.Unlock(id)
|
||||
dir := d.dir(id)
|
||||
if _, err := os.Stat(dir); err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
// If id has a root, just return it
|
||||
rootDir := path.Join(dir, "root")
|
||||
if _, err := os.Stat(rootDir); err == nil {
|
||||
return containerfs.NewLocalContainerFS(rootDir), nil
|
||||
return rootDir, nil
|
||||
}
|
||||
|
||||
mergedDir := path.Join(dir, "merged")
|
||||
if count := d.ctr.Increment(mergedDir); count > 1 {
|
||||
return containerfs.NewLocalContainerFS(mergedDir), nil
|
||||
return mergedDir, nil
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
|
@ -371,11 +371,11 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, err erro
|
|||
}()
|
||||
lowerID, err := os.ReadFile(path.Join(dir, "lower-id"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
root := d.idMap.RootPair()
|
||||
if err := idtools.MkdirAndChown(mergedDir, 0700, root); err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
var (
|
||||
lowerDir = path.Join(d.dir(string(lowerID)), "root")
|
||||
|
@ -384,14 +384,14 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, err erro
|
|||
opts = fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lowerDir, upperDir, workDir)
|
||||
)
|
||||
if err := unix.Mount("overlay", mergedDir, "overlay", 0, label.FormatMountLabel(opts, mountLabel)); err != nil {
|
||||
return nil, fmt.Errorf("error creating overlay mount to %s: %v", mergedDir, err)
|
||||
return "", fmt.Errorf("error creating overlay mount to %s: %v", mergedDir, err)
|
||||
}
|
||||
// chown "workdir/work" to the remapped root UID/GID. Overlay fs inside a
|
||||
// user namespace requires this to move a directory from lower to upper.
|
||||
if err := root.Chown(path.Join(workDir, "work")); err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
return containerfs.NewLocalContainerFS(mergedDir), nil
|
||||
return mergedDir, nil
|
||||
}
|
||||
|
||||
// Put unmounts the mount path created for the give id.
|
||||
|
|
|
@ -513,12 +513,12 @@ func (d *Driver) Remove(id string) error {
|
|||
}
|
||||
|
||||
// Get creates and mounts the required file system for the given id and returns the mount path.
|
||||
func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr error) {
|
||||
func (d *Driver) Get(id, mountLabel string) (_ string, retErr error) {
|
||||
d.locker.Lock(id)
|
||||
defer d.locker.Unlock(id)
|
||||
dir := d.dir(id)
|
||||
if _, err := os.Stat(dir); err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
diffDir := path.Join(dir, diffDirName)
|
||||
|
@ -526,14 +526,14 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
|
|||
if err != nil {
|
||||
// If no lower, just return diff directory
|
||||
if os.IsNotExist(err) {
|
||||
return containerfs.NewLocalContainerFS(diffDir), nil
|
||||
return diffDir, nil
|
||||
}
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
mergedDir := path.Join(dir, mergedDirName)
|
||||
if count := d.ctr.Increment(mergedDir); count > 1 {
|
||||
return containerfs.NewLocalContainerFS(mergedDir), nil
|
||||
return mergedDir, nil
|
||||
}
|
||||
defer func() {
|
||||
if retErr != nil {
|
||||
|
@ -559,7 +559,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
|
|||
if _, err := os.Stat(path.Join(dir, "committed")); err == nil {
|
||||
readonly = true
|
||||
} else if !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
var opts string
|
||||
|
@ -575,7 +575,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
|
|||
|
||||
root := d.idMap.RootPair()
|
||||
if err := idtools.MkdirAndChown(mergedDir, 0700, root); err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
pageSize := unix.Getpagesize()
|
||||
|
@ -592,7 +592,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
|
|||
}
|
||||
mountData = label.FormatMountLabel(opts, mountLabel)
|
||||
if len(mountData) > pageSize-1 {
|
||||
return nil, fmt.Errorf("cannot mount layer, mount label too large %d", len(mountData))
|
||||
return "", fmt.Errorf("cannot mount layer, mount label too large %d", len(mountData))
|
||||
}
|
||||
|
||||
mount = func(source string, target string, mType string, flags uintptr, label string) error {
|
||||
|
@ -602,18 +602,18 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
|
|||
}
|
||||
|
||||
if err := mount("overlay", mountTarget, "overlay", 0, mountData); err != nil {
|
||||
return nil, fmt.Errorf("error creating overlay mount to %s: %v", mergedDir, err)
|
||||
return "", fmt.Errorf("error creating overlay mount to %s: %v", mergedDir, err)
|
||||
}
|
||||
|
||||
if !readonly {
|
||||
// chown "workdir/work" to the remapped root UID/GID. Overlay fs inside a
|
||||
// user namespace requires this to move a directory from lower to upper.
|
||||
if err := root.Chown(path.Join(workDir, workDirName)); err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
return containerfs.NewLocalContainerFS(mergedDir), nil
|
||||
return mergedDir, nil
|
||||
}
|
||||
|
||||
// Put unmounts the mount path created for the give id.
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"io"
|
||||
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/plugingetter"
|
||||
"github.com/docker/docker/pkg/plugins"
|
||||
|
@ -128,20 +127,20 @@ func (d *graphDriverProxy) Remove(id string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *graphDriverProxy) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
|
||||
func (d *graphDriverProxy) Get(id, mountLabel string) (string, error) {
|
||||
args := &graphDriverRequest{
|
||||
ID: id,
|
||||
MountLabel: mountLabel,
|
||||
}
|
||||
var ret graphDriverResponse
|
||||
if err := d.client.Call("GraphDriver.Get", args, &ret); err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
var err error
|
||||
if ret.Err != "" {
|
||||
err = errors.New(ret.Err)
|
||||
}
|
||||
return containerfs.NewLocalContainerFS(d.p.ScopedPath(ret.Dir)), err
|
||||
return d.p.ScopedPath(ret.Dir), err
|
||||
}
|
||||
|
||||
func (d *graphDriverProxy) Put(id string) error {
|
||||
|
|
|
@ -172,7 +172,7 @@ func (d *Driver) create(id, parent string, size uint64) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("%s: %s", parent, err)
|
||||
}
|
||||
return CopyDir(parentDir.Path(), dir)
|
||||
return CopyDir(parentDir, dir)
|
||||
}
|
||||
|
||||
func (d *Driver) dir(id string) string {
|
||||
|
@ -185,14 +185,14 @@ func (d *Driver) Remove(id string) error {
|
|||
}
|
||||
|
||||
// Get returns the directory for the given id.
|
||||
func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
|
||||
func (d *Driver) Get(id, mountLabel string) (string, error) {
|
||||
dir := d.dir(id)
|
||||
if st, err := os.Stat(dir); err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
} else if !st.IsDir() {
|
||||
return nil, fmt.Errorf("%s: not a directory", dir)
|
||||
return "", fmt.Errorf("%s: not a directory", dir)
|
||||
}
|
||||
return containerfs.NewLocalContainerFS(dir), nil
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
// Put is a noop for vfs that return nil for the error, since this driver has no runtime resources to clean up.
|
||||
|
|
|
@ -27,7 +27,6 @@ import (
|
|||
"github.com/Microsoft/hcsshim/osversion"
|
||||
"github.com/docker/docker/daemon/graphdriver"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/longpath"
|
||||
|
@ -393,35 +392,35 @@ func (d *Driver) GetLayerPath(id string) (string, error) {
|
|||
}
|
||||
|
||||
// Get returns the rootfs path for the id. This will mount the dir at its given path.
|
||||
func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
|
||||
func (d *Driver) Get(id, mountLabel string) (string, error) {
|
||||
logrus.Debugf("WindowsGraphDriver Get() id %s mountLabel %s", id, mountLabel)
|
||||
var dir string
|
||||
|
||||
rID, err := d.resolveID(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
if count := d.ctr.Increment(rID); count > 1 {
|
||||
return containerfs.NewLocalContainerFS(d.cache[rID]), nil
|
||||
return d.cache[rID], nil
|
||||
}
|
||||
|
||||
// Getting the layer paths must be done outside of the lock.
|
||||
layerChain, err := d.getLayerChain(rID)
|
||||
if err != nil {
|
||||
d.ctr.Decrement(rID)
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := hcsshim.ActivateLayer(d.info, rID); err != nil {
|
||||
d.ctr.Decrement(rID)
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
if err := hcsshim.PrepareLayer(d.info, rID, layerChain); err != nil {
|
||||
d.ctr.Decrement(rID)
|
||||
if err2 := hcsshim.DeactivateLayer(d.info, rID); err2 != nil {
|
||||
logrus.Warnf("Failed to Deactivate %s: %s", id, err)
|
||||
}
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
mountPath, err := hcsshim.GetLayerMountPath(d.info, rID)
|
||||
|
@ -433,7 +432,7 @@ func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
|
|||
if err2 := hcsshim.DeactivateLayer(d.info, rID); err2 != nil {
|
||||
logrus.Warnf("Failed to Deactivate %s: %s", id, err)
|
||||
}
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
d.cacheMu.Lock()
|
||||
d.cache[rID] = mountPath
|
||||
|
@ -447,7 +446,7 @@ func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
|
|||
dir = d.dir(id)
|
||||
}
|
||||
|
||||
return containerfs.NewLocalContainerFS(dir), nil
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
// Put adds a new layer to the driver.
|
||||
|
@ -651,7 +650,7 @@ func (d *Driver) DiffSize(id, parent string) (size int64, err error) {
|
|||
}
|
||||
defer d.Put(id)
|
||||
|
||||
return archive.ChangesSize(layerFs.Path(), changes), nil
|
||||
return archive.ChangesSize(layerFs, changes), nil
|
||||
}
|
||||
|
||||
// GetMetadata returns custom driver information.
|
||||
|
|
|
@ -14,7 +14,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/docker/daemon/graphdriver"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
zfs "github.com/mistifyio/go-zfs"
|
||||
|
@ -363,12 +362,12 @@ func (d *Driver) Remove(id string) error {
|
|||
}
|
||||
|
||||
// Get returns the mountpoint for the given id after creating the target directories if necessary.
|
||||
func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr error) {
|
||||
func (d *Driver) Get(id, mountLabel string) (_ string, retErr error) {
|
||||
d.locker.Lock(id)
|
||||
defer d.locker.Unlock(id)
|
||||
mountpoint := d.mountPath(id)
|
||||
if count := d.ctr.Increment(mountpoint); count > 1 {
|
||||
return containerfs.NewLocalContainerFS(mountpoint), nil
|
||||
return mountpoint, nil
|
||||
}
|
||||
defer func() {
|
||||
if retErr != nil {
|
||||
|
@ -391,20 +390,20 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
|
|||
root := d.idMap.RootPair()
|
||||
// Create the target directories if they don't exist
|
||||
if err := idtools.MkdirAllAndChown(mountpoint, 0755, root); err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := mount.Mount(filesystem, mountpoint, "zfs", options); err != nil {
|
||||
return nil, errors.Wrap(err, "error creating zfs mount")
|
||||
return "", errors.Wrap(err, "error creating zfs mount")
|
||||
}
|
||||
|
||||
// this could be our first mount after creation of the filesystem, and the root dir may still have root
|
||||
// permissions instead of the remapped root uid:gid (if user namespaces are enabled):
|
||||
if err := root.Chown(mountpoint); err != nil {
|
||||
return nil, fmt.Errorf("error modifying zfs mountpoint (%s) directory ownership: %v", mountpoint, err)
|
||||
return "", fmt.Errorf("error modifying zfs mountpoint (%s) directory ownership: %v", mountpoint, err)
|
||||
}
|
||||
|
||||
return containerfs.NewLocalContainerFS(mountpoint), nil
|
||||
return mountpoint, nil
|
||||
}
|
||||
|
||||
// Put removes the existing mountpoint for the given id if it exists.
|
||||
|
|
|
@ -14,7 +14,6 @@ import (
|
|||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
|
@ -83,10 +82,10 @@ type rwLayer struct {
|
|||
released bool
|
||||
layerStore layer.Store
|
||||
rwLayer layer.RWLayer
|
||||
fs containerfs.ContainerFS
|
||||
fs string
|
||||
}
|
||||
|
||||
func (l *rwLayer) Root() containerfs.ContainerFS {
|
||||
func (l *rwLayer) Root() string {
|
||||
return l.fs
|
||||
}
|
||||
|
||||
|
@ -115,11 +114,11 @@ func (l *rwLayer) Release() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
if l.fs != nil {
|
||||
if l.fs != "" {
|
||||
if err := l.rwLayer.Unmount(); err != nil {
|
||||
return errors.Wrap(err, "failed to unmount RWLayer")
|
||||
}
|
||||
l.fs = nil
|
||||
l.fs = ""
|
||||
}
|
||||
|
||||
metadata, err := l.layerStore.ReleaseRWLayer(l.rwLayer)
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
@ -18,9 +17,9 @@ import (
|
|||
//
|
||||
// This extra layer is used by all containers as the top-most ro layer. It protects
|
||||
// the container from unwanted side-effects on the rw layer.
|
||||
func Setup(initLayerFs containerfs.ContainerFS, rootIdentity idtools.Identity) error {
|
||||
func Setup(initLayerFs string, rootIdentity idtools.Identity) error {
|
||||
// Since all paths are local to the container, we can just extract initLayerFs.Path()
|
||||
initLayer := initLayerFs.Path()
|
||||
initLayer := initLayerFs
|
||||
|
||||
for pth, typ := range map[string]string{
|
||||
"/dev/pts": "dir",
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
// excludeByIsolation is a platform specific helper function to support PS
|
||||
// filtering by Isolation. This is a Windows-only concept, so is a no-op on Unix.
|
||||
func excludeByIsolation(container *container.Snapshot, ctx *listContext) iterationAction {
|
||||
i := strings.ToLower(string(container.HostConfig.Isolation))
|
||||
i := strings.ToLower(container.HostConfig.Isolation)
|
||||
if i == "" {
|
||||
i = "default"
|
||||
}
|
||||
|
|
|
@ -721,8 +721,8 @@ func sysctlExists(s string) bool {
|
|||
// WithCommonOptions sets common docker options
|
||||
func WithCommonOptions(daemon *Daemon, c *container.Container) coci.SpecOpts {
|
||||
return func(ctx context.Context, _ coci.Client, _ *containers.Container, s *coci.Spec) error {
|
||||
if c.BaseFS == nil && !daemon.UsesSnapshotter() {
|
||||
return errors.New("populateCommonSpec: BaseFS of container " + c.ID + " is unexpectedly nil")
|
||||
if c.BaseFS == "" && !daemon.UsesSnapshotter() {
|
||||
return errors.New("populateCommonSpec: BaseFS of container " + c.ID + " is unexpectedly empty")
|
||||
}
|
||||
linkedEnv, err := daemon.setupLinkedContainers(c)
|
||||
if err != nil {
|
||||
|
@ -730,7 +730,7 @@ func WithCommonOptions(daemon *Daemon, c *container.Container) coci.SpecOpts {
|
|||
}
|
||||
if !daemon.UsesSnapshotter() {
|
||||
s.Root = &specs.Root{
|
||||
Path: c.BaseFS.Path(),
|
||||
Path: c.BaseFS,
|
||||
Readonly: c.HostConfig.ReadonlyRootfs,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"github.com/docker/docker/daemon/config"
|
||||
"github.com/docker/docker/daemon/network"
|
||||
"github.com/docker/docker/libnetwork"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
"gotest.tools/v3/skip"
|
||||
|
@ -36,7 +35,7 @@ func setupFakeDaemon(t *testing.T, c *container.Container) *Daemon {
|
|||
}
|
||||
|
||||
c.Root = root
|
||||
c.BaseFS = containerfs.NewLocalContainerFS(rootfs)
|
||||
c.BaseFS = rootfs
|
||||
|
||||
if c.Config == nil {
|
||||
c.Config = new(containertypes.Config)
|
||||
|
|
|
@ -236,11 +236,11 @@ func (daemon *Daemon) createSpecWindowsFields(c *container.Container, s *specs.S
|
|||
}
|
||||
s.Root.Readonly = false // Windows does not support a read-only root filesystem
|
||||
if !isHyperV {
|
||||
if c.BaseFS == nil {
|
||||
return errors.New("createSpecWindowsFields: BaseFS of container " + c.ID + " is unexpectedly nil")
|
||||
if c.BaseFS == "" {
|
||||
return errors.New("createSpecWindowsFields: BaseFS of container " + c.ID + " is unexpectedly empty")
|
||||
}
|
||||
|
||||
s.Root.Path = c.BaseFS.Path() // This is not set for Hyper-V containers
|
||||
s.Root.Path = c.BaseFS // This is not set for Hyper-V containers
|
||||
if !strings.HasSuffix(s.Root.Path, `\`) {
|
||||
s.Root.Path = s.Root.Path + `\` // Ensure a correctly formatted volume GUID path \\?\Volume{GUID}\
|
||||
}
|
||||
|
|
|
@ -251,7 +251,7 @@ func (daemon *Daemon) Cleanup(container *container.Container) {
|
|||
daemon.unregisterExecCommand(container, eConfig)
|
||||
}
|
||||
|
||||
if container.BaseFS != nil && container.BaseFS.Path() != "" {
|
||||
if container.BaseFS != "" {
|
||||
if err := container.UnmountVolumes(daemon.LogVolumeEvent); err != nil {
|
||||
logrus.Warnf("%s cleanup: Failed to umount volumes: %v", container.ID, err)
|
||||
}
|
||||
|
|
|
@ -213,13 +213,12 @@ func setupPlugin(t *testing.T, ec map[string]*graphEventsCounter, ext string, mu
|
|||
return
|
||||
}
|
||||
|
||||
// TODO @gupta-ak: Figure out what to do here.
|
||||
dir, err := driver.Get(req.ID, req.MountLabel)
|
||||
if err != nil {
|
||||
respond(w, err)
|
||||
return
|
||||
}
|
||||
respond(w, &graphDriverResponse{Dir: dir.Path()})
|
||||
respond(w, &graphDriverResponse{Dir: dir})
|
||||
})
|
||||
|
||||
mux.HandleFunc("/GraphDriver.Put", func(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
|
@ -15,7 +15,6 @@ import (
|
|||
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
@ -114,7 +113,7 @@ type RWLayer interface {
|
|||
|
||||
// Mount mounts the RWLayer and returns the filesystem path
|
||||
// to the writable layer.
|
||||
Mount(mountLabel string) (containerfs.ContainerFS, error)
|
||||
Mount(mountLabel string) (string, error)
|
||||
|
||||
// Unmount unmounts the RWLayer. This should be called
|
||||
// for every mount. If there are multiple mount calls
|
||||
|
@ -158,7 +157,7 @@ type Metadata struct {
|
|||
// writable mount. Changes made here will
|
||||
// not be included in the Tar stream of the
|
||||
// RWLayer.
|
||||
type MountInit func(root containerfs.ContainerFS) error
|
||||
type MountInit func(root string) error
|
||||
|
||||
// CreateRWLayerOpts contains optional arguments to be passed to CreateRWLayer
|
||||
type CreateRWLayerOpts struct {
|
||||
|
|
|
@ -786,5 +786,5 @@ func (n *naiveDiffPathDriver) DiffGetter(id string) (graphdriver.FileGetCloser,
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &fileGetPutter{storage.NewPathFileGetter(p.Path()), n.Driver, id}, nil
|
||||
return &fileGetPutter{storage.NewPathFileGetter(p), n.Driver, id}, nil
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ import (
|
|||
"github.com/docker/docker/daemon/graphdriver"
|
||||
"github.com/docker/docker/daemon/graphdriver/vfs"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/opencontainers/go-digest"
|
||||
|
@ -80,7 +79,7 @@ func newTestStore(t *testing.T) (Store, string, func()) {
|
|||
}
|
||||
}
|
||||
|
||||
type layerInit func(root containerfs.ContainerFS) error
|
||||
type layerInit func(root string) error
|
||||
|
||||
func createLayer(ls Store, parent ChainID, layerFunc layerInit) (Layer, error) {
|
||||
containerID := stringid.GenerateRandomID()
|
||||
|
@ -121,7 +120,7 @@ func createLayer(ls Store, parent ChainID, layerFunc layerInit) (Layer, error) {
|
|||
}
|
||||
|
||||
type FileApplier interface {
|
||||
ApplyFile(root containerfs.ContainerFS) error
|
||||
ApplyFile(root string) error
|
||||
}
|
||||
|
||||
type testFile struct {
|
||||
|
@ -138,22 +137,22 @@ func newTestFile(name string, content []byte, perm os.FileMode) FileApplier {
|
|||
}
|
||||
}
|
||||
|
||||
func (tf *testFile) ApplyFile(root containerfs.ContainerFS) error {
|
||||
fullPath := root.Join(root.Path(), tf.name)
|
||||
if err := root.MkdirAll(root.Dir(fullPath), 0755); err != nil {
|
||||
func (tf *testFile) ApplyFile(root string) error {
|
||||
fullPath := filepath.Join(root, tf.name)
|
||||
if err := os.MkdirAll(filepath.Dir(fullPath), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
// Check if already exists
|
||||
if stat, err := root.Stat(fullPath); err == nil && stat.Mode().Perm() != tf.permission {
|
||||
if err := root.Lchmod(fullPath, tf.permission); err != nil {
|
||||
if stat, err := os.Stat(fullPath); err == nil && stat.Mode().Perm() != tf.permission {
|
||||
if err := driver.LocalDriver.Lchmod(fullPath, tf.permission); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return driver.WriteFile(root, fullPath, tf.content, tf.permission)
|
||||
return os.WriteFile(fullPath, tf.content, tf.permission)
|
||||
}
|
||||
|
||||
func initWithFiles(files ...FileApplier) layerInit {
|
||||
return func(root containerfs.ContainerFS) error {
|
||||
return func(root string) error {
|
||||
for _, f := range files {
|
||||
if err := f.ApplyFile(root); err != nil {
|
||||
return err
|
||||
|
@ -267,7 +266,7 @@ func TestMountAndRegister(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
b, err := driver.ReadFile(path2, path2.Join(path2.Path(), "testfile.txt"))
|
||||
b, err := os.ReadFile(filepath.Join(path2, "testfile.txt"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -375,7 +374,7 @@ func TestStoreRestore(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := driver.WriteFile(pathFS, pathFS.Join(pathFS.Path(), "testfile.txt"), []byte("nothing here"), 0644); err != nil {
|
||||
if err := os.WriteFile(filepath.Join(pathFS, "testfile.txt"), []byte("nothing here"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -409,20 +408,20 @@ func TestStoreRestore(t *testing.T) {
|
|||
|
||||
if mountPath, err := m2.Mount(""); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if pathFS.Path() != mountPath.Path() {
|
||||
t.Fatalf("Unexpected path %s, expected %s", mountPath.Path(), pathFS.Path())
|
||||
} else if pathFS != mountPath {
|
||||
t.Fatalf("Unexpected path %s, expected %s", mountPath, pathFS)
|
||||
}
|
||||
|
||||
if mountPath, err := m2.Mount(""); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if pathFS.Path() != mountPath.Path() {
|
||||
t.Fatalf("Unexpected path %s, expected %s", mountPath.Path(), pathFS.Path())
|
||||
} else if pathFS != mountPath {
|
||||
t.Fatalf("Unexpected path %s, expected %s", mountPath, pathFS)
|
||||
}
|
||||
if err := m2.Unmount(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
b, err := driver.ReadFile(pathFS, pathFS.Join(pathFS.Path(), "testfile.txt"))
|
||||
b, err := os.ReadFile(filepath.Join(pathFS, "testfile.txt"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -597,7 +596,7 @@ func tarFromFiles(files ...FileApplier) ([]byte, error) {
|
|||
defer os.RemoveAll(td)
|
||||
|
||||
for _, f := range files {
|
||||
if err := f.ApplyFile(containerfs.NewLocalContainerFS(td)); err != nil {
|
||||
if err := f.ApplyFile(td); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ func GetLayerPath(s Store, layer ChainID) (string, error) {
|
|||
return "", err
|
||||
}
|
||||
|
||||
return path.Path(), nil
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func (ls *layerStore) mountID(name string) string {
|
||||
|
|
|
@ -2,13 +2,14 @@ package layer // import "github.com/docker/docker/layer"
|
|||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/containerd/continuity/driver"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
)
|
||||
|
||||
func TestMountInit(t *testing.T) {
|
||||
|
@ -28,7 +29,7 @@ func TestMountInit(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
mountInit := func(root containerfs.ContainerFS) error {
|
||||
mountInit := func(root string) error {
|
||||
return initfile.ApplyFile(root)
|
||||
}
|
||||
|
||||
|
@ -45,12 +46,12 @@ func TestMountInit(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fi, err := pathFS.Stat(pathFS.Join(pathFS.Path(), "testfile.txt"))
|
||||
fi, err := os.Stat(filepath.Join(pathFS, "testfile.txt"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
f, err := pathFS.Open(pathFS.Join(pathFS.Path(), "testfile.txt"))
|
||||
f, err := os.Open(filepath.Join(pathFS, "testfile.txt"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -88,7 +89,7 @@ func TestMountSize(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
mountInit := func(root containerfs.ContainerFS) error {
|
||||
mountInit := func(root string) error {
|
||||
return newTestFile("file-init", contentInit, 0777).ApplyFile(root)
|
||||
}
|
||||
rwLayerOpts := &CreateRWLayerOpts{
|
||||
|
@ -105,7 +106,7 @@ func TestMountSize(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := driver.WriteFile(pathFS, pathFS.Join(pathFS.Path(), "file2"), content2, 0755); err != nil {
|
||||
if err := os.WriteFile(filepath.Join(pathFS, "file2"), content2, 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -140,7 +141,7 @@ func TestMountChanges(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
mountInit := func(root containerfs.ContainerFS) error {
|
||||
mountInit := func(root string) error {
|
||||
return initfile.ApplyFile(root)
|
||||
}
|
||||
rwLayerOpts := &CreateRWLayerOpts{
|
||||
|
@ -157,23 +158,23 @@ func TestMountChanges(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := pathFS.Lchmod(pathFS.Join(pathFS.Path(), "testfile1.txt"), 0755); err != nil {
|
||||
if err := driver.LocalDriver.Lchmod(filepath.Join(pathFS, "testfile1.txt"), 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := driver.WriteFile(pathFS, pathFS.Join(pathFS.Path(), "testfile1.txt"), []byte("mount data!"), 0755); err != nil {
|
||||
if err := os.WriteFile(filepath.Join(pathFS, "testfile1.txt"), []byte("mount data!"), 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := pathFS.Remove(pathFS.Join(pathFS.Path(), "testfile2.txt")); err != nil {
|
||||
if err := os.Remove(filepath.Join(pathFS, "testfile2.txt")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := pathFS.Lchmod(pathFS.Join(pathFS.Path(), "testfile3.txt"), 0755); err != nil {
|
||||
if err := driver.LocalDriver.Lchmod(filepath.Join(pathFS, "testfile3.txt"), 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := driver.WriteFile(pathFS, pathFS.Join(pathFS.Path(), "testfile4.txt"), []byte("mount data!"), 0644); err != nil {
|
||||
if err := os.WriteFile(filepath.Join(pathFS, "testfile4.txt"), []byte("mount data!"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -248,7 +249,7 @@ func TestMountApply(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
f, err := pathFS.Open(pathFS.Join(pathFS.Path(), "newfile.txt"))
|
||||
f, err := os.Open(filepath.Join(pathFS, "newfile.txt"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
)
|
||||
|
||||
type mountedLayer struct {
|
||||
|
@ -100,7 +99,7 @@ type referencedRWLayer struct {
|
|||
*mountedLayer
|
||||
}
|
||||
|
||||
func (rl *referencedRWLayer) Mount(mountLabel string) (containerfs.ContainerFS, error) {
|
||||
func (rl *referencedRWLayer) Mount(mountLabel string) (string, error) {
|
||||
return rl.layerStore.driver.Get(rl.mountedLayer.mountID, mountLabel)
|
||||
}
|
||||
|
||||
|
|
|
@ -186,7 +186,7 @@ func (aSpace *addrSpace) UnmarshalJSON(data []byte) error {
|
|||
|
||||
aSpace.scope = datastore.LocalScope
|
||||
s := m["Scope"].(string)
|
||||
if s == string(datastore.GlobalScope) {
|
||||
if s == datastore.GlobalScope {
|
||||
aSpace.scope = datastore.GlobalScope
|
||||
}
|
||||
|
||||
|
|
|
@ -26,23 +26,23 @@ var (
|
|||
// path (from before being processed by utility functions from the path or
|
||||
// filepath stdlib packages) ends with a trailing `/.` or `/`. If the cleaned
|
||||
// path already ends in a `.` path segment, then another is not added. If the
|
||||
// clean path already ends in the separator, then another is not added.
|
||||
func PreserveTrailingDotOrSeparator(cleanedPath string, originalPath string, sep byte) string {
|
||||
// clean path already ends in a path separator, then another is not added.
|
||||
func PreserveTrailingDotOrSeparator(cleanedPath string, originalPath string) string {
|
||||
// Ensure paths are in platform semantics
|
||||
cleanedPath = strings.ReplaceAll(cleanedPath, "/", string(sep))
|
||||
originalPath = strings.ReplaceAll(originalPath, "/", string(sep))
|
||||
cleanedPath = normalizePath(cleanedPath)
|
||||
originalPath = normalizePath(originalPath)
|
||||
|
||||
if !specifiesCurrentDir(cleanedPath) && specifiesCurrentDir(originalPath) {
|
||||
if !hasTrailingPathSeparator(cleanedPath, sep) {
|
||||
if !hasTrailingPathSeparator(cleanedPath) {
|
||||
// Add a separator if it doesn't already end with one (a cleaned
|
||||
// path would only end in a separator if it is the root).
|
||||
cleanedPath += string(sep)
|
||||
cleanedPath += string(filepath.Separator)
|
||||
}
|
||||
cleanedPath += "."
|
||||
}
|
||||
|
||||
if !hasTrailingPathSeparator(cleanedPath, sep) && hasTrailingPathSeparator(originalPath, sep) {
|
||||
cleanedPath += string(sep)
|
||||
if !hasTrailingPathSeparator(cleanedPath) && hasTrailingPathSeparator(originalPath) {
|
||||
cleanedPath += string(filepath.Separator)
|
||||
}
|
||||
|
||||
return cleanedPath
|
||||
|
@ -51,14 +51,14 @@ func PreserveTrailingDotOrSeparator(cleanedPath string, originalPath string, sep
|
|||
// assertsDirectory returns whether the given path is
|
||||
// asserted to be a directory, i.e., the path ends with
|
||||
// a trailing '/' or `/.`, assuming a path separator of `/`.
|
||||
func assertsDirectory(path string, sep byte) bool {
|
||||
return hasTrailingPathSeparator(path, sep) || specifiesCurrentDir(path)
|
||||
func assertsDirectory(path string) bool {
|
||||
return hasTrailingPathSeparator(path) || specifiesCurrentDir(path)
|
||||
}
|
||||
|
||||
// hasTrailingPathSeparator returns whether the given
|
||||
// path ends with the system's path separator character.
|
||||
func hasTrailingPathSeparator(path string, sep byte) bool {
|
||||
return len(path) > 0 && path[len(path)-1] == sep
|
||||
func hasTrailingPathSeparator(path string) bool {
|
||||
return len(path) > 0 && path[len(path)-1] == filepath.Separator
|
||||
}
|
||||
|
||||
// specifiesCurrentDir returns whether the given path specifies
|
||||
|
@ -285,7 +285,7 @@ func PrepareArchiveCopy(srcContent io.Reader, srcInfo, dstInfo CopyInfo) (dstDir
|
|||
srcBase = srcInfo.RebaseName
|
||||
}
|
||||
return dstDir, RebaseArchiveEntries(srcContent, srcBase, dstBase), nil
|
||||
case assertsDirectory(dstInfo.Path, os.PathSeparator):
|
||||
case assertsDirectory(dstInfo.Path):
|
||||
// The destination does not exist and is asserted to be created as a
|
||||
// directory, but the source content is not a directory. This is an
|
||||
// error condition since you cannot create a directory from a file
|
||||
|
@ -387,8 +387,8 @@ func CopyResource(srcPath, dstPath string, followLink bool) error {
|
|||
dstPath = normalizePath(dstPath)
|
||||
|
||||
// Clean the source and destination paths.
|
||||
srcPath = PreserveTrailingDotOrSeparator(filepath.Clean(srcPath), srcPath, os.PathSeparator)
|
||||
dstPath = PreserveTrailingDotOrSeparator(filepath.Clean(dstPath), dstPath, os.PathSeparator)
|
||||
srcPath = PreserveTrailingDotOrSeparator(filepath.Clean(srcPath), srcPath)
|
||||
dstPath = PreserveTrailingDotOrSeparator(filepath.Clean(dstPath), dstPath)
|
||||
|
||||
if srcInfo, err = CopyInfoSourcePath(srcPath, followLink); err != nil {
|
||||
return err
|
||||
|
@ -451,7 +451,7 @@ func ResolveHostSourcePath(path string, followLink bool) (resolvedPath, rebaseNa
|
|||
// resolvedDirPath will have been cleaned (no trailing path separators) so
|
||||
// we can manually join it with the base path element.
|
||||
resolvedPath = resolvedDirPath + string(filepath.Separator) + basePath
|
||||
if hasTrailingPathSeparator(path, os.PathSeparator) &&
|
||||
if hasTrailingPathSeparator(path) &&
|
||||
filepath.Base(path) != filepath.Base(resolvedPath) {
|
||||
rebaseName = filepath.Base(path)
|
||||
}
|
||||
|
@ -470,8 +470,8 @@ func GetRebaseName(path, resolvedPath string) (string, string) {
|
|||
resolvedPath += string(filepath.Separator) + "."
|
||||
}
|
||||
|
||||
if hasTrailingPathSeparator(path, os.PathSeparator) &&
|
||||
!hasTrailingPathSeparator(resolvedPath, os.PathSeparator) {
|
||||
if hasTrailingPathSeparator(path) &&
|
||||
!hasTrailingPathSeparator(resolvedPath) {
|
||||
resolvedPath += string(filepath.Separator)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,203 +0,0 @@
|
|||
package containerfs // import "github.com/docker/docker/pkg/containerfs"
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// TarFunc provides a function definition for a custom Tar function
|
||||
type TarFunc func(string, *archive.TarOptions) (io.ReadCloser, error)
|
||||
|
||||
// UntarFunc provides a function definition for a custom Untar function
|
||||
type UntarFunc func(io.Reader, string, *archive.TarOptions) error
|
||||
|
||||
// Archiver provides a similar implementation of the archive.Archiver package with the rootfs abstraction
|
||||
type Archiver struct {
|
||||
SrcDriver Driver
|
||||
DstDriver Driver
|
||||
Tar TarFunc
|
||||
Untar UntarFunc
|
||||
IDMapping idtools.IdentityMapping
|
||||
}
|
||||
|
||||
// TarUntar is a convenience function which calls Tar and Untar, with the output of one piped into the other.
|
||||
// If either Tar or Untar fails, TarUntar aborts and returns the error.
|
||||
func (archiver *Archiver) TarUntar(src, dst string) error {
|
||||
logrus.Debugf("TarUntar(%s %s)", src, dst)
|
||||
tarArchive, err := archiver.Tar(src, &archive.TarOptions{Compression: archive.Uncompressed})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tarArchive.Close()
|
||||
options := &archive.TarOptions{
|
||||
IDMap: archiver.IDMapping,
|
||||
}
|
||||
return archiver.Untar(tarArchive, dst, options)
|
||||
}
|
||||
|
||||
// UntarPath untar a file from path to a destination, src is the source tar file path.
|
||||
func (archiver *Archiver) UntarPath(src, dst string) error {
|
||||
tarArchive, err := archiver.SrcDriver.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tarArchive.Close()
|
||||
options := &archive.TarOptions{
|
||||
IDMap: archiver.IDMapping,
|
||||
}
|
||||
return archiver.Untar(tarArchive, dst, options)
|
||||
}
|
||||
|
||||
// CopyWithTar creates a tar archive of filesystem path `src`, and
|
||||
// unpacks it at filesystem path `dst`.
|
||||
// The archive is streamed directly with fixed buffering and no
|
||||
// intermediary disk IO.
|
||||
func (archiver *Archiver) CopyWithTar(src, dst string) error {
|
||||
srcSt, err := archiver.SrcDriver.Stat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !srcSt.IsDir() {
|
||||
return archiver.CopyFileWithTar(src, dst)
|
||||
}
|
||||
|
||||
// if this archiver is set up with ID mapping we need to create
|
||||
// the new destination directory with the remapped root UID/GID pair
|
||||
// as owner
|
||||
|
||||
identity := idtools.Identity{UID: archiver.IDMapping.RootPair().UID, GID: archiver.IDMapping.RootPair().GID}
|
||||
|
||||
// Create dst, copy src's content into it
|
||||
if err := idtools.MkdirAllAndChownNew(dst, 0755, identity); err != nil {
|
||||
return err
|
||||
}
|
||||
logrus.Debugf("Calling TarUntar(%s, %s)", src, dst)
|
||||
return archiver.TarUntar(src, dst)
|
||||
}
|
||||
|
||||
// CopyFileWithTar emulates the behavior of the 'cp' command-line
|
||||
// for a single file. It copies a regular file from path `src` to
|
||||
// path `dst`, and preserves all its metadata.
|
||||
func (archiver *Archiver) CopyFileWithTar(src, dst string) (retErr error) {
|
||||
logrus.Debugf("CopyFileWithTar(%s, %s)", src, dst)
|
||||
srcDriver := archiver.SrcDriver
|
||||
dstDriver := archiver.DstDriver
|
||||
|
||||
srcSt, retErr := srcDriver.Stat(src)
|
||||
if retErr != nil {
|
||||
return retErr
|
||||
}
|
||||
|
||||
if srcSt.IsDir() {
|
||||
return errors.New("cannot copy a directory")
|
||||
}
|
||||
|
||||
// Clean up the trailing slash. This must be done in an operating
|
||||
// system specific manner.
|
||||
if dst[len(dst)-1] == dstDriver.Separator() {
|
||||
dst = dstDriver.Join(dst, srcDriver.Base(src))
|
||||
}
|
||||
|
||||
// The original call was system.MkdirAll, which is just
|
||||
// os.MkdirAll on not-Windows and changed for Windows.
|
||||
if dstDriver.OS() == "windows" {
|
||||
// Now we are WCOW
|
||||
if err := system.MkdirAll(filepath.Dir(dst), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// We can just use the driver.MkdirAll function
|
||||
if err := dstDriver.MkdirAll(dstDriver.Dir(dst), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
r, w := io.Pipe()
|
||||
errC := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
defer close(errC)
|
||||
errC <- func() error {
|
||||
defer w.Close()
|
||||
|
||||
srcF, err := srcDriver.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcF.Close()
|
||||
|
||||
hdr, err := archive.FileInfoHeaderNoLookups(srcSt, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hdr.Format = tar.FormatPAX
|
||||
hdr.ModTime = hdr.ModTime.Truncate(time.Second)
|
||||
hdr.AccessTime = time.Time{}
|
||||
hdr.ChangeTime = time.Time{}
|
||||
hdr.Name = dstDriver.Base(dst)
|
||||
if dstDriver.OS() == "windows" {
|
||||
hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
|
||||
} else {
|
||||
hdr.Mode = int64(os.FileMode(hdr.Mode))
|
||||
}
|
||||
|
||||
if err := remapIDs(archiver.IDMapping, hdr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tw := tar.NewWriter(w)
|
||||
defer tw.Close()
|
||||
if err := tw.WriteHeader(hdr); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.Copy(tw, srcF); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
}()
|
||||
defer func() {
|
||||
if err := <-errC; retErr == nil && err != nil {
|
||||
retErr = err
|
||||
}
|
||||
}()
|
||||
|
||||
retErr = archiver.Untar(r, dstDriver.Dir(dst), nil)
|
||||
if retErr != nil {
|
||||
r.CloseWithError(retErr)
|
||||
}
|
||||
return retErr
|
||||
}
|
||||
|
||||
// IdentityMapping returns the IdentityMapping of the archiver.
|
||||
func (archiver *Archiver) IdentityMapping() idtools.IdentityMapping {
|
||||
return archiver.IDMapping
|
||||
}
|
||||
|
||||
func remapIDs(idMapping idtools.IdentityMapping, hdr *tar.Header) error {
|
||||
ids, err := idMapping.ToHost(idtools.Identity{UID: hdr.Uid, GID: hdr.Gid})
|
||||
hdr.Uid, hdr.Gid = ids.UID, ids.GID
|
||||
return err
|
||||
}
|
||||
|
||||
// chmodTarEntry is used to adjust the file permissions used in tar header based
|
||||
// on the platform the archival is done.
|
||||
func chmodTarEntry(perm os.FileMode) os.FileMode {
|
||||
// perm &= 0755 // this 0-ed out tar flags (like link, regular file, directory marker etc.)
|
||||
permPart := perm & os.ModePerm
|
||||
noPermPart := perm &^ os.ModePerm
|
||||
// Add the x bit: make everything +x from windows
|
||||
permPart |= 0111
|
||||
permPart &= 0755
|
||||
|
||||
return noPermPart | permPart
|
||||
}
|
|
@ -2,85 +2,12 @@ package containerfs // import "github.com/docker/docker/pkg/containerfs"
|
|||
|
||||
import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/containerd/continuity/driver"
|
||||
"github.com/containerd/continuity/pathdriver"
|
||||
"github.com/moby/sys/symlink"
|
||||
)
|
||||
|
||||
// ContainerFS is that represents a root file system
|
||||
type ContainerFS interface {
|
||||
// Path returns the path to the root. Note that this may not exist
|
||||
// on the local system, so the continuity operations must be used
|
||||
Path() string
|
||||
|
||||
// ResolveScopedPath evaluates the given path scoped to the root.
|
||||
// For example, if root=/a, and path=/b/c, then this function would return /a/b/c.
|
||||
// If rawPath is true, then the function will not preform any modifications
|
||||
// before path resolution. Otherwise, the function will clean the given path
|
||||
// by making it an absolute path.
|
||||
ResolveScopedPath(path string, rawPath bool) (string, error)
|
||||
|
||||
Driver
|
||||
}
|
||||
|
||||
// Driver combines both continuity's Driver and PathDriver interfaces with a Platform
|
||||
// field to determine the OS.
|
||||
type Driver interface {
|
||||
// OS returns the OS where the rootfs is located. Essentially, runtime.GOOS.
|
||||
OS() string
|
||||
|
||||
// Architecture returns the hardware architecture where the
|
||||
// container is located.
|
||||
Architecture() string
|
||||
|
||||
// Driver & PathDriver provide methods to manipulate files & paths
|
||||
driver.Driver
|
||||
pathdriver.PathDriver
|
||||
}
|
||||
|
||||
// NewLocalContainerFS is a helper function to implement daemon's Mount interface
|
||||
// when the graphdriver mount point is a local path on the machine.
|
||||
func NewLocalContainerFS(path string) ContainerFS {
|
||||
return &local{
|
||||
path: path,
|
||||
Driver: driver.LocalDriver,
|
||||
PathDriver: pathdriver.LocalPathDriver,
|
||||
}
|
||||
}
|
||||
|
||||
// NewLocalDriver provides file and path drivers for a local file system. They are
|
||||
// essentially a wrapper around the `os` and `filepath` functions.
|
||||
func NewLocalDriver() Driver {
|
||||
return &local{
|
||||
Driver: driver.LocalDriver,
|
||||
PathDriver: pathdriver.LocalPathDriver,
|
||||
}
|
||||
}
|
||||
|
||||
type local struct {
|
||||
path string
|
||||
driver.Driver
|
||||
pathdriver.PathDriver
|
||||
}
|
||||
|
||||
func (l *local) Path() string {
|
||||
return l.path
|
||||
}
|
||||
|
||||
func (l *local) ResolveScopedPath(path string, rawPath bool) (string, error) {
|
||||
cleanedPath := path
|
||||
if !rawPath {
|
||||
cleanedPath = cleanScopedPath(path)
|
||||
}
|
||||
return symlink.FollowSymlinkInScope(filepath.Join(l.path, cleanedPath), l.path)
|
||||
}
|
||||
|
||||
func (l *local) OS() string {
|
||||
return runtime.GOOS
|
||||
}
|
||||
|
||||
func (l *local) Architecture() string {
|
||||
return runtime.GOARCH
|
||||
// ResolveScopedPath evaluates the given path scoped to the root.
|
||||
// For example, if root=/a, and path=/b/c, then this function would return /a/b/c.
|
||||
func ResolveScopedPath(root, path string) (string, error) {
|
||||
return symlink.FollowSymlinkInScope(filepath.Join(root, path), root)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ package containerfs // import "github.com/docker/docker/pkg/containerfs"
|
|||
|
||||
import "path/filepath"
|
||||
|
||||
// cleanScopedPath preappends a to combine with a mnt path.
|
||||
func cleanScopedPath(path string) string {
|
||||
// CleanScopedPath preappends a to combine with a mnt path.
|
||||
func CleanScopedPath(path string) string {
|
||||
return filepath.Join(string(filepath.Separator), path)
|
||||
}
|
||||
|
|
|
@ -2,9 +2,9 @@ package containerfs // import "github.com/docker/docker/pkg/containerfs"
|
|||
|
||||
import "path/filepath"
|
||||
|
||||
// cleanScopedPath removes the C:\ syntax, and prepares to combine
|
||||
// CleanScopedPath removes the C:\ syntax, and prepares to combine
|
||||
// with a volume path
|
||||
func cleanScopedPath(path string) string {
|
||||
func CleanScopedPath(path string) string {
|
||||
if len(path) >= 2 {
|
||||
c := path[0]
|
||||
if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
|
||||
|
|
|
@ -16,12 +16,6 @@ func DefaultPathEnv(os string) string {
|
|||
|
||||
}
|
||||
|
||||
// PathVerifier defines the subset of a PathDriver that CheckSystemDriveAndRemoveDriveLetter
|
||||
// actually uses in order to avoid system depending on containerd/continuity.
|
||||
type PathVerifier interface {
|
||||
IsAbs(string) bool
|
||||
}
|
||||
|
||||
// CheckSystemDriveAndRemoveDriveLetter verifies that a path, if it includes a drive letter,
|
||||
// is the system drive.
|
||||
// On Linux: this is a no-op.
|
||||
|
@ -37,6 +31,6 @@ type PathVerifier interface {
|
|||
// a --> a
|
||||
// /a --> \a
|
||||
// d:\ --> Fail
|
||||
func CheckSystemDriveAndRemoveDriveLetter(path string, driver PathVerifier) (string, error) {
|
||||
return checkSystemDriveAndRemoveDriveLetter(path, driver)
|
||||
func CheckSystemDriveAndRemoveDriveLetter(path string) (string, error) {
|
||||
return checkSystemDriveAndRemoveDriveLetter(path)
|
||||
}
|
||||
|
|
|
@ -12,6 +12,6 @@ func GetLongPathName(path string) (string, error) {
|
|||
|
||||
// checkSystemDriveAndRemoveDriveLetter is the non-Windows implementation
|
||||
// of CheckSystemDriveAndRemoveDriveLetter
|
||||
func checkSystemDriveAndRemoveDriveLetter(path string, driver PathVerifier) (string, error) {
|
||||
func checkSystemDriveAndRemoveDriveLetter(path string) (string, error) {
|
||||
return path, nil
|
||||
}
|
||||
|
|
|
@ -34,11 +34,11 @@ func GetLongPathName(path string) (string, error) {
|
|||
|
||||
// checkSystemDriveAndRemoveDriveLetter is the Windows implementation
|
||||
// of CheckSystemDriveAndRemoveDriveLetter
|
||||
func checkSystemDriveAndRemoveDriveLetter(path string, driver PathVerifier) (string, error) {
|
||||
func checkSystemDriveAndRemoveDriveLetter(path string) (string, error) {
|
||||
if len(path) == 2 && string(path[1]) == ":" {
|
||||
return "", fmt.Errorf("No relative path specified in %q", path)
|
||||
}
|
||||
if !driver.IsAbs(path) || len(path) < 2 {
|
||||
if !filepath.IsAbs(path) || len(path) < 2 {
|
||||
return filepath.FromSlash(path), nil
|
||||
}
|
||||
if string(path[1]) == ":" && !strings.EqualFold(string(path[0]), "c") {
|
||||
|
|
|
@ -5,21 +5,19 @@ package system // import "github.com/docker/docker/pkg/system"
|
|||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/containerd/continuity/pathdriver"
|
||||
)
|
||||
|
||||
// TestCheckSystemDriveAndRemoveDriveLetter tests CheckSystemDriveAndRemoveDriveLetter
|
||||
func TestCheckSystemDriveAndRemoveDriveLetter(t *testing.T) {
|
||||
// Fails if not C drive.
|
||||
_, err := CheckSystemDriveAndRemoveDriveLetter(`d:\`, pathdriver.LocalPathDriver)
|
||||
_, err := CheckSystemDriveAndRemoveDriveLetter(`d:\`)
|
||||
if err == nil || err.Error() != "The specified path is not on the system drive (C:)" {
|
||||
t.Fatalf("Expected error for d:")
|
||||
}
|
||||
|
||||
// Single character is unchanged
|
||||
var path string
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter("z", pathdriver.LocalPathDriver); err != nil {
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter("z"); err != nil {
|
||||
t.Fatalf("Single character should pass")
|
||||
}
|
||||
if path != "z" {
|
||||
|
@ -27,7 +25,7 @@ func TestCheckSystemDriveAndRemoveDriveLetter(t *testing.T) {
|
|||
}
|
||||
|
||||
// Two characters without colon is unchanged
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter("AB", pathdriver.LocalPathDriver); err != nil {
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter("AB"); err != nil {
|
||||
t.Fatalf("2 characters without colon should pass")
|
||||
}
|
||||
if path != "AB" {
|
||||
|
@ -35,7 +33,7 @@ func TestCheckSystemDriveAndRemoveDriveLetter(t *testing.T) {
|
|||
}
|
||||
|
||||
// Abs path without drive letter
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter(`\l`, pathdriver.LocalPathDriver); err != nil {
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter(`\l`); err != nil {
|
||||
t.Fatalf("abs path no drive letter should pass")
|
||||
}
|
||||
if path != `\l` {
|
||||
|
@ -43,7 +41,7 @@ func TestCheckSystemDriveAndRemoveDriveLetter(t *testing.T) {
|
|||
}
|
||||
|
||||
// Abs path without drive letter, linux style
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter(`/l`, pathdriver.LocalPathDriver); err != nil {
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter(`/l`); err != nil {
|
||||
t.Fatalf("abs path no drive letter linux style should pass")
|
||||
}
|
||||
if path != `\l` {
|
||||
|
@ -51,7 +49,7 @@ func TestCheckSystemDriveAndRemoveDriveLetter(t *testing.T) {
|
|||
}
|
||||
|
||||
// Drive-colon should be stripped
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter(`c:\`, pathdriver.LocalPathDriver); err != nil {
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter(`c:\`); err != nil {
|
||||
t.Fatalf("An absolute path should pass")
|
||||
}
|
||||
if path != `\` {
|
||||
|
@ -59,7 +57,7 @@ func TestCheckSystemDriveAndRemoveDriveLetter(t *testing.T) {
|
|||
}
|
||||
|
||||
// Verify with a linux-style path
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter(`c:/`, pathdriver.LocalPathDriver); err != nil {
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter(`c:/`); err != nil {
|
||||
t.Fatalf("An absolute path should pass")
|
||||
}
|
||||
if path != `\` {
|
||||
|
@ -67,7 +65,7 @@ func TestCheckSystemDriveAndRemoveDriveLetter(t *testing.T) {
|
|||
}
|
||||
|
||||
// Failure on c:
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter(`c:`, pathdriver.LocalPathDriver); err == nil {
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter(`c:`); err == nil {
|
||||
t.Fatalf("c: should fail")
|
||||
}
|
||||
if err.Error() != `No relative path specified in "c:"` {
|
||||
|
@ -75,7 +73,7 @@ func TestCheckSystemDriveAndRemoveDriveLetter(t *testing.T) {
|
|||
}
|
||||
|
||||
// Failure on d:
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter(`d:`, pathdriver.LocalPathDriver); err == nil {
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter(`d:`); err == nil {
|
||||
t.Fatalf("c: should fail")
|
||||
}
|
||||
if err.Error() != `No relative path specified in "d:"` {
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/daemon/initlayer"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/plugins"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
|
@ -55,7 +54,7 @@ func (pm *Manager) enable(p *v2.Plugin, c *controller, force bool) error {
|
|||
}
|
||||
}
|
||||
|
||||
rootFS := containerfs.NewLocalContainerFS(filepath.Join(pm.config.Root, p.PluginObj.ID, rootFSFileName))
|
||||
rootFS := filepath.Join(pm.config.Root, p.PluginObj.ID, rootFSFileName)
|
||||
if err := initlayer.Setup(rootFS, idtools.Identity{UID: 0, GID: 0}); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
|
101
vendor/github.com/containerd/continuity/pathdriver/path_driver.go
generated
vendored
101
vendor/github.com/containerd/continuity/pathdriver/path_driver.go
generated
vendored
|
@ -1,101 +0,0 @@
|
|||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package pathdriver
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// PathDriver provides all of the path manipulation functions in a common
|
||||
// interface. The context should call these and never use the `filepath`
|
||||
// package or any other package to manipulate paths.
|
||||
type PathDriver interface {
|
||||
Join(paths ...string) string
|
||||
IsAbs(path string) bool
|
||||
Rel(base, target string) (string, error)
|
||||
Base(path string) string
|
||||
Dir(path string) string
|
||||
Clean(path string) string
|
||||
Split(path string) (dir, file string)
|
||||
Separator() byte
|
||||
Abs(path string) (string, error)
|
||||
Walk(string, filepath.WalkFunc) error
|
||||
FromSlash(path string) string
|
||||
ToSlash(path string) string
|
||||
Match(pattern, name string) (matched bool, err error)
|
||||
}
|
||||
|
||||
// pathDriver is a simple default implementation calls the filepath package.
|
||||
type pathDriver struct{}
|
||||
|
||||
// LocalPathDriver is the exported pathDriver struct for convenience.
|
||||
var LocalPathDriver PathDriver = &pathDriver{}
|
||||
|
||||
func (*pathDriver) Join(paths ...string) string {
|
||||
return filepath.Join(paths...)
|
||||
}
|
||||
|
||||
func (*pathDriver) IsAbs(path string) bool {
|
||||
return filepath.IsAbs(path)
|
||||
}
|
||||
|
||||
func (*pathDriver) Rel(base, target string) (string, error) {
|
||||
return filepath.Rel(base, target)
|
||||
}
|
||||
|
||||
func (*pathDriver) Base(path string) string {
|
||||
return filepath.Base(path)
|
||||
}
|
||||
|
||||
func (*pathDriver) Dir(path string) string {
|
||||
return filepath.Dir(path)
|
||||
}
|
||||
|
||||
func (*pathDriver) Clean(path string) string {
|
||||
return filepath.Clean(path)
|
||||
}
|
||||
|
||||
func (*pathDriver) Split(path string) (dir, file string) {
|
||||
return filepath.Split(path)
|
||||
}
|
||||
|
||||
func (*pathDriver) Separator() byte {
|
||||
return filepath.Separator
|
||||
}
|
||||
|
||||
func (*pathDriver) Abs(path string) (string, error) {
|
||||
return filepath.Abs(path)
|
||||
}
|
||||
|
||||
// Note that filepath.Walk calls os.Stat, so if the context wants to
|
||||
// to call Driver.Stat() for Walk, they need to create a new struct that
|
||||
// overrides this method.
|
||||
func (*pathDriver) Walk(root string, walkFn filepath.WalkFunc) error {
|
||||
return filepath.Walk(root, walkFn)
|
||||
}
|
||||
|
||||
func (*pathDriver) FromSlash(path string) string {
|
||||
return filepath.FromSlash(path)
|
||||
}
|
||||
|
||||
func (*pathDriver) ToSlash(path string) string {
|
||||
return filepath.ToSlash(path)
|
||||
}
|
||||
|
||||
func (*pathDriver) Match(pattern, name string) (bool, error) {
|
||||
return filepath.Match(pattern, name)
|
||||
}
|
1
vendor/modules.txt
vendored
1
vendor/modules.txt
vendored
|
@ -236,7 +236,6 @@ github.com/containerd/containerd/version
|
|||
github.com/containerd/continuity/devices
|
||||
github.com/containerd/continuity/driver
|
||||
github.com/containerd/continuity/fs
|
||||
github.com/containerd/continuity/pathdriver
|
||||
github.com/containerd/continuity/sysx
|
||||
# github.com/containerd/fifo v1.0.0
|
||||
## explicit; go 1.13
|
||||
|
|
Loading…
Add table
Reference in a new issue