]> Dogcows Code - chaz/tar/commitdiff
Add basic suuport for extended attributes.
authorPavel Raiskup <praiskup@redhat.com>
Sun, 18 Nov 2012 17:59:18 +0000 (19:59 +0200)
committerSergey Poznyakoff <gray@gnu.org.ua>
Sun, 18 Nov 2012 18:15:03 +0000 (20:15 +0200)
* src/Makefile.am: Add xattrs.[ch]
* src/xattrs.c: New file.
* src/xattrs.h: New file.
* src/common.h (READ_LIKE_SUBCOMMAND): New define.
(selinux_context_option, acls_option, xattrs_option): New globals.
(xheader_xattr_init, xheader_xattr_free)
(xheader_xattr_copy, xheader_xattr_add): New protos.
(WARN_XATTR_WRITE): New mask.
* src/create.c (start_header): Handle xattrs pairs if in POSIX format.
(dump_file0): Handle extended attributes.
* src/extract.c (delayed_set_stat,delayed_link) <xattr_map_size>
<xattr_map>: New members.
(set_xattr): New static function.
(open_output_file): Accept an additional argument indicating
whether the file has already been created.
(set_stat,delay_set_stat)
(apply_nonancestor_delayed_set_stat)
(extract_file): Handle extended attributes.
* src/list.c (decode_header, simple_print_header): Display
extended attributes.
* src/tar.c: New options --xattrs, --no-xattrs, --xattrs-include,
--xattrs-exclude
(tar_stat_destroy): Free the xattr_map storage.
* src/tar.h (xattr_array): New struct.
(tar_stat_info) <xattr_map_size, xattr_map>: New members.
* src/warning.c: New warning control keyword "xattr-write".
* src/xheader.c (xheader_xattr_init)
(xheader_xattr_free, xheader_xattr_add)
(xheader_xattr_copy): New functions.
(struct xhdr_tab) <prefix>: New member.
(locate_handler): Permit selecting the keyword based on its
prefix.
(xheader_protected_pattern_p)
(xheader_protected_keyword_p): Likewise.
(xattr_coder, xattr_decoder): New functions.
(xhdr_tab): Reflect the changes to struct xhdr_tab.
New keyword "SCHILY.xattr".
* tests/Makefile.am: Add new tests.
* tests/testsuite.at: Likewise.
(AT_CHECK_UTIL, AT_XATTRS_UTILS_PREREQ)
(AT_CAPABILITIES_UTILS_PREREQ, AT_XATTRS_PREREQ): New defuns.
* tests/xattr01.at: New test.
* tests/xattr02.at: New test.
* tests/xattr03.at: New test.
* tests/xattr04.at: New test.
* tests/capabs_raw01.at: New test.

13 files changed:
src/Makefile.am
src/common.h
src/create.c
src/extract.c
src/list.c
src/tar.c
src/tar.h
src/warning.c
src/xattrs.c [new file with mode: 0644]
src/xattrs.h [new file with mode: 0644]
src/xheader.c
tests/Makefile.am
tests/testsuite.at

index de310f43512a8dba61bd852aa2eb965a4dc49b91..27c28be8f3eff1fe9c5a3d3170fa01a73b51b8a2 100644 (file)
@@ -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)
index c51ab116e41294853f2baea41cb175b4518e915d..a78e50f72f9d8d841a9730d025ea4e0e72b3d60d 100644 (file)
@@ -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;
 
@@ -256,6 +261,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;
@@ -714,6 +728,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);
@@ -734,6 +751,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 */
 
@@ -815,6 +838,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 */
index 745796c2b2bd253e486ed6f6bdbb4306b5351792..034639b864b1e48fed6df4a22c4e91b62cdec4a7 100644 (file)
@@ -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.
 
@@ -943,6 +944,21 @@ start_header (struct tar_stat_info *st)
       GNAME_TO_CHARS (st->gname, header->header.gname);
     }
 
+  if (archive_format == POSIX_FORMAT)
+    {
+      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;
 }
 
@@ -1718,6 +1734,8 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
       bool ok;
       struct stat final_stat;
 
+      xattrs_xattrs_get (parentfd, name, st, fd);
+
       if (is_dir)
        {
          const char *tag_file_name;
@@ -1836,6 +1854,8 @@ 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_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);
@@ -1854,11 +1874,20 @@ 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_xattrs_get (parentfd, name, st, 0);
+    }
   else if (S_ISBLK (st->stat.st_mode))
-    type = BLKTYPE;
+    {
+      type = BLKTYPE;
+      xattrs_xattrs_get (parentfd, name, st, 0);
+    }
   else if (S_ISFIFO (st->stat.st_mode))
-    type = FIFOTYPE;
+    {
+      type = FIFOTYPE;
+      xattrs_xattrs_get (parentfd, name, st, 0);
+    }
   else if (S_ISSOCK (st->stat.st_mode))
     {
       WARNOPT (WARN_FILE_IGNORED,
index e35c8f64d4cff763397aec98abedef3c2ee61ea6..2d8e175985e2cb0d9b2719f305628884e81b47fd 100644 (file)
@@ -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.
 
@@ -98,6 +99,9 @@ struct delayed_set_stat
     /* Directory that the name is relative to.  */
     int change_dir;
 
+    /* extended attributes*/
+    size_t xattr_map_size;
+    struct xattr_array *xattr_map;
     /* Length and contents of name.  */
     size_t file_name_len;
     char file_name[1];
@@ -138,6 +142,9 @@ struct delayed_link
        hard-linked together.  */
     struct string_list *sources;
 
+    size_t xattr_map_size;
+    struct xattr_array *xattr_map;
+
     /* The desired target of the desired link.  */
     char target[1];
   };
@@ -364,6 +371,10 @@ 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);
 }
 
 /* For each entry H in the leading prefix of entries in HEAD that do
@@ -435,6 +446,13 @@ 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)
+    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))
@@ -682,6 +700,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
@@ -742,12 +794,15 @@ 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.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);
     }
 }
@@ -863,7 +918,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;
@@ -873,6 +929,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;
@@ -944,6 +1004,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;
 
@@ -960,8 +1022,18 @@ extract_file (char *file_name, int typeflag)
     }
   else
     {
+      int file_created = 0;
+      if (set_xattr (file_name, &current_stat_info, invert_permissions,
+                     typeflag, &file_created))
+        {
+          skip_member ();
+          open_error (file_name);
+          return 1;
+        }
+
       while ((fd = open_output_file (file_name, typeflag, mode,
-                                    &current_mode, &current_mode_mask))
+                                     file_created, &current_mode,
+                                     &current_mode_mask))
             < 0)
        {
          int recover = maybe_recoverable (file_name, true, &interdir_made);
@@ -1101,6 +1173,7 @@ 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);
+      xheader_xattr_copy (&current_stat_info, &p->xattr_map, &p->xattr_map_size);
       strcpy (p->target, current_stat_info.link_name);
 
       h = delayed_set_stat_head;
@@ -1536,6 +1609,8 @@ apply_delayed_links (void)
                  st1.stat.st_gid = ds->gid;
                  st1.atime = ds->atime;
                  st1.mtime = ds->mtime;
+                  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;
@@ -1550,6 +1625,8 @@ apply_delayed_links (void)
          sources = next;
        }
 
+   xheader_xattr_free (ds->xattr_map, ds->xattr_map_size);
+
       {
        struct delayed_link *next = ds->next;
        free (ds);
index 4f85fb5b9f0b2a099ef53ca302239462245bde5f..f2605ad0c258d68ab6214ed5af1eeb8e68707951 100644 (file)
@@ -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.
 
@@ -604,6 +605,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);
@@ -1064,7 +1067,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;
@@ -1156,6 +1159,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);
@@ -1301,6 +1307,7 @@ simple_print_header (struct tar_stat_info *st, union block *blk,
        }
     }
   fflush (stdlis);
+  xattrs_print (st);
 }
 
 
index 8c4f656bb24473f6dfda5c3a7555e899ed4a8bdd..c97682076fce244dcd987b4da4656f502c0b2b4a 100644 (file)
--- 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.
 
@@ -304,6 +305,7 @@ enum
   NO_UNQUOTE_OPTION,
   NO_WILDCARDS_MATCH_SLASH_OPTION,
   NO_WILDCARDS_OPTION,
+  NO_XATTR_OPTION,
   NULL_OPTION,
   NUMERIC_OWNER_OPTION,
   OCCURRENCE_OPTION,
@@ -341,7 +343,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 +535,20 @@ 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 },
+#undef GRID
+
 #define GRID 60
   {NULL, 0, NULL, 0,
    N_("Device selection and switching:"), GRID },
@@ -2150,6 +2169,20 @@ parse_opt (int key, char *arg, struct argp_state *state)
       same_permissions_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;
@@ -2527,11 +2560,16 @@ 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 when reading */
+  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;
@@ -2740,6 +2778,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)
@@ -2784,6 +2823,7 @@ 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);
index 0b090af54d78c5bab1527ddfec777be8c4495744..7a80e87b0844367d04aa04700e838821b2380aba 100644 (file)
--- 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 */
@@ -309,6 +318,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;
 
index 102364d515b200879b51becabd615a807dbd82bf..570b3c113517450dc59d1d2f394cc03f2a553c53 100644 (file)
@@ -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
 };
 
@@ -68,7 +69,8 @@ static int warning_types[] = {
   WARN_UNKNOWN_KEYWORD,
   WARN_XDEV,
   WARN_DECOMPRESS_PROGRAM,
-  WARN_EXISTING_FILE
+  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 (file)
index 0000000..e813d53
--- /dev/null
@@ -0,0 +1,315 @@
+/* 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 <system.h>
+
+#include <fnmatch.h>
+#include <quotearg.h>
+
+#include "common.h"
+
+#include "xattr-at.h"
+
+struct xattrs_mask_map
+{
+  const char **masks;
+  int size;
+  int used;
+};
+
+/* list of fnmatch patterns */
+static struct
+{
+  /* lists of fnmatch patterns */
+  struct xattrs_mask_map incl;
+  struct xattrs_mask_map excl;
+} xattrs_setup;
+
+static void mask_map_realloc (struct xattrs_mask_map *map)
+{
+  if (map->size == 0)
+    {
+      map->size = 4;
+      map->masks = xmalloc (16 * sizeof (char *));
+      return;
+    }
+
+  if (map->size <= map->used)
+    {
+      map->size *= 2;
+      map->masks = xrealloc (map->masks, map->size * sizeof (char *));
+      return;
+    }
+}
+
+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 ssize_t xsz = 1024;
+      static char *xatrs = NULL;
+      ssize_t xret = -1;
+
+      if (!xatrs) xatrs = xmalloc (xsz);
+
+      while (((fd == 0) ?
+              ((xret = llistxattrat (parentfd, file_name, xatrs, xsz)) == -1) :
+              ((xret = flistxattr (fd, xatrs, xsz)) == -1)) &&
+             (errno == ERANGE))
+        {
+          xsz <<= 1;
+          xatrs = xrealloc (xatrs, xsz);
+        }
+
+      if (xret == -1)
+        call_arg_warn ((fd == 0) ? "llistxattrat" : "flistxattr", file_name);
+      else
+        {
+          const char *attr = xatrs;
+          static ssize_t asz = 1024;
+          static char *val = NULL;
+
+          if (!val) val = xmalloc (asz);
+
+          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))
+                {
+                  asz <<= 1;
+                  val = xrealloc (val, asz);
+                }
+
+              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));
+    }
+}
+
+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;
+}
+
+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.", strlen ("user.")) == 0;
+     }
+}
+
+static bool xattrs_kw_excluded (const char *kw, bool archiving)
+{
+  if (!xattrs_setup.excl.size)
+    return false;
+
+  return xattrs_matches_mask (kw, &xattrs_setup.excl);
+}
+
+/* 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)
+{
+  if (!xattrs_kw_included (kw, archiving))
+    return true;
+
+  return xattrs_kw_excluded (kw, archiving);
+}
+
+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)
+    {
+      /* 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 */ ))
+          continue;
+        *output = '*';
+        break;
+      }
+}
+
+void xattrs_print (struct tar_stat_info const *st)
+{
+  if (verbose_option < 3)
+    return;
+
+  /* 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 */ ))
+            continue;
+          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 (file)
index 0000000..0c08cd7
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef GUARD_XATTTRS_H
+#define GUARD_XATTTRS_H
+
+/* 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.
+*/
+
+
+/* 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 */
index 0946493b5badd8d3844dbfa0d5a2f25198757200..061d44887d554dc2aff893f20075ad1e556b4d56 100644 (file)
@@ -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,74 @@ xheader_write_global (struct xheader *xhdr)
     }
 }
 
+void xheader_xattr_init (struct tar_stat_info *st)
+{
+  st->xattr_map = NULL;
+  st->xattr_map_size = 0;
+}
+
+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;
+}
+
+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;
+    }
+}
+
 \f
 /* General Interface */
 
@@ -473,6 +541,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 +558,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 +578,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 +590,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;
 }
@@ -1468,6 +1548,26 @@ volume_filename_decoder (struct tar_stat_info *st,
 {
   decode_string (&continued_file_name, arg);
 }
+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 = NULL;
+
+  xstr = xmemdup(arg, size + 1);
+  xheader_xattr_add(st, keyword + strlen("SCHILY.xattr."), xstr, size);
+  free(xstr);
+}
 
 static void
 sparse_major_coder (struct tar_stat_info const *st, char const *keyword,
@@ -1506,53 +1606,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 +1661,16 @@ 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 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 }
 };
index 47afea1df3fe18c0442cffe672c74c720d362f97..3d870f10e1f49effdb6d95ca41d811c2ee3e7471 100644 (file)
@@ -1,7 +1,7 @@
 # Makefile for GNU tar regression tests.
 
 # Copyright (C) 1996, 1997, 1999, 2000, 2001, 2003, 2004, 2005,
-# 2006, 2007, 2009 Free Software Foundation, Inc.
+# 2006, 2007, 2009, 2012 Free Software Foundation, Inc.
 
 # François Pinard <pinard@iro.umontreal.ca>, 1988.
 # Sergey Poznyakoff <gray@mirddin.farlep.net>, 2004.
@@ -173,7 +173,12 @@ 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\
+ capabs_raw01.at
 
 TESTSUITE = $(srcdir)/testsuite
 
index d5c602393be5cc4ddb47985247f3fb544c051a66..7221ddb956637d062a475ed86fa1d4a74b538f70 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 Free Software
+# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010, 2012 Free Software
 # Foundation, Inc.
 
 # This program is free software; you can redistribute it and/or modify
@@ -117,6 +117,36 @@ 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_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_include([sparsemvp.at])
 
 AT_INIT
@@ -284,3 +314,10 @@ m4_include([star/ustar-big-2g.at])
 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.054633 seconds and 4 git commands to generate.