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

View File

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

View File

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

View File

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

View File

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

View File

@ -7,7 +7,6 @@ import (
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"strings"
"github.com/docker/docker/api/types"
@ -17,8 +16,6 @@ import (
"github.com/docker/docker/image"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/chrootarchive"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/go-connections/nat"
specs "github.com/opencontainers/image-spec/specs-go/v1"
@ -26,50 +23,8 @@ import (
"github.com/sirupsen/logrus"
)
// Archiver defines an interface for copying files from one destination to
// another using Tar/Untar.
type Archiver interface {
TarUntar(src, dst string) error
UntarPath(src, dst string) error
CopyWithTar(src, dst string) error
CopyFileWithTar(src, dst string) error
IdentityMapping() idtools.IdentityMapping
}
// The builder will use the following interfaces if the container fs implements
// these for optimized copies to and from the container.
type extractor interface {
ExtractArchive(src io.Reader, dst string, opts *archive.TarOptions) error
}
type archiver interface {
ArchivePath(src string, opts *archive.TarOptions) (io.ReadCloser, error)
}
// helper functions to get tar/untar func
func untarFunc(i interface{}) containerfs.UntarFunc {
if ea, ok := i.(extractor); ok {
return ea.ExtractArchive
}
return chrootarchive.Untar
}
func tarFunc(i interface{}) containerfs.TarFunc {
if ap, ok := i.(archiver); ok {
return ap.ArchivePath
}
return archive.TarWithOptions
}
func (b *Builder) getArchiver(src, dst containerfs.Driver) Archiver {
t, u := tarFunc(src), untarFunc(dst)
return &containerfs.Archiver{
SrcDriver: src,
DstDriver: dst,
Tar: t,
Untar: u,
IDMapping: b.idMapping,
}
func (b *Builder) getArchiver() *archive.Archiver {
return chrootarchive.NewArchiver(b.idMapping)
}
func (b *Builder) commit(dispatchState *dispatchState, comment string) error {
@ -192,7 +147,7 @@ func (b *Builder) performCopy(req dispatchRequest, inst copyInstruction) error {
// translated (if necessary because of user namespaces), and replace
// the root pair with the chown pair for copy operations
if inst.chownStr != "" {
identity, err = parseChownFlag(b, state, inst.chownStr, destInfo.root.Path(), b.idMapping)
identity, err = parseChownFlag(b, state, inst.chownStr, destInfo.root, b.idMapping)
if err != nil {
if b.options.Platform != "windows" {
return errors.Wrapf(err, "unable to convert uid/gid chown string to host mapping")
@ -205,7 +160,7 @@ func (b *Builder) performCopy(req dispatchRequest, inst copyInstruction) error {
for _, info := range inst.infos {
opts := copyFileOptions{
decompress: inst.allowLocalDecompression,
archiver: b.getArchiver(info.root, destInfo.root),
archiver: b.getArchiver(),
}
if !inst.preserveOwnership {
opts.identity = &identity

View File

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

View File

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

View File

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

View File

@ -13,6 +13,7 @@ import (
"github.com/docker/docker/builder"
"github.com/docker/docker/builder/remotecontext/urlutil"
"github.com/docker/docker/errdefs"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/fileutils"
"github.com/moby/buildkit/frontend/dockerfile/dockerignore"
"github.com/moby/buildkit/frontend/dockerfile/parser"
@ -161,7 +162,7 @@ func openAt(remote builder.Source, path string) (driver.File, error) {
if err != nil {
return nil, err
}
return remote.Root().Open(fullPath)
return os.Open(fullPath)
}
// StatAt is a helper for calling Stat on a path from a source
@ -170,12 +171,12 @@ func StatAt(remote builder.Source, path string) (os.FileInfo, error) {
if err != nil {
return nil, err
}
return remote.Root().Stat(fullPath)
return os.Stat(fullPath)
}
// FullPath is a helper for getting a full path for a path from a source
func FullPath(remote builder.Source, path string) (string, error) {
fullPath, err := remote.Root().ResolveScopedPath(path, true)
fullPath, err := containerfs.ResolveScopedPath(remote.Root(), path)
if err != nil {
if runtime.GOOS == "windows" {
return "", fmt.Errorf("failed to resolve scoped path %s (%s): %s. Possible cause is a forbidden path outside the build context", path, fullPath, err)

View File

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

View File

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

View File

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

View File

@ -35,7 +35,7 @@ func TestCloseRootDirectory(t *testing.T) {
t.Fatalf("Error while executing Close: %s", err)
}
_, err = os.Stat(src.Root().Path())
_, err = os.Stat(src.Root())
if !errors.Is(err, os.ErrNotExist) {
t.Fatal("Directory should not exist at this point")
@ -118,7 +118,7 @@ func TestRemoveDirectory(t *testing.T) {
src := makeTestArchiveContext(t, contextDir)
_, err = src.Root().Stat(src.Root().Join(src.Root().Path(), relativePath))
_, err = os.Stat(filepath.Join(src.Root(), relativePath))
if err != nil {
t.Fatalf("Statting %s shouldn't fail: %+v", relativePath, err)
}
@ -129,7 +129,7 @@ func TestRemoveDirectory(t *testing.T) {
t.Fatalf("Error when executing Remove: %s", err)
}
_, err = src.Root().Stat(src.Root().Join(src.Root().Path(), relativePath))
_, err = os.Stat(filepath.Join(src.Root(), relativePath))
if !errors.Is(err, os.ErrNotExist) {
t.Fatalf("Directory should not exist at this point: %+v ", err)
}

View File

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

View File

@ -61,10 +61,10 @@ type ExitStatus struct {
type Container struct {
StreamConfig *stream.Config
// embed for Container to support states directly.
*State `json:"State"` // Needed for Engine API version <= 1.11
Root string `json:"-"` // Path to the "home" of the container, including metadata.
BaseFS containerfs.ContainerFS `json:"-"` // interface containing graphdriver mount
RWLayer layer.RWLayer `json:"-"`
*State `json:"State"` // Needed for Engine API version <= 1.11
Root string `json:"-"` // Path to the "home" of the container, including metadata.
BaseFS string `json:"-"` // Path to the graphdriver mountpoint
RWLayer layer.RWLayer `json:"-"`
ID string
Created time.Time
Managed bool
@ -299,18 +299,18 @@ func (container *Container) SetupWorkingDirectory(rootIdentity idtools.Identity)
// symlinking to a different path) between using this method and using the
// path. See symlink.FollowSymlinkInScope for more details.
func (container *Container) GetResourcePath(path string) (string, error) {
if container.BaseFS == nil {
return "", errors.New("GetResourcePath: BaseFS of container " + container.ID + " is unexpectedly nil")
if container.BaseFS == "" {
return "", errors.New("GetResourcePath: BaseFS of container " + container.ID + " is unexpectedly empty")
}
// IMPORTANT - These are paths on the OS where the daemon is running, hence
// any filepath operations must be done in an OS agnostic way.
r, e := container.BaseFS.ResolveScopedPath(path, false)
r, e := containerfs.ResolveScopedPath(container.BaseFS, containerfs.CleanScopedPath(path))
// Log this here on the daemon side as there's otherwise no indication apart
// from the error being propagated all the way back to the client. This makes
// debugging significantly easier and clearly indicates the error comes from the daemon.
if e != nil {
logrus.Errorf("Failed to ResolveScopedPath BaseFS %s path %s %s\n", container.BaseFS.Path(), path, e)
logrus.Errorf("Failed to ResolveScopedPath BaseFS %s path %s %s\n", container.BaseFS, path, e)
}
return r, e
}

View File

@ -3,6 +3,7 @@ package daemon // import "github.com/docker/docker/daemon"
import (
"io"
"os"
"path/filepath"
"strings"
"github.com/docker/docker/api/types"
@ -20,32 +21,6 @@ import (
// path does not refer to a directory.
var ErrExtractPointNotDirectory = errors.New("extraction point is not a directory")
// The daemon will use the following interfaces if the container fs implements
// these for optimized copies to and from the container.
type extractor interface {
ExtractArchive(src io.Reader, dst string, opts *archive.TarOptions) error
}
type archiver interface {
ArchivePath(src string, opts *archive.TarOptions) (io.ReadCloser, error)
}
// helper functions to extract or archive
func extractArchive(i interface{}, src io.Reader, dst string, opts *archive.TarOptions, root string) error {
if ea, ok := i.(extractor); ok {
return ea.ExtractArchive(src, dst, opts)
}
return chrootarchive.UntarWithRoot(src, dst, opts, root)
}
func archivePath(i interface{}, src string, opts *archive.TarOptions, root string) (io.ReadCloser, error) {
if ap, ok := i.(archiver); ok {
return ap.ArchivePath(src, opts)
}
return chrootarchive.Tar(src, opts, root)
}
// ContainerCopy performs a deprecated operation of archiving the resource at
// the specified path in the container identified by the given name.
func (daemon *Daemon) ContainerCopy(name string, res string) (io.ReadCloser, error) {
@ -165,7 +140,7 @@ func (daemon *Daemon) containerStatPath(container *container.Container, path str
}
// Normalize path before sending to rootfs
path = container.BaseFS.FromSlash(path)
path = filepath.FromSlash(path)
resolvedPath, absPath, err := container.ResolvePath(path)
if err != nil {
@ -208,7 +183,7 @@ func (daemon *Daemon) containerArchivePath(container *container.Container, path
}
// Normalize path before sending to rootfs
path = container.BaseFS.FromSlash(path)
path = filepath.FromSlash(path)
resolvedPath, absPath, err := container.ResolvePath(path)
if err != nil {
@ -228,24 +203,23 @@ func (daemon *Daemon) containerArchivePath(container *container.Container, path
// also catches the case when the root directory of the container is
// requested: we want the archive entries to start with "/" and not the
// container ID.
driver := container.BaseFS
// Get the source and the base paths of the container resolved path in order
// to get the proper tar options for the rebase tar.
resolvedPath = driver.Clean(resolvedPath)
if driver.Base(resolvedPath) == "." {
resolvedPath += string(driver.Separator()) + "."
resolvedPath = filepath.Clean(resolvedPath)
if filepath.Base(resolvedPath) == "." {
resolvedPath += string(filepath.Separator) + "."
}
sourceDir := resolvedPath
sourceBase := "."
if stat.Mode&os.ModeDir == 0 { // not dir
sourceDir, sourceBase = driver.Split(resolvedPath)
sourceDir, sourceBase = filepath.Split(resolvedPath)
}
opts := archive.TarResourceRebaseOpts(sourceBase, driver.Base(absPath))
opts := archive.TarResourceRebaseOpts(sourceBase, filepath.Base(absPath))
data, err := archivePath(driver, sourceDir, opts, container.BaseFS.Path())
data, err := chrootarchive.Tar(sourceDir, opts, container.BaseFS)
if err != nil {
return nil, nil, err
}
@ -285,11 +259,10 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path
}
// Normalize path before sending to rootfs'
path = container.BaseFS.FromSlash(path)
driver := container.BaseFS
path = filepath.FromSlash(path)
// Check if a drive letter supplied, it must be the system drive. No-op except on Windows
path, err = system.CheckSystemDriveAndRemoveDriveLetter(path, driver)
path, err = system.CheckSystemDriveAndRemoveDriveLetter(path)
if err != nil {
return err
}
@ -301,10 +274,7 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path
// that you can extract an archive to a symlink that points to a directory.
// Consider the given path as an absolute path in the container.
absPath := archive.PreserveTrailingDotOrSeparator(
driver.Join(string(driver.Separator()), path),
path,
driver.Separator())
absPath := archive.PreserveTrailingDotOrSeparator(filepath.Join(string(filepath.Separator), path), path)
// This will evaluate the last path element if it is a symlink.
resolvedPath, err := container.GetResourcePath(absPath)
@ -312,7 +282,7 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path
return err
}
stat, err := driver.Lstat(resolvedPath)
stat, err := os.Lstat(resolvedPath)
if err != nil {
return err
}
@ -335,24 +305,21 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path
// a volume file path.
var baseRel string
if strings.HasPrefix(resolvedPath, `\\?\Volume{`) {
if strings.HasPrefix(resolvedPath, driver.Path()) {
baseRel = resolvedPath[len(driver.Path()):]
if strings.HasPrefix(resolvedPath, container.BaseFS) {
baseRel = resolvedPath[len(container.BaseFS):]
if baseRel[:1] == `\` {
baseRel = baseRel[1:]
}
}
} else {
baseRel, err = driver.Rel(driver.Path(), resolvedPath)
baseRel, err = filepath.Rel(container.BaseFS, resolvedPath)
}
if err != nil {
return err
}
// Make it an absolute path.
absPath = driver.Join(string(driver.Separator()), baseRel)
absPath = filepath.Join(string(filepath.Separator), baseRel)
// @ TODO: gupta-ak: Technically, this works since it no-ops
// on Windows and the file system is local anyway on linux.
// But eventually, it should be made driver aware.
toVolume, err := checkIfPathIsInAVolume(container, absPath)
if err != nil {
return err
@ -374,7 +341,7 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path
}
}
if err := extractArchive(driver, content, resolvedPath, options, container.BaseFS.Path()); err != nil {
if err := chrootarchive.UntarWithRoot(content, resolvedPath, options, container.BaseFS); err != nil {
return err
}
@ -416,27 +383,26 @@ func (daemon *Daemon) containerCopy(container *container.Container, resource str
}
// Normalize path before sending to rootfs
resource = container.BaseFS.FromSlash(resource)
driver := container.BaseFS
resource = filepath.FromSlash(resource)
basePath, err := container.GetResourcePath(resource)
if err != nil {
return nil, err
}
stat, err := driver.Stat(basePath)
stat, err := os.Stat(basePath)
if err != nil {
return nil, err
}
var filter []string
if !stat.IsDir() {
d, f := driver.Split(basePath)
d, f := filepath.Split(basePath)
basePath = d
filter = []string{f}
}
archv, err := archivePath(driver, basePath, &archive.TarOptions{
archv, err := chrootarchive.Tar(basePath, &archive.TarOptions{
Compression: archive.Uncompressed,
IncludeFiles: filter,
}, container.BaseFS.Path())
}, container.BaseFS)
if err != nil {
return nil, err
}

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)
if container.BaseFS != nil && container.BaseFS.Path() != dir.Path() {
if container.BaseFS != "" && container.BaseFS != dir {
// The mount path reported by the graph driver should always be trusted on Windows, since the
// volume path for a given mounted layer may change over time. This should only be an error
// on non-Windows operating systems.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -627,29 +627,29 @@ func (d *Driver) Remove(id string) error {
}
// Get the requested filesystem id.
func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
func (d *Driver) Get(id, mountLabel string) (string, error) {
dir := d.subvolumesDirID(id)
st, err := os.Stat(dir)
if err != nil {
return nil, err
return "", err
}
if !st.IsDir() {
return nil, fmt.Errorf("%s: not a directory", dir)
return "", fmt.Errorf("%s: not a directory", dir)
}
if quota, err := os.ReadFile(d.quotasDirID(id)); err == nil {
if size, err := strconv.ParseUint(string(quota), 10, 64); err == nil && size >= d.options.minSpace {
if err := d.enableQuota(); err != nil {
return nil, err
return "", err
}
if err := subvolLimitQgroup(dir, size); err != nil {
return nil, err
return "", err
}
}
}
return containerfs.NewLocalContainerFS(dir), nil
return dir, nil
}
// Put is not implemented for BTRFS as there is no cleanup required for the id.

View File

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

View File

@ -10,7 +10,6 @@ import (
"strconv"
"github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/devicemapper"
"github.com/docker/docker/pkg/idtools"
units "github.com/docker/go-units"
@ -175,13 +174,13 @@ func (d *Driver) Remove(id string) error {
}
// Get mounts a device with given id into the root filesystem
func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
func (d *Driver) Get(id, mountLabel string) (string, error) {
d.locker.Lock(id)
defer d.locker.Unlock(id)
mp := path.Join(d.home, "mnt", id)
rootFs := path.Join(mp, "rootfs")
if count := d.ctr.Increment(mp); count > 1 {
return containerfs.NewLocalContainerFS(rootFs), nil
return rootFs, nil
}
root := d.idMap.RootPair()
@ -189,23 +188,23 @@ func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
// Create the target directories if they don't exist
if err := idtools.MkdirAllAndChown(path.Join(d.home, "mnt"), 0755, root); err != nil {
d.ctr.Decrement(mp)
return nil, err
return "", err
}
if err := idtools.MkdirAndChown(mp, 0755, root); err != nil && !os.IsExist(err) {
d.ctr.Decrement(mp)
return nil, err
return "", err
}
// Mount the device
if err := d.DeviceSet.MountDevice(id, mp, mountLabel); err != nil {
d.ctr.Decrement(mp)
return nil, err
return "", err
}
if err := idtools.MkdirAllAndChown(rootFs, 0755, root); err != nil {
d.ctr.Decrement(mp)
d.DeviceSet.UnmountDevice(id, mp)
return nil, err
return "", err
}
idFile := path.Join(mp, "id")
@ -215,11 +214,11 @@ func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
if err := os.WriteFile(idFile, []byte(id), 0600); err != nil {
d.ctr.Decrement(mp)
d.DeviceSet.UnmountDevice(id, mp)
return nil, err
return "", err
}
}
return containerfs.NewLocalContainerFS(rootFs), nil
return rootFs, nil
}
// Put unmounts a device and removes it.

View File

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

View File

@ -50,7 +50,7 @@ func (gdw *NaiveDiffDriver) Diff(id, parent string) (arch io.ReadCloser, err err
if err != nil {
return nil, err
}
layerFs := layerRootFs.Path()
layerFs := layerRootFs
defer func() {
if err != nil {
@ -70,14 +70,12 @@ func (gdw *NaiveDiffDriver) Diff(id, parent string) (arch io.ReadCloser, err err
}), nil
}
parentRootFs, err := driver.Get(parent, "")
parentFs, err := driver.Get(parent, "")
if err != nil {
return nil, err
}
defer driver.Put(parent)
parentFs := parentRootFs.Path()
changes, err := archive.ChangesDirs(layerFs, parentFs)
if err != nil {
return nil, err
@ -106,22 +104,20 @@ func (gdw *NaiveDiffDriver) Diff(id, parent string) (arch io.ReadCloser, err err
func (gdw *NaiveDiffDriver) Changes(id, parent string) ([]archive.Change, error) {
driver := gdw.ProtoDriver
layerRootFs, err := driver.Get(id, "")
layerFs, err := driver.Get(id, "")
if err != nil {
return nil, err
}
defer driver.Put(id)
layerFs := layerRootFs.Path()
parentFs := ""
if parent != "" {
parentRootFs, err := driver.Get(parent, "")
parentFs, err = driver.Get(parent, "")
if err != nil {
return nil, err
}
defer driver.Put(parent)
parentFs = parentRootFs.Path()
}
return archive.ChangesDirs(layerFs, parentFs)
@ -140,7 +136,7 @@ func (gdw *NaiveDiffDriver) ApplyDiff(id, parent string, diff io.Reader) (size i
}
defer driver.Put(id)
layerFs := layerRootFs.Path()
layerFs := layerRootFs
options := &archive.TarOptions{IDMap: gdw.idMap}
start := time.Now().UTC()
logrus.WithField("id", id).Debug("Start untar layer")
@ -169,5 +165,5 @@ func (gdw *NaiveDiffDriver) DiffSize(id, parent string) (size int64, err error)
}
defer driver.Put(id)
return archive.ChangesSize(layerFs.Path(), changes), nil
return archive.ChangesSize(layerFs, changes), nil
}

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

View File

@ -5,9 +5,10 @@ package graphtest // import "github.com/docker/docker/daemon/graphdriver/graphte
import (
"io"
"os"
"path/filepath"
"testing"
contdriver "github.com/containerd/continuity/driver"
"github.com/docker/docker/pkg/stringid"
"gotest.tools/v3/assert"
)
@ -249,7 +250,7 @@ func DriverBenchDeepLayerRead(b *testing.B, layerCount int, drivername string, d
for i := 0; i < b.N; i++ {
// Read content
c, err := contdriver.ReadFile(root, root.Join(root.Path(), "testfile.txt"))
c, err := os.ReadFile(filepath.Join(root, "testfile.txt"))
if err != nil {
b.Fatal(err)
}

View File

@ -96,10 +96,10 @@ func DriverTestCreateEmpty(t testing.TB, drivername string, driverOptions ...str
dir, err := driver.Get("empty", "")
assert.NilError(t, err)
verifyFile(t, dir.Path(), 0755|os.ModeDir, 0, 0)
verifyFile(t, dir, 0755|os.ModeDir, 0, 0)
// Verify that the directory is empty
fis, err := readDir(dir, dir.Path())
fis, err := readDir(dir)
assert.NilError(t, err)
assert.Check(t, is.Len(fis, 0))
@ -324,19 +324,19 @@ func DriverTestSetQuota(t *testing.T, drivername string, required bool) {
quota := uint64(50 * units.MiB)
// Try to write a file smaller than quota, and ensure it works
err = writeRandomFile(path.Join(mountPath.Path(), "smallfile"), quota/2)
err = writeRandomFile(path.Join(mountPath, "smallfile"), quota/2)
if err != nil {
t.Fatal(err)
}
defer os.Remove(path.Join(mountPath.Path(), "smallfile"))
defer os.Remove(path.Join(mountPath, "smallfile"))
// Try to write a file bigger than quota. We've already filled up half the quota, so hitting the limit should be easy
err = writeRandomFile(path.Join(mountPath.Path(), "bigfile"), quota)
err = writeRandomFile(path.Join(mountPath, "bigfile"), quota)
if err == nil {
t.Fatalf("expected write to fail(), instead had success")
}
if pathError, ok := err.(*os.PathError); ok && pathError.Err != unix.EDQUOT && pathError.Err != unix.ENOSPC {
os.Remove(path.Join(mountPath.Path(), "bigfile"))
os.Remove(path.Join(mountPath, "bigfile"))
t.Fatalf("expect write() to fail with %v or %v, got %v", unix.EDQUOT, unix.ENOSPC, pathError.Err)
}
}

View File

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

View File

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

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.
func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, err error) {
func (d *Driver) Get(id, mountLabel string) (_ string, err error) {
d.locker.Lock(id)
defer d.locker.Unlock(id)
dir := d.dir(id)
if _, err := os.Stat(dir); err != nil {
return nil, err
return "", err
}
// If id has a root, just return it
rootDir := path.Join(dir, "root")
if _, err := os.Stat(rootDir); err == nil {
return containerfs.NewLocalContainerFS(rootDir), nil
return rootDir, nil
}
mergedDir := path.Join(dir, "merged")
if count := d.ctr.Increment(mergedDir); count > 1 {
return containerfs.NewLocalContainerFS(mergedDir), nil
return mergedDir, nil
}
defer func() {
if err != nil {
@ -371,11 +371,11 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, err erro
}()
lowerID, err := os.ReadFile(path.Join(dir, "lower-id"))
if err != nil {
return nil, err
return "", err
}
root := d.idMap.RootPair()
if err := idtools.MkdirAndChown(mergedDir, 0700, root); err != nil {
return nil, err
return "", err
}
var (
lowerDir = path.Join(d.dir(string(lowerID)), "root")
@ -384,14 +384,14 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, err erro
opts = fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lowerDir, upperDir, workDir)
)
if err := unix.Mount("overlay", mergedDir, "overlay", 0, label.FormatMountLabel(opts, mountLabel)); err != nil {
return nil, fmt.Errorf("error creating overlay mount to %s: %v", mergedDir, err)
return "", fmt.Errorf("error creating overlay mount to %s: %v", mergedDir, err)
}
// chown "workdir/work" to the remapped root UID/GID. Overlay fs inside a
// user namespace requires this to move a directory from lower to upper.
if err := root.Chown(path.Join(workDir, "work")); err != nil {
return nil, err
return "", err
}
return containerfs.NewLocalContainerFS(mergedDir), nil
return mergedDir, nil
}
// Put unmounts the mount path created for the give id.

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

View File

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

View File

@ -172,7 +172,7 @@ func (d *Driver) create(id, parent string, size uint64) error {
if err != nil {
return fmt.Errorf("%s: %s", parent, err)
}
return CopyDir(parentDir.Path(), dir)
return CopyDir(parentDir, dir)
}
func (d *Driver) dir(id string) string {
@ -185,14 +185,14 @@ func (d *Driver) Remove(id string) error {
}
// Get returns the directory for the given id.
func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
func (d *Driver) Get(id, mountLabel string) (string, error) {
dir := d.dir(id)
if st, err := os.Stat(dir); err != nil {
return nil, err
return "", err
} else if !st.IsDir() {
return nil, fmt.Errorf("%s: not a directory", dir)
return "", fmt.Errorf("%s: not a directory", dir)
}
return containerfs.NewLocalContainerFS(dir), nil
return dir, nil
}
// Put is a noop for vfs that return nil for the error, since this driver has no runtime resources to clean up.

View File

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

View File

@ -14,7 +14,6 @@ import (
"time"
"github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/parsers"
zfs "github.com/mistifyio/go-zfs"
@ -363,12 +362,12 @@ func (d *Driver) Remove(id string) error {
}
// Get returns the mountpoint for the given id after creating the target directories if necessary.
func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr error) {
func (d *Driver) Get(id, mountLabel string) (_ string, retErr error) {
d.locker.Lock(id)
defer d.locker.Unlock(id)
mountpoint := d.mountPath(id)
if count := d.ctr.Increment(mountpoint); count > 1 {
return containerfs.NewLocalContainerFS(mountpoint), nil
return mountpoint, nil
}
defer func() {
if retErr != nil {
@ -391,20 +390,20 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
root := d.idMap.RootPair()
// Create the target directories if they don't exist
if err := idtools.MkdirAllAndChown(mountpoint, 0755, root); err != nil {
return nil, err
return "", err
}
if err := mount.Mount(filesystem, mountpoint, "zfs", options); err != nil {
return nil, errors.Wrap(err, "error creating zfs mount")
return "", errors.Wrap(err, "error creating zfs mount")
}
// this could be our first mount after creation of the filesystem, and the root dir may still have root
// permissions instead of the remapped root uid:gid (if user namespaces are enabled):
if err := root.Chown(mountpoint); err != nil {
return nil, fmt.Errorf("error modifying zfs mountpoint (%s) directory ownership: %v", mountpoint, err)
return "", fmt.Errorf("error modifying zfs mountpoint (%s) directory ownership: %v", mountpoint, err)
}
return containerfs.NewLocalContainerFS(mountpoint), nil
return mountpoint, nil
}
// Put removes the existing mountpoint for the given id if it exists.

View File

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

View File

@ -8,7 +8,6 @@ import (
"path/filepath"
"strings"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/idtools"
"golang.org/x/sys/unix"
)
@ -18,9 +17,9 @@ import (
//
// This extra layer is used by all containers as the top-most ro layer. It protects
// the container from unwanted side-effects on the rw layer.
func Setup(initLayerFs containerfs.ContainerFS, rootIdentity idtools.Identity) error {
func Setup(initLayerFs string, rootIdentity idtools.Identity) error {
// Since all paths are local to the container, we can just extract initLayerFs.Path()
initLayer := initLayerFs.Path()
initLayer := initLayerFs
for pth, typ := range map[string]string{
"/dev/pts": "dir",

View File

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

View File

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

View File

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

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
if !isHyperV {
if c.BaseFS == nil {
return errors.New("createSpecWindowsFields: BaseFS of container " + c.ID + " is unexpectedly nil")
if c.BaseFS == "" {
return errors.New("createSpecWindowsFields: BaseFS of container " + c.ID + " is unexpectedly empty")
}
s.Root.Path = c.BaseFS.Path() // This is not set for Hyper-V containers
s.Root.Path = c.BaseFS // This is not set for Hyper-V containers
if !strings.HasSuffix(s.Root.Path, `\`) {
s.Root.Path = s.Root.Path + `\` // Ensure a correctly formatted volume GUID path \\?\Volume{GUID}\
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,13 +2,14 @@ package layer // import "github.com/docker/docker/layer"
import (
"io"
"os"
"path/filepath"
"runtime"
"sort"
"testing"
"github.com/containerd/continuity/driver"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/containerfs"
)
func TestMountInit(t *testing.T) {
@ -28,7 +29,7 @@ func TestMountInit(t *testing.T) {
t.Fatal(err)
}
mountInit := func(root containerfs.ContainerFS) error {
mountInit := func(root string) error {
return initfile.ApplyFile(root)
}
@ -45,12 +46,12 @@ func TestMountInit(t *testing.T) {
t.Fatal(err)
}
fi, err := pathFS.Stat(pathFS.Join(pathFS.Path(), "testfile.txt"))
fi, err := os.Stat(filepath.Join(pathFS, "testfile.txt"))
if err != nil {
t.Fatal(err)
}
f, err := pathFS.Open(pathFS.Join(pathFS.Path(), "testfile.txt"))
f, err := os.Open(filepath.Join(pathFS, "testfile.txt"))
if err != nil {
t.Fatal(err)
}
@ -88,7 +89,7 @@ func TestMountSize(t *testing.T) {
t.Fatal(err)
}
mountInit := func(root containerfs.ContainerFS) error {
mountInit := func(root string) error {
return newTestFile("file-init", contentInit, 0777).ApplyFile(root)
}
rwLayerOpts := &CreateRWLayerOpts{
@ -105,7 +106,7 @@ func TestMountSize(t *testing.T) {
t.Fatal(err)
}
if err := driver.WriteFile(pathFS, pathFS.Join(pathFS.Path(), "file2"), content2, 0755); err != nil {
if err := os.WriteFile(filepath.Join(pathFS, "file2"), content2, 0755); err != nil {
t.Fatal(err)
}
@ -140,7 +141,7 @@ func TestMountChanges(t *testing.T) {
t.Fatal(err)
}
mountInit := func(root containerfs.ContainerFS) error {
mountInit := func(root string) error {
return initfile.ApplyFile(root)
}
rwLayerOpts := &CreateRWLayerOpts{
@ -157,23 +158,23 @@ func TestMountChanges(t *testing.T) {
t.Fatal(err)
}
if err := pathFS.Lchmod(pathFS.Join(pathFS.Path(), "testfile1.txt"), 0755); err != nil {
if err := driver.LocalDriver.Lchmod(filepath.Join(pathFS, "testfile1.txt"), 0755); err != nil {
t.Fatal(err)
}
if err := driver.WriteFile(pathFS, pathFS.Join(pathFS.Path(), "testfile1.txt"), []byte("mount data!"), 0755); err != nil {
if err := os.WriteFile(filepath.Join(pathFS, "testfile1.txt"), []byte("mount data!"), 0755); err != nil {
t.Fatal(err)
}
if err := pathFS.Remove(pathFS.Join(pathFS.Path(), "testfile2.txt")); err != nil {
if err := os.Remove(filepath.Join(pathFS, "testfile2.txt")); err != nil {
t.Fatal(err)
}
if err := pathFS.Lchmod(pathFS.Join(pathFS.Path(), "testfile3.txt"), 0755); err != nil {
if err := driver.LocalDriver.Lchmod(filepath.Join(pathFS, "testfile3.txt"), 0755); err != nil {
t.Fatal(err)
}
if err := driver.WriteFile(pathFS, pathFS.Join(pathFS.Path(), "testfile4.txt"), []byte("mount data!"), 0644); err != nil {
if err := os.WriteFile(filepath.Join(pathFS, "testfile4.txt"), []byte("mount data!"), 0644); err != nil {
t.Fatal(err)
}
@ -248,7 +249,7 @@ func TestMountApply(t *testing.T) {
t.Fatal(err)
}
f, err := pathFS.Open(pathFS.Join(pathFS.Path(), "newfile.txt"))
f, err := os.Open(filepath.Join(pathFS, "newfile.txt"))
if err != nil {
t.Fatal(err)
}

View File

@ -5,7 +5,6 @@ import (
"sync"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/containerfs"
)
type mountedLayer struct {
@ -100,7 +99,7 @@ type referencedRWLayer struct {
*mountedLayer
}
func (rl *referencedRWLayer) Mount(mountLabel string) (containerfs.ContainerFS, error) {
func (rl *referencedRWLayer) Mount(mountLabel string) (string, error) {
return rl.layerStore.driver.Get(rl.mountedLayer.mountID, mountLabel)
}

View File

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

View File

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

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 (
"path/filepath"
"runtime"
"github.com/containerd/continuity/driver"
"github.com/containerd/continuity/pathdriver"
"github.com/moby/sys/symlink"
)
// ContainerFS is that represents a root file system
type ContainerFS interface {
// Path returns the path to the root. Note that this may not exist
// on the local system, so the continuity operations must be used
Path() string
// ResolveScopedPath evaluates the given path scoped to the root.
// For example, if root=/a, and path=/b/c, then this function would return /a/b/c.
// If rawPath is true, then the function will not preform any modifications
// before path resolution. Otherwise, the function will clean the given path
// by making it an absolute path.
ResolveScopedPath(path string, rawPath bool) (string, error)
Driver
}
// Driver combines both continuity's Driver and PathDriver interfaces with a Platform
// field to determine the OS.
type Driver interface {
// OS returns the OS where the rootfs is located. Essentially, runtime.GOOS.
OS() string
// Architecture returns the hardware architecture where the
// container is located.
Architecture() string
// Driver & PathDriver provide methods to manipulate files & paths
driver.Driver
pathdriver.PathDriver
}
// NewLocalContainerFS is a helper function to implement daemon's Mount interface
// when the graphdriver mount point is a local path on the machine.
func NewLocalContainerFS(path string) ContainerFS {
return &local{
path: path,
Driver: driver.LocalDriver,
PathDriver: pathdriver.LocalPathDriver,
}
}
// NewLocalDriver provides file and path drivers for a local file system. They are
// essentially a wrapper around the `os` and `filepath` functions.
func NewLocalDriver() Driver {
return &local{
Driver: driver.LocalDriver,
PathDriver: pathdriver.LocalPathDriver,
}
}
type local struct {
path string
driver.Driver
pathdriver.PathDriver
}
func (l *local) Path() string {
return l.path
}
func (l *local) ResolveScopedPath(path string, rawPath bool) (string, error) {
cleanedPath := path
if !rawPath {
cleanedPath = cleanScopedPath(path)
}
return symlink.FollowSymlinkInScope(filepath.Join(l.path, cleanedPath), l.path)
}
func (l *local) OS() string {
return runtime.GOOS
}
func (l *local) Architecture() string {
return runtime.GOARCH
// ResolveScopedPath evaluates the given path scoped to the root.
// For example, if root=/a, and path=/b/c, then this function would return /a/b/c.
func ResolveScopedPath(root, path string) (string, error) {
return symlink.FollowSymlinkInScope(filepath.Join(root, path), root)
}

View File

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

View File

@ -2,9 +2,9 @@ package containerfs // import "github.com/docker/docker/pkg/containerfs"
import "path/filepath"
// cleanScopedPath removes the C:\ syntax, and prepares to combine
// CleanScopedPath removes the C:\ syntax, and prepares to combine
// with a volume path
func cleanScopedPath(path string) string {
func CleanScopedPath(path string) string {
if len(path) >= 2 {
c := path[0]
if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {

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

View File

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

View File

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

View File

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

View File

@ -12,7 +12,6 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/daemon/initlayer"
"github.com/docker/docker/errdefs"
"github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/plugins"
"github.com/docker/docker/pkg/stringid"
@ -55,7 +54,7 @@ func (pm *Manager) enable(p *v2.Plugin, c *controller, force bool) error {
}
}
rootFS := containerfs.NewLocalContainerFS(filepath.Join(pm.config.Root, p.PluginObj.ID, rootFSFileName))
rootFS := filepath.Join(pm.config.Root, p.PluginObj.ID, rootFSFileName)
if err := initlayer.Setup(rootFS, idtools.Identity{UID: 0, GID: 0}); err != nil {
return errors.WithStack(err)
}

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/driver
github.com/containerd/continuity/fs
github.com/containerd/continuity/pathdriver
github.com/containerd/continuity/sysx
# github.com/containerd/fifo v1.0.0
## explicit; go 1.13