Repository: moby/moby (language: go)

Issue:
Remove local fork of Golang's archive/tar
commit aa6a9891b09cce3d9004121294301a30d45d998d (19.03 branch) and https://github.com/moby/moby/pull/40672 (master / 20.10) re-introduced a local copy of go's archive/tar package, with a patch applied [patches/0001-archive-tar-do-not-populate-user-group-names.patch](https://github.com/moby/moby/blob/841c1f338872ca37d9fe8c699336823222dba5da/patches/0001-archive-tar-do-not-populate-user-group-names.patch).

This patch was applied for the [19.03.8 release](https://github.com/docker/docker-ce/releases/tag/v19.03.8) to improve mitigation for [CVE-2019-14271](https://nvd.nist.gov/vuln/detail/CVE-2019-14271) for some nscd configuration.

We should try to get rid of this fork again.

The discussion on https://github.com/moby/moby/pull/40672#discussion_r391306456 mentioned we should open a ticket / pull request in upstream Go to make this functionality "optional", but I think @tonistiigi also had alternatives in mind to address it.



Discussion / hints:
/cc @kolyshkin @cpuguy83 @tianon 
I'm definitely all for it, especially since in Go 1.17+ we're going to have a _much_ harder time maintaining this the way we currently do (and I think it already probably causes grief for packagers who don't get to use our `vendor/` as-is).

@cpuguy83 suggested that if we still need the patch we could instead maintain a proper forked package, which would be at least possible to deal with in a Go modules world, but IMO something that doesn't require forking the standard library would be awesome if there are ideas around that :sweat_smile:
We need to revisit in the light of switching away from `vndr` to `go mod vendor` (that's without adding `go.mod` for now).

> ...I think @tonistiigi also had alternatives in mind to address it

 @tonistiigi could you please share what you were thinking in that regard?
> @cpuguy83 suggested that if we still need the patch we could instead maintain a proper forked package, which would be at least possible to deal with in a Go modules world...

Are we only concerned with Docker's usage of `archive/tar`, or perhaps there are some dependencies that are affected also?
> we could instead maintain a proper forked package, which would be at least possible to deal with in a Go modules world...

I would be ok with doing this for the short term (change the import paths to a package in moby (or could be a separate repo). What I wasn't sure about for this though would be if we're _able_ to replace it everywhere where we want it to be replaced; if `archive/tar` is used indirectly in Go stdlib, is there a risk of reintroducing the issue we're trying to fix?

I haven't looked deeply into that scenario, but possibly others know.

The "proper" fix of course is to propose a patch upstream to add a build-tag to disable the bits we're removing (`nouserlookup` or whatever), but likely go 1.19 would be the first chance to get that in
On Fri, 10 Dec 2021, 4:12 pm Sebastiaan van Stijn, ***@***.***>
wrote:

> we could instead maintain a proper forked package, which would be at least
> possible to deal with in a Go modules world...
>
> I would be ok with doing this for the short term (change the import paths
> to a package in moby (or could be a separate repo). What I wasn't sure
> about for this though would be if we're *able* to replace it everywhere
> where we want it to be replaced; if archive/tar is used indirectly in Go
> stdlib, is there a risk of reintroducing the issue we're trying to fix?
>
Do we know what code in Moby is calling stdlib to pack/unpack tarballs and
introduces problematic behaviour?

>

> @tonistiigi could you please share what you were thinking in that regard?

I don't really remember anymore. I think @cpuguy83 had a suggestion about separating out this code to another binary and guaranteeing that it is always built without cgo(or with musl). I don't think it is very safe though, especially easy for some 3rd party build to mess it up.

> Do we know what code in Moby is calling stdlib to pack/unpack tarballs and
introduces problematic behaviour?

IIRC, the extract code is doing a reexec of dockerd with a chroot applied to protect against breakouts. If that code now running inside chroot is built with cgo and upstream tar package, when it will call `lookupuser` it will call the equivalent glibc method. That glibc method will at runtime try to map some `.so` files to executable memory and run it. Inside chroot that is of course problematic as it would load the `.so` that is inside the attacker controlled extract path, not the one from the host system.
On Fri, 10 Dec 2021, 6:20 pm Tõnis Tiigi, ***@***.***> wrote:

> @tonistiigi <https://github.com/tonistiigi> could you please share what
> you were thinking in that regard?
>
> I don't really remember anymore. I think @cpuguy83
> <https://github.com/cpuguy83> had a suggestion about separating out this
> code to another binary and guaranteeing that it is always built without
> cgo(or with musl). I don't think it is very safe though, especially easy
> for some 3rd party build to mess it up.
>
Maybe a runtime check could just panic to avoid this? Just an idea...

> Do we know what code in Moby is calling stdlib to pack/unpack tarballs and
> introduces problematic behaviour?
>
> IIRC, the extract code is doing a reexec of dockerd with a chroot applied
> to protect against breakouts. If that code now running inside chroot is
> built with cgo and upstream tar package, when it will call lookupuser it
> will call the equivalent glibc method. That glibc method will at runtime
> try to map some .so files to executable memory and run it. Inside chroot
> that is of course problematic as it would load the .so that is inside the
> attacker controlled extract path, not the one from the host system..
>
It does sound like we should be in control of this, I'd surprised if the
tarball extraction is done indirectly (and even if happens to be, surely it
can addressed).
Also, for extra safety a runtime check could still be of interest, perhaps.
This definitely does need a test case.

Better late than never: https://go-review.googlesource.com/c/go/+/371054

The alternative approach is to add something like `archivetarnonames` (to disable name lookups), but since these lookups are only done by a single function that is not used internally, it seems better to add another.
For the lack of better things to do on a Friday night, wrote a proposal: https://github.com/golang/go/issues/50102. Most probably it has errors, omissions and other issues -- please review and suggest improvements.
❤️ @kolyshkin !
Thanks @kolyshkin! I added a few comments, hopefully will be somewhat helpful :)
I took a look at the situation for myself and have some possible ideas for how to get rid of the fork without regressing on the vulnerability or waiting for changes to be accepted into the upstream standard library.

The root cause of the vulnerability, AIUI, is that the cgo/POSIX implementation of `os/user` calls libc functions which, in glibc, are implemented by dynamically loading an NSS module (`libnss_*.so.2`) into the process. An attacker could trick the process into loading a malicious attacker-controlled library by setting `LD_LIBRARY_PATH` in the process's environment or dropping the malicious library into one of the default library search paths. This is not normally a security vulnerability as an attacker would need to already have enough privilege on the host that there would be no need to exploit the process: if they already have write access to one of the host's default library paths or the ability to control the `LD_LIBRARY_PATH` environment variable, they would already have enough access to e.g. replace `libc.so.6`, set `LD_PRELOAD` on the process to inject their malicious code directly, or use their (most likely) root privileges to simply replace the `dockerd` binary outright.

Ironically, the hardening of moby's archiver using a chroot is what makes the dynamic loading of NSS modules into an exploitable attack vector. The attacker has full control of the entire chroot filesystem — it's a container's filesystem! If the first call to one of the `os/user` functions which triggers the loading of the NSS modules happens after pivoting into the chroot, the modules are resolved and loaded _from the attacker-controlled container filesystem._ There was an attempt to mitigate the vulnerability with #39612 which ensures that the NSS modules are loaded into the process before pivoting into the chroot. But seeing as the forking of `archive/tar` was re-added after, I can only assume that loading the host's NSS modules then pivoting into what is effectively a completely different OS userland could still break things. So the only complete fix would be to avoid calling any code which calls into the libc functions that trigger glibc to load NSS modules into the process. Building the binary with `CGO_ENABLED=0` or the `osusergo` build flag is sufficient to ensure that none of the `os/user` functions call into libc, but that has some downsides which @kolyshkin has already elaborated upon in his proposal on golang/go. Without those build configuration changes, the issues can be avoided "merely" by ensuring that the `os/user` functions are never called by the chroot'ed process. This is easier said than done.

The function `archive/tar.FileInfoHeader` calls the problematic `os/user` functions via the unexported function `tar.statUnix`, indirectly (more on that in a moment). `FileInfoHeader` is the only function which calls `statUnix`. The `FileInfoHeader` function is used by moby when creating (not extracting) archives within the chroot. And it's a leaf function: no code in Go's standard library (1.16 and 1.17) calls that function outside of tests. `FileInfoHeader` returns a `tar.Header` struct, which has no unexported members, therefore a `tar.Header` value could be fully constructed from normal application/library code. _The `FileInfoHeader` function is not strictly required._ Therefore, for application code fully under our control, an alternative implementation which doesn't call `os/user` functions can be subbed in without any trickery, patches or hacks. This could take the form of forking and patching a copy of the standard library's implementation of `tar.FileInfoHeader` (e.g. `github.com/docker/docker/internal/tarhdr`) [or writing a totally new implementation that does exactly what moby needs it to do.](https://github.com/moby/moby/blob/79651b7a979b40e26af353ad283ca7ea5d67a855/pkg/archive/archive.go#L406-L425) This would Just Work... so long as there isn't any third-party code which indirectly calls `tar.FileInfoHeader` unexpectedly. Since the chroot-archive process is limited enough in scope(?) that can be audited manually, but it would be nice to have defense-in-depth. That's where patching `archive/tar` directly would be helpful. If only there was a way to do it in a Go Modules-compatible way.

The implementations of `tar.FileInfoHeader` in Go 1.16 and 1.17 just so happen to be written in such a way that the call to `tar.statUnix` can be monkeypatched with an alternative implementation at runtime. `statUnix` is called [indirectly through a function variable](https://cs.opensource.google/go/go/+/refs/tags/go1.17.6:src/archive/tar/common.go;l=701-703;bpv=1;bpt=1) which is [assigned at runtime](https://cs.opensource.google/go/go/+/refs/tags/go1.17.6:src/archive/tar/stat_unix.go;l=19-21). It's not exported, but there is an (unsafe) way to assign to it from a different package, anyway.
```go
import (
	"archive/tar"
	"io/fs"

	_ "unsafe" // required for go:linkname
)

//go:linkname sysStat archive/tar.sysStat
var sysStat func(fi fs.FileInfo, h *tar.Header) error
```
With this one ~weird trick~ little hack, moby code can assign `sysStat = nil` or `sysStat = myStatUnix` to ensure that any code calling into `tar.FileInfoHeader` anywhere in the process would not invoke the problematic libc functions! It could break between Go versions, but multiple versions of Go could be supported in the same codebase by utilizing build constraints. It is not ideal, but I think it would be a much more maintainable situation than the status quo while Go's standard library catches up.

What do you think? I would be happy to share my proof-of-concept, or open a PR which implements what I have proposed.
The big caveat for my ideas above is how brittle the defenses are: any call to an `os/user` function after the process has pivoted into the chroot could reintroduce the vulnerability. Extreme vigilance and static analysis would be required. Ideally we could robustly harden the chroot-archiver such that glibc `dlopen()`ing one of its modules while the process is chrooted cannot lead to execution of malicious code. I have some ideas on how to do just that.

[The dynamic linker](https://man7.org/linux/man-pages/man8/ld.so.8.html) and [its runtime counterpart `dlopen()`](https://man7.org/linux/man-pages/man3/dlopen.3.html) searches for the shared object to load by checking:
1. the directories specified in the `DT_RPATH` or `DT_RUNPATH` ELF tags embedded into the binary,
2. the directories specified in the `LD_LIBRARY_PATH` environment variable,
3. for an entry in the file `/etc/ld.so.cache` specifying the path to the object,
4. in the default paths `/lib{64}` and `/usr/lib{64}`.

I believe that removing the attacker's ability to control the contents of the root directory of the chroot filesystem is sufficient to prevent them from tricking the dynamic linker into loading shared objects from within the chroot. Mounting the container's root filesystem such that it is a subdirectory of the chroot stops the attacker from controlling the contents of the trusted `/etc`, `/usr` and `/lib` trees.

The values of `DT_RPATH`, `DT_RUNPATH` and `LD_LIBRARY_PATH` are not attacker-controlled in our threat model. The `DT_*` ELF tags are set when the binary is built, therefore are controlled by the packagers/distributors of moby. The value of `LD_LIBRARY_PATH` is controlled by the system administrator. We can guard against exploits via these configurations, even by a malicious administrator, by randomizing the directory name for the container filesystem's mountpoint to make it unpredictable.

-----

For more defense-in-depth, the container filesystem can be (bind-)mounted `noexec`. The Linux kernel blocks attempts to `mmap(PROT_EXEC)` memory pages from files on noexec filesystems, so even if an attacker found another way to trick the dynamic linker into loading a shared object from the container filesystem, attempts to map executable sections of the file into the process's memory space would fail. This is not yet sufficient to completely block all exploits, however, as relocations can be abused to build and execute a Return-Oriented Programming chain before the linker attempts to map any executable pages ([sourceware bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=21718), [ChromeOS issue](https://bugs.chromium.org/p/chromium/issues/detail?id=1182687)). There is ongoing work on both the kernel and userland sides to plug this hole upstream ([glibc patch](https://sourceware.org/pipermail/libc-alpha/2021-July/129282.html), [kernel support](https://lwn.net/Articles/832959/)) and security-hardened systems such as ChromeOS are already incorporating patches into their distributions. Once the upstream work is complete and is incorporated into shipping systems, we would get the more robust hardening with no further changes to moby code.

-----

By mounting the container filesystem as a randomly-named subdirectory of the chroot with the `noexec` option, we can ensure that bugs in moby code which trigger dynamic linking while chrooted cannot be exploited to escape the sandbox via code execution. It would at worst result in a non-exploitable crash of the chroot-archive process. Therefore (monkey)patching the Go standard library would not be necessary. Our own custom implementation of `TarInfoHeader` would still be required, but it will no longer be the vulnerability linchpin.
Bind mounting into a safe location could work... e.g. `/tmp/tarJob-<rand>/rootfs`

Originally issue I think was that we did chroot to the rootfs as a subdir but this was within the main graphdriver dir tree and allowed the container process to use symlinks to gain access to the host.

Another layer could be putting randomized junk values into all the lookup vars. I'm not sure what glibc would do here if the value doesn't exist, though.
The more I think about it, the more uneasy I get about `chroot`ing into a hostile rootfs inside a dynamically-linked process after it has started executing. It's quite the fair assumption that the library search paths which were trusted to locate the shared libraries when the executable image was first linked and loaded will continue to be trustworthy for the duration of the process's lifetime. Any version of any shared library could `dlopen` another library as a side effect of practically anything, as an implementation detail, and it would be completely justified to do so. Any mitigations to harden docker-tar against a dynamically-linked library loading code from inside the chroot could be rendered useless without warning by a glibc upgrade, or linking against musl, or bionic. And the mitigations themselves necessarily have to be complex and clever, which are not desirable properties of security-sensitive code.

I'm really warming up to the idea of building `docker-tar` as a binary with cgo always disabled as it takes native libraries completely out of the equation. And to address @tonistiigi's concern about compile-time safety, third parties can be stopped from building it dynamically-linked by adding a `!cgo` build constraint to one or more critical files.
<details>
<summary>Proof of concept</summary>

```console
$ cat main.go
//go:build !cgo
// +build !cgo

package main

import (
	"fmt"
	"os/user"
)

func main() {
	u, err := user.Lookup("docker")
	fmt.Println(u, err)
}
$ go build
package .: build constraints exclude all Go files in [path]
$ CGO_ENABLED=0 go build
$
```
</details>

With cgo out of the way, the most serious consequence of `archive/tar.TarInfoHeader` getting called while the process is chrooted would be a performance regression from repeatedly parsing `/etc/groups` for every file getting archived.

Of course, `docker-tar`, `docker-untar` and `docker-applyLayer` could all be compiled into a single binary so they all get the hardening benefits of static, cgo-less compilation while amortizing the disk usage across all three.

Fix patch:
diff --git a/Dockerfile b/Dockerfile
index 4ee4d8dd2ca53..f4bc1d0ed91c0 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -2,7 +2,6 @@
 
 ARG CROSS="false"
 ARG SYSTEMD="false"
-# IMPORTANT: When updating this please note that stdlib archive/tar pkg is vendored
 ARG GO_VERSION=1.19.12
 ARG DEBIAN_FRONTEND=noninteractive
 ARG VPNKIT_VERSION=0.5.0
diff --git a/hack/validate/golangci-lint.yml b/hack/validate/golangci-lint.yml
index 815300506c40f..96370b47cb144 100644
--- a/hack/validate/golangci-lint.yml
+++ b/hack/validate/golangci-lint.yml
@@ -98,7 +98,7 @@ issues:
       linters:
         - gosec
     # FIXME temporarily suppress these. See #39924
-    - text: "SA1019: .*\\.Xattrs is deprecated: Use PAXRecords instead"
+    - text: "SA1019: .*\\.Xattrs has been deprecated since Go 1.10: Use PAXRecords instead"
       linters:
         - staticcheck
     # FIXME temporarily suppress these. See #39926
diff --git a/hack/vendor.sh b/hack/vendor.sh
index 696119b258afb..eb8cd2f032f5c 100755
--- a/hack/vendor.sh
+++ b/hack/vendor.sh
@@ -12,17 +12,4 @@ if ! hash vndr; then
 	exit 1
 fi
 
-if [ $# -eq 0 ] || [ "$1" = "archive/tar" ]; then
-	echo "update vendored copy of archive/tar"
-	: "${GO_VERSION:=$(awk -F '[ =]' '$1 == "ARG" && $2 == "GO_VERSION" { print $3; exit }' ./Dockerfile)}"
-	rm -rf vendor/archive
-	mkdir -p ./vendor/archive/tar
-	echo "downloading: https://golang.org/dl/go${GO_VERSION%.0}.src.tar.gz"
-	curl -fsSL "https://golang.org/dl/go${GO_VERSION%.0}.src.tar.gz" \
-		| tar --extract --gzip --directory=vendor/archive/tar --strip-components=4 go/src/archive/tar
-	patch --strip=4 --directory=vendor/archive/tar --input="$PWD/patches/0001-archive-tar-do-not-populate-user-group-names.patch"
-fi
-
-if [ $# -eq 0 ] || [ "$1" != "archive/tar" ]; then
-	vndr -whitelist=^archive/tar "$@"
-fi
+exec vndr "$@"
diff --git a/patches/0001-archive-tar-do-not-populate-user-group-names.patch b/patches/0001-archive-tar-do-not-populate-user-group-names.patch
deleted file mode 100644
index c5599b6102d66..0000000000000
--- a/patches/0001-archive-tar-do-not-populate-user-group-names.patch
+++ /dev/null
@@ -1,75 +0,0 @@
-From bc0de86b495ae014b209431ed7cb90fc3d5e4d1f Mon Sep 17 00:00:00 2001
-From: Kir Kolyshkin <kolyshkin@gmail.com>
-Date: Mon, 9 Apr 2018 15:58:40 -0700
-Subject: [PATCH] archive/tar: do not populate user/group names
-
-This reverts part of commit 29a18899379c ("archive/tar: populate
-uname/gname/devmajor/devminor in FileInfoHeader"). The reason is
-using os/user functions to resolved uids/gids to names breaks
-the static build for Linux/glibc case (the resulting binary panics
-on NULL pointer dereference).
-
-For much more details, see https://github.com/golang/go/issues/23265
-
-Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
----
- src/archive/tar/stat_unix.go | 26 +++-----------------------
- 1 file changed, 3 insertions(+), 23 deletions(-)
-
-diff --git a/src/archive/tar/stat_unix.go b/src/archive/tar/stat_unix.go
-index 868105f338..9640ed4bab 100644
---- a/src/archive/tar/stat_unix.go
-+++ b/src/archive/tar/stat_unix.go
-@@ -8,10 +8,7 @@ package tar
- 
- import (
-	"io/fs"
--	"os/user"
- 	"runtime"
--	"strconv"
--	"sync"
- 	"syscall"
- )
- 
-@@ -19,10 +16,6 @@ func init() {
- 	sysStat = statUnix
- }
- 
--// userMap and groupMap caches UID and GID lookups for performance reasons.
--// The downside is that renaming uname or gname by the OS never takes effect.
--var userMap, groupMap sync.Map // map[int]string
--
- func statUnix(fi fs.FileInfo, h *Header) error {
- 	sys, ok := fi.Sys().(*syscall.Stat_t)
- 	if !ok {
-@@ -31,22 +24,9 @@ func statUnix(fi os.FileInfo, h *Header) error {
- 	h.Uid = int(sys.Uid)
- 	h.Gid = int(sys.Gid)
- 
--	// Best effort at populating Uname and Gname.
--	// The os/user functions may fail for any number of reasons
--	// (not implemented on that platform, cgo not enabled, etc).
--	if u, ok := userMap.Load(h.Uid); ok {
--		h.Uname = u.(string)
--	} else if u, err := user.LookupId(strconv.Itoa(h.Uid)); err == nil {
--		h.Uname = u.Username
--		userMap.Store(h.Uid, h.Uname)
--	}
--	if g, ok := groupMap.Load(h.Gid); ok {
--		h.Gname = g.(string)
--	} else if g, err := user.LookupGroupId(strconv.Itoa(h.Gid)); err == nil {
--		h.Gname = g.Name
--		groupMap.Store(h.Gid, h.Gname)
--	}
--
-+	// TODO(bradfitz): populate username & group.  os/user
-+	// doesn't cache LookupId lookups, and lacks group
-+	// lookup functions.
- 	h.AccessTime = statAtime(sys)
- 	h.ChangeTime = statCtime(sys)
- 
-
-base-commit: 4af1337d1e9eb9e7b766c9deb787c78413bb25c4
--- 
-2.24.1
-
diff --git a/pkg/archive/archive.go b/pkg/archive/archive.go
index ade5f5396b477..ce4aea1c54655 100644
--- a/pkg/archive/archive.go
+++ b/pkg/archive/archive.go
@@ -352,12 +352,64 @@ func (compression *Compression) Extension() string {
 	return ""
 }
 
+// nosysFileInfo hides the system-dependent info of the wrapped FileInfo to
+// prevent tar.FileInfoHeader from introspecting it and potentially calling into
+// glibc.
+type nosysFileInfo struct {
+	os.FileInfo
+}
+
+func (fi nosysFileInfo) Sys() interface{} {
+	// A Sys value of type *tar.Header is safe as it is system-independent.
+	// The tar.FileInfoHeader function copies the fields into the returned
+	// header without performing any OS lookups.
+	if sys, ok := fi.FileInfo.Sys().(*tar.Header); ok {
+		return sys
+	}
+	return nil
+}
+
+// sysStat, if non-nil, populates hdr from system-dependent fields of fi.
+var sysStat func(fi os.FileInfo, hdr *tar.Header) error
+
+// FileInfoHeaderNoLookups creates a partially-populated tar.Header from fi.
+//
+// Compared to the archive/tar.FileInfoHeader function, this function is safe to
+// call from a chrooted process as it does not populate fields which would
+// require operating system lookups. It behaves identically to
+// tar.FileInfoHeader when fi is a FileInfo value returned from
+// tar.Header.FileInfo().
+//
+// When fi is a FileInfo for a native file, such as returned from os.Stat() and
+// os.Lstat(), the returned Header value differs from one returned from
+// tar.FileInfoHeader in the following ways. The Uname and Gname fields are not
+// set as OS lookups would be required to populate them. The AccessTime and
+// ChangeTime fields are not currently set (not yet implemented) although that
+// is subject to change. Callers which require the AccessTime or ChangeTime
+// fields to be zeroed should explicitly zero them out in the returned Header
+// value to avoid any compatibility issues in the future.
+func FileInfoHeaderNoLookups(fi os.FileInfo, link string) (*tar.Header, error) {
+	hdr, err := tar.FileInfoHeader(nosysFileInfo{fi}, link)
+	if err != nil {
+		return nil, err
+	}
+	if sysStat != nil {
+		return hdr, sysStat(fi, hdr)
+	}
+	return hdr, nil
+}
+
 // FileInfoHeader creates a populated Header from fi.
-// Compared to archive pkg this function fills in more information.
-// Also, regardless of Go version, this function fills file type bits (e.g. hdr.Mode |= modeISDIR),
-// which have been deleted since Go 1.9 archive/tar.
+//
+// Compared to the archive/tar package, this function fills in less information
+// but is safe to call from a chrooted process. The AccessTime and ChangeTime
+// fields are not set in the returned header, ModTime is truncated to one-second
+// precision, and the Uname and Gname fields are only set when fi is a FileInfo
+// value returned from tar.Header.FileInfo(). Also, regardless of Go version,
+// this function fills file type bits (e.g. hdr.Mode |= modeISDIR), which have
+// been deleted since Go 1.9 archive/tar.
 func FileInfoHeader(name string, fi os.FileInfo, link string) (*tar.Header, error) {
-	hdr, err := tar.FileInfoHeader(fi, link)
+	hdr, err := FileInfoHeaderNoLookups(fi, link)
 	if err != nil {
 		return nil, err
 	}
@@ -367,9 +419,6 @@ func FileInfoHeader(name string, fi os.FileInfo, link string) (*tar.Header, erro
 	hdr.ChangeTime = time.Time{}
 	hdr.Mode = fillGo18FileTypeBits(int64(chmodTarEntry(os.FileMode(hdr.Mode))), fi)
 	hdr.Name = canonicalTarName(name, fi.IsDir())
-	if err := setHeaderForSpecialDevice(hdr, name, fi.Sys()); err != nil {
-		return nil, err
-	}
 	return hdr, nil
 }
 
@@ -629,6 +678,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
 		}
 
 	case tar.TypeLink:
+		//#nosec G305 -- The target path is checked for path traversal.
 		targetPath := filepath.Join(extractDir, hdr.Linkname)
 		// check for hardlink breakout
 		if !strings.HasPrefix(targetPath, extractDir) {
@@ -641,7 +691,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
 	case tar.TypeSymlink:
 		// 	path 				-> hdr.Linkname = targetPath
 		// e.g. /extractDir/path/to/symlink 	-> ../2/file	= /extractDir/path/2/file
-		targetPath := filepath.Join(filepath.Dir(path), hdr.Linkname)
+		targetPath := filepath.Join(filepath.Dir(path), hdr.Linkname) //#nosec G305 -- The target path is checked for path traversal.
 
 		// the reason we don't need to check symlinks in the path (with FollowSymlinkInScope) is because
 		// that symlink would first have to be created, which would be caught earlier, at this very check:
@@ -970,6 +1020,7 @@ loop:
 			}
 		}
 
+		//#nosec G305 -- The joined path is checked for path traversal.
 		path := filepath.Join(dest, hdr.Name)
 		rel, err := filepath.Rel(dest, path)
 		if err != nil {
@@ -1034,6 +1085,7 @@ loop:
 	}
 
 	for _, hdr := range dirs {
+		//#nosec G305 -- The header was checked for path traversal before it was appended to the dirs slice.
 		path := filepath.Join(dest, hdr.Name)
 
 		if err := system.Chtimes(path, hdr.AccessTime, hdr.ModTime); err != nil {
@@ -1181,7 +1233,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
 			}
 			defer srcF.Close()
 
-			hdr, err := tar.FileInfoHeader(srcSt, "")
+			hdr, err := FileInfoHeaderNoLookups(srcSt, "")
 			if err != nil {
 				return err
 			}
diff --git a/pkg/archive/archive_linux.go b/pkg/archive/archive_linux.go
index 0a3cc1f92bcc2..76321a35e3898 100644
--- a/pkg/archive/archive_linux.go
+++ b/pkg/archive/archive_linux.go
@@ -59,7 +59,7 @@ func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os
 				Gname:      hdr.Gname,
 				AccessTime: hdr.AccessTime,
 				ChangeTime: hdr.ChangeTime,
-			}
+			} //#nosec G305 -- An archive is being created, not extracted.
 		}
 	}
 
diff --git a/pkg/archive/archive_unix.go b/pkg/archive/archive_unix.go
index fea53d3ae21ed..67a88851cf25f 100644
--- a/pkg/archive/archive_unix.go
+++ b/pkg/archive/archive_unix.go
@@ -17,6 +17,10 @@ import (
 	"golang.org/x/sys/unix"
 )
 
+func init() {
+	sysStat = statUnix
+}
+
 // fixVolumePathPrefix does platform specific processing to ensure that if
 // the path being passed in is not in a volume path format, convert it to one.
 func fixVolumePathPrefix(srcPath string) string {
@@ -45,19 +49,24 @@ func chmodTarEntry(perm os.FileMode) os.FileMode {
 	return perm // noop for unix as golang APIs provide perm bits correctly
 }
 
-func setHeaderForSpecialDevice(hdr *tar.Header, name string, stat interface{}) (err error) {
-	s, ok := stat.(*syscall.Stat_t)
+// statUnix populates hdr from system-dependent fields of fi without performing
+// any OS lookups.
+func statUnix(fi os.FileInfo, hdr *tar.Header) error {
+	s, ok := fi.Sys().(*syscall.Stat_t)
+	if !ok {
+		return nil
+	}
 
-	if ok {
-		// Currently go does not fill in the major/minors
-		if s.Mode&unix.S_IFBLK != 0 ||
-			s.Mode&unix.S_IFCHR != 0 {
-			hdr.Devmajor = int64(unix.Major(uint64(s.Rdev))) //nolint: unconvert
-			hdr.Devminor = int64(unix.Minor(uint64(s.Rdev))) //nolint: unconvert
-		}
+	hdr.Uid = int(s.Uid)
+	hdr.Gid = int(s.Gid)
+
+	if s.Mode&unix.S_IFBLK != 0 ||
+		s.Mode&unix.S_IFCHR != 0 {
+		hdr.Devmajor = int64(unix.Major(uint64(s.Rdev))) //nolint: unconvert
+		hdr.Devminor = int64(unix.Minor(uint64(s.Rdev))) //nolint: unconvert
 	}
 
-	return
+	return nil
 }
 
 func getInodeFromStat(stat interface{}) (inode uint64, err error) {
diff --git a/pkg/archive/diff.go b/pkg/archive/diff.go
index e095104bd96c4..6174bc2af43a7 100644
--- a/pkg/archive/diff.go
+++ b/pkg/archive/diff.go
@@ -113,6 +113,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
 				continue
 			}
 		}
+		//#nosec G305 -- The joined path is guarded against path traversal.
 		path := filepath.Join(dest, hdr.Name)
 		rel, err := filepath.Rel(dest, path)
 		if err != nil {
@@ -209,6 +210,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
 	}
 
 	for _, hdr := range dirs {
+		//#nosec G305 -- The header was checked for path traversal before it was appended to the dirs slice.
 		path := filepath.Join(dest, hdr.Name)
 		if err := system.Chtimes(path, hdr.AccessTime, hdr.ModTime); err != nil {
 			return 0, err
diff --git a/pkg/containerfs/archiver.go b/pkg/containerfs/archiver.go
index 308e2b88d3af1..450c986785b13 100644
--- a/pkg/containerfs/archiver.go
+++ b/pkg/containerfs/archiver.go
@@ -137,7 +137,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (retErr error) {
 			}
 			defer srcF.Close()
 
-			hdr, err := tar.FileInfoHeader(srcSt, "")
+			hdr, err := archive.FileInfoHeaderNoLookups(srcSt, "")
 			if err != nil {
 				return err
 			}
diff --git a/pkg/tarsum/tarsum.go b/pkg/tarsum/tarsum.go
index 5542e1b2c0290..5ea65f1ecdb59 100644
--- a/pkg/tarsum/tarsum.go
+++ b/pkg/tarsum/tarsum.go
@@ -246,6 +246,7 @@ func (ts *tarSum) Read(buf []byte) (int, error) {
 				return 0, err
 			}
 
+			//#nosec G305 -- The joined path is not passed to any filesystem APIs.
 			ts.currentFile = path.Join(".", path.Join("/", currentHeader.Name))
 			if err := ts.encodeHeader(currentHeader); err != nil {
 				return 0, err
diff --git a/vendor.conf b/vendor.conf
index ac62213633c08..d3654f1c8fc11 100644
--- a/vendor.conf
+++ b/vendor.conf
@@ -184,13 +184,4 @@ github.com/opencontainers/selinux                   2f45b3796d18f1ab4c9fc0c888a9
 github.com/willf/bitset                             559910e8471e48d76d9e5a1ba15842dee77ad45d # v1.1.11
 
 
-# archive/tar
-# rm -rf vendor/archive
-# mkdir -p ./vendor/archive
-# git clone -b go$GOLANG_VERSION --depth=1 git://github.com/golang/go.git ./go
-# git --git-dir ./go/.git --work-tree ./go am ../patches/0001-archive-tar-do-not-populate-user-group-names.patch
-# cp -a go/src/archive/tar ./vendor/archive/tar
-# rm -rf ./go
-# vndr -whitelist=^archive/tar
-
 # DO NOT EDIT BELOW THIS LINE -------- reserved for downstream projects --------
diff --git a/vendor/archive/tar/common.go b/vendor/archive/tar/common.go
deleted file mode 100644
index f6d701d925cba..0000000000000
--- a/vendor/archive/tar/common.go
+++ /dev/null
@@ -1,726 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package tar implements access to tar archives.
-//
-// Tape archives (tar) are a file format for storing a sequence of files that
-// can be read and written in a streaming manner.
-// This package aims to cover most variations of the format,
-// including those produced by GNU and BSD tar tools.
-package tar
-
-import (
-	"errors"
-	"fmt"
-	"io/fs"
-	"math"
-	"path"
-	"reflect"
-	"strconv"
-	"strings"
-	"time"
-)
-
-// BUG: Use of the Uid and Gid fields in Header could overflow on 32-bit
-// architectures. If a large value is encountered when decoding, the result
-// stored in Header will be the truncated version.
-
-var (
-	ErrHeader          = errors.New("archive/tar: invalid tar header")
-	ErrWriteTooLong    = errors.New("archive/tar: write too long")
-	ErrFieldTooLong    = errors.New("archive/tar: header field too long")
-	ErrWriteAfterClose = errors.New("archive/tar: write after close")
-	errMissData        = errors.New("archive/tar: sparse file references non-existent data")
-	errUnrefData       = errors.New("archive/tar: sparse file contains unreferenced data")
-	errWriteHole       = errors.New("archive/tar: write non-NUL byte in sparse hole")
-)
-
-type headerError []string
-
-func (he headerError) Error() string {
-	const prefix = "archive/tar: cannot encode header"
-	var ss []string
-	for _, s := range he {
-		if s != "" {
-			ss = append(ss, s)
-		}
-	}
-	if len(ss) == 0 {
-		return prefix
-	}
-	return fmt.Sprintf("%s: %v", prefix, strings.Join(ss, "; and "))
-}
-
-// Type flags for Header.Typeflag.
-const (
-	// Type '0' indicates a regular file.
-	TypeReg  = '0'
-	TypeRegA = '\x00' // Deprecated: Use TypeReg instead.
-
-	// Type '1' to '6' are header-only flags and may not have a data body.
-	TypeLink    = '1' // Hard link
-	TypeSymlink = '2' // Symbolic link
-	TypeChar    = '3' // Character device node
-	TypeBlock   = '4' // Block device node
-	TypeDir     = '5' // Directory
-	TypeFifo    = '6' // FIFO node
-
-	// Type '7' is reserved.
-	TypeCont = '7'
-
-	// Type 'x' is used by the PAX format to store key-value records that
-	// are only relevant to the next file.
-	// This package transparently handles these types.
-	TypeXHeader = 'x'
-
-	// Type 'g' is used by the PAX format to store key-value records that
-	// are relevant to all subsequent files.
-	// This package only supports parsing and composing such headers,
-	// but does not currently support persisting the global state across files.
-	TypeXGlobalHeader = 'g'
-
-	// Type 'S' indicates a sparse file in the GNU format.
-	TypeGNUSparse = 'S'
-
-	// Types 'L' and 'K' are used by the GNU format for a meta file
-	// used to store the path or link name for the next file.
-	// This package transparently handles these types.
-	TypeGNULongName = 'L'
-	TypeGNULongLink = 'K'
-)
-
-// Keywords for PAX extended header records.
-const (
-	paxNone     = "" // Indicates that no PAX key is suitable
-	paxPath     = "path"
-	paxLinkpath = "linkpath"
-	paxSize     = "size"
-	paxUid      = "uid"
-	paxGid      = "gid"
-	paxUname    = "uname"
-	paxGname    = "gname"
-	paxMtime    = "mtime"
-	paxAtime    = "atime"
-	paxCtime    = "ctime"   // Removed from later revision of PAX spec, but was valid
-	paxCharset  = "charset" // Currently unused
-	paxComment  = "comment" // Currently unused
-
-	paxSchilyXattr = "SCHILY.xattr."
-
-	// Keywords for GNU sparse files in a PAX extended header.
-	paxGNUSparse          = "GNU.sparse."
-	paxGNUSparseNumBlocks = "GNU.sparse.numblocks"
-	paxGNUSparseOffset    = "GNU.sparse.offset"
-	paxGNUSparseNumBytes  = "GNU.sparse.numbytes"
-	paxGNUSparseMap       = "GNU.sparse.map"
-	paxGNUSparseName      = "GNU.sparse.name"
-	paxGNUSparseMajor     = "GNU.sparse.major"
-	paxGNUSparseMinor     = "GNU.sparse.minor"
-	paxGNUSparseSize      = "GNU.sparse.size"
-	paxGNUSparseRealSize  = "GNU.sparse.realsize"
-)
-
-// basicKeys is a set of the PAX keys for which we have built-in support.
-// This does not contain "charset" or "comment", which are both PAX-specific,
-// so adding them as first-class features of Header is unlikely.
-// Users can use the PAXRecords field to set it themselves.
-var basicKeys = map[string]bool{
-	paxPath: true, paxLinkpath: true, paxSize: true, paxUid: true, paxGid: true,
-	paxUname: true, paxGname: true, paxMtime: true, paxAtime: true, paxCtime: true,
-}
-
-// A Header represents a single header in a tar archive.
-// Some fields may not be populated.
-//
-// For forward compatibility, users that retrieve a Header from Reader.Next,
-// mutate it in some ways, and then pass it back to Writer.WriteHeader
-// should do so by creating a new Header and copying the fields
-// that they are interested in preserving.
-type Header struct {
-	// Typeflag is the type of header entry.
-	// The zero value is automatically promoted to either TypeReg or TypeDir
-	// depending on the presence of a trailing slash in Name.
-	Typeflag byte
-
-	Name     string // Name of file entry
-	Linkname string // Target name of link (valid for TypeLink or TypeSymlink)
-
-	Size  int64  // Logical file size in bytes
-	Mode  int64  // Permission and mode bits
-	Uid   int    // User ID of owner
-	Gid   int    // Group ID of owner
-	Uname string // User name of owner
-	Gname string // Group name of owner
-
-	// If the Format is unspecified, then Writer.WriteHeader rounds ModTime
-	// to the nearest second and ignores the AccessTime and ChangeTime fields.
-	//
-	// To use AccessTime or ChangeTime, specify the Format as PAX or GNU.
-	// To use sub-second resolution, specify the Format as PAX.
-	ModTime    time.Time // Modification time
-	AccessTime time.Time // Access time (requires either PAX or GNU support)
-	ChangeTime time.Time // Change time (requires either PAX or GNU support)
-
-	Devmajor int64 // Major device number (valid for TypeChar or TypeBlock)
-	Devminor int64 // Minor device number (valid for TypeChar or TypeBlock)
-
-	// Xattrs stores extended attributes as PAX records under the
-	// "SCHILY.xattr." namespace.
-	//
-	// The following are semantically equivalent:
-	//  h.Xattrs[key] = value
-	//  h.PAXRecords["SCHILY.xattr."+key] = value
-	//
-	// When Writer.WriteHeader is called, the contents of Xattrs will take
-	// precedence over those in PAXRecords.
-	//
-	// Deprecated: Use PAXRecords instead.
-	Xattrs map[string]string
-
-	// PAXRecords is a map of PAX extended header records.
-	//
-	// User-defined records should have keys of the following form:
-	//	VENDOR.keyword
-	// Where VENDOR is some namespace in all uppercase, and keyword may
-	// not contain the '=' character (e.g., "GOLANG.pkg.version").
-	// The key and value should be non-empty UTF-8 strings.
-	//
-	// When Writer.WriteHeader is called, PAX records derived from the
-	// other fields in Header take precedence over PAXRecords.
-	PAXRecords map[string]string
-
-	// Format specifies the format of the tar header.
-	//
-	// This is set by Reader.Next as a best-effort guess at the format.
-	// Since the Reader liberally reads some non-compliant files,
-	// it is possible for this to be FormatUnknown.
-	//
-	// If the format is unspecified when Writer.WriteHeader is called,
-	// then it uses the first format (in the order of USTAR, PAX, GNU)
-	// capable of encoding this Header (see Format).
-	Format Format
-}
-
-// sparseEntry represents a Length-sized fragment at Offset in the file.
-type sparseEntry struct{ Offset, Length int64 }
-
-func (s sparseEntry) endOffset() int64 { return s.Offset + s.Length }
-
-// A sparse file can be represented as either a sparseDatas or a sparseHoles.
-// As long as the total size is known, they are equivalent and one can be
-// converted to the other form and back. The various tar formats with sparse
-// file support represent sparse files in the sparseDatas form. That is, they
-// specify the fragments in the file that has data, and treat everything else as
-// having zero bytes. As such, the encoding and decoding logic in this package
-// deals with sparseDatas.
-//
-// However, the external API uses sparseHoles instead of sparseDatas because the
-// zero value of sparseHoles logically represents a normal file (i.e., there are
-// no holes in it). On the other hand, the zero value of sparseDatas implies
-// that the file has no data in it, which is rather odd.
-//
-// As an example, if the underlying raw file contains the 10-byte data:
-//
-//	var compactFile = "abcdefgh"
-//
-// And the sparse map has the following entries:
-//
-//	var spd sparseDatas = []sparseEntry{
-//		{Offset: 2,  Length: 5},  // Data fragment for 2..6
-//		{Offset: 18, Length: 3},  // Data fragment for 18..20
-//	}
-//	var sph sparseHoles = []sparseEntry{
-//		{Offset: 0,  Length: 2},  // Hole fragment for 0..1
-//		{Offset: 7,  Length: 11}, // Hole fragment for 7..17
-//		{Offset: 21, Length: 4},  // Hole fragment for 21..24
-//	}
-//
-// Then the content of the resulting sparse file with a Header.Size of 25 is:
-//
-//	var sparseFile = "\x00"*2 + "abcde" + "\x00"*11 + "fgh" + "\x00"*4
-type (
-	sparseDatas []sparseEntry
-	sparseHoles []sparseEntry
-)
-
-// validateSparseEntries reports whether sp is a valid sparse map.
-// It does not matter whether sp represents data fragments or hole fragments.
-func validateSparseEntries(sp []sparseEntry, size int64) bool {
-	// Validate all sparse entries. These are the same checks as performed by
-	// the BSD tar utility.
-	if size < 0 {
-		return false
-	}
-	var pre sparseEntry
-	for _, cur := range sp {
-		switch {
-		case cur.Offset < 0 || cur.Length < 0:
-			return false // Negative values are never okay
-		case cur.Offset > math.MaxInt64-cur.Length:
-			return false // Integer overflow with large length
-		case cur.endOffset() > size:
-			return false // Region extends beyond the actual size
-		case pre.endOffset() > cur.Offset:
-			return false // Regions cannot overlap and must be in order
-		}
-		pre = cur
-	}
-	return true
-}
-
-// alignSparseEntries mutates src and returns dst where each fragment's
-// starting offset is aligned up to the nearest block edge, and each
-// ending offset is aligned down to the nearest block edge.
-//
-// Even though the Go tar Reader and the BSD tar utility can handle entries
-// with arbitrary offsets and lengths, the GNU tar utility can only handle
-// offsets and lengths that are multiples of blockSize.
-func alignSparseEntries(src []sparseEntry, size int64) []sparseEntry {
-	dst := src[:0]
-	for _, s := range src {
-		pos, end := s.Offset, s.endOffset()
-		pos += blockPadding(+pos) // Round-up to nearest blockSize
-		if end != size {
-			end -= blockPadding(-end) // Round-down to nearest blockSize
-		}
-		if pos < end {
-			dst = append(dst, sparseEntry{Offset: pos, Length: end - pos})
-		}
-	}
-	return dst
-}
-
-// invertSparseEntries converts a sparse map from one form to the other.
-// If the input is sparseHoles, then it will output sparseDatas and vice-versa.
-// The input must have been already validated.
-//
-// This function mutates src and returns a normalized map where:
-//   - adjacent fragments are coalesced together
-//   - only the last fragment may be empty
-//   - the endOffset of the last fragment is the total size
-func invertSparseEntries(src []sparseEntry, size int64) []sparseEntry {
-	dst := src[:0]
-	var pre sparseEntry
-	for _, cur := range src {
-		if cur.Length == 0 {
-			continue // Skip empty fragments
-		}
-		pre.Length = cur.Offset - pre.Offset
-		if pre.Length > 0 {
-			dst = append(dst, pre) // Only add non-empty fragments
-		}
-		pre.Offset = cur.endOffset()
-	}
-	pre.Length = size - pre.Offset // Possibly the only empty fragment
-	return append(dst, pre)
-}
-
-// fileState tracks the number of logical (includes sparse holes) and physical
-// (actual in tar archive) bytes remaining for the current file.
-//
-// Invariant: logicalRemaining >= physicalRemaining
-type fileState interface {
-	logicalRemaining() int64
-	physicalRemaining() int64
-}
-
-// allowedFormats determines which formats can be used.
-// The value returned is the logical OR of multiple possible formats.
-// If the value is FormatUnknown, then the input Header cannot be encoded
-// and an error is returned explaining why.
-//
-// As a by-product of checking the fields, this function returns paxHdrs, which
-// contain all fields that could not be directly encoded.
-// A value receiver ensures that this method does not mutate the source Header.
-func (h Header) allowedFormats() (format Format, paxHdrs map[string]string, err error) {
-	format = FormatUSTAR | FormatPAX | FormatGNU
-	paxHdrs = make(map[string]string)
-
-	var whyNoUSTAR, whyNoPAX, whyNoGNU string
-	var preferPAX bool // Prefer PAX over USTAR
-	verifyString := func(s string, size int, name, paxKey string) {
-		// NUL-terminator is optional for path and linkpath.
-		// Technically, it is required for uname and gname,
-		// but neither GNU nor BSD tar checks for it.
-		tooLong := len(s) > size
-		allowLongGNU := paxKey == paxPath || paxKey == paxLinkpath
-		if hasNUL(s) || (tooLong && !allowLongGNU) {
-			whyNoGNU = fmt.Sprintf("GNU cannot encode %s=%q", name, s)
-			format.mustNotBe(FormatGNU)
-		}
-		if !isASCII(s) || tooLong {
-			canSplitUSTAR := paxKey == paxPath
-			if _, _, ok := splitUSTARPath(s); !canSplitUSTAR || !ok {
-				whyNoUSTAR = fmt.Sprintf("USTAR cannot encode %s=%q", name, s)
-				format.mustNotBe(FormatUSTAR)
-			}
-			if paxKey == paxNone {
-				whyNoPAX = fmt.Sprintf("PAX cannot encode %s=%q", name, s)
-				format.mustNotBe(FormatPAX)
-			} else {
-				paxHdrs[paxKey] = s
-			}
-		}
-		if v, ok := h.PAXRecords[paxKey]; ok && v == s {
-			paxHdrs[paxKey] = v
-		}
-	}
-	verifyNumeric := func(n int64, size int, name, paxKey string) {
-		if !fitsInBase256(size, n) {
-			whyNoGNU = fmt.Sprintf("GNU cannot encode %s=%d", name, n)
-			format.mustNotBe(FormatGNU)
-		}
-		if !fitsInOctal(size, n) {
-			whyNoUSTAR = fmt.Sprintf("USTAR cannot encode %s=%d", name, n)
-			format.mustNotBe(FormatUSTAR)
-			if paxKey == paxNone {
-				whyNoPAX = fmt.Sprintf("PAX cannot encode %s=%d", name, n)
-				format.mustNotBe(FormatPAX)
-			} else {
-				paxHdrs[paxKey] = strconv.FormatInt(n, 10)
-			}
-		}
-		if v, ok := h.PAXRecords[paxKey]; ok && v == strconv.FormatInt(n, 10) {
-			paxHdrs[paxKey] = v
-		}
-	}
-	verifyTime := func(ts time.Time, size int, name, paxKey string) {
-		if ts.IsZero() {
-			return // Always okay
-		}
-		if !fitsInBase256(size, ts.Unix()) {
-			whyNoGNU = fmt.Sprintf("GNU cannot encode %s=%v", name, ts)
-			format.mustNotBe(FormatGNU)
-		}
-		isMtime := paxKey == paxMtime
-		fitsOctal := fitsInOctal(size, ts.Unix())
-		if (isMtime && !fitsOctal) || !isMtime {
-			whyNoUSTAR = fmt.Sprintf("USTAR cannot encode %s=%v", name, ts)
-			format.mustNotBe(FormatUSTAR)
-		}
-		needsNano := ts.Nanosecond() != 0
-		if !isMtime || !fitsOctal || needsNano {
-			preferPAX = true // USTAR may truncate sub-second measurements
-			if paxKey == paxNone {
-				whyNoPAX = fmt.Sprintf("PAX cannot encode %s=%v", name, ts)
-				format.mustNotBe(FormatPAX)
-			} else {
-				paxHdrs[paxKey] = formatPAXTime(ts)
-			}
-		}
-		if v, ok := h.PAXRecords[paxKey]; ok && v == formatPAXTime(ts) {
-			paxHdrs[paxKey] = v
-		}
-	}
-
-	// Check basic fields.
-	var blk block
-	v7 := blk.toV7()
-	ustar := blk.toUSTAR()
-	gnu := blk.toGNU()
-	verifyString(h.Name, len(v7.name()), "Name", paxPath)
-	verifyString(h.Linkname, len(v7.linkName()), "Linkname", paxLinkpath)
-	verifyString(h.Uname, len(ustar.userName()), "Uname", paxUname)
-	verifyString(h.Gname, len(ustar.groupName()), "Gname", paxGname)
-	verifyNumeric(h.Mode, len(v7.mode()), "Mode", paxNone)
-	verifyNumeric(int64(h.Uid), len(v7.uid()), "Uid", paxUid)
-	verifyNumeric(int64(h.Gid), len(v7.gid()), "Gid", paxGid)
-	verifyNumeric(h.Size, len(v7.size()), "Size", paxSize)
-	verifyNumeric(h.Devmajor, len(ustar.devMajor()), "Devmajor", paxNone)
-	verifyNumeric(h.Devminor, len(ustar.devMinor()), "Devminor", paxNone)
-	verifyTime(h.ModTime, len(v7.modTime()), "ModTime", paxMtime)
-	verifyTime(h.AccessTime, len(gnu.accessTime()), "AccessTime", paxAtime)
-	verifyTime(h.ChangeTime, len(gnu.changeTime()), "ChangeTime", paxCtime)
-
-	// Check for header-only types.
-	var whyOnlyPAX, whyOnlyGNU string
-	switch h.Typeflag {
-	case TypeReg, TypeChar, TypeBlock, TypeFifo, TypeGNUSparse:
-		// Exclude TypeLink and TypeSymlink, since they may reference directories.
-		if strings.HasSuffix(h.Name, "/") {
-			return FormatUnknown, nil, headerError{"filename may not have trailing slash"}
-		}
-	case TypeXHeader, TypeGNULongName, TypeGNULongLink:
-		return FormatUnknown, nil, headerError{"cannot manually encode TypeXHeader, TypeGNULongName, or TypeGNULongLink headers"}
-	case TypeXGlobalHeader:
-		h2 := Header{Name: h.Name, Typeflag: h.Typeflag, Xattrs: h.Xattrs, PAXRecords: h.PAXRecords, Format: h.Format}
-		if !reflect.DeepEqual(h, h2) {
-			return FormatUnknown, nil, headerError{"only PAXRecords should be set for TypeXGlobalHeader"}
-		}
-		whyOnlyPAX = "only PAX supports TypeXGlobalHeader"
-		format.mayOnlyBe(FormatPAX)
-	}
-	if !isHeaderOnlyType(h.Typeflag) && h.Size < 0 {
-		return FormatUnknown, nil, headerError{"negative size on header-only type"}
-	}
-
-	// Check PAX records.
-	if len(h.Xattrs) > 0 {
-		for k, v := range h.Xattrs {
-			paxHdrs[paxSchilyXattr+k] = v
-		}
-		whyOnlyPAX = "only PAX supports Xattrs"
-		format.mayOnlyBe(FormatPAX)
-	}
-	if len(h.PAXRecords) > 0 {
-		for k, v := range h.PAXRecords {
-			switch _, exists := paxHdrs[k]; {
-			case exists:
-				continue // Do not overwrite existing records
-			case h.Typeflag == TypeXGlobalHeader:
-				paxHdrs[k] = v // Copy all records
-			case !basicKeys[k] && !strings.HasPrefix(k, paxGNUSparse):
-				paxHdrs[k] = v // Ignore local records that may conflict
-			}
-		}
-		whyOnlyPAX = "only PAX supports PAXRecords"
-		format.mayOnlyBe(FormatPAX)
-	}
-	for k, v := range paxHdrs {
-		if !validPAXRecord(k, v) {
-			return FormatUnknown, nil, headerError{fmt.Sprintf("invalid PAX record: %q", k+" = "+v)}
-		}
-	}
-
-	// TODO(dsnet): Re-enable this when adding sparse support.
-	// See https://golang.org/issue/22735
-	/*
-		// Check sparse files.
-		if len(h.SparseHoles) > 0 || h.Typeflag == TypeGNUSparse {
-			if isHeaderOnlyType(h.Typeflag) {
-				return FormatUnknown, nil, headerError{"header-only type cannot be sparse"}
-			}
-			if !validateSparseEntries(h.SparseHoles, h.Size) {
-				return FormatUnknown, nil, headerError{"invalid sparse holes"}
-			}
-			if h.Typeflag == TypeGNUSparse {
-				whyOnlyGNU = "only GNU supports TypeGNUSparse"
-				format.mayOnlyBe(FormatGNU)
-			} else {
-				whyNoGNU = "GNU supports sparse files only with TypeGNUSparse"
-				format.mustNotBe(FormatGNU)
-			}
-			whyNoUSTAR = "USTAR does not support sparse files"
-			format.mustNotBe(FormatUSTAR)
-		}
-	*/
-
-	// Check desired format.
-	if wantFormat := h.Format; wantFormat != FormatUnknown {
-		if wantFormat.has(FormatPAX) && !preferPAX {
-			wantFormat.mayBe(FormatUSTAR) // PAX implies USTAR allowed too
-		}
-		format.mayOnlyBe(wantFormat) // Set union of formats allowed and format wanted
-	}
-	if format == FormatUnknown {
-		switch h.Format {
-		case FormatUSTAR:
-			err = headerError{"Format specifies USTAR", whyNoUSTAR, whyOnlyPAX, whyOnlyGNU}
-		case FormatPAX:
-			err = headerError{"Format specifies PAX", whyNoPAX, whyOnlyGNU}
-		case FormatGNU:
-			err = headerError{"Format specifies GNU", whyNoGNU, whyOnlyPAX}
-		default:
-			err = headerError{whyNoUSTAR, whyNoPAX, whyNoGNU, whyOnlyPAX, whyOnlyGNU}
-		}
-	}
-	return format, paxHdrs, err
-}
-
-// FileInfo returns an fs.FileInfo for the Header.
-func (h *Header) FileInfo() fs.FileInfo {
-	return headerFileInfo{h}
-}
-
-// headerFileInfo implements fs.FileInfo.
-type headerFileInfo struct {
-	h *Header
-}
-
-func (fi headerFileInfo) Size() int64        { return fi.h.Size }
-func (fi headerFileInfo) IsDir() bool        { return fi.Mode().IsDir() }
-func (fi headerFileInfo) ModTime() time.Time { return fi.h.ModTime }
-func (fi headerFileInfo) Sys() any           { return fi.h }
-
-// Name returns the base name of the file.
-func (fi headerFileInfo) Name() string {
-	if fi.IsDir() {
-		return path.Base(path.Clean(fi.h.Name))
-	}
-	return path.Base(fi.h.Name)
-}
-
-// Mode returns the permission and mode bits for the headerFileInfo.
-func (fi headerFileInfo) Mode() (mode fs.FileMode) {
-	// Set file permission bits.
-	mode = fs.FileMode(fi.h.Mode).Perm()
-
-	// Set setuid, setgid and sticky bits.
-	if fi.h.Mode&c_ISUID != 0 {
-		mode |= fs.ModeSetuid
-	}
-	if fi.h.Mode&c_ISGID != 0 {
-		mode |= fs.ModeSetgid
-	}
-	if fi.h.Mode&c_ISVTX != 0 {
-		mode |= fs.ModeSticky
-	}
-
-	// Set file mode bits; clear perm, setuid, setgid, and sticky bits.
-	switch m := fs.FileMode(fi.h.Mode) &^ 07777; m {
-	case c_ISDIR:
-		mode |= fs.ModeDir
-	case c_ISFIFO:
-		mode |= fs.ModeNamedPipe
-	case c_ISLNK:
-		mode |= fs.ModeSymlink
-	case c_ISBLK:
-		mode |= fs.ModeDevice
-	case c_ISCHR:
-		mode |= fs.ModeDevice
-		mode |= fs.ModeCharDevice
-	case c_ISSOCK:
-		mode |= fs.ModeSocket
-	}
-
-	switch fi.h.Typeflag {
-	case TypeSymlink:
-		mode |= fs.ModeSymlink
-	case TypeChar:
-		mode |= fs.ModeDevice
-		mode |= fs.ModeCharDevice
-	case TypeBlock:
-		mode |= fs.ModeDevice
-	case TypeDir:
-		mode |= fs.ModeDir
-	case TypeFifo:
-		mode |= fs.ModeNamedPipe
-	}
-
-	return mode
-}
-
-// sysStat, if non-nil, populates h from system-dependent fields of fi.
-var sysStat func(fi fs.FileInfo, h *Header) error
-
-const (
-	// Mode constants from the USTAR spec:
-	// See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_06
-	c_ISUID = 04000 // Set uid
-	c_ISGID = 02000 // Set gid
-	c_ISVTX = 01000 // Save text (sticky bit)
-
-	// Common Unix mode constants; these are not defined in any common tar standard.
-	// Header.FileInfo understands these, but FileInfoHeader will never produce these.
-	c_ISDIR  = 040000  // Directory
-	c_ISFIFO = 010000  // FIFO
-	c_ISREG  = 0100000 // Regular file
-	c_ISLNK  = 0120000 // Symbolic link
-	c_ISBLK  = 060000  // Block special file
-	c_ISCHR  = 020000  // Character special file
-	c_ISSOCK = 0140000 // Socket
-)
-
-// FileInfoHeader creates a partially-populated Header from fi.
-// If fi describes a symlink, FileInfoHeader records link as the link target.
-// If fi describes a directory, a slash is appended to the name.
-//
-// Since fs.FileInfo's Name method only returns the base name of
-// the file it describes, it may be necessary to modify Header.Name
-// to provide the full path name of the file.
-func FileInfoHeader(fi fs.FileInfo, link string) (*Header, error) {
-	if fi == nil {
-		return nil, errors.New("archive/tar: FileInfo is nil")
-	}
-	fm := fi.Mode()
-	h := &Header{
-		Name:    fi.Name(),
-		ModTime: fi.ModTime(),
-		Mode:    int64(fm.Perm()), // or'd with c_IS* constants later
-	}
-	switch {
-	case fm.IsRegular():
-		h.Typeflag = TypeReg
-		h.Size = fi.Size()
-	case fi.IsDir():
-		h.Typeflag = TypeDir
-		h.Name += "/"
-	case fm&fs.ModeSymlink != 0:
-		h.Typeflag = TypeSymlink
-		h.Linkname = link
-	case fm&fs.ModeDevice != 0:
-		if fm&fs.ModeCharDevice != 0 {
-			h.Typeflag = TypeChar
-		} else {
-			h.Typeflag = TypeBlock
-		}
-	case fm&fs.ModeNamedPipe != 0:
-		h.Typeflag = TypeFifo
-	case fm&fs.ModeSocket != 0:
-		return nil, fmt.Errorf("archive/tar: sockets not supported")
-	default:
-		return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm)
-	}
-	if fm&fs.ModeSetuid != 0 {
-		h.Mode |= c_ISUID
-	}
-	if fm&fs.ModeSetgid != 0 {
-		h.Mode |= c_ISGID
-	}
-	if fm&fs.ModeSticky != 0 {
-		h.Mode |= c_ISVTX
-	}
-	// If possible, populate additional fields from OS-specific
-	// FileInfo fields.
-	if sys, ok := fi.Sys().(*Header); ok {
-		// This FileInfo came from a Header (not the OS). Use the
-		// original Header to populate all remaining fields.
-		h.Uid = sys.Uid
-		h.Gid = sys.Gid
-		h.Uname = sys.Uname
-		h.Gname = sys.Gname
-		h.AccessTime = sys.AccessTime
-		h.ChangeTime = sys.ChangeTime
-		if sys.Xattrs != nil {
-			h.Xattrs = make(map[string]string)
-			for k, v := range sys.Xattrs {
-				h.Xattrs[k] = v
-			}
-		}
-		if sys.Typeflag == TypeLink {
-			// hard link
-			h.Typeflag = TypeLink
-			h.Size = 0
-			h.Linkname = sys.Linkname
-		}
-		if sys.PAXRecords != nil {
-			h.PAXRecords = make(map[string]string)
-			for k, v := range sys.PAXRecords {
-				h.PAXRecords[k] = v
-			}
-		}
-	}
-	if sysStat != nil {
-		return h, sysStat(fi, h)
-	}
-	return h, nil
-}
-
-// isHeaderOnlyType checks if the given type flag is of the type that has no
-// data section even if a size is specified.
-func isHeaderOnlyType(flag byte) bool {
-	switch flag {
-	case TypeLink, TypeSymlink, TypeChar, TypeBlock, TypeDir, TypeFifo:
-		return true
-	default:
-		return false
-	}
-}
-
-func min(a, b int64) int64 {
-	if a < b {
-		return a
-	}
-	return b
-}
diff --git a/vendor/archive/tar/format.go b/vendor/archive/tar/format.go
deleted file mode 100644
index 8898c438b513e..0000000000000
--- a/vendor/archive/tar/format.go
+++ /dev/null
@@ -1,307 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tar
-
-import "strings"
-
-// Format represents the tar archive format.
-//
-// The original tar format was introduced in Unix V7.
-// Since then, there have been multiple competing formats attempting to
-// standardize or extend the V7 format to overcome its limitations.
-// The most common formats are the USTAR, PAX, and GNU formats,
-// each with their own advantages and limitations.
-//
-// The following table captures the capabilities of each format:
-//
-//	                  |  USTAR |       PAX |       GNU
-//	------------------+--------+-----------+----------
-//	Name              |   256B | unlimited | unlimited
-//	Linkname          |   100B | unlimited | unlimited
-//	Size              | uint33 | unlimited |    uint89
-//	Mode              | uint21 |    uint21 |    uint57
-//	Uid/Gid           | uint21 | unlimited |    uint57
-//	Uname/Gname       |    32B | unlimited |       32B
-//	ModTime           | uint33 | unlimited |     int89
-//	AccessTime        |    n/a | unlimited |     int89
-//	ChangeTime        |    n/a | unlimited |     int89
-//	Devmajor/Devminor | uint21 |    uint21 |    uint57
-//	------------------+--------+-----------+----------
-//	string encoding   |  ASCII |     UTF-8 |    binary
-//	sub-second times  |     no |       yes |        no
-//	sparse files      |     no |       yes |       yes
-//
-// The table's upper portion shows the Header fields, where each format reports
-// the maximum number of bytes allowed for each string field and
-// the integer type used to store each numeric field
-// (where timestamps are stored as the number of seconds since the Unix epoch).
-//
-// The table's lower portion shows specialized features of each format,
-// such as supported string encodings, support for sub-second timestamps,
-// or support for sparse files.
-//
-// The Writer currently provides no support for sparse files.
-type Format int
-
-// Constants to identify various tar formats.
-const (
-	// Deliberately hide the meaning of constants from public API.
-	_ Format = (1 << iota) / 4 // Sequence of 0, 0, 1, 2, 4, 8, etc...
-
-	// FormatUnknown indicates that the format is unknown.
-	FormatUnknown
-
-	// The format of the original Unix V7 tar tool prior to standardization.
-	formatV7
-
-	// FormatUSTAR represents the USTAR header format defined in POSIX.1-1988.
-	//
-	// While this format is compatible with most tar readers,
-	// the format has several limitations making it unsuitable for some usages.
-	// Most notably, it cannot support sparse files, files larger than 8GiB,
-	// filenames larger than 256 characters, and non-ASCII filenames.
-	//
-	// Reference:
-	//	http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_06
-	FormatUSTAR
-
-	// FormatPAX represents the PAX header format defined in POSIX.1-2001.
-	//
-	// PAX extends USTAR by writing a special file with Typeflag TypeXHeader
-	// preceding the original header. This file contains a set of key-value
-	// records, which are used to overcome USTAR's shortcomings, in addition to
-	// providing the ability to have sub-second resolution for timestamps.
-	//
-	// Some newer formats add their own extensions to PAX by defining their
-	// own keys and assigning certain semantic meaning to the associated values.
-	// For example, sparse file support in PAX is implemented using keys
-	// defined by the GNU manual (e.g., "GNU.sparse.map").
-	//
-	// Reference:
-	//	http://pubs.opengroup.org/onlinepubs/009695399/utilities/pax.html
-	FormatPAX
-
-	// FormatGNU represents the GNU header format.
-	//
-	// The GNU header format is older than the USTAR and PAX standards and
-	// is not compatible with them. The GNU format supports
-	// arbitrary file sizes, filenames of arbitrary encoding and length,
-	// sparse files, and other features.
-	//
-	// It is recommended that PAX be chosen over GNU unless the target
-	// application can only parse GNU formatted archives.
-	//
-	// Reference:
-	//	https://www.gnu.org/software/tar/manual/html_node/Standard.html
-	FormatGNU
-
-	// Schily's tar format, which is incompatible with USTAR.
-	// This does not cover STAR extensions to the PAX format; these fall under
-	// the PAX format.
-	formatSTAR
-
-	formatMax
-)
-
-func (f Format) has(f2 Format) bool   { return f&f2 != 0 }
-func (f *Format) mayBe(f2 Format)     { *f |= f2 }
-func (f *Format) mayOnlyBe(f2 Format) { *f &= f2 }
-func (f *Format) mustNotBe(f2 Format) { *f &^= f2 }
-
-var formatNames = map[Format]string{
-	formatV7: "V7", FormatUSTAR: "USTAR", FormatPAX: "PAX", FormatGNU: "GNU", formatSTAR: "STAR",
-}
-
-func (f Format) String() string {
-	var ss []string
-	for f2 := Format(1); f2 < formatMax; f2 <<= 1 {
-		if f.has(f2) {
-			ss = append(ss, formatNames[f2])
-		}
-	}
-	switch len(ss) {
-	case 0:
-		return "<unknown>"
-	case 1:
-		return ss[0]
-	default:
-		return "(" + strings.Join(ss, " | ") + ")"
-	}
-}
-
-// Magics used to identify various formats.
-const (
-	magicGNU, versionGNU     = "ustar ", " \x00"
-	magicUSTAR, versionUSTAR = "ustar\x00", "00"
-	trailerSTAR              = "tar\x00"
-)
-
-// Size constants from various tar specifications.
-const (
-	blockSize  = 512 // Size of each block in a tar stream
-	nameSize   = 100 // Max length of the name field in USTAR format
-	prefixSize = 155 // Max length of the prefix field in USTAR format
-
-	// Max length of a special file (PAX header, GNU long name or link).
-	// This matches the limit used by libarchive.
-	maxSpecialFileSize = 1 << 20
-)
-
-// blockPadding computes the number of bytes needed to pad offset up to the
-// nearest block edge where 0 <= n < blockSize.
-func blockPadding(offset int64) (n int64) {
-	return -offset & (blockSize - 1)
-}
-
-var zeroBlock block
-
-type block [blockSize]byte
-
-// Convert block to any number of formats.
-func (b *block) toV7() *headerV7       { return (*headerV7)(b) }
-func (b *block) toGNU() *headerGNU     { return (*headerGNU)(b) }
-func (b *block) toSTAR() *headerSTAR   { return (*headerSTAR)(b) }
-func (b *block) toUSTAR() *headerUSTAR { return (*headerUSTAR)(b) }
-func (b *block) toSparse() sparseArray { return sparseArray(b[:]) }
-
-// GetFormat checks that the block is a valid tar header based on the checksum.
-// It then attempts to guess the specific format based on magic values.
-// If the checksum fails, then FormatUnknown is returned.
-func (b *block) getFormat() Format {
-	// Verify checksum.
-	var p parser
-	value := p.parseOctal(b.toV7().chksum())
-	chksum1, chksum2 := b.computeChecksum()
-	if p.err != nil || (value != chksum1 && value != chksum2) {
-		return FormatUnknown
-	}
-
-	// Guess the magic values.
-	magic := string(b.toUSTAR().magic())
-	version := string(b.toUSTAR().version())
-	trailer := string(b.toSTAR().trailer())
-	switch {
-	case magic == magicUSTAR && trailer == trailerSTAR:
-		return formatSTAR
-	case magic == magicUSTAR:
-		return FormatUSTAR | FormatPAX
-	case magic == magicGNU && version == versionGNU:
-		return FormatGNU
-	default:
-		return formatV7
-	}
-}
-
-// setFormat writes the magic values necessary for specified format
-// and then updates the checksum accordingly.
-func (b *block) setFormat(format Format) {
-	// Set the magic values.
-	switch {
-	case format.has(formatV7):
-		// Do nothing.
-	case format.has(FormatGNU):
-		copy(b.toGNU().magic(), magicGNU)
-		copy(b.toGNU().version(), versionGNU)
-	case format.has(formatSTAR):
-		copy(b.toSTAR().magic(), magicUSTAR)
-		copy(b.toSTAR().version(), versionUSTAR)
-		copy(b.toSTAR().trailer(), trailerSTAR)
-	case format.has(FormatUSTAR | FormatPAX):
-		copy(b.toUSTAR().magic(), magicUSTAR)
-		copy(b.toUSTAR().version(), versionUSTAR)
-	default:
-		panic("invalid format")
-	}
-
-	// Update checksum.
-	// This field is special in that it is terminated by a NULL then space.
-	var f formatter
-	field := b.toV7().chksum()
-	chksum, _ := b.computeChecksum() // Possible values are 256..128776
-	f.formatOctal(field[:7], chksum) // Never fails since 128776 < 262143
-	field[7] = ' '
-}
-
-// computeChecksum computes the checksum for the header block.
-// POSIX specifies a sum of the unsigned byte values, but the Sun tar used
-// signed byte values.
-// We compute and return both.
-func (b *block) computeChecksum() (unsigned, signed int64) {
-	for i, c := range b {
-		if 148 <= i && i < 156 {
-			c = ' ' // Treat the checksum field itself as all spaces.
-		}
-		unsigned += int64(c)
-		signed += int64(int8(c))
-	}
-	return unsigned, signed
-}
-
-// Reset clears the block with all zeros.
-func (b *block) reset() {
-	*b = block{}
-}
-
-type headerV7 [blockSize]byte
-
-func (h *headerV7) name() []byte     { return h[000:][:100] }
-func (h *headerV7) mode() []byte     { return h[100:][:8] }
-func (h *headerV7) uid() []byte      { return h[108:][:8] }
-func (h *headerV7) gid() []byte      { return h[116:][:8] }
-func (h *headerV7) size() []byte     { return h[124:][:12] }
-func (h *headerV7) modTime() []byte  { return h[136:][:12] }
-func (h *headerV7) chksum() []byte   { return h[148:][:8] }
-func (h *headerV7) typeFlag() []byte { return h[156:][:1] }
-func (h *headerV7) linkName() []byte { return h[157:][:100] }
-
-type headerGNU [blockSize]byte
-
-func (h *headerGNU) v7() *headerV7       { return (*headerV7)(h) }
-func (h *headerGNU) magic() []byte       { return h[257:][:6] }
-func (h *headerGNU) version() []byte     { return h[263:][:2] }
-func (h *headerGNU) userName() []byte    { return h[265:][:32] }
-func (h *headerGNU) groupName() []byte   { return h[297:][:32] }
-func (h *headerGNU) devMajor() []byte    { return h[329:][:8] }
-func (h *headerGNU) devMinor() []byte    { return h[337:][:8] }
-func (h *headerGNU) accessTime() []byte  { return h[345:][:12] }
-func (h *headerGNU) changeTime() []byte  { return h[357:][:12] }
-func (h *headerGNU) sparse() sparseArray { return sparseArray(h[386:][:24*4+1]) }
-func (h *headerGNU) realSize() []byte    { return h[483:][:12] }
-
-type headerSTAR [blockSize]byte
-
-func (h *headerSTAR) v7() *headerV7      { return (*headerV7)(h) }
-func (h *headerSTAR) magic() []byte      { return h[257:][:6] }
-func (h *headerSTAR) version() []byte    { return h[263:][:2] }
-func (h *headerSTAR) userName() []byte   { return h[265:][:32] }
-func (h *headerSTAR) groupName() []byte  { return h[297:][:32] }
-func (h *headerSTAR) devMajor() []byte   { return h[329:][:8] }
-func (h *headerSTAR) devMinor() []byte   { return h[337:][:8] }
-func (h *headerSTAR) prefix() []byte     { return h[345:][:131] }
-func (h *headerSTAR) accessTime() []byte { return h[476:][:12] }
-func (h *headerSTAR) changeTime() []byte { return h[488:][:12] }
-func (h *headerSTAR) trailer() []byte    { return h[508:][:4] }
-
-type headerUSTAR [blockSize]byte
-
-func (h *headerUSTAR) v7() *headerV7     { return (*headerV7)(h) }
-func (h *headerUSTAR) magic() []byte     { return h[257:][:6] }
-func (h *headerUSTAR) version() []byte   { return h[263:][:2] }
-func (h *headerUSTAR) userName() []byte  { return h[265:][:32] }
-func (h *headerUSTAR) groupName() []byte { return h[297:][:32] }
-func (h *headerUSTAR) devMajor() []byte  { return h[329:][:8] }
-func (h *headerUSTAR) devMinor() []byte  { return h[337:][:8] }
-func (h *headerUSTAR) prefix() []byte    { return h[345:][:155] }
-
-type sparseArray []byte
-
-func (s sparseArray) entry(i int) sparseElem { return sparseElem(s[i*24:]) }
-func (s sparseArray) isExtended() []byte     { return s[24*s.maxEntries():][:1] }
-func (s sparseArray) maxEntries() int        { return len(s) / 24 }
-
-type sparseElem []byte
-
-func (s sparseElem) offset() []byte { return s[00:][:12] }
-func (s sparseElem) length() []byte { return s[12:][:12] }
diff --git a/vendor/archive/tar/reader.go b/vendor/archive/tar/reader.go
deleted file mode 100644
index 45848304ed9d0..0000000000000
--- a/vendor/archive/tar/reader.go
+++ /dev/null
@@ -1,869 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tar
-
-import (
-	"bytes"
-	"io"
-	"strconv"
-	"strings"
-	"time"
-)
-
-// Reader provides sequential access to the contents of a tar archive.
-// Reader.Next advances to the next file in the archive (including the first),
-// and then Reader can be treated as an io.Reader to access the file's data.
-type Reader struct {
-	r    io.Reader
-	pad  int64      // Amount of padding (ignored) after current file entry
-	curr fileReader // Reader for current file entry
-	blk  block      // Buffer to use as temporary local storage
-
-	// err is a persistent error.
-	// It is only the responsibility of every exported method of Reader to
-	// ensure that this error is sticky.
-	err error
-}
-
-type fileReader interface {
-	io.Reader
-	fileState
-
-	WriteTo(io.Writer) (int64, error)
-}
-
-// NewReader creates a new Reader reading from r.
-func NewReader(r io.Reader) *Reader {
-	return &Reader{r: r, curr: &regFileReader{r, 0}}
-}
-
-// Next advances to the next entry in the tar archive.
-// The Header.Size determines how many bytes can be read for the next file.
-// Any remaining data in the current file is automatically discarded.
-//
-// io.EOF is returned at the end of the input.
-func (tr *Reader) Next() (*Header, error) {
-	if tr.err != nil {
-		return nil, tr.err
-	}
-	hdr, err := tr.next()
-	tr.err = err
-	return hdr, err
-}
-
-func (tr *Reader) next() (*Header, error) {
-	var paxHdrs map[string]string
-	var gnuLongName, gnuLongLink string
-
-	// Externally, Next iterates through the tar archive as if it is a series of
-	// files. Internally, the tar format often uses fake "files" to add meta
-	// data that describes the next file. These meta data "files" should not
-	// normally be visible to the outside. As such, this loop iterates through
-	// one or more "header files" until it finds a "normal file".
-	format := FormatUSTAR | FormatPAX | FormatGNU
-	for {
-		// Discard the remainder of the file and any padding.
-		if err := discard(tr.r, tr.curr.physicalRemaining()); err != nil {
-			return nil, err
-		}
-		if _, err := tryReadFull(tr.r, tr.blk[:tr.pad]); err != nil {
-			return nil, err
-		}
-		tr.pad = 0
-
-		hdr, rawHdr, err := tr.readHeader()
-		if err != nil {
-			return nil, err
-		}
-		if err := tr.handleRegularFile(hdr); err != nil {
-			return nil, err
-		}
-		format.mayOnlyBe(hdr.Format)
-
-		// Check for PAX/GNU special headers and files.
-		switch hdr.Typeflag {
-		case TypeXHeader, TypeXGlobalHeader:
-			format.mayOnlyBe(FormatPAX)
-			paxHdrs, err = parsePAX(tr)
-			if err != nil {
-				return nil, err
-			}
-			if hdr.Typeflag == TypeXGlobalHeader {
-				mergePAX(hdr, paxHdrs)
-				return &Header{
-					Name:       hdr.Name,
-					Typeflag:   hdr.Typeflag,
-					Xattrs:     hdr.Xattrs,
-					PAXRecords: hdr.PAXRecords,
-					Format:     format,
-				}, nil
-			}
-			continue // This is a meta header affecting the next header
-		case TypeGNULongName, TypeGNULongLink:
-			format.mayOnlyBe(FormatGNU)
-			realname, err := readSpecialFile(tr)
-			if err != nil {
-				return nil, err
-			}
-
-			var p parser
-			switch hdr.Typeflag {
-			case TypeGNULongName:
-				gnuLongName = p.parseString(realname)
-			case TypeGNULongLink:
-				gnuLongLink = p.parseString(realname)
-			}
-			continue // This is a meta header affecting the next header
-		default:
-			// The old GNU sparse format is handled here since it is technically
-			// just a regular file with additional attributes.
-
-			if err := mergePAX(hdr, paxHdrs); err != nil {
-				return nil, err
-			}
-			if gnuLongName != "" {
-				hdr.Name = gnuLongName
-			}
-			if gnuLongLink != "" {
-				hdr.Linkname = gnuLongLink
-			}
-			if hdr.Typeflag == TypeRegA {
-				if strings.HasSuffix(hdr.Name, "/") {
-					hdr.Typeflag = TypeDir // Legacy archives use trailing slash for directories
-				} else {
-					hdr.Typeflag = TypeReg
-				}
-			}
-
-			// The extended headers may have updated the size.
-			// Thus, setup the regFileReader again after merging PAX headers.
-			if err := tr.handleRegularFile(hdr); err != nil {
-				return nil, err
-			}
-
-			// Sparse formats rely on being able to read from the logical data
-			// section; there must be a preceding call to handleRegularFile.
-			if err := tr.handleSparseFile(hdr, rawHdr); err != nil {
-				return nil, err
-			}
-
-			// Set the final guess at the format.
-			if format.has(FormatUSTAR) && format.has(FormatPAX) {
-				format.mayOnlyBe(FormatUSTAR)
-			}
-			hdr.Format = format
-			return hdr, nil // This is a file, so stop
-		}
-	}
-}
-
-// handleRegularFile sets up the current file reader and padding such that it
-// can only read the following logical data section. It will properly handle
-// special headers that contain no data section.
-func (tr *Reader) handleRegularFile(hdr *Header) error {
-	nb := hdr.Size
-	if isHeaderOnlyType(hdr.Typeflag) {
-		nb = 0
-	}
-	if nb < 0 {
-		return ErrHeader
-	}
-
-	tr.pad = blockPadding(nb)
-	tr.curr = &regFileReader{r: tr.r, nb: nb}
-	return nil
-}
-
-// handleSparseFile checks if the current file is a sparse format of any type
-// and sets the curr reader appropriately.
-func (tr *Reader) handleSparseFile(hdr *Header, rawHdr *block) error {
-	var spd sparseDatas
-	var err error
-	if hdr.Typeflag == TypeGNUSparse {
-		spd, err = tr.readOldGNUSparseMap(hdr, rawHdr)
-	} else {
-		spd, err = tr.readGNUSparsePAXHeaders(hdr)
-	}
-
-	// If sp is non-nil, then this is a sparse file.
-	// Note that it is possible for len(sp) == 0.
-	if err == nil && spd != nil {
-		if isHeaderOnlyType(hdr.Typeflag) || !validateSparseEntries(spd, hdr.Size) {
-			return ErrHeader
-		}
-		sph := invertSparseEntries(spd, hdr.Size)
-		tr.curr = &sparseFileReader{tr.curr, sph, 0}
-	}
-	return err
-}
-
-// readGNUSparsePAXHeaders checks the PAX headers for GNU sparse headers.
-// If they are found, then this function reads the sparse map and returns it.
-// This assumes that 0.0 headers have already been converted to 0.1 headers
-// by the PAX header parsing logic.
-func (tr *Reader) readGNUSparsePAXHeaders(hdr *Header) (sparseDatas, error) {
-	// Identify the version of GNU headers.
-	var is1x0 bool
-	major, minor := hdr.PAXRecords[paxGNUSparseMajor], hdr.PAXRecords[paxGNUSparseMinor]
-	switch {
-	case major == "0" && (minor == "0" || minor == "1"):
-		is1x0 = false
-	case major == "1" && minor == "0":
-		is1x0 = true
-	case major != "" || minor != "":
-		return nil, nil // Unknown GNU sparse PAX version
-	case hdr.PAXRecords[paxGNUSparseMap] != "":
-		is1x0 = false // 0.0 and 0.1 did not have explicit version records, so guess
-	default:
-		return nil, nil // Not a PAX format GNU sparse file.
-	}
-	hdr.Format.mayOnlyBe(FormatPAX)
-
-	// Update hdr from GNU sparse PAX headers.
-	if name := hdr.PAXRecords[paxGNUSparseName]; name != "" {
-		hdr.Name = name
-	}
-	size := hdr.PAXRecords[paxGNUSparseSize]
-	if size == "" {
-		size = hdr.PAXRecords[paxGNUSparseRealSize]
-	}
-	if size != "" {
-		n, err := strconv.ParseInt(size, 10, 64)
-		if err != nil {
-			return nil, ErrHeader
-		}
-		hdr.Size = n
-	}
-
-	// Read the sparse map according to the appropriate format.
-	if is1x0 {
-		return readGNUSparseMap1x0(tr.curr)
-	}
-	return readGNUSparseMap0x1(hdr.PAXRecords)
-}
-
-// mergePAX merges paxHdrs into hdr for all relevant fields of Header.
-func mergePAX(hdr *Header, paxHdrs map[string]string) (err error) {
-	for k, v := range paxHdrs {
-		if v == "" {
-			continue // Keep the original USTAR value
-		}
-		var id64 int64
-		switch k {
-		case paxPath:
-			hdr.Name = v
-		case paxLinkpath:
-			hdr.Linkname = v
-		case paxUname:
-			hdr.Uname = v
-		case paxGname:
-			hdr.Gname = v
-		case paxUid:
-			id64, err = strconv.ParseInt(v, 10, 64)
-			hdr.Uid = int(id64) // Integer overflow possible
-		case paxGid:
-			id64, err = strconv.ParseInt(v, 10, 64)
-			hdr.Gid = int(id64) // Integer overflow possible
-		case paxAtime:
-			hdr.AccessTime, err = parsePAXTime(v)
-		case paxMtime:
-			hdr.ModTime, err = parsePAXTime(v)
-		case paxCtime:
-			hdr.ChangeTime, err = parsePAXTime(v)
-		case paxSize:
-			hdr.Size, err = strconv.ParseInt(v, 10, 64)
-		default:
-			if strings.HasPrefix(k, paxSchilyXattr) {
-				if hdr.Xattrs == nil {
-					hdr.Xattrs = make(map[string]string)
-				}
-				hdr.Xattrs[k[len(paxSchilyXattr):]] = v
-			}
-		}
-		if err != nil {
-			return ErrHeader
-		}
-	}
-	hdr.PAXRecords = paxHdrs
-	return nil
-}
-
-// parsePAX parses PAX headers.
-// If an extended header (type 'x') is invalid, ErrHeader is returned
-func parsePAX(r io.Reader) (map[string]string, error) {
-	buf, err := readSpecialFile(r)
-	if err != nil {
-		return nil, err
-	}
-	sbuf := string(buf)
-
-	// For GNU PAX sparse format 0.0 support.
-	// This function transforms the sparse format 0.0 headers into format 0.1
-	// headers since 0.0 headers were not PAX compliant.
-	var sparseMap []string
-
-	paxHdrs := make(map[string]string)
-	for len(sbuf) > 0 {
-		key, value, residual, err := parsePAXRecord(sbuf)
-		if err != nil {
-			return nil, ErrHeader
-		}
-		sbuf = residual
-
-		switch key {
-		case paxGNUSparseOffset, paxGNUSparseNumBytes:
-			// Validate sparse header order and value.
-			if (len(sparseMap)%2 == 0 && key != paxGNUSparseOffset) ||
-				(len(sparseMap)%2 == 1 && key != paxGNUSparseNumBytes) ||
-				strings.Contains(value, ",") {
-				return nil, ErrHeader
-			}
-			sparseMap = append(sparseMap, value)
-		default:
-			paxHdrs[key] = value
-		}
-	}
-	if len(sparseMap) > 0 {
-		paxHdrs[paxGNUSparseMap] = strings.Join(sparseMap, ",")
-	}
-	return paxHdrs, nil
-}
-
-// readHeader reads the next block header and assumes that the underlying reader
-// is already aligned to a block boundary. It returns the raw block of the
-// header in case further processing is required.
-//
-// The err will be set to io.EOF only when one of the following occurs:
-//   - Exactly 0 bytes are read and EOF is hit.
-//   - Exactly 1 block of zeros is read and EOF is hit.
-//   - At least 2 blocks of zeros are read.
-func (tr *Reader) readHeader() (*Header, *block, error) {
-	// Two blocks of zero bytes marks the end of the archive.
-	if _, err := io.ReadFull(tr.r, tr.blk[:]); err != nil {
-		return nil, nil, err // EOF is okay here; exactly 0 bytes read
-	}
-	if bytes.Equal(tr.blk[:], zeroBlock[:]) {
-		if _, err := io.ReadFull(tr.r, tr.blk[:]); err != nil {
-			return nil, nil, err // EOF is okay here; exactly 1 block of zeros read
-		}
-		if bytes.Equal(tr.blk[:], zeroBlock[:]) {
-			return nil, nil, io.EOF // normal EOF; exactly 2 block of zeros read
-		}
-		return nil, nil, ErrHeader // Zero block and then non-zero block
-	}
-
-	// Verify the header matches a known format.
-	format := tr.blk.getFormat()
-	if format == FormatUnknown {
-		return nil, nil, ErrHeader
-	}
-
-	var p parser
-	hdr := new(Header)
-
-	// Unpack the V7 header.
-	v7 := tr.blk.toV7()
-	hdr.Typeflag = v7.typeFlag()[0]
-	hdr.Name = p.parseString(v7.name())
-	hdr.Linkname = p.parseString(v7.linkName())
-	hdr.Size = p.parseNumeric(v7.size())
-	hdr.Mode = p.parseNumeric(v7.mode())
-	hdr.Uid = int(p.parseNumeric(v7.uid()))
-	hdr.Gid = int(p.parseNumeric(v7.gid()))
-	hdr.ModTime = time.Unix(p.parseNumeric(v7.modTime()), 0)
-
-	// Unpack format specific fields.
-	if format > formatV7 {
-		ustar := tr.blk.toUSTAR()
-		hdr.Uname = p.parseString(ustar.userName())
-		hdr.Gname = p.parseString(ustar.groupName())
-		hdr.Devmajor = p.parseNumeric(ustar.devMajor())
-		hdr.Devminor = p.parseNumeric(ustar.devMinor())
-
-		var prefix string
-		switch {
-		case format.has(FormatUSTAR | FormatPAX):
-			hdr.Format = format
-			ustar := tr.blk.toUSTAR()
-			prefix = p.parseString(ustar.prefix())
-
-			// For Format detection, check if block is properly formatted since
-			// the parser is more liberal than what USTAR actually permits.
-			notASCII := func(r rune) bool { return r >= 0x80 }
-			if bytes.IndexFunc(tr.blk[:], notASCII) >= 0 {
-				hdr.Format = FormatUnknown // Non-ASCII characters in block.
-			}
-			nul := func(b []byte) bool { return int(b[len(b)-1]) == 0 }
-			if !(nul(v7.size()) && nul(v7.mode()) && nul(v7.uid()) && nul(v7.gid()) &&
-				nul(v7.modTime()) && nul(ustar.devMajor()) && nul(ustar.devMinor())) {
-				hdr.Format = FormatUnknown // Numeric fields must end in NUL
-			}
-		case format.has(formatSTAR):
-			star := tr.blk.toSTAR()
-			prefix = p.parseString(star.prefix())
-			hdr.AccessTime = time.Unix(p.parseNumeric(star.accessTime()), 0)
-			hdr.ChangeTime = time.Unix(p.parseNumeric(star.changeTime()), 0)
-		case format.has(FormatGNU):
-			hdr.Format = format
-			var p2 parser
-			gnu := tr.blk.toGNU()
-			if b := gnu.accessTime(); b[0] != 0 {
-				hdr.AccessTime = time.Unix(p2.parseNumeric(b), 0)
-			}
-			if b := gnu.changeTime(); b[0] != 0 {
-				hdr.ChangeTime = time.Unix(p2.parseNumeric(b), 0)
-			}
-
-			// Prior to Go1.8, the Writer had a bug where it would output
-			// an invalid tar file in certain rare situations because the logic
-			// incorrectly believed that the old GNU format had a prefix field.
-			// This is wrong and leads to an output file that mangles the
-			// atime and ctime fields, which are often left unused.
-			//
-			// In order to continue reading tar files created by former, buggy
-			// versions of Go, we skeptically parse the atime and ctime fields.
-			// If we are unable to parse them and the prefix field looks like
-			// an ASCII string, then we fallback on the pre-Go1.8 behavior
-			// of treating these fields as the USTAR prefix field.
-			//
-			// Note that this will not use the fallback logic for all possible
-			// files generated by a pre-Go1.8 toolchain. If the generated file
-			// happened to have a prefix field that parses as valid
-			// atime and ctime fields (e.g., when they are valid octal strings),
-			// then it is impossible to distinguish between a valid GNU file
-			// and an invalid pre-Go1.8 file.
-			//
-			// See https://golang.org/issues/12594
-			// See https://golang.org/issues/21005
-			if p2.err != nil {
-				hdr.AccessTime, hdr.ChangeTime = time.Time{}, time.Time{}
-				ustar := tr.blk.toUSTAR()
-				if s := p.parseString(ustar.prefix()); isASCII(s) {
-					prefix = s
-				}
-				hdr.Format = FormatUnknown // Buggy file is not GNU
-			}
-		}
-		if len(prefix) > 0 {
-			hdr.Name = prefix + "/" + hdr.Name
-		}
-	}
-	return hdr, &tr.blk, p.err
-}
-
-// readOldGNUSparseMap reads the sparse map from the old GNU sparse format.
-// The sparse map is stored in the tar header if it's small enough.
-// If it's larger than four entries, then one or more extension headers are used
-// to store the rest of the sparse map.
-//
-// The Header.Size does not reflect the size of any extended headers used.
-// Thus, this function will read from the raw io.Reader to fetch extra headers.
-// This method mutates blk in the process.
-func (tr *Reader) readOldGNUSparseMap(hdr *Header, blk *block) (sparseDatas, error) {
-	// Make sure that the input format is GNU.
-	// Unfortunately, the STAR format also has a sparse header format that uses
-	// the same type flag but has a completely different layout.
-	if blk.getFormat() != FormatGNU {
-		return nil, ErrHeader
-	}
-	hdr.Format.mayOnlyBe(FormatGNU)
-
-	var p parser
-	hdr.Size = p.parseNumeric(blk.toGNU().realSize())
-	if p.err != nil {
-		return nil, p.err
-	}
-	s := blk.toGNU().sparse()
-	spd := make(sparseDatas, 0, s.maxEntries())
-	for {
-		for i := 0; i < s.maxEntries(); i++ {
-			// This termination condition is identical to GNU and BSD tar.
-			if s.entry(i).offset()[0] == 0x00 {
-				break // Don't return, need to process extended headers (even if empty)
-			}
-			offset := p.parseNumeric(s.entry(i).offset())
-			length := p.parseNumeric(s.entry(i).length())
-			if p.err != nil {
-				return nil, p.err
-			}
-			spd = append(spd, sparseEntry{Offset: offset, Length: length})
-		}
-
-		if s.isExtended()[0] > 0 {
-			// There are more entries. Read an extension header and parse its entries.
-			if _, err := mustReadFull(tr.r, blk[:]); err != nil {
-				return nil, err
-			}
-			s = blk.toSparse()
-			continue
-		}
-		return spd, nil // Done
-	}
-}
-
-// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format
-// version 1.0. The format of the sparse map consists of a series of
-// newline-terminated numeric fields. The first field is the number of entries
-// and is always present. Following this are the entries, consisting of two
-// fields (offset, length). This function must stop reading at the end
-// boundary of the block containing the last newline.
-//
-// Note that the GNU manual says that numeric values should be encoded in octal
-// format. However, the GNU tar utility itself outputs these values in decimal.
-// As such, this library treats values as being encoded in decimal.
-func readGNUSparseMap1x0(r io.Reader) (sparseDatas, error) {
-	var (
-		cntNewline int64
-		buf        bytes.Buffer
-		blk        block
-	)
-
-	// feedTokens copies data in blocks from r into buf until there are
-	// at least cnt newlines in buf. It will not read more blocks than needed.
-	feedTokens := func(n int64) error {
-		for cntNewline < n {
-			if _, err := mustReadFull(r, blk[:]); err != nil {
-				return err
-			}
-			buf.Write(blk[:])
-			for _, c := range blk {
-				if c == '\n' {
-					cntNewline++
-				}
-			}
-		}
-		return nil
-	}
-
-	// nextToken gets the next token delimited by a newline. This assumes that
-	// at least one newline exists in the buffer.
-	nextToken := func() string {
-		cntNewline--
-		tok, _ := buf.ReadString('\n')
-		return strings.TrimRight(tok, "\n")
-	}
-
-	// Parse for the number of entries.
-	// Use integer overflow resistant math to check this.
-	if err := feedTokens(1); err != nil {
-		return nil, err
-	}
-	numEntries, err := strconv.ParseInt(nextToken(), 10, 0) // Intentionally parse as native int
-	if err != nil || numEntries < 0 || int(2*numEntries) < int(numEntries) {
-		return nil, ErrHeader
-	}
-
-	// Parse for all member entries.
-	// numEntries is trusted after this since a potential attacker must have
-	// committed resources proportional to what this library used.
-	if err := feedTokens(2 * numEntries); err != nil {
-		return nil, err
-	}
-	spd := make(sparseDatas, 0, numEntries)
-	for i := int64(0); i < numEntries; i++ {
-		offset, err1 := strconv.ParseInt(nextToken(), 10, 64)
-		length, err2 := strconv.ParseInt(nextToken(), 10, 64)
-		if err1 != nil || err2 != nil {
-			return nil, ErrHeader
-		}
-		spd = append(spd, sparseEntry{Offset: offset, Length: length})
-	}
-	return spd, nil
-}
-
-// readGNUSparseMap0x1 reads the sparse map as stored in GNU's PAX sparse format
-// version 0.1. The sparse map is stored in the PAX headers.
-func readGNUSparseMap0x1(paxHdrs map[string]string) (sparseDatas, error) {
-	// Get number of entries.
-	// Use integer overflow resistant math to check this.
-	numEntriesStr := paxHdrs[paxGNUSparseNumBlocks]
-	numEntries, err := strconv.ParseInt(numEntriesStr, 10, 0) // Intentionally parse as native int
-	if err != nil || numEntries < 0 || int(2*numEntries) < int(numEntries) {
-		return nil, ErrHeader
-	}
-
-	// There should be two numbers in sparseMap for each entry.
-	sparseMap := strings.Split(paxHdrs[paxGNUSparseMap], ",")
-	if len(sparseMap) == 1 && sparseMap[0] == "" {
-		sparseMap = sparseMap[:0]
-	}
-	if int64(len(sparseMap)) != 2*numEntries {
-		return nil, ErrHeader
-	}
-
-	// Loop through the entries in the sparse map.
-	// numEntries is trusted now.
-	spd := make(sparseDatas, 0, numEntries)
-	for len(sparseMap) >= 2 {
-		offset, err1 := strconv.ParseInt(sparseMap[0], 10, 64)
-		length, err2 := strconv.ParseInt(sparseMap[1], 10, 64)
-		if err1 != nil || err2 != nil {
-			return nil, ErrHeader
-		}
-		spd = append(spd, sparseEntry{Offset: offset, Length: length})
-		sparseMap = sparseMap[2:]
-	}
-	return spd, nil
-}
-
-// Read reads from the current file in the tar archive.
-// It returns (0, io.EOF) when it reaches the end of that file,
-// until Next is called to advance to the next file.
-//
-// If the current file is sparse, then the regions marked as a hole
-// are read back as NUL-bytes.
-//
-// Calling Read on special types like TypeLink, TypeSymlink, TypeChar,
-// TypeBlock, TypeDir, and TypeFifo returns (0, io.EOF) regardless of what
-// the Header.Size claims.
-func (tr *Reader) Read(b []byte) (int, error) {
-	if tr.err != nil {
-		return 0, tr.err
-	}
-	n, err := tr.curr.Read(b)
-	if err != nil && err != io.EOF {
-		tr.err = err
-	}
-	return n, err
-}
-
-// writeTo writes the content of the current file to w.
-// The bytes written matches the number of remaining bytes in the current file.
-//
-// If the current file is sparse and w is an io.WriteSeeker,
-// then writeTo uses Seek to skip past holes defined in Header.SparseHoles,
-// assuming that skipped regions are filled with NULs.
-// This always writes the last byte to ensure w is the right size.
-//
-// TODO(dsnet): Re-export this when adding sparse file support.
-// See https://golang.org/issue/22735
-func (tr *Reader) writeTo(w io.Writer) (int64, error) {
-	if tr.err != nil {
-		return 0, tr.err
-	}
-	n, err := tr.curr.WriteTo(w)
-	if err != nil {
-		tr.err = err
-	}
-	return n, err
-}
-
-// regFileReader is a fileReader for reading data from a regular file entry.
-type regFileReader struct {
-	r  io.Reader // Underlying Reader
-	nb int64     // Number of remaining bytes to read
-}
-
-func (fr *regFileReader) Read(b []byte) (n int, err error) {
-	if int64(len(b)) > fr.nb {
-		b = b[:fr.nb]
-	}
-	if len(b) > 0 {
-		n, err = fr.r.Read(b)
-		fr.nb -= int64(n)
-	}
-	switch {
-	case err == io.EOF && fr.nb > 0:
-		return n, io.ErrUnexpectedEOF
-	case err == nil && fr.nb == 0:
-		return n, io.EOF
-	default:
-		return n, err
-	}
-}
-
-func (fr *regFileReader) WriteTo(w io.Writer) (int64, error) {
-	return io.Copy(w, struct{ io.Reader }{fr})
-}
-
-// logicalRemaining implements fileState.logicalRemaining.
-func (fr regFileReader) logicalRemaining() int64 {
-	return fr.nb
-}
-
-// logicalRemaining implements fileState.physicalRemaining.
-func (fr regFileReader) physicalRemaining() int64 {
-	return fr.nb
-}
-
-// sparseFileReader is a fileReader for reading data from a sparse file entry.
-type sparseFileReader struct {
-	fr  fileReader  // Underlying fileReader
-	sp  sparseHoles // Normalized list of sparse holes
-	pos int64       // Current position in sparse file
-}
-
-func (sr *sparseFileReader) Read(b []byte) (n int, err error) {
-	finished := int64(len(b)) >= sr.logicalRemaining()
-	if finished {
-		b = b[:sr.logicalRemaining()]
-	}
-
-	b0 := b
-	endPos := sr.pos + int64(len(b))
-	for endPos > sr.pos && err == nil {
-		var nf int // Bytes read in fragment
-		holeStart, holeEnd := sr.sp[0].Offset, sr.sp[0].endOffset()
-		if sr.pos < holeStart { // In a data fragment
-			bf := b[:min(int64(len(b)), holeStart-sr.pos)]
-			nf, err = tryReadFull(sr.fr, bf)
-		} else { // In a hole fragment
-			bf := b[:min(int64(len(b)), holeEnd-sr.pos)]
-			nf, err = tryReadFull(zeroReader{}, bf)
-		}
-		b = b[nf:]
-		sr.pos += int64(nf)
-		if sr.pos >= holeEnd && len(sr.sp) > 1 {
-			sr.sp = sr.sp[1:] // Ensure last fragment always remains
-		}
-	}
-
-	n = len(b0) - len(b)
-	switch {
-	case err == io.EOF:
-		return n, errMissData // Less data in dense file than sparse file
-	case err != nil:
-		return n, err
-	case sr.logicalRemaining() == 0 && sr.physicalRemaining() > 0:
-		return n, errUnrefData // More data in dense file than sparse file
-	case finished:
-		return n, io.EOF
-	default:
-		return n, nil
-	}
-}
-
-func (sr *sparseFileReader) WriteTo(w io.Writer) (n int64, err error) {
-	ws, ok := w.(io.WriteSeeker)
-	if ok {
-		if _, err := ws.Seek(0, io.SeekCurrent); err != nil {
-			ok = false // Not all io.Seeker can really seek
-		}
-	}
-	if !ok {
-		return io.Copy(w, struct{ io.Reader }{sr})
-	}
-
-	var writeLastByte bool
-	pos0 := sr.pos
-	for sr.logicalRemaining() > 0 && !writeLastByte && err == nil {
-		var nf int64 // Size of fragment
-		holeStart, holeEnd := sr.sp[0].Offset, sr.sp[0].endOffset()
-		if sr.pos < holeStart { // In a data fragment
-			nf = holeStart - sr.pos
-			nf, err = io.CopyN(ws, sr.fr, nf)
-		} else { // In a hole fragment
-			nf = holeEnd - sr.pos
-			if sr.physicalRemaining() == 0 {
-				writeLastByte = true
-				nf--
-			}
-			_, err = ws.Seek(nf, io.SeekCurrent)
-		}
-		sr.pos += nf
-		if sr.pos >= holeEnd && len(sr.sp) > 1 {
-			sr.sp = sr.sp[1:] // Ensure last fragment always remains
-		}
-	}
-
-	// If the last fragment is a hole, then seek to 1-byte before EOF, and
-	// write a single byte to ensure the file is the right size.
-	if writeLastByte && err == nil {
-		_, err = ws.Write([]byte{0})
-		sr.pos++
-	}
-
-	n = sr.pos - pos0
-	switch {
-	case err == io.EOF:
-		return n, errMissData // Less data in dense file than sparse file
-	case err != nil:
-		return n, err
-	case sr.logicalRemaining() == 0 && sr.physicalRemaining() > 0:
-		return n, errUnrefData // More data in dense file than sparse file
-	default:
-		return n, nil
-	}
-}
-
-func (sr sparseFileReader) logicalRemaining() int64 {
-	return sr.sp[len(sr.sp)-1].endOffset() - sr.pos
-}
-func (sr sparseFileReader) physicalRemaining() int64 {
-	return sr.fr.physicalRemaining()
-}
-
-type zeroReader struct{}
-
-func (zeroReader) Read(b []byte) (int, error) {
-	for i := range b {
-		b[i] = 0
-	}
-	return len(b), nil
-}
-
-// mustReadFull is like io.ReadFull except it returns
-// io.ErrUnexpectedEOF when io.EOF is hit before len(b) bytes are read.
-func mustReadFull(r io.Reader, b []byte) (int, error) {
-	n, err := tryReadFull(r, b)
-	if err == io.EOF {
-		err = io.ErrUnexpectedEOF
-	}
-	return n, err
-}
-
-// tryReadFull is like io.ReadFull except it returns
-// io.EOF when it is hit before len(b) bytes are read.
-func tryReadFull(r io.Reader, b []byte) (n int, err error) {
-	for len(b) > n && err == nil {
-		var nn int
-		nn, err = r.Read(b[n:])
-		n += nn
-	}
-	if len(b) == n && err == io.EOF {
-		err = nil
-	}
-	return n, err
-}
-
-// readSpecialFile is like io.ReadAll except it returns
-// ErrFieldTooLong if more than maxSpecialFileSize is read.
-func readSpecialFile(r io.Reader) ([]byte, error) {
-	buf, err := io.ReadAll(io.LimitReader(r, maxSpecialFileSize+1))
-	if len(buf) > maxSpecialFileSize {
-		return nil, ErrFieldTooLong
-	}
-	return buf, err
-}
-
-// discard skips n bytes in r, reporting an error if unable to do so.
-func discard(r io.Reader, n int64) error {
-	// If possible, Seek to the last byte before the end of the data section.
-	// Do this because Seek is often lazy about reporting errors; this will mask
-	// the fact that the stream may be truncated. We can rely on the
-	// io.CopyN done shortly afterwards to trigger any IO errors.
-	var seekSkipped int64 // Number of bytes skipped via Seek
-	if sr, ok := r.(io.Seeker); ok && n > 1 {
-		// Not all io.Seeker can actually Seek. For example, os.Stdin implements
-		// io.Seeker, but calling Seek always returns an error and performs
-		// no action. Thus, we try an innocent seek to the current position
-		// to see if Seek is really supported.
-		pos1, err := sr.Seek(0, io.SeekCurrent)
-		if pos1 >= 0 && err == nil {
-			// Seek seems supported, so perform the real Seek.
-			pos2, err := sr.Seek(n-1, io.SeekCurrent)
-			if pos2 < 0 || err != nil {
-				return err
-			}
-			seekSkipped = pos2 - pos1
-		}
-	}
-
-	copySkipped, err := io.CopyN(io.Discard, r, n-seekSkipped)
-	if err == io.EOF && seekSkipped+copySkipped < n {
-		err = io.ErrUnexpectedEOF
-	}
-	return err
-}
diff --git a/vendor/archive/tar/stat_actime1.go b/vendor/archive/tar/stat_actime1.go
deleted file mode 100644
index c4c2480feeb0c..0000000000000
--- a/vendor/archive/tar/stat_actime1.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build aix || linux || dragonfly || openbsd || solaris
-
-package tar
-
-import (
-	"syscall"
-	"time"
-)
-
-func statAtime(st *syscall.Stat_t) time.Time {
-	return time.Unix(st.Atim.Unix())
-}
-
-func statCtime(st *syscall.Stat_t) time.Time {
-	return time.Unix(st.Ctim.Unix())
-}
diff --git a/vendor/archive/tar/stat_actime2.go b/vendor/archive/tar/stat_actime2.go
deleted file mode 100644
index f76d6be220f87..0000000000000
--- a/vendor/archive/tar/stat_actime2.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build darwin || freebsd || netbsd
-
-package tar
-
-import (
-	"syscall"
-	"time"
-)
-
-func statAtime(st *syscall.Stat_t) time.Time {
-	return time.Unix(st.Atimespec.Unix())
-}
-
-func statCtime(st *syscall.Stat_t) time.Time {
-	return time.Unix(st.Ctimespec.Unix())
-}
diff --git a/vendor/archive/tar/stat_unix.go b/vendor/archive/tar/stat_unix.go
deleted file mode 100644
index 5f2a4dd6fb37c..0000000000000
--- a/vendor/archive/tar/stat_unix.go
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build unix
-
-package tar
-
-import (
-	"io/fs"
-	"runtime"
-	"syscall"
-)
-
-func init() {
-	sysStat = statUnix
-}
-
-func statUnix(fi fs.FileInfo, h *Header) error {
-	sys, ok := fi.Sys().(*syscall.Stat_t)
-	if !ok {
-		return nil
-	}
-	h.Uid = int(sys.Uid)
-	h.Gid = int(sys.Gid)
-
-	// TODO(bradfitz): populate username & group.  os/user
-	// doesn't cache LookupId lookups, and lacks group
-	// lookup functions.
-	h.AccessTime = statAtime(sys)
-	h.ChangeTime = statCtime(sys)
-
-	// Best effort at populating Devmajor and Devminor.
-	if h.Typeflag == TypeChar || h.Typeflag == TypeBlock {
-		dev := uint64(sys.Rdev) // May be int32 or uint32
-		switch runtime.GOOS {
-		case "aix":
-			var major, minor uint32
-			major = uint32((dev & 0x3fffffff00000000) >> 32)
-			minor = uint32((dev & 0x00000000ffffffff) >> 0)
-			h.Devmajor, h.Devminor = int64(major), int64(minor)
-		case "linux":
-			// Copied from golang.org/x/sys/unix/dev_linux.go.
-			major := uint32((dev & 0x00000000000fff00) >> 8)
-			major |= uint32((dev & 0xfffff00000000000) >> 32)
-			minor := uint32((dev & 0x00000000000000ff) >> 0)
-			minor |= uint32((dev & 0x00000ffffff00000) >> 12)
-			h.Devmajor, h.Devminor = int64(major), int64(minor)
-		case "darwin", "ios":
-			// Copied from golang.org/x/sys/unix/dev_darwin.go.
-			major := uint32((dev >> 24) & 0xff)
-			minor := uint32(dev & 0xffffff)
-			h.Devmajor, h.Devminor = int64(major), int64(minor)
-		case "dragonfly":
-			// Copied from golang.org/x/sys/unix/dev_dragonfly.go.
-			major := uint32((dev >> 8) & 0xff)
-			minor := uint32(dev & 0xffff00ff)
-			h.Devmajor, h.Devminor = int64(major), int64(minor)
-		case "freebsd":
-			// Copied from golang.org/x/sys/unix/dev_freebsd.go.
-			major := uint32((dev >> 8) & 0xff)
-			minor := uint32(dev & 0xffff00ff)
-			h.Devmajor, h.Devminor = int64(major), int64(minor)
-		case "netbsd":
-			// Copied from golang.org/x/sys/unix/dev_netbsd.go.
-			major := uint32((dev & 0x000fff00) >> 8)
-			minor := uint32((dev & 0x000000ff) >> 0)
-			minor |= uint32((dev & 0xfff00000) >> 12)
-			h.Devmajor, h.Devminor = int64(major), int64(minor)
-		case "openbsd":
-			// Copied from golang.org/x/sys/unix/dev_openbsd.go.
-			major := uint32((dev & 0x0000ff00) >> 8)
-			minor := uint32((dev & 0x000000ff) >> 0)
-			minor |= uint32((dev & 0xffff0000) >> 8)
-			h.Devmajor, h.Devminor = int64(major), int64(minor)
-		default:
-			// TODO: Implement solaris (see https://golang.org/issue/8106)
-		}
-	}
-	return nil
-}
diff --git a/vendor/archive/tar/strconv.go b/vendor/archive/tar/strconv.go
deleted file mode 100644
index ac3196370e611..0000000000000
--- a/vendor/archive/tar/strconv.go
+++ /dev/null
@@ -1,327 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tar
-
-import (
-	"bytes"
-	"fmt"
-	"strconv"
-	"strings"
-	"time"
-)
-
-// hasNUL reports whether the NUL character exists within s.
-func hasNUL(s string) bool {
-	return strings.Contains(s, "\x00")
-}
-
-// isASCII reports whether the input is an ASCII C-style string.
-func isASCII(s string) bool {
-	for _, c := range s {
-		if c >= 0x80 || c == 0x00 {
-			return false
-		}
-	}
-	return true
-}
-
-// toASCII converts the input to an ASCII C-style string.
-// This is a best effort conversion, so invalid characters are dropped.
-func toASCII(s string) string {
-	if isASCII(s) {
-		return s
-	}
-	b := make([]byte, 0, len(s))
-	for _, c := range s {
-		if c < 0x80 && c != 0x00 {
-			b = append(b, byte(c))
-		}
-	}
-	return string(b)
-}
-
-type parser struct {
-	err error // Last error seen
-}
-
-type formatter struct {
-	err error // Last error seen
-}
-
-// parseString parses bytes as a NUL-terminated C-style string.
-// If a NUL byte is not found then the whole slice is returned as a string.
-func (*parser) parseString(b []byte) string {
-	if i := bytes.IndexByte(b, 0); i >= 0 {
-		return string(b[:i])
-	}
-	return string(b)
-}
-
-// formatString copies s into b, NUL-terminating if possible.
-func (f *formatter) formatString(b []byte, s string) {
-	if len(s) > len(b) {
-		f.err = ErrFieldTooLong
-	}
-	copy(b, s)
-	if len(s) < len(b) {
-		b[len(s)] = 0
-	}
-
-	// Some buggy readers treat regular files with a trailing slash
-	// in the V7 path field as a directory even though the full path
-	// recorded elsewhere (e.g., via PAX record) contains no trailing slash.
-	if len(s) > len(b) && b[len(b)-1] == '/' {
-		n := len(strings.TrimRight(s[:len(b)], "/"))
-		b[n] = 0 // Replace trailing slash with NUL terminator
-	}
-}
-
-// fitsInBase256 reports whether x can be encoded into n bytes using base-256
-// encoding. Unlike octal encoding, base-256 encoding does not require that the
-// string ends with a NUL character. Thus, all n bytes are available for output.
-//
-// If operating in binary mode, this assumes strict GNU binary mode; which means
-// that the first byte can only be either 0x80 or 0xff. Thus, the first byte is
-// equivalent to the sign bit in two's complement form.
-func fitsInBase256(n int, x int64) bool {
-	binBits := uint(n-1) * 8
-	return n >= 9 || (x >= -1<<binBits && x < 1<<binBits)
-}
-
-// parseNumeric parses the input as being encoded in either base-256 or octal.
-// This function may return negative numbers.
-// If parsing fails or an integer overflow occurs, err will be set.
-func (p *parser) parseNumeric(b []byte) int64 {
-	// Check for base-256 (binary) format first.
-	// If the first bit is set, then all following bits constitute a two's
-	// complement encoded number in big-endian byte order.
-	if len(b) > 0 && b[0]&0x80 != 0 {
-		// Handling negative numbers relies on the following identity:
-		//	-a-1 == ^a
-		//
-		// If the number is negative, we use an inversion mask to invert the
-		// data bytes and treat the value as an unsigned number.
-		var inv byte // 0x00 if positive or zero, 0xff if negative
-		if b[0]&0x40 != 0 {
-			inv = 0xff
-		}
-
-		var x uint64
-		for i, c := range b {
-			c ^= inv // Inverts c only if inv is 0xff, otherwise does nothing
-			if i == 0 {
-				c &= 0x7f // Ignore signal bit in first byte
-			}
-			if (x >> 56) > 0 {
-				p.err = ErrHeader // Integer overflow
-				return 0
-			}
-			x = x<<8 | uint64(c)
-		}
-		if (x >> 63) > 0 {
-			p.err = ErrHeader // Integer overflow
-			return 0
-		}
-		if inv == 0xff {
-			return ^int64(x)
-		}
-		return int64(x)
-	}
-
-	// Normal case is base-8 (octal) format.
-	return p.parseOctal(b)
-}
-
-// formatNumeric encodes x into b using base-8 (octal) encoding if possible.
-// Otherwise it will attempt to use base-256 (binary) encoding.
-func (f *formatter) formatNumeric(b []byte, x int64) {
-	if fitsInOctal(len(b), x) {
-		f.formatOctal(b, x)
-		return
-	}
-
-	if fitsInBase256(len(b), x) {
-		for i := len(b) - 1; i >= 0; i-- {
-			b[i] = byte(x)
-			x >>= 8
-		}
-		b[0] |= 0x80 // Highest bit indicates binary format
-		return
-	}
-
-	f.formatOctal(b, 0) // Last resort, just write zero
-	f.err = ErrFieldTooLong
-}
-
-func (p *parser) parseOctal(b []byte) int64 {
-	// Because unused fields are filled with NULs, we need
-	// to skip leading NULs. Fields may also be padded with
-	// spaces or NULs.
-	// So we remove leading and trailing NULs and spaces to
-	// be sure.
-	b = bytes.Trim(b, " \x00")
-
-	if len(b) == 0 {
-		return 0
-	}
-	x, perr := strconv.ParseUint(p.parseString(b), 8, 64)
-	if perr != nil {
-		p.err = ErrHeader
-	}
-	return int64(x)
-}
-
-func (f *formatter) formatOctal(b []byte, x int64) {
-	if !fitsInOctal(len(b), x) {
-		x = 0 // Last resort, just write zero
-		f.err = ErrFieldTooLong
-	}
-
-	s := strconv.FormatInt(x, 8)
-	// Add leading zeros, but leave room for a NUL.
-	if n := len(b) - len(s) - 1; n > 0 {
-		s = strings.Repeat("0", n) + s
-	}
-	f.formatString(b, s)
-}
-
-// fitsInOctal reports whether the integer x fits in a field n-bytes long
-// using octal encoding with the appropriate NUL terminator.
-func fitsInOctal(n int, x int64) bool {
-	octBits := uint(n-1) * 3
-	return x >= 0 && (n >= 22 || x < 1<<octBits)
-}
-
-// parsePAXTime takes a string of the form %d.%d as described in the PAX
-// specification. Note that this implementation allows for negative timestamps,
-// which is allowed for by the PAX specification, but not always portable.
-func parsePAXTime(s string) (time.Time, error) {
-	const maxNanoSecondDigits = 9
-
-	// Split string into seconds and sub-seconds parts.
-	ss, sn, _ := strings.Cut(s, ".")
-
-	// Parse the seconds.
-	secs, err := strconv.ParseInt(ss, 10, 64)
-	if err != nil {
-		return time.Time{}, ErrHeader
-	}
-	if len(sn) == 0 {
-		return time.Unix(secs, 0), nil // No sub-second values
-	}
-
-	// Parse the nanoseconds.
-	if strings.Trim(sn, "0123456789") != "" {
-		return time.Time{}, ErrHeader
-	}
-	if len(sn) < maxNanoSecondDigits {
-		sn += strings.Repeat("0", maxNanoSecondDigits-len(sn)) // Right pad
-	} else {
-		sn = sn[:maxNanoSecondDigits] // Right truncate
-	}
-	nsecs, _ := strconv.ParseInt(sn, 10, 64) // Must succeed
-	if len(ss) > 0 && ss[0] == '-' {
-		return time.Unix(secs, -1*nsecs), nil // Negative correction
-	}
-	return time.Unix(secs, nsecs), nil
-}
-
-// formatPAXTime converts ts into a time of the form %d.%d as described in the
-// PAX specification. This function is capable of negative timestamps.
-func formatPAXTime(ts time.Time) (s string) {
-	secs, nsecs := ts.Unix(), ts.Nanosecond()
-	if nsecs == 0 {
-		return strconv.FormatInt(secs, 10)
-	}
-
-	// If seconds is negative, then perform correction.
-	sign := ""
-	if secs < 0 {
-		sign = "-"             // Remember sign
-		secs = -(secs + 1)     // Add a second to secs
-		nsecs = -(nsecs - 1e9) // Take that second away from nsecs
-	}
-	return strings.TrimRight(fmt.Sprintf("%s%d.%09d", sign, secs, nsecs), "0")
-}
-
-// parsePAXRecord parses the input PAX record string into a key-value pair.
-// If parsing is successful, it will slice off the currently read record and
-// return the remainder as r.
-func parsePAXRecord(s string) (k, v, r string, err error) {
-	// The size field ends at the first space.
-	nStr, rest, ok := strings.Cut(s, " ")
-	if !ok {
-		return "", "", s, ErrHeader
-	}
-
-	// Parse the first token as a decimal integer.
-	n, perr := strconv.ParseInt(nStr, 10, 0) // Intentionally parse as native int
-	if perr != nil || n < 5 || n > int64(len(s)) {
-		return "", "", s, ErrHeader
-	}
-	n -= int64(len(nStr) + 1) // convert from index in s to index in rest
-	if n <= 0 {
-		return "", "", s, ErrHeader
-	}
-
-	// Extract everything between the space and the final newline.
-	rec, nl, rem := rest[:n-1], rest[n-1:n], rest[n:]
-	if nl != "\n" {
-		return "", "", s, ErrHeader
-	}
-
-	// The first equals separates the key from the value.
-	k, v, ok = strings.Cut(rec, "=")
-	if !ok {
-		return "", "", s, ErrHeader
-	}
-
-	if !validPAXRecord(k, v) {
-		return "", "", s, ErrHeader
-	}
-	return k, v, rem, nil
-}
-
-// formatPAXRecord formats a single PAX record, prefixing it with the
-// appropriate length.
-func formatPAXRecord(k, v string) (string, error) {
-	if !validPAXRecord(k, v) {
-		return "", ErrHeader
-	}
-
-	const padding = 3 // Extra padding for ' ', '=', and '\n'
-	size := len(k) + len(v) + padding
-	size += len(strconv.Itoa(size))
-	record := strconv.Itoa(size) + " " + k + "=" + v + "\n"
-
-	// Final adjustment if adding size field increased the record size.
-	if len(record) != size {
-		size = len(record)
-		record = strconv.Itoa(size) + " " + k + "=" + v + "\n"
-	}
-	return record, nil
-}
-
-// validPAXRecord reports whether the key-value pair is valid where each
-// record is formatted as:
-//
-//	"%d %s=%s\n" % (size, key, value)
-//
-// Keys and values should be UTF-8, but the number of bad writers out there
-// forces us to be a more liberal.
-// Thus, we only reject all keys with NUL, and only reject NULs in values
-// for the PAX version of the USTAR string fields.
-// The key must not contain an '=' character.
-func validPAXRecord(k, v string) bool {
-	if k == "" || strings.Contains(k, "=") {
-		return false
-	}
-	switch k {
-	case paxPath, paxLinkpath, paxUname, paxGname:
-		return !hasNUL(v)
-	default:
-		return !hasNUL(k)
-	}
-}
diff --git a/vendor/archive/tar/writer.go b/vendor/archive/tar/writer.go
deleted file mode 100644
index 9b2e3e25d4ceb..0000000000000
--- a/vendor/archive/tar/writer.go
+++ /dev/null
@@ -1,659 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tar
-
-import (
-	"fmt"
-	"io"
-	"path"
-	"sort"
-	"strings"
-	"time"
-)
-
-// Writer provides sequential writing of a tar archive.
-// Write.WriteHeader begins a new file with the provided Header,
-// and then Writer can be treated as an io.Writer to supply that file's data.
-type Writer struct {
-	w    io.Writer
-	pad  int64      // Amount of padding to write after current file entry
-	curr fileWriter // Writer for current file entry
-	hdr  Header     // Shallow copy of Header that is safe for mutations
-	blk  block      // Buffer to use as temporary local storage
-
-	// err is a persistent error.
-	// It is only the responsibility of every exported method of Writer to
-	// ensure that this error is sticky.
-	err error
-}
-
-// NewWriter creates a new Writer writing to w.
-func NewWriter(w io.Writer) *Writer {
-	return &Writer{w: w, curr: &regFileWriter{w, 0}}
-}
-
-type fileWriter interface {
-	io.Writer
-	fileState
-
-	ReadFrom(io.Reader) (int64, error)
-}
-
-// Flush finishes writing the current file's block padding.
-// The current file must be fully written before Flush can be called.
-//
-// This is unnecessary as the next call to WriteHeader or Close
-// will implicitly flush out the file's padding.
-func (tw *Writer) Flush() error {
-	if tw.err != nil {
-		return tw.err
-	}
-	if nb := tw.curr.logicalRemaining(); nb > 0 {
-		return fmt.Errorf("archive/tar: missed writing %d bytes", nb)
-	}
-	if _, tw.err = tw.w.Write(zeroBlock[:tw.pad]); tw.err != nil {
-		return tw.err
-	}
-	tw.pad = 0
-	return nil
-}
-
-// WriteHeader writes hdr and prepares to accept the file's contents.
-// The Header.Size determines how many bytes can be written for the next file.
-// If the current file is not fully written, then this returns an error.
-// This implicitly flushes any padding necessary before writing the header.
-func (tw *Writer) WriteHeader(hdr *Header) error {
-	if err := tw.Flush(); err != nil {
-		return err
-	}
-	tw.hdr = *hdr // Shallow copy of Header
-
-	// Avoid usage of the legacy TypeRegA flag, and automatically promote
-	// it to use TypeReg or TypeDir.
-	if tw.hdr.Typeflag == TypeRegA {
-		if strings.HasSuffix(tw.hdr.Name, "/") {
-			tw.hdr.Typeflag = TypeDir
-		} else {
-			tw.hdr.Typeflag = TypeReg
-		}
-	}
-
-	// Round ModTime and ignore AccessTime and ChangeTime unless
-	// the format is explicitly chosen.
-	// This ensures nominal usage of WriteHeader (without specifying the format)
-	// does not always result in the PAX format being chosen, which
-	// causes a 1KiB increase to every header.
-	if tw.hdr.Format == FormatUnknown {
-		tw.hdr.ModTime = tw.hdr.ModTime.Round(time.Second)
-		tw.hdr.AccessTime = time.Time{}
-		tw.hdr.ChangeTime = time.Time{}
-	}
-
-	allowedFormats, paxHdrs, err := tw.hdr.allowedFormats()
-	switch {
-	case allowedFormats.has(FormatUSTAR):
-		tw.err = tw.writeUSTARHeader(&tw.hdr)
-		return tw.err
-	case allowedFormats.has(FormatPAX):
-		tw.err = tw.writePAXHeader(&tw.hdr, paxHdrs)
-		return tw.err
-	case allowedFormats.has(FormatGNU):
-		tw.err = tw.writeGNUHeader(&tw.hdr)
-		return tw.err
-	default:
-		return err // Non-fatal error
-	}
-}
-
-func (tw *Writer) writeUSTARHeader(hdr *Header) error {
-	// Check if we can use USTAR prefix/suffix splitting.
-	var namePrefix string
-	if prefix, suffix, ok := splitUSTARPath(hdr.Name); ok {
-		namePrefix, hdr.Name = prefix, suffix
-	}
-
-	// Pack the main header.
-	var f formatter
-	blk := tw.templateV7Plus(hdr, f.formatString, f.formatOctal)
-	f.formatString(blk.toUSTAR().prefix(), namePrefix)
-	blk.setFormat(FormatUSTAR)
-	if f.err != nil {
-		return f.err // Should never happen since header is validated
-	}
-	return tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag)
-}
-
-func (tw *Writer) writePAXHeader(hdr *Header, paxHdrs map[string]string) error {
-	realName, realSize := hdr.Name, hdr.Size
-
-	// TODO(dsnet): Re-enable this when adding sparse support.
-	// See https://golang.org/issue/22735
-	/*
-		// Handle sparse files.
-		var spd sparseDatas
-		var spb []byte
-		if len(hdr.SparseHoles) > 0 {
-			sph := append([]sparseEntry{}, hdr.SparseHoles...) // Copy sparse map
-			sph = alignSparseEntries(sph, hdr.Size)
-			spd = invertSparseEntries(sph, hdr.Size)
-
-			// Format the sparse map.
-			hdr.Size = 0 // Replace with encoded size
-			spb = append(strconv.AppendInt(spb, int64(len(spd)), 10), '\n')
-			for _, s := range spd {
-				hdr.Size += s.Length
-				spb = append(strconv.AppendInt(spb, s.Offset, 10), '\n')
-				spb = append(strconv.AppendInt(spb, s.Length, 10), '\n')
-			}
-			pad := blockPadding(int64(len(spb)))
-			spb = append(spb, zeroBlock[:pad]...)
-			hdr.Size += int64(len(spb)) // Accounts for encoded sparse map
-
-			// Add and modify appropriate PAX records.
-			dir, file := path.Split(realName)
-			hdr.Name = path.Join(dir, "GNUSparseFile.0", file)
-			paxHdrs[paxGNUSparseMajor] = "1"
-			paxHdrs[paxGNUSparseMinor] = "0"
-			paxHdrs[paxGNUSparseName] = realName
-			paxHdrs[paxGNUSparseRealSize] = strconv.FormatInt(realSize, 10)
-			paxHdrs[paxSize] = strconv.FormatInt(hdr.Size, 10)
-			delete(paxHdrs, paxPath) // Recorded by paxGNUSparseName
-		}
-	*/
-	_ = realSize
-
-	// Write PAX records to the output.
-	isGlobal := hdr.Typeflag == TypeXGlobalHeader
-	if len(paxHdrs) > 0 || isGlobal {
-		// Sort keys for deterministic ordering.
-		var keys []string
-		for k := range paxHdrs {
-			keys = append(keys, k)
-		}
-		sort.Strings(keys)
-
-		// Write each record to a buffer.
-		var buf strings.Builder
-		for _, k := range keys {
-			rec, err := formatPAXRecord(k, paxHdrs[k])
-			if err != nil {
-				return err
-			}
-			buf.WriteString(rec)
-		}
-
-		// Write the extended header file.
-		var name string
-		var flag byte
-		if isGlobal {
-			name = realName
-			if name == "" {
-				name = "GlobalHead.0.0"
-			}
-			flag = TypeXGlobalHeader
-		} else {
-			dir, file := path.Split(realName)
-			name = path.Join(dir, "PaxHeaders.0", file)
-			flag = TypeXHeader
-		}
-		data := buf.String()
-		if len(data) > maxSpecialFileSize {
-			return ErrFieldTooLong
-		}
-		if err := tw.writeRawFile(name, data, flag, FormatPAX); err != nil || isGlobal {
-			return err // Global headers return here
-		}
-	}
-
-	// Pack the main header.
-	var f formatter // Ignore errors since they are expected
-	fmtStr := func(b []byte, s string) { f.formatString(b, toASCII(s)) }
-	blk := tw.templateV7Plus(hdr, fmtStr, f.formatOctal)
-	blk.setFormat(FormatPAX)
-	if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil {
-		return err
-	}
-
-	// TODO(dsnet): Re-enable this when adding sparse support.
-	// See https://golang.org/issue/22735
-	/*
-		// Write the sparse map and setup the sparse writer if necessary.
-		if len(spd) > 0 {
-			// Use tw.curr since the sparse map is accounted for in hdr.Size.
-			if _, err := tw.curr.Write(spb); err != nil {
-				return err
-			}
-			tw.curr = &sparseFileWriter{tw.curr, spd, 0}
-		}
-	*/
-	return nil
-}
-
-func (tw *Writer) writeGNUHeader(hdr *Header) error {
-	// Use long-link files if Name or Linkname exceeds the field size.
-	const longName = "././@LongLink"
-	if len(hdr.Name) > nameSize {
-		data := hdr.Name + "\x00"
-		if err := tw.writeRawFile(longName, data, TypeGNULongName, FormatGNU); err != nil {
-			return err
-		}
-	}
-	if len(hdr.Linkname) > nameSize {
-		data := hdr.Linkname + "\x00"
-		if err := tw.writeRawFile(longName, data, TypeGNULongLink, FormatGNU); err != nil {
-			return err
-		}
-	}
-
-	// Pack the main header.
-	var f formatter // Ignore errors since they are expected
-	var spd sparseDatas
-	var spb []byte
-	blk := tw.templateV7Plus(hdr, f.formatString, f.formatNumeric)
-	if !hdr.AccessTime.IsZero() {
-		f.formatNumeric(blk.toGNU().accessTime(), hdr.AccessTime.Unix())
-	}
-	if !hdr.ChangeTime.IsZero() {
-		f.formatNumeric(blk.toGNU().changeTime(), hdr.ChangeTime.Unix())
-	}
-	// TODO(dsnet): Re-enable this when adding sparse support.
-	// See https://golang.org/issue/22735
-	/*
-		if hdr.Typeflag == TypeGNUSparse {
-			sph := append([]sparseEntry{}, hdr.SparseHoles...) // Copy sparse map
-			sph = alignSparseEntries(sph, hdr.Size)
-			spd = invertSparseEntries(sph, hdr.Size)
-
-			// Format the sparse map.
-			formatSPD := func(sp sparseDatas, sa sparseArray) sparseDatas {
-				for i := 0; len(sp) > 0 && i < sa.MaxEntries(); i++ {
-					f.formatNumeric(sa.Entry(i).Offset(), sp[0].Offset)
-					f.formatNumeric(sa.Entry(i).Length(), sp[0].Length)
-					sp = sp[1:]
-				}
-				if len(sp) > 0 {
-					sa.IsExtended()[0] = 1
-				}
-				return sp
-			}
-			sp2 := formatSPD(spd, blk.GNU().Sparse())
-			for len(sp2) > 0 {
-				var spHdr block
-				sp2 = formatSPD(sp2, spHdr.Sparse())
-				spb = append(spb, spHdr[:]...)
-			}
-
-			// Update size fields in the header block.
-			realSize := hdr.Size
-			hdr.Size = 0 // Encoded size; does not account for encoded sparse map
-			for _, s := range spd {
-				hdr.Size += s.Length
-			}
-			copy(blk.V7().Size(), zeroBlock[:]) // Reset field
-			f.formatNumeric(blk.V7().Size(), hdr.Size)
-			f.formatNumeric(blk.GNU().RealSize(), realSize)
-		}
-	*/
-	blk.setFormat(FormatGNU)
-	if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil {
-		return err
-	}
-
-	// Write the extended sparse map and setup the sparse writer if necessary.
-	if len(spd) > 0 {
-		// Use tw.w since the sparse map is not accounted for in hdr.Size.
-		if _, err := tw.w.Write(spb); err != nil {
-			return err
-		}
-		tw.curr = &sparseFileWriter{tw.curr, spd, 0}
-	}
-	return nil
-}
-
-type (
-	stringFormatter func([]byte, string)
-	numberFormatter func([]byte, int64)
-)
-
-// templateV7Plus fills out the V7 fields of a block using values from hdr.
-// It also fills out fields (uname, gname, devmajor, devminor) that are
-// shared in the USTAR, PAX, and GNU formats using the provided formatters.
-//
-// The block returned is only valid until the next call to
-// templateV7Plus or writeRawFile.
-func (tw *Writer) templateV7Plus(hdr *Header, fmtStr stringFormatter, fmtNum numberFormatter) *block {
-	tw.blk.reset()
-
-	modTime := hdr.ModTime
-	if modTime.IsZero() {
-		modTime = time.Unix(0, 0)
-	}
-
-	v7 := tw.blk.toV7()
-	v7.typeFlag()[0] = hdr.Typeflag
-	fmtStr(v7.name(), hdr.Name)
-	fmtStr(v7.linkName(), hdr.Linkname)
-	fmtNum(v7.mode(), hdr.Mode)
-	fmtNum(v7.uid(), int64(hdr.Uid))
-	fmtNum(v7.gid(), int64(hdr.Gid))
-	fmtNum(v7.size(), hdr.Size)
-	fmtNum(v7.modTime(), modTime.Unix())
-
-	ustar := tw.blk.toUSTAR()
-	fmtStr(ustar.userName(), hdr.Uname)
-	fmtStr(ustar.groupName(), hdr.Gname)
-	fmtNum(ustar.devMajor(), hdr.Devmajor)
-	fmtNum(ustar.devMinor(), hdr.Devminor)
-
-	return &tw.blk
-}
-
-// writeRawFile writes a minimal file with the given name and flag type.
-// It uses format to encode the header format and will write data as the body.
-// It uses default values for all of the other fields (as BSD and GNU tar does).
-func (tw *Writer) writeRawFile(name, data string, flag byte, format Format) error {
-	tw.blk.reset()
-
-	// Best effort for the filename.
-	name = toASCII(name)
-	if len(name) > nameSize {
-		name = name[:nameSize]
-	}
-	name = strings.TrimRight(name, "/")
-
-	var f formatter
-	v7 := tw.blk.toV7()
-	v7.typeFlag()[0] = flag
-	f.formatString(v7.name(), name)
-	f.formatOctal(v7.mode(), 0)
-	f.formatOctal(v7.uid(), 0)
-	f.formatOctal(v7.gid(), 0)
-	f.formatOctal(v7.size(), int64(len(data))) // Must be < 8GiB
-	f.formatOctal(v7.modTime(), 0)
-	tw.blk.setFormat(format)
-	if f.err != nil {
-		return f.err // Only occurs if size condition is violated
-	}
-
-	// Write the header and data.
-	if err := tw.writeRawHeader(&tw.blk, int64(len(data)), flag); err != nil {
-		return err
-	}
-	_, err := io.WriteString(tw, data)
-	return err
-}
-
-// writeRawHeader writes the value of blk, regardless of its value.
-// It sets up the Writer such that it can accept a file of the given size.
-// If the flag is a special header-only flag, then the size is treated as zero.
-func (tw *Writer) writeRawHeader(blk *block, size int64, flag byte) error {
-	if err := tw.Flush(); err != nil {
-		return err
-	}
-	if _, err := tw.w.Write(blk[:]); err != nil {
-		return err
-	}
-	if isHeaderOnlyType(flag) {
-		size = 0
-	}
-	tw.curr = &regFileWriter{tw.w, size}
-	tw.pad = blockPadding(size)
-	return nil
-}
-
-// splitUSTARPath splits a path according to USTAR prefix and suffix rules.
-// If the path is not splittable, then it will return ("", "", false).
-func splitUSTARPath(name string) (prefix, suffix string, ok bool) {
-	length := len(name)
-	if length <= nameSize || !isASCII(name) {
-		return "", "", false
-	} else if length > prefixSize+1 {
-		length = prefixSize + 1
-	} else if name[length-1] == '/' {
-		length--
-	}
-
-	i := strings.LastIndex(name[:length], "/")
-	nlen := len(name) - i - 1 // nlen is length of suffix
-	plen := i                 // plen is length of prefix
-	if i <= 0 || nlen > nameSize || nlen == 0 || plen > prefixSize {
-		return "", "", false
-	}
-	return name[:i], name[i+1:], true
-}
-
-// Write writes to the current file in the tar archive.
-// Write returns the error ErrWriteTooLong if more than
-// Header.Size bytes are written after WriteHeader.
-//
-// Calling Write on special types like TypeLink, TypeSymlink, TypeChar,
-// TypeBlock, TypeDir, and TypeFifo returns (0, ErrWriteTooLong) regardless
-// of what the Header.Size claims.
-func (tw *Writer) Write(b []byte) (int, error) {
-	if tw.err != nil {
-		return 0, tw.err
-	}
-	n, err := tw.curr.Write(b)
-	if err != nil && err != ErrWriteTooLong {
-		tw.err = err
-	}
-	return n, err
-}
-
-// readFrom populates the content of the current file by reading from r.
-// The bytes read must match the number of remaining bytes in the current file.
-//
-// If the current file is sparse and r is an io.ReadSeeker,
-// then readFrom uses Seek to skip past holes defined in Header.SparseHoles,
-// assuming that skipped regions are all NULs.
-// This always reads the last byte to ensure r is the right size.
-//
-// TODO(dsnet): Re-export this when adding sparse file support.
-// See https://golang.org/issue/22735
-func (tw *Writer) readFrom(r io.Reader) (int64, error) {
-	if tw.err != nil {
-		return 0, tw.err
-	}
-	n, err := tw.curr.ReadFrom(r)
-	if err != nil && err != ErrWriteTooLong {
-		tw.err = err
-	}
-	return n, err
-}
-
-// Close closes the tar archive by flushing the padding, and writing the footer.
-// If the current file (from a prior call to WriteHeader) is not fully written,
-// then this returns an error.
-func (tw *Writer) Close() error {
-	if tw.err == ErrWriteAfterClose {
-		return nil
-	}
-	if tw.err != nil {
-		return tw.err
-	}
-
-	// Trailer: two zero blocks.
-	err := tw.Flush()
-	for i := 0; i < 2 && err == nil; i++ {
-		_, err = tw.w.Write(zeroBlock[:])
-	}
-
-	// Ensure all future actions are invalid.
-	tw.err = ErrWriteAfterClose
-	return err // Report IO errors
-}
-
-// regFileWriter is a fileWriter for writing data to a regular file entry.
-type regFileWriter struct {
-	w  io.Writer // Underlying Writer
-	nb int64     // Number of remaining bytes to write
-}
-
-func (fw *regFileWriter) Write(b []byte) (n int, err error) {
-	overwrite := int64(len(b)) > fw.nb
-	if overwrite {
-		b = b[:fw.nb]
-	}
-	if len(b) > 0 {
-		n, err = fw.w.Write(b)
-		fw.nb -= int64(n)
-	}
-	switch {
-	case err != nil:
-		return n, err
-	case overwrite:
-		return n, ErrWriteTooLong
-	default:
-		return n, nil
-	}
-}
-
-func (fw *regFileWriter) ReadFrom(r io.Reader) (int64, error) {
-	return io.Copy(struct{ io.Writer }{fw}, r)
-}
-
-// logicalRemaining implements fileState.logicalRemaining.
-func (fw regFileWriter) logicalRemaining() int64 {
-	return fw.nb
-}
-
-// logicalRemaining implements fileState.physicalRemaining.
-func (fw regFileWriter) physicalRemaining() int64 {
-	return fw.nb
-}
-
-// sparseFileWriter is a fileWriter for writing data to a sparse file entry.
-type sparseFileWriter struct {
-	fw  fileWriter  // Underlying fileWriter
-	sp  sparseDatas // Normalized list of data fragments
-	pos int64       // Current position in sparse file
-}
-
-func (sw *sparseFileWriter) Write(b []byte) (n int, err error) {
-	overwrite := int64(len(b)) > sw.logicalRemaining()
-	if overwrite {
-		b = b[:sw.logicalRemaining()]
-	}
-
-	b0 := b
-	endPos := sw.pos + int64(len(b))
-	for endPos > sw.pos && err == nil {
-		var nf int // Bytes written in fragment
-		dataStart, dataEnd := sw.sp[0].Offset, sw.sp[0].endOffset()
-		if sw.pos < dataStart { // In a hole fragment
-			bf := b[:min(int64(len(b)), dataStart-sw.pos)]
-			nf, err = zeroWriter{}.Write(bf)
-		} else { // In a data fragment
-			bf := b[:min(int64(len(b)), dataEnd-sw.pos)]
-			nf, err = sw.fw.Write(bf)
-		}
-		b = b[nf:]
-		sw.pos += int64(nf)
-		if sw.pos >= dataEnd && len(sw.sp) > 1 {
-			sw.sp = sw.sp[1:] // Ensure last fragment always remains
-		}
-	}
-
-	n = len(b0) - len(b)
-	switch {
-	case err == ErrWriteTooLong:
-		return n, errMissData // Not possible; implies bug in validation logic
-	case err != nil:
-		return n, err
-	case sw.logicalRemaining() == 0 && sw.physicalRemaining() > 0:
-		return n, errUnrefData // Not possible; implies bug in validation logic
-	case overwrite:
-		return n, ErrWriteTooLong
-	default:
-		return n, nil
-	}
-}
-
-func (sw *sparseFileWriter) ReadFrom(r io.Reader) (n int64, err error) {
-	rs, ok := r.(io.ReadSeeker)
-	if ok {
-		if _, err := rs.Seek(0, io.SeekCurrent); err != nil {
-			ok = false // Not all io.Seeker can really seek
-		}
-	}
-	if !ok {
-		return io.Copy(struct{ io.Writer }{sw}, r)
-	}
-
-	var readLastByte bool
-	pos0 := sw.pos
-	for sw.logicalRemaining() > 0 && !readLastByte && err == nil {
-		var nf int64 // Size of fragment
-		dataStart, dataEnd := sw.sp[0].Offset, sw.sp[0].endOffset()
-		if sw.pos < dataStart { // In a hole fragment
-			nf = dataStart - sw.pos
-			if sw.physicalRemaining() == 0 {
-				readLastByte = true
-				nf--
-			}
-			_, err = rs.Seek(nf, io.SeekCurrent)
-		} else { // In a data fragment
-			nf = dataEnd - sw.pos
-			nf, err = io.CopyN(sw.fw, rs, nf)
-		}
-		sw.pos += nf
-		if sw.pos >= dataEnd && len(sw.sp) > 1 {
-			sw.sp = sw.sp[1:] // Ensure last fragment always remains
-		}
-	}
-
-	// If the last fragment is a hole, then seek to 1-byte before EOF, and
-	// read a single byte to ensure the file is the right size.
-	if readLastByte && err == nil {
-		_, err = mustReadFull(rs, []byte{0})
-		sw.pos++
-	}
-
-	n = sw.pos - pos0
-	switch {
-	case err == io.EOF:
-		return n, io.ErrUnexpectedEOF
-	case err == ErrWriteTooLong:
-		return n, errMissData // Not possible; implies bug in validation logic
-	case err != nil:
-		return n, err
-	case sw.logicalRemaining() == 0 && sw.physicalRemaining() > 0:
-		return n, errUnrefData // Not possible; implies bug in validation logic
-	default:
-		return n, ensureEOF(rs)
-	}
-}
-
-func (sw sparseFileWriter) logicalRemaining() int64 {
-	return sw.sp[len(sw.sp)-1].endOffset() - sw.pos
-}
-func (sw sparseFileWriter) physicalRemaining() int64 {
-	return sw.fw.physicalRemaining()
-}
-
-// zeroWriter may only be written with NULs, otherwise it returns errWriteHole.
-type zeroWriter struct{}
-
-func (zeroWriter) Write(b []byte) (int, error) {
-	for i, c := range b {
-		if c != 0 {
-			return i, errWriteHole
-		}
-	}
-	return len(b), nil
-}
-
-// ensureEOF checks whether r is at EOF, reporting ErrWriteTooLong if not so.
-func ensureEOF(r io.Reader) error {
-	n, err := tryReadFull(r, []byte{0})
-	switch {
-	case n > 0:
-		return ErrWriteTooLong
-	case err == io.EOF:
-		return nil
-	default:
-		return err
-	}
-}


Test patch:
diff --git a/pkg/archive/archive_test.go b/pkg/archive/archive_test.go
index b0af57a41dfe2..e8e2152acbbe4 100644
--- a/pkg/archive/archive_test.go
+++ b/pkg/archive/archive_test.go
@@ -1360,3 +1360,12 @@ func TestPigz(t *testing.T) {
 		assert.Equal(t, reflect.TypeOf(contextReaderCloserWrapper.Reader), reflect.TypeOf(&gzip.Reader{}))
 	}
 }
+
+func TestNosysFileInfo(t *testing.T) {
+	st, err := os.Stat("archive_test.go")
+	assert.NilError(t, err)
+	h, err := tar.FileInfoHeader(nosysFileInfo{st}, "")
+	assert.NilError(t, err)
+	assert.Check(t, h.Uname == "")
+	assert.Check(t, h.Gname == "")
+}
diff --git a/vendor/archive/tar/example_test.go b/vendor/archive/tar/example_test.go
deleted file mode 100644
index a2474b959f65c..0000000000000
--- a/vendor/archive/tar/example_test.go
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tar_test
-
-import (
-	"archive/tar"
-	"bytes"
-	"fmt"
-	"io"
-	"log"
-	"os"
-)
-
-func Example_minimal() {
-	// Create and add some files to the archive.
-	var buf bytes.Buffer
-	tw := tar.NewWriter(&buf)
-	var files = []struct {
-		Name, Body string
-	}{
-		{"readme.txt", "This archive contains some text files."},
-		{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
-		{"todo.txt", "Get animal handling license."},
-	}
-	for _, file := range files {
-		hdr := &tar.Header{
-			Name: file.Name,
-			Mode: 0600,
-			Size: int64(len(file.Body)),
-		}
-		if err := tw.WriteHeader(hdr); err != nil {
-			log.Fatal(err)
-		}
-		if _, err := tw.Write([]byte(file.Body)); err != nil {
-			log.Fatal(err)
-		}
-	}
-	if err := tw.Close(); err != nil {
-		log.Fatal(err)
-	}
-
-	// Open and iterate through the files in the archive.
-	tr := tar.NewReader(&buf)
-	for {
-		hdr, err := tr.Next()
-		if err == io.EOF {
-			break // End of archive
-		}
-		if err != nil {
-			log.Fatal(err)
-		}
-		fmt.Printf("Contents of %s:\n", hdr.Name)
-		if _, err := io.Copy(os.Stdout, tr); err != nil {
-			log.Fatal(err)
-		}
-		fmt.Println()
-	}
-
-	// Output:
-	// Contents of readme.txt:
-	// This archive contains some text files.
-	// Contents of gopher.txt:
-	// Gopher names:
-	// George
-	// Geoffrey
-	// Gonzo
-	// Contents of todo.txt:
-	// Get animal handling license.
-}
diff --git a/vendor/archive/tar/fuzz_test.go b/vendor/archive/tar/fuzz_test.go
deleted file mode 100644
index e73e0d2609e50..0000000000000
--- a/vendor/archive/tar/fuzz_test.go
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tar
-
-import (
-	"bytes"
-	"io"
-	"testing"
-)
-
-func FuzzReader(f *testing.F) {
-	b := bytes.NewBuffer(nil)
-	w := NewWriter(b)
-	inp := []byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
-	err := w.WriteHeader(&Header{
-		Name: "lorem.txt",
-		Mode: 0600,
-		Size: int64(len(inp)),
-	})
-	if err != nil {
-		f.Fatalf("failed to create writer: %s", err)
-	}
-	_, err = w.Write(inp)
-	if err != nil {
-		f.Fatalf("failed to write file to archive: %s", err)
-	}
-	if err := w.Close(); err != nil {
-		f.Fatalf("failed to write archive: %s", err)
-	}
-	f.Add(b.Bytes())
-
-	f.Fuzz(func(t *testing.T, b []byte) {
-		r := NewReader(bytes.NewReader(b))
-		type file struct {
-			header  *Header
-			content []byte
-		}
-		files := []file{}
-		for {
-			hdr, err := r.Next()
-			if err == io.EOF {
-				break
-			}
-			if err != nil {
-				return
-			}
-			buf := bytes.NewBuffer(nil)
-			if _, err := io.Copy(buf, r); err != nil {
-				continue
-			}
-			files = append(files, file{header: hdr, content: buf.Bytes()})
-		}
-
-		// If we were unable to read anything out of the archive don't
-		// bother trying to roundtrip it.
-		if len(files) == 0 {
-			return
-		}
-
-		out := bytes.NewBuffer(nil)
-		w := NewWriter(out)
-		for _, f := range files {
-			if err := w.WriteHeader(f.header); err != nil {
-				t.Fatalf("unable to write previously parsed header: %s", err)
-			}
-			if _, err := w.Write(f.content); err != nil {
-				t.Fatalf("unable to write previously parsed content: %s", err)
-			}
-		}
-		if err := w.Close(); err != nil {
-			t.Fatalf("Unable to write archive: %s", err)
-		}
-
-		// TODO: We may want to check if the archive roundtrips. This would require
-		// taking into account addition of the two zero trailer blocks that Writer.Close
-		// appends.
-	})
-}
diff --git a/vendor/archive/tar/reader_test.go b/vendor/archive/tar/reader_test.go
deleted file mode 100644
index 140c736429120..0000000000000
--- a/vendor/archive/tar/reader_test.go
+++ /dev/null
@@ -1,1619 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tar
-
-import (
-	"bytes"
-	"compress/bzip2"
-	"crypto/md5"
-	"errors"
-	"fmt"
-	"io"
-	"math"
-	"os"
-	"path"
-	"reflect"
-	"strconv"
-	"strings"
-	"testing"
-	"time"
-)
-
-func TestReader(t *testing.T) {
-	vectors := []struct {
-		file    string    // Test input file
-		headers []*Header // Expected output headers
-		chksums []string  // MD5 checksum of files, leave as nil if not checked
-		err     error     // Expected error to occur
-	}{{
-		file: "testdata/gnu.tar",
-		headers: []*Header{{
-			Name:     "small.txt",
-			Mode:     0640,
-			Uid:      73025,
-			Gid:      5000,
-			Size:     5,
-			ModTime:  time.Unix(1244428340, 0),
-			Typeflag: '0',
-			Uname:    "dsymonds",
-			Gname:    "eng",
-			Format:   FormatGNU,
-		}, {
-			Name:     "small2.txt",
-			Mode:     0640,
-			Uid:      73025,
-			Gid:      5000,
-			Size:     11,
-			ModTime:  time.Unix(1244436044, 0),
-			Typeflag: '0',
-			Uname:    "dsymonds",
-			Gname:    "eng",
-			Format:   FormatGNU,
-		}},
-		chksums: []string{
-			"e38b27eaccb4391bdec553a7f3ae6b2f",
-			"c65bd2e50a56a2138bf1716f2fd56fe9",
-		},
-	}, {
-		file: "testdata/sparse-formats.tar",
-		headers: []*Header{{
-			Name:     "sparse-gnu",
-			Mode:     420,
-			Uid:      1000,
-			Gid:      1000,
-			Size:     200,
-			ModTime:  time.Unix(1392395740, 0),
-			Typeflag: 0x53,
-			Linkname: "",
-			Uname:    "david",
-			Gname:    "david",
-			Devmajor: 0,
-			Devminor: 0,
-			Format:   FormatGNU,
-		}, {
-			Name:     "sparse-posix-0.0",
-			Mode:     420,
-			Uid:      1000,
-			Gid:      1000,
-			Size:     200,
-			ModTime:  time.Unix(1392342187, 0),
-			Typeflag: 0x30,
-			Linkname: "",
-			Uname:    "david",
-			Gname:    "david",
-			Devmajor: 0,
-			Devminor: 0,
-			PAXRecords: map[string]string{
-				"GNU.sparse.size":      "200",
-				"GNU.sparse.numblocks": "95",
-				"GNU.sparse.map":       "1,1,3,1,5,1,7,1,9,1,11,1,13,1,15,1,17,1,19,1,21,1,23,1,25,1,27,1,29,1,31,1,33,1,35,1,37,1,39,1,41,1,43,1,45,1,47,1,49,1,51,1,53,1,55,1,57,1,59,1,61,1,63,1,65,1,67,1,69,1,71,1,73,1,75,1,77,1,79,1,81,1,83,1,85,1,87,1,89,1,91,1,93,1,95,1,97,1,99,1,101,1,103,1,105,1,107,1,109,1,111,1,113,1,115,1,117,1,119,1,121,1,123,1,125,1,127,1,129,1,131,1,133,1,135,1,137,1,139,1,141,1,143,1,145,1,147,1,149,1,151,1,153,1,155,1,157,1,159,1,161,1,163,1,165,1,167,1,169,1,171,1,173,1,175,1,177,1,179,1,181,1,183,1,185,1,187,1,189,1",
-			},
-			Format: FormatPAX,
-		}, {
-			Name:     "sparse-posix-0.1",
-			Mode:     420,
-			Uid:      1000,
-			Gid:      1000,
-			Size:     200,
-			ModTime:  time.Unix(1392340456, 0),
-			Typeflag: 0x30,
-			Linkname: "",
-			Uname:    "david",
-			Gname:    "david",
-			Devmajor: 0,
-			Devminor: 0,
-			PAXRecords: map[string]string{
-				"GNU.sparse.size":      "200",
-				"GNU.sparse.numblocks": "95",
-				"GNU.sparse.map":       "1,1,3,1,5,1,7,1,9,1,11,1,13,1,15,1,17,1,19,1,21,1,23,1,25,1,27,1,29,1,31,1,33,1,35,1,37,1,39,1,41,1,43,1,45,1,47,1,49,1,51,1,53,1,55,1,57,1,59,1,61,1,63,1,65,1,67,1,69,1,71,1,73,1,75,1,77,1,79,1,81,1,83,1,85,1,87,1,89,1,91,1,93,1,95,1,97,1,99,1,101,1,103,1,105,1,107,1,109,1,111,1,113,1,115,1,117,1,119,1,121,1,123,1,125,1,127,1,129,1,131,1,133,1,135,1,137,1,139,1,141,1,143,1,145,1,147,1,149,1,151,1,153,1,155,1,157,1,159,1,161,1,163,1,165,1,167,1,169,1,171,1,173,1,175,1,177,1,179,1,181,1,183,1,185,1,187,1,189,1",
-				"GNU.sparse.name":      "sparse-posix-0.1",
-			},
-			Format: FormatPAX,
-		}, {
-			Name:     "sparse-posix-1.0",
-			Mode:     420,
-			Uid:      1000,
-			Gid:      1000,
-			Size:     200,
-			ModTime:  time.Unix(1392337404, 0),
-			Typeflag: 0x30,
-			Linkname: "",
-			Uname:    "david",
-			Gname:    "david",
-			Devmajor: 0,
-			Devminor: 0,
-			PAXRecords: map[string]string{
-				"GNU.sparse.major":    "1",
-				"GNU.sparse.minor":    "0",
-				"GNU.sparse.realsize": "200",
-				"GNU.sparse.name":     "sparse-posix-1.0",
-			},
-			Format: FormatPAX,
-		}, {
-			Name:     "end",
-			Mode:     420,
-			Uid:      1000,
-			Gid:      1000,
-			Size:     4,
-			ModTime:  time.Unix(1392398319, 0),
-			Typeflag: 0x30,
-			Linkname: "",
-			Uname:    "david",
-			Gname:    "david",
-			Devmajor: 0,
-			Devminor: 0,
-			Format:   FormatGNU,
-		}},
-		chksums: []string{
-			"6f53234398c2449fe67c1812d993012f",
-			"6f53234398c2449fe67c1812d993012f",
-			"6f53234398c2449fe67c1812d993012f",
-			"6f53234398c2449fe67c1812d993012f",
-			"b0061974914468de549a2af8ced10316",
-		},
-	}, {
-		file: "testdata/star.tar",
-		headers: []*Header{{
-			Name:       "small.txt",
-			Mode:       0640,
-			Uid:        73025,
-			Gid:        5000,
-			Size:       5,
-			ModTime:    time.Unix(1244592783, 0),
-			Typeflag:   '0',
-			Uname:      "dsymonds",
-			Gname:      "eng",
-			AccessTime: time.Unix(1244592783, 0),
-			ChangeTime: time.Unix(1244592783, 0),
-		}, {
-			Name:       "small2.txt",
-			Mode:       0640,
-			Uid:        73025,
-			Gid:        5000,
-			Size:       11,
-			ModTime:    time.Unix(1244592783, 0),
-			Typeflag:   '0',
-			Uname:      "dsymonds",
-			Gname:      "eng",
-			AccessTime: time.Unix(1244592783, 0),
-			ChangeTime: time.Unix(1244592783, 0),
-		}},
-	}, {
-		file: "testdata/v7.tar",
-		headers: []*Header{{
-			Name:     "small.txt",
-			Mode:     0444,
-			Uid:      73025,
-			Gid:      5000,
-			Size:     5,
-			ModTime:  time.Unix(1244593104, 0),
-			Typeflag: '0',
-		}, {
-			Name:     "small2.txt",
-			Mode:     0444,
-			Uid:      73025,
-			Gid:      5000,
-			Size:     11,
-			ModTime:  time.Unix(1244593104, 0),
-			Typeflag: '0',
-		}},
-	}, {
-		file: "testdata/pax.tar",
-		headers: []*Header{{
-			Name:       "a/123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
-			Mode:       0664,
-			Uid:        1000,
-			Gid:        1000,
-			Uname:      "shane",
-			Gname:      "shane",
-			Size:       7,
-			ModTime:    time.Unix(1350244992, 23960108),
-			ChangeTime: time.Unix(1350244992, 23960108),
-			AccessTime: time.Unix(1350244992, 23960108),
-			Typeflag:   TypeReg,
-			PAXRecords: map[string]string{
-				"path":  "a/123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
-				"mtime": "1350244992.023960108",
-				"atime": "1350244992.023960108",
-				"ctime": "1350244992.023960108",
-			},
-			Format: FormatPAX,
-		}, {
-			Name:       "a/b",
-			Mode:       0777,
-			Uid:        1000,
-			Gid:        1000,
-			Uname:      "shane",
-			Gname:      "shane",
-			Size:       0,
-			ModTime:    time.Unix(1350266320, 910238425),
-			ChangeTime: time.Unix(1350266320, 910238425),
-			AccessTime: time.Unix(1350266320, 910238425),
-			Typeflag:   TypeSymlink,
-			Linkname:   "123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
-			PAXRecords: map[string]string{
-				"linkpath": "123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
-				"mtime":    "1350266320.910238425",
-				"atime":    "1350266320.910238425",
-				"ctime":    "1350266320.910238425",
-			},
-			Format: FormatPAX,
-		}},
-	}, {
-		file: "testdata/pax-bad-hdr-file.tar",
-		err:  ErrHeader,
-	}, {
-		file: "testdata/pax-bad-hdr-large.tar.bz2",
-		err:  ErrFieldTooLong,
-	}, {
-		file: "testdata/pax-bad-mtime-file.tar",
-		err:  ErrHeader,
-	}, {
-		file: "testdata/pax-pos-size-file.tar",
-		headers: []*Header{{
-			Name:     "foo",
-			Mode:     0640,
-			Uid:      319973,
-			Gid:      5000,
-			Size:     999,
-			ModTime:  time.Unix(1442282516, 0),
-			Typeflag: '0',
-			Uname:    "joetsai",
-			Gname:    "eng",
-			PAXRecords: map[string]string{
-				"size": "000000000000000000000999",
-			},
-			Format: FormatPAX,
-		}},
-		chksums: []string{
-			"0afb597b283fe61b5d4879669a350556",
-		},
-	}, {
-		file: "testdata/pax-records.tar",
-		headers: []*Header{{
-			Typeflag: TypeReg,
-			Name:     "file",
-			Uname:    strings.Repeat("long", 10),
-			ModTime:  time.Unix(0, 0),
-			PAXRecords: map[string]string{
-				"GOLANG.pkg": "tar",
-				"comment":    "Hello, 世界",
-				"uname":      strings.Repeat("long", 10),
-			},
-			Format: FormatPAX,
-		}},
-	}, {
-		file: "testdata/pax-global-records.tar",
-		headers: []*Header{{
-			Typeflag:   TypeXGlobalHeader,
-			Name:       "global1",
-			PAXRecords: map[string]string{"path": "global1", "mtime": "1500000000.0"},
-			Format:     FormatPAX,
-		}, {
-			Typeflag: TypeReg,
-			Name:     "file1",
-			ModTime:  time.Unix(0, 0),
-			Format:   FormatUSTAR,
-		}, {
-			Typeflag:   TypeReg,
-			Name:       "file2",
-			PAXRecords: map[string]string{"path": "file2"},
-			ModTime:    time.Unix(0, 0),
-			Format:     FormatPAX,
-		}, {
-			Typeflag:   TypeXGlobalHeader,
-			Name:       "GlobalHead.0.0",
-			PAXRecords: map[string]string{"path": ""},
-			Format:     FormatPAX,
-		}, {
-			Typeflag: TypeReg,
-			Name:     "file3",
-			ModTime:  time.Unix(0, 0),
-			Format:   FormatUSTAR,
-		}, {
-			Typeflag:   TypeReg,
-			Name:       "file4",
-			ModTime:    time.Unix(1400000000, 0),
-			PAXRecords: map[string]string{"mtime": "1400000000"},
-			Format:     FormatPAX,
-		}},
-	}, {
-		file: "testdata/nil-uid.tar", // golang.org/issue/5290
-		headers: []*Header{{
-			Name:     "P1050238.JPG.log",
-			Mode:     0664,
-			Uid:      0,
-			Gid:      0,
-			Size:     14,
-			ModTime:  time.Unix(1365454838, 0),
-			Typeflag: TypeReg,
-			Linkname: "",
-			Uname:    "eyefi",
-			Gname:    "eyefi",
-			Devmajor: 0,
-			Devminor: 0,
-			Format:   FormatGNU,
-		}},
-	}, {
-		file: "testdata/xattrs.tar",
-		headers: []*Header{{
-			Name:       "small.txt",
-			Mode:       0644,
-			Uid:        1000,
-			Gid:        10,
-			Size:       5,
-			ModTime:    time.Unix(1386065770, 448252320),
-			Typeflag:   '0',
-			Uname:      "alex",
-			Gname:      "wheel",
-			AccessTime: time.Unix(1389782991, 419875220),
-			ChangeTime: time.Unix(1389782956, 794414986),
-			Xattrs: map[string]string{
-				"user.key":  "value",
-				"user.key2": "value2",
-				// Interestingly, selinux encodes the terminating null inside the xattr
-				"security.selinux": "unconfined_u:object_r:default_t:s0\x00",
-			},
-			PAXRecords: map[string]string{
-				"mtime":                         "1386065770.44825232",
-				"atime":                         "1389782991.41987522",
-				"ctime":                         "1389782956.794414986",
-				"SCHILY.xattr.user.key":         "value",
-				"SCHILY.xattr.user.key2":        "value2",
-				"SCHILY.xattr.security.selinux": "unconfined_u:object_r:default_t:s0\x00",
-			},
-			Format: FormatPAX,
-		}, {
-			Name:       "small2.txt",
-			Mode:       0644,
-			Uid:        1000,
-			Gid:        10,
-			Size:       11,
-			ModTime:    time.Unix(1386065770, 449252304),
-			Typeflag:   '0',
-			Uname:      "alex",
-			Gname:      "wheel",
-			AccessTime: time.Unix(1389782991, 419875220),
-			ChangeTime: time.Unix(1386065770, 449252304),
-			Xattrs: map[string]string{
-				"security.selinux": "unconfined_u:object_r:default_t:s0\x00",
-			},
-			PAXRecords: map[string]string{
-				"mtime":                         "1386065770.449252304",
-				"atime":                         "1389782991.41987522",
-				"ctime":                         "1386065770.449252304",
-				"SCHILY.xattr.security.selinux": "unconfined_u:object_r:default_t:s0\x00",
-			},
-			Format: FormatPAX,
-		}},
-	}, {
-		// Matches the behavior of GNU, BSD, and STAR tar utilities.
-		file: "testdata/gnu-multi-hdrs.tar",
-		headers: []*Header{{
-			Name:     "GNU2/GNU2/long-path-name",
-			Linkname: "GNU4/GNU4/long-linkpath-name",
-			ModTime:  time.Unix(0, 0),
-			Typeflag: '2',
-			Format:   FormatGNU,
-		}},
-	}, {
-		// GNU tar file with atime and ctime fields set.
-		// Created with the GNU tar v1.27.1.
-		//	tar --incremental -S -cvf gnu-incremental.tar test2
-		file: "testdata/gnu-incremental.tar",
-		headers: []*Header{{
-			Name:       "test2/",
-			Mode:       16877,
-			Uid:        1000,
-			Gid:        1000,
-			Size:       14,
-			ModTime:    time.Unix(1441973427, 0),
-			Typeflag:   'D',
-			Uname:      "rawr",
-			Gname:      "dsnet",
-			AccessTime: time.Unix(1441974501, 0),
-			ChangeTime: time.Unix(1441973436, 0),
-			Format:     FormatGNU,
-		}, {
-			Name:       "test2/foo",
-			Mode:       33188,
-			Uid:        1000,
-			Gid:        1000,
-			Size:       64,
-			ModTime:    time.Unix(1441973363, 0),
-			Typeflag:   '0',
-			Uname:      "rawr",
-			Gname:      "dsnet",
-			AccessTime: time.Unix(1441974501, 0),
-			ChangeTime: time.Unix(1441973436, 0),
-			Format:     FormatGNU,
-		}, {
-			Name:       "test2/sparse",
-			Mode:       33188,
-			Uid:        1000,
-			Gid:        1000,
-			Size:       536870912,
-			ModTime:    time.Unix(1441973427, 0),
-			Typeflag:   'S',
-			Uname:      "rawr",
-			Gname:      "dsnet",
-			AccessTime: time.Unix(1441991948, 0),
-			ChangeTime: time.Unix(1441973436, 0),
-			Format:     FormatGNU,
-		}},
-	}, {
-		// Matches the behavior of GNU and BSD tar utilities.
-		file: "testdata/pax-multi-hdrs.tar",
-		headers: []*Header{{
-			Name:     "bar",
-			Linkname: "PAX4/PAX4/long-linkpath-name",
-			ModTime:  time.Unix(0, 0),
-			Typeflag: '2',
-			PAXRecords: map[string]string{
-				"linkpath": "PAX4/PAX4/long-linkpath-name",
-			},
-			Format: FormatPAX,
-		}},
-	}, {
-		// Both BSD and GNU tar truncate long names at first NUL even
-		// if there is data following that NUL character.
-		// This is reasonable as GNU long names are C-strings.
-		file: "testdata/gnu-long-nul.tar",
-		headers: []*Header{{
-			Name:     "0123456789",
-			Mode:     0644,
-			Uid:      1000,
-			Gid:      1000,
-			ModTime:  time.Unix(1486082191, 0),
-			Typeflag: '0',
-			Uname:    "rawr",
-			Gname:    "dsnet",
-			Format:   FormatGNU,
-		}},
-	}, {
-		// This archive was generated by Writer but is readable by both
-		// GNU and BSD tar utilities.
-		// The archive generated by GNU is nearly byte-for-byte identical
-		// to the Go version except the Go version sets a negative Devminor
-		// just to force the GNU format.
-		file: "testdata/gnu-utf8.tar",
-		headers: []*Header{{
-			Name: "☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹",
-			Mode: 0644,
-			Uid:  1000, Gid: 1000,
-			ModTime:  time.Unix(0, 0),
-			Typeflag: '0',
-			Uname:    "☺",
-			Gname:    "⚹",
-			Format:   FormatGNU,
-		}},
-	}, {
-		// This archive was generated by Writer but is readable by both
-		// GNU and BSD tar utilities.
-		// The archive generated by GNU is nearly byte-for-byte identical
-		// to the Go version except the Go version sets a negative Devminor
-		// just to force the GNU format.
-		file: "testdata/gnu-not-utf8.tar",
-		headers: []*Header{{
-			Name:     "hi\x80\x81\x82\x83bye",
-			Mode:     0644,
-			Uid:      1000,
-			Gid:      1000,
-			ModTime:  time.Unix(0, 0),
-			Typeflag: '0',
-			Uname:    "rawr",
-			Gname:    "dsnet",
-			Format:   FormatGNU,
-		}},
-	}, {
-		// BSD tar v3.1.2 and GNU tar v1.27.1 both rejects PAX records
-		// with NULs in the key.
-		file: "testdata/pax-nul-xattrs.tar",
-		err:  ErrHeader,
-	}, {
-		// BSD tar v3.1.2 rejects a PAX path with NUL in the value, while
-		// GNU tar v1.27.1 simply truncates at first NUL.
-		// We emulate the behavior of BSD since it is strange doing NUL
-		// truncations since PAX records are length-prefix strings instead
-		// of NUL-terminated C-strings.
-		file: "testdata/pax-nul-path.tar",
-		err:  ErrHeader,
-	}, {
-		file: "testdata/neg-size.tar",
-		err:  ErrHeader,
-	}, {
-		file: "testdata/issue10968.tar",
-		err:  ErrHeader,
-	}, {
-		file: "testdata/issue11169.tar",
-		err:  ErrHeader,
-	}, {
-		file: "testdata/issue12435.tar",
-		err:  ErrHeader,
-	}, {
-		// Ensure that we can read back the original Header as written with
-		// a buggy pre-Go1.8 tar.Writer.
-		file: "testdata/invalid-go17.tar",
-		headers: []*Header{{
-			Name:     "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/foo",
-			Uid:      010000000,
-			ModTime:  time.Unix(0, 0),
-			Typeflag: '0',
-		}},
-	}, {
-		// USTAR archive with a regular entry with non-zero device numbers.
-		file: "testdata/ustar-file-devs.tar",
-		headers: []*Header{{
-			Name:     "file",
-			Mode:     0644,
-			Typeflag: '0',
-			ModTime:  time.Unix(0, 0),
-			Devmajor: 1,
-			Devminor: 1,
-			Format:   FormatUSTAR,
-		}},
-	}, {
-		// Generated by Go, works on BSD tar v3.1.2 and GNU tar v.1.27.1.
-		file: "testdata/gnu-nil-sparse-data.tar",
-		headers: []*Header{{
-			Name:     "sparse.db",
-			Typeflag: TypeGNUSparse,
-			Size:     1000,
-			ModTime:  time.Unix(0, 0),
-			Format:   FormatGNU,
-		}},
-	}, {
-		// Generated by Go, works on BSD tar v3.1.2 and GNU tar v.1.27.1.
-		file: "testdata/gnu-nil-sparse-hole.tar",
-		headers: []*Header{{
-			Name:     "sparse.db",
-			Typeflag: TypeGNUSparse,
-			Size:     1000,
-			ModTime:  time.Unix(0, 0),
-			Format:   FormatGNU,
-		}},
-	}, {
-		// Generated by Go, works on BSD tar v3.1.2 and GNU tar v.1.27.1.
-		file: "testdata/pax-nil-sparse-data.tar",
-		headers: []*Header{{
-			Name:     "sparse.db",
-			Typeflag: TypeReg,
-			Size:     1000,
-			ModTime:  time.Unix(0, 0),
-			PAXRecords: map[string]string{
-				"size":                "1512",
-				"GNU.sparse.major":    "1",
-				"GNU.sparse.minor":    "0",
-				"GNU.sparse.realsize": "1000",
-				"GNU.sparse.name":     "sparse.db",
-			},
-			Format: FormatPAX,
-		}},
-	}, {
-		// Generated by Go, works on BSD tar v3.1.2 and GNU tar v.1.27.1.
-		file: "testdata/pax-nil-sparse-hole.tar",
-		headers: []*Header{{
-			Name:     "sparse.db",
-			Typeflag: TypeReg,
-			Size:     1000,
-			ModTime:  time.Unix(0, 0),
-			PAXRecords: map[string]string{
-				"size":                "512",
-				"GNU.sparse.major":    "1",
-				"GNU.sparse.minor":    "0",
-				"GNU.sparse.realsize": "1000",
-				"GNU.sparse.name":     "sparse.db",
-			},
-			Format: FormatPAX,
-		}},
-	}, {
-		file: "testdata/trailing-slash.tar",
-		headers: []*Header{{
-			Typeflag: TypeDir,
-			Name:     strings.Repeat("123456789/", 30),
-			ModTime:  time.Unix(0, 0),
-			PAXRecords: map[string]string{
-				"path": strings.Repeat("123456789/", 30),
-			},
-			Format: FormatPAX,
-		}},
-	}}
-
-	for _, v := range vectors {
-		t.Run(path.Base(v.file), func(t *testing.T) {
-			f, err := os.Open(v.file)
-			if err != nil {
-				t.Fatalf("unexpected error: %v", err)
-			}
-			defer f.Close()
-
-			var fr io.Reader = f
-			if strings.HasSuffix(v.file, ".bz2") {
-				fr = bzip2.NewReader(fr)
-			}
-
-			// Capture all headers and checksums.
-			var (
-				tr      = NewReader(fr)
-				hdrs    []*Header
-				chksums []string
-				rdbuf   = make([]byte, 8)
-			)
-			for {
-				var hdr *Header
-				hdr, err = tr.Next()
-				if err != nil {
-					if err == io.EOF {
-						err = nil // Expected error
-					}
-					break
-				}
-				hdrs = append(hdrs, hdr)
-
-				if v.chksums == nil {
-					continue
-				}
-				h := md5.New()
-				_, err = io.CopyBuffer(h, tr, rdbuf) // Effectively an incremental read
-				if err != nil {
-					break
-				}
-				chksums = append(chksums, fmt.Sprintf("%x", h.Sum(nil)))
-			}
-
-			for i, hdr := range hdrs {
-				if i >= len(v.headers) {
-					t.Fatalf("entry %d: unexpected header:\ngot %+v", i, *hdr)
-					continue
-				}
-				if !reflect.DeepEqual(*hdr, *v.headers[i]) {
-					t.Fatalf("entry %d: incorrect header:\ngot  %+v\nwant %+v", i, *hdr, *v.headers[i])
-				}
-			}
-			if len(hdrs) != len(v.headers) {
-				t.Fatalf("got %d headers, want %d headers", len(hdrs), len(v.headers))
-			}
-
-			for i, sum := range chksums {
-				if i >= len(v.chksums) {
-					t.Fatalf("entry %d: unexpected sum: got %s", i, sum)
-					continue
-				}
-				if sum != v.chksums[i] {
-					t.Fatalf("entry %d: incorrect checksum: got %s, want %s", i, sum, v.chksums[i])
-				}
-			}
-
-			if err != v.err {
-				t.Fatalf("unexpected error: got %v, want %v", err, v.err)
-			}
-			f.Close()
-		})
-	}
-}
-
-func TestPartialRead(t *testing.T) {
-	type testCase struct {
-		cnt    int    // Number of bytes to read
-		output string // Expected value of string read
-	}
-	vectors := []struct {
-		file  string
-		cases []testCase
-	}{{
-		file: "testdata/gnu.tar",
-		cases: []testCase{
-			{4, "Kilt"},
-			{6, "Google"},
-		},
-	}, {
-		file: "testdata/sparse-formats.tar",
-		cases: []testCase{
-			{2, "\x00G"},
-			{4, "\x00G\x00o"},
-			{6, "\x00G\x00o\x00G"},
-			{8, "\x00G\x00o\x00G\x00o"},
-			{4, "end\n"},
-		},
-	}}
-
-	for _, v := range vectors {
-		t.Run(path.Base(v.file), func(t *testing.T) {
-			f, err := os.Open(v.file)
-			if err != nil {
-				t.Fatalf("Open() error: %v", err)
-			}
-			defer f.Close()
-
-			tr := NewReader(f)
-			for i, tc := range v.cases {
-				hdr, err := tr.Next()
-				if err != nil || hdr == nil {
-					t.Fatalf("entry %d, Next(): got %v, want %v", i, err, nil)
-				}
-				buf := make([]byte, tc.cnt)
-				if _, err := io.ReadFull(tr, buf); err != nil {
-					t.Fatalf("entry %d, ReadFull(): got %v, want %v", i, err, nil)
-				}
-				if string(buf) != tc.output {
-					t.Fatalf("entry %d, ReadFull(): got %q, want %q", i, string(buf), tc.output)
-				}
-			}
-
-			if _, err := tr.Next(); err != io.EOF {
-				t.Fatalf("Next(): got %v, want EOF", err)
-			}
-		})
-	}
-}
-
-func TestUninitializedRead(t *testing.T) {
-	f, err := os.Open("testdata/gnu.tar")
-	if err != nil {
-		t.Fatalf("Unexpected error: %v", err)
-	}
-	defer f.Close()
-
-	tr := NewReader(f)
-	_, err = tr.Read([]byte{})
-	if err == nil || err != io.EOF {
-		t.Errorf("Unexpected error: %v, wanted %v", err, io.EOF)
-	}
-
-}
-
-type reader struct{ io.Reader }
-type readSeeker struct{ io.ReadSeeker }
-type readBadSeeker struct{ io.ReadSeeker }
-
-func (rbs *readBadSeeker) Seek(int64, int) (int64, error) { return 0, fmt.Errorf("illegal seek") }
-
-// TestReadTruncation test the ending condition on various truncated files and
-// that truncated files are still detected even if the underlying io.Reader
-// satisfies io.Seeker.
-func TestReadTruncation(t *testing.T) {
-	var ss []string
-	for _, p := range []string{
-		"testdata/gnu.tar",
-		"testdata/ustar-file-reg.tar",
-		"testdata/pax-path-hdr.tar",
-		"testdata/sparse-formats.tar",
-	} {
-		buf, err := os.ReadFile(p)
-		if err != nil {
-			t.Fatalf("unexpected error: %v", err)
-		}
-		ss = append(ss, string(buf))
-	}
-
-	data1, data2, pax, sparse := ss[0], ss[1], ss[2], ss[3]
-	data2 += strings.Repeat("\x00", 10*512)
-	trash := strings.Repeat("garbage ", 64) // Exactly 512 bytes
-
-	vectors := []struct {
-		input string // Input stream
-		cnt   int    // Expected number of headers read
-		err   error  // Expected error outcome
-	}{
-		{"", 0, io.EOF}, // Empty file is a "valid" tar file
-		{data1[:511], 0, io.ErrUnexpectedEOF},
-		{data1[:512], 1, io.ErrUnexpectedEOF},
-		{data1[:1024], 1, io.EOF},
-		{data1[:1536], 2, io.ErrUnexpectedEOF},
-		{data1[:2048], 2, io.EOF},
-		{data1, 2, io.EOF},
-		{data1[:2048] + data2[:1536], 3, io.EOF},
-		{data2[:511], 0, io.ErrUnexpectedEOF},
-		{data2[:512], 1, io.ErrUnexpectedEOF},
-		{data2[:1195], 1, io.ErrUnexpectedEOF},
-		{data2[:1196], 1, io.EOF}, // Exact end of data and start of padding
-		{data2[:1200], 1, io.EOF},
-		{data2[:1535], 1, io.EOF},
-		{data2[:1536], 1, io.EOF}, // Exact end of padding
-		{data2[:1536] + trash[:1], 1, io.ErrUnexpectedEOF},
-		{data2[:1536] + trash[:511], 1, io.ErrUnexpectedEOF},
-		{data2[:1536] + trash, 1, ErrHeader},
-		{data2[:2048], 1, io.EOF}, // Exactly 1 empty block
-		{data2[:2048] + trash[:1], 1, io.ErrUnexpectedEOF},
-		{data2[:2048] + trash[:511], 1, io.ErrUnexpectedEOF},
-		{data2[:2048] + trash, 1, ErrHeader},
-		{data2[:2560], 1, io.EOF}, // Exactly 2 empty blocks (normal end-of-stream)
-		{data2[:2560] + trash[:1], 1, io.EOF},
-		{data2[:2560] + trash[:511], 1, io.EOF},
-		{data2[:2560] + trash, 1, io.EOF},
-		{data2[:3072], 1, io.EOF},
-		{pax, 0, io.EOF}, // PAX header without data is a "valid" tar file
-		{pax + trash[:1], 0, io.ErrUnexpectedEOF},
-		{pax + trash[:511], 0, io.ErrUnexpectedEOF},
-		{sparse[:511], 0, io.ErrUnexpectedEOF},
-		{sparse[:512], 0, io.ErrUnexpectedEOF},
-		{sparse[:3584], 1, io.EOF},
-		{sparse[:9200], 1, io.EOF}, // Terminate in padding of sparse header
-		{sparse[:9216], 1, io.EOF},
-		{sparse[:9728], 2, io.ErrUnexpectedEOF},
-		{sparse[:10240], 2, io.EOF},
-		{sparse[:11264], 2, io.ErrUnexpectedEOF},
-		{sparse, 5, io.EOF},
-		{sparse + trash, 5, io.EOF},
-	}
-
-	for i, v := range vectors {
-		for j := 0; j < 6; j++ {
-			var tr *Reader
-			var s1, s2 string
-
-			switch j {
-			case 0:
-				tr = NewReader(&reader{strings.NewReader(v.input)})
-				s1, s2 = "io.Reader", "auto"
-			case 1:
-				tr = NewReader(&reader{strings.NewReader(v.input)})
-				s1, s2 = "io.Reader", "manual"
-			case 2:
-				tr = NewReader(&readSeeker{strings.NewReader(v.input)})
-				s1, s2 = "io.ReadSeeker", "auto"
-			case 3:
-				tr = NewReader(&readSeeker{strings.NewReader(v.input)})
-				s1, s2 = "io.ReadSeeker", "manual"
-			case 4:
-				tr = NewReader(&readBadSeeker{strings.NewReader(v.input)})
-				s1, s2 = "ReadBadSeeker", "auto"
-			case 5:
-				tr = NewReader(&readBadSeeker{strings.NewReader(v.input)})
-				s1, s2 = "ReadBadSeeker", "manual"
-			}
-
-			var cnt int
-			var err error
-			for {
-				if _, err = tr.Next(); err != nil {
-					break
-				}
-				cnt++
-				if s2 == "manual" {
-					if _, err = tr.writeTo(io.Discard); err != nil {
-						break
-					}
-				}
-			}
-			if err != v.err {
-				t.Errorf("test %d, NewReader(%s) with %s discard: got %v, want %v",
-					i, s1, s2, err, v.err)
-			}
-			if cnt != v.cnt {
-				t.Errorf("test %d, NewReader(%s) with %s discard: got %d headers, want %d headers",
-					i, s1, s2, cnt, v.cnt)
-			}
-		}
-	}
-}
-
-// TestReadHeaderOnly tests that Reader does not attempt to read special
-// header-only files.
-func TestReadHeaderOnly(t *testing.T) {
-	f, err := os.Open("testdata/hdr-only.tar")
-	if err != nil {
-		t.Fatalf("unexpected error: %v", err)
-	}
-	defer f.Close()
-
-	var hdrs []*Header
-	tr := NewReader(f)
-	for {
-		hdr, err := tr.Next()
-		if err == io.EOF {
-			break
-		}
-		if err != nil {
-			t.Errorf("Next(): got %v, want %v", err, nil)
-			continue
-		}
-		hdrs = append(hdrs, hdr)
-
-		// If a special flag, we should read nothing.
-		cnt, _ := io.ReadFull(tr, []byte{0})
-		if cnt > 0 && hdr.Typeflag != TypeReg {
-			t.Errorf("ReadFull(...): got %d bytes, want 0 bytes", cnt)
-		}
-	}
-
-	// File is crafted with 16 entries. The later 8 are identical to the first
-	// 8 except that the size is set.
-	if len(hdrs) != 16 {
-		t.Fatalf("len(hdrs): got %d, want %d", len(hdrs), 16)
-	}
-	for i := 0; i < 8; i++ {
-		hdr1, hdr2 := hdrs[i+0], hdrs[i+8]
-		hdr1.Size, hdr2.Size = 0, 0
-		if !reflect.DeepEqual(*hdr1, *hdr2) {
-			t.Errorf("incorrect header:\ngot  %+v\nwant %+v", *hdr1, *hdr2)
-		}
-	}
-}
-
-func TestMergePAX(t *testing.T) {
-	vectors := []struct {
-		in   map[string]string
-		want *Header
-		ok   bool
-	}{{
-		in: map[string]string{
-			"path":  "a/b/c",
-			"uid":   "1000",
-			"mtime": "1350244992.023960108",
-		},
-		want: &Header{
-			Name:    "a/b/c",
-			Uid:     1000,
-			ModTime: time.Unix(1350244992, 23960108),
-			PAXRecords: map[string]string{
-				"path":  "a/b/c",
-				"uid":   "1000",
-				"mtime": "1350244992.023960108",
-			},
-		},
-		ok: true,
-	}, {
-		in: map[string]string{
-			"gid": "gtgergergersagersgers",
-		},
-		ok: false,
-	}, {
-		in: map[string]string{
-			"missing":          "missing",
-			"SCHILY.xattr.key": "value",
-		},
-		want: &Header{
-			Xattrs: map[string]string{"key": "value"},
-			PAXRecords: map[string]string{
-				"missing":          "missing",
-				"SCHILY.xattr.key": "value",
-			},
-		},
-		ok: true,
-	}}
-
-	for i, v := range vectors {
-		got := new(Header)
-		err := mergePAX(got, v.in)
-		if v.ok && !reflect.DeepEqual(*got, *v.want) {
-			t.Errorf("test %d, mergePAX(...):\ngot  %+v\nwant %+v", i, *got, *v.want)
-		}
-		if ok := err == nil; ok != v.ok {
-			t.Errorf("test %d, mergePAX(...): got %v, want %v", i, ok, v.ok)
-		}
-	}
-}
-
-func TestParsePAX(t *testing.T) {
-	vectors := []struct {
-		in   string
-		want map[string]string
-		ok   bool
-	}{
-		{"", nil, true},
-		{"6 k=1\n", map[string]string{"k": "1"}, true},
-		{"10 a=name\n", map[string]string{"a": "name"}, true},
-		{"9 a=name\n", map[string]string{"a": "name"}, true},
-		{"30 mtime=1350244992.023960108\n", map[string]string{"mtime": "1350244992.023960108"}, true},
-		{"3 somelongkey=\n", nil, false},
-		{"50 tooshort=\n", nil, false},
-		{"13 key1=haha\n13 key2=nana\n13 key3=kaka\n",
-			map[string]string{"key1": "haha", "key2": "nana", "key3": "kaka"}, true},
-		{"13 key1=val1\n13 key2=val2\n8 key1=\n",
-			map[string]string{"key1": "", "key2": "val2"}, true},
-		{"22 GNU.sparse.size=10\n26 GNU.sparse.numblocks=2\n" +
-			"23 GNU.sparse.offset=1\n25 GNU.sparse.numbytes=2\n" +
-			"23 GNU.sparse.offset=3\n25 GNU.sparse.numbytes=4\n",
-			map[string]string{paxGNUSparseSize: "10", paxGNUSparseNumBlocks: "2", paxGNUSparseMap: "1,2,3,4"}, true},
-		{"22 GNU.sparse.size=10\n26 GNU.sparse.numblocks=1\n" +
-			"25 GNU.sparse.numbytes=2\n23 GNU.sparse.offset=1\n",
-			nil, false},
-		{"22 GNU.sparse.size=10\n26 GNU.sparse.numblocks=1\n" +
-			"25 GNU.sparse.offset=1,2\n25 GNU.sparse.numbytes=2\n",
-			nil, false},
-	}
-
-	for i, v := range vectors {
-		r := strings.NewReader(v.in)
-		got, err := parsePAX(r)
-		if !reflect.DeepEqual(got, v.want) && !(len(got) == 0 && len(v.want) == 0) {
-			t.Errorf("test %d, parsePAX():\ngot  %v\nwant %v", i, got, v.want)
-		}
-		if ok := err == nil; ok != v.ok {
-			t.Errorf("test %d, parsePAX(): got %v, want %v", i, ok, v.ok)
-		}
-	}
-}
-
-func TestReadOldGNUSparseMap(t *testing.T) {
-	populateSparseMap := func(sa sparseArray, sps []string) []string {
-		for i := 0; len(sps) > 0 && i < sa.maxEntries(); i++ {
-			copy(sa.entry(i), sps[0])
-			sps = sps[1:]
-		}
-		if len(sps) > 0 {
-			copy(sa.isExtended(), "\x80")
-		}
-		return sps
-	}
-
-	makeInput := func(format Format, size string, sps ...string) (out []byte) {
-		// Write the initial GNU header.
-		var blk block
-		gnu := blk.toGNU()
-		sparse := gnu.sparse()
-		copy(gnu.realSize(), size)
-		sps = populateSparseMap(sparse, sps)
-		if format != FormatUnknown {
-			blk.setFormat(format)
-		}
-		out = append(out, blk[:]...)
-
-		// Write extended sparse blocks.
-		for len(sps) > 0 {
-			var blk block
-			sps = populateSparseMap(blk.toSparse(), sps)
-			out = append(out, blk[:]...)
-		}
-		return out
-	}
-
-	makeSparseStrings := func(sp []sparseEntry) (out []string) {
-		var f formatter
-		for _, s := range sp {
-			var b [24]byte
-			f.formatNumeric(b[:12], s.Offset)
-			f.formatNumeric(b[12:], s.Length)
-			out = append(out, string(b[:]))
-		}
-		return out
-	}
-
-	vectors := []struct {
-		input    []byte
-		wantMap  sparseDatas
-		wantSize int64
-		wantErr  error
-	}{{
-		input:   makeInput(FormatUnknown, ""),
-		wantErr: ErrHeader,
-	}, {
-		input:    makeInput(FormatGNU, "1234", "fewa"),
-		wantSize: 01234,
-		wantErr:  ErrHeader,
-	}, {
-		input:    makeInput(FormatGNU, "0031"),
-		wantSize: 031,
-	}, {
-		input:   makeInput(FormatGNU, "80"),
-		wantErr: ErrHeader,
-	}, {
-		input: makeInput(FormatGNU, "1234",
-			makeSparseStrings(sparseDatas{{0, 0}, {1, 1}})...),
-		wantMap:  sparseDatas{{0, 0}, {1, 1}},
-		wantSize: 01234,
-	}, {
-		input: makeInput(FormatGNU, "1234",
-			append(makeSparseStrings(sparseDatas{{0, 0}, {1, 1}}), []string{"", "blah"}...)...),
-		wantMap:  sparseDatas{{0, 0}, {1, 1}},
-		wantSize: 01234,
-	}, {
-		input: makeInput(FormatGNU, "3333",
-			makeSparseStrings(sparseDatas{{0, 1}, {2, 1}, {4, 1}, {6, 1}})...),
-		wantMap:  sparseDatas{{0, 1}, {2, 1}, {4, 1}, {6, 1}},
-		wantSize: 03333,
-	}, {
-		input: makeInput(FormatGNU, "",
-			append(append(
-				makeSparseStrings(sparseDatas{{0, 1}, {2, 1}}),
-				[]string{"", ""}...),
-				makeSparseStrings(sparseDatas{{4, 1}, {6, 1}})...)...),
-		wantMap: sparseDatas{{0, 1}, {2, 1}, {4, 1}, {6, 1}},
-	}, {
-		input: makeInput(FormatGNU, "",
-			makeSparseStrings(sparseDatas{{0, 1}, {2, 1}, {4, 1}, {6, 1}, {8, 1}, {10, 1}})...)[:blockSize],
-		wantErr: io.ErrUnexpectedEOF,
-	}, {
-		input: makeInput(FormatGNU, "",
-			makeSparseStrings(sparseDatas{{0, 1}, {2, 1}, {4, 1}, {6, 1}, {8, 1}, {10, 1}})...)[:3*blockSize/2],
-		wantErr: io.ErrUnexpectedEOF,
-	}, {
-		input: makeInput(FormatGNU, "",
-			makeSparseStrings(sparseDatas{{0, 1}, {2, 1}, {4, 1}, {6, 1}, {8, 1}, {10, 1}})...),
-		wantMap: sparseDatas{{0, 1}, {2, 1}, {4, 1}, {6, 1}, {8, 1}, {10, 1}},
-	}, {
-		input: makeInput(FormatGNU, "",
-			makeSparseStrings(sparseDatas{{10 << 30, 512}, {20 << 30, 512}})...),
-		wantMap: sparseDatas{{10 << 30, 512}, {20 << 30, 512}},
-	}}
-
-	for i, v := range vectors {
-		var blk block
-		var hdr Header
-		v.input = v.input[copy(blk[:], v.input):]
-		tr := Reader{r: bytes.NewReader(v.input)}
-		got, err := tr.readOldGNUSparseMap(&hdr, &blk)
-		if !equalSparseEntries(got, v.wantMap) {
-			t.Errorf("test %d, readOldGNUSparseMap(): got %v, want %v", i, got, v.wantMap)
-		}
-		if err != v.wantErr {
-			t.Errorf("test %d, readOldGNUSparseMap() = %v, want %v", i, err, v.wantErr)
-		}
-		if hdr.Size != v.wantSize {
-			t.Errorf("test %d, Header.Size = %d, want %d", i, hdr.Size, v.wantSize)
-		}
-	}
-}
-
-func TestReadGNUSparsePAXHeaders(t *testing.T) {
-	padInput := func(s string) string {
-		return s + string(zeroBlock[:blockPadding(int64(len(s)))])
-	}
-
-	vectors := []struct {
-		inputData string
-		inputHdrs map[string]string
-		wantMap   sparseDatas
-		wantSize  int64
-		wantName  string
-		wantErr   error
-	}{{
-		inputHdrs: nil,
-		wantErr:   nil,
-	}, {
-		inputHdrs: map[string]string{
-			paxGNUSparseNumBlocks: strconv.FormatInt(math.MaxInt64, 10),
-			paxGNUSparseMap:       "0,1,2,3",
-		},
-		wantErr: ErrHeader,
-	}, {
-		inputHdrs: map[string]string{
-			paxGNUSparseNumBlocks: "4\x00",
-			paxGNUSparseMap:       "0,1,2,3",
-		},
-		wantErr: ErrHeader,
-	}, {
-		inputHdrs: map[string]string{
-			paxGNUSparseNumBlocks: "4",
-			paxGNUSparseMap:       "0,1,2,3",
-		},
-		wantErr: ErrHeader,
-	}, {
-		inputHdrs: map[string]string{
-			paxGNUSparseNumBlocks: "2",
-			paxGNUSparseMap:       "0,1,2,3",
-		},
-		wantMap: sparseDatas{{0, 1}, {2, 3}},
-	}, {
-		inputHdrs: map[string]string{
-			paxGNUSparseNumBlocks: "2",
-			paxGNUSparseMap:       "0, 1,2,3",
-		},
-		wantErr: ErrHeader,
-	}, {
-		inputHdrs: map[string]string{
-			paxGNUSparseNumBlocks: "2",
-			paxGNUSparseMap:       "0,1,02,3",
-			paxGNUSparseRealSize:  "4321",
-		},
-		wantMap:  sparseDatas{{0, 1}, {2, 3}},
-		wantSize: 4321,
-	}, {
-		inputHdrs: map[string]string{
-			paxGNUSparseNumBlocks: "2",
-			paxGNUSparseMap:       "0,one1,2,3",
-		},
-		wantErr: ErrHeader,
-	}, {
-		inputHdrs: map[string]string{
-			paxGNUSparseMajor:     "0",
-			paxGNUSparseMinor:     "0",
-			paxGNUSparseNumBlocks: "2",
-			paxGNUSparseMap:       "0,1,2,3",
-			paxGNUSparseSize:      "1234",
-			paxGNUSparseRealSize:  "4321",
-			paxGNUSparseName:      "realname",
-		},
-		wantMap:  sparseDatas{{0, 1}, {2, 3}},
-		wantSize: 1234,
-		wantName: "realname",
-	}, {
-		inputHdrs: map[string]string{
-			paxGNUSparseMajor:     "0",
-			paxGNUSparseMinor:     "0",
-			paxGNUSparseNumBlocks: "1",
-			paxGNUSparseMap:       "10737418240,512",
-			paxGNUSparseSize:      "10737418240",
-			paxGNUSparseName:      "realname",
-		},
-		wantMap:  sparseDatas{{10737418240, 512}},
-		wantSize: 10737418240,
-		wantName: "realname",
-	}, {
-		inputHdrs: map[string]string{
-			paxGNUSparseMajor:     "0",
-			paxGNUSparseMinor:     "0",
-			paxGNUSparseNumBlocks: "0",
-			paxGNUSparseMap:       "",
-		},
-		wantMap: sparseDatas{},
-	}, {
-		inputHdrs: map[string]string{
-			paxGNUSparseMajor:     "0",
-			paxGNUSparseMinor:     "1",
-			paxGNUSparseNumBlocks: "4",
-			paxGNUSparseMap:       "0,5,10,5,20,5,30,5",
-		},
-		wantMap: sparseDatas{{0, 5}, {10, 5}, {20, 5}, {30, 5}},
-	}, {
-		inputHdrs: map[string]string{
-			paxGNUSparseMajor:     "1",
-			paxGNUSparseMinor:     "0",
-			paxGNUSparseNumBlocks: "4",
-			paxGNUSparseMap:       "0,5,10,5,20,5,30,5",
-		},
-		wantErr: io.ErrUnexpectedEOF,
-	}, {
-		inputData: padInput("0\n"),
-		inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"},
-		wantMap:   sparseDatas{},
-	}, {
-		inputData: padInput("0\n")[:blockSize-1] + "#",
-		inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"},
-		wantMap:   sparseDatas{},
-	}, {
-		inputData: padInput("0"),
-		inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"},
-		wantErr:   io.ErrUnexpectedEOF,
-	}, {
-		inputData: padInput("ab\n"),
-		inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"},
-		wantErr:   ErrHeader,
-	}, {
-		inputData: padInput("1\n2\n3\n"),
-		inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"},
-		wantMap:   sparseDatas{{2, 3}},
-	}, {
-		inputData: padInput("1\n2\n"),
-		inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"},
-		wantErr:   io.ErrUnexpectedEOF,
-	}, {
-		inputData: padInput("1\n2\n\n"),
-		inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"},
-		wantErr:   ErrHeader,
-	}, {
-		inputData: string(zeroBlock[:]) + padInput("0\n"),
-		inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"},
-		wantErr:   ErrHeader,
-	}, {
-		inputData: strings.Repeat("0", blockSize) + padInput("1\n5\n1\n"),
-		inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"},
-		wantMap:   sparseDatas{{5, 1}},
-	}, {
-		inputData: padInput(fmt.Sprintf("%d\n", int64(math.MaxInt64))),
-		inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"},
-		wantErr:   ErrHeader,
-	}, {
-		inputData: padInput(strings.Repeat("0", 300) + "1\n" + strings.Repeat("0", 1000) + "5\n" + strings.Repeat("0", 800) + "2\n"),
-		inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"},
-		wantMap:   sparseDatas{{5, 2}},
-	}, {
-		inputData: padInput("2\n10737418240\n512\n21474836480\n512\n"),
-		inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"},
-		wantMap:   sparseDatas{{10737418240, 512}, {21474836480, 512}},
-	}, {
-		inputData: padInput("100\n" + func() string {
-			var ss []string
-			for i := 0; i < 100; i++ {
-				ss = append(ss, fmt.Sprintf("%d\n%d\n", int64(i)<<30, 512))
-			}
-			return strings.Join(ss, "")
-		}()),
-		inputHdrs: map[string]string{paxGNUSparseMajor: "1", paxGNUSparseMinor: "0"},
-		wantMap: func() (spd sparseDatas) {
-			for i := 0; i < 100; i++ {
-				spd = append(spd, sparseEntry{int64(i) << 30, 512})
-			}
-			return spd
-		}(),
-	}}
-
-	for i, v := range vectors {
-		var hdr Header
-		hdr.PAXRecords = v.inputHdrs
-		r := strings.NewReader(v.inputData + "#") // Add canary byte
-		tr := Reader{curr: &regFileReader{r, int64(r.Len())}}
-		got, err := tr.readGNUSparsePAXHeaders(&hdr)
-		if !equalSparseEntries(got, v.wantMap) {
-			t.Errorf("test %d, readGNUSparsePAXHeaders(): got %v, want %v", i, got, v.wantMap)
-		}
-		if err != v.wantErr {
-			t.Errorf("test %d, readGNUSparsePAXHeaders() = %v, want %v", i, err, v.wantErr)
-		}
-		if hdr.Size != v.wantSize {
-			t.Errorf("test %d, Header.Size = %d, want %d", i, hdr.Size, v.wantSize)
-		}
-		if hdr.Name != v.wantName {
-			t.Errorf("test %d, Header.Name = %s, want %s", i, hdr.Name, v.wantName)
-		}
-		if v.wantErr == nil && r.Len() == 0 {
-			t.Errorf("test %d, canary byte unexpectedly consumed", i)
-		}
-	}
-}
-
-// testNonEmptyReader wraps an io.Reader and ensures that
-// Read is never called with an empty buffer.
-type testNonEmptyReader struct{ io.Reader }
-
-func (r testNonEmptyReader) Read(b []byte) (int, error) {
-	if len(b) == 0 {
-		return 0, errors.New("unexpected empty Read call")
-	}
-	return r.Reader.Read(b)
-}
-
-func TestFileReader(t *testing.T) {
-	type (
-		testRead struct { // Read(cnt) == (wantStr, wantErr)
-			cnt     int
-			wantStr string
-			wantErr error
-		}
-		testWriteTo struct { // WriteTo(testFile{ops}) == (wantCnt, wantErr)
-			ops     fileOps
-			wantCnt int64
-			wantErr error
-		}
-		testRemaining struct { // logicalRemaining() == wantLCnt, physicalRemaining() == wantPCnt
-			wantLCnt int64
-			wantPCnt int64
-		}
-		testFnc any // testRead | testWriteTo | testRemaining
-	)
-
-	type (
-		makeReg struct {
-			str  string
-			size int64
-		}
-		makeSparse struct {
-			makeReg makeReg
-			spd     sparseDatas
-			size    int64
-		}
-		fileMaker any // makeReg | makeSparse
-	)
-
-	vectors := []struct {
-		maker fileMaker
-		tests []testFnc
-	}{{
-		maker: makeReg{"", 0},
-		tests: []testFnc{
-			testRemaining{0, 0},
-			testRead{0, "", io.EOF},
-			testRead{1, "", io.EOF},
-			testWriteTo{nil, 0, nil},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeReg{"", 1},
-		tests: []testFnc{
-			testRemaining{1, 1},
-			testRead{5, "", io.ErrUnexpectedEOF},
-			testWriteTo{nil, 0, io.ErrUnexpectedEOF},
-			testRemaining{1, 1},
-		},
-	}, {
-		maker: makeReg{"hello", 5},
-		tests: []testFnc{
-			testRemaining{5, 5},
-			testRead{5, "hello", io.EOF},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeReg{"hello, world", 50},
-		tests: []testFnc{
-			testRemaining{50, 50},
-			testRead{7, "hello, ", nil},
-			testRemaining{43, 43},
-			testRead{5, "world", nil},
-			testRemaining{38, 38},
-			testWriteTo{nil, 0, io.ErrUnexpectedEOF},
-			testRead{1, "", io.ErrUnexpectedEOF},
-			testRemaining{38, 38},
-		},
-	}, {
-		maker: makeReg{"hello, world", 5},
-		tests: []testFnc{
-			testRemaining{5, 5},
-			testRead{0, "", nil},
-			testRead{4, "hell", nil},
-			testRemaining{1, 1},
-			testWriteTo{fileOps{"o"}, 1, nil},
-			testRemaining{0, 0},
-			testWriteTo{nil, 0, nil},
-			testRead{0, "", io.EOF},
-		},
-	}, {
-		maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{0, 2}, {5, 3}}, 8},
-		tests: []testFnc{
-			testRemaining{8, 5},
-			testRead{3, "ab\x00", nil},
-			testRead{10, "\x00\x00cde", io.EOF},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{0, 2}, {5, 3}}, 8},
-		tests: []testFnc{
-			testRemaining{8, 5},
-			testWriteTo{fileOps{"ab", int64(3), "cde"}, 8, nil},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{0, 2}, {5, 3}}, 10},
-		tests: []testFnc{
-			testRemaining{10, 5},
-			testRead{100, "ab\x00\x00\x00cde\x00\x00", io.EOF},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeSparse{makeReg{"abc", 5}, sparseDatas{{0, 2}, {5, 3}}, 10},
-		tests: []testFnc{
-			testRemaining{10, 5},
-			testRead{100, "ab\x00\x00\x00c", io.ErrUnexpectedEOF},
-			testRemaining{4, 2},
-		},
-	}, {
-		maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{1, 3}, {6, 2}}, 8},
-		tests: []testFnc{
-			testRemaining{8, 5},
-			testRead{8, "\x00abc\x00\x00de", io.EOF},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{1, 3}, {6, 0}, {6, 0}, {6, 2}}, 8},
-		tests: []testFnc{
-			testRemaining{8, 5},
-			testRead{8, "\x00abc\x00\x00de", io.EOF},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{1, 3}, {6, 0}, {6, 0}, {6, 2}}, 8},
-		tests: []testFnc{
-			testRemaining{8, 5},
-			testWriteTo{fileOps{int64(1), "abc", int64(2), "de"}, 8, nil},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{1, 3}, {6, 2}}, 10},
-		tests: []testFnc{
-			testRead{100, "\x00abc\x00\x00de\x00\x00", io.EOF},
-		},
-	}, {
-		maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{1, 3}, {6, 2}}, 10},
-		tests: []testFnc{
-			testWriteTo{fileOps{int64(1), "abc", int64(2), "de", int64(1), "\x00"}, 10, nil},
-		},
-	}, {
-		maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{1, 3}, {6, 2}, {8, 0}, {8, 0}, {8, 0}, {8, 0}}, 10},
-		tests: []testFnc{
-			testRead{100, "\x00abc\x00\x00de\x00\x00", io.EOF},
-		},
-	}, {
-		maker: makeSparse{makeReg{"", 0}, sparseDatas{}, 2},
-		tests: []testFnc{
-			testRead{100, "\x00\x00", io.EOF},
-		},
-	}, {
-		maker: makeSparse{makeReg{"", 8}, sparseDatas{{1, 3}, {6, 5}}, 15},
-		tests: []testFnc{
-			testRead{100, "\x00", io.ErrUnexpectedEOF},
-		},
-	}, {
-		maker: makeSparse{makeReg{"ab", 2}, sparseDatas{{1, 3}, {6, 5}}, 15},
-		tests: []testFnc{
-			testRead{100, "\x00ab", errMissData},
-		},
-	}, {
-		maker: makeSparse{makeReg{"ab", 8}, sparseDatas{{1, 3}, {6, 5}}, 15},
-		tests: []testFnc{
-			testRead{100, "\x00ab", io.ErrUnexpectedEOF},
-		},
-	}, {
-		maker: makeSparse{makeReg{"abc", 3}, sparseDatas{{1, 3}, {6, 5}}, 15},
-		tests: []testFnc{
-			testRead{100, "\x00abc\x00\x00", errMissData},
-		},
-	}, {
-		maker: makeSparse{makeReg{"abc", 8}, sparseDatas{{1, 3}, {6, 5}}, 15},
-		tests: []testFnc{
-			testRead{100, "\x00abc\x00\x00", io.ErrUnexpectedEOF},
-		},
-	}, {
-		maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{1, 3}, {6, 5}}, 15},
-		tests: []testFnc{
-			testRead{100, "\x00abc\x00\x00de", errMissData},
-		},
-	}, {
-		maker: makeSparse{makeReg{"abcde", 5}, sparseDatas{{1, 3}, {6, 5}}, 15},
-		tests: []testFnc{
-			testWriteTo{fileOps{int64(1), "abc", int64(2), "de"}, 8, errMissData},
-		},
-	}, {
-		maker: makeSparse{makeReg{"abcde", 8}, sparseDatas{{1, 3}, {6, 5}}, 15},
-		tests: []testFnc{
-			testRead{100, "\x00abc\x00\x00de", io.ErrUnexpectedEOF},
-		},
-	}, {
-		maker: makeSparse{makeReg{"abcdefghEXTRA", 13}, sparseDatas{{1, 3}, {6, 5}}, 15},
-		tests: []testFnc{
-			testRemaining{15, 13},
-			testRead{100, "\x00abc\x00\x00defgh\x00\x00\x00\x00", errUnrefData},
-			testWriteTo{nil, 0, errUnrefData},
-			testRemaining{0, 5},
-		},
-	}, {
-		maker: makeSparse{makeReg{"abcdefghEXTRA", 13}, sparseDatas{{1, 3}, {6, 5}}, 15},
-		tests: []testFnc{
-			testRemaining{15, 13},
-			testWriteTo{fileOps{int64(1), "abc", int64(2), "defgh", int64(4)}, 15, errUnrefData},
-			testRead{100, "", errUnrefData},
-			testRemaining{0, 5},
-		},
-	}}
-
-	for i, v := range vectors {
-		var fr fileReader
-		switch maker := v.maker.(type) {
-		case makeReg:
-			r := testNonEmptyReader{strings.NewReader(maker.str)}
-			fr = &regFileReader{r, maker.size}
-		case makeSparse:
-			if !validateSparseEntries(maker.spd, maker.size) {
-				t.Fatalf("invalid sparse map: %v", maker.spd)
-			}
-			sph := invertSparseEntries(maker.spd, maker.size)
-			r := testNonEmptyReader{strings.NewReader(maker.makeReg.str)}
-			fr = &regFileReader{r, maker.makeReg.size}
-			fr = &sparseFileReader{fr, sph, 0}
-		default:
-			t.Fatalf("test %d, unknown make operation: %T", i, maker)
-		}
-
-		for j, tf := range v.tests {
-			switch tf := tf.(type) {
-			case testRead:
-				b := make([]byte, tf.cnt)
-				n, err := fr.Read(b)
-				if got := string(b[:n]); got != tf.wantStr || err != tf.wantErr {
-					t.Errorf("test %d.%d, Read(%d):\ngot  (%q, %v)\nwant (%q, %v)", i, j, tf.cnt, got, err, tf.wantStr, tf.wantErr)
-				}
-			case testWriteTo:
-				f := &testFile{ops: tf.ops}
-				got, err := fr.WriteTo(f)
-				if _, ok := err.(testError); ok {
-					t.Errorf("test %d.%d, WriteTo(): %v", i, j, err)
-				} else if got != tf.wantCnt || err != tf.wantErr {
-					t.Errorf("test %d.%d, WriteTo() = (%d, %v), want (%d, %v)", i, j, got, err, tf.wantCnt, tf.wantErr)
-				}
-				if len(f.ops) > 0 {
-					t.Errorf("test %d.%d, expected %d more operations", i, j, len(f.ops))
-				}
-			case testRemaining:
-				if got := fr.logicalRemaining(); got != tf.wantLCnt {
-					t.Errorf("test %d.%d, logicalRemaining() = %d, want %d", i, j, got, tf.wantLCnt)
-				}
-				if got := fr.physicalRemaining(); got != tf.wantPCnt {
-					t.Errorf("test %d.%d, physicalRemaining() = %d, want %d", i, j, got, tf.wantPCnt)
-				}
-			default:
-				t.Fatalf("test %d.%d, unknown test operation: %T", i, j, tf)
-			}
-		}
-	}
-}
diff --git a/vendor/archive/tar/strconv_test.go b/vendor/archive/tar/strconv_test.go
deleted file mode 100644
index add65e272ae6d..0000000000000
--- a/vendor/archive/tar/strconv_test.go
+++ /dev/null
@@ -1,441 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tar
-
-import (
-	"math"
-	"strings"
-	"testing"
-	"time"
-)
-
-func TestFitsInBase256(t *testing.T) {
-	vectors := []struct {
-		in    int64
-		width int
-		ok    bool
-	}{
-		{+1, 8, true},
-		{0, 8, true},
-		{-1, 8, true},
-		{1 << 56, 8, false},
-		{(1 << 56) - 1, 8, true},
-		{-1 << 56, 8, true},
-		{(-1 << 56) - 1, 8, false},
-		{121654, 8, true},
-		{-9849849, 8, true},
-		{math.MaxInt64, 9, true},
-		{0, 9, true},
-		{math.MinInt64, 9, true},
-		{math.MaxInt64, 12, true},
-		{0, 12, true},
-		{math.MinInt64, 12, true},
-	}
-
-	for _, v := range vectors {
-		ok := fitsInBase256(v.width, v.in)
-		if ok != v.ok {
-			t.Errorf("fitsInBase256(%d, %d): got %v, want %v", v.in, v.width, ok, v.ok)
-		}
-	}
-}
-
-func TestParseNumeric(t *testing.T) {
-	vectors := []struct {
-		in   string
-		want int64
-		ok   bool
-	}{
-		// Test base-256 (binary) encoded values.
-		{"", 0, true},
-		{"\x80", 0, true},
-		{"\x80\x00", 0, true},
-		{"\x80\x00\x00", 0, true},
-		{"\xbf", (1 << 6) - 1, true},
-		{"\xbf\xff", (1 << 14) - 1, true},
-		{"\xbf\xff\xff", (1 << 22) - 1, true},
-		{"\xff", -1, true},
-		{"\xff\xff", -1, true},
-		{"\xff\xff\xff", -1, true},
-		{"\xc0", -1 * (1 << 6), true},
-		{"\xc0\x00", -1 * (1 << 14), true},
-		{"\xc0\x00\x00", -1 * (1 << 22), true},
-		{"\x87\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
-		{"\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
-		{"\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
-		{"\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
-		{"\x80\x7f\xff\xff\xff\xff\xff\xff\xff", math.MaxInt64, true},
-		{"\x80\x80\x00\x00\x00\x00\x00\x00\x00", 0, false},
-		{"\xff\x80\x00\x00\x00\x00\x00\x00\x00", math.MinInt64, true},
-		{"\xff\x7f\xff\xff\xff\xff\xff\xff\xff", 0, false},
-		{"\xf5\xec\xd1\xc7\x7e\x5f\x26\x48\x81\x9f\x8f\x9b", 0, false},
-
-		// Test base-8 (octal) encoded values.
-		{"0000000\x00", 0, true},
-		{" \x0000000\x00", 0, true},
-		{" \x0000003\x00", 3, true},
-		{"00000000227\x00", 0227, true},
-		{"032033\x00 ", 032033, true},
-		{"320330\x00 ", 0320330, true},
-		{"0000660\x00 ", 0660, true},
-		{"\x00 0000660\x00 ", 0660, true},
-		{"0123456789abcdef", 0, false},
-		{"0123456789\x00abcdef", 0, false},
-		{"01234567\x0089abcdef", 342391, true},
-		{"0123\x7e\x5f\x264123", 0, false},
-	}
-
-	for _, v := range vectors {
-		var p parser
-		got := p.parseNumeric([]byte(v.in))
-		ok := (p.err == nil)
-		if ok != v.ok {
-			if v.ok {
-				t.Errorf("parseNumeric(%q): got parsing failure, want success", v.in)
-			} else {
-				t.Errorf("parseNumeric(%q): got parsing success, want failure", v.in)
-			}
-		}
-		if ok && got != v.want {
-			t.Errorf("parseNumeric(%q): got %d, want %d", v.in, got, v.want)
-		}
-	}
-}
-
-func TestFormatNumeric(t *testing.T) {
-	vectors := []struct {
-		in   int64
-		want string
-		ok   bool
-	}{
-		// Test base-8 (octal) encoded values.
-		{0, "0\x00", true},
-		{7, "7\x00", true},
-		{8, "\x80\x08", true},
-		{077, "77\x00", true},
-		{0100, "\x80\x00\x40", true},
-		{0, "0000000\x00", true},
-		{0123, "0000123\x00", true},
-		{07654321, "7654321\x00", true},
-		{07777777, "7777777\x00", true},
-		{010000000, "\x80\x00\x00\x00\x00\x20\x00\x00", true},
-		{0, "00000000000\x00", true},
-		{000001234567, "00001234567\x00", true},
-		{076543210321, "76543210321\x00", true},
-		{012345670123, "12345670123\x00", true},
-		{077777777777, "77777777777\x00", true},
-		{0100000000000, "\x80\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00", true},
-		{math.MaxInt64, "777777777777777777777\x00", true},
-
-		// Test base-256 (binary) encoded values.
-		{-1, "\xff", true},
-		{-1, "\xff\xff", true},
-		{-1, "\xff\xff\xff", true},
-		{(1 << 0), "0", false},
-		{(1 << 8) - 1, "\x80\xff", true},
-		{(1 << 8), "0\x00", false},
-		{(1 << 16) - 1, "\x80\xff\xff", true},
-		{(1 << 16), "00\x00", false},
-		{-1 * (1 << 0), "\xff", true},
-		{-1*(1<<0) - 1, "0", false},
-		{-1 * (1 << 8), "\xff\x00", true},
-		{-1*(1<<8) - 1, "0\x00", false},
-		{-1 * (1 << 16), "\xff\x00\x00", true},
-		{-1*(1<<16) - 1, "00\x00", false},
-		{537795476381659745, "0000000\x00", false},
-		{537795476381659745, "\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", true},
-		{-615126028225187231, "0000000\x00", false},
-		{-615126028225187231, "\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", true},
-		{math.MaxInt64, "0000000\x00", false},
-		{math.MaxInt64, "\x80\x00\x00\x00\x7f\xff\xff\xff\xff\xff\xff\xff", true},
-		{math.MinInt64, "0000000\x00", false},
-		{math.MinInt64, "\xff\xff\xff\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
-		{math.MaxInt64, "\x80\x7f\xff\xff\xff\xff\xff\xff\xff", true},
-		{math.MinInt64, "\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
-	}
-
-	for _, v := range vectors {
-		var f formatter
-		got := make([]byte, len(v.want))
-		f.formatNumeric(got, v.in)
-		ok := (f.err == nil)
-		if ok != v.ok {
-			if v.ok {
-				t.Errorf("formatNumeric(%d): got formatting failure, want success", v.in)
-			} else {
-				t.Errorf("formatNumeric(%d): got formatting success, want failure", v.in)
-			}
-		}
-		if string(got) != v.want {
-			t.Errorf("formatNumeric(%d): got %q, want %q", v.in, got, v.want)
-		}
-	}
-}
-
-func TestFitsInOctal(t *testing.T) {
-	vectors := []struct {
-		input int64
-		width int
-		ok    bool
-	}{
-		{-1, 1, false},
-		{-1, 2, false},
-		{-1, 3, false},
-		{0, 1, true},
-		{0 + 1, 1, false},
-		{0, 2, true},
-		{07, 2, true},
-		{07 + 1, 2, false},
-		{0, 4, true},
-		{0777, 4, true},
-		{0777 + 1, 4, false},
-		{0, 8, true},
-		{07777777, 8, true},
-		{07777777 + 1, 8, false},
-		{0, 12, true},
-		{077777777777, 12, true},
-		{077777777777 + 1, 12, false},
-		{math.MaxInt64, 22, true},
-		{012345670123, 12, true},
-		{01564164, 12, true},
-		{-012345670123, 12, false},
-		{-01564164, 12, false},
-		{-1564164, 30, false},
-	}
-
-	for _, v := range vectors {
-		ok := fitsInOctal(v.width, v.input)
-		if ok != v.ok {
-			t.Errorf("checkOctal(%d, %d): got %v, want %v", v.input, v.width, ok, v.ok)
-		}
-	}
-}
-
-func TestParsePAXTime(t *testing.T) {
-	vectors := []struct {
-		in   string
-		want time.Time
-		ok   bool
-	}{
-		{"1350244992.023960108", time.Unix(1350244992, 23960108), true},
-		{"1350244992.02396010", time.Unix(1350244992, 23960100), true},
-		{"1350244992.0239601089", time.Unix(1350244992, 23960108), true},
-		{"1350244992.3", time.Unix(1350244992, 300000000), true},
-		{"1350244992", time.Unix(1350244992, 0), true},
-		{"-1.000000001", time.Unix(-1, -1e0+0e0), true},
-		{"-1.000001", time.Unix(-1, -1e3+0e0), true},
-		{"-1.001000", time.Unix(-1, -1e6+0e0), true},
-		{"-1", time.Unix(-1, -0e0+0e0), true},
-		{"-1.999000", time.Unix(-1, -1e9+1e6), true},
-		{"-1.999999", time.Unix(-1, -1e9+1e3), true},
-		{"-1.999999999", time.Unix(-1, -1e9+1e0), true},
-		{"0.000000001", time.Unix(0, 1e0+0e0), true},
-		{"0.000001", time.Unix(0, 1e3+0e0), true},
-		{"0.001000", time.Unix(0, 1e6+0e0), true},
-		{"0", time.Unix(0, 0e0), true},
-		{"0.999000", time.Unix(0, 1e9-1e6), true},
-		{"0.999999", time.Unix(0, 1e9-1e3), true},
-		{"0.999999999", time.Unix(0, 1e9-1e0), true},
-		{"1.000000001", time.Unix(+1, +1e0-0e0), true},
-		{"1.000001", time.Unix(+1, +1e3-0e0), true},
-		{"1.001000", time.Unix(+1, +1e6-0e0), true},
-		{"1", time.Unix(+1, +0e0-0e0), true},
-		{"1.999000", time.Unix(+1, +1e9-1e6), true},
-		{"1.999999", time.Unix(+1, +1e9-1e3), true},
-		{"1.999999999", time.Unix(+1, +1e9-1e0), true},
-		{"-1350244992.023960108", time.Unix(-1350244992, -23960108), true},
-		{"-1350244992.02396010", time.Unix(-1350244992, -23960100), true},
-		{"-1350244992.0239601089", time.Unix(-1350244992, -23960108), true},
-		{"-1350244992.3", time.Unix(-1350244992, -300000000), true},
-		{"-1350244992", time.Unix(-1350244992, 0), true},
-		{"", time.Time{}, false},
-		{"0", time.Unix(0, 0), true},
-		{"1.", time.Unix(1, 0), true},
-		{"0.0", time.Unix(0, 0), true},
-		{".5", time.Time{}, false},
-		{"-1.3", time.Unix(-1, -3e8), true},
-		{"-1.0", time.Unix(-1, -0e0), true},
-		{"-0.0", time.Unix(-0, -0e0), true},
-		{"-0.1", time.Unix(-0, -1e8), true},
-		{"-0.01", time.Unix(-0, -1e7), true},
-		{"-0.99", time.Unix(-0, -99e7), true},
-		{"-0.98", time.Unix(-0, -98e7), true},
-		{"-1.1", time.Unix(-1, -1e8), true},
-		{"-1.01", time.Unix(-1, -1e7), true},
-		{"-2.99", time.Unix(-2, -99e7), true},
-		{"-5.98", time.Unix(-5, -98e7), true},
-		{"-", time.Time{}, false},
-		{"+", time.Time{}, false},
-		{"-1.-1", time.Time{}, false},
-		{"99999999999999999999999999999999999999999999999", time.Time{}, false},
-		{"0.123456789abcdef", time.Time{}, false},
-		{"foo", time.Time{}, false},
-		{"\x00", time.Time{}, false},
-		{"𝟵𝟴𝟳𝟲𝟱.𝟰𝟯𝟮𝟭𝟬", time.Time{}, false}, // Unicode numbers (U+1D7EC to U+1D7F5)
-		{"98765﹒43210", time.Time{}, false}, // Unicode period (U+FE52)
-	}
-
-	for _, v := range vectors {
-		ts, err := parsePAXTime(v.in)
-		ok := (err == nil)
-		if v.ok != ok {
-			if v.ok {
-				t.Errorf("parsePAXTime(%q): got parsing failure, want success", v.in)
-			} else {
-				t.Errorf("parsePAXTime(%q): got parsing success, want failure", v.in)
-			}
-		}
-		if ok && !ts.Equal(v.want) {
-			t.Errorf("parsePAXTime(%q): got (%ds %dns), want (%ds %dns)",
-				v.in, ts.Unix(), ts.Nanosecond(), v.want.Unix(), v.want.Nanosecond())
-		}
-	}
-}
-
-func TestFormatPAXTime(t *testing.T) {
-	vectors := []struct {
-		sec, nsec int64
-		want      string
-	}{
-		{1350244992, 0, "1350244992"},
-		{1350244992, 300000000, "1350244992.3"},
-		{1350244992, 23960100, "1350244992.0239601"},
-		{1350244992, 23960108, "1350244992.023960108"},
-		{+1, +1e9 - 1e0, "1.999999999"},
-		{+1, +1e9 - 1e3, "1.999999"},
-		{+1, +1e9 - 1e6, "1.999"},
-		{+1, +0e0 - 0e0, "1"},
-		{+1, +1e6 - 0e0, "1.001"},
-		{+1, +1e3 - 0e0, "1.000001"},
-		{+1, +1e0 - 0e0, "1.000000001"},
-		{0, 1e9 - 1e0, "0.999999999"},
-		{0, 1e9 - 1e3, "0.999999"},
-		{0, 1e9 - 1e6, "0.999"},
-		{0, 0e0, "0"},
-		{0, 1e6 + 0e0, "0.001"},
-		{0, 1e3 + 0e0, "0.000001"},
-		{0, 1e0 + 0e0, "0.000000001"},
-		{-1, -1e9 + 1e0, "-1.999999999"},
-		{-1, -1e9 + 1e3, "-1.999999"},
-		{-1, -1e9 + 1e6, "-1.999"},
-		{-1, -0e0 + 0e0, "-1"},
-		{-1, -1e6 + 0e0, "-1.001"},
-		{-1, -1e3 + 0e0, "-1.000001"},
-		{-1, -1e0 + 0e0, "-1.000000001"},
-		{-1350244992, 0, "-1350244992"},
-		{-1350244992, -300000000, "-1350244992.3"},
-		{-1350244992, -23960100, "-1350244992.0239601"},
-		{-1350244992, -23960108, "-1350244992.023960108"},
-	}
-
-	for _, v := range vectors {
-		got := formatPAXTime(time.Unix(v.sec, v.nsec))
-		if got != v.want {
-			t.Errorf("formatPAXTime(%ds, %dns): got %q, want %q",
-				v.sec, v.nsec, got, v.want)
-		}
-	}
-}
-
-func TestParsePAXRecord(t *testing.T) {
-	medName := strings.Repeat("CD", 50)
-	longName := strings.Repeat("AB", 100)
-
-	vectors := []struct {
-		in      string
-		wantRes string
-		wantKey string
-		wantVal string
-		ok      bool
-	}{
-		{"6 k=v\n\n", "\n", "k", "v", true},
-		{"19 path=/etc/hosts\n", "", "path", "/etc/hosts", true},
-		{"210 path=" + longName + "\nabc", "abc", "path", longName, true},
-		{"110 path=" + medName + "\n", "", "path", medName, true},
-		{"9 foo=ba\n", "", "foo", "ba", true},
-		{"11 foo=bar\n\x00", "\x00", "foo", "bar", true},
-		{"18 foo=b=\nar=\n==\x00\n", "", "foo", "b=\nar=\n==\x00", true},
-		{"27 foo=hello9 foo=ba\nworld\n", "", "foo", "hello9 foo=ba\nworld", true},
-		{"27 ☺☻☹=日a本b語ç\nmeow mix", "meow mix", "☺☻☹", "日a本b語ç", true},
-		{"17 \x00hello=\x00world\n", "17 \x00hello=\x00world\n", "", "", false},
-		{"1 k=1\n", "1 k=1\n", "", "", false},
-		{"6 k~1\n", "6 k~1\n", "", "", false},
-		{"6_k=1\n", "6_k=1\n", "", "", false},
-		{"6 k=1 ", "6 k=1 ", "", "", false},
-		{"632 k=1\n", "632 k=1\n", "", "", false},
-		{"16 longkeyname=hahaha\n", "16 longkeyname=hahaha\n", "", "", false},
-		{"3 somelongkey=\n", "3 somelongkey=\n", "", "", false},
-		{"50 tooshort=\n", "50 tooshort=\n", "", "", false},
-		{"0000000000000000000000000000000030 mtime=1432668921.098285006\n30 ctime=2147483649.15163319", "0000000000000000000000000000000030 mtime=1432668921.098285006\n30 ctime=2147483649.15163319", "mtime", "1432668921.098285006", false},
-		{"06 k=v\n", "06 k=v\n", "", "", false},
-		{"00006 k=v\n", "00006 k=v\n", "", "", false},
-		{"000006 k=v\n", "000006 k=v\n", "", "", false},
-		{"000000 k=v\n", "000000 k=v\n", "", "", false},
-		{"0 k=v\n", "0 k=v\n", "", "", false},
-		{"+0000005 x=\n", "+0000005 x=\n", "", "", false},
-	}
-
-	for _, v := range vectors {
-		key, val, res, err := parsePAXRecord(v.in)
-		ok := (err == nil)
-		if ok != v.ok {
-			if v.ok {
-				t.Errorf("parsePAXRecord(%q): got parsing failure, want success", v.in)
-			} else {
-				t.Errorf("parsePAXRecord(%q): got parsing success, want failure", v.in)
-			}
-		}
-		if v.ok && (key != v.wantKey || val != v.wantVal) {
-			t.Errorf("parsePAXRecord(%q): got (%q: %q), want (%q: %q)",
-				v.in, key, val, v.wantKey, v.wantVal)
-		}
-		if res != v.wantRes {
-			t.Errorf("parsePAXRecord(%q): got residual %q, want residual %q",
-				v.in, res, v.wantRes)
-		}
-	}
-}
-
-func TestFormatPAXRecord(t *testing.T) {
-	medName := strings.Repeat("CD", 50)
-	longName := strings.Repeat("AB", 100)
-
-	vectors := []struct {
-		inKey string
-		inVal string
-		want  string
-		ok    bool
-	}{
-		{"k", "v", "6 k=v\n", true},
-		{"path", "/etc/hosts", "19 path=/etc/hosts\n", true},
-		{"path", longName, "210 path=" + longName + "\n", true},
-		{"path", medName, "110 path=" + medName + "\n", true},
-		{"foo", "ba", "9 foo=ba\n", true},
-		{"foo", "bar", "11 foo=bar\n", true},
-		{"foo", "b=\nar=\n==\x00", "18 foo=b=\nar=\n==\x00\n", true},
-		{"foo", "hello9 foo=ba\nworld", "27 foo=hello9 foo=ba\nworld\n", true},
-		{"☺☻☹", "日a本b語ç", "27 ☺☻☹=日a本b語ç\n", true},
-		{"xhello", "\x00world", "17 xhello=\x00world\n", true},
-		{"path", "null\x00", "", false},
-		{"null\x00", "value", "", false},
-		{paxSchilyXattr + "key", "null\x00", "26 SCHILY.xattr.key=null\x00\n", true},
-	}
-
-	for _, v := range vectors {
-		got, err := formatPAXRecord(v.inKey, v.inVal)
-		ok := (err == nil)
-		if ok != v.ok {
-			if v.ok {
-				t.Errorf("formatPAXRecord(%q, %q): got format failure, want success", v.inKey, v.inVal)
-			} else {
-				t.Errorf("formatPAXRecord(%q, %q): got format success, want failure", v.inKey, v.inVal)
-			}
-		}
-		if got != v.want {
-			t.Errorf("formatPAXRecord(%q, %q): got %q, want %q",
-				v.inKey, v.inVal, got, v.want)
-		}
-	}
-}
diff --git a/vendor/archive/tar/tar_test.go b/vendor/archive/tar/tar_test.go
deleted file mode 100644
index a476f5eb010f2..0000000000000
--- a/vendor/archive/tar/tar_test.go
+++ /dev/null
@@ -1,850 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tar
-
-import (
-	"bytes"
-	"errors"
-	"fmt"
-	"internal/testenv"
-	"io"
-	"io/fs"
-	"math"
-	"os"
-	"path"
-	"path/filepath"
-	"reflect"
-	"strings"
-	"testing"
-	"time"
-)
-
-type testError struct{ error }
-
-type fileOps []any // []T where T is (string | int64)
-
-// testFile is an io.ReadWriteSeeker where the IO operations performed
-// on it must match the list of operations in ops.
-type testFile struct {
-	ops fileOps
-	pos int64
-}
-
-func (f *testFile) Read(b []byte) (int, error) {
-	if len(b) == 0 {
-		return 0, nil
-	}
-	if len(f.ops) == 0 {
-		return 0, io.EOF
-	}
-	s, ok := f.ops[0].(string)
-	if !ok {
-		return 0, errors.New("unexpected Read operation")
-	}
-
-	n := copy(b, s)
-	if len(s) > n {
-		f.ops[0] = s[n:]
-	} else {
-		f.ops = f.ops[1:]
-	}
-	f.pos += int64(len(b))
-	return n, nil
-}
-
-func (f *testFile) Write(b []byte) (int, error) {
-	if len(b) == 0 {
-		return 0, nil
-	}
-	if len(f.ops) == 0 {
-		return 0, errors.New("unexpected Write operation")
-	}
-	s, ok := f.ops[0].(string)
-	if !ok {
-		return 0, errors.New("unexpected Write operation")
-	}
-
-	if !strings.HasPrefix(s, string(b)) {
-		return 0, testError{fmt.Errorf("got Write(%q), want Write(%q)", b, s)}
-	}
-	if len(s) > len(b) {
-		f.ops[0] = s[len(b):]
-	} else {
-		f.ops = f.ops[1:]
-	}
-	f.pos += int64(len(b))
-	return len(b), nil
-}
-
-func (f *testFile) Seek(pos int64, whence int) (int64, error) {
-	if pos == 0 && whence == io.SeekCurrent {
-		return f.pos, nil
-	}
-	if len(f.ops) == 0 {
-		return 0, errors.New("unexpected Seek operation")
-	}
-	s, ok := f.ops[0].(int64)
-	if !ok {
-		return 0, errors.New("unexpected Seek operation")
-	}
-
-	if s != pos || whence != io.SeekCurrent {
-		return 0, testError{fmt.Errorf("got Seek(%d, %d), want Seek(%d, %d)", pos, whence, s, io.SeekCurrent)}
-	}
-	f.pos += s
-	f.ops = f.ops[1:]
-	return f.pos, nil
-}
-
-func equalSparseEntries(x, y []sparseEntry) bool {
-	return (len(x) == 0 && len(y) == 0) || reflect.DeepEqual(x, y)
-}
-
-func TestSparseEntries(t *testing.T) {
-	vectors := []struct {
-		in   []sparseEntry
-		size int64
-
-		wantValid    bool          // Result of validateSparseEntries
-		wantAligned  []sparseEntry // Result of alignSparseEntries
-		wantInverted []sparseEntry // Result of invertSparseEntries
-	}{{
-		in: []sparseEntry{}, size: 0,
-		wantValid:    true,
-		wantInverted: []sparseEntry{{0, 0}},
-	}, {
-		in: []sparseEntry{}, size: 5000,
-		wantValid:    true,
-		wantInverted: []sparseEntry{{0, 5000}},
-	}, {
-		in: []sparseEntry{{0, 5000}}, size: 5000,
-		wantValid:    true,
-		wantAligned:  []sparseEntry{{0, 5000}},
-		wantInverted: []sparseEntry{{5000, 0}},
-	}, {
-		in: []sparseEntry{{1000, 4000}}, size: 5000,
-		wantValid:    true,
-		wantAligned:  []sparseEntry{{1024, 3976}},
-		wantInverted: []sparseEntry{{0, 1000}, {5000, 0}},
-	}, {
-		in: []sparseEntry{{0, 3000}}, size: 5000,
-		wantValid:    true,
-		wantAligned:  []sparseEntry{{0, 2560}},
-		wantInverted: []sparseEntry{{3000, 2000}},
-	}, {
-		in: []sparseEntry{{3000, 2000}}, size: 5000,
-		wantValid:    true,
-		wantAligned:  []sparseEntry{{3072, 1928}},
-		wantInverted: []sparseEntry{{0, 3000}, {5000, 0}},
-	}, {
-		in: []sparseEntry{{2000, 2000}}, size: 5000,
-		wantValid:    true,
-		wantAligned:  []sparseEntry{{2048, 1536}},
-		wantInverted: []sparseEntry{{0, 2000}, {4000, 1000}},
-	}, {
-		in: []sparseEntry{{0, 2000}, {8000, 2000}}, size: 10000,
-		wantValid:    true,
-		wantAligned:  []sparseEntry{{0, 1536}, {8192, 1808}},
-		wantInverted: []sparseEntry{{2000, 6000}, {10000, 0}},
-	}, {
-		in: []sparseEntry{{0, 2000}, {2000, 2000}, {4000, 0}, {4000, 3000}, {7000, 1000}, {8000, 0}, {8000, 2000}}, size: 10000,
-		wantValid:    true,
-		wantAligned:  []sparseEntry{{0, 1536}, {2048, 1536}, {4096, 2560}, {7168, 512}, {8192, 1808}},
-		wantInverted: []sparseEntry{{10000, 0}},
-	}, {
-		in: []sparseEntry{{0, 0}, {1000, 0}, {2000, 0}, {3000, 0}, {4000, 0}, {5000, 0}}, size: 5000,
-		wantValid:    true,
-		wantInverted: []sparseEntry{{0, 5000}},
-	}, {
-		in: []sparseEntry{{1, 0}}, size: 0,
-		wantValid: false,
-	}, {
-		in: []sparseEntry{{-1, 0}}, size: 100,
-		wantValid: false,
-	}, {
-		in: []sparseEntry{{0, -1}}, size: 100,
-		wantValid: false,
-	}, {
-		in: []sparseEntry{{0, 0}}, size: -100,
-		wantValid: false,
-	}, {
-		in: []sparseEntry{{math.MaxInt64, 3}, {6, -5}}, size: 35,
-		wantValid: false,
-	}, {
-		in: []sparseEntry{{1, 3}, {6, -5}}, size: 35,
-		wantValid: false,
-	}, {
-		in: []sparseEntry{{math.MaxInt64, math.MaxInt64}}, size: math.MaxInt64,
-		wantValid: false,
-	}, {
-		in: []sparseEntry{{3, 3}}, size: 5,
-		wantValid: false,
-	}, {
-		in: []sparseEntry{{2, 0}, {1, 0}, {0, 0}}, size: 3,
-		wantValid: false,
-	}, {
-		in: []sparseEntry{{1, 3}, {2, 2}}, size: 10,
-		wantValid: false,
-	}}
-
-	for i, v := range vectors {
-		gotValid := validateSparseEntries(v.in, v.size)
-		if gotValid != v.wantValid {
-			t.Errorf("test %d, validateSparseEntries() = %v, want %v", i, gotValid, v.wantValid)
-		}
-		if !v.wantValid {
-			continue
-		}
-		gotAligned := alignSparseEntries(append([]sparseEntry{}, v.in...), v.size)
-		if !equalSparseEntries(gotAligned, v.wantAligned) {
-			t.Errorf("test %d, alignSparseEntries():\ngot  %v\nwant %v", i, gotAligned, v.wantAligned)
-		}
-		gotInverted := invertSparseEntries(append([]sparseEntry{}, v.in...), v.size)
-		if !equalSparseEntries(gotInverted, v.wantInverted) {
-			t.Errorf("test %d, inverseSparseEntries():\ngot  %v\nwant %v", i, gotInverted, v.wantInverted)
-		}
-	}
-}
-
-func TestFileInfoHeader(t *testing.T) {
-	fi, err := os.Stat("testdata/small.txt")
-	if err != nil {
-		t.Fatal(err)
-	}
-	h, err := FileInfoHeader(fi, "")
-	if err != nil {
-		t.Fatalf("FileInfoHeader: %v", err)
-	}
-	if g, e := h.Name, "small.txt"; g != e {
-		t.Errorf("Name = %q; want %q", g, e)
-	}
-	if g, e := h.Mode, int64(fi.Mode().Perm()); g != e {
-		t.Errorf("Mode = %#o; want %#o", g, e)
-	}
-	if g, e := h.Size, int64(5); g != e {
-		t.Errorf("Size = %v; want %v", g, e)
-	}
-	if g, e := h.ModTime, fi.ModTime(); !g.Equal(e) {
-		t.Errorf("ModTime = %v; want %v", g, e)
-	}
-	// FileInfoHeader should error when passing nil FileInfo
-	if _, err := FileInfoHeader(nil, ""); err == nil {
-		t.Fatalf("Expected error when passing nil to FileInfoHeader")
-	}
-}
-
-func TestFileInfoHeaderDir(t *testing.T) {
-	fi, err := os.Stat("testdata")
-	if err != nil {
-		t.Fatal(err)
-	}
-	h, err := FileInfoHeader(fi, "")
-	if err != nil {
-		t.Fatalf("FileInfoHeader: %v", err)
-	}
-	if g, e := h.Name, "testdata/"; g != e {
-		t.Errorf("Name = %q; want %q", g, e)
-	}
-	// Ignoring c_ISGID for golang.org/issue/4867
-	if g, e := h.Mode&^c_ISGID, int64(fi.Mode().Perm()); g != e {
-		t.Errorf("Mode = %#o; want %#o", g, e)
-	}
-	if g, e := h.Size, int64(0); g != e {
-		t.Errorf("Size = %v; want %v", g, e)
-	}
-	if g, e := h.ModTime, fi.ModTime(); !g.Equal(e) {
-		t.Errorf("ModTime = %v; want %v", g, e)
-	}
-}
-
-func TestFileInfoHeaderSymlink(t *testing.T) {
-	testenv.MustHaveSymlink(t)
-
-	tmpdir := t.TempDir()
-
-	link := filepath.Join(tmpdir, "link")
-	target := tmpdir
-	if err := os.Symlink(target, link); err != nil {
-		t.Fatal(err)
-	}
-	fi, err := os.Lstat(link)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	h, err := FileInfoHeader(fi, target)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if g, e := h.Name, fi.Name(); g != e {
-		t.Errorf("Name = %q; want %q", g, e)
-	}
-	if g, e := h.Linkname, target; g != e {
-		t.Errorf("Linkname = %q; want %q", g, e)
-	}
-	if g, e := h.Typeflag, byte(TypeSymlink); g != e {
-		t.Errorf("Typeflag = %v; want %v", g, e)
-	}
-}
-
-func TestRoundTrip(t *testing.T) {
-	data := []byte("some file contents")
-
-	var b bytes.Buffer
-	tw := NewWriter(&b)
-	hdr := &Header{
-		Name:       "file.txt",
-		Uid:        1 << 21, // Too big for 8 octal digits
-		Size:       int64(len(data)),
-		ModTime:    time.Now().Round(time.Second),
-		PAXRecords: map[string]string{"uid": "2097152"},
-		Format:     FormatPAX,
-		Typeflag:   TypeReg,
-	}
-	if err := tw.WriteHeader(hdr); err != nil {
-		t.Fatalf("tw.WriteHeader: %v", err)
-	}
-	if _, err := tw.Write(data); err != nil {
-		t.Fatalf("tw.Write: %v", err)
-	}
-	if err := tw.Close(); err != nil {
-		t.Fatalf("tw.Close: %v", err)
-	}
-
-	// Read it back.
-	tr := NewReader(&b)
-	rHdr, err := tr.Next()
-	if err != nil {
-		t.Fatalf("tr.Next: %v", err)
-	}
-	if !reflect.DeepEqual(rHdr, hdr) {
-		t.Errorf("Header mismatch.\n got %+v\nwant %+v", rHdr, hdr)
-	}
-	rData, err := io.ReadAll(tr)
-	if err != nil {
-		t.Fatalf("Read: %v", err)
-	}
-	if !bytes.Equal(rData, data) {
-		t.Errorf("Data mismatch.\n got %q\nwant %q", rData, data)
-	}
-}
-
-type headerRoundTripTest struct {
-	h  *Header
-	fm fs.FileMode
-}
-
-func TestHeaderRoundTrip(t *testing.T) {
-	vectors := []headerRoundTripTest{{
-		// regular file.
-		h: &Header{
-			Name:     "test.txt",
-			Mode:     0644,
-			Size:     12,
-			ModTime:  time.Unix(1360600916, 0),
-			Typeflag: TypeReg,
-		},
-		fm: 0644,
-	}, {
-		// symbolic link.
-		h: &Header{
-			Name:     "link.txt",
-			Mode:     0777,
-			Size:     0,
-			ModTime:  time.Unix(1360600852, 0),
-			Typeflag: TypeSymlink,
-		},
-		fm: 0777 | fs.ModeSymlink,
-	}, {
-		// character device node.
-		h: &Header{
-			Name:     "dev/null",
-			Mode:     0666,
-			Size:     0,
-			ModTime:  time.Unix(1360578951, 0),
-			Typeflag: TypeChar,
-		},
-		fm: 0666 | fs.ModeDevice | fs.ModeCharDevice,
-	}, {
-		// block device node.
-		h: &Header{
-			Name:     "dev/sda",
-			Mode:     0660,
-			Size:     0,
-			ModTime:  time.Unix(1360578954, 0),
-			Typeflag: TypeBlock,
-		},
-		fm: 0660 | fs.ModeDevice,
-	}, {
-		// directory.
-		h: &Header{
-			Name:     "dir/",
-			Mode:     0755,
-			Size:     0,
-			ModTime:  time.Unix(1360601116, 0),
-			Typeflag: TypeDir,
-		},
-		fm: 0755 | fs.ModeDir,
-	}, {
-		// fifo node.
-		h: &Header{
-			Name:     "dev/initctl",
-			Mode:     0600,
-			Size:     0,
-			ModTime:  time.Unix(1360578949, 0),
-			Typeflag: TypeFifo,
-		},
-		fm: 0600 | fs.ModeNamedPipe,
-	}, {
-		// setuid.
-		h: &Header{
-			Name:     "bin/su",
-			Mode:     0755 | c_ISUID,
-			Size:     23232,
-			ModTime:  time.Unix(1355405093, 0),
-			Typeflag: TypeReg,
-		},
-		fm: 0755 | fs.ModeSetuid,
-	}, {
-		// setguid.
-		h: &Header{
-			Name:     "group.txt",
-			Mode:     0750 | c_ISGID,
-			Size:     0,
-			ModTime:  time.Unix(1360602346, 0),
-			Typeflag: TypeReg,
-		},
-		fm: 0750 | fs.ModeSetgid,
-	}, {
-		// sticky.
-		h: &Header{
-			Name:     "sticky.txt",
-			Mode:     0600 | c_ISVTX,
-			Size:     7,
-			ModTime:  time.Unix(1360602540, 0),
-			Typeflag: TypeReg,
-		},
-		fm: 0600 | fs.ModeSticky,
-	}, {
-		// hard link.
-		h: &Header{
-			Name:     "hard.txt",
-			Mode:     0644,
-			Size:     0,
-			Linkname: "file.txt",
-			ModTime:  time.Unix(1360600916, 0),
-			Typeflag: TypeLink,
-		},
-		fm: 0644,
-	}, {
-		// More information.
-		h: &Header{
-			Name:     "info.txt",
-			Mode:     0600,
-			Size:     0,
-			Uid:      1000,
-			Gid:      1000,
-			ModTime:  time.Unix(1360602540, 0),
-			Uname:    "slartibartfast",
-			Gname:    "users",
-			Typeflag: TypeReg,
-		},
-		fm: 0600,
-	}}
-
-	for i, v := range vectors {
-		fi := v.h.FileInfo()
-		h2, err := FileInfoHeader(fi, "")
-		if err != nil {
-			t.Error(err)
-			continue
-		}
-		if strings.Contains(fi.Name(), "/") {
-			t.Errorf("FileInfo of %q contains slash: %q", v.h.Name, fi.Name())
-		}
-		name := path.Base(v.h.Name)
-		if fi.IsDir() {
-			name += "/"
-		}
-		if got, want := h2.Name, name; got != want {
-			t.Errorf("i=%d: Name: got %v, want %v", i, got, want)
-		}
-		if got, want := h2.Size, v.h.Size; got != want {
-			t.Errorf("i=%d: Size: got %v, want %v", i, got, want)
-		}
-		if got, want := h2.Uid, v.h.Uid; got != want {
-			t.Errorf("i=%d: Uid: got %d, want %d", i, got, want)
-		}
-		if got, want := h2.Gid, v.h.Gid; got != want {
-			t.Errorf("i=%d: Gid: got %d, want %d", i, got, want)
-		}
-		if got, want := h2.Uname, v.h.Uname; got != want {
-			t.Errorf("i=%d: Uname: got %q, want %q", i, got, want)
-		}
-		if got, want := h2.Gname, v.h.Gname; got != want {
-			t.Errorf("i=%d: Gname: got %q, want %q", i, got, want)
-		}
-		if got, want := h2.Linkname, v.h.Linkname; got != want {
-			t.Errorf("i=%d: Linkname: got %v, want %v", i, got, want)
-		}
-		if got, want := h2.Typeflag, v.h.Typeflag; got != want {
-			t.Logf("%#v %#v", v.h, fi.Sys())
-			t.Errorf("i=%d: Typeflag: got %q, want %q", i, got, want)
-		}
-		if got, want := h2.Mode, v.h.Mode; got != want {
-			t.Errorf("i=%d: Mode: got %o, want %o", i, got, want)
-		}
-		if got, want := fi.Mode(), v.fm; got != want {
-			t.Errorf("i=%d: fi.Mode: got %o, want %o", i, got, want)
-		}
-		if got, want := h2.AccessTime, v.h.AccessTime; got != want {
-			t.Errorf("i=%d: AccessTime: got %v, want %v", i, got, want)
-		}
-		if got, want := h2.ChangeTime, v.h.ChangeTime; got != want {
-			t.Errorf("i=%d: ChangeTime: got %v, want %v", i, got, want)
-		}
-		if got, want := h2.ModTime, v.h.ModTime; got != want {
-			t.Errorf("i=%d: ModTime: got %v, want %v", i, got, want)
-		}
-		if sysh, ok := fi.Sys().(*Header); !ok || sysh != v.h {
-			t.Errorf("i=%d: Sys didn't return original *Header", i)
-		}
-	}
-}
-
-func TestHeaderAllowedFormats(t *testing.T) {
-	vectors := []struct {
-		header  *Header           // Input header
-		paxHdrs map[string]string // Expected PAX headers that may be needed
-		formats Format            // Expected formats that can encode the header
-	}{{
-		header:  &Header{},
-		formats: FormatUSTAR | FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{Size: 077777777777},
-		formats: FormatUSTAR | FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{Size: 077777777777, Format: FormatUSTAR},
-		formats: FormatUSTAR,
-	}, {
-		header:  &Header{Size: 077777777777, Format: FormatPAX},
-		formats: FormatUSTAR | FormatPAX,
-	}, {
-		header:  &Header{Size: 077777777777, Format: FormatGNU},
-		formats: FormatGNU,
-	}, {
-		header:  &Header{Size: 077777777777 + 1},
-		paxHdrs: map[string]string{paxSize: "8589934592"},
-		formats: FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{Size: 077777777777 + 1, Format: FormatPAX},
-		paxHdrs: map[string]string{paxSize: "8589934592"},
-		formats: FormatPAX,
-	}, {
-		header:  &Header{Size: 077777777777 + 1, Format: FormatGNU},
-		paxHdrs: map[string]string{paxSize: "8589934592"},
-		formats: FormatGNU,
-	}, {
-		header:  &Header{Mode: 07777777},
-		formats: FormatUSTAR | FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{Mode: 07777777 + 1},
-		formats: FormatGNU,
-	}, {
-		header:  &Header{Devmajor: -123},
-		formats: FormatGNU,
-	}, {
-		header:  &Header{Devmajor: 1<<56 - 1},
-		formats: FormatGNU,
-	}, {
-		header:  &Header{Devmajor: 1 << 56},
-		formats: FormatUnknown,
-	}, {
-		header:  &Header{Devmajor: -1 << 56},
-		formats: FormatGNU,
-	}, {
-		header:  &Header{Devmajor: -1<<56 - 1},
-		formats: FormatUnknown,
-	}, {
-		header:  &Header{Name: "用戶名", Devmajor: -1 << 56},
-		formats: FormatGNU,
-	}, {
-		header:  &Header{Size: math.MaxInt64},
-		paxHdrs: map[string]string{paxSize: "9223372036854775807"},
-		formats: FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{Size: math.MinInt64},
-		paxHdrs: map[string]string{paxSize: "-9223372036854775808"},
-		formats: FormatUnknown,
-	}, {
-		header:  &Header{Uname: "0123456789abcdef0123456789abcdef"},
-		formats: FormatUSTAR | FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{Uname: "0123456789abcdef0123456789abcdefx"},
-		paxHdrs: map[string]string{paxUname: "0123456789abcdef0123456789abcdefx"},
-		formats: FormatPAX,
-	}, {
-		header:  &Header{Name: "foobar"},
-		formats: FormatUSTAR | FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{Name: strings.Repeat("a", nameSize)},
-		formats: FormatUSTAR | FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{Name: strings.Repeat("a", nameSize+1)},
-		paxHdrs: map[string]string{paxPath: strings.Repeat("a", nameSize+1)},
-		formats: FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{Linkname: "用戶名"},
-		paxHdrs: map[string]string{paxLinkpath: "用戶名"},
-		formats: FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{Linkname: strings.Repeat("用戶名\x00", nameSize)},
-		paxHdrs: map[string]string{paxLinkpath: strings.Repeat("用戶名\x00", nameSize)},
-		formats: FormatUnknown,
-	}, {
-		header:  &Header{Linkname: "\x00hello"},
-		paxHdrs: map[string]string{paxLinkpath: "\x00hello"},
-		formats: FormatUnknown,
-	}, {
-		header:  &Header{Uid: 07777777},
-		formats: FormatUSTAR | FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{Uid: 07777777 + 1},
-		paxHdrs: map[string]string{paxUid: "2097152"},
-		formats: FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{Xattrs: nil},
-		formats: FormatUSTAR | FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{Xattrs: map[string]string{"foo": "bar"}},
-		paxHdrs: map[string]string{paxSchilyXattr + "foo": "bar"},
-		formats: FormatPAX,
-	}, {
-		header:  &Header{Xattrs: map[string]string{"foo": "bar"}, Format: FormatGNU},
-		paxHdrs: map[string]string{paxSchilyXattr + "foo": "bar"},
-		formats: FormatUnknown,
-	}, {
-		header:  &Header{Xattrs: map[string]string{"用戶名": "\x00hello"}},
-		paxHdrs: map[string]string{paxSchilyXattr + "用戶名": "\x00hello"},
-		formats: FormatPAX,
-	}, {
-		header:  &Header{Xattrs: map[string]string{"foo=bar": "baz"}},
-		formats: FormatUnknown,
-	}, {
-		header:  &Header{Xattrs: map[string]string{"foo": ""}},
-		paxHdrs: map[string]string{paxSchilyXattr + "foo": ""},
-		formats: FormatPAX,
-	}, {
-		header:  &Header{ModTime: time.Unix(0, 0)},
-		formats: FormatUSTAR | FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{ModTime: time.Unix(077777777777, 0)},
-		formats: FormatUSTAR | FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{ModTime: time.Unix(077777777777+1, 0)},
-		paxHdrs: map[string]string{paxMtime: "8589934592"},
-		formats: FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{ModTime: time.Unix(math.MaxInt64, 0)},
-		paxHdrs: map[string]string{paxMtime: "9223372036854775807"},
-		formats: FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{ModTime: time.Unix(math.MaxInt64, 0), Format: FormatUSTAR},
-		paxHdrs: map[string]string{paxMtime: "9223372036854775807"},
-		formats: FormatUnknown,
-	}, {
-		header:  &Header{ModTime: time.Unix(-1, 0)},
-		paxHdrs: map[string]string{paxMtime: "-1"},
-		formats: FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{ModTime: time.Unix(1, 500)},
-		paxHdrs: map[string]string{paxMtime: "1.0000005"},
-		formats: FormatUSTAR | FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{ModTime: time.Unix(1, 0)},
-		formats: FormatUSTAR | FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{ModTime: time.Unix(1, 0), Format: FormatPAX},
-		formats: FormatUSTAR | FormatPAX,
-	}, {
-		header:  &Header{ModTime: time.Unix(1, 500), Format: FormatUSTAR},
-		paxHdrs: map[string]string{paxMtime: "1.0000005"},
-		formats: FormatUSTAR,
-	}, {
-		header:  &Header{ModTime: time.Unix(1, 500), Format: FormatPAX},
-		paxHdrs: map[string]string{paxMtime: "1.0000005"},
-		formats: FormatPAX,
-	}, {
-		header:  &Header{ModTime: time.Unix(1, 500), Format: FormatGNU},
-		paxHdrs: map[string]string{paxMtime: "1.0000005"},
-		formats: FormatGNU,
-	}, {
-		header:  &Header{ModTime: time.Unix(-1, 500)},
-		paxHdrs: map[string]string{paxMtime: "-0.9999995"},
-		formats: FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{ModTime: time.Unix(-1, 500), Format: FormatGNU},
-		paxHdrs: map[string]string{paxMtime: "-0.9999995"},
-		formats: FormatGNU,
-	}, {
-		header:  &Header{AccessTime: time.Unix(0, 0)},
-		paxHdrs: map[string]string{paxAtime: "0"},
-		formats: FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{AccessTime: time.Unix(0, 0), Format: FormatUSTAR},
-		paxHdrs: map[string]string{paxAtime: "0"},
-		formats: FormatUnknown,
-	}, {
-		header:  &Header{AccessTime: time.Unix(0, 0), Format: FormatPAX},
-		paxHdrs: map[string]string{paxAtime: "0"},
-		formats: FormatPAX,
-	}, {
-		header:  &Header{AccessTime: time.Unix(0, 0), Format: FormatGNU},
-		paxHdrs: map[string]string{paxAtime: "0"},
-		formats: FormatGNU,
-	}, {
-		header:  &Header{AccessTime: time.Unix(-123, 0)},
-		paxHdrs: map[string]string{paxAtime: "-123"},
-		formats: FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{AccessTime: time.Unix(-123, 0), Format: FormatPAX},
-		paxHdrs: map[string]string{paxAtime: "-123"},
-		formats: FormatPAX,
-	}, {
-		header:  &Header{ChangeTime: time.Unix(123, 456)},
-		paxHdrs: map[string]string{paxCtime: "123.000000456"},
-		formats: FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{ChangeTime: time.Unix(123, 456), Format: FormatUSTAR},
-		paxHdrs: map[string]string{paxCtime: "123.000000456"},
-		formats: FormatUnknown,
-	}, {
-		header:  &Header{ChangeTime: time.Unix(123, 456), Format: FormatGNU},
-		paxHdrs: map[string]string{paxCtime: "123.000000456"},
-		formats: FormatGNU,
-	}, {
-		header:  &Header{ChangeTime: time.Unix(123, 456), Format: FormatPAX},
-		paxHdrs: map[string]string{paxCtime: "123.000000456"},
-		formats: FormatPAX,
-	}, {
-		header:  &Header{Name: "foo/", Typeflag: TypeDir},
-		formats: FormatUSTAR | FormatPAX | FormatGNU,
-	}, {
-		header:  &Header{Name: "foo/", Typeflag: TypeReg},
-		formats: FormatUnknown,
-	}, {
-		header:  &Header{Name: "foo/", Typeflag: TypeSymlink},
-		formats: FormatUSTAR | FormatPAX | FormatGNU,
-	}}
-
-	for i, v := range vectors {
-		formats, paxHdrs, err := v.header.allowedFormats()
-		if formats != v.formats {
-			t.Errorf("test %d, allowedFormats(): got %v, want %v", i, formats, v.formats)
-		}
-		if formats&FormatPAX > 0 && !reflect.DeepEqual(paxHdrs, v.paxHdrs) && !(len(paxHdrs) == 0 && len(v.paxHdrs) == 0) {
-			t.Errorf("test %d, allowedFormats():\ngot  %v\nwant %s", i, paxHdrs, v.paxHdrs)
-		}
-		if (formats != FormatUnknown) && (err != nil) {
-			t.Errorf("test %d, unexpected error: %v", i, err)
-		}
-		if (formats == FormatUnknown) && (err == nil) {
-			t.Errorf("test %d, got nil-error, want non-nil error", i)
-		}
-	}
-}
-
-func Benchmark(b *testing.B) {
-	type file struct {
-		hdr  *Header
-		body []byte
-	}
-
-	vectors := []struct {
-		label string
-		files []file
-	}{{
-		"USTAR",
-		[]file{{
-			&Header{Name: "bar", Mode: 0640, Size: int64(3)},
-			[]byte("foo"),
-		}, {
-			&Header{Name: "world", Mode: 0640, Size: int64(5)},
-			[]byte("hello"),
-		}},
-	}, {
-		"GNU",
-		[]file{{
-			&Header{Name: "bar", Mode: 0640, Size: int64(3), Devmajor: -1},
-			[]byte("foo"),
-		}, {
-			&Header{Name: "world", Mode: 0640, Size: int64(5), Devmajor: -1},
-			[]byte("hello"),
-		}},
-	}, {
-		"PAX",
-		[]file{{
-			&Header{Name: "bar", Mode: 0640, Size: int64(3), Xattrs: map[string]string{"foo": "bar"}},
-			[]byte("foo"),
-		}, {
-			&Header{Name: "world", Mode: 0640, Size: int64(5), Xattrs: map[string]string{"foo": "bar"}},
-			[]byte("hello"),
-		}},
-	}}
-
-	b.Run("Writer", func(b *testing.B) {
-		for _, v := range vectors {
-			b.Run(v.label, func(b *testing.B) {
-				b.ReportAllocs()
-				for i := 0; i < b.N; i++ {
-					// Writing to io.Discard because we want to
-					// test purely the writer code and not bring in disk performance into this.
-					tw := NewWriter(io.Discard)
-					for _, file := range v.files {
-						if err := tw.WriteHeader(file.hdr); err != nil {
-							b.Errorf("unexpected WriteHeader error: %v", err)
-						}
-						if _, err := tw.Write(file.body); err != nil {
-							b.Errorf("unexpected Write error: %v", err)
-						}
-					}
-					if err := tw.Close(); err != nil {
-						b.Errorf("unexpected Close error: %v", err)
-					}
-				}
-			})
-		}
-	})
-
-	b.Run("Reader", func(b *testing.B) {
-		for _, v := range vectors {
-			var buf bytes.Buffer
-			var r bytes.Reader
-
-			// Write the archive to a byte buffer.
-			tw := NewWriter(&buf)
-			for _, file := range v.files {
-				tw.WriteHeader(file.hdr)
-				tw.Write(file.body)
-			}
-			tw.Close()
-			b.Run(v.label, func(b *testing.B) {
-				b.ReportAllocs()
-				// Read from the byte buffer.
-				for i := 0; i < b.N; i++ {
-					r.Reset(buf.Bytes())
-					tr := NewReader(&r)
-					if _, err := tr.Next(); err != nil {
-						b.Errorf("unexpected Next error: %v", err)
-					}
-					if _, err := io.Copy(io.Discard, tr); err != nil {
-						b.Errorf("unexpected Copy error : %v", err)
-					}
-				}
-			})
-		}
-	})
-
-}
diff --git a/vendor/archive/tar/testdata/file-and-dir.tar b/vendor/archive/tar/testdata/file-and-dir.tar
deleted file mode 100644
index c18d4283e3809..0000000000000
Binary files a/vendor/archive/tar/testdata/file-and-dir.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/gnu-incremental.tar b/vendor/archive/tar/testdata/gnu-incremental.tar
deleted file mode 100644
index 4c442e5b82d19..0000000000000
Binary files a/vendor/archive/tar/testdata/gnu-incremental.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/gnu-long-nul.tar b/vendor/archive/tar/testdata/gnu-long-nul.tar
deleted file mode 100644
index 28bc812aa60e8..0000000000000
Binary files a/vendor/archive/tar/testdata/gnu-long-nul.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/gnu-multi-hdrs.tar b/vendor/archive/tar/testdata/gnu-multi-hdrs.tar
deleted file mode 100644
index 8bcad55d06e8f..0000000000000
Binary files a/vendor/archive/tar/testdata/gnu-multi-hdrs.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/gnu-nil-sparse-data.tar b/vendor/archive/tar/testdata/gnu-nil-sparse-data.tar
deleted file mode 100644
index df1aa834538e7..0000000000000
Binary files a/vendor/archive/tar/testdata/gnu-nil-sparse-data.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/gnu-nil-sparse-hole.tar b/vendor/archive/tar/testdata/gnu-nil-sparse-hole.tar
deleted file mode 100644
index 496abfeb78a5e..0000000000000
Binary files a/vendor/archive/tar/testdata/gnu-nil-sparse-hole.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/gnu-not-utf8.tar b/vendor/archive/tar/testdata/gnu-not-utf8.tar
deleted file mode 100644
index 81cec67d33095..0000000000000
Binary files a/vendor/archive/tar/testdata/gnu-not-utf8.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/gnu-sparse-big.tar b/vendor/archive/tar/testdata/gnu-sparse-big.tar
deleted file mode 100644
index 1a5cfc96d9298..0000000000000
Binary files a/vendor/archive/tar/testdata/gnu-sparse-big.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/gnu-utf8.tar b/vendor/archive/tar/testdata/gnu-utf8.tar
deleted file mode 100644
index 2c9c8079cf651..0000000000000
Binary files a/vendor/archive/tar/testdata/gnu-utf8.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/gnu.tar b/vendor/archive/tar/testdata/gnu.tar
deleted file mode 100644
index fc899dc8dc2ad..0000000000000
Binary files a/vendor/archive/tar/testdata/gnu.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/hardlink.tar b/vendor/archive/tar/testdata/hardlink.tar
deleted file mode 100644
index 9cd1a26572e44..0000000000000
Binary files a/vendor/archive/tar/testdata/hardlink.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/hdr-only.tar b/vendor/archive/tar/testdata/hdr-only.tar
deleted file mode 100644
index f25034083de6e..0000000000000
Binary files a/vendor/archive/tar/testdata/hdr-only.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/invalid-go17.tar b/vendor/archive/tar/testdata/invalid-go17.tar
deleted file mode 100644
index 58f2488e78fb4..0000000000000
Binary files a/vendor/archive/tar/testdata/invalid-go17.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/issue10968.tar b/vendor/archive/tar/testdata/issue10968.tar
deleted file mode 100644
index 1cc837bcff14c..0000000000000
Binary files a/vendor/archive/tar/testdata/issue10968.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/issue11169.tar b/vendor/archive/tar/testdata/issue11169.tar
deleted file mode 100644
index 4d71fa1526060..0000000000000
Binary files a/vendor/archive/tar/testdata/issue11169.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/issue12435.tar b/vendor/archive/tar/testdata/issue12435.tar
deleted file mode 100644
index 3542dd8efd5d4..0000000000000
Binary files a/vendor/archive/tar/testdata/issue12435.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/neg-size.tar b/vendor/archive/tar/testdata/neg-size.tar
deleted file mode 100644
index 21edf38cc3c3d..0000000000000
Binary files a/vendor/archive/tar/testdata/neg-size.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/nil-uid.tar b/vendor/archive/tar/testdata/nil-uid.tar
deleted file mode 100644
index cc9cfaa33cc5d..0000000000000
Binary files a/vendor/archive/tar/testdata/nil-uid.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/pax-bad-hdr-file.tar b/vendor/archive/tar/testdata/pax-bad-hdr-file.tar
deleted file mode 100644
index b97cc981f29b8..0000000000000
Binary files a/vendor/archive/tar/testdata/pax-bad-hdr-file.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/pax-bad-hdr-large.tar.bz2 b/vendor/archive/tar/testdata/pax-bad-hdr-large.tar.bz2
deleted file mode 100644
index 06bf710d3ae4e..0000000000000
Binary files a/vendor/archive/tar/testdata/pax-bad-hdr-large.tar.bz2 and /dev/null differ
diff --git a/vendor/archive/tar/testdata/pax-bad-mtime-file.tar b/vendor/archive/tar/testdata/pax-bad-mtime-file.tar
deleted file mode 100644
index 9b22f7e8d9438..0000000000000
Binary files a/vendor/archive/tar/testdata/pax-bad-mtime-file.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/pax-global-records.tar b/vendor/archive/tar/testdata/pax-global-records.tar
deleted file mode 100644
index 3d3d241e65c3a..0000000000000
Binary files a/vendor/archive/tar/testdata/pax-global-records.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/pax-multi-hdrs.tar b/vendor/archive/tar/testdata/pax-multi-hdrs.tar
deleted file mode 100644
index 14bc759780802..0000000000000
Binary files a/vendor/archive/tar/testdata/pax-multi-hdrs.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/pax-nil-sparse-data.tar b/vendor/archive/tar/testdata/pax-nil-sparse-data.tar
deleted file mode 100644
index e59bd94117d9e..0000000000000
Binary files a/vendor/archive/tar/testdata/pax-nil-sparse-data.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/pax-nil-sparse-hole.tar b/vendor/archive/tar/testdata/pax-nil-sparse-hole.tar
deleted file mode 100644
index b44327bdbfb34..0000000000000
Binary files a/vendor/archive/tar/testdata/pax-nil-sparse-hole.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/pax-nul-path.tar b/vendor/archive/tar/testdata/pax-nul-path.tar
deleted file mode 100644
index c78f82b16e853..0000000000000
Binary files a/vendor/archive/tar/testdata/pax-nul-path.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/pax-nul-xattrs.tar b/vendor/archive/tar/testdata/pax-nul-xattrs.tar
deleted file mode 100644
index 881f51768f987..0000000000000
Binary files a/vendor/archive/tar/testdata/pax-nul-xattrs.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/pax-path-hdr.tar b/vendor/archive/tar/testdata/pax-path-hdr.tar
deleted file mode 100644
index ab8fc325b2615..0000000000000
Binary files a/vendor/archive/tar/testdata/pax-path-hdr.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/pax-pos-size-file.tar b/vendor/archive/tar/testdata/pax-pos-size-file.tar
deleted file mode 100644
index ea5ccf916426a..0000000000000
Binary files a/vendor/archive/tar/testdata/pax-pos-size-file.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/pax-records.tar b/vendor/archive/tar/testdata/pax-records.tar
deleted file mode 100644
index 276c211baa388..0000000000000
Binary files a/vendor/archive/tar/testdata/pax-records.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/pax-sparse-big.tar b/vendor/archive/tar/testdata/pax-sparse-big.tar
deleted file mode 100644
index 65d1f8eceb084..0000000000000
Binary files a/vendor/archive/tar/testdata/pax-sparse-big.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/pax.tar b/vendor/archive/tar/testdata/pax.tar
deleted file mode 100644
index 9bc24b6587d72..0000000000000
Binary files a/vendor/archive/tar/testdata/pax.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/small.txt b/vendor/archive/tar/testdata/small.txt
deleted file mode 100644
index b249bfc518a8c..0000000000000
--- a/vendor/archive/tar/testdata/small.txt
+++ /dev/null
@@ -1,1 +0,0 @@
-Kilts
\ No newline at end of file
diff --git a/vendor/archive/tar/testdata/small2.txt b/vendor/archive/tar/testdata/small2.txt
deleted file mode 100644
index 394ee3ecd0edf..0000000000000
--- a/vendor/archive/tar/testdata/small2.txt
+++ /dev/null
@@ -1,1 +0,0 @@
-Google.com
diff --git a/vendor/archive/tar/testdata/sparse-formats.tar b/vendor/archive/tar/testdata/sparse-formats.tar
deleted file mode 100644
index 8bd4e74d50f9c..0000000000000
Binary files a/vendor/archive/tar/testdata/sparse-formats.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/star.tar b/vendor/archive/tar/testdata/star.tar
deleted file mode 100644
index 59e2d4e604611..0000000000000
Binary files a/vendor/archive/tar/testdata/star.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/trailing-slash.tar b/vendor/archive/tar/testdata/trailing-slash.tar
deleted file mode 100644
index 93718b3034879..0000000000000
Binary files a/vendor/archive/tar/testdata/trailing-slash.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/ustar-file-devs.tar b/vendor/archive/tar/testdata/ustar-file-devs.tar
deleted file mode 100644
index 146e25b79d898..0000000000000
Binary files a/vendor/archive/tar/testdata/ustar-file-devs.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/ustar-file-reg.tar b/vendor/archive/tar/testdata/ustar-file-reg.tar
deleted file mode 100644
index c84fa27ffb861..0000000000000
Binary files a/vendor/archive/tar/testdata/ustar-file-reg.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/ustar.tar b/vendor/archive/tar/testdata/ustar.tar
deleted file mode 100644
index 29679d9a305fc..0000000000000
Binary files a/vendor/archive/tar/testdata/ustar.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/v7.tar b/vendor/archive/tar/testdata/v7.tar
deleted file mode 100644
index eb65fc9410721..0000000000000
Binary files a/vendor/archive/tar/testdata/v7.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/writer-big-long.tar b/vendor/archive/tar/testdata/writer-big-long.tar
deleted file mode 100644
index 09fc5dd3dd7fc..0000000000000
Binary files a/vendor/archive/tar/testdata/writer-big-long.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/writer-big.tar b/vendor/archive/tar/testdata/writer-big.tar
deleted file mode 100644
index 435dcbce6abc7..0000000000000
Binary files a/vendor/archive/tar/testdata/writer-big.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/writer.tar b/vendor/archive/tar/testdata/writer.tar
deleted file mode 100644
index e6d816ad0775d..0000000000000
Binary files a/vendor/archive/tar/testdata/writer.tar and /dev/null differ
diff --git a/vendor/archive/tar/testdata/xattrs.tar b/vendor/archive/tar/testdata/xattrs.tar
deleted file mode 100644
index 9701950edd1f0..0000000000000
Binary files a/vendor/archive/tar/testdata/xattrs.tar and /dev/null differ
diff --git a/vendor/archive/tar/writer_test.go b/vendor/archive/tar/writer_test.go
deleted file mode 100644
index 640264984a96e..0000000000000
--- a/vendor/archive/tar/writer_test.go
+++ /dev/null
@@ -1,1335 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tar
-
-import (
-	"bytes"
-	"encoding/hex"
-	"errors"
-	"io"
-	"os"
-	"path"
-	"reflect"
-	"sort"
-	"strings"
-	"testing"
-	"testing/iotest"
-	"time"
-)
-
-func bytediff(a, b []byte) string {
-	const (
-		uniqueA  = "-  "
-		uniqueB  = "+  "
-		identity = "   "
-	)
-	var ss []string
-	sa := strings.Split(strings.TrimSpace(hex.Dump(a)), "\n")
-	sb := strings.Split(strings.TrimSpace(hex.Dump(b)), "\n")
-	for len(sa) > 0 && len(sb) > 0 {
-		if sa[0] == sb[0] {
-			ss = append(ss, identity+sa[0])
-		} else {
-			ss = append(ss, uniqueA+sa[0])
-			ss = append(ss, uniqueB+sb[0])
-		}
-		sa, sb = sa[1:], sb[1:]
-	}
-	for len(sa) > 0 {
-		ss = append(ss, uniqueA+sa[0])
-		sa = sa[1:]
-	}
-	for len(sb) > 0 {
-		ss = append(ss, uniqueB+sb[0])
-		sb = sb[1:]
-	}
-	return strings.Join(ss, "\n")
-}
-
-func TestWriter(t *testing.T) {
-	type (
-		testHeader struct { // WriteHeader(hdr) == wantErr
-			hdr     Header
-			wantErr error
-		}
-		testWrite struct { // Write(str) == (wantCnt, wantErr)
-			str     string
-			wantCnt int
-			wantErr error
-		}
-		testReadFrom struct { // ReadFrom(testFile{ops}) == (wantCnt, wantErr)
-			ops     fileOps
-			wantCnt int64
-			wantErr error
-		}
-		testClose struct { // Close() == wantErr
-			wantErr error
-		}
-		testFnc any // testHeader | testWrite | testReadFrom | testClose
-	)
-
-	vectors := []struct {
-		file  string // Optional filename of expected output
-		tests []testFnc
-	}{{
-		// The writer test file was produced with this command:
-		// tar (GNU tar) 1.26
-		//   ln -s small.txt link.txt
-		//   tar -b 1 --format=ustar -c -f writer.tar small.txt small2.txt link.txt
-		file: "testdata/writer.tar",
-		tests: []testFnc{
-			testHeader{Header{
-				Typeflag: TypeReg,
-				Name:     "small.txt",
-				Size:     5,
-				Mode:     0640,
-				Uid:      73025,
-				Gid:      5000,
-				Uname:    "dsymonds",
-				Gname:    "eng",
-				ModTime:  time.Unix(1246508266, 0),
-			}, nil},
-			testWrite{"Kilts", 5, nil},
-
-			testHeader{Header{
-				Typeflag: TypeReg,
-				Name:     "small2.txt",
-				Size:     11,
-				Mode:     0640,
-				Uid:      73025,
-				Uname:    "dsymonds",
-				Gname:    "eng",
-				Gid:      5000,
-				ModTime:  time.Unix(1245217492, 0),
-			}, nil},
-			testWrite{"Google.com\n", 11, nil},
-
-			testHeader{Header{
-				Typeflag: TypeSymlink,
-				Name:     "link.txt",
-				Linkname: "small.txt",
-				Mode:     0777,
-				Uid:      1000,
-				Gid:      1000,
-				Uname:    "strings",
-				Gname:    "strings",
-				ModTime:  time.Unix(1314603082, 0),
-			}, nil},
-			testWrite{"", 0, nil},
-
-			testClose{nil},
-		},
-	}, {
-		// The truncated test file was produced using these commands:
-		//   dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
-		//   tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
-		file: "testdata/writer-big.tar",
-		tests: []testFnc{
-			testHeader{Header{
-				Typeflag: TypeReg,
-				Name:     "tmp/16gig.txt",
-				Size:     16 << 30,
-				Mode:     0640,
-				Uid:      73025,
-				Gid:      5000,
-				Uname:    "dsymonds",
-				Gname:    "eng",
-				ModTime:  time.Unix(1254699560, 0),
-				Format:   FormatGNU,
-			}, nil},
-		},
-	}, {
-		// This truncated file was produced using this library.
-		// It was verified to work with GNU tar 1.27.1 and BSD tar 3.1.2.
-		//  dd if=/dev/zero bs=1G count=16 >> writer-big-long.tar
-		//  gnutar -xvf writer-big-long.tar
-		//  bsdtar -xvf writer-big-long.tar
-		//
-		// This file is in PAX format.
-		file: "testdata/writer-big-long.tar",
-		tests: []testFnc{
-			testHeader{Header{
-				Typeflag: TypeReg,
-				Name:     strings.Repeat("longname/", 15) + "16gig.txt",
-				Size:     16 << 30,
-				Mode:     0644,
-				Uid:      1000,
-				Gid:      1000,
-				Uname:    "guillaume",
-				Gname:    "guillaume",
-				ModTime:  time.Unix(1399583047, 0),
-			}, nil},
-		},
-	}, {
-		// This file was produced using GNU tar v1.17.
-		//	gnutar -b 4 --format=ustar (longname/)*15 + file.txt
-		file: "testdata/ustar.tar",
-		tests: []testFnc{
-			testHeader{Header{
-				Typeflag: TypeReg,
-				Name:     strings.Repeat("longname/", 15) + "file.txt",
-				Size:     6,
-				Mode:     0644,
-				Uid:      501,
-				Gid:      20,
-				Uname:    "shane",
-				Gname:    "staff",
-				ModTime:  time.Unix(1360135598, 0),
-			}, nil},
-			testWrite{"hello\n", 6, nil},
-			testClose{nil},
-		},
-	}, {
-		// This file was produced using GNU tar v1.26:
-		//	echo "Slartibartfast" > file.txt
-		//	ln file.txt hard.txt
-		//	tar -b 1 --format=ustar -c -f hardlink.tar file.txt hard.txt
-		file: "testdata/hardlink.tar",
-		tests: []testFnc{
-			testHeader{Header{
-				Typeflag: TypeReg,
-				Name:     "file.txt",
-				Size:     15,
-				Mode:     0644,
-				Uid:      1000,
-				Gid:      100,
-				Uname:    "vbatts",
-				Gname:    "users",
-				ModTime:  time.Unix(1425484303, 0),
-			}, nil},
-			testWrite{"Slartibartfast\n", 15, nil},
-
-			testHeader{Header{
-				Typeflag: TypeLink,
-				Name:     "hard.txt",
-				Linkname: "file.txt",
-				Mode:     0644,
-				Uid:      1000,
-				Gid:      100,
-				Uname:    "vbatts",
-				Gname:    "users",
-				ModTime:  time.Unix(1425484303, 0),
-			}, nil},
-			testWrite{"", 0, nil},
-
-			testClose{nil},
-		},
-	}, {
-		tests: []testFnc{
-			testHeader{Header{
-				Typeflag: TypeReg,
-				Name:     "bad-null.txt",
-				Xattrs:   map[string]string{"null\x00null\x00": "fizzbuzz"},
-			}, headerError{}},
-		},
-	}, {
-		tests: []testFnc{
-			testHeader{Header{
-				Typeflag: TypeReg,
-				Name:     "null\x00.txt",
-			}, headerError{}},
-		},
-	}, {
-		file: "testdata/pax-records.tar",
-		tests: []testFnc{
-			testHeader{Header{
-				Typeflag: TypeReg,
-				Name:     "file",
-				Uname:    strings.Repeat("long", 10),
-				PAXRecords: map[string]string{
-					"path":           "FILE", // Should be ignored
-					"GNU.sparse.map": "0,0",  // Should be ignored
-					"comment":        "Hello, 世界",
-					"GOLANG.pkg":     "tar",
-				},
-			}, nil},
-			testClose{nil},
-		},
-	}, {
-		// Craft a theoretically valid PAX archive with global headers.
-		// The GNU and BSD tar tools do not parse these the same way.
-		//
-		// BSD tar v3.1.2 parses and ignores all global headers;
-		// the behavior is verified by researching the source code.
-		//
-		//	$ bsdtar -tvf pax-global-records.tar
-		//	----------  0 0      0           0 Dec 31  1969 file1
-		//	----------  0 0      0           0 Dec 31  1969 file2
-		//	----------  0 0      0           0 Dec 31  1969 file3
-		//	----------  0 0      0           0 May 13  2014 file4
-		//
-		// GNU tar v1.27.1 applies global headers to subsequent records,
-		// but does not do the following properly:
-		//	* It does not treat an empty record as deletion.
-		//	* It does not use subsequent global headers to update previous ones.
-		//
-		//	$ gnutar -tvf pax-global-records.tar
-		//	---------- 0/0               0 2017-07-13 19:40 global1
-		//	---------- 0/0               0 2017-07-13 19:40 file2
-		//	gnutar: Substituting `.' for empty member name
-		//	---------- 0/0               0 1969-12-31 16:00
-		//	gnutar: Substituting `.' for empty member name
-		//	---------- 0/0               0 2014-05-13 09:53
-		//
-		// According to the PAX specification, this should have been the result:
-		//	---------- 0/0               0 2017-07-13 19:40 global1
-		//	---------- 0/0               0 2017-07-13 19:40 file2
-		//	---------- 0/0               0 2017-07-13 19:40 file3
-		//	---------- 0/0               0 2014-05-13 09:53 file4
-		file: "testdata/pax-global-records.tar",
-		tests: []testFnc{
-			testHeader{Header{
-				Typeflag:   TypeXGlobalHeader,
-				PAXRecords: map[string]string{"path": "global1", "mtime": "1500000000.0"},
-			}, nil},
-			testHeader{Header{
-				Typeflag: TypeReg, Name: "file1",
-			}, nil},
-			testHeader{Header{
-				Typeflag:   TypeReg,
-				Name:       "file2",
-				PAXRecords: map[string]string{"path": "file2"},
-			}, nil},
-			testHeader{Header{
-				Typeflag:   TypeXGlobalHeader,
-				PAXRecords: map[string]string{"path": ""}, // Should delete "path", but keep "mtime"
-			}, nil},
-			testHeader{Header{
-				Typeflag: TypeReg, Name: "file3",
-			}, nil},
-			testHeader{Header{
-				Typeflag:   TypeReg,
-				Name:       "file4",
-				ModTime:    time.Unix(1400000000, 0),
-				PAXRecords: map[string]string{"mtime": "1400000000"},
-			}, nil},
-			testClose{nil},
-		},
-	}, {
-		file: "testdata/gnu-utf8.tar",
-		tests: []testFnc{
-			testHeader{Header{
-				Typeflag: TypeReg,
-				Name:     "☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹",
-				Mode:     0644,
-				Uid:      1000, Gid: 1000,
-				Uname:   "☺",
-				Gname:   "⚹",
-				ModTime: time.Unix(0, 0),
-				Format:  FormatGNU,
-			}, nil},
-			testClose{nil},
-		},
-	}, {
-		file: "testdata/gnu-not-utf8.tar",
-		tests: []testFnc{
-			testHeader{Header{
-				Typeflag: TypeReg,
-				Name:     "hi\x80\x81\x82\x83bye",
-				Mode:     0644,
-				Uid:      1000,
-				Gid:      1000,
-				Uname:    "rawr",
-				Gname:    "dsnet",
-				ModTime:  time.Unix(0, 0),
-				Format:   FormatGNU,
-			}, nil},
-			testClose{nil},
-		},
-		// TODO(dsnet): Re-enable this test when adding sparse support.
-		// See https://golang.org/issue/22735
-		/*
-			}, {
-				file: "testdata/gnu-nil-sparse-data.tar",
-				tests: []testFnc{
-					testHeader{Header{
-						Typeflag:    TypeGNUSparse,
-						Name:        "sparse.db",
-						Size:        1000,
-						SparseHoles: []sparseEntry{{Offset: 1000, Length: 0}},
-					}, nil},
-					testWrite{strings.Repeat("0123456789", 100), 1000, nil},
-					testClose{},
-				},
-			}, {
-				file: "testdata/gnu-nil-sparse-hole.tar",
-				tests: []testFnc{
-					testHeader{Header{
-						Typeflag:    TypeGNUSparse,
-						Name:        "sparse.db",
-						Size:        1000,
-						SparseHoles: []sparseEntry{{Offset: 0, Length: 1000}},
-					}, nil},
-					testWrite{strings.Repeat("\x00", 1000), 1000, nil},
-					testClose{},
-				},
-			}, {
-				file: "testdata/pax-nil-sparse-data.tar",
-				tests: []testFnc{
-					testHeader{Header{
-						Typeflag:    TypeReg,
-						Name:        "sparse.db",
-						Size:        1000,
-						SparseHoles: []sparseEntry{{Offset: 1000, Length: 0}},
-					}, nil},
-					testWrite{strings.Repeat("0123456789", 100), 1000, nil},
-					testClose{},
-				},
-			}, {
-				file: "testdata/pax-nil-sparse-hole.tar",
-				tests: []testFnc{
-					testHeader{Header{
-						Typeflag:    TypeReg,
-						Name:        "sparse.db",
-						Size:        1000,
-						SparseHoles: []sparseEntry{{Offset: 0, Length: 1000}},
-					}, nil},
-					testWrite{strings.Repeat("\x00", 1000), 1000, nil},
-					testClose{},
-				},
-			}, {
-				file: "testdata/gnu-sparse-big.tar",
-				tests: []testFnc{
-					testHeader{Header{
-						Typeflag: TypeGNUSparse,
-						Name:     "gnu-sparse",
-						Size:     6e10,
-						SparseHoles: []sparseEntry{
-							{Offset: 0e10, Length: 1e10 - 100},
-							{Offset: 1e10, Length: 1e10 - 100},
-							{Offset: 2e10, Length: 1e10 - 100},
-							{Offset: 3e10, Length: 1e10 - 100},
-							{Offset: 4e10, Length: 1e10 - 100},
-							{Offset: 5e10, Length: 1e10 - 100},
-						},
-					}, nil},
-					testReadFrom{fileOps{
-						int64(1e10 - blockSize),
-						strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10),
-						int64(1e10 - blockSize),
-						strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10),
-						int64(1e10 - blockSize),
-						strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10),
-						int64(1e10 - blockSize),
-						strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10),
-						int64(1e10 - blockSize),
-						strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10),
-						int64(1e10 - blockSize),
-						strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10),
-					}, 6e10, nil},
-					testClose{nil},
-				},
-			}, {
-				file: "testdata/pax-sparse-big.tar",
-				tests: []testFnc{
-					testHeader{Header{
-						Typeflag: TypeReg,
-						Name:     "pax-sparse",
-						Size:     6e10,
-						SparseHoles: []sparseEntry{
-							{Offset: 0e10, Length: 1e10 - 100},
-							{Offset: 1e10, Length: 1e10 - 100},
-							{Offset: 2e10, Length: 1e10 - 100},
-							{Offset: 3e10, Length: 1e10 - 100},
-							{Offset: 4e10, Length: 1e10 - 100},
-							{Offset: 5e10, Length: 1e10 - 100},
-						},
-					}, nil},
-					testReadFrom{fileOps{
-						int64(1e10 - blockSize),
-						strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10),
-						int64(1e10 - blockSize),
-						strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10),
-						int64(1e10 - blockSize),
-						strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10),
-						int64(1e10 - blockSize),
-						strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10),
-						int64(1e10 - blockSize),
-						strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10),
-						int64(1e10 - blockSize),
-						strings.Repeat("\x00", blockSize-100) + strings.Repeat("0123456789", 10),
-					}, 6e10, nil},
-					testClose{nil},
-				},
-		*/
-	}, {
-		file: "testdata/trailing-slash.tar",
-		tests: []testFnc{
-			testHeader{Header{Name: strings.Repeat("123456789/", 30)}, nil},
-			testClose{nil},
-		},
-	}, {
-		// Automatically promote zero value of Typeflag depending on the name.
-		file: "testdata/file-and-dir.tar",
-		tests: []testFnc{
-			testHeader{Header{Name: "small.txt", Size: 5}, nil},
-			testWrite{"Kilts", 5, nil},
-			testHeader{Header{Name: "dir/"}, nil},
-			testClose{nil},
-		},
-	}}
-
-	equalError := func(x, y error) bool {
-		_, ok1 := x.(headerError)
-		_, ok2 := y.(headerError)
-		if ok1 || ok2 {
-			return ok1 && ok2
-		}
-		return x == y
-	}
-	for _, v := range vectors {
-		t.Run(path.Base(v.file), func(t *testing.T) {
-			const maxSize = 10 << 10 // 10KiB
-			buf := new(bytes.Buffer)
-			tw := NewWriter(iotest.TruncateWriter(buf, maxSize))
-
-			for i, tf := range v.tests {
-				switch tf := tf.(type) {
-				case testHeader:
-					err := tw.WriteHeader(&tf.hdr)
-					if !equalError(err, tf.wantErr) {
-						t.Fatalf("test %d, WriteHeader() = %v, want %v", i, err, tf.wantErr)
-					}
-				case testWrite:
-					got, err := tw.Write([]byte(tf.str))
-					if got != tf.wantCnt || !equalError(err, tf.wantErr) {
-						t.Fatalf("test %d, Write() = (%d, %v), want (%d, %v)", i, got, err, tf.wantCnt, tf.wantErr)
-					}
-				case testReadFrom:
-					f := &testFile{ops: tf.ops}
-					got, err := tw.readFrom(f)
-					if _, ok := err.(testError); ok {
-						t.Errorf("test %d, ReadFrom(): %v", i, err)
-					} else if got != tf.wantCnt || !equalError(err, tf.wantErr) {
-						t.Errorf("test %d, ReadFrom() = (%d, %v), want (%d, %v)", i, got, err, tf.wantCnt, tf.wantErr)
-					}
-					if len(f.ops) > 0 {
-						t.Errorf("test %d, expected %d more operations", i, len(f.ops))
-					}
-				case testClose:
-					err := tw.Close()
-					if !equalError(err, tf.wantErr) {
-						t.Fatalf("test %d, Close() = %v, want %v", i, err, tf.wantErr)
-					}
-				default:
-					t.Fatalf("test %d, unknown test operation: %T", i, tf)
-				}
-			}
-
-			if v.file != "" {
-				want, err := os.ReadFile(v.file)
-				if err != nil {
-					t.Fatalf("ReadFile() = %v, want nil", err)
-				}
-				got := buf.Bytes()
-				if !bytes.Equal(want, got) {
-					t.Fatalf("incorrect result: (-got +want)\n%v", bytediff(got, want))
-				}
-			}
-		})
-	}
-}
-
-func TestPax(t *testing.T) {
-	// Create an archive with a large name
-	fileinfo, err := os.Stat("testdata/small.txt")
-	if err != nil {
-		t.Fatal(err)
-	}
-	hdr, err := FileInfoHeader(fileinfo, "")
-	if err != nil {
-		t.Fatalf("os.Stat: %v", err)
-	}
-	// Force a PAX long name to be written
-	longName := strings.Repeat("ab", 100)
-	contents := strings.Repeat(" ", int(hdr.Size))
-	hdr.Name = longName
-	var buf bytes.Buffer
-	writer := NewWriter(&buf)
-	if err := writer.WriteHeader(hdr); err != nil {
-		t.Fatal(err)
-	}
-	if _, err = writer.Write([]byte(contents)); err != nil {
-		t.Fatal(err)
-	}
-	if err := writer.Close(); err != nil {
-		t.Fatal(err)
-	}
-	// Simple test to make sure PAX extensions are in effect
-	if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.0")) {
-		t.Fatal("Expected at least one PAX header to be written.")
-	}
-	// Test that we can get a long name back out of the archive.
-	reader := NewReader(&buf)
-	hdr, err = reader.Next()
-	if err != nil {
-		t.Fatal(err)
-	}
-	if hdr.Name != longName {
-		t.Fatal("Couldn't recover long file name")
-	}
-}
-
-func TestPaxSymlink(t *testing.T) {
-	// Create an archive with a large linkname
-	fileinfo, err := os.Stat("testdata/small.txt")
-	if err != nil {
-		t.Fatal(err)
-	}
-	hdr, err := FileInfoHeader(fileinfo, "")
-	hdr.Typeflag = TypeSymlink
-	if err != nil {
-		t.Fatalf("os.Stat:1 %v", err)
-	}
-	// Force a PAX long linkname to be written
-	longLinkname := strings.Repeat("1234567890/1234567890", 10)
-	hdr.Linkname = longLinkname
-
-	hdr.Size = 0
-	var buf bytes.Buffer
-	writer := NewWriter(&buf)
-	if err := writer.WriteHeader(hdr); err != nil {
-		t.Fatal(err)
-	}
-	if err := writer.Close(); err != nil {
-		t.Fatal(err)
-	}
-	// Simple test to make sure PAX extensions are in effect
-	if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.0")) {
-		t.Fatal("Expected at least one PAX header to be written.")
-	}
-	// Test that we can get a long name back out of the archive.
-	reader := NewReader(&buf)
-	hdr, err = reader.Next()
-	if err != nil {
-		t.Fatal(err)
-	}
-	if hdr.Linkname != longLinkname {
-		t.Fatal("Couldn't recover long link name")
-	}
-}
-
-func TestPaxNonAscii(t *testing.T) {
-	// Create an archive with non ascii. These should trigger a pax header
-	// because pax headers have a defined utf-8 encoding.
-	fileinfo, err := os.Stat("testdata/small.txt")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	hdr, err := FileInfoHeader(fileinfo, "")
-	if err != nil {
-		t.Fatalf("os.Stat:1 %v", err)
-	}
-
-	// some sample data
-	chineseFilename := "文件名"
-	chineseGroupname := "組"
-	chineseUsername := "用戶名"
-
-	hdr.Name = chineseFilename
-	hdr.Gname = chineseGroupname
-	hdr.Uname = chineseUsername
-
-	contents := strings.Repeat(" ", int(hdr.Size))
-
-	var buf bytes.Buffer
-	writer := NewWriter(&buf)
-	if err := writer.WriteHeader(hdr); err != nil {
-		t.Fatal(err)
-	}
-	if _, err = writer.Write([]byte(contents)); err != nil {
-		t.Fatal(err)
-	}
-	if err := writer.Close(); err != nil {
-		t.Fatal(err)
-	}
-	// Simple test to make sure PAX extensions are in effect
-	if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.0")) {
-		t.Fatal("Expected at least one PAX header to be written.")
-	}
-	// Test that we can get a long name back out of the archive.
-	reader := NewReader(&buf)
-	hdr, err = reader.Next()
-	if err != nil {
-		t.Fatal(err)
-	}
-	if hdr.Name != chineseFilename {
-		t.Fatal("Couldn't recover unicode name")
-	}
-	if hdr.Gname != chineseGroupname {
-		t.Fatal("Couldn't recover unicode group")
-	}
-	if hdr.Uname != chineseUsername {
-		t.Fatal("Couldn't recover unicode user")
-	}
-}
-
-func TestPaxXattrs(t *testing.T) {
-	xattrs := map[string]string{
-		"user.key": "value",
-	}
-
-	// Create an archive with an xattr
-	fileinfo, err := os.Stat("testdata/small.txt")
-	if err != nil {
-		t.Fatal(err)
-	}
-	hdr, err := FileInfoHeader(fileinfo, "")
-	if err != nil {
-		t.Fatalf("os.Stat: %v", err)
-	}
-	contents := "Kilts"
-	hdr.Xattrs = xattrs
-	var buf bytes.Buffer
-	writer := NewWriter(&buf)
-	if err := writer.WriteHeader(hdr); err != nil {
-		t.Fatal(err)
-	}
-	if _, err = writer.Write([]byte(contents)); err != nil {
-		t.Fatal(err)
-	}
-	if err := writer.Close(); err != nil {
-		t.Fatal(err)
-	}
-	// Test that we can get the xattrs back out of the archive.
-	reader := NewReader(&buf)
-	hdr, err = reader.Next()
-	if err != nil {
-		t.Fatal(err)
-	}
-	if !reflect.DeepEqual(hdr.Xattrs, xattrs) {
-		t.Fatalf("xattrs did not survive round trip: got %+v, want %+v",
-			hdr.Xattrs, xattrs)
-	}
-}
-
-func TestPaxHeadersSorted(t *testing.T) {
-	fileinfo, err := os.Stat("testdata/small.txt")
-	if err != nil {
-		t.Fatal(err)
-	}
-	hdr, err := FileInfoHeader(fileinfo, "")
-	if err != nil {
-		t.Fatalf("os.Stat: %v", err)
-	}
-	contents := strings.Repeat(" ", int(hdr.Size))
-
-	hdr.Xattrs = map[string]string{
-		"foo": "foo",
-		"bar": "bar",
-		"baz": "baz",
-		"qux": "qux",
-	}
-
-	var buf bytes.Buffer
-	writer := NewWriter(&buf)
-	if err := writer.WriteHeader(hdr); err != nil {
-		t.Fatal(err)
-	}
-	if _, err = writer.Write([]byte(contents)); err != nil {
-		t.Fatal(err)
-	}
-	if err := writer.Close(); err != nil {
-		t.Fatal(err)
-	}
-	// Simple test to make sure PAX extensions are in effect
-	if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.0")) {
-		t.Fatal("Expected at least one PAX header to be written.")
-	}
-
-	// xattr bar should always appear before others
-	indices := []int{
-		bytes.Index(buf.Bytes(), []byte("bar=bar")),
-		bytes.Index(buf.Bytes(), []byte("baz=baz")),
-		bytes.Index(buf.Bytes(), []byte("foo=foo")),
-		bytes.Index(buf.Bytes(), []byte("qux=qux")),
-	}
-	if !sort.IntsAreSorted(indices) {
-		t.Fatal("PAX headers are not sorted")
-	}
-}
-
-func TestUSTARLongName(t *testing.T) {
-	// Create an archive with a path that failed to split with USTAR extension in previous versions.
-	fileinfo, err := os.Stat("testdata/small.txt")
-	if err != nil {
-		t.Fatal(err)
-	}
-	hdr, err := FileInfoHeader(fileinfo, "")
-	hdr.Typeflag = TypeDir
-	if err != nil {
-		t.Fatalf("os.Stat:1 %v", err)
-	}
-	// Force a PAX long name to be written. The name was taken from a practical example
-	// that fails and replaced ever char through numbers to anonymize the sample.
-	longName := "/0000_0000000/00000-000000000/0000_0000000/00000-0000000000000/0000_0000000/00000-0000000-00000000/0000_0000000/00000000/0000_0000000/000/0000_0000000/00000000v00/0000_0000000/000000/0000_0000000/0000000/0000_0000000/00000y-00/0000/0000/00000000/0x000000/"
-	hdr.Name = longName
-
-	hdr.Size = 0
-	var buf bytes.Buffer
-	writer := NewWriter(&buf)
-	if err := writer.WriteHeader(hdr); err != nil {
-		t.Fatal(err)
-	}
-	if err := writer.Close(); err != nil {
-		t.Fatal(err)
-	}
-	// Test that we can get a long name back out of the archive.
-	reader := NewReader(&buf)
-	hdr, err = reader.Next()
-	if err != nil {
-		t.Fatal(err)
-	}
-	if hdr.Name != longName {
-		t.Fatal("Couldn't recover long name")
-	}
-}
-
-func TestValidTypeflagWithPAXHeader(t *testing.T) {
-	var buffer bytes.Buffer
-	tw := NewWriter(&buffer)
-
-	fileName := strings.Repeat("ab", 100)
-
-	hdr := &Header{
-		Name:     fileName,
-		Size:     4,
-		Typeflag: 0,
-	}
-	if err := tw.WriteHeader(hdr); err != nil {
-		t.Fatalf("Failed to write header: %s", err)
-	}
-	if _, err := tw.Write([]byte("fooo")); err != nil {
-		t.Fatalf("Failed to write the file's data: %s", err)
-	}
-	tw.Close()
-
-	tr := NewReader(&buffer)
-
-	for {
-		header, err := tr.Next()
-		if err == io.EOF {
-			break
-		}
-		if err != nil {
-			t.Fatalf("Failed to read header: %s", err)
-		}
-		if header.Typeflag != TypeReg {
-			t.Fatalf("Typeflag should've been %d, found %d", TypeReg, header.Typeflag)
-		}
-	}
-}
-
-// failOnceWriter fails exactly once and then always reports success.
-type failOnceWriter bool
-
-func (w *failOnceWriter) Write(b []byte) (int, error) {
-	if !*w {
-		return 0, io.ErrShortWrite
-	}
-	*w = true
-	return len(b), nil
-}
-
-func TestWriterErrors(t *testing.T) {
-	t.Run("HeaderOnly", func(t *testing.T) {
-		tw := NewWriter(new(bytes.Buffer))
-		hdr := &Header{Name: "dir/", Typeflag: TypeDir}
-		if err := tw.WriteHeader(hdr); err != nil {
-			t.Fatalf("WriteHeader() = %v, want nil", err)
-		}
-		if _, err := tw.Write([]byte{0x00}); err != ErrWriteTooLong {
-			t.Fatalf("Write() = %v, want %v", err, ErrWriteTooLong)
-		}
-	})
-
-	t.Run("NegativeSize", func(t *testing.T) {
-		tw := NewWriter(new(bytes.Buffer))
-		hdr := &Header{Name: "small.txt", Size: -1}
-		if err := tw.WriteHeader(hdr); err == nil {
-			t.Fatalf("WriteHeader() = nil, want non-nil error")
-		}
-	})
-
-	t.Run("BeforeHeader", func(t *testing.T) {
-		tw := NewWriter(new(bytes.Buffer))
-		if _, err := tw.Write([]byte("Kilts")); err != ErrWriteTooLong {
-			t.Fatalf("Write() = %v, want %v", err, ErrWriteTooLong)
-		}
-	})
-
-	t.Run("AfterClose", func(t *testing.T) {
-		tw := NewWriter(new(bytes.Buffer))
-		hdr := &Header{Name: "small.txt"}
-		if err := tw.WriteHeader(hdr); err != nil {
-			t.Fatalf("WriteHeader() = %v, want nil", err)
-		}
-		if err := tw.Close(); err != nil {
-			t.Fatalf("Close() = %v, want nil", err)
-		}
-		if _, err := tw.Write([]byte("Kilts")); err != ErrWriteAfterClose {
-			t.Fatalf("Write() = %v, want %v", err, ErrWriteAfterClose)
-		}
-		if err := tw.Flush(); err != ErrWriteAfterClose {
-			t.Fatalf("Flush() = %v, want %v", err, ErrWriteAfterClose)
-		}
-		if err := tw.Close(); err != nil {
-			t.Fatalf("Close() = %v, want nil", err)
-		}
-	})
-
-	t.Run("PrematureFlush", func(t *testing.T) {
-		tw := NewWriter(new(bytes.Buffer))
-		hdr := &Header{Name: "small.txt", Size: 5}
-		if err := tw.WriteHeader(hdr); err != nil {
-			t.Fatalf("WriteHeader() = %v, want nil", err)
-		}
-		if err := tw.Flush(); err == nil {
-			t.Fatalf("Flush() = %v, want non-nil error", err)
-		}
-	})
-
-	t.Run("PrematureClose", func(t *testing.T) {
-		tw := NewWriter(new(bytes.Buffer))
-		hdr := &Header{Name: "small.txt", Size: 5}
-		if err := tw.WriteHeader(hdr); err != nil {
-			t.Fatalf("WriteHeader() = %v, want nil", err)
-		}
-		if err := tw.Close(); err == nil {
-			t.Fatalf("Close() = %v, want non-nil error", err)
-		}
-	})
-
-	t.Run("Persistence", func(t *testing.T) {
-		tw := NewWriter(new(failOnceWriter))
-		if err := tw.WriteHeader(&Header{}); err != io.ErrShortWrite {
-			t.Fatalf("WriteHeader() = %v, want %v", err, io.ErrShortWrite)
-		}
-		if err := tw.WriteHeader(&Header{Name: "small.txt"}); err == nil {
-			t.Errorf("WriteHeader() = got %v, want non-nil error", err)
-		}
-		if _, err := tw.Write(nil); err == nil {
-			t.Errorf("Write() = %v, want non-nil error", err)
-		}
-		if err := tw.Flush(); err == nil {
-			t.Errorf("Flush() = %v, want non-nil error", err)
-		}
-		if err := tw.Close(); err == nil {
-			t.Errorf("Close() = %v, want non-nil error", err)
-		}
-	})
-}
-
-func TestSplitUSTARPath(t *testing.T) {
-	sr := strings.Repeat
-
-	vectors := []struct {
-		input  string // Input path
-		prefix string // Expected output prefix
-		suffix string // Expected output suffix
-		ok     bool   // Split success?
-	}{
-		{"", "", "", false},
-		{"abc", "", "", false},
-		{"用戶名", "", "", false},
-		{sr("a", nameSize), "", "", false},
-		{sr("a", nameSize) + "/", "", "", false},
-		{sr("a", nameSize) + "/a", sr("a", nameSize), "a", true},
-		{sr("a", prefixSize) + "/", "", "", false},
-		{sr("a", prefixSize) + "/a", sr("a", prefixSize), "a", true},
-		{sr("a", nameSize+1), "", "", false},
-		{sr("/", nameSize+1), sr("/", nameSize-1), "/", true},
-		{sr("a", prefixSize) + "/" + sr("b", nameSize),
-			sr("a", prefixSize), sr("b", nameSize), true},
-		{sr("a", prefixSize) + "//" + sr("b", nameSize), "", "", false},
-		{sr("a/", nameSize), sr("a/", 77) + "a", sr("a/", 22), true},
-	}
-
-	for _, v := range vectors {
-		prefix, suffix, ok := splitUSTARPath(v.input)
-		if prefix != v.prefix || suffix != v.suffix || ok != v.ok {
-			t.Errorf("splitUSTARPath(%q):\ngot  (%q, %q, %v)\nwant (%q, %q, %v)",
-				v.input, prefix, suffix, ok, v.prefix, v.suffix, v.ok)
-		}
-	}
-}
-
-// TestIssue12594 tests that the Writer does not attempt to populate the prefix
-// field when encoding a header in the GNU format. The prefix field is valid
-// in USTAR and PAX, but not GNU.
-func TestIssue12594(t *testing.T) {
-	names := []string{
-		"0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/file.txt",
-		"0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/file.txt",
-		"0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/333/file.txt",
-		"0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34/35/36/37/38/39/40/file.txt",
-		"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000/file.txt",
-		"/home/support/.openoffice.org/3/user/uno_packages/cache/registry/com.sun.star.comp.deployment.executable.PackageRegistryBackend",
-	}
-
-	for i, name := range names {
-		var b bytes.Buffer
-
-		tw := NewWriter(&b)
-		if err := tw.WriteHeader(&Header{
-			Name: name,
-			Uid:  1 << 25, // Prevent USTAR format
-		}); err != nil {
-			t.Errorf("test %d, unexpected WriteHeader error: %v", i, err)
-		}
-		if err := tw.Close(); err != nil {
-			t.Errorf("test %d, unexpected Close error: %v", i, err)
-		}
-
-		// The prefix field should never appear in the GNU format.
-		var blk block
-		copy(blk[:], b.Bytes())
-		prefix := string(blk.toUSTAR().prefix())
-		prefix, _, _ = strings.Cut(prefix, "\x00") // Truncate at the NUL terminator
-		if blk.getFormat() == FormatGNU && len(prefix) > 0 && strings.HasPrefix(name, prefix) {
-			t.Errorf("test %d, found prefix in GNU format: %s", i, prefix)
-		}
-
-		tr := NewReader(&b)
-		hdr, err := tr.Next()
-		if err != nil {
-			t.Errorf("test %d, unexpected Next error: %v", i, err)
-		}
-		if hdr.Name != name {
-			t.Errorf("test %d, hdr.Name = %s, want %s", i, hdr.Name, name)
-		}
-	}
-}
-
-func TestWriteLongHeader(t *testing.T) {
-	for _, test := range []struct {
-		name string
-		h    *Header
-	}{{
-		name: "name too long",
-		h:    &Header{Name: strings.Repeat("a", maxSpecialFileSize)},
-	}, {
-		name: "linkname too long",
-		h:    &Header{Linkname: strings.Repeat("a", maxSpecialFileSize)},
-	}, {
-		name: "uname too long",
-		h:    &Header{Uname: strings.Repeat("a", maxSpecialFileSize)},
-	}, {
-		name: "gname too long",
-		h:    &Header{Gname: strings.Repeat("a", maxSpecialFileSize)},
-	}, {
-		name: "PAX header too long",
-		h:    &Header{PAXRecords: map[string]string{"GOLANG.x": strings.Repeat("a", maxSpecialFileSize)}},
-	}} {
-		w := NewWriter(io.Discard)
-		if err := w.WriteHeader(test.h); err != ErrFieldTooLong {
-			t.Errorf("%v: w.WriteHeader() = %v, want ErrFieldTooLong", test.name, err)
-		}
-	}
-}
-
-// testNonEmptyWriter wraps an io.Writer and ensures that
-// Write is never called with an empty buffer.
-type testNonEmptyWriter struct{ io.Writer }
-
-func (w testNonEmptyWriter) Write(b []byte) (int, error) {
-	if len(b) == 0 {
-		return 0, errors.New("unexpected empty Write call")
-	}
-	return w.Writer.Write(b)
-}
-
-func TestFileWriter(t *testing.T) {
-	type (
-		testWrite struct { // Write(str) == (wantCnt, wantErr)
-			str     string
-			wantCnt int
-			wantErr error
-		}
-		testReadFrom struct { // ReadFrom(testFile{ops}) == (wantCnt, wantErr)
-			ops     fileOps
-			wantCnt int64
-			wantErr error
-		}
-		testRemaining struct { // logicalRemaining() == wantLCnt, physicalRemaining() == wantPCnt
-			wantLCnt int64
-			wantPCnt int64
-		}
-		testFnc any // testWrite | testReadFrom | testRemaining
-	)
-
-	type (
-		makeReg struct {
-			size    int64
-			wantStr string
-		}
-		makeSparse struct {
-			makeReg makeReg
-			sph     sparseHoles
-			size    int64
-		}
-		fileMaker any // makeReg | makeSparse
-	)
-
-	vectors := []struct {
-		maker fileMaker
-		tests []testFnc
-	}{{
-		maker: makeReg{0, ""},
-		tests: []testFnc{
-			testRemaining{0, 0},
-			testWrite{"", 0, nil},
-			testWrite{"a", 0, ErrWriteTooLong},
-			testReadFrom{fileOps{""}, 0, nil},
-			testReadFrom{fileOps{"a"}, 0, ErrWriteTooLong},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeReg{1, "a"},
-		tests: []testFnc{
-			testRemaining{1, 1},
-			testWrite{"", 0, nil},
-			testWrite{"a", 1, nil},
-			testWrite{"bcde", 0, ErrWriteTooLong},
-			testWrite{"", 0, nil},
-			testReadFrom{fileOps{""}, 0, nil},
-			testReadFrom{fileOps{"a"}, 0, ErrWriteTooLong},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeReg{5, "hello"},
-		tests: []testFnc{
-			testRemaining{5, 5},
-			testWrite{"hello", 5, nil},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeReg{5, "\x00\x00\x00\x00\x00"},
-		tests: []testFnc{
-			testRemaining{5, 5},
-			testReadFrom{fileOps{"\x00\x00\x00\x00\x00"}, 5, nil},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeReg{5, "\x00\x00\x00\x00\x00"},
-		tests: []testFnc{
-			testRemaining{5, 5},
-			testReadFrom{fileOps{"\x00\x00\x00\x00\x00extra"}, 5, ErrWriteTooLong},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeReg{5, "abc\x00\x00"},
-		tests: []testFnc{
-			testRemaining{5, 5},
-			testWrite{"abc", 3, nil},
-			testRemaining{2, 2},
-			testReadFrom{fileOps{"\x00\x00"}, 2, nil},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeReg{5, "\x00\x00abc"},
-		tests: []testFnc{
-			testRemaining{5, 5},
-			testWrite{"\x00\x00", 2, nil},
-			testRemaining{3, 3},
-			testWrite{"abc", 3, nil},
-			testReadFrom{fileOps{"z"}, 0, ErrWriteTooLong},
-			testWrite{"z", 0, ErrWriteTooLong},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeSparse{makeReg{5, "abcde"}, sparseHoles{{2, 3}}, 8},
-		tests: []testFnc{
-			testRemaining{8, 5},
-			testWrite{"ab\x00\x00\x00cde", 8, nil},
-			testWrite{"a", 0, ErrWriteTooLong},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeSparse{makeReg{5, "abcde"}, sparseHoles{{2, 3}}, 8},
-		tests: []testFnc{
-			testWrite{"ab\x00\x00\x00cdez", 8, ErrWriteTooLong},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeSparse{makeReg{5, "abcde"}, sparseHoles{{2, 3}}, 8},
-		tests: []testFnc{
-			testWrite{"ab\x00", 3, nil},
-			testRemaining{5, 3},
-			testWrite{"\x00\x00cde", 5, nil},
-			testWrite{"a", 0, ErrWriteTooLong},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeSparse{makeReg{5, "abcde"}, sparseHoles{{2, 3}}, 8},
-		tests: []testFnc{
-			testWrite{"ab", 2, nil},
-			testRemaining{6, 3},
-			testReadFrom{fileOps{int64(3), "cde"}, 6, nil},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeSparse{makeReg{5, "abcde"}, sparseHoles{{2, 3}}, 8},
-		tests: []testFnc{
-			testReadFrom{fileOps{"ab", int64(3), "cde"}, 8, nil},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeSparse{makeReg{5, "abcde"}, sparseHoles{{2, 3}}, 8},
-		tests: []testFnc{
-			testReadFrom{fileOps{"ab", int64(3), "cdeX"}, 8, ErrWriteTooLong},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeSparse{makeReg{4, "abcd"}, sparseHoles{{2, 3}}, 8},
-		tests: []testFnc{
-			testReadFrom{fileOps{"ab", int64(3), "cd"}, 7, io.ErrUnexpectedEOF},
-			testRemaining{1, 0},
-		},
-	}, {
-		maker: makeSparse{makeReg{4, "abcd"}, sparseHoles{{2, 3}}, 8},
-		tests: []testFnc{
-			testReadFrom{fileOps{"ab", int64(3), "cde"}, 7, errMissData},
-			testRemaining{1, 0},
-		},
-	}, {
-		maker: makeSparse{makeReg{6, "abcde"}, sparseHoles{{2, 3}}, 8},
-		tests: []testFnc{
-			testReadFrom{fileOps{"ab", int64(3), "cde"}, 8, errUnrefData},
-			testRemaining{0, 1},
-		},
-	}, {
-		maker: makeSparse{makeReg{4, "abcd"}, sparseHoles{{2, 3}}, 8},
-		tests: []testFnc{
-			testWrite{"ab", 2, nil},
-			testRemaining{6, 2},
-			testWrite{"\x00\x00\x00", 3, nil},
-			testRemaining{3, 2},
-			testWrite{"cde", 2, errMissData},
-			testRemaining{1, 0},
-		},
-	}, {
-		maker: makeSparse{makeReg{6, "abcde"}, sparseHoles{{2, 3}}, 8},
-		tests: []testFnc{
-			testWrite{"ab", 2, nil},
-			testRemaining{6, 4},
-			testWrite{"\x00\x00\x00", 3, nil},
-			testRemaining{3, 4},
-			testWrite{"cde", 3, errUnrefData},
-			testRemaining{0, 1},
-		},
-	}, {
-		maker: makeSparse{makeReg{3, "abc"}, sparseHoles{{0, 2}, {5, 2}}, 7},
-		tests: []testFnc{
-			testRemaining{7, 3},
-			testWrite{"\x00\x00abc\x00\x00", 7, nil},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeSparse{makeReg{3, "abc"}, sparseHoles{{0, 2}, {5, 2}}, 7},
-		tests: []testFnc{
-			testRemaining{7, 3},
-			testReadFrom{fileOps{int64(2), "abc", int64(1), "\x00"}, 7, nil},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeSparse{makeReg{3, ""}, sparseHoles{{0, 2}, {5, 2}}, 7},
-		tests: []testFnc{
-			testWrite{"abcdefg", 0, errWriteHole},
-		},
-	}, {
-		maker: makeSparse{makeReg{3, "abc"}, sparseHoles{{0, 2}, {5, 2}}, 7},
-		tests: []testFnc{
-			testWrite{"\x00\x00abcde", 5, errWriteHole},
-		},
-	}, {
-		maker: makeSparse{makeReg{3, "abc"}, sparseHoles{{0, 2}, {5, 2}}, 7},
-		tests: []testFnc{
-			testWrite{"\x00\x00abc\x00\x00z", 7, ErrWriteTooLong},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeSparse{makeReg{3, "abc"}, sparseHoles{{0, 2}, {5, 2}}, 7},
-		tests: []testFnc{
-			testWrite{"\x00\x00", 2, nil},
-			testRemaining{5, 3},
-			testWrite{"abc", 3, nil},
-			testRemaining{2, 0},
-			testWrite{"\x00\x00", 2, nil},
-			testRemaining{0, 0},
-		},
-	}, {
-		maker: makeSparse{makeReg{2, "ab"}, sparseHoles{{0, 2}, {5, 2}}, 7},
-		tests: []testFnc{
-			testWrite{"\x00\x00", 2, nil},
-			testWrite{"abc", 2, errMissData},
-			testWrite{"\x00\x00", 0, errMissData},
-		},
-	}, {
-		maker: makeSparse{makeReg{4, "abc"}, sparseHoles{{0, 2}, {5, 2}}, 7},
-		tests: []testFnc{
-			testWrite{"\x00\x00", 2, nil},
-			testWrite{"abc", 3, nil},
-			testWrite{"\x00\x00", 2, errUnrefData},
-		},
-	}}
-
-	for i, v := range vectors {
-		var wantStr string
-		bb := new(bytes.Buffer)
-		w := testNonEmptyWriter{bb}
-		var fw fileWriter
-		switch maker := v.maker.(type) {
-		case makeReg:
-			fw = &regFileWriter{w, maker.size}
-			wantStr = maker.wantStr
-		case makeSparse:
-			if !validateSparseEntries(maker.sph, maker.size) {
-				t.Fatalf("invalid sparse map: %v", maker.sph)
-			}
-			spd := invertSparseEntries(maker.sph, maker.size)
-			fw = &regFileWriter{w, maker.makeReg.size}
-			fw = &sparseFileWriter{fw, spd, 0}
-			wantStr = maker.makeReg.wantStr
-		default:
-			t.Fatalf("test %d, unknown make operation: %T", i, maker)
-		}
-
-		for j, tf := range v.tests {
-			switch tf := tf.(type) {
-			case testWrite:
-				got, err := fw.Write([]byte(tf.str))
-				if got != tf.wantCnt || err != tf.wantErr {
-					t.Errorf("test %d.%d, Write(%s):\ngot  (%d, %v)\nwant (%d, %v)", i, j, tf.str, got, err, tf.wantCnt, tf.wantErr)
-				}
-			case testReadFrom:
-				f := &testFile{ops: tf.ops}
-				got, err := fw.ReadFrom(f)
-				if _, ok := err.(testError); ok {
-					t.Errorf("test %d.%d, ReadFrom(): %v", i, j, err)
-				} else if got != tf.wantCnt || err != tf.wantErr {
-					t.Errorf("test %d.%d, ReadFrom() = (%d, %v), want (%d, %v)", i, j, got, err, tf.wantCnt, tf.wantErr)
-				}
-				if len(f.ops) > 0 {
-					t.Errorf("test %d.%d, expected %d more operations", i, j, len(f.ops))
-				}
-			case testRemaining:
-				if got := fw.logicalRemaining(); got != tf.wantLCnt {
-					t.Errorf("test %d.%d, logicalRemaining() = %d, want %d", i, j, got, tf.wantLCnt)
-				}
-				if got := fw.physicalRemaining(); got != tf.wantPCnt {
-					t.Errorf("test %d.%d, physicalRemaining() = %d, want %d", i, j, got, tf.wantPCnt)
-				}
-			default:
-				t.Fatalf("test %d.%d, unknown test operation: %T", i, j, tf)
-			}
-		}
-
-		if got := bb.String(); got != wantStr {
-			t.Fatalf("test %d, String() = %q, want %q", i, got, wantStr)
-		}
-	}
-}