tar: restore replace-hardlinks option

This commit is contained in:
Sergei Reznikov
2020-12-03 15:02:07 +03:00
parent d6d4776f2e
commit 9665e4c01f
2 changed files with 123 additions and 2 deletions

View File

@@ -0,0 +1,120 @@
From 25395e3fa0b01a898b6e6ae456c8eef3c66849f1 Mon Sep 17 00:00:00 2001
From: Jonathan Schleifer <js@webkeks.org>
Date: Thu, 20 Mar 2014 14:52:58 +0100
Subject: Implement replace-hardlinks option
diff --git a/src/common.h b/src/common.h
index 501e0d3..60e1ff4 100644
--- a/src/common.h
+++ b/src/common.h
@@ -197,6 +197,8 @@ GLOBAL enum old_files old_files_option;
GLOBAL bool keep_directory_symlink_option;
+GLOBAL bool simulate_hardlinks_option;
+
/* Specified file name for incremental list. */
GLOBAL const char *listed_incremental_option;
/* Incremental dump level */
diff --git a/src/extract.c b/src/extract.c
index 8276f8f..da0962d 100644
--- a/src/extract.c
+++ b/src/extract.c
@@ -32,6 +32,8 @@ static bool we_are_root; /* true if our effective uid == 0 */
static mode_t newdir_umask; /* umask when creating new directories */
static mode_t current_umask; /* current umask (which is set to 0 if -p) */
+static int extract_symlink (char *, int);
+
#define ALL_MODE_BITS ((mode_t) ~ (mode_t) 0)
#if ! HAVE_FCHMOD && ! defined fchmod
@@ -1336,6 +1338,38 @@ extract_link (char *file_name, int typeflag)
char const *link_name;
int rc;
+ if (simulate_hardlinks_option)
+ {
+ /* symlinks have to be normalized */
+ const char* f = file_name;
+ const char* l = current_stat_info.link_name;
+ int sep_pos = 0;
+ int p_count = 0;
+ char *link_name = (char*) xmalloc(strlen(current_stat_info.link_name) * 2);
+
+ for (; *f && *l; f++, l++)
+ {
+ if (*f != *l)
+ break;
+ if (*f == DIRECTORY_SEPARATOR)
+ sep_pos = f - file_name;
+ }
+
+ for (p_count = 0; *f; f++)
+ if (*f == DIRECTORY_SEPARATOR)
+ p_count++;
+
+ link_name[0] = '\0';
+ while (p_count--)
+ strcat(link_name, "../");
+
+ strcat(link_name, &current_stat_info.link_name[sep_pos + 1]);
+ free(current_stat_info.link_name);
+ current_stat_info.link_name = link_name;
+
+ return extract_symlink(file_name, typeflag);
+ }
+
link_name = current_stat_info.link_name;
if (! absolute_names_option && contains_dot_dot (link_name))
@@ -1425,6 +1459,13 @@ extract_symlink (char *file_name, int typeflag)
#else
static int warned_once;
+ /* recursion is not welcomed here */
+ if (simulate_hardlinks_option && typeflag == LINKTYPE)
+ {
+ link_error (current_stat_info.link_name, file_name);
+ return -1;
+ }
+
if (!warned_once)
{
warned_once = 1;
diff --git a/src/tar.c b/src/tar.c
index d66fed8..23027d2 100644
--- a/src/tar.c
+++ b/src/tar.c
@@ -449,6 +449,8 @@ static struct argp_option options[] = {
{"check-device", CHECK_DEVICE_OPTION, NULL, 0,
N_("check device numbers when creating incremental archives (default)"),
GRID+1 },
+ {"replace-hardlinks", 'Q', 0, 0,
+ N_("replace hardlinks with corresponding symlink when extracting"), GRID+1 },
#undef GRID
#define GRID 30
@@ -1728,6 +1730,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
set_archive_format (arg);
break;
+ case 'Q':
+ simulate_hardlinks_option = true;
+ break;
+
case INDEX_FILE_OPTION:
index_file_name = arg;
break;
@@ -2245,6 +2251,7 @@ decode_options (int argc, char **argv)
unquote_option = true;
tar_sparse_major = 1;
tar_sparse_minor = 0;
+ simulate_hardlinks_option = false;
savedir_sort_order = SAVEDIR_SORT_NONE;
--
2.28.0

View File

@@ -12,12 +12,13 @@ archives)."
HOMEPAGE="https://www.gnu.org/software/tar/"
COPYRIGHT="1990-2018 Free Software Foundation, Inc."
LICENSE="GNU GPL v3"
REVISION="1"
REVISION="2"
SOURCE_URI="https://ftpmirror.gnu.org/tar/tar-$portVersion.tar.bz2
https://ftp.gnu.org/gnu/tar/tar-$portVersion.tar.bz2"
CHECKSUM_SHA256="e4bb9e08e12e7fa9f11fef544efc85e59ba34538593d9ad38148c7ca2bfbb566"
PATCHES="tar-$portVersion.patchset"
if [ "$effectiveTargetArchitecture" = x86_gcc2 ]; then
PATCHES="tar-$portVersion-gcc2.patchset"
PATCHES+="tar-$portVersion-gcc2.patchset"
fi
ARCHITECTURES="x86_gcc2 x86 x86_64 arm"