tar: don't crash if getcwd fails

* src/extract.c: Don't include xgetcwd.h.
(extract_dir): stat "." rather than statting getcwd's output.
* src/misc.c (normalize_filename_x): Rewrite so as not to resolve
/../, which can't be done reliably in the presence of symlinks.
Don't reject valid names such as ".".
(normalize_filename): Don't make it absolute; that way, we don't
have to invoke xgetcwd which might fail.  Don't bother to realloc
at the end, since that uses time and now saves little space.
(chdir_do): Don't crash if xgetcwd fails.
* tests/Makefile.am (TESTSUITE_AT): Add listed03.at.
* tests/listed03.at: New file.
* tests/testsuite.at: Include listed03.at.
This commit is contained in:
Paul R. Eggert
2010-07-15 11:24:39 -07:00
committed by Paul Eggert
parent ab6dd4948d
commit cc40c57a37
5 changed files with 92 additions and 91 deletions

View File

@@ -23,7 +23,6 @@
#include <quotearg.h>
#include <utimens.h>
#include <errno.h>
#include <xgetcwd.h>
#include <priv-set.h>
#include "common.h"
@@ -648,13 +647,11 @@ extract_dir (char *file_name, int typeflag)
if (one_file_system_option && root_device == 0)
{
struct stat st;
char *dir = xgetcwd ();
if (deref_stat (true, dir, &st))
stat_diag (dir);
if (stat (".", &st) != 0)
stat_diag (".");
else
root_device = st.st_dev;
free (dir);
}
if (incremental_option)

View File

@@ -1,7 +1,7 @@
/* Miscellaneous functions, not really specific to GNU tar.
Copyright (C) 1988, 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001,
2003, 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
2003, 2004, 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
@@ -233,99 +233,54 @@ zap_slashes (char *name)
return name;
}
/* Normalize NAME by resolving any relative references and
removing trailing slashes. Destructive version: modifies its argument. */
static int
normalize_filename_x (char *name)
/* Normalize FILE_NAME by removing redundant slashes and "."
components, including redundant trailing slashes. Leave ".."
alone, as it may be significant in the presence of symlinks and on
platforms where "/.." != "/". Destructive version: modifies its
argument. */
static void
normalize_filename_x (char *file_name)
{
char *p, *q;
char *name = file_name + FILE_SYSTEM_PREFIX_LEN (file_name);
char *p;
char const *q;
char c;
p = name;
if (DOUBLE_SLASH_IS_DISTINCT_ROOT && ISSLASH (*p))
p++;
/* Don't squeeze leading "//" to "/", on hosts where they're distinct. */
name += (DOUBLE_SLASH_IS_DISTINCT_ROOT
&& ISSLASH (*name) && ISSLASH (name[1]) && ! ISSLASH (name[2]));
/* Remove /./, resolve /../ and compress sequences of slashes */
for (q = p; *q; )
/* Omit redundant leading "." components. */
for (q = p = name; (*p = *q) == '.' && ISSLASH (q[1]); p += !*q)
for (q += 2; ISSLASH (*q); q++)
continue;
/* Copy components from Q to P, omitting redundant slashes and
internal "." components. */
while ((*p++ = c = *q++) != '\0')
if (ISSLASH (c))
while (ISSLASH (q[*q == '.']))
q += (*q == '.') + 1;
/* Omit redundant trailing "." component and slash. */
if (2 < p - name)
{
if (ISSLASH (*q))
{
*p++ = *q++;
while (ISSLASH (*q))
q++;
continue;
}
else if (p == name)
{
if (*q == '.')
{
if (ISSLASH (q[1]))
{
q += 2;
continue;
}
if (q[1] == '.' && ISSLASH (q[2]))
return 1;
}
}
else
{
if (*q == '.' && ISSLASH (p[-1]))
{
if (ISSLASH (q[1]))
{
q += 2;
while (ISSLASH (*q))
q++;
continue;
}
else if (q[1] == '.' && ISSLASH (q[2]))
{
do
{
--p;
}
while (p > name && !ISSLASH (p[-1]));
q += 3;
continue;
}
}
}
*p++ = *q++;
p -= p[-2] == '.' && ISSLASH (p[-3]);
p -= 2 < p - name && ISSLASH (p[-2]);
p[-1] = '\0';
}
/* Remove trailing slashes */
while (p - 1 > name && ISSLASH (p[-1]))
p--;
*p = 0;
return 0;
}
/* Normalize NAME by resolving any relative references, removing trailing
slashes, and converting it to absolute file name. Return the normalized
name, or NULL in case of error. */
/* Normalize NAME by removing redundant slashes and "." components,
including redundant trailing slashes. Return a normalized
newly-allocated copy. */
char *
normalize_filename (const char *name)
{
char *copy;
if (name[0] != '/')
{
copy = xgetcwd ();
copy = xrealloc (copy, strlen (copy) + strlen (name) + 2);
strcat (copy, "/");
strcat (copy, name);
}
else
copy = xstrdup (name);
if (normalize_filename_x (copy))
{
free (copy);
return NULL;
}
return xrealloc (copy, strlen (copy) + 1);
char *copy = xstrdup (name);
normalize_filename_x (copy);
return copy;
}
@@ -752,6 +707,8 @@ chdir_do (int i)
close (fd1);
prev->saved_cwd.desc = -1;
prev->saved_cwd.name = xgetcwd ();
if (! prev->saved_cwd.name)
err = errno;
}
else
err = errno;

View File

@@ -1,6 +1,6 @@
# Makefile for GNU tar regression tests.
# Copyright (C) 1996, 1997, 1999, 2000, 2001, 2003, 2004, 2005,
# Copyright (C) 1996, 1997, 1999, 2000, 2001, 2003, 2004, 2005,
# 2006, 2007, 2009 Free Software Foundation, Inc.
# François Pinard <pinard@iro.umontreal.ca>, 1988.
@@ -98,6 +98,7 @@ TESTSUITE_AT = \
link03.at\
listed01.at\
listed02.at\
listed03.at\
long01.at\
longv7.at\
lustar01.at\

45
tests/listed03.at Normal file
View File

@@ -0,0 +1,45 @@
# Process this file with autom4te to create testsuite. -*- Autotest -*-
# Test suite for GNU tar.
# Copyright (C) 2010 Free Software Foundation, Inc.
# This program 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, or (at your option)
# any later version.
# This program 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 <http://www.gnu.org/licenses/>.
# This checks for the --listed-incremental bug reported by J Chapman Flack at
# http://lists.gnu.org/archive/html/bug-tar/2010-06/msg00000.html
AT_SETUP([incremental dump when the parent directory is unreadable])
AT_KEYWORDS([listed incremental listed03])
AT_TAR_CHECK([
mkdir dir
mkdir dir/sub
mkdir dir/sub/a
genfile --file dir/sub/a/file
cd dir/sub
chmod a-r ..
tar -c -f archive.tar --listed-incremental=db.1 -v a
status=$?
chmod a+r ..
exit $status
],
[0],
[a/
a/file
],
[tar: a: Directory is new
],[],[],[gnu])
AT_CLEANUP

View File

@@ -41,13 +41,13 @@ $1)],$2,$3,$4,$5,$6)
m4_define([AT_TAR_WITH_HOOK],[
m4_pushdef([AT_TAR_CHECK_HOOK],[$1])
$2
m4_popdef([AT_TAR_CHECK_HOOK])])
m4_define([TAR_IGNREC_HOOK],[
AT_CHECK([grep -v '^.*tar: Record size = ' stderr; exit 0])
])
m4_define([RE_CHECK],[
AT_DATA([$1.re],[$2])
awk '{print NR " " $[]0}' $1 > $[]$.1
@@ -162,6 +162,7 @@ m4_include([incr01.at])
m4_include([incr02.at])
m4_include([listed01.at])
m4_include([listed02.at])
m4_include([listed03.at])
m4_include([incr03.at])
m4_include([incr04.at])
m4_include([incr05.at])