mirror of
https://github.com/containers/podman.git
synced 2025-12-23 22:28:30 -05:00
Remove hardcoded refs from ociartifact code
Fixes: https://issues.redhat.com/browse/RUN-3578 Signed-off-by: Nicola Sella <nsella@redhat.com>
This commit is contained in:
41
go.mod
41
go.mod
@@ -20,7 +20,7 @@ require (
|
||||
github.com/containers/winquit v1.1.0
|
||||
github.com/coreos/go-systemd/v22 v22.6.0
|
||||
github.com/crc-org/vfkit v0.6.1
|
||||
github.com/cyphar/filepath-securejoin v0.5.1
|
||||
github.com/cyphar/filepath-securejoin v0.6.0
|
||||
github.com/digitalocean/go-qemu v0.0.0-20250212194115-ee9b0668d242
|
||||
github.com/docker/distribution v2.8.3+incompatible
|
||||
github.com/docker/docker v28.5.2+incompatible
|
||||
@@ -54,7 +54,7 @@ require (
|
||||
github.com/opencontainers/image-spec v1.1.1
|
||||
github.com/opencontainers/runtime-spec v1.2.1
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20250523060157-0ea5ed0382a2
|
||||
github.com/opencontainers/selinux v1.12.0
|
||||
github.com/opencontainers/selinux v1.13.0
|
||||
github.com/openshift/imagebuilder v1.2.19
|
||||
github.com/rootless-containers/rootlesskit/v2 v2.3.5
|
||||
github.com/shirou/gopsutil/v4 v4.25.10
|
||||
@@ -64,9 +64,9 @@ require (
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/vbauerster/mpb/v8 v8.11.2
|
||||
github.com/vishvananda/netlink v1.3.1
|
||||
go.podman.io/common v0.66.0
|
||||
go.podman.io/image/v5 v5.38.0
|
||||
go.podman.io/storage v1.61.0
|
||||
go.podman.io/common v0.66.1-0.20251112195944-4afce3558e66
|
||||
go.podman.io/image/v5 v5.38.1-0.20251112195944-4afce3558e66
|
||||
go.podman.io/storage v1.61.1-0.20251112195944-4afce3558e66
|
||||
golang.org/x/crypto v0.44.0
|
||||
golang.org/x/net v0.46.0
|
||||
golang.org/x/sync v0.18.0
|
||||
@@ -81,6 +81,7 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
cyphar.com/go-pathrs v0.2.1 // indirect
|
||||
dario.cat/mergo v1.0.2 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||
@@ -95,7 +96,7 @@ require (
|
||||
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/containerd/platforms v1.0.0-rc.1 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.17.0 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.18.1 // indirect
|
||||
github.com/containerd/typeurl/v2 v2.2.3 // indirect
|
||||
github.com/containernetworking/cni v1.3.0 // indirect
|
||||
github.com/containers/common v0.62.2 // indirect
|
||||
@@ -113,7 +114,7 @@ require (
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/fsouza/go-dockerclient v1.12.2 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.2 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
@@ -129,7 +130,7 @@ require (
|
||||
github.com/hashicorp/go-retryablehttp v0.7.8 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jinzhu/copier v0.4.0 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/klauspost/compress v1.18.1 // indirect
|
||||
github.com/kr/fs v0.1.0 // indirect
|
||||
github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect
|
||||
@@ -137,9 +138,11 @@ require (
|
||||
github.com/mattn/go-runewidth v0.0.19 // indirect
|
||||
github.com/mdlayher/socket v0.5.1 // indirect
|
||||
github.com/miekg/pkcs11 v1.1.1 // indirect
|
||||
github.com/mistifyio/go-zfs/v3 v3.1.0 // indirect
|
||||
github.com/mistifyio/go-zfs/v4 v4.0.0 // indirect
|
||||
github.com/moby/buildkit v0.25.1 // indirect
|
||||
github.com/moby/go-archive v0.1.0 // indirect
|
||||
github.com/moby/moby/api v1.52.0 // indirect
|
||||
github.com/moby/moby/client v0.1.0 // indirect
|
||||
github.com/moby/patternmatcher v0.6.0 // indirect
|
||||
github.com/moby/sys/mountinfo v0.7.2 // indirect
|
||||
github.com/moby/sys/sequential v0.6.0 // indirect
|
||||
@@ -149,7 +152,7 @@ require (
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/opencontainers/runc v1.3.3 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg/sftp v1.13.9 // indirect
|
||||
github.com/pkg/sftp v1.13.10 // indirect
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||
@@ -171,24 +174,24 @@ require (
|
||||
github.com/tklauser/numcpus v0.10.0 // indirect
|
||||
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect
|
||||
github.com/ulikunitz/xz v0.5.15 // indirect
|
||||
github.com/vbatts/tar-split v0.12.1 // indirect
|
||||
github.com/vbatts/tar-split v0.12.2 // indirect
|
||||
github.com/vishvananda/netns v0.0.5 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
go.etcd.io/bbolt v1.4.3 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
|
||||
go.opentelemetry.io/otel v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect
|
||||
go.opentelemetry.io/otel v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/mod v0.29.0 // indirect
|
||||
golang.org/x/oauth2 v0.32.0 // indirect
|
||||
golang.org/x/oauth2 v0.33.0 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/tools v0.38.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
tags.cncf.io/container-device-interface/specs-go v1.0.0 // indirect
|
||||
)
|
||||
|
||||
110
go.sum
110
go.sum
@@ -1,3 +1,5 @@
|
||||
cyphar.com/go-pathrs v0.2.1 h1:9nx1vOgwVvX1mNBWDu93+vaceedpbsDqo+XuBGL40b8=
|
||||
cyphar.com/go-pathrs v0.2.1/go.mod h1:y8f1EMG7r+hCuFf/rXsKqMJrJAUoADZGNh5/vZPKcGc=
|
||||
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
|
||||
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
|
||||
@@ -51,8 +53,8 @@ github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/containerd/platforms v1.0.0-rc.1 h1:83KIq4yy1erSRgOVHNk1HYdPvzdJ5CnsWaRoJX4C41E=
|
||||
github.com/containerd/platforms v1.0.0-rc.1/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.17.0 h1:+TyQIsR/zSFI1Rm31EQBwpAA1ovYgIKHy7kctL3sLcE=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.17.0/go.mod h1:s06tWAiJcXQo9/8AReBCIo/QxcXFZ2n4qfsRnpl71SM=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.18.1 h1:cy2/lpgBXDA3cDKSyEfNOFMA/c10O1axL69EU7iirO8=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.18.1/go.mod h1:ALIEqa7B6oVDsrF37GkGN20SuvG/pIMm7FwP7ZmRb0Q=
|
||||
github.com/containerd/typeurl/v2 v2.2.3 h1:yNA/94zxWdvYACdYO8zofhrTVuQY73fFU1y++dYSw40=
|
||||
github.com/containerd/typeurl/v2 v2.2.3/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsxGtUBhJxIn7SCk=
|
||||
github.com/containernetworking/cni v1.3.0 h1:v6EpN8RznAZj9765HhXQrtXgX+ECGebEYEmnuFjskwo=
|
||||
@@ -88,12 +90,12 @@ github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/crc-org/vfkit v0.6.1 h1:JepqPrgzKBuM/jximOcwA5ZnQPMcdarPRCrF4jHFau8=
|
||||
github.com/crc-org/vfkit v0.6.1/go.mod h1:M3UMhDHg4d9/KzcslwG4Zay8EUMe7Pv6vxG/++vJ//4=
|
||||
github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
|
||||
github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
|
||||
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
|
||||
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 h1:uX1JmpONuD549D73r6cgnxyUu18Zb7yHAy5AYU0Pm4Q=
|
||||
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw=
|
||||
github.com/cyphar/filepath-securejoin v0.5.1 h1:eYgfMq5yryL4fbWfkLpFFy2ukSELzaJOTaUTuh+oF48=
|
||||
github.com/cyphar/filepath-securejoin v0.5.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
||||
github.com/cyphar/filepath-securejoin v0.6.0 h1:BtGB77njd6SVO6VztOHfPxKitJvd/VPT+OFBFMOi1Is=
|
||||
github.com/cyphar/filepath-securejoin v0.6.0/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
@@ -106,8 +108,8 @@ github.com/disiqueira/gotree/v3 v3.0.2 h1:ik5iuLQQoufZBNPY518dXhiO5056hyNBIK9lWh
|
||||
github.com/disiqueira/gotree/v3 v3.0.2/go.mod h1:ZuyjE4+mUQZlbpkI24AmruZKhg3VHEgPLDY8Qk+uUu8=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/cli v28.5.1+incompatible h1:ESutzBALAD6qyCLqbQSEf1a/U8Ybms5agw59yGVc+yY=
|
||||
github.com/docker/cli v28.5.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli v29.0.0+incompatible h1:KgsN2RUFMNM8wChxryicn4p46BdQWpXOA1XLGBGPGAw=
|
||||
github.com/docker/cli v29.0.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=
|
||||
@@ -116,8 +118,6 @@ github.com/docker/docker-credential-helpers v0.9.4 h1:76ItO69/AP/V4yT9V4uuuItG0B
|
||||
github.com/docker/docker-credential-helpers v0.9.4/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
|
||||
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
|
||||
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
|
||||
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
|
||||
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
|
||||
github.com/docker/go-plugins-helpers v0.0.0-20240701071450-45e2431495c8 h1:IMfrF5LCzP2Vhw7j4IIH3HxPsCLuZYjDqFAM/C88ulg=
|
||||
github.com/docker/go-plugins-helpers v0.0.0-20240701071450-45e2431495c8/go.mod h1:LFyLie6XcDbyKGeVK6bHe+9aJTYCxWLBg5IrJZOaXKA=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
@@ -141,8 +141,8 @@ github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZ
|
||||
github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk=
|
||||
github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01KS3zGE=
|
||||
github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc=
|
||||
github.com/go-jose/go-jose/v4 v4.1.2 h1:TK/7NqRQZfgAh+Td8AlsrvtPoUyiHh0LqVvokh+1vHI=
|
||||
github.com/go-jose/go-jose/v4 v4.1.2/go.mod h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo=
|
||||
github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=
|
||||
github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
@@ -225,8 +225,8 @@ github.com/kevinburke/ssh_config v1.4.0 h1:6xxtP5bZ2E4NF5tuQulISpTO2z8XbtH8cg1PW
|
||||
github.com/kevinburke/ssh_config v1.4.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co=
|
||||
github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0=
|
||||
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
|
||||
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
||||
@@ -265,14 +265,18 @@ github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3v
|
||||
github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A=
|
||||
github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU=
|
||||
github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||
github.com/mistifyio/go-zfs/v3 v3.1.0 h1:FZaylcg0hjUp27i23VcJJQiuBeAZjrC8lPqCGM1CopY=
|
||||
github.com/mistifyio/go-zfs/v3 v3.1.0/go.mod h1:CzVgeB0RvF2EGzQnytKVvVSDwmKJXxkOTUGbNrTja/k=
|
||||
github.com/mistifyio/go-zfs/v4 v4.0.0 h1:sU0+5dX45tdDK5xNZ3HBi95nxUc48FS92qbIZEvpAg4=
|
||||
github.com/mistifyio/go-zfs/v4 v4.0.0/go.mod h1:weotFtXTHvBwhr9Mv96KYnDkTPBOHFUbm9cBmQpesL0=
|
||||
github.com/moby/buildkit v0.25.1 h1:j7IlVkeNbEo+ZLoxdudYCHpmTsbwKvhgc/6UJ/mY/o8=
|
||||
github.com/moby/buildkit v0.25.1/go.mod h1:phM8sdqnvgK2y1dPDnbwI6veUCXHOZ6KFSl6E164tkc=
|
||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
|
||||
github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo=
|
||||
github.com/moby/moby/api v1.52.0 h1:00BtlJY4MXkkt84WhUZPRqt5TvPbgig2FZvTbe3igYg=
|
||||
github.com/moby/moby/api v1.52.0/go.mod h1:8mb+ReTlisw4pS6BRzCMts5M49W5M7bKt1cJy/YbAqc=
|
||||
github.com/moby/moby/client v0.1.0 h1:nt+hn6O9cyJQqq5UWnFGqsZRTS/JirUqzPjEl0Bdc/8=
|
||||
github.com/moby/moby/client v0.1.0/go.mod h1:O+/tw5d4a1Ha/ZA/tPxIZJapJRUS6LNZ1wiVRxYHyUE=
|
||||
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
||||
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
|
||||
@@ -316,16 +320,16 @@ github.com/opencontainers/runtime-spec v1.2.1 h1:S4k4ryNgEpxW1dzyqffOmhI1BHYcjzU
|
||||
github.com/opencontainers/runtime-spec v1.2.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20250523060157-0ea5ed0382a2 h1:2xZEHOdeQBV6PW8ZtimN863bIOl7OCW/X10K0cnxKeA=
|
||||
github.com/opencontainers/runtime-tools v0.9.1-0.20250523060157-0ea5ed0382a2/go.mod h1:MXdPzqAA8pHC58USHqNCSjyLnRQ6D+NjbpP+02Z1U/0=
|
||||
github.com/opencontainers/selinux v1.12.0 h1:6n5JV4Cf+4y0KNXW48TLj5DwfXpvWlxXplUkdTrmPb8=
|
||||
github.com/opencontainers/selinux v1.12.0/go.mod h1:BTPX+bjVbWGXw7ZZWUbdENt8w0htPSrlgOOysQaU62U=
|
||||
github.com/opencontainers/selinux v1.13.0 h1:Zza88GWezyT7RLql12URvoxsbLfjFx988+LGaWfbL84=
|
||||
github.com/opencontainers/selinux v1.13.0/go.mod h1:XxWTed+A/s5NNq4GmYScVy+9jzXhGBVEOAyucdRUY8s=
|
||||
github.com/openshift/imagebuilder v1.2.19 h1:Xqq36KMJgsRU2MPaLRML23Myvk+AaY8pE8VJ6m6Vmy4=
|
||||
github.com/openshift/imagebuilder v1.2.19/go.mod h1:fdbnfQWjxMBoB/jrvEzUk+UT1zqvtZZj7oQ7GU6RD9I=
|
||||
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
||||
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.13.9 h1:4NGkvGudBL7GteO3m6qnaQ4pC0Kvf0onSVc9gR3EWBw=
|
||||
github.com/pkg/sftp v1.13.9/go.mod h1:OBN7bVXdstkFFN/gdnHPUb5TE8eb8G1Rp9wCItqjkkA=
|
||||
github.com/pkg/sftp v1.13.10 h1:+5FbKNTe5Z9aspU88DPIKJ9z2KZoaGCu6Sr6kKR/5mU=
|
||||
github.com/pkg/sftp v1.13.10/go.mod h1:bJ1a7uDhrX/4OII+agvy28lzRvQrmIQuaHrcI1HbeGA=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
@@ -343,8 +347,8 @@ github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA
|
||||
github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/rootless-containers/rootlesskit/v2 v2.3.5 h1:WGY05oHE7xQpSkCGfYP9lMY5z19tCxA8PhWlvP1cKx8=
|
||||
github.com/rootless-containers/rootlesskit/v2 v2.3.5/go.mod h1:83EIYLeMX8UeNgLHkR1PefoSV76aKEC+OyI3vzrEfvw=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
@@ -384,12 +388,9 @@ github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3A
|
||||
github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 h1:pnnLyeX7o/5aX8qUQ69P/mLojDqwda8hFOCBTmP/6hw=
|
||||
github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6/go.mod h1:39R/xuhNgVhi+K0/zst4TLrJrVmbm6LVgl4A0+ZFS5M=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/sylabs/sif/v2 v2.22.0 h1:Y+xXufp4RdgZe02SR3nWEg7S6q4tPWN237WHYzkDSKA=
|
||||
@@ -418,8 +419,8 @@ github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8
|
||||
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA=
|
||||
github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
|
||||
github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/vbatts/tar-split v0.12.1 h1:CqKoORW7BUWBe7UL/iqTVvkTBOF8UvOMKOIZykxnnbo=
|
||||
github.com/vbatts/tar-split v0.12.1/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA=
|
||||
github.com/vbatts/tar-split v0.12.2 h1:w/Y6tjxpeiFMR47yzZPlPj/FcPLpXbTUi/9H7d3CPa4=
|
||||
github.com/vbatts/tar-split v0.12.2/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA=
|
||||
github.com/vbauerster/mpb/v8 v8.11.2 h1:OqLoHznUVU7SKS/WV+1dB5/hm20YLheYupiHhL5+M1Y=
|
||||
github.com/vbauerster/mpb/v8 v8.11.2/go.mod h1:mEB/M353al1a7wMUNtiymmPsEkGlJgeJmtlbY5adCJ8=
|
||||
github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0=
|
||||
@@ -450,32 +451,32 @@ github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
|
||||
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=
|
||||
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
||||
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
|
||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
|
||||
go.podman.io/common v0.66.0 h1:KElE3HKLFdMdJL+jv5ExBiX2Dh4Qcv8ovmzaBGRsyZM=
|
||||
go.podman.io/common v0.66.0/go.mod h1:aNd2a0S7pY+fx1X5kpQYuF4hbwLU8ZOccuVrhu7h1Xc=
|
||||
go.podman.io/image/v5 v5.38.0 h1:aUKrCANkPvze1bnhLJsaubcfz0d9v/bSDLnwsXJm6G4=
|
||||
go.podman.io/image/v5 v5.38.0/go.mod h1:hSIoIUzgBnmc4DjoIdzk63aloqVbD7QXDMkSE/cvG90=
|
||||
go.podman.io/storage v1.61.0 h1:5hD/oyRYt1f1gxgvect+8syZBQhGhV28dCw2+CZpx0Q=
|
||||
go.podman.io/storage v1.61.0/go.mod h1:A3UBK0XypjNZ6pghRhuxg62+2NIm5lcUGv/7XyMhMUI=
|
||||
go.podman.io/common v0.66.1-0.20251112195944-4afce3558e66 h1:C0U9hTxFs0cG6dWb1u7/IFwv2O7NEMivyPnqh/k/9Z8=
|
||||
go.podman.io/common v0.66.1-0.20251112195944-4afce3558e66/go.mod h1:H5zW6J35uvTzKtELI3lf4aj1QLxFY5wry/o78adU7+Q=
|
||||
go.podman.io/image/v5 v5.38.1-0.20251112195944-4afce3558e66 h1:YOTQaRJjUfS+LKrw31G7pF2oY/ReOV6n0fVZez5f0Ic=
|
||||
go.podman.io/image/v5 v5.38.1-0.20251112195944-4afce3558e66/go.mod h1:ycRSRkCZDb+EOojdmG67HARjAojZ/ERUNbFuORg3KZU=
|
||||
go.podman.io/storage v1.61.1-0.20251112195944-4afce3558e66 h1:u9vVRYZwZgPY8a/yxKTI4C3uwZHMa5GjXZEDHIwe9P4=
|
||||
go.podman.io/storage v1.61.1-0.20251112195944-4afce3558e66/go.mod h1:inOm1g24NqCjTY6aPC11MMHtj8Asgi+3aOvKOPldnCI=
|
||||
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
|
||||
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
@@ -488,7 +489,6 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
|
||||
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
|
||||
@@ -517,8 +517,8 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
|
||||
golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo=
|
||||
golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -599,10 +599,10 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b h1:ULiyYQ0FdsJhwwZUwbaXpZF5yUE3h+RA+gxvBu37ucc=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:oDOGiMSXHL4sDTJvFvIB9nRQCGdLP1o/iVaqQK8zB+M=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b h1:zPKJod4w6F1+nRGDI9ubnXYhU9NSWoFAijkHkUXeTK8=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc=
|
||||
google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
|
||||
google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
@@ -619,6 +619,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
|
||||
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
||||
pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk=
|
||||
pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
|
||||
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
|
||||
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
|
||||
src.elv.sh v0.16.0-rc1.0.20220116211855-fda62502ad7f h1:pjVeIo9Ba6K1Wy+rlwX91zT7A+xGEmxiNRBdN04gDTQ=
|
||||
|
||||
@@ -258,7 +258,7 @@ type ContainerNetworkConfig struct {
|
||||
// namespace. As of podman 4.0 this field is deprecated, use PortMappings
|
||||
// instead. The db will convert the old ports to the new structure for you.
|
||||
// These are not used unless CreateNetNS is true
|
||||
OldPortMappings []types.OCICNIPortMapping `json:"portMappings,omitempty"`
|
||||
OldPortMappings []types.OCICNIPortMapping `json:"portMappings,omitempty"` //nolint:staticcheck
|
||||
// ExposedPorts are the ports which are exposed but not forwarded
|
||||
// into the container.
|
||||
// The map key is the port and the string slice contains the protocols,
|
||||
|
||||
@@ -25,7 +25,7 @@ func pullOCITestDisk(finalDir string, vmType define.VMType) error {
|
||||
dirs := define.MachineDirs{ImageCacheDir: imageCacheDir}
|
||||
|
||||
var skipTlsVerify types.OptionalBool
|
||||
ociArtPull, err := ocipull.NewOCIArtifactPull(context.Background(), &dirs, "", "e2emachine", vmType, unusedFinalPath, skipTlsVerify)
|
||||
ociArtPull, err := ocipull.NewOCIArtifactPull(context.Background(), &dirs, "docker://quay.io/podman/machine-os", "e2emachine", vmType, unusedFinalPath, skipTlsVerify)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -24,9 +24,6 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
artifactRegistry = "quay.io"
|
||||
artifactRepo = "podman"
|
||||
artifactImageName = "machine-os"
|
||||
artifactOriginalName = specV1.AnnotationTitle
|
||||
machineOS = "linux"
|
||||
)
|
||||
@@ -92,9 +89,25 @@ func NewOCIArtifactPull(ctx context.Context, dirs *define.MachineDirs, endpoint
|
||||
|
||||
cache := false
|
||||
if endpoint == "" {
|
||||
imageName := artifactImageName
|
||||
endpoint = fmt.Sprintf("docker://%s/%s/%s:%s", artifactRegistry, artifactRepo, imageName, artifactVersion.majorMinor())
|
||||
cache = true
|
||||
return nil, fmt.Errorf("no machine image endpoint provided")
|
||||
}
|
||||
|
||||
// Automatically append the current version as a tag if endpoint has no tag.
|
||||
// This allows endpoints in containers.conf to be version-agnostic: they won't need to be
|
||||
// updated on each version bump, while still pulling the correct version-specific image.
|
||||
if image, ok := strings.CutPrefix(endpoint, "docker://"); ok {
|
||||
ref, err := reference.ParseNormalizedNamed(image)
|
||||
if err == nil {
|
||||
// Only add version tag if no tag is specified (digest-only refs are left alone)
|
||||
if _, hasTag := ref.(reference.Tagged); !hasTag {
|
||||
taggedRef, err := reference.WithTag(ref, artifactVersion.majorMinor())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to add version tag to %q: %w", endpoint, err)
|
||||
}
|
||||
endpoint = "docker://" + taggedRef.String()
|
||||
}
|
||||
}
|
||||
// If parsing failed, just continue with the original endpoint
|
||||
}
|
||||
|
||||
ociDisk := OCIArtifactDisk{
|
||||
|
||||
43
vendor/cyphar.com/go-pathrs/.golangci.yml
generated
vendored
Normal file
43
vendor/cyphar.com/go-pathrs/.golangci.yml
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# libpathrs: safe path resolution on Linux
|
||||
# Copyright (C) 2019-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||
# Copyright (C) 2019-2025 SUSE LLC
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
version: "2"
|
||||
linters:
|
||||
enable:
|
||||
- bidichk
|
||||
- cyclop
|
||||
- errname
|
||||
- errorlint
|
||||
- exhaustive
|
||||
- goconst
|
||||
- godot
|
||||
- gomoddirectives
|
||||
- gosec
|
||||
- mirror
|
||||
- misspell
|
||||
- mnd
|
||||
- nilerr
|
||||
- nilnil
|
||||
- perfsprint
|
||||
- prealloc
|
||||
- reassign
|
||||
- revive
|
||||
- unconvert
|
||||
- unparam
|
||||
- usestdlibvars
|
||||
- wastedassign
|
||||
formatters:
|
||||
enable:
|
||||
- gofumpt
|
||||
- goimports
|
||||
settings:
|
||||
goimports:
|
||||
local-prefixes:
|
||||
- cyphar.com/go-pathrs
|
||||
373
vendor/cyphar.com/go-pathrs/COPYING
generated
vendored
Normal file
373
vendor/cyphar.com/go-pathrs/COPYING
generated
vendored
Normal file
@@ -0,0 +1,373 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
14
vendor/cyphar.com/go-pathrs/doc.go
generated
vendored
Normal file
14
vendor/cyphar.com/go-pathrs/doc.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
/*
|
||||
* libpathrs: safe path resolution on Linux
|
||||
* Copyright (C) 2019-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||
* Copyright (C) 2019-2025 SUSE LLC
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
// Package pathrs provides bindings for libpathrs, a library for safe path
|
||||
// resolution on Linux.
|
||||
package pathrs
|
||||
114
vendor/cyphar.com/go-pathrs/handle_linux.go
generated
vendored
Normal file
114
vendor/cyphar.com/go-pathrs/handle_linux.go
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
//go:build linux
|
||||
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
/*
|
||||
* libpathrs: safe path resolution on Linux
|
||||
* Copyright (C) 2019-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||
* Copyright (C) 2019-2025 SUSE LLC
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package pathrs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"cyphar.com/go-pathrs/internal/fdutils"
|
||||
"cyphar.com/go-pathrs/internal/libpathrs"
|
||||
)
|
||||
|
||||
// Handle is a handle for a path within a given [Root]. This handle references
|
||||
// an already-resolved path which can be used for only one purpose -- to
|
||||
// "re-open" the handle and get an actual [os.File] which can be used for
|
||||
// ordinary operations.
|
||||
//
|
||||
// If you wish to open a file without having an intermediate [Handle] object,
|
||||
// you can try to use [Root.Open] or [Root.OpenFile].
|
||||
//
|
||||
// It is critical that perform all relevant operations through this [Handle]
|
||||
// (rather than fetching the file descriptor yourself with [Handle.IntoRaw]),
|
||||
// because the security properties of libpathrs depend on users doing all
|
||||
// relevant filesystem operations through libpathrs.
|
||||
//
|
||||
// [os.File]: https://pkg.go.dev/os#File
|
||||
type Handle struct {
|
||||
inner *os.File
|
||||
}
|
||||
|
||||
// HandleFromFile creates a new [Handle] from an existing file handle. The
|
||||
// handle will be copied by this method, so the original handle should still be
|
||||
// freed by the caller.
|
||||
//
|
||||
// This is effectively the inverse operation of [Handle.IntoRaw], and is used
|
||||
// for "deserialising" pathrs root handles.
|
||||
func HandleFromFile(file *os.File) (*Handle, error) {
|
||||
newFile, err := fdutils.DupFile(file)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("duplicate handle fd: %w", err)
|
||||
}
|
||||
return &Handle{inner: newFile}, nil
|
||||
}
|
||||
|
||||
// Open creates an "upgraded" file handle to the file referenced by the
|
||||
// [Handle]. Note that the original [Handle] is not consumed by this operation,
|
||||
// and can be opened multiple times.
|
||||
//
|
||||
// The handle returned is only usable for reading, and this is method is
|
||||
// shorthand for [Handle.OpenFile] with os.O_RDONLY.
|
||||
//
|
||||
// TODO: Rename these to "Reopen" or something.
|
||||
func (h *Handle) Open() (*os.File, error) {
|
||||
return h.OpenFile(os.O_RDONLY)
|
||||
}
|
||||
|
||||
// OpenFile creates an "upgraded" file handle to the file referenced by the
|
||||
// [Handle]. Note that the original [Handle] is not consumed by this operation,
|
||||
// and can be opened multiple times.
|
||||
//
|
||||
// The provided flags indicate which open(2) flags are used to create the new
|
||||
// handle.
|
||||
//
|
||||
// TODO: Rename these to "Reopen" or something.
|
||||
func (h *Handle) OpenFile(flags int) (*os.File, error) {
|
||||
return fdutils.WithFileFd(h.inner, func(fd uintptr) (*os.File, error) {
|
||||
newFd, err := libpathrs.Reopen(fd, flags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return os.NewFile(newFd, h.inner.Name()), nil
|
||||
})
|
||||
}
|
||||
|
||||
// IntoFile unwraps the [Handle] into its underlying [os.File].
|
||||
//
|
||||
// You almost certainly want to use [Handle.OpenFile] to get a non-O_PATH
|
||||
// version of this [Handle].
|
||||
//
|
||||
// This operation returns the internal [os.File] of the [Handle] directly, so
|
||||
// calling [Handle.Close] will also close any copies of the returned [os.File].
|
||||
// If you want to get an independent copy, use [Handle.Clone] followed by
|
||||
// [Handle.IntoFile] on the cloned [Handle].
|
||||
//
|
||||
// [os.File]: https://pkg.go.dev/os#File
|
||||
func (h *Handle) IntoFile() *os.File {
|
||||
// TODO: Figure out if we really don't want to make a copy.
|
||||
// TODO: We almost certainly want to clear r.inner here, but we can't do
|
||||
// that easily atomically (we could use atomic.Value but that'll make
|
||||
// things quite a bit uglier).
|
||||
return h.inner
|
||||
}
|
||||
|
||||
// Clone creates a copy of a [Handle], such that it has a separate lifetime to
|
||||
// the original (while referring to the same underlying file).
|
||||
func (h *Handle) Clone() (*Handle, error) {
|
||||
return HandleFromFile(h.inner)
|
||||
}
|
||||
|
||||
// Close frees all of the resources used by the [Handle].
|
||||
func (h *Handle) Close() error {
|
||||
return h.inner.Close()
|
||||
}
|
||||
75
vendor/cyphar.com/go-pathrs/internal/fdutils/fd_linux.go
generated
vendored
Normal file
75
vendor/cyphar.com/go-pathrs/internal/fdutils/fd_linux.go
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
//go:build linux
|
||||
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
/*
|
||||
* libpathrs: safe path resolution on Linux
|
||||
* Copyright (C) 2019-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||
* Copyright (C) 2019-2025 SUSE LLC
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
// Package fdutils contains a few helper methods when dealing with *os.File and
|
||||
// file descriptors.
|
||||
package fdutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"cyphar.com/go-pathrs/internal/libpathrs"
|
||||
)
|
||||
|
||||
// DupFd makes a duplicate of the given fd.
|
||||
func DupFd(fd uintptr, name string) (*os.File, error) {
|
||||
newFd, err := unix.FcntlInt(fd, unix.F_DUPFD_CLOEXEC, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fcntl(F_DUPFD_CLOEXEC): %w", err)
|
||||
}
|
||||
return os.NewFile(uintptr(newFd), name), nil
|
||||
}
|
||||
|
||||
// WithFileFd is a more ergonomic wrapper around file.SyscallConn().Control().
|
||||
func WithFileFd[T any](file *os.File, fn func(fd uintptr) (T, error)) (T, error) {
|
||||
conn, err := file.SyscallConn()
|
||||
if err != nil {
|
||||
return *new(T), err
|
||||
}
|
||||
var (
|
||||
ret T
|
||||
innerErr error
|
||||
)
|
||||
if err := conn.Control(func(fd uintptr) {
|
||||
ret, innerErr = fn(fd)
|
||||
}); err != nil {
|
||||
return *new(T), err
|
||||
}
|
||||
return ret, innerErr
|
||||
}
|
||||
|
||||
// DupFile makes a duplicate of the given file.
|
||||
func DupFile(file *os.File) (*os.File, error) {
|
||||
return WithFileFd(file, func(fd uintptr) (*os.File, error) {
|
||||
return DupFd(fd, file.Name())
|
||||
})
|
||||
}
|
||||
|
||||
// MkFile creates a new *os.File from the provided file descriptor. However,
|
||||
// unlike os.NewFile, the file's Name is based on the real path (provided by
|
||||
// /proc/self/fd/$n).
|
||||
func MkFile(fd uintptr) (*os.File, error) {
|
||||
fdPath := fmt.Sprintf("fd/%d", fd)
|
||||
fdName, err := libpathrs.ProcReadlinkat(libpathrs.ProcDefaultRootFd, libpathrs.ProcThreadSelf, fdPath)
|
||||
if err != nil {
|
||||
_ = unix.Close(int(fd))
|
||||
return nil, fmt.Errorf("failed to fetch real name of fd %d: %w", fd, err)
|
||||
}
|
||||
// TODO: Maybe we should prefix this name with something to indicate to
|
||||
// users that they must not use this path as a "safe" path. Something like
|
||||
// "//pathrs-handle:/foo/bar"?
|
||||
return os.NewFile(fd, fdName), nil
|
||||
}
|
||||
40
vendor/cyphar.com/go-pathrs/internal/libpathrs/error_unix.go
generated
vendored
Normal file
40
vendor/cyphar.com/go-pathrs/internal/libpathrs/error_unix.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
//go:build linux
|
||||
|
||||
// TODO: Use "go:build unix" once we bump the minimum Go version 1.19.
|
||||
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
/*
|
||||
* libpathrs: safe path resolution on Linux
|
||||
* Copyright (C) 2019-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||
* Copyright (C) 2019-2025 SUSE LLC
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package libpathrs
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Error represents an underlying libpathrs error.
|
||||
type Error struct {
|
||||
description string
|
||||
errno syscall.Errno
|
||||
}
|
||||
|
||||
// Error returns a textual description of the error.
|
||||
func (err *Error) Error() string {
|
||||
return err.description
|
||||
}
|
||||
|
||||
// Unwrap returns the underlying error which was wrapped by this error (if
|
||||
// applicable).
|
||||
func (err *Error) Unwrap() error {
|
||||
if err.errno != 0 {
|
||||
return err.errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
337
vendor/cyphar.com/go-pathrs/internal/libpathrs/libpathrs_linux.go
generated
vendored
Normal file
337
vendor/cyphar.com/go-pathrs/internal/libpathrs/libpathrs_linux.go
generated
vendored
Normal file
@@ -0,0 +1,337 @@
|
||||
//go:build linux
|
||||
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
/*
|
||||
* libpathrs: safe path resolution on Linux
|
||||
* Copyright (C) 2019-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||
* Copyright (C) 2019-2025 SUSE LLC
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
// Package libpathrs is an internal thin wrapper around the libpathrs C API.
|
||||
package libpathrs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
/*
|
||||
// TODO: Figure out if we need to add support for linking against libpathrs
|
||||
// statically even if in dynamically linked builds in order to make
|
||||
// packaging a bit easier (using "-Wl,-Bstatic -lpathrs -Wl,-Bdynamic" or
|
||||
// "-l:pathrs.a").
|
||||
#cgo pkg-config: pathrs
|
||||
#include <pathrs.h>
|
||||
|
||||
// This is a workaround for unsafe.Pointer() not working for non-void pointers.
|
||||
char *cast_ptr(void *ptr) { return ptr; }
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func fetchError(errID C.int) error {
|
||||
if errID >= C.__PATHRS_MAX_ERR_VALUE {
|
||||
return nil
|
||||
}
|
||||
cErr := C.pathrs_errorinfo(errID)
|
||||
defer C.pathrs_errorinfo_free(cErr)
|
||||
|
||||
var err error
|
||||
if cErr != nil {
|
||||
err = &Error{
|
||||
errno: syscall.Errno(cErr.saved_errno),
|
||||
description: C.GoString(cErr.description),
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// OpenRoot wraps pathrs_open_root.
|
||||
func OpenRoot(path string) (uintptr, error) {
|
||||
cPath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
|
||||
fd := C.pathrs_open_root(cPath)
|
||||
return uintptr(fd), fetchError(fd)
|
||||
}
|
||||
|
||||
// Reopen wraps pathrs_reopen.
|
||||
func Reopen(fd uintptr, flags int) (uintptr, error) {
|
||||
newFd := C.pathrs_reopen(C.int(fd), C.int(flags))
|
||||
return uintptr(newFd), fetchError(newFd)
|
||||
}
|
||||
|
||||
// InRootResolve wraps pathrs_inroot_resolve.
|
||||
func InRootResolve(rootFd uintptr, path string) (uintptr, error) {
|
||||
cPath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
|
||||
fd := C.pathrs_inroot_resolve(C.int(rootFd), cPath)
|
||||
return uintptr(fd), fetchError(fd)
|
||||
}
|
||||
|
||||
// InRootResolveNoFollow wraps pathrs_inroot_resolve_nofollow.
|
||||
func InRootResolveNoFollow(rootFd uintptr, path string) (uintptr, error) {
|
||||
cPath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
|
||||
fd := C.pathrs_inroot_resolve_nofollow(C.int(rootFd), cPath)
|
||||
return uintptr(fd), fetchError(fd)
|
||||
}
|
||||
|
||||
// InRootOpen wraps pathrs_inroot_open.
|
||||
func InRootOpen(rootFd uintptr, path string, flags int) (uintptr, error) {
|
||||
cPath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
|
||||
fd := C.pathrs_inroot_open(C.int(rootFd), cPath, C.int(flags))
|
||||
return uintptr(fd), fetchError(fd)
|
||||
}
|
||||
|
||||
// InRootReadlink wraps pathrs_inroot_readlink.
|
||||
func InRootReadlink(rootFd uintptr, path string) (string, error) {
|
||||
cPath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
|
||||
size := 128
|
||||
for {
|
||||
linkBuf := make([]byte, size)
|
||||
n := C.pathrs_inroot_readlink(C.int(rootFd), cPath, C.cast_ptr(unsafe.Pointer(&linkBuf[0])), C.ulong(len(linkBuf)))
|
||||
switch {
|
||||
case int(n) < C.__PATHRS_MAX_ERR_VALUE:
|
||||
return "", fetchError(n)
|
||||
case int(n) <= len(linkBuf):
|
||||
return string(linkBuf[:int(n)]), nil
|
||||
default:
|
||||
// The contents were truncated. Unlike readlinkat, pathrs returns
|
||||
// the size of the link when it checked. So use the returned size
|
||||
// as a basis for the reallocated size (but in order to avoid a DoS
|
||||
// where a magic-link is growing by a single byte each iteration,
|
||||
// make sure we are a fair bit larger).
|
||||
size += int(n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// InRootRmdir wraps pathrs_inroot_rmdir.
|
||||
func InRootRmdir(rootFd uintptr, path string) error {
|
||||
cPath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
|
||||
err := C.pathrs_inroot_rmdir(C.int(rootFd), cPath)
|
||||
return fetchError(err)
|
||||
}
|
||||
|
||||
// InRootUnlink wraps pathrs_inroot_unlink.
|
||||
func InRootUnlink(rootFd uintptr, path string) error {
|
||||
cPath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
|
||||
err := C.pathrs_inroot_unlink(C.int(rootFd), cPath)
|
||||
return fetchError(err)
|
||||
}
|
||||
|
||||
// InRootRemoveAll wraps pathrs_inroot_remove_all.
|
||||
func InRootRemoveAll(rootFd uintptr, path string) error {
|
||||
cPath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
|
||||
err := C.pathrs_inroot_remove_all(C.int(rootFd), cPath)
|
||||
return fetchError(err)
|
||||
}
|
||||
|
||||
// InRootCreat wraps pathrs_inroot_creat.
|
||||
func InRootCreat(rootFd uintptr, path string, flags int, mode uint32) (uintptr, error) {
|
||||
cPath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
|
||||
fd := C.pathrs_inroot_creat(C.int(rootFd), cPath, C.int(flags), C.uint(mode))
|
||||
return uintptr(fd), fetchError(fd)
|
||||
}
|
||||
|
||||
// InRootRename wraps pathrs_inroot_rename.
|
||||
func InRootRename(rootFd uintptr, src, dst string, flags uint) error {
|
||||
cSrc := C.CString(src)
|
||||
defer C.free(unsafe.Pointer(cSrc))
|
||||
|
||||
cDst := C.CString(dst)
|
||||
defer C.free(unsafe.Pointer(cDst))
|
||||
|
||||
err := C.pathrs_inroot_rename(C.int(rootFd), cSrc, cDst, C.uint(flags))
|
||||
return fetchError(err)
|
||||
}
|
||||
|
||||
// InRootMkdir wraps pathrs_inroot_mkdir.
|
||||
func InRootMkdir(rootFd uintptr, path string, mode uint32) error {
|
||||
cPath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
|
||||
err := C.pathrs_inroot_mkdir(C.int(rootFd), cPath, C.uint(mode))
|
||||
return fetchError(err)
|
||||
}
|
||||
|
||||
// InRootMkdirAll wraps pathrs_inroot_mkdir_all.
|
||||
func InRootMkdirAll(rootFd uintptr, path string, mode uint32) (uintptr, error) {
|
||||
cPath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
|
||||
fd := C.pathrs_inroot_mkdir_all(C.int(rootFd), cPath, C.uint(mode))
|
||||
return uintptr(fd), fetchError(fd)
|
||||
}
|
||||
|
||||
// InRootMknod wraps pathrs_inroot_mknod.
|
||||
func InRootMknod(rootFd uintptr, path string, mode uint32, dev uint64) error {
|
||||
cPath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
|
||||
err := C.pathrs_inroot_mknod(C.int(rootFd), cPath, C.uint(mode), C.dev_t(dev))
|
||||
return fetchError(err)
|
||||
}
|
||||
|
||||
// InRootSymlink wraps pathrs_inroot_symlink.
|
||||
func InRootSymlink(rootFd uintptr, path, target string) error {
|
||||
cPath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
|
||||
cTarget := C.CString(target)
|
||||
defer C.free(unsafe.Pointer(cTarget))
|
||||
|
||||
err := C.pathrs_inroot_symlink(C.int(rootFd), cPath, cTarget)
|
||||
return fetchError(err)
|
||||
}
|
||||
|
||||
// InRootHardlink wraps pathrs_inroot_hardlink.
|
||||
func InRootHardlink(rootFd uintptr, path, target string) error {
|
||||
cPath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
|
||||
cTarget := C.CString(target)
|
||||
defer C.free(unsafe.Pointer(cTarget))
|
||||
|
||||
err := C.pathrs_inroot_hardlink(C.int(rootFd), cPath, cTarget)
|
||||
return fetchError(err)
|
||||
}
|
||||
|
||||
// ProcBase is pathrs_proc_base_t (uint64_t).
|
||||
type ProcBase C.pathrs_proc_base_t
|
||||
|
||||
// FIXME: We need to open-code the constants because CGo unfortunately will
|
||||
// implicitly convert any non-literal constants (i.e. those resolved using gcc)
|
||||
// to signed integers. See <https://github.com/golang/go/issues/39136> for some
|
||||
// more information on the underlying issue (though.
|
||||
const (
|
||||
// ProcRoot is PATHRS_PROC_ROOT.
|
||||
ProcRoot ProcBase = 0xFFFF_FFFE_7072_6F63 // C.PATHRS_PROC_ROOT
|
||||
// ProcSelf is PATHRS_PROC_SELF.
|
||||
ProcSelf ProcBase = 0xFFFF_FFFE_091D_5E1F // C.PATHRS_PROC_SELF
|
||||
// ProcThreadSelf is PATHRS_PROC_THREAD_SELF.
|
||||
ProcThreadSelf ProcBase = 0xFFFF_FFFE_3EAD_5E1F // C.PATHRS_PROC_THREAD_SELF
|
||||
|
||||
// ProcBaseTypeMask is __PATHRS_PROC_TYPE_MASK.
|
||||
ProcBaseTypeMask ProcBase = 0xFFFF_FFFF_0000_0000 // C.__PATHRS_PROC_TYPE_MASK
|
||||
// ProcBaseTypePid is __PATHRS_PROC_TYPE_PID.
|
||||
ProcBaseTypePid ProcBase = 0x8000_0000_0000_0000 // C.__PATHRS_PROC_TYPE_PID
|
||||
|
||||
// ProcDefaultRootFd is PATHRS_PROC_DEFAULT_ROOTFD.
|
||||
ProcDefaultRootFd = -int(syscall.EBADF) // C.PATHRS_PROC_DEFAULT_ROOTFD
|
||||
)
|
||||
|
||||
func assertEqual[T comparable](a, b T, msg string) {
|
||||
if a != b {
|
||||
panic(fmt.Sprintf("%s ((%T) %#v != (%T) %#v)", msg, a, a, b, b))
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that the values above match the actual C values. Unfortunately, Go
|
||||
// only allows us to forcefully cast int64 to uint64 if you use a temporary
|
||||
// variable, which means we cannot do it in a const context and thus need to do
|
||||
// it at runtime (even though it is a check that fundamentally could be done at
|
||||
// compile-time)...
|
||||
func init() {
|
||||
var (
|
||||
actualProcRoot int64 = C.PATHRS_PROC_ROOT
|
||||
actualProcSelf int64 = C.PATHRS_PROC_SELF
|
||||
actualProcThreadSelf int64 = C.PATHRS_PROC_THREAD_SELF
|
||||
)
|
||||
|
||||
assertEqual(ProcRoot, ProcBase(actualProcRoot), "PATHRS_PROC_ROOT")
|
||||
assertEqual(ProcSelf, ProcBase(actualProcSelf), "PATHRS_PROC_SELF")
|
||||
assertEqual(ProcThreadSelf, ProcBase(actualProcThreadSelf), "PATHRS_PROC_THREAD_SELF")
|
||||
|
||||
var (
|
||||
actualProcBaseTypeMask uint64 = C.__PATHRS_PROC_TYPE_MASK
|
||||
actualProcBaseTypePid uint64 = C.__PATHRS_PROC_TYPE_PID
|
||||
)
|
||||
|
||||
assertEqual(ProcBaseTypeMask, ProcBase(actualProcBaseTypeMask), "__PATHRS_PROC_TYPE_MASK")
|
||||
assertEqual(ProcBaseTypePid, ProcBase(actualProcBaseTypePid), "__PATHRS_PROC_TYPE_PID")
|
||||
|
||||
assertEqual(ProcDefaultRootFd, int(C.PATHRS_PROC_DEFAULT_ROOTFD), "PATHRS_PROC_DEFAULT_ROOTFD")
|
||||
}
|
||||
|
||||
// ProcPid reimplements the PROC_PID(x) conversion.
|
||||
func ProcPid(pid uint32) ProcBase { return ProcBaseTypePid | ProcBase(pid) }
|
||||
|
||||
// ProcOpenat wraps pathrs_proc_openat.
|
||||
func ProcOpenat(procRootFd int, base ProcBase, path string, flags int) (uintptr, error) {
|
||||
cBase := C.pathrs_proc_base_t(base)
|
||||
|
||||
cPath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
|
||||
fd := C.pathrs_proc_openat(C.int(procRootFd), cBase, cPath, C.int(flags))
|
||||
return uintptr(fd), fetchError(fd)
|
||||
}
|
||||
|
||||
// ProcReadlinkat wraps pathrs_proc_readlinkat.
|
||||
func ProcReadlinkat(procRootFd int, base ProcBase, path string) (string, error) {
|
||||
// TODO: See if we can unify this code with InRootReadlink.
|
||||
|
||||
cBase := C.pathrs_proc_base_t(base)
|
||||
|
||||
cPath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
|
||||
size := 128
|
||||
for {
|
||||
linkBuf := make([]byte, size)
|
||||
n := C.pathrs_proc_readlinkat(
|
||||
C.int(procRootFd), cBase, cPath,
|
||||
C.cast_ptr(unsafe.Pointer(&linkBuf[0])), C.ulong(len(linkBuf)))
|
||||
switch {
|
||||
case int(n) < C.__PATHRS_MAX_ERR_VALUE:
|
||||
return "", fetchError(n)
|
||||
case int(n) <= len(linkBuf):
|
||||
return string(linkBuf[:int(n)]), nil
|
||||
default:
|
||||
// The contents were truncated. Unlike readlinkat, pathrs returns
|
||||
// the size of the link when it checked. So use the returned size
|
||||
// as a basis for the reallocated size (but in order to avoid a DoS
|
||||
// where a magic-link is growing by a single byte each iteration,
|
||||
// make sure we are a fair bit larger).
|
||||
size += int(n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ProcfsOpenHow is pathrs_procfs_open_how (struct).
|
||||
type ProcfsOpenHow C.pathrs_procfs_open_how
|
||||
|
||||
const (
|
||||
// ProcfsNewUnmasked is PATHRS_PROCFS_NEW_UNMASKED.
|
||||
ProcfsNewUnmasked = C.PATHRS_PROCFS_NEW_UNMASKED
|
||||
)
|
||||
|
||||
// Flags returns a pointer to the internal flags field to allow other packages
|
||||
// to modify structure fields that are internal due to Go's visibility model.
|
||||
func (how *ProcfsOpenHow) Flags() *C.uint64_t { return &how.flags }
|
||||
|
||||
// ProcfsOpen is pathrs_procfs_open (sizeof(*how) is passed automatically).
|
||||
func ProcfsOpen(how *ProcfsOpenHow) (uintptr, error) {
|
||||
fd := C.pathrs_procfs_open((*C.pathrs_procfs_open_how)(how), C.size_t(unsafe.Sizeof(*how)))
|
||||
return uintptr(fd), fetchError(fd)
|
||||
}
|
||||
246
vendor/cyphar.com/go-pathrs/procfs/procfs_linux.go
generated
vendored
Normal file
246
vendor/cyphar.com/go-pathrs/procfs/procfs_linux.go
generated
vendored
Normal file
@@ -0,0 +1,246 @@
|
||||
//go:build linux
|
||||
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
/*
|
||||
* libpathrs: safe path resolution on Linux
|
||||
* Copyright (C) 2019-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||
* Copyright (C) 2019-2025 SUSE LLC
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
// Package procfs provides a safe API for operating on /proc on Linux.
|
||||
package procfs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"cyphar.com/go-pathrs/internal/fdutils"
|
||||
"cyphar.com/go-pathrs/internal/libpathrs"
|
||||
)
|
||||
|
||||
// ProcBase is used with [ProcReadlink] and related functions to indicate what
|
||||
// /proc subpath path operations should be done relative to.
|
||||
type ProcBase struct {
|
||||
inner libpathrs.ProcBase
|
||||
}
|
||||
|
||||
var (
|
||||
// ProcRoot indicates to use /proc. Note that this mode may be more
|
||||
// expensive because we have to take steps to try to avoid leaking unmasked
|
||||
// procfs handles, so you should use [ProcBaseSelf] if you can.
|
||||
ProcRoot = ProcBase{inner: libpathrs.ProcRoot}
|
||||
// ProcSelf indicates to use /proc/self. For most programs, this is the
|
||||
// standard choice.
|
||||
ProcSelf = ProcBase{inner: libpathrs.ProcSelf}
|
||||
// ProcThreadSelf indicates to use /proc/thread-self. In multi-threaded
|
||||
// programs where one thread has a different CLONE_FS, it is possible for
|
||||
// /proc/self to point the wrong thread and so /proc/thread-self may be
|
||||
// necessary.
|
||||
ProcThreadSelf = ProcBase{inner: libpathrs.ProcThreadSelf}
|
||||
)
|
||||
|
||||
// ProcPid returns a ProcBase which indicates to use /proc/$pid for the given
|
||||
// PID (or TID). Be aware that due to PID recycling, using this is generally
|
||||
// not safe except in certain circumstances. Namely:
|
||||
//
|
||||
// - PID 1 (the init process), as that PID cannot ever get recycled.
|
||||
// - Your current PID (though you should just use [ProcBaseSelf]).
|
||||
// - Your current TID if you have used [runtime.LockOSThread] (though you
|
||||
// should just use [ProcBaseThreadSelf]).
|
||||
// - PIDs of child processes (as long as you are sure that no other part of
|
||||
// your program incorrectly catches or ignores SIGCHLD, and that you do it
|
||||
// *before* you call wait(2)or any equivalent method that could reap
|
||||
// zombies).
|
||||
func ProcPid(pid int) ProcBase {
|
||||
if pid < 0 || pid >= 1<<31 {
|
||||
panic("invalid ProcBasePid value") // TODO: should this be an error?
|
||||
}
|
||||
return ProcBase{inner: libpathrs.ProcPid(uint32(pid))}
|
||||
}
|
||||
|
||||
// ThreadCloser is a callback that needs to be called when you are done
|
||||
// operating on an [os.File] fetched using [Handle.OpenThreadSelf].
|
||||
//
|
||||
// [os.File]: https://pkg.go.dev/os#File
|
||||
type ThreadCloser func()
|
||||
|
||||
// Handle is a wrapper around an *os.File handle to "/proc", which can be
|
||||
// used to do further procfs-related operations in a safe way.
|
||||
type Handle struct {
|
||||
inner *os.File
|
||||
}
|
||||
|
||||
// Close releases all internal resources for this [Handle].
|
||||
//
|
||||
// Note that if the handle is actually the global cached handle, this operation
|
||||
// is a no-op.
|
||||
func (proc *Handle) Close() error {
|
||||
var err error
|
||||
if proc.inner != nil {
|
||||
err = proc.inner.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// OpenOption is a configuration function passed as an argument to [Open].
|
||||
type OpenOption func(*libpathrs.ProcfsOpenHow) error
|
||||
|
||||
// UnmaskedProcRoot can be passed to [Open] to request an unmasked procfs
|
||||
// handle be created.
|
||||
//
|
||||
// procfs, err := procfs.OpenRoot(procfs.UnmaskedProcRoot)
|
||||
func UnmaskedProcRoot(how *libpathrs.ProcfsOpenHow) error {
|
||||
*how.Flags() |= libpathrs.ProcfsNewUnmasked
|
||||
return nil
|
||||
}
|
||||
|
||||
// Open creates a new [Handle] to a safe "/proc", based on the passed
|
||||
// configuration options (in the form of a series of [OpenOption]s).
|
||||
func Open(opts ...OpenOption) (*Handle, error) {
|
||||
var how libpathrs.ProcfsOpenHow
|
||||
for _, opt := range opts {
|
||||
if err := opt(&how); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
fd, err := libpathrs.ProcfsOpen(&how)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var procFile *os.File
|
||||
if int(fd) >= 0 {
|
||||
procFile = os.NewFile(fd, "/proc")
|
||||
}
|
||||
// TODO: Check that fd == PATHRS_PROC_DEFAULT_ROOTFD in the <0 case?
|
||||
return &Handle{inner: procFile}, nil
|
||||
}
|
||||
|
||||
// TODO: Switch to something fdutils.WithFileFd-like.
|
||||
func (proc *Handle) fd() int {
|
||||
if proc.inner != nil {
|
||||
return int(proc.inner.Fd())
|
||||
}
|
||||
return libpathrs.ProcDefaultRootFd
|
||||
}
|
||||
|
||||
// TODO: Should we expose open?
|
||||
func (proc *Handle) open(base ProcBase, path string, flags int) (_ *os.File, Closer ThreadCloser, Err error) {
|
||||
var closer ThreadCloser
|
||||
if base == ProcThreadSelf {
|
||||
runtime.LockOSThread()
|
||||
closer = runtime.UnlockOSThread
|
||||
}
|
||||
defer func() {
|
||||
if closer != nil && Err != nil {
|
||||
closer()
|
||||
Closer = nil
|
||||
}
|
||||
}()
|
||||
|
||||
fd, err := libpathrs.ProcOpenat(proc.fd(), base.inner, path, flags)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
file, err := fdutils.MkFile(fd)
|
||||
return file, closer, err
|
||||
}
|
||||
|
||||
// OpenRoot safely opens a given path from inside /proc/.
|
||||
//
|
||||
// This function must only be used for accessing global information from procfs
|
||||
// (such as /proc/cpuinfo) or information about other processes (such as
|
||||
// /proc/1). Accessing your own process information should be done using
|
||||
// [Handle.OpenSelf] or [Handle.OpenThreadSelf].
|
||||
func (proc *Handle) OpenRoot(path string, flags int) (*os.File, error) {
|
||||
file, closer, err := proc.open(ProcRoot, path, flags)
|
||||
if closer != nil {
|
||||
// should not happen
|
||||
panic("non-zero closer returned from procOpen(ProcRoot)")
|
||||
}
|
||||
return file, err
|
||||
}
|
||||
|
||||
// OpenSelf safely opens a given path from inside /proc/self/.
|
||||
//
|
||||
// This method is recommend for getting process information about the current
|
||||
// process for almost all Go processes *except* for cases where there are
|
||||
// [runtime.LockOSThread] threads that have changed some aspect of their state
|
||||
// (such as through unshare(CLONE_FS) or changing namespaces).
|
||||
//
|
||||
// For such non-heterogeneous processes, /proc/self may reference to a task
|
||||
// that has different state from the current goroutine and so it may be
|
||||
// preferable to use [Handle.OpenThreadSelf]. The same is true if a user
|
||||
// really wants to inspect the current OS thread's information (such as
|
||||
// /proc/thread-self/stack or /proc/thread-self/status which is always uniquely
|
||||
// per-thread).
|
||||
//
|
||||
// Unlike [Handle.OpenThreadSelf], this method does not involve locking
|
||||
// the goroutine to the current OS thread and so is simpler to use and
|
||||
// theoretically has slightly less overhead.
|
||||
//
|
||||
// [runtime.LockOSThread]: https://pkg.go.dev/runtime#LockOSThread
|
||||
func (proc *Handle) OpenSelf(path string, flags int) (*os.File, error) {
|
||||
file, closer, err := proc.open(ProcSelf, path, flags)
|
||||
if closer != nil {
|
||||
// should not happen
|
||||
panic("non-zero closer returned from procOpen(ProcSelf)")
|
||||
}
|
||||
return file, err
|
||||
}
|
||||
|
||||
// OpenPid safely opens a given path from inside /proc/$pid/, where pid can be
|
||||
// either a PID or TID.
|
||||
//
|
||||
// This is effectively equivalent to calling [Handle.OpenRoot] with the
|
||||
// pid prefixed to the subpath.
|
||||
//
|
||||
// Be aware that due to PID recycling, using this is generally not safe except
|
||||
// in certain circumstances. See the documentation of [ProcPid] for more
|
||||
// details.
|
||||
func (proc *Handle) OpenPid(pid int, path string, flags int) (*os.File, error) {
|
||||
file, closer, err := proc.open(ProcPid(pid), path, flags)
|
||||
if closer != nil {
|
||||
// should not happen
|
||||
panic("non-zero closer returned from procOpen(ProcPidOpen)")
|
||||
}
|
||||
return file, err
|
||||
}
|
||||
|
||||
// OpenThreadSelf safely opens a given path from inside /proc/thread-self/.
|
||||
//
|
||||
// Most Go processes have heterogeneous threads (all threads have most of the
|
||||
// same kernel state such as CLONE_FS) and so [Handle.OpenSelf] is
|
||||
// preferable for most users.
|
||||
//
|
||||
// For non-heterogeneous threads, or users that actually want thread-specific
|
||||
// information (such as /proc/thread-self/stack or /proc/thread-self/status),
|
||||
// this method is necessary.
|
||||
//
|
||||
// Because Go can change the running OS thread of your goroutine without notice
|
||||
// (and then subsequently kill the old thread), this method will lock the
|
||||
// current goroutine to the OS thread (with [runtime.LockOSThread]) and the
|
||||
// caller is responsible for unlocking the the OS thread with the
|
||||
// [ThreadCloser] callback once they are done using the returned file. This
|
||||
// callback MUST be called AFTER you have finished using the returned
|
||||
// [os.File]. This callback is completely separate to [os.File.Close], so it
|
||||
// must be called regardless of how you close the handle.
|
||||
//
|
||||
// [runtime.LockOSThread]: https://pkg.go.dev/runtime#LockOSThread
|
||||
// [os.File]: https://pkg.go.dev/os#File
|
||||
// [os.File.Close]: https://pkg.go.dev/os#File.Close
|
||||
func (proc *Handle) OpenThreadSelf(path string, flags int) (*os.File, ThreadCloser, error) {
|
||||
return proc.open(ProcThreadSelf, path, flags)
|
||||
}
|
||||
|
||||
// Readlink safely reads the contents of a symlink from the given procfs base.
|
||||
//
|
||||
// This is effectively equivalent to doing an Open*(O_PATH|O_NOFOLLOW) of the
|
||||
// path and then doing unix.Readlinkat(fd, ""), but with the benefit that
|
||||
// thread locking is not necessary for [ProcThreadSelf].
|
||||
func (proc *Handle) Readlink(base ProcBase, path string) (string, error) {
|
||||
return libpathrs.ProcReadlinkat(proc.fd(), base.inner, path)
|
||||
}
|
||||
367
vendor/cyphar.com/go-pathrs/root_linux.go
generated
vendored
Normal file
367
vendor/cyphar.com/go-pathrs/root_linux.go
generated
vendored
Normal file
@@ -0,0 +1,367 @@
|
||||
//go:build linux
|
||||
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
/*
|
||||
* libpathrs: safe path resolution on Linux
|
||||
* Copyright (C) 2019-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||
* Copyright (C) 2019-2025 SUSE LLC
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package pathrs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"cyphar.com/go-pathrs/internal/fdutils"
|
||||
"cyphar.com/go-pathrs/internal/libpathrs"
|
||||
)
|
||||
|
||||
// Root is a handle to the root of a directory tree to resolve within. The only
|
||||
// purpose of this "root handle" is to perform operations within the directory
|
||||
// tree, or to get a [Handle] to inodes within the directory tree.
|
||||
//
|
||||
// At time of writing, it is considered a *VERY BAD IDEA* to open a [Root]
|
||||
// inside a possibly-attacker-controlled directory tree. While we do have
|
||||
// protections that should defend against it, it's far more dangerous than just
|
||||
// opening a directory tree which is not inside a potentially-untrusted
|
||||
// directory.
|
||||
type Root struct {
|
||||
inner *os.File
|
||||
}
|
||||
|
||||
// OpenRoot creates a new [Root] handle to the directory at the given path.
|
||||
func OpenRoot(path string) (*Root, error) {
|
||||
fd, err := libpathrs.OpenRoot(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
file, err := fdutils.MkFile(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Root{inner: file}, nil
|
||||
}
|
||||
|
||||
// RootFromFile creates a new [Root] handle from an [os.File] referencing a
|
||||
// directory. The provided file will be duplicated, so the original file should
|
||||
// still be closed by the caller.
|
||||
//
|
||||
// This is effectively the inverse operation of [Root.IntoFile].
|
||||
//
|
||||
// [os.File]: https://pkg.go.dev/os#File
|
||||
func RootFromFile(file *os.File) (*Root, error) {
|
||||
newFile, err := fdutils.DupFile(file)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("duplicate root fd: %w", err)
|
||||
}
|
||||
return &Root{inner: newFile}, nil
|
||||
}
|
||||
|
||||
// Resolve resolves the given path within the [Root]'s directory tree, and
|
||||
// returns a [Handle] to the resolved path. The path must already exist,
|
||||
// otherwise an error will occur.
|
||||
//
|
||||
// All symlinks (including trailing symlinks) are followed, but they are
|
||||
// resolved within the rootfs. If you wish to open a handle to the symlink
|
||||
// itself, use [ResolveNoFollow].
|
||||
func (r *Root) Resolve(path string) (*Handle, error) {
|
||||
return fdutils.WithFileFd(r.inner, func(rootFd uintptr) (*Handle, error) {
|
||||
handleFd, err := libpathrs.InRootResolve(rootFd, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
handleFile, err := fdutils.MkFile(handleFd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Handle{inner: handleFile}, nil
|
||||
})
|
||||
}
|
||||
|
||||
// ResolveNoFollow is effectively an O_NOFOLLOW version of [Resolve]. Their
|
||||
// behaviour is identical, except that *trailing* symlinks will not be
|
||||
// followed. If the final component is a trailing symlink, an O_PATH|O_NOFOLLOW
|
||||
// handle to the symlink itself is returned.
|
||||
func (r *Root) ResolveNoFollow(path string) (*Handle, error) {
|
||||
return fdutils.WithFileFd(r.inner, func(rootFd uintptr) (*Handle, error) {
|
||||
handleFd, err := libpathrs.InRootResolveNoFollow(rootFd, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
handleFile, err := fdutils.MkFile(handleFd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Handle{inner: handleFile}, nil
|
||||
})
|
||||
}
|
||||
|
||||
// Open is effectively shorthand for [Resolve] followed by [Handle.Open], but
|
||||
// can be slightly more efficient (it reduces CGo overhead and the number of
|
||||
// syscalls used when using the openat2-based resolver) and is arguably more
|
||||
// ergonomic to use.
|
||||
//
|
||||
// This is effectively equivalent to [os.Open].
|
||||
//
|
||||
// [os.Open]: https://pkg.go.dev/os#Open
|
||||
func (r *Root) Open(path string) (*os.File, error) {
|
||||
return r.OpenFile(path, os.O_RDONLY)
|
||||
}
|
||||
|
||||
// OpenFile is effectively shorthand for [Resolve] followed by
|
||||
// [Handle.OpenFile], but can be slightly more efficient (it reduces CGo
|
||||
// overhead and the number of syscalls used when using the openat2-based
|
||||
// resolver) and is arguably more ergonomic to use.
|
||||
//
|
||||
// However, if flags contains os.O_NOFOLLOW and the path is a symlink, then
|
||||
// OpenFile's behaviour will match that of openat2. In most cases an error will
|
||||
// be returned, but if os.O_PATH is provided along with os.O_NOFOLLOW then a
|
||||
// file equivalent to [ResolveNoFollow] will be returned instead.
|
||||
//
|
||||
// This is effectively equivalent to [os.OpenFile], except that os.O_CREAT is
|
||||
// not supported.
|
||||
//
|
||||
// [os.OpenFile]: https://pkg.go.dev/os#OpenFile
|
||||
func (r *Root) OpenFile(path string, flags int) (*os.File, error) {
|
||||
return fdutils.WithFileFd(r.inner, func(rootFd uintptr) (*os.File, error) {
|
||||
fd, err := libpathrs.InRootOpen(rootFd, path, flags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fdutils.MkFile(fd)
|
||||
})
|
||||
}
|
||||
|
||||
// Create creates a file within the [Root]'s directory tree at the given path,
|
||||
// and returns a handle to the file. The provided mode is used for the new file
|
||||
// (the process's umask applies).
|
||||
//
|
||||
// Unlike [os.Create], if the file already exists an error is created rather
|
||||
// than the file being opened and truncated.
|
||||
//
|
||||
// [os.Create]: https://pkg.go.dev/os#Create
|
||||
func (r *Root) Create(path string, flags int, mode os.FileMode) (*os.File, error) {
|
||||
unixMode, err := toUnixMode(mode, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fdutils.WithFileFd(r.inner, func(rootFd uintptr) (*os.File, error) {
|
||||
handleFd, err := libpathrs.InRootCreat(rootFd, path, flags, unixMode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fdutils.MkFile(handleFd)
|
||||
})
|
||||
}
|
||||
|
||||
// Rename two paths within a [Root]'s directory tree. The flags argument is
|
||||
// identical to the RENAME_* flags to the renameat2(2) system call.
|
||||
func (r *Root) Rename(src, dst string, flags uint) error {
|
||||
_, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) {
|
||||
err := libpathrs.InRootRename(rootFd, src, dst, flags)
|
||||
return struct{}{}, err
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// RemoveDir removes the named empty directory within a [Root]'s directory
|
||||
// tree.
|
||||
func (r *Root) RemoveDir(path string) error {
|
||||
_, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) {
|
||||
err := libpathrs.InRootRmdir(rootFd, path)
|
||||
return struct{}{}, err
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// RemoveFile removes the named file within a [Root]'s directory tree.
|
||||
func (r *Root) RemoveFile(path string) error {
|
||||
_, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) {
|
||||
err := libpathrs.InRootUnlink(rootFd, path)
|
||||
return struct{}{}, err
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove removes the named file or (empty) directory within a [Root]'s
|
||||
// directory tree.
|
||||
//
|
||||
// This is effectively equivalent to [os.Remove].
|
||||
//
|
||||
// [os.Remove]: https://pkg.go.dev/os#Remove
|
||||
func (r *Root) Remove(path string) error {
|
||||
// In order to match os.Remove's implementation we need to also do both
|
||||
// syscalls unconditionally and adjust the error based on whether
|
||||
// pathrs_inroot_rmdir() returned ENOTDIR.
|
||||
unlinkErr := r.RemoveFile(path)
|
||||
if unlinkErr == nil {
|
||||
return nil
|
||||
}
|
||||
rmdirErr := r.RemoveDir(path)
|
||||
if rmdirErr == nil {
|
||||
return nil
|
||||
}
|
||||
// Both failed, adjust the error in the same way that os.Remove does.
|
||||
err := rmdirErr
|
||||
if errors.Is(err, syscall.ENOTDIR) {
|
||||
err = unlinkErr
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// RemoveAll recursively deletes a path and all of its children.
|
||||
//
|
||||
// This is effectively equivalent to [os.RemoveAll].
|
||||
//
|
||||
// [os.RemoveAll]: https://pkg.go.dev/os#RemoveAll
|
||||
func (r *Root) RemoveAll(path string) error {
|
||||
_, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) {
|
||||
err := libpathrs.InRootRemoveAll(rootFd, path)
|
||||
return struct{}{}, err
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// Mkdir creates a directory within a [Root]'s directory tree. The provided
|
||||
// mode is used for the new directory (the process's umask applies).
|
||||
//
|
||||
// This is effectively equivalent to [os.Mkdir].
|
||||
//
|
||||
// [os.Mkdir]: https://pkg.go.dev/os#Mkdir
|
||||
func (r *Root) Mkdir(path string, mode os.FileMode) error {
|
||||
unixMode, err := toUnixMode(mode, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) {
|
||||
err := libpathrs.InRootMkdir(rootFd, path, unixMode)
|
||||
return struct{}{}, err
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// MkdirAll creates a directory (and any parent path components if they don't
|
||||
// exist) within a [Root]'s directory tree. The provided mode is used for any
|
||||
// directories created by this function (the process's umask applies).
|
||||
//
|
||||
// This is effectively equivalent to [os.MkdirAll].
|
||||
//
|
||||
// [os.MkdirAll]: https://pkg.go.dev/os#MkdirAll
|
||||
func (r *Root) MkdirAll(path string, mode os.FileMode) (*Handle, error) {
|
||||
unixMode, err := toUnixMode(mode, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return fdutils.WithFileFd(r.inner, func(rootFd uintptr) (*Handle, error) {
|
||||
handleFd, err := libpathrs.InRootMkdirAll(rootFd, path, unixMode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
handleFile, err := fdutils.MkFile(handleFd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Handle{inner: handleFile}, err
|
||||
})
|
||||
}
|
||||
|
||||
// Mknod creates a new device inode of the given type within a [Root]'s
|
||||
// directory tree. The provided mode is used for the new directory (the
|
||||
// process's umask applies).
|
||||
//
|
||||
// This is effectively equivalent to [unix.Mknod].
|
||||
//
|
||||
// [unix.Mknod]: https://pkg.go.dev/golang.org/x/sys/unix#Mknod
|
||||
func (r *Root) Mknod(path string, mode os.FileMode, dev uint64) error {
|
||||
unixMode, err := toUnixMode(mode, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) {
|
||||
err := libpathrs.InRootMknod(rootFd, path, unixMode, dev)
|
||||
return struct{}{}, err
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// Symlink creates a symlink within a [Root]'s directory tree. The symlink is
|
||||
// created at path and is a link to target.
|
||||
//
|
||||
// This is effectively equivalent to [os.Symlink].
|
||||
//
|
||||
// [os.Symlink]: https://pkg.go.dev/os#Symlink
|
||||
func (r *Root) Symlink(path, target string) error {
|
||||
_, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) {
|
||||
err := libpathrs.InRootSymlink(rootFd, path, target)
|
||||
return struct{}{}, err
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// Hardlink creates a hardlink within a [Root]'s directory tree. The hardlink
|
||||
// is created at path and is a link to target. Both paths are within the
|
||||
// [Root]'s directory tree (you cannot hardlink to a different [Root] or the
|
||||
// host).
|
||||
//
|
||||
// This is effectively equivalent to [os.Link].
|
||||
//
|
||||
// [os.Link]: https://pkg.go.dev/os#Link
|
||||
func (r *Root) Hardlink(path, target string) error {
|
||||
_, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) {
|
||||
err := libpathrs.InRootHardlink(rootFd, path, target)
|
||||
return struct{}{}, err
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// Readlink returns the target of a symlink with a [Root]'s directory tree.
|
||||
//
|
||||
// This is effectively equivalent to [os.Readlink].
|
||||
//
|
||||
// [os.Readlink]: https://pkg.go.dev/os#Readlink
|
||||
func (r *Root) Readlink(path string) (string, error) {
|
||||
return fdutils.WithFileFd(r.inner, func(rootFd uintptr) (string, error) {
|
||||
return libpathrs.InRootReadlink(rootFd, path)
|
||||
})
|
||||
}
|
||||
|
||||
// IntoFile unwraps the [Root] into its underlying [os.File].
|
||||
//
|
||||
// It is critical that you do not operate on this file descriptor yourself,
|
||||
// because the security properties of libpathrs depend on users doing all
|
||||
// relevant filesystem operations through libpathrs.
|
||||
//
|
||||
// This operation returns the internal [os.File] of the [Root] directly, so
|
||||
// calling [Root.Close] will also close any copies of the returned [os.File].
|
||||
// If you want to get an independent copy, use [Root.Clone] followed by
|
||||
// [Root.IntoFile] on the cloned [Root].
|
||||
//
|
||||
// [os.File]: https://pkg.go.dev/os#File
|
||||
func (r *Root) IntoFile() *os.File {
|
||||
// TODO: Figure out if we really don't want to make a copy.
|
||||
// TODO: We almost certainly want to clear r.inner here, but we can't do
|
||||
// that easily atomically (we could use atomic.Value but that'll make
|
||||
// things quite a bit uglier).
|
||||
return r.inner
|
||||
}
|
||||
|
||||
// Clone creates a copy of a [Root] handle, such that it has a separate
|
||||
// lifetime to the original (while referring to the same underlying directory).
|
||||
func (r *Root) Clone() (*Root, error) {
|
||||
return RootFromFile(r.inner)
|
||||
}
|
||||
|
||||
// Close frees all of the resources used by the [Root] handle.
|
||||
func (r *Root) Close() error {
|
||||
return r.inner.Close()
|
||||
}
|
||||
56
vendor/cyphar.com/go-pathrs/utils_linux.go
generated
vendored
Normal file
56
vendor/cyphar.com/go-pathrs/utils_linux.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
//go:build linux
|
||||
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
/*
|
||||
* libpathrs: safe path resolution on Linux
|
||||
* Copyright (C) 2019-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||
* Copyright (C) 2019-2025 SUSE LLC
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package pathrs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
//nolint:cyclop // this function needs to handle a lot of cases
|
||||
func toUnixMode(mode os.FileMode, needsType bool) (uint32, error) {
|
||||
sysMode := uint32(mode.Perm())
|
||||
switch mode & os.ModeType { //nolint:exhaustive // we only care about ModeType bits
|
||||
case 0:
|
||||
if needsType {
|
||||
sysMode |= unix.S_IFREG
|
||||
}
|
||||
case os.ModeDir:
|
||||
sysMode |= unix.S_IFDIR
|
||||
case os.ModeSymlink:
|
||||
sysMode |= unix.S_IFLNK
|
||||
case os.ModeCharDevice | os.ModeDevice:
|
||||
sysMode |= unix.S_IFCHR
|
||||
case os.ModeDevice:
|
||||
sysMode |= unix.S_IFBLK
|
||||
case os.ModeNamedPipe:
|
||||
sysMode |= unix.S_IFIFO
|
||||
case os.ModeSocket:
|
||||
sysMode |= unix.S_IFSOCK
|
||||
default:
|
||||
return 0, fmt.Errorf("invalid mode filetype %+o", mode)
|
||||
}
|
||||
if mode&os.ModeSetuid != 0 {
|
||||
sysMode |= unix.S_ISUID
|
||||
}
|
||||
if mode&os.ModeSetgid != 0 {
|
||||
sysMode |= unix.S_ISGID
|
||||
}
|
||||
if mode&os.ModeSticky != 0 {
|
||||
sysMode |= unix.S_ISVTX
|
||||
}
|
||||
return sysMode, nil
|
||||
}
|
||||
111
vendor/github.com/containerd/stargz-snapshotter/estargz/build.go
generated
vendored
111
vendor/github.com/containerd/stargz-snapshotter/estargz/build.go
generated
vendored
@@ -35,6 +35,7 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/containerd/stargz-snapshotter/estargz/errorutil"
|
||||
"github.com/klauspost/compress/zstd"
|
||||
@@ -42,6 +43,8 @@ import (
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
type GzipHelperFunc func(io.Reader) (io.ReadCloser, error)
|
||||
|
||||
type options struct {
|
||||
chunkSize int
|
||||
compressionLevel int
|
||||
@@ -50,6 +53,7 @@ type options struct {
|
||||
compression Compression
|
||||
ctx context.Context
|
||||
minChunkSize int
|
||||
gzipHelperFunc GzipHelperFunc
|
||||
}
|
||||
|
||||
type Option func(o *options) error
|
||||
@@ -127,11 +131,25 @@ func WithMinChunkSize(minChunkSize int) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithGzipHelperFunc option specifies a custom function to decompress gzip-compressed layers.
|
||||
// When a gzip-compressed layer is detected, this function will be used instead of the
|
||||
// Go standard library gzip decompression for better performance.
|
||||
// The function should take an io.Reader as input and return an io.ReadCloser.
|
||||
// If nil, the Go standard library gzip.NewReader will be used.
|
||||
func WithGzipHelperFunc(gzipHelperFunc GzipHelperFunc) Option {
|
||||
return func(o *options) error {
|
||||
o.gzipHelperFunc = gzipHelperFunc
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Blob is an eStargz blob.
|
||||
type Blob struct {
|
||||
io.ReadCloser
|
||||
diffID digest.Digester
|
||||
tocDigest digest.Digest
|
||||
diffID digest.Digester
|
||||
tocDigest digest.Digest
|
||||
readCompleted *atomic.Bool
|
||||
uncompressedSize *atomic.Int64
|
||||
}
|
||||
|
||||
// DiffID returns the digest of uncompressed blob.
|
||||
@@ -145,6 +163,19 @@ func (b *Blob) TOCDigest() digest.Digest {
|
||||
return b.tocDigest
|
||||
}
|
||||
|
||||
// UncompressedSize returns the size of uncompressed blob.
|
||||
// UncompressedSize should only be called after the blob has been fully read.
|
||||
func (b *Blob) UncompressedSize() (int64, error) {
|
||||
switch {
|
||||
case b.uncompressedSize == nil || b.readCompleted == nil:
|
||||
return -1, fmt.Errorf("readCompleted or uncompressedSize is not initialized")
|
||||
case !b.readCompleted.Load():
|
||||
return -1, fmt.Errorf("called UncompressedSize before the blob has been fully read")
|
||||
default:
|
||||
return b.uncompressedSize.Load(), nil
|
||||
}
|
||||
}
|
||||
|
||||
// Build builds an eStargz blob which is an extended version of stargz, from a blob (gzip, zstd
|
||||
// or plain tar) passed through the argument. If there are some prioritized files are listed in
|
||||
// the option, these files are grouped as "prioritized" and can be used for runtime optimization
|
||||
@@ -186,7 +217,7 @@ func Build(tarBlob *io.SectionReader, opt ...Option) (_ *Blob, rErr error) {
|
||||
rErr = fmt.Errorf("error from context %q: %w", cErr, rErr)
|
||||
}
|
||||
}()
|
||||
tarBlob, err := decompressBlob(tarBlob, layerFiles)
|
||||
tarBlob, err := decompressBlob(tarBlob, layerFiles, opts.gzipHelperFunc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -252,17 +283,28 @@ func Build(tarBlob *io.SectionReader, opt ...Option) (_ *Blob, rErr error) {
|
||||
}
|
||||
diffID := digest.Canonical.Digester()
|
||||
pr, pw := io.Pipe()
|
||||
readCompleted := new(atomic.Bool)
|
||||
uncompressedSize := new(atomic.Int64)
|
||||
go func() {
|
||||
r, err := opts.compression.Reader(io.TeeReader(io.MultiReader(append(rs, tocAndFooter)...), pw))
|
||||
var size int64
|
||||
var decompressFunc func(io.Reader) (io.ReadCloser, error)
|
||||
if _, ok := opts.compression.(*gzipCompression); ok && opts.gzipHelperFunc != nil {
|
||||
decompressFunc = opts.gzipHelperFunc
|
||||
} else {
|
||||
decompressFunc = opts.compression.Reader
|
||||
}
|
||||
decompressR, err := decompressFunc(io.TeeReader(io.MultiReader(append(rs, tocAndFooter)...), pw))
|
||||
if err != nil {
|
||||
pw.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
defer r.Close()
|
||||
if _, err := io.Copy(diffID.Hash(), r); err != nil {
|
||||
defer decompressR.Close()
|
||||
if size, err = io.Copy(diffID.Hash(), decompressR); err != nil {
|
||||
pw.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
uncompressedSize.Store(size)
|
||||
readCompleted.Store(true)
|
||||
pw.Close()
|
||||
}()
|
||||
return &Blob{
|
||||
@@ -270,8 +312,10 @@ func Build(tarBlob *io.SectionReader, opt ...Option) (_ *Blob, rErr error) {
|
||||
Reader: pr,
|
||||
closeFunc: layerFiles.CleanupAll,
|
||||
},
|
||||
tocDigest: tocDgst,
|
||||
diffID: diffID,
|
||||
tocDigest: tocDgst,
|
||||
diffID: diffID,
|
||||
readCompleted: readCompleted,
|
||||
uncompressedSize: uncompressedSize,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -366,8 +410,9 @@ func sortEntries(in io.ReaderAt, prioritized []string, missedPrioritized *[]stri
|
||||
|
||||
// Sort the tar file respecting to the prioritized files list.
|
||||
sorted := &tarFile{}
|
||||
picked := make(map[string]struct{})
|
||||
for _, l := range prioritized {
|
||||
if err := moveRec(l, intar, sorted); err != nil {
|
||||
if err := moveRec(l, intar, sorted, picked); err != nil {
|
||||
if errors.Is(err, errNotFound) && missedPrioritized != nil {
|
||||
*missedPrioritized = append(*missedPrioritized, l)
|
||||
continue // allow not found
|
||||
@@ -395,8 +440,8 @@ func sortEntries(in io.ReaderAt, prioritized []string, missedPrioritized *[]stri
|
||||
})
|
||||
}
|
||||
|
||||
// Dump all entry and concatinate them.
|
||||
return append(sorted.dump(), intar.dump()...), nil
|
||||
// Dump prioritized entries followed by the rest entries while skipping picked ones.
|
||||
return append(sorted.dump(nil), intar.dump(picked)...), nil
|
||||
}
|
||||
|
||||
// readerFromEntries returns a reader of tar archive that contains entries passed
|
||||
@@ -458,36 +503,42 @@ func importTar(in io.ReaderAt) (*tarFile, error) {
|
||||
return tf, nil
|
||||
}
|
||||
|
||||
func moveRec(name string, in *tarFile, out *tarFile) error {
|
||||
func moveRec(name string, in *tarFile, out *tarFile, picked map[string]struct{}) error {
|
||||
name = cleanEntryName(name)
|
||||
if name == "" { // root directory. stop recursion.
|
||||
if e, ok := in.get(name); ok {
|
||||
// entry of the root directory exists. we should move it as well.
|
||||
// this case will occur if tar entries are prefixed with "./", "/", etc.
|
||||
out.add(e)
|
||||
in.remove(name)
|
||||
if _, done := picked[name]; !done {
|
||||
out.add(e)
|
||||
picked[name] = struct{}{}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
_, okIn := in.get(name)
|
||||
_, okOut := out.get(name)
|
||||
if !okIn && !okOut {
|
||||
_, okPicked := picked[name]
|
||||
if !okIn && !okOut && !okPicked {
|
||||
return fmt.Errorf("file: %q: %w", name, errNotFound)
|
||||
}
|
||||
|
||||
parent, _ := path.Split(strings.TrimSuffix(name, "/"))
|
||||
if err := moveRec(parent, in, out); err != nil {
|
||||
if err := moveRec(parent, in, out, picked); err != nil {
|
||||
return err
|
||||
}
|
||||
if e, ok := in.get(name); ok && e.header.Typeflag == tar.TypeLink {
|
||||
if err := moveRec(e.header.Linkname, in, out); err != nil {
|
||||
if err := moveRec(e.header.Linkname, in, out, picked); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, done := picked[name]; done {
|
||||
return nil
|
||||
}
|
||||
if e, ok := in.get(name); ok {
|
||||
out.add(e)
|
||||
in.remove(name)
|
||||
picked[name] = struct{}{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -533,8 +584,18 @@ func (f *tarFile) get(name string) (e *entry, ok bool) {
|
||||
return
|
||||
}
|
||||
|
||||
func (f *tarFile) dump() []*entry {
|
||||
return f.stream
|
||||
func (f *tarFile) dump(skip map[string]struct{}) []*entry {
|
||||
if len(skip) == 0 {
|
||||
return f.stream
|
||||
}
|
||||
var out []*entry
|
||||
for _, e := range f.stream {
|
||||
if _, ok := skip[cleanEntryName(e.header.Name)]; ok {
|
||||
continue
|
||||
}
|
||||
out = append(out, e)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
type readCloser struct {
|
||||
@@ -649,7 +710,7 @@ func (cr *countReadSeeker) currentPos() int64 {
|
||||
return *cr.cPos
|
||||
}
|
||||
|
||||
func decompressBlob(org *io.SectionReader, tmp *tempFiles) (*io.SectionReader, error) {
|
||||
func decompressBlob(org *io.SectionReader, tmp *tempFiles, gzipHelperFunc GzipHelperFunc) (*io.SectionReader, error) {
|
||||
if org.Size() < 4 {
|
||||
return org, nil
|
||||
}
|
||||
@@ -660,7 +721,13 @@ func decompressBlob(org *io.SectionReader, tmp *tempFiles) (*io.SectionReader, e
|
||||
var dR io.Reader
|
||||
if bytes.Equal([]byte{0x1F, 0x8B, 0x08}, src[:3]) {
|
||||
// gzip
|
||||
dgR, err := gzip.NewReader(io.NewSectionReader(org, 0, org.Size()))
|
||||
var dgR io.ReadCloser
|
||||
var err error
|
||||
if gzipHelperFunc != nil {
|
||||
dgR, err = gzipHelperFunc(io.NewSectionReader(org, 0, org.Size()))
|
||||
} else {
|
||||
dgR, err = gzip.NewReader(io.NewSectionReader(org, 0, org.Size()))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
9
vendor/github.com/containerd/stargz-snapshotter/estargz/estargz.go
generated
vendored
9
vendor/github.com/containerd/stargz-snapshotter/estargz/estargz.go
generated
vendored
@@ -307,6 +307,15 @@ func (r *Reader) initFields() error {
|
||||
}
|
||||
}
|
||||
|
||||
if len(r.m) == 0 {
|
||||
r.m[""] = &TOCEntry{
|
||||
Name: "",
|
||||
Type: "dir",
|
||||
Mode: 0755,
|
||||
NumLink: 1,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
155
vendor/github.com/containerd/stargz-snapshotter/estargz/testutil.go
generated
vendored
155
vendor/github.com/containerd/stargz-snapshotter/estargz/testutil.go
generated
vendored
@@ -38,7 +38,6 @@ import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/stargz-snapshotter/estargz/errorutil"
|
||||
@@ -49,16 +48,48 @@ import (
|
||||
// TestingController is Compression with some helper methods necessary for testing.
|
||||
type TestingController interface {
|
||||
Compression
|
||||
TestStreams(t *testing.T, b []byte, streams []int64)
|
||||
DiffIDOf(*testing.T, []byte) string
|
||||
TestStreams(t TestingT, b []byte, streams []int64)
|
||||
DiffIDOf(TestingT, []byte) string
|
||||
String() string
|
||||
}
|
||||
|
||||
// TestingT is the minimal set of testing.T required to run the
|
||||
// tests defined in CompressionTestSuite. This interface exists to prevent
|
||||
// leaking the testing package from being exposed outside tests.
|
||||
type TestingT interface {
|
||||
Errorf(format string, args ...any)
|
||||
FailNow()
|
||||
Failed() bool
|
||||
Fatal(args ...any)
|
||||
Fatalf(format string, args ...any)
|
||||
Logf(format string, args ...any)
|
||||
Parallel()
|
||||
}
|
||||
|
||||
// Runner allows running subtests of TestingT. This exists instead of adding
|
||||
// a Run method to TestingT interface because the Run implementation of
|
||||
// testing.T would not satisfy the interface.
|
||||
type Runner func(t TestingT, name string, fn func(t TestingT))
|
||||
|
||||
type TestRunner struct {
|
||||
TestingT
|
||||
Runner Runner
|
||||
}
|
||||
|
||||
func (r *TestRunner) Run(name string, run func(*TestRunner)) {
|
||||
r.Runner(r.TestingT, name, func(t TestingT) {
|
||||
run(&TestRunner{TestingT: t, Runner: r.Runner})
|
||||
})
|
||||
}
|
||||
|
||||
// CompressionTestSuite tests this pkg with controllers can build valid eStargz blobs and parse them.
|
||||
func CompressionTestSuite(t *testing.T, controllers ...TestingControllerFactory) {
|
||||
t.Run("testBuild", func(t *testing.T) { t.Parallel(); testBuild(t, controllers...) })
|
||||
t.Run("testDigestAndVerify", func(t *testing.T) { t.Parallel(); testDigestAndVerify(t, controllers...) })
|
||||
t.Run("testWriteAndOpen", func(t *testing.T) { t.Parallel(); testWriteAndOpen(t, controllers...) })
|
||||
func CompressionTestSuite(t *TestRunner, controllers ...TestingControllerFactory) {
|
||||
t.Run("testBuild", func(t *TestRunner) { t.Parallel(); testBuild(t, controllers...) })
|
||||
t.Run("testDigestAndVerify", func(t *TestRunner) {
|
||||
t.Parallel()
|
||||
testDigestAndVerify(t, controllers...)
|
||||
})
|
||||
t.Run("testWriteAndOpen", func(t *TestRunner) { t.Parallel(); testWriteAndOpen(t, controllers...) })
|
||||
}
|
||||
|
||||
type TestingControllerFactory func() TestingController
|
||||
@@ -79,7 +110,7 @@ var allowedPrefix = [4]string{"", "./", "/", "../"}
|
||||
|
||||
// testBuild tests the resulting stargz blob built by this pkg has the same
|
||||
// contents as the normal stargz blob.
|
||||
func testBuild(t *testing.T, controllers ...TestingControllerFactory) {
|
||||
func testBuild(t *TestRunner, controllers ...TestingControllerFactory) {
|
||||
tests := []struct {
|
||||
name string
|
||||
chunkSize int
|
||||
@@ -165,7 +196,7 @@ func testBuild(t *testing.T, controllers ...TestingControllerFactory) {
|
||||
prefix := prefix
|
||||
for _, minChunkSize := range tt.minChunkSize {
|
||||
minChunkSize := minChunkSize
|
||||
t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,src=%d,format=%s,minChunkSize=%d", newCL(), prefix, srcCompression, srcTarFormat, minChunkSize), func(t *testing.T) {
|
||||
t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,src=%d,format=%s,minChunkSize=%d", newCL(), prefix, srcCompression, srcTarFormat, minChunkSize), func(t *TestRunner) {
|
||||
tarBlob := buildTar(t, tt.in, prefix, srcTarFormat)
|
||||
// Test divideEntries()
|
||||
entries, err := sortEntries(tarBlob, nil, nil) // identical order
|
||||
@@ -265,7 +296,7 @@ func testBuild(t *testing.T, controllers ...TestingControllerFactory) {
|
||||
}
|
||||
}
|
||||
|
||||
func isSameTarGz(t *testing.T, cla TestingController, a []byte, clb TestingController, b []byte) bool {
|
||||
func isSameTarGz(t TestingT, cla TestingController, a []byte, clb TestingController, b []byte) bool {
|
||||
aGz, err := cla.Reader(bytes.NewReader(a))
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read A")
|
||||
@@ -325,7 +356,7 @@ func isSameTarGz(t *testing.T, cla TestingController, a []byte, clb TestingContr
|
||||
return true
|
||||
}
|
||||
|
||||
func isSameVersion(t *testing.T, cla TestingController, a []byte, clb TestingController, b []byte) bool {
|
||||
func isSameVersion(t TestingT, cla TestingController, a []byte, clb TestingController, b []byte) bool {
|
||||
aJTOC, _, err := parseStargz(io.NewSectionReader(bytes.NewReader(a), 0, int64(len(a))), cla)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse A: %v", err)
|
||||
@@ -339,7 +370,7 @@ func isSameVersion(t *testing.T, cla TestingController, a []byte, clb TestingCon
|
||||
return aJTOC.Version == bJTOC.Version
|
||||
}
|
||||
|
||||
func isSameEntries(t *testing.T, a, b *Reader) bool {
|
||||
func isSameEntries(t TestingT, a, b *Reader) bool {
|
||||
aroot, ok := a.Lookup("")
|
||||
if !ok {
|
||||
t.Fatalf("failed to get root of A")
|
||||
@@ -353,7 +384,7 @@ func isSameEntries(t *testing.T, a, b *Reader) bool {
|
||||
return contains(t, aEntry, bEntry) && contains(t, bEntry, aEntry)
|
||||
}
|
||||
|
||||
func compressBlob(t *testing.T, src *io.SectionReader, srcCompression int) *io.SectionReader {
|
||||
func compressBlob(t TestingT, src *io.SectionReader, srcCompression int) *io.SectionReader {
|
||||
buf := new(bytes.Buffer)
|
||||
var w io.WriteCloser
|
||||
var err error
|
||||
@@ -387,7 +418,7 @@ type stargzEntry struct {
|
||||
|
||||
// contains checks if all child entries in "b" are also contained in "a".
|
||||
// This function also checks if the files/chunks contain the same contents among "a" and "b".
|
||||
func contains(t *testing.T, a, b stargzEntry) bool {
|
||||
func contains(t TestingT, a, b stargzEntry) bool {
|
||||
ae, ar := a.e, a.r
|
||||
be, br := b.e, b.r
|
||||
t.Logf("Comparing: %q vs %q", ae.Name, be.Name)
|
||||
@@ -498,7 +529,7 @@ func equalEntry(a, b *TOCEntry) bool {
|
||||
a.Digest == b.Digest
|
||||
}
|
||||
|
||||
func readOffset(t *testing.T, r *io.SectionReader, offset int64, e stargzEntry) ([]byte, int64, bool) {
|
||||
func readOffset(t TestingT, r *io.SectionReader, offset int64, e stargzEntry) ([]byte, int64, bool) {
|
||||
ce, ok := e.r.ChunkEntryForOffset(e.e.Name, offset)
|
||||
if !ok {
|
||||
return nil, 0, false
|
||||
@@ -517,7 +548,7 @@ func readOffset(t *testing.T, r *io.SectionReader, offset int64, e stargzEntry)
|
||||
return data[:n], offset + ce.ChunkSize, true
|
||||
}
|
||||
|
||||
func dumpTOCJSON(t *testing.T, tocJSON *JTOC) string {
|
||||
func dumpTOCJSON(t TestingT, tocJSON *JTOC) string {
|
||||
jtocData, err := json.Marshal(*tocJSON)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal TOC JSON: %v", err)
|
||||
@@ -531,20 +562,19 @@ func dumpTOCJSON(t *testing.T, tocJSON *JTOC) string {
|
||||
|
||||
const chunkSize = 3
|
||||
|
||||
// type check func(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, compressionLevel int)
|
||||
type check func(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory)
|
||||
type check func(t *TestRunner, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory)
|
||||
|
||||
// testDigestAndVerify runs specified checks against sample stargz blobs.
|
||||
func testDigestAndVerify(t *testing.T, controllers ...TestingControllerFactory) {
|
||||
func testDigestAndVerify(t *TestRunner, controllers ...TestingControllerFactory) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tarInit func(t *testing.T, dgstMap map[string]digest.Digest) (blob []tarEntry)
|
||||
tarInit func(t TestingT, dgstMap map[string]digest.Digest) (blob []tarEntry)
|
||||
checks []check
|
||||
minChunkSize []int
|
||||
}{
|
||||
{
|
||||
name: "no-regfile",
|
||||
tarInit: func(t *testing.T, dgstMap map[string]digest.Digest) (blob []tarEntry) {
|
||||
tarInit: func(t TestingT, dgstMap map[string]digest.Digest) (blob []tarEntry) {
|
||||
return tarOf(
|
||||
dir("test/"),
|
||||
)
|
||||
@@ -559,7 +589,7 @@ func testDigestAndVerify(t *testing.T, controllers ...TestingControllerFactory)
|
||||
},
|
||||
{
|
||||
name: "small-files",
|
||||
tarInit: func(t *testing.T, dgstMap map[string]digest.Digest) (blob []tarEntry) {
|
||||
tarInit: func(t TestingT, dgstMap map[string]digest.Digest) (blob []tarEntry) {
|
||||
return tarOf(
|
||||
regDigest(t, "baz.txt", "", dgstMap),
|
||||
regDigest(t, "foo.txt", "a", dgstMap),
|
||||
@@ -583,7 +613,7 @@ func testDigestAndVerify(t *testing.T, controllers ...TestingControllerFactory)
|
||||
},
|
||||
{
|
||||
name: "big-files",
|
||||
tarInit: func(t *testing.T, dgstMap map[string]digest.Digest) (blob []tarEntry) {
|
||||
tarInit: func(t TestingT, dgstMap map[string]digest.Digest) (blob []tarEntry) {
|
||||
return tarOf(
|
||||
regDigest(t, "baz.txt", "bazbazbazbazbazbazbaz", dgstMap),
|
||||
regDigest(t, "foo.txt", "a", dgstMap),
|
||||
@@ -607,7 +637,7 @@ func testDigestAndVerify(t *testing.T, controllers ...TestingControllerFactory)
|
||||
{
|
||||
name: "with-non-regfiles",
|
||||
minChunkSize: []int{0, 64000},
|
||||
tarInit: func(t *testing.T, dgstMap map[string]digest.Digest) (blob []tarEntry) {
|
||||
tarInit: func(t TestingT, dgstMap map[string]digest.Digest) (blob []tarEntry) {
|
||||
return tarOf(
|
||||
regDigest(t, "baz.txt", "bazbazbazbazbazbazbaz", dgstMap),
|
||||
regDigest(t, "foo.txt", "a", dgstMap),
|
||||
@@ -654,7 +684,7 @@ func testDigestAndVerify(t *testing.T, controllers ...TestingControllerFactory)
|
||||
srcTarFormat := srcTarFormat
|
||||
for _, minChunkSize := range tt.minChunkSize {
|
||||
minChunkSize := minChunkSize
|
||||
t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,format=%s,minChunkSize=%d", newCL(), prefix, srcTarFormat, minChunkSize), func(t *testing.T) {
|
||||
t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,format=%s,minChunkSize=%d", newCL(), prefix, srcTarFormat, minChunkSize), func(t *TestRunner) {
|
||||
// Get original tar file and chunk digests
|
||||
dgstMap := make(map[string]digest.Digest)
|
||||
tarBlob := buildTar(t, tt.tarInit(t, dgstMap), prefix, srcTarFormat)
|
||||
@@ -690,7 +720,7 @@ func testDigestAndVerify(t *testing.T, controllers ...TestingControllerFactory)
|
||||
// checkStargzTOC checks the TOC JSON of the passed stargz has the expected
|
||||
// digest and contains valid chunks. It walks all entries in the stargz and
|
||||
// checks all chunk digests stored to the TOC JSON match the actual contents.
|
||||
func checkStargzTOC(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
|
||||
func checkStargzTOC(t *TestRunner, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
|
||||
sgz, err := Open(
|
||||
io.NewSectionReader(bytes.NewReader(sgzData), 0, int64(len(sgzData))),
|
||||
WithDecompressors(controller),
|
||||
@@ -801,7 +831,7 @@ func checkStargzTOC(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstM
|
||||
// checkVerifyTOC checks the verification works for the TOC JSON of the passed
|
||||
// stargz. It walks all entries in the stargz and checks the verifications for
|
||||
// all chunks work.
|
||||
func checkVerifyTOC(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
|
||||
func checkVerifyTOC(t *TestRunner, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
|
||||
sgz, err := Open(
|
||||
io.NewSectionReader(bytes.NewReader(sgzData), 0, int64(len(sgzData))),
|
||||
WithDecompressors(controller),
|
||||
@@ -882,9 +912,9 @@ func checkVerifyTOC(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstM
|
||||
// checkVerifyInvalidTOCEntryFail checks if misconfigured TOC JSON can be
|
||||
// detected during the verification and the verification returns an error.
|
||||
func checkVerifyInvalidTOCEntryFail(filename string) check {
|
||||
return func(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
|
||||
return func(t *TestRunner, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
|
||||
funcs := map[string]rewriteFunc{
|
||||
"lost digest in a entry": func(t *testing.T, toc *JTOC, sgz *io.SectionReader) {
|
||||
"lost digest in a entry": func(t TestingT, toc *JTOC, sgz *io.SectionReader) {
|
||||
var found bool
|
||||
for _, e := range toc.Entries {
|
||||
if cleanEntryName(e.Name) == filename {
|
||||
@@ -902,7 +932,7 @@ func checkVerifyInvalidTOCEntryFail(filename string) check {
|
||||
t.Fatalf("rewrite target not found")
|
||||
}
|
||||
},
|
||||
"duplicated entry offset": func(t *testing.T, toc *JTOC, sgz *io.SectionReader) {
|
||||
"duplicated entry offset": func(t TestingT, toc *JTOC, sgz *io.SectionReader) {
|
||||
var (
|
||||
sampleEntry *TOCEntry
|
||||
targetEntry *TOCEntry
|
||||
@@ -929,7 +959,7 @@ func checkVerifyInvalidTOCEntryFail(filename string) check {
|
||||
}
|
||||
|
||||
for name, rFunc := range funcs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Run(name, func(t *TestRunner) {
|
||||
newSgz, newTocDigest := rewriteTOCJSON(t, io.NewSectionReader(bytes.NewReader(sgzData), 0, int64(len(sgzData))), rFunc, controller)
|
||||
buf := new(bytes.Buffer)
|
||||
if _, err := io.Copy(buf, newSgz); err != nil {
|
||||
@@ -958,7 +988,7 @@ func checkVerifyInvalidTOCEntryFail(filename string) check {
|
||||
// checkVerifyInvalidStargzFail checks if the verification detects that the
|
||||
// given stargz file doesn't match to the expected digest and returns error.
|
||||
func checkVerifyInvalidStargzFail(invalid *io.SectionReader) check {
|
||||
return func(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
|
||||
return func(t *TestRunner, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
|
||||
cl := newController()
|
||||
rc, err := Build(invalid, WithChunkSize(chunkSize), WithCompression(cl))
|
||||
if err != nil {
|
||||
@@ -990,7 +1020,7 @@ func checkVerifyInvalidStargzFail(invalid *io.SectionReader) check {
|
||||
// checkVerifyBrokenContentFail checks if the verifier detects broken contents
|
||||
// that doesn't match to the expected digest and returns error.
|
||||
func checkVerifyBrokenContentFail(filename string) check {
|
||||
return func(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
|
||||
return func(t *TestRunner, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
|
||||
// Parse stargz file
|
||||
sgz, err := Open(
|
||||
io.NewSectionReader(bytes.NewReader(sgzData), 0, int64(len(sgzData))),
|
||||
@@ -1047,9 +1077,9 @@ func chunkID(name string, offset, size int64) string {
|
||||
return fmt.Sprintf("%s-%d-%d", cleanEntryName(name), offset, size)
|
||||
}
|
||||
|
||||
type rewriteFunc func(t *testing.T, toc *JTOC, sgz *io.SectionReader)
|
||||
type rewriteFunc func(t TestingT, toc *JTOC, sgz *io.SectionReader)
|
||||
|
||||
func rewriteTOCJSON(t *testing.T, sgz *io.SectionReader, rewrite rewriteFunc, controller TestingController) (newSgz io.Reader, tocDigest digest.Digest) {
|
||||
func rewriteTOCJSON(t TestingT, sgz *io.SectionReader, rewrite rewriteFunc, controller TestingController) (newSgz io.Reader, tocDigest digest.Digest) {
|
||||
decodedJTOC, jtocOffset, err := parseStargz(sgz, controller)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to extract TOC JSON: %v", err)
|
||||
@@ -1120,7 +1150,7 @@ func parseStargz(sgz *io.SectionReader, controller TestingController) (decodedJT
|
||||
return decodedJTOC, tocOffset, nil
|
||||
}
|
||||
|
||||
func testWriteAndOpen(t *testing.T, controllers ...TestingControllerFactory) {
|
||||
func testWriteAndOpen(t *TestRunner, controllers ...TestingControllerFactory) {
|
||||
const content = "Some contents"
|
||||
invalidUtf8 := "\xff\xfe\xfd"
|
||||
|
||||
@@ -1464,7 +1494,7 @@ func testWriteAndOpen(t *testing.T, controllers ...TestingControllerFactory) {
|
||||
for _, srcTarFormat := range []tar.Format{tar.FormatUSTAR, tar.FormatPAX, tar.FormatGNU} {
|
||||
srcTarFormat := srcTarFormat
|
||||
for _, lossless := range []bool{true, false} {
|
||||
t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,lossless=%v,format=%s", newCL(), prefix, lossless, srcTarFormat), func(t *testing.T) {
|
||||
t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,lossless=%v,format=%s", newCL(), prefix, lossless, srcTarFormat), func(t *TestRunner) {
|
||||
var tr io.Reader = buildTar(t, tt.in, prefix, srcTarFormat)
|
||||
origTarDgstr := digest.Canonical.Digester()
|
||||
tr = io.TeeReader(tr, origTarDgstr.Hash())
|
||||
@@ -1530,6 +1560,9 @@ func testWriteAndOpen(t *testing.T, controllers ...TestingControllerFactory) {
|
||||
if err != nil {
|
||||
t.Fatalf("stargz.Open: %v", err)
|
||||
}
|
||||
if _, ok := r.Lookup(""); !ok {
|
||||
t.Fatalf("failed to lookup rootdir: %v", err)
|
||||
}
|
||||
wantTOCVersion := 1
|
||||
if tt.wantTOCVersion > 0 {
|
||||
wantTOCVersion = tt.wantTOCVersion
|
||||
@@ -1628,7 +1661,7 @@ func digestFor(content string) string {
|
||||
|
||||
type numTOCEntries int
|
||||
|
||||
func (n numTOCEntries) check(t *testing.T, r *Reader) {
|
||||
func (n numTOCEntries) check(t TestingT, r *Reader) {
|
||||
if r.toc == nil {
|
||||
t.Fatal("nil TOC")
|
||||
}
|
||||
@@ -1648,15 +1681,15 @@ func (n numTOCEntries) check(t *testing.T, r *Reader) {
|
||||
func checks(s ...stargzCheck) []stargzCheck { return s }
|
||||
|
||||
type stargzCheck interface {
|
||||
check(t *testing.T, r *Reader)
|
||||
check(t TestingT, r *Reader)
|
||||
}
|
||||
|
||||
type stargzCheckFn func(*testing.T, *Reader)
|
||||
type stargzCheckFn func(TestingT, *Reader)
|
||||
|
||||
func (f stargzCheckFn) check(t *testing.T, r *Reader) { f(t, r) }
|
||||
func (f stargzCheckFn) check(t TestingT, r *Reader) { f(t, r) }
|
||||
|
||||
func maxDepth(max int) stargzCheck {
|
||||
return stargzCheckFn(func(t *testing.T, r *Reader) {
|
||||
return stargzCheckFn(func(t TestingT, r *Reader) {
|
||||
e, ok := r.Lookup("")
|
||||
if !ok {
|
||||
t.Fatal("root directory not found")
|
||||
@@ -1673,7 +1706,7 @@ func maxDepth(max int) stargzCheck {
|
||||
})
|
||||
}
|
||||
|
||||
func getMaxDepth(t *testing.T, e *TOCEntry, current, limit int) (max int, rErr error) {
|
||||
func getMaxDepth(t TestingT, e *TOCEntry, current, limit int) (max int, rErr error) {
|
||||
if current > limit {
|
||||
return -1, fmt.Errorf("walkMaxDepth: exceeds limit: current:%d > limit:%d",
|
||||
current, limit)
|
||||
@@ -1695,7 +1728,7 @@ func getMaxDepth(t *testing.T, e *TOCEntry, current, limit int) (max int, rErr e
|
||||
}
|
||||
|
||||
func hasFileLen(file string, wantLen int) stargzCheck {
|
||||
return stargzCheckFn(func(t *testing.T, r *Reader) {
|
||||
return stargzCheckFn(func(t TestingT, r *Reader) {
|
||||
for _, ent := range r.toc.Entries {
|
||||
if ent.Name == file {
|
||||
if ent.Type != "reg" {
|
||||
@@ -1711,7 +1744,7 @@ func hasFileLen(file string, wantLen int) stargzCheck {
|
||||
}
|
||||
|
||||
func hasFileXattrs(file, name, value string) stargzCheck {
|
||||
return stargzCheckFn(func(t *testing.T, r *Reader) {
|
||||
return stargzCheckFn(func(t TestingT, r *Reader) {
|
||||
for _, ent := range r.toc.Entries {
|
||||
if ent.Name == file {
|
||||
if ent.Type != "reg" {
|
||||
@@ -1738,7 +1771,7 @@ func hasFileXattrs(file, name, value string) stargzCheck {
|
||||
}
|
||||
|
||||
func hasFileDigest(file string, digest string) stargzCheck {
|
||||
return stargzCheckFn(func(t *testing.T, r *Reader) {
|
||||
return stargzCheckFn(func(t TestingT, r *Reader) {
|
||||
ent, ok := r.Lookup(file)
|
||||
if !ok {
|
||||
t.Fatalf("didn't find TOCEntry for file %q", file)
|
||||
@@ -1750,7 +1783,7 @@ func hasFileDigest(file string, digest string) stargzCheck {
|
||||
}
|
||||
|
||||
func hasFileContentsWithPreRead(file string, offset int, want string, extra ...chunkInfo) stargzCheck {
|
||||
return stargzCheckFn(func(t *testing.T, r *Reader) {
|
||||
return stargzCheckFn(func(t TestingT, r *Reader) {
|
||||
extraMap := make(map[string]chunkInfo)
|
||||
for _, e := range extra {
|
||||
extraMap[e.name] = e
|
||||
@@ -1797,7 +1830,7 @@ func hasFileContentsWithPreRead(file string, offset int, want string, extra ...c
|
||||
}
|
||||
|
||||
func hasFileContentsRange(file string, offset int, want string) stargzCheck {
|
||||
return stargzCheckFn(func(t *testing.T, r *Reader) {
|
||||
return stargzCheckFn(func(t TestingT, r *Reader) {
|
||||
f, err := r.OpenFile(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -1814,7 +1847,7 @@ func hasFileContentsRange(file string, offset int, want string) stargzCheck {
|
||||
}
|
||||
|
||||
func hasChunkEntries(file string, wantChunks int) stargzCheck {
|
||||
return stargzCheckFn(func(t *testing.T, r *Reader) {
|
||||
return stargzCheckFn(func(t TestingT, r *Reader) {
|
||||
ent, ok := r.Lookup(file)
|
||||
if !ok {
|
||||
t.Fatalf("no file for %q", file)
|
||||
@@ -1858,7 +1891,7 @@ func hasChunkEntries(file string, wantChunks int) stargzCheck {
|
||||
}
|
||||
|
||||
func entryHasChildren(dir string, want ...string) stargzCheck {
|
||||
return stargzCheckFn(func(t *testing.T, r *Reader) {
|
||||
return stargzCheckFn(func(t TestingT, r *Reader) {
|
||||
want := append([]string(nil), want...)
|
||||
var got []string
|
||||
ent, ok := r.Lookup(dir)
|
||||
@@ -1877,7 +1910,7 @@ func entryHasChildren(dir string, want ...string) stargzCheck {
|
||||
}
|
||||
|
||||
func hasDir(file string) stargzCheck {
|
||||
return stargzCheckFn(func(t *testing.T, r *Reader) {
|
||||
return stargzCheckFn(func(t TestingT, r *Reader) {
|
||||
for _, ent := range r.toc.Entries {
|
||||
if ent.Name == cleanEntryName(file) {
|
||||
if ent.Type != "dir" {
|
||||
@@ -1891,7 +1924,7 @@ func hasDir(file string) stargzCheck {
|
||||
}
|
||||
|
||||
func hasDirLinkCount(file string, count int) stargzCheck {
|
||||
return stargzCheckFn(func(t *testing.T, r *Reader) {
|
||||
return stargzCheckFn(func(t TestingT, r *Reader) {
|
||||
for _, ent := range r.toc.Entries {
|
||||
if ent.Name == cleanEntryName(file) {
|
||||
if ent.Type != "dir" {
|
||||
@@ -1909,7 +1942,7 @@ func hasDirLinkCount(file string, count int) stargzCheck {
|
||||
}
|
||||
|
||||
func hasMode(file string, mode os.FileMode) stargzCheck {
|
||||
return stargzCheckFn(func(t *testing.T, r *Reader) {
|
||||
return stargzCheckFn(func(t TestingT, r *Reader) {
|
||||
for _, ent := range r.toc.Entries {
|
||||
if ent.Name == cleanEntryName(file) {
|
||||
if ent.Stat().Mode() != mode {
|
||||
@@ -1924,7 +1957,7 @@ func hasMode(file string, mode os.FileMode) stargzCheck {
|
||||
}
|
||||
|
||||
func hasSymlink(file, target string) stargzCheck {
|
||||
return stargzCheckFn(func(t *testing.T, r *Reader) {
|
||||
return stargzCheckFn(func(t TestingT, r *Reader) {
|
||||
for _, ent := range r.toc.Entries {
|
||||
if ent.Name == file {
|
||||
if ent.Type != "symlink" {
|
||||
@@ -1940,7 +1973,7 @@ func hasSymlink(file, target string) stargzCheck {
|
||||
}
|
||||
|
||||
func lookupMatch(name string, want *TOCEntry) stargzCheck {
|
||||
return stargzCheckFn(func(t *testing.T, r *Reader) {
|
||||
return stargzCheckFn(func(t TestingT, r *Reader) {
|
||||
e, ok := r.Lookup(name)
|
||||
if !ok {
|
||||
t.Fatalf("failed to Lookup entry %q", name)
|
||||
@@ -1953,7 +1986,7 @@ func lookupMatch(name string, want *TOCEntry) stargzCheck {
|
||||
}
|
||||
|
||||
func hasEntryOwner(entry string, owner owner) stargzCheck {
|
||||
return stargzCheckFn(func(t *testing.T, r *Reader) {
|
||||
return stargzCheckFn(func(t TestingT, r *Reader) {
|
||||
ent, ok := r.Lookup(strings.TrimSuffix(entry, "/"))
|
||||
if !ok {
|
||||
t.Errorf("entry %q not found", entry)
|
||||
@@ -1967,7 +2000,7 @@ func hasEntryOwner(entry string, owner owner) stargzCheck {
|
||||
}
|
||||
|
||||
func mustSameEntry(files ...string) stargzCheck {
|
||||
return stargzCheckFn(func(t *testing.T, r *Reader) {
|
||||
return stargzCheckFn(func(t TestingT, r *Reader) {
|
||||
var first *TOCEntry
|
||||
for _, f := range files {
|
||||
if first == nil {
|
||||
@@ -2039,7 +2072,7 @@ func (f tarEntryFunc) appendTar(tw *tar.Writer, prefix string, format tar.Format
|
||||
return f(tw, prefix, format)
|
||||
}
|
||||
|
||||
func buildTar(t *testing.T, ents []tarEntry, prefix string, opts ...interface{}) *io.SectionReader {
|
||||
func buildTar(t TestingT, ents []tarEntry, prefix string, opts ...interface{}) *io.SectionReader {
|
||||
format := tar.FormatUnknown
|
||||
for _, opt := range opts {
|
||||
switch v := opt.(type) {
|
||||
@@ -2248,7 +2281,7 @@ func noPrefetchLandmark() tarEntry {
|
||||
})
|
||||
}
|
||||
|
||||
func regDigest(t *testing.T, name string, contentStr string, digestMap map[string]digest.Digest) tarEntry {
|
||||
func regDigest(t TestingT, name string, contentStr string, digestMap map[string]digest.Digest) tarEntry {
|
||||
if digestMap == nil {
|
||||
t.Fatalf("digest map mustn't be nil")
|
||||
}
|
||||
@@ -2318,7 +2351,7 @@ func (f fileInfoOnlyMode) ModTime() time.Time { return time.Now() }
|
||||
func (f fileInfoOnlyMode) IsDir() bool { return os.FileMode(f).IsDir() }
|
||||
func (f fileInfoOnlyMode) Sys() interface{} { return nil }
|
||||
|
||||
func CheckGzipHasStreams(t *testing.T, b []byte, streams []int64) {
|
||||
func CheckGzipHasStreams(t TestingT, b []byte, streams []int64) {
|
||||
if len(streams) == 0 {
|
||||
return // nop
|
||||
}
|
||||
@@ -2356,7 +2389,7 @@ func CheckGzipHasStreams(t *testing.T, b []byte, streams []int64) {
|
||||
}
|
||||
}
|
||||
|
||||
func GzipDiffIDOf(t *testing.T, b []byte) string {
|
||||
func GzipDiffIDOf(t TestingT, b []byte) string {
|
||||
h := sha256.New()
|
||||
zr, err := gzip.NewReader(bytes.NewReader(b))
|
||||
if err != nil {
|
||||
|
||||
4
vendor/github.com/cyphar/filepath-securejoin/.golangci.yml
generated
vendored
4
vendor/github.com/cyphar/filepath-securejoin/.golangci.yml
generated
vendored
@@ -9,6 +9,10 @@
|
||||
|
||||
version: "2"
|
||||
|
||||
run:
|
||||
build-tags:
|
||||
- libpathrs
|
||||
|
||||
linters:
|
||||
enable:
|
||||
- asasalint
|
||||
|
||||
62
vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md
generated
vendored
62
vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md
generated
vendored
@@ -4,7 +4,64 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [Unreleased 0.5.z] ##
|
||||
## [Unreleased] ##
|
||||
|
||||
## [0.6.0] - 2025-11-03 ##
|
||||
|
||||
> By the Power of Greyskull!
|
||||
|
||||
While quite small code-wise, this release marks a very key point in the
|
||||
development of filepath-securejoin.
|
||||
|
||||
filepath-securejoin was originally intended (back in 2017) to simply be a
|
||||
single-purpose library that would take some common code used in container
|
||||
runtimes (specifically, Docker's `FollowSymlinksInScope`) and make it more
|
||||
general-purpose (with the eventual goals of it ending up in the Go stdlib).
|
||||
|
||||
Of course, I quickly discovered that this problem was actually far more
|
||||
complicated to solve when dealing with racing attackers, which lead to me
|
||||
developing `openat2(2)` and [libpathrs][]. I had originally planned for
|
||||
libpathrs to completely replace filepath-securejoin "once it was ready" but in
|
||||
the interim we needed to fix several race attacks in runc as part of security
|
||||
advisories. Obviously we couldn't require the usage of a pre-0.1 Rust library
|
||||
in runc so it was necessary to port bits of libpathrs into filepath-securejoin.
|
||||
(Ironically the first prototypes of libpathrs were originally written in Go and
|
||||
then rewritten to Rust, so the code in filepath-securejoin is actually Go code
|
||||
that was rewritten to Rust then re-rewritten to Go.)
|
||||
|
||||
It then became clear that pure-Go libraries will likely not be willing to
|
||||
require CGo for all of their builds, so it was necessary to accept that
|
||||
filepath-securejoin will need to stay. As such, in v0.5.0 we provided more
|
||||
pure-Go implementations of features from libpathrs but moved them into
|
||||
`pathrs-lite` subpackage to clarify what purpose these helpers serve.
|
||||
|
||||
This release finally closes the loop and makes it so that pathrs-lite can
|
||||
transparently use libpathrs (via a `libpathrs` build-tag). This means that
|
||||
upstream libraries can use the pure Go version if they prefer, but downstreams
|
||||
(either downstream library users or even downstream distributions) are able to
|
||||
migrate to libpathrs for all usages of pathrs-lite in an entire Go binary.
|
||||
|
||||
I should make it clear that I do not plan to port the rest of libpathrs to Go,
|
||||
as I do not wish to maintain two copies of the same codebase. pathrs-lite
|
||||
already provides the core essentials necessary to operate on paths safely for
|
||||
most modern systems. Users who want additional hardening or more ergonomic APIs
|
||||
are free to use [`cyphar.com/go-pathrs`][go-pathrs] (libpathrs's Go bindings).
|
||||
|
||||
[libpathrs]: https://github.com/cyphar/libpathrs
|
||||
[go-pathrs]: https://cyphar.com/go-pathrs
|
||||
|
||||
### Breaking ###
|
||||
- The deprecated `MkdirAll`, `MkdirAllHandle`, `OpenInRoot`, `OpenatInRoot` and
|
||||
`Reopen` wrappers have been removed. Please switch to using `pathrs-lite`
|
||||
directly.
|
||||
|
||||
### Added ###
|
||||
- `pathrs-lite` now has support for using [libpathrs][libpathrs] as a backend.
|
||||
This is opt-in and can be enabled at build time with the `libpathrs` build
|
||||
tag. The intention is to allow for downstream libraries and other projects to
|
||||
make use of the pure-Go `github.com/cyphar/filepath-securejoin/pathrs-lite`
|
||||
package and distributors can then opt-in to using `libpathrs` for the entire
|
||||
binary if they wish.
|
||||
|
||||
## [0.5.1] - 2025-10-31 ##
|
||||
|
||||
@@ -383,7 +440,8 @@ This is our first release of `github.com/cyphar/filepath-securejoin`,
|
||||
containing a full implementation with a coverage of 93.5% (the only missing
|
||||
cases are the error cases, which are hard to mocktest at the moment).
|
||||
|
||||
[Unreleased 0.5.z]: https://github.com/cyphar/filepath-securejoin/compare/v0.5.1...release-0.5
|
||||
[Unreleased]: https://github.com/cyphar/filepath-securejoin/compare/v0.6.0...HEAD
|
||||
[0.6.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.5.1...v0.6.0
|
||||
[0.5.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.5.0...v0.5.1
|
||||
[0.5.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.4.1...v0.5.0
|
||||
[0.4.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.4.0...v0.4.1
|
||||
|
||||
2
vendor/github.com/cyphar/filepath-securejoin/VERSION
generated
vendored
2
vendor/github.com/cyphar/filepath-securejoin/VERSION
generated
vendored
@@ -1 +1 @@
|
||||
0.5.1
|
||||
0.6.0
|
||||
|
||||
48
vendor/github.com/cyphar/filepath-securejoin/deprecated_linux.go
generated
vendored
48
vendor/github.com/cyphar/filepath-securejoin/deprecated_linux.go
generated
vendored
@@ -1,48 +0,0 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//go:build linux
|
||||
|
||||
// Copyright (C) 2024-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||
// Copyright (C) 2024-2025 SUSE LLC
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package securejoin
|
||||
|
||||
import (
|
||||
"github.com/cyphar/filepath-securejoin/pathrs-lite"
|
||||
)
|
||||
|
||||
var (
|
||||
// MkdirAll is a wrapper around [pathrs.MkdirAll].
|
||||
//
|
||||
// Deprecated: You should use [pathrs.MkdirAll] directly instead. This
|
||||
// wrapper will be removed in filepath-securejoin v0.6.
|
||||
MkdirAll = pathrs.MkdirAll
|
||||
|
||||
// MkdirAllHandle is a wrapper around [pathrs.MkdirAllHandle].
|
||||
//
|
||||
// Deprecated: You should use [pathrs.MkdirAllHandle] directly instead.
|
||||
// This wrapper will be removed in filepath-securejoin v0.6.
|
||||
MkdirAllHandle = pathrs.MkdirAllHandle
|
||||
|
||||
// OpenInRoot is a wrapper around [pathrs.OpenInRoot].
|
||||
//
|
||||
// Deprecated: You should use [pathrs.OpenInRoot] directly instead. This
|
||||
// wrapper will be removed in filepath-securejoin v0.6.
|
||||
OpenInRoot = pathrs.OpenInRoot
|
||||
|
||||
// OpenatInRoot is a wrapper around [pathrs.OpenatInRoot].
|
||||
//
|
||||
// Deprecated: You should use [pathrs.OpenatInRoot] directly instead. This
|
||||
// wrapper will be removed in filepath-securejoin v0.6.
|
||||
OpenatInRoot = pathrs.OpenatInRoot
|
||||
|
||||
// Reopen is a wrapper around [pathrs.Reopen].
|
||||
//
|
||||
// Deprecated: You should use [pathrs.Reopen] directly instead. This
|
||||
// wrapper will be removed in filepath-securejoin v0.6.
|
||||
Reopen = pathrs.Reopen
|
||||
)
|
||||
12
vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/README.md
generated
vendored
12
vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/README.md
generated
vendored
@@ -5,11 +5,13 @@ Go** implementation of the core bits of [libpathrs][]. This is not intended to
|
||||
be a complete replacement for libpathrs, instead it is mainly intended to be
|
||||
useful as a transition tool for existing Go projects.
|
||||
|
||||
The long-term plan for `pathrs-lite` is to provide a build tag that will cause
|
||||
all `pathrs-lite` operations to call into libpathrs directly, thus removing
|
||||
code duplication for projects that wish to make use of libpathrs (and providing
|
||||
the ability for software packagers to opt-in to libpathrs support without
|
||||
needing to patch upstream).
|
||||
`pathrs-lite` also provides a very easy way to switch to `libpathrs` (even for
|
||||
downstreams where `pathrs-lite` is being used in a third-party package and is
|
||||
not interested in using CGo). At build time, if you use the `libpathrs` build
|
||||
tag then `pathrs-lite` will use `libpathrs` directly instead of the pure Go
|
||||
implementation. The two backends are functionally equivalent (and we have
|
||||
integration tests to verify this), so this migration should be very easy with
|
||||
no user-visible impact.
|
||||
|
||||
[libpathrs]: https://github.com/cyphar/libpathrs
|
||||
|
||||
|
||||
2
vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/doc.go
generated
vendored
2
vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/doc.go
generated
vendored
@@ -11,4 +11,6 @@
|
||||
|
||||
// Package pathrs (pathrs-lite) is a less complete pure Go implementation of
|
||||
// some of the APIs provided by [libpathrs].
|
||||
//
|
||||
// [libpathrs]: https://github.com/cyphar/libpathrs
|
||||
package pathrs
|
||||
|
||||
16
vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/doc.go
generated
vendored
Normal file
16
vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/doc.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//go:build linux
|
||||
|
||||
// Copyright (C) 2024-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||
// Copyright (C) 2024-2025 SUSE LLC
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
// Package gopathrs is a less complete pure Go implementation of some of the
|
||||
// APIs provided by [libpathrs].
|
||||
//
|
||||
// [libpathrs]: https://github.com/cyphar/libpathrs
|
||||
package gopathrs
|
||||
@@ -9,7 +9,7 @@
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package pathrs
|
||||
package gopathrs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -166,11 +166,11 @@ func (s *symlinkStack) PopTopSymlink() (*os.File, string, bool) {
|
||||
return tailEntry.dir, tailEntry.remainingPath, true
|
||||
}
|
||||
|
||||
// partialLookupInRoot tries to lookup as much of the request path as possible
|
||||
// PartialLookupInRoot tries to lookup as much of the request path as possible
|
||||
// within the provided root (a-la RESOLVE_IN_ROOT) and opens the final existing
|
||||
// component of the requested path, returning a file handle to the final
|
||||
// existing component and a string containing the remaining path components.
|
||||
func partialLookupInRoot(root fd.Fd, unsafePath string) (*os.File, string, error) {
|
||||
func PartialLookupInRoot(root fd.Fd, unsafePath string) (*os.File, string, error) {
|
||||
return lookupInRoot(root, unsafePath, true)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package pathrs
|
||||
package gopathrs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -23,9 +23,12 @@ import (
|
||||
"github.com/cyphar/filepath-securejoin/pathrs-lite/internal/fd"
|
||||
"github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat"
|
||||
"github.com/cyphar/filepath-securejoin/pathrs-lite/internal/linux"
|
||||
"github.com/cyphar/filepath-securejoin/pathrs-lite/internal/procfs"
|
||||
)
|
||||
|
||||
var errInvalidMode = errors.New("invalid permission mode")
|
||||
// ErrInvalidMode is returned from [MkdirAll] when the requested mode is
|
||||
// invalid.
|
||||
var ErrInvalidMode = errors.New("invalid permission mode")
|
||||
|
||||
// modePermExt is like os.ModePerm except that it also includes the set[ug]id
|
||||
// and sticky bits.
|
||||
@@ -45,11 +48,11 @@ func toUnixMode(mode os.FileMode) (uint32, error) {
|
||||
}
|
||||
// We don't allow file type bits.
|
||||
if mode&os.ModeType != 0 {
|
||||
return 0, fmt.Errorf("%w %+.3o (%s): type bits not permitted", errInvalidMode, mode, mode)
|
||||
return 0, fmt.Errorf("%w %+.3o (%s): type bits not permitted", ErrInvalidMode, mode, mode)
|
||||
}
|
||||
// We don't allow other unknown modes.
|
||||
if mode&^modePermExt != 0 || sysMode&unix.S_IFMT != 0 {
|
||||
return 0, fmt.Errorf("%w %+.3o (%s): unknown mode bits", errInvalidMode, mode, mode)
|
||||
return 0, fmt.Errorf("%w %+.3o (%s): unknown mode bits", ErrInvalidMode, mode, mode)
|
||||
}
|
||||
return sysMode, nil
|
||||
}
|
||||
@@ -84,11 +87,11 @@ func MkdirAllHandle(root *os.File, unsafePath string, mode os.FileMode) (_ *os.F
|
||||
// users it seems more prudent to return an error so users notice that
|
||||
// these bits will not be set.
|
||||
if unixMode&^0o1777 != 0 {
|
||||
return nil, fmt.Errorf("%w for mkdir %+.3o: suid and sgid are ignored by mkdir", errInvalidMode, mode)
|
||||
return nil, fmt.Errorf("%w for mkdir %+.3o: suid and sgid are ignored by mkdir", ErrInvalidMode, mode)
|
||||
}
|
||||
|
||||
// Try to open as much of the path as possible.
|
||||
currentDir, remainingPath, err := partialLookupInRoot(root, unsafePath)
|
||||
currentDir, remainingPath, err := PartialLookupInRoot(root, unsafePath)
|
||||
defer func() {
|
||||
if Err != nil {
|
||||
_ = currentDir.Close()
|
||||
@@ -117,7 +120,7 @@ func MkdirAllHandle(root *os.File, unsafePath string, mode os.FileMode) (_ *os.F
|
||||
// Re-open the path to match the O_DIRECTORY reopen loop later (so that we
|
||||
// always return a non-O_PATH handle). We also check that we actually got a
|
||||
// directory.
|
||||
if reopenDir, err := Reopen(currentDir, unix.O_DIRECTORY|unix.O_CLOEXEC); errors.Is(err, unix.ENOTDIR) {
|
||||
if reopenDir, err := procfs.ReopenFd(currentDir, unix.O_DIRECTORY|unix.O_CLOEXEC); errors.Is(err, unix.ENOTDIR) {
|
||||
return nil, fmt.Errorf("cannot create subdirectories in %q: %w", currentDir.Name(), unix.ENOTDIR)
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("re-opening handle to %q: %w", currentDir.Name(), err)
|
||||
@@ -207,40 +210,3 @@ func MkdirAllHandle(root *os.File, unsafePath string, mode os.FileMode) (_ *os.F
|
||||
}
|
||||
return currentDir, nil
|
||||
}
|
||||
|
||||
// MkdirAll is a race-safe alternative to the [os.MkdirAll] function,
|
||||
// where the new directory is guaranteed to be within the root directory (if an
|
||||
// attacker can move directories from inside the root to outside the root, the
|
||||
// created directory tree might be outside of the root but the key constraint
|
||||
// is that at no point will we walk outside of the directory tree we are
|
||||
// creating).
|
||||
//
|
||||
// Effectively, MkdirAll(root, unsafePath, mode) is equivalent to
|
||||
//
|
||||
// path, _ := securejoin.SecureJoin(root, unsafePath)
|
||||
// err := os.MkdirAll(path, mode)
|
||||
//
|
||||
// But is much safer. The above implementation is unsafe because if an attacker
|
||||
// can modify the filesystem tree between [SecureJoin] and [os.MkdirAll], it is
|
||||
// possible for MkdirAll to resolve unsafe symlink components and create
|
||||
// directories outside of the root.
|
||||
//
|
||||
// If you plan to open the directory after you have created it or want to use
|
||||
// an open directory handle as the root, you should use [MkdirAllHandle] instead.
|
||||
// This function is a wrapper around [MkdirAllHandle].
|
||||
//
|
||||
// [SecureJoin]: https://pkg.go.dev/github.com/cyphar/filepath-securejoin#SecureJoin
|
||||
func MkdirAll(root, unsafePath string, mode os.FileMode) error {
|
||||
rootDir, err := os.OpenFile(root, unix.O_PATH|unix.O_DIRECTORY|unix.O_CLOEXEC, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rootDir.Close() //nolint:errcheck // close failures aren't critical here
|
||||
|
||||
f, err := MkdirAllHandle(rootDir, unsafePath, mode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = f.Close()
|
||||
return nil
|
||||
}
|
||||
26
vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/open_linux.go
generated
vendored
Normal file
26
vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/open_linux.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//go:build linux
|
||||
|
||||
// Copyright (C) 2024-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||
// Copyright (C) 2024-2025 SUSE LLC
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package gopathrs
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// OpenatInRoot is equivalent to [OpenInRoot], except that the root is provided
|
||||
// using an *[os.File] handle, to ensure that the correct root directory is used.
|
||||
func OpenatInRoot(root *os.File, unsafePath string) (*os.File, error) {
|
||||
handle, err := completeLookupInRoot(root, unsafePath)
|
||||
if err != nil {
|
||||
return nil, &os.PathError{Op: "securejoin.OpenInRoot", Path: unsafePath, Err: err}
|
||||
}
|
||||
return handle, nil
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package pathrs
|
||||
package gopathrs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
55
vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/mkdir.go
generated
vendored
Normal file
55
vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/mkdir.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//go:build linux
|
||||
|
||||
// Copyright (C) 2024-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||
// Copyright (C) 2024-2025 SUSE LLC
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package pathrs
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// MkdirAll is a race-safe alternative to the [os.MkdirAll] function,
|
||||
// where the new directory is guaranteed to be within the root directory (if an
|
||||
// attacker can move directories from inside the root to outside the root, the
|
||||
// created directory tree might be outside of the root but the key constraint
|
||||
// is that at no point will we walk outside of the directory tree we are
|
||||
// creating).
|
||||
//
|
||||
// Effectively, MkdirAll(root, unsafePath, mode) is equivalent to
|
||||
//
|
||||
// path, _ := securejoin.SecureJoin(root, unsafePath)
|
||||
// err := os.MkdirAll(path, mode)
|
||||
//
|
||||
// But is much safer. The above implementation is unsafe because if an attacker
|
||||
// can modify the filesystem tree between [SecureJoin] and [os.MkdirAll], it is
|
||||
// possible for MkdirAll to resolve unsafe symlink components and create
|
||||
// directories outside of the root.
|
||||
//
|
||||
// If you plan to open the directory after you have created it or want to use
|
||||
// an open directory handle as the root, you should use [MkdirAllHandle] instead.
|
||||
// This function is a wrapper around [MkdirAllHandle].
|
||||
//
|
||||
// [SecureJoin]: https://pkg.go.dev/github.com/cyphar/filepath-securejoin#SecureJoin
|
||||
func MkdirAll(root, unsafePath string, mode os.FileMode) error {
|
||||
rootDir, err := os.OpenFile(root, unix.O_PATH|unix.O_DIRECTORY|unix.O_CLOEXEC, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rootDir.Close() //nolint:errcheck // close failures aren't critical here
|
||||
|
||||
f, err := MkdirAllHandle(rootDir, unsafePath, mode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = f.Close()
|
||||
return nil
|
||||
}
|
||||
52
vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/mkdir_libpathrs.go
generated
vendored
Normal file
52
vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/mkdir_libpathrs.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//go:build libpathrs
|
||||
|
||||
// Copyright (C) 2024-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||
// Copyright (C) 2024-2025 SUSE LLC
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package pathrs
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"cyphar.com/go-pathrs"
|
||||
)
|
||||
|
||||
// MkdirAllHandle is equivalent to [MkdirAll], except that it is safer to use
|
||||
// in two respects:
|
||||
//
|
||||
// - The caller provides the root directory as an *[os.File] (preferably O_PATH)
|
||||
// handle. This means that the caller can be sure which root directory is
|
||||
// being used. Note that this can be emulated by using /proc/self/fd/... as
|
||||
// the root path with [os.MkdirAll].
|
||||
//
|
||||
// - Once all of the directories have been created, an *[os.File] O_PATH handle
|
||||
// to the directory at unsafePath is returned to the caller. This is done in
|
||||
// an effectively-race-free way (an attacker would only be able to swap the
|
||||
// final directory component), which is not possible to emulate with
|
||||
// [MkdirAll].
|
||||
//
|
||||
// In addition, the returned handle is obtained far more efficiently than doing
|
||||
// a brand new lookup of unsafePath (such as with [SecureJoin] or openat2) after
|
||||
// doing [MkdirAll]. If you intend to open the directory after creating it, you
|
||||
// should use MkdirAllHandle.
|
||||
//
|
||||
// [SecureJoin]: https://pkg.go.dev/github.com/cyphar/filepath-securejoin#SecureJoin
|
||||
func MkdirAllHandle(root *os.File, unsafePath string, mode os.FileMode) (*os.File, error) {
|
||||
rootRef, err := pathrs.RootFromFile(root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rootRef.Close() //nolint:errcheck // close failures aren't critical here
|
||||
|
||||
handle, err := rootRef.MkdirAll(unsafePath, mode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handle.IntoFile(), nil
|
||||
}
|
||||
42
vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/mkdir_purego.go
generated
vendored
Normal file
42
vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/mkdir_purego.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//go:build linux && !libpathrs
|
||||
|
||||
// Copyright (C) 2024-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||
// Copyright (C) 2024-2025 SUSE LLC
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package pathrs
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs"
|
||||
)
|
||||
|
||||
// MkdirAllHandle is equivalent to [MkdirAll], except that it is safer to use
|
||||
// in two respects:
|
||||
//
|
||||
// - The caller provides the root directory as an *[os.File] (preferably O_PATH)
|
||||
// handle. This means that the caller can be sure which root directory is
|
||||
// being used. Note that this can be emulated by using /proc/self/fd/... as
|
||||
// the root path with [os.MkdirAll].
|
||||
//
|
||||
// - Once all of the directories have been created, an *[os.File] O_PATH handle
|
||||
// to the directory at unsafePath is returned to the caller. This is done in
|
||||
// an effectively-race-free way (an attacker would only be able to swap the
|
||||
// final directory component), which is not possible to emulate with
|
||||
// [MkdirAll].
|
||||
//
|
||||
// In addition, the returned handle is obtained far more efficiently than doing
|
||||
// a brand new lookup of unsafePath (such as with [SecureJoin] or openat2) after
|
||||
// doing [MkdirAll]. If you intend to open the directory after creating it, you
|
||||
// should use MkdirAllHandle.
|
||||
//
|
||||
// [SecureJoin]: https://pkg.go.dev/github.com/cyphar/filepath-securejoin#SecureJoin
|
||||
func MkdirAllHandle(root *os.File, unsafePath string, mode os.FileMode) (*os.File, error) {
|
||||
return gopathrs.MkdirAllHandle(root, unsafePath, mode)
|
||||
}
|
||||
@@ -15,20 +15,8 @@ import (
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/cyphar/filepath-securejoin/pathrs-lite/internal/procfs"
|
||||
)
|
||||
|
||||
// OpenatInRoot is equivalent to [OpenInRoot], except that the root is provided
|
||||
// using an *[os.File] handle, to ensure that the correct root directory is used.
|
||||
func OpenatInRoot(root *os.File, unsafePath string) (*os.File, error) {
|
||||
handle, err := completeLookupInRoot(root, unsafePath)
|
||||
if err != nil {
|
||||
return nil, &os.PathError{Op: "securejoin.OpenInRoot", Path: unsafePath, Err: err}
|
||||
}
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
// OpenInRoot safely opens the provided unsafePath within the root.
|
||||
// Effectively, OpenInRoot(root, unsafePath) is equivalent to
|
||||
//
|
||||
@@ -55,20 +43,3 @@ func OpenInRoot(root, unsafePath string) (*os.File, error) {
|
||||
defer rootDir.Close() //nolint:errcheck // close failures aren't critical here
|
||||
return OpenatInRoot(rootDir, unsafePath)
|
||||
}
|
||||
|
||||
// Reopen takes an *[os.File] handle and re-opens it through /proc/self/fd.
|
||||
// Reopen(file, flags) is effectively equivalent to
|
||||
//
|
||||
// fdPath := fmt.Sprintf("/proc/self/fd/%d", file.Fd())
|
||||
// os.OpenFile(fdPath, flags|unix.O_CLOEXEC)
|
||||
//
|
||||
// But with some extra hardenings to ensure that we are not tricked by a
|
||||
// maliciously-configured /proc mount. While this attack scenario is not
|
||||
// common, in container runtimes it is possible for higher-level runtimes to be
|
||||
// tricked into configuring an unsafe /proc that can be used to attack file
|
||||
// operations. See [CVE-2019-19921] for more details.
|
||||
//
|
||||
// [CVE-2019-19921]: https://github.com/advisories/GHSA-fh74-hm69-rqjw
|
||||
func Reopen(handle *os.File, flags int) (*os.File, error) {
|
||||
return procfs.ReopenFd(handle, flags)
|
||||
}
|
||||
57
vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/open_libpathrs.go
generated
vendored
Normal file
57
vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/open_libpathrs.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//go:build libpathrs
|
||||
|
||||
// Copyright (C) 2024-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||
// Copyright (C) 2024-2025 SUSE LLC
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package pathrs
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"cyphar.com/go-pathrs"
|
||||
)
|
||||
|
||||
// OpenatInRoot is equivalent to [OpenInRoot], except that the root is provided
|
||||
// using an *[os.File] handle, to ensure that the correct root directory is used.
|
||||
func OpenatInRoot(root *os.File, unsafePath string) (*os.File, error) {
|
||||
rootRef, err := pathrs.RootFromFile(root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rootRef.Close() //nolint:errcheck // close failures aren't critical here
|
||||
|
||||
handle, err := rootRef.Resolve(unsafePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handle.IntoFile(), nil
|
||||
}
|
||||
|
||||
// Reopen takes an *[os.File] handle and re-opens it through /proc/self/fd.
|
||||
// Reopen(file, flags) is effectively equivalent to
|
||||
//
|
||||
// fdPath := fmt.Sprintf("/proc/self/fd/%d", file.Fd())
|
||||
// os.OpenFile(fdPath, flags|unix.O_CLOEXEC)
|
||||
//
|
||||
// But with some extra hardenings to ensure that we are not tricked by a
|
||||
// maliciously-configured /proc mount. While this attack scenario is not
|
||||
// common, in container runtimes it is possible for higher-level runtimes to be
|
||||
// tricked into configuring an unsafe /proc that can be used to attack file
|
||||
// operations. See [CVE-2019-19921] for more details.
|
||||
//
|
||||
// [CVE-2019-19921]: https://github.com/advisories/GHSA-fh74-hm69-rqjw
|
||||
func Reopen(file *os.File, flags int) (*os.File, error) {
|
||||
handle, err := pathrs.HandleFromFile(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer handle.Close() //nolint:errcheck // close failures aren't critical here
|
||||
|
||||
return handle.OpenFile(flags)
|
||||
}
|
||||
42
vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/open_purego.go
generated
vendored
Normal file
42
vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/open_purego.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//go:build linux && !libpathrs
|
||||
|
||||
// Copyright (C) 2024-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||
// Copyright (C) 2024-2025 SUSE LLC
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package pathrs
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs"
|
||||
"github.com/cyphar/filepath-securejoin/pathrs-lite/internal/procfs"
|
||||
)
|
||||
|
||||
// OpenatInRoot is equivalent to [OpenInRoot], except that the root is provided
|
||||
// using an *[os.File] handle, to ensure that the correct root directory is used.
|
||||
func OpenatInRoot(root *os.File, unsafePath string) (*os.File, error) {
|
||||
return gopathrs.OpenatInRoot(root, unsafePath)
|
||||
}
|
||||
|
||||
// Reopen takes an *[os.File] handle and re-opens it through /proc/self/fd.
|
||||
// Reopen(file, flags) is effectively equivalent to
|
||||
//
|
||||
// fdPath := fmt.Sprintf("/proc/self/fd/%d", file.Fd())
|
||||
// os.OpenFile(fdPath, flags|unix.O_CLOEXEC)
|
||||
//
|
||||
// But with some extra hardenings to ensure that we are not tricked by a
|
||||
// maliciously-configured /proc mount. While this attack scenario is not
|
||||
// common, in container runtimes it is possible for higher-level runtimes to be
|
||||
// tricked into configuring an unsafe /proc that can be used to attack file
|
||||
// operations. See [CVE-2019-19921] for more details.
|
||||
//
|
||||
// [CVE-2019-19921]: https://github.com/advisories/GHSA-fh74-hm69-rqjw
|
||||
func Reopen(handle *os.File, flags int) (*os.File, error) {
|
||||
return procfs.ReopenFd(handle, flags)
|
||||
}
|
||||
161
vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/procfs/procfs_libpathrs.go
generated
vendored
Normal file
161
vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/procfs/procfs_libpathrs.go
generated
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//go:build libpathrs
|
||||
|
||||
// Copyright (C) 2024-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||
// Copyright (C) 2024-2025 SUSE LLC
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
// Package procfs provides a safe API for operating on /proc on Linux.
|
||||
package procfs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"cyphar.com/go-pathrs/procfs"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// ProcThreadSelfCloser is a callback that needs to be called when you are done
|
||||
// operating on an [os.File] fetched using [Handle.OpenThreadSelf].
|
||||
//
|
||||
// [os.File]: https://pkg.go.dev/os#File
|
||||
type ProcThreadSelfCloser = procfs.ThreadCloser
|
||||
|
||||
// Handle is a wrapper around an *os.File handle to "/proc", which can be used
|
||||
// to do further procfs-related operations in a safe way.
|
||||
type Handle struct {
|
||||
inner *procfs.Handle
|
||||
}
|
||||
|
||||
// Close close the resources associated with this [Handle]. Note that if this
|
||||
// [Handle] was created with [OpenProcRoot], on some kernels the underlying
|
||||
// procfs handle is cached and so this Close operation may be a no-op. However,
|
||||
// you should always call Close on [Handle]s once you are done with them.
|
||||
func (proc *Handle) Close() error { return proc.inner.Close() }
|
||||
|
||||
// OpenProcRoot tries to open a "safer" handle to "/proc" (i.e., one with the
|
||||
// "subset=pid" mount option applied, available from Linux 5.8). Unless you
|
||||
// plan to do many [Handle.OpenRoot] operations, users should prefer to use
|
||||
// this over [OpenUnsafeProcRoot] which is far more dangerous to keep open.
|
||||
//
|
||||
// If a safe handle cannot be opened, OpenProcRoot will fall back to opening a
|
||||
// regular "/proc" handle.
|
||||
//
|
||||
// Note that using [Handle.OpenRoot] will still work with handles returned by
|
||||
// this function. If a subpath cannot be operated on with a safe "/proc"
|
||||
// handle, then [OpenUnsafeProcRoot] will be called internally and a temporary
|
||||
// unsafe handle will be used.
|
||||
func OpenProcRoot() (*Handle, error) {
|
||||
proc, err := procfs.Open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Handle{inner: proc}, nil
|
||||
}
|
||||
|
||||
// OpenUnsafeProcRoot opens a handle to "/proc" without any overmounts or
|
||||
// masked paths. You must be extremely careful to make sure this handle is
|
||||
// never leaked to a container and that you program cannot be tricked into
|
||||
// writing to arbitrary paths within it.
|
||||
//
|
||||
// This is not necessary if you just wish to use [Handle.OpenRoot], as handles
|
||||
// returned by [OpenProcRoot] will fall back to using a *temporary* unsafe
|
||||
// handle in that case. You should only really use this if you need to do many
|
||||
// operations with [Handle.OpenRoot] and the performance overhead of making
|
||||
// many procfs handles is an issue. If you do use OpenUnsafeProcRoot, you
|
||||
// should make sure to close the handle as soon as possible to avoid
|
||||
// known-fd-number attacks.
|
||||
func OpenUnsafeProcRoot() (*Handle, error) {
|
||||
proc, err := procfs.Open(procfs.UnmaskedProcRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Handle{inner: proc}, nil
|
||||
}
|
||||
|
||||
// OpenThreadSelf returns a handle to "/proc/thread-self/<subpath>" (or an
|
||||
// equivalent handle on older kernels where "/proc/thread-self" doesn't exist).
|
||||
// Once finished with the handle, you must call the returned closer function
|
||||
// ([runtime.UnlockOSThread]). You must not pass the returned *os.File to other
|
||||
// Go threads or use the handle after calling the closer.
|
||||
//
|
||||
// [runtime.UnlockOSThread]: https://pkg.go.dev/runtime#UnlockOSThread
|
||||
func (proc *Handle) OpenThreadSelf(subpath string) (*os.File, ProcThreadSelfCloser, error) {
|
||||
return proc.inner.OpenThreadSelf(subpath, unix.O_PATH|unix.O_NOFOLLOW)
|
||||
}
|
||||
|
||||
// OpenSelf returns a handle to /proc/self/<subpath>.
|
||||
//
|
||||
// Note that in Go programs with non-homogenous threads, this may result in
|
||||
// spurious errors. If you are monkeying around with APIs that are
|
||||
// thread-specific, you probably want to use [Handle.OpenThreadSelf] instead
|
||||
// which will guarantee that the handle refers to the same thread as the caller
|
||||
// is executing on.
|
||||
func (proc *Handle) OpenSelf(subpath string) (*os.File, error) {
|
||||
return proc.inner.OpenSelf(subpath, unix.O_PATH|unix.O_NOFOLLOW)
|
||||
}
|
||||
|
||||
// OpenRoot returns a handle to /proc/<subpath>.
|
||||
//
|
||||
// You should only use this when you need to operate on global procfs files
|
||||
// (such as sysctls in /proc/sys). Unlike [Handle.OpenThreadSelf],
|
||||
// [Handle.OpenSelf], and [Handle.OpenPid], the procfs handle used internally
|
||||
// for this operation will never use "subset=pid", which makes it a more juicy
|
||||
// target for [CVE-2024-21626]-style attacks (and doing something like opening
|
||||
// a directory with OpenRoot effectively leaks [OpenUnsafeProcRoot] as long as
|
||||
// the file descriptor is open).
|
||||
//
|
||||
// [CVE-2024-21626]: https://github.com/opencontainers/runc/security/advisories/GHSA-xr7r-f8xq-vfvv
|
||||
func (proc *Handle) OpenRoot(subpath string) (*os.File, error) {
|
||||
return proc.inner.OpenRoot(subpath, unix.O_PATH|unix.O_NOFOLLOW)
|
||||
}
|
||||
|
||||
// OpenPid returns a handle to /proc/$pid/<subpath> (pid can be a pid or tid).
|
||||
// This is mainly intended for usage when operating on other processes.
|
||||
//
|
||||
// You should not use this for the current thread, as special handling is
|
||||
// needed for /proc/thread-self (or /proc/self/task/<tid>) when dealing with
|
||||
// goroutine scheduling -- use [Handle.OpenThreadSelf] instead.
|
||||
//
|
||||
// To refer to the current thread-group, you should use prefer
|
||||
// [Handle.OpenSelf] to passing os.Getpid as the pid argument.
|
||||
func (proc *Handle) OpenPid(pid int, subpath string) (*os.File, error) {
|
||||
return proc.inner.OpenPid(pid, subpath, unix.O_PATH|unix.O_NOFOLLOW)
|
||||
}
|
||||
|
||||
// ProcSelfFdReadlink gets the real path of the given file by looking at
|
||||
// /proc/self/fd/<fd> with [readlink]. It is effectively just shorthand for
|
||||
// something along the lines of:
|
||||
//
|
||||
// proc, err := procfs.OpenProcRoot()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// link, err := proc.OpenThreadSelf(fmt.Sprintf("fd/%d", f.Fd()))
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// defer link.Close()
|
||||
// var buf [4096]byte
|
||||
// n, err := unix.Readlinkat(int(link.Fd()), "", buf[:])
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// pathname := buf[:n]
|
||||
//
|
||||
// [readlink]: https://pkg.go.dev/golang.org/x/sys/unix#Readlinkat
|
||||
func ProcSelfFdReadlink(f *os.File) (string, error) {
|
||||
proc, err := procfs.Open()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer proc.Close() //nolint:errcheck // close failures aren't critical here
|
||||
|
||||
fdPath := "fd/" + strconv.Itoa(int(f.Fd()))
|
||||
return proc.Readlink(procfs.ProcThreadSelf, fdPath)
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//go:build linux
|
||||
//go:build linux && !libpathrs
|
||||
|
||||
// Copyright (C) 2024-2025 Aleksa Sarai <cyphar@cyphar.com>
|
||||
// Copyright (C) 2024-2025 SUSE LLC
|
||||
2
vendor/github.com/go-jose/go-jose/v4/README.md
generated
vendored
2
vendor/github.com/go-jose/go-jose/v4/README.md
generated
vendored
@@ -37,7 +37,7 @@ Version 4 is the current stable version:
|
||||
import "github.com/go-jose/go-jose/v4"
|
||||
|
||||
It supports at least the current and previous Golang release. Currently it
|
||||
requires Golang 1.23.
|
||||
requires Golang 1.24.
|
||||
|
||||
Version 3 is only receiving critical security updates. Migration to Version 4 is recommended.
|
||||
|
||||
|
||||
16
vendor/github.com/go-jose/go-jose/v4/crypter.go
generated
vendored
16
vendor/github.com/go-jose/go-jose/v4/crypter.go
generated
vendored
@@ -454,13 +454,9 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error)
|
||||
return nil, errors.New("go-jose/go-jose: too many recipients in payload; expecting only one")
|
||||
}
|
||||
|
||||
critical, err := headers.getCritical()
|
||||
err := headers.checkNoCritical()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: invalid crit header")
|
||||
}
|
||||
|
||||
if len(critical) > 0 {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: unsupported crit header")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key, err := tryJWKS(decryptionKey, obj.Header)
|
||||
@@ -527,13 +523,9 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error)
|
||||
func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Header, []byte, error) {
|
||||
globalHeaders := obj.mergedHeaders(nil)
|
||||
|
||||
critical, err := globalHeaders.getCritical()
|
||||
err := globalHeaders.checkNoCritical()
|
||||
if err != nil {
|
||||
return -1, Header{}, nil, fmt.Errorf("go-jose/go-jose: invalid crit header")
|
||||
}
|
||||
|
||||
if len(critical) > 0 {
|
||||
return -1, Header{}, nil, fmt.Errorf("go-jose/go-jose: unsupported crit header")
|
||||
return -1, Header{}, nil, err
|
||||
}
|
||||
|
||||
key, err := tryJWKS(decryptionKey, obj.Header)
|
||||
|
||||
34
vendor/github.com/go-jose/go-jose/v4/shared.go
generated
vendored
34
vendor/github.com/go-jose/go-jose/v4/shared.go
generated
vendored
@@ -22,6 +22,7 @@ import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-jose/go-jose/v4/json"
|
||||
)
|
||||
|
||||
@@ -76,6 +77,9 @@ var (
|
||||
|
||||
// ErrUnsupportedEllipticCurve indicates unsupported or unknown elliptic curve has been found.
|
||||
ErrUnsupportedEllipticCurve = errors.New("go-jose/go-jose: unsupported/unknown elliptic curve")
|
||||
|
||||
// ErrUnsupportedCriticalHeader is returned when a header is marked critical but not supported by go-jose.
|
||||
ErrUnsupportedCriticalHeader = errors.New("go-jose/go-jose: unsupported critical header")
|
||||
)
|
||||
|
||||
// Key management algorithms
|
||||
@@ -166,8 +170,8 @@ const (
|
||||
)
|
||||
|
||||
// supportedCritical is the set of supported extensions that are understood and processed.
|
||||
var supportedCritical = map[string]bool{
|
||||
headerB64: true,
|
||||
var supportedCritical = map[string]struct{}{
|
||||
headerB64: {},
|
||||
}
|
||||
|
||||
// rawHeader represents the JOSE header for JWE/JWS objects (used for parsing).
|
||||
@@ -345,6 +349,32 @@ func (parsed rawHeader) getCritical() ([]string, error) {
|
||||
return q, nil
|
||||
}
|
||||
|
||||
// checkNoCritical verifies there are no critical headers present.
|
||||
func (parsed rawHeader) checkNoCritical() error {
|
||||
if _, ok := parsed[headerCritical]; ok {
|
||||
return ErrUnsupportedCriticalHeader
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkSupportedCritical verifies there are no unsupported critical headers.
|
||||
// Supported headers are passed in as a set: map of names to empty structs
|
||||
func (parsed rawHeader) checkSupportedCritical(supported map[string]struct{}) error {
|
||||
crit, err := parsed.getCritical()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, name := range crit {
|
||||
if _, ok := supported[name]; !ok {
|
||||
return ErrUnsupportedCriticalHeader
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getS2C extracts parsed "p2c" from the raw JSON.
|
||||
func (parsed rawHeader) getP2C() (int, error) {
|
||||
v := parsed[headerP2C]
|
||||
|
||||
44
vendor/github.com/go-jose/go-jose/v4/signing.go
generated
vendored
44
vendor/github.com/go-jose/go-jose/v4/signing.go
generated
vendored
@@ -404,15 +404,23 @@ func (obj JSONWebSignature) DetachedVerify(payload []byte, verificationKey inter
|
||||
}
|
||||
|
||||
signature := obj.Signatures[0]
|
||||
headers := signature.mergedHeaders()
|
||||
critical, err := headers.getCritical()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
if signature.header != nil {
|
||||
// Per https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.11,
|
||||
// 4.1.11. "crit" (Critical) Header Parameter
|
||||
// "When used, this Header Parameter MUST be integrity
|
||||
// protected; therefore, it MUST occur only within the JWS
|
||||
// Protected Header."
|
||||
err = signature.header.checkNoCritical()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range critical {
|
||||
if !supportedCritical[name] {
|
||||
return ErrCryptoFailure
|
||||
if signature.protected != nil {
|
||||
err = signature.protected.checkSupportedCritical(supportedCritical)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -421,6 +429,7 @@ func (obj JSONWebSignature) DetachedVerify(payload []byte, verificationKey inter
|
||||
return ErrCryptoFailure
|
||||
}
|
||||
|
||||
headers := signature.mergedHeaders()
|
||||
alg := headers.getSignatureAlgorithm()
|
||||
err = verifier.verifyPayload(input, signature.Signature, alg)
|
||||
if err == nil {
|
||||
@@ -469,14 +478,22 @@ func (obj JSONWebSignature) DetachedVerifyMulti(payload []byte, verificationKey
|
||||
|
||||
outer:
|
||||
for i, signature := range obj.Signatures {
|
||||
headers := signature.mergedHeaders()
|
||||
critical, err := headers.getCritical()
|
||||
if err != nil {
|
||||
continue
|
||||
if signature.header != nil {
|
||||
// Per https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.11,
|
||||
// 4.1.11. "crit" (Critical) Header Parameter
|
||||
// "When used, this Header Parameter MUST be integrity
|
||||
// protected; therefore, it MUST occur only within the JWS
|
||||
// Protected Header."
|
||||
err = signature.header.checkNoCritical()
|
||||
if err != nil {
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range critical {
|
||||
if !supportedCritical[name] {
|
||||
if signature.protected != nil {
|
||||
// Check for only supported critical headers
|
||||
err = signature.protected.checkSupportedCritical(supportedCritical)
|
||||
if err != nil {
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
@@ -486,6 +503,7 @@ outer:
|
||||
continue
|
||||
}
|
||||
|
||||
headers := signature.mergedHeaders()
|
||||
alg := headers.getSignatureAlgorithm()
|
||||
err = verifier.verifyPayload(input, signature.Signature, alg)
|
||||
if err == nil {
|
||||
|
||||
5
vendor/github.com/go-jose/go-jose/v4/symmetric.go
generated
vendored
5
vendor/github.com/go-jose/go-jose/v4/symmetric.go
generated
vendored
@@ -21,6 +21,7 @@ import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/hmac"
|
||||
"crypto/pbkdf2"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
@@ -328,7 +329,7 @@ func (ctx *symmetricKeyCipher) encryptKey(cek []byte, alg KeyAlgorithm) (recipie
|
||||
|
||||
// derive key
|
||||
keyLen, h := getPbkdf2Params(alg)
|
||||
key, err := pbkdf2Key(h, string(ctx.key), salt, ctx.p2c, keyLen)
|
||||
key, err := pbkdf2.Key(h, string(ctx.key), salt, ctx.p2c, keyLen)
|
||||
if err != nil {
|
||||
return recipientInfo{}, nil
|
||||
}
|
||||
@@ -433,7 +434,7 @@ func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipien
|
||||
|
||||
// derive key
|
||||
keyLen, h := getPbkdf2Params(alg)
|
||||
key, err := pbkdf2Key(h, string(ctx.key), salt, p2c, keyLen)
|
||||
key, err := pbkdf2.Key(h, string(ctx.key), salt, p2c, keyLen)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
28
vendor/github.com/go-jose/go-jose/v4/symmetric_go124.go
generated
vendored
28
vendor/github.com/go-jose/go-jose/v4/symmetric_go124.go
generated
vendored
@@ -1,28 +0,0 @@
|
||||
//go:build go1.24
|
||||
|
||||
/*-
|
||||
* Copyright 2014 Square Inc.
|
||||
*
|
||||
* 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 jose
|
||||
|
||||
import (
|
||||
"crypto/pbkdf2"
|
||||
"hash"
|
||||
)
|
||||
|
||||
func pbkdf2Key(h func() hash.Hash, password string, salt []byte, iter, keyLen int) ([]byte, error) {
|
||||
return pbkdf2.Key(h, password, salt, iter, keyLen)
|
||||
}
|
||||
29
vendor/github.com/go-jose/go-jose/v4/symmetric_legacy.go
generated
vendored
29
vendor/github.com/go-jose/go-jose/v4/symmetric_legacy.go
generated
vendored
@@ -1,29 +0,0 @@
|
||||
//go:build !go1.24
|
||||
|
||||
/*-
|
||||
* Copyright 2014 Square Inc.
|
||||
*
|
||||
* 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 jose
|
||||
|
||||
import (
|
||||
"hash"
|
||||
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
func pbkdf2Key(h func() hash.Hash, password string, salt []byte, iter, keyLen int) ([]byte, error) {
|
||||
return pbkdf2.Key([]byte(password), salt, iter, keyLen, h), nil
|
||||
}
|
||||
49
vendor/github.com/klauspost/compress/flate/deflate.go
generated
vendored
49
vendor/github.com/klauspost/compress/flate/deflate.go
generated
vendored
@@ -6,11 +6,12 @@
|
||||
package flate
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
|
||||
"github.com/klauspost/compress/internal/le"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -234,12 +235,9 @@ func (d *compressor) fillWindow(b []byte) {
|
||||
|
||||
// Calculate 256 hashes at the time (more L1 cache hits)
|
||||
loops := (n + 256 - minMatchLength) / 256
|
||||
for j := 0; j < loops; j++ {
|
||||
for j := range loops {
|
||||
startindex := j * 256
|
||||
end := startindex + 256 + minMatchLength - 1
|
||||
if end > n {
|
||||
end = n
|
||||
}
|
||||
end := min(startindex+256+minMatchLength-1, n)
|
||||
tocheck := d.window[startindex:end]
|
||||
dstSize := len(tocheck) - minMatchLength + 1
|
||||
|
||||
@@ -269,18 +267,12 @@ func (d *compressor) fillWindow(b []byte) {
|
||||
// We only look at chainCount possibilities before giving up.
|
||||
// pos = s.index, prevHead = s.chainHead-s.hashOffset, prevLength=minMatchLength-1, lookahead
|
||||
func (d *compressor) findMatch(pos int, prevHead int, lookahead int) (length, offset int, ok bool) {
|
||||
minMatchLook := maxMatchLength
|
||||
if lookahead < minMatchLook {
|
||||
minMatchLook = lookahead
|
||||
}
|
||||
minMatchLook := min(lookahead, maxMatchLength)
|
||||
|
||||
win := d.window[0 : pos+minMatchLook]
|
||||
|
||||
// We quit when we get a match that's at least nice long
|
||||
nice := len(win) - pos
|
||||
if d.nice < nice {
|
||||
nice = d.nice
|
||||
}
|
||||
nice := min(d.nice, len(win)-pos)
|
||||
|
||||
// If we've got a match that's good enough, only look in 1/4 the chain.
|
||||
tries := d.chain
|
||||
@@ -288,10 +280,7 @@ func (d *compressor) findMatch(pos int, prevHead int, lookahead int) (length, of
|
||||
|
||||
wEnd := win[pos+length]
|
||||
wPos := win[pos:]
|
||||
minIndex := pos - windowSize
|
||||
if minIndex < 0 {
|
||||
minIndex = 0
|
||||
}
|
||||
minIndex := max(pos-windowSize, 0)
|
||||
offset = 0
|
||||
|
||||
if d.chain < 100 {
|
||||
@@ -374,7 +363,7 @@ func (d *compressor) writeStoredBlock(buf []byte) error {
|
||||
// of the supplied slice.
|
||||
// The caller must ensure that len(b) >= 4.
|
||||
func hash4(b []byte) uint32 {
|
||||
return hash4u(binary.LittleEndian.Uint32(b), hashBits)
|
||||
return hash4u(le.Load32(b, 0), hashBits)
|
||||
}
|
||||
|
||||
// hash4 returns the hash of u to fit in a hash table with h bits.
|
||||
@@ -389,7 +378,7 @@ func bulkHash4(b []byte, dst []uint32) {
|
||||
if len(b) < 4 {
|
||||
return
|
||||
}
|
||||
hb := binary.LittleEndian.Uint32(b)
|
||||
hb := le.Load32(b, 0)
|
||||
|
||||
dst[0] = hash4u(hb, hashBits)
|
||||
end := len(b) - 4 + 1
|
||||
@@ -480,10 +469,7 @@ func (d *compressor) deflateLazy() {
|
||||
prevOffset := s.offset
|
||||
s.length = minMatchLength - 1
|
||||
s.offset = 0
|
||||
minIndex := s.index - windowSize
|
||||
if minIndex < 0 {
|
||||
minIndex = 0
|
||||
}
|
||||
minIndex := max(s.index-windowSize, 0)
|
||||
|
||||
if s.chainHead-s.hashOffset >= minIndex && lookahead > prevLength && prevLength < d.lazy {
|
||||
if newLength, newOffset, ok := d.findMatch(s.index, s.chainHead-s.hashOffset, lookahead); ok {
|
||||
@@ -503,10 +489,7 @@ func (d *compressor) deflateLazy() {
|
||||
if prevLength < maxMatchLength-checkOff {
|
||||
prevIndex := s.index - 1
|
||||
if prevIndex+prevLength < s.maxInsertIndex {
|
||||
end := lookahead
|
||||
if lookahead > maxMatchLength+checkOff {
|
||||
end = maxMatchLength + checkOff
|
||||
}
|
||||
end := min(lookahead, maxMatchLength+checkOff)
|
||||
end += prevIndex
|
||||
|
||||
// Hash at match end.
|
||||
@@ -603,15 +586,9 @@ func (d *compressor) deflateLazy() {
|
||||
// table.
|
||||
newIndex := s.index + prevLength - 1
|
||||
// Calculate missing hashes
|
||||
end := newIndex
|
||||
if end > s.maxInsertIndex {
|
||||
end = s.maxInsertIndex
|
||||
}
|
||||
end := min(newIndex, s.maxInsertIndex)
|
||||
end += minMatchLength - 1
|
||||
startindex := s.index + 1
|
||||
if startindex > s.maxInsertIndex {
|
||||
startindex = s.maxInsertIndex
|
||||
}
|
||||
startindex := min(s.index+1, s.maxInsertIndex)
|
||||
tocheck := d.window[startindex:end]
|
||||
dstSize := len(tocheck) - minMatchLength + 1
|
||||
if dstSize > 0 {
|
||||
|
||||
5
vendor/github.com/klauspost/compress/flate/dict_decoder.go
generated
vendored
5
vendor/github.com/klauspost/compress/flate/dict_decoder.go
generated
vendored
@@ -104,10 +104,7 @@ func (dd *dictDecoder) writeCopy(dist, length int) int {
|
||||
dstBase := dd.wrPos
|
||||
dstPos := dstBase
|
||||
srcPos := dstPos - dist
|
||||
endPos := dstPos + length
|
||||
if endPos > len(dd.hist) {
|
||||
endPos = len(dd.hist)
|
||||
}
|
||||
endPos := min(dstPos+length, len(dd.hist))
|
||||
|
||||
// Copy non-overlapping section after destination position.
|
||||
//
|
||||
|
||||
49
vendor/github.com/klauspost/compress/flate/fast_encoder.go
generated
vendored
49
vendor/github.com/klauspost/compress/flate/fast_encoder.go
generated
vendored
@@ -7,7 +7,6 @@ package flate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/bits"
|
||||
|
||||
"github.com/klauspost/compress/internal/le"
|
||||
)
|
||||
@@ -151,29 +150,9 @@ func (e *fastGen) matchlen(s, t int, src []byte) int32 {
|
||||
panic(fmt.Sprint(s, "-", t, "(", s-t, ") > maxMatchLength (", maxMatchOffset, ")"))
|
||||
}
|
||||
}
|
||||
s1 := min(s+maxMatchLength-4, len(src))
|
||||
left := s1 - s
|
||||
n := int32(0)
|
||||
for left >= 8 {
|
||||
diff := le.Load64(src, s) ^ le.Load64(src, t)
|
||||
if diff != 0 {
|
||||
return n + int32(bits.TrailingZeros64(diff)>>3)
|
||||
}
|
||||
s += 8
|
||||
t += 8
|
||||
n += 8
|
||||
left -= 8
|
||||
}
|
||||
|
||||
a := src[s:s1]
|
||||
a := src[s:min(s+maxMatchLength-4, len(src))]
|
||||
b := src[t:]
|
||||
for i := range a {
|
||||
if a[i] != b[i] {
|
||||
break
|
||||
}
|
||||
n++
|
||||
}
|
||||
return n
|
||||
return int32(matchLen(a, b))
|
||||
}
|
||||
|
||||
// matchlenLong will return the match length between offsets and t in src.
|
||||
@@ -193,29 +172,7 @@ func (e *fastGen) matchlenLong(s, t int, src []byte) int32 {
|
||||
panic(fmt.Sprint(s, "-", t, "(", s-t, ") > maxMatchLength (", maxMatchOffset, ")"))
|
||||
}
|
||||
}
|
||||
// Extend the match to be as long as possible.
|
||||
left := len(src) - s
|
||||
n := int32(0)
|
||||
for left >= 8 {
|
||||
diff := le.Load64(src, s) ^ le.Load64(src, t)
|
||||
if diff != 0 {
|
||||
return n + int32(bits.TrailingZeros64(diff)>>3)
|
||||
}
|
||||
s += 8
|
||||
t += 8
|
||||
n += 8
|
||||
left -= 8
|
||||
}
|
||||
|
||||
a := src[s:]
|
||||
b := src[t:]
|
||||
for i := range a {
|
||||
if a[i] != b[i] {
|
||||
break
|
||||
}
|
||||
n++
|
||||
}
|
||||
return n
|
||||
return int32(matchLen(src[s:], src[t:]))
|
||||
}
|
||||
|
||||
// Reset the encoding table.
|
||||
|
||||
42
vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go
generated
vendored
42
vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go
generated
vendored
@@ -211,7 +211,9 @@ func (w *huffmanBitWriter) flush() {
|
||||
n++
|
||||
}
|
||||
w.bits = 0
|
||||
w.write(w.bytes[:n])
|
||||
if n > 0 {
|
||||
w.write(w.bytes[:n])
|
||||
}
|
||||
w.nbytes = 0
|
||||
}
|
||||
|
||||
@@ -303,10 +305,7 @@ func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int, litE
|
||||
w.codegenFreq[size]++
|
||||
count--
|
||||
for count >= 3 {
|
||||
n := 6
|
||||
if n > count {
|
||||
n = count
|
||||
}
|
||||
n := min(6, count)
|
||||
codegen[outIndex] = 16
|
||||
outIndex++
|
||||
codegen[outIndex] = uint8(n - 3)
|
||||
@@ -316,10 +315,7 @@ func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int, litE
|
||||
}
|
||||
} else {
|
||||
for count >= 11 {
|
||||
n := 138
|
||||
if n > count {
|
||||
n = count
|
||||
}
|
||||
n := min(138, count)
|
||||
codegen[outIndex] = 18
|
||||
outIndex++
|
||||
codegen[outIndex] = uint8(n - 11)
|
||||
@@ -438,8 +434,8 @@ func (w *huffmanBitWriter) writeOutBits() {
|
||||
w.nbits -= 48
|
||||
n := w.nbytes
|
||||
|
||||
// We over-write, but faster...
|
||||
le.Store64(w.bytes[n:], bits)
|
||||
// We overwrite, but faster...
|
||||
le.Store64(w.bytes[:], n, bits)
|
||||
n += 6
|
||||
|
||||
if n >= bufferFlushSize {
|
||||
@@ -472,7 +468,7 @@ func (w *huffmanBitWriter) writeDynamicHeader(numLiterals int, numOffsets int, n
|
||||
w.writeBits(int32(numOffsets-1), 5)
|
||||
w.writeBits(int32(numCodegens-4), 4)
|
||||
|
||||
for i := 0; i < numCodegens; i++ {
|
||||
for i := range numCodegens {
|
||||
value := uint(w.codegenEncoding.codes[codegenOrder[i]].len())
|
||||
w.writeBits(int32(value), 3)
|
||||
}
|
||||
@@ -650,7 +646,7 @@ func (w *huffmanBitWriter) writeBlockDynamic(tokens *tokens, eof bool, input []b
|
||||
w.lastHeader = 0
|
||||
}
|
||||
|
||||
numLiterals, numOffsets := w.indexTokens(tokens, !sync)
|
||||
numLiterals, numOffsets := w.indexTokens(tokens, fillReuse && !sync)
|
||||
extraBits := 0
|
||||
ssize, storable := w.storedSize(input)
|
||||
|
||||
@@ -855,8 +851,7 @@ func (w *huffmanBitWriter) writeTokens(tokens []token, leCodes, oeCodes []hcode)
|
||||
bits |= c.code64() << (nbits & 63)
|
||||
nbits += c.len()
|
||||
if nbits >= 48 {
|
||||
le.Store64(w.bytes[nbytes:], bits)
|
||||
//*(*uint64)(unsafe.Pointer(&w.bytes[nbytes])) = bits
|
||||
le.Store64(w.bytes[:], nbytes, bits)
|
||||
bits >>= 48
|
||||
nbits -= 48
|
||||
nbytes += 6
|
||||
@@ -883,8 +878,7 @@ func (w *huffmanBitWriter) writeTokens(tokens []token, leCodes, oeCodes []hcode)
|
||||
bits |= c.code64() << (nbits & 63)
|
||||
nbits += c.len()
|
||||
if nbits >= 48 {
|
||||
le.Store64(w.bytes[nbytes:], bits)
|
||||
//*(*uint64)(unsafe.Pointer(&w.bytes[nbytes])) = bits
|
||||
le.Store64(w.bytes[:], nbytes, bits)
|
||||
bits >>= 48
|
||||
nbits -= 48
|
||||
nbytes += 6
|
||||
@@ -906,8 +900,7 @@ func (w *huffmanBitWriter) writeTokens(tokens []token, leCodes, oeCodes []hcode)
|
||||
bits |= uint64(extraLength) << (nbits & 63)
|
||||
nbits += extraLengthBits
|
||||
if nbits >= 48 {
|
||||
le.Store64(w.bytes[nbytes:], bits)
|
||||
//*(*uint64)(unsafe.Pointer(&w.bytes[nbytes])) = bits
|
||||
le.Store64(w.bytes[:], nbytes, bits)
|
||||
bits >>= 48
|
||||
nbits -= 48
|
||||
nbytes += 6
|
||||
@@ -932,8 +925,7 @@ func (w *huffmanBitWriter) writeTokens(tokens []token, leCodes, oeCodes []hcode)
|
||||
bits |= c.code64() << (nbits & 63)
|
||||
nbits += c.len()
|
||||
if nbits >= 48 {
|
||||
le.Store64(w.bytes[nbytes:], bits)
|
||||
//*(*uint64)(unsafe.Pointer(&w.bytes[nbytes])) = bits
|
||||
le.Store64(w.bytes[:], nbytes, bits)
|
||||
bits >>= 48
|
||||
nbits -= 48
|
||||
nbytes += 6
|
||||
@@ -954,8 +946,7 @@ func (w *huffmanBitWriter) writeTokens(tokens []token, leCodes, oeCodes []hcode)
|
||||
bits |= uint64((offset-(offsetComb>>8))&matchOffsetOnlyMask) << (nbits & 63)
|
||||
nbits += uint8(offsetComb)
|
||||
if nbits >= 48 {
|
||||
le.Store64(w.bytes[nbytes:], bits)
|
||||
//*(*uint64)(unsafe.Pointer(&w.bytes[nbytes])) = bits
|
||||
le.Store64(w.bytes[:], nbytes, bits)
|
||||
bits >>= 48
|
||||
nbits -= 48
|
||||
nbytes += 6
|
||||
@@ -1108,7 +1099,7 @@ func (w *huffmanBitWriter) writeBlockHuff(eof bool, input []byte, sync bool) {
|
||||
// We must have at least 48 bits free.
|
||||
if nbits >= 8 {
|
||||
n := nbits >> 3
|
||||
le.Store64(w.bytes[nbytes:], bits)
|
||||
le.Store64(w.bytes[:], nbytes, bits)
|
||||
bits >>= (n * 8) & 63
|
||||
nbits -= n * 8
|
||||
nbytes += n
|
||||
@@ -1137,8 +1128,7 @@ func (w *huffmanBitWriter) writeBlockHuff(eof bool, input []byte, sync bool) {
|
||||
// Remaining...
|
||||
for _, t := range input {
|
||||
if nbits >= 48 {
|
||||
le.Store64(w.bytes[nbytes:], bits)
|
||||
//*(*uint64)(unsafe.Pointer(&w.bytes[nbytes])) = bits
|
||||
le.Store64(w.bytes[:], nbytes, bits)
|
||||
bits >>= 48
|
||||
nbits -= 48
|
||||
nbytes += 6
|
||||
|
||||
2
vendor/github.com/klauspost/compress/flate/huffman_code.go
generated
vendored
2
vendor/github.com/klauspost/compress/flate/huffman_code.go
generated
vendored
@@ -91,7 +91,7 @@ func generateFixedLiteralEncoding() *huffmanEncoder {
|
||||
h := newHuffmanEncoder(literalCount)
|
||||
codes := h.codes
|
||||
var ch uint16
|
||||
for ch = 0; ch < literalCount; ch++ {
|
||||
for ch = range uint16(literalCount) {
|
||||
var bits uint16
|
||||
var size uint8
|
||||
switch {
|
||||
|
||||
4
vendor/github.com/klauspost/compress/flate/inflate.go
generated
vendored
4
vendor/github.com/klauspost/compress/flate/inflate.go
generated
vendored
@@ -485,7 +485,7 @@ func (f *decompressor) readHuffman() error {
|
||||
f.nb -= 5 + 5 + 4
|
||||
|
||||
// (HCLEN+4)*3 bits: code lengths in the magic codeOrder order.
|
||||
for i := 0; i < nclen; i++ {
|
||||
for i := range nclen {
|
||||
for f.nb < 3 {
|
||||
if err := f.moreBits(); err != nil {
|
||||
return err
|
||||
@@ -776,7 +776,7 @@ func fixedHuffmanDecoderInit() {
|
||||
fixedOnce.Do(func() {
|
||||
// These come from the RFC section 3.2.6.
|
||||
var bits [288]int
|
||||
for i := 0; i < 144; i++ {
|
||||
for i := range 144 {
|
||||
bits[i] = 8
|
||||
}
|
||||
for i := 144; i < 256; i++ {
|
||||
|
||||
5
vendor/github.com/klauspost/compress/flate/level5.go
generated
vendored
5
vendor/github.com/klauspost/compress/flate/level5.go
generated
vendored
@@ -677,10 +677,7 @@ func (e *fastEncL5Window) matchlen(s, t int32, src []byte) int32 {
|
||||
panic(fmt.Sprint(s, "-", t, "(", s-t, ") > maxMatchLength (", maxMatchOffset, ")"))
|
||||
}
|
||||
}
|
||||
s1 := int(s) + maxMatchLength - 4
|
||||
if s1 > len(src) {
|
||||
s1 = len(src)
|
||||
}
|
||||
s1 := min(int(s)+maxMatchLength-4, len(src))
|
||||
|
||||
// Extend the match to be as long as possible.
|
||||
return int32(matchLen(src[s:s1], src[t:]))
|
||||
|
||||
4
vendor/github.com/klauspost/compress/flate/stateless.go
generated
vendored
4
vendor/github.com/klauspost/compress/flate/stateless.go
generated
vendored
@@ -56,7 +56,7 @@ func NewStatelessWriter(dst io.Writer) io.WriteCloser {
|
||||
|
||||
// bitWriterPool contains bit writers that can be reused.
|
||||
var bitWriterPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
New: func() any {
|
||||
return newHuffmanBitWriter(nil)
|
||||
},
|
||||
}
|
||||
@@ -184,7 +184,7 @@ func statelessEnc(dst *tokens, src []byte, startAt int16) {
|
||||
// Index until startAt
|
||||
if startAt > 0 {
|
||||
cv := load3232(src, 0)
|
||||
for i := int16(0); i < startAt; i++ {
|
||||
for i := range startAt {
|
||||
table[hashSL(cv)] = tableEntry{offset: i}
|
||||
cv = (cv >> 8) | (uint32(src[i+4]) << 24)
|
||||
}
|
||||
|
||||
2
vendor/github.com/klauspost/compress/fse/bitwriter.go
generated
vendored
2
vendor/github.com/klauspost/compress/fse/bitwriter.go
generated
vendored
@@ -143,7 +143,7 @@ func (b *bitWriter) flush32() {
|
||||
// flushAlign will flush remaining full bytes and align to next byte boundary.
|
||||
func (b *bitWriter) flushAlign() {
|
||||
nbBytes := (b.nBits + 7) >> 3
|
||||
for i := uint8(0); i < nbBytes; i++ {
|
||||
for i := range nbBytes {
|
||||
b.out = append(b.out, byte(b.bitContainer>>(i*8)))
|
||||
}
|
||||
b.nBits = 0
|
||||
|
||||
2
vendor/github.com/klauspost/compress/fse/compress.go
generated
vendored
2
vendor/github.com/klauspost/compress/fse/compress.go
generated
vendored
@@ -396,7 +396,7 @@ func (s *Scratch) buildCTable() error {
|
||||
if v > largeLimit {
|
||||
s.zeroBits = true
|
||||
}
|
||||
for nbOccurrences := int16(0); nbOccurrences < v; nbOccurrences++ {
|
||||
for range v {
|
||||
tableSymbol[position] = symbol
|
||||
position = (position + step) & tableMask
|
||||
for position > highThreshold {
|
||||
|
||||
2
vendor/github.com/klauspost/compress/huff0/bitwriter.go
generated
vendored
2
vendor/github.com/klauspost/compress/huff0/bitwriter.go
generated
vendored
@@ -85,7 +85,7 @@ func (b *bitWriter) flush32() {
|
||||
// flushAlign will flush remaining full bytes and align to next byte boundary.
|
||||
func (b *bitWriter) flushAlign() {
|
||||
nbBytes := (b.nBits + 7) >> 3
|
||||
for i := uint8(0); i < nbBytes; i++ {
|
||||
for i := range nbBytes {
|
||||
b.out = append(b.out, byte(b.bitContainer>>(i*8)))
|
||||
}
|
||||
b.nBits = 0
|
||||
|
||||
6
vendor/github.com/klauspost/compress/huff0/compress.go
generated
vendored
6
vendor/github.com/klauspost/compress/huff0/compress.go
generated
vendored
@@ -276,7 +276,7 @@ func (s *Scratch) compress4X(src []byte) ([]byte, error) {
|
||||
offsetIdx := len(s.Out)
|
||||
s.Out = append(s.Out, sixZeros[:]...)
|
||||
|
||||
for i := 0; i < 4; i++ {
|
||||
for i := range 4 {
|
||||
toDo := src
|
||||
if len(toDo) > segmentSize {
|
||||
toDo = toDo[:segmentSize]
|
||||
@@ -312,7 +312,7 @@ func (s *Scratch) compress4Xp(src []byte) ([]byte, error) {
|
||||
segmentSize := (len(src) + 3) / 4
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(4)
|
||||
for i := 0; i < 4; i++ {
|
||||
for i := range 4 {
|
||||
toDo := src
|
||||
if len(toDo) > segmentSize {
|
||||
toDo = toDo[:segmentSize]
|
||||
@@ -326,7 +326,7 @@ func (s *Scratch) compress4Xp(src []byte) ([]byte, error) {
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
for i := 0; i < 4; i++ {
|
||||
for i := range 4 {
|
||||
o := s.tmpOut[i]
|
||||
if len(o) > math.MaxUint16 {
|
||||
// We cannot store the size in the jump table
|
||||
|
||||
14
vendor/github.com/klauspost/compress/huff0/decompress.go
generated
vendored
14
vendor/github.com/klauspost/compress/huff0/decompress.go
generated
vendored
@@ -626,7 +626,7 @@ func (d *Decoder) decompress4X8bit(dst, src []byte) ([]byte, error) {
|
||||
|
||||
var br [4]bitReaderBytes
|
||||
start := 6
|
||||
for i := 0; i < 3; i++ {
|
||||
for i := range 3 {
|
||||
length := int(src[i*2]) | (int(src[i*2+1]) << 8)
|
||||
if start+length >= len(src) {
|
||||
return nil, errors.New("truncated input (or invalid offset)")
|
||||
@@ -798,10 +798,7 @@ func (d *Decoder) decompress4X8bit(dst, src []byte) ([]byte, error) {
|
||||
remainBytes := dstEvery - (decoded / 4)
|
||||
for i := range br {
|
||||
offset := dstEvery * i
|
||||
endsAt := offset + remainBytes
|
||||
if endsAt > len(out) {
|
||||
endsAt = len(out)
|
||||
}
|
||||
endsAt := min(offset+remainBytes, len(out))
|
||||
br := &br[i]
|
||||
bitsLeft := br.remaining()
|
||||
for bitsLeft > 0 {
|
||||
@@ -864,7 +861,7 @@ func (d *Decoder) decompress4X8bit(dst, src []byte) ([]byte, error) {
|
||||
func (d *Decoder) decompress4X8bitExactly(dst, src []byte) ([]byte, error) {
|
||||
var br [4]bitReaderBytes
|
||||
start := 6
|
||||
for i := 0; i < 3; i++ {
|
||||
for i := range 3 {
|
||||
length := int(src[i*2]) | (int(src[i*2+1]) << 8)
|
||||
if start+length >= len(src) {
|
||||
return nil, errors.New("truncated input (or invalid offset)")
|
||||
@@ -1035,10 +1032,7 @@ func (d *Decoder) decompress4X8bitExactly(dst, src []byte) ([]byte, error) {
|
||||
remainBytes := dstEvery - (decoded / 4)
|
||||
for i := range br {
|
||||
offset := dstEvery * i
|
||||
endsAt := offset + remainBytes
|
||||
if endsAt > len(out) {
|
||||
endsAt = len(out)
|
||||
}
|
||||
endsAt := min(offset+remainBytes, len(out))
|
||||
br := &br[i]
|
||||
bitsLeft := br.remaining()
|
||||
for bitsLeft > 0 {
|
||||
|
||||
7
vendor/github.com/klauspost/compress/huff0/decompress_amd64.go
generated
vendored
7
vendor/github.com/klauspost/compress/huff0/decompress_amd64.go
generated
vendored
@@ -58,7 +58,7 @@ func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) {
|
||||
var br [4]bitReaderShifted
|
||||
// Decode "jump table"
|
||||
start := 6
|
||||
for i := 0; i < 3; i++ {
|
||||
for i := range 3 {
|
||||
length := int(src[i*2]) | (int(src[i*2+1]) << 8)
|
||||
if start+length >= len(src) {
|
||||
return nil, errors.New("truncated input (or invalid offset)")
|
||||
@@ -109,10 +109,7 @@ func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) {
|
||||
remainBytes := dstEvery - (decoded / 4)
|
||||
for i := range br {
|
||||
offset := dstEvery * i
|
||||
endsAt := offset + remainBytes
|
||||
if endsAt > len(out) {
|
||||
endsAt = len(out)
|
||||
}
|
||||
endsAt := min(offset+remainBytes, len(out))
|
||||
br := &br[i]
|
||||
bitsLeft := br.remaining()
|
||||
for bitsLeft > 0 {
|
||||
|
||||
4
vendor/github.com/klauspost/compress/huff0/huff0.go
generated
vendored
4
vendor/github.com/klauspost/compress/huff0/huff0.go
generated
vendored
@@ -201,7 +201,7 @@ func (c cTable) write(s *Scratch) error {
|
||||
for i := range hist[:16] {
|
||||
hist[i] = 0
|
||||
}
|
||||
for n := uint8(0); n < maxSymbolValue; n++ {
|
||||
for n := range maxSymbolValue {
|
||||
v := bitsToWeight[c[n].nBits] & 15
|
||||
huffWeight[n] = v
|
||||
hist[v]++
|
||||
@@ -271,7 +271,7 @@ func (c cTable) estTableSize(s *Scratch) (sz int, err error) {
|
||||
for i := range hist[:16] {
|
||||
hist[i] = 0
|
||||
}
|
||||
for n := uint8(0); n < maxSymbolValue; n++ {
|
||||
for n := range maxSymbolValue {
|
||||
v := bitsToWeight[c[n].nBits] & 15
|
||||
huffWeight[n] = v
|
||||
hist[v]++
|
||||
|
||||
4
vendor/github.com/klauspost/compress/internal/le/unsafe_disabled.go
generated
vendored
4
vendor/github.com/klauspost/compress/internal/le/unsafe_disabled.go
generated
vendored
@@ -37,6 +37,6 @@ func Store32(b []byte, v uint32) {
|
||||
}
|
||||
|
||||
// Store64 will store v at b.
|
||||
func Store64(b []byte, v uint64) {
|
||||
binary.LittleEndian.PutUint64(b, v)
|
||||
func Store64[I Indexer](b []byte, i I, v uint64) {
|
||||
binary.LittleEndian.PutUint64(b[i:], v)
|
||||
}
|
||||
|
||||
9
vendor/github.com/klauspost/compress/internal/le/unsafe_enabled.go
generated
vendored
9
vendor/github.com/klauspost/compress/internal/le/unsafe_enabled.go
generated
vendored
@@ -38,18 +38,15 @@ func Load64[I Indexer](b []byte, i I) uint64 {
|
||||
|
||||
// Store16 will store v at b.
|
||||
func Store16(b []byte, v uint16) {
|
||||
//binary.LittleEndian.PutUint16(b, v)
|
||||
*(*uint16)(unsafe.Pointer(unsafe.SliceData(b))) = v
|
||||
}
|
||||
|
||||
// Store32 will store v at b.
|
||||
func Store32(b []byte, v uint32) {
|
||||
//binary.LittleEndian.PutUint32(b, v)
|
||||
*(*uint32)(unsafe.Pointer(unsafe.SliceData(b))) = v
|
||||
}
|
||||
|
||||
// Store64 will store v at b.
|
||||
func Store64(b []byte, v uint64) {
|
||||
//binary.LittleEndian.PutUint64(b, v)
|
||||
*(*uint64)(unsafe.Pointer(unsafe.SliceData(b))) = v
|
||||
// Store64 will store v at b[i:].
|
||||
func Store64[I Indexer](b []byte, i I, v uint64) {
|
||||
*(*uint64)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i)) = v
|
||||
}
|
||||
|
||||
2
vendor/github.com/klauspost/compress/internal/snapref/decode.go
generated
vendored
2
vendor/github.com/klauspost/compress/internal/snapref/decode.go
generated
vendored
@@ -209,7 +209,7 @@ func (r *Reader) fill() error {
|
||||
if !r.readFull(r.buf[:len(magicBody)], false) {
|
||||
return r.err
|
||||
}
|
||||
for i := 0; i < len(magicBody); i++ {
|
||||
for i := range len(magicBody) {
|
||||
if r.buf[i] != magicBody[i] {
|
||||
r.err = ErrCorrupt
|
||||
return r.err
|
||||
|
||||
4
vendor/github.com/klauspost/compress/internal/snapref/encode.go
generated
vendored
4
vendor/github.com/klauspost/compress/internal/snapref/encode.go
generated
vendored
@@ -20,8 +20,10 @@ import (
|
||||
func Encode(dst, src []byte) []byte {
|
||||
if n := MaxEncodedLen(len(src)); n < 0 {
|
||||
panic(ErrTooLarge)
|
||||
} else if len(dst) < n {
|
||||
} else if cap(dst) < n {
|
||||
dst = make([]byte, n)
|
||||
} else {
|
||||
dst = dst[:n]
|
||||
}
|
||||
|
||||
// The block starts with the varint-encoded length of the decompressed bytes.
|
||||
|
||||
2
vendor/github.com/klauspost/compress/zstd/bitwriter.go
generated
vendored
2
vendor/github.com/klauspost/compress/zstd/bitwriter.go
generated
vendored
@@ -88,7 +88,7 @@ func (b *bitWriter) flush32() {
|
||||
// flushAlign will flush remaining full bytes and align to next byte boundary.
|
||||
func (b *bitWriter) flushAlign() {
|
||||
nbBytes := (b.nBits + 7) >> 3
|
||||
for i := uint8(0); i < nbBytes; i++ {
|
||||
for i := range nbBytes {
|
||||
b.out = append(b.out, byte(b.bitContainer>>(i*8)))
|
||||
}
|
||||
b.nBits = 0
|
||||
|
||||
6
vendor/github.com/klauspost/compress/zstd/blockdec.go
generated
vendored
6
vendor/github.com/klauspost/compress/zstd/blockdec.go
generated
vendored
@@ -54,11 +54,11 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
huffDecoderPool = sync.Pool{New: func() interface{} {
|
||||
huffDecoderPool = sync.Pool{New: func() any {
|
||||
return &huff0.Scratch{}
|
||||
}}
|
||||
|
||||
fseDecoderPool = sync.Pool{New: func() interface{} {
|
||||
fseDecoderPool = sync.Pool{New: func() any {
|
||||
return &fseDecoder{}
|
||||
}}
|
||||
)
|
||||
@@ -553,7 +553,7 @@ func (b *blockDec) prepareSequences(in []byte, hist *history) (err error) {
|
||||
if compMode&3 != 0 {
|
||||
return errors.New("corrupt block: reserved bits not zero")
|
||||
}
|
||||
for i := uint(0); i < 3; i++ {
|
||||
for i := range uint(3) {
|
||||
mode := seqCompMode((compMode >> (6 - i*2)) & 3)
|
||||
if debugDecoder {
|
||||
println("Table", tableIndex(i), "is", mode)
|
||||
|
||||
8
vendor/github.com/klauspost/compress/zstd/decoder.go
generated
vendored
8
vendor/github.com/klauspost/compress/zstd/decoder.go
generated
vendored
@@ -373,11 +373,9 @@ func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) {
|
||||
if cap(dst) == 0 && !d.o.limitToCap {
|
||||
// Allocate len(input) * 2 by default if nothing is provided
|
||||
// and we didn't get frame content size.
|
||||
size := len(input) * 2
|
||||
// Cap to 1 MB.
|
||||
if size > 1<<20 {
|
||||
size = 1 << 20
|
||||
}
|
||||
size := min(
|
||||
// Cap to 1 MB.
|
||||
len(input)*2, 1<<20)
|
||||
if uint64(size) > d.o.maxDecodedSize {
|
||||
size = int(d.o.maxDecodedSize)
|
||||
}
|
||||
|
||||
20
vendor/github.com/klauspost/compress/zstd/dict.go
generated
vendored
20
vendor/github.com/klauspost/compress/zstd/dict.go
generated
vendored
@@ -194,17 +194,17 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
|
||||
hist := o.History
|
||||
contents := o.Contents
|
||||
debug := o.DebugOut != nil
|
||||
println := func(args ...interface{}) {
|
||||
println := func(args ...any) {
|
||||
if o.DebugOut != nil {
|
||||
fmt.Fprintln(o.DebugOut, args...)
|
||||
}
|
||||
}
|
||||
printf := func(s string, args ...interface{}) {
|
||||
printf := func(s string, args ...any) {
|
||||
if o.DebugOut != nil {
|
||||
fmt.Fprintf(o.DebugOut, s, args...)
|
||||
}
|
||||
}
|
||||
print := func(args ...interface{}) {
|
||||
print := func(args ...any) {
|
||||
if o.DebugOut != nil {
|
||||
fmt.Fprint(o.DebugOut, args...)
|
||||
}
|
||||
@@ -424,16 +424,10 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
|
||||
}
|
||||
|
||||
// Literal table
|
||||
avgSize := litTotal
|
||||
if avgSize > huff0.BlockSizeMax/2 {
|
||||
avgSize = huff0.BlockSizeMax / 2
|
||||
}
|
||||
avgSize := min(litTotal, huff0.BlockSizeMax/2)
|
||||
huffBuff := make([]byte, 0, avgSize)
|
||||
// Target size
|
||||
div := litTotal / avgSize
|
||||
if div < 1 {
|
||||
div = 1
|
||||
}
|
||||
div := max(litTotal/avgSize, 1)
|
||||
if debug {
|
||||
println("Huffman weights:")
|
||||
}
|
||||
@@ -454,7 +448,7 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
|
||||
huffBuff = append(huffBuff, 255)
|
||||
}
|
||||
scratch := &huff0.Scratch{TableLog: 11}
|
||||
for tries := 0; tries < 255; tries++ {
|
||||
for tries := range 255 {
|
||||
scratch = &huff0.Scratch{TableLog: 11}
|
||||
_, _, err = huff0.Compress1X(huffBuff, scratch)
|
||||
if err == nil {
|
||||
@@ -471,7 +465,7 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
|
||||
|
||||
// Bail out.... Just generate something
|
||||
huffBuff = append(huffBuff, bytes.Repeat([]byte{255}, 10000)...)
|
||||
for i := 0; i < 128; i++ {
|
||||
for i := range 128 {
|
||||
huffBuff = append(huffBuff, byte(i))
|
||||
}
|
||||
continue
|
||||
|
||||
10
vendor/github.com/klauspost/compress/zstd/enc_base.go
generated
vendored
10
vendor/github.com/klauspost/compress/zstd/enc_base.go
generated
vendored
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
dictShardBits = 6
|
||||
dictShardBits = 7
|
||||
)
|
||||
|
||||
type fastBase struct {
|
||||
@@ -41,11 +41,9 @@ func (e *fastBase) AppendCRC(dst []byte) []byte {
|
||||
// or a window size small enough to contain the input size, if > 0.
|
||||
func (e *fastBase) WindowSize(size int64) int32 {
|
||||
if size > 0 && size < int64(e.maxMatchOff) {
|
||||
b := int32(1) << uint(bits.Len(uint(size)))
|
||||
// Keep minimum window.
|
||||
if b < 1024 {
|
||||
b = 1024
|
||||
}
|
||||
b := max(
|
||||
// Keep minimum window.
|
||||
int32(1)<<uint(bits.Len(uint(size))), 1024)
|
||||
return b
|
||||
}
|
||||
return e.maxMatchOff
|
||||
|
||||
23
vendor/github.com/klauspost/compress/zstd/enc_best.go
generated
vendored
23
vendor/github.com/klauspost/compress/zstd/enc_best.go
generated
vendored
@@ -158,11 +158,9 @@ func (e *bestFastEncoder) Encode(blk *blockEnc, src []byte) {
|
||||
|
||||
// Use this to estimate literal cost.
|
||||
// Scaled by 10 bits.
|
||||
bitsPerByte := int32((compress.ShannonEntropyBits(src) * 1024) / len(src))
|
||||
// Huffman can never go < 1 bit/byte
|
||||
if bitsPerByte < 1024 {
|
||||
bitsPerByte = 1024
|
||||
}
|
||||
bitsPerByte := max(
|
||||
// Huffman can never go < 1 bit/byte
|
||||
int32((compress.ShannonEntropyBits(src)*1024)/len(src)), 1024)
|
||||
|
||||
// Override src
|
||||
src = e.hist
|
||||
@@ -235,10 +233,7 @@ encodeLoop:
|
||||
// Extend candidate match backwards as far as possible.
|
||||
// Do not extend repeats as we can assume they are optimal
|
||||
// and offsets change if s == nextEmit.
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
}
|
||||
tMin := max(s-e.maxMatchOff, 0)
|
||||
for offset > tMin && s > nextEmit && src[offset-1] == src[s-1] && l < maxMatchLength {
|
||||
s--
|
||||
offset--
|
||||
@@ -382,10 +377,7 @@ encodeLoop:
|
||||
nextEmit = s
|
||||
|
||||
// Index skipped...
|
||||
end := s
|
||||
if s > sLimit+4 {
|
||||
end = sLimit + 4
|
||||
}
|
||||
end := min(s, sLimit+4)
|
||||
off := index0 + e.cur
|
||||
for index0 < end {
|
||||
cv0 := load6432(src, index0)
|
||||
@@ -444,10 +436,7 @@ encodeLoop:
|
||||
nextEmit = s
|
||||
|
||||
// Index old s + 1 -> s - 1 or sLimit
|
||||
end := s
|
||||
if s > sLimit-4 {
|
||||
end = sLimit - 4
|
||||
}
|
||||
end := min(s, sLimit-4)
|
||||
|
||||
off := index0 + e.cur
|
||||
for index0 < end {
|
||||
|
||||
30
vendor/github.com/klauspost/compress/zstd/enc_better.go
generated
vendored
30
vendor/github.com/klauspost/compress/zstd/enc_better.go
generated
vendored
@@ -190,10 +190,7 @@ encodeLoop:
|
||||
// and have to do special offset treatment.
|
||||
startLimit := nextEmit + 1
|
||||
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
}
|
||||
tMin := max(s-e.maxMatchOff, 0)
|
||||
for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
|
||||
repIndex--
|
||||
start--
|
||||
@@ -252,10 +249,7 @@ encodeLoop:
|
||||
// and have to do special offset treatment.
|
||||
startLimit := nextEmit + 1
|
||||
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
}
|
||||
tMin := max(s-e.maxMatchOff, 0)
|
||||
for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
|
||||
repIndex--
|
||||
start--
|
||||
@@ -480,10 +474,7 @@ encodeLoop:
|
||||
l := matched
|
||||
|
||||
// Extend backwards
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
}
|
||||
tMin := max(s-e.maxMatchOff, 0)
|
||||
for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
|
||||
s--
|
||||
t--
|
||||
@@ -719,10 +710,7 @@ encodeLoop:
|
||||
// and have to do special offset treatment.
|
||||
startLimit := nextEmit + 1
|
||||
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
}
|
||||
tMin := max(s-e.maxMatchOff, 0)
|
||||
for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
|
||||
repIndex--
|
||||
start--
|
||||
@@ -783,10 +771,7 @@ encodeLoop:
|
||||
// and have to do special offset treatment.
|
||||
startLimit := nextEmit + 1
|
||||
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
}
|
||||
tMin := max(s-e.maxMatchOff, 0)
|
||||
for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
|
||||
repIndex--
|
||||
start--
|
||||
@@ -1005,10 +990,7 @@ encodeLoop:
|
||||
l := matched
|
||||
|
||||
// Extend backwards
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
}
|
||||
tMin := max(s-e.maxMatchOff, 0)
|
||||
for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
|
||||
s--
|
||||
t--
|
||||
|
||||
32
vendor/github.com/klauspost/compress/zstd/enc_dfast.go
generated
vendored
32
vendor/github.com/klauspost/compress/zstd/enc_dfast.go
generated
vendored
@@ -13,7 +13,7 @@ const (
|
||||
dFastLongLen = 8 // Bytes used for table hash
|
||||
|
||||
dLongTableShardCnt = 1 << (dFastLongTableBits - dictShardBits) // Number of shards in the table
|
||||
dLongTableShardSize = dFastLongTableSize / tableShardCnt // Size of an individual shard
|
||||
dLongTableShardSize = dFastLongTableSize / dLongTableShardCnt // Size of an individual shard
|
||||
|
||||
dFastShortTableBits = tableBits // Bits used in the short match table
|
||||
dFastShortTableSize = 1 << dFastShortTableBits // Size of the table
|
||||
@@ -149,10 +149,7 @@ encodeLoop:
|
||||
// and have to do special offset treatment.
|
||||
startLimit := nextEmit + 1
|
||||
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
}
|
||||
tMin := max(s-e.maxMatchOff, 0)
|
||||
for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
|
||||
repIndex--
|
||||
start--
|
||||
@@ -266,10 +263,7 @@ encodeLoop:
|
||||
l := e.matchlen(s+4, t+4, src) + 4
|
||||
|
||||
// Extend backwards
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
}
|
||||
tMin := max(s-e.maxMatchOff, 0)
|
||||
for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
|
||||
s--
|
||||
t--
|
||||
@@ -462,10 +456,7 @@ encodeLoop:
|
||||
// and have to do special offset treatment.
|
||||
startLimit := nextEmit + 1
|
||||
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
}
|
||||
tMin := max(s-e.maxMatchOff, 0)
|
||||
for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] {
|
||||
repIndex--
|
||||
start--
|
||||
@@ -576,10 +567,7 @@ encodeLoop:
|
||||
l := int32(matchLen(src[s+4:], src[t+4:])) + 4
|
||||
|
||||
// Extend backwards
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
}
|
||||
tMin := max(s-e.maxMatchOff, 0)
|
||||
for t > tMin && s > nextEmit && src[t-1] == src[s-1] {
|
||||
s--
|
||||
t--
|
||||
@@ -809,10 +797,7 @@ encodeLoop:
|
||||
// and have to do special offset treatment.
|
||||
startLimit := nextEmit + 1
|
||||
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
}
|
||||
tMin := max(s-e.maxMatchOff, 0)
|
||||
for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
|
||||
repIndex--
|
||||
start--
|
||||
@@ -927,10 +912,7 @@ encodeLoop:
|
||||
l := e.matchlen(s+4, t+4, src) + 4
|
||||
|
||||
// Extend backwards
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
}
|
||||
tMin := max(s-e.maxMatchOff, 0)
|
||||
for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
|
||||
s--
|
||||
t--
|
||||
|
||||
30
vendor/github.com/klauspost/compress/zstd/enc_fast.go
generated
vendored
30
vendor/github.com/klauspost/compress/zstd/enc_fast.go
generated
vendored
@@ -143,10 +143,7 @@ encodeLoop:
|
||||
// and have to do special offset treatment.
|
||||
startLimit := nextEmit + 1
|
||||
|
||||
sMin := s - e.maxMatchOff
|
||||
if sMin < 0 {
|
||||
sMin = 0
|
||||
}
|
||||
sMin := max(s-e.maxMatchOff, 0)
|
||||
for repIndex > sMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch {
|
||||
repIndex--
|
||||
start--
|
||||
@@ -223,10 +220,7 @@ encodeLoop:
|
||||
l := e.matchlen(s+4, t+4, src) + 4
|
||||
|
||||
// Extend backwards
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
}
|
||||
tMin := max(s-e.maxMatchOff, 0)
|
||||
for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
|
||||
s--
|
||||
t--
|
||||
@@ -387,10 +381,7 @@ encodeLoop:
|
||||
// and have to do special offset treatment.
|
||||
startLimit := nextEmit + 1
|
||||
|
||||
sMin := s - e.maxMatchOff
|
||||
if sMin < 0 {
|
||||
sMin = 0
|
||||
}
|
||||
sMin := max(s-e.maxMatchOff, 0)
|
||||
for repIndex > sMin && start > startLimit && src[repIndex-1] == src[start-1] {
|
||||
repIndex--
|
||||
start--
|
||||
@@ -469,10 +460,7 @@ encodeLoop:
|
||||
l := e.matchlen(s+4, t+4, src) + 4
|
||||
|
||||
// Extend backwards
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
}
|
||||
tMin := max(s-e.maxMatchOff, 0)
|
||||
for t > tMin && s > nextEmit && src[t-1] == src[s-1] {
|
||||
s--
|
||||
t--
|
||||
@@ -655,10 +643,7 @@ encodeLoop:
|
||||
// and have to do special offset treatment.
|
||||
startLimit := nextEmit + 1
|
||||
|
||||
sMin := s - e.maxMatchOff
|
||||
if sMin < 0 {
|
||||
sMin = 0
|
||||
}
|
||||
sMin := max(s-e.maxMatchOff, 0)
|
||||
for repIndex > sMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch {
|
||||
repIndex--
|
||||
start--
|
||||
@@ -735,10 +720,7 @@ encodeLoop:
|
||||
l := e.matchlen(s+4, t+4, src) + 4
|
||||
|
||||
// Extend backwards
|
||||
tMin := s - e.maxMatchOff
|
||||
if tMin < 0 {
|
||||
tMin = 0
|
||||
}
|
||||
tMin := max(s-e.maxMatchOff, 0)
|
||||
for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
|
||||
s--
|
||||
t--
|
||||
|
||||
5
vendor/github.com/klauspost/compress/zstd/framedec.go
generated
vendored
5
vendor/github.com/klauspost/compress/zstd/framedec.go
generated
vendored
@@ -238,10 +238,7 @@ func (d *frameDec) reset(br byteBuffer) error {
|
||||
|
||||
if d.WindowSize == 0 && d.SingleSegment {
|
||||
// We may not need window in this case.
|
||||
d.WindowSize = d.FrameContentSize
|
||||
if d.WindowSize < MinWindowSize {
|
||||
d.WindowSize = MinWindowSize
|
||||
}
|
||||
d.WindowSize = max(d.FrameContentSize, MinWindowSize)
|
||||
if d.WindowSize > d.o.maxDecodedSize {
|
||||
if debugDecoder {
|
||||
printf("window size %d > max %d\n", d.WindowSize, d.o.maxWindowSize)
|
||||
|
||||
2
vendor/github.com/klauspost/compress/zstd/fse_encoder.go
generated
vendored
2
vendor/github.com/klauspost/compress/zstd/fse_encoder.go
generated
vendored
@@ -149,7 +149,7 @@ func (s *fseEncoder) buildCTable() error {
|
||||
if v > largeLimit {
|
||||
s.zeroBits = true
|
||||
}
|
||||
for nbOccurrences := int16(0); nbOccurrences < v; nbOccurrences++ {
|
||||
for range v {
|
||||
tableSymbol[position] = symbol
|
||||
position = (position + step) & tableMask
|
||||
for position > highThreshold {
|
||||
|
||||
5
vendor/github.com/klauspost/compress/zstd/seqdec.go
generated
vendored
5
vendor/github.com/klauspost/compress/zstd/seqdec.go
generated
vendored
@@ -231,10 +231,7 @@ func (s *sequenceDecs) decodeSync(hist []byte) error {
|
||||
llTable, mlTable, ofTable := s.litLengths.fse.dt[:maxTablesize], s.matchLengths.fse.dt[:maxTablesize], s.offsets.fse.dt[:maxTablesize]
|
||||
llState, mlState, ofState := s.litLengths.state.state, s.matchLengths.state.state, s.offsets.state.state
|
||||
out := s.out
|
||||
maxBlockSize := maxCompressedBlockSize
|
||||
if s.windowSize < maxBlockSize {
|
||||
maxBlockSize = s.windowSize
|
||||
}
|
||||
maxBlockSize := min(s.windowSize, maxCompressedBlockSize)
|
||||
|
||||
if debugDecoder {
|
||||
println("decodeSync: decoding", seqs, "sequences", br.remain(), "bits remain on stream")
|
||||
|
||||
10
vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go
generated
vendored
10
vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go
generated
vendored
@@ -79,10 +79,7 @@ func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) {
|
||||
|
||||
br := s.br
|
||||
|
||||
maxBlockSize := maxCompressedBlockSize
|
||||
if s.windowSize < maxBlockSize {
|
||||
maxBlockSize = s.windowSize
|
||||
}
|
||||
maxBlockSize := min(s.windowSize, maxCompressedBlockSize)
|
||||
|
||||
ctx := decodeSyncAsmContext{
|
||||
llTable: s.litLengths.fse.dt[:maxTablesize],
|
||||
@@ -237,10 +234,7 @@ func sequenceDecs_decode_56_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmC
|
||||
func (s *sequenceDecs) decode(seqs []seqVals) error {
|
||||
br := s.br
|
||||
|
||||
maxBlockSize := maxCompressedBlockSize
|
||||
if s.windowSize < maxBlockSize {
|
||||
maxBlockSize = s.windowSize
|
||||
}
|
||||
maxBlockSize := min(s.windowSize, maxCompressedBlockSize)
|
||||
|
||||
ctx := decodeAsmContext{
|
||||
llTable: s.litLengths.fse.dt[:maxTablesize],
|
||||
|
||||
56
vendor/github.com/klauspost/compress/zstd/simple_go124.go
generated
vendored
Normal file
56
vendor/github.com/klauspost/compress/zstd/simple_go124.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright 2025+ Klaus Post. All rights reserved.
|
||||
// License information can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.24
|
||||
|
||||
package zstd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
"sync"
|
||||
"weak"
|
||||
)
|
||||
|
||||
var weakMu sync.Mutex
|
||||
var simpleEnc weak.Pointer[Encoder]
|
||||
var simpleDec weak.Pointer[Decoder]
|
||||
|
||||
// EncodeTo appends the encoded data from src to dst.
|
||||
func EncodeTo(dst []byte, src []byte) []byte {
|
||||
weakMu.Lock()
|
||||
enc := simpleEnc.Value()
|
||||
if enc == nil {
|
||||
var err error
|
||||
enc, err = NewWriter(nil, WithEncoderConcurrency(runtime.NumCPU()), WithWindowSize(1<<20), WithLowerEncoderMem(true), WithZeroFrames(true))
|
||||
if err != nil {
|
||||
panic("failed to create simple encoder: " + err.Error())
|
||||
}
|
||||
simpleEnc = weak.Make(enc)
|
||||
}
|
||||
weakMu.Unlock()
|
||||
|
||||
return enc.EncodeAll(src, dst)
|
||||
}
|
||||
|
||||
// DecodeTo appends the decoded data from src to dst.
|
||||
// The maximum decoded size is 1GiB,
|
||||
// not including what may already be in dst.
|
||||
func DecodeTo(dst []byte, src []byte) ([]byte, error) {
|
||||
weakMu.Lock()
|
||||
dec := simpleDec.Value()
|
||||
if dec == nil {
|
||||
var err error
|
||||
dec, err = NewReader(nil, WithDecoderConcurrency(runtime.NumCPU()), WithDecoderLowmem(true), WithDecoderMaxMemory(1<<30))
|
||||
if err != nil {
|
||||
weakMu.Unlock()
|
||||
return nil, errors.New("failed to create simple decoder: " + err.Error())
|
||||
}
|
||||
runtime.SetFinalizer(dec, func(d *Decoder) {
|
||||
d.Close()
|
||||
})
|
||||
simpleDec = weak.Make(dec)
|
||||
}
|
||||
weakMu.Unlock()
|
||||
return dec.DecodeAll(src, dst)
|
||||
}
|
||||
2
vendor/github.com/klauspost/compress/zstd/snappy.go
generated
vendored
2
vendor/github.com/klauspost/compress/zstd/snappy.go
generated
vendored
@@ -257,7 +257,7 @@ func (r *SnappyConverter) Convert(in io.Reader, w io.Writer) (int64, error) {
|
||||
if !r.readFull(r.buf[:len(snappyMagicBody)], false) {
|
||||
return written, r.err
|
||||
}
|
||||
for i := 0; i < len(snappyMagicBody); i++ {
|
||||
for i := range len(snappyMagicBody) {
|
||||
if r.buf[i] != snappyMagicBody[i] {
|
||||
println("r.buf[i] != snappyMagicBody[i]", r.buf[i], snappyMagicBody[i], i)
|
||||
r.err = ErrSnappyCorrupt
|
||||
|
||||
2
vendor/github.com/klauspost/compress/zstd/zip.go
generated
vendored
2
vendor/github.com/klauspost/compress/zstd/zip.go
generated
vendored
@@ -19,7 +19,7 @@ const ZipMethodWinZip = 93
|
||||
const ZipMethodPKWare = 20
|
||||
|
||||
// zipReaderPool is the default reader pool.
|
||||
var zipReaderPool = sync.Pool{New: func() interface{} {
|
||||
var zipReaderPool = sync.Pool{New: func() any {
|
||||
z, err := NewReader(nil, WithDecoderLowmem(true), WithDecoderMaxWindow(128<<20), WithDecoderConcurrency(1))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
||||
4
vendor/github.com/klauspost/compress/zstd/zstd.go
generated
vendored
4
vendor/github.com/klauspost/compress/zstd/zstd.go
generated
vendored
@@ -98,13 +98,13 @@ var (
|
||||
ErrDecoderNilInput = errors.New("nil input provided as reader")
|
||||
)
|
||||
|
||||
func println(a ...interface{}) {
|
||||
func println(a ...any) {
|
||||
if debug || debugDecoder || debugEncoder {
|
||||
log.Println(a...)
|
||||
}
|
||||
}
|
||||
|
||||
func printf(format string, a ...interface{}) {
|
||||
func printf(format string, a ...any) {
|
||||
if debug || debugDecoder || debugEncoder {
|
||||
log.Printf(format, a...)
|
||||
}
|
||||
|
||||
@@ -312,7 +312,7 @@ func (d *Dataset) SetProperty(key, val string) error {
|
||||
// A full list of available ZFS properties may be found in the ZFS manual:
|
||||
// https://openzfs.github.io/openzfs-docs/man/7/zfsprops.7.html.
|
||||
func (d *Dataset) GetProperty(key string) (string, error) {
|
||||
out, err := zfsOutput("get", "-H", key, d.Name)
|
||||
out, err := zfsOutput("get", "-Hp", key, d.Name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
191
vendor/github.com/moby/moby/api/LICENSE
generated
vendored
Normal file
191
vendor/github.com/moby/moby/api/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2013-2018 Docker, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://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.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user