summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDongHun Kwak <dh0128.kwak@samsung.com>2015-12-14 15:55:53 +0900
committerDongHun Kwak <dh0128.kwak@samsung.com>2015-12-14 16:17:37 +0900
commita8d964ee3ae1acc7d0a9ed43e5f1e363d26da090 (patch)
treee25c4e9b888d173b3109ffed48153499ee00c531 /src
parent02e836feb7a708522369a8fb46a3ade8688db655 (diff)
downloadtar-accepted/tizen_3.0_base.tar.gz
tar-accepted/tizen_3.0_base.tar.bz2
tar-accepted/tizen_3.0_base.zip
sync with tizen 2.4 run unit test Change-Id: Iae1c58a660ee7dad0694163929e5b9940a0ec9c8 Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am7
-rw-r--r--src/Makefile.in20
-rw-r--r--src/common.h18
-rw-r--r--src/create.c39
-rw-r--r--src/extract.c65
-rw-r--r--src/list.c16
-rw-r--r--src/names.c8
-rw-r--r--src/system.c19
-rw-r--r--src/tar.c89
-rw-r--r--src/tar.h20
-rw-r--r--src/xattrs.c491
-rw-r--r--src/xattrs.h14
-rw-r--r--src/xheader.c224
13 files changed, 976 insertions, 54 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 61f6cbd..4f32a69 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -20,7 +20,7 @@
bin_PROGRAMS = tar
-noinst_HEADERS = arith.h common.h tar.h
+noinst_HEADERS = arith.h common.h tar.h xattrs.h
tar_SOURCES = \
buffer.c\
compare.c\
@@ -37,10 +37,11 @@ tar_SOURCES = \
tar.c\
transform.c\
update.c\
- utf8.c
+ utf8.c\
+ xattrs.c
INCLUDES = -I$(top_srcdir)/lib -I../ -I../lib
LDADD = ../lib/libtar.a $(LIBINTL) $(LIBICONV)
-tar_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
+tar_LDADD = $(LIBS) $(LDADD) $(LIB_CLOCK_GETTIME)
diff --git a/src/Makefile.in b/src/Makefile.in
index 148448a..e828328 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1,8 +1,8 @@
-# Makefile.in generated by automake 1.10a from Makefile.am.
+# Makefile.in generated by automake 1.10 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -22,9 +22,8 @@
VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
-pkglibexecdir = $(libexecdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
@@ -134,12 +133,13 @@ am_tar_OBJECTS = buffer.$(OBJEXT) compare.$(OBJEXT) create.$(OBJEXT) \
incremen.$(OBJEXT) list.$(OBJEXT) misc.$(OBJEXT) \
names.$(OBJEXT) sparse.$(OBJEXT) system.$(OBJEXT) \
tar.$(OBJEXT) transform.$(OBJEXT) update.$(OBJEXT) \
- utf8.$(OBJEXT)
+ utf8.$(OBJEXT) xattrs.$(OBJEXT)
tar_OBJECTS = $(am_tar_OBJECTS)
am__DEPENDENCIES_1 =
am__DEPENDENCIES_2 = ../lib/libtar.a $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1)
-tar_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1)
+tar_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
+ $(am__DEPENDENCIES_1)
DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@
depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
am__depfiles_maybe = depfiles
@@ -459,7 +459,7 @@ sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
-noinst_HEADERS = arith.h common.h tar.h
+noinst_HEADERS = arith.h common.h tar.h xattrs.h
tar_SOURCES = \
buffer.c\
compare.c\
@@ -476,11 +476,12 @@ tar_SOURCES = \
tar.c\
transform.c\
update.c\
- utf8.c
+ utf8.c\
+ xattrs.c
INCLUDES = -I$(top_srcdir)/lib -I../ -I../lib
LDADD = ../lib/libtar.a $(LIBINTL) $(LIBICONV)
-tar_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
+tar_LDADD = $(LIBS) $(LDADD) $(LIB_CLOCK_GETTIME)
all: all-am
.SUFFIXES:
@@ -578,6 +579,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transform.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/update.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utf8.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xattrs.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xheader.Po@am__quote@
.c.o:
diff --git a/src/common.h b/src/common.h
index 6dd1abd..b82558d 100644
--- a/src/common.h
+++ b/src/common.h
@@ -255,6 +255,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;
@@ -666,6 +675,9 @@ extern char *output_start;
void update_archive (void);
+/* Module attrs.c. */
+#include "xattrs.h"
+
/* Module xheader.c. */
void xheader_init (struct xheader *xhdr);
@@ -687,6 +699,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 */
diff --git a/src/create.c b/src/create.c
index 1b31a3d..6a61d39 100644
--- a/src/create.c
+++ b/src/create.c
@@ -24,6 +24,7 @@
#include <quotearg.h>
#include "common.h"
+
#include <hash.h>
struct link
@@ -575,7 +576,9 @@ write_gnu_long_link (struct tar_stat_info *st, const char *p, char type)
GNAME_TO_CHARS (tmpname, header->header.gname);
free (tmpname);
- strcpy (header->header.magic, OLDGNU_MAGIC);
+ strncpy (header->header.magic, OLDGNU_MAGIC, sizeof(header->header.magic));
+ strncpy (header->header.version, OLDGNU_MAGIC + sizeof(header->header.magic),
+ sizeof(header->header.version));
header->header.typeflag = type;
finish_header (st, header, -1);
@@ -907,7 +910,11 @@ start_header (struct tar_stat_info *st)
case OLDGNU_FORMAT:
case GNU_FORMAT: /*FIXME?*/
/* Overwrite header->header.magic and header.version in one blow. */
- strcpy (header->header.magic, OLDGNU_MAGIC);
+ strncpy (header->header.magic, OLDGNU_MAGIC,
+ sizeof(header->header.magic));
+ strncpy (header->header.version,
+ OLDGNU_MAGIC + sizeof(header->header.magic),
+ sizeof(header->header.version));
break;
case POSIX_FORMAT:
@@ -942,6 +949,30 @@ start_header (struct tar_stat_info *st)
GNAME_TO_CHARS (st->gname, header->header.gname);
}
+ if (archive_format == POSIX_FORMAT)
+ {
+ if (acls_option > 0)
+ {
+ if (st->acls_a_ptr)
+ xheader_store ("SCHILY.acl.access", st, NULL);
+ if (st->acls_d_ptr)
+ xheader_store ("SCHILY.acl.default", st, NULL);
+ }
+ if ((selinux_context_option > 0) && st->cntx_name)
+ xheader_store ("RHT.security.selinux", st, NULL);
+ if (xattrs_option > 0)
+ {
+ size_t scan_xattr = 0;
+ struct xattr_array *xattr_map = st->xattr_map;
+
+ while (scan_xattr < st->xattr_map_size)
+ {
+ xheader_store (xattr_map[scan_xattr].xkey, st, &scan_xattr);
+ ++scan_xattr;
+ }
+ }
+ }
+
return header;
}
@@ -1572,6 +1603,10 @@ dump_file0 (struct tar_stat_info *st, const char *p,
}
}
+ xattrs_acls_get(st, p, fd, !is_dir);
+ xattrs_selinux_get(st, p, fd);
+ xattrs_xattrs_get(st, p, fd);
+
if (is_dir)
{
const char *tag_file_name;
diff --git a/src/extract.c b/src/extract.c
index 1f231e3..d70e0da 100644
--- a/src/extract.c
+++ b/src/extract.c
@@ -69,6 +69,13 @@ struct delayed_set_stat
mode_t invert_permissions;
enum permstatus permstatus;
bool after_links;
+ char *cntx_name;
+ char *acls_a_ptr;
+ size_t acls_a_len;
+ char *acls_d_ptr;
+ size_t acls_d_len;
+ size_t xattr_map_size; /* Size of the xattr map */
+ struct xattr_array *xattr_map;
char file_name[1];
};
@@ -96,6 +103,18 @@ struct delayed_link
hard-linked together. */
struct string_list *sources;
+ /* SELinux context */
+ char *cntx_name;
+
+ /* ACLs */
+ char *acls_a_ptr;
+ size_t acls_a_len;
+ char *acls_d_ptr;
+ size_t acls_d_len;
+
+ size_t xattr_map_size; /* Size of the xattr map */
+ struct xattr_array *xattr_map;
+
/* The desired target of the desired link. */
char target[1];
};
@@ -276,6 +295,10 @@ set_stat (char const *file_name,
give files away. */
}
+ xattrs_acls_set(st, file_name, typeflag);
+ xattrs_selinux_set(st, file_name, typeflag);
+ xattrs_xattrs_set(st, file_name, typeflag);
+
if (0 < same_owner_option && permstatus != INTERDIR_PERMSTATUS)
{
/* When lchown exists, it should be used to change the attributes of
@@ -352,6 +375,23 @@ delay_set_stat (char const *file_name, struct tar_stat_info const *st,
data->invert_permissions = invert_permissions;
data->permstatus = permstatus;
data->after_links = 0;
+ data->cntx_name = NULL;
+ assign_string (&data->cntx_name, st->cntx_name);
+ if (st->acls_a_ptr)
+ data->acls_a_ptr = xmemdup(st->acls_a_ptr, st->acls_a_len);
+ else
+ {
+ data->acls_a_ptr = NULL;
+ data->acls_a_len = 0;
+ }
+ if (st->acls_d_ptr)
+ data->acls_d_ptr = xmemdup(st->acls_d_ptr, st->acls_d_len);
+ else
+ {
+ data->acls_d_ptr = NULL;
+ data->acls_d_len = 0;
+ }
+ xheader_xattr_copy (st, &data->xattr_map, &data->xattr_map_size);
strcpy (data->file_name, file_name);
delayed_set_stat_head = data;
}
@@ -599,11 +639,22 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_links)
st.stat.st_gid = data->gid;
st.atime = data->atime;
st.mtime = data->mtime;
+ st.cntx_name = data->cntx_name;
+ st.acls_a_ptr = data->acls_a_ptr;
+ st.acls_a_len = data->acls_a_len;
+ st.acls_d_ptr = data->acls_d_ptr;
+ st.acls_d_len = data->acls_d_len;
+ st.xattr_map = data->xattr_map;
+ st.xattr_map_size = data->xattr_map_size;
set_stat (data->file_name, &st, cur_info,
data->invert_permissions, data->permstatus, DIRTYPE);
}
delayed_set_stat_head = data->next;
+ xheader_xattr_free (data->xattr_map, data->xattr_map_size);
+ free (data->cntx_name);
+ free (data->acls_a_ptr);
+ free (data->acls_d_ptr);
free (data);
}
}
@@ -882,6 +933,13 @@ create_placeholder_file (char *file_name, bool is_symlink, int *interdir_made)
+ strlen (file_name) + 1);
p->sources->next = 0;
strcpy (p->sources->string, file_name);
+ p->cntx_name = NULL;
+ p->acls_a_ptr = NULL;
+ p->acls_a_len = 0;
+ p->acls_d_ptr = NULL;
+ p->acls_d_len = 0;
+ p->xattr_map = NULL;
+ p->xattr_map_size = 0;
strcpy (p->target, current_stat_info.link_name);
h = delayed_set_stat_head;
@@ -1291,6 +1349,13 @@ apply_delayed_links (void)
struct tar_stat_info st1;
st1.stat.st_uid = ds->uid;
st1.stat.st_gid = ds->gid;
+ st1.cntx_name = ds->cntx_name;
+ st1.acls_a_ptr = ds->acls_a_ptr;
+ st1.acls_a_len = ds->acls_a_len;
+ st1.acls_d_ptr = ds->acls_d_ptr;
+ st1.acls_d_len = ds->acls_d_len;
+ st1.xattr_map = ds->xattr_map;
+ st1.xattr_map_size = ds->xattr_map_size;
set_stat (source, &st1, NULL, 0, 0, SYMTYPE);
valid_source = source;
}
diff --git a/src/list.c b/src/list.c
index 75837f6..232e48f 100644
--- a/src/list.c
+++ b/src/list.c
@@ -136,6 +136,14 @@ read_and (void (*do_something) (void))
if (!ignore_zeros_option)
{
+ /*
+ * According to POSIX tar specs, this is wrong, but on the web
+ * there are some tar specs that can trigger this, and some tar
+ * implementations create tars according to that spec. For now,
+ * let's not be pedantic about issuing the warning.
+ */
+#if 0
+
char buf[UINTMAX_STRSIZE_BOUND];
status = read_header (false);
@@ -143,6 +151,7 @@ read_and (void (*do_something) (void))
break;
WARN ((0, 0, _("A lone zero block at %s"),
STRINGIFY_BIGINT (current_block_ordinal (), buf)));
+#endif
break;
}
status = prev_status;
@@ -558,6 +567,13 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
assign_string (&stat_info->gname,
header->header.gname[0] ? header->header.gname : NULL);
+ stat_info->acls_a_ptr = NULL;
+ stat_info->acls_a_len = 0;
+ stat_info->acls_d_ptr = NULL;
+ stat_info->acls_d_len = 0;
+ stat_info->cntx_name = NULL;
+ xheader_xattr_init(stat_info);
+
if (format == OLDGNU_FORMAT && incremental_option)
{
stat_info->atime.tv_sec = TIME_FROM_HEADER (header->oldgnu_header.atime);
diff --git a/src/names.c b/src/names.c
index 2eb7629..2060d1d 100644
--- a/src/names.c
+++ b/src/names.c
@@ -812,10 +812,7 @@ collect_and_sort_names (void)
next_name = name->next;
if (name->found_count || name->dir_contents)
continue;
- if (name->matching_flags & EXCLUDE_WILDCARDS)
- /* NOTE: EXCLUDE_ANCHORED is not relevant here */
- /* FIXME: just skip regexps for now */
- continue;
+
chdir_do (name->change_dir);
if (name->name[0] == 0)
continue;
@@ -1012,11 +1009,10 @@ contains_dot_dot (char const *name)
if (p[0] == '.' && p[1] == '.' && (ISSLASH (p[2]) || !p[2]))
return 1;
- do
+ while (! ISSLASH (*p))
{
if (! *p++)
return 0;
}
- while (! ISSLASH (*p));
}
}
diff --git a/src/system.c b/src/system.c
index e2d0431..70b746b 100644
--- a/src/system.c
+++ b/src/system.c
@@ -250,8 +250,25 @@ sys_compare_links (struct stat *link_data, struct stat *stat_data)
int
sys_truncate (int fd)
{
+ struct stat st;
off_t pos = lseek (fd, (off_t) 0, SEEK_CUR);
- return pos < 0 ? -1 : ftruncate (fd, pos);
+
+ if ( pos < 0)
+ return -1;
+
+ if ( ftruncate(fd, pos) && errno == EPERM ) {
+ /* wrapper around ftruncate:
+ * ftruncate may fail to grow the size of a file with some OS and filesystem
+ * combinations. Linux and vfat/fat is one example. If this is the case do
+ * a write to grow the file to the desired length.
+ */
+ if( (fstat( fd, &st ) == -1) ||
+ (st.st_size >= pos) ||
+ (lseek( fd, pos - 1, SEEK_SET) == (off_t)-1) ||
+ (write( fd, "\0", 1) == -1) )
+ return -1;
+ }
+ return 0;
}
/* Return nonzero if NAME is the name of a regular file, or if the file
diff --git a/src/tar.c b/src/tar.c
index 1b95ccf..9453093 100644
--- a/src/tar.c
+++ b/src/tar.c
@@ -247,7 +247,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,
CHECKPOINT_OPTION,
@@ -271,6 +272,7 @@ enum
MODE_OPTION,
MTIME_OPTION,
NEWER_MTIME_OPTION,
+ NO_ACLS_OPTION,
NO_ANCHORED_OPTION,
NO_DELAY_DIRECTORY_RESTORE_OPTION,
NO_IGNORE_CASE_OPTION,
@@ -280,9 +282,11 @@ enum
NO_RECURSION_OPTION,
NO_SAME_OWNER_OPTION,
NO_SAME_PERMISSIONS_OPTION,
+ NO_SELINUX_CONTEXT_OPTION,
NO_UNQUOTE_OPTION,
NO_WILDCARDS_MATCH_SLASH_OPTION,
NO_WILDCARDS_OPTION,
+ NO_XATTR_OPTION,
NULL_OPTION,
NUMERIC_OWNER_OPTION,
OCCURRENCE_OPTION,
@@ -304,6 +308,7 @@ enum
RMT_COMMAND_OPTION,
RSH_COMMAND_OPTION,
SAME_OWNER_OPTION,
+ SELINUX_CONTEXT_OPTION,
SHOW_DEFAULTS_OPTION,
SHOW_OMITTED_DIRS_OPTION,
SHOW_TRANSFORMED_NAMES_OPTION,
@@ -321,7 +326,8 @@ enum
VERSION_OPTION,
VOLNO_FILE_OPTION,
WILDCARDS_MATCH_SLASH_OPTION,
- WILDCARDS_OPTION
+ WILDCARDS_OPTION,
+ XATTR_OPTION
};
const char *argp_program_version = "tar (" PACKAGE_NAME ") " VERSION;
@@ -453,6 +459,10 @@ static struct argp_option options[] = {
{NULL, 0, NULL, 0,
N_("Handling of file attributes:"), GRID },
+ {"acls", ACLS_OPTION, 0, 0,
+ N_("Save the ACLs to the archive"), GRID+1 },
+ {"no-acls", NO_ACLS_OPTION, 0, 0,
+ N_("Don't extract the ACLs from the archive"), GRID+1 },
{"owner", OWNER_OPTION, N_("NAME"), 0,
N_("force NAME as owner for added files"), GRID+1 },
{"group", GROUP_OPTION, N_("NAME"), 0,
@@ -483,6 +493,14 @@ static struct argp_option options[] = {
{"preserve-order", 's', 0, 0,
N_("sort names to extract to match archive"), GRID+1 },
{"same-order", 0, 0, OPTION_ALIAS, NULL, GRID+1 },
+ {"selinux", SELINUX_CONTEXT_OPTION, 0, 0,
+ N_("Save the SELinux context to the archive"), GRID+1 },
+ {"no-selinux", NO_SELINUX_CONTEXT_OPTION, 0, 0,
+ N_("Don't extract the SELinux context from the archive"), GRID+1 },
+ {"xattrs", XATTR_OPTION, 0, 0,
+ N_("Save the user/root xattrs to the archive"), GRID+1 },
+ {"no-xattrs", NO_XATTR_OPTION, 0, 0,
+ N_("Don't extract the user/root xattrs from the archive"), GRID+1 },
{"preserve", PRESERVE_OPTION, 0, 0,
N_("same as both -p and -s"), GRID+1 },
{"delay-directory-restore", DELAY_DIRECTORY_RESTORE_OPTION, 0, 0,
@@ -668,7 +686,7 @@ static struct argp_option options[] = {
{"no-ignore-case", NO_IGNORE_CASE_OPTION, 0, 0,
N_("case sensitive matching (default)"), GRID+1 },
{"wildcards", WILDCARDS_OPTION, 0, 0,
- N_("use wildcards (default for exclusion)"), GRID+1 },
+ N_("use wildcards (default)"), GRID+1 },
{"no-wildcards", NO_WILDCARDS_OPTION, 0, 0,
N_("verbatim string matching"), GRID+1 },
{"no-wildcards-match-slash", NO_WILDCARDS_MATCH_SLASH_OPTION, 0, 0,
@@ -762,8 +780,7 @@ ARGMATCH_VERIFY (atime_preserve_args, atime_preserve_types);
/* Wildcard matching settings */
enum wildcards
{
- default_wildcards, /* For exclusion == enable_wildcards,
- for inclusion == disable_wildcards */
+ default_wildcards, /* enable_wildcards */
disable_wildcards,
enable_wildcards
};
@@ -791,7 +808,7 @@ struct tar_args /* Variables used during option parsing */
| recursion_option)
#define MAKE_INCL_OPTIONS(args) \
- ((((args)->wildcards == enable_wildcards) ? EXCLUDE_WILDCARDS : 0) \
+ ((((args)->wildcards != disable_wildcards) ? EXCLUDE_WILDCARDS : 0) \
| (args)->include_anchored \
| (args)->matching_flags \
| recursion_option)
@@ -1805,6 +1822,37 @@ parse_opt (int key, char *arg, struct argp_state *state)
same_permissions_option = -1;
break;
+ case ACLS_OPTION:
+ set_archive_format ("posix");
+ acls_option = 1;
+ break;
+
+ case NO_ACLS_OPTION:
+ acls_option = -1;
+ break;
+
+ case SELINUX_CONTEXT_OPTION:
+ set_archive_format ("posix");
+ selinux_context_option = 1;
+ break;
+
+ case NO_SELINUX_CONTEXT_OPTION:
+ selinux_context_option = -1;
+ break;
+
+ case XATTR_OPTION:
+ set_archive_format ("posix");
+ if (!acls_option) acls_option = 1;
+ if (!selinux_context_option) selinux_context_option = 1;
+ xattrs_option = 1;
+ break;
+
+ case NO_XATTR_OPTION:
+ if (!acls_option) acls_option = -1;
+ if (!selinux_context_option) selinux_context_option = -1;
+ xattrs_option = -1;
+ break;
+
case RECURSION_OPTION:
recursion_option = FNM_LEADING_DIR;
break;
@@ -2077,7 +2125,7 @@ decode_options (int argc, char **argv)
/* Warn about implicit use of the wildcards in command line arguments.
See TODO */
- warn_regex_usage = args.wildcards == default_wildcards;
+ warn_regex_usage = 0; //args.wildcards == default_wildcards;
/* Derive option values and check option consistency. */
@@ -2200,6 +2248,29 @@ decode_options (int argc, char **argv)
|| subcommand_option != LIST_SUBCOMMAND))
USAGE_ERROR ((0, 0, _("--pax-option can be used only on POSIX archives")));
+ /* star create's non-POSIX typed archives with xattr support, so allow the
+ extra headers */
+ if ((acls_option > 0)
+ && archive_format != POSIX_FORMAT
+ && (subcommand_option != EXTRACT_SUBCOMMAND
+ || subcommand_option != DIFF_SUBCOMMAND
+ || subcommand_option != LIST_SUBCOMMAND))
+ USAGE_ERROR ((0, 0, _("--acls can be used only on POSIX archives")));
+
+ if ((selinux_context_option > 0)
+ && archive_format != POSIX_FORMAT
+ && (subcommand_option != EXTRACT_SUBCOMMAND
+ || subcommand_option != DIFF_SUBCOMMAND
+ || subcommand_option != LIST_SUBCOMMAND))
+ USAGE_ERROR ((0, 0, _("--selinux can be used only on POSIX archives")));
+
+ if ((xattrs_option > 0)
+ && archive_format != POSIX_FORMAT
+ && (subcommand_option != EXTRACT_SUBCOMMAND
+ || subcommand_option != DIFF_SUBCOMMAND
+ || subcommand_option != LIST_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;
@@ -2401,11 +2472,15 @@ tar_stat_init (struct tar_stat_info *st)
void
tar_stat_destroy (struct tar_stat_info *st)
{
+ xheader_xattr_free (st->xattr_map, st->xattr_map_size);
free (st->orig_file_name);
free (st->file_name);
free (st->link_name);
free (st->uname);
free (st->gname);
+ free (st->cntx_name);
+ free (st->acls_a_ptr);
+ free (st->acls_d_ptr);
free (st->sparse_map);
free (st->dumpdir);
xheader_destroy (&st->xhdr);
diff --git a/src/tar.h b/src/tar.h
index 439273e..096edd1 100644
--- a/src/tar.h
+++ b/src/tar.h
@@ -276,6 +276,14 @@ struct xheader
uintmax_t string_length;
};
+/* Information about xattrs for a file. */
+struct xattr_array
+ {
+ char *xkey;
+ char *xval_ptr;
+ size_t xval_len;
+ };
+
struct tar_stat_info
{
char *orig_file_name; /* name of file read from the archive header */
@@ -287,6 +295,15 @@ struct tar_stat_info
char *uname; /* user name of owner */
char *gname; /* group name of owner */
+
+ char *cntx_name; /* SELinux context for the current archive entry. */
+
+ char *acls_a_ptr; /* Access ACLs for the current archive entry. */
+ size_t acls_a_len; /* Access ACLs for the current archive entry. */
+
+ char *acls_d_ptr; /* Default ACLs for the current archive entry. */
+ size_t acls_d_len; /* Default ACLs for the current archive entry. */
+
struct stat stat; /* regular filesystem stat */
/* STAT doesn't always have access, data modification, and status
@@ -309,6 +326,9 @@ struct tar_stat_info
size_t sparse_map_size; /* Size of the sparse map */
struct sp_array *sparse_map;
+ size_t xattr_map_size; /* Size of the xattr map */
+ struct xattr_array *xattr_map;
+
/* Extended headers */
struct xheader xhdr;
diff --git a/src/xattrs.c b/src/xattrs.c
new file mode 100644
index 0000000..1029c7c
--- /dev/null
+++ b/src/xattrs.c
@@ -0,0 +1,491 @@
+/* Create a tar archive.
+
+ Copyright (C) 2006 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 <quotearg.h>
+
+#include "common.h"
+
+
+#ifndef HAVE_SELINUX_SELINUX_H
+# undef HAVE_LIBSELINUX
+#endif
+
+#ifndef HAVE_ATTR_XATTR_H
+# undef HAVE_XATTRS
+#endif
+
+#ifndef HAVE_SYS_ACL_H
+# undef HAVE_LIBACL
+#endif
+
+#ifdef HAVE_SELINUX_SELINUX_H
+# include <selinux/selinux.h>
+#endif
+
+#ifdef HAVE_ATTR_XATTR_H
+# include <attr/xattr.h>
+#endif
+
+#ifdef HAVE_SYS_ACL_H
+# include <sys/acl.h>
+#endif
+
+
+#if 0 /* unused by xattr's atm. */
+static void xattrs__fd_get(struct tar_stat_info *st,
+ char const *file_name, int fd, const char *attr,
+ char **ret_ptr, size_t *ret_len)
+{
+#ifdef HAVE_XATTRS
+ static ssize_t asz = 1024;
+ ssize_t ret = 0;
+ static char *val = NULL;
+
+ if (!val) val = xmalloc (asz);
+
+ while (((ret = fgetxattr (fd, attr, val, asz)) == -1) &&
+ (errno == ERANGE))
+ {
+ asz <<= 1;
+ val = xrealloc (val, asz);
+ }
+
+ if (ret != -1)
+ {
+ *ret_ptr = xmemdup (val, ret);
+ *ret_len = ret;
+ }
+ else if (errno != ENOATTR)
+ call_arg_warn ("fgetxattr", file_name);
+#endif
+}
+#endif
+
+static void xattrs__acls_get_a(struct tar_stat_info *st,
+ char const *file_name, int fd,
+ char **ret_ptr, size_t *ret_len)
+{ /* "system.posix_acl_access" */
+#ifdef HAVE_LIBACL
+ char *val = NULL;
+ size_t len;
+ acl_t acl;
+
+ if (fd != -1)
+ {
+ if ((acl = acl_get_fd (fd)) == (acl_t)NULL)
+ {
+ if (errno != ENOTSUP)
+ call_arg_warn ("acl_get_fd", file_name);
+ return;
+ }
+ }
+ else if ((acl = acl_get_file (file_name, ACL_TYPE_ACCESS)) == (acl_t)NULL)
+ {
+ if (errno != ENOTSUP)
+ call_arg_warn ("acl_get_file", 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 = xstrndup (val, len);
+ *ret_len = len;
+
+ acl_free (val);
+#endif
+}
+
+static void xattrs__acls_get_d(struct tar_stat_info *st,
+ char const *file_name,
+ char **ret_ptr, size_t *ret_len)
+{ /* "system.posix_acl_default" */
+#ifdef HAVE_LIBACL
+ char *val = NULL;
+ size_t len;
+ acl_t acl;
+
+ if ((acl = acl_get_file (file_name, ACL_TYPE_DEFAULT)) == (acl_t)NULL)
+ {
+ if (errno != ENOTSUP)
+ call_arg_warn ("acl_get_file", 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 = xstrndup (val, len);
+ *ret_len = len;
+
+ acl_free (val);
+#endif
+}
+
+void xattrs_acls_get(struct tar_stat_info *st, char const *file_name, int fd,
+ int xisfile)
+{
+ if (acls_option > 0)
+ {
+#ifndef HAVE_LIBACL
+ static int done = 0;
+ if (!done)
+ WARN ((0, 0, _("ACL support requested, but not available")));
+ done = 1;
+#endif
+ xattrs__acls_get_a (st, file_name, fd,
+ &st->acls_a_ptr, &st->acls_a_len);
+ if (!xisfile)
+ xattrs__acls_get_d (st, file_name,
+ &st->acls_d_ptr, &st->acls_d_len);
+ }
+}
+
+void xattrs_selinux_get(struct tar_stat_info *st, char const *file_name, int fd)
+{
+ if (selinux_context_option > 0)
+ {
+#ifndef HAVE_LIBSELINUX
+ static int done = 0;
+ if (!done)
+ WARN ((0, 0, _("SELinux support requested, but not available")));
+ done = 1;
+#else
+ if (fd == -1)
+ {
+ if ((lgetfilecon (file_name, &st->cntx_name) == -1) && (errno != ENOTSUP) && (errno != ENODATA))
+ call_arg_warn ("lgetfilecon", file_name);
+ }
+ else if ((fgetfilecon (fd, &st->cntx_name) == -1) && (errno != ENOTSUP) && (errno != ENODATA))
+ call_arg_warn ("fgetfilecon", file_name);
+#endif
+ }
+}
+
+void xattrs_xattrs_get(struct tar_stat_info *st, char const *file_name, int fd)
+{
+ if (xattrs_option > 0)
+ { /* get all xattrs ... this include security.* and system.* if
+ available. We filter them here, but we have to filter them
+ in xattrs_xattrs_set() anyway.
+ */
+ static ssize_t xsz = 1024;
+ static char *xatrs = NULL;
+ ssize_t xret = -1;
+
+#ifndef HAVE_XATTRS
+ static int done = 0;
+ if ((xattrs_option > 0) && !done)
+ WARN ((0, 0, _("Xattr support requested, but not available")));
+ done = 1;
+#else
+
+ if (!xatrs) xatrs = xmalloc (xsz);
+
+ while (((fd == -1) ?
+ ((xret = listxattr (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 == -1) ? "listxattrs" : "flistxattrs", 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;
+
+// if (strncmp (attr, "user.", strlen("user.")) &&
+// strncmp (attr, "trusted.", strlen("trusted.")))
+// goto next_attr; /* only store normal xattrs */
+
+ while (((fd == -1) ?
+ ((aret = getxattr (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 ("fgetxattr", file_name);
+
+ next_attr:
+ 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)
+{
+#ifdef HAVE_XATTRS
+ if (ptr)
+ {
+ const char *sysname = "setxattr";
+ int ret = -1;
+
+ if (typeflag != SYMTYPE)
+ ret = setxattr (file_name, attr, ptr, len, 0);
+ else
+ {
+ sysname = "lsetxattr";
+ ret = lsetxattr (file_name, attr, ptr, len, 0);
+ }
+
+ if ((ret == -1) && (errno == EPERM))
+ call_arg_warn(sysname, file_name);
+ else if ((ret == -1) && (errno != EOPNOTSUPP))
+ call_arg_error(sysname, file_name);
+ }
+#endif
+}
+
+/* convert unix permissions into an ACL ... needed due to "default" ACLs */
+#ifdef HAVE_LIBACL
+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));
+}
+#endif
+
+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)
+{ /* "system.posix_acl_access" */
+#ifdef HAVE_LIBACL
+ 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 (file_name, type, acl) == -1)
+ {
+ if (errno != ENOTSUP)
+ call_arg_warn ("acl_set_file", file_name);
+ }
+ acl_free (acl);
+#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_LIBACL
+ static int done = 0;
+ if (!done)
+ WARN ((0, 0, _("ACL support requested, but not available")));
+ done = 1;
+#else
+ xattrs__acls_set (st, file_name, ACL_TYPE_ACCESS,
+ st->acls_a_ptr, st->acls_a_len);
+ if (S_ISDIR (st->stat.st_mode))
+ xattrs__acls_set (st, file_name, ACL_TYPE_DEFAULT,
+ st->acls_d_ptr, st->acls_d_len);
+#endif
+ }
+}
+
+void xattrs_selinux_set(struct tar_stat_info const *st,
+ char const *file_name, char typeflag)
+{
+ if ((selinux_context_option >= 0) && st->cntx_name)
+ {
+ const char *sysname = "setfilecon";
+ int ret = -1;
+
+#ifndef HAVE_LIBSELINUX
+ static int done = 0;
+ if (!done)
+ WARN ((0, 0, _("SELinux support requested, but not available")));
+ done = 1;
+#else
+ if (typeflag != SYMTYPE)
+ ret = setfilecon (file_name, st->cntx_name);
+ else
+ {
+ sysname = "lsetfilecon";
+ ret = lsetfilecon (file_name, st->cntx_name);
+ }
+
+ /* do not print warnings when SELinux is disabled */
+ if ((ret == -1) && (errno != EPERM) && (errno != ENOTSUP))
+ call_arg_error(sysname, file_name);
+#endif
+ }
+}
+
+void xattrs_xattrs_set(struct tar_stat_info const *st,
+ char const *file_name, char typeflag)
+{
+ if ((xattrs_option >= 0) && st->xattr_map_size)
+ {
+ size_t scan = 0;
+
+#ifndef HAVE_XATTRS
+ static int done = 0;
+ if (!done)
+ WARN ((0, 0, _("Xattr support requested, but not available")));
+ done = 1;
+#else
+ while (scan < st->xattr_map_size)
+ {
+ char *keyword = st->xattr_map[scan].xkey;
+
+ /* assert (!memcpy (keyword, "SCHILY.xattr.", strlen("SCHILY.xattr."))); */
+ keyword += strlen("SCHILY.xattr.");
+
+// if (strncmp (keyword, "user.", strlen("user.")) &&
+// strncmp (keyword, "trusted.", strlen("trusted.")))
+// continue; /* don't try and set anything but normal xattrs */
+
+ /* should we ignore trusted.* EPERM errors when not root ? */
+ xattrs__fd_set (st, file_name, typeflag, keyword,
+ st->xattr_map[scan].xval_ptr,
+ st->xattr_map[scan].xval_len);
+
+ ++scan;
+ }
+#endif
+ }
+}
+
diff --git a/src/xattrs.h b/src/xattrs.h
new file mode 100644
index 0000000..ebbd5c6
--- /dev/null
+++ b/src/xattrs.h
@@ -0,0 +1,14 @@
+
+extern void xattrs_acls_get(struct tar_stat_info *st,
+ char const *file_name, int fd, int xisfile);
+extern void xattrs_selinux_get(struct tar_stat_info *st,
+ char const *file_name, int fd);
+extern void xattrs_xattrs_get(struct tar_stat_info *st,
+ char const *file_name, 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);
diff --git a/src/xheader.c b/src/xheader.c
index aed2eb0..c89bbf8 100644
--- a/src/xheader.c
+++ b/src/xheader.c
@@ -82,6 +82,74 @@ struct keyword_list
char *value;
};
+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.");
+ tmp = 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;
+ }
+}
+
/* List of keyword patterns set by delete= option */
static struct keyword_list *keyword_pattern_list;
@@ -429,6 +497,7 @@ struct xhdr_tab
struct xheader *, void const *data);
void (*decoder) (struct tar_stat_info *, char const *, char const *, size_t);
bool protect;
+ bool prefix;
};
/* This declaration must be extern, because ISO C99 section 6.9.2
@@ -445,8 +514,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;
}
@@ -456,7 +534,7 @@ xheader_protected_pattern_p (const char *pattern)
struct xhdr_tab const *p;
for (p = xhdr_tab; p->keyword; p++)
- if (p->protect && fnmatch (pattern, p->keyword, 0) == 0)
+ if (!p->prefix && p->protect && fnmatch (pattern, p->keyword, 0) == 0)
return true;
return false;
}
@@ -467,7 +545,7 @@ xheader_protected_keyword_p (const char *keyword)
struct xhdr_tab const *p;
for (p = xhdr_tab; p->keyword; p++)
- if (p->protect && strcmp (p->keyword, keyword) == 0)
+ if (!p->prefix && p->protect && strcmp (p->keyword, keyword) == 0)
return true;
return false;
}
@@ -1419,6 +1497,71 @@ volume_filename_decoder (struct tar_stat_info *st,
}
static void
+xattr_selinux_coder (struct tar_stat_info const *st, char const *keyword,
+ struct xheader *xhdr, void const *data)
+{
+ code_string (st->cntx_name, keyword, xhdr);
+}
+
+static void
+xattr_selinux_decoder (struct tar_stat_info *st,
+ char const *keyword, char const *arg, size_t size)
+{
+ decode_string (&st->cntx_name, arg);
+}
+
+static void
+xattr_acls_a_coder (struct tar_stat_info const *st , char const *keyword,
+ struct xheader *xhdr, void const *data)
+{
+ xheader_print_n (xhdr, keyword, st->acls_a_ptr, st->acls_a_len);
+}
+
+static void
+xattr_acls_a_decoder (struct tar_stat_info *st,
+ char const *keyword, char const *arg, size_t size)
+{
+ st->acls_a_ptr = xmemdup (arg, size + 1);
+ st->acls_a_len = size;
+}
+
+static void
+xattr_acls_d_coder (struct tar_stat_info const *st , char const *keyword,
+ struct xheader *xhdr, void const *data)
+{
+ xheader_print_n (xhdr, keyword, st->acls_d_ptr, st->acls_d_len);
+}
+
+static void
+xattr_acls_d_decoder (struct tar_stat_info *st,
+ char const *keyword, char const *arg, size_t size)
+{
+ st->acls_d_ptr = xmemdup (arg, size + 1);
+ st->acls_d_len = size;
+}
+
+static void
+xattr_coder (struct tar_stat_info const *st , char const *keyword,
+ struct xheader *xhdr, void const *data)
+{
+ struct xattr_array *xattr_map = st->xattr_map;
+ const size_t *off = data;
+ xheader_print_n (xhdr, keyword,
+ xattr_map[*off].xval_ptr, xattr_map[*off].xval_len);
+}
+
+static void
+xattr_decoder (struct tar_stat_info *st,
+ char const *keyword, char const *arg, size_t size)
+{
+ char *xstr = 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 xheader *xhdr, void const *data)
{
@@ -1455,18 +1598,18 @@ sparse_minor_decoder (struct tar_stat_info *st,
}
struct xhdr_tab const xhdr_tab[] = {
- { "atime", atime_coder, atime_decoder, false },
- { "comment", dummy_coder, dummy_decoder, false },
- { "charset", dummy_coder, dummy_decoder, false },
- { "ctime", ctime_coder, ctime_decoder, false },
- { "gid", gid_coder, gid_decoder, false },
- { "gname", gname_coder, gname_decoder, false },
- { "linkpath", linkpath_coder, linkpath_decoder, false },
- { "mtime", mtime_coder, mtime_decoder, false },
- { "path", path_coder, path_decoder, false },
- { "size", size_coder, size_decoder, false },
- { "uid", uid_coder, uid_decoder, false },
- { "uname", uname_coder, uname_decoder, false },
+ { "atime", atime_coder, atime_decoder, false, false },
+ { "comment", dummy_coder, dummy_decoder, false, false },
+ { "charset", dummy_coder, dummy_decoder, false, false },
+ { "ctime", ctime_coder, ctime_decoder, false, false },
+ { "gid", gid_coder, gid_decoder, false, false },
+ { "gname", gname_coder, gname_decoder, false, false },
+ { "linkpath", linkpath_coder, linkpath_decoder, false, false },
+ { "mtime", mtime_coder, mtime_decoder, false, false },
+ { "path", path_coder, path_decoder, false, false },
+ { "size", size_coder, size_decoder, false, false },
+ { "uid", uid_coder, uid_decoder, false, false },
+ { "uname", uname_coder, uname_decoder, false, false },
/* Sparse file handling */
{ "GNU.sparse.name", path_coder, path_decoder,
@@ -1481,25 +1624,25 @@ struct xhdr_tab const xhdr_tab[] = {
true },
/* tar 1.14 - 1.15.90 keywords. */
- { "GNU.sparse.size", sparse_size_coder, sparse_size_decoder, true },
+ { "GNU.sparse.size", sparse_size_coder, sparse_size_decoder, true, 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,
- true },
+ true, false },
{ "GNU.sparse.numbytes", sparse_numbytes_coder, sparse_numbytes_decoder,
- true },
+ true, 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, false },
+ sparse_map_decoder, false, false },
{ "GNU.dumpdir", dumpdir_coder, dumpdir_decoder,
- true },
+ true, 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, true },
+ { "GNU.volume.label", volume_label_coder, volume_label_decoder, true, false },
/* These may be present in a first global header of the archive.
They provide the same functionality as GNUTYPE_MULTIVOL header.
@@ -1508,9 +1651,38 @@ 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,
- true },
- { "GNU.volume.size", volume_size_coder, volume_size_decoder, true },
- { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder, true },
-
+ true, false },
+ { "GNU.volume.size", volume_size_coder, volume_size_decoder, true, false },
+ { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder,
+ true, false },
+
+ /* We get the SELinux value from filecon, so add a namespace for SELinux
+ instead of storing it in SCHILY.xattr.* (which would be RAW). */
+ { "RHT.security.selinux",
+ xattr_selinux_coder, xattr_selinux_decoder, false, false },
+
+ /* ACLs, use the star format... */
+ { "SCHILY.acl.access",
+ xattr_acls_a_coder, xattr_acls_a_decoder, false, false },
+
+ { "SCHILY.acl.default",
+ xattr_acls_d_coder, xattr_acls_d_decoder, false, false },
+
+ /* FIXME: These are compat. for FC-6 ... we shipped a tar using the generic
+ header names by accident. */
+ { "SCHILY.xattr.security.selinux",
+ xattr_selinux_coder, xattr_selinux_decoder, false, false },
+ { "SCHILY.xattr.system.posix_acl_access",
+ xattr_acls_a_coder, xattr_acls_a_decoder, false, false },
+ { "SCHILY.xattr.system.posix_acl_default",
+ xattr_acls_d_coder, xattr_acls_d_decoder, false, false },
+
+ /* xattr's, use the star format note we only save the user/trusted varients... */
+ { "SCHILY.xattr.user", xattr_coder, xattr_decoder, false, true },
+ { "SCHILY.xattr.trusted", xattr_coder, xattr_decoder, false, true },
+ { "SCHILY.xattr.security.SMACK64", xattr_coder, xattr_decoder, false, true },
+
+ /* ignore everything else in the xattr namespaces... */
+ { "SCHILY.xattr", dummy_coder, dummy_decoder, false, true },
{ NULL, NULL, NULL, false }
};