06e0a0b140
Version: 2:1.26-17
3234 lines
96 KiB
Diff
3234 lines
96 KiB
Diff
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 <bug-tar@gnu.org>
|
||
|
||
|
||
@@ -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 <attr/xattr.h>, 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 <attr/xattr.h> 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 <grp.h>])
|
||
AC_CHECK_DECLS([getpwuid],,, [#include <pwd.h>])
|
||
AC_CHECK_DECLS([time],,, [#include <time.h>])
|
||
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 <attr/xattr.h> 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 <http://www.gnu.org/licenses/>. */
|
||
+
|
||
+#ifndef TAR_ATTR_XATTR_H
|
||
+#define TAR_ATTR_XATTR_H
|
||
+#include <errno.h>
|
||
+
|
||
+/* 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 <http://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <config.h>
|
||
+
|
||
+#include "xattr-at.h"
|
||
+#include "openat.h"
|
||
+
|
||
+#include <stdlib.h>
|
||
+#include <unistd.h>
|
||
+#include <errno.h>
|
||
+#include <fcntl.h>
|
||
+
|
||
+#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 <http://www.gnu.org/licenses/>. */
|
||
+
|
||
+#ifndef XATTRS_AT_H
|
||
+#define XATTRS_AT_H
|
||
+
|
||
+#include <sys/types.h>
|
||
+#include <attr/xattr.h>
|
||
+
|
||
+/* 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 <config.h>
|
||
+#include <system.h>
|
||
+
|
||
+#include <fnmatch.h>
|
||
+#include <quotearg.h>
|
||
+
|
||
+#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 <sys/acl.h>
|
||
+#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 <http://www.gnu.org/licenses/>.
|
||
+#
|
||
+# 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 <http://www.gnu.org/licenses/>.
|
||
+#
|
||
+# 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 <http://www.gnu.org/licenses/>.
|
||
+#
|
||
+# 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 <http://www.gnu.org/licenses/>.
|
||
+#
|
||
+# 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 <http://www.gnu.org/licenses/>.
|
||
+#
|
||
+# 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 <http://www.gnu.org/licenses/>.
|
||
+#
|
||
+# 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 <http://www.gnu.org/licenses/>.
|
||
+#
|
||
+# 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 <http://www.gnu.org/licenses/>.
|
||
+#
|
||
+# 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 <http://www.gnu.org/licenses/>.
|
||
+#
|
||
+# 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 <http://www.gnu.org/licenses/>.
|
||
+#
|
||
+# 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
|