X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fcompare.c;h=d29cfdd4822f683dec5c7dfb8dc01544c62330ce;hb=c48f4e8f6c849247022c3de8137b1c62f2496cba;hp=d0cf5f7d6c04963bc96928ab0c975b32d87b7af3;hpb=d769b724f437711d08f00682a0af3a63937ad407;p=chaz%2Ftar
diff --git a/src/compare.c b/src/compare.c
index d0cf5f7..d29cfdd 100644
--- a/src/compare.c
+++ b/src/compare.c
@@ -1,23 +1,24 @@
/* Diff files from a tar archive.
- Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
- 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ Copyright 1988, 1992-1994, 1996-1997, 1999-2001, 2003-2007,
+ 2009-2010, 2012-2014 Free Software Foundation, Inc.
- Written by John Gilmore, on 1987-04-30.
+ This file is part of GNU tar.
- 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.
+ 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.
- 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.
+ 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, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+ Written by John Gilmore, on 1987-04-30. */
#include
#include
@@ -66,8 +67,7 @@ report_difference (struct tar_stat_info *st, const char *fmt, ...)
fprintf (stdlis, "\n");
}
- if (exit_status == TAREXIT_SUCCESS)
- exit_status = TAREXIT_DIFFERS;
+ set_exit_status (TAREXIT_DIFFERS);
}
/* Take a buffer returned by read_and_process and do nothing with it. */
@@ -81,7 +81,7 @@ process_noop (size_t size __attribute__ ((unused)),
static int
process_rawdata (size_t bytes, char *buffer)
{
- size_t status = safe_read (diff_handle, diff_buffer, bytes);
+ size_t status = blocking_read (diff_handle, diff_buffer, bytes);
if (status != bytes)
{
@@ -123,7 +123,7 @@ read_and_process (struct tar_stat_info *st, int (*processor) (size_t, char *))
size_t data_size;
off_t size = st->stat.st_size;
- mv_begin (st);
+ mv_begin_read (st);
while (size)
{
data_block = find_next_block ();
@@ -152,7 +152,7 @@ read_and_process (struct tar_stat_info *st, int (*processor) (size_t, char *))
static int
get_stat_data (char const *file_name, struct stat *stat_data)
{
- int status = deref_stat (dereference_option, file_name, stat_data);
+ int status = deref_stat (file_name, stat_data);
if (status != 0)
{
@@ -218,12 +218,7 @@ diff_file (void)
}
else
{
- int atime_flag =
- (atime_preserve_option == system_atime_preserve
- ? O_NOATIME
- : 0);
-
- diff_handle = open (file_name, O_RDONLY | O_BINARY | atime_flag);
+ diff_handle = openat (chdir_fd, file_name, open_read_flags);
if (diff_handle < 0)
{
@@ -240,12 +235,12 @@ diff_file (void)
else
read_and_process (¤t_stat_info, process_rawdata);
- if (atime_preserve_option == replace_atime_preserve)
+ if (atime_preserve_option == replace_atime_preserve
+ && stat_data.st_size != 0)
{
- struct timespec ts[2];
- ts[0] = get_stat_atime (&stat_data);
- ts[1] = get_stat_mtime (&stat_data);
- if (set_file_atime (diff_handle, file_name, ts) != 0)
+ struct timespec atime = get_stat_atime (&stat_data);
+ if (set_file_atime (diff_handle, chdir_fd, file_name, atime)
+ != 0)
utime_error (file_name);
}
@@ -278,7 +273,8 @@ diff_symlink (void)
size_t len = strlen (current_stat_info.link_name);
char *linkbuf = alloca (len + 1);
- int status = readlink (current_stat_info.file_name, linkbuf, len + 1);
+ int status = readlinkat (chdir_fd, current_stat_info.file_name,
+ linkbuf, len + 1);
if (status < 0)
{
@@ -332,7 +328,7 @@ static int
dumpdir_cmp (const char *a, const char *b)
{
size_t len;
-
+
while (*a)
switch (*a)
{
@@ -346,7 +342,7 @@ dumpdir_cmp (const char *a, const char *b)
a += len;
b += len;
break;
-
+
case 'D':
if (strcmp(a, b))
return 1;
@@ -354,7 +350,7 @@ dumpdir_cmp (const char *a, const char *b)
a += len;
b += len;
break;
-
+
case 'R':
case 'T':
case 'X':
@@ -364,31 +360,38 @@ dumpdir_cmp (const char *a, const char *b)
}
static void
-diff_dumpdir (void)
+diff_dumpdir (struct tar_stat_info *dir)
{
- char *dumpdir_buffer;
- dev_t dev = 0;
- struct stat stat_data;
+ const char *dumpdir_buffer;
- if (deref_stat (true, current_stat_info.file_name, &stat_data))
+ if (dir->fd == 0)
{
- if (errno == ENOENT)
- stat_warn (current_stat_info.file_name);
+ void (*diag) (char const *) = NULL;
+ int fd = subfile_open (dir->parent, dir->orig_file_name, open_read_flags);
+ if (fd < 0)
+ diag = open_diag;
+ else if (fstat (fd, &dir->stat))
+ {
+ diag = stat_diag;
+ close (fd);
+ }
else
- stat_error (current_stat_info.file_name);
+ dir->fd = fd;
+ if (diag)
+ {
+ file_removed_diag (dir->orig_file_name, false, diag);
+ return;
+ }
}
- else
- dev = stat_data.st_dev;
-
- dumpdir_buffer = get_directory_contents (current_stat_info.file_name, dev);
+ dumpdir_buffer = directory_contents (scan_directory (dir));
if (dumpdir_buffer)
{
- if (dumpdir_cmp (current_stat_info.dumpdir, dumpdir_buffer))
- report_difference (¤t_stat_info, _("Contents differ"));
+ if (dumpdir_cmp (dir->dumpdir, dumpdir_buffer))
+ report_difference (dir, _("Contents differ"));
}
else
- read_and_process (¤t_stat_info, process_noop);
+ read_and_process (dir, process_noop);
}
static void
@@ -415,14 +418,17 @@ diff_multivol (void)
}
offset = OFF_FROM_HEADER (current_header->oldgnu_header.offset);
- if (stat_data.st_size != current_stat_info.stat.st_size + offset)
+ if (offset < 0
+ || INT_ADD_OVERFLOW (current_stat_info.stat.st_size, offset)
+ || stat_data.st_size != current_stat_info.stat.st_size + offset)
{
report_difference (¤t_stat_info, _("Size differs"));
skip_member ();
return;
}
- fd = open (current_stat_info.file_name, O_RDONLY | O_BINARY);
+
+ fd = openat (chdir_fd, current_stat_info.file_name, open_read_flags);
if (fd < 0)
{
@@ -436,10 +442,9 @@ diff_multivol (void)
{
seek_error_details (current_stat_info.file_name, offset);
report_difference (¤t_stat_info, NULL);
- return;
}
-
- read_and_process (¤t_stat_info, process_rawdata);
+ else
+ read_and_process (¤t_stat_info, process_rawdata);
status = close (fd);
if (status != 0)
@@ -452,7 +457,6 @@ diff_archive (void)
{
set_next_block_after (current_header);
- decode_header (current_header, ¤t_stat_info, ¤t_format, 1);
/* Print the block from current_header and current_stat_info. */
@@ -460,13 +464,13 @@ diff_archive (void)
{
if (now_verifying)
fprintf (stdlis, _("Verify "));
- print_header (¤t_stat_info, -1);
+ print_header (¤t_stat_info, current_header, -1);
}
switch (current_header->header.typeflag)
{
default:
- ERROR ((0, 0, _("%s: Unknown file type `%c', diffed as normal file"),
+ ERROR ((0, 0, _("%s: Unknown file type '%c', diffed as normal file"),
quotearg_colon (current_stat_info.file_name),
current_header->header.typeflag));
/* Fall through. */
@@ -503,7 +507,7 @@ diff_archive (void)
case GNUTYPE_DUMPDIR:
case DIRTYPE:
if (is_dumpdir (¤t_stat_info))
- diff_dumpdir ();
+ diff_dumpdir (¤t_stat_info);
diff_dir ();
break;
@@ -518,13 +522,24 @@ diff_archive (void)
void
verify_volume (void)
{
+ int may_fail = 0;
if (removed_prefixes_p ())
{
WARN((0, 0,
_("Archive contains file names with leading prefixes removed.")));
+ may_fail = 1;
+ }
+ if (transform_program_p ())
+ {
WARN((0, 0,
- _("Verification may fail to locate original files.")));
+ _("Archive contains transformed file names.")));
+ may_fail = 1;
}
+ if (may_fail)
+ WARN((0, 0,
+ _("Verification may fail to locate original files.")));
+
+ clear_directory_table ();
if (!diff_buffer)
diff_init ();
@@ -578,7 +593,9 @@ verify_volume (void)
flush_read ();
while (1)
{
- enum read_header status = read_header (false);
+ enum read_header status = read_header (¤t_header,
+ ¤t_stat_info,
+ read_header_auto);
if (status == HEADER_FAILURE)
{
@@ -588,7 +605,8 @@ verify_volume (void)
{
counter++;
set_next_block_after (current_header);
- status = read_header (false);
+ status = read_header (¤t_header, ¤t_stat_info,
+ read_header_auto);
}
while (status == HEADER_FAILURE);
@@ -597,9 +615,27 @@ verify_volume (void)
"VERIFY FAILURE: %d invalid headers detected",
counter), counter));
}
- if (status == HEADER_ZERO_BLOCK || status == HEADER_END_OF_FILE)
+ if (status == HEADER_END_OF_FILE)
break;
+ if (status == HEADER_ZERO_BLOCK)
+ {
+ set_next_block_after (current_header);
+ if (!ignore_zeros_option)
+ {
+ char buf[UINTMAX_STRSIZE_BOUND];
+
+ status = read_header (¤t_header, ¤t_stat_info,
+ read_header_auto);
+ if (status == HEADER_ZERO_BLOCK)
+ break;
+ WARNOPT (WARN_ALONE_ZERO_BLOCK,
+ (0, 0, _("A lone zero block at %s"),
+ STRINGIFY_BIGINT (current_block_ordinal (), buf)));
+ }
+ continue;
+ }
+ decode_header (current_header, ¤t_stat_info, ¤t_format, 1);
diff_archive ();
tar_stat_destroy (¤t_stat_info);
}