Use local "ensureRemoveAll" instead of docker/pkg/system
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
46fcfe5219
commit
e093a0ee08
@ -20,7 +20,6 @@ import (
|
|||||||
"github.com/containerd/containerd"
|
"github.com/containerd/containerd"
|
||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/containerd/errdefs"
|
||||||
"github.com/containerd/containerd/log"
|
"github.com/containerd/containerd/log"
|
||||||
"github.com/docker/docker/pkg/system"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
||||||
@ -76,12 +75,12 @@ func (c *criService) RemoveContainer(ctx context.Context, r *runtime.RemoveConta
|
|||||||
}
|
}
|
||||||
|
|
||||||
containerRootDir := c.getContainerRootDir(id)
|
containerRootDir := c.getContainerRootDir(id)
|
||||||
if err := system.EnsureRemoveAll(containerRootDir); err != nil {
|
if err := ensureRemoveAll(ctx, containerRootDir); err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to remove container root directory %q",
|
return nil, errors.Wrapf(err, "failed to remove container root directory %q",
|
||||||
containerRootDir)
|
containerRootDir)
|
||||||
}
|
}
|
||||||
volatileContainerRootDir := c.getVolatileContainerRootDir(id)
|
volatileContainerRootDir := c.getVolatileContainerRootDir(id)
|
||||||
if err := system.EnsureRemoveAll(volatileContainerRootDir); err != nil {
|
if err := ensureRemoveAll(ctx, volatileContainerRootDir); err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to remove volatile container root directory %q",
|
return nil, errors.Wrapf(err, "failed to remove volatile container root directory %q",
|
||||||
volatileContainerRootDir)
|
volatileContainerRootDir)
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"io/ioutil"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
@ -467,3 +468,31 @@ func TestPassThroughAnnotationsFilter(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEnsureRemoveAllNotExist(t *testing.T) {
|
||||||
|
// should never return an error for a non-existent path
|
||||||
|
if err := ensureRemoveAll(context.Background(), "/non/existent/path"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnsureRemoveAllWithDir(t *testing.T) {
|
||||||
|
dir, err := ioutil.TempDir("", "test-ensure-removeall-with-dir")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := ensureRemoveAll(context.Background(), dir); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnsureRemoveAllWithFile(t *testing.T) {
|
||||||
|
tmp, err := ioutil.TempFile("", "test-ensure-removeall-with-dir")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
tmp.Close()
|
||||||
|
if err := ensureRemoveAll(context.Background(), tmp.Name()); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -19,17 +19,24 @@ limitations under the License.
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/log"
|
||||||
|
"github.com/containerd/containerd/mount"
|
||||||
runcapparmor "github.com/opencontainers/runc/libcontainer/apparmor"
|
runcapparmor "github.com/opencontainers/runc/libcontainer/apparmor"
|
||||||
runcseccomp "github.com/opencontainers/runc/libcontainer/seccomp"
|
runcseccomp "github.com/opencontainers/runc/libcontainer/seccomp"
|
||||||
"github.com/opencontainers/selinux/go-selinux/label"
|
"github.com/opencontainers/selinux/go-selinux/label"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -141,3 +148,106 @@ func (c *criService) seccompEnabled() bool {
|
|||||||
func openLogFile(path string) (*os.File, error) {
|
func openLogFile(path string) (*os.File, error) {
|
||||||
return os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0640)
|
return os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0640)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// unmountRecursive unmounts the target and all mounts underneath, starting with
|
||||||
|
// the deepest mount first.
|
||||||
|
func unmountRecursive(ctx context.Context, target string) error {
|
||||||
|
mounts, err := mount.Self()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var toUnmount []string
|
||||||
|
for _, m := range mounts {
|
||||||
|
p, err := filepath.Rel(target, m.Mountpoint)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(p, "..") {
|
||||||
|
toUnmount = append(toUnmount, m.Mountpoint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the deepest mount be first
|
||||||
|
sort.Slice(toUnmount, func(i, j int) bool {
|
||||||
|
return len(toUnmount[i]) > len(toUnmount[j])
|
||||||
|
})
|
||||||
|
|
||||||
|
for i, mountPath := range toUnmount {
|
||||||
|
if err := mount.UnmountAll(mountPath, unix.MNT_DETACH); err != nil {
|
||||||
|
if i == len(toUnmount)-1 { // last mount
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// This is some submount, we can ignore this error for now, the final unmount will fail if this is a real problem
|
||||||
|
log.G(ctx).WithError(err).Debugf("failed to unmount submount %s", mountPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensureRemoveAll wraps `os.RemoveAll` to check for specific errors that can
|
||||||
|
// often be remedied.
|
||||||
|
// Only use `ensureRemoveAll` if you really want to make every effort to remove
|
||||||
|
// a directory.
|
||||||
|
//
|
||||||
|
// Because of the way `os.Remove` (and by extension `os.RemoveAll`) works, there
|
||||||
|
// can be a race between reading directory entries and then actually attempting
|
||||||
|
// to remove everything in the directory.
|
||||||
|
// These types of errors do not need to be returned since it's ok for the dir to
|
||||||
|
// be gone we can just retry the remove operation.
|
||||||
|
//
|
||||||
|
// This should not return a `os.ErrNotExist` kind of error under any circumstances
|
||||||
|
func ensureRemoveAll(ctx context.Context, dir string) error {
|
||||||
|
notExistErr := make(map[string]bool)
|
||||||
|
|
||||||
|
// track retries
|
||||||
|
exitOnErr := make(map[string]int)
|
||||||
|
maxRetry := 50
|
||||||
|
|
||||||
|
// Attempt to unmount anything beneath this dir first.
|
||||||
|
if err := unmountRecursive(ctx, dir); err != nil {
|
||||||
|
log.G(ctx).WithError(err).Debugf("failed to do initial unmount of %s", dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
err := os.RemoveAll(dir)
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
pe, ok := err.(*os.PathError)
|
||||||
|
if !ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
if notExistErr[pe.Path] {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
notExistErr[pe.Path] = true
|
||||||
|
|
||||||
|
// There is a race where some subdir can be removed but after the
|
||||||
|
// parent dir entries have been read.
|
||||||
|
// So the path could be from `os.Remove(subdir)`
|
||||||
|
// If the reported non-existent path is not the passed in `dir` we
|
||||||
|
// should just retry, but otherwise return with no error.
|
||||||
|
if pe.Path == dir {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if pe.Err != syscall.EBUSY {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if e := mount.Unmount(pe.Path, unix.MNT_DETACH); e != nil {
|
||||||
|
return errors.Wrapf(e, "error while removing %s", dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
if exitOnErr[pe.Path] == maxRetry {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
exitOnErr[pe.Path]++
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -19,9 +19,15 @@ limitations under the License.
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetCgroupsPath(t *testing.T) {
|
func TestGetCgroupsPath(t *testing.T) {
|
||||||
@ -56,3 +62,47 @@ func TestGetCgroupsPath(t *testing.T) {
|
|||||||
assert.Equal(t, test.expected, got)
|
assert.Equal(t, test.expected, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEnsureRemoveAllWithMount(t *testing.T) {
|
||||||
|
if os.Getuid() != 0 {
|
||||||
|
t.Skip("skipping test that requires root")
|
||||||
|
}
|
||||||
|
|
||||||
|
dir1, err := ioutil.TempDir("", "test-ensure-removeall-with-dir1")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
dir2, err := ioutil.TempDir("", "test-ensure-removeall-with-dir2")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(dir2)
|
||||||
|
|
||||||
|
bindDir := filepath.Join(dir1, "bind")
|
||||||
|
if err := os.MkdirAll(bindDir, 0755); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := unix.Mount(dir2, bindDir, "none", unix.MS_BIND, ""); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
err = ensureRemoveAll(context.Background(), dir1)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
case <-time.After(5 * time.Second):
|
||||||
|
t.Fatal("timeout waiting for EnsureRemoveAll to finish")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := os.Stat(dir1); !os.IsNotExist(err) {
|
||||||
|
t.Fatalf("expected %q to not exist", dir1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -19,9 +19,11 @@ limitations under the License.
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// openLogFile opens/creates a container log file.
|
// openLogFile opens/creates a container log file.
|
||||||
@ -156,3 +158,62 @@ func fixLongPath(path string) string {
|
|||||||
}
|
}
|
||||||
return string(pathbuf[:w])
|
return string(pathbuf[:w])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensureRemoveAll wraps `os.RemoveAll` to check for specific errors that can
|
||||||
|
// often be remedied.
|
||||||
|
// Only use `ensureRemoveAll` if you really want to make every effort to remove
|
||||||
|
// a directory.
|
||||||
|
//
|
||||||
|
// Because of the way `os.Remove` (and by extension `os.RemoveAll`) works, there
|
||||||
|
// can be a race between reading directory entries and then actually attempting
|
||||||
|
// to remove everything in the directory.
|
||||||
|
// These types of errors do not need to be returned since it's ok for the dir to
|
||||||
|
// be gone we can just retry the remove operation.
|
||||||
|
//
|
||||||
|
// This should not return a `os.ErrNotExist` kind of error under any circumstances
|
||||||
|
func ensureRemoveAll(_ context.Context, dir string) error {
|
||||||
|
notExistErr := make(map[string]bool)
|
||||||
|
|
||||||
|
// track retries
|
||||||
|
exitOnErr := make(map[string]int)
|
||||||
|
maxRetry := 50
|
||||||
|
|
||||||
|
for {
|
||||||
|
err := os.RemoveAll(dir)
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
pe, ok := err.(*os.PathError)
|
||||||
|
if !ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
if notExistErr[pe.Path] {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
notExistErr[pe.Path] = true
|
||||||
|
|
||||||
|
// There is a race where some subdir can be removed but after the
|
||||||
|
// parent dir entries have been read.
|
||||||
|
// So the path could be from `os.Remove(subdir)`
|
||||||
|
// If the reported non-existent path is not the passed in `dir` we
|
||||||
|
// should just retry, but otherwise return with no error.
|
||||||
|
if pe.Path == dir {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if pe.Err != syscall.EBUSY {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if exitOnErr[pe.Path] == maxRetry {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
exitOnErr[pe.Path]++
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -30,7 +30,6 @@ import (
|
|||||||
"github.com/containerd/containerd/log"
|
"github.com/containerd/containerd/log"
|
||||||
"github.com/containerd/containerd/platforms"
|
"github.com/containerd/containerd/platforms"
|
||||||
"github.com/containerd/typeurl"
|
"github.com/containerd/typeurl"
|
||||||
"github.com/docker/docker/pkg/system"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
||||||
@ -474,7 +473,7 @@ func cleanupOrphanedIDDirs(ctx context.Context, cntrs []containerd.Container, ba
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
dir := filepath.Join(base, d.Name())
|
dir := filepath.Join(base, d.Name())
|
||||||
if err := system.EnsureRemoveAll(dir); err != nil {
|
if err := ensureRemoveAll(ctx, dir); err != nil {
|
||||||
log.G(ctx).WithError(err).Warnf("Failed to remove id directory %q", dir)
|
log.G(ctx).WithError(err).Warnf("Failed to remove id directory %q", dir)
|
||||||
} else {
|
} else {
|
||||||
log.G(ctx).Debugf("Cleanup orphaned id directory %q", dir)
|
log.G(ctx).Debugf("Cleanup orphaned id directory %q", dir)
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
"github.com/containerd/containerd"
|
"github.com/containerd/containerd"
|
||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/containerd/errdefs"
|
||||||
"github.com/containerd/containerd/log"
|
"github.com/containerd/containerd/log"
|
||||||
"github.com/docker/docker/pkg/system"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
||||||
@ -80,12 +79,12 @@ func (c *criService) RemovePodSandbox(ctx context.Context, r *runtime.RemovePodS
|
|||||||
|
|
||||||
// Cleanup the sandbox root directories.
|
// Cleanup the sandbox root directories.
|
||||||
sandboxRootDir := c.getSandboxRootDir(id)
|
sandboxRootDir := c.getSandboxRootDir(id)
|
||||||
if err := system.EnsureRemoveAll(sandboxRootDir); err != nil {
|
if err := ensureRemoveAll(ctx, sandboxRootDir); err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to remove sandbox root directory %q",
|
return nil, errors.Wrapf(err, "failed to remove sandbox root directory %q",
|
||||||
sandboxRootDir)
|
sandboxRootDir)
|
||||||
}
|
}
|
||||||
volatileSandboxRootDir := c.getVolatileSandboxRootDir(id)
|
volatileSandboxRootDir := c.getVolatileSandboxRootDir(id)
|
||||||
if err := system.EnsureRemoveAll(volatileSandboxRootDir); err != nil {
|
if err := ensureRemoveAll(ctx, volatileSandboxRootDir); err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to remove volatile sandbox root directory %q",
|
return nil, errors.Wrapf(err, "failed to remove volatile sandbox root directory %q",
|
||||||
volatileSandboxRootDir)
|
volatileSandboxRootDir)
|
||||||
}
|
}
|
||||||
|
137
vendor/github.com/docker/docker/pkg/mount/flags.go
generated
vendored
137
vendor/github.com/docker/docker/pkg/mount/flags.go
generated
vendored
@ -1,137 +0,0 @@
|
|||||||
package mount // import "github.com/docker/docker/pkg/mount"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var flags = map[string]struct {
|
|
||||||
clear bool
|
|
||||||
flag int
|
|
||||||
}{
|
|
||||||
"defaults": {false, 0},
|
|
||||||
"ro": {false, RDONLY},
|
|
||||||
"rw": {true, RDONLY},
|
|
||||||
"suid": {true, NOSUID},
|
|
||||||
"nosuid": {false, NOSUID},
|
|
||||||
"dev": {true, NODEV},
|
|
||||||
"nodev": {false, NODEV},
|
|
||||||
"exec": {true, NOEXEC},
|
|
||||||
"noexec": {false, NOEXEC},
|
|
||||||
"sync": {false, SYNCHRONOUS},
|
|
||||||
"async": {true, SYNCHRONOUS},
|
|
||||||
"dirsync": {false, DIRSYNC},
|
|
||||||
"remount": {false, REMOUNT},
|
|
||||||
"mand": {false, MANDLOCK},
|
|
||||||
"nomand": {true, MANDLOCK},
|
|
||||||
"atime": {true, NOATIME},
|
|
||||||
"noatime": {false, NOATIME},
|
|
||||||
"diratime": {true, NODIRATIME},
|
|
||||||
"nodiratime": {false, NODIRATIME},
|
|
||||||
"bind": {false, BIND},
|
|
||||||
"rbind": {false, RBIND},
|
|
||||||
"unbindable": {false, UNBINDABLE},
|
|
||||||
"runbindable": {false, RUNBINDABLE},
|
|
||||||
"private": {false, PRIVATE},
|
|
||||||
"rprivate": {false, RPRIVATE},
|
|
||||||
"shared": {false, SHARED},
|
|
||||||
"rshared": {false, RSHARED},
|
|
||||||
"slave": {false, SLAVE},
|
|
||||||
"rslave": {false, RSLAVE},
|
|
||||||
"relatime": {false, RELATIME},
|
|
||||||
"norelatime": {true, RELATIME},
|
|
||||||
"strictatime": {false, STRICTATIME},
|
|
||||||
"nostrictatime": {true, STRICTATIME},
|
|
||||||
}
|
|
||||||
|
|
||||||
var validFlags = map[string]bool{
|
|
||||||
"": true,
|
|
||||||
"size": true,
|
|
||||||
"mode": true,
|
|
||||||
"uid": true,
|
|
||||||
"gid": true,
|
|
||||||
"nr_inodes": true,
|
|
||||||
"nr_blocks": true,
|
|
||||||
"mpol": true,
|
|
||||||
}
|
|
||||||
|
|
||||||
var propagationFlags = map[string]bool{
|
|
||||||
"bind": true,
|
|
||||||
"rbind": true,
|
|
||||||
"unbindable": true,
|
|
||||||
"runbindable": true,
|
|
||||||
"private": true,
|
|
||||||
"rprivate": true,
|
|
||||||
"shared": true,
|
|
||||||
"rshared": true,
|
|
||||||
"slave": true,
|
|
||||||
"rslave": true,
|
|
||||||
}
|
|
||||||
|
|
||||||
// MergeTmpfsOptions merge mount options to make sure there is no duplicate.
|
|
||||||
func MergeTmpfsOptions(options []string) ([]string, error) {
|
|
||||||
// We use collisions maps to remove duplicates.
|
|
||||||
// For flag, the key is the flag value (the key for propagation flag is -1)
|
|
||||||
// For data=value, the key is the data
|
|
||||||
flagCollisions := map[int]bool{}
|
|
||||||
dataCollisions := map[string]bool{}
|
|
||||||
|
|
||||||
var newOptions []string
|
|
||||||
// We process in reverse order
|
|
||||||
for i := len(options) - 1; i >= 0; i-- {
|
|
||||||
option := options[i]
|
|
||||||
if option == "defaults" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if f, ok := flags[option]; ok && f.flag != 0 {
|
|
||||||
// There is only one propagation mode
|
|
||||||
key := f.flag
|
|
||||||
if propagationFlags[option] {
|
|
||||||
key = -1
|
|
||||||
}
|
|
||||||
// Check to see if there is collision for flag
|
|
||||||
if !flagCollisions[key] {
|
|
||||||
// We prepend the option and add to collision map
|
|
||||||
newOptions = append([]string{option}, newOptions...)
|
|
||||||
flagCollisions[key] = true
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
opt := strings.SplitN(option, "=", 2)
|
|
||||||
if len(opt) != 2 || !validFlags[opt[0]] {
|
|
||||||
return nil, fmt.Errorf("Invalid tmpfs option %q", opt)
|
|
||||||
}
|
|
||||||
if !dataCollisions[opt[0]] {
|
|
||||||
// We prepend the option and add to collision map
|
|
||||||
newOptions = append([]string{option}, newOptions...)
|
|
||||||
dataCollisions[opt[0]] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return newOptions, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse fstab type mount options into mount() flags
|
|
||||||
// and device specific data
|
|
||||||
func parseOptions(options string) (int, string) {
|
|
||||||
var (
|
|
||||||
flag int
|
|
||||||
data []string
|
|
||||||
)
|
|
||||||
|
|
||||||
for _, o := range strings.Split(options, ",") {
|
|
||||||
// If the option does not exist in the flags table or the flag
|
|
||||||
// is not supported on the platform,
|
|
||||||
// then it is a data value for a specific fs type
|
|
||||||
if f, exists := flags[o]; exists && f.flag != 0 {
|
|
||||||
if f.clear {
|
|
||||||
flag &= ^f.flag
|
|
||||||
} else {
|
|
||||||
flag |= f.flag
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
data = append(data, o)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return flag, strings.Join(data, ",")
|
|
||||||
}
|
|
49
vendor/github.com/docker/docker/pkg/mount/flags_freebsd.go
generated
vendored
49
vendor/github.com/docker/docker/pkg/mount/flags_freebsd.go
generated
vendored
@ -1,49 +0,0 @@
|
|||||||
// +build freebsd,cgo
|
|
||||||
|
|
||||||
package mount // import "github.com/docker/docker/pkg/mount"
|
|
||||||
|
|
||||||
/*
|
|
||||||
#include <sys/mount.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
const (
|
|
||||||
// RDONLY will mount the filesystem as read-only.
|
|
||||||
RDONLY = C.MNT_RDONLY
|
|
||||||
|
|
||||||
// NOSUID will not allow set-user-identifier or set-group-identifier bits to
|
|
||||||
// take effect.
|
|
||||||
NOSUID = C.MNT_NOSUID
|
|
||||||
|
|
||||||
// NOEXEC will not allow execution of any binaries on the mounted file system.
|
|
||||||
NOEXEC = C.MNT_NOEXEC
|
|
||||||
|
|
||||||
// SYNCHRONOUS will allow any I/O to the file system to be done synchronously.
|
|
||||||
SYNCHRONOUS = C.MNT_SYNCHRONOUS
|
|
||||||
|
|
||||||
// NOATIME will not update the file access time when reading from a file.
|
|
||||||
NOATIME = C.MNT_NOATIME
|
|
||||||
)
|
|
||||||
|
|
||||||
// These flags are unsupported.
|
|
||||||
const (
|
|
||||||
BIND = 0
|
|
||||||
DIRSYNC = 0
|
|
||||||
MANDLOCK = 0
|
|
||||||
NODEV = 0
|
|
||||||
NODIRATIME = 0
|
|
||||||
UNBINDABLE = 0
|
|
||||||
RUNBINDABLE = 0
|
|
||||||
PRIVATE = 0
|
|
||||||
RPRIVATE = 0
|
|
||||||
SHARED = 0
|
|
||||||
RSHARED = 0
|
|
||||||
SLAVE = 0
|
|
||||||
RSLAVE = 0
|
|
||||||
RBIND = 0
|
|
||||||
RELATIVE = 0
|
|
||||||
RELATIME = 0
|
|
||||||
REMOUNT = 0
|
|
||||||
STRICTATIME = 0
|
|
||||||
mntDetach = 0
|
|
||||||
)
|
|
87
vendor/github.com/docker/docker/pkg/mount/flags_linux.go
generated
vendored
87
vendor/github.com/docker/docker/pkg/mount/flags_linux.go
generated
vendored
@ -1,87 +0,0 @@
|
|||||||
package mount // import "github.com/docker/docker/pkg/mount"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// RDONLY will mount the file system read-only.
|
|
||||||
RDONLY = unix.MS_RDONLY
|
|
||||||
|
|
||||||
// NOSUID will not allow set-user-identifier or set-group-identifier bits to
|
|
||||||
// take effect.
|
|
||||||
NOSUID = unix.MS_NOSUID
|
|
||||||
|
|
||||||
// NODEV will not interpret character or block special devices on the file
|
|
||||||
// system.
|
|
||||||
NODEV = unix.MS_NODEV
|
|
||||||
|
|
||||||
// NOEXEC will not allow execution of any binaries on the mounted file system.
|
|
||||||
NOEXEC = unix.MS_NOEXEC
|
|
||||||
|
|
||||||
// SYNCHRONOUS will allow I/O to the file system to be done synchronously.
|
|
||||||
SYNCHRONOUS = unix.MS_SYNCHRONOUS
|
|
||||||
|
|
||||||
// DIRSYNC will force all directory updates within the file system to be done
|
|
||||||
// synchronously. This affects the following system calls: create, link,
|
|
||||||
// unlink, symlink, mkdir, rmdir, mknod and rename.
|
|
||||||
DIRSYNC = unix.MS_DIRSYNC
|
|
||||||
|
|
||||||
// REMOUNT will attempt to remount an already-mounted file system. This is
|
|
||||||
// commonly used to change the mount flags for a file system, especially to
|
|
||||||
// make a readonly file system writeable. It does not change device or mount
|
|
||||||
// point.
|
|
||||||
REMOUNT = unix.MS_REMOUNT
|
|
||||||
|
|
||||||
// MANDLOCK will force mandatory locks on a filesystem.
|
|
||||||
MANDLOCK = unix.MS_MANDLOCK
|
|
||||||
|
|
||||||
// NOATIME will not update the file access time when reading from a file.
|
|
||||||
NOATIME = unix.MS_NOATIME
|
|
||||||
|
|
||||||
// NODIRATIME will not update the directory access time.
|
|
||||||
NODIRATIME = unix.MS_NODIRATIME
|
|
||||||
|
|
||||||
// BIND remounts a subtree somewhere else.
|
|
||||||
BIND = unix.MS_BIND
|
|
||||||
|
|
||||||
// RBIND remounts a subtree and all possible submounts somewhere else.
|
|
||||||
RBIND = unix.MS_BIND | unix.MS_REC
|
|
||||||
|
|
||||||
// UNBINDABLE creates a mount which cannot be cloned through a bind operation.
|
|
||||||
UNBINDABLE = unix.MS_UNBINDABLE
|
|
||||||
|
|
||||||
// RUNBINDABLE marks the entire mount tree as UNBINDABLE.
|
|
||||||
RUNBINDABLE = unix.MS_UNBINDABLE | unix.MS_REC
|
|
||||||
|
|
||||||
// PRIVATE creates a mount which carries no propagation abilities.
|
|
||||||
PRIVATE = unix.MS_PRIVATE
|
|
||||||
|
|
||||||
// RPRIVATE marks the entire mount tree as PRIVATE.
|
|
||||||
RPRIVATE = unix.MS_PRIVATE | unix.MS_REC
|
|
||||||
|
|
||||||
// SLAVE creates a mount which receives propagation from its master, but not
|
|
||||||
// vice versa.
|
|
||||||
SLAVE = unix.MS_SLAVE
|
|
||||||
|
|
||||||
// RSLAVE marks the entire mount tree as SLAVE.
|
|
||||||
RSLAVE = unix.MS_SLAVE | unix.MS_REC
|
|
||||||
|
|
||||||
// SHARED creates a mount which provides the ability to create mirrors of
|
|
||||||
// that mount such that mounts and unmounts within any of the mirrors
|
|
||||||
// propagate to the other mirrors.
|
|
||||||
SHARED = unix.MS_SHARED
|
|
||||||
|
|
||||||
// RSHARED marks the entire mount tree as SHARED.
|
|
||||||
RSHARED = unix.MS_SHARED | unix.MS_REC
|
|
||||||
|
|
||||||
// RELATIME updates inode access times relative to modify or change time.
|
|
||||||
RELATIME = unix.MS_RELATIME
|
|
||||||
|
|
||||||
// STRICTATIME allows to explicitly request full atime updates. This makes
|
|
||||||
// it possible for the kernel to default to relatime or noatime but still
|
|
||||||
// allow userspace to override it.
|
|
||||||
STRICTATIME = unix.MS_STRICTATIME
|
|
||||||
|
|
||||||
mntDetach = unix.MNT_DETACH
|
|
||||||
)
|
|
31
vendor/github.com/docker/docker/pkg/mount/flags_unsupported.go
generated
vendored
31
vendor/github.com/docker/docker/pkg/mount/flags_unsupported.go
generated
vendored
@ -1,31 +0,0 @@
|
|||||||
// +build !linux,!freebsd freebsd,!cgo
|
|
||||||
|
|
||||||
package mount // import "github.com/docker/docker/pkg/mount"
|
|
||||||
|
|
||||||
// These flags are unsupported.
|
|
||||||
const (
|
|
||||||
BIND = 0
|
|
||||||
DIRSYNC = 0
|
|
||||||
MANDLOCK = 0
|
|
||||||
NOATIME = 0
|
|
||||||
NODEV = 0
|
|
||||||
NODIRATIME = 0
|
|
||||||
NOEXEC = 0
|
|
||||||
NOSUID = 0
|
|
||||||
UNBINDABLE = 0
|
|
||||||
RUNBINDABLE = 0
|
|
||||||
PRIVATE = 0
|
|
||||||
RPRIVATE = 0
|
|
||||||
SHARED = 0
|
|
||||||
RSHARED = 0
|
|
||||||
SLAVE = 0
|
|
||||||
RSLAVE = 0
|
|
||||||
RBIND = 0
|
|
||||||
RELATIME = 0
|
|
||||||
RELATIVE = 0
|
|
||||||
REMOUNT = 0
|
|
||||||
STRICTATIME = 0
|
|
||||||
SYNCHRONOUS = 0
|
|
||||||
RDONLY = 0
|
|
||||||
mntDetach = 0
|
|
||||||
)
|
|
159
vendor/github.com/docker/docker/pkg/mount/mount.go
generated
vendored
159
vendor/github.com/docker/docker/pkg/mount/mount.go
generated
vendored
@ -1,159 +0,0 @@
|
|||||||
package mount // import "github.com/docker/docker/pkg/mount"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
// mountError records an error from mount or unmount operation
|
|
||||||
type mountError struct {
|
|
||||||
op string
|
|
||||||
source, target string
|
|
||||||
flags uintptr
|
|
||||||
data string
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *mountError) Error() string {
|
|
||||||
out := e.op + " "
|
|
||||||
|
|
||||||
if e.source != "" {
|
|
||||||
out += e.source + ":" + e.target
|
|
||||||
} else {
|
|
||||||
out += e.target
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.flags != uintptr(0) {
|
|
||||||
out += ", flags: 0x" + strconv.FormatUint(uint64(e.flags), 16)
|
|
||||||
}
|
|
||||||
if e.data != "" {
|
|
||||||
out += ", data: " + e.data
|
|
||||||
}
|
|
||||||
|
|
||||||
out += ": " + e.err.Error()
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cause returns the underlying cause of the error
|
|
||||||
func (e *mountError) Cause() error {
|
|
||||||
return e.err
|
|
||||||
}
|
|
||||||
|
|
||||||
// FilterFunc is a type defining a callback function
|
|
||||||
// to filter out unwanted entries. It takes a pointer
|
|
||||||
// to an Info struct (not fully populated, currently
|
|
||||||
// only Mountpoint is filled in), and returns two booleans:
|
|
||||||
// - skip: true if the entry should be skipped
|
|
||||||
// - stop: true if parsing should be stopped after the entry
|
|
||||||
type FilterFunc func(*Info) (skip, stop bool)
|
|
||||||
|
|
||||||
// PrefixFilter discards all entries whose mount points
|
|
||||||
// do not start with a prefix specified
|
|
||||||
func PrefixFilter(prefix string) FilterFunc {
|
|
||||||
return func(m *Info) (bool, bool) {
|
|
||||||
skip := !strings.HasPrefix(m.Mountpoint, prefix)
|
|
||||||
return skip, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SingleEntryFilter looks for a specific entry
|
|
||||||
func SingleEntryFilter(mp string) FilterFunc {
|
|
||||||
return func(m *Info) (bool, bool) {
|
|
||||||
if m.Mountpoint == mp {
|
|
||||||
return false, true // don't skip, stop now
|
|
||||||
}
|
|
||||||
return true, false // skip, keep going
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParentsFilter returns all entries whose mount points
|
|
||||||
// can be parents of a path specified, discarding others.
|
|
||||||
// For example, given `/var/lib/docker/something`, entries
|
|
||||||
// like `/var/lib/docker`, `/var` and `/` are returned.
|
|
||||||
func ParentsFilter(path string) FilterFunc {
|
|
||||||
return func(m *Info) (bool, bool) {
|
|
||||||
skip := !strings.HasPrefix(path, m.Mountpoint)
|
|
||||||
return skip, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMounts retrieves a list of mounts for the current running process,
|
|
||||||
// with an optional filter applied (use nil for no filter).
|
|
||||||
func GetMounts(f FilterFunc) ([]*Info, error) {
|
|
||||||
return parseMountTable(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mounted determines if a specified mountpoint has been mounted.
|
|
||||||
// On Linux it looks at /proc/self/mountinfo.
|
|
||||||
func Mounted(mountpoint string) (bool, error) {
|
|
||||||
entries, err := GetMounts(SingleEntryFilter(mountpoint))
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return len(entries) > 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mount will mount filesystem according to the specified configuration, on the
|
|
||||||
// condition that the target path is *not* already mounted. Options must be
|
|
||||||
// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See
|
|
||||||
// flags.go for supported option flags.
|
|
||||||
func Mount(device, target, mType, options string) error {
|
|
||||||
flag, data := parseOptions(options)
|
|
||||||
if flag&REMOUNT != REMOUNT {
|
|
||||||
if mounted, err := Mounted(target); err != nil || mounted {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mount(device, target, mType, uintptr(flag), data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ForceMount will mount a filesystem according to the specified configuration,
|
|
||||||
// *regardless* if the target path is not already mounted. Options must be
|
|
||||||
// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See
|
|
||||||
// flags.go for supported option flags.
|
|
||||||
func ForceMount(device, target, mType, options string) error {
|
|
||||||
flag, data := parseOptions(options)
|
|
||||||
return mount(device, target, mType, uintptr(flag), data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unmount lazily unmounts a filesystem on supported platforms, otherwise
|
|
||||||
// does a normal unmount.
|
|
||||||
func Unmount(target string) error {
|
|
||||||
return unmount(target, mntDetach)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RecursiveUnmount unmounts the target and all mounts underneath, starting with
|
|
||||||
// the deepsest mount first.
|
|
||||||
func RecursiveUnmount(target string) error {
|
|
||||||
mounts, err := parseMountTable(PrefixFilter(target))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make the deepest mount be first
|
|
||||||
sort.Slice(mounts, func(i, j int) bool {
|
|
||||||
return len(mounts[i].Mountpoint) > len(mounts[j].Mountpoint)
|
|
||||||
})
|
|
||||||
|
|
||||||
for i, m := range mounts {
|
|
||||||
logrus.Debugf("Trying to unmount %s", m.Mountpoint)
|
|
||||||
err = unmount(m.Mountpoint, mntDetach)
|
|
||||||
if err != nil {
|
|
||||||
if i == len(mounts)-1 { // last mount
|
|
||||||
if mounted, e := Mounted(m.Mountpoint); e != nil || mounted {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// This is some submount, we can ignore this error for now, the final unmount will fail if this is a real problem
|
|
||||||
logrus.WithError(err).Warnf("Failed to unmount submount %s", m.Mountpoint)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf("Unmounted %s", m.Mountpoint)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
59
vendor/github.com/docker/docker/pkg/mount/mounter_freebsd.go
generated
vendored
59
vendor/github.com/docker/docker/pkg/mount/mounter_freebsd.go
generated
vendored
@ -1,59 +0,0 @@
|
|||||||
package mount // import "github.com/docker/docker/pkg/mount"
|
|
||||||
|
|
||||||
/*
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/_iovec.h>
|
|
||||||
#include <sys/mount.h>
|
|
||||||
#include <sys/param.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
func allocateIOVecs(options []string) []C.struct_iovec {
|
|
||||||
out := make([]C.struct_iovec, len(options))
|
|
||||||
for i, option := range options {
|
|
||||||
out[i].iov_base = unsafe.Pointer(C.CString(option))
|
|
||||||
out[i].iov_len = C.size_t(len(option) + 1)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func mount(device, target, mType string, flag uintptr, data string) error {
|
|
||||||
isNullFS := false
|
|
||||||
|
|
||||||
xs := strings.Split(data, ",")
|
|
||||||
for _, x := range xs {
|
|
||||||
if x == "bind" {
|
|
||||||
isNullFS = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
options := []string{"fspath", target}
|
|
||||||
if isNullFS {
|
|
||||||
options = append(options, "fstype", "nullfs", "target", device)
|
|
||||||
} else {
|
|
||||||
options = append(options, "fstype", mType, "from", device)
|
|
||||||
}
|
|
||||||
rawOptions := allocateIOVecs(options)
|
|
||||||
for _, rawOption := range rawOptions {
|
|
||||||
defer C.free(rawOption.iov_base)
|
|
||||||
}
|
|
||||||
|
|
||||||
if errno := C.nmount(&rawOptions[0], C.uint(len(options)), C.int(flag)); errno != 0 {
|
|
||||||
return &mountError{
|
|
||||||
op: "mount",
|
|
||||||
source: device,
|
|
||||||
target: target,
|
|
||||||
flags: flag,
|
|
||||||
err: syscall.Errno(errno),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
73
vendor/github.com/docker/docker/pkg/mount/mounter_linux.go
generated
vendored
73
vendor/github.com/docker/docker/pkg/mount/mounter_linux.go
generated
vendored
@ -1,73 +0,0 @@
|
|||||||
package mount // import "github.com/docker/docker/pkg/mount"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// ptypes is the set propagation types.
|
|
||||||
ptypes = unix.MS_SHARED | unix.MS_PRIVATE | unix.MS_SLAVE | unix.MS_UNBINDABLE
|
|
||||||
|
|
||||||
// pflags is the full set valid flags for a change propagation call.
|
|
||||||
pflags = ptypes | unix.MS_REC | unix.MS_SILENT
|
|
||||||
|
|
||||||
// broflags is the combination of bind and read only
|
|
||||||
broflags = unix.MS_BIND | unix.MS_RDONLY
|
|
||||||
)
|
|
||||||
|
|
||||||
// isremount returns true if either device name or flags identify a remount request, false otherwise.
|
|
||||||
func isremount(device string, flags uintptr) bool {
|
|
||||||
switch {
|
|
||||||
// We treat device "" and "none" as a remount request to provide compatibility with
|
|
||||||
// requests that don't explicitly set MS_REMOUNT such as those manipulating bind mounts.
|
|
||||||
case flags&unix.MS_REMOUNT != 0, device == "", device == "none":
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func mount(device, target, mType string, flags uintptr, data string) error {
|
|
||||||
oflags := flags &^ ptypes
|
|
||||||
if !isremount(device, flags) || data != "" {
|
|
||||||
// Initial call applying all non-propagation flags for mount
|
|
||||||
// or remount with changed data
|
|
||||||
if err := unix.Mount(device, target, mType, oflags, data); err != nil {
|
|
||||||
return &mountError{
|
|
||||||
op: "mount",
|
|
||||||
source: device,
|
|
||||||
target: target,
|
|
||||||
flags: oflags,
|
|
||||||
data: data,
|
|
||||||
err: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags&ptypes != 0 {
|
|
||||||
// Change the propagation type.
|
|
||||||
if err := unix.Mount("", target, "", flags&pflags, ""); err != nil {
|
|
||||||
return &mountError{
|
|
||||||
op: "remount",
|
|
||||||
target: target,
|
|
||||||
flags: flags & pflags,
|
|
||||||
err: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if oflags&broflags == broflags {
|
|
||||||
// Remount the bind to apply read only.
|
|
||||||
if err := unix.Mount("", target, "", oflags|unix.MS_REMOUNT, ""); err != nil {
|
|
||||||
return &mountError{
|
|
||||||
op: "remount-ro",
|
|
||||||
target: target,
|
|
||||||
flags: oflags | unix.MS_REMOUNT,
|
|
||||||
err: err,
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
7
vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go
generated
vendored
7
vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go
generated
vendored
@ -1,7 +0,0 @@
|
|||||||
// +build !linux,!freebsd freebsd,!cgo
|
|
||||||
|
|
||||||
package mount // import "github.com/docker/docker/pkg/mount"
|
|
||||||
|
|
||||||
func mount(device, target, mType string, flag uintptr, data string) error {
|
|
||||||
panic("Not implemented")
|
|
||||||
}
|
|
40
vendor/github.com/docker/docker/pkg/mount/mountinfo.go
generated
vendored
40
vendor/github.com/docker/docker/pkg/mount/mountinfo.go
generated
vendored
@ -1,40 +0,0 @@
|
|||||||
package mount // import "github.com/docker/docker/pkg/mount"
|
|
||||||
|
|
||||||
// Info reveals information about a particular mounted filesystem. This
|
|
||||||
// struct is populated from the content in the /proc/<pid>/mountinfo file.
|
|
||||||
type Info struct {
|
|
||||||
// ID is a unique identifier of the mount (may be reused after umount).
|
|
||||||
ID int
|
|
||||||
|
|
||||||
// Parent indicates the ID of the mount parent (or of self for the top of the
|
|
||||||
// mount tree).
|
|
||||||
Parent int
|
|
||||||
|
|
||||||
// Major indicates one half of the device ID which identifies the device class.
|
|
||||||
Major int
|
|
||||||
|
|
||||||
// Minor indicates one half of the device ID which identifies a specific
|
|
||||||
// instance of device.
|
|
||||||
Minor int
|
|
||||||
|
|
||||||
// Root of the mount within the filesystem.
|
|
||||||
Root string
|
|
||||||
|
|
||||||
// Mountpoint indicates the mount point relative to the process's root.
|
|
||||||
Mountpoint string
|
|
||||||
|
|
||||||
// Opts represents mount-specific options.
|
|
||||||
Opts string
|
|
||||||
|
|
||||||
// Optional represents optional fields.
|
|
||||||
Optional string
|
|
||||||
|
|
||||||
// Fstype indicates the type of filesystem, such as EXT3.
|
|
||||||
Fstype string
|
|
||||||
|
|
||||||
// Source indicates filesystem specific information or "none".
|
|
||||||
Source string
|
|
||||||
|
|
||||||
// VfsOpts represents per super block options.
|
|
||||||
VfsOpts string
|
|
||||||
}
|
|
54
vendor/github.com/docker/docker/pkg/mount/mountinfo_freebsd.go
generated
vendored
54
vendor/github.com/docker/docker/pkg/mount/mountinfo_freebsd.go
generated
vendored
@ -1,54 +0,0 @@
|
|||||||
package mount // import "github.com/docker/docker/pkg/mount"
|
|
||||||
|
|
||||||
/*
|
|
||||||
#include <sys/param.h>
|
|
||||||
#include <sys/ucred.h>
|
|
||||||
#include <sys/mount.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// parseMountTable returns information about mounted filesystems
|
|
||||||
func parseMountTable(filter FilterFunc) ([]*Info, error) {
|
|
||||||
var rawEntries *C.struct_statfs
|
|
||||||
|
|
||||||
count := int(C.getmntinfo(&rawEntries, C.MNT_WAIT))
|
|
||||||
if count == 0 {
|
|
||||||
return nil, fmt.Errorf("Failed to call getmntinfo")
|
|
||||||
}
|
|
||||||
|
|
||||||
var entries []C.struct_statfs
|
|
||||||
header := (*reflect.SliceHeader)(unsafe.Pointer(&entries))
|
|
||||||
header.Cap = count
|
|
||||||
header.Len = count
|
|
||||||
header.Data = uintptr(unsafe.Pointer(rawEntries))
|
|
||||||
|
|
||||||
var out []*Info
|
|
||||||
for _, entry := range entries {
|
|
||||||
var mountinfo Info
|
|
||||||
var skip, stop bool
|
|
||||||
mountinfo.Mountpoint = C.GoString(&entry.f_mntonname[0])
|
|
||||||
|
|
||||||
if filter != nil {
|
|
||||||
// filter out entries we're not interested in
|
|
||||||
skip, stop = filter(&mountinfo)
|
|
||||||
if skip {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mountinfo.Source = C.GoString(&entry.f_mntfromname[0])
|
|
||||||
mountinfo.Fstype = C.GoString(&entry.f_fstypename[0])
|
|
||||||
|
|
||||||
out = append(out, &mountinfo)
|
|
||||||
if stop {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
143
vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go
generated
vendored
143
vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go
generated
vendored
@ -1,143 +0,0 @@
|
|||||||
package mount // import "github.com/docker/docker/pkg/mount"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
func parseInfoFile(r io.Reader, filter FilterFunc) ([]*Info, error) {
|
|
||||||
s := bufio.NewScanner(r)
|
|
||||||
out := []*Info{}
|
|
||||||
var err error
|
|
||||||
for s.Scan() {
|
|
||||||
if err = s.Err(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
See http://man7.org/linux/man-pages/man5/proc.5.html
|
|
||||||
|
|
||||||
36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
|
|
||||||
(1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
|
|
||||||
|
|
||||||
(1) mount ID: unique identifier of the mount (may be reused after umount)
|
|
||||||
(2) parent ID: ID of parent (or of self for the top of the mount tree)
|
|
||||||
(3) major:minor: value of st_dev for files on filesystem
|
|
||||||
(4) root: root of the mount within the filesystem
|
|
||||||
(5) mount point: mount point relative to the process's root
|
|
||||||
(6) mount options: per mount options
|
|
||||||
(7) optional fields: zero or more fields of the form "tag[:value]"
|
|
||||||
(8) separator: marks the end of the optional fields
|
|
||||||
(9) filesystem type: name of filesystem of the form "type[.subtype]"
|
|
||||||
(10) mount source: filesystem specific information or "none"
|
|
||||||
(11) super options: per super block options
|
|
||||||
*/
|
|
||||||
|
|
||||||
text := s.Text()
|
|
||||||
fields := strings.Split(text, " ")
|
|
||||||
numFields := len(fields)
|
|
||||||
if numFields < 10 {
|
|
||||||
// should be at least 10 fields
|
|
||||||
return nil, fmt.Errorf("Parsing '%s' failed: not enough fields (%d)", text, numFields)
|
|
||||||
}
|
|
||||||
|
|
||||||
p := &Info{}
|
|
||||||
// ignore any numbers parsing errors, as there should not be any
|
|
||||||
p.ID, _ = strconv.Atoi(fields[0])
|
|
||||||
p.Parent, _ = strconv.Atoi(fields[1])
|
|
||||||
mm := strings.Split(fields[2], ":")
|
|
||||||
if len(mm) != 2 {
|
|
||||||
return nil, fmt.Errorf("Parsing '%s' failed: unexpected minor:major pair %s", text, mm)
|
|
||||||
}
|
|
||||||
p.Major, _ = strconv.Atoi(mm[0])
|
|
||||||
p.Minor, _ = strconv.Atoi(mm[1])
|
|
||||||
|
|
||||||
p.Root, err = strconv.Unquote(`"` + fields[3] + `"`)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "Parsing '%s' failed: unable to unquote root field", fields[3])
|
|
||||||
}
|
|
||||||
|
|
||||||
p.Mountpoint, err = strconv.Unquote(`"` + fields[4] + `"`)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "Parsing '%s' failed: unable to unquote mount point field", fields[4])
|
|
||||||
}
|
|
||||||
p.Opts = fields[5]
|
|
||||||
|
|
||||||
var skip, stop bool
|
|
||||||
if filter != nil {
|
|
||||||
// filter out entries we're not interested in
|
|
||||||
skip, stop = filter(p)
|
|
||||||
if skip {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// one or more optional fields, when a separator (-)
|
|
||||||
i := 6
|
|
||||||
for ; i < numFields && fields[i] != "-"; i++ {
|
|
||||||
switch i {
|
|
||||||
case 6:
|
|
||||||
p.Optional = fields[6]
|
|
||||||
default:
|
|
||||||
/* NOTE there might be more optional fields before the such as
|
|
||||||
fields[7]...fields[N] (where N < sepIndex), although
|
|
||||||
as of Linux kernel 4.15 the only known ones are
|
|
||||||
mount propagation flags in fields[6]. The correct
|
|
||||||
behavior is to ignore any unknown optional fields.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if i == numFields {
|
|
||||||
return nil, fmt.Errorf("Parsing '%s' failed: missing separator ('-')", text)
|
|
||||||
}
|
|
||||||
|
|
||||||
// There should be 3 fields after the separator...
|
|
||||||
if i+4 > numFields {
|
|
||||||
return nil, fmt.Errorf("Parsing '%s' failed: not enough fields after a separator", text)
|
|
||||||
}
|
|
||||||
// ... but in Linux <= 3.9 mounting a cifs with spaces in a share name
|
|
||||||
// (like "//serv/My Documents") _may_ end up having a space in the last field
|
|
||||||
// of mountinfo (like "unc=//serv/My Documents"). Since kernel 3.10-rc1, cifs
|
|
||||||
// option unc= is ignored, so a space should not appear. In here we ignore
|
|
||||||
// those "extra" fields caused by extra spaces.
|
|
||||||
p.Fstype = fields[i+1]
|
|
||||||
p.Source = fields[i+2]
|
|
||||||
p.VfsOpts = fields[i+3]
|
|
||||||
|
|
||||||
out = append(out, p)
|
|
||||||
if stop {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse /proc/self/mountinfo because comparing Dev and ino does not work from
|
|
||||||
// bind mounts
|
|
||||||
func parseMountTable(filter FilterFunc) ([]*Info, error) {
|
|
||||||
f, err := os.Open("/proc/self/mountinfo")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
return parseInfoFile(f, filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PidMountInfo collects the mounts for a specific process ID. If the process
|
|
||||||
// ID is unknown, it is better to use `GetMounts` which will inspect
|
|
||||||
// "/proc/self/mountinfo" instead.
|
|
||||||
func PidMountInfo(pid int) ([]*Info, error) {
|
|
||||||
f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
return parseInfoFile(f, nil)
|
|
||||||
}
|
|
12
vendor/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go
generated
vendored
12
vendor/github.com/docker/docker/pkg/mount/mountinfo_unsupported.go
generated
vendored
@ -1,12 +0,0 @@
|
|||||||
// +build !windows,!linux,!freebsd freebsd,!cgo
|
|
||||||
|
|
||||||
package mount // import "github.com/docker/docker/pkg/mount"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
func parseMountTable(f FilterFunc) ([]*Info, error) {
|
|
||||||
return nil, fmt.Errorf("mount.parseMountTable is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
|
||||||
}
|
|
6
vendor/github.com/docker/docker/pkg/mount/mountinfo_windows.go
generated
vendored
6
vendor/github.com/docker/docker/pkg/mount/mountinfo_windows.go
generated
vendored
@ -1,6 +0,0 @@
|
|||||||
package mount // import "github.com/docker/docker/pkg/mount"
|
|
||||||
|
|
||||||
func parseMountTable(f FilterFunc) ([]*Info, error) {
|
|
||||||
// Do NOT return an error!
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
71
vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go
generated
vendored
71
vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go
generated
vendored
@ -1,71 +0,0 @@
|
|||||||
package mount // import "github.com/docker/docker/pkg/mount"
|
|
||||||
|
|
||||||
// MakeShared ensures a mounted filesystem has the SHARED mount option enabled.
|
|
||||||
// See the supported options in flags.go for further reference.
|
|
||||||
func MakeShared(mountPoint string) error {
|
|
||||||
return ensureMountedAs(mountPoint, SHARED)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeRShared ensures a mounted filesystem has the RSHARED mount option enabled.
|
|
||||||
// See the supported options in flags.go for further reference.
|
|
||||||
func MakeRShared(mountPoint string) error {
|
|
||||||
return ensureMountedAs(mountPoint, RSHARED)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakePrivate ensures a mounted filesystem has the PRIVATE mount option enabled.
|
|
||||||
// See the supported options in flags.go for further reference.
|
|
||||||
func MakePrivate(mountPoint string) error {
|
|
||||||
return ensureMountedAs(mountPoint, PRIVATE)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeRPrivate ensures a mounted filesystem has the RPRIVATE mount option
|
|
||||||
// enabled. See the supported options in flags.go for further reference.
|
|
||||||
func MakeRPrivate(mountPoint string) error {
|
|
||||||
return ensureMountedAs(mountPoint, RPRIVATE)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeSlave ensures a mounted filesystem has the SLAVE mount option enabled.
|
|
||||||
// See the supported options in flags.go for further reference.
|
|
||||||
func MakeSlave(mountPoint string) error {
|
|
||||||
return ensureMountedAs(mountPoint, SLAVE)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeRSlave ensures a mounted filesystem has the RSLAVE mount option enabled.
|
|
||||||
// See the supported options in flags.go for further reference.
|
|
||||||
func MakeRSlave(mountPoint string) error {
|
|
||||||
return ensureMountedAs(mountPoint, RSLAVE)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeUnbindable ensures a mounted filesystem has the UNBINDABLE mount option
|
|
||||||
// enabled. See the supported options in flags.go for further reference.
|
|
||||||
func MakeUnbindable(mountPoint string) error {
|
|
||||||
return ensureMountedAs(mountPoint, UNBINDABLE)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeRUnbindable ensures a mounted filesystem has the RUNBINDABLE mount
|
|
||||||
// option enabled. See the supported options in flags.go for further reference.
|
|
||||||
func MakeRUnbindable(mountPoint string) error {
|
|
||||||
return ensureMountedAs(mountPoint, RUNBINDABLE)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeMount ensures that the file or directory given is a mount point,
|
|
||||||
// bind mounting it to itself it case it is not.
|
|
||||||
func MakeMount(mnt string) error {
|
|
||||||
mounted, err := Mounted(mnt)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if mounted {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return mount(mnt, mnt, "none", uintptr(BIND), "")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ensureMountedAs(mnt string, flags int) error {
|
|
||||||
if err := MakeMount(mnt); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return mount("", mnt, "none", uintptr(flags), "")
|
|
||||||
}
|
|
22
vendor/github.com/docker/docker/pkg/mount/unmount_unix.go
generated
vendored
22
vendor/github.com/docker/docker/pkg/mount/unmount_unix.go
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
// +build !windows
|
|
||||||
|
|
||||||
package mount // import "github.com/docker/docker/pkg/mount"
|
|
||||||
|
|
||||||
import "golang.org/x/sys/unix"
|
|
||||||
|
|
||||||
func unmount(target string, flags int) error {
|
|
||||||
err := unix.Unmount(target, flags)
|
|
||||||
if err == nil || err == unix.EINVAL {
|
|
||||||
// Ignore "not mounted" error here. Note the same error
|
|
||||||
// can be returned if flags are invalid, so this code
|
|
||||||
// assumes that the flags value is always correct.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &mountError{
|
|
||||||
op: "umount",
|
|
||||||
target: target,
|
|
||||||
flags: uintptr(flags),
|
|
||||||
err: err,
|
|
||||||
}
|
|
||||||
}
|
|
7
vendor/github.com/docker/docker/pkg/mount/unmount_unsupported.go
generated
vendored
7
vendor/github.com/docker/docker/pkg/mount/unmount_unsupported.go
generated
vendored
@ -1,7 +0,0 @@
|
|||||||
// +build windows
|
|
||||||
|
|
||||||
package mount // import "github.com/docker/docker/pkg/mount"
|
|
||||||
|
|
||||||
func unmount(target string, flag int) error {
|
|
||||||
panic("Not implemented")
|
|
||||||
}
|
|
16
vendor/github.com/docker/docker/pkg/system/args_windows.go
generated
vendored
16
vendor/github.com/docker/docker/pkg/system/args_windows.go
generated
vendored
@ -1,16 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
// EscapeArgs makes a Windows-style escaped command line from a set of arguments
|
|
||||||
func EscapeArgs(args []string) string {
|
|
||||||
escapedArgs := make([]string, len(args))
|
|
||||||
for i, a := range args {
|
|
||||||
escapedArgs[i] = windows.EscapeArg(a)
|
|
||||||
}
|
|
||||||
return strings.Join(escapedArgs, " ")
|
|
||||||
}
|
|
31
vendor/github.com/docker/docker/pkg/system/chtimes.go
generated
vendored
31
vendor/github.com/docker/docker/pkg/system/chtimes.go
generated
vendored
@ -1,31 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Chtimes changes the access time and modified time of a file at the given path
|
|
||||||
func Chtimes(name string, atime time.Time, mtime time.Time) error {
|
|
||||||
unixMinTime := time.Unix(0, 0)
|
|
||||||
unixMaxTime := maxTime
|
|
||||||
|
|
||||||
// If the modified time is prior to the Unix Epoch, or after the
|
|
||||||
// end of Unix Time, os.Chtimes has undefined behavior
|
|
||||||
// default to Unix Epoch in this case, just in case
|
|
||||||
|
|
||||||
if atime.Before(unixMinTime) || atime.After(unixMaxTime) {
|
|
||||||
atime = unixMinTime
|
|
||||||
}
|
|
||||||
|
|
||||||
if mtime.Before(unixMinTime) || mtime.After(unixMaxTime) {
|
|
||||||
mtime = unixMinTime
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.Chtimes(name, atime, mtime); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Take platform specific action for setting create time.
|
|
||||||
return setCTime(name, mtime)
|
|
||||||
}
|
|
14
vendor/github.com/docker/docker/pkg/system/chtimes_unix.go
generated
vendored
14
vendor/github.com/docker/docker/pkg/system/chtimes_unix.go
generated
vendored
@ -1,14 +0,0 @@
|
|||||||
// +build !windows
|
|
||||||
|
|
||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// setCTime will set the create time on a file. On Unix, the create
|
|
||||||
// time is updated as a side effect of setting the modified time, so
|
|
||||||
// no action is required.
|
|
||||||
func setCTime(path string, ctime time.Time) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
26
vendor/github.com/docker/docker/pkg/system/chtimes_windows.go
generated
vendored
26
vendor/github.com/docker/docker/pkg/system/chtimes_windows.go
generated
vendored
@ -1,26 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
// setCTime will set the create time on a file. On Windows, this requires
|
|
||||||
// calling SetFileTime and explicitly including the create time.
|
|
||||||
func setCTime(path string, ctime time.Time) error {
|
|
||||||
ctimespec := windows.NsecToTimespec(ctime.UnixNano())
|
|
||||||
pathp, e := windows.UTF16PtrFromString(path)
|
|
||||||
if e != nil {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
h, e := windows.CreateFile(pathp,
|
|
||||||
windows.FILE_WRITE_ATTRIBUTES, windows.FILE_SHARE_WRITE, nil,
|
|
||||||
windows.OPEN_EXISTING, windows.FILE_FLAG_BACKUP_SEMANTICS, 0)
|
|
||||||
if e != nil {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
defer windows.Close(h)
|
|
||||||
c := windows.NsecToFiletime(windows.TimespecToNsec(ctimespec))
|
|
||||||
return windows.SetFileTime(h, &c, nil, nil)
|
|
||||||
}
|
|
13
vendor/github.com/docker/docker/pkg/system/errors.go
generated
vendored
13
vendor/github.com/docker/docker/pkg/system/errors.go
generated
vendored
@ -1,13 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrNotSupportedPlatform means the platform is not supported.
|
|
||||||
ErrNotSupportedPlatform = errors.New("platform and architecture is not supported")
|
|
||||||
|
|
||||||
// ErrNotSupportedOperatingSystem means the operating system is not supported.
|
|
||||||
ErrNotSupportedOperatingSystem = errors.New("operating system is not supported")
|
|
||||||
)
|
|
19
vendor/github.com/docker/docker/pkg/system/exitcode.go
generated
vendored
19
vendor/github.com/docker/docker/pkg/system/exitcode.go
generated
vendored
@ -1,19 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os/exec"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetExitCode returns the ExitStatus of the specified error if its type is
|
|
||||||
// exec.ExitError, returns 0 and an error otherwise.
|
|
||||||
func GetExitCode(err error) (int, error) {
|
|
||||||
exitCode := 0
|
|
||||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
|
||||||
if procExit, ok := exiterr.Sys().(syscall.WaitStatus); ok {
|
|
||||||
return procExit.ExitStatus(), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return exitCode, fmt.Errorf("failed to get exit code")
|
|
||||||
}
|
|
67
vendor/github.com/docker/docker/pkg/system/filesys_unix.go
generated
vendored
67
vendor/github.com/docker/docker/pkg/system/filesys_unix.go
generated
vendored
@ -1,67 +0,0 @@
|
|||||||
// +build !windows
|
|
||||||
|
|
||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MkdirAllWithACL is a wrapper for os.MkdirAll on unix systems.
|
|
||||||
func MkdirAllWithACL(path string, perm os.FileMode, sddl string) error {
|
|
||||||
return os.MkdirAll(path, perm)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MkdirAll creates a directory named path along with any necessary parents,
|
|
||||||
// with permission specified by attribute perm for all dir created.
|
|
||||||
func MkdirAll(path string, perm os.FileMode) error {
|
|
||||||
return os.MkdirAll(path, perm)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsAbs is a platform-specific wrapper for filepath.IsAbs.
|
|
||||||
func IsAbs(path string) bool {
|
|
||||||
return filepath.IsAbs(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// The functions below here are wrappers for the equivalents in the os and ioutils packages.
|
|
||||||
// They are passthrough on Unix platforms, and only relevant on Windows.
|
|
||||||
|
|
||||||
// CreateSequential creates the named file with mode 0666 (before umask), truncating
|
|
||||||
// it if it already exists. If successful, methods on the returned
|
|
||||||
// File can be used for I/O; the associated file descriptor has mode
|
|
||||||
// O_RDWR.
|
|
||||||
// If there is an error, it will be of type *PathError.
|
|
||||||
func CreateSequential(name string) (*os.File, error) {
|
|
||||||
return os.Create(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenSequential opens the named file for reading. If successful, methods on
|
|
||||||
// the returned file can be used for reading; the associated file
|
|
||||||
// descriptor has mode O_RDONLY.
|
|
||||||
// If there is an error, it will be of type *PathError.
|
|
||||||
func OpenSequential(name string) (*os.File, error) {
|
|
||||||
return os.Open(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenFileSequential is the generalized open call; most users will use Open
|
|
||||||
// or Create instead. It opens the named file with specified flag
|
|
||||||
// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
|
|
||||||
// methods on the returned File can be used for I/O.
|
|
||||||
// If there is an error, it will be of type *PathError.
|
|
||||||
func OpenFileSequential(name string, flag int, perm os.FileMode) (*os.File, error) {
|
|
||||||
return os.OpenFile(name, flag, perm)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TempFileSequential creates a new temporary file in the directory dir
|
|
||||||
// with a name beginning with prefix, opens the file for reading
|
|
||||||
// and writing, and returns the resulting *os.File.
|
|
||||||
// If dir is the empty string, TempFile uses the default directory
|
|
||||||
// for temporary files (see os.TempDir).
|
|
||||||
// Multiple programs calling TempFile simultaneously
|
|
||||||
// will not choose the same file. The caller can use f.Name()
|
|
||||||
// to find the pathname of the file. It is the caller's responsibility
|
|
||||||
// to remove the file when no longer needed.
|
|
||||||
func TempFileSequential(dir, prefix string) (f *os.File, err error) {
|
|
||||||
return ioutil.TempFile(dir, prefix)
|
|
||||||
}
|
|
294
vendor/github.com/docker/docker/pkg/system/filesys_windows.go
generated
vendored
294
vendor/github.com/docker/docker/pkg/system/filesys_windows.go
generated
vendored
@ -1,294 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// SddlAdministratorsLocalSystem is local administrators plus NT AUTHORITY\System
|
|
||||||
SddlAdministratorsLocalSystem = "D:P(A;OICI;GA;;;BA)(A;OICI;GA;;;SY)"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MkdirAllWithACL is a wrapper for MkdirAll that creates a directory
|
|
||||||
// with an appropriate SDDL defined ACL.
|
|
||||||
func MkdirAllWithACL(path string, perm os.FileMode, sddl string) error {
|
|
||||||
return mkdirall(path, true, sddl)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MkdirAll implementation that is volume path aware for Windows. It can be used
|
|
||||||
// as a drop-in replacement for os.MkdirAll()
|
|
||||||
func MkdirAll(path string, _ os.FileMode) error {
|
|
||||||
return mkdirall(path, false, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// mkdirall is a custom version of os.MkdirAll modified for use on Windows
|
|
||||||
// so that it is both volume path aware, and can create a directory with
|
|
||||||
// a DACL.
|
|
||||||
func mkdirall(path string, applyACL bool, sddl string) error {
|
|
||||||
if re := regexp.MustCompile(`^\\\\\?\\Volume{[a-z0-9-]+}$`); re.MatchString(path) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// The rest of this method is largely copied from os.MkdirAll and should be kept
|
|
||||||
// as-is to ensure compatibility.
|
|
||||||
|
|
||||||
// Fast path: if we can tell whether path is a directory or file, stop with success or error.
|
|
||||||
dir, err := os.Stat(path)
|
|
||||||
if err == nil {
|
|
||||||
if dir.IsDir() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &os.PathError{
|
|
||||||
Op: "mkdir",
|
|
||||||
Path: path,
|
|
||||||
Err: syscall.ENOTDIR,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slow path: make sure parent exists and then call Mkdir for path.
|
|
||||||
i := len(path)
|
|
||||||
for i > 0 && os.IsPathSeparator(path[i-1]) { // Skip trailing path separator.
|
|
||||||
i--
|
|
||||||
}
|
|
||||||
|
|
||||||
j := i
|
|
||||||
for j > 0 && !os.IsPathSeparator(path[j-1]) { // Scan backward over element.
|
|
||||||
j--
|
|
||||||
}
|
|
||||||
|
|
||||||
if j > 1 {
|
|
||||||
// Create parent
|
|
||||||
err = mkdirall(path[0:j-1], false, sddl)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parent now exists; invoke os.Mkdir or mkdirWithACL and use its result.
|
|
||||||
if applyACL {
|
|
||||||
err = mkdirWithACL(path, sddl)
|
|
||||||
} else {
|
|
||||||
err = os.Mkdir(path, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
// Handle arguments like "foo/." by
|
|
||||||
// double-checking that directory doesn't exist.
|
|
||||||
dir, err1 := os.Lstat(path)
|
|
||||||
if err1 == nil && dir.IsDir() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// mkdirWithACL creates a new directory. If there is an error, it will be of
|
|
||||||
// type *PathError. .
|
|
||||||
//
|
|
||||||
// This is a modified and combined version of os.Mkdir and windows.Mkdir
|
|
||||||
// in golang to cater for creating a directory am ACL permitting full
|
|
||||||
// access, with inheritance, to any subfolder/file for Built-in Administrators
|
|
||||||
// and Local System.
|
|
||||||
func mkdirWithACL(name string, sddl string) error {
|
|
||||||
sa := windows.SecurityAttributes{Length: 0}
|
|
||||||
sd, err := windows.SecurityDescriptorFromString(sddl)
|
|
||||||
if err != nil {
|
|
||||||
return &os.PathError{Op: "mkdir", Path: name, Err: err}
|
|
||||||
}
|
|
||||||
sa.Length = uint32(unsafe.Sizeof(sa))
|
|
||||||
sa.InheritHandle = 1
|
|
||||||
sa.SecurityDescriptor = sd
|
|
||||||
|
|
||||||
namep, err := windows.UTF16PtrFromString(name)
|
|
||||||
if err != nil {
|
|
||||||
return &os.PathError{Op: "mkdir", Path: name, Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
e := windows.CreateDirectory(namep, &sa)
|
|
||||||
if e != nil {
|
|
||||||
return &os.PathError{Op: "mkdir", Path: name, Err: e}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsAbs is a platform-specific wrapper for filepath.IsAbs. On Windows,
|
|
||||||
// golang filepath.IsAbs does not consider a path \windows\system32 as absolute
|
|
||||||
// as it doesn't start with a drive-letter/colon combination. However, in
|
|
||||||
// docker we need to verify things such as WORKDIR /windows/system32 in
|
|
||||||
// a Dockerfile (which gets translated to \windows\system32 when being processed
|
|
||||||
// by the daemon. This SHOULD be treated as absolute from a docker processing
|
|
||||||
// perspective.
|
|
||||||
func IsAbs(path string) bool {
|
|
||||||
if !filepath.IsAbs(path) {
|
|
||||||
if !strings.HasPrefix(path, string(os.PathSeparator)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// The origin of the functions below here are the golang OS and windows packages,
|
|
||||||
// slightly modified to only cope with files, not directories due to the
|
|
||||||
// specific use case.
|
|
||||||
//
|
|
||||||
// The alteration is to allow a file on Windows to be opened with
|
|
||||||
// FILE_FLAG_SEQUENTIAL_SCAN (particular for docker load), to avoid eating
|
|
||||||
// the standby list, particularly when accessing large files such as layer.tar.
|
|
||||||
|
|
||||||
// CreateSequential creates the named file with mode 0666 (before umask), truncating
|
|
||||||
// it if it already exists. If successful, methods on the returned
|
|
||||||
// File can be used for I/O; the associated file descriptor has mode
|
|
||||||
// O_RDWR.
|
|
||||||
// If there is an error, it will be of type *PathError.
|
|
||||||
func CreateSequential(name string) (*os.File, error) {
|
|
||||||
return OpenFileSequential(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenSequential opens the named file for reading. If successful, methods on
|
|
||||||
// the returned file can be used for reading; the associated file
|
|
||||||
// descriptor has mode O_RDONLY.
|
|
||||||
// If there is an error, it will be of type *PathError.
|
|
||||||
func OpenSequential(name string) (*os.File, error) {
|
|
||||||
return OpenFileSequential(name, os.O_RDONLY, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenFileSequential is the generalized open call; most users will use Open
|
|
||||||
// or Create instead.
|
|
||||||
// If there is an error, it will be of type *PathError.
|
|
||||||
func OpenFileSequential(name string, flag int, _ os.FileMode) (*os.File, error) {
|
|
||||||
if name == "" {
|
|
||||||
return nil, &os.PathError{Op: "open", Path: name, Err: syscall.ENOENT}
|
|
||||||
}
|
|
||||||
r, errf := windowsOpenFileSequential(name, flag, 0)
|
|
||||||
if errf == nil {
|
|
||||||
return r, nil
|
|
||||||
}
|
|
||||||
return nil, &os.PathError{Op: "open", Path: name, Err: errf}
|
|
||||||
}
|
|
||||||
|
|
||||||
func windowsOpenFileSequential(name string, flag int, _ os.FileMode) (file *os.File, err error) {
|
|
||||||
r, e := windowsOpenSequential(name, flag|windows.O_CLOEXEC, 0)
|
|
||||||
if e != nil {
|
|
||||||
return nil, e
|
|
||||||
}
|
|
||||||
return os.NewFile(uintptr(r), name), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeInheritSa() *windows.SecurityAttributes {
|
|
||||||
var sa windows.SecurityAttributes
|
|
||||||
sa.Length = uint32(unsafe.Sizeof(sa))
|
|
||||||
sa.InheritHandle = 1
|
|
||||||
return &sa
|
|
||||||
}
|
|
||||||
|
|
||||||
func windowsOpenSequential(path string, mode int, _ uint32) (fd windows.Handle, err error) {
|
|
||||||
if len(path) == 0 {
|
|
||||||
return windows.InvalidHandle, windows.ERROR_FILE_NOT_FOUND
|
|
||||||
}
|
|
||||||
pathp, err := windows.UTF16PtrFromString(path)
|
|
||||||
if err != nil {
|
|
||||||
return windows.InvalidHandle, err
|
|
||||||
}
|
|
||||||
var access uint32
|
|
||||||
switch mode & (windows.O_RDONLY | windows.O_WRONLY | windows.O_RDWR) {
|
|
||||||
case windows.O_RDONLY:
|
|
||||||
access = windows.GENERIC_READ
|
|
||||||
case windows.O_WRONLY:
|
|
||||||
access = windows.GENERIC_WRITE
|
|
||||||
case windows.O_RDWR:
|
|
||||||
access = windows.GENERIC_READ | windows.GENERIC_WRITE
|
|
||||||
}
|
|
||||||
if mode&windows.O_CREAT != 0 {
|
|
||||||
access |= windows.GENERIC_WRITE
|
|
||||||
}
|
|
||||||
if mode&windows.O_APPEND != 0 {
|
|
||||||
access &^= windows.GENERIC_WRITE
|
|
||||||
access |= windows.FILE_APPEND_DATA
|
|
||||||
}
|
|
||||||
sharemode := uint32(windows.FILE_SHARE_READ | windows.FILE_SHARE_WRITE)
|
|
||||||
var sa *windows.SecurityAttributes
|
|
||||||
if mode&windows.O_CLOEXEC == 0 {
|
|
||||||
sa = makeInheritSa()
|
|
||||||
}
|
|
||||||
var createmode uint32
|
|
||||||
switch {
|
|
||||||
case mode&(windows.O_CREAT|windows.O_EXCL) == (windows.O_CREAT | windows.O_EXCL):
|
|
||||||
createmode = windows.CREATE_NEW
|
|
||||||
case mode&(windows.O_CREAT|windows.O_TRUNC) == (windows.O_CREAT | windows.O_TRUNC):
|
|
||||||
createmode = windows.CREATE_ALWAYS
|
|
||||||
case mode&windows.O_CREAT == windows.O_CREAT:
|
|
||||||
createmode = windows.OPEN_ALWAYS
|
|
||||||
case mode&windows.O_TRUNC == windows.O_TRUNC:
|
|
||||||
createmode = windows.TRUNCATE_EXISTING
|
|
||||||
default:
|
|
||||||
createmode = windows.OPEN_EXISTING
|
|
||||||
}
|
|
||||||
// Use FILE_FLAG_SEQUENTIAL_SCAN rather than FILE_ATTRIBUTE_NORMAL as implemented in golang.
|
|
||||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
|
|
||||||
const fileFlagSequentialScan = 0x08000000 // FILE_FLAG_SEQUENTIAL_SCAN
|
|
||||||
h, e := windows.CreateFile(pathp, access, sharemode, sa, createmode, fileFlagSequentialScan, 0)
|
|
||||||
return h, e
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helpers for TempFileSequential
|
|
||||||
var rand uint32
|
|
||||||
var randmu sync.Mutex
|
|
||||||
|
|
||||||
func reseed() uint32 {
|
|
||||||
return uint32(time.Now().UnixNano() + int64(os.Getpid()))
|
|
||||||
}
|
|
||||||
func nextSuffix() string {
|
|
||||||
randmu.Lock()
|
|
||||||
r := rand
|
|
||||||
if r == 0 {
|
|
||||||
r = reseed()
|
|
||||||
}
|
|
||||||
r = r*1664525 + 1013904223 // constants from Numerical Recipes
|
|
||||||
rand = r
|
|
||||||
randmu.Unlock()
|
|
||||||
return strconv.Itoa(int(1e9 + r%1e9))[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// TempFileSequential is a copy of ioutil.TempFile, modified to use sequential
|
|
||||||
// file access. Below is the original comment from golang:
|
|
||||||
// TempFile creates a new temporary file in the directory dir
|
|
||||||
// with a name beginning with prefix, opens the file for reading
|
|
||||||
// and writing, and returns the resulting *os.File.
|
|
||||||
// If dir is the empty string, TempFile uses the default directory
|
|
||||||
// for temporary files (see os.TempDir).
|
|
||||||
// Multiple programs calling TempFile simultaneously
|
|
||||||
// will not choose the same file. The caller can use f.Name()
|
|
||||||
// to find the pathname of the file. It is the caller's responsibility
|
|
||||||
// to remove the file when no longer needed.
|
|
||||||
func TempFileSequential(dir, prefix string) (f *os.File, err error) {
|
|
||||||
if dir == "" {
|
|
||||||
dir = os.TempDir()
|
|
||||||
}
|
|
||||||
|
|
||||||
nconflict := 0
|
|
||||||
for i := 0; i < 10000; i++ {
|
|
||||||
name := filepath.Join(dir, prefix+nextSuffix())
|
|
||||||
f, err = OpenFileSequential(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
|
|
||||||
if os.IsExist(err) {
|
|
||||||
if nconflict++; nconflict > 10 {
|
|
||||||
randmu.Lock()
|
|
||||||
rand = reseed()
|
|
||||||
randmu.Unlock()
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
22
vendor/github.com/docker/docker/pkg/system/init.go
generated
vendored
22
vendor/github.com/docker/docker/pkg/system/init.go
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Used by chtimes
|
|
||||||
var maxTime time.Time
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// chtimes initialization
|
|
||||||
if unsafe.Sizeof(syscall.Timespec{}.Nsec) == 8 {
|
|
||||||
// This is a 64 bit timespec
|
|
||||||
// os.Chtimes limits time to the following
|
|
||||||
maxTime = time.Unix(0, 1<<63-1)
|
|
||||||
} else {
|
|
||||||
// This is a 32 bit timespec
|
|
||||||
maxTime = time.Unix(1<<31-1, 0)
|
|
||||||
}
|
|
||||||
}
|
|
12
vendor/github.com/docker/docker/pkg/system/init_unix.go
generated
vendored
12
vendor/github.com/docker/docker/pkg/system/init_unix.go
generated
vendored
@ -1,12 +0,0 @@
|
|||||||
// +build !windows
|
|
||||||
|
|
||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
// InitLCOW does nothing since LCOW is a windows only feature
|
|
||||||
func InitLCOW(experimental bool) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerdRuntimeSupported returns true if the use of ContainerD runtime is supported.
|
|
||||||
func ContainerdRuntimeSupported(_ bool, _ string) bool {
|
|
||||||
return true
|
|
||||||
}
|
|
40
vendor/github.com/docker/docker/pkg/system/init_windows.go
generated
vendored
40
vendor/github.com/docker/docker/pkg/system/init_windows.go
generated
vendored
@ -1,40 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/osversion"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// lcowSupported determines if Linux Containers on Windows are supported.
|
|
||||||
lcowSupported = false
|
|
||||||
|
|
||||||
// containerdRuntimeSupported determines if ContainerD should be the runtime.
|
|
||||||
// As of March 2019, this is an experimental feature.
|
|
||||||
containerdRuntimeSupported = false
|
|
||||||
)
|
|
||||||
|
|
||||||
// InitLCOW sets whether LCOW is supported or not. Requires RS5+
|
|
||||||
func InitLCOW(experimental bool) {
|
|
||||||
if experimental && osversion.Build() >= osversion.RS5 {
|
|
||||||
lcowSupported = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// InitContainerdRuntime sets whether to use ContainerD for runtime
|
|
||||||
// on Windows. This is an experimental feature still in development, and
|
|
||||||
// also requires an environment variable to be set (so as not to turn the
|
|
||||||
// feature on from simply experimental which would also mean LCOW.
|
|
||||||
func InitContainerdRuntime(experimental bool, cdPath string) {
|
|
||||||
if experimental && len(cdPath) > 0 && len(os.Getenv("DOCKER_WINDOWS_CONTAINERD_RUNTIME")) > 0 {
|
|
||||||
logrus.Warnf("Using ContainerD runtime. This feature is experimental")
|
|
||||||
containerdRuntimeSupported = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerdRuntimeSupported returns true if the use of ContainerD runtime is supported.
|
|
||||||
func ContainerdRuntimeSupported() bool {
|
|
||||||
return containerdRuntimeSupported
|
|
||||||
}
|
|
32
vendor/github.com/docker/docker/pkg/system/lcow.go
generated
vendored
32
vendor/github.com/docker/docker/pkg/system/lcow.go
generated
vendored
@ -1,32 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsOSSupported determines if an operating system is supported by the host
|
|
||||||
func IsOSSupported(os string) bool {
|
|
||||||
if strings.EqualFold(runtime.GOOS, os) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if LCOWSupported() && strings.EqualFold(os, "linux") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidatePlatform determines if a platform structure is valid.
|
|
||||||
// TODO This is a temporary windows-only function, should be replaced by
|
|
||||||
// comparison of worker capabilities
|
|
||||||
func ValidatePlatform(platform specs.Platform) error {
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
if !(platform.OS == runtime.GOOS || (LCOWSupported() && platform.OS == "linux")) {
|
|
||||||
return errors.Errorf("unsupported os %s", platform.OS)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
8
vendor/github.com/docker/docker/pkg/system/lcow_unix.go
generated
vendored
8
vendor/github.com/docker/docker/pkg/system/lcow_unix.go
generated
vendored
@ -1,8 +0,0 @@
|
|||||||
// +build !windows
|
|
||||||
|
|
||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
// LCOWSupported returns true if Linux containers on Windows are supported.
|
|
||||||
func LCOWSupported() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
6
vendor/github.com/docker/docker/pkg/system/lcow_windows.go
generated
vendored
6
vendor/github.com/docker/docker/pkg/system/lcow_windows.go
generated
vendored
@ -1,6 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
// LCOWSupported returns true if Linux containers on Windows are supported.
|
|
||||||
func LCOWSupported() bool {
|
|
||||||
return lcowSupported
|
|
||||||
}
|
|
20
vendor/github.com/docker/docker/pkg/system/lstat_unix.go
generated
vendored
20
vendor/github.com/docker/docker/pkg/system/lstat_unix.go
generated
vendored
@ -1,20 +0,0 @@
|
|||||||
// +build !windows
|
|
||||||
|
|
||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Lstat takes a path to a file and returns
|
|
||||||
// a system.StatT type pertaining to that file.
|
|
||||||
//
|
|
||||||
// Throws an error if the file does not exist
|
|
||||||
func Lstat(path string) (*StatT, error) {
|
|
||||||
s := &syscall.Stat_t{}
|
|
||||||
if err := syscall.Lstat(path, s); err != nil {
|
|
||||||
return nil, &os.PathError{Op: "Lstat", Path: path, Err: err}
|
|
||||||
}
|
|
||||||
return fromStatT(s)
|
|
||||||
}
|
|
14
vendor/github.com/docker/docker/pkg/system/lstat_windows.go
generated
vendored
14
vendor/github.com/docker/docker/pkg/system/lstat_windows.go
generated
vendored
@ -1,14 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import "os"
|
|
||||||
|
|
||||||
// Lstat calls os.Lstat to get a fileinfo interface back.
|
|
||||||
// This is then copied into our own locally defined structure.
|
|
||||||
func Lstat(path string) (*StatT, error) {
|
|
||||||
fi, err := os.Lstat(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return fromStatT(&fi)
|
|
||||||
}
|
|
17
vendor/github.com/docker/docker/pkg/system/meminfo.go
generated
vendored
17
vendor/github.com/docker/docker/pkg/system/meminfo.go
generated
vendored
@ -1,17 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
// MemInfo contains memory statistics of the host system.
|
|
||||||
type MemInfo struct {
|
|
||||||
// Total usable RAM (i.e. physical RAM minus a few reserved bits and the
|
|
||||||
// kernel binary code).
|
|
||||||
MemTotal int64
|
|
||||||
|
|
||||||
// Amount of free memory.
|
|
||||||
MemFree int64
|
|
||||||
|
|
||||||
// Total amount of swap space available.
|
|
||||||
SwapTotal int64
|
|
||||||
|
|
||||||
// Amount of swap space that is currently unused.
|
|
||||||
SwapFree int64
|
|
||||||
}
|
|
71
vendor/github.com/docker/docker/pkg/system/meminfo_linux.go
generated
vendored
71
vendor/github.com/docker/docker/pkg/system/meminfo_linux.go
generated
vendored
@ -1,71 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
units "github.com/docker/go-units"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ReadMemInfo retrieves memory statistics of the host system and returns a
|
|
||||||
// MemInfo type.
|
|
||||||
func ReadMemInfo() (*MemInfo, error) {
|
|
||||||
file, err := os.Open("/proc/meminfo")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
return parseMemInfo(file)
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseMemInfo parses the /proc/meminfo file into
|
|
||||||
// a MemInfo object given an io.Reader to the file.
|
|
||||||
// Throws error if there are problems reading from the file
|
|
||||||
func parseMemInfo(reader io.Reader) (*MemInfo, error) {
|
|
||||||
meminfo := &MemInfo{}
|
|
||||||
scanner := bufio.NewScanner(reader)
|
|
||||||
memAvailable := int64(-1)
|
|
||||||
for scanner.Scan() {
|
|
||||||
// Expected format: ["MemTotal:", "1234", "kB"]
|
|
||||||
parts := strings.Fields(scanner.Text())
|
|
||||||
|
|
||||||
// Sanity checks: Skip malformed entries.
|
|
||||||
if len(parts) < 3 || parts[2] != "kB" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to bytes.
|
|
||||||
size, err := strconv.Atoi(parts[1])
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
bytes := int64(size) * units.KiB
|
|
||||||
|
|
||||||
switch parts[0] {
|
|
||||||
case "MemTotal:":
|
|
||||||
meminfo.MemTotal = bytes
|
|
||||||
case "MemFree:":
|
|
||||||
meminfo.MemFree = bytes
|
|
||||||
case "MemAvailable:":
|
|
||||||
memAvailable = bytes
|
|
||||||
case "SwapTotal:":
|
|
||||||
meminfo.SwapTotal = bytes
|
|
||||||
case "SwapFree:":
|
|
||||||
meminfo.SwapFree = bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if memAvailable != -1 {
|
|
||||||
meminfo.MemFree = memAvailable
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle errors that may have occurred during the reading of the file.
|
|
||||||
if err := scanner.Err(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return meminfo, nil
|
|
||||||
}
|
|
8
vendor/github.com/docker/docker/pkg/system/meminfo_unsupported.go
generated
vendored
8
vendor/github.com/docker/docker/pkg/system/meminfo_unsupported.go
generated
vendored
@ -1,8 +0,0 @@
|
|||||||
// +build !linux,!windows
|
|
||||||
|
|
||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
// ReadMemInfo is not supported on platforms other than linux and windows.
|
|
||||||
func ReadMemInfo() (*MemInfo, error) {
|
|
||||||
return nil, ErrNotSupportedPlatform
|
|
||||||
}
|
|
45
vendor/github.com/docker/docker/pkg/system/meminfo_windows.go
generated
vendored
45
vendor/github.com/docker/docker/pkg/system/meminfo_windows.go
generated
vendored
@ -1,45 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
|
||||||
|
|
||||||
procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx")
|
|
||||||
)
|
|
||||||
|
|
||||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa366589(v=vs.85).aspx
|
|
||||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa366770(v=vs.85).aspx
|
|
||||||
type memorystatusex struct {
|
|
||||||
dwLength uint32
|
|
||||||
dwMemoryLoad uint32
|
|
||||||
ullTotalPhys uint64
|
|
||||||
ullAvailPhys uint64
|
|
||||||
ullTotalPageFile uint64
|
|
||||||
ullAvailPageFile uint64
|
|
||||||
ullTotalVirtual uint64
|
|
||||||
ullAvailVirtual uint64
|
|
||||||
ullAvailExtendedVirtual uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadMemInfo retrieves memory statistics of the host system and returns a
|
|
||||||
// MemInfo type.
|
|
||||||
func ReadMemInfo() (*MemInfo, error) {
|
|
||||||
msi := &memorystatusex{
|
|
||||||
dwLength: 64,
|
|
||||||
}
|
|
||||||
r1, _, _ := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(msi)))
|
|
||||||
if r1 == 0 {
|
|
||||||
return &MemInfo{}, nil
|
|
||||||
}
|
|
||||||
return &MemInfo{
|
|
||||||
MemTotal: int64(msi.ullTotalPhys),
|
|
||||||
MemFree: int64(msi.ullAvailPhys),
|
|
||||||
SwapTotal: int64(msi.ullTotalPageFile),
|
|
||||||
SwapFree: int64(msi.ullAvailPageFile),
|
|
||||||
}, nil
|
|
||||||
}
|
|
22
vendor/github.com/docker/docker/pkg/system/mknod.go
generated
vendored
22
vendor/github.com/docker/docker/pkg/system/mknod.go
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
// +build !windows
|
|
||||||
|
|
||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Mknod creates a filesystem node (file, device special file or named pipe) named path
|
|
||||||
// with attributes specified by mode and dev.
|
|
||||||
func Mknod(path string, mode uint32, dev int) error {
|
|
||||||
return unix.Mknod(path, mode, dev)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mkdev is used to build the value of linux devices (in /dev/) which specifies major
|
|
||||||
// and minor number of the newly created device special file.
|
|
||||||
// Linux device nodes are a bit weird due to backwards compat with 16 bit device nodes.
|
|
||||||
// They are, from low to high: the lower 8 bits of the minor, then 12 bits of the major,
|
|
||||||
// then the top 12 bits of the minor.
|
|
||||||
func Mkdev(major int64, minor int64) uint32 {
|
|
||||||
return uint32(unix.Mkdev(uint32(major), uint32(minor)))
|
|
||||||
}
|
|
11
vendor/github.com/docker/docker/pkg/system/mknod_windows.go
generated
vendored
11
vendor/github.com/docker/docker/pkg/system/mknod_windows.go
generated
vendored
@ -1,11 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
// Mknod is not implemented on Windows.
|
|
||||||
func Mknod(path string, mode uint32, dev int) error {
|
|
||||||
return ErrNotSupportedPlatform
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mkdev is not implemented on Windows.
|
|
||||||
func Mkdev(major int64, minor int64) uint32 {
|
|
||||||
panic("Mkdev not implemented on Windows.")
|
|
||||||
}
|
|
64
vendor/github.com/docker/docker/pkg/system/path.go
generated
vendored
64
vendor/github.com/docker/docker/pkg/system/path.go
generated
vendored
@ -1,64 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const defaultUnixPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
||||||
|
|
||||||
// DefaultPathEnv is unix style list of directories to search for
|
|
||||||
// executables. Each directory is separated from the next by a colon
|
|
||||||
// ':' character .
|
|
||||||
func DefaultPathEnv(os string) string {
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
if os != runtime.GOOS {
|
|
||||||
return defaultUnixPathEnv
|
|
||||||
}
|
|
||||||
// Deliberately empty on Windows containers on Windows as the default path will be set by
|
|
||||||
// the container. Docker has no context of what the default path should be.
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return defaultUnixPathEnv
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
// On Windows: this does the following>
|
|
||||||
// CheckSystemDriveAndRemoveDriveLetter verifies and manipulates a Windows path.
|
|
||||||
// This is used, for example, when validating a user provided path in docker cp.
|
|
||||||
// If a drive letter is supplied, it must be the system drive. The drive letter
|
|
||||||
// is always removed. Also, it translates it to OS semantics (IOW / to \). We
|
|
||||||
// need the path in this syntax so that it can ultimately be concatenated with
|
|
||||||
// a Windows long-path which doesn't support drive-letters. Examples:
|
|
||||||
// C: --> Fail
|
|
||||||
// C:\ --> \
|
|
||||||
// a --> a
|
|
||||||
// /a --> \a
|
|
||||||
// d:\ --> Fail
|
|
||||||
func CheckSystemDriveAndRemoveDriveLetter(path string, driver PathVerifier) (string, error) {
|
|
||||||
if runtime.GOOS != "windows" || LCOWSupported() {
|
|
||||||
return path, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(path) == 2 && string(path[1]) == ":" {
|
|
||||||
return "", fmt.Errorf("No relative path specified in %q", path)
|
|
||||||
}
|
|
||||||
if !driver.IsAbs(path) || len(path) < 2 {
|
|
||||||
return filepath.FromSlash(path), nil
|
|
||||||
}
|
|
||||||
if string(path[1]) == ":" && !strings.EqualFold(string(path[0]), "c") {
|
|
||||||
return "", fmt.Errorf("The specified path is not on the system drive (C:)")
|
|
||||||
}
|
|
||||||
return filepath.FromSlash(path[2:]), nil
|
|
||||||
}
|
|
10
vendor/github.com/docker/docker/pkg/system/path_unix.go
generated
vendored
10
vendor/github.com/docker/docker/pkg/system/path_unix.go
generated
vendored
@ -1,10 +0,0 @@
|
|||||||
// +build !windows
|
|
||||||
|
|
||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
// GetLongPathName converts Windows short pathnames to full pathnames.
|
|
||||||
// For example C:\Users\ADMIN~1 --> C:\Users\Administrator.
|
|
||||||
// It is a no-op on non-Windows platforms
|
|
||||||
func GetLongPathName(path string) (string, error) {
|
|
||||||
return path, nil
|
|
||||||
}
|
|
27
vendor/github.com/docker/docker/pkg/system/path_windows.go
generated
vendored
27
vendor/github.com/docker/docker/pkg/system/path_windows.go
generated
vendored
@ -1,27 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import "golang.org/x/sys/windows"
|
|
||||||
|
|
||||||
// GetLongPathName converts Windows short pathnames to full pathnames.
|
|
||||||
// For example C:\Users\ADMIN~1 --> C:\Users\Administrator.
|
|
||||||
// It is a no-op on non-Windows platforms
|
|
||||||
func GetLongPathName(path string) (string, error) {
|
|
||||||
// See https://groups.google.com/forum/#!topic/golang-dev/1tufzkruoTg
|
|
||||||
p, err := windows.UTF16FromString(path)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
b := p // GetLongPathName says we can reuse buffer
|
|
||||||
n, err := windows.GetLongPathName(&p[0], &b[0], uint32(len(b)))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if n > uint32(len(b)) {
|
|
||||||
b = make([]uint16, n)
|
|
||||||
_, err = windows.GetLongPathName(&p[0], &b[0], uint32(len(b)))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return windows.UTF16ToString(b), nil
|
|
||||||
}
|
|
24
vendor/github.com/docker/docker/pkg/system/process_unix.go
generated
vendored
24
vendor/github.com/docker/docker/pkg/system/process_unix.go
generated
vendored
@ -1,24 +0,0 @@
|
|||||||
// +build linux freebsd darwin
|
|
||||||
|
|
||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsProcessAlive returns true if process with a given pid is running.
|
|
||||||
func IsProcessAlive(pid int) bool {
|
|
||||||
err := unix.Kill(pid, syscall.Signal(0))
|
|
||||||
if err == nil || err == unix.EPERM {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// KillProcess force-stops a process.
|
|
||||||
func KillProcess(pid int) {
|
|
||||||
unix.Kill(pid, unix.SIGKILL)
|
|
||||||
}
|
|
18
vendor/github.com/docker/docker/pkg/system/process_windows.go
generated
vendored
18
vendor/github.com/docker/docker/pkg/system/process_windows.go
generated
vendored
@ -1,18 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import "os"
|
|
||||||
|
|
||||||
// IsProcessAlive returns true if process with a given pid is running.
|
|
||||||
func IsProcessAlive(pid int) bool {
|
|
||||||
_, err := os.FindProcess(pid)
|
|
||||||
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// KillProcess force-stops a process.
|
|
||||||
func KillProcess(pid int) {
|
|
||||||
p, err := os.FindProcess(pid)
|
|
||||||
if err == nil {
|
|
||||||
p.Kill()
|
|
||||||
}
|
|
||||||
}
|
|
80
vendor/github.com/docker/docker/pkg/system/rm.go
generated
vendored
80
vendor/github.com/docker/docker/pkg/system/rm.go
generated
vendored
@ -1,80 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/docker/docker/pkg/mount"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// EnsureRemoveAll wraps `os.RemoveAll` to check for specific errors that can
|
|
||||||
// often be remedied.
|
|
||||||
// Only use `EnsureRemoveAll` if you really want to make every effort to remove
|
|
||||||
// a directory.
|
|
||||||
//
|
|
||||||
// Because of the way `os.Remove` (and by extension `os.RemoveAll`) works, there
|
|
||||||
// can be a race between reading directory entries and then actually attempting
|
|
||||||
// to remove everything in the directory.
|
|
||||||
// These types of errors do not need to be returned since it's ok for the dir to
|
|
||||||
// be gone we can just retry the remove operation.
|
|
||||||
//
|
|
||||||
// This should not return a `os.ErrNotExist` kind of error under any circumstances
|
|
||||||
func EnsureRemoveAll(dir string) error {
|
|
||||||
notExistErr := make(map[string]bool)
|
|
||||||
|
|
||||||
// track retries
|
|
||||||
exitOnErr := make(map[string]int)
|
|
||||||
maxRetry := 50
|
|
||||||
|
|
||||||
// Attempt to unmount anything beneath this dir first
|
|
||||||
mount.RecursiveUnmount(dir)
|
|
||||||
|
|
||||||
for {
|
|
||||||
err := os.RemoveAll(dir)
|
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
pe, ok := err.(*os.PathError)
|
|
||||||
if !ok {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
if notExistErr[pe.Path] {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
notExistErr[pe.Path] = true
|
|
||||||
|
|
||||||
// There is a race where some subdir can be removed but after the parent
|
|
||||||
// dir entries have been read.
|
|
||||||
// So the path could be from `os.Remove(subdir)`
|
|
||||||
// If the reported non-existent path is not the passed in `dir` we
|
|
||||||
// should just retry, but otherwise return with no error.
|
|
||||||
if pe.Path == dir {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if pe.Err != syscall.EBUSY {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if mounted, _ := mount.Mounted(pe.Path); mounted {
|
|
||||||
if e := mount.Unmount(pe.Path); e != nil {
|
|
||||||
if mounted, _ := mount.Mounted(pe.Path); mounted {
|
|
||||||
return errors.Wrapf(e, "error while removing %s", dir)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if exitOnErr[pe.Path] == maxRetry {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
exitOnErr[pe.Path]++
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
}
|
|
||||||
}
|
|
13
vendor/github.com/docker/docker/pkg/system/stat_darwin.go
generated
vendored
13
vendor/github.com/docker/docker/pkg/system/stat_darwin.go
generated
vendored
@ -1,13 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import "syscall"
|
|
||||||
|
|
||||||
// fromStatT converts a syscall.Stat_t type to a system.Stat_t type
|
|
||||||
func fromStatT(s *syscall.Stat_t) (*StatT, error) {
|
|
||||||
return &StatT{size: s.Size,
|
|
||||||
mode: uint32(s.Mode),
|
|
||||||
uid: s.Uid,
|
|
||||||
gid: s.Gid,
|
|
||||||
rdev: uint64(s.Rdev),
|
|
||||||
mtim: s.Mtimespec}, nil
|
|
||||||
}
|
|
13
vendor/github.com/docker/docker/pkg/system/stat_freebsd.go
generated
vendored
13
vendor/github.com/docker/docker/pkg/system/stat_freebsd.go
generated
vendored
@ -1,13 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import "syscall"
|
|
||||||
|
|
||||||
// fromStatT converts a syscall.Stat_t type to a system.Stat_t type
|
|
||||||
func fromStatT(s *syscall.Stat_t) (*StatT, error) {
|
|
||||||
return &StatT{size: s.Size,
|
|
||||||
mode: uint32(s.Mode),
|
|
||||||
uid: s.Uid,
|
|
||||||
gid: s.Gid,
|
|
||||||
rdev: uint64(s.Rdev),
|
|
||||||
mtim: s.Mtimespec}, nil
|
|
||||||
}
|
|
20
vendor/github.com/docker/docker/pkg/system/stat_linux.go
generated
vendored
20
vendor/github.com/docker/docker/pkg/system/stat_linux.go
generated
vendored
@ -1,20 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import "syscall"
|
|
||||||
|
|
||||||
// fromStatT converts a syscall.Stat_t type to a system.Stat_t type
|
|
||||||
func fromStatT(s *syscall.Stat_t) (*StatT, error) {
|
|
||||||
return &StatT{size: s.Size,
|
|
||||||
mode: s.Mode,
|
|
||||||
uid: s.Uid,
|
|
||||||
gid: s.Gid,
|
|
||||||
// the type is 32bit on mips
|
|
||||||
rdev: uint64(s.Rdev), // nolint: unconvert
|
|
||||||
mtim: s.Mtim}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromStatT converts a syscall.Stat_t type to a system.Stat_t type
|
|
||||||
// This is exposed on Linux as pkg/archive/changes uses it.
|
|
||||||
func FromStatT(s *syscall.Stat_t) (*StatT, error) {
|
|
||||||
return fromStatT(s)
|
|
||||||
}
|
|
13
vendor/github.com/docker/docker/pkg/system/stat_openbsd.go
generated
vendored
13
vendor/github.com/docker/docker/pkg/system/stat_openbsd.go
generated
vendored
@ -1,13 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import "syscall"
|
|
||||||
|
|
||||||
// fromStatT converts a syscall.Stat_t type to a system.Stat_t type
|
|
||||||
func fromStatT(s *syscall.Stat_t) (*StatT, error) {
|
|
||||||
return &StatT{size: s.Size,
|
|
||||||
mode: uint32(s.Mode),
|
|
||||||
uid: s.Uid,
|
|
||||||
gid: s.Gid,
|
|
||||||
rdev: uint64(s.Rdev),
|
|
||||||
mtim: s.Mtim}, nil
|
|
||||||
}
|
|
66
vendor/github.com/docker/docker/pkg/system/stat_unix.go
generated
vendored
66
vendor/github.com/docker/docker/pkg/system/stat_unix.go
generated
vendored
@ -1,66 +0,0 @@
|
|||||||
// +build !windows
|
|
||||||
|
|
||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
// StatT type contains status of a file. It contains metadata
|
|
||||||
// like permission, owner, group, size, etc about a file.
|
|
||||||
type StatT struct {
|
|
||||||
mode uint32
|
|
||||||
uid uint32
|
|
||||||
gid uint32
|
|
||||||
rdev uint64
|
|
||||||
size int64
|
|
||||||
mtim syscall.Timespec
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mode returns file's permission mode.
|
|
||||||
func (s StatT) Mode() uint32 {
|
|
||||||
return s.mode
|
|
||||||
}
|
|
||||||
|
|
||||||
// UID returns file's user id of owner.
|
|
||||||
func (s StatT) UID() uint32 {
|
|
||||||
return s.uid
|
|
||||||
}
|
|
||||||
|
|
||||||
// GID returns file's group id of owner.
|
|
||||||
func (s StatT) GID() uint32 {
|
|
||||||
return s.gid
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rdev returns file's device ID (if it's special file).
|
|
||||||
func (s StatT) Rdev() uint64 {
|
|
||||||
return s.rdev
|
|
||||||
}
|
|
||||||
|
|
||||||
// Size returns file's size.
|
|
||||||
func (s StatT) Size() int64 {
|
|
||||||
return s.size
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mtim returns file's last modification time.
|
|
||||||
func (s StatT) Mtim() syscall.Timespec {
|
|
||||||
return s.mtim
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsDir reports whether s describes a directory.
|
|
||||||
func (s StatT) IsDir() bool {
|
|
||||||
return s.mode&syscall.S_IFDIR != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stat takes a path to a file and returns
|
|
||||||
// a system.StatT type pertaining to that file.
|
|
||||||
//
|
|
||||||
// Throws an error if the file does not exist
|
|
||||||
func Stat(path string) (*StatT, error) {
|
|
||||||
s := &syscall.Stat_t{}
|
|
||||||
if err := syscall.Stat(path, s); err != nil {
|
|
||||||
return nil, &os.PathError{Op: "Stat", Path: path, Err: err}
|
|
||||||
}
|
|
||||||
return fromStatT(s)
|
|
||||||
}
|
|
49
vendor/github.com/docker/docker/pkg/system/stat_windows.go
generated
vendored
49
vendor/github.com/docker/docker/pkg/system/stat_windows.go
generated
vendored
@ -1,49 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// StatT type contains status of a file. It contains metadata
|
|
||||||
// like permission, size, etc about a file.
|
|
||||||
type StatT struct {
|
|
||||||
mode os.FileMode
|
|
||||||
size int64
|
|
||||||
mtim time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
// Size returns file's size.
|
|
||||||
func (s StatT) Size() int64 {
|
|
||||||
return s.size
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mode returns file's permission mode.
|
|
||||||
func (s StatT) Mode() os.FileMode {
|
|
||||||
return os.FileMode(s.mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mtim returns file's last modification time.
|
|
||||||
func (s StatT) Mtim() time.Time {
|
|
||||||
return time.Time(s.mtim)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stat takes a path to a file and returns
|
|
||||||
// a system.StatT type pertaining to that file.
|
|
||||||
//
|
|
||||||
// Throws an error if the file does not exist
|
|
||||||
func Stat(path string) (*StatT, error) {
|
|
||||||
fi, err := os.Stat(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return fromStatT(&fi)
|
|
||||||
}
|
|
||||||
|
|
||||||
// fromStatT converts a os.FileInfo type to a system.StatT type
|
|
||||||
func fromStatT(fi *os.FileInfo) (*StatT, error) {
|
|
||||||
return &StatT{
|
|
||||||
size: (*fi).Size(),
|
|
||||||
mode: (*fi).Mode(),
|
|
||||||
mtim: (*fi).ModTime()}, nil
|
|
||||||
}
|
|
17
vendor/github.com/docker/docker/pkg/system/syscall_unix.go
generated
vendored
17
vendor/github.com/docker/docker/pkg/system/syscall_unix.go
generated
vendored
@ -1,17 +0,0 @@
|
|||||||
// +build linux freebsd
|
|
||||||
|
|
||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import "golang.org/x/sys/unix"
|
|
||||||
|
|
||||||
// Unmount is a platform-specific helper function to call
|
|
||||||
// the unmount syscall.
|
|
||||||
func Unmount(dest string) error {
|
|
||||||
return unix.Unmount(dest, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CommandLineToArgv should not be used on Unix.
|
|
||||||
// It simply returns commandLine in the only element in the returned array.
|
|
||||||
func CommandLineToArgv(commandLine string) ([]string, error) {
|
|
||||||
return []string{commandLine}, nil
|
|
||||||
}
|
|
157
vendor/github.com/docker/docker/pkg/system/syscall_windows.go
generated
vendored
157
vendor/github.com/docker/docker/pkg/system/syscall_windows.go
generated
vendored
@ -1,157 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/osversion"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
OWNER_SECURITY_INFORMATION = windows.OWNER_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.OWNER_SECURITY_INFORMATION
|
|
||||||
GROUP_SECURITY_INFORMATION = windows.GROUP_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.GROUP_SECURITY_INFORMATION
|
|
||||||
DACL_SECURITY_INFORMATION = windows.DACL_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.DACL_SECURITY_INFORMATION
|
|
||||||
SACL_SECURITY_INFORMATION = windows.SACL_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.SACL_SECURITY_INFORMATION
|
|
||||||
LABEL_SECURITY_INFORMATION = windows.LABEL_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.LABEL_SECURITY_INFORMATION
|
|
||||||
ATTRIBUTE_SECURITY_INFORMATION = windows.ATTRIBUTE_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.ATTRIBUTE_SECURITY_INFORMATION
|
|
||||||
SCOPE_SECURITY_INFORMATION = windows.SCOPE_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.SCOPE_SECURITY_INFORMATION
|
|
||||||
PROCESS_TRUST_LABEL_SECURITY_INFORMATION = 0x00000080
|
|
||||||
ACCESS_FILTER_SECURITY_INFORMATION = 0x00000100
|
|
||||||
BACKUP_SECURITY_INFORMATION = windows.BACKUP_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.BACKUP_SECURITY_INFORMATION
|
|
||||||
PROTECTED_DACL_SECURITY_INFORMATION = windows.PROTECTED_DACL_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.PROTECTED_DACL_SECURITY_INFORMATION
|
|
||||||
PROTECTED_SACL_SECURITY_INFORMATION = windows.PROTECTED_SACL_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.PROTECTED_SACL_SECURITY_INFORMATION
|
|
||||||
UNPROTECTED_DACL_SECURITY_INFORMATION = windows.UNPROTECTED_DACL_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.UNPROTECTED_DACL_SECURITY_INFORMATION
|
|
||||||
UNPROTECTED_SACL_SECURITY_INFORMATION = windows.UNPROTECTED_SACL_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.UNPROTECTED_SACL_SECURITY_INFORMATION
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
SE_UNKNOWN_OBJECT_TYPE = windows.SE_UNKNOWN_OBJECT_TYPE // Deprecated: use golang.org/x/sys/windows.SE_UNKNOWN_OBJECT_TYPE
|
|
||||||
SE_FILE_OBJECT = windows.SE_FILE_OBJECT // Deprecated: use golang.org/x/sys/windows.SE_FILE_OBJECT
|
|
||||||
SE_SERVICE = windows.SE_SERVICE // Deprecated: use golang.org/x/sys/windows.SE_SERVICE
|
|
||||||
SE_PRINTER = windows.SE_PRINTER // Deprecated: use golang.org/x/sys/windows.SE_PRINTER
|
|
||||||
SE_REGISTRY_KEY = windows.SE_REGISTRY_KEY // Deprecated: use golang.org/x/sys/windows.SE_REGISTRY_KEY
|
|
||||||
SE_LMSHARE = windows.SE_LMSHARE // Deprecated: use golang.org/x/sys/windows.SE_LMSHARE
|
|
||||||
SE_KERNEL_OBJECT = windows.SE_KERNEL_OBJECT // Deprecated: use golang.org/x/sys/windows.SE_KERNEL_OBJECT
|
|
||||||
SE_WINDOW_OBJECT = windows.SE_WINDOW_OBJECT // Deprecated: use golang.org/x/sys/windows.SE_WINDOW_OBJECT
|
|
||||||
SE_DS_OBJECT = windows.SE_DS_OBJECT // Deprecated: use golang.org/x/sys/windows.SE_DS_OBJECT
|
|
||||||
SE_DS_OBJECT_ALL = windows.SE_DS_OBJECT_ALL // Deprecated: use golang.org/x/sys/windows.SE_DS_OBJECT_ALL
|
|
||||||
SE_PROVIDER_DEFINED_OBJECT = windows.SE_PROVIDER_DEFINED_OBJECT // Deprecated: use golang.org/x/sys/windows.SE_PROVIDER_DEFINED_OBJECT
|
|
||||||
SE_WMIGUID_OBJECT = windows.SE_WMIGUID_OBJECT // Deprecated: use golang.org/x/sys/windows.SE_WMIGUID_OBJECT
|
|
||||||
SE_REGISTRY_WOW64_32KEY = windows.SE_REGISTRY_WOW64_32KEY // Deprecated: use golang.org/x/sys/windows.SE_REGISTRY_WOW64_32KEY
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
SeTakeOwnershipPrivilege = "SeTakeOwnershipPrivilege"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
ContainerAdministratorSidString = "S-1-5-93-2-1"
|
|
||||||
ContainerUserSidString = "S-1-5-93-2-2"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ntuserApiset = windows.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0")
|
|
||||||
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
|
|
||||||
procGetVersionExW = modkernel32.NewProc("GetVersionExW")
|
|
||||||
procSetNamedSecurityInfo = modadvapi32.NewProc("SetNamedSecurityInfoW")
|
|
||||||
procGetSecurityDescriptorDacl = modadvapi32.NewProc("GetSecurityDescriptorDacl")
|
|
||||||
)
|
|
||||||
|
|
||||||
// OSVersion is a wrapper for Windows version information
|
|
||||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx
|
|
||||||
type OSVersion = osversion.OSVersion
|
|
||||||
|
|
||||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724833(v=vs.85).aspx
|
|
||||||
// TODO: use golang.org/x/sys/windows.OsVersionInfoEx (needs OSVersionInfoSize to be exported)
|
|
||||||
type osVersionInfoEx struct {
|
|
||||||
OSVersionInfoSize uint32
|
|
||||||
MajorVersion uint32
|
|
||||||
MinorVersion uint32
|
|
||||||
BuildNumber uint32
|
|
||||||
PlatformID uint32
|
|
||||||
CSDVersion [128]uint16
|
|
||||||
ServicePackMajor uint16
|
|
||||||
ServicePackMinor uint16
|
|
||||||
SuiteMask uint16
|
|
||||||
ProductType byte
|
|
||||||
Reserve byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOSVersion gets the operating system version on Windows. Note that
|
|
||||||
// dockerd.exe must be manifested to get the correct version information.
|
|
||||||
// Deprecated: use github.com/Microsoft/hcsshim/osversion.Get() instead
|
|
||||||
func GetOSVersion() OSVersion {
|
|
||||||
return osversion.Get()
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsWindowsClient returns true if the SKU is client
|
|
||||||
func IsWindowsClient() bool {
|
|
||||||
osviex := &osVersionInfoEx{OSVersionInfoSize: 284}
|
|
||||||
r1, _, err := procGetVersionExW.Call(uintptr(unsafe.Pointer(osviex)))
|
|
||||||
if r1 == 0 {
|
|
||||||
logrus.Warnf("GetVersionExW failed - assuming server SKU: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
const verNTWorkstation = 0x00000001
|
|
||||||
return osviex.ProductType == verNTWorkstation
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unmount is a platform-specific helper function to call
|
|
||||||
// the unmount syscall. Not supported on Windows
|
|
||||||
func Unmount(_ string) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CommandLineToArgv wraps the Windows syscall to turn a commandline into an argument array.
|
|
||||||
func CommandLineToArgv(commandLine string) ([]string, error) {
|
|
||||||
var argc int32
|
|
||||||
|
|
||||||
argsPtr, err := windows.UTF16PtrFromString(commandLine)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
argv, err := windows.CommandLineToArgv(argsPtr, &argc)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer windows.LocalFree(windows.Handle(uintptr(unsafe.Pointer(argv))))
|
|
||||||
|
|
||||||
newArgs := make([]string, argc)
|
|
||||||
for i, v := range (*argv)[:argc] {
|
|
||||||
newArgs[i] = windows.UTF16ToString((*v)[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
return newArgs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasWin32KSupport determines whether containers that depend on win32k can
|
|
||||||
// run on this machine. Win32k is the driver used to implement windowing.
|
|
||||||
func HasWin32KSupport() bool {
|
|
||||||
// For now, check for ntuser API support on the host. In the future, a host
|
|
||||||
// may support win32k in containers even if the host does not support ntuser
|
|
||||||
// APIs.
|
|
||||||
return ntuserApiset.Load() == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetNamedSecurityInfo(objectName *uint16, objectType uint32, securityInformation uint32, sidOwner *windows.SID, sidGroup *windows.SID, dacl *byte, sacl *byte) (result error) {
|
|
||||||
r0, _, _ := syscall.Syscall9(procSetNamedSecurityInfo.Addr(), 7, uintptr(unsafe.Pointer(objectName)), uintptr(objectType), uintptr(securityInformation), uintptr(unsafe.Pointer(sidOwner)), uintptr(unsafe.Pointer(sidGroup)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(sacl)), 0, 0)
|
|
||||||
if r0 != 0 {
|
|
||||||
result = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetSecurityDescriptorDacl(securityDescriptor *byte, daclPresent *uint32, dacl **byte, daclDefaulted *uint32) (result error) {
|
|
||||||
r1, _, e1 := syscall.Syscall6(procGetSecurityDescriptorDacl.Addr(), 4, uintptr(unsafe.Pointer(securityDescriptor)), uintptr(unsafe.Pointer(daclPresent)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(daclDefaulted)), 0, 0)
|
|
||||||
if r1 == 0 {
|
|
||||||
if e1 != 0 {
|
|
||||||
result = e1
|
|
||||||
} else {
|
|
||||||
result = syscall.EINVAL
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
13
vendor/github.com/docker/docker/pkg/system/umask.go
generated
vendored
13
vendor/github.com/docker/docker/pkg/system/umask.go
generated
vendored
@ -1,13 +0,0 @@
|
|||||||
// +build !windows
|
|
||||||
|
|
||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Umask sets current process's file mode creation mask to newmask
|
|
||||||
// and returns oldmask.
|
|
||||||
func Umask(newmask int) (oldmask int, err error) {
|
|
||||||
return unix.Umask(newmask), nil
|
|
||||||
}
|
|
7
vendor/github.com/docker/docker/pkg/system/umask_windows.go
generated
vendored
7
vendor/github.com/docker/docker/pkg/system/umask_windows.go
generated
vendored
@ -1,7 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
// Umask is not supported on the windows platform.
|
|
||||||
func Umask(newmask int) (oldmask int, err error) {
|
|
||||||
// should not be called on cli code path
|
|
||||||
return 0, ErrNotSupportedPlatform
|
|
||||||
}
|
|
24
vendor/github.com/docker/docker/pkg/system/utimes_unix.go
generated
vendored
24
vendor/github.com/docker/docker/pkg/system/utimes_unix.go
generated
vendored
@ -1,24 +0,0 @@
|
|||||||
// +build linux freebsd
|
|
||||||
|
|
||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
// LUtimesNano is used to change access and modification time of the specified path.
|
|
||||||
// It's used for symbol link file because unix.UtimesNano doesn't support a NOFOLLOW flag atm.
|
|
||||||
func LUtimesNano(path string, ts []syscall.Timespec) error {
|
|
||||||
uts := []unix.Timespec{
|
|
||||||
unix.NsecToTimespec(syscall.TimespecToNsec(ts[0])),
|
|
||||||
unix.NsecToTimespec(syscall.TimespecToNsec(ts[1])),
|
|
||||||
}
|
|
||||||
err := unix.UtimesNanoAt(unix.AT_FDCWD, path, uts, unix.AT_SYMLINK_NOFOLLOW)
|
|
||||||
if err != nil && err != unix.ENOSYS {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
10
vendor/github.com/docker/docker/pkg/system/utimes_unsupported.go
generated
vendored
10
vendor/github.com/docker/docker/pkg/system/utimes_unsupported.go
generated
vendored
@ -1,10 +0,0 @@
|
|||||||
// +build !linux,!freebsd
|
|
||||||
|
|
||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import "syscall"
|
|
||||||
|
|
||||||
// LUtimesNano is only supported on linux and freebsd.
|
|
||||||
func LUtimesNano(path string, ts []syscall.Timespec) error {
|
|
||||||
return ErrNotSupportedPlatform
|
|
||||||
}
|
|
37
vendor/github.com/docker/docker/pkg/system/xattrs_linux.go
generated
vendored
37
vendor/github.com/docker/docker/pkg/system/xattrs_linux.go
generated
vendored
@ -1,37 +0,0 @@
|
|||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
import "golang.org/x/sys/unix"
|
|
||||||
|
|
||||||
// Lgetxattr retrieves the value of the extended attribute identified by attr
|
|
||||||
// and associated with the given path in the file system.
|
|
||||||
// It will returns a nil slice and nil error if the xattr is not set.
|
|
||||||
func Lgetxattr(path string, attr string) ([]byte, error) {
|
|
||||||
// Start with a 128 length byte array
|
|
||||||
dest := make([]byte, 128)
|
|
||||||
sz, errno := unix.Lgetxattr(path, attr, dest)
|
|
||||||
|
|
||||||
for errno == unix.ERANGE {
|
|
||||||
// Buffer too small, use zero-sized buffer to get the actual size
|
|
||||||
sz, errno = unix.Lgetxattr(path, attr, []byte{})
|
|
||||||
if errno != nil {
|
|
||||||
return nil, errno
|
|
||||||
}
|
|
||||||
dest = make([]byte, sz)
|
|
||||||
sz, errno = unix.Lgetxattr(path, attr, dest)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case errno == unix.ENODATA:
|
|
||||||
return nil, nil
|
|
||||||
case errno != nil:
|
|
||||||
return nil, errno
|
|
||||||
}
|
|
||||||
|
|
||||||
return dest[:sz], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lsetxattr sets the value of the extended attribute identified by attr
|
|
||||||
// and associated with the given path in the file system.
|
|
||||||
func Lsetxattr(path string, attr string, data []byte, flags int) error {
|
|
||||||
return unix.Lsetxattr(path, attr, data, flags)
|
|
||||||
}
|
|
13
vendor/github.com/docker/docker/pkg/system/xattrs_unsupported.go
generated
vendored
13
vendor/github.com/docker/docker/pkg/system/xattrs_unsupported.go
generated
vendored
@ -1,13 +0,0 @@
|
|||||||
// +build !linux
|
|
||||||
|
|
||||||
package system // import "github.com/docker/docker/pkg/system"
|
|
||||||
|
|
||||||
// Lgetxattr is not supported on platforms other than linux.
|
|
||||||
func Lgetxattr(path string, attr string) ([]byte, error) {
|
|
||||||
return nil, ErrNotSupportedPlatform
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lsetxattr is not supported on platforms other than linux.
|
|
||||||
func Lsetxattr(path string, attr string, data []byte, flags int) error {
|
|
||||||
return ErrNotSupportedPlatform
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user