|
|
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
|
|
|
|