summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/common/specgen.go6
-rw-r--r--cmd/podman/inspect/inspect.go56
-rw-r--r--go.mod4
-rw-r--r--go.sum16
-rw-r--r--libpod/image/image.go2
-rw-r--r--pkg/api/handlers/libpod/containers_create.go5
-rw-r--r--pkg/api/server/register_ping.go1
-rw-r--r--pkg/domain/entities/engine_container.go2
-rw-r--r--pkg/domain/entities/engine_image.go2
-rw-r--r--pkg/domain/infra/abi/containers.go65
-rw-r--r--pkg/domain/infra/abi/images.go14
-rw-r--r--pkg/domain/infra/tunnel/containers.go37
-rw-r--r--pkg/domain/infra/tunnel/images.go17
-rw-r--r--pkg/hooks/0.1.0/hook.go9
-rw-r--r--pkg/hooks/0.1.0/hook_test.go26
-rw-r--r--pkg/hooks/read.go6
-rw-r--r--pkg/specgen/generate/container.go159
-rw-r--r--pkg/specgen/generate/container_create.go4
-rw-r--r--pkg/specgen/generate/oci.go2
-rw-r--r--pkg/specgen/generate/storage.go4
-rw-r--r--pkg/specgen/generate/validate.go159
-rw-r--r--pkg/systemd/generate/containers.go3
-rw-r--r--pkg/systemd/generate/containers_test.go3
-rw-r--r--pkg/systemd/generate/pods.go3
-rw-r--r--pkg/systemd/generate/pods_test.go1
-rw-r--r--test/e2e/inspect_test.go40
-rw-r--r--test/e2e/logs_test.go20
-rw-r--r--test/e2e/run_test.go24
-rw-r--r--vendor/github.com/containers/common/pkg/config/config.go192
-rw-r--r--vendor/github.com/containers/common/pkg/config/containers.conf10
-rw-r--r--vendor/github.com/containers/image/v5/copy/copy.go14
-rw-r--r--vendor/github.com/containers/image/v5/oci/layout/oci_dest.go2
-rw-r--r--vendor/github.com/containers/image/v5/types/types.go4
-rw-r--r--vendor/github.com/containers/image/v5/version/version.go4
-rw-r--r--vendor/github.com/klauspost/compress/fse/bitreader.go27
-rw-r--r--vendor/github.com/klauspost/compress/fse/bytereader.go13
-rw-r--r--vendor/github.com/klauspost/compress/huff0/README.md6
-rw-r--r--vendor/github.com/klauspost/compress/huff0/bitreader.go256
-rw-r--r--vendor/github.com/klauspost/compress/huff0/decompress.go776
-rw-r--r--vendor/github.com/klauspost/compress/zstd/bitreader.go25
-rw-r--r--vendor/github.com/klauspost/compress/zstd/blockdec.go4
-rw-r--r--vendor/github.com/klauspost/compress/zstd/bytereader.go25
-rw-r--r--vendor/github.com/klauspost/compress/zstd/decoder.go15
-rw-r--r--vendor/github.com/klauspost/compress/zstd/fse_decoder.go19
-rw-r--r--vendor/modules.txt6
45 files changed, 1703 insertions, 385 deletions
diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go
index 0b44ef544..e6a524358 100644
--- a/cmd/podman/common/specgen.go
+++ b/cmd/podman/common/specgen.go
@@ -563,6 +563,8 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
// we dont think these are in the spec
// init - initbinary
// initpath
+ s.Init = c.Init
+ s.InitPath = c.InitPath
s.Stdin = c.Interactive
// quiet
// DeviceCgroupRules: c.StringSlice("device-cgroup-rule"),
@@ -625,7 +627,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
if retries < 0 {
return errors.Errorf("must specify restart policy retry count as a number greater than 0")
}
- var retriesUint uint = uint(retries)
+ var retriesUint = uint(retries)
s.RestartRetries = &retriesUint
default:
return errors.Errorf("invalid restart policy: may specify retries at most once")
@@ -635,8 +637,6 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
s.Remove = c.Rm
s.StopTimeout = &c.StopTimeout
- // TODO where should we do this?
- // func verifyContainerResources(config *cc.CreateConfig, update bool) ([]string, error) {
return nil
}
diff --git a/cmd/podman/inspect/inspect.go b/cmd/podman/inspect/inspect.go
index 1ed033ec3..d80bbffdd 100644
--- a/cmd/podman/inspect/inspect.go
+++ b/cmd/podman/inspect/inspect.go
@@ -3,12 +3,14 @@ package inspect
import (
"context"
"fmt"
+ "os"
"strings"
"github.com/containers/buildah/pkg/formats"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@@ -78,6 +80,7 @@ func newInspector(options entities.InspectOptions) (*inspector, error) {
func (i *inspector) inspect(namesOrIDs []string) error {
// data - dumping place for inspection results.
var data []interface{} //nolint
+ var errs []error
ctx := context.Background()
if len(namesOrIDs) == 0 {
@@ -97,24 +100,27 @@ func (i *inspector) inspect(namesOrIDs []string) error {
// Inspect - note that AllType requires us to expensively query one-by-one.
switch tmpType {
case AllType:
- all, err := i.inspectAll(ctx, namesOrIDs)
+ allData, allErrs, err := i.inspectAll(ctx, namesOrIDs)
if err != nil {
return err
}
- data = all
+ data = allData
+ errs = allErrs
case ImageType:
- imgData, err := i.imageEngine.Inspect(ctx, namesOrIDs, i.options)
+ imgData, allErrs, err := i.imageEngine.Inspect(ctx, namesOrIDs, i.options)
if err != nil {
return err
}
+ errs = allErrs
for i := range imgData {
data = append(data, imgData[i])
}
case ContainerType:
- ctrData, err := i.containerEngine.ContainerInspect(ctx, namesOrIDs, i.options)
+ ctrData, allErrs, err := i.containerEngine.ContainerInspect(ctx, namesOrIDs, i.options)
if err != nil {
return err
}
+ errs = allErrs
for i := range ctrData {
data = append(data, ctrData[i])
}
@@ -122,30 +128,54 @@ func (i *inspector) inspect(namesOrIDs []string) error {
return errors.Errorf("invalid type %q: must be %q, %q or %q", i.options.Type, ImageType, ContainerType, AllType)
}
+ // Always print an empty array
+ if data == nil {
+ data = []interface{}{}
+ }
+
var out formats.Writer
if i.options.Format == "json" || i.options.Format == "" { // "" for backwards compat
out = formats.JSONStructArray{Output: data}
} else {
out = formats.StdoutTemplateArray{Output: data, Template: inspectFormat(i.options.Format)}
}
- return out.Out()
+ if err := out.Out(); err != nil {
+ logrus.Errorf("Error printing inspect output: %v", err)
+ }
+ if len(errs) > 0 {
+ if len(errs) > 1 {
+ for _, err := range errs[1:] {
+ fmt.Fprintf(os.Stderr, "error inspecting object: %v\n", err)
+ }
+ }
+ return errors.Errorf("error inspecting object: %v", errs[0])
+ }
+ return nil
}
-func (i *inspector) inspectAll(ctx context.Context, namesOrIDs []string) ([]interface{}, error) {
+func (i *inspector) inspectAll(ctx context.Context, namesOrIDs []string) ([]interface{}, []error, error) {
var data []interface{} //nolint
+ allErrs := []error{}
for _, name := range namesOrIDs {
- imgData, err := i.imageEngine.Inspect(ctx, []string{name}, i.options)
- if err == nil {
- data = append(data, imgData[0])
+ ctrData, errs, err := i.containerEngine.ContainerInspect(ctx, []string{name}, i.options)
+ if err != nil {
+ return nil, nil, err
+ }
+ if len(errs) == 0 {
+ data = append(data, ctrData[0])
continue
}
- ctrData, err := i.containerEngine.ContainerInspect(ctx, []string{name}, i.options)
+ imgData, errs, err := i.imageEngine.Inspect(ctx, []string{name}, i.options)
if err != nil {
- return nil, err
+ return nil, nil, err
+ }
+ if len(errs) > 0 {
+ allErrs = append(allErrs, errors.Errorf("no such object: %q", name))
+ continue
}
- data = append(data, ctrData[0])
+ data = append(data, imgData[0])
}
- return data, nil
+ return data, allErrs, nil
}
func inspectFormat(row string) string {
diff --git a/go.mod b/go.mod
index 77245bd4d..9a08a0ef2 100644
--- a/go.mod
+++ b/go.mod
@@ -11,9 +11,9 @@ require (
github.com/containernetworking/cni v0.7.2-0.20200304161608-4fae32b84921
github.com/containernetworking/plugins v0.8.6
github.com/containers/buildah v1.14.9-0.20200523094741-de0f541d9224
- github.com/containers/common v0.13.1
+ github.com/containers/common v0.14.0
github.com/containers/conmon v2.0.18+incompatible
- github.com/containers/image/v5 v5.4.5-0.20200529084758-46b2ee6aebb0
+ github.com/containers/image/v5 v5.5.1
github.com/containers/psgo v1.5.1
github.com/containers/storage v1.20.2
github.com/coreos/go-systemd/v22 v22.1.0
diff --git a/go.sum b/go.sum
index 0f47266ae..55c5fa6db 100644
--- a/go.sum
+++ b/go.sum
@@ -70,14 +70,14 @@ github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHV
github.com/containers/buildah v1.14.9-0.20200523094741-de0f541d9224 h1:EqwBZRqyUYvU7JOmmSSPviSaAoUP1wN0cefXXDZ9ATo=
github.com/containers/buildah v1.14.9-0.20200523094741-de0f541d9224/go.mod h1:5ZkWjOuK90yl55L5R+purJNLfUo0VUr8pstJazNtYck=
github.com/containers/common v0.11.2/go.mod h1:2w3QE6VUmhltGYW4wV00h4okq1Crs7hNI1ZD2I0QRUY=
-github.com/containers/common v0.13.1 h1:6aE/IIxPPQk8DmND87tsWU1Aop/7mCC0T3dk/fZdm3k=
-github.com/containers/common v0.13.1/go.mod h1:Kg9Enw+WOUa9pwx47fzxEdzOn5+ofYXjBJdCyaCeSSA=
+github.com/containers/common v0.14.0 h1:hiZFDPf6ajKiDmojN5f5X3gboKPO73NLrYb0RXfrQiA=
+github.com/containers/common v0.14.0/go.mod h1:9olhlE+WhYof1npnMJdyRMX14/yIUint6zyHzcyRVAg=
github.com/containers/conmon v2.0.18+incompatible h1:rjwjNnE756NuXcdE/uUmj4kDbrykslPuBMHI31wh43E=
github.com/containers/conmon v2.0.18+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
github.com/containers/image/v5 v5.4.3/go.mod h1:pN0tvp3YbDd7BWavK2aE0mvJUqVd2HmhPjekyWSFm0U=
github.com/containers/image/v5 v5.4.4/go.mod h1:g7cxNXitiLi6pEr9/L9n/0wfazRuhDKXU15kV86N8h8=
-github.com/containers/image/v5 v5.4.5-0.20200529084758-46b2ee6aebb0 h1:K1ez+qAi9hCMHv/akPF4ddZumQTq/PBGf2Nzc7e+7lI=
-github.com/containers/image/v5 v5.4.5-0.20200529084758-46b2ee6aebb0/go.mod h1:XRf/UlTCkDBQONudBhSFXiLCouFKPU/oXwIjWw/tPpo=
+github.com/containers/image/v5 v5.5.1 h1:h1FCOXH6Ux9/p/E4rndsQOC4yAdRU0msRTfLVeQ7FDQ=
+github.com/containers/image/v5 v5.5.1/go.mod h1:4PyNYR0nwlGq/ybVJD9hWlhmIsNra4Q8uOQX2s6E2uM=
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDplZ7U33NwHZkrVELsZP5fYj9pM5WBZB2GE=
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
github.com/containers/ocicrypt v1.0.2 h1:Q0/IPs8ohfbXNxEfyJ2pFVmvJu5BhqJUAmc6ES9NKbo=
@@ -87,8 +87,6 @@ github.com/containers/psgo v1.5.1/go.mod h1:2ubh0SsreMZjSXW1Hif58JrEcFudQyIy9EzP
github.com/containers/storage v1.18.2/go.mod h1:WTBMf+a9ZZ/LbmEVeLHH2TX4CikWbO1Bt+/m58ZHVPg=
github.com/containers/storage v1.19.1/go.mod h1:KbXjSwKnx17ejOsjFcCXSf78mCgZkQSLPBNTMRc3XrQ=
github.com/containers/storage v1.19.2/go.mod h1:gYCp3jzgXkvubO0rI14QAjz5Mxm/qKJgLmHFyqayDnw=
-github.com/containers/storage v1.20.1 h1:2XE4eRIqSa6YjhAZjNwIkIKE6+Miy+5WV8l1KzY2ZKk=
-github.com/containers/storage v1.20.1/go.mod h1:RoKzO8KSDogCT6c06rEbanZTcKYxshorB33JikEGc3A=
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/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
@@ -257,10 +255,10 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.10.5 h1:7q6vHIqubShURwQz8cQK6yIe/xC3IF0Vm7TGfqjewrc=
github.com/klauspost/compress v1.10.5/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
-github.com/klauspost/compress v1.10.6 h1:SP6zavvTG3YjOosWePXFDlExpKIWMTO4SE/Y8MZB2vI=
-github.com/klauspost/compress v1.10.6/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
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.8 h1:eLeJ3dr/Y9+XRfJT4l+8ZjmtB5RPJhucH2HeCV5+IZY=
+github.com/klauspost/compress v1.10.8/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/pgzip v1.2.3/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/klauspost/pgzip v1.2.4 h1:TQ7CNpYKovDOmqzRHKxJh0BeaBI7UdQZYc6p7pMQh1A=
github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
@@ -318,8 +316,6 @@ github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
-github.com/onsi/ginkgo v1.12.3 h1:+RYp9QczoWz9zfUyLP/5SLXQVhfr6gZOoKGfQqHuLZQ=
-github.com/onsi/ginkgo v1.12.3/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.13.0 h1:M76yO2HkZASFjXL0HSoZJ1AYEmQxNJmY41Jx1zNUq1Y=
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
diff --git a/libpod/image/image.go b/libpod/image/image.go
index 1101e35dc..d81f7e911 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -478,7 +478,7 @@ func (ir *Runtime) getImages(rwOnly bool) ([]*Image, error) {
if err != nil {
return nil, err
}
- newImages := make([]*Image, 0, len(images))
+ newImages := []*Image{}
for _, i := range images {
if rwOnly && i.ReadOnly {
continue
diff --git a/pkg/api/handlers/libpod/containers_create.go b/pkg/api/handlers/libpod/containers_create.go
index 71f440bce..8fbff9be7 100644
--- a/pkg/api/handlers/libpod/containers_create.go
+++ b/pkg/api/handlers/libpod/containers_create.go
@@ -22,7 +22,8 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
return
}
- if err := generate.CompleteSpec(r.Context(), runtime, &sg); err != nil {
+ warn, err := generate.CompleteSpec(r.Context(), runtime, &sg)
+ if err != nil {
utils.InternalServerError(w, err)
return
}
@@ -31,6 +32,6 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, err)
return
}
- response := entities.ContainerCreateResponse{ID: ctr.ID()}
+ response := entities.ContainerCreateResponse{ID: ctr.ID(), Warnings: warn}
utils.WriteJSON(w, http.StatusCreated, response)
}
diff --git a/pkg/api/server/register_ping.go b/pkg/api/server/register_ping.go
index 8a1cda3d4..bf7763029 100644
--- a/pkg/api/server/register_ping.go
+++ b/pkg/api/server/register_ping.go
@@ -19,6 +19,7 @@ func (s *APIServer) registerPingHandlers(r *mux.Router) error {
// Return protocol information in response headers.
// `HEAD /libpod/_ping` is also supported.
// `/_ping` is available for compatibility with other engines.
+ // The '_ping' endpoints are not versioned.
// tags:
// - system (compat)
// - system
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 979df7581..837550a2e 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -24,7 +24,7 @@ type ContainerEngine interface {
ContainerExists(ctx context.Context, nameOrID string) (*BoolReport, error)
ContainerExport(ctx context.Context, nameOrID string, options ContainerExportOptions) error
ContainerInit(ctx context.Context, namesOrIds []string, options ContainerInitOptions) ([]*ContainerInitReport, error)
- ContainerInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]*ContainerInspectReport, error)
+ ContainerInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]*ContainerInspectReport, []error, error)
ContainerKill(ctx context.Context, namesOrIds []string, options KillOptions) ([]*KillReport, error)
ContainerList(ctx context.Context, options ContainerListOptions) ([]ListContainer, error)
ContainerLogs(ctx context.Context, containers []string, options ContainerLogsOptions) error
diff --git a/pkg/domain/entities/engine_image.go b/pkg/domain/entities/engine_image.go
index 60fb20b6e..7ece24c60 100644
--- a/pkg/domain/entities/engine_image.go
+++ b/pkg/domain/entities/engine_image.go
@@ -13,7 +13,7 @@ type ImageEngine interface {
Exists(ctx context.Context, nameOrID string) (*BoolReport, error)
History(ctx context.Context, nameOrID string, opts ImageHistoryOptions) (*ImageHistoryReport, error)
Import(ctx context.Context, opts ImageImportOptions) (*ImageImportReport, error)
- Inspect(ctx context.Context, namesOrIDs []string, opts InspectOptions) ([]*ImageInspectReport, error)
+ Inspect(ctx context.Context, namesOrIDs []string, opts InspectOptions) ([]*ImageInspectReport, []error, error)
List(ctx context.Context, opts ImageListOptions) ([]*ImageSummary, error)
Load(ctx context.Context, opts ImageLoadOptions) (*ImageLoadReport, error)
Prune(ctx context.Context, opts ImagePruneOptions) (*ImagePruneReport, error)
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index d2c8aefdc..8e0ffc075 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -338,20 +338,51 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
return reports, nil
}
-func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, error) {
- ctrs, err := getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
- if err != nil {
- return nil, err
+func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, []error, error) {
+ if options.Latest {
+ ctr, err := ic.Libpod.GetLatestContainer()
+ if err != nil {
+ if errors.Cause(err) == define.ErrNoSuchCtr {
+ return nil, []error{errors.Wrapf(err, "no containers to inspect")}, nil
+ }
+ return nil, nil, err
+ }
+
+ inspect, err := ctr.Inspect(options.Size)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ return []*entities.ContainerInspectReport{
+ {
+ InspectContainerData: inspect,
+ },
+ }, nil, nil
}
- reports := make([]*entities.ContainerInspectReport, 0, len(ctrs))
- for _, c := range ctrs {
- data, err := c.Inspect(options.Size)
+ var (
+ reports = make([]*entities.ContainerInspectReport, 0, len(namesOrIds))
+ errs = []error{}
+ )
+ for _, name := range namesOrIds {
+ ctr, err := ic.Libpod.LookupContainer(name)
if err != nil {
- return nil, err
+ // ErrNoSuchCtr is non-fatal, other errors will be
+ // treated as fatal.
+ if errors.Cause(err) == define.ErrNoSuchCtr {
+ errs = append(errs, errors.Errorf("no such container %s", name))
+ continue
+ }
+ return nil, nil, err
+ }
+
+ inspect, err := ctr.Inspect(options.Size)
+ if err != nil {
+ return nil, nil, err
}
- reports = append(reports, &entities.ContainerInspectReport{InspectContainerData: data})
+
+ reports = append(reports, &entities.ContainerInspectReport{InspectContainerData: inspect})
}
- return reports, nil
+ return reports, errs, nil
}
func (ic *ContainerEngine) ContainerTop(ctx context.Context, options entities.TopOptions) (*entities.StringSliceReport, error) {
@@ -511,9 +542,14 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
}
func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecGenerator) (*entities.ContainerCreateReport, error) {
- if err := generate.CompleteSpec(ctx, ic.Libpod, s); err != nil {
+ warn, err := generate.CompleteSpec(ctx, ic.Libpod, s)
+ if err != nil {
return nil, err
}
+ // Print warnings
+ for _, w := range warn {
+ fmt.Fprintf(os.Stderr, "%s\n", w)
+ }
ctr, err := generate.MakeContainer(ctx, ic.Libpod, s)
if err != nil {
return nil, err
@@ -773,9 +809,14 @@ func (ic *ContainerEngine) ContainerDiff(ctx context.Context, nameOrID string, o
}
func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.ContainerRunOptions) (*entities.ContainerRunReport, error) {
- if err := generate.CompleteSpec(ctx, ic.Libpod, opts.Spec); err != nil {
+ warn, err := generate.CompleteSpec(ctx, ic.Libpod, opts.Spec)
+ if err != nil {
return nil, err
}
+ // Print warnings
+ for _, w := range warn {
+ fmt.Fprintf(os.Stderr, "%s\n", w)
+ }
ctr, err := generate.MakeContainer(ctx, ic.Libpod, opts.Spec)
if err != nil {
return nil, err
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index e630d9bc8..0f9ddfec4 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -184,24 +184,28 @@ func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entiti
return &entities.ImagePullReport{Images: foundIDs}, nil
}
-func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts entities.InspectOptions) ([]*entities.ImageInspectReport, error) {
+func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts entities.InspectOptions) ([]*entities.ImageInspectReport, []error, error) {
reports := []*entities.ImageInspectReport{}
+ errs := []error{}
for _, i := range namesOrIDs {
img, err := ir.Libpod.ImageRuntime().NewFromLocal(i)
if err != nil {
- return nil, err
+ // This is probably a no such image, treat as nonfatal.
+ errs = append(errs, err)
+ continue
}
result, err := img.Inspect(ctx)
if err != nil {
- return nil, err
+ // This is more likely to be fatal.
+ return nil, nil, err
}
report := entities.ImageInspectReport{}
if err := domainUtils.DeepCopy(&report, result); err != nil {
- return nil, err
+ return nil, nil, err
}
reports = append(reports, &report)
}
- return reports, nil
+ return reports, errs, nil
}
func (ir *ImageEngine) Push(ctx context.Context, source string, destination string, options entities.ImagePushOptions) error {
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 955149fcf..45fbc64f8 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -185,20 +185,27 @@ func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.
return containers.Prune(ic.ClientCxt, options.Filters)
}
-func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, error) {
- ctrs, err := getContainersByContext(ic.ClientCxt, false, namesOrIds)
- if err != nil {
- return nil, err
- }
- reports := make([]*entities.ContainerInspectReport, 0, len(ctrs))
- for _, con := range ctrs {
- data, err := containers.Inspect(ic.ClientCxt, con.ID, &options.Size)
+func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, []error, error) {
+ var (
+ reports = make([]*entities.ContainerInspectReport, 0, len(namesOrIds))
+ errs = []error{}
+ )
+ for _, name := range namesOrIds {
+ inspect, err := containers.Inspect(ic.ClientCxt, name, &options.Size)
if err != nil {
- return nil, err
+ errModel, ok := err.(entities.ErrorModel)
+ if !ok {
+ return nil, nil, err
+ }
+ if errModel.ResponseCode == 404 {
+ errs = append(errs, errors.Errorf("no such container %q", name))
+ continue
+ }
+ return nil, nil, err
}
- reports = append(reports, &entities.ContainerInspectReport{InspectContainerData: data})
+ reports = append(reports, &entities.ContainerInspectReport{InspectContainerData: inspect})
}
- return reports, nil
+ return reports, errs, nil
}
func (ic *ContainerEngine) ContainerTop(ctx context.Context, options entities.TopOptions) (*entities.StringSliceReport, error) {
@@ -340,6 +347,9 @@ func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecG
if err != nil {
return nil, err
}
+ for _, w := range response.Warnings {
+ fmt.Fprintf(os.Stderr, "%s\n", w)
+ }
return &entities.ContainerCreateReport{Id: response.ID}, nil
}
@@ -370,7 +380,7 @@ func (ic *ContainerEngine) ContainerLogs(_ context.Context, nameOrIDs []string,
case <-ctx.Done():
return err
case line := <-outCh:
- _, _ = io.WriteString(options.Writer, line)
+ _, _ = io.WriteString(options.Writer, line+"\n")
}
}
}
@@ -497,6 +507,9 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
if err != nil {
return nil, err
}
+ for _, w := range con.Warnings {
+ fmt.Fprintf(os.Stderr, "%s\n", w)
+ }
report := entities.ContainerRunReport{Id: con.ID}
// Attach
if !opts.Detach {
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index ec2c53c4f..9ddc5f1a9 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -39,7 +39,7 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions)
return nil, err
}
- is := make([]*entities.ImageSummary, 0, len(images))
+ is := make([]*entities.ImageSummary, len(images))
for i, img := range images {
hold := entities.ImageSummary{}
if err := utils.DeepCopy(&hold, img); err != nil {
@@ -157,16 +157,25 @@ func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string
return nil
}
-func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts entities.InspectOptions) ([]*entities.ImageInspectReport, error) {
+func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts entities.InspectOptions) ([]*entities.ImageInspectReport, []error, error) {
reports := []*entities.ImageInspectReport{}
+ errs := []error{}
for _, i := range namesOrIDs {
r, err := images.GetImage(ir.ClientCxt, i, &opts.Size)
if err != nil {
- return nil, err
+ errModel, ok := err.(entities.ErrorModel)
+ if !ok {
+ return nil, nil, err
+ }
+ if errModel.ResponseCode == 404 {
+ errs = append(errs, errors.Wrapf(err, "unable to inspect %q", i))
+ continue
+ }
+ return nil, nil, err
}
reports = append(reports, r)
}
- return reports, nil
+ return reports, errs, nil
}
func (ir *ImageEngine) Load(ctx context.Context, opts entities.ImageLoadOptions) (*entities.ImageLoadReport, error) {
diff --git a/pkg/hooks/0.1.0/hook.go b/pkg/hooks/0.1.0/hook.go
index 88a387647..185cc90d1 100644
--- a/pkg/hooks/0.1.0/hook.go
+++ b/pkg/hooks/0.1.0/hook.go
@@ -6,7 +6,6 @@ import (
"errors"
"strings"
- "github.com/containers/libpod/pkg/hooks"
current "github.com/containers/libpod/pkg/hooks/1.0.0"
rspec "github.com/opencontainers/runtime-spec/specs-go"
)
@@ -32,8 +31,9 @@ type Hook struct {
HasBindMounts *bool `json:"hasbindmounts,omitempty"`
}
-func read(content []byte) (hook *current.Hook, err error) {
+func Read(content []byte) (hook *current.Hook, err error) {
var raw Hook
+
if err = json.Unmarshal(content, &raw); err != nil {
return nil, err
}
@@ -86,8 +86,3 @@ func read(content []byte) (hook *current.Hook, err error) {
return hook, nil
}
-
-func init() {
- hooks.Readers[""] = read
- hooks.Readers[Version] = read
-}
diff --git a/pkg/hooks/0.1.0/hook_test.go b/pkg/hooks/0.1.0/hook_test.go
index 66774075e..11881ca0b 100644
--- a/pkg/hooks/0.1.0/hook_test.go
+++ b/pkg/hooks/0.1.0/hook_test.go
@@ -9,7 +9,7 @@ import (
)
func TestGood(t *testing.T) {
- hook, err := read([]byte("{\"hook\": \"/a/b/c\", \"stages\": [\"prestart\"], \"cmds\": [\"sh\"]}"))
+ hook, err := Read([]byte("{\"hook\": \"/a/b/c\", \"stages\": [\"prestart\"], \"cmds\": [\"sh\"]}"))
if err != nil {
t.Fatal(err)
}
@@ -27,7 +27,7 @@ func TestGood(t *testing.T) {
}
func TestInvalidJSON(t *testing.T) {
- _, err := read([]byte("{"))
+ _, err := Read([]byte("{"))
if err == nil {
t.Fatal("unexpected success")
}
@@ -35,7 +35,7 @@ func TestInvalidJSON(t *testing.T) {
}
func TestArguments(t *testing.T) {
- hook, err := read([]byte("{\"hook\": \"/a/b/c\", \"arguments\": [\"d\", \"e\"], \"stages\": [\"prestart\"], \"cmds\": [\"sh\"]}"))
+ hook, err := Read([]byte("{\"hook\": \"/a/b/c\", \"arguments\": [\"d\", \"e\"], \"stages\": [\"prestart\"], \"cmds\": [\"sh\"]}"))
if err != nil {
t.Fatal(err)
}
@@ -54,7 +54,7 @@ func TestArguments(t *testing.T) {
}
func TestEmptyObject(t *testing.T) {
- _, err := read([]byte("{}"))
+ _, err := Read([]byte("{}"))
if err == nil {
t.Fatal("unexpected success")
}
@@ -62,7 +62,7 @@ func TestEmptyObject(t *testing.T) {
}
func TestNoStages(t *testing.T) {
- _, err := read([]byte("{\"hook\": \"/a/b/c\"}"))
+ _, err := Read([]byte("{\"hook\": \"/a/b/c\"}"))
if err == nil {
t.Fatal("unexpected success")
}
@@ -70,7 +70,7 @@ func TestNoStages(t *testing.T) {
}
func TestStage(t *testing.T) {
- hook, err := read([]byte("{\"hook\": \"/a/b/c\", \"stage\": [\"prestart\"]}"))
+ hook, err := Read([]byte("{\"hook\": \"/a/b/c\", \"stage\": [\"prestart\"]}"))
if err != nil {
t.Fatal(err)
}
@@ -85,7 +85,7 @@ func TestStage(t *testing.T) {
}
func TestStagesAndStage(t *testing.T) {
- _, err := read([]byte("{\"hook\": \"/a/b/c\", \"stages\": [\"prestart\"], \"stage\": [\"prestart\"]}"))
+ _, err := Read([]byte("{\"hook\": \"/a/b/c\", \"stages\": [\"prestart\"], \"stage\": [\"prestart\"]}"))
if err == nil {
t.Fatal("unexpected success")
}
@@ -93,7 +93,7 @@ func TestStagesAndStage(t *testing.T) {
}
func TestCmd(t *testing.T) {
- hook, err := read([]byte("{\"hook\": \"/a/b/c\", \"stage\": [\"prestart\"], \"cmd\": [\"sh\"]}"))
+ hook, err := Read([]byte("{\"hook\": \"/a/b/c\", \"stage\": [\"prestart\"], \"cmd\": [\"sh\"]}"))
if err != nil {
t.Fatal(err)
}
@@ -111,7 +111,7 @@ func TestCmd(t *testing.T) {
}
func TestCmdsAndCmd(t *testing.T) {
- _, err := read([]byte("{\"hook\": \"/a/b/c\", \"stages\": [\"prestart\"], \"cmds\": [\"sh\"], \"cmd\": [\"true\"]}"))
+ _, err := Read([]byte("{\"hook\": \"/a/b/c\", \"stages\": [\"prestart\"], \"cmds\": [\"sh\"], \"cmd\": [\"true\"]}"))
if err == nil {
t.Fatal("unexpected success")
}
@@ -119,7 +119,7 @@ func TestCmdsAndCmd(t *testing.T) {
}
func TestAnnotations(t *testing.T) {
- hook, err := read([]byte("{\"hook\": \"/a/b/c\", \"stage\": [\"prestart\"], \"annotations\": [\"a\", \"b\"]}"))
+ hook, err := Read([]byte("{\"hook\": \"/a/b/c\", \"stage\": [\"prestart\"], \"annotations\": [\"a\", \"b\"]}"))
if err != nil {
t.Fatal(err)
}
@@ -137,7 +137,7 @@ func TestAnnotations(t *testing.T) {
}
func TestAnnotation(t *testing.T) {
- hook, err := read([]byte("{\"hook\": \"/a/b/c\", \"stage\": [\"prestart\"], \"annotation\": [\"a\", \"b\"]}"))
+ hook, err := Read([]byte("{\"hook\": \"/a/b/c\", \"stage\": [\"prestart\"], \"annotation\": [\"a\", \"b\"]}"))
if err != nil {
t.Fatal(err)
}
@@ -155,7 +155,7 @@ func TestAnnotation(t *testing.T) {
}
func TestAnnotationsAndAnnotation(t *testing.T) {
- _, err := read([]byte("{\"hook\": \"/a/b/c\", \"stages\": [\"prestart\"], \"annotations\": [\"a\"], \"annotation\": [\"b\"]}"))
+ _, err := Read([]byte("{\"hook\": \"/a/b/c\", \"stages\": [\"prestart\"], \"annotations\": [\"a\"], \"annotation\": [\"b\"]}"))
if err == nil {
t.Fatal("unexpected success")
}
@@ -163,7 +163,7 @@ func TestAnnotationsAndAnnotation(t *testing.T) {
}
func TestHasBindMounts(t *testing.T) {
- hook, err := read([]byte("{\"hook\": \"/a/b/c\", \"stage\": [\"prestart\"], \"hasbindmounts\": true}"))
+ hook, err := Read([]byte("{\"hook\": \"/a/b/c\", \"stage\": [\"prestart\"], \"hasbindmounts\": true}"))
if err != nil {
t.Fatal(err)
}
diff --git a/pkg/hooks/read.go b/pkg/hooks/read.go
index 560ff1899..e20ae9bee 100644
--- a/pkg/hooks/read.go
+++ b/pkg/hooks/read.go
@@ -3,12 +3,12 @@ package hooks
import (
"encoding/json"
- "fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
+ old "github.com/containers/libpod/pkg/hooks/0.1.0"
current "github.com/containers/libpod/pkg/hooks/1.0.0"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -49,7 +49,7 @@ func read(content []byte) (hook *current.Hook, err error) {
}
reader, ok := Readers[ver.Version]
if !ok {
- return nil, fmt.Errorf("unrecognized hook version: %q", ver.Version)
+ return nil, errors.Errorf("unrecognized hook version: %q", ver.Version)
}
hook, err = reader(content)
@@ -95,4 +95,6 @@ func ReadDir(path string, extensionStages []string, hooks map[string]*current.Ho
func init() {
Readers[current.Version] = current.Read
+ Readers[old.Version] = old.Read
+ Readers[""] = old.Read
}
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index 3d70571d5..df27f225b 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -5,6 +5,7 @@ import (
"github.com/containers/image/v5/manifest"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/image"
ann "github.com/containers/libpod/pkg/annotations"
envLib "github.com/containers/libpod/pkg/env"
"github.com/containers/libpod/pkg/signal"
@@ -13,91 +14,103 @@ import (
"golang.org/x/sys/unix"
)
-func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerator) error {
- // If a rootfs is used, then there is no image data
- if s.ContainerStorageConfig.Rootfs != "" {
- return nil
- }
-
- newImage, err := r.ImageRuntime().NewFromLocal(s.Image)
- if err != nil {
- return err
- }
-
- _, mediaType, err := newImage.Manifest(ctx)
- if err != nil {
- return err
- }
-
- if s.HealthConfig == nil && mediaType == manifest.DockerV2Schema2MediaType {
- s.HealthConfig, err = newImage.GetHealthCheck(ctx)
+// Fill any missing parts of the spec generator (e.g. from the image).
+// Returns a set of warnings or any fatal error that occurred.
+func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerator) ([]string, error) {
+ var (
+ newImage *image.Image
+ err error
+ )
+
+ // Only add image configuration if we have an image
+ if s.Image != "" {
+ newImage, err = r.ImageRuntime().NewFromLocal(s.Image)
if err != nil {
- return err
+ return nil, err
}
- }
- // Image stop signal
- if s.StopSignal == nil {
- stopSignal, err := newImage.StopSignal(ctx)
+ _, mediaType, err := newImage.Manifest(ctx)
if err != nil {
- return err
+ return nil, err
}
- if stopSignal != "" {
- sig, err := signal.ParseSignalNameOrNumber(stopSignal)
+
+ if s.HealthConfig == nil && mediaType == manifest.DockerV2Schema2MediaType {
+ s.HealthConfig, err = newImage.GetHealthCheck(ctx)
if err != nil {
- return err
+ return nil, err
+ }
+ }
+
+ // Image stop signal
+ if s.StopSignal == nil {
+ stopSignal, err := newImage.StopSignal(ctx)
+ if err != nil {
+ return nil, err
+ }
+ if stopSignal != "" {
+ sig, err := signal.ParseSignalNameOrNumber(stopSignal)
+ if err != nil {
+ return nil, err
+ }
+ s.StopSignal = &sig
}
- s.StopSignal = &sig
}
}
rtc, err := r.GetConfig()
if err != nil {
- return err
+ return nil, err
}
// Get Default Environment
defaultEnvs, err := envLib.ParseSlice(rtc.Containers.Env)
if err != nil {
- return errors.Wrap(err, "Env fields in containers.conf failed to parse")
+ return nil, errors.Wrap(err, "Env fields in containers.conf failed to parse")
}
- // Image envs from the image if they don't exist
- // already, overriding the default environments
- imageEnvs, err := newImage.Env(ctx)
- if err != nil {
- return err
- }
+ var envs map[string]string
- envs, err := envLib.ParseSlice(imageEnvs)
- if err != nil {
- return errors.Wrap(err, "Env fields from image failed to parse")
- }
- s.Env = envLib.Join(envLib.Join(defaultEnvs, envs), s.Env)
+ if newImage != nil {
+ // Image envs from the image if they don't exist
+ // already, overriding the default environments
+ imageEnvs, err := newImage.Env(ctx)
+ if err != nil {
+ return nil, err
+ }
- labels, err := newImage.Labels(ctx)
- if err != nil {
- return err
+ envs, err = envLib.ParseSlice(imageEnvs)
+ if err != nil {
+ return nil, errors.Wrap(err, "Env fields from image failed to parse")
+ }
}
- // labels from the image that dont exist already
- if len(labels) > 0 && s.Labels == nil {
- s.Labels = make(map[string]string)
- }
- for k, v := range labels {
- if _, exists := s.Labels[k]; !exists {
- s.Labels[k] = v
+ s.Env = envLib.Join(envLib.Join(defaultEnvs, envs), s.Env)
+
+ // Labels and Annotations
+ annotations := make(map[string]string)
+ if newImage != nil {
+ labels, err := newImage.Labels(ctx)
+ if err != nil {
+ return nil, err
}
- }
- // annotations
+ // labels from the image that dont exist already
+ if len(labels) > 0 && s.Labels == nil {
+ s.Labels = make(map[string]string)
+ }
+ for k, v := range labels {
+ if _, exists := s.Labels[k]; !exists {
+ s.Labels[k] = v
+ }
+ }
- // Add annotations from the image
- annotations, err := newImage.Annotations(ctx)
- if err != nil {
- return err
- }
- for k, v := range annotations {
- annotations[k] = v
+ // Add annotations from the image
+ imgAnnotations, err := newImage.Annotations(ctx)
+ if err != nil {
+ return nil, err
+ }
+ for k, v := range imgAnnotations {
+ annotations[k] = v
+ }
}
// in the event this container is in a pod, and the pod has an infra container
@@ -121,40 +134,42 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
s.Annotations = annotations
// workdir
- workingDir, err := newImage.WorkingDir(ctx)
- if err != nil {
- return err
- }
- if len(s.WorkDir) < 1 && len(workingDir) > 1 {
- s.WorkDir = workingDir
+ if newImage != nil {
+ workingDir, err := newImage.WorkingDir(ctx)
+ if err != nil {
+ return nil, err
+ }
+ if len(s.WorkDir) < 1 && len(workingDir) > 1 {
+ s.WorkDir = workingDir
+ }
}
if len(s.SeccompProfilePath) < 1 {
p, err := libpod.DefaultSeccompPath()
if err != nil {
- return err
+ return nil, err
}
s.SeccompProfilePath = p
}
- if len(s.User) == 0 {
+ if len(s.User) == 0 && newImage != nil {
s.User, err = newImage.User(ctx)
if err != nil {
- return err
+ return nil, err
}
}
if err := finishThrottleDevices(s); err != nil {
- return err
+ return nil, err
}
// Unless already set via the CLI, check if we need to disable process
// labels or set the defaults.
if len(s.SelinuxOpts) == 0 {
if err := setLabelOpts(s, r, s.PidNS, s.IpcNS); err != nil {
- return err
+ return nil, err
}
}
- return nil
+ return verifyContainerResources(s)
}
// finishThrottleDevices takes the temporary representation of the throttle
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index 33075b543..869601e93 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -16,7 +16,9 @@ import (
"github.com/sirupsen/logrus"
)
-// MakeContainer creates a container based on the SpecGenerator
+// MakeContainer creates a container based on the SpecGenerator.
+// Returns the created, container and any warnings resulting from creating the
+// container, or an error.
func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator) (*libpod.Container, error) {
rtc, err := rt.GetConfig()
if err != nil {
diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go
index 266abd28d..1c34f622b 100644
--- a/pkg/specgen/generate/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -112,7 +112,7 @@ func makeCommand(ctx context.Context, s *specgen.SpecGenerator, img *image.Image
if initPath == "" {
return nil, errors.Errorf("no path to init binary found but container requested an init")
}
- finalCommand = append([]string{initPath, "--"}, finalCommand...)
+ finalCommand = append([]string{"/dev/init", "--"}, finalCommand...)
}
return finalCommand, nil
diff --git a/pkg/specgen/generate/storage.go b/pkg/specgen/generate/storage.go
index 241c9adeb..0d78421a6 100644
--- a/pkg/specgen/generate/storage.go
+++ b/pkg/specgen/generate/storage.go
@@ -314,8 +314,8 @@ func addContainerInitBinary(s *specgen.SpecGenerator, path string) (spec.Mount,
if !s.PidNS.IsPrivate() {
return mount, fmt.Errorf("cannot add init binary as PID 1 (PID namespace isn't private)")
}
- if s.Systemd == "true" || s.Systemd == "always" {
- return mount, fmt.Errorf("cannot use container-init binary with systemd")
+ if s.Systemd == "always" {
+ return mount, fmt.Errorf("cannot use container-init binary with systemd=always")
}
if _, err := os.Stat(path); os.IsNotExist(err) {
return mount, errors.Wrap(err, "container-init binary not found on the host")
diff --git a/pkg/specgen/generate/validate.go b/pkg/specgen/generate/validate.go
new file mode 100644
index 000000000..bb3ca9907
--- /dev/null
+++ b/pkg/specgen/generate/validate.go
@@ -0,0 +1,159 @@
+package generate
+
+import (
+ "github.com/containers/common/pkg/sysinfo"
+ "github.com/containers/libpod/pkg/cgroups"
+ "github.com/containers/libpod/pkg/specgen"
+ "github.com/pkg/errors"
+)
+
+// Verify resource limits are sanely set, removing any limits that are not
+// possible with the current cgroups config.
+func verifyContainerResources(s *specgen.SpecGenerator) ([]string, error) {
+ warnings := []string{}
+
+ cgroup2, err := cgroups.IsCgroup2UnifiedMode()
+ if err != nil || cgroup2 {
+ return warnings, err
+ }
+
+ sysInfo := sysinfo.New(true)
+
+ if s.ResourceLimits == nil {
+ return warnings, nil
+ }
+
+ // Memory checks
+ if s.ResourceLimits.Memory != nil {
+ memory := s.ResourceLimits.Memory
+ if memory.Limit != nil && !sysInfo.MemoryLimit {
+ warnings = append(warnings, "Your kernel does not support memory limit capabilities or the cgroup is not mounted. Limitation discarded.")
+ memory.Limit = nil
+ memory.Swap = nil
+ }
+ if memory.Limit != nil && memory.Swap != nil && !sysInfo.SwapLimit {
+ warnings = append(warnings, "Your kernel does not support swap limit capabilities,or the cgroup is not mounted. Memory limited without swap.")
+ memory.Swap = nil
+ }
+ if memory.Limit != nil && memory.Swap != nil && *memory.Swap < *memory.Limit {
+ return warnings, errors.New("minimum memoryswap limit should be larger than memory limit, see usage")
+ }
+ if memory.Limit == nil && memory.Swap != nil {
+ return warnings, errors.New("you should always set a memory limit when using a memoryswap limit, see usage")
+ }
+ if memory.Swappiness != nil {
+ if !sysInfo.MemorySwappiness {
+ warnings = append(warnings, "Your kernel does not support memory swappiness capabilities, or the cgroup is not mounted. Memory swappiness discarded.")
+ memory.Swappiness = nil
+ } else {
+ if *memory.Swappiness < 0 || *memory.Swappiness > 100 {
+ return warnings, errors.Errorf("invalid value: %v, valid memory swappiness range is 0-100", *memory.Swappiness)
+ }
+ }
+ }
+ if memory.Reservation != nil && !sysInfo.MemoryReservation {
+ warnings = append(warnings, "Your kernel does not support memory soft limit capabilities or the cgroup is not mounted. Limitation discarded.")
+ memory.Reservation = nil
+ }
+ if memory.Limit != nil && memory.Reservation != nil && *memory.Limit < *memory.Reservation {
+ return warnings, errors.New("minimum memory limit cannot be less than memory reservation limit, see usage")
+ }
+ if memory.Kernel != nil && !sysInfo.KernelMemory {
+ warnings = append(warnings, "Your kernel does not support kernel memory limit capabilities or the cgroup is not mounted. Limitation discarded.")
+ memory.Kernel = nil
+ }
+ if memory.DisableOOMKiller != nil && *memory.DisableOOMKiller && !sysInfo.OomKillDisable {
+ warnings = append(warnings, "Your kernel does not support OomKillDisable. OomKillDisable discarded.")
+ memory.DisableOOMKiller = nil
+ }
+ }
+
+ // Pids checks
+ if s.ResourceLimits.Pids != nil {
+ pids := s.ResourceLimits.Pids
+ // TODO: Should this be 0, or checking that ResourceLimits.Pids
+ // is set at all?
+ if pids.Limit > 0 && !sysInfo.PidsLimit {
+ warnings = append(warnings, "Your kernel does not support pids limit capabilities or the cgroup is not mounted. PIDs limit discarded.")
+ s.ResourceLimits.Pids = nil
+ }
+ }
+
+ // CPU Checks
+ if s.ResourceLimits.CPU != nil {
+ cpu := s.ResourceLimits.CPU
+ if cpu.Shares != nil && !sysInfo.CPUShares {
+ warnings = append(warnings, "Your kernel does not support CPU shares or the cgroup is not mounted. Shares discarded.")
+ cpu.Shares = nil
+ }
+ if cpu.Period != nil && !sysInfo.CPUCfsPeriod {
+ warnings = append(warnings, "Your kernel does not support CPU cfs period or the cgroup is not mounted. Period discarded.")
+ cpu.Period = nil
+ }
+ if cpu.Period != nil && (*cpu.Period < 1000 || *cpu.Period > 1000000) {
+ return warnings, errors.New("CPU cfs period cannot be less than 1ms (i.e. 1000) or larger than 1s (i.e. 1000000)")
+ }
+ if cpu.Quota != nil && !sysInfo.CPUCfsQuota {
+ warnings = append(warnings, "Your kernel does not support CPU cfs quota or the cgroup is not mounted. Quota discarded.")
+ cpu.Quota = nil
+ }
+ if cpu.Quota != nil && *cpu.Quota < 1000 {
+ return warnings, errors.New("CPU cfs quota cannot be less than 1ms (i.e. 1000)")
+ }
+ if (cpu.Cpus != "" || cpu.Mems != "") && !sysInfo.Cpuset {
+ warnings = append(warnings, "Your kernel does not support cpuset or the cgroup is not mounted. CPUset discarded.")
+ cpu.Cpus = ""
+ cpu.Mems = ""
+ }
+
+ cpusAvailable, err := sysInfo.IsCpusetCpusAvailable(cpu.Cpus)
+ if err != nil {
+ return warnings, errors.Errorf("invalid value %s for cpuset cpus", cpu.Cpus)
+ }
+ if !cpusAvailable {
+ return warnings, errors.Errorf("requested CPUs are not available - requested %s, available: %s", cpu.Cpus, sysInfo.Cpus)
+ }
+
+ memsAvailable, err := sysInfo.IsCpusetMemsAvailable(cpu.Mems)
+ if err != nil {
+ return warnings, errors.Errorf("invalid value %s for cpuset mems", cpu.Mems)
+ }
+ if !memsAvailable {
+ return warnings, errors.Errorf("requested memory nodes are not available - requested %s, available: %s", cpu.Mems, sysInfo.Mems)
+ }
+ }
+
+ // Blkio checks
+ if s.ResourceLimits.BlockIO != nil {
+ blkio := s.ResourceLimits.BlockIO
+ if blkio.Weight != nil && !sysInfo.BlkioWeight {
+ warnings = append(warnings, "Your kernel does not support Block I/O weight or the cgroup is not mounted. Weight discarded.")
+ blkio.Weight = nil
+ }
+ if blkio.Weight != nil && (*blkio.Weight > 1000 || *blkio.Weight < 10) {
+ return warnings, errors.New("range of blkio weight is from 10 to 1000")
+ }
+ if len(blkio.WeightDevice) > 0 && !sysInfo.BlkioWeightDevice {
+ warnings = append(warnings, "Your kernel does not support Block I/O weight_device or the cgroup is not mounted. Weight-device discarded.")
+ blkio.WeightDevice = nil
+ }
+ if len(blkio.ThrottleReadBpsDevice) > 0 && !sysInfo.BlkioReadBpsDevice {
+ warnings = append(warnings, "Your kernel does not support BPS Block I/O read limit or the cgroup is not mounted. Block I/O BPS read limit discarded")
+ blkio.ThrottleReadBpsDevice = nil
+ }
+ if len(blkio.ThrottleWriteBpsDevice) > 0 && !sysInfo.BlkioWriteBpsDevice {
+ warnings = append(warnings, "Your kernel does not support BPS Block I/O write limit or the cgroup is not mounted. Block I/O BPS write limit discarded.")
+ blkio.ThrottleWriteBpsDevice = nil
+ }
+ if len(blkio.ThrottleReadIOPSDevice) > 0 && !sysInfo.BlkioReadIOpsDevice {
+ warnings = append(warnings, "Your kernel does not support IOPS Block read limit or the cgroup is not mounted. Block I/O IOPS read limit discarded.")
+ blkio.ThrottleReadIOPSDevice = nil
+ }
+ if len(blkio.ThrottleWriteIOPSDevice) > 0 && !sysInfo.BlkioWriteIOpsDevice {
+ warnings = append(warnings, "Your kernel does not support IOPS Block I/O write limit or the cgroup is not mounted. Block I/O IOPS write limit discarded.")
+ blkio.ThrottleWriteIOPSDevice = nil
+ }
+ }
+
+ return warnings, nil
+}
diff --git a/pkg/systemd/generate/containers.go b/pkg/systemd/generate/containers.go
index 4180022cb..16ff0b821 100644
--- a/pkg/systemd/generate/containers.go
+++ b/pkg/systemd/generate/containers.go
@@ -83,9 +83,7 @@ ExecStartPre={{.ExecStartPre}}
{{- end}}
ExecStart={{.ExecStart}}
ExecStop={{.ExecStop}}
-{{- if .ExecStopPost}}
ExecStopPost={{.ExecStopPost}}
-{{- end}}
PIDFile={{.PIDFile}}
KillMode=none
Type=forking
@@ -170,6 +168,7 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
info.EnvVariable = EnvVariable
info.ExecStart = "{{.Executable}} start {{.ContainerNameOrID}}"
info.ExecStop = "{{.Executable}} stop {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} {{.ContainerNameOrID}}"
+ info.ExecStopPost = "{{.Executable}} stop {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} {{.ContainerNameOrID}}"
// Assemble the ExecStart command when creating a new container.
//
diff --git a/pkg/systemd/generate/containers_test.go b/pkg/systemd/generate/containers_test.go
index 8d3ea1ca0..5f35c31f5 100644
--- a/pkg/systemd/generate/containers_test.go
+++ b/pkg/systemd/generate/containers_test.go
@@ -50,6 +50,7 @@ Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
ExecStart=/usr/bin/podman start 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
ExecStop=/usr/bin/podman stop -t 10 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
+ExecStopPost=/usr/bin/podman stop -t 10 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
KillMode=none
Type=forking
@@ -71,6 +72,7 @@ Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
ExecStart=/usr/bin/podman start foobar
ExecStop=/usr/bin/podman stop -t 10 foobar
+ExecStopPost=/usr/bin/podman stop -t 10 foobar
PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
KillMode=none
Type=forking
@@ -96,6 +98,7 @@ Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
ExecStart=/usr/bin/podman start foobar
ExecStop=/usr/bin/podman stop -t 10 foobar
+ExecStopPost=/usr/bin/podman stop -t 10 foobar
PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
KillMode=none
Type=forking
diff --git a/pkg/systemd/generate/pods.go b/pkg/systemd/generate/pods.go
index 367b8381f..1bd0c7bce 100644
--- a/pkg/systemd/generate/pods.go
+++ b/pkg/systemd/generate/pods.go
@@ -82,9 +82,7 @@ ExecStartPre={{.ExecStartPre2}}
{{- end}}
ExecStart={{.ExecStart}}
ExecStop={{.ExecStop}}
-{{- if .ExecStopPost}}
ExecStopPost={{.ExecStopPost}}
-{{- end}}
PIDFile={{.PIDFile}}
KillMode=none
Type=forking
@@ -236,6 +234,7 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions)
info.EnvVariable = EnvVariable
info.ExecStart = "{{.Executable}} start {{.InfraNameOrID}}"
info.ExecStop = "{{.Executable}} stop {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} {{.InfraNameOrID}}"
+ info.ExecStopPost = "{{.Executable}} stop {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} {{.InfraNameOrID}}"
// Assemble the ExecStart command when creating a new pod.
//
diff --git a/pkg/systemd/generate/pods_test.go b/pkg/systemd/generate/pods_test.go
index f7ce33a30..e12222317 100644
--- a/pkg/systemd/generate/pods_test.go
+++ b/pkg/systemd/generate/pods_test.go
@@ -52,6 +52,7 @@ Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
ExecStart=/usr/bin/podman start jadda-jadda-infra
ExecStop=/usr/bin/podman stop -t 10 jadda-jadda-infra
+ExecStopPost=/usr/bin/podman stop -t 10 jadda-jadda-infra
PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
KillMode=none
Type=forking
diff --git a/test/e2e/inspect_test.go b/test/e2e/inspect_test.go
index 62f69f1c1..2fad38a36 100644
--- a/test/e2e/inspect_test.go
+++ b/test/e2e/inspect_test.go
@@ -223,4 +223,44 @@ var _ = Describe("Podman inspect", func() {
Expect(baseJSON[0].ID).To(Equal(ctrJSON[0].ID))
})
+
+ It("podman inspect always produces a valid array", func() {
+ baseInspect := podmanTest.Podman([]string{"inspect", "doesNotExist"})
+ baseInspect.WaitWithDefaultTimeout()
+ Expect(baseInspect.ExitCode()).To(Not(Equal(0)))
+ emptyJSON := baseInspect.InspectContainerToJSON()
+ Expect(len(emptyJSON)).To(Equal(0))
+ })
+
+ It("podman inspect one container with not exist returns 1-length valid array", func() {
+ ctrName := "testCtr"
+ create := podmanTest.Podman([]string{"create", "--name", ctrName, ALPINE, "sh"})
+ create.WaitWithDefaultTimeout()
+ Expect(create.ExitCode()).To(Equal(0))
+
+ baseInspect := podmanTest.Podman([]string{"inspect", ctrName, "doesNotExist"})
+ baseInspect.WaitWithDefaultTimeout()
+ Expect(baseInspect.ExitCode()).To(Not(Equal(0)))
+ baseJSON := baseInspect.InspectContainerToJSON()
+ Expect(len(baseJSON)).To(Equal(1))
+ Expect(baseJSON[0].Name).To(Equal(ctrName))
+ })
+
+ It("podman inspect container + image with same name gives container", func() {
+ ctrName := "testcontainer"
+ create := podmanTest.PodmanNoCache([]string{"create", "--name", ctrName, ALPINE, "sh"})
+ create.WaitWithDefaultTimeout()
+ Expect(create.ExitCode()).To(Equal(0))
+
+ tag := podmanTest.PodmanNoCache([]string{"tag", ALPINE, ctrName + ":latest"})
+ tag.WaitWithDefaultTimeout()
+ Expect(tag.ExitCode()).To(Equal(0))
+
+ baseInspect := podmanTest.Podman([]string{"inspect", ctrName})
+ baseInspect.WaitWithDefaultTimeout()
+ Expect(baseInspect.ExitCode()).To(Equal(0))
+ baseJSON := baseInspect.InspectContainerToJSON()
+ Expect(len(baseJSON)).To(Equal(1))
+ Expect(baseJSON[0].Name).To(Equal(ctrName))
+ })
})
diff --git a/test/e2e/logs_test.go b/test/e2e/logs_test.go
index f9446e0c6..5d8ce24e9 100644
--- a/test/e2e/logs_test.go
+++ b/test/e2e/logs_test.go
@@ -283,10 +283,22 @@ var _ = Describe("Podman logs", func() {
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
- // Verify that the cleanup process worked correctly and we can recreate a container with the same name
- logc = podmanTest.Podman([]string{"run", "--rm", "--name", containerName, "-dt", ALPINE, "true"})
- logc.WaitWithDefaultTimeout()
- Expect(logc).To(Exit(0))
+ // TODO: we should actually check for two podman lines,
+ // but as of 2020-06-17 there's a race condition in which
+ // 'logs -f' may not catch all output from a container
+ Expect(results.OutputToString()).To(ContainSubstring("podman"))
+
+ // Container should now be terminatING or terminatED, but we
+ // have no guarantee of which: 'logs -f' does not necessarily
+ // wait for cleanup. Run 'inspect' and accept either state.
+ inspect := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.State.Status}}", containerName})
+ inspect.WaitWithDefaultTimeout()
+ if inspect.ExitCode() == 0 {
+ Expect(inspect.OutputToString()).To(Equal("exited"))
+ // TODO: add 2-second wait loop to confirm cleanup
+ } else {
+ Expect(inspect.ErrorToString()).To(ContainSubstring("no such container"))
+ }
})
It("follow output stopped container", func() {
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index 76944b3db..6dce0b48d 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -151,12 +151,36 @@ var _ = Describe("Podman run", func() {
session := podmanTest.Podman([]string{"run", "--init", ALPINE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
+ result := podmanTest.Podman([]string{"inspect", "-l"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ conData := result.InspectContainerToJSON()
+ Expect(conData[0].Path).To(Equal("/dev/init"))
+ Expect(conData[0].Config.Annotations["io.podman.annotations.init"]).To(Equal("TRUE"))
})
It("podman run a container with --init and --init-path", func() {
session := podmanTest.Podman([]string{"run", "--init", "--init-path", "/usr/libexec/podman/catatonit", ALPINE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
+ result := podmanTest.Podman([]string{"inspect", "-l"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ conData := result.InspectContainerToJSON()
+ Expect(conData[0].Path).To(Equal("/dev/init"))
+ Expect(conData[0].Config.Annotations["io.podman.annotations.init"]).To(Equal("TRUE"))
+ })
+
+ It("podman run a container without --init", func() {
+ session := podmanTest.Podman([]string{"run", ALPINE, "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ result := podmanTest.Podman([]string{"inspect", "-l"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ conData := result.InspectContainerToJSON()
+ Expect(conData[0].Path).To(Equal("ls"))
+ Expect(conData[0].Config.Annotations["io.podman.annotations.init"]).To(Equal("FALSE"))
})
It("podman run seccomp test", func() {
diff --git a/vendor/github.com/containers/common/pkg/config/config.go b/vendor/github.com/containers/common/pkg/config/config.go
index 9657ecb69..ce479088e 100644
--- a/vendor/github.com/containers/common/pkg/config/config.go
+++ b/vendor/github.com/containers/common/pkg/config/config.go
@@ -74,105 +74,105 @@ type Config struct {
type ContainersConfig struct {
// Devices to add to all containers
- Devices []string `toml:"devices"`
+ Devices []string `toml:"devices,omitempty"`
// Volumes to add to all containers
- Volumes []string `toml:"volumes"`
+ Volumes []string `toml:"volumes,omitempty"`
// ApparmorProfile is the apparmor profile name which is used as the
// default for the runtime.
- ApparmorProfile string `toml:"apparmor_profile"`
+ ApparmorProfile string `toml:"apparmor_profile,omitempty"`
// Annotation to add to all containers
- Annotations []string `toml:"annotations"`
+ Annotations []string `toml:"annotations,omitempty"`
// Default way to create a cgroup namespace for the container
- CgroupNS string `toml:"cgroupns"`
+ CgroupNS string `toml:"cgroupns,omitempty"`
// Default cgroup configuration
- Cgroups string `toml:"cgroups"`
+ Cgroups string `toml:"cgroups,omitempty"`
// Capabilities to add to all containers.
- DefaultCapabilities []string `toml:"default_capabilities"`
+ DefaultCapabilities []string `toml:"default_capabilities,omitempty"`
// Sysctls to add to all containers.
- DefaultSysctls []string `toml:"default_sysctls"`
+ DefaultSysctls []string `toml:"default_sysctls,omitempty"`
// DefaultUlimits specifies the default ulimits to apply to containers
- DefaultUlimits []string `toml:"default_ulimits"`
+ DefaultUlimits []string `toml:"default_ulimits,omitempty"`
// DefaultMountsFile is the path to the default mounts file for testing
DefaultMountsFile string `toml:"-"`
// DNSServers set default DNS servers.
- DNSServers []string `toml:"dns_servers"`
+ DNSServers []string `toml:"dns_servers,omitempty"`
// DNSOptions set default DNS options.
- DNSOptions []string `toml:"dns_options"`
+ DNSOptions []string `toml:"dns_options,omitempty"`
// DNSSearches set default DNS search domains.
- DNSSearches []string `toml:"dns_searches"`
+ DNSSearches []string `toml:"dns_searches,omitempty"`
// EnableLabeling tells the container engines whether to use MAC
// Labeling to separate containers (SELinux)
- EnableLabeling bool `toml:"label"`
+ EnableLabeling bool `toml:"label,omitempty"`
// Env is the environment variable list for container process.
- Env []string `toml:"env"`
+ Env []string `toml:"env,omitempty"`
// EnvHost Pass all host environment variables into the container.
- EnvHost bool `toml:"env_host"`
+ EnvHost bool `toml:"env_host,omitempty"`
// HTTPProxy is the proxy environment variable list to apply to container process
- HTTPProxy bool `toml:"http_proxy"`
+ HTTPProxy bool `toml:"http_proxy,omitempty"`
// Init tells container runtimes whether to run init inside the
// container that forwards signals and reaps processes.
- Init bool `toml:"init"`
+ Init bool `toml:"init,omitempty"`
// InitPath is the path for init to run if the Init bool is enabled
- InitPath string `toml:"init_path"`
+ InitPath string `toml:"init_path,omitempty"`
// IPCNS way to to create a ipc namespace for the container
- IPCNS string `toml:"ipcns"`
+ IPCNS string `toml:"ipcns,omitempty"`
// LogDriver for the container. For example: k8s-file and journald
- LogDriver string `toml:"log_driver"`
+ LogDriver string `toml:"log_driver,omitempty"`
// LogSizeMax is the maximum number of bytes after which the log file
// will be truncated. It can be expressed as a human-friendly string
// that is parsed to bytes.
// Negative values indicate that the log file won't be truncated.
- LogSizeMax int64 `toml:"log_size_max"`
+ LogSizeMax int64 `toml:"log_size_max,omitempty"`
// NetNS indicates how to create a network namespace for the container
- NetNS string `toml:"netns"`
+ NetNS string `toml:"netns,omitempty"`
// NoHosts tells container engine whether to create its own /etc/hosts
- NoHosts bool `toml:"no_hosts"`
+ NoHosts bool `toml:"no_hosts,omitempty"`
// PidsLimit is the number of processes each container is restricted to
// by the cgroup process number controller.
- PidsLimit int64 `toml:"pids_limit"`
+ PidsLimit int64 `toml:"pids_limit,omitempty"`
// PidNS indicates how to create a pid namespace for the container
- PidNS string `toml:"pidns"`
+ PidNS string `toml:"pidns,omitempty"`
// SeccompProfile is the seccomp.json profile path which is used as the
// default for the runtime.
- SeccompProfile string `toml:"seccomp_profile"`
+ SeccompProfile string `toml:"seccomp_profile,omitempty"`
// ShmSize holds the size of /dev/shm.
- ShmSize string `toml:"shm_size"`
+ ShmSize string `toml:"shm_size,omitempty"`
// UTSNS indicates how to create a UTS namespace for the container
- UTSNS string `toml:"utsns"`
+ UTSNS string `toml:"utsns,omitempty"`
// UserNS indicates how to create a User namespace for the container
- UserNS string `toml:"userns"`
+ UserNS string `toml:"userns,omitempty"`
// UserNSSize how many UIDs to allocate for automatically created UserNS
- UserNSSize int `toml:"userns_size"`
+ UserNSSize int `toml:"userns_size,omitempty"`
}
// EngineConfig contains configuration options used to set up a engine runtime
@@ -183,20 +183,20 @@ type EngineConfig struct {
// CGroupManager is the CGroup Manager to use Valid values are "cgroupfs"
// and "systemd".
- CgroupManager string `toml:"cgroup_manager"`
+ CgroupManager string `toml:"cgroup_manager,omitempty"`
// NOTE: when changing this struct, make sure to update (*Config).Merge().
// ConmonEnvVars are environment variables to pass to the Conmon binary
// when it is launched.
- ConmonEnvVars []string `toml:"conmon_env_vars"`
+ ConmonEnvVars []string `toml:"conmon_env_vars,omitempty"`
// ConmonPath is the path to the Conmon binary used for managing containers.
// The first path pointing to a valid file will be used.
- ConmonPath []string `toml:"conmon_path"`
+ ConmonPath []string `toml:"conmon_path,omitempty"`
//DetachKeys is the sequence of keys used to detach a container.
- DetachKeys string `toml:"detach_keys"`
+ DetachKeys string `toml:"detach_keys,omitempty"`
// EnablePortReservation determines whether engine will reserve ports on the
// host when they are forwarded to containers. When enabled, when ports are
@@ -205,32 +205,32 @@ type EngineConfig struct {
// programs on the host. However, this can cause significant memory usage if
// a container has many ports forwarded to it. Disabling this can save
// memory.
- EnablePortReservation bool `toml:"enable_port_reservation"`
+ EnablePortReservation bool `toml:"enable_port_reservation,omitempty"`
// EventsLogFilePath is where the events log is stored.
- EventsLogFilePath string `toml:"events_logfile_path"`
+ EventsLogFilePath string `toml:"events_logfile_path,omitempty"`
// EventsLogger determines where events should be logged.
- EventsLogger string `toml:"events_logger"`
+ EventsLogger string `toml:"events_logger,omitempty"`
// configuration files. When the same filename is present in in
// multiple directories, the file in the directory listed last in
// this slice takes precedence.
- HooksDir []string `toml:"hooks_dir"`
+ HooksDir []string `toml:"hooks_dir,omitempty"`
// ImageDefaultTransport is the default transport method used to fetch
// images.
- ImageDefaultTransport string `toml:"image_default_transport"`
+ ImageDefaultTransport string `toml:"image_default_transport,omitempty"`
// InfraCommand is the command run to start up a pod infra container.
- InfraCommand string `toml:"infra_command"`
+ InfraCommand string `toml:"infra_command,omitempty"`
// InfraImage is the image a pod infra container will use to manage
// namespaces.
- InfraImage string `toml:"infra_image"`
+ InfraImage string `toml:"infra_image,omitempty"`
// InitPath is the path to the container-init binary.
- InitPath string `toml:"init_path"`
+ InitPath string `toml:"init_path,omitempty"`
// LockType is the type of locking to use.
LockType string `toml:"lock_type,omitempty"`
@@ -244,27 +244,27 @@ type EngineConfig struct {
Namespace string `toml:"namespace,omitempty"`
// NetworkCmdPath is the path to the slirp4netns binary.
- NetworkCmdPath string `toml:"network_cmd_path"`
+ NetworkCmdPath string `toml:"network_cmd_path,omitempty"`
// NoPivotRoot sets whether to set no-pivot-root in the OCI runtime.
- NoPivotRoot bool `toml:"no_pivot_root"`
+ NoPivotRoot bool `toml:"no_pivot_root,omitempty"`
// NumLocks is the number of locks to make available for containers and
// pods.
NumLocks uint32 `toml:"num_locks,omitempty"`
// OCIRuntime is the OCI runtime to use.
- OCIRuntime string `toml:"runtime"`
+ OCIRuntime string `toml:"runtime,omitempty"`
// OCIRuntimes are the set of configured OCI runtimes (default is runc).
- OCIRuntimes map[string][]string `toml:"runtimes"`
+ OCIRuntimes map[string][]string `toml:"runtimes,omitempty"`
// PullPolicy determines whether to pull image before creating or running a container
// default is "missing"
- PullPolicy string `toml:"pull_policy"`
+ PullPolicy string `toml:"pull_policy,omitempty"`
// Indicates whether the application should be running in Remote mode
- Remote bool `toml:"_"`
+ Remote bool `toml:"-"`
// RemoteURI containers connection information used to connect to remote system.
RemoteURI string `toml:"remote_uri,omitempty"`
@@ -280,15 +280,15 @@ type EngineConfig struct {
// RuntimeSupportsJSON is the list of the OCI runtimes that support
// --format=json.
- RuntimeSupportsJSON []string `toml:"runtime_supports_json"`
+ RuntimeSupportsJSON []string `toml:"runtime_supports_json,omitempty"`
// RuntimeSupportsNoCgroups is a list of OCI runtimes that support
// running containers without CGroups.
- RuntimeSupportsNoCgroups []string `toml:"runtime_supports_nocgroupv2"`
+ RuntimeSupportsNoCgroups []string `toml:"runtime_supports_nocgroupv2,omitempty"`
// RuntimeSupportsKVM is a list of OCI runtimes that support
// KVM separation for conatainers.
- RuntimeSupportsKVM []string `toml:"runtime_supports_kvm"`
+ RuntimeSupportsKVM []string `toml:"runtime_supports_kvm,omitempty"`
// SetOptions contains a subset of config options. It's used to indicate if
// a given option has either been set by the user or by the parsed
@@ -300,11 +300,11 @@ type EngineConfig struct {
// SignaturePolicyPath is the path to a signature policy to use for
// validating images. If left empty, the containers/image default signature
// policy will be used.
- SignaturePolicyPath string `toml:"_"`
+ SignaturePolicyPath string `toml:"-"`
// SDNotify tells container engine to allow containers to notify the host systemd of
// readiness using the SD_NOTIFY mechanism.
- SDNotify bool
+ SDNotify bool `toml:"-"`
// StateType is the type of the backing state store. Avoid using multiple
// values for this with the same containers/storage configuration on the
@@ -315,20 +315,20 @@ type EngineConfig struct {
// StaticDir is the path to a persistent directory to store container
// files.
- StaticDir string `toml:"static_dir"`
+ StaticDir string `toml:"static_dir,omitempty"`
// StopTimeout is the number of seconds to wait for container to exit
// before sending kill signal.
- StopTimeout uint `toml:"stop_timeout"`
+ StopTimeout uint `toml:"stop_timeout,omitempty"`
// TmpDir is the path to a temporary directory to store per-boot container
// files. Must be stored in a tmpfs.
- TmpDir string `toml:"tmp_dir"`
+ TmpDir string `toml:"tmp_dir,omitempty"`
// VolumePath is the default location that named volumes will be created
// under. This convention is followed by the default volume driver, but
// may not be by other drivers.
- VolumePath string `toml:"volume_path"`
+ VolumePath string `toml:"volume_path,omitempty"`
}
// SetOptions contains a subset of options in a Config. It's used to indicate if
@@ -377,14 +377,14 @@ type SetOptions struct {
// NetworkConfig represents the "network" TOML config table
type NetworkConfig struct {
// CNIPluginDirs is where CNI plugin binaries are stored.
- CNIPluginDirs []string `toml:"cni_plugin_dirs"`
+ CNIPluginDirs []string `toml:"cni_plugin_dirs,omitempty"`
// DefaultNetwork is the network name of the default CNI network
// to attach pods to.
DefaultNetwork string `toml:"default_network,omitempty"`
// NetworkConfigDir is where CNI network configuration files are stored.
- NetworkConfigDir string `toml:"network_config_dir"`
+ NetworkConfigDir string `toml:"network_config_dir,omitempty"`
}
// NewConfig creates a new Config. It starts with an empty config and, if
@@ -856,3 +856,77 @@ func Path() string {
}
return OverrideContainersConfig
}
+
+func customConfigFile() (string, error) {
+ path := os.Getenv("CONTAINERS_CONF")
+ if path != "" {
+ return path, nil
+ }
+ if unshare.IsRootless() {
+ path, err := rootlessConfigPath()
+ if err != nil {
+ return "", err
+ }
+ return path, nil
+ }
+ return OverrideContainersConfig, nil
+}
+
+//ReadCustomConfig reads the custom config and only generates a config based on it
+//If the custom config file does not exists, function will return an empty config
+func ReadCustomConfig() (*Config, error) {
+ path, err := customConfigFile()
+ if err != nil {
+ return nil, err
+ }
+ // hack since Ommitempty does not seem to work with Write
+ c, err := Default()
+ if err != nil {
+ if os.IsNotExist(errors.Cause(err)) {
+ c, err = DefaultConfig()
+ }
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ newConfig := &Config{}
+ if _, err := os.Stat(path); err == nil {
+ newConfig, err = readConfigFromFile(path, newConfig)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ if !os.IsNotExist(err) {
+ return nil, err
+ }
+ }
+ newConfig.Containers.LogSizeMax = c.Containers.LogSizeMax
+ newConfig.Containers.PidsLimit = c.Containers.PidsLimit
+ newConfig.Containers.UserNSSize = c.Containers.UserNSSize
+ newConfig.Engine.NumLocks = c.Engine.NumLocks
+ newConfig.Engine.StopTimeout = c.Engine.StopTimeout
+ return newConfig, nil
+}
+
+// Write writes the configuration to the default file
+func (c *Config) Write() error {
+ var err error
+ path, err := customConfigFile()
+ if err != nil {
+ return err
+ }
+ if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
+ return err
+ }
+ configFile, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0600)
+ if err != nil {
+ return errors.Wrapf(err, "cannot open %s", path)
+ }
+ defer configFile.Close()
+ enc := toml.NewEncoder(configFile)
+ if err := enc.Encode(c); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/vendor/github.com/containers/common/pkg/config/containers.conf b/vendor/github.com/containers/common/pkg/config/containers.conf
index a029aedeb..389479fa5 100644
--- a/vendor/github.com/containers/common/pkg/config/containers.conf
+++ b/vendor/github.com/containers/common/pkg/config/containers.conf
@@ -92,7 +92,7 @@
# Ulimits has limits for non privileged container engines.
#
# default_ulimits = [
-# “nofile”=”1280:2560”,
+# "nofile"="1280:2560",
# ]
# List of default DNS options to be added to /etc/resolv.conf inside of the container.
@@ -105,7 +105,7 @@
# Set default DNS servers.
# This option can be used to override the DNS configuration passed to the
-# container. The special value “none” can be specified to disable creation of
+# container. The special value "none" can be specified to disable creation of
# /etc/resolv.conf in the container.
# The /etc/resolv.conf file in the image will be used without changes.
#
@@ -125,7 +125,7 @@
# Path to OCI hooks directories for automatically executed hooks.
#
# hooks_dir = [
-# “/usr/share/containers/oci/hooks.d”,
+# "/usr/share/containers/oci/hooks.d",
# ]
# Default proxy environment variables passed into the container.
@@ -220,7 +220,7 @@
# userns = "host"
# Number of UIDs to allocate for the automatic container creation.
-# UIDs are allocated from the “container” UIDs listed in
+# UIDs are allocated from the "container" UIDs listed in
# /etc/subuid & /etc/subgid
#
# userns_size=65536
@@ -241,7 +241,7 @@
[engine]
# Cgroup management implementation used for the runtime.
-# Valid options “systemd” or “cgroupfs”
+# Valid options "systemd" or "cgroupfs"
#
# cgroup_manager = "systemd"
diff --git a/vendor/github.com/containers/image/v5/copy/copy.go b/vendor/github.com/containers/image/v5/copy/copy.go
index 9fc0e5123..7482fb458 100644
--- a/vendor/github.com/containers/image/v5/copy/copy.go
+++ b/vendor/github.com/containers/image/v5/copy/copy.go
@@ -659,7 +659,7 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
// With !ic.canModifyManifest, that would just be a string of repeated failures for the same reason,
// so let’s bail out early and with a better error message.
if !ic.canModifyManifest {
- return nil, "", "", errors.Wrap(err, "Writing manifest failed (and converting it is not possible)")
+ return nil, "", "", errors.Wrap(err, "Writing manifest failed (and converting it is not possible, image is signed or the destination specifies a digest)")
}
// errs is a list of errors when trying various manifest types. Also serves as an "upload succeeded" flag when set to nil.
@@ -757,7 +757,7 @@ func (ic *imageCopier) updateEmbeddedDockerReference() error {
}
if !ic.canModifyManifest {
- return errors.Errorf("Copying a schema1 image with an embedded Docker reference to %s (Docker reference %s) would invalidate existing signatures. Explicitly enable signature removal to proceed anyway",
+ return errors.Errorf("Copying a schema1 image with an embedded Docker reference to %s (Docker reference %s) would change the manifest, which is not possible (image is signed or the destination specifies a digest)",
transports.ImageName(ic.c.dest.Reference()), destRef.String())
}
ic.manifestUpdates.EmbeddedDockerReference = destRef
@@ -784,7 +784,7 @@ func (ic *imageCopier) copyLayers(ctx context.Context) error {
// If we only need to check authorization, no updates required.
if updatedSrcInfos != nil && !reflect.DeepEqual(srcInfos, updatedSrcInfos) {
if !ic.canModifyManifest {
- return errors.Errorf("Internal error: copyLayers() needs to use an updated manifest but that was known to be forbidden")
+ return errors.Errorf("Copying this image requires changing layer representation, which is not possible (image is signed or the destination specifies a digest)")
}
srcInfos = updatedSrcInfos
srcInfosUpdated = true
@@ -1060,6 +1060,14 @@ func (ic *imageCopier) copyLayer(ctx context.Context, srcInfo types.BlobInfo, to
logrus.Debugf("Skipping blob %s (already present):", srcInfo.Digest)
bar := ic.c.createProgressBar(pool, srcInfo, "blob", "skipped: already exists")
bar.SetTotal(0, true)
+
+ // Throw an event that the layer has been skipped
+ if ic.c.progress != nil && ic.c.progressInterval > 0 {
+ ic.c.progress <- types.ProgressProperties{
+ Event: types.ProgressEventSkipped,
+ Artifact: srcInfo,
+ }
+ }
return blobInfo, cachedDiffID, nil
}
}
diff --git a/vendor/github.com/containers/image/v5/oci/layout/oci_dest.go b/vendor/github.com/containers/image/v5/oci/layout/oci_dest.go
index fb0449ca5..48a32315b 100644
--- a/vendor/github.com/containers/image/v5/oci/layout/oci_dest.go
+++ b/vendor/github.com/containers/image/v5/oci/layout/oci_dest.go
@@ -279,7 +279,7 @@ func (d *ociImageDestination) addManifest(desc *imgspecv1.Descriptor) {
// If it has the same digest as another entry in the index, we already overwrote the file,
// so just pick up the other information.
for i, manifest := range d.index.Manifests {
- if manifest.Digest == desc.Digest {
+ if manifest.Digest == desc.Digest && manifest.Annotations[imgspecv1.AnnotationRefName] == "" {
// Replace it completely.
d.index.Manifests[i] = *desc
return
diff --git a/vendor/github.com/containers/image/v5/types/types.go b/vendor/github.com/containers/image/v5/types/types.go
index d469e03b5..4f624cf33 100644
--- a/vendor/github.com/containers/image/v5/types/types.go
+++ b/vendor/github.com/containers/image/v5/types/types.go
@@ -604,6 +604,10 @@ const (
// ProgressEventDone is fired when the data transfer has been finished for
// the specific artifact
ProgressEventDone
+
+ // ProgressEventSkipped is fired when the artifact has been skipped because
+ // its already available at the destination
+ ProgressEventSkipped
)
// ProgressProperties is used to pass information from the copy code to a monitor which
diff --git a/vendor/github.com/containers/image/v5/version/version.go b/vendor/github.com/containers/image/v5/version/version.go
index 7cf412723..114bce387 100644
--- a/vendor/github.com/containers/image/v5/version/version.go
+++ b/vendor/github.com/containers/image/v5/version/version.go
@@ -8,10 +8,10 @@ const (
// VersionMinor is for functionality in a backwards-compatible manner
VersionMinor = 5
// VersionPatch is for backwards-compatible bug fixes
- VersionPatch = 0
+ VersionPatch = 1
// VersionDev indicates development branch. Releases will be empty string.
- VersionDev = "-dev"
+ VersionDev = ""
)
// Version is the specification version that the package types support.
diff --git a/vendor/github.com/klauspost/compress/fse/bitreader.go b/vendor/github.com/klauspost/compress/fse/bitreader.go
index b9db204f5..f65eb3909 100644
--- a/vendor/github.com/klauspost/compress/fse/bitreader.go
+++ b/vendor/github.com/klauspost/compress/fse/bitreader.go
@@ -6,6 +6,7 @@
package fse
import (
+ "encoding/binary"
"errors"
"io"
)
@@ -34,8 +35,12 @@ func (b *bitReader) init(in []byte) error {
}
b.bitsRead = 64
b.value = 0
- b.fill()
- b.fill()
+ if len(in) >= 8 {
+ b.fillFastStart()
+ } else {
+ b.fill()
+ b.fill()
+ }
b.bitsRead += 8 - uint8(highBits(uint32(v)))
return nil
}
@@ -63,8 +68,9 @@ func (b *bitReader) fillFast() {
if b.bitsRead < 32 {
return
}
- // Do single re-slice to avoid bounds checks.
- v := b.in[b.off-4 : b.off]
+ // 2 bounds checks.
+ v := b.in[b.off-4:]
+ v = v[:4]
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
b.value = (b.value << 32) | uint64(low)
b.bitsRead -= 32
@@ -77,7 +83,8 @@ func (b *bitReader) fill() {
return
}
if b.off > 4 {
- v := b.in[b.off-4 : b.off]
+ v := b.in[b.off-4:]
+ v = v[:4]
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
b.value = (b.value << 32) | uint64(low)
b.bitsRead -= 32
@@ -91,9 +98,17 @@ func (b *bitReader) fill() {
}
}
+// fillFastStart() assumes the bitreader is empty and there is at least 8 bytes to read.
+func (b *bitReader) fillFastStart() {
+ // Do single re-slice to avoid bounds checks.
+ b.value = binary.LittleEndian.Uint64(b.in[b.off-8:])
+ b.bitsRead = 0
+ b.off -= 8
+}
+
// finished returns true if all bits have been read from the bit stream.
func (b *bitReader) finished() bool {
- return b.off == 0 && b.bitsRead >= 64
+ return b.bitsRead >= 64 && b.off == 0
}
// close the bitstream and returns an error if out-of-buffer reads occurred.
diff --git a/vendor/github.com/klauspost/compress/fse/bytereader.go b/vendor/github.com/klauspost/compress/fse/bytereader.go
index f228a46cd..abade2d60 100644
--- a/vendor/github.com/klauspost/compress/fse/bytereader.go
+++ b/vendor/github.com/klauspost/compress/fse/bytereader.go
@@ -25,19 +25,10 @@ func (b *byteReader) advance(n uint) {
b.off += int(n)
}
-// Int32 returns a little endian int32 starting at current offset.
-func (b byteReader) Int32() int32 {
- b2 := b.b[b.off : b.off+4 : b.off+4]
- v3 := int32(b2[3])
- v2 := int32(b2[2])
- v1 := int32(b2[1])
- v0 := int32(b2[0])
- return v0 | (v1 << 8) | (v2 << 16) | (v3 << 24)
-}
-
// Uint32 returns a little endian uint32 starting at current offset.
func (b byteReader) Uint32() uint32 {
- b2 := b.b[b.off : b.off+4 : b.off+4]
+ b2 := b.b[b.off:]
+ b2 = b2[:4]
v3 := uint32(b2[3])
v2 := uint32(b2[2])
v1 := uint32(b2[1])
diff --git a/vendor/github.com/klauspost/compress/huff0/README.md b/vendor/github.com/klauspost/compress/huff0/README.md
index 0a8448ce9..e12da4db2 100644
--- a/vendor/github.com/klauspost/compress/huff0/README.md
+++ b/vendor/github.com/klauspost/compress/huff0/README.md
@@ -12,8 +12,6 @@ but it can be used as a secondary step to compressors (like Snappy) that does no
* [Godoc documentation](https://godoc.org/github.com/klauspost/compress/huff0)
-THIS PACKAGE IS NOT CONSIDERED STABLE AND API OR ENCODING MAY CHANGE IN THE FUTURE.
-
## News
* Mar 2018: First implementation released. Consider this beta software for now.
@@ -75,6 +73,8 @@ which can be given to the decompressor.
Decompressing is done by calling the [`Decompress1X`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch.Decompress1X)
or [`Decompress4X`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch.Decompress4X) function.
+For concurrently decompressing content with a fixed table a stateless [`Decoder`](https://godoc.org/github.com/klauspost/compress/huff0#Decoder) can be requested which will remain correct as long as the scratch is unchanged. The capacity of the provided slice indicates the expected output size.
+
You must provide the output from the compression stage, at exactly the size you got back. If you receive an error back
your input was likely corrupted.
@@ -84,4 +84,4 @@ There are no integrity checks, so relying on errors from the decompressor does n
# Contributing
Contributions are always welcome. Be aware that adding public functions will require good justification and breaking
-changes will likely not be accepted. If in doubt open an issue before writing the PR. \ No newline at end of file
+changes will likely not be accepted. If in doubt open an issue before writing the PR.
diff --git a/vendor/github.com/klauspost/compress/huff0/bitreader.go b/vendor/github.com/klauspost/compress/huff0/bitreader.go
index 7d0903c70..a4979e886 100644
--- a/vendor/github.com/klauspost/compress/huff0/bitreader.go
+++ b/vendor/github.com/klauspost/compress/huff0/bitreader.go
@@ -6,6 +6,7 @@
package huff0
import (
+ "encoding/binary"
"errors"
"io"
)
@@ -34,29 +35,16 @@ func (b *bitReader) init(in []byte) error {
}
b.bitsRead = 64
b.value = 0
- b.fill()
- b.fill()
+ if len(in) >= 8 {
+ b.fillFastStart()
+ } else {
+ b.fill()
+ b.fill()
+ }
b.bitsRead += 8 - uint8(highBit32(uint32(v)))
return nil
}
-// getBits will return n bits. n can be 0.
-func (b *bitReader) getBits(n uint8) uint16 {
- if n == 0 || b.bitsRead >= 64 {
- return 0
- }
- return b.getBitsFast(n)
-}
-
-// getBitsFast requires that at least one bit is requested every time.
-// There are no checks if the buffer is filled.
-func (b *bitReader) getBitsFast(n uint8) uint16 {
- const regMask = 64 - 1
- v := uint16((b.value << (b.bitsRead & regMask)) >> ((regMask + 1 - n) & regMask))
- b.bitsRead += n
- return v
-}
-
// peekBitsFast requires that at least one bit is requested every time.
// There are no checks if the buffer is filled.
func (b *bitReader) peekBitsFast(n uint8) uint16 {
@@ -71,21 +59,36 @@ func (b *bitReader) fillFast() {
if b.bitsRead < 32 {
return
}
- // Do single re-slice to avoid bounds checks.
+
+ // 2 bounds checks.
v := b.in[b.off-4 : b.off]
+ v = v[:4]
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
b.value = (b.value << 32) | uint64(low)
b.bitsRead -= 32
b.off -= 4
}
+func (b *bitReader) advance(n uint8) {
+ b.bitsRead += n
+}
+
+// fillFastStart() assumes the bitreader is empty and there is at least 8 bytes to read.
+func (b *bitReader) fillFastStart() {
+ // Do single re-slice to avoid bounds checks.
+ b.value = binary.LittleEndian.Uint64(b.in[b.off-8:])
+ b.bitsRead = 0
+ b.off -= 8
+}
+
// fill() will make sure at least 32 bits are available.
func (b *bitReader) fill() {
if b.bitsRead < 32 {
return
}
if b.off > 4 {
- v := b.in[b.off-4 : b.off]
+ v := b.in[b.off-4:]
+ v = v[:4]
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
b.value = (b.value << 32) | uint64(low)
b.bitsRead -= 32
@@ -113,3 +116,214 @@ func (b *bitReader) close() error {
}
return nil
}
+
+// bitReader reads a bitstream in reverse.
+// The last set bit indicates the start of the stream and is used
+// for aligning the input.
+type bitReaderBytes struct {
+ in []byte
+ off uint // next byte to read is at in[off - 1]
+ value uint64
+ bitsRead uint8
+}
+
+// init initializes and resets the bit reader.
+func (b *bitReaderBytes) init(in []byte) error {
+ if len(in) < 1 {
+ return errors.New("corrupt stream: too short")
+ }
+ b.in = in
+ b.off = uint(len(in))
+ // The highest bit of the last byte indicates where to start
+ v := in[len(in)-1]
+ if v == 0 {
+ return errors.New("corrupt stream, did not find end of stream")
+ }
+ b.bitsRead = 64
+ b.value = 0
+ if len(in) >= 8 {
+ b.fillFastStart()
+ } else {
+ b.fill()
+ b.fill()
+ }
+ b.advance(8 - uint8(highBit32(uint32(v))))
+ return nil
+}
+
+// peekBitsFast requires that at least one bit is requested every time.
+// There are no checks if the buffer is filled.
+func (b *bitReaderBytes) peekByteFast() uint8 {
+ got := uint8(b.value >> 56)
+ return got
+}
+
+func (b *bitReaderBytes) advance(n uint8) {
+ b.bitsRead += n
+ b.value <<= n & 63
+}
+
+// fillFast() will make sure at least 32 bits are available.
+// There must be at least 4 bytes available.
+func (b *bitReaderBytes) fillFast() {
+ if b.bitsRead < 32 {
+ return
+ }
+
+ // 2 bounds checks.
+ v := b.in[b.off-4 : b.off]
+ v = v[:4]
+ low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
+ b.value |= uint64(low) << (b.bitsRead - 32)
+ b.bitsRead -= 32
+ b.off -= 4
+}
+
+// fillFastStart() assumes the bitReaderBytes is empty and there is at least 8 bytes to read.
+func (b *bitReaderBytes) fillFastStart() {
+ // Do single re-slice to avoid bounds checks.
+ b.value = binary.LittleEndian.Uint64(b.in[b.off-8:])
+ b.bitsRead = 0
+ b.off -= 8
+}
+
+// fill() will make sure at least 32 bits are available.
+func (b *bitReaderBytes) fill() {
+ if b.bitsRead < 32 {
+ return
+ }
+ if b.off > 4 {
+ v := b.in[b.off-4:]
+ v = v[:4]
+ low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
+ b.value |= uint64(low) << (b.bitsRead - 32)
+ b.bitsRead -= 32
+ b.off -= 4
+ return
+ }
+ for b.off > 0 {
+ b.value |= uint64(b.in[b.off-1]) << (b.bitsRead - 8)
+ b.bitsRead -= 8
+ b.off--
+ }
+}
+
+// finished returns true if all bits have been read from the bit stream.
+func (b *bitReaderBytes) finished() bool {
+ return b.off == 0 && b.bitsRead >= 64
+}
+
+// close the bitstream and returns an error if out-of-buffer reads occurred.
+func (b *bitReaderBytes) close() error {
+ // Release reference.
+ b.in = nil
+ if b.bitsRead > 64 {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+
+// bitReaderShifted reads a bitstream in reverse.
+// The last set bit indicates the start of the stream and is used
+// for aligning the input.
+type bitReaderShifted struct {
+ in []byte
+ off uint // next byte to read is at in[off - 1]
+ value uint64
+ bitsRead uint8
+}
+
+// init initializes and resets the bit reader.
+func (b *bitReaderShifted) init(in []byte) error {
+ if len(in) < 1 {
+ return errors.New("corrupt stream: too short")
+ }
+ b.in = in
+ b.off = uint(len(in))
+ // The highest bit of the last byte indicates where to start
+ v := in[len(in)-1]
+ if v == 0 {
+ return errors.New("corrupt stream, did not find end of stream")
+ }
+ b.bitsRead = 64
+ b.value = 0
+ if len(in) >= 8 {
+ b.fillFastStart()
+ } else {
+ b.fill()
+ b.fill()
+ }
+ b.advance(8 - uint8(highBit32(uint32(v))))
+ return nil
+}
+
+// peekBitsFast requires that at least one bit is requested every time.
+// There are no checks if the buffer is filled.
+func (b *bitReaderShifted) peekBitsFast(n uint8) uint16 {
+ return uint16(b.value >> ((64 - n) & 63))
+}
+
+func (b *bitReaderShifted) advance(n uint8) {
+ b.bitsRead += n
+ b.value <<= n & 63
+}
+
+// fillFast() will make sure at least 32 bits are available.
+// There must be at least 4 bytes available.
+func (b *bitReaderShifted) fillFast() {
+ if b.bitsRead < 32 {
+ return
+ }
+
+ // 2 bounds checks.
+ v := b.in[b.off-4 : b.off]
+ v = v[:4]
+ low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
+ b.value |= uint64(low) << ((b.bitsRead - 32) & 63)
+ b.bitsRead -= 32
+ b.off -= 4
+}
+
+// fillFastStart() assumes the bitReaderShifted is empty and there is at least 8 bytes to read.
+func (b *bitReaderShifted) fillFastStart() {
+ // Do single re-slice to avoid bounds checks.
+ b.value = binary.LittleEndian.Uint64(b.in[b.off-8:])
+ b.bitsRead = 0
+ b.off -= 8
+}
+
+// fill() will make sure at least 32 bits are available.
+func (b *bitReaderShifted) fill() {
+ if b.bitsRead < 32 {
+ return
+ }
+ if b.off > 4 {
+ v := b.in[b.off-4:]
+ v = v[:4]
+ low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
+ b.value |= uint64(low) << ((b.bitsRead - 32) & 63)
+ b.bitsRead -= 32
+ b.off -= 4
+ return
+ }
+ for b.off > 0 {
+ b.value |= uint64(b.in[b.off-1]) << ((b.bitsRead - 8) & 63)
+ b.bitsRead -= 8
+ b.off--
+ }
+}
+
+// finished returns true if all bits have been read from the bit stream.
+func (b *bitReaderShifted) finished() bool {
+ return b.off == 0 && b.bitsRead >= 64
+}
+
+// close the bitstream and returns an error if out-of-buffer reads occurred.
+func (b *bitReaderShifted) close() error {
+ // Release reference.
+ b.in = nil
+ if b.bitsRead > 64 {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
diff --git a/vendor/github.com/klauspost/compress/huff0/decompress.go b/vendor/github.com/klauspost/compress/huff0/decompress.go
index fb42a398b..a03b2634a 100644
--- a/vendor/github.com/klauspost/compress/huff0/decompress.go
+++ b/vendor/github.com/klauspost/compress/huff0/decompress.go
@@ -25,6 +25,9 @@ type dEntryDouble struct {
len uint8
}
+// Uses special code for all tables that are < 8 bits.
+const use8BitTables = true
+
// ReadTable will read a table from the input.
// The size of the input may be larger than the table definition.
// Any content remaining after the table definition will be returned.
@@ -83,6 +86,7 @@ func ReadTable(in []byte, s *Scratch) (s2 *Scratch, remain []byte, err error) {
}
v2 := v & 15
rankStats[v2]++
+ // (1 << (v2-1)) is slower since the compiler cannot prove that v2 isn't 0.
weightTotal += (1 << v2) >> 1
}
if weightTotal == 0 {
@@ -142,12 +146,14 @@ func ReadTable(in []byte, s *Scratch) (s2 *Scratch, remain []byte, err error) {
d := dEntrySingle{
entry: uint16(s.actualTableLog+1-w) | (uint16(n) << 8),
}
- single := s.dt.single[rankStats[w] : rankStats[w]+length]
+ rank := &rankStats[w]
+ single := s.dt.single[*rank : *rank+length]
for i := range single {
single[i] = d
}
- rankStats[w] += length
+ *rank += length
}
+
return s, in, nil
}
@@ -208,7 +214,10 @@ func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) {
if len(d.dt.single) == 0 {
return nil, errors.New("no table loaded")
}
- var br bitReader
+ if use8BitTables && d.actualTableLog <= 8 {
+ return d.decompress1X8Bit(dst, src)
+ }
+ var br bitReaderShifted
err := br.init(src)
if err != nil {
return dst, err
@@ -216,17 +225,6 @@ func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) {
maxDecodedSize := cap(dst)
dst = dst[:0]
- decode := func() byte {
- val := br.peekBitsFast(d.actualTableLog) /* note : actualTableLog >= 1 */
- v := d.dt.single[val]
- br.bitsRead += uint8(v.entry)
- return uint8(v.entry >> 8)
- }
- hasDec := func(v dEntrySingle) byte {
- br.bitsRead += uint8(v.entry)
- return uint8(v.entry >> 8)
- }
-
// Avoid bounds check by always having full sized table.
const tlSize = 1 << tableLogMax
const tlMask = tlSize - 1
@@ -238,11 +236,25 @@ func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) {
for br.off >= 8 {
br.fillFast()
- buf[off+0] = hasDec(dt[br.peekBitsFast(d.actualTableLog)&tlMask])
- buf[off+1] = hasDec(dt[br.peekBitsFast(d.actualTableLog)&tlMask])
+ v := dt[br.peekBitsFast(d.actualTableLog)&tlMask]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[br.peekBitsFast(d.actualTableLog)&tlMask]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ // Refill
br.fillFast()
- buf[off+2] = hasDec(dt[br.peekBitsFast(d.actualTableLog)&tlMask])
- buf[off+3] = hasDec(dt[br.peekBitsFast(d.actualTableLog)&tlMask])
+
+ v = dt[br.peekBitsFast(d.actualTableLog)&tlMask]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[br.peekBitsFast(d.actualTableLog)&tlMask]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
off += 4
if off == 0 {
if len(dst)+256 > maxDecodedSize {
@@ -259,13 +271,196 @@ func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) {
}
dst = append(dst, buf[:off]...)
- for !br.finished() {
+ // br < 8, so uint8 is fine
+ bitsLeft := uint8(br.off)*8 + 64 - br.bitsRead
+ for bitsLeft > 0 {
br.fill()
+ if false && br.bitsRead >= 32 {
+ if br.off >= 4 {
+ v := br.in[br.off-4:]
+ v = v[:4]
+ low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
+ br.value = (br.value << 32) | uint64(low)
+ br.bitsRead -= 32
+ br.off -= 4
+ } else {
+ for br.off > 0 {
+ br.value = (br.value << 8) | uint64(br.in[br.off-1])
+ br.bitsRead -= 8
+ br.off--
+ }
+ }
+ }
if len(dst) >= maxDecodedSize {
br.close()
return nil, ErrMaxDecodedSizeExceeded
}
- dst = append(dst, decode())
+ v := d.dt.single[br.peekBitsFast(d.actualTableLog)&tlMask]
+ nBits := uint8(v.entry)
+ br.advance(nBits)
+ bitsLeft -= nBits
+ dst = append(dst, uint8(v.entry>>8))
+ }
+ return dst, br.close()
+}
+
+// decompress1X8Bit will decompress a 1X encoded stream with tablelog <= 8.
+// The cap of the output buffer will be the maximum decompressed size.
+// The length of the supplied input must match the end of a block exactly.
+func (d *Decoder) decompress1X8Bit(dst, src []byte) ([]byte, error) {
+ if d.actualTableLog == 8 {
+ return d.decompress1X8BitExactly(dst, src)
+ }
+ var br bitReaderBytes
+ err := br.init(src)
+ if err != nil {
+ return dst, err
+ }
+ maxDecodedSize := cap(dst)
+ dst = dst[:0]
+
+ // Avoid bounds check by always having full sized table.
+ dt := d.dt.single[:256]
+
+ // Use temp table to avoid bound checks/append penalty.
+ var buf [256]byte
+ var off uint8
+
+ shift := (8 - d.actualTableLog) & 7
+
+ //fmt.Printf("mask: %b, tl:%d\n", mask, d.actualTableLog)
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[br.peekByteFast()>>shift]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[br.peekByteFast()>>shift]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[br.peekByteFast()>>shift]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[br.peekByteFast()>>shift]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+
+ if len(dst)+int(off) > maxDecodedSize {
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:off]...)
+
+ // br < 4, so uint8 is fine
+ bitsLeft := int8(uint8(br.off)*8 + (64 - br.bitsRead))
+ for bitsLeft > 0 {
+ if br.bitsRead >= 64-8 {
+ for br.off > 0 {
+ br.value |= uint64(br.in[br.off-1]) << (br.bitsRead - 8)
+ br.bitsRead -= 8
+ br.off--
+ }
+ }
+ if len(dst) >= maxDecodedSize {
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ v := dt[br.peekByteFast()>>shift]
+ nBits := uint8(v.entry)
+ br.advance(nBits)
+ bitsLeft -= int8(nBits)
+ dst = append(dst, uint8(v.entry>>8))
+ }
+ return dst, br.close()
+}
+
+// decompress1X8Bit will decompress a 1X encoded stream with tablelog <= 8.
+// The cap of the output buffer will be the maximum decompressed size.
+// The length of the supplied input must match the end of a block exactly.
+func (d *Decoder) decompress1X8BitExactly(dst, src []byte) ([]byte, error) {
+ var br bitReaderBytes
+ err := br.init(src)
+ if err != nil {
+ return dst, err
+ }
+ maxDecodedSize := cap(dst)
+ dst = dst[:0]
+
+ // Avoid bounds check by always having full sized table.
+ dt := d.dt.single[:256]
+
+ // Use temp table to avoid bound checks/append penalty.
+ var buf [256]byte
+ var off uint8
+
+ const shift = 0
+
+ //fmt.Printf("mask: %b, tl:%d\n", mask, d.actualTableLog)
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[br.peekByteFast()>>shift]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[br.peekByteFast()>>shift]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[br.peekByteFast()>>shift]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[br.peekByteFast()>>shift]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+
+ if len(dst)+int(off) > maxDecodedSize {
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:off]...)
+
+ // br < 4, so uint8 is fine
+ bitsLeft := int8(uint8(br.off)*8 + (64 - br.bitsRead))
+ for bitsLeft > 0 {
+ if br.bitsRead >= 64-8 {
+ for br.off > 0 {
+ br.value |= uint64(br.in[br.off-1]) << (br.bitsRead - 8)
+ br.bitsRead -= 8
+ br.off--
+ }
+ }
+ if len(dst) >= maxDecodedSize {
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ v := dt[br.peekByteFast()>>shift]
+ nBits := uint8(v.entry)
+ br.advance(nBits)
+ bitsLeft -= int8(nBits)
+ dst = append(dst, uint8(v.entry>>8))
}
return dst, br.close()
}
@@ -274,15 +469,18 @@ func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) {
// The length of the supplied input must match the end of a block exactly.
// The *capacity* of the dst slice must match the destination size of
// the uncompressed data exactly.
-func (s *Decoder) Decompress4X(dst, src []byte) ([]byte, error) {
- if len(s.dt.single) == 0 {
+func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) {
+ if len(d.dt.single) == 0 {
return nil, errors.New("no table loaded")
}
if len(src) < 6+(4*1) {
return nil, errors.New("input too small")
}
+ if use8BitTables && d.actualTableLog <= 8 {
+ return d.decompress4X8bit(dst, src)
+ }
- var br [4]bitReader
+ var br [4]bitReaderShifted
start := 6
for i := 0; i < 3; i++ {
length := int(src[i*2]) | (int(src[i*2+1]) << 8)
@@ -308,14 +506,7 @@ func (s *Decoder) Decompress4X(dst, src []byte) ([]byte, error) {
const tlSize = 1 << tableLogMax
const tlMask = tlSize - 1
- single := s.dt.single[:tlSize]
-
- decode := func(br *bitReader) byte {
- val := br.peekBitsFast(s.actualTableLog) /* note : actualTableLog >= 1 */
- v := single[val&tlMask]
- br.bitsRead += uint8(v.entry)
- return uint8(v.entry >> 8)
- }
+ single := d.dt.single[:tlSize]
// Use temp table to avoid bound checks/append penalty.
var buf [256]byte
@@ -324,69 +515,484 @@ func (s *Decoder) Decompress4X(dst, src []byte) ([]byte, error) {
// Decode 2 values from each decoder/loop.
const bufoff = 256 / 4
-bigloop:
for {
- for i := range br {
- br := &br[i]
- if br.off < 4 {
- break bigloop
- }
- br.fillFast()
+ if br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4 {
+ break
}
{
const stream = 0
- val := br[stream].peekBitsFast(s.actualTableLog)
+ const stream2 = 1
+ br[stream].fillFast()
+ br[stream2].fillFast()
+
+ val := br[stream].peekBitsFast(d.actualTableLog)
v := single[val&tlMask]
- br[stream].bitsRead += uint8(v.entry)
+ br[stream].advance(uint8(v.entry))
+ buf[off+bufoff*stream] = uint8(v.entry >> 8)
- val2 := br[stream].peekBitsFast(s.actualTableLog)
+ val2 := br[stream2].peekBitsFast(d.actualTableLog)
v2 := single[val2&tlMask]
- buf[off+bufoff*stream+1] = uint8(v2.entry >> 8)
- buf[off+bufoff*stream] = uint8(v.entry >> 8)
- br[stream].bitsRead += uint8(v2.entry)
+ br[stream2].advance(uint8(v2.entry))
+ buf[off+bufoff*stream2] = uint8(v2.entry >> 8)
+
+ val = br[stream].peekBitsFast(d.actualTableLog)
+ v = single[val&tlMask]
+ br[stream].advance(uint8(v.entry))
+ buf[off+bufoff*stream+1] = uint8(v.entry >> 8)
+
+ val2 = br[stream2].peekBitsFast(d.actualTableLog)
+ v2 = single[val2&tlMask]
+ br[stream2].advance(uint8(v2.entry))
+ buf[off+bufoff*stream2+1] = uint8(v2.entry >> 8)
}
{
- const stream = 1
- val := br[stream].peekBitsFast(s.actualTableLog)
+ const stream = 2
+ const stream2 = 3
+ br[stream].fillFast()
+ br[stream2].fillFast()
+
+ val := br[stream].peekBitsFast(d.actualTableLog)
v := single[val&tlMask]
- br[stream].bitsRead += uint8(v.entry)
+ br[stream].advance(uint8(v.entry))
+ buf[off+bufoff*stream] = uint8(v.entry >> 8)
- val2 := br[stream].peekBitsFast(s.actualTableLog)
+ val2 := br[stream2].peekBitsFast(d.actualTableLog)
v2 := single[val2&tlMask]
- buf[off+bufoff*stream+1] = uint8(v2.entry >> 8)
- buf[off+bufoff*stream] = uint8(v.entry >> 8)
- br[stream].bitsRead += uint8(v2.entry)
+ br[stream2].advance(uint8(v2.entry))
+ buf[off+bufoff*stream2] = uint8(v2.entry >> 8)
+
+ val = br[stream].peekBitsFast(d.actualTableLog)
+ v = single[val&tlMask]
+ br[stream].advance(uint8(v.entry))
+ buf[off+bufoff*stream+1] = uint8(v.entry >> 8)
+
+ val2 = br[stream2].peekBitsFast(d.actualTableLog)
+ v2 = single[val2&tlMask]
+ br[stream2].advance(uint8(v2.entry))
+ buf[off+bufoff*stream2+1] = uint8(v2.entry >> 8)
+ }
+
+ off += 2
+
+ if off == bufoff {
+ if bufoff > dstEvery {
+ return nil, errors.New("corruption detected: stream overrun 1")
+ }
+ copy(out, buf[:bufoff])
+ copy(out[dstEvery:], buf[bufoff:bufoff*2])
+ copy(out[dstEvery*2:], buf[bufoff*2:bufoff*3])
+ copy(out[dstEvery*3:], buf[bufoff*3:bufoff*4])
+ off = 0
+ out = out[bufoff:]
+ decoded += 256
+ // There must at least be 3 buffers left.
+ if len(out) < dstEvery*3 {
+ return nil, errors.New("corruption detected: stream overrun 2")
+ }
+ }
+ }
+ if off > 0 {
+ ioff := int(off)
+ if len(out) < dstEvery*3+ioff {
+ return nil, errors.New("corruption detected: stream overrun 3")
+ }
+ copy(out, buf[:off])
+ copy(out[dstEvery:dstEvery+ioff], buf[bufoff:bufoff*2])
+ copy(out[dstEvery*2:dstEvery*2+ioff], buf[bufoff*2:bufoff*3])
+ copy(out[dstEvery*3:dstEvery*3+ioff], buf[bufoff*3:bufoff*4])
+ decoded += int(off) * 4
+ out = out[off:]
+ }
+
+ // Decode remaining.
+ for i := range br {
+ offset := dstEvery * i
+ br := &br[i]
+ bitsLeft := br.off*8 + uint(64-br.bitsRead)
+ for bitsLeft > 0 {
+ br.fill()
+ if false && br.bitsRead >= 32 {
+ if br.off >= 4 {
+ v := br.in[br.off-4:]
+ v = v[:4]
+ low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
+ br.value = (br.value << 32) | uint64(low)
+ br.bitsRead -= 32
+ br.off -= 4
+ } else {
+ for br.off > 0 {
+ br.value = (br.value << 8) | uint64(br.in[br.off-1])
+ br.bitsRead -= 8
+ br.off--
+ }
+ }
+ }
+ // end inline...
+ if offset >= len(out) {
+ return nil, errors.New("corruption detected: stream overrun 4")
+ }
+
+ // Read value and increment offset.
+ val := br.peekBitsFast(d.actualTableLog)
+ v := single[val&tlMask].entry
+ nBits := uint8(v)
+ br.advance(nBits)
+ bitsLeft -= uint(nBits)
+ out[offset] = uint8(v >> 8)
+ offset++
+ }
+ decoded += offset - dstEvery*i
+ err = br.close()
+ if err != nil {
+ return nil, err
+ }
+ }
+ if dstSize != decoded {
+ return nil, errors.New("corruption detected: short output block")
+ }
+ return dst, nil
+}
+
+// Decompress4X will decompress a 4X encoded stream.
+// The length of the supplied input must match the end of a block exactly.
+// The *capacity* of the dst slice must match the destination size of
+// the uncompressed data exactly.
+func (d *Decoder) decompress4X8bit(dst, src []byte) ([]byte, error) {
+ if d.actualTableLog == 8 {
+ return d.decompress4X8bitExactly(dst, src)
+ }
+
+ var br [4]bitReaderBytes
+ start := 6
+ for i := 0; i < 3; i++ {
+ length := int(src[i*2]) | (int(src[i*2+1]) << 8)
+ if start+length >= len(src) {
+ return nil, errors.New("truncated input (or invalid offset)")
+ }
+ err := br[i].init(src[start : start+length])
+ if err != nil {
+ return nil, err
+ }
+ start += length
+ }
+ err := br[3].init(src[start:])
+ if err != nil {
+ return nil, err
+ }
+
+ // destination, offset to match first output
+ dstSize := cap(dst)
+ dst = dst[:dstSize]
+ out := dst
+ dstEvery := (dstSize + 3) / 4
+
+ shift := (8 - d.actualTableLog) & 7
+
+ const tlSize = 1 << 8
+ const tlMask = tlSize - 1
+ single := d.dt.single[:tlSize]
+
+ // Use temp table to avoid bound checks/append penalty.
+ var buf [256]byte
+ var off uint8
+ var decoded int
+
+ // Decode 4 values from each decoder/loop.
+ const bufoff = 256 / 4
+ for {
+ if br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4 {
+ break
+ }
+
+ {
+ // Interleave 2 decodes.
+ const stream = 0
+ const stream2 = 1
+ br[stream].fillFast()
+ br[stream2].fillFast()
+
+ v := single[br[stream].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream] = uint8(v >> 8)
+ br[stream].advance(uint8(v))
+
+ v2 := single[br[stream2].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream2] = uint8(v2 >> 8)
+ br[stream2].advance(uint8(v2))
+
+ v = single[br[stream].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream+1] = uint8(v >> 8)
+ br[stream].advance(uint8(v))
+
+ v2 = single[br[stream2].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream2+1] = uint8(v2 >> 8)
+ br[stream2].advance(uint8(v2))
+
+ v = single[br[stream].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream+2] = uint8(v >> 8)
+ br[stream].advance(uint8(v))
+
+ v2 = single[br[stream2].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream2+2] = uint8(v2 >> 8)
+ br[stream2].advance(uint8(v2))
+
+ v = single[br[stream].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream+3] = uint8(v >> 8)
+ br[stream].advance(uint8(v))
+
+ v2 = single[br[stream2].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream2+3] = uint8(v2 >> 8)
+ br[stream2].advance(uint8(v2))
}
{
const stream = 2
- val := br[stream].peekBitsFast(s.actualTableLog)
- v := single[val&tlMask]
- br[stream].bitsRead += uint8(v.entry)
+ const stream2 = 3
+ br[stream].fillFast()
+ br[stream2].fillFast()
- val2 := br[stream].peekBitsFast(s.actualTableLog)
- v2 := single[val2&tlMask]
- buf[off+bufoff*stream+1] = uint8(v2.entry >> 8)
- buf[off+bufoff*stream] = uint8(v.entry >> 8)
- br[stream].bitsRead += uint8(v2.entry)
+ v := single[br[stream].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream] = uint8(v >> 8)
+ br[stream].advance(uint8(v))
+
+ v2 := single[br[stream2].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream2] = uint8(v2 >> 8)
+ br[stream2].advance(uint8(v2))
+
+ v = single[br[stream].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream+1] = uint8(v >> 8)
+ br[stream].advance(uint8(v))
+
+ v2 = single[br[stream2].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream2+1] = uint8(v2 >> 8)
+ br[stream2].advance(uint8(v2))
+
+ v = single[br[stream].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream+2] = uint8(v >> 8)
+ br[stream].advance(uint8(v))
+
+ v2 = single[br[stream2].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream2+2] = uint8(v2 >> 8)
+ br[stream2].advance(uint8(v2))
+
+ v = single[br[stream].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream+3] = uint8(v >> 8)
+ br[stream].advance(uint8(v))
+
+ v2 = single[br[stream2].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream2+3] = uint8(v2 >> 8)
+ br[stream2].advance(uint8(v2))
+ }
+
+ off += 4
+
+ if off == bufoff {
+ if bufoff > dstEvery {
+ return nil, errors.New("corruption detected: stream overrun 1")
+ }
+ copy(out, buf[:bufoff])
+ copy(out[dstEvery:], buf[bufoff:bufoff*2])
+ copy(out[dstEvery*2:], buf[bufoff*2:bufoff*3])
+ copy(out[dstEvery*3:], buf[bufoff*3:bufoff*4])
+ off = 0
+ out = out[bufoff:]
+ decoded += 256
+ // There must at least be 3 buffers left.
+ if len(out) < dstEvery*3 {
+ return nil, errors.New("corruption detected: stream overrun 2")
+ }
+ }
+ }
+ if off > 0 {
+ ioff := int(off)
+ if len(out) < dstEvery*3+ioff {
+ return nil, errors.New("corruption detected: stream overrun 3")
+ }
+ copy(out, buf[:off])
+ copy(out[dstEvery:dstEvery+ioff], buf[bufoff:bufoff*2])
+ copy(out[dstEvery*2:dstEvery*2+ioff], buf[bufoff*2:bufoff*3])
+ copy(out[dstEvery*3:dstEvery*3+ioff], buf[bufoff*3:bufoff*4])
+ decoded += int(off) * 4
+ out = out[off:]
+ }
+
+ // Decode remaining.
+ for i := range br {
+ offset := dstEvery * i
+ br := &br[i]
+ bitsLeft := int(br.off*8) + int(64-br.bitsRead)
+ for bitsLeft > 0 {
+ if br.finished() {
+ return nil, io.ErrUnexpectedEOF
+ }
+ if br.bitsRead >= 56 {
+ if br.off >= 4 {
+ v := br.in[br.off-4:]
+ v = v[:4]
+ low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
+ br.value |= uint64(low) << (br.bitsRead - 32)
+ br.bitsRead -= 32
+ br.off -= 4
+ } else {
+ for br.off > 0 {
+ br.value |= uint64(br.in[br.off-1]) << (br.bitsRead - 8)
+ br.bitsRead -= 8
+ br.off--
+ }
+ }
+ }
+ // end inline...
+ if offset >= len(out) {
+ return nil, errors.New("corruption detected: stream overrun 4")
+ }
+
+ // Read value and increment offset.
+ v := single[br.peekByteFast()>>shift].entry
+ nBits := uint8(v)
+ br.advance(nBits)
+ bitsLeft -= int(nBits)
+ out[offset] = uint8(v >> 8)
+ offset++
+ }
+ decoded += offset - dstEvery*i
+ err = br.close()
+ if err != nil {
+ return nil, err
+ }
+ }
+ if dstSize != decoded {
+ return nil, errors.New("corruption detected: short output block")
+ }
+ return dst, nil
+}
+
+// Decompress4X will decompress a 4X encoded stream.
+// The length of the supplied input must match the end of a block exactly.
+// The *capacity* of the dst slice must match the destination size of
+// the uncompressed data exactly.
+func (d *Decoder) decompress4X8bitExactly(dst, src []byte) ([]byte, error) {
+ var br [4]bitReaderBytes
+ start := 6
+ for i := 0; i < 3; i++ {
+ length := int(src[i*2]) | (int(src[i*2+1]) << 8)
+ if start+length >= len(src) {
+ return nil, errors.New("truncated input (or invalid offset)")
+ }
+ err := br[i].init(src[start : start+length])
+ if err != nil {
+ return nil, err
+ }
+ start += length
+ }
+ err := br[3].init(src[start:])
+ if err != nil {
+ return nil, err
+ }
+
+ // destination, offset to match first output
+ dstSize := cap(dst)
+ dst = dst[:dstSize]
+ out := dst
+ dstEvery := (dstSize + 3) / 4
+
+ const shift = 0
+ const tlSize = 1 << 8
+ const tlMask = tlSize - 1
+ single := d.dt.single[:tlSize]
+
+ // Use temp table to avoid bound checks/append penalty.
+ var buf [256]byte
+ var off uint8
+ var decoded int
+
+ // Decode 4 values from each decoder/loop.
+ const bufoff = 256 / 4
+ for {
+ if br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4 {
+ break
}
{
- const stream = 3
- val := br[stream].peekBitsFast(s.actualTableLog)
- v := single[val&tlMask]
- br[stream].bitsRead += uint8(v.entry)
+ // Interleave 2 decodes.
+ const stream = 0
+ const stream2 = 1
+ br[stream].fillFast()
+ br[stream2].fillFast()
- val2 := br[stream].peekBitsFast(s.actualTableLog)
- v2 := single[val2&tlMask]
- buf[off+bufoff*stream+1] = uint8(v2.entry >> 8)
- buf[off+bufoff*stream] = uint8(v.entry >> 8)
- br[stream].bitsRead += uint8(v2.entry)
+ v := single[br[stream].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream] = uint8(v >> 8)
+ br[stream].advance(uint8(v))
+
+ v2 := single[br[stream2].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream2] = uint8(v2 >> 8)
+ br[stream2].advance(uint8(v2))
+
+ v = single[br[stream].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream+1] = uint8(v >> 8)
+ br[stream].advance(uint8(v))
+
+ v2 = single[br[stream2].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream2+1] = uint8(v2 >> 8)
+ br[stream2].advance(uint8(v2))
+
+ v = single[br[stream].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream+2] = uint8(v >> 8)
+ br[stream].advance(uint8(v))
+
+ v2 = single[br[stream2].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream2+2] = uint8(v2 >> 8)
+ br[stream2].advance(uint8(v2))
+
+ v = single[br[stream].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream+3] = uint8(v >> 8)
+ br[stream].advance(uint8(v))
+
+ v2 = single[br[stream2].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream2+3] = uint8(v2 >> 8)
+ br[stream2].advance(uint8(v2))
}
- off += 2
+ {
+ const stream = 2
+ const stream2 = 3
+ br[stream].fillFast()
+ br[stream2].fillFast()
+
+ v := single[br[stream].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream] = uint8(v >> 8)
+ br[stream].advance(uint8(v))
+
+ v2 := single[br[stream2].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream2] = uint8(v2 >> 8)
+ br[stream2].advance(uint8(v2))
+
+ v = single[br[stream].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream+1] = uint8(v >> 8)
+ br[stream].advance(uint8(v))
+
+ v2 = single[br[stream2].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream2+1] = uint8(v2 >> 8)
+ br[stream2].advance(uint8(v2))
+
+ v = single[br[stream].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream+2] = uint8(v >> 8)
+ br[stream].advance(uint8(v))
+
+ v2 = single[br[stream2].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream2+2] = uint8(v2 >> 8)
+ br[stream2].advance(uint8(v2))
+
+ v = single[br[stream].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream+3] = uint8(v >> 8)
+ br[stream].advance(uint8(v))
+
+ v2 = single[br[stream2].peekByteFast()>>shift].entry
+ buf[off+bufoff*stream2+3] = uint8(v2 >> 8)
+ br[stream2].advance(uint8(v2))
+ }
+
+ off += 4
if off == bufoff {
if bufoff > dstEvery {
@@ -422,12 +1028,38 @@ bigloop:
for i := range br {
offset := dstEvery * i
br := &br[i]
- for !br.finished() {
- br.fill()
+ bitsLeft := int(br.off*8) + int(64-br.bitsRead)
+ for bitsLeft > 0 {
+ if br.finished() {
+ return nil, io.ErrUnexpectedEOF
+ }
+ if br.bitsRead >= 56 {
+ if br.off >= 4 {
+ v := br.in[br.off-4:]
+ v = v[:4]
+ low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
+ br.value |= uint64(low) << (br.bitsRead - 32)
+ br.bitsRead -= 32
+ br.off -= 4
+ } else {
+ for br.off > 0 {
+ br.value |= uint64(br.in[br.off-1]) << (br.bitsRead - 8)
+ br.bitsRead -= 8
+ br.off--
+ }
+ }
+ }
+ // end inline...
if offset >= len(out) {
return nil, errors.New("corruption detected: stream overrun 4")
}
- out[offset] = decode(br)
+
+ // Read value and increment offset.
+ v := single[br.peekByteFast()>>shift].entry
+ nBits := uint8(v)
+ br.advance(nBits)
+ bitsLeft -= int(nBits)
+ out[offset] = uint8(v >> 8)
offset++
}
decoded += offset - dstEvery*i
diff --git a/vendor/github.com/klauspost/compress/zstd/bitreader.go b/vendor/github.com/klauspost/compress/zstd/bitreader.go
index 15d79d439..854458537 100644
--- a/vendor/github.com/klauspost/compress/zstd/bitreader.go
+++ b/vendor/github.com/klauspost/compress/zstd/bitreader.go
@@ -5,6 +5,7 @@
package zstd
import (
+ "encoding/binary"
"errors"
"io"
"math/bits"
@@ -34,8 +35,12 @@ func (b *bitReader) init(in []byte) error {
}
b.bitsRead = 64
b.value = 0
- b.fill()
- b.fill()
+ if len(in) >= 8 {
+ b.fillFastStart()
+ } else {
+ b.fill()
+ b.fill()
+ }
b.bitsRead += 8 - uint8(highBits(uint32(v)))
return nil
}
@@ -63,21 +68,31 @@ func (b *bitReader) fillFast() {
if b.bitsRead < 32 {
return
}
- // Do single re-slice to avoid bounds checks.
- v := b.in[b.off-4 : b.off]
+ // 2 bounds checks.
+ v := b.in[b.off-4:]
+ v = v[:4]
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
b.value = (b.value << 32) | uint64(low)
b.bitsRead -= 32
b.off -= 4
}
+// fillFastStart() assumes the bitreader is empty and there is at least 8 bytes to read.
+func (b *bitReader) fillFastStart() {
+ // Do single re-slice to avoid bounds checks.
+ b.value = binary.LittleEndian.Uint64(b.in[b.off-8:])
+ b.bitsRead = 0
+ b.off -= 8
+}
+
// fill() will make sure at least 32 bits are available.
func (b *bitReader) fill() {
if b.bitsRead < 32 {
return
}
if b.off >= 4 {
- v := b.in[b.off-4 : b.off]
+ v := b.in[b.off-4:]
+ v = v[:4]
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
b.value = (b.value << 32) | uint64(low)
b.bitsRead -= 32
diff --git a/vendor/github.com/klauspost/compress/zstd/blockdec.go b/vendor/github.com/klauspost/compress/zstd/blockdec.go
index 4a14242c7..c8ec6e331 100644
--- a/vendor/github.com/klauspost/compress/zstd/blockdec.go
+++ b/vendor/github.com/klauspost/compress/zstd/blockdec.go
@@ -83,6 +83,10 @@ type blockDec struct {
err error
decWG sync.WaitGroup
+ // Frame to use for singlethreaded decoding.
+ // Should not be used by the decoder itself since parent may be another frame.
+ localFrame *frameDec
+
// Block is RLE, this is the size.
RLESize uint32
tmp [4]byte
diff --git a/vendor/github.com/klauspost/compress/zstd/bytereader.go b/vendor/github.com/klauspost/compress/zstd/bytereader.go
index f708df1c4..2c4fca17f 100644
--- a/vendor/github.com/klauspost/compress/zstd/bytereader.go
+++ b/vendor/github.com/klauspost/compress/zstd/bytereader.go
@@ -4,8 +4,6 @@
package zstd
-import "encoding/binary"
-
// byteReader provides a byte reader that reads
// little endian values from a byte stream.
// The input stream is manually advanced.
@@ -33,7 +31,8 @@ func (b *byteReader) overread() bool {
// Int32 returns a little endian int32 starting at current offset.
func (b byteReader) Int32() int32 {
- b2 := b.b[b.off : b.off+4 : b.off+4]
+ b2 := b.b[b.off:]
+ b2 = b2[:4]
v3 := int32(b2[3])
v2 := int32(b2[2])
v1 := int32(b2[1])
@@ -57,7 +56,25 @@ func (b byteReader) Uint32() uint32 {
}
return v
}
- return binary.LittleEndian.Uint32(b.b[b.off : b.off+4])
+ b2 := b.b[b.off:]
+ b2 = b2[:4]
+ v3 := uint32(b2[3])
+ v2 := uint32(b2[2])
+ v1 := uint32(b2[1])
+ v0 := uint32(b2[0])
+ return v0 | (v1 << 8) | (v2 << 16) | (v3 << 24)
+}
+
+// Uint32NC returns a little endian uint32 starting at current offset.
+// The caller must be sure if there are at least 4 bytes left.
+func (b byteReader) Uint32NC() uint32 {
+ b2 := b.b[b.off:]
+ b2 = b2[:4]
+ v3 := uint32(b2[3])
+ v2 := uint32(b2[2])
+ v1 := uint32(b2[1])
+ v0 := uint32(b2[0])
+ return v0 | (v1 << 8) | (v2 << 16) | (v3 << 24)
}
// unread returns the unread portion of the input.
diff --git a/vendor/github.com/klauspost/compress/zstd/decoder.go b/vendor/github.com/klauspost/compress/zstd/decoder.go
index 8e34479ff..75bf05bc9 100644
--- a/vendor/github.com/klauspost/compress/zstd/decoder.go
+++ b/vendor/github.com/klauspost/compress/zstd/decoder.go
@@ -23,9 +23,6 @@ type Decoder struct {
// Unreferenced decoders, ready for use.
decoders chan *blockDec
- // Unreferenced decoders, ready for use.
- frames chan *frameDec
-
// Streams ready to be decoded.
stream chan decodeStream
@@ -90,10 +87,10 @@ func NewReader(r io.Reader, opts ...DOption) (*Decoder, error) {
// Create decoders
d.decoders = make(chan *blockDec, d.o.concurrent)
- d.frames = make(chan *frameDec, d.o.concurrent)
for i := 0; i < d.o.concurrent; i++ {
- d.frames <- newFrameDec(d.o)
- d.decoders <- newBlockDec(d.o.lowMem)
+ dec := newBlockDec(d.o.lowMem)
+ dec.localFrame = newFrameDec(d.o)
+ d.decoders <- dec
}
if r == nil {
@@ -283,15 +280,15 @@ func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) {
}
// Grab a block decoder and frame decoder.
- block, frame := <-d.decoders, <-d.frames
+ block := <-d.decoders
+ frame := block.localFrame
defer func() {
if debug {
printf("re-adding decoder: %p", block)
}
- d.decoders <- block
frame.rawInput = nil
frame.bBuf = nil
- d.frames <- frame
+ d.decoders <- block
}()
frame.bBuf = input
diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder.go b/vendor/github.com/klauspost/compress/zstd/fse_decoder.go
index 957cfeb79..e6d3d49b3 100644
--- a/vendor/github.com/klauspost/compress/zstd/fse_decoder.go
+++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder.go
@@ -55,7 +55,7 @@ func (s *fseDecoder) readNCount(b *byteReader, maxSymbol uint16) error {
if b.remain() < 4 {
return errors.New("input too small")
}
- bitStream := b.Uint32()
+ bitStream := b.Uint32NC()
nbBits := uint((bitStream & 0xF) + minTablelog) // extract tableLog
if nbBits > tablelogAbsoluteMax {
println("Invalid tablelog:", nbBits)
@@ -79,7 +79,8 @@ func (s *fseDecoder) readNCount(b *byteReader, maxSymbol uint16) error {
n0 += 24
if r := b.remain(); r > 5 {
b.advance(2)
- bitStream = b.Uint32() >> bitCount
+ // The check above should make sure we can read 32 bits
+ bitStream = b.Uint32NC() >> bitCount
} else {
// end of bit stream
bitStream >>= 16
@@ -104,10 +105,11 @@ func (s *fseDecoder) readNCount(b *byteReader, maxSymbol uint16) error {
charnum++
}
- if r := b.remain(); r >= 7 || r+int(bitCount>>3) >= 4 {
+ if r := b.remain(); r >= 7 || r-int(bitCount>>3) >= 4 {
b.advance(bitCount >> 3)
bitCount &= 7
- bitStream = b.Uint32() >> bitCount
+ // The check above should make sure we can read 32 bits
+ bitStream = b.Uint32NC() >> bitCount
} else {
bitStream >>= 2
}
@@ -148,17 +150,16 @@ func (s *fseDecoder) readNCount(b *byteReader, maxSymbol uint16) error {
threshold >>= 1
}
- //println("b.off:", b.off, "len:", len(b.b), "bc:", bitCount, "remain:", b.remain())
- if r := b.remain(); r >= 7 || r+int(bitCount>>3) >= 4 {
+ if r := b.remain(); r >= 7 || r-int(bitCount>>3) >= 4 {
b.advance(bitCount >> 3)
bitCount &= 7
+ // The check above should make sure we can read 32 bits
+ bitStream = b.Uint32NC() >> (bitCount & 31)
} else {
bitCount -= (uint)(8 * (len(b.b) - 4 - b.off))
b.off = len(b.b) - 4
- //println("b.off:", b.off, "len:", len(b.b), "bc:", bitCount, "iend", iend)
+ bitStream = b.Uint32() >> (bitCount & 31)
}
- bitStream = b.Uint32() >> (bitCount & 31)
- //printf("bitstream is now: 0b%b", bitStream)
}
s.symbolLen = charnum
if s.symbolLen <= 1 {
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 59cf7a2ad..9f307b650 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -84,7 +84,7 @@ github.com/containers/buildah/pkg/secrets
github.com/containers/buildah/pkg/supplemented
github.com/containers/buildah/pkg/umask
github.com/containers/buildah/util
-# github.com/containers/common v0.13.1
+# github.com/containers/common v0.14.0
github.com/containers/common/pkg/apparmor
github.com/containers/common/pkg/auth
github.com/containers/common/pkg/capabilities
@@ -93,7 +93,7 @@ github.com/containers/common/pkg/config
github.com/containers/common/pkg/sysinfo
# github.com/containers/conmon v2.0.18+incompatible
github.com/containers/conmon/runner/config
-# github.com/containers/image/v5 v5.4.5-0.20200529084758-46b2ee6aebb0
+# github.com/containers/image/v5 v5.5.1
github.com/containers/image/v5/copy
github.com/containers/image/v5/directory
github.com/containers/image/v5/directory/explicitfilepath
@@ -324,7 +324,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.7
+# github.com/klauspost/compress v1.10.8
github.com/klauspost/compress/flate
github.com/klauspost/compress/fse
github.com/klauspost/compress/huff0