]> git.ipfire.org Git - people/arne_f/ipfire-3.x.git/blame - tar/patches/tar-1.24-xattrs.patch
Move all packages to root.
[people/arne_f/ipfire-3.x.git] / tar / patches / tar-1.24-xattrs.patch
CommitLineData
bd523de6
MT
1diff -urNp tar-1.24-orig/configure.ac tar-1.24/configure.ac
2--- tar-1.24-orig/configure.ac 2010-10-24 23:35:35.000000000 +0200
3+++ tar-1.24/configure.ac 2010-10-25 10:24:52.548214037 +0200
9f0833cd 4@@ -44,7 +44,7 @@ AC_CHECK_HEADERS_ONCE(fcntl.h linux/fd.h
bd523de6 5 sys/param.h sys/device.h sys/gentape.h \
547b54ef
MT
6 sys/inet.h sys/io/trioctl.h \
7 sys/mtio.h sys/time.h sys/tprintf.h sys/tape.h \
8- unistd.h locale.h)
9f0833cd 9+ unistd.h locale.h attr/xattr.h sys/acl.h)
547b54ef
MT
10
11 AC_CHECK_HEADERS([sys/buf.h], [], [],
12 [#if HAVE_SYS_PARAM_H
9f0833cd 13@@ -91,6 +91,12 @@ gl_INIT
547b54ef
MT
14 tar_PAXUTILS
15
bd523de6 16 AC_CHECK_FUNCS_ONCE([fchmod fchown fsync lstat mkfifo readlink symlink])
547b54ef
MT
17+AC_CHECK_FUNCS(getxattr fgetxattr lgetxattr \
18+ setxattr fsetxattr lsetxattr \
19+ listxattr flistxattr llistxattr,
20+ AC_DEFINE(HAVE_XATTRS,,[Define if we have a working extended attributes]),)
547b54ef
MT
21+AC_CHECK_LIB(acl, acl_get_fd)
22+
23 AC_CHECK_DECLS([getgrgid],,, [#include <grp.h>])
24 AC_CHECK_DECLS([getpwuid],,, [#include <pwd.h>])
25 AC_CHECK_DECLS([time],,, [#include <time.h>])
9f0833cd 26@@ -214,6 +220,7 @@ AC_DEFINE_UNQUOTED(DEFAULT_QUOTING_STYLE
547b54ef
MT
27 # Iconv
28 AM_ICONV
29 AC_CHECK_HEADERS(iconv.h)
547b54ef
MT
30+AC_CHECK_HEADERS(attr/xattr.h)
31 AC_CHECK_TYPE(iconv_t,:,
32 AC_DEFINE(iconv_t, int,
33 [Conversion descriptor type]),
9f0833cd
MT
34@@ -223,6 +230,17 @@ AC_CHECK_TYPE(iconv_t,:,
35 #endif
36 ])
37
38+AC_ARG_ENABLE(selinux,
39+ AC_HELP_STRING([--enable-selinux],
40+ [enable SELinux support (disabled by default)]),
41+ [selinux_enabled=$enableval],
42+ [selinux_enabled=no])
43+
44+if test "x$selinux_enabled" = xyes; then
45+ AC_CHECK_LIB(selinux, getfilecon)
46+ AC_CHECK_HEADERS(selinux/selinux.h)
47+fi
48+
49 # Gettext.
50 AM_GNU_GETTEXT([external], [need-formatstring-macros])
51 AM_GNU_GETTEXT_VERSION([0.16])
bd523de6
MT
52diff -urNp tar-1.24-orig/doc/tar.texi tar-1.24/doc/tar.texi
53--- tar-1.24-orig/doc/tar.texi 2010-10-24 20:07:54.000000000 +0200
54+++ tar-1.24/doc/tar.texi 2010-10-25 10:24:52.554213688 +0200
55@@ -2370,6 +2370,10 @@ Normally when creating an archive, @comm
547b54ef
MT
56 @samp{/} from member names. This option disables that behavior.
57 @xref{absolute}.
58
59+@opsummary{acl}
60+@item --acls
61+Causes @command{tar} to store ACL's. @xref{Attributes}.
62+
63 @opsummary{after-date}
64 @item --after-date
65
bd523de6 66@@ -2915,6 +2919,10 @@ contents have changed (as opposed to jus
547b54ef
MT
67 also back up files for which any status information has
68 changed). @xref{after}.
69
70+@opsummary{no-acl}
71+@item --no-acls
72+Causes @command{tar} not to store and not to extract ACL's. @xref{Attributes}.
73+
74 @opsummary{no-anchored}
75 @item --no-anchored
76 An exclude pattern can match any subsequence of the name's components.
bd523de6 77@@ -2998,11 +3006,21 @@ locations. Usually @command{tar} determ
9f0833cd
MT
78 the archive can be seeked or not. Use this option to disable this
79 mechanism.
547b54ef
MT
80
81+@opsummary{no-selinux}
82+@item --no-selinux
83+Causes @command{tar} not to store and not to extract SELinux security context.
84+@xref{Attributes}.
85+
86 @opsummary{no-unquote}
87 @item --no-unquote
88 Treat all input file or member names literally, do not interpret
89 escape sequences. @xref{input name quoting}.
90
91+@opsummary{no-xattrs}
92+@item --no-xattrs
93+Causes @command{tar} not to store and not to extract xattrs. This option also
94+enables @option{--no-selinux} and @option{--no-acls}. @xref{Attributes}.
95+
96 @opsummary{no-wildcards}
97 @item --no-wildcards
98 Do not use wildcards.
bd523de6 99@@ -3235,6 +3253,11 @@ in cases when such recognition fails. I
9f0833cd
MT
100 archive is open for reading (e.g. with @option{--list} or
101 @option{--extract} options).
547b54ef
MT
102
103+@opsummary{selinux}
104+@item --selinux
105+Causes @command{tar} to store SElinux security context. @xref{Attributes}.
106+
107+
108 @opsummary{show-defaults}
109 @item --show-defaults
110
bd523de6 111@@ -3448,6 +3471,11 @@ Enable or disable warning messages ident
9f0833cd
MT
112 messages are suppressed if @var{keyword} is prefixed with @samp{no-}.
113 @xref{warnings}.
547b54ef
MT
114
115+@opsummary{xattrs}
116+@item --xattrs
117+Causes @command{tar} to store xattrs. This option also enables
118+@option{--selinux} and @option{--acls}. @xref{Attributes}.
119+
120 @opsummary{wildcards}
121 @item --wildcards
122 Use wildcards when matching member names with patterns.
bd523de6 123@@ -8643,6 +8671,8 @@ implementation able to read @samp{ustar}
547b54ef
MT
124 most @samp{posix} archives as well, with the only exception that any
125 additional information (such as long file names etc.) will in such
126 case be extracted as plain text files along with the files it refers to.
127+This is the only format that can store ACLs, SELinux context and extended
128+attributes.
129
130 This archive format will be the default format for future versions
131 of @GNUTAR{}.
bd523de6 132@@ -9259,6 +9289,51 @@ Same as both @option{--same-permissions}
547b54ef
MT
133
134 This option is deprecated, and will be removed in @GNUTAR{} version 1.23.
135
136+@opindex acls
137+@item --acls
138+This option causes @command{tar} to store the current ACL in the archive.
139+
140+The @option{--acls} option has no equivalent short option name.
141+
142+@opindex selinux
143+@item --selinux
144+This option causes @command{tar} to store the current SELinux security context
145+information in the archive.
146+
147+The @option{--selinux} option has no equivalent short option name.
148+
149+@opindex xattrs
150+@item --xattrs
151+This option causes @command{tar} to store the current extended attributes in
152+the archive. This option also enables @option{--acls} and @option{--selinux} if
153+they haven't been set already.
154+
155+The @option{--xattrs} option has no equivalent short option name.
156+
157+@opindex no-acls
158+@item --no-acls
159+This option causes @command{tar} not to store the current ACL in the archive
160+and not to extract any ACL information in an archive.
161+
162+The @option{--no-acls} option has no equivalent short option name.
163+
164+@opindex no-selinux
165+@item --no-selinux
166+This option causes @command{tar} not to store the current SELinux security
167+context information in the archive and not to extract any SELinux information in
168+an archive.
169+
170+The @option{--no-selinux} option has no equivalent short option name.
171+
172+@opindex no-xattrs
173+@item --no-xattrs
174+This option causes @command{tar} not to store the current extended attributes in
175+the archive and not to extract any extended attributes in an archive. This
176+option also enables @option{--no-acls} and @option{--no-selinux} if
177+they haven't been set already.
178+
179+The @option{--no-xattrs} option has no equivalent short option name.
180+
181 @end table
182
183 @node Portability
bd523de6
MT
184diff -urNp tar-1.24-orig/src/common.h tar-1.24/src/common.h
185--- tar-1.24-orig/src/common.h 2010-10-24 20:07:54.000000000 +0200
186+++ tar-1.24/src/common.h 2010-10-25 10:24:52.558475456 +0200
187@@ -253,6 +253,15 @@ GLOBAL int same_owner_option;
547b54ef
MT
188 /* If positive, preserve permissions when extracting. */
189 GLOBAL int same_permissions_option;
190
191+/* If positive, save the SELinux context. */
192+GLOBAL int selinux_context_option;
193+
194+/* If positive, save the ACLs. */
195+GLOBAL int acls_option;
196+
197+/* If positive, save the user and root xattrs. */
198+GLOBAL int xattrs_option;
199+
200 /* When set, strip the given number of file name components from the file name
201 before extracting */
202 GLOBAL size_t strip_name_components;
bd523de6 203@@ -706,6 +715,9 @@ extern char *output_start;
547b54ef
MT
204
205 void update_archive (void);
206
207+/* Module attrs.c. */
208+#include "xattrs.h"
209+
210 /* Module xheader.c. */
211
bd523de6
MT
212 void xheader_decode (struct tar_stat_info *stat);
213@@ -726,6 +738,12 @@ bool xheader_string_end (struct xheader
547b54ef
MT
214 bool xheader_keyword_deleted_p (const char *kw);
215 char *xheader_format_name (struct tar_stat_info *st, const char *fmt,
216 size_t n);
217+void xheader_xattr_init(struct tar_stat_info *st);
218+void xheader_xattr_free(struct xattr_array *vals, size_t sz);
219+void xheader_xattr_copy(const struct tar_stat_info *st,
220+ struct xattr_array **vals, size_t *sz);
221+void xheader_xattr_add(struct tar_stat_info *st,
222+ const char *key, const char *val, size_t len);
223
224 /* Module system.c */
225
bd523de6
MT
226diff -urNp tar-1.24-orig/src/create.c tar-1.24/src/create.c
227--- tar-1.24-orig/src/create.c 2010-10-24 20:07:54.000000000 +0200
228+++ tar-1.24/src/create.c 2010-10-25 10:24:52.560213618 +0200
547b54ef
MT
229@@ -24,6 +24,7 @@
230 #include <quotearg.h>
231
232 #include "common.h"
233+
234 #include <hash.h>
235
bd523de6
MT
236 /* Error number to use when an impostor is discovered.
237@@ -934,6 +935,30 @@ start_header (struct tar_stat_info *st)
547b54ef
MT
238 GNAME_TO_CHARS (st->gname, header->header.gname);
239 }
240
241+ if (archive_format == POSIX_FORMAT)
242+ {
243+ if (acls_option > 0)
244+ {
245+ if (st->acls_a_ptr)
246+ xheader_store ("SCHILY.acl.access", st, NULL);
247+ if (st->acls_d_ptr)
248+ xheader_store ("SCHILY.acl.default", st, NULL);
249+ }
250+ if ((selinux_context_option > 0) && st->cntx_name)
251+ xheader_store ("RHT.security.selinux", st, NULL);
252+ if (xattrs_option > 0)
253+ {
254+ size_t scan_xattr = 0;
255+ struct xattr_array *xattr_map = st->xattr_map;
9f0833cd 256+
547b54ef
MT
257+ while (scan_xattr < st->xattr_map_size)
258+ {
259+ xheader_store (xattr_map[scan_xattr].xkey, st, &scan_xattr);
260+ ++scan_xattr;
261+ }
262+ }
263+ }
264+
265 return header;
266 }
267
bd523de6
MT
268@@ -1709,6 +1734,10 @@ dump_file0 (struct tar_stat_info *st, ch
269 bool ok;
270 struct stat final_stat;
547b54ef
MT
271
272+ xattrs_acls_get(st, p, fd, !is_dir);
273+ xattrs_selinux_get(st, p, fd);
274+ xattrs_xattrs_get(st, p, fd);
275+
276 if (is_dir)
277 {
278 const char *tag_file_name;
bd523de6 279@@ -1826,6 +1855,9 @@ dump_file0 (struct tar_stat_info *st, ch
9f0833cd
MT
280 if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT) < size)
281 write_long_link (st);
282
283+ xattrs_selinux_get(st, p, -1);
284+ xattrs_xattrs_get(st, p, -1);
285+
286 block_ordinal = current_block_ordinal ();
287 st->stat.st_size = 0; /* force 0 size on symlink */
288 header = start_header (st);
bd523de6
MT
289@@ -1844,11 +1876,23 @@ dump_file0 (struct tar_stat_info *st, ch
290 }
291 #endif
292 else if (S_ISCHR (st->stat.st_mode))
293- type = CHRTYPE;
294+ {
295+ type = CHRTYPE;
296+ xattrs_selinux_get(st, p, -1);
297+ xattrs_xattrs_get(st, p, -1);
298+ }
299 else if (S_ISBLK (st->stat.st_mode))
300- type = BLKTYPE;
301+ {
302+ type = BLKTYPE;
303+ xattrs_selinux_get(st, p, -1);
304+ xattrs_xattrs_get(st, p, -1);
305+ }
306 else if (S_ISFIFO (st->stat.st_mode))
307- type = FIFOTYPE;
308+ {
309+ type = FIFOTYPE;
310+ xattrs_selinux_get(st, p, -1);
311+ xattrs_xattrs_get(st, p, -1);
312+ }
313 else if (S_ISSOCK (st->stat.st_mode))
314 {
315 WARNOPT (WARN_FILE_IGNORED,
316diff -urNp tar-1.24-orig/src/extract.c tar-1.24/src/extract.c
317--- tar-1.24-orig/src/extract.c 2010-10-24 20:07:54.000000000 +0200
318+++ tar-1.24/src/extract.c 2010-10-25 10:35:10.903214037 +0200
319@@ -97,6 +97,14 @@ struct delayed_set_stat
320 /* Directory that the name is relative to. */
321 int change_dir;
322
323+ /* extended attributes*/
547b54ef
MT
324+ char *cntx_name;
325+ char *acls_a_ptr;
326+ size_t acls_a_len;
327+ char *acls_d_ptr;
328+ size_t acls_d_len;
329+ size_t xattr_map_size; /* Size of the xattr map */
330+ struct xattr_array *xattr_map;
bd523de6
MT
331 /* Length and contents of name. */
332 size_t file_name_len;
547b54ef 333 char file_name[1];
bd523de6 334@@ -134,6 +142,18 @@ struct delayed_link
547b54ef
MT
335 hard-linked together. */
336 struct string_list *sources;
337
338+ /* SELinux context */
339+ char *cntx_name;
9f0833cd 340+
547b54ef
MT
341+ /* ACLs */
342+ char *acls_a_ptr;
343+ size_t acls_a_len;
344+ char *acls_d_ptr;
345+ size_t acls_d_len;
9f0833cd 346+
547b54ef
MT
347+ size_t xattr_map_size; /* Size of the xattr map */
348+ struct xattr_array *xattr_map;
9f0833cd 349+
547b54ef
MT
350 /* The desired target of the desired link. */
351 char target[1];
352 };
bd523de6
MT
353@@ -335,6 +355,10 @@ set_stat (char const *file_name,
354 utime_error (file_name);
547b54ef
MT
355 }
356
357+ xattrs_acls_set(st, file_name, typeflag);
358+ xattrs_selinux_set(st, file_name, typeflag);
359+ xattrs_xattrs_set(st, file_name, typeflag);
360+
bd523de6 361 if (0 < same_owner_option && ! interdir)
547b54ef 362 {
bd523de6
MT
363 /* Some systems allow non-root users to give files away. Once this
364@@ -431,6 +455,36 @@ delay_set_stat (char const *file_name, s
365 data->atflag = atflag;
547b54ef 366 data->after_links = 0;
bd523de6 367 data->change_dir = chdir_current;
547b54ef 368+ data->cntx_name = NULL;
bd523de6
MT
369+ if (st)
370+ assign_string (&data->cntx_name, st->cntx_name);
371+ if (st && st->acls_a_ptr)
547b54ef
MT
372+ {
373+ data->acls_a_ptr = xmemdup(st->acls_a_ptr, st->acls_a_len + 1);
374+ data->acls_a_len = st->acls_a_len;
375+ }
376+ else
377+ {
378+ data->acls_a_ptr = NULL;
379+ data->acls_a_len = 0;
380+ }
bd523de6 381+ if (st && st->acls_d_ptr)
547b54ef
MT
382+ {
383+ data->acls_d_ptr = xmemdup(st->acls_d_ptr, st->acls_d_len + 1);
384+ data->acls_d_len = st->acls_d_len;
385+ }
386+ else
387+ {
388+ data->acls_d_ptr = NULL;
389+ data->acls_d_len = 0;
390+ }
bd523de6
MT
391+ if (st)
392+ xheader_xattr_copy (st, &data->xattr_map, &data->xattr_map_size);
393+ else
394+ {
395+ data->xattr_map = NULL;
396+ data->xattr_map_size = 0;
397+ }
547b54ef
MT
398 strcpy (data->file_name, file_name);
399 delayed_set_stat_head = data;
bd523de6
MT
400 if (must_be_dot_or_slash (file_name))
401@@ -661,6 +708,31 @@ maybe_recoverable (char *file_name, bool
402 return RECOVER_NO;
9f0833cd
MT
403 }
404
405+/* Restore stat extended attributes (xattr) for FILE_NAME, using information
406+ given in *ST. Restore before extraction because they may affect layout.
407+ If not restoring permissions, invert the
408+ INVERT_PERMISSIONS bits from the file's current permissions.
409+ TYPEFLAG specifies the type of the file.
410+ FILE_CREATED indicates set_xattr has created the file */
411+static int
412+set_xattr (char const *file_name, struct tar_stat_info const *st,
413+ mode_t invert_permissions, char typeflag, int *file_created)
414+{
415+ int status = 0;
bd523de6 416+ bool interdir_made = false;
9f0833cd
MT
417+
418+ if ((xattrs_option >= 0) && st->xattr_map_size) {
419+ mode_t mode = current_stat_info.stat.st_mode & MODE_RWX & ~ current_umask;
420+
421+ do
422+ status = mknod (file_name, mode ^ invert_permissions, 0);
bd523de6 423+ while (status && maybe_recoverable ((char *)file_name, false, &interdir_made));
9f0833cd
MT
424+ xattrs_xattrs_set(st, file_name, typeflag);
425+ *file_created = 1;
426+ }
427+ return(status);
428+}
429+
430 /* Fix the statuses of all directories whose statuses need fixing, and
431 which are not ancestors of FILE_NAME. If AFTER_LINKS is
432 nonzero, do this for all such directories; otherwise, stop at the
bd523de6 433@@ -721,12 +793,23 @@ apply_nonancestor_delayed_set_stat (char
547b54ef
MT
434 sb.stat.st_gid = data->gid;
435 sb.atime = data->atime;
436 sb.mtime = data->mtime;
bd523de6
MT
437+ sb.cntx_name = data->cntx_name;
438+ sb.acls_a_ptr = data->acls_a_ptr;
439+ sb.acls_a_len = data->acls_a_len;
440+ sb.acls_d_ptr = data->acls_d_ptr;
441+ sb.acls_d_len = data->acls_d_len;
442+ sb.xattr_map = data->xattr_map;
443+ sb.xattr_map_size = data->xattr_map_size;
444 set_stat (data->file_name, &sb,
445 -1, current_mode, current_mode_mask,
446 DIRTYPE, data->interdir, data->atflag);
547b54ef
MT
447 }
448
449 delayed_set_stat_head = data->next;
450+ xheader_xattr_free (data->xattr_map, data->xattr_map_size);
451+ free (data->cntx_name);
452+ free (data->acls_a_ptr);
453+ free (data->acls_d_ptr);
454 free (data);
455 }
456 }
bd523de6 457@@ -842,6 +925,7 @@ extract_dir (char *file_name, int typefl
9f0833cd
MT
458
459 static int
bd523de6
MT
460 open_output_file (char const *file_name, int typeflag, mode_t mode,
461+ int file_created,
462 mode_t *current_mode, mode_t *current_mode_mask)
9f0833cd
MT
463 {
464 int fd;
bd523de6
MT
465@@ -852,6 +936,10 @@ open_output_file (char const *file_name,
466 ? O_TRUNC | (dereference_option ? 0 : O_NOFOLLOW)
9f0833cd
MT
467 : O_EXCL));
468
469+ /* File might be created in set_xattr. So clear O_EXCL to avoid open() failure */
470+ if (file_created)
471+ openflag = openflag & ~O_EXCL;
472+
bd523de6
MT
473 if (typeflag == CONTTYPE)
474 {
475 static int conttype_diagnosed;
476@@ -908,6 +996,7 @@ extract_file (char *file_name, int typef
477 bool interdir_made = false;
478 mode_t mode = (current_stat_info.stat.st_mode & MODE_RWX
479 & ~ (0 < same_owner_option ? S_IRWXG | S_IRWXO : 0));
480+ mode_t invert_permissions = 0 < same_owner_option ? mode & (S_IRWXG | S_IRWXO) : 0;
481 mode_t current_mode = 0;
482 mode_t current_mode_mask = 0;
483
484@@ -924,7 +1013,17 @@ extract_file (char *file_name, int typef
485 }
9f0833cd
MT
486 else
487 {
9f0833cd
MT
488+ int file_created = 0;
489+ if (set_xattr (file_name, &current_stat_info, invert_permissions,
490+ typeflag, &file_created))
491+ {
492+ skip_member ();
493+ open_error (file_name);
494+ return 1;
495+ }
496+
bd523de6
MT
497 while ((fd = open_output_file (file_name, typeflag, mode,
498+ file_created,
499 &current_mode, &current_mode_mask))
500 < 0)
501 {
502@@ -1065,6 +1164,13 @@ create_placeholder_file (char *file_name
547b54ef
MT
503 + strlen (file_name) + 1);
504 p->sources->next = 0;
505 strcpy (p->sources->string, file_name);
506+ p->cntx_name = NULL;
9f0833cd 507+ assign_string (&p->cntx_name, current_stat_info.cntx_name);
547b54ef
MT
508+ p->acls_a_ptr = NULL;
509+ p->acls_a_len = 0;
510+ p->acls_d_ptr = NULL;
511+ p->acls_d_len = 0;
9f0833cd 512+ xheader_xattr_copy (&current_stat_info, &p->xattr_map, &p->xattr_map_size);
547b54ef
MT
513 strcpy (p->target, current_stat_info.link_name);
514
515 h = delayed_set_stat_head;
bd523de6 516@@ -1499,6 +1605,13 @@ apply_delayed_links (void)
547b54ef 517 st1.stat.st_gid = ds->gid;
bd523de6
MT
518 st1.atime = ds->atime;
519 st1.mtime = ds->mtime;
547b54ef
MT
520+ st1.cntx_name = ds->cntx_name;
521+ st1.acls_a_ptr = ds->acls_a_ptr;
522+ st1.acls_a_len = ds->acls_a_len;
523+ st1.acls_d_ptr = ds->acls_d_ptr;
524+ st1.acls_d_len = ds->acls_d_len;
525+ st1.xattr_map = ds->xattr_map;
526+ st1.xattr_map_size = ds->xattr_map_size;
bd523de6
MT
527 set_stat (source, &st1, -1, 0, 0, SYMTYPE,
528 false, AT_SYMLINK_NOFOLLOW);
547b54ef 529 valid_source = source;
bd523de6 530@@ -1513,6 +1626,9 @@ apply_delayed_links (void)
9f0833cd
MT
531 sources = next;
532 }
533
534+ xheader_xattr_free (ds->xattr_map, ds->xattr_map_size);
535+ free (ds->cntx_name);
536+
537 {
538 struct delayed_link *next = ds->next;
539 free (ds);
bd523de6
MT
540diff -urNp tar-1.24-orig/src/list.c tar-1.24/src/list.c
541--- tar-1.24-orig/src/list.c 2010-10-25 09:15:14.216463863 +0200
542+++ tar-1.24/src/list.c 2010-10-25 10:24:52.563213968 +0200
543@@ -597,6 +597,13 @@ decode_header (union block *header, stru
547b54ef
MT
544 assign_string (&stat_info->gname,
545 header->header.gname[0] ? header->header.gname : NULL);
546
547+ stat_info->acls_a_ptr = NULL;
548+ stat_info->acls_a_len = 0;
549+ stat_info->acls_d_ptr = NULL;
550+ stat_info->acls_d_len = 0;
551+ stat_info->cntx_name = NULL;
552+ xheader_xattr_init(stat_info);
9f0833cd 553+
547b54ef
MT
554 if (format == OLDGNU_FORMAT && incremental_option)
555 {
556 stat_info->atime.tv_sec = TIME_FROM_HEADER (header->oldgnu_header.atime);
bd523de6
MT
557diff -urNp tar-1.24-orig/src/Makefile.am tar-1.24/src/Makefile.am
558--- tar-1.24-orig/src/Makefile.am 2010-10-24 20:07:54.000000000 +0200
559+++ tar-1.24/src/Makefile.am 2010-10-25 10:24:52.564214456 +0200
547b54ef
MT
560@@ -20,7 +20,7 @@
561
562 bin_PROGRAMS = tar
563
564-noinst_HEADERS = arith.h common.h tar.h
565+noinst_HEADERS = arith.h common.h tar.h xattrs.h
566 tar_SOURCES = \
567 buffer.c\
568 checkpoint.c\
9f0833cd
MT
569@@ -42,10 +42,11 @@ tar_SOURCES = \
570 unlink.c\
547b54ef 571 update.c\
9f0833cd
MT
572 utf8.c\
573- warning.c
574+ warning.c\
547b54ef
MT
575+ xattrs.c
576
9f0833cd 577 INCLUDES = -I$(top_srcdir)/gnu -I../ -I../gnu -I$(top_srcdir)/lib -I../lib
547b54ef 578
9f0833cd 579 LDADD = ../lib/libtar.a ../gnu/libgnu.a $(LIBINTL) $(LIBICONV)
547b54ef 580
bd523de6
MT
581-tar_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS)
582+tar_LDADD = $(LIBS) $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS)
583diff -urNp tar-1.24-orig/src/tar.c tar-1.24/src/tar.c
584--- tar-1.24-orig/src/tar.c 2010-10-24 20:07:55.000000000 +0200
585+++ tar-1.24/src/tar.c 2010-10-25 10:24:52.565223676 +0200
9f0833cd 586@@ -255,7 +255,8 @@ tar_set_quoting_style (char *arg)
547b54ef
MT
587
588 enum
589 {
590- ANCHORED_OPTION = CHAR_MAX + 1,
591+ ACLS_OPTION = CHAR_MAX + 1,
592+ ANCHORED_OPTION,
593 ATIME_PRESERVE_OPTION,
594 BACKUP_OPTION,
595 CHECK_DEVICE_OPTION,
bd523de6 596@@ -288,6 +289,7 @@ enum
547b54ef
MT
597 MODE_OPTION,
598 MTIME_OPTION,
599 NEWER_MTIME_OPTION,
600+ NO_ACLS_OPTION,
601 NO_ANCHORED_OPTION,
602 NO_AUTO_COMPRESS_OPTION,
603 NO_CHECK_DEVICE_OPTION,
bd523de6 604@@ -301,9 +303,11 @@ enum
547b54ef
MT
605 NO_SAME_OWNER_OPTION,
606 NO_SAME_PERMISSIONS_OPTION,
9f0833cd 607 NO_SEEK_OPTION,
547b54ef
MT
608+ NO_SELINUX_CONTEXT_OPTION,
609 NO_UNQUOTE_OPTION,
610 NO_WILDCARDS_MATCH_SLASH_OPTION,
611 NO_WILDCARDS_OPTION,
612+ NO_XATTR_OPTION,
613 NULL_OPTION,
614 NUMERIC_OWNER_OPTION,
615 OCCURRENCE_OPTION,
bd523de6 616@@ -325,6 +329,7 @@ enum
547b54ef
MT
617 RMT_COMMAND_OPTION,
618 RSH_COMMAND_OPTION,
619 SAME_OWNER_OPTION,
620+ SELINUX_CONTEXT_OPTION,
621 SHOW_DEFAULTS_OPTION,
622 SHOW_OMITTED_DIRS_OPTION,
623 SHOW_TRANSFORMED_NAMES_OPTION,
bd523de6 624@@ -340,7 +345,8 @@ enum
547b54ef 625 VOLNO_FILE_OPTION,
bd523de6 626 WARNING_OPTION,
547b54ef
MT
627 WILDCARDS_MATCH_SLASH_OPTION,
628- WILDCARDS_OPTION
629+ WILDCARDS_OPTION,
630+ XATTR_OPTION
631 };
632
633 const char *argp_program_version = "tar (" PACKAGE_NAME ") " VERSION;
bd523de6 634@@ -486,6 +492,10 @@ static struct argp_option options[] = {
547b54ef
MT
635 {NULL, 0, NULL, 0,
636 N_("Handling of file attributes:"), GRID },
637
9f0833cd 638+ {"acls", ACLS_OPTION, 0, 0,
547b54ef 639+ N_("Save the ACLs to the archive"), GRID+1 },
9f0833cd 640+ {"no-acls", NO_ACLS_OPTION, 0, 0,
547b54ef
MT
641+ N_("Don't extract the ACLs from the archive"), GRID+1 },
642 {"owner", OWNER_OPTION, N_("NAME"), 0,
643 N_("force NAME as owner for added files"), GRID+1 },
644 {"group", GROUP_OPTION, N_("NAME"), 0,
bd523de6 645@@ -516,6 +526,14 @@ static struct argp_option options[] = {
547b54ef
MT
646 {"preserve-order", 's', 0, 0,
647 N_("sort names to extract to match archive"), GRID+1 },
648 {"same-order", 0, 0, OPTION_ALIAS, NULL, GRID+1 },
9f0833cd 649+ {"selinux", SELINUX_CONTEXT_OPTION, 0, 0,
547b54ef 650+ N_("Save the SELinux context to the archive"), GRID+1 },
9f0833cd 651+ {"no-selinux", NO_SELINUX_CONTEXT_OPTION, 0, 0,
547b54ef 652+ N_("Don't extract the SELinux context from the archive"), GRID+1 },
9f0833cd 653+ {"xattrs", XATTR_OPTION, 0, 0,
547b54ef 654+ N_("Save the user/root xattrs to the archive"), GRID+1 },
9f0833cd 655+ {"no-xattrs", NO_XATTR_OPTION, 0, 0,
547b54ef
MT
656+ N_("Don't extract the user/root xattrs from the archive"), GRID+1 },
657 {"preserve", PRESERVE_OPTION, 0, 0,
658 N_("same as both -p and -s"), GRID+1 },
659 {"delay-directory-restore", DELAY_DIRECTORY_RESTORE_OPTION, 0, 0,
bd523de6 660@@ -2079,6 +2097,37 @@ parse_opt (int key, char *arg, struct ar
547b54ef
MT
661 same_permissions_option = -1;
662 break;
663
664+ case ACLS_OPTION:
665+ set_archive_format ("posix");
666+ acls_option = 1;
667+ break;
668+
669+ case NO_ACLS_OPTION:
670+ acls_option = -1;
671+ break;
672+
673+ case SELINUX_CONTEXT_OPTION:
674+ set_archive_format ("posix");
675+ selinux_context_option = 1;
676+ break;
677+
678+ case NO_SELINUX_CONTEXT_OPTION:
679+ selinux_context_option = -1;
680+ break;
681+
682+ case XATTR_OPTION:
683+ set_archive_format ("posix");
684+ if (!acls_option) acls_option = 1;
685+ if (!selinux_context_option) selinux_context_option = 1;
686+ xattrs_option = 1;
687+ break;
688+
689+ case NO_XATTR_OPTION:
690+ if (!acls_option) acls_option = -1;
691+ if (!selinux_context_option) selinux_context_option = -1;
692+ xattrs_option = -1;
693+ break;
694+
695 case RECURSION_OPTION:
696 recursion_option = FNM_LEADING_DIR;
697 break;
bd523de6 698@@ -2461,6 +2510,29 @@ decode_options (int argc, char **argv)
547b54ef
MT
699 || subcommand_option != LIST_SUBCOMMAND))
700 USAGE_ERROR ((0, 0, _("--pax-option can be used only on POSIX archives")));
701
702+ /* star create's non-POSIX typed archives with xattr support, so allow the
703+ extra headers */
704+ if ((acls_option > 0)
705+ && archive_format != POSIX_FORMAT
706+ && (subcommand_option != EXTRACT_SUBCOMMAND
707+ || subcommand_option != DIFF_SUBCOMMAND
708+ || subcommand_option != LIST_SUBCOMMAND))
709+ USAGE_ERROR ((0, 0, _("--acls can be used only on POSIX archives")));
710+
711+ if ((selinux_context_option > 0)
712+ && archive_format != POSIX_FORMAT
713+ && (subcommand_option != EXTRACT_SUBCOMMAND
714+ || subcommand_option != DIFF_SUBCOMMAND
715+ || subcommand_option != LIST_SUBCOMMAND))
716+ USAGE_ERROR ((0, 0, _("--selinux can be used only on POSIX archives")));
717+
718+ if ((xattrs_option > 0)
719+ && archive_format != POSIX_FORMAT
720+ && (subcommand_option != EXTRACT_SUBCOMMAND
721+ || subcommand_option != DIFF_SUBCOMMAND
722+ || subcommand_option != LIST_SUBCOMMAND))
723+ USAGE_ERROR ((0, 0, _("--xattrs can be used only on POSIX archives")));
724+
725 /* If ready to unlink hierarchies, so we are for simpler files. */
726 if (recursive_unlink_option)
727 old_files_option = UNLINK_FIRST_OLD_FILES;
bd523de6 728@@ -2713,11 +2785,15 @@ void
547b54ef
MT
729 tar_stat_destroy (struct tar_stat_info *st)
730 {
bd523de6 731 tar_stat_close (st);
547b54ef
MT
732+ xheader_xattr_free (st->xattr_map, st->xattr_map_size);
733 free (st->orig_file_name);
734 free (st->file_name);
735 free (st->link_name);
736 free (st->uname);
737 free (st->gname);
738+ free (st->cntx_name);
739+ free (st->acls_a_ptr);
740+ free (st->acls_d_ptr);
741 free (st->sparse_map);
742 free (st->dumpdir);
743 xheader_destroy (&st->xhdr);
bd523de6
MT
744diff -urNp tar-1.24-orig/src/tar.h tar-1.24/src/tar.h
745--- tar-1.24-orig/src/tar.h 2010-10-24 20:07:46.000000000 +0200
746+++ tar-1.24/src/tar.h 2010-10-25 10:24:52.567223606 +0200
547b54ef
MT
747@@ -276,6 +276,14 @@ struct xheader
748 uintmax_t string_length;
749 };
750
751+/* Information about xattrs for a file. */
752+struct xattr_array
753+ {
754+ char *xkey;
755+ char *xval_ptr;
756+ size_t xval_len;
757+ };
758+
759 struct tar_stat_info
760 {
761 char *orig_file_name; /* name of file read from the archive header */
762@@ -287,6 +295,15 @@ struct tar_stat_info
763
764 char *uname; /* user name of owner */
765 char *gname; /* group name of owner */
766+
767+ char *cntx_name; /* SELinux context for the current archive entry. */
768+
769+ char *acls_a_ptr; /* Access ACLs for the current archive entry. */
770+ size_t acls_a_len; /* Access ACLs for the current archive entry. */
9f0833cd 771+
547b54ef
MT
772+ char *acls_d_ptr; /* Default ACLs for the current archive entry. */
773+ size_t acls_d_len; /* Default ACLs for the current archive entry. */
774+
775 struct stat stat; /* regular filesystem stat */
776
777 /* STAT doesn't always have access, data modification, and status
778@@ -309,6 +326,9 @@ struct tar_stat_info
779 size_t sparse_map_size; /* Size of the sparse map */
780 struct sp_array *sparse_map;
781
782+ size_t xattr_map_size; /* Size of the xattr map */
783+ struct xattr_array *xattr_map;
784+
785 /* Extended headers */
786 struct xheader xhdr;
bd523de6
MT
787
788diff -urNp tar-1.24-orig/src/xattrs.c tar-1.24/src/xattrs.c
789--- tar-1.24-orig/src/xattrs.c 1970-01-01 01:00:00.000000000 +0100
790+++ tar-1.24/src/xattrs.c 2010-10-25 10:24:52.568214736 +0200
791@@ -0,0 +1,489 @@
547b54ef
MT
792+/* Create a tar archive.
793+
794+ Copyright (C) 2006 Free Software Foundation, Inc.
795+
796+ Written by James Antill, on 2006-07-27.
797+
798+ This program is free software; you can redistribute it and/or modify it
799+ under the terms of the GNU General Public License as published by the
800+ Free Software Foundation; either version 2, or (at your option) any later
801+ version.
802+
803+ This program is distributed in the hope that it will be useful, but
804+ WITHOUT ANY WARRANTY; without even the implied warranty of
805+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
806+ Public License for more details.
807+
808+ You should have received a copy of the GNU General Public License along
809+ with this program; if not, write to the Free Software Foundation, Inc.,
810+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
811+
812+#include <system.h>
813+
814+#include <quotearg.h>
815+
816+#include "common.h"
817+
818+
819+#ifndef HAVE_SELINUX_SELINUX_H
820+# undef HAVE_LIBSELINUX
821+#endif
822+
823+#ifndef HAVE_ATTR_XATTR_H
824+# undef HAVE_XATTRS
825+#endif
826+
827+#ifndef HAVE_SYS_ACL_H
828+# undef HAVE_LIBACL
829+#endif
830+
831+#ifdef HAVE_SELINUX_SELINUX_H
832+# include <selinux/selinux.h>
833+#endif
834+
835+#ifdef HAVE_ATTR_XATTR_H
836+# include <attr/xattr.h>
837+#endif
838+
839+#ifdef HAVE_SYS_ACL_H
840+# include <sys/acl.h>
841+#endif
842+
843+
844+#if 0 /* unused by xattr's atm. */
845+static void xattrs__fd_get(struct tar_stat_info *st,
846+ char const *file_name, int fd, const char *attr,
847+ char **ret_ptr, size_t *ret_len)
848+{
849+#ifdef HAVE_XATTRS
850+ static ssize_t asz = 1024;
851+ ssize_t ret = 0;
852+ static char *val = NULL;
9f0833cd 853+
547b54ef 854+ if (!val) val = xmalloc (asz);
9f0833cd 855+
547b54ef
MT
856+ while (((ret = fgetxattr (fd, attr, val, asz)) == -1) &&
857+ (errno == ERANGE))
858+ {
859+ asz <<= 1;
860+ val = xrealloc (val, asz);
861+ }
9f0833cd 862+
547b54ef
MT
863+ if (ret != -1)
864+ {
865+ *ret_ptr = xmemdup (val, ret + 1);
866+ *ret_len = ret;
867+ }
868+ else if (errno != ENOATTR)
869+ call_arg_warn ("fgetxattr", file_name);
870+#endif
871+}
872+#endif
873+
874+static void xattrs__acls_get_a(struct tar_stat_info *st,
875+ char const *file_name, int fd,
876+ char **ret_ptr, size_t *ret_len)
877+{ /* "system.posix_acl_access" */
878+#ifdef HAVE_LIBACL
879+ char *val = NULL;
880+ ssize_t len;
881+ acl_t acl;
882+
883+ if (fd != -1)
884+ {
885+ if ((acl = acl_get_fd (fd)) == (acl_t)NULL)
886+ {
887+ if (errno != ENOTSUP)
888+ call_arg_warn ("acl_get_fd", file_name);
889+ return;
890+ }
891+ }
892+ else if ((acl = acl_get_file (file_name, ACL_TYPE_ACCESS)) == (acl_t)NULL)
893+ {
894+ if (errno != ENOTSUP)
895+ call_arg_warn ("acl_get_file", file_name);
896+ return;
897+ }
9f0833cd
MT
898+
899+
547b54ef
MT
900+ val = acl_to_text(acl, &len);
901+ acl_free (acl);
9f0833cd 902+
547b54ef
MT
903+ if (val == NULL)
904+ {
905+ call_arg_warn ("acl_to_text", file_name);
906+ return;
907+ }
9f0833cd 908+
547b54ef
MT
909+ *ret_ptr = xstrdup (val);
910+ *ret_len = len;
9f0833cd 911+
547b54ef
MT
912+ acl_free (val);
913+#endif
914+}
915+
916+static void xattrs__acls_get_d(struct tar_stat_info *st,
917+ char const *file_name,
918+ char **ret_ptr, size_t *ret_len)
919+{ /* "system.posix_acl_default" */
920+#ifdef HAVE_LIBACL
921+ char *val = NULL;
922+ ssize_t len;
923+ acl_t acl;
9f0833cd 924+
547b54ef
MT
925+ if ((acl = acl_get_file (file_name, ACL_TYPE_DEFAULT)) == (acl_t)NULL)
926+ {
927+ if (errno != ENOTSUP)
928+ call_arg_warn ("acl_get_file", file_name);
929+ return;
930+ }
9f0833cd 931+
547b54ef
MT
932+ val = acl_to_text(acl, &len);
933+ acl_free (acl);
9f0833cd 934+
547b54ef
MT
935+ if (val == NULL)
936+ {
937+ call_arg_warn ("acl_to_text", file_name);
938+ return;
939+ }
9f0833cd 940+
547b54ef
MT
941+ *ret_ptr = xstrdup (val);
942+ *ret_len = len;
9f0833cd 943+
547b54ef
MT
944+ acl_free (val);
945+#endif
946+}
947+
948+void xattrs_acls_get(struct tar_stat_info *st, char const *file_name, int fd,
949+ int xisfile)
950+{
951+ if (acls_option > 0)
952+ {
953+#ifndef HAVE_LIBACL
954+ static int done = 0;
955+ if (!done)
956+ WARN ((0, 0, _("ACL support requested, but not available")));
957+ done = 1;
958+#endif
959+ xattrs__acls_get_a (st, file_name, fd,
960+ &st->acls_a_ptr, &st->acls_a_len);
961+ if (!xisfile)
962+ xattrs__acls_get_d (st, file_name,
963+ &st->acls_d_ptr, &st->acls_d_len);
964+ }
965+}
966+
967+void xattrs_selinux_get(struct tar_stat_info *st, char const *file_name, int fd)
968+{
969+ if (selinux_context_option > 0)
970+ {
971+#ifndef HAVE_LIBSELINUX
972+ static int done = 0;
973+ if (!done)
974+ WARN ((0, 0, _("SELinux support requested, but not available")));
975+ done = 1;
976+#else
977+ if (fd == -1)
978+ {
979+ if ((lgetfilecon (file_name, &st->cntx_name) == -1) && (errno != ENOTSUP) && (errno != ENODATA))
980+ call_arg_warn ("lgetfilecon", file_name);
981+ }
982+ else if ((fgetfilecon (fd, &st->cntx_name) == -1) && (errno != ENOTSUP) && (errno != ENODATA))
983+ call_arg_warn ("fgetfilecon", file_name);
984+#endif
985+ }
986+}
987+
988+void xattrs_xattrs_get(struct tar_stat_info *st, char const *file_name, int fd)
989+{
990+ if (xattrs_option > 0)
991+ { /* get all xattrs ... this include security.* and system.* if
992+ available. We filter them here, but we have to filter them
993+ in xattrs_xattrs_set() anyway.
994+ */
995+ static ssize_t xsz = 1024;
996+ static char *xatrs = NULL;
997+ ssize_t xret = -1;
998+
999+#ifndef HAVE_XATTRS
1000+ static int done = 0;
1001+ if ((xattrs_option > 0) && !done)
1002+ WARN ((0, 0, _("Xattr support requested, but not available")));
1003+ done = 1;
1004+#else
1005+
1006+ if (!xatrs) xatrs = xmalloc (xsz);
9f0833cd
MT
1007+
1008+ while (((fd == -1) ?
1009+ ((xret = llistxattr (file_name, xatrs, xsz)) == -1) :
547b54ef
MT
1010+ ((xret = flistxattr (fd, xatrs, xsz)) == -1)) &&
1011+ (errno == ERANGE))
1012+ {
1013+ xsz <<= 1;
1014+ xatrs = xrealloc (xatrs, xsz);
1015+ }
1016+
1017+ if (xret == -1)
9f0833cd 1018+ call_arg_warn ((fd == -1) ? "llistxattrs" : "flistxattrs", file_name);
547b54ef
MT
1019+ else
1020+ {
1021+ const char *attr = xatrs;
1022+ static ssize_t asz = 1024;
1023+ static char *val = NULL;
9f0833cd 1024+
547b54ef 1025+ if (!val) val = xmalloc (asz);
9f0833cd 1026+
547b54ef
MT
1027+ while (xret > 0)
1028+ {
1029+ size_t len = strlen (attr);
1030+ ssize_t aret = 0;
9f0833cd
MT
1031+
1032+ /* Archive all xattrs during creation, decide at extraction time
1033+ * which ones are of interest/use for the target filesystem. */
1034+ while (((fd == -1) ?
1035+ ((aret = lgetxattr (file_name, attr, val, asz)) == -1) :
547b54ef
MT
1036+ ((aret = fgetxattr (fd, attr, val, asz)) == -1)) &&
1037+ (errno == ERANGE))
1038+ {
1039+ asz <<= 1;
1040+ val = xrealloc (val, asz);
1041+ }
9f0833cd 1042+
547b54ef
MT
1043+ if (aret != -1)
1044+ xheader_xattr_add (st, attr, val, aret);
1045+ else if (errno != ENOATTR)
9f0833cd
MT
1046+ call_arg_warn ((fd==-1) ? "lgetxattr" : "fgetxattr", file_name);
1047+
547b54ef
MT
1048+ attr += len + 1;
1049+ xret -= len + 1;
1050+ }
1051+ }
1052+#endif
1053+ }
1054+}
1055+
1056+static void xattrs__fd_set(struct tar_stat_info const *st,
1057+ char const *file_name, char typeflag,
1058+ const char *attr,
1059+ const char *ptr, size_t len)
1060+{
1061+#ifdef HAVE_XATTRS
1062+ if (ptr)
1063+ {
1064+ const char *sysname = "setxattr";
1065+ int ret = -1;
1066+
1067+ if (typeflag != SYMTYPE)
1068+ ret = setxattr (file_name, attr, ptr, len, 0);
1069+ else
1070+ {
1071+ sysname = "lsetxattr";
1072+ ret = lsetxattr (file_name, attr, ptr, len, 0);
1073+ }
1074+
1075+ /* do not print warnings when SELinux is disabled */
1076+ if ((ret == -1) && (errno != EPERM) && (errno != ENOTSUP))
1077+ call_arg_error(sysname, file_name);
1078+ }
1079+#endif
1080+}
1081+
1082+/* convert unix permissions into an ACL ... needed due to "default" ACLs */
1083+#ifdef HAVE_LIBACL
1084+static acl_t perms2acl(int perms)
1085+{
1086+ char val[] = "user::---,group::---,other::---";
1087+ /* 0123456789 123456789 123456789 123456789 */
1088+
1089+ /* user */
1090+ if (perms & 0400) val[ 6] = 'r';
1091+ if (perms & 0200) val[ 7] = 'w';
1092+ if (perms & 0100) val[ 8] = 'x';
1093+
1094+ /* group */
1095+ if (perms & 0040) val[17] = 'r';
1096+ if (perms & 0020) val[18] = 'w';
1097+ if (perms & 0010) val[19] = 'x';
1098+
1099+ /* other */
1100+ if (perms & 0004) val[28] = 'r';
1101+ if (perms & 0002) val[29] = 'w';
1102+ if (perms & 0001) val[30] = 'x';
9f0833cd 1103+
547b54ef
MT
1104+ return (acl_from_text (val));
1105+}
1106+#endif
1107+
1108+static char *skip_to_ext_fields(char *ptr)
1109+{
1110+ ptr += strcspn(ptr, ":,\n"); /* skip tag name. Ie. user/group/default/mask */
1111+
1112+ if (*ptr != ':')
1113+ return (ptr); /* error? no user/group field */
1114+ ++ptr;
9f0833cd 1115+
547b54ef
MT
1116+ ptr += strcspn(ptr, ":,\n"); /* skip user/group name */
1117+
1118+ if (*ptr != ':')
1119+ return (ptr); /* error? no perms field */
1120+ ++ptr;
9f0833cd 1121+
547b54ef
MT
1122+ ptr += strcspn(ptr, ":,\n"); /* skip perms */
1123+
1124+ if (*ptr != ':')
1125+ return (ptr); /* no extra fields */
1126+
1127+ return (ptr);
1128+}
1129+
1130+/* The POSIX draft allows extra fields after the three main ones. Star
1131+ uses this to add a fourth field for user/group which is the numeric ID.
1132+ We just skip all extra fields atm. */
1133+static const char *fixup_extra_acl_fields(const char *ptr)
1134+{
1135+ char *src = (char *)ptr;
1136+ char *dst = (char *)ptr;
1137+
1138+ while (*src)
1139+ {
1140+ const char *old = src;
1141+ size_t len = 0;
1142+
1143+ src = skip_to_ext_fields(src);
1144+ len = src - old;
1145+ if (old != dst) memmove(dst, old, len);
1146+ dst += len;
1147+
1148+ if (*src == ':') /* We have extra fields, skip them all */
1149+ src += strcspn(src, "\n,");
9f0833cd 1150+
547b54ef
MT
1151+ if ((*src == '\n') || (*src == ','))
1152+ *dst++ = *src++; /* also done when dst == src, but that's ok */
1153+ }
1154+ if (src != dst)
1155+ *dst = 0;
9f0833cd 1156+
547b54ef
MT
1157+ return ptr;
1158+}
1159+
1160+static void xattrs__acls_set(struct tar_stat_info const *st,
1161+ char const *file_name, int type,
1162+ const char *ptr, size_t len)
1163+{ /* "system.posix_acl_access" */
1164+#ifdef HAVE_LIBACL
1165+ acl_t acl;
1166+
1167+ if (ptr)
1168+ {
1169+ /* assert (strlen (ptr) == len); */
1170+ ptr = fixup_extra_acl_fields(ptr);
9f0833cd 1171+
547b54ef
MT
1172+ acl = acl_from_text (ptr);
1173+ acls_option = 1;
1174+ }
1175+ else if (acls_option > 0)
1176+ acl = perms2acl (st->stat.st_mode);
1177+ else
1178+ return; /* don't call acl functions unless we first hit an ACL, or
1179+ --acls was passed explicitly */
9f0833cd 1180+
547b54ef
MT
1181+ if (acl == (acl_t)NULL)
1182+ {
1183+ call_arg_warn ("acl_from_text", file_name);
1184+ return;
1185+ }
9f0833cd 1186+
547b54ef
MT
1187+ if (acl_set_file (file_name, type, acl) == -1)
1188+ {
1189+ if (errno != ENOTSUP)
1190+ call_arg_warn ("acl_set_file", file_name);
1191+ }
1192+ acl_free (acl);
1193+#endif
1194+}
1195+
1196+void xattrs_acls_set(struct tar_stat_info const *st,
1197+ char const *file_name, char typeflag)
1198+{
1199+ if ((acls_option >= 0) && (typeflag != SYMTYPE))
1200+ {
1201+#ifndef HAVE_LIBACL
1202+ static int done = 0;
1203+ if (!done)
1204+ WARN ((0, 0, _("ACL support requested, but not available")));
1205+ done = 1;
1206+#else
1207+ xattrs__acls_set (st, file_name, ACL_TYPE_ACCESS,
1208+ st->acls_a_ptr, st->acls_a_len);
9f0833cd 1209+ if ((typeflag == DIRTYPE) || (typeflag == GNUTYPE_DUMPDIR))
547b54ef
MT
1210+ xattrs__acls_set (st, file_name, ACL_TYPE_DEFAULT,
1211+ st->acls_d_ptr, st->acls_d_len);
1212+#endif
1213+ }
1214+}
1215+
1216+void xattrs_selinux_set(struct tar_stat_info const *st,
1217+ char const *file_name, char typeflag)
1218+{
1219+ if ((selinux_context_option >= 0) && st->cntx_name)
1220+ {
1221+ const char *sysname = "setfilecon";
1222+ int ret = -1;
1223+
1224+#ifndef HAVE_LIBSELINUX
1225+ static int done = 0;
1226+ if (!done)
1227+ WARN ((0, 0, _("SELinux support requested, but not available")));
1228+ done = 1;
1229+#else
1230+ if (typeflag != SYMTYPE)
1231+ ret = setfilecon (file_name, st->cntx_name);
1232+ else
1233+ {
1234+ sysname = "lsetfilecon";
1235+ ret = lsetfilecon (file_name, st->cntx_name);
1236+ }
1237+
1238+ if ((ret == -1) && (errno == EPERM))
1239+ call_arg_warn(sysname, file_name);
1240+ else if ((ret == -1) && (errno != EOPNOTSUPP))
1241+ call_arg_error(sysname, file_name);
1242+#endif
1243+ }
1244+}
1245+
1246+void xattrs_xattrs_set(struct tar_stat_info const *st,
1247+ char const *file_name, char typeflag)
1248+{
1249+ if ((xattrs_option >= 0) && st->xattr_map_size)
1250+ {
1251+ size_t scan = 0;
1252+
1253+#ifndef HAVE_XATTRS
1254+ static int done = 0;
1255+ if (!done)
1256+ WARN ((0, 0, _("Xattr support requested, but not available")));
1257+ done = 1;
1258+#else
1259+ while (scan < st->xattr_map_size)
1260+ {
1261+ char *keyword = st->xattr_map[scan].xkey;
1262+
1263+ /* assert (!memcpy (keyword, "SCHILY.xattr.", strlen("SCHILY.xattr."))); */
1264+ keyword += strlen("SCHILY.xattr.");
1265+
1266+ if (strncmp (keyword, "user.", strlen("user.")) &&
9f0833cd 1267+ strncmp (keyword, "lustre.", strlen("lustre.")) &&
bd523de6
MT
1268+ strncmp (keyword, "trusted.", strlen("trusted.")) &&
1269+ strncmp (keyword, "security.NTACL", strlen("security.NTACL")))
547b54ef 1270+ continue; /* don't try and set anything but normal xattrs */
9f0833cd 1271+
547b54ef
MT
1272+ xattrs__fd_set (st, file_name, typeflag, keyword,
1273+ st->xattr_map[scan].xval_ptr,
1274+ st->xattr_map[scan].xval_len);
9f0833cd 1275+
547b54ef
MT
1276+ ++scan;
1277+ }
1278+#endif
1279+ }
1280+}
bd523de6
MT
1281diff -urNp tar-1.24-orig/src/xattrs.h tar-1.24/src/xattrs.h
1282--- tar-1.24-orig/src/xattrs.h 1970-01-01 01:00:00.000000000 +0100
1283+++ tar-1.24/src/xattrs.h 2010-10-25 10:24:52.569214526 +0200
547b54ef
MT
1284@@ -0,0 +1,14 @@
1285+
1286+extern void xattrs_acls_get(struct tar_stat_info *st,
1287+ char const *file_name, int fd, int xisfile);
1288+extern void xattrs_selinux_get(struct tar_stat_info *st,
1289+ char const *file_name, int fd);
1290+extern void xattrs_xattrs_get(struct tar_stat_info *st,
1291+ char const *file_name, int fd);
1292+
1293+extern void xattrs_acls_set(struct tar_stat_info const *st,
1294+ char const *file_name, char typeflag);
1295+extern void xattrs_selinux_set(struct tar_stat_info const *st,
1296+ char const *file_name, char typeflag);
1297+extern void xattrs_xattrs_set(struct tar_stat_info const *st,
1298+ char const *file_name, char typeflag);
bd523de6
MT
1299diff -urNp tar-1.24-orig/src/xheader.c tar-1.24/src/xheader.c
1300--- tar-1.24-orig/src/xheader.c 2010-10-24 20:07:46.000000000 +0200
1301+++ tar-1.24/src/xheader.c 2010-10-25 10:24:52.570223396 +0200
1302@@ -460,6 +460,74 @@ xheader_write_global (struct xheader *xh
9f0833cd
MT
1303 }
1304 }
1305
1306+void xheader_xattr_init(struct tar_stat_info *st)
1307+{
1308+ st->xattr_map = NULL;
1309+ st->xattr_map_size = 0;
1310+}
1311+
1312+void xheader_xattr_free(struct xattr_array *xattr_map, size_t xattr_map_size)
1313+{
1314+ size_t scan = 0;
1315+
1316+ while (scan < xattr_map_size)
1317+ {
1318+ free (xattr_map[scan].xkey);
1319+ free (xattr_map[scan].xval_ptr);
1320+
1321+ ++scan;
1322+ }
1323+ free (xattr_map);
1324+}
1325+
1326+static void xheader_xattr__add(struct xattr_array **xattr_map,
1327+ size_t *xattr_map_size,
1328+ const char *key, const char *val, size_t len)
1329+{
1330+ size_t pos = (*xattr_map_size)++;
1331+
1332+ *xattr_map = xrealloc (*xattr_map,
1333+ *xattr_map_size * sizeof(struct xattr_array));
1334+ (*xattr_map)[pos].xkey = xstrdup (key);
1335+ (*xattr_map)[pos].xval_ptr = xmemdup (val, len + 1);
1336+ (*xattr_map)[pos].xval_len = len;
1337+}
1338+
1339+void xheader_xattr_add(struct tar_stat_info *st,
1340+ const char *key, const char *val, size_t len)
1341+{
1342+ size_t klen = strlen (key);
1343+ char *xkey = xmalloc (strlen("SCHILY.xattr.") + klen + 1);
1344+ char *tmp = xkey;
1345+
1346+ tmp = stpcpy (tmp, "SCHILY.xattr.");
1347+ tmp = stpcpy (tmp, key);
1348+
1349+ xheader_xattr__add (&st->xattr_map, &st->xattr_map_size, xkey, val, len);
1350+
1351+ free (xkey);
1352+}
1353+
1354+void xheader_xattr_copy(const struct tar_stat_info *st,
1355+ struct xattr_array **xattr_map, size_t *xattr_map_size)
1356+{
1357+ size_t scan = 0;
1358+
1359+ *xattr_map = NULL;
1360+ *xattr_map_size = 0;
1361+
1362+ while (scan < st->xattr_map_size)
1363+ {
1364+ char *key = st->xattr_map[scan].xkey;
1365+ char *val = st->xattr_map[scan].xval_ptr;
1366+ size_t len = st->xattr_map[scan].xval_len;
1367+
1368+ xheader_xattr__add(xattr_map, xattr_map_size, key, val, len);
1369+
1370+ ++scan;
1371+ }
1372+}
1373+
1374 \f
1375 /* General Interface */
1376
bd523de6 1377@@ -473,6 +541,7 @@ struct xhdr_tab
9f0833cd
MT
1378 struct xheader *, void const *data);
1379 void (*decoder) (struct tar_stat_info *, char const *, char const *, size_t);
1380 int flags;
1381+ bool prefix;
1382 };
1383
1384 /* This declaration must be extern, because ISO C99 section 6.9.2
bd523de6 1385@@ -489,8 +558,17 @@ locate_handler (char const *keyword)
9f0833cd
MT
1386 struct xhdr_tab const *p;
1387
1388 for (p = xhdr_tab; p->keyword; p++)
1389- if (strcmp (p->keyword, keyword) == 0)
1390- return p;
1391+ if (p->prefix)
1392+ {
1393+ if (strncmp (p->keyword, keyword, strlen(p->keyword)) == 0)
1394+ return p;
1395+ }
1396+ else
1397+ {
1398+ if (strcmp (p->keyword, keyword) == 0)
1399+ return p;
1400+ }
1401+
1402 return NULL;
1403 }
1404
bd523de6 1405@@ -500,7 +578,7 @@ xheader_protected_pattern_p (const char
9f0833cd
MT
1406 struct xhdr_tab const *p;
1407
1408 for (p = xhdr_tab; p->keyword; p++)
1409- if ((p->flags & XHDR_PROTECTED) && fnmatch (pattern, p->keyword, 0) == 0)
1410+ if (!p->prefix && (p->flags & XHDR_PROTECTED) && fnmatch (pattern, p->keyword, 0) == 0)
1411 return true;
1412 return false;
1413 }
bd523de6 1414@@ -511,7 +589,7 @@ xheader_protected_keyword_p (const char
9f0833cd
MT
1415 struct xhdr_tab const *p;
1416
1417 for (p = xhdr_tab; p->keyword; p++)
1418- if ((p->flags & XHDR_PROTECTED) && strcmp (p->keyword, keyword) == 0)
1419+ if (!p->prefix && (p->flags & XHDR_PROTECTED) && strcmp (p->keyword, keyword) == 0)
1420 return true;
1421 return false;
1422 }
bd523de6 1423@@ -1470,6 +1548,71 @@ volume_filename_decoder (struct tar_stat
9f0833cd
MT
1424 }
1425
1426 static void
1427+xattr_selinux_coder (struct tar_stat_info const *st, char const *keyword,
1428+ struct xheader *xhdr, void const *data)
1429+{
1430+ code_string (st->cntx_name, keyword, xhdr);
1431+}
1432+
1433+static void
1434+xattr_selinux_decoder (struct tar_stat_info *st,
1435+ char const *keyword, char const *arg, size_t size)
1436+{
1437+ decode_string (&st->cntx_name, arg);
1438+}
1439+
1440+static void
1441+xattr_acls_a_coder (struct tar_stat_info const *st , char const *keyword,
1442+ struct xheader *xhdr, void const *data)
1443+{
1444+ xheader_print_n (xhdr, keyword, st->acls_a_ptr, st->acls_a_len);
1445+}
1446+
1447+static void
1448+xattr_acls_a_decoder (struct tar_stat_info *st,
1449+ char const *keyword, char const *arg, size_t size)
1450+{
1451+ st->acls_a_ptr = xmemdup (arg, size + 1);
1452+ st->acls_a_len = size;
1453+}
1454+
1455+static void
1456+xattr_acls_d_coder (struct tar_stat_info const *st , char const *keyword,
1457+ struct xheader *xhdr, void const *data)
1458+{
1459+ xheader_print_n (xhdr, keyword, st->acls_d_ptr, st->acls_d_len);
1460+}
1461+
1462+static void
1463+xattr_acls_d_decoder (struct tar_stat_info *st,
1464+ char const *keyword, char const *arg, size_t size)
1465+{
1466+ st->acls_d_ptr = xmemdup (arg, size + 1);
1467+ st->acls_d_len = size;
1468+}
1469+
1470+static void
1471+xattr_coder (struct tar_stat_info const *st , char const *keyword,
1472+ struct xheader *xhdr, void const *data)
1473+{
1474+ struct xattr_array *xattr_map = st->xattr_map;
1475+ const size_t *off = data;
1476+ xheader_print_n (xhdr, keyword,
1477+ xattr_map[*off].xval_ptr, xattr_map[*off].xval_len);
1478+}
1479+
1480+static void
1481+xattr_decoder (struct tar_stat_info *st,
1482+ char const *keyword, char const *arg, size_t size)
1483+{
1484+ char *xstr = NULL;
1485+
1486+ xstr = xmemdup(arg, size + 1);
1487+ xheader_xattr_add(st, keyword + strlen("SCHILY.xattr."), xstr, size);
1488+ free(xstr);
1489+}
1490+
1491+static void
1492 sparse_major_coder (struct tar_stat_info const *st, char const *keyword,
1493 struct xheader *xhdr, void const *data)
1494 {
bd523de6 1495@@ -1506,53 +1649,53 @@ sparse_minor_decoder (struct tar_stat_in
9f0833cd
MT
1496 }
1497
1498 struct xhdr_tab const xhdr_tab[] = {
1499- { "atime", atime_coder, atime_decoder, 0 },
1500- { "comment", dummy_coder, dummy_decoder, 0 },
1501- { "charset", dummy_coder, dummy_decoder, 0 },
1502- { "ctime", ctime_coder, ctime_decoder, 0 },
1503- { "gid", gid_coder, gid_decoder, 0 },
1504- { "gname", gname_coder, gname_decoder, 0 },
1505- { "linkpath", linkpath_coder, linkpath_decoder, 0 },
1506- { "mtime", mtime_coder, mtime_decoder, 0 },
1507- { "path", path_coder, path_decoder, 0 },
1508- { "size", size_coder, size_decoder, 0 },
1509- { "uid", uid_coder, uid_decoder, 0 },
1510- { "uname", uname_coder, uname_decoder, 0 },
1511+ { "atime", atime_coder, atime_decoder, 0, false },
1512+ { "comment", dummy_coder, dummy_decoder, 0, false },
1513+ { "charset", dummy_coder, dummy_decoder, 0, false },
1514+ { "ctime", ctime_coder, ctime_decoder, 0, false },
1515+ { "gid", gid_coder, gid_decoder, 0, false },
1516+ { "gname", gname_coder, gname_decoder, 0, false },
1517+ { "linkpath", linkpath_coder, linkpath_decoder, 0, false },
1518+ { "mtime", mtime_coder, mtime_decoder, 0, false },
1519+ { "path", path_coder, path_decoder, 0, false },
1520+ { "size", size_coder, size_decoder, 0, false },
1521+ { "uid", uid_coder, uid_decoder, 0, false },
1522+ { "uname", uname_coder, uname_decoder, 0, false },
1523
1524 /* Sparse file handling */
1525 { "GNU.sparse.name", path_coder, path_decoder,
1526- XHDR_PROTECTED },
1527+ XHDR_PROTECTED, false },
1528 { "GNU.sparse.major", sparse_major_coder, sparse_major_decoder,
1529- XHDR_PROTECTED },
1530+ XHDR_PROTECTED, false },
1531 { "GNU.sparse.minor", sparse_minor_coder, sparse_minor_decoder,
1532- XHDR_PROTECTED },
1533+ XHDR_PROTECTED, false },
1534 { "GNU.sparse.realsize", sparse_size_coder, sparse_size_decoder,
1535- XHDR_PROTECTED },
1536+ XHDR_PROTECTED, false },
1537 { "GNU.sparse.numblocks", sparse_numblocks_coder, sparse_numblocks_decoder,
1538- XHDR_PROTECTED },
1539+ XHDR_PROTECTED, false },
1540
1541 /* tar 1.14 - 1.15.90 keywords. */
1542 { "GNU.sparse.size", sparse_size_coder, sparse_size_decoder,
1543- XHDR_PROTECTED },
1544+ XHDR_PROTECTED, false },
1545 /* tar 1.14 - 1.15.1 keywords. Multiple instances of these appeared in 'x'
1546 headers, and each of them was meaningful. It confilcted with POSIX specs,
1547 which requires that "when extended header records conflict, the last one
1548 given in the header shall take precedence." */
1549 { "GNU.sparse.offset", sparse_offset_coder, sparse_offset_decoder,
1550- XHDR_PROTECTED },
1551+ XHDR_PROTECTED, false },
1552 { "GNU.sparse.numbytes", sparse_numbytes_coder, sparse_numbytes_decoder,
1553- XHDR_PROTECTED },
1554+ XHDR_PROTECTED, false },
1555 /* tar 1.15.90 keyword, introduced to remove the above-mentioned conflict. */
1556 { "GNU.sparse.map", NULL /* Unused, see pax_dump_header() */,
1557- sparse_map_decoder, 0 },
1558+ sparse_map_decoder, 0, false },
1559
1560 { "GNU.dumpdir", dumpdir_coder, dumpdir_decoder,
1561- XHDR_PROTECTED },
1562+ XHDR_PROTECTED, false },
1563
1564 /* Keeps the tape/volume label. May be present only in the global headers.
1565 Equivalent to GNUTYPE_VOLHDR. */
1566 { "GNU.volume.label", volume_label_coder, volume_label_decoder,
1567- XHDR_PROTECTED | XHDR_GLOBAL },
1568+ XHDR_PROTECTED | XHDR_GLOBAL, false },
1569
1570 /* These may be present in a first global header of the archive.
1571 They provide the same functionality as GNUTYPE_MULTIVOL header.
bd523de6 1572@@ -1561,11 +1704,41 @@ struct xhdr_tab const xhdr_tab[] = {
9f0833cd
MT
1573 GNU.volume.offset keeps the offset of the start of this volume,
1574 otherwise kept in oldgnu_header.offset. */
1575 { "GNU.volume.filename", volume_label_coder, volume_filename_decoder,
1576- XHDR_PROTECTED | XHDR_GLOBAL },
1577+ XHDR_PROTECTED | XHDR_GLOBAL, false },
1578 { "GNU.volume.size", volume_size_coder, volume_size_decoder,
1579- XHDR_PROTECTED | XHDR_GLOBAL },
1580+ XHDR_PROTECTED | XHDR_GLOBAL, false },
1581 { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder,
1582- XHDR_PROTECTED | XHDR_GLOBAL },
1583+ XHDR_PROTECTED | XHDR_GLOBAL, false },
1584+
1585+ /* We get the SELinux value from filecon, so add a namespace for SELinux
1586+ instead of storing it in SCHILY.xattr.* (which would be RAW). */
1587+ { "RHT.security.selinux",
1588+ xattr_selinux_coder, xattr_selinux_decoder, 0, false },
1589+
1590+ /* ACLs, use the star format... */
1591+ { "SCHILY.acl.access",
1592+ xattr_acls_a_coder, xattr_acls_a_decoder, 0, false },
1593+
1594+ { "SCHILY.acl.default",
1595+ xattr_acls_d_coder, xattr_acls_d_decoder, 0, false },
1596+
1597+ /* FIXME: These are compat. for FC-6 ... we shipped a tar using the generic
1598+ header names by accident. */
1599+ { "SCHILY.xattr.security.selinux",
1600+ xattr_selinux_coder, xattr_selinux_decoder, 0, false },
1601+ { "SCHILY.xattr.system.posix_acl_access",
1602+ xattr_acls_a_coder, xattr_acls_a_decoder, 0, false },
1603+ { "SCHILY.xattr.system.posix_acl_default",
1604+ xattr_acls_d_coder, xattr_acls_d_decoder, 0, false },
1605+
1606+ /* xattrs use the star format. note we only save some variants... */
1607+ { "SCHILY.xattr.user", xattr_coder, xattr_decoder, 0, true },
1608+ { "SCHILY.xattr.trusted", xattr_coder, xattr_decoder, 0, true },
1609+ { "SCHILY.xattr.lustre", xattr_coder, xattr_decoder, 0, true },
bd523de6 1610+ { "SCHILY.xattr.security.NTACL", xattr_coder, xattr_decoder, 0, true },
9f0833cd
MT
1611+
1612+ /* ignore everything else in the xattr namespaces... */
1613+ { "SCHILY.xattr", dummy_coder, dummy_decoder, 0, true },
1614
1615- { NULL, NULL, NULL, 0 }
1616+ { NULL, NULL, NULL, 0, false }
1617 };