From: Sergey Poznyakoff Date: Mon, 12 May 2025 14:17:21 +0000 (+0300) Subject: Handle directory members consistently when listing and when extracting. X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=b009124ffde415515081db844d7a104e1d1c6c58;p=thirdparty%2Ftar.git Handle directory members consistently when listing and when extracting. * src/list.c (skim_member): Recognize directory members using the same rules as during extraction. * tests/skipdir.at: New testcase. * tests/testsuite.at: Add new test. * tests/Makefile.am: Likewise. --- diff --git a/src/list.c b/src/list.c index ed901909..fc1b10ce 100644 --- a/src/list.c +++ b/src/list.c @@ -1414,6 +1414,23 @@ skip_member (void) skim_member (false); } +static bool +member_is_dir (struct tar_stat_info *info, char typeflag) +{ + switch (typeflag) { + case AREGTYPE: + case REGTYPE: + case CONTTYPE: + return info->had_trailing_slash; + + case DIRTYPE: + return true; + + default: + return false; + } +} + /* Skip the current member in the archive. If MUST_COPY, always copy instead of skipping. */ void @@ -1421,14 +1438,15 @@ skim_member (bool must_copy) { if (!current_stat_info.skipped) { - char save_typeflag = current_header->header.typeflag; + bool is_dir = member_is_dir (¤t_stat_info, + current_header->header.typeflag); set_next_block_after (current_header); mv_begin_read (¤t_stat_info); if (current_stat_info.is_sparse) sparse_skim_file (¤t_stat_info, must_copy); - else if (save_typeflag != DIRTYPE) + else if (!is_dir) skim_file (current_stat_info.stat.st_size, must_copy); mv_end (); diff --git a/tests/Makefile.am b/tests/Makefile.am index 03ae9767..aaa97211 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -245,6 +245,7 @@ TESTSUITE_AT = \ shortrec.at\ shortupd.at\ sigpipe.at\ + skipdir.at\ sparse01.at\ sparse02.at\ sparse03.at\ diff --git a/tests/skipdir.at b/tests/skipdir.at new file mode 100644 index 00000000..7106ee74 --- /dev/null +++ b/tests/skipdir.at @@ -0,0 +1,56 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- + +# Test suite for GNU tar. +# Copyright 2025 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 . + +# Description: determining member type when listing and extracting +# should follow the same principles. +# +# Until version 1.35 the same archive member could have been processed +# as a directory when extracting and as a regular file when being +# skipped during listing. +# +# References: https://savannah.gnu.org/patch/index.php?10100 + +AT_SETUP([skip directory members]) +AT_KEYWORDS([skipdir]) +AT_DATA([archive.in], +[/Td6WFoAAATm1rRGAgAhARwAAAAQz1jM4Cf/AG1dADedyh4ubnxHHIi7Cen6orusgKqY3paKeQwp +3//HS9EIT7Hm+MsndXfRntXVt8mu8oDpLOfC+AB9VldyCtp2jqOfTwa455qfGAcONPn6WWDgsaAh +O2Y6ptXuaF/vdaNkub7SkOBME8jHYITT5QAAAAAAHtdcflb5Zw8AAYkBgFAAAPYgb0axxGf7AgAA +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([tar tf archive.tar], +[0], +[owo1/ +owo2/ +]) +AT_CHECK([tar vxf archive.tar], +[0], +[owo1/ +owo2/ +]) +AT_CHECK([tar -xvf archive.tar --exclude owo1], +[0], +[owo2/ +]) +AT_CLEANUP diff --git a/tests/testsuite.at b/tests/testsuite.at index ff38dda6..9eda62d4 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -470,7 +470,7 @@ AT_BANNER([Volume operations]) m4_include([volume.at]) m4_include([volsize.at]) -AT_BANNER() +AT_BANNER([Various tests]) m4_include([comprec.at]) m4_include([shortfile.at]) m4_include([shortupd.at]) @@ -479,6 +479,7 @@ m4_include([truncate.at]) m4_include([grow.at]) m4_include([sigpipe.at]) m4_include([comperr.at]) +m4_include([skipdir.at]) AT_BANNER([Removing files after archiving]) m4_include([remfiles01.at])