/* Diff files from a tar archive.
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
- 2003 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
Written by John Gilmore, on 1987-04-30.
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.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
-#include "system.h"
-
-#if HAVE_UTIME_H
-# include <utime.h>
-#else
-struct utimbuf
- {
- long actime;
- long modtime;
- };
-#endif
+#include <system.h>
+#include <system-ioctl.h>
#if HAVE_LINUX_FD_H
# include <linux/fd.h>
#endif
-#include <quotearg.h>
-
#include "common.h"
-#include "rmt.h"
-
-/* Spare space for messages, hopefully safe even after gettext. */
-#define MESSAGE_BUFFER_SIZE 100
+#include <quotearg.h>
+#include <rmt.h>
+#include <stdarg.h>
/* Nonzero if we are verifying at the moment. */
bool now_verifying;
void
diff_init (void)
{
- diff_buffer = valloc (record_size);
- if (!diff_buffer)
- xalloc_die ();
+ void *ptr;
+ diff_buffer = page_aligned_alloc (&ptr, record_size);
+ if (listed_incremental_option)
+ read_directory_file ();
}
/* Sigh about something that differs by writing a MESSAGE to stdlis,
given MESSAGE is nonzero. Also set the exit status if not already. */
-static void
-report_difference (const char *message)
+void
+report_difference (struct tar_stat_info *st, const char *fmt, ...)
{
- if (message)
- fprintf (stdlis, "%s: %s\n", quotearg_colon (current_stat_info.file_name), message);
+ if (fmt)
+ {
+ va_list ap;
+
+ fprintf (stdlis, "%s: ", quotearg_colon (st->file_name));
+ va_start (ap, fmt);
+ vfprintf (stdlis, fmt, ap);
+ va_end (ap);
+ fprintf (stdlis, "\n");
+ }
if (exit_status == TAREXIT_SUCCESS)
exit_status = TAREXIT_DIFFERS;
/* Take a buffer returned by read_and_process and do nothing with it. */
static int
-process_noop (size_t size, char *data)
+process_noop (size_t size __attribute__ ((unused)),
+ char *data __attribute__ ((unused)))
{
- /* Yes, I know. SIZE and DATA are unused in this function. Some
- compilers may even report it. That's OK, just relax! */
return 1;
}
static int
process_rawdata (size_t bytes, char *buffer)
{
- ssize_t status = safe_read (diff_handle, diff_buffer, bytes);
- char message[MESSAGE_BUFFER_SIZE];
+ size_t status = safe_read (diff_handle, diff_buffer, bytes);
if (status != bytes)
{
- if (status < 0)
+ if (status == SAFE_READ_ERROR)
{
read_error (current_stat_info.file_name);
- report_difference (0);
+ report_difference (¤t_stat_info, NULL);
}
else
{
- sprintf (message, _("Could only read %lu of %lu bytes"),
- (unsigned long) status, (unsigned long) bytes);
- report_difference (message);
+ report_difference (¤t_stat_info,
+ ngettext ("Could only read %lu of %lu byte",
+ "Could only read %lu of %lu bytes",
+ bytes),
+ (unsigned long) status, (unsigned long) bytes);
}
return 0;
}
if (memcmp (buffer, diff_buffer, bytes))
{
- report_difference (_("Contents differ"));
+ report_difference (¤t_stat_info, _("Contents differ"));
return 0;
}
{
if (memcmp (buffer, dumpdir_cursor, bytes))
{
- report_difference (_("Contents differ"));
+ report_difference (¤t_stat_info, _("Contents differ"));
return 0;
}
address of the chunk it can work with. The PROCESSOR should return
nonzero for success. It it return error once, continue skipping
without calling PROCESSOR anymore. */
+
static void
-read_and_process (off_t size, int (*processor) (size_t, char *))
+read_and_process (struct tar_stat_info *st, int (*processor) (size_t, char *))
{
union block *data_block;
size_t data_size;
+ size_t size = st->stat.st_size;
- if (multi_volume_option)
- save_sizeleft = size;
+ mv_begin (st);
while (size)
{
data_block = find_next_block ();
set_next_block_after ((union block *)
(data_block->buffer + data_size - 1));
size -= data_size;
- if (multi_volume_option)
- save_sizeleft -= data_size;
+ mv_size_left (size);
}
+ mv_end ();
}
-/* JK Diff'ing a sparse file with its counterpart on the tar file is a
- bit of a different story than a normal file. First, we must know what
- areas of the file to skip through, i.e., we need to construct a
- sparsearray, which will hold all the information we need. We must
- compare small amounts of data at a time as we find it. */
-
-/* FIXME: This does not look very solid to me, at first glance. Zero areas
- are not checked, spurious sparse entries seemingly goes undetected, and
- I'm not sure overall identical sparsity is verified. */
-
-static void
-diff_sparse_files (void)
+/* Call either stat or lstat over STAT_DATA, depending on
+ --dereference (-h), for a file which should exist. Diagnose any
+ problem. Return nonzero for success, zero otherwise. */
+static int
+get_stat_data (char const *file_name, struct stat *stat_data)
{
- off_t remaining_size = current_stat_info.stat.st_size;
- char *buffer = xmalloc (BLOCKSIZE * sizeof (char));
- size_t buffer_size = BLOCKSIZE;
- union block *data_block = 0;
- int counter = 0;
- int different = 0;
-
- if (! fill_in_sparse_array ())
- fatal_exit ();
+ int status = deref_stat (dereference_option, file_name, stat_data);
- while (remaining_size > 0)
+ if (status != 0)
{
- ssize_t status;
- size_t chunk_size;
- off_t offset;
+ if (errno == ENOENT)
+ stat_warn (file_name);
+ else
+ stat_error (file_name);
+ report_difference (¤t_stat_info, NULL);
+ return 0;
+ }
-#if 0
- off_t amount_read = 0;
-#endif
+ return 1;
+}
- data_block = find_next_block ();
- if (!data_block)
- FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
- chunk_size = sparsearray[counter].numbytes;
- if (!chunk_size)
- break;
+\f
+static void
+diff_dir (void)
+{
+ struct stat stat_data;
- offset = sparsearray[counter].offset;
- if (lseek (diff_handle, offset, SEEK_SET) < 0)
- {
- seek_error_details (current_stat_info.file_name, offset);
- report_difference (0);
- }
+ if (!get_stat_data (current_stat_info.file_name, &stat_data))
+ return;
+
+ if (!S_ISDIR (stat_data.st_mode))
+ report_difference (¤t_stat_info, _("File type differs"));
+ else if ((current_stat_info.stat.st_mode & MODE_ALL) !=
+ (stat_data.st_mode & MODE_ALL))
+ report_difference (¤t_stat_info, _("Mode differs"));
+}
- /* Take care to not run out of room in our buffer. */
+static void
+diff_file (void)
+{
+ char const *file_name = current_stat_info.file_name;
+ struct stat stat_data;
- while (buffer_size < chunk_size)
+ if (!get_stat_data (file_name, &stat_data))
+ skip_member ();
+ else if (!S_ISREG (stat_data.st_mode))
+ {
+ report_difference (¤t_stat_info, _("File type differs"));
+ skip_member ();
+ }
+ else
+ {
+ if ((current_stat_info.stat.st_mode & MODE_ALL) !=
+ (stat_data.st_mode & MODE_ALL))
+ report_difference (¤t_stat_info, _("Mode differs"));
+
+ if (!sys_compare_uid (&stat_data, ¤t_stat_info.stat))
+ report_difference (¤t_stat_info, _("Uid differs"));
+ if (!sys_compare_gid (&stat_data, ¤t_stat_info.stat))
+ report_difference (¤t_stat_info, _("Gid differs"));
+
+ if (tar_timespec_cmp (get_stat_mtime (&stat_data),
+ current_stat_info.mtime))
+ report_difference (¤t_stat_info, _("Mod time differs"));
+ if (current_header->header.typeflag != GNUTYPE_SPARSE
+ && stat_data.st_size != current_stat_info.stat.st_size)
{
- if (buffer_size * 2 < buffer_size)
- xalloc_die ();
- buffer_size *= 2;
- buffer = xrealloc (buffer, buffer_size * sizeof (char));
+ report_difference (¤t_stat_info, _("Size differs"));
+ skip_member ();
}
-
- while (chunk_size > BLOCKSIZE)
+ else
{
- if (status = safe_read (diff_handle, buffer, BLOCKSIZE),
- status != BLOCKSIZE)
- {
- if (status < 0)
- {
- read_error (current_stat_info.file_name);
- report_difference (0);
- }
- else
- {
- char message[MESSAGE_BUFFER_SIZE];
+ int atime_flag =
+ (atime_preserve_option == system_atime_preserve
+ ? O_NOATIME
+ : 0);
- sprintf (message, _("Could only read %lu of %lu bytes"),
- (unsigned long) status, (unsigned long) chunk_size);
- report_difference (message);
- }
- break;
- }
+ diff_handle = open (file_name, O_RDONLY | O_BINARY | atime_flag);
- if (memcmp (buffer, data_block->buffer, BLOCKSIZE))
+ if (diff_handle < 0)
{
- different = 1;
- break;
- }
-
- chunk_size -= status;
- remaining_size -= status;
- set_next_block_after (data_block);
- data_block = find_next_block ();
- if (!data_block)
- FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
- }
- if (status = safe_read (diff_handle, buffer, chunk_size),
- status != chunk_size)
- {
- if (status < 0)
- {
- read_error (current_stat_info.file_name);
- report_difference (0);
+ open_error (file_name);
+ skip_member ();
+ report_difference (¤t_stat_info, NULL);
}
else
{
- char message[MESSAGE_BUFFER_SIZE];
+ int status;
- sprintf (message, _("Could only read %lu of %lu bytes"),
- (unsigned long) status, (unsigned long) chunk_size);
- report_difference (message);
- }
- break;
- }
+ if (current_stat_info.is_sparse)
+ sparse_diff_file (diff_handle, ¤t_stat_info);
+ else
+ read_and_process (¤t_stat_info, process_rawdata);
- if (memcmp (buffer, data_block->buffer, chunk_size))
- {
- different = 1;
- break;
- }
-#if 0
- amount_read += chunk_size;
- if (amount_read >= BLOCKSIZE)
- {
- amount_read = 0;
- set_next_block_after (data_block);
- data_block = find_next_block ();
- if (!data_block)
- FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
+ if (atime_preserve_option == replace_atime_preserve)
+ {
+ 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)
+ utime_error (file_name);
+ }
+
+ status = close (diff_handle);
+ if (status != 0)
+ close_error (file_name);
+ }
}
-#endif
- set_next_block_after (data_block);
- counter++;
- remaining_size -= chunk_size;
}
+}
-#if 0
- /* If the number of bytes read isn't the number of bytes supposedly in
- the file, they're different. */
+static void
+diff_link (void)
+{
+ struct stat file_data;
+ struct stat link_data;
+
+ if (get_stat_data (current_stat_info.file_name, &file_data)
+ && get_stat_data (current_stat_info.link_name, &link_data)
+ && !sys_compare_links (&file_data, &link_data))
+ report_difference (¤t_stat_info,
+ _("Not linked to %s"),
+ quote (current_stat_info.link_name));
+}
- if (amount_read != current_stat_info.stat.st_size)
- different = 1;
+#ifdef HAVE_READLINK
+static void
+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);
+
+ if (status < 0)
+ {
+ if (errno == ENOENT)
+ readlink_warn (current_stat_info.file_name);
+ else
+ readlink_error (current_stat_info.file_name);
+ report_difference (¤t_stat_info, NULL);
+ }
+ else if (status != len
+ || strncmp (current_stat_info.link_name, linkbuf, len) != 0)
+ report_difference (¤t_stat_info, _("Symlink differs"));
+}
#endif
- set_next_block_after (data_block);
- free (sparsearray);
+static void
+diff_special (void)
+{
+ struct stat stat_data;
+
+ /* FIXME: deal with umask. */
+
+ if (!get_stat_data (current_stat_info.file_name, &stat_data))
+ return;
- if (different)
- report_difference (_("Contents differ"));
+ if (current_header->header.typeflag == CHRTYPE
+ ? !S_ISCHR (stat_data.st_mode)
+ : current_header->header.typeflag == BLKTYPE
+ ? !S_ISBLK (stat_data.st_mode)
+ : /* current_header->header.typeflag == FIFOTYPE */
+ !S_ISFIFO (stat_data.st_mode))
+ {
+ report_difference (¤t_stat_info, _("File type differs"));
+ return;
+ }
+
+ if ((current_header->header.typeflag == CHRTYPE
+ || current_header->header.typeflag == BLKTYPE)
+ && current_stat_info.stat.st_rdev != stat_data.st_rdev)
+ {
+ report_difference (¤t_stat_info, _("Device number differs"));
+ return;
+ }
+
+ if ((current_stat_info.stat.st_mode & MODE_ALL) !=
+ (stat_data.st_mode & MODE_ALL))
+ report_difference (¤t_stat_info, _("Mode differs"));
}
-/* Call either stat or lstat over STAT_DATA, depending on
- --dereference (-h), for a file which should exist. Diagnose any
- problem. Return nonzero for success, zero otherwise. */
-static int
-get_stat_data (char const *file_name, struct stat *stat_data)
+static void
+diff_dumpdir (void)
{
- int status = deref_stat (dereference_option, file_name, stat_data);
+ char *dumpdir_buffer;
+ dev_t dev = 0;
+ struct stat stat;
- if (status != 0)
+ if (deref_stat (true, current_stat_info.file_name, &stat))
{
if (errno == ENOENT)
- stat_warn (file_name);
+ stat_warn (current_stat_info.file_name);
else
- stat_error (file_name);
- report_difference (0);
- return 0;
+ stat_error (current_stat_info.file_name);
}
+ else
+ dev = stat.st_dev;
- return 1;
+ dumpdir_buffer = get_directory_contents (current_stat_info.file_name, dev);
+
+ if (dumpdir_buffer)
+ {
+ dumpdir_cursor = dumpdir_buffer;
+ read_and_process (¤t_stat_info, process_dumpdir);
+ free (dumpdir_buffer);
+ }
+ else
+ read_and_process (¤t_stat_info, process_noop);
+}
+
+static void
+diff_multivol (void)
+{
+ struct stat stat_data;
+ int fd, status;
+ off_t offset;
+
+ if (current_stat_info.had_trailing_slash)
+ {
+ diff_dir ();
+ return;
+ }
+
+ if (!get_stat_data (current_stat_info.file_name, &stat_data))
+ return;
+
+ if (!S_ISREG (stat_data.st_mode))
+ {
+ report_difference (¤t_stat_info, _("File type differs"));
+ skip_member ();
+ return;
+ }
+
+ offset = OFF_FROM_HEADER (current_header->oldgnu_header.offset);
+ if (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);
+
+ if (fd < 0)
+ {
+ open_error (current_stat_info.file_name);
+ report_difference (¤t_stat_info, NULL);
+ skip_member ();
+ return;
+ }
+
+ if (lseek (fd, offset, SEEK_SET) < 0)
+ {
+ seek_error_details (current_stat_info.file_name, offset);
+ report_difference (¤t_stat_info, NULL);
+ return;
+ }
+
+ read_and_process (¤t_stat_info, process_rawdata);
+
+ status = close (fd);
+ if (status != 0)
+ close_error (current_stat_info.file_name);
}
/* Diff a file against the archive. */
void
diff_archive (void)
{
- struct stat stat_data;
- int status;
- struct utimbuf restore_times;
set_next_block_after (current_header);
decode_header (current_header, ¤t_stat_info, ¤t_format, 1);
{
if (now_verifying)
fprintf (stdlis, _("Verify "));
- print_header (-1);
+ print_header (¤t_stat_info, -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. */
/* Appears to be a file. See if it's really a directory. */
if (current_stat_info.had_trailing_slash)
- goto really_dir;
-
- if (!get_stat_data (current_stat_info.file_name, &stat_data))
- {
- skip_member ();
- goto quit;
- }
-
- if (!S_ISREG (stat_data.st_mode))
- {
- report_difference (_("File type differs"));
- skip_member ();
- goto quit;
- }
-
- if ((current_stat_info.stat.st_mode & MODE_ALL) != (stat_data.st_mode & MODE_ALL))
- report_difference (_("Mode differs"));
-
-#if !MSDOS
- /* stat() in djgpp's C library gives a constant number of 42 as the
- uid and gid of a file. So, comparing an FTP'ed archive just after
- unpack would fail on MSDOS. */
- if (stat_data.st_uid != current_stat_info.stat.st_uid)
- report_difference (_("Uid differs"));
- if (stat_data.st_gid != current_stat_info.stat.st_gid)
- report_difference (_("Gid differs"));
-#endif
-
- if (stat_data.st_mtime != current_stat_info.stat.st_mtime)
- report_difference (_("Mod time differs"));
- if (current_header->header.typeflag != GNUTYPE_SPARSE &&
- stat_data.st_size != current_stat_info.stat.st_size)
- {
- report_difference (_("Size differs"));
- skip_member ();
- goto quit;
- }
-
- diff_handle = open (current_stat_info.file_name, O_RDONLY | O_BINARY);
-
- if (diff_handle < 0)
- {
- open_error (current_stat_info.file_name);
- skip_member ();
- report_difference (0);
- goto quit;
- }
-
- restore_times.actime = stat_data.st_atime;
- restore_times.modtime = stat_data.st_mtime;
-
- /* Need to treat sparse files completely differently here. */
-
- if (current_header->header.typeflag == GNUTYPE_SPARSE)
- diff_sparse_files ();
+ diff_dir ();
else
- {
- if (multi_volume_option)
- {
- assign_string (&save_name, current_stat_info.file_name);
- save_totsize = current_stat_info.stat.st_size;
- /* save_sizeleft is set in read_and_process. */
- }
-
- read_and_process (current_stat_info.stat.st_size, process_rawdata);
-
- if (multi_volume_option)
- assign_string (&save_name, 0);
- }
-
- status = close (diff_handle);
- if (status != 0)
- close_error (current_stat_info.file_name);
-
- if (atime_preserve_option)
- utime (current_stat_info.file_name, &restore_times);
-
- quit:
+ diff_file ();
break;
-#if !MSDOS
case LNKTYPE:
- {
- struct stat link_data;
-
- if (!get_stat_data (current_stat_info.file_name, &stat_data))
- break;
- if (!get_stat_data (current_stat_info.link_name, &link_data))
- break;
-
- if (stat_data.st_dev != link_data.st_dev
- || stat_data.st_ino != link_data.st_ino)
- {
- char *message =
- xmalloc (MESSAGE_BUFFER_SIZE + 4 * strlen (current_stat_info.link_name));
-
- sprintf (message, _("Not linked to %s"),
- quote (current_stat_info.link_name));
- report_difference (message);
- free (message);
- break;
- }
-
- break;
- }
-#endif /* not MSDOS */
+ diff_link ();
+ break;
#ifdef HAVE_READLINK
case SYMTYPE:
- {
- size_t len = strlen (current_stat_info.link_name);
- char *linkbuf = alloca (len + 1);
-
- status = readlink (current_stat_info.file_name, linkbuf, len + 1);
-
- if (status < 0)
- {
- if (errno == ENOENT)
- readlink_warn (current_stat_info.file_name);
- else
- readlink_error (current_stat_info.file_name);
- report_difference (0);
- }
- else if (status != len
- || strncmp (current_stat_info.link_name, linkbuf, len) != 0)
- report_difference (_("Symlink differs"));
-
- break;
- }
+ diff_symlink ();
+ break;
#endif
case CHRTYPE:
case BLKTYPE:
case FIFOTYPE:
-
- /* FIXME: deal with umask. */
-
- if (!get_stat_data (current_stat_info.file_name, &stat_data))
- break;
-
- if (current_header->header.typeflag == CHRTYPE
- ? !S_ISCHR (stat_data.st_mode)
- : current_header->header.typeflag == BLKTYPE
- ? !S_ISBLK (stat_data.st_mode)
- : /* current_header->header.typeflag == FIFOTYPE */
- !S_ISFIFO (stat_data.st_mode))
- {
- report_difference (_("File type differs"));
- break;
- }
-
- if ((current_header->header.typeflag == CHRTYPE
- || current_header->header.typeflag == BLKTYPE)
- && current_stat_info.stat.st_rdev != stat_data.st_rdev)
- {
- report_difference (_("Device number differs"));
- break;
- }
-
- if ((current_stat_info.stat.st_mode & MODE_ALL) != (stat_data.st_mode & MODE_ALL))
- {
- report_difference (_("Mode differs"));
- break;
- }
-
+ diff_special ();
break;
case GNUTYPE_DUMPDIR:
- {
- char *dumpdir_buffer = get_directory_contents (current_stat_info.file_name, 0);
-
- if (multi_volume_option)
- {
- assign_string (&save_name, current_stat_info.file_name);
- save_totsize = current_stat_info.stat.st_size;
- /* save_sizeleft is set in read_and_process. */
- }
-
- if (dumpdir_buffer)
- {
- dumpdir_cursor = dumpdir_buffer;
- read_and_process (current_stat_info.stat.st_size, process_dumpdir);
- free (dumpdir_buffer);
- }
- else
- read_and_process (current_stat_info.stat.st_size, process_noop);
-
- if (multi_volume_option)
- assign_string (&save_name, 0);
- /* Fall through. */
- }
+ diff_dumpdir ();
+ /* Fall through. */
case DIRTYPE:
- really_dir:
- if (!get_stat_data (current_stat_info.file_name, &stat_data))
- break;
-
- if (!S_ISDIR (stat_data.st_mode))
- {
- report_difference (_("File type differs"));
- break;
- }
-
- if ((current_stat_info.stat.st_mode & MODE_ALL) != (stat_data.st_mode & MODE_ALL))
- {
- report_difference (_("Mode differs"));
- break;
- }
-
+ diff_dir ();
break;
case GNUTYPE_VOLHDR:
break;
case GNUTYPE_MULTIVOL:
- {
- off_t offset;
-
- if (current_stat_info.had_trailing_slash)
- goto really_dir;
-
- if (!get_stat_data (current_stat_info.file_name, &stat_data))
- break;
-
- if (!S_ISREG (stat_data.st_mode))
- {
- report_difference (_("File type differs"));
- skip_member ();
- break;
- }
-
- offset = OFF_FROM_HEADER (current_header->oldgnu_header.offset);
- if (stat_data.st_size != current_stat_info.stat.st_size + offset)
- {
- report_difference (_("Size differs"));
- skip_member ();
- break;
- }
-
- diff_handle = open (current_stat_info.file_name, O_RDONLY | O_BINARY);
-
- if (diff_handle < 0)
- {
- open_error (current_stat_info.file_name);
- report_difference (0);
- skip_member ();
- break;
- }
-
- if (lseek (diff_handle, offset, SEEK_SET) < 0)
- {
- seek_error_details (current_stat_info.file_name, offset);
- report_difference (0);
- break;
- }
-
- if (multi_volume_option)
- {
- assign_string (&save_name, current_stat_info.file_name);
- save_totsize = stat_data.st_size;
- /* save_sizeleft is set in read_and_process. */
- }
-
- read_and_process (current_stat_info.stat.st_size, process_rawdata);
-
- if (multi_volume_option)
- assign_string (&save_name, 0);
-
- status = close (diff_handle);
- if (status != 0)
- close_error (current_stat_info.file_name);
-
- break;
- }
+ diff_multivol ();
}
}
void
verify_volume (void)
{
+ if (removed_prefixes_p ())
+ {
+ WARN((0, 0,
+ _("Archive contains file names with leading prefixes removed.")));
+ WARN((0, 0,
+ _("Verification may fail to locate original files.")));
+ }
+
if (!diff_buffer)
diff_init ();
flush_read ();
while (1)
{
- enum read_header status = read_header (0);
+ enum read_header status = read_header (false);
if (status == HEADER_FAILURE)
{
do
{
counter++;
- status = read_header (0);
+ set_next_block_after (current_header);
+ status = read_header (false);
}
while (status == HEADER_FAILURE);
ERROR ((0, 0,
- _("VERIFY FAILURE: %d invalid header(s) detected"), counter));
+ ngettext ("VERIFY FAILURE: %d invalid header detected",
+ "VERIFY FAILURE: %d invalid headers detected",
+ counter), counter));
}
if (status == HEADER_ZERO_BLOCK || status == HEADER_END_OF_FILE)
break;
diff_archive ();
+ tar_stat_destroy (¤t_stat_info);
+ xheader_destroy (&extended_header);
}
access_mode = ACCESS_WRITE;