mirror of
https://github.com/containers/skopeo.git
synced 2025-07-06 19:29:18 +00:00
Merge pull request #1680 from mtrmac/test-registry-2.8.1-with-cosign-signatures
Add OCI artifact support, test syncing Cosign signatures again
This commit is contained in:
commit
b95e081162
12
go.mod
12
go.mod
@ -4,7 +4,7 @@ go 1.17
|
||||
|
||||
require (
|
||||
github.com/containers/common v0.48.0
|
||||
github.com/containers/image/v5 v5.21.2-0.20220519193817-1e26896b8059
|
||||
github.com/containers/image/v5 v5.21.2-0.20220624171159-a332352e8a29
|
||||
github.com/containers/ocicrypt v1.1.5
|
||||
github.com/containers/storage v1.41.0
|
||||
github.com/docker/docker v20.10.17+incompatible
|
||||
@ -48,10 +48,10 @@ require (
|
||||
github.com/gorilla/mux v1.7.4 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/imdario/mergo v0.3.13 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.15.4 // indirect
|
||||
github.com/klauspost/compress v1.15.6 // indirect
|
||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||
github.com/kr/pretty v0.2.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
@ -77,11 +77,11 @@ require (
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/russross/blackfriday v2.0.0+incompatible // indirect
|
||||
github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980 // indirect
|
||||
github.com/sylabs/sif/v2 v2.7.0 // indirect
|
||||
github.com/sylabs/sif/v2 v2.7.1 // indirect
|
||||
github.com/tchap/go-patricia v2.3.0+incompatible // indirect
|
||||
github.com/ulikunitz/xz v0.5.10 // indirect
|
||||
github.com/vbatts/tar-split v0.11.2 // indirect
|
||||
github.com/vbauerster/mpb/v7 v7.4.1 // indirect
|
||||
github.com/vbauerster/mpb/v7 v7.4.2 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
@ -91,7 +91,7 @@ require (
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8 // indirect
|
||||
|
22
go.sum
22
go.sum
@ -93,6 +93,7 @@ github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb0
|
||||
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20220407094043-a94812496cf5/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20220517143526-88bb52951d5b/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
|
||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
@ -273,8 +274,8 @@ github.com/containernetworking/plugins v1.1.1/go.mod h1:Sr5TH/eBsGLXK/h71HeLfX19
|
||||
github.com/containers/common v0.48.0 h1:997nnXBZ+eNpfSM7L4SxhhZubQrfEyw3jRyNMTSsNlw=
|
||||
github.com/containers/common v0.48.0/go.mod h1:zPLZCfLXfnd1jI0QRsD4By54fP4k1+ifQs+tulIe3o0=
|
||||
github.com/containers/image/v5 v5.21.1/go.mod h1:zl35egpcDQa79IEXIuoUe1bW+D1pdxRxYjNlyb3YiXw=
|
||||
github.com/containers/image/v5 v5.21.2-0.20220519193817-1e26896b8059 h1:/FzsjrQ2nJtMom9IXEGieORlwUk/NyDuuz5SWcNo324=
|
||||
github.com/containers/image/v5 v5.21.2-0.20220519193817-1e26896b8059/go.mod h1:KntCBNQn3qOuZmQuJ38ORyTozmWXiuo05Vef2S0Sm5M=
|
||||
github.com/containers/image/v5 v5.21.2-0.20220624171159-a332352e8a29 h1:fr0KoyCzB7RzDU2ZPoEz0cYZpOrgAyg/J4fj40toAfE=
|
||||
github.com/containers/image/v5 v5.21.2-0.20220624171159-a332352e8a29/go.mod h1:m8S/6BIrULuOFt38EPXazKMn0rI+HBES0hIcSb5gL3M=
|
||||
github.com/containers/libtrust v0.0.0-20200511145503-9c3a6c22cd9a h1:spAGlqziZjCJL25C6F1zsQY05tfCKE9F5YwtEWWe6hU=
|
||||
github.com/containers/libtrust v0.0.0-20200511145503-9c3a6c22cd9a/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
|
||||
github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc=
|
||||
@ -337,7 +338,6 @@ github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6
|
||||
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v20.10.14+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v20.10.16+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v20.10.17+incompatible h1:JYCuMrWaVNophQTOrMMoSwudOVEfcegoZZrleKc1xwE=
|
||||
github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
|
||||
@ -573,8 +573,9 @@ github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ
|
||||
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
|
||||
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ=
|
||||
@ -608,8 +609,9 @@ github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs
|
||||
github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.15.2/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||
github.com/klauspost/compress v1.15.4 h1:1kn4/7MepF/CHmYub99/nNX8az0IJjfSOU/jbnTVfqQ=
|
||||
github.com/klauspost/compress v1.15.4/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||
github.com/klauspost/compress v1.15.6 h1:6D9PcO8QWu0JyaQ2zUMmu16T1T+zjjEpP91guRsvDfY=
|
||||
github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
|
||||
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
@ -902,11 +904,13 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/sylabs/sif/v2 v2.7.0 h1:VFzN8alnJ/3n1JA0K9DyUtfSzezWgWrzLDcYGhgBskk=
|
||||
github.com/sylabs/sif/v2 v2.7.0/go.mod h1:TiyBWsgWeh5yBeQFNuQnvROwswqK7YJT8JA1L53bsXQ=
|
||||
github.com/sylabs/sif/v2 v2.7.1 h1:XXt9AP39sQfsMCGOGQ/XP9H47yqZOvAonalkaCaNIYM=
|
||||
github.com/sylabs/sif/v2 v2.7.1/go.mod h1:bBse2nEFd3yHkmq6KmAOFEWQg5LdFYiQUdVcgamxlc8=
|
||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
|
||||
@ -929,8 +933,9 @@ github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX
|
||||
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME=
|
||||
github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI=
|
||||
github.com/vbauerster/mpb/v7 v7.4.1 h1:NhLMWQ3gNg2KJR8oeA9lO8Xvq+eNPmixDmB6JEQOUdA=
|
||||
github.com/vbauerster/mpb/v7 v7.4.1/go.mod h1:Ygg2mV9Vj9sQBWqsK2m2pidcf9H3s6bNKtqd3/M4gBo=
|
||||
github.com/vbauerster/mpb/v7 v7.4.2 h1:n917F4d8EWdUKc9c81wFkksyG6P6Mg7IETfKCE1Xqng=
|
||||
github.com/vbauerster/mpb/v7 v7.4.2/go.mod h1:UmOiIUI8aPqWXIps0ciik3RKMdzx7+ooQpq+fBcXwBA=
|
||||
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
|
||||
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
||||
github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
|
||||
@ -1253,8 +1258,9 @@ golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc=
|
||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
|
@ -22,7 +22,7 @@ const (
|
||||
// A repository with a path with multiple components in it which
|
||||
// contains multiple tags, preferably with some tags pointing to
|
||||
// manifest lists, and with some tags that don't.
|
||||
pullableRepo = "quay.io/libpod/testimage"
|
||||
pullableRepo = "k8s.gcr.io/coredns/coredns"
|
||||
// A tagged image in the repository that we can inspect and copy.
|
||||
pullableTaggedImage = "k8s.gcr.io/coredns/coredns:v1.6.6"
|
||||
// A tagged manifest list in the repository that we can inspect and copy.
|
||||
|
170
vendor/github.com/containers/image/v5/copy/blob.go
generated
vendored
Normal file
170
vendor/github.com/containers/image/v5/copy/blob.go
generated
vendored
Normal file
@ -0,0 +1,170 @@
|
||||
package copy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/containers/image/v5/internal/private"
|
||||
compressiontypes "github.com/containers/image/v5/pkg/compression/types"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// copyBlobFromStream copies a blob with srcInfo (with known Digest and Annotations and possibly known Size) from srcReader to dest,
|
||||
// perhaps sending a copy to an io.Writer if getOriginalLayerCopyWriter != nil,
|
||||
// perhaps (de/re/)compressing it if canModifyBlob,
|
||||
// and returns a complete blobInfo of the copied blob.
|
||||
func (ic *imageCopier) copyBlobFromStream(ctx context.Context, srcReader io.Reader, srcInfo types.BlobInfo,
|
||||
getOriginalLayerCopyWriter func(decompressor compressiontypes.DecompressorFunc) io.Writer,
|
||||
isConfig bool, toEncrypt bool, bar *progressBar, layerIndex int, emptyLayer bool) (types.BlobInfo, error) {
|
||||
// The copying happens through a pipeline of connected io.Readers;
|
||||
// that pipeline is built by updating stream.
|
||||
// === Input: srcReader
|
||||
stream := sourceStream{
|
||||
reader: srcReader,
|
||||
info: srcInfo,
|
||||
}
|
||||
|
||||
// === Process input through digestingReader to validate against the expected digest.
|
||||
// Be paranoid; in case PutBlob somehow managed to ignore an error from digestingReader,
|
||||
// use a separate validation failure indicator.
|
||||
// Note that for this check we don't use the stronger "validationSucceeded" indicator, because
|
||||
// dest.PutBlob may detect that the layer already exists, in which case we don't
|
||||
// read stream to the end, and validation does not happen.
|
||||
digestingReader, err := newDigestingReader(stream.reader, srcInfo.Digest)
|
||||
if err != nil {
|
||||
return types.BlobInfo{}, errors.Wrapf(err, "preparing to verify blob %s", srcInfo.Digest)
|
||||
}
|
||||
stream.reader = digestingReader
|
||||
|
||||
// === Update progress bars
|
||||
stream.reader = bar.ProxyReader(stream.reader)
|
||||
|
||||
// === Decrypt the stream, if required.
|
||||
decryptionStep, err := ic.c.blobPipelineDecryptionStep(&stream, srcInfo)
|
||||
if err != nil {
|
||||
return types.BlobInfo{}, err
|
||||
}
|
||||
|
||||
// === Detect compression of the input stream.
|
||||
// This requires us to “peek ahead” into the stream to read the initial part, which requires us to chain through another io.Reader returned by DetectCompression.
|
||||
detectedCompression, err := blobPipelineDetectCompressionStep(&stream, srcInfo)
|
||||
if err != nil {
|
||||
return types.BlobInfo{}, err
|
||||
}
|
||||
|
||||
// === Send a copy of the original, uncompressed, stream, to a separate path if necessary.
|
||||
var originalLayerReader io.Reader // DO NOT USE this other than to drain the input if no other consumer in the pipeline has done so.
|
||||
if getOriginalLayerCopyWriter != nil {
|
||||
stream.reader = io.TeeReader(stream.reader, getOriginalLayerCopyWriter(detectedCompression.decompressor))
|
||||
originalLayerReader = stream.reader
|
||||
}
|
||||
|
||||
// WARNING: If you are adding new reasons to change the blob, update also the OptimizeDestinationImageAlreadyExists
|
||||
// short-circuit conditions
|
||||
canModifyBlob := !isConfig && ic.cannotModifyManifestReason == ""
|
||||
// === Deal with layer compression/decompression if necessary
|
||||
compressionStep, err := ic.blobPipelineCompressionStep(&stream, canModifyBlob, srcInfo, detectedCompression)
|
||||
if err != nil {
|
||||
return types.BlobInfo{}, err
|
||||
}
|
||||
defer compressionStep.close()
|
||||
|
||||
// === Encrypt the stream for valid mediatypes if ociEncryptConfig provided
|
||||
if decryptionStep.decrypting && toEncrypt {
|
||||
// If nothing else, we can only set uploadedInfo.CryptoOperation to a single value.
|
||||
// Before relaxing this, see the original pull request’s review if there are other reasons to reject this.
|
||||
return types.BlobInfo{}, errors.New("Unable to support both decryption and encryption in the same copy")
|
||||
}
|
||||
encryptionStep, err := ic.c.blobPipelineEncryptionStep(&stream, toEncrypt, srcInfo, decryptionStep)
|
||||
if err != nil {
|
||||
return types.BlobInfo{}, err
|
||||
}
|
||||
|
||||
// === Report progress using the ic.c.progress channel, if required.
|
||||
if ic.c.progress != nil && ic.c.progressInterval > 0 {
|
||||
progressReader := newProgressReader(
|
||||
stream.reader,
|
||||
ic.c.progress,
|
||||
ic.c.progressInterval,
|
||||
srcInfo,
|
||||
)
|
||||
defer progressReader.reportDone()
|
||||
stream.reader = progressReader
|
||||
}
|
||||
|
||||
// === Finally, send the layer stream to dest.
|
||||
options := private.PutBlobOptions{
|
||||
Cache: ic.c.blobInfoCache,
|
||||
IsConfig: isConfig,
|
||||
EmptyLayer: emptyLayer,
|
||||
}
|
||||
if !isConfig {
|
||||
options.LayerIndex = &layerIndex
|
||||
}
|
||||
uploadedInfo, err := ic.c.dest.PutBlobWithOptions(ctx, &errorAnnotationReader{stream.reader}, stream.info, options)
|
||||
if err != nil {
|
||||
return types.BlobInfo{}, errors.Wrap(err, "writing blob")
|
||||
}
|
||||
|
||||
uploadedInfo.Annotations = stream.info.Annotations
|
||||
|
||||
compressionStep.updateCompressionEdits(&uploadedInfo.CompressionOperation, &uploadedInfo.CompressionAlgorithm, &uploadedInfo.Annotations)
|
||||
decryptionStep.updateCryptoOperation(&uploadedInfo.CryptoOperation)
|
||||
if err := encryptionStep.updateCryptoOperationAndAnnotations(&uploadedInfo.CryptoOperation, &uploadedInfo.Annotations); err != nil {
|
||||
return types.BlobInfo{}, err
|
||||
}
|
||||
|
||||
// This is fairly horrible: the writer from getOriginalLayerCopyWriter wants to consume
|
||||
// all of the input (to compute DiffIDs), even if dest.PutBlob does not need it.
|
||||
// So, read everything from originalLayerReader, which will cause the rest to be
|
||||
// sent there if we are not already at EOF.
|
||||
if getOriginalLayerCopyWriter != nil {
|
||||
logrus.Debugf("Consuming rest of the original blob to satisfy getOriginalLayerCopyWriter")
|
||||
_, err := io.Copy(io.Discard, originalLayerReader)
|
||||
if err != nil {
|
||||
return types.BlobInfo{}, errors.Wrapf(err, "reading input blob %s", srcInfo.Digest)
|
||||
}
|
||||
}
|
||||
|
||||
if digestingReader.validationFailed { // Coverage: This should never happen.
|
||||
return types.BlobInfo{}, errors.Errorf("Internal error writing blob %s, digest verification failed but was ignored", srcInfo.Digest)
|
||||
}
|
||||
if stream.info.Digest != "" && uploadedInfo.Digest != stream.info.Digest {
|
||||
return types.BlobInfo{}, errors.Errorf("Internal error writing blob %s, blob with digest %s saved with digest %s", srcInfo.Digest, stream.info.Digest, uploadedInfo.Digest)
|
||||
}
|
||||
if digestingReader.validationSucceeded {
|
||||
if err := compressionStep.recordValidatedDigestData(ic.c, uploadedInfo, srcInfo, encryptionStep, decryptionStep); err != nil {
|
||||
return types.BlobInfo{}, err
|
||||
}
|
||||
}
|
||||
|
||||
return uploadedInfo, nil
|
||||
}
|
||||
|
||||
// sourceStream encapsulates an input consumed by copyBlobFromStream, in progress of being built.
|
||||
// This allows handles of individual aspects to build the copy pipeline without _too much_
|
||||
// specific cooperation by the caller.
|
||||
//
|
||||
// We are currently very far from a generalized plug-and-play API for building/consuming the pipeline
|
||||
// without specific knowledge of various aspects in copyBlobFromStream; that may come one day.
|
||||
type sourceStream struct {
|
||||
reader io.Reader
|
||||
info types.BlobInfo // corresponding to the data available in reader.
|
||||
}
|
||||
|
||||
// errorAnnotationReader wraps the io.Reader passed to PutBlob for annotating the error happened during read.
|
||||
// These errors are reported as PutBlob errors, so we would otherwise misleadingly attribute them to the copy destination.
|
||||
type errorAnnotationReader struct {
|
||||
reader io.Reader
|
||||
}
|
||||
|
||||
// Read annotates the error happened during read
|
||||
func (r errorAnnotationReader) Read(b []byte) (n int, err error) {
|
||||
n, err = r.reader.Read(b)
|
||||
if err != io.EOF {
|
||||
return n, errors.Wrapf(err, "happened during read")
|
||||
}
|
||||
return n, err
|
||||
}
|
320
vendor/github.com/containers/image/v5/copy/compression.go
generated
vendored
Normal file
320
vendor/github.com/containers/image/v5/copy/compression.go
generated
vendored
Normal file
@ -0,0 +1,320 @@
|
||||
package copy
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
internalblobinfocache "github.com/containers/image/v5/internal/blobinfocache"
|
||||
"github.com/containers/image/v5/pkg/compression"
|
||||
compressiontypes "github.com/containers/image/v5/pkg/compression/types"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// bpDetectCompressionStepData contains data that the copy pipeline needs about the “detect compression” step.
|
||||
type bpDetectCompressionStepData struct {
|
||||
isCompressed bool
|
||||
format compressiontypes.Algorithm // Valid if isCompressed
|
||||
decompressor compressiontypes.DecompressorFunc // Valid if isCompressed
|
||||
srcCompressorName string // Compressor name to possibly record in the blob info cache for the source blob.
|
||||
}
|
||||
|
||||
// blobPipelineDetectCompressionStep updates *stream to detect its current compression format.
|
||||
// srcInfo is only used for error messages.
|
||||
// Returns data for other steps.
|
||||
func blobPipelineDetectCompressionStep(stream *sourceStream, srcInfo types.BlobInfo) (bpDetectCompressionStepData, error) {
|
||||
// This requires us to “peek ahead” into the stream to read the initial part, which requires us to chain through another io.Reader returned by DetectCompression.
|
||||
format, decompressor, reader, err := compression.DetectCompressionFormat(stream.reader) // We could skip this in some cases, but let's keep the code path uniform
|
||||
if err != nil {
|
||||
return bpDetectCompressionStepData{}, errors.Wrapf(err, "reading blob %s", srcInfo.Digest)
|
||||
}
|
||||
stream.reader = reader
|
||||
|
||||
res := bpDetectCompressionStepData{
|
||||
isCompressed: decompressor != nil,
|
||||
format: format,
|
||||
decompressor: decompressor,
|
||||
}
|
||||
if res.isCompressed {
|
||||
res.srcCompressorName = format.Name()
|
||||
} else {
|
||||
res.srcCompressorName = internalblobinfocache.Uncompressed
|
||||
}
|
||||
|
||||
if expectedFormat, known := expectedCompressionFormats[stream.info.MediaType]; known && res.isCompressed && format.Name() != expectedFormat.Name() {
|
||||
logrus.Debugf("blob %s with type %s should be compressed with %s, but compressor appears to be %s", srcInfo.Digest.String(), srcInfo.MediaType, expectedFormat.Name(), format.Name())
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// bpCompressionStepData contains data that the copy pipeline needs about the compression step.
|
||||
type bpCompressionStepData struct {
|
||||
operation types.LayerCompression // Operation to use for updating the blob metadata.
|
||||
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.
|
||||
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.
|
||||
closers []io.Closer // Objects to close after the upload is done, if any.
|
||||
}
|
||||
|
||||
// blobPipelineCompressionStep updates *stream to compress and/or decompress it.
|
||||
// srcInfo is primarily used for error messages.
|
||||
// Returns data for other steps; the caller should eventually call updateCompressionEdits and perhaps recordValidatedBlobData,
|
||||
// and must eventually call close.
|
||||
func (ic *imageCopier) blobPipelineCompressionStep(stream *sourceStream, canModifyBlob bool, srcInfo types.BlobInfo,
|
||||
detected bpDetectCompressionStepData) (*bpCompressionStepData, error) {
|
||||
// WARNING: If you are adding new reasons to change the blob, update also the OptimizeDestinationImageAlreadyExists
|
||||
// short-circuit conditions
|
||||
layerCompressionChangeSupported := ic.src.CanChangeLayerCompression(stream.info.MediaType)
|
||||
if !layerCompressionChangeSupported {
|
||||
logrus.Debugf("Compression change for blob %s (%q) not supported", srcInfo.Digest, stream.info.MediaType)
|
||||
}
|
||||
if canModifyBlob && layerCompressionChangeSupported {
|
||||
for _, fn := range []func(*sourceStream, bpDetectCompressionStepData) (*bpCompressionStepData, error){
|
||||
ic.bpcPreserveEncrypted,
|
||||
ic.bpcCompressUncompressed,
|
||||
ic.bpcRecompressCompressed,
|
||||
ic.bpcDecompressCompressed,
|
||||
} {
|
||||
res, err := fn(stream, detected)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if res != nil {
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return ic.bpcPreserveOriginal(stream, detected, layerCompressionChangeSupported), nil
|
||||
}
|
||||
|
||||
// bpcPreserveEncrypted checks if the input is encrypted, and returns a *bpCompressionStepData if so.
|
||||
func (ic *imageCopier) bpcPreserveEncrypted(stream *sourceStream, _ bpDetectCompressionStepData) (*bpCompressionStepData, error) {
|
||||
if isOciEncrypted(stream.info.MediaType) {
|
||||
logrus.Debugf("Using original blob without modification for encrypted blob")
|
||||
// PreserveOriginal due to any compression not being able to be done on an encrypted blob unless decrypted
|
||||
return &bpCompressionStepData{
|
||||
operation: types.PreserveOriginal,
|
||||
uploadedAlgorithm: nil,
|
||||
srcCompressorName: internalblobinfocache.UnknownCompression,
|
||||
uploadedCompressorName: internalblobinfocache.UnknownCompression,
|
||||
}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// bpcCompressUncompressed checks if we should be compressing an uncompressed input, and returns a *bpCompressionStepData if so.
|
||||
func (ic *imageCopier) bpcCompressUncompressed(stream *sourceStream, detected bpDetectCompressionStepData) (*bpCompressionStepData, error) {
|
||||
if ic.c.dest.DesiredLayerCompression() == types.Compress && !detected.isCompressed {
|
||||
logrus.Debugf("Compressing blob on the fly")
|
||||
var uploadedAlgorithm *compressiontypes.Algorithm
|
||||
if ic.c.compressionFormat != nil {
|
||||
uploadedAlgorithm = ic.c.compressionFormat
|
||||
} else {
|
||||
uploadedAlgorithm = defaultCompressionFormat
|
||||
}
|
||||
|
||||
reader, annotations := ic.c.compressedStream(stream.reader, *uploadedAlgorithm)
|
||||
// Note: reader must be closed on all return paths.
|
||||
stream.reader = reader
|
||||
stream.info = types.BlobInfo{ // FIXME? Should we preserve more data in src.info?
|
||||
Digest: "",
|
||||
Size: -1,
|
||||
}
|
||||
return &bpCompressionStepData{
|
||||
operation: types.Compress,
|
||||
uploadedAlgorithm: uploadedAlgorithm,
|
||||
uploadedAnnotations: annotations,
|
||||
srcCompressorName: detected.srcCompressorName,
|
||||
uploadedCompressorName: uploadedAlgorithm.Name(),
|
||||
closers: []io.Closer{reader},
|
||||
}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// bpcRecompressCompressed checks if we should be recompressing a compressed input to another format, and returns a *bpCompressionStepData if so.
|
||||
func (ic *imageCopier) bpcRecompressCompressed(stream *sourceStream, detected bpDetectCompressionStepData) (*bpCompressionStepData, error) {
|
||||
if ic.c.dest.DesiredLayerCompression() == types.Compress && detected.isCompressed &&
|
||||
ic.c.compressionFormat != nil && ic.c.compressionFormat.Name() != detected.format.Name() {
|
||||
// When the blob is compressed, but the desired format is different, it first needs to be decompressed and finally
|
||||
// re-compressed using the desired format.
|
||||
logrus.Debugf("Blob will be converted")
|
||||
|
||||
decompressed, err := detected.decompressor(stream.reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
succeeded := false
|
||||
defer func() {
|
||||
if !succeeded {
|
||||
decompressed.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
recompressed, annotations := ic.c.compressedStream(decompressed, *ic.c.compressionFormat)
|
||||
// Note: recompressed must be closed on all return paths.
|
||||
stream.reader = recompressed
|
||||
stream.info = types.BlobInfo{ // FIXME? Should we preserve more data in src.info?
|
||||
Digest: "",
|
||||
Size: -1,
|
||||
}
|
||||
succeeded = true
|
||||
return &bpCompressionStepData{
|
||||
operation: types.PreserveOriginal,
|
||||
uploadedAlgorithm: ic.c.compressionFormat,
|
||||
uploadedAnnotations: annotations,
|
||||
srcCompressorName: detected.srcCompressorName,
|
||||
uploadedCompressorName: ic.c.compressionFormat.Name(),
|
||||
closers: []io.Closer{decompressed, recompressed},
|
||||
}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// bpcDecompressCompressed checks if we should be decompressing a compressed input, and returns a *bpCompressionStepData if so.
|
||||
func (ic *imageCopier) bpcDecompressCompressed(stream *sourceStream, detected bpDetectCompressionStepData) (*bpCompressionStepData, error) {
|
||||
if ic.c.dest.DesiredLayerCompression() == types.Decompress && detected.isCompressed {
|
||||
logrus.Debugf("Blob will be decompressed")
|
||||
s, err := detected.decompressor(stream.reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Note: s must be closed on all return paths.
|
||||
stream.reader = s
|
||||
stream.info = types.BlobInfo{ // FIXME? Should we preserve more data in src.info?
|
||||
Digest: "",
|
||||
Size: -1,
|
||||
}
|
||||
return &bpCompressionStepData{
|
||||
operation: types.Decompress,
|
||||
uploadedAlgorithm: nil,
|
||||
srcCompressorName: detected.srcCompressorName,
|
||||
uploadedCompressorName: internalblobinfocache.Uncompressed,
|
||||
closers: []io.Closer{s},
|
||||
}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// bpcPreserveOriginal returns a *bpCompressionStepData for not changing the original blob.
|
||||
func (ic *imageCopier) bpcPreserveOriginal(stream *sourceStream, detected bpDetectCompressionStepData,
|
||||
layerCompressionChangeSupported bool) *bpCompressionStepData {
|
||||
logrus.Debugf("Using original blob without modification")
|
||||
// Remember if the original blob was compressed, and if so how, so that if
|
||||
// LayerInfosForCopy() returned something that differs from what was in the
|
||||
// source's manifest, and UpdatedImage() needs to call UpdateLayerInfos(),
|
||||
// it will be able to correctly derive the MediaType for the copied blob.
|
||||
//
|
||||
// But don’t touch blobs in objects where we can’t change compression,
|
||||
// so that src.UpdatedImage() doesn’t fail; assume that for such blobs
|
||||
// LayerInfosForCopy() should not be making any changes in the first place.
|
||||
var algorithm *compressiontypes.Algorithm
|
||||
if layerCompressionChangeSupported && detected.isCompressed {
|
||||
algorithm = &detected.format
|
||||
} else {
|
||||
algorithm = nil
|
||||
}
|
||||
return &bpCompressionStepData{
|
||||
operation: types.PreserveOriginal,
|
||||
uploadedAlgorithm: algorithm,
|
||||
srcCompressorName: detected.srcCompressorName,
|
||||
uploadedCompressorName: detected.srcCompressorName,
|
||||
}
|
||||
}
|
||||
|
||||
// updateCompressionEdits sets *operation, *algorithm and updates *annotations, if necessary.
|
||||
func (d *bpCompressionStepData) updateCompressionEdits(operation *types.LayerCompression, algorithm **compressiontypes.Algorithm, annotations *map[string]string) {
|
||||
*operation = d.operation
|
||||
// If we can modify the layer's blob, set the desired algorithm for it to be set in the manifest.
|
||||
*algorithm = d.uploadedAlgorithm
|
||||
if *annotations == nil {
|
||||
*annotations = map[string]string{}
|
||||
}
|
||||
for k, v := range d.uploadedAnnotations {
|
||||
(*annotations)[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// recordValidatedBlobData updates b.blobInfoCache with data about the created uploadedInfo adnd the original srcInfo.
|
||||
// This must ONLY be called if all data has been validated by OUR code, and is not comming from third parties.
|
||||
func (d *bpCompressionStepData) recordValidatedDigestData(c *copier, uploadedInfo types.BlobInfo, srcInfo types.BlobInfo,
|
||||
encryptionStep *bpEncryptionStepData, decryptionStep *bpDecryptionStepData) error {
|
||||
// Don’t record any associations that involve encrypted data. This is a bit crude,
|
||||
// some blob substitutions (replacing pulls of encrypted data with local reuse of known decryption outcomes)
|
||||
// might be safe, but it’s not trivially obvious, so let’s be conservative for now.
|
||||
// This crude approach also means we don’t need to record whether a blob is encrypted
|
||||
// in the blob info cache (which would probably be necessary for any more complex logic),
|
||||
// and the simplicity is attractive.
|
||||
if !encryptionStep.encrypting && !decryptionStep.decrypting {
|
||||
// If d.operation != types.PreserveOriginal, we now have two reliable digest values:
|
||||
// srcinfo.Digest describes the pre-d.operation input, verified by digestingReader
|
||||
// uploadedInfo.Digest describes the post-d.operation output, computed by PutBlob
|
||||
// (because stream.info.Digest == "", this must have been computed afresh).
|
||||
switch d.operation {
|
||||
case types.PreserveOriginal:
|
||||
break // Do nothing, we have only one digest and we might not have even verified it.
|
||||
case types.Compress:
|
||||
c.blobInfoCache.RecordDigestUncompressedPair(uploadedInfo.Digest, srcInfo.Digest)
|
||||
case types.Decompress:
|
||||
c.blobInfoCache.RecordDigestUncompressedPair(srcInfo.Digest, uploadedInfo.Digest)
|
||||
default:
|
||||
return errors.Errorf("Internal error: Unexpected d.operation value %#v", d.operation)
|
||||
}
|
||||
}
|
||||
if d.uploadedCompressorName != "" && d.uploadedCompressorName != internalblobinfocache.UnknownCompression {
|
||||
c.blobInfoCache.RecordDigestCompressorName(uploadedInfo.Digest, d.uploadedCompressorName)
|
||||
}
|
||||
if srcInfo.Digest != "" && d.srcCompressorName != "" && d.srcCompressorName != internalblobinfocache.UnknownCompression {
|
||||
c.blobInfoCache.RecordDigestCompressorName(srcInfo.Digest, d.srcCompressorName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// close closes objects that carry state throughout the compression/decompression operation.
|
||||
func (d *bpCompressionStepData) close() {
|
||||
for _, c := range d.closers {
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// doCompression reads all input from src and writes its compressed equivalent to dest.
|
||||
func doCompression(dest io.Writer, src io.Reader, metadata map[string]string, compressionFormat compressiontypes.Algorithm, compressionLevel *int) error {
|
||||
compressor, err := compression.CompressStreamWithMetadata(dest, metadata, compressionFormat, compressionLevel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf := make([]byte, compressionBufferSize)
|
||||
|
||||
_, err = io.CopyBuffer(compressor, src, buf) // Sets err to nil, i.e. causes dest.Close()
|
||||
if err != nil {
|
||||
compressor.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
return compressor.Close()
|
||||
}
|
||||
|
||||
// compressGoroutine reads all input from src and writes its compressed equivalent to dest.
|
||||
func (c *copier) compressGoroutine(dest *io.PipeWriter, src io.Reader, metadata map[string]string, compressionFormat compressiontypes.Algorithm) {
|
||||
err := errors.New("Internal error: unexpected panic in compressGoroutine")
|
||||
defer func() { // Note that this is not the same as {defer dest.CloseWithError(err)}; we need err to be evaluated lazily.
|
||||
_ = dest.CloseWithError(err) // CloseWithError(nil) is equivalent to Close(), always returns nil
|
||||
}()
|
||||
|
||||
err = doCompression(dest, src, metadata, compressionFormat, c.compressionLevel)
|
||||
}
|
||||
|
||||
// compressedStream returns a stream the input reader compressed using format, and a metadata map.
|
||||
// The caller must close the returned reader.
|
||||
// AFTER the stream is consumed, metadata will be updated with annotations to use on the data.
|
||||
func (c *copier) compressedStream(reader io.Reader, algorithm compressiontypes.Algorithm) (io.ReadCloser, map[string]string) {
|
||||
pipeReader, pipeWriter := io.Pipe()
|
||||
annotations := map[string]string{}
|
||||
// If this fails while writing data, it will do pipeWriter.CloseWithError(); if it fails otherwise,
|
||||
// e.g. because we have exited and due to pipeReader.Close() above further writing to the pipe has failed,
|
||||
// we don’t care.
|
||||
go c.compressGoroutine(pipeWriter, reader, annotations, algorithm) // Closes pipeWriter
|
||||
return pipeReader, annotations
|
||||
}
|
440
vendor/github.com/containers/image/v5/copy/copy.go
generated
vendored
440
vendor/github.com/containers/image/v5/copy/copy.go
generated
vendored
@ -12,8 +12,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/containers/image/v5/image"
|
||||
internalblobinfocache "github.com/containers/image/v5/internal/blobinfocache"
|
||||
"github.com/containers/image/v5/internal/image"
|
||||
"github.com/containers/image/v5/internal/imagedestination"
|
||||
"github.com/containers/image/v5/internal/imagesource"
|
||||
"github.com/containers/image/v5/internal/pkg/platform"
|
||||
@ -25,7 +25,6 @@ import (
|
||||
"github.com/containers/image/v5/signature"
|
||||
"github.com/containers/image/v5/transports"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/containers/ocicrypt"
|
||||
encconfig "github.com/containers/ocicrypt/config"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
@ -82,7 +81,7 @@ type copier struct {
|
||||
type imageCopier struct {
|
||||
c *copier
|
||||
manifestUpdates *types.ManifestUpdateOptions
|
||||
src types.Image
|
||||
src *image.SourcedImage
|
||||
diffIDsAreNeeded bool
|
||||
cannotModifyManifestReason string // The reason the manifest cannot be modified, or an empty string if it can
|
||||
canSubstituteBlobs bool
|
||||
@ -349,13 +348,8 @@ func supportsMultipleImages(dest types.ImageDestination) bool {
|
||||
|
||||
// compareImageDestinationManifestEqual compares the `src` and `dest` image manifests (reading the manifest from the
|
||||
// (possibly remote) destination). Returning true and the destination's manifest, type and digest if they compare equal.
|
||||
func compareImageDestinationManifestEqual(ctx context.Context, options *Options, src types.Image, targetInstance *digest.Digest, dest types.ImageDestination) (bool, []byte, string, digest.Digest, error) {
|
||||
srcManifest, _, err := src.Manifest(ctx)
|
||||
if err != nil {
|
||||
return false, nil, "", "", errors.Wrapf(err, "reading manifest from image")
|
||||
}
|
||||
|
||||
srcManifestDigest, err := manifest.Digest(srcManifest)
|
||||
func compareImageDestinationManifestEqual(ctx context.Context, options *Options, src *image.SourcedImage, targetInstance *digest.Digest, dest types.ImageDestination) (bool, []byte, string, digest.Digest, error) {
|
||||
srcManifestDigest, err := manifest.Digest(src.ManifestBlob)
|
||||
if err != nil {
|
||||
return false, nil, "", "", errors.Wrapf(err, "calculating manifest digest")
|
||||
}
|
||||
@ -620,11 +614,7 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
|
||||
if named := c.dest.Reference().DockerReference(); named != nil {
|
||||
if digested, ok := named.(reference.Digested); ok {
|
||||
destIsDigestedReference = true
|
||||
sourceManifest, _, err := src.Manifest(ctx)
|
||||
if err != nil {
|
||||
return nil, "", "", errors.Wrapf(err, "reading manifest from source image")
|
||||
}
|
||||
matches, err := manifest.MatchesDigest(sourceManifest, digested.Digest())
|
||||
matches, err := manifest.MatchesDigest(src.ManifestBlob, digested.Digest())
|
||||
if err != nil {
|
||||
return nil, "", "", errors.Wrapf(err, "computing digest of source image's manifest")
|
||||
}
|
||||
@ -688,12 +678,14 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
|
||||
cannotModifyManifestReason: cannotModifyManifestReason,
|
||||
ociEncryptLayers: options.OciEncryptLayers,
|
||||
}
|
||||
// Ensure _this_ copy sees exactly the intended data when either processing a signed image or signing it.
|
||||
// This may be too conservative, but for now, better safe than sorry, _especially_ on the SignBy path:
|
||||
// The signature makes the content non-repudiable, so it very much matters that the signature is made over exactly what the user intended.
|
||||
// We do intend the RecordDigestUncompressedPair calls to only work with reliable data, but at least there’s a risk
|
||||
// that the compressed version coming from a third party may be designed to attack some other decompressor implementation,
|
||||
// and we would reuse and sign it.
|
||||
// Decide whether we can substitute blobs with semantic equivalents:
|
||||
// - Don’t do that if we can’t modify the manifest at all
|
||||
// - Ensure _this_ copy sees exactly the intended data when either processing a signed image or signing it.
|
||||
// This may be too conservative, but for now, better safe than sorry, _especially_ on the SignBy path:
|
||||
// The signature makes the content non-repudiable, so it very much matters that the signature is made over exactly what the user intended.
|
||||
// We do intend the RecordDigestUncompressedPair calls to only work with reliable data, but at least there’s a risk
|
||||
// that the compressed version coming from a third party may be designed to attack some other decompressor implementation,
|
||||
// and we would reuse and sign it.
|
||||
ic.canSubstituteBlobs = ic.cannotModifyManifestReason == "" && options.SignBy == ""
|
||||
|
||||
if err := ic.updateEmbeddedDockerReference(); err != nil {
|
||||
@ -702,12 +694,23 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
|
||||
|
||||
destRequiresOciEncryption := (isEncrypted(src) && ic.c.ociDecryptConfig != nil) || options.OciEncryptLayers != nil
|
||||
|
||||
// We compute preferredManifestMIMEType only to show it in error messages.
|
||||
// Without having to add this context in an error message, we would be happy enough to know only that no conversion is needed.
|
||||
preferredManifestMIMEType, otherManifestMIMETypeCandidates, err := ic.determineManifestConversion(ctx, c.dest.SupportedManifestMIMETypes(), options.ForceManifestMIMEType, destRequiresOciEncryption)
|
||||
manifestConversionPlan, err := determineManifestConversion(determineManifestConversionInputs{
|
||||
srcMIMEType: ic.src.ManifestMIMEType,
|
||||
destSupportedManifestMIMETypes: ic.c.dest.SupportedManifestMIMETypes(),
|
||||
forceManifestMIMEType: options.ForceManifestMIMEType,
|
||||
requiresOCIEncryption: destRequiresOciEncryption,
|
||||
cannotModifyManifestReason: ic.cannotModifyManifestReason,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, "", "", err
|
||||
}
|
||||
// We set up this part of ic.manifestUpdates quite early, not just around the
|
||||
// code that calls copyUpdatedConfigAndManifest, so that other parts of the copy code
|
||||
// (e.g. the UpdatedImageNeedsLayerDiffIDs check just below) can make decisions based
|
||||
// on the expected destination format.
|
||||
if manifestConversionPlan.preferredMIMETypeNeedsConversion {
|
||||
ic.manifestUpdates.ManifestMIMEType = manifestConversionPlan.preferredMIMEType
|
||||
}
|
||||
|
||||
// If src.UpdatedImageNeedsLayerDiffIDs(ic.manifestUpdates) will be true, it needs to be true by the time we get here.
|
||||
ic.diffIDsAreNeeded = src.UpdatedImageNeedsLayerDiffIDs(*ic.manifestUpdates)
|
||||
@ -742,22 +745,22 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
|
||||
// So, try the preferred manifest MIME type with possibly-updated blob digests, media types, and sizes if
|
||||
// we're altering how they're compressed. If the process succeeds, fine…
|
||||
manifestBytes, retManifestDigest, err := ic.copyUpdatedConfigAndManifest(ctx, targetInstance)
|
||||
retManifestType = preferredManifestMIMEType
|
||||
retManifestType = manifestConversionPlan.preferredMIMEType
|
||||
if err != nil {
|
||||
logrus.Debugf("Writing manifest using preferred type %s failed: %v", preferredManifestMIMEType, err)
|
||||
logrus.Debugf("Writing manifest using preferred type %s failed: %v", manifestConversionPlan.preferredMIMEType, err)
|
||||
// … if it fails, and the failure is either because the manifest is rejected by the registry, or
|
||||
// because we failed to create a manifest of the specified type because the specific manifest type
|
||||
// doesn't support the type of compression we're trying to use (e.g. docker v2s2 and zstd), we may
|
||||
// have other options available that could still succeed.
|
||||
_, isManifestRejected := errors.Cause(err).(types.ManifestTypeRejectedError)
|
||||
_, isCompressionIncompatible := errors.Cause(err).(manifest.ManifestLayerCompressionIncompatibilityError)
|
||||
if (!isManifestRejected && !isCompressionIncompatible) || len(otherManifestMIMETypeCandidates) == 0 {
|
||||
if (!isManifestRejected && !isCompressionIncompatible) || len(manifestConversionPlan.otherMIMETypeCandidates) == 0 {
|
||||
// We don’t have other options.
|
||||
// In principle the code below would handle this as well, but the resulting error message is fairly ugly.
|
||||
// Don’t bother the user with MIME types if we have no choice.
|
||||
return nil, "", "", err
|
||||
}
|
||||
// If the original MIME type is acceptable, determineManifestConversion always uses it as preferredManifestMIMEType.
|
||||
// If the original MIME type is acceptable, determineManifestConversion always uses it as manifestConversionPlan.preferredMIMEType.
|
||||
// So if we are here, we will definitely be trying to convert the manifest.
|
||||
// With ic.cannotModifyManifestReason != "", that would just be a string of repeated failures for the same reason,
|
||||
// so let’s bail out early and with a better error message.
|
||||
@ -766,8 +769,8 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
|
||||
}
|
||||
|
||||
// errs is a list of errors when trying various manifest types. Also serves as an "upload succeeded" flag when set to nil.
|
||||
errs := []string{fmt.Sprintf("%s(%v)", preferredManifestMIMEType, err)}
|
||||
for _, manifestMIMEType := range otherManifestMIMETypeCandidates {
|
||||
errs := []string{fmt.Sprintf("%s(%v)", manifestConversionPlan.preferredMIMEType, err)}
|
||||
for _, manifestMIMEType := range manifestConversionPlan.otherMIMETypeCandidates {
|
||||
logrus.Debugf("Trying to use manifest type %s…", manifestMIMEType)
|
||||
ic.manifestUpdates.ManifestMIMEType = manifestMIMEType
|
||||
attemptedManifest, attemptedManifestDigest, err := ic.copyUpdatedConfigAndManifest(ctx, targetInstance)
|
||||
@ -908,11 +911,7 @@ func (ic *imageCopier) copyLayers(ctx context.Context) error {
|
||||
|
||||
// The manifest is used to extract the information whether a given
|
||||
// layer is empty.
|
||||
manifestBlob, manifestType, err := ic.src.Manifest(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
man, err := manifest.FromBlob(manifestBlob, manifestType)
|
||||
man, err := manifest.FromBlob(ic.src.ManifestBlob, ic.src.ManifestMIMEType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1022,7 +1021,7 @@ func layerDigestsDiffer(a, b []types.BlobInfo) bool {
|
||||
// stores the resulting config and manifest to the destination, and returns the stored manifest
|
||||
// and its digest.
|
||||
func (ic *imageCopier) copyUpdatedConfigAndManifest(ctx context.Context, instanceDigest *digest.Digest) ([]byte, digest.Digest, error) {
|
||||
pendingImage := ic.src
|
||||
var pendingImage types.Image = ic.src
|
||||
if !ic.noPendingManifestUpdates() {
|
||||
if ic.cannotModifyManifestReason != "" {
|
||||
return nil, "", errors.Errorf("Internal error: copy needs an updated manifest but that was known to be forbidden: %q", ic.cannotModifyManifestReason)
|
||||
@ -1047,7 +1046,7 @@ func (ic *imageCopier) copyUpdatedConfigAndManifest(ctx context.Context, instanc
|
||||
return nil, "", errors.Wrap(err, "reading manifest")
|
||||
}
|
||||
|
||||
if err := ic.c.copyConfig(ctx, pendingImage); err != nil {
|
||||
if err := ic.copyConfig(ctx, pendingImage); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
@ -1067,19 +1066,19 @@ func (ic *imageCopier) copyUpdatedConfigAndManifest(ctx context.Context, instanc
|
||||
}
|
||||
|
||||
// copyConfig copies config.json, if any, from src to dest.
|
||||
func (c *copier) copyConfig(ctx context.Context, src types.Image) error {
|
||||
func (ic *imageCopier) copyConfig(ctx context.Context, src types.Image) error {
|
||||
srcInfo := src.ConfigInfo()
|
||||
if srcInfo.Digest != "" {
|
||||
if err := c.concurrentBlobCopiesSemaphore.Acquire(ctx, 1); err != nil {
|
||||
if err := ic.c.concurrentBlobCopiesSemaphore.Acquire(ctx, 1); err != nil {
|
||||
// This can only fail with ctx.Err(), so no need to blame acquiring the semaphore.
|
||||
return fmt.Errorf("copying config: %w", err)
|
||||
}
|
||||
defer c.concurrentBlobCopiesSemaphore.Release(1)
|
||||
defer ic.c.concurrentBlobCopiesSemaphore.Release(1)
|
||||
|
||||
destInfo, err := func() (types.BlobInfo, error) { // A scope for defer
|
||||
progressPool := c.newProgressPool()
|
||||
progressPool := ic.c.newProgressPool()
|
||||
defer progressPool.Wait()
|
||||
bar := c.createProgressBar(progressPool, false, srcInfo, "config", "done")
|
||||
bar := ic.c.createProgressBar(progressPool, false, srcInfo, "config", "done")
|
||||
defer bar.Abort(false)
|
||||
|
||||
configBlob, err := src.ConfigBlob(ctx)
|
||||
@ -1087,7 +1086,7 @@ func (c *copier) copyConfig(ctx context.Context, src types.Image) error {
|
||||
return types.BlobInfo{}, errors.Wrapf(err, "reading config blob %s", srcInfo.Digest)
|
||||
}
|
||||
|
||||
destInfo, err := c.copyBlobFromStream(ctx, bytes.NewReader(configBlob), srcInfo, nil, false, true, false, bar, -1, false)
|
||||
destInfo, err := ic.copyBlobFromStream(ctx, bytes.NewReader(configBlob), srcInfo, nil, true, false, bar, -1, false)
|
||||
if err != nil {
|
||||
return types.BlobInfo{}, err
|
||||
}
|
||||
@ -1146,6 +1145,10 @@ func (ic *imageCopier) copyLayer(ctx context.Context, srcInfo types.BlobInfo, to
|
||||
|
||||
// Don’t read the layer from the source if we already have the blob, and optimizations are acceptable.
|
||||
if canAvoidProcessingCompleteLayer {
|
||||
canChangeLayerCompression := ic.src.CanChangeLayerCompression(srcInfo.MediaType)
|
||||
logrus.Debugf("Checking if we can reuse blob %s: general substitution = %v, compression for MIME type %q = %v",
|
||||
srcInfo.Digest, ic.canSubstituteBlobs, srcInfo.MediaType, canChangeLayerCompression)
|
||||
canSubstitute := ic.canSubstituteBlobs && ic.src.CanChangeLayerCompression(srcInfo.MediaType)
|
||||
// TODO: at this point we don't know whether or not a blob we end up reusing is compressed using an algorithm
|
||||
// that is acceptable for use on layers in the manifest that we'll be writing later, so if we end up reusing
|
||||
// a blob that's compressed with e.g. zstd, but we're only allowed to write a v2s2 manifest, this will cause
|
||||
@ -1154,7 +1157,7 @@ func (ic *imageCopier) copyLayer(ctx context.Context, srcInfo types.BlobInfo, to
|
||||
// the ImageDestination interface lets us pass in.
|
||||
reused, blobInfo, err := ic.c.dest.TryReusingBlobWithOptions(ctx, srcInfo, private.TryReusingBlobOptions{
|
||||
Cache: ic.c.blobInfoCache,
|
||||
CanSubstitute: ic.canSubstituteBlobs,
|
||||
CanSubstitute: canSubstitute,
|
||||
EmptyLayer: emptyLayer,
|
||||
LayerIndex: &layerIndex,
|
||||
SrcRef: srcRef,
|
||||
@ -1303,7 +1306,7 @@ func (ic *imageCopier) copyLayerFromStream(ctx context.Context, srcStream io.Rea
|
||||
}
|
||||
}
|
||||
|
||||
blobInfo, err := ic.c.copyBlobFromStream(ctx, srcStream, srcInfo, getDiffIDRecorder, ic.cannotModifyManifestReason == "", false, toEncrypt, bar, layerIndex, emptyLayer) // Sets err to nil on success
|
||||
blobInfo, err := ic.copyBlobFromStream(ctx, srcStream, srcInfo, getDiffIDRecorder, false, toEncrypt, bar, layerIndex, emptyLayer) // Sets err to nil on success
|
||||
return blobInfo, diffIDChan, err
|
||||
// We need the defer … pipeWriter.CloseWithError() to happen HERE so that the caller can block on reading from diffIDChan
|
||||
}
|
||||
@ -1333,350 +1336,3 @@ func computeDiffID(stream io.Reader, decompressor compressiontypes.DecompressorF
|
||||
|
||||
return digest.Canonical.FromReader(stream)
|
||||
}
|
||||
|
||||
// errorAnnotationReader wraps the io.Reader passed to PutBlob for annotating the error happened during read.
|
||||
// These errors are reported as PutBlob errors, so we would otherwise misleadingly attribute them to the copy destination.
|
||||
type errorAnnotationReader struct {
|
||||
reader io.Reader
|
||||
}
|
||||
|
||||
// Read annotates the error happened during read
|
||||
func (r errorAnnotationReader) Read(b []byte) (n int, err error) {
|
||||
n, err = r.reader.Read(b)
|
||||
if err != io.EOF {
|
||||
return n, errors.Wrapf(err, "happened during read")
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
// copyBlobFromStream copies a blob with srcInfo (with known Digest and Annotations and possibly known Size) from srcStream to dest,
|
||||
// perhaps sending a copy to an io.Writer if getOriginalLayerCopyWriter != nil,
|
||||
// perhaps (de/re/)compressing it if canModifyBlob,
|
||||
// and returns a complete blobInfo of the copied blob.
|
||||
func (c *copier) copyBlobFromStream(ctx context.Context, srcStream io.Reader, srcInfo types.BlobInfo,
|
||||
getOriginalLayerCopyWriter func(decompressor compressiontypes.DecompressorFunc) io.Writer,
|
||||
canModifyBlob bool, isConfig bool, toEncrypt bool, bar *progressBar, layerIndex int, emptyLayer bool) (types.BlobInfo, error) {
|
||||
if isConfig { // This is guaranteed by the caller, but set it here to be explicit.
|
||||
canModifyBlob = false
|
||||
}
|
||||
|
||||
// The copying happens through a pipeline of connected io.Readers.
|
||||
// === Input: srcStream
|
||||
|
||||
// === Process input through digestingReader to validate against the expected digest.
|
||||
// Be paranoid; in case PutBlob somehow managed to ignore an error from digestingReader,
|
||||
// use a separate validation failure indicator.
|
||||
// Note that for this check we don't use the stronger "validationSucceeded" indicator, because
|
||||
// dest.PutBlob may detect that the layer already exists, in which case we don't
|
||||
// read stream to the end, and validation does not happen.
|
||||
digestingReader, err := newDigestingReader(srcStream, srcInfo.Digest)
|
||||
if err != nil {
|
||||
return types.BlobInfo{}, errors.Wrapf(err, "preparing to verify blob %s", srcInfo.Digest)
|
||||
}
|
||||
var destStream io.Reader = digestingReader
|
||||
|
||||
// === Update progress bars
|
||||
destStream = bar.ProxyReader(destStream)
|
||||
|
||||
// === Decrypt the stream, if required.
|
||||
var decrypted bool
|
||||
if isOciEncrypted(srcInfo.MediaType) && c.ociDecryptConfig != nil {
|
||||
newDesc := imgspecv1.Descriptor{
|
||||
Annotations: srcInfo.Annotations,
|
||||
}
|
||||
|
||||
var d digest.Digest
|
||||
destStream, d, err = ocicrypt.DecryptLayer(c.ociDecryptConfig, destStream, newDesc, false)
|
||||
if err != nil {
|
||||
return types.BlobInfo{}, errors.Wrapf(err, "decrypting layer %s", srcInfo.Digest)
|
||||
}
|
||||
|
||||
srcInfo.Digest = d
|
||||
srcInfo.Size = -1
|
||||
for k := range srcInfo.Annotations {
|
||||
if strings.HasPrefix(k, "org.opencontainers.image.enc") {
|
||||
delete(srcInfo.Annotations, k)
|
||||
}
|
||||
}
|
||||
decrypted = true
|
||||
}
|
||||
|
||||
// === Detect compression of the input stream.
|
||||
// This requires us to “peek ahead” into the stream to read the initial part, which requires us to chain through another io.Reader returned by DetectCompression.
|
||||
compressionFormat, decompressor, destStream, err := compression.DetectCompressionFormat(destStream) // We could skip this in some cases, but let's keep the code path uniform
|
||||
if err != nil {
|
||||
return types.BlobInfo{}, errors.Wrapf(err, "reading blob %s", srcInfo.Digest)
|
||||
}
|
||||
isCompressed := decompressor != nil
|
||||
if expectedCompressionFormat, known := expectedCompressionFormats[srcInfo.MediaType]; known && isCompressed && compressionFormat.Name() != expectedCompressionFormat.Name() {
|
||||
logrus.Debugf("blob %s with type %s should be compressed with %s, but compressor appears to be %s", srcInfo.Digest.String(), srcInfo.MediaType, expectedCompressionFormat.Name(), compressionFormat.Name())
|
||||
}
|
||||
|
||||
// === Send a copy of the original, uncompressed, stream, to a separate path if necessary.
|
||||
var originalLayerReader io.Reader // DO NOT USE this other than to drain the input if no other consumer in the pipeline has done so.
|
||||
if getOriginalLayerCopyWriter != nil {
|
||||
destStream = io.TeeReader(destStream, getOriginalLayerCopyWriter(decompressor))
|
||||
originalLayerReader = destStream
|
||||
}
|
||||
|
||||
compressionMetadata := map[string]string{}
|
||||
// === Deal with layer compression/decompression if necessary
|
||||
// WARNING: If you are adding new reasons to change the blob, update also the OptimizeDestinationImageAlreadyExists
|
||||
// short-circuit conditions
|
||||
var inputInfo types.BlobInfo
|
||||
var compressionOperation types.LayerCompression
|
||||
var uploadCompressionFormat *compressiontypes.Algorithm
|
||||
srcCompressorName := internalblobinfocache.Uncompressed
|
||||
if isCompressed {
|
||||
srcCompressorName = compressionFormat.Name()
|
||||
}
|
||||
var uploadCompressorName string
|
||||
if canModifyBlob && isOciEncrypted(srcInfo.MediaType) {
|
||||
// PreserveOriginal due to any compression not being able to be done on an encrypted blob unless decrypted
|
||||
logrus.Debugf("Using original blob without modification for encrypted blob")
|
||||
compressionOperation = types.PreserveOriginal
|
||||
inputInfo = srcInfo
|
||||
srcCompressorName = internalblobinfocache.UnknownCompression
|
||||
uploadCompressionFormat = nil
|
||||
uploadCompressorName = internalblobinfocache.UnknownCompression
|
||||
} else if canModifyBlob && c.dest.DesiredLayerCompression() == types.Compress && !isCompressed {
|
||||
logrus.Debugf("Compressing blob on the fly")
|
||||
compressionOperation = types.Compress
|
||||
pipeReader, pipeWriter := io.Pipe()
|
||||
defer pipeReader.Close()
|
||||
|
||||
if c.compressionFormat != nil {
|
||||
uploadCompressionFormat = c.compressionFormat
|
||||
} else {
|
||||
uploadCompressionFormat = defaultCompressionFormat
|
||||
}
|
||||
// If this fails while writing data, it will do pipeWriter.CloseWithError(); if it fails otherwise,
|
||||
// e.g. because we have exited and due to pipeReader.Close() above further writing to the pipe has failed,
|
||||
// we don’t care.
|
||||
go c.compressGoroutine(pipeWriter, destStream, compressionMetadata, *uploadCompressionFormat) // Closes pipeWriter
|
||||
destStream = pipeReader
|
||||
inputInfo.Digest = ""
|
||||
inputInfo.Size = -1
|
||||
uploadCompressorName = uploadCompressionFormat.Name()
|
||||
} else if canModifyBlob && c.dest.DesiredLayerCompression() == types.Compress && isCompressed &&
|
||||
c.compressionFormat != nil && c.compressionFormat.Name() != compressionFormat.Name() {
|
||||
// When the blob is compressed, but the desired format is different, it first needs to be decompressed and finally
|
||||
// re-compressed using the desired format.
|
||||
logrus.Debugf("Blob will be converted")
|
||||
|
||||
compressionOperation = types.PreserveOriginal
|
||||
s, err := decompressor(destStream)
|
||||
if err != nil {
|
||||
return types.BlobInfo{}, err
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
pipeReader, pipeWriter := io.Pipe()
|
||||
defer pipeReader.Close()
|
||||
|
||||
uploadCompressionFormat = c.compressionFormat
|
||||
go c.compressGoroutine(pipeWriter, s, compressionMetadata, *uploadCompressionFormat) // Closes pipeWriter
|
||||
|
||||
destStream = pipeReader
|
||||
inputInfo.Digest = ""
|
||||
inputInfo.Size = -1
|
||||
uploadCompressorName = uploadCompressionFormat.Name()
|
||||
} else if canModifyBlob && c.dest.DesiredLayerCompression() == types.Decompress && isCompressed {
|
||||
logrus.Debugf("Blob will be decompressed")
|
||||
compressionOperation = types.Decompress
|
||||
s, err := decompressor(destStream)
|
||||
if err != nil {
|
||||
return types.BlobInfo{}, err
|
||||
}
|
||||
defer s.Close()
|
||||
destStream = s
|
||||
inputInfo.Digest = ""
|
||||
inputInfo.Size = -1
|
||||
uploadCompressionFormat = nil
|
||||
uploadCompressorName = internalblobinfocache.Uncompressed
|
||||
} else {
|
||||
// PreserveOriginal might also need to recompress the original blob if the desired compression format is different.
|
||||
logrus.Debugf("Using original blob without modification")
|
||||
compressionOperation = types.PreserveOriginal
|
||||
inputInfo = srcInfo
|
||||
// Remember if the original blob was compressed, and if so how, so that if
|
||||
// LayerInfosForCopy() returned something that differs from what was in the
|
||||
// source's manifest, and UpdatedImage() needs to call UpdateLayerInfos(),
|
||||
// it will be able to correctly derive the MediaType for the copied blob.
|
||||
if isCompressed {
|
||||
uploadCompressionFormat = &compressionFormat
|
||||
} else {
|
||||
uploadCompressionFormat = nil
|
||||
}
|
||||
uploadCompressorName = srcCompressorName
|
||||
}
|
||||
|
||||
// === Encrypt the stream for valid mediatypes if ociEncryptConfig provided
|
||||
var (
|
||||
encrypted bool
|
||||
finalizer ocicrypt.EncryptLayerFinalizer
|
||||
)
|
||||
if toEncrypt {
|
||||
if decrypted {
|
||||
return types.BlobInfo{}, errors.New("Unable to support both decryption and encryption in the same copy")
|
||||
}
|
||||
|
||||
if !isOciEncrypted(srcInfo.MediaType) && c.ociEncryptConfig != nil {
|
||||
var annotations map[string]string
|
||||
if !decrypted {
|
||||
annotations = srcInfo.Annotations
|
||||
}
|
||||
desc := imgspecv1.Descriptor{
|
||||
MediaType: srcInfo.MediaType,
|
||||
Digest: srcInfo.Digest,
|
||||
Size: srcInfo.Size,
|
||||
Annotations: annotations,
|
||||
}
|
||||
|
||||
s, fin, err := ocicrypt.EncryptLayer(c.ociEncryptConfig, destStream, desc)
|
||||
if err != nil {
|
||||
return types.BlobInfo{}, errors.Wrapf(err, "encrypting blob %s", srcInfo.Digest)
|
||||
}
|
||||
|
||||
destStream = s
|
||||
finalizer = fin
|
||||
inputInfo.Digest = ""
|
||||
inputInfo.Size = -1
|
||||
encrypted = true
|
||||
}
|
||||
}
|
||||
|
||||
// === Report progress using the c.progress channel, if required.
|
||||
if c.progress != nil && c.progressInterval > 0 {
|
||||
progressReader := newProgressReader(
|
||||
destStream,
|
||||
c.progress,
|
||||
c.progressInterval,
|
||||
srcInfo,
|
||||
)
|
||||
defer progressReader.reportDone()
|
||||
destStream = progressReader
|
||||
}
|
||||
|
||||
// === Finally, send the layer stream to dest.
|
||||
options := private.PutBlobOptions{
|
||||
Cache: c.blobInfoCache,
|
||||
IsConfig: isConfig,
|
||||
EmptyLayer: emptyLayer,
|
||||
}
|
||||
if !isConfig {
|
||||
options.LayerIndex = &layerIndex
|
||||
}
|
||||
uploadedInfo, err := c.dest.PutBlobWithOptions(ctx, &errorAnnotationReader{destStream}, inputInfo, options)
|
||||
if err != nil {
|
||||
return types.BlobInfo{}, errors.Wrap(err, "writing blob")
|
||||
}
|
||||
|
||||
uploadedInfo.Annotations = srcInfo.Annotations
|
||||
|
||||
uploadedInfo.CompressionOperation = compressionOperation
|
||||
// If we can modify the layer's blob, set the desired algorithm for it to be set in the manifest.
|
||||
uploadedInfo.CompressionAlgorithm = uploadCompressionFormat
|
||||
if decrypted {
|
||||
uploadedInfo.CryptoOperation = types.Decrypt
|
||||
} else if encrypted {
|
||||
encryptAnnotations, err := finalizer()
|
||||
if err != nil {
|
||||
return types.BlobInfo{}, errors.Wrap(err, "Unable to finalize encryption")
|
||||
}
|
||||
uploadedInfo.CryptoOperation = types.Encrypt
|
||||
if uploadedInfo.Annotations == nil {
|
||||
uploadedInfo.Annotations = map[string]string{}
|
||||
}
|
||||
for k, v := range encryptAnnotations {
|
||||
uploadedInfo.Annotations[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// This is fairly horrible: the writer from getOriginalLayerCopyWriter wants to consume
|
||||
// all of the input (to compute DiffIDs), even if dest.PutBlob does not need it.
|
||||
// So, read everything from originalLayerReader, which will cause the rest to be
|
||||
// sent there if we are not already at EOF.
|
||||
if getOriginalLayerCopyWriter != nil {
|
||||
logrus.Debugf("Consuming rest of the original blob to satisfy getOriginalLayerCopyWriter")
|
||||
_, err := io.Copy(io.Discard, originalLayerReader)
|
||||
if err != nil {
|
||||
return types.BlobInfo{}, errors.Wrapf(err, "reading input blob %s", srcInfo.Digest)
|
||||
}
|
||||
}
|
||||
|
||||
if digestingReader.validationFailed { // Coverage: This should never happen.
|
||||
return types.BlobInfo{}, errors.Errorf("Internal error writing blob %s, digest verification failed but was ignored", srcInfo.Digest)
|
||||
}
|
||||
if inputInfo.Digest != "" && uploadedInfo.Digest != inputInfo.Digest {
|
||||
return types.BlobInfo{}, errors.Errorf("Internal error writing blob %s, blob with digest %s saved with digest %s", srcInfo.Digest, inputInfo.Digest, uploadedInfo.Digest)
|
||||
}
|
||||
if digestingReader.validationSucceeded {
|
||||
// Don’t record any associations that involve encrypted data. This is a bit crude,
|
||||
// some blob substitutions (replacing pulls of encrypted data with local reuse of known decryption outcomes)
|
||||
// might be safe, but it’s not trivially obvious, so let’s be conservative for now.
|
||||
// This crude approach also means we don’t need to record whether a blob is encrypted
|
||||
// in the blob info cache (which would probably be necessary for any more complex logic),
|
||||
// and the simplicity is attractive.
|
||||
if !encrypted && !decrypted {
|
||||
// If compressionOperation != types.PreserveOriginal, we now have two reliable digest values:
|
||||
// srcinfo.Digest describes the pre-compressionOperation input, verified by digestingReader
|
||||
// uploadedInfo.Digest describes the post-compressionOperation output, computed by PutBlob
|
||||
// (because inputInfo.Digest == "", this must have been computed afresh).
|
||||
switch compressionOperation {
|
||||
case types.PreserveOriginal:
|
||||
break // Do nothing, we have only one digest and we might not have even verified it.
|
||||
case types.Compress:
|
||||
c.blobInfoCache.RecordDigestUncompressedPair(uploadedInfo.Digest, srcInfo.Digest)
|
||||
case types.Decompress:
|
||||
c.blobInfoCache.RecordDigestUncompressedPair(srcInfo.Digest, uploadedInfo.Digest)
|
||||
default:
|
||||
return types.BlobInfo{}, errors.Errorf("Internal error: Unexpected compressionOperation value %#v", compressionOperation)
|
||||
}
|
||||
}
|
||||
if uploadCompressorName != "" && uploadCompressorName != internalblobinfocache.UnknownCompression {
|
||||
c.blobInfoCache.RecordDigestCompressorName(uploadedInfo.Digest, uploadCompressorName)
|
||||
}
|
||||
if srcInfo.Digest != "" && srcCompressorName != "" && srcCompressorName != internalblobinfocache.UnknownCompression {
|
||||
c.blobInfoCache.RecordDigestCompressorName(srcInfo.Digest, srcCompressorName)
|
||||
}
|
||||
}
|
||||
|
||||
// Copy all the metadata generated by the compressor into the annotations.
|
||||
if uploadedInfo.Annotations == nil {
|
||||
uploadedInfo.Annotations = map[string]string{}
|
||||
}
|
||||
for k, v := range compressionMetadata {
|
||||
uploadedInfo.Annotations[k] = v
|
||||
}
|
||||
|
||||
return uploadedInfo, nil
|
||||
}
|
||||
|
||||
// doCompression reads all input from src and writes its compressed equivalent to dest.
|
||||
func doCompression(dest io.Writer, src io.Reader, metadata map[string]string, compressionFormat compressiontypes.Algorithm, compressionLevel *int) error {
|
||||
compressor, err := compression.CompressStreamWithMetadata(dest, metadata, compressionFormat, compressionLevel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf := make([]byte, compressionBufferSize)
|
||||
|
||||
_, err = io.CopyBuffer(compressor, src, buf) // Sets err to nil, i.e. causes dest.Close()
|
||||
if err != nil {
|
||||
compressor.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
return compressor.Close()
|
||||
}
|
||||
|
||||
// compressGoroutine reads all input from src and writes its compressed equivalent to dest.
|
||||
func (c *copier) compressGoroutine(dest *io.PipeWriter, src io.Reader, metadata map[string]string, compressionFormat compressiontypes.Algorithm) {
|
||||
err := errors.New("Internal error: unexpected panic in compressGoroutine")
|
||||
defer func() { // Note that this is not the same as {defer dest.CloseWithError(err)}; we need err to be evaluated lazily.
|
||||
_ = dest.CloseWithError(err) // CloseWithError(nil) is equivalent to Close(), always returns nil
|
||||
}()
|
||||
|
||||
err = doCompression(dest, src, metadata, compressionFormat, c.compressionLevel)
|
||||
}
|
||||
|
24
vendor/github.com/containers/image/v5/copy/encrypt.go
generated
vendored
24
vendor/github.com/containers/image/v5/copy/encrypt.go
generated
vendored
@ -1,24 +0,0 @@
|
||||
package copy
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/containers/image/v5/types"
|
||||
)
|
||||
|
||||
// isOciEncrypted returns a bool indicating if a mediatype is encrypted
|
||||
// This function will be moved to be part of OCI spec when adopted.
|
||||
func isOciEncrypted(mediatype string) bool {
|
||||
return strings.HasSuffix(mediatype, "+encrypted")
|
||||
}
|
||||
|
||||
// isEncrypted checks if an image is encrypted
|
||||
func isEncrypted(i types.Image) bool {
|
||||
layers := i.LayerInfos()
|
||||
for _, l := range layers {
|
||||
if isOciEncrypted(l.MediaType) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
129
vendor/github.com/containers/image/v5/copy/encryption.go
generated
vendored
Normal file
129
vendor/github.com/containers/image/v5/copy/encryption.go
generated
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
package copy
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/containers/ocicrypt"
|
||||
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// isOciEncrypted returns a bool indicating if a mediatype is encrypted
|
||||
// This function will be moved to be part of OCI spec when adopted.
|
||||
func isOciEncrypted(mediatype string) bool {
|
||||
return strings.HasSuffix(mediatype, "+encrypted")
|
||||
}
|
||||
|
||||
// isEncrypted checks if an image is encrypted
|
||||
func isEncrypted(i types.Image) bool {
|
||||
layers := i.LayerInfos()
|
||||
for _, l := range layers {
|
||||
if isOciEncrypted(l.MediaType) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// bpDecryptionStepData contains data that the copy pipeline needs about the decryption step.
|
||||
type bpDecryptionStepData struct {
|
||||
decrypting bool // We are actually decrypting the stream
|
||||
}
|
||||
|
||||
// blobPipelineDecryptionStep updates *stream to decrypt if, it necessary.
|
||||
// srcInfo is only used for error messages.
|
||||
// Returns data for other steps; the caller should eventually use updateCryptoOperation.
|
||||
func (c *copier) blobPipelineDecryptionStep(stream *sourceStream, srcInfo types.BlobInfo) (*bpDecryptionStepData, error) {
|
||||
if isOciEncrypted(stream.info.MediaType) && c.ociDecryptConfig != nil {
|
||||
desc := imgspecv1.Descriptor{
|
||||
Annotations: stream.info.Annotations,
|
||||
}
|
||||
reader, decryptedDigest, err := ocicrypt.DecryptLayer(c.ociDecryptConfig, stream.reader, desc, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "decrypting layer %s", srcInfo.Digest)
|
||||
}
|
||||
|
||||
stream.reader = reader
|
||||
stream.info.Digest = decryptedDigest
|
||||
stream.info.Size = -1
|
||||
for k := range stream.info.Annotations {
|
||||
if strings.HasPrefix(k, "org.opencontainers.image.enc") {
|
||||
delete(stream.info.Annotations, k)
|
||||
}
|
||||
}
|
||||
return &bpDecryptionStepData{
|
||||
decrypting: true,
|
||||
}, nil
|
||||
}
|
||||
return &bpDecryptionStepData{
|
||||
decrypting: false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// updateCryptoOperation sets *operation, if necessary.
|
||||
func (d *bpDecryptionStepData) updateCryptoOperation(operation *types.LayerCrypto) {
|
||||
if d.decrypting {
|
||||
*operation = types.Decrypt
|
||||
}
|
||||
}
|
||||
|
||||
// bpdData contains data that the copy pipeline needs about the encryption step.
|
||||
type bpEncryptionStepData struct {
|
||||
encrypting bool // We are actually encrypting the stream
|
||||
finalizer ocicrypt.EncryptLayerFinalizer
|
||||
}
|
||||
|
||||
// blobPipelineEncryptionStep updates *stream to encrypt if, it required by toEncrypt.
|
||||
// srcInfo is primarily used for error messages.
|
||||
// Returns data for other steps; the caller should eventually call updateCryptoOperationAndAnnotations.
|
||||
func (c *copier) blobPipelineEncryptionStep(stream *sourceStream, toEncrypt bool, srcInfo types.BlobInfo,
|
||||
decryptionStep *bpDecryptionStepData) (*bpEncryptionStepData, error) {
|
||||
if toEncrypt && !isOciEncrypted(srcInfo.MediaType) && c.ociEncryptConfig != nil {
|
||||
var annotations map[string]string
|
||||
if !decryptionStep.decrypting {
|
||||
annotations = srcInfo.Annotations
|
||||
}
|
||||
desc := imgspecv1.Descriptor{
|
||||
MediaType: srcInfo.MediaType,
|
||||
Digest: srcInfo.Digest,
|
||||
Size: srcInfo.Size,
|
||||
Annotations: annotations,
|
||||
}
|
||||
reader, finalizer, err := ocicrypt.EncryptLayer(c.ociEncryptConfig, stream.reader, desc)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "encrypting blob %s", srcInfo.Digest)
|
||||
}
|
||||
|
||||
stream.reader = reader
|
||||
stream.info.Digest = ""
|
||||
stream.info.Size = -1
|
||||
return &bpEncryptionStepData{
|
||||
encrypting: true,
|
||||
finalizer: finalizer,
|
||||
}, nil
|
||||
}
|
||||
return &bpEncryptionStepData{
|
||||
encrypting: false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// updateCryptoOperationAndAnnotations sets *operation and updates *annotations, if necessary.
|
||||
func (d *bpEncryptionStepData) updateCryptoOperationAndAnnotations(operation *types.LayerCrypto, annotations *map[string]string) error {
|
||||
if !d.encrypting {
|
||||
return nil
|
||||
}
|
||||
|
||||
encryptAnnotations, err := d.finalizer()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Unable to finalize encryption")
|
||||
}
|
||||
*operation = types.Encrypt
|
||||
if *annotations == nil {
|
||||
*annotations = map[string]string{}
|
||||
}
|
||||
for k, v := range encryptAnnotations {
|
||||
(*annotations)[k] = v
|
||||
}
|
||||
return nil
|
||||
}
|
68
vendor/github.com/containers/image/v5/copy/manifest.go
generated
vendored
68
vendor/github.com/containers/image/v5/copy/manifest.go
generated
vendored
@ -38,31 +38,50 @@ func (os *orderedSet) append(s string) {
|
||||
}
|
||||
}
|
||||
|
||||
// determineManifestConversion updates ic.manifestUpdates to convert manifest to a supported MIME type, if necessary and ic.canModifyManifest.
|
||||
// Note that the conversion will only happen later, through ic.src.UpdatedImage
|
||||
// Returns the preferred manifest MIME type (whether we are converting to it or using it unmodified),
|
||||
// and a list of other possible alternatives, in order.
|
||||
func (ic *imageCopier) determineManifestConversion(ctx context.Context, destSupportedManifestMIMETypes []string, forceManifestMIMEType string, requiresOciEncryption bool) (string, []string, error) {
|
||||
_, srcType, err := ic.src.Manifest(ctx)
|
||||
if err != nil { // This should have been cached?!
|
||||
return "", nil, errors.Wrap(err, "reading manifest")
|
||||
}
|
||||
// determineManifestConversionInputs contains the inputs for determineManifestConversion.
|
||||
type determineManifestConversionInputs struct {
|
||||
srcMIMEType string // MIME type of the input manifest
|
||||
|
||||
destSupportedManifestMIMETypes []string // MIME types supported by the destination, per types.ImageDestination.SupportedManifestMIMETypes()
|
||||
|
||||
forceManifestMIMEType string // User’s choice of forced manifest MIME type
|
||||
requiresOCIEncryption bool // Restrict to manifest formats that can support OCI encryption
|
||||
cannotModifyManifestReason string // The reason the manifest cannot be modified, or an empty string if it can
|
||||
}
|
||||
|
||||
// manifestConversionPlan contains the decisions made by determineManifestConversion.
|
||||
type manifestConversionPlan struct {
|
||||
// The preferred manifest MIME type (whether we are converting to it or using it unmodified).
|
||||
// We compute this only to show it in error messages; without having to add this context
|
||||
// in an error message, we would be happy enough to know only that no conversion is needed.
|
||||
preferredMIMEType string
|
||||
preferredMIMETypeNeedsConversion bool // True if using preferredMIMEType requires a conversion step.
|
||||
otherMIMETypeCandidates []string // Other possible alternatives, in order
|
||||
}
|
||||
|
||||
// determineManifestConversion returns a plan for what formats, and possibly conversions, to use based on in.
|
||||
func determineManifestConversion(in determineManifestConversionInputs) (manifestConversionPlan, error) {
|
||||
srcType := in.srcMIMEType
|
||||
normalizedSrcType := manifest.NormalizedMIMEType(srcType)
|
||||
if srcType != normalizedSrcType {
|
||||
logrus.Debugf("Source manifest MIME type %s, treating it as %s", srcType, normalizedSrcType)
|
||||
srcType = normalizedSrcType
|
||||
}
|
||||
|
||||
if forceManifestMIMEType != "" {
|
||||
destSupportedManifestMIMETypes = []string{forceManifestMIMEType}
|
||||
destSupportedManifestMIMETypes := in.destSupportedManifestMIMETypes
|
||||
if in.forceManifestMIMEType != "" {
|
||||
destSupportedManifestMIMETypes = []string{in.forceManifestMIMEType}
|
||||
}
|
||||
|
||||
if len(destSupportedManifestMIMETypes) == 0 && (!requiresOciEncryption || manifest.MIMETypeSupportsEncryption(srcType)) {
|
||||
return srcType, []string{}, nil // Anything goes; just use the original as is, do not try any conversions.
|
||||
if len(destSupportedManifestMIMETypes) == 0 && (!in.requiresOCIEncryption || manifest.MIMETypeSupportsEncryption(srcType)) {
|
||||
return manifestConversionPlan{ // Anything goes; just use the original as is, do not try any conversions.
|
||||
preferredMIMEType: srcType,
|
||||
otherMIMETypeCandidates: []string{},
|
||||
}, nil
|
||||
}
|
||||
supportedByDest := map[string]struct{}{}
|
||||
for _, t := range destSupportedManifestMIMETypes {
|
||||
if !requiresOciEncryption || manifest.MIMETypeSupportsEncryption(t) {
|
||||
if !in.requiresOCIEncryption || manifest.MIMETypeSupportsEncryption(t) {
|
||||
supportedByDest[t] = struct{}{}
|
||||
}
|
||||
}
|
||||
@ -79,13 +98,16 @@ func (ic *imageCopier) determineManifestConversion(ctx context.Context, destSupp
|
||||
if _, ok := supportedByDest[srcType]; ok {
|
||||
prioritizedTypes.append(srcType)
|
||||
}
|
||||
if ic.cannotModifyManifestReason != "" {
|
||||
if in.cannotModifyManifestReason != "" {
|
||||
// We could also drop this check and have the caller
|
||||
// make the choice; it is already doing that to an extent, to improve error
|
||||
// messages. But it is nice to hide the “if we can't modify, do no conversion”
|
||||
// special case in here; the caller can then worry (or not) only about a good UI.
|
||||
logrus.Debugf("We can't modify the manifest, hoping for the best...")
|
||||
return srcType, []string{}, nil // Take our chances - FIXME? Or should we fail without trying?
|
||||
return manifestConversionPlan{ // Take our chances - FIXME? Or should we fail without trying?
|
||||
preferredMIMEType: srcType,
|
||||
otherMIMETypeCandidates: []string{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Then use our list of preferred types.
|
||||
@ -102,15 +124,17 @@ func (ic *imageCopier) determineManifestConversion(ctx context.Context, destSupp
|
||||
|
||||
logrus.Debugf("Manifest has MIME type %s, ordered candidate list [%s]", srcType, strings.Join(prioritizedTypes.list, ", "))
|
||||
if len(prioritizedTypes.list) == 0 { // Coverage: destSupportedManifestMIMETypes is not empty (or we would have exited in the “Anything goes” case above), so this should never happen.
|
||||
return "", nil, errors.New("Internal error: no candidate MIME types")
|
||||
return manifestConversionPlan{}, errors.New("Internal error: no candidate MIME types")
|
||||
}
|
||||
preferredType := prioritizedTypes.list[0]
|
||||
if preferredType != srcType {
|
||||
ic.manifestUpdates.ManifestMIMEType = preferredType
|
||||
} else {
|
||||
res := manifestConversionPlan{
|
||||
preferredMIMEType: prioritizedTypes.list[0],
|
||||
otherMIMETypeCandidates: prioritizedTypes.list[1:],
|
||||
}
|
||||
res.preferredMIMETypeNeedsConversion = res.preferredMIMEType != srcType
|
||||
if !res.preferredMIMETypeNeedsConversion {
|
||||
logrus.Debugf("... will first try using the original manifest unmodified")
|
||||
}
|
||||
return preferredType, prioritizedTypes.list[1:], nil
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// isMultiImage returns true if img is a list of images
|
||||
|
5
vendor/github.com/containers/image/v5/directory/directory_transport.go
generated
vendored
5
vendor/github.com/containers/image/v5/directory/directory_transport.go
generated
vendored
@ -8,7 +8,7 @@ import (
|
||||
|
||||
"github.com/containers/image/v5/directory/explicitfilepath"
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/containers/image/v5/image"
|
||||
"github.com/containers/image/v5/internal/image"
|
||||
"github.com/containers/image/v5/transports"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/opencontainers/go-digest"
|
||||
@ -140,8 +140,7 @@ func (ref dirReference) PolicyConfigurationNamespaces() []string {
|
||||
// verify that UnparsedImage, and convert it into a real Image via image.FromUnparsedImage.
|
||||
// WARNING: This may not do the right thing for a manifest list, see image.FromSource for details.
|
||||
func (ref dirReference) NewImage(ctx context.Context, sys *types.SystemContext) (types.ImageCloser, error) {
|
||||
src := newImageSource(ref)
|
||||
return image.FromSource(ctx, sys, src)
|
||||
return image.FromReference(ctx, sys, ref)
|
||||
}
|
||||
|
||||
// NewImageSource returns a types.ImageSource for this reference.
|
||||
|
8
vendor/github.com/containers/image/v5/docker/archive/transport.go
generated
vendored
8
vendor/github.com/containers/image/v5/docker/archive/transport.go
generated
vendored
@ -8,7 +8,7 @@ import (
|
||||
|
||||
"github.com/containers/image/v5/docker/internal/tarfile"
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
ctrImage "github.com/containers/image/v5/image"
|
||||
ctrImage "github.com/containers/image/v5/internal/image"
|
||||
"github.com/containers/image/v5/transports"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/pkg/errors"
|
||||
@ -185,11 +185,7 @@ func (ref archiveReference) PolicyConfigurationNamespaces() []string {
|
||||
// verify that UnparsedImage, and convert it into a real Image via image.FromUnparsedImage.
|
||||
// WARNING: This may not do the right thing for a manifest list, see image.FromSource for details.
|
||||
func (ref archiveReference) NewImage(ctx context.Context, sys *types.SystemContext) (types.ImageCloser, error) {
|
||||
src, err := newImageSource(ctx, sys, ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ctrImage.FromSource(ctx, sys, src)
|
||||
return ctrImage.FromReference(ctx, sys, ref)
|
||||
}
|
||||
|
||||
// NewImageSource returns a types.ImageSource for this reference.
|
||||
|
8
vendor/github.com/containers/image/v5/docker/daemon/daemon_transport.go
generated
vendored
8
vendor/github.com/containers/image/v5/docker/daemon/daemon_transport.go
generated
vendored
@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/containers/image/v5/docker/policyconfiguration"
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/containers/image/v5/image"
|
||||
"github.com/containers/image/v5/internal/image"
|
||||
"github.com/containers/image/v5/transports"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/opencontainers/go-digest"
|
||||
@ -195,11 +195,7 @@ func (ref daemonReference) PolicyConfigurationNamespaces() []string {
|
||||
// verify that UnparsedImage, and convert it into a real Image via image.FromUnparsedImage.
|
||||
// WARNING: This may not do the right thing for a manifest list, see image.FromSource for details.
|
||||
func (ref daemonReference) NewImage(ctx context.Context, sys *types.SystemContext) (types.ImageCloser, error) {
|
||||
src, err := newImageSource(ctx, sys, ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return image.FromSource(ctx, sys, src)
|
||||
return image.FromReference(ctx, sys, ref)
|
||||
}
|
||||
|
||||
// NewImageSource returns a types.ImageSource for this reference.
|
||||
|
5
vendor/github.com/containers/image/v5/docker/docker_client.go
generated
vendored
5
vendor/github.com/containers/image/v5/docker/docker_client.go
generated
vendored
@ -163,9 +163,8 @@ func newBearerTokenFromJSONBlob(blob []byte) (*bearerToken, error) {
|
||||
func serverDefault() *tls.Config {
|
||||
return &tls.Config{
|
||||
// Avoid fallback to SSL protocols < TLS1.0
|
||||
MinVersion: tls.VersionTLS10,
|
||||
PreferServerCipherSuites: true,
|
||||
CipherSuites: tlsconfig.DefaultServerAcceptedCiphers,
|
||||
MinVersion: tls.VersionTLS10,
|
||||
CipherSuites: tlsconfig.DefaultServerAcceptedCiphers,
|
||||
}
|
||||
}
|
||||
|
||||
|
2
vendor/github.com/containers/image/v5/docker/docker_image.go
generated
vendored
2
vendor/github.com/containers/image/v5/docker/docker_image.go
generated
vendored
@ -9,7 +9,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/containers/image/v5/image"
|
||||
"github.com/containers/image/v5/internal/image"
|
||||
"github.com/containers/image/v5/manifest"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/opencontainers/go-digest"
|
||||
|
392
vendor/github.com/containers/image/v5/image/docker_schema2.go
generated
vendored
392
vendor/github.com/containers/image/v5/image/docker_schema2.go
generated
vendored
@ -1,400 +1,14 @@
|
||||
package image
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/containers/image/v5/internal/iolimits"
|
||||
"github.com/containers/image/v5/manifest"
|
||||
"github.com/containers/image/v5/pkg/blobinfocache/none"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/opencontainers/go-digest"
|
||||
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/containers/image/v5/internal/image"
|
||||
)
|
||||
|
||||
// GzippedEmptyLayer is a gzip-compressed version of an empty tar file (1024 NULL bytes)
|
||||
// This comes from github.com/docker/distribution/manifest/schema1/config_builder.go; there is
|
||||
// a non-zero embedded timestamp; we could zero that, but that would just waste storage space
|
||||
// in registries, so let’s use the same values.
|
||||
var GzippedEmptyLayer = []byte{
|
||||
31, 139, 8, 0, 0, 9, 110, 136, 0, 255, 98, 24, 5, 163, 96, 20, 140, 88,
|
||||
0, 8, 0, 0, 255, 255, 46, 175, 181, 239, 0, 4, 0, 0,
|
||||
}
|
||||
var GzippedEmptyLayer = image.GzippedEmptyLayer
|
||||
|
||||
// GzippedEmptyLayerDigest is a digest of GzippedEmptyLayer
|
||||
const GzippedEmptyLayerDigest = digest.Digest("sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4")
|
||||
|
||||
type manifestSchema2 struct {
|
||||
src types.ImageSource // May be nil if configBlob is not nil
|
||||
configBlob []byte // If set, corresponds to contents of ConfigDescriptor.
|
||||
m *manifest.Schema2
|
||||
}
|
||||
|
||||
func manifestSchema2FromManifest(src types.ImageSource, manifestBlob []byte) (genericManifest, error) {
|
||||
m, err := manifest.Schema2FromManifest(manifestBlob)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &manifestSchema2{
|
||||
src: src,
|
||||
m: m,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// manifestSchema2FromComponents builds a new manifestSchema2 from the supplied data:
|
||||
func manifestSchema2FromComponents(config manifest.Schema2Descriptor, src types.ImageSource, configBlob []byte, layers []manifest.Schema2Descriptor) *manifestSchema2 {
|
||||
return &manifestSchema2{
|
||||
src: src,
|
||||
configBlob: configBlob,
|
||||
m: manifest.Schema2FromComponents(config, layers),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *manifestSchema2) serialize() ([]byte, error) {
|
||||
return m.m.Serialize()
|
||||
}
|
||||
|
||||
func (m *manifestSchema2) manifestMIMEType() string {
|
||||
return m.m.MediaType
|
||||
}
|
||||
|
||||
// ConfigInfo returns a complete BlobInfo for the separate config object, or a BlobInfo{Digest:""} if there isn't a separate object.
|
||||
// Note that the config object may not exist in the underlying storage in the return value of UpdatedImage! Use ConfigBlob() below.
|
||||
func (m *manifestSchema2) ConfigInfo() types.BlobInfo {
|
||||
return m.m.ConfigInfo()
|
||||
}
|
||||
|
||||
// OCIConfig returns the image configuration as per OCI v1 image-spec. Information about
|
||||
// layers in the resulting configuration isn't guaranteed to be returned to due how
|
||||
// old image manifests work (docker v2s1 especially).
|
||||
func (m *manifestSchema2) OCIConfig(ctx context.Context) (*imgspecv1.Image, error) {
|
||||
configBlob, err := m.ConfigBlob(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// docker v2s2 and OCI v1 are mostly compatible but v2s2 contains more fields
|
||||
// than OCI v1. This unmarshal makes sure we drop docker v2s2
|
||||
// fields that aren't needed in OCI v1.
|
||||
configOCI := &imgspecv1.Image{}
|
||||
if err := json.Unmarshal(configBlob, configOCI); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return configOCI, nil
|
||||
}
|
||||
|
||||
// ConfigBlob returns the blob described by ConfigInfo, iff ConfigInfo().Digest != ""; nil otherwise.
|
||||
// The result is cached; it is OK to call this however often you need.
|
||||
func (m *manifestSchema2) ConfigBlob(ctx context.Context) ([]byte, error) {
|
||||
if m.configBlob == nil {
|
||||
if m.src == nil {
|
||||
return nil, errors.Errorf("Internal error: neither src nor configBlob set in manifestSchema2")
|
||||
}
|
||||
stream, _, err := m.src.GetBlob(ctx, manifest.BlobInfoFromSchema2Descriptor(m.m.ConfigDescriptor), none.NoCache)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer stream.Close()
|
||||
blob, err := iolimits.ReadAtMost(stream, iolimits.MaxConfigBodySize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
computedDigest := digest.FromBytes(blob)
|
||||
if computedDigest != m.m.ConfigDescriptor.Digest {
|
||||
return nil, errors.Errorf("Download config.json digest %s does not match expected %s", computedDigest, m.m.ConfigDescriptor.Digest)
|
||||
}
|
||||
m.configBlob = blob
|
||||
}
|
||||
return m.configBlob, nil
|
||||
}
|
||||
|
||||
// LayerInfos returns a list of BlobInfos of layers referenced by this image, in order (the root layer first, and then successive layered layers).
|
||||
// The Digest field is guaranteed to be provided; Size may be -1.
|
||||
// WARNING: The list may contain duplicates, and they are semantically relevant.
|
||||
func (m *manifestSchema2) LayerInfos() []types.BlobInfo {
|
||||
return manifestLayerInfosToBlobInfos(m.m.LayerInfos())
|
||||
}
|
||||
|
||||
// EmbeddedDockerReferenceConflicts whether a Docker reference embedded in the manifest, if any, conflicts with destination ref.
|
||||
// It returns false if the manifest does not embed a Docker reference.
|
||||
// (This embedding unfortunately happens for Docker schema1, please do not add support for this in any new formats.)
|
||||
func (m *manifestSchema2) EmbeddedDockerReferenceConflicts(ref reference.Named) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Inspect returns various information for (skopeo inspect) parsed from the manifest and configuration.
|
||||
func (m *manifestSchema2) Inspect(ctx context.Context) (*types.ImageInspectInfo, error) {
|
||||
getter := func(info types.BlobInfo) ([]byte, error) {
|
||||
if info.Digest != m.ConfigInfo().Digest {
|
||||
// Shouldn't ever happen
|
||||
return nil, errors.New("asked for a different config blob")
|
||||
}
|
||||
config, err := m.ConfigBlob(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
return m.m.Inspect(getter)
|
||||
}
|
||||
|
||||
// UpdatedImageNeedsLayerDiffIDs returns true iff UpdatedImage(options) needs InformationOnly.LayerDiffIDs.
|
||||
// This is a horribly specific interface, but computing InformationOnly.LayerDiffIDs can be very expensive to compute
|
||||
// (most importantly it forces us to download the full layers even if they are already present at the destination).
|
||||
func (m *manifestSchema2) UpdatedImageNeedsLayerDiffIDs(options types.ManifestUpdateOptions) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// UpdatedImage returns a types.Image modified according to options.
|
||||
// This does not change the state of the original Image object.
|
||||
// The returned error will be a manifest.ManifestLayerCompressionIncompatibilityError
|
||||
// if the CompressionOperation and CompressionAlgorithm specified in one or more
|
||||
// options.LayerInfos items is anything other than gzip.
|
||||
func (m *manifestSchema2) UpdatedImage(ctx context.Context, options types.ManifestUpdateOptions) (types.Image, error) {
|
||||
copy := manifestSchema2{ // NOTE: This is not a deep copy, it still shares slices etc.
|
||||
src: m.src,
|
||||
configBlob: m.configBlob,
|
||||
m: manifest.Schema2Clone(m.m),
|
||||
}
|
||||
|
||||
converted, err := convertManifestIfRequiredWithUpdate(ctx, options, map[string]manifestConvertFn{
|
||||
manifest.DockerV2Schema1MediaType: copy.convertToManifestSchema1,
|
||||
manifest.DockerV2Schema1SignedMediaType: copy.convertToManifestSchema1,
|
||||
imgspecv1.MediaTypeImageManifest: copy.convertToManifestOCI1,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if converted != nil {
|
||||
return converted, nil
|
||||
}
|
||||
|
||||
// No conversion required, update manifest
|
||||
if options.LayerInfos != nil {
|
||||
if err := copy.m.UpdateLayerInfos(options.LayerInfos); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Ignore options.EmbeddedDockerReference: it may be set when converting from schema1 to schema2, but we really don't care.
|
||||
|
||||
return memoryImageFromManifest(©), nil
|
||||
}
|
||||
|
||||
func oci1DescriptorFromSchema2Descriptor(d manifest.Schema2Descriptor) imgspecv1.Descriptor {
|
||||
return imgspecv1.Descriptor{
|
||||
MediaType: d.MediaType,
|
||||
Size: d.Size,
|
||||
Digest: d.Digest,
|
||||
URLs: d.URLs,
|
||||
}
|
||||
}
|
||||
|
||||
// convertToManifestOCI1 returns a genericManifest implementation converted to imgspecv1.MediaTypeImageManifest.
|
||||
// It may use options.InformationOnly and also adjust *options to be appropriate for editing the returned
|
||||
// value.
|
||||
// This does not change the state of the original manifestSchema2 object.
|
||||
func (m *manifestSchema2) convertToManifestOCI1(ctx context.Context, _ *types.ManifestUpdateOptions) (genericManifest, error) {
|
||||
configOCI, err := m.OCIConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
configOCIBytes, err := json.Marshal(configOCI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config := imgspecv1.Descriptor{
|
||||
MediaType: imgspecv1.MediaTypeImageConfig,
|
||||
Size: int64(len(configOCIBytes)),
|
||||
Digest: digest.FromBytes(configOCIBytes),
|
||||
}
|
||||
|
||||
layers := make([]imgspecv1.Descriptor, len(m.m.LayersDescriptors))
|
||||
for idx := range layers {
|
||||
layers[idx] = oci1DescriptorFromSchema2Descriptor(m.m.LayersDescriptors[idx])
|
||||
switch m.m.LayersDescriptors[idx].MediaType {
|
||||
case manifest.DockerV2Schema2ForeignLayerMediaType:
|
||||
layers[idx].MediaType = imgspecv1.MediaTypeImageLayerNonDistributable
|
||||
case manifest.DockerV2Schema2ForeignLayerMediaTypeGzip:
|
||||
layers[idx].MediaType = imgspecv1.MediaTypeImageLayerNonDistributableGzip
|
||||
case manifest.DockerV2SchemaLayerMediaTypeUncompressed:
|
||||
layers[idx].MediaType = imgspecv1.MediaTypeImageLayer
|
||||
case manifest.DockerV2Schema2LayerMediaType:
|
||||
layers[idx].MediaType = imgspecv1.MediaTypeImageLayerGzip
|
||||
default:
|
||||
return nil, fmt.Errorf("Unknown media type during manifest conversion: %q", m.m.LayersDescriptors[idx].MediaType)
|
||||
}
|
||||
}
|
||||
|
||||
return manifestOCI1FromComponents(config, m.src, configOCIBytes, layers), nil
|
||||
}
|
||||
|
||||
// convertToManifestSchema1 returns a genericManifest implementation converted to manifest.DockerV2Schema1{Signed,}MediaType.
|
||||
// It may use options.InformationOnly and also adjust *options to be appropriate for editing the returned
|
||||
// value.
|
||||
// This does not change the state of the original manifestSchema2 object.
|
||||
//
|
||||
// Based on docker/distribution/manifest/schema1/config_builder.go
|
||||
func (m *manifestSchema2) convertToManifestSchema1(ctx context.Context, options *types.ManifestUpdateOptions) (genericManifest, error) {
|
||||
dest := options.InformationOnly.Destination
|
||||
|
||||
var convertedLayerUpdates []types.BlobInfo // Only used if options.LayerInfos != nil
|
||||
if options.LayerInfos != nil {
|
||||
if len(options.LayerInfos) != len(m.m.LayersDescriptors) {
|
||||
return nil, fmt.Errorf("Error converting image: layer edits for %d layers vs %d existing layers",
|
||||
len(options.LayerInfos), len(m.m.LayersDescriptors))
|
||||
}
|
||||
convertedLayerUpdates = []types.BlobInfo{}
|
||||
}
|
||||
|
||||
configBytes, err := m.ConfigBlob(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
imageConfig := &manifest.Schema2Image{}
|
||||
if err := json.Unmarshal(configBytes, imageConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Build fsLayers and History, discarding all configs. We will patch the top-level config in later.
|
||||
fsLayers := make([]manifest.Schema1FSLayers, len(imageConfig.History))
|
||||
history := make([]manifest.Schema1History, len(imageConfig.History))
|
||||
nonemptyLayerIndex := 0
|
||||
var parentV1ID string // Set in the loop
|
||||
v1ID := ""
|
||||
haveGzippedEmptyLayer := false
|
||||
if len(imageConfig.History) == 0 {
|
||||
// What would this even mean?! Anyhow, the rest of the code depends on fsLayers[0] and history[0] existing.
|
||||
return nil, errors.Errorf("Cannot convert an image with 0 history entries to %s", manifest.DockerV2Schema1SignedMediaType)
|
||||
}
|
||||
for v2Index, historyEntry := range imageConfig.History {
|
||||
parentV1ID = v1ID
|
||||
v1Index := len(imageConfig.History) - 1 - v2Index
|
||||
|
||||
var blobDigest digest.Digest
|
||||
if historyEntry.EmptyLayer {
|
||||
emptyLayerBlobInfo := types.BlobInfo{Digest: GzippedEmptyLayerDigest, Size: int64(len(GzippedEmptyLayer))}
|
||||
|
||||
if !haveGzippedEmptyLayer {
|
||||
logrus.Debugf("Uploading empty layer during conversion to schema 1")
|
||||
// Ideally we should update the relevant BlobInfoCache about this layer, but that would require passing it down here,
|
||||
// and anyway this blob is so small that it’s easier to just copy it than to worry about figuring out another location where to get it.
|
||||
info, err := dest.PutBlob(ctx, bytes.NewReader(GzippedEmptyLayer), emptyLayerBlobInfo, none.NoCache, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "uploading empty layer")
|
||||
}
|
||||
if info.Digest != emptyLayerBlobInfo.Digest {
|
||||
return nil, errors.Errorf("Internal error: Uploaded empty layer has digest %#v instead of %s", info.Digest, emptyLayerBlobInfo.Digest)
|
||||
}
|
||||
haveGzippedEmptyLayer = true
|
||||
}
|
||||
if options.LayerInfos != nil {
|
||||
convertedLayerUpdates = append(convertedLayerUpdates, emptyLayerBlobInfo)
|
||||
}
|
||||
blobDigest = emptyLayerBlobInfo.Digest
|
||||
} else {
|
||||
if nonemptyLayerIndex >= len(m.m.LayersDescriptors) {
|
||||
return nil, errors.Errorf("Invalid image configuration, needs more than the %d distributed layers", len(m.m.LayersDescriptors))
|
||||
}
|
||||
if options.LayerInfos != nil {
|
||||
convertedLayerUpdates = append(convertedLayerUpdates, options.LayerInfos[nonemptyLayerIndex])
|
||||
}
|
||||
blobDigest = m.m.LayersDescriptors[nonemptyLayerIndex].Digest
|
||||
nonemptyLayerIndex++
|
||||
}
|
||||
|
||||
// AFAICT pull ignores these ID values, at least nowadays, so we could use anything unique, including a simple counter. Use what Docker uses for cargo-cult consistency.
|
||||
v, err := v1IDFromBlobDigestAndComponents(blobDigest, parentV1ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v1ID = v
|
||||
|
||||
fakeImage := manifest.Schema1V1Compatibility{
|
||||
ID: v1ID,
|
||||
Parent: parentV1ID,
|
||||
Comment: historyEntry.Comment,
|
||||
Created: historyEntry.Created,
|
||||
Author: historyEntry.Author,
|
||||
ThrowAway: historyEntry.EmptyLayer,
|
||||
}
|
||||
fakeImage.ContainerConfig.Cmd = []string{historyEntry.CreatedBy}
|
||||
v1CompatibilityBytes, err := json.Marshal(&fakeImage)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("Internal error: Error creating v1compatibility for %#v", fakeImage)
|
||||
}
|
||||
|
||||
fsLayers[v1Index] = manifest.Schema1FSLayers{BlobSum: blobDigest}
|
||||
history[v1Index] = manifest.Schema1History{V1Compatibility: string(v1CompatibilityBytes)}
|
||||
// Note that parentV1ID of the top layer is preserved when exiting this loop
|
||||
}
|
||||
|
||||
// Now patch in real configuration for the top layer (v1Index == 0)
|
||||
v1ID, err = v1IDFromBlobDigestAndComponents(fsLayers[0].BlobSum, parentV1ID, string(configBytes)) // See above WRT v1ID value generation and cargo-cult consistency.
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v1Config, err := v1ConfigFromConfigJSON(configBytes, v1ID, parentV1ID, imageConfig.History[len(imageConfig.History)-1].EmptyLayer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
history[0].V1Compatibility = string(v1Config)
|
||||
|
||||
if options.LayerInfos != nil {
|
||||
options.LayerInfos = convertedLayerUpdates
|
||||
}
|
||||
m1, err := manifestSchema1FromComponents(dest.Reference().DockerReference(), fsLayers, history, imageConfig.Architecture)
|
||||
if err != nil {
|
||||
return nil, err // This should never happen, we should have created all the components correctly.
|
||||
}
|
||||
return m1, nil
|
||||
}
|
||||
|
||||
func v1IDFromBlobDigestAndComponents(blobDigest digest.Digest, others ...string) (string, error) {
|
||||
if err := blobDigest.Validate(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
parts := append([]string{blobDigest.Hex()}, others...)
|
||||
v1IDHash := sha256.Sum256([]byte(strings.Join(parts, " ")))
|
||||
return hex.EncodeToString(v1IDHash[:]), nil
|
||||
}
|
||||
|
||||
func v1ConfigFromConfigJSON(configJSON []byte, v1ID, parentV1ID string, throwaway bool) ([]byte, error) {
|
||||
// Preserve everything we don't specifically know about.
|
||||
// (This must be a *json.RawMessage, even though *[]byte is fairly redundant, because only *RawMessage implements json.Marshaler.)
|
||||
rawContents := map[string]*json.RawMessage{}
|
||||
if err := json.Unmarshal(configJSON, &rawContents); err != nil { // We have already unmarshaled it before, using a more detailed schema?!
|
||||
return nil, err
|
||||
}
|
||||
delete(rawContents, "rootfs")
|
||||
delete(rawContents, "history")
|
||||
|
||||
updates := map[string]interface{}{"id": v1ID}
|
||||
if parentV1ID != "" {
|
||||
updates["parent"] = parentV1ID
|
||||
}
|
||||
if throwaway {
|
||||
updates["throwaway"] = throwaway
|
||||
}
|
||||
for field, value := range updates {
|
||||
encoded, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rawContents[field] = (*json.RawMessage)(&encoded)
|
||||
}
|
||||
return json.Marshal(rawContents)
|
||||
}
|
||||
|
||||
// SupportsEncryption returns if encryption is supported for the manifest type
|
||||
func (m *manifestSchema2) SupportsEncryption(context.Context) bool {
|
||||
return false
|
||||
}
|
||||
const GzippedEmptyLayerDigest = image.GzippedEmptyLayerDigest
|
||||
|
73
vendor/github.com/containers/image/v5/image/sourced.go
generated
vendored
73
vendor/github.com/containers/image/v5/image/sourced.go
generated
vendored
@ -6,17 +6,10 @@ package image
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containers/image/v5/internal/image"
|
||||
"github.com/containers/image/v5/types"
|
||||
)
|
||||
|
||||
// imageCloser implements types.ImageCloser, perhaps allowing simple users
|
||||
// to use a single object without having keep a reference to a types.ImageSource
|
||||
// only to call types.ImageSource.Close().
|
||||
type imageCloser struct {
|
||||
types.Image
|
||||
src types.ImageSource
|
||||
}
|
||||
|
||||
// FromSource returns a types.ImageCloser implementation for the default instance of source.
|
||||
// If source is a manifest list, .Manifest() still returns the manifest list,
|
||||
// but other methods transparently return data from an appropriate image instance.
|
||||
@ -31,33 +24,7 @@ type imageCloser struct {
|
||||
// NOTE: If any kind of signature verification should happen, build an UnparsedImage from the value returned by NewImageSource,
|
||||
// verify that UnparsedImage, and convert it into a real Image via image.FromUnparsedImage instead of calling this function.
|
||||
func FromSource(ctx context.Context, sys *types.SystemContext, src types.ImageSource) (types.ImageCloser, error) {
|
||||
img, err := FromUnparsedImage(ctx, sys, UnparsedInstance(src, nil))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &imageCloser{
|
||||
Image: img,
|
||||
src: src,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ic *imageCloser) Close() error {
|
||||
return ic.src.Close()
|
||||
}
|
||||
|
||||
// sourcedImage is a general set of utilities for working with container images,
|
||||
// whatever is their underlying location (i.e. dockerImageSource-independent).
|
||||
// Note the existence of skopeo/docker.Image: some instances of a `types.Image`
|
||||
// may not be a `sourcedImage` directly. However, most users of `types.Image`
|
||||
// do not care, and those who care about `skopeo/docker.Image` know they do.
|
||||
type sourcedImage struct {
|
||||
*UnparsedImage
|
||||
manifestBlob []byte
|
||||
manifestMIMEType string
|
||||
// genericManifest contains data corresponding to manifestBlob.
|
||||
// NOTE: The manifest may have been modified in the process; DO NOT reserialize and store genericManifest
|
||||
// if you want to preserve the original manifest; use manifestBlob directly.
|
||||
genericManifest
|
||||
return image.FromSource(ctx, sys, src)
|
||||
}
|
||||
|
||||
// FromUnparsedImage returns a types.Image implementation for unparsed.
|
||||
@ -66,39 +33,5 @@ type sourcedImage struct {
|
||||
//
|
||||
// The Image must not be used after the underlying ImageSource is Close()d.
|
||||
func FromUnparsedImage(ctx context.Context, sys *types.SystemContext, unparsed *UnparsedImage) (types.Image, error) {
|
||||
// Note that the input parameter above is specifically *image.UnparsedImage, not types.UnparsedImage:
|
||||
// we want to be able to use unparsed.src. We could make that an explicit interface, but, well,
|
||||
// this is the only UnparsedImage implementation around, anyway.
|
||||
|
||||
// NOTE: It is essential for signature verification that all parsing done in this object happens on the same manifest which is returned by unparsed.Manifest().
|
||||
manifestBlob, manifestMIMEType, err := unparsed.Manifest(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parsedManifest, err := manifestInstanceFromBlob(ctx, sys, unparsed.src, manifestBlob, manifestMIMEType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &sourcedImage{
|
||||
UnparsedImage: unparsed,
|
||||
manifestBlob: manifestBlob,
|
||||
manifestMIMEType: manifestMIMEType,
|
||||
genericManifest: parsedManifest,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Size returns the size of the image as stored, if it's known, or -1 if it isn't.
|
||||
func (i *sourcedImage) Size() (int64, error) {
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
// Manifest overrides the UnparsedImage.Manifest to always use the fields which we have already fetched.
|
||||
func (i *sourcedImage) Manifest(ctx context.Context) ([]byte, string, error) {
|
||||
return i.manifestBlob, i.manifestMIMEType, nil
|
||||
}
|
||||
|
||||
func (i *sourcedImage) LayerInfosForCopy(ctx context.Context) ([]types.BlobInfo, error) {
|
||||
return i.UnparsedImage.src.LayerInfosForCopy(ctx, i.UnparsedImage.instanceDigest)
|
||||
return image.FromUnparsedImage(ctx, sys, unparsed)
|
||||
}
|
||||
|
82
vendor/github.com/containers/image/v5/image/unparsed.go
generated
vendored
82
vendor/github.com/containers/image/v5/image/unparsed.go
generated
vendored
@ -1,95 +1,19 @@
|
||||
package image
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/containers/image/v5/manifest"
|
||||
"github.com/containers/image/v5/internal/image"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// UnparsedImage implements types.UnparsedImage .
|
||||
// An UnparsedImage is a pair of (ImageSource, instance digest); it can represent either a manifest list or a single image instance.
|
||||
type UnparsedImage struct {
|
||||
src types.ImageSource
|
||||
instanceDigest *digest.Digest
|
||||
cachedManifest []byte // A private cache for Manifest(); nil if not yet known.
|
||||
// A private cache for Manifest(), may be the empty string if guessing failed.
|
||||
// Valid iff cachedManifest is not nil.
|
||||
cachedManifestMIMEType string
|
||||
cachedSignatures [][]byte // A private cache for Signatures(); nil if not yet known.
|
||||
}
|
||||
type UnparsedImage = image.UnparsedImage
|
||||
|
||||
// UnparsedInstance returns a types.UnparsedImage implementation for (source, instanceDigest).
|
||||
// If instanceDigest is not nil, it contains a digest of the specific manifest instance to retrieve (when the primary manifest is a manifest list).
|
||||
//
|
||||
// The UnparsedImage must not be used after the underlying ImageSource is Close()d.
|
||||
func UnparsedInstance(src types.ImageSource, instanceDigest *digest.Digest) *UnparsedImage {
|
||||
return &UnparsedImage{
|
||||
src: src,
|
||||
instanceDigest: instanceDigest,
|
||||
}
|
||||
}
|
||||
|
||||
// Reference returns the reference used to set up this source, _as specified by the user_
|
||||
// (not as the image itself, or its underlying storage, claims). This can be used e.g. to determine which public keys are trusted for this image.
|
||||
func (i *UnparsedImage) Reference() types.ImageReference {
|
||||
// Note that this does not depend on instanceDigest; e.g. all instances within a manifest list need to be signed with the manifest list identity.
|
||||
return i.src.Reference()
|
||||
}
|
||||
|
||||
// Manifest is like ImageSource.GetManifest, but the result is cached; it is OK to call this however often you need.
|
||||
func (i *UnparsedImage) Manifest(ctx context.Context) ([]byte, string, error) {
|
||||
if i.cachedManifest == nil {
|
||||
m, mt, err := i.src.GetManifest(ctx, i.instanceDigest)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
// ImageSource.GetManifest does not do digest verification, but we do;
|
||||
// this immediately protects also any user of types.Image.
|
||||
if digest, haveDigest := i.expectedManifestDigest(); haveDigest {
|
||||
matches, err := manifest.MatchesDigest(m, digest)
|
||||
if err != nil {
|
||||
return nil, "", errors.Wrap(err, "computing manifest digest")
|
||||
}
|
||||
if !matches {
|
||||
return nil, "", errors.Errorf("Manifest does not match provided manifest digest %s", digest)
|
||||
}
|
||||
}
|
||||
|
||||
i.cachedManifest = m
|
||||
i.cachedManifestMIMEType = mt
|
||||
}
|
||||
return i.cachedManifest, i.cachedManifestMIMEType, nil
|
||||
}
|
||||
|
||||
// expectedManifestDigest returns a the expected value of the manifest digest, and an indicator whether it is known.
|
||||
// The bool return value seems redundant with digest != ""; it is used explicitly
|
||||
// to refuse (unexpected) situations when the digest exists but is "".
|
||||
func (i *UnparsedImage) expectedManifestDigest() (digest.Digest, bool) {
|
||||
if i.instanceDigest != nil {
|
||||
return *i.instanceDigest, true
|
||||
}
|
||||
ref := i.Reference().DockerReference()
|
||||
if ref != nil {
|
||||
if canonical, ok := ref.(reference.Canonical); ok {
|
||||
return canonical.Digest(), true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Signatures is like ImageSource.GetSignatures, but the result is cached; it is OK to call this however often you need.
|
||||
func (i *UnparsedImage) Signatures(ctx context.Context) ([][]byte, error) {
|
||||
if i.cachedSignatures == nil {
|
||||
sigs, err := i.src.GetSignatures(ctx, i.instanceDigest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i.cachedSignatures = sigs
|
||||
}
|
||||
return i.cachedSignatures, nil
|
||||
return image.UnparsedInstance(src, instanceDigest)
|
||||
}
|
||||
|
@ -246,3 +246,12 @@ func (m *manifestSchema1) convertToManifestOCI1(ctx context.Context, options *ty
|
||||
func (m *manifestSchema1) SupportsEncryption(context.Context) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// CanChangeLayerCompression returns true if we can compress/decompress layers with mimeType in the current image
|
||||
// (and the code can handle that).
|
||||
// NOTE: Even if this returns true, the relevant format might not accept all compression algorithms; the set of accepted
|
||||
// algorithms depends not on the current format, but possibly on the target of a conversion (if UpdatedImage converts
|
||||
// to a different manifest format).
|
||||
func (m *manifestSchema1) CanChangeLayerCompression(mimeType string) bool {
|
||||
return true // There are no MIME types in the manifest, so we must assume a valid image.
|
||||
}
|
413
vendor/github.com/containers/image/v5/internal/image/docker_schema2.go
generated
vendored
Normal file
413
vendor/github.com/containers/image/v5/internal/image/docker_schema2.go
generated
vendored
Normal file
@ -0,0 +1,413 @@
|
||||
package image
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/containers/image/v5/internal/iolimits"
|
||||
"github.com/containers/image/v5/manifest"
|
||||
"github.com/containers/image/v5/pkg/blobinfocache/none"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/opencontainers/go-digest"
|
||||
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// GzippedEmptyLayer is a gzip-compressed version of an empty tar file (1024 NULL bytes)
|
||||
// This comes from github.com/docker/distribution/manifest/schema1/config_builder.go; there is
|
||||
// a non-zero embedded timestamp; we could zero that, but that would just waste storage space
|
||||
// in registries, so let’s use the same values.
|
||||
//
|
||||
// This is publicly visible as c/image/image.GzippedEmptyLayer.
|
||||
var GzippedEmptyLayer = []byte{
|
||||
31, 139, 8, 0, 0, 9, 110, 136, 0, 255, 98, 24, 5, 163, 96, 20, 140, 88,
|
||||
0, 8, 0, 0, 255, 255, 46, 175, 181, 239, 0, 4, 0, 0,
|
||||
}
|
||||
|
||||
// GzippedEmptyLayerDigest is a digest of GzippedEmptyLayer
|
||||
//
|
||||
// This is publicly visible as c/image/image.GzippedEmptyLayerDigest.
|
||||
const GzippedEmptyLayerDigest = digest.Digest("sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4")
|
||||
|
||||
type manifestSchema2 struct {
|
||||
src types.ImageSource // May be nil if configBlob is not nil
|
||||
configBlob []byte // If set, corresponds to contents of ConfigDescriptor.
|
||||
m *manifest.Schema2
|
||||
}
|
||||
|
||||
func manifestSchema2FromManifest(src types.ImageSource, manifestBlob []byte) (genericManifest, error) {
|
||||
m, err := manifest.Schema2FromManifest(manifestBlob)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &manifestSchema2{
|
||||
src: src,
|
||||
m: m,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// manifestSchema2FromComponents builds a new manifestSchema2 from the supplied data:
|
||||
func manifestSchema2FromComponents(config manifest.Schema2Descriptor, src types.ImageSource, configBlob []byte, layers []manifest.Schema2Descriptor) *manifestSchema2 {
|
||||
return &manifestSchema2{
|
||||
src: src,
|
||||
configBlob: configBlob,
|
||||
m: manifest.Schema2FromComponents(config, layers),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *manifestSchema2) serialize() ([]byte, error) {
|
||||
return m.m.Serialize()
|
||||
}
|
||||
|
||||
func (m *manifestSchema2) manifestMIMEType() string {
|
||||
return m.m.MediaType
|
||||
}
|
||||
|
||||
// ConfigInfo returns a complete BlobInfo for the separate config object, or a BlobInfo{Digest:""} if there isn't a separate object.
|
||||
// Note that the config object may not exist in the underlying storage in the return value of UpdatedImage! Use ConfigBlob() below.
|
||||
func (m *manifestSchema2) ConfigInfo() types.BlobInfo {
|
||||
return m.m.ConfigInfo()
|
||||
}
|
||||
|
||||
// OCIConfig returns the image configuration as per OCI v1 image-spec. Information about
|
||||
// layers in the resulting configuration isn't guaranteed to be returned to due how
|
||||
// old image manifests work (docker v2s1 especially).
|
||||
func (m *manifestSchema2) OCIConfig(ctx context.Context) (*imgspecv1.Image, error) {
|
||||
configBlob, err := m.ConfigBlob(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// docker v2s2 and OCI v1 are mostly compatible but v2s2 contains more fields
|
||||
// than OCI v1. This unmarshal makes sure we drop docker v2s2
|
||||
// fields that aren't needed in OCI v1.
|
||||
configOCI := &imgspecv1.Image{}
|
||||
if err := json.Unmarshal(configBlob, configOCI); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return configOCI, nil
|
||||
}
|
||||
|
||||
// ConfigBlob returns the blob described by ConfigInfo, iff ConfigInfo().Digest != ""; nil otherwise.
|
||||
// The result is cached; it is OK to call this however often you need.
|
||||
func (m *manifestSchema2) ConfigBlob(ctx context.Context) ([]byte, error) {
|
||||
if m.configBlob == nil {
|
||||
if m.src == nil {
|
||||
return nil, errors.Errorf("Internal error: neither src nor configBlob set in manifestSchema2")
|
||||
}
|
||||
stream, _, err := m.src.GetBlob(ctx, manifest.BlobInfoFromSchema2Descriptor(m.m.ConfigDescriptor), none.NoCache)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer stream.Close()
|
||||
blob, err := iolimits.ReadAtMost(stream, iolimits.MaxConfigBodySize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
computedDigest := digest.FromBytes(blob)
|
||||
if computedDigest != m.m.ConfigDescriptor.Digest {
|
||||
return nil, errors.Errorf("Download config.json digest %s does not match expected %s", computedDigest, m.m.ConfigDescriptor.Digest)
|
||||
}
|
||||
m.configBlob = blob
|
||||
}
|
||||
return m.configBlob, nil
|
||||
}
|
||||
|
||||
// LayerInfos returns a list of BlobInfos of layers referenced by this image, in order (the root layer first, and then successive layered layers).
|
||||
// The Digest field is guaranteed to be provided; Size may be -1.
|
||||
// WARNING: The list may contain duplicates, and they are semantically relevant.
|
||||
func (m *manifestSchema2) LayerInfos() []types.BlobInfo {
|
||||
return manifestLayerInfosToBlobInfos(m.m.LayerInfos())
|
||||
}
|
||||
|
||||
// EmbeddedDockerReferenceConflicts whether a Docker reference embedded in the manifest, if any, conflicts with destination ref.
|
||||
// It returns false if the manifest does not embed a Docker reference.
|
||||
// (This embedding unfortunately happens for Docker schema1, please do not add support for this in any new formats.)
|
||||
func (m *manifestSchema2) EmbeddedDockerReferenceConflicts(ref reference.Named) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Inspect returns various information for (skopeo inspect) parsed from the manifest and configuration.
|
||||
func (m *manifestSchema2) Inspect(ctx context.Context) (*types.ImageInspectInfo, error) {
|
||||
getter := func(info types.BlobInfo) ([]byte, error) {
|
||||
if info.Digest != m.ConfigInfo().Digest {
|
||||
// Shouldn't ever happen
|
||||
return nil, errors.New("asked for a different config blob")
|
||||
}
|
||||
config, err := m.ConfigBlob(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
return m.m.Inspect(getter)
|
||||
}
|
||||
|
||||
// UpdatedImageNeedsLayerDiffIDs returns true iff UpdatedImage(options) needs InformationOnly.LayerDiffIDs.
|
||||
// This is a horribly specific interface, but computing InformationOnly.LayerDiffIDs can be very expensive to compute
|
||||
// (most importantly it forces us to download the full layers even if they are already present at the destination).
|
||||
func (m *manifestSchema2) UpdatedImageNeedsLayerDiffIDs(options types.ManifestUpdateOptions) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// UpdatedImage returns a types.Image modified according to options.
|
||||
// This does not change the state of the original Image object.
|
||||
// The returned error will be a manifest.ManifestLayerCompressionIncompatibilityError
|
||||
// if the CompressionOperation and CompressionAlgorithm specified in one or more
|
||||
// options.LayerInfos items is anything other than gzip.
|
||||
func (m *manifestSchema2) UpdatedImage(ctx context.Context, options types.ManifestUpdateOptions) (types.Image, error) {
|
||||
copy := manifestSchema2{ // NOTE: This is not a deep copy, it still shares slices etc.
|
||||
src: m.src,
|
||||
configBlob: m.configBlob,
|
||||
m: manifest.Schema2Clone(m.m),
|
||||
}
|
||||
|
||||
converted, err := convertManifestIfRequiredWithUpdate(ctx, options, map[string]manifestConvertFn{
|
||||
manifest.DockerV2Schema1MediaType: copy.convertToManifestSchema1,
|
||||
manifest.DockerV2Schema1SignedMediaType: copy.convertToManifestSchema1,
|
||||
imgspecv1.MediaTypeImageManifest: copy.convertToManifestOCI1,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if converted != nil {
|
||||
return converted, nil
|
||||
}
|
||||
|
||||
// No conversion required, update manifest
|
||||
if options.LayerInfos != nil {
|
||||
if err := copy.m.UpdateLayerInfos(options.LayerInfos); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Ignore options.EmbeddedDockerReference: it may be set when converting from schema1 to schema2, but we really don't care.
|
||||
|
||||
return memoryImageFromManifest(©), nil
|
||||
}
|
||||
|
||||
func oci1DescriptorFromSchema2Descriptor(d manifest.Schema2Descriptor) imgspecv1.Descriptor {
|
||||
return imgspecv1.Descriptor{
|
||||
MediaType: d.MediaType,
|
||||
Size: d.Size,
|
||||
Digest: d.Digest,
|
||||
URLs: d.URLs,
|
||||
}
|
||||
}
|
||||
|
||||
// convertToManifestOCI1 returns a genericManifest implementation converted to imgspecv1.MediaTypeImageManifest.
|
||||
// It may use options.InformationOnly and also adjust *options to be appropriate for editing the returned
|
||||
// value.
|
||||
// This does not change the state of the original manifestSchema2 object.
|
||||
func (m *manifestSchema2) convertToManifestOCI1(ctx context.Context, _ *types.ManifestUpdateOptions) (genericManifest, error) {
|
||||
configOCI, err := m.OCIConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
configOCIBytes, err := json.Marshal(configOCI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config := imgspecv1.Descriptor{
|
||||
MediaType: imgspecv1.MediaTypeImageConfig,
|
||||
Size: int64(len(configOCIBytes)),
|
||||
Digest: digest.FromBytes(configOCIBytes),
|
||||
}
|
||||
|
||||
layers := make([]imgspecv1.Descriptor, len(m.m.LayersDescriptors))
|
||||
for idx := range layers {
|
||||
layers[idx] = oci1DescriptorFromSchema2Descriptor(m.m.LayersDescriptors[idx])
|
||||
switch m.m.LayersDescriptors[idx].MediaType {
|
||||
case manifest.DockerV2Schema2ForeignLayerMediaType:
|
||||
layers[idx].MediaType = imgspecv1.MediaTypeImageLayerNonDistributable
|
||||
case manifest.DockerV2Schema2ForeignLayerMediaTypeGzip:
|
||||
layers[idx].MediaType = imgspecv1.MediaTypeImageLayerNonDistributableGzip
|
||||
case manifest.DockerV2SchemaLayerMediaTypeUncompressed:
|
||||
layers[idx].MediaType = imgspecv1.MediaTypeImageLayer
|
||||
case manifest.DockerV2Schema2LayerMediaType:
|
||||
layers[idx].MediaType = imgspecv1.MediaTypeImageLayerGzip
|
||||
default:
|
||||
return nil, fmt.Errorf("Unknown media type during manifest conversion: %q", m.m.LayersDescriptors[idx].MediaType)
|
||||
}
|
||||
}
|
||||
|
||||
return manifestOCI1FromComponents(config, m.src, configOCIBytes, layers), nil
|
||||
}
|
||||
|
||||
// convertToManifestSchema1 returns a genericManifest implementation converted to manifest.DockerV2Schema1{Signed,}MediaType.
|
||||
// It may use options.InformationOnly and also adjust *options to be appropriate for editing the returned
|
||||
// value.
|
||||
// This does not change the state of the original manifestSchema2 object.
|
||||
//
|
||||
// Based on docker/distribution/manifest/schema1/config_builder.go
|
||||
func (m *manifestSchema2) convertToManifestSchema1(ctx context.Context, options *types.ManifestUpdateOptions) (genericManifest, error) {
|
||||
dest := options.InformationOnly.Destination
|
||||
|
||||
var convertedLayerUpdates []types.BlobInfo // Only used if options.LayerInfos != nil
|
||||
if options.LayerInfos != nil {
|
||||
if len(options.LayerInfos) != len(m.m.LayersDescriptors) {
|
||||
return nil, fmt.Errorf("Error converting image: layer edits for %d layers vs %d existing layers",
|
||||
len(options.LayerInfos), len(m.m.LayersDescriptors))
|
||||
}
|
||||
convertedLayerUpdates = []types.BlobInfo{}
|
||||
}
|
||||
|
||||
configBytes, err := m.ConfigBlob(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
imageConfig := &manifest.Schema2Image{}
|
||||
if err := json.Unmarshal(configBytes, imageConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Build fsLayers and History, discarding all configs. We will patch the top-level config in later.
|
||||
fsLayers := make([]manifest.Schema1FSLayers, len(imageConfig.History))
|
||||
history := make([]manifest.Schema1History, len(imageConfig.History))
|
||||
nonemptyLayerIndex := 0
|
||||
var parentV1ID string // Set in the loop
|
||||
v1ID := ""
|
||||
haveGzippedEmptyLayer := false
|
||||
if len(imageConfig.History) == 0 {
|
||||
// What would this even mean?! Anyhow, the rest of the code depends on fsLayers[0] and history[0] existing.
|
||||
return nil, errors.Errorf("Cannot convert an image with 0 history entries to %s", manifest.DockerV2Schema1SignedMediaType)
|
||||
}
|
||||
for v2Index, historyEntry := range imageConfig.History {
|
||||
parentV1ID = v1ID
|
||||
v1Index := len(imageConfig.History) - 1 - v2Index
|
||||
|
||||
var blobDigest digest.Digest
|
||||
if historyEntry.EmptyLayer {
|
||||
emptyLayerBlobInfo := types.BlobInfo{Digest: GzippedEmptyLayerDigest, Size: int64(len(GzippedEmptyLayer))}
|
||||
|
||||
if !haveGzippedEmptyLayer {
|
||||
logrus.Debugf("Uploading empty layer during conversion to schema 1")
|
||||
// Ideally we should update the relevant BlobInfoCache about this layer, but that would require passing it down here,
|
||||
// and anyway this blob is so small that it’s easier to just copy it than to worry about figuring out another location where to get it.
|
||||
info, err := dest.PutBlob(ctx, bytes.NewReader(GzippedEmptyLayer), emptyLayerBlobInfo, none.NoCache, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "uploading empty layer")
|
||||
}
|
||||
if info.Digest != emptyLayerBlobInfo.Digest {
|
||||
return nil, errors.Errorf("Internal error: Uploaded empty layer has digest %#v instead of %s", info.Digest, emptyLayerBlobInfo.Digest)
|
||||
}
|
||||
haveGzippedEmptyLayer = true
|
||||
}
|
||||
if options.LayerInfos != nil {
|
||||
convertedLayerUpdates = append(convertedLayerUpdates, emptyLayerBlobInfo)
|
||||
}
|
||||
blobDigest = emptyLayerBlobInfo.Digest
|
||||
} else {
|
||||
if nonemptyLayerIndex >= len(m.m.LayersDescriptors) {
|
||||
return nil, errors.Errorf("Invalid image configuration, needs more than the %d distributed layers", len(m.m.LayersDescriptors))
|
||||
}
|
||||
if options.LayerInfos != nil {
|
||||
convertedLayerUpdates = append(convertedLayerUpdates, options.LayerInfos[nonemptyLayerIndex])
|
||||
}
|
||||
blobDigest = m.m.LayersDescriptors[nonemptyLayerIndex].Digest
|
||||
nonemptyLayerIndex++
|
||||
}
|
||||
|
||||
// AFAICT pull ignores these ID values, at least nowadays, so we could use anything unique, including a simple counter. Use what Docker uses for cargo-cult consistency.
|
||||
v, err := v1IDFromBlobDigestAndComponents(blobDigest, parentV1ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v1ID = v
|
||||
|
||||
fakeImage := manifest.Schema1V1Compatibility{
|
||||
ID: v1ID,
|
||||
Parent: parentV1ID,
|
||||
Comment: historyEntry.Comment,
|
||||
Created: historyEntry.Created,
|
||||
Author: historyEntry.Author,
|
||||
ThrowAway: historyEntry.EmptyLayer,
|
||||
}
|
||||
fakeImage.ContainerConfig.Cmd = []string{historyEntry.CreatedBy}
|
||||
v1CompatibilityBytes, err := json.Marshal(&fakeImage)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("Internal error: Error creating v1compatibility for %#v", fakeImage)
|
||||
}
|
||||
|
||||
fsLayers[v1Index] = manifest.Schema1FSLayers{BlobSum: blobDigest}
|
||||
history[v1Index] = manifest.Schema1History{V1Compatibility: string(v1CompatibilityBytes)}
|
||||
// Note that parentV1ID of the top layer is preserved when exiting this loop
|
||||
}
|
||||
|
||||
// Now patch in real configuration for the top layer (v1Index == 0)
|
||||
v1ID, err = v1IDFromBlobDigestAndComponents(fsLayers[0].BlobSum, parentV1ID, string(configBytes)) // See above WRT v1ID value generation and cargo-cult consistency.
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v1Config, err := v1ConfigFromConfigJSON(configBytes, v1ID, parentV1ID, imageConfig.History[len(imageConfig.History)-1].EmptyLayer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
history[0].V1Compatibility = string(v1Config)
|
||||
|
||||
if options.LayerInfos != nil {
|
||||
options.LayerInfos = convertedLayerUpdates
|
||||
}
|
||||
m1, err := manifestSchema1FromComponents(dest.Reference().DockerReference(), fsLayers, history, imageConfig.Architecture)
|
||||
if err != nil {
|
||||
return nil, err // This should never happen, we should have created all the components correctly.
|
||||
}
|
||||
return m1, nil
|
||||
}
|
||||
|
||||
func v1IDFromBlobDigestAndComponents(blobDigest digest.Digest, others ...string) (string, error) {
|
||||
if err := blobDigest.Validate(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
parts := append([]string{blobDigest.Hex()}, others...)
|
||||
v1IDHash := sha256.Sum256([]byte(strings.Join(parts, " ")))
|
||||
return hex.EncodeToString(v1IDHash[:]), nil
|
||||
}
|
||||
|
||||
func v1ConfigFromConfigJSON(configJSON []byte, v1ID, parentV1ID string, throwaway bool) ([]byte, error) {
|
||||
// Preserve everything we don't specifically know about.
|
||||
// (This must be a *json.RawMessage, even though *[]byte is fairly redundant, because only *RawMessage implements json.Marshaler.)
|
||||
rawContents := map[string]*json.RawMessage{}
|
||||
if err := json.Unmarshal(configJSON, &rawContents); err != nil { // We have already unmarshaled it before, using a more detailed schema?!
|
||||
return nil, err
|
||||
}
|
||||
delete(rawContents, "rootfs")
|
||||
delete(rawContents, "history")
|
||||
|
||||
updates := map[string]interface{}{"id": v1ID}
|
||||
if parentV1ID != "" {
|
||||
updates["parent"] = parentV1ID
|
||||
}
|
||||
if throwaway {
|
||||
updates["throwaway"] = throwaway
|
||||
}
|
||||
for field, value := range updates {
|
||||
encoded, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rawContents[field] = (*json.RawMessage)(&encoded)
|
||||
}
|
||||
return json.Marshal(rawContents)
|
||||
}
|
||||
|
||||
// SupportsEncryption returns if encryption is supported for the manifest type
|
||||
func (m *manifestSchema2) SupportsEncryption(context.Context) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// CanChangeLayerCompression returns true if we can compress/decompress layers with mimeType in the current image
|
||||
// (and the code can handle that).
|
||||
// NOTE: Even if this returns true, the relevant format might not accept all compression algorithms; the set of accepted
|
||||
// algorithms depends not on the current format, but possibly on the target of a conversion (if UpdatedImage converts
|
||||
// to a different manifest format).
|
||||
func (m *manifestSchema2) CanChangeLayerCompression(mimeType string) bool {
|
||||
return m.m.CanChangeLayerCompression(mimeType)
|
||||
}
|
@ -12,9 +12,8 @@ import (
|
||||
)
|
||||
|
||||
// genericManifest is an interface for parsing, modifying image manifests and related data.
|
||||
// Note that the public methods are intended to be a subset of types.Image
|
||||
// so that embedding a genericManifest into structs works.
|
||||
// will support v1 one day...
|
||||
// The public methods are related to types.Image so that embedding a genericManifest implements most of it,
|
||||
// but there are also public methods that are only visible by packages that can import c/image/internal/image.
|
||||
type genericManifest interface {
|
||||
serialize() ([]byte, error)
|
||||
manifestMIMEType() string
|
||||
@ -51,6 +50,16 @@ type genericManifest interface {
|
||||
// the process of updating a manifest between different manifest types was to update then convert.
|
||||
// This resulted in some fields in the update being lost. This has been fixed by: https://github.com/containers/image/pull/836
|
||||
SupportsEncryption(ctx context.Context) bool
|
||||
|
||||
// The following methods are not a part of types.Image:
|
||||
// ===
|
||||
|
||||
// CanChangeLayerCompression returns true if we can compress/decompress layers with mimeType in the current image
|
||||
// (and the code can handle that).
|
||||
// NOTE: Even if this returns true, the relevant format might not accept all compression algorithms; the set of accepted
|
||||
// algorithms depends not on the current format, but possibly on the target of a conversion (if UpdatedImage converts
|
||||
// to a different manifest format).
|
||||
CanChangeLayerCompression(mimeType string) bool
|
||||
}
|
||||
|
||||
// manifestInstanceFromBlob returns a genericManifest implementation for (manblob, mt) in src.
|
@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/containers/image/v5/internal/iolimits"
|
||||
internalManifest "github.com/containers/image/v5/internal/manifest"
|
||||
"github.com/containers/image/v5/manifest"
|
||||
"github.com/containers/image/v5/pkg/blobinfocache/none"
|
||||
"github.com/containers/image/v5/types"
|
||||
@ -84,6 +85,10 @@ func (m *manifestOCI1) ConfigBlob(ctx context.Context) ([]byte, error) {
|
||||
// layers in the resulting configuration isn't guaranteed to be returned to due how
|
||||
// old image manifests work (docker v2s1 especially).
|
||||
func (m *manifestOCI1) OCIConfig(ctx context.Context) (*imgspecv1.Image, error) {
|
||||
if m.m.Config.MediaType != imgspecv1.MediaTypeImageConfig {
|
||||
return nil, internalManifest.NewNonImageArtifactError(m.m.Config.MediaType)
|
||||
}
|
||||
|
||||
cb, err := m.ConfigBlob(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -194,10 +199,15 @@ func (m *manifestOCI1) convertToManifestSchema2Generic(ctx context.Context, opti
|
||||
// value.
|
||||
// This does not change the state of the original manifestOCI1 object.
|
||||
func (m *manifestOCI1) convertToManifestSchema2(_ context.Context, _ *types.ManifestUpdateOptions) (*manifestSchema2, error) {
|
||||
if m.m.Config.MediaType != imgspecv1.MediaTypeImageConfig {
|
||||
return nil, internalManifest.NewNonImageArtifactError(m.m.Config.MediaType)
|
||||
}
|
||||
|
||||
// Create a copy of the descriptor.
|
||||
config := schema2DescriptorFromOCI1Descriptor(m.m.Config)
|
||||
|
||||
// The only difference between OCI and DockerSchema2 is the mediatypes. The
|
||||
// Above, we have already checked that this manifest refers to an image, not an OCI artifact,
|
||||
// so the only difference between OCI and DockerSchema2 is the mediatypes. The
|
||||
// media type of the manifest is handled by manifestSchema2FromComponents.
|
||||
config.MediaType = manifest.DockerV2Schema2ConfigMediaType
|
||||
|
||||
@ -233,7 +243,11 @@ func (m *manifestOCI1) convertToManifestSchema2(_ context.Context, _ *types.Mani
|
||||
// value.
|
||||
// This does not change the state of the original manifestOCI1 object.
|
||||
func (m *manifestOCI1) convertToManifestSchema1(ctx context.Context, options *types.ManifestUpdateOptions) (genericManifest, error) {
|
||||
// We can't directly convert to V1, but we can transitively convert via a V2 image
|
||||
if m.m.Config.MediaType != imgspecv1.MediaTypeImageConfig {
|
||||
return nil, internalManifest.NewNonImageArtifactError(m.m.Config.MediaType)
|
||||
}
|
||||
|
||||
// We can't directly convert images to V1, but we can transitively convert via a V2 image
|
||||
m2, err := m.convertToManifestSchema2(ctx, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -246,3 +260,12 @@ func (m *manifestOCI1) convertToManifestSchema1(ctx context.Context, options *ty
|
||||
func (m *manifestOCI1) SupportsEncryption(context.Context) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// CanChangeLayerCompression returns true if we can compress/decompress layers with mimeType in the current image
|
||||
// (and the code can handle that).
|
||||
// NOTE: Even if this returns true, the relevant format might not accept all compression algorithms; the set of accepted
|
||||
// algorithms depends not on the current format, but possibly on the target of a conversion (if UpdatedImage converts
|
||||
// to a different manifest format).
|
||||
func (m *manifestOCI1) CanChangeLayerCompression(mimeType string) bool {
|
||||
return m.m.CanChangeLayerCompression(mimeType)
|
||||
}
|
134
vendor/github.com/containers/image/v5/internal/image/sourced.go
generated
vendored
Normal file
134
vendor/github.com/containers/image/v5/internal/image/sourced.go
generated
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
// Package image consolidates knowledge about various container image formats
|
||||
// (as opposed to image storage mechanisms, which are handled by types.ImageSource)
|
||||
// and exposes all of them using an unified interface.
|
||||
package image
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containers/image/v5/types"
|
||||
)
|
||||
|
||||
// FromReference returns a types.ImageCloser implementation for the default instance reading from reference.
|
||||
// If reference poitns to a manifest list, .Manifest() still returns the manifest list,
|
||||
// but other methods transparently return data from an appropriate image instance.
|
||||
//
|
||||
// The caller must call .Close() on the returned ImageCloser.
|
||||
//
|
||||
// NOTE: If any kind of signature verification should happen, build an UnparsedImage from the value returned by NewImageSource,
|
||||
// verify that UnparsedImage, and convert it into a real Image via image.FromUnparsedImage instead of calling this function.
|
||||
func FromReference(ctx context.Context, sys *types.SystemContext, ref types.ImageReference) (types.ImageCloser, error) {
|
||||
src, err := ref.NewImageSource(ctx, sys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
img, err := FromSource(ctx, sys, src)
|
||||
if err != nil {
|
||||
src.Close()
|
||||
return nil, err
|
||||
}
|
||||
return img, nil
|
||||
}
|
||||
|
||||
// imageCloser implements types.ImageCloser, perhaps allowing simple users
|
||||
// to use a single object without having keep a reference to a types.ImageSource
|
||||
// only to call types.ImageSource.Close().
|
||||
type imageCloser struct {
|
||||
types.Image
|
||||
src types.ImageSource
|
||||
}
|
||||
|
||||
// FromSource returns a types.ImageCloser implementation for the default instance of source.
|
||||
// If source is a manifest list, .Manifest() still returns the manifest list,
|
||||
// but other methods transparently return data from an appropriate image instance.
|
||||
//
|
||||
// The caller must call .Close() on the returned ImageCloser.
|
||||
//
|
||||
// FromSource “takes ownership” of the input ImageSource and will call src.Close()
|
||||
// when the image is closed. (This does not prevent callers from using both the
|
||||
// Image and ImageSource objects simultaneously, but it means that they only need to
|
||||
// the Image.)
|
||||
//
|
||||
// NOTE: If any kind of signature verification should happen, build an UnparsedImage from the value returned by NewImageSource,
|
||||
// verify that UnparsedImage, and convert it into a real Image via image.FromUnparsedImage instead of calling this function.
|
||||
//
|
||||
// Most callers can use either FromUnparsedImage or FromReference instead.
|
||||
//
|
||||
// This is publicly visible as c/image/image.FromSource.
|
||||
func FromSource(ctx context.Context, sys *types.SystemContext, src types.ImageSource) (types.ImageCloser, error) {
|
||||
img, err := FromUnparsedImage(ctx, sys, UnparsedInstance(src, nil))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &imageCloser{
|
||||
Image: img,
|
||||
src: src,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ic *imageCloser) Close() error {
|
||||
return ic.src.Close()
|
||||
}
|
||||
|
||||
// SourcedImage is a general set of utilities for working with container images,
|
||||
// whatever is their underlying transport (i.e. ImageSource-independent).
|
||||
// Note the existence of docker.Image and image.memoryImage: various instances
|
||||
// of a types.Image may not be a SourcedImage directly.
|
||||
//
|
||||
// Most external users of `types.Image` do not care, and those who care about `docker.Image` know they do.
|
||||
//
|
||||
// Internal users may depend on methods available in SourcedImage but not (yet?) in types.Image.
|
||||
type SourcedImage struct {
|
||||
*UnparsedImage
|
||||
ManifestBlob []byte // The manifest of the relevant instance
|
||||
ManifestMIMEType string // MIME type of ManifestBlob
|
||||
// genericManifest contains data corresponding to manifestBlob.
|
||||
// NOTE: The manifest may have been modified in the process; DO NOT reserialize and store genericManifest
|
||||
// if you want to preserve the original manifest; use manifestBlob directly.
|
||||
genericManifest
|
||||
}
|
||||
|
||||
// FromUnparsedImage returns a types.Image implementation for unparsed.
|
||||
// If unparsed represents a manifest list, .Manifest() still returns the manifest list,
|
||||
// but other methods transparently return data from an appropriate single image.
|
||||
//
|
||||
// The Image must not be used after the underlying ImageSource is Close()d.
|
||||
//
|
||||
// This is publicly visible as c/image/image.FromUnparsedImage.
|
||||
func FromUnparsedImage(ctx context.Context, sys *types.SystemContext, unparsed *UnparsedImage) (*SourcedImage, error) {
|
||||
// Note that the input parameter above is specifically *image.UnparsedImage, not types.UnparsedImage:
|
||||
// we want to be able to use unparsed.src. We could make that an explicit interface, but, well,
|
||||
// this is the only UnparsedImage implementation around, anyway.
|
||||
|
||||
// NOTE: It is essential for signature verification that all parsing done in this object happens on the same manifest which is returned by unparsed.Manifest().
|
||||
manifestBlob, manifestMIMEType, err := unparsed.Manifest(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parsedManifest, err := manifestInstanceFromBlob(ctx, sys, unparsed.src, manifestBlob, manifestMIMEType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &SourcedImage{
|
||||
UnparsedImage: unparsed,
|
||||
ManifestBlob: manifestBlob,
|
||||
ManifestMIMEType: manifestMIMEType,
|
||||
genericManifest: parsedManifest,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Size returns the size of the image as stored, if it's known, or -1 if it isn't.
|
||||
func (i *SourcedImage) Size() (int64, error) {
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
// Manifest overrides the UnparsedImage.Manifest to always use the fields which we have already fetched.
|
||||
func (i *SourcedImage) Manifest(ctx context.Context) ([]byte, string, error) {
|
||||
return i.ManifestBlob, i.ManifestMIMEType, nil
|
||||
}
|
||||
|
||||
func (i *SourcedImage) LayerInfosForCopy(ctx context.Context) ([]types.BlobInfo, error) {
|
||||
return i.UnparsedImage.src.LayerInfosForCopy(ctx, i.UnparsedImage.instanceDigest)
|
||||
}
|
99
vendor/github.com/containers/image/v5/internal/image/unparsed.go
generated
vendored
Normal file
99
vendor/github.com/containers/image/v5/internal/image/unparsed.go
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
package image
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/containers/image/v5/manifest"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// UnparsedImage implements types.UnparsedImage .
|
||||
// An UnparsedImage is a pair of (ImageSource, instance digest); it can represent either a manifest list or a single image instance.
|
||||
//
|
||||
// This is publicly visible as c/image/image.UnparsedImage.
|
||||
type UnparsedImage struct {
|
||||
src types.ImageSource
|
||||
instanceDigest *digest.Digest
|
||||
cachedManifest []byte // A private cache for Manifest(); nil if not yet known.
|
||||
// A private cache for Manifest(), may be the empty string if guessing failed.
|
||||
// Valid iff cachedManifest is not nil.
|
||||
cachedManifestMIMEType string
|
||||
cachedSignatures [][]byte // A private cache for Signatures(); nil if not yet known.
|
||||
}
|
||||
|
||||
// UnparsedInstance returns a types.UnparsedImage implementation for (source, instanceDigest).
|
||||
// If instanceDigest is not nil, it contains a digest of the specific manifest instance to retrieve (when the primary manifest is a manifest list).
|
||||
//
|
||||
// The UnparsedImage must not be used after the underlying ImageSource is Close()d.
|
||||
//
|
||||
// This is publicly visible as c/image/image.UnparsedInstance.
|
||||
func UnparsedInstance(src types.ImageSource, instanceDigest *digest.Digest) *UnparsedImage {
|
||||
return &UnparsedImage{
|
||||
src: src,
|
||||
instanceDigest: instanceDigest,
|
||||
}
|
||||
}
|
||||
|
||||
// Reference returns the reference used to set up this source, _as specified by the user_
|
||||
// (not as the image itself, or its underlying storage, claims). This can be used e.g. to determine which public keys are trusted for this image.
|
||||
func (i *UnparsedImage) Reference() types.ImageReference {
|
||||
// Note that this does not depend on instanceDigest; e.g. all instances within a manifest list need to be signed with the manifest list identity.
|
||||
return i.src.Reference()
|
||||
}
|
||||
|
||||
// Manifest is like ImageSource.GetManifest, but the result is cached; it is OK to call this however often you need.
|
||||
func (i *UnparsedImage) Manifest(ctx context.Context) ([]byte, string, error) {
|
||||
if i.cachedManifest == nil {
|
||||
m, mt, err := i.src.GetManifest(ctx, i.instanceDigest)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
// ImageSource.GetManifest does not do digest verification, but we do;
|
||||
// this immediately protects also any user of types.Image.
|
||||
if digest, haveDigest := i.expectedManifestDigest(); haveDigest {
|
||||
matches, err := manifest.MatchesDigest(m, digest)
|
||||
if err != nil {
|
||||
return nil, "", errors.Wrap(err, "computing manifest digest")
|
||||
}
|
||||
if !matches {
|
||||
return nil, "", errors.Errorf("Manifest does not match provided manifest digest %s", digest)
|
||||
}
|
||||
}
|
||||
|
||||
i.cachedManifest = m
|
||||
i.cachedManifestMIMEType = mt
|
||||
}
|
||||
return i.cachedManifest, i.cachedManifestMIMEType, nil
|
||||
}
|
||||
|
||||
// expectedManifestDigest returns a the expected value of the manifest digest, and an indicator whether it is known.
|
||||
// The bool return value seems redundant with digest != ""; it is used explicitly
|
||||
// to refuse (unexpected) situations when the digest exists but is "".
|
||||
func (i *UnparsedImage) expectedManifestDigest() (digest.Digest, bool) {
|
||||
if i.instanceDigest != nil {
|
||||
return *i.instanceDigest, true
|
||||
}
|
||||
ref := i.Reference().DockerReference()
|
||||
if ref != nil {
|
||||
if canonical, ok := ref.(reference.Canonical); ok {
|
||||
return canonical.Digest(), true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Signatures is like ImageSource.GetSignatures, but the result is cached; it is OK to call this however often you need.
|
||||
func (i *UnparsedImage) Signatures(ctx context.Context) ([][]byte, error) {
|
||||
if i.cachedSignatures == nil {
|
||||
sigs, err := i.src.GetSignatures(ctx, i.instanceDigest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i.cachedSignatures = sigs
|
||||
}
|
||||
return i.cachedSignatures, nil
|
||||
}
|
32
vendor/github.com/containers/image/v5/internal/manifest/errors.go
generated
vendored
Normal file
32
vendor/github.com/containers/image/v5/internal/manifest/errors.go
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
package manifest
|
||||
|
||||
import "fmt"
|
||||
|
||||
// NonImageArtifactError (detected via errors.As) is used when asking for an image-specific operation
|
||||
// on an object which is not a “container image” in the standard sense (e.g. an OCI artifact)
|
||||
//
|
||||
// This is publicly visible as c/image/manifest.NonImageArtifactError (but we don’t provide a public constructor)
|
||||
type NonImageArtifactError struct {
|
||||
// Callers should not be blindly calling image-specific operations and only checking MIME types
|
||||
// on failure; if they care about the artifact type, they should check before using it.
|
||||
// If they blindly assume an image, they don’t really need this value; just a type check
|
||||
// is sufficient for basic "we can only pull images" UI.
|
||||
//
|
||||
// Also, there are fairly widespread “artifacts” which nevertheless use imgspecv1.MediaTypeImageConfig,
|
||||
// e.g. https://github.com/sigstore/cosign/blob/main/specs/SIGNATURE_SPEC.md , which could cause the callers
|
||||
// to complain about a non-image artifact with the correct MIME type; we should probably add some other kind of
|
||||
// type discrimination, _and_ somehow make it available in the API, if we expect API callers to make decisions
|
||||
// based on that kind of data.
|
||||
//
|
||||
// So, let’s not expose this until a specific need is identified.
|
||||
mimeType string
|
||||
}
|
||||
|
||||
// NewNonImageArtifactError returns a NonImageArtifactError about an artifact with mimeType.
|
||||
func NewNonImageArtifactError(mimeType string) error {
|
||||
return NonImageArtifactError{mimeType: mimeType}
|
||||
}
|
||||
|
||||
func (e NonImageArtifactError) Error() string {
|
||||
return fmt.Sprintf("unsupported image-specific operation on artifact with type %q", e.mimeType)
|
||||
}
|
63
vendor/github.com/containers/image/v5/manifest/common.go
generated
vendored
63
vendor/github.com/containers/image/v5/manifest/common.go
generated
vendored
@ -118,6 +118,18 @@ type compressionMIMETypeSet map[string]string
|
||||
const mtsUncompressed = "" // A key in compressionMIMETypeSet for the uncompressed variant
|
||||
const mtsUnsupportedMIMEType = "" // A value in compressionMIMETypeSet that means “recognized but unsupported”
|
||||
|
||||
// findCompressionMIMETypeSet returns a pointer to a compressionMIMETypeSet in variantTable that contains a value of mimeType, or nil if not found
|
||||
func findCompressionMIMETypeSet(variantTable []compressionMIMETypeSet, mimeType string) compressionMIMETypeSet {
|
||||
for _, variants := range variantTable {
|
||||
for _, mt := range variants {
|
||||
if mt == mimeType {
|
||||
return variants
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// compressionVariantMIMEType returns a variant of mimeType for the specified algorithm (which may be nil
|
||||
// to mean "no compression"), based on variantTable.
|
||||
// The returned error will be a ManifestLayerCompressionIncompatibilityError if mimeType has variants
|
||||
@ -130,29 +142,26 @@ func compressionVariantMIMEType(variantTable []compressionMIMETypeSet, mimeType
|
||||
if mimeType == mtsUnsupportedMIMEType { // Prevent matching against the {algo:mtsUnsupportedMIMEType} entries
|
||||
return "", fmt.Errorf("cannot update unknown MIME type")
|
||||
}
|
||||
for _, variants := range variantTable {
|
||||
for _, mt := range variants {
|
||||
if mt == mimeType { // Found the variant
|
||||
name := mtsUncompressed
|
||||
if algorithm != nil {
|
||||
name = algorithm.InternalUnstableUndocumentedMIMEQuestionMark()
|
||||
}
|
||||
if res, ok := variants[name]; ok {
|
||||
if res != mtsUnsupportedMIMEType {
|
||||
return res, nil
|
||||
}
|
||||
if name != mtsUncompressed {
|
||||
return "", ManifestLayerCompressionIncompatibilityError{fmt.Sprintf("%s compression is not supported for type %q", name, mt)}
|
||||
}
|
||||
return "", ManifestLayerCompressionIncompatibilityError{fmt.Sprintf("uncompressed variant is not supported for type %q", mt)}
|
||||
}
|
||||
if name != mtsUncompressed {
|
||||
return "", ManifestLayerCompressionIncompatibilityError{fmt.Sprintf("unknown compressed with algorithm %s variant for type %s", name, mt)}
|
||||
}
|
||||
// We can't very well say “the idea of no compression is unknown”
|
||||
return "", ManifestLayerCompressionIncompatibilityError{fmt.Sprintf("uncompressed variant is not supported for type %q", mt)}
|
||||
}
|
||||
variants := findCompressionMIMETypeSet(variantTable, mimeType)
|
||||
if variants != nil {
|
||||
name := mtsUncompressed
|
||||
if algorithm != nil {
|
||||
name = algorithm.InternalUnstableUndocumentedMIMEQuestionMark()
|
||||
}
|
||||
if res, ok := variants[name]; ok {
|
||||
if res != mtsUnsupportedMIMEType {
|
||||
return res, nil
|
||||
}
|
||||
if name != mtsUncompressed {
|
||||
return "", ManifestLayerCompressionIncompatibilityError{fmt.Sprintf("%s compression is not supported for type %q", name, mimeType)}
|
||||
}
|
||||
return "", ManifestLayerCompressionIncompatibilityError{fmt.Sprintf("uncompressed variant is not supported for type %q", mimeType)}
|
||||
}
|
||||
if name != mtsUncompressed {
|
||||
return "", ManifestLayerCompressionIncompatibilityError{fmt.Sprintf("unknown compressed with algorithm %s variant for type %s", name, mimeType)}
|
||||
}
|
||||
// We can't very well say “the idea of no compression is unknown”
|
||||
return "", ManifestLayerCompressionIncompatibilityError{fmt.Sprintf("uncompressed variant is not supported for type %q", mimeType)}
|
||||
}
|
||||
if algorithm != nil {
|
||||
return "", fmt.Errorf("unsupported MIME type for compression: %s", mimeType)
|
||||
@ -209,3 +218,13 @@ type ManifestLayerCompressionIncompatibilityError struct {
|
||||
func (m ManifestLayerCompressionIncompatibilityError) Error() string {
|
||||
return m.text
|
||||
}
|
||||
|
||||
// compressionVariantsRecognizeMIMEType returns true if variantTable contains data about compressing/decompressing layers with mimeType
|
||||
// Note that the caller still needs to worry about a specific algorithm not being supported.
|
||||
func compressionVariantsRecognizeMIMEType(variantTable []compressionMIMETypeSet, mimeType string) bool {
|
||||
if mimeType == mtsUnsupportedMIMEType { // Prevent matching against the {algo:mtsUnsupportedMIMEType} entries
|
||||
return false
|
||||
}
|
||||
variants := findCompressionMIMETypeSet(variantTable, mimeType)
|
||||
return variants != nil // Alternatively, this could be len(variants) > 1, but really the caller should ask about a specific algorithm.
|
||||
}
|
||||
|
8
vendor/github.com/containers/image/v5/manifest/docker_schema2.go
generated
vendored
8
vendor/github.com/containers/image/v5/manifest/docker_schema2.go
generated
vendored
@ -295,3 +295,11 @@ func (m *Schema2) ImageID([]digest.Digest) (string, error) {
|
||||
}
|
||||
return m.ConfigDescriptor.Digest.Hex(), nil
|
||||
}
|
||||
|
||||
// CanChangeLayerCompression returns true if we can compress/decompress layers with mimeType in the current image
|
||||
// (and the code can handle that).
|
||||
// NOTE: Even if this returns true, the relevant format might not accept all compression algorithms; the set of accepted
|
||||
// algorithms depends not on the current format, but possibly on the target of a conversion.
|
||||
func (m *Schema2) CanChangeLayerCompression(mimeType string) bool {
|
||||
return compressionVariantsRecognizeMIMEType(schema2CompressionMIMETypeSets, mimeType)
|
||||
}
|
||||
|
5
vendor/github.com/containers/image/v5/manifest/manifest.go
generated
vendored
5
vendor/github.com/containers/image/v5/manifest/manifest.go
generated
vendored
@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
internalManifest "github.com/containers/image/v5/internal/manifest"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/containers/libtrust"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
@ -34,6 +35,10 @@ const (
|
||||
DockerV2Schema2ForeignLayerMediaTypeGzip = "application/vnd.docker.image.rootfs.foreign.diff.tar.gzip"
|
||||
)
|
||||
|
||||
// NonImageArtifactError (detected via errors.As) is used when asking for an image-specific operation
|
||||
// on an object which is not a “container image” in the standard sense (e.g. an OCI artifact)
|
||||
type NonImageArtifactError = internalManifest.NonImageArtifactError
|
||||
|
||||
// SupportedSchema2MediaType checks if the specified string is a supported Docker v2s2 media type.
|
||||
func SupportedSchema2MediaType(m string) error {
|
||||
switch m {
|
||||
|
94
vendor/github.com/containers/image/v5/manifest/oci.go
generated
vendored
94
vendor/github.com/containers/image/v5/manifest/oci.go
generated
vendored
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
internalManifest "github.com/containers/image/v5/internal/manifest"
|
||||
compressiontypes "github.com/containers/image/v5/pkg/compression/types"
|
||||
"github.com/containers/image/v5/types"
|
||||
ociencspec "github.com/containers/ocicrypt/spec"
|
||||
@ -115,6 +116,12 @@ var oci1CompressionMIMETypeSets = []compressionMIMETypeSet{
|
||||
// UpdateLayerInfos replaces the original layers with the specified BlobInfos (size+digest+urls+mediatype), in order (the root layer first, and then successive layered layers)
|
||||
// The returned error will be a manifest.ManifestLayerCompressionIncompatibilityError if any of the layerInfos includes a combination of CompressionOperation and
|
||||
// CompressionAlgorithm that isn't supported by OCI.
|
||||
//
|
||||
// It’s generally the caller’s responsibility to determine whether a particular edit is acceptable, rather than relying on
|
||||
// failures of this function, because the layer is typically created _before_ UpdateLayerInfos is called, because UpdateLayerInfos needs
|
||||
// to know the final digest). See OCI1.CanChangeLayerCompression for some help in determining this; other aspects like compression
|
||||
// algorithms that might not be supported by a format, or the limited set of MIME types accepted for encryption, are not currently
|
||||
// handled — that logic should eventually also be provided as OCI1 methods, not hard-coded in callers.
|
||||
func (m *OCI1) UpdateLayerInfos(layerInfos []types.BlobInfo) error {
|
||||
if len(m.Layers) != len(layerInfos) {
|
||||
return errors.Errorf("Error preparing updated manifest: layer count changed from %d to %d", len(m.Layers), len(layerInfos))
|
||||
@ -151,6 +158,33 @@ func (m *OCI1) UpdateLayerInfos(layerInfos []types.BlobInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// getEncryptedMediaType will return the mediatype to its encrypted counterpart and return
|
||||
// an error if the mediatype does not support encryption
|
||||
func getEncryptedMediaType(mediatype string) (string, error) {
|
||||
for _, s := range strings.Split(mediatype, "+")[1:] {
|
||||
if s == "encrypted" {
|
||||
return "", errors.Errorf("unsupportedmediatype: %v already encrypted", mediatype)
|
||||
}
|
||||
}
|
||||
unsuffixedMediatype := strings.Split(mediatype, "+")[0]
|
||||
switch unsuffixedMediatype {
|
||||
case DockerV2Schema2LayerMediaType, imgspecv1.MediaTypeImageLayer, imgspecv1.MediaTypeImageLayerNonDistributable:
|
||||
return mediatype + "+encrypted", nil
|
||||
}
|
||||
|
||||
return "", errors.Errorf("unsupported mediatype to encrypt: %v", mediatype)
|
||||
}
|
||||
|
||||
// getEncryptedMediaType will return the mediatype to its encrypted counterpart and return
|
||||
// an error if the mediatype does not support decryption
|
||||
func getDecryptedMediaType(mediatype string) (string, error) {
|
||||
if !strings.HasSuffix(mediatype, "+encrypted") {
|
||||
return "", errors.Errorf("unsupported mediatype to decrypt %v:", mediatype)
|
||||
}
|
||||
|
||||
return strings.TrimSuffix(mediatype, "+encrypted"), nil
|
||||
}
|
||||
|
||||
// Serialize returns the manifest in a blob format.
|
||||
// NOTE: Serialize() does not in general reproduce the original blob if this object was loaded from one, even if no modifications were made!
|
||||
func (m *OCI1) Serialize() ([]byte, error) {
|
||||
@ -159,6 +193,14 @@ func (m *OCI1) Serialize() ([]byte, error) {
|
||||
|
||||
// Inspect returns various information for (skopeo inspect) parsed from the manifest and configuration.
|
||||
func (m *OCI1) Inspect(configGetter func(types.BlobInfo) ([]byte, error)) (*types.ImageInspectInfo, error) {
|
||||
if m.Config.MediaType != imgspecv1.MediaTypeImageConfig {
|
||||
// We could return at least the layers, but that’s already available in a better format via types.Image.LayerInfos.
|
||||
// Most software calling this without human intervention is going to expect the values to be realistic and relevant,
|
||||
// and is probably better served by failing; we can always re-visit that later if we fail now, but
|
||||
// if we started returning some data for OCI artifacts now, we couldn’t start failing in this function later.
|
||||
return nil, internalManifest.NewNonImageArtifactError(m.Config.MediaType)
|
||||
}
|
||||
|
||||
config, err := configGetter(m.ConfigInfo())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -186,35 +228,39 @@ func (m *OCI1) Inspect(configGetter func(types.BlobInfo) ([]byte, error)) (*type
|
||||
|
||||
// ImageID computes an ID which can uniquely identify this image by its contents.
|
||||
func (m *OCI1) ImageID([]digest.Digest) (string, error) {
|
||||
// The way m.Config.Digest “uniquely identifies” an image is
|
||||
// by containing RootFS.DiffIDs, which identify the layers of the image.
|
||||
// For non-image artifacts, the we can’t expect the config to change
|
||||
// any time the other layers (semantically) change, so this approach of
|
||||
// distinguishing objects only by m.Config.Digest doesn’t work in general.
|
||||
//
|
||||
// Any caller of this method presumably wants to disambiguate the same
|
||||
// images with a different representation, but doesn’t want to disambiguate
|
||||
// representations (by using a manifest digest). So, submitting a non-image
|
||||
// artifact to such a caller indicates an expectation mismatch.
|
||||
// So, we just fail here instead of inventing some other ID value (e.g.
|
||||
// by combining the config and blob layer digests). That still
|
||||
// gives us the option to not fail, and return some value, in the future,
|
||||
// without committing to that approach now.
|
||||
// (The only known caller of ImageID is storage/storageImageDestination.computeID,
|
||||
// which can’t work with non-image artifacts.)
|
||||
if m.Config.MediaType != imgspecv1.MediaTypeImageConfig {
|
||||
return "", internalManifest.NewNonImageArtifactError(m.Config.MediaType)
|
||||
}
|
||||
|
||||
if err := m.Config.Digest.Validate(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return m.Config.Digest.Hex(), nil
|
||||
}
|
||||
|
||||
// getEncryptedMediaType will return the mediatype to its encrypted counterpart and return
|
||||
// an error if the mediatype does not support encryption
|
||||
func getEncryptedMediaType(mediatype string) (string, error) {
|
||||
for _, s := range strings.Split(mediatype, "+")[1:] {
|
||||
if s == "encrypted" {
|
||||
return "", errors.Errorf("unsupportedmediatype: %v already encrypted", mediatype)
|
||||
}
|
||||
// CanChangeLayerCompression returns true if we can compress/decompress layers with mimeType in the current image
|
||||
// (and the code can handle that).
|
||||
// NOTE: Even if this returns true, the relevant format might not accept all compression algorithms; the set of accepted
|
||||
// algorithms depends not on the current format, but possibly on the target of a conversion.
|
||||
func (m *OCI1) CanChangeLayerCompression(mimeType string) bool {
|
||||
if m.Config.MediaType != imgspecv1.MediaTypeImageConfig {
|
||||
return false
|
||||
}
|
||||
unsuffixedMediatype := strings.Split(mediatype, "+")[0]
|
||||
switch unsuffixedMediatype {
|
||||
case DockerV2Schema2LayerMediaType, imgspecv1.MediaTypeImageLayer, imgspecv1.MediaTypeImageLayerNonDistributable:
|
||||
return mediatype + "+encrypted", nil
|
||||
}
|
||||
|
||||
return "", errors.Errorf("unsupported mediatype to encrypt: %v", mediatype)
|
||||
}
|
||||
|
||||
// getEncryptedMediaType will return the mediatype to its encrypted counterpart and return
|
||||
// an error if the mediatype does not support decryption
|
||||
func getDecryptedMediaType(mediatype string) (string, error) {
|
||||
if !strings.HasSuffix(mediatype, "+encrypted") {
|
||||
return "", errors.Errorf("unsupported mediatype to decrypt %v:", mediatype)
|
||||
}
|
||||
|
||||
return strings.TrimSuffix(mediatype, "+encrypted"), nil
|
||||
return compressionVariantsRecognizeMIMEType(oci1CompressionMIMETypeSets, mimeType)
|
||||
}
|
||||
|
8
vendor/github.com/containers/image/v5/oci/archive/oci_transport.go
generated
vendored
8
vendor/github.com/containers/image/v5/oci/archive/oci_transport.go
generated
vendored
@ -8,7 +8,7 @@ import (
|
||||
|
||||
"github.com/containers/image/v5/directory/explicitfilepath"
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/containers/image/v5/image"
|
||||
"github.com/containers/image/v5/internal/image"
|
||||
"github.com/containers/image/v5/internal/tmpdir"
|
||||
"github.com/containers/image/v5/oci/internal"
|
||||
ocilayout "github.com/containers/image/v5/oci/layout"
|
||||
@ -122,11 +122,7 @@ func (ref ociArchiveReference) PolicyConfigurationNamespaces() []string {
|
||||
// verify that UnparsedImage, and convert it into a real Image via image.FromUnparsedImage.
|
||||
// WARNING: This may not do the right thing for a manifest list, see image.FromSource for details.
|
||||
func (ref ociArchiveReference) NewImage(ctx context.Context, sys *types.SystemContext) (types.ImageCloser, error) {
|
||||
src, err := newImageSource(ctx, sys, ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return image.FromSource(ctx, sys, src)
|
||||
return image.FromReference(ctx, sys, ref)
|
||||
}
|
||||
|
||||
// NewImageSource returns a types.ImageSource for this reference.
|
||||
|
8
vendor/github.com/containers/image/v5/oci/layout/oci_transport.go
generated
vendored
8
vendor/github.com/containers/image/v5/oci/layout/oci_transport.go
generated
vendored
@ -10,7 +10,7 @@ import (
|
||||
|
||||
"github.com/containers/image/v5/directory/explicitfilepath"
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/containers/image/v5/image"
|
||||
"github.com/containers/image/v5/internal/image"
|
||||
"github.com/containers/image/v5/oci/internal"
|
||||
"github.com/containers/image/v5/transports"
|
||||
"github.com/containers/image/v5/types"
|
||||
@ -154,11 +154,7 @@ func (ref ociReference) PolicyConfigurationNamespaces() []string {
|
||||
// verify that UnparsedImage, and convert it into a real Image via image.FromUnparsedImage.
|
||||
// WARNING: This may not do the right thing for a manifest list, see image.FromSource for details.
|
||||
func (ref ociReference) NewImage(ctx context.Context, sys *types.SystemContext) (types.ImageCloser, error) {
|
||||
src, err := newImageSource(sys, ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return image.FromSource(ctx, sys, src)
|
||||
return image.FromReference(ctx, sys, ref)
|
||||
}
|
||||
|
||||
// getIndex returns a pointer to the index references by this ociReference. If an error occurs opening an index nil is returned together
|
||||
|
8
vendor/github.com/containers/image/v5/openshift/openshift_transport.go
generated
vendored
8
vendor/github.com/containers/image/v5/openshift/openshift_transport.go
generated
vendored
@ -8,7 +8,7 @@ import (
|
||||
|
||||
"github.com/containers/image/v5/docker/policyconfiguration"
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
genericImage "github.com/containers/image/v5/image"
|
||||
genericImage "github.com/containers/image/v5/internal/image"
|
||||
"github.com/containers/image/v5/transports"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/pkg/errors"
|
||||
@ -132,11 +132,7 @@ func (ref openshiftReference) PolicyConfigurationNamespaces() []string {
|
||||
// verify that UnparsedImage, and convert it into a real Image via image.FromUnparsedImage.
|
||||
// WARNING: This may not do the right thing for a manifest list, see image.FromSource for details.
|
||||
func (ref openshiftReference) NewImage(ctx context.Context, sys *types.SystemContext) (types.ImageCloser, error) {
|
||||
src, err := newImageSource(sys, ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return genericImage.FromSource(ctx, sys, src)
|
||||
return genericImage.FromReference(ctx, sys, ref)
|
||||
}
|
||||
|
||||
// NewImageSource returns a types.ImageSource for this reference.
|
||||
|
14
vendor/github.com/containers/image/v5/ostree/ostree_transport.go
generated
vendored
14
vendor/github.com/containers/image/v5/ostree/ostree_transport.go
generated
vendored
@ -14,7 +14,7 @@ import (
|
||||
|
||||
"github.com/containers/image/v5/directory/explicitfilepath"
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/containers/image/v5/image"
|
||||
"github.com/containers/image/v5/internal/image"
|
||||
"github.com/containers/image/v5/transports"
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/pkg/errors"
|
||||
@ -184,17 +184,7 @@ func (s *ostreeImageCloser) Size() (int64, error) {
|
||||
// NOTE: If any kind of signature verification should happen, build an UnparsedImage from the value returned by NewImageSource,
|
||||
// verify that UnparsedImage, and convert it into a real Image via image.FromUnparsedImage.
|
||||
func (ref ostreeReference) NewImage(ctx context.Context, sys *types.SystemContext) (types.ImageCloser, error) {
|
||||
var tmpDir string
|
||||
if sys == nil || sys.OSTreeTmpDirPath == "" {
|
||||
tmpDir = os.TempDir()
|
||||
} else {
|
||||
tmpDir = sys.OSTreeTmpDirPath
|
||||
}
|
||||
src, err := newImageSource(tmpDir, ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return image.FromSource(ctx, sys, src)
|
||||
return image.FromReference(ctx, sys, ref)
|
||||
}
|
||||
|
||||
// NewImageSource returns a types.ImageSource for this reference.
|
||||
|
8
vendor/github.com/containers/image/v5/sif/transport.go
generated
vendored
8
vendor/github.com/containers/image/v5/sif/transport.go
generated
vendored
@ -9,7 +9,7 @@ import (
|
||||
|
||||
"github.com/containers/image/v5/directory/explicitfilepath"
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/containers/image/v5/image"
|
||||
"github.com/containers/image/v5/internal/image"
|
||||
"github.com/containers/image/v5/transports"
|
||||
"github.com/containers/image/v5/types"
|
||||
)
|
||||
@ -139,11 +139,7 @@ func (ref sifReference) PolicyConfigurationNamespaces() []string {
|
||||
// verify that UnparsedImage, and convert it into a real Image via image.FromUnparsedImage.
|
||||
// WARNING: This may not do the right thing for a manifest list, see image.FromSource for details.
|
||||
func (ref sifReference) NewImage(ctx context.Context, sys *types.SystemContext) (types.ImageCloser, error) {
|
||||
src, err := newImageSource(ctx, sys, ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return image.FromSource(ctx, sys, src)
|
||||
return image.FromReference(ctx, sys, ref)
|
||||
}
|
||||
|
||||
// NewImageSource returns a types.ImageSource for this reference.
|
||||
|
8
vendor/github.com/containers/image/v5/storage/storage_image.go
generated
vendored
8
vendor/github.com/containers/image/v5/storage/storage_image.go
generated
vendored
@ -16,7 +16,7 @@ import (
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/containers/image/v5/image"
|
||||
"github.com/containers/image/v5/internal/image"
|
||||
"github.com/containers/image/v5/internal/private"
|
||||
"github.com/containers/image/v5/internal/putblobdigest"
|
||||
"github.com/containers/image/v5/internal/tmpdir"
|
||||
@ -486,7 +486,7 @@ func (s *storageImageDestination) PutBlob(ctx context.Context, stream io.Reader,
|
||||
}
|
||||
|
||||
// putBlobToPendingFile implements ImageDestination.PutBlobWithOptions, storing stream into an on-disk file.
|
||||
// The caller must arrange the blob to be eventually commited using s.commitLayer().
|
||||
// The caller must arrange the blob to be eventually committed using s.commitLayer().
|
||||
func (s *storageImageDestination) putBlobToPendingFile(ctx context.Context, stream io.Reader, blobinfo types.BlobInfo, options *private.PutBlobOptions) (types.BlobInfo, error) {
|
||||
// Stores a layer or data blob in our temporary directory, checking that any information
|
||||
// in the blobinfo matches the incoming data.
|
||||
@ -641,7 +641,7 @@ func (s *storageImageDestination) TryReusingBlob(ctx context.Context, blobinfo t
|
||||
}
|
||||
|
||||
// tryReusingBlobAsPending implements TryReusingBlobWithOptions, filling s.blobDiffIDs and other metadata.
|
||||
// The caller must arrange the blob to be eventually commited using s.commitLayer().
|
||||
// The caller must arrange the blob to be eventually committed using s.commitLayer().
|
||||
func (s *storageImageDestination) tryReusingBlobAsPending(ctx context.Context, blobinfo types.BlobInfo, options *private.TryReusingBlobOptions) (bool, types.BlobInfo, error) {
|
||||
// lock the entire method as it executes fairly quickly
|
||||
s.lock.Lock()
|
||||
@ -941,7 +941,7 @@ func (s *storageImageDestination) commitLayer(ctx context.Context, blob manifest
|
||||
s.lock.Unlock()
|
||||
if ok {
|
||||
layer, err := al.PutAs(id, lastLayer, nil)
|
||||
if err != nil {
|
||||
if err != nil && errors.Cause(err) != storage.ErrDuplicateID {
|
||||
return errors.Wrapf(err, "failed to put layer from digest and labels")
|
||||
}
|
||||
lastLayer = layer.ID
|
||||
|
13
vendor/github.com/containers/image/v5/tarball/tarball_reference.go
generated
vendored
13
vendor/github.com/containers/image/v5/tarball/tarball_reference.go
generated
vendored
@ -7,7 +7,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/containers/image/v5/image"
|
||||
"github.com/containers/image/v5/internal/image"
|
||||
"github.com/containers/image/v5/types"
|
||||
|
||||
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
@ -67,16 +67,7 @@ func (r *tarballReference) PolicyConfigurationNamespaces() []string {
|
||||
// verify that UnparsedImage, and convert it into a real Image via image.FromUnparsedImage.
|
||||
// WARNING: This may not do the right thing for a manifest list, see image.FromSource for details.
|
||||
func (r *tarballReference) NewImage(ctx context.Context, sys *types.SystemContext) (types.ImageCloser, error) {
|
||||
src, err := r.NewImageSource(ctx, sys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
img, err := image.FromSource(ctx, sys, src)
|
||||
if err != nil {
|
||||
src.Close()
|
||||
return nil, err
|
||||
}
|
||||
return img, nil
|
||||
return image.FromReference(ctx, sys, r)
|
||||
}
|
||||
|
||||
func (r *tarballReference) DeleteImage(ctx context.Context, sys *types.SystemContext) error {
|
||||
|
32
vendor/github.com/imdario/mergo/README.md
generated
vendored
32
vendor/github.com/imdario/mergo/README.md
generated
vendored
@ -8,8 +8,7 @@
|
||||
[![Coverage Status][9]][10]
|
||||
[![Sourcegraph][11]][12]
|
||||
[![FOSSA Status][13]][14]
|
||||
|
||||
[![GoCenter Kudos][15]][16]
|
||||
[![Become my sponsor][15]][16]
|
||||
|
||||
[1]: https://travis-ci.org/imdario/mergo.png
|
||||
[2]: https://travis-ci.org/imdario/mergo
|
||||
@ -25,8 +24,8 @@
|
||||
[12]: https://sourcegraph.com/github.com/imdario/mergo?badge
|
||||
[13]: https://app.fossa.io/api/projects/git%2Bgithub.com%2Fimdario%2Fmergo.svg?type=shield
|
||||
[14]: https://app.fossa.io/projects/git%2Bgithub.com%2Fimdario%2Fmergo?ref=badge_shield
|
||||
[15]: https://search.gocenter.io/api/ui/badge/github.com%2Fimdario%2Fmergo
|
||||
[16]: https://search.gocenter.io/github.com/imdario/mergo
|
||||
[15]: https://img.shields.io/github/sponsors/imdario
|
||||
[16]: https://github.com/sponsors/imdario
|
||||
|
||||
A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements.
|
||||
|
||||
@ -36,11 +35,11 @@ Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the
|
||||
|
||||
## Status
|
||||
|
||||
It is ready for production use. [It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, etc](https://github.com/imdario/mergo#mergo-in-the-wild).
|
||||
It is ready for production use. [It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, Microsoft, etc](https://github.com/imdario/mergo#mergo-in-the-wild).
|
||||
|
||||
### Important note
|
||||
|
||||
Please keep in mind that a problematic PR broke [0.3.9](//github.com/imdario/mergo/releases/tag/0.3.9). I reverted it in [0.3.10](//github.com/imdario/mergo/releases/tag/0.3.10), and I consider it stable but not bug-free. Also, this version adds suppot for go modules.
|
||||
Please keep in mind that a problematic PR broke [0.3.9](//github.com/imdario/mergo/releases/tag/0.3.9). I reverted it in [0.3.10](//github.com/imdario/mergo/releases/tag/0.3.10), and I consider it stable but not bug-free. Also, this version adds support for go modules.
|
||||
|
||||
Keep in mind that in [0.3.2](//github.com/imdario/mergo/releases/tag/0.3.2), Mergo changed `Merge()`and `Map()` signatures to support [transformers](#transformers). I added an optional/variadic argument so that it won't break the existing code.
|
||||
|
||||
@ -51,12 +50,12 @@ If you were using Mergo before April 6th, 2015, please check your project works
|
||||
If Mergo is useful to you, consider buying me a coffee, a beer, or making a monthly donation to allow me to keep building great free software. :heart_eyes:
|
||||
|
||||
<a href='https://ko-fi.com/B0B58839' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://az743702.vo.msecnd.net/cdn/kofi1.png?v=0' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
|
||||
[](https://beerpay.io/imdario/mergo)
|
||||
[](https://beerpay.io/imdario/mergo)
|
||||
<a href="https://liberapay.com/dario/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a>
|
||||
<a href='https://github.com/sponsors/imdario' target='_blank'><img alt="Become my sponsor" src="https://img.shields.io/github/sponsors/imdario?style=for-the-badge" /></a>
|
||||
|
||||
### Mergo in the wild
|
||||
|
||||
- [cli/cli](https://github.com/cli/cli)
|
||||
- [moby/moby](https://github.com/moby/moby)
|
||||
- [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes)
|
||||
- [vmware/dispatch](https://github.com/vmware/dispatch)
|
||||
@ -98,6 +97,8 @@ If Mergo is useful to you, consider buying me a coffee, a beer, or making a mont
|
||||
- [jnuthong/item_search](https://github.com/jnuthong/item_search)
|
||||
- [bukalapak/snowboard](https://github.com/bukalapak/snowboard)
|
||||
- [containerssh/containerssh](https://github.com/containerssh/containerssh)
|
||||
- [goreleaser/goreleaser](https://github.com/goreleaser/goreleaser)
|
||||
- [tjpnz/structbot](https://github.com/tjpnz/structbot)
|
||||
|
||||
## Install
|
||||
|
||||
@ -168,7 +169,7 @@ func main() {
|
||||
|
||||
Note: if test are failing due missing package, please execute:
|
||||
|
||||
go get gopkg.in/yaml.v2
|
||||
go get gopkg.in/yaml.v3
|
||||
|
||||
### Transformers
|
||||
|
||||
@ -218,7 +219,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Contact me
|
||||
|
||||
If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): [@im_dario](https://twitter.com/im_dario)
|
||||
@ -227,18 +227,6 @@ If I can help you, you have an idea or you are using Mergo in your projects, don
|
||||
|
||||
Written by [Dario Castañé](http://dario.im).
|
||||
|
||||
## Top Contributors
|
||||
|
||||
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/0)
|
||||
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/1)
|
||||
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/2)
|
||||
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/3)
|
||||
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/4)
|
||||
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/5)
|
||||
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/6)
|
||||
[](https://sourcerer.io/fame/imdario/imdario/mergo/links/7)
|
||||
|
||||
|
||||
## License
|
||||
|
||||
[BSD 3-Clause](http://opensource.org/licenses/BSD-3-Clause) license, as [Go language](http://golang.org/LICENSE).
|
||||
|
2
vendor/github.com/imdario/mergo/merge.go
generated
vendored
2
vendor/github.com/imdario/mergo/merge.go
generated
vendored
@ -79,7 +79,7 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co
|
||||
visited[h] = &visit{addr, typ, seen}
|
||||
}
|
||||
|
||||
if config.Transformers != nil && !isEmptyValue(dst) {
|
||||
if config.Transformers != nil && !isReflectNil(dst) && dst.IsValid() {
|
||||
if fn := config.Transformers.Transformer(dst.Type()); fn != nil {
|
||||
err = fn(dst, src)
|
||||
return
|
||||
|
4
vendor/github.com/imdario/mergo/mergo.go
generated
vendored
4
vendor/github.com/imdario/mergo/mergo.go
generated
vendored
@ -17,7 +17,7 @@ import (
|
||||
var (
|
||||
ErrNilArguments = errors.New("src and dst must not be nil")
|
||||
ErrDifferentArgumentsTypes = errors.New("src and dst must be of same type")
|
||||
ErrNotSupported = errors.New("only structs and maps are supported")
|
||||
ErrNotSupported = errors.New("only structs, maps, and slices are supported")
|
||||
ErrExpectedMapAsDestination = errors.New("dst was expected to be a map")
|
||||
ErrExpectedStructAsDestination = errors.New("dst was expected to be a struct")
|
||||
ErrNonPointerAgument = errors.New("dst must be a pointer")
|
||||
@ -65,7 +65,7 @@ func resolveValues(dst, src interface{}) (vDst, vSrc reflect.Value, err error) {
|
||||
return
|
||||
}
|
||||
vDst = reflect.ValueOf(dst).Elem()
|
||||
if vDst.Kind() != reflect.Struct && vDst.Kind() != reflect.Map {
|
||||
if vDst.Kind() != reflect.Struct && vDst.Kind() != reflect.Map && vDst.Kind() != reflect.Slice {
|
||||
err = ErrNotSupported
|
||||
return
|
||||
}
|
||||
|
23
vendor/github.com/klauspost/compress/README.md
generated
vendored
23
vendor/github.com/klauspost/compress/README.md
generated
vendored
@ -17,6 +17,24 @@ This package provides various compression algorithms.
|
||||
|
||||
# changelog
|
||||
|
||||
* May 25, 2022 (v1.15.5)
|
||||
* s2: Add concurrent stream decompression https://github.com/klauspost/compress/pull/602
|
||||
* s2: Fix final emit oob read crash on amd64 https://github.com/klauspost/compress/pull/601
|
||||
* huff0: asm implementation of Decompress1X by @WojciechMula https://github.com/klauspost/compress/pull/596
|
||||
* zstd: Use 1 less goroutine for stream decoding https://github.com/klauspost/compress/pull/588
|
||||
* zstd: Copy literal in 16 byte blocks when possible https://github.com/klauspost/compress/pull/592
|
||||
* zstd: Speed up when WithDecoderLowmem(false) https://github.com/klauspost/compress/pull/599
|
||||
* zstd: faster next state update in BMI2 version of decode by @WojciechMula in https://github.com/klauspost/compress/pull/593
|
||||
* huff0: Do not check max size when reading table. https://github.com/klauspost/compress/pull/586
|
||||
* flate: Inplace hashing for level 7-9 by @klauspost in https://github.com/klauspost/compress/pull/590
|
||||
|
||||
|
||||
* May 11, 2022 (v1.15.4)
|
||||
* huff0: decompress directly into output by @WojciechMula in [#577](https://github.com/klauspost/compress/pull/577)
|
||||
* inflate: Keep dict on stack [#581](https://github.com/klauspost/compress/pull/581)
|
||||
* zstd: Faster decoding memcopy in asm [#583](https://github.com/klauspost/compress/pull/583)
|
||||
* zstd: Fix ignored crc [#580](https://github.com/klauspost/compress/pull/580)
|
||||
|
||||
* May 5, 2022 (v1.15.3)
|
||||
* zstd: Allow to ignore checksum checking by @WojciechMula [#572](https://github.com/klauspost/compress/pull/572)
|
||||
* s2: Fix incorrect seek for io.SeekEnd in [#575](https://github.com/klauspost/compress/pull/575)
|
||||
@ -77,6 +95,9 @@ While the release has been extensively tested, it is recommended to testing when
|
||||
* zstd: add arm64 xxhash assembly in [#464](https://github.com/klauspost/compress/pull/464)
|
||||
* Add garbled for binaries for s2 in [#445](https://github.com/klauspost/compress/pull/445)
|
||||
|
||||
<details>
|
||||
<summary>See changes to v1.13.x</summary>
|
||||
|
||||
* Aug 30, 2021 (v1.13.5)
|
||||
* gz/zlib/flate: Alias stdlib errors [#425](https://github.com/klauspost/compress/pull/425)
|
||||
* s2: Add block support to commandline tools [#413](https://github.com/klauspost/compress/pull/413)
|
||||
@ -105,6 +126,8 @@ While the release has been extensively tested, it is recommended to testing when
|
||||
* Added [gzhttp](https://github.com/klauspost/compress/tree/master/gzhttp#gzip-handler) which allows wrapping HTTP servers and clients with GZIP compressors.
|
||||
* zstd: Detect short invalid signatures [#382](https://github.com/klauspost/compress/pull/382)
|
||||
* zstd: Spawn decoder goroutine only if needed. [#380](https://github.com/klauspost/compress/pull/380)
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary>See changes to v1.12.x</summary>
|
||||
|
36
vendor/github.com/klauspost/compress/flate/deflate.go
generated
vendored
36
vendor/github.com/klauspost/compress/flate/deflate.go
generated
vendored
@ -84,24 +84,23 @@ type advancedState struct {
|
||||
length int
|
||||
offset int
|
||||
maxInsertIndex int
|
||||
chainHead int
|
||||
hashOffset int
|
||||
|
||||
// Input hash chains
|
||||
// hashHead[hashValue] contains the largest inputIndex with the specified hash value
|
||||
// If hashHead[hashValue] is within the current window, then
|
||||
// hashPrev[hashHead[hashValue] & windowMask] contains the previous index
|
||||
// with the same hash value.
|
||||
chainHead int
|
||||
hashHead [hashSize]uint32
|
||||
hashPrev [windowSize]uint32
|
||||
hashOffset int
|
||||
ii uint16 // position of last match, intended to overflow to reset.
|
||||
|
||||
// input window: unprocessed data is window[index:windowEnd]
|
||||
index int
|
||||
estBitsPerByte int
|
||||
hashMatch [maxMatchLength + minMatchLength]uint32
|
||||
|
||||
hash uint32
|
||||
ii uint16 // position of last match, intended to overflow to reset.
|
||||
// Input hash chains
|
||||
// hashHead[hashValue] contains the largest inputIndex with the specified hash value
|
||||
// If hashHead[hashValue] is within the current window, then
|
||||
// hashPrev[hashHead[hashValue] & windowMask] contains the previous index
|
||||
// with the same hash value.
|
||||
hashHead [hashSize]uint32
|
||||
hashPrev [windowSize]uint32
|
||||
}
|
||||
|
||||
type compressor struct {
|
||||
@ -259,7 +258,6 @@ func (d *compressor) fillWindow(b []byte) {
|
||||
// Set the head of the hash chain to us.
|
||||
s.hashHead[newH] = uint32(di + s.hashOffset)
|
||||
}
|
||||
s.hash = newH
|
||||
}
|
||||
// Update window information.
|
||||
d.windowEnd += n
|
||||
@ -403,7 +401,6 @@ func (d *compressor) initDeflate() {
|
||||
s.hashOffset = 1
|
||||
s.length = minMatchLength - 1
|
||||
s.offset = 0
|
||||
s.hash = 0
|
||||
s.chainHead = -1
|
||||
}
|
||||
|
||||
@ -432,9 +429,6 @@ func (d *compressor) deflateLazy() {
|
||||
}
|
||||
|
||||
s.maxInsertIndex = d.windowEnd - (minMatchLength - 1)
|
||||
if s.index < s.maxInsertIndex {
|
||||
s.hash = hash4(d.window[s.index:])
|
||||
}
|
||||
|
||||
for {
|
||||
if sanity && s.index > d.windowEnd {
|
||||
@ -466,11 +460,11 @@ func (d *compressor) deflateLazy() {
|
||||
}
|
||||
if s.index < s.maxInsertIndex {
|
||||
// Update the hash
|
||||
s.hash = hash4(d.window[s.index:])
|
||||
ch := s.hashHead[s.hash&hashMask]
|
||||
hash := hash4(d.window[s.index:])
|
||||
ch := s.hashHead[hash]
|
||||
s.chainHead = int(ch)
|
||||
s.hashPrev[s.index&windowMask] = ch
|
||||
s.hashHead[s.hash&hashMask] = uint32(s.index + s.hashOffset)
|
||||
s.hashHead[hash] = uint32(s.index + s.hashOffset)
|
||||
}
|
||||
prevLength := s.length
|
||||
prevOffset := s.offset
|
||||
@ -503,7 +497,7 @@ func (d *compressor) deflateLazy() {
|
||||
end += prevIndex
|
||||
idx := prevIndex + prevLength - (4 - checkOff)
|
||||
h := hash4(d.window[idx:])
|
||||
ch2 := int(s.hashHead[h&hashMask]) - s.hashOffset - prevLength + (4 - checkOff)
|
||||
ch2 := int(s.hashHead[h]) - s.hashOffset - prevLength + (4 - checkOff)
|
||||
if ch2 > minIndex {
|
||||
length := matchLen(d.window[prevIndex:end], d.window[ch2:])
|
||||
// It seems like a pure length metric is best.
|
||||
@ -547,7 +541,6 @@ func (d *compressor) deflateLazy() {
|
||||
// Set the head of the hash chain to us.
|
||||
s.hashHead[newH] = uint32(di + s.hashOffset)
|
||||
}
|
||||
s.hash = newH
|
||||
}
|
||||
|
||||
s.index = newIndex
|
||||
@ -793,7 +786,6 @@ func (d *compressor) reset(w io.Writer) {
|
||||
d.tokens.Reset()
|
||||
s.length = minMatchLength - 1
|
||||
s.offset = 0
|
||||
s.hash = 0
|
||||
s.ii = 0
|
||||
s.maxInsertIndex = 0
|
||||
}
|
||||
|
2
vendor/github.com/klauspost/compress/flate/fast_encoder.go
generated
vendored
2
vendor/github.com/klauspost/compress/flate/fast_encoder.go
generated
vendored
@ -117,7 +117,7 @@ func (e *fastGen) addBlock(src []byte) int32 {
|
||||
// hash4 returns the hash of u to fit in a hash table with h bits.
|
||||
// Preferably h should be a constant and should always be <32.
|
||||
func hash4u(u uint32, h uint8) uint32 {
|
||||
return (u * prime4bytes) >> ((32 - h) & reg8SizeMask32)
|
||||
return (u * prime4bytes) >> (32 - h)
|
||||
}
|
||||
|
||||
type tableEntryPrev struct {
|
||||
|
10
vendor/github.com/klauspost/compress/huff0/bitreader.go
generated
vendored
10
vendor/github.com/klauspost/compress/huff0/bitreader.go
generated
vendored
@ -165,11 +165,6 @@ func (b *bitReaderShifted) peekBitsFast(n uint8) uint16 {
|
||||
return uint16(b.value >> ((64 - n) & 63))
|
||||
}
|
||||
|
||||
// peekTopBits(n) is equvialent to peekBitFast(64 - n)
|
||||
func (b *bitReaderShifted) peekTopBits(n uint8) uint16 {
|
||||
return uint16(b.value >> n)
|
||||
}
|
||||
|
||||
func (b *bitReaderShifted) advance(n uint8) {
|
||||
b.bitsRead += n
|
||||
b.value <<= n & 63
|
||||
@ -220,11 +215,6 @@ func (b *bitReaderShifted) fill() {
|
||||
}
|
||||
}
|
||||
|
||||
// finished returns true if all bits have been read from the bit stream.
|
||||
func (b *bitReaderShifted) finished() bool {
|
||||
return b.off == 0 && b.bitsRead >= 64
|
||||
}
|
||||
|
||||
func (b *bitReaderShifted) remaining() uint {
|
||||
return b.off*8 + uint(64-b.bitsRead)
|
||||
}
|
||||
|
115
vendor/github.com/klauspost/compress/huff0/bitwriter.go
generated
vendored
115
vendor/github.com/klauspost/compress/huff0/bitwriter.go
generated
vendored
@ -5,8 +5,6 @@
|
||||
|
||||
package huff0
|
||||
|
||||
import "fmt"
|
||||
|
||||
// bitWriter will write bits.
|
||||
// First bit will be LSB of the first byte of output.
|
||||
type bitWriter struct {
|
||||
@ -23,14 +21,6 @@ var bitMask16 = [32]uint16{
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF} /* up to 16 bits */
|
||||
|
||||
// addBits16NC will add up to 16 bits.
|
||||
// It will not check if there is space for them,
|
||||
// so the caller must ensure that it has flushed recently.
|
||||
func (b *bitWriter) addBits16NC(value uint16, bits uint8) {
|
||||
b.bitContainer |= uint64(value&bitMask16[bits&31]) << (b.nBits & 63)
|
||||
b.nBits += bits
|
||||
}
|
||||
|
||||
// addBits16Clean will add up to 16 bits. value may not contain more set bits than indicated.
|
||||
// It will not check if there is space for them, so the caller must ensure that it has flushed recently.
|
||||
func (b *bitWriter) addBits16Clean(value uint16, bits uint8) {
|
||||
@ -70,104 +60,6 @@ func (b *bitWriter) encTwoSymbols(ct cTable, av, bv byte) {
|
||||
b.nBits += encA.nBits + encB.nBits
|
||||
}
|
||||
|
||||
// addBits16ZeroNC will add up to 16 bits.
|
||||
// It will not check if there is space for them,
|
||||
// so the caller must ensure that it has flushed recently.
|
||||
// This is fastest if bits can be zero.
|
||||
func (b *bitWriter) addBits16ZeroNC(value uint16, bits uint8) {
|
||||
if bits == 0 {
|
||||
return
|
||||
}
|
||||
value <<= (16 - bits) & 15
|
||||
value >>= (16 - bits) & 15
|
||||
b.bitContainer |= uint64(value) << (b.nBits & 63)
|
||||
b.nBits += bits
|
||||
}
|
||||
|
||||
// flush will flush all pending full bytes.
|
||||
// There will be at least 56 bits available for writing when this has been called.
|
||||
// Using flush32 is faster, but leaves less space for writing.
|
||||
func (b *bitWriter) flush() {
|
||||
v := b.nBits >> 3
|
||||
switch v {
|
||||
case 0:
|
||||
return
|
||||
case 1:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
)
|
||||
b.bitContainer >>= 1 << 3
|
||||
case 2:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
)
|
||||
b.bitContainer >>= 2 << 3
|
||||
case 3:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
byte(b.bitContainer>>16),
|
||||
)
|
||||
b.bitContainer >>= 3 << 3
|
||||
case 4:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
byte(b.bitContainer>>16),
|
||||
byte(b.bitContainer>>24),
|
||||
)
|
||||
b.bitContainer >>= 4 << 3
|
||||
case 5:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
byte(b.bitContainer>>16),
|
||||
byte(b.bitContainer>>24),
|
||||
byte(b.bitContainer>>32),
|
||||
)
|
||||
b.bitContainer >>= 5 << 3
|
||||
case 6:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
byte(b.bitContainer>>16),
|
||||
byte(b.bitContainer>>24),
|
||||
byte(b.bitContainer>>32),
|
||||
byte(b.bitContainer>>40),
|
||||
)
|
||||
b.bitContainer >>= 6 << 3
|
||||
case 7:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
byte(b.bitContainer>>16),
|
||||
byte(b.bitContainer>>24),
|
||||
byte(b.bitContainer>>32),
|
||||
byte(b.bitContainer>>40),
|
||||
byte(b.bitContainer>>48),
|
||||
)
|
||||
b.bitContainer >>= 7 << 3
|
||||
case 8:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
byte(b.bitContainer>>16),
|
||||
byte(b.bitContainer>>24),
|
||||
byte(b.bitContainer>>32),
|
||||
byte(b.bitContainer>>40),
|
||||
byte(b.bitContainer>>48),
|
||||
byte(b.bitContainer>>56),
|
||||
)
|
||||
b.bitContainer = 0
|
||||
b.nBits = 0
|
||||
return
|
||||
default:
|
||||
panic(fmt.Errorf("bits (%d) > 64", b.nBits))
|
||||
}
|
||||
b.nBits &= 7
|
||||
}
|
||||
|
||||
// flush32 will flush out, so there are at least 32 bits available for writing.
|
||||
func (b *bitWriter) flush32() {
|
||||
if b.nBits < 32 {
|
||||
@ -201,10 +93,3 @@ func (b *bitWriter) close() error {
|
||||
b.flushAlign()
|
||||
return nil
|
||||
}
|
||||
|
||||
// reset and continue writing by appending to out.
|
||||
func (b *bitWriter) reset(out []byte) {
|
||||
b.bitContainer = 0
|
||||
b.nBits = 0
|
||||
b.out = out
|
||||
}
|
||||
|
10
vendor/github.com/klauspost/compress/huff0/bytereader.go
generated
vendored
10
vendor/github.com/klauspost/compress/huff0/bytereader.go
generated
vendored
@ -20,11 +20,6 @@ func (b *byteReader) init(in []byte) {
|
||||
b.off = 0
|
||||
}
|
||||
|
||||
// advance the stream b n bytes.
|
||||
func (b *byteReader) advance(n uint) {
|
||||
b.off += int(n)
|
||||
}
|
||||
|
||||
// Int32 returns a little endian int32 starting at current offset.
|
||||
func (b byteReader) Int32() int32 {
|
||||
v3 := int32(b.b[b.off+3])
|
||||
@ -43,11 +38,6 @@ func (b byteReader) Uint32() uint32 {
|
||||
return (v3 << 24) | (v2 << 16) | (v1 << 8) | v0
|
||||
}
|
||||
|
||||
// unread returns the unread portion of the input.
|
||||
func (b byteReader) unread() []byte {
|
||||
return b.b[b.off:]
|
||||
}
|
||||
|
||||
// remain will return the number of bytes remaining.
|
||||
func (b byteReader) remain() int {
|
||||
return len(b.b) - b.off
|
||||
|
1
vendor/github.com/klauspost/compress/huff0/compress.go
generated
vendored
1
vendor/github.com/klauspost/compress/huff0/compress.go
generated
vendored
@ -404,6 +404,7 @@ func (s *Scratch) canUseTable(c cTable) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
//lint:ignore U1000 used for debugging
|
||||
func (s *Scratch) validateTable(c cTable) bool {
|
||||
if len(c) < int(s.symbolLen) {
|
||||
return false
|
||||
|
113
vendor/github.com/klauspost/compress/huff0/decompress.go
generated
vendored
113
vendor/github.com/klauspost/compress/huff0/decompress.go
generated
vendored
@ -11,7 +11,6 @@ import (
|
||||
|
||||
type dTable struct {
|
||||
single []dEntrySingle
|
||||
double []dEntryDouble
|
||||
}
|
||||
|
||||
// single-symbols decoding
|
||||
@ -19,13 +18,6 @@ type dEntrySingle struct {
|
||||
entry uint16
|
||||
}
|
||||
|
||||
// double-symbols decoding
|
||||
type dEntryDouble struct {
|
||||
seq [4]byte
|
||||
nBits uint8
|
||||
len uint8
|
||||
}
|
||||
|
||||
// Uses special code for all tables that are < 8 bits.
|
||||
const use8BitTables = true
|
||||
|
||||
@ -35,7 +27,7 @@ const use8BitTables = true
|
||||
// If no Scratch is provided a new one is allocated.
|
||||
// The returned Scratch can be used for encoding or decoding input using this table.
|
||||
func ReadTable(in []byte, s *Scratch) (s2 *Scratch, remain []byte, err error) {
|
||||
s, err = s.prepare(in)
|
||||
s, err = s.prepare(nil)
|
||||
if err != nil {
|
||||
return s, nil, err
|
||||
}
|
||||
@ -236,108 +228,6 @@ func (d *Decoder) buffer() *[4][256]byte {
|
||||
return &[4][256]byte{}
|
||||
}
|
||||
|
||||
// Decompress1X will decompress a 1X encoded stream.
|
||||
// The cap of the output buffer will be the maximum decompressed size.
|
||||
// The length of the supplied input must match the end of a block exactly.
|
||||
func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) {
|
||||
if len(d.dt.single) == 0 {
|
||||
return nil, errors.New("no table loaded")
|
||||
}
|
||||
if use8BitTables && d.actualTableLog <= 8 {
|
||||
return d.decompress1X8Bit(dst, src)
|
||||
}
|
||||
var br bitReaderShifted
|
||||
err := br.init(src)
|
||||
if err != nil {
|
||||
return dst, err
|
||||
}
|
||||
maxDecodedSize := cap(dst)
|
||||
dst = dst[:0]
|
||||
|
||||
// Avoid bounds check by always having full sized table.
|
||||
const tlSize = 1 << tableLogMax
|
||||
const tlMask = tlSize - 1
|
||||
dt := d.dt.single[:tlSize]
|
||||
|
||||
// Use temp table to avoid bound checks/append penalty.
|
||||
bufs := d.buffer()
|
||||
buf := &bufs[0]
|
||||
var off uint8
|
||||
|
||||
for br.off >= 8 {
|
||||
br.fillFast()
|
||||
v := dt[br.peekBitsFast(d.actualTableLog)&tlMask]
|
||||
br.advance(uint8(v.entry))
|
||||
buf[off+0] = uint8(v.entry >> 8)
|
||||
|
||||
v = dt[br.peekBitsFast(d.actualTableLog)&tlMask]
|
||||
br.advance(uint8(v.entry))
|
||||
buf[off+1] = uint8(v.entry >> 8)
|
||||
|
||||
// Refill
|
||||
br.fillFast()
|
||||
|
||||
v = dt[br.peekBitsFast(d.actualTableLog)&tlMask]
|
||||
br.advance(uint8(v.entry))
|
||||
buf[off+2] = uint8(v.entry >> 8)
|
||||
|
||||
v = dt[br.peekBitsFast(d.actualTableLog)&tlMask]
|
||||
br.advance(uint8(v.entry))
|
||||
buf[off+3] = uint8(v.entry >> 8)
|
||||
|
||||
off += 4
|
||||
if off == 0 {
|
||||
if len(dst)+256 > maxDecodedSize {
|
||||
br.close()
|
||||
d.bufs.Put(bufs)
|
||||
return nil, ErrMaxDecodedSizeExceeded
|
||||
}
|
||||
dst = append(dst, buf[:]...)
|
||||
}
|
||||
}
|
||||
|
||||
if len(dst)+int(off) > maxDecodedSize {
|
||||
d.bufs.Put(bufs)
|
||||
br.close()
|
||||
return nil, ErrMaxDecodedSizeExceeded
|
||||
}
|
||||
dst = append(dst, buf[:off]...)
|
||||
|
||||
// br < 8, so uint8 is fine
|
||||
bitsLeft := uint8(br.off)*8 + 64 - br.bitsRead
|
||||
for bitsLeft > 0 {
|
||||
br.fill()
|
||||
if false && br.bitsRead >= 32 {
|
||||
if br.off >= 4 {
|
||||
v := br.in[br.off-4:]
|
||||
v = v[:4]
|
||||
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
|
||||
br.value = (br.value << 32) | uint64(low)
|
||||
br.bitsRead -= 32
|
||||
br.off -= 4
|
||||
} else {
|
||||
for br.off > 0 {
|
||||
br.value = (br.value << 8) | uint64(br.in[br.off-1])
|
||||
br.bitsRead -= 8
|
||||
br.off--
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(dst) >= maxDecodedSize {
|
||||
d.bufs.Put(bufs)
|
||||
br.close()
|
||||
return nil, ErrMaxDecodedSizeExceeded
|
||||
}
|
||||
v := d.dt.single[br.peekBitsFast(d.actualTableLog)&tlMask]
|
||||
nBits := uint8(v.entry)
|
||||
br.advance(nBits)
|
||||
bitsLeft -= nBits
|
||||
dst = append(dst, uint8(v.entry>>8))
|
||||
}
|
||||
d.bufs.Put(bufs)
|
||||
return dst, br.close()
|
||||
}
|
||||
|
||||
// decompress1X8Bit will decompress a 1X encoded stream with tablelog <= 8.
|
||||
// The cap of the output buffer will be the maximum decompressed size.
|
||||
// The length of the supplied input must match the end of a block exactly.
|
||||
@ -995,7 +885,6 @@ func (d *Decoder) decompress4X8bitExactly(dst, src []byte) ([]byte, error) {
|
||||
|
||||
const shift = 56
|
||||
const tlSize = 1 << 8
|
||||
const tlMask = tlSize - 1
|
||||
single := d.dt.single[:tlSize]
|
||||
|
||||
// Use temp table to avoid bound checks/append penalty.
|
||||
|
82
vendor/github.com/klauspost/compress/huff0/decompress_amd64.go
generated
vendored
82
vendor/github.com/klauspost/compress/huff0/decompress_amd64.go
generated
vendored
@ -2,12 +2,14 @@
|
||||
// +build amd64,!appengine,!noasm,gc
|
||||
|
||||
// This file contains the specialisation of Decoder.Decompress4X
|
||||
// that uses an asm implementation of its main loop.
|
||||
// and Decoder.Decompress1X that use an asm implementation of thir main loops.
|
||||
package huff0
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/klauspost/compress/internal/cpuinfo"
|
||||
)
|
||||
|
||||
// decompress4x_main_loop_x86 is an x86 assembler implementation
|
||||
@ -146,3 +148,81 @@ func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) {
|
||||
}
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
// decompress4x_main_loop_x86 is an x86 assembler implementation
|
||||
// of Decompress1X when tablelog > 8.
|
||||
//go:noescape
|
||||
func decompress1x_main_loop_amd64(ctx *decompress1xContext)
|
||||
|
||||
// decompress4x_main_loop_x86 is an x86 with BMI2 assembler implementation
|
||||
// of Decompress1X when tablelog > 8.
|
||||
//go:noescape
|
||||
func decompress1x_main_loop_bmi2(ctx *decompress1xContext)
|
||||
|
||||
type decompress1xContext struct {
|
||||
pbr *bitReaderShifted
|
||||
peekBits uint8
|
||||
out *byte
|
||||
outCap int
|
||||
tbl *dEntrySingle
|
||||
decoded int
|
||||
}
|
||||
|
||||
// Error reported by asm implementations
|
||||
const error_max_decoded_size_exeeded = -1
|
||||
|
||||
// Decompress1X will decompress a 1X encoded stream.
|
||||
// The cap of the output buffer will be the maximum decompressed size.
|
||||
// The length of the supplied input must match the end of a block exactly.
|
||||
func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) {
|
||||
if len(d.dt.single) == 0 {
|
||||
return nil, errors.New("no table loaded")
|
||||
}
|
||||
var br bitReaderShifted
|
||||
err := br.init(src)
|
||||
if err != nil {
|
||||
return dst, err
|
||||
}
|
||||
maxDecodedSize := cap(dst)
|
||||
dst = dst[:maxDecodedSize]
|
||||
|
||||
const tlSize = 1 << tableLogMax
|
||||
const tlMask = tlSize - 1
|
||||
|
||||
if maxDecodedSize >= 4 {
|
||||
ctx := decompress1xContext{
|
||||
pbr: &br,
|
||||
out: &dst[0],
|
||||
outCap: maxDecodedSize,
|
||||
peekBits: uint8((64 - d.actualTableLog) & 63), // see: bitReaderShifted.peekBitsFast()
|
||||
tbl: &d.dt.single[0],
|
||||
}
|
||||
|
||||
if cpuinfo.HasBMI2() {
|
||||
decompress1x_main_loop_bmi2(&ctx)
|
||||
} else {
|
||||
decompress1x_main_loop_amd64(&ctx)
|
||||
}
|
||||
if ctx.decoded == error_max_decoded_size_exeeded {
|
||||
return nil, ErrMaxDecodedSizeExceeded
|
||||
}
|
||||
|
||||
dst = dst[:ctx.decoded]
|
||||
}
|
||||
|
||||
// br < 8, so uint8 is fine
|
||||
bitsLeft := uint8(br.off)*8 + 64 - br.bitsRead
|
||||
for bitsLeft > 0 {
|
||||
br.fill()
|
||||
if len(dst) >= maxDecodedSize {
|
||||
br.close()
|
||||
return nil, ErrMaxDecodedSizeExceeded
|
||||
}
|
||||
v := d.dt.single[br.peekBitsFast(d.actualTableLog)&tlMask]
|
||||
nBits := uint8(v.entry)
|
||||
br.advance(nBits)
|
||||
bitsLeft -= nBits
|
||||
dst = append(dst, uint8(v.entry>>8))
|
||||
}
|
||||
return dst, br.close()
|
||||
}
|
||||
|
203
vendor/github.com/klauspost/compress/huff0/decompress_amd64.s
generated
vendored
203
vendor/github.com/klauspost/compress/huff0/decompress_amd64.s
generated
vendored
@ -660,3 +660,206 @@ skip_fill1003:
|
||||
SHLQ $0x02, DX
|
||||
MOVQ DX, 64(AX)
|
||||
RET
|
||||
|
||||
// func decompress1x_main_loop_amd64(ctx *decompress1xContext)
|
||||
TEXT ·decompress1x_main_loop_amd64(SB), $0-8
|
||||
MOVQ ctx+0(FP), CX
|
||||
MOVQ 16(CX), DX
|
||||
MOVQ 24(CX), BX
|
||||
CMPQ BX, $0x04
|
||||
JB error_max_decoded_size_exeeded
|
||||
LEAQ (DX)(BX*1), BX
|
||||
MOVQ (CX), SI
|
||||
MOVQ (SI), R8
|
||||
MOVQ 24(SI), R9
|
||||
MOVQ 32(SI), R10
|
||||
MOVBQZX 40(SI), R11
|
||||
MOVQ 32(CX), SI
|
||||
MOVBQZX 8(CX), DI
|
||||
JMP loop_condition
|
||||
|
||||
main_loop:
|
||||
// Check if we have room for 4 bytes in the output buffer
|
||||
LEAQ 4(DX), CX
|
||||
CMPQ CX, BX
|
||||
JGE error_max_decoded_size_exeeded
|
||||
|
||||
// Decode 4 values
|
||||
CMPQ R11, $0x20
|
||||
JL bitReader_fillFast_1_end
|
||||
SUBQ $0x20, R11
|
||||
SUBQ $0x04, R9
|
||||
MOVL (R8)(R9*1), R12
|
||||
MOVQ R11, CX
|
||||
SHLQ CL, R12
|
||||
ORQ R12, R10
|
||||
|
||||
bitReader_fillFast_1_end:
|
||||
MOVQ DI, CX
|
||||
MOVQ R10, R12
|
||||
SHRQ CL, R12
|
||||
MOVW (SI)(R12*2), CX
|
||||
MOVB CH, AL
|
||||
MOVBQZX CL, CX
|
||||
ADDQ CX, R11
|
||||
SHLQ CL, R10
|
||||
MOVQ DI, CX
|
||||
MOVQ R10, R12
|
||||
SHRQ CL, R12
|
||||
MOVW (SI)(R12*2), CX
|
||||
MOVB CH, AH
|
||||
MOVBQZX CL, CX
|
||||
ADDQ CX, R11
|
||||
SHLQ CL, R10
|
||||
BSWAPL AX
|
||||
CMPQ R11, $0x20
|
||||
JL bitReader_fillFast_2_end
|
||||
SUBQ $0x20, R11
|
||||
SUBQ $0x04, R9
|
||||
MOVL (R8)(R9*1), R12
|
||||
MOVQ R11, CX
|
||||
SHLQ CL, R12
|
||||
ORQ R12, R10
|
||||
|
||||
bitReader_fillFast_2_end:
|
||||
MOVQ DI, CX
|
||||
MOVQ R10, R12
|
||||
SHRQ CL, R12
|
||||
MOVW (SI)(R12*2), CX
|
||||
MOVB CH, AH
|
||||
MOVBQZX CL, CX
|
||||
ADDQ CX, R11
|
||||
SHLQ CL, R10
|
||||
MOVQ DI, CX
|
||||
MOVQ R10, R12
|
||||
SHRQ CL, R12
|
||||
MOVW (SI)(R12*2), CX
|
||||
MOVB CH, AL
|
||||
MOVBQZX CL, CX
|
||||
ADDQ CX, R11
|
||||
SHLQ CL, R10
|
||||
BSWAPL AX
|
||||
|
||||
// Store the decoded values
|
||||
MOVL AX, (DX)
|
||||
ADDQ $0x04, DX
|
||||
|
||||
loop_condition:
|
||||
CMPQ R9, $0x08
|
||||
JGE main_loop
|
||||
|
||||
// Update ctx structure
|
||||
MOVQ ctx+0(FP), AX
|
||||
MOVQ DX, CX
|
||||
MOVQ 16(AX), DX
|
||||
SUBQ DX, CX
|
||||
MOVQ CX, 40(AX)
|
||||
MOVQ (AX), AX
|
||||
MOVQ R9, 24(AX)
|
||||
MOVQ R10, 32(AX)
|
||||
MOVB R11, 40(AX)
|
||||
RET
|
||||
|
||||
// Report error
|
||||
error_max_decoded_size_exeeded:
|
||||
MOVQ ctx+0(FP), AX
|
||||
MOVQ $-1, CX
|
||||
MOVQ CX, 40(AX)
|
||||
RET
|
||||
|
||||
// func decompress1x_main_loop_bmi2(ctx *decompress1xContext)
|
||||
// Requires: BMI2
|
||||
TEXT ·decompress1x_main_loop_bmi2(SB), $0-8
|
||||
MOVQ ctx+0(FP), CX
|
||||
MOVQ 16(CX), DX
|
||||
MOVQ 24(CX), BX
|
||||
CMPQ BX, $0x04
|
||||
JB error_max_decoded_size_exeeded
|
||||
LEAQ (DX)(BX*1), BX
|
||||
MOVQ (CX), SI
|
||||
MOVQ (SI), R8
|
||||
MOVQ 24(SI), R9
|
||||
MOVQ 32(SI), R10
|
||||
MOVBQZX 40(SI), R11
|
||||
MOVQ 32(CX), SI
|
||||
MOVBQZX 8(CX), DI
|
||||
JMP loop_condition
|
||||
|
||||
main_loop:
|
||||
// Check if we have room for 4 bytes in the output buffer
|
||||
LEAQ 4(DX), CX
|
||||
CMPQ CX, BX
|
||||
JGE error_max_decoded_size_exeeded
|
||||
|
||||
// Decode 4 values
|
||||
CMPQ R11, $0x20
|
||||
JL bitReader_fillFast_1_end
|
||||
SUBQ $0x20, R11
|
||||
SUBQ $0x04, R9
|
||||
MOVL (R8)(R9*1), CX
|
||||
SHLXQ R11, CX, CX
|
||||
ORQ CX, R10
|
||||
|
||||
bitReader_fillFast_1_end:
|
||||
SHRXQ DI, R10, CX
|
||||
MOVW (SI)(CX*2), CX
|
||||
MOVB CH, AL
|
||||
MOVBQZX CL, CX
|
||||
ADDQ CX, R11
|
||||
SHLXQ CX, R10, R10
|
||||
SHRXQ DI, R10, CX
|
||||
MOVW (SI)(CX*2), CX
|
||||
MOVB CH, AH
|
||||
MOVBQZX CL, CX
|
||||
ADDQ CX, R11
|
||||
SHLXQ CX, R10, R10
|
||||
BSWAPL AX
|
||||
CMPQ R11, $0x20
|
||||
JL bitReader_fillFast_2_end
|
||||
SUBQ $0x20, R11
|
||||
SUBQ $0x04, R9
|
||||
MOVL (R8)(R9*1), CX
|
||||
SHLXQ R11, CX, CX
|
||||
ORQ CX, R10
|
||||
|
||||
bitReader_fillFast_2_end:
|
||||
SHRXQ DI, R10, CX
|
||||
MOVW (SI)(CX*2), CX
|
||||
MOVB CH, AH
|
||||
MOVBQZX CL, CX
|
||||
ADDQ CX, R11
|
||||
SHLXQ CX, R10, R10
|
||||
SHRXQ DI, R10, CX
|
||||
MOVW (SI)(CX*2), CX
|
||||
MOVB CH, AL
|
||||
MOVBQZX CL, CX
|
||||
ADDQ CX, R11
|
||||
SHLXQ CX, R10, R10
|
||||
BSWAPL AX
|
||||
|
||||
// Store the decoded values
|
||||
MOVL AX, (DX)
|
||||
ADDQ $0x04, DX
|
||||
|
||||
loop_condition:
|
||||
CMPQ R9, $0x08
|
||||
JGE main_loop
|
||||
|
||||
// Update ctx structure
|
||||
MOVQ ctx+0(FP), AX
|
||||
MOVQ DX, CX
|
||||
MOVQ 16(AX), DX
|
||||
SUBQ DX, CX
|
||||
MOVQ CX, 40(AX)
|
||||
MOVQ (AX), AX
|
||||
MOVQ R9, 24(AX)
|
||||
MOVQ R10, 32(AX)
|
||||
MOVB R11, 40(AX)
|
||||
RET
|
||||
|
||||
// Report error
|
||||
error_max_decoded_size_exeeded:
|
||||
MOVQ ctx+0(FP), AX
|
||||
MOVQ $-1, CX
|
||||
MOVQ CX, 40(AX)
|
||||
RET
|
||||
|
102
vendor/github.com/klauspost/compress/huff0/decompress_generic.go
generated
vendored
102
vendor/github.com/klauspost/compress/huff0/decompress_generic.go
generated
vendored
@ -191,3 +191,105 @@ func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) {
|
||||
}
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
// Decompress1X will decompress a 1X encoded stream.
|
||||
// The cap of the output buffer will be the maximum decompressed size.
|
||||
// The length of the supplied input must match the end of a block exactly.
|
||||
func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) {
|
||||
if len(d.dt.single) == 0 {
|
||||
return nil, errors.New("no table loaded")
|
||||
}
|
||||
if use8BitTables && d.actualTableLog <= 8 {
|
||||
return d.decompress1X8Bit(dst, src)
|
||||
}
|
||||
var br bitReaderShifted
|
||||
err := br.init(src)
|
||||
if err != nil {
|
||||
return dst, err
|
||||
}
|
||||
maxDecodedSize := cap(dst)
|
||||
dst = dst[:0]
|
||||
|
||||
// Avoid bounds check by always having full sized table.
|
||||
const tlSize = 1 << tableLogMax
|
||||
const tlMask = tlSize - 1
|
||||
dt := d.dt.single[:tlSize]
|
||||
|
||||
// Use temp table to avoid bound checks/append penalty.
|
||||
bufs := d.buffer()
|
||||
buf := &bufs[0]
|
||||
var off uint8
|
||||
|
||||
for br.off >= 8 {
|
||||
br.fillFast()
|
||||
v := dt[br.peekBitsFast(d.actualTableLog)&tlMask]
|
||||
br.advance(uint8(v.entry))
|
||||
buf[off+0] = uint8(v.entry >> 8)
|
||||
|
||||
v = dt[br.peekBitsFast(d.actualTableLog)&tlMask]
|
||||
br.advance(uint8(v.entry))
|
||||
buf[off+1] = uint8(v.entry >> 8)
|
||||
|
||||
// Refill
|
||||
br.fillFast()
|
||||
|
||||
v = dt[br.peekBitsFast(d.actualTableLog)&tlMask]
|
||||
br.advance(uint8(v.entry))
|
||||
buf[off+2] = uint8(v.entry >> 8)
|
||||
|
||||
v = dt[br.peekBitsFast(d.actualTableLog)&tlMask]
|
||||
br.advance(uint8(v.entry))
|
||||
buf[off+3] = uint8(v.entry >> 8)
|
||||
|
||||
off += 4
|
||||
if off == 0 {
|
||||
if len(dst)+256 > maxDecodedSize {
|
||||
br.close()
|
||||
d.bufs.Put(bufs)
|
||||
return nil, ErrMaxDecodedSizeExceeded
|
||||
}
|
||||
dst = append(dst, buf[:]...)
|
||||
}
|
||||
}
|
||||
|
||||
if len(dst)+int(off) > maxDecodedSize {
|
||||
d.bufs.Put(bufs)
|
||||
br.close()
|
||||
return nil, ErrMaxDecodedSizeExceeded
|
||||
}
|
||||
dst = append(dst, buf[:off]...)
|
||||
|
||||
// br < 8, so uint8 is fine
|
||||
bitsLeft := uint8(br.off)*8 + 64 - br.bitsRead
|
||||
for bitsLeft > 0 {
|
||||
br.fill()
|
||||
if false && br.bitsRead >= 32 {
|
||||
if br.off >= 4 {
|
||||
v := br.in[br.off-4:]
|
||||
v = v[:4]
|
||||
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
|
||||
br.value = (br.value << 32) | uint64(low)
|
||||
br.bitsRead -= 32
|
||||
br.off -= 4
|
||||
} else {
|
||||
for br.off > 0 {
|
||||
br.value = (br.value << 8) | uint64(br.in[br.off-1])
|
||||
br.bitsRead -= 8
|
||||
br.off--
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(dst) >= maxDecodedSize {
|
||||
d.bufs.Put(bufs)
|
||||
br.close()
|
||||
return nil, ErrMaxDecodedSizeExceeded
|
||||
}
|
||||
v := d.dt.single[br.peekBitsFast(d.actualTableLog)&tlMask]
|
||||
nBits := uint8(v.entry)
|
||||
br.advance(nBits)
|
||||
bitsLeft -= nBits
|
||||
dst = append(dst, uint8(v.entry>>8))
|
||||
}
|
||||
d.bufs.Put(bufs)
|
||||
return dst, br.close()
|
||||
}
|
||||
|
7
vendor/github.com/klauspost/compress/zstd/bitreader.go
generated
vendored
7
vendor/github.com/klauspost/compress/zstd/bitreader.go
generated
vendored
@ -63,13 +63,6 @@ func (b *bitReader) get32BitsFast(n uint8) uint32 {
|
||||
return v
|
||||
}
|
||||
|
||||
func (b *bitReader) get16BitsFast(n uint8) uint16 {
|
||||
const regMask = 64 - 1
|
||||
v := uint16((b.value << (b.bitsRead & regMask)) >> ((regMask + 1 - n) & regMask))
|
||||
b.bitsRead += n
|
||||
return v
|
||||
}
|
||||
|
||||
// fillFast() will make sure at least 32 bits are available.
|
||||
// There must be at least 4 bytes available.
|
||||
func (b *bitReader) fillFast() {
|
||||
|
76
vendor/github.com/klauspost/compress/zstd/bitwriter.go
generated
vendored
76
vendor/github.com/klauspost/compress/zstd/bitwriter.go
generated
vendored
@ -5,8 +5,6 @@
|
||||
|
||||
package zstd
|
||||
|
||||
import "fmt"
|
||||
|
||||
// bitWriter will write bits.
|
||||
// First bit will be LSB of the first byte of output.
|
||||
type bitWriter struct {
|
||||
@ -73,80 +71,6 @@ func (b *bitWriter) addBits16Clean(value uint16, bits uint8) {
|
||||
b.nBits += bits
|
||||
}
|
||||
|
||||
// flush will flush all pending full bytes.
|
||||
// There will be at least 56 bits available for writing when this has been called.
|
||||
// Using flush32 is faster, but leaves less space for writing.
|
||||
func (b *bitWriter) flush() {
|
||||
v := b.nBits >> 3
|
||||
switch v {
|
||||
case 0:
|
||||
case 1:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
)
|
||||
case 2:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
)
|
||||
case 3:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
byte(b.bitContainer>>16),
|
||||
)
|
||||
case 4:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
byte(b.bitContainer>>16),
|
||||
byte(b.bitContainer>>24),
|
||||
)
|
||||
case 5:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
byte(b.bitContainer>>16),
|
||||
byte(b.bitContainer>>24),
|
||||
byte(b.bitContainer>>32),
|
||||
)
|
||||
case 6:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
byte(b.bitContainer>>16),
|
||||
byte(b.bitContainer>>24),
|
||||
byte(b.bitContainer>>32),
|
||||
byte(b.bitContainer>>40),
|
||||
)
|
||||
case 7:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
byte(b.bitContainer>>16),
|
||||
byte(b.bitContainer>>24),
|
||||
byte(b.bitContainer>>32),
|
||||
byte(b.bitContainer>>40),
|
||||
byte(b.bitContainer>>48),
|
||||
)
|
||||
case 8:
|
||||
b.out = append(b.out,
|
||||
byte(b.bitContainer),
|
||||
byte(b.bitContainer>>8),
|
||||
byte(b.bitContainer>>16),
|
||||
byte(b.bitContainer>>24),
|
||||
byte(b.bitContainer>>32),
|
||||
byte(b.bitContainer>>40),
|
||||
byte(b.bitContainer>>48),
|
||||
byte(b.bitContainer>>56),
|
||||
)
|
||||
default:
|
||||
panic(fmt.Errorf("bits (%d) > 64", b.nBits))
|
||||
}
|
||||
b.bitContainer >>= v << 3
|
||||
b.nBits &= 7
|
||||
}
|
||||
|
||||
// flush32 will flush out, so there are at least 32 bits available for writing.
|
||||
func (b *bitWriter) flush32() {
|
||||
if b.nBits < 32 {
|
||||
|
31
vendor/github.com/klauspost/compress/zstd/blockdec.go
generated
vendored
31
vendor/github.com/klauspost/compress/zstd/blockdec.go
generated
vendored
@ -49,11 +49,8 @@ const (
|
||||
// Maximum possible block size (all Raw+Uncompressed).
|
||||
maxBlockSize = (1 << 21) - 1
|
||||
|
||||
// https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#literals_section_header
|
||||
maxCompressedLiteralSize = 1 << 18
|
||||
maxRLELiteralSize = 1 << 20
|
||||
maxMatchLen = 131074
|
||||
maxSequences = 0x7f00 + 0xffff
|
||||
maxMatchLen = 131074
|
||||
maxSequences = 0x7f00 + 0xffff
|
||||
|
||||
// We support slightly less than the reference decoder to be able to
|
||||
// use ints on 32 bit archs.
|
||||
@ -105,7 +102,6 @@ type blockDec struct {
|
||||
|
||||
// Block is RLE, this is the size.
|
||||
RLESize uint32
|
||||
tmp [4]byte
|
||||
|
||||
Type blockType
|
||||
|
||||
@ -368,14 +364,9 @@ func (b *blockDec) decodeLiterals(in []byte, hist *history) (remain []byte, err
|
||||
}
|
||||
if cap(b.literalBuf) < litRegenSize {
|
||||
if b.lowMem {
|
||||
b.literalBuf = make([]byte, litRegenSize)
|
||||
b.literalBuf = make([]byte, litRegenSize, litRegenSize+compressedBlockOverAlloc)
|
||||
} else {
|
||||
if litRegenSize > maxCompressedLiteralSize {
|
||||
// Exceptional
|
||||
b.literalBuf = make([]byte, litRegenSize)
|
||||
} else {
|
||||
b.literalBuf = make([]byte, litRegenSize, maxCompressedLiteralSize)
|
||||
}
|
||||
b.literalBuf = make([]byte, litRegenSize, maxCompressedBlockSize+compressedBlockOverAlloc)
|
||||
}
|
||||
}
|
||||
literals = b.literalBuf[:litRegenSize]
|
||||
@ -405,14 +396,14 @@ func (b *blockDec) decodeLiterals(in []byte, hist *history) (remain []byte, err
|
||||
// Ensure we have space to store it.
|
||||
if cap(b.literalBuf) < litRegenSize {
|
||||
if b.lowMem {
|
||||
b.literalBuf = make([]byte, 0, litRegenSize)
|
||||
b.literalBuf = make([]byte, 0, litRegenSize+compressedBlockOverAlloc)
|
||||
} else {
|
||||
b.literalBuf = make([]byte, 0, maxCompressedLiteralSize)
|
||||
b.literalBuf = make([]byte, 0, maxCompressedBlockSize+compressedBlockOverAlloc)
|
||||
}
|
||||
}
|
||||
var err error
|
||||
// Use our out buffer.
|
||||
huff.MaxDecodedSize = maxCompressedBlockSize
|
||||
huff.MaxDecodedSize = litRegenSize
|
||||
if fourStreams {
|
||||
literals, err = huff.Decoder().Decompress4X(b.literalBuf[:0:litRegenSize], literals)
|
||||
} else {
|
||||
@ -437,9 +428,9 @@ func (b *blockDec) decodeLiterals(in []byte, hist *history) (remain []byte, err
|
||||
// Ensure we have space to store it.
|
||||
if cap(b.literalBuf) < litRegenSize {
|
||||
if b.lowMem {
|
||||
b.literalBuf = make([]byte, 0, litRegenSize)
|
||||
b.literalBuf = make([]byte, 0, litRegenSize+compressedBlockOverAlloc)
|
||||
} else {
|
||||
b.literalBuf = make([]byte, 0, maxCompressedBlockSize)
|
||||
b.literalBuf = make([]byte, 0, maxCompressedBlockSize+compressedBlockOverAlloc)
|
||||
}
|
||||
}
|
||||
huff := hist.huffTree
|
||||
@ -456,7 +447,7 @@ func (b *blockDec) decodeLiterals(in []byte, hist *history) (remain []byte, err
|
||||
return in, err
|
||||
}
|
||||
hist.huffTree = huff
|
||||
huff.MaxDecodedSize = maxCompressedBlockSize
|
||||
huff.MaxDecodedSize = litRegenSize
|
||||
// Use our out buffer.
|
||||
if fourStreams {
|
||||
literals, err = huff.Decoder().Decompress4X(b.literalBuf[:0:litRegenSize], literals)
|
||||
@ -471,6 +462,8 @@ func (b *blockDec) decodeLiterals(in []byte, hist *history) (remain []byte, err
|
||||
if len(literals) != litRegenSize {
|
||||
return in, fmt.Errorf("literal output size mismatch want %d, got %d", litRegenSize, len(literals))
|
||||
}
|
||||
// Re-cap to get extra size.
|
||||
literals = b.literalBuf[:len(literals)]
|
||||
if debugDecoder {
|
||||
printf("Decompressed %d literals into %d bytes\n", litCompSize, litRegenSize)
|
||||
}
|
||||
|
4
vendor/github.com/klauspost/compress/zstd/bytebuf.go
generated
vendored
4
vendor/github.com/klauspost/compress/zstd/bytebuf.go
generated
vendored
@ -52,10 +52,6 @@ func (b *byteBuf) readBig(n int, dst []byte) ([]byte, error) {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (b *byteBuf) remain() []byte {
|
||||
return *b
|
||||
}
|
||||
|
||||
func (b *byteBuf) readByte() (byte, error) {
|
||||
bb := *b
|
||||
if len(bb) < 1 {
|
||||
|
6
vendor/github.com/klauspost/compress/zstd/bytereader.go
generated
vendored
6
vendor/github.com/klauspost/compress/zstd/bytereader.go
generated
vendored
@ -13,12 +13,6 @@ type byteReader struct {
|
||||
off int
|
||||
}
|
||||
|
||||
// init will initialize the reader and set the input.
|
||||
func (b *byteReader) init(in []byte) {
|
||||
b.b = in
|
||||
b.off = 0
|
||||
}
|
||||
|
||||
// advance the stream b n bytes.
|
||||
func (b *byteReader) advance(n uint) {
|
||||
b.off += int(n)
|
||||
|
93
vendor/github.com/klauspost/compress/zstd/decoder.go
generated
vendored
93
vendor/github.com/klauspost/compress/zstd/decoder.go
generated
vendored
@ -637,60 +637,18 @@ func (d *Decoder) startSyncDecoder(r io.Reader) error {
|
||||
|
||||
// Create Decoder:
|
||||
// ASYNC:
|
||||
// Spawn 4 go routines.
|
||||
// 0: Read frames and decode blocks.
|
||||
// 1: Decode block and literals. Receives hufftree and seqdecs, returns seqdecs and huff tree.
|
||||
// 2: Wait for recentOffsets if needed. Decode sequences, send recentOffsets.
|
||||
// 3: Wait for stream history, execute sequences, send stream history.
|
||||
// Spawn 3 go routines.
|
||||
// 0: Read frames and decode block literals.
|
||||
// 1: Decode sequences.
|
||||
// 2: Execute sequences, send to output.
|
||||
func (d *Decoder) startStreamDecoder(ctx context.Context, r io.Reader, output chan decodeOutput) {
|
||||
defer d.streamWg.Done()
|
||||
br := readerWrapper{r: r}
|
||||
|
||||
var seqPrepare = make(chan *blockDec, d.o.concurrent)
|
||||
var seqDecode = make(chan *blockDec, d.o.concurrent)
|
||||
var seqExecute = make(chan *blockDec, d.o.concurrent)
|
||||
|
||||
// Async 1: Prepare blocks...
|
||||
go func() {
|
||||
var hist history
|
||||
var hasErr bool
|
||||
for block := range seqPrepare {
|
||||
if hasErr {
|
||||
if block != nil {
|
||||
seqDecode <- block
|
||||
}
|
||||
continue
|
||||
}
|
||||
if block.async.newHist != nil {
|
||||
if debugDecoder {
|
||||
println("Async 1: new history")
|
||||
}
|
||||
hist.reset()
|
||||
if block.async.newHist.dict != nil {
|
||||
hist.setDict(block.async.newHist.dict)
|
||||
}
|
||||
}
|
||||
if block.err != nil || block.Type != blockTypeCompressed {
|
||||
hasErr = block.err != nil
|
||||
seqDecode <- block
|
||||
continue
|
||||
}
|
||||
|
||||
remain, err := block.decodeLiterals(block.data, &hist)
|
||||
block.err = err
|
||||
hasErr = block.err != nil
|
||||
if err == nil {
|
||||
block.async.literals = hist.decoders.literals
|
||||
block.async.seqData = remain
|
||||
} else if debugDecoder {
|
||||
println("decodeLiterals error:", err)
|
||||
}
|
||||
seqDecode <- block
|
||||
}
|
||||
close(seqDecode)
|
||||
}()
|
||||
|
||||
// Async 2: Decode sequences...
|
||||
// Async 1: Decode sequences...
|
||||
go func() {
|
||||
var hist history
|
||||
var hasErr bool
|
||||
@ -704,7 +662,7 @@ func (d *Decoder) startStreamDecoder(ctx context.Context, r io.Reader, output ch
|
||||
}
|
||||
if block.async.newHist != nil {
|
||||
if debugDecoder {
|
||||
println("Async 2: new history, recent:", block.async.newHist.recentOffsets)
|
||||
println("Async 1: new history, recent:", block.async.newHist.recentOffsets)
|
||||
}
|
||||
hist.decoders = block.async.newHist.decoders
|
||||
hist.recentOffsets = block.async.newHist.recentOffsets
|
||||
@ -758,7 +716,7 @@ func (d *Decoder) startStreamDecoder(ctx context.Context, r io.Reader, output ch
|
||||
}
|
||||
if block.async.newHist != nil {
|
||||
if debugDecoder {
|
||||
println("Async 3: new history")
|
||||
println("Async 2: new history")
|
||||
}
|
||||
hist.windowSize = block.async.newHist.windowSize
|
||||
hist.allocFrameBuffer = block.async.newHist.allocFrameBuffer
|
||||
@ -845,6 +803,33 @@ func (d *Decoder) startStreamDecoder(ctx context.Context, r io.Reader, output ch
|
||||
|
||||
decodeStream:
|
||||
for {
|
||||
var hist history
|
||||
var hasErr bool
|
||||
|
||||
decodeBlock := func(block *blockDec) {
|
||||
if hasErr {
|
||||
if block != nil {
|
||||
seqDecode <- block
|
||||
}
|
||||
return
|
||||
}
|
||||
if block.err != nil || block.Type != blockTypeCompressed {
|
||||
hasErr = block.err != nil
|
||||
seqDecode <- block
|
||||
return
|
||||
}
|
||||
|
||||
remain, err := block.decodeLiterals(block.data, &hist)
|
||||
block.err = err
|
||||
hasErr = block.err != nil
|
||||
if err == nil {
|
||||
block.async.literals = hist.decoders.literals
|
||||
block.async.seqData = remain
|
||||
} else if debugDecoder {
|
||||
println("decodeLiterals error:", err)
|
||||
}
|
||||
seqDecode <- block
|
||||
}
|
||||
frame := d.frame
|
||||
if debugDecoder {
|
||||
println("New frame...")
|
||||
@ -871,7 +856,7 @@ decodeStream:
|
||||
case <-ctx.Done():
|
||||
case dec := <-d.decoders:
|
||||
dec.sendErr(err)
|
||||
seqPrepare <- dec
|
||||
decodeBlock(dec)
|
||||
}
|
||||
break decodeStream
|
||||
}
|
||||
@ -891,6 +876,10 @@ decodeStream:
|
||||
if debugDecoder {
|
||||
println("Alloc History:", h.allocFrameBuffer)
|
||||
}
|
||||
hist.reset()
|
||||
if h.dict != nil {
|
||||
hist.setDict(h.dict)
|
||||
}
|
||||
dec.async.newHist = &h
|
||||
dec.async.fcs = frame.FrameContentSize
|
||||
historySent = true
|
||||
@ -917,7 +906,7 @@ decodeStream:
|
||||
}
|
||||
err = dec.err
|
||||
last := dec.Last
|
||||
seqPrepare <- dec
|
||||
decodeBlock(dec)
|
||||
if err != nil {
|
||||
break decodeStream
|
||||
}
|
||||
@ -926,7 +915,7 @@ decodeStream:
|
||||
}
|
||||
}
|
||||
}
|
||||
close(seqPrepare)
|
||||
close(seqDecode)
|
||||
wg.Wait()
|
||||
d.frame.history.b = frameHistCache
|
||||
}
|
||||
|
8
vendor/github.com/klauspost/compress/zstd/enc_better.go
generated
vendored
8
vendor/github.com/klauspost/compress/zstd/enc_better.go
generated
vendored
@ -156,8 +156,8 @@ encodeLoop:
|
||||
panic("offset0 was 0")
|
||||
}
|
||||
|
||||
nextHashS := hashLen(cv, betterShortTableBits, betterShortLen)
|
||||
nextHashL := hashLen(cv, betterLongTableBits, betterLongLen)
|
||||
nextHashS := hashLen(cv, betterShortTableBits, betterShortLen)
|
||||
candidateL := e.longTable[nextHashL]
|
||||
candidateS := e.table[nextHashS]
|
||||
|
||||
@ -518,8 +518,8 @@ encodeLoop:
|
||||
}
|
||||
|
||||
// Store this, since we have it.
|
||||
nextHashS := hashLen(cv, betterShortTableBits, betterShortLen)
|
||||
nextHashL := hashLen(cv, betterLongTableBits, betterLongLen)
|
||||
nextHashS := hashLen(cv, betterShortTableBits, betterShortLen)
|
||||
|
||||
// We have at least 4 byte match.
|
||||
// No need to check backwards. We come straight from a match
|
||||
@ -674,8 +674,8 @@ encodeLoop:
|
||||
panic("offset0 was 0")
|
||||
}
|
||||
|
||||
nextHashS := hashLen(cv, betterShortTableBits, betterShortLen)
|
||||
nextHashL := hashLen(cv, betterLongTableBits, betterLongLen)
|
||||
nextHashS := hashLen(cv, betterShortTableBits, betterShortLen)
|
||||
candidateL := e.longTable[nextHashL]
|
||||
candidateS := e.table[nextHashS]
|
||||
|
||||
@ -1047,8 +1047,8 @@ encodeLoop:
|
||||
}
|
||||
|
||||
// Store this, since we have it.
|
||||
nextHashS := hashLen(cv, betterShortTableBits, betterShortLen)
|
||||
nextHashL := hashLen(cv, betterLongTableBits, betterLongLen)
|
||||
nextHashS := hashLen(cv, betterShortTableBits, betterShortLen)
|
||||
|
||||
// We have at least 4 byte match.
|
||||
// No need to check backwards. We come straight from a match
|
||||
|
10
vendor/github.com/klauspost/compress/zstd/enc_dfast.go
generated
vendored
10
vendor/github.com/klauspost/compress/zstd/enc_dfast.go
generated
vendored
@ -127,8 +127,8 @@ encodeLoop:
|
||||
panic("offset0 was 0")
|
||||
}
|
||||
|
||||
nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
|
||||
nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
|
||||
nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
|
||||
candidateL := e.longTable[nextHashL]
|
||||
candidateS := e.table[nextHashS]
|
||||
|
||||
@ -439,8 +439,8 @@ encodeLoop:
|
||||
var t int32
|
||||
for {
|
||||
|
||||
nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
|
||||
nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
|
||||
nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
|
||||
candidateL := e.longTable[nextHashL]
|
||||
candidateS := e.table[nextHashS]
|
||||
|
||||
@ -785,8 +785,8 @@ encodeLoop:
|
||||
panic("offset0 was 0")
|
||||
}
|
||||
|
||||
nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
|
||||
nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
|
||||
nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
|
||||
candidateL := e.longTable[nextHashL]
|
||||
candidateS := e.table[nextHashS]
|
||||
|
||||
@ -969,7 +969,7 @@ encodeLoop:
|
||||
te0 := tableEntry{offset: index0 + e.cur, val: uint32(cv0)}
|
||||
te1 := tableEntry{offset: index1 + e.cur, val: uint32(cv1)}
|
||||
longHash1 := hashLen(cv0, dFastLongTableBits, dFastLongLen)
|
||||
longHash2 := hashLen(cv0, dFastLongTableBits, dFastLongLen)
|
||||
longHash2 := hashLen(cv1, dFastLongTableBits, dFastLongLen)
|
||||
e.longTable[longHash1] = te0
|
||||
e.longTable[longHash2] = te1
|
||||
e.markLongShardDirty(longHash1)
|
||||
@ -1002,8 +1002,8 @@ encodeLoop:
|
||||
}
|
||||
|
||||
// Store this, since we have it.
|
||||
nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
|
||||
nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
|
||||
nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
|
||||
|
||||
// We have at least 4 byte match.
|
||||
// No need to check backwards. We come straight from a match
|
||||
|
2
vendor/github.com/klauspost/compress/zstd/encoder.go
generated
vendored
2
vendor/github.com/klauspost/compress/zstd/encoder.go
generated
vendored
@ -551,7 +551,7 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
|
||||
}
|
||||
|
||||
// If we can do everything in one block, prefer that.
|
||||
if len(src) <= maxCompressedBlockSize {
|
||||
if len(src) <= e.o.blockSize {
|
||||
enc.Reset(e.o.dict, true)
|
||||
// Slightly faster with no history and everything in one block.
|
||||
if e.o.crc {
|
||||
|
5
vendor/github.com/klauspost/compress/zstd/framedec.go
generated
vendored
5
vendor/github.com/klauspost/compress/zstd/framedec.go
generated
vendored
@ -253,10 +253,11 @@ func (d *frameDec) reset(br byteBuffer) error {
|
||||
return ErrWindowSizeTooSmall
|
||||
}
|
||||
d.history.windowSize = int(d.WindowSize)
|
||||
if d.o.lowMem && d.history.windowSize < maxBlockSize {
|
||||
if !d.o.lowMem || d.history.windowSize < maxBlockSize {
|
||||
// Alloc 2x window size if not low-mem, or very small window size.
|
||||
d.history.allocFrameBuffer = d.history.windowSize * 2
|
||||
// TODO: Maybe use FrameContent size
|
||||
} else {
|
||||
// Alloc with one additional block
|
||||
d.history.allocFrameBuffer = d.history.windowSize + maxBlockSize
|
||||
}
|
||||
|
||||
|
40
vendor/github.com/klauspost/compress/zstd/fse_decoder.go
generated
vendored
40
vendor/github.com/klauspost/compress/zstd/fse_decoder.go
generated
vendored
@ -229,18 +229,10 @@ func (d decSymbol) newState() uint16 {
|
||||
return uint16(d >> 16)
|
||||
}
|
||||
|
||||
func (d decSymbol) baseline() uint32 {
|
||||
return uint32(d >> 32)
|
||||
}
|
||||
|
||||
func (d decSymbol) baselineInt() int {
|
||||
return int(d >> 32)
|
||||
}
|
||||
|
||||
func (d *decSymbol) set(nbits, addBits uint8, newState uint16, baseline uint32) {
|
||||
*d = decSymbol(nbits) | (decSymbol(addBits) << 8) | (decSymbol(newState) << 16) | (decSymbol(baseline) << 32)
|
||||
}
|
||||
|
||||
func (d *decSymbol) setNBits(nBits uint8) {
|
||||
const mask = 0xffffffffffffff00
|
||||
*d = (*d & mask) | decSymbol(nBits)
|
||||
@ -256,11 +248,6 @@ func (d *decSymbol) setNewState(state uint16) {
|
||||
*d = (*d & mask) | decSymbol(state)<<16
|
||||
}
|
||||
|
||||
func (d *decSymbol) setBaseline(baseline uint32) {
|
||||
const mask = 0xffffffff
|
||||
*d = (*d & mask) | decSymbol(baseline)<<32
|
||||
}
|
||||
|
||||
func (d *decSymbol) setExt(addBits uint8, baseline uint32) {
|
||||
const mask = 0xffff00ff
|
||||
*d = (*d & mask) | (decSymbol(addBits) << 8) | (decSymbol(baseline) << 32)
|
||||
@ -377,34 +364,7 @@ func (s *fseState) init(br *bitReader, tableLog uint8, dt []decSymbol) {
|
||||
s.state = dt[br.getBits(tableLog)]
|
||||
}
|
||||
|
||||
// next returns the current symbol and sets the next state.
|
||||
// At least tablelog bits must be available in the bit reader.
|
||||
func (s *fseState) next(br *bitReader) {
|
||||
lowBits := uint16(br.getBits(s.state.nbBits()))
|
||||
s.state = s.dt[s.state.newState()+lowBits]
|
||||
}
|
||||
|
||||
// finished returns true if all bits have been read from the bitstream
|
||||
// and the next state would require reading bits from the input.
|
||||
func (s *fseState) finished(br *bitReader) bool {
|
||||
return br.finished() && s.state.nbBits() > 0
|
||||
}
|
||||
|
||||
// final returns the current state symbol without decoding the next.
|
||||
func (s *fseState) final() (int, uint8) {
|
||||
return s.state.baselineInt(), s.state.addBits()
|
||||
}
|
||||
|
||||
// final returns the current state symbol without decoding the next.
|
||||
func (s decSymbol) final() (int, uint8) {
|
||||
return s.baselineInt(), s.addBits()
|
||||
}
|
||||
|
||||
// nextFast returns the next symbol and sets the next state.
|
||||
// This can only be used if no symbols are 0 bits.
|
||||
// At least tablelog bits must be available in the bit reader.
|
||||
func (s *fseState) nextFast(br *bitReader) (uint32, uint8) {
|
||||
lowBits := br.get16BitsFast(s.state.nbBits())
|
||||
s.state = s.dt[s.state.newState()+lowBits]
|
||||
return s.state.baseline(), s.state.addBits()
|
||||
}
|
||||
|
23
vendor/github.com/klauspost/compress/zstd/fse_encoder.go
generated
vendored
23
vendor/github.com/klauspost/compress/zstd/fse_encoder.go
generated
vendored
@ -76,21 +76,6 @@ func (s *fseEncoder) HistogramFinished(maxSymbol uint8, maxCount int) {
|
||||
s.clearCount = maxCount != 0
|
||||
}
|
||||
|
||||
// prepare will prepare and allocate scratch tables used for both compression and decompression.
|
||||
func (s *fseEncoder) prepare() (*fseEncoder, error) {
|
||||
if s == nil {
|
||||
s = &fseEncoder{}
|
||||
}
|
||||
s.useRLE = false
|
||||
if s.clearCount && s.maxCount == 0 {
|
||||
for i := range s.count {
|
||||
s.count[i] = 0
|
||||
}
|
||||
s.clearCount = false
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// allocCtable will allocate tables needed for compression.
|
||||
// If existing tables a re big enough, they are simply re-used.
|
||||
func (s *fseEncoder) allocCtable() {
|
||||
@ -709,14 +694,6 @@ func (c *cState) init(bw *bitWriter, ct *cTable, first symbolTransform) {
|
||||
c.state = c.stateTable[lu]
|
||||
}
|
||||
|
||||
// encode the output symbol provided and write it to the bitstream.
|
||||
func (c *cState) encode(symbolTT symbolTransform) {
|
||||
nbBitsOut := (uint32(c.state) + symbolTT.deltaNbBits) >> 16
|
||||
dstState := int32(c.state>>(nbBitsOut&15)) + int32(symbolTT.deltaFindState)
|
||||
c.bw.addBits16NC(c.state, uint8(nbBitsOut))
|
||||
c.state = c.stateTable[dstState]
|
||||
}
|
||||
|
||||
// flush will write the tablelog to the output and flush the remaining full bytes.
|
||||
func (c *cState) flush(tableLog uint8) {
|
||||
c.bw.flush32()
|
||||
|
6
vendor/github.com/klauspost/compress/zstd/hash.go
generated
vendored
6
vendor/github.com/klauspost/compress/zstd/hash.go
generated
vendored
@ -33,9 +33,3 @@ func hashLen(u uint64, length, mls uint8) uint32 {
|
||||
return (uint32(u) * prime4bytes) >> (32 - length)
|
||||
}
|
||||
}
|
||||
|
||||
// hash3 returns the hash of the lower 3 bytes of u to fit in a hash table with h bits.
|
||||
// Preferably h should be a constant and should always be <32.
|
||||
func hash3(u uint32, h uint8) uint32 {
|
||||
return ((u << (32 - 24)) * prime3bytes) >> ((32 - h) & 31)
|
||||
}
|
||||
|
102
vendor/github.com/klauspost/compress/zstd/seqdec.go
generated
vendored
102
vendor/github.com/klauspost/compress/zstd/seqdec.go
generated
vendored
@ -188,6 +188,7 @@ func (s *sequenceDecs) execute(seqs []seqVals, hist []byte) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add final literals
|
||||
copy(out[t:], s.literals)
|
||||
if debugDecoder {
|
||||
@ -203,12 +204,11 @@ func (s *sequenceDecs) execute(seqs []seqVals, hist []byte) error {
|
||||
|
||||
// decode sequences from the stream with the provided history.
|
||||
func (s *sequenceDecs) decodeSync(hist []byte) error {
|
||||
if true {
|
||||
supported, err := s.decodeSyncSimple(hist)
|
||||
if supported {
|
||||
return err
|
||||
}
|
||||
supported, err := s.decodeSyncSimple(hist)
|
||||
if supported {
|
||||
return err
|
||||
}
|
||||
|
||||
br := s.br
|
||||
seqs := s.nSeqs
|
||||
startSize := len(s.out)
|
||||
@ -396,6 +396,7 @@ func (s *sequenceDecs) decodeSync(hist []byte) error {
|
||||
ofState = ofTable[ofState.newState()&maxTableMask]
|
||||
} else {
|
||||
bits := br.get32BitsFast(nBits)
|
||||
|
||||
lowBits := uint16(bits >> ((ofState.nbBits() + mlState.nbBits()) & 31))
|
||||
llState = llTable[(llState.newState()+lowBits)&maxTableMask]
|
||||
|
||||
@ -418,16 +419,6 @@ func (s *sequenceDecs) decodeSync(hist []byte) error {
|
||||
return br.close()
|
||||
}
|
||||
|
||||
// update states, at least 27 bits must be available.
|
||||
func (s *sequenceDecs) update(br *bitReader) {
|
||||
// Max 8 bits
|
||||
s.litLengths.state.next(br)
|
||||
// Max 9 bits
|
||||
s.matchLengths.state.next(br)
|
||||
// Max 8 bits
|
||||
s.offsets.state.next(br)
|
||||
}
|
||||
|
||||
var bitMask [16]uint16
|
||||
|
||||
func init() {
|
||||
@ -436,87 +427,6 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
// update states, at least 27 bits must be available.
|
||||
func (s *sequenceDecs) updateAlt(br *bitReader) {
|
||||
// Update all 3 states at once. Approx 20% faster.
|
||||
a, b, c := s.litLengths.state.state, s.matchLengths.state.state, s.offsets.state.state
|
||||
|
||||
nBits := a.nbBits() + b.nbBits() + c.nbBits()
|
||||
if nBits == 0 {
|
||||
s.litLengths.state.state = s.litLengths.state.dt[a.newState()]
|
||||
s.matchLengths.state.state = s.matchLengths.state.dt[b.newState()]
|
||||
s.offsets.state.state = s.offsets.state.dt[c.newState()]
|
||||
return
|
||||
}
|
||||
bits := br.get32BitsFast(nBits)
|
||||
lowBits := uint16(bits >> ((c.nbBits() + b.nbBits()) & 31))
|
||||
s.litLengths.state.state = s.litLengths.state.dt[a.newState()+lowBits]
|
||||
|
||||
lowBits = uint16(bits >> (c.nbBits() & 31))
|
||||
lowBits &= bitMask[b.nbBits()&15]
|
||||
s.matchLengths.state.state = s.matchLengths.state.dt[b.newState()+lowBits]
|
||||
|
||||
lowBits = uint16(bits) & bitMask[c.nbBits()&15]
|
||||
s.offsets.state.state = s.offsets.state.dt[c.newState()+lowBits]
|
||||
}
|
||||
|
||||
// nextFast will return new states when there are at least 4 unused bytes left on the stream when done.
|
||||
func (s *sequenceDecs) nextFast(br *bitReader, llState, mlState, ofState decSymbol) (ll, mo, ml int) {
|
||||
// Final will not read from stream.
|
||||
ll, llB := llState.final()
|
||||
ml, mlB := mlState.final()
|
||||
mo, moB := ofState.final()
|
||||
|
||||
// extra bits are stored in reverse order.
|
||||
br.fillFast()
|
||||
mo += br.getBits(moB)
|
||||
if s.maxBits > 32 {
|
||||
br.fillFast()
|
||||
}
|
||||
ml += br.getBits(mlB)
|
||||
ll += br.getBits(llB)
|
||||
|
||||
if moB > 1 {
|
||||
s.prevOffset[2] = s.prevOffset[1]
|
||||
s.prevOffset[1] = s.prevOffset[0]
|
||||
s.prevOffset[0] = mo
|
||||
return
|
||||
}
|
||||
// mo = s.adjustOffset(mo, ll, moB)
|
||||
// Inlined for rather big speedup
|
||||
if ll == 0 {
|
||||
// There is an exception though, when current sequence's literals_length = 0.
|
||||
// In this case, repeated offsets are shifted by one, so an offset_value of 1 means Repeated_Offset2,
|
||||
// an offset_value of 2 means Repeated_Offset3, and an offset_value of 3 means Repeated_Offset1 - 1_byte.
|
||||
mo++
|
||||
}
|
||||
|
||||
if mo == 0 {
|
||||
mo = s.prevOffset[0]
|
||||
return
|
||||
}
|
||||
var temp int
|
||||
if mo == 3 {
|
||||
temp = s.prevOffset[0] - 1
|
||||
} else {
|
||||
temp = s.prevOffset[mo]
|
||||
}
|
||||
|
||||
if temp == 0 {
|
||||
// 0 is not valid; input is corrupted; force offset to 1
|
||||
println("temp was 0")
|
||||
temp = 1
|
||||
}
|
||||
|
||||
if mo != 1 {
|
||||
s.prevOffset[2] = s.prevOffset[1]
|
||||
}
|
||||
s.prevOffset[1] = s.prevOffset[0]
|
||||
s.prevOffset[0] = temp
|
||||
mo = temp
|
||||
return
|
||||
}
|
||||
|
||||
func (s *sequenceDecs) next(br *bitReader, llState, mlState, ofState decSymbol) (ll, mo, ml int) {
|
||||
// Final will not read from stream.
|
||||
ll, llB := llState.final()
|
||||
|
16
vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go
generated
vendored
16
vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go
generated
vendored
@ -62,6 +62,10 @@ func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) {
|
||||
if s.maxSyncLen > 0 && cap(s.out)-len(s.out)-compressedBlockOverAlloc < int(s.maxSyncLen) {
|
||||
useSafe = true
|
||||
}
|
||||
if cap(s.literals) < len(s.literals)+compressedBlockOverAlloc {
|
||||
useSafe = true
|
||||
}
|
||||
|
||||
br := s.br
|
||||
|
||||
maxBlockSize := maxCompressedBlockSize
|
||||
@ -301,6 +305,10 @@ type executeAsmContext struct {
|
||||
//go:noescape
|
||||
func sequenceDecs_executeSimple_amd64(ctx *executeAsmContext) bool
|
||||
|
||||
// Same as above, but with safe memcopies
|
||||
//go:noescape
|
||||
func sequenceDecs_executeSimple_safe_amd64(ctx *executeAsmContext) bool
|
||||
|
||||
// executeSimple handles cases when dictionary is not used.
|
||||
func (s *sequenceDecs) executeSimple(seqs []seqVals, hist []byte) error {
|
||||
// Ensure we have enough output size...
|
||||
@ -327,8 +335,12 @@ func (s *sequenceDecs) executeSimple(seqs []seqVals, hist []byte) error {
|
||||
literals: s.literals,
|
||||
windowSize: s.windowSize,
|
||||
}
|
||||
|
||||
ok := sequenceDecs_executeSimple_amd64(&ctx)
|
||||
var ok bool
|
||||
if cap(s.literals) < len(s.literals)+compressedBlockOverAlloc {
|
||||
ok = sequenceDecs_executeSimple_safe_amd64(&ctx)
|
||||
} else {
|
||||
ok = sequenceDecs_executeSimple_amd64(&ctx)
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("match offset (%d) bigger than current history (%d)",
|
||||
seqs[ctx.seqIndex].mo, ctx.outPosition+len(hist))
|
||||
|
622
vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s
generated
vendored
622
vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s
generated
vendored
@ -705,60 +705,55 @@ sequenceDecs_decode_bmi2_fill_2_end:
|
||||
MOVQ CX, (R9)
|
||||
|
||||
// Fill bitreader for state updates
|
||||
MOVQ R13, (SP)
|
||||
MOVQ $0x00000808, CX
|
||||
BEXTRQ CX, R8, R13
|
||||
MOVQ ctx+16(FP), CX
|
||||
CMPQ 96(CX), $0x00
|
||||
JZ sequenceDecs_decode_bmi2_skip_update
|
||||
|
||||
// Update Literal Length State
|
||||
MOVBQZX SI, R14
|
||||
MOVQ $0x00001010, CX
|
||||
BEXTRQ CX, SI, SI
|
||||
MOVQ R13, (SP)
|
||||
MOVQ $0x00000808, CX
|
||||
BEXTRQ CX, R8, R13
|
||||
MOVQ ctx+16(FP), CX
|
||||
CMPQ 96(CX), $0x00
|
||||
JZ sequenceDecs_decode_bmi2_skip_update
|
||||
LEAQ (SI)(DI*1), R14
|
||||
ADDQ R8, R14
|
||||
MOVBQZX R14, R14
|
||||
LEAQ (DX)(R14*1), CX
|
||||
MOVQ AX, R15
|
||||
MOVQ CX, DX
|
||||
ROLQ CL, R15
|
||||
BZHIQ R14, R15, R15
|
||||
ADDQ R15, SI
|
||||
|
||||
// Load ctx.llTable
|
||||
// Update Offset State
|
||||
BZHIQ R8, R15, CX
|
||||
SHRXQ R8, R15, R15
|
||||
MOVQ $0x00001010, R14
|
||||
BEXTRQ R14, R8, R8
|
||||
ADDQ CX, R8
|
||||
|
||||
// Load ctx.ofTable
|
||||
MOVQ ctx+16(FP), CX
|
||||
MOVQ (CX), CX
|
||||
MOVQ (CX)(SI*8), SI
|
||||
MOVQ 48(CX), CX
|
||||
MOVQ (CX)(R8*8), R8
|
||||
|
||||
// Update Match Length State
|
||||
MOVBQZX DI, R14
|
||||
MOVQ $0x00001010, CX
|
||||
BEXTRQ CX, DI, DI
|
||||
LEAQ (DX)(R14*1), CX
|
||||
MOVQ AX, R15
|
||||
MOVQ CX, DX
|
||||
ROLQ CL, R15
|
||||
BZHIQ R14, R15, R15
|
||||
ADDQ R15, DI
|
||||
BZHIQ DI, R15, CX
|
||||
SHRXQ DI, R15, R15
|
||||
MOVQ $0x00001010, R14
|
||||
BEXTRQ R14, DI, DI
|
||||
ADDQ CX, DI
|
||||
|
||||
// Load ctx.mlTable
|
||||
MOVQ ctx+16(FP), CX
|
||||
MOVQ 24(CX), CX
|
||||
MOVQ (CX)(DI*8), DI
|
||||
|
||||
// Update Offset State
|
||||
MOVBQZX R8, R14
|
||||
MOVQ $0x00001010, CX
|
||||
BEXTRQ CX, R8, R8
|
||||
LEAQ (DX)(R14*1), CX
|
||||
MOVQ AX, R15
|
||||
MOVQ CX, DX
|
||||
ROLQ CL, R15
|
||||
BZHIQ R14, R15, R15
|
||||
ADDQ R15, R8
|
||||
// Update Literal Length State
|
||||
BZHIQ SI, R15, CX
|
||||
MOVQ $0x00001010, R14
|
||||
BEXTRQ R14, SI, SI
|
||||
ADDQ CX, SI
|
||||
|
||||
// Load ctx.ofTable
|
||||
// Load ctx.llTable
|
||||
MOVQ ctx+16(FP), CX
|
||||
MOVQ 48(CX), CX
|
||||
MOVQ (CX)(R8*8), R8
|
||||
MOVQ (CX), CX
|
||||
MOVQ (CX)(SI*8), SI
|
||||
|
||||
sequenceDecs_decode_bmi2_skip_update:
|
||||
// Adjust offset
|
||||
@ -965,60 +960,55 @@ sequenceDecs_decode_56_bmi2_fill_end:
|
||||
MOVQ CX, (R9)
|
||||
|
||||
// Fill bitreader for state updates
|
||||
MOVQ R13, (SP)
|
||||
MOVQ $0x00000808, CX
|
||||
BEXTRQ CX, R8, R13
|
||||
MOVQ ctx+16(FP), CX
|
||||
CMPQ 96(CX), $0x00
|
||||
JZ sequenceDecs_decode_56_bmi2_skip_update
|
||||
|
||||
// Update Literal Length State
|
||||
MOVBQZX SI, R14
|
||||
MOVQ $0x00001010, CX
|
||||
BEXTRQ CX, SI, SI
|
||||
MOVQ R13, (SP)
|
||||
MOVQ $0x00000808, CX
|
||||
BEXTRQ CX, R8, R13
|
||||
MOVQ ctx+16(FP), CX
|
||||
CMPQ 96(CX), $0x00
|
||||
JZ sequenceDecs_decode_56_bmi2_skip_update
|
||||
LEAQ (SI)(DI*1), R14
|
||||
ADDQ R8, R14
|
||||
MOVBQZX R14, R14
|
||||
LEAQ (DX)(R14*1), CX
|
||||
MOVQ AX, R15
|
||||
MOVQ CX, DX
|
||||
ROLQ CL, R15
|
||||
BZHIQ R14, R15, R15
|
||||
ADDQ R15, SI
|
||||
|
||||
// Load ctx.llTable
|
||||
// Update Offset State
|
||||
BZHIQ R8, R15, CX
|
||||
SHRXQ R8, R15, R15
|
||||
MOVQ $0x00001010, R14
|
||||
BEXTRQ R14, R8, R8
|
||||
ADDQ CX, R8
|
||||
|
||||
// Load ctx.ofTable
|
||||
MOVQ ctx+16(FP), CX
|
||||
MOVQ (CX), CX
|
||||
MOVQ (CX)(SI*8), SI
|
||||
MOVQ 48(CX), CX
|
||||
MOVQ (CX)(R8*8), R8
|
||||
|
||||
// Update Match Length State
|
||||
MOVBQZX DI, R14
|
||||
MOVQ $0x00001010, CX
|
||||
BEXTRQ CX, DI, DI
|
||||
LEAQ (DX)(R14*1), CX
|
||||
MOVQ AX, R15
|
||||
MOVQ CX, DX
|
||||
ROLQ CL, R15
|
||||
BZHIQ R14, R15, R15
|
||||
ADDQ R15, DI
|
||||
BZHIQ DI, R15, CX
|
||||
SHRXQ DI, R15, R15
|
||||
MOVQ $0x00001010, R14
|
||||
BEXTRQ R14, DI, DI
|
||||
ADDQ CX, DI
|
||||
|
||||
// Load ctx.mlTable
|
||||
MOVQ ctx+16(FP), CX
|
||||
MOVQ 24(CX), CX
|
||||
MOVQ (CX)(DI*8), DI
|
||||
|
||||
// Update Offset State
|
||||
MOVBQZX R8, R14
|
||||
MOVQ $0x00001010, CX
|
||||
BEXTRQ CX, R8, R8
|
||||
LEAQ (DX)(R14*1), CX
|
||||
MOVQ AX, R15
|
||||
MOVQ CX, DX
|
||||
ROLQ CL, R15
|
||||
BZHIQ R14, R15, R15
|
||||
ADDQ R15, R8
|
||||
// Update Literal Length State
|
||||
BZHIQ SI, R15, CX
|
||||
MOVQ $0x00001010, R14
|
||||
BEXTRQ R14, SI, SI
|
||||
ADDQ CX, SI
|
||||
|
||||
// Load ctx.ofTable
|
||||
// Load ctx.llTable
|
||||
MOVQ ctx+16(FP), CX
|
||||
MOVQ 48(CX), CX
|
||||
MOVQ (CX)(R8*8), R8
|
||||
MOVQ (CX), CX
|
||||
MOVQ (CX)(SI*8), SI
|
||||
|
||||
sequenceDecs_decode_56_bmi2_skip_update:
|
||||
// Adjust offset
|
||||
@ -1162,6 +1152,228 @@ TEXT ·sequenceDecs_executeSimple_amd64(SB), $8-9
|
||||
// outBase += outPosition
|
||||
ADDQ DI, BX
|
||||
|
||||
main_loop:
|
||||
MOVQ (AX), R11
|
||||
MOVQ 16(AX), R12
|
||||
MOVQ 8(AX), R13
|
||||
|
||||
// Copy literals
|
||||
TESTQ R11, R11
|
||||
JZ check_offset
|
||||
XORQ R14, R14
|
||||
|
||||
copy_1:
|
||||
MOVUPS (SI)(R14*1), X0
|
||||
MOVUPS X0, (BX)(R14*1)
|
||||
ADDQ $0x10, R14
|
||||
CMPQ R14, R11
|
||||
JB copy_1
|
||||
ADDQ R11, SI
|
||||
ADDQ R11, BX
|
||||
ADDQ R11, DI
|
||||
|
||||
// Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize)
|
||||
check_offset:
|
||||
LEAQ (DI)(R10*1), R11
|
||||
CMPQ R12, R11
|
||||
JG error_match_off_too_big
|
||||
CMPQ R12, R8
|
||||
JG error_match_off_too_big
|
||||
|
||||
// Copy match from history
|
||||
MOVQ R12, R11
|
||||
SUBQ DI, R11
|
||||
JLS copy_match
|
||||
MOVQ R9, R14
|
||||
SUBQ R11, R14
|
||||
CMPQ R13, R11
|
||||
JGE copy_all_from_history
|
||||
XORQ R11, R11
|
||||
TESTQ $0x00000001, R13
|
||||
JZ copy_4_word
|
||||
MOVB (R14)(R11*1), R12
|
||||
MOVB R12, (BX)(R11*1)
|
||||
ADDQ $0x01, R11
|
||||
|
||||
copy_4_word:
|
||||
TESTQ $0x00000002, R13
|
||||
JZ copy_4_dword
|
||||
MOVW (R14)(R11*1), R12
|
||||
MOVW R12, (BX)(R11*1)
|
||||
ADDQ $0x02, R11
|
||||
|
||||
copy_4_dword:
|
||||
TESTQ $0x00000004, R13
|
||||
JZ copy_4_qword
|
||||
MOVL (R14)(R11*1), R12
|
||||
MOVL R12, (BX)(R11*1)
|
||||
ADDQ $0x04, R11
|
||||
|
||||
copy_4_qword:
|
||||
TESTQ $0x00000008, R13
|
||||
JZ copy_4_test
|
||||
MOVQ (R14)(R11*1), R12
|
||||
MOVQ R12, (BX)(R11*1)
|
||||
ADDQ $0x08, R11
|
||||
JMP copy_4_test
|
||||
|
||||
copy_4:
|
||||
MOVUPS (R14)(R11*1), X0
|
||||
MOVUPS X0, (BX)(R11*1)
|
||||
ADDQ $0x10, R11
|
||||
|
||||
copy_4_test:
|
||||
CMPQ R11, R13
|
||||
JB copy_4
|
||||
ADDQ R13, DI
|
||||
ADDQ R13, BX
|
||||
ADDQ $0x18, AX
|
||||
INCQ DX
|
||||
CMPQ DX, CX
|
||||
JB main_loop
|
||||
JMP loop_finished
|
||||
|
||||
copy_all_from_history:
|
||||
XORQ R15, R15
|
||||
TESTQ $0x00000001, R11
|
||||
JZ copy_5_word
|
||||
MOVB (R14)(R15*1), BP
|
||||
MOVB BP, (BX)(R15*1)
|
||||
ADDQ $0x01, R15
|
||||
|
||||
copy_5_word:
|
||||
TESTQ $0x00000002, R11
|
||||
JZ copy_5_dword
|
||||
MOVW (R14)(R15*1), BP
|
||||
MOVW BP, (BX)(R15*1)
|
||||
ADDQ $0x02, R15
|
||||
|
||||
copy_5_dword:
|
||||
TESTQ $0x00000004, R11
|
||||
JZ copy_5_qword
|
||||
MOVL (R14)(R15*1), BP
|
||||
MOVL BP, (BX)(R15*1)
|
||||
ADDQ $0x04, R15
|
||||
|
||||
copy_5_qword:
|
||||
TESTQ $0x00000008, R11
|
||||
JZ copy_5_test
|
||||
MOVQ (R14)(R15*1), BP
|
||||
MOVQ BP, (BX)(R15*1)
|
||||
ADDQ $0x08, R15
|
||||
JMP copy_5_test
|
||||
|
||||
copy_5:
|
||||
MOVUPS (R14)(R15*1), X0
|
||||
MOVUPS X0, (BX)(R15*1)
|
||||
ADDQ $0x10, R15
|
||||
|
||||
copy_5_test:
|
||||
CMPQ R15, R11
|
||||
JB copy_5
|
||||
ADDQ R11, BX
|
||||
ADDQ R11, DI
|
||||
SUBQ R11, R13
|
||||
|
||||
// Copy match from the current buffer
|
||||
copy_match:
|
||||
TESTQ R13, R13
|
||||
JZ handle_loop
|
||||
MOVQ BX, R11
|
||||
SUBQ R12, R11
|
||||
|
||||
// ml <= mo
|
||||
CMPQ R13, R12
|
||||
JA copy_overlapping_match
|
||||
|
||||
// Copy non-overlapping match
|
||||
ADDQ R13, DI
|
||||
MOVQ BX, R12
|
||||
ADDQ R13, BX
|
||||
|
||||
copy_2:
|
||||
MOVUPS (R11), X0
|
||||
MOVUPS X0, (R12)
|
||||
ADDQ $0x10, R11
|
||||
ADDQ $0x10, R12
|
||||
SUBQ $0x10, R13
|
||||
JHI copy_2
|
||||
JMP handle_loop
|
||||
|
||||
// Copy overlapping match
|
||||
copy_overlapping_match:
|
||||
ADDQ R13, DI
|
||||
|
||||
copy_slow_3:
|
||||
MOVB (R11), R12
|
||||
MOVB R12, (BX)
|
||||
INCQ R11
|
||||
INCQ BX
|
||||
DECQ R13
|
||||
JNZ copy_slow_3
|
||||
|
||||
handle_loop:
|
||||
ADDQ $0x18, AX
|
||||
INCQ DX
|
||||
CMPQ DX, CX
|
||||
JB main_loop
|
||||
|
||||
loop_finished:
|
||||
// Return value
|
||||
MOVB $0x01, ret+8(FP)
|
||||
|
||||
// Update the context
|
||||
MOVQ ctx+0(FP), AX
|
||||
MOVQ DX, 24(AX)
|
||||
MOVQ DI, 104(AX)
|
||||
MOVQ 80(AX), CX
|
||||
SUBQ CX, SI
|
||||
MOVQ SI, 112(AX)
|
||||
RET
|
||||
|
||||
error_match_off_too_big:
|
||||
// Return value
|
||||
MOVB $0x00, ret+8(FP)
|
||||
|
||||
// Update the context
|
||||
MOVQ ctx+0(FP), AX
|
||||
MOVQ DX, 24(AX)
|
||||
MOVQ DI, 104(AX)
|
||||
MOVQ 80(AX), CX
|
||||
SUBQ CX, SI
|
||||
MOVQ SI, 112(AX)
|
||||
RET
|
||||
|
||||
empty_seqs:
|
||||
// Return value
|
||||
MOVB $0x01, ret+8(FP)
|
||||
RET
|
||||
|
||||
// func sequenceDecs_executeSimple_safe_amd64(ctx *executeAsmContext) bool
|
||||
// Requires: SSE
|
||||
TEXT ·sequenceDecs_executeSimple_safe_amd64(SB), $8-9
|
||||
MOVQ ctx+0(FP), R10
|
||||
MOVQ 8(R10), CX
|
||||
TESTQ CX, CX
|
||||
JZ empty_seqs
|
||||
MOVQ (R10), AX
|
||||
MOVQ 24(R10), DX
|
||||
MOVQ 32(R10), BX
|
||||
MOVQ 80(R10), SI
|
||||
MOVQ 104(R10), DI
|
||||
MOVQ 120(R10), R8
|
||||
MOVQ 56(R10), R9
|
||||
MOVQ 64(R10), R10
|
||||
ADDQ R10, R9
|
||||
|
||||
// seqsBase += 24 * seqIndex
|
||||
LEAQ (DX)(DX*2), R11
|
||||
SHLQ $0x03, R11
|
||||
ADDQ R11, AX
|
||||
|
||||
// outBase += outPosition
|
||||
ADDQ DI, BX
|
||||
|
||||
main_loop:
|
||||
MOVQ (AX), R11
|
||||
MOVQ 16(AX), R12
|
||||
@ -1326,18 +1538,46 @@ copy_match:
|
||||
JA copy_overlapping_match
|
||||
|
||||
// Copy non-overlapping match
|
||||
ADDQ R13, DI
|
||||
MOVQ BX, R12
|
||||
ADDQ R13, BX
|
||||
ADDQ R13, DI
|
||||
XORQ R12, R12
|
||||
TESTQ $0x00000001, R13
|
||||
JZ copy_2_word
|
||||
MOVB (R11)(R12*1), R14
|
||||
MOVB R14, (BX)(R12*1)
|
||||
ADDQ $0x01, R12
|
||||
|
||||
copy_2_word:
|
||||
TESTQ $0x00000002, R13
|
||||
JZ copy_2_dword
|
||||
MOVW (R11)(R12*1), R14
|
||||
MOVW R14, (BX)(R12*1)
|
||||
ADDQ $0x02, R12
|
||||
|
||||
copy_2_dword:
|
||||
TESTQ $0x00000004, R13
|
||||
JZ copy_2_qword
|
||||
MOVL (R11)(R12*1), R14
|
||||
MOVL R14, (BX)(R12*1)
|
||||
ADDQ $0x04, R12
|
||||
|
||||
copy_2_qword:
|
||||
TESTQ $0x00000008, R13
|
||||
JZ copy_2_test
|
||||
MOVQ (R11)(R12*1), R14
|
||||
MOVQ R14, (BX)(R12*1)
|
||||
ADDQ $0x08, R12
|
||||
JMP copy_2_test
|
||||
|
||||
copy_2:
|
||||
MOVUPS (R11), X0
|
||||
MOVUPS X0, (R12)
|
||||
ADDQ $0x10, R11
|
||||
MOVUPS (R11)(R12*1), X0
|
||||
MOVUPS X0, (BX)(R12*1)
|
||||
ADDQ $0x10, R12
|
||||
SUBQ $0x10, R13
|
||||
JHI copy_2
|
||||
JMP handle_loop
|
||||
|
||||
copy_2_test:
|
||||
CMPQ R12, R13
|
||||
JB copy_2
|
||||
ADDQ R13, BX
|
||||
JMP handle_loop
|
||||
|
||||
// Copy overlapping match
|
||||
copy_overlapping_match:
|
||||
@ -1673,45 +1913,16 @@ sequenceDecs_decodeSync_amd64_match_len_ofs_ok:
|
||||
TESTQ AX, AX
|
||||
JZ check_offset
|
||||
XORQ R14, R14
|
||||
TESTQ $0x00000001, AX
|
||||
JZ copy_1_word
|
||||
MOVB (R11)(R14*1), R15
|
||||
MOVB R15, (R10)(R14*1)
|
||||
ADDQ $0x01, R14
|
||||
|
||||
copy_1_word:
|
||||
TESTQ $0x00000002, AX
|
||||
JZ copy_1_dword
|
||||
MOVW (R11)(R14*1), R15
|
||||
MOVW R15, (R10)(R14*1)
|
||||
ADDQ $0x02, R14
|
||||
|
||||
copy_1_dword:
|
||||
TESTQ $0x00000004, AX
|
||||
JZ copy_1_qword
|
||||
MOVL (R11)(R14*1), R15
|
||||
MOVL R15, (R10)(R14*1)
|
||||
ADDQ $0x04, R14
|
||||
|
||||
copy_1_qword:
|
||||
TESTQ $0x00000008, AX
|
||||
JZ copy_1_test
|
||||
MOVQ (R11)(R14*1), R15
|
||||
MOVQ R15, (R10)(R14*1)
|
||||
ADDQ $0x08, R14
|
||||
JMP copy_1_test
|
||||
|
||||
copy_1:
|
||||
MOVUPS (R11)(R14*1), X0
|
||||
MOVUPS X0, (R10)(R14*1)
|
||||
ADDQ $0x10, R14
|
||||
|
||||
copy_1_test:
|
||||
CMPQ R14, AX
|
||||
JB copy_1
|
||||
ADDQ AX, R11
|
||||
ADDQ AX, R10
|
||||
ADDQ AX, R12
|
||||
CMPQ R14, AX
|
||||
JB copy_1
|
||||
ADDQ AX, R11
|
||||
ADDQ AX, R10
|
||||
ADDQ AX, R12
|
||||
|
||||
// Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize)
|
||||
check_offset:
|
||||
@ -2044,60 +2255,55 @@ sequenceDecs_decodeSync_bmi2_fill_2_end:
|
||||
MOVQ CX, 24(SP)
|
||||
|
||||
// Fill bitreader for state updates
|
||||
MOVQ R12, (SP)
|
||||
MOVQ $0x00000808, CX
|
||||
BEXTRQ CX, R8, R12
|
||||
MOVQ ctx+16(FP), CX
|
||||
CMPQ 96(CX), $0x00
|
||||
JZ sequenceDecs_decodeSync_bmi2_skip_update
|
||||
|
||||
// Update Literal Length State
|
||||
MOVBQZX SI, R13
|
||||
MOVQ $0x00001010, CX
|
||||
BEXTRQ CX, SI, SI
|
||||
MOVQ R12, (SP)
|
||||
MOVQ $0x00000808, CX
|
||||
BEXTRQ CX, R8, R12
|
||||
MOVQ ctx+16(FP), CX
|
||||
CMPQ 96(CX), $0x00
|
||||
JZ sequenceDecs_decodeSync_bmi2_skip_update
|
||||
LEAQ (SI)(DI*1), R13
|
||||
ADDQ R8, R13
|
||||
MOVBQZX R13, R13
|
||||
LEAQ (DX)(R13*1), CX
|
||||
MOVQ AX, R14
|
||||
MOVQ CX, DX
|
||||
ROLQ CL, R14
|
||||
BZHIQ R13, R14, R14
|
||||
ADDQ R14, SI
|
||||
|
||||
// Load ctx.llTable
|
||||
// Update Offset State
|
||||
BZHIQ R8, R14, CX
|
||||
SHRXQ R8, R14, R14
|
||||
MOVQ $0x00001010, R13
|
||||
BEXTRQ R13, R8, R8
|
||||
ADDQ CX, R8
|
||||
|
||||
// Load ctx.ofTable
|
||||
MOVQ ctx+16(FP), CX
|
||||
MOVQ (CX), CX
|
||||
MOVQ (CX)(SI*8), SI
|
||||
MOVQ 48(CX), CX
|
||||
MOVQ (CX)(R8*8), R8
|
||||
|
||||
// Update Match Length State
|
||||
MOVBQZX DI, R13
|
||||
MOVQ $0x00001010, CX
|
||||
BEXTRQ CX, DI, DI
|
||||
LEAQ (DX)(R13*1), CX
|
||||
MOVQ AX, R14
|
||||
MOVQ CX, DX
|
||||
ROLQ CL, R14
|
||||
BZHIQ R13, R14, R14
|
||||
ADDQ R14, DI
|
||||
BZHIQ DI, R14, CX
|
||||
SHRXQ DI, R14, R14
|
||||
MOVQ $0x00001010, R13
|
||||
BEXTRQ R13, DI, DI
|
||||
ADDQ CX, DI
|
||||
|
||||
// Load ctx.mlTable
|
||||
MOVQ ctx+16(FP), CX
|
||||
MOVQ 24(CX), CX
|
||||
MOVQ (CX)(DI*8), DI
|
||||
|
||||
// Update Offset State
|
||||
MOVBQZX R8, R13
|
||||
MOVQ $0x00001010, CX
|
||||
BEXTRQ CX, R8, R8
|
||||
LEAQ (DX)(R13*1), CX
|
||||
MOVQ AX, R14
|
||||
MOVQ CX, DX
|
||||
ROLQ CL, R14
|
||||
BZHIQ R13, R14, R14
|
||||
ADDQ R14, R8
|
||||
// Update Literal Length State
|
||||
BZHIQ SI, R14, CX
|
||||
MOVQ $0x00001010, R13
|
||||
BEXTRQ R13, SI, SI
|
||||
ADDQ CX, SI
|
||||
|
||||
// Load ctx.ofTable
|
||||
// Load ctx.llTable
|
||||
MOVQ ctx+16(FP), CX
|
||||
MOVQ 48(CX), CX
|
||||
MOVQ (CX)(R8*8), R8
|
||||
MOVQ (CX), CX
|
||||
MOVQ (CX)(SI*8), SI
|
||||
|
||||
sequenceDecs_decodeSync_bmi2_skip_update:
|
||||
// Adjust offset
|
||||
@ -2180,45 +2386,16 @@ sequenceDecs_decodeSync_bmi2_match_len_ofs_ok:
|
||||
TESTQ CX, CX
|
||||
JZ check_offset
|
||||
XORQ R14, R14
|
||||
TESTQ $0x00000001, CX
|
||||
JZ copy_1_word
|
||||
MOVB (R10)(R14*1), R15
|
||||
MOVB R15, (R9)(R14*1)
|
||||
ADDQ $0x01, R14
|
||||
|
||||
copy_1_word:
|
||||
TESTQ $0x00000002, CX
|
||||
JZ copy_1_dword
|
||||
MOVW (R10)(R14*1), R15
|
||||
MOVW R15, (R9)(R14*1)
|
||||
ADDQ $0x02, R14
|
||||
|
||||
copy_1_dword:
|
||||
TESTQ $0x00000004, CX
|
||||
JZ copy_1_qword
|
||||
MOVL (R10)(R14*1), R15
|
||||
MOVL R15, (R9)(R14*1)
|
||||
ADDQ $0x04, R14
|
||||
|
||||
copy_1_qword:
|
||||
TESTQ $0x00000008, CX
|
||||
JZ copy_1_test
|
||||
MOVQ (R10)(R14*1), R15
|
||||
MOVQ R15, (R9)(R14*1)
|
||||
ADDQ $0x08, R14
|
||||
JMP copy_1_test
|
||||
|
||||
copy_1:
|
||||
MOVUPS (R10)(R14*1), X0
|
||||
MOVUPS X0, (R9)(R14*1)
|
||||
ADDQ $0x10, R14
|
||||
|
||||
copy_1_test:
|
||||
CMPQ R14, CX
|
||||
JB copy_1
|
||||
ADDQ CX, R10
|
||||
ADDQ CX, R9
|
||||
ADDQ CX, R11
|
||||
CMPQ R14, CX
|
||||
JB copy_1
|
||||
ADDQ CX, R10
|
||||
ADDQ CX, R9
|
||||
ADDQ CX, R11
|
||||
|
||||
// Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize)
|
||||
check_offset:
|
||||
@ -3108,60 +3285,55 @@ sequenceDecs_decodeSync_safe_bmi2_fill_2_end:
|
||||
MOVQ CX, 24(SP)
|
||||
|
||||
// Fill bitreader for state updates
|
||||
MOVQ R12, (SP)
|
||||
MOVQ $0x00000808, CX
|
||||
BEXTRQ CX, R8, R12
|
||||
MOVQ ctx+16(FP), CX
|
||||
CMPQ 96(CX), $0x00
|
||||
JZ sequenceDecs_decodeSync_safe_bmi2_skip_update
|
||||
|
||||
// Update Literal Length State
|
||||
MOVBQZX SI, R13
|
||||
MOVQ $0x00001010, CX
|
||||
BEXTRQ CX, SI, SI
|
||||
MOVQ R12, (SP)
|
||||
MOVQ $0x00000808, CX
|
||||
BEXTRQ CX, R8, R12
|
||||
MOVQ ctx+16(FP), CX
|
||||
CMPQ 96(CX), $0x00
|
||||
JZ sequenceDecs_decodeSync_safe_bmi2_skip_update
|
||||
LEAQ (SI)(DI*1), R13
|
||||
ADDQ R8, R13
|
||||
MOVBQZX R13, R13
|
||||
LEAQ (DX)(R13*1), CX
|
||||
MOVQ AX, R14
|
||||
MOVQ CX, DX
|
||||
ROLQ CL, R14
|
||||
BZHIQ R13, R14, R14
|
||||
ADDQ R14, SI
|
||||
|
||||
// Load ctx.llTable
|
||||
// Update Offset State
|
||||
BZHIQ R8, R14, CX
|
||||
SHRXQ R8, R14, R14
|
||||
MOVQ $0x00001010, R13
|
||||
BEXTRQ R13, R8, R8
|
||||
ADDQ CX, R8
|
||||
|
||||
// Load ctx.ofTable
|
||||
MOVQ ctx+16(FP), CX
|
||||
MOVQ (CX), CX
|
||||
MOVQ (CX)(SI*8), SI
|
||||
MOVQ 48(CX), CX
|
||||
MOVQ (CX)(R8*8), R8
|
||||
|
||||
// Update Match Length State
|
||||
MOVBQZX DI, R13
|
||||
MOVQ $0x00001010, CX
|
||||
BEXTRQ CX, DI, DI
|
||||
LEAQ (DX)(R13*1), CX
|
||||
MOVQ AX, R14
|
||||
MOVQ CX, DX
|
||||
ROLQ CL, R14
|
||||
BZHIQ R13, R14, R14
|
||||
ADDQ R14, DI
|
||||
BZHIQ DI, R14, CX
|
||||
SHRXQ DI, R14, R14
|
||||
MOVQ $0x00001010, R13
|
||||
BEXTRQ R13, DI, DI
|
||||
ADDQ CX, DI
|
||||
|
||||
// Load ctx.mlTable
|
||||
MOVQ ctx+16(FP), CX
|
||||
MOVQ 24(CX), CX
|
||||
MOVQ (CX)(DI*8), DI
|
||||
|
||||
// Update Offset State
|
||||
MOVBQZX R8, R13
|
||||
MOVQ $0x00001010, CX
|
||||
BEXTRQ CX, R8, R8
|
||||
LEAQ (DX)(R13*1), CX
|
||||
MOVQ AX, R14
|
||||
MOVQ CX, DX
|
||||
ROLQ CL, R14
|
||||
BZHIQ R13, R14, R14
|
||||
ADDQ R14, R8
|
||||
// Update Literal Length State
|
||||
BZHIQ SI, R14, CX
|
||||
MOVQ $0x00001010, R13
|
||||
BEXTRQ R13, SI, SI
|
||||
ADDQ CX, SI
|
||||
|
||||
// Load ctx.ofTable
|
||||
// Load ctx.llTable
|
||||
MOVQ ctx+16(FP), CX
|
||||
MOVQ 48(CX), CX
|
||||
MOVQ (CX)(R8*8), R8
|
||||
MOVQ (CX), CX
|
||||
MOVQ (CX)(SI*8), SI
|
||||
|
||||
sequenceDecs_decodeSync_safe_bmi2_skip_update:
|
||||
// Adjust offset
|
||||
|
9
vendor/github.com/klauspost/compress/zstd/zip.go
generated
vendored
9
vendor/github.com/klauspost/compress/zstd/zip.go
generated
vendored
@ -18,7 +18,14 @@ const ZipMethodWinZip = 93
|
||||
// See https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.3.9.TXT
|
||||
const ZipMethodPKWare = 20
|
||||
|
||||
var zipReaderPool sync.Pool
|
||||
// zipReaderPool is the default reader pool.
|
||||
var zipReaderPool = sync.Pool{New: func() interface{} {
|
||||
z, err := NewReader(nil, WithDecoderLowmem(true), WithDecoderMaxWindow(128<<20), WithDecoderConcurrency(1))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return z
|
||||
}}
|
||||
|
||||
// newZipReader creates a pooled zip decompressor.
|
||||
func newZipReader(opts ...DOption) func(r io.Reader) io.ReadCloser {
|
||||
|
11
vendor/github.com/klauspost/compress/zstd/zstd.go
generated
vendored
11
vendor/github.com/klauspost/compress/zstd/zstd.go
generated
vendored
@ -110,17 +110,6 @@ func printf(format string, a ...interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// matchLenFast does matching, but will not match the last up to 7 bytes.
|
||||
func matchLenFast(a, b []byte) int {
|
||||
endI := len(a) & (math.MaxInt32 - 7)
|
||||
for i := 0; i < endI; i += 8 {
|
||||
if diff := load64(a, i) ^ load64(b, i); diff != 0 {
|
||||
return i + bits.TrailingZeros64(diff)>>3
|
||||
}
|
||||
}
|
||||
return endI
|
||||
}
|
||||
|
||||
// matchLen returns the maximum length.
|
||||
// a must be the shortest of the two.
|
||||
// The function also returns whether all bytes matched.
|
||||
|
2
vendor/golang.org/x/sys/execabs/execabs.go
generated
vendored
2
vendor/golang.org/x/sys/execabs/execabs.go
generated
vendored
@ -53,7 +53,7 @@ func relError(file, path string) error {
|
||||
// LookPath instead returns an error.
|
||||
func LookPath(file string) (string, error) {
|
||||
path, err := exec.LookPath(file)
|
||||
if err != nil {
|
||||
if err != nil && !isGo119ErrDot(err) {
|
||||
return "", err
|
||||
}
|
||||
if filepath.Base(file) == file && !filepath.IsAbs(path) {
|
||||
|
12
vendor/golang.org/x/sys/execabs/execabs_go118.go
generated
vendored
Normal file
12
vendor/golang.org/x/sys/execabs/execabs_go118.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !go1.19
|
||||
// +build !go1.19
|
||||
|
||||
package execabs
|
||||
|
||||
func isGo119ErrDot(err error) bool {
|
||||
return false
|
||||
}
|
15
vendor/golang.org/x/sys/execabs/execabs_go119.go
generated
vendored
Normal file
15
vendor/golang.org/x/sys/execabs/execabs_go119.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.19
|
||||
// +build go1.19
|
||||
|
||||
package execabs
|
||||
|
||||
import "strings"
|
||||
|
||||
func isGo119ErrDot(err error) bool {
|
||||
// TODO: return errors.Is(err, exec.ErrDot)
|
||||
return strings.Contains(err.Error(), "current directory")
|
||||
}
|
1
vendor/golang.org/x/sys/plan9/syscall.go
generated
vendored
1
vendor/golang.org/x/sys/plan9/syscall.go
generated
vendored
@ -113,5 +113,6 @@ func (tv *Timeval) Nano() int64 {
|
||||
|
||||
// use is a no-op, but the compiler cannot see that it is.
|
||||
// Calling use(p) ensures that p is kept live until that point.
|
||||
//
|
||||
//go:noescape
|
||||
func use(p unsafe.Pointer)
|
||||
|
10
vendor/golang.org/x/sys/plan9/syscall_plan9.go
generated
vendored
10
vendor/golang.org/x/sys/plan9/syscall_plan9.go
generated
vendored
@ -115,6 +115,7 @@ func Write(fd int, p []byte) (n int, err error) {
|
||||
var ioSync int64
|
||||
|
||||
//sys fd2path(fd int, buf []byte) (err error)
|
||||
|
||||
func Fd2path(fd int) (path string, err error) {
|
||||
var buf [512]byte
|
||||
|
||||
@ -126,6 +127,7 @@ func Fd2path(fd int) (path string, err error) {
|
||||
}
|
||||
|
||||
//sys pipe(p *[2]int32) (err error)
|
||||
|
||||
func Pipe(p []int) (err error) {
|
||||
if len(p) != 2 {
|
||||
return syscall.ErrorString("bad arg in system call")
|
||||
@ -180,6 +182,7 @@ func (w Waitmsg) ExitStatus() int {
|
||||
}
|
||||
|
||||
//sys await(s []byte) (n int, err error)
|
||||
|
||||
func Await(w *Waitmsg) (err error) {
|
||||
var buf [512]byte
|
||||
var f [5][]byte
|
||||
@ -301,42 +304,49 @@ func Getgroups() (gids []int, err error) {
|
||||
}
|
||||
|
||||
//sys open(path string, mode int) (fd int, err error)
|
||||
|
||||
func Open(path string, mode int) (fd int, err error) {
|
||||
fixwd()
|
||||
return open(path, mode)
|
||||
}
|
||||
|
||||
//sys create(path string, mode int, perm uint32) (fd int, err error)
|
||||
|
||||
func Create(path string, mode int, perm uint32) (fd int, err error) {
|
||||
fixwd()
|
||||
return create(path, mode, perm)
|
||||
}
|
||||
|
||||
//sys remove(path string) (err error)
|
||||
|
||||
func Remove(path string) error {
|
||||
fixwd()
|
||||
return remove(path)
|
||||
}
|
||||
|
||||
//sys stat(path string, edir []byte) (n int, err error)
|
||||
|
||||
func Stat(path string, edir []byte) (n int, err error) {
|
||||
fixwd()
|
||||
return stat(path, edir)
|
||||
}
|
||||
|
||||
//sys bind(name string, old string, flag int) (err error)
|
||||
|
||||
func Bind(name string, old string, flag int) (err error) {
|
||||
fixwd()
|
||||
return bind(name, old, flag)
|
||||
}
|
||||
|
||||
//sys mount(fd int, afd int, old string, flag int, aname string) (err error)
|
||||
|
||||
func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
|
||||
fixwd()
|
||||
return mount(fd, afd, old, flag, aname)
|
||||
}
|
||||
|
||||
//sys wstat(path string, edir []byte) (err error)
|
||||
|
||||
func Wstat(path string, edir []byte) (err error) {
|
||||
fixwd()
|
||||
return wstat(path, edir)
|
||||
|
9
vendor/golang.org/x/sys/unix/ifreq_linux.go
generated
vendored
9
vendor/golang.org/x/sys/unix/ifreq_linux.go
generated
vendored
@ -8,7 +8,6 @@
|
||||
package unix
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
@ -45,13 +44,7 @@ func NewIfreq(name string) (*Ifreq, error) {
|
||||
|
||||
// Name returns the interface name associated with the Ifreq.
|
||||
func (ifr *Ifreq) Name() string {
|
||||
// BytePtrToString requires a NULL terminator or the program may crash. If
|
||||
// one is not present, just return the empty string.
|
||||
if !bytes.Contains(ifr.raw.Ifrn[:], []byte{0x00}) {
|
||||
return ""
|
||||
}
|
||||
|
||||
return BytePtrToString(&ifr.raw.Ifrn[0])
|
||||
return ByteSliceToString(ifr.raw.Ifrn[:])
|
||||
}
|
||||
|
||||
// According to netdevice(7), only AF_INET addresses are returned for numerous
|
||||
|
6
vendor/golang.org/x/sys/unix/syscall_aix.go
generated
vendored
6
vendor/golang.org/x/sys/unix/syscall_aix.go
generated
vendored
@ -37,6 +37,7 @@ func Creat(path string, mode uint32) (fd int, err error) {
|
||||
}
|
||||
|
||||
//sys utimes(path string, times *[2]Timeval) (err error)
|
||||
|
||||
func Utimes(path string, tv []Timeval) error {
|
||||
if len(tv) != 2 {
|
||||
return EINVAL
|
||||
@ -45,6 +46,7 @@ func Utimes(path string, tv []Timeval) error {
|
||||
}
|
||||
|
||||
//sys utimensat(dirfd int, path string, times *[2]Timespec, flag int) (err error)
|
||||
|
||||
func UtimesNano(path string, ts []Timespec) error {
|
||||
if len(ts) != 2 {
|
||||
return EINVAL
|
||||
@ -300,11 +302,13 @@ func direntNamlen(buf []byte) (uint64, bool) {
|
||||
}
|
||||
|
||||
//sys getdirent(fd int, buf []byte) (n int, err error)
|
||||
|
||||
func Getdents(fd int, buf []byte) (n int, err error) {
|
||||
return getdirent(fd, buf)
|
||||
}
|
||||
|
||||
//sys wait4(pid Pid_t, status *_C_int, options int, rusage *Rusage) (wpid Pid_t, err error)
|
||||
|
||||
func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
|
||||
var status _C_int
|
||||
var r Pid_t
|
||||
@ -372,6 +376,7 @@ func (w WaitStatus) TrapCause() int { return -1 }
|
||||
//sys fcntl(fd int, cmd int, arg int) (val int, err error)
|
||||
|
||||
//sys fsyncRange(fd int, how int, start int64, length int64) (err error) = fsync_range
|
||||
|
||||
func Fsync(fd int) error {
|
||||
return fsyncRange(fd, O_SYNC, 0, 0)
|
||||
}
|
||||
@ -536,6 +541,7 @@ func Poll(fds []PollFd, timeout int) (n int, err error) {
|
||||
//sys Getsystemcfg(label int) (n uint64)
|
||||
|
||||
//sys umount(target string) (err error)
|
||||
|
||||
func Unmount(target string, flags int) (err error) {
|
||||
if flags != 0 {
|
||||
// AIX doesn't have any flags for umount.
|
||||
|
2
vendor/golang.org/x/sys/unix/syscall_darwin.go
generated
vendored
2
vendor/golang.org/x/sys/unix/syscall_darwin.go
generated
vendored
@ -504,6 +504,7 @@ func SysctlKinfoProcSlice(name string, args ...int) ([]KinfoProc, error) {
|
||||
//sys Mkdirat(dirfd int, path string, mode uint32) (err error)
|
||||
//sys Mkfifo(path string, mode uint32) (err error)
|
||||
//sys Mknod(path string, mode uint32, dev int) (err error)
|
||||
//sys Mount(fsType string, dir string, flags int, data unsafe.Pointer) (err error)
|
||||
//sys Open(path string, mode int, perm uint32) (fd int, err error)
|
||||
//sys Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error)
|
||||
//sys Pathconf(path string, name int) (val int, err error)
|
||||
@ -572,7 +573,6 @@ func SysctlKinfoProcSlice(name string, args ...int) ([]KinfoProc, error) {
|
||||
// Nfssvc
|
||||
// Getfh
|
||||
// Quotactl
|
||||
// Mount
|
||||
// Csops
|
||||
// Waitid
|
||||
// Add_profil
|
||||
|
2
vendor/golang.org/x/sys/unix/syscall_dragonfly.go
generated
vendored
2
vendor/golang.org/x/sys/unix/syscall_dragonfly.go
generated
vendored
@ -125,11 +125,13 @@ func Pipe2(p []int, flags int) (err error) {
|
||||
}
|
||||
|
||||
//sys extpread(fd int, p []byte, flags int, offset int64) (n int, err error)
|
||||
|
||||
func pread(fd int, p []byte, offset int64) (n int, err error) {
|
||||
return extpread(fd, p, 0, offset)
|
||||
}
|
||||
|
||||
//sys extpwrite(fd int, p []byte, flags int, offset int64) (n int, err error)
|
||||
|
||||
func pwrite(fd int, p []byte, offset int64) (n int, err error) {
|
||||
return extpwrite(fd, p, 0, offset)
|
||||
}
|
||||
|
112
vendor/golang.org/x/sys/unix/syscall_linux.go
generated
vendored
112
vendor/golang.org/x/sys/unix/syscall_linux.go
generated
vendored
@ -512,24 +512,24 @@ func (sa *SockaddrL2) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
||||
//
|
||||
// Server example:
|
||||
//
|
||||
// fd, _ := Socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)
|
||||
// _ = unix.Bind(fd, &unix.SockaddrRFCOMM{
|
||||
// Channel: 1,
|
||||
// Addr: [6]uint8{0, 0, 0, 0, 0, 0}, // BDADDR_ANY or 00:00:00:00:00:00
|
||||
// })
|
||||
// _ = Listen(fd, 1)
|
||||
// nfd, sa, _ := Accept(fd)
|
||||
// fmt.Printf("conn addr=%v fd=%d", sa.(*unix.SockaddrRFCOMM).Addr, nfd)
|
||||
// Read(nfd, buf)
|
||||
// fd, _ := Socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)
|
||||
// _ = unix.Bind(fd, &unix.SockaddrRFCOMM{
|
||||
// Channel: 1,
|
||||
// Addr: [6]uint8{0, 0, 0, 0, 0, 0}, // BDADDR_ANY or 00:00:00:00:00:00
|
||||
// })
|
||||
// _ = Listen(fd, 1)
|
||||
// nfd, sa, _ := Accept(fd)
|
||||
// fmt.Printf("conn addr=%v fd=%d", sa.(*unix.SockaddrRFCOMM).Addr, nfd)
|
||||
// Read(nfd, buf)
|
||||
//
|
||||
// Client example:
|
||||
//
|
||||
// fd, _ := Socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)
|
||||
// _ = Connect(fd, &SockaddrRFCOMM{
|
||||
// Channel: 1,
|
||||
// Addr: [6]byte{0x11, 0x22, 0x33, 0xaa, 0xbb, 0xcc}, // CC:BB:AA:33:22:11
|
||||
// })
|
||||
// Write(fd, []byte(`hello`))
|
||||
// fd, _ := Socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)
|
||||
// _ = Connect(fd, &SockaddrRFCOMM{
|
||||
// Channel: 1,
|
||||
// Addr: [6]byte{0x11, 0x22, 0x33, 0xaa, 0xbb, 0xcc}, // CC:BB:AA:33:22:11
|
||||
// })
|
||||
// Write(fd, []byte(`hello`))
|
||||
type SockaddrRFCOMM struct {
|
||||
// Addr represents a bluetooth address, byte ordering is little-endian.
|
||||
Addr [6]uint8
|
||||
@ -556,12 +556,12 @@ func (sa *SockaddrRFCOMM) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
||||
// The SockaddrCAN struct must be bound to the socket file descriptor
|
||||
// using Bind before the CAN socket can be used.
|
||||
//
|
||||
// // Read one raw CAN frame
|
||||
// fd, _ := Socket(AF_CAN, SOCK_RAW, CAN_RAW)
|
||||
// addr := &SockaddrCAN{Ifindex: index}
|
||||
// Bind(fd, addr)
|
||||
// frame := make([]byte, 16)
|
||||
// Read(fd, frame)
|
||||
// // Read one raw CAN frame
|
||||
// fd, _ := Socket(AF_CAN, SOCK_RAW, CAN_RAW)
|
||||
// addr := &SockaddrCAN{Ifindex: index}
|
||||
// Bind(fd, addr)
|
||||
// frame := make([]byte, 16)
|
||||
// Read(fd, frame)
|
||||
//
|
||||
// The full SocketCAN documentation can be found in the linux kernel
|
||||
// archives at: https://www.kernel.org/doc/Documentation/networking/can.txt
|
||||
@ -632,13 +632,13 @@ func (sa *SockaddrCANJ1939) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
||||
// Here is an example of using an AF_ALG socket with SHA1 hashing.
|
||||
// The initial socket setup process is as follows:
|
||||
//
|
||||
// // Open a socket to perform SHA1 hashing.
|
||||
// fd, _ := unix.Socket(unix.AF_ALG, unix.SOCK_SEQPACKET, 0)
|
||||
// addr := &unix.SockaddrALG{Type: "hash", Name: "sha1"}
|
||||
// unix.Bind(fd, addr)
|
||||
// // Note: unix.Accept does not work at this time; must invoke accept()
|
||||
// // manually using unix.Syscall.
|
||||
// hashfd, _, _ := unix.Syscall(unix.SYS_ACCEPT, uintptr(fd), 0, 0)
|
||||
// // Open a socket to perform SHA1 hashing.
|
||||
// fd, _ := unix.Socket(unix.AF_ALG, unix.SOCK_SEQPACKET, 0)
|
||||
// addr := &unix.SockaddrALG{Type: "hash", Name: "sha1"}
|
||||
// unix.Bind(fd, addr)
|
||||
// // Note: unix.Accept does not work at this time; must invoke accept()
|
||||
// // manually using unix.Syscall.
|
||||
// hashfd, _, _ := unix.Syscall(unix.SYS_ACCEPT, uintptr(fd), 0, 0)
|
||||
//
|
||||
// Once a file descriptor has been returned from Accept, it may be used to
|
||||
// perform SHA1 hashing. The descriptor is not safe for concurrent use, but
|
||||
@ -647,39 +647,39 @@ func (sa *SockaddrCANJ1939) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
||||
// When hashing a small byte slice or string, a single Write and Read may
|
||||
// be used:
|
||||
//
|
||||
// // Assume hashfd is already configured using the setup process.
|
||||
// hash := os.NewFile(hashfd, "sha1")
|
||||
// // Hash an input string and read the results. Each Write discards
|
||||
// // previous hash state. Read always reads the current state.
|
||||
// b := make([]byte, 20)
|
||||
// for i := 0; i < 2; i++ {
|
||||
// io.WriteString(hash, "Hello, world.")
|
||||
// hash.Read(b)
|
||||
// fmt.Println(hex.EncodeToString(b))
|
||||
// }
|
||||
// // Output:
|
||||
// // 2ae01472317d1935a84797ec1983ae243fc6aa28
|
||||
// // 2ae01472317d1935a84797ec1983ae243fc6aa28
|
||||
// // Assume hashfd is already configured using the setup process.
|
||||
// hash := os.NewFile(hashfd, "sha1")
|
||||
// // Hash an input string and read the results. Each Write discards
|
||||
// // previous hash state. Read always reads the current state.
|
||||
// b := make([]byte, 20)
|
||||
// for i := 0; i < 2; i++ {
|
||||
// io.WriteString(hash, "Hello, world.")
|
||||
// hash.Read(b)
|
||||
// fmt.Println(hex.EncodeToString(b))
|
||||
// }
|
||||
// // Output:
|
||||
// // 2ae01472317d1935a84797ec1983ae243fc6aa28
|
||||
// // 2ae01472317d1935a84797ec1983ae243fc6aa28
|
||||
//
|
||||
// For hashing larger byte slices, or byte streams such as those read from
|
||||
// a file or socket, use Sendto with MSG_MORE to instruct the kernel to update
|
||||
// the hash digest instead of creating a new one for a given chunk and finalizing it.
|
||||
//
|
||||
// // Assume hashfd and addr are already configured using the setup process.
|
||||
// hash := os.NewFile(hashfd, "sha1")
|
||||
// // Hash the contents of a file.
|
||||
// f, _ := os.Open("/tmp/linux-4.10-rc7.tar.xz")
|
||||
// b := make([]byte, 4096)
|
||||
// for {
|
||||
// n, err := f.Read(b)
|
||||
// if err == io.EOF {
|
||||
// break
|
||||
// }
|
||||
// unix.Sendto(hashfd, b[:n], unix.MSG_MORE, addr)
|
||||
// }
|
||||
// hash.Read(b)
|
||||
// fmt.Println(hex.EncodeToString(b))
|
||||
// // Output: 85cdcad0c06eef66f805ecce353bec9accbeecc5
|
||||
// // Assume hashfd and addr are already configured using the setup process.
|
||||
// hash := os.NewFile(hashfd, "sha1")
|
||||
// // Hash the contents of a file.
|
||||
// f, _ := os.Open("/tmp/linux-4.10-rc7.tar.xz")
|
||||
// b := make([]byte, 4096)
|
||||
// for {
|
||||
// n, err := f.Read(b)
|
||||
// if err == io.EOF {
|
||||
// break
|
||||
// }
|
||||
// unix.Sendto(hashfd, b[:n], unix.MSG_MORE, addr)
|
||||
// }
|
||||
// hash.Read(b)
|
||||
// fmt.Println(hex.EncodeToString(b))
|
||||
// // Output: 85cdcad0c06eef66f805ecce353bec9accbeecc5
|
||||
//
|
||||
// For more information, see: http://www.chronox.de/crypto-API/crypto/userspace-if.html.
|
||||
type SockaddrALG struct {
|
||||
|
2
vendor/golang.org/x/sys/unix/syscall_openbsd.go
generated
vendored
2
vendor/golang.org/x/sys/unix/syscall_openbsd.go
generated
vendored
@ -81,6 +81,7 @@ func Pipe(p []int) (err error) {
|
||||
}
|
||||
|
||||
//sysnb pipe2(p *[2]_C_int, flags int) (err error)
|
||||
|
||||
func Pipe2(p []int, flags int) error {
|
||||
if len(p) != 2 {
|
||||
return EINVAL
|
||||
@ -95,6 +96,7 @@ func Pipe2(p []int, flags int) error {
|
||||
}
|
||||
|
||||
//sys Getdents(fd int, buf []byte) (n int, err error)
|
||||
|
||||
func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
|
||||
n, err = Getdents(fd, buf)
|
||||
if err != nil || basep == nil {
|
||||
|
2
vendor/golang.org/x/sys/unix/zerrors_linux_386.go
generated
vendored
2
vendor/golang.org/x/sys/unix/zerrors_linux_386.go
generated
vendored
@ -5,7 +5,7 @@
|
||||
// +build 386,linux
|
||||
|
||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include -m32 /build/unix/_const.go
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include -m32 _const.go
|
||||
|
||||
package unix
|
||||
|
||||
|
2
vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
generated
vendored
2
vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
generated
vendored
@ -5,7 +5,7 @@
|
||||
// +build amd64,linux
|
||||
|
||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include -m64 /build/unix/_const.go
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include -m64 _const.go
|
||||
|
||||
package unix
|
||||
|
||||
|
2
vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
generated
vendored
2
vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
generated
vendored
@ -5,7 +5,7 @@
|
||||
// +build arm,linux
|
||||
|
||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
||||
|
||||
package unix
|
||||
|
||||
|
2
vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
generated
vendored
2
vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
generated
vendored
@ -5,7 +5,7 @@
|
||||
// +build arm64,linux
|
||||
|
||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char /build/unix/_const.go
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char _const.go
|
||||
|
||||
package unix
|
||||
|
||||
|
2
vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go
generated
vendored
2
vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go
generated
vendored
@ -5,7 +5,7 @@
|
||||
// +build loong64,linux
|
||||
|
||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
||||
|
||||
package unix
|
||||
|
||||
|
2
vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
generated
vendored
2
vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
generated
vendored
@ -5,7 +5,7 @@
|
||||
// +build mips,linux
|
||||
|
||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
||||
|
||||
package unix
|
||||
|
||||
|
2
vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
generated
vendored
2
vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
generated
vendored
@ -5,7 +5,7 @@
|
||||
// +build mips64,linux
|
||||
|
||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
||||
|
||||
package unix
|
||||
|
||||
|
2
vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
generated
vendored
2
vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
generated
vendored
@ -5,7 +5,7 @@
|
||||
// +build mips64le,linux
|
||||
|
||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
||||
|
||||
package unix
|
||||
|
||||
|
2
vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
generated
vendored
2
vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
generated
vendored
@ -5,7 +5,7 @@
|
||||
// +build mipsle,linux
|
||||
|
||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
||||
|
||||
package unix
|
||||
|
||||
|
2
vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
generated
vendored
2
vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
generated
vendored
@ -5,7 +5,7 @@
|
||||
// +build ppc,linux
|
||||
|
||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
||||
|
||||
package unix
|
||||
|
||||
|
2
vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
generated
vendored
2
vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
generated
vendored
@ -5,7 +5,7 @@
|
||||
// +build ppc64,linux
|
||||
|
||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
||||
|
||||
package unix
|
||||
|
||||
|
2
vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
generated
vendored
2
vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
generated
vendored
@ -5,7 +5,7 @@
|
||||
// +build ppc64le,linux
|
||||
|
||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
||||
|
||||
package unix
|
||||
|
||||
|
2
vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
generated
vendored
2
vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
generated
vendored
@ -5,7 +5,7 @@
|
||||
// +build riscv64,linux
|
||||
|
||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
||||
|
||||
package unix
|
||||
|
||||
|
2
vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
generated
vendored
2
vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
generated
vendored
@ -5,7 +5,7 @@
|
||||
// +build s390x,linux
|
||||
|
||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char /build/unix/_const.go
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char _const.go
|
||||
|
||||
package unix
|
||||
|
||||
|
2
vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
generated
vendored
2
vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
generated
vendored
@ -5,7 +5,7 @@
|
||||
// +build sparc64,linux
|
||||
|
||||
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go
|
||||
// cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go
|
||||
|
||||
package unix
|
||||
|
||||
|
24
vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go
generated
vendored
24
vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go
generated
vendored
@ -1643,6 +1643,30 @@ var libc_mknod_trampoline_addr uintptr
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Mount(fsType string, dir string, flags int, data unsafe.Pointer) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(fsType)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var _p1 *byte
|
||||
_p1, err = BytePtrFromString(dir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, _, e1 := syscall_syscall6(libc_mount_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flags), uintptr(data), 0, 0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var libc_mount_trampoline_addr uintptr
|
||||
|
||||
//go:cgo_import_dynamic libc_mount mount "/usr/lib/libSystem.B.dylib"
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Open(path string, mode int, perm uint32) (fd int, err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
|
6
vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s
generated
vendored
6
vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s
generated
vendored
@ -600,6 +600,12 @@ TEXT libc_mknod_trampoline<>(SB),NOSPLIT,$0-0
|
||||
GLOBL ·libc_mknod_trampoline_addr(SB), RODATA, $8
|
||||
DATA ·libc_mknod_trampoline_addr(SB)/8, $libc_mknod_trampoline<>(SB)
|
||||
|
||||
TEXT libc_mount_trampoline<>(SB),NOSPLIT,$0-0
|
||||
JMP libc_mount(SB)
|
||||
|
||||
GLOBL ·libc_mount_trampoline_addr(SB), RODATA, $8
|
||||
DATA ·libc_mount_trampoline_addr(SB)/8, $libc_mount_trampoline<>(SB)
|
||||
|
||||
TEXT libc_open_trampoline<>(SB),NOSPLIT,$0-0
|
||||
JMP libc_open(SB)
|
||||
|
||||
|
24
vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go
generated
vendored
24
vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go
generated
vendored
@ -1643,6 +1643,30 @@ var libc_mknod_trampoline_addr uintptr
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Mount(fsType string, dir string, flags int, data unsafe.Pointer) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(fsType)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var _p1 *byte
|
||||
_p1, err = BytePtrFromString(dir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, _, e1 := syscall_syscall6(libc_mount_trampoline_addr, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flags), uintptr(data), 0, 0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var libc_mount_trampoline_addr uintptr
|
||||
|
||||
//go:cgo_import_dynamic libc_mount mount "/usr/lib/libSystem.B.dylib"
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Open(path string, mode int, perm uint32) (fd int, err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = BytePtrFromString(path)
|
||||
|
6
vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s
generated
vendored
6
vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s
generated
vendored
@ -600,6 +600,12 @@ TEXT libc_mknod_trampoline<>(SB),NOSPLIT,$0-0
|
||||
GLOBL ·libc_mknod_trampoline_addr(SB), RODATA, $8
|
||||
DATA ·libc_mknod_trampoline_addr(SB)/8, $libc_mknod_trampoline<>(SB)
|
||||
|
||||
TEXT libc_mount_trampoline<>(SB),NOSPLIT,$0-0
|
||||
JMP libc_mount(SB)
|
||||
|
||||
GLOBL ·libc_mount_trampoline_addr(SB), RODATA, $8
|
||||
DATA ·libc_mount_trampoline_addr(SB)/8, $libc_mount_trampoline<>(SB)
|
||||
|
||||
TEXT libc_open_trampoline<>(SB),NOSPLIT,$0-0
|
||||
JMP libc_open(SB)
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user