Merge pull request #44191 from corhere/drop-containerfs-iface

Remove LCOW: pkg/containerfs: drop ContainerFS abstraction
This commit is contained in:
Sebastiaan van Stijn 2022-09-27 10:28:35 +02:00 committed by GitHub
commit 89555e45f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 376 additions and 897 deletions

View File

@ -291,7 +291,7 @@ func (s *snapshotter) Mounts(ctx context.Context, key string) (snapshot.Mountabl
return nil, nil, err return nil, nil, err
} }
return []mount.Mount{{ return []mount.Mount{{
Source: rootfs.Path(), Source: rootfs,
Type: "bind", Type: "bind",
Options: []string{"rbind"}, Options: []string{"rbind"},
}}, func() error { }}, func() error {
@ -312,7 +312,7 @@ func (s *snapshotter) Mounts(ctx context.Context, key string) (snapshot.Mountabl
return nil, nil, err return nil, nil, err
} }
return []mount.Mount{{ return []mount.Mount{{
Source: rootfs.Path(), Source: rootfs,
Type: "bind", Type: "bind",
Options: []string{"rbind"}, Options: []string{"rbind"},
}}, func() error { }}, func() error {

View File

@ -14,7 +14,6 @@ import (
containerpkg "github.com/docker/docker/container" containerpkg "github.com/docker/docker/container"
"github.com/docker/docker/image" "github.com/docker/docker/image"
"github.com/docker/docker/layer" "github.com/docker/docker/layer"
"github.com/docker/docker/pkg/containerfs"
) )
const ( const (
@ -26,7 +25,7 @@ const (
// instructions in the builder. // instructions in the builder.
type Source interface { type Source interface {
// Root returns root path for accessing source // 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. // Close allows to signal that the filesystem tree won't be used anymore.
// For Context implementations using a temporary directory, it is recommended to // For Context implementations using a temporary directory, it is recommended to
// delete the temporary directory in Close(). // delete the temporary directory in Close().
@ -110,6 +109,6 @@ type ROLayer interface {
// RWLayer is active layer that can be read/modified // RWLayer is active layer that can be read/modified
type RWLayer interface { type RWLayer interface {
Release() error Release() error
Root() containerfs.ContainerFS Root() string
Commit() (ROLayer, error) Commit() (ROLayer, error)
} }

View File

@ -1,7 +1,6 @@
package dockerfile // import "github.com/docker/docker/builder/dockerfile" package dockerfile // import "github.com/docker/docker/builder/dockerfile"
import ( import (
"archive/tar"
"fmt" "fmt"
"io" "io"
"mime" "mime"
@ -39,14 +38,14 @@ type pathCache interface {
// copyInfo is a data object which stores the metadata about each source file in // copyInfo is a data object which stores the metadata about each source file in
// a copyInstruction // a copyInstruction
type copyInfo struct { type copyInfo struct {
root containerfs.ContainerFS root string
path string path string
hash string hash string
noDecompress bool noDecompress bool
} }
func (c copyInfo) fullPath() (string, error) { 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 { 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 path = unnamedFilename
} }
o.tmpPaths = append(o.tmpPaths, remote.Root().Path()) o.tmpPaths = append(o.tmpPaths, remote.Root())
hash, err := remote.Hash(path) hash, err := remote.Hash(path)
ci := newCopyInfoFromSource(remote, path, hash) 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()) o.source, err = remotecontext.NewLazySource(rwLayer.Root())
if err != nil { 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) { func (o *copier) copyWithWildcards(origPath string) ([]copyInfo, error) {
root := o.source.Root() root := o.source.Root()
var copyInfos []copyInfo 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 { if err != nil {
return err return err
} }
@ -272,7 +271,7 @@ func (o *copier) copyWithWildcards(origPath string) ([]copyInfo, error) {
if rel == "." { if rel == "." {
return nil return nil
} }
if match, _ := root.Match(origPath, rel); !match { if match, _ := filepath.Match(origPath, rel); !match {
return nil return nil
} }
@ -318,7 +317,7 @@ func walkSource(source builder.Source, origPath string) ([]string, error) {
} }
// Must be a dir // Must be a dir
var subfiles []string 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 { if err != nil {
return err return err
} }
@ -443,19 +442,14 @@ func downloadSource(output io.Writer, stdout io.Writer, srcURL string) (remote b
return return
} }
lc, err := remotecontext.NewLazySource(containerfs.NewLocalContainerFS(tmpDir)) lc, err := remotecontext.NewLazySource(tmpDir)
return lc, filename, err return lc, filename, err
} }
type copyFileOptions struct { type copyFileOptions struct {
decompress bool decompress bool
identity *idtools.Identity identity *idtools.Identity
archiver Archiver archiver *archive.Archiver
}
type copyEndpoint struct {
driver containerfs.Driver
path string
} }
func performCopyForInfo(dest copyInfo, source copyInfo, options copyFileOptions) error { func performCopyForInfo(dest copyInfo, source copyInfo, options copyFileOptions) error {
@ -471,96 +465,77 @@ func performCopyForInfo(dest copyInfo, source copyInfo, options copyFileOptions)
archiver := options.archiver archiver := options.archiver
srcEndpoint := &copyEndpoint{driver: source.root, path: srcPath} src, err := os.Stat(srcPath)
destEndpoint := &copyEndpoint{driver: dest.root, path: destPath}
src, err := source.root.Stat(srcPath)
if err != nil { if err != nil {
return errors.Wrapf(err, "source path not found") return errors.Wrapf(err, "source path not found")
} }
if src.IsDir() { 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) return archiver.UntarPath(srcPath, destPath)
} }
destExistsAsDir, err := isExistingDirectory(destEndpoint) destExistsAsDir, err := isExistingDirectory(destPath)
if err != nil { if err != nil {
return err return err
} }
// dest.path must be used because destPath has already been cleaned of any // dest.path must be used because destPath has already been cleaned of any
// trailing slash // 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 // source.path must be used to get the correct filename when the source
// is a symlink // is a symlink
destPath = dest.root.Join(destPath, source.root.Base(source.path)) destPath = filepath.Join(destPath, filepath.Base(source.path))
destEndpoint = &copyEndpoint{driver: dest.root, path: destPath}
} }
return copyFile(archiver, srcEndpoint, destEndpoint, options.identity) return copyFile(archiver, srcPath, destPath, options.identity)
} }
func isArchivePath(driver containerfs.ContainerFS, path string) bool { func copyDirectory(archiver *archive.Archiver, source, dest string, identity *idtools.Identity) error {
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 {
destExists, err := isExistingDirectory(dest) destExists, err := isExistingDirectory(dest)
if err != nil { if err != nil {
return errors.Wrapf(err, "failed to query destination path") 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") return errors.Wrapf(err, "failed to copy directory")
} }
if identity != nil { if identity != nil {
return fixPermissions(source.path, dest.path, *identity, !destExists) return fixPermissions(source, dest, *identity, !destExists)
} }
return nil 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 { if identity == nil {
// Use system.MkdirAll here, which is a custom version of os.MkdirAll // Use system.MkdirAll here, which is a custom version of os.MkdirAll
// modified for use on Windows to handle volume GUID paths. These paths // modified for use on Windows to handle volume GUID paths. These paths
// are of the form \\?\Volume{<GUID>}\<path>. An example would be: // are of the form \\?\Volume{<GUID>}\<path>. An example would be:
// \\?\Volume{dae8d3ac-b9a1-11e9-88eb-e8554b2ba1db}\bin\busybox.exe // \\?\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 return err
} }
} else { } 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") 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") return errors.Wrapf(err, "failed to copy file")
} }
if identity != nil { if identity != nil {
return fixPermissions(source.path, dest.path, *identity, false) return fixPermissions(source, dest, *identity, false)
} }
return nil return nil
} }
func endsInSlash(driver containerfs.Driver, path string) bool { func endsInSlash(path string) bool {
return strings.HasSuffix(path, string(driver.Separator())) return strings.HasSuffix(path, string(filepath.Separator))
} }
// isExistingDirectory returns true if the path exists and is a directory // isExistingDirectory returns true if the path exists and is a directory
func isExistingDirectory(point *copyEndpoint) (bool, error) { func isExistingDirectory(path string) (bool, error) {
destStat, err := point.driver.Stat(point.path) destStat, err := os.Stat(path)
switch { switch {
case errors.Is(err, os.ErrNotExist): case errors.Is(err, os.ErrNotExist):
return false, nil return false, nil

View File

@ -4,7 +4,6 @@ import (
"net/http" "net/http"
"testing" "testing"
"github.com/docker/docker/pkg/containerfs"
"gotest.tools/v3/assert" "gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp" is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/fs" "gotest.tools/v3/fs"
@ -39,7 +38,7 @@ func TestIsExistingDirectory(t *testing.T) {
} }
for _, testcase := range testcases { for _, testcase := range testcases {
result, err := isExistingDirectory(&copyEndpoint{driver: containerfs.NewLocalDriver(), path: testcase.path}) result, err := isExistingDirectory(testcase.path)
if !assert.Check(t, err) { if !assert.Check(t, err) {
continue continue
} }

View File

@ -9,7 +9,6 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/idtools"
) )
@ -19,8 +18,7 @@ func fixPermissions(source, destination string, identity idtools.Identity, overr
err error err error
) )
if !overrideSkip { if !overrideSkip {
destEndpoint := &copyEndpoint{driver: containerfs.NewLocalDriver(), path: destination} skipChownRoot, err = isExistingDirectory(destination)
skipChownRoot, err = isExistingDirectory(destEndpoint)
if err != nil { if err != nil {
return err return err
} }

View File

@ -7,7 +7,6 @@ import (
"crypto/sha256" "crypto/sha256"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"io"
"strings" "strings"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
@ -17,8 +16,6 @@ import (
"github.com/docker/docker/image" "github.com/docker/docker/image"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/chrootarchive" "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/docker/pkg/stringid"
"github.com/docker/go-connections/nat" "github.com/docker/go-connections/nat"
specs "github.com/opencontainers/image-spec/specs-go/v1" specs "github.com/opencontainers/image-spec/specs-go/v1"
@ -26,50 +23,8 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// Archiver defines an interface for copying files from one destination to func (b *Builder) getArchiver() *archive.Archiver {
// another using Tar/Untar. return chrootarchive.NewArchiver(b.idMapping)
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) commit(dispatchState *dispatchState, comment string) error { 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 // translated (if necessary because of user namespaces), and replace
// the root pair with the chown pair for copy operations // the root pair with the chown pair for copy operations
if inst.chownStr != "" { 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 err != nil {
if b.options.Platform != "windows" { if b.options.Platform != "windows" {
return errors.Wrapf(err, "unable to convert uid/gid chown string to host mapping") 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 { for _, info := range inst.infos {
opts := copyFileOptions{ opts := copyFileOptions{
decompress: inst.allowLocalDecompression, decompress: inst.allowLocalDecompression,
archiver: b.getArchiver(info.root, destInfo.root), archiver: b.getArchiver(),
} }
if !inst.preserveOwnership { if !inst.preserveOwnership {
opts.identity = &identity opts.identity = &identity

View File

@ -14,7 +14,6 @@ import (
"github.com/docker/docker/image" "github.com/docker/docker/image"
"github.com/docker/docker/layer" "github.com/docker/docker/layer"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/go-connections/nat" "github.com/docker/go-connections/nat"
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
"gotest.tools/v3/assert" "gotest.tools/v3/assert"
@ -183,8 +182,8 @@ func TestDeepCopyRunConfig(t *testing.T) {
type MockRWLayer struct{} type MockRWLayer struct{}
func (l *MockRWLayer) Release() error { return nil } func (l *MockRWLayer) Release() error { return nil }
func (l *MockRWLayer) Root() containerfs.ContainerFS { return nil } func (l *MockRWLayer) Root() string { return "" }
func (l *MockRWLayer) Commit() (builder.ROLayer, error) { func (l *MockRWLayer) Commit() (builder.ROLayer, error) {
return &MockROLayer{ return &MockROLayer{
diffID: layer.DiffID(digest.Digest("sha256:1234")), diffID: layer.DiffID(digest.Digest("sha256:1234")),

View File

@ -13,7 +13,6 @@ import (
containerpkg "github.com/docker/docker/container" containerpkg "github.com/docker/docker/container"
"github.com/docker/docker/image" "github.com/docker/docker/image"
"github.com/docker/docker/layer" "github.com/docker/docker/layer"
"github.com/docker/docker/pkg/containerfs"
) )
// MockBackend implements the builder.Backend interface for unit testing // MockBackend implements the builder.Backend interface for unit testing
@ -143,6 +142,6 @@ func (l *mockRWLayer) Commit() (builder.ROLayer, error) {
return nil, nil return nil, nil
} }
func (l *mockRWLayer) Root() containerfs.ContainerFS { func (l *mockRWLayer) Root() string {
return nil return ""
} }

View File

@ -15,12 +15,12 @@ import (
) )
type archiveContext struct { type archiveContext struct {
root containerfs.ContainerFS root string
sums tarsum.FileInfoSums sums tarsum.FileInfoSums
} }
func (c *archiveContext) Close() error { func (c *archiveContext) Close() error {
return c.root.RemoveAll(c.root.Path()) return os.RemoveAll(c.root)
} }
func convertPathError(err error, cleanpath string) error { 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. // 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 // Make sure we clean-up upon error. In the happy case the caller
// is expected to manage the clean-up // is expected to manage the clean-up
@ -82,7 +82,7 @@ func FromArchive(tarStream io.Reader) (builder.Source, error) {
return tsc, nil return tsc, nil
} }
func (c *archiveContext) Root() containerfs.ContainerFS { func (c *archiveContext) Root() string {
return c.root return c.root
} }
@ -91,7 +91,7 @@ func (c *archiveContext) Remove(path string) error {
if err != nil { if err != nil {
return err return err
} }
return c.root.RemoveAll(fullpath) return os.RemoveAll(fullpath)
} }
func (c *archiveContext) Hash(path string) (string, error) { func (c *archiveContext) Hash(path string) (string, error) {
@ -100,7 +100,7 @@ func (c *archiveContext) Hash(path string) (string, error) {
return "", err return "", err
} }
rel, err := c.root.Rel(c.root.Path(), fullpath) rel, err := filepath.Rel(c.root, fullpath)
if err != nil { if err != nil {
return "", convertPathError(err, cleanpath) 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 return path, nil // backwards compat TODO: see if really needed
} }
func normalize(path string, root containerfs.ContainerFS) (cleanPath, fullPath string, err error) { func normalize(path string, root string) (cleanPath, fullPath string, err error) {
cleanPath = root.Clean(string(root.Separator()) + path)[1:] cleanPath = filepath.Clean(string(filepath.Separator) + path)[1:]
fullPath, err = root.ResolveScopedPath(path, true) fullPath, err = containerfs.ResolveScopedPath(root, path)
if err != nil { if err != nil {
return "", "", errors.Wrapf(err, "forbidden path outside the build context: %s (%s)", path, cleanPath) return "", "", errors.Wrapf(err, "forbidden path outside the build context: %s (%s)", path, cleanPath)
} }

View File

@ -13,6 +13,7 @@ import (
"github.com/docker/docker/builder" "github.com/docker/docker/builder"
"github.com/docker/docker/builder/remotecontext/urlutil" "github.com/docker/docker/builder/remotecontext/urlutil"
"github.com/docker/docker/errdefs" "github.com/docker/docker/errdefs"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/fileutils" "github.com/docker/docker/pkg/fileutils"
"github.com/moby/buildkit/frontend/dockerfile/dockerignore" "github.com/moby/buildkit/frontend/dockerfile/dockerignore"
"github.com/moby/buildkit/frontend/dockerfile/parser" "github.com/moby/buildkit/frontend/dockerfile/parser"
@ -161,7 +162,7 @@ func openAt(remote builder.Source, path string) (driver.File, error) {
if err != nil { if err != nil {
return nil, err 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 // 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 { if err != nil {
return nil, err 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 // FullPath is a helper for getting a full path for a path from a source
func FullPath(remote builder.Source, path string) (string, error) { 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 err != nil {
if runtime.GOOS == "windows" { 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) return "", fmt.Errorf("failed to resolve scoped path %s (%s): %s. Possible cause is a forbidden path outside the build context", path, fullPath, err)

View File

@ -4,11 +4,11 @@ import (
"errors" "errors"
"log" "log"
"os" "os"
"path/filepath"
"sort" "sort"
"testing" "testing"
"github.com/docker/docker/builder" "github.com/docker/docker/builder"
"github.com/docker/docker/pkg/containerfs"
) )
const ( const (
@ -52,7 +52,7 @@ func checkDirectory(t *testing.T, dir string, expectedFiles []string) {
} }
func executeProcess(t *testing.T, contextDir string) { func executeProcess(t *testing.T, contextDir string) {
modifiableCtx := &stubRemote{root: containerfs.NewLocalContainerFS(contextDir)} modifiableCtx := &stubRemote{root: contextDir}
err := removeDockerfile(modifiableCtx, builder.DefaultDockerfileName) err := removeDockerfile(modifiableCtx, builder.DefaultDockerfileName)
@ -104,19 +104,19 @@ func TestProcessShouldLeaveAllFiles(t *testing.T) {
// TODO: remove after moving to a separate pkg // TODO: remove after moving to a separate pkg
type stubRemote struct { type stubRemote struct {
root containerfs.ContainerFS root string
} }
func (r *stubRemote) Hash(path string) (string, error) { func (r *stubRemote) Hash(path string) (string, error) {
return "", errors.New("not implemented") return "", errors.New("not implemented")
} }
func (r *stubRemote) Root() containerfs.ContainerFS { func (r *stubRemote) Root() string {
return r.root return r.root
} }
func (r *stubRemote) Close() error { func (r *stubRemote) Close() error {
return errors.New("not implemented") return errors.New("not implemented")
} }
func (r *stubRemote) Remove(p string) error { 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))
} }

View File

@ -3,10 +3,11 @@ package remotecontext // import "github.com/docker/docker/builder/remotecontext"
import ( import (
"encoding/hex" "encoding/hex"
"os" "os"
"path/filepath"
"runtime"
"strings" "strings"
"github.com/docker/docker/builder" "github.com/docker/docker/builder"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/pools" "github.com/docker/docker/pkg/pools"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -14,7 +15,7 @@ import (
// NewLazySource creates a new LazyContext. LazyContext defines a hashed build // NewLazySource creates a new LazyContext. LazyContext defines a hashed build
// context based on a root directory. Individual files are hashed first time // 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. // 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{ return &lazySource{
root: root, root: root,
sums: make(map[string]string), sums: make(map[string]string),
@ -22,11 +23,11 @@ func NewLazySource(root containerfs.ContainerFS) (builder.Source, error) {
} }
type lazySource struct { type lazySource struct {
root containerfs.ContainerFS root string
sums map[string]string sums map[string]string
} }
func (c *lazySource) Root() containerfs.ContainerFS { func (c *lazySource) Root() string {
return c.root return c.root
} }
@ -45,7 +46,7 @@ func (c *lazySource) Hash(path string) (string, error) {
return "", errors.WithStack(convertPathError(err, cleanPath)) return "", errors.WithStack(convertPathError(err, cleanPath))
} }
fi, err := c.root.Lstat(fullPath) fi, err := os.Lstat(fullPath)
if err != nil { if err != nil {
// Backwards compatibility: a missing file returns a path as hash. // Backwards compatibility: a missing file returns a path as hash.
// This is reached in the case of a broken symlink. // 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) { 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) h, err := NewFileHash(p, relPath, fi)
if err != nil { if err != nil {
return "", errors.Wrapf(err, "failed to create hash for %s", relPath) return "", errors.Wrapf(err, "failed to create hash for %s", relPath)
} }
if fi.Mode().IsRegular() && fi.Size() > 0 { if fi.Mode().IsRegular() && fi.Size() > 0 {
f, err := c.root.Open(p) f, err := os.Open(p)
if err != nil { if err != nil {
return "", errors.Wrapf(err, "failed to open %s", relPath) 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 // Rel makes a path relative to base path. Same as `filepath.Rel` but can also
// handle UUID paths in windows. // 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 // filepath.Rel can't handle UUID paths in windows
if basepath.OS() == "windows" { if runtime.GOOS == "windows" {
pfx := basepath.Path() + `\` pfx := basepath + `\`
if strings.HasPrefix(targpath, pfx) { if strings.HasPrefix(targpath, pfx) {
p := strings.TrimPrefix(targpath, pfx) p := strings.TrimPrefix(targpath, pfx)
if p == "" { if p == "" {
@ -98,5 +99,5 @@ func Rel(basepath containerfs.ContainerFS, targpath string) (string, error) {
return p, nil return p, nil
} }
} }
return basepath.Rel(basepath.Path(), targpath) return filepath.Rel(basepath, targpath)
} }

View File

@ -2,9 +2,9 @@ package remotecontext // import "github.com/docker/docker/builder/remotecontext"
import ( import (
"os" "os"
"path/filepath"
"sync" "sync"
"github.com/docker/docker/pkg/containerfs"
iradix "github.com/hashicorp/go-immutable-radix" iradix "github.com/hashicorp/go-immutable-radix"
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -18,7 +18,7 @@ type hashed interface {
// CachableSource is a source that contains cache records for its contents // CachableSource is a source that contains cache records for its contents
type CachableSource struct { type CachableSource struct {
mu sync.Mutex mu sync.Mutex
root containerfs.ContainerFS root string
tree *iradix.Tree tree *iradix.Tree
txn *iradix.Txn txn *iradix.Txn
} }
@ -27,7 +27,7 @@ type CachableSource struct {
func NewCachableSource(root string) *CachableSource { func NewCachableSource(root string) *CachableSource {
ts := &CachableSource{ ts := &CachableSource{
tree: iradix.New(), tree: iradix.New(),
root: containerfs.NewLocalContainerFS(root), root: root,
} }
return ts return ts
} }
@ -66,7 +66,7 @@ func (cs *CachableSource) Scan() error {
return err return err
} }
txn := iradix.New().Txn() 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 { if err != nil {
return errors.Wrapf(err, "failed to walk %s", path) 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 // Root returns a root directory for the source
func (cs *CachableSource) Root() containerfs.ContainerFS { func (cs *CachableSource) Root() string {
return cs.root return cs.root
} }

View File

@ -35,7 +35,7 @@ func TestCloseRootDirectory(t *testing.T) {
t.Fatalf("Error while executing Close: %s", err) 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) { if !errors.Is(err, os.ErrNotExist) {
t.Fatal("Directory should not exist at this point") t.Fatal("Directory should not exist at this point")
@ -118,7 +118,7 @@ func TestRemoveDirectory(t *testing.T) {
src := makeTestArchiveContext(t, contextDir) 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 { if err != nil {
t.Fatalf("Statting %s shouldn't fail: %+v", relativePath, err) 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) 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) { if !errors.Is(err, os.ErrNotExist) {
t.Fatalf("Directory should not exist at this point: %+v ", err) t.Fatalf("Directory should not exist at this point: %+v ", err)
} }

View File

@ -2,6 +2,7 @@ package container // import "github.com/docker/docker/container"
import ( import (
"os" "os"
"path/filepath"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
@ -14,24 +15,21 @@ import (
// the absolute path to the resource relative to the container's rootfs, and // 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. // an error if the path points to outside the container's rootfs.
func (container *Container) ResolvePath(path string) (resolvedPath, absPath string, err error) { func (container *Container) ResolvePath(path string) (resolvedPath, absPath string, err error) {
if container.BaseFS == nil { if container.BaseFS == "" {
return "", "", errors.New("ResolvePath: BaseFS of container " + container.ID + " is unexpectedly nil") 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 // 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 { if err != nil {
return "", "", err return "", "", err
} }
// Consider the given path as an absolute path in the container. // Consider the given path as an absolute path in the container.
absPath = archive.PreserveTrailingDotOrSeparator( absPath = archive.PreserveTrailingDotOrSeparator(filepath.Join(string(filepath.Separator), path), path)
container.BaseFS.Join(string(container.BaseFS.Separator()), path),
path,
container.BaseFS.Separator())
// Split the absPath into its Directory and Base components. We will // Split the absPath into its Directory and Base components. We will
// resolve the dir in the scope of the container then append the base. // 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) resolvedDirPath, err := container.GetResourcePath(dirPath)
if err != nil { 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 // resolvedDirPath will have been cleaned (no trailing path separators) so
// we can manually join it with the base path element. // 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 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 // resolved to a path on the host corresponding to the given absolute path
// inside the container. // inside the container.
func (container *Container) StatPath(resolvedPath, absPath string) (stat *types.ContainerPathStat, err error) { func (container *Container) StatPath(resolvedPath, absPath string) (stat *types.ContainerPathStat, err error) {
if container.BaseFS == nil { if container.BaseFS == "" {
return nil, errors.New("StatPath: BaseFS of container " + container.ID + " is unexpectedly nil") 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 { if err != nil {
return nil, err return nil, err
} }
@ -67,17 +64,17 @@ func (container *Container) StatPath(resolvedPath, absPath string) (stat *types.
return nil, err return nil, err
} }
linkTarget, err = driver.Rel(driver.Path(), hostPath) linkTarget, err = filepath.Rel(container.BaseFS, hostPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Make it an absolute path. // Make it an absolute path.
linkTarget = driver.Join(string(driver.Separator()), linkTarget) linkTarget = filepath.Join(string(filepath.Separator), linkTarget)
} }
return &types.ContainerPathStat{ return &types.ContainerPathStat{
Name: driver.Base(absPath), Name: filepath.Base(absPath),
Size: lstat.Size(), Size: lstat.Size(),
Mode: lstat.Mode(), Mode: lstat.Mode(),
Mtime: lstat.ModTime(), Mtime: lstat.ModTime(),

View File

@ -61,10 +61,10 @@ type ExitStatus struct {
type Container struct { type Container struct {
StreamConfig *stream.Config StreamConfig *stream.Config
// embed for Container to support states directly. // embed for Container to support states directly.
*State `json:"State"` // Needed for Engine API version <= 1.11 *State `json:"State"` // Needed for Engine API version <= 1.11
Root string `json:"-"` // Path to the "home" of the container, including metadata. Root string `json:"-"` // Path to the "home" of the container, including metadata.
BaseFS containerfs.ContainerFS `json:"-"` // interface containing graphdriver mount BaseFS string `json:"-"` // Path to the graphdriver mountpoint
RWLayer layer.RWLayer `json:"-"` RWLayer layer.RWLayer `json:"-"`
ID string ID string
Created time.Time Created time.Time
Managed bool 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 // symlinking to a different path) between using this method and using the
// path. See symlink.FollowSymlinkInScope for more details. // path. See symlink.FollowSymlinkInScope for more details.
func (container *Container) GetResourcePath(path string) (string, error) { func (container *Container) GetResourcePath(path string) (string, error) {
if container.BaseFS == nil { if container.BaseFS == "" {
return "", errors.New("GetResourcePath: BaseFS of container " + container.ID + " is unexpectedly nil") 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 // IMPORTANT - These are paths on the OS where the daemon is running, hence
// any filepath operations must be done in an OS agnostic way. // 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 // 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 // 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. // debugging significantly easier and clearly indicates the error comes from the daemon.
if e != nil { 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 return r, e
} }

View File

@ -3,6 +3,7 @@ package daemon // import "github.com/docker/docker/daemon"
import ( import (
"io" "io"
"os" "os"
"path/filepath"
"strings" "strings"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
@ -20,32 +21,6 @@ import (
// path does not refer to a directory. // path does not refer to a directory.
var ErrExtractPointNotDirectory = errors.New("extraction point is not 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 // ContainerCopy performs a deprecated operation of archiving the resource at
// the specified path in the container identified by the given name. // the specified path in the container identified by the given name.
func (daemon *Daemon) ContainerCopy(name string, res string) (io.ReadCloser, error) { 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 // Normalize path before sending to rootfs
path = container.BaseFS.FromSlash(path) path = filepath.FromSlash(path)
resolvedPath, absPath, err := container.ResolvePath(path) resolvedPath, absPath, err := container.ResolvePath(path)
if err != nil { if err != nil {
@ -208,7 +183,7 @@ func (daemon *Daemon) containerArchivePath(container *container.Container, path
} }
// Normalize path before sending to rootfs // Normalize path before sending to rootfs
path = container.BaseFS.FromSlash(path) path = filepath.FromSlash(path)
resolvedPath, absPath, err := container.ResolvePath(path) resolvedPath, absPath, err := container.ResolvePath(path)
if err != nil { 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 // also catches the case when the root directory of the container is
// requested: we want the archive entries to start with "/" and not the // requested: we want the archive entries to start with "/" and not the
// container ID. // container ID.
driver := container.BaseFS
// Get the source and the base paths of the container resolved path in order // Get the source and the base paths of the container resolved path in order
// to get the proper tar options for the rebase tar. // to get the proper tar options for the rebase tar.
resolvedPath = driver.Clean(resolvedPath) resolvedPath = filepath.Clean(resolvedPath)
if driver.Base(resolvedPath) == "." { if filepath.Base(resolvedPath) == "." {
resolvedPath += string(driver.Separator()) + "." resolvedPath += string(filepath.Separator) + "."
} }
sourceDir := resolvedPath sourceDir := resolvedPath
sourceBase := "." sourceBase := "."
if stat.Mode&os.ModeDir == 0 { // not dir 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 { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -285,11 +259,10 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path
} }
// Normalize path before sending to rootfs' // Normalize path before sending to rootfs'
path = container.BaseFS.FromSlash(path) path = filepath.FromSlash(path)
driver := container.BaseFS
// Check if a drive letter supplied, it must be the system drive. No-op except on Windows // 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 { if err != nil {
return err 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. // 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. // Consider the given path as an absolute path in the container.
absPath := archive.PreserveTrailingDotOrSeparator( absPath := archive.PreserveTrailingDotOrSeparator(filepath.Join(string(filepath.Separator), path), path)
driver.Join(string(driver.Separator()), path),
path,
driver.Separator())
// This will evaluate the last path element if it is a symlink. // This will evaluate the last path element if it is a symlink.
resolvedPath, err := container.GetResourcePath(absPath) resolvedPath, err := container.GetResourcePath(absPath)
@ -312,7 +282,7 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path
return err return err
} }
stat, err := driver.Lstat(resolvedPath) stat, err := os.Lstat(resolvedPath)
if err != nil { if err != nil {
return err return err
} }
@ -335,24 +305,21 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path
// a volume file path. // a volume file path.
var baseRel string var baseRel string
if strings.HasPrefix(resolvedPath, `\\?\Volume{`) { if strings.HasPrefix(resolvedPath, `\\?\Volume{`) {
if strings.HasPrefix(resolvedPath, driver.Path()) { if strings.HasPrefix(resolvedPath, container.BaseFS) {
baseRel = resolvedPath[len(driver.Path()):] baseRel = resolvedPath[len(container.BaseFS):]
if baseRel[:1] == `\` { if baseRel[:1] == `\` {
baseRel = baseRel[1:] baseRel = baseRel[1:]
} }
} }
} else { } else {
baseRel, err = driver.Rel(driver.Path(), resolvedPath) baseRel, err = filepath.Rel(container.BaseFS, resolvedPath)
} }
if err != nil { if err != nil {
return err return err
} }
// Make it an absolute path. // 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) toVolume, err := checkIfPathIsInAVolume(container, absPath)
if err != nil { if err != nil {
return err 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 return err
} }
@ -416,27 +383,26 @@ func (daemon *Daemon) containerCopy(container *container.Container, resource str
} }
// Normalize path before sending to rootfs // Normalize path before sending to rootfs
resource = container.BaseFS.FromSlash(resource) resource = filepath.FromSlash(resource)
driver := container.BaseFS
basePath, err := container.GetResourcePath(resource) basePath, err := container.GetResourcePath(resource)
if err != nil { if err != nil {
return nil, err return nil, err
} }
stat, err := driver.Stat(basePath) stat, err := os.Stat(basePath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var filter []string var filter []string
if !stat.IsDir() { if !stat.IsDir() {
d, f := driver.Split(basePath) d, f := filepath.Split(basePath)
basePath = d basePath = d
filter = []string{f} filter = []string{f}
} }
archv, err := archivePath(driver, basePath, &archive.TarOptions{ archv, err := chrootarchive.Tar(basePath, &archive.TarOptions{
Compression: archive.Uncompressed, Compression: archive.Uncompressed,
IncludeFiles: filter, IncludeFiles: filter,
}, container.BaseFS.Path()) }, container.BaseFS)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -1270,7 +1270,7 @@ func (daemon *Daemon) Mount(container *container.Container) error {
} }
logrus.WithField("container", container.ID).Debugf("container mounted via layerStore: %v", dir) 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 // 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 // volume path for a given mounted layer may change over time. This should only be an error
// on non-Windows operating systems. // on non-Windows operating systems.

View File

@ -38,7 +38,6 @@ import (
"github.com/docker/docker/libnetwork/options" "github.com/docker/docker/libnetwork/options"
lntypes "github.com/docker/docker/libnetwork/types" lntypes "github.com/docker/docker/libnetwork/types"
"github.com/docker/docker/opts" "github.com/docker/docker/opts"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/parsers/kernel" "github.com/docker/docker/pkg/parsers/kernel"
@ -1072,8 +1071,8 @@ func removeDefaultBridgeInterface() {
} }
} }
func setupInitLayer(idMapping idtools.IdentityMapping) func(containerfs.ContainerFS) error { func setupInitLayer(idMapping idtools.IdentityMapping) func(string) error {
return func(initPath containerfs.ContainerFS) error { return func(initPath string) error {
return initlayer.Setup(initPath, idMapping.RootPair()) return initlayer.Setup(initPath, idMapping.RootPair())
} }
} }

View File

@ -23,7 +23,6 @@ import (
winlibnetwork "github.com/docker/docker/libnetwork/drivers/windows" winlibnetwork "github.com/docker/docker/libnetwork/drivers/windows"
"github.com/docker/docker/libnetwork/netlabel" "github.com/docker/docker/libnetwork/netlabel"
"github.com/docker/docker/libnetwork/options" "github.com/docker/docker/libnetwork/options"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/parsers/operatingsystem" "github.com/docker/docker/pkg/parsers/operatingsystem"
@ -64,7 +63,7 @@ func (daemon *Daemon) parseSecurityOpt(container *container.Container, hostConfi
return nil return nil
} }
func setupInitLayer(idMapping idtools.IdentityMapping) func(containerfs.ContainerFS) error { func setupInitLayer(idMapping idtools.IdentityMapping) func(string) error {
return nil return nil
} }

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/docker/container" "github.com/docker/docker/container"
"github.com/docker/docker/errdefs" "github.com/docker/docker/errdefs"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/chrootarchive"
"github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/ioutils"
) )
@ -61,10 +62,10 @@ func (daemon *Daemon) containerExport(container *container.Container) (arch io.R
return nil, err return nil, err
} }
archv, err := archivePath(basefs, basefs.Path(), &archive.TarOptions{ archv, err := chrootarchive.Tar(basefs, &archive.TarOptions{
Compression: archive.Uncompressed, Compression: archive.Uncompressed,
IDMap: daemon.idMapping, IDMap: daemon.idMapping,
}, basefs.Path()) }, basefs)
if err != nil { if err != nil {
rwlayer.Unmount() rwlayer.Unmount()
return nil, err return nil, err

View File

@ -351,12 +351,12 @@ func atomicRemove(source string) error {
// Get returns the rootfs path for the id. // Get returns the rootfs path for the id.
// This will mount the dir at its given path // 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) a.locker.Lock(id)
defer a.locker.Unlock(id) defer a.locker.Unlock(id)
parents, err := a.getParentLayerPaths(id) parents, err := a.getParentLayerPaths(id)
if err != nil && !os.IsNotExist(err) { if err != nil && !os.IsNotExist(err) {
return nil, err return "", err
} }
a.pathCacheLock.Lock() 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 { 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 // If a dir does not have a parent ( no layers )do not try to mount
// just return the diff path to the data // just return the diff path to the data
if len(parents) > 0 { if len(parents) > 0 {
if err := a.mount(id, m, mountLabel, parents); err != nil { if err := a.mount(id, m, mountLabel, parents); err != nil {
return nil, err return "", err
} }
} }
a.pathCacheLock.Lock() a.pathCacheLock.Lock()
a.pathCache[id] = m a.pathCache[id] = m
a.pathCacheLock.Unlock() a.pathCacheLock.Unlock()
return containerfs.NewLocalContainerFS(m), nil return m, nil
} }
// Put unmounts and updates list of active mounts. // Put unmounts and updates list of active mounts.

View File

@ -43,14 +43,6 @@ func testInit(dir string, t testing.TB) graphdriver.Driver {
return d 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 { func newDriver(t testing.TB) *Driver {
if err := os.MkdirAll(tmp, 0755); err != nil { if err := os.MkdirAll(tmp, 0755); err != nil {
t.Fatal(err) t.Fatal(err)
@ -180,7 +172,7 @@ func TestGetWithoutParent(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
expected := path.Join(tmp, "diff", "1") expected := path.Join(tmp, "diff", "1")
if diffPath.Path() != expected { if diffPath != expected {
t.Fatalf("Expected path %s got %s", expected, diffPath) t.Fatalf("Expected path %s got %s", expected, diffPath)
} }
} }
@ -257,13 +249,13 @@ func TestMountWithParent(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if mntPath == nil { if mntPath == "" {
t.Fatal("mntPath should not be nil") t.Fatal("mntPath should not be empty")
} }
expected := path.Join(tmp, "mnt", "2") expected := path.Join(tmp, "mnt", "2")
if mntPath.Path() != expected { if mntPath != expected {
t.Fatalf("Expected %s got %s", expected, mntPath.Path()) t.Fatalf("Expected %s got %s", expected, mntPath)
} }
} }
@ -288,8 +280,8 @@ func TestRemoveMountedDir(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if mntPath == nil { if mntPath == "" {
t.Fatal("mntPath should not be nil") t.Fatal("mntPath should not be empty")
} }
mounted, err := d.mounted(d.pathCache["2"]) mounted, err := d.mounted(d.pathCache["2"])
@ -323,7 +315,7 @@ func TestGetDiff(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
diffPath, err := driverGet(d, "1", "") diffPath, err := d.Get("1", "")
if err != nil { if err != nil {
t.Fatal(err) 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -406,7 +398,7 @@ func TestChanges(t *testing.T) {
if err := d.CreateReadWrite("3", "2", nil); err != nil { if err := d.CreateReadWrite("3", "2", nil); err != nil {
t.Fatal(err) t.Fatal(err)
} }
mntPoint, err = driverGet(d, "3", "") mntPoint, err = d.Get("3", "")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -452,7 +444,7 @@ func TestDiffSize(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
diffPath, err := driverGet(d, "1", "") diffPath, err := d.Get("1", "")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -494,7 +486,7 @@ func TestChildDiffSize(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
diffPath, err := driverGet(d, "1", "") diffPath, err := d.Get("1", "")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -595,7 +587,7 @@ func TestApplyDiff(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
diffPath, err := driverGet(d, "1", "") diffPath, err := d.Get("1", "")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -630,7 +622,7 @@ func TestApplyDiff(t *testing.T) {
// Ensure that the file is in the mount point for id 3 // 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -673,7 +665,7 @@ func testMountMoreThan42Layers(t *testing.T, mountPath string) {
err := d.CreateReadWrite(current, parent, nil) err := d.CreateReadWrite(current, parent, nil)
assert.NilError(t, err, "current layer %d", i) 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) assert.NilError(t, err, "current layer %d", i)
f, err := os.Create(path.Join(point, current)) 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 // Perform the actual mount for the top most image
point, err := driverGet(d, last, "") point, err := d.Get(last, "")
assert.NilError(t, err) assert.NilError(t, err)
files, err := os.ReadDir(point) files, err := os.ReadDir(point)
assert.NilError(t, err) assert.NilError(t, err)

View File

@ -627,29 +627,29 @@ func (d *Driver) Remove(id string) error {
} }
// Get the requested filesystem id. // 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) dir := d.subvolumesDirID(id)
st, err := os.Stat(dir) st, err := os.Stat(dir)
if err != nil { if err != nil {
return nil, err return "", err
} }
if !st.IsDir() { 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 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 size, err := strconv.ParseUint(string(quota), 10, 64); err == nil && size >= d.options.minSpace {
if err := d.enableQuota(); err != nil { if err := d.enableQuota(); err != nil {
return nil, err return "", err
} }
if err := subvolLimitQgroup(dir, size); err != nil { 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. // Put is not implemented for BTRFS as there is no cleanup required for the id.

View File

@ -36,14 +36,12 @@ func TestBtrfsSubvolDelete(t *testing.T) {
} }
defer graphtest.PutDriver(t) defer graphtest.PutDriver(t)
dirFS, err := d.Get("test", "") dir, err := d.Get("test", "")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer d.Put("test") defer d.Put("test")
dir := dirFS.Path()
if err := subvolCreate(dir, "subvoltest"); err != nil { if err := subvolCreate(dir, "subvoltest"); err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -10,7 +10,6 @@ import (
"strconv" "strconv"
"github.com/docker/docker/daemon/graphdriver" "github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/devicemapper" "github.com/docker/docker/pkg/devicemapper"
"github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/idtools"
units "github.com/docker/go-units" 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 // 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) d.locker.Lock(id)
defer d.locker.Unlock(id) defer d.locker.Unlock(id)
mp := path.Join(d.home, "mnt", id) mp := path.Join(d.home, "mnt", id)
rootFs := path.Join(mp, "rootfs") rootFs := path.Join(mp, "rootfs")
if count := d.ctr.Increment(mp); count > 1 { if count := d.ctr.Increment(mp); count > 1 {
return containerfs.NewLocalContainerFS(rootFs), nil return rootFs, nil
} }
root := d.idMap.RootPair() 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 // Create the target directories if they don't exist
if err := idtools.MkdirAllAndChown(path.Join(d.home, "mnt"), 0755, root); err != nil { if err := idtools.MkdirAllAndChown(path.Join(d.home, "mnt"), 0755, root); err != nil {
d.ctr.Decrement(mp) d.ctr.Decrement(mp)
return nil, err return "", err
} }
if err := idtools.MkdirAndChown(mp, 0755, root); err != nil && !os.IsExist(err) { if err := idtools.MkdirAndChown(mp, 0755, root); err != nil && !os.IsExist(err) {
d.ctr.Decrement(mp) d.ctr.Decrement(mp)
return nil, err return "", err
} }
// Mount the device // Mount the device
if err := d.DeviceSet.MountDevice(id, mp, mountLabel); err != nil { if err := d.DeviceSet.MountDevice(id, mp, mountLabel); err != nil {
d.ctr.Decrement(mp) d.ctr.Decrement(mp)
return nil, err return "", err
} }
if err := idtools.MkdirAllAndChown(rootFs, 0755, root); err != nil { if err := idtools.MkdirAllAndChown(rootFs, 0755, root); err != nil {
d.ctr.Decrement(mp) d.ctr.Decrement(mp)
d.DeviceSet.UnmountDevice(id, mp) d.DeviceSet.UnmountDevice(id, mp)
return nil, err return "", err
} }
idFile := path.Join(mp, "id") 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 { if err := os.WriteFile(idFile, []byte(id), 0600); err != nil {
d.ctr.Decrement(mp) d.ctr.Decrement(mp)
d.DeviceSet.UnmountDevice(id, 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. // Put unmounts a device and removes it.

View File

@ -7,7 +7,6 @@ import (
"strings" "strings"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/plugingetter" "github.com/docker/docker/pkg/plugingetter"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -60,7 +59,7 @@ type ProtoDriver interface {
// Get returns the mountpoint for the layered filesystem referred // Get returns the mountpoint for the layered filesystem referred
// to by this id. You can optionally specify a mountLabel or "". // to by this id. You can optionally specify a mountLabel or "".
// Returns the absolute path to the mounted layered filesystem. // 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, // Put releases the system resources for the specified id,
// e.g, unmounting layered filesystem. // e.g, unmounting layered filesystem.
Put(id string) error Put(id string) error

View File

@ -50,7 +50,7 @@ func (gdw *NaiveDiffDriver) Diff(id, parent string) (arch io.ReadCloser, err err
if err != nil { if err != nil {
return nil, err return nil, err
} }
layerFs := layerRootFs.Path() layerFs := layerRootFs
defer func() { defer func() {
if err != nil { if err != nil {
@ -70,14 +70,12 @@ func (gdw *NaiveDiffDriver) Diff(id, parent string) (arch io.ReadCloser, err err
}), nil }), nil
} }
parentRootFs, err := driver.Get(parent, "") parentFs, err := driver.Get(parent, "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer driver.Put(parent) defer driver.Put(parent)
parentFs := parentRootFs.Path()
changes, err := archive.ChangesDirs(layerFs, parentFs) changes, err := archive.ChangesDirs(layerFs, parentFs)
if err != nil { if err != nil {
return nil, err 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) { func (gdw *NaiveDiffDriver) Changes(id, parent string) ([]archive.Change, error) {
driver := gdw.ProtoDriver driver := gdw.ProtoDriver
layerRootFs, err := driver.Get(id, "") layerFs, err := driver.Get(id, "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer driver.Put(id) defer driver.Put(id)
layerFs := layerRootFs.Path()
parentFs := "" parentFs := ""
if parent != "" { if parent != "" {
parentRootFs, err := driver.Get(parent, "") parentFs, err = driver.Get(parent, "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer driver.Put(parent) defer driver.Put(parent)
parentFs = parentRootFs.Path()
} }
return archive.ChangesDirs(layerFs, parentFs) 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) defer driver.Put(id)
layerFs := layerRootFs.Path() layerFs := layerRootFs
options := &archive.TarOptions{IDMap: gdw.idMap} options := &archive.TarOptions{IDMap: gdw.idMap}
start := time.Now().UTC() start := time.Now().UTC()
logrus.WithField("id", id).Debug("Start untar layer") 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) defer driver.Put(id)
return archive.ChangesSize(layerFs.Path(), changes), nil return archive.ChangesSize(layerFs, changes), nil
} }

View File

@ -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. // 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) d.locker.Lock(id)
defer d.locker.Unlock(id) defer d.locker.Unlock(id)
dir := d.dir(id) dir := d.dir(id)
if _, err := os.Stat(dir); err != nil { if _, err := os.Stat(dir); err != nil {
return nil, err return "", err
} }
diffDir := path.Join(dir, diffDirName) diffDir := path.Join(dir, diffDirName)
@ -316,14 +316,14 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
if err != nil { if err != nil {
// If no lower, just return diff directory // If no lower, just return diff directory
if os.IsNotExist(err) { if os.IsNotExist(err) {
return containerfs.NewLocalContainerFS(diffDir), nil return diffDir, nil
} }
return nil, err return "", err
} }
mergedDir := path.Join(dir, mergedDirName) mergedDir := path.Join(dir, mergedDirName)
if count := d.ctr.Increment(mergedDir); count > 1 { if count := d.ctr.Increment(mergedDir); count > 1 {
return containerfs.NewLocalContainerFS(mergedDir), nil return mergedDir, nil
} }
defer func() { defer func() {
if retErr != nil { 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 { if _, err := os.Stat(path.Join(dir, "committed")); err == nil {
readonly = true readonly = true
} else if !os.IsNotExist(err) { } else if !os.IsNotExist(err) {
return nil, err return "", err
} }
var opts string var opts string
@ -365,7 +365,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
mountTarget := mergedDir mountTarget := mergedDir
if err := idtools.MkdirAndChown(mergedDir, 0700, d.idMap.RootPair()); err != nil { if err := idtools.MkdirAndChown(mergedDir, 0700, d.idMap.RootPair()); err != nil {
return nil, err return "", err
} }
mountProgram := exec.Command(binary, "-o", mountData, mountTarget) mountProgram := exec.Command(binary, "-o", mountData, mountTarget)
@ -377,10 +377,10 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
if output == "" { if output == "" {
output = "<stderr empty>" 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. // Put unmounts the mount path created for the give id.

View File

@ -5,9 +5,10 @@ package graphtest // import "github.com/docker/docker/daemon/graphdriver/graphte
import ( import (
"io" "io"
"os"
"path/filepath"
"testing" "testing"
contdriver "github.com/containerd/continuity/driver"
"github.com/docker/docker/pkg/stringid" "github.com/docker/docker/pkg/stringid"
"gotest.tools/v3/assert" "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++ { for i := 0; i < b.N; i++ {
// Read content // 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 { if err != nil {
b.Fatal(err) b.Fatal(err)
} }

View File

@ -96,10 +96,10 @@ func DriverTestCreateEmpty(t testing.TB, drivername string, driverOptions ...str
dir, err := driver.Get("empty", "") dir, err := driver.Get("empty", "")
assert.NilError(t, err) 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 // Verify that the directory is empty
fis, err := readDir(dir, dir.Path()) fis, err := readDir(dir)
assert.NilError(t, err) assert.NilError(t, err)
assert.Check(t, is.Len(fis, 0)) 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) quota := uint64(50 * units.MiB)
// Try to write a file smaller than quota, and ensure it works // 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 { if err != nil {
t.Fatal(err) 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 // 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 { if err == nil {
t.Fatalf("expected write to fail(), instead had success") t.Fatalf("expected write to fail(), instead had success")
} }
if pathError, ok := err.(*os.PathError); ok && pathError.Err != unix.EDQUOT && pathError.Err != unix.ENOSPC { 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) t.Fatalf("expect write() to fail with %v or %v, got %v", unix.EDQUOT, unix.ENOSPC, pathError.Err)
} }
} }

View File

@ -3,11 +3,12 @@ package graphtest // import "github.com/docker/docker/daemon/graphdriver/graphte
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"io/fs"
"math/rand" "math/rand"
"os" "os"
"path/filepath"
"sort" "sort"
"github.com/containerd/continuity/driver"
"github.com/docker/docker/daemon/graphdriver" "github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/stringid" "github.com/docker/docker/pkg/stringid"
@ -35,17 +36,17 @@ func addFiles(drv graphdriver.Driver, layer string, seed int64) error {
} }
defer drv.Put(layer) 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 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 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 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 { 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) 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 { if err != nil {
return err return err
} }
@ -74,7 +75,7 @@ func addFile(drv graphdriver.Driver, layer, filename string, content []byte) err
} }
defer drv.Put(layer) 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 { 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) 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 { 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) defer drv.Put(layer)
for _, filename := range names { 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 return err
} }
} }
@ -109,8 +110,8 @@ func checkFileRemoved(drv graphdriver.Driver, layer, filename string) error {
} }
defer drv.Put(layer) defer drv.Put(layer)
if _, err := root.Stat(root.Join(root.Path(), filename)); err == nil { if _, err := os.Stat(filepath.Join(root, filename)); err == nil {
return fmt.Errorf("file still exists: %s", root.Join(root.Path(), filename)) return fmt.Errorf("file still exists: %s", filepath.Join(root, filename))
} else if !os.IsNotExist(err) { } else if !os.IsNotExist(err) {
return err return err
} }
@ -126,13 +127,13 @@ func addManyFiles(drv graphdriver.Driver, layer string, count int, seed int64) e
defer drv.Put(layer) defer drv.Put(layer)
for i := 0; i < count; i += 100 { 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))
if err := root.MkdirAll(dir, 0755); err != nil { if err := os.MkdirAll(dir, 0755); err != nil {
return err return err
} }
for j := 0; i+j < count && j < 100; j++ { for j := 0; i+j < count && j < 100; j++ {
file := root.Join(dir, fmt.Sprintf("file-%d", i+j)) file := filepath.Join(dir, fmt.Sprintf("file-%d", i+j))
if err := driver.WriteFile(root, file, randomContent(64, seed+int64(i+j)), 0755); err != nil { if err := os.WriteFile(file, randomContent(64, seed+int64(i+j)), 0755); err != nil {
return err return err
} }
} }
@ -151,7 +152,7 @@ func changeManyFiles(drv graphdriver.Driver, layer string, count int, seed int64
var changes []archive.Change var changes []archive.Change
for i := 0; i < count; i += 100 { for i := 0; i < count; i += 100 {
archiveRoot := fmt.Sprintf("/directory-%d", i) 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 return nil, err
} }
for j := 0; i+j < count && j < 100; j++ { 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 { switch j % 3 {
// Update file // Update file
case 0: 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 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 return nil, err
} }
// Add file // Add file
case 1: 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 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 return nil, err
} }
// Remove file // Remove file
case 2: 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 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 return nil, err
} }
} }
@ -200,10 +201,10 @@ func checkManyFiles(drv graphdriver.Driver, layer string, count int, seed int64)
defer drv.Put(layer) defer drv.Put(layer)
for i := 0; i < count; i += 100 { 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++ { for j := 0; i+j < count && j < 100; j++ {
file := root.Join(dir, fmt.Sprintf("file-%d", i+j)) file := filepath.Join(dir, fmt.Sprintf("file-%d", i+j))
fileContent, err := driver.ReadFile(root, file) fileContent, err := os.ReadFile(file)
if err != nil { if err != nil {
return err return err
} }
@ -253,17 +254,17 @@ func addLayerFiles(drv graphdriver.Driver, layer, parent string, i int) error {
} }
defer drv.Put(layer) 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 return err
} }
layerDir := root.Join(root.Path(), fmt.Sprintf("layer-%d", i)) layerDir := filepath.Join(root, fmt.Sprintf("layer-%d", i))
if err := root.MkdirAll(layerDir, 0755); err != nil { if err := os.MkdirAll(layerDir, 0755); err != nil {
return err 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 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) { 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) 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 { if err != nil {
return err return err
} }
@ -300,16 +301,16 @@ func checkManyLayers(drv graphdriver.Driver, layer string, count int) error {
} }
for i := count; i > 0; i-- { 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 { if err != nil {
return err return err
} }
if !bytes.Equal(thisLayerIDBytes, layerIDBytes) { if !bytes.Equal(thisLayerIDBytes, layerIDBytes) {
return fmt.Errorf("mismatched file content %v, expecting %v", 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 { if err != nil {
return err return err
} }
@ -317,11 +318,11 @@ func checkManyLayers(drv graphdriver.Driver, layer string, count int) error {
return nil 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") // then hides specific files (currently "lost+found")
// so the tests don't "see" it // so the tests don't "see" it
func readDir(r driver.Driver, dir string) ([]os.FileInfo, error) { func readDir(dir string) ([]fs.DirEntry, error) {
a, err := driver.ReadDir(r, dir) a, err := os.ReadDir(dir)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -5,6 +5,7 @@ package graphtest // import "github.com/docker/docker/daemon/graphdriver/graphte
import ( import (
"os" "os"
"path/filepath"
"syscall" "syscall"
"testing" "testing"
@ -44,12 +45,12 @@ func createBase(t testing.TB, driver graphdriver.Driver, name string) {
assert.NilError(t, err) assert.NilError(t, err)
defer driver.Put(name) defer driver.Put(name)
subdir := dirFS.Join(dirFS.Path(), "a subdir") subdir := filepath.Join(dirFS, "a subdir")
assert.NilError(t, dirFS.Mkdir(subdir, 0705|os.ModeSticky)) assert.NilError(t, os.Mkdir(subdir, 0705|os.ModeSticky))
assert.NilError(t, dirFS.Lchown(subdir, 1, 2)) assert.NilError(t, contdriver.LocalDriver.Lchown(subdir, 1, 2))
file := dirFS.Join(dirFS.Path(), "a file") file := filepath.Join(dirFS, "a file")
err = contdriver.WriteFile(dirFS, file, []byte("Some data"), 0222|os.ModeSetuid) err = os.WriteFile(file, []byte("Some data"), 0222|os.ModeSetuid)
assert.NilError(t, err) assert.NilError(t, err)
} }
@ -58,13 +59,13 @@ func verifyBase(t testing.TB, driver graphdriver.Driver, name string) {
assert.NilError(t, err) assert.NilError(t, err)
defer driver.Put(name) 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) 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) verifyFile(t, file, 0222|os.ModeSetuid, 0, 0)
files, err := readDir(dirFS, dirFS.Path()) files, err := readDir(dirFS)
assert.NilError(t, err) assert.NilError(t, err)
assert.Check(t, is.Len(files, 2)) assert.Check(t, is.Len(files, 2))
} }

View File

@ -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. // 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) d.locker.Lock(id)
defer d.locker.Unlock(id) defer d.locker.Unlock(id)
dir := d.dir(id) dir := d.dir(id)
if _, err := os.Stat(dir); err != nil { if _, err := os.Stat(dir); err != nil {
return nil, err return "", err
} }
// If id has a root, just return it // If id has a root, just return it
rootDir := path.Join(dir, "root") rootDir := path.Join(dir, "root")
if _, err := os.Stat(rootDir); err == nil { if _, err := os.Stat(rootDir); err == nil {
return containerfs.NewLocalContainerFS(rootDir), nil return rootDir, nil
} }
mergedDir := path.Join(dir, "merged") mergedDir := path.Join(dir, "merged")
if count := d.ctr.Increment(mergedDir); count > 1 { if count := d.ctr.Increment(mergedDir); count > 1 {
return containerfs.NewLocalContainerFS(mergedDir), nil return mergedDir, nil
} }
defer func() { defer func() {
if err != nil { 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")) lowerID, err := os.ReadFile(path.Join(dir, "lower-id"))
if err != nil { if err != nil {
return nil, err return "", err
} }
root := d.idMap.RootPair() root := d.idMap.RootPair()
if err := idtools.MkdirAndChown(mergedDir, 0700, root); err != nil { if err := idtools.MkdirAndChown(mergedDir, 0700, root); err != nil {
return nil, err return "", err
} }
var ( var (
lowerDir = path.Join(d.dir(string(lowerID)), "root") 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) 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 { 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 // 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. // user namespace requires this to move a directory from lower to upper.
if err := root.Chown(path.Join(workDir, "work")); err != nil { 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. // Put unmounts the mount path created for the give id.

View File

@ -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. // 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) d.locker.Lock(id)
defer d.locker.Unlock(id) defer d.locker.Unlock(id)
dir := d.dir(id) dir := d.dir(id)
if _, err := os.Stat(dir); err != nil { if _, err := os.Stat(dir); err != nil {
return nil, err return "", err
} }
diffDir := path.Join(dir, diffDirName) diffDir := path.Join(dir, diffDirName)
@ -526,14 +526,14 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
if err != nil { if err != nil {
// If no lower, just return diff directory // If no lower, just return diff directory
if os.IsNotExist(err) { if os.IsNotExist(err) {
return containerfs.NewLocalContainerFS(diffDir), nil return diffDir, nil
} }
return nil, err return "", err
} }
mergedDir := path.Join(dir, mergedDirName) mergedDir := path.Join(dir, mergedDirName)
if count := d.ctr.Increment(mergedDir); count > 1 { if count := d.ctr.Increment(mergedDir); count > 1 {
return containerfs.NewLocalContainerFS(mergedDir), nil return mergedDir, nil
} }
defer func() { defer func() {
if retErr != nil { 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 { if _, err := os.Stat(path.Join(dir, "committed")); err == nil {
readonly = true readonly = true
} else if !os.IsNotExist(err) { } else if !os.IsNotExist(err) {
return nil, err return "", err
} }
var opts string var opts string
@ -575,7 +575,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
root := d.idMap.RootPair() root := d.idMap.RootPair()
if err := idtools.MkdirAndChown(mergedDir, 0700, root); err != nil { if err := idtools.MkdirAndChown(mergedDir, 0700, root); err != nil {
return nil, err return "", err
} }
pageSize := unix.Getpagesize() pageSize := unix.Getpagesize()
@ -592,7 +592,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
} }
mountData = label.FormatMountLabel(opts, mountLabel) mountData = label.FormatMountLabel(opts, mountLabel)
if len(mountData) > pageSize-1 { 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 { 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 { 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 { if !readonly {
// chown "workdir/work" to the remapped root UID/GID. Overlay fs inside a // 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. // user namespace requires this to move a directory from lower to upper.
if err := root.Chown(path.Join(workDir, workDirName)); err != nil { 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. // Put unmounts the mount path created for the give id.

View File

@ -6,7 +6,6 @@ import (
"io" "io"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/plugingetter" "github.com/docker/docker/pkg/plugingetter"
"github.com/docker/docker/pkg/plugins" "github.com/docker/docker/pkg/plugins"
@ -128,20 +127,20 @@ func (d *graphDriverProxy) Remove(id string) error {
return nil return nil
} }
func (d *graphDriverProxy) Get(id, mountLabel string) (containerfs.ContainerFS, error) { func (d *graphDriverProxy) Get(id, mountLabel string) (string, error) {
args := &graphDriverRequest{ args := &graphDriverRequest{
ID: id, ID: id,
MountLabel: mountLabel, MountLabel: mountLabel,
} }
var ret graphDriverResponse var ret graphDriverResponse
if err := d.client.Call("GraphDriver.Get", args, &ret); err != nil { if err := d.client.Call("GraphDriver.Get", args, &ret); err != nil {
return nil, err return "", err
} }
var err error var err error
if ret.Err != "" { if ret.Err != "" {
err = errors.New(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 { func (d *graphDriverProxy) Put(id string) error {

View File

@ -172,7 +172,7 @@ func (d *Driver) create(id, parent string, size uint64) error {
if err != nil { if err != nil {
return fmt.Errorf("%s: %s", parent, err) return fmt.Errorf("%s: %s", parent, err)
} }
return CopyDir(parentDir.Path(), dir) return CopyDir(parentDir, dir)
} }
func (d *Driver) dir(id string) string { 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. // 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) dir := d.dir(id)
if st, err := os.Stat(dir); err != nil { if st, err := os.Stat(dir); err != nil {
return nil, err return "", err
} else if !st.IsDir() { } 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. // Put is a noop for vfs that return nil for the error, since this driver has no runtime resources to clean up.

View File

@ -27,7 +27,6 @@ import (
"github.com/Microsoft/hcsshim/osversion" "github.com/Microsoft/hcsshim/osversion"
"github.com/docker/docker/daemon/graphdriver" "github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/longpath" "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. // 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) logrus.Debugf("WindowsGraphDriver Get() id %s mountLabel %s", id, mountLabel)
var dir string var dir string
rID, err := d.resolveID(id) rID, err := d.resolveID(id)
if err != nil { if err != nil {
return nil, err return "", err
} }
if count := d.ctr.Increment(rID); count > 1 { 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. // Getting the layer paths must be done outside of the lock.
layerChain, err := d.getLayerChain(rID) layerChain, err := d.getLayerChain(rID)
if err != nil { if err != nil {
d.ctr.Decrement(rID) d.ctr.Decrement(rID)
return nil, err return "", err
} }
if err := hcsshim.ActivateLayer(d.info, rID); err != nil { if err := hcsshim.ActivateLayer(d.info, rID); err != nil {
d.ctr.Decrement(rID) d.ctr.Decrement(rID)
return nil, err return "", err
} }
if err := hcsshim.PrepareLayer(d.info, rID, layerChain); err != nil { if err := hcsshim.PrepareLayer(d.info, rID, layerChain); err != nil {
d.ctr.Decrement(rID) d.ctr.Decrement(rID)
if err2 := hcsshim.DeactivateLayer(d.info, rID); err2 != nil { if err2 := hcsshim.DeactivateLayer(d.info, rID); err2 != nil {
logrus.Warnf("Failed to Deactivate %s: %s", id, err) logrus.Warnf("Failed to Deactivate %s: %s", id, err)
} }
return nil, err return "", err
} }
mountPath, err := hcsshim.GetLayerMountPath(d.info, rID) 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 { if err2 := hcsshim.DeactivateLayer(d.info, rID); err2 != nil {
logrus.Warnf("Failed to Deactivate %s: %s", id, err) logrus.Warnf("Failed to Deactivate %s: %s", id, err)
} }
return nil, err return "", err
} }
d.cacheMu.Lock() d.cacheMu.Lock()
d.cache[rID] = mountPath d.cache[rID] = mountPath
@ -447,7 +446,7 @@ func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
dir = d.dir(id) dir = d.dir(id)
} }
return containerfs.NewLocalContainerFS(dir), nil return dir, nil
} }
// Put adds a new layer to the driver. // 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) defer d.Put(id)
return archive.ChangesSize(layerFs.Path(), changes), nil return archive.ChangesSize(layerFs, changes), nil
} }
// GetMetadata returns custom driver information. // GetMetadata returns custom driver information.

View File

@ -14,7 +14,6 @@ import (
"time" "time"
"github.com/docker/docker/daemon/graphdriver" "github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers"
zfs "github.com/mistifyio/go-zfs" 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. // 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) d.locker.Lock(id)
defer d.locker.Unlock(id) defer d.locker.Unlock(id)
mountpoint := d.mountPath(id) mountpoint := d.mountPath(id)
if count := d.ctr.Increment(mountpoint); count > 1 { if count := d.ctr.Increment(mountpoint); count > 1 {
return containerfs.NewLocalContainerFS(mountpoint), nil return mountpoint, nil
} }
defer func() { defer func() {
if retErr != nil { if retErr != nil {
@ -391,20 +390,20 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
root := d.idMap.RootPair() root := d.idMap.RootPair()
// Create the target directories if they don't exist // Create the target directories if they don't exist
if err := idtools.MkdirAllAndChown(mountpoint, 0755, root); err != nil { if err := idtools.MkdirAllAndChown(mountpoint, 0755, root); err != nil {
return nil, err return "", err
} }
if err := mount.Mount(filesystem, mountpoint, "zfs", options); err != nil { 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 // 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): // permissions instead of the remapped root uid:gid (if user namespaces are enabled):
if err := root.Chown(mountpoint); err != nil { 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. // Put removes the existing mountpoint for the given id if it exists.

View File

@ -14,7 +14,6 @@ import (
"github.com/docker/docker/errdefs" "github.com/docker/docker/errdefs"
"github.com/docker/docker/image" "github.com/docker/docker/image"
"github.com/docker/docker/layer" "github.com/docker/docker/layer"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/progress" "github.com/docker/docker/pkg/progress"
"github.com/docker/docker/pkg/streamformatter" "github.com/docker/docker/pkg/streamformatter"
"github.com/docker/docker/pkg/stringid" "github.com/docker/docker/pkg/stringid"
@ -83,10 +82,10 @@ type rwLayer struct {
released bool released bool
layerStore layer.Store layerStore layer.Store
rwLayer layer.RWLayer rwLayer layer.RWLayer
fs containerfs.ContainerFS fs string
} }
func (l *rwLayer) Root() containerfs.ContainerFS { func (l *rwLayer) Root() string {
return l.fs return l.fs
} }
@ -115,11 +114,11 @@ func (l *rwLayer) Release() error {
return nil return nil
} }
if l.fs != nil { if l.fs != "" {
if err := l.rwLayer.Unmount(); err != nil { if err := l.rwLayer.Unmount(); err != nil {
return errors.Wrap(err, "failed to unmount RWLayer") return errors.Wrap(err, "failed to unmount RWLayer")
} }
l.fs = nil l.fs = ""
} }
metadata, err := l.layerStore.ReleaseRWLayer(l.rwLayer) metadata, err := l.layerStore.ReleaseRWLayer(l.rwLayer)

View File

@ -8,7 +8,6 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/idtools"
"golang.org/x/sys/unix" "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 // 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. // 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() // 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{ for pth, typ := range map[string]string{
"/dev/pts": "dir", "/dev/pts": "dir",

View File

@ -9,7 +9,7 @@ import (
// excludeByIsolation is a platform specific helper function to support PS // 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. // filtering by Isolation. This is a Windows-only concept, so is a no-op on Unix.
func excludeByIsolation(container *container.Snapshot, ctx *listContext) iterationAction { func excludeByIsolation(container *container.Snapshot, ctx *listContext) iterationAction {
i := strings.ToLower(string(container.HostConfig.Isolation)) i := strings.ToLower(container.HostConfig.Isolation)
if i == "" { if i == "" {
i = "default" i = "default"
} }

View File

@ -721,8 +721,8 @@ func sysctlExists(s string) bool {
// WithCommonOptions sets common docker options // WithCommonOptions sets common docker options
func WithCommonOptions(daemon *Daemon, c *container.Container) coci.SpecOpts { func WithCommonOptions(daemon *Daemon, c *container.Container) coci.SpecOpts {
return func(ctx context.Context, _ coci.Client, _ *containers.Container, s *coci.Spec) error { return func(ctx context.Context, _ coci.Client, _ *containers.Container, s *coci.Spec) error {
if c.BaseFS == nil && !daemon.UsesSnapshotter() { if c.BaseFS == "" && !daemon.UsesSnapshotter() {
return errors.New("populateCommonSpec: BaseFS of container " + c.ID + " is unexpectedly nil") return errors.New("populateCommonSpec: BaseFS of container " + c.ID + " is unexpectedly empty")
} }
linkedEnv, err := daemon.setupLinkedContainers(c) linkedEnv, err := daemon.setupLinkedContainers(c)
if err != nil { if err != nil {
@ -730,7 +730,7 @@ func WithCommonOptions(daemon *Daemon, c *container.Container) coci.SpecOpts {
} }
if !daemon.UsesSnapshotter() { if !daemon.UsesSnapshotter() {
s.Root = &specs.Root{ s.Root = &specs.Root{
Path: c.BaseFS.Path(), Path: c.BaseFS,
Readonly: c.HostConfig.ReadonlyRootfs, Readonly: c.HostConfig.ReadonlyRootfs,
} }
} }

View File

@ -10,7 +10,6 @@ import (
"github.com/docker/docker/daemon/config" "github.com/docker/docker/daemon/config"
"github.com/docker/docker/daemon/network" "github.com/docker/docker/daemon/network"
"github.com/docker/docker/libnetwork" "github.com/docker/docker/libnetwork"
"github.com/docker/docker/pkg/containerfs"
"gotest.tools/v3/assert" "gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp" is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/skip" "gotest.tools/v3/skip"
@ -36,7 +35,7 @@ func setupFakeDaemon(t *testing.T, c *container.Container) *Daemon {
} }
c.Root = root c.Root = root
c.BaseFS = containerfs.NewLocalContainerFS(rootfs) c.BaseFS = rootfs
if c.Config == nil { if c.Config == nil {
c.Config = new(containertypes.Config) c.Config = new(containertypes.Config)

View File

@ -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 s.Root.Readonly = false // Windows does not support a read-only root filesystem
if !isHyperV { if !isHyperV {
if c.BaseFS == nil { if c.BaseFS == "" {
return errors.New("createSpecWindowsFields: BaseFS of container " + c.ID + " is unexpectedly nil") 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, `\`) { if !strings.HasSuffix(s.Root.Path, `\`) {
s.Root.Path = s.Root.Path + `\` // Ensure a correctly formatted volume GUID path \\?\Volume{GUID}\ s.Root.Path = s.Root.Path + `\` // Ensure a correctly formatted volume GUID path \\?\Volume{GUID}\
} }

View File

@ -251,7 +251,7 @@ func (daemon *Daemon) Cleanup(container *container.Container) {
daemon.unregisterExecCommand(container, eConfig) daemon.unregisterExecCommand(container, eConfig)
} }
if container.BaseFS != nil && container.BaseFS.Path() != "" { if container.BaseFS != "" {
if err := container.UnmountVolumes(daemon.LogVolumeEvent); err != nil { if err := container.UnmountVolumes(daemon.LogVolumeEvent); err != nil {
logrus.Warnf("%s cleanup: Failed to umount volumes: %v", container.ID, err) logrus.Warnf("%s cleanup: Failed to umount volumes: %v", container.ID, err)
} }

View File

@ -213,13 +213,12 @@ func setupPlugin(t *testing.T, ec map[string]*graphEventsCounter, ext string, mu
return return
} }
// TODO @gupta-ak: Figure out what to do here.
dir, err := driver.Get(req.ID, req.MountLabel) dir, err := driver.Get(req.ID, req.MountLabel)
if err != nil { if err != nil {
respond(w, err) respond(w, err)
return return
} }
respond(w, &graphDriverResponse{Dir: dir.Path()}) respond(w, &graphDriverResponse{Dir: dir})
}) })
mux.HandleFunc("/GraphDriver.Put", func(w http.ResponseWriter, r *http.Request) { mux.HandleFunc("/GraphDriver.Put", func(w http.ResponseWriter, r *http.Request) {

View File

@ -15,7 +15,6 @@ import (
"github.com/docker/distribution" "github.com/docker/distribution"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/containerfs"
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -114,7 +113,7 @@ type RWLayer interface {
// Mount mounts the RWLayer and returns the filesystem path // Mount mounts the RWLayer and returns the filesystem path
// to the writable layer. // to the writable layer.
Mount(mountLabel string) (containerfs.ContainerFS, error) Mount(mountLabel string) (string, error)
// Unmount unmounts the RWLayer. This should be called // Unmount unmounts the RWLayer. This should be called
// for every mount. If there are multiple mount calls // for every mount. If there are multiple mount calls
@ -158,7 +157,7 @@ type Metadata struct {
// writable mount. Changes made here will // writable mount. Changes made here will
// not be included in the Tar stream of the // not be included in the Tar stream of the
// RWLayer. // RWLayer.
type MountInit func(root containerfs.ContainerFS) error type MountInit func(root string) error
// CreateRWLayerOpts contains optional arguments to be passed to CreateRWLayer // CreateRWLayerOpts contains optional arguments to be passed to CreateRWLayer
type CreateRWLayerOpts struct { type CreateRWLayerOpts struct {

View File

@ -786,5 +786,5 @@ func (n *naiveDiffPathDriver) DiffGetter(id string) (graphdriver.FileGetCloser,
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &fileGetPutter{storage.NewPathFileGetter(p.Path()), n.Driver, id}, nil return &fileGetPutter{storage.NewPathFileGetter(p), n.Driver, id}, nil
} }

View File

@ -13,7 +13,6 @@ import (
"github.com/docker/docker/daemon/graphdriver" "github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/daemon/graphdriver/vfs" "github.com/docker/docker/daemon/graphdriver/vfs"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/stringid" "github.com/docker/docker/pkg/stringid"
"github.com/opencontainers/go-digest" "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) { func createLayer(ls Store, parent ChainID, layerFunc layerInit) (Layer, error) {
containerID := stringid.GenerateRandomID() containerID := stringid.GenerateRandomID()
@ -121,7 +120,7 @@ func createLayer(ls Store, parent ChainID, layerFunc layerInit) (Layer, error) {
} }
type FileApplier interface { type FileApplier interface {
ApplyFile(root containerfs.ContainerFS) error ApplyFile(root string) error
} }
type testFile struct { 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 { func (tf *testFile) ApplyFile(root string) error {
fullPath := root.Join(root.Path(), tf.name) fullPath := filepath.Join(root, tf.name)
if err := root.MkdirAll(root.Dir(fullPath), 0755); err != nil { if err := os.MkdirAll(filepath.Dir(fullPath), 0755); err != nil {
return err return err
} }
// Check if already exists // Check if already exists
if stat, err := root.Stat(fullPath); err == nil && stat.Mode().Perm() != tf.permission { if stat, err := os.Stat(fullPath); err == nil && stat.Mode().Perm() != tf.permission {
if err := root.Lchmod(fullPath, tf.permission); err != nil { if err := driver.LocalDriver.Lchmod(fullPath, tf.permission); err != nil {
return err return err
} }
} }
return driver.WriteFile(root, fullPath, tf.content, tf.permission) return os.WriteFile(fullPath, tf.content, tf.permission)
} }
func initWithFiles(files ...FileApplier) layerInit { func initWithFiles(files ...FileApplier) layerInit {
return func(root containerfs.ContainerFS) error { return func(root string) error {
for _, f := range files { for _, f := range files {
if err := f.ApplyFile(root); err != nil { if err := f.ApplyFile(root); err != nil {
return err return err
@ -267,7 +266,7 @@ func TestMountAndRegister(t *testing.T) {
t.Fatal(err) 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -375,7 +374,7 @@ func TestStoreRestore(t *testing.T) {
t.Fatal(err) 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) t.Fatal(err)
} }
@ -409,20 +408,20 @@ func TestStoreRestore(t *testing.T) {
if mountPath, err := m2.Mount(""); err != nil { if mountPath, err := m2.Mount(""); err != nil {
t.Fatal(err) t.Fatal(err)
} else if pathFS.Path() != mountPath.Path() { } else if pathFS != mountPath {
t.Fatalf("Unexpected path %s, expected %s", mountPath.Path(), pathFS.Path()) t.Fatalf("Unexpected path %s, expected %s", mountPath, pathFS)
} }
if mountPath, err := m2.Mount(""); err != nil { if mountPath, err := m2.Mount(""); err != nil {
t.Fatal(err) t.Fatal(err)
} else if pathFS.Path() != mountPath.Path() { } else if pathFS != mountPath {
t.Fatalf("Unexpected path %s, expected %s", mountPath.Path(), pathFS.Path()) t.Fatalf("Unexpected path %s, expected %s", mountPath, pathFS)
} }
if err := m2.Unmount(); err != nil { if err := m2.Unmount(); err != nil {
t.Fatal(err) 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -597,7 +596,7 @@ func tarFromFiles(files ...FileApplier) ([]byte, error) {
defer os.RemoveAll(td) defer os.RemoveAll(td)
for _, f := range files { for _, f := range files {
if err := f.ApplyFile(containerfs.NewLocalContainerFS(td)); err != nil { if err := f.ApplyFile(td); err != nil {
return nil, err return nil, err
} }
} }

View File

@ -37,7 +37,7 @@ func GetLayerPath(s Store, layer ChainID) (string, error) {
return "", err return "", err
} }
return path.Path(), nil return path, nil
} }
func (ls *layerStore) mountID(name string) string { func (ls *layerStore) mountID(name string) string {

View File

@ -2,13 +2,14 @@ package layer // import "github.com/docker/docker/layer"
import ( import (
"io" "io"
"os"
"path/filepath"
"runtime" "runtime"
"sort" "sort"
"testing" "testing"
"github.com/containerd/continuity/driver" "github.com/containerd/continuity/driver"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/containerfs"
) )
func TestMountInit(t *testing.T) { func TestMountInit(t *testing.T) {
@ -28,7 +29,7 @@ func TestMountInit(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
mountInit := func(root containerfs.ContainerFS) error { mountInit := func(root string) error {
return initfile.ApplyFile(root) return initfile.ApplyFile(root)
} }
@ -45,12 +46,12 @@ func TestMountInit(t *testing.T) {
t.Fatal(err) 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 { if err != nil {
t.Fatal(err) 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -88,7 +89,7 @@ func TestMountSize(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
mountInit := func(root containerfs.ContainerFS) error { mountInit := func(root string) error {
return newTestFile("file-init", contentInit, 0777).ApplyFile(root) return newTestFile("file-init", contentInit, 0777).ApplyFile(root)
} }
rwLayerOpts := &CreateRWLayerOpts{ rwLayerOpts := &CreateRWLayerOpts{
@ -105,7 +106,7 @@ func TestMountSize(t *testing.T) {
t.Fatal(err) 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) t.Fatal(err)
} }
@ -140,7 +141,7 @@ func TestMountChanges(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
mountInit := func(root containerfs.ContainerFS) error { mountInit := func(root string) error {
return initfile.ApplyFile(root) return initfile.ApplyFile(root)
} }
rwLayerOpts := &CreateRWLayerOpts{ rwLayerOpts := &CreateRWLayerOpts{
@ -157,23 +158,23 @@ func TestMountChanges(t *testing.T) {
t.Fatal(err) 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) 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) 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) 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) 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) t.Fatal(err)
} }
@ -248,7 +249,7 @@ func TestMountApply(t *testing.T) {
t.Fatal(err) 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -5,7 +5,6 @@ import (
"sync" "sync"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/containerfs"
) )
type mountedLayer struct { type mountedLayer struct {
@ -100,7 +99,7 @@ type referencedRWLayer struct {
*mountedLayer *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) return rl.layerStore.driver.Get(rl.mountedLayer.mountID, mountLabel)
} }

View File

@ -186,7 +186,7 @@ func (aSpace *addrSpace) UnmarshalJSON(data []byte) error {
aSpace.scope = datastore.LocalScope aSpace.scope = datastore.LocalScope
s := m["Scope"].(string) s := m["Scope"].(string)
if s == string(datastore.GlobalScope) { if s == datastore.GlobalScope {
aSpace.scope = datastore.GlobalScope aSpace.scope = datastore.GlobalScope
} }

View File

@ -26,23 +26,23 @@ var (
// path (from before being processed by utility functions from the path or // path (from before being processed by utility functions from the path or
// filepath stdlib packages) ends with a trailing `/.` or `/`. If the cleaned // 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 // 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. // clean path already ends in a path separator, then another is not added.
func PreserveTrailingDotOrSeparator(cleanedPath string, originalPath string, sep byte) string { func PreserveTrailingDotOrSeparator(cleanedPath string, originalPath string) string {
// Ensure paths are in platform semantics // Ensure paths are in platform semantics
cleanedPath = strings.ReplaceAll(cleanedPath, "/", string(sep)) cleanedPath = normalizePath(cleanedPath)
originalPath = strings.ReplaceAll(originalPath, "/", string(sep)) originalPath = normalizePath(originalPath)
if !specifiesCurrentDir(cleanedPath) && specifiesCurrentDir(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 // 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). // path would only end in a separator if it is the root).
cleanedPath += string(sep) cleanedPath += string(filepath.Separator)
} }
cleanedPath += "." cleanedPath += "."
} }
if !hasTrailingPathSeparator(cleanedPath, sep) && hasTrailingPathSeparator(originalPath, sep) { if !hasTrailingPathSeparator(cleanedPath) && hasTrailingPathSeparator(originalPath) {
cleanedPath += string(sep) cleanedPath += string(filepath.Separator)
} }
return cleanedPath return cleanedPath
@ -51,14 +51,14 @@ func PreserveTrailingDotOrSeparator(cleanedPath string, originalPath string, sep
// assertsDirectory returns whether the given path is // assertsDirectory returns whether the given path is
// asserted to be a directory, i.e., the path ends with // asserted to be a directory, i.e., the path ends with
// a trailing '/' or `/.`, assuming a path separator of `/`. // a trailing '/' or `/.`, assuming a path separator of `/`.
func assertsDirectory(path string, sep byte) bool { func assertsDirectory(path string) bool {
return hasTrailingPathSeparator(path, sep) || specifiesCurrentDir(path) return hasTrailingPathSeparator(path) || specifiesCurrentDir(path)
} }
// hasTrailingPathSeparator returns whether the given // hasTrailingPathSeparator returns whether the given
// path ends with the system's path separator character. // path ends with the system's path separator character.
func hasTrailingPathSeparator(path string, sep byte) bool { func hasTrailingPathSeparator(path string) bool {
return len(path) > 0 && path[len(path)-1] == sep return len(path) > 0 && path[len(path)-1] == filepath.Separator
} }
// specifiesCurrentDir returns whether the given path specifies // specifiesCurrentDir returns whether the given path specifies
@ -285,7 +285,7 @@ func PrepareArchiveCopy(srcContent io.Reader, srcInfo, dstInfo CopyInfo) (dstDir
srcBase = srcInfo.RebaseName srcBase = srcInfo.RebaseName
} }
return dstDir, RebaseArchiveEntries(srcContent, srcBase, dstBase), nil 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 // 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 // directory, but the source content is not a directory. This is an
// error condition since you cannot create a directory from a file // 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) dstPath = normalizePath(dstPath)
// Clean the source and destination paths. // Clean the source and destination paths.
srcPath = PreserveTrailingDotOrSeparator(filepath.Clean(srcPath), srcPath, os.PathSeparator) srcPath = PreserveTrailingDotOrSeparator(filepath.Clean(srcPath), srcPath)
dstPath = PreserveTrailingDotOrSeparator(filepath.Clean(dstPath), dstPath, os.PathSeparator) dstPath = PreserveTrailingDotOrSeparator(filepath.Clean(dstPath), dstPath)
if srcInfo, err = CopyInfoSourcePath(srcPath, followLink); err != nil { if srcInfo, err = CopyInfoSourcePath(srcPath, followLink); err != nil {
return err return err
@ -451,7 +451,7 @@ func ResolveHostSourcePath(path string, followLink bool) (resolvedPath, rebaseNa
// resolvedDirPath will have been cleaned (no trailing path separators) so // resolvedDirPath will have been cleaned (no trailing path separators) so
// we can manually join it with the base path element. // we can manually join it with the base path element.
resolvedPath = resolvedDirPath + string(filepath.Separator) + basePath resolvedPath = resolvedDirPath + string(filepath.Separator) + basePath
if hasTrailingPathSeparator(path, os.PathSeparator) && if hasTrailingPathSeparator(path) &&
filepath.Base(path) != filepath.Base(resolvedPath) { filepath.Base(path) != filepath.Base(resolvedPath) {
rebaseName = filepath.Base(path) rebaseName = filepath.Base(path)
} }
@ -470,8 +470,8 @@ func GetRebaseName(path, resolvedPath string) (string, string) {
resolvedPath += string(filepath.Separator) + "." resolvedPath += string(filepath.Separator) + "."
} }
if hasTrailingPathSeparator(path, os.PathSeparator) && if hasTrailingPathSeparator(path) &&
!hasTrailingPathSeparator(resolvedPath, os.PathSeparator) { !hasTrailingPathSeparator(resolvedPath) {
resolvedPath += string(filepath.Separator) resolvedPath += string(filepath.Separator)
} }

View File

@ -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
}

View File

@ -2,85 +2,12 @@ package containerfs // import "github.com/docker/docker/pkg/containerfs"
import ( import (
"path/filepath" "path/filepath"
"runtime"
"github.com/containerd/continuity/driver"
"github.com/containerd/continuity/pathdriver"
"github.com/moby/sys/symlink" "github.com/moby/sys/symlink"
) )
// ContainerFS is that represents a root file system // ResolveScopedPath evaluates the given path scoped to the root.
type ContainerFS interface { // For example, if root=/a, and path=/b/c, then this function would return /a/b/c.
// Path returns the path to the root. Note that this may not exist func ResolveScopedPath(root, path string) (string, error) {
// on the local system, so the continuity operations must be used return symlink.FollowSymlinkInScope(filepath.Join(root, path), root)
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
} }

View File

@ -5,7 +5,7 @@ package containerfs // import "github.com/docker/docker/pkg/containerfs"
import "path/filepath" import "path/filepath"
// cleanScopedPath preappends a to combine with a mnt path. // CleanScopedPath preappends a to combine with a mnt path.
func cleanScopedPath(path string) string { func CleanScopedPath(path string) string {
return filepath.Join(string(filepath.Separator), path) return filepath.Join(string(filepath.Separator), path)
} }

View File

@ -2,9 +2,9 @@ package containerfs // import "github.com/docker/docker/pkg/containerfs"
import "path/filepath" 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 // with a volume path
func cleanScopedPath(path string) string { func CleanScopedPath(path string) string {
if len(path) >= 2 { if len(path) >= 2 {
c := path[0] c := path[0]
if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') { if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {

View File

@ -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, // CheckSystemDriveAndRemoveDriveLetter verifies that a path, if it includes a drive letter,
// is the system drive. // is the system drive.
// On Linux: this is a no-op. // On Linux: this is a no-op.
@ -37,6 +31,6 @@ type PathVerifier interface {
// a --> a // a --> a
// /a --> \a // /a --> \a
// d:\ --> Fail // d:\ --> Fail
func CheckSystemDriveAndRemoveDriveLetter(path string, driver PathVerifier) (string, error) { func CheckSystemDriveAndRemoveDriveLetter(path string) (string, error) {
return checkSystemDriveAndRemoveDriveLetter(path, driver) return checkSystemDriveAndRemoveDriveLetter(path)
} }

View File

@ -12,6 +12,6 @@ func GetLongPathName(path string) (string, error) {
// checkSystemDriveAndRemoveDriveLetter is the non-Windows implementation // checkSystemDriveAndRemoveDriveLetter is the non-Windows implementation
// of CheckSystemDriveAndRemoveDriveLetter // of CheckSystemDriveAndRemoveDriveLetter
func checkSystemDriveAndRemoveDriveLetter(path string, driver PathVerifier) (string, error) { func checkSystemDriveAndRemoveDriveLetter(path string) (string, error) {
return path, nil return path, nil
} }

View File

@ -34,11 +34,11 @@ func GetLongPathName(path string) (string, error) {
// checkSystemDriveAndRemoveDriveLetter is the Windows implementation // checkSystemDriveAndRemoveDriveLetter is the Windows implementation
// of CheckSystemDriveAndRemoveDriveLetter // of CheckSystemDriveAndRemoveDriveLetter
func checkSystemDriveAndRemoveDriveLetter(path string, driver PathVerifier) (string, error) { func checkSystemDriveAndRemoveDriveLetter(path string) (string, error) {
if len(path) == 2 && string(path[1]) == ":" { if len(path) == 2 && string(path[1]) == ":" {
return "", fmt.Errorf("No relative path specified in %q", path) 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 return filepath.FromSlash(path), nil
} }
if string(path[1]) == ":" && !strings.EqualFold(string(path[0]), "c") { if string(path[1]) == ":" && !strings.EqualFold(string(path[0]), "c") {

View File

@ -5,21 +5,19 @@ package system // import "github.com/docker/docker/pkg/system"
import ( import (
"testing" "testing"
"github.com/containerd/continuity/pathdriver"
) )
// TestCheckSystemDriveAndRemoveDriveLetter tests CheckSystemDriveAndRemoveDriveLetter // TestCheckSystemDriveAndRemoveDriveLetter tests CheckSystemDriveAndRemoveDriveLetter
func TestCheckSystemDriveAndRemoveDriveLetter(t *testing.T) { func TestCheckSystemDriveAndRemoveDriveLetter(t *testing.T) {
// Fails if not C drive. // 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:)" { if err == nil || err.Error() != "The specified path is not on the system drive (C:)" {
t.Fatalf("Expected error for d:") t.Fatalf("Expected error for d:")
} }
// Single character is unchanged // Single character is unchanged
var path string 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") t.Fatalf("Single character should pass")
} }
if path != "z" { if path != "z" {
@ -27,7 +25,7 @@ func TestCheckSystemDriveAndRemoveDriveLetter(t *testing.T) {
} }
// Two characters without colon is unchanged // 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") t.Fatalf("2 characters without colon should pass")
} }
if path != "AB" { if path != "AB" {
@ -35,7 +33,7 @@ func TestCheckSystemDriveAndRemoveDriveLetter(t *testing.T) {
} }
// Abs path without drive letter // 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") t.Fatalf("abs path no drive letter should pass")
} }
if path != `\l` { if path != `\l` {
@ -43,7 +41,7 @@ func TestCheckSystemDriveAndRemoveDriveLetter(t *testing.T) {
} }
// Abs path without drive letter, linux style // 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") t.Fatalf("abs path no drive letter linux style should pass")
} }
if path != `\l` { if path != `\l` {
@ -51,7 +49,7 @@ func TestCheckSystemDriveAndRemoveDriveLetter(t *testing.T) {
} }
// Drive-colon should be stripped // 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") t.Fatalf("An absolute path should pass")
} }
if path != `\` { if path != `\` {
@ -59,7 +57,7 @@ func TestCheckSystemDriveAndRemoveDriveLetter(t *testing.T) {
} }
// Verify with a linux-style path // 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") t.Fatalf("An absolute path should pass")
} }
if path != `\` { if path != `\` {
@ -67,7 +65,7 @@ func TestCheckSystemDriveAndRemoveDriveLetter(t *testing.T) {
} }
// Failure on c: // Failure on c:
if path, err = CheckSystemDriveAndRemoveDriveLetter(`c:`, pathdriver.LocalPathDriver); err == nil { if path, err = CheckSystemDriveAndRemoveDriveLetter(`c:`); err == nil {
t.Fatalf("c: should fail") t.Fatalf("c: should fail")
} }
if err.Error() != `No relative path specified in "c:"` { if err.Error() != `No relative path specified in "c:"` {
@ -75,7 +73,7 @@ func TestCheckSystemDriveAndRemoveDriveLetter(t *testing.T) {
} }
// Failure on d: // Failure on d:
if path, err = CheckSystemDriveAndRemoveDriveLetter(`d:`, pathdriver.LocalPathDriver); err == nil { if path, err = CheckSystemDriveAndRemoveDriveLetter(`d:`); err == nil {
t.Fatalf("c: should fail") t.Fatalf("c: should fail")
} }
if err.Error() != `No relative path specified in "d:"` { if err.Error() != `No relative path specified in "d:"` {

View File

@ -12,7 +12,6 @@ import (
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/daemon/initlayer" "github.com/docker/docker/daemon/initlayer"
"github.com/docker/docker/errdefs" "github.com/docker/docker/errdefs"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/plugins" "github.com/docker/docker/pkg/plugins"
"github.com/docker/docker/pkg/stringid" "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 { if err := initlayer.Setup(rootFS, idtools.Identity{UID: 0, GID: 0}); err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }

View File

@ -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
View File

@ -236,7 +236,6 @@ github.com/containerd/containerd/version
github.com/containerd/continuity/devices github.com/containerd/continuity/devices
github.com/containerd/continuity/driver github.com/containerd/continuity/driver
github.com/containerd/continuity/fs github.com/containerd/continuity/fs
github.com/containerd/continuity/pathdriver
github.com/containerd/continuity/sysx github.com/containerd/continuity/sysx
# github.com/containerd/fifo v1.0.0 # github.com/containerd/fifo v1.0.0
## explicit; go 1.13 ## explicit; go 1.13