Working draft

K04 name-empty-with-prefix

A regular file with an empty name and a prefix: dir/, or no name?

Reject(draft) A strict parser must reject this archive.

Category
kind
Default policy
rejects it
Files
K04-name-empty-with-prefix.tar test archive, 1,536 bytes sha256 51f1f37dece16a4bad30bfeacaabd9ec71be6f3504d81ad9ea98f40ddfeef2e9
K04-name-empty-with-prefix.jsonexpected result
K04-name-empty-with-prefix.txtannotated blocks
K04-name-empty-with-prefix.pygenerator script

The case

The archive has one regular file, of typeflag 0, with size 0, an empty name field and the prefix dir.

In POSIX, the pathname is the prefix, followed by /, followed by the name, which here is empty, so the pathname is dir/. A member is extracted as a file of its own type, here a regular file, but a name that ends in a slash resolves only to a directory, so this is an error. A name that ends in a slash was the old way to archive a directory, before the typeflag of a directory existed. This case is ambiguous in practice because the member is either a directory dir, by its trailing slash, an empty file dir, by its typeflag, or no file at all, if the empty name field is taken for a missing name before the prefix is applied.

Decision point: whether a prefix makes a name of an empty name field, and whether the typeflag or the trailing slash decides the kind.

Seen in: 7 tarballs have a regular file whose name ends in a slash, such as sendmail 8.18.2, all in the name field; none has an empty name with a prefix.

The archive

Every block of 512 bytes, to scale, with its offset. Hover over a field for its bytes.

K04-name-empty-with-prefix: every block of the archive0x000000header: regular file, an empty name, and the prefix dirname [0,100): 100 NULnamemode [100,108): "0000644" + NUL, 644 (octal)uid [108,116): "0000000" + NUL, 0gid [116,124): "0000000" + NUL, 0size [124,136): "00000000000" + NUL, 0mtime [136,148): "00000000000" + NUL, 0chksum [148,156): "007674\0 ", 4028: the unsigned sum of the header, this field as spacestypeflag [156,157): "0", regular filelinkname [157,257): 100 NULlinknamemagic [257,263): "ustar" + NULversion [263,265): "00"uname [265,297): 32 NULunamegname [297,329): 32 NULgnamedevmajor [329,337): "0000000" + NUL, 0devminor [337,345): "0000000" + NUL, 0prefix [345,500): "dir" + 152 NULprefixpad [500,512): 12 NULprefix "dir" + 152 NUL0x0002002 zero blocks: the end-of-archive markerbytes 0 to 512 of 1024: 512 NUL0x0004002 zero blocks, continuedbytes 512 to 1024 of 1024: 512 NUL0x000600end of fileNULprintable ASCIIspacecontrol character, such as a newlinebyte over 0x7fwritten by the case itself
Every block, as text
K04-name-empty-with-prefix: must reject

A regular file with an empty name and a prefix: `dir/`, or no name?

The archive has one regular file, of typeflag `0`, with size 0, an empty name field and the prefix
`dir`.

In POSIX, the pathname is the prefix, followed by `/`, followed by the name, which here is
empty, so the pathname is `dir/`. A member is extracted as a file of its own type, here
a regular file, but a name that ends in a slash resolves only to a directory, so
this is an error. A name that ends in a slash was the old way
to archive a directory, before the typeflag of a directory existed. This case is ambiguous in
practice because the member is either a directory `dir`, by its trailing slash, an empty file `dir`,
by its typeflag, or no file at all, if the empty name field is taken for a missing name before the
prefix is applied.

Decision point: whether a prefix makes a name of an empty name field, and whether the typeflag or
the trailing slash decides the kind.
Seen in: 7 tarballs have a regular file whose name ends in a slash, such as sendmail 8.18.2, all in
the name field; none has an empty name with a prefix.
See also: K01, a regular file whose name ends in a slash, and N17, an empty name.

0x000000  header: regular file, an empty name, and the prefix dir
          name     [  0,100)  100 NUL
          mode     [100,108)  "0000644" + NUL  644 (octal)
          uid      [108,116)  "0000000" + NUL  0
          gid      [116,124)  "0000000" + NUL  0
          size     [124,136)  "00000000000" + NUL  0
          mtime    [136,148)  "00000000000" + NUL  0
          chksum   [148,156)  "007674\0 "  4028: the unsigned sum of the header, this field as spaces
          typeflag [156,157)  "0"  regular file
          linkname [157,257)  100 NUL
          magic    [257,263)  "ustar" + NUL
          version  [263,265)  "00"
          uname    [265,297)  32 NUL
          gname    [297,329)  32 NUL
          devmajor [329,337)  "0000000" + NUL  0
          devminor [337,345)  "0000000" + NUL  0
          prefix   [345,500)  "dir" + 152 NUL
          pad      [500,512)  12 NUL
0x000200  2 zero blocks: the end-of-archive marker
0x000600  end of file
Every byte, as a hex dump

As xxd writes it: xxd -r makes the archive of it.

00000000: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000010: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000020: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000030: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000040: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000060: 0000 0000 3030 3030 3634 3400 3030 3030  ....0000644.0000
00000070: 3030 3000 3030 3030 3030 3000 3030 3030  000.0000000.0000
00000080: 3030 3030 3030 3000 3030 3030 3030 3030  0000000.00000000
00000090: 3030 3000 3030 3736 3734 0020 3000 0000  000.007674. 0...
000000a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000f0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000100: 0075 7374 6172 0030 3000 0000 0000 0000  .ustar.00.......
00000110: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000120: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000130: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000140: 0000 0000 0000 0000 0030 3030 3030 3030  .........0000000
00000150: 0030 3030 3030 3030 0064 6972 0000 0000  .0000000.dir....
00000160: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000170: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000180: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000190: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001f0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000200: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000210: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000220: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000230: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000240: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000250: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000260: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000270: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000280: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000290: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000002a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000002b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000002c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000002d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000002e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000002f0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000300: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000310: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000320: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000330: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000340: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000350: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000360: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000370: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000380: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000390: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000003a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000003b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000003c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000003d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000003e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000003f0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000400: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000410: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000420: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000430: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000440: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000450: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000460: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000470: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000480: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000490: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000004a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000004b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000004c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000004d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000004e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000004f0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000500: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000510: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000520: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000530: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000540: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000550: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000560: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000570: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000580: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000590: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000005a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000005b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000005c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000005d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000005e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000005f0: 0000 0000 0000 0000 0000 0000 0000 0000  ................

What implementations make of it

In the outcome column, ✅ means that the implementation follows the default policy.

implementationversionoutcomewhat it makes of it
GNU tartar (GNU tar) 1.35⚠️ acceptstree A: dir/
bsdtarbsdtar 3.8.11 - libarchive 3.8.11⚠️ acceptstree A: dir/
BusyBox tarBusyBox v1.38.0, defconfig⚠️ acceptstree A: dir/
7-Zip7-Zip (z) 26.05 (x64)⚠️ acceptstree A: dir/
Python tarfile, filter=data, as in pipCPython 3.15.2⚠️ acceptstree B: dir (0 B, e3b0c442)
Python tarfile, filter=tarCPython 3.15.2⚠️ acceptstree B: dir (0 B, e3b0c442)
Python tarfile, filter=fully_trustedCPython 3.15.2⚠️ acceptstree B: dir (0 B, e3b0c442)
node-tartar 7.5.22⚠️ acceptstree B: dir (0 B, e3b0c442)
node-tar, stricttar 7.5.22⚠️ acceptstree B: dir (0 B, e3b0c442)
tar-fstar-fs 3.1.3, on tar-stream 3.2.2✅ rejectserror: Error: EISDIR: illegal operation on a directory, open 'DEST/dir/'
Java Commons CompressCommons Compress 1.28.0, Expander, on Java 27.0.1.0.2⚠️ acceptstree A: dir/
.NET System.Formats.TarSystem.Formats.Tar of .NET 10.0.14, ExtractToDirectory✅ rejectserror: IOException: Cannot create 'DEST/dir/' because a file or directory with the same name already exists.
PHP PharData, as in ComposerPharData of PHP 8.5.12, as Composer's TarDownloader calls it⚠️ acceptstree B: dir (0 B, e3b0c442)
Go containerd archive.Applycontainerd v2.4.2, archive.Apply, of go1.27.3⚠️ acceptstree B: dir (0 B, e3b0c442)
Rust tartar 0.4.46, unpack⚠️ acceptstree B: dir (0 B, e3b0c442)
Rust astral-tokio-tarastral-tokio-tar 0.7.1, unpack⚠️ acceptstree B: dir (0 B, e3b0c442)
Rust tar-codec, as in uvtar-codec 0.0.16, with the policies of uv 0.13✅ rejectserror: at byte 0: unsafe member path "dir/": only a directory may have a directory-required path suffix
RubyGemsRubyGems 4.0.20 of Ruby 4.0.9, extract_tar_gz⚠️ acceptstree B: dir (0 B, e3b0c442)
R untar, internalutils::untar of R 4.6.2, tar = "internal"⚠️ acceptstree B: dir (0 B, e3b0c442)
Perl Archive::TarArchive::Tar 3.12 of Perl v5.44.0✅ rejectserror: status 1
Haskell tartar 0.7.2.0, extract, of GHC 9.14⚠️ acceptstree B: dir (0 B, e3b0c442)
Julia Tar.jlTar 1.10.0 of Julia 1.13.3✅ rejectserror: non-directory path ending with '/' Tar.Header("dir/", :file, 0o644, 0, "")
live-bootstrap untarmescc-tools-extra a151c245e512, as live-bootstrap pins it⚠️ acceptstree C: nothing
live-bootstrap untar, --non-strictmescc-tools-extra a151c245e512, as live-bootstrap pins it⚠️ acceptstree C: nothing

Prevalence in release tarballs

The table below shows how many release tarballs have the features of this test case. The default policy rejects all of them.

ecosystemtarballswith itshare
Spack37,5532<0.01%
nixpkgs18,99040.02%
Guix10,1681<0.01%
PyPI10,0000none
crates.io5,0000none
RubyGems5,00010.02%
live-bootstrap1710none
total (distinct)82,5867<0.01%

See the list of these 7 tarballs, with the sha256 of each and an example from it.

See also