]> Dogcows Code - chaz/tar/commitdiff
Support for POSIX ACLs
authorPavel Raiskup <praiskup@redhat.com>
Sun, 18 Nov 2012 18:54:02 +0000 (20:54 +0200)
committerSergey Poznyakoff <gray@gnu.org.ua>
Sun, 18 Nov 2012 18:54:02 +0000 (20:54 +0200)
* 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) <acls_a_ptr, acls_a_len>
<acls_d_ptr, acls_d_len>: 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) <acls_a_ptr, acls_a_len>
<acls_d_ptr, acls_d_len>: 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.

12 files changed:
configure.ac
gnulib.modules
src/create.c
src/extract.c
src/tar.c
src/tar.h
src/xattrs.c
src/xheader.c
tests/Makefile.am
tests/acls01.at [new file with mode: 0644]
tests/acls02.at [new file with mode: 0644]
tests/testsuite.at

index 77976be5095598682bbb9008d1748059667bde0a..3e501a82d091da4ce56f6a6b378f00e30846bb75 100644 (file)
@@ -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 <grp.h>])
 AC_CHECK_DECLS([getpwuid],,, [#include <pwd.h>])
 AC_CHECK_DECLS([time],,, [#include <time.h>])
index 9e7a05a52c88161a9dd19d158d3eeb63252e1053..7ecdd20ae17848307a458c5a82bc54a7a45b121a 100644 (file)
@@ -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
index 034639b864b1e48fed6df4a22c4e91b62cdec4a7..37a58089d6ffcfb6385e5d5c7384e1b9f9765f18 100644 (file)
@@ -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))
index 2d8e175985e2cb0d9b2719f305628884e81b47fd..51a5ff0ced4301ddf0c92711763d74bae215deec 100644 (file)
@@ -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 (&current_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,
index c97682076fce244dcd987b4da4656f502c0b2b4a..e3f82f123e791803da0af9c6e8807e07c3525893 100644 (file)
--- 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);
index 7a80e87b0844367d04aa04700e838821b2380aba..a9671df370f94bfeb4f485cd6509e05fa128cd63 100644 (file)
--- 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
index e813d5388ad5c2048d8567eca198995a8e4fdbf8..a3f0b5f5b8740f5e43b822bfa6a5949ad571f711 100644 (file)
@@ -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 <config.h>
 #include <system.h>
 
 #include <fnmatch.h>
@@ -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 <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)
+{
+  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)
     {
index 061d44887d554dc2aff893f20075ad1e556b4d56..6141748a7228dc01d4f1272147f340fb5857b358 100644 (file)
@@ -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. */
index 3d870f10e1f49effdb6d95ca41d811c2ee3e7471..e97c5086f47bbc923a2cd16651fc4c9559381041 100644 (file)
@@ -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 (file)
index 0000000..0149f2d
--- /dev/null
@@ -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 (file)
index 0000000..2ee1c5f
--- /dev/null
@@ -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
index 7221ddb956637d062a475ed86fa1d4a74b538f70..2a65cd33ccf6a370dd7294bfcbefde236cc7cb2d 100644 (file)
@@ -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])
This page took 0.047858 seconds and 4 git commands to generate.