From 2c06a80918019471876956eef4ef22f05c9e0571 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Mon, 23 Sep 2013 19:35:29 +0300 Subject: [PATCH] Changes for compatibility with Slackware installation scripts. * src/buffer.c (short_read): the "Record size" message is controlled by the WARN_RECORD_SIZE warning_option bit. * src/common.h (keep_directory_symlink_option): New global. (WARN_RECORD_SIZE): New constant. (WARN_VERBOSE_WARNINGS): Add WARN_RECORD_SIZE. * src/extract.c (extract_dir): If keep_directory_symlink_option is set, follow symlinks to directories. * src/suffix.c (compression_suffixes): Add support for txz suffix. * src/tar.c (KEEP_DIRECTORY_SYMLINK_OPTION): New constant. (options): New option --keep-directory-symlink. (parse_opt): Handle this option. * src/warning.c: Implement "record-size" warning control. * NEWS: Update. * doc/tar.texi: Document new features. --- NEWS | 19 ++++++++++++++++++- doc/tar.texi | 38 +++++++++++++++++++++++++++++--------- src/buffer.c | 10 +++++----- src/common.h | 9 ++++++--- src/extract.c | 21 ++++++++++++++++++++- src/suffix.c | 1 + src/tar.c | 8 ++++++++ src/warning.c | 4 +++- 8 files changed, 90 insertions(+), 20 deletions(-) diff --git a/NEWS b/NEWS index 3108798..90a9022 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -GNU tar NEWS - User visible changes. 2013-02-10 +GNU tar NEWS - User visible changes. 2013-09-23 Please send GNU tar bug reports to @@ -70,6 +70,23 @@ prevent from being expanded too early, for example: * New configure option --enable-gcc-warnings, intended for debugging. +* New warning control option --warning=[no-]record-size + +On extraction, this option controls whether to display actual record +size, if it differs from the default. + +* New command line option --keep-directory-symlink + +By default, if when trying to extract a directory from the archive, +tar discovers that the corresponding file name already exists and is a +symbolic link, it first unlinks the entry, and then extracts the directory. + +This option disables this behavior and instructs tar to follow +symlinks to directories when extracting from the archive. + +It is mainly intended to provide compatibility with the Slackware +installation scripts. + version 1.26 - Sergey Poznyakoff, 2011-03-12 diff --git a/doc/tar.texi b/doc/tar.texi index ddfa055..9fde5a0 100644 --- a/doc/tar.texi +++ b/doc/tar.texi @@ -2804,6 +2804,21 @@ Specifies that @command{tar} should ask the user for confirmation before performing potentially destructive options, such as overwriting files. @xref{interactive}. +@opsummary{--keep-directory-symlink} +@item --keep-directory-symlink + +This option changes the behavior of tar when it encounters a symlink +with the same name as the directory that it is about to extract. By +default, in this case tar would first remove the symlink and then +proceed extracting the directory. + +The @option{--keep-directory-symlink} option disables this behavior +and instructs tar to follow symlinks to directories when extracting +from the archive. + +It is mainly intended to provide compatibility with the Slackware +installation scripts. + @opsummary{keep-newer-files} @item --keep-newer-files @@ -4221,6 +4236,10 @@ tar (child): trying gzip This means that @command{tar} first tried to decompress @file{archive.Z} using @command{compress}, and, when that failed, switched to @command{gzip}. +@kwindex record-size +@cindex @samp{Record size = %lu blocks}, warning message +@item record-size +@samp{Record size = %lu blocks} @end table @subheading Keywords controlling incremental extraction: @@ -10706,15 +10725,16 @@ When reading an archive, @command{tar} can usually figure out the record size on itself. When this is the case, and a non-standard record size was used when the archive was created, @command{tar} will print a message about a non-standard blocking factor, and then operate -normally. On some tape devices, however, @command{tar} cannot figure -out the record size itself. On most of those, you can specify a -blocking factor (with @option{--blocking-factor}) larger than the -actual blocking factor, and then use the @option{--read-full-records} -(@option{-B}) option. (If you specify a blocking factor with -@option{--blocking-factor} and don't use the -@option{--read-full-records} option, then @command{tar} will not -attempt to figure out the recording size itself.) On some devices, -you must always specify the record size exactly with +normally@footnote{If this message is not needed, you can turn it off +using the @option{--warning=no-record-size} option.}. On some tape +devices, however, @command{tar} cannot figure out the record size +itself. On most of those, you can specify a blocking factor (with +@option{--blocking-factor}) larger than the actual blocking factor, +and then use the @option{--read-full-records} (@option{-B}) option. +(If you specify a blocking factor with @option{--blocking-factor} and +don't use the @option{--read-full-records} option, then @command{tar} +will not attempt to figure out the recording size itself.) On some +devices, you must always specify the record size exactly with @option{--blocking-factor} when reading, because @command{tar} cannot figure it out. In any case, use @option{--list} (@option{-t}) before doing any extractions to see whether @command{tar} is reading the archive diff --git a/src/buffer.c b/src/buffer.c index 97084ab..4b44eaf 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -884,16 +884,16 @@ short_read (size_t status) left = record_size - status; if (left && left % BLOCKSIZE == 0 - && verbose_option + && (warning_option & WARN_RECORD_SIZE) && record_start_block == 0 && status != 0 && archive_is_dev ()) { unsigned long rsize = status / BLOCKSIZE; WARN ((0, 0, - ngettext ("Record size = %lu block", - "Record size = %lu blocks", - rsize), - rsize)); + ngettext ("Record size = %lu block", + "Record size = %lu blocks", + rsize), + rsize)); } while (left % BLOCKSIZE != 0 diff --git a/src/common.h b/src/common.h index 723ad90..e65e647 100644 --- a/src/common.h +++ b/src/common.h @@ -190,6 +190,8 @@ enum old_files }; GLOBAL enum old_files old_files_option; +GLOBAL bool keep_directory_symlink_option; + /* Specified file name for incremental list. */ GLOBAL const char *listed_incremental_option; /* Incremental dump level */ @@ -872,11 +874,12 @@ void checkpoint_run (bool do_write); #define WARN_DECOMPRESS_PROGRAM 0x00080000 #define WARN_EXISTING_FILE 0x00100000 #define WARN_XATTR_WRITE 0x00200000 +#define WARN_RECORD_SIZE 0x00400000 -/* The warnings composing WARN_VERBOSE_WARNINGS are enabled by default - in verbose mode */ +/* These warnings are enabled by default in verbose mode: */ #define WARN_VERBOSE_WARNINGS (WARN_RENAME_DIRECTORY|WARN_NEW_DIRECTORY|\ - WARN_DECOMPRESS_PROGRAM|WARN_EXISTING_FILE) + WARN_DECOMPRESS_PROGRAM|WARN_EXISTING_FILE|\ + WARN_RECORD_SIZE) #define WARN_ALL (~WARN_VERBOSE_WARNINGS) void set_warning_option (const char *arg); diff --git a/src/extract.c b/src/extract.c index 3d8ba10..9b6b7f9 100644 --- a/src/extract.c +++ b/src/extract.c @@ -855,7 +855,21 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_links) } - +static bool +is_directory_link (const char *file_name) +{ + struct stat st; + int e = errno; + int res; + + res = (fstatat (chdir_fd, file_name, &st, AT_SYMLINK_NOFOLLOW) == 0 && + S_ISLNK (st.st_mode) && + fstatat (chdir_fd, file_name, &st, 0) == 0 && + S_ISDIR (st.st_mode)); + errno = e; + return res; +} + /* Extractor functions for various member types */ static int @@ -911,10 +925,15 @@ extract_dir (char *file_name, int typeflag) if (errno == EEXIST && (interdir_made + || keep_directory_symlink_option || old_files_option == DEFAULT_OLD_FILES || old_files_option == OVERWRITE_OLD_FILES)) { struct stat st; + + if (keep_directory_symlink_option && is_directory_link (file_name)) + return 0; + if (deref_stat (file_name, &st) == 0) { current_mode = st.st_mode; diff --git a/src/suffix.c b/src/suffix.c index d11e9ee..cf8056c 100644 --- a/src/suffix.c +++ b/src/suffix.c @@ -43,6 +43,7 @@ static struct compression_suffix compression_suffixes[] = { { S(tlz, LZMA) }, { S(lzo, LZOP) }, { S(xz, XZ) }, + { S(txz, XZ) }, /* Slackware */ #undef S #undef __CAT2__ }; diff --git a/src/tar.c b/src/tar.c index 6dc2ec5..6c327f7 100644 --- a/src/tar.c +++ b/src/tar.c @@ -286,6 +286,7 @@ enum IGNORE_COMMAND_ERROR_OPTION, IGNORE_FAILED_READ_OPTION, INDEX_FILE_OPTION, + KEEP_DIRECTORY_SYMLINK_OPTION, KEEP_NEWER_FILES_OPTION, LEVEL_OPTION, LZIP_OPTION, @@ -485,6 +486,9 @@ static struct argp_option options[] = { {"overwrite-dir", OVERWRITE_DIR_OPTION, 0, 0, N_("overwrite metadata of existing directories when extracting (default)"), GRID+1 }, + {"keep-directory-symlink", KEEP_DIRECTORY_SYMLINK_OPTION, 0, 0, + N_("preserve existing symlinks to directories when extracting"), + GRID+1 }, #undef GRID #define GRID 40 @@ -1767,6 +1771,10 @@ parse_opt (int key, char *arg, struct argp_state *state) ignore_failed_read_option = true; break; + case KEEP_DIRECTORY_SYMLINK_OPTION: + keep_directory_symlink_option = true; + break; + case KEEP_NEWER_FILES_OPTION: old_files_option = KEEP_NEWER_FILES; break; diff --git a/src/warning.c b/src/warning.c index 81805e1..d58a575 100644 --- a/src/warning.c +++ b/src/warning.c @@ -46,6 +46,7 @@ static char const *const warning_args[] = { "decompress-program", "existing-file", "xattr-write", + "record-size", NULL }; @@ -72,7 +73,8 @@ static int warning_types[] = { WARN_XDEV, WARN_DECOMPRESS_PROGRAM, WARN_EXISTING_FILE, - WARN_XATTR_WRITE + WARN_XATTR_WRITE, + WARN_RECORD_SIZE }; ARGMATCH_VERIFY (warning_args, warning_types); -- 2.43.0