Use current_stat_info

This commit is contained in:
Sergey Poznyakoff
2003-08-31 22:41:32 +00:00
parent 096bc2bffd
commit d858a433c8
6 changed files with 921 additions and 1170 deletions

View File

@@ -669,8 +669,7 @@ open_archive (enum access_mode wanted_access)
if (archive_names == 0)
FATAL_ERROR ((0, 0, _("No archive name given")));
current_file_name = 0;
current_link_name = 0;
destroy_stat (&current_stat_info);
save_name = 0;
real_s_name = 0;
@@ -845,8 +844,8 @@ open_archive (enum access_mode wanted_access)
else
strcpy (record_start->header.name, volume_label_option);
assign_string (&current_file_name, record_start->header.name);
current_trailing_slash = strip_trailing_slashes (current_file_name);
assign_string (&current_stat_info.file_name, record_start->header.name);
current_stat_info.had_trailing_slash = strip_trailing_slashes (current_stat_info.file_name);
record_start->header.typeflag = GNUTYPE_VOLHDR;
TIME_TO_CHARS (start_time, record_start->header.mtime);
@@ -1362,10 +1361,7 @@ close_archive (void)
}
#endif /* !MSDOS */
if (current_file_name)
free (current_file_name);
if (current_link_name)
free (current_link_name);
destroy_stat (&current_stat_info);
if (save_name)
free (save_name);
if (real_s_name)

View File

@@ -1,5 +1,8 @@
/* Diff files from a tar archive.
Copyright (C) 1988, 92, 93, 94, 96, 97 Free Software Foundation, Inc.
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
2003 Free Software Foundation, Inc.
Written by John Gilmore, on 1987-04-30.
This program is free software; you can redistribute it and/or modify it
@@ -14,14 +17,26 @@
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 Place - Suite 330, Boston, MA 02111-1307, USA. */
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "system.h"
#if HAVE_UTIME_H
# include <utime.h>
#else
struct utimbuf
{
long actime;
long modtime;
};
#endif
#if HAVE_LINUX_FD_H
# include <linux/fd.h>
#endif
#include <quotearg.h>
#include "common.h"
#include "rmt.h"
@@ -29,105 +44,85 @@
#define MESSAGE_BUFFER_SIZE 100
/* Nonzero if we are verifying at the moment. */
int now_verifying = 0;
bool now_verifying;
/* File descriptor for the file we are diffing. */
static int diff_handle;
/* Area for reading file contents into. */
static char *diff_buffer = NULL;
/*--------------------------------.
| Initialize for a diff operation |
`--------------------------------*/
static char *diff_buffer;
/* Initialize for a diff operation. */
void
diff_init (void)
{
diff_buffer = (char *) valloc ((unsigned) record_size);
diff_buffer = valloc (record_size);
if (!diff_buffer)
FATAL_ERROR ((0, 0,
_("Could not allocate memory for diff buffer of %d bytes"),
record_size));
xalloc_die ();
}
/*------------------------------------------------------------------------.
| Sigh about something that differs by writing a MESSAGE to stdlis, given |
| MESSAGE is not NULL. Also set the exit status if not already. |
`------------------------------------------------------------------------*/
/* 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)
{
if (message)
fprintf (stdlis, "%s: %s\n", current_file_name, message);
fprintf (stdlis, "%s: %s\n", quotearg_colon (current_stat_info.file_name), message);
if (exit_status == TAREXIT_SUCCESS)
exit_status = TAREXIT_DIFFERS;
}
/*-----------------------------------------------------------------------.
| Takes a buffer returned by read_and_process and does nothing with it. |
`-----------------------------------------------------------------------*/
/* Yes, I know. SIZE and DATA are unused in this function. Some compilers
may even report it. That's OK, just relax! */
/* Take a buffer returned by read_and_process and do nothing with it. */
static int
process_noop (long size, char *data)
process_noop (size_t size, char *data)
{
/* 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 (long bytes, char *buffer)
process_rawdata (size_t bytes, char *buffer)
{
int status = read (diff_handle, diff_buffer, (size_t) bytes);
ssize_t status = safe_read (diff_handle, diff_buffer, bytes);
char message[MESSAGE_BUFFER_SIZE];
if (status != bytes)
{
if (status < 0)
{
WARN ((0, errno, _("Cannot read %s"), current_file_name));
report_difference (NULL);
read_error (current_stat_info.file_name);
report_difference (0);
}
else
{
sprintf (message, _("Could only read %d of %ld bytes"),
status, bytes);
sprintf (message, _("Could only read %lu of %lu bytes"),
(unsigned long) status, (unsigned long) bytes);
report_difference (message);
}
return 0;
}
if (memcmp (buffer, diff_buffer, (size_t) bytes))
if (memcmp (buffer, diff_buffer, bytes))
{
report_difference (_("Data differs"));
report_difference (_("Contents differ"));
return 0;
}
return 1;
}
/*---.
| ? |
`---*/
/* Directory contents, only for GNUTYPE_DUMPDIR. */
static char *dumpdir_cursor;
static int
process_dumpdir (long bytes, char *buffer)
process_dumpdir (size_t bytes, char *buffer)
{
if (memcmp (buffer, dumpdir_cursor, (size_t) bytes))
if (memcmp (buffer, dumpdir_cursor, bytes))
{
report_difference (_("Data differs"));
report_difference (_("Contents differ"));
return 0;
}
@@ -135,28 +130,25 @@ process_dumpdir (long bytes, char *buffer)
return 1;
}
/*------------------------------------------------------------------------.
| Some other routine wants SIZE bytes in the archive. For each chunk of |
| the archive, call PROCESSOR with the size of the chunk, and the 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. |
`------------------------------------------------------------------------*/
/* Some other routine wants SIZE bytes in the archive. For each chunk
of the archive, call PROCESSOR with the size of the chunk, and the
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 (long size, int (*processor) (long, char *))
read_and_process (off_t size, int (*processor) (size_t, char *))
{
union block *data_block;
long data_size;
size_t data_size;
if (multi_volume_option)
save_sizeleft = size;
while (size)
{
data_block = find_next_block ();
if (data_block == NULL)
if (! data_block)
{
ERROR ((0, 0, _("Unexpected EOF on archive file")));
ERROR ((0, 0, _("Unexpected EOF in archive")));
return;
}
@@ -173,98 +165,9 @@ read_and_process (long size, int (*processor) (long, char *))
}
}
/*---.
| ? |
`---*/
/* JK This routine should be used more often than it is ... look into
that. Anyhow, what it does is translate the sparse information on the
header, and in any subsequent extended headers, into an array of
structures with true numbers, as opposed to character strings. It
simply makes our life much easier, doing so many comparisong and such.
*/
static void
fill_in_sparse_array (void)
{
int counter;
/* Allocate space for our scratch space; it's initially 10 elements
long, but can change in this routine if necessary. */
sp_array_size = 10;
sparsearray = (struct sp_array *) xmalloc (sp_array_size * sizeof (struct sp_array));
/* There are at most five of these structures in the header itself;
read these in first. */
for (counter = 0; counter < SPARSES_IN_OLDGNU_HEADER; counter++)
{
/* Compare to 0, or use !(int)..., for Pyramid's dumb compiler. */
if (current_header->oldgnu_header.sp[counter].numbytes == 0)
break;
sparsearray[counter].offset =
from_oct (1 + 12, current_header->oldgnu_header.sp[counter].offset);
sparsearray[counter].numbytes =
from_oct (1 + 12, current_header->oldgnu_header.sp[counter].numbytes);
}
/* If the header's extended, we gotta read in exhdr's till we're done. */
if (current_header->oldgnu_header.isextended)
{
/* How far into the sparsearray we are `so far'. */
static int so_far_ind = SPARSES_IN_OLDGNU_HEADER;
union block *exhdr;
while (1)
{
exhdr = find_next_block ();
for (counter = 0; counter < SPARSES_IN_SPARSE_HEADER; counter++)
{
if (counter + so_far_ind > sp_array_size - 1)
{
/* We just ran out of room in our scratch area -
realloc it. */
sp_array_size *= 2;
sparsearray = (struct sp_array *)
xrealloc (sparsearray,
sp_array_size * sizeof (struct sp_array));
}
/* Convert the character strings into longs. */
sparsearray[counter + so_far_ind].offset =
from_oct (1 + 12, exhdr->sparse_header.sp[counter].offset);
sparsearray[counter + so_far_ind].numbytes =
from_oct (1 + 12, exhdr->sparse_header.sp[counter].numbytes);
}
/* If this is the last extended header for this file, we can
stop. */
if (!exhdr->sparse_header.isextended)
break;
so_far_ind += SPARSES_IN_SPARSE_HEADER;
set_next_block_after (exhdr);
}
/* Be sure to skip past the last one. */
set_next_block_after (exhdr);
}
}
/*---.
| ? |
`---*/
/* 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 contruct a
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. */
@@ -273,56 +176,68 @@ fill_in_sparse_array (void)
I'm not sure overall identical sparsity is verified. */
static void
diff_sparse_files (int size_of_file)
diff_sparse_files (void)
{
int remaining_size = size_of_file;
char *buffer = (char *) xmalloc (BLOCKSIZE * sizeof (char));
int buffer_size = BLOCKSIZE;
union block *data_block = NULL;
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;
fill_in_sparse_array ();
if (! fill_in_sparse_array ())
fatal_exit ();
while (remaining_size > 0)
{
int status;
long chunk_size;
ssize_t status;
size_t chunk_size;
off_t offset;
#if 0
int amount_read = 0;
off_t amount_read = 0;
#endif
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;
lseek (diff_handle, sparsearray[counter].offset, 0);
offset = sparsearray[counter].offset;
if (lseek (diff_handle, offset, SEEK_SET) < 0)
{
seek_error_details (current_stat_info.file_name, offset);
report_difference (0);
}
/* Take care to not run out of room in our buffer. */
while (buffer_size < chunk_size)
{
if (buffer_size * 2 < buffer_size)
xalloc_die ();
buffer_size *= 2;
buffer = (char *) xrealloc (buffer, buffer_size * sizeof (char));
buffer = xrealloc (buffer, buffer_size * sizeof (char));
}
while (chunk_size > BLOCKSIZE)
{
if (status = read (diff_handle, buffer, BLOCKSIZE),
if (status = safe_read (diff_handle, buffer, BLOCKSIZE),
status != BLOCKSIZE)
{
if (status < 0)
{
WARN ((0, errno, _("Cannot read %s"), current_file_name));
report_difference (NULL);
read_error (current_stat_info.file_name);
report_difference (0);
}
else
{
char message[MESSAGE_BUFFER_SIZE];
sprintf (message, _("Could only read %d of %ld bytes"),
status, chunk_size);
sprintf (message, _("Could only read %lu of %lu bytes"),
(unsigned long) status, (unsigned long) chunk_size);
report_difference (message);
}
break;
@@ -338,27 +253,29 @@ diff_sparse_files (int size_of_file)
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 = read (diff_handle, buffer, (size_t) chunk_size),
if (status = safe_read (diff_handle, buffer, chunk_size),
status != chunk_size)
{
if (status < 0)
{
WARN ((0, errno, _("Cannot read %s"), current_file_name));
report_difference (NULL);
read_error (current_stat_info.file_name);
report_difference (0);
}
else
{
char message[MESSAGE_BUFFER_SIZE];
sprintf (message, _("Could only read %d of %ld bytes"),
status, chunk_size);
sprintf (message, _("Could only read %lu of %lu bytes"),
(unsigned long) status, (unsigned long) chunk_size);
report_difference (message);
}
break;
}
if (memcmp (buffer, data_block->buffer, (size_t) chunk_size))
if (memcmp (buffer, data_block->buffer, chunk_size))
{
different = 1;
break;
@@ -370,6 +287,8 @@ diff_sparse_files (int size_of_file)
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")));
}
#endif
set_next_block_after (data_block);
@@ -381,7 +300,7 @@ diff_sparse_files (int size_of_file)
/* If the number of bytes read isn't the number of bytes supposedly in
the file, they're different. */
if (amount_read != size_of_file)
if (amount_read != current_stat_info.stat.st_size)
different = 1;
#endif
@@ -389,71 +308,56 @@ diff_sparse_files (int size_of_file)
free (sparsearray);
if (different)
report_difference (_("Data differs"));
report_difference (_("Contents differ"));
}
/*---------------------------------------------------------------------.
| 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. |
`---------------------------------------------------------------------*/
/* 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 (struct stat *stat_data)
get_stat_data (char const *file_name, struct stat *stat_data)
{
int status = (dereference_option
? stat (current_file_name, stat_data)
: lstat (current_file_name, stat_data));
int status = deref_stat (dereference_option, file_name, stat_data);
if (status < 0)
if (status != 0)
{
if (errno == ENOENT)
report_difference (_("File does not exist"));
stat_warn (file_name);
else
{
ERROR ((0, errno, _("Cannot stat file %s"), current_file_name));
report_difference (NULL);
}
#if 0
skip_file ((long) current_stat.st_size);
#endif
stat_error (file_name);
report_difference (0);
return 0;
}
return 1;
}
/*----------------------------------.
| Diff a file against the archive. |
`----------------------------------*/
/* Diff a file against the archive. */
void
diff_archive (void)
{
struct stat stat_data;
int name_length;
int status;
errno = EPIPE; /* FIXME: errno should be read-only */
/* FIXME: remove perrors */
struct utimbuf restore_times;
set_next_block_after (current_header);
decode_header (current_header, &current_stat, &current_format, 1);
decode_header (current_header, &current_stat_info, &current_format, 1);
/* Print the block from `current_header' and `current_stat'. */
/* Print the block from current_header and current_stat_info. */
if (verbose_option)
{
if (now_verifying)
fprintf (stdlis, _("Verify "));
print_header ();
print_header (-1);
}
switch (current_header->header.typeflag)
{
default:
WARN ((0, 0, _("Unknown file type '%c' for %s, diffed as normal file"),
current_header->header.typeflag, current_file_name));
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. */
case AREGTYPE:
@@ -463,92 +367,83 @@ diff_archive (void)
/* Appears to be a file. See if it's really a directory. */
name_length = strlen (current_file_name) - 1;
if (current_file_name[name_length] == '/')
if (current_stat_info.had_trailing_slash)
goto really_dir;
if (!get_stat_data (&stat_data))
if (!get_stat_data (current_stat_info.file_name, &stat_data))
{
if (current_header->oldgnu_header.isextended)
skip_extended_headers ();
skip_file ((long) current_stat.st_size);
skip_member ();
goto quit;
}
if (!S_ISREG (stat_data.st_mode))
{
report_difference (_("Not a regular file"));
skip_file ((long) current_stat.st_size);
report_difference (_("File type differs"));
skip_member ();
goto quit;
}
stat_data.st_mode &= 07777;
if (stat_data.st_mode != current_stat.st_mode)
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.st_uid)
if (stat_data.st_uid != current_stat_info.stat.st_uid)
report_difference (_("Uid differs"));
if (stat_data.st_gid != current_stat.st_gid)
if (stat_data.st_gid != current_stat_info.stat.st_gid)
report_difference (_("Gid differs"));
#endif
if (stat_data.st_mtime != current_stat.st_mtime)
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.st_size)
stat_data.st_size != current_stat_info.stat.st_size)
{
report_difference (_("Size differs"));
skip_file ((long) current_stat.st_size);
skip_member ();
goto quit;
}
diff_handle = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY);
diff_handle = open (current_stat_info.file_name, O_RDONLY | O_BINARY);
if (diff_handle < 0 && !absolute_names_option)
{
char *tmpbuf = xmalloc (strlen (current_file_name) + 2);
*tmpbuf = '/';
strcpy (tmpbuf + 1, current_file_name);
diff_handle = open (tmpbuf, O_NDELAY | O_RDONLY);
free (tmpbuf);
}
if (diff_handle < 0)
{
ERROR ((0, errno, _("Cannot open %s"), current_file_name));
if (current_header->oldgnu_header.isextended)
skip_extended_headers ();
skip_file ((long) current_stat.st_size);
report_difference (NULL);
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 (current_stat.st_size);
diff_sparse_files ();
else
{
if (multi_volume_option)
{
assign_string (&save_name, current_file_name);
save_totsize = current_stat.st_size;
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 ((long) (current_stat.st_size), process_rawdata);
read_and_process (current_stat_info.stat.st_size, process_rawdata);
if (multi_volume_option)
assign_string (&save_name, NULL);
assign_string (&save_name, 0);
}
status = close (diff_handle);
if (status < 0)
ERROR ((0, errno, _("Error while closing %s"), current_file_name));
if (status != 0)
close_error (current_stat_info.file_name);
if (atime_preserve_option)
utime (current_stat_info.file_name, &restore_times);
quit:
break;
@@ -556,33 +451,21 @@ diff_archive (void)
#if !MSDOS
case LNKTYPE:
{
dev_t dev;
ino_t ino;
struct stat link_data;
if (!get_stat_data (&stat_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;
dev = stat_data.st_dev;
ino = stat_data.st_ino;
status = stat (current_link_name, &stat_data);
if (status < 0)
if (stat_data.st_dev != link_data.st_dev
|| stat_data.st_ino != link_data.st_ino)
{
if (errno == ENOENT)
report_difference (_("Does not exist"));
else
{
WARN ((0, errno, _("Cannot stat file %s"), current_file_name));
report_difference (NULL);
}
break;
}
char *message =
xmalloc (MESSAGE_BUFFER_SIZE + 4 * strlen (current_stat_info.link_name));
if (stat_data.st_dev != dev || stat_data.st_ino != ino)
{
char *message = (char *)
xmalloc (MESSAGE_BUFFER_SIZE + strlen (current_link_name));
sprintf (message, _("Not linked to %s"), current_link_name);
sprintf (message, _("Not linked to %s"),
quote (current_stat_info.link_name));
report_difference (message);
free (message);
break;
@@ -592,80 +475,61 @@ diff_archive (void)
}
#endif /* not MSDOS */
#ifdef S_ISLNK
#ifdef HAVE_READLINK
case SYMTYPE:
{
char linkbuf[NAME_FIELD_SIZE + 3]; /* FIXME: may be too short. */
size_t len = strlen (current_stat_info.link_name);
char *linkbuf = alloca (len + 1);
status = readlink (current_file_name, linkbuf, (sizeof linkbuf) - 1);
status = readlink (current_stat_info.file_name, linkbuf, len + 1);
if (status < 0)
{
if (errno == ENOENT)
report_difference (_("No such file or directory"));
readlink_warn (current_stat_info.file_name);
else
{
WARN ((0, errno, _("Cannot read link %s"), current_file_name));
report_difference (NULL);
}
break;
readlink_error (current_stat_info.file_name);
report_difference (0);
}
linkbuf[status] = '\0'; /* null-terminate it */
if (strncmp (current_link_name, linkbuf, (size_t) status) != 0)
else if (status != len
|| strncmp (current_stat_info.link_name, linkbuf, len) != 0)
report_difference (_("Symlink differs"));
break;
}
#endif /* not S_ISLNK */
#endif
#ifdef S_IFCHR
case CHRTYPE:
current_stat.st_mode |= S_IFCHR;
goto check_node;
#endif /* not S_IFCHR */
#ifdef S_IFBLK
/* If local system doesn't support block devices, use default case. */
case BLKTYPE:
current_stat.st_mode |= S_IFBLK;
goto check_node;
#endif /* not S_IFBLK */
#ifdef S_ISFIFO
/* If local system doesn't support FIFOs, use default case. */
case FIFOTYPE:
# ifdef S_IFIFO
current_stat.st_mode |= S_IFIFO;
# endif
current_stat.st_rdev = 0; /* FIXME: do we need this? */
goto check_node;
#endif /* S_ISFIFO */
check_node:
/* FIXME: deal with umask. */
if (!get_stat_data (&stat_data))
if (!get_stat_data (current_stat_info.file_name, &stat_data))
break;
if (current_stat.st_rdev != stat_data.st_rdev)
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 (_("Device numbers changed"));
report_difference (_("File type differs"));
break;
}
if (
#ifdef S_IFMT
current_stat.st_mode != stat_data.st_mode
#else
/* POSIX lossage. */
(current_stat.st_mode & 07777) != (stat_data.st_mode & 07777)
#endif
)
if ((current_header->header.typeflag == CHRTYPE
|| current_header->header.typeflag == BLKTYPE)
&& current_stat_info.stat.st_rdev != stat_data.st_rdev)
{
report_difference (_("Mode or device-type changed"));
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;
}
@@ -673,49 +537,46 @@ diff_archive (void)
case GNUTYPE_DUMPDIR:
{
char *dumpdir_buffer = get_directory_contents (current_file_name, 0);
char *dumpdir_buffer = get_directory_contents (current_stat_info.file_name, 0);
if (multi_volume_option)
{
assign_string (&save_name, current_file_name);
save_totsize = current_stat.st_size;
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 ((long) (current_stat.st_size), process_dumpdir);
read_and_process (current_stat_info.stat.st_size, process_dumpdir);
free (dumpdir_buffer);
}
else
read_and_process ((long) (current_stat.st_size), process_noop);
read_and_process (current_stat_info.stat.st_size, process_noop);
if (multi_volume_option)
assign_string (&save_name, NULL);
assign_string (&save_name, 0);
/* Fall through. */
}
case DIRTYPE:
/* Check for trailing /. */
name_length = strlen (current_file_name) - 1;
really_dir:
while (name_length && current_file_name[name_length] == '/')
current_file_name[name_length--] = '\0'; /* zap / */
if (!get_stat_data (&stat_data))
if (!get_stat_data (current_stat_info.file_name, &stat_data))
break;
if (!S_ISDIR (stat_data.st_mode))
{
report_difference (_("No longer a directory"));
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;
}
if ((stat_data.st_mode & 07777) != (current_stat.st_mode & 07777))
report_difference (_("Mode differs"));
break;
case GNUTYPE_VOLHDR:
@@ -725,73 +586,65 @@ diff_archive (void)
{
off_t offset;
name_length = strlen (current_file_name) - 1;
if (current_file_name[name_length] == '/')
if (current_stat_info.had_trailing_slash)
goto really_dir;
if (!get_stat_data (&stat_data))
if (!get_stat_data (current_stat_info.file_name, &stat_data))
break;
if (!S_ISREG (stat_data.st_mode))
{
report_difference (_("Not a regular file"));
skip_file ((long) current_stat.st_size);
report_difference (_("File type differs"));
skip_member ();
break;
}
stat_data.st_mode &= 07777;
offset = from_oct (1 + 12, current_header->oldgnu_header.offset);
if (stat_data.st_size != current_stat.st_size + offset)
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_file ((long) current_stat.st_size);
skip_member ();
break;
}
diff_handle = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY);
diff_handle = open (current_stat_info.file_name, O_RDONLY | O_BINARY);
if (diff_handle < 0)
{
WARN ((0, errno, _("Cannot open file %s"), current_file_name));
report_difference (NULL);
skip_file ((long) current_stat.st_size);
open_error (current_stat_info.file_name);
report_difference (0);
skip_member ();
break;
}
status = lseek (diff_handle, offset, 0);
if (status != offset)
if (lseek (diff_handle, offset, SEEK_SET) < 0)
{
WARN ((0, errno, _("Cannot seek to %ld in file %s"),
offset, current_file_name));
report_difference (NULL);
seek_error_details (current_stat_info.file_name, offset);
report_difference (0);
break;
}
if (multi_volume_option)
{
assign_string (&save_name, current_file_name);
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 ((long) (current_stat.st_size), process_rawdata);
read_and_process (current_stat_info.stat.st_size, process_rawdata);
if (multi_volume_option)
assign_string (&save_name, NULL);
assign_string (&save_name, 0);
status = close (diff_handle);
if (status < 0)
ERROR ((0, errno, _("Error while closing %s"), current_file_name));
if (status != 0)
close_error (current_stat_info.file_name);
break;
}
}
}
/*---.
| ? |
`---*/
void
verify_volume (void)
{
@@ -829,12 +682,10 @@ verify_volume (void)
status < 0))
{
#endif
if (rmtlseek (archive, 0L, 0) != 0)
if (rmtlseek (archive, (off_t) 0, SEEK_SET) != 0)
{
/* Lseek failed. Try a different method. */
WARN ((0, errno,
_("Could not rewind archive file for verify")));
seek_warn (archive_name_array[0]);
return;
}
#ifdef MTIOCTOP
@@ -849,17 +700,19 @@ verify_volume (void)
flush_read ();
while (1)
{
enum read_header status = read_header ();
enum read_header status = read_header (0);
if (status == HEADER_FAILURE)
{
int counter = 0;
while (status == HEADER_FAILURE);
do
{
counter++;
status = read_header ();
status = read_header (0);
}
while (status == HEADER_FAILURE);
ERROR ((0, 0,
_("VERIFY FAILURE: %d invalid header(s) detected"), counter));
}

View File

@@ -359,7 +359,7 @@ write_eot (void)
/* FIXME: Cross recursion between start_header and write_long! */
static union block *start_header (const char *, struct stat *);
static union block *start_header (const char *, struct tar_stat_info *);
static void
write_long (const char *p, char type)
@@ -367,10 +367,10 @@ write_long (const char *p, char type)
size_t size = strlen (p) + 1;
size_t bufsize;
union block *header;
struct stat foo;
struct tar_stat_info foo;
memset (&foo, 0, sizeof foo);
foo.st_size = size;
foo.stat.st_size = size;
header = start_header ("././@LongLink", &foo);
header->header.typeflag = type;
@@ -400,7 +400,7 @@ write_long (const char *p, char type)
and return its address. */
static union block *
start_header (const char *name, struct stat *st)
start_header (const char *name, struct tar_stat_info *st)
{
union block *header;
@@ -411,7 +411,7 @@ start_header (const char *name, struct stat *st)
header = find_next_block ();
memset (header->buffer, 0, sizeof (union block));
assign_string (&current_file_name, name);
assign_string (&current_stat_info.file_name, name);
strncpy (header->header.name, name, NAME_FIELD_SIZE);
header->header.name[NAME_FIELD_SIZE - 1] = '\0';
@@ -419,12 +419,12 @@ start_header (const char *name, struct stat *st)
/* Override some stat fields, if requested to do so. */
if (owner_option != (uid_t) -1)
st->st_uid = owner_option;
st->stat.st_uid = owner_option;
if (group_option != (gid_t) -1)
st->st_gid = group_option;
st->stat.st_gid = group_option;
if (mode_option)
st->st_mode = ((st->st_mode & ~MODE_ALL)
| mode_adjust (st->st_mode, mode_option));
st->stat.st_mode = ((st->stat.st_mode & ~MODE_ALL)
| mode_adjust (st->stat.st_mode, mode_option));
/* Paul Eggert tried the trivial test ($WRITER cf a b; $READER tvf a)
for a few tars and came up with the following interoperability
@@ -450,22 +450,22 @@ start_header (const char *name, struct stat *st)
acceptor for Paul's test. */
if (archive_format == V7_FORMAT)
MODE_TO_CHARS (st->st_mode & MODE_ALL, header->header.mode);
MODE_TO_CHARS (st->stat.st_mode & MODE_ALL, header->header.mode);
else
MODE_TO_CHARS (st->st_mode, header->header.mode);
MODE_TO_CHARS (st->stat.st_mode, header->header.mode);
UID_TO_CHARS (st->st_uid, header->header.uid);
GID_TO_CHARS (st->st_gid, header->header.gid);
OFF_TO_CHARS (st->st_size, header->header.size);
TIME_TO_CHARS (st->st_mtime, header->header.mtime);
UID_TO_CHARS (st->stat.st_uid, header->header.uid);
GID_TO_CHARS (st->stat.st_gid, header->header.gid);
OFF_TO_CHARS (st->stat.st_size, header->header.size);
TIME_TO_CHARS (st->stat.st_mtime, header->header.mtime);
MAJOR_TO_CHARS (0, header->header.devmajor);
MINOR_TO_CHARS (0, header->header.devminor);
if (incremental_option)
if (archive_format == OLDGNU_FORMAT)
{
TIME_TO_CHARS (st->st_atime, header->oldgnu_header.atime);
TIME_TO_CHARS (st->st_ctime, header->oldgnu_header.ctime);
TIME_TO_CHARS (st->stat.st_atime, header->oldgnu_header.atime);
TIME_TO_CHARS (st->stat.st_ctime, header->oldgnu_header.ctime);
}
header->header.typeflag = archive_format == V7_FORMAT ? AREGTYPE : REGTYPE;
@@ -496,8 +496,8 @@ start_header (const char *name, struct stat *st)
}
else
{
uid_to_uname (st->st_uid, header->header.uname);
gid_to_gname (st->st_gid, header->header.gname);
uid_to_uname (st->stat.st_uid, header->header.uname);
gid_to_gname (st->stat.st_gid, header->header.gname);
}
return header;
@@ -541,7 +541,7 @@ finish_header (union block *header, off_t block_ordinal)
/* These globals are parameters to print_header, sigh. */
current_header = header;
/* current_stat is already set up. */
/* current_stat_info is already set up. */
current_format = archive_format;
print_header (block_ordinal);
}
@@ -859,7 +859,7 @@ static Hash_table *link_table;
of an incremental dump. PARENT_DEVICE is the device of P's
parent directory; it is examined only if TOP_LEVEL is zero.
Set global CURRENT_STAT to stat output for this file. */
Set global CURRENT_STAT_INFO to stat output for this file. */
/* FIXME: One should make sure that for *every* path leading to setting
exit_status to failure, a clear diagnostic has been issued. */
@@ -881,7 +881,7 @@ dump_file (char *p, int top_level, dev_t parent_device)
if (interactive_option && !confirm ("add", p))
return;
if (deref_stat (dereference_option, p, &current_stat) != 0)
if (deref_stat (dereference_option, p, &current_stat_info.stat) != 0)
{
if (ignore_failed_read_option)
stat_warn (p);
@@ -890,12 +890,12 @@ dump_file (char *p, int top_level, dev_t parent_device)
return;
}
original_ctime = current_stat.st_ctime;
restore_times.actime = current_stat.st_atime;
restore_times.modtime = current_stat.st_mtime;
original_ctime = current_stat_info.stat.st_ctime;
restore_times.actime = current_stat_info.stat.st_atime;
restore_times.modtime = current_stat_info.stat.st_mtime;
#ifdef S_ISHIDDEN
if (S_ISHIDDEN (current_stat.st_mode))
if (S_ISHIDDEN (current_stat_info.stat.st_mode))
{
char *new = (char *) alloca (strlen (p) + 2);
if (new)
@@ -911,9 +911,9 @@ dump_file (char *p, int top_level, dev_t parent_device)
put in the archive. */
if ((0 < top_level || !incremental_option)
&& !S_ISDIR (current_stat.st_mode)
&& current_stat.st_mtime < newer_mtime_option
&& (!after_date_option || current_stat.st_ctime < newer_ctime_option))
&& !S_ISDIR (current_stat_info.stat.st_mode)
&& current_stat_info.stat.st_mtime < newer_mtime_option
&& (!after_date_option || current_stat_info.stat.st_ctime < newer_ctime_option))
{
if (0 < top_level)
WARN ((0, 0, _("%s: file is unchanged; not dumped"),
@@ -925,7 +925,7 @@ dump_file (char *p, int top_level, dev_t parent_device)
#if !MSDOS
/* See if we are trying to dump the archive. */
if (ar_dev && current_stat.st_dev == ar_dev && current_stat.st_ino == ar_ino)
if (ar_dev && current_stat_info.stat.st_dev == ar_dev && current_stat_info.stat.st_ino == ar_ino)
{
WARN ((0, 0, _("%s: file is the archive; not dumped"),
quotearg_colon (p)));
@@ -933,7 +933,7 @@ dump_file (char *p, int top_level, dev_t parent_device)
}
#endif
if (S_ISDIR (current_stat.st_mode))
if (S_ISDIR (current_stat_info.stat.st_mode))
{
char *directory;
char const *entry;
@@ -941,7 +941,7 @@ dump_file (char *p, int top_level, dev_t parent_device)
char *namebuf;
size_t buflen;
size_t len;
dev_t our_device = current_stat.st_dev;
dev_t our_device = current_stat_info.stat.st_dev;
errno = 0;
@@ -979,18 +979,18 @@ dump_file (char *p, int top_level, dev_t parent_device)
directory blocks to be written even with old archives. */
block_ordinal = current_block_ordinal ();
current_stat.st_size = 0; /* force 0 size on dir */
current_stat_info.stat.st_size = 0; /* force 0 size on dir */
/* FIXME: If people could really read standard archives, this
should be:
header
= start_header (standard_option ? p : namebuf, &current_stat);
= start_header (standard_option ? p : namebuf, &current_stat_info);
but since they'd interpret DIRTYPE blocks as regular
files, we'd better put the / on the name. */
header = start_header (namebuf, &current_stat);
header = start_header (namebuf, &current_stat_info);
if (incremental_option)
header->header.typeflag = GNUTYPE_DUMPDIR;
@@ -1063,7 +1063,7 @@ dump_file (char *p, int top_level, dev_t parent_device)
avoid doing so if the user only wants to dump one file system. */
if (one_file_system_option && !top_level
&& parent_device != current_stat.st_dev)
&& parent_device != current_stat_info.stat.st_dev)
{
if (verbose_option)
WARN ((0, 0,
@@ -1104,12 +1104,12 @@ dump_file (char *p, int top_level, dev_t parent_device)
{
/* Check for multiple links. */
if (1 < current_stat.st_nlink && link_table)
if (1 < current_stat_info.stat.st_nlink && link_table)
{
struct link lp;
struct link *dup;
lp.ino = current_stat.st_ino;
lp.dev = current_stat.st_dev;
lp.ino = current_stat_info.stat.st_ino;
lp.dev = current_stat_info.stat.st_dev;
if ((dup = hash_lookup (link_table, &lp)))
{
@@ -1121,10 +1121,10 @@ dump_file (char *p, int top_level, dev_t parent_device)
block_ordinal = current_block_ordinal ();
if (NAME_FIELD_SIZE <= strlen (link_name))
write_long (link_name, GNUTYPE_LONGLINK);
assign_string (&current_link_name, link_name);
assign_string (&current_stat_info.link_name, link_name);
current_stat.st_size = 0;
header = start_header (p, &current_stat);
current_stat_info.stat.st_size = 0;
header = start_header (p, &current_stat_info);
strncpy (header->header.linkname, link_name, NAME_FIELD_SIZE);
/* Force null termination. */
@@ -1146,8 +1146,8 @@ dump_file (char *p, int top_level, dev_t parent_device)
/* This is not a link to a previously dumped file, so dump it. */
if (S_ISREG (current_stat.st_mode)
|| S_ISCTG (current_stat.st_mode))
if (S_ISREG (current_stat_info.stat.st_mode)
|| S_ISCTG (current_stat_info.stat.st_mode))
{
int f; /* file descriptor */
size_t bufsize;
@@ -1193,14 +1193,14 @@ dump_file (char *p, int top_level, dev_t parent_device)
st_blocks, so `du' and `ls -s' give wrong results. So, the
--sparse option would not work on a minix filesystem. */
if (ST_NBLOCKS (current_stat)
< (current_stat.st_size / ST_NBLOCKSIZE
+ (current_stat.st_size % ST_NBLOCKSIZE != 0)))
if (ST_NBLOCKS (current_stat_info.stat)
< (current_stat_info.stat.st_size / ST_NBLOCKSIZE
+ (current_stat_info.stat.st_size % ST_NBLOCKSIZE != 0)))
{
int counter;
block_ordinal = current_block_ordinal ();
header = start_header (p, &current_stat);
header = start_header (p, &current_stat_info);
header->header.typeflag = GNUTYPE_SPARSE;
header_moved = 1;
@@ -1221,15 +1221,15 @@ dump_file (char *p, int top_level, dev_t parent_device)
<file>. It might be kind of disconcerting if the
shrunken file size was the one that showed up. */
OFF_TO_CHARS (current_stat.st_size,
OFF_TO_CHARS (current_stat_info.stat.st_size,
header->oldgnu_header.realsize);
/* This will be the new "size" of the file, i.e., the size
of the file minus the blocks of holes that we're
skipping over. */
current_stat.st_size = find_new_file_size (sparses);
OFF_TO_CHARS (current_stat.st_size, header->header.size);
current_stat_info.stat.st_size = find_new_file_size (sparses);
OFF_TO_CHARS (current_stat_info.stat.st_size, header->header.size);
for (counter = 0;
counter < sparses && counter < SPARSES_IN_OLDGNU_HEADER;
@@ -1243,14 +1243,14 @@ dump_file (char *p, int top_level, dev_t parent_device)
}
}
sizeleft = current_stat.st_size;
sizeleft = current_stat_info.stat.st_size;
/* Don't bother opening empty, world readable files. Also do not open
files when archive is meant for /dev/null. */
if (dev_null_output
|| (sizeleft == 0
&& MODE_R == (MODE_R & current_stat.st_mode)))
&& MODE_R == (MODE_R & current_stat_info.stat.st_mode)))
f = -1;
else
{
@@ -1271,12 +1271,12 @@ dump_file (char *p, int top_level, dev_t parent_device)
if (!header_moved)
{
block_ordinal = current_block_ordinal ();
header = start_header (p, &current_stat);
header = start_header (p, &current_stat_info);
}
/* Mark contiguous files, if we support them. */
if (archive_format != V7_FORMAT && S_ISCTG (current_stat.st_mode))
if (archive_format != V7_FORMAT && S_ISCTG (current_stat_info.stat.st_mode))
header->header.typeflag = CONTTYPE;
isextended = header->oldgnu_header.isextended;
@@ -1312,7 +1312,7 @@ dump_file (char *p, int top_level, dev_t parent_device)
{
if (f < 0
|| finish_sparse_file (f, &sizeleft,
current_stat.st_size, p))
current_stat_info.stat.st_size, p))
goto padit;
}
else
@@ -1322,7 +1322,7 @@ dump_file (char *p, int top_level, dev_t parent_device)
{
assign_string (&save_name, p);
save_sizeleft = sizeleft;
save_totsize = current_stat.st_size;
save_totsize = current_stat_info.stat.st_size;
}
start = find_next_block ();
@@ -1346,7 +1346,7 @@ dump_file (char *p, int top_level, dev_t parent_device)
(ignore_failed_read_option
? read_warn_details
: read_error_details)
(p, current_stat.st_size - sizeleft, bufsize);
(p, current_stat_info.stat.st_size - sizeleft, bufsize);
goto padit;
}
sizeleft -= count;
@@ -1428,12 +1428,12 @@ dump_file (char *p, int top_level, dev_t parent_device)
goto file_was_dumped;
}
#ifdef HAVE_READLINK
else if (S_ISLNK (current_stat.st_mode))
else if (S_ISLNK (current_stat_info.stat.st_mode))
{
char *buffer;
int size;
size_t linklen = current_stat.st_size;
if (linklen != current_stat.st_size || linklen + 1 == 0)
size_t linklen = current_stat_info.stat.st_size;
if (linklen != current_stat_info.stat.st_size || linklen + 1 == 0)
xalloc_die ();
buffer = (char *) alloca (linklen + 1);
size = readlink (p, buffer, linklen + 1);
@@ -1448,11 +1448,11 @@ dump_file (char *p, int top_level, dev_t parent_device)
buffer[size] = '\0';
if (size >= NAME_FIELD_SIZE)
write_long (buffer, GNUTYPE_LONGLINK);
assign_string (&current_link_name, buffer);
assign_string (&current_stat_info.link_name, buffer);
block_ordinal = current_block_ordinal ();
current_stat.st_size = 0; /* force 0 size on symlink */
header = start_header (p, &current_stat);
current_stat_info.stat.st_size = 0; /* force 0 size on symlink */
header = start_header (p, &current_stat_info);
strncpy (header->header.linkname, buffer, NAME_FIELD_SIZE);
header->header.linkname[NAME_FIELD_SIZE - 1] = '\0';
header->header.typeflag = SYMTYPE;
@@ -1467,18 +1467,18 @@ dump_file (char *p, int top_level, dev_t parent_device)
goto file_was_dumped;
}
#endif
else if (S_ISCHR (current_stat.st_mode))
else if (S_ISCHR (current_stat_info.stat.st_mode))
type = CHRTYPE;
else if (S_ISBLK (current_stat.st_mode))
else if (S_ISBLK (current_stat_info.stat.st_mode))
type = BLKTYPE;
else if (S_ISFIFO (current_stat.st_mode))
else if (S_ISFIFO (current_stat_info.stat.st_mode))
type = FIFOTYPE;
else if (S_ISSOCK (current_stat.st_mode))
else if (S_ISSOCK (current_stat_info.stat.st_mode))
{
WARN ((0, 0, _("%s: socket ignored"), quotearg_colon (p)));
return;
}
else if (S_ISDOOR (current_stat.st_mode))
else if (S_ISDOOR (current_stat_info.stat.st_mode))
{
WARN ((0, 0, _("%s: door ignored"), quotearg_colon (p)));
return;
@@ -1491,14 +1491,14 @@ dump_file (char *p, int top_level, dev_t parent_device)
goto unknown;
block_ordinal = current_block_ordinal ();
current_stat.st_size = 0; /* force 0 size */
header = start_header (p, &current_stat);
current_stat_info.stat.st_size = 0; /* force 0 size */
header = start_header (p, &current_stat_info);
header->header.typeflag = type;
if (type != FIFOTYPE)
{
MAJOR_TO_CHARS (major (current_stat.st_rdev), header->header.devmajor);
MINOR_TO_CHARS (minor (current_stat.st_rdev), header->header.devminor);
MAJOR_TO_CHARS (major (current_stat_info.stat.st_rdev), header->header.devmajor);
MINOR_TO_CHARS (minor (current_stat_info.stat.st_rdev), header->header.devminor);
}
finish_header (header, block_ordinal);
@@ -1517,14 +1517,14 @@ unknown:
return;
file_was_dumped:
if (1 < current_stat.st_nlink)
if (1 < current_stat_info.stat.st_nlink)
{
struct link *dup;
struct link *lp = xmalloc (offsetof (struct link, name)
+ strlen (p) + 1);
lp->ino = current_stat.st_ino;
lp->dev = current_stat.st_dev;
lp->nlink = current_stat.st_nlink;
lp->ino = current_stat_info.stat.st_ino;
lp->dev = current_stat_info.stat.st_dev;
lp->nlink = current_stat_info.stat.st_nlink;
strcpy (lp->name, p);
if (! ((link_table

View File

@@ -1,5 +1,7 @@
/* Delete entries from a tar archive.
Copyright (C) 1988, 1992, 1994, 1996, 1997 Free Software Foundation, Inc.
Copyright (C) 1988, 1992, 1994, 1996, 1997, 2000, 2001, 2003 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
@@ -13,97 +15,95 @@
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 Place - Suite 330, Boston, MA 02111-1307, USA. */
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "system.h"
#define STDIN 0
#define STDOUT 1
#include "common.h"
#include "rmt.h"
static union block *new_record = NULL;
static union block *save_record = NULL;
static int records_read = 0;
static int new_blocks = 0;
static int blocks_needed = 0;
static union block *new_record;
static int new_blocks;
static bool acting_as_filter;
/* FIXME: This module should not directly handle the following three
variables, instead, this should be done in buffer.c only. */
/* FIXME: This module should not directly handle the following
variables, instead, the interface should be cleaned up. */
extern union block *record_start;
extern union block *record_end;
extern union block *current_block;
extern union block *recent_long_name;
extern union block *recent_long_link;
extern off_t records_read;
extern off_t records_written;
/*-------------------------------------------------------------------------.
| Move archive descriptor by COUNT records worth. If COUNT is positive we |
| move forward, else we move negative. If its a tape, MTIOCTOP had better |
| work. If its something else, we try to seek on it. If we can't seek, |
| we loose! |
`-------------------------------------------------------------------------*/
/* The number of records skipped at the start of the archive, when
passing over members that are not deleted. */
static off_t records_skipped;
/* Move archive descriptor by COUNT records worth. If COUNT is
positive we move forward, else we move negative. If it's a tape,
MTIOCTOP had better work. If it's something else, we try to seek
on it. If we can't seek, we lose! */
static void
move_archive (int count)
move_archive (off_t count)
{
if (count == 0)
return;
#ifdef MTIOCTOP
{
struct mtop operation;
int status;
if (count > 0)
if (count < 0
? (operation.mt_op = MTBSR,
operation.mt_count = -count,
operation.mt_count == -count)
: (operation.mt_op = MTFSR,
operation.mt_count = count,
operation.mt_count == count))
{
operation.mt_op = MTFSR;
operation.mt_count = count;
}
else
{
operation.mt_op = MTBSR;
operation.mt_count = -count;
}
if (0 <= rmtioctl (archive, MTIOCTOP, (char *) &operation))
return;
if (status = rmtioctl (archive, MTIOCTOP, (char *) &operation),
status >= 0)
return;
if (errno == EIO)
if (status = rmtioctl (archive, MTIOCTOP, (char *) &operation),
status >= 0)
return;
if (errno == EIO
&& 0 <= rmtioctl (archive, MTIOCTOP, (char *) &operation))
return;
}
}
#endif /* MTIOCTOP */
{
off_t position = rmtlseek (archive, 0L, 1);
off_t position0 = rmtlseek (archive, (off_t) 0, SEEK_CUR);
off_t increment = record_size * (off_t) count;
off_t position = position0 + increment;
position += record_size * count;
if (rmtlseek (archive, position, 0) != position)
FATAL_ERROR ((0, 0, _("Could not re-position archive file")));
if (increment / count != record_size
|| (position < position0) != (increment < 0)
|| (position = position < 0 ? 0 : position,
rmtlseek (archive, position, SEEK_SET) != position))
seek_error_details (archive_name_array[0], position);
return;
}
}
/*----------------------------------------------------------------.
| Write out the record which has been filled. If MOVE_BACK_FLAG, |
| backspace to where we started. |
`----------------------------------------------------------------*/
/* Write out the record which has been filled. If MOVE_BACK_FLAG,
backspace to where we started. */
static void
write_record (int move_back_flag)
{
save_record = record_start;
union block *save_record = record_start;
record_start = new_record;
if (archive == STDIN)
if (acting_as_filter)
{
archive = STDOUT;
archive = STDOUT_FILENO;
flush_write ();
archive = STDIN;
archive = STDIN_FILENO;
}
else
{
move_archive (-(records_read + 1));
move_archive ((records_written + records_skipped) - records_read);
flush_write ();
}
@@ -113,19 +113,24 @@ write_record (int move_back_flag)
{
/* Move the tape head back to where we were. */
if (archive != STDIN)
move_archive (records_read);
records_read--;
if (! acting_as_filter)
move_archive (records_read - (records_written + records_skipped));
}
blocks_needed = blocking_factor;
new_blocks = 0;
}
/*---.
| ? |
`---*/
static void
write_recent_blocks (union block *h, size_t blocks)
{
size_t i;
for (i = 0; i < blocks; i++)
{
new_record[new_blocks++] = h[i];
if (new_blocks == blocking_factor)
write_record (1);
}
}
void
delete_archive_members (void)
@@ -135,16 +140,17 @@ delete_archive_members (void)
/* FIXME: Should clean the routine before cleaning these variables :-( */
struct name *name;
int blocks_to_skip = 0;
int blocks_to_keep = 0;
off_t blocks_to_skip = 0;
off_t blocks_to_keep = 0;
int kept_blocks_in_record;
name_gather ();
open_archive (ACCESS_UPDATE);
acting_as_filter = strcmp (archive_name_array[0], "-") == 0;
while (logical_status == HEADER_STILL_UNREAD)
do
{
enum read_header status = read_header ();
enum read_header status = read_header (1);
switch (status)
{
@@ -152,19 +158,24 @@ delete_archive_members (void)
abort ();
case HEADER_SUCCESS:
if (name = name_scan (current_file_name), !name)
if (name = name_scan (current_stat_info.file_name), !name)
{
set_next_block_after (current_header);
if (current_header->oldgnu_header.isextended)
skip_extended_headers ();
skip_file ((long) (current_stat.st_size));
skip_member ();
break;
}
name->found = 1;
logical_status = HEADER_SUCCESS;
/* Fall through. */
case HEADER_SUCCESS_EXTENDED:
logical_status = status;
break;
case HEADER_ZERO_BLOCK:
if (ignore_zeros_option)
{
set_next_block_after (current_header);
break;
}
/* Fall through. */
case HEADER_END_OF_FILE:
logical_status = HEADER_END_OF_FILE;
break;
@@ -193,144 +204,159 @@ delete_archive_members (void)
previous_status = status;
}
while (logical_status == HEADER_STILL_UNREAD);
if (logical_status != HEADER_SUCCESS)
records_skipped = records_read - 1;
new_record = xmalloc (record_size);
if (logical_status == HEADER_SUCCESS
|| logical_status == HEADER_SUCCESS_EXTENDED)
{
write_eot ();
close_archive ();
names_notfound ();
return;
}
write_archive_to_stdout = 0;
write_archive_to_stdout = 0;
new_record = (union block *) xmalloc ((size_t) record_size);
/* Save away blocks before this one in this record. */
/* Save away blocks before this one in this record. */
new_blocks = current_block - record_start;
if (new_blocks)
memcpy (new_record, record_start, new_blocks * BLOCKSIZE);
new_blocks = current_block - record_start;
blocks_needed = blocking_factor - new_blocks;
if (new_blocks)
memcpy ((void *) new_record, (void *) record_start,
(size_t) (new_blocks * BLOCKSIZE));
#if 0
/* FIXME: Old code, before the goto was inserted. To be redesigned. */
set_next_block_after (current_header);
if (current_header->oldgnu_header.isextended)
skip_extended_headers ();
skip_file ((long) (current_stat.st_size));
#endif
logical_status = HEADER_STILL_UNREAD;
goto flush_file;
/* FIXME: Solaris 2.4 Sun cc (the ANSI one, not the old K&R) says:
"delete.c", line 223: warning: loop not entered at top
Reported by Bruno Haible. */
while (1)
{
enum read_header status;
/* Fill in a record. */
if (current_block == record_end)
if (logical_status == HEADER_SUCCESS)
{
flush_archive ();
records_read++;
}
status = read_header ();
if (status == HEADER_ZERO_BLOCK && ignore_zeros_option)
{
set_next_block_after (current_header);
continue;
}
if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK)
{
logical_status = HEADER_END_OF_FILE;
memset (new_record[new_blocks].buffer, 0,
(size_t) (BLOCKSIZE * blocks_needed));
new_blocks += blocks_needed;
blocks_needed = 0;
write_record (0);
break;
/* FIXME: Pheew! This is crufty code! */
logical_status = HEADER_STILL_UNREAD;
goto flush_file;
}
if (status == HEADER_FAILURE)
/* FIXME: Solaris 2.4 Sun cc (the ANSI one, not the old K&R) says:
"delete.c", line 223: warning: loop not entered at top
Reported by Bruno Haible. */
while (1)
{
ERROR ((0, 0, _("Deleting non-header from archive")));
set_next_block_after (current_header);
continue;
}
enum read_header status;
/* Found another header. */
if (name = name_scan (current_file_name), name)
{
name->found = 1;
flush_file:
set_next_block_after (current_header);
blocks_to_skip = (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
while (record_end - current_block <= blocks_to_skip)
{
blocks_to_skip -= (record_end - current_block);
flush_archive ();
records_read++;
}
current_block += blocks_to_skip;
blocks_to_skip = 0;
continue;
}
/* Copy header. */
new_record[new_blocks] = *current_header;
new_blocks++;
blocks_needed--;
blocks_to_keep
= (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
set_next_block_after (current_header);
if (blocks_needed == 0)
write_record (1);
/* Copy data. */
kept_blocks_in_record = record_end - current_block;
if (kept_blocks_in_record > blocks_to_keep)
kept_blocks_in_record = blocks_to_keep;
while (blocks_to_keep)
{
int count;
/* Fill in a record. */
if (current_block == record_end)
flush_archive ();
status = read_header (0);
if (status == HEADER_ZERO_BLOCK && ignore_zeros_option)
{
flush_read ();
records_read++;
current_block = record_start;
kept_blocks_in_record = blocking_factor;
if (kept_blocks_in_record > blocks_to_keep)
kept_blocks_in_record = blocks_to_keep;
set_next_block_after (current_header);
continue;
}
if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK)
{
logical_status = HEADER_END_OF_FILE;
break;
}
count = kept_blocks_in_record;
if (count > blocks_needed)
count = blocks_needed;
memcpy ((void *) (new_record + new_blocks),
(void *) current_block,
(size_t) (count * BLOCKSIZE));
new_blocks += count;
blocks_needed -= count;
current_block += count;
blocks_to_keep -= count;
kept_blocks_in_record -= count;
if (status == HEADER_FAILURE)
{
ERROR ((0, 0, _("Deleting non-header from archive")));
set_next_block_after (current_header);
continue;
}
if (blocks_needed == 0)
/* Found another header. */
if (name = name_scan (current_stat_info.file_name), name)
{
name->found = 1;
flush_file:
set_next_block_after (current_header);
blocks_to_skip = (current_stat_info.stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
while (record_end - current_block <= blocks_to_skip)
{
blocks_to_skip -= (record_end - current_block);
flush_archive ();
}
current_block += blocks_to_skip;
blocks_to_skip = 0;
continue;
}
/* Copy header. */
write_recent_blocks (recent_long_name, recent_long_name_blocks);
write_recent_blocks (recent_long_link, recent_long_link_blocks);
new_record[new_blocks] = *current_header;
new_blocks++;
blocks_to_keep
= (current_stat_info.stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
set_next_block_after (current_header);
if (new_blocks == blocking_factor)
write_record (1);
/* Copy data. */
kept_blocks_in_record = record_end - current_block;
if (kept_blocks_in_record > blocks_to_keep)
kept_blocks_in_record = blocks_to_keep;
while (blocks_to_keep)
{
int count;
if (current_block == record_end)
{
flush_read ();
current_block = record_start;
kept_blocks_in_record = blocking_factor;
if (kept_blocks_in_record > blocks_to_keep)
kept_blocks_in_record = blocks_to_keep;
}
count = kept_blocks_in_record;
if (blocking_factor - new_blocks < count)
count = blocking_factor - new_blocks;
if (! count)
abort ();
memcpy (new_record + new_blocks, current_block, count * BLOCKSIZE);
new_blocks += count;
current_block += count;
blocks_to_keep -= count;
kept_blocks_in_record -= count;
if (new_blocks == blocking_factor)
write_record (1);
}
}
}
write_eot ();
if (logical_status == HEADER_END_OF_FILE)
{
/* Write the end of tape. FIXME: we can't use write_eot here,
as it gets confused when the input is at end of file. */
int total_zero_blocks = 0;
do
{
int zero_blocks = blocking_factor - new_blocks;
memset (new_record + new_blocks, 0, BLOCKSIZE * zero_blocks);
total_zero_blocks += zero_blocks;
write_record (total_zero_blocks < 2);
}
while (total_zero_blocks < 2);
}
free (new_record);
if (! acting_as_filter && ! _isrmt (archive))
{
#if MSDOS
int status = write (archive, "", 0);
#else
off_t pos = lseek (archive, (off_t) 0, SEEK_CUR);
int status = pos < 0 ? -1 : ftruncate (archive, pos);
#endif
if (status != 0)
truncate_warn (archive_name_array[0]);
}
close_archive ();
names_notfound ();
}

View File

@@ -129,14 +129,15 @@ extr_init (void)
}
/* If restoring permissions, restore the mode for FILE_NAME from
information given in *STAT_INFO (where *CURRENT_STAT_INFO gives
the current status if CURRENT_STAT_INFO is nonzero); otherwise invert the
information given in *STAT_INFO (where *CUR_INFO gives
the current status if CUR_INFO is nonzero); otherwise invert the
INVERT_PERMISSIONS bits from the file's current permissions.
PERMSTATUS specifies the status of the file's permissions.
TYPEFLAG specifies the type of the file. */
static void
set_mode (char const *file_name, struct stat const *stat_info,
struct stat const *current_stat_info,
set_mode (char const *file_name,
struct stat const *stat_info,
struct stat const *cur_info,
mode_t invert_permissions, enum permstatus permstatus,
char typeflag)
{
@@ -168,16 +169,16 @@ set_mode (char const *file_name, struct stat const *stat_info,
that we created, so there's no point optimizing this code for
other cases. */
struct stat st;
if (! current_stat_info)
if (! cur_info)
{
if (stat (file_name, &st) != 0)
{
stat_error (file_name);
return;
}
current_stat_info = &st;
cur_info = &st;
}
mode = current_stat_info->st_mode ^ invert_permissions;
mode = cur_info->st_mode ^ invert_permissions;
}
if (chmod (file_name, mode) != 0)
@@ -199,7 +200,7 @@ check_time (char const *file_name, time_t t)
/* Restore stat attributes (owner, group, mode and times) for
FILE_NAME, using information given in *STAT_INFO.
If CURRENT_STAT_INFO is nonzero, *CURRENT_STAT_INFO is the
If CUR_INFO is nonzero, *CUR_INFO is the
file's currernt status.
If not restoring permissions, invert the
INVERT_PERMISSIONS bits from the file's current permissions.
@@ -212,8 +213,9 @@ check_time (char const *file_name, time_t t)
punt for the rest. Sigh! */
static void
set_stat (char const *file_name, struct stat const *stat_info,
struct stat const *current_stat_info,
set_stat (char const *file_name,
struct stat const *stat_info,
struct stat const *cur_info,
mode_t invert_permissions, enum permstatus permstatus,
char typeflag)
{
@@ -252,7 +254,7 @@ set_stat (char const *file_name, struct stat const *stat_info,
done, it is not possible anymore to change file permissions, so we
have to set permissions prior to possibly giving files away. */
set_mode (file_name, stat_info, current_stat_info,
set_mode (file_name, stat_info, cur_info,
invert_permissions, permstatus, typeflag);
}
@@ -332,9 +334,9 @@ repair_delayed_set_stat (char const *dir_name,
if (st.st_dev == dir_stat_info->st_dev
&& st.st_ino == dir_stat_info->st_ino)
{
data->stat_info = current_stat;
data->invert_permissions = (MODE_RWX
& (current_stat.st_mode ^ st.st_mode));
data->stat_info = current_stat_info.stat;
data->invert_permissions =
(MODE_RWX & (current_stat_info.stat.st_mode ^ st.st_mode));
data->permstatus = ARCHIVED_PERMSTATUS;
return;
}
@@ -388,7 +390,7 @@ make_directories (char *file_name)
invert_permissions is zero, because
repair_delayed_set_stat may need to update the struct. */
delay_set_stat (file_name,
&current_stat /* ignored */,
&current_stat_info.stat /* ignored */,
invert_permissions, INTERDIR_PERMSTATUS);
print_for_mkdir (file_name, cursor - file_name, mode);
@@ -400,13 +402,16 @@ make_directories (char *file_name)
*cursor = '/';
if (errno == EEXIST
if (errno == EEXIST)
continue; /* Directory already exists. */
else if ((errno == ENOSYS /* Automounted dirs on Solaris return
this. Reported by Warren Hyde
<Warren.Hyde@motorola.com> */
#if MSDOS
/* Turbo C mkdir gives a funny errno. */
|| errno == EACCES
|| errno == EACCES /* Turbo C mkdir gives a funny errno. */
#endif
)
/* Directory already exists. */
)
&& access (file_name, W_OK) == 0)
continue;
/* Some other error in the mkdir. We return to the caller. */
@@ -493,7 +498,7 @@ maybe_recoverable (char *file_name, int *interdir_made)
bool
fill_in_sparse_array (void)
{
off_t sparse_data_size = current_stat.st_size;
off_t sparse_data_size = current_stat_info.stat.st_size;
off_t file_size = OFF_FROM_HEADER (current_header->oldgnu_header.realsize);
int sparses;
int counter;
@@ -560,7 +565,8 @@ fill_in_sparse_array (void)
return 1;
invalid_member:
ERROR ((0, 0, "%s: invalid sparse archive member", current_file_name));
ERROR ((0, 0, _("%s: invalid sparse archive member"),
current_stat_info.file_name));
return 0;
}
@@ -640,7 +646,7 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_symlinks)
struct delayed_set_stat *data = delayed_set_stat_head;
bool skip_this_one = 0;
struct stat st;
struct stat const *current_stat_info = 0;
struct stat const *cur_info = 0;
check_for_renamed_directories |= data->after_symlinks;
@@ -654,7 +660,7 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_symlinks)
if (check_for_renamed_directories)
{
current_stat_info = &st;
cur_info = &st;
if (stat (data->file_name, &st) != 0)
{
stat_error (data->file_name);
@@ -671,7 +677,7 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_symlinks)
}
if (! skip_this_one)
set_stat (data->file_name, &data->stat_info, current_stat_info,
set_stat (data->file_name, &data->stat_info, cur_info,
data->invert_permissions, data->permstatus, DIRTYPE);
delayed_set_stat_head = data->next;
@@ -694,13 +700,12 @@ extract_archive (void)
off_t file_size;
int interdir_made = 0;
char typeflag;
union block *exhdr;
char *file_name;
set_next_block_after (current_header);
decode_header (current_header, &current_stat, &current_format, 1);
decode_header (current_header, &current_stat_info, &current_format, 1);
if (interactive_option && !confirm ("extract", current_file_name))
if (interactive_option && !confirm ("extract", current_stat_info.file_name))
{
skip_member ();
return;
@@ -711,7 +716,7 @@ extract_archive (void)
if (verbose_option)
print_header (-1);
file_name = safer_name_suffix (current_file_name, 0);
file_name = safer_name_suffix (current_stat_info.file_name, 0);
apply_nonancestor_delayed_set_stat (file_name, 0);
@@ -745,7 +750,7 @@ extract_archive (void)
/* Appears to be a file. But BSD tar uses the convention that a slash
suffix means a directory. */
if (current_trailing_slash)
if (current_stat_info.had_trailing_slash)
goto really_dir;
/* FIXME: deal with protection issues. */
@@ -755,7 +760,7 @@ extract_archive (void)
| (old_files_option == OVERWRITE_OLD_FILES
? O_TRUNC
: O_EXCL));
mode = current_stat.st_mode & MODE_RWX & ~ current_umask;
mode = current_stat_info.stat.st_mode & MODE_RWX & ~ current_umask;
if (to_stdout_option)
{
@@ -776,7 +781,7 @@ extract_archive (void)
the open call that creates them. */
if (typeflag == CONTTYPE)
fd = open (file_name, openflag | O_CTG, mode, current_stat.st_size);
fd = open (file_name, openflag | O_CTG, mode, current_stat_info.stat.st_size);
else
fd = open (file_name, openflag, mode);
@@ -823,16 +828,16 @@ extract_archive (void)
name = xmalloc (name_length_bis);
memcpy (name, file_name, name_length_bis);
size = extract_sparse_file (fd, name,
current_stat.st_size, file_size);
current_stat_info.stat.st_size, file_size);
free (sparsearray);
}
else
for (size = current_stat.st_size; size > 0; )
for (size = current_stat_info.stat.st_size; size > 0; )
{
if (multi_volume_option)
{
assign_string (&save_name, current_file_name);
save_totsize = current_stat.st_size;
assign_string (&save_name, current_stat_info.file_name);
save_totsize = current_stat_info.stat.st_size;
save_sizeleft = size;
}
@@ -883,7 +888,7 @@ extract_archive (void)
undo_last_backup ();
}
set_stat (file_name, &current_stat, 0, 0,
set_stat (file_name, &current_stat_info.stat, 0, 0,
(old_files_option == OVERWRITE_OLD_FILES
? UNKNOWN_PERMSTATUS
: ARCHIVED_PERMSTATUS),
@@ -896,19 +901,19 @@ extract_archive (void)
break;
if (absolute_names_option
|| ! (ISSLASH (current_link_name
[FILESYSTEM_PREFIX_LEN (current_link_name)])
|| contains_dot_dot (current_link_name)))
|| ! (ISSLASH (current_stat_info.link_name
[FILESYSTEM_PREFIX_LEN (current_stat_info.link_name)])
|| contains_dot_dot (current_stat_info.link_name)))
{
while (status = symlink (current_link_name, file_name),
while (status = symlink (current_stat_info.link_name, file_name),
status != 0)
if (!maybe_recoverable (file_name, &interdir_made))
break;
if (status == 0)
set_stat (file_name, &current_stat, 0, 0, 0, SYMTYPE);
set_stat (file_name, &current_stat_info.stat, 0, 0, 0, SYMTYPE);
else
symlink_error (current_link_name, file_name);
symlink_error (current_stat_info.link_name, file_name);
}
else
{
@@ -937,19 +942,19 @@ extract_archive (void)
struct delayed_set_stat *h;
struct delayed_symlink *p =
xmalloc (offsetof (struct delayed_symlink, target)
+ strlen (current_link_name) + 1);
+ strlen (current_stat_info.link_name) + 1);
p->next = delayed_symlink_head;
delayed_symlink_head = p;
p->dev = st.st_dev;
p->ino = st.st_ino;
p->mtime = st.st_mtime;
p->uid = current_stat.st_uid;
p->gid = current_stat.st_gid;
p->uid = current_stat_info.stat.st_uid;
p->gid = current_stat_info.stat.st_gid;
p->sources = xmalloc (offsetof (struct string_list, string)
+ strlen (file_name) + 1);
p->sources->next = 0;
strcpy (p->sources->string, file_name);
strcpy (p->target, current_link_name);
strcpy (p->target, current_stat_info.link_name);
h = delayed_set_stat_head;
if (h && ! h->after_symlinks
@@ -1002,7 +1007,7 @@ extract_archive (void)
again_link:
{
char const *link_name = safer_name_suffix (current_link_name, 1);
char const *link_name = safer_name_suffix (current_stat_info.link_name, 1);
struct stat st1, st2;
int e;
@@ -1049,13 +1054,13 @@ extract_archive (void)
#if S_IFCHR
case CHRTYPE:
current_stat.st_mode |= S_IFCHR;
current_stat_info.stat.st_mode |= S_IFCHR;
goto make_node;
#endif
#if S_IFBLK
case BLKTYPE:
current_stat.st_mode |= S_IFBLK;
current_stat_info.stat.st_mode |= S_IFBLK;
#endif
#if S_IFCHR || S_IFBLK
@@ -1063,8 +1068,8 @@ extract_archive (void)
if (! prepare_to_extract (file_name, 0))
break;
status = mknod (file_name, current_stat.st_mode,
current_stat.st_rdev);
status = mknod (file_name, current_stat_info.stat.st_mode,
current_stat_info.stat.st_rdev);
if (status != 0)
{
if (maybe_recoverable (file_name, &interdir_made))
@@ -1074,7 +1079,7 @@ extract_archive (void)
undo_last_backup ();
break;
};
set_stat (file_name, &current_stat, 0, 0,
set_stat (file_name, &current_stat_info.stat, 0, 0,
ARCHIVED_PERMSTATUS, typeflag);
break;
#endif
@@ -1084,13 +1089,13 @@ extract_archive (void)
if (! prepare_to_extract (file_name, 0))
break;
while (status = mkfifo (file_name, current_stat.st_mode),
while (status = mkfifo (file_name, current_stat_info.stat.st_mode),
status != 0)
if (!maybe_recoverable (file_name, &interdir_made))
break;
if (status == 0)
set_stat (file_name, &current_stat, 0, 0,
set_stat (file_name, &current_stat_info.stat, NULL, 0,
ARCHIVED_PERMSTATUS, typeflag);
else
{
@@ -1114,7 +1119,7 @@ extract_archive (void)
else if (typeflag == GNUTYPE_DUMPDIR)
skip_member ();
mode = ((current_stat.st_mode
mode = ((current_stat_info.stat.st_mode
| (we_are_root ? 0 : MODE_WXUSR))
& MODE_RWX);
@@ -1167,8 +1172,8 @@ extract_archive (void)
if (status == 0
|| old_files_option == DEFAULT_OLD_FILES
|| old_files_option == OVERWRITE_OLD_FILES)
delay_set_stat (file_name, &current_stat,
MODE_RWX & (mode ^ current_stat.st_mode),
delay_set_stat (file_name, &current_stat_info.stat,
MODE_RWX & (mode ^ current_stat_info.stat.st_mode),
(status == 0
? ARCHIVED_PERMSTATUS
: UNKNOWN_PERMSTATUS));
@@ -1176,7 +1181,7 @@ extract_archive (void)
case GNUTYPE_VOLHDR:
if (verbose_option)
fprintf (stdlis, _("Reading %s\n"), quote (current_file_name));
fprintf (stdlis, _("Reading %s\n"), quote (current_stat_info.file_name));
break;
case GNUTYPE_NAMES:
@@ -1186,7 +1191,7 @@ extract_archive (void)
case GNUTYPE_MULTIVOL:
ERROR ((0, 0,
_("%s: Cannot extract -- file is continued from another volume"),
quotearg_colon (current_file_name)));
quotearg_colon (current_stat_info.file_name)));
skip_member ();
if (backup_option)
undo_last_backup ();

File diff suppressed because it is too large Load Diff