From d36f5a3cc3280d6c4a58367bf51b527d5c14ac04 Mon Sep 17 00:00:00 2001 From: Pavel Raiskup Date: Sun, 18 Nov 2012 20:54:02 +0200 Subject: [PATCH] Support for POSIX ACLs * configure.ac: Check whether ACLs are available on the host system. * gnulib.modules: Add acl * src/create.c (start_header): Store ACLs when creating a POSIX archive. (dump_file0): Handle ACLs. * src/extract.c (delayed_set_stat) : New members. (delayed_link): Likewise. (set_stat,delay_set_stat) (apply_nonancestor_delayed_set_stat): Set ACLs. * src/tar.c: New options: "--acls", "--no-acls" (tar_stat_destroy): Free acls_a_ptr and acls_d_ptr fields. * src/tar.h (tar_stat_info) : New members. * src/xattrs.c (xattrs_acls_get, xattrs_acls_set): New functions. * src/xheader.c: Support new keywors: "SCHILY.acl.access" and "SCHILY.acl.default". * tests/Makefile.am: Add new tests. * tests/testsuite.at: Likewise. * tests/acls01.at: New test. * tests/acls02.at: New test. --- configure.ac | 20 ++++ gnulib.modules | 1 + src/create.c | 11 ++ src/extract.c | 45 ++++++++ src/tar.c | 26 ++++- src/tar.h | 7 ++ src/xattrs.c | 327 ++++++++++++++++++++++++++++++++++++++++++++++++++++- src/xheader.c | 43 +++++++ tests/Makefile.am | 2 + tests/acls01.at | 53 +++++++++ tests/acls02.at | 59 ++++++++++ tests/testsuite.at | 33 ++++-- 12 files changed, 617 insertions(+), 10 deletions(-) create mode 100644 tests/acls01.at create mode 100644 tests/acls02.at diff --git a/configure.ac b/configure.ac index 77976be5..3e501a82 100644 --- a/configure.ac +++ b/configure.ac @@ -93,6 +93,26 @@ tar_PAXUTILS TAR_HEADERS_ATTR_XATTR_H AC_CHECK_FUNCS_ONCE([fchmod fchown fsync lstat mkfifo readlink symlink]) + +# we use gnulib's acl.h - because of very useful file_has_acl() function. M4 +# file from gnulib/acl does a quite good job of course. The problem is that +# this function works on wide list of platforms and we need to 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]) +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 + AC_CHECK_DECLS([getgrgid],,, [#include ]) AC_CHECK_DECLS([getpwuid],,, [#include ]) AC_CHECK_DECLS([time],,, [#include ]) diff --git a/gnulib.modules b/gnulib.modules index 9e7a05a5..7ecdd20a 100644 --- a/gnulib.modules +++ b/gnulib.modules @@ -1,6 +1,7 @@ # List of gnulib modules needed for GNU tar. # A module name per line. Empty lines and comments are ignored. +acl alloca argmatch argp diff --git a/src/create.c b/src/create.c index 034639b8..37a58089 100644 --- a/src/create.c +++ b/src/create.c @@ -946,6 +946,13 @@ start_header (struct tar_stat_info *st) 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 (xattrs_option > 0) { size_t scan_xattr = 0; @@ -1734,6 +1741,7 @@ 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_xattrs_get (parentfd, name, st, fd); if (is_dir) @@ -1876,16 +1884,19 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p) else if (S_ISCHR (st->stat.st_mode)) { type = CHRTYPE; + xattrs_acls_get (parentfd, name, st, 0, true); xattrs_xattrs_get (parentfd, name, st, 0); } else if (S_ISBLK (st->stat.st_mode)) { type = BLKTYPE; + xattrs_acls_get (parentfd, name, st, 0, true); xattrs_xattrs_get (parentfd, name, st, 0); } else if (S_ISFIFO (st->stat.st_mode)) { type = FIFOTYPE; + xattrs_acls_get (parentfd, name, st, 0, true); xattrs_xattrs_get (parentfd, name, st, 0); } else if (S_ISSOCK (st->stat.st_mode)) diff --git a/src/extract.c b/src/extract.c index 2d8e1759..51a5ff0c 100644 --- a/src/extract.c +++ b/src/extract.c @@ -100,6 +100,10 @@ struct delayed_set_stat int change_dir; /* extended attributes*/ + 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. */ @@ -142,6 +146,12 @@ struct delayed_link hard-linked together. */ struct string_list *sources; + /* 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; @@ -375,6 +385,7 @@ set_stat (char const *file_name, /* 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); } /* For each entry H in the leading prefix of entries in HEAD that do @@ -446,6 +457,26 @@ 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; + 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 @@ -794,6 +825,10 @@ 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.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, @@ -803,6 +838,8 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_links) delayed_set_stat_head = data->next; xheader_xattr_free (data->xattr_map, data->xattr_map_size); + free (data->acls_a_ptr); + free (data->acls_d_ptr); free (data); } } @@ -1173,6 +1210,10 @@ 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->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); @@ -1609,6 +1650,10 @@ apply_delayed_links (void) st1.stat.st_gid = ds->gid; st1.atime = ds->atime; st1.mtime = ds->mtime; + 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, diff --git a/src/tar.c b/src/tar.c index c9768207..e3f82f12 100644 --- a/src/tar.c +++ b/src/tar.c @@ -256,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, @@ -289,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, @@ -547,6 +549,10 @@ static struct argp_option options[] = { 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 }, + {"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 @@ -2169,6 +2175,15 @@ 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 XATTR_OPTION: set_archive_format ("posix"); xattrs_option = 1; @@ -2564,7 +2579,12 @@ decode_options (int argc, char **argv) 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 when reading */ + 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 ((xattrs_option > 0) && archive_format != POSIX_FORMAT && !READ_LIKE_SUBCOMMAND) @@ -2829,6 +2849,8 @@ tar_stat_destroy (struct tar_stat_info *st) free (st->link_name); free (st->uname); free (st->gname); + 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 7a80e87b..a9671df3 100644 --- a/src/tar.h +++ b/src/tar.h @@ -296,6 +296,13 @@ struct tar_stat_info char *uname; /* user name of owner */ char *gname; /* group name of owner */ + + 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 diff --git a/src/xattrs.c b/src/xattrs.c index e813d538..a3f0b5f5 100644 --- a/src/xattrs.c +++ b/src/xattrs.c @@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include #include #include @@ -43,6 +44,318 @@ static struct struct xattrs_mask_map excl; } xattrs_setup; +/* disable posix acls when problem found in gnulib script m4/acl.m4 */ +#if ! USE_ACL +# undef HAVE_POSIX_ACLS +#endif + +#ifdef HAVE_POSIX_ACLS +# include "acl.h" +# include +#endif + +#ifdef HAVE_POSIX_ACLS + +/* acl-at wrappers, TODO: move to gnulib in future? */ +acl_t acl_get_file_at (int dirfd, const char *file, acl_type_t type); +int acl_set_file_at (int dirfd, const char *file, acl_type_t type, acl_t acl); +int file_has_acl_at (int dirfd, char const *, struct stat const *); + +/* acl_get_file_at */ +#define AT_FUNC_NAME acl_get_file_at +#define AT_FUNC_RESULT acl_t +#define AT_FUNC_FAIL (acl_t)NULL +#define AT_FUNC_F1 acl_get_file +#define AT_FUNC_POST_FILE_PARAM_DECLS , acl_type_t type +#define AT_FUNC_POST_FILE_ARGS , type +#include "at-func.c" +#undef AT_FUNC_NAME +#undef AT_FUNC_F1 +#undef AT_FUNC_RESULT +#undef AT_FUNC_FAIL +#undef AT_FUNC_POST_FILE_PARAM_DECLS +#undef AT_FUNC_POST_FILE_ARGS + +/* acl_set_file_at */ +#define AT_FUNC_NAME acl_set_file_at +#define AT_FUNC_F1 acl_set_file +#define AT_FUNC_POST_FILE_PARAM_DECLS , acl_type_t type, acl_t acl +#define AT_FUNC_POST_FILE_ARGS , type, acl +#include "at-func.c" +#undef AT_FUNC_NAME +#undef AT_FUNC_F1 +#undef AT_FUNC_POST_FILE_PARAM_DECLS +#undef AT_FUNC_POST_FILE_ARGS + +/* gnulib file_has_acl_at */ +#define AT_FUNC_NAME file_has_acl_at +#define AT_FUNC_F1 file_has_acl +#define AT_FUNC_POST_FILE_PARAM_DECLS , struct stat const *st +#define AT_FUNC_POST_FILE_ARGS , st +#include "at-func.c" +#undef AT_FUNC_NAME +#undef AT_FUNC_F1 +#undef AT_FUNC_POST_FILE_PARAM_DECLS +#undef AT_FUNC_POST_FILE_ARGS + +/* convert unix permissions into an ACL ... needed due to "default" ACLs */ +static acl_t perms2acl (int perms) +{ + char val[] = "user::---,group::---,other::---"; + /* 0123456789 123456789 123456789 123456789 */ + + /* user */ + if (perms & 0400) val[ 6] = 'r'; + if (perms & 0200) val[ 7] = 'w'; + if (perms & 0100) val[ 8] = 'x'; + + /* group */ + if (perms & 0040) val[17] = 'r'; + if (perms & 0020) val[18] = 'w'; + if (perms & 0010) val[19] = 'x'; + + /* other */ + if (perms & 0004) val[28] = 'r'; + if (perms & 0002) val[29] = 'w'; + if (perms & 0001) val[30] = 'x'; + + return (acl_from_text (val)); +} + +static char *skip_to_ext_fields (char *ptr) +{ + ptr += strcspn (ptr, ":,\n"); /* skip tag name. Ie. user/group/default/mask */ + + if (*ptr != ':') + return (ptr); /* error? no user/group field */ + ++ptr; + + ptr += strcspn (ptr, ":,\n"); /* skip user/group name */ + + if (*ptr != ':') + return (ptr); /* error? no perms field */ + ++ptr; + + ptr += strcspn (ptr, ":,\n"); /* skip perms */ + + if (*ptr != ':') + return (ptr); /* no extra fields */ + + 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. + We just skip all extra fields atm. */ +static const char *fixup_extra_acl_fields (const char *ptr) +{ + char *src = (char *)ptr; + char *dst = (char *)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; +} + +static void xattrs__acls_set (struct tar_stat_info const *st, + char const *file_name, int type, + const char *ptr, size_t len, bool def) +{ /* "system.posix_acl_access" */ + 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 == (acl_t)NULL) + { + 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) +{ /* "system.posix_acl_access" */ + char *val = NULL; + ssize_t len; + acl_t acl; + + if ((acl = acl_get_file_at (parentfd, file_name, ACL_TYPE_ACCESS)) + == (acl_t)NULL) + { + if (errno != ENOTSUP) + call_arg_warn ("acl_get_file_at", file_name); + return; + } + + val = acl_to_text (acl, &len); + acl_free (acl); + + if (val == NULL) + { + call_arg_warn ("acl_to_text", file_name); + return; + } + + *ret_ptr = xstrdup (val); + *ret_len = len; + + acl_free (val); +} + +static void xattrs__acls_get_d (int parentfd, char const *file_name, + struct tar_stat_info *st, + char **ret_ptr, size_t *ret_len) +{ /* "system.posix_acl_default" */ + char *val = NULL; + ssize_t len; + acl_t acl; + + if ((acl = acl_get_file_at (parentfd, file_name, ACL_TYPE_DEFAULT)) + == (acl_t)NULL) + { + if (errno != ENOTSUP) + call_arg_warn ("acl_get_file_at", file_name); + return; + } + + val = acl_to_text (acl, &len); + acl_free (acl); + + if (val == NULL) + { + 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; + obstack_init (&stk); + int pref_len = strlen (prefix); + const char *oldstring = aclstring; + + if (!aclstring || !len) + return; + + int pos = 0; + 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'); + const char *toprint = obstack_finish (&stk); + + fprintf (stdlis, "%s", toprint); + + 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->size == 0) @@ -276,7 +589,7 @@ void xattrs_print_char (struct tar_stat_info const *st, char *output) return; } - if (xattrs_option > 0) + if (xattrs_option > 0 || acls_option > 0) { /* placeholders */ *output = ' '; @@ -292,6 +605,9 @@ void xattrs_print_char (struct tar_stat_info const *st, char *output) *output = '*'; break; } + + if (acls_option && (st->acls_a_len || st->acls_d_len)) + *output = '+'; } void xattrs_print (struct tar_stat_info const *st) @@ -299,6 +615,15 @@ void xattrs_print (struct tar_stat_info const *st) if (verbose_option < 3) return; + /* 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) { diff --git a/src/xheader.c b/src/xheader.c index 061d4488..6141748a 100644 --- a/src/xheader.c +++ b/src/xheader.c @@ -464,6 +464,11 @@ 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; } void xheader_xattr_free (struct xattr_array *xattr_map, size_t xattr_map_size) @@ -1548,6 +1553,37 @@ volume_filename_decoder (struct tar_stat_info *st, { decode_string (&continued_file_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) @@ -1667,6 +1703,13 @@ struct xhdr_tab const xhdr_tab[] = { { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder, XHDR_PROTECTED | XHDR_GLOBAL, 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. */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 3d870f10..e97c5086 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -178,6 +178,8 @@ TESTSUITE_AT = \ xattr02.at\ xattr03.at\ xattr04.at\ + acls01.at\ + acls02.at\ capabs_raw01.at TESTSUITE = $(srcdir)/testsuite diff --git a/tests/acls01.at b/tests/acls01.at new file mode 100644 index 00000000..0149f2de --- /dev/null +++ b/tests/acls01.at @@ -0,0 +1,53 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# +# Test suite for GNU tar. +# Copyright (C) 2011 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Test description: +# +# This is basic test for acl support. + +AT_SETUP([acls: basic functionality]) +AT_KEYWORDS([xattrs acls acls01]) + +AT_TAR_CHECK([ +AT_XATTRS_UTILS_PREREQ +AT_ACLS_PREREQ + +mkdir dir +genfile --file dir/file + +MYNAME=$( id -un ) + +setfacl -m u:$MYNAME:--x dir/file +setfacl -m u:$MYNAME:--x dir + +getfattr -h -m. -d dir dir/file > before + +tar --acls -cf archive.tar dir +rm -rf dir + +tar --acls -xf archive.tar + +getfattr -h -m. -d dir dir/file > after + +diff before after +test "$?" = 0 +], +[0], +[]) + +AT_CLEANUP diff --git a/tests/acls02.at b/tests/acls02.at new file mode 100644 index 00000000..2ee1c5fc --- /dev/null +++ b/tests/acls02.at @@ -0,0 +1,59 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# +# Test suite for GNU tar. +# Copyright (C) 2011 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Test description: +# +# This is basic test for acl support. + +AT_SETUP([acls: work with -C]) +AT_KEYWORDS([xattrs acls acls02]) + +AT_TAR_CHECK([ +AT_XATTRS_UTILS_PREREQ +AT_ACLS_PREREQ + +mkdir dir +mkdir dir/subdir +genfile --file dir/subdir/file + +MYNAME=$( id -un ) + +setfacl -m u:$MYNAME:--x dir/subdir +setfacl -m u:$MYNAME:--x dir/subdir/file + +cd dir +getfattr -h -m. -d subdir subdir/file > ../before +cd .. + +tar --acls -cf archive.tar -C dir subdir +rm -rf dir + +mkdir dir +tar --acls -xf archive.tar -C dir + +cd dir +getfattr -h -m. -d subdir subdir/file > ../after +cd .. + +diff before after +test "$?" = 0 +], +[0], +[]) + +AT_CLEANUP diff --git a/tests/testsuite.at b/tests/testsuite.at index 7221ddb9..2a65cd33 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -1,7 +1,7 @@ # Process this file with autom4te to create testsuite. -*- Autotest -*- # Test suite for GNU tar. -# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010, 2012 Free Software +# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010, 2011, 2012 Free Software # Foundation, Inc. # This program is free software; you can redistribute it and/or modify @@ -130,6 +130,12 @@ m4_define([AT_XATTRS_UTILS_PREREQ],[ AT_CHECK_UTIL(setfattr -n user.test -v test $file,0) AT_CHECK_UTIL(getfattr $file,0) ]) +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) @@ -146,6 +152,15 @@ m4_define([AT_XATTRS_PREREQ],[ AT_SKIP_TEST fi ]) +m4_define([AT_ACLS_PREREQ],[ + AT_XATTRS_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]) @@ -305,6 +320,16 @@ 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([acls01.at]) +m4_include([acls02.at]) + +m4_include([capabs_raw01.at]) + m4_include([star/gtarfail.at]) m4_include([star/gtarfail2.at]) @@ -315,9 +340,3 @@ m4_include([star/ustar-big-8g.at]) m4_include([star/pax-big-10g.at]) -m4_include([xattr01.at]) -m4_include([xattr02.at]) -m4_include([xattr03.at]) -m4_include([xattr04.at]) - -m4_include([capabs_raw01.at]) -- 2.11.4.GIT