Fix the logic of prepare_to_extract.

* src/extract.c (prepare_to_extract): Return true to proceed with
the extraction, and false to skip the current member.  If extracting
over a pipe, skip unlinking logic.
(extract_archive): Update accordingly.
This commit is contained in:
Sergey Poznyakoff
2020-06-22 22:17:46 +03:00
parent 63712973c7
commit 34d15af170

View File

@@ -1621,47 +1621,23 @@ extract_fifo (char *file_name, int typeflag)
} }
#endif #endif
static int
extract_volhdr (char *file_name, int typeflag)
{
skip_member ();
return 0;
}
static int
extract_failure (char *file_name, int typeflag)
{
return 1;
}
static int
extract_skip (char *file_name, int typeflag)
{
skip_member ();
return 0;
}
typedef int (*tar_extractor_t) (char *file_name, int typeflag); typedef int (*tar_extractor_t) (char *file_name, int typeflag);
/* Prepare to extract a file. Find extractor function. /* Prepare to extract a file. Find extractor function.
Return zero if extraction should not proceed. */ Return true to proceed with the extraction, false to skip the current
member. */
static int static bool
prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun) prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun)
{ {
int rc = 1; tar_extractor_t extractor = NULL;
if (EXTRACT_OVER_PIPE)
rc = 0;
/* Select the extractor */ /* Select the extractor */
switch (typeflag) switch (typeflag)
{ {
case GNUTYPE_SPARSE: case GNUTYPE_SPARSE:
*fun = extract_file; extractor = extract_file;
rc = 1;
break; break;
case AREGTYPE: case AREGTYPE:
@@ -1670,106 +1646,101 @@ prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun)
/* Appears to be a file. But BSD tar uses the convention that a slash /* Appears to be a file. But BSD tar uses the convention that a slash
suffix means a directory. */ suffix means a directory. */
if (current_stat_info.had_trailing_slash) if (current_stat_info.had_trailing_slash)
*fun = extract_dir; extractor = extract_dir;
else else
{ extractor = extract_file;
*fun = extract_file;
rc = 1;
}
break; break;
case SYMTYPE: case SYMTYPE:
*fun = extract_symlink; extractor = extract_symlink;
break; break;
case LNKTYPE: case LNKTYPE:
*fun = extract_link; extractor = extract_link;
break; break;
#if S_IFCHR #if S_IFCHR
case CHRTYPE: case CHRTYPE:
current_stat_info.stat.st_mode |= S_IFCHR; current_stat_info.stat.st_mode |= S_IFCHR;
*fun = extract_node; extractor = extract_node;
break; break;
#endif #endif
#if S_IFBLK #if S_IFBLK
case BLKTYPE: case BLKTYPE:
current_stat_info.stat.st_mode |= S_IFBLK; current_stat_info.stat.st_mode |= S_IFBLK;
*fun = extract_node; extractor = extract_node;
break; break;
#endif #endif
#if HAVE_MKFIFO || defined mkfifo #if HAVE_MKFIFO || defined mkfifo
case FIFOTYPE: case FIFOTYPE:
*fun = extract_fifo; extractor = extract_fifo;
break; break;
#endif #endif
case DIRTYPE: case DIRTYPE:
case GNUTYPE_DUMPDIR: case GNUTYPE_DUMPDIR:
*fun = extract_dir; extractor = extract_dir;
if (current_stat_info.is_dumpdir) if (current_stat_info.is_dumpdir)
delay_directory_restore_option = true; delay_directory_restore_option = true;
break; break;
case GNUTYPE_VOLHDR: case GNUTYPE_VOLHDR:
*fun = extract_volhdr; return false;
break;
case GNUTYPE_MULTIVOL: case GNUTYPE_MULTIVOL:
ERROR ((0, 0, ERROR ((0, 0,
_("%s: Cannot extract -- file is continued from another volume"), _("%s: Cannot extract -- file is continued from another volume"),
quotearg_colon (current_stat_info.file_name))); quotearg_colon (current_stat_info.file_name)));
*fun = extract_skip; return false;
break;
case GNUTYPE_LONGNAME: case GNUTYPE_LONGNAME:
case GNUTYPE_LONGLINK: case GNUTYPE_LONGLINK:
ERROR ((0, 0, _("Unexpected long name header"))); ERROR ((0, 0, _("Unexpected long name header")));
*fun = extract_failure; return false;
break;
default: default:
WARNOPT (WARN_UNKNOWN_CAST, WARNOPT (WARN_UNKNOWN_CAST,
(0, 0, (0, 0,
_("%s: Unknown file type '%c', extracted as normal file"), _("%s: Unknown file type '%c', extracted as normal file"),
quotearg_colon (file_name), typeflag)); quotearg_colon (file_name), typeflag));
*fun = extract_file; extractor = extract_file;
} }
/* Determine whether the extraction should proceed */ if (!EXTRACT_OVER_PIPE)
if (rc == 0)
return 0;
switch (old_files_option)
{ {
case UNLINK_FIRST_OLD_FILES: switch (old_files_option)
if (!remove_any_file (file_name,
recursive_unlink_option ? RECURSIVE_REMOVE_OPTION
: ORDINARY_REMOVE_OPTION)
&& errno && errno != ENOENT)
{ {
unlink_error (file_name); case UNLINK_FIRST_OLD_FILES:
return 0; if (!remove_any_file (file_name,
} recursive_unlink_option
break; ? RECURSIVE_REMOVE_OPTION
: ORDINARY_REMOVE_OPTION)
&& errno && errno != ENOENT)
{
unlink_error (file_name);
return false;
}
break;
case KEEP_NEWER_FILES: case KEEP_NEWER_FILES:
if (file_newer_p (file_name, 0, &current_stat_info)) if (file_newer_p (file_name, 0, &current_stat_info))
{ {
WARNOPT (WARN_IGNORE_NEWER, WARNOPT (WARN_IGNORE_NEWER,
(0, 0, _("Current %s is newer or same age"), (0, 0, _("Current %s is newer or same age"),
quote (file_name))); quote (file_name)));
return 0; return false;
} }
break; break;
default: default:
break; break;
}
} }
*fun = extractor;
return 1;
return true;
} }
/* Extract a file from the archive. */ /* Extract a file from the archive. */
@@ -1832,13 +1803,14 @@ extract_archive (void)
if (prepare_to_extract (current_stat_info.file_name, typeflag, &fun)) if (prepare_to_extract (current_stat_info.file_name, typeflag, &fun))
{ {
if (fun && (*fun) (current_stat_info.file_name, typeflag) if (fun (current_stat_info.file_name, typeflag) == 0)
&& backup_option) return;
undo_last_backup ();
} }
else else
skip_member (); skip_member ();
if (backup_option)
undo_last_backup ();
} }
/* Extract the links whose final extraction were delayed. */ /* Extract the links whose final extraction were delayed. */