diff --git a/SOURCES/tar-1.14-loneZeroWarning.patch b/SOURCES/tar-1.14-loneZeroWarning.patch new file mode 100644 index 00000000..1bb86abb --- /dev/null +++ b/SOURCES/tar-1.14-loneZeroWarning.patch @@ -0,0 +1,29 @@ +diff --git a/src/list.c b/src/list.c +index cf2de09..f4e6e0a 100644 +--- a/src/list.c ++++ b/src/list.c +@@ -212,6 +212,14 @@ read_and (void (*do_something) (void)) + + if (!ignore_zeros_option) + { ++ /* ++ * According to POSIX tar specs, this is wrong, but on the web ++ * there are some tar specs that can trigger this, and some tar ++ * implementations create tars according to that spec. For now, ++ * let's not be pedantic about issuing the warning. ++ */ ++#if 0 ++ + char buf[UINTMAX_STRSIZE_BOUND]; + + status = read_header (¤t_header, ¤t_stat_info, +@@ -221,6 +229,9 @@ read_and (void (*do_something) (void)) + WARNOPT (WARN_ALONE_ZERO_BLOCK, + (0, 0, _("A lone zero block at %s"), + STRINGIFY_BIGINT (current_block_ordinal (), buf))); ++#endif ++ status = read_header (¤t_header, ¤t_stat_info, ++ read_header_auto); + break; + } + status = prev_status; diff --git a/SOURCES/tar-1.15.1-vfatTruncate.patch b/SOURCES/tar-1.15.1-vfatTruncate.patch new file mode 100644 index 00000000..0fa3f199 --- /dev/null +++ b/SOURCES/tar-1.15.1-vfatTruncate.patch @@ -0,0 +1,31 @@ +diff --git a/src/system.c b/src/system.c +index ba4ac2d..ea88cd6 100644 +--- a/src/system.c ++++ b/src/system.c +@@ -231,8 +231,25 @@ sys_compare_links (struct stat *link_data, struct stat *stat_data) + int + sys_truncate (int fd) + { ++ struct stat st; + off_t pos = lseek (fd, (off_t) 0, SEEK_CUR); +- return pos < 0 ? -1 : ftruncate (fd, pos); ++ ++ if ( pos < 0) ++ return -1; ++ ++ if ( ftruncate(fd, pos) && errno == EPERM ) { ++ /* wrapper around ftruncate: ++ * ftruncate may fail to grow the size of a file with some OS and filesystem ++ * combinations. Linux and vfat/fat is one example. If this is the case do ++ * a write to grow the file to the desired length. ++ */ ++ if( (fstat( fd, &st ) == -1) || ++ (st.st_size >= pos) || ++ (lseek( fd, pos - 1, SEEK_SET) == (off_t)-1) || ++ (write( fd, "\0", 1) == -1) ) ++ return -1; ++ } ++ return 0; + } + + /* Return nonzero if NAME is the name of a regular file, or if the file diff --git a/SOURCES/tar-1.17-wildcards.patch b/SOURCES/tar-1.17-wildcards.patch new file mode 100644 index 00000000..eee34de8 --- /dev/null +++ b/SOURCES/tar-1.17-wildcards.patch @@ -0,0 +1,92 @@ +diff --git a/doc/tar.texi b/doc/tar.texi +index db8f986..d70d113 100644 +--- a/doc/tar.texi ++++ b/doc/tar.texi +@@ -7597,7 +7597,7 @@ The following table summarizes pattern-matching default values: + + @multitable @columnfractions .3 .7 + @headitem Members @tab Default settings +-@item Inclusion @tab @option{--no-wildcards --anchored --no-wildcards-match-slash} ++@item Inclusion @tab @option{--wildcards --anchored --wildcards-match-slash} + @item Exclusion @tab @option{--wildcards --no-anchored --wildcards-match-slash} + @end multitable + +@@ -12038,6 +12038,9 @@ version of this document is available at + @table @asis + @item Use of globbing patterns when listing and extracting. + ++Note: Following is true for original unpatched GNU tar. ++For compatibility reasons, the old behavior was preserved. ++ + Previous versions of GNU tar assumed shell-style globbing when + extracting from or listing an archive. For example: + +diff --git a/src/names.c b/src/names.c +index ba4d509..3911f8c 100644 +--- a/src/names.c ++++ b/src/names.c +@@ -966,10 +966,7 @@ collect_and_sort_names (void) + + if (name->found_count || name->directory) + continue; +- if (name->matching_flags & EXCLUDE_WILDCARDS) +- /* NOTE: EXCLUDE_ANCHORED is not relevant here */ +- /* FIXME: just skip regexps for now */ +- continue; ++ + chdir_do (name->change_dir); + + if (name->name[0] == 0) +diff --git a/src/tar.c b/src/tar.c +index 928cfdd..22d3db1 100644 +--- a/src/tar.c ++++ b/src/tar.c +@@ -722,7 +722,7 @@ static struct argp_option options[] = { + {"no-ignore-case", NO_IGNORE_CASE_OPTION, 0, 0, + N_("case sensitive matching (default)"), GRID+1 }, + {"wildcards", WILDCARDS_OPTION, 0, 0, +- N_("use wildcards (default for exclusion)"), GRID+1 }, ++ N_("use wildcards (default)"), GRID+1 }, + {"no-wildcards", NO_WILDCARDS_OPTION, 0, 0, + N_("verbatim string matching"), GRID+1 }, + {"no-wildcards-match-slash", NO_WILDCARDS_MATCH_SLASH_OPTION, 0, 0, +@@ -815,8 +815,7 @@ ARGMATCH_VERIFY (atime_preserve_args, atime_preserve_types); + /* Wildcard matching settings */ + enum wildcards + { +- default_wildcards, /* For exclusion == enable_wildcards, +- for inclusion == disable_wildcards */ ++ default_wildcards, /* enable_wildcards */ + disable_wildcards, + enable_wildcards + }; +@@ -847,7 +846,7 @@ struct tar_args /* Variables used during option parsing */ + | recursion_option) + + #define MAKE_INCL_OPTIONS(args) \ +- ((((args)->wildcards == enable_wildcards) ? EXCLUDE_WILDCARDS : 0) \ ++ ((((args)->wildcards != disable_wildcards) ? EXCLUDE_WILDCARDS : 0) \ + | (args)->include_anchored \ + | (args)->matching_flags \ + | recursion_option) +@@ -2347,7 +2346,7 @@ decode_options (int argc, char **argv) + + /* Warn about implicit use of the wildcards in command line arguments. + See TODO */ +- warn_regex_usage = args.wildcards == default_wildcards; ++ warn_regex_usage = 0; /* args.wildcards == default_wildcards; */ + + /* Derive option values and check option consistency. */ + +diff --git a/tests/exclude01.at b/tests/exclude01.at +index 778a7fc..bd65ae0 100644 +--- a/tests/exclude01.at ++++ b/tests/exclude01.at +@@ -59,6 +59,7 @@ testdir/dir2/file2 + testdir/dir3/ + NEXT + testdir/dir1/* ++testdir/dir1/file1 + NEXT + testdir/dir1/* + NEXT diff --git a/SOURCES/tar-1.22-atime-rofs.patch b/SOURCES/tar-1.22-atime-rofs.patch new file mode 100644 index 00000000..25a29085 --- /dev/null +++ b/SOURCES/tar-1.22-atime-rofs.patch @@ -0,0 +1,13 @@ +diff --git a/src/create.c b/src/create.c +index 43b5a4c..f98cbb5 100644 +--- a/src/create.c ++++ b/src/create.c +@@ -1798,7 +1798,8 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p) + } + else if (atime_preserve_option == replace_atime_preserve + && fd && (is_dir || original_size != 0) +- && set_file_atime (fd, parentfd, name, st->atime) != 0) ++ && set_file_atime (fd, parentfd, name, st->atime) != 0 ++ && errno != EROFS ) + utime_error (p); + } diff --git a/SOURCES/tar-1.23-oldarchive.patch b/SOURCES/tar-1.23-oldarchive.patch new file mode 100644 index 00000000..fd32bd77 --- /dev/null +++ b/SOURCES/tar-1.23-oldarchive.patch @@ -0,0 +1,14 @@ +diff -urNp tar-1.23-orig/src/tar.c tar-1.23/src/tar.c +--- tar-1.23-orig/src/tar.c 2010-06-01 13:55:03.792173060 +0200 ++++ tar-1.23/src/tar.c 2010-06-01 14:01:40.494172986 +0200 +@@ -1911,6 +1911,10 @@ parse_opt (int key, char *arg, struct ar + _("Invalid number"))); + } + break; ++ ++ case OLD_ARCHIVE_OPTION: ++ set_archive_format ("v7"); ++ break; + + case OVERWRITE_DIR_OPTION: + old_files_option = DEFAULT_OLD_FILES; diff --git a/SOURCES/tar-1.26-add-skip-old-files-option.patch b/SOURCES/tar-1.26-add-skip-old-files-option.patch new file mode 100644 index 00000000..2a496045 --- /dev/null +++ b/SOURCES/tar-1.26-add-skip-old-files-option.patch @@ -0,0 +1,370 @@ +diff --git a/doc/tar.texi b/doc/tar.texi +index d70d113..a0e3d5f 100644 +--- a/doc/tar.texi ++++ b/doc/tar.texi +@@ -1881,6 +1881,7 @@ The other operations of @command{tar} (@option{--list}, + @option{--extract}, @option{--compare}, and @option{--update}) + will act on the entire contents of the archive. + ++@anchor{exit status} + @cindex exit status + @cindex return status + Besides successful exits, @GNUTAR{} may fail for +@@ -2815,7 +2816,10 @@ when extracting files from an archive. + @item --keep-old-files + @itemx -k + +-Do not overwrite existing files when extracting files from an archive. ++Do not overwrite existing files when extracting files from an ++archive. Return error if such files exist. See also ++@ref{--skip-old-files}. ++ + @xref{Keep Old Files}. + + @opsummary{label} +@@ -3268,6 +3272,20 @@ the archive creation operations it instructs @command{tar} to list the + member names stored in the archive, as opposed to the actual file + names. @xref{listing member and file names}. + ++@opsummary{skip-old-files} ++@item --skip-old-files ++ ++Do not overwrite existing files when extracting files from an ++archive. @xref{Keep Old Files}. ++ ++This option differs from @option{--keep-old-files} in that it does not ++treat such files as an error, instead it just silently avoids ++overwriting them. ++ ++The @option{--warning=existing-file} option can be used together with ++this option to produce warning messages about existing old files ++(@pxref{warnings}). ++ + @opsummary{sparse} + @item --sparse + @itemx -S +@@ -4443,11 +4461,11 @@ in the archive; the most recently archived members will be extracted + last. Additionally, an extracted member will @emph{replace} a file of + the same name which existed in the directory already, and @command{tar} + will not prompt you about this@footnote{Unless you give it +-@option{--keep-old-files} option, or the disk copy is newer than +-the one in the archive and you invoke @command{tar} with +-@option{--keep-newer-files} option.}. Thus, only the most recently archived +-member will end up being extracted, as it will replace the one +-extracted before it, and so on. ++@option{--keep-old-files} (or @option{--skip-old-files}) option, or ++the disk copy is newer than the one in the archive and you invoke ++@command{tar} with @option{--keep-newer-files} option.}. Thus, only ++the most recently archived member will end up being extracted, as it ++will replace the one extracted before it, and so on. + + @cindex extracting @var{n}th copy of the file + @xopindex{occurrence, described} +@@ -5123,10 +5141,25 @@ such a directory, use the @option{--no-overwrite-dir} option. + @cindex Overwriting old files, prevention + @xopindex{keep-old-files, introduced} + To be even more cautious and prevent existing files from being replaced, use +-the @option{--keep-old-files} (@option{-k}) option. It causes @command{tar} to refuse +-to replace or update a file that already exists, i.e., a file with the +-same name as an archive member prevents extraction of that archive +-member. Instead, it reports an error. ++the @option{--keep-old-files} (@option{-k}) option. It causes ++@command{tar} to refuse to replace or update a file that already ++exists, i.e., a file with the same name as an archive member prevents ++extraction of that archive member. Instead, it reports an error. For ++example: ++ ++@example ++$ @kbd{ls} ++blues ++$ @kbd{tar -x -k -f archive.tar} ++tar: blues: Cannot open: File exists ++tar: Exiting with failure status due to previous errors ++@end example ++ ++@xopindex{skip-old-files, introduced} ++If you wish to preserve old files untouched, but don't want ++@command{tar} to treat them as errors, use the ++@option{--skip-old-files} option. This option causes @command{tar} to ++silently skip extracting over existing files. + + @xopindex{overwrite, introduced} + To be more aggressive about altering existing files, use the +@@ -5192,16 +5225,24 @@ archive, but remove other files before extracting. + @node Keep Old Files + @unnumberedsubsubsec Keep Old Files + ++@GNUTAR{} provides two options to control its actions in a situation ++when it is about to extract a file which already exists on disk. ++ + @table @option + @opindex keep-old-files + @item --keep-old-files + @itemx -k +-Do not replace existing files from archive. The +-@option{--keep-old-files} (@option{-k}) option prevents @command{tar} +-from replacing existing files with files with the same name from the +-archive. The @option{--keep-old-files} option is meaningless with +-@option{--list} (@option{-t}). Prevents @command{tar} from replacing +-files in the file system during extraction. ++Do not replace existing files from archive. When such a file is ++encountered, @command{tar} issues an error message. Upon end of ++extraction, @command{tar} exits with code 2 (@pxref{exit status}). ++ ++@item --skip-old-files ++Do not replace existing files from archive, but do not treat that ++as error. Such files are silently skipped and do not affect ++@command{tar} exit status. ++ ++Additional verbosity can be obtained using @option{--warning=existing-file} ++together with that option (@pxref{warnings}). + @end table + + @node Keep Newer Files +diff --git a/src/common.h b/src/common.h +index 0b9bd7a..2409413 100644 +--- a/src/common.h ++++ b/src/common.h +@@ -182,6 +182,7 @@ enum old_files + OVERWRITE_OLD_FILES, /* --overwrite */ + UNLINK_FIRST_OLD_FILES, /* --unlink-first */ + KEEP_OLD_FILES, /* --keep-old-files */ ++ SKIP_OLD_FILES, /* --skip-old-files */ + KEEP_NEWER_FILES /* --keep-newer-files */ + }; + GLOBAL enum old_files old_files_option; +@@ -807,11 +808,12 @@ void checkpoint_run (bool do_write); + #define WARN_UNKNOWN_KEYWORD 0x00020000 + #define WARN_XDEV 0x00040000 + #define WARN_DECOMPRESS_PROGRAM 0x00080000 ++#define WARN_EXISTING_FILE 0x00100000 + + /* The warnings composing WARN_VERBOSE_WARNINGS are enabled by default + in verbose mode */ + #define WARN_VERBOSE_WARNINGS (WARN_RENAME_DIRECTORY|WARN_NEW_DIRECTORY|\ +- WARN_DECOMPRESS_PROGRAM) ++ WARN_DECOMPRESS_PROGRAM|WARN_EXISTING_FILE) + #define WARN_ALL (~WARN_VERBOSE_WARNINGS) + + void set_warning_option (const char *arg); +diff --git a/src/extract.c b/src/extract.c +index aaea56e..662ea0b 100644 +--- a/src/extract.c ++++ b/src/extract.c +@@ -639,9 +639,14 @@ maybe_recoverable (char *file_name, bool regular, bool *interdir_made) + + switch (old_files_option) + { +- case KEEP_OLD_FILES: ++ case SKIP_OLD_FILES: ++ WARNOPT (WARN_EXISTING_FILE, ++ (0, 0, _("%s: skipping existing file"), file_name)); + return RECOVER_SKIP; + ++ case KEEP_OLD_FILES: ++ return RECOVER_NO; ++ + case KEEP_NEWER_FILES: + if (file_newer_p (file_name, stp, ¤t_stat_info)) + break; +diff --git a/src/tar.c b/src/tar.c +index 7b62996..7a673e0 100644 +--- a/src/tar.c ++++ b/src/tar.c +@@ -328,6 +328,7 @@ enum + SHOW_DEFAULTS_OPTION, + SHOW_OMITTED_DIRS_OPTION, + SHOW_TRANSFORMED_NAMES_OPTION, ++ SKIP_OLD_FILES_OPTION, + SPARSE_VERSION_OPTION, + STRIP_COMPONENTS_OPTION, + SUFFIX_OPTION, +@@ -452,7 +453,11 @@ static struct argp_option options[] = { + {"remove-files", REMOVE_FILES_OPTION, 0, 0, + N_("remove files after adding them to the archive"), GRID+1 }, + {"keep-old-files", 'k', 0, 0, +- N_("don't replace existing files when extracting"), GRID+1 }, ++ N_("don't replace existing files when extracting, " ++ "treat them as errors"), GRID+1 }, ++ {"skip-old-files", SKIP_OLD_FILES_OPTION, 0, 0, ++ N_("don't replace existing files when extracting, silently skip over them"), ++ GRID+1 }, + {"keep-newer-files", KEEP_NEWER_FILES_OPTION, 0, 0, + N_("don't replace existing files that are newer than their archive copies"), GRID+1 }, + {"overwrite", OVERWRITE_OPTION, 0, 0, +@@ -1618,6 +1623,10 @@ parse_opt (int key, char *arg, struct argp_state *state) + sparse_option = true; + break; + ++ case SKIP_OLD_FILES_OPTION: ++ old_files_option = SKIP_OLD_FILES; ++ break; ++ + case SPARSE_VERSION_OPTION: + sparse_option = true; + { +diff --git a/src/warning.c b/src/warning.c +index 5d1bcab..ee9d684 100644 +--- a/src/warning.c ++++ b/src/warning.c +@@ -42,6 +42,7 @@ static char const *const warning_args[] = { + "unknown-keyword", + "xdev", + "decompress-program", ++ "existing-file", + NULL + }; + +@@ -66,7 +67,8 @@ static int warning_types[] = { + WARN_UNKNOWN_CAST, + WARN_UNKNOWN_KEYWORD, + WARN_XDEV, +- WARN_DECOMPRESS_PROGRAM ++ WARN_DECOMPRESS_PROGRAM, ++ WARN_EXISTING_FILE, + }; + + ARGMATCH_VERIFY (warning_args, warning_types); +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 119f1f3..3d78ea2 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -77,6 +77,8 @@ TESTSUITE_AT = \ + extrac07.at\ + extrac08.at\ + extrac09.at\ ++ extrac18.at\ ++ extrac19.at\ + extrac10.at\ + extrac11.at\ + extrac12.at\ +diff --git a/tests/extrac18.at b/tests/extrac18.at +new file mode 100644 +index 0000000..8b42ef7 +--- /dev/null ++++ b/tests/extrac18.at +@@ -0,0 +1,60 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# ++# Test suite for GNU tar. ++# Copyright (C) 2011 Free Software Foundation, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3, or (at your option) ++# any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Description: Check the functionality of the --keep-old-files option. ++# It should report an error and cause tar to exit with status 2. ++# ++# There was a regression in versions 1.23 to 1.26 inclusive, where ++# this option silently skipped such files. ++# Reported by: Doug McLaren , ++# Gary Partis , ++# Jim Meyering ++# ++# References: <20111117045433.GA8245@algol.frenzied.us>, ++# <4F3D824717847C4487F77228F83329A3514CBB@server.Partis.local>, ++# <87wrar6zzz.fsf@rho.meyering.net> ++ ++AT_SETUP([keep-old-files]) ++AT_KEYWORDS([extract extrac18 old-files keep-old-files]) ++ ++AT_TAR_CHECK([ ++mkdir dir ++cd dir ++echo 'Old file a' > a ++echo 'Old file b' > b ++ ++tar cf ../archive . ++ ++rm b ++echo 'File a' > a ++ ++tar -x -k -f ../archive ++echo status=$? ++ ++cat a ++], ++[0], ++[status=2 ++File a ++], ++[tar: ./a: Cannot open: File exists ++tar: Exiting with failure status due to previous errors ++]) ++ ++AT_CLEANUP ++ +diff --git a/tests/extrac19.at b/tests/extrac19.at +new file mode 100644 +index 0000000..43c4c50 +--- /dev/null ++++ b/tests/extrac19.at +@@ -0,0 +1,44 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# ++# Test suite for GNU tar. ++# Copyright (C) 2011 Free Software Foundation, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3, or (at your option) ++# any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++AT_SETUP([skip-old-files]) ++AT_KEYWORDS([extract extrac19 old-files skip-old-files]) ++ ++AT_TAR_CHECK([ ++mkdir dir ++cd dir ++echo 'Old file a' > a ++echo 'Old file b' > b ++ ++tar cf ../archive . ++ ++rm b ++echo 'File a' > a ++ ++tar -x --skip-old-files -f ../archive ++echo status=$? ++ ++cat a ++], ++[0], ++[status=0 ++File a ++]) ++ ++AT_CLEANUP ++ +diff --git a/tests/testsuite.at b/tests/testsuite.at +index d1dab36..e43653e 100644 +--- a/tests/testsuite.at ++++ b/tests/testsuite.at +@@ -166,6 +166,9 @@ m4_include([extrac15.at]) + m4_include([extrac16.at]) + m4_include([extrac17.at]) + ++m4_include([extrac18.at]) ++m4_include([extrac19.at]) ++ + m4_include([label01.at]) + m4_include([label02.at]) + m4_include([label03.at]) diff --git a/SOURCES/tar-1.26-allow-extract-single-volume.patch b/SOURCES/tar-1.26-allow-extract-single-volume.patch new file mode 100644 index 00000000..11a88153 --- /dev/null +++ b/SOURCES/tar-1.26-allow-extract-single-volume.patch @@ -0,0 +1,27 @@ +diff --git a/src/extract.c b/src/extract.c +index 87b383a..340beea 100644 +--- a/src/extract.c ++++ b/src/extract.c +@@ -1415,6 +1415,13 @@ 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); + + +@@ -1495,7 +1502,7 @@ prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun) + ERROR ((0, 0, + _("%s: Cannot extract -- file is continued from another volume"), + quotearg_colon (current_stat_info.file_name))); +- *fun = extract_failure; ++ *fun = extract_skip; + break; + + case GNUTYPE_LONGNAME: diff --git a/SOURCES/tar-1.26-default-acls.patch b/SOURCES/tar-1.26-default-acls.patch new file mode 100644 index 00000000..0b18e2b6 --- /dev/null +++ b/SOURCES/tar-1.26-default-acls.patch @@ -0,0 +1,266 @@ +From e3a7b9c8f26ca3b5a9aedd4c1d596a4a8504c812 Mon Sep 17 00:00:00 2001 +From: Pavel Raiskup +Date: Thu, 4 Jun 2015 09:30:38 +0200 +Subject: [PATCH] acls: don't mistakenly set default ACLs + +Upstream commits +efbf4cce0b93e8c5a5fc93335b917bbeae2f67cb +9df17e6005e7a333399e3dc21a7afec75565c767 +7fe7adcbb985e78aaf9f78051fa26167779be1f6 +--- + configure.ac | 2 + + src/xattrs.c | 37 ++++++++++++--- + tests/Makefile.am | 1 + + tests/acls03.at | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + tests/testsuite.at | 1 + + 5 files changed, 165 insertions(+), 7 deletions(-) + create mode 100644 tests/acls03.at + +diff --git a/configure.ac b/configure.ac +index 9b3e0c8..7ccb579 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -85,6 +85,8 @@ if test "x$with_posix_acls" != "xno"; then + AC_SEARCH_LIBS([acl_set_fd], [acl pacl],, [with_posix_acl=no]) + AC_SEARCH_LIBS([acl_to_text], [acl pacl],, [with_posix_acl=no]) + AC_SEARCH_LIBS([acl_from_text], [acl pacl],, [with_posix_acl=no]) ++ AC_SEARCH_LIBS([acl_delete_def_file], [acl pacl],, [with_posix_acl=no]) ++ AC_SEARCH_LIBS([acl_free], [acl pacl],, [with_posix_acl=no]) + if test "x$with_posix_acls" != xno; then + AC_DEFINE(HAVE_POSIX_ACLS,,[Define when we have working POSIX acls]) + fi +diff --git a/src/xattrs.c b/src/xattrs.c +index bdf6ba0..5bd4b02 100644 +--- a/src/xattrs.c ++++ b/src/xattrs.c +@@ -61,6 +61,7 @@ static struct + acl_t acl_get_file_at (int dirfd, const char *file, acl_type_t type); + int acl_set_file_at (int dirfd, const char *file, acl_type_t type, acl_t acl); + int file_has_acl_at (int dirfd, char const *, struct stat const *); ++int acl_delete_def_file_at (int, char const *); + + /* acl_get_file_at */ + #define AT_FUNC_NAME acl_get_file_at +@@ -88,6 +89,17 @@ int file_has_acl_at (int dirfd, char const *, struct stat const *); + #undef AT_FUNC_POST_FILE_PARAM_DECLS + #undef AT_FUNC_POST_FILE_ARGS + ++/* acl_delete_def_file_at */ ++#define AT_FUNC_NAME acl_delete_def_file_at ++#define AT_FUNC_F1 acl_delete_def_file ++#define AT_FUNC_POST_FILE_PARAM_DECLS ++#define AT_FUNC_POST_FILE_ARGS ++#include "at-func.c" ++#undef AT_FUNC_NAME ++#undef AT_FUNC_F1 ++#undef AT_FUNC_POST_FILE_PARAM_DECLS ++#undef AT_FUNC_POST_FILE_ARGS ++ + /* gnulib file_has_acl_at */ + #define AT_FUNC_NAME file_has_acl_at + #define AT_FUNC_F1 file_has_acl +@@ -187,7 +199,8 @@ fixup_extra_acl_fields (char *ptr) + return ptr; + } + +-/* "system.posix_acl_access" */ ++/* Set the "system.posix_acl_access/system.posix_acl_default" extended ++ attribute. Called only when acls_option > 0. */ + static void + xattrs__acls_set (struct tar_stat_info const *st, + char const *file_name, int type, +@@ -199,15 +212,25 @@ xattrs__acls_set (struct tar_stat_info const *st, + { + /* assert (strlen (ptr) == len); */ + ptr = fixup_extra_acl_fields (ptr); +- + acl = acl_from_text (ptr); +- acls_option = 1; + } +- else if (acls_option > 0) ++ else if (def) ++ { ++ /* No "default" IEEE 1003.1e ACL set for directory. At this moment, ++ FILE_NAME may already have inherited default acls from parent ++ directory; clean them up. */ ++ if (acl_delete_def_file_at (chdir_fd, file_name)) ++ WARNOPT (WARN_XATTR_WRITE, ++ (0, errno, ++ _("acl_delete_def_file_at: Cannot drop default POSIX ACLs " ++ "for file '%s'"), ++ file_name)); ++ return; ++ } ++ else ++ /* There is nothing like "acl_delete_def_file" for non-default acls, we ++ need to re-set ACLs based on permission bits */ + acl = perms2acl (st->stat.st_mode); +- else +- return; /* don't call acl functions unless we first hit an ACL, or +- --acls was passed explicitly */ + + if (!acl) + { +diff --git a/tests/Makefile.am b/tests/Makefile.am +index b0da439..228e936 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -179,6 +179,7 @@ TESTSUITE_AT = \ + xattr05.at\ + acls01.at\ + acls02.at\ ++ acls03.at\ + selnx01.at\ + selacl01.at\ + capabs_raw01.at +diff --git a/tests/acls03.at b/tests/acls03.at +new file mode 100644 +index 0000000..83c5bdc +--- /dev/null ++++ b/tests/acls03.at +@@ -0,0 +1,131 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# ++# Test suite for GNU tar. ++# Copyright 2013, 2014 Free Software Foundation, Inc. ++ ++# This file is part of GNU tar. ++ ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++ ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++ ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++# Test description: ++# ++# Check the storing/restoring with/without default ACLs. When --acls is passed, ++# restored directory tree should always match archive contents (even when the ++# archive does not contain any ACLs). ++# ++# References: ++# http://www.mail-archive.com/bug-tar@gnu.org/msg04355.html ++ ++AT_SETUP([acls: default ACLs]) ++AT_KEYWORDS([xattrs acls acls03]) ++ ++m4_define([ACL_LISTDIR], [ ++ cd $1 ++ $1="$(find d1 | sort | xargs -n 1 getfacl)" ++ cd .. ++]) ++ ++m4_define([ACL_ASSERT], [ ++ echo "$$1" > $1.log ++ echo "$$2" > $2.log ++ if test ! "$$1" "$3" "$$2"; then ++ echo "bad '$1' against '$2' output" ++ fi ++]) ++ ++AT_TAR_CHECK([ ++AT_XATTRS_UTILS_PREREQ ++AT_ACLS_PREREQ ++AT_SORT_PREREQ ++ ++MYNAME=$( id -un ) ++MYGROUP=$( id -gn ) ++ ++# Prepare directory structure with default ACLs ++mkdir -p pure/d1/d2 ++genfile --file pure/d1/f2a ++genfile --file pure/d1/f2b ++genfile --file pure/d1/d2/f3a ++genfile --file pure/d1/d2/f3b ++setfacl -m g:$MYGROUP:r-x pure/d1 ++setfacl -d -m g:$MYGROUP:rwx pure/d1 ++setfacl -d -m u:$MYNAME:rwx pure/d1 ++# "*a" files have "some" additional ACLs ++setfacl -m u:$MYNAME:--- pure/d1/d2/f3a ++setfacl -m u:$MYNAME:--- pure/d1/f2a ++ ++# use default format (no acls stored) ++tar -cf noacl.tar -C pure d1 ++ ++# use posix format, acls stored ++tar --acls -cf acl.tar -C pure d1 ++ ++# Directory names are chosen based on "how the files were extracted from ++# archive". Equivalent no* tags are used also: ++# ^sacl_ — extracted archive has stored ACLs ++# _def_ — target directory (-C) has default ACLs ++# _optacl$ — extraction was done with --acls option ++ ++mkdir sacl_def_optacl ++mkdir sacl_def_optnoacl ++mkdir sacl_nodef_optacl ++mkdir sacl_nodef_optnoacl ++mkdir nosacl_def_optacl ++mkdir nosacl_def_optnoacl ++mkdir nosacl_nodef_optacl ++mkdir nosacl_nodef_optnoacl ++ ++setfacl -d -m u:$MYNAME:--- nosacl_def_optnoacl sacl_def_optnoacl sacl_def_optacl nosacl_def_optacl ++setfacl -d -m g:$MYGROUP:--- nosacl_def_optnoacl sacl_def_optnoacl sacl_def_optacl nosacl_def_optacl ++ ++tar -xf acl.tar -C sacl_nodef_optnoacl ++tar --acls -xf acl.tar -C sacl_nodef_optacl ++tar -xf acl.tar -C sacl_def_optnoacl ++tar --acls -xf acl.tar -C sacl_def_optacl ++tar -xf noacl.tar -C nosacl_def_optnoacl ++# _NO_ ACLs in output ++tar -xf noacl.tar -C nosacl_nodef_optnoacl ++tar -xf noacl.tar -C nosacl_nodef_optacl ++tar -cf noacl_repackaged.tar -C nosacl_nodef_optnoacl d1 ++# _NO_ ACLs in output (even when default ACLs exist) ++tar --acls -xf noacl_repackaged.tar -C nosacl_def_optacl ++ ++ACL_LISTDIR(pure) ++ ++ACL_LISTDIR(sacl_def_optacl) ++ACL_LISTDIR(sacl_def_optnoacl) ++ACL_LISTDIR(sacl_nodef_optacl) ++ACL_LISTDIR(sacl_nodef_optnoacl) ++ACL_LISTDIR(nosacl_def_optacl) ++ACL_LISTDIR(nosacl_def_optnoacl) ++ACL_LISTDIR(nosacl_nodef_optacl) ++ACL_LISTDIR(nosacl_nodef_optnoacl) ++ ++ACL_ASSERT(pure, sacl_def_optacl, =) ++ ++ACL_ASSERT(sacl_def_optacl, sacl_nodef_optacl, =) ++ACL_ASSERT(sacl_def_optnoacl, nosacl_def_optnoacl, =) ++ACL_ASSERT(sacl_nodef_optnoacl, nosacl_nodef_optnoacl, =) ++ACL_ASSERT(nosacl_def_optacl, nosacl_nodef_optacl, =) ++ACL_ASSERT(nosacl_def_optacl, nosacl_nodef_optnoacl, =) ++ ++ACL_ASSERT(sacl_def_optacl, sacl_def_optnoacl, !=) ++ACL_ASSERT(sacl_def_optacl, nosacl_def_optnoacl, !=) ++ACL_ASSERT(nosacl_def_optnoacl, nosacl_nodef_optnoacl, !=) ++], ++[0], ++[], ++[]) ++ ++AT_CLEANUP +diff --git a/tests/testsuite.at b/tests/testsuite.at +index d5925b3..10cf26a 100644 +--- a/tests/testsuite.at ++++ b/tests/testsuite.at +@@ -341,6 +341,7 @@ m4_include([xattr05.at]) + + m4_include([acls01.at]) + m4_include([acls02.at]) ++m4_include([acls03.at]) + + m4_include([selnx01.at]) + m4_include([selacl01.at]) +-- +2.1.0 diff --git a/SOURCES/tar-1.26-directory_with_remove-files.patch b/SOURCES/tar-1.26-directory_with_remove-files.patch new file mode 100644 index 00000000..57840ee5 --- /dev/null +++ b/SOURCES/tar-1.26-directory_with_remove-files.patch @@ -0,0 +1,3500 @@ +From 4bf4efe97d25784eb5e56c8ee337af3c7866ec34 Mon Sep 17 00:00:00 2001 +From: Sergey Poznyakoff +Date: Tue, 24 Sep 2013 14:01:13 +0300 +Subject: [PATCH 01/11] Fix normalize_filename. + +The function did not take into account eventual -C options, which +in particular led to various problems when using -C and --remove-files +together. + +* src/common.h (namebuf_add_dir,namebuf_finish) +(tar_getcwd): New prototypes. +* src/misc.c (namebuf_add_dir,namebuf_finish) +(tar_getcwd): New functions. +(normalize_filename): Use tar_getcwd. +--- + src/common.h | 4 ++++ + src/misc.c | 41 ++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 44 insertions(+), 1 deletion(-) + +diff --git a/src/common.h b/src/common.h +index 16ba401..85a6977 100644 +--- a/src/common.h ++++ b/src/common.h +@@ -603,6 +603,10 @@ typedef struct namebuf *namebuf_t; + namebuf_t namebuf_create (const char *dir); + void namebuf_free (namebuf_t buf); + char *namebuf_name (namebuf_t buf, const char *name); ++void namebuf_add_dir (namebuf_t buf, const char *name); ++char *namebuf_finish (namebuf_t buf); ++ ++char *tar_getcwd (void); + + void code_ns_fraction (int ns, char *p); + char const *code_timespec (struct timespec ts, char *sbuf); +diff --git a/src/misc.c b/src/misc.c +index b75f2ab..f45f79a 100644 +--- a/src/misc.c ++++ b/src/misc.c +@@ -283,7 +283,7 @@ normalize_filename (const char *name) + getcwd is slow, it might fail, and it does not necessarily + return a canonical name even when it succeeds. Perhaps we + can use dev+ino pairs instead of names? */ +- copy = xgetcwd (); ++ copy = tar_getcwd (); + if (copy) + { + size_t copylen = strlen (copy); +@@ -777,6 +777,21 @@ chdir_do (int i) + } + } + ++char * ++tar_getcwd (void) ++{ ++ static char *cwd; ++ namebuf_t nbuf; ++ int i; ++ ++ if (!cwd) ++ cwd = xgetcwd (); ++ nbuf = namebuf_create (cwd); ++ for (i = 1; i <= chdir_current; i++) ++ namebuf_add_dir (nbuf, wd[i].name); ++ return namebuf_finish (nbuf); ++} ++ + void + close_diag (char const *name) + { +@@ -945,3 +960,27 @@ namebuf_name (namebuf_t buf, const char *name) + + return ret; + } ++ ++void ++namebuf_add_dir (namebuf_t buf, const char *name) ++{ ++ static char dirsep[] = { DIRECTORY_SEPARATOR, 0 }; ++ if (!ISSLASH (buf->buffer[buf->dir_length - 1])) ++ { ++ namebuf_name (buf, dirsep); ++ buf->dir_length++; ++ } ++ namebuf_name (buf, name); ++ buf->dir_length += strlen (name); ++} ++ ++char * ++namebuf_finish (namebuf_t buf) ++{ ++ char *res = buf->buffer; ++ ++ if (ISSLASH (buf->buffer[buf->dir_length - 1])) ++ buf->buffer[buf->dir_length] = 0; ++ free (buf); ++ return res; ++} +-- +2.9.3 + + +From 272e1c879644b3684031acd62c9adb0adc5133b5 Mon Sep 17 00:00:00 2001 +From: Sergey Poznyakoff +Date: Wed, 25 Sep 2013 15:58:43 +0300 +Subject: [PATCH 02/11] Improve tar_getcwd + +* src/common.h (tar_getcwd): Return pointer is const. +* src/misc.c (wd) : New member. +(chdir_arg): Initialize cwd. +(tar_getcwd): Use cwd member to cache the result. Take into +account absolute pathnames, +(normalize_filename): Don't free the value +returned from tar_getcwd. +* src/names.c (name_next_elt): Remove leftover call chdir(). +* tests/Makefile.am: Add new tests. +* tests/testsuite.at: Likewise. + +* tests/incr08.at: New testcase. +* tests/remfiles04.at: New testcase. +* tests/remfiles05.at: New testcase. +* tests/remfiles06.at: New testcase. +* tests/remfiles07.at: New testcase. +--- + src/common.h | 2 +- + src/misc.c | 57 +++++++++++++++++++++++------------ + src/names.c | 3 +- + tests/Makefile.am | 5 ++++ + tests/incr08.at | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + tests/remfiles04.at | 53 +++++++++++++++++++++++++++++++++ + tests/remfiles05.at | 60 +++++++++++++++++++++++++++++++++++++ + tests/remfiles06.at | 66 ++++++++++++++++++++++++++++++++++++++++ + tests/remfiles07.at | 63 +++++++++++++++++++++++++++++++++++++++ + tests/testsuite.at | 5 ++++ + 10 files changed, 378 insertions(+), 22 deletions(-) + create mode 100644 tests/incr08.at + create mode 100644 tests/remfiles04.at + create mode 100644 tests/remfiles05.at + create mode 100644 tests/remfiles06.at + create mode 100644 tests/remfiles07.at + +diff --git a/src/common.h b/src/common.h +index 85a6977..99f8552 100644 +--- a/src/common.h ++++ b/src/common.h +@@ -606,7 +606,7 @@ char *namebuf_name (namebuf_t buf, const char *name); + void namebuf_add_dir (namebuf_t buf, const char *name); + char *namebuf_finish (namebuf_t buf); + +-char *tar_getcwd (void); ++const char *tar_getcwd (void); + + void code_ns_fraction (int ns, char *p); + char const *code_timespec (struct timespec ts, char *sbuf); +diff --git a/src/misc.c b/src/misc.c +index f45f79a..2fd5280 100644 +--- a/src/misc.c ++++ b/src/misc.c +@@ -283,21 +283,20 @@ normalize_filename (const char *name) + getcwd is slow, it might fail, and it does not necessarily + return a canonical name even when it succeeds. Perhaps we + can use dev+ino pairs instead of names? */ +- copy = tar_getcwd (); +- if (copy) +- { +- size_t copylen = strlen (copy); +- bool need_separator = ! (DOUBLE_SLASH_IS_DISTINCT_ROOT +- && copylen == 2 && ISSLASH (copy[1])); +- copy = xrealloc (copy, copylen + need_separator + strlen (name) + 1); +- copy[copylen] = DIRECTORY_SEPARATOR; +- strcpy (copy + copylen + need_separator, name); +- } +- else +- WARN ((0, errno, _("Cannot get working directory"))); ++ const char *cwd = tar_getcwd (); ++ size_t copylen; ++ bool need_separator; ++ ++ copylen = strlen (cwd); ++ need_separator = ! (DOUBLE_SLASH_IS_DISTINCT_ROOT ++ && copylen == 2 && ISSLASH (cwd[1])); ++ copy = xmalloc (copylen + need_separator + strlen (name) + 1); ++ strcpy (copy, cwd); ++ copy[copylen] = DIRECTORY_SEPARATOR; ++ strcpy (copy + copylen + need_separator, name); + } + +- if (! copy) ++ if (!copy) + copy = xstrdup (name); + normalize_filename_x (copy); + return copy; +@@ -632,7 +631,8 @@ struct wd + { + /* The directory's name. */ + char const *name; +- ++ /* Current working directory; initialized by tar_getcwd */ ++ char *cwd; + /* If nonzero, the file descriptor of the directory, or AT_FDCWD if + the working directory. If zero, the directory needs to be opened + to be used. */ +@@ -687,6 +687,7 @@ chdir_arg (char const *dir) + if (! wd_count) + { + wd[wd_count].name = "."; ++ wd[wd_count].cwd = NULL; + wd[wd_count].fd = AT_FDCWD; + wd_count++; + } +@@ -704,6 +705,7 @@ chdir_arg (char const *dir) + } + + wd[wd_count].name = dir; ++ wd[wd_count].cwd = NULL; + wd[wd_count].fd = 0; + return wd_count++; + } +@@ -777,7 +779,7 @@ chdir_do (int i) + } + } + +-char * ++const char * + tar_getcwd (void) + { + static char *cwd; +@@ -786,10 +788,27 @@ tar_getcwd (void) + + if (!cwd) + cwd = xgetcwd (); +- nbuf = namebuf_create (cwd); +- for (i = 1; i <= chdir_current; i++) +- namebuf_add_dir (nbuf, wd[i].name); +- return namebuf_finish (nbuf); ++ if (!wd) ++ return cwd; ++ ++ if (0 == chdir_current || !wd[chdir_current].cwd) ++ { ++ if (IS_ABSOLUTE_FILE_NAME (wd[chdir_current].name)) ++ return wd[chdir_current].name; ++ ++ if (!wd[0].cwd) ++ wd[0].cwd = cwd; ++ ++ for (i = chdir_current - 1; i > 0; i--) ++ if (wd[i].cwd) ++ break; ++ ++ nbuf = namebuf_create (wd[i].cwd); ++ for (i++; i <= chdir_current; i++) ++ namebuf_add_dir (nbuf, wd[i].name); ++ wd[chdir_current].cwd = namebuf_finish (nbuf); ++ } ++ return wd[chdir_current].cwd; + } + + void +diff --git a/src/names.c b/src/names.c +index 3911f8c..8c3052f 100644 +--- a/src/names.c ++++ b/src/names.c +@@ -351,8 +351,7 @@ name_next_elt (int change_dirs) + + if (change_dirs && ep->type == NELT_CHDIR) + { +- if (chdir (name_buffer) < 0) +- chdir_fatal (name_buffer); ++ chdir_do (chdir_arg (xstrdup (ep->v.name))); + } + else + { +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 228e936..1d10360 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -99,6 +99,7 @@ TESTSUITE_AT = \ + incr05.at\ + incr06.at\ + incr07.at\ ++ incr08.at\ + indexfile.at\ + ignfail.at\ + label01.at\ +@@ -139,6 +140,10 @@ TESTSUITE_AT = \ + remfiles01.at\ + remfiles02.at\ + remfiles03.at\ ++ remfiles04.at\ ++ remfiles05.at\ ++ remfiles06.at\ ++ remfiles07.at\ + same-order01.at\ + same-order02.at\ + shortfile.at\ +diff --git a/tests/incr08.at b/tests/incr08.at +new file mode 100644 +index 0000000..5210d28 +--- /dev/null ++++ b/tests/incr08.at +@@ -0,0 +1,86 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Description: In tar 1.26 listed-incremental with -C and absolute path ++# would malfunction under certain conditions due to buggy filename ++# normalization. ++# ++# The value returned by normalize_filename() is used to populate the "caname" ++# field in both the "directory" structure in incremen.c and the "name" ++# structure in names.c, and in both cases that field is then used in the ++# "hash" and "compare" functions for the related hash tables. Thus, the ++# fact that the returned value doesn't reflect the operation of previous ++# "-C" options means that it's possible for two different directories to ++# be given the same "caname" value in the hashed structure and thus end up ++# being confused with each other. ++# ++# The bug is triggered when dumping both relative paths after -C and ++# absolute paths that match the process' current working directory. ++# ++# Reported by: Nathan Stratton Treadway ++# References: <20130922192135.GJ32256@shire.ontko.com>, ++# http://lists.gnu.org/archive/html/bug-tar/2013-09/msg00034.html ++ ++AT_SETUP([filename normalization]) ++AT_KEYWORDS([incremental create incr08]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++mkdir tartest ++cd tartest ++mkdir foo ++mkdir foo/subdir ++mkdir foo/subdir/dir1 ++mkdir subdir ++mkdir subdir/dir2 ++decho A ++find|sort ++ ++decho B ++DIR=`pwd` ++tar -cvf ../foo.tar --listed-incremental=../foo.snar -C foo . $DIR 2>../err |\ ++ sed "s|$DIR|ABSPATH|" ++sed "s|$DIR|ABSPATH|" ../err >&2 ++], ++[0], ++[A ++. ++./foo ++./foo/subdir ++./foo/subdir/dir1 ++./subdir ++./subdir/dir2 ++B ++./ ++./subdir/ ++./subdir/dir1/ ++ABSPATH/ ++ABSPATH/subdir/ ++ABSPATH/subdir/dir2/ ++], ++[A ++B ++tar: .: Directory is new ++tar: ./subdir: Directory is new ++tar: ./subdir/dir1: Directory is new ++tar: ABSPATH: Directory is new ++tar: ABSPATH/subdir: Directory is new ++tar: ABSPATH/subdir/dir2: Directory is new ++tar: Removing leading `/' from member names ++],[],[],[gnu]) ++ ++AT_CLEANUP +diff --git a/tests/remfiles04.at b/tests/remfiles04.at +new file mode 100644 +index 0000000..04df45b +--- /dev/null ++++ b/tests/remfiles04.at +@@ -0,0 +1,53 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Description: Tar 1.26 would remove wrong files when called with ++# --remove-files and -C ++# Reported by: Jörgen Strand ++# References: <9FC79E5CB90CEC47B9647DCAB7BD327A01AD83B452EE@seldmbx02.corpusers.net> ++# http://lists.gnu.org/archive/html/bug-tar/2013-09/msg00024.html ++ ++AT_SETUP([remove-files with -C]) ++AT_KEYWORDS([create remove-files remfiles04]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++mkdir foo ++echo bar > bar ++echo foobar > foo/bar ++tar -cf foo.tar --remove-files -C foo bar ++echo A ++find . | sort ++echo foobar > foo/bar ++tar -rf foo.tar --remove-files -C foo bar ++echo B ++find . | sort ++], ++[0], ++[A ++. ++./bar ++./foo ++./foo.tar ++B ++. ++./bar ++./foo ++./foo.tar ++],[],[],[],[gnu]) ++ ++AT_CLEANUP +diff --git a/tests/remfiles05.at b/tests/remfiles05.at +new file mode 100644 +index 0000000..04425a7 +--- /dev/null ++++ b/tests/remfiles05.at +@@ -0,0 +1,60 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Description: Tar 1.26 would remove wrong files when invoked with ++# --listed-incremental and -C ++# Reported by: Nathan Stratton Treadway ++# References: <20130921171234.GG32256@shire.ontko.com>, ++# http://lists.gnu.org/archive/html/bug-tar/2013-09/msg00028.html ++ ++AT_SETUP([incremental and -C]) ++AT_KEYWORDS([incremental create remove-files remfiles05]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++mkdir foo ++echo bar > bar ++echo foo/bar > foo/bar ++decho A ++find . | sort ++ ++decho B ++tar -cvf foo.tar --listed-incremental=foo.snar --remove-files -C foo bar ++decho C ++find . | sort ++], ++[0], ++[A ++. ++./bar ++./foo ++./foo/bar ++B ++bar ++C ++. ++./bar ++./foo ++./foo.snar ++./foo.tar ++], ++[A ++B ++C ++],[],[],[gnu]) ++ ++AT_CLEANUP +diff --git a/tests/remfiles06.at b/tests/remfiles06.at +new file mode 100644 +index 0000000..75ddcfa +--- /dev/null ++++ b/tests/remfiles06.at +@@ -0,0 +1,66 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Description: There was a leftover call to chdir in name_next_elt() in ++# tar 1.26. After commit e3d28d84 this call would confuse the tar_getcwd ++# function. ++# Reported by: Nathan Stratton Treadway ++# References: <20130924145657.GM32256@shire.ontko.com>, ++# http://lists.gnu.org/archive/html/bug-tar/2013-09/msg00045.html ++ ++AT_SETUP([incremental with two -C]) ++AT_KEYWORDS([incremental create remove-files remfiles06]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++mkdir tartest ++cd tartest ++mkdir foo ++echo foo/file > foo/file ++mkdir bar ++echo bar/file > bar/file ++decho A ++find|sort ++ ++decho B ++tar -cvf ../foo.tar --remove-files -C foo file -C ../bar file ++ ++decho C ++find|sort ++], ++[0], ++[A ++. ++./bar ++./bar/file ++./foo ++./foo/file ++B ++file ++file ++C ++. ++./bar ++./foo ++], ++[A ++B ++C ++],[],[],[gnu]) ++ ++AT_CLEANUP ++ +diff --git a/tests/remfiles07.at b/tests/remfiles07.at +new file mode 100644 +index 0000000..84ab625 +--- /dev/null ++++ b/tests/remfiles07.at +@@ -0,0 +1,63 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Description: See remfiles06.at ++# Reported by: Nathan Stratton Treadway ++# References: <20130924185129.GO32256@shire.ontko.com> ++ ++AT_SETUP([incremental with -C to absolute path]) ++AT_KEYWORDS([incremental create remove-files remfiles07]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++mkdir tartest ++cd tartest ++mkdir foo ++echo foo/file > foo/file ++mkdir bar ++echo bar/file > bar/file ++decho A ++find|sort ++ ++DIR=`pwd` ++decho B ++tar -cvf ../foo.tar --remove-files -C foo file -C $DIR/bar file ++ ++decho C ++find|sort ++], ++[0], ++[A ++. ++./bar ++./bar/file ++./foo ++./foo/file ++B ++file ++file ++C ++. ++./bar ++./foo ++], ++[A ++B ++C ++],[],[],[gnu]) ++ ++AT_CLEANUP +diff --git a/tests/testsuite.at b/tests/testsuite.at +index 10cf26a..5c805e7 100644 +--- a/tests/testsuite.at ++++ b/tests/testsuite.at +@@ -260,6 +260,7 @@ m4_include([incr03.at]) + m4_include([incr05.at]) + m4_include([incr06.at]) + m4_include([incr07.at]) ++m4_include([incr08.at]) + + m4_include([filerem01.at]) + m4_include([filerem02.at]) +@@ -330,6 +331,10 @@ m4_include([grow.at]) + m4_include([remfiles01.at]) + m4_include([remfiles02.at]) + m4_include([remfiles03.at]) ++m4_include([remfiles04.at]) ++m4_include([remfiles05.at]) ++m4_include([remfiles06.at]) ++m4_include([remfiles07.at]) + + m4_include([sigpipe.at]) + +-- +2.9.3 + + +From 0c5f95ca80d507a00825c8e3fd05ed5ad993ce17 Mon Sep 17 00:00:00 2001 +From: Sergey Poznyakoff +Date: Thu, 26 Sep 2013 15:41:47 +0300 +Subject: [PATCH 03/11] Use relative addressing in deferred unlinks. + +* src/common.h (tar_dirname): New function. +* src/misc.c (normalize_filename_x): Make extern. +(tar_dirname): New function. +(tar_getcwd): Take into account absoulte pathnames. +* src/unlink.c (deferred_unlink) : New member; keeps the +value of chdir_current at the moment of structure allocation. +(flush_deferred_unlinks): Use chdir_do and relative addressing. +(queue_deferred_unlink): Initialize dir_idx. +* tests/Makefile.am: Add new tests. +* tests/testsuite.at: Add new tests. +* tests/remfiles06.at: Fix description. +* tests/remfiles07.at: Fix description. +* tests/remfiles08.at: New test case. +--- + src/common.h | 2 ++ + src/misc.c | 28 +++++++++++++++++++--------- + src/unlink.c | 27 +++++++++++++++++++++++---- + tests/Makefile.am | 1 + + tests/remfiles06.at | 4 ++-- + tests/remfiles07.at | 4 ++-- + tests/remfiles08.at | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ + tests/testsuite.at | 1 + + 8 files changed, 98 insertions(+), 17 deletions(-) + create mode 100644 tests/remfiles08.at + +diff --git a/src/common.h b/src/common.h +index 99f8552..7d64227 100644 +--- a/src/common.h ++++ b/src/common.h +@@ -596,6 +596,7 @@ void assign_string (char **dest, const char *src); + int unquote_string (char *str); + char *zap_slashes (char *name); + char *normalize_filename (const char *name); ++void normalize_filename_x (char *name); + void replace_prefix (char **pname, const char *samp, size_t slen, + const char *repl, size_t rlen); + char *tar_savedir (const char *name, int must_exist); +@@ -607,6 +608,7 @@ void namebuf_add_dir (namebuf_t buf, const char *name); + char *namebuf_finish (namebuf_t buf); + + const char *tar_getcwd (void); ++const char *tar_dirname (void); + + void code_ns_fraction (int ns, char *p); + char const *code_timespec (struct timespec ts, char *sbuf); +diff --git a/src/misc.c b/src/misc.c +index 2fd5280..c7d51b2 100644 +--- a/src/misc.c ++++ b/src/misc.c +@@ -229,11 +229,12 @@ zap_slashes (char *name) + } + + /* Normalize FILE_NAME by removing redundant slashes and "." +- components, including redundant trailing slashes. Leave ".." +- alone, as it may be significant in the presence of symlinks and on +- platforms where "/.." != "/". Destructive version: modifies its +- argument. */ +-static void ++ components, including redundant trailing slashes. ++ Leave ".." alone, as it may be significant in the presence ++ of symlinks and on platforms where "/.." != "/". ++ ++ Destructive version: modifies its argument. */ ++void + normalize_filename_x (char *file_name) + { + char *name = file_name + FILE_SYSTEM_PREFIX_LEN (file_name); +@@ -267,8 +268,9 @@ normalize_filename_x (char *file_name) + } + + /* Normalize NAME by removing redundant slashes and "." components, +- including redundant trailing slashes. Return a normalized +- newly-allocated copy. */ ++ including redundant trailing slashes. ++ ++ Return a normalized newly-allocated copy. */ + + char * + normalize_filename (const char *name) +@@ -780,6 +782,12 @@ chdir_do (int i) + } + + const char * ++tar_dirname (void) ++{ ++ return wd[chdir_current].name; ++} ++ ++const char * + tar_getcwd (void) + { + static char *cwd; +@@ -794,8 +802,10 @@ tar_getcwd (void) + if (0 == chdir_current || !wd[chdir_current].cwd) + { + if (IS_ABSOLUTE_FILE_NAME (wd[chdir_current].name)) +- return wd[chdir_current].name; +- ++ { ++ wd[chdir_current].cwd = xstrdup (wd[chdir_current].name); ++ return wd[chdir_current].cwd; ++ } + if (!wd[0].cwd) + wd[0].cwd = cwd; + +diff --git a/src/unlink.c b/src/unlink.c +index b281636..10e0b41 100644 +--- a/src/unlink.c ++++ b/src/unlink.c +@@ -22,7 +22,9 @@ + struct deferred_unlink + { + struct deferred_unlink *next; /* Next unlink in the queue */ +- char *file_name; /* Absolute name of the file to unlink */ ++ int dir_idx; /* Directory index in wd */ ++ char *file_name; /* Name of the file to unlink, relative ++ to dir_idx */ + bool is_dir; /* True if file_name is a directory */ + off_t records_written; /* Number of records written when this + entry got added to the queue */ +@@ -68,16 +70,30 @@ static void + flush_deferred_unlinks (bool force) + { + struct deferred_unlink *p, *prev = NULL; ++ int saved_chdir = chdir_current; + + for (p = dunlink_head; p; ) + { + struct deferred_unlink *next = p->next; ++ + if (force + || records_written > p->records_written + deferred_unlink_delay) + { ++ chdir_do (p->dir_idx); + if (p->is_dir) + { +- if (unlinkat (chdir_fd, p->file_name, AT_REMOVEDIR) != 0) ++ const char *fname; ++ ++ if (p->file_name[0] == 0 || ++ strcmp (p->file_name, ".") == 0) ++ { ++ fname = tar_dirname (); ++ chdir_do (p->dir_idx - 1); ++ } ++ else ++ fname = p->file_name; ++ ++ if (unlinkat (chdir_fd, fname, AT_REMOVEDIR) != 0) + { + switch (errno) + { +@@ -95,7 +111,7 @@ flush_deferred_unlinks (bool force) + } + /* fall through */ + default: +- rmdir_error (p->file_name); ++ rmdir_error (fname); + } + } + } +@@ -120,6 +136,7 @@ flush_deferred_unlinks (bool force) + } + if (!dunlink_head) + dunlink_tail = NULL; ++ chdir_do (saved_chdir); + } + + void +@@ -145,7 +162,9 @@ queue_deferred_unlink (const char *name, bool is_dir) + + p = dunlink_alloc (); + p->next = NULL; +- p->file_name = normalize_filename (name); ++ p->dir_idx = chdir_current; ++ p->file_name = xstrdup (name); ++ normalize_filename_x (p->file_name); + p->is_dir = is_dir; + p->records_written = records_written; + +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 1d10360..29ebab1 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -144,6 +144,7 @@ TESTSUITE_AT = \ + remfiles05.at\ + remfiles06.at\ + remfiles07.at\ ++ remfiles08.at\ + same-order01.at\ + same-order02.at\ + shortfile.at\ +diff --git a/tests/remfiles06.at b/tests/remfiles06.at +index 75ddcfa..c2d9876 100644 +--- a/tests/remfiles06.at ++++ b/tests/remfiles06.at +@@ -22,8 +22,8 @@ + # References: <20130924145657.GM32256@shire.ontko.com>, + # http://lists.gnu.org/archive/html/bug-tar/2013-09/msg00045.html + +-AT_SETUP([incremental with two -C]) +-AT_KEYWORDS([incremental create remove-files remfiles06]) ++AT_SETUP([remove with two -C]) ++AT_KEYWORDS([remove-files remfiles06]) + + AT_TAR_CHECK([ + AT_SORT_PREREQ +diff --git a/tests/remfiles07.at b/tests/remfiles07.at +index 84ab625..742e0a1 100644 +--- a/tests/remfiles07.at ++++ b/tests/remfiles07.at +@@ -19,8 +19,8 @@ + # Reported by: Nathan Stratton Treadway + # References: <20130924185129.GO32256@shire.ontko.com> + +-AT_SETUP([incremental with -C to absolute path]) +-AT_KEYWORDS([incremental create remove-files remfiles07]) ++AT_SETUP([remove with -C to absolute path]) ++AT_KEYWORDS([create remove-files remfiles07]) + + AT_TAR_CHECK([ + AT_SORT_PREREQ +diff --git a/tests/remfiles08.at b/tests/remfiles08.at +new file mode 100644 +index 0000000..54f5de1 +--- /dev/null ++++ b/tests/remfiles08.at +@@ -0,0 +1,48 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Description: See remfiles06.at ++# Reported by: Nathan Stratton Treadway ++# References: <20130926050634.GW32256@shire.ontko.com> ++ ++AT_SETUP([remove with -C to absolute and relative paths]) ++AT_KEYWORDS([incremental create remove-files remfiles08]) ++ ++AT_TAR_CHECK([ ++mkdir foo ++mkdir bar ++echo foo/foo_file > foo/foo_file ++echo bar/bar_file > bar/bar_file ++decho A ++tar -cvf foo.tar --remove-files -C `pwd`/foo . -C ../bar . ++decho B ++], ++[0], ++[A ++./ ++./foo_file ++./ ++./bar_file ++B ++. ++./foo.tar ++], ++[A ++B ++],[],[],[gnu]) ++ ++AT_CLEANUP +diff --git a/tests/testsuite.at b/tests/testsuite.at +index 5c805e7..d468dcf 100644 +--- a/tests/testsuite.at ++++ b/tests/testsuite.at +@@ -335,6 +335,7 @@ m4_include([remfiles04.at]) + m4_include([remfiles05.at]) + m4_include([remfiles06.at]) + m4_include([remfiles07.at]) ++m4_include([remfiles08.at]) + + m4_include([sigpipe.at]) + +-- +2.9.3 + + +From 195c6f2b71f49ecc374ae01e20d7287f24501178 Mon Sep 17 00:00:00 2001 +From: Sergey Poznyakoff +Date: Fri, 27 Sep 2013 00:59:18 +0300 +Subject: [PATCH 04/11] Bugfix + +* tests/remfiles08.at: Restore missing find +--- + tests/remfiles08.at | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tests/remfiles08.at b/tests/remfiles08.at +index 54f5de1..0649e85 100644 +--- a/tests/remfiles08.at ++++ b/tests/remfiles08.at +@@ -30,6 +30,7 @@ echo bar/bar_file > bar/bar_file + decho A + tar -cvf foo.tar --remove-files -C `pwd`/foo . -C ../bar . + decho B ++find + ], + [0], + [A +-- +2.9.3 + + +From 2cce74ec554ec7fca4c3b1d2963beb6a729881fe Mon Sep 17 00:00:00 2001 +From: Sergey Poznyakoff +Date: Tue, 1 Oct 2013 21:48:30 +0300 +Subject: [PATCH 05/11] Revamp tar_getcwd/normalize_filename stuff. + +The changes are based on the discussion with Nathan. + +* src/common.h (normalize_filename): Take two arguments. All +callers updated. +(tar_getcwd): Replaced with .. +(tar_getcdpath): New proto. +* src/misc.c (normalize_filename): Take two arguments. +(chdir_arg): Populate cwd along with creating the +structure. +(tar_getcwd): Removed. +(tar_getcdpath): New function. + +* tests/incr09.at: New test case. +* tests/Makefile.am: Add new tests. +* tests/testsuite.at: Likewise. +--- + src/common.h | 4 ++-- + src/incremen.c | 4 ++-- + src/misc.c | 48 ++++++++++++++++---------------------------- + src/names.c | 6 ++---- + tests/Makefile.am | 1 + + tests/incr09.at | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + tests/testsuite.at | 1 + + 7 files changed, 84 insertions(+), 39 deletions(-) + create mode 100644 tests/incr09.at + +diff --git a/src/common.h b/src/common.h +index 7d64227..16b501b 100644 +--- a/src/common.h ++++ b/src/common.h +@@ -595,7 +595,7 @@ void skip_member (void); + void assign_string (char **dest, const char *src); + int unquote_string (char *str); + char *zap_slashes (char *name); +-char *normalize_filename (const char *name); ++char *normalize_filename (int cdidx, const char *name); + void normalize_filename_x (char *name); + void replace_prefix (char **pname, const char *samp, size_t slen, + const char *repl, size_t rlen); +@@ -607,7 +607,7 @@ char *namebuf_name (namebuf_t buf, const char *name); + void namebuf_add_dir (namebuf_t buf, const char *name); + char *namebuf_finish (namebuf_t buf); + +-const char *tar_getcwd (void); ++const char *tar_getcdpath (int); + const char *tar_dirname (void); + + void code_ns_fraction (int ns, char *p); +diff --git a/src/incremen.c b/src/incremen.c +index b2ab5bf..cb12bbc 100644 +--- a/src/incremen.c ++++ b/src/incremen.c +@@ -279,7 +279,7 @@ free_directory (struct directory *dir) + static struct directory * + attach_directory (const char *name) + { +- char *cname = normalize_filename (name); ++ char *cname = normalize_filename (chdir_current, name); + struct directory *dir = make_directory (name, cname); + if (dirtail) + dirtail->next = dir; +@@ -350,7 +350,7 @@ find_directory (const char *name) + return 0; + else + { +- char *caname = normalize_filename (name); ++ char *caname = normalize_filename (chdir_current, name); + struct directory *dir = make_directory (name, caname); + struct directory *ret = hash_lookup (directory_table, dir); + free_directory (dir); +diff --git a/src/misc.c b/src/misc.c +index c7d51b2..280f85c 100644 +--- a/src/misc.c ++++ b/src/misc.c +@@ -273,7 +273,7 @@ normalize_filename_x (char *file_name) + Return a normalized newly-allocated copy. */ + + char * +-normalize_filename (const char *name) ++normalize_filename (int cdidx, const char *name) + { + char *copy = NULL; + +@@ -285,7 +285,7 @@ normalize_filename (const char *name) + getcwd is slow, it might fail, and it does not necessarily + return a canonical name even when it succeeds. Perhaps we + can use dev+ino pairs instead of names? */ +- const char *cwd = tar_getcwd (); ++ const char *cwd = tar_getcdpath (cdidx); + size_t copylen; + bool need_separator; + +@@ -689,7 +689,7 @@ chdir_arg (char const *dir) + if (! wd_count) + { + wd[wd_count].name = "."; +- wd[wd_count].cwd = NULL; ++ wd[wd_count].cwd = xgetcwd (); + wd[wd_count].fd = AT_FDCWD; + wd_count++; + } +@@ -707,7 +707,14 @@ chdir_arg (char const *dir) + } + + wd[wd_count].name = dir; +- wd[wd_count].cwd = NULL; ++ if (IS_ABSOLUTE_FILE_NAME (wd[wd_count].name)) ++ wd[wd_count].cwd = xstrdup (wd[wd_count].name); ++ else ++ { ++ namebuf_t nbuf = namebuf_create (wd[wd_count - 1].cwd); ++ namebuf_add_dir (nbuf, wd[wd_count].name); ++ wd[wd_count].cwd = namebuf_finish (nbuf); ++ } + wd[wd_count].fd = 0; + return wd_count++; + } +@@ -788,37 +795,16 @@ tar_dirname (void) + } + + const char * +-tar_getcwd (void) ++tar_getcdpath (int idx) + { +- static char *cwd; +- namebuf_t nbuf; +- int i; +- +- if (!cwd) +- cwd = xgetcwd (); + if (!wd) +- return cwd; +- +- if (0 == chdir_current || !wd[chdir_current].cwd) + { +- if (IS_ABSOLUTE_FILE_NAME (wd[chdir_current].name)) +- { +- wd[chdir_current].cwd = xstrdup (wd[chdir_current].name); +- return wd[chdir_current].cwd; +- } +- if (!wd[0].cwd) +- wd[0].cwd = cwd; +- +- for (i = chdir_current - 1; i > 0; i--) +- if (wd[i].cwd) +- break; +- +- nbuf = namebuf_create (wd[i].cwd); +- for (i++; i <= chdir_current; i++) +- namebuf_add_dir (nbuf, wd[i].name); +- wd[chdir_current].cwd = namebuf_finish (nbuf); ++ static char *cwd; ++ if (!cwd) ++ cwd = xgetcwd (); ++ return cwd; + } +- return wd[chdir_current].cwd; ++ return wd[idx].cwd; + } + + void +diff --git a/src/names.c b/src/names.c +index 8c3052f..125f0b5 100644 +--- a/src/names.c ++++ b/src/names.c +@@ -1004,13 +1004,11 @@ collect_and_sort_names (void) + namelist = merge_sort (namelist, num_names, compare_names); + + num_names = 0; +- nametab = hash_initialize (0, 0, +- name_hash, +- name_compare, NULL); ++ nametab = hash_initialize (0, 0, name_hash, name_compare, NULL); + for (name = namelist; name; name = next_name) + { + next_name = name->next; +- name->caname = normalize_filename (name->name); ++ name->caname = normalize_filename (name->change_dir, name->name); + if (prev_name) + { + struct name *p = hash_lookup (nametab, name); +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 29ebab1..b05a151 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -99,6 +99,7 @@ TESTSUITE_AT = \ + incr06.at\ + incr07.at\ + incr08.at\ ++ incr09.at\ + indexfile.at\ + ignfail.at\ + label01.at\ +diff --git a/tests/incr09.at b/tests/incr09.at +new file mode 100644 +index 0000000..b6130a6 +--- /dev/null ++++ b/tests/incr09.at +@@ -0,0 +1,59 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++AT_SETUP([incremental with alternating -C]) ++AT_KEYWORDS([incremental create incr09]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++mkdir foo bar middle ++echo foo/foo_file > foo/foo_file ++echo bar/bar_file > bar/bar_file ++echo middle/file > middle/middle_file ++decho A ++tar -cvf foo.tar --incremental -C foo . -C `pwd` middle -C bar . ++ ++rm foo.tar ++>toplevel_file ++decho B ++tar -cvf foo.tar --incremental -C foo . -C `pwd` toplevel_file -C bar . ++], ++[0], ++[A ++./ ++./ ++middle/ ++./bar_file ++./foo_file ++middle/middle_file ++B ++./ ++./ ++toplevel_file ++./bar_file ++./foo_file ++], ++[A ++tar: .: Directory is new ++tar: middle: Directory is new ++tar: .: Directory is new ++B ++tar: .: Directory is new ++tar: .: Directory is new ++],[],[],[gnu]) ++ ++AT_CLEANUP +diff --git a/tests/testsuite.at b/tests/testsuite.at +index d468dcf..a9f2ab6 100644 +--- a/tests/testsuite.at ++++ b/tests/testsuite.at +@@ -260,6 +260,7 @@ m4_include([incr04.at]) + m4_include([incr06.at]) + m4_include([incr07.at]) + m4_include([incr08.at]) ++m4_include([incr09.at]) + + m4_include([filerem01.at]) + m4_include([filerem02.at]) +-- +2.9.3 + + +From 779b02280a9561029d0e459275af3b3a59e521c3 Mon Sep 17 00:00:00 2001 +From: Sergey Poznyakoff +Date: Thu, 3 Oct 2013 22:41:04 +0300 +Subject: [PATCH 06/11] Tiny changes. + +* src/misc.c: Fix comments, rename wd.cwd to wd.abspath (Nathan Stratton +Treadway); +* src/tar.c (options): Reword description of the --starting-file and +--preserve-order options. +(decode_options): Both --starting-file and --preserve-order have meaning +only when used together with an archive reading command. (Pavel Raiskup). +--- + src/misc.c | 44 +++++++++++++++++++++++++++++--------------- + src/tar.c | 5 +++-- + 2 files changed, 32 insertions(+), 17 deletions(-) + +diff --git a/src/misc.c b/src/misc.c +index 280f85c..201ed16 100644 +--- a/src/misc.c ++++ b/src/misc.c +@@ -279,21 +279,23 @@ normalize_filename (int cdidx, const char *name) + + if (IS_RELATIVE_FILE_NAME (name)) + { +- /* Set COPY to the absolute file name if possible. ++ /* Set COPY to the absolute path for this name. + + FIXME: There should be no need to get the absolute file name. +- getcwd is slow, it might fail, and it does not necessarily +- return a canonical name even when it succeeds. Perhaps we +- can use dev+ino pairs instead of names? */ +- const char *cwd = tar_getcdpath (cdidx); ++ tar_getcdpath does not return a true "canonical" path, so ++ this following approach may lead to situations where the same ++ file or directory is processed twice under different absolute ++ paths without that duplication being detected. Perhaps we ++ should use dev+ino pairs instead of names? */ ++ const char *cdpath = tar_getcdpath (cdidx); + size_t copylen; + bool need_separator; + +- copylen = strlen (cwd); ++ copylen = strlen (cdpath); + need_separator = ! (DOUBLE_SLASH_IS_DISTINCT_ROOT +- && copylen == 2 && ISSLASH (cwd[1])); ++ && copylen == 2 && ISSLASH (cdpath[1])); + copy = xmalloc (copylen + need_separator + strlen (name) + 1); +- strcpy (copy, cwd); ++ strcpy (copy, cdpath); + copy[copylen] = DIRECTORY_SEPARATOR; + strcpy (copy + copylen + need_separator, name); + } +@@ -633,8 +635,10 @@ struct wd + { + /* The directory's name. */ + char const *name; +- /* Current working directory; initialized by tar_getcwd */ +- char *cwd; ++ /* "absolute" path representing this directory; in the contrast to ++ the real absolute pathname, it can contain /../ components (see ++ normalize_filename_x for the reason of it). */ ++ char *abspath; + /* If nonzero, the file descriptor of the directory, or AT_FDCWD if + the working directory. If zero, the directory needs to be opened + to be used. */ +@@ -689,7 +693,7 @@ chdir_arg (char const *dir) + if (! wd_count) + { + wd[wd_count].name = "."; +- wd[wd_count].cwd = xgetcwd (); ++ wd[wd_count].abspath = xgetcwd (); + wd[wd_count].fd = AT_FDCWD; + wd_count++; + } +@@ -707,13 +711,16 @@ chdir_arg (char const *dir) + } + + wd[wd_count].name = dir; ++ /* if the given name is an absolute path, then use that path ++ to represent this working directory; otherwise, construct ++ a path based on the previous -C option's absolute path */ + if (IS_ABSOLUTE_FILE_NAME (wd[wd_count].name)) +- wd[wd_count].cwd = xstrdup (wd[wd_count].name); ++ wd[wd_count].abspath = xstrdup (wd[wd_count].name); + else + { +- namebuf_t nbuf = namebuf_create (wd[wd_count - 1].cwd); ++ namebuf_t nbuf = namebuf_create (wd[wd_count - 1].abspath); + namebuf_add_dir (nbuf, wd[wd_count].name); +- wd[wd_count].cwd = namebuf_finish (nbuf); ++ wd[wd_count].abspath = namebuf_finish (nbuf); + } + wd[wd_count].fd = 0; + return wd_count++; +@@ -794,6 +801,13 @@ tar_dirname (void) + return wd[chdir_current].name; + } + ++/* Return the absolute path that represents the working ++ directory referenced by IDX. ++ ++ If wd is empty, then there were no -C options given, and ++ chdir_args() has never been called, so we simply return the ++ process's actual cwd. (Note that in this case IDX is ignored, ++ since it should always be 0.) */ + const char * + tar_getcdpath (int idx) + { +@@ -804,7 +818,7 @@ tar_getcdpath (int idx) + cwd = xgetcwd (); + return cwd; + } +- return wd[idx].cwd; ++ return wd[idx].abspath; + } + + void +diff --git a/src/tar.c b/src/tar.c +index 18277e4..d11daa1 100644 +--- a/src/tar.c ++++ b/src/tar.c +@@ -536,7 +536,8 @@ static struct argp_option options[] = { + {"no-same-permissions", NO_SAME_PERMISSIONS_OPTION, 0, 0, + N_("apply the user's umask when extracting permissions from the archive (default for ordinary users)"), GRID+1 }, + {"preserve-order", 's', 0, 0, +- N_("sort names to extract to match archive"), GRID+1 }, ++ N_("member arguments are listed in the same order as the " ++ "files in the archive"), GRID+1 }, + {"same-order", 0, 0, OPTION_ALIAS, NULL, GRID+1 }, + {"preserve", PRESERVE_OPTION, 0, 0, + N_("same as both -p and -s"), GRID+1 }, +@@ -730,7 +731,7 @@ static struct argp_option options[] = { + {"hard-dereference", HARD_DEREFERENCE_OPTION, 0, 0, + N_("follow hard links; archive and dump the files they refer to"), GRID+1 }, + {"starting-file", 'K', N_("MEMBER-NAME"), 0, +- N_("begin at member MEMBER-NAME in the archive"), GRID+1 }, ++ N_("begin at member MEMBER-NAME when reading the archive"), GRID+1 }, + {"newer", 'N', N_("DATE-OR-FILE"), 0, + N_("only store files newer than DATE-OR-FILE"), GRID+1 }, + {"after-date", 0, 0, OPTION_ALIAS, NULL, GRID+1 }, +-- +2.9.3 + + +From 79f04038e17dec01031113f4ba68f291f22012c3 Mon Sep 17 00:00:00 2001 +From: Nathan Stratton Treadway +Date: Sat, 5 Oct 2013 08:53:08 +0300 +Subject: [PATCH 07/11] Provide comprehensive testcases for various file + removal modes. + +* tests/Makefile.am: Add new testcases. +* tests/testsuite.at: Likewise. +* tests/incr09.at: Add description. +* tests/remfiles04a.at: New file. +* tests/remfiles05.at: Rename to ... +* tests/remfiles04b.at: ... this. +* tests/remfiles04.at: Rename to ... +* tests/remfiles04c.at: ... this. +* tests/remfiles05a.at: New file. +* tests/remfiles05b.at: New file. +* tests/remfiles06.at: Rename to ... +* tests/remfiles05c.at: ... this. +* tests/remfiles06a.at: New file. +* tests/remfiles06b.at: New file. +* tests/remfiles06c.at: New file. +* tests/remfiles07a.at: New file. +* tests/remfiles07b.at: New file. +* tests/remfiles07c.at: New file. +* tests/remfiles08a.at: New file. +* tests/remfiles08b.at: New file. +* tests/remfiles08c.at: New file. +* tests/remfiles08.at: Rename to ... +* tests/remfiles09a.at: ... this. +* tests/remfiles09b.at: New file. +* tests/remfiles07.at: Rename to ... +* tests/remfiles09c.at: ... this. +--- + tests/Makefile.am | 23 ++++++++--- + tests/incr09.at | 8 ++++ + tests/remfiles04a.at | 45 ++++++++++++++++++++++ + tests/remfiles04b.at | 53 +++++++++++++++++++++++++ + tests/{remfiles04.at => remfiles04c.at} | 21 +++++++--- + tests/remfiles05a.at | 64 +++++++++++++++++++++++++++++++ + tests/remfiles05b.at | 55 ++++++++++++++++++++++++++ + tests/{remfiles05.at => remfiles05c.at} | 35 ++++++++++------- + tests/remfiles06.at | 65 ------------------------------- + tests/remfiles06a.at | 56 +++++++++++++++++++++++++++ + tests/remfiles06b.at | 56 +++++++++++++++++++++++++++ + tests/remfiles06c.at | 68 +++++++++++++++++++++++++++++++++ + tests/remfiles07a.at | 56 +++++++++++++++++++++++++++ + tests/remfiles07b.at | 56 +++++++++++++++++++++++++++ + tests/remfiles07c.at | 68 +++++++++++++++++++++++++++++++++ + tests/remfiles08a.at | 56 +++++++++++++++++++++++++++ + tests/remfiles08b.at | 56 +++++++++++++++++++++++++++ + tests/remfiles08c.at | 68 +++++++++++++++++++++++++++++++++ + tests/{remfiles08.at => remfiles09a.at} | 27 +++++++------ + tests/remfiles09b.at | 57 +++++++++++++++++++++++++++ + tests/{remfiles07.at => remfiles09c.at} | 37 ++++++++---------- + tests/testsuite.at | 23 ++++++++--- + 22 files changed, 923 insertions(+), 130 deletions(-) + create mode 100644 tests/remfiles04a.at + create mode 100644 tests/remfiles04b.at + rename tests/{remfiles04.at => remfiles04c.at} (69%) + create mode 100644 tests/remfiles05a.at + create mode 100644 tests/remfiles05b.at + rename tests/{remfiles05.at => remfiles05c.at} (63%) + create mode 100644 tests/remfiles06a.at + create mode 100644 tests/remfiles06b.at + create mode 100644 tests/remfiles06c.at + create mode 100644 tests/remfiles07a.at + create mode 100644 tests/remfiles07b.at + create mode 100644 tests/remfiles07c.at + create mode 100644 tests/remfiles08a.at + create mode 100644 tests/remfiles08b.at + create mode 100644 tests/remfiles08c.at + rename tests/{remfiles08.at => remfiles09a.at} (66%) + create mode 100644 tests/remfiles09b.at + rename tests/{remfiles07.at => remfiles09c.at} (68%) + +diff --git a/tests/Makefile.am b/tests/Makefile.am +index b05a151..cf6f576 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -141,11 +141,24 @@ TESTSUITE_AT = \ + remfiles01.at\ + remfiles02.at\ + remfiles03.at\ +- remfiles04.at\ +- remfiles05.at\ +- remfiles06.at\ +- remfiles07.at\ +- remfiles08.at\ ++ remfiles04a.at\ ++ remfiles04b.at\ ++ remfiles04c.at\ ++ remfiles05a.at\ ++ remfiles05b.at\ ++ remfiles05c.at\ ++ remfiles06a.at\ ++ remfiles06b.at\ ++ remfiles06c.at\ ++ remfiles07a.at\ ++ remfiles07b.at\ ++ remfiles07c.at\ ++ remfiles08a.at\ ++ remfiles08b.at\ ++ remfiles08c.at\ ++ remfiles09a.at\ ++ remfiles09b.at\ ++ remfiles09c.at\ + same-order01.at\ + same-order02.at\ + shortfile.at\ +diff --git a/tests/incr09.at b/tests/incr09.at +index b6130a6..e91fb5a 100644 +--- a/tests/incr09.at ++++ b/tests/incr09.at +@@ -15,6 +15,14 @@ + # You should have received a copy of the GNU General Public License + # along with this program. If not, see . + ++# Description: For some intermediate versions of tar 1.26.90, ++# tar would fail to correctly cannonicalize archive member names ++# in incremental mode if there was a -C options with an absolute path ++# on the command line without any archive members specified within that ++# directory. (In that case, the canonical name generated for ++# members specified after later -C options wouldn't correctly reflect the ++# previous absolute path.) ++ + AT_SETUP([incremental with alternating -C]) + AT_KEYWORDS([incremental create incr09]) + +diff --git a/tests/remfiles04a.at b/tests/remfiles04a.at +new file mode 100644 +index 0000000..d1e4614 +--- /dev/null ++++ b/tests/remfiles04a.at +@@ -0,0 +1,45 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Description: ensure tar correctly respects -C option when deleting ++# files due to the --remove-files option. ++# ++# This case checks the use of a single relative-path -C option, ++# in --create/non-incremental mode. ++# ++ ++AT_SETUP([remove-files with -C:rel in -c/non-incr. mode]) ++AT_KEYWORDS([create remove-files remfiles04 remfiles04a]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++mkdir foo ++echo bar > bar ++echo foobar > foo/bar ++tar -cf foo.tar --remove-files -C foo bar ++echo A ++find . | sort ++], ++[0], ++[A ++. ++./bar ++./foo ++./foo.tar ++],[],[],[],[gnu]) ++ ++AT_CLEANUP +diff --git a/tests/remfiles04b.at b/tests/remfiles04b.at +new file mode 100644 +index 0000000..3208557 +--- /dev/null ++++ b/tests/remfiles04b.at +@@ -0,0 +1,53 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Description: ensure tar correctly respects -C option when deleting ++# files due to the --remove-files option. ++# ++# This case checks the use of a single relative-path -C option, ++# in --create/incremental mode. ++# ++# (Tar 1.26 would remove files in original working directory when called in ++# this manner. [It would follow the -C for archiving the files, but ignore it ++# for removing them afterwards.] ++# ++# Reported by: Nathan Stratton Treadway ++# References: <20130921171234.GG32256@shire.ontko.com>, ++# http://lists.gnu.org/archive/html/bug-tar/2013-09/msg00028.html ++# ) ++ ++AT_SETUP([remove-files with -C:rel in -c/incr. mode]) ++AT_KEYWORDS([create incremental remove-files remfiles04 remfiles04b]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++mkdir foo ++echo bar > bar ++echo foobar > foo/bar ++tar -cf foo.tar --incremental --remove-files -C foo bar ++echo A ++find . | sort ++], ++[0], ++[A ++. ++./bar ++./foo ++./foo.tar ++],[],[],[],[gnu]) ++ ++AT_CLEANUP +diff --git a/tests/remfiles04.at b/tests/remfiles04c.at +similarity index 69% +rename from tests/remfiles04.at +rename to tests/remfiles04c.at +index 04df45b..a1b6d56 100644 +--- a/tests/remfiles04.at ++++ b/tests/remfiles04c.at +@@ -15,24 +15,32 @@ + # You should have received a copy of the GNU General Public License + # along with this program. If not, see . + +-# Description: Tar 1.26 would remove wrong files when called with +-# --remove-files and -C ++# Description: ensure tar correctly respects -C option when deleting ++# files due to the --remove-files option. ++# ++# This case checks the use of a single relative-path -C option, ++# in --append mode. ++# ++# (Tar 1.26 would remove files in original working directory when called in ++# this manner. [It would follow the -C for archiving the files, but ignore it ++# for removing them afterwards.] ++# + # Reported by: Jörgen Strand + # References: <9FC79E5CB90CEC47B9647DCAB7BD327A01AD83B452EE@seldmbx02.corpusers.net> + # http://lists.gnu.org/archive/html/bug-tar/2013-09/msg00024.html ++# ) + +-AT_SETUP([remove-files with -C]) +-AT_KEYWORDS([create remove-files remfiles04]) ++AT_SETUP([remove-files with -C:rel in -r mode]) ++AT_KEYWORDS([create append remove-files remfiles04 remfiles04c]) + + AT_TAR_CHECK([ + AT_SORT_PREREQ + mkdir foo + echo bar > bar + echo foobar > foo/bar +-tar -cf foo.tar --remove-files -C foo bar ++tar -cf foo.tar -C foo bar + echo A + find . | sort +-echo foobar > foo/bar + tar -rf foo.tar --remove-files -C foo bar + echo B + find . | sort +@@ -43,6 +51,7 @@ find . | sort + ./bar + ./foo + ./foo.tar ++./foo/bar + B + . + ./bar +diff --git a/tests/remfiles05a.at b/tests/remfiles05a.at +new file mode 100644 +index 0000000..4ceec37 +--- /dev/null ++++ b/tests/remfiles05a.at +@@ -0,0 +1,64 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Description: ensure tar correctly respects -C option when deleting ++# files due to the --remove-files option. ++# ++# This case checks the use of two relative-path -C options, ++# in --create/non-incremental mode. ++# ++# (This specific case failed during development of tar 1.26.90: ++# There was a leftover call to chdir in name_next_elt() in ++# tar 1.26. After commit e3d28d84 this call would confuse the ++# tar_getcwd function. ++# ++# Reported by: Nathan Stratton Treadway ++# References: <20130924145657.GM32256@shire.ontko.com>, ++# http://lists.gnu.org/archive/html/bug-tar/2013-09/msg00045.html ++# ) ++ ++AT_SETUP([remove-files with -C:rel,rel in -c/non-incr. mode]) ++AT_KEYWORDS([create remove-files remfiles05 remfiles05a]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++mkdir foo ++mkdir bar ++echo file > file ++echo foo/file > foo/file ++echo bar/file > bar/file ++decho A ++tar -cvf foo.tar --remove-files -C foo file -C ../bar file ++decho B ++find . | sort ++], ++[0], ++[A ++file ++file ++B ++. ++./bar ++./file ++./foo ++./foo.tar ++], ++[A ++B ++],[],[],[gnu]) ++ ++AT_CLEANUP +diff --git a/tests/remfiles05b.at b/tests/remfiles05b.at +new file mode 100644 +index 0000000..d120efd +--- /dev/null ++++ b/tests/remfiles05b.at +@@ -0,0 +1,55 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Description: ensure tar correctly respects -C option when deleting ++# files due to the --remove-files option. ++# ++# This case checks the use of two relative-path -C options, ++# in --create/incremental mode. ++# ++ ++AT_SETUP([remove-files with -C:rel,rel in -c/incr. mode]) ++AT_KEYWORDS([create incremental remove-files remfiles05 remfiles05b]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++mkdir foo ++mkdir bar ++echo file > file ++echo foo/file > foo/file ++echo bar/file > bar/file ++decho A ++tar -cvf foo.tar --incremental --remove-files -C foo file -C ../bar file ++decho B ++find . | sort ++], ++[0], ++[A ++file ++file ++B ++. ++./bar ++./file ++./foo ++./foo.tar ++], ++[A ++B ++],[],[],[gnu]) ++ ++AT_CLEANUP +diff --git a/tests/remfiles05.at b/tests/remfiles05c.at +similarity index 63% +rename from tests/remfiles05.at +rename to tests/remfiles05c.at +index 04425a7..a01b092 100644 +--- a/tests/remfiles05.at ++++ b/tests/remfiles05c.at +@@ -15,25 +15,28 @@ + # You should have received a copy of the GNU General Public License + # along with this program. If not, see . + +-# Description: Tar 1.26 would remove wrong files when invoked with +-# --listed-incremental and -C +-# Reported by: Nathan Stratton Treadway +-# References: <20130921171234.GG32256@shire.ontko.com>, +-# http://lists.gnu.org/archive/html/bug-tar/2013-09/msg00028.html ++# Description: ensure tar correctly respects -C option when deleting ++# files due to the --remove-files option. ++# ++# This case checks the use of two relative-path -C options, ++# in --append mode. ++# + +-AT_SETUP([incremental and -C]) +-AT_KEYWORDS([incremental create remove-files remfiles05]) ++AT_SETUP([remove-files with -C:rel,rel in -r mode]) ++AT_KEYWORDS([create append remove-files remfiles05 remfiles05c]) + + AT_TAR_CHECK([ + AT_SORT_PREREQ + mkdir foo +-echo bar > bar +-echo foo/bar > foo/bar ++mkdir bar ++echo file > file ++echo foo/file > foo/file ++echo bar/file > bar/file ++tar -cf foo.tar -C foo file -C ../bar file + decho A + find . | sort +- + decho B +-tar -cvf foo.tar --listed-incremental=foo.snar --remove-files -C foo bar ++tar -rvf foo.tar --remove-files -C foo file -C ../bar file + decho C + find . | sort + ], +@@ -41,15 +44,19 @@ find . | sort + [A + . + ./bar ++./bar/file ++./file + ./foo +-./foo/bar ++./foo.tar ++./foo/file + B +-bar ++file ++file + C + . + ./bar ++./file + ./foo +-./foo.snar + ./foo.tar + ], + [A +diff --git a/tests/remfiles06.at b/tests/remfiles06.at +deleted file mode 100644 +index c2d9876..8b13789 +--- a/tests/remfiles06.at ++++ /dev/null +@@ -1,66 +0,0 @@ +-# Process this file with autom4te to create testsuite. -*- Autotest -*- +-# Test suite for GNU tar. +-# Copyright 2013 Free Software Foundation, Inc. +-# +-# GNU tar is free software; you can redistribute it and/or modify +-# it under the terms of the GNU General Public License as published by +-# the Free Software Foundation; either version 3 of the License, or +-# (at your option) any later version. +-# +-# GNU tar is distributed in the hope that it will be useful, +-# but WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-# GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License +-# along with this program. If not, see . +- +-# Description: There was a leftover call to chdir in name_next_elt() in +-# tar 1.26. After commit e3d28d84 this call would confuse the tar_getcwd +-# function. +-# Reported by: Nathan Stratton Treadway +-# References: <20130924145657.GM32256@shire.ontko.com>, +-# http://lists.gnu.org/archive/html/bug-tar/2013-09/msg00045.html +- +-AT_SETUP([remove with two -C]) +-AT_KEYWORDS([remove-files remfiles06]) +- +-AT_TAR_CHECK([ +-AT_SORT_PREREQ +-mkdir tartest +-cd tartest +-mkdir foo +-echo foo/file > foo/file +-mkdir bar +-echo bar/file > bar/file +-decho A +-find|sort +- +-decho B +-tar -cvf ../foo.tar --remove-files -C foo file -C ../bar file +- +-decho C +-find|sort +-], +-[0], +-[A +-. +-./bar +-./bar/file +-./foo +-./foo/file +-B +-file +-file +-C +-. +-./bar +-./foo +-], +-[A +-B +-C +-],[],[],[gnu]) +- +-AT_CLEANUP +- +diff --git a/tests/remfiles06a.at b/tests/remfiles06a.at +new file mode 100644 +index 0000000..fe762c1 +--- /dev/null ++++ b/tests/remfiles06a.at +@@ -0,0 +1,56 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Description: ensure tar correctly respects -C option when deleting ++# files due to the --remove-files option. ++# ++# This case checks the use of a relative -C option followed by an absolute -C, ++# in --create/non-incremental mode. ++# ++ ++AT_SETUP([remove-files with -C:rel,abs in -c/non-incr. mode]) ++AT_KEYWORDS([create remove-files remfiles06 remfiles06a]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++mkdir foo ++mkdir bar ++echo file > file ++echo foo/file > foo/file ++echo bar/file > bar/file ++DIR=`pwd` ++decho A ++tar -cvf foo.tar --remove-files -C foo file -C $DIR/bar file ++decho B ++find . | sort ++], ++[0], ++[A ++file ++file ++B ++. ++./bar ++./file ++./foo ++./foo.tar ++], ++[A ++B ++],[],[],[gnu]) ++ ++AT_CLEANUP +diff --git a/tests/remfiles06b.at b/tests/remfiles06b.at +new file mode 100644 +index 0000000..3b867fb +--- /dev/null ++++ b/tests/remfiles06b.at +@@ -0,0 +1,56 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Description: ensure tar correctly respects -C option when deleting ++# files due to the --remove-files option. ++# ++# This case checks the use of a relative -C option followed by an absolute -C, ++# in --create/incremental mode. ++# ++ ++AT_SETUP([remove-files with -C:rel,abs in -c/incr. mode]) ++AT_KEYWORDS([create incremental remove-files remfiles06 remfiles06b]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++mkdir foo ++mkdir bar ++echo file > file ++echo foo/file > foo/file ++echo bar/file > bar/file ++DIR=`pwd` ++decho A ++tar -cvf foo.tar --incremental --remove-files -C foo file -C $DIR/bar file ++decho B ++find . | sort ++], ++[0], ++[A ++file ++file ++B ++. ++./bar ++./file ++./foo ++./foo.tar ++], ++[A ++B ++],[],[],[gnu]) ++ ++AT_CLEANUP +diff --git a/tests/remfiles06c.at b/tests/remfiles06c.at +new file mode 100644 +index 0000000..ad9164d +--- /dev/null ++++ b/tests/remfiles06c.at +@@ -0,0 +1,68 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Description: ensure tar correctly respects -C option when deleting ++# files due to the --remove-files option. ++# ++# This case checks the use of a relative -C option followed by an absolute -C, ++# in --append mode. ++# ++ ++AT_SETUP([remove-files with -C:rel,abs in -r mode]) ++AT_KEYWORDS([create append remove-files remfiles06 remfiles06c]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++mkdir foo ++mkdir bar ++echo file > file ++echo foo/file > foo/file ++echo bar/file > bar/file ++DIR=`pwd` ++tar -cf foo.tar -C foo file -C $DIR/bar file ++decho A ++find . | sort ++decho B ++tar -rvf foo.tar --remove-files -C foo file -C ../bar file ++decho C ++find . | sort ++], ++[0], ++[A ++. ++./bar ++./bar/file ++./file ++./foo ++./foo.tar ++./foo/file ++B ++file ++file ++C ++. ++./bar ++./file ++./foo ++./foo.tar ++], ++[A ++B ++C ++],[],[],[gnu]) ++ ++AT_CLEANUP +diff --git a/tests/remfiles07a.at b/tests/remfiles07a.at +new file mode 100644 +index 0000000..95f645c +--- /dev/null ++++ b/tests/remfiles07a.at +@@ -0,0 +1,56 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Description: ensure tar correctly respects -C option when deleting ++# files due to the --remove-files option. ++# ++# This case checks the use of a relative -C option followed by an absolute -C, ++# in --create/non-incremental mode. ++# ++ ++AT_SETUP([remove-files with -C:rel,abs in -c/non-incr. mode]) ++AT_KEYWORDS([create remove-files remfiles07 remfiles07a]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++mkdir foo ++mkdir bar ++echo file > file ++echo foo/file > foo/file ++echo bar/file > bar/file ++DIR=`pwd` ++decho A ++tar -cvf foo.tar --remove-files -C foo file -C $DIR/bar file ++decho B ++find . | sort ++], ++[0], ++[A ++file ++file ++B ++. ++./bar ++./file ++./foo ++./foo.tar ++], ++[A ++B ++],[],[],[gnu]) ++ ++AT_CLEANUP +diff --git a/tests/remfiles07b.at b/tests/remfiles07b.at +new file mode 100644 +index 0000000..ca67e5d +--- /dev/null ++++ b/tests/remfiles07b.at +@@ -0,0 +1,56 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Description: ensure tar correctly respects -C option when deleting ++# files due to the --remove-files option. ++# ++# This case checks the use of a relative -C option followed by an absolute -C, ++# in --create/incremental mode. ++# ++ ++AT_SETUP([remove-files with -C:rel,abs in -c/incr. mode]) ++AT_KEYWORDS([create incremental remove-files remfiles07 remfiles07b]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++mkdir foo ++mkdir bar ++echo file > file ++echo foo/file > foo/file ++echo bar/file > bar/file ++DIR=`pwd` ++decho A ++tar -cvf foo.tar --incremental --remove-files -C foo file -C $DIR/bar file ++decho B ++find . | sort ++], ++[0], ++[A ++file ++file ++B ++. ++./bar ++./file ++./foo ++./foo.tar ++], ++[A ++B ++],[],[],[gnu]) ++ ++AT_CLEANUP +diff --git a/tests/remfiles07c.at b/tests/remfiles07c.at +new file mode 100644 +index 0000000..6a5c870 +--- /dev/null ++++ b/tests/remfiles07c.at +@@ -0,0 +1,68 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Description: ensure tar correctly respects -C option when deleting ++# files due to the --remove-files option. ++# ++# This case checks the use of a relative -C option followed by an absolute -C, ++# in --append mode. ++# ++ ++AT_SETUP([remove-files with -C:rel,abs in -r mode]) ++AT_KEYWORDS([create append remove-files remfiles07 remfiles07c]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++mkdir foo ++mkdir bar ++echo file > file ++echo foo/file > foo/file ++echo bar/file > bar/file ++DIR=`pwd` ++tar -cf foo.tar -C foo file -C $DIR/bar file ++decho A ++find . | sort ++decho B ++tar -rvf foo.tar --remove-files -C foo file -C $DIR/bar file ++decho C ++find . | sort ++], ++[0], ++[A ++. ++./bar ++./bar/file ++./file ++./foo ++./foo.tar ++./foo/file ++B ++file ++file ++C ++. ++./bar ++./file ++./foo ++./foo.tar ++], ++[A ++B ++C ++],[],[],[gnu]) ++ ++AT_CLEANUP +diff --git a/tests/remfiles08a.at b/tests/remfiles08a.at +new file mode 100644 +index 0000000..eadf149 +--- /dev/null ++++ b/tests/remfiles08a.at +@@ -0,0 +1,56 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Description: ensure tar correctly respects -C option when deleting ++# files due to the --remove-files option. ++# ++# This case checks the use of an absolute -C option followed by a relative -C, ++# in --create/non-incremental mode. ++# ++ ++AT_SETUP([remove-files with -C:abs,rel in -c/non-incr. mode]) ++AT_KEYWORDS([create remove-files remfiles08 remfiles08a]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++mkdir foo ++mkdir bar ++echo file > file ++echo foo/file > foo/file ++echo bar/file > bar/file ++DIR=`pwd` ++decho A ++tar -cvf foo.tar --remove-files -C $DIR/foo file -C ../bar file ++decho B ++find . | sort ++], ++[0], ++[A ++file ++file ++B ++. ++./bar ++./file ++./foo ++./foo.tar ++], ++[A ++B ++],[],[],[gnu]) ++ ++AT_CLEANUP +diff --git a/tests/remfiles08b.at b/tests/remfiles08b.at +new file mode 100644 +index 0000000..9faf2bb +--- /dev/null ++++ b/tests/remfiles08b.at +@@ -0,0 +1,56 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Description: ensure tar correctly respects -C option when deleting ++# files due to the --remove-files option. ++# ++# This case checks the use of an absolute -C option followed by a relative -C, ++# in --create/incremental mode. ++# ++ ++AT_SETUP([remove-files with -C:abs,rel in -c/incr. mode]) ++AT_KEYWORDS([create incremental remove-files remfiles08 remfiles08b]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++mkdir foo ++mkdir bar ++echo file > file ++echo foo/file > foo/file ++echo bar/file > bar/file ++DIR=`pwd` ++decho A ++tar -cvf foo.tar --incremental --remove-files -C $DIR/foo file -C ../bar file ++decho B ++find . | sort ++], ++[0], ++[A ++file ++file ++B ++. ++./bar ++./file ++./foo ++./foo.tar ++], ++[A ++B ++],[],[],[gnu]) ++ ++AT_CLEANUP +diff --git a/tests/remfiles08c.at b/tests/remfiles08c.at +new file mode 100644 +index 0000000..a220f4c +--- /dev/null ++++ b/tests/remfiles08c.at +@@ -0,0 +1,68 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Description: ensure tar correctly respects -C option when deleting ++# files due to the --remove-files option. ++# ++# This case checks the use of an absolute -C option followed by a relative -C, ++# in --append mode. ++# ++ ++AT_SETUP([remove-files with -C:abs,rel in -r mode]) ++AT_KEYWORDS([create append remove-files remfiles08 remfiles08c]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++mkdir foo ++mkdir bar ++echo file > file ++echo foo/file > foo/file ++echo bar/file > bar/file ++DIR=`pwd` ++tar -cf foo.tar -C $DIR/foo file -C ../bar file ++decho A ++find . | sort ++decho B ++tar -rvf foo.tar --remove-files -C $DIR/foo file -C ../bar file ++decho C ++find . | sort ++], ++[0], ++[A ++. ++./bar ++./bar/file ++./file ++./foo ++./foo.tar ++./foo/file ++B ++file ++file ++C ++. ++./bar ++./file ++./foo ++./foo.tar ++], ++[A ++B ++C ++],[],[],[gnu]) ++ ++AT_CLEANUP +diff --git a/tests/remfiles08.at b/tests/remfiles09a.at +similarity index 66% +rename from tests/remfiles08.at +rename to tests/remfiles09a.at +index 0649e85..fd28b4f 100644 +--- a/tests/remfiles08.at ++++ b/tests/remfiles09a.at +@@ -15,29 +15,28 @@ + # You should have received a copy of the GNU General Public License + # along with this program. If not, see . + +-# Description: See remfiles06.at +-# Reported by: Nathan Stratton Treadway +-# References: <20130926050634.GW32256@shire.ontko.com> ++# Description: check --remove-files operation when archiving/deleting ++# directory trees. ++# ++# This case checks the operation ++# in --create/non-incremental mode. ++# + +-AT_SETUP([remove with -C to absolute and relative paths]) +-AT_KEYWORDS([incremental create remove-files remfiles08]) ++AT_SETUP([remove-files on full directory in -c/non-incr. mode]) ++AT_KEYWORDS([create remove-files remfiles09 remfiles09a]) + + AT_TAR_CHECK([ + mkdir foo +-mkdir bar +-echo foo/foo_file > foo/foo_file +-echo bar/bar_file > bar/bar_file ++echo foo/file > foo/file + decho A +-tar -cvf foo.tar --remove-files -C `pwd`/foo . -C ../bar . ++tar -cvf foo.tar --remove-files foo + decho B +-find ++find . + ], + [0], + [A +-./ +-./foo_file +-./ +-./bar_file ++foo/ ++foo/file + B + . + ./foo.tar +diff --git a/tests/remfiles09b.at b/tests/remfiles09b.at +new file mode 100644 +index 0000000..30cc3ee +--- /dev/null ++++ b/tests/remfiles09b.at +@@ -0,0 +1,57 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Description: check --remove-files operation when archiving/deleting ++# directory trees. ++# ++# This case checks the operation ++# in --create/incremental mode. ++# ++# Note: in tar 1.27, when run in incremental mode tar will attempt to remove ++# the directory before removing the files within that directory, and thus ++# the --remove-files operation will cause tar to abort with an error status. ++# This issue will be fixed in a later version of tar. ++ ++AT_SETUP([remove-files on full directory in -c/incr. mode]) ++AT_KEYWORDS([create incremental remove-files remfiles09 remfiles09b]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++mkdir foo ++echo foo/file > foo/file ++decho A ++tar -cvf foo.tar --incremental --remove-files foo ++TARSTAT=$? ++decho B ++find . ++test $TARSTAT -ne 0 && AT_SKIP_TEST # we expect to fail in tar 1.27 ++], ++[0], ++[A ++foo/ ++foo/file ++B ++. ++./foo ++./foo.tar ++], ++[A ++tar: foo: Directory is new ++B ++],[],[],[gnu]) ++ ++AT_CLEANUP +diff --git a/tests/remfiles07.at b/tests/remfiles09c.at +similarity index 68% +rename from tests/remfiles07.at +rename to tests/remfiles09c.at +index 742e0a1..7241608 100644 +--- a/tests/remfiles07.at ++++ b/tests/remfiles09c.at +@@ -15,45 +15,40 @@ + # You should have received a copy of the GNU General Public License + # along with this program. If not, see . + +-# Description: See remfiles06.at +-# Reported by: Nathan Stratton Treadway +-# References: <20130924185129.GO32256@shire.ontko.com> ++# Description: check --remove-files operation when archiving/deleting ++# directory trees. ++# ++# This case checks the operation ++# in --append mode. ++# + +-AT_SETUP([remove with -C to absolute path]) +-AT_KEYWORDS([create remove-files remfiles07]) ++AT_SETUP([remove-files on full directory in -r mode]) ++AT_KEYWORDS([create append remove-files remfiles09 remfiles09c]) + + AT_TAR_CHECK([ + AT_SORT_PREREQ +-mkdir tartest +-cd tartest + mkdir foo + echo foo/file > foo/file +-mkdir bar +-echo bar/file > bar/file ++tar -cf foo.tar foo + decho A +-find|sort +- +-DIR=`pwd` ++find . | sort + decho B +-tar -cvf ../foo.tar --remove-files -C foo file -C $DIR/bar file +- ++tar -rvf foo.tar --remove-files foo + decho C +-find|sort ++find . | sort + ], + [0], + [A + . +-./bar +-./bar/file + ./foo ++./foo.tar + ./foo/file + B +-file +-file ++foo/ ++foo/file + C + . +-./bar +-./foo ++./foo.tar + ], + [A + B +diff --git a/tests/testsuite.at b/tests/testsuite.at +index a9f2ab6..1cc425f 100644 +--- a/tests/testsuite.at ++++ b/tests/testsuite.at +@@ -332,11 +332,24 @@ m4_include([grow.at]) + m4_include([remfiles01.at]) + m4_include([remfiles02.at]) + m4_include([remfiles03.at]) +-m4_include([remfiles04.at]) +-m4_include([remfiles05.at]) +-m4_include([remfiles06.at]) +-m4_include([remfiles07.at]) +-m4_include([remfiles08.at]) ++m4_include([remfiles04a.at]) ++m4_include([remfiles04b.at]) ++m4_include([remfiles04c.at]) ++m4_include([remfiles05a.at]) ++m4_include([remfiles05b.at]) ++m4_include([remfiles05c.at]) ++m4_include([remfiles06a.at]) ++m4_include([remfiles06b.at]) ++m4_include([remfiles06c.at]) ++m4_include([remfiles07a.at]) ++m4_include([remfiles07b.at]) ++m4_include([remfiles07c.at]) ++m4_include([remfiles08a.at]) ++m4_include([remfiles08b.at]) ++m4_include([remfiles08c.at]) ++m4_include([remfiles09a.at]) ++m4_include([remfiles09b.at]) ++m4_include([remfiles09c.at]) + + m4_include([sigpipe.at]) + +-- +2.9.3 + + +From c3d32c9c848f1f305cd9aefd9f485cdfbcee51b2 Mon Sep 17 00:00:00 2001 +From: Sergey Poznyakoff +Date: Sat, 5 Oct 2013 09:29:55 +0300 +Subject: [PATCH 08/11] Xfail the remfiles09b test. + +* tests/remfiles09b.at: Turn into expected failure. +--- + tests/remfiles09b.at | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tests/remfiles09b.at b/tests/remfiles09b.at +index 30cc3ee..de9b172 100644 +--- a/tests/remfiles09b.at ++++ b/tests/remfiles09b.at +@@ -29,6 +29,8 @@ + AT_SETUP([remove-files on full directory in -c/incr. mode]) + AT_KEYWORDS([create incremental remove-files remfiles09 remfiles09b]) + ++AT_XFAIL_IF(true) # we expect to fail in tar 1.27 ++ + AT_TAR_CHECK([ + AT_SORT_PREREQ + mkdir foo +@@ -38,7 +40,6 @@ tar -cvf foo.tar --incremental --remove-files foo + TARSTAT=$? + decho B + find . +-test $TARSTAT -ne 0 && AT_SKIP_TEST # we expect to fail in tar 1.27 + ], + [0], + [A +-- +2.9.3 + + +From 2c5449cc473b0a9affed02feaf3ad42e5e89bfb5 Mon Sep 17 00:00:00 2001 +From: Paul Eggert +Date: Tue, 29 Apr 2014 14:22:07 -0700 +Subject: [PATCH 09/11] tar: do not dereference NULL pointer with + '--remove-files .' + +Problem reported by Thorsten Hirsch in: +http://lists.gnu.org/archive/html/bug-tar/2014-04/msg00011.html +* src/unlink.c (flush_deferred_unlinks): +Do not attempt to find the parent of "." when "." is +at the top level. +* tests/remfiles10.at: New file. +* tests/Makefile.am (TESTSUITE_AT): +* tests/testsuite.at: Add it. +--- + src/unlink.c | 5 +++-- + tests/Makefile.am | 1 + + tests/remfiles10.at | 46 ++++++++++++++++++++++++++++++++++++++++++++++ + tests/testsuite.at | 1 + + 4 files changed, 51 insertions(+), 2 deletions(-) + create mode 100644 tests/remfiles10.at + +diff --git a/src/unlink.c b/src/unlink.c +index 10e0b41..6e41acc 100644 +--- a/src/unlink.c ++++ b/src/unlink.c +@@ -84,8 +84,9 @@ flush_deferred_unlinks (bool force) + { + const char *fname; + +- if (p->file_name[0] == 0 || +- strcmp (p->file_name, ".") == 0) ++ if (p->dir_idx ++ && (p->file_name[0] == 0 ++ || strcmp (p->file_name, ".") == 0)) + { + fname = tar_dirname (); + chdir_do (p->dir_idx - 1); +diff --git a/tests/Makefile.am b/tests/Makefile.am +index cf6f576..792c83c 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -159,6 +159,7 @@ TESTSUITE_AT = \ + remfiles09a.at\ + remfiles09b.at\ + remfiles09c.at\ ++ remfiles10.at\ + same-order01.at\ + same-order02.at\ + shortfile.at\ +diff --git a/tests/remfiles10.at b/tests/remfiles10.at +new file mode 100644 +index 0000000..b4fe139 +--- /dev/null ++++ b/tests/remfiles10.at +@@ -0,0 +1,46 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2014 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Check --remove-files with . ++ ++AT_SETUP([remove-files]) ++AT_KEYWORDS([create remove-files remfiles10]) ++ ++AT_TAR_CHECK([ ++mkdir foo ++echo foo/file > foo/file ++decho A ++(cd foo && tar -cvf ../foo.tar --remove-files .) ++tar_status=$? ++decho B ++find foo ++exit $tar_status ++], ++[2], ++[A ++./ ++./file ++B ++foo ++], ++[A ++tar: .: Cannot rmdir: Invalid argument ++tar: Exiting with failure status due to previous errors ++B ++],[],[],[gnu]) ++ ++AT_CLEANUP +diff --git a/tests/testsuite.at b/tests/testsuite.at +index 1cc425f..1078724 100644 +--- a/tests/testsuite.at ++++ b/tests/testsuite.at +@@ -350,6 +350,7 @@ m4_include([remfiles08c.at]) + m4_include([remfiles09a.at]) + m4_include([remfiles09b.at]) + m4_include([remfiles09c.at]) ++m4_include([remfiles10.at]) + + m4_include([sigpipe.at]) + +-- +2.9.3 + + +From 612e134f4905f479b78b6d7faf9798494697a742 Mon Sep 17 00:00:00 2001 +From: Nathan Stratton Treadway +Date: Sun, 27 Jul 2014 23:27:28 +0300 +Subject: [PATCH 10/11] Restructure the remfiles testsuite. + +--- + tests/remfiles06c.at | 2 +- + tests/remfiles07a.at | 6 +++--- + tests/remfiles07b.at | 6 +++--- + tests/remfiles07c.at | 8 ++++---- + tests/remfiles08a.at | 31 +++++++++++++++---------------- + tests/remfiles08b.at | 38 ++++++++++++++++++++++---------------- + tests/remfiles08c.at | 37 ++++++++++++++++++------------------- + tests/remfiles09a.at | 2 +- + tests/remfiles09b.at | 3 --- + 9 files changed, 67 insertions(+), 66 deletions(-) + +diff --git a/tests/remfiles06c.at b/tests/remfiles06c.at +index ad9164d..abb8e68 100644 +--- a/tests/remfiles06c.at ++++ b/tests/remfiles06c.at +@@ -37,7 +37,7 @@ tar -cf foo.tar -C foo file -C $DIR/bar file + decho A + find . | sort + decho B +-tar -rvf foo.tar --remove-files -C foo file -C ../bar file ++tar -rvf foo.tar --remove-files -C foo file -C $DIR/bar file + decho C + find . | sort + ], +diff --git a/tests/remfiles07a.at b/tests/remfiles07a.at +index 95f645c..5b7df3e 100644 +--- a/tests/remfiles07a.at ++++ b/tests/remfiles07a.at +@@ -18,11 +18,11 @@ + # Description: ensure tar correctly respects -C option when deleting + # files due to the --remove-files option. + # +-# This case checks the use of a relative -C option followed by an absolute -C, ++# This case checks the use of an absolute -C option followed by a relative -C, + # in --create/non-incremental mode. + # + +-AT_SETUP([remove-files with -C:rel,abs in -c/non-incr. mode]) ++AT_SETUP([remove-files with -C:abs,rel in -c/non-incr. mode]) + AT_KEYWORDS([create remove-files remfiles07 remfiles07a]) + + AT_TAR_CHECK([ +@@ -34,7 +34,7 @@ echo foo/file > foo/file + echo bar/file > bar/file + DIR=`pwd` + decho A +-tar -cvf foo.tar --remove-files -C foo file -C $DIR/bar file ++tar -cvf foo.tar --remove-files -C $DIR/foo file -C ../bar file + decho B + find . | sort + ], +diff --git a/tests/remfiles07b.at b/tests/remfiles07b.at +index ca67e5d..0147c5d 100644 +--- a/tests/remfiles07b.at ++++ b/tests/remfiles07b.at +@@ -18,11 +18,11 @@ + # Description: ensure tar correctly respects -C option when deleting + # files due to the --remove-files option. + # +-# This case checks the use of a relative -C option followed by an absolute -C, ++# This case checks the use of an absolute -C option followed by a relative -C, + # in --create/incremental mode. + # + +-AT_SETUP([remove-files with -C:rel,abs in -c/incr. mode]) ++AT_SETUP([remove-files with -C:abs,rel in -c/incr. mode]) + AT_KEYWORDS([create incremental remove-files remfiles07 remfiles07b]) + + AT_TAR_CHECK([ +@@ -34,7 +34,7 @@ echo foo/file > foo/file + echo bar/file > bar/file + DIR=`pwd` + decho A +-tar -cvf foo.tar --incremental --remove-files -C foo file -C $DIR/bar file ++tar -cvf foo.tar --incremental --remove-files -C $DIR/foo file -C ../bar file + decho B + find . | sort + ], +diff --git a/tests/remfiles07c.at b/tests/remfiles07c.at +index 6a5c870..f190539 100644 +--- a/tests/remfiles07c.at ++++ b/tests/remfiles07c.at +@@ -18,11 +18,11 @@ + # Description: ensure tar correctly respects -C option when deleting + # files due to the --remove-files option. + # +-# This case checks the use of a relative -C option followed by an absolute -C, ++# This case checks the use of an absolute -C option followed by a relative -C, + # in --append mode. + # + +-AT_SETUP([remove-files with -C:rel,abs in -r mode]) ++AT_SETUP([remove-files with -C:abs,rel in -r mode]) + AT_KEYWORDS([create append remove-files remfiles07 remfiles07c]) + + AT_TAR_CHECK([ +@@ -33,11 +33,11 @@ echo file > file + echo foo/file > foo/file + echo bar/file > bar/file + DIR=`pwd` +-tar -cf foo.tar -C foo file -C $DIR/bar file ++tar -cf foo.tar -C $DIR/foo file -C ../bar file + decho A + find . | sort + decho B +-tar -rvf foo.tar --remove-files -C foo file -C $DIR/bar file ++tar -rvf foo.tar --remove-files -C $DIR/foo file -C ../bar file + decho C + find . | sort + ], +diff --git a/tests/remfiles08a.at b/tests/remfiles08a.at +index eadf149..1ffffb2 100644 +--- a/tests/remfiles08a.at ++++ b/tests/remfiles08a.at +@@ -15,38 +15,37 @@ + # You should have received a copy of the GNU General Public License + # along with this program. If not, see . + +-# Description: ensure tar correctly respects -C option when deleting +-# files due to the --remove-files option. ++# Description: If tar 1.26 was called with the --remove-files option and told ++# to archive (and thus delete) two subdirectories where the second was ++# specified relative to the first, it would be unable to delete the ++# second directory (and its contents), since the relative path would no ++# longer be valid once the first directory was deleted. + # +-# This case checks the use of an absolute -C option followed by a relative -C, ++# This case checks for successful deletion of all archived items + # in --create/non-incremental mode. + # + +-AT_SETUP([remove-files with -C:abs,rel in -c/non-incr. mode]) ++AT_SETUP([remove-files deleting two subdirs in -c/non-incr. mode]) + AT_KEYWORDS([create remove-files remfiles08 remfiles08a]) + + AT_TAR_CHECK([ +-AT_SORT_PREREQ + mkdir foo + mkdir bar +-echo file > file +-echo foo/file > foo/file +-echo bar/file > bar/file +-DIR=`pwd` ++echo foo/foo_file > foo/foo_file ++echo bar/bar_file > bar/bar_file + decho A +-tar -cvf foo.tar --remove-files -C $DIR/foo file -C ../bar file ++tar -cvf foo.tar --remove-files -C foo . -C ../bar . + decho B +-find . | sort ++find . + ], + [0], + [A +-file +-file ++./ ++./foo_file ++./ ++./bar_file + B + . +-./bar +-./file +-./foo + ./foo.tar + ], + [A +diff --git a/tests/remfiles08b.at b/tests/remfiles08b.at +index 9faf2bb..d61c9ab 100644 +--- a/tests/remfiles08b.at ++++ b/tests/remfiles08b.at +@@ -15,41 +15,47 @@ + # You should have received a copy of the GNU General Public License + # along with this program. If not, see . + +-# Description: ensure tar correctly respects -C option when deleting +-# files due to the --remove-files option. ++# Description: If tar 1.26 was called with the --remove-files option and told ++# to archive (and thus delete) two subdirectories where the second was ++# specified relative to the first, it would be unable to delete the ++# second directory (and its contents), since the relative path would no ++# longer be valid once the first directory was deleted. + # +-# This case checks the use of an absolute -C option followed by a relative -C, ++# This case checks for successful deletion of all archived items + # in --create/incremental mode. + # ++# Note: tar 1.27 fails this test case due to a more general issue ++# archving-and-removing a full directory tree when run in incremental ++# mode; see remfiles09b.at for that specific test case. + +-AT_SETUP([remove-files with -C:abs,rel in -c/incr. mode]) ++AT_SETUP([remove-files deleting two subdirs in -c/incr. mode]) + AT_KEYWORDS([create incremental remove-files remfiles08 remfiles08b]) + ++AT_XFAIL_IF(true) # we expect to fail in tar 1.27 ++ + AT_TAR_CHECK([ +-AT_SORT_PREREQ + mkdir foo + mkdir bar +-echo file > file +-echo foo/file > foo/file +-echo bar/file > bar/file +-DIR=`pwd` ++echo foo/foo_file > foo/foo_file ++echo bar/bar_file > bar/bar_file + decho A +-tar -cvf foo.tar --incremental --remove-files -C $DIR/foo file -C ../bar file ++tar -cvf foo.tar --incremental --remove-files -C foo . -C ../bar . + decho B +-find . | sort ++find . + ], + [0], + [A +-file +-file ++./ ++./ ++./foo_file ++./bar_file + B + . +-./bar +-./file +-./foo + ./foo.tar + ], + [A ++tar: .: Directory is new ++tar: .: Directory is new + B + ],[],[],[gnu]) + +diff --git a/tests/remfiles08c.at b/tests/remfiles08c.at +index a220f4c..19b18e2 100644 +--- a/tests/remfiles08c.at ++++ b/tests/remfiles08c.at +@@ -15,49 +15,48 @@ + # You should have received a copy of the GNU General Public License + # along with this program. If not, see . + +-# Description: ensure tar correctly respects -C option when deleting +-# files due to the --remove-files option. ++# Description: If tar 1.26 was called with the --remove-files option and told ++# to archive (and thus delete) two subdirectories where the second was ++# specified relative to the first, it would be unable to delete the ++# second directory (and its contents), since the relative path would no ++# longer be valid once the first directory was deleted. + # +-# This case checks the use of an absolute -C option followed by a relative -C, ++# This case checks for successful deletion of all archived items + # in --append mode. + # + +-AT_SETUP([remove-files with -C:abs,rel in -r mode]) ++AT_SETUP([remove-files deleting two subdirs in -r mode]) + AT_KEYWORDS([create append remove-files remfiles08 remfiles08c]) + + AT_TAR_CHECK([ + AT_SORT_PREREQ + mkdir foo + mkdir bar +-echo file > file +-echo foo/file > foo/file +-echo bar/file > bar/file +-DIR=`pwd` +-tar -cf foo.tar -C $DIR/foo file -C ../bar file ++echo foo/foo_file > foo/foo_file ++echo bar/bar_file > bar/bar_file ++tar -cf foo.tar -C foo . -C ../bar . + decho A + find . | sort + decho B +-tar -rvf foo.tar --remove-files -C $DIR/foo file -C ../bar file ++tar -rvf foo.tar --remove-files -C foo . -C ../bar . + decho C +-find . | sort ++find . + ], + [0], + [A + . + ./bar +-./bar/file +-./file ++./bar/bar_file + ./foo + ./foo.tar +-./foo/file ++./foo/foo_file + B +-file +-file ++./ ++./foo_file ++./ ++./bar_file + C + . +-./bar +-./file +-./foo + ./foo.tar + ], + [A +diff --git a/tests/remfiles09a.at b/tests/remfiles09a.at +index fd28b4f..f4a3bf5 100644 +--- a/tests/remfiles09a.at ++++ b/tests/remfiles09a.at +@@ -31,7 +31,7 @@ echo foo/file > foo/file + decho A + tar -cvf foo.tar --remove-files foo + decho B +-find . ++find . + ], + [0], + [A +diff --git a/tests/remfiles09b.at b/tests/remfiles09b.at +index de9b172..e12fe32 100644 +--- a/tests/remfiles09b.at ++++ b/tests/remfiles09b.at +@@ -32,12 +32,10 @@ AT_KEYWORDS([create incremental remove-files remfiles09 remfiles09b]) + AT_XFAIL_IF(true) # we expect to fail in tar 1.27 + + AT_TAR_CHECK([ +-AT_SORT_PREREQ + mkdir foo + echo foo/file > foo/file + decho A + tar -cvf foo.tar --incremental --remove-files foo +-TARSTAT=$? + decho B + find . + ], +@@ -47,7 +45,6 @@ foo/ + foo/file + B + . +-./foo + ./foo.tar + ], + [A +-- +2.9.3 + + +From 6030b8a2589ff69d9200578e0aecc1f10aedb073 Mon Sep 17 00:00:00 2001 +From: Sergey Poznyakoff +Date: Wed, 11 Nov 2015 13:01:45 +0200 +Subject: [PATCH 11/11] Work around unlinkat bug on FreeBSD and GNU/Hurd + +* src/unlink.c (dunlink_insert): New function. +(flush_deferred_unlinks): Skip cwds and nonempty directories +at the first pass. If force is requested, run a second pass +removing them. +(queue_deferred_unlink): Make sure current working directory +entries are sorted in descending order by the value of dir_idx. +This makes sure they will be removed in right order, which works +around unlinkat bug on FreeBSD and GNU/Hurd. +* tests/remfiles08b.at: Remove expected failure. +* tests/remfiles09b.at: Likewise. +--- + src/unlink.c | 91 +++++++++++++++++++++++++++++++++++++++++----------- + tests/remfiles08b.at | 2 -- + tests/remfiles09b.at | 2 -- + 3 files changed, 72 insertions(+), 23 deletions(-) + +diff --git a/src/unlink.c b/src/unlink.c +index 6e41acc..f5fb81d 100644 +--- a/src/unlink.c ++++ b/src/unlink.c +@@ -30,6 +30,10 @@ struct deferred_unlink + entry got added to the queue */ + }; + ++#define IS_CWD(p) \ ++ ((p)->is_dir \ ++ && ((p)->file_name[0] == 0 || strcmp ((p)->file_name, ".") == 0)) ++ + /* The unlink queue */ + static struct deferred_unlink *dunlink_head, *dunlink_tail; + +@@ -59,6 +63,24 @@ dunlink_alloc (void) + } + + static void ++dunlink_insert (struct deferred_unlink *anchor, struct deferred_unlink *p) ++{ ++ if (anchor) ++ { ++ p->next = anchor->next; ++ anchor->next = p; ++ } ++ else ++ { ++ p->next = dunlink_head; ++ dunlink_head = p; ++ } ++ if (!p->next) ++ dunlink_tail = p; ++ dunlink_count++; ++} ++ ++static void + dunlink_reclaim (struct deferred_unlink *p) + { + free (p->file_name); +@@ -84,12 +106,11 @@ flush_deferred_unlinks (bool force) + { + const char *fname; + +- if (p->dir_idx +- && (p->file_name[0] == 0 +- || strcmp (p->file_name, ".") == 0)) ++ if (p->dir_idx && IS_CWD (p)) + { +- fname = tar_dirname (); +- chdir_do (p->dir_idx - 1); ++ prev = p; ++ p = next; ++ continue; + } + else + fname = p->file_name; +@@ -102,15 +123,12 @@ flush_deferred_unlinks (bool force) + /* nothing to worry about */ + break; + case ENOTEMPTY: +- if (!force) +- { +- /* Keep the record in list, in the hope we'll +- be able to remove it later */ +- prev = p; +- p = next; +- continue; +- } +- /* fall through */ ++ /* Keep the record in list, in the hope we'll ++ be able to remove it later */ ++ prev = p; ++ p = next; ++ continue; ++ + default: + rmdir_error (fname); + } +@@ -137,6 +155,34 @@ flush_deferred_unlinks (bool force) + } + if (!dunlink_head) + dunlink_tail = NULL; ++ else if (force) ++ { ++ for (p = dunlink_head; p; ) ++ { ++ struct deferred_unlink *next = p->next; ++ const char *fname; ++ ++ chdir_do (p->dir_idx); ++ if (p->dir_idx && IS_CWD (p)) ++ { ++ fname = tar_dirname (); ++ chdir_do (p->dir_idx - 1); ++ } ++ else ++ fname = p->file_name; ++ ++ if (unlinkat (chdir_fd, fname, AT_REMOVEDIR) != 0) ++ { ++ if (errno != ENOENT) ++ rmdir_error (fname); ++ } ++ dunlink_reclaim (p); ++ dunlink_count--; ++ p = next; ++ } ++ dunlink_head = dunlink_tail = NULL; ++ } ++ + chdir_do (saved_chdir); + } + +@@ -169,10 +215,17 @@ queue_deferred_unlink (const char *name, bool is_dir) + p->is_dir = is_dir; + p->records_written = records_written; + +- if (dunlink_tail) +- dunlink_tail->next = p; ++ if (IS_CWD (p)) ++ { ++ struct deferred_unlink *q, *prev; ++ for (q = dunlink_head, prev = NULL; q; prev = q, q = q->next) ++ if (IS_CWD (q) && q->dir_idx < p->dir_idx) ++ break; ++ if (q) ++ dunlink_insert (prev, p); ++ else ++ dunlink_insert (dunlink_tail, p); ++ } + else +- dunlink_head = p; +- dunlink_tail = p; +- dunlink_count++; ++ dunlink_insert (dunlink_tail, p); + } +diff --git a/tests/remfiles08b.at b/tests/remfiles08b.at +index d61c9ab..4487f83 100644 +--- a/tests/remfiles08b.at ++++ b/tests/remfiles08b.at +@@ -31,8 +31,6 @@ + AT_SETUP([remove-files deleting two subdirs in -c/incr. mode]) + AT_KEYWORDS([create incremental remove-files remfiles08 remfiles08b]) + +-AT_XFAIL_IF(true) # we expect to fail in tar 1.27 +- + AT_TAR_CHECK([ + mkdir foo + mkdir bar +diff --git a/tests/remfiles09b.at b/tests/remfiles09b.at +index e12fe32..4d05aa5 100644 +--- a/tests/remfiles09b.at ++++ b/tests/remfiles09b.at +@@ -29,8 +29,6 @@ + AT_SETUP([remove-files on full directory in -c/incr. mode]) + AT_KEYWORDS([create incremental remove-files remfiles09 remfiles09b]) + +-AT_XFAIL_IF(true) # we expect to fail in tar 1.27 +- + AT_TAR_CHECK([ + mkdir foo + echo foo/file > foo/file +-- +2.9.3 diff --git a/SOURCES/tar-1.26-docu-xattrs.patch b/SOURCES/tar-1.26-docu-xattrs.patch new file mode 100644 index 00000000..74f1f8ef --- /dev/null +++ b/SOURCES/tar-1.26-docu-xattrs.patch @@ -0,0 +1,372 @@ +diff --git a/doc/tar.texi b/doc/tar.texi +index d678db9..ab8a0c8 100644 +--- a/doc/tar.texi ++++ b/doc/tar.texi +@@ -37,7 +37,8 @@ This manual is for @acronym{GNU} @command{tar} (version + from archives. + + Copyright @copyright{} 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001, +-2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. ++2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software ++Foundation, Inc. + + @quotation + Permission is granted to copy, distribute and/or modify this document +@@ -162,6 +163,7 @@ How to Create Archives + How to List Archives + + * list dir:: ++* List Extended Attributes:: + + How to Extract Members from an Archive + +@@ -1492,6 +1494,7 @@ for a detailed discussion of globbing patterns and related + + @menu + * list dir:: ++* List Extended Attributes:: + @end menu + + @node list dir +@@ -1522,6 +1525,116 @@ drwxrwxrwx myself/user 0 1990-05-31 21:49 practice/ + When you use a directory name as a file name argument, @command{tar} acts on + all the files (including sub-directories) in that directory. + ++@node List Extended Attributes ++@unnumberedsubsec Listing xattrs, POSIX ACLs and SELinux context ++ ++From upstream GNU tar 1.26.9, tar is able to store, extract and list extended ++file attributes. Listing of those attributes is then active only in verbose and ++double-verbose mode. ++ ++This section exercises how to list attributes on examples. Lets start with ++simple verbose mode. This output is inspired by GNU @command{ls -l} command ++output. ++ ++@itemize @bullet ++@item ++Show only pure extended attributes. ++ ++@smallexample ++$ tar --xattrs --list -v archive.tar ++-rw-rwxr-- user/group 0 2012-08-08 15:15 acls.txt ++-rw-rw-r--* user/group 0 2012-08-08 15:15 xattrs.txt ++@end smallexample ++ ++Note the asterisk on the third line! It reflects the situation that the file ++'xattrs.txt' has some extended attribute set. The default mode (same as if you ++are extracting extended attributes) shows information only about extended ++attributes from 'user.*' domain. Anyway, feel free to change the sensitivity ++using @option{--xattrs-include} or @option{--xattrs-exclude} options. ++ ++@item Show only POSIX ACLs - the character you should look for is '+': ++ ++@smallexample ++$ tar --acls --list -v archive.tar ++-rw-rwxr--+ praiskup/praiskup 0 2012-08-08 15:15 acls.txt ++-rw-rw-r-- praiskup/praiskup 0 2012-08-08 15:15 xattrs.txt ++@end smallexample ++ ++@item Show only SELinux - the key character is '.': ++ ++@smallexample ++$ tar --selinux --list -v archive.tar ++-rw-rw-r--. praiskup/praiskup 0 2012-08-08 15:16 selinux_only.txt ++-rw-rw-r-- praiskup/praiskup 0 2012-08-08 15:15 xattrs.txt ++@end smallexample ++ ++@item ++Show info about ACLs, SELinux and general extended attributes together: ++ ++@smallexample ++$ tar --selinux --acls --xattrs --list -v archive.tar ++-rw-rw-r--. praiskup/praiskup 0 2012-08-08 15:16 selinux_only.txt ++-rw-rwxr--+ praiskup/praiskup 0 2012-08-08 15:15 acls.txt ++-rw-rw-r--. praiskup/praiskup 0 2012-08-08 15:15 xattrs.txt ++@end smallexample ++ ++In this case, the priority of character is '+' > '.' > '*'. You don't see the ++general extended attributes flag ('*' character) on this example because it is ++hidden by '.' (meaning that the file has SELinux context set). ++ ++@end itemize ++ ++The example of double verbose mode is here. In this output the single verbose ++characters '.', '+' and '*' are also present after the permission string. ++ ++@smallexample ++$ tar --xattrs --selinux --acls -tvvf archive.tar ++-rw-rw-r--. praiskup/praiskup 0 2012-08-08 15:16 selinux_only.txt ++ s: unconfined_u:object_r:user_tmp_t:s0 ++-rw-rwxr--+ praiskup/praiskup 0 2012-08-08 15:15 acls.txt ++ s: unconfined_u:object_r:user_tmp_t:s0 ++ a: user::rw-,user:tester:rwx,group::rw-,mask::rwx,other::r-- ++-rw-rw-r--. praiskup/praiskup 0 2012-08-08 15:15 xattrs.txt ++ s: unconfined_u:object_r:user_tmp_t:s0 ++ x: 12 user.xattr ++ x: 12 user.we_like_tar ++@end smallexample ++ ++This mode extends tar's output with additional lines beginning with ++distinguishing characters - 's' for SELinux context, 'a' for POSIX Access ++Control Lists and 'x' for generic extended attributes. ++ ++In this format, POSIX ACLs are written in SHORT TEXT FORM as specified in manual ++page @command{man 5 acl}. ++ ++Use the @option{--xattrs-include} again if you want to print other than default ++'user.*' extended attributes domain: ++ ++@smallexample ++$ tar --xattrs --xattrs-include='*' --acls --selinux -tvvf archive.tar ++-rw-rw-r--. praiskup/praiskup 0 2012-08-08 15:16 selinux_only.txt ++ s: unconfined_u:object_r:user_tmp_t:s0 ++ x: 36 security.selinux ++-rw-rwxr--+ praiskup/praiskup 0 2012-08-08 15:15 acls.txt ++ s: unconfined_u:object_r:user_tmp_t:s0 ++ a: user::rw-,user:tester:rwx,group::rw-,mask::rwx,other::r-- ++ x: 36 security.selinux ++ x: 44 system.posix_acl_access ++-rw-rw-r--. praiskup/praiskup 0 2012-08-08 15:15 xattrs.txt ++ s: unconfined_u:object_r:user_tmp_t:s0 ++ x: 36 security.selinux ++ x: 12 user.xattr ++ x: 12 user.we_like_tar ++@end smallexample ++ ++As is in @pxref{Option Summary} section described, tar by default stores all ++extended attributes that are available (not only 'user.*' domain). It means ++that the SELinux context and POSIX ACLs (because they are implemented using the ++generic extended attributes on usual file system) may be stored twice sometimes ++-- firstly in "raw" file system binary format and secondly in more portable way ++-- using appropriate system calls (invoked by @command{tar} options ++@option{--selinux} and @option{--acls}). ++ + @node extract + @section How to Extract Members from an Archive + @cindex Extraction +@@ -2371,6 +2484,10 @@ Normally when creating an archive, @command{tar} strips an initial + @samp{/} from member names. This option disables that behavior. + @xref{absolute}. + ++@opsummary{acls} ++@item --acls ++Causes @command{tar} to store/restore/list POSIX ACL's. @xref{Attributes}. ++ + @opsummary{after-date} + @item --after-date + +@@ -2919,6 +3036,11 @@ contents have changed (as opposed to just @option{--newer}, which will + also back up files for which any status information has + changed). @xref{after}. + ++@opsummary{no-acls} ++@item --no-acls ++Causes @command{tar} not to store, extract or list POSIX ACL's. ++@xref{Attributes}. ++ + @opsummary{no-anchored} + @item --no-anchored + An exclude pattern can match any subsequence of the name's components. +@@ -3002,11 +3124,20 @@ locations. Usually @command{tar} determines automatically whether + the archive can be seeked or not. Use this option to disable this + mechanism. + ++@opsummary{no-selinux} ++@item --no-selinux ++Causes @command{tar} not to store, extract or list SELinux security context. ++@xref{Attributes}. ++ + @opsummary{no-unquote} + @item --no-unquote + Treat all input file or member names literally, do not interpret + escape sequences. @xref{input name quoting}. + ++@opsummary{no-xattrs} ++@item --no-xattrs ++Causes @command{tar} not to store, extract or list xattrs. @xref{Attributes}. ++ + @opsummary{no-wildcards} + @item --no-wildcards + Do not use wildcards. +@@ -3239,6 +3370,11 @@ in cases when such recognition fails. It takes effect only if the + archive is open for reading (e.g. with @option{--list} or + @option{--extract} options). + ++@opsummary{selinux} ++@item --selinux ++Causes @command{tar} to store, extract or list SELinux security context. ++@xref{Attributes}. ++ + @opsummary{show-defaults} + @item --show-defaults + +@@ -3466,6 +3602,11 @@ Enable or disable warning messages identified by @var{keyword}. The + messages are suppressed if @var{keyword} is prefixed with @samp{no-}. + @xref{warnings}. + ++@opsummary{xattrs} ++@item --xattrs ++Causes @command{tar} to store, restore or list extended file attributes. For ++more info see @xref{Attributes}. ++ + @opsummary{wildcards} + @item --wildcards + Use wildcards when matching member names with patterns. +@@ -4218,6 +4359,11 @@ 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 xattr-write ++@item xattr-write ++@samp{%s: Cannot set '%s' extended attribute for file '%s'} ++@*@samp{%s: Cannot set POSIX ACLs for file '%s'} ++@*@samp{%s: Cannot set SELinux context for file '%s'} + @end table + + @subheading Keywords controlling incremental extraction: +@@ -8770,6 +8916,8 @@ implementation able to read @samp{ustar} archives will be able to read + most @samp{posix} archives as well, with the only exception that any + additional information (such as long file names etc.) will in such + case be extracted as plain text files along with the files it refers to. ++This is the only format that can store ACLs, SELinux context and extended ++attributes. + + This archive format will be the default format for future versions + of @GNUTAR{}. +@@ -9412,6 +9560,135 @@ Same as both @option{--same-permissions} and @option{--same-order}. + + This option is deprecated, and will be removed in @GNUTAR{} version 1.23. + ++@opindex xattrs ++@item --xattrs ++This option causes @command{tar} to store, restore or list the extended file ++attributes (for information about extended attributes see @command{man(5) ++attr}). ++ ++Note that all extended attributes are stored "as-is" (in file system binary ++format) and the resulting archive may be not fully portable. See the ++@option{--selinux} and @option{--acls} options when you want to deal with these ++types of extended attributes in a better way. ++ ++The @option{--xattrs} option implies the option @option{--format=posix} when ++tar is in @option{--create} operation mode. It is the only one format which ++hase usable headers for storing additional file information like extended ++attributes are. ++ ++By default, all extended attributes are stored into the archive. The reason is ++that we want to make the backup process as complete as possible by default. On ++the other hand, during extracting only the 'user.*' domain is extracted by ++default. Anyway, this default behaviour may be easily modified by the ++@option{--xattrs-include} and @option{--xattrs-exclude} options. ++ ++When you list an archive in verbose mode ++(@command{tar --xattrs --verbose -tf archive.tar}), tar shows the '*' character ++after the permissions string of concrete file ringht to tell you that at least ++one extended attribute is stored with corresponding file. ++ ++Double verbose mode (@command{tar --xattrs -tvvf archive.tar}) prints the ++extended attribute length (in bytes) and its ASCII key (for printed examples ++@pxref{List Extended Attributes}). ++ ++@option{--xattrs} option has no equivalent short option. ++ ++Warnings which occur during impossible writing of extended attributes to ++a file system may be suppressed using the @option{--warning=no-xattr-write} ++option. ++ ++@opindex no-xattrs ++@item --no-xattrs ++This option causes @command{tar} not to store/extract or list the current ++extended attributes. This option does not affect options @option{--no-selinux} ++or @option{--no-acls}. ++ ++The @option{--no-xattrs} option has no equivalent short option name. ++ ++@opindex xattrs-include ++@opindex xattrs-exclude ++@item --xattrs-include=MASK ++@itemx --xattrs-exclude=MASK ++ ++These options allows the xattr store/restore/list process to be more fine ++grained. The default configuration is that @option{--create} mode handles all ++available extended attributes and the @option{--extract}/@option{--list} mode ++handles only 'user.*' domain. These options may be used for editing of this ++default behaviour. ++ ++@itemize @bullet ++@item ++Lets say we want to store all attributes except some "public restricted" domain ++(e.g. 'user.restricted.*' domain. The correct way how to do it is: ++ ++@command{tar --xattrs --xattrs-include='*' --xattrs-exclude='user.restricted.*' ++-cf archive.tar FILES} ++@item ++And, when we want to extract only some specific domain from an archive - we can ++use: ++ ++@command{tar --xattrs --xattrs-include='security.capability' -xf archive.tar ++FILES} ++@end itemize ++ ++Multiple passed include/exclude patterns are combined together. The attribute ++is covered then only if (1) at least one of all include patterns matches its ++keyword and (2) no exclude pattern matches its keyword. ++ ++When only include pattern is set - exclude pattern is left in default mode (and ++vice versa). ++ ++@opindex selinux ++@item --selinux ++This option causes @command{tar} to store/extract/list the SELinux context ++information into/from an archive. Command @command{tar} is able to show info ++whether the SELinux context is present in archived file using the verbose ++listing mode (@command{tar --selinux -tvf archive.tar}). It shows the '.' ++character after permission string in that case. Double-verbose listing mode ++(@command{tar -tvvf archive.tar}) then prints the full SELinux context to ++standard output, @pxref{List Extended Attributes} for printed example. ++ ++This option implies the @option{--format=posix} when @command{tar} works in ++@option{--create} operation mode. ++ ++Warnings complaining that SELinux context may not be written to a file system ++may be suppressed by the @option{--warning=no-xattr-write} option. ++ ++The @option{--selinux} option has no equivalent short option name. ++ ++@opindex no-selinux ++@item --no-selinux ++This option causes @command{tar} not to store the current SELinux security ++context information in the archive and not to extract any SELinux information in ++an archive. ++ ++The @option{--no-selinux} option has no equivalent short option name. ++ ++@opindex acls ++@item --acls ++This option causes @command{tar} to store the current POSIX access control lists ++into the archive or restore POSIX ACLs from an archive. It also allows ++@command{tar} to show whether archived file contains ACLs when the verbose mode ++is active (@option{tar --acls -tvf} shows the symbol '+' after the permission ++characters in that case). Double-verbose mode allows @command{tar} to list ++contained POSIX ACLs (@command{tar --acls -tvvf archive.tar}), for printed ++examples @pxref{List Extended Attributes}. ++ ++This option implies the @option{--format=posix} when @command{tar} works in ++@option{--create} operation mode. ++ ++Warnings complaining that POSIX ACLs may not be written to a file system may be ++suppressed by the @option{--warning=no-xattr-write} option. ++ ++The @option{--acls} option has no equivalent short form. ++ ++@opindex no-acls ++@item --no-acls ++This option causes @command{tar} not to store the current POSIX ACL into the ++archive and not to extract any POSIX ACL information from an archive. ++ ++The @option{--no-acls} option has no equivalent short option name. ++ + @end table + + @node Portability diff --git a/SOURCES/tar-1.26-dont-segfault-with-disabled-selinux.patch b/SOURCES/tar-1.26-dont-segfault-with-disabled-selinux.patch new file mode 100644 index 00000000..139a6968 --- /dev/null +++ b/SOURCES/tar-1.26-dont-segfault-with-disabled-selinux.patch @@ -0,0 +1,31 @@ +From b6b3ed1fa4c6de12908a9f01d1689f156c3cd441 Mon Sep 17 00:00:00 2001 +From: Pavel Raiskup +Date: Wed, 1 Jul 2015 12:30:57 +0200 +Subject: [PATCH] selinux-h: avoid double free after *getfilecon() + +Originally reported by Ben Shelton on bug-tar: +http://lists.gnu.org/archive/html/bug-tar/2015-04/msg00009.html + +* lib/getfilecon.c (map_to_failure): Set the already freed '*con' +pointer to NULL. Man getfilecon(3) says that any non-NULL '*con' +parameter should be freed by freecon(3) (regardless the return +value). +--- + ChangeLog | 9 +++++++++ + lib/getfilecon.c | 1 + + 2 files changed, 10 insertions(+) + +diff --git a/lib/getfilecon.c b/lib/getfilecon.c +index 9ac69be..ef6adc8 100644 +--- a/gnu/getfilecon.c ++++ b/gnu/getfilecon.c +@@ -57,6 +57,7 @@ map_to_failure (int ret, security_context_t *con) + if (ret == 10 && strcmp (*con, "unlabeled") == 0) + { + freecon (*con); ++ *con = NULL; + errno = ENODATA; + return -1; + } +-- +2.7.4 diff --git a/SOURCES/tar-1.26-fix-symlink-eating-bug.patch b/SOURCES/tar-1.26-fix-symlink-eating-bug.patch new file mode 100644 index 00000000..11706f5e --- /dev/null +++ b/SOURCES/tar-1.26-fix-symlink-eating-bug.patch @@ -0,0 +1,91 @@ +diff --git a/gnu/stat-time.h b/gnu/stat-time.h +index 1dc4098..7b8428e 100644 +--- a/gnu/stat-time.h ++++ b/gnu/stat-time.h +@@ -144,7 +144,7 @@ get_stat_mtime (struct stat const *st) + } + + /* Return *ST's birth time, if available; otherwise return a value +- with negative tv_nsec. */ ++ with tv_sec and tv_nsec both equal to -1. */ + static inline struct timespec + get_stat_birthtime (struct stat const *st) + { +@@ -163,7 +163,7 @@ get_stat_birthtime (struct stat const *st) + t.tv_sec = st->st_ctime; + t.tv_nsec = 0; + #else +- /* Birth time is not supported. Set tv_sec to avoid undefined behavior. */ ++ /* Birth time is not supported. */ + t.tv_sec = -1; + t.tv_nsec = -1; + /* Avoid a "parameter unused" warning. */ +@@ -177,10 +177,12 @@ get_stat_birthtime (struct stat const *st) + using zero. Attempt to work around this problem. Alas, this can + report failure even for valid time stamps. Also, NetBSD + sometimes returns junk in the birth time fields; work around this +- bug if it it is detected. There's no need to detect negative +- tv_nsec junk as negative tv_nsec already indicates an error. */ +- if (t.tv_sec == 0 || 1000000000 <= t.tv_nsec) +- t.tv_nsec = -1; ++ bug if it is detected. */ ++ if (! (t.tv_sec && 0 <= t.tv_nsec && t.tv_nsec < 1000000000)) ++ { ++ t.tv_sec = -1; ++ t.tv_nsec = -1; ++ } + #endif + + return t; +diff --git a/src/extract.c b/src/extract.c +index 340beea..3afb95d 100644 +--- a/src/extract.c ++++ b/src/extract.c +@@ -119,12 +119,15 @@ struct delayed_link + /* The next delayed link in the list. */ + struct delayed_link *next; + +- /* The device, inode number and ctime of the placeholder. Use +- ctime, not mtime, to make false matches less likely if some +- other process removes the placeholder. */ ++ /* The device, inode number and birthtime of the placeholder. ++ birthtime.tv_nsec is negative if the birthtime is not available. ++ Don't use mtime as this would allow for false matches if some ++ other process removes the placeholder. Don't use ctime as ++ this would cause race conditions and other screwups, e.g., ++ when restoring hard-linked symlinks. */ + dev_t dev; + ino_t ino; +- struct timespec ctime; ++ struct timespec birthtime; + + /* True if the link is symbolic. */ + bool is_symlink; +@@ -1200,7 +1203,7 @@ create_placeholder_file (char *file_name, bool is_symlink, bool *interdir_made) + delayed_link_head = p; + p->dev = st.st_dev; + p->ino = st.st_ino; +- p->ctime = get_stat_ctime (&st); ++ p->birthtime = get_stat_birthtime (&st); + p->is_symlink = is_symlink; + if (is_symlink) + { +@@ -1265,7 +1268,8 @@ extract_link (char *file_name, int typeflag) + if (ds->change_dir == chdir_current + && ds->dev == st1.st_dev + && ds->ino == st1.st_ino +- && timespec_cmp (ds->ctime, get_stat_ctime (&st1)) == 0) ++ && (timespec_cmp (ds->birthtime, get_stat_birthtime (&st1)) ++ == 0)) + { + struct string_list *p = xmalloc (offsetof (struct string_list, string) + + strlen (file_name) + 1); +@@ -1638,7 +1642,7 @@ apply_delayed_links (void) + if (fstatat (chdir_fd, source, &st, AT_SYMLINK_NOFOLLOW) == 0 + && st.st_dev == ds->dev + && st.st_ino == ds->ino +- && timespec_cmp (get_stat_ctime (&st), ds->ctime) == 0) ++ && timespec_cmp (get_stat_birthtime (&st), ds->birthtime) == 0) + { + /* Unlink the placeholder, then create a hard link if possible, + a symbolic link otherwise. */ diff --git a/SOURCES/tar-1.26-keep-directory-symlink-doc-and-test.patch b/SOURCES/tar-1.26-keep-directory-symlink-doc-and-test.patch new file mode 100644 index 00000000..c49f8d14 --- /dev/null +++ b/SOURCES/tar-1.26-keep-directory-symlink-doc-and-test.patch @@ -0,0 +1,208 @@ +From 49b5cd11bc3d64b0316cfc5b7245d25e4f7f4fcd Mon Sep 17 00:00:00 2001 +From: Pavel Raiskup +Date: Thu, 19 Oct 2017 16:53:00 +0200 +Subject: [PATCH] test keep-directory-symlink + +Upstream commit: +From d06126f814563b01e598b85a8cc233604a2948f2 Mon Sep 17 00:00:00 2001 +From: Pavel Raiskup +Date: Tue, 28 Feb 2017 09:55:09 +0100 +Subject: [PATCH] Test and document --keep-directory-symlink + +* doc/tar.1: Document the option. +* tests/extrac20.at: New testcase. +* tests/Makefile.am: Mention extrac20. +* tests/testsuite.at: Likewise. +--- + tests/Makefile.am | 1 + + tests/extrac20.at | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + tests/testsuite.at | 2 +- + 3 files changed, 153 insertions(+), 1 deletion(-) + create mode 100644 tests/extrac20.at + +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 094b71c..bd8d3e8 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -79,6 +79,7 @@ TESTSUITE_AT = \ + extrac09.at\ + extrac18.at\ + extrac19.at\ ++ extrac20.at\ + extrac10.at\ + extrac11.at\ + extrac12.at\ +diff --git a/tests/extrac20.at b/tests/extrac20.at +new file mode 100644 +index 0000000..dd9b00d +--- /dev/null ++++ b/tests/extrac20.at +@@ -0,0 +1,151 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# ++# Test suite for GNU tar. ++# Copyright 2017 Free Software Foundation, Inc. ++ ++# This file is part of GNU tar. ++ ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++ ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++ ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++AT_SETUP([keep-directory-symlink]) ++AT_KEYWORDS([extrac20 extract old-files keep-old-files]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++ ++for i in a b c ++do ++ dir=in$i ++ mkdir -p $dir/root/dir $dir/root/dirsymlink ++ touch $dir/root/dirsymlink/file$i ++ test $i != a && touch $dir/root/dirsymlink/file.conflict ++ tar cf archive$i.tar -C $dir root ++done ++ ++prep() ++{ ++ echo "== $1 ==" ++ echo "== $1 ==" >&2 ++ backup_dir=$1 ++ dir=out ++ mkdir -p $dir/root/dir ++ ln -s dir $dir/root/dirsymlink ++ test $round = normal && cd $dir >/dev/null ++} ++ ++clean() ++{ ++ test $round = normal && cd .. >/dev/null ++ find $dir | sort ++ mv $dir $backup_dir ++} ++ ++# Expand to '-f ../$1' or '-f $1 -C $dir' depending on $round variable ++file_spec() ++{ ++ if test $round = normal ++ then ++ echo "-f ../$1" ++ else ++ echo "-f $1 -C $dir" ++ fi ++} ++ ++for round in normal dir ++do ++ # Check that 'dirsymlink' replaces 'dir' ++ prep without_option_$round ++ tar -x `file_spec archivea.tar` || exit 1 ++ tar -x `file_spec archiveb.tar` || exit 1 ++ clean ++ ++ # Keep directory symlink must keep root/dirsymlink ++ prep with_option_$round ++ tar -x --keep-directory-symlink `file_spec archivea.tar` || exit 1 ++ tar -x --keep-directory-symlink `file_spec archiveb.tar` || exit 1 ++ clean ++ ++ prep collision_$round ++ tar -x --keep-directory-symlink `file_spec archivea.tar` --keep-old-files || exit 1 ++ tar -x --keep-directory-symlink `file_spec archiveb.tar` --keep-old-files || exit 1 ++ tar -x --keep-directory-symlink `file_spec archivec.tar` --keep-old-files && exit 1 ++ clean ++done ++], ++[0], ++[== without_option_normal == ++out ++out/root ++out/root/dir ++out/root/dirsymlink ++out/root/dirsymlink/file.conflict ++out/root/dirsymlink/filea ++out/root/dirsymlink/fileb ++== with_option_normal == ++out ++out/root ++out/root/dir ++out/root/dir/file.conflict ++out/root/dir/filea ++out/root/dir/fileb ++out/root/dirsymlink ++== collision_normal == ++out ++out/root ++out/root/dir ++out/root/dir/file.conflict ++out/root/dir/filea ++out/root/dir/fileb ++out/root/dir/filec ++out/root/dirsymlink ++== without_option_dir == ++out ++out/root ++out/root/dir ++out/root/dirsymlink ++out/root/dirsymlink/file.conflict ++out/root/dirsymlink/filea ++out/root/dirsymlink/fileb ++== with_option_dir == ++out ++out/root ++out/root/dir ++out/root/dir/file.conflict ++out/root/dir/filea ++out/root/dir/fileb ++out/root/dirsymlink ++== collision_dir == ++out ++out/root ++out/root/dir ++out/root/dir/file.conflict ++out/root/dir/filea ++out/root/dir/fileb ++out/root/dir/filec ++out/root/dirsymlink ++], ++[== without_option_normal == ++== with_option_normal == ++== collision_normal == ++tar: root/dirsymlink/file.conflict: Cannot open: File exists ++tar: Exiting with failure status due to previous errors ++== without_option_dir == ++== with_option_dir == ++== collision_dir == ++tar: root/dirsymlink/file.conflict: Cannot open: File exists ++tar: Exiting with failure status due to previous errors ++]) ++ ++AT_CLEANUP ++ +diff --git a/tests/testsuite.at b/tests/testsuite.at +index f7f00ee..b540948 100644 +--- a/tests/testsuite.at ++++ b/tests/testsuite.at +@@ -234,9 +234,9 @@ m4_include([extrac14.at]) + m4_include([extrac15.at]) + m4_include([extrac16.at]) + m4_include([extrac17.at]) +- + m4_include([extrac18.at]) + m4_include([extrac19.at]) ++m4_include([extrac20.at]) + + m4_include([label01.at]) + m4_include([label02.at]) +-- +2.13.6 diff --git a/SOURCES/tar-1.26-keep-directory-symlink.patch b/SOURCES/tar-1.26-keep-directory-symlink.patch new file mode 100644 index 00000000..4d55f3eb --- /dev/null +++ b/SOURCES/tar-1.26-keep-directory-symlink.patch @@ -0,0 +1,169 @@ +From c4a4cafaa330793d776b001c272bf19869aac39c 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 | 12 ++++++++++++ + doc/tar.texi | 15 +++++++++++++++ + src/common.h | 2 ++ + src/extract.c | 19 +++++++++++++++++++ + src/tar.c | 8 ++++++++ + 5 files changed, 56 insertions(+) + +diff --git a/NEWS b/NEWS +index 8f3c416..36a27da 100644 +--- a/NEWS ++++ b/NEWS +@@ -6,6 +6,18 @@ Please send GNU tar bug reports to + When creating a PAX-format archive, tar no longer arbitrarily restricts + the size of the representation of a sparse file to be less than 8 GiB. + ++* 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 6bd59c7..fb03b85 100644 +--- a/doc/tar.texi ++++ b/doc/tar.texi +@@ -2923,6 +2923,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 + +diff --git a/src/common.h b/src/common.h +index 16ba401..274da01 100644 +--- a/src/common.h ++++ b/src/common.h +@@ -192,6 +192,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 */ +diff --git a/src/extract.c b/src/extract.c +index 3afb95d..b622a2a 100644 +--- a/src/extract.c ++++ b/src/extract.c +@@ -854,7 +854,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 +@@ -910,10 +924,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/tar.c b/src/tar.c +index 18277e4..d62ca0e 100644 +--- a/src/tar.c ++++ b/src/tar.c +@@ -290,6 +290,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, +@@ -488,6 +489,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 +@@ -1878,6 +1882,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; +-- +2.9.3 diff --git a/SOURCES/tar-1.26-large-sparse-file-listing.patch b/SOURCES/tar-1.26-large-sparse-file-listing.patch new file mode 100644 index 00000000..33336924 --- /dev/null +++ b/SOURCES/tar-1.26-large-sparse-file-listing.patch @@ -0,0 +1,389 @@ +From 77cef4ee39ee083838e5cf2137b0f344b49afb6a Mon Sep 17 00:00:00 2001 +From: Pavel Raiskup +Date: Tue, 29 Jan 2013 10:39:30 +0100 +Subject: [PATCH 1/4] Fix bug in sparse file listing + +List posix archives containing sparse files >8GB correctly and do not fail. +This fixes also bug in format of listing for sparse files >8GB - now the +real size is printed instead of the effective one (this is not strictly +posix format related). + +* src/list.c: Remove redundant assignment. +* src/tar.h: Add new 'real_size' and 'real_size_set' fields in + tar_stat_info struct. +* src/xheader.c: Correctly handle (especially sparse) file sizes directly in + xheader_decode(). +--- + src/list.c | 1 - + src/tar.h | 4 ++++ + src/xheader.c | 15 ++++++++++++++- + 3 files changed, 18 insertions(+), 2 deletions(-) + +diff --git a/src/list.c b/src/list.c +index dd501a9..6db36d1 100644 +--- a/src/list.c ++++ b/src/list.c +@@ -670,7 +670,6 @@ decode_header (union block *header, struct tar_stat_info *stat_info, + } + } + +- stat_info->archive_file_size = stat_info->stat.st_size; + xheader_decode (stat_info); + + if (sparse_member_p (stat_info)) +diff --git a/src/tar.h b/src/tar.h +index b181e58..690c146 100644 +--- a/src/tar.h ++++ b/src/tar.h +@@ -327,6 +327,10 @@ struct tar_stat_info + size_t sparse_map_size; /* Size of the sparse map */ + struct sp_array *sparse_map; + ++ off_t real_size; /* The real size of sparse file */ ++ int real_size_set; /* True when GNU.sparse.realsize is set in ++ archived file */ ++ + size_t xattr_map_size; /* Size of the xattr map */ + struct xattr_array *xattr_map; + +diff --git a/src/xheader.c b/src/xheader.c +index be793d4..708aece 100644 +--- a/src/xheader.c ++++ b/src/xheader.c +@@ -764,6 +764,16 @@ xheader_decode (struct tar_stat_info *st) + continue; + } + run_override_list (keyword_override_list, st); ++ ++ /* The archived (effective) file size is always set directly in tar header ++ field, possibly overridden by "size" extended header - in both cases, ++ result is now decoded in st->stat.st_size */ ++ st->archive_file_size = st->stat.st_size; ++ ++ /* The real file size (given by stat()) may be redefined for sparse ++ files in "GNU.sparse.realsize" extended header */ ++ if (st->real_size_set) ++ st->stat.st_size = st->real_size; + } + + static void +@@ -1438,7 +1435,10 @@ sparse_size_decoder (struct tar_stat_info *st, + { + uintmax_t u; + if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword)) +- st->stat.st_size = u; ++ { ++ st->real_size_set = 1; ++ st->real_size = u; ++ } + } + + static void +-- +2.13.5 + + +From 198d4621b2a367986c71cd2489c1465ec3be89dc Mon Sep 17 00:00:00 2001 +From: Sergey Poznyakoff +Date: Fri, 7 Nov 2014 11:47:44 +0200 +Subject: [PATCH 2/4] Add testcase for the previous commit. + +* tests/sparse05.at: New file. +* tests/Makefile.am: Add sparse05.at +* tests/testsuite.at: Include sparse05.at +--- + tests/Makefile.am | 1 + + tests/sparse05.at | 46 ++++++++++++++++++++++++++++++++++++++++++++++ + tests/testsuite.at | 1 + + 3 files changed, 48 insertions(+) + create mode 100644 tests/sparse05.at + +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 8e1ef8d..094b71c 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -171,6 +171,7 @@ TESTSUITE_AT = \ + sparse02.at\ + sparse03.at\ + sparse04.at\ ++ sparse05.at\ + sparsemv.at\ + sparsemvp.at\ + spmvp00.at\ +diff --git a/tests/sparse05.at b/tests/sparse05.at +new file mode 100644 +index 0000000..72f3274 +--- /dev/null ++++ b/tests/sparse05.at +@@ -0,0 +1,46 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# ++# Test suite for GNU tar. ++# Copyright 2014 Free Software Foundation, Inc. ++ ++# This file is part of GNU tar. ++ ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++ ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++ ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++AT_SETUP([listing sparse files bigger than 2^33 B]) ++AT_KEYWORDS([sparse sparse05]) ++ ++# Description: If an archive in POSIX.1-2001 archive contained a sparse file ++# member whose real size (excluding zero blocks) is bigger than 2^33 bytes, ++# tar 1.28 would incorrectly list the real member size. ++# Reported by: Pavel Raiskup ++# References: <1359119879.15037.4.camel@raiskup>, ++# http://lists.gnu.org/archive/html/bug-tar/2013-01/msg00001.html ++ ++AT_TAR_CHECK([ ++(echo 0 =2560 ++for i in `seq 1 999`; do ++ echo 10M =2560 ++done) | genfile --sparse --file BIGFILE --block-size 4K - || AT_SKIP_TEST ++tar -f - -c --sparse --posix BIGFILE | tar tvf - | awk '{ print $3, $(NF) }' ++], ++[0], ++[20961034240 BIGFILE ++], ++[], ++[], ++[], ++[pax]) ++ ++AT_CLEANUP +diff --git a/tests/testsuite.at b/tests/testsuite.at +index 3eb0eee..f7f00ee 100644 +--- a/tests/testsuite.at ++++ b/tests/testsuite.at +@@ -308,6 +308,7 @@ m4_include([sparse01.at]) + m4_include([sparse02.at]) + m4_include([sparse03.at]) + m4_include([sparse04.at]) ++m4_include([sparse05.at]) + m4_include([sparsemv.at]) + m4_include([spmvp00.at]) + m4_include([spmvp01.at]) +-- +2.13.5 + + +From 8a795036f08bca508c3f3425f41c566562573e5f Mon Sep 17 00:00:00 2001 +From: Sergey Poznyakoff +Date: Fri, 7 Nov 2014 11:37:33 +0200 +Subject: [PATCH 3/4] genfile: improve sparse mode + +Paxutils: 45af1632aa64a5ba1b108e248920e67c180e8485 + +* tests/genfile.c (generate_sparse_file): Handle '-' argument +(read from stdin); +If content strings starts with '=', treat it as fragment size and +use default pattern to fill it. +* doc/genfile.texi: Document changes to genfile. +--- + doc/genfile.texi | 31 +++++++++++++++------- + tests/genfile.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++------- + 2 files changed, 91 insertions(+), 19 deletions(-) + +diff --git a/doc/genfile.texi b/doc/genfile.texi +index b37e26e..b993b9b 100644 +--- a/doc/genfile.texi ++++ b/doc/genfile.texi +@@ -124,9 +124,8 @@ the rest of the command line specifies a so-called @dfn{file map}. + descriptors}. Each descriptor is composed of two values: a number, + specifying fragment offset from the end of the previous fragment or, + for the very first fragment, from the beginning of the file, and +-@dfn{contents string}, i.e., a string of characters, specifying the +-pattern to fill the fragment with. File offset can be suffixed with +-the following quantifiers: ++@dfn{contents string}, that specifies the pattern to fill the fragment ++with. File offset can be suffixed with the following quantifiers: + + @table @samp + @item k +@@ -140,17 +139,29 @@ The number is expressed in megabytes. + The number is expressed in gigabytes. + @end table + +- For each letter in contents string @command{genfile} will generate +-a @dfn{block} of data, filled with this letter and will write it to +-the fragment. The size of block is given by @option{--block-size} +-option. It defaults to 512. Thus, if the string consists of @var{n} +-characters, the resulting file fragment will contain +-@code{@var{n}*@var{block-size}} of data. ++ Contents string can be either a fragment size or a pattern. ++Fragment size is a decimal number, prefixed with an equals sign. It ++can be suffixed with a quantifier, as discussed above. If fragment ++size is given, the fragment of that size will be filled with the ++currently selected pattern (@pxref{Generate Mode, --pattern}) and ++written to the file. + +- Last fragment descriptor can have only file offset part. In this ++ A pattern is a string of arbitrary ASCII characters. For each ++of them, @command{genfile} will generate a @dfn{block} of data, ++filled with that character and will write it to the fragment. The size ++of block is given by @option{--block-size} option. It defaults to 512. ++Thus, if pattern consists of @var{n} characters, the resulting file ++fragment will contain @code{@var{n}*@var{block-size}} bytes of data. ++ ++ The last fragment descriptor can have only file offset part. In this + case @command{genfile} will create a hole at the end of the file up to + the given offset. + ++ A dash appearing as a fragment descriptor instructs ++@command{genfile} to read file map from the standard input. Each line ++of input should consist of fragment offset and contents string, ++separated by any amount of whitespace. ++ + For example, consider the following invocation: + + @smallexample +diff --git a/tests/genfile.c b/tests/genfile.c +index fa480ef..d41336b 100644 +--- a/tests/genfile.c ++++ b/tests/genfile.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + #define obstack_chunk_alloc malloc + #define obstack_chunk_free free + #include +@@ -506,6 +507,53 @@ mksparse (int fd, off_t displ, char *marks) + } + } + ++static int ++make_fragment (int fd, char *offstr, char *mapstr) ++{ ++ int i; ++ off_t displ = get_size (offstr, 1); ++ ++ file_length += displ; ++ ++ if (!mapstr || !*mapstr) ++ { ++ mkhole (fd, displ); ++ return 1; ++ } ++ else if (*mapstr == '=') ++ { ++ off_t n = get_size (mapstr + 1, 1); ++ ++ switch (pattern) ++ { ++ case DEFAULT_PATTERN: ++ for (i = 0; i < block_size; i++) ++ buffer[i] = i & 255; ++ break; ++ ++ case ZEROS_PATTERN: ++ memset (buffer, 0, block_size); ++ break; ++ } ++ ++ if (lseek (fd, displ, SEEK_CUR) == -1) ++ error (EXIT_FAILURE, errno, "lseek"); ++ ++ for (; n; n--) ++ { ++ if (write (fd, buffer, block_size) != block_size) ++ error (EXIT_FAILURE, errno, "write"); ++ file_length += block_size; ++ } ++ } ++ else ++ { ++ file_length += block_size * strlen (mapstr); ++ mksparse (fd, displ, mapstr); ++ } ++ return 0; ++} ++ + static void + generate_sparse_file (int argc, char **argv) + { +@@ -526,20 +574,33 @@ generate_sparse_file (int argc, char **argv) + + file_length = 0; + +- for (i = 0; i < argc; i += 2) ++ while (argc) + { +- off_t displ = get_size (argv[i], 1); +- file_length += displ; ++ if (argv[0][0] == '-' && argv[0][1] == 0) ++ { ++ char buf[256]; ++ while (fgets (buf, sizeof (buf), stdin)) ++ { ++ size_t n = strlen (buf); + +- if (i == argc-1) +- { +- mkhole (fd, displ); +- break; ++ while (n > 0 && c_isspace (buf[n-1])) ++ buf[--n] = 0; ++ ++ n = strcspn (buf, " \t"); ++ buf[n++] = 0; ++ while (buf[n] && c_isblank (buf[n])) ++ ++n; ++ make_fragment (fd, buf, buf + n); ++ } ++ ++argv; ++ --argc; + } + else + { +- file_length += block_size * strlen (argv[i+1]); +- mksparse (fd, displ, argv[i+1]); ++ if (make_fragment (fd, argv[0], argv[1])) ++ break; ++ argc -= 2; ++ argv += 2; + } + } + +-- +2.13.5 + + +From 29e35df407d6c7b1e1ff57f7ef2030a253132a8a Mon Sep 17 00:00:00 2001 +From: Pavel Raiskup +Date: Fri, 4 Dec 2015 19:36:14 +0100 +Subject: [PATCH 4/4] genfile: remove unused variable + +paxutils: 58b8ac114790e2de7992db1a387ec14238783f39 + +* tests/genfile.c (generate_sparse_file): Remove unused 'i'. +--- + tests/genfile.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tests/genfile.c b/tests/genfile.c +index d41336b..4699d21 100644 +--- a/tests/genfile.c ++++ b/tests/genfile.c +@@ -557,7 +557,6 @@ make_fragment (int fd, char *offstr, char *mapstr) + static void + generate_sparse_file (int argc, char **argv) + { +- int i; + int fd; + int flags = O_CREAT | O_RDWR | O_BINARY; + +-- +2.13.5 diff --git a/SOURCES/tar-1.26-non-deterministic-archive-detection.patch b/SOURCES/tar-1.26-non-deterministic-archive-detection.patch new file mode 100644 index 00000000..146c02f7 --- /dev/null +++ b/SOURCES/tar-1.26-non-deterministic-archive-detection.patch @@ -0,0 +1,77 @@ + +From 1847ec67cec36a17354115374954fea211d1f0da Mon Sep 17 00:00:00 2001 +From: Sergey Poznyakoff +Date: Thu, 19 Feb 2015 17:00:58 +0200 +Subject: [PATCH] Improve compression format recognition + +Some comressed archives can pass the checksum test, which makes tar +treat them as uncompressed archives. + +* src/buffer.c (check_compressed_archive): Test the checksum only +if the block we read looks like a valid tar header (i.e. has +a magic string). +--- + src/buffer.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/buffer.c b/src/buffer.c +index a7d8971..1a96595 100644 +--- a/src/buffer.c ++++ b/src/buffer.c +@@ -391,7 +391,10 @@ check_compressed_archive (bool *pshort) + /* Restore global values */ + read_full_records = sfr; + +- if (tar_checksum (record_start, true) == HEADER_SUCCESS) ++ if ((strcmp (record_start->header.magic, TMAGIC) == 0 || ++ strcmp (record_start->buffer + offsetof (struct posix_header, magic), ++ OLDGNU_MAGIC) == 0) && ++ tar_checksum (record_start, true) == HEADER_SUCCESS) + /* Probably a valid header */ + return ct_tar; + +-- +2.13.5 + + + +From 1e8b786e651d174a5fc9bf63a08d00c2d592ee3e Mon Sep 17 00:00:00 2001 +From: Pavel Raiskup +Date: Thu, 30 Mar 2017 13:30:15 +0200 +Subject: [PATCH] Fix non-deterministic archive type detection + +Due to analysis of partly uninitialized read-ahead buffer +(short_read call), we sometimes mistakenly classified very small +compressed archives as non-compressed; which in turn caused +extraction failure. + +* src/buffer.c (check_compressed_archive): Don't assume that +archives smaller than BLOCKSIZE could be non-compressed, as tar +header always has at least one block. +--- + src/buffer.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/src/buffer.c b/src/buffer.c +index 57fe813..6f96c2f 100644 +--- a/src/buffer.c ++++ b/src/buffer.c +@@ -402,10 +402,12 @@ check_compressed_archive (bool *pshort) + /* Restore global values */ + read_full_records = sfr; + +- if ((strcmp (record_start->header.magic, TMAGIC) == 0 || +- strcmp (record_start->buffer + offsetof (struct posix_header, magic), +- OLDGNU_MAGIC) == 0) && +- tar_checksum (record_start, true) == HEADER_SUCCESS) ++ if (record_start != record_end /* no files smaller than BLOCKSIZE */ ++ && (strcmp (record_start->header.magic, TMAGIC) == 0 ++ || strcmp (record_start->buffer + offsetof (struct posix_header, ++ magic), ++ OLDGNU_MAGIC) == 0) ++ && tar_checksum (record_start, true) == HEADER_SUCCESS) + /* Probably a valid header */ + return ct_tar; + +-- +2.13.5 diff --git a/SOURCES/tar-1.26-pax-big-sparse-files.patch b/SOURCES/tar-1.26-pax-big-sparse-files.patch new file mode 100644 index 00000000..1d56a81e --- /dev/null +++ b/SOURCES/tar-1.26-pax-big-sparse-files.patch @@ -0,0 +1,66 @@ +diff --git a/NEWS b/NEWS +index 8aeae33..8f3c416 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,10 +1,15 @@ + GNU tar NEWS - User visible changes. 2012-11-19 + Please send GNU tar bug reports to + ++** Sparse files with large data ++ ++When creating a PAX-format archive, tar no longer arbitrarily restricts ++the size of the representation of a sparse file to be less than 8 GiB. ++ + + version 1.26 - Sergey Poznyakoff, 2011-03-12 + +-* Bugfixes ++* Bug fixes + + ** Fix the --verify option, which broke in version 1.24. + +diff --git a/src/sparse.c b/src/sparse.c +index 4b2f982..cfd0c66 100644 +--- a/src/sparse.c ++++ b/src/sparse.c +@@ -919,6 +919,18 @@ pax_sparse_member_p (struct tar_sparse_file *file) + || file->stat_info->sparse_major > 0; + } + ++/* Start a header that uses the effective (shrunken) file size. */ ++static union block * ++pax_start_header (struct tar_stat_info *st) ++{ ++ off_t realsize = st->stat.st_size; ++ union block *blk; ++ st->stat.st_size = st->archive_file_size; ++ blk = start_header (st); ++ st->stat.st_size = realsize; ++ return blk; ++} ++ + static bool + pax_dump_header_0 (struct tar_sparse_file *file) + { +@@ -968,9 +980,7 @@ pax_dump_header_0 (struct tar_sparse_file *file) + return false; + } + } +- blk = start_header (file->stat_info); +- /* Store the effective (shrunken) file size */ +- OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size); ++ blk = pax_start_header (file->stat_info); + finish_header (file->stat_info, blk, block_ordinal); + if (save_file_name) + { +@@ -1035,9 +1045,7 @@ pax_dump_header_1 (struct tar_sparse_file *file) + if (strlen (file->stat_info->file_name) > NAME_FIELD_SIZE) + file->stat_info->file_name[NAME_FIELD_SIZE] = 0; + +- blk = start_header (file->stat_info); +- /* Store the effective (shrunken) file size */ +- OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size); ++ blk = pax_start_header (file->stat_info); + finish_header (file->stat_info, blk, block_ordinal); + free (file->stat_info->file_name); + file->stat_info->file_name = save_file_name; diff --git a/SOURCES/tar-1.26-posix-biguid.patch b/SOURCES/tar-1.26-posix-biguid.patch new file mode 100644 index 00000000..8a9ca98a --- /dev/null +++ b/SOURCES/tar-1.26-posix-biguid.patch @@ -0,0 +1,15 @@ +diff --git a/src/create.c b/src/create.c +index 25387a9..9a7a05a 100644 +--- a/src/create.c ++++ b/src/create.c +@@ -514,8 +514,8 @@ start_private_header (const char *name, size_t size, time_t t) + + TIME_TO_CHARS (t, header->header.mtime); + MODE_TO_CHARS (S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, header->header.mode); +- UID_TO_CHARS (getuid (), header->header.uid); +- GID_TO_CHARS (getgid (), header->header.gid); ++ UID_TO_CHARS (0, header->header.uid); ++ GID_TO_CHARS (0, header->header.gid); + MAJOR_TO_CHARS (0, header->header.devmajor); + MINOR_TO_CHARS (0, header->header.devminor); + strncpy (header->header.magic, TMAGIC, TMAGLEN); diff --git a/SOURCES/tar-1.26-restore-incremental-backups.patch b/SOURCES/tar-1.26-restore-incremental-backups.patch new file mode 100644 index 00000000..f8a3508c --- /dev/null +++ b/SOURCES/tar-1.26-restore-incremental-backups.patch @@ -0,0 +1,250 @@ +diff -urN tar-1.26/src/common.h tar-1.26new/src/common.h +--- tar-1.26/src/common.h 2017-01-24 09:43:08.638550577 +0100 ++++ tar-1.26new/src/common.h 2017-01-23 10:58:19.675411746 +0100 +@@ -598,6 +598,7 @@ + char *normalize_filename (const char *name); + void replace_prefix (char **pname, const char *samp, size_t slen, + const char *repl, size_t rlen); ++char *tar_savedir (const char *name, int must_exist); + + typedef struct namebuf *namebuf_t; + namebuf_t namebuf_create (const char *dir); +diff -urN tar-1.26/src/incremen.c tar-1.26new/src/incremen.c +--- tar-1.26/src/incremen.c 2011-02-16 23:12:16.000000000 +0100 ++++ tar-1.26new/src/incremen.c 2017-01-23 10:58:19.676411754 +0100 +@@ -1580,7 +1580,7 @@ + if (!is_dumpdir (¤t_stat_info)) + return false; + +- current_dir = savedir (directory_name); ++ current_dir = tar_savedir (directory_name, 0); + + if (!current_dir) + /* The directory doesn't exist now. It'll be created. In any +diff -urN tar-1.26/src/misc.c tar-1.26new/src/misc.c +--- tar-1.26/src/misc.c 2011-02-16 23:12:16.000000000 +0100 ++++ tar-1.26new/src/misc.c 2017-01-23 10:58:19.677411762 +0100 +@@ -483,7 +483,7 @@ + + case RECURSIVE_REMOVE_OPTION: + { +- char *directory = savedir (file_name); ++ char *directory = tar_savedir (file_name, 0); + char const *entry; + size_t entrylen; + +@@ -945,3 +945,31 @@ + strcpy (buf->buffer + buf->dir_length, name); + return buf->buffer; + } ++ ++/* Return the filenames in directory NAME, relative to the chdir_fd. ++ If the directory does not exist, report error if MUST_EXIST is ++ true. ++ ++ Return NULL on errors. ++*/ ++char * ++tar_savedir (const char *name, int must_exist) ++{ ++ char *ret = NULL; ++ DIR *dir = NULL; ++ int fd = openat (chdir_fd, name, open_read_flags | O_DIRECTORY); ++ if (fd < 0) ++ { ++ if (!must_exist && errno == ENOENT) ++ return NULL; ++ open_error (name); ++ } ++ else if (! ((dir = fdopendir (fd)) ++ && (ret = streamsavedir (dir)))) ++ savedir_error (name); ++ ++ if (dir ? closedir (dir) != 0 : 0 <= fd && close (fd) != 0) ++ savedir_error (name); ++ ++ return ret; ++} +diff -urN tar-1.26/src/update.c tar-1.26new/src/update.c +--- tar-1.26/src/update.c 2017-01-24 09:43:08.620550423 +0100 ++++ tar-1.26new/src/update.c 2017-01-23 12:29:20.410943374 +0100 +@@ -144,16 +144,8 @@ + { + if (S_ISDIR (s.st_mode)) + { +- char *p, *dirp; +- DIR *stream; +- int fd = openat (chdir_fd, name->name, +- open_read_flags | O_DIRECTORY); +- if (fd < 0) +- open_error (name->name); +- else if (! ((stream = fdopendir (fd)) +- && (dirp = streamsavedir (stream)))) +- savedir_error (name->name); +- else ++ char *p, *dirp = tar_savedir (name->name, 1); ++ if (dirp) + { + namebuf_t nbuf = namebuf_create (name->name); + +@@ -166,11 +158,6 @@ + + remname (name); + } +- +- if (stream +- ? closedir (stream) != 0 +- : 0 <= fd && close (fd) != 0) +- savedir_error (name->name); + } + else if (tar_timespec_cmp (get_stat_mtime (&s), + current_stat_info.mtime) +diff -urN tar-1.26/tests/incr07.at tar-1.26new/tests/incr07.at +--- tar-1.26/tests/incr07.at 1970-01-01 01:00:00.000000000 +0100 ++++ tar-1.26new/tests/incr07.at 2017-01-24 09:39:34.305615960 +0100 +@@ -0,0 +1,112 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# Test suite for GNU tar. ++# Copyright 2009, 2013 Free Software Foundation, Inc. ++# ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++AT_SETUP([incremental restores with -C]) ++AT_KEYWORDS([incremental extract incr07]) ++ ++# Tar 1.26 had problems extracting from incremental restores when given ++# the -C option. The code in incremen.c:try_purge_directory and ++# misc.c:remove_any_file was using savedir(), which ignored eventual changes ++# in the current working directory and caused the malfunctioning. ++# ++# The problem was reported by Piotr Rotter on 2013-03-22. ++# ++# This testcase is based on scripts provided by Piotr Rotter and Nathan ++# Stratton Treadway. ++# ++# References: <514C8F56.90900@active24.pl>, ++# http://lists.gnu.org/archive/html/bug-tar/2013-03/msg00036.html, ++# <20130326181922.GZ3732@shire.ontko.com>, ++# http://lists.gnu.org/archive/html/bug-tar/2013-03/msg00042.html, ++# <20130327051828.GA3732@shire.ontko.com>, ++# http://lists.gnu.org/archive/html/bug-tar/2013-03/msg00043.html, ++# <20130327054957.GB3732@shire.ontko.com>, ++# http://lists.gnu.org/archive/html/bug-tar/2013-03/msg00044.html ++ ++AT_TAR_CHECK([ ++mkdir dirA ++echo 'a' > dirA/a ++echo 'a' > dirA/b ++ ++decho C0 ++tar -g test.snar -vcf test.0.tar dirA ++ ++echo 'a' > dirA/c ++decho C1 ++tar -g test.snar -vcf test.1.tar dirA ++ ++rm -f dirA/a ++decho C2 ++tar -g test.snar -vcf test.2.tar dirA ++ ++mkdir ext ++rm -rf dirA ++ ++decho E0 ++tar -g test.snar -vxf test.0.tar -C ext/ ++decho E1 ++tar -g test.snar -vxf test.1.tar -C ext/ ++ ++decho E2 ++tar -g test.snar -vxf test.2.tar -C ext/ ++ ++mkdir ext/dirA/dirB ++touch ext/dirA/dirB/file ++ ++decho E3 ++tar -g test.snar -vxf test.2.tar -C ext/ ++ ++echo FIN ++test -d dirA && echo >&2 "toplevel dirA exists" ++exit 0 ++], ++[0], ++[C0 ++dirA/ ++dirA/a ++dirA/b ++C1 ++dirA/ ++dirA/c ++C2 ++dirA/ ++E0 ++dirA/ ++dirA/a ++dirA/b ++E1 ++dirA/ ++dirA/c ++E2 ++dirA/ ++tar: Deleting `dirA/a' ++E3 ++dirA/ ++tar: Deleting `dirA/dirB' ++FIN ++], ++[C0 ++tar: dirA: Directory is new ++C1 ++C2 ++E0 ++E1 ++E2 ++E3 ++],[],[],[gnu, oldgnu, posix]) ++ ++AT_CLEANUP +diff -urN tar-1.26/tests/Makefile.am tar-1.26new/tests/Makefile.am +--- tar-1.26/tests/Makefile.am 2017-01-24 09:43:08.656550731 +0100 ++++ tar-1.26new/tests/Makefile.am 2017-01-23 10:58:19.678411770 +0100 +@@ -98,6 +98,7 @@ + incr04.at\ + incr05.at\ + incr06.at\ ++ incr07.at\ + indexfile.at\ + ignfail.at\ + label01.at\ +diff -urN tar-1.26/tests/testsuite.at tar-1.26new/tests/testsuite.at +--- tar-1.26/tests/testsuite.at 2017-01-24 09:43:08.656550731 +0100 ++++ tar-1.26new/tests/testsuite.at 2017-01-23 10:58:19.678411770 +0100 +@@ -259,6 +259,7 @@ + m4_include([incr04.at]) + m4_include([incr05.at]) + m4_include([incr06.at]) ++m4_include([incr07.at]) + + m4_include([filerem01.at]) + m4_include([filerem02.at]) +diff -urN tar-1.26/THANKS tar-1.26new/THANKS +--- tar-1.26/THANKS 2017-01-24 09:43:08.636550560 +0100 ++++ tar-1.26new/THANKS 2017-01-23 10:58:19.674411738 +0100 +@@ -397,6 +397,7 @@ + Philippe Defert defert@cern.ch + Piercarlo Grandi piercarl@sabi.demon.co.uk + Pierce Cantrell cantrell@ee.tamu.edu ++Piotr Rotter piotr.rotter@active24.pl + R. Kent Dybvig dyb@cadence.bloomington.in.us + R. Scott Butler butler@prism.es.dupont.com + Rainer Orth ro@TechFak.Uni-Bielefeld.DE diff --git a/SOURCES/tar-1.26-selinux-gnulib.patch b/SOURCES/tar-1.26-selinux-gnulib.patch new file mode 100644 index 00000000..b8c3367f --- /dev/null +++ b/SOURCES/tar-1.26-selinux-gnulib.patch @@ -0,0 +1,3602 @@ +From f733da5249b0b119cb551c73b322439bcbbc013a Mon Sep 17 00:00:00 2001 +From: Pavel Raiskup +Date: Tue, 19 Feb 2013 10:41:10 +0100 +Subject: [PATCH] x + +--- + build-aux/snippet/unused-parameter.h | 38 ++ + gnu/Makefile.am | 93 +++- + gnu/acl-internal.h | 267 ++++++++++ + gnu/acl.h | 30 ++ + gnu/acl_entries.c | 77 +++ + gnu/copy-acl.c | 620 +++++++++++++++++++++++ + gnu/file-has-acl.c | 920 +++++++++++++++++++++++++++++++++++ + gnu/getfilecon.c | 88 ++++ + gnu/se-context.in.h | 30 ++ + gnu/se-selinux.in.h | 99 ++++ + gnu/selinux-at.c | 74 +++ + gnu/selinux-at.h | 54 ++ + gnu/set-mode-acl.c | 699 ++++++++++++++++++++++++++ + m4/acl.m4 | 165 +++++++ + m4/gnulib-comp.m4 | 27 +- + m4/selinux-context-h.m4 | 22 + + m4/selinux-selinux-h.m4 | 69 +++ + 17 files changed, 3365 insertions(+), 7 deletions(-) + create mode 100644 build-aux/snippet/unused-parameter.h + create mode 100644 gnu/acl-internal.h + create mode 100644 gnu/acl.h + create mode 100644 gnu/acl_entries.c + create mode 100644 gnu/copy-acl.c + create mode 100644 gnu/file-has-acl.c + create mode 100644 gnu/getfilecon.c + create mode 100644 gnu/se-context.in.h + create mode 100644 gnu/se-selinux.in.h + create mode 100644 gnu/selinux-at.c + create mode 100644 gnu/selinux-at.h + create mode 100644 gnu/set-mode-acl.c + create mode 100644 m4/acl.m4 + create mode 100644 m4/selinux-context-h.m4 + create mode 100644 m4/selinux-selinux-h.m4 + +diff --git a/build-aux/snippet/unused-parameter.h b/build-aux/snippet/unused-parameter.h +new file mode 100644 +index 0000000..6b60482 +--- /dev/null ++++ b/build-aux/snippet/unused-parameter.h +@@ -0,0 +1,38 @@ ++/* -*- buffer-read-only: t -*- vi: set ro: */ ++/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ ++/* A C macro for declaring that specific function parameters are not used. ++ Copyright (C) 2008-2012 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify it ++ under the terms of the GNU General Public License as published ++ by the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++/* _GL_UNUSED_PARAMETER is a marker that can be appended to function parameter ++ declarations for parameters that are not used. This helps to reduce ++ warnings, such as from GCC -Wunused-parameter. The syntax is as follows: ++ type param _GL_UNUSED_PARAMETER ++ or more generally ++ param_decl _GL_UNUSED_PARAMETER ++ For example: ++ int param _GL_UNUSED_PARAMETER ++ int *(*param)(void) _GL_UNUSED_PARAMETER ++ Other possible, but obscure and discouraged syntaxes: ++ int _GL_UNUSED_PARAMETER *(*param)(void) ++ _GL_UNUSED_PARAMETER int *(*param)(void) ++ */ ++#ifndef _GL_UNUSED_PARAMETER ++# if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7) ++# define _GL_UNUSED_PARAMETER __attribute__ ((__unused__)) ++# else ++# define _GL_UNUSED_PARAMETER ++# endif ++#endif +diff --git a/gnu/Makefile.am b/gnu/Makefile.am +index 06eb0d9..77d75d2 100644 +--- a/gnu/Makefile.am ++++ b/gnu/Makefile.am +@@ -1,6 +1,3 @@ +-# -*- buffer-read-only: t -*- vi: set ro: +-# DO NOT EDIT! GENERATED AUTOMATICALLY! +-## DO NOT EDIT! GENERATED AUTOMATICALLY! + ## Process this file with automake to produce Makefile.in. + # Copyright (C) 2002-2011 Free Software Foundation, Inc. + # +@@ -38,8 +35,17 @@ libgnu_a_LIBADD = $(gl_LIBOBJS) + libgnu_a_DEPENDENCIES = $(gl_LIBOBJS) + EXTRA_libgnu_a_SOURCES = + +-## begin gnulib module alloca ++## begin gnulib module acl ++ ++libgnu_a_SOURCES += set-mode-acl.c copy-acl.c file-has-acl.c ++ ++EXTRA_DIST += acl-internal.h acl.h acl_entries.c + ++EXTRA_libgnu_a_SOURCES += acl_entries.c ++ ++## end gnulib module acl ++ ++## begin gnulib module alloca + + EXTRA_DIST += alloca.c + +@@ -179,6 +185,31 @@ EXTRA_DIST += $(top_srcdir)/build-aux/c++defs.h + + ## end gnulib module c++defs + ++## begin gnulib module snippet/unused-parameter ++ ++# The BUILT_SOURCES created by this Makefile snippet are not used via #include ++# statements but through direct file reference. Therefore this snippet must be ++# present in all Makefile.am that need it. This is ensured by the applicability ++# 'all' defined above. ++ ++BUILT_SOURCES += unused-parameter.h ++# The unused-parameter.h that gets inserted into generated .h files is the same ++# as build-aux/snippet/unused-parameter.h, except that it has the copyright ++# header cut off. ++unused-parameter.h: $(top_srcdir)/build-aux/snippet/unused-parameter.h ++ $(AM_V_GEN)rm -f $@-t $@ && \ ++ sed -n -e '/GL_UNUSED_PARAMETER/,$$p' \ ++ < $(top_srcdir)/build-aux/snippet/unused-parameter.h \ ++ > $@-t && \ ++ mv $@-t $@ ++MOSTLYCLEANFILES += unused-parameter.h unused-parameter.h-t ++ ++UNUSED_PARAMETER_H=unused-parameter.h ++ ++EXTRA_DIST += $(top_srcdir)/build-aux/snippet/unused-parameter.h ++ ++## end gnulib module snippet/unused-parameter ++ + ## begin gnulib module c-ctype + + libgnu_a_SOURCES += c-ctype.h c-ctype.c +@@ -1386,6 +1417,60 @@ EXTRA_libgnu_a_SOURCES += savedir.c + + ## end gnulib module savedir + ++## begin gnulib module selinux-at ++ ++ ++EXTRA_DIST += at-func.c selinux-at.c selinux-at.h ++ ++EXTRA_libgnu_a_SOURCES += at-func.c selinux-at.c ++ ++## end gnulib module selinux-at ++ ++## begin gnulib module selinux-h ++ ++libgnu_a_SOURCES += se-context.in.h se-selinux.in.h ++ ++BUILT_SOURCES += selinux/selinux.h ++selinux/selinux.h: se-selinux.in.h $(top_builddir)/config.status $(UNUSED_PARAMETER_H) ++ $(AM_V_at)$(MKDIR_P) selinux ++ $(AM_V_GEN)rm -f $@-t $@ && \ ++ { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \ ++ sed -e 's|@''GUARD_PREFIX''@|GL|g' \ ++ -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \ ++ -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \ ++ -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \ ++ -e 's|@''NEXT_SELINUX_SELINUX_H''@|$(NEXT_SELINUX_SELINUX_H)|g' \ ++ -e '/definition of _GL_UNUSED_PARAMETER/r $(UNUSED_PARAMETER_H)' \ ++ < $(srcdir)/se-selinux.in.h; \ ++ } > $@-t && \ ++ chmod a-x $@-t && \ ++ mv $@-t $@ ++MOSTLYCLEANFILES += selinux/selinux.h selinux/selinux.h-t ++ ++BUILT_SOURCES += $(SELINUX_CONTEXT_H) ++if GL_GENERATE_SELINUX_CONTEXT_H ++selinux/context.h: se-context.in.h $(top_builddir)/config.status $(UNUSED_PARAMETER_H) ++ $(AM_V_at)$(MKDIR_P) selinux ++ $(AM_V_GEN)rm -f $@-t $@ && \ ++ { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \ ++ sed -e '/definition of _GL_UNUSED_PARAMETER/r $(UNUSED_PARAMETER_H)' \ ++ < $(srcdir)/se-context.in.h; \ ++ } > $@-t && \ ++ chmod a-x $@-t && \ ++ mv $@-t $@ ++else ++selinux/context.h: $(top_builddir)/config.status ++ rm -f $@ ++endif ++MOSTLYCLEANFILES += selinux/context.h selinux/context.h-t ++MOSTLYCLEANDIRS += selinux ++ ++EXTRA_DIST += getfilecon.c ++ ++EXTRA_libgnu_a_SOURCES += getfilecon.c ++ ++## end gnulib module selinux-h ++ + ## begin gnulib module setenv + + +diff --git a/gnu/acl-internal.h b/gnu/acl-internal.h +new file mode 100644 +index 0000000..07309e0 +--- /dev/null ++++ b/gnu/acl-internal.h +@@ -0,0 +1,267 @@ ++/* -*- buffer-read-only: t -*- vi: set ro: */ ++/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ ++/* Internal implementation of access control lists. ++ ++ Copyright (C) 2002-2003, 2005-2012 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++ Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */ ++ ++#include "acl.h" ++ ++#include ++#include ++ ++/* All systems define the ACL related API in . */ ++#if HAVE_SYS_ACL_H ++# include ++#endif ++#if defined HAVE_FACL && ! defined GETACLCNT && defined ACL_CNT ++# define GETACLCNT ACL_CNT ++#endif ++ ++/* On Linux, additional ACL related API is available in . */ ++#ifdef HAVE_ACL_LIBACL_H ++# include ++#endif ++ ++/* On HP-UX >= 11.11, additional ACL API is available in . */ ++#if HAVE_ACLV_H ++# include ++# include ++/* HP-UX 11.11 lacks these declarations. */ ++extern int acl (char *, int, int, struct acl *); ++extern int aclsort (int, int, struct acl *); ++#endif ++ ++#include "error.h" ++#include "quote.h" ++ ++#include ++#ifndef ENOSYS ++# define ENOSYS (-1) ++#endif ++#ifndef ENOTSUP ++# define ENOTSUP (-1) ++#endif ++ ++#include ++#ifndef MIN ++# define MIN(a,b) ((a) < (b) ? (a) : (b)) ++#endif ++ ++#ifndef SIZE_MAX ++# define SIZE_MAX ((size_t) -1) ++#endif ++ ++#ifndef HAVE_FCHMOD ++# define HAVE_FCHMOD false ++# define fchmod(fd, mode) (-1) ++#endif ++ ++/* Recognize some common errors such as from an NFS mount that does ++ not support ACLs, even when local drives do. */ ++#if defined __APPLE__ && defined __MACH__ /* Mac OS X */ ++# define ACL_NOT_WELL_SUPPORTED(Err) \ ++ ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY || (Err) == ENOENT) ++#elif defined EOPNOTSUPP /* Tru64 NFS */ ++# define ACL_NOT_WELL_SUPPORTED(Err) \ ++ ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY || (Err) == EOPNOTSUPP) ++#else ++# define ACL_NOT_WELL_SUPPORTED(Err) \ ++ ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY) ++#endif ++ ++#if USE_ACL ++ ++# if HAVE_ACL_GET_FILE ++/* POSIX 1003.1e (draft 17 -- abandoned) specific version. */ ++/* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */ ++ ++# ifndef MIN_ACL_ENTRIES ++# define MIN_ACL_ENTRIES 4 ++# endif ++ ++/* POSIX 1003.1e (draft 17) */ ++# ifdef HAVE_ACL_GET_FD ++/* Most platforms have a 1-argument acl_get_fd, only OSF/1 has a 2-argument ++ macro(!). */ ++# if HAVE_ACL_FREE_TEXT /* OSF/1 */ ++static inline acl_t ++rpl_acl_get_fd (int fd) ++{ ++ return acl_get_fd (fd, ACL_TYPE_ACCESS); ++} ++# undef acl_get_fd ++# define acl_get_fd rpl_acl_get_fd ++# endif ++# else ++# define HAVE_ACL_GET_FD false ++# undef acl_get_fd ++# define acl_get_fd(fd) (NULL) ++# endif ++ ++/* POSIX 1003.1e (draft 17) */ ++# ifdef HAVE_ACL_SET_FD ++/* Most platforms have a 2-argument acl_set_fd, only OSF/1 has a 3-argument ++ macro(!). */ ++# if HAVE_ACL_FREE_TEXT /* OSF/1 */ ++static inline int ++rpl_acl_set_fd (int fd, acl_t acl) ++{ ++ return acl_set_fd (fd, ACL_TYPE_ACCESS, acl); ++} ++# undef acl_set_fd ++# define acl_set_fd rpl_acl_set_fd ++# endif ++# else ++# define HAVE_ACL_SET_FD false ++# undef acl_set_fd ++# define acl_set_fd(fd, acl) (-1) ++# endif ++ ++/* POSIX 1003.1e (draft 13) */ ++# if ! HAVE_ACL_FREE_TEXT ++# define acl_free_text(buf) acl_free (buf) ++# endif ++ ++/* Linux-specific */ ++# ifndef HAVE_ACL_EXTENDED_FILE ++# define HAVE_ACL_EXTENDED_FILE false ++# define acl_extended_file(name) (-1) ++# endif ++ ++/* Linux-specific */ ++# ifndef HAVE_ACL_FROM_MODE ++# define HAVE_ACL_FROM_MODE false ++# define acl_from_mode(mode) (NULL) ++# endif ++ ++/* Set to 1 if a file's mode is implicit by the ACL. ++ Set to 0 if a file's mode is stored independently from the ACL. */ ++# if (HAVE_ACL_COPY_EXT_NATIVE && HAVE_ACL_CREATE_ENTRY_NP) || defined __sgi /* Mac OS X, IRIX */ ++# define MODE_INSIDE_ACL 0 ++# else ++# define MODE_INSIDE_ACL 1 ++# endif ++ ++/* Return the number of entries in ACL. ++ Return -1 and set errno upon failure to determine it. */ ++/* Define a replacement for acl_entries if needed. (Only Linux has it.) */ ++# if !HAVE_ACL_ENTRIES ++# define acl_entries rpl_acl_entries ++extern int acl_entries (acl_t); ++# endif ++ ++# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */ ++/* ACL is an ACL, from a file, stored as type ACL_TYPE_EXTENDED. ++ Return 1 if the given ACL is non-trivial. ++ Return 0 if it is trivial. */ ++extern int acl_extended_nontrivial (acl_t); ++# else ++/* ACL is an ACL, from a file, stored as type ACL_TYPE_ACCESS. ++ Return 1 if the given ACL is non-trivial. ++ Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. ++ Return -1 and set errno upon failure to determine it. */ ++extern int acl_access_nontrivial (acl_t); ++# endif ++ ++# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ ++ ++/* Set to 1 if a file's mode is implicit by the ACL. ++ Set to 0 if a file's mode is stored independently from the ACL. */ ++# if defined __CYGWIN__ /* Cygwin */ ++# define MODE_INSIDE_ACL 0 ++# else /* Solaris */ ++# define MODE_INSIDE_ACL 1 ++# endif ++ ++/* Return 1 if the given ACL is non-trivial. ++ Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ ++extern int acl_nontrivial (int count, aclent_t *entries); ++ ++# ifdef ACE_GETACL /* Solaris 10 */ ++ ++/* Test an ACL retrieved with ACE_GETACL. ++ Return 1 if the given ACL, consisting of COUNT entries, is non-trivial. ++ Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ ++extern int acl_ace_nontrivial (int count, ace_t *entries); ++ ++/* Definitions for when the built executable is executed on Solaris 10 ++ (newer version) or Solaris 11. */ ++/* For a_type. */ ++# define OLD_ALLOW 0 ++# define OLD_DENY 1 ++# define NEW_ACE_ACCESS_ALLOWED_ACE_TYPE 0 /* replaces ALLOW */ ++# define NEW_ACE_ACCESS_DENIED_ACE_TYPE 1 /* replaces DENY */ ++/* For a_flags. */ ++# define OLD_ACE_OWNER 0x0100 ++# define OLD_ACE_GROUP 0x0200 ++# define OLD_ACE_OTHER 0x0400 ++# define NEW_ACE_OWNER 0x1000 ++# define NEW_ACE_GROUP 0x2000 ++# define NEW_ACE_IDENTIFIER_GROUP 0x0040 ++# define NEW_ACE_EVERYONE 0x4000 ++/* For a_access_mask. */ ++# define NEW_ACE_READ_DATA 0x001 /* corresponds to 'r' */ ++# define NEW_ACE_WRITE_DATA 0x002 /* corresponds to 'w' */ ++# define NEW_ACE_APPEND_DATA 0x004 ++# define NEW_ACE_READ_NAMED_ATTRS 0x008 ++# define NEW_ACE_WRITE_NAMED_ATTRS 0x010 ++# define NEW_ACE_EXECUTE 0x020 ++# define NEW_ACE_DELETE_CHILD 0x040 ++# define NEW_ACE_READ_ATTRIBUTES 0x080 ++# define NEW_ACE_WRITE_ATTRIBUTES 0x100 ++# define NEW_ACE_DELETE 0x10000 ++# define NEW_ACE_READ_ACL 0x20000 ++# define NEW_ACE_WRITE_ACL 0x40000 ++# define NEW_ACE_WRITE_OWNER 0x80000 ++# define NEW_ACE_SYNCHRONIZE 0x100000 ++ ++# endif ++ ++# elif HAVE_GETACL /* HP-UX */ ++ ++/* Return 1 if the given ACL is non-trivial. ++ Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ ++extern int acl_nontrivial (int count, struct acl_entry *entries, struct stat *sb); ++ ++# if HAVE_ACLV_H /* HP-UX >= 11.11 */ ++ ++/* Return 1 if the given ACL is non-trivial. ++ Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ ++extern int aclv_nontrivial (int count, struct acl *entries); ++ ++# endif ++ ++# elif HAVE_ACLX_GET && 0 /* AIX */ ++ ++/* TODO */ ++ ++# elif HAVE_STATACL /* older AIX */ ++ ++/* Return 1 if the given ACL is non-trivial. ++ Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ ++extern int acl_nontrivial (struct acl *a); ++ ++# elif HAVE_ACLSORT /* NonStop Kernel */ ++ ++/* Return 1 if the given ACL is non-trivial. ++ Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ ++extern int acl_nontrivial (int count, struct acl *entries); ++ ++# endif ++ ++#endif +diff --git a/gnu/acl.h b/gnu/acl.h +new file mode 100644 +index 0000000..d808a90 +--- /dev/null ++++ b/gnu/acl.h +@@ -0,0 +1,30 @@ ++/* -*- buffer-read-only: t -*- vi: set ro: */ ++/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ ++/* acl.c - access control lists ++ ++ Copyright (C) 2002, 2008-2012 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++ Written by Paul Eggert. */ ++ ++#include ++#include ++ ++int file_has_acl (char const *, struct stat const *); ++int qset_acl (char const *, int, mode_t); ++int set_acl (char const *, int, mode_t); ++int qcopy_acl (char const *, int, char const *, int, mode_t); ++int copy_acl (char const *, int, char const *, int, mode_t); ++int chmod_or_fchmod (char const *, int, mode_t); +diff --git a/gnu/acl_entries.c b/gnu/acl_entries.c +new file mode 100644 +index 0000000..11adc22 +--- /dev/null ++++ b/gnu/acl_entries.c +@@ -0,0 +1,77 @@ ++/* -*- buffer-read-only: t -*- vi: set ro: */ ++/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ ++/* Return the number of entries in an ACL. ++ ++ Copyright (C) 2002-2003, 2005-2012 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++ Written by Paul Eggert and Andreas Gruenbacher. */ ++ ++#include ++ ++#include "acl-internal.h" ++ ++/* This file assumes POSIX-draft like ACLs ++ (Linux, FreeBSD, Mac OS X, IRIX, Tru64). */ ++ ++/* Return the number of entries in ACL. ++ Return -1 and set errno upon failure to determine it. */ ++ ++int ++acl_entries (acl_t acl) ++{ ++ int count = 0; ++ ++ if (acl != NULL) ++ { ++#if HAVE_ACL_FIRST_ENTRY /* Linux, FreeBSD, Mac OS X */ ++# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */ ++ /* acl_get_entry returns 0 when it successfully fetches an entry, ++ and -1/EINVAL at the end. */ ++ acl_entry_t ace; ++ int got_one; ++ ++ for (got_one = acl_get_entry (acl, ACL_FIRST_ENTRY, &ace); ++ got_one >= 0; ++ got_one = acl_get_entry (acl, ACL_NEXT_ENTRY, &ace)) ++ count++; ++# else /* Linux, FreeBSD */ ++ /* acl_get_entry returns 1 when it successfully fetches an entry, ++ and 0 at the end. */ ++ acl_entry_t ace; ++ int got_one; ++ ++ for (got_one = acl_get_entry (acl, ACL_FIRST_ENTRY, &ace); ++ got_one > 0; ++ got_one = acl_get_entry (acl, ACL_NEXT_ENTRY, &ace)) ++ count++; ++ if (got_one < 0) ++ return -1; ++# endif ++#else /* IRIX, Tru64 */ ++# if HAVE_ACL_TO_SHORT_TEXT /* IRIX */ ++ /* Don't use acl_get_entry: it is undocumented. */ ++ count = acl->acl_cnt; ++# endif ++# if HAVE_ACL_FREE_TEXT /* Tru64 */ ++ /* Don't use acl_get_entry: it takes only one argument and does not ++ work. */ ++ count = acl->acl_num; ++# endif ++#endif ++ } ++ ++ return count; ++} +diff --git a/gnu/copy-acl.c b/gnu/copy-acl.c +new file mode 100644 +index 0000000..a4d82f7 +--- /dev/null ++++ b/gnu/copy-acl.c +@@ -0,0 +1,620 @@ ++/* -*- buffer-read-only: t -*- vi: set ro: */ ++/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ ++/* copy-acl.c - copy access control list from one file to another file ++ ++ Copyright (C) 2002-2003, 2005-2012 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++ Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */ ++ ++#include ++ ++#include "acl.h" ++ ++#include "acl-internal.h" ++ ++#include "gettext.h" ++#define _(msgid) gettext (msgid) ++ ++ ++/* Copy access control lists from one file to another. If SOURCE_DESC is ++ a valid file descriptor, use file descriptor operations, else use ++ filename based operations on SRC_NAME. Likewise for DEST_DESC and ++ DST_NAME. ++ If access control lists are not available, fchmod the target file to ++ MODE. Also sets the non-permission bits of the destination file ++ (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set. ++ Return 0 if successful. ++ Return -2 and set errno for an error relating to the source file. ++ Return -1 and set errno for an error relating to the destination file. */ ++ ++int ++qcopy_acl (const char *src_name, int source_desc, const char *dst_name, ++ int dest_desc, mode_t mode) ++{ ++#if USE_ACL && HAVE_ACL_GET_FILE ++ /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */ ++ /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */ ++# if !HAVE_ACL_TYPE_EXTENDED ++ /* Linux, FreeBSD, IRIX, Tru64 */ ++ ++ acl_t acl; ++ int ret; ++ ++ if (HAVE_ACL_GET_FD && source_desc != -1) ++ acl = acl_get_fd (source_desc); ++ else ++ acl = acl_get_file (src_name, ACL_TYPE_ACCESS); ++ if (acl == NULL) ++ { ++ if (ACL_NOT_WELL_SUPPORTED (errno)) ++ return qset_acl (dst_name, dest_desc, mode); ++ else ++ return -2; ++ } ++ ++ if (HAVE_ACL_SET_FD && dest_desc != -1) ++ ret = acl_set_fd (dest_desc, acl); ++ else ++ ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl); ++ if (ret != 0) ++ { ++ int saved_errno = errno; ++ ++ if (ACL_NOT_WELL_SUPPORTED (errno) && !acl_access_nontrivial (acl)) ++ { ++ acl_free (acl); ++ return chmod_or_fchmod (dst_name, dest_desc, mode); ++ } ++ else ++ { ++ acl_free (acl); ++ chmod_or_fchmod (dst_name, dest_desc, mode); ++ errno = saved_errno; ++ return -1; ++ } ++ } ++ else ++ acl_free (acl); ++ ++ if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX))) ++ { ++ /* We did not call chmod so far, and either the mode and the ACL are ++ separate or special bits are to be set which don't fit into ACLs. */ ++ ++ if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0) ++ return -1; ++ } ++ ++ if (S_ISDIR (mode)) ++ { ++ acl = acl_get_file (src_name, ACL_TYPE_DEFAULT); ++ if (acl == NULL) ++ return -2; ++ ++ if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl)) ++ { ++ int saved_errno = errno; ++ ++ acl_free (acl); ++ errno = saved_errno; ++ return -1; ++ } ++ else ++ acl_free (acl); ++ } ++ return 0; ++ ++# else /* HAVE_ACL_TYPE_EXTENDED */ ++ /* Mac OS X */ ++ ++ /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS) ++ and acl_get_file (name, ACL_TYPE_DEFAULT) ++ always return NULL / EINVAL. You have to use ++ acl_get_file (name, ACL_TYPE_EXTENDED) ++ or acl_get_fd (open (name, ...)) ++ to retrieve an ACL. ++ On the other hand, ++ acl_set_file (name, ACL_TYPE_ACCESS, acl) ++ and acl_set_file (name, ACL_TYPE_DEFAULT, acl) ++ have the same effect as ++ acl_set_file (name, ACL_TYPE_EXTENDED, acl): ++ Each of these calls sets the file's ACL. */ ++ ++ acl_t acl; ++ int ret; ++ ++ if (HAVE_ACL_GET_FD && source_desc != -1) ++ acl = acl_get_fd (source_desc); ++ else ++ acl = acl_get_file (src_name, ACL_TYPE_EXTENDED); ++ if (acl == NULL) ++ { ++ if (ACL_NOT_WELL_SUPPORTED (errno)) ++ return qset_acl (dst_name, dest_desc, mode); ++ else ++ return -2; ++ } ++ ++ if (HAVE_ACL_SET_FD && dest_desc != -1) ++ ret = acl_set_fd (dest_desc, acl); ++ else ++ ret = acl_set_file (dst_name, ACL_TYPE_EXTENDED, acl); ++ if (ret != 0) ++ { ++ int saved_errno = errno; ++ ++ if (ACL_NOT_WELL_SUPPORTED (errno) && !acl_extended_nontrivial (acl)) ++ { ++ acl_free (acl); ++ return chmod_or_fchmod (dst_name, dest_desc, mode); ++ } ++ else ++ { ++ acl_free (acl); ++ chmod_or_fchmod (dst_name, dest_desc, mode); ++ errno = saved_errno; ++ return -1; ++ } ++ } ++ else ++ acl_free (acl); ++ ++ /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */ ++ return chmod_or_fchmod (dst_name, dest_desc, mode); ++ ++# endif ++ ++#elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ ++ ++ /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions ++ of Unixware. The acl() call returns the access and default ACL both ++ at once. */ ++# ifdef ACE_GETACL ++ int ace_count; ++ ace_t *ace_entries; ++# endif ++ int count; ++ aclent_t *entries; ++ int did_chmod; ++ int saved_errno; ++ int ret; ++ ++# ifdef ACE_GETACL ++ /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4 ++ file systems (whereas the other ones are used in UFS file systems). ++ There is an API ++ pathconf (name, _PC_ACL_ENABLED) ++ fpathconf (desc, _PC_ACL_ENABLED) ++ that allows to determine which of the two kinds of ACLs is supported ++ for the given file. But some file systems may implement this call ++ incorrectly, so better not use it. ++ When fetching the source ACL, we simply fetch both ACL types. ++ When setting the destination ACL, we try either ACL types, assuming ++ that the kernel will translate the ACL from one form to the other. ++ (See in ++ the description of ENOTSUP.) */ ++ for (;;) ++ { ++ ace_count = (source_desc != -1 ++ ? facl (source_desc, ACE_GETACLCNT, 0, NULL) ++ : acl (src_name, ACE_GETACLCNT, 0, NULL)); ++ ++ if (ace_count < 0) ++ { ++ if (errno == ENOSYS || errno == EINVAL) ++ { ++ ace_count = 0; ++ ace_entries = NULL; ++ break; ++ } ++ else ++ return -2; ++ } ++ ++ if (ace_count == 0) ++ { ++ ace_entries = NULL; ++ break; ++ } ++ ++ ace_entries = (ace_t *) malloc (ace_count * sizeof (ace_t)); ++ if (ace_entries == NULL) ++ { ++ errno = ENOMEM; ++ return -2; ++ } ++ ++ ret = (source_desc != -1 ++ ? facl (source_desc, ACE_GETACL, ace_count, ace_entries) ++ : acl (src_name, ACE_GETACL, ace_count, ace_entries)); ++ if (ret < 0) ++ { ++ free (ace_entries); ++ if (errno == ENOSYS || errno == EINVAL) ++ { ++ ace_count = 0; ++ ace_entries = NULL; ++ break; ++ } ++ else ++ return -2; ++ } ++ if (ret == ace_count) ++ break; ++ /* Huh? The number of ACL entries changed since the last call. ++ Repeat. */ ++ } ++# endif ++ ++ for (;;) ++ { ++ count = (source_desc != -1 ++ ? facl (source_desc, GETACLCNT, 0, NULL) ++ : acl (src_name, GETACLCNT, 0, NULL)); ++ ++ if (count < 0) ++ { ++ if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP) ++ { ++ count = 0; ++ entries = NULL; ++ break; ++ } ++ else ++ return -2; ++ } ++ ++ if (count == 0) ++ { ++ entries = NULL; ++ break; ++ } ++ ++ entries = (aclent_t *) malloc (count * sizeof (aclent_t)); ++ if (entries == NULL) ++ { ++ errno = ENOMEM; ++ return -2; ++ } ++ ++ if ((source_desc != -1 ++ ? facl (source_desc, GETACL, count, entries) ++ : acl (src_name, GETACL, count, entries)) ++ == count) ++ break; ++ /* Huh? The number of ACL entries changed since the last call. ++ Repeat. */ ++ } ++ ++ /* Is there an ACL of either kind? */ ++# ifdef ACE_GETACL ++ if (ace_count == 0) ++# endif ++ if (count == 0) ++ return qset_acl (dst_name, dest_desc, mode); ++ ++ did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */ ++ saved_errno = 0; /* the first non-ignorable error code */ ++ ++ if (!MODE_INSIDE_ACL) ++ { ++ /* On Cygwin, it is necessary to call chmod before acl, because ++ chmod can change the contents of the ACL (in ways that don't ++ change the allowed accesses, but still visible). */ ++ if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0) ++ saved_errno = errno; ++ did_chmod = 1; ++ } ++ ++ /* If both ace_entries and entries are available, try SETACL before ++ ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL ++ can. */ ++ ++ if (count > 0) ++ { ++ ret = (dest_desc != -1 ++ ? facl (dest_desc, SETACL, count, entries) ++ : acl (dst_name, SETACL, count, entries)); ++ if (ret < 0 && saved_errno == 0) ++ { ++ saved_errno = errno; ++ if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) ++ && !acl_nontrivial (count, entries)) ++ saved_errno = 0; ++ } ++ else ++ did_chmod = 1; ++ } ++ free (entries); ++ ++# ifdef ACE_GETACL ++ if (ace_count > 0) ++ { ++ ret = (dest_desc != -1 ++ ? facl (dest_desc, ACE_SETACL, ace_count, ace_entries) ++ : acl (dst_name, ACE_SETACL, ace_count, ace_entries)); ++ if (ret < 0 && saved_errno == 0) ++ { ++ saved_errno = errno; ++ if ((errno == ENOSYS || errno == EINVAL || errno == ENOTSUP) ++ && !acl_ace_nontrivial (ace_count, ace_entries)) ++ saved_errno = 0; ++ } ++ } ++ free (ace_entries); ++# endif ++ ++ if (MODE_INSIDE_ACL ++ && did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0)) ++ { ++ /* We did not call chmod so far, and either the mode and the ACL are ++ separate or special bits are to be set which don't fit into ACLs. */ ++ ++ if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0) ++ { ++ if (saved_errno == 0) ++ saved_errno = errno; ++ } ++ } ++ ++ if (saved_errno) ++ { ++ errno = saved_errno; ++ return -1; ++ } ++ return 0; ++ ++#elif USE_ACL && HAVE_GETACL /* HP-UX */ ++ ++ struct acl_entry entries[NACLENTRIES]; ++ int count; ++# if HAVE_ACLV_H ++ struct acl aclv_entries[NACLVENTRIES]; ++ int aclv_count; ++# endif ++ int did_chmod; ++ int saved_errno; ++ int ret; ++ ++ count = (source_desc != -1 ++ ? fgetacl (source_desc, NACLENTRIES, entries) ++ : getacl (src_name, NACLENTRIES, entries)); ++ ++ if (count < 0) ++ { ++ if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP) ++ count = 0; ++ else ++ return -2; ++ } ++ else if (count > 0) ++ { ++ if (count > NACLENTRIES) ++ /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */ ++ abort (); ++ } ++ ++# if HAVE_ACLV_H ++ aclv_count = acl ((char *) src_name, ACL_GET, NACLVENTRIES, aclv_entries); ++ ++ if (aclv_count < 0) ++ { ++ if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) ++ count = 0; ++ else ++ return -2; ++ } ++ else if (aclv_count > 0) ++ { ++ if (aclv_count > NACLVENTRIES) ++ /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation. */ ++ abort (); ++ } ++# endif ++ ++ if (count == 0) ++# if HAVE_ACLV_H ++ if (aclv_count == 0) ++# endif ++ return qset_acl (dst_name, dest_desc, mode); ++ ++ did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */ ++ saved_errno = 0; /* the first non-ignorable error code */ ++ ++ if (count > 0) ++ { ++ ret = (dest_desc != -1 ++ ? fsetacl (dest_desc, count, entries) ++ : setacl (dst_name, count, entries)); ++ if (ret < 0 && saved_errno == 0) ++ { ++ saved_errno = errno; ++ if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP) ++ { ++ struct stat source_statbuf; ++ ++ if ((source_desc != -1 ++ ? fstat (source_desc, &source_statbuf) ++ : stat (src_name, &source_statbuf)) == 0) ++ { ++ if (!acl_nontrivial (count, entries, &source_statbuf)) ++ saved_errno = 0; ++ } ++ else ++ saved_errno = errno; ++ } ++ } ++ else ++ did_chmod = 1; ++ } ++ ++# if HAVE_ACLV_H ++ if (aclv_count > 0) ++ { ++ ret = acl ((char *) dst_name, ACL_SET, aclv_count, aclv_entries); ++ if (ret < 0 && saved_errno == 0) ++ { ++ saved_errno = errno; ++ if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) ++ { ++ if (!aclv_nontrivial (aclv_count, aclv_entries)) ++ saved_errno = 0; ++ } ++ } ++ else ++ did_chmod = 1; ++ } ++# endif ++ ++ if (did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0)) ++ { ++ /* We did not call chmod so far, and special bits are to be set which ++ don't fit into ACLs. */ ++ ++ if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0) ++ { ++ if (saved_errno == 0) ++ saved_errno = errno; ++ } ++ } ++ ++ if (saved_errno) ++ { ++ errno = saved_errno; ++ return -1; ++ } ++ return 0; ++ ++#elif USE_ACL && HAVE_ACLX_GET && 0 /* AIX */ ++ ++ /* TODO */ ++ ++#elif USE_ACL && HAVE_STATACL /* older AIX */ ++ ++ union { struct acl a; char room[4096]; } u; ++ int ret; ++ ++ if ((source_desc != -1 ++ ? fstatacl (source_desc, STX_NORMAL, &u.a, sizeof (u)) ++ : statacl (src_name, STX_NORMAL, &u.a, sizeof (u))) ++ < 0) ++ return -2; ++ ++ ret = (dest_desc != -1 ++ ? fchacl (dest_desc, &u.a, u.a.acl_len) ++ : chacl (dst_name, &u.a, u.a.acl_len)); ++ if (ret < 0) ++ { ++ int saved_errno = errno; ++ ++ chmod_or_fchmod (dst_name, dest_desc, mode); ++ errno = saved_errno; ++ return -1; ++ } ++ ++ /* No need to call chmod_or_fchmod at this point, since the mode bits ++ S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL. */ ++ ++ return 0; ++ ++#elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */ ++ ++ struct acl entries[NACLENTRIES]; ++ int count; ++ int ret; ++ ++ count = acl ((char *) src_name, ACL_GET, NACLENTRIES, entries); ++ ++ if (count < 0) ++ { ++ if (0) ++ count = 0; ++ else ++ return -2; ++ } ++ else if (count > 0) ++ { ++ if (count > NACLENTRIES) ++ /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */ ++ abort (); ++ } ++ ++ if (count == 0) ++ return qset_acl (dst_name, dest_desc, mode); ++ ++ ret = acl ((char *) dst_name, ACL_SET, count, entries); ++ if (ret < 0) ++ { ++ int saved_errno = errno; ++ ++ if (0) ++ { ++ if (!acl_nontrivial (count, entries)) ++ return chmod_or_fchmod (dst_name, dest_desc, mode); ++ } ++ ++ chmod_or_fchmod (dst_name, dest_desc, mode); ++ errno = saved_errno; ++ return -1; ++ } ++ ++ if (mode & (S_ISUID | S_ISGID | S_ISVTX)) ++ { ++ /* We did not call chmod so far, and either the mode and the ACL are ++ separate or special bits are to be set which don't fit into ACLs. */ ++ ++ return chmod_or_fchmod (dst_name, dest_desc, mode); ++ } ++ return 0; ++ ++#else ++ ++ return qset_acl (dst_name, dest_desc, mode); ++ ++#endif ++} ++ ++ ++/* Copy access control lists from one file to another. If SOURCE_DESC is ++ a valid file descriptor, use file descriptor operations, else use ++ filename based operations on SRC_NAME. Likewise for DEST_DESC and ++ DST_NAME. ++ If access control lists are not available, fchmod the target file to ++ MODE. Also sets the non-permission bits of the destination file ++ (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set. ++ Return 0 if successful, otherwise output a diagnostic and return a ++ negative error code. */ ++ ++int ++copy_acl (const char *src_name, int source_desc, const char *dst_name, ++ int dest_desc, mode_t mode) ++{ ++ int ret = qcopy_acl (src_name, source_desc, dst_name, dest_desc, mode); ++ switch (ret) ++ { ++ case -2: ++ error (0, errno, "%s", quote (src_name)); ++ break; ++ ++ case -1: ++ error (0, errno, _("preserving permissions for %s"), quote (dst_name)); ++ break; ++ ++ default: ++ break; ++ } ++ return ret; ++} +diff --git a/gnu/file-has-acl.c b/gnu/file-has-acl.c +new file mode 100644 +index 0000000..17872a5 +--- /dev/null ++++ b/gnu/file-has-acl.c +@@ -0,0 +1,920 @@ ++/* -*- buffer-read-only: t -*- vi: set ro: */ ++/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ ++/* Test whether a file has a nontrivial access control list. ++ ++ Copyright (C) 2002-2003, 2005-2012 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++ Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */ ++ ++/* Without this pragma, gcc 4.7.0 20120126 may suggest that the ++ file_has_acl function might be candidate for attribute 'const' */ ++#if (__GNUC__ == 4 && 6 <= __GNUC_MINOR__) || 4 < __GNUC__ ++# pragma GCC diagnostic ignored "-Wsuggest-attribute=const" ++#endif ++ ++#include ++ ++#include "acl.h" ++ ++#include "acl-internal.h" ++ ++ ++#if USE_ACL && HAVE_ACL_GET_FILE ++ ++# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */ ++ ++/* ACL is an ACL, from a file, stored as type ACL_TYPE_EXTENDED. ++ Return 1 if the given ACL is non-trivial. ++ Return 0 if it is trivial. */ ++int ++acl_extended_nontrivial (acl_t acl) ++{ ++ /* acl is non-trivial if it is non-empty. */ ++ return (acl_entries (acl) > 0); ++} ++ ++# else /* Linux, FreeBSD, IRIX, Tru64 */ ++ ++/* ACL is an ACL, from a file, stored as type ACL_TYPE_ACCESS. ++ Return 1 if the given ACL is non-trivial. ++ Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. ++ Return -1 and set errno upon failure to determine it. */ ++int ++acl_access_nontrivial (acl_t acl) ++{ ++ /* acl is non-trivial if it has some entries other than for "user::", ++ "group::", and "other::". Normally these three should be present ++ at least, allowing us to write ++ return (3 < acl_entries (acl)); ++ but the following code is more robust. */ ++# if HAVE_ACL_FIRST_ENTRY /* Linux, FreeBSD */ ++ ++ acl_entry_t ace; ++ int got_one; ++ ++ for (got_one = acl_get_entry (acl, ACL_FIRST_ENTRY, &ace); ++ got_one > 0; ++ got_one = acl_get_entry (acl, ACL_NEXT_ENTRY, &ace)) ++ { ++ acl_tag_t tag; ++ if (acl_get_tag_type (ace, &tag) < 0) ++ return -1; ++ if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || tag == ACL_OTHER)) ++ return 1; ++ } ++ return got_one; ++ ++# else /* IRIX, Tru64 */ ++# if HAVE_ACL_TO_SHORT_TEXT /* IRIX */ ++ /* Don't use acl_get_entry: it is undocumented. */ ++ ++ int count = acl->acl_cnt; ++ int i; ++ ++ for (i = 0; i < count; i++) ++ { ++ acl_entry_t ace = &acl->acl_entry[i]; ++ acl_tag_t tag = ace->ae_tag; ++ ++ if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ ++ || tag == ACL_OTHER_OBJ)) ++ return 1; ++ } ++ return 0; ++ ++# endif ++# if HAVE_ACL_FREE_TEXT /* Tru64 */ ++ /* Don't use acl_get_entry: it takes only one argument and does not work. */ ++ ++ int count = acl->acl_num; ++ acl_entry_t ace; ++ ++ for (ace = acl->acl_first; count > 0; ace = ace->next, count--) ++ { ++ acl_tag_t tag; ++ acl_perm_t perm; ++ ++ tag = ace->entry->acl_type; ++ if (!(tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || tag == ACL_OTHER)) ++ return 1; ++ ++ perm = ace->entry->acl_perm; ++ /* On Tru64, perm can also contain non-standard bits such as ++ PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ... */ ++ if ((perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)) != 0) ++ return 1; ++ } ++ return 0; ++ ++# endif ++# endif ++} ++ ++# endif ++ ++ ++#elif USE_ACL && HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ ++ ++/* Test an ACL retrieved with GETACL. ++ Return 1 if the given ACL, consisting of COUNT entries, is non-trivial. ++ Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ ++int ++acl_nontrivial (int count, aclent_t *entries) ++{ ++ int i; ++ ++ for (i = 0; i < count; i++) ++ { ++ aclent_t *ace = &entries[i]; ++ ++ /* Note: If ace->a_type = USER_OBJ, ace->a_id is the st_uid from stat(). ++ If ace->a_type = GROUP_OBJ, ace->a_id is the st_gid from stat(). ++ We don't need to check ace->a_id in these cases. */ ++ if (!(ace->a_type == USER_OBJ ++ || ace->a_type == GROUP_OBJ ++ || ace->a_type == OTHER_OBJ ++ /* Note: Cygwin does not return a CLASS_OBJ ("mask:") entry ++ sometimes. */ ++ || ace->a_type == CLASS_OBJ)) ++ return 1; ++ } ++ return 0; ++} ++ ++# ifdef ACE_GETACL ++ ++/* A shortcut for a bitmask. */ ++# define NEW_ACE_WRITEA_DATA (NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA) ++ ++/* Test an ACL retrieved with ACE_GETACL. ++ Return 1 if the given ACL, consisting of COUNT entries, is non-trivial. ++ Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ ++int ++acl_ace_nontrivial (int count, ace_t *entries) ++{ ++ int i; ++ ++ /* The flags in the ace_t structure changed in a binary incompatible way ++ when ACL_NO_TRIVIAL etc. were introduced in version 1.15. ++ How to distinguish the two conventions at runtime? ++ In the old convention, usually three ACEs have a_flags = ACE_OWNER / ++ ACE_GROUP / ACE_OTHER, in the range 0x0100..0x0400. In the new ++ convention, these values are not used. */ ++ int old_convention = 0; ++ ++ for (i = 0; i < count; i++) ++ if (entries[i].a_flags & (OLD_ACE_OWNER | OLD_ACE_GROUP | OLD_ACE_OTHER)) ++ { ++ old_convention = 1; ++ break; ++ } ++ ++ if (old_convention) ++ /* Running on Solaris 10. */ ++ for (i = 0; i < count; i++) ++ { ++ ace_t *ace = &entries[i]; ++ ++ /* Note: ++ If ace->a_flags = ACE_OWNER, ace->a_who is the st_uid from stat(). ++ If ace->a_flags = ACE_GROUP, ace->a_who is the st_gid from stat(). ++ We don't need to check ace->a_who in these cases. */ ++ if (!(ace->a_type == OLD_ALLOW ++ && (ace->a_flags == OLD_ACE_OWNER ++ || ace->a_flags == OLD_ACE_GROUP ++ || ace->a_flags == OLD_ACE_OTHER))) ++ return 1; ++ } ++ else ++ { ++ /* Running on Solaris 10 (newer version) or Solaris 11. */ ++ unsigned int access_masks[6] = ++ { ++ 0, /* owner@ deny */ ++ 0, /* owner@ allow */ ++ 0, /* group@ deny */ ++ 0, /* group@ allow */ ++ 0, /* everyone@ deny */ ++ 0 /* everyone@ allow */ ++ }; ++ ++ for (i = 0; i < count; i++) ++ { ++ ace_t *ace = &entries[i]; ++ unsigned int index1; ++ unsigned int index2; ++ ++ if (ace->a_type == NEW_ACE_ACCESS_ALLOWED_ACE_TYPE) ++ index1 = 1; ++ else if (ace->a_type == NEW_ACE_ACCESS_DENIED_ACE_TYPE) ++ index1 = 0; ++ else ++ return 1; ++ ++ if (ace->a_flags == NEW_ACE_OWNER) ++ index2 = 0; ++ else if (ace->a_flags == (NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP)) ++ index2 = 2; ++ else if (ace->a_flags == NEW_ACE_EVERYONE) ++ index2 = 4; ++ else ++ return 1; ++ ++ access_masks[index1 + index2] |= ace->a_access_mask; ++ } ++ ++ /* The same bit shouldn't be both allowed and denied. */ ++ if (access_masks[0] & access_masks[1]) ++ return 1; ++ if (access_masks[2] & access_masks[3]) ++ return 1; ++ if (access_masks[4] & access_masks[5]) ++ return 1; ++ ++ /* Check minimum masks. */ ++ if ((NEW_ACE_WRITE_NAMED_ATTRS ++ | NEW_ACE_WRITE_ATTRIBUTES ++ | NEW_ACE_WRITE_ACL ++ | NEW_ACE_WRITE_OWNER) ++ & ~ access_masks[1]) ++ return 1; ++ access_masks[1] &= ~(NEW_ACE_WRITE_NAMED_ATTRS ++ | NEW_ACE_WRITE_ATTRIBUTES ++ | NEW_ACE_WRITE_ACL ++ | NEW_ACE_WRITE_OWNER); ++ if ((NEW_ACE_READ_NAMED_ATTRS ++ | NEW_ACE_READ_ATTRIBUTES ++ | NEW_ACE_READ_ACL ++ | NEW_ACE_SYNCHRONIZE) ++ & ~ access_masks[5]) ++ return 1; ++ access_masks[5] &= ~(NEW_ACE_READ_NAMED_ATTRS ++ | NEW_ACE_READ_ATTRIBUTES ++ | NEW_ACE_READ_ACL ++ | NEW_ACE_SYNCHRONIZE); ++ ++ /* Check the allowed or denied bits. */ ++ switch ((access_masks[0] | access_masks[1]) ++ & ~(NEW_ACE_READ_NAMED_ATTRS ++ | NEW_ACE_READ_ATTRIBUTES ++ | NEW_ACE_READ_ACL ++ | NEW_ACE_SYNCHRONIZE)) ++ { ++ case 0: ++ case NEW_ACE_READ_DATA: ++ case NEW_ACE_WRITEA_DATA: ++ case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA: ++ case NEW_ACE_EXECUTE: ++ case NEW_ACE_READ_DATA | NEW_ACE_EXECUTE: ++ case NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE: ++ case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE: ++ break; ++ default: ++ return 1; ++ } ++ switch ((access_masks[2] | access_masks[3]) ++ & ~(NEW_ACE_READ_NAMED_ATTRS ++ | NEW_ACE_READ_ATTRIBUTES ++ | NEW_ACE_READ_ACL ++ | NEW_ACE_SYNCHRONIZE)) ++ { ++ case 0: ++ case NEW_ACE_READ_DATA: ++ case NEW_ACE_WRITEA_DATA: ++ case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA: ++ case NEW_ACE_EXECUTE: ++ case NEW_ACE_READ_DATA | NEW_ACE_EXECUTE: ++ case NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE: ++ case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE: ++ break; ++ default: ++ return 1; ++ } ++ switch ((access_masks[4] | access_masks[5]) ++ & ~(NEW_ACE_WRITE_NAMED_ATTRS ++ | NEW_ACE_WRITE_ATTRIBUTES ++ | NEW_ACE_WRITE_ACL ++ | NEW_ACE_WRITE_OWNER)) ++ { ++ case 0: ++ case NEW_ACE_READ_DATA: ++ case NEW_ACE_WRITEA_DATA: ++ case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA: ++ case NEW_ACE_EXECUTE: ++ case NEW_ACE_READ_DATA | NEW_ACE_EXECUTE: ++ case NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE: ++ case NEW_ACE_READ_DATA | NEW_ACE_WRITEA_DATA | NEW_ACE_EXECUTE: ++ break; ++ default: ++ return 1; ++ } ++ ++ /* Check that the NEW_ACE_WRITE_DATA and NEW_ACE_APPEND_DATA bits are ++ either both allowed or both denied. */ ++ if (((access_masks[0] & NEW_ACE_WRITE_DATA) != 0) ++ != ((access_masks[0] & NEW_ACE_APPEND_DATA) != 0)) ++ return 1; ++ if (((access_masks[2] & NEW_ACE_WRITE_DATA) != 0) ++ != ((access_masks[2] & NEW_ACE_APPEND_DATA) != 0)) ++ return 1; ++ if (((access_masks[4] & NEW_ACE_WRITE_DATA) != 0) ++ != ((access_masks[4] & NEW_ACE_APPEND_DATA) != 0)) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++# endif ++ ++#elif USE_ACL && HAVE_GETACL /* HP-UX */ ++ ++/* Return 1 if the given ACL is non-trivial. ++ Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ ++int ++acl_nontrivial (int count, struct acl_entry *entries, struct stat *sb) ++{ ++ int i; ++ ++ for (i = 0; i < count; i++) ++ { ++ struct acl_entry *ace = &entries[i]; ++ ++ if (!((ace->uid == sb->st_uid && ace->gid == ACL_NSGROUP) ++ || (ace->uid == ACL_NSUSER && ace->gid == sb->st_gid) ++ || (ace->uid == ACL_NSUSER && ace->gid == ACL_NSGROUP))) ++ return 1; ++ } ++ return 0; ++} ++ ++# if HAVE_ACLV_H /* HP-UX >= 11.11 */ ++ ++/* Return 1 if the given ACL is non-trivial. ++ Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ ++int ++aclv_nontrivial (int count, struct acl *entries) ++{ ++ int i; ++ ++ for (i = 0; i < count; i++) ++ { ++ struct acl *ace = &entries[i]; ++ ++ /* Note: If ace->a_type = USER_OBJ, ace->a_id is the st_uid from stat(). ++ If ace->a_type = GROUP_OBJ, ace->a_id is the st_gid from stat(). ++ We don't need to check ace->a_id in these cases. */ ++ if (!(ace->a_type == USER_OBJ /* no need to check ace->a_id here */ ++ || ace->a_type == GROUP_OBJ /* no need to check ace->a_id here */ ++ || ace->a_type == CLASS_OBJ ++ || ace->a_type == OTHER_OBJ)) ++ return 1; ++ } ++ return 0; ++} ++ ++# endif ++ ++#elif USE_ACL && (HAVE_ACLX_GET || HAVE_STATACL) /* AIX */ ++ ++/* Return 1 if the given ACL is non-trivial. ++ Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ ++int ++acl_nontrivial (struct acl *a) ++{ ++ /* The normal way to iterate through an ACL is like this: ++ struct acl_entry *ace; ++ for (ace = a->acl_ext; ace != acl_last (a); ace = acl_nxt (ace)) ++ { ++ struct ace_id *aei; ++ switch (ace->ace_type) ++ { ++ case ACC_PERMIT: ++ case ACC_DENY: ++ case ACC_SPECIFY: ++ ...; ++ } ++ for (aei = ace->ace_id; aei != id_last (ace); aei = id_nxt (aei)) ++ ... ++ } ++ */ ++ return (acl_last (a) != a->acl_ext ? 1 : 0); ++} ++ ++# if HAVE_ACLX_GET && defined ACL_AIX_WIP /* newer AIX */ ++ ++/* Return 1 if the given ACL is non-trivial. ++ Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ ++int ++acl_nfs4_nontrivial (nfs4_acl_int_t *a) ++{ ++# if 1 /* let's try this first */ ++ return (a->aclEntryN > 0 ? 1 : 0); ++# else ++ int count = a->aclEntryN; ++ int i; ++ ++ for (i = 0; i < count; i++) ++ { ++ nfs4_ace_int_t *ace = &a->aclEntry[i]; ++ ++ if (!((ace->flags & ACE4_ID_SPECIAL) != 0 ++ && (ace->aceWho.special_whoid == ACE4_WHO_OWNER ++ || ace->aceWho.special_whoid == ACE4_WHO_GROUP ++ || ace->aceWho.special_whoid == ACE4_WHO_EVERYONE) ++ && ace->aceType == ACE4_ACCESS_ALLOWED_ACE_TYPE ++ && ace->aceFlags == 0 ++ && (ace->aceMask & ~(ACE4_READ_DATA | ACE4_LIST_DIRECTORY ++ | ACE4_WRITE_DATA | ACE4_ADD_FILE ++ | ACE4_EXECUTE)) == 0)) ++ return 1; ++ } ++ return 0; ++# endif ++} ++ ++# endif ++ ++#elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */ ++ ++/* Test an ACL retrieved with ACL_GET. ++ Return 1 if the given ACL, consisting of COUNT entries, is non-trivial. ++ Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ ++int ++acl_nontrivial (int count, struct acl *entries) ++{ ++ int i; ++ ++ for (i = 0; i < count; i++) ++ { ++ struct acl *ace = &entries[i]; ++ ++ /* Note: If ace->a_type = USER_OBJ, ace->a_id is the st_uid from stat(). ++ If ace->a_type = GROUP_OBJ, ace->a_id is the st_gid from stat(). ++ We don't need to check ace->a_id in these cases. */ ++ if (!(ace->a_type == USER_OBJ /* no need to check ace->a_id here */ ++ || ace->a_type == GROUP_OBJ /* no need to check ace->a_id here */ ++ || ace->a_type == CLASS_OBJ ++ || ace->a_type == OTHER_OBJ)) ++ return 1; ++ } ++ return 0; ++} ++ ++#endif ++ ++ ++/* Return 1 if NAME has a nontrivial access control list, 0 if NAME ++ only has no or a base access control list, and -1 (setting errno) ++ on error. SB must be set to the stat buffer of NAME, obtained ++ through stat() or lstat(). */ ++ ++int ++file_has_acl (char const *name, struct stat const *sb) ++{ ++#if USE_ACL ++ if (! S_ISLNK (sb->st_mode)) ++ { ++# if HAVE_ACL_GET_FILE ++ ++ /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */ ++ /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */ ++ int ret; ++ ++ if (HAVE_ACL_EXTENDED_FILE) /* Linux */ ++ { ++ /* On Linux, acl_extended_file is an optimized function: It only ++ makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for ++ ACL_TYPE_DEFAULT. */ ++ ret = acl_extended_file (name); ++ } ++ else /* FreeBSD, Mac OS X, IRIX, Tru64 */ ++ { ++# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */ ++ /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS) ++ and acl_get_file (name, ACL_TYPE_DEFAULT) ++ always return NULL / EINVAL. There is no point in making ++ these two useless calls. The real ACL is retrieved through ++ acl_get_file (name, ACL_TYPE_EXTENDED). */ ++ acl_t acl = acl_get_file (name, ACL_TYPE_EXTENDED); ++ if (acl) ++ { ++ ret = acl_extended_nontrivial (acl); ++ acl_free (acl); ++ } ++ else ++ ret = -1; ++# else /* FreeBSD, IRIX, Tru64 */ ++ acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS); ++ if (acl) ++ { ++ int saved_errno; ++ ++ ret = acl_access_nontrivial (acl); ++ saved_errno = errno; ++ acl_free (acl); ++ errno = saved_errno; ++# if HAVE_ACL_FREE_TEXT /* Tru64 */ ++ /* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always ++ returns NULL with errno not set. There is no point in ++ making this call. */ ++# else /* FreeBSD, IRIX */ ++ /* On Linux, FreeBSD, IRIX, acl_get_file (name, ACL_TYPE_ACCESS) ++ and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory ++ either both succeed or both fail; it depends on the ++ file system. Therefore there is no point in making the second ++ call if the first one already failed. */ ++ if (ret == 0 && S_ISDIR (sb->st_mode)) ++ { ++ acl = acl_get_file (name, ACL_TYPE_DEFAULT); ++ if (acl) ++ { ++ ret = (0 < acl_entries (acl)); ++ acl_free (acl); ++ } ++ else ++ ret = -1; ++ } ++# endif ++ } ++ else ++ ret = -1; ++# endif ++ } ++ if (ret < 0) ++ return ACL_NOT_WELL_SUPPORTED (errno) ? 0 : -1; ++ return ret; ++ ++# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ ++ ++# if defined ACL_NO_TRIVIAL ++ ++ /* Solaris 10 (newer version), which has additional API declared in ++ (acl_t) and implemented in libsec (acl_set, acl_trivial, ++ acl_fromtext, ...). */ ++ return acl_trivial (name); ++ ++# else /* Solaris, Cygwin, general case */ ++ ++ /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions ++ of Unixware. The acl() call returns the access and default ACL both ++ at once. */ ++ { ++ /* Initially, try to read the entries into a stack-allocated buffer. ++ Use malloc if it does not fit. */ ++ enum ++ { ++ alloc_init = 4000 / sizeof (aclent_t), /* >= 3 */ ++ alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (aclent_t)) ++ }; ++ aclent_t buf[alloc_init]; ++ size_t alloc = alloc_init; ++ aclent_t *entries = buf; ++ aclent_t *malloced = NULL; ++ int count; ++ ++ for (;;) ++ { ++ count = acl (name, GETACL, alloc, entries); ++ if (count < 0 && errno == ENOSPC) ++ { ++ /* Increase the size of the buffer. */ ++ free (malloced); ++ if (alloc > alloc_max / 2) ++ { ++ errno = ENOMEM; ++ return -1; ++ } ++ alloc = 2 * alloc; /* <= alloc_max */ ++ entries = malloced = ++ (aclent_t *) malloc (alloc * sizeof (aclent_t)); ++ if (entries == NULL) ++ { ++ errno = ENOMEM; ++ return -1; ++ } ++ continue; ++ } ++ break; ++ } ++ if (count < 0) ++ { ++ if (errno == ENOSYS || errno == ENOTSUP) ++ ; ++ else ++ { ++ int saved_errno = errno; ++ free (malloced); ++ errno = saved_errno; ++ return -1; ++ } ++ } ++ else if (count == 0) ++ ; ++ else ++ { ++ /* Don't use MIN_ACL_ENTRIES: It's set to 4 on Cygwin, but Cygwin ++ returns only 3 entries for files with no ACL. But this is safe: ++ If there are more than 4 entries, there cannot be only the ++ "user::", "group::", "other:", and "mask:" entries. */ ++ if (count > 4) ++ { ++ free (malloced); ++ return 1; ++ } ++ ++ if (acl_nontrivial (count, entries)) ++ { ++ free (malloced); ++ return 1; ++ } ++ } ++ free (malloced); ++ } ++ ++# ifdef ACE_GETACL ++ /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4 ++ file systems (whereas the other ones are used in UFS file systems). */ ++ { ++ /* Initially, try to read the entries into a stack-allocated buffer. ++ Use malloc if it does not fit. */ ++ enum ++ { ++ alloc_init = 4000 / sizeof (ace_t), /* >= 3 */ ++ alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t)) ++ }; ++ ace_t buf[alloc_init]; ++ size_t alloc = alloc_init; ++ ace_t *entries = buf; ++ ace_t *malloced = NULL; ++ int count; ++ ++ for (;;) ++ { ++ count = acl (name, ACE_GETACL, alloc, entries); ++ if (count < 0 && errno == ENOSPC) ++ { ++ /* Increase the size of the buffer. */ ++ free (malloced); ++ if (alloc > alloc_max / 2) ++ { ++ errno = ENOMEM; ++ return -1; ++ } ++ alloc = 2 * alloc; /* <= alloc_max */ ++ entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t)); ++ if (entries == NULL) ++ { ++ errno = ENOMEM; ++ return -1; ++ } ++ continue; ++ } ++ break; ++ } ++ if (count < 0) ++ { ++ if (errno == ENOSYS || errno == EINVAL) ++ ; ++ else ++ { ++ int saved_errno = errno; ++ free (malloced); ++ errno = saved_errno; ++ return -1; ++ } ++ } ++ else if (count == 0) ++ ; ++ else ++ { ++ /* In the old (original Solaris 10) convention: ++ If there are more than 3 entries, there cannot be only the ++ ACE_OWNER, ACE_GROUP, ACE_OTHER entries. ++ In the newer Solaris 10 and Solaris 11 convention: ++ If there are more than 6 entries, there cannot be only the ++ ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with ++ NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with ++ NEW_ACE_ACCESS_DENIED_ACE_TYPE. */ ++ if (count > 6) ++ { ++ free (malloced); ++ return 1; ++ } ++ ++ if (acl_ace_nontrivial (count, entries)) ++ { ++ free (malloced); ++ return 1; ++ } ++ } ++ free (malloced); ++ } ++# endif ++ ++ return 0; ++# endif ++ ++# elif HAVE_GETACL /* HP-UX */ ++ ++ { ++ struct acl_entry entries[NACLENTRIES]; ++ int count; ++ ++ count = getacl (name, NACLENTRIES, entries); ++ ++ if (count < 0) ++ { ++ /* ENOSYS is seen on newer HP-UX versions. ++ EOPNOTSUPP is typically seen on NFS mounts. ++ ENOTSUP was seen on Quantum StorNext file systems (cvfs). */ ++ if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP) ++ ; ++ else ++ return -1; ++ } ++ else if (count == 0) ++ return 0; ++ else /* count > 0 */ ++ { ++ if (count > NACLENTRIES) ++ /* If NACLENTRIES cannot be trusted, use dynamic memory ++ allocation. */ ++ abort (); ++ ++ /* If there are more than 3 entries, there cannot be only the ++ (uid,%), (%,gid), (%,%) entries. */ ++ if (count > 3) ++ return 1; ++ ++ { ++ struct stat statbuf; ++ ++ if (stat (name, &statbuf) < 0) ++ return -1; ++ ++ return acl_nontrivial (count, entries, &statbuf); ++ } ++ } ++ } ++ ++# if HAVE_ACLV_H /* HP-UX >= 11.11 */ ++ ++ { ++ struct acl entries[NACLVENTRIES]; ++ int count; ++ ++ count = acl ((char *) name, ACL_GET, NACLVENTRIES, entries); ++ ++ if (count < 0) ++ { ++ /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23. ++ EINVAL is seen on NFS in HP-UX 11.31. */ ++ if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) ++ ; ++ else ++ return -1; ++ } ++ else if (count == 0) ++ return 0; ++ else /* count > 0 */ ++ { ++ if (count > NACLVENTRIES) ++ /* If NACLVENTRIES cannot be trusted, use dynamic memory ++ allocation. */ ++ abort (); ++ ++ /* If there are more than 4 entries, there cannot be only the ++ four base ACL entries. */ ++ if (count > 4) ++ return 1; ++ ++ return aclv_nontrivial (count, entries); ++ } ++ } ++ ++# endif ++ ++# elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */ ++ ++ acl_type_t type; ++ char aclbuf[1024]; ++ void *acl = aclbuf; ++ size_t aclsize = sizeof (aclbuf); ++ mode_t mode; ++ ++ for (;;) ++ { ++ /* The docs say that type being 0 is equivalent to ACL_ANY, but it ++ is not true, in AIX 5.3. */ ++ type.u64 = ACL_ANY; ++ if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0) ++ break; ++ if (errno == ENOSYS) ++ return 0; ++ if (errno != ENOSPC) ++ { ++ if (acl != aclbuf) ++ { ++ int saved_errno = errno; ++ free (acl); ++ errno = saved_errno; ++ } ++ return -1; ++ } ++ aclsize = 2 * aclsize; ++ if (acl != aclbuf) ++ free (acl); ++ acl = malloc (aclsize); ++ if (acl == NULL) ++ { ++ errno = ENOMEM; ++ return -1; ++ } ++ } ++ ++ if (type.u64 == ACL_AIXC) ++ { ++ int result = acl_nontrivial ((struct acl *) acl); ++ if (acl != aclbuf) ++ free (acl); ++ return result; ++ } ++ else if (type.u64 == ACL_NFS4) ++ { ++ int result = acl_nfs4_nontrivial ((nfs4_acl_int_t *) acl); ++ if (acl != aclbuf) ++ free (acl); ++ return result; ++ } ++ else ++ { ++ /* A newer type of ACL has been introduced in the system. ++ We should better support it. */ ++ if (acl != aclbuf) ++ free (acl); ++ errno = EINVAL; ++ return -1; ++ } ++ ++# elif HAVE_STATACL /* older AIX */ ++ ++ union { struct acl a; char room[4096]; } u; ++ ++ if (statacl (name, STX_NORMAL, &u.a, sizeof (u)) < 0) ++ return -1; ++ ++ return acl_nontrivial (&u.a); ++ ++# elif HAVE_ACLSORT /* NonStop Kernel */ ++ ++ { ++ struct acl entries[NACLENTRIES]; ++ int count; ++ ++ count = acl ((char *) name, ACL_GET, NACLENTRIES, entries); ++ ++ if (count < 0) ++ { ++ if (errno == ENOSYS || errno == ENOTSUP) ++ ; ++ else ++ return -1; ++ } ++ else if (count == 0) ++ return 0; ++ else /* count > 0 */ ++ { ++ if (count > NACLENTRIES) ++ /* If NACLENTRIES cannot be trusted, use dynamic memory ++ allocation. */ ++ abort (); ++ ++ /* If there are more than 4 entries, there cannot be only the ++ four base ACL entries. */ ++ if (count > 4) ++ return 1; ++ ++ return acl_nontrivial (count, entries); ++ } ++ } ++ ++# endif ++ } ++#endif ++ ++ return 0; ++} +diff --git a/gnu/getfilecon.c b/gnu/getfilecon.c +new file mode 100644 +index 0000000..4a0f40d +--- /dev/null ++++ b/gnu/getfilecon.c +@@ -0,0 +1,88 @@ ++/* -*- buffer-read-only: t -*- vi: set ro: */ ++/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ ++/* wrap getfilecon, lgetfilecon, and fgetfilecon ++ Copyright (C) 2009-2012 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3, or (at your option) ++ any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, see . */ ++ ++/* written by Jim Meyering */ ++ ++#include ++ ++#include ++ ++#include ++#include ++#include ++ ++/* FIXME: remove this once there is an errno-gnu module ++ that guarantees the definition of ENODATA. */ ++#ifndef ENODATA ++# define ENODATA ENOTSUP ++#endif ++ ++#undef getfilecon ++#undef lgetfilecon ++#undef fgetfilecon ++int getfilecon (char const *file, security_context_t *con); ++int lgetfilecon (char const *file, security_context_t *con); ++int fgetfilecon (int fd, security_context_t *con); ++ ++/* getfilecon, lgetfilecon, and fgetfilecon can all misbehave, be it ++ via an old version of libselinux where these would return 0 and set the ++ result context to NULL, or via a modern kernel+lib operating on a file ++ from a disk whose attributes were set by a kernel from around 2006. ++ In that latter case, the functions return a length of 10 for the ++ "unlabeled" context. Map both failures to a return value of -1, and ++ set errno to ENOTSUP in the first case, and ENODATA in the latter. */ ++ ++static inline int ++map_to_failure (int ret, security_context_t *con) ++{ ++ if (ret == 0) ++ { ++ errno = ENOTSUP; ++ return -1; ++ } ++ ++ if (ret == 10 && strcmp (*con, "unlabeled") == 0) ++ { ++ freecon (*con); ++ errno = ENODATA; ++ return -1; ++ } ++ ++ return ret; ++} ++ ++int ++rpl_getfilecon (char const *file, security_context_t *con) ++{ ++ int ret = getfilecon (file, con); ++ return map_to_failure (ret, con); ++} ++ ++int ++rpl_lgetfilecon (char const *file, security_context_t *con) ++{ ++ int ret = lgetfilecon (file, con); ++ return map_to_failure (ret, con); ++} ++ ++int ++rpl_fgetfilecon (int fd, security_context_t *con) ++{ ++ int ret = fgetfilecon (fd, con); ++ return map_to_failure (ret, con); ++} +diff --git a/gnu/se-context.in.h b/gnu/se-context.in.h +new file mode 100644 +index 0000000..adb13ba +--- /dev/null ++++ b/gnu/se-context.in.h +@@ -0,0 +1,30 @@ ++/* -*- buffer-read-only: t -*- vi: set ro: */ ++/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ ++#ifndef SELINUX_CONTEXT_H ++# define SELINUX_CONTEXT_H ++ ++# include ++ ++/* The definition of _GL_UNUSED_PARAMETER is copied here. */ ++ ++typedef int context_t; ++static inline context_t context_new (char const *s _GL_UNUSED_PARAMETER) ++ { errno = ENOTSUP; return 0; } ++static inline char *context_str (context_t con _GL_UNUSED_PARAMETER) ++ { errno = ENOTSUP; return (void *) 0; } ++static inline void context_free (context_t c _GL_UNUSED_PARAMETER) {} ++ ++static inline int context_user_set (context_t sc _GL_UNUSED_PARAMETER, ++ char const *s _GL_UNUSED_PARAMETER) ++ { errno = ENOTSUP; return -1; } ++static inline int context_role_set (context_t sc _GL_UNUSED_PARAMETER, ++ char const *s _GL_UNUSED_PARAMETER) ++ { errno = ENOTSUP; return -1; } ++static inline int context_range_set (context_t sc _GL_UNUSED_PARAMETER, ++ char const *s _GL_UNUSED_PARAMETER) ++ { errno = ENOTSUP; return -1; } ++static inline int context_type_set (context_t sc _GL_UNUSED_PARAMETER, ++ char const *s _GL_UNUSED_PARAMETER) ++ { errno = ENOTSUP; return -1; } ++ ++#endif +diff --git a/gnu/se-selinux.in.h b/gnu/se-selinux.in.h +new file mode 100644 +index 0000000..34205a1 +--- /dev/null ++++ b/gnu/se-selinux.in.h +@@ -0,0 +1,99 @@ ++/* -*- buffer-read-only: t -*- vi: set ro: */ ++/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ ++/* Replacement for platforms that lack it. ++ Copyright (C) 2008-2012 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#ifndef _@GUARD_PREFIX@_SELINUX_SELINUX_H ++# define _@GUARD_PREFIX@_SELINUX_SELINUX_H ++ ++# if __GNUC__ >= 3 ++@PRAGMA_SYSTEM_HEADER@ ++# endif ++@PRAGMA_COLUMNS@ ++ ++# if HAVE_SELINUX_SELINUX_H ++ ++#@INCLUDE_NEXT@ @NEXT_SELINUX_SELINUX_H@ ++ ++# else ++ ++# include ++# include ++ ++/* The definition of _GL_UNUSED_PARAMETER is copied here. */ ++ ++# if !GNULIB_defined_security_types ++ ++typedef unsigned short security_class_t; ++# define security_context_t char* ++# define is_selinux_enabled() 0 ++ ++static inline int getcon (security_context_t *con _GL_UNUSED_PARAMETER) ++ { errno = ENOTSUP; return -1; } ++static inline void freecon (security_context_t con _GL_UNUSED_PARAMETER) {} ++ ++ ++static inline int getfscreatecon (security_context_t *con _GL_UNUSED_PARAMETER) ++ { errno = ENOTSUP; return -1; } ++static inline int setfscreatecon (security_context_t con _GL_UNUSED_PARAMETER) ++ { errno = ENOTSUP; return -1; } ++static inline int matchpathcon (char const *file _GL_UNUSED_PARAMETER, ++ mode_t m _GL_UNUSED_PARAMETER, ++ security_context_t *con _GL_UNUSED_PARAMETER) ++ { errno = ENOTSUP; return -1; } ++static inline int getfilecon (char const *file _GL_UNUSED_PARAMETER, ++ security_context_t *con _GL_UNUSED_PARAMETER) ++ { errno = ENOTSUP; return -1; } ++static inline int lgetfilecon (char const *file _GL_UNUSED_PARAMETER, ++ security_context_t *con _GL_UNUSED_PARAMETER) ++ { errno = ENOTSUP; return -1; } ++static inline int fgetfilecon (int fd, ++ security_context_t *con _GL_UNUSED_PARAMETER) ++ { errno = ENOTSUP; return -1; } ++static inline int setfilecon (char const *file _GL_UNUSED_PARAMETER, ++ security_context_t con _GL_UNUSED_PARAMETER) ++ { errno = ENOTSUP; return -1; } ++static inline int lsetfilecon (char const *file _GL_UNUSED_PARAMETER, ++ security_context_t con _GL_UNUSED_PARAMETER) ++ { errno = ENOTSUP; return -1; } ++static inline int fsetfilecon (int fd _GL_UNUSED_PARAMETER, ++ security_context_t con _GL_UNUSED_PARAMETER) ++ { errno = ENOTSUP; return -1; } ++ ++static inline int security_check_context ++ (security_context_t con _GL_UNUSED_PARAMETER) ++ { errno = ENOTSUP; return -1; } ++static inline int security_check_context_raw ++ (security_context_t con _GL_UNUSED_PARAMETER) ++ { errno = ENOTSUP; return -1; } ++static inline int setexeccon (security_context_t con _GL_UNUSED_PARAMETER) ++ { errno = ENOTSUP; return -1; } ++static inline int security_compute_create ++ (security_context_t scon _GL_UNUSED_PARAMETER, ++ security_context_t tcon _GL_UNUSED_PARAMETER, ++ security_class_t tclass _GL_UNUSED_PARAMETER, ++ security_context_t *newcon _GL_UNUSED_PARAMETER) ++ { errno = ENOTSUP; return -1; } ++static inline int matchpathcon_init_prefix ++ (char const *path _GL_UNUSED_PARAMETER, ++ char const *prefix _GL_UNUSED_PARAMETER) ++ { errno = ENOTSUP; return -1; } ++ ++# define GNULIB_defined_security_types 1 ++# endif ++ ++# endif ++#endif /* _@GUARD_PREFIX@_SELINUX_SELINUX_H */ +diff --git a/gnu/selinux-at.c b/gnu/selinux-at.c +new file mode 100644 +index 0000000..f6619fa +--- /dev/null ++++ b/gnu/selinux-at.c +@@ -0,0 +1,74 @@ ++/* -*- buffer-read-only: t -*- vi: set ro: */ ++/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ ++/* openat-style fd-relative functions for SE Linux ++ Copyright (C) 2007, 2009-2012 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++/* written by Jim Meyering */ ++ ++#include ++ ++#include "selinux-at.h" ++#include "openat.h" ++ ++#include ++#include ++#include ++#include ++ ++#include "dirname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */ ++#include "save-cwd.h" ++ ++#include "openat-priv.h" ++ ++#define AT_FUNC_NAME getfileconat ++#define AT_FUNC_F1 getfilecon ++#define AT_FUNC_POST_FILE_PARAM_DECLS , security_context_t *con ++#define AT_FUNC_POST_FILE_ARGS , con ++#include "at-func.c" ++#undef AT_FUNC_NAME ++#undef AT_FUNC_F1 ++#undef AT_FUNC_POST_FILE_PARAM_DECLS ++#undef AT_FUNC_POST_FILE_ARGS ++ ++#define AT_FUNC_NAME lgetfileconat ++#define AT_FUNC_F1 lgetfilecon ++#define AT_FUNC_POST_FILE_PARAM_DECLS , security_context_t *con ++#define AT_FUNC_POST_FILE_ARGS , con ++#include "at-func.c" ++#undef AT_FUNC_NAME ++#undef AT_FUNC_F1 ++#undef AT_FUNC_POST_FILE_PARAM_DECLS ++#undef AT_FUNC_POST_FILE_ARGS ++ ++#define AT_FUNC_NAME setfileconat ++#define AT_FUNC_F1 setfilecon ++#define AT_FUNC_POST_FILE_PARAM_DECLS , security_context_t con ++#define AT_FUNC_POST_FILE_ARGS , con ++#include "at-func.c" ++#undef AT_FUNC_NAME ++#undef AT_FUNC_F1 ++#undef AT_FUNC_POST_FILE_PARAM_DECLS ++#undef AT_FUNC_POST_FILE_ARGS ++ ++#define AT_FUNC_NAME lsetfileconat ++#define AT_FUNC_F1 lsetfilecon ++#define AT_FUNC_POST_FILE_PARAM_DECLS , security_context_t con ++#define AT_FUNC_POST_FILE_ARGS , con ++#include "at-func.c" ++#undef AT_FUNC_NAME ++#undef AT_FUNC_F1 ++#undef AT_FUNC_POST_FILE_PARAM_DECLS ++#undef AT_FUNC_POST_FILE_ARGS +diff --git a/gnu/selinux-at.h b/gnu/selinux-at.h +new file mode 100644 +index 0000000..4ab3109 +--- /dev/null ++++ b/gnu/selinux-at.h +@@ -0,0 +1,54 @@ ++/* -*- buffer-read-only: t -*- vi: set ro: */ ++/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ ++/* Prototypes for openat-style fd-relative SELinux functions ++ Copyright (C) 2007, 2009-2012 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#include ++#include ++ ++/* These are the dir-fd-relative variants of the functions without the ++ "at" suffix. For example, getfileconat (AT_FDCWD, file, &c) is usually ++ equivalent to getfilecon (file, &c). The emulation is accomplished ++ by first attempting getfilecon ("/proc/self/fd/DIR_FD/FILE", &c). ++ Failing that, simulate it via save_cwd/fchdir/getfilecon/restore_cwd. ++ If either the save_cwd or the restore_cwd fails (relatively unlikely), ++ then give a diagnostic and exit nonzero. */ ++ ++/* dir-fd-relative getfilecon. Set *CON to the SELinux security context ++ of the file specified by DIR_FD and FILE and return the length of *CON. ++ DIR_FD and FILE are interpreted as for fstatat[*]. A non-NULL *CON ++ must be freed with freecon. Upon error, set *CON to NULL, set errno ++ and return -1. ++ [*] with flags=0 here, with flags=AT_SYMLINK_NOFOLLOW for lgetfileconat */ ++int getfileconat (int dir_fd, char const *file, security_context_t *con); ++ ++/* dir-fd-relative lgetfilecon. This function is just like getfileconat, ++ except when DIR_FD and FILE specify a symlink: lgetfileconat operates on ++ the symlink, while getfileconat operates on the referent of the symlink. */ ++int lgetfileconat (int dir_fd, char const *file, security_context_t *con); ++ ++/* dir-fd-relative setfilecon. Set the SELinux security context of ++ the file specified by DIR_FD and FILE to CON. DIR_FD and FILE are ++ interpreted as for fstatat[*]. Upon success, return 0. ++ Otherwise, return -1 and set errno. */ ++int setfileconat (int dir_fd, char const *file, security_context_t con); ++ ++/* dir-fd-relative lsetfilecon. This function is just like setfileconat, ++ except that rather than dereferencing a symlink, this function affects it. */ ++/* dir-fd-relative lsetfilecon. This function is just like setfileconat, ++ except when DIR_FD and FILE specify a symlink: lsetfileconat operates on ++ the symlink, while setfileconat operates on the referent of the symlink. */ ++int lsetfileconat (int dir_fd, char const *file, security_context_t con); +diff --git a/gnu/set-mode-acl.c b/gnu/set-mode-acl.c +new file mode 100644 +index 0000000..edc8e26 +--- /dev/null ++++ b/gnu/set-mode-acl.c +@@ -0,0 +1,699 @@ ++/* -*- buffer-read-only: t -*- vi: set ro: */ ++/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ ++/* set-mode-acl.c - set access control list equivalent to a mode ++ ++ Copyright (C) 2002-2003, 2005-2012 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++ Written by Paul Eggert and Andreas Gruenbacher, and Bruno Haible. */ ++ ++#include ++ ++#include "acl.h" ++ ++#include "acl-internal.h" ++ ++#include "gettext.h" ++#define _(msgid) gettext (msgid) ++ ++ ++/* If DESC is a valid file descriptor use fchmod to change the ++ file's mode to MODE on systems that have fchown. On systems ++ that don't have fchown and if DESC is invalid, use chown on ++ NAME instead. ++ Return 0 if successful. Return -1 and set errno upon failure. */ ++ ++int ++chmod_or_fchmod (const char *name, int desc, mode_t mode) ++{ ++ if (HAVE_FCHMOD && desc != -1) ++ return fchmod (desc, mode); ++ else ++ return chmod (name, mode); ++} ++ ++/* Set the access control lists of a file. If DESC is a valid file ++ descriptor, use file descriptor operations where available, else use ++ filename based operations on NAME. If access control lists are not ++ available, fchmod the target file to MODE. Also sets the ++ non-permission bits of the destination file (S_ISUID, S_ISGID, S_ISVTX) ++ to those from MODE if any are set. ++ Return 0 if successful. Return -1 and set errno upon failure. */ ++ ++int ++qset_acl (char const *name, int desc, mode_t mode) ++{ ++#if USE_ACL ++# if HAVE_ACL_GET_FILE ++ /* POSIX 1003.1e draft 17 (abandoned) specific version. */ ++ /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */ ++# if !HAVE_ACL_TYPE_EXTENDED ++ /* Linux, FreeBSD, IRIX, Tru64 */ ++ ++ /* We must also have acl_from_text and acl_delete_def_file. ++ (acl_delete_def_file could be emulated with acl_init followed ++ by acl_set_file, but acl_set_file with an empty acl is ++ unspecified.) */ ++ ++# ifndef HAVE_ACL_FROM_TEXT ++# error Must have acl_from_text (see POSIX 1003.1e draft 17). ++# endif ++# ifndef HAVE_ACL_DELETE_DEF_FILE ++# error Must have acl_delete_def_file (see POSIX 1003.1e draft 17). ++# endif ++ ++ acl_t acl; ++ int ret; ++ ++ if (HAVE_ACL_FROM_MODE) /* Linux */ ++ { ++ acl = acl_from_mode (mode); ++ if (!acl) ++ return -1; ++ } ++ else /* FreeBSD, IRIX, Tru64 */ ++ { ++ /* If we were to create the ACL using the functions acl_init(), ++ acl_create_entry(), acl_set_tag_type(), acl_set_qualifier(), ++ acl_get_permset(), acl_clear_perm[s](), acl_add_perm(), we ++ would need to create a qualifier. I don't know how to do this. ++ So create it using acl_from_text(). */ ++ ++# if HAVE_ACL_FREE_TEXT /* Tru64 */ ++ char acl_text[] = "u::---,g::---,o::---,"; ++# else /* FreeBSD, IRIX */ ++ char acl_text[] = "u::---,g::---,o::---"; ++# endif ++ ++ if (mode & S_IRUSR) acl_text[ 3] = 'r'; ++ if (mode & S_IWUSR) acl_text[ 4] = 'w'; ++ if (mode & S_IXUSR) acl_text[ 5] = 'x'; ++ if (mode & S_IRGRP) acl_text[10] = 'r'; ++ if (mode & S_IWGRP) acl_text[11] = 'w'; ++ if (mode & S_IXGRP) acl_text[12] = 'x'; ++ if (mode & S_IROTH) acl_text[17] = 'r'; ++ if (mode & S_IWOTH) acl_text[18] = 'w'; ++ if (mode & S_IXOTH) acl_text[19] = 'x'; ++ ++ acl = acl_from_text (acl_text); ++ if (!acl) ++ return -1; ++ } ++ if (HAVE_ACL_SET_FD && desc != -1) ++ ret = acl_set_fd (desc, acl); ++ else ++ ret = acl_set_file (name, ACL_TYPE_ACCESS, acl); ++ if (ret != 0) ++ { ++ int saved_errno = errno; ++ acl_free (acl); ++ ++ if (ACL_NOT_WELL_SUPPORTED (errno)) ++ return chmod_or_fchmod (name, desc, mode); ++ else ++ { ++ errno = saved_errno; ++ return -1; ++ } ++ } ++ else ++ acl_free (acl); ++ ++ if (S_ISDIR (mode) && acl_delete_def_file (name)) ++ return -1; ++ ++ if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX))) ++ { ++ /* We did not call chmod so far, and either the mode and the ACL are ++ separate or special bits are to be set which don't fit into ACLs. */ ++ return chmod_or_fchmod (name, desc, mode); ++ } ++ return 0; ++ ++# else /* HAVE_ACL_TYPE_EXTENDED */ ++ /* Mac OS X */ ++ ++ /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS) ++ and acl_get_file (name, ACL_TYPE_DEFAULT) ++ always return NULL / EINVAL. You have to use ++ acl_get_file (name, ACL_TYPE_EXTENDED) ++ or acl_get_fd (open (name, ...)) ++ to retrieve an ACL. ++ On the other hand, ++ acl_set_file (name, ACL_TYPE_ACCESS, acl) ++ and acl_set_file (name, ACL_TYPE_DEFAULT, acl) ++ have the same effect as ++ acl_set_file (name, ACL_TYPE_EXTENDED, acl): ++ Each of these calls sets the file's ACL. */ ++ ++ acl_t acl; ++ int ret; ++ ++ /* Remove the ACL if the file has ACLs. */ ++ if (HAVE_ACL_GET_FD && desc != -1) ++ acl = acl_get_fd (desc); ++ else ++ acl = acl_get_file (name, ACL_TYPE_EXTENDED); ++ if (acl) ++ { ++ acl_free (acl); ++ ++ acl = acl_init (0); ++ if (acl) ++ { ++ if (HAVE_ACL_SET_FD && desc != -1) ++ ret = acl_set_fd (desc, acl); ++ else ++ ret = acl_set_file (name, ACL_TYPE_EXTENDED, acl); ++ if (ret != 0) ++ { ++ int saved_errno = errno; ++ ++ acl_free (acl); ++ ++ if (ACL_NOT_WELL_SUPPORTED (saved_errno)) ++ return chmod_or_fchmod (name, desc, mode); ++ else ++ { ++ errno = saved_errno; ++ return -1; ++ } ++ } ++ acl_free (acl); ++ } ++ } ++ ++ /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */ ++ return chmod_or_fchmod (name, desc, mode); ++# endif ++ ++# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ ++ ++ int done_setacl = 0; ++ ++# ifdef ACE_GETACL ++ /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4 ++ file systems (whereas the other ones are used in UFS file systems). */ ++ ++ /* The flags in the ace_t structure changed in a binary incompatible way ++ when ACL_NO_TRIVIAL etc. were introduced in version 1.15. ++ How to distinguish the two conventions at runtime? ++ We fetch the existing ACL. In the old convention, usually three ACEs have ++ a_flags = ACE_OWNER / ACE_GROUP / ACE_OTHER, in the range 0x0100..0x0400. ++ In the new convention, these values are not used. */ ++ int convention; ++ ++ { ++ /* Initially, try to read the entries into a stack-allocated buffer. ++ Use malloc if it does not fit. */ ++ enum ++ { ++ alloc_init = 4000 / sizeof (ace_t), /* >= 3 */ ++ alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t)) ++ }; ++ ace_t buf[alloc_init]; ++ size_t alloc = alloc_init; ++ ace_t *entries = buf; ++ ace_t *malloced = NULL; ++ int count; ++ ++ for (;;) ++ { ++ count = (desc != -1 ++ ? facl (desc, ACE_GETACL, alloc, entries) ++ : acl (name, ACE_GETACL, alloc, entries)); ++ if (count < 0 && errno == ENOSPC) ++ { ++ /* Increase the size of the buffer. */ ++ free (malloced); ++ if (alloc > alloc_max / 2) ++ { ++ errno = ENOMEM; ++ return -1; ++ } ++ alloc = 2 * alloc; /* <= alloc_max */ ++ entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t)); ++ if (entries == NULL) ++ { ++ errno = ENOMEM; ++ return -1; ++ } ++ continue; ++ } ++ break; ++ } ++ ++ if (count <= 0) ++ convention = -1; ++ else ++ { ++ int i; ++ ++ convention = 0; ++ for (i = 0; i < count; i++) ++ if (entries[i].a_flags & (OLD_ACE_OWNER | OLD_ACE_GROUP | OLD_ACE_OTHER)) ++ { ++ convention = 1; ++ break; ++ } ++ } ++ free (malloced); ++ } ++ ++ if (convention >= 0) ++ { ++ ace_t entries[6]; ++ int count; ++ int ret; ++ ++ if (convention) ++ { ++ /* Running on Solaris 10. */ ++ entries[0].a_type = OLD_ALLOW; ++ entries[0].a_flags = OLD_ACE_OWNER; ++ entries[0].a_who = 0; /* irrelevant */ ++ entries[0].a_access_mask = (mode >> 6) & 7; ++ entries[1].a_type = OLD_ALLOW; ++ entries[1].a_flags = OLD_ACE_GROUP; ++ entries[1].a_who = 0; /* irrelevant */ ++ entries[1].a_access_mask = (mode >> 3) & 7; ++ entries[2].a_type = OLD_ALLOW; ++ entries[2].a_flags = OLD_ACE_OTHER; ++ entries[2].a_who = 0; ++ entries[2].a_access_mask = mode & 7; ++ count = 3; ++ } ++ else ++ { ++ /* Running on Solaris 10 (newer version) or Solaris 11. ++ The details here were found through "/bin/ls -lvd somefiles". */ ++ entries[0].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE; ++ entries[0].a_flags = NEW_ACE_OWNER; ++ entries[0].a_who = 0; /* irrelevant */ ++ entries[0].a_access_mask = 0; ++ entries[1].a_type = NEW_ACE_ACCESS_ALLOWED_ACE_TYPE; ++ entries[1].a_flags = NEW_ACE_OWNER; ++ entries[1].a_who = 0; /* irrelevant */ ++ entries[1].a_access_mask = NEW_ACE_WRITE_NAMED_ATTRS ++ | NEW_ACE_WRITE_ATTRIBUTES ++ | NEW_ACE_WRITE_ACL ++ | NEW_ACE_WRITE_OWNER; ++ if (mode & 0400) ++ entries[1].a_access_mask |= NEW_ACE_READ_DATA; ++ else ++ entries[0].a_access_mask |= NEW_ACE_READ_DATA; ++ if (mode & 0200) ++ entries[1].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA; ++ else ++ entries[0].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA; ++ if (mode & 0100) ++ entries[1].a_access_mask |= NEW_ACE_EXECUTE; ++ else ++ entries[0].a_access_mask |= NEW_ACE_EXECUTE; ++ entries[2].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE; ++ entries[2].a_flags = NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP; ++ entries[2].a_who = 0; /* irrelevant */ ++ entries[2].a_access_mask = 0; ++ entries[3].a_type = NEW_ACE_ACCESS_ALLOWED_ACE_TYPE; ++ entries[3].a_flags = NEW_ACE_GROUP | NEW_ACE_IDENTIFIER_GROUP; ++ entries[3].a_who = 0; /* irrelevant */ ++ entries[3].a_access_mask = 0; ++ if (mode & 0040) ++ entries[3].a_access_mask |= NEW_ACE_READ_DATA; ++ else ++ entries[2].a_access_mask |= NEW_ACE_READ_DATA; ++ if (mode & 0020) ++ entries[3].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA; ++ else ++ entries[2].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA; ++ if (mode & 0010) ++ entries[3].a_access_mask |= NEW_ACE_EXECUTE; ++ else ++ entries[2].a_access_mask |= NEW_ACE_EXECUTE; ++ entries[4].a_type = NEW_ACE_ACCESS_DENIED_ACE_TYPE; ++ entries[4].a_flags = NEW_ACE_EVERYONE; ++ entries[4].a_who = 0; ++ entries[4].a_access_mask = NEW_ACE_WRITE_NAMED_ATTRS ++ | NEW_ACE_WRITE_ATTRIBUTES ++ | NEW_ACE_WRITE_ACL ++ | NEW_ACE_WRITE_OWNER; ++ entries[5].a_type = NEW_ACE_ACCESS_ALLOWED_ACE_TYPE; ++ entries[5].a_flags = NEW_ACE_EVERYONE; ++ entries[5].a_who = 0; ++ entries[5].a_access_mask = NEW_ACE_READ_NAMED_ATTRS ++ | NEW_ACE_READ_ATTRIBUTES ++ | NEW_ACE_READ_ACL ++ | NEW_ACE_SYNCHRONIZE; ++ if (mode & 0004) ++ entries[5].a_access_mask |= NEW_ACE_READ_DATA; ++ else ++ entries[4].a_access_mask |= NEW_ACE_READ_DATA; ++ if (mode & 0002) ++ entries[5].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA; ++ else ++ entries[4].a_access_mask |= NEW_ACE_WRITE_DATA | NEW_ACE_APPEND_DATA; ++ if (mode & 0001) ++ entries[5].a_access_mask |= NEW_ACE_EXECUTE; ++ else ++ entries[4].a_access_mask |= NEW_ACE_EXECUTE; ++ count = 6; ++ } ++ if (desc != -1) ++ ret = facl (desc, ACE_SETACL, count, entries); ++ else ++ ret = acl (name, ACE_SETACL, count, entries); ++ if (ret < 0 && errno != EINVAL && errno != ENOTSUP) ++ { ++ if (errno == ENOSYS) ++ return chmod_or_fchmod (name, desc, mode); ++ return -1; ++ } ++ if (ret == 0) ++ done_setacl = 1; ++ } ++# endif ++ ++ if (!done_setacl) ++ { ++ aclent_t entries[3]; ++ int ret; ++ ++ entries[0].a_type = USER_OBJ; ++ entries[0].a_id = 0; /* irrelevant */ ++ entries[0].a_perm = (mode >> 6) & 7; ++ entries[1].a_type = GROUP_OBJ; ++ entries[1].a_id = 0; /* irrelevant */ ++ entries[1].a_perm = (mode >> 3) & 7; ++ entries[2].a_type = OTHER_OBJ; ++ entries[2].a_id = 0; ++ entries[2].a_perm = mode & 7; ++ ++ if (desc != -1) ++ ret = facl (desc, SETACL, ++ sizeof (entries) / sizeof (aclent_t), entries); ++ else ++ ret = acl (name, SETACL, ++ sizeof (entries) / sizeof (aclent_t), entries); ++ if (ret < 0) ++ { ++ if (errno == ENOSYS || errno == EOPNOTSUPP) ++ return chmod_or_fchmod (name, desc, mode); ++ return -1; ++ } ++ } ++ ++ if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX))) ++ { ++ /* We did not call chmod so far, so the special bits have not yet ++ been set. */ ++ return chmod_or_fchmod (name, desc, mode); ++ } ++ return 0; ++ ++# elif HAVE_GETACL /* HP-UX */ ++ ++ struct stat statbuf; ++ int ret; ++ ++ if (desc != -1) ++ ret = fstat (desc, &statbuf); ++ else ++ ret = stat (name, &statbuf); ++ if (ret < 0) ++ return -1; ++ ++ { ++ struct acl_entry entries[3]; ++ ++ entries[0].uid = statbuf.st_uid; ++ entries[0].gid = ACL_NSGROUP; ++ entries[0].mode = (mode >> 6) & 7; ++ entries[1].uid = ACL_NSUSER; ++ entries[1].gid = statbuf.st_gid; ++ entries[1].mode = (mode >> 3) & 7; ++ entries[2].uid = ACL_NSUSER; ++ entries[2].gid = ACL_NSGROUP; ++ entries[2].mode = mode & 7; ++ ++ if (desc != -1) ++ ret = fsetacl (desc, sizeof (entries) / sizeof (struct acl_entry), entries); ++ else ++ ret = setacl (name, sizeof (entries) / sizeof (struct acl_entry), entries); ++ } ++ if (ret < 0) ++ { ++ if (!(errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)) ++ return -1; ++ ++# if HAVE_ACLV_H /* HP-UX >= 11.11 */ ++ { ++ struct acl entries[4]; ++ ++ entries[0].a_type = USER_OBJ; ++ entries[0].a_id = 0; /* irrelevant */ ++ entries[0].a_perm = (mode >> 6) & 7; ++ entries[1].a_type = GROUP_OBJ; ++ entries[1].a_id = 0; /* irrelevant */ ++ entries[1].a_perm = (mode >> 3) & 7; ++ entries[2].a_type = CLASS_OBJ; ++ entries[2].a_id = 0; ++ entries[2].a_perm = (mode >> 3) & 7; ++ entries[3].a_type = OTHER_OBJ; ++ entries[3].a_id = 0; ++ entries[3].a_perm = mode & 7; ++ ++ ret = aclsort (sizeof (entries) / sizeof (struct acl), 1, entries); ++ if (ret > 0) ++ abort (); ++ if (ret < 0) ++ { ++ if (0) ++ return chmod_or_fchmod (name, desc, mode); ++ return -1; ++ } ++ ++ ret = acl ((char *) name, ACL_SET, ++ sizeof (entries) / sizeof (struct acl), entries); ++ if (ret < 0) ++ { ++ if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) ++ return chmod_or_fchmod (name, desc, mode); ++ return -1; ++ } ++ } ++# else ++ return chmod_or_fchmod (name, desc, mode); ++# endif ++ } ++ ++ if (mode & (S_ISUID | S_ISGID | S_ISVTX)) ++ { ++ /* We did not call chmod so far, so the special bits have not yet ++ been set. */ ++ return chmod_or_fchmod (name, desc, mode); ++ } ++ return 0; ++ ++# elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */ ++ ++ acl_type_list_t types; ++ size_t types_size = sizeof (types); ++ acl_type_t type; ++ ++ if (aclx_gettypes (name, &types, &types_size) < 0 ++ || types.num_entries == 0) ++ return chmod_or_fchmod (name, desc, mode); ++ ++ /* XXX Do we need to clear all types of ACLs for the given file, or is it ++ sufficient to clear the first one? */ ++ type = types.entries[0]; ++ if (type.u64 == ACL_AIXC) ++ { ++ union { struct acl a; char room[128]; } u; ++ int ret; ++ ++ u.a.acl_len = (char *) &u.a.acl_ext[0] - (char *) &u.a; /* no entries */ ++ u.a.acl_mode = mode & ~(S_IXACL | 0777); ++ u.a.u_access = (mode >> 6) & 7; ++ u.a.g_access = (mode >> 3) & 7; ++ u.a.o_access = mode & 7; ++ ++ if (desc != -1) ++ ret = aclx_fput (desc, SET_ACL | SET_MODE_S_BITS, ++ type, &u.a, u.a.acl_len, mode); ++ else ++ ret = aclx_put (name, SET_ACL | SET_MODE_S_BITS, ++ type, &u.a, u.a.acl_len, mode); ++ if (!(ret < 0 && errno == ENOSYS)) ++ return ret; ++ } ++ else if (type.u64 == ACL_NFS4) ++ { ++ union { nfs4_acl_int_t a; char room[128]; } u; ++ nfs4_ace_int_t *ace; ++ int ret; ++ ++ u.a.aclVersion = NFS4_ACL_INT_STRUCT_VERSION; ++ u.a.aclEntryN = 0; ++ ace = &u.a.aclEntry[0]; ++ { ++ ace->flags = ACE4_ID_SPECIAL; ++ ace->aceWho.special_whoid = ACE4_WHO_OWNER; ++ ace->aceType = ACE4_ACCESS_ALLOWED_ACE_TYPE; ++ ace->aceFlags = 0; ++ ace->aceMask = ++ (mode & 0400 ? ACE4_READ_DATA | ACE4_LIST_DIRECTORY : 0) ++ | (mode & 0200 ++ ? ACE4_WRITE_DATA | ACE4_ADD_FILE | ACE4_APPEND_DATA ++ | ACE4_ADD_SUBDIRECTORY ++ : 0) ++ | (mode & 0100 ? ACE4_EXECUTE : 0); ++ ace->aceWhoString[0] = '\0'; ++ ace->entryLen = (char *) &ace->aceWhoString[4] - (char *) ace; ++ ace = (nfs4_ace_int_t *) (char *) &ace->aceWhoString[4]; ++ u.a.aclEntryN++; ++ } ++ { ++ ace->flags = ACE4_ID_SPECIAL; ++ ace->aceWho.special_whoid = ACE4_WHO_GROUP; ++ ace->aceType = ACE4_ACCESS_ALLOWED_ACE_TYPE; ++ ace->aceFlags = 0; ++ ace->aceMask = ++ (mode & 0040 ? ACE4_READ_DATA | ACE4_LIST_DIRECTORY : 0) ++ | (mode & 0020 ++ ? ACE4_WRITE_DATA | ACE4_ADD_FILE | ACE4_APPEND_DATA ++ | ACE4_ADD_SUBDIRECTORY ++ : 0) ++ | (mode & 0010 ? ACE4_EXECUTE : 0); ++ ace->aceWhoString[0] = '\0'; ++ ace->entryLen = (char *) &ace->aceWhoString[4] - (char *) ace; ++ ace = (nfs4_ace_int_t *) (char *) &ace->aceWhoString[4]; ++ u.a.aclEntryN++; ++ } ++ { ++ ace->flags = ACE4_ID_SPECIAL; ++ ace->aceWho.special_whoid = ACE4_WHO_EVERYONE; ++ ace->aceType = ACE4_ACCESS_ALLOWED_ACE_TYPE; ++ ace->aceFlags = 0; ++ ace->aceMask = ++ (mode & 0004 ? ACE4_READ_DATA | ACE4_LIST_DIRECTORY : 0) ++ | (mode & 0002 ++ ? ACE4_WRITE_DATA | ACE4_ADD_FILE | ACE4_APPEND_DATA ++ | ACE4_ADD_SUBDIRECTORY ++ : 0) ++ | (mode & 0001 ? ACE4_EXECUTE : 0); ++ ace->aceWhoString[0] = '\0'; ++ ace->entryLen = (char *) &ace->aceWhoString[4] - (char *) ace; ++ ace = (nfs4_ace_int_t *) (char *) &ace->aceWhoString[4]; ++ u.a.aclEntryN++; ++ } ++ u.a.aclLength = (char *) ace - (char *) &u.a; ++ ++ if (desc != -1) ++ ret = aclx_fput (desc, SET_ACL | SET_MODE_S_BITS, ++ type, &u.a, u.a.aclLength, mode); ++ else ++ ret = aclx_put (name, SET_ACL | SET_MODE_S_BITS, ++ type, &u.a, u.a.aclLength, mode); ++ if (!(ret < 0 && errno == ENOSYS)) ++ return ret; ++ } ++ ++ return chmod_or_fchmod (name, desc, mode); ++ ++# elif HAVE_STATACL /* older AIX */ ++ ++ union { struct acl a; char room[128]; } u; ++ int ret; ++ ++ u.a.acl_len = (char *) &u.a.acl_ext[0] - (char *) &u.a; /* no entries */ ++ u.a.acl_mode = mode & ~(S_IXACL | 0777); ++ u.a.u_access = (mode >> 6) & 7; ++ u.a.g_access = (mode >> 3) & 7; ++ u.a.o_access = mode & 7; ++ ++ if (desc != -1) ++ ret = fchacl (desc, &u.a, u.a.acl_len); ++ else ++ ret = chacl (name, &u.a, u.a.acl_len); ++ ++ if (ret < 0 && errno == ENOSYS) ++ return chmod_or_fchmod (name, desc, mode); ++ ++ return ret; ++ ++# elif HAVE_ACLSORT /* NonStop Kernel */ ++ ++ struct acl entries[4]; ++ int ret; ++ ++ entries[0].a_type = USER_OBJ; ++ entries[0].a_id = 0; /* irrelevant */ ++ entries[0].a_perm = (mode >> 6) & 7; ++ entries[1].a_type = GROUP_OBJ; ++ entries[1].a_id = 0; /* irrelevant */ ++ entries[1].a_perm = (mode >> 3) & 7; ++ entries[2].a_type = CLASS_OBJ; ++ entries[2].a_id = 0; ++ entries[2].a_perm = (mode >> 3) & 7; ++ entries[3].a_type = OTHER_OBJ; ++ entries[3].a_id = 0; ++ entries[3].a_perm = mode & 7; ++ ++ ret = aclsort (sizeof (entries) / sizeof (struct acl), 1, entries); ++ if (ret > 0) ++ abort (); ++ if (ret < 0) ++ { ++ if (0) ++ return chmod_or_fchmod (name, desc, mode); ++ return -1; ++ } ++ ++ ret = acl ((char *) name, ACL_SET, ++ sizeof (entries) / sizeof (struct acl), entries); ++ if (ret < 0) ++ { ++ if (0) ++ return chmod_or_fchmod (name, desc, mode); ++ return -1; ++ } ++ ++ if (mode & (S_ISUID | S_ISGID | S_ISVTX)) ++ { ++ /* We did not call chmod so far, so the special bits have not yet ++ been set. */ ++ return chmod_or_fchmod (name, desc, mode); ++ } ++ return 0; ++ ++# else /* Unknown flavor of ACLs */ ++ return chmod_or_fchmod (name, desc, mode); ++# endif ++#else /* !USE_ACL */ ++ return chmod_or_fchmod (name, desc, mode); ++#endif ++} ++ ++/* As with qset_acl, but also output a diagnostic on failure. */ ++ ++int ++set_acl (char const *name, int desc, mode_t mode) ++{ ++ int ret = qset_acl (name, desc, mode); ++ if (ret != 0) ++ error (0, errno, _("setting permissions for %s"), quote (name)); ++ return ret; ++} +diff --git a/m4/acl.m4 b/m4/acl.m4 +new file mode 100644 +index 0000000..19aa548 +--- /dev/null ++++ b/m4/acl.m4 +@@ -0,0 +1,165 @@ ++# acl.m4 - check for access control list (ACL) primitives ++# serial 14 ++ ++# Copyright (C) 2002, 2004-2012 Free Software Foundation, Inc. ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# Written by Paul Eggert and Jim Meyering. ++ ++AC_DEFUN([gl_FUNC_ACL], ++[ ++ AC_ARG_ENABLE([acl], ++ AS_HELP_STRING([--disable-acl], [do not support ACLs]), ++ , [enable_acl=auto]) ++ ++ LIB_ACL= ++ use_acl=0 ++ AC_REQUIRE([AC_C_INLINE]) ++ if test "x$enable_acl" != "xno"; then ++ dnl On all platforms, the ACL related API is declared in . ++ AC_CHECK_HEADERS([sys/acl.h]) ++ if test $ac_cv_header_sys_acl_h = yes; then ++ ac_save_LIBS=$LIBS ++ ++ dnl Test for POSIX-draft-like API (Linux, FreeBSD, Mac OS X, IRIX, Tru64). ++ dnl -lacl is needed on Linux, -lpacl is needed on OSF/1. ++ if test $use_acl = 0; then ++ AC_SEARCH_LIBS([acl_get_file], [acl pacl], ++ [if test "$ac_cv_search_acl_get_file" != "none required"; then ++ LIB_ACL=$ac_cv_search_acl_get_file ++ fi ++ AC_CHECK_FUNCS( ++ [acl_get_file acl_get_fd acl_set_file acl_set_fd \ ++ acl_free acl_from_mode acl_from_text \ ++ acl_delete_def_file acl_extended_file \ ++ acl_delete_fd_np acl_delete_file_np \ ++ acl_copy_ext_native acl_create_entry_np \ ++ acl_to_short_text acl_free_text]) ++ # If the acl_get_file bug is detected, don't enable the ACL support. ++ gl_ACL_GET_FILE([use_acl=1], []) ++ if test $use_acl = 1; then ++ dnl On Linux, additional API is declared in . ++ AC_CHECK_HEADERS([acl/libacl.h]) ++ AC_REPLACE_FUNCS([acl_entries]) ++ AC_CACHE_CHECK([for ACL_FIRST_ENTRY], ++ [gl_cv_acl_ACL_FIRST_ENTRY], ++ [AC_COMPILE_IFELSE([AC_LANG_PROGRAM( ++[[#include ++#include ++int type = ACL_FIRST_ENTRY;]])], ++ [gl_cv_acl_ACL_FIRST_ENTRY=yes], ++ [gl_cv_acl_ACL_FIRST_ENTRY=no])]) ++ if test $gl_cv_acl_ACL_FIRST_ENTRY = yes; then ++ AC_DEFINE([HAVE_ACL_FIRST_ENTRY], [1], ++ [Define to 1 if the constant ACL_FIRST_ENTRY exists.]) ++ fi ++ dnl On Mac OS X, other types of ACLs are supported. ++ AC_CACHE_CHECK([for ACL_TYPE_EXTENDED], ++ [gl_cv_acl_ACL_TYPE_EXTENDED], ++ [AC_COMPILE_IFELSE([AC_LANG_PROGRAM( ++[[#include ++#include ++int type = ACL_TYPE_EXTENDED;]])], ++ [gl_cv_acl_ACL_TYPE_EXTENDED=yes], ++ [gl_cv_acl_ACL_TYPE_EXTENDED=no])]) ++ if test $gl_cv_acl_ACL_TYPE_EXTENDED = yes; then ++ AC_DEFINE([HAVE_ACL_TYPE_EXTENDED], [1], ++ [Define to 1 if the ACL type ACL_TYPE_EXTENDED exists.]) ++ fi ++ else ++ LIB_ACL= ++ fi ++ ]) ++ fi ++ ++ dnl Test for Solaris API (Solaris, Cygwin). ++ if test $use_acl = 0; then ++ AC_CHECK_FUNCS([facl]) ++ if test $ac_cv_func_facl = yes; then ++ AC_SEARCH_LIBS([acl_trivial], [sec], ++ [if test "$ac_cv_search_acl_trivial" != "none required"; then ++ LIB_ACL=$ac_cv_search_acl_trivial ++ fi ++ ]) ++ AC_CHECK_FUNCS([acl_trivial]) ++ use_acl=1 ++ fi ++ fi ++ ++ dnl Test for HP-UX API. ++ if test $use_acl = 0; then ++ AC_CHECK_FUNCS([getacl]) ++ if test $ac_cv_func_getacl = yes; then ++ use_acl=1 ++ fi ++ dnl Test for HP-UX 11.11 API. ++ AC_CHECK_HEADERS([aclv.h], [], [], [#include ]) ++ fi ++ ++ dnl Test for AIX API (AIX 5.3 or newer). ++ if test $use_acl = 0; then ++ AC_CHECK_FUNCS([aclx_get]) ++ if test $ac_cv_func_aclx_get = yes; then ++ use_acl=1 ++ fi ++ fi ++ ++ dnl Test for older AIX API. ++ if test $use_acl = 0 || test "$ac_cv_func_aclx_get" = yes; then ++ AC_CHECK_FUNCS([statacl]) ++ if test $ac_cv_func_statacl = yes; then ++ use_acl=1 ++ fi ++ fi ++ ++ dnl Test for NonStop Kernel API. ++ if test $use_acl = 0; then ++ AC_CHECK_FUNCS([aclsort]) ++ if test $ac_cv_func_aclsort = yes; then ++ use_acl=1 ++ fi ++ fi ++ ++ LIBS=$ac_save_LIBS ++ fi ++ if test "x$enable_acl$use_acl" = "xyes0"; then ++ AC_MSG_ERROR([ACLs enabled but support not detected]) ++ elif test "x$enable_acl$use_acl" = "xauto0"; then ++ AC_MSG_WARN([libacl development library was not found or not usable.]) ++ AC_MSG_WARN([AC_PACKAGE_NAME will be built without ACL support.]) ++ fi ++ fi ++ AC_SUBST([LIB_ACL]) ++ AC_DEFINE_UNQUOTED([USE_ACL], [$use_acl], ++ [Define to nonzero if you want access control list support.]) ++ USE_ACL=$use_acl ++ AC_SUBST([USE_ACL]) ++]) ++ ++# gl_ACL_GET_FILE(IF-WORKS, IF-NOT) ++# ------------------------------------- ++# If 'acl_get_file' works (does not have a particular bug), ++# run IF-WORKS, otherwise, IF-NOT. ++# This tests for a Darwin 8.7.0 bug, whereby acl_get_file returns NULL, ++# but sets errno = ENOENT for an existing file or directory. ++AC_DEFUN([gl_ACL_GET_FILE], ++[ ++ AC_CACHE_CHECK([for working acl_get_file], [gl_cv_func_working_acl_get_file], ++ [AC_RUN_IFELSE( ++ [AC_LANG_PROGRAM( ++ [[#include ++ #include ++ #include ++ ]], ++ [[if (!acl_get_file (".", ACL_TYPE_ACCESS) && errno == ENOENT) ++ return 1; ++ return 0; ++ ]])], ++ [gl_cv_func_working_acl_get_file=yes], ++ [gl_cv_func_working_acl_get_file=no], ++ [gl_cv_func_working_acl_get_file=cross-compiling])]) ++ ++ AS_IF([test $gl_cv_func_working_acl_get_file = yes], [$1], [$2]) ++]) +diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 +index 837538e..147ecc0 100644 +--- a/m4/gnulib-comp.m4 ++++ b/m4/gnulib-comp.m4 +@@ -1,6 +1,3 @@ +-# -*- buffer-read-only: t -*- vi: set ro: +-# DO NOT EDIT! GENERATED AUTOMATICALLY! +-# DO NOT EDIT! GENERATED AUTOMATICALLY! + # Copyright (C) 2002-2011 Free Software Foundation, Inc. + # + # This file is free software, distributed under the terms of the GNU +@@ -256,6 +253,7 @@ AC_DEFUN([gl_INIT], + gl_source_base='gnu' + # Code from module alloca: + # Code from module alloca-opt: ++ gl_FUNC_ACL + gl_FUNC_ALLOCA + # Code from module areadlink: + # Code from module areadlinkat: +@@ -565,6 +563,15 @@ AC_DEFUN([gl_INIT], + gl_SAVE_CWD + # Code from module savedir: + gl_SAVEDIR ++ # Code from module acl: ++ AC_CHECK_HEADERS([selinux/flask.h]) ++ AC_LIBOBJ([selinux-at]) ++ gl_HEADERS_SELINUX_SELINUX_H ++ gl_HEADERS_SELINUX_CONTEXT_H ++ AC_REQUIRE([AC_C_INLINE]) ++ if test "$with_selinux" != no && test "$ac_cv_header_selinux_selinux_h" = yes; then ++ AC_LIBOBJ([getfilecon]) ++ fi + # Code from module setenv: + gl_FUNC_SETENV + gl_STDLIB_MODULE_INDICATOR([setenv]) +@@ -875,10 +882,14 @@ AC_DEFUN([gltests_LIBSOURCES], [ + AC_DEFUN([gl_FILE_LIST], [ + build-aux/arg-nonnull.h + build-aux/c++defs.h ++ build-aux/snippet/unused-parameter.h + build-aux/config.rpath + build-aux/gitlog-to-changelog + build-aux/warn-on-use.h + doc/parse-datetime.texi ++ lib/acl-internal.h ++ lib/acl.h ++ lib/acl_entries.c + lib/alloca.c + lib/alloca.in.h + lib/anytostr.c +@@ -928,6 +939,7 @@ AC_DEFUN([gl_FILE_LIST], [ + lib/closeout.c + lib/closeout.h + lib/config.charset ++ lib/copy-acl.c + lib/dirent--.h + lib/dirent-safer.h + lib/dirent.in.h +@@ -955,6 +967,7 @@ AC_DEFUN([gl_FILE_LIST], [ + lib/fd-safer.c + lib/fdopendir.c + lib/fdutimensat.c ++ lib/file-has-acl.c + lib/fileblocks.c + lib/filenamecat-lgpl.c + lib/filenamecat.h +@@ -1083,6 +1096,11 @@ AC_DEFUN([gl_FILE_LIST], [ + lib/save-cwd.h + lib/savedir.c + lib/savedir.h ++ lib/se-context.in.h ++ lib/se-selinux.in.h ++ lib/selinux-at.c ++ lib/selinux-at.h ++ lib/set-mode-acl.c + lib/setenv.c + lib/size_max.h + lib/sleep.c +@@ -1176,6 +1194,7 @@ AC_DEFUN([gl_FILE_LIST], [ + lib/xvasprintf.c + lib/xvasprintf.h + m4/00gnulib.m4 ++ m4/acl.m4 + m4/alloca.m4 + m4/argmatch.m4 + m4/argp.m4 +@@ -1314,6 +1333,8 @@ AC_DEFUN([gl_FILE_LIST], [ + m4/safe-write.m4 + m4/save-cwd.m4 + m4/savedir.m4 ++ m4/selinux-context-h.m4 ++ m4/selinux-selinux-h.m4 + m4/setenv.m4 + m4/size_max.m4 + m4/sleep.m4 +diff --git a/m4/selinux-context-h.m4 b/m4/selinux-context-h.m4 +new file mode 100644 +index 0000000..7ad67bb +--- /dev/null ++++ b/m4/selinux-context-h.m4 +@@ -0,0 +1,22 @@ ++# serial 3 -*- Autoconf -*- ++# Copyright (C) 2006-2007, 2009-2012 Free Software Foundation, Inc. ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# From Jim Meyering ++# Provide , if necessary. ++ ++AC_DEFUN([gl_HEADERS_SELINUX_CONTEXT_H], ++[ ++ AC_REQUIRE([gl_LIBSELINUX]) ++ if test "$with_selinux" != no; then ++ AC_CHECK_HEADERS([selinux/context.h], ++ [SELINUX_CONTEXT_H=], ++ [SELINUX_CONTEXT_H=selinux/context.h]) ++ else ++ SELINUX_CONTEXT_H=selinux/context.h ++ fi ++ AC_SUBST([SELINUX_CONTEXT_H]) ++ AM_CONDITIONAL([GL_GENERATE_SELINUX_CONTEXT_H], [test -n "$SELINUX_CONTEXT_H"]) ++]) +diff --git a/m4/selinux-selinux-h.m4 b/m4/selinux-selinux-h.m4 +new file mode 100644 +index 0000000..ed5215b +--- /dev/null ++++ b/m4/selinux-selinux-h.m4 +@@ -0,0 +1,69 @@ ++# serial 5 -*- Autoconf -*- ++# Copyright (C) 2006-2007, 2009-2012 Free Software Foundation, Inc. ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# From Jim Meyering ++# Provide , if necessary. ++# If it is already present, provide wrapper functions to guard against ++# misbehavior from getfilecon, lgetfilecon, and fgetfilecon. ++ ++AC_DEFUN([gl_HEADERS_SELINUX_SELINUX_H], ++[ ++ AC_REQUIRE([gl_LIBSELINUX]) ++ if test "$with_selinux" != no; then ++ AC_CHECK_HEADERS([selinux/selinux.h]) ++ ++ if test "$ac_cv_header_selinux_selinux_h" = yes; then ++ # We do have , so do compile getfilecon.c ++ # and arrange to use its wrappers. ++ gl_CHECK_NEXT_HEADERS([selinux/selinux.h]) ++ AC_DEFINE([getfilecon], [rpl_getfilecon], ++ [Always use our getfilecon wrapper.]) ++ AC_DEFINE([lgetfilecon], [rpl_lgetfilecon], ++ [Always use our lgetfilecon wrapper.]) ++ AC_DEFINE([fgetfilecon], [rpl_fgetfilecon], ++ [Always use our fgetfilecon wrapper.]) ++ fi ++ ++ case "$ac_cv_search_setfilecon:$ac_cv_header_selinux_selinux_h" in ++ no:*) # already warned ++ ;; ++ *:no) ++ AC_MSG_WARN([libselinux was found but selinux/selinux.h is missing.]) ++ AC_MSG_WARN([AC_PACKAGE_NAME will be compiled without SELinux support.]) ++ esac ++ else ++ # Do as if does not exist, even if ++ # AC_CHECK_HEADERS_ONCE has already determined that it exists. ++ AC_DEFINE([HAVE_SELINUX_SELINUX_H], [0]) ++ fi ++]) ++ ++AC_DEFUN([gl_LIBSELINUX], ++[ ++ AC_REQUIRE([AC_CANONICAL_HOST]) ++ AC_REQUIRE([AC_CANONICAL_BUILD]) ++ ++ AC_ARG_WITH([selinux], ++ AS_HELP_STRING([--without-selinux], [do not use SELinux, even on systems with SELinux]), ++ [], [with_selinux=maybe]) ++ ++ LIB_SELINUX= ++ if test "$with_selinux" != no; then ++ gl_save_LIBS=$LIBS ++ AC_SEARCH_LIBS([setfilecon], [selinux], ++ [test "$ac_cv_search_setfilecon" = "none required" || ++ LIB_SELINUX=$ac_cv_search_setfilecon]) ++ LIBS=$gl_save_LIBS ++ fi ++ AC_SUBST([LIB_SELINUX]) ++ ++ # Warn if SELinux is found but libselinux is absent; ++ if test "$ac_cv_search_setfilecon" = no && ++ test "$host" = "$build" && test -d /selinux; then ++ AC_MSG_WARN([This system supports SELinux but libselinux is missing.]) ++ AC_MSG_WARN([AC_PACKAGE_NAME will be compiled without SELinux support.]) ++ fi ++]) +-- +1.8.1.2 diff --git a/SOURCES/tar-1.26-silence-gcc.patch b/SOURCES/tar-1.26-silence-gcc.patch new file mode 100644 index 00000000..b9bce2ce --- /dev/null +++ b/SOURCES/tar-1.26-silence-gcc.patch @@ -0,0 +1,152 @@ +diff --git a/lib/rmt.h b/lib/rmt.h +index 2ce9dc5..4580e49 100644 +--- a/lib/rmt.h ++++ b/lib/rmt.h +@@ -17,8 +17,9 @@ + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +-extern char *rmt_command; +-extern char *rmt_dev_name__; ++/* upstream fix 0b3d84a0ee */ ++extern char const *rmt_command; ++extern char const *rmt_dev_name__; + + int rmt_open__ (const char *, int, int, const char *); + int rmt_close__ (int); +diff --git a/lib/rtapelib.c b/lib/rtapelib.c +index 3aee428..1cef0fc 100644 +--- a/lib/rtapelib.c ++++ b/lib/rtapelib.c +@@ -90,10 +90,10 @@ static int from_remote[MAXUNIT][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}}; + /* The pipes for sending data to remote tape drives. */ + static int to_remote[MAXUNIT][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}}; + +-char *rmt_command = DEFAULT_RMT_COMMAND; ++char const *rmt_command = DEFAULT_RMT_COMMAND; /* upstream fix 0b3d84a0ee */ + + /* Temporary variable used by macros in rmt.h. */ +-char *rmt_dev_name__; ++char const *rmt_dev_name__; /* upstream fix 0b3d84a0ee */ + + /* If true, always consider file names to be local, even if they contain + colons */ +@@ -490,15 +490,17 @@ rmt_open__ (const char *file_name, int open_mode, int bias, + { + /* Child. */ + +- close (STDIN_FILENO); +- dup (to_remote[remote_pipe_number][PREAD]); +- close (to_remote[remote_pipe_number][PREAD]); +- close (to_remote[remote_pipe_number][PWRITE]); +- +- close (STDOUT_FILENO); +- dup (from_remote[remote_pipe_number][PWRITE]); +- close (from_remote[remote_pipe_number][PREAD]); +- close (from_remote[remote_pipe_number][PWRITE]); ++ /* upstream fix 0b3d84a0ee */ ++ if (dup2 (to_remote[remote_pipe_number][PREAD], STDIN_FILENO) < 0 ++ || (to_remote[remote_pipe_number][PREAD] != STDIN_FILENO ++ && close (to_remote[remote_pipe_number][PREAD]) != 0) ++ || (to_remote[remote_pipe_number][PWRITE] != STDIN_FILENO ++ && close (to_remote[remote_pipe_number][PWRITE]) != 0) ++ || dup2 (from_remote[remote_pipe_number][PWRITE], STDOUT_FILENO) < 0 ++ || close (from_remote[remote_pipe_number][PREAD]) != 0 ++ || close (from_remote[remote_pipe_number][PWRITE]) != 0) ++ error (EXIT_ON_EXEC_ERROR, errno, ++ _("Cannot redirect files for remote shell")); + + sys_reset_uid_gid (); + +diff --git a/lib/system.h b/lib/system.h +index 2deb585..599d4ba 100644 +--- a/lib/system.h ++++ b/lib/system.h +@@ -471,8 +471,13 @@ char *getenv (); + # define SET_BINARY_MODE(arc) + # define ERRNO_IS_EACCES 0 + # define TTY_NAME "/dev/tty" +-# define sys_reset_uid_gid() \ +- do { setuid (getuid ()); setgid (getgid ()); } while (0) ++ ++/* upstream fix 0b3d84a0ee */ ++# define sys_reset_uid_gid() \ ++ do { \ ++ if (! (setuid (getuid ()) == 0 && setgid (getgid ()) == 0)) \ ++ abort (); \ ++ } while (0) + #endif + + #if XENIX +diff --git a/src/compare.c b/src/compare.c +index 273269a..796d7aa 100644 +--- a/src/compare.c ++++ b/src/compare.c +@@ -362,7 +362,7 @@ static void + diff_dumpdir (void) + { + const char *dumpdir_buffer; +- dev_t dev = 0; ++ /* upstream fix 5bb04335079 */ + struct stat stat_data; + + if (deref_stat (current_stat_info.file_name, &stat_data) != 0) +@@ -372,8 +372,7 @@ diff_dumpdir (void) + else + stat_error (current_stat_info.file_name); + } +- else +- dev = stat_data.st_dev; ++ /* upstream fix 5bb04335079 */ + + dumpdir_buffer = directory_contents (scan_directory (¤t_stat_info)); + +diff --git a/tests/genfile.c b/tests/genfile.c +index 8541be6..fa480ef 100644 +--- a/tests/genfile.c ++++ b/tests/genfile.c +@@ -485,9 +485,11 @@ generate_files_from_list () + static void + mkhole (int fd, off_t displ) + { +- if (lseek (fd, displ, SEEK_CUR) == -1) ++ off_t offset = lseek (fd, displ, SEEK_CUR); ++ if (offset < 0) + error (EXIT_FAILURE, errno, "lseek"); +- ftruncate (fd, lseek (fd, 0, SEEK_CUR)); ++ if (ftruncate (fd, offset) != 0) ++ error (EXIT_FAILURE, errno, "ftruncate"); + } + + static void +@@ -685,13 +687,18 @@ exec_checkpoint (struct action *p) + error (0, errno, _("cannot open `%s'"), p->name); + break; + } +- ftruncate (fd, p->size); ++ if (ftruncate (fd, p->size) != 0) ++ { ++ error (0, errno, _("cannot truncate `%s'"), p->name); ++ break; ++ } + close (fd); + } + break; + + case OPT_EXEC: +- system (p->name); ++ if (system (p->name) != 0) ++ error (0, 0, _("command failed: %s"), p->name); + break; + + case OPT_UNLINK: +@@ -761,7 +768,8 @@ exec_command (void) + signal (SIGCHLD, SIG_DFL); + #endif + +- pipe (fd); ++ if (pipe (fd) != 0) ++ error (EXIT_FAILURE, errno, "pipe"); + + pid = fork (); + if (pid == -1) diff --git a/SOURCES/tar-1.26-stdio.in.patch b/SOURCES/tar-1.26-stdio.in.patch new file mode 100644 index 00000000..c6e89f08 --- /dev/null +++ b/SOURCES/tar-1.26-stdio.in.patch @@ -0,0 +1,14 @@ +diff --git a/gnu/stdio.in.h b/gnu/stdio.in.h +index 465a9c9..b703457 100644 +--- a/gnu/stdio.in.h ++++ b/gnu/stdio.in.h +@@ -164,7 +164,9 @@ _GL_WARN_ON_USE (fflush, "fflush is not always POSIX compliant - " + so any use of gets warrants an unconditional warning. Assume it is + always declared, since it is required by C89. */ + #undef gets ++#if HAVE_RAW_DECL_GETS + _GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead"); ++#endif + + #if @GNULIB_FOPEN@ + # if @REPLACE_FOPEN@ diff --git a/SOURCES/tar-1.26-update-with-change-directory.patch b/SOURCES/tar-1.26-update-with-change-directory.patch new file mode 100644 index 00000000..ec58fac7 --- /dev/null +++ b/SOURCES/tar-1.26-update-with-change-directory.patch @@ -0,0 +1,147 @@ +From 207b445ca7018a95f2f96d9514b8d87c80e8e11e Mon Sep 17 00:00:00 2001 +From: Pavel Raiskup +Date: Wed, 4 Apr 2012 18:04:53 +0200 +Subject: [PATCH] Bad cooperation of -C and -u options + +Previously, tar did not update archive with newly created files in archived +directory -- it failed instead with "file not found" error (because it looked +in bad directory in filesystem). +--- + src/update.c | 4 +- + tests/Makefile.am | 3 +- + tests/testsuite.at | 3 +- + tests/update03.at | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 65 insertions(+), 4 deletions(-) + create mode 100644 tests/update03.at + +diff --git a/src/update.c b/src/update.c +index e3228d4..4739e0d 100644 +--- a/src/update.c ++++ b/src/update.c +@@ -1,7 +1,7 @@ + /* Update a tar archive. + + Copyright (C) 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001, 2003, +- 2004, 2005, 2007, 2010 Free Software Foundation, Inc. ++ 2004, 2005, 2007, 2010, 2011, 2012 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the +@@ -159,7 +159,7 @@ update_archive (void) + + for (p = dirp; *p; p += strlen (p) + 1) + addname (namebuf_name (nbuf, p), +- 0, false, NULL); ++ name->change_dir, false, NULL); + + namebuf_free (nbuf); + free (dirp); +diff --git a/tests/Makefile.am b/tests/Makefile.am +index ab7d104..119f1f3 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -1,7 +1,7 @@ + # Makefile for GNU tar regression tests. + + # Copyright (C) 1996, 1997, 1999, 2000, 2001, 2003, 2004, 2005, +-# 2006, 2007, 2009 Free Software Foundation, Inc. ++# 2006, 2007, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. + + # François Pinard , 1988. + # Sergey Poznyakoff , 2004. +@@ -156,6 +156,7 @@ TESTSUITE_AT = \ + update.at\ + update01.at\ + update02.at\ ++ update03.at\ + volsize.at\ + volume.at\ + verbose.at\ +diff --git a/tests/testsuite.at b/tests/testsuite.at +index 8366ef0..13f7506 100644 +--- a/tests/testsuite.at ++++ b/tests/testsuite.at +@@ -1,7 +1,7 @@ + # Process this file with autom4te to create testsuite. -*- Autotest -*- + + # Test suite for GNU tar. +-# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Free Software ++# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010, 2011, 2012 Free Software + # Foundation, Inc. + + # This program is free software; you can redistribute it and/or modify +@@ -241,6 +241,7 @@ m4_include([spmvp10.at]) + m4_include([update.at]) + m4_include([update01.at]) + m4_include([update02.at]) ++m4_include([update03.at]) + + m4_include([verify.at]) + +diff --git a/tests/update03.at b/tests/update03.at +new file mode 100644 +index 0000000..185f9eb +--- /dev/null ++++ b/tests/update03.at +@@ -0,0 +1,59 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++ ++# Test suite for GNU tar. ++# Copyright (C) 2012 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify it under ++# the terms of the GNU General Public License as published by the Free Software ++# Foundation; either version 3, or (at your option) any later version. ++ ++# This program is distributed in the hope that it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ++# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ++# details. ++ ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin ++# Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ ++# Description: ++# Test if the '--update' option works with the '--directory DIR' option ++# properly. In version <= 1.26 tar this combination caused problems. ++# ++# References: ++# https://bugzilla.redhat.com/show_bug.cgi?id=688567 ++# ++# Last-Affected-Version: 1.26.90 ++ ++AT_SETUP([update & change directory (-C)]) ++AT_KEYWORDS([update update03]) ++ ++AT_TAR_CHECK([ ++AT_SORT_PREREQ ++ ++# prepare filesystem ++mkdir dir ++mkdir dir/subdir ++genfile --file dir/subdir/a ++ ++# crate archive of subdir ++tar -C dir -cf file.tar subdir ++ ++# update filesystem ++mkdir dir/subdir/b ++genfile --file dir/subdir/b/c ++ ++# sync the 'file.tar' archive ++tar -C dir -uf file.tar subdir ++ ++# print contents ++tar -tf file.tar | sort || exit 1 ++], ++[0], ++[subdir/ ++subdir/a ++subdir/b/ ++subdir/b/c ++]) ++ ++AT_CLEANUP +-- +1.7.7.6 diff --git a/SOURCES/tar-1.26-xattrs-exclude-include-repair.patch b/SOURCES/tar-1.26-xattrs-exclude-include-repair.patch new file mode 100644 index 00000000..4010cd2b --- /dev/null +++ b/SOURCES/tar-1.26-xattrs-exclude-include-repair.patch @@ -0,0 +1,121 @@ +diff -urN tar-1.26/src/xattrs.c tar-1.26new/src/xattrs.c +--- tar-1.26/src/xattrs.c 2017-01-10 10:58:11.894958586 +0100 ++++ tar-1.26new/src/xattrs.c 2017-01-10 11:54:23.418221159 +0100 +@@ -436,8 +436,12 @@ + clear_mask_map (&xattrs_setup.excl); + } + +-/* get all xattrs from file given by FILE_NAME or FD (when non-zero). This +- includes all the user.*, security.*, system.*, etc. available domains */ ++static bool xattrs_masked_out (const char *kw, bool archiving); ++ ++/* get xattrs from file given by FILE_NAME or FD (when non-zero) ++ xattrs are checked against the user supplied include/exclude mask ++ if no mask is given this includes all the user.*, security.*, system.*, ++ etc. available domains */ + void + xattrs_xattrs_get (int parentfd, char const *file_name, + struct tar_stat_info *st, int fd) +@@ -482,8 +486,6 @@ + size_t len = strlen (attr); + ssize_t aret = 0; + +- /* Archive all xattrs during creation, decide at extraction time +- * which ones are of interest/use for the target filesystem. */ + while (((fd == 0) + ? ((aret = lgetxattrat (parentfd, file_name, attr, + val, asz)) == -1) +@@ -494,7 +496,10 @@ + } + + if (aret != -1) +- xheader_xattr_add (st, attr, val, aret); ++ { ++ if (!xattrs_masked_out (attr, true)) ++ xheader_xattr_add (st, attr, val, aret); ++ } + else if (errno != ENOATTR) + call_arg_warn ((fd == 0) ? "lgetxattrat" + : "fgetxattr", file_name); +diff -urN tar-1.26/tests/Makefile.am tar-1.26new/tests/Makefile.am +--- tar-1.26/tests/Makefile.am 2017-01-10 10:58:11.894958586 +0100 ++++ tar-1.26new/tests/Makefile.am 2017-01-10 11:53:55.046987231 +0100 +@@ -177,6 +177,7 @@ + xattr03.at\ + xattr04.at\ + xattr05.at\ ++ xattr06.at\ + acls01.at\ + acls02.at\ + acls03.at\ +diff -urN tar-1.26/tests/testsuite.at tar-1.26new/tests/testsuite.at +--- tar-1.26/tests/testsuite.at 2017-01-10 10:58:11.896958604 +0100 ++++ tar-1.26new/tests/testsuite.at 2017-01-10 11:53:55.047987240 +0100 +@@ -338,6 +338,7 @@ + m4_include([xattr03.at]) + m4_include([xattr04.at]) + m4_include([xattr05.at]) ++m4_include([xattr06.at]) + + m4_include([acls01.at]) + m4_include([acls02.at]) +diff -urN tar-1.26/tests/xattr06.at tar-1.26new/tests/xattr06.at +--- tar-1.26/tests/xattr06.at 1970-01-01 01:00:00.000000000 +0100 ++++ tar-1.26new/tests/xattr06.at 2017-01-10 11:54:23.418221159 +0100 +@@ -0,0 +1,56 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# ++# Test suite for GNU tar. ++# Copyright 2012-2014, 2016 Free Software Foundation, Inc. ++ ++# This file is part of GNU tar. ++ ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++ ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++ ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++# Test description: Test for exclude of xattr during archive creation ++# ++# Relevant mailing list thread: ++# ++# http://lists.gnu.org/archive/html/bug-tar/2016-05/msg00031.html ++ ++AT_SETUP([xattrs: exclude xattrs on create ]) ++AT_KEYWORDS([xattrs xattr06]) ++ ++AT_TAR_CHECK([ ++AT_XATTRS_PREREQ ++ ++mkdir dir ++mkdir output ++genfile --file dir/file ++ ++for attr in excluded incla inclb inclc incl_excluded ++do ++ setfattr -n user.${attr} -v value dir/file || AT_SKIP_TEST ++done ++ ++tar --xattrs-include=user.incl'*' --xattrs-exclude=user.incl_excluded -cf archive.tar -C dir . ++tar -xf archive.tar --xattrs-include=user.incl[[ab]] --xattrs-exclude=user.inclb -C output ++ ++getfattr -d output/file | grep -v \ ++ -e excluded \ ++ -e inclb \ ++ -e inclc > filtered ++getfattr -d output/file > full ++# if they differ then the attribute is still present ++diff filtered full ++], ++[0], ++[]) ++ ++AT_CLEANUP diff --git a/SOURCES/tar-1.26-xattrs-include-implies-xattrs.patch b/SOURCES/tar-1.26-xattrs-include-implies-xattrs.patch new file mode 100644 index 00000000..f6b1f622 --- /dev/null +++ b/SOURCES/tar-1.26-xattrs-include-implies-xattrs.patch @@ -0,0 +1,38 @@ +diff --git a/src/tar.c b/src/tar.c +index e244808..18277e4 100644 +--- a/src/tar.c ++++ b/src/tar.c +@@ -162,6 +162,14 @@ set_archive_format (char const *name) + archive_format = p->fmt; + } + ++static void ++set_xattr_option (int value) ++{ ++ if (value == 1) ++ set_archive_format ("posix"); ++ xattrs_option = value; ++} ++ + const char * + archive_format_string (enum archive_format fmt) + { +@@ -2141,16 +2149,16 @@ parse_opt (int key, char *arg, struct argp_state *state) + break; + + case XATTR_OPTION: +- set_archive_format ("posix"); +- xattrs_option = 1; ++ set_xattr_option (1); + break; + + case NO_XATTR_OPTION: +- xattrs_option = -1; ++ set_xattr_option (-1); + break; + + case XATTR_INCLUDE: + case XATTR_EXCLUDE: ++ set_xattr_option (1); + xattrs_mask_add (arg, (key == XATTR_INCLUDE)); + break; diff --git a/SOURCES/tar-1.26-xattrs-printing.patch b/SOURCES/tar-1.26-xattrs-printing.patch new file mode 100644 index 00000000..11952650 --- /dev/null +++ b/SOURCES/tar-1.26-xattrs-printing.patch @@ -0,0 +1,35 @@ +diff --git a/src/xattrs.c b/src/xattrs.c +index 5a4bf72..bdf6ba0 100644 +--- a/src/xattrs.c ++++ b/src/xattrs.c +@@ -693,7 +693,7 @@ xattrs_print_char (struct tar_stat_info const *st, char *output) + if (selinux_context_option > 0 && st->cntx_name) + *output = '.'; + +- if (acls_option && (st->acls_a_len || st->acls_d_len)) ++ if (acls_option > 0 && (st->acls_a_len || st->acls_d_len)) + *output = '+'; + } + +@@ -704,11 +704,11 @@ xattrs_print (struct tar_stat_info const *st) + return; + + /* selinux */ +- if (selinux_context_option && st->cntx_name) ++ if (selinux_context_option > 0 && st->cntx_name) + fprintf (stdlis, " s: %s\n", st->cntx_name); + + /* acls */ +- if (acls_option && (st->acls_a_len || st->acls_d_len)) ++ if (acls_option > 0 && (st->acls_a_len || st->acls_d_len)) + { + fprintf (stdlis, " a: "); + acls_one_line ("", ',', st->acls_a_ptr, st->acls_a_len); +@@ -717,7 +717,7 @@ xattrs_print (struct tar_stat_info const *st) + } + + /* xattrs */ +- if (xattrs_option && st->xattr_map_size) ++ if (xattrs_option > 0 && st->xattr_map_size) + { + int i; diff --git a/SOURCES/tar-1.26-xattrs-skip-old-files-hangs.patch b/SOURCES/tar-1.26-xattrs-skip-old-files-hangs.patch new file mode 100644 index 00000000..994b85e7 --- /dev/null +++ b/SOURCES/tar-1.26-xattrs-skip-old-files-hangs.patch @@ -0,0 +1,214 @@ +diff --git a/THANKS b/THANKS +index e87381f..6fa0a9e 100644 +--- a/THANKS ++++ b/THANKS +@@ -131,6 +131,7 @@ David Nugent davidn@blaze.net.au + David Shaw david.shaw@alcatel.com.au + David Steiner dsteiner@ispa.uni-osnabrueck.de + David Taylor taylor@think.com ++Dawid dpc@dpc.pw + Dean Gaudet dgaudet@watdragon.uwaterloo.ca + Demizu Noritoshi nori-d@is.aist-nara.ac.jp + Denis Excoffier denis.excoffier@free.fr +diff --git a/src/extract.c b/src/extract.c +index b622a2a..63e4d14 100644 +--- a/src/extract.c ++++ b/src/extract.c +@@ -745,13 +745,13 @@ maybe_recoverable (char *file_name, bool regular, bool *interdir_made) + in advance dramatically improves the following performance of reading and + writing a file). If not restoring permissions, invert the INVERT_PERMISSIONS + bits from the file's current permissions. TYPEFLAG specifies the type of the +- file. FILE_CREATED indicates set_xattr has created the file */ ++ file. Returns non-zero when error occurs (while un-available xattrs is not ++ an error, rather no-op). Non-zero FILE_CREATED indicates set_xattr has ++ created the file. */ + static int + set_xattr (char const *file_name, struct tar_stat_info const *st, + mode_t invert_permissions, char typeflag, int *file_created) + { +- int status = 0; +- + #ifdef HAVE_XATTRS + bool interdir_made = false; + +@@ -759,17 +759,32 @@ set_xattr (char const *file_name, struct tar_stat_info const *st, + { + mode_t mode = current_stat_info.stat.st_mode & MODE_RWX & ~ current_umask; + +- do +- status = mknodat (chdir_fd, file_name, mode ^ invert_permissions, 0); +- while (status && maybe_recoverable ((char *)file_name, false, +- &interdir_made)); ++ for (;;) ++ { ++ if (!mknodat (chdir_fd, file_name, mode ^ invert_permissions, 0)) ++ { ++ /* Successfully created file */ ++ xattrs_xattrs_set (st, file_name, typeflag, 0); ++ *file_created = 1; ++ return 0; ++ } + +- xattrs_xattrs_set (st, file_name, typeflag, 0); +- *file_created = 1; ++ switch (maybe_recoverable ((char *)file_name, false, &interdir_made)) ++ { ++ case RECOVER_OK: ++ continue; ++ case RECOVER_NO: ++ skip_member (); ++ open_error (file_name); ++ return 1; ++ case RECOVER_SKIP: ++ return 0; ++ } ++ } + } + #endif + +- return(status); ++ return 0; + } + + /* Fix the statuses of all directories whose statuses need fixing, and +@@ -1089,11 +1104,7 @@ extract_file (char *file_name, int typeflag) + int file_created = 0; + if (set_xattr (file_name, ¤t_stat_info, invert_permissions, + typeflag, &file_created)) +- { +- skip_member (); +- open_error (file_name); +- return 1; +- } ++ return 1; + + while ((fd = open_output_file (file_name, typeflag, mode, + file_created, ¤t_mode, +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 2a70314..8e1ef8d 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -200,6 +200,7 @@ TESTSUITE_AT = \ + xattr04.at\ + xattr05.at\ + xattr06.at\ ++ xattr07.at\ + acls01.at\ + acls02.at\ + acls03.at\ +diff --git a/tests/testsuite.at b/tests/testsuite.at +index ebce9cc..3eb0eee 100644 +--- a/tests/testsuite.at ++++ b/tests/testsuite.at +@@ -361,6 +361,7 @@ m4_include([xattr03.at]) + m4_include([xattr04.at]) + m4_include([xattr05.at]) + m4_include([xattr06.at]) ++m4_include([xattr07.at]) + + m4_include([acls01.at]) + m4_include([acls02.at]) +diff --git a/tests/xattr07.at b/tests/xattr07.at +new file mode 100644 +index 0000000..a834981 +--- /dev/null ++++ b/tests/xattr07.at +@@ -0,0 +1,73 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# ++# Test suite for GNU tar. ++# Copyright 2011, 2013-2014, 2016 Free Software Foundation, Inc. ++ ++# This file is part of GNU tar. ++ ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++ ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++ ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++# Test description: ++# Test that --keep-old-files doesn't change xattrs of already existing file. ++# Per report: ++# https://lists.gnu.org/archive/html/bug-tar/2016-10/msg00001.html ++ ++AT_SETUP([xattrs: xattrs and --skip-old-files]) ++AT_KEYWORDS([xattrs xattr07]) ++ ++AT_TAR_CHECK([ ++AT_XATTRS_PREREQ ++mkdir dir ++genfile --file dir/file ++genfile --file dir/file2 ++ ++setfattr -n user.test -v OurDirValue dir ++setfattr -n user.test -v OurFileValue dir/file ++setfattr -n user.test -v OurFileValue dir/file2 ++ ++tar --xattrs -cf archive.tar dir ++ ++setfattr -n user.test -v OurDirValue2 dir ++setfattr -n user.test -v OurFileValue2 dir/file ++setfattr -n user.test -v OurFileValue2 dir/file2 ++ ++# Check that tar continues to file2 too! ++tar --xattrs -xvf archive.tar --skip-old-files ++tar --xattrs -xvf archive.tar --keep-old-files ++ ++getfattr -h -d dir | grep -v -e '^#' -e ^$ ++getfattr -h -d dir/file | grep -v -e '^#' -e ^$ ++getfattr -h -d dir/file2 | grep -v -e '^#' -e ^$ ++], ++[0], ++[dir/ ++dir/file ++dir/file2 ++dir/ ++dir/file ++dir/file2 ++user.test="OurDirValue2" ++user.test="OurFileValue2" ++user.test="OurFileValue2" ++], [tar: dir: skipping existing file ++tar: dir/file: skipping existing file ++tar: dir/file: skipping existing file ++tar: dir/file2: skipping existing file ++tar: dir/file2: skipping existing file ++tar: dir/file: Cannot open: File exists ++tar: dir/file2: Cannot open: File exists ++tar: Exiting with failure status due to previous errors ++]) ++ ++AT_CLEANUP +From f2a7560718946e0920b55419f0953953bf824077 Mon Sep 17 00:00:00 2001 +From: Pavel Raiskup +Date: Mon, 28 Nov 2016 08:44:42 +0100 +Subject: [PATCH] tests: more deterministic xattr07 + +* tests/xattr07.at: Define order of files within tested archive. +--- + tests/xattr07.at | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/xattr07.at b/tests/xattr07.at +index a834981..47d54b8 100644 +--- a/tests/xattr07.at ++++ b/tests/xattr07.at +@@ -36,7 +36,7 @@ setfattr -n user.test -v OurDirValue dir + setfattr -n user.test -v OurFileValue dir/file + setfattr -n user.test -v OurFileValue dir/file2 + +-tar --xattrs -cf archive.tar dir ++tar --xattrs --no-recursion -cf archive.tar dir dir/file dir/file2 + + setfattr -n user.test -v OurDirValue2 dir + setfattr -n user.test -v OurFileValue2 dir/file +-- +2.13.5 diff --git a/SOURCES/tar-1.26-xattrs.patch b/SOURCES/tar-1.26-xattrs.patch new file mode 100644 index 00000000..45afefa1 --- /dev/null +++ b/SOURCES/tar-1.26-xattrs.patch @@ -0,0 +1,3233 @@ +diff --git a/NEWS b/NEWS +index 12c1dd6..8aeae33 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,4 +1,4 @@ +-GNU tar NEWS - User visible changes. 2011-03-12 ++GNU tar NEWS - User visible changes. 2012-11-19 + Please send GNU tar bug reports to + + +@@ -22,6 +22,17 @@ zero-sized files. + When invoked with these two options, tar 1.25 would add only the + top-level directory to the archive, but not its contents. + ++* Support for POSIX ACLs, extended attributes and SELinux context. ++ ++Starting with this version tar is able to store, extract and list ++extended file attributes, POSIX.1e ACLs and SELinux context. This is ++controlled by the command line options --xattrs, --acls and --selinux, ++correspondingly. Each of these options has a `--no-' counterpart ++(e.g. --no-xattrs), which disables the corresponding feature. ++Additionally, the options --xattrs-include and --xattrs-exclude allow ++you to selectively control for which files to store (or extract) the ++extended attributes. ++ + + version 1.25 - Sergey Poznyakoff, 2010-11-07 + +diff --git a/THANKS b/THANKS +index 0364c50..54c96a0 100644 +--- a/THANKS ++++ b/THANKS +@@ -296,6 +296,7 @@ Kimmy Posey kimmyd@bnr.ca + Koji Kishi kis@rqa.sony.co.jp + Konno Hiroharu konno@pac.co.jp + Kurt Jaeger pi@lf.net ++James Antill jantill@redhat.com + Larry Creech lcreech@lonestar.rcclub.org + Larry Schwimmer rosebud@cyclone.stanford.edu + Lasse Collin lasse.collin@tukaani.org +@@ -374,6 +375,7 @@ Oswald P. Backus IV backus@lks.csi.com + Pascal Meheut pascal@cnam.cnam.fr + Patrick Fulconis fulco@sig.uvsq.fr + Patrick Timmons timmons@electech.polymtl.ca ++Pavel Raiskup praiskup@redhat.com + Paul Eggert eggert@twinsun.com + Paul Kanz paul@icx.com + Paul Mitchell P.Mitchell@surrey.ac.uk +diff --git a/acinclude.m4 b/acinclude.m4 +index 10a27e5..30381d3 100644 +--- a/acinclude.m4 ++++ b/acinclude.m4 +@@ -24,3 +24,29 @@ AC_DEFUN([TAR_COMPR_PROGRAM],[ + [tar_compr_var=m4_if($2,,$1,$2)]) + AC_DEFINE_UNQUOTED(tar_compr_define, "$tar_compr_var", + [Define to the program name of ]$1[ compressor program])]) ++ ++# Provide , if necessary ++ ++AC_DEFUN([TAR_HEADERS_ATTR_XATTR_H], ++[ ++ AC_ARG_WITH([xattrs], ++ AS_HELP_STRING([--without-xattrs], [don't use linux extended attributes]), ++ [], [with_xattrs=maybe] ++ ) ++ ++ AC_CHECK_HEADERS([attr/xattr.h]) ++ AM_CONDITIONAL([TAR_COND_XATTR_H],[test "$ac_cv_header_attr_xattr_h" = yes]) ++ if test "$ac_cv_header_attr_xattr_h" = yes; then ++ AC_CHECK_FUNCS(getxattr fgetxattr lgetxattr \ ++ setxattr fsetxattr lsetxattr \ ++ listxattr flistxattr llistxattr, ++ # only when functions are present ++ AC_DEFINE([HAVE_ATTR_XATTR_H], [1], ++ [define to 1 if we have header]) ++ if test "$with_xattrs" != no; then ++ AC_DEFINE([HAVE_XATTRS],,[Define when we have working linux xattrs.]) ++ fi ++ ) ++ fi ++]) ++ +\ No newline at end of file +diff --git a/configure.ac b/configure.ac +index db69cb8..9b3e0c8 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -70,6 +70,29 @@ if test $diff_cv_st_fstype_string = yes; then + [Define if struct stat has a char st_fstype[] member.]) + fi + ++# even if we use gnulib's acl.h with integrated m4 file later on (used because ++# of very useful file_has_acl() function) we need following checks that restrict ++# tar to use POSIX.1e ACLs only. ++AC_ARG_WITH([posix-acls], ++ AS_HELP_STRING([--without-posix-acls], ++ [do not use POSIX.1e access control lists]), ++ [with_posix_acls=no]) ++if test "x$with_posix_acls" != "xno"; then ++ AC_CHECK_HEADERS(sys/acl.h,, [with_posix_acl=no]) ++ AC_SEARCH_LIBS([acl_get_file], [acl pacl],, [with_posix_acl=no]) ++ AC_SEARCH_LIBS([acl_get_fd], [acl pacl],, [with_posix_acl=no]) ++ AC_SEARCH_LIBS([acl_set_file], [acl pacl],, [with_posix_acl=no]) ++ AC_SEARCH_LIBS([acl_set_fd], [acl pacl],, [with_posix_acl=no]) ++ AC_SEARCH_LIBS([acl_to_text], [acl pacl],, [with_posix_acl=no]) ++ AC_SEARCH_LIBS([acl_from_text], [acl pacl],, [with_posix_acl=no]) ++ if test "x$with_posix_acls" != xno; then ++ AC_DEFINE(HAVE_POSIX_ACLS,,[Define when we have working POSIX acls]) ++ fi ++else ++ # disable acls in gnulib's checks ++ export enable_acl=no ++fi ++ + AC_TYPE_SIGNAL + AC_TYPE_MODE_T + AC_TYPE_PID_T +@@ -90,7 +113,10 @@ gl_INIT + # paxutils modules + tar_PAXUTILS + ++TAR_HEADERS_ATTR_XATTR_H ++ + AC_CHECK_FUNCS_ONCE([fchmod fchown fsync lstat mkfifo readlink symlink]) ++ + AC_CHECK_DECLS([getgrgid],,, [#include ]) + AC_CHECK_DECLS([getpwuid],,, [#include ]) + AC_CHECK_DECLS([time],,, [#include ]) +diff --git a/lib/Makefile.am b/lib/Makefile.am +index efd6826..d73fac8 100644 +--- a/lib/Makefile.am ++++ b/lib/Makefile.am +@@ -28,11 +28,24 @@ BUILT_SOURCES = rmt-command.h + CLEANFILES = rmt-command.h rmt-command.h-t + INCLUDES = -I$(top_srcdir)/gnu -I../ -I../gnu + +-noinst_HEADERS = system.h system-ioctl.h rmt.h paxlib.h stdopen.h ++noinst_HEADERS = system.h system-ioctl.h rmt.h paxlib.h stdopen.h xattr-at.h + libtar_a_SOURCES = \ + paxerror.c paxexit-status.c paxlib.h paxnames.c \ + prepargs.c prepargs.h \ + rtapelib.c \ + rmt.h \ + stdopen.c stdopen.h \ +- system.h system-ioctl.h ++ system.h system-ioctl.h \ ++ xattr-at.c ++ ++if !TAR_COND_XATTR_H ++BUILT_SOURCES += attr/xattr.h ++attr/xattr.h: attr-xattr.in.h $(top_builddir)/config.status ++ $(AM_V_at)$(MKDIR_P) attr ++ $(AM_V_GEN)rm -f $@-t $@ && \ ++ cp $(srcdir)/attr-xattr.in.h attr/xattr.h ++ ++MOSTLYCLEANFILES = attr/xattr.h attr/xattr.h ++endif ++ ++EXTRA_DIST = attr-xattr.in.h +diff --git a/lib/attr-xattr.in.h b/lib/attr-xattr.in.h +new file mode 100644 +index 0000000..b5796fe +--- /dev/null ++++ b/lib/attr-xattr.in.h +@@ -0,0 +1,58 @@ ++/* Replacement for platforms that lack it. ++ Copyright (C) 2012 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#ifndef TAR_ATTR_XATTR_H ++#define TAR_ATTR_XATTR_H ++#include ++ ++/* setting */ ++static inline int setxattr (const char *path, const char *name, const void ++ *value, size_t size, int flags) ++{ errno = ENOTSUP; return -1; } ++ ++static inline int lsetxattr (const char *path, const char *name, const void ++ *value, size_t size, int flags) ++{ errno = ENOTSUP; return -1; } ++ ++static inline int fsetxattr (int filedes, const char *name, const void *value, ++ size_t size, int flags) ++{ errno = ENOTSUP; return -1; } ++ ++ ++/* getting */ ++static inline ssize_t getxattr (const char *path, const char *name, void *value, ++ size_t size) ++{ errno = ENOTSUP; return -1; } ++static inline ssize_t lgetxattr (const char *path, const char *name, void ++ *value, size_t size) ++{ errno = ENOTSUP; return -1; } ++static inline ssize_t fgetxattr (int filedes, const char *name, void *value, ++ size_t size) ++{ errno = ENOTSUP; return -1; } ++ ++ ++/* listing */ ++static inline ssize_t listxattr (const char *path, char *list, size_t size) ++{ errno = ENOTSUP; return -1; } ++ ++static inline ssize_t llistxattr (const char *path, char *list, size_t size) ++{ errno = ENOTSUP; return -1; } ++ ++static inline ssize_t flistxattr (int filedes, char *list, size_t size) ++{ errno = ENOTSUP; return -1; } ++ ++#endif ++ +diff --git a/lib/xattr-at.c b/lib/xattr-at.c +new file mode 100644 +index 0000000..746578c +--- /dev/null ++++ b/lib/xattr-at.c +@@ -0,0 +1,110 @@ ++/* openat-style fd-relative functions for operating with extended file ++ attributes. ++ ++ Copyright (C) 2012 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#include ++ ++#include "xattr-at.h" ++#include "openat.h" ++ ++#include ++#include ++#include ++#include ++ ++#include "dirname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */ ++#include "save-cwd.h" ++ ++#include "openat-priv.h" ++ ++/* setxattrat */ ++#define AT_FUNC_NAME setxattrat ++#define AT_FUNC_F1 setxattr ++#define AT_FUNC_POST_FILE_PARAM_DECLS , const char *name, const void *value \ ++ , size_t size, int flags ++#define AT_FUNC_POST_FILE_ARGS , name, value, size, flags ++#include "at-func.c" ++#undef AT_FUNC_NAME ++#undef AT_FUNC_F1 ++#undef AT_FUNC_POST_FILE_PARAM_DECLS ++#undef AT_FUNC_POST_FILE_ARGS ++ ++/* lsetxattrat */ ++#define AT_FUNC_NAME lsetxattrat ++#define AT_FUNC_F1 lsetxattr ++#define AT_FUNC_POST_FILE_PARAM_DECLS , const char *name, const void *value \ ++ , size_t size, int flags ++#define AT_FUNC_POST_FILE_ARGS , name, value, size, flags ++#include "at-func.c" ++#undef AT_FUNC_NAME ++#undef AT_FUNC_F1 ++#undef AT_FUNC_POST_FILE_PARAM_DECLS ++#undef AT_FUNC_POST_FILE_ARGS ++ ++/* getxattrat */ ++#define AT_FUNC_NAME getxattrat ++#define AT_FUNC_RESULT ssize_t ++#define AT_FUNC_F1 getxattr ++#define AT_FUNC_POST_FILE_PARAM_DECLS , const char *name, void *value \ ++ , size_t size ++#define AT_FUNC_POST_FILE_ARGS , name, value, size ++#include "at-func.c" ++#undef AT_FUNC_NAME ++#undef AT_FUNC_F1 ++#undef AT_FUNC_RESULT ++#undef AT_FUNC_POST_FILE_PARAM_DECLS ++#undef AT_FUNC_POST_FILE_ARGS ++ ++/* lgetxattrat */ ++#define AT_FUNC_NAME lgetxattrat ++#define AT_FUNC_RESULT ssize_t ++#define AT_FUNC_F1 lgetxattr ++#define AT_FUNC_POST_FILE_PARAM_DECLS , const char *name, void *value \ ++ , size_t size ++#define AT_FUNC_POST_FILE_ARGS , name, value, size ++#include "at-func.c" ++#undef AT_FUNC_NAME ++#undef AT_FUNC_F1 ++#undef AT_FUNC_RESULT ++#undef AT_FUNC_POST_FILE_PARAM_DECLS ++#undef AT_FUNC_POST_FILE_ARGS ++ ++/* listxattrat */ ++#define AT_FUNC_NAME listxattrat ++#define AT_FUNC_RESULT ssize_t ++#define AT_FUNC_F1 listxattr ++#define AT_FUNC_POST_FILE_PARAM_DECLS , char *list , size_t size ++#define AT_FUNC_POST_FILE_ARGS , list , size ++#include "at-func.c" ++#undef AT_FUNC_NAME ++#undef AT_FUNC_F1 ++#undef AT_FUNC_RESULT ++#undef AT_FUNC_POST_FILE_PARAM_DECLS ++#undef AT_FUNC_POST_FILE_ARGS ++ ++/* llistxattrat */ ++#define AT_FUNC_NAME llistxattrat ++#define AT_FUNC_RESULT ssize_t ++#define AT_FUNC_F1 llistxattr ++#define AT_FUNC_POST_FILE_PARAM_DECLS , char *list , size_t size ++#define AT_FUNC_POST_FILE_ARGS , list , size ++#include "at-func.c" ++#undef AT_FUNC_NAME ++#undef AT_FUNC_F1 ++#undef AT_FUNC_RESULT ++#undef AT_FUNC_POST_FILE_PARAM_DECLS ++#undef AT_FUNC_POST_FILE_ARGS +diff --git a/lib/xattr-at.h b/lib/xattr-at.h +new file mode 100644 +index 0000000..360245c +--- /dev/null ++++ b/lib/xattr-at.h +@@ -0,0 +1,66 @@ ++/* Prototypes for openat-style fd-relative functions for operating with ++ extended file attributes. ++ ++ Copyright (C) 2012 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#ifndef XATTRS_AT_H ++#define XATTRS_AT_H ++ ++#include ++#include ++ ++/* These are the dir-fd-relative variants of the functions without the ++ "at" suffix. For example, setxattrat (AT_FDCWD, path, name, value, size, ++ flags &c) is usually equivalent to setxattr (file, name, value, size, ++ flags). For more info use the setxattr(2), getxattr(2) or listxattr(2) ++ manpages. */ ++ ++/* dir-fd-relative setxattr. Operation sets the VALUE of the extended ++ attribute identified by NAME and associated with the given PATH in the ++ filesystem relatively to directory identified by DIR_FD. See the ++ setxattr(2) manpage for the description of all parameters. */ ++int setxattrat (int dir_fd, const char *path, const char *name, ++ const void *value, size_t size, int flags); ++ ++/* dir-fd-relative lsetxattr. This function is just like setxattrat, ++ except when DIR_FD and FILE specify a symlink: lsetxattrat operates on the ++ symlink, while the setxattrat operates on the referent of the symlink. */ ++int lsetxattrat (int dir_fd, const char *path, const char *name, ++ const void *value, size_t size, int flags); ++ ++/* dir-fd-relative getxattr. Operation gets the VALUE of the extended ++ attribute idenfified by NAME and associated with the given PATH in the ++ filesystem relatively to directory identified by DIR_FD. For more info ++ about all parameters see the getxattr(2) manpage. */ ++ssize_t getxattrat (int dir_fd, const char *path, const char *name, ++ void *value, size_t size); ++ ++/* dir-fd-relative lgetxattr. This function is just like getxattrat, ++ except when DIR_FD and FILE specify a symlink: lgetxattrat operates on the ++ symlink, while the getxattrat operates on the referent of the symlink. */ ++ssize_t lgetxattrat (int dir_fd, const char *path, const char *name, ++ void *value, size_t size); ++ ++/* dir-fd-relative listxattr. Obtain the list of extended attrubtes names. For ++ more info see the listxattr(2) manpage. */ ++ssize_t listxattrat (int dir_fd, const char *path, char *list, size_t size); ++ ++/* dir-fd-relative llistxattr. This function is just like listxattrat, ++ except when DIR_FD and FILE specify a symlink: llistxattr operates on the ++ symlink, while the listxattrat operates on the referent of the symlink. */ ++ssize_t llistxattrat (int dir_fd, const char *path, char *list, size_t size); ++ ++#endif /* XATTRS_AT_H */ +diff --git a/src/Makefile.am b/src/Makefile.am +index de310f4..782df19 100644 +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -20,7 +20,7 @@ + + bin_PROGRAMS = tar + +-noinst_HEADERS = arith.h common.h tar.h ++noinst_HEADERS = arith.h common.h tar.h xattrs.h + tar_SOURCES = \ + buffer.c\ + checkpoint.c\ +@@ -42,10 +42,11 @@ tar_SOURCES = \ + unlink.c\ + update.c\ + utf8.c\ +- warning.c ++ warning.c\ ++ xattrs.c + + INCLUDES = -I$(top_srcdir)/gnu -I../ -I../gnu -I$(top_srcdir)/lib -I../lib + + LDADD = ../lib/libtar.a ../gnu/libgnu.a $(LIBINTL) $(LIBICONV) + +-tar_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS) ++tar_LDADD = $(LIBS) $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS) $(LIB_SELINUX) +diff --git a/src/common.h b/src/common.h +index 2409413..16ba401 100644 +--- a/src/common.h ++++ b/src/common.h +@@ -1,8 +1,8 @@ + /* Common declarations for the tar program. + + Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001, +- 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, +- Inc. ++ 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 ++ Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the +@@ -91,6 +91,11 @@ enum subcommand + + GLOBAL enum subcommand subcommand_option; + ++#define READ_LIKE_SUBCOMMAND \ ++ (subcommand_option == EXTRACT_SUBCOMMAND \ ++ || subcommand_option == DIFF_SUBCOMMAND \ ++ || subcommand_option == LIST_SUBCOMMAND) ++ + /* Selected format for output archive. */ + GLOBAL enum archive_format archive_format; + +@@ -254,6 +259,15 @@ GLOBAL int same_owner_option; + /* If positive, preserve permissions when extracting. */ + GLOBAL int same_permissions_option; + ++/* If positive, save the SELinux context. */ ++GLOBAL int selinux_context_option; ++ ++/* If positive, save the ACLs. */ ++GLOBAL int acls_option; ++ ++/* If positive, save the user and root xattrs. */ ++GLOBAL int xattrs_option; ++ + /* When set, strip the given number of file name components from the file name + before extracting */ + GLOBAL size_t strip_name_components; +@@ -708,6 +722,9 @@ extern char *output_start; + + void update_archive (void); + ++/* Module attrs.c. */ ++#include "xattrs.h" ++ + /* Module xheader.c. */ + + void xheader_decode (struct tar_stat_info *stat); +@@ -728,6 +745,12 @@ bool xheader_string_end (struct xheader *xhdr, char const *keyword); + bool xheader_keyword_deleted_p (const char *kw); + char *xheader_format_name (struct tar_stat_info *st, const char *fmt, + size_t n); ++void xheader_xattr_init (struct tar_stat_info *st); ++void xheader_xattr_free (struct xattr_array *vals, size_t sz); ++void xheader_xattr_copy (const struct tar_stat_info *st, ++ struct xattr_array **vals, size_t *sz); ++void xheader_xattr_add (struct tar_stat_info *st, ++ const char *key, const char *val, size_t len); + + /* Module system.c */ + +@@ -809,6 +832,7 @@ void checkpoint_run (bool do_write); + #define WARN_XDEV 0x00040000 + #define WARN_DECOMPRESS_PROGRAM 0x00080000 + #define WARN_EXISTING_FILE 0x00100000 ++#define WARN_XATTR_WRITE 0x00200000 + + /* The warnings composing WARN_VERBOSE_WARNINGS are enabled by default + in verbose mode */ +diff --git a/src/create.c b/src/create.c +index f98cbb5..25387a9 100644 +--- a/src/create.c ++++ b/src/create.c +@@ -1,7 +1,8 @@ + /* Create a tar archive. + + Copyright (C) 1985, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001, +- 2003, 2004, 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc. ++ 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2012 ++ Free Software Foundation, Inc. + + Written by John Gilmore, on 1985-08-25. + +@@ -936,6 +937,30 @@ start_header (struct tar_stat_info *st) + GNAME_TO_CHARS (st->gname, header->header.gname); + } + ++ if (archive_format == POSIX_FORMAT) ++ { ++ if (acls_option > 0) ++ { ++ if (st->acls_a_ptr) ++ xheader_store ("SCHILY.acl.access", st, NULL); ++ if (st->acls_d_ptr) ++ xheader_store ("SCHILY.acl.default", st, NULL); ++ } ++ if ((selinux_context_option > 0) && st->cntx_name) ++ xheader_store ("RHT.security.selinux", st, NULL); ++ if (xattrs_option > 0) ++ { ++ size_t scan_xattr = 0; ++ struct xattr_array *xattr_map = st->xattr_map; ++ ++ while (scan_xattr < st->xattr_map_size) ++ { ++ xheader_store (xattr_map[scan_xattr].xkey, st, &scan_xattr); ++ ++scan_xattr; ++ } ++ } ++ } ++ + return header; + } + +@@ -1711,6 +1736,10 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p) + bool ok; + struct stat final_stat; + ++ xattrs_acls_get (parentfd, name, st, 0, !is_dir); ++ xattrs_selinux_get (parentfd, name, st, fd); ++ xattrs_xattrs_get (parentfd, name, st, fd); ++ + if (is_dir) + { + const char *tag_file_name; +@@ -1830,6 +1859,9 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p) + if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT) < size) + write_long_link (st); + ++ xattrs_selinux_get (parentfd, name, st, 0); ++ xattrs_xattrs_get (parentfd, name, st, 0); ++ + block_ordinal = current_block_ordinal (); + st->stat.st_size = 0; /* force 0 size on symlink */ + header = start_header (st); +@@ -1848,11 +1880,26 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p) + } + #endif + else if (S_ISCHR (st->stat.st_mode)) +- type = CHRTYPE; ++ { ++ type = CHRTYPE; ++ xattrs_acls_get (parentfd, name, st, 0, true); ++ xattrs_selinux_get (parentfd, name, st, 0); ++ xattrs_xattrs_get (parentfd, name, st, 0); ++ } + else if (S_ISBLK (st->stat.st_mode)) +- type = BLKTYPE; ++ { ++ type = BLKTYPE; ++ xattrs_acls_get (parentfd, name, st, 0, true); ++ xattrs_selinux_get (parentfd, name, st, 0); ++ xattrs_xattrs_get (parentfd, name, st, 0); ++ } + else if (S_ISFIFO (st->stat.st_mode)) +- type = FIFOTYPE; ++ { ++ type = FIFOTYPE; ++ xattrs_acls_get (parentfd, name, st, 0, true); ++ xattrs_selinux_get (parentfd, name, st, 0); ++ xattrs_xattrs_get (parentfd, name, st, 0); ++ } + else if (S_ISSOCK (st->stat.st_mode)) + { + WARNOPT (WARN_FILE_IGNORED, +diff --git a/src/extract.c b/src/extract.c +index 662ea0b..87b383a 100644 +--- a/src/extract.c ++++ b/src/extract.c +@@ -1,7 +1,8 @@ + /* Extract files from a tar archive. + + Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000, +- 2001, 2003, 2004, 2005, 2006, 2007, 2010 Free Software Foundation, Inc. ++ 2001, 2003, 2004, 2005, 2006, 2007, 2010, 2012 ++ Free Software Foundation, Inc. + + Written by John Gilmore, on 1985-11-19. + +@@ -97,6 +98,14 @@ struct delayed_set_stat + /* Directory that the name is relative to. */ + int change_dir; + ++ /* extended attributes*/ ++ char *cntx_name; ++ char *acls_a_ptr; ++ size_t acls_a_len; ++ char *acls_d_ptr; ++ size_t acls_d_len; ++ size_t xattr_map_size; ++ struct xattr_array *xattr_map; + /* Length and contents of name. */ + size_t file_name_len; + char file_name[1]; +@@ -134,6 +143,18 @@ struct delayed_link + hard-linked together. */ + struct string_list *sources; + ++ /* SELinux context */ ++ char *cntx_name; ++ ++ /* ACLs */ ++ char *acls_a_ptr; ++ size_t acls_a_len; ++ char *acls_d_ptr; ++ size_t acls_d_len; ++ ++ size_t xattr_map_size; ++ struct xattr_array *xattr_map; ++ + /* The desired target of the desired link. */ + char target[1]; + }; +@@ -360,6 +381,12 @@ set_stat (char const *file_name, + st->stat.st_mode & ~ current_umask, + 0 < same_permissions_option && ! interdir ? MODE_ALL : MODE_RWX, + fd, current_mode, current_mode_mask, typeflag, atflag); ++ ++ /* these three calls must be done *after* fd_chown() call because fd_chown ++ causes that linux capabilities becomes cleared. */ ++ xattrs_xattrs_set (st, file_name, typeflag, 1); ++ xattrs_acls_set (st, file_name, typeflag); ++ xattrs_selinux_set (st, file_name, typeflag); + } + + /* For each entry H in the leading prefix of entries in HEAD that do +@@ -431,6 +458,36 @@ delay_set_stat (char const *file_name, struct tar_stat_info const *st, + data->atflag = atflag; + data->after_links = 0; + data->change_dir = chdir_current; ++ data->cntx_name = NULL; ++ if (st) ++ assign_string (&data->cntx_name, st->cntx_name); ++ if (st && st->acls_a_ptr) ++ { ++ data->acls_a_ptr = xmemdup (st->acls_a_ptr, st->acls_a_len + 1); ++ data->acls_a_len = st->acls_a_len; ++ } ++ else ++ { ++ data->acls_a_ptr = NULL; ++ data->acls_a_len = 0; ++ } ++ if (st && st->acls_d_ptr) ++ { ++ data->acls_d_ptr = xmemdup (st->acls_d_ptr, st->acls_d_len + 1); ++ data->acls_d_len = st->acls_d_len; ++ } ++ else ++ { ++ data->acls_d_ptr = NULL; ++ data->acls_d_len = 0; ++ } ++ if (st) ++ xheader_xattr_copy (st, &data->xattr_map, &data->xattr_map_size); ++ else ++ { ++ data->xattr_map = NULL; ++ data->xattr_map_size = 0; ++ } + strcpy (data->file_name, file_name); + delayed_set_stat_head = data; + if (must_be_dot_or_slash (file_name)) +@@ -678,6 +735,40 @@ maybe_recoverable (char *file_name, bool regular, bool *interdir_made) + return RECOVER_NO; + } + ++/* Restore stat extended attributes (xattr) for FILE_NAME, using information ++ given in *ST. Restore before extraction because they may affect file layout ++ (e.g. on Lustre distributed parallel filesystem - setting info about how many ++ servers is this file striped over, stripe size, mirror copies, etc. ++ in advance dramatically improves the following performance of reading and ++ writing a file). If not restoring permissions, invert the INVERT_PERMISSIONS ++ bits from the file's current permissions. TYPEFLAG specifies the type of the ++ file. FILE_CREATED indicates set_xattr has created the file */ ++static int ++set_xattr (char const *file_name, struct tar_stat_info const *st, ++ mode_t invert_permissions, char typeflag, int *file_created) ++{ ++ int status = 0; ++ ++#ifdef HAVE_XATTRS ++ bool interdir_made = false; ++ ++ if ((xattrs_option > 0) && st->xattr_map_size) ++ { ++ mode_t mode = current_stat_info.stat.st_mode & MODE_RWX & ~ current_umask; ++ ++ do ++ status = mknodat (chdir_fd, file_name, mode ^ invert_permissions, 0); ++ while (status && maybe_recoverable ((char *)file_name, false, ++ &interdir_made)); ++ ++ xattrs_xattrs_set (st, file_name, typeflag, 0); ++ *file_created = 1; ++ } ++#endif ++ ++ return(status); ++} ++ + /* Fix the statuses of all directories whose statuses need fixing, and + which are not ancestors of FILE_NAME. If AFTER_LINKS is + nonzero, do this for all such directories; otherwise, stop at the +@@ -738,12 +829,23 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_links) + sb.stat.st_gid = data->gid; + sb.atime = data->atime; + sb.mtime = data->mtime; ++ sb.cntx_name = data->cntx_name; ++ sb.acls_a_ptr = data->acls_a_ptr; ++ sb.acls_a_len = data->acls_a_len; ++ sb.acls_d_ptr = data->acls_d_ptr; ++ sb.acls_d_len = data->acls_d_len; ++ sb.xattr_map = data->xattr_map; ++ sb.xattr_map_size = data->xattr_map_size; + set_stat (data->file_name, &sb, + -1, current_mode, current_mode_mask, + DIRTYPE, data->interdir, data->atflag); + } + + delayed_set_stat_head = data->next; ++ xheader_xattr_free (data->xattr_map, data->xattr_map_size); ++ free (data->cntx_name); ++ free (data->acls_a_ptr); ++ free (data->acls_d_ptr); + free (data); + } + } +@@ -859,7 +961,8 @@ extract_dir (char *file_name, int typeflag) + + static int + open_output_file (char const *file_name, int typeflag, mode_t mode, +- mode_t *current_mode, mode_t *current_mode_mask) ++ int file_created, mode_t *current_mode, ++ mode_t *current_mode_mask) + { + int fd; + bool overwriting_old_files = old_files_option == OVERWRITE_OLD_FILES; +@@ -869,6 +972,10 @@ open_output_file (char const *file_name, int typeflag, mode_t mode, + ? O_TRUNC | (dereference_option ? 0 : O_NOFOLLOW) + : O_EXCL)); + ++ /* File might be created in set_xattr. So clear O_EXCL to avoid open() fail */ ++ if (file_created) ++ openflag = openflag & ~O_EXCL; ++ + if (typeflag == CONTTYPE) + { + static int conttype_diagnosed; +@@ -939,6 +1046,8 @@ extract_file (char *file_name, int typeflag) + bool interdir_made = false; + mode_t mode = (current_stat_info.stat.st_mode & MODE_RWX + & ~ (0 < same_owner_option ? S_IRWXG | S_IRWXO : 0)); ++ mode_t invert_permissions = 0 < same_owner_option ? mode & (S_IRWXG | S_IRWXO) ++ : 0; + mode_t current_mode = 0; + mode_t current_mode_mask = 0; + +@@ -955,8 +1064,18 @@ extract_file (char *file_name, int typeflag) + } + else + { ++ int file_created = 0; ++ if (set_xattr (file_name, ¤t_stat_info, invert_permissions, ++ typeflag, &file_created)) ++ { ++ skip_member (); ++ open_error (file_name); ++ return 1; ++ } ++ + while ((fd = open_output_file (file_name, typeflag, mode, +- ¤t_mode, ¤t_mode_mask)) ++ file_created, ¤t_mode, ++ ¤t_mode_mask)) + < 0) + { + int recover = maybe_recoverable (file_name, true, &interdir_made); +@@ -1096,6 +1215,13 @@ create_placeholder_file (char *file_name, bool is_symlink, bool *interdir_made) + + strlen (file_name) + 1); + p->sources->next = 0; + strcpy (p->sources->string, file_name); ++ p->cntx_name = NULL; ++ assign_string (&p->cntx_name, current_stat_info.cntx_name); ++ p->acls_a_ptr = NULL; ++ p->acls_a_len = 0; ++ p->acls_d_ptr = NULL; ++ p->acls_d_len = 0; ++ xheader_xattr_copy (¤t_stat_info, &p->xattr_map, &p->xattr_map_size); + strcpy (p->target, current_stat_info.link_name); + + h = delayed_set_stat_head; +@@ -1530,6 +1656,13 @@ apply_delayed_links (void) + st1.stat.st_gid = ds->gid; + st1.atime = ds->atime; + st1.mtime = ds->mtime; ++ st1.cntx_name = ds->cntx_name; ++ st1.acls_a_ptr = ds->acls_a_ptr; ++ st1.acls_a_len = ds->acls_a_len; ++ st1.acls_d_ptr = ds->acls_d_ptr; ++ st1.acls_d_len = ds->acls_d_len; ++ st1.xattr_map = ds->xattr_map; ++ st1.xattr_map_size = ds->xattr_map_size; + set_stat (source, &st1, -1, 0, 0, SYMTYPE, + false, AT_SYMLINK_NOFOLLOW); + valid_source = source; +@@ -1544,6 +1677,9 @@ apply_delayed_links (void) + sources = next; + } + ++ xheader_xattr_free (ds->xattr_map, ds->xattr_map_size); ++ free (ds->cntx_name); ++ + { + struct delayed_link *next = ds->next; + free (ds); +diff --git a/src/list.c b/src/list.c +index f4e6e0a..dd501a9 100644 +--- a/src/list.c ++++ b/src/list.c +@@ -1,7 +1,8 @@ + /* List a tar archive, with support routines for reading a tar archive. + + Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000, +- 2001, 2003, 2004, 2005, 2006, 2007, 2010 Free Software Foundation, Inc. ++ 2001, 2003, 2004, 2005, 2006, 2007, 2010, 2012 ++ Free Software Foundation, Inc. + + Written by John Gilmore, on 1985-08-26. + +@@ -615,6 +616,8 @@ decode_header (union block *header, struct tar_stat_info *stat_info, + assign_string (&stat_info->gname, + header->header.gname[0] ? header->header.gname : NULL); + ++ xheader_xattr_init (stat_info); ++ + if (format == OLDGNU_FORMAT && incremental_option) + { + stat_info->atime.tv_sec = TIME_FROM_HEADER (header->oldgnu_header.atime); +@@ -1075,7 +1078,7 @@ static void + simple_print_header (struct tar_stat_info *st, union block *blk, + off_t block_ordinal) + { +- char modes[11]; ++ char modes[12]; + char const *time_stamp; + int time_stamp_len; + char *temp_name; +@@ -1167,6 +1170,9 @@ simple_print_header (struct tar_stat_info *st, union block *blk, + + pax_decode_mode (st->stat.st_mode, modes + 1); + ++ /* extended attributes: GNU `ls -l'-like preview */ ++ xattrs_print_char (st, modes + 10); ++ + /* Time stamp. */ + + time_stamp = tartime (st->mtime, full_time_option); +@@ -1312,6 +1318,7 @@ simple_print_header (struct tar_stat_info *st, union block *blk, + } + } + fflush (stdlis); ++ xattrs_print (st); + } + + +diff --git a/src/tar.c b/src/tar.c +index 7a673e0..e244808 100644 +--- a/src/tar.c ++++ b/src/tar.c +@@ -1,7 +1,8 @@ + /* A tar (tape archiver) program. + + Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000, +- 2001, 2003, 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc. ++ 2001, 2003, 2004, 2005, 2006, 2007, 2012 ++ Free Software Foundation, Inc. + + Written by John Gilmore, starting 1985-08-25. + +@@ -255,7 +256,8 @@ tar_set_quoting_style (char *arg) + + enum + { +- ANCHORED_OPTION = CHAR_MAX + 1, ++ ACLS_OPTION = CHAR_MAX + 1, ++ ANCHORED_OPTION, + ATIME_PRESERVE_OPTION, + BACKUP_OPTION, + CHECK_DEVICE_OPTION, +@@ -288,6 +290,7 @@ enum + MODE_OPTION, + MTIME_OPTION, + NEWER_MTIME_OPTION, ++ NO_ACLS_OPTION, + NO_ANCHORED_OPTION, + NO_AUTO_COMPRESS_OPTION, + NO_CHECK_DEVICE_OPTION, +@@ -301,9 +304,11 @@ enum + NO_SAME_OWNER_OPTION, + NO_SAME_PERMISSIONS_OPTION, + NO_SEEK_OPTION, ++ NO_SELINUX_CONTEXT_OPTION, + NO_UNQUOTE_OPTION, + NO_WILDCARDS_MATCH_SLASH_OPTION, + NO_WILDCARDS_OPTION, ++ NO_XATTR_OPTION, + NULL_OPTION, + NUMERIC_OWNER_OPTION, + OCCURRENCE_OPTION, +@@ -325,6 +330,7 @@ enum + RMT_COMMAND_OPTION, + RSH_COMMAND_OPTION, + SAME_OWNER_OPTION, ++ SELINUX_CONTEXT_OPTION, + SHOW_DEFAULTS_OPTION, + SHOW_OMITTED_DIRS_OPTION, + SHOW_TRANSFORMED_NAMES_OPTION, +@@ -341,7 +347,10 @@ enum + VOLNO_FILE_OPTION, + WARNING_OPTION, + WILDCARDS_MATCH_SLASH_OPTION, +- WILDCARDS_OPTION ++ WILDCARDS_OPTION, ++ XATTR_OPTION, ++ XATTR_EXCLUDE, ++ XATTR_INCLUDE + }; + + const char *argp_program_version = "tar (" PACKAGE_NAME ") " VERSION; +@@ -530,6 +539,28 @@ static struct argp_option options[] = { + N_("cancel the effect of --delay-directory-restore option"), GRID+1 }, + #undef GRID + ++#define GRID 55 ++ {NULL, 0, NULL, 0, ++ N_("Handling of extended file attributes:"), GRID }, ++ ++ {"xattrs", XATTR_OPTION, 0, 0, ++ N_("Enable extended attributes support"), GRID+1 }, ++ {"no-xattrs", NO_XATTR_OPTION, 0, 0, ++ N_("Disable extended attributes support"), GRID+1 }, ++ {"xattrs-include", XATTR_INCLUDE, N_("MASK"), 0, ++ N_("specify the include pattern for xattr keys"), GRID+1 }, ++ {"xattrs-exclude", XATTR_EXCLUDE, N_("MASK"), 0, ++ N_("specify the exclude pattern for xattr keys"), GRID+1 }, ++ {"selinux", SELINUX_CONTEXT_OPTION, 0, 0, ++ N_("Enable the SELinux context support"), GRID+1 }, ++ {"no-selinux", NO_SELINUX_CONTEXT_OPTION, 0, 0, ++ N_("Disable the SELinux context support"), GRID+1 }, ++ {"acls", ACLS_OPTION, 0, 0, ++ N_("Enable the POSIX ACLs support"), GRID+1 }, ++ {"no-acls", NO_ACLS_OPTION, 0, 0, ++ N_("Disable the POSIX ACLs support"), GRID+1 }, ++#undef GRID ++ + #define GRID 60 + {NULL, 0, NULL, 0, + N_("Device selection and switching:"), GRID }, +@@ -2091,6 +2122,38 @@ parse_opt (int key, char *arg, struct argp_state *state) + same_permissions_option = -1; + break; + ++ case ACLS_OPTION: ++ set_archive_format ("posix"); ++ acls_option = 1; ++ break; ++ ++ case NO_ACLS_OPTION: ++ acls_option = -1; ++ break; ++ ++ case SELINUX_CONTEXT_OPTION: ++ set_archive_format ("posix"); ++ selinux_context_option = 1; ++ break; ++ ++ case NO_SELINUX_CONTEXT_OPTION: ++ selinux_context_option = -1; ++ break; ++ ++ case XATTR_OPTION: ++ set_archive_format ("posix"); ++ xattrs_option = 1; ++ break; ++ ++ case NO_XATTR_OPTION: ++ xattrs_option = -1; ++ break; ++ ++ case XATTR_INCLUDE: ++ case XATTR_EXCLUDE: ++ xattrs_mask_add (arg, (key == XATTR_INCLUDE)); ++ break; ++ + case RECURSION_OPTION: + recursion_option = FNM_LEADING_DIR; + break; +@@ -2468,11 +2531,26 @@ decode_options (int argc, char **argv) + --gray */ + if (args.pax_option + && archive_format != POSIX_FORMAT +- && (subcommand_option != EXTRACT_SUBCOMMAND +- || subcommand_option != DIFF_SUBCOMMAND +- || subcommand_option != LIST_SUBCOMMAND)) ++ && !READ_LIKE_SUBCOMMAND) + USAGE_ERROR ((0, 0, _("--pax-option can be used only on POSIX archives"))); + ++ /* star creates non-POSIX typed archives with xattr support, so allow the ++ extra headers whenn reading */ ++ if ((acls_option > 0) ++ && archive_format != POSIX_FORMAT ++ && !READ_LIKE_SUBCOMMAND) ++ USAGE_ERROR ((0, 0, _("--acls can be used only on POSIX archives"))); ++ ++ if ((selinux_context_option > 0) ++ && archive_format != POSIX_FORMAT ++ && !READ_LIKE_SUBCOMMAND) ++ USAGE_ERROR ((0, 0, _("--selinux can be used only on POSIX archives"))); ++ ++ if ((xattrs_option > 0) ++ && archive_format != POSIX_FORMAT ++ && !READ_LIKE_SUBCOMMAND) ++ USAGE_ERROR ((0, 0, _("--xattrs can be used only on POSIX archives"))); ++ + /* If ready to unlink hierarchies, so we are for simpler files. */ + if (recursive_unlink_option) + old_files_option = UNLINK_FIRST_OLD_FILES; +@@ -2681,6 +2759,7 @@ main (int argc, char **argv) + /* Dispose of allocated memory, and return. */ + + free (archive_name_array); ++ xattrs_clear_setup (); + name_term (); + + if (exit_status == TAREXIT_FAILURE) +@@ -2725,11 +2804,15 @@ void + tar_stat_destroy (struct tar_stat_info *st) + { + tar_stat_close (st); ++ xheader_xattr_free (st->xattr_map, st->xattr_map_size); + free (st->orig_file_name); + free (st->file_name); + free (st->link_name); + free (st->uname); + free (st->gname); ++ free (st->cntx_name); ++ free (st->acls_a_ptr); ++ free (st->acls_d_ptr); + free (st->sparse_map); + free (st->dumpdir); + xheader_destroy (&st->xhdr); +diff --git a/src/tar.h b/src/tar.h +index ce9850c..b181e58 100644 +--- a/src/tar.h ++++ b/src/tar.h +@@ -1,7 +1,8 @@ + /* GNU tar Archive Format description. + + Copyright (C) 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +- 2000, 2001, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. ++ 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2012 ++ Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the +@@ -276,6 +277,14 @@ struct xheader + uintmax_t string_length; + }; + ++/* Information about xattrs for a file. */ ++struct xattr_array ++ { ++ char *xkey; ++ char *xval_ptr; ++ size_t xval_len; ++ }; ++ + struct tar_stat_info + { + char *orig_file_name; /* name of file read from the archive header */ +@@ -287,6 +296,15 @@ struct tar_stat_info + + char *uname; /* user name of owner */ + char *gname; /* group name of owner */ ++ ++ char *cntx_name; /* SELinux context for the current archive entry. */ ++ ++ char *acls_a_ptr; /* Access ACLs for the current archive entry. */ ++ size_t acls_a_len; /* Access ACLs for the current archive entry. */ ++ ++ char *acls_d_ptr; /* Default ACLs for the current archive entry. */ ++ size_t acls_d_len; /* Default ACLs for the current archive entry. */ ++ + struct stat stat; /* regular filesystem stat */ + + /* STAT doesn't always have access, data modification, and status +@@ -309,6 +327,9 @@ struct tar_stat_info + size_t sparse_map_size; /* Size of the sparse map */ + struct sp_array *sparse_map; + ++ size_t xattr_map_size; /* Size of the xattr map */ ++ struct xattr_array *xattr_map; ++ + /* Extended headers */ + struct xheader xhdr; + +diff --git a/src/warning.c b/src/warning.c +index ee9d684..570b3c1 100644 +--- a/src/warning.c ++++ b/src/warning.c +@@ -1,6 +1,6 @@ + /* This file is part of GNU tar. + +- Copyright (C) 2009 Free Software Foundation, Inc. ++ Copyright (C) 2009, 2012 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the +@@ -43,6 +43,7 @@ static char const *const warning_args[] = { + "xdev", + "decompress-program", + "existing-file", ++ "xattr-write", + NULL + }; + +@@ -69,6 +70,7 @@ static int warning_types[] = { + WARN_XDEV, + WARN_DECOMPRESS_PROGRAM, + WARN_EXISTING_FILE, ++ WARN_XATTR_WRITE + }; + + ARGMATCH_VERIFY (warning_args, warning_types); +diff --git a/src/xattrs.c b/src/xattrs.c +new file mode 100644 +index 0000000..5a4bf72 +--- /dev/null ++++ b/src/xattrs.c +@@ -0,0 +1,732 @@ ++/* Support for extended attributes. ++ ++ Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software ++ Foundation, Inc. ++ ++ Written by James Antill, on 2006-07-27. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms of the GNU General Public License as published by the ++ Free Software Foundation; either version 2, or (at your option) any later ++ version. ++ ++ This program is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General ++ Public License for more details. ++ ++ You should have received a copy of the GNU General Public License along ++ with this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ ++ ++#include ++#include ++ ++#include ++#include ++ ++#include "common.h" ++ ++#include "xattr-at.h" ++#include "selinux-at.h" ++ ++struct xattrs_mask_map ++{ ++ const char **masks; ++ size_t size; ++ size_t used; ++}; ++ ++/* list of fnmatch patterns */ ++static struct ++{ ++ /* lists of fnmatch patterns */ ++ struct xattrs_mask_map incl; ++ struct xattrs_mask_map excl; ++} xattrs_setup; ++ ++/* disable posix acls when problem found in gnulib script m4/acl.m4 */ ++#if ! USE_ACL ++# undef HAVE_POSIX_ACLS ++#endif ++ ++#ifdef HAVE_POSIX_ACLS ++# include "acl.h" ++# include ++#endif ++ ++#ifdef HAVE_POSIX_ACLS ++ ++/* acl-at wrappers, TODO: move to gnulib in future? */ ++acl_t acl_get_file_at (int dirfd, const char *file, acl_type_t type); ++int acl_set_file_at (int dirfd, const char *file, acl_type_t type, acl_t acl); ++int file_has_acl_at (int dirfd, char const *, struct stat const *); ++ ++/* acl_get_file_at */ ++#define AT_FUNC_NAME acl_get_file_at ++#define AT_FUNC_RESULT acl_t ++#define AT_FUNC_FAIL (acl_t)NULL ++#define AT_FUNC_F1 acl_get_file ++#define AT_FUNC_POST_FILE_PARAM_DECLS , acl_type_t type ++#define AT_FUNC_POST_FILE_ARGS , type ++#include "at-func.c" ++#undef AT_FUNC_NAME ++#undef AT_FUNC_F1 ++#undef AT_FUNC_RESULT ++#undef AT_FUNC_FAIL ++#undef AT_FUNC_POST_FILE_PARAM_DECLS ++#undef AT_FUNC_POST_FILE_ARGS ++ ++/* acl_set_file_at */ ++#define AT_FUNC_NAME acl_set_file_at ++#define AT_FUNC_F1 acl_set_file ++#define AT_FUNC_POST_FILE_PARAM_DECLS , acl_type_t type, acl_t acl ++#define AT_FUNC_POST_FILE_ARGS , type, acl ++#include "at-func.c" ++#undef AT_FUNC_NAME ++#undef AT_FUNC_F1 ++#undef AT_FUNC_POST_FILE_PARAM_DECLS ++#undef AT_FUNC_POST_FILE_ARGS ++ ++/* gnulib file_has_acl_at */ ++#define AT_FUNC_NAME file_has_acl_at ++#define AT_FUNC_F1 file_has_acl ++#define AT_FUNC_POST_FILE_PARAM_DECLS , struct stat const *st ++#define AT_FUNC_POST_FILE_ARGS , st ++#include "at-func.c" ++#undef AT_FUNC_NAME ++#undef AT_FUNC_F1 ++#undef AT_FUNC_POST_FILE_PARAM_DECLS ++#undef AT_FUNC_POST_FILE_ARGS ++ ++/* convert unix permissions into an ACL ... needed due to "default" ACLs */ ++static acl_t ++perms2acl (int perms) ++{ ++ char val[] = "user::---,group::---,other::---"; ++ /* 0123456789 123456789 123456789 123456789 */ ++ ++ /* user */ ++ if (perms & 0400) ++ val[6] = 'r'; ++ if (perms & 0200) ++ val[7] = 'w'; ++ if (perms & 0100) ++ val[8] = 'x'; ++ ++ /* group */ ++ if (perms & 0040) ++ val[17] = 'r'; ++ if (perms & 0020) ++ val[18] = 'w'; ++ if (perms & 0010) ++ val[19] = 'x'; ++ ++ /* other */ ++ if (perms & 0004) ++ val[28] = 'r'; ++ if (perms & 0002) ++ val[29] = 'w'; ++ if (perms & 0001) ++ val[30] = 'x'; ++ ++ return acl_from_text (val); ++} ++ ++static char * ++skip_to_ext_fields (char *ptr) ++{ ++ /* skip tag name (user/group/default/mask) */ ++ ptr += strcspn (ptr, ":,\n"); ++ ++ if (*ptr != ':') ++ return ptr; ++ ++ptr; ++ ++ ptr += strcspn (ptr, ":,\n"); /* skip user/group name */ ++ ++ if (*ptr != ':') ++ return ptr; ++ ++ptr; ++ ++ ptr += strcspn (ptr, ":,\n"); /* skip perms */ ++ ++ return ptr; ++} ++ ++/* The POSIX draft allows extra fields after the three main ones. Star ++ uses this to add a fourth field for user/group which is the numeric ID. ++ This function removes such extra fields by overwriting them with the ++ characters that follow. */ ++static char * ++fixup_extra_acl_fields (char *ptr) ++{ ++ char *src = ptr; ++ char *dst = ptr; ++ ++ while (*src) ++ { ++ const char *old = src; ++ size_t len = 0; ++ ++ src = skip_to_ext_fields (src); ++ len = src - old; ++ if (old != dst) ++ memmove (dst, old, len); ++ dst += len; ++ ++ if (*src == ':') /* We have extra fields, skip them all */ ++ src += strcspn (src, "\n,"); ++ ++ if ((*src == '\n') || (*src == ',')) ++ *dst++ = *src++; /* also done when dst == src, but that's ok */ ++ } ++ if (src != dst) ++ *dst = 0; ++ ++ return ptr; ++} ++ ++/* "system.posix_acl_access" */ ++static void ++xattrs__acls_set (struct tar_stat_info const *st, ++ char const *file_name, int type, ++ char *ptr, size_t len, bool def) ++{ ++ acl_t acl; ++ ++ if (ptr) ++ { ++ /* assert (strlen (ptr) == len); */ ++ ptr = fixup_extra_acl_fields (ptr); ++ ++ acl = acl_from_text (ptr); ++ acls_option = 1; ++ } ++ else if (acls_option > 0) ++ acl = perms2acl (st->stat.st_mode); ++ else ++ return; /* don't call acl functions unless we first hit an ACL, or ++ --acls was passed explicitly */ ++ ++ if (!acl) ++ { ++ call_arg_warn ("acl_from_text", file_name); ++ return; ++ } ++ ++ if (acl_set_file_at (chdir_fd, file_name, type, acl) == -1) ++ /* warn even if filesystem does not support acls */ ++ WARNOPT (WARN_XATTR_WRITE, ++ (0, errno, ++ _ ("acl_set_file_at: Cannot set POSIX ACLs for file '%s'"), ++ file_name)); ++ ++ acl_free (acl); ++} ++ ++static void ++xattrs__acls_get_a (int parentfd, const char *file_name, ++ struct tar_stat_info *st, ++ char **ret_ptr, size_t * ret_len) ++{ ++ char *val = NULL; ++ ssize_t len; ++ acl_t acl; ++ ++ if (!(acl = acl_get_file_at (parentfd, file_name, ACL_TYPE_ACCESS))) ++ { ++ if (errno != ENOTSUP) ++ call_arg_warn ("acl_get_file_at", file_name); ++ return; ++ } ++ ++ val = acl_to_text (acl, &len); ++ acl_free (acl); ++ ++ if (!val) ++ { ++ call_arg_warn ("acl_to_text", file_name); ++ return; ++ } ++ ++ *ret_ptr = xstrdup (val); ++ *ret_len = len; ++ ++ acl_free (val); ++} ++ ++/* "system.posix_acl_default" */ ++static void ++xattrs__acls_get_d (int parentfd, char const *file_name, ++ struct tar_stat_info *st, ++ char **ret_ptr, size_t * ret_len) ++{ ++ char *val = NULL; ++ ssize_t len; ++ acl_t acl; ++ ++ if (!(acl = acl_get_file_at (parentfd, file_name, ACL_TYPE_DEFAULT))) ++ { ++ if (errno != ENOTSUP) ++ call_arg_warn ("acl_get_file_at", file_name); ++ return; ++ } ++ ++ val = acl_to_text (acl, &len); ++ acl_free (acl); ++ ++ if (!val) ++ { ++ call_arg_warn ("acl_to_text", file_name); ++ return; ++ } ++ ++ *ret_ptr = xstrdup (val); ++ *ret_len = len; ++ ++ acl_free (val); ++} ++#endif /* HAVE_POSIX_ACLS */ ++ ++static void ++acls_one_line (const char *prefix, char delim, ++ const char *aclstring, size_t len) ++{ ++ /* support both long and short text representation of posix acls */ ++ struct obstack stk; ++ int pref_len = strlen (prefix); ++ const char *oldstring = aclstring; ++ int pos = 0; ++ ++ if (!aclstring || !len) ++ return; ++ ++ obstack_init (&stk); ++ while (pos <= len) ++ { ++ int move = strcspn (aclstring, ",\n"); ++ if (!move) ++ break; ++ ++ if (oldstring != aclstring) ++ obstack_1grow (&stk, delim); ++ ++ obstack_grow (&stk, prefix, pref_len); ++ obstack_grow (&stk, aclstring, move); ++ ++ aclstring += move + 1; ++ } ++ ++ obstack_1grow (&stk, '\0'); ++ ++ fprintf (stdlis, "%s", (char *) obstack_finish (&stk)); ++ ++ obstack_free (&stk, NULL); ++} ++ ++void ++xattrs_acls_get (int parentfd, char const *file_name, ++ struct tar_stat_info *st, int fd, int xisfile) ++{ ++ if (acls_option > 0) ++ { ++#ifndef HAVE_POSIX_ACLS ++ static int done = 0; ++ if (!done) ++ WARN ((0, 0, _("POSIX ACL support is not available"))); ++ done = 1; ++#else ++ int err = file_has_acl_at (parentfd, file_name, &st->stat); ++ if (err == 0) ++ return; ++ if (err == -1) ++ { ++ call_arg_warn ("file_has_acl_at", file_name); ++ return; ++ } ++ ++ xattrs__acls_get_a (parentfd, file_name, st, ++ &st->acls_a_ptr, &st->acls_a_len); ++ if (!xisfile) ++ xattrs__acls_get_d (parentfd, file_name, st, ++ &st->acls_d_ptr, &st->acls_d_len); ++#endif ++ } ++} ++ ++void ++xattrs_acls_set (struct tar_stat_info const *st, ++ char const *file_name, char typeflag) ++{ ++ if (acls_option > 0 && typeflag != SYMTYPE) ++ { ++#ifndef HAVE_POSIX_ACLS ++ static int done = 0; ++ if (!done) ++ WARN ((0, 0, _("POSIX ACL support is not available"))); ++ done = 1; ++#else ++ xattrs__acls_set (st, file_name, ACL_TYPE_ACCESS, ++ st->acls_a_ptr, st->acls_a_len, false); ++ if (typeflag == DIRTYPE || typeflag == GNUTYPE_DUMPDIR) ++ xattrs__acls_set (st, file_name, ACL_TYPE_DEFAULT, ++ st->acls_d_ptr, st->acls_d_len, true); ++#endif ++ } ++} ++ ++static void ++mask_map_realloc (struct xattrs_mask_map *map) ++{ ++ if (map->used == map->size) ++ { ++ if (map->size == 0) ++ map->size = 4; ++ map->masks = x2nrealloc (map->masks, &map->size, sizeof (map->masks[0])); ++ } ++} ++ ++void ++xattrs_mask_add (const char *mask, bool incl) ++{ ++ struct xattrs_mask_map *mask_map = ++ incl ? &xattrs_setup.incl : &xattrs_setup.excl; ++ /* ensure there is enough space */ ++ mask_map_realloc (mask_map); ++ /* just assign pointers -- we silently expect that pointer "mask" is valid ++ through the whole program (pointer to argv array) */ ++ mask_map->masks[mask_map->used++] = mask; ++} ++ ++static void ++clear_mask_map (struct xattrs_mask_map *mask_map) ++{ ++ if (mask_map->size) ++ free (mask_map->masks); ++} ++ ++void ++xattrs_clear_setup () ++{ ++ clear_mask_map (&xattrs_setup.incl); ++ clear_mask_map (&xattrs_setup.excl); ++} ++ ++/* get all xattrs from file given by FILE_NAME or FD (when non-zero). This ++ includes all the user.*, security.*, system.*, etc. available domains */ ++void ++xattrs_xattrs_get (int parentfd, char const *file_name, ++ struct tar_stat_info *st, int fd) ++{ ++ if (xattrs_option > 0) ++ { ++#ifndef HAVE_XATTRS ++ static int done = 0; ++ if (!done) ++ WARN ((0, 0, _("XATTR support is not available"))); ++ done = 1; ++#else ++ static size_t xsz = 1024; ++ static char *xatrs = NULL; ++ ssize_t xret = -1; ++ ++ if (!xatrs) ++ xatrs = x2nrealloc (xatrs, &xsz, 1); ++ ++ while (((fd == 0) ? ++ ((xret = ++ llistxattrat (parentfd, file_name, xatrs, xsz)) == -1) : ++ ((xret = flistxattr (fd, xatrs, xsz)) == -1)) ++ && (errno == ERANGE)) ++ { ++ xatrs = x2nrealloc (xatrs, &xsz, 1); ++ } ++ ++ if (xret == -1) ++ call_arg_warn ((fd == 0) ? "llistxattrat" : "flistxattr", file_name); ++ else ++ { ++ const char *attr = xatrs; ++ static size_t asz = 1024; ++ static char *val = NULL; ++ ++ if (!val) ++ val = x2nrealloc (val, &asz, 1); ++ ++ while (xret > 0) ++ { ++ size_t len = strlen (attr); ++ ssize_t aret = 0; ++ ++ /* Archive all xattrs during creation, decide at extraction time ++ * which ones are of interest/use for the target filesystem. */ ++ while (((fd == 0) ++ ? ((aret = lgetxattrat (parentfd, file_name, attr, ++ val, asz)) == -1) ++ : ((aret = fgetxattr (fd, attr, val, asz)) == -1)) ++ && (errno == ERANGE)) ++ { ++ val = x2nrealloc (val, &asz, 1); ++ } ++ ++ if (aret != -1) ++ xheader_xattr_add (st, attr, val, aret); ++ else if (errno != ENOATTR) ++ call_arg_warn ((fd == 0) ? "lgetxattrat" ++ : "fgetxattr", file_name); ++ ++ attr += len + 1; ++ xret -= len + 1; ++ } ++ } ++#endif ++ } ++} ++ ++static void ++xattrs__fd_set (struct tar_stat_info const *st, ++ char const *file_name, char typeflag, ++ const char *attr, const char *ptr, size_t len) ++{ ++ if (ptr) ++ { ++ const char *sysname = "setxattrat"; ++ int ret = -1; ++ ++ if (typeflag != SYMTYPE) ++ ret = setxattrat (chdir_fd, file_name, attr, ptr, len, 0); ++ else ++ { ++ sysname = "lsetxattr"; ++ ret = lsetxattrat (chdir_fd, file_name, attr, ptr, len, 0); ++ } ++ ++ if (ret == -1) ++ WARNOPT (WARN_XATTR_WRITE, ++ (0, errno, ++ _("%s: Cannot set '%s' extended attribute for file '%s'"), ++ sysname, attr, file_name)); ++ } ++} ++ ++/* lgetfileconat is called against FILE_NAME iff the FD parameter is set to ++ zero, otherwise the fgetfileconat is used against correct file descriptor */ ++void ++xattrs_selinux_get (int parentfd, char const *file_name, ++ struct tar_stat_info *st, int fd) ++{ ++ if (selinux_context_option > 0) ++ { ++#if HAVE_SELINUX_SELINUX_H != 1 ++ static int done = 0; ++ if (!done) ++ WARN ((0, 0, _("SELinux support is not available"))); ++ done = 1; ++#else ++ int result = fd ? ++ fgetfilecon (fd, &st->cntx_name) ++ : lgetfileconat (parentfd, file_name, &st->cntx_name); ++ ++ if (result == -1 && errno != ENODATA && errno != ENOTSUP) ++ call_arg_warn (fd ? "fgetfilecon" : "lgetfileconat", file_name); ++#endif ++ } ++} ++ ++void ++xattrs_selinux_set (struct tar_stat_info const *st, ++ char const *file_name, char typeflag) ++{ ++ if (selinux_context_option > 0) ++ { ++#if HAVE_SELINUX_SELINUX_H != 1 ++ static int done = 0; ++ if (!done) ++ WARN ((0, 0, _("SELinux support is not available"))); ++ done = 1; ++#else ++ const char *sysname = "setfilecon"; ++ int ret; ++ ++ if (!st->cntx_name) ++ return; ++ ++ if (typeflag != SYMTYPE) ++ { ++ ret = setfileconat (chdir_fd, file_name, st->cntx_name); ++ sysname = "setfileconat"; ++ } ++ else ++ { ++ ret = lsetfileconat (chdir_fd, file_name, st->cntx_name); ++ sysname = "lsetfileconat"; ++ } ++ ++ if (ret == -1) ++ WARNOPT (WARN_XATTR_WRITE, ++ (0, errno, ++ _("%s: Cannot set SELinux context for file '%s'"), ++ sysname, file_name)); ++#endif ++ } ++} ++ ++static bool ++xattrs_matches_mask (const char *kw, struct xattrs_mask_map *mm) ++{ ++ int i; ++ ++ if (!mm->size) ++ return false; ++ ++ for (i = 0; i < mm->used; i++) ++ if (fnmatch (mm->masks[i], kw, 0) == 0) ++ return true; ++ ++ return false; ++} ++ ++#define USER_DOT_PFX "user." ++ ++static bool ++xattrs_kw_included (const char *kw, bool archiving) ++{ ++ if (xattrs_setup.incl.size) ++ return xattrs_matches_mask (kw, &xattrs_setup.incl); ++ else if (archiving) ++ return true; ++ else ++ return strncmp (kw, USER_DOT_PFX, sizeof (USER_DOT_PFX) - 1) == 0; ++} ++ ++static bool ++xattrs_kw_excluded (const char *kw, bool archiving) ++{ ++ return xattrs_setup.excl.size ? ++ xattrs_matches_mask (kw, &xattrs_setup.excl) : false; ++} ++ ++/* Check whether the xattr with keyword KW should be discarded from list of ++ attributes that are going to be archived/excluded (set ARCHIVING=true for ++ archiving, false for excluding) */ ++static bool ++xattrs_masked_out (const char *kw, bool archiving) ++{ ++ return xattrs_kw_included (kw, archiving) ? ++ xattrs_kw_excluded (kw, archiving) : true; ++} ++ ++void ++xattrs_xattrs_set (struct tar_stat_info const *st, ++ char const *file_name, char typeflag, int later_run) ++{ ++ if (xattrs_option > 0) ++ { ++#ifndef HAVE_XATTRS ++ static int done = 0; ++ if (!done) ++ WARN ((0, 0, _("XATTR support is not available"))); ++ done = 1; ++#else ++ size_t scan = 0; ++ ++ if (!st->xattr_map_size) ++ return; ++ ++ for (; scan < st->xattr_map_size; ++scan) ++ { ++ char *keyword = st->xattr_map[scan].xkey; ++ keyword += strlen ("SCHILY.xattr."); ++ ++ /* TODO: this 'later_run' workaround is temporary solution -> once ++ capabilities should become fully supported by it's API and there ++ should exist something like xattrs_capabilities_set() call. ++ For a regular files: all extended attributes are restored during ++ the first run except 'security.capability' which is restored in ++ 'later_run == 1'. */ ++ if (typeflag == REGTYPE ++ && later_run == !!strcmp (keyword, "security.capability")) ++ continue; ++ ++ if (xattrs_masked_out (keyword, false /* extracting */ )) ++ /* we don't want to restore this keyword */ ++ continue; ++ ++ xattrs__fd_set (st, file_name, typeflag, keyword, ++ st->xattr_map[scan].xval_ptr, ++ st->xattr_map[scan].xval_len); ++ } ++#endif ++ } ++} ++ ++void ++xattrs_print_char (struct tar_stat_info const *st, char *output) ++{ ++ int i; ++ ++ if (verbose_option < 2) ++ { ++ *output = 0; ++ return; ++ } ++ ++ if (xattrs_option > 0 || selinux_context_option > 0 || acls_option > 0) ++ { ++ /* placeholders */ ++ *output = ' '; ++ output[1] = 0; ++ } ++ ++ if (xattrs_option > 0 && st->xattr_map_size) ++ for (i = 0; i < st->xattr_map_size; ++i) ++ { ++ char *keyword = st->xattr_map[i].xkey + strlen ("SCHILY.xattr."); ++ if (!xattrs_masked_out (keyword, false /* like extracting */ )) ++ { ++ *output = '*'; ++ break; ++ } ++ } ++ ++ if (selinux_context_option > 0 && st->cntx_name) ++ *output = '.'; ++ ++ if (acls_option && (st->acls_a_len || st->acls_d_len)) ++ *output = '+'; ++} ++ ++void ++xattrs_print (struct tar_stat_info const *st) ++{ ++ if (verbose_option < 3) ++ return; ++ ++ /* selinux */ ++ if (selinux_context_option && st->cntx_name) ++ fprintf (stdlis, " s: %s\n", st->cntx_name); ++ ++ /* acls */ ++ if (acls_option && (st->acls_a_len || st->acls_d_len)) ++ { ++ fprintf (stdlis, " a: "); ++ acls_one_line ("", ',', st->acls_a_ptr, st->acls_a_len); ++ acls_one_line ("default:", ',', st->acls_d_ptr, st->acls_d_len); ++ fprintf (stdlis, "\n"); ++ } ++ ++ /* xattrs */ ++ if (xattrs_option && st->xattr_map_size) ++ { ++ int i; ++ ++ for (i = 0; i < st->xattr_map_size; ++i) ++ { ++ char *keyword = st->xattr_map[i].xkey + strlen ("SCHILY.xattr."); ++ if (!xattrs_masked_out (keyword, false /* like extracting */ )) ++ fprintf (stdlis, " x: %lu %s\n", ++ (unsigned long) st->xattr_map[i].xval_len, keyword); ++ } ++ } ++} +diff --git a/src/xattrs.h b/src/xattrs.h +new file mode 100644 +index 0000000..bfef466 +--- /dev/null ++++ b/src/xattrs.h +@@ -0,0 +1,51 @@ ++/* Support for extended attributes. ++ ++ Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software ++ Foundation, Inc. ++ ++ Written by James Antill, on 2006-07-27. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms of the GNU General Public License as published by the ++ Free Software Foundation; either version 3, or (at your option) any later ++ version. ++ ++ This program is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General ++ Public License for more details. ++ ++ You should have received a copy of the GNU General Public License along ++ with this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++*/ ++ ++#ifndef GUARD_XATTTRS_H ++#define GUARD_XATTTRS_H ++ ++/* Add include/exclude fnmatch pattern for xattr key domain. Set INCL parameter ++ to true/false if you want to add include/exclude pattern */ ++extern void xattrs_mask_add (const char *mask, bool incl); ++ ++/* clear helping structures when tar finishes */ ++extern void xattrs_clear_setup (); ++ ++extern void xattrs_acls_get (int parentfd, char const *file_name, ++ struct tar_stat_info *st, int fd, int xisfile); ++extern void xattrs_selinux_get (int parentfd, char const *file_name, ++ struct tar_stat_info *st, int fd); ++extern void xattrs_xattrs_get (int parentfd, char const *file_name, ++ struct tar_stat_info *st, int fd); ++ ++extern void xattrs_acls_set (struct tar_stat_info const *st, ++ char const *file_name, char typeflag); ++extern void xattrs_selinux_set (struct tar_stat_info const *st, ++ char const *file_name, char typeflag); ++extern void xattrs_xattrs_set (struct tar_stat_info const *st, ++ char const *file_name, char typeflag, ++ int later_run); ++ ++extern void xattrs_print_char (struct tar_stat_info const *st, char *output); ++extern void xattrs_print (struct tar_stat_info const *st); ++ ++#endif /* GUARD_XATTTRS_H */ +diff --git a/src/xheader.c b/src/xheader.c +index 2284e97..be793d4 100644 +--- a/src/xheader.c ++++ b/src/xheader.c +@@ -1,7 +1,7 @@ + /* POSIX extended headers for tar. + +- Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009, 2010 Free Software +- Foundation, Inc. ++ Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2012 ++ Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the +@@ -460,6 +460,123 @@ xheader_write_global (struct xheader *xhdr) + } + } + ++void ++xheader_xattr_init (struct tar_stat_info *st) ++{ ++ st->xattr_map = NULL; ++ st->xattr_map_size = 0; ++ ++ st->acls_a_ptr = NULL; ++ st->acls_a_len = 0; ++ st->acls_d_ptr = NULL; ++ st->acls_d_len = 0; ++ st->cntx_name = NULL; ++} ++ ++void ++xheader_xattr_free (struct xattr_array *xattr_map, size_t xattr_map_size) ++{ ++ size_t scan = 0; ++ ++ while (scan < xattr_map_size) ++ { ++ free (xattr_map[scan].xkey); ++ free (xattr_map[scan].xval_ptr); ++ ++ ++scan; ++ } ++ free (xattr_map); ++} ++ ++static void ++xheader_xattr__add (struct xattr_array **xattr_map, ++ size_t *xattr_map_size, ++ const char *key, const char *val, size_t len) ++{ ++ size_t pos = (*xattr_map_size)++; ++ ++ *xattr_map = xrealloc (*xattr_map, ++ *xattr_map_size * sizeof(struct xattr_array)); ++ (*xattr_map)[pos].xkey = xstrdup (key); ++ (*xattr_map)[pos].xval_ptr = xmemdup (val, len + 1); ++ (*xattr_map)[pos].xval_len = len; ++} ++ ++/* This is reversal function for xattr_encode_keyword. See comment for ++ xattr_encode_keyword() for more info. */ ++static void ++xattr_decode_keyword (char *keyword) ++{ ++ char *kpr, *kpl; /* keyword pointer left/right */ ++ kpr = kpl = keyword; ++ ++ for (;;) ++ { ++ if (*kpr == '%') ++ { ++ if (kpr[1] == '3' && kpr[2] == 'D') ++ { ++ *kpl = '='; ++ kpr += 3; ++ kpl ++; ++ continue; ++ } ++ else if (kpr[1] == '2' && kpr[2] == '5') ++ { ++ *kpl = '%'; ++ kpr += 3; ++ kpl ++; ++ continue; ++ } ++ } ++ ++ *kpl = *kpr; ++ ++ if (*kpr == 0) ++ break; ++ ++ kpr++; ++ kpl++; ++ } ++} ++ ++void ++xheader_xattr_add (struct tar_stat_info *st, ++ const char *key, const char *val, size_t len) ++{ ++ size_t klen = strlen (key); ++ char *xkey = xmalloc (strlen("SCHILY.xattr.") + klen + 1); ++ char *tmp = xkey; ++ ++ tmp = stpcpy (tmp, "SCHILY.xattr."); ++ stpcpy (tmp, key); ++ ++ xheader_xattr__add (&st->xattr_map, &st->xattr_map_size, xkey, val, len); ++ ++ free (xkey); ++} ++ ++void ++xheader_xattr_copy (const struct tar_stat_info *st, ++ struct xattr_array **xattr_map, size_t *xattr_map_size) ++{ ++ size_t scan = 0; ++ ++ *xattr_map = NULL; ++ *xattr_map_size = 0; ++ ++ while (scan < st->xattr_map_size) ++ { ++ char *key = st->xattr_map[scan].xkey; ++ char *val = st->xattr_map[scan].xval_ptr; ++ size_t len = st->xattr_map[scan].xval_len; ++ ++ xheader_xattr__add(xattr_map, xattr_map_size, key, val, len); ++ ++ ++scan; ++ } ++} ++ + + /* General Interface */ + +@@ -473,6 +590,7 @@ struct xhdr_tab + struct xheader *, void const *data); + void (*decoder) (struct tar_stat_info *, char const *, char const *, size_t); + int flags; ++ bool prefix; /* select handler comparing prefix only */ + }; + + /* This declaration must be extern, because ISO C99 section 6.9.2 +@@ -489,8 +607,17 @@ locate_handler (char const *keyword) + struct xhdr_tab const *p; + + for (p = xhdr_tab; p->keyword; p++) +- if (strcmp (p->keyword, keyword) == 0) +- return p; ++ if (p->prefix) ++ { ++ if (strncmp (p->keyword, keyword, strlen(p->keyword)) == 0) ++ return p; ++ } ++ else ++ { ++ if (strcmp (p->keyword, keyword) == 0) ++ return p; ++ } ++ + return NULL; + } + +@@ -500,7 +627,8 @@ xheader_protected_pattern_p (const char *pattern) + struct xhdr_tab const *p; + + for (p = xhdr_tab; p->keyword; p++) +- if ((p->flags & XHDR_PROTECTED) && fnmatch (pattern, p->keyword, 0) == 0) ++ if (!p->prefix && (p->flags & XHDR_PROTECTED) ++ && fnmatch (pattern, p->keyword, 0) == 0) + return true; + return false; + } +@@ -511,7 +639,8 @@ xheader_protected_keyword_p (const char *keyword) + struct xhdr_tab const *p; + + for (p = xhdr_tab; p->keyword; p++) +- if ((p->flags & XHDR_PROTECTED) && strcmp (p->keyword, keyword) == 0) ++ if (!p->prefix && (p->flags & XHDR_PROTECTED) ++ && strcmp (p->keyword, keyword) == 0) + return true; + return false; + } +@@ -721,15 +850,71 @@ xheader_read (struct xheader *xhdr, union block *p, size_t size) + while (size > 0); + } + ++/* xattr_encode_keyword() substitutes '=' ~~> '%3D' and '%' ~~> '%25' ++ in extended attribute keywords. This is needed because the '=' character ++ has special purpose in extended attribute header - it splits keyword and ++ value part of header. If there was the '=' occurrence allowed inside ++ keyword, there would be no unambiguous way how to decode this extended ++ attribute. ++ ++ (http://lists.gnu.org/archive/html/bug-tar/2012-10/msg00017.html) ++ */ ++static char * ++xattr_encode_keyword(const char *keyword) ++{ ++ static char *encode_buffer = NULL; ++ static size_t encode_buffer_size = 0; ++ size_t bp; /* keyword/buffer pointers */ ++ ++ if (!encode_buffer) ++ { ++ encode_buffer_size = 256; ++ encode_buffer = xmalloc (encode_buffer_size); ++ } ++ else ++ *encode_buffer = 0; ++ ++ for (bp = 0; *keyword != 0; ++bp, ++keyword) ++ { ++ char c = *keyword; ++ ++ if (bp + 2 /* enough for URL encoding also.. */ >= encode_buffer_size) ++ { ++ encode_buffer = x2realloc (encode_buffer, &encode_buffer_size); ++ } ++ ++ if (c == '%') ++ { ++ strcpy (encode_buffer + bp, "%25"); ++ bp += 2; ++ } ++ else if (c == '=') ++ { ++ strcpy (encode_buffer + bp, "%3D"); ++ bp += 2; ++ } ++ else ++ encode_buffer[bp] = c; ++ } ++ ++ encode_buffer[bp] = 0; ++ ++ return encode_buffer; ++} ++ + static void + xheader_print_n (struct xheader *xhdr, char const *keyword, + char const *value, size_t vsize) + { +- size_t len = strlen (keyword) + vsize + 3; /* ' ' + '=' + '\n' */ + size_t p; + size_t n = 0; + char nbuf[UINTMAX_STRSIZE_BOUND]; + char const *np; ++ size_t len, klen; ++ ++ keyword = xattr_encode_keyword (keyword); ++ klen = strlen (keyword); ++ len = klen + vsize + 3; /* ' ' + '=' + '\n' */ + + do + { +@@ -741,7 +926,7 @@ xheader_print_n (struct xheader *xhdr, char const *keyword, + + x_obstack_grow (xhdr, np, n); + x_obstack_1grow (xhdr, ' '); +- x_obstack_grow (xhdr, keyword, strlen (keyword)); ++ x_obstack_grow (xhdr, keyword, klen); + x_obstack_1grow (xhdr, '='); + x_obstack_grow (xhdr, value, vsize); + x_obstack_1grow (xhdr, '\n'); +@@ -1002,8 +1187,6 @@ decode_time (struct timespec *ts, char const *arg, char const *keyword) + return true; + } + +- +- + static void + code_num (uintmax_t value, char const *keyword, struct xheader *xhdr) + { +@@ -1470,6 +1653,80 @@ volume_filename_decoder (struct tar_stat_info *st, + } + + static void ++xattr_selinux_coder (struct tar_stat_info const *st, char const *keyword, ++ struct xheader *xhdr, void const *data) ++{ ++ code_string (st->cntx_name, keyword, xhdr); ++} ++ ++static void ++xattr_selinux_decoder (struct tar_stat_info *st, ++ char const *keyword, char const *arg, size_t size) ++{ ++ decode_string (&st->cntx_name, arg); ++} ++ ++static void ++xattr_acls_a_coder (struct tar_stat_info const *st , char const *keyword, ++ struct xheader *xhdr, void const *data) ++{ ++ xheader_print_n (xhdr, keyword, st->acls_a_ptr, st->acls_a_len); ++} ++ ++static void ++xattr_acls_a_decoder (struct tar_stat_info *st, ++ char const *keyword, char const *arg, size_t size) ++{ ++ st->acls_a_ptr = xmemdup (arg, size + 1); ++ st->acls_a_len = size; ++} ++ ++static void ++xattr_acls_d_coder (struct tar_stat_info const *st , char const *keyword, ++ struct xheader *xhdr, void const *data) ++{ ++ xheader_print_n (xhdr, keyword, st->acls_d_ptr, st->acls_d_len); ++} ++ ++static void ++xattr_acls_d_decoder (struct tar_stat_info *st, ++ char const *keyword, char const *arg, size_t size) ++{ ++ st->acls_d_ptr = xmemdup (arg, size + 1); ++ st->acls_d_len = size; ++} ++ ++static void ++xattr_coder (struct tar_stat_info const *st, char const *keyword, ++ struct xheader *xhdr, void const *data) ++{ ++ struct xattr_array *xattr_map = st->xattr_map; ++ const size_t *off = data; ++ xheader_print_n (xhdr, keyword, ++ xattr_map[*off].xval_ptr, xattr_map[*off].xval_len); ++} ++ ++static void ++xattr_decoder (struct tar_stat_info *st, ++ char const *keyword, char const *arg, size_t size) ++{ ++ char *xstr, *xkey; ++ ++ /* copy keyword */ ++ size_t klen_raw = strlen (keyword); ++ xkey = alloca (klen_raw + 1); ++ memcpy (xkey, keyword, klen_raw + 1) /* including null-terminating */; ++ ++ /* copy value */ ++ xstr = alloca (size + 1); ++ memcpy (xstr, arg, size + 1); /* separator included, for GNU tar '\n' */; ++ ++ xattr_decode_keyword (xkey); ++ ++ xheader_xattr_add (st, xkey + strlen("SCHILY.xattr."), xstr, size); ++} ++ ++static void + sparse_major_coder (struct tar_stat_info const *st, char const *keyword, + struct xheader *xhdr, void const *data) + { +@@ -1506,53 +1763,53 @@ sparse_minor_decoder (struct tar_stat_info *st, + } + + struct xhdr_tab const xhdr_tab[] = { +- { "atime", atime_coder, atime_decoder, 0 }, +- { "comment", dummy_coder, dummy_decoder, 0 }, +- { "charset", dummy_coder, dummy_decoder, 0 }, +- { "ctime", ctime_coder, ctime_decoder, 0 }, +- { "gid", gid_coder, gid_decoder, 0 }, +- { "gname", gname_coder, gname_decoder, 0 }, +- { "linkpath", linkpath_coder, linkpath_decoder, 0 }, +- { "mtime", mtime_coder, mtime_decoder, 0 }, +- { "path", path_coder, path_decoder, 0 }, +- { "size", size_coder, size_decoder, 0 }, +- { "uid", uid_coder, uid_decoder, 0 }, +- { "uname", uname_coder, uname_decoder, 0 }, ++ { "atime", atime_coder, atime_decoder, 0, false }, ++ { "comment", dummy_coder, dummy_decoder, 0, false }, ++ { "charset", dummy_coder, dummy_decoder, 0, false }, ++ { "ctime", ctime_coder, ctime_decoder, 0, false }, ++ { "gid", gid_coder, gid_decoder, 0, false }, ++ { "gname", gname_coder, gname_decoder, 0, false }, ++ { "linkpath", linkpath_coder, linkpath_decoder, 0, false }, ++ { "mtime", mtime_coder, mtime_decoder, 0, false }, ++ { "path", path_coder, path_decoder, 0, false }, ++ { "size", size_coder, size_decoder, 0, false }, ++ { "uid", uid_coder, uid_decoder, 0, false }, ++ { "uname", uname_coder, uname_decoder, 0, false }, + + /* Sparse file handling */ + { "GNU.sparse.name", path_coder, path_decoder, +- XHDR_PROTECTED }, ++ XHDR_PROTECTED, false }, + { "GNU.sparse.major", sparse_major_coder, sparse_major_decoder, +- XHDR_PROTECTED }, ++ XHDR_PROTECTED, false }, + { "GNU.sparse.minor", sparse_minor_coder, sparse_minor_decoder, +- XHDR_PROTECTED }, ++ XHDR_PROTECTED, false }, + { "GNU.sparse.realsize", sparse_size_coder, sparse_size_decoder, +- XHDR_PROTECTED }, ++ XHDR_PROTECTED, false }, + { "GNU.sparse.numblocks", sparse_numblocks_coder, sparse_numblocks_decoder, +- XHDR_PROTECTED }, ++ XHDR_PROTECTED, false }, + + /* tar 1.14 - 1.15.90 keywords. */ + { "GNU.sparse.size", sparse_size_coder, sparse_size_decoder, +- XHDR_PROTECTED }, ++ XHDR_PROTECTED, false }, + /* tar 1.14 - 1.15.1 keywords. Multiple instances of these appeared in 'x' + headers, and each of them was meaningful. It confilcted with POSIX specs, + which requires that "when extended header records conflict, the last one + given in the header shall take precedence." */ + { "GNU.sparse.offset", sparse_offset_coder, sparse_offset_decoder, +- XHDR_PROTECTED }, ++ XHDR_PROTECTED, false }, + { "GNU.sparse.numbytes", sparse_numbytes_coder, sparse_numbytes_decoder, +- XHDR_PROTECTED }, ++ XHDR_PROTECTED, false }, + /* tar 1.15.90 keyword, introduced to remove the above-mentioned conflict. */ + { "GNU.sparse.map", NULL /* Unused, see pax_dump_header() */, +- sparse_map_decoder, 0 }, ++ sparse_map_decoder, 0, false }, + + { "GNU.dumpdir", dumpdir_coder, dumpdir_decoder, +- XHDR_PROTECTED }, ++ XHDR_PROTECTED, false }, + + /* Keeps the tape/volume label. May be present only in the global headers. + Equivalent to GNUTYPE_VOLHDR. */ + { "GNU.volume.label", volume_label_coder, volume_label_decoder, +- XHDR_PROTECTED | XHDR_GLOBAL }, ++ XHDR_PROTECTED | XHDR_GLOBAL, false }, + + /* These may be present in a first global header of the archive. + They provide the same functionality as GNUTYPE_MULTIVOL header. +@@ -1561,11 +1818,28 @@ struct xhdr_tab const xhdr_tab[] = { + GNU.volume.offset keeps the offset of the start of this volume, + otherwise kept in oldgnu_header.offset. */ + { "GNU.volume.filename", volume_label_coder, volume_filename_decoder, +- XHDR_PROTECTED | XHDR_GLOBAL }, ++ XHDR_PROTECTED | XHDR_GLOBAL, false }, + { "GNU.volume.size", volume_size_coder, volume_size_decoder, +- XHDR_PROTECTED | XHDR_GLOBAL }, ++ XHDR_PROTECTED | XHDR_GLOBAL, false }, + { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder, +- XHDR_PROTECTED | XHDR_GLOBAL }, ++ XHDR_PROTECTED | XHDR_GLOBAL, false }, ++ ++ /* We get the SELinux value from filecon, so add a namespace for SELinux ++ instead of storing it in SCHILY.xattr.* (which would be RAW). */ ++ { "RHT.security.selinux", ++ xattr_selinux_coder, xattr_selinux_decoder, 0, false }, ++ ++ /* ACLs, use the star format... */ ++ { "SCHILY.acl.access", ++ xattr_acls_a_coder, xattr_acls_a_decoder, 0, false }, ++ ++ { "SCHILY.acl.default", ++ xattr_acls_d_coder, xattr_acls_d_decoder, 0, false }, ++ ++ /* We are storing all extended attributes using this rule even if some of them ++ were stored by some previous rule (duplicates) -- we just have to make sure ++ they are restored *only once* during extraction later on. */ ++ { "SCHILY.xattr", xattr_coder, xattr_decoder, 0, true }, + +- { NULL, NULL, NULL, 0 } ++ { NULL, NULL, NULL, 0, false } + }; +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 3d78ea2..b0da439 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -171,7 +171,17 @@ TESTSUITE_AT = \ + star/multi-fail.at\ + star/ustar-big-2g.at\ + star/ustar-big-8g.at\ +- star/pax-big-10g.at ++ star/pax-big-10g.at\ ++ xattr01.at\ ++ xattr02.at\ ++ xattr03.at\ ++ xattr04.at\ ++ xattr05.at\ ++ acls01.at\ ++ acls02.at\ ++ selnx01.at\ ++ selacl01.at\ ++ capabs_raw01.at + + TESTSUITE = $(srcdir)/testsuite + +diff --git a/tests/acls01.at b/tests/acls01.at +new file mode 100644 +index 0000000..0149f2d +--- /dev/null ++++ b/tests/acls01.at +@@ -0,0 +1,53 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# ++# Test suite for GNU tar. ++# Copyright (C) 2011 Free Software Foundation, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3, or (at your option) ++# any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++# Test description: ++# ++# This is basic test for acl support. ++ ++AT_SETUP([acls: basic functionality]) ++AT_KEYWORDS([xattrs acls acls01]) ++ ++AT_TAR_CHECK([ ++AT_XATTRS_UTILS_PREREQ ++AT_ACLS_PREREQ ++ ++mkdir dir ++genfile --file dir/file ++ ++MYNAME=$( id -un ) ++ ++setfacl -m u:$MYNAME:--x dir/file ++setfacl -m u:$MYNAME:--x dir ++ ++getfattr -h -m. -d dir dir/file > before ++ ++tar --acls -cf archive.tar dir ++rm -rf dir ++ ++tar --acls -xf archive.tar ++ ++getfattr -h -m. -d dir dir/file > after ++ ++diff before after ++test "$?" = 0 ++], ++[0], ++[]) ++ ++AT_CLEANUP +diff --git a/tests/acls02.at b/tests/acls02.at +new file mode 100644 +index 0000000..2ee1c5f +--- /dev/null ++++ b/tests/acls02.at +@@ -0,0 +1,59 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# ++# Test suite for GNU tar. ++# Copyright (C) 2011 Free Software Foundation, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3, or (at your option) ++# any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++# Test description: ++# ++# This is basic test for acl support. ++ ++AT_SETUP([acls: work with -C]) ++AT_KEYWORDS([xattrs acls acls02]) ++ ++AT_TAR_CHECK([ ++AT_XATTRS_UTILS_PREREQ ++AT_ACLS_PREREQ ++ ++mkdir dir ++mkdir dir/subdir ++genfile --file dir/subdir/file ++ ++MYNAME=$( id -un ) ++ ++setfacl -m u:$MYNAME:--x dir/subdir ++setfacl -m u:$MYNAME:--x dir/subdir/file ++ ++cd dir ++getfattr -h -m. -d subdir subdir/file > ../before ++cd .. ++ ++tar --acls -cf archive.tar -C dir subdir ++rm -rf dir ++ ++mkdir dir ++tar --acls -xf archive.tar -C dir ++ ++cd dir ++getfattr -h -m. -d subdir subdir/file > ../after ++cd .. ++ ++diff before after ++test "$?" = 0 ++], ++[0], ++[]) ++ ++AT_CLEANUP +diff --git a/tests/capabs_raw01.at b/tests/capabs_raw01.at +new file mode 100644 +index 0000000..8eea0cf +--- /dev/null ++++ b/tests/capabs_raw01.at +@@ -0,0 +1,51 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# ++# Test suite for GNU tar. ++# Copyright (C) 2012 Free Software Foundation, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3, or (at your option) ++# any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++# Test description: Test if file capabilities are archived/restored correctly ++# using just the default xattr support (capabilities are stored/restored in ++# binary format -> system dependant). ++ ++AT_SETUP([capabilities: binary store/restore]) ++AT_KEYWORDS([xattrs capabilities capabs_raw01]) ++ ++AT_TAR_CHECK([ ++AT_PRIVILEGED_PREREQ ++AT_XATTRS_PREREQ ++AT_CAPABILITIES_UTILS_PREREQ ++ ++mkdir dir ++genfile --file dir/file ++ ++setcap "= cap_chown=ei" dir/file ++ ++# archive whole directory including binary xattrs ++tar --xattrs -cf archive.tar dir ++ ++# clear the directory ++rm -rf dir ++ ++# restore _all_ xattrs (not just the user.* domain) ++tar --xattrs --xattrs-include='*' -xf archive.tar ++ ++getcap dir/file ++], ++[0], ++[dir/file = cap_chown+ei ++]) ++ ++AT_CLEANUP +diff --git a/tests/selacl01.at b/tests/selacl01.at +new file mode 100644 +index 0000000..90d0c5b +--- /dev/null ++++ b/tests/selacl01.at +@@ -0,0 +1,64 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# ++# Test suite for GNU tar. ++# Copyright (C) 2011 Free Software Foundation, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3, or (at your option) ++# any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++# Test description: ++# ++# This is basic test for support of extended attributes. ++ ++AT_SETUP([acls/selinux: special files & fifos]) ++AT_KEYWORDS([xattrs selinux acls selacls01]) ++ ++AT_TAR_CHECK([ ++AT_PRIVILEGED_PREREQ ++AT_XATTRS_UTILS_PREREQ ++AT_SELINUX_PREREQ ++AT_ACLS_PREREQ ++ ++mkdir dir ++mkfifo dir/fifo ++MAJOR=$( stat /dev/urandom --printf="%t" ) ++MINOR=$( stat /dev/urandom --printf="%T" ) ++mknod dir/chartype c $MAJOR $MINOR ++ ++# setup attributes ++restorecon -R dir ++chcon -h --user=system_u dir/fifo ++chcon -h --user=system_u dir/chartype ++setfacl -m u:$UID:--- dir/fifo ++setfacl -m u:$UID:rwx dir/chartype ++ ++getfacl dir/fifo >> before ++getfattr -msecurity.selinux dir/chartype >> before ++ ++tar --xattrs --selinux --acls -cf archive.tar dir ++ ++mv dir olddir ++ ++tar --xattrs --selinux --acls -xf archive.tar ++ ++getfacl dir/fifo >> after ++getfattr -msecurity.selinux dir/chartype >> after ++ ++diff before after ++echo separator ++], ++[0], ++[separator ++]) ++ ++AT_CLEANUP +diff --git a/tests/selnx01.at b/tests/selnx01.at +new file mode 100644 +index 0000000..79f7267 +--- /dev/null ++++ b/tests/selnx01.at +@@ -0,0 +1,96 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# ++# Test suite for GNU tar. ++# Copyright (C) 2012 Free Software Foundation, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3, or (at your option) ++# any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++# Test description: ++# ++# This is basic test for selinux support (store & restore). ++ ++AT_SETUP([selinux: basic store/restore]) ++AT_KEYWORDS([xattrs selinux selnx01]) ++ ++AT_TAR_CHECK([ ++AT_XATTRS_UTILS_PREREQ ++AT_SELINUX_PREREQ ++ ++mkdir dir ++genfile --file dir/file ++ln -s file dir/link ++ ++getfattr -h -d -msecurity.selinux dir dir/file dir/link > start ++ ++restorecon -R dir ++chcon -h --user=system_u dir ++chcon -h --user=unconfined_u dir/file ++chcon -h --user=system_u dir/link ++ ++# archive whole directory including selinux contexts ++tar --selinux -cf archive.tar dir ++ ++# clear the directory ++rm -rf dir ++ ++# ================================================ ++# check if selinux contexts are correctly restored ++ ++tar --selinux -xf archive.tar ++ ++# archive for later debugging ++cp archive.tar archive_origin.tar ++ ++# check if selinux contexts were restored ++getfattr -h -d dir dir/file dir/link -msecurity.selinux | \ ++ grep -v -e '^#' -e ^$ | cut -d: -f1 ++ ++# =========================================================================== ++# check if selinux contexts are not restored when --selinux option is missing ++ ++getfattr -h -d -msecurity.selinux dir dir/file dir/link > with_selinux ++rm -rf dir ++tar -xf archive.tar ++getfattr -h -d -msecurity.selinux dir dir/file dir/link > without_selinux ++ ++diff with_selinux without_selinux > diff_with_without ++if test "$?" -eq "0"; then ++ echo "selinux contexts probably restored while --selinux is off" ++fi ++ ++# ================================================================= ++# check if selinux is not archived when --selinux option is missing ++ ++tar -cf archive.tar dir ++ ++# clear the directory ++rm -rf dir ++ ++# restore (with --selinux) ++tar --selinux -xf archive.tar dir ++ ++getfattr -h -d -msecurity.selinux dir dir/file dir/link > final ++diff start final > final_diff ++if test "$?" -ne "0"; then ++ echo "bad result" ++fi ++ ++], ++[0], ++[security.selinux="system_u ++security.selinux="unconfined_u ++security.selinux="system_u ++]) ++ ++AT_CLEANUP +diff --git a/tests/testsuite.at b/tests/testsuite.at +index e43653e..8d5811d 100644 +--- a/tests/testsuite.at ++++ b/tests/testsuite.at +@@ -81,13 +81,6 @@ m4_define([AT_GZIP_PREREQ],[ + cat /dev/null | m4_if([$1],[],gzip,[$1]) - > /dev/null 2>&1 || AT_SKIP_TEST + ]) + +-dnl AT_SIGPIPE_PREREQ - Skip test unless SIGPIPE handling is the default +-m4_define([AT_SIGPIPE_PREREQ],[ +-case `(cat "$at_myself" 2>&3 | :) 3>&1 >/dev/null` in #( +-?*) AT_SKIP_TEST;; +-esac +-]) +- + dnl AT_SORT_PREREQ - Skip test if sort utility outputs unwanted data on stderr + m4_define([AT_SORT_PREREQ],[ + test -z "`sort < /dev/null 2>&1`" || AT_SKIP_TEST +@@ -103,10 +96,86 @@ rm -f $[]$ + test $result -eq 0 && AT_SKIP_TEST + ]) + ++dnl AT_SIGPIPE_PREREQ - Skip test unless SIGPIPE handling is the default ++m4_define([AT_SIGPIPE_PREREQ],[ ++case `(cat "$at_myself" 2>&3 | :) 3>&1 >/dev/null` in #( ++?*) AT_SKIP_TEST;; ++esac ++]) ++ ++dnl AT_PRIVILEGED_PREREQ - Skip test if not running at root privileges ++m4_define([AT_PRIVILEGED_PREREQ],[ ++echo "test" > $[]$ ++chmod 0 $[]$ ++cat $[]$ > /dev/null 2>&1 ++result=$? ++rm -f $[]$ ++test $result -eq 0 || AT_SKIP_TEST ++]) ++ + m4_define([AT_TAR_MKHIER],[ + install-sh -d $1 >/dev/null dnl + m4_if([$2],,,&& genfile --file [$1]/[$2]) || AT_SKIP_TEST]) + ++dnl Skip test when utlity does not return expected return value ++m4_define([AT_CHECK_UTIL],[ ++ $1 &> /dev/null ++ if test "$?" != $2; then ++ AT_SKIP_TEST ++ fi ++]) ++ ++m4_define([AT_XATTRS_UTILS_PREREQ],[ ++ file=$( mktemp -p . ) ++ AT_CHECK_UTIL(setfattr -n user.test -v test $file,0) ++ AT_CHECK_UTIL(getfattr $file,0) ++]) ++m4_define([AT_SELINUX_UTILS_PREREQ],[ ++ file=$( mktemp -p . ) ++ AT_CHECK_UTIL(restorecon $file, 0) ++ AT_CHECK_UTIL(chcon -h --user=unconfined_u $file,0) ++ rm -rf $file ++]) ++m4_define([AT_ACLS_UTILS_PREREQ],[ ++ file=$( mktemp -p . ) ++ AT_CHECK_UTIL(setfacl -m u:$UID:rwx $file,0) ++ AT_CHECK_UTIL(getfacl $file,0) ++ rm -rf $file ++]) ++m4_define([AT_CAPABILITIES_UTILS_PREREQ],[ ++ file=$( mktemp -p . ) ++ AT_CHECK_UTIL(setcap "= cap_chown=ei" $file,0) ++ AT_CHECK_UTIL(getcap $file,0) ++ rm -rf $file ++]) ++m4_define([AT_XATTRS_PREREQ],[ ++ AT_XATTRS_UTILS_PREREQ ++ file=$( mktemp -p . ) ++ setfattr -n user.test -v ahoj $file ++ # check whether tar fails to store xattrs ++ err=$( tar --xattrs -cf /dev/null $file 2>&1 >/dev/null | wc -l ) ++ if test "$err" != "0"; then ++ AT_SKIP_TEST ++ fi ++]) ++m4_define([AT_SELINUX_PREREQ],[ ++ AT_SELINUX_UTILS_PREREQ ++ file=$( mktemp -p . ) ++ err=$( tar --selinux -cf /dev/null $file 2>&1 >/dev/null | wc -l ) ++ if test "$err" != "0"; then ++ AT_SKIP_TEST ++ fi ++]) ++m4_define([AT_ACLS_PREREQ],[ ++ AT_ACLS_UTILS_PREREQ ++ file=$( mktemp -p . ) ++ setfacl -m u:$UID:rwx $file ++ err=$( tar --acls -cf /dev/null $file 2>&1 >/dev/null | wc -l ) ++ if test "$err" != "0"; then ++ AT_SKIP_TEST ++ fi ++]) ++ + m4_include([sparsemvp.at]) + + AT_INIT +@@ -264,6 +334,20 @@ m4_include([remfiles03.at]) + + m4_include([sigpipe.at]) + ++m4_include([xattr01.at]) ++m4_include([xattr02.at]) ++m4_include([xattr03.at]) ++m4_include([xattr04.at]) ++m4_include([xattr05.at]) ++ ++m4_include([acls01.at]) ++m4_include([acls02.at]) ++ ++m4_include([selnx01.at]) ++m4_include([selacl01.at]) ++ ++m4_include([capabs_raw01.at]) ++ + m4_include([star/gtarfail.at]) + m4_include([star/gtarfail2.at]) + +@@ -273,3 +357,4 @@ m4_include([star/ustar-big-2g.at]) + m4_include([star/ustar-big-8g.at]) + + m4_include([star/pax-big-10g.at]) ++ +diff --git a/tests/xattr01.at b/tests/xattr01.at +new file mode 100644 +index 0000000..fd960d5 +--- /dev/null ++++ b/tests/xattr01.at +@@ -0,0 +1,47 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# ++# Test suite for GNU tar. ++# Copyright (C) 2011 Free Software Foundation, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3, or (at your option) ++# any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++# Test description: ++# ++# This is basic test for support of extended attributes. ++ ++AT_SETUP([xattrs: basic functionality]) ++AT_KEYWORDS([xattrs xattr01]) ++ ++AT_TAR_CHECK([ ++AT_XATTRS_PREREQ ++mkdir dir ++genfile --file dir/file ++ ++setfattr -n user.test -v OurDirValue dir ++setfattr -n user.test -v OurFileValue dir/file ++ ++tar --xattrs -cf archive.tar dir ++ ++rm -rf dir ++tar --xattrs -xf archive.tar ++ ++getfattr -h -d dir | grep -v -e '^#' -e ^$ ++getfattr -h -d dir/file | grep -v -e '^#' -e ^$ ++], ++[0], ++[user.test="OurDirValue" ++user.test="OurFileValue" ++]) ++ ++AT_CLEANUP +diff --git a/tests/xattr02.at b/tests/xattr02.at +new file mode 100644 +index 0000000..3aae3f9 +--- /dev/null ++++ b/tests/xattr02.at +@@ -0,0 +1,55 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# ++# Test suite for GNU tar. ++# Copyright (C) 2011 Free Software Foundation, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3, or (at your option) ++# any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++# Test description: ++# ++# Cooperation of the '-C' option and storing/restoring extended attributes. ++ ++AT_SETUP([xattrs: change directory with -C option]) ++AT_KEYWORDS([xattrs xattr02]) ++ ++AT_TAR_CHECK([ ++AT_XATTRS_PREREQ ++ ++mkdir dir ++mkdir dir/subdir ++mkdir dir/subdir/subsubdir ++genfile --file dir/file1 ++genfile --file dir/subdir/file2 ++ ++setfattr -n user.test -v OurFile1Value dir/file1 ++setfattr -n user.test -v OurFile2Value dir/subdir/file2 ++setfattr -n user.test -v OurDirValue dir/subdir/subsubdir ++ ++tar --xattrs -cf archive.tar -C dir file1 -C subdir file2 subsubdir ++ ++rm -rf dir ++ ++tar --xattrs -xf archive.tar ++ ++getfattr -h -d file1 | grep -v -e '^#' -e ^$ ++getfattr -h -d file2 | grep -v -e '^#' -e ^$ ++getfattr -h -d subsubdir | grep -v -e '^#' -e ^$ ++], ++[0], ++[user.test="OurFile1Value" ++user.test="OurFile2Value" ++user.test="OurDirValue" ++]) ++ ++AT_CLEANUP +diff --git a/tests/xattr03.at b/tests/xattr03.at +new file mode 100644 +index 0000000..d834f9f +--- /dev/null ++++ b/tests/xattr03.at +@@ -0,0 +1,56 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# ++# Test suite for GNU tar. ++# Copyright (C) 2012 Free Software Foundation, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3, or (at your option) ++# any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++# Test description: ++# ++# Setup of the trusted.* domain under privileged user. ++ ++AT_SETUP([xattrs: trusted.* attributes]) ++AT_KEYWORDS([xattrs xattr03]) ++ ++AT_TAR_CHECK([ ++AT_PRIVILEGED_PREREQ ++AT_XATTRS_PREREQ ++ ++mkdir dir ++mkdir dir/subdir ++mkdir dir/subdir/subsubdir ++genfile --file dir/file1 ++genfile --file dir/subdir/file2 ++ ++setfattr -n trusted.test -v OurFile1Value dir/file1 ++setfattr -n trusted.test -v OurFile2Value dir/subdir/file2 ++setfattr -n trusted.test -v OurDirValue dir/subdir/subsubdir ++ ++tar --xattrs -cf archive.tar -C dir file1 -C subdir file2 subsubdir ++ ++rm -rf dir ++ ++tar --xattrs --xattrs-include=trusted* -xf archive.tar ++ ++getfattr -mtrusted. -d file1 | grep -v -e '^#' -e ^$ ++getfattr -mtrusted. -d file2 | grep -v -e '^#' -e ^$ ++getfattr -mtrusted. -d subsubdir | grep -v -e '^#' -e ^$ ++], ++[0], ++[trusted.test="OurFile1Value" ++trusted.test="OurFile2Value" ++trusted.test="OurDirValue" ++]) ++ ++AT_CLEANUP +diff --git a/tests/xattr04.at b/tests/xattr04.at +new file mode 100644 +index 0000000..31832af +--- /dev/null ++++ b/tests/xattr04.at +@@ -0,0 +1,48 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# ++# Test suite for GNU tar. ++# Copyright (C) 2012 Free Software Foundation, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3, or (at your option) ++# any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++# Test description: Test for the regression caused by tar update from 1.23 to ++# 1.26, Red Hat xattr patch was not ready for open->openat conversion. ++# ++# Related commit 4bde4f3. See the bug: https://bugzilla.redhat.com/717684 ++ ++AT_SETUP([xattrs: s/open/openat/ regression]) ++AT_KEYWORDS([xattrs xattr04]) ++ ++AT_TAR_CHECK([ ++AT_XATTRS_PREREQ ++ ++mkdir dir ++mkdir output ++genfile --file dir/file ++ ++setfattr -n user.test -v value dir/file ++ ++# archive whole directory including binary xattrs ++tar --xattrs -cf archive.tar -C dir . ++ ++tar --xattrs -xf archive.tar -C output ++ret=$? ++getfattr -h -d output/file | grep -v -e '^#' -e ^$ ++exit $ret ++], ++[0], ++[user.test="value" ++]) ++ ++AT_CLEANUP +diff --git a/tests/xattr05.at b/tests/xattr05.at +new file mode 100644 +index 0000000..27dc469 +--- /dev/null ++++ b/tests/xattr05.at +@@ -0,0 +1,49 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest -*- ++# ++# Test suite for GNU tar. ++# Copyright (C) 2012 Free Software Foundation, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3, or (at your option) ++# any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++# Test description: Test for archiving/extracting of extended attributes ++# having the '=' character in its keyword. ++# ++# Relevant mailing list thread: ++# ++# http://lists.gnu.org/archive/html/bug-tar/2012-10/msg00017.html ++ ++AT_SETUP([xattrs: keywords with '=' and '%']) ++AT_KEYWORDS([xattrs xattr05]) ++ ++AT_TAR_CHECK([ ++AT_XATTRS_PREREQ ++ ++mkdir dir ++mkdir output ++genfile --file dir/file ++ ++setfattr -n user.=NAME%3D= -v value dir/file ++getfattr -d dir/file | grep -v '# ' > before ++ ++# archive whole directory including binary xattrs ++tar --xattrs -cf archive.tar -C dir . ++ ++tar --xattrs -xf archive.tar -C output ++getfattr -d output/file | grep -v '# ' > after ++diff before after ++], ++[0], ++[]) ++ ++AT_CLEANUP diff --git a/SOURCES/tar-1.27-sparse-stat-detection.patch b/SOURCES/tar-1.27-sparse-stat-detection.patch new file mode 100644 index 00000000..ecc59f0c --- /dev/null +++ b/SOURCES/tar-1.27-sparse-stat-detection.patch @@ -0,0 +1,21 @@ +diff --git a/lib/system.h b/lib/system.h +index ef46267..e7f531c 100644 +--- a/lib/system.h ++++ b/lib/system.h +@@ -389,9 +389,16 @@ extern int errno; + # define ST_NBLOCKSIZE 512 + #endif + ++/* Network Appliance file systems store small files directly in the ++ inode if st_size <= 64; in this case the number of blocks can be ++ zero. Perhaps other file systems have similar problems; so, ++ somewhat arbitrarily, do not consider a file to be sparse if ++ it has no blocks but st_size < ST_NBLOCKSIZE. */ + #define ST_IS_SPARSE(st) \ + (ST_NBLOCKS (st) \ +- < ((st).st_size / ST_NBLOCKSIZE + ((st).st_size % ST_NBLOCKSIZE != 0))) ++ < ((st).st_size / ST_NBLOCKSIZE \ ++ + ((st).st_size % ST_NBLOCKSIZE != 0 \ ++ && (st).st_size / ST_NBLOCKSIZE != 0))) + + /* Declare standard functions. */ diff --git a/SOURCES/tar.1 b/SOURCES/tar.1 new file mode 100644 index 00000000..3beb97fa --- /dev/null +++ b/SOURCES/tar.1 @@ -0,0 +1,638 @@ +.\" This file was originally generated by help2man +.TH TAR "1" "February 2013" "tar 1.26" "User Commands" +.SH NAME +tar \- manual page for tar 1.26 +.SH SYNOPSIS +.B tar +[\fIOPTION\fR...] [\fIFILE\fR]... +.SH DESCRIPTION +GNU `tar' saves many files together into a single tape or disk archive, and can +restore individual files from the archive. + +Note that this manual page contains just very brief description (or more like +a list of possible functionality) originally generated by the +.B +help2man +utility. The full documentation for +.B tar +is maintained as a Texinfo manual. If the +.B info +and +.B tar +programs are properly installed at your site, the command +.B `info tar' +should give you access to the complete manual. +.SH EXAMPLES +.TP +tar \fB\-cf\fR archive.tar foo bar +# Create archive.tar from files foo and bar. +.TP +tar \fB\-tvf\fR archive.tar +# List all files in archive.tar verbosely. +.TP +tar \fB\-xf\fR archive.tar +# Extract all files from archive.tar. +.IP +.SH DEFAULTS +*This* tar installation defaults to: + +\fB\-\-format\fR=\fIgnu\fR \fB\-f\-\fR \fB\-b20\fR \fB\-\-quoting\-style\fR=\fIescape\fR \fB\-\-rmt\-command=\fR/sbin/rmt +\fB\-\-rsh\-command=\fR/usr/bin/rsh +.SH \fBMain operation mode:\fR +.TP +\fB\-A\fR, \fB\-\-catenate\fR, \fB\-\-concatenate\fR +append tar files to an archive +.TP +\fB\-c\fR, \fB\-\-create\fR +create a new archive +.TP +\fB\-d\fR, \fB\-\-diff\fR, \fB\-\-compare\fR +find differences between archive and file system +.TP +\fB\-\-delete\fR +delete from the archive (not on mag tapes!) +.TP +\fB\-r\fR, \fB\-\-append\fR +append files to the end of an archive +.TP +\fB\-t\fR, \fB\-\-list\fR +list the contents of an archive +.TP +\fB\-\-test\-label\fR +test the archive volume label and exit +.TP +\fB\-u\fR, \fB\-\-update\fR +only append files newer than copy in archive +.TP +\fB\-x\fR, \fB\-\-extract\fR, \fB\-\-get\fR +extract files from an archive +.IP +.SH \fBCommon options:\fR +.TP +\fB-C\fR, \fB--directory=DIR\fR +change to directory DIR +.TP +\fB-f\fR, \fB--file=ARCHIVE\fR +use archive file or device ARCHIVE +.TP +\fB-j\fR, \fB--bzip2\fR +filter the archive through bzip2 +.TP +\fB -J\fR, \fB--xz\fR +filter the archive through xz +.TP +\fB-p\fR, \fB--preserve-permissions\fR +extract information about file permissions (default for superuser) +.TP +\fB-v\fR, \fB--verbose\fR +verbosely list files processed +.TP +\fB-z\fR, \fB--gzip\fR +filter the archive through gzip + +.SH \fBOperation modifiers:\fR +.TP +\fB\-\-check\-device\fR +check device numbers when creating incremental +archives (default) +.TP +\fB\-g\fR, \fB\-\-listed\-incremental\fR=\fIFILE\fR +handle new GNU\-format incremental backup +.TP +\fB\-G\fR, \fB\-\-incremental\fR +handle old GNU\-format incremental backup +.TP +\fB\-\-ignore\-failed\-read\fR +do not exit with nonzero on unreadable files +.TP +\fB\-\-level\fR=\fINUMBER\fR +dump level for created listed\-incremental archive +.TP +\fB\-n\fR, \fB\-\-seek\fR +archive is seekable +.TP +\fB\-\-no\-check\-device\fR +do not check device numbers when creating +incremental archives +.TP +\fB\-\-no\-seek\fR +archive is not seekable +.TP +\fB\-\-occurrence\fR[=\fINUMBER\fR] +process only the NUMBERth occurrence of each file +in the archive; this option is valid only in +conjunction with one of the subcommands \fB\-\-delete\fR, +\fB\-\-diff\fR, \fB\-\-extract\fR or \fB\-\-list\fR and when a list of +files is given either on the command line or via +the \fB\-T\fR option; NUMBER defaults to 1 +.TP +\fB\-\-sparse\-version\fR=\fIMAJOR[\fR.MINOR] +set version of the sparse format to use (implies +\fB\-\-sparse\fR) +.TP +\fB\-S\fR, \fB\-\-sparse\fR +handle sparse files efficiently +.IP +.SH \fBOverwrite control:\fR +.TP +\fB\-k\fR, \fB\-\-keep\-old\-files\fR +don't replace existing files when extracting, +treat them as errors +.TP +\fB\-\-keep\-newer\-files\fR +don't replace existing files that are newer than +their archive copies +.TP +\fB\-\-keep\-directory\-symlink\fR +Don't replace existing symlinks to directories when extracting. +.TP +\fB\-\-no\-overwrite\-dir\fR +preserve metadata of existing directories +.TP +\fB\-\-overwrite\fR +overwrite existing files when extracting +.TP +\fB\-\-overwrite\-dir\fR +overwrite metadata of existing directories when +extracting (default) +.TP +\fB\-\-recursive\-unlink\fR +empty hierarchies prior to extracting directory +.TP +\fB\-\-remove\-files\fR +remove files after adding them to the archive +.TP +\fB\-\-skip\-old\-files\fR +don't replace existing files when extracting, +silently skip over them +.TP +\fB\-U\fR, \fB\-\-unlink\-first\fR +remove each file prior to extracting over it +.TP +\fB\-W\fR, \fB\-\-verify\fR +attempt to verify the archive after writing it +.IP +.SH \fBSelect output stream:\fR +.HP +\fB\-\-ignore\-command\-error\fR ignore exit codes of children +.TP +\fB\-\-no\-ignore\-command\-error\fR +treat non\-zero exit codes of children as +error +.TP +\fB\-O\fR, \fB\-\-to\-stdout\fR +extract files to standard output +.TP +\fB\-\-to\-command\fR=\fICOMMAND\fR +pipe extracted files to another program +.IP +.SH \fBHandling of file attributes:\fR +.TP +\fB\-\-atime\-preserve\fR[=\fIMETHOD\fR] +preserve access times on dumped files, either +by restoring the times after reading +(METHOD='replace'; default) or by not setting the +times in the first place (METHOD='system') +.TP +\fB\-\-delay\-directory\-restore\fR +delay setting modification times and +permissions of extracted directories until the end +of extraction +.TP +\fB\-\-group\fR=\fINAME\fR +force NAME as group for added files +.TP +\fB\-\-mode\fR=\fICHANGES\fR +force (symbolic) mode CHANGES for added files +.TP +\fB\-\-mtime\fR=\fIDATE\-OR\-FILE\fR +set mtime for added files from DATE\-OR\-FILE +.TP +\fB\-m\fR, \fB\-\-touch\fR +don't extract file modified time +.TP +\fB\-\-no\-delay\-directory\-restore\fR +cancel the effect of \fB\-\-delay\-directory\-restore\fR +option +.TP +\fB\-\-no\-same\-owner\fR +extract files as yourself (default for ordinary +users) +.TP +\fB\-\-no\-same\-permissions\fR +apply the user's umask when extracting permissions +from the archive (default for ordinary users) +.TP +\fB\-\-numeric\-owner\fR +always use numbers for user/group names +.TP +\fB\-\-owner\fR=\fINAME\fR +force NAME as owner for added files +.TP +\fB\-p\fR, \fB\-\-preserve\-permissions\fR, \fB\-\-same\-permissions\fR +extract information about file permissions +(default for superuser) +.TP +\fB\-\-preserve\fR +same as both \fB\-p\fR and \fB\-s\fR +.TP +\fB\-\-same\-owner\fR +try extracting files with the same ownership as +exists in the archive (default for superuser) +.TP +\fB\-s\fR, \fB\-\-preserve\-order\fR, \fB\-\-same\-order\fR +sort names to extract to match archive +.IP +.SH \fBHandling of extended file attributes:\fR +.TP +\fB\-\-acls\fR +Enable the POSIX ACLs support +.TP +\fB\-\-no\-acls\fR +Disable the POSIX ACLs support +.TP +\fB\-\-no\-selinux\fR +Disable the SELinux context support +.TP +\fB\-\-no\-xattrs\fR +Disable extended attributes support +.TP +\fB\-\-selinux\fR +Enable the SELinux context support +.TP +\fB\-\-xattrs\fR +Enable extended attributes support +.TP +\fB\-\-xattrs\-exclude\fR=\fIMASK\fR +specify the exclude pattern for xattr keys +.TP +\fB\-\-xattrs\-include\fR=\fIMASK\fR +specify the include pattern for xattr keys +.IP +.SH \fBDevice selection and switching:\fR +.TP +\fB\-f\fR, \fB\-\-file\fR=\fIARCHIVE\fR +use archive file or device ARCHIVE +.TP +\fB\-\-force\-local\fR +archive file is local even if it has a colon +.TP +\fB\-F\fR, \fB\-\-info\-script\fR=\fINAME\fR, \fB\-\-new\-volume\-script\fR=\fINAME\fR +run script at end of each tape (implies \fB\-M\fR) +.TP +\fB\-L\fR, \fB\-\-tape\-length\fR=\fINUMBER\fR +change tape after writing NUMBER x 1024 bytes +.TP +\fB\-M\fR, \fB\-\-multi\-volume\fR +create/list/extract multi\-volume archive +.TP +\fB\-\-rmt\-command\fR=\fICOMMAND\fR +use given rmt COMMAND instead of rmt +.TP +\fB\-\-rsh\-command\fR=\fICOMMAND\fR +use remote COMMAND instead of rsh +.TP +\fB\-\-volno\-file\fR=\fIFILE\fR +use/update the volume number in FILE +.IP +.SH \fBDevice blocking:\fR +.TP +\fB\-b\fR, \fB\-\-blocking\-factor\fR=\fIBLOCKS\fR +BLOCKS x 512 bytes per record +.TP +\fB\-B\fR, \fB\-\-read\-full\-records\fR +reblock as we read (for 4.2BSD pipes) +.TP +\fB\-i\fR, \fB\-\-ignore\-zeros\fR +ignore zeroed blocks in archive (means EOF) +.TP +\fB\-\-record\-size\fR=\fINUMBER\fR +NUMBER of bytes per record, multiple of 512 +.IP +.SH \fBArchive format selection:\fR +\fB\-H\fR, \fB\-\-format\fR=\fIFORMAT\fR +.RS +create archive of the given format +.sp +FORMAT is one of the following: +.RS +.TP +gnu +GNU tar 1.13.x format +.TP +oldgnu +GNU format as per tar <= 1.12 +.TP +pax +POSIX 1003.1\-2001 (pax) format +.TP +posix +same as pax +.TP +ustar +POSIX 1003.1\-1988 (ustar) format +.TP +v7 +old V7 tar format +.RE +.RE +.TP +\fB\-\-old\-archive\fR, \fB\-\-portability\fR +same as \fB\-\-format\fR=\fIv7\fR +.TP +\fB\-\-pax\-option\fR=\fIkeyword[[\fR:]=value][,keyword[[:]=value]]... +control pax keywords +.TP +\fB\-\-posix\fR +same as \fB\-\-format\fR=\fIposix\fR +.TP +\fB\-V\fR, \fB\-\-label\fR=\fITEXT\fR +create archive with volume name TEXT; at +list/extract time, use TEXT as a globbing pattern +for volume name +.IP +.SH \fBCompression options:\fR +.TP +\fB\-a\fR, \fB\-\-auto\-compress\fR +use archive suffix to determine the compression +program +.TP +\fB\-I\fR, \fB\-\-use\-compress\-program\fR=\fIPROG\fR +filter through PROG (must accept \fB\-d\fR) +.TP +\fB\-j\fR, \fB\-\-bzip2\fR +filter the archive through bzip2 +.TP +\fB\-J\fR, \fB\-\-xz\fR +filter the archive through xz +.TP +\fB\-\-lzip\fR +filter the archive through lzip +.TP +\fB\-\-lzma\fR +filter the archive through lzma +.HP +\fB\-\-lzop\fR +.TP +\fB\-\-no\-auto\-compress\fR +do not use archive suffix to determine the +compression program +.TP +\fB\-z\fR, \fB\-\-gzip\fR, \fB\-\-gunzip\fR, \fB\-\-ungzip\fR +filter the archive through gzip +.TP +\fB\-Z\fR, \fB\-\-compress\fR, \fB\-\-uncompress\fR +filter the archive through compress +.TP +\fBNote: You might need to install external program (lzip/ncompress/lzma...) to use some of these compression options\fB +.IP +.SH \fBLocal file selection:\fR +.TP +\fB\-\-add\-file\fR=\fIFILE\fR +add given FILE to the archive (useful if its name +starts with a dash) +.TP +\fB\-\-backup\fR[=\fICONTROL\fR] +backup before removal, choose version CONTROL +.TP +\fB\-C\fR, \fB\-\-directory\fR=\fIDIR\fR +change to directory DIR +.TP +\fB\-\-exclude\fR=\fIPATTERN\fR +exclude files, given as a PATTERN +.TP +\fB\-\-exclude\-backups\fR +exclude backup and lock files +.TP +\fB\-\-exclude\-caches\fR +exclude contents of directories containing +CACHEDIR.TAG, except for the tag file itself +.TP +\fB\-\-exclude\-caches\-all\fR +exclude directories containing CACHEDIR.TAG +.TP +\fB\-\-exclude\-caches\-under\fR exclude everything under directories containing +CACHEDIR.TAG +.TP +\fB\-\-exclude\-tag\fR=\fIFILE\fR +exclude contents of directories containing FILE, +except for FILE itself +.HP +\fB\-\-exclude\-tag\-all\fR=\fIFILE\fR exclude directories containing FILE +.TP +\fB\-\-exclude\-tag\-under\fR=\fIFILE\fR +exclude everything under directories +containing FILE +.TP +\fB\-\-exclude\-vcs\fR +exclude version control system directories +.TP +\fB\-h\fR, \fB\-\-dereference\fR +follow symlinks; archive and dump the files they +point to +.TP +\fB\-\-hard\-dereference\fR +follow hard links; archive and dump the files they +refer to +.TP +\fB\-K\fR, \fB\-\-starting\-file\fR=\fIMEMBER\-NAME\fR +begin at member MEMBER\-NAME in the archive +.TP +\fB\-\-newer\-mtime\fR=\fIDATE\fR +compare date and time when data changed only +.TP +\fB\-\-no\-null\fR +disable the effect of the previous \fB\-\-null\fR option +.TP +\fB\-\-no\-recursion\fR +avoid descending automatically in directories +.TP +\fB\-\-no\-unquote\fR +do not unquote filenames read with \fB\-T\fR +.HP +\fB\-\-null\fR \fB\-T\fR reads null\-terminated names, disable \fB\-C\fR +.TP +\fB\-N\fR, \fB\-\-newer\fR=\fIDATE\-OR\-FILE\fR, \fB\-\-after\-date\fR=\fIDATE\-OR\-FILE\fR +only store files newer than DATE\-OR\-FILE +.TP +\fB\-\-one\-file\-system\fR +stay in local file system when creating archive +.TP +\fB\-P\fR, \fB\-\-absolute\-names\fR +don't strip leading `/'s from file names +.TP +\fB\-\-recursion\fR +recurse into directories (default) +.TP +\fB\-\-suffix\fR=\fISTRING\fR +backup before removal, override usual suffix ('~' +unless overridden by environment variable +SIMPLE_BACKUP_SUFFIX) +.TP +\fB\-T\fR, \fB\-\-files\-from\fR=\fIFILE\fR +get names to extract or create from FILE +.TP +\fB\-\-unquote\fR +unquote filenames read with \fB\-T\fR (default) +.TP +\fB\-X\fR, \fB\-\-exclude\-from\fR=\fIFILE\fR +exclude patterns listed in FILE +.IP +.SH \fBFile name transformations:\fR +.TP +\fB\-\-strip\-components\fR=\fINUMBER\fR +strip NUMBER leading components from file +names on extraction +.TP +\fB\-\-transform\fR=\fIEXPRESSION\fR, \fB\-\-xform\fR=\fIEXPRESSION\fR +use sed replace EXPRESSION to transform file +names +.IP +File name matching options (affect both exclude and include patterns): +.TP +\fB\-\-anchored\fR +patterns match file name start +.TP +\fB\-\-ignore\-case\fR +ignore case +.TP +\fB\-\-no\-anchored\fR +patterns match after any `/' (default for +exclusion) +.TP +\fB\-\-no\-ignore\-case\fR +case sensitive matching (default) +.TP +\fB\-\-no\-wildcards\fR +verbatim string matching +.TP +\fB\-\-no\-wildcards\-match\-slash\fR +wildcards do not match `/' +.TP +\fB\-\-wildcards\fR +use wildcards (default) +.TP +\fB\-\-wildcards\-match\-slash\fR +wildcards match `/' (default for exclusion) +.IP +.SH \fBInformative output:\fR +.TP +\fB\-\-checkpoint\fR[=\fINUMBER\fR] +display progress messages every NUMBERth record +(default 10) +.TP +\fB\-\-checkpoint\-action\fR=\fIACTION\fR +execute ACTION on each checkpoint +.TP +\fB\-\-full\-time\fR +print file time to its full resolution +.TP +\fB\-\-index\-file\fR=\fIFILE\fR +send verbose output to FILE +.TP +\fB\-l\fR, \fB\-\-check\-links\fR +print a message if not all links are dumped +.TP +\fB\-\-no\-quote\-chars\fR=\fISTRING\fR +disable quoting for characters from STRING +.TP +\fB\-\-quote\-chars\fR=\fISTRING\fR +additionally quote characters from STRING +.TP +\fB\-\-quoting\-style\fR=\fISTYLE\fR +set name quoting style; see below for valid STYLE +values +.TP +\fB\-R\fR, \fB\-\-block\-number\fR +show block number within archive with each +message +.TP +\fB\-\-show\-defaults\fR +show tar defaults +.TP +\fB\-\-show\-omitted\-dirs\fR +when listing or extracting, list each directory +that does not match search criteria +.TP +\fB\-\-show\-transformed\-names\fR, \fB\-\-show\-stored\-names\fR +show file or archive names after transformation +.TP +\fB\-\-totals\fR[=\fISIGNAL\fR] +print total bytes after processing the archive; +with an argument \- print total bytes when this +SIGNAL is delivered; Allowed signals are: SIGHUP, +SIGQUIT, SIGINT, SIGUSR1 and SIGUSR2; the names +without SIG prefix are also accepted +.TP +\fB\-\-utc\fR +print file modification dates in UTC +.TP +\fB\-v\fR, \fB\-\-verbose\fR +verbosely list files processed +.TP +\fB\-\-warning\fR=\fIKEYWORD\fR +warning control +.TP +\fB\-w\fR, \fB\-\-interactive\fR, \fB\-\-confirmation\fR +ask for confirmation for every action +.IP +.SH \fBCompatibility options:\fR +.TP +\fB\-o\fR +when creating, same as \fB\-\-old\-archive\fR; when +extracting, same as \fB\-\-no\-same\-owner\fR +.IP +.SH \fBOther options:\fR +.TP +\-?, \fB\-\-help\fR +give this help list +.TP +\fB\-\-restrict\fR +disable use of some potentially harmful options +.TP +\fB\-\-usage\fR +give a short usage message +.TP +\fB\-\-version\fR +print program version +.PP +.PP +Mandatory or optional arguments to long options are also mandatory or optional +for any corresponding short options. +.PP +The backup suffix is `~', unless set with \fB\-\-suffix\fR or SIMPLE_BACKUP_SUFFIX. +The version control may be set with \fB\-\-backup\fR or VERSION_CONTROL, values are: +.TP +none, off +never make backups +.TP +t, numbered +make numbered backups +.TP +nil, existing +numbered if numbered backups exist, simple otherwise +.TP +never, simple +always make simple backups +.PP +Valid arguments for the \fB\-\-quoting\-style\fR option are: +.IP +literal +shell +shell\-always +c +c\-maybe +escape +locale +clocale +.PP +.SH AUTHOR +Written by John Gilmore and Jay Fenlason. +.SH "REPORTING BUGS" +Report bugs to . +.SH COPYRIGHT +Copyright \(co 2013 Free Software Foundation, Inc. +License GPLv3+: GNU GPL version 3 or later . +.br +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. diff --git a/SPECS/tar.spec b/SPECS/tar.spec new file mode 100644 index 00000000..426fc829 --- /dev/null +++ b/SPECS/tar.spec @@ -0,0 +1,956 @@ +%if %{?WITH_SELINUX:0}%{!?WITH_SELINUX:1} +%global WITH_SELINUX 1 +%endif +Summary: A GNU file archiving program +Name: tar +Epoch: 2 +Version: 1.26 +Release: 34%{?dist} +License: GPLv3+ +Group: Applications/Archiving +URL: http://www.gnu.org/software/tar/ + +Source0: ftp://ftp.gnu.org/pub/gnu/tar/tar-%{version}.tar.xz +Source1: ftp://ftp.gnu.org/pub/gnu/tar/tar-%{version}.tar.xz.sig +# Manpage for tar and gtar, a bit modified help2man generated manpage +Source2: tar.1 + +# Stop issuing lone zero block warnings. +# ~> https://bugzilla.redhat.com/show_bug.cgi?id=135601 +# ~> downstream +Patch1: tar-1.14-loneZeroWarning.patch + +# Fix extracting sparse files to a file system like vfat, when ftruncate may fail +# to grow the size of a file. +# ~> #179507, +# ~> http://lists.gnu.org/archive/html/bug-tar/2006-02/msg00000.html +# ~> still downtream (do we need this now? ftruncate & vfat works is now OK) +Patch2: tar-1.15.1-vfatTruncate.patch + +# Change inclusion defaults of tar to +# "--wildcards --anchored --wildcards-match-slash" for compatibility reasons. +# ~> #206841 +# ~> downstream (compatibility) +Patch3: tar-1.17-wildcards.patch + +# Ignore errors from setting utime() for source file on read-only file-system. +# ~> #500742 +# ~> http://lists.gnu.org/archive/html/bug-tar/2009-06/msg00016.html +# ~> still downstream +Patch4: tar-1.22-atime-rofs.patch + +# The --old-archive option was not working. +# ~> #594044 +# ~> http://lists.gnu.org/archive/html/bug-tar/2010-05/msg00015.html +# ~> upstream (2a61a37) +Patch5: tar-1.23-oldarchive.patch + +# Fix for bad cooperation of -C and -u options. +# ~> #688567 +# ~> http://lists.gnu.org/archive/html/bug-tar/2012-02/msg00007.html +# ~> still downstream +Patch6: tar-1.26-update-with-change-directory.patch + +# Fix rawhide build failure with undefined gets. +# ~> upstream (gnulib) +Patch7: tar-1.26-stdio.in.patch + +# Fix regression with --keep-old-files option. +# ~> #799252 +# ~> http://lists.gnu.org/archive/html/bug-tar/2011-11/msg00043.html +# ~> upstream (7a5a3708c) +Patch8: tar-1.26-add-skip-old-files-option.patch + +# Prepare included gnulib library for SELinux support. +# -> Related to the next patch. +Patch9: tar-1.26-selinux-gnulib.patch + +# Add support for extended attributes, SELinux and POSIX ACLs. +# ~> Original implementation #200925 +# ~> http://lists.gnu.org/archive/html/bug-tar/2012-08/msg00012.html +# ~> upstream (b997c90f9, 696338043, d36f5a3cc, 085cace18, up-to ~> 83701a590) +Patch10: tar-1.26-xattrs.patch + +# Fix problem with bit UIDs/GIDs (> 2^21) and --posix format. +# ~> #913406 +# ~> upstream (it is part of df7b55a8f6354e) +Patch11: tar-1.26-posix-biguid.patch + +# Allow store sparse files of effective size >8GB into pax archives +# ~> #516309 +# ~> http://lists.gnu.org/archive/html/bug-tar/2013-01/msg00001.html +# ~> already upstream (2f6c03cba) +Patch12: tar-1.26-pax-big-sparse-files.patch + +# Fix: Allow extracting single volume in a multi-volume archive +# ~> #919897 +# ~> http://lists.gnu.org/archive/html/bug-tar/2013-03/msg00002.html +# ~> upstream (beca89bc) +Patch13: tar-1.26-allow-extract-single-volume.patch + +# Do not print xattrs/selinux/acls when --no-xattrs/--no-acls/--no-selinux +# options are used during -tvv output. (TODO: merge this with xattrs patch +# once becomes upstream) +# ~> downstream (yet) +# ~> proposal: http://lists.gnu.org/archive/html/bug-tar/2013-05/msg00020.html +Patch14: tar-1.26-xattrs-printing.patch + +# Use a birthtime instead of ctime. +# ~> upstream (189e43 & 49bd10) +# ~> http://lists.gnu.org/archive/html/bug-tar/2011-06/msg00000.html +# ~> http://lists.gnu.org/archive/html/bug-tar/2013-05/msg00022.html +Patch15: tar-1.26-fix-symlink-eating-bug.patch + +# Add documentation which was not yet pushed upstream +# ~> downstream +# ~> #996753 +Patch16: tar-1.26-docu-xattrs.patch + +# The --xattrs-include or --xattrs-exclude options should imply --xattrs. +# ~> still downstream +# http://lists.gnu.org/archive/html/bug-tar/2013-05/msg00020.html +# ~> #965969 +Patch17: tar-1.26-xattrs-include-implies-xattrs.patch + +# If the 'st_size' != 0 && count(blocks) == 0 && st_size < size(block), this +# does not necessarily must be a sparse file. +# ~> upstream (paxutils): 986382a0bb3261 +# ~> #1024095, #1024268 +Patch18: tar-1.27-sparse-stat-detection.patch + +# Don't add "false" default acls when during extraction (#1220890) +# ~> #1220890 +Patch19: tar-1.26-default-acls.patch + +# Make sure getfilecon's wrapper set's freed pointer to NULL to avoid double +# free later in client code. +# ~> upstream commit (gnulib): b6b3ed1fa4c +# ~> rhbz#1347396 +Patch20: tar-1.26-dont-segfault-with-disabled-selinux.patch + +# Restore incremental backups correctly, files were not being removed +# ~> upstream commits: 738fb9c2f44 b6979c7278e f86e0605d0e +# ~> rhbz#1184697 +Patch21: tar-1.26-restore-incremental-backups.patch + +# Fix the behavior of tar when --directory option is used together with +# --remove-files. +# ~> upstream commits: e3d28d84bda b41b004638f f7077dd38b0 d3fd92c6fb2 +# d28eee6b4f1 74ce228f6df 3125d311e17 3de5db2a151 fc58a8bd984 +# fcde08534bd e6fcc73efa7 +# ~> rhbz#1319820 +Patch22: tar-1.26-directory_with_remove-files.patch + +# Repair the ignorance of --xattrs-exclude/include options +# ~> upstream: bb6ddd8e04c and c81a0853bb8 +# ~> rhbz#1341786 +Patch23: tar-1.26-xattrs-exclude-include-repair.patch + +# Intorduce new option "--keep-directory-symlink", backported from version 1.27 +# ~> upstream: 2c06a809180 +# ~> rhbz#1350640 +Patch24: tar-1.26-keep-directory-symlink.patch + +# Fix non-determinism in archive-type-heuristic +# ~> upstream: 1847ec67cec + 1e8b786e651 +# ~> rhbz#1437297 +Patch25: tar-1.26-non-deterministic-archive-detection.patch + +# Avoid tar to hang with --extract --xatrrs and --skip-old-files options +# ~> upstream: 597b0ae509 and ca9399d4e +# -> proposed: https://www.mail-archive.com/bug-tar@gnu.org/msg05229.html +# ~> rhbz#1408168 +Patch26: tar-1.26-xattrs-skip-old-files-hangs.patch + +# List sparse files of 8GB+ properly, without failure. +# ~> upstream: 586a6263e9d97 ec94fbdf458ad +# ~> paxutils-upstream: 45af1632aa64a 58b8ac114790e +Patch27: tar-1.26-large-sparse-file-listing.patch + +# Document (and test) --keep-directory-option +# ~> upstream: d06126f814563b01e598b85a8cc233604a2948f2 +# ~> rhbz#1504146 +Patch28: tar-1.26-keep-directory-symlink-doc-and-test.patch + +# Silence gcc warnings +# ~> upstream tar: 17f99bc6f, 5bb0433 +# ~> upstream paxutils: 0b3d84a0 +Patch999: tar-1.26-silence-gcc.patch + +# run "make check" by default +%bcond_without check + +BuildRequires: autoconf automake texinfo gettext libacl-devel rsh + +%if %{with check} +# cover needs of tar's testsuite +BuildRequires: attr acl policycoreutils +%endif + +%if %{WITH_SELINUX} +BuildRequires: libselinux-devel +%endif +Provides: bundled(gnulib) +Provides: /bin/tar +Provides: /bin/gtar +Requires(post): /sbin/install-info +Requires(preun): /sbin/install-info + +%description +The GNU tar program saves many files together in one archive and can +restore individual files (or all of the files) from that archive. Tar +can also be used to add supplemental files to an archive and to update +or list files in the archive. Tar includes multivolume support, +automatic archive compression/decompression, the ability to perform +remote archives, and the ability to perform incremental and full +backups. + +If you want to use tar for remote backups, you also need to install +the rmt package on the remote box. + +%prep +%setup -q +%patch1 -p1 -b .loneZeroWarning +%patch2 -p1 -b .vfatTruncate +%patch3 -p1 -b .wildcards +%patch4 -p1 -b .rofs +%patch5 -p1 -b .oldarchive +%patch6 -p1 -b .update_and_changedir +%patch7 -p1 -b .gets %{?_rawbuild} +%patch8 -p1 -b .skip-old-files +%patch9 -p1 -b .selinux-gnulib-prep +%patch10 -p1 -b .xattrs-selinux-acls +%patch11 -p1 -b .big_uid_gid +%patch12 -p1 -b .pax-sparse-big-files +%patch13 -p1 -b .extract-single-volume +%patch14 -p1 -b .print-xattrs-fix +%patch15 -p1 -b .birthtime +%patch16 -p1 -b .xattrs-documentation +%patch17 -p1 -b .xattrs-if-xattrs-include +%patch18 -p1 -b .sparse-stat-detection +%patch19 -p1 -b .default-acls +%patch20 -p1 -b .disabled-selinux +%patch21 -p1 -b .incremental-backups +%patch22 -p1 -b .directory +%patch23 -p1 -b .xattrs-exclude-include +%patch24 -p1 -b .keep-directory-symlink +%patch25 -p1 -b .fix-archive-detection-heuristic +%patch26 -p1 -b .extract-xattrs-hangs +%patch27 -p1 -b .large-sparse-file-listing +%patch28 -p1 -b .test-and-doc-for-keep-dir-symlink +%patch999 -p1 -b .silence-gcc + +autoreconf -v + +%build +%if ! %{WITH_SELINUX} +%global CONFIGURE_SELINUX --without-selinux +%endif + +%configure %{?CONFIGURE_SELINUX} \ + DEFAULT_RMT_DIR=%{_sysconfdir} \ + RSH=/usr/bin/ssh +make + +%install +make DESTDIR=$RPM_BUILD_ROOT install + +ln -s tar $RPM_BUILD_ROOT%{_bindir}/gtar +rm -f $RPM_BUILD_ROOT/%{_infodir}/dir +mkdir -p $RPM_BUILD_ROOT%{_mandir}/man1 +install -c -p -m 0644 %{SOURCE2} $RPM_BUILD_ROOT%{_mandir}/man1 +ln -s tar.1.gz $RPM_BUILD_ROOT%{_mandir}/man1/gtar.1 + +# XXX Nuke unpackaged files. +rm -f $RPM_BUILD_ROOT%{_sysconfdir}/rmt + +%find_lang %name + +%check +%if %{with check} +rm -f $RPM_BUILD_ROOT/test/testsuite +make check || TESTSUITEFLAGS=-v make check +%endif + +%clean +rm -rf $RPM_BUILD_ROOT + +%post +if [ -f %{_infodir}/tar.info.gz ]; then + /sbin/install-info %{_infodir}/tar.info.gz %{_infodir}/dir || : +fi + +%preun +if [ $1 = 0 ]; then + if [ -f %{_infodir}/tar.info.gz ]; then + /sbin/install-info --delete %{_infodir}/tar.info.gz %{_infodir}/dir || : + fi +fi + +%files -f %{name}.lang +%doc AUTHORS ChangeLog ChangeLog.1 COPYING NEWS README THANKS TODO +%{_bindir}/tar +%{_bindir}/gtar +%{_mandir}/man1/tar.1* +%{_mandir}/man1/gtar.1* +%{_infodir}/tar.info* + +%changelog +* Thu Oct 19 2017 Pavel Raiskup - 1.26-34 +- document --keep-directory-symlink in manual page (rhbz#1504146) + +* Thu Sep 07 2017 Pavel Raiskup - 1.26-33 +- extract: deterministic archive type detection (rhbz#1437297) +- avoid hang when extracting with --xattrs --skip-old-files (rhbz#1408168) +- fix listing of large sparse members (rhbz#1347229) + +* Tue Feb 28 2017 Tomas Repik - 2:1.26-32 +- restore incremental backups correctly, files were not being removed (rhbz#1184697) +- fix the behavior of tar when --directory option is used together with + --remove-files +- repair the ignorance of --xattrs-exclude/include options (rhbz#1341786) +- Intorduce new option '--keep-directory-symlink' + +* Mon Jun 20 2016 Pavel Raiskup - 1.26-31 +- avoid double free in selinux code (rhbz#1347396) + +* Thu Jun 04 2015 Pavel Raiskup - 1.26-30 +- don't mistakenly set default ACLs (#1220890) + +* Fri Jan 24 2014 Daniel Mach - 2:1.26-29 +- Mass rebuild 2014-01-24 + +* Fri Dec 27 2013 Daniel Mach - 2:1.26-28 +- Mass rebuild 2013-12-27 + +* Mon Nov 18 2013 Pavel Raiskup - 1.26-27 +- sparse file detection based on fstat() fix (#1024268) + +* Mon Sep 09 2013 Pavel Raiskup - 1.26-26 +- the --xattrs-include implies --xattrs now (#965969) + +* Wed Aug 14 2013 Pavel Raiskup - 1.26-26 +- add documenation for xattrs-like options (#996753) + +* Thu Jun 20 2013 Pavel Raiskup - 1.26-25 +- the /etc/rmt seems to be the best place where to look for rmt binary (see the + commit message in Fedora's cpio.git for more info) + +* Tue Jun 04 2013 Pavel Raiskup - 2:1.26-24 +- fix "symlink eating" bug (already fixed in upstream git) + +* Thu May 30 2013 Pavel Raiskup - 2:1.26-23 +- use /usr/bin/ssh as the default remote shell binary (#969015) +- do not verbose-print xattrs when --no-xattrs option is used +- do not override the config.{guess,sub} twice, this is already done by the + redhat-rpm-config package (#951442) + +* Tue May 28 2013 Pavel Raiskup - 2:1.26-22 +- again search for 'rmt' binary in %%{_sbindir} on target host + +* Tue Mar 26 2013 Pavel Raiskup - 2:1.26-21 +- enable build for arm64 (#926610) +- silence gcc warnings (lint fixes without risk from upstream) for RPMDiff + +* Tue Mar 19 2013 Pavel Raiskup - 2:1.26-20 +- allow extracting single volume from multi-volume archive (#919897) +- usrmove: /bin/tar ~> /usr/bin/tar, selinux handling edit + +* Fri Mar 01 2013 Pavel Raiskup - 2:1.26-19 +- fix creating sparse pax archives containing files of effective + size >8GB (#516309) +- silence rpmlint (fix bad dates in changelog based on git log dates) + +* Wed Feb 20 2013 Pavel Raiskup - 2:1.26-18 +- fix problems with big uids/gids and pax format (> 2^21) (#913406) + +* Mon Feb 18 2013 Pavel Raiskup - 2:1.26-17 +- add possibility to 'rpmbuild' without %%check phase +- make the autoreconf phase verbose +- re-create older patches (avoid offset warnings during patching) +- remove patches which we don't need now (xattrs - will be updated, sigpipe - + test should work now, partial revert of *at() conversion was done because of + incompatible xattr patch) +- add upstream up2date xattr patch + +* Fri Feb 01 2013 Pavel Raiskup - 2:1.26-16 +- make the info documentation more visible in manpage (#903666) +- sync tar.1 manpage with actual --help output (e.g. added --skip-old-files) +- add the last_help2man_run file to git repo to allow more easily find changes + in --help in future +- make the DEFAULTS section to be more visible in man page +- verbose 'make check' only when some fail happened (append to koji build.log) + +* Thu Nov 29 2012 Ondrej Vasik - 2:1.26-15 +- add missing --full-time option to manpage + +* Thu Oct 18 2012 Pavel Raiskup - 2:1.26-14 +- fix bad behaviour of --keep-old-files and add --skip-old-files option + (#799252) + +* Wed Oct 10 2012 Pavel Raiskup 2:1.26-13 +- fix badly written macro for building --without-selinux +- allow to build tar in difference CoverityScan by forcing the '.gets' patch to + be applied even in the run without patches + +* Fri Oct 05 2012 Pavel Raiskup 2:1.26-12 +- repair the xattr-gnulib-prepare patch to allow build tar without SELinux + support +- fedora-review compliance -> remove trailing white-spaces, remove macro from + comment, remove BR of gawk;coreutils;gzip that should be covered automatically + by minimum build environment, do not `rm -rf' buildroot at the beginning of + install phase (needed only in EPEL), remove BuildRoot definition, remove + defattr macro, s/define/global/ +- do not use ${VAR} syntax for bash variables, use just $VAR + +* Wed Aug 22 2012 Pavel Raiskup 2:1.26-11 +- fix manpage to reflect #850291 related commit + +* Tue Aug 21 2012 Pavel Raiskup 2:1.26-10 +- prepare Gnulib for new xattrs (#850291) +- new version of RH xattrs patch (#850291) +- enable verbose mode in testsuite to allow better debugging on error + +* Sat Jul 21 2012 Fedora Release Engineering - 2:1.26-9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Thu Jul 12 2012 Pavel Raiskup 2:1.26-8 +- force the fchown() be called before xattrs_set() (#771927) + +* Sat Jun 16 2012 Ondrej Vasik 2:1.26-7 +- store&restore security.capability extended attributes category + (#771927) +- fix build failure with undefined gets + +* Tue May 15 2012 Ondrej Vasik 2:1.26-6 +- add virtual provides for bundled(gnulib) copylib (#821790) + +* Thu Apr 05 2012 Pavel Raiskup 2:1.26-5 +- fix for bad cooperation of the '-C' (change directory) and '-u' (update + package) options (#688567) + +* Sat Jan 14 2012 Fedora Release Engineering - 2:1.26-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Sun Oct 2 2011 Ville Skyttä - 2:1.26-3 +- Man page heading formatting fixes. + +* Mon Sep 26 2011 Kamil Dudka 2:1.26-2 +- restore basic functionality of --acl, --selinux, and --xattr (#717684) + +* Sat Mar 12 2011 Ondrej Vasik 2:1.26-1 +- new upstream release 1.26 +* Wed Feb 09 2011 Fedora Release Engineering - 2:1.25-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Thu Jan 20 2011 Ondrej Vasik 2:1.25-5 +- drop unnecessary hard dependency on info package(#671157) + +* Mon Jan 03 2011 Ondrej Vasik 2:1.25-4 +- mention that some compression options might not work if + the external program is not available(#666755) + +* Wed Dec 08 2010 Kamil Dudka 2:1.25-3 +- correctly store long sparse file names in PAX archives (#656834) + +* Tue Nov 23 2010 Ondrej Vasik 2:1.25-2 +- fix issue with --one-file-system and --listed-incremental + (#654718) + +* Mon Nov 08 2010 Ondrej Vasik 2:1.25-1 +- new upstream release 1.25 + +* Mon Oct 25 2010 Ondrej Vasik 2:1.24-1 +- new upstream release 1.24, use .xz archive + +* Wed Sep 29 2010 jkeating - 2:1.23-8 +- Rebuilt for gcc bug 634757 + +* Fri Sep 24 2010 Kamil Dudka 2:1.23-7 +- match non-stripped file names (#637085) + +* Mon Sep 20 2010 Kamil Dudka 2:1.23-6 +- fix exclusion of long file names with --xattrs (#634866) +- do not crash with --listed-incremental (#635318) + +* Mon Aug 16 2010 Ondrej Vasik 2:1.23-5 +- add support for security.NTACL xattrs (#621215) + +* Tue Jun 01 2010 Ondrej Vasik 2:1.23-4 +- recognize old-archive/portability options(#594044) + +* Wed Apr 07 2010 Ondrej Vasik 2:1.23-3 +- allow storing of extended attributes for fifo and block + or character devices files(#573147) + +* Mon Mar 15 2010 Ondrej Vasik 2:1.23-2 +- update help2maned manpage + +* Fri Mar 12 2010 Ondrej Vasik 2:1.23-1 +- new upstream release 1.23, remove applied patches + +* Wed Mar 10 2010 Ondrej Vasik 2:1.22-17 +- CVE-2010-0624 tar, cpio: Heap-based buffer overflow + by expanding a specially-crafted archive (#572149) +- realloc within check_exclusion_tags() caused invalid write + (#570591) +- not closing file descriptors for excluded files/dirs with + exlude-tag... options could cause descriptor exhaustion + (#570591) + +* Sat Feb 20 2010 Kamil Dudka 2:1.22-16 +- support for "lustre.*" extended attributes (#561855) + +* Thu Feb 04 2010 Ondrej Vasik 2:1.22-15 +- fix segfault with corrupted metadata in code_ns_fraction + (#531441) + +* Wed Feb 03 2010 Kamil Dudka 2:1.22-14 +- allow also build with SELinux support + +* Mon Feb 01 2010 Ondrej Vasik 2:1.22-13 +- allow build without SELinux support(#556679) + +* Tue Jan 05 2010 Ondrej Vasik 2:1.22-12 +- do not fail with POSIX 2008 glibc futimens() (#552320) +- temporarily disable fix for #531441, causing stack smashing + with newer glibc(#551206) + +* Tue Dec 08 2009 Ondrej Vasik 2:1.22-11 +- fix segfault with corrupted metadata in code_ns_fraction + (#531441) +- commented patches and sources + +* Fri Nov 27 2009 Ondrej Vasik 2:1.22-10 +- store xattrs for symlinks (#525992) - by Kamil Dudka +- update tar(1) manpage (#539787) +- fix memory leak in xheader (#518079) + +* Wed Nov 18 2009 Kamil Dudka 2:1.22-9 +- store SELinux context for symlinks (#525992) + +* Thu Aug 27 2009 Ondrej Vasik 2:1.22-8 +- provide symlink manpage for gtar + +* Thu Aug 06 2009 Ondrej Vasik 2:1.22-7 +- do process install-info only without --excludedocs(#515923) + +* Sun Jul 26 2009 Fedora Release Engineering - 2:1.22-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Thu Jul 16 2009 Ondrej Vasik 2:1.22-5 +- Fix restoring of directory default acls(#511145) +- Do not patch generated autotools files + +* Thu Jun 25 2009 Ondrej Vasik 2:1.22-4 +- Report record size only if the archive refers to a device + (#487760) +- Do not sigabrt with new gcc/glibc because of writing to + struct members of gnutar header at once via strcpy + +* Fri May 15 2009 Ondrej Vasik 2:1.22-3 +- ignore errors from setting utime() for source file + on read-only filesystem (#500742) + +* Fri Mar 06 2009 Kamil Dudka 2:1.22-2 +- improve tar-1.14-loneZeroWarning.patch (#487315) + +* Mon Mar 02 2009 Ondrej Vasik 2:1.22-1 +- New upstream release 1.22, removed applied patch + +* Wed Feb 25 2009 Fedora Release Engineering - 2:1.21-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Mon Jan 05 2009 Ondrej Vasik 2:1.21-1 +- New upstream release 1.21, removed applied patches +- add support for -I option, fix testsuite failure + +* Thu Dec 11 2008 Ondrej Vasik 2:1.20-6 +- add BuildRequires for rsh (#475950) + +* Fri Nov 21 2008 Ondrej Vasik 2:1.20-5 +- fix off-by-one errors in xattrs patch (#472355) + +* Mon Nov 10 2008 Kamil Dudka 2:1.20-4 +- fixed bug #465803: labels with --multi-volume (upstream patch) + +* Fri Oct 10 2008 Ondrej Vasik 2:1.20-3 +- Fixed wrong documentation for xattrs options (#466517) +- fixed bug with null file terminator and change dirs + (upstream) + +* Fri Aug 29 2008 Ondrej Vasik 2:1.20-2 +- patch fuzz clean up + +* Mon May 26 2008 Ondrej Vasik 2:1.20-1 +- new upstream release 1.20 (lzma support, few new options + and bugfixes) +- heavily modified xattrs patches(as tar-1.20 now uses automake + 1.10.1) + +* Tue Feb 12 2008 Radek Brich 2:1.19-3 +- do not print getfilecon/setfilecon warnings when SELinux is disabled + or SELinux data are not available (bz#431879) +- fix for GCC 4.3 + +* Mon Jan 21 2008 Radek Brich 2:1.19-2 +- fix errors in man page + * fix definition of --occurrence (bz#416661, patch by Jonathan Wakely) + * update meaning of -l: it has changed from --one-filesystem + to --check-links (bz#426717) +- update license tag, tar 1.19 is GPLv3+ + +* Mon Dec 17 2007 Radek Brich 2:1.19-1 +- upgrade to 1.19 +- updated xattrs patch, removed 3 upstream patches + +* Wed Dec 12 2007 Radek Brich 2:1.17-5 +- fix (non)detection of xattrs +- move configure stuff from -xattrs patch to -xattrs-conf, + so the original patch could be easily read +- fix -xattrs patch to work with zero length files and show + warnings when xattrs not available (fixes by James Antill) +- possible corruption (#408621) - add warning to man page + for now, may be actually fixed later, depending on upstream + +* Tue Oct 23 2007 Radek Brich 2:1.17-4 +- upstream patch for CVE-2007-4476 + (tar stack crashing in safer_name_suffix) + +* Tue Aug 28 2007 Radek Brich 2:1.17-3 +- gawk build dependency + +* Tue Aug 28 2007 Radek Brich 2:1.17-2 +- updated license tag +- fixed CVE-2007-4131 tar directory traversal vulnerability (#251921) + +* Thu Jun 28 2007 Radek Brich 2:1.17-1 +- new upstream version +- patch for wildcards (#206841), restoring old behavior +- patch for testsuite +- update -xattrs patch +- drop 13 obsolete patches + +* Tue Feb 06 2007 Peter Vrabec 2:1.15.1-26 +- fix spec file to meet Fedora standards (#226478) + +* Mon Jan 22 2007 Peter Vrabec 2:1.15.1-25 +- fix non-failsafe install-info use in scriptlets (#223718) + +* Wed Jan 03 2007 Peter Vrabec 2:1.15.1-24 +- supply tar man page (#219375) + +* Tue Dec 12 2006 Florian La Roche 2:1.15.1-23 +- fix CVE-2006-6097 GNU tar directory traversal (#216937) + +* Sun Dec 10 2006 Peter Vrabec 2:1.15.1-22 +- fix some rpmlint spec file issues + +* Wed Oct 25 2006 Peter Vrabec 2:1.15.1-21 +- build with dist-tag + +* Mon Oct 09 2006 Peter Vrabec 2:1.15.1-20 +- another fix of tar-1.15.1-xattrs.patch from James Antill + +* Wed Oct 04 2006 Peter Vrabec 2:1.15.1-19 +- another fix of tar-1.15.1-xattrs.patch from James Antill + +* Sun Oct 01 2006 Peter Vrabec 2:1.15.1-18 +- fix tar-1.15.1-xattrs.patch (#208701) + +* Tue Sep 19 2006 Peter Vrabec 2:1.15.1-17 +- start new epoch, downgrade to solid stable 1.15.1-16 (#206979), +- all patches are backported + +* Tue Sep 19 2006 Peter Vrabec 1.15.91-2 +- apply patches, which were forgotten during upgrade + +* Wed Sep 13 2006 Peter Vrabec 1.15.91-1 +- upgrade, which also fix incremental backup (#206121) + +* Fri Sep 08 2006 Peter Vrabec 1.15.90-7 +- fix tar-debuginfo package (#205615) + +* Thu Aug 10 2006 Peter Vrabec 1.15.90-6 +- add xattr support (#200925), patch from james.antill@redhat.com + +* Mon Jul 24 2006 Peter Vrabec 1.15.90-5 +- fix incompatibilities in appending files to the end + of an archive (#199515) + +* Tue Jul 18 2006 Peter Vrabec 1.15.90-4 +- fix problem with unpacking archives in a directory for which + one has write permission but does not own (such as /tmp) (#149686) + +* Wed Jul 12 2006 Jesse Keating - 1.15.90-3.1 +- rebuild + +* Thu Jun 29 2006 Peter Vrabec 1.15.90-3 +- fix typo in tar.1 man page + +* Tue Apr 25 2006 Peter Vrabec 1.15.90-2 +- exclude listed02.at from testsuite again, because it + still fails on s390 + +* Tue Apr 25 2006 Peter Vrabec 1.15.90-1 +- upgrade + +* Mon Apr 24 2006 Peter Vrabec 1.15.1-16 +- fix problem when options at the end of command line were + not recognized (#188707) + +* Thu Apr 13 2006 Peter Vrabec 1.15.1-15 +- fix segmentation faul introduced with hugeSparse.patch + +* Wed Mar 22 2006 Peter Vrabec 1.15.1-14 +- fix problems with extracting large sparse archive members (#185460) + +* Fri Feb 17 2006 Peter Vrabec 1.15.1-13 +- fix heap overlfow bug CVE-2006-0300 (#181773) + +* Fri Feb 10 2006 Jesse Keating - 1.15.1-12.2 +- bump again for double-long bug on ppc(64) + +* Tue Feb 07 2006 Jesse Keating - 1.15.1-12.1 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Mon Feb 06 2006 Peter Vrabec 1.15.1-12 +- fix extracting sparse files to a filesystem like vfat, + when ftruncate may fail to grow the size of a file.(#179507) + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Fri Nov 04 2005 Peter Vrabec 1.15.1-11 +- correctly pad archive members that shrunk during archiving (#172373) + +* Tue Sep 06 2005 Peter Vrabec 1.15.1-10 +- provide man page (#163709, #54243, #56041) + +* Mon Aug 15 2005 Peter Vrabec 1.15.1-9 +- silence newer option (#164902) + +* Wed Jul 27 2005 Peter Vrabec 1.15.1-8 +- A file is dumpable if it is sparse and both --sparse + and --totals are specified (#154882) + +* Tue Jul 26 2005 Peter Vrabec 1.15.1-7 +- exclude listed02.at from testsuite + +* Fri Jul 22 2005 Peter Vrabec 1.15.1-6 +- remove tar-1.14-err.patch, not needed (158743) + +* Fri Apr 15 2005 Peter Vrabec 1.15.1-5 +- extract sparse files even if the output fd is not seekable.(#154882) +- (sparse_scan_file): Bugfix. offset had incorrect type. + +* Mon Mar 14 2005 Peter Vrabec +- gcc4 fix (#150993) 1.15.1-4 + +* Mon Jan 31 2005 Peter Vrabec +- rebuild 1.15.1-3 + +* Mon Jan 17 2005 Peter Vrabec +- fix tests/testsuite + +* Fri Jan 07 2005 Peter Vrabec +- upgrade to 1.15.1 + +* Mon Oct 11 2004 Peter Vrabec +- patch to stop issuing lone zero block warnings +- rebuilt + +* Mon Oct 11 2004 Peter Vrabec +- URL added to spec file +- spec file clean up + +* Tue Jun 15 2004 Elliot Lee +- rebuilt + +* Mon Jun 7 2004 Jeff Johnson 1.14-1 +- upgrade to 1.14. + +* Fri Feb 13 2004 Elliot Lee +- rebuilt + +* Tue Jun 17 2003 Jeff Johnson 1.13.25-13 +- rebuilt because of crt breakage on ppc64. +- dump automake15 requirement. + +* Wed Jun 04 2003 Elliot Lee +- rebuilt + +* Wed Jan 22 2003 Tim Powers +- rebuilt + +* Fri Nov 29 2002 Tim Powers 1.13.25-10 +- fix broken buildrquires on autoconf253 + +* Thu Nov 7 2002 Jeff Johnson 1.13.25-9 +- rebuild from CVS. + +* Fri Aug 23 2002 Phil Knirsch 1.13.25-8 +- Included security patch from errata release. + +* Mon Jul 1 2002 Bernhard Rosenkraenzer 1.13.25-7 +- Fix argv NULL termination (#64869) + +* Thu May 23 2002 Tim Powers +- automated rebuild + +* Tue Apr 9 2002 Bernhard Rosenkraenzer 1.13.25-4 +- Fix build with autoconf253 (LIBOBJ change; autoconf252 worked) + +* Wed Jan 09 2002 Tim Powers +- automated rebuild + +* Tue Oct 23 2001 Bernhard Rosenkraenzer 1.13.25-2 +- Don't include hardlinks to sockets in a tar file (#54827) + +* Thu Sep 27 2001 Bernhard Rosenkraenzer 1.13.25-1 +- 1.13.25 + +* Tue Sep 18 2001 Bernhard Rosenkraenzer 1.13.22-1 +- Update to 1.13.22, adapt patches + +* Mon Aug 27 2001 Bernhard Rosenkraenzer 1.13.19-6 +- Fix #52084 + +* Thu May 17 2001 Bernhard Rosenkraenzer 1.13.19-5 +- Fix build with current autoconf (stricter checking on AC_DEFINE) +- Fix segfault when tarring directories without having read permissions + (#40802) + +* Tue Mar 6 2001 Bernhard Rosenkraenzer +- Don't depend on librt. + +* Fri Feb 23 2001 Trond Eivind Glomsröd +- langify + +* Thu Feb 22 2001 Bernhard Rosenkraenzer +- Fix up the man page (#28915) + +* Wed Feb 21 2001 Bernhard Rosenkraenzer +- 1.3.19, nukes -I and fixes up -N +- Add -I back in as an alias to -j with a nice loud warning + +* Mon Oct 30 2000 Bernhard Rosenkraenzer +- 1.3.18 +- Update man page to reflect changes + +* Thu Oct 5 2000 Bernhard Rosenkraenzer +- Fix the "ignore failed read" option (Bug #8330) + +* Mon Sep 25 2000 Bernhard Rosenkraenzer +- fix hang on tar tvzf - + +* Fri Aug 18 2000 Bernhard Rosenkraenzer +- really fix exit code (Bug #15448) + +* Mon Aug 7 2000 Bernhard Rosenkraenzer +- fix exit code (Bug #15448), patch from Tim Waugh + +* Wed Jul 12 2000 Prospector +- automatic rebuild + +* Mon Jun 19 2000 Bernhard Rosenkraenzer +- FHSify + +* Fri Apr 28 2000 Bill Nottingham +- fix for ia64 + +* Wed Feb 9 2000 Bernhard Rosenkränzer +- Fix the exclude bug (#9201) + +* Wed Feb 02 2000 Cristian Gafton +- man pages are compressed +- fix description +- fix fnmatch build problems + +* Sun Jan 9 2000 Bernhard Rosenkränzer +- 1.13.17 +- remove dotbug patch (fixed in base) +- update download URL + +* Fri Jan 7 2000 Bernhard Rosenkränzer +- Fix a severe bug (tar xf any_package_containing_. would delete the + current directory) + +* Wed Jan 5 2000 Bernhard Rosenkränzer +- 1.3.16 +- unset LINGUAS before running configure + +* Tue Nov 9 1999 Bernhard Rosenkränzer +- 1.13.14 +- Update man page to know about -I / --bzip +- Remove dependancy on rmt - tar can be used for anything local + without it. + +* Fri Aug 27 1999 Preston Brown +- upgrade to 1.13.11. + +* Wed Aug 18 1999 Jeff Johnson +- update to 1.13.9. + +* Thu Aug 12 1999 Jeff Johnson +- update to 1.13.6. +- support -y --bzip2 options for bzip2 compression (#2415). + +* Fri Jul 23 1999 Jeff Johnson +- update to 1.13.5. + +* Tue Jul 13 1999 Bill Nottingham +- update to 1.13 + +* Sat Jun 26 1999 Jeff Johnson +- update to 1.12.64014. +- pipe patch corrected for remote tars now merged in. + +* Sun Jun 20 1999 Jeff Johnson +- update to tar-1.12.64013. +- subtract (and reopen #2415) bzip2 support using -y. +- move gtar to /bin. + +* Tue Jun 15 1999 Jeff Johnson +- upgrade to tar-1.12.64011 to +- add bzip2 support (#2415) +- fix filename bug (#3479) + +* Mon Mar 29 1999 Jeff Johnson +- fix suspended tar with compression over pipe produces error (#390). + +* Sun Mar 21 1999 Cristian Gafton +- auto rebuild in the new build environment (release 8) + +* Mon Mar 08 1999 Michael Maher +- added patch for bad name cache. +- FIXES BUG 320 + +* Wed Feb 24 1999 Preston Brown +- Injected new description and group. + +* Fri Dec 18 1998 Preston Brown +- bumped spec number for initial rh 6.0 build + +* Tue Aug 4 1998 Jeff Johnson +- add /usr/bin/gtar symlink (change #421) + +* Tue Jul 14 1998 Jeff Johnson +- Fiddle bindir/libexecdir to get RH install correct. +- Don't include /sbin/rmt -- use the rmt from dump. +- Turn on nls. + +* Mon Apr 27 1998 Prospector System +- translations modified for de, fr, tr + +* Thu Oct 16 1997 Donnie Barnes +- updated from 1.11.8 to 1.12 +- various spec file cleanups +- /sbin/install-info support + +* Thu Jun 19 1997 Erik Troan +- built against glibc + +* Thu May 29 1997 Michael Fulbright +- Fixed to include rmt