diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1933e27d..c9c943a1 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -2,20 +2,23 @@ name: build
on:
push:
- branches:
- tags:
+ branches: ["**"]
+ tags: ["**"]
pull_request:
+permissions:
+ contents: read
+
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@v7
- name: set up go 1.26
- uses: actions/setup-go@v6
+ uses: actions/setup-go@v7
with:
go-version: "1.26"
id: go
@@ -58,24 +61,24 @@ jobs:
artifact: linux-arm64
runs-on: ${{ matrix.runner }}
steps:
- - uses: actions/checkout@v6
+ - uses: actions/checkout@v7
- - uses: docker/setup-buildx-action@v3
+ - uses: docker/setup-buildx-action@v4
- - uses: docker/login-action@v3
+ - uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.PKG_TOKEN }}
- - uses: docker/login-action@v3
+ - uses: docker/login-action@v4
with:
username: ${{ github.actor }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
- name: build and push by digest
id: build
- uses: docker/build-push-action@v6
+ uses: docker/build-push-action@v7
with:
context: .
platforms: ${{ matrix.platform }}
@@ -91,7 +94,7 @@ jobs:
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- - uses: actions/upload-artifact@v6
+ - uses: actions/upload-artifact@v7
with:
name: digests-${{ matrix.artifact }}
path: /tmp/digests/*
@@ -101,21 +104,21 @@ jobs:
needs: docker
runs-on: ubuntu-latest
steps:
- - uses: actions/download-artifact@v7
+ - uses: actions/download-artifact@v8
with:
path: /tmp/digests
pattern: digests-*
merge-multiple: true
- - uses: docker/setup-buildx-action@v3
+ - uses: docker/setup-buildx-action@v4
- - uses: docker/login-action@v3
+ - uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.PKG_TOKEN }}
- - uses: docker/login-action@v3
+ - uses: docker/login-action@v4
with:
username: ${{ github.actor }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
diff --git a/go.mod b/go.mod
index 8886c89a..9fdefe20 100644
--- a/go.mod
+++ b/go.mod
@@ -3,39 +3,34 @@ module github.com/umputun/docker-logger
go 1.26
require (
- github.com/fsouza/go-dockerclient v1.13.0
- github.com/go-pkgz/lgr v0.12.2
+ github.com/fsouza/go-dockerclient v1.13.2
+ github.com/go-pkgz/lgr v0.12.4
github.com/hashicorp/go-multierror v1.1.1
github.com/jessevdk/go-flags v1.6.1
github.com/pkg/errors v0.9.1
- github.com/stretchr/testify v1.11.1
+ github.com/stretchr/testify v1.12.1
gopkg.in/natefinch/lumberjack.v2 v2.2.1
)
require (
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
- github.com/Microsoft/go-winio v0.6.2 // indirect
+ github.com/Microsoft/go-winio v0.6.3-0.20251027160822-ad3df93bed29 // indirect
github.com/containerd/log v0.1.0 // indirect
- github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
- github.com/klauspost/compress v1.18.4 // indirect
- github.com/kr/text v0.2.0 // indirect
- github.com/moby/go-archive v0.2.0 // indirect
- github.com/moby/moby/api v1.53.0 // indirect
- github.com/moby/moby/client v0.2.2 // indirect
- github.com/moby/moby/v2 v2.0.0-beta.6 // indirect
- github.com/moby/patternmatcher v0.6.0 // indirect
- github.com/moby/sys/sequential v0.6.0 // indirect
- github.com/moby/sys/user v0.4.0 // indirect
- github.com/moby/sys/userns v0.1.0 // indirect
+ github.com/klauspost/compress v1.19.2 // indirect
+ github.com/moby/go-archive v0.3.3 // indirect
+ github.com/moby/moby/api v1.55.0 // indirect
+ github.com/moby/moby/client v0.5.1 // indirect
+ github.com/moby/patternmatcher v0.6.1 // indirect
+ github.com/moby/sys/sequential v0.7.0 // indirect
+ github.com/moby/sys/user v0.4.1 // indirect
+ github.com/moby/sys/userns v0.2.0 // indirect
github.com/moby/term v0.5.2 // indirect
- github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
- github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
- github.com/sirupsen/logrus v1.9.4 // indirect
- golang.org/x/sys v0.41.0 // indirect
- gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
- gopkg.in/yaml.v3 v3.0.1 // indirect
+ github.com/sirupsen/logrus v1.10.1 // indirect
+ go.yaml.in/yaml/v3 v3.0.5 // indirect
+ golang.org/x/sys v0.47.0 // indirect
+ golang.org/x/term v0.45.0 // indirect
)
diff --git a/go.sum b/go.sum
index 8b539634..43fdcb1a 100644
--- a/go.sum
+++ b/go.sum
@@ -2,21 +2,18 @@ github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8af
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
-github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
-github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
+github.com/Microsoft/go-winio v0.6.3-0.20251027160822-ad3df93bed29 h1:0kQAzHq8vLs7Pptv+7TxjdETLf/nIqJpIB4oC6Ba4vY=
+github.com/Microsoft/go-winio v0.6.3-0.20251027160822-ad3df93bed29/go.mod h1:ZWa7ssZJT30CCDGJ7fk/2SBTq9BIQrrVjrcss0UW2s0=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
-github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
-github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/fsouza/go-dockerclient v1.13.0 h1:i6VWBKrFprrqDDK6rEYw0Zp5KsN+cVlqZ/ODaIX2erM=
-github.com/fsouza/go-dockerclient v1.13.0/go.mod h1:slZeNd4OpH+YfOrTc4+fkjtq8fwKymehRReLvUVFfpI=
-github.com/go-pkgz/lgr v0.12.2 h1:EZ5NNdJuXdi4Yt3Yz1jcaRGVQYEG5j9vGgd7BYTiKbw=
-github.com/go-pkgz/lgr v0.12.2/go.mod h1:lpCDgVvCIxBHZp8+sGCj9MPctIzKZyZ3QdE19ddqd54=
+github.com/fsouza/go-dockerclient v1.13.2 h1:u+jAOuR9TZ3PAx2pdHA+ALt1ZZhS8Qx+A4d964IqXtw=
+github.com/fsouza/go-dockerclient v1.13.2/go.mod h1:SJu2b0vfcF8sbsWs9VVG03iEjsogvo7JADvsi2wVYAI=
+github.com/go-pkgz/lgr v0.12.4 h1:lDeQ4BR28ldXrKau6BOjq7A8nHzcXz+MF4xUfV4l1Ok=
+github.com/go-pkgz/lgr v0.12.4/go.mod h1:Lw6DkNRnCPyX07mqkiUK/p+eA1opq4GKkWfWia64RA8=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -26,55 +23,46 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4=
github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc=
-github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=
-github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/moby/go-archive v0.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8=
-github.com/moby/go-archive v0.2.0/go.mod h1:mNeivT14o8xU+5q1YnNrkQVpK+dnNe/K6fHqnTg4qPU=
-github.com/moby/moby/api v1.53.0 h1:PihqG1ncw4W+8mZs69jlwGXdaYBeb5brF6BL7mPIS/w=
-github.com/moby/moby/api v1.53.0/go.mod h1:8mb+ReTlisw4pS6BRzCMts5M49W5M7bKt1cJy/YbAqc=
-github.com/moby/moby/client v0.2.2 h1:Pt4hRMCAIlyjL3cr8M5TrXCwKzguebPAc2do2ur7dEM=
-github.com/moby/moby/client v0.2.2/go.mod h1:2EkIPVNCqR05CMIzL1mfA07t0HvVUUOl85pasRz/GmQ=
-github.com/moby/moby/v2 v2.0.0-beta.6 h1:esIpPmQk4oZyPkbu+5hDAE+as2LEKaYxQcWSC5zUGiM=
-github.com/moby/moby/v2 v2.0.0-beta.6/go.mod h1:nrC3bakOe44FcxsHAuvxsIHWtS4Vcf8Kn1j44kcZRLs=
-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/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
-github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
-github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
-github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
-github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
-github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
+github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8=
+github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
+github.com/moby/go-archive v0.3.3 h1:OxxR9paxsluYi+zDUEXTTaIxtkK3viymW+Ka7vRhhME=
+github.com/moby/go-archive v0.3.3/go.mod h1:Npdv43fFqlhZW7Xo8fbm3ZMYFvAGNviUPqX21VERbcE=
+github.com/moby/moby/api v1.55.0 h1:2/sexvQyqIWS8pRSCFddBfpW2qE7vR7FCL+vN8pxwMc=
+github.com/moby/moby/api v1.55.0/go.mod h1:+RQ6wluLwtYaTd1WnPLykIDPekkuyD/ROWQClE83pzs=
+github.com/moby/moby/client v0.5.1 h1:tYNaJno4c0HXz12y5BiqEDy0rVTYkWzI26lGvnTMiJw=
+github.com/moby/moby/client v0.5.1/go.mod h1:odLstlZ6uSnfvAgVxMpvgmb8SUdd+siH2T0GBuxVAlM=
+github.com/moby/patternmatcher v0.6.1 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U=
+github.com/moby/patternmatcher v0.6.1/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
+github.com/moby/sys/mount v0.3.5 h1:eS3fsZTjHaBihwjp4/+5Z3jxqLXYsbwxqpVSfFv3M00=
+github.com/moby/sys/mount v0.3.5/go.mod h1:WUQDO+/uCiCIkIztx8SrwIDVn2dtMFRBebRhpDFT71M=
+github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
+github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4=
+github.com/moby/sys/sequential v0.7.0 h1:ASQNGNROJSuOO6LL6bPHbKvuZu6NU8P4ldPWk31zj/8=
+github.com/moby/sys/sequential v0.7.0/go.mod h1:NfSTAp6V3fw4tmkD62PEcOKeZKquXT8VKCkf7aVR79o=
+github.com/moby/sys/user v0.4.1 h1:RgjRlaDKi/Xmyrz4t8lyzXT6v2ooFeO/7xtchmhVWE0=
+github.com/moby/sys/user v0.4.1/go.mod h1:E9QsW5WRe1kUAf7kW8hXKwu1uhsZEAdPLYHYSDudF4Y=
+github.com/moby/sys/userns v0.2.0 h1:nEtDtp7NCV/6dutSklNe8FrENPwFdc4mXnZqC/JWgXM=
+github.com/moby/sys/userns v0.2.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
-github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
-github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
-github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
-github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
-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/sirupsen/logrus v1.10.1 h1:xi4336Zh11WpU14fXR6I67V3yaTPQYwRx2WEtHbRg4Q=
+github.com/sirupsen/logrus v1.10.1/go.mod h1:vsQHnG7xzNsxk3NrwboUiWPnIC3dmbjcGPykD7+tiHk=
+github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE=
+github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg=
+go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
+go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
-golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
-golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=
-golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
-gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
+golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0=
+golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
-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=
diff --git a/vendor/github.com/Microsoft/go-winio/.golangci.yml b/vendor/github.com/Microsoft/go-winio/.golangci.yml
index faedfe93..924b5ce5 100644
--- a/vendor/github.com/Microsoft/go-winio/.golangci.yml
+++ b/vendor/github.com/Microsoft/go-winio/.golangci.yml
@@ -59,6 +59,10 @@ issues:
text: "^directive `//nolint:errorlint` should provide explanation"
source: '[=|!]= io.EOF'
+ - linters:
+ - gosec
+ text: "^G115: integer overflow conversion"
+
linters-settings:
exhaustive:
diff --git a/vendor/github.com/Microsoft/go-winio/backup.go b/vendor/github.com/Microsoft/go-winio/backup.go
index b54341da..7c2e4ba2 100644
--- a/vendor/github.com/Microsoft/go-winio/backup.go
+++ b/vendor/github.com/Microsoft/go-winio/backup.go
@@ -1,5 +1,4 @@
//go:build windows
-// +build windows
package winio
diff --git a/vendor/github.com/Microsoft/go-winio/file.go b/vendor/github.com/Microsoft/go-winio/file.go
index fe82a180..f3821376 100644
--- a/vendor/github.com/Microsoft/go-winio/file.go
+++ b/vendor/github.com/Microsoft/go-winio/file.go
@@ -1,5 +1,4 @@
//go:build windows
-// +build windows
package winio
diff --git a/vendor/github.com/Microsoft/go-winio/fileinfo.go b/vendor/github.com/Microsoft/go-winio/fileinfo.go
index c860eb99..01cd891e 100644
--- a/vendor/github.com/Microsoft/go-winio/fileinfo.go
+++ b/vendor/github.com/Microsoft/go-winio/fileinfo.go
@@ -1,5 +1,4 @@
//go:build windows
-// +build windows
package winio
diff --git a/vendor/github.com/Microsoft/go-winio/hvsock.go b/vendor/github.com/Microsoft/go-winio/hvsock.go
index c4fdd9d4..d4960f5b 100644
--- a/vendor/github.com/Microsoft/go-winio/hvsock.go
+++ b/vendor/github.com/Microsoft/go-winio/hvsock.go
@@ -1,5 +1,4 @@
//go:build windows
-// +build windows
package winio
diff --git a/vendor/github.com/Microsoft/go-winio/pipe.go b/vendor/github.com/Microsoft/go-winio/pipe.go
index a2da6639..58c68e95 100644
--- a/vendor/github.com/Microsoft/go-winio/pipe.go
+++ b/vendor/github.com/Microsoft/go-winio/pipe.go
@@ -1,5 +1,4 @@
//go:build windows
-// +build windows
package winio
diff --git a/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go
index 805bd354..b933821a 100644
--- a/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go
+++ b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go
@@ -1,5 +1,4 @@
//go:build !windows
-// +build !windows
package guid
diff --git a/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go
index 27e45ee5..4aa95a70 100644
--- a/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go
+++ b/vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go
@@ -1,5 +1,4 @@
//go:build windows
-// +build windows
package guid
diff --git a/vendor/github.com/Microsoft/go-winio/privilege.go b/vendor/github.com/Microsoft/go-winio/privilege.go
index d9b90b6e..747eefd3 100644
--- a/vendor/github.com/Microsoft/go-winio/privilege.go
+++ b/vendor/github.com/Microsoft/go-winio/privilege.go
@@ -1,5 +1,4 @@
//go:build windows
-// +build windows
package winio
diff --git a/vendor/github.com/Microsoft/go-winio/reparse.go b/vendor/github.com/Microsoft/go-winio/reparse.go
index 67d1a104..b03e517f 100644
--- a/vendor/github.com/Microsoft/go-winio/reparse.go
+++ b/vendor/github.com/Microsoft/go-winio/reparse.go
@@ -1,5 +1,4 @@
//go:build windows
-// +build windows
package winio
diff --git a/vendor/github.com/Microsoft/go-winio/sd.go b/vendor/github.com/Microsoft/go-winio/sd.go
index c3685e98..7834c6ad 100644
--- a/vendor/github.com/Microsoft/go-winio/sd.go
+++ b/vendor/github.com/Microsoft/go-winio/sd.go
@@ -1,5 +1,4 @@
//go:build windows
-// +build windows
package winio
diff --git a/vendor/github.com/fsouza/go-dockerclient/client.go b/vendor/github.com/fsouza/go-dockerclient/client.go
index 16ae3dbf..89ef9df1 100644
--- a/vendor/github.com/fsouza/go-dockerclient/client.go
+++ b/vendor/github.com/fsouza/go-dockerclient/client.go
@@ -32,7 +32,6 @@ import (
"github.com/moby/moby/api/pkg/stdcopy"
"github.com/moby/moby/client/pkg/jsonmessage"
- "github.com/moby/moby/v2/pkg/homedir"
)
const (
@@ -1001,7 +1000,7 @@ func addQueryStringValue(items url.Values, key string, v reflect.Value) bool {
vLen := v.Len()
var valuesAdded int
if vLen > 0 {
- for i := 0; i < vLen; i++ {
+ for i := range vLen {
if addQueryStringValue(items, key, v.Index(i)) {
valuesAdded++
}
@@ -1098,7 +1097,7 @@ func getDockerEnv() (*dockerEnv, error) {
if dockerTLSVerify {
dockerCertPath = os.Getenv("DOCKER_CERT_PATH")
if dockerCertPath == "" {
- home := homedir.Get()
+ home, _ := os.UserHomeDir()
if home == "" {
return nil, errors.New("environment variable HOME must be set if DOCKER_CERT_PATH is not set")
}
diff --git a/vendor/github.com/fsouza/go-dockerclient/container.go b/vendor/github.com/fsouza/go-dockerclient/container.go
index c6280714..df0e4151 100644
--- a/vendor/github.com/fsouza/go-dockerclient/container.go
+++ b/vendor/github.com/fsouza/go-dockerclient/container.go
@@ -47,7 +47,7 @@ type APIContainers struct {
SizeRootFs int64 `json:"SizeRootFs,omitempty" yaml:"SizeRootFs,omitempty" toml:"SizeRootFs,omitempty"`
Names []string `json:"Names,omitempty" yaml:"Names,omitempty" toml:"Names,omitempty"`
Labels map[string]string `json:"Labels,omitempty" yaml:"Labels,omitempty" toml:"Labels,omitempty"`
- Networks NetworkList `json:"NetworkSettings,omitempty" yaml:"NetworkSettings,omitempty" toml:"NetworkSettings,omitempty"`
+ Networks NetworkList `json:"NetworkSettings" yaml:"NetworkSettings,omitempty" toml:"NetworkSettings,omitempty"`
Mounts []APIMount `json:"Mounts,omitempty" yaml:"Mounts,omitempty" toml:"Mounts,omitempty"`
}
@@ -77,8 +77,8 @@ func (p Port) Proto() string {
// HealthCheck represents one check of health.
type HealthCheck struct {
- Start time.Time `json:"Start,omitempty" yaml:"Start,omitempty" toml:"Start,omitempty"`
- End time.Time `json:"End,omitempty" yaml:"End,omitempty" toml:"End,omitempty"`
+ Start time.Time `json:"Start" yaml:"Start,omitempty" toml:"Start,omitempty"`
+ End time.Time `json:"End" yaml:"End,omitempty" toml:"End,omitempty"`
ExitCode int `json:"ExitCode,omitempty" yaml:"ExitCode,omitempty" toml:"ExitCode,omitempty"`
Output string `json:"Output,omitempty" yaml:"Output,omitempty" toml:"Output,omitempty"`
}
@@ -102,9 +102,9 @@ type State struct {
Pid int `json:"Pid,omitempty" yaml:"Pid,omitempty" toml:"Pid,omitempty"`
ExitCode int `json:"ExitCode,omitempty" yaml:"ExitCode,omitempty" toml:"ExitCode,omitempty"`
Error string `json:"Error,omitempty" yaml:"Error,omitempty" toml:"Error,omitempty"`
- StartedAt time.Time `json:"StartedAt,omitempty" yaml:"StartedAt,omitempty" toml:"StartedAt,omitempty"`
- FinishedAt time.Time `json:"FinishedAt,omitempty" yaml:"FinishedAt,omitempty" toml:"FinishedAt,omitempty"`
- Health Health `json:"Health,omitempty" yaml:"Health,omitempty" toml:"Health,omitempty"`
+ StartedAt time.Time `json:"StartedAt" yaml:"StartedAt,omitempty" toml:"StartedAt,omitempty"`
+ FinishedAt time.Time `json:"FinishedAt" yaml:"FinishedAt,omitempty" toml:"FinishedAt,omitempty"`
+ Health Health `json:"Health" yaml:"Health,omitempty" toml:"Health,omitempty"`
}
// String returns a human-readable description of the state
@@ -314,7 +314,7 @@ type BindOptions struct {
type VolumeOptions struct {
NoCopy bool `json:"NoCopy,omitempty" yaml:"NoCopy,omitempty" toml:"NoCopy,omitempty"`
Labels map[string]string `json:"Labels,omitempty" yaml:"Labels,omitempty" toml:"Labels,omitempty"`
- DriverConfig VolumeDriverConfig `json:"DriverConfig,omitempty" yaml:"DriverConfig,omitempty" toml:"DriverConfig,omitempty"`
+ DriverConfig VolumeDriverConfig `json:"DriverConfig" yaml:"DriverConfig,omitempty" toml:"DriverConfig,omitempty"`
}
// TempfsOptions contains optional configuration for the tempfs type
@@ -406,13 +406,13 @@ type HealthConfig struct {
type Container struct {
ID string `json:"Id" yaml:"Id" toml:"Id"`
- Created time.Time `json:"Created,omitempty" yaml:"Created,omitempty" toml:"Created,omitempty"`
+ Created time.Time `json:"Created" yaml:"Created,omitempty" toml:"Created,omitempty"`
Path string `json:"Path,omitempty" yaml:"Path,omitempty" toml:"Path,omitempty"`
Args []string `json:"Args,omitempty" yaml:"Args,omitempty" toml:"Args,omitempty"`
Config *Config `json:"Config,omitempty" yaml:"Config,omitempty" toml:"Config,omitempty"`
- State State `json:"State,omitempty" yaml:"State,omitempty" toml:"State,omitempty"`
+ State State `json:"State" yaml:"State,omitempty" toml:"State,omitempty"`
Image string `json:"Image,omitempty" yaml:"Image,omitempty" toml:"Image,omitempty"`
Node *SwarmNode `json:"Node,omitempty" yaml:"Node,omitempty" toml:"Node,omitempty"`
@@ -507,11 +507,11 @@ type HostConfig struct {
ConsoleSize [2]int `json:"ConsoleSize,omitempty" yaml:"ConsoleSize,omitempty" toml:"ConsoleSize,omitempty"` // Windows only height x width
PidMode string `json:"PidMode,omitempty" yaml:"PidMode,omitempty" toml:"PidMode,omitempty"`
UTSMode string `json:"UTSMode,omitempty" yaml:"UTSMode,omitempty" toml:"UTSMode,omitempty"`
- RestartPolicy RestartPolicy `json:"RestartPolicy,omitempty" yaml:"RestartPolicy,omitempty" toml:"RestartPolicy,omitempty"`
+ RestartPolicy RestartPolicy `json:"RestartPolicy" yaml:"RestartPolicy,omitempty" toml:"RestartPolicy,omitempty"`
Devices []Device `json:"Devices,omitempty" yaml:"Devices,omitempty" toml:"Devices,omitempty"`
DeviceCgroupRules []string `json:"DeviceCgroupRules,omitempty" yaml:"DeviceCgroupRules,omitempty" toml:"DeviceCgroupRules,omitempty"`
DeviceRequests []DeviceRequest `json:"DeviceRequests,omitempty" yaml:"DeviceRequests,omitempty" toml:"DeviceRequests,omitempty"`
- LogConfig LogConfig `json:"LogConfig,omitempty" yaml:"LogConfig,omitempty" toml:"LogConfig,omitempty"`
+ LogConfig LogConfig `json:"LogConfig" yaml:"LogConfig,omitempty" toml:"LogConfig,omitempty"`
SecurityOpt []string `json:"SecurityOpt,omitempty" yaml:"SecurityOpt,omitempty" toml:"SecurityOpt,omitempty"`
CgroupnsMode string `json:"CgroupnsMode,omitempty" yaml:"CgroupnsMode,omitempty" toml:"CgroupnsMode,omitempty"` // v1.40+
Cgroup string `json:"Cgroup,omitempty" yaml:"Cgroup,omitempty" toml:"Cgroup,omitempty"`
diff --git a/vendor/github.com/fsouza/go-dockerclient/container_stats.go b/vendor/github.com/fsouza/go-dockerclient/container_stats.go
index 99d9faa3..67a3eacf 100644
--- a/vendor/github.com/fsouza/go-dockerclient/container_stats.go
+++ b/vendor/github.com/fsouza/go-dockerclient/container_stats.go
@@ -14,13 +14,13 @@ import (
//
// See https://goo.gl/Dk3Xio for more details.
type Stats struct {
- Read time.Time `json:"read,omitempty" yaml:"read,omitempty" toml:"read,omitempty"`
- PreRead time.Time `json:"preread,omitempty" yaml:"preread,omitempty" toml:"preread,omitempty"`
+ Read time.Time `json:"read" yaml:"read,omitempty" toml:"read,omitempty"`
+ PreRead time.Time `json:"preread" yaml:"preread,omitempty" toml:"preread,omitempty"`
NumProcs uint32 `json:"num_procs" yaml:"num_procs" toml:"num_procs"`
PidsStats struct {
Current uint64 `json:"current,omitempty" yaml:"current,omitempty"`
- } `json:"pids_stats,omitempty" yaml:"pids_stats,omitempty" toml:"pids_stats,omitempty"`
- Network NetworkStats `json:"network,omitempty" yaml:"network,omitempty" toml:"network,omitempty"`
+ } `json:"pids_stats" yaml:"pids_stats,omitempty" toml:"pids_stats,omitempty"`
+ Network NetworkStats `json:"network" yaml:"network,omitempty" toml:"network,omitempty"`
Networks map[string]NetworkStats `json:"networks,omitempty" yaml:"networks,omitempty" toml:"networks,omitempty"`
MemoryStats struct {
Stats struct {
@@ -79,7 +79,7 @@ type Stats struct {
WorkingsetActivate uint64 `json:"workingset_activate,omitempty" yaml:"workingset_activate,omitempty" toml:"workingset_activate,omitempty"`
WorkingsetNodereclaim uint64 `json:"workingset_nodereclaim,omitempty" yaml:"workingset_nodereclaim,omitempty" toml:"workingset_nodereclaim,omitempty"`
WorkingsetRefault uint64 `json:"workingset_refault,omitempty" yaml:"workingset_refault,omitempty" toml:"workingset_refault,omitempty"`
- } `json:"stats,omitempty" yaml:"stats,omitempty" toml:"stats,omitempty"`
+ } `json:"stats" yaml:"stats,omitempty" toml:"stats,omitempty"`
MaxUsage uint64 `json:"max_usage,omitempty" yaml:"max_usage,omitempty" toml:"max_usage,omitempty"`
Usage uint64 `json:"usage,omitempty" yaml:"usage,omitempty" toml:"usage,omitempty"`
Failcnt uint64 `json:"failcnt,omitempty" yaml:"failcnt,omitempty" toml:"failcnt,omitempty"`
@@ -87,7 +87,7 @@ type Stats struct {
Commit uint64 `json:"commitbytes,omitempty" yaml:"commitbytes,omitempty" toml:"privateworkingset,omitempty"`
CommitPeak uint64 `json:"commitpeakbytes,omitempty" yaml:"commitpeakbytes,omitempty" toml:"commitpeakbytes,omitempty"`
PrivateWorkingSet uint64 `json:"privateworkingset,omitempty" yaml:"privateworkingset,omitempty" toml:"privateworkingset,omitempty"`
- } `json:"memory_stats,omitempty" yaml:"memory_stats,omitempty" toml:"memory_stats,omitempty"`
+ } `json:"memory_stats" yaml:"memory_stats,omitempty" toml:"memory_stats,omitempty"`
BlkioStats struct {
IOServiceBytesRecursive []BlkioStatsEntry `json:"io_service_bytes_recursive,omitempty" yaml:"io_service_bytes_recursive,omitempty" toml:"io_service_bytes_recursive,omitempty"`
IOServicedRecursive []BlkioStatsEntry `json:"io_serviced_recursive,omitempty" yaml:"io_serviced_recursive,omitempty" toml:"io_serviced_recursive,omitempty"`
@@ -97,15 +97,15 @@ type Stats struct {
IOMergedRecursive []BlkioStatsEntry `json:"io_merged_recursive,omitempty" yaml:"io_merged_recursive,omitempty" toml:"io_merged_recursive,omitempty"`
IOTimeRecursive []BlkioStatsEntry `json:"io_time_recursive,omitempty" yaml:"io_time_recursive,omitempty" toml:"io_time_recursive,omitempty"`
SectorsRecursive []BlkioStatsEntry `json:"sectors_recursive,omitempty" yaml:"sectors_recursive,omitempty" toml:"sectors_recursive,omitempty"`
- } `json:"blkio_stats,omitempty" yaml:"blkio_stats,omitempty" toml:"blkio_stats,omitempty"`
- CPUStats CPUStats `json:"cpu_stats,omitempty" yaml:"cpu_stats,omitempty" toml:"cpu_stats,omitempty"`
- PreCPUStats CPUStats `json:"precpu_stats,omitempty"`
+ } `json:"blkio_stats" yaml:"blkio_stats,omitempty" toml:"blkio_stats,omitempty"`
+ CPUStats CPUStats `json:"cpu_stats" yaml:"cpu_stats,omitempty" toml:"cpu_stats,omitempty"`
+ PreCPUStats CPUStats `json:"precpu_stats"`
StorageStats struct {
ReadCountNormalized uint64 `json:"read_count_normalized,omitempty" yaml:"read_count_normalized,omitempty" toml:"read_count_normalized,omitempty"`
ReadSizeBytes uint64 `json:"read_size_bytes,omitempty" yaml:"read_size_bytes,omitempty" toml:"read_size_bytes,omitempty"`
WriteCountNormalized uint64 `json:"write_count_normalized,omitempty" yaml:"write_count_normalized,omitempty" toml:"write_count_normalized,omitempty"`
WriteSizeBytes uint64 `json:"write_size_bytes,omitempty" yaml:"write_size_bytes,omitempty" toml:"write_size_bytes,omitempty"`
- } `json:"storage_stats,omitempty" yaml:"storage_stats,omitempty" toml:"storage_stats,omitempty"`
+ } `json:"storage_stats" yaml:"storage_stats,omitempty" toml:"storage_stats,omitempty"`
}
// NetworkStats is a stats entry for network stats
@@ -127,14 +127,14 @@ type CPUStats struct {
UsageInUsermode uint64 `json:"usage_in_usermode,omitempty" yaml:"usage_in_usermode,omitempty" toml:"usage_in_usermode,omitempty"`
TotalUsage uint64 `json:"total_usage,omitempty" yaml:"total_usage,omitempty" toml:"total_usage,omitempty"`
UsageInKernelmode uint64 `json:"usage_in_kernelmode,omitempty" yaml:"usage_in_kernelmode,omitempty" toml:"usage_in_kernelmode,omitempty"`
- } `json:"cpu_usage,omitempty" yaml:"cpu_usage,omitempty" toml:"cpu_usage,omitempty"`
+ } `json:"cpu_usage" yaml:"cpu_usage,omitempty" toml:"cpu_usage,omitempty"`
SystemCPUUsage uint64 `json:"system_cpu_usage,omitempty" yaml:"system_cpu_usage,omitempty" toml:"system_cpu_usage,omitempty"`
OnlineCPUs uint64 `json:"online_cpus,omitempty" yaml:"online_cpus,omitempty" toml:"online_cpus,omitempty"`
ThrottlingData struct {
Periods uint64 `json:"periods,omitempty"`
ThrottledPeriods uint64 `json:"throttled_periods,omitempty"`
ThrottledTime uint64 `json:"throttled_time,omitempty"`
- } `json:"throttling_data,omitempty" yaml:"throttling_data,omitempty" toml:"throttling_data,omitempty"`
+ } `json:"throttling_data" yaml:"throttling_data,omitempty" toml:"throttling_data,omitempty"`
}
// BlkioStatsEntry is a stats entry for blkio_stats
diff --git a/vendor/github.com/fsouza/go-dockerclient/container_update.go b/vendor/github.com/fsouza/go-dockerclient/container_update.go
index b44fc847..b17837e5 100644
--- a/vendor/github.com/fsouza/go-dockerclient/container_update.go
+++ b/vendor/github.com/fsouza/go-dockerclient/container_update.go
@@ -23,7 +23,7 @@ type UpdateContainerOptions struct {
MemoryReservation int `json:"MemoryReservation"`
// Deprecated: KernelMemory is deprecated as of API 1.42 and removed in API 1.52.
KernelMemory int `json:"KernelMemory"`
- RestartPolicy RestartPolicy `json:"RestartPolicy,omitempty"`
+ RestartPolicy RestartPolicy `json:"RestartPolicy"`
Context context.Context
}
diff --git a/vendor/github.com/fsouza/go-dockerclient/event.go b/vendor/github.com/fsouza/go-dockerclient/event.go
index 22d64f6a..dbe1c353 100644
--- a/vendor/github.com/fsouza/go-dockerclient/event.go
+++ b/vendor/github.com/fsouza/go-dockerclient/event.go
@@ -12,6 +12,7 @@ import (
"net"
"net/http"
"net/http/httputil"
+ "slices"
"strconv"
"sync"
"sync/atomic"
@@ -65,7 +66,7 @@ type APIEvents struct {
// New API Fields in 1.22
Action string `json:"action,omitempty"`
Type string `json:"type,omitempty"`
- Actor APIActor `json:"actor,omitempty"`
+ Actor APIActor `json:"actor"`
// Old API fields for < 1.22
Status string `json:"status,omitempty"`
@@ -197,12 +198,7 @@ func (eventState *eventMonitoringState) listernersCount() int {
}
func listenerExists(a chan<- *APIEvents, list *[]chan<- *APIEvents) bool {
- for _, b := range *list {
- if b == a {
- return true
- }
- }
- return false
+ return slices.Contains(*list, a)
}
func (eventState *eventMonitoringState) enableEventMonitoring(c *Client, opts EventsOptions) error {
diff --git a/vendor/github.com/fsouza/go-dockerclient/exec.go b/vendor/github.com/fsouza/go-dockerclient/exec.go
index c8399b0b..f2788a41 100644
--- a/vendor/github.com/fsouza/go-dockerclient/exec.go
+++ b/vendor/github.com/fsouza/go-dockerclient/exec.go
@@ -183,7 +183,7 @@ type ExecProcessConfig struct {
type ExecInspect struct {
ID string `json:"ID,omitempty" yaml:"ID,omitempty" toml:"ID,omitempty"`
ExitCode int `json:"ExitCode,omitempty" yaml:"ExitCode,omitempty" toml:"ExitCode,omitempty"`
- ProcessConfig ExecProcessConfig `json:"ProcessConfig,omitempty" yaml:"ProcessConfig,omitempty" toml:"ProcessConfig,omitempty"`
+ ProcessConfig ExecProcessConfig `json:"ProcessConfig" yaml:"ProcessConfig,omitempty" toml:"ProcessConfig,omitempty"`
ContainerID string `json:"ContainerID,omitempty" yaml:"ContainerID,omitempty" toml:"ContainerID,omitempty"`
DetachKeys string `json:"DetachKeys,omitempty" yaml:"DetachKeys,omitempty" toml:"DetachKeys,omitempty"`
Running bool `json:"Running,omitempty" yaml:"Running,omitempty" toml:"Running,omitempty"`
diff --git a/vendor/github.com/fsouza/go-dockerclient/image.go b/vendor/github.com/fsouza/go-dockerclient/image.go
index 5998ea70..2d3c4b65 100644
--- a/vendor/github.com/fsouza/go-dockerclient/image.go
+++ b/vendor/github.com/fsouza/go-dockerclient/image.go
@@ -43,9 +43,9 @@ type Image struct {
RepoTags []string `json:"RepoTags,omitempty" yaml:"RepoTags,omitempty" toml:"RepoTags,omitempty"`
Parent string `json:"Parent,omitempty" yaml:"Parent,omitempty" toml:"Parent,omitempty"`
Comment string `json:"Comment,omitempty" yaml:"Comment,omitempty" toml:"Comment,omitempty"`
- Created time.Time `json:"Created,omitempty" yaml:"Created,omitempty" toml:"Created,omitempty"`
+ Created time.Time `json:"Created" yaml:"Created,omitempty" toml:"Created,omitempty"`
Container string `json:"Container,omitempty" yaml:"Container,omitempty" toml:"Container,omitempty"`
- ContainerConfig Config `json:"ContainerConfig,omitempty" yaml:"ContainerConfig,omitempty" toml:"ContainerConfig,omitempty"`
+ ContainerConfig Config `json:"ContainerConfig" yaml:"ContainerConfig,omitempty" toml:"ContainerConfig,omitempty"`
DockerVersion string `json:"DockerVersion,omitempty" yaml:"DockerVersion,omitempty" toml:"DockerVersion,omitempty"`
Author string `json:"Author,omitempty" yaml:"Author,omitempty" toml:"Author,omitempty"`
Config *Config `json:"Config,omitempty" yaml:"Config,omitempty" toml:"Config,omitempty"`
@@ -66,7 +66,7 @@ type ImagePre012 struct {
Comment string `json:"comment,omitempty"`
Created time.Time `json:"created"`
Container string `json:"container,omitempty"`
- ContainerConfig Config `json:"container_config,omitempty"`
+ ContainerConfig Config `json:"container_config"`
DockerVersion string `json:"docker_version,omitempty"`
Author string `json:"author,omitempty"`
Config *Config `json:"config,omitempty"`
@@ -411,12 +411,13 @@ func (c *Client) ExportImages(opts ExportImagesOptions) error {
var err error
var exporturl string
if c.requestedAPIVersion.GreaterThanOrEqualTo(apiVersion125) {
- str := opts.Names[0]
+ var str strings.Builder
+ str.WriteString(opts.Names[0])
for _, val := range opts.Names[1:] {
- str += "," + val
+ str.WriteString("," + val)
}
exporturl, err = c.getPath("/images/get", ExportImagesOptions{
- Names: []string{str},
+ Names: []string{str.String()},
OutputStream: opts.OutputStream,
InactivityTimeout: opts.InactivityTimeout,
Context: opts.Context,
@@ -442,6 +443,7 @@ type ImportImageOptions struct {
Repository string `qs:"repo"`
Source string `qs:"fromSrc"`
Tag string `qs:"tag"`
+ Platform string `qs:"platform" ver:"1.32"`
InputStream io.Reader `qs:"-"`
OutputStream io.Writer `qs:"-"`
diff --git a/vendor/github.com/fsouza/go-dockerclient/misc.go b/vendor/github.com/fsouza/go-dockerclient/misc.go
index 7fd5f841..b7e1b8dc 100644
--- a/vendor/github.com/fsouza/go-dockerclient/misc.go
+++ b/vendor/github.com/fsouza/go-dockerclient/misc.go
@@ -110,7 +110,7 @@ type ContainerdInfo struct {
Namespaces struct {
Containers string `json:"Containers,omitempty"`
Plugins string `json:"Plugins,omitempty"`
- } `json:"Namespaces,omitempty"`
+ } `json:"Namespaces"`
}
// SwarmInfo contains basic swarm information from docker info.
diff --git a/vendor/github.com/fsouza/go-dockerclient/plugin.go b/vendor/github.com/fsouza/go-dockerclient/plugin.go
index 7951e362..044ffd5f 100644
--- a/vendor/github.com/fsouza/go-dockerclient/plugin.go
+++ b/vendor/github.com/fsouza/go-dockerclient/plugin.go
@@ -136,16 +136,16 @@ type PluginUser struct {
type PluginConfig struct {
Description string `json:"Description,omitempty" yaml:"Description,omitempty" toml:"Description,omitempty"`
Documentation string
- Interface PluginInterface `json:"Interface,omitempty" yaml:"Interface,omitempty" toml:"Interface,omitempty"`
+ Interface PluginInterface `json:"Interface" yaml:"Interface,omitempty" toml:"Interface,omitempty"`
Entrypoint []string `json:"Entrypoint,omitempty" yaml:"Entrypoint,omitempty" toml:"Entrypoint,omitempty"`
WorkDir string `json:"WorkDir,omitempty" yaml:"WorkDir,omitempty" toml:"WorkDir,omitempty"`
- User PluginUser `json:"User,omitempty" yaml:"User,omitempty" toml:"User,omitempty"`
- Network PluginNetwork `json:"Network,omitempty" yaml:"Network,omitempty" toml:"Network,omitempty"`
- Linux PluginLinux `json:"Linux,omitempty" yaml:"Linux,omitempty" toml:"Linux,omitempty"`
+ User PluginUser `json:"User" yaml:"User,omitempty" toml:"User,omitempty"`
+ Network PluginNetwork `json:"Network" yaml:"Network,omitempty" toml:"Network,omitempty"`
+ Linux PluginLinux `json:"Linux" yaml:"Linux,omitempty" toml:"Linux,omitempty"`
PropagatedMount string `json:"PropagatedMount,omitempty" yaml:"PropagatedMount,omitempty" toml:"PropagatedMount,omitempty"`
Mounts []Mount `json:"Mounts,omitempty" yaml:"Mounts,omitempty" toml:"Mounts,omitempty"`
Env []PluginEnv `json:"Env,omitempty" yaml:"Env,omitempty" toml:"Env,omitempty"`
- Args PluginArgs `json:"Args,omitempty" yaml:"Args,omitempty" toml:"Args,omitempty"`
+ Args PluginArgs `json:"Args" yaml:"Args,omitempty" toml:"Args,omitempty"`
}
// PluginDetail specify results from the ListPlugins function.
@@ -156,8 +156,8 @@ type PluginDetail struct {
Name string `json:"Name,omitempty" yaml:"Name,omitempty" toml:"Name,omitempty"`
Tag string `json:"Tag,omitempty" yaml:"Tag,omitempty" toml:"Tag,omitempty"`
Active bool `json:"Enabled,omitempty" yaml:"Active,omitempty" toml:"Active,omitempty"`
- Settings PluginSettings `json:"Settings,omitempty" yaml:"Settings,omitempty" toml:"Settings,omitempty"`
- Config PluginConfig `json:"Config,omitempty" yaml:"Config,omitempty" toml:"Config,omitempty"`
+ Settings PluginSettings `json:"Settings" yaml:"Settings,omitempty" toml:"Settings,omitempty"`
+ Config PluginConfig `json:"Config" yaml:"Config,omitempty" toml:"Config,omitempty"`
}
// ListPlugins returns pluginDetails or an error.
diff --git a/vendor/github.com/fsouza/go-dockerclient/volume.go b/vendor/github.com/fsouza/go-dockerclient/volume.go
index 92dcb71b..00e73f5e 100644
--- a/vendor/github.com/fsouza/go-dockerclient/volume.go
+++ b/vendor/github.com/fsouza/go-dockerclient/volume.go
@@ -29,7 +29,7 @@ type Volume struct {
Mountpoint string `json:"Mountpoint,omitempty" yaml:"Mountpoint,omitempty" toml:"Mountpoint,omitempty"`
Labels map[string]string `json:"Labels,omitempty" yaml:"Labels,omitempty" toml:"Labels,omitempty"`
Options map[string]string `json:"Options,omitempty" yaml:"Options,omitempty" toml:"Options,omitempty"`
- CreatedAt time.Time `json:"CreatedAt,omitempty" yaml:"CreatedAt,omitempty" toml:"CreatedAt,omitempty"`
+ CreatedAt time.Time `json:"CreatedAt" yaml:"CreatedAt,omitempty" toml:"CreatedAt,omitempty"`
}
// ListVolumesOptions specify parameters to the ListVolumes function.
diff --git a/vendor/github.com/go-pkgz/lgr/CLAUDE.md b/vendor/github.com/go-pkgz/lgr/CLAUDE.md
new file mode 100644
index 00000000..76818245
--- /dev/null
+++ b/vendor/github.com/go-pkgz/lgr/CLAUDE.md
@@ -0,0 +1,28 @@
+# Go-PKGZ/LGR Development Guidelines
+
+## Build & Test Commands
+- Build: `go build -race`
+- Test all: `go test -timeout=60s -race -covermode=atomic -coverprofile=profile.cov`
+- Test single file: `go test -run TestName`
+- Benchmark: `go test -bench=. -run=Bench`
+- Lint: `golangci-lint run`
+
+## Code Style Guidelines
+- Go 1.21 compatibility required
+- Maximum line length: 140 characters
+- No package names with underscores
+- Use early returns (enforced by prealloc linter)
+- Test files use testify for assertions: `require` for fatal assertions, `assert` for non-fatal ones
+- Indent with tabs, not spaces
+
+## Error Handling
+- FATAL logs to stderr and calls os.Exit(1)
+- ERROR logs to both stdout and stderr
+- PANIC logs stack trace and runtime info to stderr
+- Stack traces for ERROR level can be enabled with StackTraceOnError option
+
+## Project Conventions
+- Public API follows interface-based design (`lgr.L` interface)
+- Avoid global loggers, prefer dependency injection
+- Functional options pattern for logger configuration
+- Secret logging sanitization with `lgr.Secret` option
\ No newline at end of file
diff --git a/vendor/github.com/go-pkgz/lgr/logger.go b/vendor/github.com/go-pkgz/lgr/logger.go
index 14ae39ca..20ab5097 100644
--- a/vendor/github.com/go-pkgz/lgr/logger.go
+++ b/vendor/github.com/go-pkgz/lgr/logger.go
@@ -164,6 +164,12 @@ func (l *Logger) logf(format string, args ...interface{}) {
return
}
+ // hide secrets in the message itself, covers slog handler and panic dump paths
+ // as well as the formatted line redacted later in this function
+ if len(l.secrets) > 0 {
+ msg = string(l.hideSecrets([]byte(msg)))
+ }
+
// if slog handler is set, use it
if l.slogHandler != nil {
// get the caller's PC so slog handlers can resolve source info when AddSource is enabled
diff --git a/vendor/github.com/go-pkgz/lgr/slog.go b/vendor/github.com/go-pkgz/lgr/slog.go
index 3b121986..dd9ac3ab 100644
--- a/vendor/github.com/go-pkgz/lgr/slog.go
+++ b/vendor/github.com/go-pkgz/lgr/slog.go
@@ -23,13 +23,13 @@ func FromSlogHandler(h slog.Handler) L {
// SetupWithSlog sets up the global logger with a slog logger
func SetupWithSlog(logger *slog.Logger) {
options := []Option{SlogHandler(logger.Handler())}
-
+
// check if the slog handler is enabled for debug level
// if so, enable debug mode in lgr to prevent filtering
if logger.Handler().Enabled(context.Background(), slog.LevelDebug) {
options = append(options, Debug)
}
-
+
Setup(options...)
}
@@ -59,12 +59,6 @@ func (h *lgrSlogHandler) Handle(_ context.Context, record slog.Record) error {
// build message with attributes
msg := record.Message
- // add time if record has it, otherwise current time is used by lgr
- var timeStr string
- if !record.Time.IsZero() {
- timeStr = record.Time.Format("2006/01/02 15:04:05.000 ")
- }
-
// format attributes as key=value pairs
var attrs strings.Builder
if len(h.attrs) > 0 || record.NumAttrs() > 0 {
@@ -82,8 +76,8 @@ func (h *lgrSlogHandler) Handle(_ context.Context, record slog.Record) error {
return true
})
- // combine everything into final message
- logMsg := fmt.Sprintf("%s%s %s%s", timeStr, level, msg, attrs.String())
+ // combine level prefix and message; lgr.Logf adds its own timestamp and level formatting
+ logMsg := fmt.Sprintf("%s %s%s", level, msg, attrs.String())
h.lgr.Logf(logMsg)
return nil
}
diff --git a/vendor/github.com/klauspost/compress/.gitattributes b/vendor/github.com/klauspost/compress/.gitattributes
index 40243359..57aa6487 100644
--- a/vendor/github.com/klauspost/compress/.gitattributes
+++ b/vendor/github.com/klauspost/compress/.gitattributes
@@ -1,2 +1,3 @@
* -text
*.bin -text -diff
+*.md text eol=lf
diff --git a/vendor/github.com/klauspost/compress/.goreleaser.yml b/vendor/github.com/klauspost/compress/.goreleaser.yml
index 4528059c..804a2018 100644
--- a/vendor/github.com/klauspost/compress/.goreleaser.yml
+++ b/vendor/github.com/klauspost/compress/.goreleaser.yml
@@ -31,6 +31,9 @@ builds:
- mips64le
goarm:
- 7
+ ignore:
+ - goos: windows
+ goarch: arm
-
id: "s2d"
binary: s2d
@@ -57,6 +60,9 @@ builds:
- mips64le
goarm:
- 7
+ ignore:
+ - goos: windows
+ goarch: arm
-
id: "s2sx"
binary: s2sx
@@ -84,6 +90,9 @@ builds:
- mips64le
goarm:
- 7
+ ignore:
+ - goos: windows
+ goarch: arm
archives:
-
@@ -91,7 +100,7 @@ archives:
name_template: "s2-{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
format_overrides:
- goos: windows
- format: zip
+ formats: ['zip']
files:
- unpack/*
- s2/LICENSE
diff --git a/vendor/github.com/klauspost/compress/README.md b/vendor/github.com/klauspost/compress/README.md
index 5125c1f2..0e9f170d 100644
--- a/vendor/github.com/klauspost/compress/README.md
+++ b/vendor/github.com/klauspost/compress/README.md
@@ -1,693 +1,712 @@
-# compress
-
-This package provides various compression algorithms.
-
-* [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and decompression in pure Go.
-* [S2](https://github.com/klauspost/compress/tree/master/s2#s2-compression) is a high performance replacement for Snappy.
-* Optimized [deflate](https://godoc.org/github.com/klauspost/compress/flate) packages which can be used as a dropin replacement for [gzip](https://godoc.org/github.com/klauspost/compress/gzip), [zip](https://godoc.org/github.com/klauspost/compress/zip) and [zlib](https://godoc.org/github.com/klauspost/compress/zlib).
-* [snappy](https://github.com/klauspost/compress/tree/master/snappy) is a drop-in replacement for `github.com/golang/snappy` offering better compression and concurrent streams.
-* [huff0](https://github.com/klauspost/compress/tree/master/huff0) and [FSE](https://github.com/klauspost/compress/tree/master/fse) implementations for raw entropy encoding.
-* [gzhttp](https://github.com/klauspost/compress/tree/master/gzhttp) Provides client and server wrappers for handling gzipped/zstd HTTP requests efficiently.
-* [pgzip](https://github.com/klauspost/pgzip) is a separate package that provides a very fast parallel gzip implementation.
-
-[](https://pkg.go.dev/github.com/klauspost/compress?tab=subdirectories)
-[](https://github.com/klauspost/compress/actions/workflows/go.yml)
-[](https://sourcegraph.com/github.com/klauspost/compress?badge)
-
-# package usage
-
-Use `go get github.com/klauspost/compress@latest` to add it to your project.
-
-This package will support the current Go version and 2 versions back.
-
-* Use the `nounsafe` tag to disable all use of the "unsafe" package.
-* Use the `noasm` tag to disable all assembly across packages.
-
-Use the links above for more information on each.
-
-# changelog
-* Jan 16th, 2026 [1.18.3](https://github.com/klauspost/compress/releases/tag/v1.18.3)
- * Downstream CVE-2025-61728. See [golang/go#77102](https://github.com/golang/go/issues/77102).
-
-* Dec 1st, 2025 - [1.18.2](https://github.com/klauspost/compress/releases/tag/v1.18.2)
- * flate: Fix invalid encoding on level 9 with single value input in https://github.com/klauspost/compress/pull/1115
- * flate: reduce stateless allocations by @RXamzin in https://github.com/klauspost/compress/pull/1106
-
-* Oct 20, 2025 - [1.18.1](https://github.com/klauspost/compress/releases/tag/v1.18.1) - RETRACTED
- * zstd: Add simple zstd EncodeTo/DecodeTo functions https://github.com/klauspost/compress/pull/1079
- * zstd: Fix incorrect buffer size in dictionary encodes https://github.com/klauspost/compress/pull/1059
- * s2: check for cap, not len of buffer in EncodeBetter/Best by @vdarulis in https://github.com/klauspost/compress/pull/1080
- * zlib: Avoiding extra allocation in zlib.reader.Reset by @travelpolicy in https://github.com/klauspost/compress/pull/1086
- * gzhttp: remove redundant err check in zstdReader by @ryanfowler in https://github.com/klauspost/compress/pull/1090
- * flate: Faster load+store https://github.com/klauspost/compress/pull/1104
- * flate: Simplify matchlen https://github.com/klauspost/compress/pull/1101
- * flate: Use exact sizes for huffman tables https://github.com/klauspost/compress/pull/1103
-
-* Feb 19th, 2025 - [1.18.0](https://github.com/klauspost/compress/releases/tag/v1.18.0)
- * Add unsafe little endian loaders https://github.com/klauspost/compress/pull/1036
- * fix: check `r.err != nil` but return a nil value error `err` by @alingse in https://github.com/klauspost/compress/pull/1028
- * flate: Simplify L4-6 loading https://github.com/klauspost/compress/pull/1043
- * flate: Simplify matchlen (remove asm) https://github.com/klauspost/compress/pull/1045
- * s2: Improve small block compression speed w/o asm https://github.com/klauspost/compress/pull/1048
- * flate: Fix matchlen L5+L6 https://github.com/klauspost/compress/pull/1049
- * flate: Cleanup & reduce casts https://github.com/klauspost/compress/pull/1050
-
-
- See changes to v1.17.x
-
-* Oct 11th, 2024 - [1.17.11](https://github.com/klauspost/compress/releases/tag/v1.17.11)
- * zstd: Fix extra CRC written with multiple Close calls https://github.com/klauspost/compress/pull/1017
- * s2: Don't use stack for index tables https://github.com/klauspost/compress/pull/1014
- * gzhttp: No content-type on no body response code by @juliens in https://github.com/klauspost/compress/pull/1011
- * gzhttp: Do not set the content-type when response has no body by @kevinpollet in https://github.com/klauspost/compress/pull/1013
-
-* Sep 23rd, 2024 - [1.17.10](https://github.com/klauspost/compress/releases/tag/v1.17.10)
- * gzhttp: Add TransportAlwaysDecompress option. https://github.com/klauspost/compress/pull/978
- * gzhttp: Add supported decompress request body by @mirecl in https://github.com/klauspost/compress/pull/1002
- * s2: Add EncodeBuffer buffer recycling callback https://github.com/klauspost/compress/pull/982
- * zstd: Improve memory usage on small streaming encodes https://github.com/klauspost/compress/pull/1007
- * flate: read data written with partial flush by @vajexal in https://github.com/klauspost/compress/pull/996
-
-* Jun 12th, 2024 - [1.17.9](https://github.com/klauspost/compress/releases/tag/v1.17.9)
- * s2: Reduce ReadFrom temporary allocations https://github.com/klauspost/compress/pull/949
- * flate, zstd: Shave some bytes off amd64 matchLen by @greatroar in https://github.com/klauspost/compress/pull/963
- * Upgrade zip/zlib to 1.22.4 upstream https://github.com/klauspost/compress/pull/970 https://github.com/klauspost/compress/pull/971
- * zstd: BuildDict fails with RLE table https://github.com/klauspost/compress/pull/951
-
-* Apr 9th, 2024 - [1.17.8](https://github.com/klauspost/compress/releases/tag/v1.17.8)
- * zstd: Reject blocks where reserved values are not 0 https://github.com/klauspost/compress/pull/885
- * zstd: Add RLE detection+encoding https://github.com/klauspost/compress/pull/938
-
-* Feb 21st, 2024 - [1.17.7](https://github.com/klauspost/compress/releases/tag/v1.17.7)
- * s2: Add AsyncFlush method: Complete the block without flushing by @Jille in https://github.com/klauspost/compress/pull/927
- * s2: Fix literal+repeat exceeds dst crash https://github.com/klauspost/compress/pull/930
-
-* Feb 5th, 2024 - [1.17.6](https://github.com/klauspost/compress/releases/tag/v1.17.6)
- * zstd: Fix incorrect repeat coding in best mode https://github.com/klauspost/compress/pull/923
- * s2: Fix DecodeConcurrent deadlock on errors https://github.com/klauspost/compress/pull/925
-
-* Jan 26th, 2024 - [v1.17.5](https://github.com/klauspost/compress/releases/tag/v1.17.5)
- * flate: Fix reset with dictionary on custom window encodes https://github.com/klauspost/compress/pull/912
- * zstd: Add Frame header encoding and stripping https://github.com/klauspost/compress/pull/908
- * zstd: Limit better/best default window to 8MB https://github.com/klauspost/compress/pull/913
- * zstd: Speed improvements by @greatroar in https://github.com/klauspost/compress/pull/896 https://github.com/klauspost/compress/pull/910
- * s2: Fix callbacks for skippable blocks and disallow 0xfe (Padding) by @Jille in https://github.com/klauspost/compress/pull/916 https://github.com/klauspost/compress/pull/917
-https://github.com/klauspost/compress/pull/919 https://github.com/klauspost/compress/pull/918
-
-* Dec 1st, 2023 - [v1.17.4](https://github.com/klauspost/compress/releases/tag/v1.17.4)
- * huff0: Speed up symbol counting by @greatroar in https://github.com/klauspost/compress/pull/887
- * huff0: Remove byteReader by @greatroar in https://github.com/klauspost/compress/pull/886
- * gzhttp: Allow overriding decompression on transport https://github.com/klauspost/compress/pull/892
- * gzhttp: Clamp compression level https://github.com/klauspost/compress/pull/890
- * gzip: Error out if reserved bits are set https://github.com/klauspost/compress/pull/891
-
-* Nov 15th, 2023 - [v1.17.3](https://github.com/klauspost/compress/releases/tag/v1.17.3)
- * fse: Fix max header size https://github.com/klauspost/compress/pull/881
- * zstd: Improve better/best compression https://github.com/klauspost/compress/pull/877
- * gzhttp: Fix missing content type on Close https://github.com/klauspost/compress/pull/883
-
-* Oct 22nd, 2023 - [v1.17.2](https://github.com/klauspost/compress/releases/tag/v1.17.2)
- * zstd: Fix rare *CORRUPTION* output in "best" mode. See https://github.com/klauspost/compress/pull/876
-
-* Oct 14th, 2023 - [v1.17.1](https://github.com/klauspost/compress/releases/tag/v1.17.1)
- * s2: Fix S2 "best" dictionary wrong encoding https://github.com/klauspost/compress/pull/871
- * flate: Reduce allocations in decompressor and minor code improvements by @fakefloordiv in https://github.com/klauspost/compress/pull/869
- * s2: Fix EstimateBlockSize on 6&7 length input https://github.com/klauspost/compress/pull/867
-
-* Sept 19th, 2023 - [v1.17.0](https://github.com/klauspost/compress/releases/tag/v1.17.0)
- * Add experimental dictionary builder https://github.com/klauspost/compress/pull/853
- * Add xerial snappy read/writer https://github.com/klauspost/compress/pull/838
- * flate: Add limited window compression https://github.com/klauspost/compress/pull/843
- * s2: Do 2 overlapping match checks https://github.com/klauspost/compress/pull/839
- * flate: Add amd64 assembly matchlen https://github.com/klauspost/compress/pull/837
- * gzip: Copy bufio.Reader on Reset by @thatguystone in https://github.com/klauspost/compress/pull/860
-
-
-
- See changes to v1.16.x
-
-
-* July 1st, 2023 - [v1.16.7](https://github.com/klauspost/compress/releases/tag/v1.16.7)
- * zstd: Fix default level first dictionary encode https://github.com/klauspost/compress/pull/829
- * s2: add GetBufferCapacity() method by @GiedriusS in https://github.com/klauspost/compress/pull/832
-
-* June 13, 2023 - [v1.16.6](https://github.com/klauspost/compress/releases/tag/v1.16.6)
- * zstd: correctly ignore WithEncoderPadding(1) by @ianlancetaylor in https://github.com/klauspost/compress/pull/806
- * zstd: Add amd64 match length assembly https://github.com/klauspost/compress/pull/824
- * gzhttp: Handle informational headers by @rtribotte in https://github.com/klauspost/compress/pull/815
- * s2: Improve Better compression slightly https://github.com/klauspost/compress/pull/663
-
-* Apr 16, 2023 - [v1.16.5](https://github.com/klauspost/compress/releases/tag/v1.16.5)
- * zstd: readByte needs to use io.ReadFull by @jnoxon in https://github.com/klauspost/compress/pull/802
- * gzip: Fix WriterTo after initial read https://github.com/klauspost/compress/pull/804
-
-* Apr 5, 2023 - [v1.16.4](https://github.com/klauspost/compress/releases/tag/v1.16.4)
- * zstd: Improve zstd best efficiency by @greatroar and @klauspost in https://github.com/klauspost/compress/pull/784
- * zstd: Respect WithAllLitEntropyCompression https://github.com/klauspost/compress/pull/792
- * zstd: Fix amd64 not always detecting corrupt data https://github.com/klauspost/compress/pull/785
- * zstd: Various minor improvements by @greatroar in https://github.com/klauspost/compress/pull/788 https://github.com/klauspost/compress/pull/794 https://github.com/klauspost/compress/pull/795
- * s2: Fix huge block overflow https://github.com/klauspost/compress/pull/779
- * s2: Allow CustomEncoder fallback https://github.com/klauspost/compress/pull/780
- * gzhttp: Support ResponseWriter Unwrap() in gzhttp handler by @jgimenez in https://github.com/klauspost/compress/pull/799
-
-* Mar 13, 2023 - [v1.16.1](https://github.com/klauspost/compress/releases/tag/v1.16.1)
- * zstd: Speed up + improve best encoder by @greatroar in https://github.com/klauspost/compress/pull/776
- * gzhttp: Add optional [BREACH mitigation](https://github.com/klauspost/compress/tree/master/gzhttp#breach-mitigation). https://github.com/klauspost/compress/pull/762 https://github.com/klauspost/compress/pull/768 https://github.com/klauspost/compress/pull/769 https://github.com/klauspost/compress/pull/770 https://github.com/klauspost/compress/pull/767
- * s2: Add Intel LZ4s converter https://github.com/klauspost/compress/pull/766
- * zstd: Minor bug fixes https://github.com/klauspost/compress/pull/771 https://github.com/klauspost/compress/pull/772 https://github.com/klauspost/compress/pull/773
- * huff0: Speed up compress1xDo by @greatroar in https://github.com/klauspost/compress/pull/774
-
-* Feb 26, 2023 - [v1.16.0](https://github.com/klauspost/compress/releases/tag/v1.16.0)
- * s2: Add [Dictionary](https://github.com/klauspost/compress/tree/master/s2#dictionaries) support. https://github.com/klauspost/compress/pull/685
- * s2: Add Compression Size Estimate. https://github.com/klauspost/compress/pull/752
- * s2: Add support for custom stream encoder. https://github.com/klauspost/compress/pull/755
- * s2: Add LZ4 block converter. https://github.com/klauspost/compress/pull/748
- * s2: Support io.ReaderAt in ReadSeeker. https://github.com/klauspost/compress/pull/747
- * s2c/s2sx: Use concurrent decoding. https://github.com/klauspost/compress/pull/746
-
-
-
- See changes to v1.15.x
-
-* Jan 21st, 2023 (v1.15.15)
- * deflate: Improve level 7-9 https://github.com/klauspost/compress/pull/739
- * zstd: Add delta encoding support by @greatroar in https://github.com/klauspost/compress/pull/728
- * zstd: Various speed improvements by @greatroar https://github.com/klauspost/compress/pull/741 https://github.com/klauspost/compress/pull/734 https://github.com/klauspost/compress/pull/736 https://github.com/klauspost/compress/pull/744 https://github.com/klauspost/compress/pull/743 https://github.com/klauspost/compress/pull/745
- * gzhttp: Add SuffixETag() and DropETag() options to prevent ETag collisions on compressed responses by @willbicks in https://github.com/klauspost/compress/pull/740
-
-* Jan 3rd, 2023 (v1.15.14)
-
- * flate: Improve speed in big stateless blocks https://github.com/klauspost/compress/pull/718
- * zstd: Minor speed tweaks by @greatroar in https://github.com/klauspost/compress/pull/716 https://github.com/klauspost/compress/pull/720
- * export NoGzipResponseWriter for custom ResponseWriter wrappers by @harshavardhana in https://github.com/klauspost/compress/pull/722
- * s2: Add example for indexing and existing stream https://github.com/klauspost/compress/pull/723
-
-* Dec 11, 2022 (v1.15.13)
- * zstd: Add [MaxEncodedSize](https://pkg.go.dev/github.com/klauspost/compress@v1.15.13/zstd#Encoder.MaxEncodedSize) to encoder https://github.com/klauspost/compress/pull/691
- * zstd: Various tweaks and improvements https://github.com/klauspost/compress/pull/693 https://github.com/klauspost/compress/pull/695 https://github.com/klauspost/compress/pull/696 https://github.com/klauspost/compress/pull/701 https://github.com/klauspost/compress/pull/702 https://github.com/klauspost/compress/pull/703 https://github.com/klauspost/compress/pull/704 https://github.com/klauspost/compress/pull/705 https://github.com/klauspost/compress/pull/706 https://github.com/klauspost/compress/pull/707 https://github.com/klauspost/compress/pull/708
-
-* Oct 26, 2022 (v1.15.12)
-
- * zstd: Tweak decoder allocs. https://github.com/klauspost/compress/pull/680
- * gzhttp: Always delete `HeaderNoCompression` https://github.com/klauspost/compress/pull/683
-
-* Sept 26, 2022 (v1.15.11)
-
- * flate: Improve level 1-3 compression https://github.com/klauspost/compress/pull/678
- * zstd: Improve "best" compression by @nightwolfz in https://github.com/klauspost/compress/pull/677
- * zstd: Fix+reduce decompression allocations https://github.com/klauspost/compress/pull/668
- * zstd: Fix non-effective noescape tag https://github.com/klauspost/compress/pull/667
-
-* Sept 16, 2022 (v1.15.10)
-
- * zstd: Add [WithDecodeAllCapLimit](https://pkg.go.dev/github.com/klauspost/compress@v1.15.10/zstd#WithDecodeAllCapLimit) https://github.com/klauspost/compress/pull/649
- * Add Go 1.19 - deprecate Go 1.16 https://github.com/klauspost/compress/pull/651
- * flate: Improve level 5+6 compression https://github.com/klauspost/compress/pull/656
- * zstd: Improve "better" compression https://github.com/klauspost/compress/pull/657
- * s2: Improve "best" compression https://github.com/klauspost/compress/pull/658
- * s2: Improve "better" compression. https://github.com/klauspost/compress/pull/635
- * s2: Slightly faster non-assembly decompression https://github.com/klauspost/compress/pull/646
- * Use arrays for constant size copies https://github.com/klauspost/compress/pull/659
-
-* July 21, 2022 (v1.15.9)
-
- * zstd: Fix decoder crash on amd64 (no BMI) on invalid input https://github.com/klauspost/compress/pull/645
- * zstd: Disable decoder extended memory copies (amd64) due to possible crashes https://github.com/klauspost/compress/pull/644
- * zstd: Allow single segments up to "max decoded size" https://github.com/klauspost/compress/pull/643
-
-* July 13, 2022 (v1.15.8)
-
- * gzip: fix stack exhaustion bug in Reader.Read https://github.com/klauspost/compress/pull/641
- * s2: Add Index header trim/restore https://github.com/klauspost/compress/pull/638
- * zstd: Optimize seqdeq amd64 asm by @greatroar in https://github.com/klauspost/compress/pull/636
- * zstd: Improve decoder memcopy https://github.com/klauspost/compress/pull/637
- * huff0: Pass a single bitReader pointer to asm by @greatroar in https://github.com/klauspost/compress/pull/634
- * zstd: Branchless getBits for amd64 w/o BMI2 by @greatroar in https://github.com/klauspost/compress/pull/640
- * gzhttp: Remove header before writing https://github.com/klauspost/compress/pull/639
-
-* June 29, 2022 (v1.15.7)
-
- * s2: Fix absolute forward seeks https://github.com/klauspost/compress/pull/633
- * zip: Merge upstream https://github.com/klauspost/compress/pull/631
- * zip: Re-add zip64 fix https://github.com/klauspost/compress/pull/624
- * zstd: translate fseDecoder.buildDtable into asm by @WojciechMula in https://github.com/klauspost/compress/pull/598
- * flate: Faster histograms https://github.com/klauspost/compress/pull/620
- * deflate: Use compound hcode https://github.com/klauspost/compress/pull/622
-
-* June 3, 2022 (v1.15.6)
- * s2: Improve coding for long, close matches https://github.com/klauspost/compress/pull/613
- * s2c: Add Snappy/S2 stream recompression https://github.com/klauspost/compress/pull/611
- * zstd: Always use configured block size https://github.com/klauspost/compress/pull/605
- * zstd: Fix incorrect hash table placement for dict encoding in default https://github.com/klauspost/compress/pull/606
- * zstd: Apply default config to ZipDecompressor without options https://github.com/klauspost/compress/pull/608
- * gzhttp: Exclude more common archive formats https://github.com/klauspost/compress/pull/612
- * s2: Add ReaderIgnoreCRC https://github.com/klauspost/compress/pull/609
- * s2: Remove sanity load on index creation https://github.com/klauspost/compress/pull/607
- * snappy: Use dedicated function for scoring https://github.com/klauspost/compress/pull/614
- * s2c+s2d: Use official snappy framed extension https://github.com/klauspost/compress/pull/610
-
-* May 25, 2022 (v1.15.5)
- * s2: Add concurrent stream decompression https://github.com/klauspost/compress/pull/602
- * s2: Fix final emit oob read crash on amd64 https://github.com/klauspost/compress/pull/601
- * huff0: asm implementation of Decompress1X by @WojciechMula https://github.com/klauspost/compress/pull/596
- * zstd: Use 1 less goroutine for stream decoding https://github.com/klauspost/compress/pull/588
- * zstd: Copy literal in 16 byte blocks when possible https://github.com/klauspost/compress/pull/592
- * zstd: Speed up when WithDecoderLowmem(false) https://github.com/klauspost/compress/pull/599
- * zstd: faster next state update in BMI2 version of decode by @WojciechMula in https://github.com/klauspost/compress/pull/593
- * huff0: Do not check max size when reading table. https://github.com/klauspost/compress/pull/586
- * flate: Inplace hashing for level 7-9 https://github.com/klauspost/compress/pull/590
-
-
-* May 11, 2022 (v1.15.4)
- * huff0: decompress directly into output by @WojciechMula in [#577](https://github.com/klauspost/compress/pull/577)
- * inflate: Keep dict on stack [#581](https://github.com/klauspost/compress/pull/581)
- * zstd: Faster decoding memcopy in asm [#583](https://github.com/klauspost/compress/pull/583)
- * zstd: Fix ignored crc [#580](https://github.com/klauspost/compress/pull/580)
-
-* May 5, 2022 (v1.15.3)
- * zstd: Allow to ignore checksum checking by @WojciechMula [#572](https://github.com/klauspost/compress/pull/572)
- * s2: Fix incorrect seek for io.SeekEnd in [#575](https://github.com/klauspost/compress/pull/575)
-
-* Apr 26, 2022 (v1.15.2)
- * zstd: Add x86-64 assembly for decompression on streams and blocks. Contributed by [@WojciechMula](https://github.com/WojciechMula). Typically 2x faster. [#528](https://github.com/klauspost/compress/pull/528) [#531](https://github.com/klauspost/compress/pull/531) [#545](https://github.com/klauspost/compress/pull/545) [#537](https://github.com/klauspost/compress/pull/537)
- * zstd: Add options to ZipDecompressor and fixes [#539](https://github.com/klauspost/compress/pull/539)
- * s2: Use sorted search for index [#555](https://github.com/klauspost/compress/pull/555)
- * Minimum version is Go 1.16, added CI test on 1.18.
-
-* Mar 11, 2022 (v1.15.1)
- * huff0: Add x86 assembly of Decode4X by @WojciechMula in [#512](https://github.com/klauspost/compress/pull/512)
- * zstd: Reuse zip decoders in [#514](https://github.com/klauspost/compress/pull/514)
- * zstd: Detect extra block data and report as corrupted in [#520](https://github.com/klauspost/compress/pull/520)
- * zstd: Handle zero sized frame content size stricter in [#521](https://github.com/klauspost/compress/pull/521)
- * zstd: Add stricter block size checks in [#523](https://github.com/klauspost/compress/pull/523)
-
-* Mar 3, 2022 (v1.15.0)
- * zstd: Refactor decoder [#498](https://github.com/klauspost/compress/pull/498)
- * zstd: Add stream encoding without goroutines [#505](https://github.com/klauspost/compress/pull/505)
- * huff0: Prevent single blocks exceeding 16 bits by @klauspost in[#507](https://github.com/klauspost/compress/pull/507)
- * flate: Inline literal emission [#509](https://github.com/klauspost/compress/pull/509)
- * gzhttp: Add zstd to transport [#400](https://github.com/klauspost/compress/pull/400)
- * gzhttp: Make content-type optional [#510](https://github.com/klauspost/compress/pull/510)
-
-Both compression and decompression now supports "synchronous" stream operations. This means that whenever "concurrency" is set to 1, they will operate without spawning goroutines.
-
-Stream decompression is now faster on asynchronous, since the goroutine allocation much more effectively splits the workload. On typical streams this will typically use 2 cores fully for decompression. When a stream has finished decoding no goroutines will be left over, so decoders can now safely be pooled and still be garbage collected.
-
-While the release has been extensively tested, it is recommended to testing when upgrading.
-
-
-
-
- See changes to v1.14.x
-
-* Feb 22, 2022 (v1.14.4)
- * flate: Fix rare huffman only (-2) corruption. [#503](https://github.com/klauspost/compress/pull/503)
- * zip: Update deprecated CreateHeaderRaw to correctly call CreateRaw by @saracen in [#502](https://github.com/klauspost/compress/pull/502)
- * zip: don't read data descriptor early by @saracen in [#501](https://github.com/klauspost/compress/pull/501) #501
- * huff0: Use static decompression buffer up to 30% faster [#499](https://github.com/klauspost/compress/pull/499) [#500](https://github.com/klauspost/compress/pull/500)
-
-* Feb 17, 2022 (v1.14.3)
- * flate: Improve fastest levels compression speed ~10% more throughput. [#482](https://github.com/klauspost/compress/pull/482) [#489](https://github.com/klauspost/compress/pull/489) [#490](https://github.com/klauspost/compress/pull/490) [#491](https://github.com/klauspost/compress/pull/491) [#494](https://github.com/klauspost/compress/pull/494) [#478](https://github.com/klauspost/compress/pull/478)
- * flate: Faster decompression speed, ~5-10%. [#483](https://github.com/klauspost/compress/pull/483)
- * s2: Faster compression with Go v1.18 and amd64 microarch level 3+. [#484](https://github.com/klauspost/compress/pull/484) [#486](https://github.com/klauspost/compress/pull/486)
-
-* Jan 25, 2022 (v1.14.2)
- * zstd: improve header decoder by @dsnet [#476](https://github.com/klauspost/compress/pull/476)
- * zstd: Add bigger default blocks [#469](https://github.com/klauspost/compress/pull/469)
- * zstd: Remove unused decompression buffer [#470](https://github.com/klauspost/compress/pull/470)
- * zstd: Fix logically dead code by @ningmingxiao [#472](https://github.com/klauspost/compress/pull/472)
- * flate: Improve level 7-9 [#471](https://github.com/klauspost/compress/pull/471) [#473](https://github.com/klauspost/compress/pull/473)
- * zstd: Add noasm tag for xxhash [#475](https://github.com/klauspost/compress/pull/475)
-
-* Jan 11, 2022 (v1.14.1)
- * s2: Add stream index in [#462](https://github.com/klauspost/compress/pull/462)
- * flate: Speed and efficiency improvements in [#439](https://github.com/klauspost/compress/pull/439) [#461](https://github.com/klauspost/compress/pull/461) [#455](https://github.com/klauspost/compress/pull/455) [#452](https://github.com/klauspost/compress/pull/452) [#458](https://github.com/klauspost/compress/pull/458)
- * zstd: Performance improvement in [#420]( https://github.com/klauspost/compress/pull/420) [#456](https://github.com/klauspost/compress/pull/456) [#437](https://github.com/klauspost/compress/pull/437) [#467](https://github.com/klauspost/compress/pull/467) [#468](https://github.com/klauspost/compress/pull/468)
- * zstd: add arm64 xxhash assembly in [#464](https://github.com/klauspost/compress/pull/464)
- * Add garbled for binaries for s2 in [#445](https://github.com/klauspost/compress/pull/445)
-
-
-
- See changes to v1.13.x
-
-* Aug 30, 2021 (v1.13.5)
- * gz/zlib/flate: Alias stdlib errors [#425](https://github.com/klauspost/compress/pull/425)
- * s2: Add block support to commandline tools [#413](https://github.com/klauspost/compress/pull/413)
- * zstd: pooledZipWriter should return Writers to the same pool [#426](https://github.com/klauspost/compress/pull/426)
- * Removed golang/snappy as external dependency for tests [#421](https://github.com/klauspost/compress/pull/421)
-
-* Aug 12, 2021 (v1.13.4)
- * Add [snappy replacement package](https://github.com/klauspost/compress/tree/master/snappy).
- * zstd: Fix incorrect encoding in "best" mode [#415](https://github.com/klauspost/compress/pull/415)
-
-* Aug 3, 2021 (v1.13.3)
- * zstd: Improve Best compression [#404](https://github.com/klauspost/compress/pull/404)
- * zstd: Fix WriteTo error forwarding [#411](https://github.com/klauspost/compress/pull/411)
- * gzhttp: Return http.HandlerFunc instead of http.Handler. Unlikely breaking change. [#406](https://github.com/klauspost/compress/pull/406)
- * s2sx: Fix max size error [#399](https://github.com/klauspost/compress/pull/399)
- * zstd: Add optional stream content size on reset [#401](https://github.com/klauspost/compress/pull/401)
- * zstd: use SpeedBestCompression for level >= 10 [#410](https://github.com/klauspost/compress/pull/410)
-
-* Jun 14, 2021 (v1.13.1)
- * s2: Add full Snappy output support [#396](https://github.com/klauspost/compress/pull/396)
- * zstd: Add configurable [Decoder window](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithDecoderMaxWindow) size [#394](https://github.com/klauspost/compress/pull/394)
- * gzhttp: Add header to skip compression [#389](https://github.com/klauspost/compress/pull/389)
- * s2: Improve speed with bigger output margin [#395](https://github.com/klauspost/compress/pull/395)
-
-* Jun 3, 2021 (v1.13.0)
- * Added [gzhttp](https://github.com/klauspost/compress/tree/master/gzhttp#gzip-handler) which allows wrapping HTTP servers and clients with GZIP compressors.
- * zstd: Detect short invalid signatures [#382](https://github.com/klauspost/compress/pull/382)
- * zstd: Spawn decoder goroutine only if needed. [#380](https://github.com/klauspost/compress/pull/380)
-
-
-
-
- See changes to v1.12.x
-
-* May 25, 2021 (v1.12.3)
- * deflate: Better/faster Huffman encoding [#374](https://github.com/klauspost/compress/pull/374)
- * deflate: Allocate less for history. [#375](https://github.com/klauspost/compress/pull/375)
- * zstd: Forward read errors [#373](https://github.com/klauspost/compress/pull/373)
-
-* Apr 27, 2021 (v1.12.2)
- * zstd: Improve better/best compression [#360](https://github.com/klauspost/compress/pull/360) [#364](https://github.com/klauspost/compress/pull/364) [#365](https://github.com/klauspost/compress/pull/365)
- * zstd: Add helpers to compress/decompress zstd inside zip files [#363](https://github.com/klauspost/compress/pull/363)
- * deflate: Improve level 5+6 compression [#367](https://github.com/klauspost/compress/pull/367)
- * s2: Improve better/best compression [#358](https://github.com/klauspost/compress/pull/358) [#359](https://github.com/klauspost/compress/pull/358)
- * s2: Load after checking src limit on amd64. [#362](https://github.com/klauspost/compress/pull/362)
- * s2sx: Limit max executable size [#368](https://github.com/klauspost/compress/pull/368)
-
-* Apr 14, 2021 (v1.12.1)
- * snappy package removed. Upstream added as dependency.
- * s2: Better compression in "best" mode [#353](https://github.com/klauspost/compress/pull/353)
- * s2sx: Add stdin input and detect pre-compressed from signature [#352](https://github.com/klauspost/compress/pull/352)
- * s2c/s2d: Add http as possible input [#348](https://github.com/klauspost/compress/pull/348)
- * s2c/s2d/s2sx: Always truncate when writing files [#352](https://github.com/klauspost/compress/pull/352)
- * zstd: Reduce memory usage further when using [WithLowerEncoderMem](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithLowerEncoderMem) [#346](https://github.com/klauspost/compress/pull/346)
- * s2: Fix potential problem with amd64 assembly and profilers [#349](https://github.com/klauspost/compress/pull/349)
-
-
-
- See changes to v1.11.x
-
-* Mar 26, 2021 (v1.11.13)
- * zstd: Big speedup on small dictionary encodes [#344](https://github.com/klauspost/compress/pull/344) [#345](https://github.com/klauspost/compress/pull/345)
- * zstd: Add [WithLowerEncoderMem](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithLowerEncoderMem) encoder option [#336](https://github.com/klauspost/compress/pull/336)
- * deflate: Improve entropy compression [#338](https://github.com/klauspost/compress/pull/338)
- * s2: Clean up and minor performance improvement in best [#341](https://github.com/klauspost/compress/pull/341)
-
-* Mar 5, 2021 (v1.11.12)
- * s2: Add `s2sx` binary that creates [self extracting archives](https://github.com/klauspost/compress/tree/master/s2#s2sx-self-extracting-archives).
- * s2: Speed up decompression on non-assembly platforms [#328](https://github.com/klauspost/compress/pull/328)
-
-* Mar 1, 2021 (v1.11.9)
- * s2: Add ARM64 decompression assembly. Around 2x output speed. [#324](https://github.com/klauspost/compress/pull/324)
- * s2: Improve "better" speed and efficiency. [#325](https://github.com/klauspost/compress/pull/325)
- * s2: Fix binaries.
-
-* Feb 25, 2021 (v1.11.8)
- * s2: Fixed occasional out-of-bounds write on amd64. Upgrade recommended.
- * s2: Add AMD64 assembly for better mode. 25-50% faster. [#315](https://github.com/klauspost/compress/pull/315)
- * s2: Less upfront decoder allocation. [#322](https://github.com/klauspost/compress/pull/322)
- * zstd: Faster "compression" of incompressible data. [#314](https://github.com/klauspost/compress/pull/314)
- * zip: Fix zip64 headers. [#313](https://github.com/klauspost/compress/pull/313)
-
-* Jan 14, 2021 (v1.11.7)
- * Use Bytes() interface to get bytes across packages. [#309](https://github.com/klauspost/compress/pull/309)
- * s2: Add 'best' compression option. [#310](https://github.com/klauspost/compress/pull/310)
- * s2: Add ReaderMaxBlockSize, changes `s2.NewReader` signature to include varargs. [#311](https://github.com/klauspost/compress/pull/311)
- * s2: Fix crash on small better buffers. [#308](https://github.com/klauspost/compress/pull/308)
- * s2: Clean up decoder. [#312](https://github.com/klauspost/compress/pull/312)
-
-* Jan 7, 2021 (v1.11.6)
- * zstd: Make decoder allocations smaller [#306](https://github.com/klauspost/compress/pull/306)
- * zstd: Free Decoder resources when Reset is called with a nil io.Reader [#305](https://github.com/klauspost/compress/pull/305)
-
-* Dec 20, 2020 (v1.11.4)
- * zstd: Add Best compression mode [#304](https://github.com/klauspost/compress/pull/304)
- * Add header decoder [#299](https://github.com/klauspost/compress/pull/299)
- * s2: Add uncompressed stream option [#297](https://github.com/klauspost/compress/pull/297)
- * Simplify/speed up small blocks with known max size. [#300](https://github.com/klauspost/compress/pull/300)
- * zstd: Always reset literal dict encoder [#303](https://github.com/klauspost/compress/pull/303)
-
-* Nov 15, 2020 (v1.11.3)
- * inflate: 10-15% faster decompression [#293](https://github.com/klauspost/compress/pull/293)
- * zstd: Tweak DecodeAll default allocation [#295](https://github.com/klauspost/compress/pull/295)
-
-* Oct 11, 2020 (v1.11.2)
- * s2: Fix out of bounds read in "better" block compression [#291](https://github.com/klauspost/compress/pull/291)
-
-* Oct 1, 2020 (v1.11.1)
- * zstd: Set allLitEntropy true in default configuration [#286](https://github.com/klauspost/compress/pull/286)
-
-* Sept 8, 2020 (v1.11.0)
- * zstd: Add experimental compression [dictionaries](https://github.com/klauspost/compress/tree/master/zstd#dictionaries) [#281](https://github.com/klauspost/compress/pull/281)
- * zstd: Fix mixed Write and ReadFrom calls [#282](https://github.com/klauspost/compress/pull/282)
- * inflate/gz: Limit variable shifts, ~5% faster decompression [#274](https://github.com/klauspost/compress/pull/274)
-
-
-
- See changes to v1.10.x
-
-* July 8, 2020 (v1.10.11)
- * zstd: Fix extra block when compressing with ReadFrom. [#278](https://github.com/klauspost/compress/pull/278)
- * huff0: Also populate compression table when reading decoding table. [#275](https://github.com/klauspost/compress/pull/275)
-
-* June 23, 2020 (v1.10.10)
- * zstd: Skip entropy compression in fastest mode when no matches. [#270](https://github.com/klauspost/compress/pull/270)
-
-* June 16, 2020 (v1.10.9):
- * zstd: API change for specifying dictionaries. See [#268](https://github.com/klauspost/compress/pull/268)
- * zip: update CreateHeaderRaw to handle zip64 fields. [#266](https://github.com/klauspost/compress/pull/266)
- * Fuzzit tests removed. The service has been purchased and is no longer available.
-
-* June 5, 2020 (v1.10.8):
- * 1.15x faster zstd block decompression. [#265](https://github.com/klauspost/compress/pull/265)
-
-* June 1, 2020 (v1.10.7):
- * Added zstd decompression [dictionary support](https://github.com/klauspost/compress/tree/master/zstd#dictionaries)
- * Increase zstd decompression speed up to 1.19x. [#259](https://github.com/klauspost/compress/pull/259)
- * Remove internal reset call in zstd compression and reduce allocations. [#263](https://github.com/klauspost/compress/pull/263)
-
-* May 21, 2020: (v1.10.6)
- * zstd: Reduce allocations while decoding. [#258](https://github.com/klauspost/compress/pull/258), [#252](https://github.com/klauspost/compress/pull/252)
- * zstd: Stricter decompression checks.
-
-* April 12, 2020: (v1.10.5)
- * s2-commands: Flush output when receiving SIGINT. [#239](https://github.com/klauspost/compress/pull/239)
-
-* Apr 8, 2020: (v1.10.4)
- * zstd: Minor/special case optimizations. [#251](https://github.com/klauspost/compress/pull/251), [#250](https://github.com/klauspost/compress/pull/250), [#249](https://github.com/klauspost/compress/pull/249), [#247](https://github.com/klauspost/compress/pull/247)
-* Mar 11, 2020: (v1.10.3)
- * s2: Use S2 encoder in pure Go mode for Snappy output as well. [#245](https://github.com/klauspost/compress/pull/245)
- * s2: Fix pure Go block encoder. [#244](https://github.com/klauspost/compress/pull/244)
- * zstd: Added "better compression" mode. [#240](https://github.com/klauspost/compress/pull/240)
- * zstd: Improve speed of fastest compression mode by 5-10% [#241](https://github.com/klauspost/compress/pull/241)
- * zstd: Skip creating encoders when not needed. [#238](https://github.com/klauspost/compress/pull/238)
-
-* Feb 27, 2020: (v1.10.2)
- * Close to 50% speedup in inflate (gzip/zip decompression). [#236](https://github.com/klauspost/compress/pull/236) [#234](https://github.com/klauspost/compress/pull/234) [#232](https://github.com/klauspost/compress/pull/232)
- * Reduce deflate level 1-6 memory usage up to 59%. [#227](https://github.com/klauspost/compress/pull/227)
-
-* Feb 18, 2020: (v1.10.1)
- * Fix zstd crash when resetting multiple times without sending data. [#226](https://github.com/klauspost/compress/pull/226)
- * deflate: Fix dictionary use on level 1-6. [#224](https://github.com/klauspost/compress/pull/224)
- * Remove deflate writer reference when closing. [#224](https://github.com/klauspost/compress/pull/224)
-
-* Feb 4, 2020: (v1.10.0)
- * Add optional dictionary to [stateless deflate](https://pkg.go.dev/github.com/klauspost/compress/flate?tab=doc#StatelessDeflate). Breaking change, send `nil` for previous behaviour. [#216](https://github.com/klauspost/compress/pull/216)
- * Fix buffer overflow on repeated small block deflate. [#218](https://github.com/klauspost/compress/pull/218)
- * Allow copying content from an existing ZIP file without decompressing+compressing. [#214](https://github.com/klauspost/compress/pull/214)
- * Added [S2](https://github.com/klauspost/compress/tree/master/s2#s2-compression) AMD64 assembler and various optimizations. Stream speed >10GB/s. [#186](https://github.com/klauspost/compress/pull/186)
-
-
-
-
- See changes prior to v1.10.0
-
-* Jan 20,2020 (v1.9.8) Optimize gzip/deflate with better size estimates and faster table generation. [#207](https://github.com/klauspost/compress/pull/207) by [luyu6056](https://github.com/luyu6056), [#206](https://github.com/klauspost/compress/pull/206).
-* Jan 11, 2020: S2 Encode/Decode will use provided buffer if capacity is big enough. [#204](https://github.com/klauspost/compress/pull/204)
-* Jan 5, 2020: (v1.9.7) Fix another zstd regression in v1.9.5 - v1.9.6 removed.
-* Jan 4, 2020: (v1.9.6) Regression in v1.9.5 fixed causing corrupt zstd encodes in rare cases.
-* Jan 4, 2020: Faster IO in [s2c + s2d commandline tools](https://github.com/klauspost/compress/tree/master/s2#commandline-tools) compression/decompression. [#192](https://github.com/klauspost/compress/pull/192)
-* Dec 29, 2019: Removed v1.9.5 since fuzz tests showed a compatibility problem with the reference zstandard decoder.
-* Dec 29, 2019: (v1.9.5) zstd: 10-20% faster block compression. [#199](https://github.com/klauspost/compress/pull/199)
-* Dec 29, 2019: [zip](https://godoc.org/github.com/klauspost/compress/zip) package updated with latest Go features
-* Dec 29, 2019: zstd: Single segment flag condintions tweaked. [#197](https://github.com/klauspost/compress/pull/197)
-* Dec 18, 2019: s2: Faster compression when ReadFrom is used. [#198](https://github.com/klauspost/compress/pull/198)
-* Dec 10, 2019: s2: Fix repeat length output when just above at 16MB limit.
-* Dec 10, 2019: zstd: Add function to get decoder as io.ReadCloser. [#191](https://github.com/klauspost/compress/pull/191)
-* Dec 3, 2019: (v1.9.4) S2: limit max repeat length. [#188](https://github.com/klauspost/compress/pull/188)
-* Dec 3, 2019: Add [WithNoEntropyCompression](https://godoc.org/github.com/klauspost/compress/zstd#WithNoEntropyCompression) to zstd [#187](https://github.com/klauspost/compress/pull/187)
-* Dec 3, 2019: Reduce memory use for tests. Check for leaked goroutines.
-* Nov 28, 2019 (v1.9.3) Less allocations in stateless deflate.
-* Nov 28, 2019: 5-20% Faster huff0 decode. Impacts zstd as well. [#184](https://github.com/klauspost/compress/pull/184)
-* Nov 12, 2019 (v1.9.2) Added [Stateless Compression](#stateless-compression) for gzip/deflate.
-* Nov 12, 2019: Fixed zstd decompression of large single blocks. [#180](https://github.com/klauspost/compress/pull/180)
-* Nov 11, 2019: Set default [s2c](https://github.com/klauspost/compress/tree/master/s2#commandline-tools) block size to 4MB.
-* Nov 11, 2019: Reduce inflate memory use by 1KB.
-* Nov 10, 2019: Less allocations in deflate bit writer.
-* Nov 10, 2019: Fix inconsistent error returned by zstd decoder.
-* Oct 28, 2019 (v1.9.1) ztsd: Fix crash when compressing blocks. [#174](https://github.com/klauspost/compress/pull/174)
-* Oct 24, 2019 (v1.9.0) zstd: Fix rare data corruption [#173](https://github.com/klauspost/compress/pull/173)
-* Oct 24, 2019 zstd: Fix huff0 out of buffer write [#171](https://github.com/klauspost/compress/pull/171) and always return errors [#172](https://github.com/klauspost/compress/pull/172)
-* Oct 10, 2019: Big deflate rewrite, 30-40% faster with better compression [#105](https://github.com/klauspost/compress/pull/105)
-
-
-
-
- See changes prior to v1.9.0
-
-* Oct 10, 2019: (v1.8.6) zstd: Allow partial reads to get flushed data. [#169](https://github.com/klauspost/compress/pull/169)
-* Oct 3, 2019: Fix inconsistent results on broken zstd streams.
-* Sep 25, 2019: Added `-rm` (remove source files) and `-q` (no output except errors) to `s2c` and `s2d` [commands](https://github.com/klauspost/compress/tree/master/s2#commandline-tools)
-* Sep 16, 2019: (v1.8.4) Add `s2c` and `s2d` [commandline tools](https://github.com/klauspost/compress/tree/master/s2#commandline-tools).
-* Sep 10, 2019: (v1.8.3) Fix s2 decoder [Skip](https://godoc.org/github.com/klauspost/compress/s2#Reader.Skip).
-* Sep 7, 2019: zstd: Added [WithWindowSize](https://godoc.org/github.com/klauspost/compress/zstd#WithWindowSize), contributed by [ianwilkes](https://github.com/ianwilkes).
-* Sep 5, 2019: (v1.8.2) Add [WithZeroFrames](https://godoc.org/github.com/klauspost/compress/zstd#WithZeroFrames) which adds full zero payload block encoding option.
-* Sep 5, 2019: Lazy initialization of zstandard predefined en/decoder tables.
-* Aug 26, 2019: (v1.8.1) S2: 1-2% compression increase in "better" compression mode.
-* Aug 26, 2019: zstd: Check maximum size of Huffman 1X compressed literals while decoding.
-* Aug 24, 2019: (v1.8.0) Added [S2 compression](https://github.com/klauspost/compress/tree/master/s2#s2-compression), a high performance replacement for Snappy.
-* Aug 21, 2019: (v1.7.6) Fixed minor issues found by fuzzer. One could lead to zstd not decompressing.
-* Aug 18, 2019: Add [fuzzit](https://fuzzit.dev/) continuous fuzzing.
-* Aug 14, 2019: zstd: Skip incompressible data 2x faster. [#147](https://github.com/klauspost/compress/pull/147)
-* Aug 4, 2019 (v1.7.5): Better literal compression. [#146](https://github.com/klauspost/compress/pull/146)
-* Aug 4, 2019: Faster zstd compression. [#143](https://github.com/klauspost/compress/pull/143) [#144](https://github.com/klauspost/compress/pull/144)
-* Aug 4, 2019: Faster zstd decompression. [#145](https://github.com/klauspost/compress/pull/145) [#143](https://github.com/klauspost/compress/pull/143) [#142](https://github.com/klauspost/compress/pull/142)
-* July 15, 2019 (v1.7.4): Fix double EOF block in rare cases on zstd encoder.
-* July 15, 2019 (v1.7.3): Minor speedup/compression increase in default zstd encoder.
-* July 14, 2019: zstd decoder: Fix decompression error on multiple uses with mixed content.
-* July 7, 2019 (v1.7.2): Snappy update, zstd decoder potential race fix.
-* June 17, 2019: zstd decompression bugfix.
-* June 17, 2019: fix 32 bit builds.
-* June 17, 2019: Easier use in modules (less dependencies).
-* June 9, 2019: New stronger "default" [zstd](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression mode. Matches zstd default compression ratio.
-* June 5, 2019: 20-40% throughput in [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and better compression.
-* June 5, 2019: deflate/gzip compression: Reduce memory usage of lower compression levels.
-* June 2, 2019: Added [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression!
-* May 25, 2019: deflate/gzip: 10% faster bit writer, mostly visible in lower levels.
-* Apr 22, 2019: [zstd](https://github.com/klauspost/compress/tree/master/zstd#zstd) decompression added.
-* Aug 1, 2018: Added [huff0 README](https://github.com/klauspost/compress/tree/master/huff0#huff0-entropy-compression).
-* Jul 8, 2018: Added [Performance Update 2018](#performance-update-2018) below.
-* Jun 23, 2018: Merged [Go 1.11 inflate optimizations](https://go-review.googlesource.com/c/go/+/102235). Go 1.9 is now required. Backwards compatible version tagged with [v1.3.0](https://github.com/klauspost/compress/releases/tag/v1.3.0).
-* Apr 2, 2018: Added [huff0](https://godoc.org/github.com/klauspost/compress/huff0) en/decoder. Experimental for now, API may change.
-* Mar 4, 2018: Added [FSE Entropy](https://godoc.org/github.com/klauspost/compress/fse) en/decoder. Experimental for now, API may change.
-* Nov 3, 2017: Add compression [Estimate](https://godoc.org/github.com/klauspost/compress#Estimate) function.
-* May 28, 2017: Reduce allocations when resetting decoder.
-* Apr 02, 2017: Change back to official crc32, since changes were merged in Go 1.7.
-* Jan 14, 2017: Reduce stack pressure due to array copies. See [Issue #18625](https://github.com/golang/go/issues/18625).
-* Oct 25, 2016: Level 2-4 have been rewritten and now offers significantly better performance than before.
-* Oct 20, 2016: Port zlib changes from Go 1.7 to fix zlib writer issue. Please update.
-* Oct 16, 2016: Go 1.7 changes merged. Apples to apples this package is a few percent faster, but has a significantly better balance between speed and compression per level.
-* Mar 24, 2016: Always attempt Huffman encoding on level 4-7. This improves base 64 encoded data compression.
-* Mar 24, 2016: Small speedup for level 1-3.
-* Feb 19, 2016: Faster bit writer, level -2 is 15% faster, level 1 is 4% faster.
-* Feb 19, 2016: Handle small payloads faster in level 1-3.
-* Feb 19, 2016: Added faster level 2 + 3 compression modes.
-* Feb 19, 2016: [Rebalanced compression levels](https://blog.klauspost.com/rebalancing-deflate-compression-levels/), so there is a more even progression in terms of compression. New default level is 5.
-* Feb 14, 2016: Snappy: Merge upstream changes.
-* Feb 14, 2016: Snappy: Fix aggressive skipping.
-* Feb 14, 2016: Snappy: Update benchmark.
-* Feb 13, 2016: Deflate: Fixed assembler problem that could lead to sub-optimal compression.
-* Feb 12, 2016: Snappy: Added AMD64 SSE 4.2 optimizations to matching, which makes easy to compress material run faster. Typical speedup is around 25%.
-* Feb 9, 2016: Added Snappy package fork. This version is 5-7% faster, much more on hard to compress content.
-* Jan 30, 2016: Optimize level 1 to 3 by not considering static dictionary or storing uncompressed. ~4-5% speedup.
-* Jan 16, 2016: Optimization on deflate level 1,2,3 compression.
-* Jan 8 2016: Merge [CL 18317](https://go-review.googlesource.com/#/c/18317): fix reading, writing of zip64 archives.
-* Dec 8 2015: Make level 1 and -2 deterministic even if write size differs.
-* Dec 8 2015: Split encoding functions, so hashing and matching can potentially be inlined. 1-3% faster on AMD64. 5% faster on other platforms.
-* Dec 8 2015: Fixed rare [one byte out-of bounds read](https://github.com/klauspost/compress/issues/20). Please update!
-* Nov 23 2015: Optimization on token writer. ~2-4% faster. Contributed by [@dsnet](https://github.com/dsnet).
-* Nov 20 2015: Small optimization to bit writer on 64 bit systems.
-* Nov 17 2015: Fixed out-of-bound errors if the underlying Writer returned an error. See [#15](https://github.com/klauspost/compress/issues/15).
-* Nov 12 2015: Added [io.WriterTo](https://golang.org/pkg/io/#WriterTo) support to gzip/inflate.
-* Nov 11 2015: Merged [CL 16669](https://go-review.googlesource.com/#/c/16669/4): archive/zip: enable overriding (de)compressors per file
-* Oct 15 2015: Added skipping on uncompressible data. Random data speed up >5x.
-
-
-
-# deflate usage
-
-The packages are drop-in replacements for standard library [deflate](https://godoc.org/github.com/klauspost/compress/flate), [gzip](https://godoc.org/github.com/klauspost/compress/gzip), [zip](https://godoc.org/github.com/klauspost/compress/zip), and [zlib](https://godoc.org/github.com/klauspost/compress/zlib). Simply replace the import path to use them:
-
-Typical speed is about 2x of the standard library packages.
-
-| old import | new import | Documentation |
-|------------------|---------------------------------------|-------------------------------------------------------------------------|
-| `compress/gzip` | `github.com/klauspost/compress/gzip` | [gzip](https://pkg.go.dev/github.com/klauspost/compress/gzip?tab=doc) |
-| `compress/zlib` | `github.com/klauspost/compress/zlib` | [zlib](https://pkg.go.dev/github.com/klauspost/compress/zlib?tab=doc) |
-| `archive/zip` | `github.com/klauspost/compress/zip` | [zip](https://pkg.go.dev/github.com/klauspost/compress/zip?tab=doc) |
-| `compress/flate` | `github.com/klauspost/compress/flate` | [flate](https://pkg.go.dev/github.com/klauspost/compress/flate?tab=doc) |
-
-You may also be interested in [pgzip](https://github.com/klauspost/pgzip), which is a drop-in replacement for gzip, which support multithreaded compression on big files and the optimized [crc32](https://github.com/klauspost/crc32) package used by these packages.
-
-The packages implement the same API as the standard library, so you can use the original godoc documentation: [gzip](http://golang.org/pkg/compress/gzip/), [zip](http://golang.org/pkg/archive/zip/), [zlib](http://golang.org/pkg/compress/zlib/), [flate](http://golang.org/pkg/compress/flate/).
-
-Currently there is only minor speedup on decompression (mostly CRC32 calculation).
-
-Memory usage is typically 1MB for a Writer. stdlib is in the same range.
-If you expect to have a lot of concurrently allocated Writers consider using
-the stateless compression described below.
-
-For compression performance, see: [this spreadsheet](https://docs.google.com/spreadsheets/d/1nuNE2nPfuINCZJRMt6wFWhKpToF95I47XjSsc-1rbPQ/edit?usp=sharing).
-
-To disable all assembly add `-tags=noasm`. This works across all packages.
-
-# Stateless compression
-
-This package offers stateless compression as a special option for gzip/deflate.
-It will do compression but without maintaining any state between Write calls.
-
-This means there will be no memory kept between Write calls, but compression and speed will be suboptimal.
-
-This is only relevant in cases where you expect to run many thousands of compressors concurrently,
-but with very little activity. This is *not* intended for regular web servers serving individual requests.
-
-Because of this, the size of actual Write calls will affect output size.
-
-In gzip, specify level `-3` / `gzip.StatelessCompression` to enable.
-
-For direct deflate use, NewStatelessWriter and StatelessDeflate are available. See [documentation](https://godoc.org/github.com/klauspost/compress/flate#NewStatelessWriter)
-
-A `bufio.Writer` can of course be used to control write sizes. For example, to use a 4KB buffer:
-
-```go
- // replace 'ioutil.Discard' with your output.
- gzw, err := gzip.NewWriterLevel(ioutil.Discard, gzip.StatelessCompression)
- if err != nil {
- return err
- }
- defer gzw.Close()
-
- w := bufio.NewWriterSize(gzw, 4096)
- defer w.Flush()
-
- // Write to 'w'
-```
-
-This will only use up to 4KB in memory when the writer is idle.
-
-Compression is almost always worse than the fastest compression level
-and each write will allocate (a little) memory.
-
-
-# Other packages
-
-Here are other packages of good quality and pure Go (no cgo wrappers or autoconverted code):
-
-* [github.com/pierrec/lz4](https://github.com/pierrec/lz4) - strong multithreaded LZ4 compression.
-* [github.com/cosnicolaou/pbzip2](https://github.com/cosnicolaou/pbzip2) - multithreaded bzip2 decompression.
-* [github.com/dsnet/compress](https://github.com/dsnet/compress) - brotli decompression, bzip2 writer.
-* [github.com/ronanh/intcomp](https://github.com/ronanh/intcomp) - Integer compression.
-* [github.com/spenczar/fpc](https://github.com/spenczar/fpc) - Float compression.
-* [github.com/minio/zipindex](https://github.com/minio/zipindex) - External ZIP directory index.
-* [github.com/ybirader/pzip](https://github.com/ybirader/pzip) - Fast concurrent zip archiver and extractor.
-
-# license
-
-This code is licensed under the same conditions as the original Go code. See LICENSE file.
-
-
-
-
+# compress
+
+This package provides various compression algorithms.
+
+* [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and decompression in pure Go.
+* [S2](https://github.com/klauspost/compress/tree/master/s2#s2-compression) is a high performance replacement for Snappy.
+* Optimized [deflate](https://godoc.org/github.com/klauspost/compress/flate) packages which can be used as a dropin replacement for [gzip](https://godoc.org/github.com/klauspost/compress/gzip), [zip](https://godoc.org/github.com/klauspost/compress/zip) and [zlib](https://godoc.org/github.com/klauspost/compress/zlib).
+* [snappy](https://github.com/klauspost/compress/tree/master/snappy) is a drop-in replacement for `github.com/golang/snappy` offering better compression and concurrent streams.
+* [huff0](https://github.com/klauspost/compress/tree/master/huff0) and [FSE](https://github.com/klauspost/compress/tree/master/fse) implementations for raw entropy encoding.
+* [gzhttp](https://github.com/klauspost/compress/tree/master/gzhttp) Provides client and server wrappers for handling gzipped/zstd HTTP requests efficiently.
+* [pgzip](https://github.com/klauspost/pgzip) is a separate package that provides a very fast parallel gzip implementation.
+
+[](https://pkg.go.dev/github.com/klauspost/compress?tab=subdirectories)
+[](https://github.com/klauspost/compress/actions/workflows/go.yml)
+[](https://sourcegraph.com/github.com/klauspost/compress?badge)
+
+# package usage
+
+Use `go get github.com/klauspost/compress@latest` to add it to your project.
+
+This package will support the current Go version and 2 versions back.
+
+* Use the `nounsafe` tag to disable all use of the "unsafe" package.
+* Use the `noasm` tag to disable all assembly across packages.
+
+Use the links above for more information on each.
+
+# changelog
+
+* Jul 1st, 2026 [1.19.0](https://github.com/klauspost/compress/releases/tag/v1.19.0)
+ * zstd: Add true concurrent stream encodingin https://github.com/klauspost/compress/pull/1136
+ * zstd: arm64 decoder asm by @lizthegrey in https://github.com/klauspost/compress/pull/1160
+ * flate: Add inflate checkpoints in https://github.com/klauspost/compress/pull/1154
+ * zstd: avoid unused BuildDict encoder allocation by @snissn in https://github.com/klauspost/compress/pull/1147
+ * snappy/s2: Limit length of varint in `decodedLen` by @eustas in https://github.com/klauspost/compress/pull/1148
+ * gzhttp: match qvalue parameter case-insensitively (RFC 7231) by @z9z in https://github.com/klauspost/compress/pull/1149
+ * zip: add NameDecoder callback for legacy encoding rewrite by @SAY-5 in https://github.com/klauspost/compress/pull/1150
+ * huff0: Allow building tables from histogram in https://github.com/klauspost/compress/pull/1155
+ * huff0: Allow building table from oversized histogram in https://github.com/klauspost/compress/pull/1156
+ * s2sx: Clean symlink targets in https://github.com/klauspost/compress/pull/1163
+
+* Feb 9th, 2026 [1.18.4](https://github.com/klauspost/compress/releases/tag/v1.18.4)
+ * gzhttp: Add zstandard to server handler wrapper https://github.com/klauspost/compress/pull/1121
+ * zstd: Add ResetWithOptions to encoder/decoder https://github.com/klauspost/compress/pull/1122
+ * gzhttp: preserve qvalue when extra parameters follow in Accept-Encoding by @analytically in https://github.com/klauspost/compress/pull/1116
+
+* Jan 16th, 2026 [1.18.3](https://github.com/klauspost/compress/releases/tag/v1.18.3)
+ * Downstream CVE-2025-61728. See [golang/go#77102](https://github.com/golang/go/issues/77102).
+
+* Dec 1st, 2025 - [1.18.2](https://github.com/klauspost/compress/releases/tag/v1.18.2)
+ * flate: Fix invalid encoding on level 9 with single value input in https://github.com/klauspost/compress/pull/1115
+ * flate: reduce stateless allocations by @RXamzin in https://github.com/klauspost/compress/pull/1106
+
+* Oct 20, 2025 - [1.18.1](https://github.com/klauspost/compress/releases/tag/v1.18.1) - RETRACTED
+ * zstd: Add simple zstd EncodeTo/DecodeTo functions https://github.com/klauspost/compress/pull/1079
+ * zstd: Fix incorrect buffer size in dictionary encodes https://github.com/klauspost/compress/pull/1059
+ * s2: check for cap, not len of buffer in EncodeBetter/Best by @vdarulis in https://github.com/klauspost/compress/pull/1080
+ * zlib: Avoiding extra allocation in zlib.reader.Reset by @travelpolicy in https://github.com/klauspost/compress/pull/1086
+ * gzhttp: remove redundant err check in zstdReader by @ryanfowler in https://github.com/klauspost/compress/pull/1090
+ * flate: Faster load+store https://github.com/klauspost/compress/pull/1104
+ * flate: Simplify matchlen https://github.com/klauspost/compress/pull/1101
+ * flate: Use exact sizes for huffman tables https://github.com/klauspost/compress/pull/1103
+
+* Feb 19th, 2025 - [1.18.0](https://github.com/klauspost/compress/releases/tag/v1.18.0)
+ * Add unsafe little endian loaders https://github.com/klauspost/compress/pull/1036
+ * fix: check `r.err != nil` but return a nil value error `err` by @alingse in https://github.com/klauspost/compress/pull/1028
+ * flate: Simplify L4-6 loading https://github.com/klauspost/compress/pull/1043
+ * flate: Simplify matchlen (remove asm) https://github.com/klauspost/compress/pull/1045
+ * s2: Improve small block compression speed w/o asm https://github.com/klauspost/compress/pull/1048
+ * flate: Fix matchlen L5+L6 https://github.com/klauspost/compress/pull/1049
+ * flate: Cleanup & reduce casts https://github.com/klauspost/compress/pull/1050
+
+
+ See changes to v1.17.x
+
+* Oct 11th, 2024 - [1.17.11](https://github.com/klauspost/compress/releases/tag/v1.17.11)
+ * zstd: Fix extra CRC written with multiple Close calls https://github.com/klauspost/compress/pull/1017
+ * s2: Don't use stack for index tables https://github.com/klauspost/compress/pull/1014
+ * gzhttp: No content-type on no body response code by @juliens in https://github.com/klauspost/compress/pull/1011
+ * gzhttp: Do not set the content-type when response has no body by @kevinpollet in https://github.com/klauspost/compress/pull/1013
+
+* Sep 23rd, 2024 - [1.17.10](https://github.com/klauspost/compress/releases/tag/v1.17.10)
+ * gzhttp: Add TransportAlwaysDecompress option. https://github.com/klauspost/compress/pull/978
+ * gzhttp: Add supported decompress request body by @mirecl in https://github.com/klauspost/compress/pull/1002
+ * s2: Add EncodeBuffer buffer recycling callback https://github.com/klauspost/compress/pull/982
+ * zstd: Improve memory usage on small streaming encodes https://github.com/klauspost/compress/pull/1007
+ * flate: read data written with partial flush by @vajexal in https://github.com/klauspost/compress/pull/996
+
+* Jun 12th, 2024 - [1.17.9](https://github.com/klauspost/compress/releases/tag/v1.17.9)
+ * s2: Reduce ReadFrom temporary allocations https://github.com/klauspost/compress/pull/949
+ * flate, zstd: Shave some bytes off amd64 matchLen by @greatroar in https://github.com/klauspost/compress/pull/963
+ * Upgrade zip/zlib to 1.22.4 upstream https://github.com/klauspost/compress/pull/970 https://github.com/klauspost/compress/pull/971
+ * zstd: BuildDict fails with RLE table https://github.com/klauspost/compress/pull/951
+
+* Apr 9th, 2024 - [1.17.8](https://github.com/klauspost/compress/releases/tag/v1.17.8)
+ * zstd: Reject blocks where reserved values are not 0 https://github.com/klauspost/compress/pull/885
+ * zstd: Add RLE detection+encoding https://github.com/klauspost/compress/pull/938
+
+* Feb 21st, 2024 - [1.17.7](https://github.com/klauspost/compress/releases/tag/v1.17.7)
+ * s2: Add AsyncFlush method: Complete the block without flushing by @Jille in https://github.com/klauspost/compress/pull/927
+ * s2: Fix literal+repeat exceeds dst crash https://github.com/klauspost/compress/pull/930
+
+* Feb 5th, 2024 - [1.17.6](https://github.com/klauspost/compress/releases/tag/v1.17.6)
+ * zstd: Fix incorrect repeat coding in best mode https://github.com/klauspost/compress/pull/923
+ * s2: Fix DecodeConcurrent deadlock on errors https://github.com/klauspost/compress/pull/925
+
+* Jan 26th, 2024 - [v1.17.5](https://github.com/klauspost/compress/releases/tag/v1.17.5)
+ * flate: Fix reset with dictionary on custom window encodes https://github.com/klauspost/compress/pull/912
+ * zstd: Add Frame header encoding and stripping https://github.com/klauspost/compress/pull/908
+ * zstd: Limit better/best default window to 8MB https://github.com/klauspost/compress/pull/913
+ * zstd: Speed improvements by @greatroar in https://github.com/klauspost/compress/pull/896 https://github.com/klauspost/compress/pull/910
+ * s2: Fix callbacks for skippable blocks and disallow 0xfe (Padding) by @Jille in https://github.com/klauspost/compress/pull/916 https://github.com/klauspost/compress/pull/917
+https://github.com/klauspost/compress/pull/919 https://github.com/klauspost/compress/pull/918
+
+* Dec 1st, 2023 - [v1.17.4](https://github.com/klauspost/compress/releases/tag/v1.17.4)
+ * huff0: Speed up symbol counting by @greatroar in https://github.com/klauspost/compress/pull/887
+ * huff0: Remove byteReader by @greatroar in https://github.com/klauspost/compress/pull/886
+ * gzhttp: Allow overriding decompression on transport https://github.com/klauspost/compress/pull/892
+ * gzhttp: Clamp compression level https://github.com/klauspost/compress/pull/890
+ * gzip: Error out if reserved bits are set https://github.com/klauspost/compress/pull/891
+
+* Nov 15th, 2023 - [v1.17.3](https://github.com/klauspost/compress/releases/tag/v1.17.3)
+ * fse: Fix max header size https://github.com/klauspost/compress/pull/881
+ * zstd: Improve better/best compression https://github.com/klauspost/compress/pull/877
+ * gzhttp: Fix missing content type on Close https://github.com/klauspost/compress/pull/883
+
+* Oct 22nd, 2023 - [v1.17.2](https://github.com/klauspost/compress/releases/tag/v1.17.2)
+ * zstd: Fix rare *CORRUPTION* output in "best" mode. See https://github.com/klauspost/compress/pull/876
+
+* Oct 14th, 2023 - [v1.17.1](https://github.com/klauspost/compress/releases/tag/v1.17.1)
+ * s2: Fix S2 "best" dictionary wrong encoding https://github.com/klauspost/compress/pull/871
+ * flate: Reduce allocations in decompressor and minor code improvements by @fakefloordiv in https://github.com/klauspost/compress/pull/869
+ * s2: Fix EstimateBlockSize on 6&7 length input https://github.com/klauspost/compress/pull/867
+
+* Sept 19th, 2023 - [v1.17.0](https://github.com/klauspost/compress/releases/tag/v1.17.0)
+ * Add experimental dictionary builder https://github.com/klauspost/compress/pull/853
+ * Add xerial snappy read/writer https://github.com/klauspost/compress/pull/838
+ * flate: Add limited window compression https://github.com/klauspost/compress/pull/843
+ * s2: Do 2 overlapping match checks https://github.com/klauspost/compress/pull/839
+ * flate: Add amd64 assembly matchlen https://github.com/klauspost/compress/pull/837
+ * gzip: Copy bufio.Reader on Reset by @thatguystone in https://github.com/klauspost/compress/pull/860
+
+
+
+ See changes to v1.16.x
+
+
+* July 1st, 2023 - [v1.16.7](https://github.com/klauspost/compress/releases/tag/v1.16.7)
+ * zstd: Fix default level first dictionary encode https://github.com/klauspost/compress/pull/829
+ * s2: add GetBufferCapacity() method by @GiedriusS in https://github.com/klauspost/compress/pull/832
+
+* June 13, 2023 - [v1.16.6](https://github.com/klauspost/compress/releases/tag/v1.16.6)
+ * zstd: correctly ignore WithEncoderPadding(1) by @ianlancetaylor in https://github.com/klauspost/compress/pull/806
+ * zstd: Add amd64 match length assembly https://github.com/klauspost/compress/pull/824
+ * gzhttp: Handle informational headers by @rtribotte in https://github.com/klauspost/compress/pull/815
+ * s2: Improve Better compression slightly https://github.com/klauspost/compress/pull/663
+
+* Apr 16, 2023 - [v1.16.5](https://github.com/klauspost/compress/releases/tag/v1.16.5)
+ * zstd: readByte needs to use io.ReadFull by @jnoxon in https://github.com/klauspost/compress/pull/802
+ * gzip: Fix WriterTo after initial read https://github.com/klauspost/compress/pull/804
+
+* Apr 5, 2023 - [v1.16.4](https://github.com/klauspost/compress/releases/tag/v1.16.4)
+ * zstd: Improve zstd best efficiency by @greatroar and @klauspost in https://github.com/klauspost/compress/pull/784
+ * zstd: Respect WithAllLitEntropyCompression https://github.com/klauspost/compress/pull/792
+ * zstd: Fix amd64 not always detecting corrupt data https://github.com/klauspost/compress/pull/785
+ * zstd: Various minor improvements by @greatroar in https://github.com/klauspost/compress/pull/788 https://github.com/klauspost/compress/pull/794 https://github.com/klauspost/compress/pull/795
+ * s2: Fix huge block overflow https://github.com/klauspost/compress/pull/779
+ * s2: Allow CustomEncoder fallback https://github.com/klauspost/compress/pull/780
+ * gzhttp: Support ResponseWriter Unwrap() in gzhttp handler by @jgimenez in https://github.com/klauspost/compress/pull/799
+
+* Mar 13, 2023 - [v1.16.1](https://github.com/klauspost/compress/releases/tag/v1.16.1)
+ * zstd: Speed up + improve best encoder by @greatroar in https://github.com/klauspost/compress/pull/776
+ * gzhttp: Add optional [BREACH mitigation](https://github.com/klauspost/compress/tree/master/gzhttp#breach-mitigation). https://github.com/klauspost/compress/pull/762 https://github.com/klauspost/compress/pull/768 https://github.com/klauspost/compress/pull/769 https://github.com/klauspost/compress/pull/770 https://github.com/klauspost/compress/pull/767
+ * s2: Add Intel LZ4s converter https://github.com/klauspost/compress/pull/766
+ * zstd: Minor bug fixes https://github.com/klauspost/compress/pull/771 https://github.com/klauspost/compress/pull/772 https://github.com/klauspost/compress/pull/773
+ * huff0: Speed up compress1xDo by @greatroar in https://github.com/klauspost/compress/pull/774
+
+* Feb 26, 2023 - [v1.16.0](https://github.com/klauspost/compress/releases/tag/v1.16.0)
+ * s2: Add [Dictionary](https://github.com/klauspost/compress/tree/master/s2#dictionaries) support. https://github.com/klauspost/compress/pull/685
+ * s2: Add Compression Size Estimate. https://github.com/klauspost/compress/pull/752
+ * s2: Add support for custom stream encoder. https://github.com/klauspost/compress/pull/755
+ * s2: Add LZ4 block converter. https://github.com/klauspost/compress/pull/748
+ * s2: Support io.ReaderAt in ReadSeeker. https://github.com/klauspost/compress/pull/747
+ * s2c/s2sx: Use concurrent decoding. https://github.com/klauspost/compress/pull/746
+
+
+
+ See changes to v1.15.x
+
+* Jan 21st, 2023 (v1.15.15)
+ * deflate: Improve level 7-9 https://github.com/klauspost/compress/pull/739
+ * zstd: Add delta encoding support by @greatroar in https://github.com/klauspost/compress/pull/728
+ * zstd: Various speed improvements by @greatroar https://github.com/klauspost/compress/pull/741 https://github.com/klauspost/compress/pull/734 https://github.com/klauspost/compress/pull/736 https://github.com/klauspost/compress/pull/744 https://github.com/klauspost/compress/pull/743 https://github.com/klauspost/compress/pull/745
+ * gzhttp: Add SuffixETag() and DropETag() options to prevent ETag collisions on compressed responses by @willbicks in https://github.com/klauspost/compress/pull/740
+
+* Jan 3rd, 2023 (v1.15.14)
+
+ * flate: Improve speed in big stateless blocks https://github.com/klauspost/compress/pull/718
+ * zstd: Minor speed tweaks by @greatroar in https://github.com/klauspost/compress/pull/716 https://github.com/klauspost/compress/pull/720
+ * export NoGzipResponseWriter for custom ResponseWriter wrappers by @harshavardhana in https://github.com/klauspost/compress/pull/722
+ * s2: Add example for indexing and existing stream https://github.com/klauspost/compress/pull/723
+
+* Dec 11, 2022 (v1.15.13)
+ * zstd: Add [MaxEncodedSize](https://pkg.go.dev/github.com/klauspost/compress@v1.15.13/zstd#Encoder.MaxEncodedSize) to encoder https://github.com/klauspost/compress/pull/691
+ * zstd: Various tweaks and improvements https://github.com/klauspost/compress/pull/693 https://github.com/klauspost/compress/pull/695 https://github.com/klauspost/compress/pull/696 https://github.com/klauspost/compress/pull/701 https://github.com/klauspost/compress/pull/702 https://github.com/klauspost/compress/pull/703 https://github.com/klauspost/compress/pull/704 https://github.com/klauspost/compress/pull/705 https://github.com/klauspost/compress/pull/706 https://github.com/klauspost/compress/pull/707 https://github.com/klauspost/compress/pull/708
+
+* Oct 26, 2022 (v1.15.12)
+
+ * zstd: Tweak decoder allocs. https://github.com/klauspost/compress/pull/680
+ * gzhttp: Always delete `HeaderNoCompression` https://github.com/klauspost/compress/pull/683
+
+* Sept 26, 2022 (v1.15.11)
+
+ * flate: Improve level 1-3 compression https://github.com/klauspost/compress/pull/678
+ * zstd: Improve "best" compression by @nightwolfz in https://github.com/klauspost/compress/pull/677
+ * zstd: Fix+reduce decompression allocations https://github.com/klauspost/compress/pull/668
+ * zstd: Fix non-effective noescape tag https://github.com/klauspost/compress/pull/667
+
+* Sept 16, 2022 (v1.15.10)
+
+ * zstd: Add [WithDecodeAllCapLimit](https://pkg.go.dev/github.com/klauspost/compress@v1.15.10/zstd#WithDecodeAllCapLimit) https://github.com/klauspost/compress/pull/649
+ * Add Go 1.19 - deprecate Go 1.16 https://github.com/klauspost/compress/pull/651
+ * flate: Improve level 5+6 compression https://github.com/klauspost/compress/pull/656
+ * zstd: Improve "better" compression https://github.com/klauspost/compress/pull/657
+ * s2: Improve "best" compression https://github.com/klauspost/compress/pull/658
+ * s2: Improve "better" compression. https://github.com/klauspost/compress/pull/635
+ * s2: Slightly faster non-assembly decompression https://github.com/klauspost/compress/pull/646
+ * Use arrays for constant size copies https://github.com/klauspost/compress/pull/659
+
+* July 21, 2022 (v1.15.9)
+
+ * zstd: Fix decoder crash on amd64 (no BMI) on invalid input https://github.com/klauspost/compress/pull/645
+ * zstd: Disable decoder extended memory copies (amd64) due to possible crashes https://github.com/klauspost/compress/pull/644
+ * zstd: Allow single segments up to "max decoded size" https://github.com/klauspost/compress/pull/643
+
+* July 13, 2022 (v1.15.8)
+
+ * gzip: fix stack exhaustion bug in Reader.Read https://github.com/klauspost/compress/pull/641
+ * s2: Add Index header trim/restore https://github.com/klauspost/compress/pull/638
+ * zstd: Optimize seqdeq amd64 asm by @greatroar in https://github.com/klauspost/compress/pull/636
+ * zstd: Improve decoder memcopy https://github.com/klauspost/compress/pull/637
+ * huff0: Pass a single bitReader pointer to asm by @greatroar in https://github.com/klauspost/compress/pull/634
+ * zstd: Branchless getBits for amd64 w/o BMI2 by @greatroar in https://github.com/klauspost/compress/pull/640
+ * gzhttp: Remove header before writing https://github.com/klauspost/compress/pull/639
+
+* June 29, 2022 (v1.15.7)
+
+ * s2: Fix absolute forward seeks https://github.com/klauspost/compress/pull/633
+ * zip: Merge upstream https://github.com/klauspost/compress/pull/631
+ * zip: Re-add zip64 fix https://github.com/klauspost/compress/pull/624
+ * zstd: translate fseDecoder.buildDtable into asm by @WojciechMula in https://github.com/klauspost/compress/pull/598
+ * flate: Faster histograms https://github.com/klauspost/compress/pull/620
+ * deflate: Use compound hcode https://github.com/klauspost/compress/pull/622
+
+* June 3, 2022 (v1.15.6)
+ * s2: Improve coding for long, close matches https://github.com/klauspost/compress/pull/613
+ * s2c: Add Snappy/S2 stream recompression https://github.com/klauspost/compress/pull/611
+ * zstd: Always use configured block size https://github.com/klauspost/compress/pull/605
+ * zstd: Fix incorrect hash table placement for dict encoding in default https://github.com/klauspost/compress/pull/606
+ * zstd: Apply default config to ZipDecompressor without options https://github.com/klauspost/compress/pull/608
+ * gzhttp: Exclude more common archive formats https://github.com/klauspost/compress/pull/612
+ * s2: Add ReaderIgnoreCRC https://github.com/klauspost/compress/pull/609
+ * s2: Remove sanity load on index creation https://github.com/klauspost/compress/pull/607
+ * snappy: Use dedicated function for scoring https://github.com/klauspost/compress/pull/614
+ * s2c+s2d: Use official snappy framed extension https://github.com/klauspost/compress/pull/610
+
+* May 25, 2022 (v1.15.5)
+ * s2: Add concurrent stream decompression https://github.com/klauspost/compress/pull/602
+ * s2: Fix final emit oob read crash on amd64 https://github.com/klauspost/compress/pull/601
+ * huff0: asm implementation of Decompress1X by @WojciechMula https://github.com/klauspost/compress/pull/596
+ * zstd: Use 1 less goroutine for stream decoding https://github.com/klauspost/compress/pull/588
+ * zstd: Copy literal in 16 byte blocks when possible https://github.com/klauspost/compress/pull/592
+ * zstd: Speed up when WithDecoderLowmem(false) https://github.com/klauspost/compress/pull/599
+ * zstd: faster next state update in BMI2 version of decode by @WojciechMula in https://github.com/klauspost/compress/pull/593
+ * huff0: Do not check max size when reading table. https://github.com/klauspost/compress/pull/586
+ * flate: Inplace hashing for level 7-9 https://github.com/klauspost/compress/pull/590
+
+
+* May 11, 2022 (v1.15.4)
+ * huff0: decompress directly into output by @WojciechMula in [#577](https://github.com/klauspost/compress/pull/577)
+ * inflate: Keep dict on stack [#581](https://github.com/klauspost/compress/pull/581)
+ * zstd: Faster decoding memcopy in asm [#583](https://github.com/klauspost/compress/pull/583)
+ * zstd: Fix ignored crc [#580](https://github.com/klauspost/compress/pull/580)
+
+* May 5, 2022 (v1.15.3)
+ * zstd: Allow to ignore checksum checking by @WojciechMula [#572](https://github.com/klauspost/compress/pull/572)
+ * s2: Fix incorrect seek for io.SeekEnd in [#575](https://github.com/klauspost/compress/pull/575)
+
+* Apr 26, 2022 (v1.15.2)
+ * zstd: Add x86-64 assembly for decompression on streams and blocks. Contributed by [@WojciechMula](https://github.com/WojciechMula). Typically 2x faster. [#528](https://github.com/klauspost/compress/pull/528) [#531](https://github.com/klauspost/compress/pull/531) [#545](https://github.com/klauspost/compress/pull/545) [#537](https://github.com/klauspost/compress/pull/537)
+ * zstd: Add options to ZipDecompressor and fixes [#539](https://github.com/klauspost/compress/pull/539)
+ * s2: Use sorted search for index [#555](https://github.com/klauspost/compress/pull/555)
+ * Minimum version is Go 1.16, added CI test on 1.18.
+
+* Mar 11, 2022 (v1.15.1)
+ * huff0: Add x86 assembly of Decode4X by @WojciechMula in [#512](https://github.com/klauspost/compress/pull/512)
+ * zstd: Reuse zip decoders in [#514](https://github.com/klauspost/compress/pull/514)
+ * zstd: Detect extra block data and report as corrupted in [#520](https://github.com/klauspost/compress/pull/520)
+ * zstd: Handle zero sized frame content size stricter in [#521](https://github.com/klauspost/compress/pull/521)
+ * zstd: Add stricter block size checks in [#523](https://github.com/klauspost/compress/pull/523)
+
+* Mar 3, 2022 (v1.15.0)
+ * zstd: Refactor decoder [#498](https://github.com/klauspost/compress/pull/498)
+ * zstd: Add stream encoding without goroutines [#505](https://github.com/klauspost/compress/pull/505)
+ * huff0: Prevent single blocks exceeding 16 bits by @klauspost in[#507](https://github.com/klauspost/compress/pull/507)
+ * flate: Inline literal emission [#509](https://github.com/klauspost/compress/pull/509)
+ * gzhttp: Add zstd to transport [#400](https://github.com/klauspost/compress/pull/400)
+ * gzhttp: Make content-type optional [#510](https://github.com/klauspost/compress/pull/510)
+
+Both compression and decompression now supports "synchronous" stream operations. This means that whenever "concurrency" is set to 1, they will operate without spawning goroutines.
+
+Stream decompression is now faster on asynchronous, since the goroutine allocation much more effectively splits the workload. On typical streams this will typically use 2 cores fully for decompression. When a stream has finished decoding no goroutines will be left over, so decoders can now safely be pooled and still be garbage collected.
+
+While the release has been extensively tested, it is recommended to testing when upgrading.
+
+
+
+
+ See changes to v1.14.x
+
+* Feb 22, 2022 (v1.14.4)
+ * flate: Fix rare huffman only (-2) corruption. [#503](https://github.com/klauspost/compress/pull/503)
+ * zip: Update deprecated CreateHeaderRaw to correctly call CreateRaw by @saracen in [#502](https://github.com/klauspost/compress/pull/502)
+ * zip: don't read data descriptor early by @saracen in [#501](https://github.com/klauspost/compress/pull/501) #501
+ * huff0: Use static decompression buffer up to 30% faster [#499](https://github.com/klauspost/compress/pull/499) [#500](https://github.com/klauspost/compress/pull/500)
+
+* Feb 17, 2022 (v1.14.3)
+ * flate: Improve fastest levels compression speed ~10% more throughput. [#482](https://github.com/klauspost/compress/pull/482) [#489](https://github.com/klauspost/compress/pull/489) [#490](https://github.com/klauspost/compress/pull/490) [#491](https://github.com/klauspost/compress/pull/491) [#494](https://github.com/klauspost/compress/pull/494) [#478](https://github.com/klauspost/compress/pull/478)
+ * flate: Faster decompression speed, ~5-10%. [#483](https://github.com/klauspost/compress/pull/483)
+ * s2: Faster compression with Go v1.18 and amd64 microarch level 3+. [#484](https://github.com/klauspost/compress/pull/484) [#486](https://github.com/klauspost/compress/pull/486)
+
+* Jan 25, 2022 (v1.14.2)
+ * zstd: improve header decoder by @dsnet [#476](https://github.com/klauspost/compress/pull/476)
+ * zstd: Add bigger default blocks [#469](https://github.com/klauspost/compress/pull/469)
+ * zstd: Remove unused decompression buffer [#470](https://github.com/klauspost/compress/pull/470)
+ * zstd: Fix logically dead code by @ningmingxiao [#472](https://github.com/klauspost/compress/pull/472)
+ * flate: Improve level 7-9 [#471](https://github.com/klauspost/compress/pull/471) [#473](https://github.com/klauspost/compress/pull/473)
+ * zstd: Add noasm tag for xxhash [#475](https://github.com/klauspost/compress/pull/475)
+
+* Jan 11, 2022 (v1.14.1)
+ * s2: Add stream index in [#462](https://github.com/klauspost/compress/pull/462)
+ * flate: Speed and efficiency improvements in [#439](https://github.com/klauspost/compress/pull/439) [#461](https://github.com/klauspost/compress/pull/461) [#455](https://github.com/klauspost/compress/pull/455) [#452](https://github.com/klauspost/compress/pull/452) [#458](https://github.com/klauspost/compress/pull/458)
+ * zstd: Performance improvement in [#420]( https://github.com/klauspost/compress/pull/420) [#456](https://github.com/klauspost/compress/pull/456) [#437](https://github.com/klauspost/compress/pull/437) [#467](https://github.com/klauspost/compress/pull/467) [#468](https://github.com/klauspost/compress/pull/468)
+ * zstd: add arm64 xxhash assembly in [#464](https://github.com/klauspost/compress/pull/464)
+ * Add garbled for binaries for s2 in [#445](https://github.com/klauspost/compress/pull/445)
+
+
+
+ See changes to v1.13.x
+
+* Aug 30, 2021 (v1.13.5)
+ * gz/zlib/flate: Alias stdlib errors [#425](https://github.com/klauspost/compress/pull/425)
+ * s2: Add block support to commandline tools [#413](https://github.com/klauspost/compress/pull/413)
+ * zstd: pooledZipWriter should return Writers to the same pool [#426](https://github.com/klauspost/compress/pull/426)
+ * Removed golang/snappy as external dependency for tests [#421](https://github.com/klauspost/compress/pull/421)
+
+* Aug 12, 2021 (v1.13.4)
+ * Add [snappy replacement package](https://github.com/klauspost/compress/tree/master/snappy).
+ * zstd: Fix incorrect encoding in "best" mode [#415](https://github.com/klauspost/compress/pull/415)
+
+* Aug 3, 2021 (v1.13.3)
+ * zstd: Improve Best compression [#404](https://github.com/klauspost/compress/pull/404)
+ * zstd: Fix WriteTo error forwarding [#411](https://github.com/klauspost/compress/pull/411)
+ * gzhttp: Return http.HandlerFunc instead of http.Handler. Unlikely breaking change. [#406](https://github.com/klauspost/compress/pull/406)
+ * s2sx: Fix max size error [#399](https://github.com/klauspost/compress/pull/399)
+ * zstd: Add optional stream content size on reset [#401](https://github.com/klauspost/compress/pull/401)
+ * zstd: use SpeedBestCompression for level >= 10 [#410](https://github.com/klauspost/compress/pull/410)
+
+* Jun 14, 2021 (v1.13.1)
+ * s2: Add full Snappy output support [#396](https://github.com/klauspost/compress/pull/396)
+ * zstd: Add configurable [Decoder window](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithDecoderMaxWindow) size [#394](https://github.com/klauspost/compress/pull/394)
+ * gzhttp: Add header to skip compression [#389](https://github.com/klauspost/compress/pull/389)
+ * s2: Improve speed with bigger output margin [#395](https://github.com/klauspost/compress/pull/395)
+
+* Jun 3, 2021 (v1.13.0)
+ * Added [gzhttp](https://github.com/klauspost/compress/tree/master/gzhttp#gzip-handler) which allows wrapping HTTP servers and clients with GZIP compressors.
+ * zstd: Detect short invalid signatures [#382](https://github.com/klauspost/compress/pull/382)
+ * zstd: Spawn decoder goroutine only if needed. [#380](https://github.com/klauspost/compress/pull/380)
+
+
+
+
+ See changes to v1.12.x
+
+* May 25, 2021 (v1.12.3)
+ * deflate: Better/faster Huffman encoding [#374](https://github.com/klauspost/compress/pull/374)
+ * deflate: Allocate less for history. [#375](https://github.com/klauspost/compress/pull/375)
+ * zstd: Forward read errors [#373](https://github.com/klauspost/compress/pull/373)
+
+* Apr 27, 2021 (v1.12.2)
+ * zstd: Improve better/best compression [#360](https://github.com/klauspost/compress/pull/360) [#364](https://github.com/klauspost/compress/pull/364) [#365](https://github.com/klauspost/compress/pull/365)
+ * zstd: Add helpers to compress/decompress zstd inside zip files [#363](https://github.com/klauspost/compress/pull/363)
+ * deflate: Improve level 5+6 compression [#367](https://github.com/klauspost/compress/pull/367)
+ * s2: Improve better/best compression [#358](https://github.com/klauspost/compress/pull/358) [#359](https://github.com/klauspost/compress/pull/358)
+ * s2: Load after checking src limit on amd64. [#362](https://github.com/klauspost/compress/pull/362)
+ * s2sx: Limit max executable size [#368](https://github.com/klauspost/compress/pull/368)
+
+* Apr 14, 2021 (v1.12.1)
+ * snappy package removed. Upstream added as dependency.
+ * s2: Better compression in "best" mode [#353](https://github.com/klauspost/compress/pull/353)
+ * s2sx: Add stdin input and detect pre-compressed from signature [#352](https://github.com/klauspost/compress/pull/352)
+ * s2c/s2d: Add http as possible input [#348](https://github.com/klauspost/compress/pull/348)
+ * s2c/s2d/s2sx: Always truncate when writing files [#352](https://github.com/klauspost/compress/pull/352)
+ * zstd: Reduce memory usage further when using [WithLowerEncoderMem](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithLowerEncoderMem) [#346](https://github.com/klauspost/compress/pull/346)
+ * s2: Fix potential problem with amd64 assembly and profilers [#349](https://github.com/klauspost/compress/pull/349)
+
+
+
+ See changes to v1.11.x
+
+* Mar 26, 2021 (v1.11.13)
+ * zstd: Big speedup on small dictionary encodes [#344](https://github.com/klauspost/compress/pull/344) [#345](https://github.com/klauspost/compress/pull/345)
+ * zstd: Add [WithLowerEncoderMem](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithLowerEncoderMem) encoder option [#336](https://github.com/klauspost/compress/pull/336)
+ * deflate: Improve entropy compression [#338](https://github.com/klauspost/compress/pull/338)
+ * s2: Clean up and minor performance improvement in best [#341](https://github.com/klauspost/compress/pull/341)
+
+* Mar 5, 2021 (v1.11.12)
+ * s2: Add `s2sx` binary that creates [self extracting archives](https://github.com/klauspost/compress/tree/master/s2#s2sx-self-extracting-archives).
+ * s2: Speed up decompression on non-assembly platforms [#328](https://github.com/klauspost/compress/pull/328)
+
+* Mar 1, 2021 (v1.11.9)
+ * s2: Add ARM64 decompression assembly. Around 2x output speed. [#324](https://github.com/klauspost/compress/pull/324)
+ * s2: Improve "better" speed and efficiency. [#325](https://github.com/klauspost/compress/pull/325)
+ * s2: Fix binaries.
+
+* Feb 25, 2021 (v1.11.8)
+ * s2: Fixed occasional out-of-bounds write on amd64. Upgrade recommended.
+ * s2: Add AMD64 assembly for better mode. 25-50% faster. [#315](https://github.com/klauspost/compress/pull/315)
+ * s2: Less upfront decoder allocation. [#322](https://github.com/klauspost/compress/pull/322)
+ * zstd: Faster "compression" of incompressible data. [#314](https://github.com/klauspost/compress/pull/314)
+ * zip: Fix zip64 headers. [#313](https://github.com/klauspost/compress/pull/313)
+
+* Jan 14, 2021 (v1.11.7)
+ * Use Bytes() interface to get bytes across packages. [#309](https://github.com/klauspost/compress/pull/309)
+ * s2: Add 'best' compression option. [#310](https://github.com/klauspost/compress/pull/310)
+ * s2: Add ReaderMaxBlockSize, changes `s2.NewReader` signature to include varargs. [#311](https://github.com/klauspost/compress/pull/311)
+ * s2: Fix crash on small better buffers. [#308](https://github.com/klauspost/compress/pull/308)
+ * s2: Clean up decoder. [#312](https://github.com/klauspost/compress/pull/312)
+
+* Jan 7, 2021 (v1.11.6)
+ * zstd: Make decoder allocations smaller [#306](https://github.com/klauspost/compress/pull/306)
+ * zstd: Free Decoder resources when Reset is called with a nil io.Reader [#305](https://github.com/klauspost/compress/pull/305)
+
+* Dec 20, 2020 (v1.11.4)
+ * zstd: Add Best compression mode [#304](https://github.com/klauspost/compress/pull/304)
+ * Add header decoder [#299](https://github.com/klauspost/compress/pull/299)
+ * s2: Add uncompressed stream option [#297](https://github.com/klauspost/compress/pull/297)
+ * Simplify/speed up small blocks with known max size. [#300](https://github.com/klauspost/compress/pull/300)
+ * zstd: Always reset literal dict encoder [#303](https://github.com/klauspost/compress/pull/303)
+
+* Nov 15, 2020 (v1.11.3)
+ * inflate: 10-15% faster decompression [#293](https://github.com/klauspost/compress/pull/293)
+ * zstd: Tweak DecodeAll default allocation [#295](https://github.com/klauspost/compress/pull/295)
+
+* Oct 11, 2020 (v1.11.2)
+ * s2: Fix out of bounds read in "better" block compression [#291](https://github.com/klauspost/compress/pull/291)
+
+* Oct 1, 2020 (v1.11.1)
+ * zstd: Set allLitEntropy true in default configuration [#286](https://github.com/klauspost/compress/pull/286)
+
+* Sept 8, 2020 (v1.11.0)
+ * zstd: Add experimental compression [dictionaries](https://github.com/klauspost/compress/tree/master/zstd#dictionaries) [#281](https://github.com/klauspost/compress/pull/281)
+ * zstd: Fix mixed Write and ReadFrom calls [#282](https://github.com/klauspost/compress/pull/282)
+ * inflate/gz: Limit variable shifts, ~5% faster decompression [#274](https://github.com/klauspost/compress/pull/274)
+
+
+
+ See changes to v1.10.x
+
+* July 8, 2020 (v1.10.11)
+ * zstd: Fix extra block when compressing with ReadFrom. [#278](https://github.com/klauspost/compress/pull/278)
+ * huff0: Also populate compression table when reading decoding table. [#275](https://github.com/klauspost/compress/pull/275)
+
+* June 23, 2020 (v1.10.10)
+ * zstd: Skip entropy compression in fastest mode when no matches. [#270](https://github.com/klauspost/compress/pull/270)
+
+* June 16, 2020 (v1.10.9):
+ * zstd: API change for specifying dictionaries. See [#268](https://github.com/klauspost/compress/pull/268)
+ * zip: update CreateHeaderRaw to handle zip64 fields. [#266](https://github.com/klauspost/compress/pull/266)
+ * Fuzzit tests removed. The service has been purchased and is no longer available.
+
+* June 5, 2020 (v1.10.8):
+ * 1.15x faster zstd block decompression. [#265](https://github.com/klauspost/compress/pull/265)
+
+* June 1, 2020 (v1.10.7):
+ * Added zstd decompression [dictionary support](https://github.com/klauspost/compress/tree/master/zstd#dictionaries)
+ * Increase zstd decompression speed up to 1.19x. [#259](https://github.com/klauspost/compress/pull/259)
+ * Remove internal reset call in zstd compression and reduce allocations. [#263](https://github.com/klauspost/compress/pull/263)
+
+* May 21, 2020: (v1.10.6)
+ * zstd: Reduce allocations while decoding. [#258](https://github.com/klauspost/compress/pull/258), [#252](https://github.com/klauspost/compress/pull/252)
+ * zstd: Stricter decompression checks.
+
+* April 12, 2020: (v1.10.5)
+ * s2-commands: Flush output when receiving SIGINT. [#239](https://github.com/klauspost/compress/pull/239)
+
+* Apr 8, 2020: (v1.10.4)
+ * zstd: Minor/special case optimizations. [#251](https://github.com/klauspost/compress/pull/251), [#250](https://github.com/klauspost/compress/pull/250), [#249](https://github.com/klauspost/compress/pull/249), [#247](https://github.com/klauspost/compress/pull/247)
+* Mar 11, 2020: (v1.10.3)
+ * s2: Use S2 encoder in pure Go mode for Snappy output as well. [#245](https://github.com/klauspost/compress/pull/245)
+ * s2: Fix pure Go block encoder. [#244](https://github.com/klauspost/compress/pull/244)
+ * zstd: Added "better compression" mode. [#240](https://github.com/klauspost/compress/pull/240)
+ * zstd: Improve speed of fastest compression mode by 5-10% [#241](https://github.com/klauspost/compress/pull/241)
+ * zstd: Skip creating encoders when not needed. [#238](https://github.com/klauspost/compress/pull/238)
+
+* Feb 27, 2020: (v1.10.2)
+ * Close to 50% speedup in inflate (gzip/zip decompression). [#236](https://github.com/klauspost/compress/pull/236) [#234](https://github.com/klauspost/compress/pull/234) [#232](https://github.com/klauspost/compress/pull/232)
+ * Reduce deflate level 1-6 memory usage up to 59%. [#227](https://github.com/klauspost/compress/pull/227)
+
+* Feb 18, 2020: (v1.10.1)
+ * Fix zstd crash when resetting multiple times without sending data. [#226](https://github.com/klauspost/compress/pull/226)
+ * deflate: Fix dictionary use on level 1-6. [#224](https://github.com/klauspost/compress/pull/224)
+ * Remove deflate writer reference when closing. [#224](https://github.com/klauspost/compress/pull/224)
+
+* Feb 4, 2020: (v1.10.0)
+ * Add optional dictionary to [stateless deflate](https://pkg.go.dev/github.com/klauspost/compress/flate?tab=doc#StatelessDeflate). Breaking change, send `nil` for previous behaviour. [#216](https://github.com/klauspost/compress/pull/216)
+ * Fix buffer overflow on repeated small block deflate. [#218](https://github.com/klauspost/compress/pull/218)
+ * Allow copying content from an existing ZIP file without decompressing+compressing. [#214](https://github.com/klauspost/compress/pull/214)
+ * Added [S2](https://github.com/klauspost/compress/tree/master/s2#s2-compression) AMD64 assembler and various optimizations. Stream speed >10GB/s. [#186](https://github.com/klauspost/compress/pull/186)
+
+
+
+
+ See changes prior to v1.10.0
+
+* Jan 20,2020 (v1.9.8) Optimize gzip/deflate with better size estimates and faster table generation. [#207](https://github.com/klauspost/compress/pull/207) by [luyu6056](https://github.com/luyu6056), [#206](https://github.com/klauspost/compress/pull/206).
+* Jan 11, 2020: S2 Encode/Decode will use provided buffer if capacity is big enough. [#204](https://github.com/klauspost/compress/pull/204)
+* Jan 5, 2020: (v1.9.7) Fix another zstd regression in v1.9.5 - v1.9.6 removed.
+* Jan 4, 2020: (v1.9.6) Regression in v1.9.5 fixed causing corrupt zstd encodes in rare cases.
+* Jan 4, 2020: Faster IO in [s2c + s2d commandline tools](https://github.com/klauspost/compress/tree/master/s2#commandline-tools) compression/decompression. [#192](https://github.com/klauspost/compress/pull/192)
+* Dec 29, 2019: Removed v1.9.5 since fuzz tests showed a compatibility problem with the reference zstandard decoder.
+* Dec 29, 2019: (v1.9.5) zstd: 10-20% faster block compression. [#199](https://github.com/klauspost/compress/pull/199)
+* Dec 29, 2019: [zip](https://godoc.org/github.com/klauspost/compress/zip) package updated with latest Go features
+* Dec 29, 2019: zstd: Single segment flag condintions tweaked. [#197](https://github.com/klauspost/compress/pull/197)
+* Dec 18, 2019: s2: Faster compression when ReadFrom is used. [#198](https://github.com/klauspost/compress/pull/198)
+* Dec 10, 2019: s2: Fix repeat length output when just above at 16MB limit.
+* Dec 10, 2019: zstd: Add function to get decoder as io.ReadCloser. [#191](https://github.com/klauspost/compress/pull/191)
+* Dec 3, 2019: (v1.9.4) S2: limit max repeat length. [#188](https://github.com/klauspost/compress/pull/188)
+* Dec 3, 2019: Add [WithNoEntropyCompression](https://godoc.org/github.com/klauspost/compress/zstd#WithNoEntropyCompression) to zstd [#187](https://github.com/klauspost/compress/pull/187)
+* Dec 3, 2019: Reduce memory use for tests. Check for leaked goroutines.
+* Nov 28, 2019 (v1.9.3) Less allocations in stateless deflate.
+* Nov 28, 2019: 5-20% Faster huff0 decode. Impacts zstd as well. [#184](https://github.com/klauspost/compress/pull/184)
+* Nov 12, 2019 (v1.9.2) Added [Stateless Compression](#stateless-compression) for gzip/deflate.
+* Nov 12, 2019: Fixed zstd decompression of large single blocks. [#180](https://github.com/klauspost/compress/pull/180)
+* Nov 11, 2019: Set default [s2c](https://github.com/klauspost/compress/tree/master/s2#commandline-tools) block size to 4MB.
+* Nov 11, 2019: Reduce inflate memory use by 1KB.
+* Nov 10, 2019: Less allocations in deflate bit writer.
+* Nov 10, 2019: Fix inconsistent error returned by zstd decoder.
+* Oct 28, 2019 (v1.9.1) ztsd: Fix crash when compressing blocks. [#174](https://github.com/klauspost/compress/pull/174)
+* Oct 24, 2019 (v1.9.0) zstd: Fix rare data corruption [#173](https://github.com/klauspost/compress/pull/173)
+* Oct 24, 2019 zstd: Fix huff0 out of buffer write [#171](https://github.com/klauspost/compress/pull/171) and always return errors [#172](https://github.com/klauspost/compress/pull/172)
+* Oct 10, 2019: Big deflate rewrite, 30-40% faster with better compression [#105](https://github.com/klauspost/compress/pull/105)
+
+
+
+
+ See changes prior to v1.9.0
+
+* Oct 10, 2019: (v1.8.6) zstd: Allow partial reads to get flushed data. [#169](https://github.com/klauspost/compress/pull/169)
+* Oct 3, 2019: Fix inconsistent results on broken zstd streams.
+* Sep 25, 2019: Added `-rm` (remove source files) and `-q` (no output except errors) to `s2c` and `s2d` [commands](https://github.com/klauspost/compress/tree/master/s2#commandline-tools)
+* Sep 16, 2019: (v1.8.4) Add `s2c` and `s2d` [commandline tools](https://github.com/klauspost/compress/tree/master/s2#commandline-tools).
+* Sep 10, 2019: (v1.8.3) Fix s2 decoder [Skip](https://godoc.org/github.com/klauspost/compress/s2#Reader.Skip).
+* Sep 7, 2019: zstd: Added [WithWindowSize](https://godoc.org/github.com/klauspost/compress/zstd#WithWindowSize), contributed by [ianwilkes](https://github.com/ianwilkes).
+* Sep 5, 2019: (v1.8.2) Add [WithZeroFrames](https://godoc.org/github.com/klauspost/compress/zstd#WithZeroFrames) which adds full zero payload block encoding option.
+* Sep 5, 2019: Lazy initialization of zstandard predefined en/decoder tables.
+* Aug 26, 2019: (v1.8.1) S2: 1-2% compression increase in "better" compression mode.
+* Aug 26, 2019: zstd: Check maximum size of Huffman 1X compressed literals while decoding.
+* Aug 24, 2019: (v1.8.0) Added [S2 compression](https://github.com/klauspost/compress/tree/master/s2#s2-compression), a high performance replacement for Snappy.
+* Aug 21, 2019: (v1.7.6) Fixed minor issues found by fuzzer. One could lead to zstd not decompressing.
+* Aug 18, 2019: Add [fuzzit](https://fuzzit.dev/) continuous fuzzing.
+* Aug 14, 2019: zstd: Skip incompressible data 2x faster. [#147](https://github.com/klauspost/compress/pull/147)
+* Aug 4, 2019 (v1.7.5): Better literal compression. [#146](https://github.com/klauspost/compress/pull/146)
+* Aug 4, 2019: Faster zstd compression. [#143](https://github.com/klauspost/compress/pull/143) [#144](https://github.com/klauspost/compress/pull/144)
+* Aug 4, 2019: Faster zstd decompression. [#145](https://github.com/klauspost/compress/pull/145) [#143](https://github.com/klauspost/compress/pull/143) [#142](https://github.com/klauspost/compress/pull/142)
+* July 15, 2019 (v1.7.4): Fix double EOF block in rare cases on zstd encoder.
+* July 15, 2019 (v1.7.3): Minor speedup/compression increase in default zstd encoder.
+* July 14, 2019: zstd decoder: Fix decompression error on multiple uses with mixed content.
+* July 7, 2019 (v1.7.2): Snappy update, zstd decoder potential race fix.
+* June 17, 2019: zstd decompression bugfix.
+* June 17, 2019: fix 32 bit builds.
+* June 17, 2019: Easier use in modules (less dependencies).
+* June 9, 2019: New stronger "default" [zstd](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression mode. Matches zstd default compression ratio.
+* June 5, 2019: 20-40% throughput in [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and better compression.
+* June 5, 2019: deflate/gzip compression: Reduce memory usage of lower compression levels.
+* June 2, 2019: Added [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression!
+* May 25, 2019: deflate/gzip: 10% faster bit writer, mostly visible in lower levels.
+* Apr 22, 2019: [zstd](https://github.com/klauspost/compress/tree/master/zstd#zstd) decompression added.
+* Aug 1, 2018: Added [huff0 README](https://github.com/klauspost/compress/tree/master/huff0#huff0-entropy-compression).
+* Jul 8, 2018: Added [Performance Update 2018](#performance-update-2018) below.
+* Jun 23, 2018: Merged [Go 1.11 inflate optimizations](https://go-review.googlesource.com/c/go/+/102235). Go 1.9 is now required. Backwards compatible version tagged with [v1.3.0](https://github.com/klauspost/compress/releases/tag/v1.3.0).
+* Apr 2, 2018: Added [huff0](https://godoc.org/github.com/klauspost/compress/huff0) en/decoder. Experimental for now, API may change.
+* Mar 4, 2018: Added [FSE Entropy](https://godoc.org/github.com/klauspost/compress/fse) en/decoder. Experimental for now, API may change.
+* Nov 3, 2017: Add compression [Estimate](https://godoc.org/github.com/klauspost/compress#Estimate) function.
+* May 28, 2017: Reduce allocations when resetting decoder.
+* Apr 02, 2017: Change back to official crc32, since changes were merged in Go 1.7.
+* Jan 14, 2017: Reduce stack pressure due to array copies. See [Issue #18625](https://github.com/golang/go/issues/18625).
+* Oct 25, 2016: Level 2-4 have been rewritten and now offers significantly better performance than before.
+* Oct 20, 2016: Port zlib changes from Go 1.7 to fix zlib writer issue. Please update.
+* Oct 16, 2016: Go 1.7 changes merged. Apples to apples this package is a few percent faster, but has a significantly better balance between speed and compression per level.
+* Mar 24, 2016: Always attempt Huffman encoding on level 4-7. This improves base 64 encoded data compression.
+* Mar 24, 2016: Small speedup for level 1-3.
+* Feb 19, 2016: Faster bit writer, level -2 is 15% faster, level 1 is 4% faster.
+* Feb 19, 2016: Handle small payloads faster in level 1-3.
+* Feb 19, 2016: Added faster level 2 + 3 compression modes.
+* Feb 19, 2016: [Rebalanced compression levels](https://blog.klauspost.com/rebalancing-deflate-compression-levels/), so there is a more even progression in terms of compression. New default level is 5.
+* Feb 14, 2016: Snappy: Merge upstream changes.
+* Feb 14, 2016: Snappy: Fix aggressive skipping.
+* Feb 14, 2016: Snappy: Update benchmark.
+* Feb 13, 2016: Deflate: Fixed assembler problem that could lead to sub-optimal compression.
+* Feb 12, 2016: Snappy: Added AMD64 SSE 4.2 optimizations to matching, which makes easy to compress material run faster. Typical speedup is around 25%.
+* Feb 9, 2016: Added Snappy package fork. This version is 5-7% faster, much more on hard to compress content.
+* Jan 30, 2016: Optimize level 1 to 3 by not considering static dictionary or storing uncompressed. ~4-5% speedup.
+* Jan 16, 2016: Optimization on deflate level 1,2,3 compression.
+* Jan 8 2016: Merge [CL 18317](https://go-review.googlesource.com/#/c/18317): fix reading, writing of zip64 archives.
+* Dec 8 2015: Make level 1 and -2 deterministic even if write size differs.
+* Dec 8 2015: Split encoding functions, so hashing and matching can potentially be inlined. 1-3% faster on AMD64. 5% faster on other platforms.
+* Dec 8 2015: Fixed rare [one byte out-of bounds read](https://github.com/klauspost/compress/issues/20). Please update!
+* Nov 23 2015: Optimization on token writer. ~2-4% faster. Contributed by [@dsnet](https://github.com/dsnet).
+* Nov 20 2015: Small optimization to bit writer on 64 bit systems.
+* Nov 17 2015: Fixed out-of-bound errors if the underlying Writer returned an error. See [#15](https://github.com/klauspost/compress/issues/15).
+* Nov 12 2015: Added [io.WriterTo](https://golang.org/pkg/io/#WriterTo) support to gzip/inflate.
+* Nov 11 2015: Merged [CL 16669](https://go-review.googlesource.com/#/c/16669/4): archive/zip: enable overriding (de)compressors per file
+* Oct 15 2015: Added skipping on uncompressible data. Random data speed up >5x.
+
+
+
+# deflate usage
+
+The packages are drop-in replacements for standard library [deflate](https://godoc.org/github.com/klauspost/compress/flate), [gzip](https://godoc.org/github.com/klauspost/compress/gzip), [zip](https://godoc.org/github.com/klauspost/compress/zip), and [zlib](https://godoc.org/github.com/klauspost/compress/zlib). Simply replace the import path to use them:
+
+Typical speed is about 2x of the standard library packages.
+
+| old import | new import | Documentation |
+|------------------|---------------------------------------|-------------------------------------------------------------------------|
+| `compress/gzip` | `github.com/klauspost/compress/gzip` | [gzip](https://pkg.go.dev/github.com/klauspost/compress/gzip?tab=doc) |
+| `compress/zlib` | `github.com/klauspost/compress/zlib` | [zlib](https://pkg.go.dev/github.com/klauspost/compress/zlib?tab=doc) |
+| `archive/zip` | `github.com/klauspost/compress/zip` | [zip](https://pkg.go.dev/github.com/klauspost/compress/zip?tab=doc) |
+| `compress/flate` | `github.com/klauspost/compress/flate` | [flate](https://pkg.go.dev/github.com/klauspost/compress/flate?tab=doc) |
+
+You may also be interested in [pgzip](https://github.com/klauspost/pgzip), which is a drop-in replacement for gzip, which support multithreaded compression on big files and the optimized [crc32](https://github.com/klauspost/crc32) package used by these packages.
+
+The packages implement the same API as the standard library, so you can use the original godoc documentation: [gzip](http://golang.org/pkg/compress/gzip/), [zip](http://golang.org/pkg/archive/zip/), [zlib](http://golang.org/pkg/compress/zlib/), [flate](http://golang.org/pkg/compress/flate/).
+
+Currently there is only minor speedup on decompression (mostly CRC32 calculation).
+
+Memory usage is typically 1MB for a Writer. stdlib is in the same range.
+If you expect to have a lot of concurrently allocated Writers consider using
+the stateless compression described below.
+
+For compression performance, see: [this spreadsheet](https://docs.google.com/spreadsheets/d/1nuNE2nPfuINCZJRMt6wFWhKpToF95I47XjSsc-1rbPQ/edit?usp=sharing).
+
+To disable all assembly add `-tags=noasm`. This works across all packages.
+
+# Stateless compression
+
+This package offers stateless compression as a special option for gzip/deflate.
+It will do compression but without maintaining any state between Write calls.
+
+This means there will be no memory kept between Write calls, but compression and speed will be suboptimal.
+
+This is only relevant in cases where you expect to run many thousands of compressors concurrently,
+but with very little activity. This is *not* intended for regular web servers serving individual requests.
+
+Because of this, the size of actual Write calls will affect output size.
+
+In gzip, specify level `-3` / `gzip.StatelessCompression` to enable.
+
+For direct deflate use, NewStatelessWriter and StatelessDeflate are available. See [documentation](https://godoc.org/github.com/klauspost/compress/flate#NewStatelessWriter)
+
+A `bufio.Writer` can of course be used to control write sizes. For example, to use a 4KB buffer:
+
+```go
+ // replace 'ioutil.Discard' with your output.
+ gzw, err := gzip.NewWriterLevel(ioutil.Discard, gzip.StatelessCompression)
+ if err != nil {
+ return err
+ }
+ defer gzw.Close()
+
+ w := bufio.NewWriterSize(gzw, 4096)
+ defer w.Flush()
+
+ // Write to 'w'
+```
+
+This will only use up to 4KB in memory when the writer is idle.
+
+Compression is almost always worse than the fastest compression level
+and each write will allocate (a little) memory.
+
+
+# Other packages
+
+Here are other packages of good quality and pure Go (no cgo wrappers or autoconverted code):
+
+* [github.com/pierrec/lz4](https://github.com/pierrec/lz4) - strong multithreaded LZ4 compression.
+* [github.com/cosnicolaou/pbzip2](https://github.com/cosnicolaou/pbzip2) - multithreaded bzip2 decompression.
+* [github.com/dsnet/compress](https://github.com/dsnet/compress) - brotli decompression, bzip2 writer.
+* [github.com/ronanh/intcomp](https://github.com/ronanh/intcomp) - Integer compression.
+* [github.com/spenczar/fpc](https://github.com/spenczar/fpc) - Float compression.
+* [github.com/minio/zipindex](https://github.com/minio/zipindex) - External ZIP directory index.
+* [github.com/ybirader/pzip](https://github.com/ybirader/pzip) - Fast concurrent zip archiver and extractor.
+
+# license
+
+This code is licensed under the same conditions as the original Go code. See LICENSE file.
+
+
+
+
+
diff --git a/vendor/github.com/klauspost/compress/fse/README.md b/vendor/github.com/klauspost/compress/fse/README.md
index ea7324da..27d8ed56 100644
--- a/vendor/github.com/klauspost/compress/fse/README.md
+++ b/vendor/github.com/klauspost/compress/fse/README.md
@@ -1,79 +1,79 @@
-# Finite State Entropy
-
-This package provides Finite State Entropy encoding and decoding.
-
-Finite State Entropy (also referenced as [tANS](https://en.wikipedia.org/wiki/Asymmetric_numeral_systems#tANS))
-encoding provides a fast near-optimal symbol encoding/decoding
-for byte blocks as implemented in [zstandard](https://github.com/facebook/zstd).
-
-This can be used for compressing input with a lot of similar input values to the smallest number of bytes.
-This does not perform any multi-byte [dictionary coding](https://en.wikipedia.org/wiki/Dictionary_coder) as LZ coders,
-but it can be used as a secondary step to compressors (like Snappy) that does not do entropy encoding.
-
-* [Godoc documentation](https://godoc.org/github.com/klauspost/compress/fse)
-
-## News
-
- * Feb 2018: First implementation released. Consider this beta software for now.
-
-# Usage
-
-This package provides a low level interface that allows to compress single independent blocks.
-
-Each block is separate, and there is no built in integrity checks.
-This means that the caller should keep track of block sizes and also do checksums if needed.
-
-Compressing a block is done via the [`Compress`](https://godoc.org/github.com/klauspost/compress/fse#Compress) function.
-You must provide input and will receive the output and maybe an error.
-
-These error values can be returned:
-
-| Error | Description |
-|---------------------|-----------------------------------------------------------------------------|
-| `` | Everything ok, output is returned |
-| `ErrIncompressible` | Returned when input is judged to be too hard to compress |
-| `ErrUseRLE` | Returned from the compressor when the input is a single byte value repeated |
-| `(error)` | An internal error occurred. |
-
-As can be seen above there are errors that will be returned even under normal operation so it is important to handle these.
-
-To reduce allocations you can provide a [`Scratch`](https://godoc.org/github.com/klauspost/compress/fse#Scratch) object
-that can be re-used for successive calls. Both compression and decompression accepts a `Scratch` object, and the same
-object can be used for both.
-
-Be aware, that when re-using a `Scratch` object that the *output* buffer is also re-used, so if you are still using this
-you must set the `Out` field in the scratch to nil. The same buffer is used for compression and decompression output.
-
-Decompressing is done by calling the [`Decompress`](https://godoc.org/github.com/klauspost/compress/fse#Decompress) function.
-You must provide the output from the compression stage, at exactly the size you got back. If you receive an error back
-your input was likely corrupted.
-
-It is important to note that a successful decoding does *not* mean your output matches your original input.
-There are no integrity checks, so relying on errors from the decompressor does not assure your data is valid.
-
-For more detailed usage, see examples in the [godoc documentation](https://godoc.org/github.com/klauspost/compress/fse#pkg-examples).
-
-# Performance
-
-A lot of factors are affecting speed. Block sizes and compressibility of the material are primary factors.
-All compression functions are currently only running on the calling goroutine so only one core will be used per block.
-
-The compressor is significantly faster if symbols are kept as small as possible. The highest byte value of the input
-is used to reduce some of the processing, so if all your input is above byte value 64 for instance, it may be
-beneficial to transpose all your input values down by 64.
-
-With moderate block sizes around 64k speed are typically 200MB/s per core for compression and
-around 300MB/s decompression speed.
-
-The same hardware typically does Huffman (deflate) encoding at 125MB/s and decompression at 100MB/s.
-
-# Plans
-
-At one point, more internals will be exposed to facilitate more "expert" usage of the components.
-
-A streaming interface is also likely to be implemented. Likely compatible with [FSE stream format](https://github.com/Cyan4973/FiniteStateEntropy/blob/dev/programs/fileio.c#L261).
-
-# Contributing
-
-Contributions are always welcome. Be aware that adding public functions will require good justification and breaking
+# Finite State Entropy
+
+This package provides Finite State Entropy encoding and decoding.
+
+Finite State Entropy (also referenced as [tANS](https://en.wikipedia.org/wiki/Asymmetric_numeral_systems#tANS))
+encoding provides a fast near-optimal symbol encoding/decoding
+for byte blocks as implemented in [zstandard](https://github.com/facebook/zstd).
+
+This can be used for compressing input with a lot of similar input values to the smallest number of bytes.
+This does not perform any multi-byte [dictionary coding](https://en.wikipedia.org/wiki/Dictionary_coder) as LZ coders,
+but it can be used as a secondary step to compressors (like Snappy) that does not do entropy encoding.
+
+* [Godoc documentation](https://godoc.org/github.com/klauspost/compress/fse)
+
+## News
+
+ * Feb 2018: First implementation released. Consider this beta software for now.
+
+# Usage
+
+This package provides a low level interface that allows to compress single independent blocks.
+
+Each block is separate, and there is no built in integrity checks.
+This means that the caller should keep track of block sizes and also do checksums if needed.
+
+Compressing a block is done via the [`Compress`](https://godoc.org/github.com/klauspost/compress/fse#Compress) function.
+You must provide input and will receive the output and maybe an error.
+
+These error values can be returned:
+
+| Error | Description |
+|---------------------|-----------------------------------------------------------------------------|
+| `` | Everything ok, output is returned |
+| `ErrIncompressible` | Returned when input is judged to be too hard to compress |
+| `ErrUseRLE` | Returned from the compressor when the input is a single byte value repeated |
+| `(error)` | An internal error occurred. |
+
+As can be seen above there are errors that will be returned even under normal operation so it is important to handle these.
+
+To reduce allocations you can provide a [`Scratch`](https://godoc.org/github.com/klauspost/compress/fse#Scratch) object
+that can be re-used for successive calls. Both compression and decompression accepts a `Scratch` object, and the same
+object can be used for both.
+
+Be aware, that when re-using a `Scratch` object that the *output* buffer is also re-used, so if you are still using this
+you must set the `Out` field in the scratch to nil. The same buffer is used for compression and decompression output.
+
+Decompressing is done by calling the [`Decompress`](https://godoc.org/github.com/klauspost/compress/fse#Decompress) function.
+You must provide the output from the compression stage, at exactly the size you got back. If you receive an error back
+your input was likely corrupted.
+
+It is important to note that a successful decoding does *not* mean your output matches your original input.
+There are no integrity checks, so relying on errors from the decompressor does not assure your data is valid.
+
+For more detailed usage, see examples in the [godoc documentation](https://godoc.org/github.com/klauspost/compress/fse#pkg-examples).
+
+# Performance
+
+A lot of factors are affecting speed. Block sizes and compressibility of the material are primary factors.
+All compression functions are currently only running on the calling goroutine so only one core will be used per block.
+
+The compressor is significantly faster if symbols are kept as small as possible. The highest byte value of the input
+is used to reduce some of the processing, so if all your input is above byte value 64 for instance, it may be
+beneficial to transpose all your input values down by 64.
+
+With moderate block sizes around 64k speed are typically 200MB/s per core for compression and
+around 300MB/s decompression speed.
+
+The same hardware typically does Huffman (deflate) encoding at 125MB/s and decompression at 100MB/s.
+
+# Plans
+
+At one point, more internals will be exposed to facilitate more "expert" usage of the components.
+
+A streaming interface is also likely to be implemented. Likely compatible with [FSE stream format](https://github.com/Cyan4973/FiniteStateEntropy/blob/dev/programs/fileio.c#L261).
+
+# Contributing
+
+Contributions are always welcome. Be aware that adding public functions will require good justification and breaking
changes will likely not be accepted. If in doubt open an issue before writing the PR.
\ No newline at end of file
diff --git a/vendor/github.com/klauspost/compress/huff0/README.md b/vendor/github.com/klauspost/compress/huff0/README.md
index 8b6e5c66..26d5101b 100644
--- a/vendor/github.com/klauspost/compress/huff0/README.md
+++ b/vendor/github.com/klauspost/compress/huff0/README.md
@@ -1,89 +1,89 @@
-# Huff0 entropy compression
-
-This package provides Huff0 encoding and decoding as used in zstd.
-
-[Huff0](https://github.com/Cyan4973/FiniteStateEntropy#new-generation-entropy-coders),
-a Huffman codec designed for modern CPU, featuring OoO (Out of Order) operations on multiple ALU
-(Arithmetic Logic Unit), achieving extremely fast compression and decompression speeds.
-
-This can be used for compressing input with a lot of similar input values to the smallest number of bytes.
-This does not perform any multi-byte [dictionary coding](https://en.wikipedia.org/wiki/Dictionary_coder) as LZ coders,
-but it can be used as a secondary step to compressors (like Snappy) that does not do entropy encoding.
-
-* [Godoc documentation](https://godoc.org/github.com/klauspost/compress/huff0)
-
-## News
-
-This is used as part of the [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and decompression package.
-
-This ensures that most functionality is well tested.
-
-# Usage
-
-This package provides a low level interface that allows to compress single independent blocks.
-
-Each block is separate, and there is no built in integrity checks.
-This means that the caller should keep track of block sizes and also do checksums if needed.
-
-Compressing a block is done via the [`Compress1X`](https://godoc.org/github.com/klauspost/compress/huff0#Compress1X) and
-[`Compress4X`](https://godoc.org/github.com/klauspost/compress/huff0#Compress4X) functions.
-You must provide input and will receive the output and maybe an error.
-
-These error values can be returned:
-
-| Error | Description |
-|---------------------|-----------------------------------------------------------------------------|
-| `` | Everything ok, output is returned |
-| `ErrIncompressible` | Returned when input is judged to be too hard to compress |
-| `ErrUseRLE` | Returned from the compressor when the input is a single byte value repeated |
-| `ErrTooBig` | Returned if the input block exceeds the maximum allowed size (128 Kib) |
-| `(error)` | An internal error occurred. |
-
-
-As can be seen above some of there are errors that will be returned even under normal operation so it is important to handle these.
-
-To reduce allocations you can provide a [`Scratch`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch) object
-that can be re-used for successive calls. Both compression and decompression accepts a `Scratch` object, and the same
-object can be used for both.
-
-Be aware, that when re-using a `Scratch` object that the *output* buffer is also re-used, so if you are still using this
-you must set the `Out` field in the scratch to nil. The same buffer is used for compression and decompression output.
-
-The `Scratch` object will retain state that allows to re-use previous tables for encoding and decoding.
-
-## Tables and re-use
-
-Huff0 allows for reusing tables from the previous block to save space if that is expected to give better/faster results.
-
-The Scratch object allows you to set a [`ReusePolicy`](https://godoc.org/github.com/klauspost/compress/huff0#ReusePolicy)
-that controls this behaviour. See the documentation for details. This can be altered between each block.
-
-Do however note that this information is *not* stored in the output block and it is up to the users of the package to
-record whether [`ReadTable`](https://godoc.org/github.com/klauspost/compress/huff0#ReadTable) should be called,
-based on the boolean reported back from the CompressXX call.
-
-If you want to store the table separate from the data, you can access them as `OutData` and `OutTable` on the
-[`Scratch`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch) object.
-
-## Decompressing
-
-The first part of decoding is to initialize the decoding table through [`ReadTable`](https://godoc.org/github.com/klauspost/compress/huff0#ReadTable).
-This will initialize the decoding tables.
-You can supply the complete block to `ReadTable` and it will return the data part of the block
-which can be given to the decompressor.
-
-Decompressing is done by calling the [`Decompress1X`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch.Decompress1X)
-or [`Decompress4X`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch.Decompress4X) function.
-
-For concurrently decompressing content with a fixed table a stateless [`Decoder`](https://godoc.org/github.com/klauspost/compress/huff0#Decoder) can be requested which will remain correct as long as the scratch is unchanged. The capacity of the provided slice indicates the expected output size.
-
-You must provide the output from the compression stage, at exactly the size you got back. If you receive an error back
-your input was likely corrupted.
-
-It is important to note that a successful decoding does *not* mean your output matches your original input.
-There are no integrity checks, so relying on errors from the decompressor does not assure your data is valid.
-
-# Contributing
-
-Contributions are always welcome. Be aware that adding public functions will require good justification and breaking
-changes will likely not be accepted. If in doubt open an issue before writing the PR.
+# Huff0 entropy compression
+
+This package provides Huff0 encoding and decoding as used in zstd.
+
+[Huff0](https://github.com/Cyan4973/FiniteStateEntropy#new-generation-entropy-coders),
+a Huffman codec designed for modern CPU, featuring OoO (Out of Order) operations on multiple ALU
+(Arithmetic Logic Unit), achieving extremely fast compression and decompression speeds.
+
+This can be used for compressing input with a lot of similar input values to the smallest number of bytes.
+This does not perform any multi-byte [dictionary coding](https://en.wikipedia.org/wiki/Dictionary_coder) as LZ coders,
+but it can be used as a secondary step to compressors (like Snappy) that does not do entropy encoding.
+
+* [Godoc documentation](https://godoc.org/github.com/klauspost/compress/huff0)
+
+## News
+
+This is used as part of the [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and decompression package.
+
+This ensures that most functionality is well tested.
+
+# Usage
+
+This package provides a low level interface that allows to compress single independent blocks.
+
+Each block is separate, and there is no built in integrity checks.
+This means that the caller should keep track of block sizes and also do checksums if needed.
+
+Compressing a block is done via the [`Compress1X`](https://godoc.org/github.com/klauspost/compress/huff0#Compress1X) and
+[`Compress4X`](https://godoc.org/github.com/klauspost/compress/huff0#Compress4X) functions.
+You must provide input and will receive the output and maybe an error.
+
+These error values can be returned:
+
+| Error | Description |
+|---------------------|-----------------------------------------------------------------------------|
+| `` | Everything ok, output is returned |
+| `ErrIncompressible` | Returned when input is judged to be too hard to compress |
+| `ErrUseRLE` | Returned from the compressor when the input is a single byte value repeated |
+| `ErrTooBig` | Returned if the input block exceeds the maximum allowed size (128 Kib) |
+| `(error)` | An internal error occurred. |
+
+
+As can be seen above some of there are errors that will be returned even under normal operation so it is important to handle these.
+
+To reduce allocations you can provide a [`Scratch`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch) object
+that can be re-used for successive calls. Both compression and decompression accepts a `Scratch` object, and the same
+object can be used for both.
+
+Be aware, that when re-using a `Scratch` object that the *output* buffer is also re-used, so if you are still using this
+you must set the `Out` field in the scratch to nil. The same buffer is used for compression and decompression output.
+
+The `Scratch` object will retain state that allows to re-use previous tables for encoding and decoding.
+
+## Tables and re-use
+
+Huff0 allows for reusing tables from the previous block to save space if that is expected to give better/faster results.
+
+The Scratch object allows you to set a [`ReusePolicy`](https://godoc.org/github.com/klauspost/compress/huff0#ReusePolicy)
+that controls this behaviour. See the documentation for details. This can be altered between each block.
+
+Do however note that this information is *not* stored in the output block and it is up to the users of the package to
+record whether [`ReadTable`](https://godoc.org/github.com/klauspost/compress/huff0#ReadTable) should be called,
+based on the boolean reported back from the CompressXX call.
+
+If you want to store the table separate from the data, you can access them as `OutData` and `OutTable` on the
+[`Scratch`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch) object.
+
+## Decompressing
+
+The first part of decoding is to initialize the decoding table through [`ReadTable`](https://godoc.org/github.com/klauspost/compress/huff0#ReadTable).
+This will initialize the decoding tables.
+You can supply the complete block to `ReadTable` and it will return the data part of the block
+which can be given to the decompressor.
+
+Decompressing is done by calling the [`Decompress1X`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch.Decompress1X)
+or [`Decompress4X`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch.Decompress4X) function.
+
+For concurrently decompressing content with a fixed table a stateless [`Decoder`](https://godoc.org/github.com/klauspost/compress/huff0#Decoder) can be requested which will remain correct as long as the scratch is unchanged. The capacity of the provided slice indicates the expected output size.
+
+You must provide the output from the compression stage, at exactly the size you got back. If you receive an error back
+your input was likely corrupted.
+
+It is important to note that a successful decoding does *not* mean your output matches your original input.
+There are no integrity checks, so relying on errors from the decompressor does not assure your data is valid.
+
+# Contributing
+
+Contributions are always welcome. Be aware that adding public functions will require good justification and breaking
+changes will likely not be accepted. If in doubt open an issue before writing the PR.
diff --git a/vendor/github.com/klauspost/compress/huff0/build_table.go b/vendor/github.com/klauspost/compress/huff0/build_table.go
new file mode 100644
index 00000000..e3757c87
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/build_table.go
@@ -0,0 +1,168 @@
+package huff0
+
+import "errors"
+
+// BuildCTable builds a Huffman compression table from a precomputed symbol
+// histogram and installs it as the previous (reuse) table on s.
+//
+// After this call:
+// - EstimateSize/CanUseTable can probe the table against other histograms.
+// - Compress1X/Compress4X with Reuse = ReusePolicyMust will encode without
+// emitting a new table header.
+// - TransferCTable can hand the table to a sibling Scratch.
+//
+// count[i] is the number of occurrences of symbol i. The histogram must have
+// at least 2 distinct non-zero symbols; ErrUseRLE is returned for a single
+// symbol and an error is returned for an empty histogram.
+func (s *Scratch) BuildCTable(count *[256]uint32) error {
+ if s == nil {
+ return errors.New("huff0: BuildCTable on nil Scratch")
+ }
+ if count == nil {
+ return errors.New("huff0: nil count passed to BuildCTable")
+ }
+ var err error
+ s, err = s.prepare(nil)
+ if err != nil {
+ return err
+ }
+ s.count = *count
+ var total, maxCount int
+ var symLen uint16
+ for i, v := range s.count {
+ total += int(v)
+ if int(v) > maxCount {
+ maxCount = int(v)
+ }
+ if v != 0 {
+ symLen = uint16(i) + 1
+ }
+ }
+ if total == 0 {
+ return errors.New("huff0: empty histogram")
+ }
+ if symLen < 2 || maxCount == total {
+ return ErrUseRLE
+ }
+ // huff0's internal rank table assumes total ≤ BlockSizeMax (it uses
+ // highBit32(count+1) + 1 as a rank index into a fixed-size array).
+ // Histograms summed across multiple blocks can exceed that; scale the
+ // counts down preserving the distribution. Non-zero entries round up so
+ // rare symbols stay representable.
+ if total > BlockSizeMax {
+ shift := uint(0)
+ for total>>shift > BlockSizeMax {
+ shift++
+ }
+ round := uint32(1<> shift
+ if scaled == 0 {
+ scaled = 1
+ }
+ s.count[i] = scaled
+ newTotal += int(scaled)
+ if int(scaled) > newMax {
+ newMax = int(scaled)
+ }
+ }
+ total = newTotal
+ maxCount = newMax
+ if maxCount == total {
+ return ErrUseRLE
+ }
+ }
+ s.symbolLen = symLen
+ s.maxCount = maxCount
+ s.srcLen = total
+ if err := s.buildCTable(); err != nil {
+ return err
+ }
+ if cap(s.prevTable) < len(s.cTable) {
+ s.prevTable = make(cTable, 0, maxSymbolValue+1)
+ }
+ s.prevTable = s.prevTable[:len(s.cTable)]
+ copy(s.prevTable, s.cTable)
+ s.prevTableLog = s.actualTableLog
+ // Force the next Compress* to recount from real input.
+ s.clearCount = true
+ s.maxCount = 0
+ return nil
+}
+
+// EstimateSize returns an estimated compressed payload size in bytes for the
+// supplied histogram using the table currently stored in prevTable. It returns
+// -1 when the table cannot encode every non-zero symbol of hist (i.e. when
+// CanUseTable would return false). The estimate excludes the table header.
+func (s *Scratch) EstimateSize(hist *[256]uint32) int {
+ if s == nil || hist == nil || len(s.prevTable) == 0 {
+ return -1
+ }
+ pt := s.prevTable
+ nbBits := uint32(7)
+ for i, v := range hist {
+ if v == 0 {
+ continue
+ }
+ if i >= len(pt) || pt[i].nBits == 0 {
+ return -1
+ }
+ nbBits += uint32(pt[i].nBits) * v
+ }
+ return int(nbBits >> 3)
+}
+
+// CanUseTable reports whether the table in prevTable can encode every
+// non-zero symbol present in hist.
+func (s *Scratch) CanUseTable(hist *[256]uint32) bool {
+ if s == nil || hist == nil || len(s.prevTable) == 0 {
+ return false
+ }
+ pt := s.prevTable
+ for i, v := range hist {
+ if v == 0 {
+ continue
+ }
+ if i >= len(pt) || pt[i].nBits == 0 {
+ return false
+ }
+ }
+ return true
+}
+
+// AppendTable serializes the table currently stored in prevTable (e.g. as
+// installed by BuildCTable or carried over from a previous Compress call)
+// into a self-delimiting zstd-style header and appends it to dst. The
+// returned slice can be parsed back by ReadTable.
+func (s *Scratch) AppendTable(dst []byte) ([]byte, error) {
+ if s == nil || len(s.prevTable) == 0 {
+ return dst, errors.New("huff0: AppendTable with empty table")
+ }
+ // cTable.write reads s.actualTableLog, s.symbolLen, s.huffWeight, s.fse
+ // and writes into s.Out. Save/restore Out so we don't disturb in-flight
+ // compression buffers.
+ saveOut := s.Out
+ saveTL := s.actualTableLog
+ saveSL := s.symbolLen
+ if s.fse == nil {
+ // Lazily init in case AppendTable is called on a fresh Scratch.
+ if _, err := s.prepare(nil); err != nil {
+ return dst, err
+ }
+ saveOut = s.Out
+ }
+ s.Out = s.Out[:0]
+ s.actualTableLog = s.prevTableLog
+ s.symbolLen = uint16(len(s.prevTable))
+ if err := s.prevTable.write(s); err != nil {
+ s.Out, s.actualTableLog, s.symbolLen = saveOut, saveTL, saveSL
+ return dst, err
+ }
+ dst = append(dst, s.Out...)
+ s.Out, s.actualTableLog, s.symbolLen = saveOut, saveTL, saveSL
+ return dst, nil
+}
diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go
index 99ddd4af..7035d656 100644
--- a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go
+++ b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go
@@ -1,223 +1,49 @@
//go:build amd64 && !appengine && !noasm && gc
-// +build amd64,!appengine,!noasm,gc
-// This file contains the specialisation of Decoder.Decompress4X
-// and Decoder.Decompress1X that use an asm implementation of thir main loops.
+// amd64 stubs and dispatch for the asm loops used by decompress_asm.go.
package huff0
import (
- "errors"
- "fmt"
-
"github.com/klauspost/compress/internal/cpuinfo"
)
-// decompress4x_main_loop_x86 is an x86 assembler implementation
+// decompress4x_main_loop_amd64 is an x86 assembler implementation
// of Decompress4X when tablelog > 8.
//
//go:noescape
func decompress4x_main_loop_amd64(ctx *decompress4xContext)
-// decompress4x_8b_loop_x86 is an x86 assembler implementation
+// decompress4x_8b_main_loop_amd64 is an x86 assembler implementation
// of Decompress4X when tablelog <= 8 which decodes 4 entries
// per loop.
//
//go:noescape
func decompress4x_8b_main_loop_amd64(ctx *decompress4xContext)
-// fallback8BitSize is the size where using Go version is faster.
-const fallback8BitSize = 800
-
-type decompress4xContext struct {
- pbr *[4]bitReaderShifted
- peekBits uint8
- out *byte
- dstEvery int
- tbl *dEntrySingle
- decoded int
- limit *byte
-}
-
-// Decompress4X will decompress a 4X encoded stream.
-// The length of the supplied input must match the end of a block exactly.
-// The *capacity* of the dst slice must match the destination size of
-// the uncompressed data exactly.
-func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) {
- if len(d.dt.single) == 0 {
- return nil, errors.New("no table loaded")
- }
- if len(src) < 6+(4*1) {
- return nil, errors.New("input too small")
- }
-
- use8BitTables := d.actualTableLog <= 8
- if cap(dst) < fallback8BitSize && use8BitTables {
- return d.decompress4X8bit(dst, src)
- }
-
- var br [4]bitReaderShifted
- // Decode "jump table"
- start := 6
- 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)")
- }
- err := br[i].init(src[start : start+length])
- if err != nil {
- return nil, err
- }
- start += length
- }
- err := br[3].init(src[start:])
- if err != nil {
- return nil, err
- }
-
- // destination, offset to match first output
- dstSize := cap(dst)
- dst = dst[:dstSize]
- out := dst
- dstEvery := (dstSize + 3) / 4
-
- const tlSize = 1 << tableLogMax
- const tlMask = tlSize - 1
- single := d.dt.single[:tlSize]
-
- var decoded int
-
- if len(out) > 4*4 && !(br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4) {
- ctx := decompress4xContext{
- pbr: &br,
- peekBits: uint8((64 - d.actualTableLog) & 63), // see: bitReaderShifted.peekBitsFast()
- out: &out[0],
- dstEvery: dstEvery,
- tbl: &single[0],
- limit: &out[dstEvery-4], // Always stop decoding when first buffer gets here to avoid writing OOB on last.
- }
- if use8BitTables {
- decompress4x_8b_main_loop_amd64(&ctx)
- } else {
- decompress4x_main_loop_amd64(&ctx)
- }
-
- decoded = ctx.decoded
- out = out[decoded/4:]
- }
-
- // Decode remaining.
- remainBytes := dstEvery - (decoded / 4)
- for i := range br {
- offset := dstEvery * i
- endsAt := min(offset+remainBytes, len(out))
- br := &br[i]
- bitsLeft := br.remaining()
- for bitsLeft > 0 {
- br.fill()
- if offset >= endsAt {
- return nil, errors.New("corruption detected: stream overrun 4")
- }
-
- // Read value and increment offset.
- val := br.peekBitsFast(d.actualTableLog)
- v := single[val&tlMask].entry
- nBits := uint8(v)
- br.advance(nBits)
- bitsLeft -= uint(nBits)
- out[offset] = uint8(v >> 8)
- offset++
- }
- if offset != endsAt {
- return nil, fmt.Errorf("corruption detected: short output block %d, end %d != %d", i, offset, endsAt)
- }
- decoded += offset - dstEvery*i
- err = br.close()
- if err != nil {
- return nil, err
- }
- }
- if dstSize != decoded {
- return nil, errors.New("corruption detected: short output block")
- }
- return dst, nil
-}
-
-// decompress4x_main_loop_x86 is an x86 assembler implementation
+// decompress1x_main_loop_amd64 is an x86 assembler implementation
// of Decompress1X when tablelog > 8.
//
//go:noescape
func decompress1x_main_loop_amd64(ctx *decompress1xContext)
-// decompress4x_main_loop_x86 is an x86 with BMI2 assembler implementation
+// decompress1x_main_loop_bmi2 is an x86 with BMI2 assembler implementation
// of Decompress1X when tablelog > 8.
//
//go:noescape
func decompress1x_main_loop_bmi2(ctx *decompress1xContext)
-type decompress1xContext struct {
- pbr *bitReaderShifted
- peekBits uint8
- out *byte
- outCap int
- tbl *dEntrySingle
- decoded int
+func decompress4x_main_loop_asm(ctx *decompress4xContext) {
+ decompress4x_main_loop_amd64(ctx)
}
-// Error reported by asm implementations
-const error_max_decoded_size_exeeded = -1
-
-// Decompress1X will decompress a 1X encoded stream.
-// The cap of the output buffer will be the maximum decompressed size.
-// The length of the supplied input must match the end of a block exactly.
-func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) {
- if len(d.dt.single) == 0 {
- return nil, errors.New("no table loaded")
- }
- var br bitReaderShifted
- err := br.init(src)
- if err != nil {
- return dst, err
- }
- maxDecodedSize := cap(dst)
- dst = dst[:maxDecodedSize]
-
- const tlSize = 1 << tableLogMax
- const tlMask = tlSize - 1
-
- if maxDecodedSize >= 4 {
- ctx := decompress1xContext{
- pbr: &br,
- out: &dst[0],
- outCap: maxDecodedSize,
- peekBits: uint8((64 - d.actualTableLog) & 63), // see: bitReaderShifted.peekBitsFast()
- tbl: &d.dt.single[0],
- }
-
- if cpuinfo.HasBMI2() {
- decompress1x_main_loop_bmi2(&ctx)
- } else {
- decompress1x_main_loop_amd64(&ctx)
- }
- if ctx.decoded == error_max_decoded_size_exeeded {
- return nil, ErrMaxDecodedSizeExceeded
- }
-
- dst = dst[:ctx.decoded]
- }
+func decompress4x_8b_main_loop_asm(ctx *decompress4xContext) {
+ decompress4x_8b_main_loop_amd64(ctx)
+}
- // br < 8, so uint8 is fine
- bitsLeft := uint8(br.off)*8 + 64 - br.bitsRead
- for bitsLeft > 0 {
- br.fill()
- if len(dst) >= maxDecodedSize {
- br.close()
- return nil, ErrMaxDecodedSizeExceeded
- }
- v := d.dt.single[br.peekBitsFast(d.actualTableLog)&tlMask]
- nBits := uint8(v.entry)
- br.advance(nBits)
- bitsLeft -= nBits
- dst = append(dst, uint8(v.entry>>8))
+func decompress1x_main_loop_asm(ctx *decompress1xContext) {
+ if cpuinfo.HasBMI2() {
+ decompress1x_main_loop_bmi2(ctx)
+ } else {
+ decompress1x_main_loop_amd64(ctx)
}
- return dst, br.close()
}
diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s
index c4c7ab2d..c5d4a710 100644
--- a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s
+++ b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s
@@ -1,6 +1,6 @@
-// Code generated by command: go run gen.go -out ../decompress_amd64.s -pkg=huff0. DO NOT EDIT.
+// Code generated by command: go run gen.go -out ../decompress.s -arch amd64,arm64 -pkg=huff0. DO NOT EDIT.
-//go:build amd64 && !appengine && !noasm && gc
+//go:build !appengine && !noasm && gc
// func decompress4x_main_loop_amd64(ctx *decompress4xContext)
TEXT ·decompress4x_main_loop_amd64(SB), $0-8
diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_arm64.go b/vendor/github.com/klauspost/compress/huff0/decompress_arm64.go
new file mode 100644
index 00000000..8ba3c810
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/decompress_arm64.go
@@ -0,0 +1,37 @@
+//go:build arm64 && !appengine && !noasm && gc
+
+// arm64 stubs and dispatch for the asm loops used by decompress_asm.go.
+// The asm (decompress_arm64.s) is generated by the avo arm64 lowering
+// printer from the same source as the amd64 asm; see _generate/gen.go.
+package huff0
+
+// decompress4x_main_loop_arm64 is an arm64 assembler implementation
+// of Decompress4X when tablelog > 8.
+//
+//go:noescape
+func decompress4x_main_loop_arm64(ctx *decompress4xContext)
+
+// decompress4x_8b_main_loop_arm64 is an arm64 assembler implementation
+// of Decompress4X when tablelog <= 8 which decodes 4 entries
+// per loop.
+//
+//go:noescape
+func decompress4x_8b_main_loop_arm64(ctx *decompress4xContext)
+
+// decompress1x_main_loop_arm64 is an arm64 assembler implementation
+// of Decompress1X when tablelog > 8.
+//
+//go:noescape
+func decompress1x_main_loop_arm64(ctx *decompress1xContext)
+
+func decompress4x_main_loop_asm(ctx *decompress4xContext) {
+ decompress4x_main_loop_arm64(ctx)
+}
+
+func decompress4x_8b_main_loop_asm(ctx *decompress4xContext) {
+ decompress4x_8b_main_loop_arm64(ctx)
+}
+
+func decompress1x_main_loop_asm(ctx *decompress1xContext) {
+ decompress1x_main_loop_arm64(ctx)
+}
diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_arm64.s b/vendor/github.com/klauspost/compress/huff0/decompress_arm64.s
new file mode 100644
index 00000000..e1601272
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/decompress_arm64.s
@@ -0,0 +1,851 @@
+// Code generated by command: go run gen.go -out ../decompress.s -arch amd64,arm64 -pkg=huff0. DO NOT EDIT.
+// EXPERIMENTAL arm64 output lowered from an amd64 avo program.
+
+//go:build arm64 && !appengine && !noasm && gc
+
+// func decompress4x_main_loop_amd64(ctx *decompress4xContext)
+TEXT ·decompress4x_main_loop_arm64(SB), $0-8
+ // Preload values
+ MOVD ctx+0(FP), R0
+ MOVBU 8(R0), R6
+ MOVD 16(R0), R3
+ MOVD 48(R0), R5
+ MOVD 24(R0), R7
+ MOVD 32(R0), R8
+ MOVD (R0), R9
+
+ // Main loop
+main_loop:
+ MOVD $0, R2
+ CMP R5, R3
+ CSET GE, R16
+ BFI $0, R16, $8, R2
+
+ // br0.fillFast32()
+ MOVD 32(R9), R10
+ MOVBU 40(R9), R11
+ CMP $0x20, R11
+ BLS skip_fill0
+ MOVD 24(R9), R0
+ SUB $0x20, R11, R11
+ SUB $0x04, R0, R0
+ MOVD (R9), R12
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ ADD R12, R0, R15
+ MOVWU (R15), R12
+ MOVD R11, R1
+ LSL R1, R12, R12
+ MOVD R0, 24(R9)
+ ORR R12, R10, R10
+
+ // exhausted += (br0.off < 4)
+ CMP $0x04, R0
+ CSINC HS, R2, R2, R16
+ BFI $0, R16, $8, R2
+
+skip_fill0:
+ // val0 := br0.peekTopBits(peekBits)
+ MOVD R10, R12
+ MOVD R6, R1
+ LSR R1, R12, R12
+
+ // v0 := table[val0&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br0.advance(uint8(v0.entry)
+ UBFX $8, R1, $8, R16
+ BFI $0, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+
+ // val1 := br0.peekTopBits(peekBits)
+ MOVD R6, R1
+ MOVD R10, R12
+ LSR R1, R12, R12
+
+ // v1 := table[val1&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br0.advance(uint8(v1.entry))
+ UBFX $8, R1, $8, R16
+ BFI $8, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+
+ // these two writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ MOVH R0, (R3)
+
+ // update the bitreader structure
+ MOVD R10, 32(R9)
+ MOVB R11, 40(R9)
+
+ // br1.fillFast32()
+ MOVD 80(R9), R10
+ MOVBU 88(R9), R11
+ CMP $0x20, R11
+ BLS skip_fill1
+ MOVD 72(R9), R0
+ SUB $0x20, R11, R11
+ SUB $0x04, R0, R0
+ MOVD 48(R9), R12
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ ADD R12, R0, R15
+ MOVWU (R15), R12
+ MOVD R11, R1
+ LSL R1, R12, R12
+ MOVD R0, 72(R9)
+ ORR R12, R10, R10
+
+ // exhausted += (br1.off < 4)
+ CMP $0x04, R0
+ CSINC HS, R2, R2, R16
+ BFI $0, R16, $8, R2
+
+skip_fill1:
+ // val0 := br1.peekTopBits(peekBits)
+ MOVD R10, R12
+ MOVD R6, R1
+ LSR R1, R12, R12
+
+ // v0 := table[val0&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br1.advance(uint8(v0.entry)
+ UBFX $8, R1, $8, R16
+ BFI $0, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+
+ // val1 := br1.peekTopBits(peekBits)
+ MOVD R6, R1
+ MOVD R10, R12
+ LSR R1, R12, R12
+
+ // v1 := table[val1&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br1.advance(uint8(v1.entry))
+ UBFX $8, R1, $8, R16
+ BFI $8, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+
+ // these two writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ ADD R7, R3, R15
+ MOVH R0, (R15)
+
+ // update the bitreader structure
+ MOVD R10, 80(R9)
+ MOVB R11, 88(R9)
+
+ // br2.fillFast32()
+ MOVD 128(R9), R10
+ MOVBU 136(R9), R11
+ CMP $0x20, R11
+ BLS skip_fill2
+ MOVD 120(R9), R0
+ SUB $0x20, R11, R11
+ SUB $0x04, R0, R0
+ MOVD 96(R9), R12
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ ADD R12, R0, R15
+ MOVWU (R15), R12
+ MOVD R11, R1
+ LSL R1, R12, R12
+ MOVD R0, 120(R9)
+ ORR R12, R10, R10
+
+ // exhausted += (br2.off < 4)
+ CMP $0x04, R0
+ CSINC HS, R2, R2, R16
+ BFI $0, R16, $8, R2
+
+skip_fill2:
+ // val0 := br2.peekTopBits(peekBits)
+ MOVD R10, R12
+ MOVD R6, R1
+ LSR R1, R12, R12
+
+ // v0 := table[val0&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br2.advance(uint8(v0.entry)
+ UBFX $8, R1, $8, R16
+ BFI $0, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+
+ // val1 := br2.peekTopBits(peekBits)
+ MOVD R6, R1
+ MOVD R10, R12
+ LSR R1, R12, R12
+
+ // v1 := table[val1&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br2.advance(uint8(v1.entry))
+ UBFX $8, R1, $8, R16
+ BFI $8, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+
+ // these two writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ ADD R7<<1, R3, R15
+ MOVH R0, (R15)
+
+ // update the bitreader structure
+ MOVD R10, 128(R9)
+ MOVB R11, 136(R9)
+
+ // br3.fillFast32()
+ MOVD 176(R9), R10
+ MOVBU 184(R9), R11
+ CMP $0x20, R11
+ BLS skip_fill3
+ MOVD 168(R9), R0
+ SUB $0x20, R11, R11
+ SUB $0x04, R0, R0
+ MOVD 144(R9), R12
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ ADD R12, R0, R15
+ MOVWU (R15), R12
+ MOVD R11, R1
+ LSL R1, R12, R12
+ MOVD R0, 168(R9)
+ ORR R12, R10, R10
+
+ // exhausted += (br3.off < 4)
+ CMP $0x04, R0
+ CSINC HS, R2, R2, R16
+ BFI $0, R16, $8, R2
+
+skip_fill3:
+ // val0 := br3.peekTopBits(peekBits)
+ MOVD R10, R12
+ MOVD R6, R1
+ LSR R1, R12, R12
+
+ // v0 := table[val0&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br3.advance(uint8(v0.entry)
+ UBFX $8, R1, $8, R16
+ BFI $0, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+
+ // val1 := br3.peekTopBits(peekBits)
+ MOVD R6, R1
+ MOVD R10, R12
+ LSR R1, R12, R12
+
+ // v1 := table[val1&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br3.advance(uint8(v1.entry))
+ UBFX $8, R1, $8, R16
+ BFI $8, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+
+ // these two writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ ADD R7<<1, R7, R1
+ ADD R1, R3, R15
+ MOVH R0, (R15)
+
+ // update the bitreader structure
+ MOVD R10, 176(R9)
+ MOVB R11, 184(R9)
+ ADD $0x02, R3, R3
+ AND $0xff, R2, R15
+ AND $0xff, R2, R16
+ TST R16, R15
+ BEQ main_loop
+ MOVD ctx+0(FP), R0
+ MOVD 16(R0), R16
+ SUB R16, R3, R3
+ LSL $0x02, R3, R3
+ MOVD R3, 40(R0)
+ RET
+
+// func decompress4x_8b_main_loop_amd64(ctx *decompress4xContext)
+TEXT ·decompress4x_8b_main_loop_arm64(SB), $0-8
+ // Preload values
+ MOVD ctx+0(FP), R1
+ MOVBU 8(R1), R6
+ MOVD 16(R1), R3
+ MOVD 48(R1), R5
+ MOVD 24(R1), R7
+ MOVD 32(R1), R8
+ MOVD (R1), R9
+
+ // Main loop
+main_loop:
+ MOVD $0, R2
+ CMP R5, R3
+ CSET GE, R16
+ BFI $0, R16, $8, R2
+
+ // br0.fillFast32()
+ MOVD 32(R9), R10
+ MOVBU 40(R9), R11
+ CMP $0x20, R11
+ BLS skip_fill0
+ MOVD 24(R9), R12
+ SUB $0x20, R11, R11
+ SUB $0x04, R12, R12
+ MOVD (R9), R13
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ ADD R13, R12, R15
+ MOVWU (R15), R13
+ MOVD R11, R1
+ LSL R1, R13, R13
+ MOVD R12, 24(R9)
+ ORR R13, R10, R10
+
+ // exhausted += (br0.off < 4)
+ CMP $0x04, R12
+ CSINC HS, R2, R2, R16
+ BFI $0, R16, $8, R2
+
+skip_fill0:
+ // val0 := br0.peekTopBits(peekBits)
+ MOVD R10, R12
+ MOVD R6, R1
+ LSR R1, R12, R12
+
+ // v0 := table[val0&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br0.advance(uint8(v0.entry)
+ UBFX $8, R1, $8, R16
+ BFI $0, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+
+ // val1 := br0.peekTopBits(peekBits)
+ MOVD R10, R12
+ MOVD R6, R1
+ LSR R1, R12, R12
+
+ // v1 := table[val0&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br0.advance(uint8(v1.entry)
+ UBFX $8, R1, $8, R16
+ BFI $8, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+ REVW R0, R0
+
+ // val2 := br0.peekTopBits(peekBits)
+ MOVD R10, R12
+ MOVD R6, R1
+ LSR R1, R12, R12
+
+ // v2 := table[val0&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br0.advance(uint8(v2.entry)
+ UBFX $8, R1, $8, R16
+ BFI $8, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+
+ // val3 := br0.peekTopBits(peekBits)
+ MOVD R10, R12
+ MOVD R6, R1
+ LSR R1, R12, R12
+
+ // v3 := table[val0&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br0.advance(uint8(v3.entry)
+ UBFX $8, R1, $8, R16
+ BFI $0, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+ REVW R0, R0
+
+ // these four writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ // out[id * dstEvery + 3] = uint8(v2.entry >> 8)
+ // out[id * dstEvery + 4] = uint8(v3.entry >> 8)
+ MOVW R0, (R3)
+
+ // update the bitreader structure
+ MOVD R10, 32(R9)
+ MOVB R11, 40(R9)
+
+ // br1.fillFast32()
+ MOVD 80(R9), R10
+ MOVBU 88(R9), R11
+ CMP $0x20, R11
+ BLS skip_fill1
+ MOVD 72(R9), R12
+ SUB $0x20, R11, R11
+ SUB $0x04, R12, R12
+ MOVD 48(R9), R13
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ ADD R13, R12, R15
+ MOVWU (R15), R13
+ MOVD R11, R1
+ LSL R1, R13, R13
+ MOVD R12, 72(R9)
+ ORR R13, R10, R10
+
+ // exhausted += (br1.off < 4)
+ CMP $0x04, R12
+ CSINC HS, R2, R2, R16
+ BFI $0, R16, $8, R2
+
+skip_fill1:
+ // val0 := br1.peekTopBits(peekBits)
+ MOVD R10, R12
+ MOVD R6, R1
+ LSR R1, R12, R12
+
+ // v0 := table[val0&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br1.advance(uint8(v0.entry)
+ UBFX $8, R1, $8, R16
+ BFI $0, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+
+ // val1 := br1.peekTopBits(peekBits)
+ MOVD R10, R12
+ MOVD R6, R1
+ LSR R1, R12, R12
+
+ // v1 := table[val0&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br1.advance(uint8(v1.entry)
+ UBFX $8, R1, $8, R16
+ BFI $8, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+ REVW R0, R0
+
+ // val2 := br1.peekTopBits(peekBits)
+ MOVD R10, R12
+ MOVD R6, R1
+ LSR R1, R12, R12
+
+ // v2 := table[val0&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br1.advance(uint8(v2.entry)
+ UBFX $8, R1, $8, R16
+ BFI $8, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+
+ // val3 := br1.peekTopBits(peekBits)
+ MOVD R10, R12
+ MOVD R6, R1
+ LSR R1, R12, R12
+
+ // v3 := table[val0&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br1.advance(uint8(v3.entry)
+ UBFX $8, R1, $8, R16
+ BFI $0, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+ REVW R0, R0
+
+ // these four writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ // out[id * dstEvery + 3] = uint8(v2.entry >> 8)
+ // out[id * dstEvery + 4] = uint8(v3.entry >> 8)
+ ADD R7, R3, R15
+ MOVW R0, (R15)
+
+ // update the bitreader structure
+ MOVD R10, 80(R9)
+ MOVB R11, 88(R9)
+
+ // br2.fillFast32()
+ MOVD 128(R9), R10
+ MOVBU 136(R9), R11
+ CMP $0x20, R11
+ BLS skip_fill2
+ MOVD 120(R9), R12
+ SUB $0x20, R11, R11
+ SUB $0x04, R12, R12
+ MOVD 96(R9), R13
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ ADD R13, R12, R15
+ MOVWU (R15), R13
+ MOVD R11, R1
+ LSL R1, R13, R13
+ MOVD R12, 120(R9)
+ ORR R13, R10, R10
+
+ // exhausted += (br2.off < 4)
+ CMP $0x04, R12
+ CSINC HS, R2, R2, R16
+ BFI $0, R16, $8, R2
+
+skip_fill2:
+ // val0 := br2.peekTopBits(peekBits)
+ MOVD R10, R12
+ MOVD R6, R1
+ LSR R1, R12, R12
+
+ // v0 := table[val0&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br2.advance(uint8(v0.entry)
+ UBFX $8, R1, $8, R16
+ BFI $0, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+
+ // val1 := br2.peekTopBits(peekBits)
+ MOVD R10, R12
+ MOVD R6, R1
+ LSR R1, R12, R12
+
+ // v1 := table[val0&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br2.advance(uint8(v1.entry)
+ UBFX $8, R1, $8, R16
+ BFI $8, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+ REVW R0, R0
+
+ // val2 := br2.peekTopBits(peekBits)
+ MOVD R10, R12
+ MOVD R6, R1
+ LSR R1, R12, R12
+
+ // v2 := table[val0&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br2.advance(uint8(v2.entry)
+ UBFX $8, R1, $8, R16
+ BFI $8, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+
+ // val3 := br2.peekTopBits(peekBits)
+ MOVD R10, R12
+ MOVD R6, R1
+ LSR R1, R12, R12
+
+ // v3 := table[val0&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br2.advance(uint8(v3.entry)
+ UBFX $8, R1, $8, R16
+ BFI $0, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+ REVW R0, R0
+
+ // these four writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ // out[id * dstEvery + 3] = uint8(v2.entry >> 8)
+ // out[id * dstEvery + 4] = uint8(v3.entry >> 8)
+ ADD R7<<1, R3, R15
+ MOVW R0, (R15)
+
+ // update the bitreader structure
+ MOVD R10, 128(R9)
+ MOVB R11, 136(R9)
+
+ // br3.fillFast32()
+ MOVD 176(R9), R10
+ MOVBU 184(R9), R11
+ CMP $0x20, R11
+ BLS skip_fill3
+ MOVD 168(R9), R12
+ SUB $0x20, R11, R11
+ SUB $0x04, R12, R12
+ MOVD 144(R9), R13
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ ADD R13, R12, R15
+ MOVWU (R15), R13
+ MOVD R11, R1
+ LSL R1, R13, R13
+ MOVD R12, 168(R9)
+ ORR R13, R10, R10
+
+ // exhausted += (br3.off < 4)
+ CMP $0x04, R12
+ CSINC HS, R2, R2, R16
+ BFI $0, R16, $8, R2
+
+skip_fill3:
+ // val0 := br3.peekTopBits(peekBits)
+ MOVD R10, R12
+ MOVD R6, R1
+ LSR R1, R12, R12
+
+ // v0 := table[val0&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br3.advance(uint8(v0.entry)
+ UBFX $8, R1, $8, R16
+ BFI $0, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+
+ // val1 := br3.peekTopBits(peekBits)
+ MOVD R10, R12
+ MOVD R6, R1
+ LSR R1, R12, R12
+
+ // v1 := table[val0&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br3.advance(uint8(v1.entry)
+ UBFX $8, R1, $8, R16
+ BFI $8, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+ REVW R0, R0
+
+ // val2 := br3.peekTopBits(peekBits)
+ MOVD R10, R12
+ MOVD R6, R1
+ LSR R1, R12, R12
+
+ // v2 := table[val0&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br3.advance(uint8(v2.entry)
+ UBFX $8, R1, $8, R16
+ BFI $8, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+
+ // val3 := br3.peekTopBits(peekBits)
+ MOVD R10, R12
+ MOVD R6, R1
+ LSR R1, R12, R12
+
+ // v3 := table[val0&mask]
+ ADD R12<<1, R8, R15
+ MOVHU (R15), R1
+
+ // br3.advance(uint8(v3.entry)
+ UBFX $8, R1, $8, R16
+ BFI $0, R16, $8, R0
+ LSL R1, R10, R10
+ ADD R1, R11, R15
+ BFI $0, R15, $8, R11
+ REVW R0, R0
+
+ // these four writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ // out[id * dstEvery + 3] = uint8(v2.entry >> 8)
+ // out[id * dstEvery + 4] = uint8(v3.entry >> 8)
+ ADD R7<<1, R7, R1
+ ADD R1, R3, R15
+ MOVW R0, (R15)
+
+ // update the bitreader structure
+ MOVD R10, 176(R9)
+ MOVB R11, 184(R9)
+ ADD $0x04, R3, R3
+ AND $0xff, R2, R15
+ AND $0xff, R2, R16
+ TST R16, R15
+ BEQ main_loop
+ MOVD ctx+0(FP), R0
+ MOVD 16(R0), R16
+ SUB R16, R3, R3
+ LSL $0x02, R3, R3
+ MOVD R3, 40(R0)
+ RET
+
+// func decompress1x_main_loop_amd64(ctx *decompress1xContext)
+TEXT ·decompress1x_main_loop_arm64(SB), $0-8
+ MOVD ctx+0(FP), R1
+ MOVD 16(R1), R2
+ MOVD 24(R1), R3
+ CMP $0x04, R3
+ BLO error_max_decoded_size_exceeded
+ ADD R3, R2, R3
+ MOVD (R1), R5
+ MOVD (R5), R7
+ MOVD 24(R5), R8
+ MOVD 32(R5), R9
+ MOVBU 40(R5), R10
+ MOVD 32(R1), R5
+ MOVBU 8(R1), R6
+ JMP loop_condition
+
+main_loop:
+ // Check if we have room for 4 bytes in the output buffer
+ ADD $4, R2, R1
+ CMP R3, R1
+ BGE error_max_decoded_size_exceeded
+
+ // Decode 4 values
+ CMP $0x20, R10
+ BLT bitReader_fillFast_1_end
+ SUB $0x20, R10, R10
+ SUB $0x04, R8, R8
+ ADD R8, R7, R15
+ MOVWU (R15), R11
+ MOVD R10, R1
+ LSL R1, R11, R11
+ ORR R11, R9, R9
+
+bitReader_fillFast_1_end:
+ MOVD R6, R1
+ MOVD R9, R11
+ LSR R1, R11, R11
+ ADD R11<<1, R5, R15
+ MOVHU (R15), R1
+ UBFX $8, R1, $8, R16
+ BFI $0, R16, $8, R0
+ MOVBU R1, R1
+ ADD R1, R10, R10
+ LSL R1, R9, R9
+ MOVD R6, R1
+ MOVD R9, R11
+ LSR R1, R11, R11
+ ADD R11<<1, R5, R15
+ MOVHU (R15), R1
+ UBFX $8, R1, $8, R16
+ BFI $8, R16, $8, R0
+ MOVBU R1, R1
+ ADD R1, R10, R10
+ LSL R1, R9, R9
+ REVW R0, R0
+ CMP $0x20, R10
+ BLT bitReader_fillFast_2_end
+ SUB $0x20, R10, R10
+ SUB $0x04, R8, R8
+ ADD R8, R7, R15
+ MOVWU (R15), R11
+ MOVD R10, R1
+ LSL R1, R11, R11
+ ORR R11, R9, R9
+
+bitReader_fillFast_2_end:
+ MOVD R6, R1
+ MOVD R9, R11
+ LSR R1, R11, R11
+ ADD R11<<1, R5, R15
+ MOVHU (R15), R1
+ UBFX $8, R1, $8, R16
+ BFI $8, R16, $8, R0
+ MOVBU R1, R1
+ ADD R1, R10, R10
+ LSL R1, R9, R9
+ MOVD R6, R1
+ MOVD R9, R11
+ LSR R1, R11, R11
+ ADD R11<<1, R5, R15
+ MOVHU (R15), R1
+ UBFX $8, R1, $8, R16
+ BFI $0, R16, $8, R0
+ MOVBU R1, R1
+ ADD R1, R10, R10
+ LSL R1, R9, R9
+ REVW R0, R0
+
+ // Store the decoded values
+ MOVW R0, (R2)
+ ADD $0x04, R2, R2
+
+loop_condition:
+ CMP $0x08, R8
+ BGE main_loop
+
+ // Update ctx structure
+ MOVD ctx+0(FP), R0
+ MOVD 16(R0), R16
+ SUB R16, R2, R2
+ MOVD R2, 40(R0)
+ MOVD (R0), R0
+ MOVD R8, 24(R0)
+ MOVD R9, 32(R0)
+ MOVB R10, 40(R0)
+ RET
+
+ // Report error
+error_max_decoded_size_exceeded:
+ MOVD ctx+0(FP), R0
+ MOVD $-1, R1
+ MOVD R1, 40(R0)
+ RET
+
+// skipped decompress1x_main_loop_bmi2 (generic twin preferred on arm64)
diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_asm.go b/vendor/github.com/klauspost/compress/huff0/decompress_asm.go
new file mode 100644
index 00000000..4854dd43
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/decompress_asm.go
@@ -0,0 +1,193 @@
+//go:build (amd64 || arm64) && !appengine && !noasm && gc
+
+// This file contains the specialisation of Decoder.Decompress4X
+// and Decoder.Decompress1X that use an asm implementation of their main loops.
+// The asm function stubs and any per-arch dispatch live in decompress_amd64.go
+// and decompress_arm64.go.
+package huff0
+
+import (
+ "errors"
+ "fmt"
+)
+
+// fallback8BitSize is the size where using Go version is faster.
+const fallback8BitSize = 800
+
+type decompress4xContext struct {
+ pbr *[4]bitReaderShifted
+ peekBits uint8
+ out *byte
+ dstEvery int
+ tbl *dEntrySingle
+ decoded int
+ limit *byte
+}
+
+// Decompress4X will decompress a 4X encoded stream.
+// The length of the supplied input must match the end of a block exactly.
+// The *capacity* of the dst slice must match the destination size of
+// the uncompressed data exactly.
+func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) {
+ if len(d.dt.single) == 0 {
+ return nil, errors.New("no table loaded")
+ }
+ if len(src) < 6+(4*1) {
+ return nil, errors.New("input too small")
+ }
+
+ use8BitTables := d.actualTableLog <= 8
+ if cap(dst) < fallback8BitSize && use8BitTables {
+ return d.decompress4X8bit(dst, src)
+ }
+
+ var br [4]bitReaderShifted
+ // Decode "jump table"
+ start := 6
+ 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)")
+ }
+ err := br[i].init(src[start : start+length])
+ if err != nil {
+ return nil, err
+ }
+ start += length
+ }
+ err := br[3].init(src[start:])
+ if err != nil {
+ return nil, err
+ }
+
+ // destination, offset to match first output
+ dstSize := cap(dst)
+ dst = dst[:dstSize]
+ out := dst
+ dstEvery := (dstSize + 3) / 4
+
+ const tlSize = 1 << tableLogMax
+ const tlMask = tlSize - 1
+ single := d.dt.single[:tlSize]
+
+ var decoded int
+
+ if len(out) > 4*4 && !(br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4) {
+ ctx := decompress4xContext{
+ pbr: &br,
+ peekBits: uint8((64 - d.actualTableLog) & 63), // see: bitReaderShifted.peekBitsFast()
+ out: &out[0],
+ dstEvery: dstEvery,
+ tbl: &single[0],
+ limit: &out[dstEvery-4], // Always stop decoding when first buffer gets here to avoid writing OOB on last.
+ }
+ if use8BitTables {
+ decompress4x_8b_main_loop_asm(&ctx)
+ } else {
+ decompress4x_main_loop_asm(&ctx)
+ }
+
+ decoded = ctx.decoded
+ out = out[decoded/4:]
+ }
+
+ // Decode remaining.
+ remainBytes := dstEvery - (decoded / 4)
+ for i := range br {
+ offset := dstEvery * i
+ endsAt := min(offset+remainBytes, len(out))
+ br := &br[i]
+ bitsLeft := br.remaining()
+ for bitsLeft > 0 {
+ br.fill()
+ if offset >= endsAt {
+ return nil, errors.New("corruption detected: stream overrun 4")
+ }
+
+ // Read value and increment offset.
+ val := br.peekBitsFast(d.actualTableLog)
+ v := single[val&tlMask].entry
+ nBits := uint8(v)
+ br.advance(nBits)
+ bitsLeft -= uint(nBits)
+ out[offset] = uint8(v >> 8)
+ offset++
+ }
+ if offset != endsAt {
+ return nil, fmt.Errorf("corruption detected: short output block %d, end %d != %d", i, offset, endsAt)
+ }
+ decoded += offset - dstEvery*i
+ err = br.close()
+ if err != nil {
+ return nil, err
+ }
+ }
+ if dstSize != decoded {
+ return nil, errors.New("corruption detected: short output block")
+ }
+ return dst, nil
+}
+
+type decompress1xContext struct {
+ pbr *bitReaderShifted
+ peekBits uint8
+ out *byte
+ outCap int
+ tbl *dEntrySingle
+ decoded int
+}
+
+// Error reported by asm implementations
+const error_max_decoded_size_exeeded = -1
+
+// Decompress1X will decompress a 1X encoded stream.
+// The cap of the output buffer will be the maximum decompressed size.
+// The length of the supplied input must match the end of a block exactly.
+func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) {
+ if len(d.dt.single) == 0 {
+ return nil, errors.New("no table loaded")
+ }
+ var br bitReaderShifted
+ err := br.init(src)
+ if err != nil {
+ return dst, err
+ }
+ maxDecodedSize := cap(dst)
+ dst = dst[:maxDecodedSize]
+
+ const tlSize = 1 << tableLogMax
+ const tlMask = tlSize - 1
+
+ if maxDecodedSize >= 4 {
+ ctx := decompress1xContext{
+ pbr: &br,
+ out: &dst[0],
+ outCap: maxDecodedSize,
+ peekBits: uint8((64 - d.actualTableLog) & 63), // see: bitReaderShifted.peekBitsFast()
+ tbl: &d.dt.single[0],
+ }
+
+ decompress1x_main_loop_asm(&ctx)
+ if ctx.decoded == error_max_decoded_size_exeeded {
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+
+ dst = dst[:ctx.decoded]
+ }
+
+ // br < 8, so uint8 is fine
+ bitsLeft := uint8(br.off)*8 + 64 - br.bitsRead
+ for bitsLeft > 0 {
+ br.fill()
+ if len(dst) >= maxDecodedSize {
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ v := d.dt.single[br.peekBitsFast(d.actualTableLog)&tlMask]
+ nBits := uint8(v.entry)
+ br.advance(nBits)
+ bitsLeft -= nBits
+ dst = append(dst, uint8(v.entry>>8))
+ }
+ return dst, br.close()
+}
diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_generic.go b/vendor/github.com/klauspost/compress/huff0/decompress_generic.go
index 908c17de..e1bca5c6 100644
--- a/vendor/github.com/klauspost/compress/huff0/decompress_generic.go
+++ b/vendor/github.com/klauspost/compress/huff0/decompress_generic.go
@@ -1,5 +1,4 @@
-//go:build !amd64 || appengine || !gc || noasm
-// +build !amd64 appengine !gc noasm
+//go:build (!amd64 && !arm64) || appengine || !gc || noasm
// This file contains a generic implementation of Decoder.Decompress4X.
package huff0
diff --git a/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.go b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.go
index e802579c..b97f9056 100644
--- a/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.go
+++ b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.go
@@ -1,5 +1,4 @@
//go:build amd64 && !appengine && !noasm && gc
-// +build amd64,!appengine,!noasm,gc
package cpuinfo
diff --git a/vendor/github.com/klauspost/compress/internal/snapref/decode.go b/vendor/github.com/klauspost/compress/internal/snapref/decode.go
index a2c82fcd..584b7574 100644
--- a/vendor/github.com/klauspost/compress/internal/snapref/decode.go
+++ b/vendor/github.com/klauspost/compress/internal/snapref/decode.go
@@ -31,7 +31,7 @@ func DecodedLen(src []byte) (int, error) {
// that the length header occupied.
func decodedLen(src []byte) (blockLen, headerLen int, err error) {
v, n := binary.Uvarint(src)
- if n <= 0 || v > 0xffffffff {
+ if n <= 0 || n > 5 || v > 0xffffffff {
return 0, 0, ErrCorrupt
}
diff --git a/vendor/github.com/klauspost/compress/zstd/README.md b/vendor/github.com/klauspost/compress/zstd/README.md
index c11d7fa2..a5aeeaed 100644
--- a/vendor/github.com/klauspost/compress/zstd/README.md
+++ b/vendor/github.com/klauspost/compress/zstd/README.md
@@ -75,14 +75,47 @@ The above is fine for big encodes. However, whenever possible try to *reuse* the
To reuse the encoder, you can use the `Reset(io.Writer)` function to change to another output.
This will allow the encoder to reuse all resources and avoid wasteful allocations.
-Currently stream encoding has 'light' concurrency, meaning up to 2 goroutines can be working on part
-of a stream. This is independent of the `WithEncoderConcurrency(n)`, but that is likely to change
+By default, stream encoding has 'light' concurrency, meaning up to 2 goroutines can be working on part
+of a stream. This is independent of the `WithEncoderConcurrency(n)`, but that is likely to change
in the future. So if you want to limit concurrency for future updates, specify the concurrency
you would like.
If you would like stream encoding to be done without spawning async goroutines, use `WithEncoderConcurrency(1)`
which will compress input as each block is completed, blocking on writes until each has completed.
+#### Parallel Stream Compression
+
+For maximum throughput on large streams, use `WithConcurrentBlocks(true)` together with
+`WithEncoderConcurrency(n)` where n is the number of CPU cores you want to use.
+This splits the input into large sections (jobs) that are compressed simultaneously by multiple goroutines,
+similar to how the C zstd library does multithreaded compression.
+
+```Go
+enc, err := zstd.NewWriter(out,
+ zstd.WithEncoderLevel(zstd.SpeedDefault),
+ zstd.WithEncoderConcurrency(runtime.GOMAXPROCS(0)),
+ zstd.WithConcurrentBlocks(true),
+)
+```
+
+Each non-first job receives an overlap prefix from the previous job for match context,
+so compression ratio is only marginally affected. Output is flushed in order,
+producing a valid single-frame zstd stream.
+
+Benchmark on 1.8GB GOB stream (AMD Ryzen 9 9950X):
+
+| Level | 1 thread | 4 threads | 16 threads | 1T ratio | 16T ratio |
+|---------|:----------:|:------------------:|:-------------------:|:--------:|:---------:|
+| fastest | 783 MB/s | 2950 MB/s (3.8×) | 6939 MB/s (8.9×) | 12.24% | 12.26% |
+| default | 728 MB/s | 2533 MB/s (3.5×) | 5340 MB/s (7.3×) | 10.67% | 10.68% |
+| better | 434 MB/s | 1105 MB/s (2.5×) | 2206 MB/s (5.1×) | 9.14% | 9.21% |
+| best | 129 MB/s | 367 MB/s (2.8×) | 884 MB/s (6.8×) | 8.48% | 8.63% |
+
+Notes:
+* Not compatible with dictionary encoding.
+* `Flush()` dispatches the current partial job, so latency-sensitive callers can force output.
+* `EncodeAll` is unaffected — it uses its own concurrency via the encoder pool.
+
You can specify your desired compression level using `WithEncoderLevel()` option. Currently only pre-defined
compression settings can be specified.
diff --git a/vendor/github.com/klauspost/compress/zstd/blockdec.go b/vendor/github.com/klauspost/compress/zstd/blockdec.go
index 2329e996..51f9da03 100644
--- a/vendor/github.com/klauspost/compress/zstd/blockdec.go
+++ b/vendor/github.com/klauspost/compress/zstd/blockdec.go
@@ -400,8 +400,9 @@ func (b *blockDec) decodeLiterals(in []byte, hist *history) (remain []byte, err
}
}
var err error
- // Use our out buffer.
- huff.MaxDecodedSize = litRegenSize
+ // Decoder.Decompress* uses cap(dst) for the size limit. Do not write
+ // MaxDecodedSize on hist.huffTree: with a trained dictionary that
+ // pointer aliases the shared dict.litEnc and concurrent DecodeAll races.
if fourStreams {
literals, err = huff.Decoder().Decompress4X(b.literalBuf[:0:litRegenSize], literals)
} else {
@@ -673,10 +674,6 @@ func (b *blockDec) executeSequences(hist *history) error {
hbytes := hist.b
if len(hbytes) > hist.windowSize {
hbytes = hbytes[len(hbytes)-hist.windowSize:]
- // We do not need history anymore.
- if hist.dict != nil {
- hist.dict.content = nil
- }
}
hist.decoders.windowSize = hist.windowSize
hist.decoders.out = b.dst[:0]
diff --git a/vendor/github.com/klauspost/compress/zstd/blockenc.go b/vendor/github.com/klauspost/compress/zstd/blockenc.go
index fd35ea14..0e33aea4 100644
--- a/vendor/github.com/klauspost/compress/zstd/blockenc.go
+++ b/vendor/github.com/klauspost/compress/zstd/blockenc.go
@@ -78,6 +78,7 @@ func (b *blockEnc) initNewEncode() {
b.recentOffsets = [3]uint32{1, 4, 8}
b.litEnc.Reuse = huff0.ReusePolicyNone
b.coders.setPrev(nil, nil, nil)
+ b.dictLitEnc = nil
}
// reset will reset the block for a new encode, but in the same stream,
diff --git a/vendor/github.com/klauspost/compress/zstd/dict.go b/vendor/github.com/klauspost/compress/zstd/dict.go
index 2ffbfdf3..67f40e79 100644
--- a/vendor/github.com/klauspost/compress/zstd/dict.go
+++ b/vendor/github.com/klauspost/compress/zstd/dict.go
@@ -230,7 +230,7 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
}
block := blockEnc{lowMem: false}
block.init()
- enc := encoder(&bestFastEncoder{fastBase: fastBase{maxMatchOff: int32(maxMatchLen), bufferReset: math.MaxInt32 - int32(maxMatchLen*2), lowMem: false}})
+ var enc encoder
if o.Level != 0 {
eOpts := encoderOptions{
level: o.Level,
@@ -242,6 +242,7 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
enc = eOpts.encoder()
} else {
o.Level = SpeedBestCompression
+ enc = encoder(&bestFastEncoder{fastBase: fastBase{maxMatchOff: int32(maxMatchLen), bufferReset: math.MaxInt32 - int32(maxMatchLen*2), lowMem: false}})
}
var (
remain [256]int
@@ -295,40 +296,81 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
if offset > 3 {
newOffsets[offset-3]++
} else {
- newOffsets[uint32(o.Offsets[offset-1])]++
+ // Repeat codes reference the training Offsets. Skip unset
+ // (zero) entries so they are not ranked as real offsets.
+ prev := o.Offsets[offset-1]
+ if prev > 0 {
+ newOffsets[uint32(prev)]++
+ }
}
}
}
// Find most used offsets.
var sortedOffsets []uint32
for k := range newOffsets {
+ if k == 0 {
+ continue
+ }
sortedOffsets = append(sortedOffsets, k)
}
sort.Slice(sortedOffsets, func(i, j int) bool {
a, b := sortedOffsets[i], sortedOffsets[j]
- if a == b {
+ ca, cb := newOffsets[a], newOffsets[b]
+ if ca == cb {
// Prefer the longer offset
- return sortedOffsets[i] > sortedOffsets[j]
+ return a > b
}
- return newOffsets[sortedOffsets[i]] > newOffsets[sortedOffsets[j]]
+ return ca > cb
})
- if len(sortedOffsets) > 3 {
- if debug {
- print("Offsets:")
- for i, v := range sortedOffsets {
- if i > 20 {
- break
- }
- printf("[%d: %d],", v, newOffsets[v])
+ if debug {
+ print("Offsets:")
+ for i, v := range sortedOffsets {
+ if i > 20 {
+ break
}
- println("")
+ printf("[%d: %d],", v, newOffsets[v])
+ }
+ println("")
+ }
+ // Dictionary recent-offsets must be three positive values within the
+ // history. Ranked matches may be fewer (or empty when only unset
+ // repeat codes were seen), so fill remaining slots with defaults.
+ used := make(map[int]bool, 3)
+ var finalOffsets [3]int
+ nOff := 0
+ for _, v := range sortedOffsets {
+ iv := int(v)
+ if iv <= 0 || iv > len(hist) || used[iv] {
+ continue
+ }
+ finalOffsets[nOff] = iv
+ used[iv] = true
+ nOff++
+ if nOff == 3 {
+ break
}
-
- sortedOffsets = sortedOffsets[:3]
}
- for i, v := range sortedOffsets {
- o.Offsets[i] = int(v)
+ for _, def := range []int{1, 4, 8} {
+ if nOff == 3 {
+ break
+ }
+ if def <= len(hist) && !used[def] {
+ finalOffsets[nOff] = def
+ used[def] = true
+ nOff++
+ }
+ }
+ for def := 1; nOff < 3 && def <= len(hist); def++ {
+ if !used[def] {
+ finalOffsets[nOff] = def
+ used[def] = true
+ nOff++
+ }
+ }
+ if nOff < 3 {
+ return nil, fmt.Errorf("could not determine 3 valid dictionary offsets (history size %d)", len(hist))
}
+ o.Offsets = finalOffsets
if debug {
println("New repeat offsets", o.Offsets)
}
@@ -336,6 +378,9 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
if nUsed == 0 || seqs == 0 {
return nil, fmt.Errorf("%d blocks, %d sequences found", nUsed, seqs)
}
+ if litTotal == 0 {
+ return nil, errors.New("0 literals found")
+ }
if debug {
println("Sequences:", seqs, "Blocks:", nUsed, "Literals:", litTotal)
}
@@ -516,11 +561,10 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
out.Write(binary.LittleEndian.AppendUint32(nil, uint32(o.Offsets[1])))
out.Write(binary.LittleEndian.AppendUint32(nil, uint32(o.Offsets[2])))
out.Write(hist)
+ if _, err := loadDict(out.Bytes()); err != nil {
+ return nil, fmt.Errorf("built dictionary failed validation: %w", err)
+ }
if debug {
- _, err := loadDict(out.Bytes())
- if err != nil {
- panic(err)
- }
i, err := InspectDictionary(out.Bytes())
if err != nil {
panic(err)
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_base.go b/vendor/github.com/klauspost/compress/zstd/enc_base.go
index c1192ec3..c4fea575 100644
--- a/vendor/github.com/klauspost/compress/zstd/enc_base.go
+++ b/vendor/github.com/klauspost/compress/zstd/enc_base.go
@@ -21,7 +21,7 @@ type fastBase struct {
crc *xxhash.Digest
tmp [8]byte
blk *blockEnc
- lastDictID uint32
+ lastDict *dict
lowMem bool
}
@@ -128,6 +128,34 @@ func (e *fastBase) matchlen(s, t int32, src []byte) int32 {
return int32(matchLen(src[s:], src[t:]))
}
+// resetBasePrefix resets the encoder state and loads prefix as initial history.
+// This is used for parallel job encoding where non-first jobs need overlap context.
+// Rep offsets are set to defaults [1,4,8] (invalidated, matching C behavior).
+func (e *fastBase) resetBasePrefix(prefix []byte) {
+ if e.blk == nil {
+ e.blk = &blockEnc{lowMem: e.lowMem}
+ e.blk.init()
+ } else {
+ e.blk.reset(nil)
+ }
+ e.blk.initNewEncode()
+ if e.crc == nil {
+ e.crc = xxhash.New()
+ } else {
+ e.crc.Reset()
+ }
+ e.blk.dictLitEnc = nil
+ e.ensureHist(len(prefix) + maxCompressedBlockSize)
+ // Bump cur so old table entries fall outside the window.
+ // When cur >= bufferReset, leave it; the first Encode call
+ // will shift/clear tables, preserving valid prefix entries.
+ if e.cur < e.bufferReset {
+ e.cur += e.maxMatchOff + int32(len(e.hist))
+ }
+ e.hist = e.hist[:0]
+ e.hist = append(e.hist, prefix...)
+}
+
// Reset the encoding table.
func (e *fastBase) resetBase(d *dict, singleBlock bool) {
if e.blk == nil {
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_best.go b/vendor/github.com/klauspost/compress/zstd/enc_best.go
index c1581cfc..c71382dd 100644
--- a/vendor/github.com/klauspost/compress/zstd/enc_best.go
+++ b/vendor/github.com/klauspost/compress/zstd/enc_best.go
@@ -479,10 +479,13 @@ func (e *bestFastEncoder) Reset(d *dict, singleBlock bool) {
if d == nil {
return
}
+ dictChanged := d != e.lastDict
// Init or copy dict table
- if len(e.dictTable) != len(e.table) || d.id != e.lastDictID {
+ if len(e.dictTable) != len(e.table) || dictChanged {
if len(e.dictTable) != len(e.table) {
e.dictTable = make([]prevEntry, len(e.table))
+ } else {
+ clear(e.dictTable)
}
end := int32(len(d.content)) - 8 + e.maxMatchOff
for i := e.maxMatchOff; i < end; i += 4 {
@@ -510,13 +513,14 @@ func (e *bestFastEncoder) Reset(d *dict, singleBlock bool) {
offset: i + 3,
}
}
- e.lastDictID = d.id
}
- // Init or copy dict table
- if len(e.dictLongTable) != len(e.longTable) || d.id != e.lastDictID {
+ // Init or copy dict long table
+ if len(e.dictLongTable) != len(e.longTable) || dictChanged {
if len(e.dictLongTable) != len(e.longTable) {
e.dictLongTable = make([]prevEntry, len(e.longTable))
+ } else {
+ clear(e.dictLongTable)
}
if len(d.content) >= 8 {
cv := load6432(d.content, 0)
@@ -538,8 +542,8 @@ func (e *bestFastEncoder) Reset(d *dict, singleBlock bool) {
off++
}
}
- e.lastDictID = d.id
}
+ e.lastDict = d
// Reset table to initial state
copy(e.longTable[:], e.dictLongTable)
@@ -547,3 +551,18 @@ func (e *bestFastEncoder) Reset(d *dict, singleBlock bool) {
// Reset table to initial state
copy(e.table[:], e.dictTable)
}
+
+func (e *bestFastEncoder) ResetPrefix(prefix []byte) {
+ e.resetBasePrefix(prefix)
+ if len(prefix) < 8 {
+ return
+ }
+ end := e.cur + int32(len(prefix)) - 8
+ for i := e.cur; i < end; i++ {
+ cv := load6432(prefix, i-e.cur)
+ h := hashLen(cv, bestLongTableBits, bestLongLen)
+ e.longTable[h] = prevEntry{offset: i, prev: e.longTable[h].offset}
+ h0 := hashLen(cv, bestShortTableBits, bestShortLen)
+ e.table[h0] = prevEntry{offset: i, prev: e.table[h0].offset}
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_better.go b/vendor/github.com/klauspost/compress/zstd/enc_better.go
index 85dcd28c..523d57f3 100644
--- a/vendor/github.com/klauspost/compress/zstd/enc_better.go
+++ b/vendor/github.com/klauspost/compress/zstd/enc_better.go
@@ -1096,16 +1096,33 @@ func (e *betterFastEncoder) Reset(d *dict, singleBlock bool) {
}
}
+func (e *betterFastEncoder) ResetPrefix(prefix []byte) {
+ e.resetBasePrefix(prefix)
+ if len(prefix) < 8 {
+ return
+ }
+ end := e.cur + int32(len(prefix)) - 8
+ for i := e.cur; i < end; i += 2 {
+ cv := load6432(prefix, i-e.cur)
+ h := hashLen(cv, betterLongTableBits, betterLongLen)
+ e.longTable[h] = prevEntry{offset: i, prev: e.longTable[h].offset}
+ e.table[hashLen(cv>>8, betterShortTableBits, betterShortLen)] = tableEntry{val: uint32(cv >> 8), offset: i + 1}
+ }
+}
+
// ResetDict will reset and set a dictionary if not nil
func (e *betterFastEncoderDict) Reset(d *dict, singleBlock bool) {
e.resetBase(d, singleBlock)
if d == nil {
return
}
+ dictChanged := d != e.lastDict
// Init or copy dict table
- if len(e.dictTable) != len(e.table) || d.id != e.lastDictID {
+ if len(e.dictTable) != len(e.table) || dictChanged {
if len(e.dictTable) != len(e.table) {
e.dictTable = make([]tableEntry, len(e.table))
+ } else {
+ clear(e.dictTable)
}
end := int32(len(d.content)) - 8 + e.maxMatchOff
for i := e.maxMatchOff; i < end; i += 4 {
@@ -1133,14 +1150,15 @@ func (e *betterFastEncoderDict) Reset(d *dict, singleBlock bool) {
offset: i + 3,
}
}
- e.lastDictID = d.id
e.allDirty = true
}
- // Init or copy dict table
- if len(e.dictLongTable) != len(e.longTable) || d.id != e.lastDictID {
+ // Init or copy dict long table
+ if len(e.dictLongTable) != len(e.longTable) || dictChanged {
if len(e.dictLongTable) != len(e.longTable) {
e.dictLongTable = make([]prevEntry, len(e.longTable))
+ } else {
+ clear(e.dictLongTable)
}
if len(d.content) >= 8 {
cv := load6432(d.content, 0)
@@ -1162,9 +1180,9 @@ func (e *betterFastEncoderDict) Reset(d *dict, singleBlock bool) {
off++
}
}
- e.lastDictID = d.id
e.allDirty = true
}
+ e.lastDict = d
// Reset table to initial state
{
@@ -1225,6 +1243,10 @@ func (e *betterFastEncoderDict) Reset(d *dict, singleBlock bool) {
e.allDirty = false
}
+func (e *betterFastEncoderDict) ResetPrefix([]byte) {
+ panic("ResetPrefix not supported for dict encoders")
+}
+
func (e *betterFastEncoderDict) markLongShardDirty(entryNum uint32) {
e.longTableShardDirty[entryNum/betterLongTableShardSize] = true
}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_dfast.go b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go
index cf8cad00..712ba7ab 100644
--- a/vendor/github.com/klauspost/compress/zstd/enc_dfast.go
+++ b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go
@@ -1037,18 +1037,33 @@ func (e *doubleFastEncoder) Reset(d *dict, singleBlock bool) {
}
}
+func (e *doubleFastEncoder) ResetPrefix(prefix []byte) {
+ e.fastEncoder.ResetPrefix(prefix)
+ if len(prefix) < 8 {
+ return
+ }
+ end := e.cur + int32(len(prefix)) - 8
+ for i := e.cur + 1; i < end; i += 2 {
+ cv := load6432(prefix, i-e.cur)
+ e.longTable[hashLen(cv, dFastLongTableBits, dFastLongLen)] = tableEntry{val: uint32(cv), offset: i}
+ }
+}
+
// ResetDict will reset and set a dictionary if not nil
func (e *doubleFastEncoderDict) Reset(d *dict, singleBlock bool) {
allDirty := e.allDirty
+ dictChanged := d != e.lastDict
e.fastEncoderDict.Reset(d, singleBlock)
if d == nil {
return
}
// Init or copy dict table
- if len(e.dictLongTable) != len(e.longTable) || d.id != e.lastDictID {
+ if len(e.dictLongTable) != len(e.longTable) || dictChanged {
if len(e.dictLongTable) != len(e.longTable) {
e.dictLongTable = make([]tableEntry, len(e.longTable))
+ } else {
+ clear(e.dictLongTable)
}
if len(d.content) >= 8 {
cv := load6432(d.content, 0)
@@ -1065,7 +1080,6 @@ func (e *doubleFastEncoderDict) Reset(d *dict, singleBlock bool) {
}
}
}
- e.lastDictID = d.id
allDirty = true
}
// Reset table to initial state
@@ -1100,6 +1114,10 @@ func (e *doubleFastEncoderDict) Reset(d *dict, singleBlock bool) {
}
}
+func (e *doubleFastEncoderDict) ResetPrefix([]byte) {
+ panic("ResetPrefix not supported for dict encoders")
+}
+
func (e *doubleFastEncoderDict) markLongShardDirty(entryNum uint32) {
e.longTableShardDirty[entryNum/dLongTableShardSize] = true
}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_fast.go b/vendor/github.com/klauspost/compress/zstd/enc_fast.go
index 9180a3a5..06045e24 100644
--- a/vendor/github.com/klauspost/compress/zstd/enc_fast.go
+++ b/vendor/github.com/klauspost/compress/zstd/enc_fast.go
@@ -797,6 +797,19 @@ func (e *fastEncoder) Reset(d *dict, singleBlock bool) {
}
}
+func (e *fastEncoder) ResetPrefix(prefix []byte) {
+ e.resetBasePrefix(prefix)
+ if len(prefix) < 8 {
+ return
+ }
+ end := e.cur + int32(len(prefix)) - 8
+ // Index every 4th
+ for i := e.cur + 1; i < end; i += 4 {
+ cv := load6432(prefix, i-e.cur)
+ e.table[hashLen(cv, tableBits, tableFastHashLen)] = tableEntry{val: uint32(cv), offset: i}
+ }
+}
+
// ResetDict will reset and set a dictionary if not nil
func (e *fastEncoderDict) Reset(d *dict, singleBlock bool) {
e.resetBase(d, singleBlock)
@@ -805,9 +818,11 @@ func (e *fastEncoderDict) Reset(d *dict, singleBlock bool) {
}
// Init or copy dict table
- if len(e.dictTable) != len(e.table) || d.id != e.lastDictID {
+ if len(e.dictTable) != len(e.table) || d != e.lastDict {
if len(e.dictTable) != len(e.table) {
e.dictTable = make([]tableEntry, len(e.table))
+ } else {
+ clear(e.dictTable)
}
if true {
end := e.maxMatchOff + int32(len(d.content)) - 8
@@ -827,7 +842,7 @@ func (e *fastEncoderDict) Reset(d *dict, singleBlock bool) {
}
}
}
- e.lastDictID = d.id
+ e.lastDict = d
e.allDirty = true
}
@@ -864,6 +879,10 @@ func (e *fastEncoderDict) Reset(d *dict, singleBlock bool) {
e.allDirty = false
}
+func (e *fastEncoderDict) ResetPrefix([]byte) {
+ panic("ResetPrefix not supported for dict encoders")
+}
+
func (e *fastEncoderDict) markAllShardsDirty() {
e.allDirty = true
}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_jobs.go b/vendor/github.com/klauspost/compress/zstd/enc_jobs.go
new file mode 100644
index 00000000..95ce67ac
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/enc_jobs.go
@@ -0,0 +1,352 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "fmt"
+ rdebug "runtime/debug"
+ "sync"
+)
+
+type encJob struct {
+ prefix []byte // overlap from previous job (nil for first)
+ input []byte // job's own input data (swapped from filling)
+ last bool // last block of last job gets last=true
+ output []byte // compressed blocks (filled by worker)
+ err error // encoding error
+ done chan struct{} // closed when complete
+}
+
+type jobState struct {
+ jobSize int
+ overlapSize int
+ filling []byte // accumulates input up to jobSize
+ nextPrefix []byte // overlap prefix prepared for the next dispatched job
+
+ jobSeq int // next job sequence number
+
+ jobCh chan *encJob // dispatch to workers
+ resultCh chan *encJob // ordered results to flusher
+
+ workerWg sync.WaitGroup
+ flusherWg sync.WaitGroup
+
+ mu sync.Mutex
+ flushedSeq int // last flushed sequence number
+ cond *sync.Cond
+
+ flusherErr error
+ started bool
+
+ inputPool sync.Pool // *[]byte buffers of jobSize cap
+ outputPool sync.Pool // *[]byte buffers for compressed output
+ overlapPool sync.Pool // *[]byte buffers for overlap prefixes
+}
+
+func (e *Encoder) startJobWorkers() {
+ js := &e.state.jobs
+ n := e.o.concurrent
+ js.jobCh = make(chan *encJob, n)
+ js.resultCh = make(chan *encJob, n)
+ js.flushedSeq = 0
+ js.cond = sync.NewCond(&js.mu)
+
+ // Workers borrow encoders from the shared e.encoders pool per-job.
+ // Ensure the pool is initialized before any worker tries to borrow.
+ e.init.Do(e.initialize)
+
+ for range n {
+ js.workerWg.Add(1)
+ go e.jobWorker()
+ }
+ js.flusherWg.Add(1)
+ go e.jobFlusher()
+ js.started = true
+}
+
+func (e *Encoder) jobWorker() {
+ js := &e.state.jobs
+ defer js.workerWg.Done()
+ for job := range js.jobCh {
+ enc := <-e.encoders
+ e.compressJob(enc, job)
+ e.encoders <- enc
+ close(job.done)
+ }
+}
+
+func (e *Encoder) compressJob(enc encoder, job *encJob) {
+ defer func() {
+ if r := recover(); r != nil {
+ job.err = fmt.Errorf("panic in parallel job: %v", r)
+ rdebug.PrintStack()
+ }
+ }()
+
+ if len(job.prefix) > 0 {
+ enc.ResetPrefix(job.prefix)
+ } else {
+ enc.Reset(nil, false)
+ }
+
+ data := job.input
+ if len(data) == 0 && job.last {
+ blk := enc.Block()
+ blk.reset(nil)
+ blk.last = true
+ blk.encodeRaw(nil)
+ job.output = append(job.output, blk.output...)
+ return
+ }
+
+ blk := enc.Block()
+ for len(data) > 0 {
+ todo := data
+ if len(todo) > e.o.blockSize {
+ todo = todo[:e.o.blockSize]
+ }
+ data = data[len(todo):]
+
+ blk.pushOffsets()
+ enc.Encode(blk, todo)
+ blk.last = len(data) == 0 && job.last
+
+ err := blk.encode(todo, e.o.noEntropy, !e.o.allLitEntropy)
+ if err != nil {
+ job.err = err
+ return
+ }
+ job.output = append(job.output, blk.output...)
+ blk.reset(nil)
+ }
+}
+
+func (js *jobState) getInputBuf(size int) []byte {
+ if v := js.inputPool.Get(); v != nil {
+ bp := v.(*[]byte)
+ b := *bp
+ if cap(b) >= size {
+ return b[:0]
+ }
+ }
+ return make([]byte, 0, size)
+}
+
+func (js *jobState) putInputBuf(b []byte) {
+ if cap(b) > 0 {
+ b = b[:0]
+ js.inputPool.Put(&b)
+ }
+}
+
+func (js *jobState) getOutputBuf(size int) []byte {
+ if v := js.outputPool.Get(); v != nil {
+ bp := v.(*[]byte)
+ b := *bp
+ if cap(b) >= size {
+ return b[:0]
+ }
+ }
+ return make([]byte, 0, size)
+}
+
+func (js *jobState) putOutputBuf(b []byte) {
+ if cap(b) > 0 {
+ b = b[:0]
+ js.outputPool.Put(&b)
+ }
+}
+
+func (js *jobState) getOverlapBuf(size int) []byte {
+ if v := js.overlapPool.Get(); v != nil {
+ bp := v.(*[]byte)
+ b := *bp
+ if cap(b) >= size {
+ return b[:size]
+ }
+ }
+ return make([]byte, size)
+}
+
+func (js *jobState) putOverlapBuf(b []byte) {
+ if cap(b) > 0 {
+ b = b[:0]
+ js.overlapPool.Put(&b)
+ }
+}
+
+func (e *Encoder) jobFlusher() {
+ js := &e.state.jobs
+ defer js.flusherWg.Done()
+ for job := range js.resultCh {
+ <-job.done
+ // Worker has fully exited compressJob, so the prefix is no longer
+ // in use. Return it to the pool regardless of outcome.
+ if job.prefix != nil {
+ js.putOverlapBuf(job.prefix)
+ job.prefix = nil
+ }
+ if job.err != nil {
+ js.mu.Lock()
+ js.flusherErr = job.err
+ js.cond.Broadcast()
+ js.mu.Unlock()
+ for range js.resultCh {
+ }
+ return
+ }
+ if len(job.output) > 0 {
+ _, err := e.state.w.Write(job.output)
+ if err != nil {
+ js.mu.Lock()
+ js.flusherErr = err
+ js.cond.Broadcast()
+ js.mu.Unlock()
+ for range js.resultCh {
+ }
+ return
+ }
+ e.state.nWritten += int64(len(job.output))
+ }
+ // Return buffers to pools.
+ js.putInputBuf(job.input)
+ js.putOutputBuf(job.output)
+ job.input = nil
+ job.output = nil
+
+ js.mu.Lock()
+ js.flushedSeq++
+ js.cond.Broadcast()
+ js.mu.Unlock()
+ }
+}
+
+func (e *Encoder) shutdownJobWorkers() {
+ js := &e.state.jobs
+ if !js.started {
+ return
+ }
+ close(js.jobCh)
+ js.workerWg.Wait()
+ close(js.resultCh)
+ js.flusherWg.Wait()
+ js.started = false
+}
+
+// waitAllJobs blocks until all dispatched jobs have been flushed.
+func (e *Encoder) waitAllJobs() {
+ js := &e.state.jobs
+ if !js.started {
+ return
+ }
+ js.mu.Lock()
+ for js.flushedSeq < js.jobSeq && js.flusherErr == nil {
+ js.cond.Wait()
+ }
+ js.mu.Unlock()
+}
+
+func (e *Encoder) dispatchJob(final bool) error {
+ s := &e.state
+ js := &s.jobs
+
+ js.mu.Lock()
+ fErr := js.flusherErr
+ js.mu.Unlock()
+ if fErr != nil {
+ return fErr
+ }
+
+ if !s.headerWritten {
+ // Single-block optimization: fall through to encodeAll path.
+ if final && len(js.filling) > 0 && len(js.filling) <= e.o.blockSize {
+ s.current = e.encodeAll(s.encoder, js.filling, s.current[:0])
+ var n2 int
+ n2, s.err = s.w.Write(s.current)
+ if s.err != nil {
+ return s.err
+ }
+ s.nWritten += int64(n2)
+ s.nInput += int64(len(js.filling))
+ s.current = s.current[:0]
+ js.filling = js.filling[:0]
+ s.headerWritten = true
+ s.fullFrameWritten = true
+ s.eofWritten = true
+ return nil
+ }
+ if final && len(js.filling) == 0 && !e.o.fullZero {
+ s.headerWritten = true
+ s.fullFrameWritten = true
+ s.eofWritten = true
+ return nil
+ }
+
+ var tmp [maxHeaderSize]byte
+ fh := frameHeader{
+ ContentSize: uint64(s.frameContentSize),
+ WindowSize: uint32(s.encoder.WindowSize(s.frameContentSize)),
+ SingleSegment: false,
+ Checksum: e.o.crc,
+ DictID: 0,
+ }
+ dst := fh.appendTo(tmp[:0])
+ var n2 int
+ n2, s.err = s.w.Write(dst)
+ if s.err != nil {
+ return s.err
+ }
+ s.nWritten += int64(n2)
+ s.headerWritten = true
+ }
+
+ if len(js.filling) == 0 && !final {
+ return nil
+ }
+
+ if !js.started {
+ e.startJobWorkers()
+ }
+
+ // Estimate output size for pooled buffer.
+ outputEst := max(len(js.filling)/2, 512)
+
+ job := &encJob{
+ last: final,
+ done: make(chan struct{}),
+ output: js.getOutputBuf(outputEst),
+ }
+
+ // Each job owns its prefix slice; the flusher returns it to the pool
+ // after <-job.done, so workers and dispatch never share a buffer.
+ if js.nextPrefix != nil {
+ job.prefix = js.nextPrefix
+ js.nextPrefix = nil
+ }
+
+ // Build the next job's prefix from the tail of this job's input.
+ if !final && len(js.filling) > 0 {
+ overlapLen := min(js.overlapSize, len(js.filling))
+ np := js.getOverlapBuf(overlapLen)
+ copy(np, js.filling[len(js.filling)-overlapLen:])
+ js.nextPrefix = np
+ }
+
+ // Swap filling buffer into job — zero-copy for the input data.
+ job.input = js.filling
+ js.filling = js.getInputBuf(js.jobSize)
+
+ s.nInput += int64(len(job.input))
+ js.jobSeq++
+
+ if final {
+ s.eofWritten = true
+ }
+
+ js.resultCh <- job
+ js.jobCh <- job
+
+ return nil
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/encoder.go b/vendor/github.com/klauspost/compress/zstd/encoder.go
index 19e730ac..6ee96d87 100644
--- a/vendor/github.com/klauspost/compress/zstd/encoder.go
+++ b/vendor/github.com/klauspost/compress/zstd/encoder.go
@@ -38,6 +38,7 @@ type encoder interface {
WindowSize(size int64) int32
UseBlock(*blockEnc)
Reset(d *dict, singleBlock bool)
+ ResetPrefix(prefix []byte)
}
type encoderState struct {
@@ -60,6 +61,9 @@ type encoderState struct {
wg sync.WaitGroup
// This waitgroup indicates we have a block encoding/writing.
wWg sync.WaitGroup
+
+ // Parallel job state (used when concurrentBlocks is enabled).
+ jobs jobState
}
// NewWriter will create a new Zstandard encoder.
@@ -74,6 +78,9 @@ func NewWriter(w io.Writer, opts ...EOption) (*Encoder, error) {
return nil, err
}
}
+ if e.o.concurrentBlocks && (e.o.dict != nil || e.o.concurrent <= 1) {
+ e.o.concurrentBlocks = false
+ }
if w != nil {
e.Reset(w)
}
@@ -95,12 +102,31 @@ func (e *Encoder) initialize() {
// as a new, independent stream.
func (e *Encoder) Reset(w io.Writer) {
s := &e.state
+
+ if e.o.concurrentBlocks {
+ e.shutdownJobWorkers()
+ js := &s.jobs
+ js.jobSize = e.o.jobSize()
+ js.overlapSize = e.o.overlapSize()
+ // js.filling is allocated lazily on first Write/ReadFrom so callers
+ // that only use EncodeAll don't pay the (up to ~32 MB) jobSize cost.
+ js.filling = js.filling[:0]
+ if js.nextPrefix != nil {
+ js.putOverlapBuf(js.nextPrefix)
+ js.nextPrefix = nil
+ }
+ js.jobSeq = 0
+ js.flushedSeq = 0
+ js.flusherErr = nil
+ js.started = false
+ }
+
s.wg.Wait()
s.wWg.Wait()
if cap(s.filling) == 0 {
s.filling = make([]byte, 0, e.o.blockSize)
}
- if e.o.concurrent > 1 {
+ if e.o.concurrent > 1 && !e.o.concurrentBlocks {
if cap(s.current) == 0 {
s.current = make([]byte, 0, e.o.blockSize)
}
@@ -138,11 +164,21 @@ func (e *Encoder) Reset(w io.Writer) {
func (e *Encoder) ResetWithOptions(w io.Writer, opts ...EOption) error {
e.o.resetOpt = true
defer func() { e.o.resetOpt = false }()
+ hadDict := e.o.dict != nil
for _, o := range opts {
if err := o(&e.o); err != nil {
return err
}
}
+ hasDict := e.o.dict != nil
+ if e.o.concurrentBlocks && hasDict {
+ e.o.concurrentBlocks = false
+ }
+ if hadDict != hasDict {
+ // Dict presence changed — encoder type must be recreated.
+ e.state.encoder = nil
+ e.init = sync.Once{}
+ }
e.Reset(w)
return nil
}
@@ -169,6 +205,49 @@ func (e *Encoder) Write(p []byte) (n int, err error) {
if s.eofWritten {
return 0, ErrEncoderClosed
}
+ if e.o.concurrentBlocks {
+ return e.writeJobs(p)
+ }
+ return e.writeBlocks(p)
+}
+
+func (e *Encoder) writeJobs(p []byte) (n int, err error) {
+ s := &e.state
+ js := &s.jobs
+ jobSize := js.jobSize
+ if cap(js.filling) == 0 && len(p) > 0 {
+ js.filling = make([]byte, 0, jobSize)
+ }
+ for len(p) > 0 {
+ if len(p)+len(js.filling) < jobSize {
+ if e.o.crc {
+ _, _ = s.encoder.CRC().Write(p)
+ }
+ js.filling = append(js.filling, p...)
+ return n + len(p), nil
+ }
+ add := p
+ if len(p)+len(js.filling) > jobSize {
+ add = add[:jobSize-len(js.filling)]
+ }
+ if e.o.crc {
+ _, _ = s.encoder.CRC().Write(add)
+ }
+ js.filling = append(js.filling, add...)
+ p = p[len(add):]
+ n += len(add)
+ if len(js.filling) < jobSize {
+ return n, nil
+ }
+ if err := e.dispatchJob(false); err != nil {
+ return n, err
+ }
+ }
+ return n, nil
+}
+
+func (e *Encoder) writeBlocks(p []byte) (n int, err error) {
+ s := &e.state
for len(p) > 0 {
if len(p)+len(s.filling) < e.o.blockSize {
if e.o.crc {
@@ -367,6 +446,10 @@ func (e *Encoder) ReadFrom(r io.Reader) (n int64, err error) {
println("Using ReadFrom")
}
+ if e.o.concurrentBlocks {
+ return e.readFromJobs(r)
+ }
+
// Flush any current writes.
if len(e.state.filling) > 0 {
if err := e.nextBlock(false); err != nil {
@@ -380,7 +463,6 @@ func (e *Encoder) ReadFrom(r io.Reader) (n int64, err error) {
if e.o.crc {
_, _ = e.state.encoder.CRC().Write(src[:n2])
}
- // src is now the unfilled part...
src = src[n2:]
n += int64(n2)
switch err {
@@ -413,15 +495,63 @@ func (e *Encoder) ReadFrom(r io.Reader) (n int64, err error) {
}
}
+func (e *Encoder) readFromJobs(r io.Reader) (n int64, err error) {
+ js := &e.state.jobs
+ jobSize := js.jobSize
+
+ // Flush any current filling.
+ if len(js.filling) > 0 {
+ if err := e.dispatchJob(false); err != nil {
+ return 0, err
+ }
+ }
+
+ if cap(js.filling) < jobSize {
+ js.filling = make([]byte, 0, jobSize)
+ }
+ js.filling = js.filling[:jobSize]
+ src := js.filling
+ for {
+ n2, err := r.Read(src)
+ if e.o.crc {
+ _, _ = e.state.encoder.CRC().Write(src[:n2])
+ }
+ src = src[n2:]
+ n += int64(n2)
+ switch err {
+ case io.EOF:
+ js.filling = js.filling[:len(js.filling)-len(src)]
+ return n, nil
+ case nil:
+ default:
+ e.state.err = err
+ return n, err
+ }
+ if len(src) > 0 {
+ continue
+ }
+ if err = e.dispatchJob(false); err != nil {
+ return n, err
+ }
+ if cap(js.filling) < jobSize {
+ js.filling = make([]byte, 0, jobSize)
+ }
+ js.filling = js.filling[:jobSize]
+ src = js.filling
+ }
+}
+
// Flush will send the currently written data to output
// and block until everything has been written.
// This should only be used on rare occasions where pushing the currently queued data is critical.
func (e *Encoder) Flush() error {
s := &e.state
+ if e.o.concurrentBlocks {
+ return e.flushJobs()
+ }
if len(s.filling) > 0 {
err := e.nextBlock(false)
if err != nil {
- // Ignore Flush after Close.
if errors.Is(s.err, ErrEncoderClosed) {
return nil
}
@@ -431,7 +561,6 @@ func (e *Encoder) Flush() error {
s.wg.Wait()
s.wWg.Wait()
if s.err != nil {
- // Ignore Flush after Close.
if errors.Is(s.err, ErrEncoderClosed) {
return nil
}
@@ -440,6 +569,20 @@ func (e *Encoder) Flush() error {
return s.writeErr
}
+func (e *Encoder) flushJobs() error {
+ js := &e.state.jobs
+ if len(js.filling) > 0 {
+ if err := e.dispatchJob(false); err != nil {
+ return err
+ }
+ }
+ e.waitAllJobs()
+ js.mu.Lock()
+ fErr := js.flusherErr
+ js.mu.Unlock()
+ return fErr
+}
+
// Close will flush the final output and close the stream.
// The function will block until everything has been written.
// The Encoder can still be re-used after calling this.
@@ -448,6 +591,16 @@ func (e *Encoder) Close() error {
if s.encoder == nil {
return nil
}
+ if e.o.concurrentBlocks {
+ return e.closeJobs()
+ }
+ if s.w == nil {
+ if len(s.filling) == 0 && !s.headerWritten && !s.eofWritten && s.nInput == 0 {
+ return nil
+ }
+ return errors.New("zstd: encoder has no writer")
+ }
+
err := e.nextBlock(true)
if err != nil {
if errors.Is(s.err, ErrEncoderClosed) {
@@ -498,6 +651,68 @@ func (e *Encoder) Close() error {
return s.err
}
+func (e *Encoder) closeJobs() error {
+ s := &e.state
+ js := &s.jobs
+
+ if errors.Is(s.err, ErrEncoderClosed) {
+ return nil
+ }
+
+ if s.w == nil {
+ if len(js.filling) == 0 && !s.headerWritten && !s.eofWritten && s.nInput == 0 {
+ return nil
+ }
+ return errors.New("zstd: encoder has no writer")
+ }
+
+ if err := e.dispatchJob(true); err != nil {
+ e.shutdownJobWorkers()
+ if errors.Is(s.err, ErrEncoderClosed) {
+ return nil
+ }
+ return err
+ }
+
+ if s.frameContentSize > 0 && s.nInput != s.frameContentSize {
+ e.shutdownJobWorkers()
+ return fmt.Errorf("frame content size %d given, but %d bytes was written", s.frameContentSize, s.nInput)
+ }
+
+ if s.fullFrameWritten {
+ e.shutdownJobWorkers()
+ s.err = ErrEncoderClosed
+ return nil
+ }
+
+ e.shutdownJobWorkers()
+ if js.flusherErr != nil {
+ return js.flusherErr
+ }
+
+ // Write CRC
+ if e.o.crc {
+ var tmp [4]byte
+ _, s.err = s.w.Write(s.encoder.AppendCRC(tmp[:0]))
+ s.nWritten += 4
+ }
+
+ // Add padding
+ if s.err == nil && e.o.pad > 0 {
+ add := calcSkippableFrame(s.nWritten, int64(e.o.pad))
+ frame, err := skippableFrame(js.filling[:0], add, rand.Reader)
+ if err != nil {
+ return err
+ }
+ _, s.err = s.w.Write(frame)
+ }
+ if s.err == nil {
+ s.err = ErrEncoderClosed
+ return nil
+ }
+ return s.err
+}
+
// EncodeAll will encode all input in src and append it to dst.
// This function can be called concurrently, but each call will only run on a single goroutine.
// If empty input is given, nothing is returned, unless WithZeroFrames is specified.
diff --git a/vendor/github.com/klauspost/compress/zstd/encoder_options.go b/vendor/github.com/klauspost/compress/zstd/encoder_options.go
index 8e0f5cac..a8081496 100644
--- a/vendor/github.com/klauspost/compress/zstd/encoder_options.go
+++ b/vendor/github.com/klauspost/compress/zstd/encoder_options.go
@@ -14,22 +14,23 @@ type EOption func(*encoderOptions) error
// options retains accumulated state of multiple options.
type encoderOptions struct {
- resetOpt bool
- concurrent int
- level EncoderLevel
- single *bool
- pad int
- blockSize int
- windowSize int
- crc bool
- fullZero bool
- noEntropy bool
- allLitEntropy bool
- customWindow bool
- customALEntropy bool
- customBlockSize bool
- lowMem bool
- dict *dict
+ resetOpt bool
+ concurrent int
+ level EncoderLevel
+ single *bool
+ pad int
+ blockSize int
+ windowSize int
+ crc bool
+ fullZero bool
+ noEntropy bool
+ allLitEntropy bool
+ customWindow bool
+ customALEntropy bool
+ customBlockSize bool
+ lowMem bool
+ dict *dict
+ concurrentBlocks bool
}
func (o *encoderOptions) setDefault() {
@@ -42,6 +43,7 @@ func (o *encoderOptions) setDefault() {
level: SpeedDefault,
allLitEntropy: false,
lowMem: false,
+ fullZero: true,
}
}
@@ -332,6 +334,42 @@ func WithLowerEncoderMem(b bool) EOption {
}
}
+// WithConcurrentBlocks enables job-based parallel compression for streams.
+// When enabled and concurrent > 1, input is split into large sections (jobs)
+// that are compressed simultaneously by multiple goroutines.
+// Each non-first job receives an overlap prefix from the previous job for match context.
+// Output is flushed in order, producing a valid single-frame zstd stream.
+//
+// Currently disabled when used with dictionary encoding.
+// Cannot be changed with ResetWithOptions.
+func WithConcurrentBlocks(b bool) EOption {
+ return func(o *encoderOptions) error {
+ if o.resetOpt && b != o.concurrentBlocks {
+ return errors.New("WithConcurrentBlocks cannot be changed on Reset")
+ }
+ o.concurrentBlocks = b
+ return nil
+ }
+}
+
+// jobSize returns the input section size per parallel job.
+func (o *encoderOptions) jobSize() int {
+ s := max(o.windowSize*4, 512<<10)
+ return s
+}
+
+// overlapSize returns the overlap prefix size for parallel jobs.
+func (o *encoderOptions) overlapSize() int {
+ switch o.level {
+ case SpeedBestCompression:
+ return o.windowSize / 2
+ case SpeedBetterCompression:
+ return o.windowSize / 4
+ default:
+ return o.windowSize / 8
+ }
+}
+
// WithEncoderDict allows to register a dictionary that will be used for the encode.
//
// The slice dict must be in the [dictionary format] produced by
diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.s b/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.s
index bcde3986..deeadc49 100644
--- a/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.s
+++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.s
@@ -1,4 +1,4 @@
-// Code generated by command: go run gen_fse.go -out ../fse_decoder_amd64.s -pkg=zstd. DO NOT EDIT.
+// Code generated by command: go run gen_fse.go -out ../fse_decoder.s -arch amd64,arm64 -pkg=zstd. DO NOT EDIT.
//go:build !appengine && !noasm && gc && !noasm
diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder_arm64.s b/vendor/github.com/klauspost/compress/zstd/fse_decoder_arm64.s
new file mode 100644
index 00000000..77ee3913
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder_arm64.s
@@ -0,0 +1,153 @@
+// Code generated by command: go run gen_fse.go -out ../fse_decoder.s -arch amd64,arm64 -pkg=zstd. DO NOT EDIT.
+// EXPERIMENTAL arm64 output lowered from an amd64 avo program.
+
+//go:build arm64 && !appengine && !noasm && gc && !noasm
+
+// func buildDtable_asm(s *fseDecoder, ctx *buildDtableAsmContext) int
+TEXT ·buildDtable_asm(SB), $0-24
+ MOVD ctx+8(FP), R1
+ MOVD s+0(FP), R6
+
+ // Load values
+ MOVBU 4098(R6), R2
+ MOVD $0, R0
+ MOVD $1, R16
+ LSL R2, R16, R16
+ ORR R16, R0, R0
+ MOVD (R1), R3
+ MOVD 16(R1), R5
+ SUB $1, R0, R7
+ MOVD 8(R1), R1
+ MOVHU 4096(R6), R6
+
+ // End load values
+ // Init, lay down lowprob symbols
+ MOVD $0, R8
+ JMP init_main_loop_condition
+
+init_main_loop:
+ ADD R8<<1, R1, R15
+ MOVH (R15), R9
+ AND $0xffff, R9, R15
+ MOVD $-1, R16
+ AND $0xffff, R16, R16
+ CMP R16, R15
+ BNE do_not_update_high_threshold
+ ADD R7<<3, R5, R15
+ MOVB R8, 1(R15)
+ SUB $1, R7, R7
+ MOVD $0x0000000000000001, R9
+
+do_not_update_high_threshold:
+ ADD R8<<1, R3, R15
+ MOVH R9, (R15)
+ ADD $1, R8, R8
+
+init_main_loop_condition:
+ CMP R6, R8
+ BLT init_main_loop
+
+ // Spread symbols
+ // Calculate table step
+ MOVD R0, R8
+ LSR $0x01, R8, R8
+ MOVD R0, R9
+ LSR $0x03, R9, R9
+ ADD R9, R8, R8
+ ADD $3, R8, R8
+
+ // Fill add bits values
+ SUB $1, R0, R9
+ MOVD $0, R10
+ MOVD $0, R11
+ JMP spread_main_loop_condition
+
+spread_main_loop:
+ MOVD $0, R12
+ ADD R11<<1, R1, R15
+ MOVH (R15), R13
+ JMP spread_inner_loop_condition
+
+spread_inner_loop:
+ ADD R10<<3, R5, R15
+ MOVB R11, 1(R15)
+
+adjust_position:
+ ADD R8, R10, R10
+ AND R9, R10, R10
+ CMP R7, R10
+ BGT adjust_position
+ ADD $1, R12, R12
+
+spread_inner_loop_condition:
+ CMP R13, R12
+ BLT spread_inner_loop
+ ADD $1, R11, R11
+
+spread_main_loop_condition:
+ CMP R6, R11
+ BLT spread_main_loop
+ TST R10, R10
+ BEQ spread_check_ok
+ MOVD ctx+8(FP), R0
+ MOVD R10, 24(R0)
+ MOVD $+1, R16
+ MOVD R16, ret+16(FP)
+ RET
+
+spread_check_ok:
+ // Build Decoding table
+ MOVD $0, R6
+
+build_table_main_table:
+ ADD R6<<3, R5, R15
+ MOVBU 1(R15), R1
+ ADD R1<<1, R3, R15
+ MOVHU (R15), R7
+ ADD $1, R7, R8
+ ADD R1<<1, R3, R15
+ MOVH R8, (R15)
+ MOVD R7, R8
+ CLZ R8, R16
+ MOVD $63, R8
+ SUB R16, R8, R8
+ MOVD R2, R1
+ SUB R8, R1, R1
+ LSL R1, R7, R7
+ SUB R0, R7, R7
+ ADD R6<<3, R5, R15
+ MOVB R1, (R15)
+ ADD R6<<3, R5, R15
+ MOVH R7, 2(R15)
+ CMP R0, R7
+ BLE build_table_check1_ok
+ MOVD ctx+8(FP), R1
+ MOVD R7, 24(R1)
+ MOVD R0, 32(R1)
+ MOVD $+2, R16
+ MOVD R16, ret+16(FP)
+ RET
+
+build_table_check1_ok:
+ AND $0xff, R1, R15
+ AND $0xff, R1, R16
+ TST R16, R15
+ BNE build_table_check2_ok
+ AND $0xffff, R7, R15
+ AND $0xffff, R6, R16
+ CMP R16, R15
+ BNE build_table_check2_ok
+ MOVD ctx+8(FP), R0
+ MOVD R7, 24(R0)
+ MOVD R6, 32(R0)
+ MOVD $+3, R16
+ MOVD R16, ret+16(FP)
+ RET
+
+build_table_check2_ok:
+ ADD $1, R6, R6
+ CMP R0, R6
+ BLT build_table_main_table
+ MOVD $+0, R16
+ MOVD R16, ret+16(FP)
+ RET
diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.go b/vendor/github.com/klauspost/compress/zstd/fse_decoder_asm.go
similarity index 81%
rename from vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.go
rename to vendor/github.com/klauspost/compress/zstd/fse_decoder_asm.go
index d04a829b..4ffc7e3c 100644
--- a/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.go
+++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder_asm.go
@@ -1,5 +1,4 @@
-//go:build amd64 && !appengine && !noasm && gc
-// +build amd64,!appengine,!noasm,gc
+//go:build (amd64 || arm64) && !appengine && !noasm && gc
package zstd
@@ -7,6 +6,10 @@ import (
"fmt"
)
+// buildDtable_asm is generated by _generate/gen_fse.go and lowered to each
+// architecture (amd64 by goasm, arm64 by the avo arm64 lowering printer). The
+// Go side is identical across architectures, so it lives here.
+
type buildDtableAsmContext struct {
// inputs
stateTable *uint16
@@ -19,7 +22,7 @@ type buildDtableAsmContext struct {
errParam2 uint64
}
-// buildDtable_asm is an x86 assembly implementation of fseDecoder.buildDtable.
+// buildDtable_asm is an assembly implementation of fseDecoder.buildDtable.
// Function returns non-zero exit code on error.
//
//go:noescape
diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go b/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go
index 8adfebb0..38fd2ccb 100644
--- a/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go
+++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go
@@ -1,5 +1,4 @@
-//go:build !amd64 || appengine || !gc || noasm
-// +build !amd64 appengine !gc noasm
+//go:build (!amd64 && !arm64) || appengine || !gc || noasm
package zstd
diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_other.go b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_other.go
index 0be16cef..9576426e 100644
--- a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_other.go
+++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_other.go
@@ -1,5 +1,4 @@
//go:build (!amd64 && !arm64) || appengine || !gc || purego || noasm
-// +build !amd64,!arm64 appengine !gc purego noasm
package xxhash
diff --git a/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.go b/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.go
index f41932b7..1ed18927 100644
--- a/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.go
+++ b/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.go
@@ -1,5 +1,4 @@
//go:build amd64 && !appengine && !noasm && gc
-// +build amd64,!appengine,!noasm,gc
// Copyright 2019+ Klaus Post. All rights reserved.
// License information can be found in the LICENSE file.
diff --git a/vendor/github.com/klauspost/compress/zstd/matchlen_generic.go b/vendor/github.com/klauspost/compress/zstd/matchlen_generic.go
index bea1779e..379746c9 100644
--- a/vendor/github.com/klauspost/compress/zstd/matchlen_generic.go
+++ b/vendor/github.com/klauspost/compress/zstd/matchlen_generic.go
@@ -1,5 +1,4 @@
//go:build !amd64 || appengine || !gc || noasm
-// +build !amd64 appengine !gc noasm
// Copyright 2019+ Klaus Post. All rights reserved.
// License information can be found in the LICENSE file.
diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go
index 1f8c3cec..1281da88 100644
--- a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go
+++ b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go
@@ -1,324 +1,85 @@
//go:build amd64 && !appengine && !noasm && gc
-// +build amd64,!appengine,!noasm,gc
package zstd
import (
- "fmt"
- "io"
-
"github.com/klauspost/compress/internal/cpuinfo"
)
-type decodeSyncAsmContext struct {
- llTable []decSymbol
- mlTable []decSymbol
- ofTable []decSymbol
- llState uint64
- mlState uint64
- ofState uint64
- iteration int
- litRemain int
- out []byte
- outPosition int
- literals []byte
- litPosition int
- history []byte
- windowSize int
- ll int // set on error (not for all errors, please refer to _generate/gen.go)
- ml int // set on error (not for all errors, please refer to _generate/gen.go)
- mo int // set on error (not for all errors, please refer to _generate/gen.go)
-}
+// The shared decode/decodeSync/executeSimple wrappers and context structs live
+// in seqdec_asm.go; this file only declares the amd64 asm routines and the
+// dispatch helpers that pick the BMI2 / non-BMI2 (and 56-bit / safe) variant.
-// sequenceDecs_decodeSync_amd64 implements the main loop of sequenceDecs.decodeSync in x86 asm.
+// sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm.
//
// Please refer to seqdec_generic.go for the reference implementation.
//
//go:noescape
-func sequenceDecs_decodeSync_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
+func sequenceDecs_decode_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
-// sequenceDecs_decodeSync_bmi2 implements the main loop of sequenceDecs.decodeSync in x86 asm with BMI2 extensions.
+// sequenceDecs_decode_56_amd64 implements the main loop of sequenceDecs in x86 asm.
//
//go:noescape
-func sequenceDecs_decodeSync_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
+func sequenceDecs_decode_56_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
-// sequenceDecs_decodeSync_safe_amd64 does the same as above, but does not write more than output buffer.
+// sequenceDecs_decode_bmi2 implements the main loop of sequenceDecs in x86 asm with BMI2 extensions.
//
//go:noescape
-func sequenceDecs_decodeSync_safe_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
+func sequenceDecs_decode_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
-// sequenceDecs_decodeSync_safe_bmi2 does the same as above, but does not write more than output buffer.
+// sequenceDecs_decode_56_bmi2 implements the main loop of sequenceDecs in x86 asm with BMI2 extensions.
//
//go:noescape
-func sequenceDecs_decodeSync_safe_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
-
-// decode sequences from the stream with the provided history but without a dictionary.
-func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) {
- if len(s.dict) > 0 {
- return false, nil
- }
- if s.maxSyncLen == 0 && cap(s.out)-len(s.out) < maxCompressedBlockSize {
- return false, nil
- }
-
- // FIXME: Using unsafe memory copies leads to rare, random crashes
- // with fuzz testing. It is therefore disabled for now.
- const useSafe = true
- /*
- useSafe := false
- if s.maxSyncLen == 0 && cap(s.out)-len(s.out) < maxCompressedBlockSizeAlloc {
- useSafe = true
- }
- if s.maxSyncLen > 0 && cap(s.out)-len(s.out)-compressedBlockOverAlloc < int(s.maxSyncLen) {
- useSafe = true
- }
- if cap(s.literals) < len(s.literals)+compressedBlockOverAlloc {
- useSafe = true
- }
- */
-
- br := s.br
-
- maxBlockSize := min(s.windowSize, maxCompressedBlockSize)
-
- ctx := decodeSyncAsmContext{
- llTable: s.litLengths.fse.dt[:maxTablesize],
- mlTable: s.matchLengths.fse.dt[:maxTablesize],
- ofTable: s.offsets.fse.dt[:maxTablesize],
- llState: uint64(s.litLengths.state.state),
- mlState: uint64(s.matchLengths.state.state),
- ofState: uint64(s.offsets.state.state),
- iteration: s.nSeqs - 1,
- litRemain: len(s.literals),
- out: s.out,
- outPosition: len(s.out),
- literals: s.literals,
- windowSize: s.windowSize,
- history: hist,
- }
-
- s.seqSize = 0
- startSize := len(s.out)
+func sequenceDecs_decode_56_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
- var errCode int
+// decodeAsm runs the sequenceDecs decode loop, choosing the BMI2 / 56-bit variant.
+func decodeAsm(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext, lte56bits bool) int {
if cpuinfo.HasBMI2() {
- if useSafe {
- errCode = sequenceDecs_decodeSync_safe_bmi2(s, br, &ctx)
- } else {
- errCode = sequenceDecs_decodeSync_bmi2(s, br, &ctx)
- }
- } else {
- if useSafe {
- errCode = sequenceDecs_decodeSync_safe_amd64(s, br, &ctx)
- } else {
- errCode = sequenceDecs_decodeSync_amd64(s, br, &ctx)
- }
- }
- switch errCode {
- case noError:
- break
-
- case errorMatchLenOfsMismatch:
- return true, fmt.Errorf("zero matchoff and matchlen (%d) > 0", ctx.ml)
-
- case errorMatchLenTooBig:
- return true, fmt.Errorf("match len (%d) bigger than max allowed length", ctx.ml)
-
- case errorMatchOffTooBig:
- return true, fmt.Errorf("match offset (%d) bigger than current history (%d)",
- ctx.mo, ctx.outPosition+len(hist)-startSize)
-
- case errorNotEnoughLiterals:
- return true, fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available",
- ctx.ll, ctx.litRemain+ctx.ll)
-
- case errorOverread:
- return true, io.ErrUnexpectedEOF
-
- case errorNotEnoughSpace:
- size := ctx.outPosition + ctx.ll + ctx.ml
- if debugDecoder {
- println("msl:", s.maxSyncLen, "cap", cap(s.out), "bef:", startSize, "sz:", size-startSize, "mbs:", maxBlockSize, "outsz:", cap(s.out)-startSize)
+ if lte56bits {
+ return sequenceDecs_decode_56_bmi2(s, br, ctx)
}
- return true, fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
-
- default:
- return true, fmt.Errorf("sequenceDecs_decode returned erroneous code %d", errCode)
- }
-
- s.seqSize += ctx.litRemain
- if s.seqSize > maxBlockSize {
- return true, fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
+ return sequenceDecs_decode_bmi2(s, br, ctx)
}
- err := br.close()
- if err != nil {
- printf("Closing sequences: %v, %+v\n", err, *br)
- return true, err
+ if lte56bits {
+ return sequenceDecs_decode_56_amd64(s, br, ctx)
}
-
- s.literals = s.literals[ctx.litPosition:]
- t := ctx.outPosition
- s.out = s.out[:t]
-
- // Add final literals
- s.out = append(s.out, s.literals...)
- if debugDecoder {
- t += len(s.literals)
- if t != len(s.out) {
- panic(fmt.Errorf("length mismatch, want %d, got %d", len(s.out), t))
- }
- }
-
- return true, nil
+ return sequenceDecs_decode_amd64(s, br, ctx)
}
-// --------------------------------------------------------------------------------
-
-type decodeAsmContext struct {
- llTable []decSymbol
- mlTable []decSymbol
- ofTable []decSymbol
- llState uint64
- mlState uint64
- ofState uint64
- iteration int
- seqs []seqVals
- litRemain int
-}
-
-const noError = 0
-
-// error reported when mo == 0 && ml > 0
-const errorMatchLenOfsMismatch = 1
-
-// error reported when ml > maxMatchLen
-const errorMatchLenTooBig = 2
-
-// error reported when mo > available history or mo > s.windowSize
-const errorMatchOffTooBig = 3
-
-// error reported when the sum of literal lengths exeeceds the literal buffer size
-const errorNotEnoughLiterals = 4
-
-// error reported when capacity of `out` is too small
-const errorNotEnoughSpace = 5
-
-// error reported when bits are overread.
-const errorOverread = 6
-
-// sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm.
+// sequenceDecs_decodeSync_amd64 implements the main loop of sequenceDecs.decodeSync in x86 asm.
//
// Please refer to seqdec_generic.go for the reference implementation.
//
//go:noescape
-func sequenceDecs_decode_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
+func sequenceDecs_decodeSync_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
-// sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm.
-//
-// Please refer to seqdec_generic.go for the reference implementation.
+// sequenceDecs_decodeSync_bmi2 implements the main loop of sequenceDecs.decodeSync in x86 asm with BMI2 extensions.
//
//go:noescape
-func sequenceDecs_decode_56_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
+func sequenceDecs_decodeSync_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
-// sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm with BMI2 extensions.
+// sequenceDecs_decodeSync_safe_amd64 does the same as above, but does not write more than output buffer.
//
//go:noescape
-func sequenceDecs_decode_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
+func sequenceDecs_decodeSync_safe_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
-// sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm with BMI2 extensions.
+// sequenceDecs_decodeSync_safe_bmi2 does the same as above, but does not write more than output buffer.
//
//go:noescape
-func sequenceDecs_decode_56_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
-
-// decode sequences from the stream without the provided history.
-func (s *sequenceDecs) decode(seqs []seqVals) error {
- br := s.br
-
- maxBlockSize := min(s.windowSize, maxCompressedBlockSize)
-
- ctx := decodeAsmContext{
- llTable: s.litLengths.fse.dt[:maxTablesize],
- mlTable: s.matchLengths.fse.dt[:maxTablesize],
- ofTable: s.offsets.fse.dt[:maxTablesize],
- llState: uint64(s.litLengths.state.state),
- mlState: uint64(s.matchLengths.state.state),
- ofState: uint64(s.offsets.state.state),
- seqs: seqs,
- iteration: len(seqs) - 1,
- litRemain: len(s.literals),
- }
-
- if debugDecoder {
- println("decode: decoding", len(seqs), "sequences", br.remain(), "bits remain on stream")
- }
+func sequenceDecs_decodeSync_safe_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
- s.seqSize = 0
- lte56bits := s.maxBits+s.offsets.fse.actualTableLog+s.matchLengths.fse.actualTableLog+s.litLengths.fse.actualTableLog <= 56
- var errCode int
+// decodeSyncAsm runs the decodeSync loop, choosing the BMI2 / safe variant.
+func decodeSyncAsm(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext, safe bool) int {
if cpuinfo.HasBMI2() {
- if lte56bits {
- errCode = sequenceDecs_decode_56_bmi2(s, br, &ctx)
- } else {
- errCode = sequenceDecs_decode_bmi2(s, br, &ctx)
- }
- } else {
- if lte56bits {
- errCode = sequenceDecs_decode_56_amd64(s, br, &ctx)
- } else {
- errCode = sequenceDecs_decode_amd64(s, br, &ctx)
+ if safe {
+ return sequenceDecs_decodeSync_safe_bmi2(s, br, ctx)
}
+ return sequenceDecs_decodeSync_bmi2(s, br, ctx)
}
- if errCode != 0 {
- i := len(seqs) - ctx.iteration - 1
- switch errCode {
- case errorMatchLenOfsMismatch:
- ml := ctx.seqs[i].ml
- return fmt.Errorf("zero matchoff and matchlen (%d) > 0", ml)
-
- case errorMatchLenTooBig:
- ml := ctx.seqs[i].ml
- return fmt.Errorf("match len (%d) bigger than max allowed length", ml)
-
- case errorNotEnoughLiterals:
- ll := ctx.seqs[i].ll
- return fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available", ll, ctx.litRemain+ll)
- case errorOverread:
- return io.ErrUnexpectedEOF
- }
-
- return fmt.Errorf("sequenceDecs_decode_amd64 returned erroneous code %d", errCode)
+ if safe {
+ return sequenceDecs_decodeSync_safe_amd64(s, br, ctx)
}
-
- if ctx.litRemain < 0 {
- return fmt.Errorf("literal count is too big: total available %d, total requested %d",
- len(s.literals), len(s.literals)-ctx.litRemain)
- }
-
- s.seqSize += ctx.litRemain
- if s.seqSize > maxBlockSize {
- return fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
- }
- if debugDecoder {
- println("decode: ", br.remain(), "bits remain on stream. code:", errCode)
- }
- err := br.close()
- if err != nil {
- printf("Closing sequences: %v, %+v\n", err, *br)
- }
- return err
-}
-
-// --------------------------------------------------------------------------------
-
-type executeAsmContext struct {
- seqs []seqVals
- seqIndex int
- out []byte
- history []byte
- literals []byte
- outPosition int
- litPosition int
- windowSize int
+ return sequenceDecs_decodeSync_amd64(s, br, ctx)
}
// sequenceDecs_executeSimple_amd64 implements the main loop of sequenceDecs.executeSimple in x86 asm.
@@ -335,54 +96,10 @@ func sequenceDecs_executeSimple_amd64(ctx *executeAsmContext) bool
//go:noescape
func sequenceDecs_executeSimple_safe_amd64(ctx *executeAsmContext) bool
-// executeSimple handles cases when dictionary is not used.
-func (s *sequenceDecs) executeSimple(seqs []seqVals, hist []byte) error {
- // Ensure we have enough output size...
- if len(s.out)+s.seqSize+compressedBlockOverAlloc > cap(s.out) {
- addBytes := s.seqSize + len(s.out) + compressedBlockOverAlloc
- s.out = append(s.out, make([]byte, addBytes)...)
- s.out = s.out[:len(s.out)-addBytes]
- }
-
- if debugDecoder {
- printf("Execute %d seqs with literals: %d into %d bytes\n", len(seqs), len(s.literals), s.seqSize)
- }
-
- var t = len(s.out)
- out := s.out[:t+s.seqSize]
-
- ctx := executeAsmContext{
- seqs: seqs,
- seqIndex: 0,
- out: out,
- history: hist,
- outPosition: t,
- litPosition: 0,
- literals: s.literals,
- windowSize: s.windowSize,
+// executeSimpleAsm runs the executeSimple loop, choosing the safe variant.
+func executeSimpleAsm(ctx *executeAsmContext, safe bool) bool {
+ if safe {
+ return sequenceDecs_executeSimple_safe_amd64(ctx)
}
- var ok bool
- if cap(s.literals) < len(s.literals)+compressedBlockOverAlloc {
- ok = sequenceDecs_executeSimple_safe_amd64(&ctx)
- } else {
- ok = sequenceDecs_executeSimple_amd64(&ctx)
- }
- if !ok {
- return fmt.Errorf("match offset (%d) bigger than current history (%d)",
- seqs[ctx.seqIndex].mo, ctx.outPosition+len(hist))
- }
- s.literals = s.literals[ctx.litPosition:]
- t = ctx.outPosition
-
- // Add final literals
- copy(out[t:], s.literals)
- if debugDecoder {
- t += len(s.literals)
- if t != len(out) {
- panic(fmt.Errorf("length mismatch, want %d, got %d, ss: %d", len(out), t, s.seqSize))
- }
- }
- s.out = out
-
- return nil
+ return sequenceDecs_executeSimple_amd64(ctx)
}
diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s
index a708ca6d..4d3188ff 100644
--- a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s
+++ b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s
@@ -1,4 +1,4 @@
-// Code generated by command: go run gen.go -out ../seqdec_amd64.s -pkg=zstd. DO NOT EDIT.
+// Code generated by command: go run gen.go -out ../seqdec.s -arch amd64,arm64 -pkg=zstd. DO NOT EDIT.
//go:build !appengine && !noasm && gc && !noasm
@@ -2081,7 +2081,7 @@ sequenceDecs_decodeSync_amd64_match_len_ofs_ok:
MOVQ 16(SP), R13
// Check if we have enough space in s.out
- LEAQ (AX)(R13*1), R14
+ LEAQ 16(AX)(R13*1), R14
ADDQ R10, R14
CMPQ R14, 32(SP)
JA error_not_enough_space
@@ -2601,7 +2601,7 @@ sequenceDecs_decodeSync_bmi2_match_len_ofs_ok:
MOVQ 16(SP), R13
// Check if we have enough space in s.out
- LEAQ (CX)(R13*1), R14
+ LEAQ 16(CX)(R13*1), R14
ADDQ R9, R14
CMPQ R14, 32(SP)
JA error_not_enough_space
diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_arm64.go b/vendor/github.com/klauspost/compress/zstd/seqdec_arm64.go
new file mode 100644
index 00000000..5ad262ac
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/seqdec_arm64.go
@@ -0,0 +1,70 @@
+//go:build arm64 && !appengine && !noasm && gc
+
+package zstd
+
+// The shared decode/decodeSync/executeSimple wrappers and context structs live
+// in seqdec_asm.go; this file only declares the arm64 asm routines (generated
+// by the avo arm64 lowering printer) and the dispatch helpers. arm64 has no
+// BMI2, so each helper selects only between the 56-bit / safe variants.
+
+// sequenceDecs_decode_arm64 implements the main loop of sequenceDecs in arm64 asm.
+//
+// Please refer to seqdec_generic.go for the reference implementation.
+//
+//go:noescape
+func sequenceDecs_decode_arm64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
+
+// sequenceDecs_decode_56_arm64 implements the main loop of sequenceDecs in arm64 asm.
+//
+//go:noescape
+func sequenceDecs_decode_56_arm64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
+
+// decodeAsm runs the sequenceDecs decode loop, choosing the 56-bit variant.
+func decodeAsm(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext, lte56bits bool) int {
+ if lte56bits {
+ return sequenceDecs_decode_56_arm64(s, br, ctx)
+ }
+ return sequenceDecs_decode_arm64(s, br, ctx)
+}
+
+// sequenceDecs_decodeSync_arm64 implements the main loop of sequenceDecs.decodeSync in arm64 asm.
+//
+// Please refer to seqdec_generic.go for the reference implementation.
+//
+//go:noescape
+func sequenceDecs_decodeSync_arm64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
+
+// sequenceDecs_decodeSync_safe_arm64 does the same as above, but does not write more than output buffer.
+//
+//go:noescape
+func sequenceDecs_decodeSync_safe_arm64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
+
+// decodeSyncAsm runs the decodeSync loop, choosing the safe variant.
+func decodeSyncAsm(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext, safe bool) int {
+ if safe {
+ return sequenceDecs_decodeSync_safe_arm64(s, br, ctx)
+ }
+ return sequenceDecs_decodeSync_arm64(s, br, ctx)
+}
+
+// sequenceDecs_executeSimple_arm64 implements the main loop of sequenceDecs.executeSimple in arm64 asm.
+//
+// Returns false if a match offset is too big.
+//
+// Please refer to seqdec_generic.go for the reference implementation.
+//
+//go:noescape
+func sequenceDecs_executeSimple_arm64(ctx *executeAsmContext) bool
+
+// Same as above, but with safe memcopies
+//
+//go:noescape
+func sequenceDecs_executeSimple_safe_arm64(ctx *executeAsmContext) bool
+
+// executeSimpleAsm runs the executeSimple loop, choosing the safe variant.
+func executeSimpleAsm(ctx *executeAsmContext, safe bool) bool {
+ if safe {
+ return sequenceDecs_executeSimple_safe_arm64(ctx)
+ }
+ return sequenceDecs_executeSimple_arm64(ctx)
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_arm64.s b/vendor/github.com/klauspost/compress/zstd/seqdec_arm64.s
new file mode 100644
index 00000000..6f54ef21
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/seqdec_arm64.s
@@ -0,0 +1,2750 @@
+// Code generated by command: go run gen.go -out ../seqdec.s -arch amd64,arm64 -pkg=zstd. DO NOT EDIT.
+// EXPERIMENTAL arm64 output lowered from an amd64 avo program.
+
+//go:build arm64 && !appengine && !noasm && gc && !noasm
+
+// func sequenceDecs_decode_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
+// Requires: CMOV
+TEXT ·sequenceDecs_decode_arm64(SB), $8-32
+ MOVD br+8(FP), R1
+ MOVD 24(R1), R2
+ MOVBU 40(R1), R3
+ MOVD (R1), R0
+ MOVD 32(R1), R5
+ ADD R5, R0, R0
+ MOVD R0, 8(RSP)
+ MOVD ctx+16(FP), R0
+ MOVD 72(R0), R6
+ MOVD 80(R0), R7
+ MOVD 88(R0), R8
+ MOVD 104(R0), R9
+ MOVD s+0(FP), R0
+ MOVD 144(R0), R10
+ MOVD 152(R0), R11
+ MOVD 160(R0), R12
+
+sequenceDecs_decode_amd64_main_loop:
+ MOVD 8(RSP), R13
+
+ // Fill bitreader to have enough for the offset and match length.
+ CMP $0x08, R5
+ BLT sequenceDecs_decode_amd64_fill_byte_by_byte
+ MOVD R3, R0
+ LSR $0x03, R0, R0
+ SUB R0, R13, R13
+ MOVD (R13), R2
+ SUB R0, R5, R5
+ AND $0x07, R3, R3
+ JMP sequenceDecs_decode_amd64_fill_end
+
+sequenceDecs_decode_amd64_fill_byte_by_byte:
+ CMP $0x00, R5
+ BLE sequenceDecs_decode_amd64_fill_check_overread
+ CMP $0x07, R3
+ BLE sequenceDecs_decode_amd64_fill_end
+ LSL $0x08, R2, R2
+ SUB $0x01, R13, R13
+ SUB $0x01, R5, R5
+ SUB $0x08, R3, R3
+ MOVBU (R13), R0
+ ORR R0, R2, R2
+ JMP sequenceDecs_decode_amd64_fill_byte_by_byte
+
+sequenceDecs_decode_amd64_fill_check_overread:
+ CMP $0x40, R3
+ BHI error_overread
+
+sequenceDecs_decode_amd64_fill_end:
+ // Update offset
+ MOVD R8, R0
+ MOVD R3, R1
+ MOVD R2, R14
+ LSL R1, R14, R14
+ UBFX $8, R0, $8, R16
+ BFI $0, R16, $8, R1
+ LSR $0x20, R0, R0
+ TST R1, R1
+ BEQ sequenceDecs_decode_amd64_of_update_zero
+ ADD R1, R3, R3
+ CMP $0x40, R3
+ BHI sequenceDecs_decode_amd64_of_update_zero
+ CMP $0x40, R1
+ BHS sequenceDecs_decode_amd64_of_update_zero
+ NEG R1, R1
+ LSR R1, R14, R14
+ ADD R14, R0, R0
+
+sequenceDecs_decode_amd64_of_update_zero:
+ MOVD R0, 16(R9)
+
+ // Update match length
+ MOVD R7, R0
+ MOVD R3, R1
+ MOVD R2, R14
+ LSL R1, R14, R14
+ UBFX $8, R0, $8, R16
+ BFI $0, R16, $8, R1
+ LSR $0x20, R0, R0
+ TST R1, R1
+ BEQ sequenceDecs_decode_amd64_ml_update_zero
+ ADD R1, R3, R3
+ CMP $0x40, R3
+ BHI sequenceDecs_decode_amd64_ml_update_zero
+ CMP $0x40, R1
+ BHS sequenceDecs_decode_amd64_ml_update_zero
+ NEG R1, R1
+ LSR R1, R14, R14
+ ADD R14, R0, R0
+
+sequenceDecs_decode_amd64_ml_update_zero:
+ MOVD R0, 8(R9)
+
+ // Fill bitreader to have enough for the remaining
+ CMP $0x08, R5
+ BLT sequenceDecs_decode_amd64_fill_2_byte_by_byte
+ MOVD R3, R0
+ LSR $0x03, R0, R0
+ SUB R0, R13, R13
+ MOVD (R13), R2
+ SUB R0, R5, R5
+ AND $0x07, R3, R3
+ JMP sequenceDecs_decode_amd64_fill_2_end
+
+sequenceDecs_decode_amd64_fill_2_byte_by_byte:
+ CMP $0x00, R5
+ BLE sequenceDecs_decode_amd64_fill_2_check_overread
+ CMP $0x07, R3
+ BLE sequenceDecs_decode_amd64_fill_2_end
+ LSL $0x08, R2, R2
+ SUB $0x01, R13, R13
+ SUB $0x01, R5, R5
+ SUB $0x08, R3, R3
+ MOVBU (R13), R0
+ ORR R0, R2, R2
+ JMP sequenceDecs_decode_amd64_fill_2_byte_by_byte
+
+sequenceDecs_decode_amd64_fill_2_check_overread:
+ CMP $0x40, R3
+ BHI error_overread
+
+sequenceDecs_decode_amd64_fill_2_end:
+ // Update literal length
+ MOVD R6, R0
+ MOVD R3, R1
+ MOVD R2, R14
+ LSL R1, R14, R14
+ UBFX $8, R0, $8, R16
+ BFI $0, R16, $8, R1
+ LSR $0x20, R0, R0
+ TST R1, R1
+ BEQ sequenceDecs_decode_amd64_ll_update_zero
+ ADD R1, R3, R3
+ CMP $0x40, R3
+ BHI sequenceDecs_decode_amd64_ll_update_zero
+ CMP $0x40, R1
+ BHS sequenceDecs_decode_amd64_ll_update_zero
+ NEG R1, R1
+ LSR R1, R14, R14
+ ADD R14, R0, R0
+
+sequenceDecs_decode_amd64_ll_update_zero:
+ MOVD R0, (R9)
+
+ // Fill bitreader for state updates
+ MOVD R13, 8(RSP)
+ MOVD R8, R0
+ LSR $0x08, R0, R0
+ MOVBU R0, R0
+ MOVD ctx+16(FP), R1
+ MOVD 96(R1), R16
+ CMP $0x00, R16
+ BEQ sequenceDecs_decode_amd64_skip_update
+
+ // Update Literal Length State
+ MOVBU R6, R13
+ LSRW $0x10, R6, R6
+ ADD R13, R3, R1
+ MOVD R2, R14
+ MOVD R1, R3
+ NEG R1, R16
+ ROR R16, R14, R14
+ MOVD $0x00000001, R4
+ BFI $0, R13, $8, R1
+ LSLW R1, R4, R4
+ SUBW $1, R4, R4
+ AND R4, R14, R14
+ ADD R14, R6, R6
+
+ // Load ctx.llTable
+ MOVD ctx+16(FP), R1
+ MOVD (R1), R1
+ ADD R6<<3, R1, R15
+ MOVD (R15), R6
+
+ // Update Match Length State
+ MOVBU R7, R13
+ LSRW $0x10, R7, R7
+ ADD R13, R3, R1
+ MOVD R2, R14
+ MOVD R1, R3
+ NEG R1, R16
+ ROR R16, R14, R14
+ MOVD $0x00000001, R4
+ BFI $0, R13, $8, R1
+ LSLW R1, R4, R4
+ SUBW $1, R4, R4
+ AND R4, R14, R14
+ ADD R14, R7, R7
+
+ // Load ctx.mlTable
+ MOVD ctx+16(FP), R1
+ MOVD 24(R1), R1
+ ADD R7<<3, R1, R15
+ MOVD (R15), R7
+
+ // Update Offset State
+ MOVBU R8, R13
+ LSRW $0x10, R8, R8
+ ADD R13, R3, R1
+ MOVD R2, R14
+ MOVD R1, R3
+ NEG R1, R16
+ ROR R16, R14, R14
+ MOVD $0x00000001, R4
+ BFI $0, R13, $8, R1
+ LSLW R1, R4, R4
+ SUBW $1, R4, R4
+ AND R4, R14, R14
+ ADD R14, R8, R8
+
+ // Load ctx.ofTable
+ MOVD ctx+16(FP), R1
+ MOVD 48(R1), R1
+ ADD R8<<3, R1, R15
+ MOVD (R15), R8
+
+sequenceDecs_decode_amd64_skip_update:
+ // Adjust offset
+ MOVD 16(R9), R1
+ CMP $0x01, R0
+ BLS sequenceDecs_decode_amd64_adjust_offsetB_1_or_0
+ MOVD R11, R12
+ MOVD R10, R11
+ MOVD R1, R10
+ JMP sequenceDecs_decode_amd64_after_adjust
+
+sequenceDecs_decode_amd64_adjust_offsetB_1_or_0:
+ MOVD (R9), R16
+ CMP $0x00000000, R16
+ BNE sequenceDecs_decode_amd64_adjust_offset_maybezero
+ ADD $1, R1, R1
+ JMP sequenceDecs_decode_amd64_adjust_offset_nonzero
+
+sequenceDecs_decode_amd64_adjust_offset_maybezero:
+ TST R1, R1
+ BNE sequenceDecs_decode_amd64_adjust_offset_nonzero
+ MOVD R10, R1
+ JMP sequenceDecs_decode_amd64_after_adjust
+
+sequenceDecs_decode_amd64_adjust_offset_nonzero:
+ CMP $0x01, R1
+ BLO sequenceDecs_decode_amd64_adjust_zero
+ BEQ sequenceDecs_decode_amd64_adjust_one
+ CMP $0x02, R1
+ BHI sequenceDecs_decode_amd64_adjust_three
+ JMP sequenceDecs_decode_amd64_adjust_two
+
+sequenceDecs_decode_amd64_adjust_zero:
+ MOVD R10, R0
+ JMP sequenceDecs_decode_amd64_adjust_test_temp_valid
+
+sequenceDecs_decode_amd64_adjust_one:
+ MOVD R11, R0
+ JMP sequenceDecs_decode_amd64_adjust_test_temp_valid
+
+sequenceDecs_decode_amd64_adjust_two:
+ MOVD R12, R0
+ JMP sequenceDecs_decode_amd64_adjust_test_temp_valid
+
+sequenceDecs_decode_amd64_adjust_three:
+ SUB $1, R10, R0
+
+sequenceDecs_decode_amd64_adjust_test_temp_valid:
+ TST R0, R0
+ BNE sequenceDecs_decode_amd64_adjust_temp_valid
+ MOVD $0x00000001, R0
+
+sequenceDecs_decode_amd64_adjust_temp_valid:
+ CMP $0x01, R1
+ CSEL NE, R11, R12, R12
+ MOVD R10, R11
+ MOVD R0, R10
+ MOVD R0, R1
+
+sequenceDecs_decode_amd64_after_adjust:
+ MOVD R1, 16(R9)
+
+ // Check values
+ MOVD 8(R9), R0
+ MOVD (R9), R13
+ ADD R13, R0, R14
+ MOVD s+0(FP), R4
+ MOVD 256(R4), R16
+ ADD R14, R16, R16
+ MOVD R16, 256(R4)
+ MOVD ctx+16(FP), R14
+ MOVD 128(R14), R16
+ SUBS R13, R16, R16
+ MOVD R16, 128(R14)
+ BMI error_not_enough_literals
+ CMP $0x00020002, R0
+ BHI sequenceDecs_decode_amd64_error_match_len_too_big
+ TST R1, R1
+ BNE sequenceDecs_decode_amd64_match_len_ofs_ok
+ TST R0, R0
+ BNE sequenceDecs_decode_amd64_error_match_len_ofs_mismatch
+
+sequenceDecs_decode_amd64_match_len_ofs_ok:
+ ADD $0x18, R9, R9
+ MOVD ctx+16(FP), R0
+ MOVD 96(R0), R16
+ SUBS $1, R16, R16
+ MOVD R16, 96(R0)
+ BPL sequenceDecs_decode_amd64_main_loop
+ MOVD s+0(FP), R0
+ MOVD R10, 144(R0)
+ MOVD R11, 152(R0)
+ MOVD R12, 160(R0)
+ MOVD br+8(FP), R0
+ MOVD R2, 24(R0)
+ MOVB R3, 40(R0)
+ MOVD R5, 32(R0)
+
+ // Return success
+ MOVD $0x00000000, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with match length error
+sequenceDecs_decode_amd64_error_match_len_ofs_mismatch:
+ MOVD $0x00000001, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with match too long error
+sequenceDecs_decode_amd64_error_match_len_too_big:
+ MOVD $0x00000002, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with match offset too long error
+ MOVD $0x00000003, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with not enough literals error
+error_not_enough_literals:
+ MOVD $0x00000004, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with overread error
+error_overread:
+ MOVD $0x00000006, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+// func sequenceDecs_decode_56_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
+// Requires: CMOV
+TEXT ·sequenceDecs_decode_56_arm64(SB), $8-32
+ MOVD br+8(FP), R1
+ MOVD 24(R1), R2
+ MOVBU 40(R1), R3
+ MOVD (R1), R0
+ MOVD 32(R1), R5
+ ADD R5, R0, R0
+ MOVD R0, 8(RSP)
+ MOVD ctx+16(FP), R0
+ MOVD 72(R0), R6
+ MOVD 80(R0), R7
+ MOVD 88(R0), R8
+ MOVD 104(R0), R9
+ MOVD s+0(FP), R0
+ MOVD 144(R0), R10
+ MOVD 152(R0), R11
+ MOVD 160(R0), R12
+
+sequenceDecs_decode_56_amd64_main_loop:
+ MOVD 8(RSP), R13
+
+ // Fill bitreader to have enough for the offset and match length.
+ CMP $0x08, R5
+ BLT sequenceDecs_decode_56_amd64_fill_byte_by_byte
+ MOVD R3, R0
+ LSR $0x03, R0, R0
+ SUB R0, R13, R13
+ MOVD (R13), R2
+ SUB R0, R5, R5
+ AND $0x07, R3, R3
+ JMP sequenceDecs_decode_56_amd64_fill_end
+
+sequenceDecs_decode_56_amd64_fill_byte_by_byte:
+ CMP $0x00, R5
+ BLE sequenceDecs_decode_56_amd64_fill_check_overread
+ CMP $0x07, R3
+ BLE sequenceDecs_decode_56_amd64_fill_end
+ LSL $0x08, R2, R2
+ SUB $0x01, R13, R13
+ SUB $0x01, R5, R5
+ SUB $0x08, R3, R3
+ MOVBU (R13), R0
+ ORR R0, R2, R2
+ JMP sequenceDecs_decode_56_amd64_fill_byte_by_byte
+
+sequenceDecs_decode_56_amd64_fill_check_overread:
+ CMP $0x40, R3
+ BHI error_overread
+
+sequenceDecs_decode_56_amd64_fill_end:
+ // Update offset
+ MOVD R8, R0
+ MOVD R3, R1
+ MOVD R2, R14
+ LSL R1, R14, R14
+ UBFX $8, R0, $8, R16
+ BFI $0, R16, $8, R1
+ LSR $0x20, R0, R0
+ TST R1, R1
+ BEQ sequenceDecs_decode_56_amd64_of_update_zero
+ ADD R1, R3, R3
+ CMP $0x40, R3
+ BHI sequenceDecs_decode_56_amd64_of_update_zero
+ CMP $0x40, R1
+ BHS sequenceDecs_decode_56_amd64_of_update_zero
+ NEG R1, R1
+ LSR R1, R14, R14
+ ADD R14, R0, R0
+
+sequenceDecs_decode_56_amd64_of_update_zero:
+ MOVD R0, 16(R9)
+
+ // Update match length
+ MOVD R7, R0
+ MOVD R3, R1
+ MOVD R2, R14
+ LSL R1, R14, R14
+ UBFX $8, R0, $8, R16
+ BFI $0, R16, $8, R1
+ LSR $0x20, R0, R0
+ TST R1, R1
+ BEQ sequenceDecs_decode_56_amd64_ml_update_zero
+ ADD R1, R3, R3
+ CMP $0x40, R3
+ BHI sequenceDecs_decode_56_amd64_ml_update_zero
+ CMP $0x40, R1
+ BHS sequenceDecs_decode_56_amd64_ml_update_zero
+ NEG R1, R1
+ LSR R1, R14, R14
+ ADD R14, R0, R0
+
+sequenceDecs_decode_56_amd64_ml_update_zero:
+ MOVD R0, 8(R9)
+
+ // Update literal length
+ MOVD R6, R0
+ MOVD R3, R1
+ MOVD R2, R14
+ LSL R1, R14, R14
+ UBFX $8, R0, $8, R16
+ BFI $0, R16, $8, R1
+ LSR $0x20, R0, R0
+ TST R1, R1
+ BEQ sequenceDecs_decode_56_amd64_ll_update_zero
+ ADD R1, R3, R3
+ CMP $0x40, R3
+ BHI sequenceDecs_decode_56_amd64_ll_update_zero
+ CMP $0x40, R1
+ BHS sequenceDecs_decode_56_amd64_ll_update_zero
+ NEG R1, R1
+ LSR R1, R14, R14
+ ADD R14, R0, R0
+
+sequenceDecs_decode_56_amd64_ll_update_zero:
+ MOVD R0, (R9)
+
+ // Fill bitreader for state updates
+ MOVD R13, 8(RSP)
+ MOVD R8, R0
+ LSR $0x08, R0, R0
+ MOVBU R0, R0
+ MOVD ctx+16(FP), R1
+ MOVD 96(R1), R16
+ CMP $0x00, R16
+ BEQ sequenceDecs_decode_56_amd64_skip_update
+
+ // Update Literal Length State
+ MOVBU R6, R13
+ LSRW $0x10, R6, R6
+ ADD R13, R3, R1
+ MOVD R2, R14
+ MOVD R1, R3
+ NEG R1, R16
+ ROR R16, R14, R14
+ MOVD $0x00000001, R4
+ BFI $0, R13, $8, R1
+ LSLW R1, R4, R4
+ SUBW $1, R4, R4
+ AND R4, R14, R14
+ ADD R14, R6, R6
+
+ // Load ctx.llTable
+ MOVD ctx+16(FP), R1
+ MOVD (R1), R1
+ ADD R6<<3, R1, R15
+ MOVD (R15), R6
+
+ // Update Match Length State
+ MOVBU R7, R13
+ LSRW $0x10, R7, R7
+ ADD R13, R3, R1
+ MOVD R2, R14
+ MOVD R1, R3
+ NEG R1, R16
+ ROR R16, R14, R14
+ MOVD $0x00000001, R4
+ BFI $0, R13, $8, R1
+ LSLW R1, R4, R4
+ SUBW $1, R4, R4
+ AND R4, R14, R14
+ ADD R14, R7, R7
+
+ // Load ctx.mlTable
+ MOVD ctx+16(FP), R1
+ MOVD 24(R1), R1
+ ADD R7<<3, R1, R15
+ MOVD (R15), R7
+
+ // Update Offset State
+ MOVBU R8, R13
+ LSRW $0x10, R8, R8
+ ADD R13, R3, R1
+ MOVD R2, R14
+ MOVD R1, R3
+ NEG R1, R16
+ ROR R16, R14, R14
+ MOVD $0x00000001, R4
+ BFI $0, R13, $8, R1
+ LSLW R1, R4, R4
+ SUBW $1, R4, R4
+ AND R4, R14, R14
+ ADD R14, R8, R8
+
+ // Load ctx.ofTable
+ MOVD ctx+16(FP), R1
+ MOVD 48(R1), R1
+ ADD R8<<3, R1, R15
+ MOVD (R15), R8
+
+sequenceDecs_decode_56_amd64_skip_update:
+ // Adjust offset
+ MOVD 16(R9), R1
+ CMP $0x01, R0
+ BLS sequenceDecs_decode_56_amd64_adjust_offsetB_1_or_0
+ MOVD R11, R12
+ MOVD R10, R11
+ MOVD R1, R10
+ JMP sequenceDecs_decode_56_amd64_after_adjust
+
+sequenceDecs_decode_56_amd64_adjust_offsetB_1_or_0:
+ MOVD (R9), R16
+ CMP $0x00000000, R16
+ BNE sequenceDecs_decode_56_amd64_adjust_offset_maybezero
+ ADD $1, R1, R1
+ JMP sequenceDecs_decode_56_amd64_adjust_offset_nonzero
+
+sequenceDecs_decode_56_amd64_adjust_offset_maybezero:
+ TST R1, R1
+ BNE sequenceDecs_decode_56_amd64_adjust_offset_nonzero
+ MOVD R10, R1
+ JMP sequenceDecs_decode_56_amd64_after_adjust
+
+sequenceDecs_decode_56_amd64_adjust_offset_nonzero:
+ CMP $0x01, R1
+ BLO sequenceDecs_decode_56_amd64_adjust_zero
+ BEQ sequenceDecs_decode_56_amd64_adjust_one
+ CMP $0x02, R1
+ BHI sequenceDecs_decode_56_amd64_adjust_three
+ JMP sequenceDecs_decode_56_amd64_adjust_two
+
+sequenceDecs_decode_56_amd64_adjust_zero:
+ MOVD R10, R0
+ JMP sequenceDecs_decode_56_amd64_adjust_test_temp_valid
+
+sequenceDecs_decode_56_amd64_adjust_one:
+ MOVD R11, R0
+ JMP sequenceDecs_decode_56_amd64_adjust_test_temp_valid
+
+sequenceDecs_decode_56_amd64_adjust_two:
+ MOVD R12, R0
+ JMP sequenceDecs_decode_56_amd64_adjust_test_temp_valid
+
+sequenceDecs_decode_56_amd64_adjust_three:
+ SUB $1, R10, R0
+
+sequenceDecs_decode_56_amd64_adjust_test_temp_valid:
+ TST R0, R0
+ BNE sequenceDecs_decode_56_amd64_adjust_temp_valid
+ MOVD $0x00000001, R0
+
+sequenceDecs_decode_56_amd64_adjust_temp_valid:
+ CMP $0x01, R1
+ CSEL NE, R11, R12, R12
+ MOVD R10, R11
+ MOVD R0, R10
+ MOVD R0, R1
+
+sequenceDecs_decode_56_amd64_after_adjust:
+ MOVD R1, 16(R9)
+
+ // Check values
+ MOVD 8(R9), R0
+ MOVD (R9), R13
+ ADD R13, R0, R14
+ MOVD s+0(FP), R4
+ MOVD 256(R4), R16
+ ADD R14, R16, R16
+ MOVD R16, 256(R4)
+ MOVD ctx+16(FP), R14
+ MOVD 128(R14), R16
+ SUBS R13, R16, R16
+ MOVD R16, 128(R14)
+ BMI error_not_enough_literals
+ CMP $0x00020002, R0
+ BHI sequenceDecs_decode_56_amd64_error_match_len_too_big
+ TST R1, R1
+ BNE sequenceDecs_decode_56_amd64_match_len_ofs_ok
+ TST R0, R0
+ BNE sequenceDecs_decode_56_amd64_error_match_len_ofs_mismatch
+
+sequenceDecs_decode_56_amd64_match_len_ofs_ok:
+ ADD $0x18, R9, R9
+ MOVD ctx+16(FP), R0
+ MOVD 96(R0), R16
+ SUBS $1, R16, R16
+ MOVD R16, 96(R0)
+ BPL sequenceDecs_decode_56_amd64_main_loop
+ MOVD s+0(FP), R0
+ MOVD R10, 144(R0)
+ MOVD R11, 152(R0)
+ MOVD R12, 160(R0)
+ MOVD br+8(FP), R0
+ MOVD R2, 24(R0)
+ MOVB R3, 40(R0)
+ MOVD R5, 32(R0)
+
+ // Return success
+ MOVD $0x00000000, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with match length error
+sequenceDecs_decode_56_amd64_error_match_len_ofs_mismatch:
+ MOVD $0x00000001, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with match too long error
+sequenceDecs_decode_56_amd64_error_match_len_too_big:
+ MOVD $0x00000002, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with match offset too long error
+ MOVD $0x00000003, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with not enough literals error
+error_not_enough_literals:
+ MOVD $0x00000004, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with overread error
+error_overread:
+ MOVD $0x00000006, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+// skipped sequenceDecs_decode_bmi2 (generic twin preferred on arm64)
+
+// skipped sequenceDecs_decode_56_bmi2 (generic twin preferred on arm64)
+
+// func sequenceDecs_executeSimple_amd64(ctx *executeAsmContext) bool
+// Requires: SSE
+TEXT ·sequenceDecs_executeSimple_arm64(SB), $8-9
+ MOVD ctx+0(FP), R9
+ MOVD 8(R9), R1
+ TST R1, R1
+ BEQ empty_seqs
+ MOVD (R9), R0
+ MOVD 24(R9), R2
+ MOVD 32(R9), R3
+ MOVD 80(R9), R5
+ MOVD 104(R9), R6
+ MOVD 120(R9), R7
+ MOVD 56(R9), R8
+ MOVD 64(R9), R9
+ ADD R9, R8, R8
+
+ // seqsBase += 24 * seqIndex
+ ADD R2<<1, R2, R10
+ LSL $0x03, R10, R10
+ ADD R10, R0, R0
+
+ // outBase += outPosition
+ ADD R6, R3, R3
+
+main_loop:
+ MOVD (R0), R10
+ MOVD 16(R0), R11
+ MOVD 8(R0), R12
+
+ // Copy literals
+ TST R10, R10
+ BEQ check_offset
+ MOVD $0, R13
+
+copy_1:
+ ADD R13, R5, R15
+ VLD1 (R15), [V0.B16]
+ ADD R13, R3, R15
+ VST1 [V0.B16], (R15)
+ ADD $0x10, R13, R13
+ CMP R10, R13
+ BLO copy_1
+ ADD R10, R5, R5
+ ADD R10, R3, R3
+ ADD R10, R6, R6
+
+ // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize)
+check_offset:
+ ADD R9, R6, R10
+ CMP R10, R11
+ BGT error_match_off_too_big
+ CMP R7, R11
+ BGT error_match_off_too_big
+
+ // Copy match from history
+ MOVD R11, R10
+ SUBS R6, R10, R10
+ BLS copy_match
+ MOVD R8, R13
+ SUB R10, R13, R13
+ CMP R10, R12
+ BGT copy_all_from_history
+ MOVD R12, R10
+ SUBS $0x10, R10, R10
+ BLO copy_4_small
+
+copy_4_loop:
+ VLD1 (R13), [V0.B16]
+ VST1 [V0.B16], (R3)
+ ADD $0x10, R13, R13
+ ADD $0x10, R3, R3
+ SUBS $0x10, R10, R10
+ BHS copy_4_loop
+ ADD R10, R13, R13
+ ADD $16, R13, R13
+ ADD R10, R3, R3
+ ADD $16, R3, R3
+ ADD $-16, R13, R15
+ VLD1 (R15), [V0.B16]
+ ADD $-16, R3, R15
+ VST1 [V0.B16], (R15)
+ JMP copy_4_end
+
+copy_4_small:
+ CMP $0x03, R12
+ BEQ copy_4_move_3
+ CMP $0x08, R12
+ BLO copy_4_move_4through7
+ JMP copy_4_move_8through16
+
+copy_4_move_3:
+ MOVHU (R13), R10
+ MOVBU 2(R13), R16
+ BFI $0, R16, $8, R11
+ MOVH R10, (R3)
+ MOVB R11, 2(R3)
+ ADD R12, R13, R13
+ ADD R12, R3, R3
+ JMP copy_4_end
+
+copy_4_move_4through7:
+ MOVWU (R13), R10
+ ADD R12, R13, R15
+ MOVWU -4(R15), R11
+ MOVW R10, (R3)
+ ADD R12, R3, R15
+ MOVW R11, -4(R15)
+ ADD R12, R13, R13
+ ADD R12, R3, R3
+ JMP copy_4_end
+
+copy_4_move_8through16:
+ MOVD (R13), R10
+ ADD R12, R13, R15
+ MOVD -8(R15), R11
+ MOVD R10, (R3)
+ ADD R12, R3, R15
+ MOVD R11, -8(R15)
+ ADD R12, R13, R13
+ ADD R12, R3, R3
+
+copy_4_end:
+ ADD R12, R6, R6
+ ADD $0x18, R0, R0
+ ADD $1, R2, R2
+ CMP R1, R2
+ BLO main_loop
+ JMP loop_finished
+
+copy_all_from_history:
+ MOVD R10, R14
+ SUBS $0x10, R14, R14
+ BLO copy_5_small
+
+copy_5_loop:
+ VLD1 (R13), [V0.B16]
+ VST1 [V0.B16], (R3)
+ ADD $0x10, R13, R13
+ ADD $0x10, R3, R3
+ SUBS $0x10, R14, R14
+ BHS copy_5_loop
+ ADD R14, R13, R13
+ ADD $16, R13, R13
+ ADD R14, R3, R3
+ ADD $16, R3, R3
+ ADD $-16, R13, R15
+ VLD1 (R15), [V0.B16]
+ ADD $-16, R3, R15
+ VST1 [V0.B16], (R15)
+ JMP copy_5_end
+
+copy_5_small:
+ CMP $0x03, R10
+ BEQ copy_5_move_3
+ BLO copy_5_move_1or2
+ CMP $0x08, R10
+ BLO copy_5_move_4through7
+ JMP copy_5_move_8through16
+
+copy_5_move_1or2:
+ MOVBU (R13), R16
+ BFI $0, R16, $8, R14
+ ADD R10, R13, R15
+ MOVBU -1(R15), R16
+ BFI $0, R16, $8, R4
+ MOVB R14, (R3)
+ ADD R10, R3, R15
+ MOVB R4, -1(R15)
+ ADD R10, R13, R13
+ ADD R10, R3, R3
+ JMP copy_5_end
+
+copy_5_move_3:
+ MOVHU (R13), R14
+ MOVBU 2(R13), R16
+ BFI $0, R16, $8, R4
+ MOVH R14, (R3)
+ MOVB R4, 2(R3)
+ ADD R10, R13, R13
+ ADD R10, R3, R3
+ JMP copy_5_end
+
+copy_5_move_4through7:
+ MOVWU (R13), R14
+ ADD R10, R13, R15
+ MOVWU -4(R15), R4
+ MOVW R14, (R3)
+ ADD R10, R3, R15
+ MOVW R4, -4(R15)
+ ADD R10, R13, R13
+ ADD R10, R3, R3
+ JMP copy_5_end
+
+copy_5_move_8through16:
+ MOVD (R13), R14
+ ADD R10, R13, R15
+ MOVD -8(R15), R4
+ MOVD R14, (R3)
+ ADD R10, R3, R15
+ MOVD R4, -8(R15)
+ ADD R10, R13, R13
+ ADD R10, R3, R3
+
+copy_5_end:
+ ADD R10, R6, R6
+ SUB R10, R12, R12
+
+ // Copy match from the current buffer
+copy_match:
+ MOVD R3, R10
+ SUB R11, R10, R10
+
+ // ml <= mo
+ CMP R11, R12
+ BHI copy_overlapping_match
+
+ // Copy non-overlapping match
+ ADD R12, R6, R6
+ MOVD R3, R11
+ ADD R12, R3, R3
+
+copy_2:
+ VLD1 (R10), [V0.B16]
+ VST1 [V0.B16], (R11)
+ ADD $0x10, R10, R10
+ ADD $0x10, R11, R11
+ SUBS $0x10, R12, R12
+ BHI copy_2
+ JMP handle_loop
+
+ // Copy overlapping match
+copy_overlapping_match:
+ ADD R12, R6, R6
+
+copy_slow_3:
+ MOVBU (R10), R16
+ BFI $0, R16, $8, R11
+ MOVB R11, (R3)
+ ADD $1, R10, R10
+ ADD $1, R3, R3
+ SUBS $1, R12, R12
+ BNE copy_slow_3
+
+handle_loop:
+ ADD $0x18, R0, R0
+ ADD $1, R2, R2
+ CMP R1, R2
+ BLO main_loop
+
+loop_finished:
+ // Return value
+ MOVD $0x01, R16
+ MOVB R16, ret+8(FP)
+
+ // Update the context
+ MOVD ctx+0(FP), R0
+ MOVD R2, 24(R0)
+ MOVD R6, 104(R0)
+ MOVD 80(R0), R16
+ SUB R16, R5, R5
+ MOVD R5, 112(R0)
+ RET
+
+error_match_off_too_big:
+ // Return value
+ MOVD $0x00, R16
+ MOVB R16, ret+8(FP)
+
+ // Update the context
+ MOVD ctx+0(FP), R0
+ MOVD R2, 24(R0)
+ MOVD R6, 104(R0)
+ MOVD 80(R0), R16
+ SUB R16, R5, R5
+ MOVD R5, 112(R0)
+ RET
+
+empty_seqs:
+ // Return value
+ MOVD $0x01, R16
+ MOVB R16, ret+8(FP)
+ RET
+
+// func sequenceDecs_executeSimple_safe_amd64(ctx *executeAsmContext) bool
+// Requires: SSE
+TEXT ·sequenceDecs_executeSimple_safe_arm64(SB), $8-9
+ MOVD ctx+0(FP), R9
+ MOVD 8(R9), R1
+ TST R1, R1
+ BEQ empty_seqs
+ MOVD (R9), R0
+ MOVD 24(R9), R2
+ MOVD 32(R9), R3
+ MOVD 80(R9), R5
+ MOVD 104(R9), R6
+ MOVD 120(R9), R7
+ MOVD 56(R9), R8
+ MOVD 64(R9), R9
+ ADD R9, R8, R8
+
+ // seqsBase += 24 * seqIndex
+ ADD R2<<1, R2, R10
+ LSL $0x03, R10, R10
+ ADD R10, R0, R0
+
+ // outBase += outPosition
+ ADD R6, R3, R3
+
+main_loop:
+ MOVD (R0), R10
+ MOVD 16(R0), R11
+ MOVD 8(R0), R12
+
+ // Copy literals
+ TST R10, R10
+ BEQ check_offset
+ MOVD R10, R13
+ SUBS $0x10, R13, R13
+ BLO copy_1_small
+
+copy_1_loop:
+ VLD1 (R5), [V0.B16]
+ VST1 [V0.B16], (R3)
+ ADD $0x10, R5, R5
+ ADD $0x10, R3, R3
+ SUBS $0x10, R13, R13
+ BHS copy_1_loop
+ ADD R13, R5, R5
+ ADD $16, R5, R5
+ ADD R13, R3, R3
+ ADD $16, R3, R3
+ ADD $-16, R5, R15
+ VLD1 (R15), [V0.B16]
+ ADD $-16, R3, R15
+ VST1 [V0.B16], (R15)
+ JMP copy_1_end
+
+copy_1_small:
+ CMP $0x03, R10
+ BEQ copy_1_move_3
+ BLO copy_1_move_1or2
+ CMP $0x08, R10
+ BLO copy_1_move_4through7
+ JMP copy_1_move_8through16
+
+copy_1_move_1or2:
+ MOVBU (R5), R16
+ BFI $0, R16, $8, R13
+ ADD R10, R5, R15
+ MOVBU -1(R15), R16
+ BFI $0, R16, $8, R14
+ MOVB R13, (R3)
+ ADD R10, R3, R15
+ MOVB R14, -1(R15)
+ ADD R10, R5, R5
+ ADD R10, R3, R3
+ JMP copy_1_end
+
+copy_1_move_3:
+ MOVHU (R5), R13
+ MOVBU 2(R5), R16
+ BFI $0, R16, $8, R14
+ MOVH R13, (R3)
+ MOVB R14, 2(R3)
+ ADD R10, R5, R5
+ ADD R10, R3, R3
+ JMP copy_1_end
+
+copy_1_move_4through7:
+ MOVWU (R5), R13
+ ADD R10, R5, R15
+ MOVWU -4(R15), R14
+ MOVW R13, (R3)
+ ADD R10, R3, R15
+ MOVW R14, -4(R15)
+ ADD R10, R5, R5
+ ADD R10, R3, R3
+ JMP copy_1_end
+
+copy_1_move_8through16:
+ MOVD (R5), R13
+ ADD R10, R5, R15
+ MOVD -8(R15), R14
+ MOVD R13, (R3)
+ ADD R10, R3, R15
+ MOVD R14, -8(R15)
+ ADD R10, R5, R5
+ ADD R10, R3, R3
+
+copy_1_end:
+ ADD R10, R6, R6
+
+ // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize)
+check_offset:
+ ADD R9, R6, R10
+ CMP R10, R11
+ BGT error_match_off_too_big
+ CMP R7, R11
+ BGT error_match_off_too_big
+
+ // Copy match from history
+ MOVD R11, R10
+ SUBS R6, R10, R10
+ BLS copy_match
+ MOVD R8, R13
+ SUB R10, R13, R13
+ CMP R10, R12
+ BGT copy_all_from_history
+ MOVD R12, R10
+ SUBS $0x10, R10, R10
+ BLO copy_4_small
+
+copy_4_loop:
+ VLD1 (R13), [V0.B16]
+ VST1 [V0.B16], (R3)
+ ADD $0x10, R13, R13
+ ADD $0x10, R3, R3
+ SUBS $0x10, R10, R10
+ BHS copy_4_loop
+ ADD R10, R13, R13
+ ADD $16, R13, R13
+ ADD R10, R3, R3
+ ADD $16, R3, R3
+ ADD $-16, R13, R15
+ VLD1 (R15), [V0.B16]
+ ADD $-16, R3, R15
+ VST1 [V0.B16], (R15)
+ JMP copy_4_end
+
+copy_4_small:
+ CMP $0x03, R12
+ BEQ copy_4_move_3
+ CMP $0x08, R12
+ BLO copy_4_move_4through7
+ JMP copy_4_move_8through16
+
+copy_4_move_3:
+ MOVHU (R13), R10
+ MOVBU 2(R13), R16
+ BFI $0, R16, $8, R11
+ MOVH R10, (R3)
+ MOVB R11, 2(R3)
+ ADD R12, R13, R13
+ ADD R12, R3, R3
+ JMP copy_4_end
+
+copy_4_move_4through7:
+ MOVWU (R13), R10
+ ADD R12, R13, R15
+ MOVWU -4(R15), R11
+ MOVW R10, (R3)
+ ADD R12, R3, R15
+ MOVW R11, -4(R15)
+ ADD R12, R13, R13
+ ADD R12, R3, R3
+ JMP copy_4_end
+
+copy_4_move_8through16:
+ MOVD (R13), R10
+ ADD R12, R13, R15
+ MOVD -8(R15), R11
+ MOVD R10, (R3)
+ ADD R12, R3, R15
+ MOVD R11, -8(R15)
+ ADD R12, R13, R13
+ ADD R12, R3, R3
+
+copy_4_end:
+ ADD R12, R6, R6
+ ADD $0x18, R0, R0
+ ADD $1, R2, R2
+ CMP R1, R2
+ BLO main_loop
+ JMP loop_finished
+
+copy_all_from_history:
+ MOVD R10, R14
+ SUBS $0x10, R14, R14
+ BLO copy_5_small
+
+copy_5_loop:
+ VLD1 (R13), [V0.B16]
+ VST1 [V0.B16], (R3)
+ ADD $0x10, R13, R13
+ ADD $0x10, R3, R3
+ SUBS $0x10, R14, R14
+ BHS copy_5_loop
+ ADD R14, R13, R13
+ ADD $16, R13, R13
+ ADD R14, R3, R3
+ ADD $16, R3, R3
+ ADD $-16, R13, R15
+ VLD1 (R15), [V0.B16]
+ ADD $-16, R3, R15
+ VST1 [V0.B16], (R15)
+ JMP copy_5_end
+
+copy_5_small:
+ CMP $0x03, R10
+ BEQ copy_5_move_3
+ BLO copy_5_move_1or2
+ CMP $0x08, R10
+ BLO copy_5_move_4through7
+ JMP copy_5_move_8through16
+
+copy_5_move_1or2:
+ MOVBU (R13), R16
+ BFI $0, R16, $8, R14
+ ADD R10, R13, R15
+ MOVBU -1(R15), R16
+ BFI $0, R16, $8, R4
+ MOVB R14, (R3)
+ ADD R10, R3, R15
+ MOVB R4, -1(R15)
+ ADD R10, R13, R13
+ ADD R10, R3, R3
+ JMP copy_5_end
+
+copy_5_move_3:
+ MOVHU (R13), R14
+ MOVBU 2(R13), R16
+ BFI $0, R16, $8, R4
+ MOVH R14, (R3)
+ MOVB R4, 2(R3)
+ ADD R10, R13, R13
+ ADD R10, R3, R3
+ JMP copy_5_end
+
+copy_5_move_4through7:
+ MOVWU (R13), R14
+ ADD R10, R13, R15
+ MOVWU -4(R15), R4
+ MOVW R14, (R3)
+ ADD R10, R3, R15
+ MOVW R4, -4(R15)
+ ADD R10, R13, R13
+ ADD R10, R3, R3
+ JMP copy_5_end
+
+copy_5_move_8through16:
+ MOVD (R13), R14
+ ADD R10, R13, R15
+ MOVD -8(R15), R4
+ MOVD R14, (R3)
+ ADD R10, R3, R15
+ MOVD R4, -8(R15)
+ ADD R10, R13, R13
+ ADD R10, R3, R3
+
+copy_5_end:
+ ADD R10, R6, R6
+ SUB R10, R12, R12
+
+ // Copy match from the current buffer
+copy_match:
+ MOVD R3, R10
+ SUB R11, R10, R10
+
+ // ml <= mo
+ CMP R11, R12
+ BHI copy_overlapping_match
+
+ // Copy non-overlapping match
+ ADD R12, R6, R6
+ MOVD R12, R11
+ SUBS $0x10, R11, R11
+ BLO copy_2_small
+
+copy_2_loop:
+ VLD1 (R10), [V0.B16]
+ VST1 [V0.B16], (R3)
+ ADD $0x10, R10, R10
+ ADD $0x10, R3, R3
+ SUBS $0x10, R11, R11
+ BHS copy_2_loop
+ ADD R11, R10, R10
+ ADD $16, R10, R10
+ ADD R11, R3, R3
+ ADD $16, R3, R3
+ ADD $-16, R10, R15
+ VLD1 (R15), [V0.B16]
+ ADD $-16, R3, R15
+ VST1 [V0.B16], (R15)
+ JMP copy_2_end
+
+copy_2_small:
+ CMP $0x03, R12
+ BEQ copy_2_move_3
+ BLO copy_2_move_1or2
+ CMP $0x08, R12
+ BLO copy_2_move_4through7
+ JMP copy_2_move_8through16
+
+copy_2_move_1or2:
+ MOVBU (R10), R16
+ BFI $0, R16, $8, R11
+ ADD R12, R10, R15
+ MOVBU -1(R15), R16
+ BFI $0, R16, $8, R13
+ MOVB R11, (R3)
+ ADD R12, R3, R15
+ MOVB R13, -1(R15)
+ ADD R12, R10, R10
+ ADD R12, R3, R3
+ JMP copy_2_end
+
+copy_2_move_3:
+ MOVHU (R10), R11
+ MOVBU 2(R10), R16
+ BFI $0, R16, $8, R13
+ MOVH R11, (R3)
+ MOVB R13, 2(R3)
+ ADD R12, R10, R10
+ ADD R12, R3, R3
+ JMP copy_2_end
+
+copy_2_move_4through7:
+ MOVWU (R10), R11
+ ADD R12, R10, R15
+ MOVWU -4(R15), R13
+ MOVW R11, (R3)
+ ADD R12, R3, R15
+ MOVW R13, -4(R15)
+ ADD R12, R10, R10
+ ADD R12, R3, R3
+ JMP copy_2_end
+
+copy_2_move_8through16:
+ MOVD (R10), R11
+ ADD R12, R10, R15
+ MOVD -8(R15), R13
+ MOVD R11, (R3)
+ ADD R12, R3, R15
+ MOVD R13, -8(R15)
+ ADD R12, R10, R10
+ ADD R12, R3, R3
+
+copy_2_end:
+ JMP handle_loop
+
+ // Copy overlapping match
+copy_overlapping_match:
+ ADD R12, R6, R6
+
+copy_slow_3:
+ MOVBU (R10), R16
+ BFI $0, R16, $8, R11
+ MOVB R11, (R3)
+ ADD $1, R10, R10
+ ADD $1, R3, R3
+ SUBS $1, R12, R12
+ BNE copy_slow_3
+
+handle_loop:
+ ADD $0x18, R0, R0
+ ADD $1, R2, R2
+ CMP R1, R2
+ BLO main_loop
+
+loop_finished:
+ // Return value
+ MOVD $0x01, R16
+ MOVB R16, ret+8(FP)
+
+ // Update the context
+ MOVD ctx+0(FP), R0
+ MOVD R2, 24(R0)
+ MOVD R6, 104(R0)
+ MOVD 80(R0), R16
+ SUB R16, R5, R5
+ MOVD R5, 112(R0)
+ RET
+
+error_match_off_too_big:
+ // Return value
+ MOVD $0x00, R16
+ MOVB R16, ret+8(FP)
+
+ // Update the context
+ MOVD ctx+0(FP), R0
+ MOVD R2, 24(R0)
+ MOVD R6, 104(R0)
+ MOVD 80(R0), R16
+ SUB R16, R5, R5
+ MOVD R5, 112(R0)
+ RET
+
+empty_seqs:
+ // Return value
+ MOVD $0x01, R16
+ MOVB R16, ret+8(FP)
+ RET
+
+// func sequenceDecs_decodeSync_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
+// Requires: CMOV, SSE
+TEXT ·sequenceDecs_decodeSync_arm64(SB), $64-32
+ MOVD br+8(FP), R1
+ MOVD 24(R1), R2
+ MOVBU 40(R1), R3
+ MOVD (R1), R0
+ MOVD 32(R1), R5
+ ADD R5, R0, R0
+ MOVD R0, 8(RSP)
+ MOVD ctx+16(FP), R0
+ MOVD 72(R0), R6
+ MOVD 80(R0), R7
+ MOVD 88(R0), R8
+ MOVD $0, R1
+ MOVD R1, 16(RSP)
+ MOVD R1, 24(RSP)
+ MOVD R1, 32(RSP)
+ MOVD 112(R0), R9
+ MOVD 128(R0), R1
+ MOVD R1, 40(RSP)
+ MOVD 144(R0), R10
+ MOVD 136(R0), R11
+ MOVD 200(R0), R1
+ MOVD R1, 64(RSP)
+ MOVD 176(R0), R1
+ MOVD R1, 56(RSP)
+ MOVD 184(R0), R0
+ MOVD R0, 48(RSP)
+ MOVD 48(RSP), R0
+ MOVD 56(RSP), R16
+ ADD R0, R16, R16
+ MOVD R16, 56(RSP)
+
+ // Calculate pointer to s.out[cap(s.out)] (a past-end pointer)
+ MOVD 40(RSP), R16
+ ADD R9, R16, R16
+ MOVD R16, 40(RSP)
+
+ // outBase += outPosition
+ ADD R11, R9, R9
+
+sequenceDecs_decodeSync_amd64_main_loop:
+ MOVD 8(RSP), R12
+
+ // Fill bitreader to have enough for the offset and match length.
+ CMP $0x08, R5
+ BLT sequenceDecs_decodeSync_amd64_fill_byte_by_byte
+ MOVD R3, R0
+ LSR $0x03, R0, R0
+ SUB R0, R12, R12
+ MOVD (R12), R2
+ SUB R0, R5, R5
+ AND $0x07, R3, R3
+ JMP sequenceDecs_decodeSync_amd64_fill_end
+
+sequenceDecs_decodeSync_amd64_fill_byte_by_byte:
+ CMP $0x00, R5
+ BLE sequenceDecs_decodeSync_amd64_fill_check_overread
+ CMP $0x07, R3
+ BLE sequenceDecs_decodeSync_amd64_fill_end
+ LSL $0x08, R2, R2
+ SUB $0x01, R12, R12
+ SUB $0x01, R5, R5
+ SUB $0x08, R3, R3
+ MOVBU (R12), R0
+ ORR R0, R2, R2
+ JMP sequenceDecs_decodeSync_amd64_fill_byte_by_byte
+
+sequenceDecs_decodeSync_amd64_fill_check_overread:
+ CMP $0x40, R3
+ BHI error_overread
+
+sequenceDecs_decodeSync_amd64_fill_end:
+ // Update offset
+ MOVD R8, R0
+ MOVD R3, R1
+ MOVD R2, R13
+ LSL R1, R13, R13
+ UBFX $8, R0, $8, R16
+ BFI $0, R16, $8, R1
+ LSR $0x20, R0, R0
+ TST R1, R1
+ BEQ sequenceDecs_decodeSync_amd64_of_update_zero
+ ADD R1, R3, R3
+ CMP $0x40, R3
+ BHI sequenceDecs_decodeSync_amd64_of_update_zero
+ CMP $0x40, R1
+ BHS sequenceDecs_decodeSync_amd64_of_update_zero
+ NEG R1, R1
+ LSR R1, R13, R13
+ ADD R13, R0, R0
+
+sequenceDecs_decodeSync_amd64_of_update_zero:
+ MOVD R0, 16(RSP)
+
+ // Update match length
+ MOVD R7, R0
+ MOVD R3, R1
+ MOVD R2, R13
+ LSL R1, R13, R13
+ UBFX $8, R0, $8, R16
+ BFI $0, R16, $8, R1
+ LSR $0x20, R0, R0
+ TST R1, R1
+ BEQ sequenceDecs_decodeSync_amd64_ml_update_zero
+ ADD R1, R3, R3
+ CMP $0x40, R3
+ BHI sequenceDecs_decodeSync_amd64_ml_update_zero
+ CMP $0x40, R1
+ BHS sequenceDecs_decodeSync_amd64_ml_update_zero
+ NEG R1, R1
+ LSR R1, R13, R13
+ ADD R13, R0, R0
+
+sequenceDecs_decodeSync_amd64_ml_update_zero:
+ MOVD R0, 24(RSP)
+
+ // Fill bitreader to have enough for the remaining
+ CMP $0x08, R5
+ BLT sequenceDecs_decodeSync_amd64_fill_2_byte_by_byte
+ MOVD R3, R0
+ LSR $0x03, R0, R0
+ SUB R0, R12, R12
+ MOVD (R12), R2
+ SUB R0, R5, R5
+ AND $0x07, R3, R3
+ JMP sequenceDecs_decodeSync_amd64_fill_2_end
+
+sequenceDecs_decodeSync_amd64_fill_2_byte_by_byte:
+ CMP $0x00, R5
+ BLE sequenceDecs_decodeSync_amd64_fill_2_check_overread
+ CMP $0x07, R3
+ BLE sequenceDecs_decodeSync_amd64_fill_2_end
+ LSL $0x08, R2, R2
+ SUB $0x01, R12, R12
+ SUB $0x01, R5, R5
+ SUB $0x08, R3, R3
+ MOVBU (R12), R0
+ ORR R0, R2, R2
+ JMP sequenceDecs_decodeSync_amd64_fill_2_byte_by_byte
+
+sequenceDecs_decodeSync_amd64_fill_2_check_overread:
+ CMP $0x40, R3
+ BHI error_overread
+
+sequenceDecs_decodeSync_amd64_fill_2_end:
+ // Update literal length
+ MOVD R6, R0
+ MOVD R3, R1
+ MOVD R2, R13
+ LSL R1, R13, R13
+ UBFX $8, R0, $8, R16
+ BFI $0, R16, $8, R1
+ LSR $0x20, R0, R0
+ TST R1, R1
+ BEQ sequenceDecs_decodeSync_amd64_ll_update_zero
+ ADD R1, R3, R3
+ CMP $0x40, R3
+ BHI sequenceDecs_decodeSync_amd64_ll_update_zero
+ CMP $0x40, R1
+ BHS sequenceDecs_decodeSync_amd64_ll_update_zero
+ NEG R1, R1
+ LSR R1, R13, R13
+ ADD R13, R0, R0
+
+sequenceDecs_decodeSync_amd64_ll_update_zero:
+ MOVD R0, 32(RSP)
+
+ // Fill bitreader for state updates
+ MOVD R12, 8(RSP)
+ MOVD R8, R0
+ LSR $0x08, R0, R0
+ MOVBU R0, R0
+ MOVD ctx+16(FP), R1
+ MOVD 96(R1), R16
+ CMP $0x00, R16
+ BEQ sequenceDecs_decodeSync_amd64_skip_update
+
+ // Update Literal Length State
+ MOVBU R6, R12
+ LSRW $0x10, R6, R6
+ ADD R12, R3, R1
+ MOVD R2, R13
+ MOVD R1, R3
+ NEG R1, R16
+ ROR R16, R13, R13
+ MOVD $0x00000001, R14
+ BFI $0, R12, $8, R1
+ LSLW R1, R14, R14
+ SUBW $1, R14, R14
+ AND R14, R13, R13
+ ADD R13, R6, R6
+
+ // Load ctx.llTable
+ MOVD ctx+16(FP), R1
+ MOVD (R1), R1
+ ADD R6<<3, R1, R15
+ MOVD (R15), R6
+
+ // Update Match Length State
+ MOVBU R7, R12
+ LSRW $0x10, R7, R7
+ ADD R12, R3, R1
+ MOVD R2, R13
+ MOVD R1, R3
+ NEG R1, R16
+ ROR R16, R13, R13
+ MOVD $0x00000001, R14
+ BFI $0, R12, $8, R1
+ LSLW R1, R14, R14
+ SUBW $1, R14, R14
+ AND R14, R13, R13
+ ADD R13, R7, R7
+
+ // Load ctx.mlTable
+ MOVD ctx+16(FP), R1
+ MOVD 24(R1), R1
+ ADD R7<<3, R1, R15
+ MOVD (R15), R7
+
+ // Update Offset State
+ MOVBU R8, R12
+ LSRW $0x10, R8, R8
+ ADD R12, R3, R1
+ MOVD R2, R13
+ MOVD R1, R3
+ NEG R1, R16
+ ROR R16, R13, R13
+ MOVD $0x00000001, R14
+ BFI $0, R12, $8, R1
+ LSLW R1, R14, R14
+ SUBW $1, R14, R14
+ AND R14, R13, R13
+ ADD R13, R8, R8
+
+ // Load ctx.ofTable
+ MOVD ctx+16(FP), R1
+ MOVD 48(R1), R1
+ ADD R8<<3, R1, R15
+ MOVD (R15), R8
+
+sequenceDecs_decodeSync_amd64_skip_update:
+ // Adjust offset
+ MOVD s+0(FP), R1
+ MOVD 16(RSP), R12
+ CMP $0x01, R0
+ BLS sequenceDecs_decodeSync_amd64_adjust_offsetB_1_or_0
+ ADD $144, R1, R15
+ VLD1 (R15), [V0.B16]
+ MOVD R12, 144(R1)
+ ADD $152, R1, R15
+ VST1 [V0.B16], (R15)
+ JMP sequenceDecs_decodeSync_amd64_after_adjust
+
+sequenceDecs_decodeSync_amd64_adjust_offsetB_1_or_0:
+ MOVD 32(RSP), R16
+ CMP $0x00000000, R16
+ BNE sequenceDecs_decodeSync_amd64_adjust_offset_maybezero
+ ADD $1, R12, R12
+ JMP sequenceDecs_decodeSync_amd64_adjust_offset_nonzero
+
+sequenceDecs_decodeSync_amd64_adjust_offset_maybezero:
+ TST R12, R12
+ BNE sequenceDecs_decodeSync_amd64_adjust_offset_nonzero
+ MOVD 144(R1), R12
+ JMP sequenceDecs_decodeSync_amd64_after_adjust
+
+sequenceDecs_decodeSync_amd64_adjust_offset_nonzero:
+ MOVD R12, R0
+ MOVD $0, R13
+ MOVD $-1, R14
+ CMP $0x03, R12
+ CSEL EQ, R13, R0, R0
+ CSEL EQ, R14, R13, R13
+ ADD R0<<3, R1, R15
+ MOVD 144(R15), R16
+ ADDS R16, R13, R13
+ BNE sequenceDecs_decodeSync_amd64_adjust_temp_valid
+ MOVD $0x00000001, R13
+
+sequenceDecs_decodeSync_amd64_adjust_temp_valid:
+ CMP $0x01, R12
+ BEQ sequenceDecs_decodeSync_amd64_adjust_skip
+ MOVD 152(R1), R0
+ MOVD R0, 160(R1)
+
+sequenceDecs_decodeSync_amd64_adjust_skip:
+ MOVD 144(R1), R0
+ MOVD R0, 152(R1)
+ MOVD R13, 144(R1)
+ MOVD R13, R12
+
+sequenceDecs_decodeSync_amd64_after_adjust:
+ MOVD R12, 16(RSP)
+
+ // Check values
+ MOVD 24(RSP), R0
+ MOVD 32(RSP), R1
+ ADD R1, R0, R13
+ MOVD s+0(FP), R14
+ MOVD 256(R14), R16
+ ADD R13, R16, R16
+ MOVD R16, 256(R14)
+ MOVD ctx+16(FP), R13
+ MOVD 104(R13), R16
+ SUBS R1, R16, R16
+ MOVD R16, 104(R13)
+ BMI error_not_enough_literals
+ CMP $0x00020002, R0
+ BHI sequenceDecs_decodeSync_amd64_error_match_len_too_big
+ TST R12, R12
+ BNE sequenceDecs_decodeSync_amd64_match_len_ofs_ok
+ TST R0, R0
+ BNE sequenceDecs_decodeSync_amd64_error_match_len_ofs_mismatch
+
+sequenceDecs_decodeSync_amd64_match_len_ofs_ok:
+ MOVD 32(RSP), R0
+ MOVD 16(RSP), R1
+ MOVD 24(RSP), R12
+
+ // Check if we have enough space in s.out
+ ADD R12, R0, R13
+ ADD $16, R13, R13
+ ADD R9, R13, R13
+ MOVD 40(RSP), R16
+ CMP R16, R13
+ BHI error_not_enough_space
+
+ // Copy literals
+ TST R0, R0
+ BEQ check_offset
+ MOVD $0, R13
+
+copy_1:
+ ADD R13, R10, R15
+ VLD1 (R15), [V0.B16]
+ ADD R13, R9, R15
+ VST1 [V0.B16], (R15)
+ ADD $0x10, R13, R13
+ CMP R0, R13
+ BLO copy_1
+ ADD R0, R10, R10
+ ADD R0, R9, R9
+ ADD R0, R11, R11
+
+ // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize)
+check_offset:
+ MOVD R11, R0
+ MOVD 48(RSP), R16
+ ADD R16, R0, R0
+ CMP R0, R1
+ BGT error_match_off_too_big
+ MOVD 64(RSP), R16
+ CMP R16, R1
+ BGT error_match_off_too_big
+
+ // Copy match from history
+ MOVD R1, R0
+ SUBS R11, R0, R0
+ BLS copy_match
+ MOVD 56(RSP), R13
+ SUB R0, R13, R13
+ CMP R0, R12
+ BGT copy_all_from_history
+ MOVD R12, R0
+ SUBS $0x10, R0, R0
+ BLO copy_4_small
+
+copy_4_loop:
+ VLD1 (R13), [V0.B16]
+ VST1 [V0.B16], (R9)
+ ADD $0x10, R13, R13
+ ADD $0x10, R9, R9
+ SUBS $0x10, R0, R0
+ BHS copy_4_loop
+ ADD R0, R13, R13
+ ADD $16, R13, R13
+ ADD R0, R9, R9
+ ADD $16, R9, R9
+ ADD $-16, R13, R15
+ VLD1 (R15), [V0.B16]
+ ADD $-16, R9, R15
+ VST1 [V0.B16], (R15)
+ JMP copy_4_end
+
+copy_4_small:
+ CMP $0x03, R12
+ BEQ copy_4_move_3
+ CMP $0x08, R12
+ BLO copy_4_move_4through7
+ JMP copy_4_move_8through16
+
+copy_4_move_3:
+ MOVHU (R13), R0
+ MOVBU 2(R13), R16
+ BFI $0, R16, $8, R1
+ MOVH R0, (R9)
+ MOVB R1, 2(R9)
+ ADD R12, R13, R13
+ ADD R12, R9, R9
+ JMP copy_4_end
+
+copy_4_move_4through7:
+ MOVWU (R13), R0
+ ADD R12, R13, R15
+ MOVWU -4(R15), R1
+ MOVW R0, (R9)
+ ADD R12, R9, R15
+ MOVW R1, -4(R15)
+ ADD R12, R13, R13
+ ADD R12, R9, R9
+ JMP copy_4_end
+
+copy_4_move_8through16:
+ MOVD (R13), R0
+ ADD R12, R13, R15
+ MOVD -8(R15), R1
+ MOVD R0, (R9)
+ ADD R12, R9, R15
+ MOVD R1, -8(R15)
+ ADD R12, R13, R13
+ ADD R12, R9, R9
+
+copy_4_end:
+ ADD R12, R11, R11
+ JMP handle_loop
+ JMP loop_finished
+
+copy_all_from_history:
+ MOVD R0, R14
+ SUBS $0x10, R14, R14
+ BLO copy_5_small
+
+copy_5_loop:
+ VLD1 (R13), [V0.B16]
+ VST1 [V0.B16], (R9)
+ ADD $0x10, R13, R13
+ ADD $0x10, R9, R9
+ SUBS $0x10, R14, R14
+ BHS copy_5_loop
+ ADD R14, R13, R13
+ ADD $16, R13, R13
+ ADD R14, R9, R9
+ ADD $16, R9, R9
+ ADD $-16, R13, R15
+ VLD1 (R15), [V0.B16]
+ ADD $-16, R9, R15
+ VST1 [V0.B16], (R15)
+ JMP copy_5_end
+
+copy_5_small:
+ CMP $0x03, R0
+ BEQ copy_5_move_3
+ BLO copy_5_move_1or2
+ CMP $0x08, R0
+ BLO copy_5_move_4through7
+ JMP copy_5_move_8through16
+
+copy_5_move_1or2:
+ MOVBU (R13), R16
+ BFI $0, R16, $8, R14
+ ADD R0, R13, R15
+ MOVBU -1(R15), R16
+ BFI $0, R16, $8, R4
+ MOVB R14, (R9)
+ ADD R0, R9, R15
+ MOVB R4, -1(R15)
+ ADD R0, R13, R13
+ ADD R0, R9, R9
+ JMP copy_5_end
+
+copy_5_move_3:
+ MOVHU (R13), R14
+ MOVBU 2(R13), R16
+ BFI $0, R16, $8, R4
+ MOVH R14, (R9)
+ MOVB R4, 2(R9)
+ ADD R0, R13, R13
+ ADD R0, R9, R9
+ JMP copy_5_end
+
+copy_5_move_4through7:
+ MOVWU (R13), R14
+ ADD R0, R13, R15
+ MOVWU -4(R15), R4
+ MOVW R14, (R9)
+ ADD R0, R9, R15
+ MOVW R4, -4(R15)
+ ADD R0, R13, R13
+ ADD R0, R9, R9
+ JMP copy_5_end
+
+copy_5_move_8through16:
+ MOVD (R13), R14
+ ADD R0, R13, R15
+ MOVD -8(R15), R4
+ MOVD R14, (R9)
+ ADD R0, R9, R15
+ MOVD R4, -8(R15)
+ ADD R0, R13, R13
+ ADD R0, R9, R9
+
+copy_5_end:
+ ADD R0, R11, R11
+ SUB R0, R12, R12
+
+ // Copy match from the current buffer
+copy_match:
+ MOVD R9, R0
+ SUB R1, R0, R0
+
+ // ml <= mo
+ CMP R1, R12
+ BHI copy_overlapping_match
+
+ // Copy non-overlapping match
+ ADD R12, R11, R11
+ MOVD R9, R1
+ ADD R12, R9, R9
+
+copy_2:
+ VLD1 (R0), [V0.B16]
+ VST1 [V0.B16], (R1)
+ ADD $0x10, R0, R0
+ ADD $0x10, R1, R1
+ SUBS $0x10, R12, R12
+ BHI copy_2
+ JMP handle_loop
+
+ // Copy overlapping match
+copy_overlapping_match:
+ ADD R12, R11, R11
+
+copy_slow_3:
+ MOVBU (R0), R16
+ BFI $0, R16, $8, R1
+ MOVB R1, (R9)
+ ADD $1, R0, R0
+ ADD $1, R9, R9
+ SUBS $1, R12, R12
+ BNE copy_slow_3
+
+handle_loop:
+ MOVD ctx+16(FP), R0
+ MOVD 96(R0), R16
+ SUBS $1, R16, R16
+ MOVD R16, 96(R0)
+ BPL sequenceDecs_decodeSync_amd64_main_loop
+
+loop_finished:
+ MOVD br+8(FP), R0
+ MOVD R2, 24(R0)
+ MOVB R3, 40(R0)
+ MOVD R5, 32(R0)
+
+ // Update the context
+ MOVD ctx+16(FP), R0
+ MOVD R11, 136(R0)
+ MOVD 144(R0), R1
+ SUB R1, R10, R10
+ MOVD R10, 168(R0)
+
+ // Return success
+ MOVD $0x00000000, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with match length error
+sequenceDecs_decodeSync_amd64_error_match_len_ofs_mismatch:
+ MOVD 24(RSP), R0
+ MOVD ctx+16(FP), R1
+ MOVD R0, 216(R1)
+ MOVD $0x00000001, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with match too long error
+sequenceDecs_decodeSync_amd64_error_match_len_too_big:
+ MOVD ctx+16(FP), R0
+ MOVD 24(RSP), R1
+ MOVD R1, 216(R0)
+ MOVD $0x00000002, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with match offset too long error
+error_match_off_too_big:
+ MOVD ctx+16(FP), R0
+ MOVD 16(RSP), R1
+ MOVD R1, 224(R0)
+ MOVD R11, 136(R0)
+ MOVD $0x00000003, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with not enough literals error
+error_not_enough_literals:
+ MOVD ctx+16(FP), R0
+ MOVD 32(RSP), R1
+ MOVD R1, 208(R0)
+ MOVD $0x00000004, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with overread error
+error_overread:
+ MOVD $0x00000006, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with not enough output space error
+error_not_enough_space:
+ MOVD ctx+16(FP), R0
+ MOVD 32(RSP), R1
+ MOVD R1, 208(R0)
+ MOVD 24(RSP), R1
+ MOVD R1, 216(R0)
+ MOVD R11, 136(R0)
+ MOVD $0x00000005, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+// skipped sequenceDecs_decodeSync_bmi2 (generic twin preferred on arm64)
+
+// func sequenceDecs_decodeSync_safe_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
+// Requires: CMOV, SSE
+TEXT ·sequenceDecs_decodeSync_safe_arm64(SB), $64-32
+ MOVD br+8(FP), R1
+ MOVD 24(R1), R2
+ MOVBU 40(R1), R3
+ MOVD (R1), R0
+ MOVD 32(R1), R5
+ ADD R5, R0, R0
+ MOVD R0, 8(RSP)
+ MOVD ctx+16(FP), R0
+ MOVD 72(R0), R6
+ MOVD 80(R0), R7
+ MOVD 88(R0), R8
+ MOVD $0, R1
+ MOVD R1, 16(RSP)
+ MOVD R1, 24(RSP)
+ MOVD R1, 32(RSP)
+ MOVD 112(R0), R9
+ MOVD 128(R0), R1
+ MOVD R1, 40(RSP)
+ MOVD 144(R0), R10
+ MOVD 136(R0), R11
+ MOVD 200(R0), R1
+ MOVD R1, 64(RSP)
+ MOVD 176(R0), R1
+ MOVD R1, 56(RSP)
+ MOVD 184(R0), R0
+ MOVD R0, 48(RSP)
+ MOVD 48(RSP), R0
+ MOVD 56(RSP), R16
+ ADD R0, R16, R16
+ MOVD R16, 56(RSP)
+
+ // Calculate pointer to s.out[cap(s.out)] (a past-end pointer)
+ MOVD 40(RSP), R16
+ ADD R9, R16, R16
+ MOVD R16, 40(RSP)
+
+ // outBase += outPosition
+ ADD R11, R9, R9
+
+sequenceDecs_decodeSync_safe_amd64_main_loop:
+ MOVD 8(RSP), R12
+
+ // Fill bitreader to have enough for the offset and match length.
+ CMP $0x08, R5
+ BLT sequenceDecs_decodeSync_safe_amd64_fill_byte_by_byte
+ MOVD R3, R0
+ LSR $0x03, R0, R0
+ SUB R0, R12, R12
+ MOVD (R12), R2
+ SUB R0, R5, R5
+ AND $0x07, R3, R3
+ JMP sequenceDecs_decodeSync_safe_amd64_fill_end
+
+sequenceDecs_decodeSync_safe_amd64_fill_byte_by_byte:
+ CMP $0x00, R5
+ BLE sequenceDecs_decodeSync_safe_amd64_fill_check_overread
+ CMP $0x07, R3
+ BLE sequenceDecs_decodeSync_safe_amd64_fill_end
+ LSL $0x08, R2, R2
+ SUB $0x01, R12, R12
+ SUB $0x01, R5, R5
+ SUB $0x08, R3, R3
+ MOVBU (R12), R0
+ ORR R0, R2, R2
+ JMP sequenceDecs_decodeSync_safe_amd64_fill_byte_by_byte
+
+sequenceDecs_decodeSync_safe_amd64_fill_check_overread:
+ CMP $0x40, R3
+ BHI error_overread
+
+sequenceDecs_decodeSync_safe_amd64_fill_end:
+ // Update offset
+ MOVD R8, R0
+ MOVD R3, R1
+ MOVD R2, R13
+ LSL R1, R13, R13
+ UBFX $8, R0, $8, R16
+ BFI $0, R16, $8, R1
+ LSR $0x20, R0, R0
+ TST R1, R1
+ BEQ sequenceDecs_decodeSync_safe_amd64_of_update_zero
+ ADD R1, R3, R3
+ CMP $0x40, R3
+ BHI sequenceDecs_decodeSync_safe_amd64_of_update_zero
+ CMP $0x40, R1
+ BHS sequenceDecs_decodeSync_safe_amd64_of_update_zero
+ NEG R1, R1
+ LSR R1, R13, R13
+ ADD R13, R0, R0
+
+sequenceDecs_decodeSync_safe_amd64_of_update_zero:
+ MOVD R0, 16(RSP)
+
+ // Update match length
+ MOVD R7, R0
+ MOVD R3, R1
+ MOVD R2, R13
+ LSL R1, R13, R13
+ UBFX $8, R0, $8, R16
+ BFI $0, R16, $8, R1
+ LSR $0x20, R0, R0
+ TST R1, R1
+ BEQ sequenceDecs_decodeSync_safe_amd64_ml_update_zero
+ ADD R1, R3, R3
+ CMP $0x40, R3
+ BHI sequenceDecs_decodeSync_safe_amd64_ml_update_zero
+ CMP $0x40, R1
+ BHS sequenceDecs_decodeSync_safe_amd64_ml_update_zero
+ NEG R1, R1
+ LSR R1, R13, R13
+ ADD R13, R0, R0
+
+sequenceDecs_decodeSync_safe_amd64_ml_update_zero:
+ MOVD R0, 24(RSP)
+
+ // Fill bitreader to have enough for the remaining
+ CMP $0x08, R5
+ BLT sequenceDecs_decodeSync_safe_amd64_fill_2_byte_by_byte
+ MOVD R3, R0
+ LSR $0x03, R0, R0
+ SUB R0, R12, R12
+ MOVD (R12), R2
+ SUB R0, R5, R5
+ AND $0x07, R3, R3
+ JMP sequenceDecs_decodeSync_safe_amd64_fill_2_end
+
+sequenceDecs_decodeSync_safe_amd64_fill_2_byte_by_byte:
+ CMP $0x00, R5
+ BLE sequenceDecs_decodeSync_safe_amd64_fill_2_check_overread
+ CMP $0x07, R3
+ BLE sequenceDecs_decodeSync_safe_amd64_fill_2_end
+ LSL $0x08, R2, R2
+ SUB $0x01, R12, R12
+ SUB $0x01, R5, R5
+ SUB $0x08, R3, R3
+ MOVBU (R12), R0
+ ORR R0, R2, R2
+ JMP sequenceDecs_decodeSync_safe_amd64_fill_2_byte_by_byte
+
+sequenceDecs_decodeSync_safe_amd64_fill_2_check_overread:
+ CMP $0x40, R3
+ BHI error_overread
+
+sequenceDecs_decodeSync_safe_amd64_fill_2_end:
+ // Update literal length
+ MOVD R6, R0
+ MOVD R3, R1
+ MOVD R2, R13
+ LSL R1, R13, R13
+ UBFX $8, R0, $8, R16
+ BFI $0, R16, $8, R1
+ LSR $0x20, R0, R0
+ TST R1, R1
+ BEQ sequenceDecs_decodeSync_safe_amd64_ll_update_zero
+ ADD R1, R3, R3
+ CMP $0x40, R3
+ BHI sequenceDecs_decodeSync_safe_amd64_ll_update_zero
+ CMP $0x40, R1
+ BHS sequenceDecs_decodeSync_safe_amd64_ll_update_zero
+ NEG R1, R1
+ LSR R1, R13, R13
+ ADD R13, R0, R0
+
+sequenceDecs_decodeSync_safe_amd64_ll_update_zero:
+ MOVD R0, 32(RSP)
+
+ // Fill bitreader for state updates
+ MOVD R12, 8(RSP)
+ MOVD R8, R0
+ LSR $0x08, R0, R0
+ MOVBU R0, R0
+ MOVD ctx+16(FP), R1
+ MOVD 96(R1), R16
+ CMP $0x00, R16
+ BEQ sequenceDecs_decodeSync_safe_amd64_skip_update
+
+ // Update Literal Length State
+ MOVBU R6, R12
+ LSRW $0x10, R6, R6
+ ADD R12, R3, R1
+ MOVD R2, R13
+ MOVD R1, R3
+ NEG R1, R16
+ ROR R16, R13, R13
+ MOVD $0x00000001, R14
+ BFI $0, R12, $8, R1
+ LSLW R1, R14, R14
+ SUBW $1, R14, R14
+ AND R14, R13, R13
+ ADD R13, R6, R6
+
+ // Load ctx.llTable
+ MOVD ctx+16(FP), R1
+ MOVD (R1), R1
+ ADD R6<<3, R1, R15
+ MOVD (R15), R6
+
+ // Update Match Length State
+ MOVBU R7, R12
+ LSRW $0x10, R7, R7
+ ADD R12, R3, R1
+ MOVD R2, R13
+ MOVD R1, R3
+ NEG R1, R16
+ ROR R16, R13, R13
+ MOVD $0x00000001, R14
+ BFI $0, R12, $8, R1
+ LSLW R1, R14, R14
+ SUBW $1, R14, R14
+ AND R14, R13, R13
+ ADD R13, R7, R7
+
+ // Load ctx.mlTable
+ MOVD ctx+16(FP), R1
+ MOVD 24(R1), R1
+ ADD R7<<3, R1, R15
+ MOVD (R15), R7
+
+ // Update Offset State
+ MOVBU R8, R12
+ LSRW $0x10, R8, R8
+ ADD R12, R3, R1
+ MOVD R2, R13
+ MOVD R1, R3
+ NEG R1, R16
+ ROR R16, R13, R13
+ MOVD $0x00000001, R14
+ BFI $0, R12, $8, R1
+ LSLW R1, R14, R14
+ SUBW $1, R14, R14
+ AND R14, R13, R13
+ ADD R13, R8, R8
+
+ // Load ctx.ofTable
+ MOVD ctx+16(FP), R1
+ MOVD 48(R1), R1
+ ADD R8<<3, R1, R15
+ MOVD (R15), R8
+
+sequenceDecs_decodeSync_safe_amd64_skip_update:
+ // Adjust offset
+ MOVD s+0(FP), R1
+ MOVD 16(RSP), R12
+ CMP $0x01, R0
+ BLS sequenceDecs_decodeSync_safe_amd64_adjust_offsetB_1_or_0
+ ADD $144, R1, R15
+ VLD1 (R15), [V0.B16]
+ MOVD R12, 144(R1)
+ ADD $152, R1, R15
+ VST1 [V0.B16], (R15)
+ JMP sequenceDecs_decodeSync_safe_amd64_after_adjust
+
+sequenceDecs_decodeSync_safe_amd64_adjust_offsetB_1_or_0:
+ MOVD 32(RSP), R16
+ CMP $0x00000000, R16
+ BNE sequenceDecs_decodeSync_safe_amd64_adjust_offset_maybezero
+ ADD $1, R12, R12
+ JMP sequenceDecs_decodeSync_safe_amd64_adjust_offset_nonzero
+
+sequenceDecs_decodeSync_safe_amd64_adjust_offset_maybezero:
+ TST R12, R12
+ BNE sequenceDecs_decodeSync_safe_amd64_adjust_offset_nonzero
+ MOVD 144(R1), R12
+ JMP sequenceDecs_decodeSync_safe_amd64_after_adjust
+
+sequenceDecs_decodeSync_safe_amd64_adjust_offset_nonzero:
+ MOVD R12, R0
+ MOVD $0, R13
+ MOVD $-1, R14
+ CMP $0x03, R12
+ CSEL EQ, R13, R0, R0
+ CSEL EQ, R14, R13, R13
+ ADD R0<<3, R1, R15
+ MOVD 144(R15), R16
+ ADDS R16, R13, R13
+ BNE sequenceDecs_decodeSync_safe_amd64_adjust_temp_valid
+ MOVD $0x00000001, R13
+
+sequenceDecs_decodeSync_safe_amd64_adjust_temp_valid:
+ CMP $0x01, R12
+ BEQ sequenceDecs_decodeSync_safe_amd64_adjust_skip
+ MOVD 152(R1), R0
+ MOVD R0, 160(R1)
+
+sequenceDecs_decodeSync_safe_amd64_adjust_skip:
+ MOVD 144(R1), R0
+ MOVD R0, 152(R1)
+ MOVD R13, 144(R1)
+ MOVD R13, R12
+
+sequenceDecs_decodeSync_safe_amd64_after_adjust:
+ MOVD R12, 16(RSP)
+
+ // Check values
+ MOVD 24(RSP), R0
+ MOVD 32(RSP), R1
+ ADD R1, R0, R13
+ MOVD s+0(FP), R14
+ MOVD 256(R14), R16
+ ADD R13, R16, R16
+ MOVD R16, 256(R14)
+ MOVD ctx+16(FP), R13
+ MOVD 104(R13), R16
+ SUBS R1, R16, R16
+ MOVD R16, 104(R13)
+ BMI error_not_enough_literals
+ CMP $0x00020002, R0
+ BHI sequenceDecs_decodeSync_safe_amd64_error_match_len_too_big
+ TST R12, R12
+ BNE sequenceDecs_decodeSync_safe_amd64_match_len_ofs_ok
+ TST R0, R0
+ BNE sequenceDecs_decodeSync_safe_amd64_error_match_len_ofs_mismatch
+
+sequenceDecs_decodeSync_safe_amd64_match_len_ofs_ok:
+ MOVD 32(RSP), R0
+ MOVD 16(RSP), R1
+ MOVD 24(RSP), R12
+
+ // Check if we have enough space in s.out
+ ADD R12, R0, R13
+ ADD R9, R13, R13
+ MOVD 40(RSP), R16
+ CMP R16, R13
+ BHI error_not_enough_space
+
+ // Copy literals
+ TST R0, R0
+ BEQ check_offset
+ MOVD R0, R13
+ SUBS $0x10, R13, R13
+ BLO copy_1_small
+
+copy_1_loop:
+ VLD1 (R10), [V0.B16]
+ VST1 [V0.B16], (R9)
+ ADD $0x10, R10, R10
+ ADD $0x10, R9, R9
+ SUBS $0x10, R13, R13
+ BHS copy_1_loop
+ ADD R13, R10, R10
+ ADD $16, R10, R10
+ ADD R13, R9, R9
+ ADD $16, R9, R9
+ ADD $-16, R10, R15
+ VLD1 (R15), [V0.B16]
+ ADD $-16, R9, R15
+ VST1 [V0.B16], (R15)
+ JMP copy_1_end
+
+copy_1_small:
+ CMP $0x03, R0
+ BEQ copy_1_move_3
+ BLO copy_1_move_1or2
+ CMP $0x08, R0
+ BLO copy_1_move_4through7
+ JMP copy_1_move_8through16
+
+copy_1_move_1or2:
+ MOVBU (R10), R16
+ BFI $0, R16, $8, R13
+ ADD R0, R10, R15
+ MOVBU -1(R15), R16
+ BFI $0, R16, $8, R14
+ MOVB R13, (R9)
+ ADD R0, R9, R15
+ MOVB R14, -1(R15)
+ ADD R0, R10, R10
+ ADD R0, R9, R9
+ JMP copy_1_end
+
+copy_1_move_3:
+ MOVHU (R10), R13
+ MOVBU 2(R10), R16
+ BFI $0, R16, $8, R14
+ MOVH R13, (R9)
+ MOVB R14, 2(R9)
+ ADD R0, R10, R10
+ ADD R0, R9, R9
+ JMP copy_1_end
+
+copy_1_move_4through7:
+ MOVWU (R10), R13
+ ADD R0, R10, R15
+ MOVWU -4(R15), R14
+ MOVW R13, (R9)
+ ADD R0, R9, R15
+ MOVW R14, -4(R15)
+ ADD R0, R10, R10
+ ADD R0, R9, R9
+ JMP copy_1_end
+
+copy_1_move_8through16:
+ MOVD (R10), R13
+ ADD R0, R10, R15
+ MOVD -8(R15), R14
+ MOVD R13, (R9)
+ ADD R0, R9, R15
+ MOVD R14, -8(R15)
+ ADD R0, R10, R10
+ ADD R0, R9, R9
+
+copy_1_end:
+ ADD R0, R11, R11
+
+ // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize)
+check_offset:
+ MOVD R11, R0
+ MOVD 48(RSP), R16
+ ADD R16, R0, R0
+ CMP R0, R1
+ BGT error_match_off_too_big
+ MOVD 64(RSP), R16
+ CMP R16, R1
+ BGT error_match_off_too_big
+
+ // Copy match from history
+ MOVD R1, R0
+ SUBS R11, R0, R0
+ BLS copy_match
+ MOVD 56(RSP), R13
+ SUB R0, R13, R13
+ CMP R0, R12
+ BGT copy_all_from_history
+ MOVD R12, R0
+ SUBS $0x10, R0, R0
+ BLO copy_4_small
+
+copy_4_loop:
+ VLD1 (R13), [V0.B16]
+ VST1 [V0.B16], (R9)
+ ADD $0x10, R13, R13
+ ADD $0x10, R9, R9
+ SUBS $0x10, R0, R0
+ BHS copy_4_loop
+ ADD R0, R13, R13
+ ADD $16, R13, R13
+ ADD R0, R9, R9
+ ADD $16, R9, R9
+ ADD $-16, R13, R15
+ VLD1 (R15), [V0.B16]
+ ADD $-16, R9, R15
+ VST1 [V0.B16], (R15)
+ JMP copy_4_end
+
+copy_4_small:
+ CMP $0x03, R12
+ BEQ copy_4_move_3
+ CMP $0x08, R12
+ BLO copy_4_move_4through7
+ JMP copy_4_move_8through16
+
+copy_4_move_3:
+ MOVHU (R13), R0
+ MOVBU 2(R13), R16
+ BFI $0, R16, $8, R1
+ MOVH R0, (R9)
+ MOVB R1, 2(R9)
+ ADD R12, R13, R13
+ ADD R12, R9, R9
+ JMP copy_4_end
+
+copy_4_move_4through7:
+ MOVWU (R13), R0
+ ADD R12, R13, R15
+ MOVWU -4(R15), R1
+ MOVW R0, (R9)
+ ADD R12, R9, R15
+ MOVW R1, -4(R15)
+ ADD R12, R13, R13
+ ADD R12, R9, R9
+ JMP copy_4_end
+
+copy_4_move_8through16:
+ MOVD (R13), R0
+ ADD R12, R13, R15
+ MOVD -8(R15), R1
+ MOVD R0, (R9)
+ ADD R12, R9, R15
+ MOVD R1, -8(R15)
+ ADD R12, R13, R13
+ ADD R12, R9, R9
+
+copy_4_end:
+ ADD R12, R11, R11
+ JMP handle_loop
+ JMP loop_finished
+
+copy_all_from_history:
+ MOVD R0, R14
+ SUBS $0x10, R14, R14
+ BLO copy_5_small
+
+copy_5_loop:
+ VLD1 (R13), [V0.B16]
+ VST1 [V0.B16], (R9)
+ ADD $0x10, R13, R13
+ ADD $0x10, R9, R9
+ SUBS $0x10, R14, R14
+ BHS copy_5_loop
+ ADD R14, R13, R13
+ ADD $16, R13, R13
+ ADD R14, R9, R9
+ ADD $16, R9, R9
+ ADD $-16, R13, R15
+ VLD1 (R15), [V0.B16]
+ ADD $-16, R9, R15
+ VST1 [V0.B16], (R15)
+ JMP copy_5_end
+
+copy_5_small:
+ CMP $0x03, R0
+ BEQ copy_5_move_3
+ BLO copy_5_move_1or2
+ CMP $0x08, R0
+ BLO copy_5_move_4through7
+ JMP copy_5_move_8through16
+
+copy_5_move_1or2:
+ MOVBU (R13), R16
+ BFI $0, R16, $8, R14
+ ADD R0, R13, R15
+ MOVBU -1(R15), R16
+ BFI $0, R16, $8, R4
+ MOVB R14, (R9)
+ ADD R0, R9, R15
+ MOVB R4, -1(R15)
+ ADD R0, R13, R13
+ ADD R0, R9, R9
+ JMP copy_5_end
+
+copy_5_move_3:
+ MOVHU (R13), R14
+ MOVBU 2(R13), R16
+ BFI $0, R16, $8, R4
+ MOVH R14, (R9)
+ MOVB R4, 2(R9)
+ ADD R0, R13, R13
+ ADD R0, R9, R9
+ JMP copy_5_end
+
+copy_5_move_4through7:
+ MOVWU (R13), R14
+ ADD R0, R13, R15
+ MOVWU -4(R15), R4
+ MOVW R14, (R9)
+ ADD R0, R9, R15
+ MOVW R4, -4(R15)
+ ADD R0, R13, R13
+ ADD R0, R9, R9
+ JMP copy_5_end
+
+copy_5_move_8through16:
+ MOVD (R13), R14
+ ADD R0, R13, R15
+ MOVD -8(R15), R4
+ MOVD R14, (R9)
+ ADD R0, R9, R15
+ MOVD R4, -8(R15)
+ ADD R0, R13, R13
+ ADD R0, R9, R9
+
+copy_5_end:
+ ADD R0, R11, R11
+ SUB R0, R12, R12
+
+ // Copy match from the current buffer
+copy_match:
+ MOVD R9, R0
+ SUB R1, R0, R0
+
+ // ml <= mo
+ CMP R1, R12
+ BHI copy_overlapping_match
+
+ // Copy non-overlapping match
+ ADD R12, R11, R11
+ MOVD R12, R1
+ SUBS $0x10, R1, R1
+ BLO copy_2_small
+
+copy_2_loop:
+ VLD1 (R0), [V0.B16]
+ VST1 [V0.B16], (R9)
+ ADD $0x10, R0, R0
+ ADD $0x10, R9, R9
+ SUBS $0x10, R1, R1
+ BHS copy_2_loop
+ ADD R1, R0, R0
+ ADD $16, R0, R0
+ ADD R1, R9, R9
+ ADD $16, R9, R9
+ ADD $-16, R0, R15
+ VLD1 (R15), [V0.B16]
+ ADD $-16, R9, R15
+ VST1 [V0.B16], (R15)
+ JMP copy_2_end
+
+copy_2_small:
+ CMP $0x03, R12
+ BEQ copy_2_move_3
+ BLO copy_2_move_1or2
+ CMP $0x08, R12
+ BLO copy_2_move_4through7
+ JMP copy_2_move_8through16
+
+copy_2_move_1or2:
+ MOVBU (R0), R16
+ BFI $0, R16, $8, R1
+ ADD R12, R0, R15
+ MOVBU -1(R15), R16
+ BFI $0, R16, $8, R13
+ MOVB R1, (R9)
+ ADD R12, R9, R15
+ MOVB R13, -1(R15)
+ ADD R12, R0, R0
+ ADD R12, R9, R9
+ JMP copy_2_end
+
+copy_2_move_3:
+ MOVHU (R0), R1
+ MOVBU 2(R0), R16
+ BFI $0, R16, $8, R13
+ MOVH R1, (R9)
+ MOVB R13, 2(R9)
+ ADD R12, R0, R0
+ ADD R12, R9, R9
+ JMP copy_2_end
+
+copy_2_move_4through7:
+ MOVWU (R0), R1
+ ADD R12, R0, R15
+ MOVWU -4(R15), R13
+ MOVW R1, (R9)
+ ADD R12, R9, R15
+ MOVW R13, -4(R15)
+ ADD R12, R0, R0
+ ADD R12, R9, R9
+ JMP copy_2_end
+
+copy_2_move_8through16:
+ MOVD (R0), R1
+ ADD R12, R0, R15
+ MOVD -8(R15), R13
+ MOVD R1, (R9)
+ ADD R12, R9, R15
+ MOVD R13, -8(R15)
+ ADD R12, R0, R0
+ ADD R12, R9, R9
+
+copy_2_end:
+ JMP handle_loop
+
+ // Copy overlapping match
+copy_overlapping_match:
+ ADD R12, R11, R11
+
+copy_slow_3:
+ MOVBU (R0), R16
+ BFI $0, R16, $8, R1
+ MOVB R1, (R9)
+ ADD $1, R0, R0
+ ADD $1, R9, R9
+ SUBS $1, R12, R12
+ BNE copy_slow_3
+
+handle_loop:
+ MOVD ctx+16(FP), R0
+ MOVD 96(R0), R16
+ SUBS $1, R16, R16
+ MOVD R16, 96(R0)
+ BPL sequenceDecs_decodeSync_safe_amd64_main_loop
+
+loop_finished:
+ MOVD br+8(FP), R0
+ MOVD R2, 24(R0)
+ MOVB R3, 40(R0)
+ MOVD R5, 32(R0)
+
+ // Update the context
+ MOVD ctx+16(FP), R0
+ MOVD R11, 136(R0)
+ MOVD 144(R0), R1
+ SUB R1, R10, R10
+ MOVD R10, 168(R0)
+
+ // Return success
+ MOVD $0x00000000, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with match length error
+sequenceDecs_decodeSync_safe_amd64_error_match_len_ofs_mismatch:
+ MOVD 24(RSP), R0
+ MOVD ctx+16(FP), R1
+ MOVD R0, 216(R1)
+ MOVD $0x00000001, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with match too long error
+sequenceDecs_decodeSync_safe_amd64_error_match_len_too_big:
+ MOVD ctx+16(FP), R0
+ MOVD 24(RSP), R1
+ MOVD R1, 216(R0)
+ MOVD $0x00000002, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with match offset too long error
+error_match_off_too_big:
+ MOVD ctx+16(FP), R0
+ MOVD 16(RSP), R1
+ MOVD R1, 224(R0)
+ MOVD R11, 136(R0)
+ MOVD $0x00000003, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with not enough literals error
+error_not_enough_literals:
+ MOVD ctx+16(FP), R0
+ MOVD 32(RSP), R1
+ MOVD R1, 208(R0)
+ MOVD $0x00000004, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with overread error
+error_overread:
+ MOVD $0x00000006, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+ // Return with not enough output space error
+error_not_enough_space:
+ MOVD ctx+16(FP), R0
+ MOVD 32(RSP), R1
+ MOVD R1, 208(R0)
+ MOVD 24(RSP), R1
+ MOVD R1, 216(R0)
+ MOVD R11, 136(R0)
+ MOVD $0x00000005, R16
+ MOVD R16, ret+24(FP)
+ RET
+
+// skipped sequenceDecs_decodeSync_safe_bmi2 (generic twin preferred on arm64)
diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_asm.go b/vendor/github.com/klauspost/compress/zstd/seqdec_asm.go
new file mode 100644
index 00000000..42ce5de7
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/seqdec_asm.go
@@ -0,0 +1,316 @@
+//go:build (amd64 || arm64) && !appengine && !noasm && gc
+
+package zstd
+
+import (
+ "fmt"
+ "io"
+)
+
+// This file holds the parts of the assembly sequence decoder that are identical
+// across architectures: the context structs exchanged with the asm, the error
+// codes, and the decode/decodeSync/executeSimple wrappers. Each architecture
+// supplies the small dispatch helpers (decodeAsm, decodeSyncAsm,
+// executeSimpleAsm) that select the concrete asm routine — amd64 also chooses a
+// BMI2 variant, arm64 has a single implementation.
+
+type decodeSyncAsmContext struct {
+ llTable []decSymbol
+ mlTable []decSymbol
+ ofTable []decSymbol
+ llState uint64
+ mlState uint64
+ ofState uint64
+ iteration int
+ litRemain int
+ out []byte
+ outPosition int
+ literals []byte
+ litPosition int
+ history []byte
+ windowSize int
+ ll int // set on error (not for all errors, please refer to _generate/gen.go)
+ ml int // set on error (not for all errors, please refer to _generate/gen.go)
+ mo int // set on error (not for all errors, please refer to _generate/gen.go)
+}
+
+type decodeAsmContext struct {
+ llTable []decSymbol
+ mlTable []decSymbol
+ ofTable []decSymbol
+ llState uint64
+ mlState uint64
+ ofState uint64
+ iteration int
+ seqs []seqVals
+ litRemain int
+}
+
+type executeAsmContext struct {
+ seqs []seqVals
+ seqIndex int
+ out []byte
+ history []byte
+ literals []byte
+ outPosition int
+ litPosition int
+ windowSize int
+}
+
+const noError = 0
+
+// error reported when mo == 0 && ml > 0
+const errorMatchLenOfsMismatch = 1
+
+// error reported when ml > maxMatchLen
+const errorMatchLenTooBig = 2
+
+// error reported when mo > available history or mo > s.windowSize
+const errorMatchOffTooBig = 3
+
+// error reported when the sum of literal lengths exeeceds the literal buffer size
+const errorNotEnoughLiterals = 4
+
+// error reported when capacity of `out` is too small
+const errorNotEnoughSpace = 5
+
+// error reported when bits are overread.
+const errorOverread = 6
+
+// useSafeDecodeSync reports whether decodeSyncSimple must use the bounds-exact
+// ("safe") copy variants for the current buffer geometry.
+//
+// When the output and literal buffers have compressedBlockOverAlloc (16)
+// bytes of slack past their logical use, the assembly may use extended
+// memory copies that read and write in 16-byte blocks, overrunning the end
+// of a literal run or match by up to 15 bytes. Otherwise it must use the
+// bounds-exact ("safe") copies. This mirrors the analogous, always-dynamic
+// selection in executeSimple below.
+//
+// The unsafe copies were disabled in #644 (2022) as a mitigation for a
+// crash, but that crash's root cause — an unguarded bitReader overread that
+// produced out-of-range match offsets/lengths — was fixed three days later
+// in #645, which also added the fuzz corpus that has guarded this path since.
+// See #1168. An asan-instrumented fuzz job (see .github/workflows/go.yml)
+// covers the extended-copy path, which -race and plain fuzzing cannot.
+func (s *sequenceDecs) useSafeDecodeSync() bool {
+ if s.maxSyncLen == 0 && cap(s.out)-len(s.out) < maxCompressedBlockSizeAlloc {
+ return true
+ }
+ if s.maxSyncLen > 0 && cap(s.out)-len(s.out)-compressedBlockOverAlloc < int(s.maxSyncLen) {
+ return true
+ }
+ if cap(s.literals) < len(s.literals)+compressedBlockOverAlloc {
+ return true
+ }
+ return false
+}
+
+// decode sequences from the stream with the provided history but without a dictionary.
+func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) {
+ if len(s.dict) > 0 {
+ return false, nil
+ }
+ if s.maxSyncLen == 0 && cap(s.out)-len(s.out) < maxCompressedBlockSize {
+ return false, nil
+ }
+
+ useSafe := s.useSafeDecodeSync()
+
+ br := s.br
+
+ maxBlockSize := min(s.windowSize, maxCompressedBlockSize)
+
+ ctx := decodeSyncAsmContext{
+ llTable: s.litLengths.fse.dt[:maxTablesize],
+ mlTable: s.matchLengths.fse.dt[:maxTablesize],
+ ofTable: s.offsets.fse.dt[:maxTablesize],
+ llState: uint64(s.litLengths.state.state),
+ mlState: uint64(s.matchLengths.state.state),
+ ofState: uint64(s.offsets.state.state),
+ iteration: s.nSeqs - 1,
+ litRemain: len(s.literals),
+ out: s.out,
+ outPosition: len(s.out),
+ literals: s.literals,
+ windowSize: s.windowSize,
+ history: hist,
+ }
+
+ s.seqSize = 0
+ startSize := len(s.out)
+
+ errCode := decodeSyncAsm(s, br, &ctx, useSafe)
+ switch errCode {
+ case noError:
+ break
+
+ case errorMatchLenOfsMismatch:
+ return true, fmt.Errorf("zero matchoff and matchlen (%d) > 0", ctx.ml)
+
+ case errorMatchLenTooBig:
+ return true, fmt.Errorf("match len (%d) bigger than max allowed length", ctx.ml)
+
+ case errorMatchOffTooBig:
+ return true, fmt.Errorf("match offset (%d) bigger than current history (%d)",
+ ctx.mo, ctx.outPosition+len(hist)-startSize)
+
+ case errorNotEnoughLiterals:
+ return true, fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available",
+ ctx.ll, ctx.litRemain+ctx.ll)
+
+ case errorOverread:
+ return true, io.ErrUnexpectedEOF
+
+ case errorNotEnoughSpace:
+ size := ctx.outPosition + ctx.ll + ctx.ml
+ if debugDecoder {
+ println("msl:", s.maxSyncLen, "cap", cap(s.out), "bef:", startSize, "sz:", size-startSize, "mbs:", maxBlockSize, "outsz:", cap(s.out)-startSize)
+ }
+ return true, fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
+
+ default:
+ return true, fmt.Errorf("sequenceDecs_decode returned erroneous code %d", errCode)
+ }
+
+ s.seqSize += ctx.litRemain
+ if s.seqSize > maxBlockSize {
+ return true, fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
+ }
+ err := br.close()
+ if err != nil {
+ printf("Closing sequences: %v, %+v\n", err, *br)
+ return true, err
+ }
+
+ s.literals = s.literals[ctx.litPosition:]
+ t := ctx.outPosition
+ s.out = s.out[:t]
+
+ // Add final literals
+ s.out = append(s.out, s.literals...)
+ if debugDecoder {
+ t += len(s.literals)
+ if t != len(s.out) {
+ panic(fmt.Errorf("length mismatch, want %d, got %d", len(s.out), t))
+ }
+ }
+
+ return true, nil
+}
+
+// decode sequences from the stream without the provided history.
+func (s *sequenceDecs) decode(seqs []seqVals) error {
+ br := s.br
+
+ maxBlockSize := min(s.windowSize, maxCompressedBlockSize)
+
+ ctx := decodeAsmContext{
+ llTable: s.litLengths.fse.dt[:maxTablesize],
+ mlTable: s.matchLengths.fse.dt[:maxTablesize],
+ ofTable: s.offsets.fse.dt[:maxTablesize],
+ llState: uint64(s.litLengths.state.state),
+ mlState: uint64(s.matchLengths.state.state),
+ ofState: uint64(s.offsets.state.state),
+ seqs: seqs,
+ iteration: len(seqs) - 1,
+ litRemain: len(s.literals),
+ }
+
+ if debugDecoder {
+ println("decode: decoding", len(seqs), "sequences", br.remain(), "bits remain on stream")
+ }
+
+ s.seqSize = 0
+ lte56bits := s.maxBits+s.offsets.fse.actualTableLog+s.matchLengths.fse.actualTableLog+s.litLengths.fse.actualTableLog <= 56
+ errCode := decodeAsm(s, br, &ctx, lte56bits)
+ if errCode != 0 {
+ i := len(seqs) - ctx.iteration - 1
+ switch errCode {
+ case errorMatchLenOfsMismatch:
+ ml := ctx.seqs[i].ml
+ return fmt.Errorf("zero matchoff and matchlen (%d) > 0", ml)
+
+ case errorMatchLenTooBig:
+ ml := ctx.seqs[i].ml
+ return fmt.Errorf("match len (%d) bigger than max allowed length", ml)
+
+ case errorNotEnoughLiterals:
+ ll := ctx.seqs[i].ll
+ return fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available", ll, ctx.litRemain+ll)
+ case errorOverread:
+ return io.ErrUnexpectedEOF
+ }
+
+ return fmt.Errorf("sequenceDecs_decode_amd64 returned erroneous code %d", errCode)
+ }
+
+ if ctx.litRemain < 0 {
+ return fmt.Errorf("literal count is too big: total available %d, total requested %d",
+ len(s.literals), len(s.literals)-ctx.litRemain)
+ }
+
+ s.seqSize += ctx.litRemain
+ if s.seqSize > maxBlockSize {
+ return fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
+ }
+ if debugDecoder {
+ println("decode: ", br.remain(), "bits remain on stream. code:", errCode)
+ }
+ err := br.close()
+ if err != nil {
+ printf("Closing sequences: %v, %+v\n", err, *br)
+ }
+ return err
+}
+
+// executeSimple handles cases when dictionary is not used.
+func (s *sequenceDecs) executeSimple(seqs []seqVals, hist []byte) error {
+ // Ensure we have enough output size...
+ if len(s.out)+s.seqSize+compressedBlockOverAlloc > cap(s.out) {
+ addBytes := s.seqSize + len(s.out) + compressedBlockOverAlloc
+ s.out = append(s.out, make([]byte, addBytes)...)
+ s.out = s.out[:len(s.out)-addBytes]
+ }
+
+ if debugDecoder {
+ printf("Execute %d seqs with literals: %d into %d bytes\n", len(seqs), len(s.literals), s.seqSize)
+ }
+
+ var t = len(s.out)
+ out := s.out[:t+s.seqSize]
+
+ ctx := executeAsmContext{
+ seqs: seqs,
+ seqIndex: 0,
+ out: out,
+ history: hist,
+ outPosition: t,
+ litPosition: 0,
+ literals: s.literals,
+ windowSize: s.windowSize,
+ }
+ // useSafe avoids overwriting the output buffer when the literals slice has
+ // not been allocated with the required over-allocation slack.
+ useSafe := cap(s.literals) < len(s.literals)+compressedBlockOverAlloc
+
+ ok := executeSimpleAsm(&ctx, useSafe)
+ if !ok {
+ return fmt.Errorf("match offset (%d) bigger than current history (%d)",
+ seqs[ctx.seqIndex].mo, ctx.outPosition+len(hist))
+ }
+ s.literals = s.literals[ctx.litPosition:]
+ t = ctx.outPosition
+
+ // Add final literals
+ copy(out[t:], s.literals)
+ if debugDecoder {
+ t += len(s.literals)
+ if t != len(out) {
+ panic(fmt.Errorf("length mismatch, want %d, got %d, ss: %d", len(out), t, s.seqSize))
+ }
+ }
+ s.out = out
+
+ return nil
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_generic.go b/vendor/github.com/klauspost/compress/zstd/seqdec_generic.go
index 7cec2197..8a3db6ba 100644
--- a/vendor/github.com/klauspost/compress/zstd/seqdec_generic.go
+++ b/vendor/github.com/klauspost/compress/zstd/seqdec_generic.go
@@ -1,5 +1,4 @@
-//go:build !amd64 || appengine || !gc || noasm
-// +build !amd64 appengine !gc noasm
+//go:build (!amd64 && !arm64) || appengine || !gc || noasm
package zstd
diff --git a/vendor/github.com/klauspost/compress/zstd/snappy.go b/vendor/github.com/klauspost/compress/zstd/snappy.go
index 336c2889..36c56f36 100644
--- a/vendor/github.com/klauspost/compress/zstd/snappy.go
+++ b/vendor/github.com/klauspost/compress/zstd/snappy.go
@@ -334,9 +334,10 @@ func decodeSnappy(blk *blockEnc, src []byte) error {
return errUnsupportedLiteralLength
}
- //if length > snappyMaxBlockSize-d || uint32(length) > len(src)-s {
- // return ErrSnappyCorrupt
- //}
+ if length > len(src)-s {
+ println("length > len(src)-s", length, len(src)-s)
+ return ErrSnappyCorrupt
+ }
blk.literals = append(blk.literals, src[s:s+length]...)
//println(length, "litLen")
diff --git a/vendor/github.com/moby/go-archive/.golangci.yml b/vendor/github.com/moby/go-archive/.golangci.yml
index 21439e5c..761e36d9 100644
--- a/vendor/github.com/moby/go-archive/.golangci.yml
+++ b/vendor/github.com/moby/go-archive/.golangci.yml
@@ -9,6 +9,7 @@ issues:
linters:
enable:
- errorlint
+ - gosec
- unconvert
- unparam
exclusions:
@@ -16,7 +17,18 @@ linters:
presets:
- comments
- std-error-handling
+ rules:
+ # Ignore "G204: Subprocess launched with a potential tainted input or cmd arguments"
+ - path: '(.+)_test\.go'
+ linters:
+ - gosec
+ text: 'G204: Subprocess launched'
settings:
+ gosec:
+ excludes:
+ - G301 # Expect directory permissions to be 0750 or less
+ - G304 # Potential file inclusion via variable
+ - G306 # Expect WriteFile permissions to be 0600 or less
staticcheck:
# Enable all options, with some exceptions.
# For defaults, see https://golangci-lint.run/usage/linters/#staticcheck
diff --git a/vendor/github.com/moby/go-archive/archive.go b/vendor/github.com/moby/go-archive/archive.go
index 8dce2e6e..689720af 100644
--- a/vendor/github.com/moby/go-archive/archive.go
+++ b/vendor/github.com/moby/go-archive/archive.go
@@ -8,13 +8,16 @@ import (
"fmt"
"io"
"os"
+ "path"
"path/filepath"
"runtime"
"strings"
+ "sync"
"syscall"
"time"
"github.com/containerd/log"
+ "github.com/moby/go-archive/internal/archiveoptions"
"github.com/moby/patternmatcher"
"github.com/moby/sys/sequential"
"github.com/moby/sys/user"
@@ -46,9 +49,18 @@ type (
// TarOptions wraps the tar options.
TarOptions struct {
- IncludeFiles []string
- ExcludePatterns []string
- Compression compression.Compression
+ // IncludeFiles lists archive-relative paths to include.
+ // Paths use POSIX ('/') separators.
+ IncludeFiles []string
+
+ // ExcludePatterns lists archive-relative exclude patterns.
+ // Patterns use POSIX ('/') separators, matching patternmatcher semantics.
+ ExcludePatterns []string
+ Compression compression.Compression
+ // NoLchown disables applying ownership from the archive to extracted files
+ // and directories. Despite its historical name, it applies to all ownership
+ // changes, leaving extracted filesystem objects owned by the user performing
+ // the extraction.
NoLchown bool
IDMap user.IdentityMapping
ChownOpts *ChownOpts
@@ -70,9 +82,22 @@ type (
// were probably in the archive for a reason, so set this option at
// your own peril.
BestEffortXattrs bool
+
+ // internalOptions contains options for use by packages within this module.
+ internalOptions *archiveoptions.Options
}
)
+// WithProcSelfFD returns a copy of opts prepared for extraction in a
+// filesystem context where /proc/self/fd may not be accessible by path.
+//
+// The caller must invoke the returned cleanup function after extraction
+// completes. On platforms that do not use /proc/self/fd for extraction,
+// the returned cleanup function is a no-op.
+func WithProcSelfFD(opts *TarOptions) (*TarOptions, func(), error) {
+ return withProcSelfFD(opts)
+}
+
// Archiver implements the Archiver interface and allows the reuse of most utility functions of
// this package with a pluggable Untar function. Also, to facilitate the passing of specific id
// mappings for untar, an Archiver can be created with maps which will then be passed to Untar operations.
@@ -86,10 +111,33 @@ func NewDefaultArchiver() *Archiver {
return &Archiver{Untar: Untar}
}
-// breakoutError is used to differentiate errors related to breaking out
-// When testing archive breakout in the unit tests, this error is expected
-// in order for the test to pass.
-type breakoutError error
+// isPathEscapes reports whether err is os.Root's path-containment error.
+//
+// os.Root currently returns an unexported errPathEscapes sentinel, so callers
+// cannot detect it with errors.Is. Keep the string comparison isolated here
+// until Go exports the error; see https://go.dev/issue/74640.
+func isPathEscapes(err error) bool {
+ // https://github.com/golang/go/blob/go1.26.5/src/os/file.go#L421
+ const errPathEscapes = "path escapes from parent"
+ for err != nil {
+ if errors.Unwrap(err) == nil {
+ return err.Error() == errPathEscapes
+ }
+ err = errors.Unwrap(err)
+ }
+ return false
+}
+
+// breakoutErr marks errors caused by archive breakout attempts.
+// Unit tests use it to distinguish expected breakout failures from other
+// errors.
+type breakoutErr struct{ error }
+
+func breakoutError(err error) error {
+ return &breakoutErr{error: err}
+}
+
+func (e *breakoutErr) Unwrap() error { return e.error }
const (
AUFSWhiteoutFormat WhiteoutFormat = 0 // AUFSWhiteoutFormat is the default format for whiteouts
@@ -98,17 +146,17 @@ const (
// IsArchivePath checks if the (possibly compressed) file at the given path
// starts with a tar file header.
-func IsArchivePath(path string) bool {
- file, err := os.Open(path)
+func IsArchivePath(filePath string) bool {
+ file, err := os.Open(filePath)
if err != nil {
return false
}
- defer file.Close()
+ defer func() { _ = file.Close() }()
rdr, err := compression.DecompressStream(file)
if err != nil {
return false
}
- defer rdr.Close()
+ defer func() { _ = rdr.Close() }()
r := tar.NewReader(rdr)
_, err = r.Next()
return err == nil
@@ -129,8 +177,10 @@ func ReplaceFileTarWrapper(inputTarStream io.ReadCloser, mods map[string]TarModi
go func() {
tarReader := tar.NewReader(inputTarStream)
tarWriter := tar.NewWriter(pipeWriter)
- defer inputTarStream.Close()
- defer tarWriter.Close()
+ defer func() {
+ _ = tarWriter.Close()
+ _ = inputTarStream.Close()
+ }()
modify := func(name string, original *tar.Header, modifier TarModifierFunc, tarReader io.Reader) error {
header, data, err := modifier(name, original, tarReader)
@@ -164,7 +214,7 @@ func ReplaceFileTarWrapper(inputTarStream io.ReadCloser, mods map[string]TarModi
break
}
if err != nil {
- pipeWriter.CloseWithError(err)
+ _ = pipeWriter.CloseWithError(err)
return
}
@@ -172,11 +222,11 @@ func ReplaceFileTarWrapper(inputTarStream io.ReadCloser, mods map[string]TarModi
if !ok {
// No modifiers for this file, copy the header and data
if err := tarWriter.WriteHeader(originalHeader); err != nil {
- pipeWriter.CloseWithError(err)
+ _ = pipeWriter.CloseWithError(err)
return
}
if err := copyWithBuffer(tarWriter, tarReader); err != nil {
- pipeWriter.CloseWithError(err)
+ _ = pipeWriter.CloseWithError(err)
return
}
continue
@@ -184,7 +234,7 @@ func ReplaceFileTarWrapper(inputTarStream io.ReadCloser, mods map[string]TarModi
delete(mods, originalHeader.Name)
if err := modify(originalHeader.Name, originalHeader, modifier, tarReader); err != nil {
- pipeWriter.CloseWithError(err)
+ _ = pipeWriter.CloseWithError(err)
return
}
}
@@ -192,12 +242,12 @@ func ReplaceFileTarWrapper(inputTarStream io.ReadCloser, mods map[string]TarModi
// Apply the modifiers that haven't matched any files in the archive
for name, modifier := range mods {
if err := modify(name, nil, modifier, nil); err != nil {
- pipeWriter.CloseWithError(err)
+ _ = pipeWriter.CloseWithError(err)
return
}
}
- pipeWriter.Close()
+ _ = pipeWriter.Close()
}()
return pipeReader
}
@@ -218,7 +268,7 @@ func FileInfoHeader(name string, fi os.FileInfo, link string) (*tar.Header, erro
hdr.ModTime = hdr.ModTime.Truncate(time.Second)
hdr.AccessTime = time.Time{}
hdr.ChangeTime = time.Time{}
- hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
+ hdr.Mode = chmodTarEntry(hdr.Mode)
hdr.Name = canonicalTarName(name, fi.IsDir())
return hdr, nil
}
@@ -227,7 +277,7 @@ const paxSchilyXattr = "SCHILY.xattr."
// ReadSecurityXattrToTarHeader reads security.capability xattr from filesystem
// to a tar header
-func ReadSecurityXattrToTarHeader(path string, hdr *tar.Header) error {
+func ReadSecurityXattrToTarHeader(filePath string, hdr *tar.Header) error {
const (
// Values based on linux/include/uapi/linux/capability.h
xattrCapsSz2 = 20
@@ -235,7 +285,7 @@ func ReadSecurityXattrToTarHeader(path string, hdr *tar.Header) error {
vfsCapRevision2 = 2
vfsCapRevision3 = 3
)
- capability, _ := lgetxattr(path, "security.capability")
+ capability, _ := lgetxattr(filePath, "security.capability")
if capability != nil {
if capability[versionOffset] == vfsCapRevision3 {
// Convert VFS_CAP_REVISION_3 to VFS_CAP_REVISION_2 as root UID makes no
@@ -253,7 +303,7 @@ func ReadSecurityXattrToTarHeader(path string, hdr *tar.Header) error {
type tarWhiteoutConverter interface {
ConvertWrite(*tar.Header, string, os.FileInfo) (*tar.Header, error)
- ConvertRead(*tar.Header, string) (bool, error)
+ ConvertRead(*os.Root, *tar.Header, string) (bool, error)
}
type tarAppender struct {
@@ -292,9 +342,10 @@ func canonicalTarName(name string, isDir bool) string {
return name
}
-// addTarFile adds to the tar archive a file from `path` as `name`
-func (ta *tarAppender) addTarFile(path, name string) error {
- fi, err := os.Lstat(path)
+// addTarFile adds to the tar archive a file from `srcPath` as `name`
+func (ta *tarAppender) addTarFile(srcPath, archivePath string) error {
+ archivePath = filepath.ToSlash(archivePath)
+ fi, err := os.Lstat(srcPath)
if err != nil {
return err
}
@@ -302,17 +353,17 @@ func (ta *tarAppender) addTarFile(path, name string) error {
var link string
if fi.Mode()&os.ModeSymlink != 0 {
var err error
- link, err = os.Readlink(path)
+ link, err = os.Readlink(srcPath)
if err != nil {
return err
}
}
- hdr, err := FileInfoHeader(name, fi, link)
+ hdr, err := FileInfoHeader(archivePath, fi, link)
if err != nil {
return err
}
- if err := ReadSecurityXattrToTarHeader(path, hdr); err != nil {
+ if err := ReadSecurityXattrToTarHeader(srcPath, hdr); err != nil {
return err
}
@@ -321,7 +372,7 @@ func (ta *tarAppender) addTarFile(path, name string) error {
if !fi.IsDir() && hasHardlinks(fi) {
inode, err := getInodeFromStat(fi.Sys())
if err != nil {
- return err
+ return fmt.Errorf("unexpected file info for %q: %w", srcPath, err)
}
// a link should have a name that it links too
// and that linked name should be first in the tar archive
@@ -330,7 +381,7 @@ func (ta *tarAppender) addTarFile(path, name string) error {
hdr.Linkname = oldpath
hdr.Size = 0 // This Must be here for the writer math to add up!
} else {
- ta.SeenFiles[inode] = name
+ ta.SeenFiles[inode] = hdr.Name
}
}
@@ -341,7 +392,7 @@ func (ta *tarAppender) addTarFile(path, name string) error {
// handle re-mapping container ID mappings back to host ID mappings before
// writing tar headers/files. We skip whiteout files because they were written
// by the kernel and already have proper ownership relative to the host
- if !isOverlayWhiteout && !strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) && !ta.IdentityMapping.Empty() {
+ if !isOverlayWhiteout && !strings.HasPrefix(path.Base(hdr.Name), WhiteoutPrefix) && !ta.IdentityMapping.Empty() {
uid, gid, err := getFileUIDGID(fi.Sys())
if err != nil {
return err
@@ -359,7 +410,7 @@ func (ta *tarAppender) addTarFile(path, name string) error {
}
if ta.WhiteoutConverter != nil {
- wo, err := ta.WhiteoutConverter.ConvertWrite(hdr, path, fi)
+ wo, err := ta.WhiteoutConverter.ConvertWrite(hdr, srcPath, fi)
if err != nil {
return err
}
@@ -370,12 +421,12 @@ func (ta *tarAppender) addTarFile(path, name string) error {
// hdr may have been updated to be a whiteout with returning
// a whiteout header
if wo != nil {
+ if hdr.Typeflag == tar.TypeReg && hdr.Size > 0 {
+ return fmt.Errorf("tar: cannot use whiteout for non-empty file %q", hdr.Name)
+ }
if err := ta.TarWriter.WriteHeader(hdr); err != nil {
return err
}
- if hdr.Typeflag == tar.TypeReg && hdr.Size > 0 {
- return fmt.Errorf("tar: cannot use whiteout for non-empty file")
- }
hdr = wo
}
}
@@ -387,13 +438,13 @@ func (ta *tarAppender) addTarFile(path, name string) error {
if hdr.Typeflag == tar.TypeReg && hdr.Size > 0 {
// We use sequential file access to avoid depleting the standby list on
// Windows. On Linux, this equates to a regular os.Open.
- file, err := sequential.Open(path)
+ file, err := sequential.Open(srcPath)
if err != nil {
return err
}
err = copyWithBuffer(ta.TarWriter, file)
- file.Close()
+ _ = file.Close()
if err != nil {
return err
}
@@ -402,11 +453,99 @@ func (ta *tarAppender) addTarFile(path, name string) error {
return nil
}
-func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, opts *TarOptions) error {
+// resolveArchivePath resolves intermediate symlinks in name using chroot-like
+// semantics when os.Root cannot traverse them. The final path component is
+// intentionally preserved because archive extraction may create or replace it.
+//
+// This is a compatibility workaround rather than the preferred long-term
+// implementation. It resolves the path separately before the actual operation,
+// so a concurrent filesystem change may cause the operation to affect a
+// different path within root. The subsequent os.Root operation still confines
+// the operation to root and prevents such a change from escaping it.
+//
+// Paths with missing components are supported. Existing symlinks are resolved,
+// and any remaining nonexistent components are retained for later creation.
+//
+// This helper should eventually be replaced by handle-relative resolution and
+// operations with resolve-in-root semantics, avoiding the resolution/use race
+// and repeated path traversal.
+func resolveArchivePath(root *os.Root, name string) (string, error) {
+ parent, base := filepath.Split(name)
+ if parent == "" {
+ return name, nil
+ }
+
+ parent = filepath.Clean(parent)
+
+ // Follow the final parent component: it is an intermediate component of name,
+ // and an absolute symlink there must trigger the resolve-in-root fallback.
+ _, statErr := root.Stat(parent)
+ switch {
+ case statErr == nil:
+ return name, nil
+ case !os.IsNotExist(statErr) && !isPathEscapes(statErr):
+ return "", statErr
+ }
+
+ // Resolve the parent both to handle ENOENT from missing components or dangling
+ // symlinks, and to determine whether an os.Root breakout was caused by an
+ // absolute symlink. Relative symlink escapes preserve the original Stat error.
+ resolved, err := resolveFSRootPath(root.Name(), parent)
+ if err != nil {
+ return "", err
+ }
+
+ if isPathEscapes(statErr) && (!resolved.followedAbsoluteLink || resolved.relativeEscapeBeforeAbsolute) {
+ return "", statErr
+ }
+
+ relParent, err := filepath.Rel(root.Name(), resolved.path)
+ if err != nil {
+ return "", breakoutError(fmt.Errorf(
+ "could not make resolved parent %q relative to root %q: %w",
+ resolved.path,
+ root.Name(),
+ err,
+ ))
+ }
+ if relParent != "." && !filepath.IsLocal(relParent) {
+ return "", breakoutError(fmt.Errorf(
+ "resolved parent %q escapes root %q",
+ resolved.path,
+ root.Name(),
+ ))
+ }
+
+ return filepath.Join(relParent, base), nil
+}
+
+// resolveHardlinkTarget validates a POSIX hardlink target and resolves it to
+// the native, root-relative filesystem path used for extraction.
+func resolveHardlinkTarget(root *os.Root, linkname string) (string, error) {
+ cleaned := path.Clean(linkname)
+ if strings.HasPrefix(cleaned, "/") {
+ // Some image builders (e.g. kaniko) write hardlink targets as absolute
+ // paths. Resolve those relative to the extraction root, with chroot-like
+ // semantics matching absolute symlink targets. Strip the root from the
+ // original linkname rather than the cleaned one so that ".." components
+ // are not collapsed against "/" but instead rejected below.
+ cleaned = path.Clean(strings.TrimLeft(linkname, "/"))
+ }
+ if cleaned == "." || !filepath.IsLocal(cleaned) {
+ return "", breakoutError(fmt.Errorf("invalid hardlink target %q", linkname))
+ }
+ return resolveArchivePath(root, filepath.FromSlash(cleaned))
+}
+
+// createTarFile extracts a single tar entry into the given root. dstPath is the
+// root-relative path of the entry being extracted, in native (host-separator)
+// form so it can be passed directly to os.Root methods and fsRootPath.
+func createTarFile(root *os.Root, dstPath string, hdr *tar.Header, reader io.Reader, opts *TarOptions) error {
var (
Lchown = true
inUserns, bestEffortXattrs bool
chownOpts *ChownOpts
+ internalOpts *archiveoptions.Options
)
// TODO(thaJeztah): make opts a required argument.
@@ -415,6 +554,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, o
inUserns = opts.InUserNS // TODO(thaJeztah): consider deprecating opts.InUserNS and detect locally.
chownOpts = opts.ChownOpts
bestEffortXattrs = opts.BestEffortXattrs
+ internalOpts = opts.internalOptions
}
// hdr.Mode is in linux format, which we can use for sycalls,
@@ -422,20 +562,35 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, o
// so use hdrInfo.Mode() (they differ for e.g. setuid bits)
hdrInfo := hdr.FileInfo()
+ var hardlinkTarget string
+ if hdr.Typeflag == tar.TypeLink {
+ var err error
+ hardlinkTarget, err = resolveHardlinkTarget(root, hdr.Linkname)
+ if err != nil {
+ return err
+ }
+ }
+
switch hdr.Typeflag {
case tar.TypeDir:
- // Create directory unless it exists as a directory already.
- // In that case we just want to merge the two
- if fi, err := os.Lstat(path); err != nil || !fi.IsDir() {
- if err := os.Mkdir(path, hdrInfo.Mode()); err != nil {
+ // Create directory unless it already exists as one; merge in that case.
+ // os.Root.Mkdir only accepts the nine least-significant permission
+ // bits; special bits (setuid, setgid, sticky) are applied afterward
+ // by handleLChmod via root.Chmod.
+ if fi, err := root.Lstat(dstPath); err != nil || !fi.IsDir() {
+ if err := root.Mkdir(dstPath, hdrInfo.Mode()&0o777); err != nil {
return err
}
}
case tar.TypeReg:
- // Source is regular file. We use sequential file access to avoid depleting
- // the standby list on Windows. On Linux, this equates to a regular os.OpenFile.
- file, err := sequential.OpenFile(path, os.O_CREATE|os.O_WRONLY, hdrInfo.Mode())
+ // Source is a regular file. Use os.Root.OpenFile so that all
+ // path resolution is bounded within root using openat(2) semantics.
+ // os.Root.OpenFile only accepts the nine least-significant permission
+ // bits; special bits are applied afterward by handleLChmod.
+ // We use sequential file access to avoid depleting the standby list
+ // on Windows (go1.26). On Linux, this equates to a regular os.OpenFile.
+ file, err := root.OpenFile(dstPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC|windows_O_FILE_FLAG_SEQUENTIAL_SCAN, hdrInfo.Mode()&0o777)
if err != nil {
return err
}
@@ -447,47 +602,41 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, o
case tar.TypeBlock, tar.TypeChar:
if inUserns { // cannot create devices in a userns
- log.G(context.TODO()).WithFields(log.Fields{"path": path, "type": hdr.Typeflag}).Debug("skipping device nodes in a userns")
+ log.G(context.TODO()).WithFields(log.Fields{"path": dstPath, "type": hdr.Typeflag}).Debug("skipping device nodes in a userns")
return nil
}
- // Handle this is an OS-specific way
- if err := handleTarTypeBlockCharFifo(hdr, path); err != nil {
+ if err := handleTarTypeBlockCharFifo(root, hdr, dstPath); err != nil {
return err
}
case tar.TypeFifo:
- // Handle this is an OS-specific way
- if err := handleTarTypeBlockCharFifo(hdr, path); err != nil {
+ if err := handleTarTypeBlockCharFifo(root, hdr, dstPath); err != nil {
if inUserns && errors.Is(err, syscall.EPERM) {
// In most cases, cannot create a fifo if running in user namespace
- log.G(context.TODO()).WithFields(log.Fields{"error": err, "path": path, "type": hdr.Typeflag}).Debug("creating fifo node in a userns")
+ log.G(context.TODO()).WithFields(log.Fields{"error": err, "path": dstPath, "type": hdr.Typeflag}).Debug("creating fifo node in a userns")
return nil
}
return err
}
case tar.TypeLink:
- // #nosec G305 -- The target path is checked for path traversal.
- targetPath := filepath.Join(extractDir, hdr.Linkname)
- // check for hardlink breakout
- if !strings.HasPrefix(targetPath, extractDir) {
- return breakoutError(fmt.Errorf("invalid hardlink %q -> %q", targetPath, hdr.Linkname))
- }
- if err := os.Link(targetPath, path); err != nil {
+ if err := root.Link(hardlinkTarget, dstPath); err != nil {
return err
}
case tar.TypeSymlink:
- // path -> hdr.Linkname = targetPath
- // e.g. /extractDir/path/to/symlink -> ../2/file = /extractDir/path/2/file
- targetPath := filepath.Join(filepath.Dir(path), hdr.Linkname) // #nosec G305 -- The target path is checked for path traversal.
-
- // the reason we don't need to check symlinks in the path (with FollowSymlinkInScope) is because
- // that symlink would first have to be created, which would be caught earlier, at this very check:
- if !strings.HasPrefix(targetPath, extractDir) {
- return breakoutError(fmt.Errorf("invalid symlink %q -> %q", path, hdr.Linkname))
- }
- if err := os.Symlink(hdr.Linkname, path); err != nil {
+ // Symlink targets are archive data, not filesystem paths. Preserve the
+ // target verbatim rather than cleaning or converting it (filepath.FromSlash).
+ linkTarget := hdr.Linkname
+
+ // os.Root.Symlink contains the symlink's location (newname) within
+ // root but stores the target (oldname) verbatim, so absolute targets
+ // such as /usr/lib -- common and legitimate in container images -- are
+ // preserved rather than rejected. The symlink node is therefore always
+ // created within root via openat(2) semantics, without resolving to an
+ // absolute path; containment applies when the symlink is followed, not
+ // at creation.
+ if err := root.Symlink(linkTarget, dstPath); err != nil {
return err
}
@@ -504,22 +653,31 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, o
if chownOpts == nil {
chownOpts = &ChownOpts{UID: hdr.Uid, GID: hdr.Gid}
}
- if err := os.Lchown(path, chownOpts.UID, chownOpts.GID); err != nil {
+ if err := root.Lchown(dstPath, chownOpts.UID, chownOpts.GID); err != nil {
var msg string
if inUserns && errors.Is(err, syscall.EINVAL) {
msg = " (try increasing the number of subordinate IDs in /etc/subuid and /etc/subgid)"
}
- return fmt.Errorf("failed to Lchown %q for UID %d, GID %d%s: %w", path, hdr.Uid, hdr.Gid, msg, err)
+ return fmt.Errorf("failed to Lchown %q for UID %d, GID %d%s: %w", dstPath, hdr.Uid, hdr.Gid, msg, err)
}
}
var xattrErrs []string
+ absPath := sync.OnceValues(func() (string, error) {
+ return fsRootPath(root.Name(), dstPath)
+ })
for key, value := range hdr.PAXRecords {
xattr, ok := strings.CutPrefix(key, paxSchilyXattr)
if !ok {
continue
}
- if err := lsetxattr(path, xattr, []byte(value), 0); err != nil {
+ // os.Root has no xattr support; use the absolute path derived from
+ // the root so the path remains bounded.
+ ap, err := absPath()
+ if err != nil {
+ return err
+ }
+ if err := lsetxattr(ap, xattr, []byte(value), 0); err != nil {
if bestEffortXattrs && errors.Is(err, syscall.ENOTSUP) || errors.Is(err, syscall.EPERM) {
// EPERM occurs if modifying xattrs is not allowed. This can
// happen when running in userns with restrictions (ChromeOS).
@@ -538,39 +696,43 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, o
// There is no LChmod, so ignore mode for symlink. Also, this
// must happen after chown, as that can modify the file mode
- if err := handleLChmod(hdr, path, hdrInfo); err != nil {
+ if err := handleLChmod(root, dstPath, hardlinkTarget, hdr, hdrInfo, internalOpts); err != nil {
return err
}
aTime := boundTime(latestTime(hdr.AccessTime, hdr.ModTime))
mTime := boundTime(hdr.ModTime)
- // chtimes doesn't support a NOFOLLOW flag atm
- if hdr.Typeflag == tar.TypeLink {
- if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
- if err := chtimes(path, aTime, mTime); err != nil {
+ switch hdr.Typeflag {
+ case tar.TypeSymlink:
+ // Apply timestamps to the symlink itself (AT_SYMLINK_NOFOLLOW).
+ if err := lchtimes(root, dstPath, aTime, mTime); err != nil {
+ return err
+ }
+ case tar.TypeLink:
+ // Follow the hardlink only when its target is not itself a symlink.
+ fi, err := root.Lstat(hardlinkTarget)
+ if err == nil && fi.Mode()&os.ModeSymlink == 0 {
+ if err := chtimes(root, dstPath, aTime, mTime); err != nil {
return err
}
}
- } else if hdr.Typeflag != tar.TypeSymlink {
- if err := chtimes(path, aTime, mTime); err != nil {
- return err
- }
- } else {
- if err := lchtimes(path, aTime, mTime); err != nil {
+ default:
+ // All other file types follow symlinks.
+ if err := chtimes(root, dstPath, aTime, mTime); err != nil {
return err
}
}
return nil
}
-// Tar creates an archive from the directory at `path`, and returns it as a
+// Tar creates an archive from the directory at `srcPath`, and returns it as a
// stream of bytes.
-func Tar(path string, comp compression.Compression) (io.ReadCloser, error) {
- return TarWithOptions(path, &TarOptions{Compression: comp})
+func Tar(srcPath string, comp compression.Compression) (io.ReadCloser, error) {
+ return TarWithOptions(srcPath, &TarOptions{Compression: comp})
}
-// TarWithOptions creates an archive from the directory at `path`, only including files whose relative
+// TarWithOptions creates an archive from the directory at `srcPath`, only including files whose relative
// paths are included in `options.IncludeFiles` (if non-nil) or not in `options.ExcludePatterns`.
func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error) {
tb, err := NewTarballer(srcPath, options)
@@ -639,13 +801,13 @@ func (t *Tarballer) Do() {
defer func() {
// Make sure to check the error on Close.
- if err := ta.TarWriter.Close(); err != nil {
+ if err := ta.TarWriter.Close(); err != nil && !errors.Is(err, io.ErrClosedPipe) {
log.G(context.TODO()).Errorf("Can't close tar writer: %s", err)
}
- if err := t.compressWriter.Close(); err != nil {
+ if err := t.compressWriter.Close(); err != nil && !errors.Is(err, io.ErrClosedPipe) {
log.G(context.TODO()).Errorf("Can't close compress writer: %s", err)
}
- if err := t.pipeWriter.Close(); err != nil {
+ if err := t.pipeWriter.Close(); err != nil && !errors.Is(err, io.ErrClosedPipe) {
log.G(context.TODO()).Errorf("Can't close pipe writer: %s", err)
}
}()
@@ -803,11 +965,28 @@ func (t *Tarballer) Do() {
}
}
+// unpackedDir records a directory whose mtime must be restored after all
+// entries are extracted, along with the root-relative entry name used during
+// extraction.
+type unpackedDir struct {
+ hdr *tar.Header
+ name string // root-relative entry name
+}
+
// Unpack unpacks the decompressedArchive to dest with options.
func Unpack(decompressedArchive io.Reader, dest string, options *TarOptions) error {
+ if options == nil {
+ options = &TarOptions{}
+ }
+ root, err := os.OpenRoot(dest)
+ if err != nil {
+ return err
+ }
+ defer func() { _ = root.Close() }()
+
tr := tar.NewReader(decompressedArchive)
- var dirs []*tar.Header
+ var dirs []unpackedDir
whiteoutConverter := getWhiteoutConverter(options.WhiteoutFormat)
// Iterate through the files in the archive.
@@ -828,48 +1007,53 @@ loop:
continue
}
- // Normalize name, for safety and for a simple is-root check
- // This keeps "../" as-is, but normalizes "/../" to "/". Or Windows:
- // This keeps "..\" as-is, but normalizes "\..\" to "\".
- hdr.Name = filepath.Clean(hdr.Name)
-
+ // Strip a leading "/" so absolute entries stay root-relative, and
+ // normalize the POSIX tar path. Skip entries referring to the extraction
+ // root and reject paths that escape it.
+ name := path.Clean(strings.TrimLeft(hdr.Name, "/"))
+ if name == "." {
+ continue
+ }
+ if !filepath.IsLocal(name) {
+ return breakoutError(fmt.Errorf("invalid entry name %q", hdr.Name))
+ }
for _, exclude := range options.ExcludePatterns {
- if strings.HasPrefix(hdr.Name, exclude) {
+ if strings.HasPrefix(name, exclude) {
continue loop
}
}
- // Ensure that the parent directory exists.
- err = createImpliedDirectories(dest, hdr, options)
- if err != nil {
- return err
+ hdr.Name = name
+
+ // Skip entries whose name (or hardlink target) Windows cannot represent.
+ if err := unrepresentableOnWindows(hdr); err != nil {
+ log.G(context.TODO()).Warnf("Windows: ignoring entry: %v", err)
+ continue loop
}
- // #nosec G305 -- The joined path is checked for path traversal.
- path := filepath.Join(dest, hdr.Name)
- rel, err := filepath.Rel(dest, path)
+ // dstPath is the native (host-separator) form of the entry name,
+ // used at all filesystem boundaries (os.Root methods, fsRootPath).
+ // hdr.Name stays POSIX (forward-slash) for logical string checks.
+ dstPath, err := resolveArchivePath(root, filepath.FromSlash(hdr.Name))
if err != nil {
return err
}
- if strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
- return breakoutError(fmt.Errorf("%q is outside of %q", hdr.Name, dest))
- }
- // If path exits we almost always just want to remove and replace it
+ // If dstPath exists we almost always just want to remove and replace it.
// The only exception is when it is a directory *and* the file from
// the layer is also a directory. Then we want to merge them (i.e.
// just apply the metadata from the layer).
- if fi, err := os.Lstat(path); err == nil {
+ if fi, err := root.Lstat(dstPath); err == nil {
if options.NoOverwriteDirNonDir && fi.IsDir() && hdr.Typeflag != tar.TypeDir {
// If NoOverwriteDirNonDir is true then we cannot replace
// an existing directory with a non-directory from the archive.
- return fmt.Errorf("cannot overwrite directory %q with non-directory %q", path, dest)
+ return fmt.Errorf("cannot overwrite directory %q with non-directory %q", hdr.Name, dest)
}
if options.NoOverwriteDirNonDir && !fi.IsDir() && hdr.Typeflag == tar.TypeDir {
// If NoOverwriteDirNonDir is true then we cannot replace
// an existing non-directory with a directory from the archive.
- return fmt.Errorf("cannot overwrite non-directory %q with directory %q", path, dest)
+ return fmt.Errorf("cannot overwrite non-directory %q with directory %q", hdr.Name, dest)
}
if fi.IsDir() && hdr.Name == "." {
@@ -877,7 +1061,7 @@ loop:
}
if !fi.IsDir() || hdr.Typeflag != tar.TypeDir {
- if err := os.RemoveAll(path); err != nil {
+ if err := root.RemoveAll(dstPath); err != nil {
return err
}
}
@@ -887,8 +1071,16 @@ loop:
return err
}
+ // Ensure that the parent directory exists.
+ //
+ // This must be done before whiteoutConverter.ConvertRead, which
+ // may set xattrs on the directory or create whiteout files.
+ if err := createImpliedDirectories(root, dstPath, options); err != nil {
+ return err
+ }
+
if whiteoutConverter != nil {
- writeFile, err := whiteoutConverter.ConvertRead(hdr, path)
+ writeFile, err := whiteoutConverter.ConvertRead(root, hdr, dstPath)
if err != nil {
return err
}
@@ -897,51 +1089,121 @@ loop:
}
}
- if err := createTarFile(path, dest, hdr, tr, options); err != nil {
+ if err := createTarFile(root, dstPath, hdr, tr, options); err != nil {
return err
}
// Directory mtimes must be handled at the end to avoid further
// file creation in them to modify the directory mtime
if hdr.Typeflag == tar.TypeDir {
- dirs = append(dirs, hdr)
+ dirs = append(dirs, unpackedDir{hdr: hdr, name: dstPath})
}
}
- for _, hdr := range dirs {
- // #nosec G305 -- The header was checked for path traversal before it was appended to the dirs slice.
- path := filepath.Join(dest, hdr.Name)
-
- if err := chtimes(path, boundTime(latestTime(hdr.AccessTime, hdr.ModTime)), boundTime(hdr.ModTime)); err != nil {
+ for _, d := range dirs {
+ aTime := boundTime(latestTime(d.hdr.AccessTime, d.hdr.ModTime))
+ if err := chtimes(root, d.name, aTime, boundTime(d.hdr.ModTime)); err != nil {
return err
}
}
return nil
}
-// createImpliedDirectories will create all parent directories of the current path with default permissions, if they do
-// not already exist. This is possible as the tar format supports 'implicit' directories, where their existence is
-// defined by the paths of files in the tar, but there are no header entries for the directories themselves, and thus
-// we most both create them and choose metadata like permissions.
+// unrepresentableOnWindows returns an error describing why a tar entry cannot
+// be faithfully created on Windows, or nil if it can (always on non-Windows).
+// On Windows ":" is illegal in a filename and "\" is a path separator, so a tar
+// name or hardlink target containing them (they use POSIX semantics) would be
+// misinterpreted by os.Root (e.g. "a\b" resolved as two components). Symlink
+// targets are stored verbatim (not resolved at creation), so they are exempt.
+func unrepresentableOnWindows(hdr *tar.Header) error {
+ if runtime.GOOS != "windows" {
+ return nil
+ }
+ if strings.ContainsAny(hdr.Name, `:\`) {
+ return fmt.Errorf("entry name %q contains a character Windows cannot represent in a path", hdr.Name)
+ }
+ // A hardlink target is resolved within the root by os.Root.Link; a symlink
+ // target is stored verbatim, so only hardlinks need the target checked.
+ if hdr.Typeflag == tar.TypeLink && strings.ContainsAny(hdr.Linkname, `:\`) {
+ return fmt.Errorf("hardlink target %q contains a character Windows cannot represent in a path", hdr.Linkname)
+ }
+ return nil
+}
+
+// createImpliedDirectories creates all parent directories of dstPath with
+// default permissions if they do not already exist. This is necessary because
+// the tar format permits implicit directories whose existence is defined only
+// by file paths, without corresponding directory headers from which metadata
+// could be restored.
//
-// The caller should have performed filepath.Clean(hdr.Name), so hdr.Name will now be in the filepath format for the OS
-// on which the daemon is running. This precondition is required because this function assumes a OS-specific path
-// separator when checking that a path is not the root.
-func createImpliedDirectories(dest string, hdr *tar.Header, options *TarOptions) error {
- // Not the root directory, ensure that the parent directory exists
- if !strings.HasSuffix(hdr.Name, string(os.PathSeparator)) {
- parent := filepath.Dir(hdr.Name)
- parentPath := filepath.Join(dest, parent)
- if _, err := os.Lstat(parentPath); err != nil && os.IsNotExist(err) {
- // RootPair() is confined inside this loop as most cases will not require a call, so we can spend some
- // unneeded function calls in the uncommon case to encapsulate logic -- implied directories are a niche
- // usage that reduces the portability of an image.
- uid, gid := options.IDMap.RootPair()
-
- err = user.MkdirAllAndChown(parentPath, ImpliedDirectoryMode, uid, gid, user.WithOnlyNew)
+// The caller must pass a normalized, root-relative local path. Any archive-path
+// conversion and resolve-in-root handling must already have been applied.
+// Directory creation is performed through root, so it remains confined to the
+// extraction destination even if the destination tree changes concurrently.
+func createImpliedDirectories(root *os.Root, dstPath string, options *TarOptions) error {
+ parent := filepath.Dir(dstPath)
+
+ // Skip when the parent is the root itself; nothing to create.
+ if parent == "." || parent == "" {
+ return nil
+ }
+ if _, err := root.Lstat(parent); err == nil {
+ return nil
+ } else if !os.IsNotExist(err) {
+ return err
+ }
+ // RootPair() is confined inside this loop as most cases will not require a call, so we can spend some
+ // unneeded function calls in the uncommon case to encapsulate logic -- implied directories are a niche
+ // usage that reduces the portability of an image.
+ uid, gid := options.IDMap.RootPair()
+
+ // Similar to [user.MkdirAllAndChown]
+ //
+ // [user.MkdirAllAndChown]: https://pkg.go.dev/github.com/moby/sys/user#MkdirAllAndChown
+ var cur string
+ for c := range strings.SplitSeq(parent, string(os.PathSeparator)) {
+ if c == "" {
+ continue
+ }
+ cur = filepath.Join(cur, c)
+ if err := root.Mkdir(cur, ImpliedDirectoryMode); err != nil {
+ if !errors.Is(err, os.ErrExist) {
+ return err
+ }
+
+ fi, err := root.Stat(cur)
if err != nil {
return err
}
+ if fi.IsDir() {
+ continue
+ }
+ return &os.PathError{Op: "mkdir", Path: cur, Err: syscall.ENOTDIR}
+ }
+ if options.NoLchown {
+ continue
+ }
+ // Only the successful Mkdir case is newly-created.
+ dir, err := root.Open(cur)
+ if err != nil {
+ return err
+ }
+ if uid != 0 || gid != 0 {
+ if err := dir.Chown(uid, gid); err != nil {
+ _ = dir.Close()
+ return err
+ }
+ }
+ // root.Mkdir applies the mode subject to the process umask, so
+ // re-apply it with Chmod to guarantee ImpliedDirectoryMode
+ // independent of umask, matching the previous MkdirAllAndChown
+ // behavior.
+ if err := dir.Chmod(ImpliedDirectoryMode); err != nil {
+ _ = dir.Close()
+ return err
+ }
+ if err := dir.Close(); err != nil {
+ return err
}
}
@@ -974,9 +1236,6 @@ func untarHandler(tarArchive io.Reader, dest string, options *TarOptions, decomp
if options == nil {
options = &TarOptions{}
}
- if options.ExcludePatterns == nil {
- options.ExcludePatterns = []string{}
- }
r := tarArchive
if decompress {
@@ -984,7 +1243,7 @@ func untarHandler(tarArchive io.Reader, dest string, options *TarOptions, decomp
if err != nil {
return err
}
- defer decompressedArchive.Close()
+ defer func() { _ = decompressedArchive.Close() }()
r = decompressedArchive
}
@@ -998,7 +1257,7 @@ func (archiver *Archiver) TarUntar(src, dst string) error {
if err != nil {
return err
}
- defer archive.Close()
+ defer func() { _ = archive.Close() }()
return archiver.Untar(archive, dst, &TarOptions{
IDMap: archiver.IDMapping,
})
@@ -1010,7 +1269,7 @@ func (archiver *Archiver) UntarPath(src, dst string) error {
if err != nil {
return err
}
- defer archive.Close()
+ defer func() { _ = archive.Close() }()
return archiver.Untar(archive, dst, &TarOptions{
IDMap: archiver.IDMapping,
})
@@ -1070,13 +1329,13 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
defer close(errC)
errC <- func() error {
- defer w.Close()
+ defer func() { _ = w.Close() }()
srcF, err := os.Open(src)
if err != nil {
return err
}
- defer srcF.Close()
+ defer func() { _ = srcF.Close() }()
hdr, err := tarheader.FileInfoHeaderNoLookups(srcSt, "")
if err != nil {
@@ -1087,14 +1346,14 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
hdr.AccessTime = time.Time{}
hdr.ChangeTime = time.Time{}
hdr.Name = filepath.Base(dst)
- hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
+ hdr.Mode = chmodTarEntry(hdr.Mode)
if err := remapIDs(archiver.IDMapping, hdr); err != nil {
return err
}
tw := tar.NewWriter(w)
- defer tw.Close()
+ defer func() { _ = tw.Close() }()
if err := tw.WriteHeader(hdr); err != nil {
return err
}
@@ -1112,7 +1371,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
err = archiver.Untar(r, filepath.Dir(dst), nil)
if err != nil {
- r.CloseWithError(err)
+ _ = r.CloseWithError(err)
}
return err
}
diff --git a/vendor/github.com/moby/go-archive/archive_linux.go b/vendor/github.com/moby/go-archive/archive_linux.go
index 7b6c3e02..c813cf9a 100644
--- a/vendor/github.com/moby/go-archive/archive_linux.go
+++ b/vendor/github.com/moby/go-archive/archive_linux.go
@@ -4,45 +4,71 @@ import (
"archive/tar"
"fmt"
"os"
+ "path"
"path/filepath"
"strings"
+ "github.com/moby/go-archive/internal/archiveoptions"
"github.com/moby/sys/userns"
"golang.org/x/sys/unix"
)
+func withProcSelfFD(opts *TarOptions) (*TarOptions, func(), error) {
+ procSelfFD, err := os.Open("/proc/self/fd")
+ if err != nil {
+ return nil, nil, err
+ }
+
+ var prepared TarOptions
+ if opts != nil {
+ prepared = *opts
+ }
+ prepared.internalOptions = &archiveoptions.Options{
+ ProcSelfFD: procSelfFD,
+ }
+
+ return &prepared, func() { _ = procSelfFD.Close() }, nil
+}
+
func getWhiteoutConverter(format WhiteoutFormat) tarWhiteoutConverter {
if format == OverlayWhiteoutFormat {
- return overlayWhiteoutConverter{}
+ return newOverlayWhiteoutConverter()
}
return nil
}
-type overlayWhiteoutConverter struct{}
+type overlayWhiteoutConverter struct {
+ opaqueXattr string
+}
+
+func newOverlayWhiteoutConverter() overlayWhiteoutConverter {
+ opaqueXattr := "trusted.overlay.opaque"
+ if userns.RunningInUserNS() {
+ opaqueXattr = "user.overlay.opaque"
+ }
+ return overlayWhiteoutConverter{
+ opaqueXattr: opaqueXattr,
+ }
+}
-func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os.FileInfo) (wo *tar.Header, _ error) {
+func (c overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, filePath string, fi os.FileInfo) (wo *tar.Header, _ error) {
// convert whiteouts to AUFS format
if fi.Mode()&os.ModeCharDevice != 0 && hdr.Devmajor == 0 && hdr.Devminor == 0 {
// we just rename the file and make it normal
- dir, filename := filepath.Split(hdr.Name)
- hdr.Name = filepath.Join(dir, WhiteoutPrefix+filename)
+ dir, filename := path.Split(hdr.Name)
+ hdr.Name = path.Join(dir, WhiteoutPrefix+filename)
hdr.Mode = 0o600
hdr.Typeflag = tar.TypeReg
hdr.Size = 0
}
- if fi.Mode()&os.ModeDir == 0 {
+ if !fi.IsDir() {
// FIXME(thaJeztah): return a sentinel error instead of nil, nil
return nil, nil
}
- opaqueXattrName := "trusted.overlay.opaque"
- if userns.RunningInUserNS() {
- opaqueXattrName = "user.overlay.opaque"
- }
-
// convert opaque dirs to AUFS format by writing an empty file with the prefix
- opaque, err := lgetxattr(path, opaqueXattrName)
+ opaque, err := lgetxattr(filePath, c.opaqueXattr)
if err != nil {
return nil, err
}
@@ -50,14 +76,14 @@ func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os
// FIXME(thaJeztah): return a sentinel error instead of nil, nil
return nil, nil
}
- delete(hdr.PAXRecords, paxSchilyXattr+opaqueXattrName)
+ delete(hdr.PAXRecords, paxSchilyXattr+c.opaqueXattr)
// create a header for the whiteout file
// it should inherit some properties from the parent, but be a regular file
return &tar.Header{
Typeflag: tar.TypeReg,
Mode: hdr.Mode & int64(os.ModePerm),
- Name: filepath.Join(hdr.Name, WhiteoutOpaqueDir), // #nosec G305 -- An archive is being created, not extracted.
+ Name: path.Join(hdr.Name, WhiteoutOpaqueDir), // #nosec G305 -- An archive is being created, not extracted.
Size: 0,
Uid: hdr.Uid,
Uname: hdr.Uname,
@@ -68,40 +94,67 @@ func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os
}, nil
}
-func (c overlayWhiteoutConverter) ConvertRead(hdr *tar.Header, path string) (bool, error) {
- base := filepath.Base(path)
- dir := filepath.Dir(path)
+func (c overlayWhiteoutConverter) ConvertRead(root *os.Root, hdr *tar.Header, filePath string) (bool, error) {
+ base := filepath.Base(filePath)
+ dir := filepath.Dir(filePath)
+
+ switch base {
+ case WhiteoutPrefix, WhiteoutPrefix + ".", WhiteoutPrefix + "..":
+ return false, fmt.Errorf("invalid whiteout entry %q", hdr.Name)
+
+ case WhiteoutOpaqueDir:
+ parent, err := root.Open(dir)
+ if err != nil {
+ return false, err
+ }
+ defer parent.Close()
- // if a directory is marked as opaque by the AUFS special file, we need to translate that to overlay
- if base == WhiteoutOpaqueDir {
- opaqueXattrName := "trusted.overlay.opaque"
- if userns.RunningInUserNS() {
- opaqueXattrName = "user.overlay.opaque"
+ // If a directory is marked as opaque by the AUFS special file, we need to translate that to overlay.
+ if err := unix.Fsetxattr(int(parent.Fd()), c.opaqueXattr, []byte{'y'}, 0); err != nil {
+ return false, fmt.Errorf("fsetxattr('%s', %s=y): %w", dir, c.opaqueXattr, err)
}
+ // Don't write the whiteout file itself.
+ return false, nil
- err := unix.Setxattr(dir, opaqueXattrName, []byte{'y'}, 0)
+ default:
+ originalBase, ok := strings.CutPrefix(base, WhiteoutPrefix)
+ if !ok {
+ // Regular file.
+ return true, nil
+ }
+
+ parent, err := root.Open(dir)
if err != nil {
- return false, fmt.Errorf("setxattr('%s', %s=y): %w", dir, opaqueXattrName, err)
+ return false, err
}
- // don't write the file itself
- return false, err
- }
+ defer parent.Close()
- // if a file was deleted and we are using overlay, we need to create a character device
- if strings.HasPrefix(base, WhiteoutPrefix) {
- originalBase := base[len(WhiteoutPrefix):]
+ // If a file was deleted, and we are using overlay, we need to create a character device.
originalPath := filepath.Join(dir, originalBase)
-
- if err := unix.Mknod(originalPath, unix.S_IFCHR, 0); err != nil {
+ if err := unix.Mknodat(int(parent.Fd()), originalBase, unix.S_IFCHR, 0); err != nil {
return false, fmt.Errorf("failed to mknod('%s', S_IFCHR, 0): %w", originalPath, err)
}
- if err := os.Chown(originalPath, hdr.Uid, hdr.Gid); err != nil {
- return false, err
+
+ // Header IDs have already been remapped. Optimize the common non-remapped
+ // root-owned (0:0) case by assuming the created whiteout has the expected
+ // ownership, rather than comparing against the effective UID/GID or stat'ing
+ // the created node to verify it.
+ if hdr.Uid != 0 || hdr.Gid != 0 {
+ // TODO(thaJeztah): Revisit whether whiteout ownership needs to be preserved.
+ //
+ // This was added in the original overlay whiteout implementation:
+ // https://github.com/moby/moby/pull/18560 / https://github.com/moby/moby/pull/22126
+ //
+ // OverlayFS documents whiteouts in terms of a character device with device
+ // number 0:0, not ownership: https://docs.kernel.org/filesystems/overlayfs.html#whiteouts-and-opaque-directories
+ //
+ // If ownership is not required, this Fchownat can be removed to avoid the remaining TOCTOU window.
+ if err := unix.Fchownat(int(parent.Fd()), originalBase, hdr.Uid, hdr.Gid, unix.AT_SYMLINK_NOFOLLOW); err != nil {
+ return false, &os.PathError{Op: "lchown", Path: originalPath, Err: err}
+ }
}
- // don't write the file itself
+ // Don't write the whiteout file itself.
return false, nil
}
-
- return true, nil
}
diff --git a/vendor/github.com/moby/go-archive/archive_other.go b/vendor/github.com/moby/go-archive/archive_other.go
index 6495549f..c8fe0434 100644
--- a/vendor/github.com/moby/go-archive/archive_other.go
+++ b/vendor/github.com/moby/go-archive/archive_other.go
@@ -2,6 +2,14 @@
package archive
+func withProcSelfFD(opts *TarOptions) (*TarOptions, func(), error) {
+ var prepared TarOptions
+ if opts != nil {
+ prepared = *opts
+ }
+ return &prepared, func() {}, nil
+}
+
func getWhiteoutConverter(format WhiteoutFormat) tarWhiteoutConverter {
return nil
}
diff --git a/vendor/github.com/moby/go-archive/archive_unix.go b/vendor/github.com/moby/go-archive/archive_unix.go
index 3a9f5b0b..6b333e5b 100644
--- a/vendor/github.com/moby/go-archive/archive_unix.go
+++ b/vendor/github.com/moby/go-archive/archive_unix.go
@@ -5,14 +5,19 @@ package archive
import (
"archive/tar"
"errors"
+ "fmt"
+ "math"
"os"
"path/filepath"
"strings"
"syscall"
+ "github.com/moby/go-archive/internal/archiveoptions"
"golang.org/x/sys/unix"
)
+var errInvalidArchive = errors.New("invalid archive")
+
// addLongPathPrefix adds the Windows long path prefix to the path provided if
// it does not already have it. It is a no-op on platforms other than Windows.
func addLongPathPrefix(srcPath string) string {
@@ -29,20 +34,19 @@ func getWalkRoot(srcPath string, include string) string {
// chmodTarEntry is used to adjust the file permissions used in tar header based
// on the platform the archival is done.
-func chmodTarEntry(perm os.FileMode) os.FileMode {
- return perm // noop for unix as golang APIs provide perm bits correctly
+func chmodTarEntry(mode int64) int64 {
+ return mode // noop for unix as golang APIs provide perm bits correctly
}
-func getInodeFromStat(stat interface{}) (uint64, error) {
+func getInodeFromStat(stat any) (uint64, error) {
s, ok := stat.(*syscall.Stat_t)
if !ok {
- // FIXME(thaJeztah): this should likely return an error; see https://github.com/moby/moby/pull/49493#discussion_r1979152897
- return 0, nil
+ return 0, fmt.Errorf("unexpected stat type %T", stat)
}
return s.Ino, nil
}
-func getFileUIDGID(stat interface{}) (int, int, error) {
+func getFileUIDGID(stat any) (int, int, error) {
s, ok := stat.(*syscall.Stat_t)
if !ok {
@@ -56,7 +60,7 @@ func getFileUIDGID(stat interface{}) (int, int, error) {
//
// Creating device nodes is not supported when running in a user namespace,
// produces a [syscall.EPERM] in most cases.
-func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {
+func handleTarTypeBlockCharFifo(root *os.Root, hdr *tar.Header, dstPath string) error {
mode := uint32(hdr.Mode & 0o7777)
switch hdr.Typeflag {
case tar.TypeBlock:
@@ -67,20 +71,78 @@ func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {
mode |= unix.S_IFIFO
}
- return mknod(path, mode, unix.Mkdev(uint32(hdr.Devmajor), uint32(hdr.Devminor)))
+ // Devmajor and Devminor come straight from the (untrusted) tar header as
+ // int64, but Mkdev only takes uint32. Casting a value that does not fit
+ // silently truncates it, so the node created on disk would carry a
+ // different major/minor than the header declares. Reject those instead of
+ // creating a mismatched device.
+ if hdr.Devmajor < 0 || hdr.Devmajor > math.MaxUint32 ||
+ hdr.Devminor < 0 || hdr.Devminor > math.MaxUint32 {
+ return fmt.Errorf("device number %d:%d for %q out of range: %w", hdr.Devmajor, hdr.Devminor, hdr.Name, errInvalidArchive)
+ }
+
+ // Prefer mknodat; fall back to a bounded path where unavailable.
+ return mknodInRoot(root, dstPath, mode, unix.Mkdev(uint32(hdr.Devmajor), uint32(hdr.Devminor)))
}
-func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
- if hdr.Typeflag == tar.TypeLink {
- if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
- if err := os.Chmod(path, hdrInfo.Mode()); err != nil {
- return err
- }
- }
- } else if hdr.Typeflag != tar.TypeSymlink {
- if err := os.Chmod(path, hdrInfo.Mode()); err != nil {
- return err
+// handleLChmod applies the mode from hdrInfo to dstPath within root, skipping
+// symlinks (there is no lchmod). For hardlinks, the mode is applied only when
+// the link target is itself not a symlink.
+func handleLChmod(root *os.Root, dstPath string, hardlinkTarget string, hdr *tar.Header, hdrInfo os.FileInfo, opts *archiveoptions.Options) error {
+ switch hdr.Typeflag {
+ case tar.TypeSymlink:
+ return nil
+
+ case tar.TypeLink:
+ // If the target is a symlink, there is no way to chmod the hardlink
+ // without following it.
+ fi, err := root.Lstat(hardlinkTarget)
+ if err != nil || fi.Mode()&os.ModeSymlink != 0 {
+ return nil
}
+ return chmodNoSymlink(root, dstPath, hdrInfo.Mode(), opts)
+
+ default:
+ return chmodNoSymlink(root, dstPath, hdrInfo.Mode(), opts)
+ }
+}
+
+// chmodNoSymlink applies mode to a non-symlink entry.
+//
+// Callers must have already excluded symlink entries.
+func chmodNoSymlink(root *os.Root, name string, mode os.FileMode, opts *archiveoptions.Options) error {
+ parent, err := root.OpenFile(filepath.Dir(name), os.O_RDONLY, 0)
+ if err != nil {
+ return err
+ }
+ defer parent.Close()
+
+ base := filepath.Base(name)
+ perm := fileModeToPerm(mode)
+ // #nosec G115 -- ignore integer overflow conversion for parent.Fd
+ if err := unix.Fchmodat(int(parent.Fd()), base, perm, unix.AT_SYMLINK_NOFOLLOW); err == nil {
+ return nil
+ } else if !errors.Is(err, syscall.EOPNOTSUPP) {
+ return &os.PathError{Op: "fchmodat2", Path: name, Err: err}
+ }
+
+ // Fallback for systems that cannot perform fchmodat with AT_SYMLINK_NOFOLLOW.
+ return chmodNoSymlinkFallback(int(parent.Fd()), base, name, perm, opts) // #nosec G115 -- ignore integer overflow conversion for parent.Fd
+}
+
+// fileModeToPerm returns the subset of an os.FileMode that can be applied
+// by chmod.
+func fileModeToPerm(mode os.FileMode) uint32 {
+ perm := uint32(mode.Perm())
+
+ if mode&os.ModeSetuid != 0 {
+ perm |= unix.S_ISUID
+ }
+ if mode&os.ModeSetgid != 0 {
+ perm |= unix.S_ISGID
+ }
+ if mode&os.ModeSticky != 0 {
+ perm |= unix.S_ISVTX
}
- return nil
+ return perm
}
diff --git a/vendor/github.com/moby/go-archive/archive_windows.go b/vendor/github.com/moby/go-archive/archive_windows.go
index 0e3e316a..a0e43363 100644
--- a/vendor/github.com/moby/go-archive/archive_windows.go
+++ b/vendor/github.com/moby/go-archive/archive_windows.go
@@ -33,30 +33,31 @@ func getWalkRoot(srcPath string, include string) string {
// chmodTarEntry is used to adjust the file permissions used in tar header based
// on the platform the archival is done.
-func chmodTarEntry(perm os.FileMode) os.FileMode {
+func chmodTarEntry(mode int64) int64 {
// Remove group- and world-writable bits.
- perm &= 0o755
+ mode &= 0o755
// Add the x bit: make everything +x on Windows
- return perm | 0o111
+ return mode | 0o111
}
-func getInodeFromStat(stat interface{}) (uint64, error) {
+func getInodeFromStat(stat any) (uint64, error) {
// do nothing. no notion of Inode in stat on Windows
return 0, nil
}
// handleTarTypeBlockCharFifo is an OS-specific helper function used by
// createTarFile to handle the following types of header: Block; Char; Fifo
-func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {
+func handleTarTypeBlockCharFifo(root *os.Root, hdr *tar.Header, path string) error {
return nil
}
-func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
+// handleLChmod is a no-op on Windows because chmod is not supported.
+func handleLChmod(root *os.Root, dstPath string, hardlinkTarget string, hdr *tar.Header, hdrInfo os.FileInfo, opts any) error {
return nil
}
-func getFileUIDGID(stat interface{}) (int, int, error) {
+func getFileUIDGID(stat any) (int, int, error) {
// no notion of file ownership mapping yet on Windows
return 0, 0, nil
}
diff --git a/vendor/github.com/moby/go-archive/changes.go b/vendor/github.com/moby/go-archive/changes.go
index 02a0372c..c5d647c0 100644
--- a/vendor/github.com/moby/go-archive/changes.go
+++ b/vendor/github.com/moby/go-archive/changes.go
@@ -7,6 +7,7 @@ import (
"fmt"
"io"
"io/fs"
+ "maps"
"os"
"path/filepath"
"sort"
@@ -217,8 +218,8 @@ func (info *FileInfo) LookUp(path string) *FileInfo {
return info
}
- pathElements := strings.Split(path, string(os.PathSeparator))
- for _, elem := range pathElements {
+ pathElements := strings.SplitSeq(path, string(os.PathSeparator))
+ for elem := range pathElements {
if elem != "" {
child := parent.children[elem]
if child == nil {
@@ -256,9 +257,7 @@ func (info *FileInfo) addChanges(oldInfo *FileInfo, changes *[]Change) {
// otherwise any previous delete/change is considered recursive
oldChildren := make(map[string]*FileInfo)
if oldInfo != nil && info.isDir() {
- for k, v := range oldInfo.children {
- oldChildren[k] = v
- }
+ maps.Copy(oldChildren, oldInfo.children)
}
for name, newChild := range info.children {
@@ -401,7 +400,7 @@ func ExportChanges(dir string, changes []Change, idMap user.IdentityMapping) (io
whiteOut := filepath.Join(whiteOutDir, WhiteoutPrefix+whiteOutBase)
timestamp := time.Now()
hdr := &tar.Header{
- Name: whiteOut[1:],
+ Name: strings.TrimPrefix(filepath.ToSlash(whiteOut), "/"),
Size: 0,
ModTime: timestamp,
AccessTime: timestamp,
@@ -411,9 +410,10 @@ func ExportChanges(dir string, changes []Change, idMap user.IdentityMapping) (io
log.G(context.TODO()).Debugf("Can't write whiteout header: %s", err)
}
} else {
- path := filepath.Join(dir, change.Path)
- if err := ta.addTarFile(path, change.Path[1:]); err != nil {
- log.G(context.TODO()).Debugf("Can't add file %s to tar: %s", path, err)
+ srcPath := filepath.Join(dir, change.Path)
+ archivePath := strings.TrimPrefix(filepath.ToSlash(change.Path), "/")
+ if err := ta.addTarFile(srcPath, archivePath); err != nil {
+ log.G(context.TODO()).Debugf("Can't add file %s to tar: %s", srcPath, err)
}
}
}
diff --git a/vendor/github.com/moby/go-archive/changes_linux.go b/vendor/github.com/moby/go-archive/changes_linux.go
index 8289fe17..39ec7475 100644
--- a/vendor/github.com/moby/go-archive/changes_linux.go
+++ b/vendor/github.com/moby/go-archive/changes_linux.go
@@ -265,7 +265,7 @@ func parseDirent(buf []byte, names []nameIno) (consumed int, newnames []nameIno)
}
func clen(n []byte) int {
- for i := 0; i < len(n); i++ {
+ for i := range n {
if n[i] == 0 {
return i
}
diff --git a/vendor/github.com/moby/go-archive/changes_other.go b/vendor/github.com/moby/go-archive/changes_other.go
index a8a3a5a6..7eb195d5 100644
--- a/vendor/github.com/moby/go-archive/changes_other.go
+++ b/vendor/github.com/moby/go-archive/changes_other.go
@@ -26,7 +26,7 @@ func collectFileInfoForChanges(oldDir, newDir string) (*FileInfo, *FileInfo, err
}()
// block until both routines have returned
- for i := 0; i < 2; i++ {
+ for range 2 {
if err := <-errs; err != nil {
return nil, nil, err
}
diff --git a/vendor/github.com/moby/go-archive/chmod_linux.go b/vendor/github.com/moby/go-archive/chmod_linux.go
new file mode 100644
index 00000000..8d92f594
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/chmod_linux.go
@@ -0,0 +1,46 @@
+package archive
+
+import (
+ "fmt"
+ "os"
+ "runtime"
+ "strconv"
+
+ "github.com/moby/go-archive/internal/archiveoptions"
+ "golang.org/x/sys/unix"
+)
+
+// chmodNoSymlinkFallback applies mode without following the final path
+// component on systems without fchmodat2 support.
+//
+// Callers must have already excluded symlink entries.
+func chmodNoSymlinkFallback(parentFD int, base, name string, perm uint32, opts *archiveoptions.Options) error {
+ fd, err := unix.Openat(parentFD, base, unix.O_PATH|unix.O_NOFOLLOW|unix.O_CLOEXEC, 0)
+ if err != nil {
+ return &os.PathError{Op: "openat", Path: name, Err: err}
+ }
+ defer unix.Close(fd)
+
+ if opts != nil && opts.ProcSelfFD != nil {
+ err := unix.Fchmodat(int(opts.ProcSelfFD.Fd()), strconv.Itoa(fd), perm, 0)
+ // Keep the os.File alive until fchmodat has finished using its descriptor.
+ runtime.KeepAlive(opts.ProcSelfFD)
+ if err != nil {
+ return &os.PathError{
+ Op: "fchmodat",
+ Path: name,
+ Err: fmt.Errorf("via pre-opened /proc/self/fd/%d: %w", fd, err),
+ }
+ }
+ } else {
+ procPath := "/proc/self/fd/" + strconv.Itoa(fd)
+ if err := unix.Chmod(procPath, perm); err != nil {
+ return &os.PathError{
+ Op: "chmod",
+ Path: name,
+ Err: fmt.Errorf("via %s: %w", procPath, err),
+ }
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/moby/go-archive/chmod_unix_nolinux.go b/vendor/github.com/moby/go-archive/chmod_unix_nolinux.go
new file mode 100644
index 00000000..0acddb1b
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/chmod_unix_nolinux.go
@@ -0,0 +1,27 @@
+//go:build !linux && !windows
+
+package archive
+
+import (
+ "os"
+
+ "github.com/moby/go-archive/internal/archiveoptions"
+ "golang.org/x/sys/unix"
+)
+
+// chmodNoSymlinkFallback applies mode without following the final path
+// component on systems without fchmodat2 support.
+//
+// Callers must have already excluded symlink entries.
+func chmodNoSymlinkFallback(parentFD int, base, name string, perm uint32, _ *archiveoptions.Options) error {
+ fd, err := unix.Openat(parentFD, base, unix.O_RDONLY|unix.O_NOFOLLOW|unix.O_NONBLOCK|unix.O_CLOEXEC, 0)
+ if err != nil {
+ return &os.PathError{Op: "openat", Path: name, Err: err}
+ }
+ defer unix.Close(fd)
+
+ if err := unix.Fchmod(fd, perm); err != nil {
+ return &os.PathError{Op: "fchmod", Path: name, Err: err}
+ }
+ return nil
+}
diff --git a/vendor/github.com/moby/go-archive/compression/compression.go b/vendor/github.com/moby/go-archive/compression/compression.go
index e298cefb..82426792 100644
--- a/vendor/github.com/moby/go-archive/compression/compression.go
+++ b/vendor/github.com/moby/go-archive/compression/compression.go
@@ -66,7 +66,7 @@ type nopWriteCloser struct {
func (nopWriteCloser) Close() error { return nil }
var bufioReader32KPool = &sync.Pool{
- New: func() interface{} { return bufio.NewReaderSize(nil, 32*1024) },
+ New: func() any { return bufio.NewReaderSize(nil, 32*1024) },
}
type bufferedReader struct {
@@ -217,7 +217,7 @@ func gzipDecompress(ctx context.Context, buf io.Reader) (io.ReadCloser, error) {
log.G(ctx).Debugf("Using %s to decompress", unpigzPath)
- return cmdStream(exec.CommandContext(ctx, unpigzPath, "-d", "-c"), buf)
+ return cmdStream(exec.CommandContext(ctx, unpigzPath, "-d", "-c"), buf) // #nosec G204 -- Subprocess launched with variable
}
// cmdStream executes a command, and returns its stdout as a stream.
diff --git a/vendor/github.com/moby/go-archive/copy.go b/vendor/github.com/moby/go-archive/copy.go
index 77d038c4..7447e8bd 100644
--- a/vendor/github.com/moby/go-archive/copy.go
+++ b/vendor/github.com/moby/go-archive/copy.go
@@ -22,7 +22,7 @@ var (
)
var copyPool = sync.Pool{
- New: func() interface{} { s := make([]byte, 32*1024); return &s },
+ New: func() any { s := make([]byte, 32*1024); return &s },
}
func copyWithBuffer(dst io.Writer, src io.Reader) error {
@@ -316,16 +316,40 @@ func PrepareArchiveCopy(srcContent io.Reader, srcInfo, dstInfo CopyInfo) (dstDir
}
}
+// newNameRebaser returns a function that replaces oldBase with newBase at the
+// beginning of POSIX-style archive entry names. It converts oldBase and newBase
+// to forward-slash form and trims trailing slashes.
+//
+// When rebasing from the archive root, the returned function removes all
+// leading slashes from names. It otherwise preserves the remainder verbatim
+// and does not clean or canonicalize paths.
+func newNameRebaser(oldBase, newBase string) func(string) string {
+ oldBase = strings.TrimRight(filepath.ToSlash(oldBase), "/")
+ newBase = strings.TrimRight(filepath.ToSlash(newBase), "/")
+
+ if oldBase == "" {
+ return func(name string) string {
+ name = strings.TrimLeft(name, "/")
+ if newBase == "" {
+ return name
+ }
+ return newBase + "/" + name
+ }
+ }
+
+ return func(name string) string {
+ suffix, ok := strings.CutPrefix(name, oldBase)
+ if !ok || suffix != "" && !strings.HasPrefix(suffix, "/") {
+ return name
+ }
+ return newBase + suffix
+ }
+}
+
// RebaseArchiveEntries rewrites the given srcContent archive replacing
// an occurrence of oldBase with newBase at the beginning of entry names.
func RebaseArchiveEntries(srcContent io.Reader, oldBase, newBase string) io.ReadCloser {
- if oldBase == string(os.PathSeparator) {
- // If oldBase specifies the root directory, use an empty string as
- // oldBase instead so that newBase doesn't replace the path separator
- // that all paths will start with.
- oldBase = ""
- }
-
+ rebase := newNameRebaser(oldBase, newBase)
rebased, w := io.Pipe()
go func() {
@@ -336,12 +360,12 @@ func RebaseArchiveEntries(srcContent io.Reader, oldBase, newBase string) io.Read
hdr, err := srcTar.Next()
if errors.Is(err, io.EOF) {
// Signals end of archive.
- rebasedTar.Close()
- w.Close()
+ _ = rebasedTar.Close()
+ _ = w.Close()
return
}
if err != nil {
- w.CloseWithError(err)
+ _ = w.CloseWithError(err)
return
}
@@ -353,13 +377,13 @@ func RebaseArchiveEntries(srcContent io.Reader, oldBase, newBase string) io.Read
//
// To fix, set the format to PAX here. See docker/for-linux issue #484.
hdr.Format = tar.FormatPAX
- hdr.Name = strings.Replace(hdr.Name, oldBase, newBase, 1)
+ hdr.Name = rebase(hdr.Name)
if hdr.Typeflag == tar.TypeLink {
- hdr.Linkname = strings.Replace(hdr.Linkname, oldBase, newBase, 1)
+ hdr.Linkname = rebase(hdr.Linkname)
}
if err = rebasedTar.WriteHeader(hdr); err != nil {
- w.CloseWithError(err)
+ _ = w.CloseWithError(err)
return
}
@@ -374,7 +398,7 @@ func RebaseArchiveEntries(srcContent io.Reader, oldBase, newBase string) io.Read
// not be vulnerable to this code consuming memory.
//nolint:gosec // G110: Potential DoS vulnerability via decompression bomb (gosec)
if _, err = io.Copy(rebasedTar, srcTar); err != nil {
- w.CloseWithError(err)
+ _ = w.CloseWithError(err)
return
}
}
@@ -408,7 +432,7 @@ func CopyResource(srcPath, dstPath string, followLink bool) error {
if err != nil {
return err
}
- defer content.Close()
+ defer func() { _ = content.Close() }()
return CopyTo(content, srcInfo, dstPath)
}
@@ -427,14 +451,12 @@ func CopyTo(content io.Reader, srcInfo CopyInfo, dstPath string) error {
if err != nil {
return err
}
- defer copyArchive.Close()
+ defer func() { _ = copyArchive.Close() }()
- options := &TarOptions{
+ return Untar(copyArchive, dstDir, &TarOptions{
NoLchown: true,
NoOverwriteDirNonDir: true,
- }
-
- return Untar(copyArchive, dstDir, options)
+ })
}
// ResolveHostSourcePath decides real path need to be copied with parameters such as
diff --git a/vendor/github.com/moby/go-archive/dev_darwin.go b/vendor/github.com/moby/go-archive/dev_darwin.go
new file mode 100644
index 00000000..fcfe730c
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/dev_darwin.go
@@ -0,0 +1,21 @@
+//go:build darwin
+
+package archive
+
+import (
+ "os"
+
+ "golang.org/x/sys/unix"
+)
+
+func mknod(path string, mode uint32, dev uint64) error {
+ return unix.Mknod(path, mode, int(dev)) // #nosec G115 -- Required conversion for the platform-specific Mknod API.
+}
+
+func mknodInRoot(root *os.Root, path string, mode uint32, dev uint64) error {
+ abs, err := fsRootPath(root.Name(), path)
+ if err != nil {
+ return err
+ }
+ return unix.Mknod(abs, mode, int(dev)) // #nosec G115 -- Required conversion for the platform-specific Mknod API.
+}
diff --git a/vendor/github.com/moby/go-archive/dev_freebsd.go b/vendor/github.com/moby/go-archive/dev_freebsd.go
index b3068fce..d18e829b 100644
--- a/vendor/github.com/moby/go-archive/dev_freebsd.go
+++ b/vendor/github.com/moby/go-archive/dev_freebsd.go
@@ -2,8 +2,23 @@
package archive
-import "golang.org/x/sys/unix"
+import (
+ "os"
+ "path/filepath"
+
+ "golang.org/x/sys/unix"
+)
func mknod(path string, mode uint32, dev uint64) error {
return unix.Mknod(path, mode, dev)
}
+
+func mknodInRoot(root *os.Root, path string, mode uint32, dev uint64) error {
+ parent, err := root.OpenFile(filepath.Dir(path), os.O_RDONLY|unix.O_DIRECTORY, 0)
+ if err != nil {
+ return err
+ }
+ defer parent.Close()
+
+ return unix.Mknodat(int(parent.Fd()), filepath.Base(path), mode, dev)
+}
diff --git a/vendor/github.com/moby/go-archive/dev_unix.go b/vendor/github.com/moby/go-archive/dev_unix.go
index dffc596f..0eb8b6da 100644
--- a/vendor/github.com/moby/go-archive/dev_unix.go
+++ b/vendor/github.com/moby/go-archive/dev_unix.go
@@ -1,9 +1,24 @@
-//go:build !windows && !freebsd
+//go:build !darwin && !freebsd && !windows
package archive
-import "golang.org/x/sys/unix"
+import (
+ "os"
+ "path/filepath"
+
+ "golang.org/x/sys/unix"
+)
func mknod(path string, mode uint32, dev uint64) error {
- return unix.Mknod(path, mode, int(dev))
+ return unix.Mknod(path, mode, int(dev)) // #nosec G115 -- Required conversion for the platform-specific Mknod API.
+}
+
+func mknodInRoot(root *os.Root, path string, mode uint32, dev uint64) error {
+ parent, err := root.OpenFile(filepath.Dir(path), os.O_RDONLY|unix.O_DIRECTORY, 0)
+ if err != nil {
+ return err
+ }
+ defer parent.Close()
+
+ return unix.Mknodat(int(parent.Fd()), filepath.Base(path), mode, int(dev)) // #nosec G115 -- Required conversion for the platform-specific Mknod API.
}
diff --git a/vendor/github.com/moby/go-archive/diff.go b/vendor/github.com/moby/go-archive/diff.go
index 96db972d..b9450186 100644
--- a/vendor/github.com/moby/go-archive/diff.go
+++ b/vendor/github.com/moby/go-archive/diff.go
@@ -7,8 +7,8 @@ import (
"fmt"
"io"
"os"
+ "path"
"path/filepath"
- "runtime"
"strings"
"github.com/containerd/log"
@@ -20,17 +20,23 @@ import (
// compressed or uncompressed.
// Returns the size in bytes of the contents of the layer.
func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64, err error) {
+ root, err := os.OpenRoot(dest)
+ if err != nil {
+ return 0, err
+ }
+ defer root.Close()
+
tr := tar.NewReader(layer)
- var dirs []*tar.Header
+ var dirs []unpackedDir
+ // unpackedPaths tracks resolved, native-separator, root-relative paths
+ // already written in this layer so that the AUFS opaque-whiteout walk
+ // knows which paths to preserve.
unpackedPaths := make(map[string]struct{})
if options == nil {
options = &TarOptions{}
}
- if options.ExcludePatterns == nil {
- options.ExcludePatterns = []string{}
- }
aufsTempdir := ""
aufsHardlinks := make(map[string]*tar.Header)
@@ -48,34 +54,22 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
size += hdr.Size
- // Normalize name, for safety and for a simple is-root check
- hdr.Name = filepath.Clean(hdr.Name)
-
- // Windows does not support filenames with colons in them. Ignore
- // these files. This is not a problem though (although it might
- // appear that it is). Let's suppose a client is running docker pull.
- // The daemon it points to is Windows. Would it make sense for the
- // client to be doing a docker pull Ubuntu for example (which has files
- // with colons in the name under /usr/share/man/man3)? No, absolutely
- // not as it would really only make sense that they were pulling a
- // Windows image. However, for development, it is necessary to be able
- // to pull Linux images which are in the repository.
- //
- // TODO Windows. Once the registry is aware of what images are Windows-
- // specific or Linux-specific, this warning should be changed to an error
- // to cater for the situation where someone does manage to upload a Linux
- // image but have it tagged as Windows inadvertently.
- if runtime.GOOS == "windows" {
- if strings.Contains(hdr.Name, ":") {
- log.G(context.TODO()).Warnf("Windows: Ignoring %s (is this a Linux image?)", hdr.Name)
- continue
- }
+ // Strip a leading "/" so absolute entries stay root-relative, and
+ // normalize the POSIX tar path. Skip entries referring to the extraction
+ // root and reject paths that escape it.
+ name := path.Clean(strings.TrimLeft(hdr.Name, "/"))
+ if name == "." {
+ continue
+ }
+ if !filepath.IsLocal(name) {
+ return 0, breakoutError(fmt.Errorf("invalid entry name %q", hdr.Name))
}
+ hdr.Name = name
- // Ensure that the parent directory exists.
- err = createImpliedDirectories(dest, hdr, options)
- if err != nil {
- return 0, err
+ // Skip entries whose name (or hardlink target) Windows cannot represent.
+ if err := unrepresentableOnWindows(hdr); err != nil {
+ log.G(context.TODO()).Warnf("Windows: ignoring entry: %v", err)
+ continue
}
// Skip AUFS metadata dirs
@@ -84,7 +78,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
// We don't want this directory, but we need the files in them so that
// such hardlinks can be resolved.
if strings.HasPrefix(hdr.Name, WhiteoutLinkDir) && hdr.Typeflag == tar.TypeReg {
- basename := filepath.Base(hdr.Name)
+ basename := path.Base(hdr.Name)
aufsHardlinks[basename] = hdr
if aufsTempdir == "" {
if aufsTempdir, err = os.MkdirTemp(dest, "dockerplnk"); err != nil {
@@ -92,47 +86,68 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
}
defer os.RemoveAll(aufsTempdir)
}
- if err := createTarFile(filepath.Join(aufsTempdir, basename), dest, hdr, tr, options); err != nil {
+ aufsRoot, err := os.OpenRoot(aufsTempdir)
+ if err != nil {
return 0, err
}
+ cerr := createTarFile(aufsRoot, basename, hdr, tr, options)
+ _ = aufsRoot.Close()
+ if cerr != nil {
+ return 0, cerr
+ }
}
if hdr.Name != WhiteoutOpaqueDir {
continue
}
}
- // #nosec G305 -- The joined path is guarded against path traversal.
- path := filepath.Join(dest, hdr.Name)
- rel, err := filepath.Rel(dest, path)
+ // dstPath is the native (host-separator) form of the entry name,
+ // used at all filesystem boundaries (os.Root methods, fsRootPath).
+ // The tar-header name (hdr.Name) is POSIX, so convert it here.
+ dstPath, err := resolveArchivePath(root, filepath.FromSlash(hdr.Name))
if err != nil {
return 0, err
}
-
- // Note as these operations are platform specific, so must the slash be.
- if strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
- return 0, breakoutError(fmt.Errorf("%q is outside of %q", hdr.Name, dest))
+ // Ensure that the parent directory exists.
+ if err := createImpliedDirectories(root, dstPath, options); err != nil {
+ return 0, err
}
- base := filepath.Base(path)
-
- if strings.HasPrefix(base, WhiteoutPrefix) {
- dir := filepath.Dir(path)
+ if base := filepath.Base(dstPath); strings.HasPrefix(base, WhiteoutPrefix) {
+ dir := filepath.Dir(dstPath)
if base == WhiteoutOpaqueDir {
- _, err := os.Lstat(dir)
+ _, err := root.Lstat(dir)
+ if err != nil {
+ return 0, err
+ }
+ // Walk the absolute directory so we can call os.RemoveAll on
+ // paths outside the walk callback's reach, then convert each
+ // walked path back to a root-relative name for the
+ // unpackedPaths check.
+ // fsRootPath walks each path component and bounds any symlinks
+ // within the root to prevent TOCTOU symlink attacks.
+ absDir, err := fsRootPath(root.Name(), dir)
if err != nil {
return 0, err
}
- err = filepath.WalkDir(dir, func(path string, info os.DirEntry, err error) error {
+ err = filepath.WalkDir(absDir, func(p string, info os.DirEntry, err error) error {
if err != nil {
if os.IsNotExist(err) {
- err = nil // parent was deleted
+ return nil // parent was deleted
}
return err
}
- if path == dir {
+ if p == absDir {
return nil
}
- if _, exists := unpackedPaths[path]; !exists {
- return os.RemoveAll(path)
+ rel, err := filepath.Rel(root.Name(), p)
+ if err != nil {
+ return err
+ }
+
+ // unpackedPaths is keyed by resolved, native-separator,
+ // root-relative paths, matching filepath.WalkDir's paths.
+ if _, exists := unpackedPaths[rel]; !exists {
+ return root.RemoveAll(rel)
}
return nil
})
@@ -142,18 +157,18 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
} else {
originalBase := base[len(WhiteoutPrefix):]
originalPath := filepath.Join(dir, originalBase)
- if err := os.RemoveAll(originalPath); err != nil {
+ if err := root.RemoveAll(originalPath); err != nil {
return 0, err
}
}
} else {
- // If path exits we almost always just want to remove and replace it.
+ // If dstPath exists we almost always just want to remove and replace it.
// The only exception is when it is a directory *and* the file from
// the layer is also a directory. Then we want to merge them (i.e.
// just apply the metadata from the layer).
- if fi, err := os.Lstat(path); err == nil {
+ if fi, err := root.Lstat(dstPath); err == nil {
if !fi.IsDir() || hdr.Typeflag != tar.TypeDir {
- if err := os.RemoveAll(path); err != nil {
+ if err := root.RemoveAll(dstPath); err != nil {
return 0, err
}
}
@@ -164,8 +179,8 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
// Hard links into /.wh..wh.plnk don't work, as we don't extract that directory, so
// we manually retarget these into the temporary files we extracted them into
- if hdr.Typeflag == tar.TypeLink && strings.HasPrefix(filepath.Clean(hdr.Linkname), WhiteoutLinkDir) {
- linkBasename := filepath.Base(hdr.Linkname)
+ if hdr.Typeflag == tar.TypeLink && strings.HasPrefix(path.Clean(hdr.Linkname), WhiteoutLinkDir) {
+ linkBasename := path.Base(hdr.Linkname)
srcHdr = aufsHardlinks[linkBasename]
if srcHdr == nil {
return 0, errors.New("invalid aufs hardlink")
@@ -182,23 +197,23 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
return 0, err
}
- if err := createTarFile(path, dest, srcHdr, srcData, options); err != nil {
+ if err := createTarFile(root, dstPath, srcHdr, srcData, options); err != nil {
return 0, err
}
// Directory mtimes must be handled at the end to avoid further
// file creation in them to modify the directory mtime
if hdr.Typeflag == tar.TypeDir {
- dirs = append(dirs, hdr)
+ dirs = append(dirs, unpackedDir{hdr: hdr, name: dstPath})
}
- unpackedPaths[path] = struct{}{}
+ // Record the resolved, native-separator, root-relative path so it
+ // matches the paths produced by the opaque-whiteout walk.
+ unpackedPaths[dstPath] = struct{}{}
}
}
- for _, hdr := range dirs {
- // #nosec G305 -- The header was checked for path traversal before it was appended to the dirs slice.
- path := filepath.Join(dest, hdr.Name)
- if err := chtimes(path, hdr.AccessTime, hdr.ModTime); err != nil {
+ for _, d := range dirs {
+ if err := chtimes(root, d.name, boundTime(latestTime(d.hdr.AccessTime, d.hdr.ModTime)), boundTime(d.hdr.ModTime)); err != nil {
return 0, err
}
}
diff --git a/vendor/github.com/moby/go-archive/internal/archiveoptions/options.go b/vendor/github.com/moby/go-archive/internal/archiveoptions/options.go
new file mode 100644
index 00000000..201eb91b
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/internal/archiveoptions/options.go
@@ -0,0 +1,12 @@
+// Package archiveoptions defines internal options shared between archive and
+// chrootarchive.
+package archiveoptions
+
+import "os"
+
+// Options contains extraction resources supplied by internal callers.
+type Options struct {
+ // ProcSelfFD references /proc/self/fd as opened before entering a chroot.
+ // The caller retains ownership of the file.
+ ProcSelfFD *os.File
+}
diff --git a/vendor/github.com/moby/go-archive/rootpath.go b/vendor/github.com/moby/go-archive/rootpath.go
new file mode 100644
index 00000000..7d34839d
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/rootpath.go
@@ -0,0 +1,142 @@
+/*
+ Copyright The containerd Authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package archive
+
+import (
+ "errors"
+ "os"
+ "path/filepath"
+)
+
+var errTooManyLinks = errors.New("too many links")
+
+type fsRootPathResult struct {
+ path string
+ followedAbsoluteLink bool
+ relativeEscapeBeforeAbsolute bool
+}
+
+// fsRootPath joins a path with a root, evaluating and bounding any
+// symlink to the root directory.
+func fsRootPath(root, path string) (string, error) {
+ result, err := resolveFSRootPath(root, path)
+ if err != nil {
+ return "", err
+ }
+ return result.path, nil
+}
+
+func resolveFSRootPath(root, path string) (fsRootPathResult, error) {
+ result := fsRootPathResult{path: root}
+ if path == "" {
+ return result, nil
+ }
+ var linksWalked int // to protect against cycles
+ for {
+ i := linksWalked
+ newpath, err := walkLinks(root, path, &linksWalked, &result)
+ if err != nil {
+ return fsRootPathResult{}, err
+ }
+ path = newpath
+ if i == linksWalked {
+ newpath = filepath.Join(string(os.PathSeparator), newpath)
+ if path == newpath {
+ result.path = filepath.Join(root, newpath)
+ return result, nil
+ }
+ path = newpath
+ }
+ }
+}
+
+func walkLink(root, path string, linksWalked *int, result *fsRootPathResult) (newpath string, islink bool, err error) {
+ if *linksWalked > 255 {
+ return "", false, errTooManyLinks
+ }
+
+ path = filepath.Join(string(os.PathSeparator), path)
+ if path == string(os.PathSeparator) {
+ return path, false, nil
+ }
+ realPath := filepath.Join(root, path)
+
+ fi, err := os.Lstat(realPath)
+ if err != nil {
+ // If path does not yet exist, treat as non-symlink
+ if os.IsNotExist(err) {
+ return path, false, nil
+ }
+ return "", false, err
+ }
+ if fi.Mode()&os.ModeSymlink == 0 {
+ return path, false, nil
+ }
+ newpath, err = os.Readlink(realPath)
+ if err != nil {
+ return "", false, err
+ }
+ if filepath.IsAbs(newpath) {
+ result.followedAbsoluteLink = true
+ } else if !result.followedAbsoluteLink {
+ // Record an escape before a later absolute link can make the original
+ // os.Root error appear eligible for resolve-in-root fallback.
+ relativeDir, err := filepath.Rel(string(os.PathSeparator), filepath.Dir(path))
+ if err != nil {
+ return "", false, err
+ }
+
+ resolved := filepath.Join(relativeDir, newpath)
+ if resolved != "." && !filepath.IsLocal(resolved) {
+ result.relativeEscapeBeforeAbsolute = true
+ }
+ }
+
+ *linksWalked++
+ return newpath, true, nil
+}
+
+func walkLinks(root, path string, linksWalked *int, result *fsRootPathResult) (string, error) {
+ switch dir, file := filepath.Split(path); {
+ case dir == "":
+ newpath, _, err := walkLink(root, file, linksWalked, result)
+ return newpath, err
+ case file == "":
+ if os.IsPathSeparator(dir[len(dir)-1]) {
+ if dir == string(os.PathSeparator) {
+ return dir, nil
+ }
+ return walkLinks(root, dir[:len(dir)-1], linksWalked, result)
+ }
+ newpath, _, err := walkLink(root, dir, linksWalked, result)
+ return newpath, err
+
+ default:
+ newdir, err := walkLinks(root, dir, linksWalked, result)
+ if err != nil {
+ return "", err
+ }
+ newpath, islink, err := walkLink(root, filepath.Join(newdir, file), linksWalked, result)
+ if err != nil {
+ return "", err
+ }
+ if !islink || filepath.IsAbs(newpath) {
+ return newpath, nil
+ }
+ return filepath.Join(newdir, newpath), nil
+ }
+}
diff --git a/vendor/github.com/moby/go-archive/sequential_other.go b/vendor/github.com/moby/go-archive/sequential_other.go
new file mode 100644
index 00000000..90edb139
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/sequential_other.go
@@ -0,0 +1,6 @@
+//go:build !windows
+
+package archive
+
+// windows_O_FILE_FLAG_SEQUENTIAL_SCAN is not supported on go < 1.26.
+const windows_O_FILE_FLAG_SEQUENTIAL_SCAN = 0
diff --git a/vendor/github.com/moby/go-archive/sequential_windows_go126.go b/vendor/github.com/moby/go-archive/sequential_windows_go126.go
new file mode 100644
index 00000000..1e80d11b
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/sequential_windows_go126.go
@@ -0,0 +1,9 @@
+//go:build windows && go1.26
+
+package archive
+
+// windows_O_FILE_FLAG_SEQUENTIAL_SCAN matches [golang.org/x/sys/windows.O_FILE_FLAG_SEQUENTIAL_SCAN].
+// Starting in Go 1.26, os.OpenFile supports passing this flag through.
+//
+// TODO(thaJeztah): use windows.O_FILE_FLAG_SEQUENTIAL_SCAN once we drop Go <1.26.
+const windows_O_FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000
diff --git a/vendor/github.com/moby/go-archive/sequential_windows_pre126.go b/vendor/github.com/moby/go-archive/sequential_windows_pre126.go
new file mode 100644
index 00000000..2b281741
--- /dev/null
+++ b/vendor/github.com/moby/go-archive/sequential_windows_pre126.go
@@ -0,0 +1,6 @@
+//go:build windows && !go1.26
+
+package archive
+
+// windows_O_FILE_FLAG_SEQUENTIAL_SCAN is not supported on go < 1.26.
+const windows_O_FILE_FLAG_SEQUENTIAL_SCAN = 0
diff --git a/vendor/github.com/moby/go-archive/tarheader/tarheader.go b/vendor/github.com/moby/go-archive/tarheader/tarheader.go
index 03732a4f..78ab55cd 100644
--- a/vendor/github.com/moby/go-archive/tarheader/tarheader.go
+++ b/vendor/github.com/moby/go-archive/tarheader/tarheader.go
@@ -32,7 +32,7 @@ func (fi nosysFileInfo) Gname() (string, error) {
return "", nil
}
-func (fi nosysFileInfo) Sys() interface{} {
+func (fi nosysFileInfo) Sys() any {
// A Sys value of type *tar.Header is safe as it is system-independent.
// The tar.FileInfoHeader function copies the fields into the returned
// header without performing any OS lookups.
diff --git a/vendor/github.com/moby/go-archive/tarheader/tarheader_unix.go b/vendor/github.com/moby/go-archive/tarheader/tarheader_unix.go
index 9c3311c6..bd12d46a 100644
--- a/vendor/github.com/moby/go-archive/tarheader/tarheader_unix.go
+++ b/vendor/github.com/moby/go-archive/tarheader/tarheader_unix.go
@@ -36,10 +36,11 @@ func sysStat(fi os.FileInfo, hdr *tar.Header) error {
hdr.Uid = int(s.Uid)
hdr.Gid = int(s.Gid)
- if s.Mode&unix.S_IFBLK != 0 ||
- s.Mode&unix.S_IFCHR != 0 {
- hdr.Devmajor = int64(unix.Major(uint64(s.Rdev))) //nolint: unconvert
- hdr.Devminor = int64(unix.Minor(uint64(s.Rdev))) //nolint: unconvert
+ if s.Mode&unix.S_IFBLK != 0 || s.Mode&unix.S_IFCHR != 0 {
+ // #nosec G115 -- Rdev type varies by platform.
+ rdev := uint64(s.Rdev) //nolint:unconvert // Rdev type varies by platform.
+ hdr.Devmajor = int64(unix.Major(rdev))
+ hdr.Devminor = int64(unix.Minor(rdev))
}
return nil
diff --git a/vendor/github.com/moby/go-archive/time.go b/vendor/github.com/moby/go-archive/time.go
index 4e9ae950..fb8c0299 100644
--- a/vendor/github.com/moby/go-archive/time.go
+++ b/vendor/github.com/moby/go-archive/time.go
@@ -22,6 +22,10 @@ func init() {
}
}
+// boundTime returns t if it falls within the range supported by os.Chtimes.
+// Times before the Unix epoch (minTime) or after the end of Unix time
+// (maxTime) are replaced with minTime, as os.Chtimes has undefined behavior
+// outside that range.
func boundTime(t time.Time) time.Time {
if t.Before(minTime) || t.After(maxTime) {
return minTime
diff --git a/vendor/github.com/moby/go-archive/time_nonwindows.go b/vendor/github.com/moby/go-archive/time_nonwindows.go
index 5bfdfa2f..418bc887 100644
--- a/vendor/github.com/moby/go-archive/time_nonwindows.go
+++ b/vendor/github.com/moby/go-archive/time_nonwindows.go
@@ -3,18 +3,55 @@
package archive
import (
+ "errors"
"os"
+ "path"
+ "path/filepath"
+ "strings"
+ "syscall"
"time"
"golang.org/x/sys/unix"
)
-// chtimes changes the access time and modified time of a file at the given path.
-// If the modified time is prior to the Unix Epoch (unixMinTime), or after the
-// end of Unix Time (unixEpochTime), os.Chtimes has undefined behavior. In this
-// case, Chtimes defaults to Unix Epoch, just in case.
-func chtimes(name string, atime time.Time, mtime time.Time) error {
- return os.Chtimes(name, atime, mtime)
+// chtimes changes the access and modification time of a file at the given
+// path relative to root.
+//
+// Callers must use boundTime to ensure timestamps are within the range
+// supported by os.Chtimes.
+func chtimes(root *os.Root, name string, atime, mtime time.Time) error {
+ return root.Chtimes(name, atime, mtime)
+}
+
+func lchtimes(root *os.Root, name string, atime, mtime time.Time) error {
+ dir, base := path.Split(filepath.ToSlash(name))
+ if base == "" {
+ return &os.PathError{Op: "lchtimes", Path: name, Err: syscall.EINVAL}
+ }
+
+ dir = strings.TrimSuffix(dir, "/")
+ if dir == "" {
+ dir = "."
+ }
+
+ parent, err := root.Open(dir)
+ if err != nil {
+ return err
+ }
+ defer parent.Close()
+
+ utimes := [2]unix.Timespec{
+ timeToTimespec(atime),
+ timeToTimespec(mtime),
+ }
+ // #nosec G115 -- ignore integer overflow conversion for parent.Fd
+ if err := unix.UtimesNanoAt(int(parent.Fd()), base, utimes[:], unix.AT_SYMLINK_NOFOLLOW); err != nil {
+ if errors.Is(err, unix.ENOSYS) {
+ return nil
+ }
+ return &os.PathError{Op: "lchtimes", Path: name, Err: err}
+ }
+ return nil
}
func timeToTimespec(time time.Time) unix.Timespec {
@@ -27,15 +64,3 @@ func timeToTimespec(time time.Time) unix.Timespec {
}
return unix.NsecToTimespec(time.UnixNano())
}
-
-func lchtimes(name string, atime time.Time, mtime time.Time) error {
- utimes := [2]unix.Timespec{
- timeToTimespec(atime),
- timeToTimespec(mtime),
- }
- err := unix.UtimesNanoAt(unix.AT_FDCWD, name, utimes[0:], unix.AT_SYMLINK_NOFOLLOW)
- if err != nil && err != unix.ENOSYS {
- return err
- }
- return err
-}
diff --git a/vendor/github.com/moby/go-archive/time_windows.go b/vendor/github.com/moby/go-archive/time_windows.go
index af1f7c8f..66173c58 100644
--- a/vendor/github.com/moby/go-archive/time_windows.go
+++ b/vendor/github.com/moby/go-archive/time_windows.go
@@ -1,32 +1,111 @@
package archive
import (
+ "errors"
"os"
+ "path/filepath"
"time"
+ "unsafe"
"golang.org/x/sys/windows"
)
-func chtimes(name string, atime time.Time, mtime time.Time) error {
- if err := os.Chtimes(name, atime, mtime); err != nil {
+// chtimes changes the access and modification time of a file at the given
+// path relative to root.
+//
+// Symlink entries are handled separately through lchtimes. The final path
+// component is expected not to be a reparse point; if one is encountered,
+// chtimes returns an error.
+//
+// Callers must use boundTime to ensure timestamps are within the range
+// supported by os.Chtimes.
+func chtimes(root *os.Root, name string, atime, mtime time.Time) error {
+ parent, err := root.OpenFile(filepath.Dir(name), os.O_RDONLY, 0)
+ if err != nil {
return err
}
+ defer parent.Close()
+
+ // Symlink entries are handled by lchtimes. The destination for all
+ // chtimes callers is therefore expected not to be a reparse point.
+ //
+ // Do not follow the final component: if it was concurrently replaced
+ // with a reparse point, fail instead of updating its target.
+ return chtimesAt(parent, filepath.Base(name), atime, mtime, true)
+}
- pathp, err := windows.UTF16PtrFromString(name)
+func lchtimes(root *os.Root, name string, atime time.Time, mtime time.Time) error {
+ return nil
+}
+
+func chtimesAt(parent *os.File, name string, atime, mtime time.Time, noFollow bool) error {
+ h, err := openForWriteAttributesAt(windows.Handle(parent.Fd()), name, noFollow)
if err != nil {
+ if noFollow && errors.Is(err, windows.STATUS_REPARSE_POINT_ENCOUNTERED) {
+ // Encountering a reparse point when noFollow is requested is unexpected.
+ // Treat it as a potential breakout to fail extraction safely.
+ return breakoutError(err)
+ }
return err
}
- h, err := windows.CreateFile(pathp,
- windows.FILE_WRITE_ATTRIBUTES, windows.FILE_SHARE_WRITE, nil,
- windows.OPEN_EXISTING, windows.FILE_FLAG_BACKUP_SEMANTICS, 0)
+ defer func() { _ = windows.Close(h) }()
+
+ var (
+ creationTime = windows.NsecToFiletime(mtime.UnixNano())
+ accessTime = windows.NsecToFiletime(atime.UnixNano())
+ modificationTime = windows.NsecToFiletime(mtime.UnixNano())
+ )
+ return windows.SetFileTime(h, &creationTime, &accessTime, &modificationTime)
+}
+
+// openForWriteAttributesAt opens name relative to parent with permission to
+// modify its file attributes. If noFollow is true, it does not follow reparse
+// points.
+//
+// This implementation is based on Go's internal Windows Openat support:
+//
+// https://github.com/golang/go/blob/go1.26.0/src/internal/syscall/windows/at_windows.go
+//
+// It is used by os.Root's Windows implementation for root-relative filesystem
+// operations:
+//
+// https://github.com/golang/go/blob/go1.26.0/src/os/root_windows.go
+//
+// Keep this implementation aligned with the upstream code until an equivalent
+// operation is available from golang.org/x/sys/windows.
+func openForWriteAttributesAt(parent windows.Handle, name string, noFollow bool) (windows.Handle, error) {
+ name16, err := windows.UTF16FromString(name)
if err != nil {
- return err
+ return windows.InvalidHandle, err
}
- defer windows.Close(h)
- c := windows.NsecToFiletime(mtime.UnixNano())
- return windows.SetFileTime(h, &c, nil, nil)
-}
-func lchtimes(name string, atime time.Time, mtime time.Time) error {
- return nil
+ attrs := uint32(windows.OBJ_CASE_INSENSITIVE)
+ if noFollow {
+ attrs |= windows.OBJ_DONT_REPARSE
+ }
+
+ var handle windows.Handle
+ err = windows.NtCreateFile(
+ &handle,
+ windows.SYNCHRONIZE|windows.FILE_WRITE_ATTRIBUTES,
+ &windows.OBJECT_ATTRIBUTES{
+ Length: uint32(unsafe.Sizeof(windows.OBJECT_ATTRIBUTES{})),
+ RootDirectory: parent,
+ ObjectName: &windows.NTUnicodeString{
+ Length: uint16((len(name16) - 1) * 2), // #nosec G115 -- Length is USHORT by definition. A Windows path component cannot exceed uint16 bytes.
+ MaximumLength: uint16(len(name16) * 2), // #nosec G115 -- MaximumLength is USHORT by definition. A Windows path component cannot exceed uint16 bytes.
+ Buffer: &name16[0],
+ },
+ Attributes: attrs,
+ },
+ &windows.IO_STATUS_BLOCK{},
+ nil,
+ windows.FILE_ATTRIBUTE_NORMAL,
+ windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE,
+ windows.FILE_OPEN,
+ windows.FILE_OPEN_FOR_BACKUP_INTENT|windows.FILE_SYNCHRONOUS_IO_NONALERT,
+ 0, // EA buffer
+ 0, // EA length
+ )
+ return handle, err
}
diff --git a/vendor/github.com/moby/go-archive/xattr_supported.go b/vendor/github.com/moby/go-archive/xattr_supported.go
index 652a1f0f..8478fe14 100644
--- a/vendor/github.com/moby/go-archive/xattr_supported.go
+++ b/vendor/github.com/moby/go-archive/xattr_supported.go
@@ -13,26 +13,26 @@ import (
// lgetxattr retrieves the value of the extended attribute identified by attr
// and associated with the given path in the file system.
// It returns a nil slice and nil error if the xattr is not set.
-func lgetxattr(path string, attr string) ([]byte, error) {
+func lgetxattr(filePath string, attr string) ([]byte, error) {
// Start with a 128 length byte array
dest := make([]byte, 128)
- sz, err := unix.Lgetxattr(path, attr, dest)
+ sz, err := unix.Lgetxattr(filePath, attr, dest)
for errors.Is(err, unix.ERANGE) {
// Buffer too small, use zero-sized buffer to get the actual size
- sz, err = unix.Lgetxattr(path, attr, []byte{})
+ sz, err = unix.Lgetxattr(filePath, attr, []byte{})
if err != nil {
- return nil, wrapPathError("lgetxattr", path, attr, err)
+ return nil, wrapPathError("lgetxattr", filePath, attr, err)
}
dest = make([]byte, sz)
- sz, err = unix.Lgetxattr(path, attr, dest)
+ sz, err = unix.Lgetxattr(filePath, attr, dest)
}
if err != nil {
if errors.Is(err, noattr) {
return nil, nil
}
- return nil, wrapPathError("lgetxattr", path, attr, err)
+ return nil, wrapPathError("lgetxattr", filePath, attr, err)
}
return dest[:sz], nil
@@ -40,13 +40,13 @@ func lgetxattr(path string, attr string) ([]byte, error) {
// lsetxattr sets the value of the extended attribute identified by attr
// and associated with the given path in the file system.
-func lsetxattr(path string, attr string, data []byte, flags int) error {
- return wrapPathError("lsetxattr", path, attr, unix.Lsetxattr(path, attr, data, flags))
+func lsetxattr(filePath string, attr string, data []byte, flags int) error {
+ return wrapPathError("lsetxattr", filePath, attr, unix.Lsetxattr(filePath, attr, data, flags))
}
-func wrapPathError(op, path, attr string, err error) error {
+func wrapPathError(op, filePath, attr string, err error) error {
if err == nil {
return nil
}
- return &fs.PathError{Op: op, Path: path, Err: fmt.Errorf("xattr %q: %w", attr, err)}
+ return &fs.PathError{Op: op, Path: filePath, Err: fmt.Errorf("xattr %q: %w", attr, err)}
}
diff --git a/vendor/github.com/moby/moby/api/types/jsonstream/json_error.go b/vendor/github.com/moby/moby/api/types/jsonstream/json_error.go
index 632b25fd..0dcc9337 100644
--- a/vendor/github.com/moby/moby/api/types/jsonstream/json_error.go
+++ b/vendor/github.com/moby/moby/api/types/jsonstream/json_error.go
@@ -8,5 +8,8 @@ type Error struct {
}
func (e *Error) Error() string {
+ if e == nil {
+ return ""
+ }
return e.Message
}
diff --git a/vendor/github.com/moby/moby/client/pkg/jsonmessage/jsonmessage.go b/vendor/github.com/moby/moby/client/pkg/jsonmessage/jsonmessage.go
index 9e949c5e..a955363d 100644
--- a/vendor/github.com/moby/moby/client/pkg/jsonmessage/jsonmessage.go
+++ b/vendor/github.com/moby/moby/client/pkg/jsonmessage/jsonmessage.go
@@ -17,9 +17,28 @@ import (
var timeNow = time.Now // For overriding in tests.
// RFC3339NanoFixed is time.RFC3339Nano with nanoseconds padded using zeros to
-// ensure the formatted time isalways the same number of characters.
+// ensure the formatted time is always the same number of characters.
const RFC3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00"
+// DisplayOpt configures behavior for [DisplayStream] and [DisplayMessages].
+// Options are applied in order; if an option returns an error, processing
+// stops and the error is returned to the caller.
+type DisplayOpt func(*displayOpts) error
+
+type displayOpts struct {
+ auxCallback func(jsonstream.Message)
+}
+
+// WithAuxCallback registers a callback that is invoked for auxiliary
+// jsonstream messages as they are processed. The callback is optional;
+// if not provided, auxiliary messages are ignored.
+func WithAuxCallback(fn func(jsonstream.Message)) DisplayOpt {
+ return func(opts *displayOpts) error {
+ opts.auxCallback = fn
+ return nil
+ }
+}
+
func RenderTUIProgress(p jsonstream.Progress, width uint16) string {
var (
pbBox string
@@ -37,16 +56,10 @@ func RenderTUIProgress(p jsonstream.Progress, width uint16) string {
}
}
- percentage := int(float64(p.Current)/float64(p.Total)*100) / 2
- if percentage > 50 {
- percentage = 50
- }
+ percentage := min(int(float64(p.Current)/float64(p.Total)*100)/2, 50)
if width > 110 {
// this number can't be negative gh#7136
- numSpaces := 0
- if 50-percentage > 0 {
- numSpaces = 50 - percentage
- }
+ numSpaces := max(50-percentage, 0)
pbBox = fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", numSpaces))
}
@@ -115,7 +128,7 @@ func cursorDown(out io.Writer, l uint) {
// Display prints the JSONMessage to out. If isTerminal is true, it erases
// the entire current line when displaying the progressbar. It returns an
-// error if the [JSONMessage.Error] field is non-nil.
+// error if [jsonstream.Message.Error] is non-nil.
func Display(jm jsonstream.Message, out io.Writer, isTerminal bool, width uint16) error {
if jm.Error != nil {
return jm.Error
@@ -144,14 +157,28 @@ func Display(jm jsonstream.Message, out io.Writer, isTerminal bool, width uint16
return nil
}
-type JSONMessagesStream iter.Seq2[jsonstream.Message, error]
+type JSONMessagesStream = iter.Seq2[jsonstream.Message, error]
-// DisplayJSONMessagesStream reads a JSON message stream from in, and writes
-// each [JSONMessage] to out.
-// see DisplayJSONMessages for details
+// DisplayJSONMessagesStream is like [DisplayStream], but allows the caller to
+// explicitly provide the terminal file descriptor and whether out is a terminal.
func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool, auxCallback func(jsonstream.Message)) error {
+ var opts []DisplayOpt
+ if auxCallback != nil {
+ opts = append(opts, WithAuxCallback(auxCallback))
+ }
+ return displayJSONMessagesStream(in, out, terminalFd, isTerminal, opts...)
+}
+
+// DisplayStream reads a JSON message stream from in, and writes each
+// [jsonstream.Message] to out. See [DisplayMessages] for details.
+func DisplayStream(in io.Reader, out io.Writer, opts ...DisplayOpt) error {
+ terminalFd, isTerminal := term.GetFdInfo(out)
+ return displayJSONMessagesStream(in, out, terminalFd, isTerminal, opts...)
+}
+
+func displayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool, opts ...DisplayOpt) error {
dec := json.NewDecoder(in)
- var f JSONMessagesStream = func(yield func(jsonstream.Message, error) bool) {
+ f := func(yield func(jsonstream.Message, error) bool) {
for {
var jm jsonstream.Message
err := dec.Decode(&jm)
@@ -164,26 +191,48 @@ func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr,
}
}
- return DisplayJSONMessages(f, out, terminalFd, isTerminal, auxCallback)
+ return displayJSONMessages(f, out, terminalFd, isTerminal, opts...)
+}
+
+// DisplayJSONMessages is like [DisplayMessages], but allows the caller to
+// explicitly provide the terminal file descriptor and whether out is a terminal.
+func DisplayJSONMessages(messages iter.Seq2[jsonstream.Message, error], out io.Writer, terminalFd uintptr, isTerminal bool, auxCallback func(jsonstream.Message)) error {
+ var opts []DisplayOpt
+ if auxCallback != nil {
+ opts = append(opts, WithAuxCallback(auxCallback))
+ }
+ return displayJSONMessages(messages, out, terminalFd, isTerminal, opts...)
}
-// DisplayJSONMessages writes each [JSONMessage] from stream to out.
-// It returns an error if an invalid JSONMessage is received, or if
-// a JSONMessage containers a non-zero [JSONMessage.Error].
+// DisplayMessages writes each [jsonstream.Message] from stream to out.
+// It returns an error if an invalid [jsonstream.Message] is received, or if
+// a message contains a non-zero [jsonstream.Message.Error].
//
-// Presentation of the JSONMessage depends on whether a terminal is attached,
-// and on the terminal width. Progress bars ([JSONProgress]) are suppressed
-// on narrower terminals (< 110 characters).
+// Presentation of the message depends on whether out is a terminal, and on the
+// terminal width. Progress bars ([jsonstream.Progress]) are suppressed on
+// narrower terminals (< 110 characters). If out is a terminal, it prints a
+// newline ("\n") at the end of each line and moves the cursor while displaying.
//
-// - isTerminal describes if out is a terminal, in which case it prints
-// a newline ("\n") at the end of each line and moves the cursor while
-// displaying.
-// - terminalFd is the fd of the current terminal (if any), and used
-// to get the terminal width.
-// - auxCallback allows handling the [JSONMessage.Aux] field. It is
-// called if a JSONMessage contains an Aux field, in which case
-// DisplayJSONMessagesStream does not present the JSONMessage.
-func DisplayJSONMessages(messages JSONMessagesStream, out io.Writer, terminalFd uintptr, isTerminal bool, auxCallback func(jsonstream.Message)) error {
+// auxCallback allows handling the [jsonstream.Message.Aux] field. It is called
+// if a message contains an Aux field, in which case DisplayMessages does not
+// present the message.
+func DisplayMessages(messages iter.Seq2[jsonstream.Message, error], out io.Writer, opts ...DisplayOpt) error {
+ terminalFd, isTerminal := term.GetFdInfo(out)
+ return displayJSONMessages(messages, out, terminalFd, isTerminal, opts...)
+}
+
+func displayJSONMessages(messages iter.Seq2[jsonstream.Message, error], out io.Writer, terminalFd uintptr, isTerminal bool, opts ...DisplayOpt) error {
+ var cfg displayOpts
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if err := opt(&cfg); err != nil {
+ return err
+ }
+ }
+ auxCallback := cfg.auxCallback
+
ids := make(map[string]uint)
var width uint16 = 200
if isTerminal {
diff --git a/vendor/github.com/moby/moby/v2/AUTHORS b/vendor/github.com/moby/moby/v2/AUTHORS
deleted file mode 100644
index cb9bc376..00000000
--- a/vendor/github.com/moby/moby/v2/AUTHORS
+++ /dev/null
@@ -1,2516 +0,0 @@
-# File @generated by hack/generate-authors.sh. DO NOT EDIT.
-# This file lists all contributors to the repository.
-# See hack/generate-authors.sh to make modifications.
-
-17neverends
-7sunarni <710720732@qq.com>
-Aanand Prasad
-Aarni Koskela
-Aaron Davidson
-Aaron Feng
-Aaron Hnatiw
-Aaron Huslage
-Aaron L. Xu
-Aaron Lehmann
-Aaron Welch
-Aaron Yoshitake
-Abdur Rehman
-Abel Muiño
-Abhijeet Kasurde
-Abhinandan Prativadi
-Abhinav Ajgaonkar
-Abhishek Chanda
-Abhishek Sharma
-Abin Shahab
-Abirdcfly
-Abubacarr Ceesay
-Ada Mancini
-Adam Avilla
-Adam Dobrawy
-Adam Eijdenberg
-Adam Kunk
-Adam Lamers
-Adam Miller
-Adam Mills
-Adam Pointer
-Adam Simon
-Adam Singer
-Adam Thornton
-Adam Walz
-Adam Williams
-AdamKorcz
-Addam Hardy
-Aditi Rajagopal
-Aditya
-Adnan Khan
-Adolfo Ochagavía
-Adria Casas
-Adrian Moisey
-Adrian Mouat
-Adrian Oprea
-Adrien Folie
-Adrien Gallouët
-Adrien Pompée
-Ahmed Kamal
-Ahmet Alp Balkan
-Aidan Feldman
-Aidan Hobson Sayers
-AJ Bowen
-Ajey Charantimath
-ajneu
-Akash Gupta
-Akhil Mohan
-Akihiro Matsushima
-Akihiro Suda
-Akim Demaille
-Akira Koyasu
-Akshay Karle
-Akshay Moghe
-Al Tobey
-alambike
-Alan Hoyle
-Alan Scherger
-Alan Thompson
-Alano Terblanche
-Albert Callarisa
-Albert Zhang
-Albin Kerouanton
-Alec Benson
-Alejandro González Hevia
-Aleksa Sarai
-Aleksandr Chebotov
-Aleksandrs Fadins
-Alena Prokharchyk
-Alessandro Boch
-Alessio Biancalana
-Alessio Perugini
-Alex Chan
-Alex Chen
-Alex Coventry
-Alex Crawford
-Alex Ellis
-Alex Gaynor
-Alex Goodman
-Alex Nordlund
-Alex Olshansky
-Alex Samorukov
-Alex Stockinger
-Alex Warhawk
-Alexander Artemenko
-Alexander Boyd
-Alexander Larsson
-Alexander Midlash
-Alexander Morozov
-Alexander Polakov
-Alexander Shopov
-Alexandre Beslic
-Alexandre Garnier
-Alexandre González
-Alexandre Jomin
-Alexandru Sfirlogea
-Alexei Margasov
-Alexey Guskov
-Alexey Kotlyarov
-Alexey Shamrin
-Alexis Ries
-Alexis Thomas
-Alfred Landrum
-Ali Dehghani
-Alicia Lauerman
-Alihan Demir
-Allen Madsen
-Allen Sun
-almoehi
-Alvaro Saurin
-Alvin Deng
-Alvin Richards
-amangoel
-Amen Belayneh
-Ameya Gawde
-Amir Goldstein
-AmirBuddy
-Amit Bakshi
-Amit Krishnan
-Amit Shukla
-Amr Gawish
-Amy Lindburg
-Anand Patil
-AnandkumarPatel
-Anatoly Borodin
-Anca Iordache
-Anchal Agrawal
-Anda Xu
-Anders Janmyr
-Andre Dublin <81dublin@gmail.com>
-Andre Granovsky
-Andrea Denisse Gómez
-Andrea Luzzardi
-Andrea Turli
-Andreas Elvers
-Andreas Köhler
-Andreas Savvides
-Andreas Tiefenthaler
-Andrei Gherzan
-Andrei Ushakov
-Andrei Vagin
-Andrew Baxter <423qpsxzhh8k3h@s.rendaw.me>
-Andrew C. Bodine
-Andrew Clay Shafer
-Andrew Duckworth
-Andrew France
-Andrew Gerrand
-Andrew Guenther
-Andrew He
-Andrew Hsu
-Andrew Kim
-Andrew Kuklewicz
-Andrew Macgregor
-Andrew Macpherson
-Andrew Martin
-Andrew McDonnell
-Andrew Munsell
-Andrew Pennebaker
-Andrew Po
-Andrew Weiss
-Andrew Williams
-Andrews Medina
-Andrey Epifanov
-Andrey Kolomentsev
-Andrey Petrov
-Andrey Stolbovsky
-André Martins
-Andrés Maldonado
-Andy Chambers
-andy diller
-Andy Goldstein
-Andy Kipp
-Andy Lindeman
-Andy Rothfusz
-Andy Smith
-Andy Wilson
-Andy Zhang
-Aneesh Kulkarni
-Anes Hasicic
-Angel Velazquez
-Anil Belur
-Anil Madhavapeddy
-Anirudh Aithal
-Ankit Jain
-Ankush Agarwal
-Anonmily
-Anran Qiao
-Anshul Pundir
-Anthon van der Neut
-Anthony Baire
-Anthony Bishopric
-Anthony Dahanne
-Anthony Nandaa
-Anthony Sottile
-Anton Löfgren
-Anton Nikitin
-Anton Polonskiy
-Anton Tiurin
-Antonio Aguilar
-Antonio Murdaca
-Antonis Kalipetis
-Antony Messerli
-Anuj Bahuguna
-Anuj Varma
-Anusha Ragunathan
-Anyu Wang
-apocas
-Arash Deshmeh
-arcosx
-ArikaChen
-Arko Dasgupta
-Arnaud Lefebvre
-Arnaud Porterie
-Arnaud Rebillout
-Artem Khramov
-Arthur Barr
-Arthur Gautier
-Artur Meyster
-Arun Gupta
-Asad Saeeduddin
-Asbjørn Enge
-Ashly Mathew
-Austin Vazquez
-averagehuman
-Avi Das
-Avi Kivity
-Avi Miller
-Avi Vaid
-Azat Khuyiyakhmetov
-Bao Yonglei
-Bardia Keyoumarsi
-Barnaby Gray
-Barry Allard
-Bartłomiej Piotrowski
-Bastiaan Bakker
-Bastien Pascard
-bdevloed
-Bearice Ren
-Ben Bonnefoy
-Ben Firshman
-Ben Golub
-Ben Gould