this matches historical practice.
(unlink_destination): New function, which checks for unlink failures. (maybe_recoverable): Stay quiet if -U. (extract_archive): Use O_EXCL if unlink_first_option. Report unlink failures. Use HAVE_SYMLINK, not S_ISLNK, to determine whether symlink exists. Use HAVE_MKFIFO || defined mkfifo, not S_ISFIFO, to determine whether mkfifo exists.
This commit is contained in:
@@ -91,18 +91,21 @@ extr_init (void)
|
||||
static void
|
||||
set_mode (char *file_name, struct stat *stat_info)
|
||||
{
|
||||
/* We ought to force permission when -k is not selected, because if the
|
||||
/* Do nothing unless we are restoring the original permissions.
|
||||
|
||||
We must force permission when -k and -U are not selected, because if the
|
||||
file already existed, open or creat would save the permission bits from
|
||||
the previously created file, ignoring the ones we specified.
|
||||
|
||||
But with -k selected, we know *we* created this file, so the mode
|
||||
But with -k or -U selected, we know *we* created this file, so the mode
|
||||
bits were set by our open. If the file has abnormal mode bits, we must
|
||||
chmod since writing or chown has probably reset them. If the file is
|
||||
normal, we merely skip the chmod. This works because we did umask (0)
|
||||
when -p, so umask will have left the specified mode alone. */
|
||||
|
||||
if (!keep_old_files_option
|
||||
|| (stat_info->st_mode & (S_ISUID | S_ISGID | S_ISVTX)))
|
||||
if ((we_are_root || same_permissions_option)
|
||||
&& ((!keep_old_files_option && !unlink_first_option)
|
||||
|| (stat_info->st_mode & (S_ISUID | S_ISGID | S_ISVTX))))
|
||||
if (chmod (file_name, ~current_umask & stat_info->st_mode) < 0)
|
||||
ERROR ((0, errno, _("%s: Cannot change mode to %04lo"),
|
||||
file_name,
|
||||
@@ -281,6 +284,25 @@ make_directories (char *file_name)
|
||||
return did_something; /* tell them to retry if we made one */
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------.
|
||||
| Unlink the destination, if we are supposed to do so. |
|
||||
| Return zero if extraction should not proceed. |
|
||||
`--------------------------------------------------------------------*/
|
||||
|
||||
static int
|
||||
unlink_destination (char const *file_name)
|
||||
{
|
||||
if (unlink_first_option
|
||||
&& !remove_any_file (file_name, recursive_unlink_option)
|
||||
&& errno != ENOENT)
|
||||
{
|
||||
ERROR ((0, errno, _("Cannot remove %s"), file_name));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------.
|
||||
| Attempt repairing what went wrong with the extraction. Delete an |
|
||||
| already existing file or create missing intermediate directories. |
|
||||
@@ -294,10 +316,10 @@ maybe_recoverable (char *file_name)
|
||||
switch (errno)
|
||||
{
|
||||
case EEXIST:
|
||||
/* Attempt deleting an existing file. However, with -k, just stay
|
||||
/* Attempt deleting an existing file. However, with -k or -U, just stay
|
||||
quiet. */
|
||||
|
||||
if (keep_old_files_option)
|
||||
if (keep_old_files_option || unlink_first_option)
|
||||
return 0;
|
||||
|
||||
return remove_any_file (file_name, 0);
|
||||
@@ -541,7 +563,7 @@ Removing leading `/' from absolute path names in the archive")));
|
||||
/* FIXME: deal with protection issues. */
|
||||
|
||||
again_file:
|
||||
openflag = (keep_old_files_option ?
|
||||
openflag = (keep_old_files_option || unlink_first_option ?
|
||||
O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_EXCL :
|
||||
O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_TRUNC)
|
||||
| ((typeflag == GNUTYPE_SPARSE) ? 0 : O_APPEND);
|
||||
@@ -561,8 +583,15 @@ Removing leading `/' from absolute path names in the archive")));
|
||||
goto extract_file;
|
||||
}
|
||||
|
||||
if (unlink_first_option)
|
||||
remove_any_file (CURRENT_FILE_NAME, recursive_unlink_option);
|
||||
if (!unlink_destination (CURRENT_FILE_NAME))
|
||||
{
|
||||
if (current_header->oldgnu_header.isextended)
|
||||
skip_extended_headers ();
|
||||
skip_file (current_stat.st_size);
|
||||
if (backup_option)
|
||||
undo_last_backup ();
|
||||
break;
|
||||
}
|
||||
|
||||
#if O_CTG
|
||||
/* Contiguous files (on the Masscomp) have to specify the size in
|
||||
@@ -696,9 +725,9 @@ Removing leading `/' from absolute path names in the archive")));
|
||||
if (to_stdout_option)
|
||||
break;
|
||||
|
||||
#ifdef S_ISLNK
|
||||
if (unlink_first_option)
|
||||
remove_any_file (CURRENT_FILE_NAME, recursive_unlink_option);
|
||||
#ifdef HAVE_SYMLINK
|
||||
if (!unlink_destination (CURRENT_FILE_NAME))
|
||||
break;
|
||||
|
||||
while (status = symlink (current_link_name, CURRENT_FILE_NAME),
|
||||
status != 0)
|
||||
@@ -723,7 +752,7 @@ Removing leading `/' from absolute path names in the archive")));
|
||||
}
|
||||
break;
|
||||
|
||||
#else /* not S_ISLNK */
|
||||
#else
|
||||
{
|
||||
static int warned_once = 0;
|
||||
|
||||
@@ -736,14 +765,14 @@ Attempting extraction of symbolic links as hard links")));
|
||||
}
|
||||
/* Fall through. */
|
||||
|
||||
#endif /* not S_ISLNK */
|
||||
#endif
|
||||
|
||||
case LNKTYPE:
|
||||
if (to_stdout_option)
|
||||
break;
|
||||
|
||||
if (unlink_first_option)
|
||||
remove_any_file (CURRENT_FILE_NAME, recursive_unlink_option);
|
||||
if (!unlink_destination (CURRENT_FILE_NAME))
|
||||
break;
|
||||
|
||||
again_link:
|
||||
{
|
||||
@@ -789,8 +818,8 @@ Attempting extraction of symbolic links as hard links")));
|
||||
if (to_stdout_option)
|
||||
break;
|
||||
|
||||
if (unlink_first_option)
|
||||
remove_any_file (CURRENT_FILE_NAME, recursive_unlink_option);
|
||||
if (!unlink_destination (CURRENT_FILE_NAME))
|
||||
break;
|
||||
|
||||
status = mknod (CURRENT_FILE_NAME, current_stat.st_mode,
|
||||
current_stat.st_rdev);
|
||||
@@ -808,13 +837,13 @@ Attempting extraction of symbolic links as hard links")));
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef S_ISFIFO
|
||||
#if HAVE_MKFIFO || defined mkfifo
|
||||
case FIFOTYPE:
|
||||
if (to_stdout_option)
|
||||
break;
|
||||
|
||||
if (unlink_first_option)
|
||||
remove_any_file (CURRENT_FILE_NAME, recursive_unlink_option);
|
||||
if (!unlink_destination (CURRENT_FILE_NAME))
|
||||
break;
|
||||
|
||||
while (status = mkfifo (CURRENT_FILE_NAME, current_stat.st_mode),
|
||||
status != 0)
|
||||
|
||||
Reference in New Issue
Block a user