Gentoo Archives: gentoo-commits

From: "Mike Frysinger (vapier)" <vapier@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] gentoo-x86 commit in app-arch/tar/files: tar-1.26-xattr.patch
Date: Sun, 05 Feb 2012 04:30:04
Message-Id: 20120205042953.3125F2004B@flycatcher.gentoo.org
1 vapier 12/02/05 04:29:53
2
3 Added: tar-1.26-xattr.patch
4 Log:
5 Add xattr support #382067 by Anthony Basile.
6
7 (Portage version: 2.2.0_alpha84/cvs/Linux x86_64)
8
9 Revision Changes Path
10 1.1 app-arch/tar/files/tar-1.26-xattr.patch
11
12 file : http://sources.gentoo.org/viewvc.cgi/gentoo-x86/app-arch/tar/files/tar-1.26-xattr.patch?rev=1.1&view=markup
13 plain: http://sources.gentoo.org/viewvc.cgi/gentoo-x86/app-arch/tar/files/tar-1.26-xattr.patch?rev=1.1&content-type=text/plain
14
15 Index: tar-1.26-xattr.patch
16 ===================================================================
17 https://bugs.gentoo.org/382067
18
19 add optional xattr support
20
21 --- a/configure.ac
22 +++ b/configure.ac
23 @@ -223,6 +223,20 @@ AC_CHECK_TYPE(iconv_t,:,
24 #endif
25 ])
26
27 +AC_ARG_ENABLE(xattr,
28 + AC_HELP_STRING([--enable-xattr],
29 + [enable Extended Attribute support (disabled by default)]),
30 + [xattr_enabled=$enableval],
31 + [xattr_enabled=no])
32 +
33 +if test "x$xattr_enabled" = xyes; then
34 + AC_CHECK_HEADERS(attr/xattr.h)
35 + AC_CHECK_FUNCS(getxattr fgetxattr lgetxattr \
36 + setxattr fsetxattr lsetxattr \
37 + listxattr flistxattr llistxattr,
38 + AC_DEFINE(HAVE_XATTRS,1,[Define if we have a working extended attributes]),)
39 +fi
40 +
41 # Gettext.
42 AM_GNU_GETTEXT([external], [need-formatstring-macros])
43 AM_GNU_GETTEXT_VERSION([0.16])
44 --- a/doc/tar.texi
45 +++ b/doc/tar.texi
46 @@ -3002,6 +3002,10 @@ mechanism.
47 Treat all input file or member names literally, do not interpret
48 escape sequences. @xref{input name quoting}.
49
50 +@opsummary{no-xattrs}
51 +@item --no-xattrs
52 +Causes @command{tar} not to store and not to extract xattrs. @xref{Attributes}.
53 +
54 @opsummary{no-wildcards}
55 @item --no-wildcards
56 Do not use wildcards.
57 @@ -3447,6 +3451,10 @@ Enable or disable warning messages identified by @var{keyword}. The
58 messages are suppressed if @var{keyword} is prefixed with @samp{no-}.
59 @xref{warnings}.
60
61 +@opsummary{xattrs}
62 +@item --xattrs
63 +Causes @command{tar} to store xattrs. @xref{Attributes}.
64 +
65 @opsummary{wildcards}
66 @item --wildcards
67 Use wildcards when matching member names with patterns.
68 @@ -8659,6 +8667,8 @@ implementation able to read @samp{ustar} archives will be able to read
69 most @samp{posix} archives as well, with the only exception that any
70 additional information (such as long file names etc.) will in such
71 case be extracted as plain text files along with the files it refers to.
72 +This is the only format that can store ACLs, SELinux context and extended
73 +attributes.
74
75 This archive format will be the default format for future versions
76 of @GNUTAR{}.
77 @@ -9293,6 +9303,20 @@ Same as both @option{--same-permissions} and @option{--same-order}.
78
79 This option is deprecated, and will be removed in @GNUTAR{} version 1.23.
80
81 +@opindex xattrs
82 +@item --xattrs
83 +This option causes @command{tar} to store the current extended attributes in
84 +the archive.
85 +
86 +The @option{--xattrs} option has no equivalent short option name.
87 +
88 +@opindex no-xattrs
89 +@item --no-xattrs
90 +This option causes @command{tar} not to store the current extended attributes in
91 +the archive and not to extract any extended attributes in an archive.
92 +
93 +The @option{--no-xattrs} option has no equivalent short option name.
94 +
95 @end table
96
97 @node Portability
98 --- a/src/Makefile.am
99 +++ b/src/Makefile.am
100 @@ -20,7 +20,7 @@
101
102 bin_PROGRAMS = tar
103
104 -noinst_HEADERS = arith.h common.h tar.h
105 +noinst_HEADERS = arith.h common.h tar.h xattrs.h
106 tar_SOURCES = \
107 buffer.c\
108 checkpoint.c\
109 @@ -42,10 +42,11 @@ tar_SOURCES = \
110 unlink.c\
111 update.c\
112 utf8.c\
113 - warning.c
114 + warning.c\
115 + xattrs.c
116
117 INCLUDES = -I$(top_srcdir)/gnu -I../ -I../gnu -I$(top_srcdir)/lib -I../lib
118
119 LDADD = ../lib/libtar.a ../gnu/libgnu.a $(LIBINTL) $(LIBICONV)
120
121 -tar_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS)
122 +tar_LDADD = $(LIBS) $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS)
123 --- a/src/common.h
124 +++ b/src/common.h
125 @@ -253,6 +253,9 @@ GLOBAL int same_owner_option;
126 /* If positive, preserve permissions when extracting. */
127 GLOBAL int same_permissions_option;
128
129 +/* If positive, save the user and root xattrs. */
130 +GLOBAL int xattrs_option;
131 +
132 /* When set, strip the given number of file name components from the file name
133 before extracting */
134 GLOBAL size_t strip_name_components;
135 @@ -707,6 +710,9 @@ extern char *output_start;
136
137 void update_archive (void);
138
139 +/* Module attrs.c. */
140 +#include "xattrs.h"
141 +
142 /* Module xheader.c. */
143
144 void xheader_decode (struct tar_stat_info *stat);
145 @@ -727,6 +733,12 @@ bool xheader_string_end (struct xheader *xhdr, char const *keyword);
146 bool xheader_keyword_deleted_p (const char *kw);
147 char *xheader_format_name (struct tar_stat_info *st, const char *fmt,
148 size_t n);
149 +void xheader_xattr_init (struct tar_stat_info *st);
150 +void xheader_xattr_free (struct xattr_array *vals, size_t sz);
151 +void xheader_xattr_copy (const struct tar_stat_info *st,
152 + struct xattr_array **vals, size_t *sz);
153 +void xheader_xattr_add (struct tar_stat_info *st,
154 + const char *key, const char *val, size_t len);
155
156 /* Module system.c */
157
158 --- a/src/create.c
159 +++ b/src/create.c
160 @@ -936,6 +936,21 @@ start_header (struct tar_stat_info *st)
161 GNAME_TO_CHARS (st->gname, header->header.gname);
162 }
163
164 + if (archive_format == POSIX_FORMAT)
165 + {
166 + if (xattrs_option > 0)
167 + {
168 + size_t scan_xattr = 0;
169 + struct xattr_array *xattr_map = st->xattr_map;
170 +
171 + while (scan_xattr < st->xattr_map_size)
172 + {
173 + xheader_store (xattr_map[scan_xattr].xkey, st, &scan_xattr);
174 + ++scan_xattr;
175 + }
176 + }
177 + }
178 +
179 return header;
180 }
181
182 @@ -1711,6 +1726,11 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
183 bool ok;
184 struct stat final_stat;
185
186 + if (fd == 0)
187 + xattrs_xattrs_get (st, p, -1);
188 + else
189 + xattrs_xattrs_get (st, p, fd);
190 +
191 if (is_dir)
192 {
193 const char *tag_file_name;
194 @@ -1829,6 +1849,8 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
195 if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT) < size)
196 write_long_link (st);
197
198 + xattrs_xattrs_get (st, p, -1);
199 +
200 block_ordinal = current_block_ordinal ();
201 st->stat.st_size = 0; /* force 0 size on symlink */
202 header = start_header (st);
203 @@ -1847,11 +1869,20 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
204 }
205 #endif
206 else if (S_ISCHR (st->stat.st_mode))
207 - type = CHRTYPE;
208 + {
209 + type = CHRTYPE;
210 + xattrs_xattrs_get (st, p, -1);
211 + }
212 else if (S_ISBLK (st->stat.st_mode))
213 - type = BLKTYPE;
214 + {
215 + type = BLKTYPE;
216 + xattrs_xattrs_get (st, p, -1);
217 + }
218 else if (S_ISFIFO (st->stat.st_mode))
219 - type = FIFOTYPE;
220 + {
221 + type = FIFOTYPE;
222 + xattrs_xattrs_get (st, p, -1);
223 + }
224 else if (S_ISSOCK (st->stat.st_mode))
225 {
226 WARNOPT (WARN_FILE_IGNORED,
227 --- a/src/extract.c
228 +++ b/src/extract.c
229 @@ -97,6 +97,9 @@ struct delayed_set_stat
230 /* Directory that the name is relative to. */
231 int change_dir;
232
233 + /* extended attributes*/
234 + size_t xattr_map_size; /* Size of the xattr map */
235 + struct xattr_array *xattr_map;
236 /* Length and contents of name. */
237 size_t file_name_len;
238 char file_name[1];
239 @@ -134,6 +137,9 @@ struct delayed_link
240 hard-linked together. */
241 struct string_list *sources;
242
243 + size_t xattr_map_size; /* Size of the xattr map */
244 + struct xattr_array *xattr_map;
245 +
246 /* The desired target of the desired link. */
247 char target[1];
248 };
249 @@ -335,6 +341,8 @@ set_stat (char const *file_name,
250 utime_error (file_name);
251 }
252
253 + xattrs_xattrs_set (st, file_name, typeflag);
254 +
255 if (0 < same_owner_option && ! interdir)
256 {
257 /* Some systems allow non-root users to give files away. Once this
258 @@ -431,6 +439,13 @@ delay_set_stat (char const *file_name, struct tar_stat_info const *st,
259 data->atflag = atflag;
260 data->after_links = 0;
261 data->change_dir = chdir_current;
262 + if (st)
263 + xheader_xattr_copy (st, &data->xattr_map, &data->xattr_map_size);
264 + else
265 + {
266 + data->xattr_map = NULL;
267 + data->xattr_map_size = 0;
268 + }
269 strcpy (data->file_name, file_name);
270 delayed_set_stat_head = data;
271 if (must_be_dot_or_slash (file_name))
272 @@ -673,6 +688,31 @@ maybe_recoverable (char *file_name, bool regular, bool *interdir_made)
273 return RECOVER_NO;
274 }
275
276 +/* Restore stat extended attributes (xattr) for FILE_NAME, using information
277 + given in *ST. Restore before extraction because they may affect layout.
278 + If not restoring permissions, invert the
279 + INVERT_PERMISSIONS bits from the file's current permissions.
280 + TYPEFLAG specifies the type of the file.
281 + FILE_CREATED indicates set_xattr has created the file */
282 +static int
283 +set_xattr (char const *file_name, struct tar_stat_info const *st,
284 + mode_t invert_permissions, char typeflag, int *file_created)
285 +{
286 + int status = 0;
287 + bool interdir_made = false;
288 +
289 + if ((xattrs_option >= 0) && st->xattr_map_size) {
290 + mode_t mode = current_stat_info.stat.st_mode & MODE_RWX & ~ current_umask;
291 +
292 + do
293 + status = mknod (file_name, mode ^ invert_permissions, 0);
294 + while (status && maybe_recoverable ((char *)file_name, false, &interdir_made));
295 + xattrs_xattrs_set (st, file_name, typeflag);
296 + *file_created = 1;
297 + }
298 + return(status);
299 +}
300 +
301 /* Fix the statuses of all directories whose statuses need fixing, and
302 which are not ancestors of FILE_NAME. If AFTER_LINKS is
303 nonzero, do this for all such directories; otherwise, stop at the
304 @@ -733,12 +773,15 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_links)
305 sb.stat.st_gid = data->gid;
306 sb.atime = data->atime;
307 sb.mtime = data->mtime;
308 + sb.xattr_map = data->xattr_map;
309 + sb.xattr_map_size = data->xattr_map_size;
310 set_stat (data->file_name, &sb,
311 -1, current_mode, current_mode_mask,
312 DIRTYPE, data->interdir, data->atflag);
313 }
314
315 delayed_set_stat_head = data->next;
316 + xheader_xattr_free (data->xattr_map, data->xattr_map_size);
317 free (data);
318 }
319 }
320 @@ -854,6 +897,7 @@ extract_dir (char *file_name, int typeflag)
321
322 static int
323 open_output_file (char const *file_name, int typeflag, mode_t mode,
324 + int file_created,
325 mode_t *current_mode, mode_t *current_mode_mask)
326 {
327 int fd;
328 @@ -864,6 +908,10 @@ open_output_file (char const *file_name, int typeflag, mode_t mode,
329 ? O_TRUNC | (dereference_option ? 0 : O_NOFOLLOW)
330 : O_EXCL));
331
332 + /* File might be created in set_xattr. So clear O_EXCL to avoid open() failure */
333 + if (file_created)
334 + openflag = openflag & ~O_EXCL;
335 +
336 if (typeflag == CONTTYPE)
337 {
338 static int conttype_diagnosed;
339 @@ -934,6 +982,7 @@ extract_file (char *file_name, int typeflag)
340 bool interdir_made = false;
341 mode_t mode = (current_stat_info.stat.st_mode & MODE_RWX
342 & ~ (0 < same_owner_option ? S_IRWXG | S_IRWXO : 0));
343 + mode_t invert_permissions = 0 < same_owner_option ? mode & (S_IRWXG | S_IRWXO) : 0;
344 mode_t current_mode = 0;
345 mode_t current_mode_mask = 0;
346
347 @@ -950,7 +999,17 @@ extract_file (char *file_name, int typeflag)
348 }
349 else
350 {
351 + int file_created = 0;
352 + if (set_xattr (file_name, &current_stat_info, invert_permissions,
353 + typeflag, &file_created))
354 + {
355 + skip_member ();
356 + open_error (file_name);
357 + return 1;
358 + }
359 +
360 while ((fd = open_output_file (file_name, typeflag, mode,
361 + file_created,
362 &current_mode, &current_mode_mask))
363 < 0)
364 {
365 @@ -1091,6 +1150,7 @@ create_placeholder_file (char *file_name, bool is_symlink, bool *interdir_made)
366 + strlen (file_name) + 1);
367 p->sources->next = 0;
368 strcpy (p->sources->string, file_name);
369 + xheader_xattr_copy (&current_stat_info, &p->xattr_map, &p->xattr_map_size);
370 strcpy (p->target, current_stat_info.link_name);
371
372 h = delayed_set_stat_head;
373 @@ -1525,6 +1585,8 @@ apply_delayed_links (void)
374 st1.stat.st_gid = ds->gid;
375 st1.atime = ds->atime;
376 st1.mtime = ds->mtime;
377 + st1.xattr_map = ds->xattr_map;
378 + st1.xattr_map_size = ds->xattr_map_size;
379 set_stat (source, &st1, -1, 0, 0, SYMTYPE,
380 false, AT_SYMLINK_NOFOLLOW);
381 valid_source = source;
382 @@ -1539,6 +1601,8 @@ apply_delayed_links (void)
383 sources = next;
384 }
385
386 + xheader_xattr_free (ds->xattr_map, ds->xattr_map_size);
387 +
388 {
389 struct delayed_link *next = ds->next;
390 free (ds);
391 --- a/src/list.c
392 +++ b/src/list.c
393 @@ -604,6 +604,8 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
394 assign_string (&stat_info->gname,
395 header->header.gname[0] ? header->header.gname : NULL);
396
397 + xheader_xattr_init (stat_info);
398 +
399 if (format == OLDGNU_FORMAT && incremental_option)
400 {
401 stat_info->atime.tv_sec = TIME_FROM_HEADER (header->oldgnu_header.atime);
402 --- a/src/tar.c
403 +++ b/src/tar.c
404 @@ -304,6 +304,7 @@ enum
405 NO_UNQUOTE_OPTION,
406 NO_WILDCARDS_MATCH_SLASH_OPTION,
407 NO_WILDCARDS_OPTION,
408 + NO_XATTR_OPTION,
409 NULL_OPTION,
410 NUMERIC_OWNER_OPTION,
411 OCCURRENCE_OPTION,
412 @@ -340,7 +341,8 @@ enum
413 VOLNO_FILE_OPTION,
414 WARNING_OPTION,
415 WILDCARDS_MATCH_SLASH_OPTION,
416 - WILDCARDS_OPTION
417 + WILDCARDS_OPTION,
418 + XATTR_OPTION
419 };
420
421 const char *argp_program_version = "tar (" PACKAGE_NAME ") " VERSION;
422 @@ -516,6 +518,10 @@ static struct argp_option options[] = {
423 {"preserve-order", 's', 0, 0,
424 N_("sort names to extract to match archive"), GRID+1 },
425 {"same-order", 0, 0, OPTION_ALIAS, NULL, GRID+1 },
426 + {"xattrs", XATTR_OPTION, 0, 0,
427 + N_("Save the user/root xattrs to the archive"), GRID+1 },
428 + {"no-xattrs", NO_XATTR_OPTION, 0, 0,
429 + N_("Don't extract the user/root xattrs from the archive"), GRID+1 },
430 {"preserve", PRESERVE_OPTION, 0, 0,
431 N_("same as both -p and -s"), GRID+1 },
432 {"delay-directory-restore", DELAY_DIRECTORY_RESTORE_OPTION, 0, 0,
433 @@ -2079,6 +2085,15 @@ parse_opt (int key, char *arg, struct argp_state *state)
434 same_permissions_option = -1;
435 break;
436
437 + case XATTR_OPTION:
438 + set_archive_format ("posix");
439 + xattrs_option = 1;
440 + break;
441 +
442 + case NO_XATTR_OPTION:
443 + xattrs_option = -1;
444 + break;
445 +
446 case RECURSION_OPTION:
447 recursion_option = FNM_LEADING_DIR;
448 break;
449 @@ -2461,6 +2476,15 @@ decode_options (int argc, char **argv)
450 || subcommand_option != LIST_SUBCOMMAND))
451 USAGE_ERROR ((0, 0, _("--pax-option can be used only on POSIX archives")));
452
453 + /* star create's non-POSIX typed archives with xattr support, so allow the
454 + extra headers */
455 + if ((xattrs_option > 0)
456 + && archive_format != POSIX_FORMAT
457 + && (subcommand_option != EXTRACT_SUBCOMMAND
458 + || subcommand_option != DIFF_SUBCOMMAND
459 + || subcommand_option != LIST_SUBCOMMAND))
460 + USAGE_ERROR ((0, 0, _("--xattrs can be used only on POSIX archives")));
461 +
462 /* If ready to unlink hierarchies, so we are for simpler files. */
463 if (recursive_unlink_option)
464 old_files_option = UNLINK_FIRST_OLD_FILES;
465 @@ -2713,6 +2737,7 @@ void
466 tar_stat_destroy (struct tar_stat_info *st)
467 {
468 tar_stat_close (st);
469 + xheader_xattr_free (st->xattr_map, st->xattr_map_size);
470 free (st->orig_file_name);
471 free (st->file_name);
472 free (st->link_name);
473 --- a/src/tar.h
474 +++ b/src/tar.h
475 @@ -276,6 +276,14 @@ struct xheader
476 uintmax_t string_length;
477 };
478
479 +/* Information about xattrs for a file. */
480 +struct xattr_array
481 + {
482 + char *xkey;
483 + char *xval_ptr;
484 + size_t xval_len;
485 + };
486 +
487 struct tar_stat_info
488 {
489 char *orig_file_name; /* name of file read from the archive header */
490 @@ -287,6 +295,7 @@ struct tar_stat_info
491
492 char *uname; /* user name of owner */
493 char *gname; /* group name of owner */
494 +
495 struct stat stat; /* regular filesystem stat */
496
497 /* STAT doesn't always have access, data modification, and status
498 @@ -309,6 +318,9 @@ struct tar_stat_info
499 size_t sparse_map_size; /* Size of the sparse map */
500 struct sp_array *sparse_map;
501
502 + size_t xattr_map_size; /* Size of the xattr map */
503 + struct xattr_array *xattr_map;
504 +
505 /* Extended headers */
506 struct xheader xhdr;
507
508 --- /dev/null
509 +++ b/src/xattrs.c
510 @@ -0,0 +1,181 @@
511 +/* Create a tar archive.
512 +
513 + Copyright (C) 2006 Free Software Foundation, Inc.
514 +
515 + Written by James Antill, on 2006-07-27.
516 +
517 + This program is free software; you can redistribute it and/or modify it
518 + under the terms of the GNU General Public License as published by the
519 + Free Software Foundation; either version 2, or (at your option) any later
520 + version.
521 +
522 + This program is distributed in the hope that it will be useful, but
523 + WITHOUT ANY WARRANTY; without even the implied warranty of
524 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
525 + Public License for more details.
526 +
527 + You should have received a copy of the GNU General Public License along
528 + with this program; if not, write to the Free Software Foundation, Inc.,
529 + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
530 +
531 +#include <system.h>
532 +
533 +#include <quotearg.h>
534 +
535 +#include "common.h"
536 +
537 +
538 +#ifndef HAVE_ATTR_XATTR_H
539 +# undef HAVE_XATTRS
540 +#endif
541 +
542 +#ifdef HAVE_ATTR_XATTR_H
543 +# include <attr/xattr.h>
544 +#endif
545 +
546 +
547 +void xattrs_xattrs_get (struct tar_stat_info *st, char const *file_name, int fd)
548 +{
549 + if (xattrs_option > 0)
550 + { /* get all xattrs ... this include security.* and system.* if
551 + available. We filter them here, but we have to filter them
552 + in xattrs_xattrs_set() anyway.
553 + */
554 + static ssize_t xsz = 1024;
555 + static char *xatrs = NULL;
556 + ssize_t xret = -1;
557 +
558 +#ifndef HAVE_XATTRS
559 + static int done = 0;
560 + if ((xattrs_option > 0) && !done)
561 + WARN ((0, 0, _("Xattr support requested, but not available")));
562 + done = 1;
563 +#else
564 +
565 + if (!xatrs) xatrs = xmalloc (xsz);
566 +
567 + while (((fd == -1) ?
568 + ((xret = llistxattr (file_name, xatrs, xsz)) == -1) :
569 + ((xret = flistxattr (fd, xatrs, xsz)) == -1)) &&
570 + (errno == ERANGE))
571 + {
572 + xsz <<= 1;
573 + xatrs = xrealloc (xatrs, xsz);
574 + }
575 +
576 + if (xret == -1)
577 + call_arg_warn ((fd == -1) ? "llistxattrs" : "flistxattrs", file_name);
578 + else
579 + {
580 + const char *attr = xatrs;
581 + static ssize_t asz = 1024;
582 + static char *val = NULL;
583 +
584 + if (!val) val = xmalloc (asz);
585 +
586 + while (xret > 0)
587 + {
588 + size_t len = strlen (attr);
589 + ssize_t aret = 0;
590 +
591 + /* Archive all xattrs during creation, decide at extraction time
592 + * which ones are of interest/use for the target filesystem. */
593 + while (((fd == -1) ?
594 + ((aret = lgetxattr (file_name, attr, val, asz)) == -1) :
595 + ((aret = fgetxattr (fd, attr, val, asz)) == -1)) &&
596 + (errno == ERANGE))
597 + {
598 + asz <<= 1;
599 + val = xrealloc (val, asz);
600 + }
601 +
602 + if (aret != -1)
603 + xheader_xattr_add (st, attr, val, aret);
604 + else if (errno != ENOATTR)
605 + call_arg_warn ((fd==-1) ? "lgetxattr" : "fgetxattr", file_name);
606 +
607 + attr += len + 1;
608 + xret -= len + 1;
609 + }
610 + }
611 +#endif
612 + }
613 +}
614 +
615 +static void xattrs__fd_set (struct tar_stat_info const *st,
616 + char const *file_name, char typeflag,
617 + const char *attr,
618 + const char *ptr, size_t len)
619 +{
620 +#ifdef HAVE_XATTRS
621 + if (ptr)
622 + {
623 + const char *sysname = "setxattr";
624 + int ret = -1;
625 +
626 + if (typeflag != SYMTYPE)
627 + ret = setxattr (file_name, attr, ptr, len, 0);
628 + else
629 + {
630 + sysname = "lsetxattr";
631 + ret = lsetxattr (file_name, attr, ptr, len, 0);
632 + }
633 +
634 + /* do not print warnings when SELinux is disabled */
635 + if ((ret == -1) && (errno != EPERM) && (errno != ENOTSUP))
636 + call_arg_error (sysname, file_name);
637 + }
638 +#endif
639 +}
640 +
641 +static char *skip_to_ext_fields (char *ptr)
642 +{
643 + ptr += strcspn (ptr, ":,\n"); /* skip tag name. Ie. user/group/default/mask */
644 +
645 + if (*ptr != ':')
646 + return (ptr); /* error? no user/group field */
647 + ++ptr;
648 +
649 + ptr += strcspn (ptr, ":,\n"); /* skip user/group name */
650 +
651 + if (*ptr != ':')
652 + return (ptr); /* error? no perms field */
653 + ++ptr;
654 +
655 + ptr += strcspn (ptr, ":,\n"); /* skip perms */
656 +
657 + if (*ptr != ':')
658 + return (ptr); /* no extra fields */
659 +
660 + return (ptr);
661 +}
662 +
663 +void xattrs_xattrs_set (struct tar_stat_info const *st,
664 + char const *file_name, char typeflag)
665 +{
666 + if ((xattrs_option >= 0) && st->xattr_map_size)
667 + {
668 + size_t scan = 0;
669 +
670 +#ifndef HAVE_XATTRS
671 + static int done = 0;
672 + if (!done)
673 + WARN ((0, 0, _("Xattr support requested, but not available")));
674 + done = 1;
675 +#else
676 + while (scan < st->xattr_map_size)
677 + {
678 + char *keyword = st->xattr_map[scan].xkey;
679 +
680 + /* assert (!memcpy (keyword, "SCHILY.xattr.", strlen("SCHILY.xattr."))); */
681 + keyword += strlen ("SCHILY.xattr.");
682 +
683 + xattrs__fd_set (st, file_name, typeflag, keyword,
684 + st->xattr_map[scan].xval_ptr,
685 + st->xattr_map[scan].xval_len);
686 +
687 + ++scan;
688 + }
689 +#endif
690 + }
691 +}
692 --- /dev/null
693 +++ b/src/xattrs.h
694 @@ -0,0 +1,6 @@
695 +
696 +extern void xattrs_xattrs_get (struct tar_stat_info *st,
697 + char const *file_name, int fd);
698 +
699 +extern void xattrs_xattrs_set (struct tar_stat_info const *st,
700 + char const *file_name, char typeflag);
701 --- a/src/xheader.c
702 +++ b/src/xheader.c
703 @@ -460,6 +460,74 @@ xheader_write_global (struct xheader *xhdr)
704 }
705 }
706
707 +void xheader_xattr_init (struct tar_stat_info *st)
708 +{
709 + st->xattr_map = NULL;
710 + st->xattr_map_size = 0;
711 +}
712 +
713 +void xheader_xattr_free (struct xattr_array *xattr_map, size_t xattr_map_size)
714 +{
715 + size_t scan = 0;
716 +
717 + while (scan < xattr_map_size)
718 + {
719 + free (xattr_map[scan].xkey);
720 + free (xattr_map[scan].xval_ptr);
721 +
722 + ++scan;
723 + }
724 + free (xattr_map);
725 +}
726 +
727 +static void xheader_xattr__add (struct xattr_array **xattr_map,
728 + size_t *xattr_map_size,
729 + const char *key, const char *val, size_t len)
730 +{
731 + size_t pos = (*xattr_map_size)++;
732 +
733 + *xattr_map = xrealloc (*xattr_map,
734 + *xattr_map_size * sizeof (struct xattr_array));
735 + (*xattr_map)[pos].xkey = xstrdup (key);
736 + (*xattr_map)[pos].xval_ptr = xmemdup (val, len + 1);
737 + (*xattr_map)[pos].xval_len = len;
738 +}
739 +
740 +void xheader_xattr_add (struct tar_stat_info *st,
741 + const char *key, const char *val, size_t len)
742 +{
743 + size_t klen = strlen (key);
744 + char *xkey = xmalloc (strlen("SCHILY.xattr.") + klen + 1);
745 + char *tmp = xkey;
746 +
747 + tmp = stpcpy (tmp, "SCHILY.xattr.");
748 + tmp = stpcpy (tmp, key);
749 +
750 + xheader_xattr__add (&st->xattr_map, &st->xattr_map_size, xkey, val, len);
751 +
752 + free (xkey);
753 +}
754 +
755 +void xheader_xattr_copy (const struct tar_stat_info *st,
756 + struct xattr_array **xattr_map, size_t *xattr_map_size)
757 +{
758 + size_t scan = 0;
759 +
760 + *xattr_map = NULL;
761 + *xattr_map_size = 0;
762 +
763 + while (scan < st->xattr_map_size)
764 + {
765 + char *key = st->xattr_map[scan].xkey;
766 + char *val = st->xattr_map[scan].xval_ptr;
767 + size_t len = st->xattr_map[scan].xval_len;
768 +
769 + xheader_xattr__add (xattr_map, xattr_map_size, key, val, len);
770 +
771 + ++scan;
772 + }
773 +}
774 +
775
776 /* General Interface */
777
778 @@ -473,6 +541,7 @@ struct xhdr_tab
779 struct xheader *, void const *data);
780 void (*decoder) (struct tar_stat_info *, char const *, char const *, size_t);
781 int flags;
782 + bool prefix;
783 };
784
785 /* This declaration must be extern, because ISO C99 section 6.9.2
786 @@ -489,8 +558,17 @@ locate_handler (char const *keyword)
787 struct xhdr_tab const *p;
788
789 for (p = xhdr_tab; p->keyword; p++)
790 - if (strcmp (p->keyword, keyword) == 0)
791 - return p;
792 + if (p->prefix)
793 + {
794 + if (strncmp (p->keyword, keyword, strlen(p->keyword)) == 0)
795 + return p;
796 + }
797 + else
798 + {
799 + if (strcmp (p->keyword, keyword) == 0)
800 + return p;
801 + }
802 +
803 return NULL;
804 }
805
806 @@ -500,7 +578,7 @@ xheader_protected_pattern_p (const char *pattern)
807 struct xhdr_tab const *p;
808
809 for (p = xhdr_tab; p->keyword; p++)
810 - if ((p->flags & XHDR_PROTECTED) && fnmatch (pattern, p->keyword, 0) == 0)
811 + if (!p->prefix && (p->flags & XHDR_PROTECTED) && fnmatch (pattern, p->keyword, 0) == 0)
812 return true;
813 return false;
814 }
815 @@ -511,7 +589,7 @@ xheader_protected_keyword_p (const char *keyword)
816 struct xhdr_tab const *p;
817
818 for (p = xhdr_tab; p->keyword; p++)
819 - if ((p->flags & XHDR_PROTECTED) && strcmp (p->keyword, keyword) == 0)
820 + if (!p->prefix && (p->flags & XHDR_PROTECTED) && strcmp (p->keyword, keyword) == 0)
821 return true;
822 return false;
823 }
824 @@ -1470,6 +1548,27 @@ volume_filename_decoder (struct tar_stat_info *st,
825 }
826
827 static void
828 +xattr_coder (struct tar_stat_info const *st , char const *keyword,
829 + struct xheader *xhdr, void const *data)
830 +{
831 + struct xattr_array *xattr_map = st->xattr_map;
832 + const size_t *off = data;
833 + xheader_print_n (xhdr, keyword,
834 + xattr_map[*off].xval_ptr, xattr_map[*off].xval_len);
835 +}
836 +
837 +static void
838 +xattr_decoder (struct tar_stat_info *st,
839 + char const *keyword, char const *arg, size_t size)
840 +{
841 + char *xstr = NULL;
842 +
843 + xstr = xmemdup (arg, size + 1);
844 + xheader_xattr_add (st, keyword + strlen("SCHILY.xattr."), xstr, size);
845 + free (xstr);
846 +}
847 +
848 +static void
849 sparse_major_coder (struct tar_stat_info const *st, char const *keyword,
850 struct xheader *xhdr, void const *data)
851 {
852 @@ -1506,53 +1605,53 @@ sparse_minor_decoder (struct tar_stat_info *st,
853 }
854
855 struct xhdr_tab const xhdr_tab[] = {
856 - { "atime", atime_coder, atime_decoder, 0 },
857 - { "comment", dummy_coder, dummy_decoder, 0 },
858 - { "charset", dummy_coder, dummy_decoder, 0 },
859 - { "ctime", ctime_coder, ctime_decoder, 0 },
860 - { "gid", gid_coder, gid_decoder, 0 },
861 - { "gname", gname_coder, gname_decoder, 0 },
862 - { "linkpath", linkpath_coder, linkpath_decoder, 0 },
863 - { "mtime", mtime_coder, mtime_decoder, 0 },
864 - { "path", path_coder, path_decoder, 0 },
865 - { "size", size_coder, size_decoder, 0 },
866 - { "uid", uid_coder, uid_decoder, 0 },
867 - { "uname", uname_coder, uname_decoder, 0 },
868 + { "atime", atime_coder, atime_decoder, 0, false },
869 + { "comment", dummy_coder, dummy_decoder, 0, false },
870 + { "charset", dummy_coder, dummy_decoder, 0, false },
871 + { "ctime", ctime_coder, ctime_decoder, 0, false },
872 + { "gid", gid_coder, gid_decoder, 0, false },
873 + { "gname", gname_coder, gname_decoder, 0, false },
874 + { "linkpath", linkpath_coder, linkpath_decoder, 0, false },
875 + { "mtime", mtime_coder, mtime_decoder, 0, false },
876 + { "path", path_coder, path_decoder, 0, false },
877 + { "size", size_coder, size_decoder, 0, false },
878 + { "uid", uid_coder, uid_decoder, 0, false },
879 + { "uname", uname_coder, uname_decoder, 0, false },
880
881 /* Sparse file handling */
882 { "GNU.sparse.name", path_coder, path_decoder,
883 - XHDR_PROTECTED },
884 + XHDR_PROTECTED, false },
885 { "GNU.sparse.major", sparse_major_coder, sparse_major_decoder,
886 - XHDR_PROTECTED },
887 + XHDR_PROTECTED, false },
888 { "GNU.sparse.minor", sparse_minor_coder, sparse_minor_decoder,
889 - XHDR_PROTECTED },
890 + XHDR_PROTECTED, false },
891 { "GNU.sparse.realsize", sparse_size_coder, sparse_size_decoder,
892 - XHDR_PROTECTED },
893 + XHDR_PROTECTED, false },
894 { "GNU.sparse.numblocks", sparse_numblocks_coder, sparse_numblocks_decoder,
895 - XHDR_PROTECTED },
896 + XHDR_PROTECTED, false },
897
898 /* tar 1.14 - 1.15.90 keywords. */
899 { "GNU.sparse.size", sparse_size_coder, sparse_size_decoder,
900 - XHDR_PROTECTED },
901 + XHDR_PROTECTED, false },
902 /* tar 1.14 - 1.15.1 keywords. Multiple instances of these appeared in 'x'
903 headers, and each of them was meaningful. It confilcted with POSIX specs,
904 which requires that "when extended header records conflict, the last one
905 given in the header shall take precedence." */
906 { "GNU.sparse.offset", sparse_offset_coder, sparse_offset_decoder,
907 - XHDR_PROTECTED },
908 + XHDR_PROTECTED, false },
909 { "GNU.sparse.numbytes", sparse_numbytes_coder, sparse_numbytes_decoder,
910 - XHDR_PROTECTED },
911 + XHDR_PROTECTED, false },
912 /* tar 1.15.90 keyword, introduced to remove the above-mentioned conflict. */
913 { "GNU.sparse.map", NULL /* Unused, see pax_dump_header() */,
914 - sparse_map_decoder, 0 },
915 + sparse_map_decoder, 0, false },
916
917 { "GNU.dumpdir", dumpdir_coder, dumpdir_decoder,
918 - XHDR_PROTECTED },
919 + XHDR_PROTECTED, false },
920
921 /* Keeps the tape/volume label. May be present only in the global headers.
922 Equivalent to GNUTYPE_VOLHDR. */
923 { "GNU.volume.label", volume_label_coder, volume_label_decoder,
924 - XHDR_PROTECTED | XHDR_GLOBAL },
925 + XHDR_PROTECTED | XHDR_GLOBAL, false },
926
927 /* These may be present in a first global header of the archive.
928 They provide the same functionality as GNUTYPE_MULTIVOL header.
929 @@ -1561,11 +1660,14 @@ struct xhdr_tab const xhdr_tab[] = {
930 GNU.volume.offset keeps the offset of the start of this volume,
931 otherwise kept in oldgnu_header.offset. */
932 { "GNU.volume.filename", volume_label_coder, volume_filename_decoder,
933 - XHDR_PROTECTED | XHDR_GLOBAL },
934 + XHDR_PROTECTED | XHDR_GLOBAL, false },
935 { "GNU.volume.size", volume_size_coder, volume_size_decoder,
936 - XHDR_PROTECTED | XHDR_GLOBAL },
937 + XHDR_PROTECTED | XHDR_GLOBAL, false },
938 { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder,
939 - XHDR_PROTECTED | XHDR_GLOBAL },
940 + XHDR_PROTECTED | XHDR_GLOBAL, false },
941 +
942 + /* xattrs use the star format. note we only save some variants... */
943 + { "SCHILY.xattr", xattr_coder, xattr_decoder, 0, true },
944
945 - { NULL, NULL, NULL, 0 }
946 + { NULL, NULL, NULL, 0, false }
947 };