diff --git a/NEWS b/NEWS index 501cfee3..8e18040d 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -GNU tar NEWS - User visible changes. 2026-04-04 +GNU tar NEWS - User visible changes. 2026-06-20 Please send GNU tar bug reports to version 1.35.90 (git) @@ -73,6 +73,11 @@ option. ** tar --ignore-failed-read no longer complains about a file removed before reading. +** tar no longer behaves erratically when reading nonzero size fields + in archive headers representing special files, fifos, and symlinks. + Although these size fields are typically zero, POSIX allows some to + be nonzero, and in practice they do not count data blocks. + * Performance improvements ** Sparse files are now read and written with larger blocksizes. diff --git a/THANKS b/THANKS index 8c5c99d9..fcf35695 100644 --- a/THANKS +++ b/THANKS @@ -39,6 +39,7 @@ Andrey A. Chernov ache@astral.msk.su Andy Gay andy@rdl.co.uk Anthony G. Basile blueness@gentoo.org Antonio Jose Coutinho ajc@di.uminho.pt +Antonio Teixeira antonio.teixeira@suse.com Ariel Faigon ariel@engr.sgi.com Arne Wichmann aw@math.uni-sb.de Arnold Robbins arnold@gnu.org diff --git a/src/list.c b/src/list.c index 5ab6de42..1c992cf4 100644 --- a/src/list.c +++ b/src/list.c @@ -535,6 +535,22 @@ read_header (union block **return_block, struct tar_stat_info *info, struct posix_header const *h = &header->header; char namebuf[sizeof h->prefix + 1 + NAME_FIELD_SIZE + 1]; + switch (h->typeflag) + { + /* For these file types, although POSIX does not specify the + meaning of the size, it does say there should be no data, + so treat the size as zero. */ + case BLKTYPE: case CHRTYPE: case FIFOTYPE: + + /* For these file types, POSIX requires that the size be zero. + Be generous and accept any size as zero, as some + nonconforming programs generate nonzero size fields along + with no data. */ + case LNKTYPE: case SYMTYPE: + + info->stat.st_size = 0; + } + free (recent_long_name); if (next_long_name) diff --git a/tests/Makefile.am b/tests/Makefile.am index 103c6de7..4f666b09 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -143,6 +143,7 @@ TESTSUITE_AT = \ extrac31.at\ extrac32.at\ extrac33.at\ + extrac34.at\ filerem01.at\ filerem02.at\ filerem03.at\ diff --git a/tests/extrac32.at b/tests/extrac32.at index d3505fdb..af40916d 100644 --- a/tests/extrac32.at +++ b/tests/extrac32.at @@ -36,11 +36,13 @@ base64 -d < archive.in | xz -c -d > archive.tar AT_CHECK([tar tf archive.tar], [0], [carrier_entry +injected.txt marker.txt ]) AT_CHECK([tar xvf archive.tar], [0], [carrier_entry +injected.txt marker.txt ]) AT_CLEANUP diff --git a/tests/extrac34.at b/tests/extrac34.at new file mode 100644 index 00000000..1cedb463 --- /dev/null +++ b/tests/extrac34.at @@ -0,0 +1,40 @@ +# Check hard link with nonzero size field in tarball. -*- Autotest -*- + +# Copyright 2026 Free Software Foundation, Inc. + +# This file is part of GNU tar. + +# GNU tar is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# GNU tar is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Check extracting from a nonconforming tarball that has +# a hard link with nonzero size. + +AT_SETUP([hard link with a nonzero size field]) +AT_KEYWORDS([extract extrac34 hard link]) +AT_DATA([archive.in], +[/Td6WFoAAATm1rRGBMBwgFAhARwAAAAAAAAAAAbKrCjgJ/8AaF0AMIAzUBhoiawFdYeRen4lxlj0 +QWRLpUM+28ArRsXVY5bGv4H5kijsqiJ4Z9YIVhZd01+IppF+AkltS60aB8fuUW35Tp/3XzUx9Mq2 +4ypJFzvcgHXsSIvc9L+mmTDuHzhvJQ/oe7ya8QAASbOfD7CgZcIAAYwBgFAAAEWxohaxxGf7AgAA +AAAEWVo= +]) +AT_CHECK([base64 --help >/dev/null 2>&1 || AT_SKIP_TEST +xz --help >/dev/null 2>&1 || AT_SKIP_TEST +base64 -d < archive.in | xz -c -d > archive.tar +]) +AT_CHECK([mkdir dir +]) +AT_CHECK([tar -C dir -xf archive.tar || exit 1 +cmp dir/a dir/b +]) +AT_CLEANUP diff --git a/tests/testsuite.at b/tests/testsuite.at index 70d36a5a..ab30c2ab 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -360,6 +360,7 @@ m4_include([extrac30.at]) m4_include([extrac31.at]) m4_include([extrac32.at]) m4_include([extrac33.at]) +m4_include([extrac34.at]) m4_include([backup01.at])