mirror of
https://git.savannah.gnu.org/git/tar.git
synced 2026-09-20 15:14:14 +00:00
(<quotearg.h>): New include.
(start_header): Use `member names' to refer to archive member names, not `archive names'. Warn about `..' in member names. (finish_sparse_file, dump_file): Quote arbitrary strings in diagnostics. (finish_sparse_file, dump_file): Don't assume that gettext preserves errno. (dump_file): Don't use `access' to determine whether a directory is readable; this isn't reliable if tar is setuid. Use `opendir' instead. Check for readdir and closedir failures. Don't dump sockets as if they were fifos; just warn and skip.
This commit is contained in:
+84
-66
@@ -33,6 +33,8 @@ struct utimbuf
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <quotearg.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#ifndef MSDOS
|
#ifndef MSDOS
|
||||||
@@ -422,7 +424,7 @@ start_header (const char *name, struct stat *st)
|
|||||||
if (!warned_once)
|
if (!warned_once)
|
||||||
{
|
{
|
||||||
warned_once = 1;
|
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));
|
(int) prefix_len, name));
|
||||||
}
|
}
|
||||||
name += prefix_len;
|
name += prefix_len;
|
||||||
@@ -434,10 +436,19 @@ start_header (const char *name, struct stat *st)
|
|||||||
if (!warned_once)
|
if (!warned_once)
|
||||||
{
|
{
|
||||||
warned_once = 1;
|
warned_once = 1;
|
||||||
WARN ((0, 0, _("Removing leading `/' from archive names")));
|
WARN ((0, 0, _("Removing leading `/' from member names")));
|
||||||
}
|
}
|
||||||
name++;
|
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))
|
if (sizeof header->header.name <= strlen (name))
|
||||||
@@ -767,17 +778,18 @@ finish_sparse_file (int file, off_t *sizeleft, off_t fullsize, char *name)
|
|||||||
|
|
||||||
ERROR ((0, 0, _("Wrote %s of %s bytes to file %s"),
|
ERROR ((0, 0, _("Wrote %s of %s bytes to file %s"),
|
||||||
STRINGIFY_BIGINT (fullsize - *sizeleft, buf1),
|
STRINGIFY_BIGINT (fullsize - *sizeleft, buf1),
|
||||||
STRINGIFY_BIGINT (fullsize, buf2),
|
STRINGIFY_BIGINT (fullsize, buf2), quote (name)));
|
||||||
name));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lseek (file, sparsearray[sparse_index++].offset, SEEK_SET) < 0)
|
if (lseek (file, sparsearray[sparse_index++].offset, SEEK_SET) < 0)
|
||||||
{
|
{
|
||||||
char buf[UINTMAX_STRSIZE_BOUND];
|
char buf[UINTMAX_STRSIZE_BOUND];
|
||||||
ERROR ((0, errno, _("lseek error at byte %s in file %s"),
|
int e = errno;
|
||||||
STRINGIFY_BIGINT (sparsearray[sparse_index - 1].offset, buf),
|
ERROR ((0, e, _("lseek error at byte %s in file %s"),
|
||||||
name));
|
STRINGIFY_BIGINT (sparsearray[sparse_index - 1].offset,
|
||||||
|
buf),
|
||||||
|
quote (name)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -804,10 +816,11 @@ finish_sparse_file (int file, off_t *sizeleft, off_t fullsize, char *name)
|
|||||||
if (count < 0)
|
if (count < 0)
|
||||||
{
|
{
|
||||||
char buf[UINTMAX_STRSIZE_BOUND];
|
char buf[UINTMAX_STRSIZE_BOUND];
|
||||||
ERROR ((0, errno,
|
int e = errno;
|
||||||
|
ERROR ((0, e,
|
||||||
_("Read error at byte %s, reading %lu bytes, in file %s"),
|
_("Read error at byte %s, reading %lu bytes, in file %s"),
|
||||||
STRINGIFY_BIGINT (fullsize - *sizeleft, buf),
|
STRINGIFY_BIGINT (fullsize - *sizeleft, buf),
|
||||||
(unsigned long) bufsize, name));
|
(unsigned long) bufsize, quote (name)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
bufsize -= count;
|
bufsize -= count;
|
||||||
@@ -828,11 +841,11 @@ finish_sparse_file (int file, off_t *sizeleft, off_t fullsize, char *name)
|
|||||||
if (count < 0)
|
if (count < 0)
|
||||||
{
|
{
|
||||||
char buf[UINTMAX_STRSIZE_BOUND];
|
char buf[UINTMAX_STRSIZE_BOUND];
|
||||||
|
int e = errno;
|
||||||
ERROR ((0, errno,
|
ERROR ((0, e,
|
||||||
_("Read error at byte %s, reading %lu bytes, in file %s"),
|
_("Read error at byte %s, reading %lu bytes, in file %s"),
|
||||||
STRINGIFY_BIGINT (fullsize - *sizeleft, buf),
|
STRINGIFY_BIGINT (fullsize - *sizeleft, buf),
|
||||||
(unsigned long) bufsize, name));
|
(unsigned long) bufsize, quote (name)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#if 0
|
#if 0
|
||||||
@@ -843,8 +856,7 @@ finish_sparse_file (int file, off_t *sizeleft, off_t fullsize, char *name)
|
|||||||
if (count != bufsize)
|
if (count != bufsize)
|
||||||
{
|
{
|
||||||
ERROR ((0, 0,
|
ERROR ((0, 0,
|
||||||
_("File %s shrunk, padding with zeros"),
|
_("File %s shrunk, padding with zeros"), quote (name)));
|
||||||
name));
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
start = find_next_block ();
|
start = find_next_block ();
|
||||||
@@ -950,9 +962,10 @@ dump_file (char *p, int top_level, dev_t parent_device)
|
|||||||
|
|
||||||
if (deref_stat (dereference_option, p, ¤t_stat) != 0)
|
if (deref_stat (dereference_option, p, ¤t_stat) != 0)
|
||||||
{
|
{
|
||||||
WARN ((0, errno, _("Cannot add file %s"), p));
|
if (ignore_failed_read_option)
|
||||||
if (!ignore_failed_read_option)
|
stat_error (p);
|
||||||
exit_status = TAREXIT_FAILURE;
|
else
|
||||||
|
stat_warn (p);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -982,7 +995,7 @@ dump_file (char *p, int top_level, dev_t parent_device)
|
|||||||
&& (!after_date_option || current_stat.st_ctime < newer_ctime_option))
|
&& (!after_date_option || current_stat.st_ctime < newer_ctime_option))
|
||||||
{
|
{
|
||||||
if (0 < top_level)
|
if (0 < top_level)
|
||||||
WARN ((0, 0, _("%s: is unchanged; not dumped"), p));
|
WARN ((0, 0, _("%s is unchanged; not dumped"), quote (p)));
|
||||||
/* FIXME: recheck this return. */
|
/* FIXME: recheck this return. */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -992,7 +1005,7 @@ dump_file (char *p, int top_level, dev_t parent_device)
|
|||||||
|
|
||||||
if (ar_dev && current_stat.st_dev == ar_dev && current_stat.st_ino == ar_ino)
|
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 is the archive; not dumped"), quote (p)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -1006,18 +1019,15 @@ dump_file (char *p, int top_level, dev_t parent_device)
|
|||||||
size_t len;
|
size_t len;
|
||||||
dev_t our_device = current_stat.st_dev;
|
dev_t our_device = current_stat.st_dev;
|
||||||
|
|
||||||
/* If this tar program is installed suid root, like for Amanda, the
|
errno = 0;
|
||||||
access might look like denied, while it is not really.
|
|
||||||
|
|
||||||
FIXME: I have the feeling this test is done too early. Couldn't it
|
directory = opendir (p);
|
||||||
just be bundled in later actions? I guess that the proper support
|
if (! directory)
|
||||||
of --ignore-failed-read is the key of the current writing. */
|
|
||||||
|
|
||||||
if (access (p, R_OK) == -1 && geteuid () != 0)
|
|
||||||
{
|
{
|
||||||
WARN ((0, errno, _("Cannot add directory %s"), p));
|
if (ignore_failed_read_option)
|
||||||
if (!ignore_failed_read_option)
|
opendir_warn (p);
|
||||||
exit_status = TAREXIT_FAILURE;
|
else
|
||||||
|
opendir_error (p);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1134,24 +1144,16 @@ dump_file (char *p, int top_level, dev_t parent_device)
|
|||||||
&& parent_device != current_stat.st_dev)
|
&& parent_device != current_stat.st_dev)
|
||||||
{
|
{
|
||||||
if (verbose_option)
|
if (verbose_option)
|
||||||
WARN ((0, 0, _("%s: On a different filesystem; not dumped"), p));
|
WARN ((0, 0, _("%s is on a different filesystem; not dumped"),
|
||||||
|
quote (p)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now output all the files in the directory. */
|
/* Now output all the files in the directory. */
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
|
|
||||||
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. */
|
/* 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. */
|
/* Skip `.', `..', and excluded file names. */
|
||||||
|
|
||||||
@@ -1168,7 +1170,16 @@ dump_file (char *p, int top_level, dev_t parent_device)
|
|||||||
dump_file (namebuf, 0, our_device);
|
dump_file (namebuf, 0, our_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir (directory);
|
if (errno)
|
||||||
|
{
|
||||||
|
if (ignore_failed_read_option)
|
||||||
|
readdir_warn (p);
|
||||||
|
else
|
||||||
|
readdir_error (p);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closedir (directory) != 0)
|
||||||
|
closedir_error (p);
|
||||||
free (namebuf);
|
free (namebuf);
|
||||||
if (atime_preserve_option)
|
if (atime_preserve_option)
|
||||||
utime (p, &restore_times);
|
utime (p, &restore_times);
|
||||||
@@ -1229,7 +1240,7 @@ dump_file (char *p, int top_level, dev_t parent_device)
|
|||||||
|
|
||||||
if (remove_files_option)
|
if (remove_files_option)
|
||||||
if (unlink (p) == -1)
|
if (unlink (p) == -1)
|
||||||
ERROR ((0, errno, _("Cannot remove %s"), p));
|
unlink_error (p);
|
||||||
|
|
||||||
/* We dumped it. */
|
/* We dumped it. */
|
||||||
return;
|
return;
|
||||||
@@ -1364,11 +1375,12 @@ dump_file (char *p, int top_level, dev_t parent_device)
|
|||||||
if (f < 0)
|
if (f < 0)
|
||||||
{
|
{
|
||||||
if (! top_level && errno == ENOENT)
|
if (! top_level && errno == ENOENT)
|
||||||
WARN ((0, 0, _("%s: file removed before we read it"), p));
|
WARN ((0, 0, _("File %s removed before we read it"),
|
||||||
|
quote (p)));
|
||||||
|
else if (ignore_failed_read_option)
|
||||||
|
open_warn (p);
|
||||||
else
|
else
|
||||||
WARN ((0, errno, _("Cannot add file %s"), p));
|
open_error (p);
|
||||||
if (!ignore_failed_read_option)
|
|
||||||
exit_status = TAREXIT_FAILURE;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1416,7 +1428,8 @@ dump_file (char *p, int top_level, dev_t parent_device)
|
|||||||
if (save_typeflag == GNUTYPE_SPARSE)
|
if (save_typeflag == GNUTYPE_SPARSE)
|
||||||
{
|
{
|
||||||
if (f < 0
|
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;
|
goto padit;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1448,11 +1461,12 @@ dump_file (char *p, int top_level, dev_t parent_device)
|
|||||||
if (count < 0)
|
if (count < 0)
|
||||||
{
|
{
|
||||||
char buf[UINTMAX_STRSIZE_BOUND];
|
char buf[UINTMAX_STRSIZE_BOUND];
|
||||||
ERROR ((0, errno,
|
int e = errno;
|
||||||
|
ERROR ((0, e,
|
||||||
_("Read error at byte %s, reading %lu bytes, in file %s"),
|
_("Read error at byte %s, reading %lu bytes, in file %s"),
|
||||||
STRINGIFY_BIGINT (current_stat.st_size - sizeleft,
|
STRINGIFY_BIGINT (current_stat.st_size - sizeleft,
|
||||||
buf),
|
buf),
|
||||||
(unsigned long) bufsize, p));
|
(unsigned long) bufsize, quote (p)));
|
||||||
goto padit;
|
goto padit;
|
||||||
}
|
}
|
||||||
sizeleft -= count;
|
sizeleft -= count;
|
||||||
@@ -1468,7 +1482,7 @@ dump_file (char *p, int top_level, dev_t parent_device)
|
|||||||
char buf[UINTMAX_STRSIZE_BOUND];
|
char buf[UINTMAX_STRSIZE_BOUND];
|
||||||
ERROR ((0, 0,
|
ERROR ((0, 0,
|
||||||
_("File %s shrunk by %s bytes, padding with zeros"),
|
_("File %s shrunk by %s bytes, padding with zeros"),
|
||||||
p, STRINGIFY_BIGINT (sizeleft, buf)));
|
quote (p), STRINGIFY_BIGINT (sizeleft, buf)));
|
||||||
goto padit; /* short read */
|
goto padit; /* short read */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1480,18 +1494,18 @@ dump_file (char *p, int top_level, dev_t parent_device)
|
|||||||
{
|
{
|
||||||
struct stat final_stat;
|
struct stat final_stat;
|
||||||
if (fstat (f, &final_stat) != 0)
|
if (fstat (f, &final_stat) != 0)
|
||||||
ERROR ((0, errno, "%s: fstat", p));
|
stat_error (p);
|
||||||
else if (final_stat.st_ctime != original_ctime)
|
else if (final_stat.st_ctime != original_ctime)
|
||||||
ERROR ((0, 0, _("%s: file changed as we read it"), p));
|
ERROR ((0, 0, _("File %s changed as we read it"), quote (p)));
|
||||||
if (close (f) != 0)
|
if (close (f) != 0)
|
||||||
ERROR ((0, errno, _("%s: close"), p));
|
close_error (p);
|
||||||
if (atime_preserve_option)
|
if (atime_preserve_option)
|
||||||
utime (p, &restore_times);
|
utime (p, &restore_times);
|
||||||
}
|
}
|
||||||
if (remove_files_option)
|
if (remove_files_option)
|
||||||
{
|
{
|
||||||
if (unlink (p) == -1)
|
if (unlink (p) == -1)
|
||||||
ERROR ((0, errno, _("Cannot remove %s"), p));
|
unlink_error (p);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -1526,9 +1540,10 @@ dump_file (char *p, int top_level, dev_t parent_device)
|
|||||||
size = readlink (p, buffer, PATH_MAX + 1);
|
size = readlink (p, buffer, PATH_MAX + 1);
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
{
|
{
|
||||||
WARN ((0, errno, _("Cannot add file %s"), p));
|
if (ignore_failed_read_option)
|
||||||
if (!ignore_failed_read_option)
|
readlink_warn (p);
|
||||||
exit_status = TAREXIT_FAILURE;
|
else
|
||||||
|
readlink_error (p);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
buffer[size] = '\0';
|
buffer[size] = '\0';
|
||||||
@@ -1545,7 +1560,7 @@ dump_file (char *p, int top_level, dev_t parent_device)
|
|||||||
if (remove_files_option)
|
if (remove_files_option)
|
||||||
{
|
{
|
||||||
if (unlink (p) == -1)
|
if (unlink (p) == -1)
|
||||||
ERROR ((0, errno, _("Cannot remove %s"), p));
|
unlink_error (p);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1554,16 +1569,18 @@ dump_file (char *p, int top_level, dev_t parent_device)
|
|||||||
type = CHRTYPE;
|
type = CHRTYPE;
|
||||||
else if (S_ISBLK (current_stat.st_mode))
|
else if (S_ISBLK (current_stat.st_mode))
|
||||||
type = BLKTYPE;
|
type = BLKTYPE;
|
||||||
else if (S_ISFIFO (current_stat.st_mode)
|
else if (S_ISFIFO (current_stat.st_mode))
|
||||||
|| S_ISSOCK (current_stat.st_mode))
|
|
||||||
type = FIFOTYPE;
|
type = FIFOTYPE;
|
||||||
#ifdef S_ISDOOR
|
else if (S_ISSOCK (current_stat.st_mode))
|
||||||
else if (S_ISDOOR (current_stat.st_mode))
|
|
||||||
{
|
{
|
||||||
WARN ((0, 0, _("%s: door ignored"), p));
|
WARN ((0, 0, _("%s: socket ignored"), quotearg_colon (p)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (S_ISDOOR (current_stat.st_mode))
|
||||||
|
{
|
||||||
|
WARN ((0, 0, _("%s: door ignored"), quotearg_colon (p)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
else
|
else
|
||||||
goto unknown;
|
goto unknown;
|
||||||
}
|
}
|
||||||
@@ -1585,10 +1602,11 @@ dump_file (char *p, int top_level, dev_t parent_device)
|
|||||||
if (remove_files_option)
|
if (remove_files_option)
|
||||||
{
|
{
|
||||||
if (unlink (p) == -1)
|
if (unlink (p) == -1)
|
||||||
ERROR ((0, errno, _("Cannot remove %s"), p));
|
unlink_error (p);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
unknown:
|
unknown:
|
||||||
ERROR ((0, 0, _("%s: Unknown file type; file ignored"), p));
|
ERROR ((0, 0, _("%s: Unknown file type; file ignored"),
|
||||||
|
quotearg_colon (p)));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user