mirror of https://github.com/containers/podman.git
Vendor in latest containers/common with default capabilities
Also update vendor of containers/storage and image Cleanup display of added/dropped capabilties as well Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
parent
1cc22631f6
commit
3718ac8e96
|
@ -162,7 +162,7 @@ When executing RUN instructions, run the command specified in the instruction
|
|||
with the specified capability removed from its capability set.
|
||||
The CAP\_CHOWN, CAP\_DAC\_OVERRIDE, CAP\_FOWNER,
|
||||
CAP\_FSETID, CAP\_KILL, CAP\_NET\_BIND\_SERVICE, CAP\_SETFCAP,
|
||||
CAP\_SETGID, CAP\_SETPCAP, CAP\_SETUID, and CAP\_SYS\_CHROOT capabilities are
|
||||
CAP\_SETGID, CAP\_SETPCAP, and CAP\_SETUID capabilities are
|
||||
granted by default; this option can be used to remove them.
|
||||
|
||||
If a capability is specified to both the **--cap-add** and **--cap-drop**
|
||||
|
|
|
@ -129,7 +129,6 @@ $ podman container inspect foobar
|
|||
"CAP_SETGID",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_SETUID",
|
||||
"CAP_SYS_CHROOT"
|
||||
],
|
||||
"BoundingCaps": [
|
||||
"CAP_CHOWN",
|
||||
|
@ -142,7 +141,6 @@ $ podman container inspect foobar
|
|||
"CAP_SETGID",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_SETUID",
|
||||
"CAP_SYS_CHROOT"
|
||||
],
|
||||
"ExecIDs": [],
|
||||
"GraphDriver": {
|
||||
|
@ -248,11 +246,7 @@ $ podman container inspect foobar
|
|||
"VolumeDriver": "",
|
||||
"VolumesFrom": null,
|
||||
"CapAdd": [],
|
||||
"CapDrop": [
|
||||
"CAP_AUDIT_WRITE",
|
||||
"CAP_MKNOD",
|
||||
"CAP_NET_RAW"
|
||||
],
|
||||
"CapDrop": [],
|
||||
"Dns": [],
|
||||
"DnsOptions": [],
|
||||
"DnsSearch": [],
|
||||
|
@ -325,7 +319,7 @@ overlay
|
|||
|
||||
```
|
||||
$ podman container inspect --latest --format {{.EffectiveCaps}}
|
||||
[CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER CAP_FSETID CAP_KILL CAP_NET_BIND_SERVICE CAP_SETFCAP CAP_SETGID CAP_SETPCAP CAP_SETUID CAP_SYS_CHROOT]
|
||||
[CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER CAP_FSETID CAP_KILL CAP_NET_BIND_SERVICE CAP_SETFCAP CAP_SETGID CAP_SETPCAP CAP_SETUID]
|
||||
```
|
||||
|
||||
## SEE ALSO
|
||||
|
|
|
@ -91,7 +91,7 @@ host:
|
|||
path: /run/user/3267/podman/podman.sock
|
||||
security:
|
||||
apparmorEnabled: false
|
||||
capabilities: CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_NET_BIND_SERVICE,CAP_SETFCAP,CAP_SETGID,CAP_SETPCAP,CAP_SETUID,CAP_SYS_CHROOT
|
||||
capabilities: CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_NET_BIND_SERVICE,CAP_SETFCAP,CAP_SETGID,CAP_SETPCAP,CAP_SETUID
|
||||
rootless: true
|
||||
seccompEnabled: true
|
||||
seccompProfilePath: /usr/share/containers/seccomp.json
|
||||
|
@ -224,7 +224,7 @@ $ podman info --format json
|
|||
"serviceIsRemote": false,
|
||||
"security": {
|
||||
"apparmorEnabled": false,
|
||||
"capabilities": "CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_NET_BIND_SERVICE,CAP_SETFCAP,CAP_SETGID,CAP_SETPCAP,CAP_SETUID,CAP_SYS_CHROOT",
|
||||
"capabilities": "CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_NET_BIND_SERVICE,CAP_SETFCAP,CAP_SETGID,CAP_SETPCAP,CAP_SETUID",
|
||||
"rootless": true,
|
||||
"seccompEnabled": true,
|
||||
"seccompProfilePath": "/usr/share/containers/seccomp.json",
|
||||
|
|
|
@ -138,7 +138,7 @@ size: 4405240
|
|||
|
||||
```
|
||||
podman container inspect --latest --format {{.EffectiveCaps}}
|
||||
[CAP_CHOWN CAP_DAC_OVERRIDE CAP_FSETID CAP_FOWNER CAP_MKNOD CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SETFCAP CAP_SETPCAP CAP_NET_BIND_SERVICE CAP_SYS_CHROOT CAP_KILL CAP_AUDIT_WRITE]
|
||||
[CAP_CHOWN CAP_DAC_OVERRIDE CAP_FSETID CAP_FOWNER CAP_SETGID CAP_SETUID CAP_SETFCAP CAP_SETPCAP CAP_NET_BIND_SERVICE CAP_KILL]
|
||||
```
|
||||
|
||||
```
|
||||
|
|
|
@ -78,12 +78,6 @@ spec:
|
|||
- containerPort: 3306
|
||||
hostPort: 36533
|
||||
resources: {}
|
||||
securityContext:
|
||||
capabilities:
|
||||
drop:
|
||||
- CAP_MKNOD
|
||||
- CAP_NET_RAW
|
||||
- CAP_AUDIT_WRITE
|
||||
tty: true
|
||||
status: {}
|
||||
```
|
||||
|
@ -109,12 +103,6 @@ spec:
|
|||
image: docker.io/library/alpine:latest
|
||||
name: test-bind-mount
|
||||
resources: {}
|
||||
securityContext:
|
||||
capabilities:
|
||||
drop:
|
||||
- CAP_MKNOD
|
||||
- CAP_NET_RAW
|
||||
- CAP_AUDIT_WRITE
|
||||
volumeMounts:
|
||||
- mountPath: /volume
|
||||
name: home-user-my-data-host
|
||||
|
@ -148,12 +136,6 @@ spec:
|
|||
image: docker.io/library/alpine:latest
|
||||
name: test-bind-mount
|
||||
resources: {}
|
||||
securityContext:
|
||||
capabilities:
|
||||
drop:
|
||||
- CAP_MKNOD
|
||||
- CAP_NET_RAW
|
||||
- CAP_AUDIT_WRITE
|
||||
volumeMounts:
|
||||
- mountPath: /volume
|
||||
name: priceless-data-pvc
|
||||
|
|
26
go.mod
26
go.mod
|
@ -12,12 +12,12 @@ require (
|
|||
github.com/containernetworking/cni v1.1.2
|
||||
github.com/containernetworking/plugins v1.1.1
|
||||
github.com/containers/buildah v1.28.1-0.20221130132810-cf661299d14f
|
||||
github.com/containers/common v0.50.2-0.20221206110749-eb48ebbf8ca9
|
||||
github.com/containers/common v0.50.2-0.20221215152004-4a63cf13ee8d
|
||||
github.com/containers/conmon v2.0.20+incompatible
|
||||
github.com/containers/image/v5 v5.23.1-0.20221130170538-333c50e3eac8
|
||||
github.com/containers/image/v5 v5.23.1-0.20221215093114-15fbbcf9f484
|
||||
github.com/containers/ocicrypt v1.1.6
|
||||
github.com/containers/psgo v1.8.0
|
||||
github.com/containers/storage v1.44.1-0.20221201083122-c5a80ad65f42
|
||||
github.com/containers/storage v1.44.1-0.20221215163359-b0949d90efad
|
||||
github.com/coreos/go-systemd/v22 v22.5.0
|
||||
github.com/coreos/stream-metadata-go v0.0.0-20210225230131-70edb9eb47b3
|
||||
github.com/cyphar/filepath-securejoin v0.2.3
|
||||
|
@ -73,12 +73,12 @@ require (
|
|||
require (
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.0 // indirect
|
||||
github.com/Microsoft/hcsshim v0.9.5 // indirect
|
||||
github.com/Microsoft/hcsshim v0.9.6 // indirect
|
||||
github.com/VividCortex/ewma v1.2.0 // indirect
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
|
||||
github.com/chzyer/readline v1.5.1 // indirect
|
||||
github.com/containerd/cgroups v1.0.4 // indirect
|
||||
github.com/containerd/containerd v1.6.10 // indirect
|
||||
github.com/containerd/containerd v1.6.12 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.13.0 // indirect
|
||||
github.com/containers/libtrust v0.0.0-20200511145503-9c3a6c22cd9a // indirect
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect
|
||||
|
@ -99,7 +99,7 @@ require (
|
|||
github.com/imdario/mergo v0.3.13 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||
github.com/jinzhu/copier v0.3.5 // indirect
|
||||
github.com/klauspost/compress v1.15.12 // indirect
|
||||
github.com/klauspost/compress v1.15.13 // indirect
|
||||
github.com/klauspost/pgzip v1.2.6-0.20220930104621-17e8dac29df8 // indirect
|
||||
github.com/kr/fs v0.1.0 // indirect
|
||||
github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf // indirect
|
||||
|
@ -119,11 +119,11 @@ require (
|
|||
github.com/proglottis/gpgme v0.1.3 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/seccomp/libseccomp-golang v0.10.0 // indirect
|
||||
github.com/sigstore/sigstore v1.4.6 // indirect
|
||||
github.com/sigstore/sigstore v1.5.0 // indirect
|
||||
github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980 // indirect
|
||||
github.com/sylabs/sif/v2 v2.9.0 // indirect
|
||||
github.com/tchap/go-patricia v2.3.0+incompatible // indirect
|
||||
github.com/theupdateframework/go-tuf v0.5.2-0.20220930112810-3890c1e7ace4 // indirect
|
||||
github.com/theupdateframework/go-tuf v0.5.2-0.20221207161717-9cb61d6e65f5 // indirect
|
||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
|
||||
github.com/vbatts/tar-split v0.11.2 // indirect
|
||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect
|
||||
|
@ -132,11 +132,11 @@ require (
|
|||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
golang.org/x/crypto v0.3.0 // indirect
|
||||
golang.org/x/mod v0.6.0 // indirect
|
||||
golang.org/x/tools v0.2.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20221111202108-142d8a6fa32e // indirect
|
||||
google.golang.org/grpc v1.50.1 // indirect
|
||||
golang.org/x/crypto v0.4.0 // indirect
|
||||
golang.org/x/mod v0.7.0 // indirect
|
||||
golang.org/x/tools v0.4.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20221206210731-b1a01be3a5f6 // indirect
|
||||
google.golang.org/grpc v1.51.0 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
|
|
53
go.sum
53
go.sum
|
@ -83,8 +83,8 @@ github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwT
|
|||
github.com/Microsoft/hcsshim v0.8.22/go.mod h1:91uVCVzvX2QD16sMCenoxxXo6L1wJnLMX2PSufFMtF0=
|
||||
github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg=
|
||||
github.com/Microsoft/hcsshim v0.9.4/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
|
||||
github.com/Microsoft/hcsshim v0.9.5 h1:AbV+VPfTrIVffukazHcpxmz/sRiE6YaMDzHWR9BXZHo=
|
||||
github.com/Microsoft/hcsshim v0.9.5/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
|
||||
github.com/Microsoft/hcsshim v0.9.6 h1:VwnDOgLeoi2du6dAznfmspNqTiwczvjv4K7NxuY9jsY=
|
||||
github.com/Microsoft/hcsshim v0.9.6/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
|
||||
github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
|
||||
github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
|
@ -203,8 +203,8 @@ github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoT
|
|||
github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
|
||||
github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
|
||||
github.com/containerd/containerd v1.5.9/go.mod h1:fvQqCfadDGga5HZyn3j4+dx56qj2I9YwBrlSdalvJYQ=
|
||||
github.com/containerd/containerd v1.6.10 h1:8aiav7I2ZyQLbTlNMcBXyAU1FtFvp6VuyuW13qSd6Hk=
|
||||
github.com/containerd/containerd v1.6.10/go.mod h1:CVqfxdJ95PDgORwA219AwwLrREZgrTFybXu2HfMKRG0=
|
||||
github.com/containerd/containerd v1.6.12 h1:kJ9b3mOFKf8yqo05Ob+tMoxvt1pbVWhnB0re9Y+k+8c=
|
||||
github.com/containerd/containerd v1.6.12/go.mod h1:K4Bw7gjgh4TnkmQY+py/PYQGp4e7xgnHAeg87VeWb3A=
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
|
@ -264,12 +264,12 @@ github.com/containernetworking/plugins v1.1.1 h1:+AGfFigZ5TiQH00vhR8qPeSatj53eNG
|
|||
github.com/containernetworking/plugins v1.1.1/go.mod h1:Sr5TH/eBsGLXK/h71HeLfX19sZPp3ry5uHSkI4LPxV8=
|
||||
github.com/containers/buildah v1.28.1-0.20221130132810-cf661299d14f h1:Nzbda2tG7/aimoKnDxysqFgS1Q/gSsbcn88lFPj9LwY=
|
||||
github.com/containers/buildah v1.28.1-0.20221130132810-cf661299d14f/go.mod h1:0HcSoS6BHXWzMKqtxY1L0gupebEX33oPC+X62lPi6+c=
|
||||
github.com/containers/common v0.50.2-0.20221206110749-eb48ebbf8ca9 h1:L54LXA/DGRhp1cDN11HLaXcLCYh/ftqDhKYn9S1uetc=
|
||||
github.com/containers/common v0.50.2-0.20221206110749-eb48ebbf8ca9/go.mod h1:M1epBsHlUAeySDuMx+HdbvKBVf0odzLciecS5AQa6FA=
|
||||
github.com/containers/common v0.50.2-0.20221215152004-4a63cf13ee8d h1:hdbVVcY0ae0IDi4PUCJLgnrpguu9F+fSGcZO/OYWx8w=
|
||||
github.com/containers/common v0.50.2-0.20221215152004-4a63cf13ee8d/go.mod h1:w/ixwYVLjaj9XSeTIngI9ZZx/VH1TqmzrjC4eGF2AtU=
|
||||
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
|
||||
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
|
||||
github.com/containers/image/v5 v5.23.1-0.20221130170538-333c50e3eac8 h1:GLTTwKYkNGDhG3HagLuPvhieu1JEjDs9RsCDr8oJr9s=
|
||||
github.com/containers/image/v5 v5.23.1-0.20221130170538-333c50e3eac8/go.mod h1:dXknI7O86/PznywqTwyHaCpuK1MBh1QYxLkSqyDswI0=
|
||||
github.com/containers/image/v5 v5.23.1-0.20221215093114-15fbbcf9f484 h1:MOoO2wWaMCwP5nIte9H2512yEkvVVsjlxV5B+vK8ujE=
|
||||
github.com/containers/image/v5 v5.23.1-0.20221215093114-15fbbcf9f484/go.mod h1:QPpyvEyj40UAP6rG7rdxlPmitvoOefgdigMKi30iaBw=
|
||||
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=
|
||||
|
@ -281,8 +281,8 @@ github.com/containers/psgo v1.8.0 h1:2loGekmGAxM9ir5OsXWEfGwFxorMPYnc6gEDsGFQvhY
|
|||
github.com/containers/psgo v1.8.0/go.mod h1:T8ZxnX3Ur4RvnhxFJ7t8xJ1F48RhiZB4rSrOaR/qGHc=
|
||||
github.com/containers/storage v1.37.0/go.mod h1:kqeJeS0b7DO2ZT1nVWs0XufrmPFbgV3c+Q/45RlH6r4=
|
||||
github.com/containers/storage v1.43.0/go.mod h1:uZ147thiIFGdVTjMmIw19knttQnUCl3y9zjreHrg11s=
|
||||
github.com/containers/storage v1.44.1-0.20221201083122-c5a80ad65f42 h1:lba+h0VcMGvO/C4Q+oMhGxpgajzyQifbcedOYQNVRx8=
|
||||
github.com/containers/storage v1.44.1-0.20221201083122-c5a80ad65f42/go.mod h1:pYkSXaKIGAuEQmIf/melI5wbS/JBM++6Xp4JuVTqY7U=
|
||||
github.com/containers/storage v1.44.1-0.20221215163359-b0949d90efad h1:s1HIzrTnTI51kcrhnkXlvvzKs05V3MKviDsrTarhFyU=
|
||||
github.com/containers/storage v1.44.1-0.20221215163359-b0949d90efad/go.mod h1:o+bCRUdLbr6MPQaV5TphvdxBUucUBDFqzAcPIi8WWtg=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
|
||||
|
@ -614,8 +614,9 @@ github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdY
|
|||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.15.7/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||
github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM=
|
||||
github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
|
||||
github.com/klauspost/compress v1.15.13 h1:NFn1Wr8cfnenSJSA46lLq4wHCcBzKTSjnBIexDMMOV0=
|
||||
github.com/klauspost/compress v1.15.13/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
|
||||
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/klauspost/pgzip v1.2.6-0.20220930104621-17e8dac29df8 h1:BcxbplxjtczA1a6d3wYoa7a0WL3rq9DKBMGHeKyjEF0=
|
||||
github.com/klauspost/pgzip v1.2.6-0.20220930104621-17e8dac29df8/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
|
@ -659,8 +660,8 @@ github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vq
|
|||
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
|
||||
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||
|
@ -848,8 +849,8 @@ github.com/seccomp/libseccomp-golang v0.10.0 h1:aA4bp+/Zzi0BnWZ2F1wgNBs5gTpm+na2
|
|||
github.com/seccomp/libseccomp-golang v0.10.0/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
|
||||
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sigstore/sigstore v1.4.6 h1:2F1LPnQf6h1lRDCyNMoBE0WCPsA+IU5kAEAbGxG8S+U=
|
||||
github.com/sigstore/sigstore v1.4.6/go.mod h1:jGHEfVTFgpfDpBz7pSY4X+Sd+g36qdAUxGufNk47k7g=
|
||||
github.com/sigstore/sigstore v1.5.0 h1:NqstQ6SwwhQsp6Ll0wgk/d9g5MlfmEppo14aquUjJ/8=
|
||||
github.com/sigstore/sigstore v1.5.0/go.mod h1:fRAaZ9xXh7ZQ0GJqZdpmNJ3pemuHBu2PgIAngmzIFSI=
|
||||
github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
|
@ -917,8 +918,8 @@ github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG
|
|||
github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
|
||||
github.com/tchap/go-patricia v2.3.0+incompatible h1:GkY4dP3cEfEASBPPkWd+AmjYxhmDkqO9/zg7R0lSQRs=
|
||||
github.com/tchap/go-patricia v2.3.0+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
|
||||
github.com/theupdateframework/go-tuf v0.5.2-0.20220930112810-3890c1e7ace4 h1:1i/Afw3rmaR1gF3sfVkG2X6ldkikQwA9zY380LrR5YI=
|
||||
github.com/theupdateframework/go-tuf v0.5.2-0.20220930112810-3890c1e7ace4/go.mod h1:vAqWV3zEs89byeFsAYoh/Q14vJTgJkHwnnRCWBBBINY=
|
||||
github.com/theupdateframework/go-tuf v0.5.2-0.20221207161717-9cb61d6e65f5 h1:s+Yvt6bzRwHljSE7j6DLBDcfpZEdBhrvLgOUmd8f7ZM=
|
||||
github.com/theupdateframework/go-tuf v0.5.2-0.20221207161717-9cb61d6e65f5/go.mod h1:Le8NAjvDJK1vmLgpVYr4AR1Tqam/b/mTdQyTy37UJDA=
|
||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0=
|
||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
|
@ -1017,8 +1018,8 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPh
|
|||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
|
||||
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
@ -1054,8 +1055,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=
|
||||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
||||
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
|
||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -1319,8 +1320,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
|
|||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
|
||||
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
||||
golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4=
|
||||
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
@ -1401,8 +1402,8 @@ google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6D
|
|||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20221111202108-142d8a6fa32e h1:azcyH5lGzGy7pkLCbhPe0KkKxsM7c6UA/FZIXImKE7M=
|
||||
google.golang.org/genproto v0.0.0-20221111202108-142d8a6fa32e/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
|
||||
google.golang.org/genproto v0.0.0-20221206210731-b1a01be3a5f6 h1:AGXp12e/9rItf6/4QymU7WsAUwCf+ICW75cuR91nJIc=
|
||||
google.golang.org/genproto v0.0.0-20221206210731-b1a01be3a5f6/go.mod h1:1dOng4TWOomJrDGhpXjfCD35wQC6jnC7HpRmOFRqEV0=
|
||||
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
|
@ -1428,8 +1429,8 @@ google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
|
|||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY=
|
||||
google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
|
||||
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
|
|
@ -139,15 +139,15 @@ func (c *Container) platformInspectContainerHostConfig(ctrSpec *spec.Spec, hostC
|
|||
if ctrSpec.Process != nil {
|
||||
// Max an O(1) lookup table for default bounding caps.
|
||||
boundingCaps := make(map[string]bool)
|
||||
if !hostConfig.Privileged {
|
||||
for _, cap := range c.runtime.config.Containers.DefaultCapabilities {
|
||||
boundingCaps[cap] = true
|
||||
}
|
||||
} else {
|
||||
g, err := generate.New("linux")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !hostConfig.Privileged {
|
||||
for _, cap := range g.Config.Process.Capabilities.Bounding {
|
||||
boundingCaps[cap] = true
|
||||
}
|
||||
} else {
|
||||
// If we are privileged, use all caps.
|
||||
for _, cap := range capability.List() {
|
||||
if g.HostSpecific && cap > validate.LastCap() {
|
||||
|
@ -156,7 +156,7 @@ func (c *Container) platformInspectContainerHostConfig(ctrSpec *spec.Spec, hostC
|
|||
boundingCaps[fmt.Sprintf("CAP_%s", strings.ToUpper(cap.String()))] = true
|
||||
}
|
||||
}
|
||||
// Iterate through spec caps.
|
||||
// Iterate through default caps.
|
||||
// If it's not in default bounding caps, it was added.
|
||||
// If it is, delete from the default set. Whatever remains after
|
||||
// we finish are the dropped caps.
|
||||
|
|
|
@ -27,7 +27,6 @@ import (
|
|||
"github.com/containers/podman/v4/pkg/specgen"
|
||||
"github.com/containers/podman/v4/pkg/util"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/opencontainers/runtime-tools/generate"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
|
@ -602,7 +601,7 @@ func containerToV1Container(ctx context.Context, c *Container) (v1.Container, []
|
|||
kubeContainer := v1.Container{}
|
||||
kubeVolumes := []v1.Volume{}
|
||||
annotations := make(map[string]string)
|
||||
kubeSec, err := generateKubeSecurityContext(c)
|
||||
kubeSec, hasSecData, err := generateKubeSecurityContext(c)
|
||||
if err != nil {
|
||||
return kubeContainer, kubeVolumes, nil, annotations, err
|
||||
}
|
||||
|
@ -677,7 +676,7 @@ func containerToV1Container(ctx context.Context, c *Container) (v1.Container, []
|
|||
kubeContainer.WorkingDir = c.WorkingDir()
|
||||
}
|
||||
|
||||
if imgData.User == c.User() {
|
||||
if imgData.User == c.User() && hasSecData {
|
||||
kubeSec.RunAsGroup, kubeSec.RunAsUser = nil, nil
|
||||
}
|
||||
|
||||
|
@ -690,7 +689,9 @@ func containerToV1Container(ctx context.Context, c *Container) (v1.Container, []
|
|||
kubeContainer.Ports = ports
|
||||
// This should not be applicable
|
||||
// container.EnvFromSource =
|
||||
if hasSecData {
|
||||
kubeContainer.SecurityContext = kubeSec
|
||||
}
|
||||
kubeContainer.StdinOnce = false
|
||||
kubeContainer.TTY = c.Terminal()
|
||||
|
||||
|
@ -983,27 +984,16 @@ func determineCapAddDropFromCapabilities(defaultCaps, containerCaps []string) *v
|
|||
}
|
||||
}
|
||||
|
||||
if len(add) > 0 || len(drop) > 0 {
|
||||
return &v1.Capabilities{
|
||||
Add: add,
|
||||
Drop: drop,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func capAddDrop(caps *specs.LinuxCapabilities) (*v1.Capabilities, error) {
|
||||
g, err := generate.New("linux")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defCaps := g.Config.Process.Capabilities
|
||||
// Combine all the default capabilities into a slice
|
||||
defaultCaps := make([]string, 0, len(defCaps.Ambient)+len(defCaps.Bounding)+len(defCaps.Effective)+len(defCaps.Inheritable)+len(defCaps.Permitted))
|
||||
defaultCaps = append(defaultCaps, defCaps.Ambient...)
|
||||
defaultCaps = append(defaultCaps, defCaps.Bounding...)
|
||||
defaultCaps = append(defaultCaps, defCaps.Effective...)
|
||||
defaultCaps = append(defaultCaps, defCaps.Inheritable...)
|
||||
defaultCaps = append(defaultCaps, defCaps.Permitted...)
|
||||
|
||||
func (c *Container) capAddDrop(caps *specs.LinuxCapabilities) *v1.Capabilities {
|
||||
// Combine all the container's capabilities into a slice
|
||||
containerCaps := make([]string, 0, len(caps.Ambient)+len(caps.Bounding)+len(caps.Effective)+len(caps.Inheritable)+len(caps.Permitted))
|
||||
containerCaps = append(containerCaps, caps.Ambient...)
|
||||
|
@ -1012,12 +1002,12 @@ func capAddDrop(caps *specs.LinuxCapabilities) (*v1.Capabilities, error) {
|
|||
containerCaps = append(containerCaps, caps.Inheritable...)
|
||||
containerCaps = append(containerCaps, caps.Permitted...)
|
||||
|
||||
calculatedCaps := determineCapAddDropFromCapabilities(defaultCaps, containerCaps)
|
||||
return calculatedCaps, nil
|
||||
calculatedCaps := determineCapAddDropFromCapabilities(c.runtime.config.Containers.DefaultCapabilities, containerCaps)
|
||||
return calculatedCaps
|
||||
}
|
||||
|
||||
// generateKubeSecurityContext generates a securityContext based on the existing container
|
||||
func generateKubeSecurityContext(c *Container) (*v1.SecurityContext, error) {
|
||||
func generateKubeSecurityContext(c *Container) (*v1.SecurityContext, bool, error) {
|
||||
privileged := c.Privileged()
|
||||
ro := c.IsReadOnly()
|
||||
allowPrivEscalation := !c.config.Spec.Process.NoNewPrivileges
|
||||
|
@ -1025,19 +1015,17 @@ func generateKubeSecurityContext(c *Container) (*v1.SecurityContext, error) {
|
|||
var capabilities *v1.Capabilities
|
||||
if !privileged {
|
||||
// Running privileged adds all caps.
|
||||
newCaps, err := capAddDrop(c.config.Spec.Process.Capabilities)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
capabilities = newCaps
|
||||
capabilities = c.capAddDrop(c.config.Spec.Process.Capabilities)
|
||||
}
|
||||
|
||||
scHasData := false
|
||||
sc := v1.SecurityContext{
|
||||
// RunAsNonRoot is an optional parameter; our first implementations should be root only; however
|
||||
// I'm leaving this as a bread-crumb for later
|
||||
//RunAsNonRoot: &nonRoot,
|
||||
}
|
||||
if capabilities != nil {
|
||||
scHasData = true
|
||||
sc.Capabilities = capabilities
|
||||
}
|
||||
var selinuxOpts v1.SELinuxOptions
|
||||
|
@ -1048,24 +1036,30 @@ func generateKubeSecurityContext(c *Container) (*v1.SecurityContext, error) {
|
|||
case "type":
|
||||
selinuxOpts.Type = opts[1]
|
||||
sc.SELinuxOptions = &selinuxOpts
|
||||
scHasData = true
|
||||
case "level":
|
||||
selinuxOpts.Level = opts[1]
|
||||
sc.SELinuxOptions = &selinuxOpts
|
||||
scHasData = true
|
||||
}
|
||||
case 1:
|
||||
if opts[0] == "disable" {
|
||||
selinuxOpts.Type = "spc_t"
|
||||
sc.SELinuxOptions = &selinuxOpts
|
||||
scHasData = true
|
||||
}
|
||||
}
|
||||
|
||||
if !allowPrivEscalation {
|
||||
scHasData = true
|
||||
sc.AllowPrivilegeEscalation = &allowPrivEscalation
|
||||
}
|
||||
if privileged {
|
||||
scHasData = true
|
||||
sc.Privileged = &privileged
|
||||
}
|
||||
if ro {
|
||||
scHasData = true
|
||||
sc.ReadOnlyRootFilesystem = &ro
|
||||
}
|
||||
if c.User() != "" {
|
||||
|
@ -1074,7 +1068,7 @@ func generateKubeSecurityContext(c *Container) (*v1.SecurityContext, error) {
|
|||
defer c.lock.Unlock()
|
||||
}
|
||||
if err := c.syncContainer(); err != nil {
|
||||
return nil, fmt.Errorf("unable to sync container during YAML generation: %w", err)
|
||||
return nil, false, fmt.Errorf("unable to sync container during YAML generation: %w", err)
|
||||
}
|
||||
|
||||
mountpoint := c.state.Mountpoint
|
||||
|
@ -1082,7 +1076,7 @@ func generateKubeSecurityContext(c *Container) (*v1.SecurityContext, error) {
|
|||
var err error
|
||||
mountpoint, err = c.mount()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to mount %s mountpoint: %w", c.ID(), err)
|
||||
return nil, false, fmt.Errorf("failed to mount %s mountpoint: %w", c.ID(), err)
|
||||
}
|
||||
defer func() {
|
||||
if err := c.unmount(false); err != nil {
|
||||
|
@ -1094,14 +1088,16 @@ func generateKubeSecurityContext(c *Container) (*v1.SecurityContext, error) {
|
|||
|
||||
execUser, err := lookup.GetUserGroupInfo(mountpoint, c.User(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, false, err
|
||||
}
|
||||
uid := int64(execUser.Uid)
|
||||
gid := int64(execUser.Gid)
|
||||
scHasData = true
|
||||
sc.RunAsUser = &uid
|
||||
sc.RunAsGroup = &gid
|
||||
}
|
||||
return &sc, nil
|
||||
|
||||
return &sc, scHasData, nil
|
||||
}
|
||||
|
||||
// generateKubeVolumeDeviceFromLinuxDevice takes a list of devices and makes a VolumeDevice struct for kube
|
||||
|
|
|
@ -293,7 +293,7 @@ func (r *RootlessNetNS) Cleanup(runtime *Runtime) error {
|
|||
return nil
|
||||
}
|
||||
logrus.Debug("Cleaning up rootless network namespace")
|
||||
err = netns.UnmountNS(r.ns)
|
||||
err = netns.UnmountNS(r.ns.Path())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -605,7 +605,7 @@ func (r *Runtime) createNetNS(ctr *Container) (n ns.NetNS, q map[string]types.St
|
|||
}
|
||||
defer func() {
|
||||
if retErr != nil {
|
||||
if err := netns.UnmountNS(ctrNS); err != nil {
|
||||
if err := netns.UnmountNS(ctrNS.Path()); err != nil {
|
||||
logrus.Errorf("Unmounting partially created network namespace for container %s: %v", ctr.ID(), err)
|
||||
}
|
||||
if err := ctrNS.Close(); err != nil {
|
||||
|
@ -705,7 +705,7 @@ func (r *Runtime) teardownNetNS(ctr *Container) error {
|
|||
prevErr := r.teardownCNI(ctr)
|
||||
|
||||
// First unmount the namespace
|
||||
if err := netns.UnmountNS(ctr.state.NetNS); err != nil {
|
||||
if err := netns.UnmountNS(ctr.state.NetNS.Path()); err != nil {
|
||||
if prevErr != nil {
|
||||
logrus.Error(prevErr)
|
||||
}
|
||||
|
|
|
@ -6,12 +6,10 @@
|
|||
default_capabilities = [
|
||||
"CHOWN",
|
||||
"DAC_OVERRIDE",
|
||||
"FOWNER",
|
||||
"FSETID",
|
||||
"KILL",
|
||||
"MKNOD",
|
||||
"NET_BIND_SERVICE",
|
||||
"SETGID",
|
||||
"SETPCAP",
|
||||
"SETUID",
|
||||
]
|
||||
|
|
|
@ -113,8 +113,8 @@ var _ = Describe("Verify podman containers.conf usage", func() {
|
|||
Expect(result).Should(Exit(0))
|
||||
Expect(result.Out.Contents()).To(
|
||||
And(
|
||||
ContainSubstring("SYS_CHROOT"),
|
||||
ContainSubstring("NET_RAW"),
|
||||
ContainSubstring("FOWNER"),
|
||||
ContainSubstring("SETFCAP"),
|
||||
))
|
||||
})
|
||||
|
||||
|
@ -130,8 +130,8 @@ var _ = Describe("Verify podman containers.conf usage", func() {
|
|||
Expect(result).Should(Exit(0))
|
||||
Expect(result.Out.Contents()).ToNot(
|
||||
And(
|
||||
ContainSubstring("SYS_CHROOT"),
|
||||
ContainSubstring("NET_RAW"),
|
||||
ContainSubstring("SETUID"),
|
||||
ContainSubstring("FOWNER"),
|
||||
))
|
||||
})
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@ var _ = Describe("Podman generate kube", func() {
|
|||
Expect(pod.Spec.SecurityContext).To(BeNil())
|
||||
Expect(pod.Spec.DNSConfig).To(BeNil())
|
||||
Expect(pod.Spec.Containers[0]).To(HaveField("WorkingDir", ""))
|
||||
Expect(pod.Spec.Containers[0].SecurityContext).To(BeNil())
|
||||
Expect(pod.Spec.Containers[0].Env).To(BeNil())
|
||||
Expect(pod).To(HaveField("Name", "top-pod"))
|
||||
|
||||
|
|
|
@ -514,7 +514,7 @@ var _ = Describe("Podman inspect", func() {
|
|||
|
||||
It("Dropped capabilities are sorted", func() {
|
||||
ctrName := "testCtr"
|
||||
session := podmanTest.Podman([]string{"run", "-d", "--cap-drop", "CAP_AUDIT_WRITE", "--cap-drop", "CAP_MKNOD", "--cap-drop", "CAP_NET_RAW", "--name", ctrName, ALPINE, "top"})
|
||||
session := podmanTest.Podman([]string{"run", "-d", "--cap-drop", "SETUID", "--cap-drop", "SETGID", "--cap-drop", "CAP_NET_BIND_SERVICE", "--name", ctrName, ALPINE, "top"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
|
||||
|
@ -525,9 +525,26 @@ var _ = Describe("Podman inspect", func() {
|
|||
data := inspect.InspectContainerToJSON()
|
||||
Expect(data).To(HaveLen(1))
|
||||
Expect(data[0].HostConfig.CapDrop).To(HaveLen(3))
|
||||
Expect(data[0].HostConfig.CapDrop[0]).To(Equal("CAP_AUDIT_WRITE"))
|
||||
Expect(data[0].HostConfig.CapDrop[1]).To(Equal("CAP_MKNOD"))
|
||||
Expect(data[0].HostConfig.CapDrop[2]).To(Equal("CAP_NET_RAW"))
|
||||
Expect(data[0].HostConfig.CapDrop[0]).To(Equal("CAP_NET_BIND_SERVICE"))
|
||||
Expect(data[0].HostConfig.CapDrop[1]).To(Equal("CAP_SETGID"))
|
||||
Expect(data[0].HostConfig.CapDrop[2]).To(Equal("CAP_SETUID"))
|
||||
})
|
||||
|
||||
It("Add capabilities are sorted", func() {
|
||||
ctrName := "testCtr"
|
||||
session := podmanTest.Podman([]string{"run", "-d", "--cap-add", "SYS_ADMIN", "--cap-add", "CAP_NET_ADMIN", "--name", ctrName, ALPINE, "top"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
|
||||
inspect := podmanTest.Podman([]string{"inspect", ctrName})
|
||||
inspect.WaitWithDefaultTimeout()
|
||||
Expect(inspect).Should(Exit(0))
|
||||
|
||||
data := inspect.InspectContainerToJSON()
|
||||
Expect(data).To(HaveLen(1))
|
||||
Expect(data[0].HostConfig.CapAdd).To(HaveLen(2))
|
||||
Expect(data[0].HostConfig.CapAdd[0]).To(Equal("CAP_NET_ADMIN"))
|
||||
Expect(data[0].HostConfig.CapAdd[1]).To(Equal("CAP_SYS_ADMIN"))
|
||||
})
|
||||
|
||||
It("podman inspect container with GO format for PidFile", func() {
|
||||
|
|
|
@ -62,11 +62,6 @@ spec:
|
|||
resources: {}
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
capabilities:
|
||||
drop:
|
||||
- CAP_MKNOD
|
||||
- CAP_NET_RAW
|
||||
- CAP_AUDIT_WRITE
|
||||
privileged: false
|
||||
readOnlyRootFilesystem: false
|
||||
seLinuxOptions: {}
|
||||
|
|
|
@ -423,11 +423,6 @@ spec:
|
|||
name: test
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: true
|
||||
capabilities:
|
||||
drop:
|
||||
- CAP_MKNOD
|
||||
- CAP_NET_RAW
|
||||
- CAP_AUDIT_WRITE
|
||||
privileged: false
|
||||
readOnlyRootFilesystem: false
|
||||
seLinuxOptions:
|
||||
|
@ -4463,12 +4458,6 @@ spec:
|
|||
- "1000"
|
||||
image: non-existing-image
|
||||
name: vol-test-3
|
||||
securityContext:
|
||||
capabilities:
|
||||
drop:
|
||||
- CAP_MKNOD
|
||||
- CAP_NET_RAW
|
||||
- CAP_AUDIT_WRITE
|
||||
`
|
||||
|
||||
// the image is incorrect so the kube play will fail, but it will clean up the pod that was created for it before the failure happened
|
||||
|
|
|
@ -411,7 +411,7 @@ var _ = Describe("Podman pod create", func() {
|
|||
Expect(session.ErrorToString()).To(ContainSubstring("extra host entries must be specified on the pod: network cannot be configured when it is shared with a pod"))
|
||||
|
||||
// verify we can see the pods hosts
|
||||
session = podmanTest.Podman([]string{"run", "--pod", podID, ALPINE, "ping", "-c", "1", "host1"})
|
||||
session = podmanTest.Podman([]string{"run", "--cap-add", "net_raw", "--pod", podID, ALPINE, "ping", "-c", "1", "host1"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
})
|
||||
|
|
|
@ -434,7 +434,7 @@ EXPOSE 2004-2005/tcp`, ALPINE)
|
|||
})
|
||||
|
||||
It("podman run slirp4netns network with host loopback", func() {
|
||||
session := podmanTest.Podman([]string{"run", "--network", "slirp4netns:allow_host_loopback=true", ALPINE, "ping", "-c1", "10.0.2.2"})
|
||||
session := podmanTest.Podman([]string{"run", "--cap-add", "net_raw", "--network", "slirp4netns:allow_host_loopback=true", ALPINE, "ping", "-c1", "10.0.2.2"})
|
||||
session.Wait(30)
|
||||
Expect(session).Should(Exit(0))
|
||||
})
|
||||
|
@ -451,7 +451,7 @@ EXPOSE 2004-2005/tcp`, ALPINE)
|
|||
Expect(slirp4netnsHelp).Should(Exit(0))
|
||||
|
||||
networkConfiguration := "slirp4netns:cidr=192.168.0.0/24,allow_host_loopback=true"
|
||||
session := podmanTest.Podman([]string{"run", "--network", networkConfiguration, ALPINE, "ping", "-c1", "192.168.0.2"})
|
||||
session := podmanTest.Podman([]string{"run", "--cap-add", "net_raw", "--network", networkConfiguration, ALPINE, "ping", "-c1", "192.168.0.2"})
|
||||
session.Wait(30)
|
||||
|
||||
if strings.Contains(slirp4netnsHelp.OutputToString(), "cidr") {
|
||||
|
@ -988,11 +988,11 @@ EXPOSE 2004-2005/tcp`, ALPINE)
|
|||
|
||||
pingTest := func(netns string) {
|
||||
hostname := "testctr"
|
||||
run := podmanTest.Podman([]string{"run", netns, "--hostname", hostname, ALPINE, "ping", "-c", "1", hostname})
|
||||
run := podmanTest.Podman([]string{"run", netns, "--cap-add", "net_raw", "--hostname", hostname, ALPINE, "ping", "-c", "1", hostname})
|
||||
run.WaitWithDefaultTimeout()
|
||||
Expect(run).Should(Exit(0))
|
||||
|
||||
run = podmanTest.Podman([]string{"run", netns, "--hostname", hostname, "--name", "test", ALPINE, "ping", "-c", "1", "test"})
|
||||
run = podmanTest.Podman([]string{"run", netns, "--cap-add", "net_raw", "--hostname", hostname, "--name", "test", ALPINE, "ping", "-c", "1", "test"})
|
||||
run.WaitWithDefaultTimeout()
|
||||
Expect(run).Should(Exit(0))
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ var _ = Describe("Podman generate kube", func() {
|
|||
test1.WaitWithDefaultTimeout()
|
||||
Expect(test1).Should(Exit(0))
|
||||
|
||||
commit := podmanTest.Podman([]string{"commit", "-c", "label=io.containers.capabilities=sys_chroot,setuid", "test1", "image1"})
|
||||
commit := podmanTest.Podman([]string{"commit", "-c", "label=io.containers.capabilities=setgid,setuid", "test1", "image1"})
|
||||
commit.WaitWithDefaultTimeout()
|
||||
Expect(commit).Should(Exit(0))
|
||||
|
||||
|
@ -108,7 +108,7 @@ var _ = Describe("Podman generate kube", func() {
|
|||
|
||||
ctr := inspect.InspectContainerToJSON()
|
||||
caps := strings.Join(ctr[0].EffectiveCaps, ",")
|
||||
Expect(caps).To(Equal("CAP_SETUID,CAP_SYS_CHROOT"))
|
||||
Expect(caps).To(Equal("CAP_SETGID,CAP_SETUID"))
|
||||
|
||||
})
|
||||
|
||||
|
|
|
@ -495,7 +495,7 @@ var _ = Describe("Podman run", func() {
|
|||
session := podmanTest.Podman([]string{"run", "--rm", "--user", "bin", ALPINE, "grep", "CapBnd", "/proc/self/status"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
Expect(session.OutputToString()).To(ContainSubstring("00000000a80425fb"))
|
||||
Expect(session.OutputToString()).To(ContainSubstring("00000000800005fb"))
|
||||
|
||||
session = podmanTest.Podman([]string{"run", "--rm", "--user", "bin", ALPINE, "grep", "CapEff", "/proc/self/status"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
|
@ -510,12 +510,12 @@ var _ = Describe("Podman run", func() {
|
|||
session = podmanTest.Podman([]string{"run", "--rm", "--user", "root", ALPINE, "grep", "CapBnd", "/proc/self/status"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
Expect(session.OutputToString()).To(ContainSubstring("00000000a80425fb"))
|
||||
Expect(session.OutputToString()).To(ContainSubstring("00000000800005fb"))
|
||||
|
||||
session = podmanTest.Podman([]string{"run", "--rm", "--user", "root", ALPINE, "grep", "CapEff", "/proc/self/status"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
Expect(session.OutputToString()).To(ContainSubstring("00000000a80425fb"))
|
||||
Expect(session.OutputToString()).To(ContainSubstring("00000000800005fb"))
|
||||
|
||||
session = podmanTest.Podman([]string{"run", "--rm", "--user", "root", ALPINE, "grep", "CapInh", "/proc/self/status"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
|
@ -525,12 +525,12 @@ var _ = Describe("Podman run", func() {
|
|||
session = podmanTest.Podman([]string{"run", "--rm", ALPINE, "grep", "CapBnd", "/proc/self/status"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
Expect(session.OutputToString()).To(ContainSubstring("00000000a80425fb"))
|
||||
Expect(session.OutputToString()).To(ContainSubstring("00000000800005fb"))
|
||||
|
||||
session = podmanTest.Podman([]string{"run", "--rm", ALPINE, "grep", "CapEff", "/proc/self/status"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
Expect(session.OutputToString()).To(ContainSubstring("00000000a80425fb"))
|
||||
Expect(session.OutputToString()).To(ContainSubstring("00000000800005fb"))
|
||||
|
||||
session = podmanTest.Podman([]string{"run", "--user=1000:1000", "--cap-add=DAC_OVERRIDE", "--rm", ALPINE, "grep", "CapAmb", "/proc/self/status"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
|
@ -598,7 +598,7 @@ USER bin`, BB)
|
|||
session := podmanTest.Podman([]string{"run", "--rm", "--user", "bin", "test", "grep", "CapBnd", "/proc/self/status"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(Exit(0))
|
||||
Expect(session.OutputToString()).To(ContainSubstring("00000000a80425fb"))
|
||||
Expect(session.OutputToString()).To(ContainSubstring("00000000800005fb"))
|
||||
|
||||
session = podmanTest.Podman([]string{"run", "--rm", "--user", "bin", "test", "grep", "CapEff", "/proc/self/status"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
|
|
|
@ -262,10 +262,10 @@ EOF
|
|||
t0=$(date --iso-8601=seconds)
|
||||
|
||||
CONTAINERS_CONF=$containersConf run_podman create --name=$cname $IMAGE
|
||||
run_podman container inspect --size=true $cname
|
||||
CONTAINERS_CONF=$containersConf run_podman container inspect --size=true $cname
|
||||
inspect_json=$(jq -r --tab . <<< "$output")
|
||||
|
||||
run_podman --events-backend=$1 events \
|
||||
CONTAINERS_CONF=$containersConf run_podman --events-backend=$1 events \
|
||||
--since="$t0" \
|
||||
--filter=status=$cname \
|
||||
--filter=status=create \
|
||||
|
@ -276,7 +276,7 @@ EOF
|
|||
|
||||
# Make sure that the inspect data doesn't show by default in
|
||||
# podman-events.
|
||||
run_podman --events-backend=$1 events \
|
||||
CONTAINERS_CONF=$containersConf run_podman --events-backend=$1 events \
|
||||
--since="$t0" \
|
||||
--filter=status=$cname \
|
||||
--filter=status=create \
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
load helpers
|
||||
|
||||
# standard capability drop list
|
||||
capabilities='{"drop":["CAP_MKNOD","CAP_NET_RAW","CAP_AUDIT_WRITE"]}'
|
||||
# capability drop list
|
||||
capabilities='{"drop":["CAP_FOWNER","CAP_SETFCAP"]}'
|
||||
|
||||
# Warning that is emitted once on containers, multiple times on pods
|
||||
kubernetes_63='Truncation Annotation: .* Kubernetes only allows 63 characters'
|
||||
|
@ -31,7 +31,7 @@ json.dump(yaml.safe_load(sys.stdin), sys.stdout)'
|
|||
|
||||
@test "podman kube generate - container" {
|
||||
cname=c$(random_string 15)
|
||||
run_podman container create --name $cname $IMAGE top
|
||||
run_podman container create --cap-drop fowner --cap-drop setfcap --name $cname $IMAGE top
|
||||
run_podman kube generate $cname
|
||||
|
||||
# Convert yaml to json, and dump to stdout (to help in case of errors)
|
||||
|
@ -95,7 +95,7 @@ status | = | null
|
|||
run_podman 125 kube generate $pname
|
||||
assert "$output" =~ "Error: .* only has an infra container"
|
||||
|
||||
run_podman container create --name $cname1 --pod $pname $IMAGE top
|
||||
run_podman container create --cap-drop fowner --cap-drop setfcap --name $cname1 --pod $pname $IMAGE top
|
||||
run_podman container create --name $cname2 --pod $pname $IMAGE bottom
|
||||
run_podman kube generate $pname
|
||||
|
||||
|
|
|
@ -86,6 +86,12 @@ type Container interface {
|
|||
// container to be terminated by some error condition (including calling
|
||||
// Close).
|
||||
Wait() error
|
||||
// WaitChannel returns the wait channel of the container
|
||||
WaitChannel() <-chan struct{}
|
||||
// WaitError returns the container termination error.
|
||||
// This function should only be called after the channel in WaitChannel()
|
||||
// is closed. Otherwise it is not thread safe.
|
||||
WaitError() error
|
||||
// Modify sends a request to modify container resources
|
||||
Modify(ctx context.Context, config interface{}) error
|
||||
}
|
||||
|
|
|
@ -287,11 +287,19 @@ func (computeSystem *System) waitBackground() {
|
|||
oc.SetSpanStatus(span, err)
|
||||
}
|
||||
|
||||
func (computeSystem *System) WaitChannel() <-chan struct{} {
|
||||
return computeSystem.waitBlock
|
||||
}
|
||||
|
||||
func (computeSystem *System) WaitError() error {
|
||||
return computeSystem.waitError
|
||||
}
|
||||
|
||||
// Wait synchronously waits for the compute system to shutdown or terminate. If
|
||||
// the compute system has already exited returns the previous error (if any).
|
||||
func (computeSystem *System) Wait() error {
|
||||
<-computeSystem.waitBlock
|
||||
return computeSystem.waitError
|
||||
<-computeSystem.WaitChannel()
|
||||
return computeSystem.WaitError()
|
||||
}
|
||||
|
||||
// ExitError returns an error describing the reason the compute system terminated.
|
||||
|
|
|
@ -15,6 +15,10 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (n *cniNetwork) NetworkUpdate(name string, options types.NetworkUpdateOptions) error {
|
||||
return fmt.Errorf("NetworkUpdate is not supported for backend CNI: %w", types.ErrInvalidArg)
|
||||
}
|
||||
|
||||
// NetworkCreate will take a partial filled Network and fill the
|
||||
// missing fields. It creates the Network and returns the full Network.
|
||||
func (n *cniNetwork) NetworkCreate(net types.Network, options *types.NetworkCreateOptions) (types.Network, error) {
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
|
@ -19,6 +20,65 @@ import (
|
|||
"github.com/containers/storage/pkg/stringid"
|
||||
)
|
||||
|
||||
func sliceRemoveDuplicates(strList []string) []string {
|
||||
list := make([]string, 0, len(strList))
|
||||
for _, item := range strList {
|
||||
if !util.StringInSlice(item, list) {
|
||||
list = append(list, item)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func (n *netavarkNetwork) commitNetwork(network *types.Network) error {
|
||||
confPath := filepath.Join(n.networkConfigDir, network.Name+".json")
|
||||
f, err := os.Create(confPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
enc := json.NewEncoder(f)
|
||||
enc.SetIndent("", " ")
|
||||
err = enc.Encode(network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *netavarkNetwork) NetworkUpdate(name string, options types.NetworkUpdateOptions) error {
|
||||
n.lock.Lock()
|
||||
defer n.lock.Unlock()
|
||||
err := n.loadNetworks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
network, err := n.getNetwork(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
networkDNSServersBefore := network.NetworkDNSServers
|
||||
networkDNSServersAfter := []string{}
|
||||
for _, server := range networkDNSServersBefore {
|
||||
if util.StringInSlice(server, options.RemoveDNSServers) {
|
||||
continue
|
||||
}
|
||||
networkDNSServersAfter = append(networkDNSServersAfter, server)
|
||||
}
|
||||
networkDNSServersAfter = append(networkDNSServersAfter, options.AddDNSServers...)
|
||||
networkDNSServersAfter = sliceRemoveDuplicates(networkDNSServersAfter)
|
||||
network.NetworkDNSServers = networkDNSServersAfter
|
||||
if reflect.DeepEqual(networkDNSServersBefore, networkDNSServersAfter) {
|
||||
return nil
|
||||
}
|
||||
err = n.commitNetwork(network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return n.execUpdate(network.Name, network.NetworkDNSServers)
|
||||
}
|
||||
|
||||
// NetworkCreate will take a partial filled Network and fill the
|
||||
// missing fields. It creates the Network and returns the full Network.
|
||||
func (n *netavarkNetwork) NetworkCreate(net types.Network, options *types.NetworkCreateOptions) (types.Network, error) {
|
||||
|
@ -163,15 +223,7 @@ func (n *netavarkNetwork) networkCreate(newNetwork *types.Network, defaultNet bo
|
|||
newNetwork.Created = time.Now()
|
||||
|
||||
if !defaultNet {
|
||||
confPath := filepath.Join(n.networkConfigDir, newNetwork.Name+".json")
|
||||
f, err := os.Create(confPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
enc := json.NewEncoder(f)
|
||||
enc.SetIndent("", " ")
|
||||
err = enc.Encode(newNetwork)
|
||||
err = n.commitNetwork(newNetwork)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/common/libnetwork/internal/util"
|
||||
"github.com/containers/common/libnetwork/types"
|
||||
|
@ -18,6 +19,11 @@ type netavarkOptions struct {
|
|||
Networks map[string]*types.Network `json:"network_info"`
|
||||
}
|
||||
|
||||
func (n *netavarkNetwork) execUpdate(networkName string, networkDNSServers []string) error {
|
||||
retErr := n.execNetavark([]string{"update", networkName, "--network-dns-servers", strings.Join(networkDNSServers, ",")}, nil, nil)
|
||||
return retErr
|
||||
}
|
||||
|
||||
// Setup will setup the container network namespace. It returns
|
||||
// a map of StatusBlocks, the key is the network name.
|
||||
func (n *netavarkNetwork) Setup(namespacePath string, options types.SetupOptions) (map[string]types.StatusBlock, error) {
|
||||
|
|
|
@ -10,6 +10,8 @@ type ContainerNetwork interface {
|
|||
// NetworkCreate will take a partial filled Network and fill the
|
||||
// missing fields. It creates the Network and returns the full Network.
|
||||
NetworkCreate(Network, *NetworkCreateOptions) (Network, error)
|
||||
// NetworkUpdate will take network name and ID and updates network DNS Servers.
|
||||
NetworkUpdate(nameOrID string, options NetworkUpdateOptions) error
|
||||
// NetworkRemove will remove the Network with the given name or ID.
|
||||
NetworkRemove(nameOrID string) error
|
||||
// NetworkList will return all known Networks. Optionally you can
|
||||
|
@ -70,6 +72,14 @@ type Network struct {
|
|||
IPAMOptions map[string]string `json:"ipam_options,omitempty"`
|
||||
}
|
||||
|
||||
// NetworkOptions for a given container.
|
||||
type NetworkUpdateOptions struct {
|
||||
// List of custom DNS server for podman's DNS resolver.
|
||||
// Priority order will be kept as defined by user in the configuration.
|
||||
AddDNSServers []string `json:"add_dns_servers,omitempty"`
|
||||
RemoveDNSServers []string `json:"remove_dns_servers,omitempty"`
|
||||
}
|
||||
|
||||
// IPNet is used as custom net.IPNet type to add Marshal/Unmarshal methods.
|
||||
type IPNet struct {
|
||||
net.IPNet
|
||||
|
|
|
@ -52,19 +52,18 @@
|
|||
# List of default capabilities for containers. If it is empty or commented out,
|
||||
# the default capabilities defined in the container engine will be added.
|
||||
#
|
||||
default_capabilities = [
|
||||
"CHOWN",
|
||||
"DAC_OVERRIDE",
|
||||
"FOWNER",
|
||||
"FSETID",
|
||||
"KILL",
|
||||
"NET_BIND_SERVICE",
|
||||
"SETFCAP",
|
||||
"SETGID",
|
||||
"SETPCAP",
|
||||
"SETUID",
|
||||
"SYS_CHROOT"
|
||||
]
|
||||
#default_capabilities = [
|
||||
# "CHOWN",
|
||||
# "DAC_OVERRIDE",
|
||||
# "FOWNER",
|
||||
# "FSETID",
|
||||
# "KILL",
|
||||
# "NET_BIND_SERVICE",
|
||||
# "SETFCAP",
|
||||
# "SETGID",
|
||||
# "SETPCAP",
|
||||
# "SETUID",
|
||||
#]
|
||||
|
||||
# A list of sysctls to be set in containers by default,
|
||||
# specified as "name=value",
|
||||
|
|
|
@ -50,20 +50,16 @@ var (
|
|||
DefaultHooksDirs = []string{"/usr/share/containers/oci/hooks.d"}
|
||||
// DefaultCapabilities is the default for the default_capabilities option in the containers.conf file.
|
||||
DefaultCapabilities = []string{
|
||||
"CAP_AUDIT_WRITE",
|
||||
"CAP_CHOWN",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_FOWNER",
|
||||
"CAP_FSETID",
|
||||
"CAP_KILL",
|
||||
"CAP_MKNOD",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_SETUID",
|
||||
"CAP_SYS_CHROOT",
|
||||
}
|
||||
|
||||
// Search these locations in which CNIPlugins can be installed.
|
||||
|
|
|
@ -14,5 +14,9 @@ func getLibpodTmpDir() string {
|
|||
|
||||
// getDefaultMachineVolumes returns default mounted volumes (possibly with env vars, which will be expanded)
|
||||
func getDefaultMachineVolumes() []string {
|
||||
return []string{"$HOME:$HOME"}
|
||||
return []string{
|
||||
"/Users:/Users",
|
||||
"/private:/private",
|
||||
"/var/folders:/var/folders",
|
||||
}
|
||||
}
|
||||
|
|
|
@ -179,14 +179,13 @@ func NewNSWithName(name string) (ns.NetNS, error) {
|
|||
return ns.GetNS(nsPath)
|
||||
}
|
||||
|
||||
// UnmountNS unmounts the NS held by the netns object
|
||||
func UnmountNS(netns ns.NetNS) error {
|
||||
// UnmountNS unmounts the given netns path
|
||||
func UnmountNS(nsPath string) error {
|
||||
nsRunDir, err := GetNSRunDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nsPath := netns.Path()
|
||||
// Only unmount if it's been bind-mounted (don't touch namespaces in /proc...)
|
||||
if strings.HasPrefix(nsPath, nsRunDir) {
|
||||
if err := unix.Unmount(nsPath, unix.MNT_DETACH); err != nil {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/*
|
||||
Package report provides helper structs/methods/funcs for formatting output
|
||||
|
||||
# Examples
|
||||
|
||||
To format output for an array of structs:
|
||||
|
||||
ExamplePodman:
|
||||
|
@ -54,7 +56,7 @@ Helpers:
|
|||
... "table" keyword prefix in format text
|
||||
}
|
||||
|
||||
Template Functions:
|
||||
# Template Functions
|
||||
|
||||
The following template functions are added to the template when parsed:
|
||||
- join strings.Join, {{join .Field separator}}
|
||||
|
|
|
@ -522,9 +522,8 @@ func parseRetryAfter(res *http.Response, fallbackDelay time.Duration) time.Durat
|
|||
return time.Duration(num) * time.Second
|
||||
}
|
||||
// Second, check if we have an HTTP date.
|
||||
// If the delta between the date and now is positive, use it.
|
||||
// Otherwise, fall back to using the default exponential back off.
|
||||
if t, err := http.ParseTime(after); err == nil {
|
||||
// If the delta between the date and now is positive, use it.
|
||||
delta := time.Until(t)
|
||||
if delta > 0 {
|
||||
return delta
|
||||
|
@ -532,7 +531,6 @@ func parseRetryAfter(res *http.Response, fallbackDelay time.Duration) time.Durat
|
|||
logrus.Debugf("Retry-After date in the past, ignoring it")
|
||||
return fallbackDelay
|
||||
}
|
||||
// If the header contents are bogus, fall back to using the default exponential back off.
|
||||
logrus.Debugf("Invalid Retry-After format, ignoring it")
|
||||
return fallbackDelay
|
||||
}
|
||||
|
@ -590,7 +588,7 @@ func (c *dockerClient) makeRequestToResolvedURL(ctx context.Context, method stri
|
|||
case <-time.After(delay):
|
||||
// Nothing
|
||||
}
|
||||
delay = delay * 2 // exponential back off
|
||||
delay = delay * 2 // If the registry does not specify a delay, back off exponentially.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -639,7 +639,7 @@ func (d *dockerImageDestination) putSignaturesToSigstoreAttachments(ctx context.
|
|||
|
||||
ociManifest, err := d.c.getSigstoreAttachmentManifest(ctx, d.ref, manifestDigest)
|
||||
if err != nil {
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
var ociConfig imgspecv1.Image // Most fields empty by default
|
||||
if ociManifest == nil {
|
||||
|
@ -711,13 +711,13 @@ func (d *dockerImageDestination) putSignaturesToSigstoreAttachments(ctx context.
|
|||
LayerIndex: nil,
|
||||
})
|
||||
if err != nil {
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
ociManifest.Config = configDesc
|
||||
|
||||
manifestBlob, err := ociManifest.Serialize()
|
||||
if err != nil {
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
logrus.Debugf("Uploading sigstore attachment manifest")
|
||||
return d.uploadManifest(ctx, manifestBlob, sigstoreAttachmentTag(manifestDigest))
|
||||
|
|
|
@ -34,16 +34,20 @@ func NewReaderFromFile(sys *types.SystemContext, path string) (*Reader, error) {
|
|||
}
|
||||
defer file.Close()
|
||||
|
||||
// If the file is already not compressed we can just return the file itself
|
||||
// If the file is seekable and already not compressed we can just return the file itself
|
||||
// as a source. Otherwise we pass the stream to NewReaderFromStream.
|
||||
stream, isCompressed, err := compression.AutoDecompress(file)
|
||||
var stream io.Reader = file
|
||||
if _, err := file.Seek(0, io.SeekCurrent); err == nil { // seeking is possible
|
||||
decompressed, isCompressed, err := compression.AutoDecompress(file)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("detecting compression for file %q: %w", path, err)
|
||||
}
|
||||
defer stream.Close()
|
||||
defer decompressed.Close()
|
||||
stream = decompressed
|
||||
if !isCompressed {
|
||||
return newReader(path, false)
|
||||
}
|
||||
}
|
||||
return NewReaderFromStream(sys, stream)
|
||||
}
|
||||
|
||||
|
|
|
@ -346,7 +346,7 @@ func (t *tarFI) Sys() interface{} {
|
|||
func (w *Writer) sendSymlinkLocked(path string, target string) error {
|
||||
hdr, err := tar.FileInfoHeader(&tarFI{path: path, size: 0, isSymlink: true}, target)
|
||||
if err != nil {
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
logrus.Debugf("Sending as tar link %s -> %s", path, target)
|
||||
return w.tar.WriteHeader(hdr)
|
||||
|
@ -363,7 +363,7 @@ func (w *Writer) sendBytesLocked(path string, b []byte) error {
|
|||
func (w *Writer) sendFileLocked(path string, expectedSize int64, stream io.Reader) error {
|
||||
hdr, err := tar.FileInfoHeader(&tarFI{path: path, size: expectedSize}, "")
|
||||
if err != nil {
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
logrus.Debugf("Sending as tar file %s", path)
|
||||
if err := w.tar.WriteHeader(hdr); err != nil {
|
||||
|
|
|
@ -56,7 +56,7 @@ var (
|
|||
// appropriate for sys and the users’ configuration.
|
||||
// A valid key is a repository, a namespace within a registry, or a registry hostname;
|
||||
// using forms other than just a registry may fail depending on configuration.
|
||||
// Returns a human-redable description of the location that was updated.
|
||||
// Returns a human-readable description of the location that was updated.
|
||||
// NOTE: The return value is only intended to be read by humans; its form is not an API,
|
||||
// it may change (or new forms can be added) any time.
|
||||
func SetCredentials(sys *types.SystemContext, key, username, password string) (string, error) {
|
||||
|
@ -78,25 +78,28 @@ func SetCredentials(sys *types.SystemContext, key, username, password string) (s
|
|||
switch helper {
|
||||
// Special-case the built-in helpers for auth files.
|
||||
case sysregistriesv2.AuthenticationFileHelper:
|
||||
desc, err = modifyJSON(sys, func(auths *dockerConfigFile) (bool, error) {
|
||||
desc, err = modifyJSON(sys, func(auths *dockerConfigFile) (bool, string, error) {
|
||||
if ch, exists := auths.CredHelpers[key]; exists {
|
||||
if isNamespaced {
|
||||
return false, unsupportedNamespaceErr(ch)
|
||||
return false, "", unsupportedNamespaceErr(ch)
|
||||
}
|
||||
return false, setAuthToCredHelper(ch, key, username, password)
|
||||
desc, err := setAuthToCredHelper(ch, key, username, password)
|
||||
if err != nil {
|
||||
return false, "", err
|
||||
}
|
||||
return false, desc, nil
|
||||
}
|
||||
creds := base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
|
||||
newCreds := dockerAuthConfig{Auth: creds}
|
||||
auths.AuthConfigs[key] = newCreds
|
||||
return true, nil
|
||||
return true, "", nil
|
||||
})
|
||||
// External helpers.
|
||||
default:
|
||||
if isNamespaced {
|
||||
err = unsupportedNamespaceErr(helper)
|
||||
} else {
|
||||
desc = fmt.Sprintf("credential helper: %s", helper)
|
||||
err = setAuthToCredHelper(helper, key, username, password)
|
||||
desc, err = setAuthToCredHelper(helper, key, username, password)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -214,6 +217,7 @@ func getAuthFilePaths(sys *types.SystemContext, homeDir string) []authPath {
|
|||
// Logging the error as a warning instead and moving on to pulling the image
|
||||
logrus.Warnf("%v: Trying to pull image in the event that it is a public image.", err)
|
||||
}
|
||||
if sys == nil || (sys.AuthFilePath == "" && sys.LegacyFormatAuthFilePath == "") {
|
||||
xdgCfgHome := os.Getenv("XDG_CONFIG_HOME")
|
||||
if xdgCfgHome == "" {
|
||||
xdgCfgHome = filepath.Join(homeDir, ".config")
|
||||
|
@ -231,6 +235,7 @@ func getAuthFilePaths(sys *types.SystemContext, homeDir string) []authPath {
|
|||
paths = append(paths,
|
||||
authPath{path: filepath.Join(homeDir, dockerLegacyHomePath), legacyFormat: true},
|
||||
)
|
||||
}
|
||||
return paths
|
||||
}
|
||||
|
||||
|
@ -403,7 +408,7 @@ func RemoveAuthentication(sys *types.SystemContext, key string) error {
|
|||
switch helper {
|
||||
// Special-case the built-in helper for auth files.
|
||||
case sysregistriesv2.AuthenticationFileHelper:
|
||||
_, err = modifyJSON(sys, func(auths *dockerConfigFile) (bool, error) {
|
||||
_, err = modifyJSON(sys, func(auths *dockerConfigFile) (bool, string, error) {
|
||||
if innerHelper, exists := auths.CredHelpers[key]; exists {
|
||||
removeFromCredHelper(innerHelper)
|
||||
}
|
||||
|
@ -411,7 +416,7 @@ func RemoveAuthentication(sys *types.SystemContext, key string) error {
|
|||
isLoggedIn = true
|
||||
delete(auths.AuthConfigs, key)
|
||||
}
|
||||
return true, multiErr
|
||||
return true, "", multiErr
|
||||
})
|
||||
if err != nil {
|
||||
multiErr = multierror.Append(multiErr, err)
|
||||
|
@ -446,18 +451,18 @@ func RemoveAllAuthentication(sys *types.SystemContext) error {
|
|||
switch helper {
|
||||
// Special-case the built-in helper for auth files.
|
||||
case sysregistriesv2.AuthenticationFileHelper:
|
||||
_, err = modifyJSON(sys, func(auths *dockerConfigFile) (bool, error) {
|
||||
_, err = modifyJSON(sys, func(auths *dockerConfigFile) (bool, string, error) {
|
||||
for registry, helper := range auths.CredHelpers {
|
||||
// Helpers in auth files are expected
|
||||
// to exist, so no special treatment
|
||||
// for them.
|
||||
if err := deleteAuthFromCredHelper(helper, registry); err != nil {
|
||||
return false, err
|
||||
return false, "", err
|
||||
}
|
||||
}
|
||||
auths.CredHelpers = make(map[string]string)
|
||||
auths.AuthConfigs = make(map[string]dockerAuthConfig)
|
||||
return true, nil
|
||||
return true, "", nil
|
||||
})
|
||||
// External helpers.
|
||||
default:
|
||||
|
@ -573,8 +578,11 @@ func readJSONFile(path string, legacyFormat bool) (dockerConfigFile, error) {
|
|||
|
||||
// modifyJSON finds an auth.json file, calls editor on the contents, and
|
||||
// writes it back if editor returns true.
|
||||
// Returns a human-redable description of the file, to be returned by SetCredentials.
|
||||
func modifyJSON(sys *types.SystemContext, editor func(auths *dockerConfigFile) (bool, error)) (string, error) {
|
||||
// Returns a human-readable description of the file, to be returned by SetCredentials.
|
||||
//
|
||||
// The editor may also return a human-readable description of the updated location; if it is "",
|
||||
// the file itself is used.
|
||||
func modifyJSON(sys *types.SystemContext, editor func(auths *dockerConfigFile) (bool, string, error)) (string, error) {
|
||||
path, legacyFormat, err := getPathToAuth(sys)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@ -593,7 +601,7 @@ func modifyJSON(sys *types.SystemContext, editor func(auths *dockerConfigFile) (
|
|||
return "", fmt.Errorf("reading JSON file %q: %w", path, err)
|
||||
}
|
||||
|
||||
updated, err := editor(&auths)
|
||||
updated, description, err := editor(&auths)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("updating %q: %w", path, err)
|
||||
}
|
||||
|
@ -608,7 +616,10 @@ func modifyJSON(sys *types.SystemContext, editor func(auths *dockerConfigFile) (
|
|||
}
|
||||
}
|
||||
|
||||
return path, nil
|
||||
if description == "" {
|
||||
description = path
|
||||
}
|
||||
return description, nil
|
||||
}
|
||||
|
||||
func getAuthFromCredHelper(credHelper, registry string) (types.DockerAuthConfig, error) {
|
||||
|
@ -636,7 +647,9 @@ func getAuthFromCredHelper(credHelper, registry string) (types.DockerAuthConfig,
|
|||
}
|
||||
}
|
||||
|
||||
func setAuthToCredHelper(credHelper, registry, username, password string) error {
|
||||
// setAuthToCredHelper stores (username, password) for registry in credHelper.
|
||||
// Returns a human-readable description of the destination, to be returned by SetCredentials.
|
||||
func setAuthToCredHelper(credHelper, registry, username, password string) (string, error) {
|
||||
helperName := fmt.Sprintf("docker-credential-%s", credHelper)
|
||||
p := helperclient.NewShellProgramFunc(helperName)
|
||||
creds := &credentials.Credentials{
|
||||
|
@ -644,7 +657,10 @@ func setAuthToCredHelper(credHelper, registry, username, password string) error
|
|||
Username: username,
|
||||
Secret: password,
|
||||
}
|
||||
return helperclient.Store(p, creds)
|
||||
if err := helperclient.Store(p, creds); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("credential helper: %s", credHelper), nil
|
||||
}
|
||||
|
||||
func deleteAuthFromCredHelper(credHelper, registry string) error {
|
||||
|
|
27
vendor/github.com/containers/image/v5/pkg/sysregistriesv2/system_registries_v2.go
generated
vendored
27
vendor/github.com/containers/image/v5/pkg/sysregistriesv2/system_registries_v2.go
generated
vendored
|
@ -198,6 +198,7 @@ type V1RegistriesConf struct {
|
|||
}
|
||||
|
||||
// Nonempty returns true if config contains at least one configuration entry.
|
||||
// Empty arrays are treated as missing entries.
|
||||
func (config *V1RegistriesConf) Nonempty() bool {
|
||||
copy := *config // A shallow copy
|
||||
if copy.V1TOMLConfig.Search.Registries != nil && len(copy.V1TOMLConfig.Search.Registries) == 0 {
|
||||
|
@ -209,7 +210,15 @@ func (config *V1RegistriesConf) Nonempty() bool {
|
|||
if copy.V1TOMLConfig.Block.Registries != nil && len(copy.V1TOMLConfig.Block.Registries) == 0 {
|
||||
copy.V1TOMLConfig.Block.Registries = nil
|
||||
}
|
||||
return !reflect.DeepEqual(copy, V1RegistriesConf{})
|
||||
return copy.hasSetField()
|
||||
}
|
||||
|
||||
// hasSetField returns true if config contains at least one configuration entry.
|
||||
// This is useful because of a subtlety of the behavior of the TOML decoder, where a missing array field
|
||||
// is not modified while unmarshaling (in our case remains to nil), while an [] is unmarshaled
|
||||
// as a non-nil []string{}.
|
||||
func (config *V1RegistriesConf) hasSetField() bool {
|
||||
return !reflect.DeepEqual(*config, V1RegistriesConf{})
|
||||
}
|
||||
|
||||
// V2RegistriesConf is the sysregistries v2 configuration format.
|
||||
|
@ -257,7 +266,15 @@ func (config *V2RegistriesConf) Nonempty() bool {
|
|||
if !copy.shortNameAliasConf.nonempty() {
|
||||
copy.shortNameAliasConf = shortNameAliasConf{}
|
||||
}
|
||||
return !reflect.DeepEqual(copy, V2RegistriesConf{})
|
||||
return copy.hasSetField()
|
||||
}
|
||||
|
||||
// hasSetField returns true if config contains at least one configuration entry.
|
||||
// This is useful because of a subtlety of the behavior of the TOML decoder, where a missing array field
|
||||
// is not modified while unmarshaling (in our case remains to nil), while an [] is unmarshaled
|
||||
// as a non-nil []string{}.
|
||||
func (config *V2RegistriesConf) hasSetField() bool {
|
||||
return !reflect.DeepEqual(*config, V2RegistriesConf{})
|
||||
}
|
||||
|
||||
// parsedConfig is the result of parsing, and possibly merging, configuration files;
|
||||
|
@ -923,15 +940,15 @@ func loadConfigFile(path string, forceV2 bool) (*parsedConfig, error) {
|
|||
logrus.Debugf("Failed to decode keys %q from %q", keys, path)
|
||||
}
|
||||
|
||||
if combinedTOML.V1RegistriesConf.Nonempty() {
|
||||
if combinedTOML.V1RegistriesConf.hasSetField() {
|
||||
// Enforce the v2 format if requested.
|
||||
if forceV2 {
|
||||
return nil, &InvalidRegistries{s: "registry must be in v2 format but is in v1"}
|
||||
}
|
||||
|
||||
// Convert a v1 config into a v2 config.
|
||||
if combinedTOML.V2RegistriesConf.Nonempty() {
|
||||
return nil, &InvalidRegistries{s: "mixing sysregistry v1/v2 is not supported"}
|
||||
if combinedTOML.V2RegistriesConf.hasSetField() {
|
||||
return nil, &InvalidRegistries{s: fmt.Sprintf("mixing sysregistry v1/v2 is not supported: %#v", combinedTOML)}
|
||||
}
|
||||
converted, err := combinedTOML.V1RegistriesConf.ConvertToV2()
|
||||
if err != nil {
|
||||
|
|
|
@ -2,6 +2,7 @@ package tlsclientconfig
|
|||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
|
@ -10,8 +11,6 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/go-connections/sockets"
|
||||
"github.com/docker/go-connections/tlsconfig"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
|
@ -47,7 +46,7 @@ func SetupCertificates(dir string, tlsc *tls.Config) error {
|
|||
return err
|
||||
}
|
||||
if tlsc.RootCAs == nil {
|
||||
systemPool, err := tlsconfig.SystemCertPool()
|
||||
systemPool, err := x509.SystemCertPool()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get system cert pool: %w", err)
|
||||
}
|
||||
|
@ -103,8 +102,5 @@ func NewTransport() *http.Transport {
|
|||
// TODO(dmcgowan): Call close idle connections when complete and use keep alive
|
||||
DisableKeepAlives: true,
|
||||
}
|
||||
if _, err := sockets.DialerFromEnvironment(direct); err != nil {
|
||||
logrus.Debugf("Can't execute DialerFromEnvironment: %v", err)
|
||||
}
|
||||
return tr
|
||||
}
|
||||
|
|
|
@ -89,14 +89,37 @@ func (s *storageImageSource) Close() error {
|
|||
// The Digest field in BlobInfo is guaranteed to be provided, Size may be -1 and MediaType may be optionally provided.
|
||||
// May update BlobInfoCache, preferably after it knows for certain that a blob truly exists at a specific location.
|
||||
func (s *storageImageSource) GetBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache) (rc io.ReadCloser, n int64, err error) {
|
||||
if info.Digest == image.GzippedEmptyLayerDigest {
|
||||
// We need a valid digest value.
|
||||
digest := info.Digest
|
||||
err = digest.Validate()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if digest == image.GzippedEmptyLayerDigest {
|
||||
return io.NopCloser(bytes.NewReader(image.GzippedEmptyLayer)), int64(len(image.GzippedEmptyLayer)), nil
|
||||
}
|
||||
|
||||
// Check if the blob corresponds to a diff that was used to initialize any layers. Our
|
||||
// callers should try to retrieve layers using their uncompressed digests, so no need to
|
||||
// check if they're using one of the compressed digests, which we can't reproduce anyway.
|
||||
layers, _ := s.imageRef.transport.store.LayersByUncompressedDigest(digest)
|
||||
|
||||
// If it's not a layer, then it must be a data item.
|
||||
if len(layers) == 0 {
|
||||
b, err := s.imageRef.transport.store.ImageBigData(s.image.ID, digest.String())
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
r := bytes.NewReader(b)
|
||||
logrus.Debugf("exporting opaque data as blob %q", digest.String())
|
||||
return io.NopCloser(r), int64(r.Len()), nil
|
||||
}
|
||||
|
||||
// NOTE: the blob is first written to a temporary file and subsequently
|
||||
// closed. The intention is to keep the time we own the storage lock
|
||||
// as short as possible to allow other processes to access the storage.
|
||||
rc, n, _, err = s.getBlobAndLayerID(info)
|
||||
rc, n, _, err = s.getBlobAndLayerID(digest, layers)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
@ -111,7 +134,7 @@ func (s *storageImageSource) GetBlob(ctx context.Context, info types.BlobInfo, c
|
|||
return nil, 0, err
|
||||
}
|
||||
|
||||
if _, err := tmpFile.Seek(0, 0); err != nil {
|
||||
if _, err := tmpFile.Seek(0, io.SeekStart); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
|
@ -124,35 +147,16 @@ func (s *storageImageSource) GetBlob(ctx context.Context, info types.BlobInfo, c
|
|||
}
|
||||
|
||||
// getBlobAndLayer reads the data blob or filesystem layer which matches the digest and size, if given.
|
||||
func (s *storageImageSource) getBlobAndLayerID(info types.BlobInfo) (rc io.ReadCloser, n int64, layerID string, err error) {
|
||||
func (s *storageImageSource) getBlobAndLayerID(digest digest.Digest, layers []storage.Layer) (rc io.ReadCloser, n int64, layerID string, err error) {
|
||||
var layer storage.Layer
|
||||
var diffOptions *storage.DiffOptions
|
||||
// We need a valid digest value.
|
||||
err = info.Digest.Validate()
|
||||
if err != nil {
|
||||
return nil, -1, "", err
|
||||
}
|
||||
// Check if the blob corresponds to a diff that was used to initialize any layers. Our
|
||||
// callers should try to retrieve layers using their uncompressed digests, so no need to
|
||||
// check if they're using one of the compressed digests, which we can't reproduce anyway.
|
||||
layers, _ := s.imageRef.transport.store.LayersByUncompressedDigest(info.Digest)
|
||||
|
||||
// If it's not a layer, then it must be a data item.
|
||||
if len(layers) == 0 {
|
||||
b, err := s.imageRef.transport.store.ImageBigData(s.image.ID, info.Digest.String())
|
||||
if err != nil {
|
||||
return nil, -1, "", err
|
||||
}
|
||||
r := bytes.NewReader(b)
|
||||
logrus.Debugf("exporting opaque data as blob %q", info.Digest.String())
|
||||
return io.NopCloser(r), int64(r.Len()), "", nil
|
||||
}
|
||||
// Step through the list of matching layers. Tests may want to verify that if we have multiple layers
|
||||
// which claim to have the same contents, that we actually do have multiple layers, otherwise we could
|
||||
// just go ahead and use the first one every time.
|
||||
s.getBlobMutex.Lock()
|
||||
i := s.layerPosition[info.Digest]
|
||||
s.layerPosition[info.Digest] = i + 1
|
||||
i := s.layerPosition[digest]
|
||||
s.layerPosition[digest] = i + 1
|
||||
s.getBlobMutex.Unlock()
|
||||
if len(layers) > 0 {
|
||||
layer = layers[i%len(layers)]
|
||||
|
@ -168,7 +172,7 @@ func (s *storageImageSource) getBlobAndLayerID(info types.BlobInfo) (rc io.ReadC
|
|||
} else {
|
||||
n = layer.UncompressedSize
|
||||
}
|
||||
logrus.Debugf("exporting filesystem layer %q without compression for blob %q", layer.ID, info.Digest)
|
||||
logrus.Debugf("exporting filesystem layer %q without compression for blob %q", layer.ID, digest)
|
||||
rc, err = s.imageRef.transport.store.Diff("", layer.ID, diffOptions)
|
||||
if err != nil {
|
||||
return nil, -1, "", err
|
||||
|
|
|
@ -125,6 +125,13 @@ type BlobInfo struct {
|
|||
URLs []string
|
||||
Annotations map[string]string
|
||||
MediaType string
|
||||
|
||||
// NOTE: The following fields contain desired _edits_ to blob infos.
|
||||
// Conceptually then don't belong in the BlobInfo object at all;
|
||||
// the edits should be provided specifically as parameters to the edit implementation.
|
||||
// We can’t remove the fields without breaking compatibility, but don’t
|
||||
// add any more.
|
||||
|
||||
// CompressionOperation is used in Image.UpdateLayerInfos to instruct
|
||||
// whether the original layer's "compressed or not" should be preserved,
|
||||
// possibly while changing the compression algorithm from one to another,
|
||||
|
@ -144,6 +151,7 @@ type BlobInfo struct {
|
|||
// TODO: To remove together with CompressionOperation in re-design to
|
||||
// remove field out out of BlobInfo.
|
||||
CryptoOperation LayerCrypto
|
||||
// Before adding any fields to this struct, read the NOTE above.
|
||||
}
|
||||
|
||||
// BICTransportScope encapsulates transport-dependent representation of a “scope” where blobs are or are not present.
|
||||
|
|
|
@ -58,6 +58,11 @@ func (c *RefCounter) incdec(path string, infoOp func(minfo *minfo)) int {
|
|||
}
|
||||
infoOp(m)
|
||||
count := m.count
|
||||
if count <= 0 {
|
||||
// If the mounted path has been decremented enough have no references,
|
||||
// then its entry can be removed.
|
||||
delete(c.counts, path)
|
||||
}
|
||||
c.mu.Unlock()
|
||||
return count
|
||||
}
|
||||
|
|
|
@ -1202,6 +1202,9 @@ func (d *Driver) Remove(id string) error {
|
|||
if err := system.EnsureRemoveAll(dir); err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
if d.quotaCtl != nil {
|
||||
d.quotaCtl.ClearQuota(dir)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -211,6 +211,12 @@ func (q *Control) SetQuota(targetPath string, quota Quota) error {
|
|||
return q.setProjectQuota(projectID, quota)
|
||||
}
|
||||
|
||||
// ClearQuota removes the map entry in the quotas map for targetPath.
|
||||
// It does so to prevent the map leaking entries as directories are deleted.
|
||||
func (q *Control) ClearQuota(targetPath string) {
|
||||
delete(q.quotas, targetPath)
|
||||
}
|
||||
|
||||
// setProjectQuota - set the quota for project id on xfs block device
|
||||
func (q *Control) setProjectQuota(projectID uint32, quota Quota) error {
|
||||
var d C.fs_disk_quota_t
|
||||
|
|
|
@ -57,12 +57,12 @@ func Init(base string, opt graphdriver.Options) (graphdriver.Driver, error) {
|
|||
return nil, fmt.Errorf("the 'zfs' command is not available: %w", graphdriver.ErrPrerequisites)
|
||||
}
|
||||
|
||||
file, err := os.OpenFile("/dev/zfs", os.O_RDWR, 0600)
|
||||
file, err := unix.Open("/dev/zfs", unix.O_RDWR, 0600)
|
||||
if err != nil {
|
||||
logger.Debugf("cannot open /dev/zfs: %v", err)
|
||||
return nil, fmt.Errorf("could not open /dev/zfs: %v: %w", err, graphdriver.ErrPrerequisites)
|
||||
}
|
||||
defer file.Close()
|
||||
defer unix.Close(file)
|
||||
|
||||
options, err := parseOptions(opt.DriverOptions)
|
||||
if err != nil {
|
||||
|
|
|
@ -299,6 +299,9 @@ type rwLayerStore interface {
|
|||
|
||||
// Clean up unreferenced layers
|
||||
GarbageCollect() error
|
||||
|
||||
// supportsShifting() returns true if the driver.Driver.SupportsShifting().
|
||||
supportsShifting() bool
|
||||
}
|
||||
|
||||
type layerStore struct {
|
||||
|
@ -806,15 +809,14 @@ func (r *layerStore) saveLayers(saveLocations layerLocations) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var opts *ioutils.AtomicFileWriterOptions
|
||||
opts := ioutils.AtomicFileWriterOptions{}
|
||||
if location == volatileLayerLocation {
|
||||
opts = &ioutils.AtomicFileWriterOptions{
|
||||
NoSync: true,
|
||||
opts.NoSync = true
|
||||
}
|
||||
}
|
||||
if err := ioutils.AtomicWriteFileWithOpts(rpath, jldata, 0600, opts); err != nil {
|
||||
if err := ioutils.AtomicWriteFileWithOpts(rpath, jldata, 0600, &opts); err != nil {
|
||||
return err
|
||||
}
|
||||
r.layerspathsModified[locationIndex] = opts.ModTime
|
||||
}
|
||||
lw, err := r.lockfile.RecordWrite()
|
||||
if err != nil {
|
||||
|
@ -2234,6 +2236,10 @@ func (r *layerStore) LayersByUncompressedDigest(d digest.Digest) ([]Layer, error
|
|||
return r.layersByDigestMap(r.byuncompressedsum, d)
|
||||
}
|
||||
|
||||
func (r *layerStore) supportsShifting() bool {
|
||||
return r.driver.SupportsShifting()
|
||||
}
|
||||
|
||||
func closeAll(closes ...func() error) (rErr error) {
|
||||
for _, f := range closes {
|
||||
if err := f(); err != nil {
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AtomicFileWriterOptions specifies options for creating the atomic file writer.
|
||||
|
@ -13,6 +14,9 @@ type AtomicFileWriterOptions struct {
|
|||
// storage after it has been written and before it is moved to
|
||||
// the specified path.
|
||||
NoSync bool
|
||||
// On successful return from Close() this is set to the mtime of the
|
||||
// newly written file.
|
||||
ModTime time.Time
|
||||
}
|
||||
|
||||
var defaultWriterOptions = AtomicFileWriterOptions{}
|
||||
|
@ -74,6 +78,11 @@ func AtomicWriteFileWithOpts(filename string, data []byte, perm os.FileMode, opt
|
|||
if err1 := f.Close(); err == nil {
|
||||
err = err1
|
||||
}
|
||||
|
||||
if opts != nil {
|
||||
opts.ModTime = f.modTime
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -87,6 +96,7 @@ type atomicFileWriter struct {
|
|||
writeErr error
|
||||
perm os.FileMode
|
||||
noSync bool
|
||||
modTime time.Time
|
||||
}
|
||||
|
||||
func (w *atomicFileWriter) Write(dt []byte) (int, error) {
|
||||
|
@ -109,9 +119,25 @@ func (w *atomicFileWriter) Close() (retErr error) {
|
|||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// fstat before closing the fd
|
||||
info, statErr := w.f.Stat()
|
||||
if statErr == nil {
|
||||
w.modTime = info.ModTime()
|
||||
}
|
||||
// We delay error reporting until after the real call to close()
|
||||
// to match the traditional linux close() behaviour that an fd
|
||||
// is invalid (closed) even if close returns failure. While
|
||||
// weird, this allows a well defined way to not leak open fds.
|
||||
|
||||
if err := w.f.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if statErr != nil {
|
||||
return statErr
|
||||
}
|
||||
|
||||
if err := os.Chmod(w.f.Name(), w.perm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -264,7 +264,7 @@ func (s *store) getAutoUserNS(options *types.AutoUserNsOptions, image *Image, rl
|
|||
}
|
||||
}
|
||||
if s.autoNsMaxSize > 0 && size > s.autoNsMaxSize {
|
||||
return nil, nil, fmt.Errorf("the container needs a user namespace with size %q that is bigger than the maximum value allowed with userns=auto %q", size, s.autoNsMaxSize)
|
||||
return nil, nil, fmt.Errorf("the container needs a user namespace with size %v that is bigger than the maximum value allowed with userns=auto %v", size, s.autoNsMaxSize)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,11 @@ This package provides various compression algorithms.
|
|||
|
||||
# changelog
|
||||
|
||||
* Oct 26, 2022 (v1.15.12)
|
||||
|
||||
* zstd: Tweak decoder allocs. https://github.com/klauspost/compress/pull/680
|
||||
* gzhttp: Always delete `HeaderNoCompression` https://github.com/klauspost/compress/pull/683
|
||||
|
||||
* Sept 26, 2022 (v1.15.11)
|
||||
|
||||
* flate: Improve level 1-3 compression https://github.com/klauspost/compress/pull/678
|
||||
|
|
|
@ -365,30 +365,30 @@ func (s *Scratch) countSimple(in []byte) (max int, reuse bool) {
|
|||
m := uint32(0)
|
||||
if len(s.prevTable) > 0 {
|
||||
for i, v := range s.count[:] {
|
||||
if v == 0 {
|
||||
continue
|
||||
}
|
||||
if v > m {
|
||||
m = v
|
||||
}
|
||||
if v > 0 {
|
||||
s.symbolLen = uint16(i) + 1
|
||||
if i >= len(s.prevTable) {
|
||||
reuse = false
|
||||
} else {
|
||||
if s.prevTable[i].nBits == 0 {
|
||||
} else if s.prevTable[i].nBits == 0 {
|
||||
reuse = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return int(m), reuse
|
||||
}
|
||||
for i, v := range s.count[:] {
|
||||
if v == 0 {
|
||||
continue
|
||||
}
|
||||
if v > m {
|
||||
m = v
|
||||
}
|
||||
if v > 0 {
|
||||
s.symbolLen = uint16(i) + 1
|
||||
}
|
||||
}
|
||||
return int(m), false
|
||||
}
|
||||
|
||||
|
|
|
@ -82,8 +82,9 @@ type blockDec struct {
|
|||
|
||||
err error
|
||||
|
||||
// Check against this crc
|
||||
checkCRC []byte
|
||||
// Check against this crc, if hasCRC is true.
|
||||
checkCRC uint32
|
||||
hasCRC bool
|
||||
|
||||
// Frame to use for singlethreaded decoding.
|
||||
// Should not be used by the decoder itself since parent may be another frame.
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
package zstd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
|
@ -102,8 +101,8 @@ func (h *Header) Decode(in []byte) error {
|
|||
}
|
||||
h.HeaderSize += 4
|
||||
b, in := in[:4], in[4:]
|
||||
if !bytes.Equal(b, frameMagic) {
|
||||
if !bytes.Equal(b[1:4], skippableFrameMagic) || b[0]&0xf0 != 0x50 {
|
||||
if string(b) != frameMagic {
|
||||
if string(b[1:4]) != skippableFrameMagic || b[0]&0xf0 != 0x50 {
|
||||
return ErrMagicMismatch
|
||||
}
|
||||
if len(in) < 4 {
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
package zstd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
|
@ -459,7 +458,11 @@ func (d *Decoder) nextBlock(blocking bool) (ok bool) {
|
|||
println("got", len(d.current.b), "bytes, error:", d.current.err, "data crc:", tmp)
|
||||
}
|
||||
|
||||
if !d.o.ignoreChecksum && len(next.b) > 0 {
|
||||
if d.o.ignoreChecksum {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(next.b) > 0 {
|
||||
n, err := d.current.crc.Write(next.b)
|
||||
if err == nil {
|
||||
if n != len(next.b) {
|
||||
|
@ -467,18 +470,16 @@ func (d *Decoder) nextBlock(blocking bool) (ok bool) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if next.err == nil && next.d != nil && len(next.d.checkCRC) != 0 {
|
||||
got := d.current.crc.Sum64()
|
||||
var tmp [4]byte
|
||||
binary.LittleEndian.PutUint32(tmp[:], uint32(got))
|
||||
if !d.o.ignoreChecksum && !bytes.Equal(tmp[:], next.d.checkCRC) {
|
||||
if next.err == nil && next.d != nil && next.d.hasCRC {
|
||||
got := uint32(d.current.crc.Sum64())
|
||||
if got != next.d.checkCRC {
|
||||
if debugDecoder {
|
||||
println("CRC Check Failed:", tmp[:], " (got) !=", next.d.checkCRC, "(on stream)")
|
||||
printf("CRC Check Failed: %08x (got) != %08x (on stream)\n", got, next.d.checkCRC)
|
||||
}
|
||||
d.current.err = ErrCRCMismatch
|
||||
} else {
|
||||
if debugDecoder {
|
||||
println("CRC ok", tmp[:])
|
||||
printf("CRC ok %08x\n", got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -918,18 +919,22 @@ decodeStream:
|
|||
println("next block returned error:", err)
|
||||
}
|
||||
dec.err = err
|
||||
dec.checkCRC = nil
|
||||
dec.hasCRC = false
|
||||
if dec.Last && frame.HasCheckSum && err == nil {
|
||||
crc, err := frame.rawInput.readSmall(4)
|
||||
if err != nil {
|
||||
if len(crc) < 4 {
|
||||
if err == nil {
|
||||
err = io.ErrUnexpectedEOF
|
||||
|
||||
}
|
||||
println("CRC missing?", err)
|
||||
dec.err = err
|
||||
}
|
||||
var tmp [4]byte
|
||||
copy(tmp[:], crc)
|
||||
dec.checkCRC = tmp[:]
|
||||
} else {
|
||||
dec.checkCRC = binary.LittleEndian.Uint32(crc)
|
||||
dec.hasCRC = true
|
||||
if debugDecoder {
|
||||
println("found crc to check:", dec.checkCRC)
|
||||
printf("found crc to check: %08x\n", dec.checkCRC)
|
||||
}
|
||||
}
|
||||
}
|
||||
err = dec.err
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package zstd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
@ -20,7 +19,7 @@ type dict struct {
|
|||
content []byte
|
||||
}
|
||||
|
||||
var dictMagic = [4]byte{0x37, 0xa4, 0x30, 0xec}
|
||||
const dictMagic = "\x37\xa4\x30\xec"
|
||||
|
||||
// ID returns the dictionary id or 0 if d is nil.
|
||||
func (d *dict) ID() uint32 {
|
||||
|
@ -50,7 +49,7 @@ func loadDict(b []byte) (*dict, error) {
|
|||
ofDec: sequenceDec{fse: &fseDecoder{}},
|
||||
mlDec: sequenceDec{fse: &fseDecoder{}},
|
||||
}
|
||||
if !bytes.Equal(b[:4], dictMagic[:]) {
|
||||
if string(b[:4]) != dictMagic {
|
||||
return nil, ErrMagicMismatch
|
||||
}
|
||||
d.id = binary.LittleEndian.Uint32(b[4:8])
|
||||
|
|
|
@ -16,6 +16,7 @@ type fastBase struct {
|
|||
cur int32
|
||||
// maximum offset. Should be at least 2x block size.
|
||||
maxMatchOff int32
|
||||
bufferReset int32
|
||||
hist []byte
|
||||
crc *xxhash.Digest
|
||||
tmp [8]byte
|
||||
|
@ -56,8 +57,8 @@ func (e *fastBase) Block() *blockEnc {
|
|||
}
|
||||
|
||||
func (e *fastBase) addBlock(src []byte) int32 {
|
||||
if debugAsserts && e.cur > bufferReset {
|
||||
panic(fmt.Sprintf("ecur (%d) > buffer reset (%d)", e.cur, bufferReset))
|
||||
if debugAsserts && e.cur > e.bufferReset {
|
||||
panic(fmt.Sprintf("ecur (%d) > buffer reset (%d)", e.cur, e.bufferReset))
|
||||
}
|
||||
// check if we have space already
|
||||
if len(e.hist)+len(src) > cap(e.hist) {
|
||||
|
@ -126,24 +127,7 @@ func (e *fastBase) matchlen(s, t int32, src []byte) int32 {
|
|||
panic(fmt.Sprintf("len(src)-s (%d) > maxCompressedBlockSize (%d)", len(src)-int(s), maxCompressedBlockSize))
|
||||
}
|
||||
}
|
||||
a := src[s:]
|
||||
b := src[t:]
|
||||
b = b[:len(a)]
|
||||
end := int32((len(a) >> 3) << 3)
|
||||
for i := int32(0); i < end; i += 8 {
|
||||
if diff := load6432(a, i) ^ load6432(b, i); diff != 0 {
|
||||
return i + int32(bits.TrailingZeros64(diff)>>3)
|
||||
}
|
||||
}
|
||||
|
||||
a = a[end:]
|
||||
b = b[end:]
|
||||
for i := range a {
|
||||
if a[i] != b[i] {
|
||||
return int32(i) + end
|
||||
}
|
||||
}
|
||||
return int32(len(a)) + end
|
||||
return int32(matchLen(src[s:], src[t:]))
|
||||
}
|
||||
|
||||
// Reset the encoding table.
|
||||
|
@ -171,7 +155,7 @@ func (e *fastBase) resetBase(d *dict, singleBlock bool) {
|
|||
|
||||
// We offset current position so everything will be out of reach.
|
||||
// If above reset line, history will be purged.
|
||||
if e.cur < bufferReset {
|
||||
if e.cur < e.bufferReset {
|
||||
e.cur += e.maxMatchOff + int32(len(e.hist))
|
||||
}
|
||||
e.hist = e.hist[:0]
|
||||
|
|
|
@ -85,14 +85,10 @@ func (e *bestFastEncoder) Encode(blk *blockEnc, src []byte) {
|
|||
)
|
||||
|
||||
// Protect against e.cur wraparound.
|
||||
for e.cur >= bufferReset {
|
||||
for e.cur >= e.bufferReset-int32(len(e.hist)) {
|
||||
if len(e.hist) == 0 {
|
||||
for i := range e.table[:] {
|
||||
e.table[i] = prevEntry{}
|
||||
}
|
||||
for i := range e.longTable[:] {
|
||||
e.longTable[i] = prevEntry{}
|
||||
}
|
||||
e.table = [bestShortTableSize]prevEntry{}
|
||||
e.longTable = [bestLongTableSize]prevEntry{}
|
||||
e.cur = e.maxMatchOff
|
||||
break
|
||||
}
|
||||
|
@ -193,8 +189,8 @@ encodeLoop:
|
|||
panic("offset0 was 0")
|
||||
}
|
||||
|
||||
bestOf := func(a, b match) match {
|
||||
if a.est+(a.s-b.s)*bitsPerByte>>10 < b.est+(b.s-a.s)*bitsPerByte>>10 {
|
||||
bestOf := func(a, b *match) *match {
|
||||
if a.est-b.est+(a.s-b.s)*bitsPerByte>>10 < 0 {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
|
@ -220,22 +216,26 @@ encodeLoop:
|
|||
return m
|
||||
}
|
||||
|
||||
best := bestOf(matchAt(candidateL.offset-e.cur, s, uint32(cv), -1), matchAt(candidateL.prev-e.cur, s, uint32(cv), -1))
|
||||
best = bestOf(best, matchAt(candidateS.offset-e.cur, s, uint32(cv), -1))
|
||||
best = bestOf(best, matchAt(candidateS.prev-e.cur, s, uint32(cv), -1))
|
||||
m1 := matchAt(candidateL.offset-e.cur, s, uint32(cv), -1)
|
||||
m2 := matchAt(candidateL.prev-e.cur, s, uint32(cv), -1)
|
||||
m3 := matchAt(candidateS.offset-e.cur, s, uint32(cv), -1)
|
||||
m4 := matchAt(candidateS.prev-e.cur, s, uint32(cv), -1)
|
||||
best := bestOf(bestOf(&m1, &m2), bestOf(&m3, &m4))
|
||||
|
||||
if canRepeat && best.length < goodEnough {
|
||||
cv32 := uint32(cv >> 8)
|
||||
spp := s + 1
|
||||
best = bestOf(best, matchAt(spp-offset1, spp, cv32, 1))
|
||||
best = bestOf(best, matchAt(spp-offset2, spp, cv32, 2))
|
||||
best = bestOf(best, matchAt(spp-offset3, spp, cv32, 3))
|
||||
m1 := matchAt(spp-offset1, spp, cv32, 1)
|
||||
m2 := matchAt(spp-offset2, spp, cv32, 2)
|
||||
m3 := matchAt(spp-offset3, spp, cv32, 3)
|
||||
best = bestOf(bestOf(best, &m1), bestOf(&m2, &m3))
|
||||
if best.length > 0 {
|
||||
cv32 = uint32(cv >> 24)
|
||||
spp += 2
|
||||
best = bestOf(best, matchAt(spp-offset1, spp, cv32, 1))
|
||||
best = bestOf(best, matchAt(spp-offset2, spp, cv32, 2))
|
||||
best = bestOf(best, matchAt(spp-offset3, spp, cv32, 3))
|
||||
m1 := matchAt(spp-offset1, spp, cv32, 1)
|
||||
m2 := matchAt(spp-offset2, spp, cv32, 2)
|
||||
m3 := matchAt(spp-offset3, spp, cv32, 3)
|
||||
best = bestOf(bestOf(best, &m1), bestOf(&m2, &m3))
|
||||
}
|
||||
}
|
||||
// Load next and check...
|
||||
|
@ -262,26 +262,33 @@ encodeLoop:
|
|||
candidateL2 := e.longTable[hashLen(cv2, bestLongTableBits, bestLongLen)]
|
||||
|
||||
// Short at s+1
|
||||
best = bestOf(best, matchAt(candidateS.offset-e.cur, s, uint32(cv), -1))
|
||||
m1 := matchAt(candidateS.offset-e.cur, s, uint32(cv), -1)
|
||||
// Long at s+1, s+2
|
||||
best = bestOf(best, matchAt(candidateL.offset-e.cur, s, uint32(cv), -1))
|
||||
best = bestOf(best, matchAt(candidateL.prev-e.cur, s, uint32(cv), -1))
|
||||
best = bestOf(best, matchAt(candidateL2.offset-e.cur, s+1, uint32(cv2), -1))
|
||||
best = bestOf(best, matchAt(candidateL2.prev-e.cur, s+1, uint32(cv2), -1))
|
||||
m2 := matchAt(candidateL.offset-e.cur, s, uint32(cv), -1)
|
||||
m3 := matchAt(candidateL.prev-e.cur, s, uint32(cv), -1)
|
||||
m4 := matchAt(candidateL2.offset-e.cur, s+1, uint32(cv2), -1)
|
||||
m5 := matchAt(candidateL2.prev-e.cur, s+1, uint32(cv2), -1)
|
||||
best = bestOf(bestOf(bestOf(best, &m1), &m2), bestOf(bestOf(&m3, &m4), &m5))
|
||||
if false {
|
||||
// Short at s+3.
|
||||
// Too often worse...
|
||||
best = bestOf(best, matchAt(e.table[hashLen(cv2>>8, bestShortTableBits, bestShortLen)].offset-e.cur, s+2, uint32(cv2>>8), -1))
|
||||
m := matchAt(e.table[hashLen(cv2>>8, bestShortTableBits, bestShortLen)].offset-e.cur, s+2, uint32(cv2>>8), -1)
|
||||
best = bestOf(best, &m)
|
||||
}
|
||||
// See if we can find a better match by checking where the current best ends.
|
||||
// Use that offset to see if we can find a better full match.
|
||||
if sAt := best.s + best.length; sAt < sLimit {
|
||||
nextHashL := hashLen(load6432(src, sAt), bestLongTableBits, bestLongLen)
|
||||
candidateEnd := e.longTable[nextHashL]
|
||||
if pos := candidateEnd.offset - e.cur - best.length; pos >= 0 {
|
||||
bestEnd := bestOf(best, matchAt(pos, best.s, load3232(src, best.s), -1))
|
||||
if pos := candidateEnd.prev - e.cur - best.length; pos >= 0 {
|
||||
bestEnd = bestOf(bestEnd, matchAt(pos, best.s, load3232(src, best.s), -1))
|
||||
// Start check at a fixed offset to allow for a few mismatches.
|
||||
// For this compression level 2 yields the best results.
|
||||
const skipBeginning = 2
|
||||
if pos := candidateEnd.offset - e.cur - best.length + skipBeginning; pos >= 0 {
|
||||
m := matchAt(pos, best.s+skipBeginning, load3232(src, best.s+skipBeginning), -1)
|
||||
bestEnd := bestOf(best, &m)
|
||||
if pos := candidateEnd.prev - e.cur - best.length + skipBeginning; pos >= 0 {
|
||||
m := matchAt(pos, best.s+skipBeginning, load3232(src, best.s+skipBeginning), -1)
|
||||
bestEnd = bestOf(bestEnd, &m)
|
||||
}
|
||||
best = bestEnd
|
||||
}
|
||||
|
|
|
@ -62,14 +62,10 @@ func (e *betterFastEncoder) Encode(blk *blockEnc, src []byte) {
|
|||
)
|
||||
|
||||
// Protect against e.cur wraparound.
|
||||
for e.cur >= bufferReset {
|
||||
for e.cur >= e.bufferReset-int32(len(e.hist)) {
|
||||
if len(e.hist) == 0 {
|
||||
for i := range e.table[:] {
|
||||
e.table[i] = tableEntry{}
|
||||
}
|
||||
for i := range e.longTable[:] {
|
||||
e.longTable[i] = prevEntry{}
|
||||
}
|
||||
e.table = [betterShortTableSize]tableEntry{}
|
||||
e.longTable = [betterLongTableSize]prevEntry{}
|
||||
e.cur = e.maxMatchOff
|
||||
break
|
||||
}
|
||||
|
@ -587,7 +583,7 @@ func (e *betterFastEncoderDict) Encode(blk *blockEnc, src []byte) {
|
|||
)
|
||||
|
||||
// Protect against e.cur wraparound.
|
||||
for e.cur >= bufferReset {
|
||||
for e.cur >= e.bufferReset-int32(len(e.hist)) {
|
||||
if len(e.hist) == 0 {
|
||||
for i := range e.table[:] {
|
||||
e.table[i] = tableEntry{}
|
||||
|
|
|
@ -44,14 +44,10 @@ func (e *doubleFastEncoder) Encode(blk *blockEnc, src []byte) {
|
|||
)
|
||||
|
||||
// Protect against e.cur wraparound.
|
||||
for e.cur >= bufferReset {
|
||||
for e.cur >= e.bufferReset-int32(len(e.hist)) {
|
||||
if len(e.hist) == 0 {
|
||||
for i := range e.table[:] {
|
||||
e.table[i] = tableEntry{}
|
||||
}
|
||||
for i := range e.longTable[:] {
|
||||
e.longTable[i] = tableEntry{}
|
||||
}
|
||||
e.table = [dFastShortTableSize]tableEntry{}
|
||||
e.longTable = [dFastLongTableSize]tableEntry{}
|
||||
e.cur = e.maxMatchOff
|
||||
break
|
||||
}
|
||||
|
@ -388,7 +384,7 @@ func (e *doubleFastEncoder) EncodeNoHist(blk *blockEnc, src []byte) {
|
|||
)
|
||||
|
||||
// Protect against e.cur wraparound.
|
||||
if e.cur >= bufferReset {
|
||||
if e.cur >= e.bufferReset {
|
||||
for i := range e.table[:] {
|
||||
e.table[i] = tableEntry{}
|
||||
}
|
||||
|
@ -685,7 +681,7 @@ encodeLoop:
|
|||
}
|
||||
|
||||
// We do not store history, so we must offset e.cur to avoid false matches for next user.
|
||||
if e.cur < bufferReset {
|
||||
if e.cur < e.bufferReset {
|
||||
e.cur += int32(len(src))
|
||||
}
|
||||
}
|
||||
|
@ -700,7 +696,7 @@ func (e *doubleFastEncoderDict) Encode(blk *blockEnc, src []byte) {
|
|||
)
|
||||
|
||||
// Protect against e.cur wraparound.
|
||||
for e.cur >= bufferReset {
|
||||
for e.cur >= e.bufferReset-int32(len(e.hist)) {
|
||||
if len(e.hist) == 0 {
|
||||
for i := range e.table[:] {
|
||||
e.table[i] = tableEntry{}
|
||||
|
|
|
@ -43,7 +43,7 @@ func (e *fastEncoder) Encode(blk *blockEnc, src []byte) {
|
|||
)
|
||||
|
||||
// Protect against e.cur wraparound.
|
||||
for e.cur >= bufferReset {
|
||||
for e.cur >= e.bufferReset-int32(len(e.hist)) {
|
||||
if len(e.hist) == 0 {
|
||||
for i := range e.table[:] {
|
||||
e.table[i] = tableEntry{}
|
||||
|
@ -310,7 +310,7 @@ func (e *fastEncoder) EncodeNoHist(blk *blockEnc, src []byte) {
|
|||
}
|
||||
|
||||
// Protect against e.cur wraparound.
|
||||
if e.cur >= bufferReset {
|
||||
if e.cur >= e.bufferReset {
|
||||
for i := range e.table[:] {
|
||||
e.table[i] = tableEntry{}
|
||||
}
|
||||
|
@ -538,7 +538,7 @@ encodeLoop:
|
|||
println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
|
||||
}
|
||||
// We do not store history, so we must offset e.cur to avoid false matches for next user.
|
||||
if e.cur < bufferReset {
|
||||
if e.cur < e.bufferReset {
|
||||
e.cur += int32(len(src))
|
||||
}
|
||||
}
|
||||
|
@ -555,11 +555,9 @@ func (e *fastEncoderDict) Encode(blk *blockEnc, src []byte) {
|
|||
return
|
||||
}
|
||||
// Protect against e.cur wraparound.
|
||||
for e.cur >= bufferReset {
|
||||
for e.cur >= e.bufferReset-int32(len(e.hist)) {
|
||||
if len(e.hist) == 0 {
|
||||
for i := range e.table[:] {
|
||||
e.table[i] = tableEntry{}
|
||||
}
|
||||
e.table = [tableSize]tableEntry{}
|
||||
e.cur = e.maxMatchOff
|
||||
break
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"crypto/rand"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
rdebug "runtime/debug"
|
||||
"sync"
|
||||
|
||||
|
@ -639,3 +640,37 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
|
|||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// MaxEncodedSize returns the expected maximum
|
||||
// size of an encoded block or stream.
|
||||
func (e *Encoder) MaxEncodedSize(size int) int {
|
||||
frameHeader := 4 + 2 // magic + frame header & window descriptor
|
||||
if e.o.dict != nil {
|
||||
frameHeader += 4
|
||||
}
|
||||
// Frame content size:
|
||||
if size < 256 {
|
||||
frameHeader++
|
||||
} else if size < 65536+256 {
|
||||
frameHeader += 2
|
||||
} else if size < math.MaxInt32 {
|
||||
frameHeader += 4
|
||||
} else {
|
||||
frameHeader += 8
|
||||
}
|
||||
// Final crc
|
||||
if e.o.crc {
|
||||
frameHeader += 4
|
||||
}
|
||||
|
||||
// Max overhead is 3 bytes/block.
|
||||
// There cannot be 0 blocks.
|
||||
blocks := (size + e.o.blockSize) / e.o.blockSize
|
||||
|
||||
// Combine, add padding.
|
||||
maxSz := frameHeader + 3*blocks + size
|
||||
if e.o.pad > 1 {
|
||||
maxSz += calcSkippableFrame(int64(maxSz), int64(e.o.pad))
|
||||
}
|
||||
return maxSz
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package zstd
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
@ -47,22 +48,22 @@ func (o encoderOptions) encoder() encoder {
|
|||
switch o.level {
|
||||
case SpeedFastest:
|
||||
if o.dict != nil {
|
||||
return &fastEncoderDict{fastEncoder: fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), lowMem: o.lowMem}}}
|
||||
return &fastEncoderDict{fastEncoder: fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}}
|
||||
}
|
||||
return &fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), lowMem: o.lowMem}}
|
||||
return &fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}
|
||||
|
||||
case SpeedDefault:
|
||||
if o.dict != nil {
|
||||
return &doubleFastEncoderDict{fastEncoderDict: fastEncoderDict{fastEncoder: fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), lowMem: o.lowMem}}}}
|
||||
return &doubleFastEncoderDict{fastEncoderDict: fastEncoderDict{fastEncoder: fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}}}
|
||||
}
|
||||
return &doubleFastEncoder{fastEncoder: fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), lowMem: o.lowMem}}}
|
||||
return &doubleFastEncoder{fastEncoder: fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}}
|
||||
case SpeedBetterCompression:
|
||||
if o.dict != nil {
|
||||
return &betterFastEncoderDict{betterFastEncoder: betterFastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), lowMem: o.lowMem}}}
|
||||
return &betterFastEncoderDict{betterFastEncoder: betterFastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}}
|
||||
}
|
||||
return &betterFastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), lowMem: o.lowMem}}
|
||||
return &betterFastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}
|
||||
case SpeedBestCompression:
|
||||
return &bestFastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), lowMem: o.lowMem}}
|
||||
return &bestFastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}
|
||||
}
|
||||
panic("unknown compression level")
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
package zstd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
|
@ -43,9 +43,9 @@ const (
|
|||
MaxWindowSize = 1 << 29
|
||||
)
|
||||
|
||||
var (
|
||||
frameMagic = []byte{0x28, 0xb5, 0x2f, 0xfd}
|
||||
skippableFrameMagic = []byte{0x2a, 0x4d, 0x18}
|
||||
const (
|
||||
frameMagic = "\x28\xb5\x2f\xfd"
|
||||
skippableFrameMagic = "\x2a\x4d\x18"
|
||||
)
|
||||
|
||||
func newFrameDec(o decoderOptions) *frameDec {
|
||||
|
@ -89,9 +89,9 @@ func (d *frameDec) reset(br byteBuffer) error {
|
|||
copy(signature[1:], b)
|
||||
}
|
||||
|
||||
if !bytes.Equal(signature[1:4], skippableFrameMagic) || signature[0]&0xf0 != 0x50 {
|
||||
if string(signature[1:4]) != skippableFrameMagic || signature[0]&0xf0 != 0x50 {
|
||||
if debugDecoder {
|
||||
println("Not skippable", hex.EncodeToString(signature[:]), hex.EncodeToString(skippableFrameMagic))
|
||||
println("Not skippable", hex.EncodeToString(signature[:]), hex.EncodeToString([]byte(skippableFrameMagic)))
|
||||
}
|
||||
// Break if not skippable frame.
|
||||
break
|
||||
|
@ -114,9 +114,9 @@ func (d *frameDec) reset(br byteBuffer) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
if !bytes.Equal(signature[:], frameMagic) {
|
||||
if string(signature[:]) != frameMagic {
|
||||
if debugDecoder {
|
||||
println("Got magic numbers: ", signature, "want:", frameMagic)
|
||||
println("Got magic numbers: ", signature, "want:", []byte(frameMagic))
|
||||
}
|
||||
return ErrMagicMismatch
|
||||
}
|
||||
|
@ -305,7 +305,7 @@ func (d *frameDec) checkCRC() error {
|
|||
}
|
||||
|
||||
// We can overwrite upper tmp now
|
||||
want, err := d.rawInput.readSmall(4)
|
||||
buf, err := d.rawInput.readSmall(4)
|
||||
if err != nil {
|
||||
println("CRC missing?", err)
|
||||
return err
|
||||
|
@ -315,22 +315,17 @@ func (d *frameDec) checkCRC() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
var tmp [4]byte
|
||||
got := d.crc.Sum64()
|
||||
// Flip to match file order.
|
||||
tmp[0] = byte(got >> 0)
|
||||
tmp[1] = byte(got >> 8)
|
||||
tmp[2] = byte(got >> 16)
|
||||
tmp[3] = byte(got >> 24)
|
||||
want := binary.LittleEndian.Uint32(buf[:4])
|
||||
got := uint32(d.crc.Sum64())
|
||||
|
||||
if !bytes.Equal(tmp[:], want) {
|
||||
if got != want {
|
||||
if debugDecoder {
|
||||
println("CRC Check Failed:", tmp[:], "!=", want)
|
||||
printf("CRC check failed: got %08x, want %08x\n", got, want)
|
||||
}
|
||||
return ErrCRCMismatch
|
||||
}
|
||||
if debugDecoder {
|
||||
println("CRC ok", tmp[:])
|
||||
printf("CRC ok %08x\n", got)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -2,12 +2,7 @@
|
|||
|
||||
VENDORED: Go to [github.com/cespare/xxhash](https://github.com/cespare/xxhash) for original package.
|
||||
|
||||
|
||||
[](https://godoc.org/github.com/cespare/xxhash)
|
||||
[](https://travis-ci.org/cespare/xxhash)
|
||||
|
||||
xxhash is a Go implementation of the 64-bit
|
||||
[xxHash](http://cyan4973.github.io/xxHash/) algorithm, XXH64. This is a
|
||||
xxhash is a Go implementation of the 64-bit [xxHash] algorithm, XXH64. This is a
|
||||
high-quality hashing algorithm that is much faster than anything in the Go
|
||||
standard library.
|
||||
|
||||
|
@ -28,8 +23,23 @@ func (*Digest) WriteString(string) (int, error)
|
|||
func (*Digest) Sum64() uint64
|
||||
```
|
||||
|
||||
This implementation provides a fast pure-Go implementation and an even faster
|
||||
assembly implementation for amd64.
|
||||
The package is written with optimized pure Go and also contains even faster
|
||||
assembly implementations for amd64 and arm64. If desired, the `purego` build tag
|
||||
opts into using the Go code even on those architectures.
|
||||
|
||||
[xxHash]: http://cyan4973.github.io/xxHash/
|
||||
|
||||
## Compatibility
|
||||
|
||||
This package is in a module and the latest code is in version 2 of the module.
|
||||
You need a version of Go with at least "minimal module compatibility" to use
|
||||
github.com/cespare/xxhash/v2:
|
||||
|
||||
* 1.9.7+ for Go 1.9
|
||||
* 1.10.3+ for Go 1.10
|
||||
* Go 1.11 or later
|
||||
|
||||
I recommend using the latest release of Go.
|
||||
|
||||
## Benchmarks
|
||||
|
||||
|
@ -37,22 +47,25 @@ Here are some quick benchmarks comparing the pure-Go and assembly
|
|||
implementations of Sum64.
|
||||
|
||||
| input size | purego | asm |
|
||||
| --- | --- | --- |
|
||||
| 5 B | 979.66 MB/s | 1291.17 MB/s |
|
||||
| 100 B | 7475.26 MB/s | 7973.40 MB/s |
|
||||
| 4 KB | 17573.46 MB/s | 17602.65 MB/s |
|
||||
| 10 MB | 17131.46 MB/s | 17142.16 MB/s |
|
||||
| ---------- | --------- | --------- |
|
||||
| 4 B | 1.3 GB/s | 1.2 GB/s |
|
||||
| 16 B | 2.9 GB/s | 3.5 GB/s |
|
||||
| 100 B | 6.9 GB/s | 8.1 GB/s |
|
||||
| 4 KB | 11.7 GB/s | 16.7 GB/s |
|
||||
| 10 MB | 12.0 GB/s | 17.3 GB/s |
|
||||
|
||||
These numbers were generated on Ubuntu 18.04 with an Intel i7-8700K CPU using
|
||||
the following commands under Go 1.11.2:
|
||||
These numbers were generated on Ubuntu 20.04 with an Intel Xeon Platinum 8252C
|
||||
CPU using the following commands under Go 1.19.2:
|
||||
|
||||
```
|
||||
$ go test -tags purego -benchtime 10s -bench '/xxhash,direct,bytes'
|
||||
$ go test -benchtime 10s -bench '/xxhash,direct,bytes'
|
||||
benchstat <(go test -tags purego -benchtime 500ms -count 15 -bench 'Sum64$')
|
||||
benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$')
|
||||
```
|
||||
|
||||
## Projects using this package
|
||||
|
||||
- [InfluxDB](https://github.com/influxdata/influxdb)
|
||||
- [Prometheus](https://github.com/prometheus/prometheus)
|
||||
- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics)
|
||||
- [FreeCache](https://github.com/coocood/freecache)
|
||||
- [FastCache](https://github.com/VictoriaMetrics/fastcache)
|
||||
|
|
|
@ -18,19 +18,11 @@ const (
|
|||
prime5 uint64 = 2870177450012600261
|
||||
)
|
||||
|
||||
// NOTE(caleb): I'm using both consts and vars of the primes. Using consts where
|
||||
// possible in the Go code is worth a small (but measurable) performance boost
|
||||
// by avoiding some MOVQs. Vars are needed for the asm and also are useful for
|
||||
// convenience in the Go code in a few places where we need to intentionally
|
||||
// avoid constant arithmetic (e.g., v1 := prime1 + prime2 fails because the
|
||||
// result overflows a uint64).
|
||||
var (
|
||||
prime1v = prime1
|
||||
prime2v = prime2
|
||||
prime3v = prime3
|
||||
prime4v = prime4
|
||||
prime5v = prime5
|
||||
)
|
||||
// Store the primes in an array as well.
|
||||
//
|
||||
// The consts are used when possible in Go code to avoid MOVs but we need a
|
||||
// contiguous array of the assembly code.
|
||||
var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5}
|
||||
|
||||
// Digest implements hash.Hash64.
|
||||
type Digest struct {
|
||||
|
@ -52,10 +44,10 @@ func New() *Digest {
|
|||
|
||||
// Reset clears the Digest's state so that it can be reused.
|
||||
func (d *Digest) Reset() {
|
||||
d.v1 = prime1v + prime2
|
||||
d.v1 = primes[0] + prime2
|
||||
d.v2 = prime2
|
||||
d.v3 = 0
|
||||
d.v4 = -prime1v
|
||||
d.v4 = -primes[0]
|
||||
d.total = 0
|
||||
d.n = 0
|
||||
}
|
||||
|
@ -71,21 +63,23 @@ func (d *Digest) Write(b []byte) (n int, err error) {
|
|||
n = len(b)
|
||||
d.total += uint64(n)
|
||||
|
||||
memleft := d.mem[d.n&(len(d.mem)-1):]
|
||||
|
||||
if d.n+n < 32 {
|
||||
// This new data doesn't even fill the current block.
|
||||
copy(d.mem[d.n:], b)
|
||||
copy(memleft, b)
|
||||
d.n += n
|
||||
return
|
||||
}
|
||||
|
||||
if d.n > 0 {
|
||||
// Finish off the partial block.
|
||||
copy(d.mem[d.n:], b)
|
||||
c := copy(memleft, b)
|
||||
d.v1 = round(d.v1, u64(d.mem[0:8]))
|
||||
d.v2 = round(d.v2, u64(d.mem[8:16]))
|
||||
d.v3 = round(d.v3, u64(d.mem[16:24]))
|
||||
d.v4 = round(d.v4, u64(d.mem[24:32]))
|
||||
b = b[32-d.n:]
|
||||
b = b[c:]
|
||||
d.n = 0
|
||||
}
|
||||
|
||||
|
@ -135,21 +129,20 @@ func (d *Digest) Sum64() uint64 {
|
|||
|
||||
h += d.total
|
||||
|
||||
i, end := 0, d.n
|
||||
for ; i+8 <= end; i += 8 {
|
||||
k1 := round(0, u64(d.mem[i:i+8]))
|
||||
b := d.mem[:d.n&(len(d.mem)-1)]
|
||||
for ; len(b) >= 8; b = b[8:] {
|
||||
k1 := round(0, u64(b[:8]))
|
||||
h ^= k1
|
||||
h = rol27(h)*prime1 + prime4
|
||||
}
|
||||
if i+4 <= end {
|
||||
h ^= uint64(u32(d.mem[i:i+4])) * prime1
|
||||
if len(b) >= 4 {
|
||||
h ^= uint64(u32(b[:4])) * prime1
|
||||
h = rol23(h)*prime2 + prime3
|
||||
i += 4
|
||||
b = b[4:]
|
||||
}
|
||||
for i < end {
|
||||
h ^= uint64(d.mem[i]) * prime5
|
||||
for ; len(b) > 0; b = b[1:] {
|
||||
h ^= uint64(b[0]) * prime5
|
||||
h = rol11(h) * prime1
|
||||
i++
|
||||
}
|
||||
|
||||
h ^= h >> 33
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !appengine && gc && !purego && !noasm
|
||||
// +build !appengine
|
||||
// +build gc
|
||||
// +build !purego
|
||||
|
@ -5,212 +6,205 @@
|
|||
|
||||
#include "textflag.h"
|
||||
|
||||
// Register allocation:
|
||||
// AX h
|
||||
// SI pointer to advance through b
|
||||
// DX n
|
||||
// BX loop end
|
||||
// R8 v1, k1
|
||||
// R9 v2
|
||||
// R10 v3
|
||||
// R11 v4
|
||||
// R12 tmp
|
||||
// R13 prime1v
|
||||
// R14 prime2v
|
||||
// DI prime4v
|
||||
// Registers:
|
||||
#define h AX
|
||||
#define d AX
|
||||
#define p SI // pointer to advance through b
|
||||
#define n DX
|
||||
#define end BX // loop end
|
||||
#define v1 R8
|
||||
#define v2 R9
|
||||
#define v3 R10
|
||||
#define v4 R11
|
||||
#define x R12
|
||||
#define prime1 R13
|
||||
#define prime2 R14
|
||||
#define prime4 DI
|
||||
|
||||
// round reads from and advances the buffer pointer in SI.
|
||||
// It assumes that R13 has prime1v and R14 has prime2v.
|
||||
#define round(r) \
|
||||
MOVQ (SI), R12 \
|
||||
ADDQ $8, SI \
|
||||
IMULQ R14, R12 \
|
||||
ADDQ R12, r \
|
||||
ROLQ $31, r \
|
||||
IMULQ R13, r
|
||||
#define round(acc, x) \
|
||||
IMULQ prime2, x \
|
||||
ADDQ x, acc \
|
||||
ROLQ $31, acc \
|
||||
IMULQ prime1, acc
|
||||
|
||||
// mergeRound applies a merge round on the two registers acc and val.
|
||||
// It assumes that R13 has prime1v, R14 has prime2v, and DI has prime4v.
|
||||
#define mergeRound(acc, val) \
|
||||
IMULQ R14, val \
|
||||
ROLQ $31, val \
|
||||
IMULQ R13, val \
|
||||
XORQ val, acc \
|
||||
IMULQ R13, acc \
|
||||
ADDQ DI, acc
|
||||
// round0 performs the operation x = round(0, x).
|
||||
#define round0(x) \
|
||||
IMULQ prime2, x \
|
||||
ROLQ $31, x \
|
||||
IMULQ prime1, x
|
||||
|
||||
// mergeRound applies a merge round on the two registers acc and x.
|
||||
// It assumes that prime1, prime2, and prime4 have been loaded.
|
||||
#define mergeRound(acc, x) \
|
||||
round0(x) \
|
||||
XORQ x, acc \
|
||||
IMULQ prime1, acc \
|
||||
ADDQ prime4, acc
|
||||
|
||||
// blockLoop processes as many 32-byte blocks as possible,
|
||||
// updating v1, v2, v3, and v4. It assumes that there is at least one block
|
||||
// to process.
|
||||
#define blockLoop() \
|
||||
loop: \
|
||||
MOVQ +0(p), x \
|
||||
round(v1, x) \
|
||||
MOVQ +8(p), x \
|
||||
round(v2, x) \
|
||||
MOVQ +16(p), x \
|
||||
round(v3, x) \
|
||||
MOVQ +24(p), x \
|
||||
round(v4, x) \
|
||||
ADDQ $32, p \
|
||||
CMPQ p, end \
|
||||
JLE loop
|
||||
|
||||
// func Sum64(b []byte) uint64
|
||||
TEXT ·Sum64(SB), NOSPLIT, $0-32
|
||||
TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32
|
||||
// Load fixed primes.
|
||||
MOVQ ·prime1v(SB), R13
|
||||
MOVQ ·prime2v(SB), R14
|
||||
MOVQ ·prime4v(SB), DI
|
||||
MOVQ ·primes+0(SB), prime1
|
||||
MOVQ ·primes+8(SB), prime2
|
||||
MOVQ ·primes+24(SB), prime4
|
||||
|
||||
// Load slice.
|
||||
MOVQ b_base+0(FP), SI
|
||||
MOVQ b_len+8(FP), DX
|
||||
LEAQ (SI)(DX*1), BX
|
||||
MOVQ b_base+0(FP), p
|
||||
MOVQ b_len+8(FP), n
|
||||
LEAQ (p)(n*1), end
|
||||
|
||||
// The first loop limit will be len(b)-32.
|
||||
SUBQ $32, BX
|
||||
SUBQ $32, end
|
||||
|
||||
// Check whether we have at least one block.
|
||||
CMPQ DX, $32
|
||||
CMPQ n, $32
|
||||
JLT noBlocks
|
||||
|
||||
// Set up initial state (v1, v2, v3, v4).
|
||||
MOVQ R13, R8
|
||||
ADDQ R14, R8
|
||||
MOVQ R14, R9
|
||||
XORQ R10, R10
|
||||
XORQ R11, R11
|
||||
SUBQ R13, R11
|
||||
MOVQ prime1, v1
|
||||
ADDQ prime2, v1
|
||||
MOVQ prime2, v2
|
||||
XORQ v3, v3
|
||||
XORQ v4, v4
|
||||
SUBQ prime1, v4
|
||||
|
||||
// Loop until SI > BX.
|
||||
blockLoop:
|
||||
round(R8)
|
||||
round(R9)
|
||||
round(R10)
|
||||
round(R11)
|
||||
blockLoop()
|
||||
|
||||
CMPQ SI, BX
|
||||
JLE blockLoop
|
||||
MOVQ v1, h
|
||||
ROLQ $1, h
|
||||
MOVQ v2, x
|
||||
ROLQ $7, x
|
||||
ADDQ x, h
|
||||
MOVQ v3, x
|
||||
ROLQ $12, x
|
||||
ADDQ x, h
|
||||
MOVQ v4, x
|
||||
ROLQ $18, x
|
||||
ADDQ x, h
|
||||
|
||||
MOVQ R8, AX
|
||||
ROLQ $1, AX
|
||||
MOVQ R9, R12
|
||||
ROLQ $7, R12
|
||||
ADDQ R12, AX
|
||||
MOVQ R10, R12
|
||||
ROLQ $12, R12
|
||||
ADDQ R12, AX
|
||||
MOVQ R11, R12
|
||||
ROLQ $18, R12
|
||||
ADDQ R12, AX
|
||||
|
||||
mergeRound(AX, R8)
|
||||
mergeRound(AX, R9)
|
||||
mergeRound(AX, R10)
|
||||
mergeRound(AX, R11)
|
||||
mergeRound(h, v1)
|
||||
mergeRound(h, v2)
|
||||
mergeRound(h, v3)
|
||||
mergeRound(h, v4)
|
||||
|
||||
JMP afterBlocks
|
||||
|
||||
noBlocks:
|
||||
MOVQ ·prime5v(SB), AX
|
||||
MOVQ ·primes+32(SB), h
|
||||
|
||||
afterBlocks:
|
||||
ADDQ DX, AX
|
||||
ADDQ n, h
|
||||
|
||||
// Right now BX has len(b)-32, and we want to loop until SI > len(b)-8.
|
||||
ADDQ $24, BX
|
||||
ADDQ $24, end
|
||||
CMPQ p, end
|
||||
JG try4
|
||||
|
||||
CMPQ SI, BX
|
||||
JG fourByte
|
||||
loop8:
|
||||
MOVQ (p), x
|
||||
ADDQ $8, p
|
||||
round0(x)
|
||||
XORQ x, h
|
||||
ROLQ $27, h
|
||||
IMULQ prime1, h
|
||||
ADDQ prime4, h
|
||||
|
||||
wordLoop:
|
||||
// Calculate k1.
|
||||
MOVQ (SI), R8
|
||||
ADDQ $8, SI
|
||||
IMULQ R14, R8
|
||||
ROLQ $31, R8
|
||||
IMULQ R13, R8
|
||||
CMPQ p, end
|
||||
JLE loop8
|
||||
|
||||
XORQ R8, AX
|
||||
ROLQ $27, AX
|
||||
IMULQ R13, AX
|
||||
ADDQ DI, AX
|
||||
try4:
|
||||
ADDQ $4, end
|
||||
CMPQ p, end
|
||||
JG try1
|
||||
|
||||
CMPQ SI, BX
|
||||
JLE wordLoop
|
||||
MOVL (p), x
|
||||
ADDQ $4, p
|
||||
IMULQ prime1, x
|
||||
XORQ x, h
|
||||
|
||||
fourByte:
|
||||
ADDQ $4, BX
|
||||
CMPQ SI, BX
|
||||
JG singles
|
||||
ROLQ $23, h
|
||||
IMULQ prime2, h
|
||||
ADDQ ·primes+16(SB), h
|
||||
|
||||
MOVL (SI), R8
|
||||
ADDQ $4, SI
|
||||
IMULQ R13, R8
|
||||
XORQ R8, AX
|
||||
|
||||
ROLQ $23, AX
|
||||
IMULQ R14, AX
|
||||
ADDQ ·prime3v(SB), AX
|
||||
|
||||
singles:
|
||||
ADDQ $4, BX
|
||||
CMPQ SI, BX
|
||||
try1:
|
||||
ADDQ $4, end
|
||||
CMPQ p, end
|
||||
JGE finalize
|
||||
|
||||
singlesLoop:
|
||||
MOVBQZX (SI), R12
|
||||
ADDQ $1, SI
|
||||
IMULQ ·prime5v(SB), R12
|
||||
XORQ R12, AX
|
||||
loop1:
|
||||
MOVBQZX (p), x
|
||||
ADDQ $1, p
|
||||
IMULQ ·primes+32(SB), x
|
||||
XORQ x, h
|
||||
ROLQ $11, h
|
||||
IMULQ prime1, h
|
||||
|
||||
ROLQ $11, AX
|
||||
IMULQ R13, AX
|
||||
|
||||
CMPQ SI, BX
|
||||
JL singlesLoop
|
||||
CMPQ p, end
|
||||
JL loop1
|
||||
|
||||
finalize:
|
||||
MOVQ AX, R12
|
||||
SHRQ $33, R12
|
||||
XORQ R12, AX
|
||||
IMULQ R14, AX
|
||||
MOVQ AX, R12
|
||||
SHRQ $29, R12
|
||||
XORQ R12, AX
|
||||
IMULQ ·prime3v(SB), AX
|
||||
MOVQ AX, R12
|
||||
SHRQ $32, R12
|
||||
XORQ R12, AX
|
||||
MOVQ h, x
|
||||
SHRQ $33, x
|
||||
XORQ x, h
|
||||
IMULQ prime2, h
|
||||
MOVQ h, x
|
||||
SHRQ $29, x
|
||||
XORQ x, h
|
||||
IMULQ ·primes+16(SB), h
|
||||
MOVQ h, x
|
||||
SHRQ $32, x
|
||||
XORQ x, h
|
||||
|
||||
MOVQ AX, ret+24(FP)
|
||||
MOVQ h, ret+24(FP)
|
||||
RET
|
||||
|
||||
// writeBlocks uses the same registers as above except that it uses AX to store
|
||||
// the d pointer.
|
||||
|
||||
// func writeBlocks(d *Digest, b []byte) int
|
||||
TEXT ·writeBlocks(SB), NOSPLIT, $0-40
|
||||
TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40
|
||||
// Load fixed primes needed for round.
|
||||
MOVQ ·prime1v(SB), R13
|
||||
MOVQ ·prime2v(SB), R14
|
||||
MOVQ ·primes+0(SB), prime1
|
||||
MOVQ ·primes+8(SB), prime2
|
||||
|
||||
// Load slice.
|
||||
MOVQ b_base+8(FP), SI
|
||||
MOVQ b_len+16(FP), DX
|
||||
LEAQ (SI)(DX*1), BX
|
||||
SUBQ $32, BX
|
||||
MOVQ b_base+8(FP), p
|
||||
MOVQ b_len+16(FP), n
|
||||
LEAQ (p)(n*1), end
|
||||
SUBQ $32, end
|
||||
|
||||
// Load vN from d.
|
||||
MOVQ d+0(FP), AX
|
||||
MOVQ 0(AX), R8 // v1
|
||||
MOVQ 8(AX), R9 // v2
|
||||
MOVQ 16(AX), R10 // v3
|
||||
MOVQ 24(AX), R11 // v4
|
||||
MOVQ s+0(FP), d
|
||||
MOVQ 0(d), v1
|
||||
MOVQ 8(d), v2
|
||||
MOVQ 16(d), v3
|
||||
MOVQ 24(d), v4
|
||||
|
||||
// We don't need to check the loop condition here; this function is
|
||||
// always called with at least one block of data to process.
|
||||
blockLoop:
|
||||
round(R8)
|
||||
round(R9)
|
||||
round(R10)
|
||||
round(R11)
|
||||
|
||||
CMPQ SI, BX
|
||||
JLE blockLoop
|
||||
blockLoop()
|
||||
|
||||
// Copy vN back to d.
|
||||
MOVQ R8, 0(AX)
|
||||
MOVQ R9, 8(AX)
|
||||
MOVQ R10, 16(AX)
|
||||
MOVQ R11, 24(AX)
|
||||
MOVQ v1, 0(d)
|
||||
MOVQ v2, 8(d)
|
||||
MOVQ v3, 16(d)
|
||||
MOVQ v4, 24(d)
|
||||
|
||||
// The number of bytes written is SI minus the old base pointer.
|
||||
SUBQ b_base+8(FP), SI
|
||||
MOVQ SI, ret+32(FP)
|
||||
// The number of bytes written is p minus the old base pointer.
|
||||
SUBQ b_base+8(FP), p
|
||||
MOVQ p, ret+32(FP)
|
||||
|
||||
RET
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
// +build gc,!purego,!noasm
|
||||
//go:build !appengine && gc && !purego && !noasm
|
||||
// +build !appengine
|
||||
// +build gc
|
||||
// +build !purego
|
||||
// +build !noasm
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// Register allocation.
|
||||
// Registers:
|
||||
#define digest R1
|
||||
#define h R2 // Return value.
|
||||
#define p R3 // Input pointer.
|
||||
#define len R4
|
||||
#define nblocks R5 // len / 32.
|
||||
#define h R2 // return value
|
||||
#define p R3 // input pointer
|
||||
#define n R4 // input length
|
||||
#define nblocks R5 // n / 32
|
||||
#define prime1 R7
|
||||
#define prime2 R8
|
||||
#define prime3 R9
|
||||
|
@ -25,60 +29,52 @@
|
|||
#define round(acc, x) \
|
||||
MADD prime2, acc, x, acc \
|
||||
ROR $64-31, acc \
|
||||
MUL prime1, acc \
|
||||
MUL prime1, acc
|
||||
|
||||
// x = round(0, x).
|
||||
// round0 performs the operation x = round(0, x).
|
||||
#define round0(x) \
|
||||
MUL prime2, x \
|
||||
ROR $64-31, x \
|
||||
MUL prime1, x \
|
||||
MUL prime1, x
|
||||
|
||||
#define mergeRound(x) \
|
||||
#define mergeRound(acc, x) \
|
||||
round0(x) \
|
||||
EOR x, h \
|
||||
MADD h, prime4, prime1, h \
|
||||
EOR x, acc \
|
||||
MADD acc, prime4, prime1, acc
|
||||
|
||||
// Update v[1-4] with 32-byte blocks. Assumes len >= 32.
|
||||
#define blocksLoop() \
|
||||
LSR $5, len, nblocks \
|
||||
// blockLoop processes as many 32-byte blocks as possible,
|
||||
// updating v1, v2, v3, and v4. It assumes that n >= 32.
|
||||
#define blockLoop() \
|
||||
LSR $5, n, nblocks \
|
||||
PCALIGN $16 \
|
||||
loop: \
|
||||
LDP.P 32(p), (x1, x2) \
|
||||
LDP.P 16(p), (x1, x2) \
|
||||
LDP.P 16(p), (x3, x4) \
|
||||
round(v1, x1) \
|
||||
LDP -16(p), (x3, x4) \
|
||||
round(v2, x2) \
|
||||
SUB $1, nblocks \
|
||||
round(v3, x3) \
|
||||
round(v4, x4) \
|
||||
CBNZ nblocks, loop \
|
||||
|
||||
// The primes are repeated here to ensure that they're stored
|
||||
// in a contiguous array, so we can load them with LDP.
|
||||
DATA primes<> +0(SB)/8, $11400714785074694791
|
||||
DATA primes<> +8(SB)/8, $14029467366897019727
|
||||
DATA primes<>+16(SB)/8, $1609587929392839161
|
||||
DATA primes<>+24(SB)/8, $9650029242287828579
|
||||
DATA primes<>+32(SB)/8, $2870177450012600261
|
||||
GLOBL primes<>(SB), NOPTR+RODATA, $40
|
||||
SUB $1, nblocks \
|
||||
CBNZ nblocks, loop
|
||||
|
||||
// func Sum64(b []byte) uint64
|
||||
TEXT ·Sum64(SB), NOFRAME+NOSPLIT, $0-32
|
||||
LDP b_base+0(FP), (p, len)
|
||||
TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32
|
||||
LDP b_base+0(FP), (p, n)
|
||||
|
||||
LDP primes<> +0(SB), (prime1, prime2)
|
||||
LDP primes<>+16(SB), (prime3, prime4)
|
||||
MOVD primes<>+32(SB), prime5
|
||||
LDP ·primes+0(SB), (prime1, prime2)
|
||||
LDP ·primes+16(SB), (prime3, prime4)
|
||||
MOVD ·primes+32(SB), prime5
|
||||
|
||||
CMP $32, len
|
||||
CSEL LO, prime5, ZR, h // if len < 32 { h = prime5 } else { h = 0 }
|
||||
BLO afterLoop
|
||||
CMP $32, n
|
||||
CSEL LT, prime5, ZR, h // if n < 32 { h = prime5 } else { h = 0 }
|
||||
BLT afterLoop
|
||||
|
||||
ADD prime1, prime2, v1
|
||||
MOVD prime2, v2
|
||||
MOVD $0, v3
|
||||
NEG prime1, v4
|
||||
|
||||
blocksLoop()
|
||||
blockLoop()
|
||||
|
||||
ROR $64-1, v1, x1
|
||||
ROR $64-7, v2, x2
|
||||
|
@ -88,71 +84,75 @@ TEXT ·Sum64(SB), NOFRAME+NOSPLIT, $0-32
|
|||
ADD x3, x4
|
||||
ADD x2, x4, h
|
||||
|
||||
mergeRound(v1)
|
||||
mergeRound(v2)
|
||||
mergeRound(v3)
|
||||
mergeRound(v4)
|
||||
mergeRound(h, v1)
|
||||
mergeRound(h, v2)
|
||||
mergeRound(h, v3)
|
||||
mergeRound(h, v4)
|
||||
|
||||
afterLoop:
|
||||
ADD len, h
|
||||
ADD n, h
|
||||
|
||||
TBZ $4, len, try8
|
||||
TBZ $4, n, try8
|
||||
LDP.P 16(p), (x1, x2)
|
||||
|
||||
round0(x1)
|
||||
|
||||
// NOTE: here and below, sequencing the EOR after the ROR (using a
|
||||
// rotated register) is worth a small but measurable speedup for small
|
||||
// inputs.
|
||||
ROR $64-27, h
|
||||
EOR x1 @> 64-27, h, h
|
||||
MADD h, prime4, prime1, h
|
||||
|
||||
round0(x2)
|
||||
ROR $64-27, h
|
||||
EOR x2 @> 64-27, h
|
||||
EOR x2 @> 64-27, h, h
|
||||
MADD h, prime4, prime1, h
|
||||
|
||||
try8:
|
||||
TBZ $3, len, try4
|
||||
TBZ $3, n, try4
|
||||
MOVD.P 8(p), x1
|
||||
|
||||
round0(x1)
|
||||
ROR $64-27, h
|
||||
EOR x1 @> 64-27, h
|
||||
EOR x1 @> 64-27, h, h
|
||||
MADD h, prime4, prime1, h
|
||||
|
||||
try4:
|
||||
TBZ $2, len, try2
|
||||
TBZ $2, n, try2
|
||||
MOVWU.P 4(p), x2
|
||||
|
||||
MUL prime1, x2
|
||||
ROR $64-23, h
|
||||
EOR x2 @> 64-23, h
|
||||
EOR x2 @> 64-23, h, h
|
||||
MADD h, prime3, prime2, h
|
||||
|
||||
try2:
|
||||
TBZ $1, len, try1
|
||||
TBZ $1, n, try1
|
||||
MOVHU.P 2(p), x3
|
||||
AND $255, x3, x1
|
||||
LSR $8, x3, x2
|
||||
|
||||
MUL prime5, x1
|
||||
ROR $64-11, h
|
||||
EOR x1 @> 64-11, h
|
||||
EOR x1 @> 64-11, h, h
|
||||
MUL prime1, h
|
||||
|
||||
MUL prime5, x2
|
||||
ROR $64-11, h
|
||||
EOR x2 @> 64-11, h
|
||||
EOR x2 @> 64-11, h, h
|
||||
MUL prime1, h
|
||||
|
||||
try1:
|
||||
TBZ $0, len, end
|
||||
TBZ $0, n, finalize
|
||||
MOVBU (p), x4
|
||||
|
||||
MUL prime5, x4
|
||||
ROR $64-11, h
|
||||
EOR x4 @> 64-11, h
|
||||
EOR x4 @> 64-11, h, h
|
||||
MUL prime1, h
|
||||
|
||||
end:
|
||||
finalize:
|
||||
EOR h >> 33, h
|
||||
MUL prime2, h
|
||||
EOR h >> 29, h
|
||||
|
@ -163,24 +163,22 @@ end:
|
|||
RET
|
||||
|
||||
// func writeBlocks(d *Digest, b []byte) int
|
||||
//
|
||||
// Assumes len(b) >= 32.
|
||||
TEXT ·writeBlocks(SB), NOFRAME+NOSPLIT, $0-40
|
||||
LDP primes<>(SB), (prime1, prime2)
|
||||
TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40
|
||||
LDP ·primes+0(SB), (prime1, prime2)
|
||||
|
||||
// Load state. Assume v[1-4] are stored contiguously.
|
||||
MOVD d+0(FP), digest
|
||||
LDP 0(digest), (v1, v2)
|
||||
LDP 16(digest), (v3, v4)
|
||||
|
||||
LDP b_base+8(FP), (p, len)
|
||||
LDP b_base+8(FP), (p, n)
|
||||
|
||||
blocksLoop()
|
||||
blockLoop()
|
||||
|
||||
// Store updated state.
|
||||
STP (v1, v2), 0(digest)
|
||||
STP (v3, v4), 16(digest)
|
||||
|
||||
BIC $31, len
|
||||
MOVD len, ret+32(FP)
|
||||
BIC $31, n
|
||||
MOVD n, ret+32(FP)
|
||||
RET
|
||||
|
|
|
@ -13,4 +13,4 @@ package xxhash
|
|||
func Sum64(b []byte) uint64
|
||||
|
||||
//go:noescape
|
||||
func writeBlocks(d *Digest, b []byte) int
|
||||
func writeBlocks(s *Digest, b []byte) int
|
||||
|
|
|
@ -15,10 +15,10 @@ func Sum64(b []byte) uint64 {
|
|||
var h uint64
|
||||
|
||||
if n >= 32 {
|
||||
v1 := prime1v + prime2
|
||||
v1 := primes[0] + prime2
|
||||
v2 := prime2
|
||||
v3 := uint64(0)
|
||||
v4 := -prime1v
|
||||
v4 := -primes[0]
|
||||
for len(b) >= 32 {
|
||||
v1 = round(v1, u64(b[0:8:len(b)]))
|
||||
v2 = round(v2, u64(b[8:16:len(b)]))
|
||||
|
@ -37,19 +37,18 @@ func Sum64(b []byte) uint64 {
|
|||
|
||||
h += uint64(n)
|
||||
|
||||
i, end := 0, len(b)
|
||||
for ; i+8 <= end; i += 8 {
|
||||
k1 := round(0, u64(b[i:i+8:len(b)]))
|
||||
for ; len(b) >= 8; b = b[8:] {
|
||||
k1 := round(0, u64(b[:8]))
|
||||
h ^= k1
|
||||
h = rol27(h)*prime1 + prime4
|
||||
}
|
||||
if i+4 <= end {
|
||||
h ^= uint64(u32(b[i:i+4:len(b)])) * prime1
|
||||
if len(b) >= 4 {
|
||||
h ^= uint64(u32(b[:4])) * prime1
|
||||
h = rol23(h)*prime2 + prime3
|
||||
i += 4
|
||||
b = b[4:]
|
||||
}
|
||||
for ; i < end; i++ {
|
||||
h ^= uint64(b[i]) * prime5
|
||||
for ; len(b) > 0; b = b[1:] {
|
||||
h ^= uint64(b[0]) * prime5
|
||||
h = rol11(h) * prime1
|
||||
}
|
||||
|
||||
|
|
|
@ -36,9 +36,6 @@ const forcePreDef = false
|
|||
// zstdMinMatch is the minimum zstd match length.
|
||||
const zstdMinMatch = 3
|
||||
|
||||
// Reset the buffer offset when reaching this.
|
||||
const bufferReset = math.MaxInt32 - MaxWindowSize
|
||||
|
||||
// fcsUnknown is used for unknown frame content size.
|
||||
const fcsUnknown = math.MaxUint64
|
||||
|
||||
|
@ -110,26 +107,25 @@ func printf(format string, a ...interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
// matchLen returns the maximum length.
|
||||
// matchLen returns the maximum common prefix length of a and b.
|
||||
// a must be the shortest of the two.
|
||||
// The function also returns whether all bytes matched.
|
||||
func matchLen(a, b []byte) int {
|
||||
b = b[:len(a)]
|
||||
for i := 0; i < len(a)-7; i += 8 {
|
||||
if diff := load64(a, i) ^ load64(b, i); diff != 0 {
|
||||
return i + (bits.TrailingZeros64(diff) >> 3)
|
||||
func matchLen(a, b []byte) (n int) {
|
||||
for ; len(a) >= 8 && len(b) >= 8; a, b = a[8:], b[8:] {
|
||||
diff := binary.LittleEndian.Uint64(a) ^ binary.LittleEndian.Uint64(b)
|
||||
if diff != 0 {
|
||||
return n + bits.TrailingZeros64(diff)>>3
|
||||
}
|
||||
n += 8
|
||||
}
|
||||
|
||||
checked := (len(a) >> 3) << 3
|
||||
a = a[checked:]
|
||||
b = b[checked:]
|
||||
for i := range a {
|
||||
if a[i] != b[i] {
|
||||
return i + checked
|
||||
break
|
||||
}
|
||||
n++
|
||||
}
|
||||
return len(a) + checked
|
||||
return n
|
||||
|
||||
}
|
||||
|
||||
func load3232(b []byte, i int32) uint32 {
|
||||
|
@ -140,10 +136,6 @@ func load6432(b []byte, i int32) uint64 {
|
|||
return binary.LittleEndian.Uint64(b[i:])
|
||||
}
|
||||
|
||||
func load64(b []byte, i int) uint64 {
|
||||
return binary.LittleEndian.Uint64(b[i:])
|
||||
}
|
||||
|
||||
type byter interface {
|
||||
Bytes() []byte
|
||||
Len() int
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
// Copyright 2022 The Sigstore Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cryptoutils
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
// OIDOtherName is the OID for the OtherName SAN per RFC 5280
|
||||
OIDOtherName = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 7}
|
||||
// SANOID is the OID for Subject Alternative Name per RFC 5280
|
||||
SANOID = asn1.ObjectIdentifier{2, 5, 29, 17}
|
||||
)
|
||||
|
||||
// OtherName describes a name related to a certificate which is not in one
|
||||
// of the standard name formats. RFC 5280, 4.2.1.6:
|
||||
//
|
||||
// OtherName ::= SEQUENCE {
|
||||
// type-id OBJECT IDENTIFIER,
|
||||
// value [0] EXPLICIT ANY DEFINED BY type-id }
|
||||
//
|
||||
// OtherName for Fulcio-issued certificates only supports UTF-8 strings as values.
|
||||
type OtherName struct {
|
||||
ID asn1.ObjectIdentifier
|
||||
Value string `asn1:"utf8,explicit,tag:0"`
|
||||
}
|
||||
|
||||
// MarshalOtherNameSAN creates a Subject Alternative Name extension
|
||||
// with an OtherName sequence. RFC 5280, 4.2.1.6:
|
||||
//
|
||||
// SubjectAltName ::= GeneralNames
|
||||
// GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
|
||||
// GeneralName ::= CHOICE {
|
||||
//
|
||||
// otherName [0] OtherName,
|
||||
// ... }
|
||||
func MarshalOtherNameSAN(name string, critical bool) (*pkix.Extension, error) {
|
||||
o := OtherName{
|
||||
ID: OIDOtherName,
|
||||
Value: name,
|
||||
}
|
||||
bytes, err := asn1.MarshalWithParams(o, "tag:0")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sans, err := asn1.Marshal([]asn1.RawValue{{FullBytes: bytes}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pkix.Extension{
|
||||
Id: SANOID,
|
||||
Critical: critical,
|
||||
Value: sans,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UnmarshalOtherNameSAN extracts a UTF-8 string from the OtherName
|
||||
// field in the Subject Alternative Name extension.
|
||||
func UnmarshalOtherNameSAN(exts []pkix.Extension) (string, error) {
|
||||
var otherNames []string
|
||||
|
||||
for _, e := range exts {
|
||||
if !e.Id.Equal(SANOID) {
|
||||
continue
|
||||
}
|
||||
|
||||
var seq asn1.RawValue
|
||||
rest, err := asn1.Unmarshal(e.Value, &seq)
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if len(rest) != 0 {
|
||||
return "", fmt.Errorf("trailing data after X.509 extension")
|
||||
}
|
||||
if !seq.IsCompound || seq.Tag != asn1.TagSequence || seq.Class != asn1.ClassUniversal {
|
||||
return "", asn1.StructuralError{Msg: "bad SAN sequence"}
|
||||
}
|
||||
|
||||
rest = seq.Bytes
|
||||
for len(rest) > 0 {
|
||||
var v asn1.RawValue
|
||||
rest, err = asn1.Unmarshal(rest, &v)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// skip all GeneralName fields except OtherName
|
||||
if v.Tag != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var other OtherName
|
||||
if _, err := asn1.UnmarshalWithParams(v.FullBytes, &other, "tag:0"); err != nil {
|
||||
return "", fmt.Errorf("could not parse requested OtherName SAN: %w", err)
|
||||
}
|
||||
if !other.ID.Equal(OIDOtherName) {
|
||||
return "", fmt.Errorf("unexpected OID for OtherName, expected %v, got %v", OIDOtherName, other.ID)
|
||||
}
|
||||
otherNames = append(otherNames, other.Value)
|
||||
}
|
||||
}
|
||||
|
||||
if len(otherNames) == 0 {
|
||||
return "", errors.New("no OtherName found")
|
||||
}
|
||||
if len(otherNames) != 1 {
|
||||
return "", errors.New("expected only one OtherName")
|
||||
}
|
||||
|
||||
return otherNames[0], nil
|
||||
}
|
||||
|
||||
// GetSubjectAlternateNames extracts all subject alternative names from
|
||||
// the certificate, including email addresses, DNS, IP addresses, URIs,
|
||||
// and OtherName SANs
|
||||
func GetSubjectAlternateNames(cert *x509.Certificate) []string {
|
||||
sans := []string{}
|
||||
sans = append(sans, cert.DNSNames...)
|
||||
sans = append(sans, cert.EmailAddresses...)
|
||||
for _, ip := range cert.IPAddresses {
|
||||
sans = append(sans, ip.String())
|
||||
}
|
||||
for _, uri := range cert.URIs {
|
||||
sans = append(sans, uri.String())
|
||||
}
|
||||
// ignore error if there's no OtherName SAN
|
||||
otherName, _ := UnmarshalOtherNameSAN(cert.Extensions)
|
||||
if len(otherName) > 0 {
|
||||
sans = append(sans, otherName)
|
||||
}
|
||||
return sans
|
||||
}
|
|
@ -76,7 +76,6 @@ import (
|
|||
"go/format"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -166,7 +165,7 @@ func main() {
|
|||
baseName := fmt.Sprintf("%s_string.go", types[0])
|
||||
outputName = filepath.Join(dir, strings.ToLower(baseName))
|
||||
}
|
||||
err := ioutil.WriteFile(outputName, src, 0644)
|
||||
err := os.WriteFile(outputName, src, 0644)
|
||||
if err != nil {
|
||||
log.Fatalf("writing output: %s", err)
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ import (
|
|||
"io/ioutil"
|
||||
"os/exec"
|
||||
|
||||
"golang.org/x/tools/go/internal/gcimporter"
|
||||
"golang.org/x/tools/internal/gcimporter"
|
||||
)
|
||||
|
||||
// Find returns the name of an object (.o) or archive (.a) file
|
||||
|
|
|
@ -604,17 +604,12 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse
|
|||
|
||||
// Work around https://golang.org/issue/28749:
|
||||
// cmd/go puts assembly, C, and C++ files in CompiledGoFiles.
|
||||
// Filter out any elements of CompiledGoFiles that are also in OtherFiles.
|
||||
// We have to keep this workaround in place until go1.12 is a distant memory.
|
||||
if len(pkg.OtherFiles) > 0 {
|
||||
other := make(map[string]bool, len(pkg.OtherFiles))
|
||||
for _, f := range pkg.OtherFiles {
|
||||
other[f] = true
|
||||
}
|
||||
|
||||
// Remove files from CompiledGoFiles that are non-go files
|
||||
// (or are not files that look like they are from the cache).
|
||||
if len(pkg.CompiledGoFiles) > 0 {
|
||||
out := pkg.CompiledGoFiles[:0]
|
||||
for _, f := range pkg.CompiledGoFiles {
|
||||
if other[f] {
|
||||
if ext := filepath.Ext(f); ext != ".go" && ext != "" { // ext == "" means the file is from the cache, so probably cgo-processed file
|
||||
continue
|
||||
}
|
||||
out = append(out, f)
|
||||
|
|
|
@ -303,6 +303,9 @@ type Package struct {
|
|||
// of the package, or while parsing or type-checking its files.
|
||||
Errors []Error
|
||||
|
||||
// TypeErrors contains the subset of errors produced during type checking.
|
||||
TypeErrors []types.Error
|
||||
|
||||
// GoFiles lists the absolute file paths of the package's Go source files.
|
||||
GoFiles []string
|
||||
|
||||
|
@ -911,6 +914,7 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
|
|||
|
||||
case types.Error:
|
||||
// from type checker
|
||||
lpkg.TypeErrors = append(lpkg.TypeErrors, err)
|
||||
errs = append(errs, Error{
|
||||
Pos: err.Fset.Position(err.Pos).String(),
|
||||
Msg: err.Msg,
|
||||
|
@ -1017,7 +1021,7 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
|
|||
tc := &types.Config{
|
||||
Importer: importer,
|
||||
|
||||
// Type-check bodies of functions only in non-initial packages.
|
||||
// Type-check bodies of functions only in initial packages.
|
||||
// Example: for import graph A->B->C and initial packages {A,C},
|
||||
// we can ignore function bodies in B.
|
||||
IgnoreFuncBodies: ld.Mode&NeedDeps == 0 && !lpkg.initial,
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/constant"
|
||||
"go/token"
|
||||
"go/types"
|
||||
|
@ -145,7 +144,7 @@ func BExportData(fset *token.FileSet, pkg *types.Package) (b []byte, err error)
|
|||
objcount := 0
|
||||
scope := pkg.Scope()
|
||||
for _, name := range scope.Names() {
|
||||
if !ast.IsExported(name) {
|
||||
if !token.IsExported(name) {
|
||||
continue
|
||||
}
|
||||
if trace {
|
||||
|
@ -482,7 +481,7 @@ func (p *exporter) method(m *types.Func) {
|
|||
|
||||
p.pos(m)
|
||||
p.string(m.Name())
|
||||
if m.Name() != "_" && !ast.IsExported(m.Name()) {
|
||||
if m.Name() != "_" && !token.IsExported(m.Name()) {
|
||||
p.pkg(m.Pkg(), false)
|
||||
}
|
||||
|
||||
|
@ -501,7 +500,7 @@ func (p *exporter) fieldName(f *types.Var) {
|
|||
// 3) field name doesn't match base type name (alias name)
|
||||
bname := basetypeName(f.Type())
|
||||
if name == bname {
|
||||
if ast.IsExported(name) {
|
||||
if token.IsExported(name) {
|
||||
name = "" // 1) we don't need to know the field name or package
|
||||
} else {
|
||||
name = "?" // 2) use unexported name "?" to force package export
|
||||
|
@ -514,7 +513,7 @@ func (p *exporter) fieldName(f *types.Var) {
|
|||
}
|
||||
|
||||
p.string(name)
|
||||
if name != "" && !ast.IsExported(name) {
|
||||
if name != "" && !token.IsExported(name) {
|
||||
p.pkg(f.Pkg(), false)
|
||||
}
|
||||
}
|
|
@ -9,10 +9,11 @@
|
|||
// Package gcimporter provides various functions for reading
|
||||
// gc-generated object files that can be used to implement the
|
||||
// Importer interface defined by the Go 1.5 standard library package.
|
||||
package gcimporter // import "golang.org/x/tools/go/internal/gcimporter"
|
||||
package gcimporter // import "golang.org/x/tools/internal/gcimporter"
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/build"
|
||||
|
@ -22,10 +23,12 @@ import (
|
|||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"text/scanner"
|
||||
)
|
||||
|
||||
|
@ -38,6 +41,47 @@ const (
|
|||
trace = false
|
||||
)
|
||||
|
||||
var exportMap sync.Map // package dir → func() (string, bool)
|
||||
|
||||
// lookupGorootExport returns the location of the export data
|
||||
// (normally found in the build cache, but located in GOROOT/pkg
|
||||
// in prior Go releases) for the package located in pkgDir.
|
||||
//
|
||||
// (We use the package's directory instead of its import path
|
||||
// mainly to simplify handling of the packages in src/vendor
|
||||
// and cmd/vendor.)
|
||||
func lookupGorootExport(pkgDir string) (string, bool) {
|
||||
f, ok := exportMap.Load(pkgDir)
|
||||
if !ok {
|
||||
var (
|
||||
listOnce sync.Once
|
||||
exportPath string
|
||||
)
|
||||
f, _ = exportMap.LoadOrStore(pkgDir, func() (string, bool) {
|
||||
listOnce.Do(func() {
|
||||
cmd := exec.Command("go", "list", "-export", "-f", "{{.Export}}", pkgDir)
|
||||
cmd.Dir = build.Default.GOROOT
|
||||
var output []byte
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
exports := strings.Split(string(bytes.TrimSpace(output)), "\n")
|
||||
if len(exports) != 1 {
|
||||
return
|
||||
}
|
||||
|
||||
exportPath = exports[0]
|
||||
})
|
||||
|
||||
return exportPath, exportPath != ""
|
||||
})
|
||||
}
|
||||
|
||||
return f.(func() (string, bool))()
|
||||
}
|
||||
|
||||
var pkgExts = [...]string{".a", ".o"}
|
||||
|
||||
// FindPkg returns the filename and unique package id for an import
|
||||
|
@ -60,11 +104,18 @@ func FindPkg(path, srcDir string) (filename, id string) {
|
|||
}
|
||||
bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
|
||||
if bp.PkgObj == "" {
|
||||
var ok bool
|
||||
if bp.Goroot && bp.Dir != "" {
|
||||
filename, ok = lookupGorootExport(bp.Dir)
|
||||
}
|
||||
if !ok {
|
||||
id = path // make sure we have an id to print in error message
|
||||
return
|
||||
}
|
||||
} else {
|
||||
noext = strings.TrimSuffix(bp.PkgObj, ".a")
|
||||
id = bp.ImportPath
|
||||
}
|
||||
|
||||
case build.IsLocalImport(path):
|
||||
// "./x" -> "/this/directory/x.ext", "/this/directory/x"
|
||||
|
@ -85,6 +136,12 @@ func FindPkg(path, srcDir string) (filename, id string) {
|
|||
}
|
||||
}
|
||||
|
||||
if filename != "" {
|
||||
if f, err := os.Stat(filename); err == nil && !f.IsDir() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// try extensions
|
||||
for _, ext := range pkgExts {
|
||||
filename = noext + ext
|
|
@ -12,7 +12,6 @@ import (
|
|||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/constant"
|
||||
"go/token"
|
||||
"go/types"
|
||||
|
@ -26,6 +25,41 @@ import (
|
|||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
// IExportShallow encodes "shallow" export data for the specified package.
|
||||
//
|
||||
// No promises are made about the encoding other than that it can be
|
||||
// decoded by the same version of IIExportShallow. If you plan to save
|
||||
// export data in the file system, be sure to include a cryptographic
|
||||
// digest of the executable in the key to avoid version skew.
|
||||
func IExportShallow(fset *token.FileSet, pkg *types.Package) ([]byte, error) {
|
||||
// In principle this operation can only fail if out.Write fails,
|
||||
// but that's impossible for bytes.Buffer---and as a matter of
|
||||
// fact iexportCommon doesn't even check for I/O errors.
|
||||
// TODO(adonovan): handle I/O errors properly.
|
||||
// TODO(adonovan): use byte slices throughout, avoiding copying.
|
||||
const bundle, shallow = false, true
|
||||
var out bytes.Buffer
|
||||
err := iexportCommon(&out, fset, bundle, shallow, iexportVersion, []*types.Package{pkg})
|
||||
return out.Bytes(), err
|
||||
}
|
||||
|
||||
// IImportShallow decodes "shallow" types.Package data encoded by IExportShallow
|
||||
// in the same executable. This function cannot import data from
|
||||
// cmd/compile or gcexportdata.Write.
|
||||
func IImportShallow(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string, insert InsertType) (*types.Package, error) {
|
||||
const bundle = false
|
||||
pkgs, err := iimportCommon(fset, imports, data, bundle, path, insert)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pkgs[0], nil
|
||||
}
|
||||
|
||||
// InsertType is the type of a function that creates a types.TypeName
|
||||
// object for a named type and inserts it into the scope of the
|
||||
// specified Package.
|
||||
type InsertType = func(pkg *types.Package, name string)
|
||||
|
||||
// Current bundled export format version. Increase with each format change.
|
||||
// 0: initial implementation
|
||||
const bundleVersion = 0
|
||||
|
@ -36,15 +70,17 @@ const bundleVersion = 0
|
|||
// The package path of the top-level package will not be recorded,
|
||||
// so that calls to IImportData can override with a provided package path.
|
||||
func IExportData(out io.Writer, fset *token.FileSet, pkg *types.Package) error {
|
||||
return iexportCommon(out, fset, false, iexportVersion, []*types.Package{pkg})
|
||||
const bundle, shallow = false, false
|
||||
return iexportCommon(out, fset, bundle, shallow, iexportVersion, []*types.Package{pkg})
|
||||
}
|
||||
|
||||
// IExportBundle writes an indexed export bundle for pkgs to out.
|
||||
func IExportBundle(out io.Writer, fset *token.FileSet, pkgs []*types.Package) error {
|
||||
return iexportCommon(out, fset, true, iexportVersion, pkgs)
|
||||
const bundle, shallow = true, false
|
||||
return iexportCommon(out, fset, bundle, shallow, iexportVersion, pkgs)
|
||||
}
|
||||
|
||||
func iexportCommon(out io.Writer, fset *token.FileSet, bundle bool, version int, pkgs []*types.Package) (err error) {
|
||||
func iexportCommon(out io.Writer, fset *token.FileSet, bundle, shallow bool, version int, pkgs []*types.Package) (err error) {
|
||||
if !debug {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
|
@ -61,6 +97,7 @@ func iexportCommon(out io.Writer, fset *token.FileSet, bundle bool, version int,
|
|||
p := iexporter{
|
||||
fset: fset,
|
||||
version: version,
|
||||
shallow: shallow,
|
||||
allPkgs: map[*types.Package]bool{},
|
||||
stringIndex: map[string]uint64{},
|
||||
declIndex: map[types.Object]uint64{},
|
||||
|
@ -82,7 +119,7 @@ func iexportCommon(out io.Writer, fset *token.FileSet, bundle bool, version int,
|
|||
for _, pkg := range pkgs {
|
||||
scope := pkg.Scope()
|
||||
for _, name := range scope.Names() {
|
||||
if ast.IsExported(name) {
|
||||
if token.IsExported(name) {
|
||||
p.pushDecl(scope.Lookup(name))
|
||||
}
|
||||
}
|
||||
|
@ -205,7 +242,8 @@ type iexporter struct {
|
|||
out *bytes.Buffer
|
||||
version int
|
||||
|
||||
localpkg *types.Package
|
||||
shallow bool // don't put types from other packages in the index
|
||||
localpkg *types.Package // (nil in bundle mode)
|
||||
|
||||
// allPkgs tracks all packages that have been referenced by
|
||||
// the export data, so we can ensure to include them in the
|
||||
|
@ -256,6 +294,11 @@ func (p *iexporter) pushDecl(obj types.Object) {
|
|||
panic("cannot export package unsafe")
|
||||
}
|
||||
|
||||
// Shallow export data: don't index decls from other packages.
|
||||
if p.shallow && obj.Pkg() != p.localpkg {
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := p.declIndex[obj]; ok {
|
||||
return
|
||||
}
|
||||
|
@ -497,7 +540,7 @@ func (w *exportWriter) pkg(pkg *types.Package) {
|
|||
w.string(w.exportPath(pkg))
|
||||
}
|
||||
|
||||
func (w *exportWriter) qualifiedIdent(obj types.Object) {
|
||||
func (w *exportWriter) qualifiedType(obj *types.TypeName) {
|
||||
name := w.p.exportName(obj)
|
||||
|
||||
// Ensure any referenced declarations are written out too.
|
||||
|
@ -556,11 +599,11 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
|
|||
return
|
||||
}
|
||||
w.startType(definedType)
|
||||
w.qualifiedIdent(t.Obj())
|
||||
w.qualifiedType(t.Obj())
|
||||
|
||||
case *typeparams.TypeParam:
|
||||
w.startType(typeParamType)
|
||||
w.qualifiedIdent(t.Obj())
|
||||
w.qualifiedType(t.Obj())
|
||||
|
||||
case *types.Pointer:
|
||||
w.startType(pointerType)
|
||||
|
@ -602,14 +645,17 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
|
|||
|
||||
case *types.Struct:
|
||||
w.startType(structType)
|
||||
w.setPkg(pkg, true)
|
||||
|
||||
n := t.NumFields()
|
||||
if n > 0 {
|
||||
w.setPkg(t.Field(0).Pkg(), true) // qualifying package for field objects
|
||||
} else {
|
||||
w.setPkg(pkg, true)
|
||||
}
|
||||
w.uint64(uint64(n))
|
||||
for i := 0; i < n; i++ {
|
||||
f := t.Field(i)
|
||||
w.pos(f.Pos())
|
||||
w.string(f.Name())
|
||||
w.string(f.Name()) // unexported fields implicitly qualified by prior setPkg
|
||||
w.typ(f.Type(), pkg)
|
||||
w.bool(f.Anonymous())
|
||||
w.string(t.Tag(i)) // note (or tag)
|
|
@ -85,7 +85,7 @@ const (
|
|||
// If the export data version is not recognized or the format is otherwise
|
||||
// compromised, an error is returned.
|
||||
func IImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (int, *types.Package, error) {
|
||||
pkgs, err := iimportCommon(fset, imports, data, false, path)
|
||||
pkgs, err := iimportCommon(fset, imports, data, false, path, nil)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
@ -94,10 +94,10 @@ func IImportData(fset *token.FileSet, imports map[string]*types.Package, data []
|
|||
|
||||
// IImportBundle imports a set of packages from the serialized package bundle.
|
||||
func IImportBundle(fset *token.FileSet, imports map[string]*types.Package, data []byte) ([]*types.Package, error) {
|
||||
return iimportCommon(fset, imports, data, true, "")
|
||||
return iimportCommon(fset, imports, data, true, "", nil)
|
||||
}
|
||||
|
||||
func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data []byte, bundle bool, path string) (pkgs []*types.Package, err error) {
|
||||
func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data []byte, bundle bool, path string, insert InsertType) (pkgs []*types.Package, err error) {
|
||||
const currentVersion = iexportVersionCurrent
|
||||
version := int64(-1)
|
||||
if !debug {
|
||||
|
@ -147,6 +147,7 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data
|
|||
p := iimporter{
|
||||
version: int(version),
|
||||
ipath: path,
|
||||
insert: insert,
|
||||
|
||||
stringData: stringData,
|
||||
stringCache: make(map[uint64]string),
|
||||
|
@ -187,11 +188,18 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data
|
|||
} else if pkg.Name() != pkgName {
|
||||
errorf("conflicting names %s and %s for package %q", pkg.Name(), pkgName, path)
|
||||
}
|
||||
if i == 0 && !bundle {
|
||||
p.localpkg = pkg
|
||||
}
|
||||
|
||||
p.pkgCache[pkgPathOff] = pkg
|
||||
|
||||
// Read index for package.
|
||||
nameIndex := make(map[string]uint64)
|
||||
for nSyms := r.uint64(); nSyms > 0; nSyms-- {
|
||||
nSyms := r.uint64()
|
||||
// In shallow mode we don't expect an index for other packages.
|
||||
assert(nSyms == 0 || p.localpkg == pkg || p.insert == nil)
|
||||
for ; nSyms > 0; nSyms-- {
|
||||
name := p.stringAt(r.uint64())
|
||||
nameIndex[name] = r.uint64()
|
||||
}
|
||||
|
@ -267,6 +275,9 @@ type iimporter struct {
|
|||
version int
|
||||
ipath string
|
||||
|
||||
localpkg *types.Package
|
||||
insert func(pkg *types.Package, name string) // "shallow" mode only
|
||||
|
||||
stringData []byte
|
||||
stringCache map[uint64]string
|
||||
pkgCache map[uint64]*types.Package
|
||||
|
@ -310,6 +321,13 @@ func (p *iimporter) doDecl(pkg *types.Package, name string) {
|
|||
|
||||
off, ok := p.pkgIndex[pkg][name]
|
||||
if !ok {
|
||||
// In "shallow" mode, call back to the application to
|
||||
// find the object and insert it into the package scope.
|
||||
if p.insert != nil {
|
||||
assert(pkg != p.localpkg)
|
||||
p.insert(pkg, name) // "can't fail"
|
||||
return
|
||||
}
|
||||
errorf("%v.%v not in index", pkg, name)
|
||||
}
|
||||
|
|
@ -21,3 +21,17 @@ func additionalPredeclared() []types.Type {
|
|||
types.Universe.Lookup("any").Type(),
|
||||
}
|
||||
}
|
||||
|
||||
// See cmd/compile/internal/types.SplitVargenSuffix.
|
||||
func splitVargenSuffix(name string) (base, suffix string) {
|
||||
i := len(name)
|
||||
for i > 0 && name[i-1] >= '0' && name[i-1] <= '9' {
|
||||
i--
|
||||
}
|
||||
const dot = "·"
|
||||
if i >= len(dot) && name[i-len(dot):i] == dot {
|
||||
i -= len(dot)
|
||||
return name[:i], name[i:]
|
||||
}
|
||||
return name, ""
|
||||
}
|
|
@ -14,7 +14,7 @@ import (
|
|||
"go/types"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/internal/pkgbits"
|
||||
"golang.org/x/tools/internal/pkgbits"
|
||||
)
|
||||
|
||||
// A pkgReader holds the shared state for reading a unified IR package
|
||||
|
@ -158,6 +158,17 @@ func (pr *pkgReader) newReader(k pkgbits.RelocKind, idx pkgbits.Index, marker pk
|
|||
}
|
||||
}
|
||||
|
||||
func (pr *pkgReader) tempReader(k pkgbits.RelocKind, idx pkgbits.Index, marker pkgbits.SyncMarker) *reader {
|
||||
return &reader{
|
||||
Decoder: pr.TempDecoder(k, idx, marker),
|
||||
p: pr,
|
||||
}
|
||||
}
|
||||
|
||||
func (pr *pkgReader) retireReader(r *reader) {
|
||||
pr.RetireDecoder(&r.Decoder)
|
||||
}
|
||||
|
||||
// @@@ Positions
|
||||
|
||||
func (r *reader) pos() token.Pos {
|
||||
|
@ -182,14 +193,16 @@ func (pr *pkgReader) posBaseIdx(idx pkgbits.Index) string {
|
|||
return b
|
||||
}
|
||||
|
||||
r := pr.newReader(pkgbits.RelocPosBase, idx, pkgbits.SyncPosBase)
|
||||
var filename string
|
||||
{
|
||||
r := pr.tempReader(pkgbits.RelocPosBase, idx, pkgbits.SyncPosBase)
|
||||
|
||||
// Within types2, position bases have a lot more details (e.g.,
|
||||
// keeping track of where //line directives appeared exactly).
|
||||
//
|
||||
// For go/types, we just track the file name.
|
||||
|
||||
filename := r.String()
|
||||
filename = r.String()
|
||||
|
||||
if r.Bool() { // file base
|
||||
// Was: "b = token.NewTrimmedFileBase(filename, true)"
|
||||
|
@ -201,7 +214,8 @@ func (pr *pkgReader) posBaseIdx(idx pkgbits.Index) string {
|
|||
// Was: "b = token.NewLineBase(pos, filename, true, line, col)"
|
||||
_, _, _ = pos, line, col
|
||||
}
|
||||
|
||||
pr.retireReader(r)
|
||||
}
|
||||
b := filename
|
||||
pr.posBases[idx] = b
|
||||
return b
|
||||
|
@ -259,22 +273,22 @@ func (r *reader) doPkg() *types.Package {
|
|||
// packages rooted from pkgs.
|
||||
func flattenImports(pkgs []*types.Package) []*types.Package {
|
||||
var res []*types.Package
|
||||
|
||||
seen := make(map[*types.Package]bool)
|
||||
var add func(pkg *types.Package)
|
||||
add = func(pkg *types.Package) {
|
||||
if seen[pkg] {
|
||||
return
|
||||
}
|
||||
seen[pkg] = true
|
||||
res = append(res, pkg)
|
||||
for _, imp := range pkg.Imports() {
|
||||
add(imp)
|
||||
}
|
||||
}
|
||||
|
||||
seen := make(map[*types.Package]struct{})
|
||||
for _, pkg := range pkgs {
|
||||
add(pkg)
|
||||
if _, ok := seen[pkg]; ok {
|
||||
continue
|
||||
}
|
||||
seen[pkg] = struct{}{}
|
||||
res = append(res, pkg)
|
||||
|
||||
// pkg.Imports() is already flattened.
|
||||
for _, pkg := range pkg.Imports() {
|
||||
if _, ok := seen[pkg]; ok {
|
||||
continue
|
||||
}
|
||||
seen[pkg] = struct{}{}
|
||||
res = append(res, pkg)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
@ -307,12 +321,15 @@ func (pr *pkgReader) typIdx(info typeInfo, dict *readerDict) types.Type {
|
|||
return typ
|
||||
}
|
||||
|
||||
r := pr.newReader(pkgbits.RelocType, idx, pkgbits.SyncTypeIdx)
|
||||
var typ types.Type
|
||||
{
|
||||
r := pr.tempReader(pkgbits.RelocType, idx, pkgbits.SyncTypeIdx)
|
||||
r.dict = dict
|
||||
|
||||
typ := r.doTyp()
|
||||
typ = r.doTyp()
|
||||
assert(typ != nil)
|
||||
|
||||
pr.retireReader(r)
|
||||
}
|
||||
// See comment in pkgReader.typIdx explaining how this happens.
|
||||
if prev := *where; prev != nil {
|
||||
return prev
|
||||
|
@ -478,18 +495,30 @@ func (r *reader) obj() (types.Object, []types.Type) {
|
|||
}
|
||||
|
||||
func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
|
||||
rname := pr.newReader(pkgbits.RelocName, idx, pkgbits.SyncObject1)
|
||||
|
||||
objPkg, objName := rname.qualifiedIdent()
|
||||
var objPkg *types.Package
|
||||
var objName string
|
||||
var tag pkgbits.CodeObj
|
||||
{
|
||||
rname := pr.tempReader(pkgbits.RelocName, idx, pkgbits.SyncObject1)
|
||||
|
||||
objPkg, objName = rname.qualifiedIdent()
|
||||
assert(objName != "")
|
||||
|
||||
tag := pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj))
|
||||
tag = pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj))
|
||||
pr.retireReader(rname)
|
||||
}
|
||||
|
||||
if tag == pkgbits.ObjStub {
|
||||
assert(objPkg == nil || objPkg == types.Unsafe)
|
||||
return objPkg, objName
|
||||
}
|
||||
|
||||
// Ignore local types promoted to global scope (#55110).
|
||||
if _, suffix := splitVargenSuffix(objName); suffix != "" {
|
||||
return objPkg, objName
|
||||
}
|
||||
|
||||
if objPkg.Scope().Lookup(objName) == nil {
|
||||
dict := pr.objDictIdx(idx)
|
||||
|
||||
|
@ -583,10 +612,11 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
|
|||
}
|
||||
|
||||
func (pr *pkgReader) objDictIdx(idx pkgbits.Index) *readerDict {
|
||||
r := pr.newReader(pkgbits.RelocObjDict, idx, pkgbits.SyncObject1)
|
||||
|
||||
var dict readerDict
|
||||
|
||||
{
|
||||
r := pr.tempReader(pkgbits.RelocObjDict, idx, pkgbits.SyncObject1)
|
||||
if implicits := r.Len(); implicits != 0 {
|
||||
errorf("unexpected object with %v implicit type parameter(s)", implicits)
|
||||
}
|
||||
|
@ -602,6 +632,8 @@ func (pr *pkgReader) objDictIdx(idx pkgbits.Index) *readerDict {
|
|||
dict.derived[i] = derivedInfo{r.Reloc(pkgbits.RelocType), r.Bool()}
|
||||
}
|
||||
|
||||
pr.retireReader(r)
|
||||
}
|
||||
// function references follow, but reader doesn't need those
|
||||
|
||||
return &dict
|
|
@ -7,6 +7,7 @@ package gocommand
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -56,3 +57,23 @@ func GoVersion(ctx context.Context, inv Invocation, r *Runner) (int, error) {
|
|||
}
|
||||
return 0, fmt.Errorf("no parseable ReleaseTags in %v", tags)
|
||||
}
|
||||
|
||||
// GoVersionString reports the go version string as shown in `go version` command output.
|
||||
// When `go version` outputs in non-standard form, this returns an empty string.
|
||||
func GoVersionString(ctx context.Context, inv Invocation, r *Runner) (string, error) {
|
||||
inv.Verb = "version"
|
||||
goVersion, err := r.Run(ctx, inv)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return parseGoVersionOutput(goVersion.Bytes()), nil
|
||||
}
|
||||
|
||||
func parseGoVersionOutput(data []byte) string {
|
||||
re := regexp.MustCompile(`^go version (go\S+|devel \S+)`)
|
||||
m := re.FindSubmatch(data)
|
||||
if len(m) != 2 {
|
||||
return "" // unrecognized version
|
||||
}
|
||||
return string(m[1])
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ package pkgbits
|
|||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/constant"
|
||||
"go/token"
|
||||
|
@ -52,6 +53,8 @@ type PkgDecoder struct {
|
|||
// For example, section K's end positions start at elemEndsEnds[K-1]
|
||||
// (or 0, if K==0) and end at elemEndsEnds[K].
|
||||
elemEndsEnds [numRelocs]uint32
|
||||
|
||||
scratchRelocEnt []RelocEnt
|
||||
}
|
||||
|
||||
// PkgPath returns the package path for the package
|
||||
|
@ -165,6 +168,21 @@ func (pr *PkgDecoder) NewDecoder(k RelocKind, idx Index, marker SyncMarker) Deco
|
|||
return r
|
||||
}
|
||||
|
||||
// TempDecoder returns a Decoder for the given (section, index) pair,
|
||||
// and decodes the given SyncMarker from the element bitstream.
|
||||
// If possible the Decoder should be RetireDecoder'd when it is no longer
|
||||
// needed, this will avoid heap allocations.
|
||||
func (pr *PkgDecoder) TempDecoder(k RelocKind, idx Index, marker SyncMarker) Decoder {
|
||||
r := pr.TempDecoderRaw(k, idx)
|
||||
r.Sync(marker)
|
||||
return r
|
||||
}
|
||||
|
||||
func (pr *PkgDecoder) RetireDecoder(d *Decoder) {
|
||||
pr.scratchRelocEnt = d.Relocs
|
||||
d.Relocs = nil
|
||||
}
|
||||
|
||||
// NewDecoderRaw returns a Decoder for the given (section, index) pair.
|
||||
//
|
||||
// Most callers should use NewDecoder instead.
|
||||
|
@ -188,6 +206,30 @@ func (pr *PkgDecoder) NewDecoderRaw(k RelocKind, idx Index) Decoder {
|
|||
return r
|
||||
}
|
||||
|
||||
func (pr *PkgDecoder) TempDecoderRaw(k RelocKind, idx Index) Decoder {
|
||||
r := Decoder{
|
||||
common: pr,
|
||||
k: k,
|
||||
Idx: idx,
|
||||
}
|
||||
|
||||
r.Data.Reset(pr.DataIdx(k, idx))
|
||||
r.Sync(SyncRelocs)
|
||||
l := r.Len()
|
||||
if cap(pr.scratchRelocEnt) >= l {
|
||||
r.Relocs = pr.scratchRelocEnt[:l]
|
||||
pr.scratchRelocEnt = nil
|
||||
} else {
|
||||
r.Relocs = make([]RelocEnt, l)
|
||||
}
|
||||
for i := range r.Relocs {
|
||||
r.Sync(SyncReloc)
|
||||
r.Relocs[i] = RelocEnt{RelocKind(r.Len()), Index(r.Len())}
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// A Decoder provides methods for decoding an individual element's
|
||||
// bitstream data.
|
||||
type Decoder struct {
|
||||
|
@ -207,11 +249,39 @@ func (r *Decoder) checkErr(err error) {
|
|||
}
|
||||
|
||||
func (r *Decoder) rawUvarint() uint64 {
|
||||
x, err := binary.ReadUvarint(&r.Data)
|
||||
x, err := readUvarint(&r.Data)
|
||||
r.checkErr(err)
|
||||
return x
|
||||
}
|
||||
|
||||
// readUvarint is a type-specialized copy of encoding/binary.ReadUvarint.
|
||||
// This avoids the interface conversion and thus has better escape properties,
|
||||
// which flows up the stack.
|
||||
func readUvarint(r *strings.Reader) (uint64, error) {
|
||||
var x uint64
|
||||
var s uint
|
||||
for i := 0; i < binary.MaxVarintLen64; i++ {
|
||||
b, err := r.ReadByte()
|
||||
if err != nil {
|
||||
if i > 0 && err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
return x, err
|
||||
}
|
||||
if b < 0x80 {
|
||||
if i == binary.MaxVarintLen64-1 && b > 1 {
|
||||
return x, overflow
|
||||
}
|
||||
return x | uint64(b)<<s, nil
|
||||
}
|
||||
x |= uint64(b&0x7f) << s
|
||||
s += 7
|
||||
}
|
||||
return x, overflow
|
||||
}
|
||||
|
||||
var overflow = errors.New("pkgbits: readUvarint overflows a 64-bit integer")
|
||||
|
||||
func (r *Decoder) rawVarint() int64 {
|
||||
ux := r.rawUvarint()
|
||||
|
||||
|
@ -410,8 +480,12 @@ func (r *Decoder) bigFloat() *big.Float {
|
|||
// PeekPkgPath returns the package path for the specified package
|
||||
// index.
|
||||
func (pr *PkgDecoder) PeekPkgPath(idx Index) string {
|
||||
r := pr.NewDecoder(RelocPkg, idx, SyncPkgDef)
|
||||
path := r.String()
|
||||
var path string
|
||||
{
|
||||
r := pr.TempDecoder(RelocPkg, idx, SyncPkgDef)
|
||||
path = r.String()
|
||||
pr.RetireDecoder(&r)
|
||||
}
|
||||
if path == "" {
|
||||
path = pr.pkgPath
|
||||
}
|
||||
|
@ -421,14 +495,23 @@ func (pr *PkgDecoder) PeekPkgPath(idx Index) string {
|
|||
// PeekObj returns the package path, object name, and CodeObj for the
|
||||
// specified object index.
|
||||
func (pr *PkgDecoder) PeekObj(idx Index) (string, string, CodeObj) {
|
||||
r := pr.NewDecoder(RelocName, idx, SyncObject1)
|
||||
var ridx Index
|
||||
var name string
|
||||
var rcode int
|
||||
{
|
||||
r := pr.TempDecoder(RelocName, idx, SyncObject1)
|
||||
r.Sync(SyncSym)
|
||||
r.Sync(SyncPkg)
|
||||
path := pr.PeekPkgPath(r.Reloc(RelocPkg))
|
||||
name := r.String()
|
||||
ridx = r.Reloc(RelocPkg)
|
||||
name = r.String()
|
||||
rcode = r.Code(SyncCodeObj)
|
||||
pr.RetireDecoder(&r)
|
||||
}
|
||||
|
||||
path := pr.PeekPkgPath(ridx)
|
||||
assert(name != "")
|
||||
|
||||
tag := CodeObj(r.Code(SyncCodeObj))
|
||||
tag := CodeObj(rcode)
|
||||
|
||||
return path, name, tag
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue