summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/common/specgen.go9
-rw-r--r--cmd/podman/parse/json.go9
-rw-r--r--cmd/podman/parse/json_test.go30
-rw-r--r--cmd/podman/pods/create.go2
-rw-r--r--cmd/podman/system/info.go3
-rw-r--r--cmd/podman/system/version.go3
-rw-r--r--go.mod6
-rw-r--r--go.sum10
-rw-r--r--libpod/options.go8
-rw-r--r--pkg/api/handlers/compat/containers_attach.go79
-rw-r--r--pkg/api/handlers/compat/exec.go14
-rw-r--r--pkg/api/server/handler_api.go1
-rw-r--r--pkg/api/server/idletracker/idletracker.go74
-rw-r--r--pkg/api/server/server.go72
-rw-r--r--pkg/bindings/containers/attach.go8
-rw-r--r--pkg/domain/entities/pods.go2
-rw-r--r--pkg/spec/createconfig.go4
-rw-r--r--pkg/specgen/generate/container_create.go4
-rw-r--r--pkg/specgen/generate/pod_create.go4
-rw-r--r--pkg/specgen/podspecgen.go6
-rw-r--r--pkg/specgen/specgen.go7
-rw-r--r--pkg/varlinkapi/create.go4
-rw-r--r--test/e2e/exec_test.go5
-rw-r--r--test/e2e/info_test.go30
-rw-r--r--test/e2e/pod_inspect_test.go1
-rw-r--r--test/e2e/version_test.go34
-rw-r--r--vendor/github.com/containers/storage/.cirrus.yml10
-rw-r--r--vendor/github.com/containers/storage/VERSION2
-rw-r--r--vendor/github.com/containers/storage/drivers/devmapper/device_setup.go18
-rw-r--r--vendor/github.com/containers/storage/drivers/devmapper/deviceset.go5
-rw-r--r--vendor/github.com/containers/storage/go.mod14
-rw-r--r--vendor/github.com/containers/storage/go.sum63
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/archive.go20
-rw-r--r--vendor/github.com/containers/storage/pkg/config/config.go7
-rw-r--r--vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go5
-rw-r--r--vendor/github.com/containers/storage/storage.conf6
-rw-r--r--vendor/github.com/containers/storage/store.go90
-rw-r--r--vendor/github.com/containers/storage/utils.go111
-rw-r--r--vendor/github.com/hashicorp/go-multierror/.travis.yml2
-rw-r--r--vendor/github.com/hashicorp/go-multierror/README.md40
-rw-r--r--vendor/github.com/hashicorp/go-multierror/go.mod2
-rw-r--r--vendor/github.com/hashicorp/go-multierror/go.sum2
-rw-r--r--vendor/github.com/hashicorp/go-multierror/group.go38
-rw-r--r--vendor/github.com/hashicorp/go-multierror/multierror.go67
-rw-r--r--vendor/github.com/klauspost/compress/zstd/README.md206
-rw-r--r--vendor/github.com/klauspost/compress/zstd/blockenc.go4
-rw-r--r--vendor/github.com/klauspost/compress/zstd/decoder.go20
-rw-r--r--vendor/github.com/klauspost/compress/zstd/decoder_options.go16
-rw-r--r--vendor/github.com/klauspost/compress/zstd/encoder.go6
-rw-r--r--vendor/github.com/klauspost/compress/zstd/encoder_options.go38
-rw-r--r--vendor/github.com/klauspost/compress/zstd/snappy.go2
-rw-r--r--vendor/github.com/opencontainers/selinux/go-selinux/doc.go21
-rw-r--r--vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go2
-rw-r--r--vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go1
-rw-r--r--vendor/github.com/opencontainers/selinux/go-selinux/selinux.go249
-rw-r--r--vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go481
-rw-r--r--vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go190
-rw-r--r--vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go8
-rw-r--r--vendor/github.com/willf/bitset/.gitignore26
-rw-r--r--vendor/github.com/willf/bitset/.travis.yml37
-rw-r--r--vendor/github.com/willf/bitset/LICENSE27
-rw-r--r--vendor/github.com/willf/bitset/Makefile191
-rw-r--r--vendor/github.com/willf/bitset/README.md96
-rw-r--r--vendor/github.com/willf/bitset/azure-pipelines.yml39
-rw-r--r--vendor/github.com/willf/bitset/bitset.go879
-rw-r--r--vendor/github.com/willf/bitset/popcnt.go53
-rw-r--r--vendor/github.com/willf/bitset/popcnt_19.go45
-rw-r--r--vendor/github.com/willf/bitset/popcnt_amd64.go68
-rw-r--r--vendor/github.com/willf/bitset/popcnt_amd64.s104
-rw-r--r--vendor/github.com/willf/bitset/popcnt_generic.go24
-rw-r--r--vendor/github.com/willf/bitset/trailing_zeros_18.go14
-rw-r--r--vendor/github.com/willf/bitset/trailing_zeros_19.go9
-rw-r--r--vendor/modules.txt10
73 files changed, 3148 insertions, 649 deletions
diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go
index 8d051ead7..f17077484 100644
--- a/cmd/podman/common/specgen.go
+++ b/cmd/podman/common/specgen.go
@@ -380,6 +380,9 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
}
var command []string
+ // Include the command used to create the container.
+ s.ContainerCreateCommand = os.Args
+
// Build the command
// If we have an entry point, it goes first
if c.Entrypoint != nil {
@@ -510,8 +513,10 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
s.ContainerSecurityConfig.SelinuxOpts = append(s.ContainerSecurityConfig.SelinuxOpts, con[1])
s.Annotations[define.InspectAnnotationLabel] = strings.Join(s.ContainerSecurityConfig.SelinuxOpts, ",label=")
case "apparmor":
- s.ContainerSecurityConfig.ApparmorProfile = con[1]
- s.Annotations[define.InspectAnnotationApparmor] = con[1]
+ if !c.Privileged {
+ s.ContainerSecurityConfig.ApparmorProfile = con[1]
+ s.Annotations[define.InspectAnnotationApparmor] = con[1]
+ }
case "seccomp":
s.SeccompProfilePath = con[1]
s.Annotations[define.InspectAnnotationSeccomp] = con[1]
diff --git a/cmd/podman/parse/json.go b/cmd/podman/parse/json.go
new file mode 100644
index 000000000..95a6633b8
--- /dev/null
+++ b/cmd/podman/parse/json.go
@@ -0,0 +1,9 @@
+package parse
+
+import "regexp"
+
+var jsonFormatRegex = regexp.MustCompile(`^(\s*json\s*|\s*{{\s*json\s*\.\s*}}\s*)$`)
+
+func MatchesJSONFormat(s string) bool {
+ return jsonFormatRegex.Match([]byte(s))
+}
diff --git a/cmd/podman/parse/json_test.go b/cmd/podman/parse/json_test.go
new file mode 100644
index 000000000..5cad185fd
--- /dev/null
+++ b/cmd/podman/parse/json_test.go
@@ -0,0 +1,30 @@
+package parse
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestMatchesJSONFormat(t *testing.T) {
+ tests := []struct {
+ input string
+ expected bool
+ }{
+ {"json", true},
+ {" json", true},
+ {"json ", true},
+ {" json ", true},
+ {"{{json .}}", true},
+ {"{{ json .}}", true},
+ {"{{json . }}", true},
+ {" {{ json . }} ", true},
+ {"{{json }}", false},
+ {"{{json .", false},
+ {"json . }}", false},
+ }
+
+ for _, tt := range tests {
+ assert.Equal(t, tt.expected, MatchesJSONFormat(tt.input))
+ }
+}
diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go
index 0e2a085fd..d57a2f2f7 100644
--- a/cmd/podman/pods/create.go
+++ b/cmd/podman/pods/create.go
@@ -149,6 +149,8 @@ func create(cmd *cobra.Command, args []string) error {
}
}
+ createOptions.CreateCommand = os.Args
+
if replace {
if err := replacePod(createOptions.Name); err != nil {
return err
diff --git a/cmd/podman/system/info.go b/cmd/podman/system/info.go
index 699f7b55c..410b3455a 100644
--- a/cmd/podman/system/info.go
+++ b/cmd/podman/system/info.go
@@ -5,6 +5,7 @@ import (
"os"
"text/template"
+ "github.com/containers/libpod/v2/cmd/podman/parse"
"github.com/containers/libpod/v2/cmd/podman/registry"
"github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
@@ -68,7 +69,7 @@ func info(cmd *cobra.Command, args []string) error {
return err
}
- if inFormat == "json" {
+ if parse.MatchesJSONFormat(inFormat) {
b, err := json.MarshalIndent(info, "", " ")
if err != nil {
return err
diff --git a/cmd/podman/system/version.go b/cmd/podman/system/version.go
index 5aac34699..9b70bc9f4 100644
--- a/cmd/podman/system/version.go
+++ b/cmd/podman/system/version.go
@@ -8,6 +8,7 @@ import (
"text/tabwriter"
"github.com/containers/buildah/pkg/formats"
+ "github.com/containers/libpod/v2/cmd/podman/parse"
"github.com/containers/libpod/v2/cmd/podman/registry"
"github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/libpod/define"
@@ -41,7 +42,7 @@ func version(cmd *cobra.Command, args []string) error {
}
switch {
- case versionFormat == "json", versionFormat == "{{ json .}}":
+ case parse.MatchesJSONFormat(versionFormat):
s, err := json.MarshalToString(versions)
if err != nil {
return err
diff --git a/go.mod b/go.mod
index d321f46d6..b28335aa0 100644
--- a/go.mod
+++ b/go.mod
@@ -15,7 +15,7 @@ require (
github.com/containers/conmon v2.0.18+incompatible
github.com/containers/image/v5 v5.5.1
github.com/containers/psgo v1.5.1
- github.com/containers/storage v1.20.2
+ github.com/containers/storage v1.21.0
github.com/coreos/go-systemd/v22 v22.1.0
github.com/cri-o/ocicni v0.2.0
github.com/cyphar/filepath-securejoin v0.2.2
@@ -31,7 +31,7 @@ require (
github.com/google/uuid v1.1.1
github.com/gorilla/mux v1.7.4
github.com/gorilla/schema v1.1.0
- github.com/hashicorp/go-multierror v1.0.0
+ github.com/hashicorp/go-multierror v1.1.0
github.com/hpcloud/tail v1.0.0
github.com/json-iterator/go v1.1.10
github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618
@@ -42,7 +42,7 @@ require (
github.com/opencontainers/runc v1.0.0-rc91.0.20200708210054-ce54a9d4d79b
github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2
github.com/opencontainers/runtime-tools v0.9.0
- github.com/opencontainers/selinux v1.5.2
+ github.com/opencontainers/selinux v1.6.0
github.com/opentracing/opentracing-go v1.2.0
github.com/pkg/errors v0.9.1
github.com/pmezard/go-difflib v1.0.0
diff --git a/go.sum b/go.sum
index 29cb0648b..350f4bcf0 100644
--- a/go.sum
+++ b/go.sum
@@ -86,6 +86,8 @@ github.com/containers/psgo v1.5.1 h1:MQNb7FLbXqBdqz6u4lI2QWizVz4RSTzs1+Nk9XT1iVA
github.com/containers/psgo v1.5.1/go.mod h1:2ubh0SsreMZjSXW1Hif58JrEcFudQyIy9EzPUWfawVU=
github.com/containers/storage v1.20.2 h1:tw/uKRPDnmVrluIzer3dawTFG/bTJLP8IEUyHFhltYk=
github.com/containers/storage v1.20.2/go.mod h1:oOB9Ie8OVPojvoaKWEGSEtHbXUAs+tSyr7RO7ZGteMc=
+github.com/containers/storage v1.21.0 h1:9VpsAmqwA9P+xQZc2sWZ3sj5NQojvg47P6orW34nYFU=
+github.com/containers/storage v1.21.0/go.mod h1:I1EIAA7B4OwWRSA0b4yq2AW1wjvvfcY0zLWQuwTa4zw=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-iptables v0.4.5 h1:DpHb9vJrZQEFMcVLFKAAGMUVX0XoRC0ptCthinRYm38=
@@ -223,6 +225,8 @@ github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
+github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@@ -253,6 +257,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.10.8 h1:eLeJ3dr/Y9+XRfJT4l+8ZjmtB5RPJhucH2HeCV5+IZY=
github.com/klauspost/compress v1.10.8/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.10.10 h1:a/y8CglcM7gLGYmlbP/stPE5sR3hbhFRUjCBfd/0B3I=
+github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/pgzip v1.2.4 h1:TQ7CNpYKovDOmqzRHKxJh0BeaBI7UdQZYc6p7pMQh1A=
github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -345,6 +351,8 @@ github.com/opencontainers/selinux v1.3.0/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOl
github.com/opencontainers/selinux v1.5.1/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
github.com/opencontainers/selinux v1.5.2 h1:F6DgIsjgBIcDksLW4D5RG9bXok6oqZ3nvMwj4ZoFu/Q=
github.com/opencontainers/selinux v1.5.2/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
+github.com/opencontainers/selinux v1.6.0 h1:+bIAS/Za3q5FTwWym4fTB0vObnfCf3G/NC7K6Jx62mY=
+github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
github.com/openshift/imagebuilder v1.1.6 h1:1+YzRxIIefY4QqtCImx6rg+75QrKNfBoPAKxgMo/khM=
github.com/openshift/imagebuilder v1.1.6/go.mod h1:9aJRczxCH0mvT6XQ+5STAQaPWz7OsWcU5/mRkt8IWeo=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
@@ -459,6 +467,8 @@ github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYp
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
+github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243 h1:R43TdZy32XXSXjJn7M/HhALJ9imq6ztLnChfYJpVDnM=
+github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b h1:6cLsL+2FW6dRAdl5iMtHgRogVCff0QpRi9653YmdcJA=
github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
diff --git a/libpod/options.go b/libpod/options.go
index 104d7c9db..b3c11ebc1 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1419,12 +1419,12 @@ func WithPreserveFDs(fd uint) CtrCreateOption {
// WithCreateCommand adds the full command plus arguments of the current
// process to the container config.
-func WithCreateCommand() CtrCreateOption {
+func WithCreateCommand(cmd []string) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return define.ErrCtrFinalized
}
- ctr.config.CreateCommand = os.Args
+ ctr.config.CreateCommand = cmd
return nil
}
}
@@ -1625,12 +1625,12 @@ func WithPodHostname(hostname string) PodCreateOption {
// WithPodCreateCommand adds the full command plus arguments of the current
// process to the pod config.
-func WithPodCreateCommand() PodCreateOption {
+func WithPodCreateCommand(createCmd []string) PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
- pod.config.CreateCommand = os.Args
+ pod.config.CreateCommand = createCmd
return nil
}
}
diff --git a/pkg/api/handlers/compat/containers_attach.go b/pkg/api/handlers/compat/containers_attach.go
index 325f96b40..71586fca4 100644
--- a/pkg/api/handlers/compat/containers_attach.go
+++ b/pkg/api/handlers/compat/containers_attach.go
@@ -1,23 +1,22 @@
package compat
import (
+ "bufio"
"fmt"
+ "io"
+ "net"
"net/http"
+ "strings"
"github.com/containers/libpod/v2/libpod"
"github.com/containers/libpod/v2/libpod/define"
"github.com/containers/libpod/v2/pkg/api/handlers/utils"
+ "github.com/containers/libpod/v2/pkg/api/server/idletracker"
"github.com/gorilla/schema"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
-// AttachHeader is the literal header sent for upgraded/hijacked connections for
-// attach, sourced from Docker at:
-// https://raw.githubusercontent.com/moby/moby/b95fad8e51bd064be4f4e58a996924f343846c85/api/server/router/container/container_routes.go
-// Using literally to ensure compatibility with existing clients.
-const AttachHeader = "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n"
-
func AttachContainer(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
@@ -98,21 +97,11 @@ func AttachContainer(w http.ResponseWriter, r *http.Request) {
return
}
- // Hijack the connection
- hijacker, ok := w.(http.Hijacker)
- if !ok {
- utils.InternalServerError(w, errors.Errorf("unable to hijack connection"))
- return
- }
-
- connection, buffer, err := hijacker.Hijack()
+ connection, buffer, err := AttachConnection(w, r)
if err != nil {
- utils.InternalServerError(w, errors.Wrapf(err, "error hijacking connection"))
+ utils.InternalServerError(w, err)
return
}
-
- fmt.Fprintf(connection, AttachHeader)
-
logrus.Debugf("Hijack for attach of container %s successful", ctr.ID())
// Perform HTTP attach.
@@ -126,3 +115,57 @@ func AttachContainer(w http.ResponseWriter, r *http.Request) {
logrus.Debugf("Attach for container %s completed successfully", ctr.ID())
}
+
+type HijackedConnection struct {
+ net.Conn // Connection
+ idleTracker *idletracker.IdleTracker // Connection tracker
+}
+
+func (c HijackedConnection) Close() error {
+ logrus.Debugf("Hijacked connection closed")
+
+ c.idleTracker.TrackHijackedClosed()
+ return c.Conn.Close()
+}
+
+func AttachConnection(w http.ResponseWriter, r *http.Request) (net.Conn, *bufio.ReadWriter, error) {
+ idleTracker := r.Context().Value("idletracker").(*idletracker.IdleTracker)
+
+ // Hijack the connection
+ hijacker, ok := w.(http.Hijacker)
+ if !ok {
+ return nil, nil, errors.Errorf("unable to hijack connection")
+ }
+
+ connection, buffer, err := hijacker.Hijack()
+ if err != nil {
+ return nil, nil, errors.Wrapf(err, "error hijacking connection")
+ }
+ trackedConnection := HijackedConnection{
+ Conn: connection,
+ idleTracker: idleTracker,
+ }
+
+ WriteAttachHeaders(r, trackedConnection)
+
+ return trackedConnection, buffer, nil
+}
+
+func WriteAttachHeaders(r *http.Request, connection io.Writer) {
+ // AttachHeader is the literal header sent for upgraded/hijacked connections for
+ // attach, sourced from Docker at:
+ // https://raw.githubusercontent.com/moby/moby/b95fad8e51bd064be4f4e58a996924f343846c85/api/server/router/container/container_routes.go
+ // Using literally to ensure compatibility with existing clients.
+ c := r.Header.Get("Connection")
+ proto := r.Header.Get("Upgrade")
+ if len(proto) == 0 || !strings.EqualFold(c, "Upgrade") {
+ // OK - can't upgrade if not requested or protocol is not specified
+ fmt.Fprintf(connection,
+ "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
+ } else {
+ // Upraded
+ fmt.Fprintf(connection,
+ "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: %s\r\n\r\n",
+ proto)
+ }
+}
diff --git a/pkg/api/handlers/compat/exec.go b/pkg/api/handlers/compat/exec.go
index aee4196dd..a3b8cb573 100644
--- a/pkg/api/handlers/compat/exec.go
+++ b/pkg/api/handlers/compat/exec.go
@@ -173,21 +173,11 @@ func ExecStartHandler(w http.ResponseWriter, r *http.Request) {
return
}
- // Hijack the connection
- hijacker, ok := w.(http.Hijacker)
- if !ok {
- utils.InternalServerError(w, errors.Errorf("unable to hijack connection"))
- return
- }
-
- connection, buffer, err := hijacker.Hijack()
+ connection, buffer, err := AttachConnection(w, r)
if err != nil {
- utils.InternalServerError(w, errors.Wrapf(err, "error hijacking connection"))
+ utils.InternalServerError(w, err)
return
}
-
- fmt.Fprintf(connection, AttachHeader)
-
logrus.Debugf("Hijack for attach of container %s exec session %s successful", sessionCtr.ID(), sessionID)
if err := sessionCtr.ExecHTTPStartAndAttach(sessionID, connection, buffer, nil, nil, nil); err != nil {
diff --git a/pkg/api/server/handler_api.go b/pkg/api/server/handler_api.go
index b0fd932ba..53fe8952b 100644
--- a/pkg/api/server/handler_api.go
+++ b/pkg/api/server/handler_api.go
@@ -37,6 +37,7 @@ func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc {
c := context.WithValue(r.Context(), "decoder", s.Decoder) //nolint
c = context.WithValue(c, "runtime", s.Runtime) //nolint
c = context.WithValue(c, "shutdownFunc", s.Shutdown) //nolint
+ c = context.WithValue(c, "idletracker", s.idleTracker) //nolint
r = r.WithContext(c)
h(w, r)
diff --git a/pkg/api/server/idletracker/idletracker.go b/pkg/api/server/idletracker/idletracker.go
new file mode 100644
index 000000000..1ee905a99
--- /dev/null
+++ b/pkg/api/server/idletracker/idletracker.go
@@ -0,0 +1,74 @@
+package idletracker
+
+import (
+ "net"
+ "net/http"
+ "sync"
+ "time"
+
+ "github.com/sirupsen/logrus"
+)
+
+type IdleTracker struct {
+ http map[net.Conn]struct{}
+ hijacked int
+ total int
+ mux sync.Mutex
+ timer *time.Timer
+ Duration time.Duration
+}
+
+func NewIdleTracker(idle time.Duration) *IdleTracker {
+ return &IdleTracker{
+ http: make(map[net.Conn]struct{}),
+ Duration: idle,
+ timer: time.NewTimer(idle),
+ }
+}
+
+func (t *IdleTracker) ConnState(conn net.Conn, state http.ConnState) {
+ t.mux.Lock()
+ defer t.mux.Unlock()
+
+ oldActive := t.ActiveConnections()
+ logrus.Debugf("IdleTracker %p:%v %d/%d connection(s)", conn, state, oldActive, t.TotalConnections())
+ switch state {
+ case http.StateNew, http.StateActive:
+ t.http[conn] = struct{}{}
+ // stop the timer if we transitioned from idle
+ if oldActive == 0 {
+ t.timer.Stop()
+ }
+ t.total++
+ case http.StateHijacked:
+ // hijacked connections are handled elsewhere
+ delete(t.http, conn)
+ t.hijacked++
+ case http.StateIdle, http.StateClosed:
+ delete(t.http, conn)
+ // Restart the timer if we've become idle
+ if oldActive > 0 && len(t.http) == 0 {
+ t.timer.Stop()
+ t.timer.Reset(t.Duration)
+ }
+ }
+}
+
+func (t *IdleTracker) TrackHijackedClosed() {
+ t.mux.Lock()
+ defer t.mux.Unlock()
+
+ t.hijacked--
+}
+
+func (t *IdleTracker) ActiveConnections() int {
+ return len(t.http) + t.hijacked
+}
+
+func (t *IdleTracker) TotalConnections() int {
+ return t.total
+}
+
+func (t *IdleTracker) Done() <-chan time.Time {
+ return t.timer.C
+}
diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go
index 8af6d3186..1c6007745 100644
--- a/pkg/api/server/server.go
+++ b/pkg/api/server/server.go
@@ -10,12 +10,12 @@ import (
"runtime"
goRuntime "runtime"
"strings"
- "sync"
"syscall"
"time"
"github.com/containers/libpod/v2/libpod"
"github.com/containers/libpod/v2/pkg/api/handlers"
+ "github.com/containers/libpod/v2/pkg/api/server/idletracker"
"github.com/coreos/go-systemd/v22/activation"
"github.com/gorilla/mux"
"github.com/gorilla/schema"
@@ -24,14 +24,14 @@ import (
)
type APIServer struct {
- http.Server // The HTTP work happens here
- *schema.Decoder // Decoder for Query parameters to structs
- context.Context // Context to carry objects to handlers
- *libpod.Runtime // Where the real work happens
- net.Listener // mux for routing HTTP API calls to libpod routines
- context.CancelFunc // Stop APIServer
- idleTracker *IdleTracker // Track connections to support idle shutdown
- pprof *http.Server // Sidecar http server for providing performance data
+ http.Server // The HTTP work happens here
+ *schema.Decoder // Decoder for Query parameters to structs
+ context.Context // Context to carry objects to handlers
+ *libpod.Runtime // Where the real work happens
+ net.Listener // mux for routing HTTP API calls to libpod routines
+ context.CancelFunc // Stop APIServer
+ idleTracker *idletracker.IdleTracker // Track connections to support idle shutdown
+ pprof *http.Server // Sidecar http server for providing performance data
}
// Number of seconds to wait for next request, if exceeded shutdown server
@@ -68,7 +68,7 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li
}
router := mux.NewRouter().UseEncodedPath()
- idle := NewIdleTracker(duration)
+ idle := idletracker.NewIdleTracker(duration)
server := APIServer{
Server: http.Server{
@@ -231,55 +231,3 @@ func (s *APIServer) Shutdown() error {
func (s *APIServer) Close() error {
return s.Server.Close()
}
-
-type IdleTracker struct {
- active map[net.Conn]struct{}
- total int
- mux sync.Mutex
- timer *time.Timer
- Duration time.Duration
-}
-
-func NewIdleTracker(idle time.Duration) *IdleTracker {
- return &IdleTracker{
- active: make(map[net.Conn]struct{}),
- Duration: idle,
- timer: time.NewTimer(idle),
- }
-}
-
-func (t *IdleTracker) ConnState(conn net.Conn, state http.ConnState) {
- t.mux.Lock()
- defer t.mux.Unlock()
-
- oldActive := len(t.active)
- logrus.Debugf("IdleTracker %p:%v %d/%d connection(s)", conn, state, t.ActiveConnections(), t.TotalConnections())
- switch state {
- case http.StateNew, http.StateActive, http.StateHijacked:
- t.active[conn] = struct{}{}
- // stop the timer if we transitioned from idle
- if oldActive == 0 {
- t.timer.Stop()
- }
- t.total++
- case http.StateIdle, http.StateClosed:
- delete(t.active, conn)
- // Restart the timer if we've become idle
- if oldActive > 0 && len(t.active) == 0 {
- t.timer.Stop()
- t.timer.Reset(t.Duration)
- }
- }
-}
-
-func (t *IdleTracker) ActiveConnections() int {
- return len(t.active)
-}
-
-func (t *IdleTracker) TotalConnections() int {
- return t.total
-}
-
-func (t *IdleTracker) Done() <-chan time.Time {
- return t.timer.C
-}
diff --git a/pkg/bindings/containers/attach.go b/pkg/bindings/containers/attach.go
index 077bb244f..297563688 100644
--- a/pkg/bindings/containers/attach.go
+++ b/pkg/bindings/containers/attach.go
@@ -457,15 +457,15 @@ func ExecStartAndAttach(ctx context.Context, sessionID string, streams *define.A
switch {
case fd == 0:
- if streams.AttachOutput {
+ if streams.AttachInput {
+ // Write STDIN to STDOUT (echoing characters
+ // typed by another attach session)
if _, err := streams.OutputStream.Write(frame[0:l]); err != nil {
return err
}
}
case fd == 1:
- if streams.AttachInput {
- // Write STDIN to STDOUT (echoing characters
- // typed by another attach session)
+ if streams.AttachOutput {
if _, err := streams.OutputStream.Write(frame[0:l]); err != nil {
return err
}
diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go
index 8023034ef..9e9b834ef 100644
--- a/pkg/domain/entities/pods.go
+++ b/pkg/domain/entities/pods.go
@@ -104,6 +104,7 @@ type PodRmReport struct {
type PodCreateOptions struct {
CGroupParent string
+ CreateCommand []string
Hostname string
Infra bool
InfraImage string
@@ -133,6 +134,7 @@ func (p PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) {
}
s.InfraImage = p.InfraImage
s.SharedNamespaces = p.Share
+ s.PodCreateCommand = p.CreateCommand
// Networking config
s.NetNS = p.Net.Network
diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go
index 879c66895..55c3238d2 100644
--- a/pkg/spec/createconfig.go
+++ b/pkg/spec/createconfig.go
@@ -406,10 +406,6 @@ func CreateContainerFromCreateConfig(ctx context.Context, r *libpod.Runtime, cre
return nil, err
}
- // Set the CreateCommand explicitly. Some (future) consumers of libpod
- // might not want to set it.
- options = append(options, libpod.WithCreateCommand())
-
ctr, err := r.NewContainer(ctx, runtimeSpec, options...)
if err != nil {
return nil, err
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index 8df5b996e..1bcd33672 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -78,7 +78,9 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
}
options := []libpod.CtrCreateOption{}
- options = append(options, libpod.WithCreateCommand())
+ if s.ContainerCreateCommand != nil {
+ options = append(options, libpod.WithCreateCommand(s.ContainerCreateCommand))
+ }
var newImage *image.Image
if s.Rootfs != "" {
diff --git a/pkg/specgen/generate/pod_create.go b/pkg/specgen/generate/pod_create.go
index 690651a23..4fe1b6435 100644
--- a/pkg/specgen/generate/pod_create.go
+++ b/pkg/specgen/generate/pod_create.go
@@ -93,7 +93,9 @@ func createPodOptions(p *specgen.PodSpecGenerator) ([]libpod.PodCreateOption, er
options = append(options, libpod.WithInfraContainerPorts(ports))
}
options = append(options, libpod.WithPodCgroups())
- options = append(options, libpod.WithPodCreateCommand())
+ if p.PodCreateCommand != nil {
+ options = append(options, libpod.WithPodCreateCommand(p.PodCreateCommand))
+ }
if len(p.InfraConmonPidFile) > 0 {
options = append(options, libpod.WithInfraConmonPidFile(p.InfraConmonPidFile))
}
diff --git a/pkg/specgen/podspecgen.go b/pkg/specgen/podspecgen.go
index 600d27004..3c32ec365 100644
--- a/pkg/specgen/podspecgen.go
+++ b/pkg/specgen/podspecgen.go
@@ -49,6 +49,12 @@ type PodBasicConfig struct {
// Conflicts with NoInfra=true.
// Optional.
SharedNamespaces []string `json:"shared_namespaces,omitempty"`
+ // PodCreateCommand is the command used to create this pod.
+ // This will be shown in the output of Inspect() on the pod, and may
+ // also be used by some tools that wish to recreate the pod
+ // (e.g. `podman generate systemd --new`).
+ // Optional.
+ PodCreateCommand []string `json:"pod_create_command,omitempty"`
}
// PodNetworkConfig contains networking configuration for a pod.
diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go
index b4e10fa87..16d4b7c8c 100644
--- a/pkg/specgen/specgen.go
+++ b/pkg/specgen/specgen.go
@@ -135,6 +135,13 @@ type ContainerBasicConfig struct {
// Remove indicates if the container should be removed once it has been started
// and exits
Remove bool `json:"remove,omitempty"`
+ // ContainerCreateCommand is the command that was used to create this
+ // container.
+ // This will be shown in the output of Inspect() on the container, and
+ // may also be used by some tools that wish to recreate the container
+ // (e.g. `podman generate systemd --new`).
+ // Optional.
+ ContainerCreateCommand []string `json:"containerCreateCommand,omitempty"`
// PreserveFDs is a number of additional file descriptors (in addition
// to 0, 1, 2) that will be passed to the executed process. The total FDs
// passed will be 3 + PreserveFDs.
diff --git a/pkg/varlinkapi/create.go b/pkg/varlinkapi/create.go
index 5c5f075f7..ac93939d9 100644
--- a/pkg/varlinkapi/create.go
+++ b/pkg/varlinkapi/create.go
@@ -915,10 +915,6 @@ func CreateContainerFromCreateConfig(ctx context.Context, r *libpod.Runtime, cre
return nil, err
}
- // Set the CreateCommand explicitly. Some (future) consumers of libpod
- // might not want to set it.
- options = append(options, libpod.WithCreateCommand())
-
ctr, err := r.NewContainer(ctx, runtimeSpec, options...)
if err != nil {
return nil, err
diff --git a/test/e2e/exec_test.go b/test/e2e/exec_test.go
index 4f744e401..0e60c4a7d 100644
--- a/test/e2e/exec_test.go
+++ b/test/e2e/exec_test.go
@@ -79,7 +79,6 @@ var _ = Describe("Podman exec", func() {
})
It("podman exec environment test", func() {
- Skip(v2remotefail)
setup := podmanTest.RunTopContainer("test1")
setup.WaitWithDefaultTimeout()
Expect(setup.ExitCode()).To(Equal(0))
@@ -99,7 +98,6 @@ var _ = Describe("Podman exec", func() {
It("podman exec os.Setenv env", func() {
// remote doesn't properly interpret os.Setenv
- SkipIfRemote()
setup := podmanTest.RunTopContainer("test1")
setup.WaitWithDefaultTimeout()
Expect(setup.ExitCode()).To(Equal(0))
@@ -159,7 +157,6 @@ var _ = Describe("Podman exec", func() {
})
It("podman exec with user only in container", func() {
- Skip(v2remotefail)
testUser := "test123"
setup := podmanTest.Podman([]string{"run", "--name", "test1", "-d", fedoraMinimal, "sleep", "60"})
setup.WaitWithDefaultTimeout()
@@ -176,7 +173,6 @@ var _ = Describe("Podman exec", func() {
})
It("podman exec with user from run", func() {
- Skip(v2remotefail)
testUser := "guest"
setup := podmanTest.Podman([]string{"run", "--user", testUser, "-d", ALPINE, "top"})
setup.WaitWithDefaultTimeout()
@@ -196,7 +192,6 @@ var _ = Describe("Podman exec", func() {
})
It("podman exec simple working directory test", func() {
- Skip(v2remotefail)
setup := podmanTest.RunTopContainer("test1")
setup.WaitWithDefaultTimeout()
Expect(setup.ExitCode()).To(Equal(0))
diff --git a/test/e2e/info_test.go b/test/e2e/info_test.go
index e38ace53f..8aa9712fd 100644
--- a/test/e2e/info_test.go
+++ b/test/e2e/info_test.go
@@ -11,6 +11,7 @@ import (
. "github.com/containers/libpod/v2/test/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/gexec"
)
var _ = Describe("Podman Info", func() {
@@ -35,11 +36,30 @@ var _ = Describe("Podman Info", func() {
processTestResult(f)
})
- It("podman info json output", func() {
- session := podmanTest.Podman([]string{"info", "--format=json"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
-
+ It("podman info --format json", func() {
+ tests := []struct {
+ input string
+ success bool
+ exitCode int
+ }{
+ {"json", true, 0},
+ {" json", true, 0},
+ {"json ", true, 0},
+ {" json ", true, 0},
+ {"{{json .}}", true, 0},
+ {"{{ json .}}", true, 0},
+ {"{{json . }}", true, 0},
+ {" {{ json . }} ", true, 0},
+ {"{{json }}", false, 125},
+ {"{{json .", false, 125},
+ {"json . }}", false, 0}, // Note: this does NOT fail but produces garbage
+ }
+ for _, tt := range tests {
+ session := podmanTest.Podman([]string{"info", "--format", tt.input})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(tt.exitCode))
+ Expect(session.IsJSONOutputValid()).To(Equal(tt.success))
+ }
})
It("podman info --format GO template", func() {
diff --git a/test/e2e/pod_inspect_test.go b/test/e2e/pod_inspect_test.go
index e2c2ac607..5e3634435 100644
--- a/test/e2e/pod_inspect_test.go
+++ b/test/e2e/pod_inspect_test.go
@@ -59,7 +59,6 @@ var _ = Describe("Podman pod inspect", func() {
})
It("podman pod inspect (CreateCommand)", func() {
- Skip(v2remotefail)
podName := "myTestPod"
createCommand := []string{"pod", "create", "--name", podName, "--hostname", "rudolph", "--share", "net"}
diff --git a/test/e2e/version_test.go b/test/e2e/version_test.go
index 775be6511..eb1d1b733 100644
--- a/test/e2e/version_test.go
+++ b/test/e2e/version_test.go
@@ -55,17 +55,29 @@ var _ = Describe("Podman version", func() {
})
It("podman version --format json", func() {
- session := podmanTest.Podman([]string{"version", "--format", "json"})
- session.WaitWithDefaultTimeout()
- Expect(session).Should(Exit(0))
- Expect(session.IsJSONOutputValid()).To(BeTrue())
- })
-
- It("podman version --format json", func() {
- session := podmanTest.Podman([]string{"version", "--format", "{{ json .}}"})
- session.WaitWithDefaultTimeout()
- Expect(session).Should(Exit(0))
- Expect(session.IsJSONOutputValid()).To(BeTrue())
+ tests := []struct {
+ input string
+ success bool
+ exitCode int
+ }{
+ {"json", true, 0},
+ {" json", true, 0},
+ {"json ", true, 0},
+ {" json ", true, 0},
+ {"{{json .}}", true, 0},
+ {"{{ json .}}", true, 0},
+ {"{{json . }}", true, 0},
+ {" {{ json . }} ", true, 0},
+ {"{{json }}", false, 125},
+ {"{{json .", false, 125},
+ {"json . }}", false, 0}, // Note: this does NOT fail but produces garbage
+ }
+ for _, tt := range tests {
+ session := podmanTest.Podman([]string{"version", "--format", tt.input})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(tt.exitCode))
+ Expect(session.IsJSONOutputValid()).To(Equal(tt.success))
+ }
})
It("podman version --format GO template", func() {
diff --git a/vendor/github.com/containers/storage/.cirrus.yml b/vendor/github.com/containers/storage/.cirrus.yml
index 15bf47baf..ce99cb0a5 100644
--- a/vendor/github.com/containers/storage/.cirrus.yml
+++ b/vendor/github.com/containers/storage/.cirrus.yml
@@ -19,12 +19,12 @@ env:
###
FEDORA_NAME: "fedora-32"
PRIOR_FEDORA_NAME: "fedora-31"
- UBUNTU_NAME: "ubuntu-19"
- PRIOR_UBUNTU_NAME: "ubuntu-18"
+ UBUNTU_NAME: "ubuntu-20"
+ PRIOR_UBUNTU_NAME: "ubuntu-19"
# GCE project where images live
IMAGE_PROJECT: "libpod-218412"
- _BUILT_IMAGE_SUFFIX: "libpod-6224667180531712" # From the packer output of 'build_vm_images_script'
+ _BUILT_IMAGE_SUFFIX: "libpod-6508632441356288"
FEDORA_CACHE_IMAGE_NAME: "${FEDORA_NAME}-${_BUILT_IMAGE_SUFFIX}"
PRIOR_FEDORA_CACHE_IMAGE_NAME: "${PRIOR_FEDORA_NAME}-${_BUILT_IMAGE_SUFFIX}"
UBUNTU_CACHE_IMAGE_NAME: "${UBUNTU_NAME}-${_BUILT_IMAGE_SUFFIX}"
@@ -104,7 +104,7 @@ lint_task:
env:
CIRRUS_WORKING_DIR: "/go/src/github.com/containers/storage"
container:
- image: golang:1.12
+ image: golang:1.13
modules_cache:
fingerprint_script: cat go.sum
folder: $GOPATH/pkg/mod
@@ -140,7 +140,7 @@ meta_task:
vendor_task:
container:
- image: golang:1.13
+ image: golang:1.14
modules_cache:
fingerprint_script: cat go.sum
folder: $GOPATH/pkg/mod
diff --git a/vendor/github.com/containers/storage/VERSION b/vendor/github.com/containers/storage/VERSION
index 769e37e15..3500250a4 100644
--- a/vendor/github.com/containers/storage/VERSION
+++ b/vendor/github.com/containers/storage/VERSION
@@ -1 +1 @@
-1.20.2
+1.21.0
diff --git a/vendor/github.com/containers/storage/drivers/devmapper/device_setup.go b/vendor/github.com/containers/storage/drivers/devmapper/device_setup.go
index 7553a93eb..5bfbb49e2 100644
--- a/vendor/github.com/containers/storage/drivers/devmapper/device_setup.go
+++ b/vendor/github.com/containers/storage/drivers/devmapper/device_setup.go
@@ -23,6 +23,7 @@ type directLVMConfig struct {
ThinpMetaPercent uint64
AutoExtendPercent uint64
AutoExtendThreshold uint64
+ MetaDataSize string
}
var (
@@ -121,15 +122,19 @@ func checkDevHasFS(dev string) error {
}
func verifyBlockDevice(dev string, force bool) error {
- realPath, err := filepath.Abs(dev)
+ absPath, err := filepath.Abs(dev)
if err != nil {
return errors.Errorf("unable to get absolute path for %s: %s", dev, err)
}
- if realPath, err = filepath.EvalSymlinks(realPath); err != nil {
+ realPath, err := filepath.EvalSymlinks(absPath)
+ if err != nil {
return errors.Errorf("failed to canonicalise path for %s: %s", dev, err)
}
- if err := checkDevAvailable(realPath); err != nil {
- return err
+ if err := checkDevAvailable(absPath); err != nil {
+ logrus.Infof("block device '%s' not available, checking '%s'", absPath, realPath)
+ if err := checkDevAvailable(realPath); err != nil {
+ return errors.Errorf("neither '%s' nor '%s' are in the output of lvmdiskscan, can't use device.", absPath, realPath)
+ }
}
if err := checkDevInVG(realPath); err != nil {
return err
@@ -205,8 +210,11 @@ func setupDirectLVM(cfg directLVMConfig) error {
if cfg.ThinpMetaPercent == 0 {
cfg.ThinpMetaPercent = 1
}
+ if cfg.MetaDataSize == "" {
+ cfg.MetaDataSize = "128k"
+ }
- out, err := exec.Command("pvcreate", "-f", cfg.Device).CombinedOutput()
+ out, err := exec.Command("pvcreate", "--metadatasize", cfg.MetaDataSize, "-f", cfg.Device).CombinedOutput()
if err != nil {
return errors.Wrap(err, string(out))
}
diff --git a/vendor/github.com/containers/storage/drivers/devmapper/deviceset.go b/vendor/github.com/containers/storage/drivers/devmapper/deviceset.go
index ff6e297f4..b7a95bfc2 100644
--- a/vendor/github.com/containers/storage/drivers/devmapper/deviceset.go
+++ b/vendor/github.com/containers/storage/drivers/devmapper/deviceset.go
@@ -101,6 +101,7 @@ type DeviceSet struct {
// Options
dataLoopbackSize int64
+ metaDataSize string
metaDataLoopbackSize int64
baseFsSize uint64
filesystem string
@@ -2708,6 +2709,8 @@ func NewDeviceSet(root string, doInit bool, options []string, uidMaps, gidMaps [
devices.mountOptions = joinMountOptions(devices.mountOptions, val)
case "dm.metadatadev":
devices.metadataDevice = val
+ case "dm.metadata_size":
+ devices.metaDataSize = val
case "dm.datadev":
devices.dataDevice = val
case "dm.thinpooldev":
@@ -2743,6 +2746,8 @@ func NewDeviceSet(root string, doInit bool, options []string, uidMaps, gidMaps [
return nil, err
}
+ case "dm.metaDataSize":
+ lvmSetupConfig.MetaDataSize = val
case "dm.min_free_space":
if !strings.HasSuffix(val, "%") {
return nil, fmt.Errorf("devmapper: Option dm.min_free_space requires %% suffix")
diff --git a/vendor/github.com/containers/storage/go.mod b/vendor/github.com/containers/storage/go.mod
index 01ac1827b..36101194e 100644
--- a/vendor/github.com/containers/storage/go.mod
+++ b/vendor/github.com/containers/storage/go.mod
@@ -5,24 +5,24 @@ require (
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5
github.com/Microsoft/hcsshim v0.8.9
github.com/docker/go-units v0.4.0
- github.com/hashicorp/go-multierror v1.0.0
- github.com/klauspost/compress v1.10.7
+ github.com/hashicorp/go-multierror v1.1.0
+ github.com/klauspost/compress v1.10.10
github.com/klauspost/pgzip v1.2.4
github.com/mattn/go-shellwords v1.0.10
github.com/mistifyio/go-zfs v2.1.1+incompatible
github.com/opencontainers/go-digest v1.0.0
- github.com/opencontainers/runc v1.0.0-rc90
- github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700
- github.com/opencontainers/selinux v1.5.2
+ github.com/opencontainers/runc v1.0.0-rc91
+ github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2
+ github.com/opencontainers/selinux v1.6.0
github.com/pkg/errors v0.9.1
github.com/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7
github.com/sirupsen/logrus v1.6.0
- github.com/stretchr/testify v1.6.0
+ github.com/stretchr/testify v1.6.1
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2
github.com/tchap/go-patricia v2.3.0+incompatible
github.com/vbatts/tar-split v0.11.1
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9
- golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9
+ golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775
gotest.tools v2.2.0+incompatible
)
diff --git a/vendor/github.com/containers/storage/go.sum b/vendor/github.com/containers/storage/go.sum
index 2b5a279c6..d9b0d6396 100644
--- a/vendor/github.com/containers/storage/go.sum
+++ b/vendor/github.com/containers/storage/go.sum
@@ -5,11 +5,17 @@ github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6tr
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
github.com/Microsoft/hcsshim v0.8.9 h1:VrfodqvztU8YSOvygU+DN1BGaSGxmrNfqOv5oOuX2Bk=
github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8=
+github.com/checkpoint-restore/go-criu/v4 v4.0.2 h1:jt+rnBIhFtPw0fhtpYGcUOilh4aO9Hj7r+YLEtf30uA=
+github.com/checkpoint-restore/go-criu/v4 v4.0.2/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
+github.com/cilium/ebpf v0.0.0-20200507155900-a9f01edf17e3 h1:qcqzLJa2xCo9sgdCzpT/SJSYxROTEstuhf7ZBHMirms=
+github.com/cilium/ebpf v0.0.0-20200507155900-a9f01edf17e3/go.mod h1:XT+cAw5wfvsodedcijoh1l9cf7v1x9FlFB/3VmF/O8s=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s=
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1 h1:uict5mhHFTzKLUCufdSLym7z/J0CbBJT59lYbP9wtbg=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
+github.com/containerd/console v1.0.0 h1:fU3UuQapBs+zLJu82NhR11Rif1ny2zfMMAyPJzSN5tQ=
+github.com/containerd/console v1.0.0/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
@@ -18,6 +24,12 @@ github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDG
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd/v22 v22.0.0 h1:XJIw/+VlJ+87J+doOxznsAWIdmWuViOVhkQamW5YV28=
+github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg=
+github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -25,6 +37,8 @@ github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68FptL43tDKIq8FladmaTs3Xs7Z8=
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
+github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME=
+github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
@@ -34,20 +48,22 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
-github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
+github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.10.7 h1:7rix8v8GpI3ZBb0nSozFRgbtXKv+hOe+qfEpZqybrAg=
-github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.10.10 h1:a/y8CglcM7gLGYmlbP/stPE5sR3hbhFRUjCBfd/0B3I=
+github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/pgzip v1.2.4 h1:TQ7CNpYKovDOmqzRHKxJh0BeaBI7UdQZYc6p7pMQh1A=
github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -62,16 +78,23 @@ github.com/mattn/go-shellwords v1.0.10 h1:Y7Xqm8piKOO3v10Thp7Z36h4FYFjt5xB//6XvO
github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/mistifyio/go-zfs v2.1.1+incompatible h1:gAMO1HM9xBRONLHHYnu5iFsOJUiJdNZo6oqSENd4eW8=
github.com/mistifyio/go-zfs v2.1.1+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
+github.com/moby/sys/mountinfo v0.1.3 h1:KIrhRO14+AkwKvG/g2yIpNMOUVZ02xNhOw8KY1WsLOI=
+github.com/moby/sys/mountinfo v0.1.3/go.mod h1:w2t2Avltqx8vE7gX5l+QiBKxODu2TX0+Syr3h52Tw4o=
+github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618 h1:7InQ7/zrOh6SlFjaXFubv0xX0HsuC9qJsdqm7bNQpYM=
+github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618/go.mod h1:x8F1gnqOkIEiO4rqoeEEEqQbo7HjGMTvyoq3gej4iT0=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/runc v1.0.0-rc90 h1:4+xo8mtWixbHoEm451+WJNUrq12o2/tDsyK9Vgc/NcA=
-github.com/opencontainers/runc v1.0.0-rc90/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v1.0.0-rc91 h1:Tp8LWs5G8rFpzTsbRjAtQkPVexhCu0bnANE5IfIhJ6g=
+github.com/opencontainers/runc v1.0.0-rc91/go.mod h1:3Sm6Dt7OT8z88EbdQqqcRN2oCT54jbi72tT/HqgflT8=
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700 h1:eNUVfm/RFLIi1G7flU5/ZRTHvd4kcVuzfRnL6OFlzCI=
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
-github.com/opencontainers/selinux v1.5.2 h1:F6DgIsjgBIcDksLW4D5RG9bXok6oqZ3nvMwj4ZoFu/Q=
-github.com/opencontainers/selinux v1.5.2/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
+github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2 h1:9mv9SC7GWmRWE0J/+oD8w3GsN2KYGKtg6uwLN7hfP5E=
+github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/selinux v1.5.1/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
+github.com/opencontainers/selinux v1.6.0 h1:+bIAS/Za3q5FTwWym4fTB0vObnfCf3G/NC7K6Jx62mY=
+github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -80,6 +103,12 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7 h1:gGBSHPOU7g8YjTbhwn+lvFm2VDEhhA+PwDIlstkgSxE=
github.com/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M=
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/seccomp/libseccomp-golang v0.9.1 h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo=
+github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
+github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
@@ -89,16 +118,24 @@ github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/stretchr/testify v1.6.0 h1:jlIyCplCJFULU/01vCkhKuTyc3OorI3bJFuw6obfgho=
-github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0TYG7HtkIgExQo+2RdLuwRft63jn2HWj8=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/tchap/go-patricia v2.3.0+incompatible h1:GkY4dP3cEfEASBPPkWd+AmjYxhmDkqO9/zg7R0lSQRs=
github.com/tchap/go-patricia v2.3.0+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5 h1:MCfT24H3f//U5+UCrZp1/riVO3B50BovxtDiNn0XKkk=
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
+github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/vbatts/tar-split v0.11.1 h1:0Odu65rhcZ3JZaPHxl7tCI3V/C/Q9Zf82UFravl02dE=
github.com/vbatts/tar-split v0.11.1/go.mod h1:LEuURwDEiWjRjwu46yU3KVGuUdVv/dcnpcEPSzR8z6g=
+github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
+github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
+github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k=
+github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
+github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243 h1:R43TdZy32XXSXjJn7M/HhALJ9imq6ztLnChfYJpVDnM=
+github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -124,10 +161,14 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 h1:1/DFK4b7JH8DmkqhUk48onnSfrPzImPoVxuomtbT2nk=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775 h1:TC0v2RSO1u2kn1ZugjrFXkRZAEaqMN/RW+OTZkBzmLE=
+golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -137,6 +178,8 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
diff --git a/vendor/github.com/containers/storage/pkg/archive/archive.go b/vendor/github.com/containers/storage/pkg/archive/archive.go
index bf819a801..863465456 100644
--- a/vendor/github.com/containers/storage/pkg/archive/archive.go
+++ b/vendor/github.com/containers/storage/pkg/archive/archive.go
@@ -390,16 +390,18 @@ func fillGo18FileTypeBits(mode int64, fi os.FileInfo) int64 {
return mode
}
-// ReadSecurityXattrToTarHeader reads security.capability xattr from filesystem
-// to a tar header
+// ReadSecurityXattrToTarHeader reads security.capability, security,image
+// xattrs from filesystem to a tar header
func ReadSecurityXattrToTarHeader(path string, hdr *tar.Header) error {
- capability, err := system.Lgetxattr(path, "security.capability")
- if err != nil && err != system.EOPNOTSUPP && err != system.ErrNotSupportedPlatform {
- return err
- }
- if capability != nil {
- hdr.Xattrs = make(map[string]string)
- hdr.Xattrs["security.capability"] = string(capability)
+ for _, xattr := range []string{"security.capability", "security.ima"} {
+ capability, err := system.Lgetxattr(path, xattr)
+ if err != nil && err != system.EOPNOTSUPP && err != system.ErrNotSupportedPlatform {
+ return errors.Wrapf(err, "failed to read %q attribute from %q", xattr, path)
+ }
+ if capability != nil {
+ hdr.Xattrs = make(map[string]string)
+ hdr.Xattrs[xattr] = string(capability)
+ }
}
return nil
}
diff --git a/vendor/github.com/containers/storage/pkg/config/config.go b/vendor/github.com/containers/storage/pkg/config/config.go
index 4a35997ea..c2fa2109e 100644
--- a/vendor/github.com/containers/storage/pkg/config/config.go
+++ b/vendor/github.com/containers/storage/pkg/config/config.go
@@ -39,6 +39,10 @@ type ThinpoolOptionsConfig struct {
// log_level sets the log level of devicemapper.
LogLevel string `toml:"log_level"`
+ // MetadataSize specifies the size of the metadata for the thinpool
+ // It will be used with the `pvcreate --metadata` option.
+ MetadataSize string `toml:"metadatasize"`
+
// MinFreeSpace specifies the min free space percent in a thin pool
// require for new device creation to
MinFreeSpace string `toml:"min_free_space"`
@@ -218,6 +222,9 @@ func GetGraphDriverOptions(driverName string, options OptionsConfig) []string {
if options.Thinpool.LogLevel != "" {
doptions = append(doptions, fmt.Sprintf("dm.libdm_log_level=%s", options.Thinpool.LogLevel))
}
+ if options.Thinpool.MetadataSize != "" {
+ doptions = append(doptions, fmt.Sprintf("dm.metadata_size=%s", options.Thinpool.MetadataSize))
+ }
if options.Thinpool.MinFreeSpace != "" {
doptions = append(doptions, fmt.Sprintf("dm.min_free_space=%s", options.Thinpool.MinFreeSpace))
}
diff --git a/vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go b/vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go
index 6429d6254..35104b2fd 100644
--- a/vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go
+++ b/vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go
@@ -35,9 +35,9 @@ type lockfile struct {
// necessary.
func openLock(path string, ro bool) (int, error) {
if ro {
- return unix.Open(path, os.O_RDONLY, 0)
+ return unix.Open(path, os.O_RDONLY|unix.O_CLOEXEC, 0)
}
- return unix.Open(path, os.O_RDWR|os.O_CREATE, unix.S_IRUSR|unix.S_IWUSR)
+ return unix.Open(path, os.O_RDWR|unix.O_CLOEXEC|os.O_CREATE, unix.S_IRUSR|unix.S_IWUSR|unix.S_IRGRP|unix.S_IROTH)
}
// createLockerForPath returns a Locker object, possibly (depending on the platform)
@@ -106,7 +106,6 @@ func (l *lockfile) lock(lType int16, recursive bool) {
if err != nil {
panic(fmt.Sprintf("error opening %q: %v", l.file, err))
}
- unix.CloseOnExec(fd)
l.fd = uintptr(fd)
// Optimization: only use the (expensive) fcntl syscall when
diff --git a/vendor/github.com/containers/storage/storage.conf b/vendor/github.com/containers/storage/storage.conf
index 19909e9c6..a8ec9d98b 100644
--- a/vendor/github.com/containers/storage/storage.conf
+++ b/vendor/github.com/containers/storage/storage.conf
@@ -67,7 +67,7 @@ additionalimagestores = [
# squashed down to the default uid in the container. These images will have no
# separation between the users in the container. Only supported for the overlay
# and vfs drivers.
-#ignore_chown_errors = false
+#ignore_chown_errors = "false"
# Path to an helper program to use for mounting the file system instead of mounting it
# directly.
@@ -132,6 +132,10 @@ mountopt = "nodev"
# device.
# mkfsarg = ""
+# metadata_size is used to set the `pvcreate --metadatasize` options when
+# creating thin devices. Default is 128k
+# metadata_size = ""
+
# Size is used to set a maximum size of the container image.
# size = ""
diff --git a/vendor/github.com/containers/storage/store.go b/vendor/github.com/containers/storage/store.go
index 263f4edb2..56e1e545b 100644
--- a/vendor/github.com/containers/storage/store.go
+++ b/vendor/github.com/containers/storage/store.go
@@ -265,6 +265,15 @@ type Store interface {
// Wipe removes all known layers, images, and containers.
Wipe() error
+ // MountImage mounts an image to temp directory and returns the mount point.
+ // MountImage allows caller to mount an image. Images will always
+ // be mounted read/only
+ MountImage(id string, mountOptions []string, mountLabel string) (string, error)
+
+ // Unmount attempts to unmount an image, given an ID.
+ // Returns whether or not the layer is still mounted.
+ UnmountImage(id string, force bool) (bool, error)
+
// Mount attempts to mount a layer, image, or container for access, and
// returns the pathname if it succeeds.
// Note if the mountLabel == "", the default label for the container
@@ -346,6 +355,9 @@ type Store interface {
// Names returns the list of names for a layer, image, or container.
Names(id string) ([]string, error)
+ // Free removes the store from the list of stores
+ Free()
+
// SetNames changes the list of names for a layer, image, or container.
// Duplicate names are removed from the list automatically.
SetNames(id string, names []string) error
@@ -2591,25 +2603,11 @@ func (s *store) Version() ([][2]string, error) {
return [][2]string{}, nil
}
-func (s *store) Mount(id, mountLabel string) (string, error) {
- container, err := s.Container(id)
- var (
- uidMap, gidMap []idtools.IDMap
- mountOpts []string
- )
- if err == nil {
- uidMap, gidMap = container.UIDMap, container.GIDMap
- id = container.LayerID
- mountOpts = container.MountOpts()
- }
+func (s *store) mount(id string, options drivers.MountOpts) (string, error) {
rlstore, err := s.LayerStore()
if err != nil {
return "", err
}
-
- s.graphLock.Lock()
- defer s.graphLock.Unlock()
-
rlstore.Lock()
defer rlstore.Unlock()
if modified, err := rlstore.Modified(); modified || err != nil {
@@ -2630,17 +2628,49 @@ func (s *store) Mount(id, mountLabel string) (string, error) {
}
if rlstore.Exists(id) {
- options := drivers.MountOpts{
- MountLabel: mountLabel,
- UidMaps: uidMap,
- GidMaps: gidMap,
- Options: mountOpts,
- }
return rlstore.Mount(id, options)
}
return "", ErrLayerUnknown
}
+func (s *store) MountImage(id string, mountOpts []string, mountLabel string) (string, error) {
+ // Append ReadOnly option to mountOptions
+ img, err := s.Image(id)
+ if err != nil {
+ return "", err
+ }
+
+ if err := validateMountOptions(mountOpts); err != nil {
+ return "", err
+ }
+ options := drivers.MountOpts{
+ MountLabel: mountLabel,
+ Options: append(mountOpts, "ro"),
+ }
+
+ return s.mount(img.TopLayer, options)
+}
+
+func (s *store) Mount(id, mountLabel string) (string, error) {
+ container, err := s.Container(id)
+ var (
+ uidMap, gidMap []idtools.IDMap
+ mountOpts []string
+ )
+ if err == nil {
+ uidMap, gidMap = container.UIDMap, container.GIDMap
+ id = container.LayerID
+ mountOpts = container.MountOpts()
+ }
+ options := drivers.MountOpts{
+ MountLabel: mountLabel,
+ UidMaps: uidMap,
+ GidMaps: gidMap,
+ Options: mountOpts,
+ }
+ return s.mount(id, options)
+}
+
func (s *store) Mounted(id string) (int, error) {
if layerID, err := s.ContainerLayerID(id); err == nil {
id = layerID
@@ -2660,6 +2690,14 @@ func (s *store) Mounted(id string) (int, error) {
return rlstore.Mounted(id)
}
+func (s *store) UnmountImage(id string, force bool) (bool, error) {
+ img, err := s.Image(id)
+ if err != nil {
+ return false, err
+ }
+ return s.Unmount(img.TopLayer, force)
+}
+
func (s *store) Unmount(id string, force bool) (bool, error) {
if layerID, err := s.ContainerLayerID(id); err == nil {
id = layerID
@@ -3601,3 +3639,13 @@ func GetMountOptions(driver string, graphDriverOptions []string) ([]string, erro
}
return nil, nil
}
+
+// Free removes the store from the list of stores
+func (s *store) Free() {
+ for i := 0; i < len(stores); i++ {
+ if stores[i] == s {
+ stores = append(stores[:i], stores[i+1:]...)
+ return
+ }
+ }
+}
diff --git a/vendor/github.com/containers/storage/utils.go b/vendor/github.com/containers/storage/utils.go
index 235bf6d41..101f5cc7a 100644
--- a/vendor/github.com/containers/storage/utils.go
+++ b/vendor/github.com/containers/storage/utils.go
@@ -2,6 +2,7 @@ package storage
import (
"fmt"
+ "io/ioutil"
"os"
"os/exec"
"os/user"
@@ -82,31 +83,92 @@ func GetRootlessRuntimeDir(rootlessUID int) (string, error) {
return path, nil
}
-func getRootlessRuntimeDir(rootlessUID int) (string, error) {
- runtimeDir, err := homedir.GetRuntimeDir()
+type rootlessRuntimeDirEnvironment interface {
+ getProcCommandFile() string
+ getRunUserDir() string
+ getTmpPerUserDir() string
+
+ homeDirGetRuntimeDir() (string, error)
+ systemLstat(string) (*system.StatT, error)
+ homedirGet() string
+}
+
+type rootlessRuntimeDirEnvironmentImplementation struct {
+ procCommandFile string
+ runUserDir string
+ tmpPerUserDir string
+}
+
+func (env rootlessRuntimeDirEnvironmentImplementation) getProcCommandFile() string {
+ return env.procCommandFile
+}
+func (env rootlessRuntimeDirEnvironmentImplementation) getRunUserDir() string {
+ return env.runUserDir
+}
+func (env rootlessRuntimeDirEnvironmentImplementation) getTmpPerUserDir() string {
+ return env.tmpPerUserDir
+}
+func (rootlessRuntimeDirEnvironmentImplementation) homeDirGetRuntimeDir() (string, error) {
+ return homedir.GetRuntimeDir()
+}
+func (rootlessRuntimeDirEnvironmentImplementation) systemLstat(path string) (*system.StatT, error) {
+ return system.Lstat(path)
+}
+func (rootlessRuntimeDirEnvironmentImplementation) homedirGet() string {
+ return homedir.Get()
+}
+
+func isRootlessRuntimeDirOwner(dir string, env rootlessRuntimeDirEnvironment) bool {
+ st, err := env.systemLstat(dir)
+ return err == nil && int(st.UID()) == os.Getuid() && st.Mode()&0700 == 0700 && st.Mode()&0066 == 0000
+}
+
+// getRootlessRuntimeDirIsolated is an internal implementation detail of getRootlessRuntimeDir to allow testing.
+// Everyone but the tests this is intended for should only call getRootlessRuntimeDir, never this function.
+func getRootlessRuntimeDirIsolated(env rootlessRuntimeDirEnvironment) (string, error) {
+ runtimeDir, err := env.homeDirGetRuntimeDir()
if err == nil {
return runtimeDir, nil
}
- tmpDir := fmt.Sprintf("/run/user/%d", rootlessUID)
- st, err := system.Stat(tmpDir)
- if err == nil && int(st.UID()) == os.Getuid() && st.Mode()&0700 == 0700 && st.Mode()&0066 == 0000 {
- return tmpDir, nil
+
+ initCommand, err := ioutil.ReadFile(env.getProcCommandFile())
+ if err != nil || string(initCommand) == "systemd" {
+ runUserDir := env.getRunUserDir()
+ if isRootlessRuntimeDirOwner(runUserDir, env) {
+ return runUserDir, nil
+ }
}
- tmpDir = fmt.Sprintf("%s/%d", os.TempDir(), rootlessUID)
- if err := os.MkdirAll(tmpDir, 0700); err != nil {
- logrus.Errorf("failed to create %s: %v", tmpDir, err)
- } else {
- return tmpDir, nil
+
+ tmpPerUserDir := env.getTmpPerUserDir()
+ if _, err := env.systemLstat(tmpPerUserDir); os.IsNotExist(err) {
+ if err := os.Mkdir(tmpPerUserDir, 0700); err != nil {
+ logrus.Errorf("failed to create temp directory for user: %v", err)
+ } else {
+ return tmpPerUserDir, nil
+ }
+ } else if isRootlessRuntimeDirOwner(tmpPerUserDir, env) {
+ return tmpPerUserDir, nil
}
- home := homedir.Get()
- if home == "" {
- return "", errors.Wrapf(err, "neither XDG_RUNTIME_DIR nor HOME was set non-empty")
+
+ homeDir := env.homedirGet()
+ if homeDir == "" {
+ return "", errors.New("neither XDG_RUNTIME_DIR not temp dir nor HOME was set non-empty")
}
- resolvedHome, err := filepath.EvalSymlinks(home)
+ resolvedHomeDir, err := filepath.EvalSymlinks(homeDir)
if err != nil {
- return "", errors.Wrapf(err, "cannot resolve %s", home)
+ return "", errors.Wrapf(err, "cannot resolve %s", homeDir)
}
- return filepath.Join(resolvedHome, "rundir"), nil
+ return filepath.Join(resolvedHomeDir, "rundir"), nil
+}
+
+func getRootlessRuntimeDir(rootlessUID int) (string, error) {
+ return getRootlessRuntimeDirIsolated(
+ rootlessRuntimeDirEnvironmentImplementation{
+ "/proc/1/comm",
+ fmt.Sprintf("/run/user/%d", rootlessUID),
+ fmt.Sprintf("%s/containers-user-%d", os.TempDir(), rootlessUID),
+ },
+ )
}
// getRootlessDirInfo returns the parent path of where the storage for containers and
@@ -248,3 +310,18 @@ func validRootlessStoragePathFormat(path string) error {
}
return nil
}
+
+func validateMountOptions(mountOptions []string) error {
+ var Empty struct{}
+ // Add invalid options for ImageMount() here.
+ invalidOptions := map[string]struct{}{
+ "rw": Empty,
+ }
+
+ for _, opt := range mountOptions {
+ if _, ok := invalidOptions[opt]; ok {
+ return fmt.Errorf(" %q option not supported", opt)
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/hashicorp/go-multierror/.travis.yml b/vendor/github.com/hashicorp/go-multierror/.travis.yml
index 304a83595..24b80388f 100644
--- a/vendor/github.com/hashicorp/go-multierror/.travis.yml
+++ b/vendor/github.com/hashicorp/go-multierror/.travis.yml
@@ -9,4 +9,4 @@ branches:
only:
- master
-script: make test testrace
+script: env GO111MODULE=on make test testrace
diff --git a/vendor/github.com/hashicorp/go-multierror/README.md b/vendor/github.com/hashicorp/go-multierror/README.md
index ead5830f7..e92fa614c 100644
--- a/vendor/github.com/hashicorp/go-multierror/README.md
+++ b/vendor/github.com/hashicorp/go-multierror/README.md
@@ -14,9 +14,10 @@ be a list of errors. If the caller knows this, they can unwrap the
list and access the errors. If the caller doesn't know, the error
formats to a nice human-readable format.
-`go-multierror` implements the
-[errwrap](https://github.com/hashicorp/errwrap) interface so that it can
-be used with that library, as well.
+`go-multierror` is fully compatible with the Go standard library
+[errors](https://golang.org/pkg/errors/) package, including the
+functions `As`, `Is`, and `Unwrap`. This provides a standardized approach
+for introspecting on error values.
## Installation and Docs
@@ -81,6 +82,39 @@ if err := something(); err != nil {
}
```
+You can also use the standard [`errors.Unwrap`](https://golang.org/pkg/errors/#Unwrap)
+function. This will continue to unwrap into subsequent errors until none exist.
+
+**Extracting an error**
+
+The standard library [`errors.As`](https://golang.org/pkg/errors/#As)
+function can be used directly with a multierror to extract a specific error:
+
+```go
+// Assume err is a multierror value
+err := somefunc()
+
+// We want to know if "err" has a "RichErrorType" in it and extract it.
+var errRich RichErrorType
+if errors.As(err, &errRich) {
+ // It has it, and now errRich is populated.
+}
+```
+
+**Checking for an exact error value**
+
+Some errors are returned as exact errors such as the [`ErrNotExist`](https://golang.org/pkg/os/#pkg-variables)
+error in the `os` package. You can check if this error is present by using
+the standard [`errors.Is`](https://golang.org/pkg/errors/#Is) function.
+
+```go
+// Assume err is a multierror value
+err := somefunc()
+if errors.Is(err, os.ErrNotExist) {
+ // err contains os.ErrNotExist
+}
+```
+
**Returning a multierror only if there are errors**
If you build a `multierror.Error`, you can use the `ErrorOrNil` function
diff --git a/vendor/github.com/hashicorp/go-multierror/go.mod b/vendor/github.com/hashicorp/go-multierror/go.mod
index 2534331d5..0afe8e6f9 100644
--- a/vendor/github.com/hashicorp/go-multierror/go.mod
+++ b/vendor/github.com/hashicorp/go-multierror/go.mod
@@ -1,3 +1,5 @@
module github.com/hashicorp/go-multierror
+go 1.14
+
require github.com/hashicorp/errwrap v1.0.0
diff --git a/vendor/github.com/hashicorp/go-multierror/go.sum b/vendor/github.com/hashicorp/go-multierror/go.sum
index 85b1f8ff3..e8238e9ec 100644
--- a/vendor/github.com/hashicorp/go-multierror/go.sum
+++ b/vendor/github.com/hashicorp/go-multierror/go.sum
@@ -1,4 +1,2 @@
-github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce h1:prjrVgOk2Yg6w+PflHoszQNLTUh4kaByUcEWM/9uin4=
-github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
diff --git a/vendor/github.com/hashicorp/go-multierror/group.go b/vendor/github.com/hashicorp/go-multierror/group.go
new file mode 100644
index 000000000..9c29efb7f
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-multierror/group.go
@@ -0,0 +1,38 @@
+package multierror
+
+import "sync"
+
+// Group is a collection of goroutines which return errors that need to be
+// coalesced.
+type Group struct {
+ mutex sync.Mutex
+ err *Error
+ wg sync.WaitGroup
+}
+
+// Go calls the given function in a new goroutine.
+//
+// If the function returns an error it is added to the group multierror which
+// is returned by Wait.
+func (g *Group) Go(f func() error) {
+ g.wg.Add(1)
+
+ go func() {
+ defer g.wg.Done()
+
+ if err := f(); err != nil {
+ g.mutex.Lock()
+ g.err = Append(g.err, err)
+ g.mutex.Unlock()
+ }
+ }()
+}
+
+// Wait blocks until all function calls from the Go method have returned, then
+// returns the multierror.
+func (g *Group) Wait() *Error {
+ g.wg.Wait()
+ g.mutex.Lock()
+ defer g.mutex.Unlock()
+ return g.err
+}
diff --git a/vendor/github.com/hashicorp/go-multierror/multierror.go b/vendor/github.com/hashicorp/go-multierror/multierror.go
index 89b1422d1..d05dd9269 100644
--- a/vendor/github.com/hashicorp/go-multierror/multierror.go
+++ b/vendor/github.com/hashicorp/go-multierror/multierror.go
@@ -1,6 +1,7 @@
package multierror
import (
+ "errors"
"fmt"
)
@@ -49,3 +50,69 @@ func (e *Error) GoString() string {
func (e *Error) WrappedErrors() []error {
return e.Errors
}
+
+// Unwrap returns an error from Error (or nil if there are no errors).
+// This error returned will further support Unwrap to get the next error,
+// etc. The order will match the order of Errors in the multierror.Error
+// at the time of calling.
+//
+// The resulting error supports errors.As/Is/Unwrap so you can continue
+// to use the stdlib errors package to introspect further.
+//
+// This will perform a shallow copy of the errors slice. Any errors appended
+// to this error after calling Unwrap will not be available until a new
+// Unwrap is called on the multierror.Error.
+func (e *Error) Unwrap() error {
+ // If we have no errors then we do nothing
+ if e == nil || len(e.Errors) == 0 {
+ return nil
+ }
+
+ // If we have exactly one error, we can just return that directly.
+ if len(e.Errors) == 1 {
+ return e.Errors[0]
+ }
+
+ // Shallow copy the slice
+ errs := make([]error, len(e.Errors))
+ copy(errs, e.Errors)
+ return chain(errs)
+}
+
+// chain implements the interfaces necessary for errors.Is/As/Unwrap to
+// work in a deterministic way with multierror. A chain tracks a list of
+// errors while accounting for the current represented error. This lets
+// Is/As be meaningful.
+//
+// Unwrap returns the next error. In the cleanest form, Unwrap would return
+// the wrapped error here but we can't do that if we want to properly
+// get access to all the errors. Instead, users are recommended to use
+// Is/As to get the correct error type out.
+//
+// Precondition: []error is non-empty (len > 0)
+type chain []error
+
+// Error implements the error interface
+func (e chain) Error() string {
+ return e[0].Error()
+}
+
+// Unwrap implements errors.Unwrap by returning the next error in the
+// chain or nil if there are no more errors.
+func (e chain) Unwrap() error {
+ if len(e) == 1 {
+ return nil
+ }
+
+ return e[1:]
+}
+
+// As implements errors.As by attempting to map to the current value.
+func (e chain) As(target interface{}) bool {
+ return errors.As(e[0], target)
+}
+
+// Is implements errors.Is by comparing the current value directly.
+func (e chain) Is(target error) bool {
+ return errors.Is(e[0], target)
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/README.md b/vendor/github.com/klauspost/compress/zstd/README.md
index f2a80b5d0..ac3640dc9 100644
--- a/vendor/github.com/klauspost/compress/zstd/README.md
+++ b/vendor/github.com/klauspost/compress/zstd/README.md
@@ -5,11 +5,9 @@ It offers a very wide range of compression / speed trade-off, while being backed
A high performance compression algorithm is implemented. For now focused on speed.
This package provides [compression](#Compressor) to and [decompression](#Decompressor) of Zstandard content.
-Note that custom dictionaries are not supported yet, so if your code relies on that,
-you cannot use the package as-is.
+Note that custom dictionaries are only supported for decompression.
This package is pure Go and without use of "unsafe".
-If a significant speedup can be achieved using "unsafe", it may be added as an option later.
The `zstd` package is provided as open source software using a Go standard license.
@@ -142,80 +140,96 @@ Using the Encoder for both a stream and individual blocks concurrently is safe.
I have collected some speed examples to compare speed and compression against other compressors.
* `file` is the input file.
-* `out` is the compressor used. `zskp` is this package. `gzstd` is gzip standard library. `zstd` is the Datadog cgo library.
+* `out` is the compressor used. `zskp` is this package. `zstd` is the Datadog cgo library. `gzstd/gzkp` is gzip standard and this library.
* `level` is the compression level used. For `zskp` level 1 is "fastest", level 2 is "default".
* `insize`/`outsize` is the input/output size.
* `millis` is the number of milliseconds used for compression.
* `mb/s` is megabytes (2^20 bytes) per second.
```
-The test data for the Large Text Compression Benchmark is the first
-10^9 bytes of the English Wikipedia dump on Mar. 3, 2006.
-http://mattmahoney.net/dc/textdata.html
-
-file out level insize outsize millis mb/s
-enwik9 zskp 1 1000000000 343833033 5840 163.30
-enwik9 zskp 2 1000000000 317822183 8449 112.87
-enwik9 gzstd 1 1000000000 382578136 13627 69.98
-enwik9 gzstd 3 1000000000 349139651 22344 42.68
-enwik9 zstd 1 1000000000 357416379 4838 197.12
-enwik9 zstd 3 1000000000 313734522 7556 126.21
+Silesia Corpus:
+http://sun.aei.polsl.pl/~sdeor/corpus/silesia.zip
-GOB stream of binary data. Highly compressible.
-https://files.klauspost.com/compress/gob-stream.7z
+This package:
+file out level insize outsize millis mb/s
+silesia.tar zskp 1 211947520 73101992 643 313.87
+silesia.tar zskp 2 211947520 67504318 969 208.38
+silesia.tar zskp 3 211947520 65177448 1899 106.44
-file out level insize outsize millis mb/s
-gob-stream zskp 1 1911399616 234981983 5100 357.42
-gob-stream zskp 2 1911399616 208674003 6698 272.15
-gob-stream gzstd 1 1911399616 357382641 14727 123.78
-gob-stream gzstd 3 1911399616 327835097 17005 107.19
-gob-stream zstd 1 1911399616 250787165 4075 447.22
-gob-stream zstd 3 1911399616 208191888 5511 330.77
-
-Highly compressible JSON file. Similar to logs in a lot of ways.
-https://files.klauspost.com/compress/adresser.001.gz
-
-file out level insize outsize millis mb/s
-adresser.001 zskp 1 1073741824 18510122 1477 692.83
-adresser.001 zskp 2 1073741824 19831697 1705 600.59
-adresser.001 gzstd 1 1073741824 47755503 3079 332.47
-adresser.001 gzstd 3 1073741824 40052381 3051 335.63
-adresser.001 zstd 1 1073741824 16135896 994 1030.18
-adresser.001 zstd 3 1073741824 17794465 905 1131.49
+cgo zstd:
+silesia.tar zstd 1 211947520 73605392 543 371.56
+silesia.tar zstd 3 211947520 66793289 864 233.68
+silesia.tar zstd 6 211947520 62916450 1913 105.66
-VM Image, Linux mint with a few installed applications:
-https://files.klauspost.com/compress/rawstudio-mint14.7z
+gzip, stdlib/this package:
+silesia.tar gzstd 1 211947520 80007735 1654 122.21
+silesia.tar gzkp 1 211947520 80369488 1168 173.06
-file out level insize outsize millis mb/s
-rawstudio-mint14.tar zskp 1 8558382592 3648168838 33398 244.38
-rawstudio-mint14.tar zskp 2 8558382592 3376721436 50962 160.16
-rawstudio-mint14.tar gzstd 1 8558382592 3926257486 84712 96.35
-rawstudio-mint14.tar gzstd 3 8558382592 3740711978 176344 46.28
-rawstudio-mint14.tar zstd 1 8558382592 3607859742 27903 292.51
-rawstudio-mint14.tar zstd 3 8558382592 3341710879 46700 174.77
+GOB stream of binary data. Highly compressible.
+https://files.klauspost.com/compress/gob-stream.7z
+file out level insize outsize millis mb/s
+gob-stream zskp 1 1911399616 235022249 3088 590.30
+gob-stream zskp 2 1911399616 205669791 3786 481.34
+gob-stream zskp 3 1911399616 185792019 9324 195.48
+gob-stream zstd 1 1911399616 249810424 2637 691.26
+gob-stream zstd 3 1911399616 208192146 3490 522.31
+gob-stream zstd 6 1911399616 193632038 6687 272.56
+gob-stream gzstd 1 1911399616 357382641 10251 177.82
+gob-stream gzkp 1 1911399616 362156523 5695 320.08
-The test data is designed to test archivers in realistic backup scenarios.
-http://mattmahoney.net/dc/10gb.html
+The test data for the Large Text Compression Benchmark is the first
+10^9 bytes of the English Wikipedia dump on Mar. 3, 2006.
+http://mattmahoney.net/dc/textdata.html
-file out level insize outsize millis mb/s
-10gb.tar zskp 1 10065157632 4883149814 45715 209.97
-10gb.tar zskp 2 10065157632 4638110010 60970 157.44
-10gb.tar gzstd 1 10065157632 5198296126 97769 98.18
-10gb.tar gzstd 3 10065157632 4932665487 313427 30.63
-10gb.tar zstd 1 10065157632 4940796535 40391 237.65
-10gb.tar zstd 3 10065157632 4638618579 52911 181.42
+file out level insize outsize millis mb/s
+enwik9 zskp 1 1000000000 343848582 3609 264.18
+enwik9 zskp 2 1000000000 317276632 5746 165.97
+enwik9 zskp 3 1000000000 294540704 11725 81.34
+enwik9 zstd 1 1000000000 358072021 3110 306.65
+enwik9 zstd 3 1000000000 313734672 4784 199.35
+enwik9 zstd 6 1000000000 295138875 10290 92.68
+enwik9 gzstd 1 1000000000 382578136 9604 99.30
+enwik9 gzkp 1 1000000000 383825945 6544 145.73
+
+Highly compressible JSON file.
+https://files.klauspost.com/compress/github-june-2days-2019.json.zst
+
+file out level insize outsize millis mb/s
+github-june-2days-2019.json zskp 1 6273951764 699045015 10620 563.40
+github-june-2days-2019.json zskp 2 6273951764 617881763 11687 511.96
+github-june-2days-2019.json zskp 3 6273951764 537511906 29252 204.54
+github-june-2days-2019.json zstd 1 6273951764 766284037 8450 708.00
+github-june-2days-2019.json zstd 3 6273951764 661889476 10927 547.57
+github-june-2days-2019.json zstd 6 6273951764 642756859 22996 260.18
+github-june-2days-2019.json gzstd 1 6273951764 1164400847 29948 199.79
+github-june-2days-2019.json gzkp 1 6273951764 1128755542 19236 311.03
-Silesia Corpus:
-http://sun.aei.polsl.pl/~sdeor/corpus/silesia.zip
+VM Image, Linux mint with a few installed applications:
+https://files.klauspost.com/compress/rawstudio-mint14.7z
-file out level insize outsize millis mb/s
-silesia.tar zskp 1 211947520 73025800 1108 182.26
-silesia.tar zskp 2 211947520 67674684 1599 126.41
-silesia.tar gzstd 1 211947520 80007735 2515 80.37
-silesia.tar gzstd 3 211947520 73133380 4259 47.45
-silesia.tar zstd 1 211947520 73513991 933 216.64
-silesia.tar zstd 3 211947520 66793301 1377 146.79
+file out level insize outsize millis mb/s
+rawstudio-mint14.tar zskp 1 8558382592 3667489370 20210 403.84
+rawstudio-mint14.tar zskp 2 8558382592 3364592300 31873 256.07
+rawstudio-mint14.tar zskp 3 8558382592 3224594213 71751 113.75
+rawstudio-mint14.tar zstd 1 8558382592 3609250104 17136 476.27
+rawstudio-mint14.tar zstd 3 8558382592 3341679997 29262 278.92
+rawstudio-mint14.tar zstd 6 8558382592 3235846406 77904 104.77
+rawstudio-mint14.tar gzstd 1 8558382592 3926257486 57722 141.40
+rawstudio-mint14.tar gzkp 1 8558382592 3970463184 41749 195.49
+
+CSV data:
+https://files.klauspost.com/compress/nyc-taxi-data-10M.csv.zst
+
+file out level insize outsize millis mb/s
+nyc-taxi-data-10M.csv zskp 1 3325605752 641339945 8925 355.35
+nyc-taxi-data-10M.csv zskp 2 3325605752 591748091 11268 281.44
+nyc-taxi-data-10M.csv zskp 3 3325605752 538490114 19880 159.53
+nyc-taxi-data-10M.csv zstd 1 3325605752 687399637 8233 385.18
+nyc-taxi-data-10M.csv zstd 3 3325605752 598514411 10065 315.07
+nyc-taxi-data-10M.csv zstd 6 3325605752 570522953 20038 158.27
+nyc-taxi-data-10M.csv gzstd 1 3325605752 928656485 23876 132.83
+nyc-taxi-data-10M.csv gzkp 1 3325605752 924718719 16388 193.53
```
### Converters
@@ -315,13 +329,13 @@ Data compressed with [dictionaries](https://github.com/facebook/zstd#the-case-fo
Dictionaries are added individually to Decoders.
Dictionaries are generated by the `zstd --train` command and contains an initial state for the decoder.
-To add a dictionary use the `RegisterDict(data)` with the dictionary data before starting any decompression.
+To add a dictionary use the `WithDecoderDicts(dicts ...[]byte)` option with the dictionary data.
+Several dictionaries can be added at once.
The dictionary will be used automatically for the data that specifies them.
-
A re-used Decoder will still contain the dictionaries registered.
-When registering a dictionary with the same ID it will override the existing.
+When registering multiple dictionaries with the same ID, the last one will be used.
### Allocation-less operation
@@ -364,36 +378,42 @@ These are some examples of performance compared to [datadog cgo library](https:/
The first two are streaming decodes and the last are smaller inputs.
```
-BenchmarkDecoderSilesia-8 20 642550210 ns/op 329.85 MB/s 3101 B/op 8 allocs/op
-BenchmarkDecoderSilesiaCgo-8 100 384930000 ns/op 550.61 MB/s 451878 B/op 9713 allocs/op
-
-BenchmarkDecoderEnwik9-2 10 3146000080 ns/op 317.86 MB/s 2649 B/op 9 allocs/op
-BenchmarkDecoderEnwik9Cgo-2 20 1905900000 ns/op 524.69 MB/s 1125120 B/op 45785 allocs/op
-
-BenchmarkDecoder_DecodeAll/z000000.zst-8 200 7049994 ns/op 138.26 MB/s 40 B/op 2 allocs/op
-BenchmarkDecoder_DecodeAll/z000001.zst-8 100000 19560 ns/op 97.49 MB/s 40 B/op 2 allocs/op
-BenchmarkDecoder_DecodeAll/z000002.zst-8 5000 297599 ns/op 236.99 MB/s 40 B/op 2 allocs/op
-BenchmarkDecoder_DecodeAll/z000003.zst-8 2000 725502 ns/op 141.17 MB/s 40 B/op 2 allocs/op
-BenchmarkDecoder_DecodeAll/z000004.zst-8 200000 9314 ns/op 54.54 MB/s 40 B/op 2 allocs/op
-BenchmarkDecoder_DecodeAll/z000005.zst-8 10000 137500 ns/op 104.72 MB/s 40 B/op 2 allocs/op
-BenchmarkDecoder_DecodeAll/z000006.zst-8 500 2316009 ns/op 206.06 MB/s 40 B/op 2 allocs/op
-BenchmarkDecoder_DecodeAll/z000007.zst-8 20000 64499 ns/op 344.90 MB/s 40 B/op 2 allocs/op
-BenchmarkDecoder_DecodeAll/z000008.zst-8 50000 24900 ns/op 219.56 MB/s 40 B/op 2 allocs/op
-BenchmarkDecoder_DecodeAll/z000009.zst-8 1000 2348999 ns/op 154.01 MB/s 40 B/op 2 allocs/op
-
-BenchmarkDecoder_DecodeAllCgo/z000000.zst-8 500 4268005 ns/op 228.38 MB/s 1228849 B/op 3 allocs/op
-BenchmarkDecoder_DecodeAllCgo/z000001.zst-8 100000 15250 ns/op 125.05 MB/s 2096 B/op 3 allocs/op
-BenchmarkDecoder_DecodeAllCgo/z000002.zst-8 10000 147399 ns/op 478.49 MB/s 73776 B/op 3 allocs/op
-BenchmarkDecoder_DecodeAllCgo/z000003.zst-8 5000 320798 ns/op 319.27 MB/s 139312 B/op 3 allocs/op
-BenchmarkDecoder_DecodeAllCgo/z000004.zst-8 200000 10004 ns/op 50.77 MB/s 560 B/op 3 allocs/op
-BenchmarkDecoder_DecodeAllCgo/z000005.zst-8 20000 73599 ns/op 195.64 MB/s 19120 B/op 3 allocs/op
-BenchmarkDecoder_DecodeAllCgo/z000006.zst-8 1000 1119003 ns/op 426.48 MB/s 557104 B/op 3 allocs/op
-BenchmarkDecoder_DecodeAllCgo/z000007.zst-8 20000 103450 ns/op 215.04 MB/s 71296 B/op 9 allocs/op
-BenchmarkDecoder_DecodeAllCgo/z000008.zst-8 100000 20130 ns/op 271.58 MB/s 6192 B/op 3 allocs/op
-BenchmarkDecoder_DecodeAllCgo/z000009.zst-8 2000 1123500 ns/op 322.00 MB/s 368688 B/op 3 allocs/op
+BenchmarkDecoderSilesia-8 3 385000067 ns/op 550.51 MB/s 5498 B/op 8 allocs/op
+BenchmarkDecoderSilesiaCgo-8 6 197666567 ns/op 1072.25 MB/s 270672 B/op 8 allocs/op
+
+BenchmarkDecoderEnwik9-8 1 2027001600 ns/op 493.34 MB/s 10496 B/op 18 allocs/op
+BenchmarkDecoderEnwik9Cgo-8 2 979499200 ns/op 1020.93 MB/s 270672 B/op 8 allocs/op
+
+Concurrent performance:
+
+BenchmarkDecoder_DecodeAllParallel/kppkn.gtb.zst-16 28915 42469 ns/op 4340.07 MB/s 114 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/geo.protodata.zst-16 116505 9965 ns/op 11900.16 MB/s 16 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/plrabn12.txt.zst-16 8952 134272 ns/op 3588.70 MB/s 915 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/lcet10.txt.zst-16 11820 102538 ns/op 4161.90 MB/s 594 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/asyoulik.txt.zst-16 34782 34184 ns/op 3661.88 MB/s 60 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/alice29.txt.zst-16 27712 43447 ns/op 3500.58 MB/s 99 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/html_x_4.zst-16 62826 18750 ns/op 21845.10 MB/s 104 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/paper-100k.pdf.zst-16 631545 1794 ns/op 57078.74 MB/s 2 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/fireworks.jpeg.zst-16 1690140 712 ns/op 172938.13 MB/s 1 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/urls.10K.zst-16 10432 113593 ns/op 6180.73 MB/s 1143 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/html.zst-16 113206 10671 ns/op 9596.27 MB/s 15 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/comp-data.bin.zst-16 1530615 779 ns/op 5229.49 MB/s 0 B/op 0 allocs/op
+
+BenchmarkDecoder_DecodeAllParallelCgo/kppkn.gtb.zst-16 65217 16192 ns/op 11383.34 MB/s 46 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallelCgo/geo.protodata.zst-16 292671 4039 ns/op 29363.19 MB/s 6 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallelCgo/plrabn12.txt.zst-16 26314 46021 ns/op 10470.43 MB/s 293 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallelCgo/lcet10.txt.zst-16 33897 34900 ns/op 12227.96 MB/s 205 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallelCgo/asyoulik.txt.zst-16 104348 11433 ns/op 10949.01 MB/s 20 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallelCgo/alice29.txt.zst-16 75949 15510 ns/op 9805.60 MB/s 32 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallelCgo/html_x_4.zst-16 173910 6756 ns/op 60624.29 MB/s 37 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallelCgo/paper-100k.pdf.zst-16 923076 1339 ns/op 76474.87 MB/s 1 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallelCgo/fireworks.jpeg.zst-16 922920 1351 ns/op 91102.57 MB/s 2 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallelCgo/urls.10K.zst-16 27649 43618 ns/op 16096.19 MB/s 407 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallelCgo/html.zst-16 279073 4160 ns/op 24614.18 MB/s 6 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallelCgo/comp-data.bin.zst-16 749938 1579 ns/op 2581.71 MB/s 0 B/op 0 allocs/op
```
-This reflects the performance around May 2019, but this may be out of date.
+This reflects the performance around May 2020, but this may be out of date.
# Contributions
diff --git a/vendor/github.com/klauspost/compress/zstd/blockenc.go b/vendor/github.com/klauspost/compress/zstd/blockenc.go
index 4f0eba22f..c584f6aab 100644
--- a/vendor/github.com/klauspost/compress/zstd/blockenc.go
+++ b/vendor/github.com/klauspost/compress/zstd/blockenc.go
@@ -444,9 +444,9 @@ func fuzzFseEncoder(data []byte) int {
}
// encode will encode the block and append the output in b.output.
-func (b *blockEnc) encode(raw bool) error {
+func (b *blockEnc) encode(raw, rawAllLits bool) error {
if len(b.sequences) == 0 {
- return b.encodeLits(raw)
+ return b.encodeLits(rawAllLits)
}
// We want some difference
if len(b.literals) > (b.size - (b.size >> 5)) {
diff --git a/vendor/github.com/klauspost/compress/zstd/decoder.go b/vendor/github.com/klauspost/compress/zstd/decoder.go
index 75bf05bc9..66b51bf2d 100644
--- a/vendor/github.com/klauspost/compress/zstd/decoder.go
+++ b/vendor/github.com/klauspost/compress/zstd/decoder.go
@@ -85,6 +85,13 @@ func NewReader(r io.Reader, opts ...DOption) (*Decoder, error) {
d.current.output = make(chan decodeOutput, d.o.concurrent)
d.current.flushed = true
+ // Transfer option dicts.
+ d.dicts = make(map[uint32]dict, len(d.o.dicts))
+ for _, dc := range d.o.dicts {
+ d.dicts[dc.id] = dc
+ }
+ d.o.dicts = nil
+
// Create decoders
d.decoders = make(chan *blockDec, d.o.concurrent)
for i := 0; i < d.o.concurrent; i++ {
@@ -399,19 +406,6 @@ func (d *Decoder) Close() {
d.current.err = ErrDecoderClosed
}
-// RegisterDict will load a dictionary
-func (d *Decoder) RegisterDict(b []byte) error {
- dc, err := loadDict(b)
- if err != nil {
- return err
- }
- if d.dicts == nil {
- d.dicts = make(map[uint32]dict, 1)
- }
- d.dicts[dc.id] = *dc
- return nil
-}
-
// IOReadCloser returns the decoder as an io.ReadCloser for convenience.
// Any changes to the decoder will be reflected, so the returned ReadCloser
// can be reused along with the decoder.
diff --git a/vendor/github.com/klauspost/compress/zstd/decoder_options.go b/vendor/github.com/klauspost/compress/zstd/decoder_options.go
index 2ac9cd2dd..284d38449 100644
--- a/vendor/github.com/klauspost/compress/zstd/decoder_options.go
+++ b/vendor/github.com/klauspost/compress/zstd/decoder_options.go
@@ -18,6 +18,7 @@ type decoderOptions struct {
lowMem bool
concurrent int
maxDecodedSize uint64
+ dicts []dict
}
func (o *decoderOptions) setDefault() {
@@ -66,3 +67,18 @@ func WithDecoderMaxMemory(n uint64) DOption {
return nil
}
}
+
+// WithDecoderDicts allows to register one or more dictionaries for the decoder.
+// If several dictionaries with the same ID is provided the last one will be used.
+func WithDecoderDicts(dicts ...[]byte) DOption {
+ return func(o *decoderOptions) error {
+ for _, b := range dicts {
+ d, err := loadDict(b)
+ if err != nil {
+ return err
+ }
+ o.dicts = append(o.dicts, *d)
+ }
+ return nil
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/encoder.go b/vendor/github.com/klauspost/compress/zstd/encoder.go
index bf42bb1cf..c56d2241f 100644
--- a/vendor/github.com/klauspost/compress/zstd/encoder.go
+++ b/vendor/github.com/klauspost/compress/zstd/encoder.go
@@ -280,7 +280,7 @@ func (e *Encoder) nextBlock(final bool) error {
// If we got the exact same number of literals as input,
// assume the literals cannot be compressed.
if len(src) != len(blk.literals) || len(src) != e.o.blockSize {
- err = blk.encode(e.o.noEntropy)
+ err = blk.encode(e.o.noEntropy, !e.o.allLitEntropy)
}
switch err {
case errIncompressible:
@@ -491,7 +491,7 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
if len(blk.literals) != len(src) || len(src) != e.o.blockSize {
// Output directly to dst
blk.output = dst
- err = blk.encode(e.o.noEntropy)
+ err = blk.encode(e.o.noEntropy, !e.o.allLitEntropy)
}
switch err {
@@ -528,7 +528,7 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
// If we got the exact same number of literals as input,
// assume the literals cannot be compressed.
if len(blk.literals) != len(todo) || len(todo) != e.o.blockSize {
- err = blk.encode(e.o.noEntropy)
+ err = blk.encode(e.o.noEntropy, !e.o.allLitEntropy)
}
switch err {
diff --git a/vendor/github.com/klauspost/compress/zstd/encoder_options.go b/vendor/github.com/klauspost/compress/zstd/encoder_options.go
index 3fc03097a..dfac14ddd 100644
--- a/vendor/github.com/klauspost/compress/zstd/encoder_options.go
+++ b/vendor/github.com/klauspost/compress/zstd/encoder_options.go
@@ -12,16 +12,18 @@ type EOption func(*encoderOptions) error
// options retains accumulated state of multiple options.
type encoderOptions struct {
- concurrent int
- level EncoderLevel
- single *bool
- pad int
- blockSize int
- windowSize int
- crc bool
- fullZero bool
- noEntropy bool
- customWindow bool
+ concurrent int
+ level EncoderLevel
+ single *bool
+ pad int
+ blockSize int
+ windowSize int
+ crc bool
+ fullZero bool
+ noEntropy bool
+ allLitEntropy bool
+ customWindow bool
+ customALEntropy bool
}
func (o *encoderOptions) setDefault() {
@@ -207,6 +209,10 @@ func WithEncoderLevel(l EncoderLevel) EOption {
o.windowSize = 16 << 20
}
}
+ if !o.customALEntropy {
+ o.allLitEntropy = l > SpeedFastest
+ }
+
return nil
}
}
@@ -221,6 +227,18 @@ func WithZeroFrames(b bool) EOption {
}
}
+// WithAllLitEntropyCompression will apply entropy compression if no matches are found.
+// Disabling this will skip incompressible data faster, but in cases with no matches but
+// skewed character distribution compression is lost.
+// Default value depends on the compression level selected.
+func WithAllLitEntropyCompression(b bool) EOption {
+ return func(o *encoderOptions) error {
+ o.customALEntropy = true
+ o.allLitEntropy = b
+ return nil
+ }
+}
+
// WithNoEntropyCompression will always skip entropy compression of literals.
// This can be useful if content has matches, but unlikely to benefit from entropy
// compression. Usually the slight speed improvement is not worth enabling this.
diff --git a/vendor/github.com/klauspost/compress/zstd/snappy.go b/vendor/github.com/klauspost/compress/zstd/snappy.go
index 356956ba2..690428cd2 100644
--- a/vendor/github.com/klauspost/compress/zstd/snappy.go
+++ b/vendor/github.com/klauspost/compress/zstd/snappy.go
@@ -178,7 +178,7 @@ func (r *SnappyConverter) Convert(in io.Reader, w io.Writer) (int64, error) {
r.err = ErrSnappyCorrupt
return written, r.err
}
- err = r.block.encode(false)
+ err = r.block.encode(false, false)
switch err {
case errIncompressible:
r.block.popOffsets()
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/doc.go b/vendor/github.com/opencontainers/selinux/go-selinux/doc.go
new file mode 100644
index 000000000..79a8e6446
--- /dev/null
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/doc.go
@@ -0,0 +1,21 @@
+/*
+Package selinux provides a high-level interface for interacting with selinux.
+
+This package uses a selinux build tag to enable the selinux functionality. This
+allows non-linux and linux users who do not have selinux support to still use
+tools that rely on this library.
+
+To compile with full selinux support use the -tags=selinux option in your build
+and test commands.
+
+Usage:
+
+ import "github.com/opencontainers/selinux/go-selinux"
+
+ // Ensure that selinux is enforcing mode.
+ if selinux.EnforceMode() != selinux.Enforcing {
+ selinux.SetEnforceMode(selinux.Enforcing)
+ }
+
+*/
+package selinux
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go
index 779e2e3a8..10ac15a85 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go
@@ -73,9 +73,9 @@ func InitLabels(options []string) (plabel string, mlabel string, Err error) {
selinux.ReleaseLabel(processLabel)
}
processLabel = pcon.Get()
- mountLabel = mcon.Get()
selinux.ReserveLabel(processLabel)
}
+ mountLabel = mcon.Get()
}
return processLabel, mountLabel, nil
}
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go
index c2bdd35d7..a7d2d5e34 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go
@@ -30,7 +30,6 @@ func Relabel(path string, fileLabel string, shared bool) error {
// DisableSecOpt returns a security opt that can disable labeling
// support for future container processes
func DisableSecOpt() []string {
- // TODO the selinux.DisableSecOpt stub returns []string{"disable"} instead of "nil"
return nil
}
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go
new file mode 100644
index 000000000..50760dc93
--- /dev/null
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go
@@ -0,0 +1,249 @@
+package selinux
+
+import (
+ "github.com/pkg/errors"
+)
+
+const (
+ // Enforcing constant indicate SELinux is in enforcing mode
+ Enforcing = 1
+ // Permissive constant to indicate SELinux is in permissive mode
+ Permissive = 0
+ // Disabled constant to indicate SELinux is disabled
+ Disabled = -1
+
+ // DefaultCategoryRange is the upper bound on the category range
+ DefaultCategoryRange = uint32(1024)
+)
+
+var (
+ // ErrMCSAlreadyExists is returned when trying to allocate a duplicate MCS.
+ ErrMCSAlreadyExists = errors.New("MCS label already exists")
+ // ErrEmptyPath is returned when an empty path has been specified.
+ ErrEmptyPath = errors.New("empty path")
+
+ // InvalidLabel is returned when an invalid label is specified.
+ InvalidLabel = errors.New("Invalid Label")
+
+ // ErrIncomparable is returned two levels are not comparable
+ ErrIncomparable = errors.New("incomparable levels")
+ // ErrLevelSyntax is returned when a sensitivity or category do not have correct syntax in a level
+ ErrLevelSyntax = errors.New("invalid level syntax")
+
+ // CategoryRange allows the upper bound on the category range to be adjusted
+ CategoryRange = DefaultCategoryRange
+)
+
+// Context is a representation of the SELinux label broken into 4 parts
+type Context map[string]string
+
+// SetDisabled disables SELinux support for the package
+func SetDisabled() {
+ setDisabled()
+}
+
+// GetEnabled returns whether SELinux is currently enabled.
+func GetEnabled() bool {
+ return getEnabled()
+}
+
+// ClassIndex returns the int index for an object class in the loaded policy,
+// or -1 and an error
+func ClassIndex(class string) (int, error) {
+ return classIndex(class)
+}
+
+// SetFileLabel sets the SELinux label for this path or returns an error.
+func SetFileLabel(fpath string, label string) error {
+ return setFileLabel(fpath, label)
+}
+
+// FileLabel returns the SELinux label for this path or returns an error.
+func FileLabel(fpath string) (string, error) {
+ return fileLabel(fpath)
+}
+
+// SetFSCreateLabel tells kernel the label to create all file system objects
+// created by this task. Setting label="" to return to default.
+func SetFSCreateLabel(label string) error {
+ return setFSCreateLabel(label)
+}
+
+// FSCreateLabel returns the default label the kernel which the kernel is using
+// for file system objects created by this task. "" indicates default.
+func FSCreateLabel() (string, error) {
+ return fsCreateLabel()
+}
+
+// CurrentLabel returns the SELinux label of the current process thread, or an error.
+func CurrentLabel() (string, error) {
+ return currentLabel()
+}
+
+// PidLabel returns the SELinux label of the given pid, or an error.
+func PidLabel(pid int) (string, error) {
+ return pidLabel(pid)
+}
+
+// ExecLabel returns the SELinux label that the kernel will use for any programs
+// that are executed by the current process thread, or an error.
+func ExecLabel() (string, error) {
+ return execLabel()
+}
+
+// CanonicalizeContext takes a context string and writes it to the kernel
+// the function then returns the context that the kernel will use. Use this
+// function to check if two contexts are equivalent
+func CanonicalizeContext(val string) (string, error) {
+ return canonicalizeContext(val)
+}
+
+// ComputeCreateContext requests the type transition from source to target for
+// class from the kernel.
+func ComputeCreateContext(source string, target string, class string) (string, error) {
+ return computeCreateContext(source, target, class)
+}
+
+// CalculateGlbLub computes the glb (greatest lower bound) and lub (least upper bound)
+// of a source and target range.
+// The glblub is calculated as the greater of the low sensitivities and
+// the lower of the high sensitivities and the and of each category bitset.
+func CalculateGlbLub(sourceRange, targetRange string) (string, error) {
+ return calculateGlbLub(sourceRange, targetRange)
+}
+
+// SetExecLabel sets the SELinux label that the kernel will use for any programs
+// that are executed by the current process thread, or an error.
+func SetExecLabel(label string) error {
+ return setExecLabel(label)
+}
+
+// SetTaskLabel sets the SELinux label for the current thread, or an error.
+// This requires the dyntransition permission.
+func SetTaskLabel(label string) error {
+ return setTaskLabel(label)
+}
+
+// SetSocketLabel takes a process label and tells the kernel to assign the
+// label to the next socket that gets created
+func SetSocketLabel(label string) error {
+ return setSocketLabel(label)
+}
+
+// SocketLabel retrieves the current socket label setting
+func SocketLabel() (string, error) {
+ return socketLabel()
+}
+
+// PeerLabel retrieves the label of the client on the other side of a socket
+func PeerLabel(fd uintptr) (string, error) {
+ return peerLabel(fd)
+}
+
+// SetKeyLabel takes a process label and tells the kernel to assign the
+// label to the next kernel keyring that gets created
+func SetKeyLabel(label string) error {
+ return setKeyLabel(label)
+}
+
+// KeyLabel retrieves the current kernel keyring label setting
+func KeyLabel() (string, error) {
+ return keyLabel()
+}
+
+// Get returns the Context as a string
+func (c Context) Get() string {
+ return c.get()
+}
+
+// NewContext creates a new Context struct from the specified label
+func NewContext(label string) (Context, error) {
+ return newContext(label)
+}
+
+// ClearLabels clears all reserved labels
+func ClearLabels() {
+ clearLabels()
+}
+
+// ReserveLabel reserves the MLS/MCS level component of the specified label
+func ReserveLabel(label string) {
+ reserveLabel(label)
+}
+
+// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
+func EnforceMode() int {
+ return enforceMode()
+}
+
+// SetEnforceMode sets the current SELinux mode Enforcing, Permissive.
+// Disabled is not valid, since this needs to be set at boot time.
+func SetEnforceMode(mode int) error {
+ return setEnforceMode(mode)
+}
+
+// DefaultEnforceMode returns the systems default SELinux mode Enforcing,
+// Permissive or Disabled. Note this is is just the default at boot time.
+// EnforceMode tells you the systems current mode.
+func DefaultEnforceMode() int {
+ return defaultEnforceMode()
+}
+
+// ReleaseLabel un-reserves the MLS/MCS Level field of the specified label,
+// allowing it to be used by another process.
+func ReleaseLabel(label string) {
+ releaseLabel(label)
+}
+
+// ROFileLabel returns the specified SELinux readonly file label
+func ROFileLabel() string {
+ return roFileLabel()
+}
+
+// KVMContainerLabels returns the default processLabel and mountLabel to be used
+// for kvm containers by the calling process.
+func KVMContainerLabels() (string, string) {
+ return kvmContainerLabels()
+}
+
+// InitContainerLabels returns the default processLabel and file labels to be
+// used for containers running an init system like systemd by the calling process.
+func InitContainerLabels() (string, string) {
+ return initContainerLabels()
+}
+
+// ContainerLabels returns an allocated processLabel and fileLabel to be used for
+// container labeling by the calling process.
+func ContainerLabels() (processLabel string, fileLabel string) {
+ return containerLabels()
+}
+
+// SecurityCheckContext validates that the SELinux label is understood by the kernel
+func SecurityCheckContext(val string) error {
+ return securityCheckContext(val)
+}
+
+// CopyLevel returns a label with the MLS/MCS level from src label replaced on
+// the dest label.
+func CopyLevel(src, dest string) (string, error) {
+ return copyLevel(src, dest)
+}
+
+// Chcon changes the fpath file object to the SELinux label label.
+// If fpath is a directory and recurse is true, then Chcon walks the
+// directory tree setting the label.
+func Chcon(fpath string, label string, recurse bool) error {
+ return chcon(fpath, label, recurse)
+}
+
+// DupSecOpt takes an SELinux process label and returns security options that
+// can be used to set the SELinux Type and Level for future container processes.
+func DupSecOpt(src string) ([]string, error) {
+ return dupSecOpt(src)
+}
+
+// DisableSecOpt returns a security opt that can be used to disable SELinux
+// labeling support for future container processes.
+func DisableSecOpt() []string {
+ return disableSecOpt()
+}
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
index 9c979e5e2..d6b0d49db 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
@@ -20,17 +20,12 @@ import (
"github.com/opencontainers/selinux/pkg/pwalk"
"github.com/pkg/errors"
+ "github.com/willf/bitset"
"golang.org/x/sys/unix"
)
const (
- // Enforcing constant indicate SELinux is in enforcing mode
- Enforcing = 1
- // Permissive constant to indicate SELinux is in permissive mode
- Permissive = 0
- // Disabled constant to indicate SELinux is disabled
- Disabled = -1
-
+ minSensLen = 2
contextFile = "/usr/share/containers/selinux/contexts"
selinuxDir = "/etc/selinux/"
selinuxConfig = selinuxDir + "config"
@@ -49,17 +44,27 @@ type selinuxState struct {
sync.Mutex
}
+type level struct {
+ sens uint
+ cats *bitset.BitSet
+}
+
+type mlsRange struct {
+ low *level
+ high *level
+}
+
+type levelItem byte
+
+const (
+ sensitivity levelItem = 's'
+ category levelItem = 'c'
+)
+
var (
- // ErrMCSAlreadyExists is returned when trying to allocate a duplicate MCS.
- ErrMCSAlreadyExists = errors.New("MCS label already exists")
- // ErrEmptyPath is returned when an empty path has been specified.
- ErrEmptyPath = errors.New("empty path")
- // InvalidLabel is returned when an invalid label is specified.
- InvalidLabel = errors.New("Invalid Label")
-
- assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`)
- roFileLabel string
- state = selinuxState{
+ assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`)
+ readOnlyFileLabel string
+ state = selinuxState{
mcsList: make(map[string]bool),
}
@@ -68,9 +73,6 @@ var (
haveThreadSelf bool
)
-// Context is a representation of the SELinux label broken into 4 parts
-type Context map[string]string
-
func (s *selinuxState) setEnable(enabled bool) bool {
s.Lock()
defer s.Unlock()
@@ -97,8 +99,8 @@ func (s *selinuxState) getEnabled() bool {
return s.setEnable(enabled)
}
-// SetDisabled disables selinux support for the package
-func SetDisabled() {
+// setDisabled disables SELinux support for the package
+func setDisabled() {
state.setEnable(false)
}
@@ -190,15 +192,15 @@ func (s *selinuxState) getSELinuxfs() string {
// getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs
// filesystem or an empty string if no mountpoint is found. Selinuxfs is
-// a proc-like pseudo-filesystem that exposes the selinux policy API to
+// a proc-like pseudo-filesystem that exposes the SELinux policy API to
// processes. The existence of an selinuxfs mount is used to determine
-// whether selinux is currently enabled or not.
+// whether SELinux is currently enabled or not.
func getSelinuxMountPoint() string {
return state.getSELinuxfs()
}
-// GetEnabled returns whether selinux is currently enabled.
-func GetEnabled() bool {
+// getEnabled returns whether SELinux is currently enabled.
+func getEnabled() bool {
return state.getEnabled()
}
@@ -282,8 +284,9 @@ func readCon(fpath string) (string, error) {
return strings.Trim(retval, "\x00"), nil
}
-// ClassIndex returns the int index for an object class in the loaded policy, or -1 and an error
-func ClassIndex(class string) (int, error) {
+// classIndex returns the int index for an object class in the loaded policy,
+// or -1 and an error
+func classIndex(class string) (int, error) {
permpath := fmt.Sprintf("class/%s/index", class)
indexpath := filepath.Join(getSelinuxMountPoint(), permpath)
@@ -299,8 +302,8 @@ func ClassIndex(class string) (int, error) {
return index, nil
}
-// SetFileLabel sets the SELinux label for this path or returns an error.
-func SetFileLabel(fpath string, label string) error {
+// setFileLabel sets the SELinux label for this path or returns an error.
+func setFileLabel(fpath string, label string) error {
if fpath == "" {
return ErrEmptyPath
}
@@ -310,8 +313,8 @@ func SetFileLabel(fpath string, label string) error {
return nil
}
-// FileLabel returns the SELinux label for this path or returns an error.
-func FileLabel(fpath string) (string, error) {
+// fileLabel returns the SELinux label for this path or returns an error.
+func fileLabel(fpath string) (string, error) {
if fpath == "" {
return "", ErrEmptyPath
}
@@ -327,37 +330,31 @@ func FileLabel(fpath string) (string, error) {
return string(label), nil
}
-/*
-SetFSCreateLabel tells kernel the label to create all file system objects
-created by this task. Setting label="" to return to default.
-*/
-func SetFSCreateLabel(label string) error {
+// setFSCreateLabel tells kernel the label to create all file system objects
+// created by this task. Setting label="" to return to default.
+func setFSCreateLabel(label string) error {
return writeAttr("fscreate", label)
}
-/*
-FSCreateLabel returns the default label the kernel which the kernel is using
-for file system objects created by this task. "" indicates default.
-*/
-func FSCreateLabel() (string, error) {
+// fsCreateLabel returns the default label the kernel which the kernel is using
+// for file system objects created by this task. "" indicates default.
+func fsCreateLabel() (string, error) {
return readAttr("fscreate")
}
-// CurrentLabel returns the SELinux label of the current process thread, or an error.
-func CurrentLabel() (string, error) {
+// currentLabel returns the SELinux label of the current process thread, or an error.
+func currentLabel() (string, error) {
return readAttr("current")
}
-// PidLabel returns the SELinux label of the given pid, or an error.
-func PidLabel(pid int) (string, error) {
+// pidLabel returns the SELinux label of the given pid, or an error.
+func pidLabel(pid int) (string, error) {
return readCon(fmt.Sprintf("/proc/%d/attr/current", pid))
}
-/*
-ExecLabel returns the SELinux label that the kernel will use for any programs
-that are executed by the current process thread, or an error.
-*/
-func ExecLabel() (string, error) {
+// ExecLabel returns the SELinux label that the kernel will use for any programs
+// that are executed by the current process thread, or an error.
+func execLabel() (string, error) {
return readAttr("exec")
}
@@ -366,7 +363,7 @@ func writeCon(fpath, val string) error {
return ErrEmptyPath
}
if val == "" {
- if !GetEnabled() {
+ if !getEnabled() {
return nil
}
}
@@ -418,20 +415,17 @@ func writeAttr(attr, val string) error {
return writeCon(attrPath(attr), val)
}
-/*
-CanonicalizeContext takes a context string and writes it to the kernel
-the function then returns the context that the kernel will use. This function
-can be used to see if two contexts are equivalent
-*/
-func CanonicalizeContext(val string) (string, error) {
+// canonicalizeContext takes a context string and writes it to the kernel
+// the function then returns the context that the kernel will use. Use this
+// function to check if two contexts are equivalent
+func canonicalizeContext(val string) (string, error) {
return readWriteCon(filepath.Join(getSelinuxMountPoint(), "context"), val)
}
-/*
-ComputeCreateContext requests the type transition from source to target for class from the kernel.
-*/
-func ComputeCreateContext(source string, target string, class string) (string, error) {
- classidx, err := ClassIndex(class)
+// computeCreateContext requests the type transition from source to target for
+// class from the kernel.
+func computeCreateContext(source string, target string, class string) (string, error) {
+ classidx, err := classIndex(class)
if err != nil {
return "", err
}
@@ -439,6 +433,217 @@ func ComputeCreateContext(source string, target string, class string) (string, e
return readWriteCon(filepath.Join(getSelinuxMountPoint(), "create"), fmt.Sprintf("%s %s %d", source, target, classidx))
}
+// catsToBitset stores categories in a bitset.
+func catsToBitset(cats string) (*bitset.BitSet, error) {
+ bitset := &bitset.BitSet{}
+
+ catlist := strings.Split(cats, ",")
+ for _, r := range catlist {
+ ranges := strings.SplitN(r, ".", 2)
+ if len(ranges) > 1 {
+ catstart, err := parseLevelItem(ranges[0], category)
+ if err != nil {
+ return nil, err
+ }
+ catend, err := parseLevelItem(ranges[1], category)
+ if err != nil {
+ return nil, err
+ }
+ for i := catstart; i <= catend; i++ {
+ bitset.Set(i)
+ }
+ } else {
+ cat, err := parseLevelItem(ranges[0], category)
+ if err != nil {
+ return nil, err
+ }
+ bitset.Set(cat)
+ }
+ }
+
+ return bitset, nil
+}
+
+// parseLevelItem parses and verifies that a sensitivity or category are valid
+func parseLevelItem(s string, sep levelItem) (uint, error) {
+ if len(s) < minSensLen || levelItem(s[0]) != sep {
+ return 0, ErrLevelSyntax
+ }
+ val, err := strconv.ParseUint(s[1:], 10, 32)
+ if err != nil {
+ return 0, err
+ }
+
+ return uint(val), nil
+}
+
+// parseLevel fills a level from a string that contains
+// a sensitivity and categories
+func (l *level) parseLevel(levelStr string) error {
+ lvl := strings.SplitN(levelStr, ":", 2)
+ sens, err := parseLevelItem(lvl[0], sensitivity)
+ if err != nil {
+ return errors.Wrap(err, "failed to parse sensitivity")
+ }
+ l.sens = sens
+ if len(lvl) > 1 {
+ cats, err := catsToBitset(lvl[1])
+ if err != nil {
+ return errors.Wrap(err, "failed to parse categories")
+ }
+ l.cats = cats
+ }
+
+ return nil
+}
+
+// rangeStrToMLSRange marshals a string representation of a range.
+func rangeStrToMLSRange(rangeStr string) (*mlsRange, error) {
+ mlsRange := &mlsRange{}
+ levelSlice := strings.SplitN(rangeStr, "-", 2)
+
+ switch len(levelSlice) {
+ // rangeStr that has a low and a high level, e.g. s4:c0.c1023-s6:c0.c1023
+ case 2:
+ mlsRange.high = &level{}
+ if err := mlsRange.high.parseLevel(levelSlice[1]); err != nil {
+ return nil, errors.Wrapf(err, "failed to parse high level %q", levelSlice[1])
+ }
+ fallthrough
+ // rangeStr that is single level, e.g. s6:c0,c3,c5,c30.c1023
+ case 1:
+ mlsRange.low = &level{}
+ if err := mlsRange.low.parseLevel(levelSlice[0]); err != nil {
+ return nil, errors.Wrapf(err, "failed to parse low level %q", levelSlice[0])
+ }
+ }
+
+ if mlsRange.high == nil {
+ mlsRange.high = mlsRange.low
+ }
+
+ return mlsRange, nil
+}
+
+// bitsetToStr takes a category bitset and returns it in the
+// canonical selinux syntax
+func bitsetToStr(c *bitset.BitSet) string {
+ var str string
+ i, e := c.NextSet(0)
+ len := 0
+ for e {
+ if len == 0 {
+ if str != "" {
+ str += ","
+ }
+ str += "c" + strconv.Itoa(int(i))
+ }
+
+ next, e := c.NextSet(i + 1)
+ if e {
+ // consecutive cats
+ if next == i+1 {
+ len++
+ i = next
+ continue
+ }
+ }
+ if len == 1 {
+ str += ",c" + strconv.Itoa(int(i))
+ } else if len > 1 {
+ str += ".c" + strconv.Itoa(int(i))
+ }
+ if !e {
+ break
+ }
+ len = 0
+ i = next
+ }
+
+ return str
+}
+
+func (l1 *level) equal(l2 *level) bool {
+ if l2 == nil || l1 == nil {
+ return l1 == l2
+ }
+ if l1.sens != l2.sens {
+ return false
+ }
+ return l1.cats.Equal(l2.cats)
+}
+
+// String returns an mlsRange as a string.
+func (m mlsRange) String() string {
+ low := "s" + strconv.Itoa(int(m.low.sens))
+ if m.low.cats != nil && m.low.cats.Count() > 0 {
+ low += ":" + bitsetToStr(m.low.cats)
+ }
+
+ if m.low.equal(m.high) {
+ return low
+ }
+
+ high := "s" + strconv.Itoa(int(m.high.sens))
+ if m.high.cats != nil && m.high.cats.Count() > 0 {
+ high += ":" + bitsetToStr(m.high.cats)
+ }
+
+ return low + "-" + high
+}
+
+func max(a, b uint) uint {
+ if a > b {
+ return a
+ }
+ return b
+}
+
+func min(a, b uint) uint {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+// calculateGlbLub computes the glb (greatest lower bound) and lub (least upper bound)
+// of a source and target range.
+// The glblub is calculated as the greater of the low sensitivities and
+// the lower of the high sensitivities and the and of each category bitset.
+func calculateGlbLub(sourceRange, targetRange string) (string, error) {
+ s, err := rangeStrToMLSRange(sourceRange)
+ if err != nil {
+ return "", err
+ }
+ t, err := rangeStrToMLSRange(targetRange)
+ if err != nil {
+ return "", err
+ }
+
+ if s.high.sens < t.low.sens || t.high.sens < s.low.sens {
+ /* these ranges have no common sensitivities */
+ return "", ErrIncomparable
+ }
+
+ outrange := &mlsRange{low: &level{}, high: &level{}}
+
+ /* take the greatest of the low */
+ outrange.low.sens = max(s.low.sens, t.low.sens)
+
+ /* take the least of the high */
+ outrange.high.sens = min(s.high.sens, t.high.sens)
+
+ /* find the intersecting categories */
+ if s.low.cats != nil && t.low.cats != nil {
+ outrange.low.cats = s.low.cats.Intersection(t.low.cats)
+ }
+ if s.high.cats != nil && t.high.cats != nil {
+ outrange.high.cats = s.high.cats.Intersection(t.high.cats)
+ }
+
+ return outrange.String(), nil
+}
+
func readWriteCon(fpath string, val string) (string, error) {
if fpath == "" {
return "", ErrEmptyPath
@@ -461,41 +666,37 @@ func readWriteCon(fpath string, val string) (string, error) {
return strings.Trim(retval, "\x00"), nil
}
-/*
-SetExecLabel sets the SELinux label that the kernel will use for any programs
-that are executed by the current process thread, or an error.
-*/
-func SetExecLabel(label string) error {
+// setExecLabel sets the SELinux label that the kernel will use for any programs
+// that are executed by the current process thread, or an error.
+func setExecLabel(label string) error {
return writeAttr("exec", label)
}
-/*
-SetTaskLabel sets the SELinux label for the current thread, or an error.
-This requires the dyntransition permission.
-*/
-func SetTaskLabel(label string) error {
+// setTaskLabel sets the SELinux label for the current thread, or an error.
+// This requires the dyntransition permission.
+func setTaskLabel(label string) error {
return writeAttr("current", label)
}
-// SetSocketLabel takes a process label and tells the kernel to assign the
+// setSocketLabel takes a process label and tells the kernel to assign the
// label to the next socket that gets created
-func SetSocketLabel(label string) error {
+func setSocketLabel(label string) error {
return writeAttr("sockcreate", label)
}
-// SocketLabel retrieves the current socket label setting
-func SocketLabel() (string, error) {
+// socketLabel retrieves the current socket label setting
+func socketLabel() (string, error) {
return readAttr("sockcreate")
}
-// PeerLabel retrieves the label of the client on the other side of a socket
-func PeerLabel(fd uintptr) (string, error) {
+// peerLabel retrieves the label of the client on the other side of a socket
+func peerLabel(fd uintptr) (string, error) {
return unix.GetsockoptString(int(fd), unix.SOL_SOCKET, unix.SO_PEERSEC)
}
-// SetKeyLabel takes a process label and tells the kernel to assign the
+// setKeyLabel takes a process label and tells the kernel to assign the
// label to the next kernel keyring that gets created
-func SetKeyLabel(label string) error {
+func setKeyLabel(label string) error {
err := writeCon("/proc/self/attr/keycreate", label)
if os.IsNotExist(errors.Cause(err)) {
return nil
@@ -506,21 +707,21 @@ func SetKeyLabel(label string) error {
return err
}
-// KeyLabel retrieves the current kernel keyring label setting
-func KeyLabel() (string, error) {
+// keyLabel retrieves the current kernel keyring label setting
+func keyLabel() (string, error) {
return readCon("/proc/self/attr/keycreate")
}
-// Get returns the Context as a string
-func (c Context) Get() string {
+// get returns the Context as a string
+func (c Context) get() string {
if c["level"] != "" {
return fmt.Sprintf("%s:%s:%s:%s", c["user"], c["role"], c["type"], c["level"])
}
return fmt.Sprintf("%s:%s:%s", c["user"], c["role"], c["type"])
}
-// NewContext creates a new Context struct from the specified label
-func NewContext(label string) (Context, error) {
+// newContext creates a new Context struct from the specified label
+func newContext(label string) (Context, error) {
c := make(Context)
if len(label) != 0 {
@@ -538,15 +739,15 @@ func NewContext(label string) (Context, error) {
return c, nil
}
-// ClearLabels clears all reserved labels
-func ClearLabels() {
+// clearLabels clears all reserved labels
+func clearLabels() {
state.Lock()
state.mcsList = make(map[string]bool)
state.Unlock()
}
-// ReserveLabel reserves the MLS/MCS level component of the specified label
-func ReserveLabel(label string) {
+// reserveLabel reserves the MLS/MCS level component of the specified label
+func reserveLabel(label string) {
if len(label) != 0 {
con := strings.SplitN(label, ":", 4)
if len(con) > 3 {
@@ -559,8 +760,8 @@ func selinuxEnforcePath() string {
return path.Join(getSelinuxMountPoint(), "enforce")
}
-// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
-func EnforceMode() int {
+// enforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
+func enforceMode() int {
var enforce int
enforceB, err := ioutil.ReadFile(selinuxEnforcePath())
@@ -574,20 +775,16 @@ func EnforceMode() int {
return enforce
}
-/*
-SetEnforceMode sets the current SELinux mode Enforcing, Permissive.
-Disabled is not valid, since this needs to be set at boot time.
-*/
-func SetEnforceMode(mode int) error {
+// setEnforceMode sets the current SELinux mode Enforcing, Permissive.
+// Disabled is not valid, since this needs to be set at boot time.
+func setEnforceMode(mode int) error {
return ioutil.WriteFile(selinuxEnforcePath(), []byte(strconv.Itoa(mode)), 0644)
}
-/*
-DefaultEnforceMode returns the systems default SELinux mode Enforcing,
-Permissive or Disabled. Note this is is just the default at boot time.
-EnforceMode tells you the systems current mode.
-*/
-func DefaultEnforceMode() int {
+// defaultEnforceMode returns the systems default SELinux mode Enforcing,
+// Permissive or Disabled. Note this is is just the default at boot time.
+// EnforceMode tells you the systems current mode.
+func defaultEnforceMode() int {
switch readConfig(selinuxTag) {
case "enforcing":
return Enforcing
@@ -667,11 +864,9 @@ func uniqMcs(catRange uint32) string {
return mcs
}
-/*
-ReleaseLabel will unreserve the MLS/MCS Level field of the specified label.
-Allowing it to be used by another process.
-*/
-func ReleaseLabel(label string) {
+// releaseLabel un-reserves the MLS/MCS Level field of the specified label,
+// allowing it to be used by another process.
+func releaseLabel(label string) {
if len(label) != 0 {
con := strings.SplitN(label, ":", 4)
if len(con) > 3 {
@@ -680,9 +875,9 @@ func ReleaseLabel(label string) {
}
}
-// ROFileLabel returns the specified SELinux readonly file label
-func ROFileLabel() string {
- return roFileLabel
+// roFileLabel returns the specified SELinux readonly file label
+func roFileLabel() string {
+ return readOnlyFileLabel
}
func openContextFile() (*os.File, error) {
@@ -737,11 +932,9 @@ func loadLabels() map[string]string {
return labels
}
-/*
-KVMContainerLabels returns the default processLabel and mountLabel to be used
-for kvm containers by the calling process.
-*/
-func KVMContainerLabels() (string, string) {
+// kvmContainerLabels returns the default processLabel and mountLabel to be used
+// for kvm containers by the calling process.
+func kvmContainerLabels() (string, string) {
processLabel := labels["kvm_process"]
if processLabel == "" {
processLabel = labels["process"]
@@ -750,11 +943,9 @@ func KVMContainerLabels() (string, string) {
return addMcs(processLabel, labels["file"])
}
-/*
-InitContainerLabels returns the default processLabel and file labels to be
-used for containers running an init system like systemd by the calling process.
-*/
-func InitContainerLabels() (string, string) {
+// initContainerLabels returns the default processLabel and file labels to be
+// used for containers running an init system like systemd by the calling process.
+func initContainerLabels() (string, string) {
processLabel := labels["init_process"]
if processLabel == "" {
processLabel = labels["process"]
@@ -763,25 +954,23 @@ func InitContainerLabels() (string, string) {
return addMcs(processLabel, labels["file"])
}
-/*
-ContainerLabels returns an allocated processLabel and fileLabel to be used for
-container labeling by the calling process.
-*/
-func ContainerLabels() (processLabel string, fileLabel string) {
- if !GetEnabled() {
+// containerLabels returns an allocated processLabel and fileLabel to be used for
+// container labeling by the calling process.
+func containerLabels() (processLabel string, fileLabel string) {
+ if !getEnabled() {
return "", ""
}
processLabel = labels["process"]
fileLabel = labels["file"]
- roFileLabel = labels["ro_file"]
+ readOnlyFileLabel = labels["ro_file"]
if processLabel == "" || fileLabel == "" {
return "", fileLabel
}
- if roFileLabel == "" {
- roFileLabel = fileLabel
+ if readOnlyFileLabel == "" {
+ readOnlyFileLabel = fileLabel
}
return addMcs(processLabel, fileLabel)
@@ -790,7 +979,7 @@ func ContainerLabels() (processLabel string, fileLabel string) {
func addMcs(processLabel, fileLabel string) (string, string) {
scon, _ := NewContext(processLabel)
if scon["level"] != "" {
- mcs := uniqMcs(1024)
+ mcs := uniqMcs(CategoryRange)
scon["level"] = mcs
processLabel = scon.Get()
scon, _ = NewContext(fileLabel)
@@ -800,16 +989,14 @@ func addMcs(processLabel, fileLabel string) (string, string) {
return processLabel, fileLabel
}
-// SecurityCheckContext validates that the SELinux label is understood by the kernel
-func SecurityCheckContext(val string) error {
+// securityCheckContext validates that the SELinux label is understood by the kernel
+func securityCheckContext(val string) error {
return ioutil.WriteFile(path.Join(getSelinuxMountPoint(), "context"), []byte(val), 0644)
}
-/*
-CopyLevel returns a label with the MLS/MCS level from src label replaced on
-the dest label.
-*/
-func CopyLevel(src, dest string) (string, error) {
+// copyLevel returns a label with the MLS/MCS level from src label replaced on
+// the dest label.
+func copyLevel(src, dest string) (string, error) {
if src == "" {
return "", nil
}
@@ -833,7 +1020,7 @@ func CopyLevel(src, dest string) (string, error) {
return tcon.Get(), nil
}
-// Prevent users from relabing system files
+// Prevent users from relabeling system files
func badPrefix(fpath string) error {
if fpath == "" {
return ErrEmptyPath
@@ -848,10 +1035,10 @@ func badPrefix(fpath string) error {
return nil
}
-// Chcon changes the fpath file object to the SELinux label label.
-// If fpath is a directory and recurse is true, Chcon will walk the
+// chcon changes the fpath file object to the SELinux label label.
+// If fpath is a directory and recurse is true, then chcon walks the
// directory tree setting the label.
-func Chcon(fpath string, label string, recurse bool) error {
+func chcon(fpath string, label string, recurse bool) error {
if fpath == "" {
return ErrEmptyPath
}
@@ -876,9 +1063,9 @@ func Chcon(fpath string, label string, recurse bool) error {
})
}
-// DupSecOpt takes an SELinux process label and returns security options that
+// dupSecOpt takes an SELinux process label and returns security options that
// can be used to set the SELinux Type and Level for future container processes.
-func DupSecOpt(src string) ([]string, error) {
+func dupSecOpt(src string) ([]string, error) {
if src == "" {
return nil, nil
}
@@ -903,8 +1090,8 @@ func DupSecOpt(src string) ([]string, error) {
return dup, nil
}
-// DisableSecOpt returns a security opt that can be used to disable SELinux
+// disableSecOpt returns a security opt that can be used to disable SELinux
// labeling support for future container processes.
-func DisableSecOpt() []string {
+func disableSecOpt() []string {
return []string{"disable"}
}
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go
index f9f5e2061..c526b210f 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go
@@ -2,253 +2,147 @@
package selinux
-import (
- "errors"
-)
-
-const (
- // Enforcing constant indicate SELinux is in enforcing mode
- Enforcing = 1
- // Permissive constant to indicate SELinux is in permissive mode
- Permissive = 0
- // Disabled constant to indicate SELinux is disabled
- Disabled = -1
-)
-
-var (
- // ErrMCSAlreadyExists is returned when trying to allocate a duplicate MCS.
- ErrMCSAlreadyExists = errors.New("MCS label already exists")
- // ErrEmptyPath is returned when an empty path has been specified.
- ErrEmptyPath = errors.New("empty path")
-)
-
-// Context is a representation of the SELinux label broken into 4 parts
-type Context map[string]string
-
-// SetDisabled disables selinux support for the package
-func SetDisabled() {
- return
-}
-
-// GetEnabled returns whether selinux is currently enabled.
-func GetEnabled() bool {
+func setDisabled() {
+}
+
+func getEnabled() bool {
return false
}
-// ClassIndex returns the int index for an object class in the loaded policy, or -1 and an error
-func ClassIndex(class string) (int, error) {
+func classIndex(class string) (int, error) {
return -1, nil
}
-// SetFileLabel sets the SELinux label for this path or returns an error.
-func SetFileLabel(fpath string, label string) error {
+func setFileLabel(fpath string, label string) error {
return nil
}
-// FileLabel returns the SELinux label for this path or returns an error.
-func FileLabel(fpath string) (string, error) {
+func fileLabel(fpath string) (string, error) {
return "", nil
}
-/*
-SetFSCreateLabel tells kernel the label to create all file system objects
-created by this task. Setting label="" to return to default.
-*/
-func SetFSCreateLabel(label string) error {
+func setFSCreateLabel(label string) error {
return nil
}
-/*
-FSCreateLabel returns the default label the kernel which the kernel is using
-for file system objects created by this task. "" indicates default.
-*/
-func FSCreateLabel() (string, error) {
+func fsCreateLabel() (string, error) {
+ return "", nil
+}
+
+func currentLabel() (string, error) {
return "", nil
}
-// CurrentLabel returns the SELinux label of the current process thread, or an error.
-func CurrentLabel() (string, error) {
+func pidLabel(pid int) (string, error) {
return "", nil
}
-// PidLabel returns the SELinux label of the given pid, or an error.
-func PidLabel(pid int) (string, error) {
+func execLabel() (string, error) {
return "", nil
}
-/*
-ExecLabel returns the SELinux label that the kernel will use for any programs
-that are executed by the current process thread, or an error.
-*/
-func ExecLabel() (string, error) {
+func canonicalizeContext(val string) (string, error) {
return "", nil
}
-/*
-CanonicalizeContext takes a context string and writes it to the kernel
-the function then returns the context that the kernel will use. This function
-can be used to see if two contexts are equivalent
-*/
-func CanonicalizeContext(val string) (string, error) {
+func computeCreateContext(source string, target string, class string) (string, error) {
return "", nil
}
-/*
-ComputeCreateContext requests the type transition from source to target for class from the kernel.
-*/
-func ComputeCreateContext(source string, target string, class string) (string, error) {
+func calculateGlbLub(sourceRange, targetRange string) (string, error) {
return "", nil
}
-/*
-SetExecLabel sets the SELinux label that the kernel will use for any programs
-that are executed by the current process thread, or an error.
-*/
-func SetExecLabel(label string) error {
+func setExecLabel(label string) error {
return nil
}
-/*
-SetTaskLabel sets the SELinux label for the current thread, or an error.
-This requires the dyntransition permission.
-*/
-func SetTaskLabel(label string) error {
+func setTaskLabel(label string) error {
return nil
}
-/*
-SetSocketLabel sets the SELinux label that the kernel will use for any programs
-that are executed by the current process thread, or an error.
-*/
-func SetSocketLabel(label string) error {
+func setSocketLabel(label string) error {
return nil
}
-// SocketLabel retrieves the current socket label setting
-func SocketLabel() (string, error) {
+func socketLabel() (string, error) {
return "", nil
}
-// PeerLabel retrieves the label of the client on the other side of a socket
-func PeerLabel(fd uintptr) (string, error) {
+func peerLabel(fd uintptr) (string, error) {
return "", nil
}
-// SetKeyLabel takes a process label and tells the kernel to assign the
-// label to the next kernel keyring that gets created
-func SetKeyLabel(label string) error {
+func setKeyLabel(label string) error {
return nil
}
-// KeyLabel retrieves the current kernel keyring label setting
-func KeyLabel() (string, error) {
+func keyLabel() (string, error) {
return "", nil
}
-// Get returns the Context as a string
-func (c Context) Get() string {
+func (c Context) get() string {
return ""
}
-// NewContext creates a new Context struct from the specified label
-func NewContext(label string) (Context, error) {
+func newContext(label string) (Context, error) {
c := make(Context)
return c, nil
}
-// ClearLabels clears all reserved MLS/MCS levels
-func ClearLabels() {
- return
+func clearLabels() {
}
-// ReserveLabel reserves the MLS/MCS level component of the specified label
-func ReserveLabel(label string) {
- return
+func reserveLabel(label string) {
}
-// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
-func EnforceMode() int {
+func enforceMode() int {
return Disabled
}
-/*
-SetEnforceMode sets the current SELinux mode Enforcing, Permissive.
-Disabled is not valid, since this needs to be set at boot time.
-*/
-func SetEnforceMode(mode int) error {
+func setEnforceMode(mode int) error {
return nil
}
-/*
-DefaultEnforceMode returns the systems default SELinux mode Enforcing,
-Permissive or Disabled. Note this is is just the default at boot time.
-EnforceMode tells you the systems current mode.
-*/
-func DefaultEnforceMode() int {
+func defaultEnforceMode() int {
return Disabled
}
-/*
-ReleaseLabel will unreserve the MLS/MCS Level field of the specified label.
-Allowing it to be used by another process.
-*/
-func ReleaseLabel(label string) {
- return
+func releaseLabel(label string) {
}
-// ROFileLabel returns the specified SELinux readonly file label
-func ROFileLabel() string {
+func roFileLabel() string {
return ""
}
-// KVMContainerLabels returns the default processLabel and mountLabel to be used
-// for kvm containers by the calling process.
-func KVMContainerLabels() (string, string) {
+func kvmContainerLabels() (string, string) {
return "", ""
}
-// InitContainerLabels returns the default processLabel and file labels to be
-// used for containers running an init system like systemd by the calling
-func InitContainerLabels() (string, string) {
+func initContainerLabels() (string, string) {
return "", ""
}
-/*
-ContainerLabels returns an allocated processLabel and fileLabel to be used for
-container labeling by the calling process.
-*/
-func ContainerLabels() (processLabel string, fileLabel string) {
+func containerLabels() (processLabel string, fileLabel string) {
return "", ""
}
-// SecurityCheckContext validates that the SELinux label is understood by the kernel
-func SecurityCheckContext(val string) error {
+func securityCheckContext(val string) error {
return nil
}
-/*
-CopyLevel returns a label with the MLS/MCS level from src label replaced on
-the dest label.
-*/
-func CopyLevel(src, dest string) (string, error) {
+func copyLevel(src, dest string) (string, error) {
return "", nil
}
-// Chcon changes the `fpath` file object to the SELinux label `label`.
-// If `fpath` is a directory and `recurse`` is true, Chcon will walk the
-// directory tree setting the label.
-func Chcon(fpath string, label string, recurse bool) error {
+func chcon(fpath string, label string, recurse bool) error {
return nil
}
-// DupSecOpt takes an SELinux process label and returns security options that
-// can be used to set the SELinux Type and Level for future container processes.
-func DupSecOpt(src string) ([]string, error) {
+func dupSecOpt(src string) ([]string, error) {
return nil, nil
}
-// DisableSecOpt returns a security opt that can be used to disable SELinux
-// labeling support for future container processes.
-func DisableSecOpt() []string {
+func disableSecOpt() []string {
return []string{"disable"}
}
diff --git a/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go b/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go
index 2ee0d0150..63fde1842 100644
--- a/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go
+++ b/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go
@@ -48,7 +48,11 @@ func WalkN(root string, walkFn WalkFunc, num int) error {
errCh := make(chan error, 1) // get the first error, ignore others
// Start walking a tree asap
- var err error
+ var (
+ err error
+ wg sync.WaitGroup
+ )
+ wg.Add(1)
go func() {
err = filepath.Walk(root, func(p string, info os.FileInfo, err error) error {
if err != nil {
@@ -68,9 +72,9 @@ func WalkN(root string, walkFn WalkFunc, num int) error {
if err == nil {
close(files)
}
+ wg.Done()
}()
- var wg sync.WaitGroup
wg.Add(num)
for i := 0; i < num; i++ {
go func() {
diff --git a/vendor/github.com/willf/bitset/.gitignore b/vendor/github.com/willf/bitset/.gitignore
new file mode 100644
index 000000000..5c204d28b
--- /dev/null
+++ b/vendor/github.com/willf/bitset/.gitignore
@@ -0,0 +1,26 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
+
+target
diff --git a/vendor/github.com/willf/bitset/.travis.yml b/vendor/github.com/willf/bitset/.travis.yml
new file mode 100644
index 000000000..094aa5ce0
--- /dev/null
+++ b/vendor/github.com/willf/bitset/.travis.yml
@@ -0,0 +1,37 @@
+language: go
+
+sudo: false
+
+branches:
+ except:
+ - release
+
+branches:
+ only:
+ - master
+ - travis
+
+go:
+ - "1.11.x"
+ - tip
+
+matrix:
+ allow_failures:
+ - go: tip
+
+before_install:
+ - if [ -n "$GH_USER" ]; then git config --global github.user ${GH_USER}; fi;
+ - if [ -n "$GH_TOKEN" ]; then git config --global github.token ${GH_TOKEN}; fi;
+ - go get github.com/mattn/goveralls
+
+before_script:
+ - make deps
+
+script:
+ - make qa
+
+after_failure:
+ - cat ./target/test/report.xml
+
+after_success:
+ - if [ "$TRAVIS_GO_VERSION" = "1.11.1" ]; then $HOME/gopath/bin/goveralls -covermode=count -coverprofile=target/report/coverage.out -service=travis-ci; fi;
diff --git a/vendor/github.com/willf/bitset/LICENSE b/vendor/github.com/willf/bitset/LICENSE
new file mode 100644
index 000000000..59cab8a93
--- /dev/null
+++ b/vendor/github.com/willf/bitset/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2014 Will Fitzgerald. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/willf/bitset/Makefile b/vendor/github.com/willf/bitset/Makefile
new file mode 100644
index 000000000..db8377106
--- /dev/null
+++ b/vendor/github.com/willf/bitset/Makefile
@@ -0,0 +1,191 @@
+# MAKEFILE
+#
+# @author Nicola Asuni <info@tecnick.com>
+# @link https://github.com/willf/bitset
+# ------------------------------------------------------------------------------
+
+# List special make targets that are not associated with files
+.PHONY: help all test format fmtcheck vet lint coverage cyclo ineffassign misspell structcheck varcheck errcheck gosimple astscan qa deps clean nuke
+
+# Use bash as shell (Note: Ubuntu now uses dash which doesn't support PIPESTATUS).
+SHELL=/bin/bash
+
+# CVS path (path to the parent dir containing the project)
+CVSPATH=github.com/willf
+
+# Project owner
+OWNER=willf
+
+# Project vendor
+VENDOR=willf
+
+# Project name
+PROJECT=bitset
+
+# Project version
+VERSION=$(shell cat VERSION)
+
+# Name of RPM or DEB package
+PKGNAME=${VENDOR}-${PROJECT}
+
+# Current directory
+CURRENTDIR=$(shell pwd)
+
+# GO lang path
+ifneq ($(GOPATH),)
+ ifeq ($(findstring $(GOPATH),$(CURRENTDIR)),)
+ # the defined GOPATH is not valid
+ GOPATH=
+ endif
+endif
+ifeq ($(GOPATH),)
+ # extract the GOPATH
+ GOPATH=$(firstword $(subst /src/, ,$(CURRENTDIR)))
+endif
+
+# --- MAKE TARGETS ---
+
+# Display general help about this command
+help:
+ @echo ""
+ @echo "$(PROJECT) Makefile."
+ @echo "GOPATH=$(GOPATH)"
+ @echo "The following commands are available:"
+ @echo ""
+ @echo " make qa : Run all the tests"
+ @echo " make test : Run the unit tests"
+ @echo ""
+ @echo " make format : Format the source code"
+ @echo " make fmtcheck : Check if the source code has been formatted"
+ @echo " make vet : Check for suspicious constructs"
+ @echo " make lint : Check for style errors"
+ @echo " make coverage : Generate the coverage report"
+ @echo " make cyclo : Generate the cyclomatic complexity report"
+ @echo " make ineffassign : Detect ineffectual assignments"
+ @echo " make misspell : Detect commonly misspelled words in source files"
+ @echo " make structcheck : Find unused struct fields"
+ @echo " make varcheck : Find unused global variables and constants"
+ @echo " make errcheck : Check that error return values are used"
+ @echo " make gosimple : Suggest code simplifications"
+ @echo " make astscan : GO AST scanner"
+ @echo ""
+ @echo " make docs : Generate source code documentation"
+ @echo ""
+ @echo " make deps : Get the dependencies"
+ @echo " make clean : Remove any build artifact"
+ @echo " make nuke : Deletes any intermediate file"
+ @echo ""
+
+# Alias for help target
+all: help
+
+# Run the unit tests
+test:
+ @mkdir -p target/test
+ @mkdir -p target/report
+ GOPATH=$(GOPATH) \
+ go test \
+ -covermode=atomic \
+ -bench=. \
+ -race \
+ -cpuprofile=target/report/cpu.out \
+ -memprofile=target/report/mem.out \
+ -mutexprofile=target/report/mutex.out \
+ -coverprofile=target/report/coverage.out \
+ -v ./... | \
+ tee >(PATH=$(GOPATH)/bin:$(PATH) go-junit-report > target/test/report.xml); \
+ test $${PIPESTATUS[0]} -eq 0
+
+# Format the source code
+format:
+ @find . -type f -name "*.go" -exec gofmt -s -w {} \;
+
+# Check if the source code has been formatted
+fmtcheck:
+ @mkdir -p target
+ @find . -type f -name "*.go" -exec gofmt -s -d {} \; | tee target/format.diff
+ @test ! -s target/format.diff || { echo "ERROR: the source code has not been formatted - please use 'make format' or 'gofmt'"; exit 1; }
+
+# Check for syntax errors
+vet:
+ GOPATH=$(GOPATH) go vet .
+
+# Check for style errors
+lint:
+ GOPATH=$(GOPATH) PATH=$(GOPATH)/bin:$(PATH) golint .
+
+# Generate the coverage report
+coverage:
+ @mkdir -p target/report
+ GOPATH=$(GOPATH) \
+ go tool cover -html=target/report/coverage.out -o target/report/coverage.html
+
+# Report cyclomatic complexity
+cyclo:
+ @mkdir -p target/report
+ GOPATH=$(GOPATH) gocyclo -avg ./ | tee target/report/cyclo.txt ; test $${PIPESTATUS[0]} -eq 0
+
+# Detect ineffectual assignments
+ineffassign:
+ @mkdir -p target/report
+ GOPATH=$(GOPATH) ineffassign ./ | tee target/report/ineffassign.txt ; test $${PIPESTATUS[0]} -eq 0
+
+# Detect commonly misspelled words in source files
+misspell:
+ @mkdir -p target/report
+ GOPATH=$(GOPATH) misspell -error ./ | tee target/report/misspell.txt ; test $${PIPESTATUS[0]} -eq 0
+
+# Find unused struct fields
+structcheck:
+ @mkdir -p target/report
+ GOPATH=$(GOPATH) structcheck -a ./ | tee target/report/structcheck.txt
+
+# Find unused global variables and constants
+varcheck:
+ @mkdir -p target/report
+ GOPATH=$(GOPATH) varcheck -e ./ | tee target/report/varcheck.txt
+
+# Check that error return values are used
+errcheck:
+ @mkdir -p target/report
+ GOPATH=$(GOPATH) errcheck ./ | tee target/report/errcheck.txt
+
+# AST scanner
+astscan:
+ @mkdir -p target/report
+ GOPATH=$(GOPATH) gosec . | tee target/report/astscan.txt ; test $${PIPESTATUS[0]} -eq 0 || true
+
+# Generate source docs
+docs:
+ @mkdir -p target/docs
+ nohup sh -c 'GOPATH=$(GOPATH) godoc -http=127.0.0.1:6060' > target/godoc_server.log 2>&1 &
+ wget --directory-prefix=target/docs/ --execute robots=off --retry-connrefused --recursive --no-parent --adjust-extension --page-requisites --convert-links http://127.0.0.1:6060/pkg/github.com/${VENDOR}/${PROJECT}/ ; kill -9 `lsof -ti :6060`
+ @echo '<html><head><meta http-equiv="refresh" content="0;./127.0.0.1:6060/pkg/'${CVSPATH}'/'${PROJECT}'/index.html"/></head><a href="./127.0.0.1:6060/pkg/'${CVSPATH}'/'${PROJECT}'/index.html">'${PKGNAME}' Documentation ...</a></html>' > target/docs/index.html
+
+# Alias to run all quality-assurance checks
+qa: fmtcheck test vet lint coverage cyclo ineffassign misspell structcheck varcheck errcheck gosimple astscan
+
+# --- INSTALL ---
+
+# Get the dependencies
+deps:
+ GOPATH=$(GOPATH) go get ./...
+ GOPATH=$(GOPATH) go get golang.org/x/lint/golint
+ GOPATH=$(GOPATH) go get github.com/jstemmer/go-junit-report
+ GOPATH=$(GOPATH) go get github.com/axw/gocov/gocov
+ GOPATH=$(GOPATH) go get github.com/fzipp/gocyclo
+ GOPATH=$(GOPATH) go get github.com/gordonklaus/ineffassign
+ GOPATH=$(GOPATH) go get github.com/client9/misspell/cmd/misspell
+ GOPATH=$(GOPATH) go get github.com/opennota/check/cmd/structcheck
+ GOPATH=$(GOPATH) go get github.com/opennota/check/cmd/varcheck
+ GOPATH=$(GOPATH) go get github.com/kisielk/errcheck
+ GOPATH=$(GOPATH) go get github.com/securego/gosec/cmd/gosec/...
+
+# Remove any build artifact
+clean:
+ GOPATH=$(GOPATH) go clean ./...
+
+# Deletes any intermediate file
+nuke:
+ rm -rf ./target
+ GOPATH=$(GOPATH) go clean -i ./...
diff --git a/vendor/github.com/willf/bitset/README.md b/vendor/github.com/willf/bitset/README.md
new file mode 100644
index 000000000..6c62b20c6
--- /dev/null
+++ b/vendor/github.com/willf/bitset/README.md
@@ -0,0 +1,96 @@
+# bitset
+
+*Go language library to map between non-negative integers and boolean values*
+
+[![Master Build Status](https://secure.travis-ci.org/willf/bitset.png?branch=master)](https://travis-ci.org/willf/bitset?branch=master)
+[![Master Coverage Status](https://coveralls.io/repos/willf/bitset/badge.svg?branch=master&service=github)](https://coveralls.io/github/willf/bitset?branch=master)
+[![Go Report Card](https://goreportcard.com/badge/github.com/willf/bitset)](https://goreportcard.com/report/github.com/willf/bitset)
+[![GoDoc](https://godoc.org/github.com/willf/bitset?status.svg)](http://godoc.org/github.com/willf/bitset)
+
+
+## Description
+
+Package bitset implements bitsets, a mapping between non-negative integers and boolean values.
+It should be more efficient than map[uint] bool.
+
+It provides methods for setting, clearing, flipping, and testing individual integers.
+
+But it also provides set intersection, union, difference, complement, and symmetric operations, as well as tests to check whether any, all, or no bits are set, and querying a bitset's current length and number of positive bits.
+
+BitSets are expanded to the size of the largest set bit; the memory allocation is approximately Max bits, where Max is the largest set bit. BitSets are never shrunk. On creation, a hint can be given for the number of bits that will be used.
+
+Many of the methods, including Set, Clear, and Flip, return a BitSet pointer, which allows for chaining.
+
+### Example use:
+
+```go
+package main
+
+import (
+ "fmt"
+ "math/rand"
+
+ "github.com/willf/bitset"
+)
+
+func main() {
+ fmt.Printf("Hello from BitSet!\n")
+ var b bitset.BitSet
+ // play some Go Fish
+ for i := 0; i < 100; i++ {
+ card1 := uint(rand.Intn(52))
+ card2 := uint(rand.Intn(52))
+ b.Set(card1)
+ if b.Test(card2) {
+ fmt.Println("Go Fish!")
+ }
+ b.Clear(card1)
+ }
+
+ // Chaining
+ b.Set(10).Set(11)
+
+ for i, e := b.NextSet(0); e; i, e = b.NextSet(i + 1) {
+ fmt.Println("The following bit is set:", i)
+ }
+ if b.Intersection(bitset.New(100).Set(10)).Count() == 1 {
+ fmt.Println("Intersection works.")
+ } else {
+ fmt.Println("Intersection doesn't work???")
+ }
+}
+```
+
+As an alternative to BitSets, one should check out the 'big' package, which provides a (less set-theoretical) view of bitsets.
+
+Godoc documentation is at: https://godoc.org/github.com/willf/bitset
+
+
+## Implementation Note
+
+Go 1.9 introduced a native `math/bits` library. We provide backward compatibility to Go 1.7, which might be removed.
+
+It is possible that a later version will match the `math/bits` return signature for counts (which is `int`, rather than our library's `unit64`). If so, the version will be bumped.
+
+## Installation
+
+```bash
+go get github.com/willf/bitset
+```
+
+## Contributing
+
+If you wish to contribute to this project, please branch and issue a pull request against master ("[GitHub Flow](https://guides.github.com/introduction/flow/)")
+
+This project include a Makefile that allows you to test and build the project with simple commands.
+To see all available options:
+```bash
+make help
+```
+
+## Running all tests
+
+Before committing the code, please check if it passes all tests using (note: this will install some dependencies):
+```bash
+make qa
+```
diff --git a/vendor/github.com/willf/bitset/azure-pipelines.yml b/vendor/github.com/willf/bitset/azure-pipelines.yml
new file mode 100644
index 000000000..f9b295918
--- /dev/null
+++ b/vendor/github.com/willf/bitset/azure-pipelines.yml
@@ -0,0 +1,39 @@
+# Go
+# Build your Go project.
+# Add steps that test, save build artifacts, deploy, and more:
+# https://docs.microsoft.com/azure/devops/pipelines/languages/go
+
+trigger:
+- master
+
+pool:
+ vmImage: 'Ubuntu-16.04'
+
+variables:
+ GOBIN: '$(GOPATH)/bin' # Go binaries path
+ GOROOT: '/usr/local/go1.11' # Go installation path
+ GOPATH: '$(system.defaultWorkingDirectory)/gopath' # Go workspace path
+ modulePath: '$(GOPATH)/src/github.com/$(build.repository.name)' # Path to the module's code
+
+steps:
+- script: |
+ mkdir -p '$(GOBIN)'
+ mkdir -p '$(GOPATH)/pkg'
+ mkdir -p '$(modulePath)'
+ shopt -s extglob
+ shopt -s dotglob
+ mv !(gopath) '$(modulePath)'
+ echo '##vso[task.prependpath]$(GOBIN)'
+ echo '##vso[task.prependpath]$(GOROOT)/bin'
+ displayName: 'Set up the Go workspace'
+
+- script: |
+ go version
+ go get -v -t -d ./...
+ if [ -f Gopkg.toml ]; then
+ curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
+ dep ensure
+ fi
+ go build -v .
+ workingDirectory: '$(modulePath)'
+ displayName: 'Get dependencies, then build'
diff --git a/vendor/github.com/willf/bitset/bitset.go b/vendor/github.com/willf/bitset/bitset.go
new file mode 100644
index 000000000..22e5d42e5
--- /dev/null
+++ b/vendor/github.com/willf/bitset/bitset.go
@@ -0,0 +1,879 @@
+/*
+Package bitset implements bitsets, a mapping
+between non-negative integers and boolean values. It should be more
+efficient than map[uint] bool.
+
+It provides methods for setting, clearing, flipping, and testing
+individual integers.
+
+But it also provides set intersection, union, difference,
+complement, and symmetric operations, as well as tests to
+check whether any, all, or no bits are set, and querying a
+bitset's current length and number of positive bits.
+
+BitSets are expanded to the size of the largest set bit; the
+memory allocation is approximately Max bits, where Max is
+the largest set bit. BitSets are never shrunk. On creation,
+a hint can be given for the number of bits that will be used.
+
+Many of the methods, including Set,Clear, and Flip, return
+a BitSet pointer, which allows for chaining.
+
+Example use:
+
+ import "bitset"
+ var b BitSet
+ b.Set(10).Set(11)
+ if b.Test(1000) {
+ b.Clear(1000)
+ }
+ if B.Intersection(bitset.New(100).Set(10)).Count() > 1 {
+ fmt.Println("Intersection works.")
+ }
+
+As an alternative to BitSets, one should check out the 'big' package,
+which provides a (less set-theoretical) view of bitsets.
+
+*/
+package bitset
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/base64"
+ "encoding/binary"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "strconv"
+)
+
+// the wordSize of a bit set
+const wordSize = uint(64)
+
+// log2WordSize is lg(wordSize)
+const log2WordSize = uint(6)
+
+// allBits has every bit set
+const allBits uint64 = 0xffffffffffffffff
+
+// default binary BigEndian
+var binaryOrder binary.ByteOrder = binary.BigEndian
+
+// default json encoding base64.URLEncoding
+var base64Encoding = base64.URLEncoding
+
+// Base64StdEncoding Marshal/Unmarshal BitSet with base64.StdEncoding(Default: base64.URLEncoding)
+func Base64StdEncoding() { base64Encoding = base64.StdEncoding }
+
+// LittleEndian Marshal/Unmarshal Binary as Little Endian(Default: binary.BigEndian)
+func LittleEndian() { binaryOrder = binary.LittleEndian }
+
+// A BitSet is a set of bits. The zero value of a BitSet is an empty set of length 0.
+type BitSet struct {
+ length uint
+ set []uint64
+}
+
+// Error is used to distinguish errors (panics) generated in this package.
+type Error string
+
+// safeSet will fixup b.set to be non-nil and return the field value
+func (b *BitSet) safeSet() []uint64 {
+ if b.set == nil {
+ b.set = make([]uint64, wordsNeeded(0))
+ }
+ return b.set
+}
+
+// From is a constructor used to create a BitSet from an array of integers
+func From(buf []uint64) *BitSet {
+ return &BitSet{uint(len(buf)) * 64, buf}
+}
+
+// Bytes returns the bitset as array of integers
+func (b *BitSet) Bytes() []uint64 {
+ return b.set
+}
+
+// wordsNeeded calculates the number of words needed for i bits
+func wordsNeeded(i uint) int {
+ if i > (Cap() - wordSize + 1) {
+ return int(Cap() >> log2WordSize)
+ }
+ return int((i + (wordSize - 1)) >> log2WordSize)
+}
+
+// New creates a new BitSet with a hint that length bits will be required
+func New(length uint) (bset *BitSet) {
+ defer func() {
+ if r := recover(); r != nil {
+ bset = &BitSet{
+ 0,
+ make([]uint64, 0),
+ }
+ }
+ }()
+
+ bset = &BitSet{
+ length,
+ make([]uint64, wordsNeeded(length)),
+ }
+
+ return bset
+}
+
+// Cap returns the total possible capacity, or number of bits
+func Cap() uint {
+ return ^uint(0)
+}
+
+// Len returns the number of bits in the BitSet.
+// Note the difference to method Count, see example.
+func (b *BitSet) Len() uint {
+ return b.length
+}
+
+// extendSetMaybe adds additional words to incorporate new bits if needed
+func (b *BitSet) extendSetMaybe(i uint) {
+ if i >= b.length { // if we need more bits, make 'em
+ nsize := wordsNeeded(i + 1)
+ if b.set == nil {
+ b.set = make([]uint64, nsize)
+ } else if cap(b.set) >= nsize {
+ b.set = b.set[:nsize] // fast resize
+ } else if len(b.set) < nsize {
+ newset := make([]uint64, nsize, 2*nsize) // increase capacity 2x
+ copy(newset, b.set)
+ b.set = newset
+ }
+ b.length = i + 1
+ }
+}
+
+// Test whether bit i is set.
+func (b *BitSet) Test(i uint) bool {
+ if i >= b.length {
+ return false
+ }
+ return b.set[i>>log2WordSize]&(1<<(i&(wordSize-1))) != 0
+}
+
+// Set bit i to 1
+func (b *BitSet) Set(i uint) *BitSet {
+ b.extendSetMaybe(i)
+ b.set[i>>log2WordSize] |= 1 << (i & (wordSize - 1))
+ return b
+}
+
+// Clear bit i to 0
+func (b *BitSet) Clear(i uint) *BitSet {
+ if i >= b.length {
+ return b
+ }
+ b.set[i>>log2WordSize] &^= 1 << (i & (wordSize - 1))
+ return b
+}
+
+// SetTo sets bit i to value
+func (b *BitSet) SetTo(i uint, value bool) *BitSet {
+ if value {
+ return b.Set(i)
+ }
+ return b.Clear(i)
+}
+
+// Flip bit at i
+func (b *BitSet) Flip(i uint) *BitSet {
+ if i >= b.length {
+ return b.Set(i)
+ }
+ b.set[i>>log2WordSize] ^= 1 << (i & (wordSize - 1))
+ return b
+}
+
+// Shrink shrinks BitSet to desired length in bits. It clears all bits > length
+// and reduces the size and length of the set.
+//
+// A new slice is allocated to store the new bits, so you may see an increase in
+// memory usage until the GC runs. Normally this should not be a problem, but if you
+// have an extremely large BitSet its important to understand that the old BitSet will
+// remain in memory until the GC frees it.
+func (b *BitSet) Shrink(length uint) *BitSet {
+ idx := wordsNeeded(length + 1)
+ if idx > len(b.set) {
+ return b
+ }
+ shrunk := make([]uint64, idx)
+ copy(shrunk, b.set[:idx])
+ b.set = shrunk
+ b.length = length + 1
+ b.set[idx-1] &= (allBits >> (uint64(64) - uint64(length&(wordSize-1)) - 1))
+ return b
+}
+
+// InsertAt takes an index which indicates where a bit should be
+// inserted. Then it shifts all the bits in the set to the left by 1, starting
+// from the given index position, and sets the index position to 0.
+//
+// Depending on the size of your BitSet, and where you are inserting the new entry,
+// this method could be extremely slow and in some cases might cause the entire BitSet
+// to be recopied.
+func (b *BitSet) InsertAt(idx uint) *BitSet {
+ insertAtElement := (idx >> log2WordSize)
+
+ // if length of set is a multiple of wordSize we need to allocate more space first
+ if b.isLenExactMultiple() {
+ b.set = append(b.set, uint64(0))
+ }
+
+ var i uint
+ for i = uint(len(b.set) - 1); i > insertAtElement; i-- {
+ // all elements above the position where we want to insert can simply by shifted
+ b.set[i] <<= 1
+
+ // we take the most significant bit of the previous element and set it as
+ // the least significant bit of the current element
+ b.set[i] |= (b.set[i-1] & 0x8000000000000000) >> 63
+ }
+
+ // generate a mask to extract the data that we need to shift left
+ // within the element where we insert a bit
+ dataMask := ^(uint64(1)<<uint64(idx&(wordSize-1)) - 1)
+
+ // extract that data that we'll shift
+ data := b.set[i] & dataMask
+
+ // set the positions of the data mask to 0 in the element where we insert
+ b.set[i] &= ^dataMask
+
+ // shift data mask to the left and insert its data to the slice element
+ b.set[i] |= data << 1
+
+ // add 1 to length of BitSet
+ b.length++
+
+ return b
+}
+
+// String creates a string representation of the Bitmap
+func (b *BitSet) String() string {
+ // follows code from https://github.com/RoaringBitmap/roaring
+ var buffer bytes.Buffer
+ start := []byte("{")
+ buffer.Write(start)
+ counter := 0
+ i, e := b.NextSet(0)
+ for e {
+ counter = counter + 1
+ // to avoid exhausting the memory
+ if counter > 0x40000 {
+ buffer.WriteString("...")
+ break
+ }
+ buffer.WriteString(strconv.FormatInt(int64(i), 10))
+ i, e = b.NextSet(i + 1)
+ if e {
+ buffer.WriteString(",")
+ }
+ }
+ buffer.WriteString("}")
+ return buffer.String()
+}
+
+// DeleteAt deletes the bit at the given index position from
+// within the bitset
+// All the bits residing on the left of the deleted bit get
+// shifted right by 1
+// The running time of this operation may potentially be
+// relatively slow, O(length)
+func (b *BitSet) DeleteAt(i uint) *BitSet {
+ // the index of the slice element where we'll delete a bit
+ deleteAtElement := i >> log2WordSize
+
+ // generate a mask for the data that needs to be shifted right
+ // within that slice element that gets modified
+ dataMask := ^((uint64(1) << (i & (wordSize - 1))) - 1)
+
+ // extract the data that we'll shift right from the slice element
+ data := b.set[deleteAtElement] & dataMask
+
+ // set the masked area to 0 while leaving the rest as it is
+ b.set[deleteAtElement] &= ^dataMask
+
+ // shift the previously extracted data to the right and then
+ // set it in the previously masked area
+ b.set[deleteAtElement] |= (data >> 1) & dataMask
+
+ // loop over all the consecutive slice elements to copy each
+ // lowest bit into the highest position of the previous element,
+ // then shift the entire content to the right by 1
+ for i := int(deleteAtElement) + 1; i < len(b.set); i++ {
+ b.set[i-1] |= (b.set[i] & 1) << 63
+ b.set[i] >>= 1
+ }
+
+ b.length = b.length - 1
+
+ return b
+}
+
+// NextSet returns the next bit set from the specified index,
+// including possibly the current index
+// along with an error code (true = valid, false = no set bit found)
+// for i,e := v.NextSet(0); e; i,e = v.NextSet(i + 1) {...}
+func (b *BitSet) NextSet(i uint) (uint, bool) {
+ x := int(i >> log2WordSize)
+ if x >= len(b.set) {
+ return 0, false
+ }
+ w := b.set[x]
+ w = w >> (i & (wordSize - 1))
+ if w != 0 {
+ return i + trailingZeroes64(w), true
+ }
+ x = x + 1
+ for x < len(b.set) {
+ if b.set[x] != 0 {
+ return uint(x)*wordSize + trailingZeroes64(b.set[x]), true
+ }
+ x = x + 1
+
+ }
+ return 0, false
+}
+
+// NextSetMany returns many next bit sets from the specified index,
+// including possibly the current index and up to cap(buffer).
+// If the returned slice has len zero, then no more set bits were found
+//
+// buffer := make([]uint, 256) // this should be reused
+// j := uint(0)
+// j, buffer = bitmap.NextSetMany(j, buffer)
+// for ; len(buffer) > 0; j, buffer = bitmap.NextSetMany(j,buffer) {
+// for k := range buffer {
+// do something with buffer[k]
+// }
+// j += 1
+// }
+//
+func (b *BitSet) NextSetMany(i uint, buffer []uint) (uint, []uint) {
+ myanswer := buffer
+ capacity := cap(buffer)
+ x := int(i >> log2WordSize)
+ if x >= len(b.set) || capacity == 0 {
+ return 0, myanswer[:0]
+ }
+ skip := i & (wordSize - 1)
+ word := b.set[x] >> skip
+ myanswer = myanswer[:capacity]
+ size := int(0)
+ for word != 0 {
+ r := trailingZeroes64(word)
+ t := word & ((^word) + 1)
+ myanswer[size] = r + i
+ size++
+ if size == capacity {
+ goto End
+ }
+ word = word ^ t
+ }
+ x++
+ for idx, word := range b.set[x:] {
+ for word != 0 {
+ r := trailingZeroes64(word)
+ t := word & ((^word) + 1)
+ myanswer[size] = r + (uint(x+idx) << 6)
+ size++
+ if size == capacity {
+ goto End
+ }
+ word = word ^ t
+ }
+ }
+End:
+ if size > 0 {
+ return myanswer[size-1], myanswer[:size]
+ }
+ return 0, myanswer[:0]
+}
+
+// NextClear returns the next clear bit from the specified index,
+// including possibly the current index
+// along with an error code (true = valid, false = no bit found i.e. all bits are set)
+func (b *BitSet) NextClear(i uint) (uint, bool) {
+ x := int(i >> log2WordSize)
+ if x >= len(b.set) {
+ return 0, false
+ }
+ w := b.set[x]
+ w = w >> (i & (wordSize - 1))
+ wA := allBits >> (i & (wordSize - 1))
+ index := i + trailingZeroes64(^w)
+ if w != wA && index < b.length {
+ return index, true
+ }
+ x++
+ for x < len(b.set) {
+ index = uint(x)*wordSize + trailingZeroes64(^b.set[x])
+ if b.set[x] != allBits && index < b.length {
+ return index, true
+ }
+ x++
+ }
+ return 0, false
+}
+
+// ClearAll clears the entire BitSet
+func (b *BitSet) ClearAll() *BitSet {
+ if b != nil && b.set != nil {
+ for i := range b.set {
+ b.set[i] = 0
+ }
+ }
+ return b
+}
+
+// wordCount returns the number of words used in a bit set
+func (b *BitSet) wordCount() int {
+ return len(b.set)
+}
+
+// Clone this BitSet
+func (b *BitSet) Clone() *BitSet {
+ c := New(b.length)
+ if b.set != nil { // Clone should not modify current object
+ copy(c.set, b.set)
+ }
+ return c
+}
+
+// Copy into a destination BitSet
+// Returning the size of the destination BitSet
+// like array copy
+func (b *BitSet) Copy(c *BitSet) (count uint) {
+ if c == nil {
+ return
+ }
+ if b.set != nil { // Copy should not modify current object
+ copy(c.set, b.set)
+ }
+ count = c.length
+ if b.length < c.length {
+ count = b.length
+ }
+ return
+}
+
+// Count (number of set bits).
+// Also known as "popcount" or "popularity count".
+func (b *BitSet) Count() uint {
+ if b != nil && b.set != nil {
+ return uint(popcntSlice(b.set))
+ }
+ return 0
+}
+
+// Equal tests the equivalence of two BitSets.
+// False if they are of different sizes, otherwise true
+// only if all the same bits are set
+func (b *BitSet) Equal(c *BitSet) bool {
+ if c == nil || b == nil {
+ return c == b
+ }
+ if b.length != c.length {
+ return false
+ }
+ if b.length == 0 { // if they have both length == 0, then could have nil set
+ return true
+ }
+ // testing for equality shoud not transform the bitset (no call to safeSet)
+
+ for p, v := range b.set {
+ if c.set[p] != v {
+ return false
+ }
+ }
+ return true
+}
+
+func panicIfNull(b *BitSet) {
+ if b == nil {
+ panic(Error("BitSet must not be null"))
+ }
+}
+
+// Difference of base set and other set
+// This is the BitSet equivalent of &^ (and not)
+func (b *BitSet) Difference(compare *BitSet) (result *BitSet) {
+ panicIfNull(b)
+ panicIfNull(compare)
+ result = b.Clone() // clone b (in case b is bigger than compare)
+ l := int(compare.wordCount())
+ if l > int(b.wordCount()) {
+ l = int(b.wordCount())
+ }
+ for i := 0; i < l; i++ {
+ result.set[i] = b.set[i] &^ compare.set[i]
+ }
+ return
+}
+
+// DifferenceCardinality computes the cardinality of the differnce
+func (b *BitSet) DifferenceCardinality(compare *BitSet) uint {
+ panicIfNull(b)
+ panicIfNull(compare)
+ l := int(compare.wordCount())
+ if l > int(b.wordCount()) {
+ l = int(b.wordCount())
+ }
+ cnt := uint64(0)
+ cnt += popcntMaskSlice(b.set[:l], compare.set[:l])
+ cnt += popcntSlice(b.set[l:])
+ return uint(cnt)
+}
+
+// InPlaceDifference computes the difference of base set and other set
+// This is the BitSet equivalent of &^ (and not)
+func (b *BitSet) InPlaceDifference(compare *BitSet) {
+ panicIfNull(b)
+ panicIfNull(compare)
+ l := int(compare.wordCount())
+ if l > int(b.wordCount()) {
+ l = int(b.wordCount())
+ }
+ for i := 0; i < l; i++ {
+ b.set[i] &^= compare.set[i]
+ }
+}
+
+// Convenience function: return two bitsets ordered by
+// increasing length. Note: neither can be nil
+func sortByLength(a *BitSet, b *BitSet) (ap *BitSet, bp *BitSet) {
+ if a.length <= b.length {
+ ap, bp = a, b
+ } else {
+ ap, bp = b, a
+ }
+ return
+}
+
+// Intersection of base set and other set
+// This is the BitSet equivalent of & (and)
+func (b *BitSet) Intersection(compare *BitSet) (result *BitSet) {
+ panicIfNull(b)
+ panicIfNull(compare)
+ b, compare = sortByLength(b, compare)
+ result = New(b.length)
+ for i, word := range b.set {
+ result.set[i] = word & compare.set[i]
+ }
+ return
+}
+
+// IntersectionCardinality computes the cardinality of the union
+func (b *BitSet) IntersectionCardinality(compare *BitSet) uint {
+ panicIfNull(b)
+ panicIfNull(compare)
+ b, compare = sortByLength(b, compare)
+ cnt := popcntAndSlice(b.set, compare.set)
+ return uint(cnt)
+}
+
+// InPlaceIntersection destructively computes the intersection of
+// base set and the compare set.
+// This is the BitSet equivalent of & (and)
+func (b *BitSet) InPlaceIntersection(compare *BitSet) {
+ panicIfNull(b)
+ panicIfNull(compare)
+ l := int(compare.wordCount())
+ if l > int(b.wordCount()) {
+ l = int(b.wordCount())
+ }
+ for i := 0; i < l; i++ {
+ b.set[i] &= compare.set[i]
+ }
+ for i := l; i < len(b.set); i++ {
+ b.set[i] = 0
+ }
+ if compare.length > 0 {
+ b.extendSetMaybe(compare.length - 1)
+ }
+}
+
+// Union of base set and other set
+// This is the BitSet equivalent of | (or)
+func (b *BitSet) Union(compare *BitSet) (result *BitSet) {
+ panicIfNull(b)
+ panicIfNull(compare)
+ b, compare = sortByLength(b, compare)
+ result = compare.Clone()
+ for i, word := range b.set {
+ result.set[i] = word | compare.set[i]
+ }
+ return
+}
+
+// UnionCardinality computes the cardinality of the uniton of the base set
+// and the compare set.
+func (b *BitSet) UnionCardinality(compare *BitSet) uint {
+ panicIfNull(b)
+ panicIfNull(compare)
+ b, compare = sortByLength(b, compare)
+ cnt := popcntOrSlice(b.set, compare.set)
+ if len(compare.set) > len(b.set) {
+ cnt += popcntSlice(compare.set[len(b.set):])
+ }
+ return uint(cnt)
+}
+
+// InPlaceUnion creates the destructive union of base set and compare set.
+// This is the BitSet equivalent of | (or).
+func (b *BitSet) InPlaceUnion(compare *BitSet) {
+ panicIfNull(b)
+ panicIfNull(compare)
+ l := int(compare.wordCount())
+ if l > int(b.wordCount()) {
+ l = int(b.wordCount())
+ }
+ if compare.length > 0 {
+ b.extendSetMaybe(compare.length - 1)
+ }
+ for i := 0; i < l; i++ {
+ b.set[i] |= compare.set[i]
+ }
+ if len(compare.set) > l {
+ for i := l; i < len(compare.set); i++ {
+ b.set[i] = compare.set[i]
+ }
+ }
+}
+
+// SymmetricDifference of base set and other set
+// This is the BitSet equivalent of ^ (xor)
+func (b *BitSet) SymmetricDifference(compare *BitSet) (result *BitSet) {
+ panicIfNull(b)
+ panicIfNull(compare)
+ b, compare = sortByLength(b, compare)
+ // compare is bigger, so clone it
+ result = compare.Clone()
+ for i, word := range b.set {
+ result.set[i] = word ^ compare.set[i]
+ }
+ return
+}
+
+// SymmetricDifferenceCardinality computes the cardinality of the symmetric difference
+func (b *BitSet) SymmetricDifferenceCardinality(compare *BitSet) uint {
+ panicIfNull(b)
+ panicIfNull(compare)
+ b, compare = sortByLength(b, compare)
+ cnt := popcntXorSlice(b.set, compare.set)
+ if len(compare.set) > len(b.set) {
+ cnt += popcntSlice(compare.set[len(b.set):])
+ }
+ return uint(cnt)
+}
+
+// InPlaceSymmetricDifference creates the destructive SymmetricDifference of base set and other set
+// This is the BitSet equivalent of ^ (xor)
+func (b *BitSet) InPlaceSymmetricDifference(compare *BitSet) {
+ panicIfNull(b)
+ panicIfNull(compare)
+ l := int(compare.wordCount())
+ if l > int(b.wordCount()) {
+ l = int(b.wordCount())
+ }
+ if compare.length > 0 {
+ b.extendSetMaybe(compare.length - 1)
+ }
+ for i := 0; i < l; i++ {
+ b.set[i] ^= compare.set[i]
+ }
+ if len(compare.set) > l {
+ for i := l; i < len(compare.set); i++ {
+ b.set[i] = compare.set[i]
+ }
+ }
+}
+
+// Is the length an exact multiple of word sizes?
+func (b *BitSet) isLenExactMultiple() bool {
+ return b.length%wordSize == 0
+}
+
+// Clean last word by setting unused bits to 0
+func (b *BitSet) cleanLastWord() {
+ if !b.isLenExactMultiple() {
+ b.set[len(b.set)-1] &= allBits >> (wordSize - b.length%wordSize)
+ }
+}
+
+// Complement computes the (local) complement of a biset (up to length bits)
+func (b *BitSet) Complement() (result *BitSet) {
+ panicIfNull(b)
+ result = New(b.length)
+ for i, word := range b.set {
+ result.set[i] = ^word
+ }
+ result.cleanLastWord()
+ return
+}
+
+// All returns true if all bits are set, false otherwise. Returns true for
+// empty sets.
+func (b *BitSet) All() bool {
+ panicIfNull(b)
+ return b.Count() == b.length
+}
+
+// None returns true if no bit is set, false otherwise. Returns true for
+// empty sets.
+func (b *BitSet) None() bool {
+ panicIfNull(b)
+ if b != nil && b.set != nil {
+ for _, word := range b.set {
+ if word > 0 {
+ return false
+ }
+ }
+ return true
+ }
+ return true
+}
+
+// Any returns true if any bit is set, false otherwise
+func (b *BitSet) Any() bool {
+ panicIfNull(b)
+ return !b.None()
+}
+
+// IsSuperSet returns true if this is a superset of the other set
+func (b *BitSet) IsSuperSet(other *BitSet) bool {
+ for i, e := other.NextSet(0); e; i, e = other.NextSet(i + 1) {
+ if !b.Test(i) {
+ return false
+ }
+ }
+ return true
+}
+
+// IsStrictSuperSet returns true if this is a strict superset of the other set
+func (b *BitSet) IsStrictSuperSet(other *BitSet) bool {
+ return b.Count() > other.Count() && b.IsSuperSet(other)
+}
+
+// DumpAsBits dumps a bit set as a string of bits
+func (b *BitSet) DumpAsBits() string {
+ if b.set == nil {
+ return "."
+ }
+ buffer := bytes.NewBufferString("")
+ i := len(b.set) - 1
+ for ; i >= 0; i-- {
+ fmt.Fprintf(buffer, "%064b.", b.set[i])
+ }
+ return buffer.String()
+}
+
+// BinaryStorageSize returns the binary storage requirements
+func (b *BitSet) BinaryStorageSize() int {
+ return binary.Size(uint64(0)) + binary.Size(b.set)
+}
+
+// WriteTo writes a BitSet to a stream
+func (b *BitSet) WriteTo(stream io.Writer) (int64, error) {
+ length := uint64(b.length)
+
+ // Write length
+ err := binary.Write(stream, binaryOrder, length)
+ if err != nil {
+ return 0, err
+ }
+
+ // Write set
+ err = binary.Write(stream, binaryOrder, b.set)
+ return int64(b.BinaryStorageSize()), err
+}
+
+// ReadFrom reads a BitSet from a stream written using WriteTo
+func (b *BitSet) ReadFrom(stream io.Reader) (int64, error) {
+ var length uint64
+
+ // Read length first
+ err := binary.Read(stream, binaryOrder, &length)
+ if err != nil {
+ return 0, err
+ }
+ newset := New(uint(length))
+
+ if uint64(newset.length) != length {
+ return 0, errors.New("Unmarshalling error: type mismatch")
+ }
+
+ // Read remaining bytes as set
+ err = binary.Read(stream, binaryOrder, newset.set)
+ if err != nil {
+ return 0, err
+ }
+
+ *b = *newset
+ return int64(b.BinaryStorageSize()), nil
+}
+
+// MarshalBinary encodes a BitSet into a binary form and returns the result.
+func (b *BitSet) MarshalBinary() ([]byte, error) {
+ var buf bytes.Buffer
+ writer := bufio.NewWriter(&buf)
+
+ _, err := b.WriteTo(writer)
+ if err != nil {
+ return []byte{}, err
+ }
+
+ err = writer.Flush()
+
+ return buf.Bytes(), err
+}
+
+// UnmarshalBinary decodes the binary form generated by MarshalBinary.
+func (b *BitSet) UnmarshalBinary(data []byte) error {
+ buf := bytes.NewReader(data)
+ reader := bufio.NewReader(buf)
+
+ _, err := b.ReadFrom(reader)
+
+ return err
+}
+
+// MarshalJSON marshals a BitSet as a JSON structure
+func (b *BitSet) MarshalJSON() ([]byte, error) {
+ buffer := bytes.NewBuffer(make([]byte, 0, b.BinaryStorageSize()))
+ _, err := b.WriteTo(buffer)
+ if err != nil {
+ return nil, err
+ }
+
+ // URLEncode all bytes
+ return json.Marshal(base64Encoding.EncodeToString(buffer.Bytes()))
+}
+
+// UnmarshalJSON unmarshals a BitSet from JSON created using MarshalJSON
+func (b *BitSet) UnmarshalJSON(data []byte) error {
+ // Unmarshal as string
+ var s string
+ err := json.Unmarshal(data, &s)
+ if err != nil {
+ return err
+ }
+
+ // URLDecode string
+ buf, err := base64Encoding.DecodeString(s)
+ if err != nil {
+ return err
+ }
+
+ _, err = b.ReadFrom(bytes.NewReader(buf))
+ return err
+}
diff --git a/vendor/github.com/willf/bitset/popcnt.go b/vendor/github.com/willf/bitset/popcnt.go
new file mode 100644
index 000000000..76577a838
--- /dev/null
+++ b/vendor/github.com/willf/bitset/popcnt.go
@@ -0,0 +1,53 @@
+package bitset
+
+// bit population count, take from
+// https://code.google.com/p/go/issues/detail?id=4988#c11
+// credit: https://code.google.com/u/arnehormann/
+func popcount(x uint64) (n uint64) {
+ x -= (x >> 1) & 0x5555555555555555
+ x = (x>>2)&0x3333333333333333 + x&0x3333333333333333
+ x += x >> 4
+ x &= 0x0f0f0f0f0f0f0f0f
+ x *= 0x0101010101010101
+ return x >> 56
+}
+
+func popcntSliceGo(s []uint64) uint64 {
+ cnt := uint64(0)
+ for _, x := range s {
+ cnt += popcount(x)
+ }
+ return cnt
+}
+
+func popcntMaskSliceGo(s, m []uint64) uint64 {
+ cnt := uint64(0)
+ for i := range s {
+ cnt += popcount(s[i] &^ m[i])
+ }
+ return cnt
+}
+
+func popcntAndSliceGo(s, m []uint64) uint64 {
+ cnt := uint64(0)
+ for i := range s {
+ cnt += popcount(s[i] & m[i])
+ }
+ return cnt
+}
+
+func popcntOrSliceGo(s, m []uint64) uint64 {
+ cnt := uint64(0)
+ for i := range s {
+ cnt += popcount(s[i] | m[i])
+ }
+ return cnt
+}
+
+func popcntXorSliceGo(s, m []uint64) uint64 {
+ cnt := uint64(0)
+ for i := range s {
+ cnt += popcount(s[i] ^ m[i])
+ }
+ return cnt
+}
diff --git a/vendor/github.com/willf/bitset/popcnt_19.go b/vendor/github.com/willf/bitset/popcnt_19.go
new file mode 100644
index 000000000..fc8ff4f36
--- /dev/null
+++ b/vendor/github.com/willf/bitset/popcnt_19.go
@@ -0,0 +1,45 @@
+// +build go1.9
+
+package bitset
+
+import "math/bits"
+
+func popcntSlice(s []uint64) uint64 {
+ var cnt int
+ for _, x := range s {
+ cnt += bits.OnesCount64(x)
+ }
+ return uint64(cnt)
+}
+
+func popcntMaskSlice(s, m []uint64) uint64 {
+ var cnt int
+ for i := range s {
+ cnt += bits.OnesCount64(s[i] &^ m[i])
+ }
+ return uint64(cnt)
+}
+
+func popcntAndSlice(s, m []uint64) uint64 {
+ var cnt int
+ for i := range s {
+ cnt += bits.OnesCount64(s[i] & m[i])
+ }
+ return uint64(cnt)
+}
+
+func popcntOrSlice(s, m []uint64) uint64 {
+ var cnt int
+ for i := range s {
+ cnt += bits.OnesCount64(s[i] | m[i])
+ }
+ return uint64(cnt)
+}
+
+func popcntXorSlice(s, m []uint64) uint64 {
+ var cnt int
+ for i := range s {
+ cnt += bits.OnesCount64(s[i] ^ m[i])
+ }
+ return uint64(cnt)
+}
diff --git a/vendor/github.com/willf/bitset/popcnt_amd64.go b/vendor/github.com/willf/bitset/popcnt_amd64.go
new file mode 100644
index 000000000..4cf64f24a
--- /dev/null
+++ b/vendor/github.com/willf/bitset/popcnt_amd64.go
@@ -0,0 +1,68 @@
+// +build !go1.9
+// +build amd64,!appengine
+
+package bitset
+
+// *** the following functions are defined in popcnt_amd64.s
+
+//go:noescape
+
+func hasAsm() bool
+
+// useAsm is a flag used to select the GO or ASM implementation of the popcnt function
+var useAsm = hasAsm()
+
+//go:noescape
+
+func popcntSliceAsm(s []uint64) uint64
+
+//go:noescape
+
+func popcntMaskSliceAsm(s, m []uint64) uint64
+
+//go:noescape
+
+func popcntAndSliceAsm(s, m []uint64) uint64
+
+//go:noescape
+
+func popcntOrSliceAsm(s, m []uint64) uint64
+
+//go:noescape
+
+func popcntXorSliceAsm(s, m []uint64) uint64
+
+func popcntSlice(s []uint64) uint64 {
+ if useAsm {
+ return popcntSliceAsm(s)
+ }
+ return popcntSliceGo(s)
+}
+
+func popcntMaskSlice(s, m []uint64) uint64 {
+ if useAsm {
+ return popcntMaskSliceAsm(s, m)
+ }
+ return popcntMaskSliceGo(s, m)
+}
+
+func popcntAndSlice(s, m []uint64) uint64 {
+ if useAsm {
+ return popcntAndSliceAsm(s, m)
+ }
+ return popcntAndSliceGo(s, m)
+}
+
+func popcntOrSlice(s, m []uint64) uint64 {
+ if useAsm {
+ return popcntOrSliceAsm(s, m)
+ }
+ return popcntOrSliceGo(s, m)
+}
+
+func popcntXorSlice(s, m []uint64) uint64 {
+ if useAsm {
+ return popcntXorSliceAsm(s, m)
+ }
+ return popcntXorSliceGo(s, m)
+}
diff --git a/vendor/github.com/willf/bitset/popcnt_amd64.s b/vendor/github.com/willf/bitset/popcnt_amd64.s
new file mode 100644
index 000000000..666c0dcc1
--- /dev/null
+++ b/vendor/github.com/willf/bitset/popcnt_amd64.s
@@ -0,0 +1,104 @@
+// +build !go1.9
+// +build amd64,!appengine
+
+TEXT ·hasAsm(SB),4,$0-1
+MOVQ $1, AX
+CPUID
+SHRQ $23, CX
+ANDQ $1, CX
+MOVB CX, ret+0(FP)
+RET
+
+#define POPCNTQ_DX_DX BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0xd2
+
+TEXT ·popcntSliceAsm(SB),4,$0-32
+XORQ AX, AX
+MOVQ s+0(FP), SI
+MOVQ s_len+8(FP), CX
+TESTQ CX, CX
+JZ popcntSliceEnd
+popcntSliceLoop:
+BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0x16 // POPCNTQ (SI), DX
+ADDQ DX, AX
+ADDQ $8, SI
+LOOP popcntSliceLoop
+popcntSliceEnd:
+MOVQ AX, ret+24(FP)
+RET
+
+TEXT ·popcntMaskSliceAsm(SB),4,$0-56
+XORQ AX, AX
+MOVQ s+0(FP), SI
+MOVQ s_len+8(FP), CX
+TESTQ CX, CX
+JZ popcntMaskSliceEnd
+MOVQ m+24(FP), DI
+popcntMaskSliceLoop:
+MOVQ (DI), DX
+NOTQ DX
+ANDQ (SI), DX
+POPCNTQ_DX_DX
+ADDQ DX, AX
+ADDQ $8, SI
+ADDQ $8, DI
+LOOP popcntMaskSliceLoop
+popcntMaskSliceEnd:
+MOVQ AX, ret+48(FP)
+RET
+
+TEXT ·popcntAndSliceAsm(SB),4,$0-56
+XORQ AX, AX
+MOVQ s+0(FP), SI
+MOVQ s_len+8(FP), CX
+TESTQ CX, CX
+JZ popcntAndSliceEnd
+MOVQ m+24(FP), DI
+popcntAndSliceLoop:
+MOVQ (DI), DX
+ANDQ (SI), DX
+POPCNTQ_DX_DX
+ADDQ DX, AX
+ADDQ $8, SI
+ADDQ $8, DI
+LOOP popcntAndSliceLoop
+popcntAndSliceEnd:
+MOVQ AX, ret+48(FP)
+RET
+
+TEXT ·popcntOrSliceAsm(SB),4,$0-56
+XORQ AX, AX
+MOVQ s+0(FP), SI
+MOVQ s_len+8(FP), CX
+TESTQ CX, CX
+JZ popcntOrSliceEnd
+MOVQ m+24(FP), DI
+popcntOrSliceLoop:
+MOVQ (DI), DX
+ORQ (SI), DX
+POPCNTQ_DX_DX
+ADDQ DX, AX
+ADDQ $8, SI
+ADDQ $8, DI
+LOOP popcntOrSliceLoop
+popcntOrSliceEnd:
+MOVQ AX, ret+48(FP)
+RET
+
+TEXT ·popcntXorSliceAsm(SB),4,$0-56
+XORQ AX, AX
+MOVQ s+0(FP), SI
+MOVQ s_len+8(FP), CX
+TESTQ CX, CX
+JZ popcntXorSliceEnd
+MOVQ m+24(FP), DI
+popcntXorSliceLoop:
+MOVQ (DI), DX
+XORQ (SI), DX
+POPCNTQ_DX_DX
+ADDQ DX, AX
+ADDQ $8, SI
+ADDQ $8, DI
+LOOP popcntXorSliceLoop
+popcntXorSliceEnd:
+MOVQ AX, ret+48(FP)
+RET
diff --git a/vendor/github.com/willf/bitset/popcnt_generic.go b/vendor/github.com/willf/bitset/popcnt_generic.go
new file mode 100644
index 000000000..21e0ff7b4
--- /dev/null
+++ b/vendor/github.com/willf/bitset/popcnt_generic.go
@@ -0,0 +1,24 @@
+// +build !go1.9
+// +build !amd64 appengine
+
+package bitset
+
+func popcntSlice(s []uint64) uint64 {
+ return popcntSliceGo(s)
+}
+
+func popcntMaskSlice(s, m []uint64) uint64 {
+ return popcntMaskSliceGo(s, m)
+}
+
+func popcntAndSlice(s, m []uint64) uint64 {
+ return popcntAndSliceGo(s, m)
+}
+
+func popcntOrSlice(s, m []uint64) uint64 {
+ return popcntOrSliceGo(s, m)
+}
+
+func popcntXorSlice(s, m []uint64) uint64 {
+ return popcntXorSliceGo(s, m)
+}
diff --git a/vendor/github.com/willf/bitset/trailing_zeros_18.go b/vendor/github.com/willf/bitset/trailing_zeros_18.go
new file mode 100644
index 000000000..c52b61be9
--- /dev/null
+++ b/vendor/github.com/willf/bitset/trailing_zeros_18.go
@@ -0,0 +1,14 @@
+// +build !go1.9
+
+package bitset
+
+var deBruijn = [...]byte{
+ 0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
+ 62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
+ 63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
+ 54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
+}
+
+func trailingZeroes64(v uint64) uint {
+ return uint(deBruijn[((v&-v)*0x03f79d71b4ca8b09)>>58])
+}
diff --git a/vendor/github.com/willf/bitset/trailing_zeros_19.go b/vendor/github.com/willf/bitset/trailing_zeros_19.go
new file mode 100644
index 000000000..36a988e71
--- /dev/null
+++ b/vendor/github.com/willf/bitset/trailing_zeros_19.go
@@ -0,0 +1,9 @@
+// +build go1.9
+
+package bitset
+
+import "math/bits"
+
+func trailingZeroes64(v uint64) uint {
+ return uint(bits.TrailingZeros64(v))
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 65a3ff178..689165af4 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -155,7 +155,7 @@ github.com/containers/psgo/internal/dev
github.com/containers/psgo/internal/host
github.com/containers/psgo/internal/proc
github.com/containers/psgo/internal/process
-# github.com/containers/storage v1.20.2
+# github.com/containers/storage v1.21.0
github.com/containers/storage
github.com/containers/storage/drivers
github.com/containers/storage/drivers/aufs
@@ -308,7 +308,7 @@ github.com/gorilla/mux
github.com/gorilla/schema
# github.com/hashicorp/errwrap v1.0.0
github.com/hashicorp/errwrap
-# github.com/hashicorp/go-multierror v1.0.0
+# github.com/hashicorp/go-multierror v1.1.0
github.com/hashicorp/go-multierror
# github.com/hashicorp/golang-lru v0.5.1
github.com/hashicorp/golang-lru/simplelru
@@ -326,7 +326,7 @@ github.com/inconshreveable/mousetrap
github.com/ishidawataru/sctp
# github.com/json-iterator/go v1.1.10
github.com/json-iterator/go
-# github.com/klauspost/compress v1.10.8
+# github.com/klauspost/compress v1.10.10
github.com/klauspost/compress/flate
github.com/klauspost/compress/fse
github.com/klauspost/compress/huff0
@@ -428,7 +428,7 @@ github.com/opencontainers/runtime-tools/generate
github.com/opencontainers/runtime-tools/generate/seccomp
github.com/opencontainers/runtime-tools/specerror
github.com/opencontainers/runtime-tools/validate
-# github.com/opencontainers/selinux v1.5.2
+# github.com/opencontainers/selinux v1.6.0
github.com/opencontainers/selinux/go-selinux
github.com/opencontainers/selinux/go-selinux/label
github.com/opencontainers/selinux/pkg/pwalk
@@ -544,6 +544,8 @@ github.com/vishvananda/netlink
github.com/vishvananda/netlink/nl
# github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df
github.com/vishvananda/netns
+# github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243
+github.com/willf/bitset
# github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b
github.com/xeipuuv/gojsonpointer
# github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415