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\
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)
/* 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
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;
/* 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;
void update_archive (void);
+/* Module attrs.c. */
+#include "xattrs.h"
+
/* Module xheader.c. */
void xheader_decode (struct tar_stat_info *stat);
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 */
#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 */
/* 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.
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;
}
bool ok;
struct stat final_stat;
+ xattrs_xattrs_get (parentfd, name, st, fd);
+
if (is_dir)
{
const char *tag_file_name;
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);
}
#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,
/* 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.
/* 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];
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];
};
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
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))
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
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);
}
}
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;
? 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;
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;
}
else
{
+ int file_created = 0;
+ if (set_xattr (file_name, ¤t_stat_info, invert_permissions,
+ typeflag, &file_created))
+ {
+ skip_member ();
+ open_error (file_name);
+ return 1;
+ }
+
while ((fd = open_output_file (file_name, typeflag, mode,
- ¤t_mode, ¤t_mode_mask))
+ file_created, ¤t_mode,
+ ¤t_mode_mask))
< 0)
{
int recover = maybe_recoverable (file_name, true, &interdir_made);
+ strlen (file_name) + 1);
p->sources->next = 0;
strcpy (p->sources->string, file_name);
+ xheader_xattr_copy (¤t_stat_info, &p->xattr_map, &p->xattr_map_size);
strcpy (p->target, current_stat_info.link_name);
h = delayed_set_stat_head;
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;
sources = next;
}
+ xheader_xattr_free (ds->xattr_map, ds->xattr_map_size);
+
{
struct delayed_link *next = ds->next;
free (ds);
/* 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.
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);
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;
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);
}
}
fflush (stdlis);
+ xattrs_print (st);
}
/* 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.
NO_UNQUOTE_OPTION,
NO_WILDCARDS_MATCH_SLASH_OPTION,
NO_WILDCARDS_OPTION,
+ NO_XATTR_OPTION,
NULL_OPTION,
NUMERIC_OWNER_OPTION,
OCCURRENCE_OPTION,
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;
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 },
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;
--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;
/* Dispose of allocated memory, and return. */
free (archive_name_array);
+ xattrs_clear_setup ();
name_term ();
if (exit_status == TAREXIT_FAILURE)
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);
/* 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
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 */
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;
/* 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
"xdev",
"decompress-program",
"existing-file",
+ "xattr-write",
NULL
};
WARN_UNKNOWN_KEYWORD,
WARN_XDEV,
WARN_DECOMPRESS_PROGRAM,
- WARN_EXISTING_FILE
+ WARN_EXISTING_FILE,
+ WARN_XATTR_WRITE
};
ARGMATCH_VERIFY (warning_args, warning_types);
--- /dev/null
+/* 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);
+ }
+ }
+}
--- /dev/null
+#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 */
/* 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
}
}
+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 */
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
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;
}
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;
}
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;
}
{
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,
}
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.
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 }
};
# 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.
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
# 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
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
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])