diff options
29 files changed, 844 insertions, 452 deletions
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index ab3a984f0..599b430ea 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -84,7 +84,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { cgroupsFlagName := "cgroups" createFlags.StringVar( &cf.CGroupsMode, - cgroupsFlagName, containerConfig.Cgroups(), + cgroupsFlagName, cgroupConfig(), `control container cgroup configuration ("enabled"|"disabled"|"no-conmon"|"split")`, ) _ = cmd.RegisterFlagCompletionFunc(cgroupsFlagName, AutocompleteCgroupMode) @@ -180,7 +180,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { deviceFlagName := "device" createFlags.StringSliceVar( &cf.Devices, - deviceFlagName, containerConfig.Devices(), + deviceFlagName, devices(), fmt.Sprintf("Add a host device to the container"), ) _ = cmd.RegisterFlagCompletionFunc(deviceFlagName, completion.AutocompleteDefault) @@ -238,7 +238,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { envFlagName := "env" createFlags.StringArrayP( - envFlagName, "e", containerConfig.Env(), + envFlagName, "e", env(), "Set environment variables in container", ) _ = cmd.RegisterFlagCompletionFunc(envFlagName, completion.AutocompleteNone) @@ -357,7 +357,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { initPathFlagName := "init-path" createFlags.StringVar( &cf.InitPath, - initPathFlagName, containerConfig.InitPath(), + initPathFlagName, initPath(), // Do not use the Value field for setting the default value to determine user input (i.e., non-empty string) fmt.Sprintf("Path to the container-init binary"), ) @@ -508,7 +508,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { pidsLimitFlagName := "pids-limit" createFlags.Int64( - pidsLimitFlagName, containerConfig.PidsLimit(), + pidsLimitFlagName, pidsLimit(), "Tune container pids limit (set 0 for unlimited, -1 for server defaults)", ) _ = cmd.RegisterFlagCompletionFunc(pidsLimitFlagName, completion.AutocompleteNone) @@ -543,7 +543,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { pullFlagName := "pull" createFlags.StringVar( &cf.Pull, - pullFlagName, containerConfig.Engine.PullPolicy, + pullFlagName, policy(), `Pull image before creating ("always"|"missing"|"never")`, ) _ = cmd.RegisterFlagCompletionFunc(pullFlagName, AutocompletePullOption) @@ -606,7 +606,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { shmSizeFlagName := "shm-size" createFlags.String( - shmSizeFlagName, containerConfig.ShmSize(), + shmSizeFlagName, shmSize(), "Size of /dev/shm "+sizeWithUnitFormat, ) _ = cmd.RegisterFlagCompletionFunc(shmSizeFlagName, completion.AutocompleteNone) @@ -715,7 +715,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { ulimitFlagName := "ulimit" createFlags.StringSliceVar( &cf.Ulimit, - ulimitFlagName, containerConfig.Ulimits(), + ulimitFlagName, ulimits(), "Ulimit options", ) _ = cmd.RegisterFlagCompletionFunc(ulimitFlagName, completion.AutocompleteNone) @@ -753,7 +753,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { volumeFlagName := "volume" createFlags.StringArrayVarP( &cf.Volume, - volumeFlagName, "v", containerConfig.Volumes(), + volumeFlagName, "v", volumes(), "Bind mount a volume into the container", ) _ = cmd.RegisterFlagCompletionFunc(volumeFlagName, AutocompleteVolumeFlag) diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go index 4b52663c3..f34666fff 100644 --- a/cmd/podman/common/create_opts.go +++ b/cmd/podman/common/create_opts.go @@ -6,6 +6,7 @@ import ( "strconv" "strings" + "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/api/handlers" "github.com/containers/podman/v2/pkg/cgroups" "github.com/containers/podman/v2/pkg/domain/entities" @@ -440,3 +441,66 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup cmd = append(cmd, cc.Config.Cmd...) return &cliOpts, cmd, nil } + +func ulimits() []string { + if !registry.IsRemote() { + return containerConfig.Ulimits() + } + return nil +} + +func cgroupConfig() string { + if !registry.IsRemote() { + return containerConfig.Cgroups() + } + return "" +} + +func devices() []string { + if !registry.IsRemote() { + return containerConfig.Devices() + } + return nil +} + +func env() []string { + if !registry.IsRemote() { + return containerConfig.Env() + } + return nil +} + +func initPath() string { + if !registry.IsRemote() { + return containerConfig.InitPath() + } + return "" +} + +func pidsLimit() int64 { + if !registry.IsRemote() { + return containerConfig.PidsLimit() + } + return -1 +} + +func policy() string { + if !registry.IsRemote() { + return containerConfig.Engine.PullPolicy + } + return "" +} + +func shmSize() string { + if !registry.IsRemote() { + return containerConfig.ShmSize() + } + return "" +} + +func volumes() []string { + if !registry.IsRemote() { + return containerConfig.Volumes() + } + return nil +} diff --git a/cmd/podman/common/volumes.go b/cmd/podman/common/volumes.go index b3c160ddf..0468f15e0 100644 --- a/cmd/podman/common/volumes.go +++ b/cmd/podman/common/volumes.go @@ -10,7 +10,6 @@ import ( "github.com/containers/podman/v2/pkg/util" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" - "github.com/sirupsen/logrus" ) const ( @@ -45,7 +44,7 @@ func parseVolumes(volumeFlag, mountFlag, tmpfsFlag []string, addReadOnlyTmpfs bo } // Next --volumes flag. - volumeMounts, volumeVolumes, overlayVolumes, err := getVolumeMounts(volumeFlag) + volumeMounts, volumeVolumes, overlayVolumes, err := specgen.GenVolumeMounts(volumeFlag) if err != nil { return nil, nil, nil, nil, err } @@ -594,105 +593,6 @@ func getImageVolume(args []string) (*specgen.ImageVolume, error) { return newVolume, nil } -func getVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*specgen.NamedVolume, map[string]*specgen.OverlayVolume, error) { - mounts := make(map[string]spec.Mount) - volumes := make(map[string]*specgen.NamedVolume) - overlayVolumes := make(map[string]*specgen.OverlayVolume) - - volumeFormatErr := errors.Errorf("incorrect volume format, should be [host-dir:]ctr-dir[:option]") - - for _, vol := range volumeFlag { - var ( - options []string - src string - dest string - err error - ) - - splitVol := strings.Split(vol, ":") - if len(splitVol) > 3 { - return nil, nil, nil, errors.Wrapf(volumeFormatErr, vol) - } - - src = splitVol[0] - if len(splitVol) == 1 { - // This is an anonymous named volume. Only thing given - // is destination. - // Name/source will be blank, and populated by libpod. - src = "" - dest = splitVol[0] - } else if len(splitVol) > 1 { - dest = splitVol[1] - } - if len(splitVol) > 2 { - if options, err = parse.ValidateVolumeOpts(strings.Split(splitVol[2], ",")); err != nil { - return nil, nil, nil, err - } - } - - // Do not check source dir for anonymous volumes - if len(splitVol) > 1 { - if err := parse.ValidateVolumeHostDir(src); err != nil { - return nil, nil, nil, err - } - } - if err := parse.ValidateVolumeCtrDir(dest); err != nil { - return nil, nil, nil, err - } - - cleanDest := filepath.Clean(dest) - - if strings.HasPrefix(src, "/") || strings.HasPrefix(src, ".") { - // This is not a named volume - overlayFlag := false - for _, o := range options { - if o == "O" { - overlayFlag = true - if len(options) > 1 { - return nil, nil, nil, errors.New("can't use 'O' with other options") - } - } - } - if overlayFlag { - // This is a overlay volume - newOverlayVol := new(specgen.OverlayVolume) - newOverlayVol.Destination = cleanDest - newOverlayVol.Source = src - if _, ok := overlayVolumes[newOverlayVol.Destination]; ok { - return nil, nil, nil, errors.Wrapf(errDuplicateDest, newOverlayVol.Destination) - } - overlayVolumes[newOverlayVol.Destination] = newOverlayVol - } else { - newMount := spec.Mount{ - Destination: cleanDest, - Type: string(TypeBind), - Source: src, - Options: options, - } - if _, ok := mounts[newMount.Destination]; ok { - return nil, nil, nil, errors.Wrapf(errDuplicateDest, newMount.Destination) - } - mounts[newMount.Destination] = newMount - } - } else { - // This is a named volume - newNamedVol := new(specgen.NamedVolume) - newNamedVol.Name = src - newNamedVol.Dest = cleanDest - newNamedVol.Options = options - - if _, ok := volumes[newNamedVol.Dest]; ok { - return nil, nil, nil, errors.Wrapf(errDuplicateDest, newNamedVol.Dest) - } - volumes[newNamedVol.Dest] = newNamedVol - } - - logrus.Debugf("User mount %s:%s options %v", src, dest, options) - } - - return mounts, volumes, overlayVolumes, nil -} - // GetTmpfsMounts creates spec.Mount structs for user-requested tmpfs mounts func getTmpfsMounts(tmpfsFlag []string) (map[string]spec.Mount, error) { m := make(map[string]spec.Mount) diff --git a/cmd/podman/networks/rm.go b/cmd/podman/networks/rm.go index 34e756a3a..1504d9385 100644 --- a/cmd/podman/networks/rm.go +++ b/cmd/podman/networks/rm.go @@ -18,6 +18,7 @@ var ( networkrmDescription = `Remove networks` networkrmCommand = &cobra.Command{ Use: "rm [options] NETWORK [NETWORK...]", + Aliases: []string{"remove"}, Short: "network rm", Long: networkrmDescription, RunE: networkRm, diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md index 749af8a66..8251ba3b6 100644 --- a/docs/source/markdown/podman-create.1.md +++ b/docs/source/markdown/podman-create.1.md @@ -18,6 +18,10 @@ any point. The initial status of the container created with **podman create** is 'created'. +Default settings for flags are defined in `containers.conf`. Most settings for +remote connections use the server's containers.conf, except when documented in +man pages. + ## OPTIONS #### **--add-host**=*host* @@ -817,6 +821,7 @@ Signal to stop a container. Default is SIGTERM. #### **--stop-timeout**=*seconds* Timeout (in seconds) to stop a container. Default is 10. +Remote connections use local containers.conf for defaults #### **--subgidname**=*name* @@ -893,10 +898,12 @@ standard input. #### **--tz**=*timezone* Set timezone in container. This flag takes area-based timezones, GMT time, as well as `local`, which sets the timezone in the container to match the host machine. See `/usr/share/zoneinfo/` for valid timezones. +Remote connections use local containers.conf for defaults #### **--umask**=*umask* Set the umask inside the container. Defaults to `0022`. +Remote connections use local containers.conf for defaults #### **--uidmap**=*container_uid:host_uid:amount* diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index 5b2cdd6a5..bc3d5a8bb 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -33,6 +33,10 @@ is located at _/run/.containerenv_. When running from a user defined network namespace, the _/etc/netns/NSNAME/resolv.conf_ will be used if it exists, otherwise _/etc/resolv.conf_ will be used. +Default settings are defined in `containers.conf`. Most settings for remote +connections use the servers containers.conf, except when documented in man +pages. + ## OPTIONS #### **--add-host**=_host_:_ip_ @@ -857,6 +861,7 @@ Signal to stop a container. Default is **SIGTERM**. #### **--stop-timeout**=*seconds* Timeout to stop a container. Default is **10**. +Remote connections use local containers.conf for defaults #### **--subgidname**=*name* @@ -952,10 +957,12 @@ standard input. #### **--tz**=*timezone* Set timezone in container. This flag takes area-based timezones, GMT time, as well as `local`, which sets the timezone in the container to match the host machine. See `/usr/share/zoneinfo/` for valid timezones. +Remote connections use local containers.conf for defaults #### **--umask**=*umask* Set the umask inside the container. Defaults to `0022`. +Remote connections use local containers.conf for defaults #### **--uidmap**=*container_uid*:*host_uid*:*amount* diff --git a/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md index 1954ca2aa..68a17d26b 100644 --- a/docs/source/markdown/podman.1.md +++ b/docs/source/markdown/podman.1.md @@ -17,6 +17,10 @@ Podman uses Buildah(1) internally to create container images. Both tools share i (not container) storage, hence each can use or manipulate images (but not containers) created by the other. +Default settings for flags are defined in `containers.conf`. Most settings for +Remote connections use the server's containers.conf, except when documented in +man pages. + **podman [GLOBAL OPTIONS]** ## GLOBAL OPTIONS @@ -33,6 +37,7 @@ Path of the configuration directory for CNI networks. (Default: `/etc/cni/net.d #### **--connection**, **-c** Connection to use for remote podman (Default connection is configured in `containers.conf`) +Remote connections use local containers.conf for default. #### **--conmon** Path of the conmon binary (Default path is configured in `containers.conf`) @@ -71,6 +76,7 @@ Identity value resolution precedence: - command line value - environment variable `CONTAINER_SSHKEY`, if `CONTAINER_HOST` is found - `containers.conf` +Remote connections use local containers.conf for default. #### **--log-level**=*level* @@ -86,6 +92,7 @@ Path to the command binary to use for setting up a network. It is currently onl #### **--remote**, **-r** Access Podman service will be remote +Remote connections use local containers.conf for default. #### **--url**=*value* URL to access Podman service (default from `containers.conf`, rootless `unix://run/user/$UID/podman/podman.sock` or as root `unix://run/podman/podman.sock`). @@ -104,6 +111,7 @@ URL value resolution precedence: - environment variable `CONTAINER_HOST` - `containers.conf` - `unix://run/podman/podman.sock` +Remote connections use local containers.conf for default. #### **--root**=*value* @@ -13,9 +13,9 @@ require ( github.com/containers/buildah v1.18.0 github.com/containers/common v0.27.0 github.com/containers/conmon v2.0.20+incompatible - github.com/containers/image/v5 v5.8.0 + github.com/containers/image/v5 v5.8.1 github.com/containers/psgo v1.5.1 - github.com/containers/storage v1.24.0 + github.com/containers/storage v1.24.1 github.com/coreos/go-systemd/v22 v22.1.0 github.com/cri-o/ocicni v0.2.1-0.20201102180012-75c612fda1a2 github.com/cyphar/filepath-securejoin v0.2.2 @@ -103,6 +103,8 @@ github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOB github.com/containers/image/v5 v5.7.0/go.mod h1:8aOy+YaItukxghRORkvhq5ibWttHErzDLy6egrKfKos= github.com/containers/image/v5 v5.8.0 h1:B3FGHi0bdGXgg698kBIGOlHCXN5n+scJr6/5354GOPU= github.com/containers/image/v5 v5.8.0/go.mod h1:jKxdRtyIDumVa56hdsZvV+gwx4zB50hRou6pIuCWLkg= +github.com/containers/image/v5 v5.8.1 h1:aHW8a/Kd0dTJ7PTL/fc6y12sJqHxWgqilu+XyHfjD8Q= +github.com/containers/image/v5 v5.8.1/go.mod h1:blOEFd/iFdeyh891ByhCVUc+xAcaI3gBegXECwz9UbQ= 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.3 h1:vYgl+RZ9Q3DPMuTfxmN+qp0X2Bj52uuY2vnt6GzVe1c= @@ -115,6 +117,8 @@ github.com/containers/storage v1.23.9 h1:qbgnTp76pLSyW3vYwY5GH4vk5cHYVXFJ+CsUEBp github.com/containers/storage v1.23.9/go.mod h1:3b2ktpB6pw53SEeIoFfO0sQfP9+IoJJKPq5iJk74gxE= github.com/containers/storage v1.24.0 h1:Fo2LkF7tkMLmo38sTZ/G8wHjcn8JfUFPfyTxM4WwMfk= github.com/containers/storage v1.24.0/go.mod h1:A4d3BzuZK9b3oLVEsiSRhZLPIx3z7utgiPyXLK/YMhY= +github.com/containers/storage v1.24.1 h1:1+f8fy6ly35c8SLet5jzZ8t0WJJs5+xSpfMAYw0R3kc= +github.com/containers/storage v1.24.1/go.mod h1:0xJL06Dmd+ZYXIUdnBUPN0JnhHGgwMkLvnnAonJfWJU= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-iptables v0.4.5 h1:DpHb9vJrZQEFMcVLFKAAGMUVX0XoRC0ptCthinRYm38= @@ -322,6 +326,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/klauspost/compress v1.11.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.2 h1:MiK62aErc3gIiVEtyzKfeOHgW7atJb5g/KNX5m3c2nQ= github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.3 h1:dB4Bn0tN3wdCzQxnS8r06kV74qN/TAfaIS0bVE8h3jc= +github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= diff --git a/libpod/container.go b/libpod/container.go index 4b9e6a5ba..31c958959 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -17,6 +17,7 @@ import ( "github.com/cri-o/ocicni/pkg/ocicni" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) // CgroupfsDefaultCgroupParent is the cgroup parent for CGroupFS in libpod @@ -920,19 +921,39 @@ func (c *Container) CGroupPath() (string, error) { return "", errors.Wrapf(define.ErrNoCgroups, "this container is not creating cgroups") } - // Read /proc/[PID]/cgroup and look at the first line. cgroups(7) - // nails it down to three fields with the 3rd pointing to the cgroup's - // path which works both on v1 and v2. + // Read /proc/[PID]/cgroup and find the *longest* cgroup entry. That's + // needed to account for hacks in cgroups v1, where each line in the + // file could potentially point to a cgroup. The longest one, however, + // is the libpod-specific one we're looking for. + // + // See #8397 on the need for the longest-path look up. procPath := fmt.Sprintf("/proc/%d/cgroup", c.state.PID) lines, err := ioutil.ReadFile(procPath) if err != nil { return "", err } - fields := bytes.Split(bytes.Split(lines, []byte("\n"))[0], []byte(":")) - if len(fields) != 3 { - return "", errors.Errorf("expected 3 fields but got %d: %s", len(fields), procPath) + + var cgroupPath string + for _, line := range bytes.Split(lines, []byte("\n")) { + // cgroups(7) nails it down to three fields with the 3rd + // pointing to the cgroup's path which works both on v1 and v2. + fields := bytes.Split(line, []byte(":")) + if len(fields) != 3 { + logrus.Debugf("Error parsing cgroup: expected 3 fields but got %d: %s", len(fields), procPath) + continue + } + path := string(fields[2]) + if len(path) > len(cgroupPath) { + cgroupPath = path + } + } - return string(fields[2]), nil + + if len(cgroupPath) == 0 { + return "", errors.Errorf("could not find any cgroup in %q", procPath) + } + + return cgroupPath, nil } // RootFsSize returns the root FS size of the container diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index c049e64cf..45a374216 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -111,7 +111,7 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener return nil, errors.Wrap(err, "invalid config provided") } - finalMounts, finalVolumes, err := finalizeMounts(ctx, s, rt, rtc, newImage) + finalMounts, finalVolumes, finalOverlays, err := finalizeMounts(ctx, s, rt, rtc, newImage) if err != nil { return nil, err } @@ -121,7 +121,7 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener return nil, err } - opts, err := createContainerOptions(ctx, rt, s, pod, finalVolumes, newImage, command) + opts, err := createContainerOptions(ctx, rt, s, pod, finalVolumes, finalOverlays, newImage, command) if err != nil { return nil, err } @@ -144,7 +144,7 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener return rt.NewContainer(ctx, runtimeSpec, options...) } -func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator, pod *libpod.Pod, volumes []*specgen.NamedVolume, img *image.Image, command []string) ([]libpod.CtrCreateOption, error) { +func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator, pod *libpod.Pod, volumes []*specgen.NamedVolume, overlays []*specgen.OverlayVolume, img *image.Image, command []string) ([]libpod.CtrCreateOption, error) { var options []libpod.CtrCreateOption var err error @@ -224,7 +224,7 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen. for _, volume := range volumes { destinations = append(destinations, volume.Dest) } - for _, overlayVolume := range s.OverlayVolumes { + for _, overlayVolume := range overlays { destinations = append(destinations, overlayVolume.Destination) } for _, imageVolume := range s.ImageVolumes { @@ -244,9 +244,9 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen. options = append(options, libpod.WithNamedVolumes(vols)) } - if len(s.OverlayVolumes) != 0 { + if len(overlays) != 0 { var vols []*libpod.ContainerOverlayVolume - for _, v := range s.OverlayVolumes { + for _, v := range overlays { vols = append(vols, &libpod.ContainerOverlayVolume{ Dest: v.Destination, Source: v.Source, diff --git a/pkg/specgen/generate/storage.go b/pkg/specgen/generate/storage.go index b225f79ee..331a5c5bf 100644 --- a/pkg/specgen/generate/storage.go +++ b/pkg/specgen/generate/storage.go @@ -33,17 +33,17 @@ var ( ) // Produce final mounts and named volumes for a container -func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, img *image.Image) ([]spec.Mount, []*specgen.NamedVolume, error) { +func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, img *image.Image) ([]spec.Mount, []*specgen.NamedVolume, []*specgen.OverlayVolume, error) { // Get image volumes baseMounts, baseVolumes, err := getImageVolumes(ctx, img, s) if err != nil { - return nil, nil, err + return nil, nil, nil, err } // Get volumes-from mounts volFromMounts, volFromVolumes, err := getVolumesFrom(s.VolumesFrom, rt) if err != nil { - return nil, nil, err + return nil, nil, nil, err } // Supersede from --volumes-from. @@ -57,19 +57,53 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru // Need to make map forms of specgen mounts/volumes. unifiedMounts := map[string]spec.Mount{} unifiedVolumes := map[string]*specgen.NamedVolume{} + unifiedOverlays := map[string]*specgen.OverlayVolume{} + + // Need to make map forms of specgen mounts/volumes. + commonMounts, commonVolumes, commonOverlayVolumes, err := specgen.GenVolumeMounts(rtc.Volumes()) + if err != nil { + return nil, nil, nil, err + } + for _, m := range s.Mounts { if _, ok := unifiedMounts[m.Destination]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, "conflict in specified mounts - multiple mounts at %q", m.Destination) + return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict in specified mounts - multiple mounts at %q", m.Destination) } unifiedMounts[m.Destination] = m } + + for _, m := range commonMounts { + if _, ok := unifiedMounts[m.Destination]; !ok { + unifiedMounts[m.Destination] = m + } + } + for _, v := range s.Volumes { if _, ok := unifiedVolumes[v.Dest]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, "conflict in specified volumes - multiple volumes at %q", v.Dest) + return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict in specified volumes - multiple volumes at %q", v.Dest) } unifiedVolumes[v.Dest] = v } + for _, v := range commonVolumes { + if _, ok := unifiedVolumes[v.Dest]; !ok { + unifiedVolumes[v.Dest] = v + } + } + + for _, v := range s.OverlayVolumes { + if _, ok := unifiedOverlays[v.Destination]; ok { + return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict in specified volumes - multiple volumes at %q", v.Destination) + } + unifiedOverlays[v.Destination] = v + } + + for _, v := range commonOverlayVolumes { + if _, ok := unifiedOverlays[v.Destination]; ok { + unifiedOverlays[v.Destination] = v + } + } + // If requested, add container init binary if s.Init { initPath := s.InitPath @@ -78,10 +112,10 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru } initMount, err := addContainerInitBinary(s, initPath) if err != nil { - return nil, nil, err + return nil, nil, nil, err } if _, ok := unifiedMounts[initMount.Destination]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, "conflict with mount added by --init to %q", initMount.Destination) + return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict with mount added by --init to %q", initMount.Destination) } unifiedMounts[initMount.Destination] = initMount } @@ -115,12 +149,12 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru // Check for conflicts between named volumes and mounts for dest := range baseMounts { if _, ok := baseVolumes[dest]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest) + return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest) } } for dest := range baseVolumes { if _, ok := baseMounts[dest]; ok { - return nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest) + return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest) } } // Final step: maps to arrays @@ -129,7 +163,7 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru if mount.Type == TypeBind { absSrc, err := filepath.Abs(mount.Source) if err != nil { - return nil, nil, errors.Wrapf(err, "error getting absolute path of %s", mount.Source) + return nil, nil, nil, errors.Wrapf(err, "error getting absolute path of %s", mount.Source) } mount.Source = absSrc } @@ -140,7 +174,12 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru finalVolumes = append(finalVolumes, volume) } - return finalMounts, finalVolumes, nil + finalOverlays := make([]*specgen.OverlayVolume, 0, len(unifiedOverlays)) + for _, volume := range unifiedOverlays { + finalOverlays = append(finalOverlays, volume) + } + + return finalMounts, finalVolumes, finalOverlays, nil } // Get image volumes from the given image diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go index 0a9a16ea7..fad2406e5 100644 --- a/pkg/specgen/specgen.go +++ b/pkg/specgen/specgen.go @@ -1,13 +1,13 @@ package specgen import ( - "errors" "net" "syscall" "github.com/containers/image/v5/manifest" "github.com/containers/storage" spec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" ) // LogConfig describes the logging characteristics for a container @@ -459,42 +459,6 @@ type SpecGenerator struct { ContainerHealthCheckConfig } -// NamedVolume holds information about a named volume that will be mounted into -// the container. -type NamedVolume struct { - // Name is the name of the named volume to be mounted. May be empty. - // If empty, a new named volume with a pseudorandomly generated name - // will be mounted at the given destination. - Name string - // Destination to mount the named volume within the container. Must be - // an absolute path. Path will be created if it does not exist. - Dest string - // Options are options that the named volume will be mounted with. - Options []string -} - -// OverlayVolume holds information about a overlay volume that will be mounted into -// the container. -type OverlayVolume struct { - // Destination is the absolute path where the mount will be placed in the container. - Destination string `json:"destination"` - // Source specifies the source path of the mount. - Source string `json:"source,omitempty"` -} - -// ImageVolume is a volume based on a container image. The container image is -// first mounted on the host and is then bind-mounted into the container. An -// ImageVolume is always mounted read only. -type ImageVolume struct { - // Source is the source of the image volume. The image can be referred - // to by name and by ID. - Source string - // Destination is the absolute path of the mount in the container. - Destination string - // ReadWrite sets the volume writable. - ReadWrite bool -} - // PortMapping is one or more ports that will be mapped into the container. type PortMapping struct { // HostIP is the IP that we will bind to on the host. diff --git a/pkg/specgen/volumes.go b/pkg/specgen/volumes.go new file mode 100644 index 000000000..1178f9960 --- /dev/null +++ b/pkg/specgen/volumes.go @@ -0,0 +1,149 @@ +package specgen + +import ( + "path/filepath" + "strings" + + "github.com/containers/buildah/pkg/parse" + spec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +// NamedVolume holds information about a named volume that will be mounted into +// the container. +type NamedVolume struct { + // Name is the name of the named volume to be mounted. May be empty. + // If empty, a new named volume with a pseudorandomly generated name + // will be mounted at the given destination. + Name string + // Destination to mount the named volume within the container. Must be + // an absolute path. Path will be created if it does not exist. + Dest string + // Options are options that the named volume will be mounted with. + Options []string +} + +// OverlayVolume holds information about a overlay volume that will be mounted into +// the container. +type OverlayVolume struct { + // Destination is the absolute path where the mount will be placed in the container. + Destination string `json:"destination"` + // Source specifies the source path of the mount. + Source string `json:"source,omitempty"` +} + +// ImageVolume is a volume based on a container image. The container image is +// first mounted on the host and is then bind-mounted into the container. An +// ImageVolume is always mounted read only. +type ImageVolume struct { + // Source is the source of the image volume. The image can be referred + // to by name and by ID. + Source string + // Destination is the absolute path of the mount in the container. + Destination string + // ReadWrite sets the volume writable. + ReadWrite bool +} + +// GenVolumeMounts parses user input into mounts, volumes and overlay volumes +func GenVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*NamedVolume, map[string]*OverlayVolume, error) { + errDuplicateDest := errors.Errorf("duplicate mount destination") + + mounts := make(map[string]spec.Mount) + volumes := make(map[string]*NamedVolume) + overlayVolumes := make(map[string]*OverlayVolume) + + volumeFormatErr := errors.Errorf("incorrect volume format, should be [host-dir:]ctr-dir[:option]") + + for _, vol := range volumeFlag { + var ( + options []string + src string + dest string + err error + ) + + splitVol := strings.Split(vol, ":") + if len(splitVol) > 3 { + return nil, nil, nil, errors.Wrapf(volumeFormatErr, vol) + } + + src = splitVol[0] + if len(splitVol) == 1 { + // This is an anonymous named volume. Only thing given + // is destination. + // Name/source will be blank, and populated by libpod. + src = "" + dest = splitVol[0] + } else if len(splitVol) > 1 { + dest = splitVol[1] + } + if len(splitVol) > 2 { + if options, err = parse.ValidateVolumeOpts(strings.Split(splitVol[2], ",")); err != nil { + return nil, nil, nil, err + } + } + + // Do not check source dir for anonymous volumes + if len(splitVol) > 1 { + if err := parse.ValidateVolumeHostDir(src); err != nil { + return nil, nil, nil, err + } + } + if err := parse.ValidateVolumeCtrDir(dest); err != nil { + return nil, nil, nil, err + } + + cleanDest := filepath.Clean(dest) + + if strings.HasPrefix(src, "/") || strings.HasPrefix(src, ".") { + // This is not a named volume + overlayFlag := false + for _, o := range options { + if o == "O" { + overlayFlag = true + if len(options) > 1 { + return nil, nil, nil, errors.New("can't use 'O' with other options") + } + } + } + if overlayFlag { + // This is a overlay volume + newOverlayVol := new(OverlayVolume) + newOverlayVol.Destination = cleanDest + newOverlayVol.Source = src + if _, ok := overlayVolumes[newOverlayVol.Destination]; ok { + return nil, nil, nil, errors.Wrapf(errDuplicateDest, newOverlayVol.Destination) + } + overlayVolumes[newOverlayVol.Destination] = newOverlayVol + } else { + newMount := spec.Mount{ + Destination: cleanDest, + Type: "bind", + Source: src, + Options: options, + } + if _, ok := mounts[newMount.Destination]; ok { + return nil, nil, nil, errors.Wrapf(errDuplicateDest, newMount.Destination) + } + mounts[newMount.Destination] = newMount + } + } else { + // This is a named volume + newNamedVol := new(NamedVolume) + newNamedVol.Name = src + newNamedVol.Dest = cleanDest + newNamedVol.Options = options + + if _, ok := volumes[newNamedVol.Dest]; ok { + return nil, nil, nil, errors.Wrapf(errDuplicateDest, newNamedVol.Dest) + } + volumes[newNamedVol.Dest] = newNamedVol + } + + logrus.Debugf("User mount %s:%s options %v", src, dest, options) + } + + return mounts, volumes, overlayVolumes, nil +} diff --git a/test/e2e/config/containers-remote.conf b/test/e2e/config/containers-remote.conf new file mode 100644 index 000000000..bc9eab951 --- /dev/null +++ b/test/e2e/config/containers-remote.conf @@ -0,0 +1,51 @@ +[containers] + +# A list of ulimits to be set in containers by default, specified as +# "<ulimit name>=<soft limit>:<hard limit>", for example: +# "nofile=1024:2048" +# See setrlimit(2) for a list of resource names. +# Any limit not specified here will be inherited from the process launching the +# container engine. +# Ulimits has limits for non privileged container engines. +# +default_ulimits = [ + "nofile=100:100", +] + +# Environment variable list for the conmon process; used for passing necessary +# environment variables to conmon or the runtime. +# +env = [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "foo=bar1", +] + +# container engines use container separation using MAC(SELinux) labeling. +# Flag is ignored on label disabled systems. +# +label = false + +# Size of /dev/shm. Specified as <number><unit>. +# Unit is optional, values: +# b (bytes), k (kilobytes), m (megabytes), or g (gigabytes). +# If the unit is omitted, the system uses bytes. +# +shm_size = "202k" + +# List of devices. Specified as +# "<device-on-host>:<device-on-container>:<permissions>", for example: +# "/dev/sdc:/dev/xvdc:rwm". +# If it is empty or commented out, only the default devices will be used +# +devices = [] + +default_sysctls = [ + "net.ipv4.ping_group_range=0 0", +] + +dns_searches=[ "barfoo.com", ] +dns_servers=[ "4.3.2.1", ] + +tz = "America/New_York" + +umask = "0022" diff --git a/test/e2e/containers_conf_test.go b/test/e2e/containers_conf_test.go index 1d5be218b..906153c0f 100644 --- a/test/e2e/containers_conf_test.go +++ b/test/e2e/containers_conf_test.go @@ -177,6 +177,9 @@ var _ = Describe("Podman run", func() { } os.Setenv("CONTAINERS_CONF", conffile) + if IsRemote() { + podmanTest.RestartRemoteService() + } result := podmanTest.Podman([]string{"run", ALPINE, "ls", tempdir}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) @@ -224,6 +227,17 @@ var _ = Describe("Podman run", func() { Expect(session.LineInOuputStartsWith("search")).To(BeFalse()) }) + It("podman run use containers.conf search domain", func() { + session := podmanTest.Podman([]string{"run", ALPINE, "cat", "/etc/resolv.conf"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.LineInOuputStartsWith("search")).To(BeTrue()) + Expect(session.OutputToString()).To(ContainSubstring("foobar.com")) + + Expect(session.OutputToString()).To(ContainSubstring("1.2.3.4")) + Expect(session.OutputToString()).To(ContainSubstring("debug")) + }) + It("podman run containers.conf timezone", func() { //containers.conf timezone set to Pacific/Honolulu session := podmanTest.Podman([]string{"run", ALPINE, "date", "+'%H %Z'"}) @@ -231,6 +245,7 @@ var _ = Describe("Podman run", func() { Expect(session.ExitCode()).To(Equal(0)) Expect(session.OutputToString()).To(ContainSubstring("HST")) }) + It("podman run containers.conf umask", func() { //containers.conf umask set to 0002 if !strings.Contains(podmanTest.OCIRuntime, "crun") { @@ -243,4 +258,57 @@ var _ = Describe("Podman run", func() { Expect(session.OutputToString()).To(Equal("0002")) }) + It("podman-remote test localcontainers.conf versus remote containers.conf", func() { + if !IsRemote() { + Skip("this test is only for remote") + } + + os.Setenv("CONTAINERS_CONF", "config/containers-remote.conf") + // Configuration that comes from remote server + // env + session := podmanTest.Podman([]string{"run", ALPINE, "printenv", "foo"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(Equal("bar")) + + // dns-search, server, options + session = podmanTest.Podman([]string{"run", ALPINE, "cat", "/etc/resolv.conf"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.LineInOuputStartsWith("search")).To(BeTrue()) + Expect(session.OutputToString()).To(ContainSubstring("foobar.com")) + Expect(session.OutputToString()).To(ContainSubstring("1.2.3.4")) + Expect(session.OutputToString()).To(ContainSubstring("debug")) + + // sysctls + session = podmanTest.Podman([]string{"run", "--rm", ALPINE, "cat", "/proc/sys/net/ipv4/ping_group_range"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring("1000")) + + // shm-size + session = podmanTest.Podman([]string{"run", ALPINE, "grep", "shm", "/proc/self/mounts"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring("size=200k")) + + // ulimits + session = podmanTest.Podman([]string{"run", "--rm", fedoraMinimal, "ulimit", "-n"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring("500")) + + // Configuration that comes from remote client + // Timezone + session = podmanTest.Podman([]string{"run", ALPINE, "date", "+'%H %Z'"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring("EST")) + + // Umask + session = podmanTest.Podman([]string{"run", "--rm", ALPINE, "sh", "-c", "umask"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(Equal("0022")) + }) }) diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go index c6593df34..139a90ac7 100644 --- a/test/e2e/network_test.go +++ b/test/e2e/network_test.go @@ -76,31 +76,36 @@ var _ = Describe("Podman network", func() { Expect(session.LineInOutputContains(name)).To(BeFalse()) }) - It("podman network rm no args", func() { - session := podmanTest.Podman([]string{"network", "rm"}) - session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).ToNot(BeZero()) - }) - - It("podman network rm", func() { - SkipIfRootless("FIXME: This one is definitely broken in rootless mode") - name, path := generateNetworkConfig(podmanTest) - defer removeConf(path) - - session := podmanTest.Podman([]string{"network", "ls", "--quiet"}) - session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Equal(0)) - Expect(session.LineInOutputContains(name)).To(BeTrue()) - - rm := podmanTest.Podman([]string{"network", "rm", name}) - rm.WaitWithDefaultTimeout() - Expect(rm.ExitCode()).To(BeZero()) - - results := podmanTest.Podman([]string{"network", "ls", "--quiet"}) - results.WaitWithDefaultTimeout() - Expect(results.ExitCode()).To(Equal(0)) - Expect(results.LineInOutputContains(name)).To(BeFalse()) - }) + rm_func := func(rm string) { + It(fmt.Sprintf("podman network %s no args", rm), func() { + session := podmanTest.Podman([]string{"network", rm}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).ToNot(BeZero()) + + }) + + It(fmt.Sprintf("podman network %s", rm), func() { + name, path := generateNetworkConfig(podmanTest) + defer removeConf(path) + + session := podmanTest.Podman([]string{"network", "ls", "--quiet"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.LineInOutputContains(name)).To(BeTrue()) + + rm := podmanTest.Podman([]string{"network", rm, name}) + rm.WaitWithDefaultTimeout() + Expect(rm.ExitCode()).To(BeZero()) + + results := podmanTest.Podman([]string{"network", "ls", "--quiet"}) + results.WaitWithDefaultTimeout() + Expect(results.ExitCode()).To(Equal(0)) + Expect(results.LineInOutputContains(name)).To(BeFalse()) + }) + } + + rm_func("rm") + rm_func("remove") It("podman network inspect no args", func() { session := podmanTest.Podman([]string{"network", "inspect"}) diff --git a/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/shortnames.go b/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/shortnames.go index fadfe1a35..4001b65b6 100644 --- a/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/shortnames.go +++ b/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/shortnames.go @@ -8,8 +8,8 @@ import ( "github.com/BurntSushi/toml" "github.com/containers/image/v5/docker/reference" "github.com/containers/image/v5/types" + "github.com/containers/storage/pkg/homedir" "github.com/containers/storage/pkg/lockfile" - "github.com/docker/docker/pkg/homedir" "github.com/pkg/errors" ) diff --git a/vendor/github.com/containers/image/v5/version/version.go b/vendor/github.com/containers/image/v5/version/version.go index 3ef1c2410..14e553c9f 100644 --- a/vendor/github.com/containers/image/v5/version/version.go +++ b/vendor/github.com/containers/image/v5/version/version.go @@ -8,7 +8,7 @@ const ( // VersionMinor is for functionality in a backwards-compatible manner VersionMinor = 8 // VersionPatch is for backwards-compatible bug fixes - VersionPatch = 0 + VersionPatch = 1 // VersionDev indicates development branch. Releases will be empty string. VersionDev = "" diff --git a/vendor/github.com/containers/storage/VERSION b/vendor/github.com/containers/storage/VERSION index 53cc1a6f9..f9e8384bb 100644 --- a/vendor/github.com/containers/storage/VERSION +++ b/vendor/github.com/containers/storage/VERSION @@ -1 +1 @@ -1.24.0 +1.24.1 diff --git a/vendor/github.com/containers/storage/go.mod b/vendor/github.com/containers/storage/go.mod index 34c1ea7ad..86a5d8644 100644 --- a/vendor/github.com/containers/storage/go.mod +++ b/vendor/github.com/containers/storage/go.mod @@ -8,7 +8,7 @@ require ( github.com/Microsoft/hcsshim v0.8.9 github.com/docker/go-units v0.4.0 github.com/hashicorp/go-multierror v1.1.0 - github.com/klauspost/compress v1.11.2 + github.com/klauspost/compress v1.11.3 github.com/klauspost/pgzip v1.2.5 github.com/mattn/go-shellwords v1.0.10 github.com/mistifyio/go-zfs v2.1.1+incompatible diff --git a/vendor/github.com/containers/storage/go.sum b/vendor/github.com/containers/storage/go.sum index bec6aa59a..a5d3f3b82 100644 --- a/vendor/github.com/containers/storage/go.sum +++ b/vendor/github.com/containers/storage/go.sum @@ -64,8 +64,8 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.11.2 h1:MiK62aErc3gIiVEtyzKfeOHgW7atJb5g/KNX5m3c2nQ= -github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.3 h1:dB4Bn0tN3wdCzQxnS8r06kV74qN/TAfaIS0bVE8h3jc= +github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= diff --git a/vendor/github.com/containers/storage/pkg/unshare/unshare.go b/vendor/github.com/containers/storage/pkg/unshare/unshare.go index a08fb674d..a9210b0bf 100644 --- a/vendor/github.com/containers/storage/pkg/unshare/unshare.go +++ b/vendor/github.com/containers/storage/pkg/unshare/unshare.go @@ -26,6 +26,7 @@ func HomeDir() (string, error) { return } homeDir, homeDirErr = usr.HomeDir, nil + return } homeDir, homeDirErr = home, nil }) diff --git a/vendor/github.com/klauspost/compress/flate/gen_inflate.go b/vendor/github.com/klauspost/compress/flate/gen_inflate.go index b26d19ec2..35fc072a3 100644 --- a/vendor/github.com/klauspost/compress/flate/gen_inflate.go +++ b/vendor/github.com/klauspost/compress/flate/gen_inflate.go @@ -42,16 +42,6 @@ func (f *decompressor) $FUNCNAME$() { stateDict ) fr := f.r.($TYPE$) - moreBits := func() error { - c, err := fr.ReadByte() - if err != nil { - return noEOF(err) - } - f.roffset++ - f.b |= uint32(c) << f.nb - f.nb += 8 - return nil - } switch f.stepState { case stateInit: @@ -112,9 +102,7 @@ readLiteral: } } - var n uint // number of bits extra var length int - var err error switch { case v < 256: f.dict.writeByte(byte(v)) @@ -131,71 +119,97 @@ readLiteral: // otherwise, reference to older data case v < 265: length = v - (257 - 3) - n = 0 - case v < 269: - length = v*2 - (265*2 - 11) - n = 1 - case v < 273: - length = v*4 - (269*4 - 19) - n = 2 - case v < 277: - length = v*8 - (273*8 - 35) - n = 3 - case v < 281: - length = v*16 - (277*16 - 67) - n = 4 - case v < 285: - length = v*32 - (281*32 - 131) - n = 5 case v < maxNumLit: - length = 258 - n = 0 - default: - if debugDecode { - fmt.Println(v, ">= maxNumLit") - } - f.err = CorruptInputError(f.roffset) - return - } - if n > 0 { + val := decCodeToLen[(v - 257)] + length = int(val.length) + 3 + n := uint(val.extra) for f.nb < n { - if err = moreBits(); err != nil { + c, err := fr.ReadByte() + if err != nil { if debugDecode { fmt.Println("morebits n>0:", err) } f.err = err return } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 } length += int(f.b & uint32(1<<(n®SizeMaskUint32)-1)) f.b >>= n & regSizeMaskUint32 f.nb -= n + default: + if debugDecode { + fmt.Println(v, ">= maxNumLit") + } + f.err = CorruptInputError(f.roffset) + return } var dist uint32 if f.hd == nil { for f.nb < 5 { - if err = f.moreBits(); err != nil { + c, err := fr.ReadByte() + if err != nil { if debugDecode { fmt.Println("morebits f.nb<5:", err) } f.err = err return } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 } dist = uint32(bits.Reverse8(uint8(f.b & 0x1F << 3))) f.b >>= 5 f.nb -= 5 } else { - sym, err := f.huffSym(f.hd) - if err != nil { - if debugDecode { - fmt.Println("huffsym:", err) + // Since a huffmanDecoder can be empty or be composed of a degenerate tree + // with single element, huffSym must error on these two edge cases. In both + // cases, the chunks slice will be 0 for the invalid sequence, leading it + // satisfy the n == 0 check below. + n := uint(f.hd.maxRead) + // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers, + // but is smart enough to keep local variables in registers, so use nb and b, + // inline call to moreBits and reassign b,nb back to f on return. + nb, b := f.nb, f.b + for { + for nb < n { + c, err := fr.ReadByte() + if err != nil { + f.b = b + f.nb = nb + f.err = noEOF(err) + return + } + f.roffset++ + b |= uint32(c) << (nb & regSizeMaskUint32) + nb += 8 + } + chunk := f.hd.chunks[b&(huffmanNumChunks-1)] + n = uint(chunk & huffmanCountMask) + if n > huffmanChunkBits { + chunk = f.hd.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hd.linkMask] + n = uint(chunk & huffmanCountMask) + } + if n <= nb { + if n == 0 { + f.b = b + f.nb = nb + if debugDecode { + fmt.Println("huffsym: n==0") + } + f.err = CorruptInputError(f.roffset) + return + } + f.b = b >> (n & regSizeMaskUint32) + f.nb = nb - n + dist = uint32(chunk >> huffmanValueShift) + break } - f.err = err - return } - dist = uint32(sym) } switch { @@ -206,13 +220,17 @@ readLiteral: // have 1 bit in bottom of dist, need nb more. extra := (dist & 1) << (nb & regSizeMaskUint32) for f.nb < nb { - if err = f.moreBits(); err != nil { + c, err := fr.ReadByte() + if err != nil { if debugDecode { fmt.Println("morebits f.nb<nb:", err) } f.err = err return } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 } extra |= f.b & uint32(1<<(nb®SizeMaskUint32)-1) f.b >>= nb & regSizeMaskUint32 diff --git a/vendor/github.com/klauspost/compress/flate/inflate.go b/vendor/github.com/klauspost/compress/flate/inflate.go index 189e9fe0b..16bc51408 100644 --- a/vendor/github.com/klauspost/compress/flate/inflate.go +++ b/vendor/github.com/klauspost/compress/flate/inflate.go @@ -29,6 +29,13 @@ const ( debugDecode = false ) +// Value of length - 3 and extra bits. +type lengthExtra struct { + length, extra uint8 +} + +var decCodeToLen = [32]lengthExtra{{length: 0x0, extra: 0x0}, {length: 0x1, extra: 0x0}, {length: 0x2, extra: 0x0}, {length: 0x3, extra: 0x0}, {length: 0x4, extra: 0x0}, {length: 0x5, extra: 0x0}, {length: 0x6, extra: 0x0}, {length: 0x7, extra: 0x0}, {length: 0x8, extra: 0x1}, {length: 0xa, extra: 0x1}, {length: 0xc, extra: 0x1}, {length: 0xe, extra: 0x1}, {length: 0x10, extra: 0x2}, {length: 0x14, extra: 0x2}, {length: 0x18, extra: 0x2}, {length: 0x1c, extra: 0x2}, {length: 0x20, extra: 0x3}, {length: 0x28, extra: 0x3}, {length: 0x30, extra: 0x3}, {length: 0x38, extra: 0x3}, {length: 0x40, extra: 0x4}, {length: 0x50, extra: 0x4}, {length: 0x60, extra: 0x4}, {length: 0x70, extra: 0x4}, {length: 0x80, extra: 0x5}, {length: 0xa0, extra: 0x5}, {length: 0xc0, extra: 0x5}, {length: 0xe0, extra: 0x5}, {length: 0xff, extra: 0x0}, {length: 0x0, extra: 0x0}, {length: 0x0, extra: 0x0}, {length: 0x0, extra: 0x0}} + // Initialize the fixedHuffmanDecoder only once upon first use. var fixedOnce sync.Once var fixedHuffmanDecoder huffmanDecoder diff --git a/vendor/github.com/klauspost/compress/flate/inflate_gen.go b/vendor/github.com/klauspost/compress/flate/inflate_gen.go index 9a92a1b30..cc6db2792 100644 --- a/vendor/github.com/klauspost/compress/flate/inflate_gen.go +++ b/vendor/github.com/klauspost/compress/flate/inflate_gen.go @@ -20,16 +20,6 @@ func (f *decompressor) huffmanBytesBuffer() { stateDict ) fr := f.r.(*bytes.Buffer) - moreBits := func() error { - c, err := fr.ReadByte() - if err != nil { - return noEOF(err) - } - f.roffset++ - f.b |= uint32(c) << f.nb - f.nb += 8 - return nil - } switch f.stepState { case stateInit: @@ -90,9 +80,7 @@ readLiteral: } } - var n uint // number of bits extra var length int - var err error switch { case v < 256: f.dict.writeByte(byte(v)) @@ -109,71 +97,97 @@ readLiteral: // otherwise, reference to older data case v < 265: length = v - (257 - 3) - n = 0 - case v < 269: - length = v*2 - (265*2 - 11) - n = 1 - case v < 273: - length = v*4 - (269*4 - 19) - n = 2 - case v < 277: - length = v*8 - (273*8 - 35) - n = 3 - case v < 281: - length = v*16 - (277*16 - 67) - n = 4 - case v < 285: - length = v*32 - (281*32 - 131) - n = 5 case v < maxNumLit: - length = 258 - n = 0 - default: - if debugDecode { - fmt.Println(v, ">= maxNumLit") - } - f.err = CorruptInputError(f.roffset) - return - } - if n > 0 { + val := decCodeToLen[(v - 257)] + length = int(val.length) + 3 + n := uint(val.extra) for f.nb < n { - if err = moreBits(); err != nil { + c, err := fr.ReadByte() + if err != nil { if debugDecode { fmt.Println("morebits n>0:", err) } f.err = err return } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 } length += int(f.b & uint32(1<<(n®SizeMaskUint32)-1)) f.b >>= n & regSizeMaskUint32 f.nb -= n + default: + if debugDecode { + fmt.Println(v, ">= maxNumLit") + } + f.err = CorruptInputError(f.roffset) + return } var dist uint32 if f.hd == nil { for f.nb < 5 { - if err = f.moreBits(); err != nil { + c, err := fr.ReadByte() + if err != nil { if debugDecode { fmt.Println("morebits f.nb<5:", err) } f.err = err return } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 } dist = uint32(bits.Reverse8(uint8(f.b & 0x1F << 3))) f.b >>= 5 f.nb -= 5 } else { - sym, err := f.huffSym(f.hd) - if err != nil { - if debugDecode { - fmt.Println("huffsym:", err) + // Since a huffmanDecoder can be empty or be composed of a degenerate tree + // with single element, huffSym must error on these two edge cases. In both + // cases, the chunks slice will be 0 for the invalid sequence, leading it + // satisfy the n == 0 check below. + n := uint(f.hd.maxRead) + // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers, + // but is smart enough to keep local variables in registers, so use nb and b, + // inline call to moreBits and reassign b,nb back to f on return. + nb, b := f.nb, f.b + for { + for nb < n { + c, err := fr.ReadByte() + if err != nil { + f.b = b + f.nb = nb + f.err = noEOF(err) + return + } + f.roffset++ + b |= uint32(c) << (nb & regSizeMaskUint32) + nb += 8 + } + chunk := f.hd.chunks[b&(huffmanNumChunks-1)] + n = uint(chunk & huffmanCountMask) + if n > huffmanChunkBits { + chunk = f.hd.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hd.linkMask] + n = uint(chunk & huffmanCountMask) + } + if n <= nb { + if n == 0 { + f.b = b + f.nb = nb + if debugDecode { + fmt.Println("huffsym: n==0") + } + f.err = CorruptInputError(f.roffset) + return + } + f.b = b >> (n & regSizeMaskUint32) + f.nb = nb - n + dist = uint32(chunk >> huffmanValueShift) + break } - f.err = err - return } - dist = uint32(sym) } switch { @@ -184,13 +198,17 @@ readLiteral: // have 1 bit in bottom of dist, need nb more. extra := (dist & 1) << (nb & regSizeMaskUint32) for f.nb < nb { - if err = f.moreBits(); err != nil { + c, err := fr.ReadByte() + if err != nil { if debugDecode { fmt.Println("morebits f.nb<nb:", err) } f.err = err return } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 } extra |= f.b & uint32(1<<(nb®SizeMaskUint32)-1) f.b >>= nb & regSizeMaskUint32 @@ -246,16 +264,6 @@ func (f *decompressor) huffmanBytesReader() { stateDict ) fr := f.r.(*bytes.Reader) - moreBits := func() error { - c, err := fr.ReadByte() - if err != nil { - return noEOF(err) - } - f.roffset++ - f.b |= uint32(c) << f.nb - f.nb += 8 - return nil - } switch f.stepState { case stateInit: @@ -316,9 +324,7 @@ readLiteral: } } - var n uint // number of bits extra var length int - var err error switch { case v < 256: f.dict.writeByte(byte(v)) @@ -335,71 +341,97 @@ readLiteral: // otherwise, reference to older data case v < 265: length = v - (257 - 3) - n = 0 - case v < 269: - length = v*2 - (265*2 - 11) - n = 1 - case v < 273: - length = v*4 - (269*4 - 19) - n = 2 - case v < 277: - length = v*8 - (273*8 - 35) - n = 3 - case v < 281: - length = v*16 - (277*16 - 67) - n = 4 - case v < 285: - length = v*32 - (281*32 - 131) - n = 5 case v < maxNumLit: - length = 258 - n = 0 - default: - if debugDecode { - fmt.Println(v, ">= maxNumLit") - } - f.err = CorruptInputError(f.roffset) - return - } - if n > 0 { + val := decCodeToLen[(v - 257)] + length = int(val.length) + 3 + n := uint(val.extra) for f.nb < n { - if err = moreBits(); err != nil { + c, err := fr.ReadByte() + if err != nil { if debugDecode { fmt.Println("morebits n>0:", err) } f.err = err return } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 } length += int(f.b & uint32(1<<(n®SizeMaskUint32)-1)) f.b >>= n & regSizeMaskUint32 f.nb -= n + default: + if debugDecode { + fmt.Println(v, ">= maxNumLit") + } + f.err = CorruptInputError(f.roffset) + return } var dist uint32 if f.hd == nil { for f.nb < 5 { - if err = f.moreBits(); err != nil { + c, err := fr.ReadByte() + if err != nil { if debugDecode { fmt.Println("morebits f.nb<5:", err) } f.err = err return } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 } dist = uint32(bits.Reverse8(uint8(f.b & 0x1F << 3))) f.b >>= 5 f.nb -= 5 } else { - sym, err := f.huffSym(f.hd) - if err != nil { - if debugDecode { - fmt.Println("huffsym:", err) + // Since a huffmanDecoder can be empty or be composed of a degenerate tree + // with single element, huffSym must error on these two edge cases. In both + // cases, the chunks slice will be 0 for the invalid sequence, leading it + // satisfy the n == 0 check below. + n := uint(f.hd.maxRead) + // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers, + // but is smart enough to keep local variables in registers, so use nb and b, + // inline call to moreBits and reassign b,nb back to f on return. + nb, b := f.nb, f.b + for { + for nb < n { + c, err := fr.ReadByte() + if err != nil { + f.b = b + f.nb = nb + f.err = noEOF(err) + return + } + f.roffset++ + b |= uint32(c) << (nb & regSizeMaskUint32) + nb += 8 + } + chunk := f.hd.chunks[b&(huffmanNumChunks-1)] + n = uint(chunk & huffmanCountMask) + if n > huffmanChunkBits { + chunk = f.hd.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hd.linkMask] + n = uint(chunk & huffmanCountMask) + } + if n <= nb { + if n == 0 { + f.b = b + f.nb = nb + if debugDecode { + fmt.Println("huffsym: n==0") + } + f.err = CorruptInputError(f.roffset) + return + } + f.b = b >> (n & regSizeMaskUint32) + f.nb = nb - n + dist = uint32(chunk >> huffmanValueShift) + break } - f.err = err - return } - dist = uint32(sym) } switch { @@ -410,13 +442,17 @@ readLiteral: // have 1 bit in bottom of dist, need nb more. extra := (dist & 1) << (nb & regSizeMaskUint32) for f.nb < nb { - if err = f.moreBits(); err != nil { + c, err := fr.ReadByte() + if err != nil { if debugDecode { fmt.Println("morebits f.nb<nb:", err) } f.err = err return } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 } extra |= f.b & uint32(1<<(nb®SizeMaskUint32)-1) f.b >>= nb & regSizeMaskUint32 @@ -472,16 +508,6 @@ func (f *decompressor) huffmanBufioReader() { stateDict ) fr := f.r.(*bufio.Reader) - moreBits := func() error { - c, err := fr.ReadByte() - if err != nil { - return noEOF(err) - } - f.roffset++ - f.b |= uint32(c) << f.nb - f.nb += 8 - return nil - } switch f.stepState { case stateInit: @@ -542,9 +568,7 @@ readLiteral: } } - var n uint // number of bits extra var length int - var err error switch { case v < 256: f.dict.writeByte(byte(v)) @@ -561,71 +585,97 @@ readLiteral: // otherwise, reference to older data case v < 265: length = v - (257 - 3) - n = 0 - case v < 269: - length = v*2 - (265*2 - 11) - n = 1 - case v < 273: - length = v*4 - (269*4 - 19) - n = 2 - case v < 277: - length = v*8 - (273*8 - 35) - n = 3 - case v < 281: - length = v*16 - (277*16 - 67) - n = 4 - case v < 285: - length = v*32 - (281*32 - 131) - n = 5 case v < maxNumLit: - length = 258 - n = 0 - default: - if debugDecode { - fmt.Println(v, ">= maxNumLit") - } - f.err = CorruptInputError(f.roffset) - return - } - if n > 0 { + val := decCodeToLen[(v - 257)] + length = int(val.length) + 3 + n := uint(val.extra) for f.nb < n { - if err = moreBits(); err != nil { + c, err := fr.ReadByte() + if err != nil { if debugDecode { fmt.Println("morebits n>0:", err) } f.err = err return } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 } length += int(f.b & uint32(1<<(n®SizeMaskUint32)-1)) f.b >>= n & regSizeMaskUint32 f.nb -= n + default: + if debugDecode { + fmt.Println(v, ">= maxNumLit") + } + f.err = CorruptInputError(f.roffset) + return } var dist uint32 if f.hd == nil { for f.nb < 5 { - if err = f.moreBits(); err != nil { + c, err := fr.ReadByte() + if err != nil { if debugDecode { fmt.Println("morebits f.nb<5:", err) } f.err = err return } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 } dist = uint32(bits.Reverse8(uint8(f.b & 0x1F << 3))) f.b >>= 5 f.nb -= 5 } else { - sym, err := f.huffSym(f.hd) - if err != nil { - if debugDecode { - fmt.Println("huffsym:", err) + // Since a huffmanDecoder can be empty or be composed of a degenerate tree + // with single element, huffSym must error on these two edge cases. In both + // cases, the chunks slice will be 0 for the invalid sequence, leading it + // satisfy the n == 0 check below. + n := uint(f.hd.maxRead) + // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers, + // but is smart enough to keep local variables in registers, so use nb and b, + // inline call to moreBits and reassign b,nb back to f on return. + nb, b := f.nb, f.b + for { + for nb < n { + c, err := fr.ReadByte() + if err != nil { + f.b = b + f.nb = nb + f.err = noEOF(err) + return + } + f.roffset++ + b |= uint32(c) << (nb & regSizeMaskUint32) + nb += 8 + } + chunk := f.hd.chunks[b&(huffmanNumChunks-1)] + n = uint(chunk & huffmanCountMask) + if n > huffmanChunkBits { + chunk = f.hd.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hd.linkMask] + n = uint(chunk & huffmanCountMask) + } + if n <= nb { + if n == 0 { + f.b = b + f.nb = nb + if debugDecode { + fmt.Println("huffsym: n==0") + } + f.err = CorruptInputError(f.roffset) + return + } + f.b = b >> (n & regSizeMaskUint32) + f.nb = nb - n + dist = uint32(chunk >> huffmanValueShift) + break } - f.err = err - return } - dist = uint32(sym) } switch { @@ -636,13 +686,17 @@ readLiteral: // have 1 bit in bottom of dist, need nb more. extra := (dist & 1) << (nb & regSizeMaskUint32) for f.nb < nb { - if err = f.moreBits(); err != nil { + c, err := fr.ReadByte() + if err != nil { if debugDecode { fmt.Println("morebits f.nb<nb:", err) } f.err = err return } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 } extra |= f.b & uint32(1<<(nb®SizeMaskUint32)-1) f.b >>= nb & regSizeMaskUint32 @@ -698,16 +752,6 @@ func (f *decompressor) huffmanStringsReader() { stateDict ) fr := f.r.(*strings.Reader) - moreBits := func() error { - c, err := fr.ReadByte() - if err != nil { - return noEOF(err) - } - f.roffset++ - f.b |= uint32(c) << f.nb - f.nb += 8 - return nil - } switch f.stepState { case stateInit: @@ -768,9 +812,7 @@ readLiteral: } } - var n uint // number of bits extra var length int - var err error switch { case v < 256: f.dict.writeByte(byte(v)) @@ -787,71 +829,97 @@ readLiteral: // otherwise, reference to older data case v < 265: length = v - (257 - 3) - n = 0 - case v < 269: - length = v*2 - (265*2 - 11) - n = 1 - case v < 273: - length = v*4 - (269*4 - 19) - n = 2 - case v < 277: - length = v*8 - (273*8 - 35) - n = 3 - case v < 281: - length = v*16 - (277*16 - 67) - n = 4 - case v < 285: - length = v*32 - (281*32 - 131) - n = 5 case v < maxNumLit: - length = 258 - n = 0 - default: - if debugDecode { - fmt.Println(v, ">= maxNumLit") - } - f.err = CorruptInputError(f.roffset) - return - } - if n > 0 { + val := decCodeToLen[(v - 257)] + length = int(val.length) + 3 + n := uint(val.extra) for f.nb < n { - if err = moreBits(); err != nil { + c, err := fr.ReadByte() + if err != nil { if debugDecode { fmt.Println("morebits n>0:", err) } f.err = err return } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 } length += int(f.b & uint32(1<<(n®SizeMaskUint32)-1)) f.b >>= n & regSizeMaskUint32 f.nb -= n + default: + if debugDecode { + fmt.Println(v, ">= maxNumLit") + } + f.err = CorruptInputError(f.roffset) + return } var dist uint32 if f.hd == nil { for f.nb < 5 { - if err = f.moreBits(); err != nil { + c, err := fr.ReadByte() + if err != nil { if debugDecode { fmt.Println("morebits f.nb<5:", err) } f.err = err return } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 } dist = uint32(bits.Reverse8(uint8(f.b & 0x1F << 3))) f.b >>= 5 f.nb -= 5 } else { - sym, err := f.huffSym(f.hd) - if err != nil { - if debugDecode { - fmt.Println("huffsym:", err) + // Since a huffmanDecoder can be empty or be composed of a degenerate tree + // with single element, huffSym must error on these two edge cases. In both + // cases, the chunks slice will be 0 for the invalid sequence, leading it + // satisfy the n == 0 check below. + n := uint(f.hd.maxRead) + // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers, + // but is smart enough to keep local variables in registers, so use nb and b, + // inline call to moreBits and reassign b,nb back to f on return. + nb, b := f.nb, f.b + for { + for nb < n { + c, err := fr.ReadByte() + if err != nil { + f.b = b + f.nb = nb + f.err = noEOF(err) + return + } + f.roffset++ + b |= uint32(c) << (nb & regSizeMaskUint32) + nb += 8 + } + chunk := f.hd.chunks[b&(huffmanNumChunks-1)] + n = uint(chunk & huffmanCountMask) + if n > huffmanChunkBits { + chunk = f.hd.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hd.linkMask] + n = uint(chunk & huffmanCountMask) + } + if n <= nb { + if n == 0 { + f.b = b + f.nb = nb + if debugDecode { + fmt.Println("huffsym: n==0") + } + f.err = CorruptInputError(f.roffset) + return + } + f.b = b >> (n & regSizeMaskUint32) + f.nb = nb - n + dist = uint32(chunk >> huffmanValueShift) + break } - f.err = err - return } - dist = uint32(sym) } switch { @@ -862,13 +930,17 @@ readLiteral: // have 1 bit in bottom of dist, need nb more. extra := (dist & 1) << (nb & regSizeMaskUint32) for f.nb < nb { - if err = f.moreBits(); err != nil { + c, err := fr.ReadByte() + if err != nil { if debugDecode { fmt.Println("morebits f.nb<nb:", err) } f.err = err return } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 } extra |= f.b & uint32(1<<(nb®SizeMaskUint32)-1) f.b >>= nb & regSizeMaskUint32 diff --git a/vendor/github.com/klauspost/compress/zstd/README.md b/vendor/github.com/klauspost/compress/zstd/README.md index 07f7285f0..08e553f75 100644 --- a/vendor/github.com/klauspost/compress/zstd/README.md +++ b/vendor/github.com/klauspost/compress/zstd/README.md @@ -54,11 +54,11 @@ To create a writer with default options, do like this: ```Go // Compress input to output. func Compress(in io.Reader, out io.Writer) error { - w, err := NewWriter(output) + enc, err := zstd.NewWriter(out) if err != nil { return err } - _, err := io.Copy(w, input) + _, err = io.Copy(enc, in) if err != nil { enc.Close() return err diff --git a/vendor/github.com/klauspost/compress/zstd/decoder.go b/vendor/github.com/klauspost/compress/zstd/decoder.go index d78be6d42..cdda0de58 100644 --- a/vendor/github.com/klauspost/compress/zstd/decoder.go +++ b/vendor/github.com/klauspost/compress/zstd/decoder.go @@ -323,19 +323,23 @@ func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) { } if frame.FrameContentSize > 0 && frame.FrameContentSize < 1<<30 { // Never preallocate moe than 1 GB up front. - if uint64(cap(dst)) < frame.FrameContentSize { + if cap(dst)-len(dst) < int(frame.FrameContentSize) { dst2 := make([]byte, len(dst), len(dst)+int(frame.FrameContentSize)) copy(dst2, dst) dst = dst2 } } if cap(dst) == 0 { - // Allocate window size * 2 by default if nothing is provided and we didn't get frame content size. - size := frame.WindowSize * 2 + // Allocate len(input) * 2 by default if nothing is provided + // and we didn't get frame content size. + size := len(input) * 2 // Cap to 1 MB. if size > 1<<20 { size = 1 << 20 } + if uint64(size) > d.o.maxDecodedSize { + size = int(d.o.maxDecodedSize) + } dst = make([]byte, 0, size) } diff --git a/vendor/modules.txt b/vendor/modules.txt index 320d9851f..965713ed1 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -104,7 +104,7 @@ github.com/containers/common/pkg/sysinfo github.com/containers/common/version # github.com/containers/conmon v2.0.20+incompatible github.com/containers/conmon/runner/config -# github.com/containers/image/v5 v5.8.0 +# github.com/containers/image/v5 v5.8.1 github.com/containers/image/v5/copy github.com/containers/image/v5/directory github.com/containers/image/v5/directory/explicitfilepath @@ -168,7 +168,7 @@ github.com/containers/psgo/internal/dev github.com/containers/psgo/internal/host github.com/containers/psgo/internal/proc github.com/containers/psgo/internal/process -# github.com/containers/storage v1.24.0 +# github.com/containers/storage v1.24.1 github.com/containers/storage github.com/containers/storage/drivers github.com/containers/storage/drivers/aufs @@ -339,7 +339,7 @@ github.com/json-iterator/go # github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a github.com/juju/ansiterm github.com/juju/ansiterm/tabwriter -# github.com/klauspost/compress v1.11.2 +# github.com/klauspost/compress v1.11.3 github.com/klauspost/compress/flate github.com/klauspost/compress/fse github.com/klauspost/compress/huff0 |