New Upstream Release - golang-github-tonistiigi-fsutil

Ready changes

Summary

Merged new upstream version: 0.0~git20220930.4638ad6 (was: 0.0~git20200331.f427cf1).

Resulting package

Built on 2022-11-09T16:19 (took 12m6s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases golang-github-tonistiigi-fsutil-dev

Lintian Result

Diff

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..b1bff2e
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,97 @@
+name: ci
+
+on:
+  schedule:
+    - cron: '0 8 */6 * *' # every 6 days
+  push:
+    branches:
+      - master
+      - gh_test_ci
+  pull_request:
+    branches:
+      - master
+
+jobs:
+  test:
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        GO_VERSION: ["1.18", "1.19"]
+    env:
+      GO_VERSION: ${{ matrix.GO_VERSION }}
+    steps:
+      -
+         name: Set up Docker Buildx
+         uses: docker/setup-buildx-action@v1
+      -
+        name: Checkout
+        uses: actions/checkout@v2
+      -
+        name: Build
+        run: |
+          docker buildx bake
+      -
+        name: Test
+        run: |
+          docker buildx bake test
+      -
+        name: Linters
+        run: |
+          docker buildx bake lint validate-gomod validate-shfmt
+      -
+        name: Cross
+        run: |
+          docker buildx bake cross
+
+  test-macos:
+    runs-on: macos-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        go:
+          - 1.18
+          - 1.19
+    steps:
+      -
+        name: Checkout
+        uses: actions/checkout@v2
+      -
+        name: Set up Go
+        uses: actions/setup-go@v2
+        with:
+          go-version: ${{ matrix.go }}
+      -
+        name: Cache Go modules
+        uses: actions/cache@v2
+        with:
+          path: ~/go/pkg/mod
+          key: ${{ runner.os }}-go-${{ matrix.go }}-${{ hashFiles('**/go.sum') }}
+          restore-keys: |
+            ${{ runner.os }}-go-${{ matrix.go }}-
+      -
+        name: Test
+        run: |
+          go test ./...
+
+  test-freebsd-amd64:
+    runs-on: macos-10.15
+    env:
+      VAGRANT_VAGRANTFILE: hack/Vagrantfile.freebsd13
+    steps:
+      -
+        name: Checkout
+        uses: actions/checkout@v2
+      -
+        name: Cache Vagrant boxes
+        uses: actions/cache@v2
+        with:
+          path: ~/.vagrant.d/boxes
+          key: ${{ runner.os }}-vagrant-${{ hashFiles('hack/Vagrantfile.freebsd13') }}
+          restore-keys: |
+            ${{ runner.os }}-vagrant-
+      -
+        name: Set up vagrant
+        run: vagrant up
+      -
+        name: Test
+        run: vagrant ssh -- "cd /vagrant; go test -buildvcs=false ./..."
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..51b9602
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+# if you want to ignore files created by your editor/tools, consider using a
+# global .gitignore or .git/info/exclude see https://help.github.com/articles/ignoring-files
+.*
+!.github
+!.gitignore
+!.travis.yml
+*.prof
+# support running go modules in vendor mode for local development
+vendor/
diff --git a/.golangci.yml b/.golangci.yml
new file mode 100644
index 0000000..788dfd5
--- /dev/null
+++ b/.golangci.yml
@@ -0,0 +1,20 @@
+run:
+  timeout: 10m
+  skip-files:
+    - ".*\\.pb\\.go$"
+
+linters:
+  enable:
+    - gofmt
+    - govet
+    - deadcode
+    - goimports
+    - ineffassign
+    - misspell
+    - unused
+    - varcheck
+    - golint
+    - staticcheck
+    - typecheck
+    - structcheck
+  disable-all: true
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 4109d9c..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-dist: trusty
-sudo: required
-
-services:
-  - docker
-
-language: go
-
-go: 
- - "1.12.x"
-
-install:
- - export GO111MODULE=on
-
-script:
- - go build ./...
- - go test -c -o test ./
- - sudo ./test -test.v
- - go test -c -o test ./copy
- - sudo ./test -test.v
- - GOOS=darwin go build ./...
- - GOOS=windows go build ./...
- - GOARCH=arm GOARM=7 go build ./...
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..252b497
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,30 @@
+#syntax=docker/dockerfile:1
+ARG GO_VERSION=1.18
+
+FROM --platform=$BUILDPLATFORM tonistiigi/xx:1.1.0 AS xx
+
+FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine AS base
+RUN apk add --no-cache git
+COPY --from=xx / /
+WORKDIR /src
+
+FROM base AS build
+ARG TARGETPLATFORM
+RUN --mount=target=. --mount=target=/go/pkg/mod,type=cache \
+    --mount=target=/root/.cache,type=cache \
+    xx-go build ./...
+
+FROM base AS test
+ARG TESTFLAGS
+RUN --mount=target=. --mount=target=/go/pkg/mod,type=cache \
+    --mount=target=/root/.cache,type=cache \
+    CGO_ENABLED=0 xx-go test -test.v ${TESTFLAGS} ./...
+
+FROM base AS test-noroot
+RUN mkdir /go/pkg && chmod 0777 /go/pkg
+USER 1000:1000
+RUN --mount=target=. \
+    --mount=target=/tmp/.cache,type=cache \
+    CGO_ENABLED=0 GOCACHE=/tmp/gocache xx-go test -test.v ./...
+
+FROM build
diff --git a/bench/bench_test.go b/bench/bench_test.go
index b63b2e6..1130e20 100644
--- a/bench/bench_test.go
+++ b/bench/bench_test.go
@@ -1,14 +1,12 @@
 package bench
 
 import (
-	"io/ioutil"
 	"os"
 	"os/exec"
 	"testing"
 
 	"github.com/containerd/continuity"
 	"github.com/docker/docker/pkg/archive"
-	"github.com/docker/docker/pkg/chrootarchive"
 	"github.com/docker/docker/pkg/reexec"
 )
 
@@ -25,7 +23,7 @@ func benchmarkInitialCopy(b *testing.B, fn func(string, string) error, size int)
 		if err != nil {
 			b.Error(err)
 		}
-		destdir, err := ioutil.TempDir(baseDir, "destdir")
+		destdir, err := os.MkdirTemp(baseDir, "destdir")
 		if err != nil {
 			os.RemoveAll(tmpdir)
 			b.Error(err)
@@ -71,7 +69,7 @@ func benchmarkIncrementalCopy(b *testing.B, fn func(string, string) error, size
 	if err != nil {
 		b.Error(err)
 	}
-	destdir, err := ioutil.TempDir(baseDir, "destdir")
+	destdir, err := os.MkdirTemp(baseDir, "destdir")
 	if err != nil {
 		os.RemoveAll(tmpdir)
 		b.Error(err)
@@ -120,10 +118,6 @@ func copyWithTar(src, dest string) error {
 	return archive.NewDefaultArchiver().CopyWithTar(src, dest)
 }
 
-func chrootCopyWithTar(src, dest string) error {
-	return chrootarchive.NewArchiver(nil).CopyWithTar(src, dest)
-}
-
 func cpa(src, dest string) error {
 	cmd := exec.Command("cp", "-a", src+"/.", dest)
 	return cmd.Run()
@@ -162,6 +156,9 @@ func BenchmarkCopyWithTar1000(b *testing.B) {
 	benchmarkInitialCopy(b, copyWithTar, 1000)
 }
 
+// func chrootCopyWithTar(src, dest string) error {
+// 	return chrootarchive.NewArchiver(nil).CopyWithTar(src, dest)
+// }
 // func BenchmarkChrootCopyWithTar10(b *testing.B) {
 //   benchmarkInitialCopy(b, chrootCopyWithTar, 10)
 // }
diff --git a/bench/go.mod b/bench/go.mod
new file mode 100644
index 0000000..62d0af8
--- /dev/null
+++ b/bench/go.mod
@@ -0,0 +1,33 @@
+module github.com/tonistiigi/fsutil/bench
+
+go 1.18
+
+require (
+	github.com/containerd/continuity v0.3.0
+	github.com/docker/docker v20.10.18+incompatible
+	github.com/pkg/errors v0.9.1
+	github.com/tonistiigi/fsutil v0.0.0-00010101000000-000000000000
+	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
+)
+
+require (
+	github.com/Microsoft/go-winio v0.5.2 // indirect
+	github.com/Microsoft/hcsshim v0.8.17 // indirect
+	github.com/containerd/cgroups v1.0.1 // indirect
+	github.com/containerd/containerd v1.5.2 // indirect
+	github.com/docker/go-units v0.4.0 // indirect
+	github.com/gogo/protobuf v1.3.2 // indirect
+	github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
+	github.com/moby/patternmatcher v0.5.0 // indirect
+	github.com/moby/sys/mount v0.2.0 // indirect
+	github.com/moby/sys/mountinfo v0.4.1 // indirect
+	github.com/opencontainers/go-digest v1.0.0 // indirect
+	github.com/opencontainers/image-spec v1.0.1 // indirect
+	github.com/opencontainers/runc v1.0.0-rc93 // indirect
+	github.com/sirupsen/logrus v1.8.1 // indirect
+	go.opencensus.io v0.22.3 // indirect
+	golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
+	google.golang.org/protobuf v1.26.0 // indirect
+)
+
+replace github.com/tonistiigi/fsutil => ../
diff --git a/bench/go.sum b/bench/go.sum
new file mode 100644
index 0000000..d124a29
--- /dev/null
+++ b/bench/go.sum
@@ -0,0 +1,935 @@
+bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
+github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw=
+github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg=
+github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
+github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
+github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
+github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
+github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
+github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
+github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
+github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
+github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
+github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
+github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
+github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
+github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
+github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
+github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
+github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8=
+github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
+github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
+github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
+github.com/Microsoft/hcsshim v0.8.17 h1:yFHH5bghP9ij5Y34PPaMOE8g//oXZ0uJQeMENVo2zcI=
+github.com/Microsoft/hcsshim v0.8.17/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
+github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
+github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
+github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
+github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
+github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
+github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
+github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
+github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
+github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
+github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
+github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc=
+github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
+github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
+github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
+github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU=
+github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
+github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
+github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E=
+github.com/containerd/btrfs v0.0.0-20210316141732-918d888fb676/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss=
+github.com/containerd/btrfs v1.0.0/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss=
+github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI=
+github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
+github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
+github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
+github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
+github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
+github.com/containerd/cgroups v1.0.1 h1:iJnMvco9XGvKUvNQkv88bE4uJXxRQH18efbKo9w5vHQ=
+github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU=
+github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
+github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
+github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
+github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw=
+github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ=
+github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ=
+github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU=
+github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI=
+github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s=
+github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
+github.com/containerd/containerd v1.5.2 h1:MG/Bg1pbmMb61j3wHCFWPxESXHieiKr2xG64px/k8zQ=
+github.com/containerd/containerd v1.5.2/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
+github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
+github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
+github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
+github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo=
+github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y=
+github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ=
+github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM=
+github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg=
+github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM=
+github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
+github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
+github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0=
+github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0=
+github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4=
+github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4=
+github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU=
+github.com/containerd/go-cni v1.0.2/go.mod h1:nrNABBHzu0ZwCug9Ije8hL2xBCYh/pjfMb1aZGrrohk=
+github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
+github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
+github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g=
+github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok=
+github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok=
+github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0=
+github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA=
+github.com/containerd/imgcrypt v1.1.1-0.20210312161619-7ed62a527887/go.mod h1:5AZJNI6sLHJljKuI9IHnw1pWqo/F0nGDOuR9zgTs7ow=
+github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJrXQb0Dpc4ms=
+github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c=
+github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
+github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
+github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
+github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
+github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8=
+github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
+github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
+github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
+github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk=
+github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg=
+github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s=
+github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw=
+github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y=
+github.com/containerd/zfs v0.0.0-20210315114300-dde8f0fda960/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY=
+github.com/containerd/zfs v0.0.0-20210324211415-d5c4544f0433/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY=
+github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY=
+github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
+github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
+github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
+github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM=
+github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8=
+github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc=
+github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4=
+github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY=
+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
+github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
+github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
+github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
+github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
+github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
+github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
+github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8=
+github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
+github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
+github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
+github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/docker v20.10.18+incompatible h1:SN84VYXTBNGn92T/QwIRPlum9zfemfitN7pbsp26WSc=
+github.com/docker/docker v20.10.18+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
+github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
+github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
+github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
+github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
+github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
+github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
+github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
+github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
+github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
+github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
+github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
+github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
+github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
+github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
+github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
+github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
+github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
+github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
+github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
+github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
+github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU=
+github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
+github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
+github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
+github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
+github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
+github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
+github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo=
+github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
+github.com/moby/sys/mount v0.2.0 h1:WhCW5B355jtxndN5ovugJlMFJawbUODuW8fSnEH6SSM=
+github.com/moby/sys/mount v0.2.0/go.mod h1:aAivFE2LB3W4bACsUXChRHQ0qKWsetY4Y9V7sxOougM=
+github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
+github.com/moby/sys/mountinfo v0.4.1 h1:1O+1cHA1aujwEwwVMa2Xm2l+gIpUHyd3+D+d7LZh1kM=
+github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
+github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ=
+github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
+github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
+github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
+github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
+github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
+github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+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.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
+github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v1.0.0-rc93 h1:x2UMpOOVf3kQ8arv/EsDGwim8PTNqzL1/EYDr/+scOM=
+github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
+github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
+github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
+github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
+github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+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.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
+github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
+github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
+github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
+github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
+github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
+github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
+github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
+github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8=
+github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
+github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
+github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
+github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
+github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
+github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
+github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
+github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
+github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
+github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
+github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
+github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
+github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
+github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
+go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
+go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
+golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
+gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
+gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
+gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
+gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo=
+k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ=
+k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8=
+k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
+k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
+k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc=
+k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU=
+k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM=
+k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q=
+k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y=
+k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k=
+k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0=
+k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk=
+k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI=
+k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM=
+k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM=
+k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI=
+k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI=
+k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc=
+k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
+k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
+k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
+k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM=
+k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
+k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
+sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
+sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
+sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
+sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
diff --git a/bench/util.go b/bench/util.go
index 782693a..17e39a4 100644
--- a/bench/util.go
+++ b/bench/util.go
@@ -4,7 +4,6 @@ import (
 	"crypto/rand"
 	"encoding/hex"
 	"errors"
-	"io/ioutil"
 	"math"
 	mathrand "math/rand"
 	"os"
@@ -15,7 +14,7 @@ import (
 
 func createTestDir(n int) (string, error) {
 	const nesting = 1.0 / 3.0
-	rootDir, err := ioutil.TempDir(os.Getenv("BENCH_BASE_DIR"), "diffcopy")
+	rootDir, err := os.MkdirTemp(os.Getenv("BENCH_BASE_DIR"), "diffcopy")
 	if err != nil {
 		return "", err
 	}
diff --git a/chtimes_linux.go b/chtimes_linux.go
index 74f08a1..dd65a49 100644
--- a/chtimes_linux.go
+++ b/chtimes_linux.go
@@ -1,3 +1,4 @@
+//go:build linux
 // +build linux
 
 package fsutil
diff --git a/chtimes_nolinux.go b/chtimes_nolinux.go
index cdd80ec..a3ba098 100644
--- a/chtimes_nolinux.go
+++ b/chtimes_nolinux.go
@@ -5,16 +5,18 @@ package fsutil
 import (
 	"os"
 	"time"
+
+	"github.com/pkg/errors"
 )
 
 func chtimes(path string, un int64) error {
 	mtime := time.Unix(0, un)
 	fi, err := os.Lstat(path)
 	if err != nil {
-		return err
+		return errors.WithStack(err)
 	}
 	if fi.Mode()&os.ModeSymlink != 0 {
 		return nil
 	}
-	return os.Chtimes(path, mtime, mtime)
+	return errors.WithStack(os.Chtimes(path, mtime, mtime))
 }
diff --git a/cmd/walk/walk.go b/cmd/walk/walk.go
index 6f6dd37..2b4311a 100644
--- a/cmd/walk/walk.go
+++ b/cmd/walk/walk.go
@@ -3,7 +3,6 @@ package main
 import (
 	"context"
 	"flag"
-	"io/ioutil"
 	"os"
 	"strings"
 
@@ -19,7 +18,7 @@ func main() {
 	var excludes []string
 
 	if len(flag.Args()) > 1 {
-		dt, err := ioutil.ReadFile(flag.Args()[1])
+		dt, err := os.ReadFile(flag.Args()[1])
 		if err != nil {
 			panic(err)
 		}
diff --git a/copy/copy.go b/copy/copy.go
index 27b7d56..75586bc 100644
--- a/copy/copy.go
+++ b/copy/copy.go
@@ -2,8 +2,8 @@ package fs
 
 import (
 	"context"
-	"io/ioutil"
 	"os"
+	"path"
 	"path/filepath"
 	"runtime"
 	"strings"
@@ -11,7 +11,9 @@ import (
 	"time"
 
 	"github.com/containerd/continuity/fs"
+	"github.com/moby/patternmatcher"
 	"github.com/pkg/errors"
+	"github.com/tonistiigi/fsutil"
 )
 
 var bufferPool = &sync.Pool{
@@ -86,7 +88,10 @@ func Copy(ctx context.Context, srcRoot, src, dstRoot, dst string, opts ...Opt) e
 		return err
 	}
 
-	c := newCopier(ci.Chown, ci.Utime, ci.Mode, ci.XAttrErrorHandler)
+	c, err := newCopier(dstRoot, ci.Chown, ci.Utime, ci.Mode, ci.XAttrErrorHandler, ci.IncludePatterns, ci.ExcludePatterns, ci.ChangeFunc)
+	if err != nil {
+		return err
+	}
 	srcs := []string{src}
 
 	if ci.AllowWildcards {
@@ -109,7 +114,7 @@ func Copy(ctx context.Context, srcRoot, src, dstRoot, dst string, opts ...Opt) e
 		if err != nil {
 			return err
 		}
-		if err := c.copy(ctx, srcFollowed, dst, false); err != nil {
+		if err := c.copy(ctx, srcFollowed, "", dst, false, patternmatcher.MatchInfo{}, patternmatcher.MatchInfo{}); err != nil {
 			return err
 		}
 	}
@@ -147,7 +152,7 @@ func (c *copier) prepareTargetDir(srcFollowed, src, destPath string, copyDirCont
 }
 
 type User struct {
-	Uid, Gid int
+	UID, GID int
 }
 
 type Chowner func(*User) (*User, error)
@@ -162,6 +167,11 @@ type CopyInfo struct {
 	XAttrErrorHandler XAttrErrorHandler
 	CopyDirContents   bool
 	FollowLinks       bool
+	// Include only files/dirs matching at least one of these patterns
+	IncludePatterns []string
+	// Exclude files/dir matching any of these patterns (even if they match an include pattern)
+	ExcludePatterns []string
+	ChangeFunc      fsutil.ChangeFunc
 }
 
 type Opt func(*CopyInfo)
@@ -175,7 +185,7 @@ func WithCopyInfo(ci CopyInfo) func(*CopyInfo) {
 func WithChown(uid, gid int) Opt {
 	return func(ci *CopyInfo) {
 		ci.Chown = func(*User) (*User, error) {
-			return &User{Uid: uid, Gid: gid}, nil
+			return &User{UID: uid, GID: gid}, nil
 		}
 	}
 }
@@ -197,50 +207,149 @@ func AllowXAttrErrors(ci *CopyInfo) {
 	WithXAttrErrorHandler(h)(ci)
 }
 
+func WithIncludePattern(includePattern string) Opt {
+	return func(ci *CopyInfo) {
+		ci.IncludePatterns = append(ci.IncludePatterns, includePattern)
+	}
+}
+
+func WithExcludePattern(excludePattern string) Opt {
+	return func(ci *CopyInfo) {
+		ci.ExcludePatterns = append(ci.ExcludePatterns, excludePattern)
+	}
+}
+
+func WithChangeNotifier(fn fsutil.ChangeFunc) Opt {
+	return func(ci *CopyInfo) {
+		ci.ChangeFunc = fn
+	}
+}
+
 type copier struct {
-	chown             Chowner
-	utime             *time.Time
-	mode              *int
-	inodes            map[uint64]string
-	xattrErrorHandler XAttrErrorHandler
+	chown                 Chowner
+	utime                 *time.Time
+	mode                  *int
+	inodes                map[uint64]string
+	xattrErrorHandler     XAttrErrorHandler
+	includePatternMatcher *patternmatcher.PatternMatcher
+	excludePatternMatcher *patternmatcher.PatternMatcher
+	parentDirs            []parentDir
+	changefn              fsutil.ChangeFunc
+	root                  string
 }
 
-func newCopier(chown Chowner, tm *time.Time, mode *int, xeh XAttrErrorHandler) *copier {
+type parentDir struct {
+	srcPath string
+	dstPath string
+	copied  bool
+}
+
+func newCopier(root string, chown Chowner, tm *time.Time, mode *int, xeh XAttrErrorHandler, includePatterns, excludePatterns []string, changeFunc fsutil.ChangeFunc) (*copier, error) {
 	if xeh == nil {
 		xeh = func(dst, src, key string, err error) error {
 			return err
 		}
 	}
-	return &copier{inodes: map[uint64]string{}, chown: chown, utime: tm, xattrErrorHandler: xeh, mode: mode}
+
+	var includePatternMatcher *patternmatcher.PatternMatcher
+	if len(includePatterns) != 0 {
+		var err error
+		includePatternMatcher, err = patternmatcher.New(includePatterns)
+		if err != nil {
+			return nil, errors.Wrapf(err, "invalid includepatterns: %s", includePatterns)
+		}
+	}
+
+	var excludePatternMatcher *patternmatcher.PatternMatcher
+	if len(excludePatterns) != 0 {
+		var err error
+		excludePatternMatcher, err = patternmatcher.New(excludePatterns)
+		if err != nil {
+			return nil, errors.Wrapf(err, "invalid excludepatterns: %s", excludePatterns)
+		}
+	}
+
+	return &copier{
+		root:                  root,
+		inodes:                map[uint64]string{},
+		chown:                 chown,
+		utime:                 tm,
+		xattrErrorHandler:     xeh,
+		mode:                  mode,
+		includePatternMatcher: includePatternMatcher,
+		excludePatternMatcher: excludePatternMatcher,
+		changefn:              changeFunc,
+	}, nil
 }
 
 // dest is always clean
-func (c *copier) copy(ctx context.Context, src, target string, overwriteTargetMetadata bool) error {
+func (c *copier) copy(ctx context.Context, src, srcComponents, target string, overwriteTargetMetadata bool, parentIncludeMatchInfo, parentExcludeMatchInfo patternmatcher.MatchInfo) error {
 	select {
 	case <-ctx.Done():
 		return ctx.Err()
 	default:
 	}
+
 	fi, err := os.Lstat(src)
 	if err != nil {
 		return errors.Wrapf(err, "failed to stat %s", src)
 	}
 
+	include := true
+	var (
+		includeMatchInfo patternmatcher.MatchInfo
+		excludeMatchInfo patternmatcher.MatchInfo
+	)
+	if srcComponents != "" {
+		matchesIncludePattern := false
+		matchesExcludePattern := false
+		matchesIncludePattern, includeMatchInfo, err = c.include(srcComponents, fi, parentIncludeMatchInfo)
+		if err != nil {
+			return err
+		}
+		include = matchesIncludePattern
+
+		matchesExcludePattern, excludeMatchInfo, err = c.exclude(srcComponents, fi, parentExcludeMatchInfo)
+		if err != nil {
+			return err
+		}
+		if matchesExcludePattern {
+			include = false
+		}
+	}
+
+	if include {
+		if err := c.createParentDirs(src, srcComponents, target, overwriteTargetMetadata); err != nil {
+			return err
+		}
+	}
+
 	if !fi.IsDir() {
+		if !include {
+			return nil
+		}
+
 		if err := ensureEmptyFileTarget(target); err != nil {
 			return err
 		}
 	}
 
-	copyFileInfo := true
+	copyFileInfo := include
+	notify := true
 
 	switch {
 	case fi.IsDir():
-		if created, err := c.copyDirectory(ctx, src, target, fi, overwriteTargetMetadata); err != nil {
+		if created, err := c.copyDirectory(
+			ctx, src, srcComponents, target, fi, overwriteTargetMetadata,
+			include, includeMatchInfo, excludeMatchInfo,
+		); err != nil {
 			return err
 		} else if !overwriteTargetMetadata {
+			// if we aren't supposed to overwrite existing target metadata,
+			// then we only need to copy file info if we newly created it
 			copyFileInfo = created
 		}
+		notify = false
 	case (fi.Mode() & os.ModeType) == 0:
 		link, err := getLinkSource(target, fi, c.inodes)
 		if err != nil {
@@ -261,13 +370,12 @@ func (c *copier) copy(ctx context.Context, src, target string, overwriteTargetMe
 		if err := os.Symlink(link, target); err != nil {
 			return errors.Wrapf(err, "failed to create symlink: %s", target)
 		}
-	case (fi.Mode() & os.ModeDevice) == os.ModeDevice:
+	case (fi.Mode() & os.ModeDevice) == os.ModeDevice,
+		(fi.Mode() & os.ModeNamedPipe) == os.ModeNamedPipe,
+		(fi.Mode() & os.ModeSocket) == os.ModeSocket:
 		if err := copyDevice(target, fi); err != nil {
 			return errors.Wrapf(err, "failed to create device")
 		}
-	default:
-		// TODO: Support pipes and sockets
-		return errors.Wrapf(err, "unsupported mode %s", fi.Mode())
 	}
 
 	if copyFileInfo {
@@ -279,39 +387,140 @@ func (c *copier) copy(ctx context.Context, src, target string, overwriteTargetMe
 			return errors.Wrap(err, "failed to copy xattrs")
 		}
 	}
+	if notify {
+		if err := c.notifyChange(target, fi); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (c *copier) notifyChange(target string, fi os.FileInfo) error {
+	if c.changefn != nil {
+		if err := c.changefn(fsutil.ChangeKindAdd, path.Clean(strings.TrimPrefix(target, c.root)), fi, nil); err != nil {
+			return errors.Wrap(err, "failed to notify file change")
+		}
+	}
+	return nil
+}
+
+func (c *copier) include(path string, fi os.FileInfo, parentIncludeMatchInfo patternmatcher.MatchInfo) (bool, patternmatcher.MatchInfo, error) {
+	if c.includePatternMatcher == nil {
+		return true, patternmatcher.MatchInfo{}, nil
+	}
+
+	m, matchInfo, err := c.includePatternMatcher.MatchesUsingParentResults(path, parentIncludeMatchInfo)
+	if err != nil {
+		return false, matchInfo, errors.Wrap(err, "failed to match includepatterns")
+	}
+	return m, matchInfo, nil
+}
+
+func (c *copier) exclude(path string, fi os.FileInfo, parentExcludeMatchInfo patternmatcher.MatchInfo) (bool, patternmatcher.MatchInfo, error) {
+	if c.excludePatternMatcher == nil {
+		return false, patternmatcher.MatchInfo{}, nil
+	}
+
+	m, matchInfo, err := c.excludePatternMatcher.MatchesUsingParentResults(path, parentExcludeMatchInfo)
+	if err != nil {
+		return false, matchInfo, errors.Wrap(err, "failed to match excludepatterns")
+	}
+	return m, matchInfo, nil
+}
+
+// Delayed creation of parent directories when a file or dir matches an include
+// pattern.
+func (c *copier) createParentDirs(src, srcComponents, target string, overwriteTargetMetadata bool) error {
+	for i, parentDir := range c.parentDirs {
+		if parentDir.copied {
+			continue
+		}
+
+		fi, err := os.Stat(parentDir.srcPath)
+		if err != nil {
+			return errors.Wrapf(err, "failed to stat %s", src)
+		}
+		if !fi.IsDir() {
+			return errors.Errorf("%s is not a directory", parentDir.srcPath)
+		}
+
+		created, err := copyDirectoryOnly(parentDir.srcPath, parentDir.dstPath, fi, overwriteTargetMetadata)
+		if err != nil {
+			return err
+		}
+		if created {
+			if err := c.copyFileInfo(fi, parentDir.dstPath); err != nil {
+				return errors.Wrap(err, "failed to copy file info")
+			}
+
+			if err := copyXAttrs(parentDir.dstPath, parentDir.srcPath, c.xattrErrorHandler); err != nil {
+				return errors.Wrap(err, "failed to copy xattrs")
+			}
+		}
+
+		c.parentDirs[i].copied = true
+	}
 	return nil
 }
 
-func (c *copier) copyDirectory(ctx context.Context, src, dst string, stat os.FileInfo, overwriteTargetMetadata bool) (bool, error) {
+func (c *copier) copyDirectory(
+	ctx context.Context,
+	src string,
+	srcComponents string,
+	dst string,
+	stat os.FileInfo,
+	overwriteTargetMetadata bool,
+	include bool,
+	includeMatchInfo patternmatcher.MatchInfo,
+	excludeMatchInfo patternmatcher.MatchInfo,
+) (bool, error) {
 	if !stat.IsDir() {
 		return false, errors.Errorf("source is not directory")
 	}
 
 	created := false
 
-	if st, err := os.Lstat(dst); err != nil {
-		if !os.IsNotExist(err) {
-			return false, err
-		}
-		created = true
-		if err := os.Mkdir(dst, stat.Mode()); err != nil {
-			return created, errors.Wrapf(err, "failed to mkdir %s", dst)
+	parentDir := parentDir{
+		srcPath: src,
+		dstPath: dst,
+	}
+
+	// If this directory passed include/exclude matching directly, go ahead
+	// and create the directory. Otherwise, delay to handle include
+	// patterns like a/*/c where we do not want to create a/b until we
+	// encounter a/b/c.
+	if include {
+		var err error
+		created, err = copyDirectoryOnly(src, dst, stat, overwriteTargetMetadata)
+		if err != nil {
+			return created, err
 		}
-	} else if !st.IsDir() {
-		return false, errors.Errorf("cannot copy to non-directory: %s", dst)
-	} else if overwriteTargetMetadata {
-		if err := os.Chmod(dst, stat.Mode()); err != nil {
-			return false, errors.Wrapf(err, "failed to chmod on %s", dst)
+		if created || overwriteTargetMetadata {
+			if err := c.notifyChange(dst, stat); err != nil {
+				return created, err
+			}
 		}
+		parentDir.copied = true
 	}
 
-	fis, err := ioutil.ReadDir(src)
+	c.parentDirs = append(c.parentDirs, parentDir)
+
+	defer func() {
+		c.parentDirs = c.parentDirs[:len(c.parentDirs)-1]
+	}()
+
+	fis, err := os.ReadDir(src)
 	if err != nil {
 		return false, errors.Wrapf(err, "failed to read %s", src)
 	}
 
 	for _, fi := range fis {
-		if err := c.copy(ctx, filepath.Join(src, fi.Name()), filepath.Join(dst, fi.Name()), true); err != nil {
+		if err := c.copy(
+			ctx,
+			filepath.Join(src, fi.Name()), filepath.Join(srcComponents, fi.Name()),
+			filepath.Join(dst, fi.Name()),
+			true, includeMatchInfo, excludeMatchInfo,
+		); err != nil {
 			return false, err
 		}
 	}
@@ -319,6 +528,25 @@ func (c *copier) copyDirectory(ctx context.Context, src, dst string, stat os.Fil
 	return created, nil
 }
 
+func copyDirectoryOnly(src, dst string, stat os.FileInfo, overwriteTargetMetadata bool) (bool, error) {
+	if st, err := os.Lstat(dst); err != nil {
+		if !os.IsNotExist(err) {
+			return false, err
+		}
+		if err := os.Mkdir(dst, stat.Mode()); err != nil {
+			return false, errors.Wrapf(err, "failed to mkdir %s", dst)
+		}
+		return true, nil
+	} else if !st.IsDir() {
+		return false, errors.Errorf("cannot copy to non-directory: %s", dst)
+	} else if overwriteTargetMetadata {
+		if err := os.Chmod(dst, stat.Mode()); err != nil {
+			return false, errors.Wrapf(err, "failed to chmod on %s", dst)
+		}
+	}
+	return false, nil
+}
+
 func ensureEmptyFileTarget(dst string) error {
 	fi, err := os.Lstat(dst)
 	if err != nil {
diff --git a/copy/copy_darwin.go b/copy/copy_darwin.go
index 2882dfd..bc93b21 100644
--- a/copy/copy_darwin.go
+++ b/copy/copy_darwin.go
@@ -1,3 +1,4 @@
+//go:build darwin
 // +build darwin
 
 package fs
@@ -5,21 +6,13 @@ package fs
 import (
 	"io"
 	"os"
-	"syscall"
-	"unsafe"
 
 	"github.com/pkg/errors"
 	"golang.org/x/sys/unix"
 )
 
-// <sys/clonefile.h
-// int clonefileat(int, const char *, int, const char *, uint32_t) __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0);
-
-const CLONE_NOFOLLOW = 0x0001    /* Don't follow symbolic links */
-const CLONE_NOOWNERCOPY = 0x0002 /* Don't copy ownership information from */
-
 func copyFile(source, target string) error {
-	if err := clonefile(source, target); err != nil {
+	if err := unix.Clonefileat(unix.AT_FDCWD, source, unix.AT_FDCWD, target, unix.CLONE_NOFOLLOW); err != nil {
 		if err != unix.EINVAL {
 			return err
 		}
@@ -49,36 +42,6 @@ func copyFileContent(dst, src *os.File) error {
 	return err
 }
 
-// errnoErr returns common boxed Errno values, to prevent
-// allocations at runtime.
-func errnoErr(e syscall.Errno) error {
-	switch e {
-	case 0:
-		return nil
-	case unix.EAGAIN:
-		return syscall.EAGAIN
-	case unix.EINVAL:
-		return syscall.EINVAL
-	case unix.ENOENT:
-		return syscall.ENOENT
-	}
-	return e
-}
-
-func clonefile(src, dst string) (err error) {
-	var _p0, _p1 *byte
-	_p0, err = unix.BytePtrFromString(src)
-	if err != nil {
-		return
-	}
-	_p1, err = unix.BytePtrFromString(dst)
-	if err != nil {
-		return
-	}
-	fdcwd := unix.AT_FDCWD
-	_, _, e1 := unix.Syscall6(unix.SYS_CLONEFILEAT, uintptr(fdcwd), uintptr(unsafe.Pointer(_p0)), uintptr(fdcwd), uintptr(unsafe.Pointer(_p1)), uintptr(CLONE_NOFOLLOW), 0)
-	if e1 != 0 {
-		err = errnoErr(e1)
-	}
-	return
+func mknod(dst string, mode uint32, rDev int) error {
+	return unix.Mknod(dst, uint32(mode), rDev)
 }
diff --git a/copy/copy_freebsd.go b/copy/copy_freebsd.go
new file mode 100644
index 0000000..1b9dbb3
--- /dev/null
+++ b/copy/copy_freebsd.go
@@ -0,0 +1,38 @@
+//go:build freebsd
+// +build freebsd
+
+package fs
+
+import (
+	"io"
+	"os"
+
+	"github.com/pkg/errors"
+	"golang.org/x/sys/unix"
+)
+
+func copyFile(source, target string) error {
+	src, err := os.Open(source)
+	if err != nil {
+		return errors.Wrapf(err, "failed to open source %s", source)
+	}
+	defer src.Close()
+	tgt, err := os.Create(target)
+	if err != nil {
+		return errors.Wrapf(err, "failed to open target %s", target)
+	}
+	defer tgt.Close()
+
+	return copyFileContent(tgt, src)
+}
+
+func copyFileContent(dst, src *os.File) error {
+	buf := bufferPool.Get().(*[]byte)
+	_, err := io.CopyBuffer(dst, src, *buf)
+	bufferPool.Put(buf)
+	return err
+}
+
+func mknod(dst string, mode uint32, rDev int) error {
+	return unix.Mknod(dst, uint32(mode), uint64(rDev))
+}
diff --git a/copy/copy_linux.go b/copy/copy_linux.go
index 268a9fc..2ac813e 100644
--- a/copy/copy_linux.go
+++ b/copy/copy_linux.go
@@ -10,7 +10,7 @@ import (
 	"golang.org/x/sys/unix"
 )
 
-func getUidGid(fi os.FileInfo) (uid, gid int) {
+func getUIDGID(fi os.FileInfo) (uid, gid int) {
 	st := fi.Sys().(*syscall.Stat_t)
 	return int(st.Uid), int(st.Gid)
 }
@@ -19,8 +19,8 @@ func (c *copier) copyFileInfo(fi os.FileInfo, name string) error {
 	st := fi.Sys().(*syscall.Stat_t)
 
 	chown := c.chown
-	uid, gid := getUidGid(fi)
-	old := &User{Uid: uid, Gid: gid}
+	uid, gid := getUIDGID(fi)
+	old := &User{UID: uid, GID: gid}
 	if chown == nil {
 		chown = func(u *User) (*User, error) {
 			return u, nil
@@ -89,14 +89,18 @@ func copyFileContent(dst, src *os.File) error {
 
 		n, err := unix.CopyFileRange(int(src.Fd()), nil, int(dst.Fd()), nil, desired, 0)
 		if err != nil {
-			if (err != unix.ENOSYS && err != unix.EXDEV && err != unix.EPERM) || !first {
+			// matches go/src/internal/poll/copy_file_range_linux.go
+			if (err != unix.ENOSYS && err != unix.EXDEV && err != unix.EPERM && err != syscall.EIO && err != unix.EOPNOTSUPP && err != syscall.EINVAL) || !first {
 				return errors.Wrap(err, "copy file range failed")
 			}
 
 			buf := bufferPool.Get().(*[]byte)
 			_, err = io.CopyBuffer(dst, src, *buf)
 			bufferPool.Put(buf)
-			return errors.Wrap(err, "userspace copy failed")
+			if err != nil {
+				return errors.Wrap(err, "userspace copy failed")
+			}
+			return nil
 		}
 
 		first = false
@@ -105,10 +109,6 @@ func copyFileContent(dst, src *os.File) error {
 	return nil
 }
 
-func copyDevice(dst string, fi os.FileInfo) error {
-	st, ok := fi.Sys().(*syscall.Stat_t)
-	if !ok {
-		return errors.New("unsupported stat type")
-	}
-	return unix.Mknod(dst, uint32(fi.Mode()), int(st.Rdev))
+func mknod(dst string, mode uint32, rDev int) error {
+	return unix.Mknod(dst, uint32(mode), rDev)
 }
diff --git a/copy/copy_nowindows.go b/copy/copy_nowindows.go
index cbd784e..382fe20 100644
--- a/copy/copy_nowindows.go
+++ b/copy/copy_nowindows.go
@@ -1,8 +1,12 @@
+//go:build !windows
 // +build !windows
 
 package fs
 
 import (
+	"os"
+	"syscall"
+
 	"github.com/pkg/errors"
 
 	"github.com/containerd/continuity/sysx"
@@ -26,3 +30,17 @@ func copyXAttrs(dst, src string, xeh XAttrErrorHandler) error {
 
 	return nil
 }
+
+func copyDevice(dst string, fi os.FileInfo) error {
+	st, ok := fi.Sys().(*syscall.Stat_t)
+	if !ok {
+		return errors.New("unsupported stat type")
+	}
+	var rDev int
+	if fi.Mode()&os.ModeDevice == os.ModeDevice || fi.Mode()&os.ModeCharDevice == os.ModeCharDevice {
+		rDev = int(st.Rdev)
+	}
+	mode := st.Mode
+	mode &^= syscall.S_IFSOCK // socket copied as stub
+	return mknod(dst, uint32(mode), rDev)
+}
diff --git a/copy/copy_test.go b/copy/copy_test.go
index bf63992..bc6c6d1 100644
--- a/copy/copy_test.go
+++ b/copy/copy_test.go
@@ -3,16 +3,30 @@ package fs
 import (
 	"context"
 	_ "crypto/sha256"
-	"io/ioutil"
+	"fmt"
 	"os"
 	"path/filepath"
+	"sort"
+	"strings"
 	"testing"
 
 	"github.com/containerd/continuity/fs/fstest"
 	"github.com/pkg/errors"
+	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
+	"github.com/tonistiigi/fsutil"
+	"golang.org/x/sys/unix"
 )
 
+// requiresRoot skips tests that require root
+func requiresRoot(t *testing.T) {
+	t.Helper()
+	if os.Getuid() != 0 {
+		t.Skip("skipping test that requires root")
+		return
+	}
+}
+
 // TODO: Create copy directory which requires privilege
 //  chown
 //  mknod
@@ -29,7 +43,9 @@ func TestCopyDirectory(t *testing.T) {
 		fstest.CreateDir("/home", 0755),
 	)
 
-	if err := testCopy(apply); err != nil {
+	exp := "add:/etc,add:/etc/hosts,add:/etc/hosts.allow,add:/home,add:/usr,add:/usr/local,add:/usr/local/lib,add:/usr/local/lib/libnothing.so,add:/usr/local/lib/libnothing.so.2"
+
+	if err := testCopy(t, apply, exp); err != nil {
 		t.Fatalf("Copy test failed: %+v", err)
 	}
 }
@@ -43,15 +59,15 @@ func TestCopyDirectoryWithLocalSymlink(t *testing.T) {
 		fstest.Symlink("nothing.txt", "link-no-nothing.txt"),
 	)
 
-	if err := testCopy(apply); err != nil {
+	exp := "add:/link-no-nothing.txt,add:/nothing.txt"
+
+	if err := testCopy(t, apply, exp); err != nil {
 		t.Fatalf("Copy test failed: %+v", err)
 	}
 }
 
 func TestCopyToWorkDir(t *testing.T) {
-	t1, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(t1)
+	t1 := t.TempDir()
 
 	apply := fstest.Apply(
 		fstest.CreateFile("foo.txt", []byte("contents"), 0755),
@@ -59,21 +75,59 @@ func TestCopyToWorkDir(t *testing.T) {
 
 	require.NoError(t, apply.Apply(t1))
 
-	t2, err := ioutil.TempDir("", "test")
+	t2 := t.TempDir()
+	err := Copy(context.TODO(), t1, "foo.txt", t2, "foo.txt")
 	require.NoError(t, err)
-	defer os.RemoveAll(t2)
 
-	err = Copy(context.TODO(), t1, "foo.txt", t2, "foo.txt")
+	err = fstest.CheckDirectoryEqual(t1, t2)
 	require.NoError(t, err)
+}
 
-	err = fstest.CheckDirectoryEqual(t1, t2)
+func TestCopyDevicesAndFifo(t *testing.T) {
+	requiresRoot(t)
+
+	t1 := t.TempDir()
+
+	err := mknod(filepath.Join(t1, "char"), unix.S_IFCHR|0444, int(unix.Mkdev(1, 9)))
+	require.NoError(t, err)
+
+	err = mknod(filepath.Join(t1, "block"), unix.S_IFBLK|0441, int(unix.Mkdev(3, 2)))
+	require.NoError(t, err)
+
+	err = mknod(filepath.Join(t1, "socket"), unix.S_IFSOCK|0555, 0)
+	require.NoError(t, err)
+
+	err = unix.Mkfifo(filepath.Join(t1, "fifo"), 0555)
+	require.NoError(t, err)
+
+	t2 := t.TempDir()
+
+	err = Copy(context.TODO(), t1, ".", t2, ".")
+	require.NoError(t, err)
+
+	fi, err := os.Lstat(filepath.Join(t2, "char"))
 	require.NoError(t, err)
+	assert.Equal(t, os.ModeCharDevice, fi.Mode()&os.ModeCharDevice)
+	assert.Equal(t, os.FileMode(0444), fi.Mode()&0777)
+
+	fi, err = os.Lstat(filepath.Join(t2, "block"))
+	require.NoError(t, err)
+	assert.Equal(t, os.ModeDevice, fi.Mode()&os.ModeDevice)
+	assert.Equal(t, os.FileMode(0441), fi.Mode()&0777)
+
+	fi, err = os.Lstat(filepath.Join(t2, "fifo"))
+	require.NoError(t, err)
+	assert.Equal(t, os.ModeNamedPipe, fi.Mode()&os.ModeNamedPipe)
+	assert.Equal(t, os.FileMode(0555), fi.Mode()&0777)
+
+	fi, err = os.Lstat(filepath.Join(t2, "socket"))
+	require.NoError(t, err)
+	assert.NotEqual(t, os.ModeSocket, fi.Mode()&os.ModeSocket) // socket copied as stub
+	assert.Equal(t, os.FileMode(0555), fi.Mode()&0777)
 }
 
 func TestCopySingleFile(t *testing.T) {
-	t1, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(t1)
+	t1 := t.TempDir()
 
 	apply := fstest.Apply(
 		fstest.CreateFile("foo.txt", []byte("contents"), 0755),
@@ -81,19 +135,15 @@ func TestCopySingleFile(t *testing.T) {
 
 	require.NoError(t, apply.Apply(t1))
 
-	t2, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(t2)
+	t2 := t.TempDir()
 
-	err = Copy(context.TODO(), t1, "foo.txt", t2, "/")
+	err := Copy(context.TODO(), t1, "foo.txt", t2, "/")
 	require.NoError(t, err)
 
 	err = fstest.CheckDirectoryEqual(t1, t2)
 	require.NoError(t, err)
 
-	t3, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(t2)
+	t3 := t.TempDir()
 
 	err = Copy(context.TODO(), t1, "foo.txt", t3, "foo.txt")
 	require.NoError(t, err)
@@ -101,21 +151,27 @@ func TestCopySingleFile(t *testing.T) {
 	err = fstest.CheckDirectoryEqual(t1, t2)
 	require.NoError(t, err)
 
-	t4, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(t2)
+	t4 := t.TempDir()
 
 	err = Copy(context.TODO(), t1, "foo.txt", t4, "foo2.txt")
 	require.NoError(t, err)
 
 	_, err = os.Stat(filepath.Join(t4, "foo2.txt"))
 	require.NoError(t, err)
+
+	ch := &changeCollector{}
+
+	err = Copy(context.TODO(), t1, "foo.txt", t4, "a/b/c/foo2.txt", WithChangeNotifier(ch.onChange))
+	require.NoError(t, err)
+
+	_, err = os.Stat(filepath.Join(t4, "a/b/c/foo2.txt"))
+	require.NoError(t, err)
+
+	require.Equal(t, "add:/a/b/c/foo2.txt", ch.String())
 }
 
 func TestCopyOverrideFile(t *testing.T) {
-	t1, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(t1)
+	t1 := t.TempDir()
 
 	apply := fstest.Apply(
 		fstest.CreateFile("foo.txt", []byte("contents"), 0755),
@@ -123,11 +179,9 @@ func TestCopyOverrideFile(t *testing.T) {
 
 	require.NoError(t, apply.Apply(t1))
 
-	t2, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(t2)
+	t2 := t.TempDir()
 
-	err = Copy(context.TODO(), t1, "foo.txt", t2, "foo.txt")
+	err := Copy(context.TODO(), t1, "foo.txt", t2, "foo.txt")
 	require.NoError(t, err)
 
 	err = fstest.CheckDirectoryEqual(t1, t2)
@@ -147,9 +201,7 @@ func TestCopyOverrideFile(t *testing.T) {
 }
 
 func TestCopyDirectoryBasename(t *testing.T) {
-	t1, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(t1)
+	t1 := t.TempDir()
 
 	apply := fstest.Apply(
 		fstest.CreateDir("foo", 0755),
@@ -158,29 +210,33 @@ func TestCopyDirectoryBasename(t *testing.T) {
 	)
 	require.NoError(t, apply.Apply(t1))
 
-	t2, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(t2)
+	t2 := t.TempDir()
 
-	err = Copy(context.TODO(), t1, "foo", t2, "foo")
+	ch := &changeCollector{}
+
+	err := Copy(context.TODO(), t1, "foo", t2, "foo", WithChangeNotifier(ch.onChange))
 	require.NoError(t, err)
 
 	err = fstest.CheckDirectoryEqual(t1, t2)
 	require.NoError(t, err)
 
+	require.Equal(t, "add:/foo,add:/foo/bar,add:/foo/bar/baz.txt", ch.String())
+
+	ch = &changeCollector{}
 	err = Copy(context.TODO(), t1, "foo", t2, "foo", WithCopyInfo(CopyInfo{
 		CopyDirContents: true,
+		ChangeFunc:      ch.onChange,
 	}))
 	require.NoError(t, err)
 
+	require.Equal(t, "add:/foo/bar,add:/foo/bar/baz.txt", ch.String())
+
 	err = fstest.CheckDirectoryEqual(t1, t2)
 	require.NoError(t, err)
 }
 
 func TestCopyWildcards(t *testing.T) {
-	t1, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(t1)
+	t1 := t.TempDir()
 
 	apply := fstest.Apply(
 		fstest.CreateFile("foo.txt", []byte("foo-contents"), 0755),
@@ -190,11 +246,9 @@ func TestCopyWildcards(t *testing.T) {
 
 	require.NoError(t, apply.Apply(t1))
 
-	t2, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(t2)
+	t2 := t.TempDir()
 
-	err = Copy(context.TODO(), t1, "foo*", t2, "/")
+	err := Copy(context.TODO(), t1, "foo*", t2, "/")
 	require.Error(t, err)
 
 	err = Copy(context.TODO(), t1, "foo*", t2, "/", AllowWildcards)
@@ -208,13 +262,11 @@ func TestCopyWildcards(t *testing.T) {
 	require.Error(t, err)
 	require.True(t, os.IsNotExist(err))
 
-	t2, err = ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(t2)
+	t3 := t.TempDir()
 
-	err = Copy(context.TODO(), t1, "bar*", t2, "foo.txt", AllowWildcards)
+	err = Copy(context.TODO(), t1, "bar*", t3, "foo.txt", AllowWildcards)
 	require.NoError(t, err)
-	dt, err := ioutil.ReadFile(filepath.Join(t2, "foo.txt"))
+	dt, err := os.ReadFile(filepath.Join(t3, "foo.txt"))
 	require.NoError(t, err)
 	require.Equal(t, "bar-contents", string(dt))
 }
@@ -224,9 +276,7 @@ func TestCopyExistingDirDest(t *testing.T) {
 		t.Skip()
 	}
 
-	t1, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(t1)
+	t1 := t.TempDir()
 
 	apply := fstest.Apply(
 		fstest.CreateDir("dir", 0755),
@@ -235,9 +285,7 @@ func TestCopyExistingDirDest(t *testing.T) {
 	)
 	require.NoError(t, apply.Apply(t1))
 
-	t2, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(t2)
+	t2 := t.TempDir()
 
 	apply = fstest.Apply(
 		// notice how perms for destination and source are different
@@ -249,11 +297,11 @@ func TestCopyExistingDirDest(t *testing.T) {
 	require.NoError(t, apply.Apply(t2))
 
 	for _, x := range []string{"dir", "dir/bar.txt"} {
-		err = os.Chown(filepath.Join(t2, x), 1, 1)
+		err := os.Chown(filepath.Join(t2, x), 1, 1)
 		require.NoErrorf(t, err, "x=%s", x)
 	}
 
-	err = Copy(context.TODO(), t1, "dir", t2, "dir", WithCopyInfo(CopyInfo{
+	err := Copy(context.TODO(), t1, "dir", t2, "dir", WithCopyInfo(CopyInfo{
 		CopyDirContents: true,
 	}))
 	require.NoError(t, err)
@@ -262,7 +310,7 @@ func TestCopyExistingDirDest(t *testing.T) {
 	st, err := os.Lstat(filepath.Join(t2, "dir"))
 	require.NoError(t, err)
 	require.Equal(t, st.Mode()&os.ModePerm, os.FileMode(0700))
-	uid, gid := getUidGid(st)
+	uid, gid := getUIDGID(st)
 	require.Equal(t, 1, uid)
 	require.Equal(t, 1, gid)
 
@@ -274,18 +322,16 @@ func TestCopyExistingDirDest(t *testing.T) {
 	st, err = os.Lstat(filepath.Join(t2, "dir/bar.txt"))
 	require.NoError(t, err)
 	require.Equal(t, os.FileMode(0644), st.Mode()&os.ModePerm)
-	uid, gid = getUidGid(st)
+	uid, gid = getUIDGID(st)
 	require.Equal(t, 0, uid)
 	require.Equal(t, 0, gid)
-	dt, err := ioutil.ReadFile(filepath.Join(t2, "dir/bar.txt"))
+	dt, err := os.ReadFile(filepath.Join(t2, "dir/bar.txt"))
 	require.NoError(t, err)
 	require.Equal(t, "bar-contents", string(dt))
 }
 
 func TestCopySymlinks(t *testing.T) {
-	t1, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(t1)
+	t1 := t.TempDir()
 
 	apply := fstest.Apply(
 		fstest.CreateDir("testdir", 0755),
@@ -295,11 +341,9 @@ func TestCopySymlinks(t *testing.T) {
 	)
 	require.NoError(t, apply.Apply(t1))
 
-	t2, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(t2)
+	t2 := t.TempDir()
 
-	err = Copy(context.TODO(), t1, "link/link2", t2, "foo", WithCopyInfo(CopyInfo{
+	err := Copy(context.TODO(), t1, "link/link2", t2, "foo", WithCopyInfo(CopyInfo{
 		FollowLinks: true,
 	}))
 	require.NoError(t, err)
@@ -309,12 +353,11 @@ func TestCopySymlinks(t *testing.T) {
 	require.NoError(t, err)
 	require.Equal(t, os.FileMode(0644), st.Mode()&os.ModePerm)
 	require.Equal(t, 0, int(st.Mode()&os.ModeSymlink))
-	dt, err := ioutil.ReadFile(filepath.Join(t2, "foo"))
+	dt, err := os.ReadFile(filepath.Join(t2, "foo"))
+	require.NoError(t, err)
 	require.Equal(t, "foo-contents", string(dt))
 
-	t3, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(t2)
+	t3 := t.TempDir()
 
 	err = Copy(context.TODO(), t1, "link/link2", t3, "foo", WithCopyInfo(CopyInfo{}))
 	require.NoError(t, err)
@@ -328,26 +371,199 @@ func TestCopySymlinks(t *testing.T) {
 	require.Equal(t, "foo.txt", link)
 }
 
-func testCopy(apply fstest.Applier) error {
-	t1, err := ioutil.TempDir("", "test-copy-src-")
-	if err != nil {
-		return errors.Wrap(err, "failed to create temporary directory")
-	}
-	defer os.RemoveAll(t1)
-
-	t2, err := ioutil.TempDir("", "test-copy-dst-")
-	if err != nil {
-		return errors.Wrap(err, "failed to create temporary directory")
-	}
-	defer os.RemoveAll(t2)
+func testCopy(t *testing.T, apply fstest.Applier, exp string) error {
+	t1 := t.TempDir()
+	t2 := t.TempDir()
 
 	if err := apply.Apply(t1); err != nil {
 		return errors.Wrap(err, "failed to apply changes")
 	}
 
-	if err := Copy(context.TODO(), t1, "/.", t2, "/"); err != nil {
+	ch := &changeCollector{}
+	if err := Copy(context.TODO(), t1, "/.", t2, "/", WithChangeNotifier(ch.onChange)); err != nil {
 		return errors.Wrap(err, "failed to copy")
 	}
 
+	if exp != ch.String() {
+		return errors.Errorf("unexpected changes: %s", ch)
+	}
+
 	return fstest.CheckDirectoryEqual(t1, t2)
 }
+
+func TestCopyIncludeExclude(t *testing.T) {
+	t1 := t.TempDir()
+
+	apply := fstest.Apply(
+		fstest.CreateDir("bar", 0755),
+		fstest.CreateFile("bar/foo", []byte("foo-contents"), 0755),
+		fstest.CreateDir("bar/baz", 0755),
+		fstest.CreateFile("bar/baz/foo3", []byte("foo3-contents"), 0755),
+		fstest.CreateFile("foo2", []byte("foo2-contents"), 0755),
+	)
+
+	require.NoError(t, apply.Apply(t1))
+
+	testCases := []struct {
+		name            string
+		opts            []Opt
+		expectedResults []string
+		expectedChanges string
+	}{
+		{
+			name:            "include bar",
+			opts:            []Opt{WithIncludePattern("bar")},
+			expectedResults: []string{"bar", "bar/foo", "bar/baz", "bar/baz/foo3"},
+			expectedChanges: "add:/bar,add:/bar/baz,add:/bar/baz/foo3,add:/bar/foo",
+		},
+		{
+			name:            "include *",
+			opts:            []Opt{WithIncludePattern("*")},
+			expectedResults: []string{"bar", "bar/foo", "bar/baz", "bar/baz/foo3", "foo2"},
+			expectedChanges: "add:/bar,add:/bar/baz,add:/bar/baz/foo3,add:/bar/foo,add:/foo2",
+		},
+		{
+			name:            "include bar/foo",
+			opts:            []Opt{WithIncludePattern("bar/foo")},
+			expectedResults: []string{"bar", "bar/foo"},
+			expectedChanges: "add:/bar/foo",
+		},
+		{
+			name:            "include bar except bar/foo",
+			opts:            []Opt{WithIncludePattern("bar"), WithIncludePattern("!bar/foo")},
+			expectedResults: []string{"bar", "bar/baz", "bar/baz/foo3"},
+			expectedChanges: "add:/bar,add:/bar/baz,add:/bar/baz/foo3",
+		},
+		{
+			name:            "include bar/foo and foo*",
+			opts:            []Opt{WithIncludePattern("bar/foo"), WithIncludePattern("foo*")},
+			expectedResults: []string{"bar", "bar/foo", "foo2"},
+			expectedChanges: "add:/bar/foo,add:/foo2",
+		},
+		{
+			name:            "include b*",
+			opts:            []Opt{WithIncludePattern("b*")},
+			expectedResults: []string{"bar", "bar/foo", "bar/baz", "bar/baz/foo3"},
+			expectedChanges: "add:/bar,add:/bar/baz,add:/bar/baz/foo3,add:/bar/foo",
+		},
+		{
+			name:            "include bar/f*",
+			opts:            []Opt{WithIncludePattern("bar/f*")},
+			expectedResults: []string{"bar", "bar/foo"},
+		},
+		{
+			name:            "include bar/g*",
+			opts:            []Opt{WithIncludePattern("bar/g*")},
+			expectedResults: nil,
+		},
+		{
+			name:            "include b*/f*",
+			opts:            []Opt{WithIncludePattern("b*/f*")},
+			expectedResults: []string{"bar", "bar/foo"},
+		},
+		{
+			name:            "include b*/foo",
+			opts:            []Opt{WithIncludePattern("b*/foo")},
+			expectedResults: []string{"bar", "bar/foo"},
+		},
+		{
+			name:            "include b*/",
+			opts:            []Opt{WithIncludePattern("b*/")},
+			expectedResults: []string{"bar", "bar/foo", "bar/baz", "bar/baz/foo3"},
+		},
+		{
+			name:            "include bar/*/foo3",
+			opts:            []Opt{WithIncludePattern("bar/*/foo3")},
+			expectedResults: []string{"bar", "bar/baz", "bar/baz/foo3"},
+		},
+		{
+			name:            "exclude bar*, !bar/baz",
+			opts:            []Opt{WithExcludePattern("bar*"), WithExcludePattern("!bar/baz")},
+			expectedResults: []string{"bar", "bar/baz", "bar/baz/foo3", "foo2"},
+		},
+		{
+			name:            "exclude **, !bar/baz",
+			opts:            []Opt{WithExcludePattern("**"), WithExcludePattern("!bar/baz")},
+			expectedResults: []string{"bar", "bar/baz", "bar/baz/foo3"},
+		},
+		{
+			name:            "exclude **, !bar/baz, bar/baz/foo3",
+			opts:            []Opt{WithExcludePattern("**"), WithExcludePattern("!bar/baz"), WithExcludePattern("bar/baz/foo3")},
+			expectedResults: []string{"bar", "bar/baz"},
+		},
+		{
+			name:            "include bar, exclude bar/baz",
+			opts:            []Opt{WithIncludePattern("bar"), WithExcludePattern("bar/baz")},
+			expectedResults: []string{"bar", "bar/foo"},
+		},
+		{
+			name:            "doublestar include",
+			opts:            []Opt{WithIncludePattern("**/foo3")},
+			expectedResults: []string{"bar", "bar/baz", "bar/baz/foo3"},
+		},
+		{
+			name:            "doublestar matching second item in path",
+			opts:            []Opt{WithIncludePattern("**/baz")},
+			expectedResults: []string{"bar", "bar/baz", "bar/baz/foo3"},
+			expectedChanges: "add:/bar/baz,add:/bar/baz/foo3",
+		},
+		{
+			name:            "doublestar matching first item in path",
+			opts:            []Opt{WithIncludePattern("**/bar")},
+			expectedResults: []string{"bar", "bar/foo", "bar/baz", "bar/baz/foo3"},
+			expectedChanges: "add:/bar,add:/bar/baz,add:/bar/baz/foo3,add:/bar/foo",
+		},
+		{
+			name:            "doublestar exclude",
+			opts:            []Opt{WithIncludePattern("bar"), WithExcludePattern("**/foo3")},
+			expectedResults: []string{"bar", "bar/foo", "bar/baz"},
+			expectedChanges: "add:/bar,add:/bar/baz,add:/bar/foo",
+		},
+		{
+			name:            "exclude bar/baz",
+			opts:            []Opt{WithExcludePattern("bar/baz")},
+			expectedResults: []string{"bar", "bar/foo", "foo2"},
+			expectedChanges: "add:/bar,add:/bar/foo,add:/foo2",
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			t2 := t.TempDir()
+
+			ch := &changeCollector{}
+			tc.opts = append(tc.opts, WithChangeNotifier(ch.onChange))
+
+			err := Copy(context.Background(), t1, "/", t2, "/", tc.opts...)
+			require.NoError(t, err, tc.name)
+
+			var results []string
+			for _, path := range []string{"bar", "bar/foo", "bar/baz", "bar/baz/asdf", "bar/baz/asdf/x", "bar/baz/foo3", "foo2"} {
+				_, err := os.Stat(filepath.Join(t2, path))
+				if err == nil {
+					results = append(results, path)
+				}
+			}
+
+			require.Equal(t, tc.expectedResults, results, tc.name)
+
+			if tc.expectedChanges != "" {
+				require.Equal(t, tc.expectedChanges, ch.String())
+			}
+		})
+	}
+}
+
+type changeCollector struct {
+	changes []string
+}
+
+func (c *changeCollector) onChange(kind fsutil.ChangeKind, path string, _ os.FileInfo, _ error) error {
+	c.changes = append(c.changes, fmt.Sprintf("%s:%s", kind, path))
+	return nil
+}
+
+func (c *changeCollector) String() string {
+	sort.Strings(c.changes)
+	return strings.Join(c.changes, ",")
+}
diff --git a/copy/copy_unix.go b/copy/copy_unix.go
index e80ee78..22281ba 100644
--- a/copy/copy_unix.go
+++ b/copy/copy_unix.go
@@ -1,3 +1,4 @@
+//go:build solaris || darwin || freebsd
 // +build solaris darwin freebsd
 
 package fs
@@ -10,7 +11,7 @@ import (
 	"golang.org/x/sys/unix"
 )
 
-func getUidGid(fi os.FileInfo) (uid, gid int) {
+func getUIDGID(fi os.FileInfo) (uid, gid int) {
 	st := fi.Sys().(*syscall.Stat_t)
 	return int(st.Uid), int(st.Gid)
 }
@@ -18,8 +19,8 @@ func getUidGid(fi os.FileInfo) (uid, gid int) {
 func (c *copier) copyFileInfo(fi os.FileInfo, name string) error {
 	st := fi.Sys().(*syscall.Stat_t)
 	chown := c.chown
-	uid, gid := getUidGid(fi)
-	old := &User{Uid: uid, Gid: gid}
+	uid, gid := getUIDGID(fi)
+	old := &User{UID: uid, GID: gid}
 	if chown == nil {
 		chown = func(u *User) (*User, error) {
 			return u, nil
@@ -51,11 +52,3 @@ func (c *copier) copyFileInfo(fi os.FileInfo, name string) error {
 	}
 	return nil
 }
-
-func copyDevice(dst string, fi os.FileInfo) error {
-	st, ok := fi.Sys().(*syscall.Stat_t)
-	if !ok {
-		return errors.New("unsupported stat type")
-	}
-	return unix.Mknod(dst, uint32(fi.Mode()), int(st.Rdev))
-}
diff --git a/copy/hardlink_unix.go b/copy/hardlink_unix.go
index 3b825c9..a02c5a5 100644
--- a/copy/hardlink_unix.go
+++ b/copy/hardlink_unix.go
@@ -1,3 +1,4 @@
+//go:build !windows
 // +build !windows
 
 package fs
diff --git a/copy/mkdir.go b/copy/mkdir.go
index b5eeb90..9854754 100644
--- a/copy/mkdir.go
+++ b/copy/mkdir.go
@@ -17,7 +17,7 @@ func Chown(p string, old *User, fn Chowner) error {
 		return errors.WithStack(err)
 	}
 	if user != nil {
-		if err := os.Lchown(p, user.Uid, user.Gid); err != nil {
+		if err := os.Lchown(p, user.UID, user.GID); err != nil {
 			return err
 		}
 	}
diff --git a/copy/mkdir_unix.go b/copy/mkdir_unix.go
index 8fb0f6b..f6d196b 100644
--- a/copy/mkdir_unix.go
+++ b/copy/mkdir_unix.go
@@ -1,3 +1,4 @@
+//go:build !windows
 // +build !windows
 
 package fs
diff --git a/copy/stat_sysv.go b/copy/stat_sysv.go
index 59accf0..31ea3d9 100644
--- a/copy/stat_sysv.go
+++ b/copy/stat_sysv.go
@@ -1,3 +1,4 @@
+//go:build dragonfly || linux || solaris
 // +build dragonfly linux solaris
 
 package fs
diff --git a/debian/changelog b/debian/changelog
index 7d2d9b0..0b67a67 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+golang-github-tonistiigi-fsutil (0.0~git20220930.4638ad6-1) UNRELEASED; urgency=low
+
+  * New upstream snapshot.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Wed, 09 Nov 2022 16:07:39 -0000
+
 golang-github-tonistiigi-fsutil (0.0~git20200331.f427cf1-3) unstable; urgency=medium
 
   * Team upload.
diff --git a/diff.go b/diff.go
index 1cbc32b..a7405dc 100644
--- a/diff.go
+++ b/diff.go
@@ -19,9 +19,9 @@ type HandleChangeFn func(ChangeKind, string, os.FileInfo, error) error
 
 type ContentHasher func(*types.Stat) (hash.Hash, error)
 
-func GetWalkerFn(root string) walkerFn {
+func getWalkerFn(root string) walkerFn {
 	return func(ctx context.Context, pathC chan<- *currentPath) error {
-		return Walk(ctx, root, nil, func(path string, f os.FileInfo, err error) error {
+		return errors.Wrap(Walk(ctx, root, nil, func(path string, f os.FileInfo, err error) error {
 			if err != nil {
 				return err
 			}
@@ -42,7 +42,7 @@ func GetWalkerFn(root string) walkerFn {
 			case pathC <- p:
 				return nil
 			}
-		})
+		}), "failed to walk")
 	}
 }
 
diff --git a/diff_containerd.go b/diff_containerd.go
index 3702715..d8619ab 100644
--- a/diff_containerd.go
+++ b/diff_containerd.go
@@ -1,7 +1,9 @@
 package fsutil
 
 import (
+	"bytes"
 	"context"
+	"io"
 	"os"
 	"strings"
 
@@ -31,10 +33,25 @@ const (
 	ChangeKindDelete
 )
 
+func (k ChangeKind) String() string {
+	switch k {
+	case ChangeKindAdd:
+		return "add"
+	case ChangeKindModify:
+		return "modify"
+	case ChangeKindDelete:
+		return "delete"
+	default:
+		return "unknown"
+	}
+}
+
 // ChangeFunc is the type of function called for each change
 // computed during a directory changes calculation.
 type ChangeFunc func(ChangeKind, string, os.FileInfo, error) error
 
+const compareChunkSize = 32 * 1024
+
 type currentPath struct {
 	path string
 	stat *types.Stat
@@ -42,7 +59,7 @@ type currentPath struct {
 }
 
 // doubleWalkDiff walks both directories to create a diff
-func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b walkerFn, filter FilterFunc) (err error) {
+func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b walkerFn, filter FilterFunc, differ DiffType) (err error) {
 	g, ctx := errgroup.WithContext(ctx)
 
 	var (
@@ -116,7 +133,7 @@ func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b walkerFn, fil
 				}
 				f1 = nil
 			case ChangeKindModify:
-				same, err := sameFile(f1, f2copy)
+				same, err := sameFile(f1, f2copy, differ)
 				if err != nil {
 					return err
 				}
@@ -165,7 +182,10 @@ func pathChange(lower, upper *currentPath) (ChangeKind, string) {
 	}
 }
 
-func sameFile(f1, f2 *currentPath) (same bool, retErr error) {
+func sameFile(f1, f2 *currentPath, differ DiffType) (same bool, retErr error) {
+	if differ == DiffNone {
+		return false, nil
+	}
 	// If not a directory also check size, modtime, and content
 	if !f1.stat.IsDir() {
 		if f1.stat.Size_ != f2.stat.Size_ {
@@ -177,7 +197,43 @@ func sameFile(f1, f2 *currentPath) (same bool, retErr error) {
 		}
 	}
 
-	return compareStat(f1.stat, f2.stat)
+	same, err := compareStat(f1.stat, f2.stat)
+	if err != nil || !same || differ == DiffMetadata {
+		return same, err
+	}
+	return compareFileContent(f1.path, f2.path)
+}
+
+func compareFileContent(p1, p2 string) (bool, error) {
+	f1, err := os.Open(p1)
+	if err != nil {
+		return false, err
+	}
+	defer f1.Close()
+	f2, err := os.Open(p2)
+	if err != nil {
+		return false, err
+	}
+	defer f2.Close()
+
+	b1 := make([]byte, compareChunkSize)
+	b2 := make([]byte, compareChunkSize)
+	for {
+		n1, err1 := f1.Read(b1)
+		if err1 != nil && err1 != io.EOF {
+			return false, err1
+		}
+		n2, err2 := f2.Read(b2)
+		if err2 != nil && err2 != io.EOF {
+			return false, err2
+		}
+		if n1 != n2 || !bytes.Equal(b1[:n1], b2[:n2]) {
+			return false, nil
+		}
+		if err1 == io.EOF && err2 == io.EOF {
+			return true, nil
+		}
+	}
 }
 
 // compareStat returns whether the stats are equivalent,
diff --git a/diff_containerd_linux.go b/diff_containerd_linux.go
deleted file mode 100644
index 4ac7ec5..0000000
--- a/diff_containerd_linux.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package fsutil
-
-import (
-	"bytes"
-	"syscall"
-
-	"github.com/containerd/continuity/sysx"
-	"github.com/pkg/errors"
-)
-
-// compareSysStat returns whether the stats are equivalent,
-// whether the files are considered the same file, and
-// an error
-func compareSysStat(s1, s2 interface{}) (bool, error) {
-	ls1, ok := s1.(*syscall.Stat_t)
-	if !ok {
-		return false, nil
-	}
-	ls2, ok := s2.(*syscall.Stat_t)
-	if !ok {
-		return false, nil
-	}
-
-	return ls1.Mode == ls2.Mode && ls1.Uid == ls2.Uid && ls1.Gid == ls2.Gid && ls1.Rdev == ls2.Rdev, nil
-}
-
-func compareCapabilities(p1, p2 string) (bool, error) {
-	c1, err := sysx.LGetxattr(p1, "security.capability")
-	if err != nil && err != syscall.ENODATA {
-		return false, errors.Wrapf(err, "failed to get xattr for %s", p1)
-	}
-	c2, err := sysx.LGetxattr(p2, "security.capability")
-	if err != nil && err != syscall.ENODATA {
-		return false, errors.Wrapf(err, "failed to get xattr for %s", p2)
-	}
-	return bytes.Equal(c1, c2), nil
-}
diff --git a/diskwriter.go b/diskwriter.go
index 70323c8..8f2574b 100644
--- a/diskwriter.go
+++ b/diskwriter.go
@@ -8,6 +8,7 @@ import (
 	"path/filepath"
 	"strconv"
 	"sync"
+	"syscall"
 	"time"
 
 	"github.com/opencontainers/go-digest"
@@ -32,7 +33,6 @@ type DiskWriter struct {
 	opt  DiskWriterOpt
 	dest string
 
-	wg     sync.WaitGroup
 	ctx    context.Context
 	cancel func()
 	eg     *errgroup.Group
@@ -104,7 +104,7 @@ func (dw *DiskWriter) HandleChange(kind ChangeKind, p string, fi os.FileInfo, er
 
 	stat, ok := fi.Sys().(*types.Stat)
 	if !ok {
-		return errors.Errorf("%s invalid change without stat information", p)
+		return errors.WithStack(&os.PathError{Path: p, Err: syscall.EBADMSG, Op: "change without stat info"})
 	}
 
 	statCopy := *stat
@@ -118,13 +118,13 @@ func (dw *DiskWriter) HandleChange(kind ChangeKind, p string, fi os.FileInfo, er
 	rename := true
 	oldFi, err := os.Lstat(destPath)
 	if err != nil {
-		if os.IsNotExist(err) {
+		if errors.Is(err, os.ErrNotExist) {
 			if kind != ChangeKindAdd {
-				return errors.Wrapf(err, "invalid addition: %s", destPath)
+				return errors.Wrap(err, "modify/rm")
 			}
 			rename = false
 		} else {
-			return errors.Wrapf(err, "failed to stat %s", destPath)
+			return errors.WithStack(err)
 		}
 	}
 
@@ -285,7 +285,6 @@ func (hw *hashedWriter) Digest() digest.Digest {
 
 type lazyFileWriter struct {
 	dest     string
-	ctx      context.Context
 	f        *os.File
 	fileMode *os.FileMode
 }
@@ -324,10 +323,6 @@ func (lfw *lazyFileWriter) Close() error {
 	return err
 }
 
-func mkdev(major int64, minor int64) uint32 {
-	return uint32(((minor & 0xfff00) << 12) | ((major & 0xfff) << 8) | (minor & 0xff))
-}
-
 // Random number state.
 // We generate random temporary file names so that there's a good
 // chance the file doesn't exist yet - keeps the number of tries in
diff --git a/diskwriter_freebsd.go b/diskwriter_freebsd.go
new file mode 100644
index 0000000..ed6356f
--- /dev/null
+++ b/diskwriter_freebsd.go
@@ -0,0 +1,17 @@
+//go:build freebsd
+// +build freebsd
+
+package fsutil
+
+import (
+	"github.com/tonistiigi/fsutil/types"
+	"golang.org/x/sys/unix"
+)
+
+func createSpecialFile(path string, mode uint32, stat *types.Stat) error {
+	return unix.Mknod(path, mode, mkdev(stat.Devmajor, stat.Devminor))
+}
+
+func mkdev(major int64, minor int64) uint64 {
+	return unix.Mkdev(uint32(major), uint32(minor))
+}
diff --git a/diskwriter_test.go b/diskwriter_test.go
index 459de86..4b6edb3 100644
--- a/diskwriter_test.go
+++ b/diskwriter_test.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"io"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"sync"
@@ -15,6 +14,8 @@ import (
 	"github.com/opencontainers/go-digest"
 	"github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+	"golang.org/x/sys/unix"
 )
 
 // requiresRoot skips tests that require root
@@ -37,9 +38,7 @@ func TestWriterSimple(t *testing.T) {
 		"ADD foo2 file >foo",
 	})
 
-	dest, err := ioutil.TempDir("", "dest")
-	assert.NoError(t, err)
-	defer os.RemoveAll(dest)
+	dest := t.TempDir()
 
 	dw, err := NewDiskWriter(context.TODO(), dest, DiskWriterOpt{
 		SyncDataCb: noOpWriteTo,
@@ -140,9 +139,7 @@ func TestWalkerWriterSimple(t *testing.T) {
 	assert.NoError(t, err)
 	defer os.RemoveAll(d)
 
-	dest, err := ioutil.TempDir("", "dest")
-	assert.NoError(t, err)
-	defer os.RemoveAll(dest)
+	dest := t.TempDir()
 
 	dw, err := NewDiskWriter(context.TODO(), dest, DiskWriterOpt{
 		SyncDataCb: newWriteToFunc(d, 0),
@@ -163,7 +160,7 @@ file foo
 file foo2
 `)
 
-	dt, err := ioutil.ReadFile(filepath.Join(dest, "foo"))
+	dt, err := os.ReadFile(filepath.Join(dest, "foo"))
 	assert.NoError(t, err)
 	assert.Equal(t, []byte("mydata"), dt)
 
@@ -181,9 +178,7 @@ func TestWalkerWriterAsync(t *testing.T) {
 	assert.NoError(t, err)
 	defer os.RemoveAll(d)
 
-	dest, err := ioutil.TempDir("", "dest")
-	assert.NoError(t, err)
-	defer os.RemoveAll(dest)
+	dest := t.TempDir()
 
 	dw, err := NewDiskWriter(context.TODO(), dest, DiskWriterOpt{
 		AsyncDataCb: newWriteToFunc(d, 300*time.Millisecond),
@@ -198,11 +193,11 @@ func TestWalkerWriterAsync(t *testing.T) {
 	err = dw.Wait(context.TODO())
 	assert.NoError(t, err)
 
-	dt, err := ioutil.ReadFile(filepath.Join(dest, "foo/foo3"))
+	dt, err := os.ReadFile(filepath.Join(dest, "foo/foo3"))
 	assert.NoError(t, err)
 	assert.Equal(t, "data3", string(dt))
 
-	dt, err = ioutil.ReadFile(filepath.Join(dest, "foo/foo4"))
+	dt, err = os.ReadFile(filepath.Join(dest, "foo/foo4"))
 	assert.NoError(t, err)
 	assert.Equal(t, "data3", string(dt))
 
@@ -216,7 +211,7 @@ func TestWalkerWriterAsync(t *testing.T) {
 		assert.Equal(t, stat1.Ino, stat2.Ino)
 	}
 
-	dt, err = ioutil.ReadFile(filepath.Join(dest, "foo5"))
+	dt, err = os.ReadFile(filepath.Join(dest, "foo5"))
 	assert.NoError(t, err)
 	assert.Equal(t, "data5", string(dt))
 
@@ -224,6 +219,53 @@ func TestWalkerWriterAsync(t *testing.T) {
 	assert.True(t, duration < 500*time.Millisecond)
 }
 
+func TestWalkerWriterDevices(t *testing.T) {
+	requiresRoot(t)
+
+	d, err := tmpDir(changeStream([]string{
+		"ADD foo dir",
+		"ADD foo/foo1 file data1",
+	}))
+	require.NoError(t, err)
+
+	err = unix.Mknod(filepath.Join(d, "foo/block"), syscall.S_IFBLK|0600, mkdev(2, 3))
+	require.NoError(t, err)
+
+	err = unix.Mknod(filepath.Join(d, "foo/char"), syscall.S_IFCHR|0400, mkdev(1, 9))
+	require.NoError(t, err)
+
+	dest := t.TempDir()
+
+	dw, err := NewDiskWriter(context.TODO(), dest, DiskWriterOpt{
+		SyncDataCb: newWriteToFunc(d, 0),
+	})
+	assert.NoError(t, err)
+
+	err = Walk(context.Background(), d, nil, readAsAdd(dw.HandleChange))
+	assert.NoError(t, err)
+
+	err = dw.Wait(context.TODO())
+	assert.NoError(t, err)
+
+	fi, err := os.Lstat(filepath.Join(dest, "foo/char"))
+	require.NoError(t, err)
+
+	stat, ok := fi.Sys().(*syscall.Stat_t)
+	require.True(t, ok)
+
+	assert.Equal(t, uint64(1), stat.Rdev>>8)
+	assert.Equal(t, uint64(9), stat.Rdev&0xff)
+
+	fi, err = os.Lstat(filepath.Join(dest, "foo/block"))
+	require.NoError(t, err)
+
+	stat, ok = fi.Sys().(*syscall.Stat_t)
+	require.True(t, ok)
+
+	assert.Equal(t, uint64(2), stat.Rdev>>8)
+	assert.Equal(t, uint64(3), stat.Rdev&0xff)
+}
+
 func readAsAdd(f HandleChangeFn) filepath.WalkFunc {
 	return func(path string, fi os.FileInfo, err error) error {
 		return f(ChangeKindAdd, path, fi, err)
diff --git a/diskwriter_unix.go b/diskwriter_unix.go
index ff0a22e..1d97d6f 100644
--- a/diskwriter_unix.go
+++ b/diskwriter_unix.go
@@ -1,3 +1,4 @@
+//go:build !windows
 // +build !windows
 
 package fsutil
@@ -17,17 +18,17 @@ func rewriteMetadata(p string, stat *types.Stat) error {
 	}
 
 	if err := os.Lchown(p, int(stat.Uid), int(stat.Gid)); err != nil {
-		return errors.Wrapf(err, "failed to lchown %s", p)
+		return errors.WithStack(err)
 	}
 
 	if os.FileMode(stat.Mode)&os.ModeSymlink == 0 {
 		if err := os.Chmod(p, os.FileMode(stat.Mode)); err != nil {
-			return errors.Wrapf(err, "failed to chown %s", p)
+			return errors.WithStack(err)
 		}
 	}
 
 	if err := chtimes(p, stat.ModTime); err != nil {
-		return errors.Wrapf(err, "failed to chtimes %s", p)
+		return err
 	}
 
 	return nil
@@ -45,8 +46,8 @@ func handleTarTypeBlockCharFifo(path string, stat *types.Stat) error {
 		mode |= syscall.S_IFBLK
 	}
 
-	if err := syscall.Mknod(path, mode, int(mkdev(stat.Devmajor, stat.Devminor))); err != nil {
-		return err
+	if err := createSpecialFile(path, mode, stat); err != nil {
+		return errors.WithStack(err)
 	}
 	return nil
 }
diff --git a/diskwriter_unixnobsd.go b/diskwriter_unixnobsd.go
new file mode 100644
index 0000000..927dba4
--- /dev/null
+++ b/diskwriter_unixnobsd.go
@@ -0,0 +1,17 @@
+//go:build !windows && !freebsd
+// +build !windows,!freebsd
+
+package fsutil
+
+import (
+	"github.com/tonistiigi/fsutil/types"
+	"golang.org/x/sys/unix"
+)
+
+func createSpecialFile(path string, mode uint32, stat *types.Stat) error {
+	return unix.Mknod(path, mode, mkdev(stat.Devmajor, stat.Devminor))
+}
+
+func mkdev(major int64, minor int64) int {
+	return int(unix.Mkdev(uint32(major), uint32(minor)))
+}
diff --git a/docker-bake.hcl b/docker-bake.hcl
new file mode 100644
index 0000000..3d7d182
--- /dev/null
+++ b/docker-bake.hcl
@@ -0,0 +1,67 @@
+variable "GO_VERSION" {
+  default = "1.18"
+}
+
+group "default" {
+  targets = ["build"]
+}
+
+target "build" {
+  args = {
+    GO_VERSION = "${GO_VERSION}"
+  }
+}
+
+group "test" {
+  targets = ["test-root", "test-noroot"]
+}
+
+target "test-root" {
+  inherits = ["build"]
+  target = "test"
+}
+
+target "test-noroot" {
+  inherits = ["build"]
+  target = "test-noroot"
+}
+
+target "lint" {
+  dockerfile = "./hack/dockerfiles/lint.Dockerfile"
+  args = {
+    GO_VERSION = "${GO_VERSION}"
+  }
+}
+
+target "validate-gomod" {
+  dockerfile = "./hack/dockerfiles/gomod.Dockerfile"
+  target = "validate"
+  args = {
+    # go mod may produce different results between go versions,
+    # if this becomes a problem, this should be switched to use
+    # a fixed go version.
+    GO_VERSION = "${GO_VERSION}"
+  }
+}
+
+target "gomod" {
+  inherits = ["validate-gomod"]
+  output = ["."]
+  target = "update"
+}
+
+target "validate-shfmt" {
+  dockerfile = "./hack/dockerfiles/shfmt.Dockerfile"
+  target = "validate"
+}
+
+target "shfmt" {
+  inherits = ["validate-shfmt"]
+  output = ["."]
+  target = "update"
+}
+
+target "cross" {
+  inherits = ["build"]
+  platforms = ["linux/amd64", "linux/386", "linux/arm64", "linux/arm", "linux/ppc64le", "linux/s390x", "darwin/amd64", "darwin/arm64", "windows/amd64", "windows/arm64", "freebsd/amd64", "freebsd/arm64"]
+}
diff --git a/followlinks.go b/followlinks.go
index ed4af6e..136a908 100644
--- a/followlinks.go
+++ b/followlinks.go
@@ -1,7 +1,6 @@
 package fsutil
 
 import (
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"runtime"
@@ -75,12 +74,12 @@ func (r *symlinkResolver) readSymlink(p string, allowWildcard bool) ([]string, e
 	realPath := filepath.Join(r.root, p)
 	base := filepath.Base(p)
 	if allowWildcard && containsWildcards(base) {
-		fis, err := ioutil.ReadDir(filepath.Dir(realPath))
+		fis, err := os.ReadDir(filepath.Dir(realPath))
 		if err != nil {
-			if os.IsNotExist(err) {
+			if errors.Is(err, os.ErrNotExist) {
 				return nil, nil
 			}
-			return nil, errors.Wrapf(err, "failed to read dir %s", filepath.Dir(realPath))
+			return nil, errors.Wrap(err, "readdir")
 		}
 		var out []string
 		for _, f := range fis {
@@ -97,17 +96,17 @@ func (r *symlinkResolver) readSymlink(p string, allowWildcard bool) ([]string, e
 
 	fi, err := os.Lstat(realPath)
 	if err != nil {
-		if os.IsNotExist(err) {
+		if errors.Is(err, os.ErrNotExist) {
 			return nil, nil
 		}
-		return nil, errors.Wrapf(err, "failed to lstat %s", realPath)
+		return nil, errors.WithStack(err)
 	}
 	if fi.Mode()&os.ModeSymlink == 0 {
 		return nil, nil
 	}
 	link, err := os.Readlink(realPath)
 	if err != nil {
-		return nil, errors.Wrapf(err, "failed to readlink %s", realPath)
+		return nil, errors.WithStack(err)
 	}
 	link = filepath.Clean(link)
 	if filepath.IsAbs(link) {
diff --git a/followlinks_test.go b/followlinks_test.go
index e618beb..522763f 100644
--- a/followlinks_test.go
+++ b/followlinks_test.go
@@ -1,8 +1,6 @@
 package fsutil
 
 import (
-	"io/ioutil"
-	"os"
 	"testing"
 
 	"github.com/containerd/continuity/fs/fstest"
@@ -10,9 +8,7 @@ import (
 )
 
 func TestFollowLinks(t *testing.T) {
-	tmpDir, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(tmpDir)
+	tmpDir := t.TempDir()
 
 	apply := fstest.Apply(
 		fstest.CreateDir("dir", 0700),
@@ -32,9 +28,7 @@ func TestFollowLinks(t *testing.T) {
 }
 
 func TestFollowLinksLoop(t *testing.T) {
-	tmpDir, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(tmpDir)
+	tmpDir := t.TempDir()
 
 	apply := fstest.Apply(
 		fstest.Symlink("l1", "l1"),
@@ -50,9 +44,7 @@ func TestFollowLinksLoop(t *testing.T) {
 }
 
 func TestFollowLinksAbsolute(t *testing.T) {
-	tmpDir, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(tmpDir)
+	tmpDir := t.TempDir()
 
 	apply := fstest.Apply(
 		fstest.CreateDir("dir", 0700),
@@ -69,9 +61,7 @@ func TestFollowLinksAbsolute(t *testing.T) {
 	require.Equal(t, out, []string{"baz", "dir/l1", "foo/bar"})
 
 	// same but a link outside root
-	tmpDir, err = ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(tmpDir)
+	tmpDir = t.TempDir()
 
 	apply = fstest.Apply(
 		fstest.CreateDir("dir", 0700),
@@ -89,9 +79,7 @@ func TestFollowLinksAbsolute(t *testing.T) {
 }
 
 func TestFollowLinksNotExists(t *testing.T) {
-	tmpDir, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(tmpDir)
+	tmpDir := t.TempDir()
 
 	out, err := FollowLinks(tmpDir, []string{"foo/bar/baz", "bar/baz"})
 	require.NoError(t, err)
@@ -111,9 +99,7 @@ func TestFollowLinksNotExists(t *testing.T) {
 }
 
 func TestFollowLinksNormalized(t *testing.T) {
-	tmpDir, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(tmpDir)
+	tmpDir := t.TempDir()
 
 	out, err := FollowLinks(tmpDir, []string{"foo/bar/baz", "foo/bar"})
 	require.NoError(t, err)
@@ -141,9 +127,7 @@ func TestFollowLinksNormalized(t *testing.T) {
 }
 
 func TestFollowLinksWildcard(t *testing.T) {
-	tmpDir, err := ioutil.TempDir("", "test")
-	require.NoError(t, err)
-	defer os.RemoveAll(tmpDir)
+	tmpDir := t.TempDir()
 
 	apply := fstest.Apply(
 		fstest.CreateDir("dir", 0700),
diff --git a/fs.go b/fs.go
index a9467e9..db587b7 100644
--- a/fs.go
+++ b/fs.go
@@ -3,12 +3,12 @@ package fsutil
 import (
 	"context"
 	"io"
-	"io/ioutil"
 	"os"
 	"path"
 	"path/filepath"
 	"sort"
 	"strings"
+	"syscall"
 
 	"github.com/pkg/errors"
 	"github.com/tonistiigi/fsutil/types"
@@ -36,7 +36,8 @@ func (fs *fs) Walk(ctx context.Context, fn filepath.WalkFunc) error {
 }
 
 func (fs *fs) Open(p string) (io.ReadCloser, error) {
-	return os.Open(filepath.Join(fs.root, p))
+	rc, err := os.Open(filepath.Join(fs.root, p))
+	return rc, errors.WithStack(err)
 }
 
 type Dir struct {
@@ -51,10 +52,10 @@ func SubDirFS(dirs []Dir) (FS, error) {
 	m := map[string]Dir{}
 	for _, d := range dirs {
 		if path.Base(d.Stat.Path) != d.Stat.Path {
-			return nil, errors.Errorf("subdir %s must be single file", d.Stat.Path)
+			return nil, errors.WithStack(&os.PathError{Path: d.Stat.Path, Err: syscall.EISDIR, Op: "invalid path"})
 		}
 		if _, ok := m[d.Stat.Path]; ok {
-			return nil, errors.Errorf("invalid path %s", d.Stat.Path)
+			return nil, errors.WithStack(&os.PathError{Path: d.Stat.Path, Err: syscall.EEXIST, Op: "duplicate path"})
 		}
 		m[d.Stat.Path] = d
 	}
@@ -70,7 +71,7 @@ func (fs *subDirFS) Walk(ctx context.Context, fn filepath.WalkFunc) error {
 	for _, d := range fs.dirs {
 		fi := &StatInfo{Stat: &d.Stat}
 		if !fi.IsDir() {
-			return errors.Errorf("fs subdir %s not mode directory", d.Stat.Path)
+			return errors.WithStack(&os.PathError{Path: d.Stat.Path, Err: syscall.ENOTDIR, Op: "walk subdir"})
 		}
 		if err := fn(d.Stat.Path, fi, nil); err != nil {
 			return err
@@ -78,7 +79,7 @@ func (fs *subDirFS) Walk(ctx context.Context, fn filepath.WalkFunc) error {
 		if err := d.FS.Walk(ctx, func(p string, fi os.FileInfo, err error) error {
 			stat, ok := fi.Sys().(*types.Stat)
 			if !ok {
-				return errors.Wrapf(err, "invalid fileinfo without stat info: %s", p)
+				return errors.WithStack(&os.PathError{Path: d.Stat.Path, Err: syscall.EBADMSG, Op: "fileinfo without stat info"})
 			}
 			stat.Path = path.Join(d.Stat.Path, stat.Path)
 			if stat.Linkname != "" {
@@ -101,11 +102,11 @@ func (fs *subDirFS) Walk(ctx context.Context, fn filepath.WalkFunc) error {
 func (fs *subDirFS) Open(p string) (io.ReadCloser, error) {
 	parts := strings.SplitN(filepath.Clean(p), string(filepath.Separator), 2)
 	if len(parts) == 0 {
-		return ioutil.NopCloser(&emptyReader{}), nil
+		return io.NopCloser(&emptyReader{}), nil
 	}
 	d, ok := fs.m[parts[0]]
 	if !ok {
-		return nil, os.ErrNotExist
+		return nil, errors.WithStack(&os.PathError{Path: parts[0], Err: syscall.ENOENT, Op: "open"})
 	}
 	return d.FS.Open(parts[1])
 }
diff --git a/go.mod b/go.mod
index fe8cc86..a229a00 100644
--- a/go.mod
+++ b/go.mod
@@ -1,28 +1,25 @@
 module github.com/tonistiigi/fsutil
 
+go 1.18
+
 require (
-	github.com/Microsoft/go-winio v0.4.11 // indirect
-	github.com/containerd/continuity v0.0.0-20181001140422-bd77b46c8352
-	github.com/davecgh/go-spew v1.1.1 // indirect
-	github.com/docker/docker v0.0.0-20180531152204-71cd53e4a197
-	github.com/docker/go-units v0.3.1 // indirect
-	github.com/gogo/protobuf v1.3.1
-	github.com/google/go-cmp v0.2.0 // indirect
-	github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect
-	github.com/onsi/ginkgo v1.7.0 // indirect
-	github.com/onsi/gomega v1.4.3 // indirect
-	github.com/opencontainers/go-digest v1.0.0-rc1
-	github.com/opencontainers/image-spec v1.0.1 // indirect
-	github.com/opencontainers/runc v1.0.0-rc6 // indirect
-	github.com/pkg/errors v0.8.1
-	github.com/sirupsen/logrus v1.0.3 // indirect
-	github.com/stretchr/testify v1.3.0
-	golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 // indirect
-	golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f
-	golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e
-	gopkg.in/airbrake/gobrake.v2 v2.0.9 // indirect
-	gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 // indirect
-	gotest.tools v2.1.0+incompatible // indirect
+	github.com/containerd/continuity v0.3.0
+	github.com/gogo/protobuf v1.3.2
+	github.com/moby/patternmatcher v0.5.0
+	github.com/opencontainers/go-digest v1.0.0
+	github.com/pkg/errors v0.9.1
+	github.com/stretchr/testify v1.7.0
+	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
+	golang.org/x/sys v0.0.0-20220412211240-33da011f77ad
 )
 
-go 1.13
+require (
+	github.com/Microsoft/go-winio v0.5.2 // indirect
+	github.com/davecgh/go-spew v1.1.1 // indirect
+	github.com/kr/pretty v0.2.0 // indirect
+	github.com/pmezard/go-difflib v1.0.0 // indirect
+	github.com/sirupsen/logrus v1.8.1 // indirect
+	google.golang.org/protobuf v1.26.0 // indirect
+	gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
+	gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
+)
diff --git a/go.sum b/go.sum
index 4adcb66..eb2b7c5 100644
--- a/go.sum
+++ b/go.sum
@@ -1,70 +1,76 @@
-github.com/Microsoft/go-winio v0.4.11 h1:zoIOcVf0xPN1tnMVbTtEdI+P8OofVk3NObnwOQ6nK2Q=
-github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
-github.com/containerd/continuity v0.0.0-20181001140422-bd77b46c8352 h1:CdBoaTKPl60tksFVWYc5QnLWwXBcU+XcLiXx8+NcZ9o=
-github.com/containerd/continuity v0.0.0-20181001140422-bd77b46c8352/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
+github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
+github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
+github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg=
+github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/docker/docker v0.0.0-20180531152204-71cd53e4a197 h1:raQhUHOMIAZAWHmo3hLEwoIy0aVkKb2uxZdWw/Up+HI=
-github.com/docker/docker v0.0.0-20180531152204-71cd53e4a197/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/go-units v0.3.1 h1:QAFdsA6jLCnglbqE6mUsHuPcJlntY94DkxHf4deHKIU=
-github.com/docker/go-units v0.3.1/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
-github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
-github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
-github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
-github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI=
-github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
-github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
-github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
-github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
-github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
-github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
-github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
-github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/runc v1.0.0-rc6 h1:7AoN22rYxxkmsJS48wFaziH/n0OvrZVqL/TglgHKbKQ=
-github.com/opencontainers/runc v1.0.0-rc6/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
-github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
+github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo=
+github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
+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/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.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/sirupsen/logrus v1.0.3 h1:B5C/igNWoiULof20pKfY4VntcIPqKuwEmoLZrabbUrc=
-github.com/sirupsen/logrus v1.0.3/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
+github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
+github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
-golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
-golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
-golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
+golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo=
-gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
-gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 h1:OAj3g0cR6Dx/R07QgQe8wkA9RNjB2u4i700xBkIT4e0=
-gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
-gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
-gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gotest.tools v2.1.0+incompatible h1:5USw7CrJBYKqjg9R7QlA6jzqZKEAtvW82aNmsxxGPxw=
-gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/hack/Vagrantfile.freebsd13 b/hack/Vagrantfile.freebsd13
new file mode 100644
index 0000000..ca34513
--- /dev/null
+++ b/hack/Vagrantfile.freebsd13
@@ -0,0 +1,37 @@
+# This code is taken from the Vagrantfile from libjail-rs
+# https://github.com/fubarnetes/libjail-rs/blob/727353bd6565c5e7a9be2664258d0197a1c8bb35/Vagrantfile
+# licensed under BSD-3 Clause License:
+# BSD 3-Clause License
+
+# Copyright (c) 2018, Fabian Freyer <fabian.freyer@physik.tu-berlin.de> All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+# * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+# * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+# * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Vagrant.configure("2") do |config|
+  # Unreleased version
+  #
+  # config.vm.define "fbsd_14_0" do |fbsd_14_0|
+  #   fbsd_14_0.vm.box = "freebsd/FreeBSD-14.0-CURRENT"
+  # end
+
+  # Stable version
+  #
+  config.vm.define "fbsd_13_0" do |fbsd_13_0|
+    fbsd_13_0.vm.box = "freebsd/FreeBSD-13.0-STABLE"
+  end
+
+  config.vm.synced_folder ".", "/vagrant", type: "rsync", rsync__auto: true
+
+  config.vm.provision "shell", inline: <<-SHELL
+    pkg bootstrap
+    pkg install -y go
+  SHELL
+end
diff --git a/hack/dockerfiles/gomod.Dockerfile b/hack/dockerfiles/gomod.Dockerfile
new file mode 100644
index 0000000..1981caf
--- /dev/null
+++ b/hack/dockerfiles/gomod.Dockerfile
@@ -0,0 +1,21 @@
+# syntax=docker/dockerfile:1
+ARG GO_VERSION=1.18
+
+FROM golang:${GO_VERSION}-alpine AS gomod
+RUN  apk add --no-cache git
+WORKDIR /src
+RUN --mount=target=/src,rw \
+  --mount=target=/go/pkg/mod,type=cache \
+  go mod tidy && \
+  mkdir /out && cp -r go.mod go.sum /out && \
+  cd bench && go mod tidy && \
+  mkdir /out/bench && cp -r go.mod go.sum /out/bench
+
+FROM scratch AS update
+COPY --from=gomod /out /
+
+FROM gomod AS validate
+RUN --mount=target=.,rw \
+  git add -A && \
+  cp -rf /out/* . && \
+  ./hack/validate-gomod check
diff --git a/hack/dockerfiles/lint.Dockerfile b/hack/dockerfiles/lint.Dockerfile
new file mode 100644
index 0000000..da48d4a
--- /dev/null
+++ b/hack/dockerfiles/lint.Dockerfile
@@ -0,0 +1,9 @@
+# syntax=docker/dockerfile:1
+ARG GO_VERSION=1.18
+
+FROM golang:${GO_VERSION}-alpine
+RUN apk add --no-cache git gcc musl-dev
+RUN wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.49.0
+WORKDIR /go/src/github.com/tonistiigi/fsutil
+RUN --mount=target=/go/src/github.com/tonistiigi/fsutil --mount=target=/root/.cache,type=cache --mount=target=/go/pkg/mod,type=cache \
+  golangci-lint run
diff --git a/hack/dockerfiles/shfmt.Dockerfile b/hack/dockerfiles/shfmt.Dockerfile
new file mode 100644
index 0000000..b57b1e3
--- /dev/null
+++ b/hack/dockerfiles/shfmt.Dockerfile
@@ -0,0 +1,16 @@
+# syntax=docker/dockerfile:1
+FROM mvdan/shfmt:v3.4.3-alpine AS shfmt
+WORKDIR /src
+ARG SHFMT_FLAGS="-i 2 -ci"
+
+FROM shfmt AS generate
+RUN --mount=target=/src,rw \
+  shfmt -l -w $SHFMT_FLAGS ./hack && \
+  mkdir -p /out && cp -r ./hack /out/
+
+FROM scratch AS update
+COPY --from=generate /out /
+
+FROM shfmt AS validate
+RUN --mount=target=. \
+  shfmt $SHFMT_FLAGS -d ./hack
diff --git a/hack/lint b/hack/lint
new file mode 100755
index 0000000..30b8e29
--- /dev/null
+++ b/hack/lint
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+
+set -eu -o pipefail -x
+
+: ${CONTINUOUS_INTEGRATION=}
+
+progressFlag=""
+if [ "$CONTINUOUS_INTEGRATION" == "true" ]; then progressFlag="--progress=plain"; fi
+
+cacheOnlyFlag=""
+if ! docker build --help 2>&1 | grep buildx >/dev/null; then cacheOnlyFlag="-o type=cacheonly"; fi
+
+export DOCKER_BUILDKIT=1
+docker build $progressFlag $cacheOnlyFlag -f ./hack/dockerfiles/lint.Dockerfile .
diff --git a/hack/shfmt b/hack/shfmt
new file mode 100755
index 0000000..1859e2c
--- /dev/null
+++ b/hack/shfmt
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+set -eu -o pipefail -x
+
+: ${CONTINUOUS_INTEGRATION=}
+
+progressFlag=""
+if [ "$CONTINUOUS_INTEGRATION" == "true" ]; then progressFlag="--progress=plain"; fi
+
+export DOCKER_BUILDKIT=1
+docker build $progressFlag -f ./hack/dockerfiles/shfmt.Dockerfile --target update -o . .
diff --git a/hack/update-gomod b/hack/update-gomod
new file mode 100755
index 0000000..1615ee6
--- /dev/null
+++ b/hack/update-gomod
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+set -eu -o pipefail -x
+
+: ${CONTINUOUS_INTEGRATION=}
+
+progressFlag=""
+if [ "$CONTINUOUS_INTEGRATION" == "true" ]; then progressFlag="--progress=plain"; fi
+
+export DOCKER_BUILDKIT=1
+docker build $progressFlag -f ./hack/dockerfiles/gomod.Dockerfile --target update -o . .
diff --git a/hack/validate-gomod b/hack/validate-gomod
new file mode 100755
index 0000000..e9340c9
--- /dev/null
+++ b/hack/validate-gomod
@@ -0,0 +1,36 @@
+#!/usr/bin/env sh
+
+set -eu
+
+: ${CONTINUOUS_INTEGRATION=}
+: ${DOCKER_BUILDKIT=}
+
+progressFlag=""
+if [ "$CONTINUOUS_INTEGRATION" = "true" ]; then progressFlag="--progress=plain"; fi
+
+cacheOnlyFlag=""
+if ! docker build --help 2>&1 | grep buildx >/dev/null; then cacheOnlyFlag="-o type=cacheonly"; fi
+
+case ${1:-} in
+  '')
+    export DOCKER_BUILDKIT=1
+    docker build $progressFlag $cacheOnlyFlag -f ./hack/dockerfiles/gomod.Dockerfile --target validate . || exit 1
+    ;;
+  check)
+    status="$(git status --porcelain -- go.mod go.sum bench/go.mod bench/go.sum 2>/dev/null)"
+    diffs=$(echo "$status" | grep -v '^[RAD] ' || true)
+    if [ "$diffs" ]; then
+      {
+        set +x
+        echo 'The result of "./hack/validate-gomod" differs'
+        echo
+        echo "$diffs"
+        echo
+        echo 'Please vendor your package with "./hack/update-gomod"'
+        echo
+      } >&2
+      exit 1
+    fi
+    echo 'Congratulations! go.mod is done the right way.'
+    ;;
+esac
diff --git a/hack/validate-shfmt b/hack/validate-shfmt
new file mode 100755
index 0000000..7e838c1
--- /dev/null
+++ b/hack/validate-shfmt
@@ -0,0 +1,15 @@
+#!/usr/bin/env sh
+
+set -eu
+
+: ${CONTINUOUS_INTEGRATION=}
+: ${DOCKER_BUILDKIT=}
+
+progressFlag=""
+if [ "$CONTINUOUS_INTEGRATION" = "true" ]; then progressFlag="--progress=plain"; fi
+
+cacheOnlyFlag=""
+if ! docker build --help 2>&1 | grep buildx >/dev/null; then cacheOnlyFlag="-o type=cacheonly"; fi
+
+export DOCKER_BUILDKIT=1
+docker build $progressFlag $cacheOnlyFlag -f ./hack/dockerfiles/shfmt.Dockerfile --target validate .
diff --git a/hardlinks.go b/hardlinks.go
index d977f0d..ef8bbfb 100644
--- a/hardlinks.go
+++ b/hardlinks.go
@@ -2,6 +2,7 @@ package fsutil
 
 import (
 	"os"
+	"syscall"
 
 	"github.com/pkg/errors"
 	"github.com/tonistiigi/fsutil/types"
@@ -28,7 +29,7 @@ func (v *Hardlinks) HandleChange(kind ChangeKind, p string, fi os.FileInfo, err
 
 	stat, ok := fi.Sys().(*types.Stat)
 	if !ok {
-		return errors.Errorf("invalid change without stat info: %s", p)
+		return errors.WithStack(&os.PathError{Path: p, Err: syscall.EBADMSG, Op: "change without stat info"})
 	}
 
 	if fi.IsDir() || fi.Mode()&os.ModeSymlink != 0 {
diff --git a/receive.go b/receive.go
index 0210dcd..209d1d2 100644
--- a/receive.go
+++ b/receive.go
@@ -11,16 +11,25 @@ import (
 	"golang.org/x/sync/errgroup"
 )
 
+type DiffType int
+
+const (
+	DiffMetadata DiffType = iota
+	DiffNone
+	DiffContent
+)
+
 type ReceiveOpt struct {
 	NotifyHashed  ChangeFunc
 	ContentHasher ContentHasher
 	ProgressCb    func(int, bool)
 	Merge         bool
 	Filter        FilterFunc
+	Differ        DiffType
 }
 
 func Receive(ctx context.Context, conn Stream, dest string, opt ReceiveOpt) error {
-	ctx, cancel := context.WithCancel(context.Background())
+	ctx, cancel := context.WithCancel(ctx)
 	defer cancel()
 
 	r := &receiver{
@@ -33,6 +42,7 @@ func Receive(ctx context.Context, conn Stream, dest string, opt ReceiveOpt) erro
 		progressCb:    opt.ProgressCb,
 		merge:         opt.Merge,
 		filter:        opt.Filter,
+		differ:        opt.Differ,
 	}
 	return r.run(ctx)
 }
@@ -47,6 +57,7 @@ type receiver struct {
 	progressCb func(int, bool)
 	merge      bool
 	filter     FilterFunc
+	differ     DiffType
 
 	notifyHashed   ChangeFunc
 	contentHasher  ContentHasher
@@ -105,7 +116,6 @@ func (w *dynamicWalker) fill(ctx context.Context, pathC chan<- *currentPath) err
 			return ctx.Err()
 		}
 	}
-	return nil
 }
 
 func (r *receiver) run(ctx context.Context) error {
@@ -131,9 +141,9 @@ func (r *receiver) run(ctx context.Context) error {
 		}()
 		destWalker := emptyWalker
 		if !r.merge {
-			destWalker = GetWalkerFn(r.dest)
+			destWalker = getWalkerFn(r.dest)
 		}
-		err := doubleWalkDiff(ctx, dw.HandleChange, destWalker, w.fill, r.filter)
+		err := doubleWalkDiff(ctx, dw.HandleChange, destWalker, w.fill, r.filter, r.differ)
 		if err != nil {
 			return err
 		}
diff --git a/receive_test.go b/receive_test.go
index c5a182f..6faefdc 100644
--- a/receive_test.go
+++ b/receive_test.go
@@ -6,7 +6,6 @@ import (
 	"crypto/sha256"
 	"hash"
 	"io"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"sync"
@@ -28,9 +27,7 @@ func TestInvalidExcludePatterns(t *testing.T) {
 	assert.NoError(t, err)
 	defer os.RemoveAll(d)
 
-	dest, err := ioutil.TempDir("", "dest")
-	assert.NoError(t, err)
-	defer os.RemoveAll(dest)
+	dest := t.TempDir()
 
 	ts := newNotificationBuffer()
 	chs := &changes{fn: ts.HandleChange}
@@ -40,13 +37,18 @@ func TestInvalidExcludePatterns(t *testing.T) {
 
 	eg.Go(func() error {
 		defer s1.(*fakeConnProto).closeSend()
-		return Send(ctx, s1, NewFS(d, &WalkOpt{ExcludePatterns: []string{"!"}}), nil)
+		err := Send(ctx, s1, NewFS(d, &WalkOpt{ExcludePatterns: []string{"!"}}), nil)
+		assert.Contains(t, err.Error(), "invalid excludepatterns")
+		return err
 	})
 	eg.Go(func() error {
-		return Receive(ctx, s2, dest, ReceiveOpt{
+		err := Receive(ctx, s2, dest, ReceiveOpt{
 			NotifyHashed:  chs.HandleChange,
 			ContentHasher: simpleSHA256Hasher,
 		})
+		assert.Contains(t, err.Error(), "error from sender:")
+		assert.Contains(t, err.Error(), "invalid excludepatterns")
+		return err
 	})
 
 	errCh := make(chan error)
@@ -57,7 +59,7 @@ func TestInvalidExcludePatterns(t *testing.T) {
 	case <-time.After(15 * time.Second):
 		t.Fatal("timeout")
 	case err = <-errCh:
-		assert.Contains(t, err.Error(), "error from sender:")
+		assert.Contains(t, err.Error(), "invalid excludepatterns")
 	}
 }
 
@@ -71,9 +73,7 @@ func TestCopyWithSubDir(t *testing.T) {
 	assert.NoError(t, err)
 	defer os.RemoveAll(d)
 
-	dest, err := ioutil.TempDir("", "dest")
-	assert.NoError(t, err)
-	defer os.RemoveAll(dest)
+	dest := t.TempDir()
 
 	eg, ctx := errgroup.WithContext(context.Background())
 	s1, s2 := sockPairProto(ctx)
@@ -93,7 +93,7 @@ func TestCopyWithSubDir(t *testing.T) {
 	err = eg.Wait()
 	assert.NoError(t, err)
 
-	dt, err := ioutil.ReadFile(filepath.Join(dest, "sub/foo/bar"))
+	dt, err := os.ReadFile(filepath.Join(dest, "sub/foo/bar"))
 	assert.NoError(t, err)
 	assert.Equal(t, "data1", string(dt))
 }
@@ -122,10 +122,10 @@ func TestCopySwitchDirToFile(t *testing.T) {
 		eg.Go(func() error {
 			defer s1.(*fakeConnProto).closeSend()
 			return Send(ctx, s1, NewFS(src, &WalkOpt{
-				Map: func(_ string, s *types.Stat) bool {
+				Map: func(_ string, s *types.Stat) MapResult {
 					s.Uid = 0
 					s.Gid = 0
-					return true
+					return MapResultKeep
 				},
 			}), nil)
 		})
@@ -178,9 +178,7 @@ func TestCopySimple(t *testing.T) {
 	assert.NoError(t, err)
 	defer os.RemoveAll(d)
 
-	dest, err := ioutil.TempDir("", "dest")
-	assert.NoError(t, err)
-	defer os.RemoveAll(dest)
+	dest := t.TempDir()
 
 	ts := newNotificationBuffer()
 	chs := &changes{fn: ts.HandleChange}
@@ -193,10 +191,10 @@ func TestCopySimple(t *testing.T) {
 	eg.Go(func() error {
 		defer s1.(*fakeConnProto).closeSend()
 		return Send(ctx, s1, NewFS(d, &WalkOpt{
-			Map: func(_ string, s *types.Stat) bool {
+			Map: func(_ string, s *types.Stat) MapResult {
 				s.Uid = 0
 				s.Gid = 0
-				return true
+				return MapResultKeep
 			},
 		}), nil)
 	})
@@ -229,11 +227,11 @@ symlink:../../ zzz/bb/cc/dd
 file zzz.aa
 `)
 
-	dt, err := ioutil.ReadFile(filepath.Join(dest, "zzz/aa"))
+	dt, err := os.ReadFile(filepath.Join(dest, "zzz/aa"))
 	assert.NoError(t, err)
 	assert.Equal(t, "data3", string(dt))
 
-	dt, err = ioutil.ReadFile(filepath.Join(dest, "foo2"))
+	dt, err = os.ReadFile(filepath.Join(dest, "foo2"))
 	assert.NoError(t, err)
 	assert.Equal(t, "dat2", string(dt))
 
@@ -257,7 +255,7 @@ file zzz.aa
 	assert.Equal(t, ok, true)
 	assert.Equal(t, k, ChangeKindAdd)
 
-	err = ioutil.WriteFile(filepath.Join(d, "zzz/bb/cc/foo"), []byte("data5"), 0600)
+	err = os.WriteFile(filepath.Join(d, "zzz/bb/cc/foo"), []byte("data5"), 0600)
 	assert.NoError(t, err)
 
 	err = os.RemoveAll(filepath.Join(d, "foo2"))
@@ -271,10 +269,10 @@ file zzz.aa
 	eg.Go(func() error {
 		defer s1.(*fakeConnProto).closeSend()
 		return Send(ctx, s1, NewFS(d, &WalkOpt{
-			Map: func(_ string, s *types.Stat) bool {
+			Map: func(_ string, s *types.Stat) MapResult {
 				s.Uid = 0
 				s.Gid = 0
-				return true
+				return MapResultKeep
 			},
 		}), nil)
 	})
@@ -307,7 +305,7 @@ file zzz/bb/cc/foo
 file zzz.aa
 `)
 
-	dt, err = ioutil.ReadFile(filepath.Join(dest, "zzz/bb/cc/foo"))
+	dt, err = os.ReadFile(filepath.Join(dest, "zzz/bb/cc/foo"))
 	assert.NoError(t, err)
 	assert.Equal(t, "data5", string(dt))
 
@@ -337,28 +335,25 @@ file zzz.aa
 	assert.Equal(t, ok, false)
 }
 
-func sockPair(ctx context.Context) (Stream, Stream) {
-	c1 := make(chan *types.Packet, 32)
-	c2 := make(chan *types.Packet, 32)
-	return &fakeConn{ctx, c1, c2}, &fakeConn{ctx, c2, c1}
-}
-
 func sockPairProto(ctx context.Context) (Stream, Stream) {
 	c1 := make(chan []byte, 32)
 	c2 := make(chan []byte, 32)
 	return &fakeConnProto{ctx, c1, c2}, &fakeConnProto{ctx, c2, c1}
 }
 
+//nolint:unused
 type fakeConn struct {
 	ctx      context.Context
 	recvChan chan *types.Packet
 	sendChan chan *types.Packet
 }
 
+//nolint:unused
 func (fc *fakeConn) Context() context.Context {
 	return fc.ctx
 }
 
+//nolint:unused
 func (fc *fakeConn) RecvMsg(m interface{}) error {
 	p, ok := m.(*types.Packet)
 	if !ok {
@@ -373,6 +368,7 @@ func (fc *fakeConn) RecvMsg(m interface{}) error {
 	}
 }
 
+//nolint:unused
 func (fc *fakeConn) SendMsg(m interface{}) error {
 	p, ok := m.(*types.Packet)
 	if !ok {
@@ -455,6 +451,9 @@ func simpleSHA256Hasher(s *types.Stat) (hash.Hash, error) {
 	h := sha256.New()
 	ss := *s
 	ss.ModTime = 0
+	// Unlike Linux, on FreeBSD's stat() call returns -1 in st_rdev for regular files
+	ss.Devminor = 0
+	ss.Devmajor = 0
 
 	if os.FileMode(ss.Mode)&os.ModeSymlink != 0 {
 		ss.Mode = ss.Mode | 0777
diff --git a/send.go b/send.go
index e7c5a37..2c1a380 100644
--- a/send.go
+++ b/send.go
@@ -5,6 +5,7 @@ import (
 	"io"
 	"os"
 	"sync"
+	"syscall"
 
 	"github.com/pkg/errors"
 	"github.com/tonistiigi/fsutil/types"
@@ -13,7 +14,8 @@ import (
 
 var bufPool = sync.Pool{
 	New: func() interface{} {
-		return make([]byte, 32*1<<10)
+		buf := make([]byte, 32*1<<10)
+		return &buf
 	},
 }
 
@@ -131,9 +133,9 @@ func (s *sender) sendFile(h *sendHandle) error {
 	f, err := s.fs.Open(h.path)
 	if err == nil {
 		defer f.Close()
-		buf := bufPool.Get().([]byte)
+		buf := bufPool.Get().(*[]byte)
 		defer bufPool.Put(buf)
-		if _, err := io.CopyBuffer(&fileSender{sender: s, id: h.id}, f, buf); err != nil {
+		if _, err := io.CopyBuffer(&fileSender{sender: s, id: h.id}, f, *buf); err != nil {
 			return err
 		}
 	}
@@ -148,7 +150,7 @@ func (s *sender) walk(ctx context.Context) error {
 		}
 		stat, ok := fi.Sys().(*types.Stat)
 		if !ok {
-			return errors.Wrapf(err, "invalid fileinfo without stat info: %s", path)
+			return errors.WithStack(&os.PathError{Path: path, Err: syscall.EBADMSG, Op: "fileinfo without stat info"})
 		}
 
 		p := &types.Packet{
diff --git a/stat.go b/stat.go
index 789dce3..2ab8da1 100644
--- a/stat.go
+++ b/stat.go
@@ -31,13 +31,13 @@ func mkstat(path, relpath string, fi os.FileInfo, inodemap map[uint64]string) (*
 		if fi.Mode()&os.ModeSymlink != 0 {
 			link, err := os.Readlink(path)
 			if err != nil {
-				return nil, errors.Wrapf(err, "failed to readlink %s", path)
+				return nil, errors.WithStack(err)
 			}
 			stat.Linkname = link
 		}
 	}
 	if err := loadXattr(path, stat); err != nil {
-		return nil, errors.Wrapf(err, "failed to xattr %s", relpath)
+		return nil, err
 	}
 
 	if runtime.GOOS == "windows" {
@@ -58,7 +58,7 @@ func mkstat(path, relpath string, fi os.FileInfo, inodemap map[uint64]string) (*
 func Stat(path string) (*types.Stat, error) {
 	fi, err := os.Lstat(path)
 	if err != nil {
-		return nil, errors.Wrap(err, "os stat")
+		return nil, errors.WithStack(err)
 	}
 	return mkstat(path, filepath.Base(path), fi, nil)
 }
diff --git a/stat_unix.go b/stat_unix.go
index af08522..5923aef 100644
--- a/stat_unix.go
+++ b/stat_unix.go
@@ -1,3 +1,4 @@
+//go:build !windows
 // +build !windows
 
 package fsutil
@@ -14,7 +15,7 @@ import (
 func loadXattr(origpath string, stat *types.Stat) error {
 	xattrs, err := sysx.LListxattr(origpath)
 	if err != nil {
-		if errors.Cause(err) == syscall.ENOTSUP {
+		if errors.Is(err, syscall.ENOTSUP) {
 			return nil
 		}
 		return errors.Wrapf(err, "failed to xattr %s", origpath)
diff --git a/tarwriter.go b/tarwriter.go
index 06f28c5..bd46a22 100644
--- a/tarwriter.go
+++ b/tarwriter.go
@@ -7,6 +7,7 @@ import (
 	"os"
 	"path/filepath"
 	"strings"
+	"syscall"
 
 	"github.com/pkg/errors"
 	"github.com/tonistiigi/fsutil/types"
@@ -15,9 +16,12 @@ import (
 func WriteTar(ctx context.Context, fs FS, w io.Writer) error {
 	tw := tar.NewWriter(w)
 	err := fs.Walk(ctx, func(path string, fi os.FileInfo, err error) error {
+		if err != nil && !errors.Is(err, os.ErrNotExist) {
+			return err
+		}
 		stat, ok := fi.Sys().(*types.Stat)
 		if !ok {
-			return errors.Wrapf(err, "invalid fileinfo without stat info: %s", path)
+			return errors.WithStack(&os.PathError{Path: path, Err: syscall.EBADMSG, Op: "fileinfo without stat info"})
 		}
 		hdr, err := tar.FileInfoHeader(fi, stat.Linkname)
 		if err != nil {
@@ -37,7 +41,7 @@ func WriteTar(ctx context.Context, fs FS, w io.Writer) error {
 		hdr.Linkname = stat.Linkname
 		if hdr.Linkname != "" {
 			hdr.Size = 0
-			if fi.Mode() & os.ModeSymlink != 0 {
+			if fi.Mode()&os.ModeSymlink != 0 {
 				hdr.Typeflag = tar.TypeSymlink
 			} else {
 				hdr.Typeflag = tar.TypeLink
@@ -52,7 +56,7 @@ func WriteTar(ctx context.Context, fs FS, w io.Writer) error {
 		}
 
 		if err := tw.WriteHeader(hdr); err != nil {
-			return errors.Wrap(err, "failed to write file header")
+			return errors.Wrapf(err, "failed to write file header %s", name)
 		}
 
 		if hdr.Typeflag == tar.TypeReg && hdr.Size > 0 && hdr.Linkname == "" {
@@ -61,10 +65,10 @@ func WriteTar(ctx context.Context, fs FS, w io.Writer) error {
 				return err
 			}
 			if _, err := io.Copy(tw, rc); err != nil {
-				return err
+				return errors.WithStack(err)
 			}
 			if err := rc.Close(); err != nil {
-				return err
+				return errors.WithStack(err)
 			}
 		}
 		return nil
diff --git a/util/protostream.go b/util/protostream.go
index d12d794..e0e0917 100644
--- a/util/protostream.go
+++ b/util/protostream.go
@@ -11,7 +11,8 @@ import (
 
 var bufPool = sync.Pool{
 	New: func() interface{} {
-		return make([]byte, 32*1<<10)
+		buf := make([]byte, 32*1<<10)
+		return &buf
 	},
 }
 
@@ -38,13 +39,13 @@ func (c *protoStream) RecvMsg(m interface{}) error {
 	if length == 0 {
 		return nil
 	}
-	buf := bufPool.Get().([]byte)
+	buf := *bufPool.Get().(*[]byte)
 	if cap(buf) < int(length) {
 		buf = make([]byte, length)
 	} else {
 		buf = buf[:length]
 	}
-	defer bufPool.Put(buf)
+	defer bufPool.Put(&buf)
 	if _, err := io.ReadFull(c.Reader, buf); err != nil {
 		return err
 	}
@@ -55,7 +56,7 @@ func (c *protoStream) RecvMsg(m interface{}) error {
 	return nil
 }
 
-func (fc *protoStream) SendMsg(m interface{}) error {
+func (c *protoStream) SendMsg(m interface{}) error {
 	type marshalerSizer interface {
 		MarshalTo([]byte) (int, error)
 		Size() int
@@ -67,10 +68,10 @@ func (fc *protoStream) SendMsg(m interface{}) error {
 	if _, err := msg.MarshalTo(b[4:]); err != nil {
 		return err
 	}
-	_, err := fc.Writer.Write(b)
+	_, err := c.Writer.Write(b)
 	return err
 }
 
-func (fc *protoStream) Context() context.Context {
-	return fc.ctx
+func (c *protoStream) Context() context.Context {
+	return c.ctx
 }
diff --git a/validator.go b/validator.go
index 2bd1287..9bd7d94 100644
--- a/validator.go
+++ b/validator.go
@@ -6,6 +6,7 @@ import (
 	"runtime"
 	"sort"
 	"strings"
+	"syscall"
 
 	"github.com/pkg/errors"
 )
@@ -31,10 +32,10 @@ func (v *Validator) HandleChange(kind ChangeKind, p string, fi os.FileInfo, err
 		p = strings.Replace(p, "\\", "", -1)
 	}
 	if p != path.Clean(p) {
-		return errors.Errorf("invalid unclean path %s", p)
+		return errors.WithStack(&os.PathError{Path: p, Err: syscall.EINVAL, Op: "unclean path"})
 	}
 	if path.IsAbs(p) {
-		return errors.Errorf("abolute path %s not allowed", p)
+		return errors.WithStack(&os.PathError{Path: p, Err: syscall.EINVAL, Op: "absolute path"})
 	}
 	dir := path.Dir(p)
 	base := path.Base(p)
@@ -42,7 +43,7 @@ func (v *Validator) HandleChange(kind ChangeKind, p string, fi os.FileInfo, err
 		dir = ""
 	}
 	if dir == ".." || strings.HasPrefix(p, "../") {
-		return errors.Errorf("invalid path: %s", p)
+		return errors.WithStack(&os.PathError{Path: p, Err: syscall.EINVAL, Op: "escape check"})
 	}
 
 	// find a parent dir from saved records
diff --git a/walker.go b/walker.go
index e0518e2..f95101f 100644
--- a/walker.go
+++ b/walker.go
@@ -8,7 +8,7 @@ import (
 	"syscall"
 	"time"
 
-	"github.com/docker/docker/pkg/fileutils"
+	"github.com/moby/patternmatcher"
 	"github.com/pkg/errors"
 	"github.com/tonistiigi/fsutil/types"
 )
@@ -19,36 +19,51 @@ type WalkOpt struct {
 	// FollowPaths contains symlinks that are resolved into include patterns
 	// before performing the fs walk
 	FollowPaths []string
-	Map         FilterFunc
+	Map         MapFunc
 }
 
+type MapFunc func(string, *types.Stat) MapResult
+
+// The result of the walk function controls
+// both how WalkDir continues and whether the path is kept.
+type MapResult int
+
+const (
+	// Keep the current path and continue.
+	MapResultKeep MapResult = iota
+
+	// Exclude the current path and continue.
+	MapResultExclude
+
+	// Exclude the current path, and skip the rest of the dir.
+	// If path is a dir, skip the current directory.
+	// If path is a file, skip the rest of the parent directory.
+	// (This matches the semantics of fs.SkipDir.)
+	MapResultSkipDir
+)
+
 func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) error {
 	root, err := filepath.EvalSymlinks(p)
 	if err != nil {
-		return errors.Wrapf(err, "failed to resolve %s", root)
+		return errors.WithStack(&os.PathError{Op: "resolve", Path: root, Err: err})
 	}
 	fi, err := os.Stat(root)
 	if err != nil {
-		return errors.Wrapf(err, "failed to stat: %s", root)
+		return errors.WithStack(err)
 	}
 	if !fi.IsDir() {
-		return errors.Errorf("%s is not a directory", root)
+		return errors.WithStack(&os.PathError{Op: "walk", Path: root, Err: syscall.ENOTDIR})
 	}
 
-	var pm *fileutils.PatternMatcher
-	if opt != nil && opt.ExcludePatterns != nil {
-		pm, err = fileutils.NewPatternMatcher(opt.ExcludePatterns)
-		if err != nil {
-			return errors.Wrapf(err, "invalid excludepaths %s", opt.ExcludePatterns)
-		}
-	}
+	var (
+		includePatterns []string
+		includeMatcher  *patternmatcher.PatternMatcher
+		excludeMatcher  *patternmatcher.PatternMatcher
+	)
 
-	var includePatterns []string
 	if opt != nil && opt.IncludePatterns != nil {
 		includePatterns = make([]string, len(opt.IncludePatterns))
-		for k := range opt.IncludePatterns {
-			includePatterns[k] = filepath.Clean(opt.IncludePatterns[k])
-		}
+		copy(includePatterns, opt.IncludePatterns)
 	}
 	if opt != nil && opt.FollowPaths != nil {
 		targets, err := FollowLinks(p, opt.FollowPaths)
@@ -61,21 +76,63 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err
 		}
 	}
 
-	var lastIncludedDir string
+	patternChars := "*[]?^"
+	if os.PathSeparator != '\\' {
+		patternChars += `\`
+	}
 
-	seenFiles := make(map[uint64]string)
-	return filepath.Walk(root, func(path string, fi os.FileInfo, err error) (retErr error) {
+	onlyPrefixIncludes := true
+	if len(includePatterns) != 0 {
+		includeMatcher, err = patternmatcher.New(includePatterns)
 		if err != nil {
-			if os.IsNotExist(err) {
-				return filepath.SkipDir
+			return errors.Wrapf(err, "invalid includepatterns: %s", opt.IncludePatterns)
+		}
+
+		for _, p := range includeMatcher.Patterns() {
+			if !p.Exclusion() && strings.ContainsAny(patternWithoutTrailingGlob(p), patternChars) {
+				onlyPrefixIncludes = false
+				break
+			}
+		}
+
+	}
+
+	onlyPrefixExcludeExceptions := true
+	if opt != nil && opt.ExcludePatterns != nil {
+		excludeMatcher, err = patternmatcher.New(opt.ExcludePatterns)
+		if err != nil {
+			return errors.Wrapf(err, "invalid excludepatterns: %s", opt.ExcludePatterns)
+		}
+
+		for _, p := range excludeMatcher.Patterns() {
+			if p.Exclusion() && strings.ContainsAny(patternWithoutTrailingGlob(p), patternChars) {
+				onlyPrefixExcludeExceptions = false
+				break
 			}
-			return err
 		}
+	}
+
+	type visitedDir struct {
+		fi               os.FileInfo
+		path             string
+		origpath         string
+		pathWithSep      string
+		includeMatchInfo patternmatcher.MatchInfo
+		excludeMatchInfo patternmatcher.MatchInfo
+		calledFn         bool
+	}
+
+	// used only for include/exclude handling
+	var parentDirs []visitedDir
+
+	seenFiles := make(map[uint64]string)
+	return filepath.Walk(root, func(path string, fi os.FileInfo, walkErr error) (retErr error) {
 		defer func() {
 			if retErr != nil && isNotExist(retErr) {
 				retErr = filepath.SkipDir
 			}
 		}()
+
 		origpath := path
 		path, err = filepath.Rel(root, path)
 		if err != nil {
@@ -86,67 +143,131 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err
 			return nil
 		}
 
-		if opt != nil {
-			if includePatterns != nil {
-				skip := false
-				if lastIncludedDir != "" {
-					if strings.HasPrefix(path, lastIncludedDir+string(filepath.Separator)) {
-						skip = true
-					}
+		var (
+			dir   visitedDir
+			isDir bool
+		)
+		if fi != nil {
+			isDir = fi.IsDir()
+		}
+
+		if includeMatcher != nil || excludeMatcher != nil {
+			for len(parentDirs) != 0 {
+				lastParentDir := parentDirs[len(parentDirs)-1].pathWithSep
+				if strings.HasPrefix(path, lastParentDir) {
+					break
 				}
+				parentDirs = parentDirs[:len(parentDirs)-1]
+			}
+
+			if isDir {
+				dir = visitedDir{
+					fi:          fi,
+					path:        path,
+					origpath:    origpath,
+					pathWithSep: path + string(filepath.Separator),
+				}
+			}
+		}
+
+		skip := false
+
+		if includeMatcher != nil {
+			var parentIncludeMatchInfo patternmatcher.MatchInfo
+			if len(parentDirs) != 0 {
+				parentIncludeMatchInfo = parentDirs[len(parentDirs)-1].includeMatchInfo
+			}
+			m, matchInfo, err := includeMatcher.MatchesUsingParentResults(path, parentIncludeMatchInfo)
+			if err != nil {
+				return errors.Wrap(err, "failed to match includepatterns")
+			}
+
+			if isDir {
+				dir.includeMatchInfo = matchInfo
+			}
 
-				if !skip {
-					matched := false
-					partial := true
-					for _, p := range includePatterns {
-						if ok, p := matchPrefix(p, path); ok {
-							matched = true
-							if !p {
-								partial = false
-								break
-							}
+			if !m {
+				if isDir && onlyPrefixIncludes {
+					// Optimization: we can skip walking this dir if no include
+					// patterns could match anything inside it.
+					dirSlash := path + string(filepath.Separator)
+					for _, pat := range includeMatcher.Patterns() {
+						if pat.Exclusion() {
+							continue
 						}
-					}
-					if !matched {
-						if fi.IsDir() {
-							return filepath.SkipDir
+						patStr := patternWithoutTrailingGlob(pat) + string(filepath.Separator)
+						if strings.HasPrefix(patStr, dirSlash) {
+							goto passedIncludeFilter
 						}
-						return nil
-					}
-					if !partial && fi.IsDir() {
-						lastIncludedDir = path
 					}
+					return filepath.SkipDir
 				}
+			passedIncludeFilter:
+				skip = true
+			}
+		}
+
+		if excludeMatcher != nil {
+			var parentExcludeMatchInfo patternmatcher.MatchInfo
+			if len(parentDirs) != 0 {
+				parentExcludeMatchInfo = parentDirs[len(parentDirs)-1].excludeMatchInfo
+			}
+			m, matchInfo, err := excludeMatcher.MatchesUsingParentResults(path, parentExcludeMatchInfo)
+			if err != nil {
+				return errors.Wrap(err, "failed to match excludepatterns")
+			}
+
+			if isDir {
+				dir.excludeMatchInfo = matchInfo
 			}
-			if pm != nil {
-				m, err := pm.Matches(path)
-				if err != nil {
-					return errors.Wrap(err, "failed to match excludepatterns")
-				}
 
-				if m {
-					if fi.IsDir() {
-						if !pm.Exclusions() {
-							return filepath.SkipDir
+			if m {
+				if isDir && onlyPrefixExcludeExceptions {
+					// Optimization: we can skip walking this dir if no
+					// exceptions to exclude patterns could match anything
+					// inside it.
+					if !excludeMatcher.Exclusions() {
+						return filepath.SkipDir
+					}
+
+					dirSlash := path + string(filepath.Separator)
+					for _, pat := range excludeMatcher.Patterns() {
+						if !pat.Exclusion() {
+							continue
 						}
-						dirSlash := path + string(filepath.Separator)
-						for _, pat := range pm.Patterns() {
-							if !pat.Exclusion() {
-								continue
-							}
-							patStr := pat.String() + string(filepath.Separator)
-							if strings.HasPrefix(patStr, dirSlash) {
-								goto passedFilter
-							}
+						patStr := patternWithoutTrailingGlob(pat) + string(filepath.Separator)
+						if strings.HasPrefix(patStr, dirSlash) {
+							goto passedExcludeFilter
 						}
-						return filepath.SkipDir
 					}
-					return nil
+					return filepath.SkipDir
 				}
+			passedExcludeFilter:
+				skip = true
+			}
+		}
+
+		if walkErr != nil {
+			if skip && errors.Is(walkErr, os.ErrPermission) {
+				return nil
 			}
+			return walkErr
+		}
+
+		if includeMatcher != nil || excludeMatcher != nil {
+			defer func() {
+				if isDir {
+					parentDirs = append(parentDirs, dir)
+				}
+			}()
+		}
+
+		if skip {
+			return nil
 		}
 
-	passedFilter:
+		dir.calledFn = true
+
 		stat, err := mkstat(origpath, path, fi, seenFiles)
 		if err != nil {
 			return err
@@ -157,10 +278,39 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err
 			return ctx.Err()
 		default:
 			if opt != nil && opt.Map != nil {
-				if allowed := opt.Map(stat.Path, stat); !allowed {
+				result := opt.Map(stat.Path, stat)
+				if result == MapResultSkipDir {
+					return filepath.SkipDir
+				} else if result == MapResultExclude {
 					return nil
 				}
 			}
+			for i, parentDir := range parentDirs {
+				if parentDir.calledFn {
+					continue
+				}
+				parentStat, err := mkstat(parentDir.origpath, parentDir.path, parentDir.fi, seenFiles)
+				if err != nil {
+					return err
+				}
+
+				select {
+				case <-ctx.Done():
+					return ctx.Err()
+				default:
+				}
+				if opt != nil && opt.Map != nil {
+					result := opt.Map(parentStat.Path, parentStat)
+					if result == MapResultSkipDir || result == MapResultExclude {
+						continue
+					}
+				}
+
+				if err := fn(parentStat.Path, &StatInfo{parentStat}, nil); err != nil {
+					return err
+				}
+				parentDirs[i].calledFn = true
+			}
 			if err := fn(stat.Path, &StatInfo{stat}, nil); err != nil {
 				return err
 			}
@@ -169,6 +319,16 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err
 	})
 }
 
+func patternWithoutTrailingGlob(p *patternmatcher.Pattern) string {
+	patStr := p.String()
+	// We use filepath.Separator here because patternmatcher.Pattern patterns
+	// get transformed to use the native path separator:
+	// https://github.com/moby/patternmatcher/blob/130b41bafc16209dc1b52a103fdac1decad04f1a/patternmatcher.go#L52
+	patStr = strings.TrimSuffix(patStr, string(filepath.Separator)+"**")
+	patStr = strings.TrimSuffix(patStr, string(filepath.Separator)+"*")
+	return patStr
+}
+
 type StatInfo struct {
 	*types.Stat
 }
@@ -192,39 +352,6 @@ func (s *StatInfo) Sys() interface{} {
 	return s.Stat
 }
 
-func matchPrefix(pattern, name string) (bool, bool) {
-	count := strings.Count(name, string(filepath.Separator))
-	partial := false
-	if strings.Count(pattern, string(filepath.Separator)) > count {
-		pattern = trimUntilIndex(pattern, string(filepath.Separator), count)
-		partial = true
-	}
-	m, _ := filepath.Match(pattern, name)
-	return m, partial
-}
-
-func trimUntilIndex(str, sep string, count int) string {
-	s := str
-	i := 0
-	c := 0
-	for {
-		idx := strings.Index(s, sep)
-		s = s[idx+len(sep):]
-		i += idx + len(sep)
-		c++
-		if c > count {
-			return str[:i-len(sep)]
-		}
-	}
-}
-
 func isNotExist(err error) bool {
-	err = errors.Cause(err)
-	if os.IsNotExist(err) {
-		return true
-	}
-	if pe, ok := err.(*os.PathError); ok {
-		err = pe.Err
-	}
-	return err == syscall.ENOTDIR
+	return errors.Is(err, os.ErrNotExist) || errors.Is(err, syscall.ENOTDIR)
 }
diff --git a/walker_test.go b/walker_test.go
index 57c1eb2..bcc89bb 100644
--- a/walker_test.go
+++ b/walker_test.go
@@ -4,15 +4,16 @@ import (
 	"bytes"
 	"context"
 	"fmt"
-	"io/ioutil"
 	"net"
 	"os"
 	"path/filepath"
+	"runtime"
 	"strings"
 	"testing"
 
 	"github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 	"github.com/tonistiigi/fsutil/types"
 )
 
@@ -87,8 +88,7 @@ file bar/foo
 	}, bufWalk(b))
 	assert.NoError(t, err)
 
-	assert.Equal(t, `dir bar
-`, string(b.Bytes()))
+	assert.Empty(t, b.Bytes())
 
 	b.Reset()
 	err = Walk(context.Background(), d, &WalkOpt{
@@ -149,7 +149,6 @@ func TestWalkerExclude(t *testing.T) {
 dir foo
 file foo/bar2
 `, string(b.Bytes()))
-
 }
 
 func TestWalkerFollowLinks(t *testing.T) {
@@ -218,12 +217,12 @@ func TestWalkerMap(t *testing.T) {
 	defer os.RemoveAll(d)
 	b := &bytes.Buffer{}
 	err = Walk(context.Background(), d, &WalkOpt{
-		Map: func(_ string, s *types.Stat) bool {
+		Map: func(_ string, s *types.Stat) MapResult {
 			if strings.HasPrefix(s.Path, "foo") {
 				s.Path = "_" + s.Path
-				return true
+				return MapResultKeep
 			}
-			return false
+			return MapResultExclude
 		},
 	}, bufWalk(b))
 	assert.NoError(t, err)
@@ -234,52 +233,97 @@ file _foo2
 `, string(b.Bytes()))
 }
 
-func TestMatchPrefix(t *testing.T) {
-	ok, partial := matchPrefix("foo", "foo")
-	assert.Equal(t, true, ok)
-	assert.Equal(t, false, partial)
-
-	ok, partial = matchPrefix("foo/bar/baz", "foo")
-	assert.Equal(t, true, ok)
-	assert.Equal(t, true, partial)
-
-	ok, partial = matchPrefix("foo/bar/baz", "foo/bar")
-	assert.Equal(t, true, ok)
-	assert.Equal(t, true, partial)
+func TestWalkerMapSkipDir(t *testing.T) {
+	d, err := tmpDir(changeStream([]string{
+		"ADD excludeDir dir",
+		"ADD excludeDir/a.txt file",
+		"ADD includeDir dir",
+		"ADD includeDir/a.txt file",
+	}))
+	assert.NoError(t, err)
+	defer os.RemoveAll(d)
 
-	ok, partial = matchPrefix("foo/bar/baz", "foo/bax")
-	assert.Equal(t, false, ok)
+	// SkipDir is a performance optimization - don't even
+	// bother walking directories we don't care about.
+	walked := []string{}
+	b := &bytes.Buffer{}
+	err = Walk(context.Background(), d, &WalkOpt{
+		Map: func(_ string, s *types.Stat) MapResult {
+			walked = append(walked, s.Path)
+			if strings.HasPrefix(s.Path, "excludeDir") {
+				return MapResultSkipDir
+			}
+			if strings.HasPrefix(s.Path, "includeDir") {
+				return MapResultKeep
+			}
+			return MapResultExclude
+		},
+	}, bufWalk(b))
+	assert.NoError(t, err)
 
-	ok, partial = matchPrefix("foo/bar/baz", "foo/bar/baz")
-	assert.Equal(t, true, ok)
-	assert.Equal(t, false, partial)
+	assert.Equal(t, `dir includeDir
+file includeDir/a.txt
+`, string(b.Bytes()))
+	assert.Equal(t, []string{"excludeDir", "includeDir", "includeDir/a.txt"}, walked)
+}
 
-	ok, partial = matchPrefix("f*", "foo")
-	assert.Equal(t, true, ok)
-	assert.Equal(t, false, partial)
+func TestWalkerPermissionDenied(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		t.Skip("os.Chmod not fully supported on Windows")
+	}
+	if os.Getuid() == 0 {
+		t.Skip("test cannot run as root")
+	}
 
-	ok, partial = matchPrefix("foo/bar/*", "foo")
-	assert.Equal(t, true, ok)
-	assert.Equal(t, true, partial)
+	d, err := tmpDir(changeStream([]string{
+		"ADD foo dir",
+		"ADD foo/bar dir",
+	}))
+	assert.NoError(t, err)
+	err = os.Chmod(filepath.Join(d, "foo", "bar"), 0000)
+	require.NoError(t, err)
+	defer func() {
+		os.Chmod(filepath.Join(d, "bar"), 0700)
+		os.RemoveAll(d)
+	}()
 
-	ok, partial = matchPrefix("foo/*/baz", "foo")
-	assert.Equal(t, true, ok)
-	assert.Equal(t, true, partial)
+	b := &bytes.Buffer{}
+	err = Walk(context.Background(), d, &WalkOpt{}, bufWalk(b))
+	if assert.Error(t, err) {
+		assert.Contains(t, err.Error(), "permission denied")
+	}
 
-	ok, partial = matchPrefix("*/*/baz", "foo")
-	assert.Equal(t, true, ok)
-	assert.Equal(t, true, partial)
+	b.Reset()
+	err = Walk(context.Background(), d, &WalkOpt{
+		ExcludePatterns: []string{"**/bar"},
+	}, bufWalk(b))
+	assert.NoError(t, err)
+	assert.Equal(t, `dir foo
+`, string(b.Bytes()))
 
-	ok, partial = matchPrefix("*/bar/baz", "foo/bar")
-	assert.Equal(t, true, ok)
-	assert.Equal(t, true, partial)
+	b.Reset()
+	err = Walk(context.Background(), d, &WalkOpt{
+		ExcludePatterns: []string{"**/bar", "!foo/bar/baz"},
+	}, bufWalk(b))
+	assert.NoError(t, err)
+	assert.Equal(t, `dir foo
+`, string(b.Bytes()))
 
-	ok, partial = matchPrefix("*/bar/baz", "foo/bax")
-	assert.Equal(t, false, ok)
+	b.Reset()
+	err = Walk(context.Background(), d, &WalkOpt{
+		ExcludePatterns: []string{"**/bar", "!foo/bar"},
+	}, bufWalk(b))
+	if assert.Error(t, err) {
+		assert.Contains(t, err.Error(), "permission denied")
+	}
 
-	ok, partial = matchPrefix("*/*/baz", "foo/bar/baz")
-	assert.Equal(t, true, ok)
-	assert.Equal(t, false, partial)
+	b.Reset()
+	err = Walk(context.Background(), d, &WalkOpt{
+		IncludePatterns: []string{"foo", "!**/bar"},
+	}, bufWalk(b))
+	assert.NoError(t, err)
+	assert.Equal(t, `dir foo
+`, string(b.Bytes()))
 }
 
 func bufWalk(buf *bytes.Buffer) filepath.WalkFunc {
@@ -305,7 +349,7 @@ func bufWalk(buf *bytes.Buffer) filepath.WalkFunc {
 }
 
 func tmpDir(inp []*change) (dir string, retErr error) {
-	tmpdir, err := ioutil.TempDir("", "diff")
+	tmpdir, err := os.MkdirTemp("", "diff")
 	if err != nil {
 		return "", err
 	}
@@ -343,6 +387,14 @@ func tmpDir(inp []*change) (dir string, retErr error) {
 				if err != nil {
 					return "", err
 				}
+
+				// Make sure all files start with the same default permissions,
+				// regardless of OS settings.
+				err = os.Chmod(p, 0644)
+				if err != nil {
+					return "", err
+				}
+
 				if len(c.data) > 0 {
 					if _, err := f.Write([]byte(c.data)); err != nil {
 						return "", err
@@ -354,3 +406,357 @@ func tmpDir(inp []*change) (dir string, retErr error) {
 	}
 	return tmpdir, nil
 }
+
+func BenchmarkWalker(b *testing.B) {
+	for _, scenario := range []struct {
+		maxDepth int
+		pattern  string
+		expected int
+	}{{
+		maxDepth: 1,
+		pattern:  "target",
+		expected: 1,
+	}, {
+		maxDepth: 1,
+		pattern:  "**/target",
+		expected: 1,
+	}, {
+		maxDepth: 2,
+		pattern:  "*/target",
+		expected: 52,
+	}, {
+		maxDepth: 2,
+		pattern:  "**/target",
+		expected: 52,
+	}, {
+		maxDepth: 3,
+		pattern:  "*/*/target",
+		expected: 1378,
+	}, {
+		maxDepth: 3,
+		pattern:  "**/target",
+		expected: 1378,
+	}, {
+		maxDepth: 4,
+		pattern:  "*/*/*/target",
+		expected: 2794,
+	}, {
+		maxDepth: 4,
+		pattern:  "**/target",
+		expected: 2794,
+	}, {
+		maxDepth: 5,
+		pattern:  "*/*/*/*/target",
+		expected: 1405,
+	}, {
+		maxDepth: 5,
+		pattern:  "**/target",
+		expected: 1405,
+	}, {
+		maxDepth: 6,
+		pattern:  "*/*/*/*/*/target",
+		expected: 2388,
+	}, {
+		maxDepth: 6,
+		pattern:  "**/target",
+		expected: 2388,
+	}} {
+		scenario := scenario // copy loop var
+		b.Run(fmt.Sprintf("[%d]-%s", scenario.maxDepth, scenario.pattern), func(b *testing.B) {
+			tmpdir, err := os.MkdirTemp("", "walk")
+			if err != nil {
+				b.Error(err)
+			}
+			defer func() {
+				b.StopTimer()
+				os.RemoveAll(tmpdir)
+			}()
+			mkBenchTree(tmpdir, scenario.maxDepth, 1)
+
+			// don't include time to setup dirs in benchmark
+			b.ResetTimer()
+
+			for i := 0; i < b.N; i++ {
+				count := 0
+				err = Walk(context.Background(), tmpdir, &WalkOpt{
+					IncludePatterns: []string{scenario.pattern},
+				}, func(path string, fi os.FileInfo, err error) error {
+					count++
+					return nil
+				})
+				if err != nil {
+					b.Error(err)
+				}
+				if count != scenario.expected {
+					b.Errorf("Got count %d, expected %d", count, scenario.expected)
+				}
+			}
+		})
+	}
+
+}
+
+func TestWalkerDoublestarInclude(t *testing.T) {
+	d, err := tmpDir(changeStream([]string{
+		"ADD a dir",
+		"ADD a/b dir",
+		"ADD a/b/baz dir",
+		"ADD a/b/bar dir ",
+		"ADD a/b/bar/foo file",
+		"ADD a/b/bar/fop file",
+		"ADD bar dir",
+		"ADD bar/foo file",
+		"ADD baz dir",
+		"ADD foo2 file",
+		"ADD foo dir",
+		"ADD foo/bar dir",
+		"ADD foo/bar/bee file",
+	}))
+
+	assert.NoError(t, err)
+	defer os.RemoveAll(d)
+	b := &bytes.Buffer{}
+	err = Walk(context.Background(), d, &WalkOpt{
+		IncludePatterns: []string{"**"},
+	}, bufWalk(b))
+	assert.NoError(t, err)
+
+	trimEqual(t, `
+		dir a
+		dir a/b
+		dir a/b/bar
+		file a/b/bar/foo
+		file a/b/bar/fop
+		dir a/b/baz
+		dir bar
+		file bar/foo
+		dir baz
+		dir foo
+		dir foo/bar
+		file foo/bar/bee
+		file foo2
+	`, string(b.Bytes()))
+
+	b.Reset()
+	err = Walk(context.Background(), d, &WalkOpt{
+		IncludePatterns: []string{"**/bar"},
+	}, bufWalk(b))
+	assert.NoError(t, err)
+
+	trimEqual(t, `
+		dir a
+		dir a/b
+		dir a/b/bar
+		file a/b/bar/foo
+		file a/b/bar/fop
+		dir bar
+		file bar/foo
+		dir foo
+		dir foo/bar
+		file foo/bar/bee
+	`, string(b.Bytes()))
+
+	b.Reset()
+	err = Walk(context.Background(), d, &WalkOpt{
+		IncludePatterns: []string{"**/bar/foo"},
+	}, bufWalk(b))
+	assert.NoError(t, err)
+
+	trimEqual(t, `
+		dir a
+		dir a/b
+		dir a/b/bar
+		file a/b/bar/foo
+		dir bar
+		file bar/foo
+	`, string(b.Bytes()))
+
+	b.Reset()
+	err = Walk(context.Background(), d, &WalkOpt{
+		IncludePatterns: []string{"**/b*"},
+	}, bufWalk(b))
+	assert.NoError(t, err)
+
+	trimEqual(t, `
+		dir a
+		dir a/b
+		dir a/b/bar
+		file a/b/bar/foo
+		file a/b/bar/fop
+		dir a/b/baz
+		dir bar
+		file bar/foo
+		dir baz
+		dir foo
+		dir foo/bar
+		file foo/bar/bee
+	`, string(b.Bytes()))
+
+	b.Reset()
+	err = Walk(context.Background(), d, &WalkOpt{
+		IncludePatterns: []string{"**/bar/f*"},
+	}, bufWalk(b))
+	assert.NoError(t, err)
+
+	trimEqual(t, `
+			dir a
+			dir a/b
+			dir a/b/bar
+			file a/b/bar/foo
+			file a/b/bar/fop
+			dir bar
+			file bar/foo
+	`, string(b.Bytes()))
+
+	b.Reset()
+	err = Walk(context.Background(), d, &WalkOpt{
+		IncludePatterns: []string{"**/bar/g*"},
+	}, bufWalk(b))
+	assert.NoError(t, err)
+
+	trimEqual(t, ``, string(b.Bytes()))
+
+	b.Reset()
+	err = Walk(context.Background(), d, &WalkOpt{
+		IncludePatterns: []string{"**/f*"},
+	}, bufWalk(b))
+	assert.NoError(t, err)
+
+	trimEqual(t, `
+		dir a
+		dir a/b
+		dir a/b/bar
+		file a/b/bar/foo
+		file a/b/bar/fop
+		dir bar
+		file bar/foo
+		dir foo
+		dir foo/bar
+		file foo/bar/bee
+		file foo2
+	`, string(b.Bytes()))
+
+	b.Reset()
+	err = Walk(context.Background(), d, &WalkOpt{
+		IncludePatterns: []string{"**/b*/f*"},
+	}, bufWalk(b))
+	assert.NoError(t, err)
+
+	trimEqual(t, `
+		dir a
+		dir a/b
+		dir a/b/bar
+		file a/b/bar/foo
+		file a/b/bar/fop
+		dir bar
+		file bar/foo
+	`, string(b.Bytes()))
+
+	b.Reset()
+	err = Walk(context.Background(), d, &WalkOpt{
+		IncludePatterns: []string{"**/b*/foo"},
+	}, bufWalk(b))
+	assert.NoError(t, err)
+
+	trimEqual(t, `
+		dir a
+		dir a/b
+		dir a/b/bar
+		file a/b/bar/foo
+		dir bar
+		file bar/foo
+	`, string(b.Bytes()))
+
+	b.Reset()
+	err = Walk(context.Background(), d, &WalkOpt{
+		IncludePatterns: []string{"**/foo/**"},
+	}, bufWalk(b))
+	assert.NoError(t, err)
+
+	trimEqual(t, `
+		dir foo
+		dir foo/bar
+		file foo/bar/bee
+	`, string(b.Bytes()))
+
+	b.Reset()
+	err = Walk(context.Background(), d, &WalkOpt{
+		IncludePatterns: []string{"**/baz"},
+	}, bufWalk(b))
+	assert.NoError(t, err)
+
+	trimEqual(t, `
+		dir a
+		dir a/b
+		dir a/b/baz
+		dir baz
+	`, string(b.Bytes()))
+}
+
+func trimEqual(t assert.TestingT, expected, actual string, msgAndArgs ...interface{}) bool {
+	lines := []string{}
+	for _, line := range strings.Split(expected, "\n") {
+		line = strings.TrimSpace(line)
+		if line != "" {
+			lines = append(lines, line)
+		}
+	}
+	lines = append(lines, "") // we expect a trailing newline
+	expected = strings.Join(lines, "\n")
+
+	return assert.Equal(t, expected, actual, msgAndArgs)
+}
+
+// mkBenchTree will create directories named a-z recursively
+// up to 3 layers deep.  If maxDepth is > 3 we will shorten
+// the last letter to prevent the generated inodes going over
+// 25k. The final directory in the tree will contain only files.
+// Additionally there is a single file named `target`
+// in each leaf directory.
+func mkBenchTree(dir string, maxDepth, depth int) error {
+	end := 'z'
+	switch maxDepth {
+	case 1, 2, 3:
+		end = 'z' // max 19682 inodes
+	case 4:
+		end = 'k' // max 19030 inodes
+	case 5:
+		end = 'e' // max 12438 inodes
+	case 6:
+		end = 'd' // max 8188 inodes
+	case 7, 8:
+		end = 'c' // max 16398 inodes
+	case 9, 10, 11, 12:
+		end = 'b' // max 16378 inodes
+	default:
+		panic("depth cannot be > 12, would create too many files")
+	}
+
+	if depth == maxDepth {
+		fd, err := os.Create(filepath.Join(dir, "target"))
+		if err != nil {
+			return err
+		}
+		fd.Close()
+	}
+	for r := 'a'; r <= end; r++ {
+		p := filepath.Join(dir, string(r))
+		if depth == maxDepth {
+			fd, err := os.Create(p)
+			if err != nil {
+				return err
+			}
+			fd.Close()
+		} else {
+			err := os.Mkdir(p, 0755)
+			if err != nil {
+				return err
+			}
+			err = mkBenchTree(p, maxDepth, depth+1)
+			if err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/share/gocode/src/github.com/tonistiigi/fsutil/copy/copy_freebsd.go
-rw-r--r--  root/root   /usr/share/gocode/src/github.com/tonistiigi/fsutil/diskwriter_freebsd.go
-rw-r--r--  root/root   /usr/share/gocode/src/github.com/tonistiigi/fsutil/diskwriter_unixnobsd.go

Files in first set of .debs but not in second

-rw-r--r--  root/root   /usr/share/gocode/src/github.com/tonistiigi/fsutil/diff_containerd_linux.go

No differences were encountered in the control files

More details

Full run details