};
#endif
+#include <quotearg.h>
+
#include "common.h"
#ifndef MSDOS
if (!warned_once)
{
warned_once = 1;
- WARN ((0, 0, _("Removing `%.*s' prefix from archive names"),
+ WARN ((0, 0, _("Removing `%.*s' prefix from member names"),
(int) prefix_len, name));
}
name += prefix_len;
if (!warned_once)
{
warned_once = 1;
- WARN ((0, 0, _("Removing leading `/' from archive names")));
+ WARN ((0, 0, _("Removing leading `/' from member names")));
}
name++;
}
+
+ {
+ static int warned_once;
+ if (! warned_once && contains_dot_dot (name))
+ {
+ warned_once = 1;
+ WARN ((0, 0, _("Member names contain `..'")));
+ }
+ }
}
if (sizeof header->header.name <= strlen (name))
| ? |
`---*/
-static void
-find_new_file_size (off_t *filesize, int highest_index)
+static off_t
+find_new_file_size (int sparses)
{
- int counter;
-
- *filesize = 0;
- for (counter = 0;
- sparsearray[counter].numbytes && counter <= highest_index;
- counter++)
- *filesize += sparsearray[counter].numbytes;
+ int i;
+ off_t s = 0;
+ for (i = 0; i < sparses; i++)
+ s += sparsearray[i].numbytes;
+ return s;
}
/*-----------------------------------------------------------------------.
size_t numbytes = 0;
off_t offset = 0;
int file;
- int sparse_index = 0;
+ int sparses = 0;
ssize_t count;
char buffer[BLOCKSIZE];
init_sparsearray ();
clear_buffer (buffer);
- while (count = safe_read (file, buffer, sizeof buffer), count != 0)
+ while (0 < (count = safe_read (file, buffer, sizeof buffer)))
{
/* Realloc the scratch area as necessary. FIXME: should reallocate
only at beginning of a new instance of non-zero data. */
- if (sparse_index > sp_array_size - 1)
+ if (sp_array_size <= sparses)
{
sparsearray =
xrealloc (sparsearray,
{
if (numbytes)
{
- sparsearray[sparse_index++].numbytes = numbytes;
+ sparsearray[sparses++].numbytes = numbytes;
numbytes = 0;
}
}
else
{
if (!numbytes)
- sparsearray[sparse_index].offset = offset;
+ sparsearray[sparses].offset = offset;
numbytes += count;
}
if (!zero_block_p (buffer))
{
if (!numbytes)
- sparsearray[sparse_index].offset = offset;
+ sparsearray[sparses].offset = offset;
numbytes += count;
}
else
}
if (numbytes)
- sparsearray[sparse_index++].numbytes = numbytes;
+ sparsearray[sparses++].numbytes = numbytes;
else
{
- sparsearray[sparse_index].offset = offset - 1;
- sparsearray[sparse_index++].numbytes = 1;
+ sparsearray[sparses].offset = offset - 1;
+ sparsearray[sparses++].numbytes = 1;
}
close (file);
- return sparse_index - 1;
+ return count < 0 ? 0 : sparses;
}
/*---.
{
union block *start;
size_t bufsize;
- int sparse_index = 0;
+ int sparses = 0;
ssize_t count;
while (*sizeleft > 0)
{
start = find_next_block ();
memset (start->buffer, 0, BLOCKSIZE);
- bufsize = sparsearray[sparse_index].numbytes;
- if (!bufsize)
- {
- /* We blew it, maybe. */
- char buf1[UINTMAX_STRSIZE_BOUND];
- char buf2[UINTMAX_STRSIZE_BOUND];
-
- ERROR ((0, 0, _("Wrote %s of %s bytes to file %s"),
- STRINGIFY_BIGINT (fullsize - *sizeleft, buf1),
- STRINGIFY_BIGINT (fullsize, buf2),
- name));
- break;
- }
+ bufsize = sparsearray[sparses].numbytes;
+ if (! bufsize)
+ abort ();
- if (lseek (file, sparsearray[sparse_index++].offset, SEEK_SET) < 0)
+ if (lseek (file, sparsearray[sparses++].offset, SEEK_SET) < 0)
{
- char buf[UINTMAX_STRSIZE_BOUND];
- ERROR ((0, errno, _("lseek error at byte %s in file %s"),
- STRINGIFY_BIGINT (sparsearray[sparse_index - 1].offset, buf),
- name));
+ (ignore_failed_read_option ? seek_warn_details : seek_error_details)
+ (name, sparsearray[sparses - 1].offset);
break;
}
while (bufsize > BLOCKSIZE)
{
-#if 0
- if (amount_read)
- {
- count = safe_read (file, start->buffer + amount_read,
- BLOCKSIZE - amount_read);
- bufsize -= BLOCKSIZE - amount_read;
- amount_read = 0;
- set_next_block_after (start);
- start = find_next_block ();
- memset (start->buffer, 0, BLOCKSIZE);
- }
-#endif
- /* Store the data. */
-
count = safe_read (file, start->buffer, BLOCKSIZE);
if (count < 0)
{
- char buf[UINTMAX_STRSIZE_BOUND];
- ERROR ((0, errno,
- _("Read error at byte %s, reading %lu bytes, in file %s"),
- STRINGIFY_BIGINT (fullsize - *sizeleft, buf),
- (unsigned long) bufsize, name));
+ (ignore_failed_read_option
+ ? read_warn_details
+ : read_error_details)
+ (name, fullsize - *sizeleft, bufsize);
return 1;
}
bufsize -= count;
if (count < 0)
{
- char buf[UINTMAX_STRSIZE_BOUND];
-
- ERROR ((0, errno,
- _("Read error at byte %s, reading %lu bytes, in file %s"),
- STRINGIFY_BIGINT (fullsize - *sizeleft, buf),
- (unsigned long) bufsize, name));
+ (ignore_failed_read_option
+ ? read_warn_details
+ : read_error_details)
+ (name, fullsize - *sizeleft, bufsize);
return 1;
}
-#if 0
- if (amount_read >= BLOCKSIZE)
- {
- amount_read = 0;
- set_next_block_after (start + (count - 1) / BLOCKSIZE);
- if (count != bufsize)
- {
- ERROR ((0, 0,
- _("File %s shrunk, padding with zeros"),
- name));
- return 1;
- }
- start = find_next_block ();
- }
- else
- amount_read += bufsize;
-#endif
+
*sizeleft -= count;
set_next_block_after (start);
-
}
free (sparsearray);
#if 0
/* Dump a single file, recursing on directories. P is the file name
to dump. TOP_LEVEL tells whether this is a top-level call; zero
means no, positive means yes, and negative means an incremental
- dump where it's irrelevant. PARENT_DEVICE is the device of P's
+ 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. */
char type;
union block *exhdr;
char save_typeflag;
+ time_t original_ctime;
struct utimbuf restore_times;
- off_t restore_size;
- /* FIXME: `header' and `upperbound' might be used uninitialized in this
+ /* FIXME: `header' and `sparses' might be used uninitialized in this
function. Reported by Bruno Haible. */
if (interactive_option && !confirm ("add", p))
if (deref_stat (dereference_option, p, ¤t_stat) != 0)
{
- WARN ((0, errno, _("Cannot add file %s"), p));
- if (!ignore_failed_read_option)
- exit_status = TAREXIT_FAILURE;
+ if (ignore_failed_read_option)
+ stat_warn (p);
+ else
+ stat_error (p);
return;
}
+ original_ctime = current_stat.st_ctime;
restore_times.actime = current_stat.st_atime;
restore_times.modtime = current_stat.st_mtime;
- restore_size = current_stat.st_size;
#ifdef S_ISHIDDEN
if (S_ISHIDDEN (current_stat.st_mode))
&& (!after_date_option || current_stat.st_ctime < newer_ctime_option))
{
if (0 < top_level)
- WARN ((0, 0, _("%s: is unchanged; not dumped"), p));
+ WARN ((0, 0, _("%s: file is unchanged; not dumped"),
+ quotearg_colon (p)));
/* FIXME: recheck this return. */
return;
}
if (ar_dev && current_stat.st_dev == ar_dev && current_stat.st_ino == ar_ino)
{
- WARN ((0, 0, _("%s is the archive; not dumped"), p));
+ WARN ((0, 0, _("%s: file is the archive; not dumped"),
+ quotearg_colon (p)));
return;
}
#endif
size_t len;
dev_t our_device = current_stat.st_dev;
- /* If this tar program is installed suid root, like for Amanda, the
- access might look like denied, while it is not really.
-
- FIXME: I have the feeling this test is done too early. Couldn't it
- just be bundled in later actions? I guess that the proper support
- of --ignore-failed-read is the key of the current writing. */
+ errno = 0;
- if (access (p, R_OK) == -1 && geteuid () != 0)
+ directory = opendir (p);
+ if (! directory)
{
- WARN ((0, errno, _("Cannot add directory %s"), p));
- if (!ignore_failed_read_option)
- exit_status = TAREXIT_FAILURE;
+ if (ignore_failed_read_option)
+ opendir_warn (p);
+ else
+ opendir_error (p);
return;
}
}
if (multi_volume_option)
assign_string (&save_name, 0);
- if (atime_preserve_option)
- utime (p, &restore_times);
- return;
+ goto finish_dir;
}
/* See if we are about to recurse into a directory, and avoid doing
so if the user wants that we do not descend into directories. */
if (no_recurse_option)
- return;
+ goto finish_dir;
/* See if we are crossing from one file system to another, and
avoid doing so if the user only wants to dump one file system. */
&& parent_device != current_stat.st_dev)
{
if (verbose_option)
- WARN ((0, 0, _("%s: On a different filesystem; not dumped"), p));
- return;
+ WARN ((0, 0,
+ _("%s: file is on a different filesystem; not dumped"),
+ quotearg_colon (p)));
+ goto finish_dir;
}
/* Now output all the files in the directory. */
- errno = 0; /* FIXME: errno should be read-only */
-
- directory = opendir (p);
- if (!directory)
- {
- ERROR ((0, errno, _("Cannot open directory %s"), p));
- return;
- }
-
/* FIXME: Should speed this up by cd-ing into the dir. */
- while (entry = readdir (directory), entry)
+ while (errno = 0, (entry = readdir (directory)))
{
/* Skip `.', `..', and excluded file names. */
dump_file (namebuf, 0, our_device);
}
- closedir (directory);
+ if (errno)
+ {
+ if (ignore_failed_read_option)
+ readdir_warn (p);
+ else
+ readdir_error (p);
+ }
+
+ finish_dir:
+ if (closedir (directory) != 0)
+ {
+ if (ignore_failed_read_option)
+ closedir_warn (p);
+ else
+ closedir_error (p);
+ }
+
free (namebuf);
if (atime_preserve_option)
utime (p, &restore_times);
if (remove_files_option)
if (unlink (p) == -1)
- ERROR ((0, errno, _("Cannot remove %s"), p));
+ unlink_error (p);
/* We dumped it. */
return;
union block *start;
int header_moved;
char isextended = 0;
- int upperbound;
+ int sparses;
header_moved = 0;
< (current_stat.st_size / ST_NBLOCKSIZE
+ (current_stat.st_size % ST_NBLOCKSIZE != 0)))
{
- off_t filesize = current_stat.st_size;
int counter;
header = start_header (p, ¤t_stat);
header_moved = 1;
/* Call the routine that figures out the layout of the
- sparse file in question. UPPERBOUND is the index of the
- last element of the "sparsearray," i.e., the number of
- elements it needed to describe the file. */
+ sparse file in question. SPARSES is the index of the
+ first unused element of the "sparsearray," i.e.,
+ the number of elements it needed to describe the file. */
- upperbound = deal_with_sparse (p, header);
+ sparses = deal_with_sparse (p, header);
/* See if we'll need an extended header later. */
- if (upperbound > SPARSES_IN_OLDGNU_HEADER - 1)
+ if (SPARSES_IN_OLDGNU_HEADER < sparses)
header->oldgnu_header.isextended = 1;
/* We store the "real" file size so we can show that in
of the file minus the blocks of holes that we're
skipping over. */
- find_new_file_size (&filesize, upperbound);
- current_stat.st_size = filesize;
- OFF_TO_CHARS (filesize, header->header.size);
+ current_stat.st_size = find_new_file_size (sparses);
+ OFF_TO_CHARS (current_stat.st_size, header->header.size);
- for (counter = 0; counter < SPARSES_IN_OLDGNU_HEADER; counter++)
+ for (counter = 0;
+ counter < sparses && counter < SPARSES_IN_OLDGNU_HEADER;
+ counter++)
{
- if (!sparsearray[counter].numbytes)
- break;
-
OFF_TO_CHARS (sparsearray[counter].offset,
header->oldgnu_header.sp[counter].offset);
SIZE_TO_CHARS (sparsearray[counter].numbytes,
header->oldgnu_header.sp[counter].numbytes);
}
-
}
}
else
- upperbound = SPARSES_IN_OLDGNU_HEADER - 1;
+ sparses = SPARSES_IN_OLDGNU_HEADER;
sizeleft = current_stat.st_size;
f = open (p, O_RDONLY | O_BINARY);
if (f < 0)
{
- WARN ((0, errno, _("Cannot add file %s"), p));
- if (!ignore_failed_read_option)
- exit_status = TAREXIT_FAILURE;
+ if (! top_level && errno == ENOENT)
+ WARN ((0, 0, _("%s: File removed before we read it"),
+ quotearg_colon (p)));
+ else
+ (ignore_failed_read_option ? open_warn : open_error) (p);
return;
}
}
memset (exhdr->buffer, 0, BLOCKSIZE);
for (counter = 0; counter < SPARSES_IN_SPARSE_HEADER; counter++)
{
- if (counter + index_offset > upperbound)
+ if (sparses <= counter + index_offset)
break;
SIZE_TO_CHARS (sparsearray[counter + index_offset].numbytes,
exhdr->sparse_header.sp[counter].offset);
}
set_next_block_after (exhdr);
- if (index_offset + counter <= upperbound)
+ if (counter + index_offset < sparses)
{
index_offset += counter;
exhdr->sparse_header.isextended = 1;
if (save_typeflag == GNUTYPE_SPARSE)
{
if (f < 0
- || finish_sparse_file (f, &sizeleft, current_stat.st_size, p))
+ || finish_sparse_file (f, &sizeleft,
+ current_stat.st_size, p))
goto padit;
}
else
count = safe_read (f, start->buffer, bufsize);
if (count < 0)
{
- char buf[UINTMAX_STRSIZE_BOUND];
- ERROR ((0, errno,
- _("Read error at byte %s, reading %lu bytes, in file %s"),
- STRINGIFY_BIGINT (current_stat.st_size - sizeleft,
- buf),
- (unsigned long) bufsize, p));
+ (ignore_failed_read_option
+ ? read_warn_details
+ : read_error_details)
+ (p, current_stat.st_size - sizeleft, bufsize);
goto padit;
}
sizeleft -= count;
else
{
char buf[UINTMAX_STRSIZE_BOUND];
- ERROR ((0, 0,
- _("File %s shrunk by %s bytes, padding with zeros"),
- p, STRINGIFY_BIGINT (sizeleft, buf)));
+ WARN ((0, 0,
+ _("%s: File shrank by %s bytes; padding with zeros"),
+ quotearg_colon (p),
+ STRINGIFY_BIGINT (sizeleft, buf)));
+ if (! ignore_failed_read_option)
+ exit_status = TAREXIT_FAILURE;
goto padit; /* short read */
}
}
{
struct stat final_stat;
if (fstat (f, &final_stat) != 0)
- ERROR ((0, errno, "%s: fstat", p));
- else if (final_stat.st_mtime != restore_times.modtime
- || final_stat.st_size != restore_size)
- ERROR ((0, errno, _("%s: file changed as we read it"), p));
+ {
+ if (ignore_failed_read_option)
+ stat_warn (p);
+ else
+ stat_error (p);
+ }
+ else if (final_stat.st_ctime != original_ctime)
+ {
+ char const *qp = quotearg_colon (p);
+ WARN ((0, 0, _("%s: file changed as we read it"), qp));
+ if (! ignore_failed_read_option)
+ exit_status = TAREXIT_FAILURE;
+ }
if (close (f) != 0)
- ERROR ((0, errno, _("%s: close"), p));
+ {
+ if (ignore_failed_read_option)
+ close_warn (p);
+ else
+ close_error (p);
+ }
if (atime_preserve_option)
utime (p, &restore_times);
}
if (remove_files_option)
{
if (unlink (p) == -1)
- ERROR ((0, errno, _("Cannot remove %s"), p));
+ unlink_error (p);
}
return;
size = readlink (p, buffer, PATH_MAX + 1);
if (size < 0)
{
- WARN ((0, errno, _("Cannot add file %s"), p));
- if (!ignore_failed_read_option)
- exit_status = TAREXIT_FAILURE;
+ if (ignore_failed_read_option)
+ readlink_warn (p);
+ else
+ readlink_error (p);
return;
}
buffer[size] = '\0';
if (remove_files_option)
{
if (unlink (p) == -1)
- ERROR ((0, errno, _("Cannot remove %s"), p));
+ unlink_error (p);
}
return;
}
type = CHRTYPE;
else if (S_ISBLK (current_stat.st_mode))
type = BLKTYPE;
- else if (S_ISFIFO (current_stat.st_mode)
- || S_ISSOCK (current_stat.st_mode))
+ else if (S_ISFIFO (current_stat.st_mode))
type = FIFOTYPE;
-#ifdef S_ISDOOR
+ else if (S_ISSOCK (current_stat.st_mode))
+ {
+ WARN ((0, 0, _("%s: socket ignored"), quotearg_colon (p)));
+ return;
+ }
else if (S_ISDOOR (current_stat.st_mode))
{
- WARN ((0, 0, _("%s: door ignored"), p));
+ WARN ((0, 0, _("%s: door ignored"), quotearg_colon (p)));
return;
}
-#endif
else
goto unknown;
}
if (remove_files_option)
{
if (unlink (p) == -1)
- ERROR ((0, errno, _("Cannot remove %s"), p));
+ unlink_error (p);
}
return;
unknown:
- ERROR ((0, 0, _("%s: Unknown file type; file ignored"), p));
+ WARN ((0, 0, _("%s: Unknown file type; file ignored"),
+ quotearg_colon (p)));
+ if (! ignore_failed_read_option)
+ exit_status = TAREXIT_FAILURE;
}