go.mod: update osbuild/images to v0.74.0
This commit is contained in:
parent
3789ff4ce8
commit
c9972f7da8
327 changed files with 8341 additions and 12785 deletions
61
go.mod
61
go.mod
|
|
@ -1,6 +1,8 @@
|
||||||
module github.com/osbuild/osbuild-composer
|
module github.com/osbuild/osbuild-composer
|
||||||
|
|
||||||
go 1.21
|
go 1.21.0
|
||||||
|
|
||||||
|
toolchain go1.21.11
|
||||||
|
|
||||||
exclude github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
exclude github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
||||||
|
|
||||||
|
|
@ -16,7 +18,7 @@ require (
|
||||||
github.com/Azure/go-autorest/autorest v0.11.29
|
github.com/Azure/go-autorest/autorest v0.11.29
|
||||||
github.com/Azure/go-autorest/autorest/azure/auth v0.5.13
|
github.com/Azure/go-autorest/autorest/azure/auth v0.5.13
|
||||||
github.com/BurntSushi/toml v1.4.0
|
github.com/BurntSushi/toml v1.4.0
|
||||||
github.com/aws/aws-sdk-go v1.55.2
|
github.com/aws/aws-sdk-go v1.55.5
|
||||||
github.com/coreos/go-semver v0.3.1
|
github.com/coreos/go-semver v0.3.1
|
||||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
|
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
|
||||||
github.com/deepmap/oapi-codegen v1.8.2
|
github.com/deepmap/oapi-codegen v1.8.2
|
||||||
|
|
@ -36,7 +38,7 @@ require (
|
||||||
github.com/labstack/gommon v0.4.2
|
github.com/labstack/gommon v0.4.2
|
||||||
github.com/openshift-online/ocm-sdk-go v0.1.432
|
github.com/openshift-online/ocm-sdk-go v0.1.432
|
||||||
github.com/oracle/oci-go-sdk/v54 v54.0.0
|
github.com/oracle/oci-go-sdk/v54 v54.0.0
|
||||||
github.com/osbuild/images v0.72.0
|
github.com/osbuild/images v0.74.0
|
||||||
github.com/osbuild/osbuild-composer/pkg/splunk_logger v0.0.0-20231117174845-e969a9dc3cd1
|
github.com/osbuild/osbuild-composer/pkg/splunk_logger v0.0.0-20231117174845-e969a9dc3cd1
|
||||||
github.com/osbuild/pulp-client v0.1.0
|
github.com/osbuild/pulp-client v0.1.0
|
||||||
github.com/prometheus/client_golang v1.19.1
|
github.com/prometheus/client_golang v1.19.1
|
||||||
|
|
@ -46,19 +48,19 @@ require (
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
github.com/ubccr/kerby v0.0.0-20170626144437-201a958fc453
|
github.com/ubccr/kerby v0.0.0-20170626144437-201a958fc453
|
||||||
github.com/vmware/govmomi v0.39.0
|
github.com/vmware/govmomi v0.39.0
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
|
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8
|
||||||
golang.org/x/oauth2 v0.21.0
|
golang.org/x/oauth2 v0.21.0
|
||||||
golang.org/x/sync v0.7.0
|
golang.org/x/sync v0.7.0
|
||||||
golang.org/x/sys v0.22.0
|
golang.org/x/sys v0.22.0
|
||||||
google.golang.org/api v0.189.0
|
google.golang.org/api v0.190.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go v0.115.0 // indirect
|
cloud.google.com/go v0.115.0 // indirect
|
||||||
cloud.google.com/go/auth v0.7.2 // indirect
|
cloud.google.com/go/auth v0.7.3 // indirect
|
||||||
cloud.google.com/go/auth/oauth2adapt v0.2.3 // indirect
|
cloud.google.com/go/auth/oauth2adapt v0.2.3 // indirect
|
||||||
cloud.google.com/go/compute/metadata v0.5.0 // indirect
|
cloud.google.com/go/compute/metadata v0.5.0 // indirect
|
||||||
cloud.google.com/go/iam v1.1.10 // indirect
|
cloud.google.com/go/iam v1.1.12 // indirect
|
||||||
dario.cat/mergo v1.0.0 // indirect
|
dario.cat/mergo v1.0.0 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.13.0 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.13.0 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
|
||||||
|
|
@ -72,7 +74,7 @@ require (
|
||||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
|
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
|
||||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||||
github.com/Microsoft/hcsshim v0.12.3 // indirect
|
github.com/Microsoft/hcsshim v0.12.5 // indirect
|
||||||
github.com/VividCortex/ewma v1.2.0 // indirect
|
github.com/VividCortex/ewma v1.2.0 // indirect
|
||||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
|
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
|
||||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||||
|
|
@ -83,25 +85,25 @@ require (
|
||||||
github.com/containerd/cgroups/v3 v3.0.3 // indirect
|
github.com/containerd/cgroups/v3 v3.0.3 // indirect
|
||||||
github.com/containerd/errdefs v0.1.0 // indirect
|
github.com/containerd/errdefs v0.1.0 // indirect
|
||||||
github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect
|
github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect
|
||||||
github.com/containers/common v0.59.2 // indirect
|
github.com/containers/common v0.60.0 // indirect
|
||||||
github.com/containers/image/v5 v5.31.1 // indirect
|
github.com/containers/image/v5 v5.32.0 // indirect
|
||||||
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect
|
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect
|
||||||
github.com/containers/ocicrypt v1.1.10 // indirect
|
github.com/containers/ocicrypt v1.2.0 // indirect
|
||||||
github.com/containers/storage v1.54.0 // indirect
|
github.com/containers/storage v1.55.0 // indirect
|
||||||
github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f // indirect
|
github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f // indirect
|
||||||
github.com/cyphar/filepath-securejoin v0.2.5 // indirect
|
github.com/cyphar/filepath-securejoin v0.3.1 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||||
github.com/distribution/reference v0.6.0 // indirect
|
github.com/distribution/reference v0.6.0 // indirect
|
||||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||||
github.com/docker/docker v26.1.3+incompatible // indirect
|
github.com/docker/docker v27.1.1+incompatible // indirect
|
||||||
github.com/docker/docker-credential-helpers v0.8.1 // indirect
|
github.com/docker/docker-credential-helpers v0.8.2 // indirect
|
||||||
github.com/docker/go-connections v0.5.0 // indirect
|
github.com/docker/go-connections v0.5.0 // indirect
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
github.com/dougm/pretty v0.0.0-20171025230240-2ee9d7453c02 // indirect
|
github.com/dougm/pretty v0.0.0-20171025230240-2ee9d7453c02 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/ghodss/yaml v1.0.0 // indirect
|
github.com/ghodss/yaml v1.0.0 // indirect
|
||||||
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
|
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
|
||||||
github.com/go-logr/logr v1.4.2 // indirect
|
github.com/go-logr/logr v1.4.2 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-openapi/analysis v0.23.0 // indirect
|
github.com/go-openapi/analysis v0.23.0 // indirect
|
||||||
|
|
@ -120,9 +122,9 @@ require (
|
||||||
github.com/golang/glog v1.2.0 // indirect
|
github.com/golang/glog v1.2.0 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/google/go-containerregistry v0.19.1 // indirect
|
github.com/google/go-containerregistry v0.20.0 // indirect
|
||||||
github.com/google/go-intervals v0.0.2 // indirect
|
github.com/google/go-intervals v0.0.2 // indirect
|
||||||
github.com/google/s2a-go v0.1.7 // indirect
|
github.com/google/s2a-go v0.1.8 // indirect
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
||||||
github.com/googleapis/gax-go/v2 v2.13.0 // indirect
|
github.com/googleapis/gax-go/v2 v2.13.0 // indirect
|
||||||
github.com/gorilla/css v1.0.0 // indirect
|
github.com/gorilla/css v1.0.0 // indirect
|
||||||
|
|
@ -142,11 +144,11 @@ require (
|
||||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/compress v1.17.8 // indirect
|
github.com/klauspost/compress v1.17.9 // indirect
|
||||||
github.com/klauspost/pgzip v1.2.6 // indirect
|
github.com/klauspost/pgzip v1.2.6 // indirect
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||||
github.com/letsencrypt/boulder v0.0.0-20230907030200-6d76a0f91e1e // indirect
|
github.com/letsencrypt/boulder v0.0.0-20240418210053-89b07f4543e0 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
|
@ -158,8 +160,8 @@ require (
|
||||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||||
github.com/moby/sys/mountinfo v0.7.1 // indirect
|
github.com/moby/sys/mountinfo v0.7.2 // indirect
|
||||||
github.com/moby/sys/user v0.1.0 // indirect
|
github.com/moby/sys/user v0.2.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/oklog/ulid v1.3.1 // indirect
|
github.com/oklog/ulid v1.3.1 // indirect
|
||||||
|
|
@ -174,17 +176,17 @@ require (
|
||||||
github.com/proglottis/gpgme v0.1.3 // indirect
|
github.com/proglottis/gpgme v0.1.3 // indirect
|
||||||
github.com/prometheus/client_model v0.6.0 // indirect
|
github.com/prometheus/client_model v0.6.0 // indirect
|
||||||
github.com/prometheus/common v0.51.1 // indirect
|
github.com/prometheus/common v0.51.1 // indirect
|
||||||
github.com/prometheus/procfs v0.12.0 // indirect
|
github.com/prometheus/procfs v0.15.1 // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect
|
github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect
|
||||||
github.com/sigstore/fulcio v1.4.5 // indirect
|
github.com/sigstore/fulcio v1.4.5 // indirect
|
||||||
github.com/sigstore/rekor v1.3.6 // indirect
|
github.com/sigstore/rekor v1.3.6 // indirect
|
||||||
github.com/sigstore/sigstore v1.8.3 // indirect
|
github.com/sigstore/sigstore v1.8.4 // indirect
|
||||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
|
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
|
||||||
github.com/sony/gobreaker v0.4.2-0.20210216022020-dd874f9dd33b // indirect
|
github.com/sony/gobreaker v0.4.2-0.20210216022020-dd874f9dd33b // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 // indirect
|
github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 // indirect
|
||||||
github.com/sylabs/sif/v2 v2.16.0 // indirect
|
github.com/sylabs/sif/v2 v2.18.0 // indirect
|
||||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
|
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
|
||||||
github.com/tchap/go-patricia/v2 v2.3.1 // indirect
|
github.com/tchap/go-patricia/v2 v2.3.1 // indirect
|
||||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
|
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
|
||||||
|
|
@ -192,7 +194,7 @@ require (
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||||
github.com/vbatts/tar-split v0.11.5 // indirect
|
github.com/vbatts/tar-split v0.11.5 // indirect
|
||||||
github.com/vbauerster/mpb/v8 v8.7.3 // indirect
|
github.com/vbauerster/mpb/v8 v8.7.4 // indirect
|
||||||
go.mongodb.org/mongo-driver v1.14.0 // indirect
|
go.mongodb.org/mongo-driver v1.14.0 // indirect
|
||||||
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect
|
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect
|
||||||
go.opencensus.io v0.24.0 // indirect
|
go.opencensus.io v0.24.0 // indirect
|
||||||
|
|
@ -208,12 +210,11 @@ require (
|
||||||
golang.org/x/text v0.16.0 // indirect
|
golang.org/x/text v0.16.0 // indirect
|
||||||
golang.org/x/time v0.5.0 // indirect
|
golang.org/x/time v0.5.0 // indirect
|
||||||
golang.org/x/tools v0.23.0 // indirect
|
golang.org/x/tools v0.23.0 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20240722135656-d784300faade // indirect
|
google.golang.org/genproto v0.0.0-20240730163845-b1a4ccb954bf // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240722135656-d784300faade // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20240725223205-93522f1f2a9f // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240730163845-b1a4ccb954bf // indirect
|
||||||
google.golang.org/grpc v1.64.1 // indirect
|
google.golang.org/grpc v1.64.1 // indirect
|
||||||
google.golang.org/protobuf v1.34.2 // indirect
|
google.golang.org/protobuf v1.34.2 // indirect
|
||||||
gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect
|
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
|
|
||||||
127
go.sum
127
go.sum
|
|
@ -1,18 +1,18 @@
|
||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14=
|
cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14=
|
||||||
cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU=
|
cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU=
|
||||||
cloud.google.com/go/auth v0.7.2 h1:uiha352VrCDMXg+yoBtaD0tUF4Kv9vrtrWPYXwutnDE=
|
cloud.google.com/go/auth v0.7.3 h1:98Vr+5jMaCZ5NZk6e/uBgf60phTk/XN84r8QEWB9yjY=
|
||||||
cloud.google.com/go/auth v0.7.2/go.mod h1:VEc4p5NNxycWQTMQEDQF0bd6aTMb6VgYDXEwiJJQAbs=
|
cloud.google.com/go/auth v0.7.3/go.mod h1:HJtWUx1P5eqjy/f6Iq5KeytNpbAcGolPhOgyop2LlzA=
|
||||||
cloud.google.com/go/auth/oauth2adapt v0.2.3 h1:MlxF+Pd3OmSudg/b1yZ5lJwoXCEaeedAguodky1PcKI=
|
cloud.google.com/go/auth/oauth2adapt v0.2.3 h1:MlxF+Pd3OmSudg/b1yZ5lJwoXCEaeedAguodky1PcKI=
|
||||||
cloud.google.com/go/auth/oauth2adapt v0.2.3/go.mod h1:tMQXOfZzFuNuUxOypHlQEXgdfX5cuhwU+ffUuXRJE8I=
|
cloud.google.com/go/auth/oauth2adapt v0.2.3/go.mod h1:tMQXOfZzFuNuUxOypHlQEXgdfX5cuhwU+ffUuXRJE8I=
|
||||||
cloud.google.com/go/compute v1.27.4 h1:XM8ulx6crjdl09XBfji7viFgZOEQuIxBwKmjRH9Rtmc=
|
cloud.google.com/go/compute v1.27.4 h1:XM8ulx6crjdl09XBfji7viFgZOEQuIxBwKmjRH9Rtmc=
|
||||||
cloud.google.com/go/compute v1.27.4/go.mod h1:7JZS+h21ERAGHOy5qb7+EPyXlQwzshzrx1x6L9JhTqU=
|
cloud.google.com/go/compute v1.27.4/go.mod h1:7JZS+h21ERAGHOy5qb7+EPyXlQwzshzrx1x6L9JhTqU=
|
||||||
cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY=
|
cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY=
|
||||||
cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
|
cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
|
||||||
cloud.google.com/go/iam v1.1.10 h1:ZSAr64oEhQSClwBL670MsJAW5/RLiC6kfw3Bqmd5ZDI=
|
cloud.google.com/go/iam v1.1.12 h1:JixGLimRrNGcxvJEQ8+clfLxPlbeZA6MuRJ+qJNQ5Xw=
|
||||||
cloud.google.com/go/iam v1.1.10/go.mod h1:iEgMq62sg8zx446GCaijmA2Miwg5o3UbO+nI47WHJps=
|
cloud.google.com/go/iam v1.1.12/go.mod h1:9LDX8J7dN5YRyzVHxwQzrQs9opFFqn0Mxs9nAeB+Hhg=
|
||||||
cloud.google.com/go/longrunning v0.5.9 h1:haH9pAuXdPAMqHvzX0zlWQigXT7B0+CL4/2nXXdBo5k=
|
cloud.google.com/go/longrunning v0.5.11 h1:Havn1kGjz3whCfoD8dxMLP73Ph5w+ODyZB9RUsDxtGk=
|
||||||
cloud.google.com/go/longrunning v0.5.9/go.mod h1:HD+0l9/OOW0za6UWdKJtXoFAX/BGg/3Wj8p10NeWF7c=
|
cloud.google.com/go/longrunning v0.5.11/go.mod h1:rDn7//lmlfWV1Dx6IB4RatCPenTwwmqXuiP0/RgoEO4=
|
||||||
cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs=
|
cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs=
|
||||||
cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0=
|
cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0=
|
||||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||||
|
|
@ -76,16 +76,16 @@ github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2
|
||||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||||
github.com/Microsoft/hcsshim v0.12.3 h1:LS9NXqXhMoqNCplK1ApmVSfB4UnVLRDWRapB6EIlxE0=
|
github.com/Microsoft/hcsshim v0.12.5 h1:bpTInLlDy/nDRWFVcefDZZ1+U8tS+rz3MxjKgu9boo0=
|
||||||
github.com/Microsoft/hcsshim v0.12.3/go.mod h1:Iyl1WVpZzr+UkzjekHZbV8o5Z9ZkxNGx6CtY2Qg/JVQ=
|
github.com/Microsoft/hcsshim v0.12.5/go.mod h1:tIUGego4G1EN5Hb6KC90aDYiUI2dqLSTTOCjVNpOgZ8=
|
||||||
github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
|
github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
|
||||||
github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
|
github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
|
||||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
|
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
|
||||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
|
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||||
github.com/aws/aws-sdk-go v1.55.2 h1:/2OFM8uFfK9e+cqHTw9YPrvTzIXT2XkFGXRM7WbJb7E=
|
github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU=
|
||||||
github.com/aws/aws-sdk-go v1.55.2/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
|
github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
|
||||||
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
||||||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
|
@ -107,16 +107,16 @@ github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
github.com/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G/ZW/0kEe2oEKCdS/ZxIyoCU=
|
github.com/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G/ZW/0kEe2oEKCdS/ZxIyoCU=
|
||||||
github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk=
|
github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk=
|
||||||
github.com/containers/common v0.59.2 h1:FcURZzlMYMVZXqjMEop6C0A3yWilrfmWUPUw09APHvI=
|
github.com/containers/common v0.60.0 h1:QMNygqiiit9LU/yqee9Dv0N0oQ+rQq41ElfdOBQtw7w=
|
||||||
github.com/containers/common v0.59.2/go.mod h1:/PHpbapKSHQU29Jmjn3Ld3jekoHvX0zx7qQxxyPqSTM=
|
github.com/containers/common v0.60.0/go.mod h1:dtKVe11xkV89tqzRX9s/B0ORjeB2dy5UB46aGjunMn8=
|
||||||
github.com/containers/image/v5 v5.31.1 h1:3x9soI6Biml/GiDLpkSmKrkRSwVGctxu/vONpoUdklA=
|
github.com/containers/image/v5 v5.32.0 h1:yjbweazPfr8xOzQ2hkkYm1A2V0jN96/kES6Gwyxj7hQ=
|
||||||
github.com/containers/image/v5 v5.31.1/go.mod h1:5QfOqSackPkSbF7Qxc1DnVNnPJKQ+KWLkfEfDpK590Q=
|
github.com/containers/image/v5 v5.32.0/go.mod h1:x5e0RDfGaY6bnQ13gJ2LqbfHvzssfB/y5a8HduGFxJc=
|
||||||
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA=
|
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA=
|
||||||
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
|
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
|
||||||
github.com/containers/ocicrypt v1.1.10 h1:r7UR6o8+lyhkEywetubUUgcKFjOWOaWz8cEBrCPX0ic=
|
github.com/containers/ocicrypt v1.2.0 h1:X14EgRK3xNFvJEfI5O4Qn4T3E25ANudSOZz/sirVuPM=
|
||||||
github.com/containers/ocicrypt v1.1.10/go.mod h1:YfzSSr06PTHQwSTUKqDSjish9BeW1E4HUmreluQcMd8=
|
github.com/containers/ocicrypt v1.2.0/go.mod h1:ZNviigQajtdlxIZGibvblVuIFBKIuUI2M0QM12SD31U=
|
||||||
github.com/containers/storage v1.54.0 h1:xwYAlf6n9OnIlURQLLg3FYHbO74fQ/2W2N6EtQEUM4I=
|
github.com/containers/storage v1.55.0 h1:wTWZ3YpcQf1F+dSP4KxG9iqDfpQY1otaUXjPpffuhgg=
|
||||||
github.com/containers/storage v1.54.0/go.mod h1:PlMOoinRrBSnhYODLxt4EXl0nmJt+X0kjG0Xdt9fMTw=
|
github.com/containers/storage v1.55.0/go.mod h1:28cB81IDk+y7ok60Of6u52RbCeBRucbFOeLunhER1RQ=
|
||||||
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
|
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
|
||||||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
|
|
@ -129,8 +129,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
|
||||||
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
|
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
|
||||||
github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f h1:eHnXnuK47UlSTOQexbzxAZfekVz6i+LKRdj1CU5DPaM=
|
github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f h1:eHnXnuK47UlSTOQexbzxAZfekVz6i+LKRdj1CU5DPaM=
|
||||||
github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw=
|
github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw=
|
||||||
github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo=
|
github.com/cyphar/filepath-securejoin v0.3.1 h1:1V7cHiaW+C+39wEfpH6XlLBQo3j/PciWFrgfCLS8XrE=
|
||||||
github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
github.com/cyphar/filepath-securejoin v0.3.1/go.mod h1:F7i41x/9cBF7lzCrVsYs9fuzwRZm4NQsGTBdpp6mETc=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
|
|
@ -142,14 +142,14 @@ github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi
|
||||||
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
|
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
|
||||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||||
github.com/docker/cli v26.1.3+incompatible h1:bUpXT/N0kDE3VUHI2r5VMsYQgi38kYuoC0oL9yt3lqc=
|
github.com/docker/cli v27.1.1+incompatible h1:goaZxOqs4QKxznZjjBWKONQci/MywhtRv2oNn0GkeZE=
|
||||||
github.com/docker/cli v26.1.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
github.com/docker/cli v27.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
github.com/docker/docker v26.1.3+incompatible h1:lLCzRbrVZrljpVNobJu1J2FHk8V0s4BawoZippkc+xo=
|
github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY=
|
||||||
github.com/docker/docker v26.1.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/docker-credential-helpers v0.8.1 h1:j/eKUktUltBtMzKqmfLB0PAgqYyMHOp5vfsD1807oKo=
|
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
|
||||||
github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
||||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||||
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
|
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
|
||||||
|
|
@ -178,8 +178,8 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
|
||||||
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
|
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
|
||||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||||
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||||
github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k=
|
github.com/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk=
|
||||||
github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
|
github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
|
||||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
|
|
@ -254,11 +254,10 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-containerregistry v0.19.1 h1:yMQ62Al6/V0Z7CqIrrS1iYoA5/oQCm88DeNujc7C1KY=
|
github.com/google/go-containerregistry v0.20.0 h1:wRqHpOeVh3DnenOrPy9xDOLdnLatiGuuNRVelR2gSbg=
|
||||||
github.com/google/go-containerregistry v0.19.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI=
|
github.com/google/go-containerregistry v0.20.0/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI=
|
||||||
github.com/google/go-intervals v0.0.2 h1:FGrVEiUnTRKR8yE04qzXYaJMtnIYqobR5QbblK3ixcM=
|
github.com/google/go-intervals v0.0.2 h1:FGrVEiUnTRKR8yE04qzXYaJMtnIYqobR5QbblK3ixcM=
|
||||||
github.com/google/go-intervals v0.0.2/go.mod h1:MkaR3LNRfeKLPmqgJYs4E66z5InYjmCjbbr4TQlcT6Y=
|
github.com/google/go-intervals v0.0.2/go.mod h1:MkaR3LNRfeKLPmqgJYs4E66z5InYjmCjbbr4TQlcT6Y=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
|
@ -267,8 +266,8 @@ github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1
|
||||||
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
|
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
|
||||||
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
|
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
|
github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM=
|
||||||
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
|
github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
|
@ -370,8 +369,8 @@ github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4d
|
||||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||||
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||||
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
|
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
|
||||||
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||||
github.com/kolo/xmlrpc v0.0.0-20201022064351-38db28db192b h1:iNjcivnc6lhbvJA3LD622NPrUponluJrBWPIwGG/3Bg=
|
github.com/kolo/xmlrpc v0.0.0-20201022064351-38db28db192b h1:iNjcivnc6lhbvJA3LD622NPrUponluJrBWPIwGG/3Bg=
|
||||||
|
|
@ -394,8 +393,8 @@ github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0Sh
|
||||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||||
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
||||||
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
||||||
github.com/letsencrypt/boulder v0.0.0-20230907030200-6d76a0f91e1e h1:RLTpX495BXToqxpM90Ws4hXEo4Wfh81jr9DX1n/4WOo=
|
github.com/letsencrypt/boulder v0.0.0-20240418210053-89b07f4543e0 h1:aiPrFdHDCCvigNBCkOWj2lv9Bx5xDp210OANZEoiP0I=
|
||||||
github.com/letsencrypt/boulder v0.0.0-20230907030200-6d76a0f91e1e/go.mod h1:EAuqr9VFWxBi9nD5jc/EA2MT1RFty9288TF6zdtYoCU=
|
github.com/letsencrypt/boulder v0.0.0-20240418210053-89b07f4543e0/go.mod h1:srVwm2N3DC/tWqQ+igZXDrmKlNRN8X/dmJ1wEZrv760=
|
||||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
|
|
@ -438,10 +437,10 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua
|
||||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||||
github.com/moby/sys/mountinfo v0.7.1 h1:/tTvQaSJRr2FshkhXiIpux6fQ2Zvc4j7tAhMTStAG2g=
|
github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
|
||||||
github.com/moby/sys/mountinfo v0.7.1/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
|
github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4=
|
||||||
github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg=
|
github.com/moby/sys/user v0.2.0 h1:OnpapJsRp25vkhw8TFG6OLJODNh/3rEwRWtJ3kakwRM=
|
||||||
github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
|
github.com/moby/sys/user v0.2.0/go.mod h1:RYstrcWOJpVh+6qzUqp2bU3eaRpdiQeKGlKitaH0PM8=
|
||||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
|
@ -453,8 +452,8 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
|
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/onsi/ginkgo/v2 v2.18.0 h1:W9Y7IWXxPUpAit9ieMOLI7PJZGaW22DTKgiVAuhDTLc=
|
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
|
||||||
github.com/onsi/ginkgo/v2 v2.18.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
|
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
|
||||||
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
|
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
|
||||||
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
|
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
|
||||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
|
|
@ -469,8 +468,8 @@ github.com/openshift-online/ocm-sdk-go v0.1.432 h1:XIlCJKxXXznMP5Usu9lVGZa+UTYVl
|
||||||
github.com/openshift-online/ocm-sdk-go v0.1.432/go.mod h1:CiAu2jwl3ITKOxkeV0Qnhzv4gs35AmpIzVABQLtcI2Y=
|
github.com/openshift-online/ocm-sdk-go v0.1.432/go.mod h1:CiAu2jwl3ITKOxkeV0Qnhzv4gs35AmpIzVABQLtcI2Y=
|
||||||
github.com/oracle/oci-go-sdk/v54 v54.0.0 h1:CDLjeSejv2aDpElAJrhKpi6zvT/zhZCZuXchUUZ+LS4=
|
github.com/oracle/oci-go-sdk/v54 v54.0.0 h1:CDLjeSejv2aDpElAJrhKpi6zvT/zhZCZuXchUUZ+LS4=
|
||||||
github.com/oracle/oci-go-sdk/v54 v54.0.0/go.mod h1:+t+yvcFGVp+3ZnztnyxqXfQDsMlq8U25faBLa+mqCMc=
|
github.com/oracle/oci-go-sdk/v54 v54.0.0/go.mod h1:+t+yvcFGVp+3ZnztnyxqXfQDsMlq8U25faBLa+mqCMc=
|
||||||
github.com/osbuild/images v0.72.0 h1:WKRXokWCpkS6zusc2yadXbW5jQD4cNvBMHZUV/8L4jM=
|
github.com/osbuild/images v0.74.0 h1:V3biAGZ+9z10DnCJAMXYalIlcVLmWNMiaZXSHwl+N5s=
|
||||||
github.com/osbuild/images v0.72.0/go.mod h1:McWtOOsi/2gH2J4tQ8Vnvg+O3jVf44XIj3jUWJZt47E=
|
github.com/osbuild/images v0.74.0/go.mod h1:DTCMxDrZSkrgQdz+Kda+rSvCXk1453lNMupBFIE+3d8=
|
||||||
github.com/osbuild/osbuild-composer/pkg/splunk_logger v0.0.0-20231117174845-e969a9dc3cd1 h1:UFEJIcPa46W8gtWgOYzriRKYyy1t6SWL0BI7fPTuVvc=
|
github.com/osbuild/osbuild-composer/pkg/splunk_logger v0.0.0-20231117174845-e969a9dc3cd1 h1:UFEJIcPa46W8gtWgOYzriRKYyy1t6SWL0BI7fPTuVvc=
|
||||||
github.com/osbuild/osbuild-composer/pkg/splunk_logger v0.0.0-20231117174845-e969a9dc3cd1/go.mod h1:z+WA+dX6qMwc7fqY5jCzESDIlg4WR2sBQezxsoXv9Ik=
|
github.com/osbuild/osbuild-composer/pkg/splunk_logger v0.0.0-20231117174845-e969a9dc3cd1/go.mod h1:z+WA+dX6qMwc7fqY5jCzESDIlg4WR2sBQezxsoXv9Ik=
|
||||||
github.com/osbuild/pulp-client v0.1.0 h1:L0C4ezBJGTamN3BKdv+rKLuq/WxXJbsFwz/Hj7aEmJ8=
|
github.com/osbuild/pulp-client v0.1.0 h1:L0C4ezBJGTamN3BKdv+rKLuq/WxXJbsFwz/Hj7aEmJ8=
|
||||||
|
|
@ -496,8 +495,8 @@ github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZ
|
||||||
github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
|
github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
|
||||||
github.com/prometheus/common v0.51.1 h1:eIjN50Bwglz6a/c3hAgSMcofL3nD+nFQkV6Dd4DsQCw=
|
github.com/prometheus/common v0.51.1 h1:eIjN50Bwglz6a/c3hAgSMcofL3nD+nFQkV6Dd4DsQCw=
|
||||||
github.com/prometheus/common v0.51.1/go.mod h1:lrWtQx+iDfn2mbH5GUzlH9TSHyfZpHkSiG1W7y3sF2Q=
|
github.com/prometheus/common v0.51.1/go.mod h1:lrWtQx+iDfn2mbH5GUzlH9TSHyfZpHkSiG1W7y3sF2Q=
|
||||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
|
@ -524,8 +523,8 @@ github.com/sigstore/fulcio v1.4.5 h1:WWNnrOknD0DbruuZWCbN+86WRROpEl3Xts+WT2Ek1yc
|
||||||
github.com/sigstore/fulcio v1.4.5/go.mod h1:oz3Qwlma8dWcSS/IENR/6SjbW4ipN0cxpRVfgdsjMU8=
|
github.com/sigstore/fulcio v1.4.5/go.mod h1:oz3Qwlma8dWcSS/IENR/6SjbW4ipN0cxpRVfgdsjMU8=
|
||||||
github.com/sigstore/rekor v1.3.6 h1:QvpMMJVWAp69a3CHzdrLelqEqpTM3ByQRt5B5Kspbi8=
|
github.com/sigstore/rekor v1.3.6 h1:QvpMMJVWAp69a3CHzdrLelqEqpTM3ByQRt5B5Kspbi8=
|
||||||
github.com/sigstore/rekor v1.3.6/go.mod h1:JDTSNNMdQ/PxdsS49DJkJ+pRJCO/83nbR5p3aZQteXc=
|
github.com/sigstore/rekor v1.3.6/go.mod h1:JDTSNNMdQ/PxdsS49DJkJ+pRJCO/83nbR5p3aZQteXc=
|
||||||
github.com/sigstore/sigstore v1.8.3 h1:G7LVXqL+ekgYtYdksBks9B38dPoIsbscjQJX/MGWkA4=
|
github.com/sigstore/sigstore v1.8.4 h1:g4ICNpiENFnWxjmBzBDWUn62rNFeny/P77HUC8da32w=
|
||||||
github.com/sigstore/sigstore v1.8.3/go.mod h1:mqbTEariiGA94cn6G3xnDiV6BD8eSLdL/eA7bvJ0fVs=
|
github.com/sigstore/sigstore v1.8.4/go.mod h1:1jIKtkTFEeISen7en+ZPWdDHazqhxco/+v9CNjc7oNg=
|
||||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
|
|
@ -558,8 +557,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/sylabs/sif/v2 v2.16.0 h1:2eqaBaQQsn5DZTzm3QZm0HupZQEjNXfxRnCmtyCihEU=
|
github.com/sylabs/sif/v2 v2.18.0 h1:eXugsS1qx7St2Wu/AJ21KnsQiVCpouPlTigABh+6KYI=
|
||||||
github.com/sylabs/sif/v2 v2.16.0/go.mod h1:d5TxgD/mhMUU3kWLmZmWJQ99Wg0asaTP0bq3ezR1xpg=
|
github.com/sylabs/sif/v2 v2.18.0/go.mod h1:GOQj7LIBqp15fjqH5i8ZEbLp8SXJi9S+xbRO+QQAdRo=
|
||||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
|
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
|
||||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||||
github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes=
|
github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes=
|
||||||
|
|
@ -578,8 +577,8 @@ github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQ
|
||||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||||
github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts=
|
github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts=
|
||||||
github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk=
|
github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk=
|
||||||
github.com/vbauerster/mpb/v8 v8.7.3 h1:n/mKPBav4FFWp5fH4U0lPpXfiOmCEgl5Yx/NM3tKJA0=
|
github.com/vbauerster/mpb/v8 v8.7.4 h1:p4f16iMfUt3PkAC73SCzAtgtSf8TYDqEbJUT3odPrPo=
|
||||||
github.com/vbauerster/mpb/v8 v8.7.3/go.mod h1:9nFlNpDGVoTmQ4QvNjSLtwLmAFjwmq0XaAF26toHGNM=
|
github.com/vbauerster/mpb/v8 v8.7.4/go.mod h1:r1B5k2Ljj5KJFCekfihbiqyV4VaaRTANYmvWA2btufI=
|
||||||
github.com/vmware/govmomi v0.39.0 h1:soLZ08Q2zvjRSinNup8xVlw0KDDCJPPA1rIDmBhi7As=
|
github.com/vmware/govmomi v0.39.0 h1:soLZ08Q2zvjRSinNup8xVlw0KDDCJPPA1rIDmBhi7As=
|
||||||
github.com/vmware/govmomi v0.39.0/go.mod h1:oHzAQ1r6152zYDGcUqeK+EO8LhKo5wjtvWZBGHws2Hc=
|
github.com/vmware/govmomi v0.39.0/go.mod h1:oHzAQ1r6152zYDGcUqeK+EO8LhKo5wjtvWZBGHws2Hc=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||||
|
|
@ -648,8 +647,8 @@ golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZP
|
||||||
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
||||||
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
|
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
|
@ -774,19 +773,19 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/api v0.189.0 h1:equMo30LypAkdkLMBqfeIqtyAnlyig1JSZArl4XPwdI=
|
google.golang.org/api v0.190.0 h1:ASM+IhLY1zljNdLu19W1jTmU6A+gMk6M46Wlur61s+Q=
|
||||||
google.golang.org/api v0.189.0/go.mod h1:FLWGJKb0hb+pU2j+rJqwbnsF+ym+fQs73rbJ+KAUgy8=
|
google.golang.org/api v0.190.0/go.mod h1:QIr6I9iedBLnfqoD6L6Vze1UvS5Hzj5r2aUBOaZnLHo=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
google.golang.org/genproto v0.0.0-20240722135656-d784300faade h1:lKFsS7wpngDgSCeFn7MoLy+wBDQZ1UQIJD4UNM1Qvkg=
|
google.golang.org/genproto v0.0.0-20240730163845-b1a4ccb954bf h1:OqdXDEakZCVtDiZTjcxfwbHPCT11ycCEsTKesBVKvyY=
|
||||||
google.golang.org/genproto v0.0.0-20240722135656-d784300faade/go.mod h1:FfBgJBJg9GcpPvKIuHSZ/aE1g2ecGL74upMzGZjiGEY=
|
google.golang.org/genproto v0.0.0-20240730163845-b1a4ccb954bf/go.mod h1:mCr1K1c8kX+1iSBREvU3Juo11CB+QOEWxbRS01wWl5M=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240722135656-d784300faade h1:WxZOF2yayUHpHSbUE6NMzumUzBxYc3YGwo0YHnbzsJY=
|
google.golang.org/genproto/googleapis/api v0.0.0-20240725223205-93522f1f2a9f h1:b1Ln/PG8orm0SsBbHZWke8dDp2lrCD4jSmfglFpTZbk=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240722135656-d784300faade/go.mod h1:mw8MG/Qz5wfgYr6VqVCiZcHe/GJEfI+oGGDCohaVgB0=
|
google.golang.org/genproto/googleapis/api v0.0.0-20240725223205-93522f1f2a9f/go.mod h1:AHT0dDg3SoMOgZGnZk29b5xTbPHMoEC8qthmBLJCpys=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade h1:oCRSWfwGXQsqlVdErcyTt4A93Y8fo0/9D4b1gnI++qo=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240730163845-b1a4ccb954bf h1:liao9UHurZLtiEwBgT9LMOnKYsHze6eA6w1KQCMVN2Q=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240730163845-b1a4ccb954bf/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
|
|
@ -810,8 +809,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs=
|
|
||||||
gopkg.in/go-jose/go-jose.v2 v2.6.3/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI=
|
|
||||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
|
|
||||||
9
vendor/cloud.google.com/go/auth/CHANGES.md
generated
vendored
9
vendor/cloud.google.com/go/auth/CHANGES.md
generated
vendored
|
|
@ -1,5 +1,14 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [0.7.3](https://github.com/googleapis/google-cloud-go/compare/auth/v0.7.2...auth/v0.7.3) (2024-08-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth/oauth2adapt:** Update dependencies ([257c40b](https://github.com/googleapis/google-cloud-go/commit/257c40bd6d7e59730017cf32bda8823d7a232758))
|
||||||
|
* **auth:** Disable automatic universe domain check for MDS ([#10620](https://github.com/googleapis/google-cloud-go/issues/10620)) ([7cea5ed](https://github.com/googleapis/google-cloud-go/commit/7cea5edd5a0c1e6bca558696f5607879141910e8))
|
||||||
|
* **auth:** Update dependencies ([257c40b](https://github.com/googleapis/google-cloud-go/commit/257c40bd6d7e59730017cf32bda8823d7a232758))
|
||||||
|
|
||||||
## [0.7.2](https://github.com/googleapis/google-cloud-go/compare/auth/v0.7.1...auth/v0.7.2) (2024-07-22)
|
## [0.7.2](https://github.com/googleapis/google-cloud-go/compare/auth/v0.7.1...auth/v0.7.2) (2024-07-22)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
14
vendor/cloud.google.com/go/auth/auth.go
generated
vendored
14
vendor/cloud.google.com/go/auth/auth.go
generated
vendored
|
|
@ -101,6 +101,20 @@ func (t *Token) IsValid() bool {
|
||||||
return t.isValidWithEarlyExpiry(defaultExpiryDelta)
|
return t.isValidWithEarlyExpiry(defaultExpiryDelta)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MetadataString is a convenience method for accessing string values in the
|
||||||
|
// token's metadata. Returns an empty string if the metadata is nil or the value
|
||||||
|
// for the given key cannot be cast to a string.
|
||||||
|
func (t *Token) MetadataString(k string) string {
|
||||||
|
if t.Metadata == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
s, ok := t.Metadata[k].(string)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Token) isValidWithEarlyExpiry(earlyExpiry time.Duration) bool {
|
func (t *Token) isValidWithEarlyExpiry(earlyExpiry time.Duration) bool {
|
||||||
if t.isEmpty() {
|
if t.isEmpty() {
|
||||||
return false
|
return false
|
||||||
|
|
|
||||||
4
vendor/cloud.google.com/go/auth/grpctransport/directpath.go
generated
vendored
4
vendor/cloud.google.com/go/auth/grpctransport/directpath.go
generated
vendored
|
|
@ -66,10 +66,10 @@ func isTokenProviderDirectPathCompatible(tp auth.TokenProvider, _ *Options) bool
|
||||||
if tok == nil {
|
if tok == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if source, _ := tok.Metadata["auth.google.tokenSource"].(string); source != "compute-metadata" {
|
if tok.MetadataString("auth.google.tokenSource") != "compute-metadata" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if acct, _ := tok.Metadata["auth.google.serviceAccount"].(string); acct != "default" {
|
if tok.MetadataString("auth.google.serviceAccount") != "default" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
|
||||||
16
vendor/cloud.google.com/go/auth/grpctransport/grpctransport.go
generated
vendored
16
vendor/cloud.google.com/go/auth/grpctransport/grpctransport.go
generated
vendored
|
|
@ -337,17 +337,19 @@ func (c *grpcCredentialsProvider) getClientUniverseDomain() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *grpcCredentialsProvider) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
|
func (c *grpcCredentialsProvider) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
|
||||||
credentialsUniverseDomain, err := c.creds.UniverseDomain(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := transport.ValidateUniverseDomain(c.getClientUniverseDomain(), credentialsUniverseDomain); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
token, err := c.creds.Token(ctx)
|
token, err := c.creds.Token(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if token.MetadataString("auth.google.tokenSource") != "compute-metadata" {
|
||||||
|
credentialsUniverseDomain, err := c.creds.UniverseDomain(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := transport.ValidateUniverseDomain(c.getClientUniverseDomain(), credentialsUniverseDomain); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
if c.secure {
|
if c.secure {
|
||||||
ri, _ := grpccreds.RequestInfoFromContext(ctx)
|
ri, _ := grpccreds.RequestInfoFromContext(ctx)
|
||||||
if err = grpccreds.CheckSecurityLevel(ri.AuthInfo, grpccreds.PrivacyAndIntegrity); err != nil {
|
if err = grpccreds.CheckSecurityLevel(ri.AuthInfo, grpccreds.PrivacyAndIntegrity); err != nil {
|
||||||
|
|
|
||||||
16
vendor/cloud.google.com/go/auth/httptransport/transport.go
generated
vendored
16
vendor/cloud.google.com/go/auth/httptransport/transport.go
generated
vendored
|
|
@ -193,17 +193,19 @@ func (t *authTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
credentialsUniverseDomain, err := t.creds.UniverseDomain(req.Context())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := transport.ValidateUniverseDomain(t.getClientUniverseDomain(), credentialsUniverseDomain); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
token, err := t.creds.Token(req.Context())
|
token, err := t.creds.Token(req.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if token.MetadataString("auth.google.tokenSource") != "compute-metadata" {
|
||||||
|
credentialsUniverseDomain, err := t.creds.UniverseDomain(req.Context())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := transport.ValidateUniverseDomain(t.getClientUniverseDomain(), credentialsUniverseDomain); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
req2 := req.Clone(req.Context())
|
req2 := req.Clone(req.Context())
|
||||||
SetAuthHeader(token, req2)
|
SetAuthHeader(token, req2)
|
||||||
reqBodyClosed = true
|
reqBodyClosed = true
|
||||||
|
|
|
||||||
14
vendor/cloud.google.com/go/iam/CHANGES.md
generated
vendored
14
vendor/cloud.google.com/go/iam/CHANGES.md
generated
vendored
|
|
@ -1,6 +1,20 @@
|
||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
|
|
||||||
|
## [1.1.12](https://github.com/googleapis/google-cloud-go/compare/iam/v1.1.11...iam/v1.1.12) (2024-07-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **iam:** Update dependencies ([257c40b](https://github.com/googleapis/google-cloud-go/commit/257c40bd6d7e59730017cf32bda8823d7a232758))
|
||||||
|
|
||||||
|
## [1.1.11](https://github.com/googleapis/google-cloud-go/compare/iam/v1.1.10...iam/v1.1.11) (2024-07-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **iam:** Bump google.golang.org/grpc@v1.64.1 ([8ecc4e9](https://github.com/googleapis/google-cloud-go/commit/8ecc4e9622e5bbe9b90384d5848ab816027226c5))
|
||||||
|
|
||||||
## [1.1.10](https://github.com/googleapis/google-cloud-go/compare/iam/v1.1.9...iam/v1.1.10) (2024-07-01)
|
## [1.1.10](https://github.com/googleapis/google-cloud-go/compare/iam/v1.1.9...iam/v1.1.10) (2024-07-01)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
46
vendor/github.com/Microsoft/hcsshim/hnsaccelnet.go
generated
vendored
Normal file
46
vendor/github.com/Microsoft/hcsshim/hnsaccelnet.go
generated
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package hcsshim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HNSNnvManagementMacAddress represents management mac address
|
||||||
|
// which needs to be excluded from VF reassignment
|
||||||
|
type HNSNnvManagementMacAddress = hns.HNSNnvManagementMacAddress
|
||||||
|
|
||||||
|
// HNSNnvManagementMacList represents a list of management
|
||||||
|
// mac addresses for exclusion from VF reassignment
|
||||||
|
type HNSNnvManagementMacList = hns.HNSNnvManagementMacList
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrorEmptyMacAddressList = errors.New("management mac_address list is empty")
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetNnvManagementMacAddresses sets a list of
|
||||||
|
// management mac addresses in hns for exclusion from VF reassignment.
|
||||||
|
func SetNnvManagementMacAddresses(managementMacAddresses []string) (*HNSNnvManagementMacList, error) {
|
||||||
|
if len(managementMacAddresses) == 0 {
|
||||||
|
return nil, ErrorEmptyMacAddressList
|
||||||
|
}
|
||||||
|
nnvManagementMacList := &HNSNnvManagementMacList{}
|
||||||
|
for _, mac := range managementMacAddresses {
|
||||||
|
nnvManagementMacList.MacAddressList = append(nnvManagementMacList.MacAddressList, HNSNnvManagementMacAddress{MacAddress: mac})
|
||||||
|
}
|
||||||
|
return nnvManagementMacList.Set()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNnvManagementMacAddresses retrieves a list of
|
||||||
|
// management mac addresses in hns for exclusion from VF reassignment.
|
||||||
|
func GetNnvManagementMacAddresses() (*HNSNnvManagementMacList, error) {
|
||||||
|
return hns.GetNnvManagementMacAddressList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteNnvManagementMacAddresses delete list of
|
||||||
|
// management mac addresses in hns which are excluded from VF reassignment.
|
||||||
|
func DeleteNnvManagementMacAddresses() (*HNSNnvManagementMacList, error) {
|
||||||
|
return hns.DeleteNnvManagementMacAddressList()
|
||||||
|
}
|
||||||
60
vendor/github.com/Microsoft/hcsshim/internal/hns/hnsaccelnet.go
generated
vendored
Normal file
60
vendor/github.com/Microsoft/hcsshim/internal/hns/hnsaccelnet.go
generated
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package hns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HNSNnvManagementMacAddress represents management mac address
|
||||||
|
// which needs to be excluded from VF reassignment
|
||||||
|
type HNSNnvManagementMacAddress struct {
|
||||||
|
MacAddress string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// HNSNnvManagementMacList represents a list of management
|
||||||
|
// mac addresses for exclusion from VF reassignment
|
||||||
|
type HNSNnvManagementMacList struct {
|
||||||
|
MacAddressList []HNSNnvManagementMacAddress `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// HNSNnvManagementMacRequest makes a HNS call to modify/query NnvManagementMacList
|
||||||
|
func HNSNnvManagementMacRequest(method, path, request string) (*HNSNnvManagementMacList, error) {
|
||||||
|
nnvManagementMacList := &HNSNnvManagementMacList{}
|
||||||
|
err := hnsCall(method, "/accelnet/"+path, request, &nnvManagementMacList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nnvManagementMacList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set ManagementMacAddressList by sending "POST" NnvManagementMacRequest to HNS.
|
||||||
|
func (nnvManagementMacList *HNSNnvManagementMacList) Set() (*HNSNnvManagementMacList, error) {
|
||||||
|
operation := "Set"
|
||||||
|
title := "hcsshim::nnvManagementMacList::" + operation
|
||||||
|
logrus.Debugf(title+" id=%s", nnvManagementMacList.MacAddressList)
|
||||||
|
|
||||||
|
jsonString, err := json.Marshal(nnvManagementMacList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return HNSNnvManagementMacRequest("POST", "", string(jsonString))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get ManagementMacAddressList by sending "GET" NnvManagementMacRequest to HNS.
|
||||||
|
func GetNnvManagementMacAddressList() (*HNSNnvManagementMacList, error) {
|
||||||
|
operation := "Get"
|
||||||
|
title := "hcsshim::nnvManagementMacList::" + operation
|
||||||
|
logrus.Debugf(title)
|
||||||
|
return HNSNnvManagementMacRequest("GET", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete ManagementMacAddressList by sending "DELETE" NnvManagementMacRequest to HNS.
|
||||||
|
func DeleteNnvManagementMacAddressList() (*HNSNnvManagementMacList, error) {
|
||||||
|
operation := "Delete"
|
||||||
|
title := "hcsshim::nnvManagementMacList::" + operation
|
||||||
|
logrus.Debugf(title)
|
||||||
|
return HNSNnvManagementMacRequest("DELETE", "", "")
|
||||||
|
}
|
||||||
23
vendor/github.com/Microsoft/hcsshim/internal/hns/hnsendpoint.go
generated
vendored
23
vendor/github.com/Microsoft/hcsshim/internal/hns/hnsendpoint.go
generated
vendored
|
|
@ -10,6 +10,28 @@ import (
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// EndpointState represents the states of an HNS Endpoint lifecycle.
|
||||||
|
type EndpointState uint16
|
||||||
|
|
||||||
|
// EndpointState const
|
||||||
|
// The lifecycle of an Endpoint goes through created, attached, AttachedSharing - endpoint is being shared with other containers,
|
||||||
|
// detached, after being attached, degraded and finally destroyed.
|
||||||
|
// Note: This attribute is used by calico to define stale containers and is dependent on HNS v1 api, if we move to HNS v2 api we will need
|
||||||
|
// to update the current calico code and cordinate the change with calico. Reach out to Microsoft to facilate the change via HNS.
|
||||||
|
const (
|
||||||
|
Uninitialized EndpointState = iota
|
||||||
|
Created EndpointState = 1
|
||||||
|
Attached EndpointState = 2
|
||||||
|
AttachedSharing EndpointState = 3
|
||||||
|
Detached EndpointState = 4
|
||||||
|
Degraded EndpointState = 5
|
||||||
|
Destroyed EndpointState = 6
|
||||||
|
)
|
||||||
|
|
||||||
|
func (es EndpointState) String() string {
|
||||||
|
return [...]string{"Uninitialized", "Attached", "AttachedSharing", "Detached", "Degraded", "Destroyed"}[es]
|
||||||
|
}
|
||||||
|
|
||||||
// HNSEndpoint represents a network endpoint in HNS
|
// HNSEndpoint represents a network endpoint in HNS
|
||||||
type HNSEndpoint struct {
|
type HNSEndpoint struct {
|
||||||
Id string `json:"ID,omitempty"`
|
Id string `json:"ID,omitempty"`
|
||||||
|
|
@ -34,6 +56,7 @@ type HNSEndpoint struct {
|
||||||
Namespace *Namespace `json:",omitempty"`
|
Namespace *Namespace `json:",omitempty"`
|
||||||
EncapOverhead uint16 `json:",omitempty"`
|
EncapOverhead uint16 `json:",omitempty"`
|
||||||
SharedContainers []string `json:",omitempty"`
|
SharedContainers []string `json:",omitempty"`
|
||||||
|
State EndpointState `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SystemType represents the type of the system on which actions are done
|
// SystemType represents the type of the system on which actions are done
|
||||||
|
|
|
||||||
7
vendor/github.com/Microsoft/hcsshim/internal/hns/hnspolicy.go
generated
vendored
7
vendor/github.com/Microsoft/hcsshim/internal/hns/hnspolicy.go
generated
vendored
|
|
@ -57,9 +57,10 @@ type PaPolicy struct {
|
||||||
|
|
||||||
type OutboundNatPolicy struct {
|
type OutboundNatPolicy struct {
|
||||||
Policy
|
Policy
|
||||||
VIP string `json:"VIP,omitempty"`
|
VIP string `json:"VIP,omitempty"`
|
||||||
Exceptions []string `json:"ExceptionList,omitempty"`
|
Exceptions []string `json:"ExceptionList,omitempty"`
|
||||||
Destinations []string `json:",omitempty"`
|
Destinations []string `json:",omitempty"`
|
||||||
|
MaxPortPoolUsage uint16 `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProxyPolicy struct {
|
type ProxyPolicy struct {
|
||||||
|
|
|
||||||
9
vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go
generated
vendored
9
vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go
generated
vendored
|
|
@ -9503,6 +9503,12 @@ var awsPartition = partition{
|
||||||
endpointKey{
|
endpointKey{
|
||||||
Region: "eu-central-1",
|
Region: "eu-central-1",
|
||||||
}: endpoint{},
|
}: endpoint{},
|
||||||
|
endpointKey{
|
||||||
|
Region: "eu-north-1",
|
||||||
|
}: endpoint{},
|
||||||
|
endpointKey{
|
||||||
|
Region: "eu-south-2",
|
||||||
|
}: endpoint{},
|
||||||
endpointKey{
|
endpointKey{
|
||||||
Region: "eu-west-1",
|
Region: "eu-west-1",
|
||||||
}: endpoint{},
|
}: endpoint{},
|
||||||
|
|
@ -32566,6 +32572,9 @@ var awsPartition = partition{
|
||||||
endpointKey{
|
endpointKey{
|
||||||
Region: "ca-central-1",
|
Region: "ca-central-1",
|
||||||
}: endpoint{},
|
}: endpoint{},
|
||||||
|
endpointKey{
|
||||||
|
Region: "ca-west-1",
|
||||||
|
}: endpoint{},
|
||||||
endpointKey{
|
endpointKey{
|
||||||
Region: "eu-central-1",
|
Region: "eu-central-1",
|
||||||
}: endpoint{},
|
}: endpoint{},
|
||||||
|
|
|
||||||
2
vendor/github.com/aws/aws-sdk-go/aws/version.go
generated
vendored
2
vendor/github.com/aws/aws-sdk-go/aws/version.go
generated
vendored
|
|
@ -5,4 +5,4 @@ package aws
|
||||||
const SDKName = "aws-sdk-go"
|
const SDKName = "aws-sdk-go"
|
||||||
|
|
||||||
// SDKVersion is the version of this SDK
|
// SDKVersion is the version of this SDK
|
||||||
const SDKVersion = "1.55.2"
|
const SDKVersion = "1.55.5"
|
||||||
|
|
|
||||||
106
vendor/github.com/aws/aws-sdk-go/service/ec2/api.go
generated
vendored
106
vendor/github.com/aws/aws-sdk-go/service/ec2/api.go
generated
vendored
|
|
@ -124700,9 +124700,38 @@ type FleetLaunchTemplateOverrides struct {
|
||||||
// The Availability Zone in which to launch the instances.
|
// The Availability Zone in which to launch the instances.
|
||||||
AvailabilityZone *string `locationName:"availabilityZone" type:"string"`
|
AvailabilityZone *string `locationName:"availabilityZone" type:"string"`
|
||||||
|
|
||||||
// The ID of the AMI. An AMI is required to launch an instance. This parameter
|
// The ID of the AMI in the format ami-17characters00000.
|
||||||
// is only available for fleets of type instant. For fleets of type maintain
|
//
|
||||||
// and request, you must specify the AMI ID in the launch template.
|
// Alternatively, you can specify a Systems Manager parameter, using one of
|
||||||
|
// the following formats. The Systems Manager parameter will resolve to an AMI
|
||||||
|
// ID on launch.
|
||||||
|
//
|
||||||
|
// To reference a public parameter:
|
||||||
|
//
|
||||||
|
// * resolve:ssm:public-parameter
|
||||||
|
//
|
||||||
|
// To reference a parameter stored in the same account:
|
||||||
|
//
|
||||||
|
// * resolve:ssm:parameter-name
|
||||||
|
//
|
||||||
|
// * resolve:ssm:parameter-name:version-number
|
||||||
|
//
|
||||||
|
// * resolve:ssm:parameter-name:label
|
||||||
|
//
|
||||||
|
// To reference a parameter shared from another Amazon Web Services account:
|
||||||
|
//
|
||||||
|
// * resolve:ssm:parameter-ARN
|
||||||
|
//
|
||||||
|
// * resolve:ssm:parameter-ARN:version-number
|
||||||
|
//
|
||||||
|
// * resolve:ssm:parameter-ARN:label
|
||||||
|
//
|
||||||
|
// For more information, see Use a Systems Manager parameter instead of an AMI
|
||||||
|
// ID (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/create-launch-template.html#use-an-ssm-parameter-instead-of-an-ami-id)
|
||||||
|
// in the Amazon EC2 User Guide.
|
||||||
|
//
|
||||||
|
// This parameter is only available for fleets of type instant. For fleets of
|
||||||
|
// type maintain and request, you must specify the AMI ID in the launch template.
|
||||||
ImageId *string `locationName:"imageId" type:"string"`
|
ImageId *string `locationName:"imageId" type:"string"`
|
||||||
|
|
||||||
// The attributes for the instance types. When you specify instance attributes,
|
// The attributes for the instance types. When you specify instance attributes,
|
||||||
|
|
@ -124845,9 +124874,38 @@ type FleetLaunchTemplateOverridesRequest struct {
|
||||||
// The Availability Zone in which to launch the instances.
|
// The Availability Zone in which to launch the instances.
|
||||||
AvailabilityZone *string `type:"string"`
|
AvailabilityZone *string `type:"string"`
|
||||||
|
|
||||||
// The ID of the AMI. An AMI is required to launch an instance. This parameter
|
// The ID of the AMI in the format ami-17characters00000.
|
||||||
// is only available for fleets of type instant. For fleets of type maintain
|
//
|
||||||
// and request, you must specify the AMI ID in the launch template.
|
// Alternatively, you can specify a Systems Manager parameter, using one of
|
||||||
|
// the following formats. The Systems Manager parameter will resolve to an AMI
|
||||||
|
// ID on launch.
|
||||||
|
//
|
||||||
|
// To reference a public parameter:
|
||||||
|
//
|
||||||
|
// * resolve:ssm:public-parameter
|
||||||
|
//
|
||||||
|
// To reference a parameter stored in the same account:
|
||||||
|
//
|
||||||
|
// * resolve:ssm:parameter-name
|
||||||
|
//
|
||||||
|
// * resolve:ssm:parameter-name:version-number
|
||||||
|
//
|
||||||
|
// * resolve:ssm:parameter-name:label
|
||||||
|
//
|
||||||
|
// To reference a parameter shared from another Amazon Web Services account:
|
||||||
|
//
|
||||||
|
// * resolve:ssm:parameter-ARN
|
||||||
|
//
|
||||||
|
// * resolve:ssm:parameter-ARN:version-number
|
||||||
|
//
|
||||||
|
// * resolve:ssm:parameter-ARN:label
|
||||||
|
//
|
||||||
|
// For more information, see Use a Systems Manager parameter instead of an AMI
|
||||||
|
// ID (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/create-launch-template.html#use-an-ssm-parameter-instead-of-an-ami-id)
|
||||||
|
// in the Amazon EC2 User Guide.
|
||||||
|
//
|
||||||
|
// This parameter is only available for fleets of type instant. For fleets of
|
||||||
|
// type maintain and request, you must specify the AMI ID in the launch template.
|
||||||
ImageId *string `type:"string"`
|
ImageId *string `type:"string"`
|
||||||
|
|
||||||
// The attributes for the instance types. When you specify instance attributes,
|
// The attributes for the instance types. When you specify instance attributes,
|
||||||
|
|
@ -168935,12 +168993,17 @@ type RequestLaunchTemplateData struct {
|
||||||
// The name or Amazon Resource Name (ARN) of an IAM instance profile.
|
// The name or Amazon Resource Name (ARN) of an IAM instance profile.
|
||||||
IamInstanceProfile *LaunchTemplateIamInstanceProfileSpecificationRequest `type:"structure"`
|
IamInstanceProfile *LaunchTemplateIamInstanceProfileSpecificationRequest `type:"structure"`
|
||||||
|
|
||||||
// The ID of the AMI. Alternatively, you can specify a Systems Manager parameter,
|
// The ID of the AMI in the format ami-17characters00000.
|
||||||
// which will resolve to an AMI ID on launch.
|
|
||||||
//
|
//
|
||||||
// Valid formats:
|
// Alternatively, you can specify a Systems Manager parameter, using one of
|
||||||
|
// the following formats. The Systems Manager parameter will resolve to an AMI
|
||||||
|
// ID on launch.
|
||||||
//
|
//
|
||||||
// * ami-17characters00000
|
// To reference a public parameter:
|
||||||
|
//
|
||||||
|
// * resolve:ssm:public-parameter
|
||||||
|
//
|
||||||
|
// To reference a parameter stored in the same account:
|
||||||
//
|
//
|
||||||
// * resolve:ssm:parameter-name
|
// * resolve:ssm:parameter-name
|
||||||
//
|
//
|
||||||
|
|
@ -168948,15 +169011,26 @@ type RequestLaunchTemplateData struct {
|
||||||
//
|
//
|
||||||
// * resolve:ssm:parameter-name:label
|
// * resolve:ssm:parameter-name:label
|
||||||
//
|
//
|
||||||
// * resolve:ssm:public-parameter
|
// To reference a parameter shared from another Amazon Web Services account:
|
||||||
//
|
//
|
||||||
// Currently, EC2 Fleet and Spot Fleet do not support specifying a Systems Manager
|
// * resolve:ssm:parameter-ARN
|
||||||
// parameter. If the launch template will be used by an EC2 Fleet or Spot Fleet,
|
//
|
||||||
// you must specify the AMI ID.
|
// * resolve:ssm:parameter-ARN:version-number
|
||||||
|
//
|
||||||
|
// * resolve:ssm:parameter-ARN:label
|
||||||
//
|
//
|
||||||
// For more information, see Use a Systems Manager parameter instead of an AMI
|
// For more information, see Use a Systems Manager parameter instead of an AMI
|
||||||
// ID (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/create-launch-template.html#use-an-ssm-parameter-instead-of-an-ami-id)
|
// ID (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/create-launch-template.html#use-an-ssm-parameter-instead-of-an-ami-id)
|
||||||
// in the Amazon EC2 User Guide.
|
// in the Amazon EC2 User Guide.
|
||||||
|
//
|
||||||
|
// If the launch template will be used for an EC2 Fleet or Spot Fleet, note
|
||||||
|
// the following:
|
||||||
|
//
|
||||||
|
// * Only EC2 Fleets of type instant support specifying a Systems Manager
|
||||||
|
// parameter.
|
||||||
|
//
|
||||||
|
// * For EC2 Fleets of type maintain or request, or for Spot Fleets, you
|
||||||
|
// must specify the AMI ID.
|
||||||
ImageId *string `type:"string"`
|
ImageId *string `type:"string"`
|
||||||
|
|
||||||
// Indicates whether an instance stops or terminates when you initiate shutdown
|
// Indicates whether an instance stops or terminates when you initiate shutdown
|
||||||
|
|
@ -201114,9 +201188,6 @@ const (
|
||||||
// ResourceTypeVpcBlockPublicAccessExclusion is a ResourceType enum value
|
// ResourceTypeVpcBlockPublicAccessExclusion is a ResourceType enum value
|
||||||
ResourceTypeVpcBlockPublicAccessExclusion = "vpc-block-public-access-exclusion"
|
ResourceTypeVpcBlockPublicAccessExclusion = "vpc-block-public-access-exclusion"
|
||||||
|
|
||||||
// ResourceTypeVpcEncryptionControl is a ResourceType enum value
|
|
||||||
ResourceTypeVpcEncryptionControl = "vpc-encryption-control"
|
|
||||||
|
|
||||||
// ResourceTypeIpamResourceDiscovery is a ResourceType enum value
|
// ResourceTypeIpamResourceDiscovery is a ResourceType enum value
|
||||||
ResourceTypeIpamResourceDiscovery = "ipam-resource-discovery"
|
ResourceTypeIpamResourceDiscovery = "ipam-resource-discovery"
|
||||||
|
|
||||||
|
|
@ -201216,7 +201287,6 @@ func ResourceType_Values() []string {
|
||||||
ResourceTypeVerifiedAccessTrustProvider,
|
ResourceTypeVerifiedAccessTrustProvider,
|
||||||
ResourceTypeVpnConnectionDeviceType,
|
ResourceTypeVpnConnectionDeviceType,
|
||||||
ResourceTypeVpcBlockPublicAccessExclusion,
|
ResourceTypeVpcBlockPublicAccessExclusion,
|
||||||
ResourceTypeVpcEncryptionControl,
|
|
||||||
ResourceTypeIpamResourceDiscovery,
|
ResourceTypeIpamResourceDiscovery,
|
||||||
ResourceTypeIpamResourceDiscoveryAssociation,
|
ResourceTypeIpamResourceDiscoveryAssociation,
|
||||||
ResourceTypeInstanceConnectEndpoint,
|
ResourceTypeInstanceConnectEndpoint,
|
||||||
|
|
|
||||||
10
vendor/github.com/containers/image/v5/copy/compression.go
generated
vendored
10
vendor/github.com/containers/image/v5/copy/compression.go
generated
vendored
|
|
@ -73,7 +73,7 @@ type bpCompressionStepData struct {
|
||||||
operation bpcOperation // What we are actually doing
|
operation bpcOperation // What we are actually doing
|
||||||
uploadedOperation types.LayerCompression // Operation to use for updating the blob metadata (matching the end state, not necessarily what we do)
|
uploadedOperation types.LayerCompression // Operation to use for updating the blob metadata (matching the end state, not necessarily what we do)
|
||||||
uploadedAlgorithm *compressiontypes.Algorithm // An algorithm parameter for the compressionOperation edits.
|
uploadedAlgorithm *compressiontypes.Algorithm // An algorithm parameter for the compressionOperation edits.
|
||||||
uploadedAnnotations map[string]string // Annotations that should be set on the uploaded blob. WARNING: This is only set after the srcStream.reader is fully consumed.
|
uploadedAnnotations map[string]string // Compression-related annotations that should be set on the uploaded blob. WARNING: This is only set after the srcStream.reader is fully consumed.
|
||||||
srcCompressorName string // Compressor name to record in the blob info cache for the source blob.
|
srcCompressorName string // Compressor name to record in the blob info cache for the source blob.
|
||||||
uploadedCompressorName string // Compressor name to record in the blob info cache for the uploaded blob.
|
uploadedCompressorName string // Compressor name to record in the blob info cache for the uploaded blob.
|
||||||
closers []io.Closer // Objects to close after the upload is done, if any.
|
closers []io.Closer // Objects to close after the upload is done, if any.
|
||||||
|
|
@ -323,7 +323,11 @@ func (d *bpCompressionStepData) recordValidatedDigestData(c *copier, uploadedInf
|
||||||
return fmt.Errorf("Internal error: Unexpected d.operation value %#v", d.operation)
|
return fmt.Errorf("Internal error: Unexpected d.operation value %#v", d.operation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if d.uploadedCompressorName != "" && d.uploadedCompressorName != internalblobinfocache.UnknownCompression {
|
if d.srcCompressorName == "" || d.uploadedCompressorName == "" {
|
||||||
|
return fmt.Errorf("internal error: missing compressor names (src: %q, uploaded: %q)",
|
||||||
|
d.srcCompressorName, d.uploadedCompressorName)
|
||||||
|
}
|
||||||
|
if d.uploadedCompressorName != internalblobinfocache.UnknownCompression {
|
||||||
if d.uploadedCompressorName != compressiontypes.ZstdChunkedAlgorithmName {
|
if d.uploadedCompressorName != compressiontypes.ZstdChunkedAlgorithmName {
|
||||||
// HACK: Don’t record zstd:chunked algorithms.
|
// HACK: Don’t record zstd:chunked algorithms.
|
||||||
// There is already a similar hack in internal/imagedestination/impl/helpers.CandidateMatchesTryReusingBlobOptions,
|
// There is already a similar hack in internal/imagedestination/impl/helpers.CandidateMatchesTryReusingBlobOptions,
|
||||||
|
|
@ -337,7 +341,7 @@ func (d *bpCompressionStepData) recordValidatedDigestData(c *copier, uploadedInf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if srcInfo.Digest != "" && srcInfo.Digest != uploadedInfo.Digest &&
|
if srcInfo.Digest != "" && srcInfo.Digest != uploadedInfo.Digest &&
|
||||||
d.srcCompressorName != "" && d.srcCompressorName != internalblobinfocache.UnknownCompression {
|
d.srcCompressorName != internalblobinfocache.UnknownCompression {
|
||||||
if d.srcCompressorName != compressiontypes.ZstdChunkedAlgorithmName {
|
if d.srcCompressorName != compressiontypes.ZstdChunkedAlgorithmName {
|
||||||
// HACK: Don’t record zstd:chunked algorithms, see above.
|
// HACK: Don’t record zstd:chunked algorithms, see above.
|
||||||
c.blobInfoCache.RecordDigestCompressorName(srcInfo.Digest, d.srcCompressorName)
|
c.blobInfoCache.RecordDigestCompressorName(srcInfo.Digest, d.srcCompressorName)
|
||||||
|
|
|
||||||
14
vendor/github.com/containers/image/v5/copy/single.go
generated
vendored
14
vendor/github.com/containers/image/v5/copy/single.go
generated
vendored
|
|
@ -409,7 +409,6 @@ func (ic *imageCopier) compareImageDestinationManifestEqual(ctx context.Context,
|
||||||
// copyLayers copies layers from ic.src/ic.c.rawSource to dest, using and updating ic.manifestUpdates if necessary and ic.cannotModifyManifestReason == "".
|
// copyLayers copies layers from ic.src/ic.c.rawSource to dest, using and updating ic.manifestUpdates if necessary and ic.cannotModifyManifestReason == "".
|
||||||
func (ic *imageCopier) copyLayers(ctx context.Context) ([]compressiontypes.Algorithm, error) {
|
func (ic *imageCopier) copyLayers(ctx context.Context) ([]compressiontypes.Algorithm, error) {
|
||||||
srcInfos := ic.src.LayerInfos()
|
srcInfos := ic.src.LayerInfos()
|
||||||
numLayers := len(srcInfos)
|
|
||||||
updatedSrcInfos, err := ic.src.LayerInfosForCopy(ctx)
|
updatedSrcInfos, err := ic.src.LayerInfosForCopy(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -440,7 +439,7 @@ func (ic *imageCopier) copyLayers(ctx context.Context) ([]compressiontypes.Algor
|
||||||
// copyGroup is used to determine if all layers are copied
|
// copyGroup is used to determine if all layers are copied
|
||||||
copyGroup := sync.WaitGroup{}
|
copyGroup := sync.WaitGroup{}
|
||||||
|
|
||||||
data := make([]copyLayerData, numLayers)
|
data := make([]copyLayerData, len(srcInfos))
|
||||||
copyLayerHelper := func(index int, srcLayer types.BlobInfo, toEncrypt bool, pool *mpb.Progress, srcRef reference.Named) {
|
copyLayerHelper := func(index int, srcLayer types.BlobInfo, toEncrypt bool, pool *mpb.Progress, srcRef reference.Named) {
|
||||||
defer ic.c.concurrentBlobCopiesSemaphore.Release(1)
|
defer ic.c.concurrentBlobCopiesSemaphore.Release(1)
|
||||||
defer copyGroup.Done()
|
defer copyGroup.Done()
|
||||||
|
|
@ -463,9 +462,7 @@ func (ic *imageCopier) copyLayers(ctx context.Context) ([]compressiontypes.Algor
|
||||||
|
|
||||||
// Decide which layers to encrypt
|
// Decide which layers to encrypt
|
||||||
layersToEncrypt := set.New[int]()
|
layersToEncrypt := set.New[int]()
|
||||||
var encryptAll bool
|
|
||||||
if ic.c.options.OciEncryptLayers != nil {
|
if ic.c.options.OciEncryptLayers != nil {
|
||||||
encryptAll = len(*ic.c.options.OciEncryptLayers) == 0
|
|
||||||
totalLayers := len(srcInfos)
|
totalLayers := len(srcInfos)
|
||||||
for _, l := range *ic.c.options.OciEncryptLayers {
|
for _, l := range *ic.c.options.OciEncryptLayers {
|
||||||
switch {
|
switch {
|
||||||
|
|
@ -478,7 +475,7 @@ func (ic *imageCopier) copyLayers(ctx context.Context) ([]compressiontypes.Algor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if encryptAll {
|
if len(*ic.c.options.OciEncryptLayers) == 0 { // “encrypt all layers”
|
||||||
for i := 0; i < len(srcInfos); i++ {
|
for i := 0; i < len(srcInfos); i++ {
|
||||||
layersToEncrypt.Add(i)
|
layersToEncrypt.Add(i)
|
||||||
}
|
}
|
||||||
|
|
@ -493,8 +490,7 @@ func (ic *imageCopier) copyLayers(ctx context.Context) ([]compressiontypes.Algor
|
||||||
defer copyGroup.Wait()
|
defer copyGroup.Wait()
|
||||||
|
|
||||||
for i, srcLayer := range srcInfos {
|
for i, srcLayer := range srcInfos {
|
||||||
err = ic.c.concurrentBlobCopiesSemaphore.Acquire(ctx, 1)
|
if err := ic.c.concurrentBlobCopiesSemaphore.Acquire(ctx, 1); err != nil {
|
||||||
if err != nil {
|
|
||||||
// This can only fail with ctx.Err(), so no need to blame acquiring the semaphore.
|
// This can only fail with ctx.Err(), so no need to blame acquiring the semaphore.
|
||||||
return fmt.Errorf("copying layer: %w", err)
|
return fmt.Errorf("copying layer: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -509,8 +505,8 @@ func (ic *imageCopier) copyLayers(ctx context.Context) ([]compressiontypes.Algor
|
||||||
}
|
}
|
||||||
|
|
||||||
compressionAlgos := set.New[string]()
|
compressionAlgos := set.New[string]()
|
||||||
destInfos := make([]types.BlobInfo, numLayers)
|
destInfos := make([]types.BlobInfo, len(srcInfos))
|
||||||
diffIDs := make([]digest.Digest, numLayers)
|
diffIDs := make([]digest.Digest, len(srcInfos))
|
||||||
for i, cld := range data {
|
for i, cld := range data {
|
||||||
if cld.err != nil {
|
if cld.err != nil {
|
||||||
return nil, cld.err
|
return nil, cld.err
|
||||||
|
|
|
||||||
76
vendor/github.com/containers/image/v5/docker/docker_client.go
generated
vendored
76
vendor/github.com/containers/image/v5/docker/docker_client.go
generated
vendored
|
|
@ -86,11 +86,9 @@ type extensionSignatureList struct {
|
||||||
Signatures []extensionSignature `json:"signatures"`
|
Signatures []extensionSignature `json:"signatures"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bearerToken records a cached token we can use to authenticate.
|
||||||
type bearerToken struct {
|
type bearerToken struct {
|
||||||
Token string `json:"token"`
|
token string
|
||||||
AccessToken string `json:"access_token"`
|
|
||||||
ExpiresIn int `json:"expires_in"`
|
|
||||||
IssuedAt time.Time `json:"issued_at"`
|
|
||||||
expirationTime time.Time
|
expirationTime time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -147,25 +145,6 @@ const (
|
||||||
noAuth
|
noAuth
|
||||||
)
|
)
|
||||||
|
|
||||||
func newBearerTokenFromJSONBlob(blob []byte) (*bearerToken, error) {
|
|
||||||
token := new(bearerToken)
|
|
||||||
if err := json.Unmarshal(blob, &token); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if token.Token == "" {
|
|
||||||
token.Token = token.AccessToken
|
|
||||||
}
|
|
||||||
if token.ExpiresIn < minimumTokenLifetimeSeconds {
|
|
||||||
token.ExpiresIn = minimumTokenLifetimeSeconds
|
|
||||||
logrus.Debugf("Increasing token expiration to: %d seconds", token.ExpiresIn)
|
|
||||||
}
|
|
||||||
if token.IssuedAt.IsZero() {
|
|
||||||
token.IssuedAt = time.Now().UTC()
|
|
||||||
}
|
|
||||||
token.expirationTime = token.IssuedAt.Add(time.Duration(token.ExpiresIn) * time.Second)
|
|
||||||
return token, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// dockerCertDir returns a path to a directory to be consumed by tlsclientconfig.SetupCertificates() depending on ctx and hostPort.
|
// dockerCertDir returns a path to a directory to be consumed by tlsclientconfig.SetupCertificates() depending on ctx and hostPort.
|
||||||
func dockerCertDir(sys *types.SystemContext, hostPort string) (string, error) {
|
func dockerCertDir(sys *types.SystemContext, hostPort string) (string, error) {
|
||||||
if sys != nil && sys.DockerCertPath != "" {
|
if sys != nil && sys.DockerCertPath != "" {
|
||||||
|
|
@ -774,7 +753,7 @@ func (c *dockerClient) setupRequestAuth(req *http.Request, extraScope *authScope
|
||||||
token = *t
|
token = *t
|
||||||
c.tokenCache.Store(cacheKey, token)
|
c.tokenCache.Store(cacheKey, token)
|
||||||
}
|
}
|
||||||
registryToken = token.Token
|
registryToken = token.token
|
||||||
}
|
}
|
||||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", registryToken))
|
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", registryToken))
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -827,12 +806,7 @@ func (c *dockerClient) getBearerTokenOAuth2(ctx context.Context, challenge chall
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenBlob, err := iolimits.ReadAtMost(res.Body, iolimits.MaxAuthTokenBodySize)
|
return newBearerTokenFromHTTPResponseBody(res)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return newBearerTokenFromJSONBlob(tokenBlob)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *dockerClient) getBearerToken(ctx context.Context, challenge challenge,
|
func (c *dockerClient) getBearerToken(ctx context.Context, challenge challenge,
|
||||||
|
|
@ -878,12 +852,50 @@ func (c *dockerClient) getBearerToken(ctx context.Context, challenge challenge,
|
||||||
if err := httpResponseToError(res, "Requesting bearer token"); err != nil {
|
if err := httpResponseToError(res, "Requesting bearer token"); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tokenBlob, err := iolimits.ReadAtMost(res.Body, iolimits.MaxAuthTokenBodySize)
|
|
||||||
|
return newBearerTokenFromHTTPResponseBody(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newBearerTokenFromHTTPResponseBody parses a http.Response to obtain a bearerToken.
|
||||||
|
// The caller is still responsible for ensuring res.Body is closed.
|
||||||
|
func newBearerTokenFromHTTPResponseBody(res *http.Response) (*bearerToken, error) {
|
||||||
|
blob, err := iolimits.ReadAtMost(res.Body, iolimits.MaxAuthTokenBodySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return newBearerTokenFromJSONBlob(tokenBlob)
|
var token struct {
|
||||||
|
Token string `json:"token"`
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
ExpiresIn int `json:"expires_in"`
|
||||||
|
IssuedAt time.Time `json:"issued_at"`
|
||||||
|
expirationTime time.Time
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(blob, &token); err != nil {
|
||||||
|
const bodySampleLength = 50
|
||||||
|
bodySample := blob
|
||||||
|
if len(bodySample) > bodySampleLength {
|
||||||
|
bodySample = bodySample[:bodySampleLength]
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("decoding bearer token (last URL %q, body start %q): %w", res.Request.URL.Redacted(), string(bodySample), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bt := &bearerToken{
|
||||||
|
token: token.Token,
|
||||||
|
}
|
||||||
|
if bt.token == "" {
|
||||||
|
bt.token = token.AccessToken
|
||||||
|
}
|
||||||
|
|
||||||
|
if token.ExpiresIn < minimumTokenLifetimeSeconds {
|
||||||
|
token.ExpiresIn = minimumTokenLifetimeSeconds
|
||||||
|
logrus.Debugf("Increasing token expiration to: %d seconds", token.ExpiresIn)
|
||||||
|
}
|
||||||
|
if token.IssuedAt.IsZero() {
|
||||||
|
token.IssuedAt = time.Now().UTC()
|
||||||
|
}
|
||||||
|
bt.expirationTime = token.IssuedAt.Add(time.Duration(token.ExpiresIn) * time.Second)
|
||||||
|
return bt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// detectPropertiesHelper performs the work of detectProperties which executes
|
// detectPropertiesHelper performs the work of detectProperties which executes
|
||||||
|
|
|
||||||
2
vendor/github.com/containers/image/v5/docker/docker_image_dest.go
generated
vendored
2
vendor/github.com/containers/image/v5/docker/docker_image_dest.go
generated
vendored
|
|
@ -361,8 +361,6 @@ func (d *dockerImageDestination) TryReusingBlobWithOptions(ctx context.Context,
|
||||||
logrus.Debugf("Error parsing BlobInfoCache location reference: %s", err)
|
logrus.Debugf("Error parsing BlobInfoCache location reference: %s", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if !candidate.UnknownLocation {
|
|
||||||
if candidate.CompressionAlgorithm != nil {
|
if candidate.CompressionAlgorithm != nil {
|
||||||
logrus.Debugf("Trying to reuse blob with cached digest %s compressed with %s in destination repo %s", candidate.Digest.String(), candidate.CompressionAlgorithm.Name(), candidateRepo.Name())
|
logrus.Debugf("Trying to reuse blob with cached digest %s compressed with %s in destination repo %s", candidate.Digest.String(), candidate.CompressionAlgorithm.Name(), candidateRepo.Name())
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
31
vendor/github.com/containers/image/v5/docker/docker_image_src.go
generated
vendored
31
vendor/github.com/containers/image/v5/docker/docker_image_src.go
generated
vendored
|
|
@ -1,7 +1,9 @@
|
||||||
package docker
|
package docker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
@ -11,6 +13,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
|
@ -162,6 +165,34 @@ func newImageSourceAttempt(ctx context.Context, sys *types.SystemContext, logica
|
||||||
client.Close()
|
client.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if h, err := sysregistriesv2.AdditionalLayerStoreAuthHelper(endpointSys); err == nil && h != "" {
|
||||||
|
acf := map[string]struct {
|
||||||
|
Username string `json:"username,omitempty"`
|
||||||
|
Password string `json:"password,omitempty"`
|
||||||
|
IdentityToken string `json:"identityToken,omitempty"`
|
||||||
|
}{
|
||||||
|
physicalRef.ref.String(): {
|
||||||
|
Username: client.auth.Username,
|
||||||
|
Password: client.auth.Password,
|
||||||
|
IdentityToken: client.auth.IdentityToken,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
acfD, err := json.Marshal(acf)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnf("failed to marshal auth config: %v", err)
|
||||||
|
} else {
|
||||||
|
cmd := exec.Command(h)
|
||||||
|
cmd.Stdin = bytes.NewReader(acfD)
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
var stderr string
|
||||||
|
if ee, ok := err.(*exec.ExitError); ok {
|
||||||
|
stderr = string(ee.Stderr)
|
||||||
|
}
|
||||||
|
logrus.Warnf("Failed to call additional-layer-store-auth-helper (stderr:%s): %v", stderr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
55
vendor/github.com/containers/image/v5/internal/manifest/oci_index.go
generated
vendored
55
vendor/github.com/containers/image/v5/internal/manifest/oci_index.go
generated
vendored
|
|
@ -1,6 +1,7 @@
|
||||||
package manifest
|
package manifest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
|
|
@ -296,29 +297,51 @@ func OCI1IndexPublicFromComponents(components []imgspecv1.Descriptor, annotation
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i, component := range components {
|
for i, component := range components {
|
||||||
var platform *imgspecv1.Platform
|
index.Manifests[i] = oci1DescriptorClone(component)
|
||||||
if component.Platform != nil {
|
|
||||||
platformCopy := ociPlatformClone(*component.Platform)
|
|
||||||
platform = &platformCopy
|
|
||||||
}
|
|
||||||
m := imgspecv1.Descriptor{
|
|
||||||
MediaType: component.MediaType,
|
|
||||||
ArtifactType: component.ArtifactType,
|
|
||||||
Size: component.Size,
|
|
||||||
Digest: component.Digest,
|
|
||||||
URLs: slices.Clone(component.URLs),
|
|
||||||
Annotations: maps.Clone(component.Annotations),
|
|
||||||
Platform: platform,
|
|
||||||
}
|
|
||||||
index.Manifests[i] = m
|
|
||||||
}
|
}
|
||||||
return &index
|
return &index
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func oci1DescriptorClone(d imgspecv1.Descriptor) imgspecv1.Descriptor {
|
||||||
|
var platform *imgspecv1.Platform
|
||||||
|
if d.Platform != nil {
|
||||||
|
platformCopy := ociPlatformClone(*d.Platform)
|
||||||
|
platform = &platformCopy
|
||||||
|
}
|
||||||
|
return imgspecv1.Descriptor{
|
||||||
|
MediaType: d.MediaType,
|
||||||
|
Digest: d.Digest,
|
||||||
|
Size: d.Size,
|
||||||
|
URLs: slices.Clone(d.URLs),
|
||||||
|
Annotations: maps.Clone(d.Annotations),
|
||||||
|
Data: bytes.Clone(d.Data),
|
||||||
|
Platform: platform,
|
||||||
|
ArtifactType: d.ArtifactType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// OCI1IndexPublicClone creates a deep copy of the passed-in index.
|
// OCI1IndexPublicClone creates a deep copy of the passed-in index.
|
||||||
// This is publicly visible as c/image/manifest.OCI1IndexClone.
|
// This is publicly visible as c/image/manifest.OCI1IndexClone.
|
||||||
func OCI1IndexPublicClone(index *OCI1IndexPublic) *OCI1IndexPublic {
|
func OCI1IndexPublicClone(index *OCI1IndexPublic) *OCI1IndexPublic {
|
||||||
return OCI1IndexPublicFromComponents(index.Manifests, index.Annotations)
|
var subject *imgspecv1.Descriptor
|
||||||
|
if index.Subject != nil {
|
||||||
|
s := oci1DescriptorClone(*index.Subject)
|
||||||
|
subject = &s
|
||||||
|
}
|
||||||
|
manifests := make([]imgspecv1.Descriptor, len(index.Manifests))
|
||||||
|
for i, m := range index.Manifests {
|
||||||
|
manifests[i] = oci1DescriptorClone(m)
|
||||||
|
}
|
||||||
|
return &OCI1IndexPublic{
|
||||||
|
Index: imgspecv1.Index{
|
||||||
|
Versioned: index.Versioned,
|
||||||
|
MediaType: index.MediaType,
|
||||||
|
ArtifactType: index.ArtifactType,
|
||||||
|
Manifests: manifests,
|
||||||
|
Subject: subject,
|
||||||
|
Annotations: maps.Clone(index.Annotations),
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToOCI1Index returns the index encoded as an OCI1 index.
|
// ToOCI1Index returns the index encoded as an OCI1 index.
|
||||||
|
|
|
||||||
12
vendor/github.com/containers/image/v5/pkg/blobinfocache/default.go
generated
vendored
12
vendor/github.com/containers/image/v5/pkg/blobinfocache/default.go
generated
vendored
|
|
@ -74,3 +74,15 @@ func DefaultCache(sys *types.SystemContext) types.BlobInfoCache {
|
||||||
logrus.Debugf("Using SQLite blob info cache at %s", path)
|
logrus.Debugf("Using SQLite blob info cache at %s", path)
|
||||||
return cache
|
return cache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CleanupDefaultCache removes the blob info cache directory.
|
||||||
|
// It deletes the cache directory but it does not affect any file or memory buffer currently
|
||||||
|
// in use.
|
||||||
|
func CleanupDefaultCache(sys *types.SystemContext) error {
|
||||||
|
dir, err := blobInfoCacheDir(sys, rootless.GetRootlessEUID())
|
||||||
|
if err != nil {
|
||||||
|
// Mirror the DefaultCache behavior that does not fail in this case
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return os.RemoveAll(dir)
|
||||||
|
}
|
||||||
|
|
|
||||||
2
vendor/github.com/containers/image/v5/pkg/blobinfocache/memory/memory.go
generated
vendored
2
vendor/github.com/containers/image/v5/pkg/blobinfocache/memory/memory.go
generated
vendored
|
|
@ -27,7 +27,7 @@ type cache struct {
|
||||||
uncompressedDigests map[digest.Digest]digest.Digest
|
uncompressedDigests map[digest.Digest]digest.Digest
|
||||||
digestsByUncompressed map[digest.Digest]*set.Set[digest.Digest] // stores a set of digests for each uncompressed digest
|
digestsByUncompressed map[digest.Digest]*set.Set[digest.Digest] // stores a set of digests for each uncompressed digest
|
||||||
knownLocations map[locationKey]map[types.BICLocationReference]time.Time // stores last known existence time for each location reference
|
knownLocations map[locationKey]map[types.BICLocationReference]time.Time // stores last known existence time for each location reference
|
||||||
compressors map[digest.Digest]string // stores a compressor name, or blobinfocache.Unknown (not blobinfocache.UnknownCompression), for each digest
|
compressors map[digest.Digest]string // stores a compressor name, or blobinfocache.Uncompressed (not blobinfocache.UnknownCompression), for each digest
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a BlobInfoCache implementation which is in-memory only.
|
// New returns a BlobInfoCache implementation which is in-memory only.
|
||||||
|
|
|
||||||
20
vendor/github.com/containers/image/v5/pkg/sysregistriesv2/system_registries_v2.go
generated
vendored
20
vendor/github.com/containers/image/v5/pkg/sysregistriesv2/system_registries_v2.go
generated
vendored
|
|
@ -248,6 +248,11 @@ type V2RegistriesConf struct {
|
||||||
// potentially use all unqualified-search registries
|
// potentially use all unqualified-search registries
|
||||||
ShortNameMode string `toml:"short-name-mode"`
|
ShortNameMode string `toml:"short-name-mode"`
|
||||||
|
|
||||||
|
// AdditionalLayerStoreAuthHelper is a helper binary that receives
|
||||||
|
// registry credentials pass them to Additional Layer Store for
|
||||||
|
// registry authentication. These credentials are only collected when pulling (not pushing).
|
||||||
|
AdditionalLayerStoreAuthHelper string `toml:"additional-layer-store-auth-helper"`
|
||||||
|
|
||||||
shortNameAliasConf
|
shortNameAliasConf
|
||||||
|
|
||||||
// If you add any field, make sure to update Nonempty() below.
|
// If you add any field, make sure to update Nonempty() below.
|
||||||
|
|
@ -825,6 +830,16 @@ func CredentialHelpers(sys *types.SystemContext) ([]string, error) {
|
||||||
return config.partialV2.CredentialHelpers, nil
|
return config.partialV2.CredentialHelpers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AdditionalLayerStoreAuthHelper returns the helper for passing registry
|
||||||
|
// credentials to Additional Layer Store.
|
||||||
|
func AdditionalLayerStoreAuthHelper(sys *types.SystemContext) (string, error) {
|
||||||
|
config, err := getConfig(sys)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return config.partialV2.AdditionalLayerStoreAuthHelper, nil
|
||||||
|
}
|
||||||
|
|
||||||
// refMatchingSubdomainPrefix returns the length of ref
|
// refMatchingSubdomainPrefix returns the length of ref
|
||||||
// iff ref, which is a registry, repository namespace, repository or image reference (as formatted by
|
// iff ref, which is a registry, repository namespace, repository or image reference (as formatted by
|
||||||
// reference.Domain(), reference.Named.Name() or reference.Reference.String()
|
// reference.Domain(), reference.Named.Name() or reference.Reference.String()
|
||||||
|
|
@ -1051,6 +1066,11 @@ func (c *parsedConfig) updateWithConfigurationFrom(updates *parsedConfig) {
|
||||||
c.shortNameMode = updates.shortNameMode
|
c.shortNameMode = updates.shortNameMode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// == Merge AdditionalLayerStoreAuthHelper:
|
||||||
|
if updates.partialV2.AdditionalLayerStoreAuthHelper != "" {
|
||||||
|
c.partialV2.AdditionalLayerStoreAuthHelper = updates.partialV2.AdditionalLayerStoreAuthHelper
|
||||||
|
}
|
||||||
|
|
||||||
// == Merge aliasCache:
|
// == Merge aliasCache:
|
||||||
// We don’t maintain (in fact we actively clear) c.partialV2.shortNameAliasConf.
|
// We don’t maintain (in fact we actively clear) c.partialV2.shortNameAliasConf.
|
||||||
c.aliasCache.updateWithConfigurationFrom(updates.aliasCache)
|
c.aliasCache.updateWithConfigurationFrom(updates.aliasCache)
|
||||||
|
|
|
||||||
3
vendor/github.com/containers/image/v5/signature/mechanism_openpgp.go
generated
vendored
3
vendor/github.com/containers/image/v5/signature/mechanism_openpgp.go
generated
vendored
|
|
@ -15,6 +15,7 @@ import (
|
||||||
|
|
||||||
"github.com/containers/image/v5/signature/internal"
|
"github.com/containers/image/v5/signature/internal"
|
||||||
"github.com/containers/storage/pkg/homedir"
|
"github.com/containers/storage/pkg/homedir"
|
||||||
|
|
||||||
// This is a fallback code; the primary recommendation is to use the gpgme mechanism
|
// This is a fallback code; the primary recommendation is to use the gpgme mechanism
|
||||||
// implementation, which is out-of-process and more appropriate for handling long-term private key material
|
// implementation, which is out-of-process and more appropriate for handling long-term private key material
|
||||||
// than any Go implementation.
|
// than any Go implementation.
|
||||||
|
|
@ -150,7 +151,7 @@ func (m *openpgpSigningMechanism) Verify(unverifiedSignature []byte) (contents [
|
||||||
return nil, "", fmt.Errorf("signature error: %v", md.SignatureError)
|
return nil, "", fmt.Errorf("signature error: %v", md.SignatureError)
|
||||||
}
|
}
|
||||||
if md.SignedBy == nil {
|
if md.SignedBy == nil {
|
||||||
return nil, "", internal.NewInvalidSignatureError(fmt.Sprintf("Invalid GPG signature: %#v", md.Signature))
|
return nil, "", internal.NewInvalidSignatureError(fmt.Sprintf("Key not found for key ID %x in signature", md.SignedByKeyId))
|
||||||
}
|
}
|
||||||
if md.Signature != nil {
|
if md.Signature != nil {
|
||||||
if md.Signature.SigLifetimeSecs != nil {
|
if md.Signature.SigLifetimeSecs != nil {
|
||||||
|
|
|
||||||
6
vendor/github.com/containers/image/v5/storage/storage_dest.go
generated
vendored
6
vendor/github.com/containers/image/v5/storage/storage_dest.go
generated
vendored
|
|
@ -325,7 +325,13 @@ func (s *storageImageDestination) PutBlobPartial(ctx context.Context, chunkAcces
|
||||||
if out.UncompressedDigest != "" {
|
if out.UncompressedDigest != "" {
|
||||||
// The computation of UncompressedDigest means the whole layer has been consumed; while doing that, chunked.GetDiffer is
|
// The computation of UncompressedDigest means the whole layer has been consumed; while doing that, chunked.GetDiffer is
|
||||||
// responsible for ensuring blobDigest has been validated.
|
// responsible for ensuring blobDigest has been validated.
|
||||||
|
if out.CompressedDigest != blobDigest {
|
||||||
|
return private.UploadedBlob{}, fmt.Errorf("internal error: ApplyDiffWithDiffer returned CompressedDigest %q not matching expected %q",
|
||||||
|
out.CompressedDigest, blobDigest)
|
||||||
|
}
|
||||||
s.lockProtected.blobDiffIDs[blobDigest] = out.UncompressedDigest
|
s.lockProtected.blobDiffIDs[blobDigest] = out.UncompressedDigest
|
||||||
|
// We trust ApplyDiffWithDiffer to validate or create both values correctly.
|
||||||
|
options.Cache.RecordDigestUncompressedPair(out.CompressedDigest, out.UncompressedDigest)
|
||||||
} else {
|
} else {
|
||||||
// Don’t identify layers by TOC if UncompressedDigest is available.
|
// Don’t identify layers by TOC if UncompressedDigest is available.
|
||||||
// - Using UncompressedDigest allows image reuse with non-partially-pulled layers
|
// - Using UncompressedDigest allows image reuse with non-partially-pulled layers
|
||||||
|
|
|
||||||
4
vendor/github.com/containers/image/v5/version/version.go
generated
vendored
4
vendor/github.com/containers/image/v5/version/version.go
generated
vendored
|
|
@ -6,9 +6,9 @@ const (
|
||||||
// VersionMajor is for an API incompatible changes
|
// VersionMajor is for an API incompatible changes
|
||||||
VersionMajor = 5
|
VersionMajor = 5
|
||||||
// VersionMinor is for functionality in a backwards-compatible manner
|
// VersionMinor is for functionality in a backwards-compatible manner
|
||||||
VersionMinor = 31
|
VersionMinor = 32
|
||||||
// VersionPatch is for backwards-compatible bug fixes
|
// VersionPatch is for backwards-compatible bug fixes
|
||||||
VersionPatch = 1
|
VersionPatch = 0
|
||||||
|
|
||||||
// VersionDev indicates development branch. Releases will be empty string.
|
// VersionDev indicates development branch. Releases will be empty string.
|
||||||
VersionDev = ""
|
VersionDev = ""
|
||||||
|
|
|
||||||
2
vendor/github.com/containers/ocicrypt/.golangci.yml
generated
vendored
2
vendor/github.com/containers/ocicrypt/.golangci.yml
generated
vendored
|
|
@ -7,7 +7,7 @@ linters:
|
||||||
- goimports
|
- goimports
|
||||||
- revive
|
- revive
|
||||||
- ineffassign
|
- ineffassign
|
||||||
- vet
|
- govet
|
||||||
- unused
|
- unused
|
||||||
- misspell
|
- misspell
|
||||||
|
|
||||||
|
|
|
||||||
3
vendor/github.com/containers/ocicrypt/blockcipher/blockcipher.go
generated
vendored
3
vendor/github.com/containers/ocicrypt/blockcipher/blockcipher.go
generated
vendored
|
|
@ -96,9 +96,8 @@ func (lbco LayerBlockCipherOptions) GetOpt(key string) (value []byte, ok bool) {
|
||||||
return v, ok
|
return v, ok
|
||||||
} else if v, ok := lbco.Private.CipherOptions[key]; ok {
|
} else if v, ok := lbco.Private.CipherOptions[key]; ok {
|
||||||
return v, ok
|
return v, ok
|
||||||
} else {
|
|
||||||
return nil, false
|
|
||||||
}
|
}
|
||||||
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func wrapFinalizerWithType(fin Finalizer, typ LayerCipherType) Finalizer {
|
func wrapFinalizerWithType(fin Finalizer, typ LayerCipherType) Finalizer {
|
||||||
|
|
|
||||||
3
vendor/github.com/containers/ocicrypt/gpg.go
generated
vendored
3
vendor/github.com/containers/ocicrypt/gpg.go
generated
vendored
|
|
@ -79,9 +79,8 @@ func GuessGPGVersion() GPGVersion {
|
||||||
return GPGv2
|
return GPGv2
|
||||||
} else if err := exec.Command("gpg", "--version").Run(); err == nil {
|
} else if err := exec.Command("gpg", "--version").Run(); err == nil {
|
||||||
return GPGv1
|
return GPGv1
|
||||||
} else {
|
|
||||||
return GPGVersionUndetermined
|
|
||||||
}
|
}
|
||||||
|
return GPGVersionUndetermined
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGPGClient creates a new GPGClient object representing the given version
|
// NewGPGClient creates a new GPGClient object representing the given version
|
||||||
|
|
|
||||||
8
vendor/github.com/containers/ocicrypt/keywrap/jwe/keywrapper_jwe.go
generated
vendored
8
vendor/github.com/containers/ocicrypt/keywrap/jwe/keywrapper_jwe.go
generated
vendored
|
|
@ -24,7 +24,7 @@ import (
|
||||||
"github.com/containers/ocicrypt/config"
|
"github.com/containers/ocicrypt/config"
|
||||||
"github.com/containers/ocicrypt/keywrap"
|
"github.com/containers/ocicrypt/keywrap"
|
||||||
"github.com/containers/ocicrypt/utils"
|
"github.com/containers/ocicrypt/utils"
|
||||||
"github.com/go-jose/go-jose/v3"
|
"github.com/go-jose/go-jose/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type jweKeyWrapper struct {
|
type jweKeyWrapper struct {
|
||||||
|
|
@ -65,7 +65,11 @@ func (kw *jweKeyWrapper) WrapKeys(ec *config.EncryptConfig, optsData []byte) ([]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kw *jweKeyWrapper) UnwrapKey(dc *config.DecryptConfig, jweString []byte) ([]byte, error) {
|
func (kw *jweKeyWrapper) UnwrapKey(dc *config.DecryptConfig, jweString []byte) ([]byte, error) {
|
||||||
jwe, err := jose.ParseEncrypted(string(jweString))
|
// cf. list of algorithms in func addPubKeys() below
|
||||||
|
keyEncryptionAlgorithms := []jose.KeyAlgorithm{jose.RSA_OAEP, jose.RSA_OAEP_256, jose.ECDH_ES_A128KW, jose.ECDH_ES_A192KW, jose.ECDH_ES_A256KW}
|
||||||
|
// accept all algorithms defined in RFC 7518, section 5.1
|
||||||
|
contentEncryption := []jose.ContentEncryption{jose.A128CBC_HS256, jose.A192CBC_HS384, jose.A256CBC_HS512, jose.A128GCM, jose.A192GCM, jose.A256GCM}
|
||||||
|
jwe, err := jose.ParseEncrypted(string(jweString), keyEncryptionAlgorithms, contentEncryption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("jose.ParseEncrypted failed")
|
return nil, errors.New("jose.ParseEncrypted failed")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
6
vendor/github.com/containers/ocicrypt/keywrap/keyprovider/keyprovider.go
generated
vendored
6
vendor/github.com/containers/ocicrypt/keywrap/keyprovider/keyprovider.go
generated
vendored
|
|
@ -124,9 +124,8 @@ func (kw *keyProviderKeyWrapper) WrapKeys(ec *config.EncryptConfig, optsData []b
|
||||||
}
|
}
|
||||||
|
|
||||||
return protocolOuput.KeyWrapResults.Annotation, nil
|
return protocolOuput.KeyWrapResults.Annotation, nil
|
||||||
} else {
|
|
||||||
return nil, errors.New("Unsupported keyprovider invocation. Supported invocation methods are grpc and cmd")
|
|
||||||
}
|
}
|
||||||
|
return nil, errors.New("Unsupported keyprovider invocation. Supported invocation methods are grpc and cmd")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
@ -162,9 +161,8 @@ func (kw *keyProviderKeyWrapper) UnwrapKey(dc *config.DecryptConfig, jsonString
|
||||||
}
|
}
|
||||||
|
|
||||||
return protocolOuput.KeyUnwrapResults.OptsData, nil
|
return protocolOuput.KeyUnwrapResults.OptsData, nil
|
||||||
} else {
|
|
||||||
return nil, errors.New("Unsupported keyprovider invocation. Supported invocation methods are grpc and cmd")
|
|
||||||
}
|
}
|
||||||
|
return nil, errors.New("Unsupported keyprovider invocation. Supported invocation methods are grpc and cmd")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getProviderGRPCOutput(input []byte, connString string, operation KeyProviderKeyWrapProtocolOperation) (*KeyProviderKeyWrapProtocolOutput, error) {
|
func getProviderGRPCOutput(input []byte, connString string, operation KeyProviderKeyWrapProtocolOperation) (*KeyProviderKeyWrapProtocolOutput, error) {
|
||||||
|
|
|
||||||
2
vendor/github.com/containers/ocicrypt/utils/utils.go
generated
vendored
2
vendor/github.com/containers/ocicrypt/utils/utils.go
generated
vendored
|
|
@ -26,7 +26,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containers/ocicrypt/crypto/pkcs11"
|
"github.com/containers/ocicrypt/crypto/pkcs11"
|
||||||
"github.com/go-jose/go-jose/v3"
|
"github.com/go-jose/go-jose/v4"
|
||||||
"golang.org/x/crypto/openpgp"
|
"golang.org/x/crypto/openpgp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
2
vendor/github.com/containers/storage/.cirrus.yml
generated
vendored
2
vendor/github.com/containers/storage/.cirrus.yml
generated
vendored
|
|
@ -23,7 +23,7 @@ env:
|
||||||
# GCE project where images live
|
# GCE project where images live
|
||||||
IMAGE_PROJECT: "libpod-218412"
|
IMAGE_PROJECT: "libpod-218412"
|
||||||
# VM Image built in containers/automation_images
|
# VM Image built in containers/automation_images
|
||||||
IMAGE_SUFFIX: "c20240513t140131z-f40f39d13"
|
IMAGE_SUFFIX: "c20240529t141726z-f40f39d13"
|
||||||
FEDORA_CACHE_IMAGE_NAME: "fedora-${IMAGE_SUFFIX}"
|
FEDORA_CACHE_IMAGE_NAME: "fedora-${IMAGE_SUFFIX}"
|
||||||
DEBIAN_CACHE_IMAGE_NAME: "debian-${IMAGE_SUFFIX}"
|
DEBIAN_CACHE_IMAGE_NAME: "debian-${IMAGE_SUFFIX}"
|
||||||
|
|
||||||
|
|
|
||||||
6
vendor/github.com/containers/storage/.golangci.yml
generated
vendored
6
vendor/github.com/containers/storage/.golangci.yml
generated
vendored
|
|
@ -1,11 +1,7 @@
|
||||||
---
|
---
|
||||||
run:
|
run:
|
||||||
concurrency: 6
|
concurrency: 6
|
||||||
deadline: 5m
|
timeout: 5m
|
||||||
skip-dirs-use-default: true
|
|
||||||
linters:
|
linters:
|
||||||
enable:
|
enable:
|
||||||
- gofumpt
|
- gofumpt
|
||||||
disable:
|
|
||||||
- errcheck
|
|
||||||
- staticcheck
|
|
||||||
|
|
|
||||||
2
vendor/github.com/containers/storage/Makefile
generated
vendored
2
vendor/github.com/containers/storage/Makefile
generated
vendored
|
|
@ -53,6 +53,8 @@ local-cross cross: ## cross build the binaries for arm, darwin, and freebsd
|
||||||
os=`echo $${target} | cut -f1 -d/` ; \
|
os=`echo $${target} | cut -f1 -d/` ; \
|
||||||
arch=`echo $${target} | cut -f2 -d/` ; \
|
arch=`echo $${target} | cut -f2 -d/` ; \
|
||||||
suffix=$${os}.$${arch} ; \
|
suffix=$${os}.$${arch} ; \
|
||||||
|
echo env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} $(GO) build -compiler gc -tags \"$(NATIVETAGS) $(TAGS)\" $(FLAGS) ./... ; \
|
||||||
|
env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} $(GO) build -compiler gc -tags "$(NATIVETAGS) $(TAGS)" $(FLAGS) ./... || exit 1 ; \
|
||||||
echo env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} $(GO) build -compiler gc -tags \"$(NATIVETAGS) $(TAGS)\" $(FLAGS) -o containers-storage.$${suffix} ./cmd/containers-storage ; \
|
echo env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} $(GO) build -compiler gc -tags \"$(NATIVETAGS) $(TAGS)\" $(FLAGS) -o containers-storage.$${suffix} ./cmd/containers-storage ; \
|
||||||
env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} $(GO) build -compiler gc -tags "$(NATIVETAGS) $(TAGS)" $(FLAGS) -o containers-storage.$${suffix} ./cmd/containers-storage || exit 1 ; \
|
env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} $(GO) build -compiler gc -tags "$(NATIVETAGS) $(TAGS)" $(FLAGS) -o containers-storage.$${suffix} ./cmd/containers-storage || exit 1 ; \
|
||||||
done
|
done
|
||||||
|
|
|
||||||
2
vendor/github.com/containers/storage/VERSION
generated
vendored
2
vendor/github.com/containers/storage/VERSION
generated
vendored
|
|
@ -1 +1 @@
|
||||||
1.54.0
|
1.55.0
|
||||||
|
|
|
||||||
17
vendor/github.com/containers/storage/check.go
generated
vendored
17
vendor/github.com/containers/storage/check.go
generated
vendored
|
|
@ -304,7 +304,14 @@ func (s *store) Check(options *CheckOptions) (CheckReport, error) {
|
||||||
archiveErr = err
|
archiveErr = err
|
||||||
}
|
}
|
||||||
// consume any trailer after the EOF marker
|
// consume any trailer after the EOF marker
|
||||||
io.Copy(io.Discard, diffReader)
|
if _, err := io.Copy(io.Discard, diffReader); err != nil {
|
||||||
|
err = fmt.Errorf("layer %s: consume any trailer after the EOF marker: %w", layerID, err)
|
||||||
|
if isReadWrite {
|
||||||
|
report.Layers[layerID] = append(report.Layers[layerID], err)
|
||||||
|
} else {
|
||||||
|
report.ROLayers[layerID] = append(report.ROLayers[layerID], err)
|
||||||
|
}
|
||||||
|
}
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}(id, reader)
|
}(id, reader)
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
@ -366,7 +373,7 @@ func (s *store) Check(options *CheckOptions) (CheckReport, error) {
|
||||||
if options.LayerMountable {
|
if options.LayerMountable {
|
||||||
func() {
|
func() {
|
||||||
// Mount the layer.
|
// Mount the layer.
|
||||||
mountPoint, err := s.graphDriver.Get(id, drivers.MountOpts{MountLabel: layer.MountLabel})
|
mountPoint, err := s.graphDriver.Get(id, drivers.MountOpts{MountLabel: layer.MountLabel, Options: []string{"ro"}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("%slayer %s: %w", readWriteDesc, id, err)
|
err := fmt.Errorf("%slayer %s: %w", readWriteDesc, id, err)
|
||||||
if isReadWrite {
|
if isReadWrite {
|
||||||
|
|
@ -955,6 +962,9 @@ func (c *checkDirectory) add(path string, typeflag byte, uid, gid int, size int6
|
||||||
mtime: mtime,
|
mtime: mtime,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case tar.TypeXGlobalHeader:
|
||||||
|
// ignore, since even though it looks like a valid pathname, it doesn't end
|
||||||
|
// up on the filesystem
|
||||||
default:
|
default:
|
||||||
// treat these as TypeReg items
|
// treat these as TypeReg items
|
||||||
delete(c.directory, components[0])
|
delete(c.directory, components[0])
|
||||||
|
|
@ -966,9 +976,6 @@ func (c *checkDirectory) add(path string, typeflag byte, uid, gid int, size int6
|
||||||
mode: mode,
|
mode: mode,
|
||||||
mtime: mtime,
|
mtime: mtime,
|
||||||
}
|
}
|
||||||
case tar.TypeXGlobalHeader:
|
|
||||||
// ignore, since even though it looks like a valid pathname, it doesn't end
|
|
||||||
// up on the filesystem
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
43
vendor/github.com/containers/storage/drivers/aufs/aufs.go
generated
vendored
43
vendor/github.com/containers/storage/drivers/aufs/aufs.go
generated
vendored
|
|
@ -30,7 +30,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -75,8 +74,6 @@ func init() {
|
||||||
type Driver struct {
|
type Driver struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
root string
|
root string
|
||||||
uidMaps []idtools.IDMap
|
|
||||||
gidMaps []idtools.IDMap
|
|
||||||
ctr *graphdriver.RefCounter
|
ctr *graphdriver.RefCounter
|
||||||
pathCacheLock sync.Mutex
|
pathCacheLock sync.Mutex
|
||||||
pathCache map[string]string
|
pathCache map[string]string
|
||||||
|
|
@ -129,22 +126,16 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
|
||||||
|
|
||||||
a := &Driver{
|
a := &Driver{
|
||||||
root: home,
|
root: home,
|
||||||
uidMaps: options.UIDMaps,
|
|
||||||
gidMaps: options.GIDMaps,
|
|
||||||
pathCache: make(map[string]string),
|
pathCache: make(map[string]string),
|
||||||
ctr: graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicAufs)),
|
ctr: graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicAufs)),
|
||||||
locker: locker.New(),
|
locker: locker.New(),
|
||||||
mountOptions: mountOptions,
|
mountOptions: mountOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
rootUID, rootGID, err := idtools.GetRootUIDGID(options.UIDMaps, options.GIDMaps)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Create the root aufs driver dir and return
|
// Create the root aufs driver dir and return
|
||||||
// if it already exists
|
// if it already exists
|
||||||
// If not populate the dir structure
|
// If not populate the dir structure
|
||||||
if err := idtools.MkdirAllAs(home, 0o700, rootUID, rootGID); err != nil {
|
if err := os.MkdirAll(home, 0o700); err != nil {
|
||||||
if os.IsExist(err) {
|
if os.IsExist(err) {
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
@ -157,7 +148,7 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
|
||||||
|
|
||||||
// Populate the dir structure
|
// Populate the dir structure
|
||||||
for _, p := range paths {
|
for _, p := range paths {
|
||||||
if err := idtools.MkdirAllAs(path.Join(home, p), 0o700, rootUID, rootGID); err != nil {
|
if err := os.MkdirAll(path.Join(home, p), 0o700); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -191,13 +182,7 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a nil error if the kernel supports aufs
|
// Return a nil error if the kernel supports aufs
|
||||||
// We cannot modprobe because inside dind modprobe fails
|
|
||||||
// to run
|
|
||||||
func supportsAufs() error {
|
func supportsAufs() error {
|
||||||
// We can try to modprobe aufs first before looking at
|
|
||||||
// proc/filesystems for when aufs is supported
|
|
||||||
exec.Command("modprobe", "aufs").Run()
|
|
||||||
|
|
||||||
if unshare.IsRootless() {
|
if unshare.IsRootless() {
|
||||||
return ErrAufsNested
|
return ErrAufsNested
|
||||||
}
|
}
|
||||||
|
|
@ -334,7 +319,7 @@ func (a *Driver) createDirsFor(id, parent string) error {
|
||||||
// The path of directories are <aufs_root_path>/mnt/<image_id>
|
// The path of directories are <aufs_root_path>/mnt/<image_id>
|
||||||
// and <aufs_root_path>/diff/<image_id>
|
// and <aufs_root_path>/diff/<image_id>
|
||||||
for _, p := range paths {
|
for _, p := range paths {
|
||||||
rootPair := idtools.NewIDMappingsFromMaps(a.uidMaps, a.gidMaps).RootPair()
|
rootPair := idtools.IDPair{UID: 0, GID: 0}
|
||||||
rootPerms := defaultPerms
|
rootPerms := defaultPerms
|
||||||
if parent != "" {
|
if parent != "" {
|
||||||
st, err := system.Stat(path.Join(a.rootPath(), p, parent))
|
st, err := system.Stat(path.Join(a.rootPath(), p, parent))
|
||||||
|
|
@ -355,7 +340,9 @@ func (a *Driver) createDirsFor(id, parent string) error {
|
||||||
// Remove will unmount and remove the given id.
|
// Remove will unmount and remove the given id.
|
||||||
func (a *Driver) Remove(id string) error {
|
func (a *Driver) Remove(id string) error {
|
||||||
a.locker.Lock(id)
|
a.locker.Lock(id)
|
||||||
defer a.locker.Unlock(id)
|
defer func() {
|
||||||
|
_ = a.locker.Unlock(id)
|
||||||
|
}()
|
||||||
a.pathCacheLock.Lock()
|
a.pathCacheLock.Lock()
|
||||||
mountpoint, exists := a.pathCache[id]
|
mountpoint, exists := a.pathCache[id]
|
||||||
a.pathCacheLock.Unlock()
|
a.pathCacheLock.Unlock()
|
||||||
|
|
@ -446,7 +433,10 @@ func atomicRemove(source string) error {
|
||||||
// This will mount the dir at its given path
|
// This will mount the dir at its given path
|
||||||
func (a *Driver) Get(id string, options graphdriver.MountOpts) (string, error) {
|
func (a *Driver) Get(id string, options graphdriver.MountOpts) (string, error) {
|
||||||
a.locker.Lock(id)
|
a.locker.Lock(id)
|
||||||
defer a.locker.Unlock(id)
|
defer func() {
|
||||||
|
_ = a.locker.Unlock(id)
|
||||||
|
}()
|
||||||
|
|
||||||
parents, err := a.getParentLayerPaths(id)
|
parents, err := a.getParentLayerPaths(id)
|
||||||
if err != nil && !os.IsNotExist(err) {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
@ -483,7 +473,10 @@ func (a *Driver) Get(id string, options graphdriver.MountOpts) (string, error) {
|
||||||
// Put unmounts and updates list of active mounts.
|
// Put unmounts and updates list of active mounts.
|
||||||
func (a *Driver) Put(id string) error {
|
func (a *Driver) Put(id string) error {
|
||||||
a.locker.Lock(id)
|
a.locker.Lock(id)
|
||||||
defer a.locker.Unlock(id)
|
defer func() {
|
||||||
|
_ = a.locker.Unlock(id)
|
||||||
|
}()
|
||||||
|
|
||||||
a.pathCacheLock.Lock()
|
a.pathCacheLock.Lock()
|
||||||
m, exists := a.pathCache[id]
|
m, exists := a.pathCache[id]
|
||||||
if !exists {
|
if !exists {
|
||||||
|
|
@ -506,7 +499,9 @@ func (a *Driver) Put(id string) error {
|
||||||
// For AUFS, it queries the mountpoint for this ID.
|
// For AUFS, it queries the mountpoint for this ID.
|
||||||
func (a *Driver) ReadWriteDiskUsage(id string) (*directory.DiskUsage, error) {
|
func (a *Driver) ReadWriteDiskUsage(id string) (*directory.DiskUsage, error) {
|
||||||
a.locker.Lock(id)
|
a.locker.Lock(id)
|
||||||
defer a.locker.Unlock(id)
|
defer func() {
|
||||||
|
_ = a.locker.Unlock(id)
|
||||||
|
}()
|
||||||
a.pathCacheLock.Lock()
|
a.pathCacheLock.Lock()
|
||||||
m, exists := a.pathCache[id]
|
m, exists := a.pathCache[id]
|
||||||
if !exists {
|
if !exists {
|
||||||
|
|
@ -689,7 +684,9 @@ func (a *Driver) Cleanup() error {
|
||||||
func (a *Driver) aufsMount(ro []string, rw, target string, options graphdriver.MountOpts) (err error) {
|
func (a *Driver) aufsMount(ro []string, rw, target string, options graphdriver.MountOpts) (err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Unmount(target)
|
if err1 := Unmount(target); err1 != nil {
|
||||||
|
logrus.Warnf("Unmount %q: %v", target, err1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
||||||
26
vendor/github.com/containers/storage/drivers/btrfs/btrfs.go
generated
vendored
26
vendor/github.com/containers/storage/drivers/btrfs/btrfs.go
generated
vendored
|
|
@ -66,11 +66,7 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
|
||||||
return nil, fmt.Errorf("%q is not on a btrfs filesystem: %w", home, graphdriver.ErrPrerequisites)
|
return nil, fmt.Errorf("%q is not on a btrfs filesystem: %w", home, graphdriver.ErrPrerequisites)
|
||||||
}
|
}
|
||||||
|
|
||||||
rootUID, rootGID, err := idtools.GetRootUIDGID(options.UIDMaps, options.GIDMaps)
|
if err := os.MkdirAll(filepath.Join(home, "subvolumes"), 0o700); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := idtools.MkdirAllAs(filepath.Join(home, "subvolumes"), 0o700, rootUID, rootGID); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,8 +81,6 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
|
||||||
|
|
||||||
driver := &Driver{
|
driver := &Driver{
|
||||||
home: home,
|
home: home,
|
||||||
uidMaps: options.UIDMaps,
|
|
||||||
gidMaps: options.GIDMaps,
|
|
||||||
options: opt,
|
options: opt,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,8 +123,6 @@ func parseOptions(opt []string) (btrfsOptions, bool, error) {
|
||||||
type Driver struct {
|
type Driver struct {
|
||||||
// root of the file system
|
// root of the file system
|
||||||
home string
|
home string
|
||||||
uidMaps []idtools.IDMap
|
|
||||||
gidMaps []idtools.IDMap
|
|
||||||
options btrfsOptions
|
options btrfsOptions
|
||||||
quotaEnabled bool
|
quotaEnabled bool
|
||||||
once sync.Once
|
once sync.Once
|
||||||
|
|
@ -481,11 +473,7 @@ func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts
|
||||||
func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
|
func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
|
||||||
quotas := d.quotasDir()
|
quotas := d.quotasDir()
|
||||||
subvolumes := d.subvolumesDir()
|
subvolumes := d.subvolumesDir()
|
||||||
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
|
if err := os.MkdirAll(subvolumes, 0o700); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := idtools.MkdirAllAs(subvolumes, 0o700, rootUID, rootGID); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if parent == "" {
|
if parent == "" {
|
||||||
|
|
@ -523,7 +511,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
|
||||||
if err := d.setStorageSize(path.Join(subvolumes, id), driver); err != nil {
|
if err := d.setStorageSize(path.Join(subvolumes, id), driver); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := idtools.MkdirAllAs(quotas, 0o700, rootUID, rootGID); err != nil {
|
if err := os.MkdirAll(quotas, 0o700); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := os.WriteFile(path.Join(quotas, id), []byte(fmt.Sprint(driver.options.size)), 0o644); err != nil {
|
if err := os.WriteFile(path.Join(quotas, id), []byte(fmt.Sprint(driver.options.size)), 0o644); err != nil {
|
||||||
|
|
@ -531,14 +519,6 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we have a remapped root (user namespaces enabled), change the created snapshot
|
|
||||||
// dir ownership to match
|
|
||||||
if rootUID != 0 || rootGID != 0 {
|
|
||||||
if err := os.Chown(path.Join(subvolumes, id), rootUID, rootGID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mountLabel := ""
|
mountLabel := ""
|
||||||
if opts != nil {
|
if opts != nil {
|
||||||
mountLabel = opts.MountLabel
|
mountLabel = opts.MountLabel
|
||||||
|
|
|
||||||
10
vendor/github.com/containers/storage/drivers/chown.go
generated
vendored
10
vendor/github.com/containers/storage/drivers/chown.go
generated
vendored
|
|
@ -4,11 +4,12 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/containers/storage/pkg/idtools"
|
"github.com/containers/storage/pkg/idtools"
|
||||||
"github.com/containers/storage/pkg/reexec"
|
"github.com/containers/storage/pkg/reexec"
|
||||||
"github.com/opencontainers/selinux/pkg/pwalk"
|
"github.com/opencontainers/selinux/pkg/pwalkdir"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -54,13 +55,14 @@ func chownByMapsMain() {
|
||||||
|
|
||||||
chowner := newLChowner()
|
chowner := newLChowner()
|
||||||
|
|
||||||
chown := func(path string, info os.FileInfo, _ error) error {
|
var chown fs.WalkDirFunc = func(path string, d fs.DirEntry, _ error) error {
|
||||||
if path == "." {
|
info, err := d.Info()
|
||||||
|
if path == "." || err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return chowner.LChown(path, info, toHost, toContainer)
|
return chowner.LChown(path, info, toHost, toContainer)
|
||||||
}
|
}
|
||||||
if err := pwalk.Walk(".", chown); err != nil {
|
if err := pwalkdir.Walk(".", chown); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "error during chown: %v", err)
|
fmt.Fprintf(os.Stderr, "error during chown: %v", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
4
vendor/github.com/containers/storage/drivers/chroot_unix.go
generated
vendored
4
vendor/github.com/containers/storage/drivers/chroot_unix.go
generated
vendored
|
|
@ -1,5 +1,5 @@
|
||||||
//go:build linux || darwin || freebsd || solaris
|
//go:build !windows
|
||||||
// +build linux darwin freebsd solaris
|
// +build !windows
|
||||||
|
|
||||||
package graphdriver
|
package graphdriver
|
||||||
|
|
||||||
|
|
|
||||||
6
vendor/github.com/containers/storage/drivers/copy/copy_linux.go
generated
vendored
6
vendor/github.com/containers/storage/drivers/copy/copy_linux.go
generated
vendored
|
|
@ -50,13 +50,13 @@ func CopyRegularToFile(srcPath string, dstFile *os.File, fileinfo os.FileInfo, c
|
||||||
defer srcFile.Close()
|
defer srcFile.Close()
|
||||||
|
|
||||||
if *copyWithFileClone {
|
if *copyWithFileClone {
|
||||||
_, _, err = unix.Syscall(unix.SYS_IOCTL, dstFile.Fd(), C.FICLONE, srcFile.Fd())
|
_, _, errno := unix.Syscall(unix.SYS_IOCTL, dstFile.Fd(), C.FICLONE, srcFile.Fd())
|
||||||
if err == nil {
|
if errno == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
*copyWithFileClone = false
|
*copyWithFileClone = false
|
||||||
if err == unix.EXDEV {
|
if errno == unix.EXDEV {
|
||||||
*copyWithFileRange = false
|
*copyWithFileRange = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
16
vendor/github.com/containers/storage/drivers/driver.go
generated
vendored
16
vendor/github.com/containers/storage/drivers/driver.go
generated
vendored
|
|
@ -193,6 +193,7 @@ type DriverWithDifferOutput struct {
|
||||||
UIDs []uint32
|
UIDs []uint32
|
||||||
GIDs []uint32
|
GIDs []uint32
|
||||||
UncompressedDigest digest.Digest
|
UncompressedDigest digest.Digest
|
||||||
|
CompressedDigest digest.Digest
|
||||||
Metadata string
|
Metadata string
|
||||||
BigData map[string][]byte
|
BigData map[string][]byte
|
||||||
TarSplit []byte
|
TarSplit []byte
|
||||||
|
|
@ -215,20 +216,25 @@ const (
|
||||||
DifferOutputFormatFlat
|
DifferOutputFormatFlat
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// DifferFsVerity is a part of the experimental Differ interface and should not be used from outside of c/storage.
|
||||||
|
// It configures the fsverity requirement.
|
||||||
type DifferFsVerity int
|
type DifferFsVerity int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// DifferFsVerityDisabled means no fs-verity is used
|
// DifferFsVerityDisabled means no fs-verity is used
|
||||||
DifferFsVerityDisabled = iota
|
DifferFsVerityDisabled = iota
|
||||||
|
|
||||||
// DifferFsVerityEnabled means fs-verity is used when supported
|
// DifferFsVerityIfAvailable means fs-verity is used when supported by
|
||||||
DifferFsVerityEnabled
|
// the underlying kernel and filesystem.
|
||||||
|
DifferFsVerityIfAvailable
|
||||||
|
|
||||||
// DifferFsVerityRequired means fs-verity is required
|
// DifferFsVerityRequired means fs-verity is required. Note this is not
|
||||||
|
// currently set or exposed by the overlay driver.
|
||||||
DifferFsVerityRequired
|
DifferFsVerityRequired
|
||||||
)
|
)
|
||||||
|
|
||||||
// DifferOptions overrides how the differ work
|
// DifferOptions is a part of the experimental Differ interface and should not be used from outside of c/storage.
|
||||||
|
// It overrides how the differ works.
|
||||||
type DifferOptions struct {
|
type DifferOptions struct {
|
||||||
// Format defines the destination directory layout format
|
// Format defines the destination directory layout format
|
||||||
Format DifferOutputFormat
|
Format DifferOutputFormat
|
||||||
|
|
@ -377,8 +383,6 @@ type Options struct {
|
||||||
ImageStore string
|
ImageStore string
|
||||||
DriverPriority []string
|
DriverPriority []string
|
||||||
DriverOptions []string
|
DriverOptions []string
|
||||||
UIDMaps []idtools.IDMap
|
|
||||||
GIDMaps []idtools.IDMap
|
|
||||||
ExperimentalEnabled bool
|
ExperimentalEnabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
6
vendor/github.com/containers/storage/drivers/overlay/check.go
generated
vendored
6
vendor/github.com/containers/storage/drivers/overlay/check.go
generated
vendored
|
|
@ -263,7 +263,11 @@ func supportsIdmappedLowerLayers(home string) (bool, error) {
|
||||||
if err := idmap.CreateIDMappedMount(lowerDir, lowerMappedDir, int(pid)); err != nil {
|
if err := idmap.CreateIDMappedMount(lowerDir, lowerMappedDir, int(pid)); err != nil {
|
||||||
return false, fmt.Errorf("create mapped mount: %w", err)
|
return false, fmt.Errorf("create mapped mount: %w", err)
|
||||||
}
|
}
|
||||||
defer unix.Unmount(lowerMappedDir, unix.MNT_DETACH)
|
defer func() {
|
||||||
|
if err := unix.Unmount(lowerMappedDir, unix.MNT_DETACH); err != nil {
|
||||||
|
logrus.Warnf("Unmount %q: %v", lowerMappedDir, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lowerMappedDir, upperDir, workDir)
|
opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lowerMappedDir, upperDir, workDir)
|
||||||
flags := uintptr(0)
|
flags := uintptr(0)
|
||||||
|
|
|
||||||
12
vendor/github.com/containers/storage/drivers/overlay/composefs.go
generated
vendored
12
vendor/github.com/containers/storage/drivers/overlay/composefs.go
generated
vendored
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
@ -56,7 +57,7 @@ func generateComposeFsBlob(verityDigests map[string]string, toc interface{}, com
|
||||||
|
|
||||||
fd, err := unix.Openat(unix.AT_FDCWD, destFile, unix.O_WRONLY|unix.O_CREAT|unix.O_TRUNC|unix.O_EXCL|unix.O_CLOEXEC, 0o644)
|
fd, err := unix.Openat(unix.AT_FDCWD, destFile, unix.O_WRONLY|unix.O_CREAT|unix.O_TRUNC|unix.O_EXCL|unix.O_CLOEXEC, 0o644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to open output file %q: %w", destFile, err)
|
return &fs.PathError{Op: "openat", Path: destFile, Err: err}
|
||||||
}
|
}
|
||||||
outFd := os.NewFile(uintptr(fd), "outFd")
|
outFd := os.NewFile(uintptr(fd), "outFd")
|
||||||
|
|
||||||
|
|
@ -117,7 +118,7 @@ func hasACL(path string) (bool, error) {
|
||||||
|
|
||||||
fd, err := unix.Openat(unix.AT_FDCWD, path, unix.O_RDONLY|unix.O_CLOEXEC, 0)
|
fd, err := unix.Openat(unix.AT_FDCWD, path, unix.O_RDONLY|unix.O_CLOEXEC, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, &fs.PathError{Op: "openat", Path: path, Err: err}
|
||||||
}
|
}
|
||||||
defer unix.Close(fd)
|
defer unix.Close(fd)
|
||||||
// do not worry about checking the magic number, if the file is invalid
|
// do not worry about checking the magic number, if the file is invalid
|
||||||
|
|
@ -125,7 +126,7 @@ func hasACL(path string) (bool, error) {
|
||||||
flags := make([]byte, 4)
|
flags := make([]byte, 4)
|
||||||
nread, err := unix.Pread(fd, flags, 8)
|
nread, err := unix.Pread(fd, flags, 8)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, fmt.Errorf("pread %q: %w", path, err)
|
||||||
}
|
}
|
||||||
if nread != 4 {
|
if nread != 4 {
|
||||||
return false, fmt.Errorf("failed to read flags from %q", path)
|
return false, fmt.Errorf("failed to read flags from %q", path)
|
||||||
|
|
@ -150,5 +151,8 @@ func mountComposefsBlob(dataDir, mountPoint string) error {
|
||||||
mountOpts += ",noacl"
|
mountOpts += ",noacl"
|
||||||
}
|
}
|
||||||
|
|
||||||
return unix.Mount(loop.Name(), mountPoint, "erofs", unix.MS_RDONLY, mountOpts)
|
if err := unix.Mount(loop.Name(), mountPoint, "erofs", unix.MS_RDONLY, mountOpts); err != nil {
|
||||||
|
return fmt.Errorf("failed to mount erofs image at %q: %w", mountPoint, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
271
vendor/github.com/containers/storage/drivers/overlay/overlay.go
generated
vendored
271
vendor/github.com/containers/storage/drivers/overlay/overlay.go
generated
vendored
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
|
|
@ -119,8 +120,6 @@ type Driver struct {
|
||||||
home string
|
home string
|
||||||
runhome string
|
runhome string
|
||||||
imageStore string
|
imageStore string
|
||||||
uidMaps []idtools.IDMap
|
|
||||||
gidMaps []idtools.IDMap
|
|
||||||
ctr *graphdriver.RefCounter
|
ctr *graphdriver.RefCounter
|
||||||
quotaCtl *quota.Control
|
quotaCtl *quota.Control
|
||||||
options overlayOptions
|
options overlayOptions
|
||||||
|
|
@ -332,13 +331,9 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
|
||||||
backingFs = fsName
|
backingFs = fsName
|
||||||
|
|
||||||
runhome := filepath.Join(options.RunRoot, filepath.Base(home))
|
runhome := filepath.Join(options.RunRoot, filepath.Base(home))
|
||||||
rootUID, rootGID, err := idtools.GetRootUIDGID(options.UIDMaps, options.GIDMaps)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the driver home dir
|
// Create the driver home dir
|
||||||
if err := idtools.MkdirAllAs(path.Join(home, linkDir), 0o755, 0, 0); err != nil {
|
if err := os.MkdirAll(path.Join(home, linkDir), 0o755); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -348,7 +343,7 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := idtools.MkdirAllAs(runhome, 0o700, rootUID, rootGID); err != nil {
|
if err := os.MkdirAll(runhome, 0o700); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -373,9 +368,6 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if opts.forceMask != nil {
|
|
||||||
return nil, errors.New("'force_mask' is supported only with 'mount_program'")
|
|
||||||
}
|
|
||||||
// check if they are running over btrfs, aufs, overlay, or ecryptfs
|
// check if they are running over btrfs, aufs, overlay, or ecryptfs
|
||||||
switch fsMagic {
|
switch fsMagic {
|
||||||
case graphdriver.FsMagicAufs, graphdriver.FsMagicOverlay, graphdriver.FsMagicEcryptfs:
|
case graphdriver.FsMagicAufs, graphdriver.FsMagicOverlay, graphdriver.FsMagicEcryptfs:
|
||||||
|
|
@ -457,8 +449,6 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
|
||||||
home: home,
|
home: home,
|
||||||
imageStore: options.ImageStore,
|
imageStore: options.ImageStore,
|
||||||
runhome: runhome,
|
runhome: runhome,
|
||||||
uidMaps: options.UIDMaps,
|
|
||||||
gidMaps: options.GIDMaps,
|
|
||||||
ctr: graphdriver.NewRefCounter(graphdriver.NewFsChecker(fileSystemType)),
|
ctr: graphdriver.NewRefCounter(graphdriver.NewFsChecker(fileSystemType)),
|
||||||
supportsDType: supportsDType,
|
supportsDType: supportsDType,
|
||||||
usingMetacopy: usingMetacopy,
|
usingMetacopy: usingMetacopy,
|
||||||
|
|
@ -698,12 +688,8 @@ func SupportsNativeOverlay(home, runhome string) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func supportsOverlay(home string, homeMagic graphdriver.FsMagic, rootUID, rootGID int) (supportsDType bool, err error) {
|
func supportsOverlay(home string, homeMagic graphdriver.FsMagic, rootUID, rootGID int) (supportsDType bool, err error) {
|
||||||
// We can try to modprobe overlay first
|
|
||||||
|
|
||||||
selinuxLabelTest := selinux.PrivContainerMountLabel()
|
selinuxLabelTest := selinux.PrivContainerMountLabel()
|
||||||
|
|
||||||
exec.Command("modprobe", "overlay").Run()
|
|
||||||
|
|
||||||
logLevel := logrus.ErrorLevel
|
logLevel := logrus.ErrorLevel
|
||||||
if unshare.IsRootless() {
|
if unshare.IsRootless() {
|
||||||
logLevel = logrus.DebugLevel
|
logLevel = logrus.DebugLevel
|
||||||
|
|
@ -831,7 +817,9 @@ func (d *Driver) useNaiveDiff() bool {
|
||||||
logrus.Info(nativeDiffCacheText)
|
logrus.Info(nativeDiffCacheText)
|
||||||
useNaiveDiffOnly = true
|
useNaiveDiffOnly = true
|
||||||
}
|
}
|
||||||
cachedFeatureRecord(d.runhome, feature, !useNaiveDiffOnly, nativeDiffCacheText)
|
if err := cachedFeatureRecord(d.runhome, feature, !useNaiveDiffOnly, nativeDiffCacheText); err != nil {
|
||||||
|
logrus.Warnf("Recording overlay native-diff support status: %v", err)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
return useNaiveDiffOnly
|
return useNaiveDiffOnly
|
||||||
}
|
}
|
||||||
|
|
@ -860,14 +848,14 @@ func (d *Driver) Status() [][2]string {
|
||||||
// Metadata returns meta data about the overlay driver such as
|
// Metadata returns meta data about the overlay driver such as
|
||||||
// LowerDir, UpperDir, WorkDir and MergeDir used to store data.
|
// LowerDir, UpperDir, WorkDir and MergeDir used to store data.
|
||||||
func (d *Driver) Metadata(id string) (map[string]string, error) {
|
func (d *Driver) Metadata(id string) (map[string]string, error) {
|
||||||
dir := d.dir(id)
|
dir, _, inAdditionalStore := d.dir2(id, false)
|
||||||
if err := fileutils.Exists(dir); err != nil {
|
if err := fileutils.Exists(dir); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata := map[string]string{
|
metadata := map[string]string{
|
||||||
"WorkDir": path.Join(dir, "work"),
|
"WorkDir": path.Join(dir, "work"),
|
||||||
"MergedDir": path.Join(dir, "merged"),
|
"MergedDir": d.getMergedDir(id, dir, inAdditionalStore),
|
||||||
"UpperDir": path.Join(dir, "diff"),
|
"UpperDir": path.Join(dir, "diff"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -983,6 +971,10 @@ func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if d.options.forceMask != nil && d.options.mountProgram == "" {
|
||||||
|
return fmt.Errorf("overlay: force_mask option for writeable layers is only supported with a mount_program")
|
||||||
|
}
|
||||||
|
|
||||||
if _, ok := opts.StorageOpt["size"]; !ok {
|
if _, ok := opts.StorageOpt["size"]; !ok {
|
||||||
if opts.StorageOpt == nil {
|
if opts.StorageOpt == nil {
|
||||||
opts.StorageOpt = map[string]string{}
|
opts.StorageOpt = map[string]string{}
|
||||||
|
|
@ -1021,8 +1013,8 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, readOnl
|
||||||
|
|
||||||
disableQuota := readOnly
|
disableQuota := readOnly
|
||||||
|
|
||||||
uidMaps := d.uidMaps
|
var uidMaps []idtools.IDMap
|
||||||
gidMaps := d.gidMaps
|
var gidMaps []idtools.IDMap
|
||||||
|
|
||||||
if opts != nil && opts.IDMappings != nil {
|
if opts != nil && opts.IDMappings != nil {
|
||||||
uidMaps = opts.IDMappings.UIDs()
|
uidMaps = opts.IDMappings.UIDs()
|
||||||
|
|
@ -1047,14 +1039,23 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, readOnl
|
||||||
if err := idtools.MkdirAllAndChownNew(path.Dir(dir), 0o755, idPair); err != nil {
|
if err := idtools.MkdirAllAndChownNew(path.Dir(dir), 0o755, idPair); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
st := idtools.Stat{IDs: idPair, Mode: defaultPerms}
|
||||||
|
|
||||||
if parent != "" {
|
if parent != "" {
|
||||||
parentBase := d.dir(parent)
|
parentBase := d.dir(parent)
|
||||||
st, err := system.Stat(filepath.Join(parentBase, "diff"))
|
parentDiff := filepath.Join(parentBase, "diff")
|
||||||
if err != nil {
|
if xSt, err := idtools.GetContainersOverrideXattr(parentDiff); err == nil {
|
||||||
return err
|
st = xSt
|
||||||
|
} else {
|
||||||
|
systemSt, err := system.Stat(parentDiff)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
st.IDs.UID = int(systemSt.UID())
|
||||||
|
st.IDs.GID = int(systemSt.GID())
|
||||||
|
st.Mode = os.FileMode(systemSt.Mode())
|
||||||
}
|
}
|
||||||
rootUID = int(st.UID())
|
|
||||||
rootGID = int(st.GID())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := fileutils.Lexists(dir); err == nil {
|
if err := fileutils.Lexists(dir); err == nil {
|
||||||
|
|
@ -1100,22 +1101,21 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, readOnl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
perms := defaultPerms
|
forcedSt := st
|
||||||
if d.options.forceMask != nil {
|
if d.options.forceMask != nil {
|
||||||
perms = *d.options.forceMask
|
forcedSt.IDs = idPair
|
||||||
|
forcedSt.Mode = *d.options.forceMask
|
||||||
}
|
}
|
||||||
|
|
||||||
if parent != "" {
|
diff := path.Join(dir, "diff")
|
||||||
parentBase := d.dir(parent)
|
if err := idtools.MkdirAs(diff, forcedSt.Mode, forcedSt.IDs.UID, forcedSt.IDs.GID); err != nil {
|
||||||
st, err := system.Stat(filepath.Join(parentBase, "diff"))
|
return err
|
||||||
if err != nil {
|
}
|
||||||
|
|
||||||
|
if d.options.forceMask != nil {
|
||||||
|
if err := idtools.SetContainersOverrideXattr(diff, st); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
perms = os.FileMode(st.Mode())
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := idtools.MkdirAs(path.Join(dir, "diff"), perms, rootUID, rootGID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lid := generateID(idLength)
|
lid := generateID(idLength)
|
||||||
|
|
@ -1130,16 +1130,16 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, readOnl
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := idtools.MkdirAs(path.Join(dir, "work"), 0o700, rootUID, rootGID); err != nil {
|
if err := idtools.MkdirAs(path.Join(dir, "work"), 0o700, forcedSt.IDs.UID, forcedSt.IDs.GID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := idtools.MkdirAs(path.Join(dir, "merged"), 0o700, rootUID, rootGID); err != nil {
|
if err := idtools.MkdirAs(path.Join(dir, "merged"), 0o700, forcedSt.IDs.UID, forcedSt.IDs.GID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// if no parent directory, create a dummy lower directory and skip writing a "lowers" file
|
// if no parent directory, create a dummy lower directory and skip writing a "lowers" file
|
||||||
if parent == "" {
|
if parent == "" {
|
||||||
return idtools.MkdirAs(path.Join(dir, "empty"), 0o700, rootUID, rootGID)
|
return idtools.MkdirAs(path.Join(dir, "empty"), 0o700, forcedSt.IDs.UID, forcedSt.IDs.GID)
|
||||||
}
|
}
|
||||||
|
|
||||||
lower, err := d.getLower(parent)
|
lower, err := d.getLower(parent)
|
||||||
|
|
@ -1283,12 +1283,6 @@ func (d *Driver) getLowerDirs(id string) ([]string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Driver) optsAppendMappings(opts string, uidMaps, gidMaps []idtools.IDMap) string {
|
func (d *Driver) optsAppendMappings(opts string, uidMaps, gidMaps []idtools.IDMap) string {
|
||||||
if uidMaps == nil {
|
|
||||||
uidMaps = d.uidMaps
|
|
||||||
}
|
|
||||||
if gidMaps == nil {
|
|
||||||
gidMaps = d.gidMaps
|
|
||||||
}
|
|
||||||
if uidMaps != nil {
|
if uidMaps != nil {
|
||||||
var uids, gids bytes.Buffer
|
var uids, gids bytes.Buffer
|
||||||
if len(uidMaps) == 1 && uidMaps[0].Size == 1 {
|
if len(uidMaps) == 1 && uidMaps[0].Size == 1 {
|
||||||
|
|
@ -1539,11 +1533,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
|
||||||
for err == nil {
|
for err == nil {
|
||||||
absLowers = append(absLowers, filepath.Join(dir, nameWithSuffix("diff", diffN)))
|
absLowers = append(absLowers, filepath.Join(dir, nameWithSuffix("diff", diffN)))
|
||||||
diffN++
|
diffN++
|
||||||
st, err = os.Stat(filepath.Join(dir, nameWithSuffix("diff", diffN)))
|
err = fileutils.Exists(filepath.Join(dir, nameWithSuffix("diff", diffN)))
|
||||||
if err == nil && !permsKnown {
|
|
||||||
perms = os.FileMode(st.Mode())
|
|
||||||
permsKnown = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
idmappedMountProcessPid := -1
|
idmappedMountProcessPid := -1
|
||||||
|
|
@ -1561,7 +1551,11 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
|
||||||
composefsMounts := []string{}
|
composefsMounts := []string{}
|
||||||
defer func() {
|
defer func() {
|
||||||
for _, m := range composefsMounts {
|
for _, m := range composefsMounts {
|
||||||
defer unix.Unmount(m, unix.MNT_DETACH)
|
defer func(m string) {
|
||||||
|
if err := unix.Unmount(m, unix.MNT_DETACH); err != nil {
|
||||||
|
logrus.Warnf("Unmount %q: %v", m, err)
|
||||||
|
}
|
||||||
|
}(m)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
@ -1665,7 +1659,11 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
|
||||||
skipIDMappingLayers[composefsMount] = composefsMount
|
skipIDMappingLayers[composefsMount] = composefsMount
|
||||||
// overlay takes a reference on the mount, so it is safe to unmount
|
// overlay takes a reference on the mount, so it is safe to unmount
|
||||||
// the mapped idmounts as soon as the final overlay file system is mounted.
|
// the mapped idmounts as soon as the final overlay file system is mounted.
|
||||||
defer unix.Unmount(composefsMount, unix.MNT_DETACH)
|
defer func() {
|
||||||
|
if err := unix.Unmount(composefsMount, unix.MNT_DETACH); err != nil {
|
||||||
|
logrus.Warnf("Unmount %q: %v", composefsMount, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
absLowers = append(absLowers, composefsMount)
|
absLowers = append(absLowers, composefsMount)
|
||||||
continue
|
continue
|
||||||
|
|
@ -1705,10 +1703,10 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mergedDir := path.Join(dir, "merged")
|
mergedDir := d.getMergedDir(id, dir, inAdditionalStore)
|
||||||
// Attempt to create the merged dir only if it doesn't exist.
|
// Attempt to create the merged dir only if it doesn't exist.
|
||||||
if err := fileutils.Exists(mergedDir); err != nil && os.IsNotExist(err) {
|
if err := fileutils.Exists(mergedDir); err != nil && os.IsNotExist(err) {
|
||||||
if err := idtools.MkdirAs(mergedDir, 0o700, rootUID, rootGID); err != nil && !os.IsExist(err) {
|
if err := idtools.MkdirAllAs(mergedDir, 0o700, rootUID, rootGID); err != nil && !os.IsExist(err) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1772,7 +1770,11 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
|
||||||
|
|
||||||
// overlay takes a reference on the mount, so it is safe to unmount
|
// overlay takes a reference on the mount, so it is safe to unmount
|
||||||
// the mapped idmounts as soon as the final overlay file system is mounted.
|
// the mapped idmounts as soon as the final overlay file system is mounted.
|
||||||
defer unix.Unmount(root, unix.MNT_DETACH)
|
defer func() {
|
||||||
|
if err := unix.Unmount(root, unix.MNT_DETACH); err != nil {
|
||||||
|
logrus.Warnf("Unmount %q: %v", root, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// relative path to the layer through the id mapped mount
|
// relative path to the layer through the id mapped mount
|
||||||
|
|
@ -1854,7 +1856,9 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
|
||||||
mountFunc = func(source string, target string, mType string, flags uintptr, label string) error {
|
mountFunc = func(source string, target string, mType string, flags uintptr, label string) error {
|
||||||
return mountOverlayFrom(d.home, source, target, mType, flags, label)
|
return mountOverlayFrom(d.home, source, target, mType, flags, label)
|
||||||
}
|
}
|
||||||
mountTarget = path.Join(id, "merged")
|
if !inAdditionalStore {
|
||||||
|
mountTarget = path.Join(id, "merged")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// overlay has a check in place to prevent mounting the same file system twice
|
// overlay has a check in place to prevent mounting the same file system twice
|
||||||
|
|
@ -1873,13 +1877,26 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
|
||||||
return mergedDir, nil
|
return mergedDir, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getMergedDir returns the directory path that should be used as the mount point for the overlayfs.
|
||||||
|
func (d *Driver) getMergedDir(id, dir string, inAdditionalStore bool) string {
|
||||||
|
// If the layer is in an additional store, the lock we might hold only a reading lock. To prevent
|
||||||
|
// races with other processes, use a private directory under the main store rundir. At this point, the
|
||||||
|
// current process is holding an exclusive lock on the store, and since the rundir cannot be shared for
|
||||||
|
// different stores, it is safe to assume the current process has exclusive access to it.
|
||||||
|
if inAdditionalStore {
|
||||||
|
return path.Join(d.runhome, id, "merged")
|
||||||
|
}
|
||||||
|
return path.Join(dir, "merged")
|
||||||
|
}
|
||||||
|
|
||||||
// Put unmounts the mount path created for the give id.
|
// Put unmounts the mount path created for the give id.
|
||||||
func (d *Driver) Put(id string) error {
|
func (d *Driver) Put(id string) error {
|
||||||
dir, _, inAdditionalStore := d.dir2(id, false)
|
dir, _, inAdditionalStore := d.dir2(id, false)
|
||||||
if err := fileutils.Exists(dir); err != nil {
|
if err := fileutils.Exists(dir); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
mountpoint := path.Join(dir, "merged")
|
mountpoint := d.getMergedDir(id, dir, inAdditionalStore)
|
||||||
|
|
||||||
if count := d.ctr.Decrement(mountpoint); count > 0 {
|
if count := d.ctr.Decrement(mountpoint); count > 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -1936,7 +1953,15 @@ func (d *Driver) Put(id string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !inAdditionalStore {
|
if inAdditionalStore {
|
||||||
|
// check the base name for extra safety
|
||||||
|
if strings.HasPrefix(mountpoint, d.runhome) && filepath.Base(mountpoint) == "merged" {
|
||||||
|
err := os.RemoveAll(filepath.Dir(mountpoint))
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warningf("Failed to remove mountpoint %s overlay: %s: %v", id, mountpoint, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
uid, gid := int(0), int(0)
|
uid, gid := int(0), int(0)
|
||||||
fi, err := os.Stat(mountpoint)
|
fi, err := os.Stat(mountpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -1953,7 +1978,7 @@ func (d *Driver) Put(id string) error {
|
||||||
// rename(2) can be used on an empty directory, as it is the mountpoint after umount, and it retains
|
// rename(2) can be used on an empty directory, as it is the mountpoint after umount, and it retains
|
||||||
// its atomic semantic. In this way the "merged" directory is never removed.
|
// its atomic semantic. In this way the "merged" directory is never removed.
|
||||||
if err := unix.Rename(tmpMountpoint, mountpoint); err != nil {
|
if err := unix.Rename(tmpMountpoint, mountpoint); err != nil {
|
||||||
logrus.Debugf("Failed to replace mountpoint %s overlay: %s - %v", id, mountpoint, err)
|
logrus.Debugf("Failed to replace mountpoint %s overlay: %s: %v", id, mountpoint, err)
|
||||||
return fmt.Errorf("replacing mount point %q: %w", mountpoint, err)
|
return fmt.Errorf("replacing mount point %q: %w", mountpoint, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2024,11 +2049,27 @@ func (d *Driver) getWhiteoutFormat() archive.WhiteoutFormat {
|
||||||
}
|
}
|
||||||
|
|
||||||
type overlayFileGetter struct {
|
type overlayFileGetter struct {
|
||||||
diffDirs []string
|
diffDirs []string
|
||||||
|
composefsMounts map[string]*os.File // map from diff dir to the directory with the composefs blob mounted
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *overlayFileGetter) Get(path string) (io.ReadCloser, error) {
|
func (g *overlayFileGetter) Get(path string) (io.ReadCloser, error) {
|
||||||
|
buf := make([]byte, unix.PathMax)
|
||||||
for _, d := range g.diffDirs {
|
for _, d := range g.diffDirs {
|
||||||
|
if f, found := g.composefsMounts[d]; found {
|
||||||
|
// there is no *at equivalent for getxattr, but it can be emulated by opening the file under /proc/self/fd/$FD/$PATH
|
||||||
|
len, err := unix.Getxattr(fmt.Sprintf("/proc/self/fd/%d/%s", int(f.Fd()), path), "trusted.overlay.redirect", buf)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, unix.ENODATA) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, &fs.PathError{Op: "getxattr", Path: path, Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the xattr value is the path to the file in the composefs layer diff directory
|
||||||
|
return os.Open(filepath.Join(d, string(buf[:len])))
|
||||||
|
}
|
||||||
|
|
||||||
f, err := os.Open(filepath.Join(d, path))
|
f, err := os.Open(filepath.Join(d, path))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return f, nil
|
return f, nil
|
||||||
|
|
@ -2041,7 +2082,16 @@ func (g *overlayFileGetter) Get(path string) (io.ReadCloser, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *overlayFileGetter) Close() error {
|
func (g *overlayFileGetter) Close() error {
|
||||||
return nil
|
var errs *multierror.Error
|
||||||
|
for _, f := range g.composefsMounts {
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
errs = multierror.Append(errs, err)
|
||||||
|
}
|
||||||
|
if err := unix.Rmdir(f.Name()); err != nil {
|
||||||
|
errs = multierror.Append(errs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errs.ErrorOrNil()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Driver) getStagingDir(id string) string {
|
func (d *Driver) getStagingDir(id string) string {
|
||||||
|
|
@ -2052,10 +2102,7 @@ func (d *Driver) getStagingDir(id string) string {
|
||||||
// DiffGetter returns a FileGetCloser that can read files from the directory that
|
// DiffGetter returns a FileGetCloser that can read files from the directory that
|
||||||
// contains files for the layer differences, either for this layer, or one of our
|
// contains files for the layer differences, either for this layer, or one of our
|
||||||
// lowers if we're just a template directory. Used for direct access for tar-split.
|
// lowers if we're just a template directory. Used for direct access for tar-split.
|
||||||
func (d *Driver) DiffGetter(id string) (graphdriver.FileGetCloser, error) {
|
func (d *Driver) DiffGetter(id string) (_ graphdriver.FileGetCloser, Err error) {
|
||||||
if d.usingComposefs {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
p, err := d.getDiffPath(id)
|
p, err := d.getDiffPath(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -2064,7 +2111,43 @@ func (d *Driver) DiffGetter(id string) (graphdriver.FileGetCloser, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &overlayFileGetter{diffDirs: append([]string{p}, paths...)}, nil
|
|
||||||
|
// map from diff dir to the directory with the composefs blob mounted
|
||||||
|
composefsMounts := make(map[string]*os.File)
|
||||||
|
defer func() {
|
||||||
|
if Err != nil {
|
||||||
|
for _, f := range composefsMounts {
|
||||||
|
f.Close()
|
||||||
|
if err := unix.Rmdir(f.Name()); err != nil && !os.IsNotExist(err) {
|
||||||
|
logrus.Warnf("Failed to remove %s: %v", f.Name(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
diffDirs := append([]string{p}, paths...)
|
||||||
|
for _, diffDir := range diffDirs {
|
||||||
|
// diffDir has the form $GRAPH_ROOT/overlay/$ID/diff, so grab the $ID from the parent directory
|
||||||
|
id := path.Base(path.Dir(diffDir))
|
||||||
|
composefsBlob := d.getComposefsData(id)
|
||||||
|
if fileutils.Exists(composefsBlob) != nil {
|
||||||
|
// not a composefs layer, ignore it
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dir, err := os.MkdirTemp(d.runhome, "composefs-mnt")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := mountComposefsBlob(composefsBlob, dir); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fd, err := os.Open(dir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
composefsMounts[diffDir] = fd
|
||||||
|
_ = unix.Unmount(dir, unix.MNT_DETACH)
|
||||||
|
}
|
||||||
|
return &overlayFileGetter{diffDirs: diffDirs, composefsMounts: composefsMounts}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CleanupStagingDirectory cleanups the staging directory.
|
// CleanupStagingDirectory cleanups the staging directory.
|
||||||
|
|
@ -2100,9 +2183,16 @@ func supportsDataOnlyLayersCached(home, runhome string) (bool, error) {
|
||||||
// ApplyDiffWithDiffer applies the changes in the new layer using the specified function
|
// ApplyDiffWithDiffer applies the changes in the new layer using the specified function
|
||||||
func (d *Driver) ApplyDiffWithDiffer(id, parent string, options *graphdriver.ApplyDiffWithDifferOpts, differ graphdriver.Differ) (output graphdriver.DriverWithDifferOutput, errRet error) {
|
func (d *Driver) ApplyDiffWithDiffer(id, parent string, options *graphdriver.ApplyDiffWithDifferOpts, differ graphdriver.Differ) (output graphdriver.DriverWithDifferOutput, errRet error) {
|
||||||
var idMappings *idtools.IDMappings
|
var idMappings *idtools.IDMappings
|
||||||
|
var forceMask *os.FileMode
|
||||||
|
|
||||||
if options != nil {
|
if options != nil {
|
||||||
idMappings = options.Mappings
|
idMappings = options.Mappings
|
||||||
|
forceMask = options.ForceMask
|
||||||
}
|
}
|
||||||
|
if d.options.forceMask != nil {
|
||||||
|
forceMask = d.options.forceMask
|
||||||
|
}
|
||||||
|
|
||||||
if idMappings == nil {
|
if idMappings == nil {
|
||||||
idMappings = &idtools.IDMappings{}
|
idMappings = &idtools.IDMappings{}
|
||||||
}
|
}
|
||||||
|
|
@ -2120,8 +2210,8 @@ func (d *Driver) ApplyDiffWithDiffer(id, parent string, options *graphdriver.App
|
||||||
return graphdriver.DriverWithDifferOutput{}, err
|
return graphdriver.DriverWithDifferOutput{}, err
|
||||||
}
|
}
|
||||||
perms := defaultPerms
|
perms := defaultPerms
|
||||||
if d.options.forceMask != nil {
|
if forceMask != nil {
|
||||||
perms = *d.options.forceMask
|
perms = *forceMask
|
||||||
}
|
}
|
||||||
applyDir = filepath.Join(layerDir, "dir")
|
applyDir = filepath.Join(layerDir, "dir")
|
||||||
if err := os.Mkdir(applyDir, perms); err != nil {
|
if err := os.Mkdir(applyDir, perms); err != nil {
|
||||||
|
|
@ -2155,7 +2245,7 @@ func (d *Driver) ApplyDiffWithDiffer(id, parent string, options *graphdriver.App
|
||||||
}
|
}
|
||||||
if d.usingComposefs {
|
if d.usingComposefs {
|
||||||
differOptions.Format = graphdriver.DifferOutputFormatFlat
|
differOptions.Format = graphdriver.DifferOutputFormatFlat
|
||||||
differOptions.UseFsVerity = graphdriver.DifferFsVerityEnabled
|
differOptions.UseFsVerity = graphdriver.DifferFsVerityIfAvailable
|
||||||
}
|
}
|
||||||
out, err := differ.ApplyDiff(applyDir, &archive.TarOptions{
|
out, err := differ.ApplyDiff(applyDir, &archive.TarOptions{
|
||||||
UIDMaps: idMappings.UIDs(),
|
UIDMaps: idMappings.UIDs(),
|
||||||
|
|
@ -2163,6 +2253,7 @@ func (d *Driver) ApplyDiffWithDiffer(id, parent string, options *graphdriver.App
|
||||||
IgnoreChownErrors: d.options.ignoreChownErrors,
|
IgnoreChownErrors: d.options.ignoreChownErrors,
|
||||||
WhiteoutFormat: d.getWhiteoutFormat(),
|
WhiteoutFormat: d.getWhiteoutFormat(),
|
||||||
InUserNS: unshare.IsRootless(),
|
InUserNS: unshare.IsRootless(),
|
||||||
|
ForceMask: forceMask,
|
||||||
}, &differOptions)
|
}, &differOptions)
|
||||||
|
|
||||||
out.Target = applyDir
|
out.Target = applyDir
|
||||||
|
|
@ -2342,14 +2433,18 @@ func (d *Driver) Changes(id string, idMappings *idtools.IDMappings, parent strin
|
||||||
// layers.
|
// layers.
|
||||||
diffPath, err := d.getDiffPath(id)
|
diffPath, err := d.getDiffPath(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("failed to get diff path: %w", err)
|
||||||
}
|
}
|
||||||
layers, err := d.getLowerDiffPaths(id)
|
layers, err := d.getLowerDiffPaths(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("failed to get lower diff path: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return archive.OverlayChanges(layers, diffPath)
|
c, err := archive.OverlayChanges(layers, diffPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("computing changes: %w", err)
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdditionalImageStores returns additional image stores supported by the driver
|
// AdditionalImageStores returns additional image stores supported by the driver
|
||||||
|
|
@ -2476,6 +2571,19 @@ func nameWithSuffix(name string, number int) string {
|
||||||
return fmt.Sprintf("%s%d", name, number)
|
return fmt.Sprintf("%s%d", name, number)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateOneAdditionalLayerPath(target string) error {
|
||||||
|
for _, p := range []string{
|
||||||
|
filepath.Join(target, "diff"),
|
||||||
|
filepath.Join(target, "info"),
|
||||||
|
filepath.Join(target, "blob"),
|
||||||
|
} {
|
||||||
|
if err := fileutils.Exists(p); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Driver) getAdditionalLayerPath(tocDigest digest.Digest, ref string) (string, error) {
|
func (d *Driver) getAdditionalLayerPath(tocDigest digest.Digest, ref string) (string, error) {
|
||||||
refElem := base64.StdEncoding.EncodeToString([]byte(ref))
|
refElem := base64.StdEncoding.EncodeToString([]byte(ref))
|
||||||
for _, ls := range d.options.layerStores {
|
for _, ls := range d.options.layerStores {
|
||||||
|
|
@ -2484,18 +2592,11 @@ func (d *Driver) getAdditionalLayerPath(tocDigest digest.Digest, ref string) (st
|
||||||
ref = refElem
|
ref = refElem
|
||||||
}
|
}
|
||||||
target := path.Join(ls.path, ref, tocDigest.String())
|
target := path.Join(ls.path, ref, tocDigest.String())
|
||||||
// Check if all necessary files exist
|
err := validateOneAdditionalLayerPath(target)
|
||||||
for _, p := range []string{
|
if err == nil {
|
||||||
filepath.Join(target, "diff"),
|
return target, nil
|
||||||
filepath.Join(target, "info"),
|
|
||||||
filepath.Join(target, "blob"),
|
|
||||||
} {
|
|
||||||
if err := fileutils.Exists(p); err != nil {
|
|
||||||
wrapped := fmt.Errorf("failed to stat additional layer %q: %w", p, err)
|
|
||||||
return "", fmt.Errorf("%v: %w", wrapped, graphdriver.ErrLayerUnknown)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return target, nil
|
logrus.Debugf("additional Layer Store %v failed to stat additional layer: %v", ls, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", fmt.Errorf("additional layer (%q, %q) not found: %w", tocDigest, ref, graphdriver.ErrLayerUnknown)
|
return "", fmt.Errorf("additional layer (%q, %q) not found: %w", tocDigest, ref, graphdriver.ErrLayerUnknown)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
//go:build linux && cgo
|
//go:build linux && cgo && !exclude_disk_quota
|
||||||
// +build linux,cgo
|
// +build linux,cgo,!exclude_disk_quota
|
||||||
|
|
||||||
package overlay
|
package overlay
|
||||||
|
|
||||||
18
vendor/github.com/containers/storage/drivers/overlay/overlay_disk_quota_unsupported.go
generated
vendored
Normal file
18
vendor/github.com/containers/storage/drivers/overlay/overlay_disk_quota_unsupported.go
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
//go:build linux && (!cgo || exclude_disk_quota)
|
||||||
|
// +build linux
|
||||||
|
// +build !cgo exclude_disk_quota
|
||||||
|
|
||||||
|
package overlay
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"github.com/containers/storage/pkg/directory"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReadWriteDiskUsage returns the disk usage of the writable directory for the ID.
|
||||||
|
// For Overlay, it attempts to check the XFS quota for size, and falls back to
|
||||||
|
// finding the size of the "diff" directory.
|
||||||
|
func (d *Driver) ReadWriteDiskUsage(id string) (*directory.DiskUsage, error) {
|
||||||
|
return directory.Usage(path.Join(d.dir(id), "diff"))
|
||||||
|
}
|
||||||
10
vendor/github.com/containers/storage/drivers/overlay/overlay_nocgo.go
generated
vendored
10
vendor/github.com/containers/storage/drivers/overlay/overlay_nocgo.go
generated
vendored
|
|
@ -5,18 +5,8 @@ package overlay
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path"
|
|
||||||
|
|
||||||
"github.com/containers/storage/pkg/directory"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadWriteDiskUsage returns the disk usage of the writable directory for the ID.
|
|
||||||
// For Overlay, it attempts to check the XFS quota for size, and falls back to
|
|
||||||
// finding the size of the "diff" directory.
|
|
||||||
func (d *Driver) ReadWriteDiskUsage(id string) (*directory.DiskUsage, error) {
|
|
||||||
return directory.Usage(path.Join(d.dir(id), "diff"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func getComposeFsHelper() (string, error) {
|
func getComposeFsHelper() (string, error) {
|
||||||
return "", fmt.Errorf("composefs not supported on this build")
|
return "", fmt.Errorf("composefs not supported on this build")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
11
vendor/github.com/containers/storage/drivers/quota/projectquota_supported.go
generated
vendored
11
vendor/github.com/containers/storage/drivers/quota/projectquota_supported.go
generated
vendored
|
|
@ -19,16 +19,6 @@ package quota
|
||||||
#include <linux/quota.h>
|
#include <linux/quota.h>
|
||||||
#include <linux/dqblk_xfs.h>
|
#include <linux/dqblk_xfs.h>
|
||||||
|
|
||||||
#ifndef FS_XFLAG_PROJINHERIT
|
|
||||||
struct fsxattr {
|
|
||||||
__u32 fsx_xflags;
|
|
||||||
__u32 fsx_extsize;
|
|
||||||
__u32 fsx_nextents;
|
|
||||||
__u32 fsx_projid;
|
|
||||||
unsigned char fsx_pad[12];
|
|
||||||
};
|
|
||||||
#define FS_XFLAG_PROJINHERIT 0x00000200
|
|
||||||
#endif
|
|
||||||
#ifndef FS_IOC_FSGETXATTR
|
#ifndef FS_IOC_FSGETXATTR
|
||||||
#define FS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr)
|
#define FS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr)
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -357,7 +347,6 @@ func setProjectID(targetPath string, projectID uint32) error {
|
||||||
return fmt.Errorf("failed to get projid for %s: %w", targetPath, errno)
|
return fmt.Errorf("failed to get projid for %s: %w", targetPath, errno)
|
||||||
}
|
}
|
||||||
fsx.fsx_projid = C.__u32(projectID)
|
fsx.fsx_projid = C.__u32(projectID)
|
||||||
fsx.fsx_xflags |= C.FS_XFLAG_PROJINHERIT
|
|
||||||
_, _, errno = unix.Syscall(unix.SYS_IOCTL, getDirFd(dir), C.FS_IOC_FSSETXATTR,
|
_, _, errno = unix.Syscall(unix.SYS_IOCTL, getDirFd(dir), C.FS_IOC_FSSETXATTR,
|
||||||
uintptr(unsafe.Pointer(&fsx)))
|
uintptr(unsafe.Pointer(&fsx)))
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
|
|
|
||||||
31
vendor/github.com/containers/storage/drivers/vfs/driver.go
generated
vendored
31
vendor/github.com/containers/storage/drivers/vfs/driver.go
generated
vendored
|
|
@ -33,12 +33,10 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
|
||||||
d := &Driver{
|
d := &Driver{
|
||||||
name: "vfs",
|
name: "vfs",
|
||||||
home: home,
|
home: home,
|
||||||
idMappings: idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps),
|
|
||||||
imageStore: options.ImageStore,
|
imageStore: options.ImageStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
rootIDs := d.idMappings.RootPair()
|
if err := os.MkdirAll(filepath.Join(home, "dir"), 0o700); err != nil {
|
||||||
if err := idtools.MkdirAllAndChown(filepath.Join(home, "dir"), 0o700, rootIDs); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, option := range options.DriverOptions {
|
for _, option := range options.DriverOptions {
|
||||||
|
|
@ -79,7 +77,6 @@ type Driver struct {
|
||||||
name string
|
name string
|
||||||
home string
|
home string
|
||||||
additionalHomes []string
|
additionalHomes []string
|
||||||
idMappings *idtools.IDMappings
|
|
||||||
ignoreChownErrors bool
|
ignoreChownErrors bool
|
||||||
naiveDiff graphdriver.DiffDriver
|
naiveDiff graphdriver.DiffDriver
|
||||||
updater graphdriver.LayerIDMapUpdater
|
updater graphdriver.LayerIDMapUpdater
|
||||||
|
|
@ -152,14 +149,21 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, ro bool
|
||||||
return fmt.Errorf("--storage-opt is not supported for vfs")
|
return fmt.Errorf("--storage-opt is not supported for vfs")
|
||||||
}
|
}
|
||||||
|
|
||||||
idMappings := d.idMappings
|
var uidMaps []idtools.IDMap
|
||||||
|
var gidMaps []idtools.IDMap
|
||||||
|
|
||||||
if opts != nil && opts.IDMappings != nil {
|
if opts != nil && opts.IDMappings != nil {
|
||||||
idMappings = opts.IDMappings
|
uidMaps = opts.IDMappings.UIDs()
|
||||||
|
gidMaps = opts.IDMappings.GIDs()
|
||||||
|
}
|
||||||
|
|
||||||
|
rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
dir := d.dir2(id, ro)
|
dir := d.dir2(id, ro)
|
||||||
rootIDs := idMappings.RootPair()
|
if err := os.MkdirAll(filepath.Dir(dir), 0o700); err != nil {
|
||||||
if err := idtools.MkdirAllAndChown(filepath.Dir(dir), 0o700, rootIDs); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -174,21 +178,24 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, ro bool
|
||||||
rootPerms = os.FileMode(0o700)
|
rootPerms = os.FileMode(0o700)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
idPair := idtools.IDPair{UID: rootUID, GID: rootGID}
|
||||||
if parent != "" {
|
if parent != "" {
|
||||||
st, err := system.Stat(d.dir(parent))
|
st, err := system.Stat(d.dir(parent))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rootPerms = os.FileMode(st.Mode())
|
rootPerms = os.FileMode(st.Mode())
|
||||||
rootIDs.UID = int(st.UID())
|
idPair.UID = int(st.UID())
|
||||||
rootIDs.GID = int(st.GID())
|
idPair.GID = int(st.GID())
|
||||||
}
|
}
|
||||||
if err := idtools.MkdirAndChown(dir, rootPerms, rootIDs); err != nil {
|
if err := idtools.MkdirAllAndChownNew(dir, rootPerms, idPair); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
labelOpts := []string{"level:s0"}
|
labelOpts := []string{"level:s0"}
|
||||||
if _, mountLabel, err := label.InitLabels(labelOpts); err == nil {
|
if _, mountLabel, err := label.InitLabels(labelOpts); err == nil {
|
||||||
label.SetFileLabel(dir, mountLabel)
|
if err := label.SetFileLabel(dir, mountLabel); err != nil {
|
||||||
|
logrus.Debugf("Set %s label to %q file ended with error: %v", mountLabel, dir, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if parent != "" {
|
if parent != "" {
|
||||||
parentDir, err := d.Get(parent, graphdriver.MountOpts{})
|
parentDir, err := d.Get(parent, graphdriver.MountOpts{})
|
||||||
|
|
|
||||||
20
vendor/github.com/containers/storage/drivers/zfs/zfs.go
generated
vendored
20
vendor/github.com/containers/storage/drivers/zfs/zfs.go
generated
vendored
|
|
@ -106,11 +106,7 @@ func Init(base string, opt graphdriver.Options) (graphdriver.Driver, error) {
|
||||||
return nil, fmt.Errorf("zfs get all -t filesystem -rHp '%s' should contain '%s'", options.fsName, options.fsName)
|
return nil, fmt.Errorf("zfs get all -t filesystem -rHp '%s' should contain '%s'", options.fsName, options.fsName)
|
||||||
}
|
}
|
||||||
|
|
||||||
rootUID, rootGID, err := idtools.GetRootUIDGID(opt.UIDMaps, opt.GIDMaps)
|
if err := os.MkdirAll(base, 0o700); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get root uid/gid: %w", err)
|
|
||||||
}
|
|
||||||
if err := idtools.MkdirAllAs(base, 0o700, rootUID, rootGID); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create '%s': %w", base, err)
|
return nil, fmt.Errorf("failed to create '%s': %w", base, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,8 +114,6 @@ func Init(base string, opt graphdriver.Options) (graphdriver.Driver, error) {
|
||||||
dataset: rootDataset,
|
dataset: rootDataset,
|
||||||
options: options,
|
options: options,
|
||||||
filesystemsCache: filesystemsCache,
|
filesystemsCache: filesystemsCache,
|
||||||
uidMaps: opt.UIDMaps,
|
|
||||||
gidMaps: opt.GIDMaps,
|
|
||||||
ctr: graphdriver.NewRefCounter(graphdriver.NewDefaultChecker()),
|
ctr: graphdriver.NewRefCounter(graphdriver.NewDefaultChecker()),
|
||||||
}
|
}
|
||||||
return graphdriver.NewNaiveDiffDriver(d, graphdriver.NewNaiveLayerIDMapUpdater(d)), nil
|
return graphdriver.NewNaiveDiffDriver(d, graphdriver.NewNaiveLayerIDMapUpdater(d)), nil
|
||||||
|
|
@ -177,8 +171,6 @@ type Driver struct {
|
||||||
options zfsOptions
|
options zfsOptions
|
||||||
sync.Mutex // protects filesystem cache against concurrent access
|
sync.Mutex // protects filesystem cache against concurrent access
|
||||||
filesystemsCache map[string]bool
|
filesystemsCache map[string]bool
|
||||||
uidMaps []idtools.IDMap
|
|
||||||
gidMaps []idtools.IDMap
|
|
||||||
ctr *graphdriver.RefCounter
|
ctr *graphdriver.RefCounter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -248,7 +240,9 @@ func (d *Driver) cloneFilesystem(name, parentName string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
snapshot.Destroy(zfs.DestroyDeferDeletion)
|
if err1 := snapshot.Destroy(zfs.DestroyDeferDeletion); err1 != nil {
|
||||||
|
logrus.Warnf("Destroy zfs.DestroyDeferDeletion: %v", err1)
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return snapshot.Destroy(zfs.DestroyDeferDeletion)
|
return snapshot.Destroy(zfs.DestroyDeferDeletion)
|
||||||
|
|
@ -448,12 +442,8 @@ func (d *Driver) Get(id string, options graphdriver.MountOpts) (_ string, retErr
|
||||||
opts := label.FormatMountLabel(mountOptions, options.MountLabel)
|
opts := label.FormatMountLabel(mountOptions, options.MountLabel)
|
||||||
logrus.WithField("storage-driver", "zfs").Debugf(`mount("%s", "%s", "%s")`, filesystem, mountpoint, opts)
|
logrus.WithField("storage-driver", "zfs").Debugf(`mount("%s", "%s", "%s")`, filesystem, mountpoint, opts)
|
||||||
|
|
||||||
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
// Create the target directories if they don't exist
|
// Create the target directories if they don't exist
|
||||||
if err := idtools.MkdirAllAs(mountpoint, 0o755, rootUID, rootGID); err != nil {
|
if err := os.MkdirAll(mountpoint, 0o755); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
4
vendor/github.com/containers/storage/layers.go
generated
vendored
4
vendor/github.com/containers/storage/layers.go
generated
vendored
|
|
@ -2529,7 +2529,9 @@ func (r *layerStore) applyDiffFromStagingDirectory(id string, diffOutput *driver
|
||||||
layer.GIDs = diffOutput.GIDs
|
layer.GIDs = diffOutput.GIDs
|
||||||
updateDigestMap(&r.byuncompressedsum, layer.UncompressedDigest, diffOutput.UncompressedDigest, layer.ID)
|
updateDigestMap(&r.byuncompressedsum, layer.UncompressedDigest, diffOutput.UncompressedDigest, layer.ID)
|
||||||
layer.UncompressedDigest = diffOutput.UncompressedDigest
|
layer.UncompressedDigest = diffOutput.UncompressedDigest
|
||||||
updateDigestMap(&r.bytocsum, diffOutput.TOCDigest, diffOutput.TOCDigest, layer.ID)
|
updateDigestMap(&r.bycompressedsum, layer.CompressedDigest, diffOutput.CompressedDigest, layer.ID)
|
||||||
|
layer.CompressedDigest = diffOutput.CompressedDigest
|
||||||
|
updateDigestMap(&r.bytocsum, layer.TOCDigest, diffOutput.TOCDigest, layer.ID)
|
||||||
layer.TOCDigest = diffOutput.TOCDigest
|
layer.TOCDigest = diffOutput.TOCDigest
|
||||||
layer.UncompressedSize = diffOutput.Size
|
layer.UncompressedSize = diffOutput.Size
|
||||||
layer.Metadata = diffOutput.Metadata
|
layer.Metadata = diffOutput.Metadata
|
||||||
|
|
|
||||||
2
vendor/github.com/containers/storage/lockfile_compat.go
generated
vendored
2
vendor/github.com/containers/storage/lockfile_compat.go
generated
vendored
|
|
@ -5,7 +5,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Deprecated: Use lockfile.*LockFile.
|
// Deprecated: Use lockfile.*LockFile.
|
||||||
type Locker = lockfile.Locker //lint:ignore SA1019 // lockfile.Locker is deprecated
|
type Locker = lockfile.Locker //nolint:staticcheck // SA1019 lockfile.Locker is deprecated
|
||||||
|
|
||||||
// Deprecated: Use lockfile.GetLockFile.
|
// Deprecated: Use lockfile.GetLockFile.
|
||||||
func GetLockfile(path string) (lockfile.Locker, error) {
|
func GetLockfile(path string) (lockfile.Locker, error) {
|
||||||
|
|
|
||||||
88
vendor/github.com/containers/storage/pkg/archive/archive.go
generated
vendored
88
vendor/github.com/containers/storage/pkg/archive/archive.go
generated
vendored
|
|
@ -70,6 +70,8 @@ type (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const PaxSchilyXattr = "SCHILY.xattr."
|
||||||
|
|
||||||
const (
|
const (
|
||||||
tarExt = "tar"
|
tarExt = "tar"
|
||||||
solaris = "solaris"
|
solaris = "solaris"
|
||||||
|
|
@ -169,10 +171,17 @@ func DetectCompression(source []byte) Compression {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecompressStream decompresses the archive and returns a ReaderCloser with the decompressed archive.
|
// DecompressStream decompresses the archive and returns a ReaderCloser with the decompressed archive.
|
||||||
func DecompressStream(archive io.Reader) (io.ReadCloser, error) {
|
func DecompressStream(archive io.Reader) (_ io.ReadCloser, Err error) {
|
||||||
p := pools.BufioReader32KPool
|
p := pools.BufioReader32KPool
|
||||||
buf := p.Get(archive)
|
buf := p.Get(archive)
|
||||||
bs, err := buf.Peek(10)
|
bs, err := buf.Peek(10)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if Err != nil {
|
||||||
|
p.Put(buf)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
if err != nil && err != io.EOF {
|
if err != nil && err != io.EOF {
|
||||||
// Note: we'll ignore any io.EOF error because there are some odd
|
// Note: we'll ignore any io.EOF error because there are some odd
|
||||||
// cases where the layer.tar file will be empty (zero bytes) and
|
// cases where the layer.tar file will be empty (zero bytes) and
|
||||||
|
|
@ -189,6 +198,12 @@ func DecompressStream(archive io.Reader) (io.ReadCloser, error) {
|
||||||
readBufWrapper := p.NewReadCloserWrapper(buf, buf)
|
readBufWrapper := p.NewReadCloserWrapper(buf, buf)
|
||||||
return readBufWrapper, nil
|
return readBufWrapper, nil
|
||||||
case Gzip:
|
case Gzip:
|
||||||
|
cleanup := func() {
|
||||||
|
p.Put(buf)
|
||||||
|
}
|
||||||
|
if rc, canUse := tryProcFilter([]string{"pigz", "-d"}, buf, cleanup); canUse {
|
||||||
|
return rc, nil
|
||||||
|
}
|
||||||
gzReader, err := gzip.NewReader(buf)
|
gzReader, err := gzip.NewReader(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -207,6 +222,12 @@ func DecompressStream(archive io.Reader) (io.ReadCloser, error) {
|
||||||
readBufWrapper := p.NewReadCloserWrapper(buf, xzReader)
|
readBufWrapper := p.NewReadCloserWrapper(buf, xzReader)
|
||||||
return readBufWrapper, nil
|
return readBufWrapper, nil
|
||||||
case Zstd:
|
case Zstd:
|
||||||
|
cleanup := func() {
|
||||||
|
p.Put(buf)
|
||||||
|
}
|
||||||
|
if rc, canUse := tryProcFilter([]string{"zstd", "-d"}, buf, cleanup); canUse {
|
||||||
|
return rc, nil
|
||||||
|
}
|
||||||
return zstdReader(buf)
|
return zstdReader(buf)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported compression format %s", (&compression).Extension())
|
return nil, fmt.Errorf("unsupported compression format %s", (&compression).Extension())
|
||||||
|
|
@ -214,9 +235,16 @@ func DecompressStream(archive io.Reader) (io.ReadCloser, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompressStream compresses the dest with specified compression algorithm.
|
// CompressStream compresses the dest with specified compression algorithm.
|
||||||
func CompressStream(dest io.Writer, compression Compression) (io.WriteCloser, error) {
|
func CompressStream(dest io.Writer, compression Compression) (_ io.WriteCloser, Err error) {
|
||||||
p := pools.BufioWriter32KPool
|
p := pools.BufioWriter32KPool
|
||||||
buf := p.Get(dest)
|
buf := p.Get(dest)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if Err != nil {
|
||||||
|
p.Put(buf)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
switch compression {
|
switch compression {
|
||||||
case Uncompressed:
|
case Uncompressed:
|
||||||
writeBufWrapper := p.NewWriteCloserWrapper(buf, buf)
|
writeBufWrapper := p.NewWriteCloserWrapper(buf, buf)
|
||||||
|
|
@ -391,11 +419,11 @@ func FileInfoHeader(name string, fi os.FileInfo, link string) (*tar.Header, erro
|
||||||
return hdr, nil
|
return hdr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadSecurityXattrToTarHeader reads security.capability, security,image
|
// readSecurityXattrToTarHeader reads security.capability, security,image
|
||||||
// xattrs from filesystem to a tar header
|
// xattrs from filesystem to a tar header
|
||||||
func ReadSecurityXattrToTarHeader(path string, hdr *tar.Header) error {
|
func readSecurityXattrToTarHeader(path string, hdr *tar.Header) error {
|
||||||
if hdr.Xattrs == nil {
|
if hdr.PAXRecords == nil {
|
||||||
hdr.Xattrs = make(map[string]string)
|
hdr.PAXRecords = make(map[string]string)
|
||||||
}
|
}
|
||||||
for _, xattr := range []string{"security.capability", "security.ima"} {
|
for _, xattr := range []string{"security.capability", "security.ima"} {
|
||||||
capability, err := system.Lgetxattr(path, xattr)
|
capability, err := system.Lgetxattr(path, xattr)
|
||||||
|
|
@ -403,14 +431,14 @@ func ReadSecurityXattrToTarHeader(path string, hdr *tar.Header) error {
|
||||||
return fmt.Errorf("failed to read %q attribute from %q: %w", xattr, path, err)
|
return fmt.Errorf("failed to read %q attribute from %q: %w", xattr, path, err)
|
||||||
}
|
}
|
||||||
if capability != nil {
|
if capability != nil {
|
||||||
hdr.Xattrs[xattr] = string(capability)
|
hdr.PAXRecords[PaxSchilyXattr+xattr] = string(capability)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadUserXattrToTarHeader reads user.* xattr from filesystem to a tar header
|
// readUserXattrToTarHeader reads user.* xattr from filesystem to a tar header
|
||||||
func ReadUserXattrToTarHeader(path string, hdr *tar.Header) error {
|
func readUserXattrToTarHeader(path string, hdr *tar.Header) error {
|
||||||
xattrs, err := system.Llistxattr(path)
|
xattrs, err := system.Llistxattr(path)
|
||||||
if err != nil && !errors.Is(err, system.EOPNOTSUPP) && err != system.ErrNotSupportedPlatform {
|
if err != nil && !errors.Is(err, system.EOPNOTSUPP) && err != system.ErrNotSupportedPlatform {
|
||||||
return err
|
return err
|
||||||
|
|
@ -425,10 +453,10 @@ func ReadUserXattrToTarHeader(path string, hdr *tar.Header) error {
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if hdr.Xattrs == nil {
|
if hdr.PAXRecords == nil {
|
||||||
hdr.Xattrs = make(map[string]string)
|
hdr.PAXRecords = make(map[string]string)
|
||||||
}
|
}
|
||||||
hdr.Xattrs[key] = string(value)
|
hdr.PAXRecords[PaxSchilyXattr+key] = string(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -516,10 +544,10 @@ func (ta *tarAppender) addTarFile(path, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ReadSecurityXattrToTarHeader(path, hdr); err != nil {
|
if err := readSecurityXattrToTarHeader(path, hdr); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ReadUserXattrToTarHeader(path, hdr); err != nil {
|
if err := readUserXattrToTarHeader(path, hdr); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ReadFileFlagsToTarHeader(path, hdr); err != nil {
|
if err := ReadFileFlagsToTarHeader(path, hdr); err != nil {
|
||||||
|
|
@ -642,7 +670,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case tar.TypeReg, tar.TypeRegA:
|
case tar.TypeReg:
|
||||||
// Source is regular file. We use system.OpenFileSequential to use sequential
|
// Source is regular file. We use system.OpenFileSequential to use sequential
|
||||||
// file access to avoid depleting the standby list on Windows.
|
// file access to avoid depleting the standby list on Windows.
|
||||||
// On Linux, this equates to a regular os.OpenFile
|
// On Linux, this equates to a regular os.OpenFile
|
||||||
|
|
@ -701,8 +729,11 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
|
||||||
}
|
}
|
||||||
|
|
||||||
if forceMask != nil && (hdr.Typeflag != tar.TypeSymlink || runtime.GOOS == "darwin") {
|
if forceMask != nil && (hdr.Typeflag != tar.TypeSymlink || runtime.GOOS == "darwin") {
|
||||||
value := fmt.Sprintf("%d:%d:0%o", hdr.Uid, hdr.Gid, hdrInfo.Mode()&0o7777)
|
value := idtools.Stat{
|
||||||
if err := system.Lsetxattr(path, idtools.ContainersOverrideXattr, []byte(value), 0); err != nil {
|
IDs: idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid},
|
||||||
|
Mode: hdrInfo.Mode() & 0o7777,
|
||||||
|
}
|
||||||
|
if err := idtools.SetContainersOverrideXattr(path, value); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -753,11 +784,15 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
|
||||||
}
|
}
|
||||||
|
|
||||||
var errs []string
|
var errs []string
|
||||||
for key, value := range hdr.Xattrs {
|
for key, value := range hdr.PAXRecords {
|
||||||
if _, found := xattrsToIgnore[key]; found {
|
xattrKey, ok := strings.CutPrefix(key, PaxSchilyXattr)
|
||||||
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := system.Lsetxattr(path, key, []byte(value), 0); err != nil {
|
if _, found := xattrsToIgnore[xattrKey]; found {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := system.Lsetxattr(path, xattrKey, []byte(value), 0); err != nil {
|
||||||
if errors.Is(err, syscall.ENOTSUP) || (inUserns && errors.Is(err, syscall.EPERM)) {
|
if errors.Is(err, syscall.ENOTSUP) || (inUserns && errors.Is(err, syscall.EPERM)) {
|
||||||
// We ignore errors here because not all graphdrivers support
|
// We ignore errors here because not all graphdrivers support
|
||||||
// xattrs *cough* old versions of AUFS *cough*. However only
|
// xattrs *cough* old versions of AUFS *cough*. However only
|
||||||
|
|
@ -1113,9 +1148,14 @@ loop:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.ForceMask != nil && rootHdr != nil {
|
if options.ForceMask != nil {
|
||||||
value := fmt.Sprintf("%d:%d:0%o", rootHdr.Uid, rootHdr.Gid, rootHdr.Mode)
|
value := idtools.Stat{Mode: 0o755}
|
||||||
if err := system.Lsetxattr(dest, idtools.ContainersOverrideXattr, []byte(value), 0); err != nil {
|
if rootHdr != nil {
|
||||||
|
value.IDs.UID = rootHdr.Uid
|
||||||
|
value.IDs.GID = rootHdr.Gid
|
||||||
|
value.Mode = os.FileMode(rootHdr.Mode)
|
||||||
|
}
|
||||||
|
if err := idtools.SetContainersOverrideXattr(dest, value); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1337,7 +1377,7 @@ func remapIDs(readIDMappings, writeIDMappings *idtools.IDMappings, chownOpts *id
|
||||||
}
|
}
|
||||||
} else if runtime.GOOS == darwin {
|
} else if runtime.GOOS == darwin {
|
||||||
uid, gid = hdr.Uid, hdr.Gid
|
uid, gid = hdr.Uid, hdr.Gid
|
||||||
if xstat, ok := hdr.Xattrs[idtools.ContainersOverrideXattr]; ok {
|
if xstat, ok := hdr.PAXRecords[PaxSchilyXattr+idtools.ContainersOverrideXattr]; ok {
|
||||||
attrs := strings.Split(string(xstat), ":")
|
attrs := strings.Split(string(xstat), ":")
|
||||||
if len(attrs) == 3 {
|
if len(attrs) == 3 {
|
||||||
val, err := strconv.ParseUint(attrs[0], 10, 32)
|
val, err := strconv.ParseUint(attrs[0], 10, 32)
|
||||||
|
|
|
||||||
4
vendor/github.com/containers/storage/pkg/archive/archive_bsd.go
generated
vendored
4
vendor/github.com/containers/storage/pkg/archive/archive_bsd.go
generated
vendored
|
|
@ -1,5 +1,5 @@
|
||||||
//go:build freebsd || darwin
|
//go:build netbsd || freebsd || darwin
|
||||||
// +build freebsd darwin
|
// +build netbsd freebsd darwin
|
||||||
|
|
||||||
package archive
|
package archive
|
||||||
|
|
||||||
|
|
|
||||||
4
vendor/github.com/containers/storage/pkg/archive/archive_linux.go
generated
vendored
4
vendor/github.com/containers/storage/pkg/archive/archive_linux.go
generated
vendored
|
|
@ -48,8 +48,8 @@ func (o overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(opaque) == 1 && opaque[0] == 'y' {
|
if len(opaque) == 1 && opaque[0] == 'y' {
|
||||||
if hdr.Xattrs != nil {
|
if hdr.PAXRecords != nil {
|
||||||
delete(hdr.Xattrs, getOverlayOpaqueXattrName())
|
delete(hdr.PAXRecords, PaxSchilyXattr+getOverlayOpaqueXattrName())
|
||||||
}
|
}
|
||||||
// If there are no lower layers, then it can't have been deleted in this layer.
|
// If there are no lower layers, then it can't have been deleted in this layer.
|
||||||
if len(o.rolayers) == 0 {
|
if len(o.rolayers) == 0 {
|
||||||
|
|
|
||||||
8
vendor/github.com/containers/storage/pkg/archive/changes_linux.go
generated
vendored
8
vendor/github.com/containers/storage/pkg/archive/changes_linux.go
generated
vendored
|
|
@ -316,7 +316,11 @@ func parseDirent(buf []byte, names []nameIno) (consumed int, newnames []nameIno)
|
||||||
// with respect to the parent layers
|
// with respect to the parent layers
|
||||||
func OverlayChanges(layers []string, rw string) ([]Change, error) {
|
func OverlayChanges(layers []string, rw string) ([]Change, error) {
|
||||||
dc := func(root, path string, fi os.FileInfo) (string, error) {
|
dc := func(root, path string, fi os.FileInfo) (string, error) {
|
||||||
return overlayDeletedFile(layers, root, path, fi)
|
r, err := overlayDeletedFile(layers, root, path, fi)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("overlay deleted file query: %w", err)
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
}
|
}
|
||||||
return changes(layers, rw, dc, nil, overlayLowerContainsWhiteout)
|
return changes(layers, rw, dc, nil, overlayLowerContainsWhiteout)
|
||||||
}
|
}
|
||||||
|
|
@ -351,7 +355,7 @@ func overlayDeletedFile(layers []string, root, path string, fi os.FileInfo) (str
|
||||||
// If the directory isn't marked as opaque, then it's just a normal directory.
|
// If the directory isn't marked as opaque, then it's just a normal directory.
|
||||||
opaque, err := system.Lgetxattr(filepath.Join(root, path), getOverlayOpaqueXattrName())
|
opaque, err := system.Lgetxattr(filepath.Join(root, path), getOverlayOpaqueXattrName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", fmt.Errorf("failed querying overlay opaque xattr: %w", err)
|
||||||
}
|
}
|
||||||
if len(opaque) != 1 || opaque[0] != 'y' {
|
if len(opaque) != 1 || opaque[0] != 'y' {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
|
||||||
4
vendor/github.com/containers/storage/pkg/archive/changes_unix.go
generated
vendored
4
vendor/github.com/containers/storage/pkg/archive/changes_unix.go
generated
vendored
|
|
@ -31,9 +31,9 @@ func statDifferent(oldStat *system.StatT, oldInfo *FileInfo, newStat *system.Sta
|
||||||
ownerChanged ||
|
ownerChanged ||
|
||||||
oldStat.Rdev() != newStat.Rdev() ||
|
oldStat.Rdev() != newStat.Rdev() ||
|
||||||
oldStat.Flags() != newStat.Flags() ||
|
oldStat.Flags() != newStat.Flags() ||
|
||||||
|
!sameFsTimeSpec(oldStat.Mtim(), newStat.Mtim()) ||
|
||||||
// Don't look at size for dirs, its not a good measure of change
|
// Don't look at size for dirs, its not a good measure of change
|
||||||
(oldStat.Mode()&unix.S_IFDIR != unix.S_IFDIR &&
|
((oldStat.Mode()&unix.S_IFDIR != unix.S_IFDIR) && (oldStat.Size() != newStat.Size())) {
|
||||||
(!sameFsTimeSpec(oldStat.Mtim(), newStat.Mtim()) || (oldStat.Size() != newStat.Size()))) {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
|
||||||
73
vendor/github.com/containers/storage/pkg/archive/filter.go
generated
vendored
Normal file
73
vendor/github.com/containers/storage/pkg/archive/filter.go
generated
vendored
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
package archive
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var filterPath sync.Map
|
||||||
|
|
||||||
|
func getFilterPath(name string) string {
|
||||||
|
path, ok := filterPath.Load(name)
|
||||||
|
if ok {
|
||||||
|
return path.(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
path, err := exec.LookPath(name)
|
||||||
|
if err != nil {
|
||||||
|
path = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
filterPath.Store(name, path)
|
||||||
|
return path.(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type errorRecordingReader struct {
|
||||||
|
r io.Reader
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *errorRecordingReader) Read(p []byte) (int, error) {
|
||||||
|
n, err := r.r.Read(p)
|
||||||
|
if r.err == nil && err != io.EOF {
|
||||||
|
r.err = err
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// tryProcFilter tries to run the command specified in args, passing input to its stdin and returning its stdout.
|
||||||
|
// cleanup() is a caller provided function that will be called when the command finishes running, regardless of
|
||||||
|
// whether it succeeds or fails.
|
||||||
|
// If the command is not found, it returns (nil, false) and the cleanup function is not called.
|
||||||
|
func tryProcFilter(args []string, input io.Reader, cleanup func()) (io.ReadCloser, bool) {
|
||||||
|
path := getFilterPath(args[0])
|
||||||
|
if path == "" {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
var stderrBuf bytes.Buffer
|
||||||
|
|
||||||
|
inputWithError := &errorRecordingReader{r: input}
|
||||||
|
|
||||||
|
r, w := io.Pipe()
|
||||||
|
cmd := exec.Command(path, args[1:]...)
|
||||||
|
cmd.Stdin = inputWithError
|
||||||
|
cmd.Stdout = w
|
||||||
|
cmd.Stderr = &stderrBuf
|
||||||
|
go func() {
|
||||||
|
err := cmd.Run()
|
||||||
|
// if there is an error reading from input, prefer to return that error
|
||||||
|
if inputWithError.err != nil {
|
||||||
|
err = inputWithError.err
|
||||||
|
} else if err != nil && stderrBuf.Len() > 0 {
|
||||||
|
err = fmt.Errorf("%s: %w", strings.TrimRight(stderrBuf.String(), "\n"), err)
|
||||||
|
}
|
||||||
|
w.CloseWithError(err) // CloseWithErr(nil) == Close()
|
||||||
|
cleanup()
|
||||||
|
}()
|
||||||
|
return r, true
|
||||||
|
}
|
||||||
2
vendor/github.com/containers/storage/pkg/chrootarchive/archive_darwin.go
generated
vendored
2
vendor/github.com/containers/storage/pkg/chrootarchive/archive_darwin.go
generated
vendored
|
|
@ -10,9 +10,11 @@ func invokeUnpack(decompressedArchive io.Reader,
|
||||||
dest string,
|
dest string,
|
||||||
options *archive.TarOptions, root string,
|
options *archive.TarOptions, root string,
|
||||||
) error {
|
) error {
|
||||||
|
_ = root // Restricting the operation to this root is not implemented on macOS
|
||||||
return archive.Unpack(decompressedArchive, dest, options)
|
return archive.Unpack(decompressedArchive, dest, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
func invokePack(srcPath string, options *archive.TarOptions, root string) (io.ReadCloser, error) {
|
func invokePack(srcPath string, options *archive.TarOptions, root string) (io.ReadCloser, error) {
|
||||||
|
_ = root // Restricting the operation to this root is not implemented on macOS
|
||||||
return archive.TarWithOptions(srcPath, options)
|
return archive.TarWithOptions(srcPath, options)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
7
vendor/github.com/containers/storage/pkg/chrootarchive/archive_unix.go
generated
vendored
7
vendor/github.com/containers/storage/pkg/chrootarchive/archive_unix.go
generated
vendored
|
|
@ -107,12 +107,15 @@ func invokeUnpack(decompressedArchive io.Reader, dest string, options *archive.T
|
||||||
w.Close()
|
w.Close()
|
||||||
|
|
||||||
if err := cmd.Wait(); err != nil {
|
if err := cmd.Wait(); err != nil {
|
||||||
|
errorOut := fmt.Errorf("unpacking failed (error: %w; output: %s)", err, output)
|
||||||
// when `xz -d -c -q | storage-untar ...` failed on storage-untar side,
|
// when `xz -d -c -q | storage-untar ...` failed on storage-untar side,
|
||||||
// we need to exhaust `xz`'s output, otherwise the `xz` side will be
|
// we need to exhaust `xz`'s output, otherwise the `xz` side will be
|
||||||
// pending on write pipe forever
|
// pending on write pipe forever
|
||||||
io.Copy(io.Discard, decompressedArchive)
|
if _, err := io.Copy(io.Discard, decompressedArchive); err != nil {
|
||||||
|
return fmt.Errorf("%w\nexhausting input failed (error: %w)", errorOut, err)
|
||||||
|
}
|
||||||
|
|
||||||
return fmt.Errorf("processing tar file(%s): %w", output, err)
|
return errorOut
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
5
vendor/github.com/containers/storage/pkg/chrootarchive/chroot_linux.go
generated
vendored
5
vendor/github.com/containers/storage/pkg/chrootarchive/chroot_linux.go
generated
vendored
|
|
@ -19,10 +19,13 @@ import (
|
||||||
// Old root is removed after the call to pivot_root so it is no longer available under the new root.
|
// Old root is removed after the call to pivot_root so it is no longer available under the new root.
|
||||||
// This is similar to how libcontainer sets up a container's rootfs
|
// This is similar to how libcontainer sets up a container's rootfs
|
||||||
func chroot(path string) (err error) {
|
func chroot(path string) (err error) {
|
||||||
caps, err := capability.NewPid(0)
|
caps, err := capability.NewPid2(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := caps.Load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// initialize nss libraries in Glibc so that the dynamic libraries are loaded in the host
|
// initialize nss libraries in Glibc so that the dynamic libraries are loaded in the host
|
||||||
// environment not in the chroot from untrusted files.
|
// environment not in the chroot from untrusted files.
|
||||||
|
|
|
||||||
6
vendor/github.com/containers/storage/pkg/chrootarchive/diff_unix.go
generated
vendored
6
vendor/github.com/containers/storage/pkg/chrootarchive/diff_unix.go
generated
vendored
|
|
@ -40,11 +40,13 @@ func applyLayer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to be able to set any perms
|
// We need to be able to set any perms
|
||||||
oldmask, err := system.Umask(0)
|
oldMask, err := system.Umask(0)
|
||||||
defer system.Umask(oldmask)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatal(err)
|
fatal(err)
|
||||||
}
|
}
|
||||||
|
defer func() {
|
||||||
|
_, _ = system.Umask(oldMask) // Ignore err. This can only fail with ErrNotSupportedPlatform, in which case we would have failed above.
|
||||||
|
}()
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(os.Getenv("OPT")), &options); err != nil {
|
if err := json.Unmarshal([]byte(os.Getenv("OPT")), &options); err != nil {
|
||||||
fatal(err)
|
fatal(err)
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,15 @@ package chunked
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"github.com/docker/go-units"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const bloomFilterMaxLength = 100 * units.MB // max size for bloom filter
|
||||||
|
|
||||||
type bloomFilter struct {
|
type bloomFilter struct {
|
||||||
bitArray []uint64
|
bitArray []uint64
|
||||||
k uint32
|
k uint32
|
||||||
|
|
@ -79,6 +84,10 @@ func readBloomFilter(reader io.Reader) (*bloomFilter, error) {
|
||||||
if err := binary.Read(reader, binary.LittleEndian, &k); err != nil {
|
if err := binary.Read(reader, binary.LittleEndian, &k); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// sanity check
|
||||||
|
if bloomFilterLen > bloomFilterMaxLength {
|
||||||
|
return nil, fmt.Errorf("bloom filter length %d exceeds max length %d", bloomFilterLen, bloomFilterMaxLength)
|
||||||
|
}
|
||||||
bloomFilterArray := make([]uint64, bloomFilterLen)
|
bloomFilterArray := make([]uint64, bloomFilterLen)
|
||||||
if err := binary.Read(reader, binary.LittleEndian, &bloomFilterArray); err != nil {
|
if err := binary.Read(reader, binary.LittleEndian, &bloomFilterArray); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
32
vendor/github.com/containers/storage/pkg/chunked/cache_linux.go
generated
vendored
32
vendor/github.com/containers/storage/pkg/chunked/cache_linux.go
generated
vendored
|
|
@ -18,6 +18,7 @@ import (
|
||||||
graphdriver "github.com/containers/storage/drivers"
|
graphdriver "github.com/containers/storage/drivers"
|
||||||
"github.com/containers/storage/pkg/chunked/internal"
|
"github.com/containers/storage/pkg/chunked/internal"
|
||||||
"github.com/containers/storage/pkg/ioutils"
|
"github.com/containers/storage/pkg/ioutils"
|
||||||
|
"github.com/docker/go-units"
|
||||||
jsoniter "github.com/json-iterator/go"
|
jsoniter "github.com/json-iterator/go"
|
||||||
digest "github.com/opencontainers/go-digest"
|
digest "github.com/opencontainers/go-digest"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
@ -34,6 +35,8 @@ const (
|
||||||
// https://pages.cs.wisc.edu/~cao/papers/summary-cache/node8.html
|
// https://pages.cs.wisc.edu/~cao/papers/summary-cache/node8.html
|
||||||
bloomFilterScale = 10 // how much bigger is the bloom filter than the number of entries
|
bloomFilterScale = 10 // how much bigger is the bloom filter than the number of entries
|
||||||
bloomFilterHashes = 3 // number of hash functions for the bloom filter
|
bloomFilterHashes = 3 // number of hash functions for the bloom filter
|
||||||
|
|
||||||
|
maxTagsLen = 100 * units.MB // max size for tags len
|
||||||
)
|
)
|
||||||
|
|
||||||
type cacheFile struct {
|
type cacheFile struct {
|
||||||
|
|
@ -77,7 +80,9 @@ var (
|
||||||
func (c *layer) release() {
|
func (c *layer) release() {
|
||||||
runtime.SetFinalizer(c, nil)
|
runtime.SetFinalizer(c, nil)
|
||||||
if c.mmapBuffer != nil {
|
if c.mmapBuffer != nil {
|
||||||
unix.Munmap(c.mmapBuffer)
|
if err := unix.Munmap(c.mmapBuffer); err != nil {
|
||||||
|
logrus.Warnf("Error Munmap: layer %q: %v", c.id, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,7 +194,9 @@ func (c *layersCache) loadLayerCache(layerID string) (_ *layer, errRet error) {
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if errRet != nil && mmapBuffer != nil {
|
if errRet != nil && mmapBuffer != nil {
|
||||||
unix.Munmap(mmapBuffer)
|
if err := unix.Munmap(mmapBuffer); err != nil {
|
||||||
|
logrus.Warnf("Error Munmap: layer %q: %v", layerID, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
cacheFile, err := readCacheFileFromMemory(buffer)
|
cacheFile, err := readCacheFileFromMemory(buffer)
|
||||||
|
|
@ -280,6 +287,13 @@ func (c *layersCache) load() error {
|
||||||
newLayers = append(newLayers, l)
|
newLayers = append(newLayers, l)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if r.ReadOnly {
|
||||||
|
// if the layer is coming from a read-only store, do not attempt
|
||||||
|
// to write to it.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// the cache file is either not present or broken. Try to generate it from the TOC.
|
// the cache file is either not present or broken. Try to generate it from the TOC.
|
||||||
l, err = c.createCacheFileFromTOC(r.ID)
|
l, err = c.createCacheFileFromTOC(r.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -635,6 +649,14 @@ func readCacheFileFromMemory(bigDataBuffer []byte) (*cacheFile, error) {
|
||||||
if err := binary.Read(bigData, binary.LittleEndian, &fnamesLen); err != nil {
|
if err := binary.Read(bigData, binary.LittleEndian, &fnamesLen); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tagsLen > maxTagsLen {
|
||||||
|
return nil, fmt.Errorf("tags len %d exceeds the maximum allowed size %d", tagsLen, maxTagsLen)
|
||||||
|
}
|
||||||
|
if digestLen > tagLen {
|
||||||
|
return nil, fmt.Errorf("digest len %d exceeds the tag len %d", digestLen, tagLen)
|
||||||
|
}
|
||||||
|
|
||||||
tags := make([]byte, tagsLen)
|
tags := make([]byte, tagsLen)
|
||||||
if _, err := bigData.Read(tags); err != nil {
|
if _, err := bigData.Read(tags); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -643,6 +665,10 @@ func readCacheFileFromMemory(bigDataBuffer []byte) (*cacheFile, error) {
|
||||||
// retrieve the unread part of the buffer.
|
// retrieve the unread part of the buffer.
|
||||||
remaining := bigDataBuffer[len(bigDataBuffer)-bigData.Len():]
|
remaining := bigDataBuffer[len(bigDataBuffer)-bigData.Len():]
|
||||||
|
|
||||||
|
if vdataLen >= uint64(len(remaining)) {
|
||||||
|
return nil, fmt.Errorf("vdata len %d exceeds the remaining buffer size %d", vdataLen, len(remaining))
|
||||||
|
}
|
||||||
|
|
||||||
vdata := remaining[:vdataLen]
|
vdata := remaining[:vdataLen]
|
||||||
fnames := remaining[vdataLen:]
|
fnames := remaining[vdataLen:]
|
||||||
|
|
||||||
|
|
@ -901,7 +927,7 @@ func unmarshalToc(manifest []byte) (*internal.TOC, error) {
|
||||||
s := iter.ReadString()
|
s := iter.ReadString()
|
||||||
d, err := digest.Parse(s)
|
d, err := digest.Parse(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Invalid tarSplitDigest %q: %w", s, err)
|
return nil, fmt.Errorf("invalid tarSplitDigest %q: %w", s, err)
|
||||||
}
|
}
|
||||||
toc.TarSplitDigest = d
|
toc.TarSplitDigest = d
|
||||||
|
|
||||||
|
|
|
||||||
149
vendor/github.com/containers/storage/pkg/chunked/compression_linux.go
generated
vendored
149
vendor/github.com/containers/storage/pkg/chunked/compression_linux.go
generated
vendored
|
|
@ -5,13 +5,16 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"maps"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/containers/storage/pkg/chunked/internal"
|
"github.com/containers/storage/pkg/chunked/internal"
|
||||||
"github.com/klauspost/compress/zstd"
|
"github.com/klauspost/compress/zstd"
|
||||||
"github.com/klauspost/pgzip"
|
"github.com/klauspost/pgzip"
|
||||||
digest "github.com/opencontainers/go-digest"
|
digest "github.com/opencontainers/go-digest"
|
||||||
"github.com/vbatts/tar-split/archive/tar"
|
"github.com/vbatts/tar-split/archive/tar"
|
||||||
|
expMaps "golang.org/x/exp/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
var typesToTar = map[string]byte{
|
var typesToTar = map[string]byte{
|
||||||
|
|
@ -209,20 +212,162 @@ func readZstdChunkedManifest(blobStream ImageSourceSeekable, tocDigest digest.Di
|
||||||
}
|
}
|
||||||
|
|
||||||
decodedTarSplit := []byte{}
|
decodedTarSplit := []byte{}
|
||||||
if tarSplitChunk.Offset > 0 {
|
if toc.TarSplitDigest != "" {
|
||||||
|
if tarSplitChunk.Offset <= 0 {
|
||||||
|
return nil, nil, nil, 0, fmt.Errorf("TOC requires a tar-split, but the %s annotation does not describe a position", internal.TarSplitInfoKey)
|
||||||
|
}
|
||||||
tarSplit, err := readBlob(tarSplitChunk.Length)
|
tarSplit, err := readBlob(tarSplitChunk.Length)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, 0, err
|
return nil, nil, nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
decodedTarSplit, err = decodeAndValidateBlob(tarSplit, tarSplitLengthUncompressed, toc.TarSplitDigest.String())
|
decodedTarSplit, err = decodeAndValidateBlob(tarSplit, tarSplitLengthUncompressed, toc.TarSplitDigest.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, 0, fmt.Errorf("validating and decompressing tar-split: %w", err)
|
return nil, nil, nil, 0, fmt.Errorf("validating and decompressing tar-split: %w", err)
|
||||||
}
|
}
|
||||||
|
// We use the TOC for creating on-disk files, but the tar-split for creating metadata
|
||||||
|
// when exporting the layer contents. Ensure the two match, otherwise local inspection of a container
|
||||||
|
// might be misleading about the exported contents.
|
||||||
|
if err := ensureTOCMatchesTarSplit(toc, decodedTarSplit); err != nil {
|
||||||
|
return nil, nil, nil, 0, fmt.Errorf("tar-split and TOC data is inconsistent: %w", err)
|
||||||
|
}
|
||||||
|
} else if tarSplitChunk.Offset > 0 {
|
||||||
|
// We must ignore the tar-split when the digest is not present in the TOC, because we can’t authenticate it.
|
||||||
|
//
|
||||||
|
// But if we asked for the chunk, now we must consume the data to not block the producer.
|
||||||
|
// Ideally the GetBlobAt API should be changed so that this is not necessary.
|
||||||
|
_, err := readBlob(tarSplitChunk.Length)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, 0, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return decodedBlob, toc, decodedTarSplit, int64(manifestChunk.Offset), err
|
return decodedBlob, toc, decodedTarSplit, int64(manifestChunk.Offset), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensureTOCMatchesTarSplit validates that toc and tarSplit contain _exactly_ the same entries.
|
||||||
|
func ensureTOCMatchesTarSplit(toc *internal.TOC, tarSplit []byte) error {
|
||||||
|
pendingFiles := map[string]*internal.FileMetadata{} // Name -> an entry in toc.Entries
|
||||||
|
for i := range toc.Entries {
|
||||||
|
e := &toc.Entries[i]
|
||||||
|
if e.Type != internal.TypeChunk {
|
||||||
|
if _, ok := pendingFiles[e.Name]; ok {
|
||||||
|
return fmt.Errorf("TOC contains duplicate entries for path %q", e.Name)
|
||||||
|
}
|
||||||
|
pendingFiles[e.Name] = e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := iterateTarSplit(tarSplit, func(hdr *tar.Header) error {
|
||||||
|
e, ok := pendingFiles[hdr.Name]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("tar-split contains an entry for %q missing in TOC", hdr.Name)
|
||||||
|
}
|
||||||
|
delete(pendingFiles, hdr.Name)
|
||||||
|
expected, err := internal.NewFileMetadata(hdr)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("determining expected metadata for %q: %w", hdr.Name, err)
|
||||||
|
}
|
||||||
|
if err := ensureFileMetadataAttributesMatch(e, &expected); err != nil {
|
||||||
|
return fmt.Errorf("TOC and tar-split metadata doesn’t match: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(pendingFiles) != 0 {
|
||||||
|
remaining := expMaps.Keys(pendingFiles)
|
||||||
|
if len(remaining) > 5 {
|
||||||
|
remaining = remaining[:5] // Just to limit the size of the output.
|
||||||
|
}
|
||||||
|
return fmt.Errorf("TOC contains entries not present in tar-split, incl. %q", remaining)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensureTimePointersMatch ensures that a and b are equal
|
||||||
|
func ensureTimePointersMatch(a, b *time.Time) error {
|
||||||
|
// We didn’t always use “timeIfNotZero” when creating the TOC, so treat time.IsZero the same as nil.
|
||||||
|
// The archive/tar code turns time.IsZero() timestamps into an Unix timestamp of 0 when writing, but turns an Unix timestamp of 0
|
||||||
|
// when writing into a (local-timezone) Jan 1 1970, which is not IsZero(). So, treat that the same as IsZero as well.
|
||||||
|
unixZero := time.Unix(0, 0)
|
||||||
|
if a != nil && (a.IsZero() || a.Equal(unixZero)) {
|
||||||
|
a = nil
|
||||||
|
}
|
||||||
|
if b != nil && (b.IsZero() || b.Equal(unixZero)) {
|
||||||
|
b = nil
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case a == nil && b == nil:
|
||||||
|
return nil
|
||||||
|
case a == nil:
|
||||||
|
return fmt.Errorf("nil != %v", *b)
|
||||||
|
case b == nil:
|
||||||
|
return fmt.Errorf("%v != nil", *a)
|
||||||
|
default:
|
||||||
|
if a.Equal(*b) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("%v != %v", *a, *b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensureFileMetadataAttributesMatch ensures that a and b match in file attributes (it ignores entries relevant to locating data
|
||||||
|
// in the tar stream or matching contents)
|
||||||
|
func ensureFileMetadataAttributesMatch(a, b *internal.FileMetadata) error {
|
||||||
|
// Keep this in sync with internal.FileMetadata!
|
||||||
|
|
||||||
|
if a.Type != b.Type {
|
||||||
|
return fmt.Errorf("mismatch of Type: %q != %q", a.Type, b.Type)
|
||||||
|
}
|
||||||
|
if a.Name != b.Name {
|
||||||
|
return fmt.Errorf("mismatch of Name: %q != %q", a.Name, b.Name)
|
||||||
|
}
|
||||||
|
if a.Linkname != b.Linkname {
|
||||||
|
return fmt.Errorf("mismatch of Linkname: %q != %q", a.Linkname, b.Linkname)
|
||||||
|
}
|
||||||
|
if a.Mode != b.Mode {
|
||||||
|
return fmt.Errorf("mismatch of Mode: %q != %q", a.Mode, b.Mode)
|
||||||
|
}
|
||||||
|
if a.Size != b.Size {
|
||||||
|
return fmt.Errorf("mismatch of Size: %q != %q", a.Size, b.Size)
|
||||||
|
}
|
||||||
|
if a.UID != b.UID {
|
||||||
|
return fmt.Errorf("mismatch of UID: %q != %q", a.UID, b.UID)
|
||||||
|
}
|
||||||
|
if a.GID != b.GID {
|
||||||
|
return fmt.Errorf("mismatch of GID: %q != %q", a.GID, b.GID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ensureTimePointersMatch(a.ModTime, b.ModTime); err != nil {
|
||||||
|
return fmt.Errorf("mismatch of ModTime: %w", err)
|
||||||
|
}
|
||||||
|
if err := ensureTimePointersMatch(a.AccessTime, b.AccessTime); err != nil {
|
||||||
|
return fmt.Errorf("mismatch of AccessTime: %w", err)
|
||||||
|
}
|
||||||
|
if err := ensureTimePointersMatch(a.ChangeTime, b.ChangeTime); err != nil {
|
||||||
|
return fmt.Errorf("mismatch of ChangeTime: %w", err)
|
||||||
|
}
|
||||||
|
if a.Devmajor != b.Devmajor {
|
||||||
|
return fmt.Errorf("mismatch of Devmajor: %q != %q", a.Devmajor, b.Devmajor)
|
||||||
|
}
|
||||||
|
if a.Devminor != b.Devminor {
|
||||||
|
return fmt.Errorf("mismatch of Devminor: %q != %q", a.Devminor, b.Devminor)
|
||||||
|
}
|
||||||
|
if !maps.Equal(a.Xattrs, b.Xattrs) {
|
||||||
|
return fmt.Errorf("mismatch of Xattrs: %q != %q", a.Xattrs, b.Xattrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Digest is not compared
|
||||||
|
// Offset is not compared
|
||||||
|
// EndOffset is not compared
|
||||||
|
|
||||||
|
// ChunkSize is not compared
|
||||||
|
// ChunkOffset is not compared
|
||||||
|
// ChunkDigest is not compared
|
||||||
|
// ChunkType is not compared
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func decodeAndValidateBlob(blob []byte, lengthUncompressed uint64, expectedCompressedChecksum string) ([]byte, error) {
|
func decodeAndValidateBlob(blob []byte, lengthUncompressed uint64, expectedCompressedChecksum string) ([]byte, error) {
|
||||||
d, err := digest.Parse(expectedCompressedChecksum)
|
d, err := digest.Parse(expectedCompressedChecksum)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
31
vendor/github.com/containers/storage/pkg/chunked/compressor/compressor.go
generated
vendored
31
vendor/github.com/containers/storage/pkg/chunked/compressor/compressor.go
generated
vendored
|
|
@ -7,7 +7,6 @@ package compressor
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/base64"
|
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/containers/storage/pkg/chunked/internal"
|
"github.com/containers/storage/pkg/chunked/internal"
|
||||||
|
|
@ -369,34 +368,14 @@ func writeZstdChunkedStream(destFile io.Writer, outMetadata map[string]string, r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typ, err := internal.GetType(hdr.Typeflag)
|
mainEntry, err := internal.NewFileMetadata(hdr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
xattrs := make(map[string]string)
|
mainEntry.Digest = checksum
|
||||||
for k, v := range hdr.Xattrs {
|
mainEntry.Offset = startOffset
|
||||||
xattrs[k] = base64.StdEncoding.EncodeToString([]byte(v))
|
mainEntry.EndOffset = lastOffset
|
||||||
}
|
entries := []internal.FileMetadata{mainEntry}
|
||||||
entries := []internal.FileMetadata{
|
|
||||||
{
|
|
||||||
Type: typ,
|
|
||||||
Name: hdr.Name,
|
|
||||||
Linkname: hdr.Linkname,
|
|
||||||
Mode: hdr.Mode,
|
|
||||||
Size: hdr.Size,
|
|
||||||
UID: hdr.Uid,
|
|
||||||
GID: hdr.Gid,
|
|
||||||
ModTime: &hdr.ModTime,
|
|
||||||
AccessTime: &hdr.AccessTime,
|
|
||||||
ChangeTime: &hdr.ChangeTime,
|
|
||||||
Devmajor: hdr.Devmajor,
|
|
||||||
Devminor: hdr.Devminor,
|
|
||||||
Xattrs: xattrs,
|
|
||||||
Digest: checksum,
|
|
||||||
Offset: startOffset,
|
|
||||||
EndOffset: lastOffset,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for i := 1; i < len(chunks); i++ {
|
for i := 1; i < len(chunks); i++ {
|
||||||
entries = append(entries, internal.FileMetadata{
|
entries = append(entries, internal.FileMetadata{
|
||||||
Type: internal.TypeChunk,
|
Type: internal.TypeChunk,
|
||||||
|
|
|
||||||
77
vendor/github.com/containers/storage/pkg/chunked/dump/dump.go
generated
vendored
77
vendor/github.com/containers/storage/pkg/chunked/dump/dump.go
generated
vendored
|
|
@ -1,13 +1,16 @@
|
||||||
|
//go:build unix
|
||||||
|
|
||||||
package dump
|
package dump
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"unicode"
|
|
||||||
|
|
||||||
"github.com/containers/storage/pkg/chunked/internal"
|
"github.com/containers/storage/pkg/chunked/internal"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
|
|
@ -20,20 +23,26 @@ const (
|
||||||
ESCAPE_LONE_DASH
|
ESCAPE_LONE_DASH
|
||||||
)
|
)
|
||||||
|
|
||||||
func escaped(val string, escape int) string {
|
func escaped(val []byte, escape int) string {
|
||||||
noescapeSpace := escape&NOESCAPE_SPACE != 0
|
noescapeSpace := escape&NOESCAPE_SPACE != 0
|
||||||
escapeEqual := escape&ESCAPE_EQUAL != 0
|
escapeEqual := escape&ESCAPE_EQUAL != 0
|
||||||
escapeLoneDash := escape&ESCAPE_LONE_DASH != 0
|
escapeLoneDash := escape&ESCAPE_LONE_DASH != 0
|
||||||
|
|
||||||
length := len(val)
|
if escapeLoneDash && len(val) == 1 && val[0] == '-' {
|
||||||
|
|
||||||
if escapeLoneDash && val == "-" {
|
|
||||||
return fmt.Sprintf("\\x%.2x", val[0])
|
return fmt.Sprintf("\\x%.2x", val[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is intended to match the C isprint API with LC_CTYPE=C
|
||||||
|
isprint := func(c byte) bool {
|
||||||
|
return c >= 32 && c < 127
|
||||||
|
}
|
||||||
|
// This is intended to match the C isgraph API with LC_CTYPE=C
|
||||||
|
isgraph := func(c byte) bool {
|
||||||
|
return c > 32 && c < 127
|
||||||
|
}
|
||||||
|
|
||||||
var result string
|
var result string
|
||||||
for i := 0; i < length; i++ {
|
for _, c := range []byte(val) {
|
||||||
c := val[i]
|
|
||||||
hexEscape := false
|
hexEscape := false
|
||||||
var special string
|
var special string
|
||||||
|
|
||||||
|
|
@ -50,9 +59,9 @@ func escaped(val string, escape int) string {
|
||||||
hexEscape = escapeEqual
|
hexEscape = escapeEqual
|
||||||
default:
|
default:
|
||||||
if noescapeSpace {
|
if noescapeSpace {
|
||||||
hexEscape = !unicode.IsPrint(rune(c))
|
hexEscape = !isprint(c)
|
||||||
} else {
|
} else {
|
||||||
hexEscape = !unicode.IsPrint(rune(c)) || unicode.IsSpace(rune(c))
|
hexEscape = !isgraph(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,8 +76,8 @@ func escaped(val string, escape int) string {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func escapedOptional(val string, escape int) string {
|
func escapedOptional(val []byte, escape int) string {
|
||||||
if val == "" {
|
if len(val) == 0 {
|
||||||
return "-"
|
return "-"
|
||||||
}
|
}
|
||||||
return escaped(val, escape)
|
return escaped(val, escape)
|
||||||
|
|
@ -104,10 +113,31 @@ func sanitizeName(name string) string {
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
func dumpNode(out io.Writer, links map[string]int, verityDigests map[string]string, entry *internal.FileMetadata) error {
|
func dumpNode(out io.Writer, added map[string]*internal.FileMetadata, links map[string]int, verityDigests map[string]string, entry *internal.FileMetadata) error {
|
||||||
path := sanitizeName(entry.Name)
|
path := sanitizeName(entry.Name)
|
||||||
|
|
||||||
if _, err := fmt.Fprint(out, escaped(path, ESCAPE_STANDARD)); err != nil {
|
parent := filepath.Dir(path)
|
||||||
|
if _, found := added[parent]; !found && path != "/" {
|
||||||
|
parentEntry := &internal.FileMetadata{
|
||||||
|
Name: parent,
|
||||||
|
Type: internal.TypeDir,
|
||||||
|
Mode: 0o755,
|
||||||
|
}
|
||||||
|
if err := dumpNode(out, added, links, verityDigests, parentEntry); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if e, found := added[path]; found {
|
||||||
|
// if the entry was already added, make sure it has the same data
|
||||||
|
if !reflect.DeepEqual(*e, *entry) {
|
||||||
|
return fmt.Errorf("entry %q already added with different data", path)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
added[path] = entry
|
||||||
|
|
||||||
|
if _, err := fmt.Fprint(out, escaped([]byte(path), ESCAPE_STANDARD)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,7 +181,7 @@ func dumpNode(out io.Writer, links map[string]int, verityDigests map[string]stri
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := fmt.Fprintf(out, escapedOptional(payload, ESCAPE_LONE_DASH)); err != nil {
|
if _, err := fmt.Fprint(out, escapedOptional([]byte(payload), ESCAPE_LONE_DASH)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -165,14 +195,18 @@ func dumpNode(out io.Writer, links map[string]int, verityDigests map[string]stri
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
digest := verityDigests[payload]
|
digest := verityDigests[payload]
|
||||||
if _, err := fmt.Fprintf(out, escapedOptional(digest, ESCAPE_LONE_DASH)); err != nil {
|
if _, err := fmt.Fprint(out, escapedOptional([]byte(digest), ESCAPE_LONE_DASH)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range entry.Xattrs {
|
for k, vEncoded := range entry.Xattrs {
|
||||||
name := escaped(k, ESCAPE_EQUAL)
|
v, err := base64.StdEncoding.DecodeString(vEncoded)
|
||||||
value := escaped(v, ESCAPE_EQUAL)
|
if err != nil {
|
||||||
|
return fmt.Errorf("decode xattr %q: %w", k, err)
|
||||||
|
}
|
||||||
|
name := escaped([]byte(k), ESCAPE_EQUAL)
|
||||||
|
|
||||||
|
value := escaped(v, ESCAPE_EQUAL)
|
||||||
if _, err := fmt.Fprintf(out, " %s=%s", name, value); err != nil {
|
if _, err := fmt.Fprintf(out, " %s=%s", name, value); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -201,6 +235,7 @@ func GenerateDump(tocI interface{}, verityDigests map[string]string) (io.Reader,
|
||||||
}()
|
}()
|
||||||
|
|
||||||
links := make(map[string]int)
|
links := make(map[string]int)
|
||||||
|
added := make(map[string]*internal.FileMetadata)
|
||||||
for _, e := range toc.Entries {
|
for _, e := range toc.Entries {
|
||||||
if e.Linkname == "" {
|
if e.Linkname == "" {
|
||||||
continue
|
continue
|
||||||
|
|
@ -211,14 +246,14 @@ func GenerateDump(tocI interface{}, verityDigests map[string]string) (io.Reader,
|
||||||
links[e.Linkname] = links[e.Linkname] + 1
|
links[e.Linkname] = links[e.Linkname] + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(toc.Entries) == 0 || (sanitizeName(toc.Entries[0].Name) != "/") {
|
if len(toc.Entries) == 0 {
|
||||||
root := &internal.FileMetadata{
|
root := &internal.FileMetadata{
|
||||||
Name: "/",
|
Name: "/",
|
||||||
Type: internal.TypeDir,
|
Type: internal.TypeDir,
|
||||||
Mode: 0o755,
|
Mode: 0o755,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := dumpNode(w, links, verityDigests, root); err != nil {
|
if err := dumpNode(w, added, links, verityDigests, root); err != nil {
|
||||||
pipeW.CloseWithError(err)
|
pipeW.CloseWithError(err)
|
||||||
closed = true
|
closed = true
|
||||||
return
|
return
|
||||||
|
|
@ -229,7 +264,7 @@ func GenerateDump(tocI interface{}, verityDigests map[string]string) (io.Reader,
|
||||||
if e.Type == internal.TypeChunk {
|
if e.Type == internal.TypeChunk {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := dumpNode(w, links, verityDigests, &e); err != nil {
|
if err := dumpNode(w, added, links, verityDigests, &e); err != nil {
|
||||||
pipeW.CloseWithError(err)
|
pipeW.CloseWithError(err)
|
||||||
closed = true
|
closed = true
|
||||||
return
|
return
|
||||||
|
|
|
||||||
605
vendor/github.com/containers/storage/pkg/chunked/filesystem_linux.go
generated
vendored
Normal file
605
vendor/github.com/containers/storage/pkg/chunked/filesystem_linux.go
generated
vendored
Normal file
|
|
@ -0,0 +1,605 @@
|
||||||
|
package chunked
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"sync/atomic"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
driversCopy "github.com/containers/storage/drivers/copy"
|
||||||
|
"github.com/containers/storage/pkg/archive"
|
||||||
|
"github.com/containers/storage/pkg/chunked/internal"
|
||||||
|
securejoin "github.com/cyphar/filepath-securejoin"
|
||||||
|
"github.com/vbatts/tar-split/archive/tar"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// procPathForFile returns an absolute path in /proc which
|
||||||
|
// refers to the file; see procPathForFd.
|
||||||
|
func procPathForFile(f *os.File) string {
|
||||||
|
return procPathForFd(int(f.Fd()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// procPathForFd returns an absolute path in /proc which
|
||||||
|
// refers to the file; this allows passing a file descriptor
|
||||||
|
// in places that don't accept a file descriptor.
|
||||||
|
func procPathForFd(fd int) string {
|
||||||
|
return fmt.Sprintf("/proc/self/fd/%d", fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fileMetadata is a wrapper around internal.FileMetadata with additional private fields that
|
||||||
|
// are not part of the TOC document.
|
||||||
|
// Type: TypeChunk entries are stored in Chunks, the primary [fileMetadata] entries never use TypeChunk.
|
||||||
|
type fileMetadata struct {
|
||||||
|
internal.FileMetadata
|
||||||
|
|
||||||
|
// chunks stores the TypeChunk entries relevant to this entry when FileMetadata.Type == TypeReg.
|
||||||
|
chunks []*internal.FileMetadata
|
||||||
|
|
||||||
|
// skipSetAttrs is set when the file attributes must not be
|
||||||
|
// modified, e.g. it is a hard link from a different source,
|
||||||
|
// or a composefs file.
|
||||||
|
skipSetAttrs bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func doHardLink(dirfd, srcFd int, destFile string) error {
|
||||||
|
destDir, destBase := filepath.Split(destFile)
|
||||||
|
destDirFd := dirfd
|
||||||
|
if destDir != "" && destDir != "." {
|
||||||
|
f, err := openOrCreateDirUnderRoot(dirfd, destDir, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
destDirFd = int(f.Fd())
|
||||||
|
}
|
||||||
|
|
||||||
|
doLink := func() error {
|
||||||
|
// Using unix.AT_EMPTY_PATH requires CAP_DAC_READ_SEARCH while this variant that uses
|
||||||
|
// /proc/self/fd doesn't and can be used with rootless.
|
||||||
|
srcPath := procPathForFd(srcFd)
|
||||||
|
err := unix.Linkat(unix.AT_FDCWD, srcPath, destDirFd, destBase, unix.AT_SYMLINK_FOLLOW)
|
||||||
|
if err != nil {
|
||||||
|
return &fs.PathError{Op: "linkat", Path: destFile, Err: err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := doLink()
|
||||||
|
|
||||||
|
// if the destination exists, unlink it first and try again
|
||||||
|
if err != nil && os.IsExist(err) {
|
||||||
|
if err := unix.Unlinkat(destDirFd, destBase, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return doLink()
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyFileContent(srcFd int, fileMetadata *fileMetadata, dirfd int, mode os.FileMode, useHardLinks bool) (*os.File, int64, error) {
|
||||||
|
destFile := fileMetadata.Name
|
||||||
|
src := procPathForFd(srcFd)
|
||||||
|
st, err := os.Stat(src)
|
||||||
|
if err != nil {
|
||||||
|
return nil, -1, fmt.Errorf("copy file content for %q: %w", destFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
copyWithFileRange, copyWithFileClone := true, true
|
||||||
|
|
||||||
|
if useHardLinks {
|
||||||
|
err := doHardLink(dirfd, srcFd, destFile)
|
||||||
|
if err == nil {
|
||||||
|
// if the file was deduplicated with a hard link, skip overriding file metadata.
|
||||||
|
fileMetadata.skipSetAttrs = true
|
||||||
|
return nil, st.Size(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the destination file already exists, we shouldn't blow it away
|
||||||
|
dstFile, err := openFileUnderRoot(dirfd, destFile, newFileFlags, mode)
|
||||||
|
if err != nil {
|
||||||
|
return nil, -1, fmt.Errorf("open file %q under rootfs for copy: %w", destFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = driversCopy.CopyRegularToFile(src, dstFile, st, ©WithFileRange, ©WithFileClone)
|
||||||
|
if err != nil {
|
||||||
|
dstFile.Close()
|
||||||
|
return nil, -1, fmt.Errorf("copy to file %q under rootfs: %w", destFile, err)
|
||||||
|
}
|
||||||
|
return dstFile, st.Size(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func timeToTimespec(time *time.Time) (ts unix.Timespec) {
|
||||||
|
if time == nil || time.IsZero() {
|
||||||
|
// Return UTIME_OMIT special value
|
||||||
|
ts.Sec = 0
|
||||||
|
ts.Nsec = ((1 << 30) - 2)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return unix.NsecToTimespec(time.UnixNano())
|
||||||
|
}
|
||||||
|
|
||||||
|
// chown changes the owner and group of the file at the specified path under the directory
|
||||||
|
// pointed by dirfd.
|
||||||
|
// If nofollow is true, the function will not follow symlinks.
|
||||||
|
// If path is empty, the function will change the owner and group of the file descriptor.
|
||||||
|
// absolutePath is the absolute path of the file, used only for error messages.
|
||||||
|
func chown(dirfd int, path string, uid, gid int, nofollow bool, absolutePath string) error {
|
||||||
|
var err error
|
||||||
|
flags := 0
|
||||||
|
if nofollow {
|
||||||
|
flags |= unix.AT_SYMLINK_NOFOLLOW
|
||||||
|
} else if path == "" {
|
||||||
|
flags |= unix.AT_EMPTY_PATH
|
||||||
|
}
|
||||||
|
err = unix.Fchownat(dirfd, path, uid, gid, flags)
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if errors.Is(err, syscall.EINVAL) {
|
||||||
|
return fmt.Errorf(`potentially insufficient UIDs or GIDs available in the user namespace (requested %d:%d for %s): Check /etc/subuid and /etc/subgid if configured locally and run "podman system migrate": %w`, uid, gid, path, err)
|
||||||
|
}
|
||||||
|
return &fs.PathError{Op: "fchownat", Path: absolutePath, Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setFileAttrs sets the file attributes for file given metadata
|
||||||
|
func setFileAttrs(dirfd int, file *os.File, mode os.FileMode, metadata *fileMetadata, options *archive.TarOptions, usePath bool) error {
|
||||||
|
if metadata.skipSetAttrs {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if file == nil {
|
||||||
|
return errors.New("invalid file")
|
||||||
|
}
|
||||||
|
fd := int(file.Fd())
|
||||||
|
|
||||||
|
t, err := typeToTarType(metadata.Type)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it is a symlink, force to use the path
|
||||||
|
if t == tar.TypeSymlink {
|
||||||
|
usePath = true
|
||||||
|
}
|
||||||
|
|
||||||
|
baseName := ""
|
||||||
|
if usePath {
|
||||||
|
dirName := filepath.Dir(metadata.Name)
|
||||||
|
if dirName != "" {
|
||||||
|
parentFd, err := openFileUnderRoot(dirfd, dirName, unix.O_PATH|unix.O_DIRECTORY, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer parentFd.Close()
|
||||||
|
|
||||||
|
dirfd = int(parentFd.Fd())
|
||||||
|
}
|
||||||
|
baseName = filepath.Base(metadata.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
doChown := func() error {
|
||||||
|
var err error
|
||||||
|
if usePath {
|
||||||
|
err = chown(dirfd, baseName, metadata.UID, metadata.GID, true, metadata.Name)
|
||||||
|
} else {
|
||||||
|
err = chown(fd, "", metadata.UID, metadata.GID, false, metadata.Name)
|
||||||
|
}
|
||||||
|
if options.IgnoreChownErrors {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
doSetXattr := func(k string, v []byte) error {
|
||||||
|
err := unix.Fsetxattr(fd, k, v, 0)
|
||||||
|
if err != nil {
|
||||||
|
return &fs.PathError{Op: "fsetxattr", Path: metadata.Name, Err: err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
doUtimes := func() error {
|
||||||
|
ts := []unix.Timespec{timeToTimespec(metadata.AccessTime), timeToTimespec(metadata.ModTime)}
|
||||||
|
var err error
|
||||||
|
if usePath {
|
||||||
|
err = unix.UtimesNanoAt(dirfd, baseName, ts, unix.AT_SYMLINK_NOFOLLOW)
|
||||||
|
} else {
|
||||||
|
err = unix.UtimesNanoAt(unix.AT_FDCWD, procPathForFd(fd), ts, 0)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return &fs.PathError{Op: "utimensat", Path: metadata.Name, Err: err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
doChmod := func() error {
|
||||||
|
var err error
|
||||||
|
op := ""
|
||||||
|
if usePath {
|
||||||
|
err = unix.Fchmodat(dirfd, baseName, uint32(mode), unix.AT_SYMLINK_NOFOLLOW)
|
||||||
|
op = "fchmodat"
|
||||||
|
} else {
|
||||||
|
err = unix.Fchmod(fd, uint32(mode))
|
||||||
|
op = "fchmod"
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return &fs.PathError{Op: op, Path: metadata.Name, Err: err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := doChown(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
canIgnore := func(err error) bool {
|
||||||
|
return err == nil || errors.Is(err, unix.ENOSYS) || errors.Is(err, unix.ENOTSUP)
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range metadata.Xattrs {
|
||||||
|
if _, found := xattrsToIgnore[k]; found {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
data, err := base64.StdEncoding.DecodeString(v)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("decode xattr %q: %w", v, err)
|
||||||
|
}
|
||||||
|
if err := doSetXattr(k, data); !canIgnore(err) {
|
||||||
|
return fmt.Errorf("set xattr %s=%q for %q: %w", k, data, metadata.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := doUtimes(); !canIgnore(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := doChmod(); !canIgnore(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func openFileUnderRootFallback(dirfd int, name string, flags uint64, mode os.FileMode) (int, error) {
|
||||||
|
root := procPathForFd(dirfd)
|
||||||
|
|
||||||
|
targetRoot, err := os.Readlink(root)
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
|
||||||
|
hasNoFollow := (flags & unix.O_NOFOLLOW) != 0
|
||||||
|
|
||||||
|
var fd int
|
||||||
|
// If O_NOFOLLOW is specified in the flags, then resolve only the parent directory and use the
|
||||||
|
// last component as the path to openat().
|
||||||
|
if hasNoFollow {
|
||||||
|
dirName, baseName := filepath.Split(name)
|
||||||
|
if dirName != "" && dirName != "." {
|
||||||
|
newRoot, err := securejoin.SecureJoin(root, dirName)
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
root = newRoot
|
||||||
|
}
|
||||||
|
|
||||||
|
parentDirfd, err := unix.Open(root, unix.O_PATH|unix.O_CLOEXEC, 0)
|
||||||
|
if err != nil {
|
||||||
|
return -1, &fs.PathError{Op: "open", Path: root, Err: err}
|
||||||
|
}
|
||||||
|
defer unix.Close(parentDirfd)
|
||||||
|
|
||||||
|
fd, err = unix.Openat(parentDirfd, baseName, int(flags), uint32(mode))
|
||||||
|
if err != nil {
|
||||||
|
return -1, &fs.PathError{Op: "openat", Path: name, Err: err}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newPath, err := securejoin.SecureJoin(root, name)
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
fd, err = unix.Openat(dirfd, newPath, int(flags), uint32(mode))
|
||||||
|
if err != nil {
|
||||||
|
return -1, &fs.PathError{Op: "openat", Path: newPath, Err: err}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
target, err := os.Readlink(procPathForFd(fd))
|
||||||
|
if err != nil {
|
||||||
|
unix.Close(fd)
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add an additional check to make sure the opened fd is inside the rootfs
|
||||||
|
if !strings.HasPrefix(target, targetRoot) {
|
||||||
|
unix.Close(fd)
|
||||||
|
return -1, fmt.Errorf("while resolving %q. It resolves outside the root directory", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func openFileUnderRootOpenat2(dirfd int, name string, flags uint64, mode os.FileMode) (int, error) {
|
||||||
|
how := unix.OpenHow{
|
||||||
|
Flags: flags,
|
||||||
|
Mode: uint64(mode & 0o7777),
|
||||||
|
Resolve: unix.RESOLVE_IN_ROOT,
|
||||||
|
}
|
||||||
|
fd, err := unix.Openat2(dirfd, name, &how)
|
||||||
|
if err != nil {
|
||||||
|
return -1, &fs.PathError{Op: "openat2", Path: name, Err: err}
|
||||||
|
}
|
||||||
|
return fd, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// skipOpenat2 is set when openat2 is not supported by the underlying kernel and avoid
|
||||||
|
// using it again.
|
||||||
|
var skipOpenat2 int32
|
||||||
|
|
||||||
|
// openFileUnderRootRaw tries to open a file using openat2 and if it is not supported fallbacks to a
|
||||||
|
// userspace lookup.
|
||||||
|
func openFileUnderRootRaw(dirfd int, name string, flags uint64, mode os.FileMode) (int, error) {
|
||||||
|
var fd int
|
||||||
|
var err error
|
||||||
|
if name == "" {
|
||||||
|
fd, err := unix.Dup(dirfd)
|
||||||
|
if err != nil {
|
||||||
|
return -1, fmt.Errorf("failed to duplicate file descriptor %d: %w", dirfd, err)
|
||||||
|
}
|
||||||
|
return fd, nil
|
||||||
|
}
|
||||||
|
if atomic.LoadInt32(&skipOpenat2) > 0 {
|
||||||
|
fd, err = openFileUnderRootFallback(dirfd, name, flags, mode)
|
||||||
|
} else {
|
||||||
|
fd, err = openFileUnderRootOpenat2(dirfd, name, flags, mode)
|
||||||
|
// If the function failed with ENOSYS, switch off the support for openat2
|
||||||
|
// and fallback to using safejoin.
|
||||||
|
if err != nil && errors.Is(err, unix.ENOSYS) {
|
||||||
|
atomic.StoreInt32(&skipOpenat2, 1)
|
||||||
|
fd, err = openFileUnderRootFallback(dirfd, name, flags, mode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fd, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// openFileUnderRoot safely opens a file under the specified root directory using openat2
|
||||||
|
// dirfd is an open file descriptor to the target checkout directory.
|
||||||
|
// name is the path to open relative to dirfd.
|
||||||
|
// flags are the flags to pass to the open syscall.
|
||||||
|
// mode specifies the mode to use for newly created files.
|
||||||
|
func openFileUnderRoot(dirfd int, name string, flags uint64, mode os.FileMode) (*os.File, error) {
|
||||||
|
fd, err := openFileUnderRootRaw(dirfd, name, flags, mode)
|
||||||
|
if err == nil {
|
||||||
|
return os.NewFile(uintptr(fd), name), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
hasCreate := (flags & unix.O_CREAT) != 0
|
||||||
|
if errors.Is(err, unix.ENOENT) && hasCreate {
|
||||||
|
parent := filepath.Dir(name)
|
||||||
|
if parent != "" {
|
||||||
|
newDirfd, err2 := openOrCreateDirUnderRoot(dirfd, parent, 0)
|
||||||
|
if err2 == nil {
|
||||||
|
defer newDirfd.Close()
|
||||||
|
fd, err := openFileUnderRootRaw(int(newDirfd.Fd()), filepath.Base(name), flags, mode)
|
||||||
|
if err == nil {
|
||||||
|
return os.NewFile(uintptr(fd), name), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("open %q under the rootfs: %w", name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// openOrCreateDirUnderRoot safely opens a directory or create it if it is missing.
|
||||||
|
// dirfd is an open file descriptor to the target checkout directory.
|
||||||
|
// name is the path to open relative to dirfd.
|
||||||
|
// mode specifies the mode to use for newly created files.
|
||||||
|
func openOrCreateDirUnderRoot(dirfd int, name string, mode os.FileMode) (*os.File, error) {
|
||||||
|
fd, err := openFileUnderRootRaw(dirfd, name, unix.O_DIRECTORY|unix.O_RDONLY, 0)
|
||||||
|
if err == nil {
|
||||||
|
return os.NewFile(uintptr(fd), name), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if errors.Is(err, unix.ENOENT) {
|
||||||
|
parent := filepath.Dir(name)
|
||||||
|
if parent != "" {
|
||||||
|
pDir, err2 := openOrCreateDirUnderRoot(dirfd, parent, mode)
|
||||||
|
if err2 != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer pDir.Close()
|
||||||
|
|
||||||
|
baseName := filepath.Base(name)
|
||||||
|
|
||||||
|
if err2 := unix.Mkdirat(int(pDir.Fd()), baseName, uint32(mode)); err2 != nil {
|
||||||
|
return nil, &fs.PathError{Op: "mkdirat", Path: name, Err: err2}
|
||||||
|
}
|
||||||
|
|
||||||
|
fd, err = openFileUnderRootRaw(int(pDir.Fd()), baseName, unix.O_DIRECTORY|unix.O_RDONLY, 0)
|
||||||
|
if err == nil {
|
||||||
|
return os.NewFile(uintptr(fd), name), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// appendHole creates a hole with the specified size at the open fd.
|
||||||
|
// fd is the open file descriptor.
|
||||||
|
// name is the path to use for error messages.
|
||||||
|
// size is the size of the hole to create.
|
||||||
|
func appendHole(fd int, name string, size int64) error {
|
||||||
|
off, err := unix.Seek(fd, size, unix.SEEK_CUR)
|
||||||
|
if err != nil {
|
||||||
|
return &fs.PathError{Op: "seek", Path: name, Err: err}
|
||||||
|
}
|
||||||
|
// Make sure the file size is changed. It might be the last hole and no other data written afterwards.
|
||||||
|
if err := unix.Ftruncate(fd, off); err != nil {
|
||||||
|
return &fs.PathError{Op: "ftruncate", Path: name, Err: err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func safeMkdir(dirfd int, mode os.FileMode, name string, metadata *fileMetadata, options *archive.TarOptions) error {
|
||||||
|
parent, base := filepath.Split(name)
|
||||||
|
parentFd := dirfd
|
||||||
|
if parent != "" && parent != "." {
|
||||||
|
parentFile, err := openOrCreateDirUnderRoot(dirfd, parent, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer parentFile.Close()
|
||||||
|
parentFd = int(parentFile.Fd())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := unix.Mkdirat(parentFd, base, uint32(mode)); err != nil {
|
||||||
|
if !os.IsExist(err) {
|
||||||
|
return &fs.PathError{Op: "mkdirat", Path: name, Err: err}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := openFileUnderRoot(parentFd, base, unix.O_DIRECTORY|unix.O_RDONLY, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
return setFileAttrs(dirfd, file, mode, metadata, options, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func safeLink(dirfd int, mode os.FileMode, metadata *fileMetadata, options *archive.TarOptions) error {
|
||||||
|
sourceFile, err := openFileUnderRoot(dirfd, metadata.Linkname, unix.O_PATH|unix.O_RDONLY|unix.O_NOFOLLOW, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer sourceFile.Close()
|
||||||
|
|
||||||
|
err = doHardLink(dirfd, int(sourceFile.Fd()), metadata.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newFile, err := openFileUnderRoot(dirfd, metadata.Name, unix.O_WRONLY|unix.O_NOFOLLOW, 0)
|
||||||
|
if err != nil {
|
||||||
|
// If the target is a symlink, open the file with O_PATH.
|
||||||
|
if errors.Is(err, unix.ELOOP) {
|
||||||
|
newFile, err := openFileUnderRoot(dirfd, metadata.Name, unix.O_PATH|unix.O_NOFOLLOW, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer newFile.Close()
|
||||||
|
|
||||||
|
return setFileAttrs(dirfd, newFile, mode, metadata, options, true)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer newFile.Close()
|
||||||
|
|
||||||
|
return setFileAttrs(dirfd, newFile, mode, metadata, options, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func safeSymlink(dirfd int, metadata *fileMetadata) error {
|
||||||
|
destDir, destBase := filepath.Split(metadata.Name)
|
||||||
|
destDirFd := dirfd
|
||||||
|
if destDir != "" && destDir != "." {
|
||||||
|
f, err := openOrCreateDirUnderRoot(dirfd, destDir, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
destDirFd = int(f.Fd())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := unix.Symlinkat(metadata.Linkname, destDirFd, destBase); err != nil {
|
||||||
|
return &fs.PathError{Op: "symlinkat", Path: metadata.Name, Err: err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type whiteoutHandler struct {
|
||||||
|
Dirfd int
|
||||||
|
Root string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d whiteoutHandler) Setxattr(path, name string, value []byte) error {
|
||||||
|
file, err := openOrCreateDirUnderRoot(d.Dirfd, path, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
if err := unix.Fsetxattr(int(file.Fd()), name, value, 0); err != nil {
|
||||||
|
return &fs.PathError{Op: "fsetxattr", Path: path, Err: err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d whiteoutHandler) Mknod(path string, mode uint32, dev int) error {
|
||||||
|
dir, base := filepath.Split(path)
|
||||||
|
dirfd := d.Dirfd
|
||||||
|
if dir != "" && dir != "." {
|
||||||
|
dir, err := openOrCreateDirUnderRoot(d.Dirfd, dir, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer dir.Close()
|
||||||
|
|
||||||
|
dirfd = int(dir.Fd())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := unix.Mknodat(dirfd, base, mode, dev); err != nil {
|
||||||
|
return &fs.PathError{Op: "mknodat", Path: path, Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d whiteoutHandler) Chown(path string, uid, gid int) error {
|
||||||
|
file, err := openFileUnderRoot(d.Dirfd, path, unix.O_PATH, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
return chown(int(file.Fd()), "", uid, gid, false, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
type readerAtCloser interface {
|
||||||
|
io.ReaderAt
|
||||||
|
io.Closer
|
||||||
|
}
|
||||||
|
|
||||||
|
// seekableFile is a struct that wraps an *os.File to provide an ImageSourceSeekable.
|
||||||
|
type seekableFile struct {
|
||||||
|
reader readerAtCloser
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *seekableFile) Close() error {
|
||||||
|
return f.reader.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *seekableFile) GetBlobAt(chunks []ImageSourceChunk) (chan io.ReadCloser, chan error, error) {
|
||||||
|
streams := make(chan io.ReadCloser)
|
||||||
|
errs := make(chan error)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for _, chunk := range chunks {
|
||||||
|
streams <- io.NopCloser(io.NewSectionReader(f.reader, int64(chunk.Offset), int64(chunk.Length)))
|
||||||
|
}
|
||||||
|
close(streams)
|
||||||
|
close(errs)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return streams, errs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSeekableFile(reader readerAtCloser) *seekableFile {
|
||||||
|
return &seekableFile{reader: reader}
|
||||||
|
}
|
||||||
114
vendor/github.com/containers/storage/pkg/chunked/internal/compression.go
generated
vendored
114
vendor/github.com/containers/storage/pkg/chunked/internal/compression.go
generated
vendored
|
|
@ -5,25 +5,57 @@ package internal
|
||||||
// larger software like the graph drivers.
|
// larger software like the graph drivers.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"archive/tar"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/containers/storage/pkg/archive"
|
||||||
jsoniter "github.com/json-iterator/go"
|
jsoniter "github.com/json-iterator/go"
|
||||||
"github.com/klauspost/compress/zstd"
|
"github.com/klauspost/compress/zstd"
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
|
"github.com/vbatts/tar-split/archive/tar"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TOC is short for Table of Contents and is used by the zstd:chunked
|
||||||
|
// file format to effectively add an overall index into the contents
|
||||||
|
// of a tarball; it also includes file metadata.
|
||||||
type TOC struct {
|
type TOC struct {
|
||||||
Version int `json:"version"`
|
// Version is currently expected to be 1
|
||||||
Entries []FileMetadata `json:"entries"`
|
Version int `json:"version"`
|
||||||
TarSplitDigest digest.Digest `json:"tarSplitDigest,omitempty"`
|
// Entries is the list of file metadata in this TOC.
|
||||||
|
// The ordering in this array currently defaults to being the same
|
||||||
|
// as that of the tar stream; however, this should not be relied on.
|
||||||
|
Entries []FileMetadata `json:"entries"`
|
||||||
|
// TarSplitDigest is the checksum of the "tar-split" data which
|
||||||
|
// is included as a distinct skippable zstd frame before the TOC.
|
||||||
|
TarSplitDigest digest.Digest `json:"tarSplitDigest,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FileMetadata is an entry in the TOC that includes both generic file metadata
|
||||||
|
// that duplicates what can found in the tar header (and should match), but
|
||||||
|
// also special/custom content (see below).
|
||||||
|
//
|
||||||
|
// Regular files may optionally be represented as a sequence of “chunks”,
|
||||||
|
// which may be ChunkTypeData or ChunkTypeZeros (and ChunkTypeData boundaries
|
||||||
|
// are heuristically determined to increase chance of chunk matching / reuse
|
||||||
|
// similar to rsync). In that case, the regular file is represented
|
||||||
|
// as an initial TypeReg entry (with all metadata for the file as a whole)
|
||||||
|
// immediately followed by zero or more TypeChunk entries (containing only Type,
|
||||||
|
// Name and Chunk* fields); if there is at least one TypeChunk entry, the Chunk*
|
||||||
|
// fields are relevant in all of these entries, including the initial
|
||||||
|
// TypeReg one.
|
||||||
|
//
|
||||||
|
// Note that the metadata here, when fetched by a zstd:chunked aware client,
|
||||||
|
// is used instead of that in the tar stream. The contents of the tar stream
|
||||||
|
// are not used in this scenario.
|
||||||
type FileMetadata struct {
|
type FileMetadata struct {
|
||||||
|
// If you add any fields, update ensureFileMetadataMatches as well!
|
||||||
|
|
||||||
|
// The metadata below largely duplicates that in the tar headers.
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Linkname string `json:"linkName,omitempty"`
|
Linkname string `json:"linkName,omitempty"`
|
||||||
|
|
@ -37,9 +69,11 @@ type FileMetadata struct {
|
||||||
Devmajor int64 `json:"devMajor,omitempty"`
|
Devmajor int64 `json:"devMajor,omitempty"`
|
||||||
Devminor int64 `json:"devMinor,omitempty"`
|
Devminor int64 `json:"devMinor,omitempty"`
|
||||||
Xattrs map[string]string `json:"xattrs,omitempty"`
|
Xattrs map[string]string `json:"xattrs,omitempty"`
|
||||||
Digest string `json:"digest,omitempty"`
|
// Digest is a hexadecimal sha256 checksum of the file contents; it
|
||||||
Offset int64 `json:"offset,omitempty"`
|
// is empty for empty files
|
||||||
EndOffset int64 `json:"endOffset,omitempty"`
|
Digest string `json:"digest,omitempty"`
|
||||||
|
Offset int64 `json:"offset,omitempty"`
|
||||||
|
EndOffset int64 `json:"endOffset,omitempty"`
|
||||||
|
|
||||||
ChunkSize int64 `json:"chunkSize,omitempty"`
|
ChunkSize int64 `json:"chunkSize,omitempty"`
|
||||||
ChunkOffset int64 `json:"chunkOffset,omitempty"`
|
ChunkOffset int64 `json:"chunkOffset,omitempty"`
|
||||||
|
|
@ -53,19 +87,23 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// The following types correspond to regular types of entries that can
|
||||||
|
// appear in a tar archive.
|
||||||
TypeReg = "reg"
|
TypeReg = "reg"
|
||||||
TypeChunk = "chunk"
|
|
||||||
TypeLink = "hardlink"
|
TypeLink = "hardlink"
|
||||||
TypeChar = "char"
|
TypeChar = "char"
|
||||||
TypeBlock = "block"
|
TypeBlock = "block"
|
||||||
TypeDir = "dir"
|
TypeDir = "dir"
|
||||||
TypeFifo = "fifo"
|
TypeFifo = "fifo"
|
||||||
TypeSymlink = "symlink"
|
TypeSymlink = "symlink"
|
||||||
|
// TypeChunk is special; in zstd:chunked not only are files individually
|
||||||
|
// compressed and indexable, there is a "rolling checksum" used to compute
|
||||||
|
// "chunks" of individual file contents, that are also added to the TOC
|
||||||
|
TypeChunk = "chunk"
|
||||||
)
|
)
|
||||||
|
|
||||||
var TarTypes = map[byte]string{
|
var TarTypes = map[byte]string{
|
||||||
tar.TypeReg: TypeReg,
|
tar.TypeReg: TypeReg,
|
||||||
tar.TypeRegA: TypeReg,
|
|
||||||
tar.TypeLink: TypeLink,
|
tar.TypeLink: TypeLink,
|
||||||
tar.TypeChar: TypeChar,
|
tar.TypeChar: TypeChar,
|
||||||
tar.TypeBlock: TypeBlock,
|
tar.TypeBlock: TypeBlock,
|
||||||
|
|
@ -83,11 +121,23 @@ func GetType(t byte) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// ManifestChecksumKey is a hexadecimal sha256 digest of the compressed manifest digest.
|
||||||
ManifestChecksumKey = "io.github.containers.zstd-chunked.manifest-checksum"
|
ManifestChecksumKey = "io.github.containers.zstd-chunked.manifest-checksum"
|
||||||
ManifestInfoKey = "io.github.containers.zstd-chunked.manifest-position"
|
// ManifestInfoKey is an annotation that signals the start of the TOC (manifest)
|
||||||
TarSplitInfoKey = "io.github.containers.zstd-chunked.tarsplit-position"
|
// contents which are embedded as a skippable zstd frame. It has a format of
|
||||||
|
// four decimal integers separated by `:` as follows:
|
||||||
|
// <offset>:<length>:<uncompressed length>:<type>
|
||||||
|
// The <type> is ManifestTypeCRFS which should have the value `1`.
|
||||||
|
ManifestInfoKey = "io.github.containers.zstd-chunked.manifest-position"
|
||||||
|
// TarSplitInfoKey is an annotation that signals the start of the "tar-split" metadata
|
||||||
|
// contents which are embedded as a skippable zstd frame. It has a format of
|
||||||
|
// three decimal integers separated by `:` as follows:
|
||||||
|
// <offset>:<length>:<uncompressed length>
|
||||||
|
TarSplitInfoKey = "io.github.containers.zstd-chunked.tarsplit-position"
|
||||||
|
|
||||||
TarSplitChecksumKey = "io.github.containers.zstd-chunked.tarsplit-checksum" // Deprecated: Use the TOC.TarSplitDigest field instead, this annotation is no longer read nor written.
|
// TarSplitChecksumKey is no longer used and is replaced by the TOC.TarSplitDigest field instead.
|
||||||
|
// The value is retained here as a constant as a historical reference for older zstd:chunked images.
|
||||||
|
// TarSplitChecksumKey = "io.github.containers.zstd-chunked.tarsplit-checksum"
|
||||||
|
|
||||||
// ManifestTypeCRFS is a manifest file compatible with the CRFS TOC file.
|
// ManifestTypeCRFS is a manifest file compatible with the CRFS TOC file.
|
||||||
ManifestTypeCRFS = 1
|
ManifestTypeCRFS = 1
|
||||||
|
|
@ -232,3 +282,43 @@ func footerDataToBlob(footer ZstdChunkedFooterData) []byte {
|
||||||
|
|
||||||
return manifestDataLE
|
return manifestDataLE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// timeIfNotZero returns a pointer to the time.Time if it is not zero, otherwise it returns nil.
|
||||||
|
func timeIfNotZero(t *time.Time) *time.Time {
|
||||||
|
if t == nil || t.IsZero() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFileMetadata creates a basic FileMetadata entry for hdr.
|
||||||
|
// The caller must set DigestOffset/EndOffset, and the Chunk* values, separately.
|
||||||
|
func NewFileMetadata(hdr *tar.Header) (FileMetadata, error) {
|
||||||
|
typ, err := GetType(hdr.Typeflag)
|
||||||
|
if err != nil {
|
||||||
|
return FileMetadata{}, err
|
||||||
|
}
|
||||||
|
xattrs := make(map[string]string)
|
||||||
|
for k, v := range hdr.PAXRecords {
|
||||||
|
xattrKey, ok := strings.CutPrefix(k, archive.PaxSchilyXattr)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
xattrs[xattrKey] = base64.StdEncoding.EncodeToString([]byte(v))
|
||||||
|
}
|
||||||
|
return FileMetadata{
|
||||||
|
Type: typ,
|
||||||
|
Name: hdr.Name,
|
||||||
|
Linkname: hdr.Linkname,
|
||||||
|
Mode: hdr.Mode,
|
||||||
|
Size: hdr.Size,
|
||||||
|
UID: hdr.Uid,
|
||||||
|
GID: hdr.Gid,
|
||||||
|
ModTime: timeIfNotZero(&hdr.ModTime),
|
||||||
|
AccessTime: timeIfNotZero(&hdr.AccessTime),
|
||||||
|
ChangeTime: timeIfNotZero(&hdr.ChangeTime),
|
||||||
|
Devmajor: hdr.Devmajor,
|
||||||
|
Devminor: hdr.Devminor,
|
||||||
|
Xattrs: xattrs,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
670
vendor/github.com/containers/storage/pkg/chunked/storage_linux.go
generated
vendored
670
vendor/github.com/containers/storage/pkg/chunked/storage_linux.go
generated
vendored
|
|
@ -8,20 +8,18 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash"
|
"hash"
|
||||||
"io"
|
"io"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/containerd/stargz-snapshotter/estargz"
|
"github.com/containerd/stargz-snapshotter/estargz"
|
||||||
storage "github.com/containers/storage"
|
storage "github.com/containers/storage"
|
||||||
graphdriver "github.com/containers/storage/drivers"
|
graphdriver "github.com/containers/storage/drivers"
|
||||||
driversCopy "github.com/containers/storage/drivers/copy"
|
|
||||||
"github.com/containers/storage/pkg/archive"
|
"github.com/containers/storage/pkg/archive"
|
||||||
"github.com/containers/storage/pkg/chunked/compressor"
|
"github.com/containers/storage/pkg/chunked/compressor"
|
||||||
"github.com/containers/storage/pkg/chunked/internal"
|
"github.com/containers/storage/pkg/chunked/internal"
|
||||||
|
|
@ -29,8 +27,6 @@ import (
|
||||||
"github.com/containers/storage/pkg/fsverity"
|
"github.com/containers/storage/pkg/fsverity"
|
||||||
"github.com/containers/storage/pkg/idtools"
|
"github.com/containers/storage/pkg/idtools"
|
||||||
"github.com/containers/storage/pkg/system"
|
"github.com/containers/storage/pkg/system"
|
||||||
"github.com/containers/storage/types"
|
|
||||||
securejoin "github.com/cyphar/filepath-securejoin"
|
|
||||||
jsoniter "github.com/json-iterator/go"
|
jsoniter "github.com/json-iterator/go"
|
||||||
"github.com/klauspost/compress/zstd"
|
"github.com/klauspost/compress/zstd"
|
||||||
"github.com/klauspost/pgzip"
|
"github.com/klauspost/pgzip"
|
||||||
|
|
@ -42,9 +38,8 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
maxNumberMissingChunks = 1024
|
maxNumberMissingChunks = 1024
|
||||||
autoMergePartsThreshold = 128 // if the gap between two ranges is below this threshold, automatically merge them.
|
autoMergePartsThreshold = 1024 // if the gap between two ranges is below this threshold, automatically merge them.
|
||||||
newFileFlags = (unix.O_CREAT | unix.O_TRUNC | unix.O_EXCL | unix.O_WRONLY)
|
newFileFlags = (unix.O_CREAT | unix.O_TRUNC | unix.O_EXCL | unix.O_WRONLY)
|
||||||
containersOverrideXattr = "user.containers.override_stat"
|
|
||||||
bigDataKey = "zstd-chunked-manifest"
|
bigDataKey = "zstd-chunked-manifest"
|
||||||
chunkedData = "zstd-chunked-data"
|
chunkedData = "zstd-chunked-data"
|
||||||
chunkedLayerDataKey = "zstd-chunked-layer-data"
|
chunkedLayerDataKey = "zstd-chunked-layer-data"
|
||||||
|
|
@ -59,21 +54,6 @@ const (
|
||||||
copyGoRoutines = 32
|
copyGoRoutines = 32
|
||||||
)
|
)
|
||||||
|
|
||||||
// fileMetadata is a wrapper around internal.FileMetadata with additional private fields that
|
|
||||||
// are not part of the TOC document.
|
|
||||||
// Type: TypeChunk entries are stored in Chunks, the primary [fileMetadata] entries never use TypeChunk.
|
|
||||||
type fileMetadata struct {
|
|
||||||
internal.FileMetadata
|
|
||||||
|
|
||||||
// chunks stores the TypeChunk entries relevant to this entry when FileMetadata.Type == TypeReg.
|
|
||||||
chunks []*internal.FileMetadata
|
|
||||||
|
|
||||||
// skipSetAttrs is set when the file attributes must not be
|
|
||||||
// modified, e.g. it is a hard link from a different source,
|
|
||||||
// or a composefs file.
|
|
||||||
skipSetAttrs bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type compressedFileType int
|
type compressedFileType int
|
||||||
|
|
||||||
type chunkedDiffer struct {
|
type chunkedDiffer struct {
|
||||||
|
|
@ -111,7 +91,7 @@ type chunkedDiffer struct {
|
||||||
|
|
||||||
blobSize int64
|
blobSize int64
|
||||||
|
|
||||||
storeOpts *types.StoreOptions
|
pullOptions map[string]string
|
||||||
|
|
||||||
useFsVerity graphdriver.DifferFsVerity
|
useFsVerity graphdriver.DifferFsVerity
|
||||||
fsVerityDigests map[string]string
|
fsVerityDigests map[string]string
|
||||||
|
|
@ -127,98 +107,7 @@ type chunkedLayerData struct {
|
||||||
Format graphdriver.DifferOutputFormat `json:"format"`
|
Format graphdriver.DifferOutputFormat `json:"format"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func timeToTimespec(time *time.Time) (ts unix.Timespec) {
|
func (c *chunkedDiffer) convertTarToZstdChunked(destDirectory string, payload *os.File) (int64, *seekableFile, digest.Digest, map[string]string, error) {
|
||||||
if time == nil || time.IsZero() {
|
|
||||||
// Return UTIME_OMIT special value
|
|
||||||
ts.Sec = 0
|
|
||||||
ts.Nsec = ((1 << 30) - 2)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return unix.NsecToTimespec(time.UnixNano())
|
|
||||||
}
|
|
||||||
|
|
||||||
func doHardLink(srcFd int, destDirFd int, destBase string) error {
|
|
||||||
doLink := func() error {
|
|
||||||
// Using unix.AT_EMPTY_PATH requires CAP_DAC_READ_SEARCH while this variant that uses
|
|
||||||
// /proc/self/fd doesn't and can be used with rootless.
|
|
||||||
srcPath := fmt.Sprintf("/proc/self/fd/%d", srcFd)
|
|
||||||
return unix.Linkat(unix.AT_FDCWD, srcPath, destDirFd, destBase, unix.AT_SYMLINK_FOLLOW)
|
|
||||||
}
|
|
||||||
|
|
||||||
err := doLink()
|
|
||||||
|
|
||||||
// if the destination exists, unlink it first and try again
|
|
||||||
if err != nil && os.IsExist(err) {
|
|
||||||
unix.Unlinkat(destDirFd, destBase, 0)
|
|
||||||
return doLink()
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyFileContent(srcFd int, fileMetadata *fileMetadata, dirfd int, mode os.FileMode, useHardLinks bool) (*os.File, int64, error) {
|
|
||||||
destFile := fileMetadata.Name
|
|
||||||
src := fmt.Sprintf("/proc/self/fd/%d", srcFd)
|
|
||||||
st, err := os.Stat(src)
|
|
||||||
if err != nil {
|
|
||||||
return nil, -1, fmt.Errorf("copy file content for %q: %w", destFile, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
copyWithFileRange, copyWithFileClone := true, true
|
|
||||||
|
|
||||||
if useHardLinks {
|
|
||||||
destDirPath := filepath.Dir(destFile)
|
|
||||||
destBase := filepath.Base(destFile)
|
|
||||||
destDir, err := openFileUnderRoot(destDirPath, dirfd, 0, mode)
|
|
||||||
if err == nil {
|
|
||||||
defer destDir.Close()
|
|
||||||
|
|
||||||
err := doHardLink(srcFd, int(destDir.Fd()), destBase)
|
|
||||||
if err == nil {
|
|
||||||
// if the file was deduplicated with a hard link, skip overriding file metadata.
|
|
||||||
fileMetadata.skipSetAttrs = true
|
|
||||||
return nil, st.Size(), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the destination file already exists, we shouldn't blow it away
|
|
||||||
dstFile, err := openFileUnderRoot(destFile, dirfd, newFileFlags, mode)
|
|
||||||
if err != nil {
|
|
||||||
return nil, -1, fmt.Errorf("open file %q under rootfs for copy: %w", destFile, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = driversCopy.CopyRegularToFile(src, dstFile, st, ©WithFileRange, ©WithFileClone)
|
|
||||||
if err != nil {
|
|
||||||
dstFile.Close()
|
|
||||||
return nil, -1, fmt.Errorf("copy to file %q under rootfs: %w", destFile, err)
|
|
||||||
}
|
|
||||||
return dstFile, st.Size(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type seekableFile struct {
|
|
||||||
file *os.File
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *seekableFile) Close() error {
|
|
||||||
return f.file.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *seekableFile) GetBlobAt(chunks []ImageSourceChunk) (chan io.ReadCloser, chan error, error) {
|
|
||||||
streams := make(chan io.ReadCloser)
|
|
||||||
errs := make(chan error)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for _, chunk := range chunks {
|
|
||||||
streams <- io.NopCloser(io.NewSectionReader(f.file, int64(chunk.Offset), int64(chunk.Length)))
|
|
||||||
}
|
|
||||||
close(streams)
|
|
||||||
close(errs)
|
|
||||||
}()
|
|
||||||
|
|
||||||
return streams, errs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertTarToZstdChunked(destDirectory string, payload *os.File) (int64, *seekableFile, digest.Digest, map[string]string, error) {
|
|
||||||
diff, err := archive.DecompressStream(payload)
|
diff, err := archive.DecompressStream(payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, "", nil, err
|
return 0, nil, "", nil, err
|
||||||
|
|
@ -226,7 +115,7 @@ func convertTarToZstdChunked(destDirectory string, payload *os.File) (int64, *se
|
||||||
|
|
||||||
fd, err := unix.Open(destDirectory, unix.O_TMPFILE|unix.O_RDWR|unix.O_CLOEXEC, 0o600)
|
fd, err := unix.Open(destDirectory, unix.O_TMPFILE|unix.O_RDWR|unix.O_CLOEXEC, 0o600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, "", nil, err
|
return 0, nil, "", nil, &fs.PathError{Op: "open", Path: destDirectory, Err: err}
|
||||||
}
|
}
|
||||||
|
|
||||||
f := os.NewFile(uintptr(fd), destDirectory)
|
f := os.NewFile(uintptr(fd), destDirectory)
|
||||||
|
|
@ -240,7 +129,7 @@ func convertTarToZstdChunked(destDirectory string, payload *os.File) (int64, *se
|
||||||
}
|
}
|
||||||
|
|
||||||
convertedOutputDigester := digest.Canonical.Digester()
|
convertedOutputDigester := digest.Canonical.Digester()
|
||||||
copied, err := io.Copy(io.MultiWriter(chunked, convertedOutputDigester.Hash()), diff)
|
copied, err := io.CopyBuffer(io.MultiWriter(chunked, convertedOutputDigester.Hash()), diff, c.copyBuffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
f.Close()
|
f.Close()
|
||||||
return 0, nil, "", nil, err
|
return 0, nil, "", nil, err
|
||||||
|
|
@ -249,21 +138,15 @@ func convertTarToZstdChunked(destDirectory string, payload *os.File) (int64, *se
|
||||||
f.Close()
|
f.Close()
|
||||||
return 0, nil, "", nil, err
|
return 0, nil, "", nil, err
|
||||||
}
|
}
|
||||||
is := seekableFile{
|
|
||||||
file: f,
|
|
||||||
}
|
|
||||||
|
|
||||||
return copied, &is, convertedOutputDigester.Digest(), newAnnotations, nil
|
return copied, newSeekableFile(f), convertedOutputDigester.Digest(), newAnnotations, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDiffer returns a differ than can be used with ApplyDiffWithDiffer.
|
// GetDiffer returns a differ than can be used with ApplyDiffWithDiffer.
|
||||||
func GetDiffer(ctx context.Context, store storage.Store, blobDigest digest.Digest, blobSize int64, annotations map[string]string, iss ImageSourceSeekable) (graphdriver.Differ, error) {
|
func GetDiffer(ctx context.Context, store storage.Store, blobDigest digest.Digest, blobSize int64, annotations map[string]string, iss ImageSourceSeekable) (graphdriver.Differ, error) {
|
||||||
storeOpts, err := types.DefaultStoreOptions()
|
pullOptions := store.PullOptions()
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !parseBooleanPullOption(&storeOpts, "enable_partial_images", true) {
|
if !parseBooleanPullOption(pullOptions, "enable_partial_images", true) {
|
||||||
return nil, errors.New("enable_partial_images not configured")
|
return nil, errors.New("enable_partial_images not configured")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -279,21 +162,21 @@ func GetDiffer(ctx context.Context, store storage.Store, blobDigest digest.Diges
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("parsing zstd:chunked TOC digest %q: %w", zstdChunkedTOCDigestString, err)
|
return nil, fmt.Errorf("parsing zstd:chunked TOC digest %q: %w", zstdChunkedTOCDigestString, err)
|
||||||
}
|
}
|
||||||
return makeZstdChunkedDiffer(ctx, store, blobSize, zstdChunkedTOCDigest, annotations, iss, &storeOpts)
|
return makeZstdChunkedDiffer(store, blobSize, zstdChunkedTOCDigest, annotations, iss, pullOptions)
|
||||||
}
|
}
|
||||||
if hasEstargzTOC {
|
if hasEstargzTOC {
|
||||||
estargzTOCDigest, err := digest.Parse(estargzTOCDigestString)
|
estargzTOCDigest, err := digest.Parse(estargzTOCDigestString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("parsing estargz TOC digest %q: %w", estargzTOCDigestString, err)
|
return nil, fmt.Errorf("parsing estargz TOC digest %q: %w", estargzTOCDigestString, err)
|
||||||
}
|
}
|
||||||
return makeEstargzChunkedDiffer(ctx, store, blobSize, estargzTOCDigest, iss, &storeOpts)
|
return makeEstargzChunkedDiffer(store, blobSize, estargzTOCDigest, iss, pullOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
return makeConvertFromRawDiffer(ctx, store, blobDigest, blobSize, annotations, iss, &storeOpts)
|
return makeConvertFromRawDiffer(store, blobDigest, blobSize, iss, pullOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeConvertFromRawDiffer(ctx context.Context, store storage.Store, blobDigest digest.Digest, blobSize int64, annotations map[string]string, iss ImageSourceSeekable, storeOpts *types.StoreOptions) (*chunkedDiffer, error) {
|
func makeConvertFromRawDiffer(store storage.Store, blobDigest digest.Digest, blobSize int64, iss ImageSourceSeekable, pullOptions map[string]string) (*chunkedDiffer, error) {
|
||||||
if !parseBooleanPullOption(storeOpts, "convert_images", false) {
|
if !parseBooleanPullOption(pullOptions, "convert_images", false) {
|
||||||
return nil, errors.New("convert_images not configured")
|
return nil, errors.New("convert_images not configured")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -309,12 +192,12 @@ func makeConvertFromRawDiffer(ctx context.Context, store storage.Store, blobDige
|
||||||
convertToZstdChunked: true,
|
convertToZstdChunked: true,
|
||||||
copyBuffer: makeCopyBuffer(),
|
copyBuffer: makeCopyBuffer(),
|
||||||
layersCache: layersCache,
|
layersCache: layersCache,
|
||||||
storeOpts: storeOpts,
|
pullOptions: pullOptions,
|
||||||
stream: iss,
|
stream: iss,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeZstdChunkedDiffer(ctx context.Context, store storage.Store, blobSize int64, tocDigest digest.Digest, annotations map[string]string, iss ImageSourceSeekable, storeOpts *types.StoreOptions) (*chunkedDiffer, error) {
|
func makeZstdChunkedDiffer(store storage.Store, blobSize int64, tocDigest digest.Digest, annotations map[string]string, iss ImageSourceSeekable, pullOptions map[string]string) (*chunkedDiffer, error) {
|
||||||
manifest, toc, tarSplit, tocOffset, err := readZstdChunkedManifest(iss, tocDigest, annotations)
|
manifest, toc, tarSplit, tocOffset, err := readZstdChunkedManifest(iss, tocDigest, annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("read zstd:chunked manifest: %w", err)
|
return nil, fmt.Errorf("read zstd:chunked manifest: %w", err)
|
||||||
|
|
@ -333,14 +216,14 @@ func makeZstdChunkedDiffer(ctx context.Context, store storage.Store, blobSize in
|
||||||
layersCache: layersCache,
|
layersCache: layersCache,
|
||||||
manifest: manifest,
|
manifest: manifest,
|
||||||
toc: toc,
|
toc: toc,
|
||||||
storeOpts: storeOpts,
|
pullOptions: pullOptions,
|
||||||
stream: iss,
|
stream: iss,
|
||||||
tarSplit: tarSplit,
|
tarSplit: tarSplit,
|
||||||
tocOffset: tocOffset,
|
tocOffset: tocOffset,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeEstargzChunkedDiffer(ctx context.Context, store storage.Store, blobSize int64, tocDigest digest.Digest, iss ImageSourceSeekable, storeOpts *types.StoreOptions) (*chunkedDiffer, error) {
|
func makeEstargzChunkedDiffer(store storage.Store, blobSize int64, tocDigest digest.Digest, iss ImageSourceSeekable, pullOptions map[string]string) (*chunkedDiffer, error) {
|
||||||
manifest, tocOffset, err := readEstargzChunkedManifest(iss, blobSize, tocDigest)
|
manifest, tocOffset, err := readEstargzChunkedManifest(iss, blobSize, tocDigest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("read zstd:chunked manifest: %w", err)
|
return nil, fmt.Errorf("read zstd:chunked manifest: %w", err)
|
||||||
|
|
@ -358,7 +241,7 @@ func makeEstargzChunkedDiffer(ctx context.Context, store storage.Store, blobSize
|
||||||
fileType: fileTypeEstargz,
|
fileType: fileTypeEstargz,
|
||||||
layersCache: layersCache,
|
layersCache: layersCache,
|
||||||
manifest: manifest,
|
manifest: manifest,
|
||||||
storeOpts: storeOpts,
|
pullOptions: pullOptions,
|
||||||
stream: iss,
|
stream: iss,
|
||||||
tocOffset: tocOffset,
|
tocOffset: tocOffset,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
@ -375,15 +258,15 @@ func makeCopyBuffer() []byte {
|
||||||
// dirfd is an open file descriptor to the destination root directory.
|
// dirfd is an open file descriptor to the destination root directory.
|
||||||
// useHardLinks defines whether the deduplication can be performed using hard links.
|
// useHardLinks defines whether the deduplication can be performed using hard links.
|
||||||
func copyFileFromOtherLayer(file *fileMetadata, source string, name string, dirfd int, useHardLinks bool) (bool, *os.File, int64, error) {
|
func copyFileFromOtherLayer(file *fileMetadata, source string, name string, dirfd int, useHardLinks bool) (bool, *os.File, int64, error) {
|
||||||
srcDirfd, err := unix.Open(source, unix.O_RDONLY, 0)
|
srcDirfd, err := unix.Open(source, unix.O_RDONLY|unix.O_CLOEXEC, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil, 0, fmt.Errorf("open source file: %w", err)
|
return false, nil, 0, &fs.PathError{Op: "open", Path: source, Err: err}
|
||||||
}
|
}
|
||||||
defer unix.Close(srcDirfd)
|
defer unix.Close(srcDirfd)
|
||||||
|
|
||||||
srcFile, err := openFileUnderRoot(name, srcDirfd, unix.O_RDONLY, 0)
|
srcFile, err := openFileUnderRoot(srcDirfd, name, unix.O_RDONLY|syscall.O_CLOEXEC, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil, 0, fmt.Errorf("open source file under target rootfs (%s): %w", name, err)
|
return false, nil, 0, err
|
||||||
}
|
}
|
||||||
defer srcFile.Close()
|
defer srcFile.Close()
|
||||||
|
|
||||||
|
|
@ -420,7 +303,7 @@ func canDedupFileWithHardLink(file *fileMetadata, fd int, s os.FileInfo) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
path := fmt.Sprintf("/proc/self/fd/%d", fd)
|
path := procPathForFd(fd)
|
||||||
|
|
||||||
listXattrs, err := system.Llistxattr(path)
|
listXattrs, err := system.Llistxattr(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -476,7 +359,7 @@ func findFileInOSTreeRepos(file *fileMetadata, ostreeRepos []string, dirfd int,
|
||||||
if st.Size() != file.Size {
|
if st.Size() != file.Size {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fd, err := unix.Open(sourceFile, unix.O_RDONLY|unix.O_NONBLOCK, 0)
|
fd, err := unix.Open(sourceFile, unix.O_RDONLY|unix.O_NONBLOCK|unix.O_CLOEXEC, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("could not open sourceFile %s: %v", sourceFile, err)
|
logrus.Debugf("could not open sourceFile %s: %v", sourceFile, err)
|
||||||
return false, nil, 0, nil
|
return false, nil, 0, nil
|
||||||
|
|
@ -585,15 +468,15 @@ type missingPart struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *originFile) OpenFile() (io.ReadCloser, error) {
|
func (o *originFile) OpenFile() (io.ReadCloser, error) {
|
||||||
srcDirfd, err := unix.Open(o.Root, unix.O_RDONLY, 0)
|
srcDirfd, err := unix.Open(o.Root, unix.O_RDONLY|unix.O_CLOEXEC, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("open source file: %w", err)
|
return nil, &fs.PathError{Op: "open", Path: o.Root, Err: err}
|
||||||
}
|
}
|
||||||
defer unix.Close(srcDirfd)
|
defer unix.Close(srcDirfd)
|
||||||
|
|
||||||
srcFile, err := openFileUnderRoot(o.Path, srcDirfd, unix.O_RDONLY, 0)
|
srcFile, err := openFileUnderRoot(srcDirfd, o.Path, unix.O_RDONLY|unix.O_CLOEXEC, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("open source file under target rootfs: %w", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := srcFile.Seek(o.Offset, 0); err != nil {
|
if _, err := srcFile.Seek(o.Offset, 0); err != nil {
|
||||||
|
|
@ -603,253 +486,6 @@ func (o *originFile) OpenFile() (io.ReadCloser, error) {
|
||||||
return srcFile, nil
|
return srcFile, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// setFileAttrs sets the file attributes for file given metadata
|
|
||||||
func setFileAttrs(dirfd int, file *os.File, mode os.FileMode, metadata *fileMetadata, options *archive.TarOptions, usePath bool) error {
|
|
||||||
if metadata.skipSetAttrs {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if file == nil || file.Fd() < 0 {
|
|
||||||
return errors.New("invalid file")
|
|
||||||
}
|
|
||||||
fd := int(file.Fd())
|
|
||||||
|
|
||||||
t, err := typeToTarType(metadata.Type)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it is a symlink, force to use the path
|
|
||||||
if t == tar.TypeSymlink {
|
|
||||||
usePath = true
|
|
||||||
}
|
|
||||||
|
|
||||||
baseName := ""
|
|
||||||
if usePath {
|
|
||||||
dirName := filepath.Dir(metadata.Name)
|
|
||||||
if dirName != "" {
|
|
||||||
parentFd, err := openFileUnderRoot(dirName, dirfd, unix.O_PATH|unix.O_DIRECTORY, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer parentFd.Close()
|
|
||||||
|
|
||||||
dirfd = int(parentFd.Fd())
|
|
||||||
}
|
|
||||||
baseName = filepath.Base(metadata.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
doChown := func() error {
|
|
||||||
if usePath {
|
|
||||||
return unix.Fchownat(dirfd, baseName, metadata.UID, metadata.GID, unix.AT_SYMLINK_NOFOLLOW)
|
|
||||||
}
|
|
||||||
return unix.Fchown(fd, metadata.UID, metadata.GID)
|
|
||||||
}
|
|
||||||
|
|
||||||
doSetXattr := func(k string, v []byte) error {
|
|
||||||
return unix.Fsetxattr(fd, k, v, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
doUtimes := func() error {
|
|
||||||
ts := []unix.Timespec{timeToTimespec(metadata.AccessTime), timeToTimespec(metadata.ModTime)}
|
|
||||||
if usePath {
|
|
||||||
return unix.UtimesNanoAt(dirfd, baseName, ts, unix.AT_SYMLINK_NOFOLLOW)
|
|
||||||
}
|
|
||||||
return unix.UtimesNanoAt(unix.AT_FDCWD, fmt.Sprintf("/proc/self/fd/%d", fd), ts, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
doChmod := func() error {
|
|
||||||
if usePath {
|
|
||||||
return unix.Fchmodat(dirfd, baseName, uint32(mode), unix.AT_SYMLINK_NOFOLLOW)
|
|
||||||
}
|
|
||||||
return unix.Fchmod(fd, uint32(mode))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := doChown(); err != nil {
|
|
||||||
if !options.IgnoreChownErrors {
|
|
||||||
return fmt.Errorf("chown %q to %d:%d: %w", metadata.Name, metadata.UID, metadata.GID, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
canIgnore := func(err error) bool {
|
|
||||||
return err == nil || errors.Is(err, unix.ENOSYS) || errors.Is(err, unix.ENOTSUP)
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range metadata.Xattrs {
|
|
||||||
if _, found := xattrsToIgnore[k]; found {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
data, err := base64.StdEncoding.DecodeString(v)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("decode xattr %q: %w", v, err)
|
|
||||||
}
|
|
||||||
if err := doSetXattr(k, data); !canIgnore(err) {
|
|
||||||
return fmt.Errorf("set xattr %s=%q for %q: %w", k, data, metadata.Name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := doUtimes(); !canIgnore(err) {
|
|
||||||
return fmt.Errorf("set utimes for %q: %w", metadata.Name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := doChmod(); !canIgnore(err) {
|
|
||||||
return fmt.Errorf("chmod %q: %w", metadata.Name, err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func openFileUnderRootFallback(dirfd int, name string, flags uint64, mode os.FileMode) (int, error) {
|
|
||||||
root := fmt.Sprintf("/proc/self/fd/%d", dirfd)
|
|
||||||
|
|
||||||
targetRoot, err := os.Readlink(root)
|
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
|
|
||||||
hasNoFollow := (flags & unix.O_NOFOLLOW) != 0
|
|
||||||
|
|
||||||
var fd int
|
|
||||||
// If O_NOFOLLOW is specified in the flags, then resolve only the parent directory and use the
|
|
||||||
// last component as the path to openat().
|
|
||||||
if hasNoFollow {
|
|
||||||
dirName := filepath.Dir(name)
|
|
||||||
if dirName != "" {
|
|
||||||
newRoot, err := securejoin.SecureJoin(root, filepath.Dir(name))
|
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
root = newRoot
|
|
||||||
}
|
|
||||||
|
|
||||||
parentDirfd, err := unix.Open(root, unix.O_PATH, 0)
|
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
defer unix.Close(parentDirfd)
|
|
||||||
|
|
||||||
fd, err = unix.Openat(parentDirfd, filepath.Base(name), int(flags), uint32(mode))
|
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newPath, err := securejoin.SecureJoin(root, name)
|
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
fd, err = unix.Openat(dirfd, newPath, int(flags), uint32(mode))
|
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
target, err := os.Readlink(fmt.Sprintf("/proc/self/fd/%d", fd))
|
|
||||||
if err != nil {
|
|
||||||
unix.Close(fd)
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add an additional check to make sure the opened fd is inside the rootfs
|
|
||||||
if !strings.HasPrefix(target, targetRoot) {
|
|
||||||
unix.Close(fd)
|
|
||||||
return -1, fmt.Errorf("while resolving %q. It resolves outside the root directory", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fd, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func openFileUnderRootOpenat2(dirfd int, name string, flags uint64, mode os.FileMode) (int, error) {
|
|
||||||
how := unix.OpenHow{
|
|
||||||
Flags: flags,
|
|
||||||
Mode: uint64(mode & 0o7777),
|
|
||||||
Resolve: unix.RESOLVE_IN_ROOT,
|
|
||||||
}
|
|
||||||
return unix.Openat2(dirfd, name, &how)
|
|
||||||
}
|
|
||||||
|
|
||||||
// skipOpenat2 is set when openat2 is not supported by the underlying kernel and avoid
|
|
||||||
// using it again.
|
|
||||||
var skipOpenat2 int32
|
|
||||||
|
|
||||||
// openFileUnderRootRaw tries to open a file using openat2 and if it is not supported fallbacks to a
|
|
||||||
// userspace lookup.
|
|
||||||
func openFileUnderRootRaw(dirfd int, name string, flags uint64, mode os.FileMode) (int, error) {
|
|
||||||
var fd int
|
|
||||||
var err error
|
|
||||||
if atomic.LoadInt32(&skipOpenat2) > 0 {
|
|
||||||
fd, err = openFileUnderRootFallback(dirfd, name, flags, mode)
|
|
||||||
} else {
|
|
||||||
fd, err = openFileUnderRootOpenat2(dirfd, name, flags, mode)
|
|
||||||
// If the function failed with ENOSYS, switch off the support for openat2
|
|
||||||
// and fallback to using safejoin.
|
|
||||||
if err != nil && errors.Is(err, unix.ENOSYS) {
|
|
||||||
atomic.StoreInt32(&skipOpenat2, 1)
|
|
||||||
fd, err = openFileUnderRootFallback(dirfd, name, flags, mode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fd, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// openFileUnderRoot safely opens a file under the specified root directory using openat2
|
|
||||||
// name is the path to open relative to dirfd.
|
|
||||||
// dirfd is an open file descriptor to the target checkout directory.
|
|
||||||
// flags are the flags to pass to the open syscall.
|
|
||||||
// mode specifies the mode to use for newly created files.
|
|
||||||
func openFileUnderRoot(name string, dirfd int, flags uint64, mode os.FileMode) (*os.File, error) {
|
|
||||||
fd, err := openFileUnderRootRaw(dirfd, name, flags, mode)
|
|
||||||
if err == nil {
|
|
||||||
return os.NewFile(uintptr(fd), name), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
hasCreate := (flags & unix.O_CREAT) != 0
|
|
||||||
if errors.Is(err, unix.ENOENT) && hasCreate {
|
|
||||||
parent := filepath.Dir(name)
|
|
||||||
if parent != "" {
|
|
||||||
newDirfd, err2 := openOrCreateDirUnderRoot(parent, dirfd, 0)
|
|
||||||
if err2 == nil {
|
|
||||||
defer newDirfd.Close()
|
|
||||||
fd, err := openFileUnderRootRaw(int(newDirfd.Fd()), filepath.Base(name), flags, mode)
|
|
||||||
if err == nil {
|
|
||||||
return os.NewFile(uintptr(fd), name), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("open %q under the rootfs: %w", name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// openOrCreateDirUnderRoot safely opens a directory or create it if it is missing.
|
|
||||||
// name is the path to open relative to dirfd.
|
|
||||||
// dirfd is an open file descriptor to the target checkout directory.
|
|
||||||
// mode specifies the mode to use for newly created files.
|
|
||||||
func openOrCreateDirUnderRoot(name string, dirfd int, mode os.FileMode) (*os.File, error) {
|
|
||||||
fd, err := openFileUnderRootRaw(dirfd, name, unix.O_DIRECTORY|unix.O_RDONLY, mode)
|
|
||||||
if err == nil {
|
|
||||||
return os.NewFile(uintptr(fd), name), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if errors.Is(err, unix.ENOENT) {
|
|
||||||
parent := filepath.Dir(name)
|
|
||||||
if parent != "" {
|
|
||||||
pDir, err2 := openOrCreateDirUnderRoot(parent, dirfd, mode)
|
|
||||||
if err2 != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer pDir.Close()
|
|
||||||
|
|
||||||
baseName := filepath.Base(name)
|
|
||||||
|
|
||||||
if err2 := unix.Mkdirat(int(pDir.Fd()), baseName, 0o755); err2 != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
fd, err = openFileUnderRootRaw(int(pDir.Fd()), baseName, unix.O_DIRECTORY|unix.O_RDONLY, mode)
|
|
||||||
if err == nil {
|
|
||||||
return os.NewFile(uintptr(fd), name), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *chunkedDiffer) prepareCompressedStreamToFile(partCompression compressedFileType, from io.Reader, mf *missingFileChunk) (compressedFileType, error) {
|
func (c *chunkedDiffer) prepareCompressedStreamToFile(partCompression compressedFileType, from io.Reader, mf *missingFileChunk) (compressedFileType, error) {
|
||||||
switch {
|
switch {
|
||||||
case partCompression == fileTypeHole:
|
case partCompression == fileTypeHole:
|
||||||
|
|
@ -918,23 +554,14 @@ func hashHole(h hash.Hash, size int64, copyBuffer []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// appendHole creates a hole with the specified size at the open fd.
|
|
||||||
func appendHole(fd int, size int64) error {
|
|
||||||
off, err := unix.Seek(fd, size, unix.SEEK_CUR)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Make sure the file size is changed. It might be the last hole and no other data written afterwards.
|
|
||||||
if err := unix.Ftruncate(fd, off); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *chunkedDiffer) appendCompressedStreamToFile(compression compressedFileType, destFile *destinationFile, size int64) error {
|
func (c *chunkedDiffer) appendCompressedStreamToFile(compression compressedFileType, destFile *destinationFile, size int64) error {
|
||||||
switch compression {
|
switch compression {
|
||||||
case fileTypeZstdChunked:
|
case fileTypeZstdChunked:
|
||||||
defer c.zstdReader.Reset(nil)
|
defer func() {
|
||||||
|
if err := c.zstdReader.Reset(nil); err != nil {
|
||||||
|
logrus.Warnf("release of references to the previous zstd reader failed: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
if _, err := io.CopyBuffer(destFile.to, io.LimitReader(c.zstdReader, size), c.copyBuffer); err != nil {
|
if _, err := io.CopyBuffer(destFile.to, io.LimitReader(c.zstdReader, size), c.copyBuffer); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -948,7 +575,7 @@ func (c *chunkedDiffer) appendCompressedStreamToFile(compression compressedFileT
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case fileTypeHole:
|
case fileTypeHole:
|
||||||
if err := appendHole(int(destFile.file.Fd()), size); err != nil {
|
if err := appendHole(int(destFile.file.Fd()), destFile.metadata.Name, size); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if destFile.hash != nil {
|
if destFile.hash != nil {
|
||||||
|
|
@ -977,7 +604,7 @@ type destinationFile struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func openDestinationFile(dirfd int, metadata *fileMetadata, options *archive.TarOptions, skipValidation bool, recordFsVerity recordFsVerityFunc) (*destinationFile, error) {
|
func openDestinationFile(dirfd int, metadata *fileMetadata, options *archive.TarOptions, skipValidation bool, recordFsVerity recordFsVerityFunc) (*destinationFile, error) {
|
||||||
file, err := openFileUnderRoot(metadata.Name, dirfd, newFileFlags, 0)
|
file, err := openFileUnderRoot(dirfd, metadata.Name, newFileFlags, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -1080,7 +707,7 @@ func (c *chunkedDiffer) recordFsVerity(path string, roFile *os.File) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *chunkedDiffer) storeMissingFiles(streams chan io.ReadCloser, errs chan error, dest string, dirfd int, missingParts []missingPart, options *archive.TarOptions) (Err error) {
|
func (c *chunkedDiffer) storeMissingFiles(streams chan io.ReadCloser, errs chan error, dirfd int, missingParts []missingPart, options *archive.TarOptions) (Err error) {
|
||||||
var destFile *destinationFile
|
var destFile *destinationFile
|
||||||
|
|
||||||
filesToClose := make(chan *destinationFile, 3)
|
filesToClose := make(chan *destinationFile, 3)
|
||||||
|
|
@ -1294,7 +921,7 @@ func mergeMissingChunks(missingParts []missingPart, target int) []missingPart {
|
||||||
return newMissingParts
|
return newMissingParts
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *chunkedDiffer) retrieveMissingFiles(stream ImageSourceSeekable, dest string, dirfd int, missingParts []missingPart, options *archive.TarOptions) error {
|
func (c *chunkedDiffer) retrieveMissingFiles(stream ImageSourceSeekable, dirfd int, missingParts []missingPart, options *archive.TarOptions) error {
|
||||||
var chunksToRequest []ImageSourceChunk
|
var chunksToRequest []ImageSourceChunk
|
||||||
|
|
||||||
calculateChunksToRequest := func() {
|
calculateChunksToRequest := func() {
|
||||||
|
|
@ -1333,167 +960,12 @@ func (c *chunkedDiffer) retrieveMissingFiles(stream ImageSourceSeekable, dest st
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.storeMissingFiles(streams, errs, dest, dirfd, missingParts, options); err != nil {
|
if err := c.storeMissingFiles(streams, errs, dirfd, missingParts, options); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func safeMkdir(dirfd int, mode os.FileMode, name string, metadata *fileMetadata, options *archive.TarOptions) error {
|
|
||||||
parent := filepath.Dir(name)
|
|
||||||
base := filepath.Base(name)
|
|
||||||
|
|
||||||
parentFd := dirfd
|
|
||||||
if parent != "." {
|
|
||||||
parentFile, err := openOrCreateDirUnderRoot(parent, dirfd, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer parentFile.Close()
|
|
||||||
parentFd = int(parentFile.Fd())
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := unix.Mkdirat(parentFd, base, uint32(mode)); err != nil {
|
|
||||||
if !os.IsExist(err) {
|
|
||||||
return fmt.Errorf("mkdir %q: %w", name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := openFileUnderRoot(base, parentFd, unix.O_DIRECTORY|unix.O_RDONLY, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
return setFileAttrs(dirfd, file, mode, metadata, options, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func safeLink(dirfd int, mode os.FileMode, metadata *fileMetadata, options *archive.TarOptions) error {
|
|
||||||
sourceFile, err := openFileUnderRoot(metadata.Linkname, dirfd, unix.O_PATH|unix.O_RDONLY|unix.O_NOFOLLOW, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer sourceFile.Close()
|
|
||||||
|
|
||||||
destDir, destBase := filepath.Dir(metadata.Name), filepath.Base(metadata.Name)
|
|
||||||
destDirFd := dirfd
|
|
||||||
if destDir != "." {
|
|
||||||
f, err := openOrCreateDirUnderRoot(destDir, dirfd, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
destDirFd = int(f.Fd())
|
|
||||||
}
|
|
||||||
|
|
||||||
err = doHardLink(int(sourceFile.Fd()), destDirFd, destBase)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("create hardlink %q pointing to %q: %w", metadata.Name, metadata.Linkname, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
newFile, err := openFileUnderRoot(metadata.Name, dirfd, unix.O_WRONLY|unix.O_NOFOLLOW, 0)
|
|
||||||
if err != nil {
|
|
||||||
// If the target is a symlink, open the file with O_PATH.
|
|
||||||
if errors.Is(err, unix.ELOOP) {
|
|
||||||
newFile, err := openFileUnderRoot(metadata.Name, dirfd, unix.O_PATH|unix.O_NOFOLLOW, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer newFile.Close()
|
|
||||||
|
|
||||||
return setFileAttrs(dirfd, newFile, mode, metadata, options, true)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer newFile.Close()
|
|
||||||
|
|
||||||
return setFileAttrs(dirfd, newFile, mode, metadata, options, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func safeSymlink(dirfd int, mode os.FileMode, metadata *fileMetadata, options *archive.TarOptions) error {
|
|
||||||
destDir, destBase := filepath.Dir(metadata.Name), filepath.Base(metadata.Name)
|
|
||||||
destDirFd := dirfd
|
|
||||||
if destDir != "." {
|
|
||||||
f, err := openOrCreateDirUnderRoot(destDir, dirfd, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
destDirFd = int(f.Fd())
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := unix.Symlinkat(metadata.Linkname, destDirFd, destBase); err != nil {
|
|
||||||
return fmt.Errorf("create symlink %q pointing to %q: %w", metadata.Name, metadata.Linkname, err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type whiteoutHandler struct {
|
|
||||||
Dirfd int
|
|
||||||
Root string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d whiteoutHandler) Setxattr(path, name string, value []byte) error {
|
|
||||||
file, err := openOrCreateDirUnderRoot(path, d.Dirfd, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
if err := unix.Fsetxattr(int(file.Fd()), name, value, 0); err != nil {
|
|
||||||
return fmt.Errorf("set xattr %s=%q for %q: %w", name, value, path, err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d whiteoutHandler) Mknod(path string, mode uint32, dev int) error {
|
|
||||||
dir := filepath.Dir(path)
|
|
||||||
base := filepath.Base(path)
|
|
||||||
|
|
||||||
dirfd := d.Dirfd
|
|
||||||
if dir != "" {
|
|
||||||
dir, err := openOrCreateDirUnderRoot(dir, d.Dirfd, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer dir.Close()
|
|
||||||
|
|
||||||
dirfd = int(dir.Fd())
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := unix.Mknodat(dirfd, base, mode, dev); err != nil {
|
|
||||||
return fmt.Errorf("mknod %q: %w", path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkChownErr(err error, name string, uid, gid int) error {
|
|
||||||
if errors.Is(err, syscall.EINVAL) {
|
|
||||||
return fmt.Errorf(`potentially insufficient UIDs or GIDs available in user namespace (requested %d:%d for %s): Check /etc/subuid and /etc/subgid if configured locally and run "podman system migrate": %w`, uid, gid, name, err)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d whiteoutHandler) Chown(path string, uid, gid int) error {
|
|
||||||
file, err := openFileUnderRoot(path, d.Dirfd, unix.O_PATH, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
if err := unix.Fchownat(int(file.Fd()), "", uid, gid, unix.AT_EMPTY_PATH); err != nil {
|
|
||||||
var stat unix.Stat_t
|
|
||||||
if unix.Fstat(int(file.Fd()), &stat) == nil {
|
|
||||||
if stat.Uid == uint32(uid) && stat.Gid == uint32(gid) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return checkChownErr(err, path, uid, gid)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type hardLinkToCreate struct {
|
type hardLinkToCreate struct {
|
||||||
dest string
|
dest string
|
||||||
dirfd int
|
dirfd int
|
||||||
|
|
@ -1501,8 +973,8 @@ type hardLinkToCreate struct {
|
||||||
metadata *fileMetadata
|
metadata *fileMetadata
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseBooleanPullOption(storeOpts *storage.StoreOptions, name string, def bool) bool {
|
func parseBooleanPullOption(pullOptions map[string]string, name string, def bool) bool {
|
||||||
if value, ok := storeOpts.PullOptions[name]; ok {
|
if value, ok := pullOptions[name]; ok {
|
||||||
return strings.ToLower(value) == "true"
|
return strings.ToLower(value) == "true"
|
||||||
}
|
}
|
||||||
return def
|
return def
|
||||||
|
|
@ -1515,10 +987,10 @@ type findAndCopyFileOptions struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func reopenFileReadOnly(f *os.File) (*os.File, error) {
|
func reopenFileReadOnly(f *os.File) (*os.File, error) {
|
||||||
path := fmt.Sprintf("/proc/self/fd/%d", f.Fd())
|
path := procPathForFile(f)
|
||||||
fd, err := unix.Open(path, unix.O_RDONLY|unix.O_CLOEXEC, 0)
|
fd, err := unix.Open(path, unix.O_RDONLY|unix.O_CLOEXEC, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, &fs.PathError{Op: "open", Path: path, Err: err}
|
||||||
}
|
}
|
||||||
return os.NewFile(uintptr(fd), f.Name()), nil
|
return os.NewFile(uintptr(fd), f.Name()), nil
|
||||||
}
|
}
|
||||||
|
|
@ -1636,7 +1108,7 @@ func (c *chunkedDiffer) copyAllBlobToFile(destination *os.File) (digest.Digest,
|
||||||
r := io.TeeReader(payload, originalRawDigester.Hash())
|
r := io.TeeReader(payload, originalRawDigester.Hash())
|
||||||
|
|
||||||
// copy the entire tarball and compute its digest
|
// copy the entire tarball and compute its digest
|
||||||
_, err = io.Copy(destination, r)
|
_, err = io.CopyBuffer(destination, r, c.copyBuffer)
|
||||||
|
|
||||||
return originalRawDigester.Digest(), err
|
return originalRawDigester.Digest(), err
|
||||||
}
|
}
|
||||||
|
|
@ -1654,13 +1126,14 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff
|
||||||
// stream to use for reading the zstd:chunked or Estargz file.
|
// stream to use for reading the zstd:chunked or Estargz file.
|
||||||
stream := c.stream
|
stream := c.stream
|
||||||
|
|
||||||
|
var compressedDigest digest.Digest
|
||||||
var uncompressedDigest digest.Digest
|
var uncompressedDigest digest.Digest
|
||||||
var convertedBlobSize int64
|
var convertedBlobSize int64
|
||||||
|
|
||||||
if c.convertToZstdChunked {
|
if c.convertToZstdChunked {
|
||||||
fd, err := unix.Open(dest, unix.O_TMPFILE|unix.O_RDWR|unix.O_CLOEXEC, 0o600)
|
fd, err := unix.Open(dest, unix.O_TMPFILE|unix.O_RDWR|unix.O_CLOEXEC, 0o600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return graphdriver.DriverWithDifferOutput{}, err
|
return graphdriver.DriverWithDifferOutput{}, &fs.PathError{Op: "open", Path: dest, Err: err}
|
||||||
}
|
}
|
||||||
blobFile := os.NewFile(uintptr(fd), "blob-file")
|
blobFile := os.NewFile(uintptr(fd), "blob-file")
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|
@ -1670,7 +1143,7 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// calculate the checksum before accessing the file.
|
// calculate the checksum before accessing the file.
|
||||||
compressedDigest, err := c.copyAllBlobToFile(blobFile)
|
compressedDigest, err = c.copyAllBlobToFile(blobFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return graphdriver.DriverWithDifferOutput{}, err
|
return graphdriver.DriverWithDifferOutput{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -1683,7 +1156,7 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff
|
||||||
return graphdriver.DriverWithDifferOutput{}, err
|
return graphdriver.DriverWithDifferOutput{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tarSize, fileSource, diffID, annotations, err := convertTarToZstdChunked(dest, blobFile)
|
tarSize, fileSource, diffID, annotations, err := c.convertTarToZstdChunked(dest, blobFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return graphdriver.DriverWithDifferOutput{}, err
|
return graphdriver.DriverWithDifferOutput{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -1756,14 +1229,15 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff
|
||||||
},
|
},
|
||||||
TOCDigest: c.tocDigest,
|
TOCDigest: c.tocDigest,
|
||||||
UncompressedDigest: uncompressedDigest,
|
UncompressedDigest: uncompressedDigest,
|
||||||
|
CompressedDigest: compressedDigest,
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the hard links deduplication is used, file attributes are ignored because setting them
|
// When the hard links deduplication is used, file attributes are ignored because setting them
|
||||||
// modifies the source file as well.
|
// modifies the source file as well.
|
||||||
useHardLinks := parseBooleanPullOption(c.storeOpts, "use_hard_links", false)
|
useHardLinks := parseBooleanPullOption(c.pullOptions, "use_hard_links", false)
|
||||||
|
|
||||||
// List of OSTree repositories to use for deduplication
|
// List of OSTree repositories to use for deduplication
|
||||||
ostreeRepos := strings.Split(c.storeOpts.PullOptions["ostree_repos"], ":")
|
ostreeRepos := strings.Split(c.pullOptions["ostree_repos"], ":")
|
||||||
|
|
||||||
whiteoutConverter := archive.GetWhiteoutConverter(options.WhiteoutFormat, options.WhiteoutData)
|
whiteoutConverter := archive.GetWhiteoutConverter(options.WhiteoutFormat, options.WhiteoutData)
|
||||||
|
|
||||||
|
|
@ -1790,16 +1264,19 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff
|
||||||
if options.ForceMask != nil {
|
if options.ForceMask != nil {
|
||||||
uid, gid, mode, err := archive.GetFileOwner(dest)
|
uid, gid, mode, err := archive.GetFileOwner(dest)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
value := fmt.Sprintf("%d:%d:0%o", uid, gid, mode)
|
value := idtools.Stat{
|
||||||
if err := unix.Setxattr(dest, containersOverrideXattr, []byte(value), 0); err != nil {
|
IDs: idtools.IDPair{UID: int(uid), GID: int(gid)},
|
||||||
|
Mode: os.FileMode(mode),
|
||||||
|
}
|
||||||
|
if err := idtools.SetContainersOverrideXattr(dest, value); err != nil {
|
||||||
return output, err
|
return output, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dirfd, err := unix.Open(dest, unix.O_RDONLY|unix.O_PATH, 0)
|
dirfd, err := unix.Open(dest, unix.O_RDONLY|unix.O_PATH|unix.O_CLOEXEC, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return output, fmt.Errorf("cannot open %q: %w", dest, err)
|
return output, &fs.PathError{Op: "open", Path: dest, Err: err}
|
||||||
}
|
}
|
||||||
defer unix.Close(dirfd)
|
defer unix.Close(dirfd)
|
||||||
|
|
||||||
|
|
@ -1812,7 +1289,9 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff
|
||||||
for _, e := range mergedEntries {
|
for _, e := range mergedEntries {
|
||||||
d := e.Name[0:2]
|
d := e.Name[0:2]
|
||||||
if _, found := createdDirs[d]; !found {
|
if _, found := createdDirs[d]; !found {
|
||||||
unix.Mkdirat(dirfd, d, 0o755)
|
if err := unix.Mkdirat(dirfd, d, 0o755); err != nil {
|
||||||
|
return output, &fs.PathError{Op: "mkdirat", Path: d, Err: err}
|
||||||
|
}
|
||||||
createdDirs[d] = struct{}{}
|
createdDirs[d] = struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1868,11 +1347,14 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff
|
||||||
}
|
}
|
||||||
|
|
||||||
filesToWaitFor := 0
|
filesToWaitFor := 0
|
||||||
for i, r := range mergedEntries {
|
for i := range mergedEntries {
|
||||||
|
r := &mergedEntries[i]
|
||||||
if options.ForceMask != nil {
|
if options.ForceMask != nil {
|
||||||
value := fmt.Sprintf("%d:%d:0%o", r.UID, r.GID, r.Mode&0o7777)
|
value := idtools.FormatContainersOverrideXattr(r.UID, r.GID, int(r.Mode))
|
||||||
r.Xattrs[containersOverrideXattr] = base64.StdEncoding.EncodeToString([]byte(value))
|
if r.Xattrs == nil {
|
||||||
r.Mode = int64(*options.ForceMask)
|
r.Xattrs = make(map[string]string)
|
||||||
|
}
|
||||||
|
r.Xattrs[idtools.ContainersOverrideXattr] = base64.StdEncoding.EncodeToString([]byte(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
mode := os.FileMode(r.Mode)
|
mode := os.FileMode(r.Mode)
|
||||||
|
|
@ -1916,12 +1398,12 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff
|
||||||
if r.Size == 0 {
|
if r.Size == 0 {
|
||||||
// Used to have a scope for cleanup.
|
// Used to have a scope for cleanup.
|
||||||
createEmptyFile := func() error {
|
createEmptyFile := func() error {
|
||||||
file, err := openFileUnderRoot(r.Name, dirfd, newFileFlags, 0)
|
file, err := openFileUnderRoot(dirfd, r.Name, newFileFlags, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
if err := setFileAttrs(dirfd, file, mode, &r, options, false); err != nil {
|
if err := setFileAttrs(dirfd, file, mode, r, options, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -1936,7 +1418,7 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff
|
||||||
if r.Name == "" || r.Name == "." {
|
if r.Name == "" || r.Name == "." {
|
||||||
output.RootDirMode = &mode
|
output.RootDirMode = &mode
|
||||||
}
|
}
|
||||||
if err := safeMkdir(dirfd, mode, r.Name, &r, options); err != nil {
|
if err := safeMkdir(dirfd, mode, r.Name, r, options); err != nil {
|
||||||
return output, err
|
return output, err
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
|
@ -1950,12 +1432,12 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff
|
||||||
dest: dest,
|
dest: dest,
|
||||||
dirfd: dirfd,
|
dirfd: dirfd,
|
||||||
mode: mode,
|
mode: mode,
|
||||||
metadata: &r,
|
metadata: r,
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
|
|
||||||
case tar.TypeSymlink:
|
case tar.TypeSymlink:
|
||||||
if err := safeSymlink(dirfd, mode, &r, options); err != nil {
|
if err := safeSymlink(dirfd, r); err != nil {
|
||||||
return output, err
|
return output, err
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
|
@ -2057,7 +1539,7 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff
|
||||||
}
|
}
|
||||||
// There are some missing files. Prepare a multirange request for the missing chunks.
|
// There are some missing files. Prepare a multirange request for the missing chunks.
|
||||||
if len(missingParts) > 0 {
|
if len(missingParts) > 0 {
|
||||||
if err := c.retrieveMissingFiles(stream, dest, dirfd, missingParts, options); err != nil {
|
if err := c.retrieveMissingFiles(stream, dirfd, missingParts, options); err != nil {
|
||||||
return output, err
|
return output, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2167,13 +1649,13 @@ func (c *chunkedDiffer) mergeTocEntries(fileType compressedFileType, entries []i
|
||||||
// validateChunkChecksum checks if the file at $root/$path[offset:chunk.ChunkSize] has the
|
// validateChunkChecksum checks if the file at $root/$path[offset:chunk.ChunkSize] has the
|
||||||
// same digest as chunk.ChunkDigest
|
// same digest as chunk.ChunkDigest
|
||||||
func validateChunkChecksum(chunk *internal.FileMetadata, root, path string, offset int64, copyBuffer []byte) bool {
|
func validateChunkChecksum(chunk *internal.FileMetadata, root, path string, offset int64, copyBuffer []byte) bool {
|
||||||
parentDirfd, err := unix.Open(root, unix.O_PATH, 0)
|
parentDirfd, err := unix.Open(root, unix.O_PATH|unix.O_CLOEXEC, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
defer unix.Close(parentDirfd)
|
defer unix.Close(parentDirfd)
|
||||||
|
|
||||||
fd, err := openFileUnderRoot(path, parentDirfd, unix.O_RDONLY, 0)
|
fd, err := openFileUnderRoot(parentDirfd, path, unix.O_RDONLY|unix.O_CLOEXEC, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
68
vendor/github.com/containers/storage/pkg/chunked/tar_split_linux.go
generated
vendored
Normal file
68
vendor/github.com/containers/storage/pkg/chunked/tar_split_linux.go
generated
vendored
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
package chunked
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/vbatts/tar-split/archive/tar"
|
||||||
|
"github.com/vbatts/tar-split/tar/storage"
|
||||||
|
)
|
||||||
|
|
||||||
|
// iterateTarSplit calls handler for each tar header in tarSplit
|
||||||
|
func iterateTarSplit(tarSplit []byte, handler func(hdr *tar.Header) error) error {
|
||||||
|
// This, strictly speaking, hard-codes undocumented assumptions about how github.com/vbatts/tar-split/tar/asm.NewInputTarStream
|
||||||
|
// forms the tar-split contents. Pragmatically, NewInputTarStream should always produce storage.FileType entries at least
|
||||||
|
// for every non-empty file, which constraints it basically to the output we expect.
|
||||||
|
//
|
||||||
|
// Specifically, we assume:
|
||||||
|
// - There is a separate SegmentType entry for every tar header, but only one SegmentType entry for the full header incl. any extensions
|
||||||
|
// - (There is a FileType entry for every tar header, we ignore it)
|
||||||
|
// - Trailing padding of a file, if any, is included in the next SegmentType entry
|
||||||
|
// - At the end, there may be SegmentType entries just for the terminating zero blocks.
|
||||||
|
|
||||||
|
unpacker := storage.NewJSONUnpacker(bytes.NewReader(tarSplit))
|
||||||
|
for {
|
||||||
|
tsEntry, err := unpacker.Next()
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("reading tar-split entries: %w", err)
|
||||||
|
}
|
||||||
|
switch tsEntry.Type {
|
||||||
|
case storage.SegmentType:
|
||||||
|
payload := tsEntry.Payload
|
||||||
|
// This is horrible, but we don’t know how much padding to skip. (It can be computed from the previous hdr.Size for non-sparse
|
||||||
|
// files, but for sparse files that is set to the logical size.)
|
||||||
|
//
|
||||||
|
// First, assume that all padding is zero bytes.
|
||||||
|
// A tar header starts with a file name, which might in principle be empty, but
|
||||||
|
// at least https://github.com/opencontainers/image-spec/blob/main/layer.md#populate-initial-filesystem suggests that
|
||||||
|
// the tar name should never be empty (it should be ".", or maybe "./").
|
||||||
|
//
|
||||||
|
// This will cause us to skip all zero bytes in the trailing blocks, but that’s fine.
|
||||||
|
i := 0
|
||||||
|
for i < len(payload) && payload[i] == 0 {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
payload = payload[i:]
|
||||||
|
tr := tar.NewReader(bytes.NewReader(payload))
|
||||||
|
hdr, err := tr.Next()
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF { // Probably the last entry, but let’s let the unpacker drive that.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return fmt.Errorf("decoding a tar header from a tar-split entry: %w", err)
|
||||||
|
}
|
||||||
|
if err := handler(hdr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
case storage.FileType:
|
||||||
|
// Nothing
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unexpected tar-split entry type %q", tsEntry.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
vendor/github.com/containers/storage/pkg/config/config.go
generated
vendored
11
vendor/github.com/containers/storage/pkg/config/config.go
generated
vendored
|
|
@ -75,10 +75,6 @@ type OptionsConfig struct {
|
||||||
// Size
|
// Size
|
||||||
Size string `toml:"size,omitempty"`
|
Size string `toml:"size,omitempty"`
|
||||||
|
|
||||||
// RemapUIDs is a list of default UID mappings to use for layers.
|
|
||||||
RemapUIDs string `toml:"remap-uids,omitempty"`
|
|
||||||
// RemapGIDs is a list of default GID mappings to use for layers.
|
|
||||||
RemapGIDs string `toml:"remap-gids,omitempty"`
|
|
||||||
// IgnoreChownErrors is a flag for whether chown errors should be
|
// IgnoreChownErrors is a flag for whether chown errors should be
|
||||||
// ignored when building an image.
|
// ignored when building an image.
|
||||||
IgnoreChownErrors string `toml:"ignore_chown_errors,omitempty"`
|
IgnoreChownErrors string `toml:"ignore_chown_errors,omitempty"`
|
||||||
|
|
@ -90,13 +86,6 @@ type OptionsConfig struct {
|
||||||
// files and directories.
|
// files and directories.
|
||||||
ForceMask os.FileMode `toml:"force_mask,omitempty"`
|
ForceMask os.FileMode `toml:"force_mask,omitempty"`
|
||||||
|
|
||||||
// RemapUser is the name of one or more entries in /etc/subuid which
|
|
||||||
// should be used to set up default UID mappings.
|
|
||||||
RemapUser string `toml:"remap-user,omitempty"`
|
|
||||||
// RemapGroup is the name of one or more entries in /etc/subgid which
|
|
||||||
// should be used to set up default GID mappings.
|
|
||||||
RemapGroup string `toml:"remap-group,omitempty"`
|
|
||||||
|
|
||||||
// RootAutoUsernsUser is the name of one or more entries in /etc/subuid and
|
// RootAutoUsernsUser is the name of one or more entries in /etc/subuid and
|
||||||
// /etc/subgid which should be used to set up automatically a userns.
|
// /etc/subgid which should be used to set up automatically a userns.
|
||||||
RootAutoUsernsUser string `toml:"root-auto-userns-user,omitempty"`
|
RootAutoUsernsUser string `toml:"root-auto-userns-user,omitempty"`
|
||||||
|
|
|
||||||
4
vendor/github.com/containers/storage/pkg/directory/directory_unix.go
generated
vendored
4
vendor/github.com/containers/storage/pkg/directory/directory_unix.go
generated
vendored
|
|
@ -1,5 +1,5 @@
|
||||||
//go:build linux || darwin || freebsd || solaris
|
//go:build !windows
|
||||||
// +build linux darwin freebsd solaris
|
// +build !windows
|
||||||
|
|
||||||
package directory
|
package directory
|
||||||
|
|
||||||
|
|
|
||||||
38
vendor/github.com/containers/storage/pkg/homedir/homedir_others.go
generated
vendored
38
vendor/github.com/containers/storage/pkg/homedir/homedir_others.go
generated
vendored
|
|
@ -1,38 +0,0 @@
|
||||||
//go:build !linux && !darwin && !freebsd && !windows
|
|
||||||
// +build !linux,!darwin,!freebsd,!windows
|
|
||||||
|
|
||||||
package homedir
|
|
||||||
|
|
||||||
// Copyright 2013-2018 Docker, Inc.
|
|
||||||
// NOTE: this package has originally been copied from github.com/docker/docker.
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetRuntimeDir is unsupported on non-linux system.
|
|
||||||
func GetRuntimeDir() (string, error) {
|
|
||||||
return "", errors.New("homedir.GetRuntimeDir() is not supported on this system")
|
|
||||||
}
|
|
||||||
|
|
||||||
// StickRuntimeDirContents is unsupported on non-linux system.
|
|
||||||
func StickRuntimeDirContents(files []string) ([]string, error) {
|
|
||||||
return nil, errors.New("homedir.StickRuntimeDirContents() is not supported on this system")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetConfigHome returns XDG_CONFIG_HOME.
|
|
||||||
// GetConfigHome returns $HOME/.config and nil error if XDG_CONFIG_HOME is not set.
|
|
||||||
//
|
|
||||||
// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
|
|
||||||
func GetConfigHome() (string, error) {
|
|
||||||
if xdgConfigHome := os.Getenv("XDG_CONFIG_HOME"); xdgConfigHome != "" {
|
|
||||||
return xdgConfigHome, nil
|
|
||||||
}
|
|
||||||
home := Get()
|
|
||||||
if home == "" {
|
|
||||||
return "", errors.New("could not get either XDG_CONFIG_HOME or HOME")
|
|
||||||
}
|
|
||||||
return filepath.Join(home, ".config"), nil
|
|
||||||
}
|
|
||||||
15
vendor/github.com/containers/storage/pkg/idmap/idmapped_utils.go
generated
vendored
15
vendor/github.com/containers/storage/pkg/idmap/idmapped_utils.go
generated
vendored
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/containers/storage/pkg/idtools"
|
"github.com/containers/storage/pkg/idtools"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -61,12 +62,20 @@ func CreateUsernsProcess(uidMaps []idtools.IDMap, gidMaps []idtools.IDMap) (int,
|
||||||
_ = unix.Prctl(unix.PR_SET_PDEATHSIG, uintptr(unix.SIGKILL), 0, 0, 0)
|
_ = unix.Prctl(unix.PR_SET_PDEATHSIG, uintptr(unix.SIGKILL), 0, 0, 0)
|
||||||
// just wait for the SIGKILL
|
// just wait for the SIGKILL
|
||||||
for {
|
for {
|
||||||
syscall.Pause()
|
_ = syscall.Pause()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cleanupFunc := func() {
|
cleanupFunc := func() {
|
||||||
unix.Kill(int(pid), unix.SIGKILL)
|
err1 := unix.Kill(int(pid), unix.SIGKILL)
|
||||||
_, _ = unix.Wait4(int(pid), nil, 0, nil)
|
if err1 != nil && err1 != syscall.ESRCH {
|
||||||
|
logrus.Warnf("kill process pid: %d with SIGKILL ended with error: %v", int(pid), err1)
|
||||||
|
}
|
||||||
|
if err1 != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, err := unix.Wait4(int(pid), nil, 0, nil); err != nil {
|
||||||
|
logrus.Warnf("wait4 pid: %d ended with error: %v", int(pid), err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
writeMappings := func(fname string, idmap []idtools.IDMap) error {
|
writeMappings := func(fname string, idmap []idtools.IDMap) error {
|
||||||
mappings := ""
|
mappings := ""
|
||||||
|
|
|
||||||
72
vendor/github.com/containers/storage/pkg/idtools/idtools.go
generated
vendored
72
vendor/github.com/containers/storage/pkg/idtools/idtools.go
generated
vendored
|
|
@ -367,21 +367,77 @@ func checkChownErr(err error, name string, uid, gid int) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stat contains file states that can be overriden with ContainersOverrideXattr.
|
||||||
|
type Stat struct {
|
||||||
|
IDs IDPair
|
||||||
|
Mode os.FileMode
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatContainersOverrideXattr will format the given uid, gid, and mode into a string
|
||||||
|
// that can be used as the value for the ContainersOverrideXattr xattr.
|
||||||
|
func FormatContainersOverrideXattr(uid, gid, mode int) string {
|
||||||
|
return fmt.Sprintf("%d:%d:0%o", uid, gid, mode&0o7777)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetContainersOverrideXattr will get and decode ContainersOverrideXattr.
|
||||||
|
func GetContainersOverrideXattr(path string) (Stat, error) {
|
||||||
|
var stat Stat
|
||||||
|
xstat, err := system.Lgetxattr(path, ContainersOverrideXattr)
|
||||||
|
if err != nil {
|
||||||
|
return stat, err
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs := strings.Split(string(xstat), ":")
|
||||||
|
if len(attrs) != 3 {
|
||||||
|
return stat, fmt.Errorf("The number of clons in %s does not equal to 3",
|
||||||
|
ContainersOverrideXattr)
|
||||||
|
}
|
||||||
|
|
||||||
|
value, err := strconv.ParseUint(attrs[0], 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return stat, fmt.Errorf("Failed to parse UID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stat.IDs.UID = int(value)
|
||||||
|
|
||||||
|
value, err = strconv.ParseUint(attrs[0], 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return stat, fmt.Errorf("Failed to parse GID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stat.IDs.GID = int(value)
|
||||||
|
|
||||||
|
value, err = strconv.ParseUint(attrs[2], 8, 32)
|
||||||
|
if err != nil {
|
||||||
|
return stat, fmt.Errorf("Failed to parse mode: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stat.Mode = os.FileMode(value)
|
||||||
|
|
||||||
|
return stat, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetContainersOverrideXattr will encode and set ContainersOverrideXattr.
|
||||||
|
func SetContainersOverrideXattr(path string, stat Stat) error {
|
||||||
|
value := FormatContainersOverrideXattr(stat.IDs.UID, stat.IDs.GID, int(stat.Mode))
|
||||||
|
return system.Lsetxattr(path, ContainersOverrideXattr, []byte(value), 0)
|
||||||
|
}
|
||||||
|
|
||||||
func SafeChown(name string, uid, gid int) error {
|
func SafeChown(name string, uid, gid int) error {
|
||||||
if runtime.GOOS == "darwin" {
|
if runtime.GOOS == "darwin" {
|
||||||
var mode uint64 = 0o0700
|
var mode os.FileMode = 0o0700
|
||||||
xstat, err := system.Lgetxattr(name, ContainersOverrideXattr)
|
xstat, err := system.Lgetxattr(name, ContainersOverrideXattr)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
attrs := strings.Split(string(xstat), ":")
|
attrs := strings.Split(string(xstat), ":")
|
||||||
if len(attrs) == 3 {
|
if len(attrs) == 3 {
|
||||||
val, err := strconv.ParseUint(attrs[2], 8, 32)
|
val, err := strconv.ParseUint(attrs[2], 8, 32)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
mode = val
|
mode = os.FileMode(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
value := fmt.Sprintf("%d:%d:0%o", uid, gid, mode)
|
value := Stat{IDPair{uid, gid}, mode}
|
||||||
if err = system.Lsetxattr(name, ContainersOverrideXattr, []byte(value), 0); err != nil {
|
if err = SetContainersOverrideXattr(name, value); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
uid = os.Getuid()
|
uid = os.Getuid()
|
||||||
|
|
@ -397,19 +453,19 @@ func SafeChown(name string, uid, gid int) error {
|
||||||
|
|
||||||
func SafeLchown(name string, uid, gid int) error {
|
func SafeLchown(name string, uid, gid int) error {
|
||||||
if runtime.GOOS == "darwin" {
|
if runtime.GOOS == "darwin" {
|
||||||
var mode uint64 = 0o0700
|
var mode os.FileMode = 0o0700
|
||||||
xstat, err := system.Lgetxattr(name, ContainersOverrideXattr)
|
xstat, err := system.Lgetxattr(name, ContainersOverrideXattr)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
attrs := strings.Split(string(xstat), ":")
|
attrs := strings.Split(string(xstat), ":")
|
||||||
if len(attrs) == 3 {
|
if len(attrs) == 3 {
|
||||||
val, err := strconv.ParseUint(attrs[2], 8, 32)
|
val, err := strconv.ParseUint(attrs[2], 8, 32)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
mode = val
|
mode = os.FileMode(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
value := fmt.Sprintf("%d:%d:0%o", uid, gid, mode)
|
value := Stat{IDPair{uid, gid}, mode}
|
||||||
if err = system.Lsetxattr(name, ContainersOverrideXattr, []byte(value), 0); err != nil {
|
if err = SetContainersOverrideXattr(name, value); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
uid = os.Getuid()
|
uid = os.Getuid()
|
||||||
|
|
|
||||||
5
vendor/github.com/containers/storage/pkg/ioutils/fswriters.go
generated
vendored
5
vendor/github.com/containers/storage/pkg/ioutils/fswriters.go
generated
vendored
|
|
@ -150,10 +150,13 @@ func (w *atomicFileWriter) complete(commit bool) (retErr error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
w.closeTempFile()
|
err := w.closeTempFile()
|
||||||
if retErr != nil || w.writeErr != nil {
|
if retErr != nil || w.writeErr != nil {
|
||||||
os.Remove(w.f.Name())
|
os.Remove(w.f.Name())
|
||||||
}
|
}
|
||||||
|
if retErr == nil {
|
||||||
|
retErr = err
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if commit {
|
if commit {
|
||||||
|
|
|
||||||
11
vendor/github.com/containers/storage/pkg/lockfile/lockfile.go
generated
vendored
11
vendor/github.com/containers/storage/pkg/lockfile/lockfile.go
generated
vendored
|
|
@ -415,7 +415,9 @@ func (l *LockFile) lock(lType lockType) {
|
||||||
// Optimization: only use the (expensive) syscall when
|
// Optimization: only use the (expensive) syscall when
|
||||||
// the counter is 0. In this case, we're either the first
|
// the counter is 0. In this case, we're either the first
|
||||||
// reader lock or a writer lock.
|
// reader lock or a writer lock.
|
||||||
lockHandle(l.fd, lType, false)
|
if err := lockHandle(l.fd, lType, false); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
l.lockType = lType
|
l.lockType = lType
|
||||||
l.locked = true
|
l.locked = true
|
||||||
|
|
@ -426,10 +428,13 @@ func (l *LockFile) lock(lType lockType) {
|
||||||
// command.
|
// command.
|
||||||
func (l *LockFile) tryLock(lType lockType) error {
|
func (l *LockFile) tryLock(lType lockType) error {
|
||||||
var success bool
|
var success bool
|
||||||
|
var rwMutexUnlocker func()
|
||||||
if lType == readLock {
|
if lType == readLock {
|
||||||
success = l.rwMutex.TryRLock()
|
success = l.rwMutex.TryRLock()
|
||||||
|
rwMutexUnlocker = l.rwMutex.RUnlock
|
||||||
} else {
|
} else {
|
||||||
success = l.rwMutex.TryLock()
|
success = l.rwMutex.TryLock()
|
||||||
|
rwMutexUnlocker = l.rwMutex.Unlock
|
||||||
}
|
}
|
||||||
if !success {
|
if !success {
|
||||||
return fmt.Errorf("resource temporarily unavailable")
|
return fmt.Errorf("resource temporarily unavailable")
|
||||||
|
|
@ -440,7 +445,7 @@ func (l *LockFile) tryLock(lType lockType) error {
|
||||||
// If we're the first reference on the lock, we need to open the file again.
|
// If we're the first reference on the lock, we need to open the file again.
|
||||||
fd, err := openLock(l.file, l.ro)
|
fd, err := openLock(l.file, l.ro)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.rwMutex.Unlock()
|
rwMutexUnlocker()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
l.fd = fd
|
l.fd = fd
|
||||||
|
|
@ -450,7 +455,7 @@ func (l *LockFile) tryLock(lType lockType) error {
|
||||||
// reader lock or a writer lock.
|
// reader lock or a writer lock.
|
||||||
if err = lockHandle(l.fd, lType, true); err != nil {
|
if err = lockHandle(l.fd, lType, true); err != nil {
|
||||||
closeHandle(fd)
|
closeHandle(fd)
|
||||||
l.rwMutex.Unlock()
|
rwMutexUnlocker()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
4
vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go
generated
vendored
4
vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go
generated
vendored
|
|
@ -1,5 +1,5 @@
|
||||||
//go:build linux || solaris || darwin || freebsd
|
//go:build !windows
|
||||||
// +build linux solaris darwin freebsd
|
// +build !windows
|
||||||
|
|
||||||
package lockfile
|
package lockfile
|
||||||
|
|
||||||
|
|
|
||||||
56
vendor/github.com/containers/storage/pkg/loopback/attach_loopback.go
generated
vendored
56
vendor/github.com/containers/storage/pkg/loopback/attach_loopback.go
generated
vendored
|
|
@ -6,10 +6,12 @@ package loopback
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Loopback related errors
|
// Loopback related errors
|
||||||
|
|
@ -39,7 +41,7 @@ func getNextFreeLoopbackIndex() (int, error) {
|
||||||
return index, err
|
return index, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func openNextAvailableLoopback(index int, sparseName string, sparseFile *os.File) (loopFile *os.File, err error) {
|
func openNextAvailableLoopback(sparseName string, sparseFile *os.File) (loopFile *os.File, err error) {
|
||||||
// Read information about the loopback file.
|
// Read information about the loopback file.
|
||||||
var st syscall.Stat_t
|
var st syscall.Stat_t
|
||||||
err = syscall.Fstat(int(sparseFile.Fd()), &st)
|
err = syscall.Fstat(int(sparseFile.Fd()), &st)
|
||||||
|
|
@ -48,31 +50,51 @@ func openNextAvailableLoopback(index int, sparseName string, sparseFile *os.File
|
||||||
return nil, ErrAttachLoopbackDevice
|
return nil, ErrAttachLoopbackDevice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// upper bound to avoid infinite loop
|
||||||
|
remaining := 1000
|
||||||
|
|
||||||
// Start looking for a free /dev/loop
|
// Start looking for a free /dev/loop
|
||||||
for {
|
for {
|
||||||
target := fmt.Sprintf("/dev/loop%d", index)
|
if remaining == 0 {
|
||||||
index++
|
logrus.Errorf("No free loopback devices available")
|
||||||
|
|
||||||
fi, err := os.Stat(target)
|
|
||||||
if err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
logrus.Error("There are no more loopback devices available.")
|
|
||||||
}
|
|
||||||
return nil, ErrAttachLoopbackDevice
|
return nil, ErrAttachLoopbackDevice
|
||||||
}
|
}
|
||||||
|
remaining--
|
||||||
|
|
||||||
if fi.Mode()&os.ModeDevice != os.ModeDevice {
|
index, err := getNextFreeLoopbackIndex()
|
||||||
logrus.Errorf("Loopback device %s is not a block device.", target)
|
if err != nil {
|
||||||
continue
|
logrus.Debugf("Error retrieving the next available loopback: %s", err)
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
target := fmt.Sprintf("/dev/loop%d", index)
|
||||||
|
|
||||||
// OpenFile adds O_CLOEXEC
|
// OpenFile adds O_CLOEXEC
|
||||||
loopFile, err = os.OpenFile(target, os.O_RDWR, 0o644)
|
loopFile, err = os.OpenFile(target, os.O_RDWR, 0o644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// The kernel returns ENXIO when opening a device that is in the "deleting" or "rundown" state, so
|
||||||
|
// just treat ENXIO as if the device does not exist.
|
||||||
|
if errors.Is(err, fs.ErrNotExist) || errors.Is(err, unix.ENXIO) {
|
||||||
|
// Another process could have taken the loopback device in the meantime. So repeat
|
||||||
|
// the process with the next loopback device.
|
||||||
|
continue
|
||||||
|
}
|
||||||
logrus.Errorf("Opening loopback device: %s", err)
|
logrus.Errorf("Opening loopback device: %s", err)
|
||||||
return nil, ErrAttachLoopbackDevice
|
return nil, ErrAttachLoopbackDevice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fi, err := loopFile.Stat()
|
||||||
|
if err != nil {
|
||||||
|
loopFile.Close()
|
||||||
|
logrus.Errorf("Stat loopback device: %s", err)
|
||||||
|
return nil, ErrAttachLoopbackDevice
|
||||||
|
}
|
||||||
|
if fi.Mode()&os.ModeDevice != os.ModeDevice {
|
||||||
|
loopFile.Close()
|
||||||
|
logrus.Errorf("Loopback device %s is not a block device.", target)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Try to attach to the loop file
|
// Try to attach to the loop file
|
||||||
if err := ioctlLoopSetFd(loopFile.Fd(), sparseFile.Fd()); err != nil {
|
if err := ioctlLoopSetFd(loopFile.Fd(), sparseFile.Fd()); err != nil {
|
||||||
loopFile.Close()
|
loopFile.Close()
|
||||||
|
|
@ -124,14 +146,6 @@ func AttachLoopDeviceRO(sparseName string) (loop *os.File, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func attachLoopDevice(sparseName string, readonly bool) (loop *os.File, err error) {
|
func attachLoopDevice(sparseName string, readonly bool) (loop *os.File, err error) {
|
||||||
// Try to retrieve the next available loopback device via syscall.
|
|
||||||
// If it fails, we discard error and start looping for a
|
|
||||||
// loopback from index 0.
|
|
||||||
startIndex, err := getNextFreeLoopbackIndex()
|
|
||||||
if err != nil {
|
|
||||||
logrus.Debugf("Error retrieving the next available loopback: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var sparseFile *os.File
|
var sparseFile *os.File
|
||||||
|
|
||||||
// OpenFile adds O_CLOEXEC
|
// OpenFile adds O_CLOEXEC
|
||||||
|
|
@ -146,7 +160,7 @@ func attachLoopDevice(sparseName string, readonly bool) (loop *os.File, err erro
|
||||||
}
|
}
|
||||||
defer sparseFile.Close()
|
defer sparseFile.Close()
|
||||||
|
|
||||||
loopFile, err := openNextAvailableLoopback(startIndex, sparseName, sparseFile)
|
loopFile, err := openNextAvailableLoopback(sparseName, sparseFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
17
vendor/github.com/containers/storage/pkg/mount/mountinfo_linux.go
generated
vendored
17
vendor/github.com/containers/storage/pkg/mount/mountinfo_linux.go
generated
vendored
|
|
@ -1,5 +1,18 @@
|
||||||
package mount
|
package mount
|
||||||
|
|
||||||
import "github.com/moby/sys/mountinfo"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
var PidMountInfo = mountinfo.PidMountInfo
|
"github.com/moby/sys/mountinfo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PidMountInfo(pid int) ([]*Info, error) {
|
||||||
|
f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
return mountinfo.GetMountsFromReader(f, nil)
|
||||||
|
}
|
||||||
|
|
|
||||||
4
vendor/github.com/containers/storage/pkg/system/syscall_unix.go
generated
vendored
4
vendor/github.com/containers/storage/pkg/system/syscall_unix.go
generated
vendored
|
|
@ -1,5 +1,5 @@
|
||||||
//go:build linux || freebsd || darwin
|
//go:build !windows
|
||||||
// +build linux freebsd darwin
|
// +build !windows
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
||||||
12
vendor/github.com/containers/storage/pkg/unshare/unshare_linux.go
generated
vendored
12
vendor/github.com/containers/storage/pkg/unshare/unshare_linux.go
generated
vendored
|
|
@ -526,8 +526,11 @@ func MaybeReexecUsingUserNamespace(evenForRoot bool) {
|
||||||
} else {
|
} else {
|
||||||
// If we have CAP_SYS_ADMIN, then we don't need to create a new namespace in order to be able
|
// If we have CAP_SYS_ADMIN, then we don't need to create a new namespace in order to be able
|
||||||
// to use unshare(), so don't bother creating a new user namespace at this point.
|
// to use unshare(), so don't bother creating a new user namespace at this point.
|
||||||
capabilities, err := capability.NewPid(0)
|
capabilities, err := capability.NewPid2(0)
|
||||||
|
bailOnError(err, "Initializing a new Capabilities object of pid 0")
|
||||||
|
err = capabilities.Load()
|
||||||
bailOnError(err, "Reading the current capabilities sets")
|
bailOnError(err, "Reading the current capabilities sets")
|
||||||
|
|
||||||
if capabilities.Get(capability.EFFECTIVE, capability.CAP_SYS_ADMIN) {
|
if capabilities.Get(capability.EFFECTIVE, capability.CAP_SYS_ADMIN) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -587,7 +590,12 @@ func MaybeReexecUsingUserNamespace(evenForRoot bool) {
|
||||||
cmd.Hook = func(int) error {
|
cmd.Hook = func(int) error {
|
||||||
go func() {
|
go func() {
|
||||||
for receivedSignal := range interrupted {
|
for receivedSignal := range interrupted {
|
||||||
cmd.Cmd.Process.Signal(receivedSignal)
|
if err := cmd.Cmd.Process.Signal(receivedSignal); err != nil {
|
||||||
|
logrus.Warnf(
|
||||||
|
"Failed to send a signal '%d' to the Process (PID: %d): %v",
|
||||||
|
receivedSignal, cmd.Cmd.Process.Pid, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
26
vendor/github.com/containers/storage/storage.conf
generated
vendored
26
vendor/github.com/containers/storage/storage.conf
generated
vendored
|
|
@ -19,6 +19,10 @@ driver = "overlay"
|
||||||
# Temporary storage location
|
# Temporary storage location
|
||||||
runroot = "/run/containers/storage"
|
runroot = "/run/containers/storage"
|
||||||
|
|
||||||
|
# Priority list for the storage drivers that will be tested one
|
||||||
|
# after the other to pick the storage driver if it is not defined.
|
||||||
|
# driver_priority = ["overlay", "btrfs"]
|
||||||
|
|
||||||
# Primary Read/Write location of container storage
|
# Primary Read/Write location of container storage
|
||||||
# When changing the graphroot location on an SELINUX system, you must
|
# When changing the graphroot location on an SELINUX system, you must
|
||||||
# ensure the labeling matches the default locations labels with the
|
# ensure the labeling matches the default locations labels with the
|
||||||
|
|
@ -77,28 +81,6 @@ additionalimagestores = [
|
||||||
# operation so it is not enabled by default.
|
# operation so it is not enabled by default.
|
||||||
pull_options = {enable_partial_images = "true", use_hard_links = "false", ostree_repos=""}
|
pull_options = {enable_partial_images = "true", use_hard_links = "false", ostree_repos=""}
|
||||||
|
|
||||||
# Remap-UIDs/GIDs is the mapping from UIDs/GIDs as they should appear inside of
|
|
||||||
# a container, to the UIDs/GIDs as they should appear outside of the container,
|
|
||||||
# and the length of the range of UIDs/GIDs. Additional mapped sets can be
|
|
||||||
# listed and will be heeded by libraries, but there are limits to the number of
|
|
||||||
# mappings which the kernel will allow when you later attempt to run a
|
|
||||||
# container.
|
|
||||||
#
|
|
||||||
# remap-uids = "0:1668442479:65536"
|
|
||||||
# remap-gids = "0:1668442479:65536"
|
|
||||||
|
|
||||||
# Remap-User/Group is a user name which can be used to look up one or more UID/GID
|
|
||||||
# ranges in the /etc/subuid or /etc/subgid file. Mappings are set up starting
|
|
||||||
# with an in-container ID of 0 and then a host-level ID taken from the lowest
|
|
||||||
# range that matches the specified name, and using the length of that range.
|
|
||||||
# Additional ranges are then assigned, using the ranges which specify the
|
|
||||||
# lowest host-level IDs first, to the lowest not-yet-mapped in-container ID,
|
|
||||||
# until all of the entries have been used for maps. This setting overrides the
|
|
||||||
# Remap-UIDs/GIDs setting.
|
|
||||||
#
|
|
||||||
# remap-user = "containers"
|
|
||||||
# remap-group = "containers"
|
|
||||||
|
|
||||||
# Root-auto-userns-user is a user name which can be used to look up one or more UID/GID
|
# Root-auto-userns-user is a user name which can be used to look up one or more UID/GID
|
||||||
# ranges in the /etc/subuid and /etc/subgid file. These ranges will be partitioned
|
# ranges in the /etc/subuid and /etc/subgid file. These ranges will be partitioned
|
||||||
# to containers configured to create automatically a user namespace. Containers
|
# to containers configured to create automatically a user namespace. Containers
|
||||||
|
|
|
||||||
21
vendor/github.com/containers/storage/storage.conf-freebsd
generated
vendored
21
vendor/github.com/containers/storage/storage.conf-freebsd
generated
vendored
|
|
@ -39,27 +39,6 @@ graphroot = "/var/db/containers/storage"
|
||||||
additionalimagestores = [
|
additionalimagestores = [
|
||||||
]
|
]
|
||||||
|
|
||||||
# Remap-UIDs/GIDs is the mapping from UIDs/GIDs as they should appear inside of
|
|
||||||
# a container, to the UIDs/GIDs as they should appear outside of the container,
|
|
||||||
# and the length of the range of UIDs/GIDs. Additional mapped sets can be
|
|
||||||
# listed and will be heeded by libraries, but there are limits to the number of
|
|
||||||
# mappings which the kernel will allow when you later attempt to run a
|
|
||||||
# container.
|
|
||||||
#
|
|
||||||
# remap-uids = 0:1668442479:65536
|
|
||||||
# remap-gids = 0:1668442479:65536
|
|
||||||
|
|
||||||
# Remap-User/Group is a user name which can be used to look up one or more UID/GID
|
|
||||||
# ranges in the /etc/subuid or /etc/subgid file. Mappings are set up starting
|
|
||||||
# with an in-container ID of 0 and then a host-level ID taken from the lowest
|
|
||||||
# range that matches the specified name, and using the length of that range.
|
|
||||||
# Additional ranges are then assigned, using the ranges which specify the
|
|
||||||
# lowest host-level IDs first, to the lowest not-yet-mapped in-container ID,
|
|
||||||
# until all of the entries have been used for maps.
|
|
||||||
#
|
|
||||||
# remap-user = "containers"
|
|
||||||
# remap-group = "containers"
|
|
||||||
|
|
||||||
# Root-auto-userns-user is a user name which can be used to look up one or more UID/GID
|
# Root-auto-userns-user is a user name which can be used to look up one or more UID/GID
|
||||||
# ranges in the /etc/subuid and /etc/subgid file. These ranges will be partitioned
|
# ranges in the /etc/subuid and /etc/subgid file. These ranges will be partitioned
|
||||||
# to containers configured to create automatically a user namespace. Containers
|
# to containers configured to create automatically a user namespace. Containers
|
||||||
|
|
|
||||||
102
vendor/github.com/containers/storage/store.go
generated
vendored
102
vendor/github.com/containers/storage/store.go
generated
vendored
|
|
@ -1088,8 +1088,6 @@ func (s *store) createGraphDriverLocked() (drivers.Driver, error) {
|
||||||
RunRoot: s.runRoot,
|
RunRoot: s.runRoot,
|
||||||
DriverPriority: s.graphDriverPriority,
|
DriverPriority: s.graphDriverPriority,
|
||||||
DriverOptions: s.graphOptions,
|
DriverOptions: s.graphOptions,
|
||||||
UIDMaps: s.uidMap,
|
|
||||||
GIDMaps: s.gidMap,
|
|
||||||
}
|
}
|
||||||
return drivers.New(s.graphDriverName, config)
|
return drivers.New(s.graphDriverName, config)
|
||||||
}
|
}
|
||||||
|
|
@ -1437,7 +1435,9 @@ func (s *store) canUseShifting(uidmap, gidmap []idtools.IDMap) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// putLayer requires the rlstore, rlstores, as well as s.containerStore (even if not an argument to this function) to be locked for write.
|
// On entry:
|
||||||
|
// - rlstore must be locked for writing
|
||||||
|
// - rlstores MUST NOT be locked
|
||||||
func (s *store) putLayer(rlstore rwLayerStore, rlstores []roLayerStore, id, parent string, names []string, mountLabel string, writeable bool, lOptions *LayerOptions, diff io.Reader, slo *stagedLayerOptions) (*Layer, int64, error) {
|
func (s *store) putLayer(rlstore rwLayerStore, rlstores []roLayerStore, id, parent string, names []string, mountLabel string, writeable bool, lOptions *LayerOptions, diff io.Reader, slo *stagedLayerOptions) (*Layer, int64, error) {
|
||||||
var parentLayer *Layer
|
var parentLayer *Layer
|
||||||
var options LayerOptions
|
var options LayerOptions
|
||||||
|
|
@ -1474,6 +1474,11 @@ func (s *store) putLayer(rlstore rwLayerStore, rlstores []roLayerStore, id, pare
|
||||||
return nil, -1, ErrLayerUnknown
|
return nil, -1, ErrLayerUnknown
|
||||||
}
|
}
|
||||||
parentLayer = ilayer
|
parentLayer = ilayer
|
||||||
|
|
||||||
|
if err := s.containerStore.startWriting(); err != nil {
|
||||||
|
return nil, -1, err
|
||||||
|
}
|
||||||
|
defer s.containerStore.stopWriting()
|
||||||
containers, err := s.containerStore.Containers()
|
containers, err := s.containerStore.Containers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, -1, err
|
return nil, -1, err
|
||||||
|
|
@ -1490,6 +1495,13 @@ func (s *store) putLayer(rlstore rwLayerStore, rlstores []roLayerStore, id, pare
|
||||||
gidMap = ilayer.GIDMap
|
gidMap = ilayer.GIDMap
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// FIXME? It’s unclear why we are holding containerStore locked here at all
|
||||||
|
// (and because we are not modifying it, why it is a write lock, not a read lock).
|
||||||
|
if err := s.containerStore.startWriting(); err != nil {
|
||||||
|
return nil, -1, err
|
||||||
|
}
|
||||||
|
defer s.containerStore.stopWriting()
|
||||||
|
|
||||||
if !options.HostUIDMapping && len(options.UIDMap) == 0 {
|
if !options.HostUIDMapping && len(options.UIDMap) == 0 {
|
||||||
uidMap = s.uidMap
|
uidMap = s.uidMap
|
||||||
}
|
}
|
||||||
|
|
@ -1497,23 +1509,17 @@ func (s *store) putLayer(rlstore rwLayerStore, rlstores []roLayerStore, id, pare
|
||||||
gidMap = s.gidMap
|
gidMap = s.gidMap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
layerOptions := LayerOptions{
|
|
||||||
OriginalDigest: options.OriginalDigest,
|
|
||||||
OriginalSize: options.OriginalSize,
|
|
||||||
UncompressedDigest: options.UncompressedDigest,
|
|
||||||
Flags: options.Flags,
|
|
||||||
}
|
|
||||||
if s.canUseShifting(uidMap, gidMap) {
|
if s.canUseShifting(uidMap, gidMap) {
|
||||||
layerOptions.IDMappingOptions = types.IDMappingOptions{HostUIDMapping: true, HostGIDMapping: true, UIDMap: nil, GIDMap: nil}
|
options.IDMappingOptions = types.IDMappingOptions{HostUIDMapping: true, HostGIDMapping: true, UIDMap: nil, GIDMap: nil}
|
||||||
} else {
|
} else {
|
||||||
layerOptions.IDMappingOptions = types.IDMappingOptions{
|
options.IDMappingOptions = types.IDMappingOptions{
|
||||||
HostUIDMapping: options.HostUIDMapping,
|
HostUIDMapping: options.HostUIDMapping,
|
||||||
HostGIDMapping: options.HostGIDMapping,
|
HostGIDMapping: options.HostGIDMapping,
|
||||||
UIDMap: copyIDMap(uidMap),
|
UIDMap: copyIDMap(uidMap),
|
||||||
GIDMap: copyIDMap(gidMap),
|
GIDMap: copyIDMap(gidMap),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rlstore.create(id, parentLayer, names, mountLabel, nil, &layerOptions, writeable, diff, slo)
|
return rlstore.create(id, parentLayer, names, mountLabel, nil, &options, writeable, diff, slo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) PutLayer(id, parent string, names []string, mountLabel string, writeable bool, lOptions *LayerOptions, diff io.Reader) (*Layer, int64, error) {
|
func (s *store) PutLayer(id, parent string, names []string, mountLabel string, writeable bool, lOptions *LayerOptions, diff io.Reader) (*Layer, int64, error) {
|
||||||
|
|
@ -1525,10 +1531,6 @@ func (s *store) PutLayer(id, parent string, names []string, mountLabel string, w
|
||||||
return nil, -1, err
|
return nil, -1, err
|
||||||
}
|
}
|
||||||
defer rlstore.stopWriting()
|
defer rlstore.stopWriting()
|
||||||
if err := s.containerStore.startWriting(); err != nil {
|
|
||||||
return nil, -1, err
|
|
||||||
}
|
|
||||||
defer s.containerStore.stopWriting()
|
|
||||||
return s.putLayer(rlstore, rlstores, id, parent, names, mountLabel, writeable, lOptions, diff, nil)
|
return s.putLayer(rlstore, rlstores, id, parent, names, mountLabel, writeable, lOptions, diff, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2844,7 +2846,7 @@ func (s *store) mount(id string, options drivers.MountOpts) (string, error) {
|
||||||
exists := store.Exists(id)
|
exists := store.Exists(id)
|
||||||
store.stopReading()
|
store.stopReading()
|
||||||
if exists {
|
if exists {
|
||||||
return "", fmt.Errorf("mounting read/only store images is not allowed: %w", ErrLayerUnknown)
|
return "", fmt.Errorf("mounting read/only store images is not allowed: %w", ErrStoreIsReadOnly)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2928,14 +2930,40 @@ func (s *store) Unmount(id string, force bool) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *store) Changes(from, to string) ([]archive.Change, error) {
|
func (s *store) Changes(from, to string) ([]archive.Change, error) {
|
||||||
if res, done, err := readAllLayerStores(s, func(store roLayerStore) ([]archive.Change, bool, error) {
|
// NaiveDiff could cause mounts to happen without a lock, so be safe
|
||||||
|
// and treat the .Diff operation as a Mount.
|
||||||
|
// We need to make sure the home mount is present when the Mount is done, which happens by possibly reinitializing the graph driver
|
||||||
|
// in startUsingGraphDriver().
|
||||||
|
if err := s.startUsingGraphDriver(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer s.stopUsingGraphDriver()
|
||||||
|
|
||||||
|
rlstore, lstores, err := s.bothLayerStoreKindsLocked()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := rlstore.startWriting(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if rlstore.Exists(to) {
|
||||||
|
res, err := rlstore.Changes(from, to)
|
||||||
|
rlstore.stopWriting()
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
rlstore.stopWriting()
|
||||||
|
|
||||||
|
for _, s := range lstores {
|
||||||
|
store := s
|
||||||
|
if err := store.startReading(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if store.Exists(to) {
|
if store.Exists(to) {
|
||||||
res, err := store.Changes(from, to)
|
res, err := store.Changes(from, to)
|
||||||
return res, true, err
|
store.stopReading()
|
||||||
|
return res, err
|
||||||
}
|
}
|
||||||
return nil, false, nil
|
store.stopReading()
|
||||||
}); done {
|
|
||||||
return res, err
|
|
||||||
}
|
}
|
||||||
return nil, ErrLayerUnknown
|
return nil, ErrLayerUnknown
|
||||||
}
|
}
|
||||||
|
|
@ -2966,12 +2994,30 @@ func (s *store) Diff(from, to string, options *DiffOptions) (io.ReadCloser, erro
|
||||||
}
|
}
|
||||||
defer s.stopUsingGraphDriver()
|
defer s.stopUsingGraphDriver()
|
||||||
|
|
||||||
layerStores, err := s.allLayerStoresLocked()
|
rlstore, lstores, err := s.bothLayerStoreKindsLocked()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range layerStores {
|
if err := rlstore.startWriting(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if rlstore.Exists(to) {
|
||||||
|
rc, err := rlstore.Diff(from, to, options)
|
||||||
|
if rc != nil && err == nil {
|
||||||
|
wrapped := ioutils.NewReadCloserWrapper(rc, func() error {
|
||||||
|
err := rc.Close()
|
||||||
|
rlstore.stopWriting()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
return wrapped, nil
|
||||||
|
}
|
||||||
|
rlstore.stopWriting()
|
||||||
|
return rc, err
|
||||||
|
}
|
||||||
|
rlstore.stopWriting()
|
||||||
|
|
||||||
|
for _, s := range lstores {
|
||||||
store := s
|
store := s
|
||||||
if err := store.startReading(); err != nil {
|
if err := store.startReading(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -3009,16 +3055,14 @@ func (s *store) ApplyStagedLayer(args ApplyStagedLayerOptions) (*Layer, error) {
|
||||||
return layer, err
|
return layer, err
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
// This code path exists only for cmd/containers/storage.applyDiffUsingStagingDirectory; we have tests that
|
||||||
|
// assume layer creation and applying a staged layer are separate steps. Production pull code always uses the
|
||||||
|
// other path, where layer creation is atomic.
|
||||||
return layer, rlstore.applyDiffFromStagingDirectory(args.ID, args.DiffOutput, args.DiffOptions)
|
return layer, rlstore.applyDiffFromStagingDirectory(args.ID, args.DiffOutput, args.DiffOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the layer doesn't exist yet, try to create it.
|
// if the layer doesn't exist yet, try to create it.
|
||||||
|
|
||||||
if err := s.containerStore.startWriting(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer s.containerStore.stopWriting()
|
|
||||||
|
|
||||||
slo := stagedLayerOptions{
|
slo := stagedLayerOptions{
|
||||||
DiffOutput: args.DiffOutput,
|
DiffOutput: args.DiffOutput,
|
||||||
DiffOptions: args.DiffOptions,
|
DiffOptions: args.DiffOptions,
|
||||||
|
|
|
||||||
29
vendor/github.com/containers/storage/types/options.go
generated
vendored
29
vendor/github.com/containers/storage/types/options.go
generated
vendored
|
|
@ -352,7 +352,7 @@ func getRootlessStorageOpts(systemOpts StoreOptions) (StoreOptions, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.GraphDriverName == "" {
|
if opts.GraphDriverName == "" {
|
||||||
if canUseRootlessOverlay(opts.GraphRoot, opts.RunRoot) {
|
if canUseRootlessOverlay() {
|
||||||
opts.GraphDriverName = overlayDriver
|
opts.GraphDriverName = overlayDriver
|
||||||
} else {
|
} else {
|
||||||
opts.GraphDriverName = "vfs"
|
opts.GraphDriverName = "vfs"
|
||||||
|
|
@ -481,33 +481,6 @@ func ReloadConfigurationFile(configFile string, storeOptions *StoreOptions) erro
|
||||||
if config.Storage.Options.MountOpt != "" {
|
if config.Storage.Options.MountOpt != "" {
|
||||||
storeOptions.GraphDriverOptions = append(storeOptions.GraphDriverOptions, fmt.Sprintf("%s.mountopt=%s", config.Storage.Driver, config.Storage.Options.MountOpt))
|
storeOptions.GraphDriverOptions = append(storeOptions.GraphDriverOptions, fmt.Sprintf("%s.mountopt=%s", config.Storage.Driver, config.Storage.Options.MountOpt))
|
||||||
}
|
}
|
||||||
|
|
||||||
uidmap, err := idtools.ParseIDMap([]string{config.Storage.Options.RemapUIDs}, "remap-uids")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
gidmap, err := idtools.ParseIDMap([]string{config.Storage.Options.RemapGIDs}, "remap-gids")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.Storage.Options.RemapUser != "" && config.Storage.Options.RemapGroup == "" {
|
|
||||||
config.Storage.Options.RemapGroup = config.Storage.Options.RemapUser
|
|
||||||
}
|
|
||||||
if config.Storage.Options.RemapGroup != "" && config.Storage.Options.RemapUser == "" {
|
|
||||||
config.Storage.Options.RemapUser = config.Storage.Options.RemapGroup
|
|
||||||
}
|
|
||||||
if config.Storage.Options.RemapUser != "" && config.Storage.Options.RemapGroup != "" {
|
|
||||||
mappings, err := idtools.NewIDMappings(config.Storage.Options.RemapUser, config.Storage.Options.RemapGroup)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Warningf("Error initializing ID mappings for %s:%s %v\n", config.Storage.Options.RemapUser, config.Storage.Options.RemapGroup, err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
uidmap = mappings.UIDs()
|
|
||||||
gidmap = mappings.GIDs()
|
|
||||||
}
|
|
||||||
storeOptions.UIDMap = uidmap
|
|
||||||
storeOptions.GIDMap = gidmap
|
|
||||||
storeOptions.RootAutoNsUser = config.Storage.Options.RootAutoUsernsUser
|
storeOptions.RootAutoNsUser = config.Storage.Options.RootAutoUsernsUser
|
||||||
if config.Storage.Options.AutoUsernsMinSize > 0 {
|
if config.Storage.Options.AutoUsernsMinSize > 0 {
|
||||||
storeOptions.AutoNsMinSize = config.Storage.Options.AutoUsernsMinSize
|
storeOptions.AutoNsMinSize = config.Storage.Options.AutoUsernsMinSize
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//go:build freebsd || netbsd
|
||||||
|
|
||||||
package types
|
package types
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -14,6 +16,6 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// canUseRootlessOverlay returns true if the overlay driver can be used for rootless containers
|
// canUseRootlessOverlay returns true if the overlay driver can be used for rootless containers
|
||||||
func canUseRootlessOverlay(home, runhome string) bool {
|
func canUseRootlessOverlay() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
2
vendor/github.com/containers/storage/types/options_darwin.go
generated
vendored
2
vendor/github.com/containers/storage/types/options_darwin.go
generated
vendored
|
|
@ -11,6 +11,6 @@ const (
|
||||||
var defaultOverrideConfigFile = "/etc/containers/storage.conf"
|
var defaultOverrideConfigFile = "/etc/containers/storage.conf"
|
||||||
|
|
||||||
// canUseRootlessOverlay returns true if the overlay driver can be used for rootless containers
|
// canUseRootlessOverlay returns true if the overlay driver can be used for rootless containers
|
||||||
func canUseRootlessOverlay(home, runhome string) bool {
|
func canUseRootlessOverlay() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
vendor/github.com/containers/storage/types/options_linux.go
generated
vendored
2
vendor/github.com/containers/storage/types/options_linux.go
generated
vendored
|
|
@ -22,7 +22,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// canUseRootlessOverlay returns true if the overlay driver can be used for rootless containers
|
// canUseRootlessOverlay returns true if the overlay driver can be used for rootless containers
|
||||||
func canUseRootlessOverlay(home, runhome string) bool {
|
func canUseRootlessOverlay() bool {
|
||||||
// we check first for fuse-overlayfs since it is cheaper.
|
// we check first for fuse-overlayfs since it is cheaper.
|
||||||
if path, _ := exec.LookPath("fuse-overlayfs"); path != "" {
|
if path, _ := exec.LookPath("fuse-overlayfs"); path != "" {
|
||||||
return true
|
return true
|
||||||
|
|
|
||||||
2
vendor/github.com/containers/storage/types/options_windows.go
generated
vendored
2
vendor/github.com/containers/storage/types/options_windows.go
generated
vendored
|
|
@ -14,6 +14,6 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// canUseRootlessOverlay returns true if the overlay driver can be used for rootless containers
|
// canUseRootlessOverlay returns true if the overlay driver can be used for rootless containers
|
||||||
func canUseRootlessOverlay(home, runhome string) bool {
|
func canUseRootlessOverlay() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
vendor/github.com/containers/storage/types/storage_test.conf
generated
vendored
10
vendor/github.com/containers/storage/types/storage_test.conf
generated
vendored
|
|
@ -25,16 +25,6 @@ rootless_storage_path = "$HOME/$UID/containers/storage"
|
||||||
additionalimagestores = [
|
additionalimagestores = [
|
||||||
]
|
]
|
||||||
|
|
||||||
# Remap-UIDs/GIDs is the mapping from UIDs/GIDs as they should appear inside of
|
|
||||||
# a container, to the UIDs/GIDs as they should appear outside of the container,
|
|
||||||
# and the length of the range of UIDs/GIDs. Additional mapped sets can be
|
|
||||||
# listed and will be heeded by libraries, but there are limits to the number of
|
|
||||||
# mappings which the kernel will allow when you later attempt to run a
|
|
||||||
# container.
|
|
||||||
#
|
|
||||||
remap-uids = "0:1000000000:30000"
|
|
||||||
remap-gids = "0:1500000000:60000"
|
|
||||||
|
|
||||||
[storage.options.overlay]
|
[storage.options.overlay]
|
||||||
|
|
||||||
# mountopt specifies comma separated list of extra mount options
|
# mountopt specifies comma separated list of extra mount options
|
||||||
|
|
|
||||||
5
vendor/github.com/containers/storage/types/utils.go
generated
vendored
5
vendor/github.com/containers/storage/types/utils.go
generated
vendored
|
|
@ -66,7 +66,10 @@ func reloadConfigurationFileIfNeeded(configFile string, storeOptions *StoreOptio
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ReloadConfigurationFile(configFile, storeOptions)
|
if err := ReloadConfigurationFile(configFile, storeOptions); err != nil {
|
||||||
|
logrus.Warningf("Failed to reload %q %v\n", configFile, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
prevReloadConfig.storeOptions = storeOptions
|
prevReloadConfig.storeOptions = storeOptions
|
||||||
prevReloadConfig.mod = mtime
|
prevReloadConfig.mod = mtime
|
||||||
|
|
|
||||||
138
vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md
generated
vendored
Normal file
138
vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md
generated
vendored
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
# Changelog #
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||||
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
## [Unreleased] ##
|
||||||
|
|
||||||
|
## [0.3.1] - 2024-07-23 ##
|
||||||
|
|
||||||
|
### Changed ###
|
||||||
|
- By allowing `Open(at)InRoot` to opt-out of the extra work done by `MkdirAll`
|
||||||
|
to do the necessary "partial lookups", `Open(at)InRoot` now does less work
|
||||||
|
for both implementations (resulting in a many-fold decrease in the number of
|
||||||
|
operations for `openat2`, and a modest improvement for non-`openat2`) and is
|
||||||
|
far more guaranteed to match the correct `openat2(RESOLVE_IN_ROOT)`
|
||||||
|
behaviour.
|
||||||
|
- We now use `readlinkat(fd, "")` where possible. For `Open(at)InRoot` this
|
||||||
|
effectively just means that we no longer risk getting spurious errors during
|
||||||
|
rename races. However, for our hardened procfs handler, this in theory should
|
||||||
|
prevent mount attacks from tricking us when doing magic-link readlinks (even
|
||||||
|
when using the unsafe host `/proc` handle). Unfortunately `Reopen` is still
|
||||||
|
potentially vulnerable to those kinds of somewhat-esoteric attacks.
|
||||||
|
|
||||||
|
Technically this [will only work on post-2.6.39 kernels][linux-readlinkat-emptypath]
|
||||||
|
but it seems incredibly unlikely anyone is using `filepath-securejoin` on a
|
||||||
|
pre-2011 kernel.
|
||||||
|
|
||||||
|
### Fixed ###
|
||||||
|
- Several improvements were made to the errors returned by `Open(at)InRoot` and
|
||||||
|
`MkdirAll` when dealing with invalid paths under the emulated (ie.
|
||||||
|
non-`openat2`) implementation. Previously, some paths would return the wrong
|
||||||
|
error (`ENOENT` when the last component was a non-directory), and other paths
|
||||||
|
would be returned as though they were acceptable (trailing-slash components
|
||||||
|
after a non-directory would be ignored by `Open(at)InRoot`).
|
||||||
|
|
||||||
|
These changes were done to match `openat2`'s behaviour and purely is a
|
||||||
|
consistency fix (most users are going to be using `openat2` anyway).
|
||||||
|
|
||||||
|
[linux-readlinkat-emptypath]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=65cfc6722361570bfe255698d9cd4dccaf47570d
|
||||||
|
|
||||||
|
## [0.3.0] - 2024-07-11 ##
|
||||||
|
|
||||||
|
### Added ###
|
||||||
|
- A new set of `*os.File`-based APIs have been added. These are adapted from
|
||||||
|
[libpathrs][] and we strongly suggest using them if possible (as they provide
|
||||||
|
far more protection against attacks than `SecureJoin`):
|
||||||
|
|
||||||
|
- `Open(at)InRoot` resolves a path inside a rootfs and returns an `*os.File`
|
||||||
|
handle to the path. Note that the handle returned is an `O_PATH` handle,
|
||||||
|
which cannot be used for reading or writing (as well as some other
|
||||||
|
operations -- [see open(2) for more details][open.2])
|
||||||
|
|
||||||
|
- `Reopen` takes an `O_PATH` file handle and safely re-opens it to upgrade
|
||||||
|
it to a regular handle. This can also be used with non-`O_PATH` handles,
|
||||||
|
but `O_PATH` is the most obvious application.
|
||||||
|
|
||||||
|
- `MkdirAll` is an implementation of `os.MkdirAll` that is safe to use to
|
||||||
|
create a directory tree within a rootfs.
|
||||||
|
|
||||||
|
As these are new APIs, they may change in the future. However, they should be
|
||||||
|
safe to start migrating to as we have extensive tests ensuring they behave
|
||||||
|
correctly and are safe against various races and other attacks.
|
||||||
|
|
||||||
|
[libpathrs]: https://github.com/openSUSE/libpathrs
|
||||||
|
[open.2]: https://www.man7.org/linux/man-pages/man2/open.2.html
|
||||||
|
|
||||||
|
## [0.2.5] - 2024-05-03 ##
|
||||||
|
|
||||||
|
### Changed ###
|
||||||
|
- Some minor changes were made to how lexical components (like `..` and `.`)
|
||||||
|
are handled during path generation in `SecureJoin`. There is no behaviour
|
||||||
|
change as a result of this fix (the resulting paths are the same).
|
||||||
|
|
||||||
|
### Fixed ###
|
||||||
|
- The error returned when we hit a symlink loop now references the correct
|
||||||
|
path. (#10)
|
||||||
|
|
||||||
|
## [0.2.4] - 2023-09-06 ##
|
||||||
|
|
||||||
|
### Security ###
|
||||||
|
- This release fixes a potential security issue in filepath-securejoin when
|
||||||
|
used on Windows ([GHSA-6xv5-86q9-7xr8][], which could be used to generate
|
||||||
|
paths outside of the provided rootfs in certain cases), as well as improving
|
||||||
|
the overall behaviour of filepath-securejoin when dealing with Windows paths
|
||||||
|
that contain volume names. Thanks to Paulo Gomes for discovering and fixing
|
||||||
|
these issues.
|
||||||
|
|
||||||
|
### Fixed ###
|
||||||
|
- Switch to GitHub Actions for CI so we can test on Windows as well as Linux
|
||||||
|
and MacOS.
|
||||||
|
|
||||||
|
[GHSA-6xv5-86q9-7xr8]: https://github.com/advisories/GHSA-6xv5-86q9-7xr8
|
||||||
|
|
||||||
|
## [0.2.3] - 2021-06-04 ##
|
||||||
|
|
||||||
|
### Changed ###
|
||||||
|
- Switch to Go 1.13-style `%w` error wrapping, letting us drop the dependency
|
||||||
|
on `github.com/pkg/errors`.
|
||||||
|
|
||||||
|
## [0.2.2] - 2018-09-05 ##
|
||||||
|
|
||||||
|
### Changed ###
|
||||||
|
- Use `syscall.ELOOP` as the base error for symlink loops, rather than our own
|
||||||
|
(internal) error. This allows callers to more easily use `errors.Is` to check
|
||||||
|
for this case.
|
||||||
|
|
||||||
|
## [0.2.1] - 2018-09-05 ##
|
||||||
|
|
||||||
|
### Fixed ###
|
||||||
|
- Use our own `IsNotExist` implementation, which lets us handle `ENOTDIR`
|
||||||
|
properly within `SecureJoin`.
|
||||||
|
|
||||||
|
## [0.2.0] - 2017-07-19 ##
|
||||||
|
|
||||||
|
We now have 100% test coverage!
|
||||||
|
|
||||||
|
### Added ###
|
||||||
|
- Add a `SecureJoinVFS` API that can be used for mocking (as we do in our new
|
||||||
|
tests) or for implementing custom handling of lookup operations (such as for
|
||||||
|
rootless containers, where work is necessary to access directories with weird
|
||||||
|
modes because we don't have `CAP_DAC_READ_SEARCH` or `CAP_DAC_OVERRIDE`).
|
||||||
|
|
||||||
|
## 0.1.0 - 2017-07-19
|
||||||
|
|
||||||
|
This is our first release of `github.com/cyphar/filepath-securejoin`,
|
||||||
|
containing a full implementation with a coverage of 93.5% (the only missing
|
||||||
|
cases are the error cases, which are hard to mocktest at the moment).
|
||||||
|
|
||||||
|
[Unreleased]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.1...HEAD
|
||||||
|
[0.3.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.0...v0.3.1
|
||||||
|
[0.3.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.5...v0.3.0
|
||||||
|
[0.2.5]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.4...v0.2.5
|
||||||
|
[0.2.4]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.3...v0.2.4
|
||||||
|
[0.2.3]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.2...v0.2.3
|
||||||
|
[0.2.2]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.1...v0.2.2
|
||||||
|
[0.2.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.0...v0.2.1
|
||||||
|
[0.2.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.1.0...v0.2.0
|
||||||
2
vendor/github.com/cyphar/filepath-securejoin/LICENSE
generated
vendored
2
vendor/github.com/cyphar/filepath-securejoin/LICENSE
generated
vendored
|
|
@ -1,5 +1,5 @@
|
||||||
Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved.
|
Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved.
|
||||||
Copyright (C) 2017 SUSE LLC. All rights reserved.
|
Copyright (C) 2017-2024 SUSE LLC. All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are
|
modification, are permitted provided that the following conditions are
|
||||||
|
|
|
||||||
135
vendor/github.com/cyphar/filepath-securejoin/README.md
generated
vendored
135
vendor/github.com/cyphar/filepath-securejoin/README.md
generated
vendored
|
|
@ -2,31 +2,24 @@
|
||||||
|
|
||||||
[](https://github.com/cyphar/filepath-securejoin/actions/workflows/ci.yml)
|
[](https://github.com/cyphar/filepath-securejoin/actions/workflows/ci.yml)
|
||||||
|
|
||||||
An implementation of `SecureJoin`, a [candidate for inclusion in the Go
|
### Old API ###
|
||||||
standard library][go#20126]. The purpose of this function is to be a "secure"
|
|
||||||
alternative to `filepath.Join`, and in particular it provides certain
|
|
||||||
guarantees that are not provided by `filepath.Join`.
|
|
||||||
|
|
||||||
> **NOTE**: This code is *only* safe if you are not at risk of other processes
|
This library was originally just an implementation of `SecureJoin` which was
|
||||||
> modifying path components after you've used `SecureJoin`. If it is possible
|
[intended to be included in the Go standard library][go#20126] as a safer
|
||||||
> for a malicious process to modify path components of the resolved path, then
|
`filepath.Join` that would restrict the path lookup to be inside a root
|
||||||
> you will be vulnerable to some fairly trivial TOCTOU race conditions. [There
|
directory.
|
||||||
> are some Linux kernel patches I'm working on which might allow for a better
|
|
||||||
> solution.][lwn-obeneath]
|
|
||||||
>
|
|
||||||
> In addition, with a slightly modified API it might be possible to use
|
|
||||||
> `O_PATH` and verify that the opened path is actually the resolved one -- but
|
|
||||||
> I have not done that yet. I might add it in the future as a helper function
|
|
||||||
> to help users verify the path (we can't just return `/proc/self/fd/<foo>`
|
|
||||||
> because that doesn't always work transparently for all users).
|
|
||||||
|
|
||||||
This is the function prototype:
|
The implementation was based on code that existed in several container
|
||||||
|
runtimes. Unfortunately, this API is **fundamentally unsafe** against attackers
|
||||||
|
that can modify path components after `SecureJoin` returns and before the
|
||||||
|
caller uses the path, allowing for some fairly trivial TOCTOU attacks.
|
||||||
|
|
||||||
```go
|
`SecureJoin` (and `SecureJoinVFS`) are still provided by this library to
|
||||||
func SecureJoin(root, unsafePath string) (string, error)
|
support legacy users, but new users are strongly suggested to avoid using
|
||||||
```
|
`SecureJoin` and instead use the [new api](#new-api) or switch to
|
||||||
|
[libpathrs][libpathrs].
|
||||||
|
|
||||||
This library **guarantees** the following:
|
With the above limitations in mind, this library guarantees the following:
|
||||||
|
|
||||||
* If no error is set, the resulting string **must** be a child path of
|
* If no error is set, the resulting string **must** be a child path of
|
||||||
`root` and will not contain any symlink path components (they will all be
|
`root` and will not contain any symlink path components (they will all be
|
||||||
|
|
@ -47,7 +40,7 @@ This library **guarantees** the following:
|
||||||
A (trivial) implementation of this function on GNU/Linux systems could be done
|
A (trivial) implementation of this function on GNU/Linux systems could be done
|
||||||
with the following (note that this requires root privileges and is far more
|
with the following (note that this requires root privileges and is far more
|
||||||
opaque than the implementation in this library, and also requires that
|
opaque than the implementation in this library, and also requires that
|
||||||
`readlink` is inside the `root` path):
|
`readlink` is inside the `root` path and is trustworthy):
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package securejoin
|
package securejoin
|
||||||
|
|
@ -70,9 +63,105 @@ func SecureJoin(root, unsafePath string) (string, error) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[lwn-obeneath]: https://lwn.net/Articles/767547/
|
[libpathrs]: https://github.com/openSUSE/libpathrs
|
||||||
[go#20126]: https://github.com/golang/go/issues/20126
|
[go#20126]: https://github.com/golang/go/issues/20126
|
||||||
|
|
||||||
|
### New API ###
|
||||||
|
|
||||||
|
While we recommend users switch to [libpathrs][libpathrs] as soon as it has a
|
||||||
|
stable release, some methods implemented by libpathrs have been ported to this
|
||||||
|
library to ease the transition. These APIs are only supported on Linux.
|
||||||
|
|
||||||
|
These APIs are implemented such that `filepath-securejoin` will
|
||||||
|
opportunistically use certain newer kernel APIs that make these operations far
|
||||||
|
more secure. In particular:
|
||||||
|
|
||||||
|
* All of the lookup operations will use [`openat2`][openat2.2] on new enough
|
||||||
|
kernels (Linux 5.6 or later) to restrict lookups through magic-links and
|
||||||
|
bind-mounts (for certain operations) and to make use of `RESOLVE_IN_ROOT` to
|
||||||
|
efficiently resolve symlinks within a rootfs.
|
||||||
|
|
||||||
|
* The APIs provide hardening against a malicious `/proc` mount to either detect
|
||||||
|
or avoid being tricked by a `/proc` that is not legitimate. This is done
|
||||||
|
using [`openat2`][openat2.2] for all users, and privileged users will also be
|
||||||
|
further protected by using [`fsopen`][fsopen.2] and [`open_tree`][open_tree.2]
|
||||||
|
(Linux 4.18 or later).
|
||||||
|
|
||||||
|
[openat2.2]: https://www.man7.org/linux/man-pages/man2/openat2.2.html
|
||||||
|
[fsopen.2]: https://github.com/brauner/man-pages-md/blob/main/fsopen.md
|
||||||
|
[open_tree.2]: https://github.com/brauner/man-pages-md/blob/main/open_tree.md
|
||||||
|
|
||||||
|
#### `OpenInRoot` ####
|
||||||
|
|
||||||
|
```go
|
||||||
|
func OpenInRoot(root, unsafePath string) (*os.File, error)
|
||||||
|
func OpenatInRoot(root *os.File, unsafePath string) (*os.File, error)
|
||||||
|
func Reopen(handle *os.File, flags int) (*os.File, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
`OpenInRoot` is a much safer version of
|
||||||
|
|
||||||
|
```go
|
||||||
|
path, err := securejoin.SecureJoin(root, unsafePath)
|
||||||
|
file, err := os.OpenFile(path, unix.O_PATH|unix.O_CLOEXEC)
|
||||||
|
```
|
||||||
|
|
||||||
|
that protects against various race attacks that could lead to serious security
|
||||||
|
issues, depending on the application. Note that the returned `*os.File` is an
|
||||||
|
`O_PATH` file descriptor, which is quite restricted. Callers will probably need
|
||||||
|
to use `Reopen` to get a more usable handle (this split is done to provide
|
||||||
|
useful features like PTY spawning and to avoid users accidentally opening bad
|
||||||
|
inodes that could cause a DoS).
|
||||||
|
|
||||||
|
Callers need to be careful in how they use the returned `*os.File`. Usually it
|
||||||
|
is only safe to operate on the handle directly, and it is very easy to create a
|
||||||
|
security issue. [libpathrs][libpathrs] provides far more helpers to make using
|
||||||
|
these handles safer -- there is currently no plan to port them to
|
||||||
|
`filepath-securejoin`.
|
||||||
|
|
||||||
|
`OpenatInRoot` is like `OpenInRoot` except that the root is provided using an
|
||||||
|
`*os.File`. This allows you to ensure that multiple `OpenatInRoot` (or
|
||||||
|
`MkdirAllHandle`) calls are operating on the same rootfs.
|
||||||
|
|
||||||
|
> **NOTE**: Unlike `SecureJoin`, `OpenInRoot` will error out as soon as it hits
|
||||||
|
> a dangling symlink or non-existent path. This is in contrast to `SecureJoin`
|
||||||
|
> which treated non-existent components as though they were real directories,
|
||||||
|
> and would allow for partial resolution of dangling symlinks. These behaviours
|
||||||
|
> are at odds with how Linux treats non-existent paths and dangling symlinks,
|
||||||
|
> and so these are no longer allowed.
|
||||||
|
|
||||||
|
#### `MkdirAll` ####
|
||||||
|
|
||||||
|
```go
|
||||||
|
func MkdirAll(root, unsafePath string, mode int) error
|
||||||
|
func MkdirAllHandle(root *os.File, unsafePath string, mode int) (*os.File, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
`MkdirAll` is a much safer version of
|
||||||
|
|
||||||
|
```go
|
||||||
|
path, err := securejoin.SecureJoin(root, unsafePath)
|
||||||
|
err = os.MkdirAll(path, mode)
|
||||||
|
```
|
||||||
|
|
||||||
|
that protects against the same kinds of races that `OpenInRoot` protects
|
||||||
|
against.
|
||||||
|
|
||||||
|
`MkdirAllHandle` is like `MkdirAll` except that the root is provided using an
|
||||||
|
`*os.File` (the reason for this is the same as with `OpenatInRoot`) and an
|
||||||
|
`*os.File` of the final created directory is returned (this directory is
|
||||||
|
guaranteed to be effectively identical to the directory created by
|
||||||
|
`MkdirAllHandle`, which is not possible to ensure by just using `OpenatInRoot`
|
||||||
|
after `MkdirAll`).
|
||||||
|
|
||||||
|
> **NOTE**: Unlike `SecureJoin`, `MkdirAll` will error out as soon as it hits
|
||||||
|
> a dangling symlink or non-existent path. This is in contrast to `SecureJoin`
|
||||||
|
> which treated non-existent components as though they were real directories,
|
||||||
|
> and would allow for partial resolution of dangling symlinks. These behaviours
|
||||||
|
> are at odds with how Linux treats non-existent paths and dangling symlinks,
|
||||||
|
> and so these are no longer allowed. This means that `MkdirAll` will not
|
||||||
|
> create non-existent directories referenced by a dangling symlink.
|
||||||
|
|
||||||
### License ###
|
### License ###
|
||||||
|
|
||||||
The license of this project is the same as Go, which is a BSD 3-clause license
|
The license of this project is the same as Go, which is a BSD 3-clause license
|
||||||
|
|
|
||||||
2
vendor/github.com/cyphar/filepath-securejoin/VERSION
generated
vendored
2
vendor/github.com/cyphar/filepath-securejoin/VERSION
generated
vendored
|
|
@ -1 +1 @@
|
||||||
0.2.5
|
0.3.1
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue