]> git.ipfire.org Git - thirdparty/tar.git/blame - src/xattrs.c
Avoid gcc 13 "unused parameter" warnings
[thirdparty/tar.git] / src / xattrs.c
CommitLineData
69633804
PR
1/* Support for extended attributes.
2
c6f0ad51 3 Copyright (C) 2006-2024 Free Software Foundation, Inc.
69633804 4
cd7bdd40 5 This file is part of GNU tar.
69633804 6
cd7bdd40
PE
7 GNU tar is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
69633804 11
cd7bdd40
PE
12 GNU tar is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
69633804 16
cd7bdd40
PE
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20 Written by James Antill, on 2006-07-27. */
69633804 21
d36f5a3c 22#include <config.h>
69633804
PR
23#include <system.h>
24
25#include <fnmatch.h>
26#include <quotearg.h>
27
28#include "common.h"
29
30#include "xattr-at.h"
085cace1 31#include "selinux-at.h"
69633804 32
66262c10
SP
33#define XATTRS_PREFIX "SCHILY.xattr."
34#define XATTRS_PREFIX_LEN (sizeof XATTRS_PREFIX - 1)
35
36void
37xheader_xattr_init (struct tar_stat_info *st)
38{
39 xattr_map_init (&st->xattr_map);
40
41 st->acls_a_ptr = NULL;
42 st->acls_a_len = 0;
43 st->acls_d_ptr = NULL;
44 st->acls_d_len = 0;
45 st->cntx_name = NULL;
46}
47
48void
49xattr_map_init (struct xattr_map *map)
50{
51 memset (map, 0, sizeof *map);
52}
53
54void
55xattr_map_free (struct xattr_map *xattr_map)
56{
57 size_t i;
58
59 for (i = 0; i < xattr_map->xm_size; i++)
60 {
61 free (xattr_map->xm_map[i].xkey);
62 free (xattr_map->xm_map[i].xval_ptr);
63 }
64 free (xattr_map->xm_map);
65}
66
67void
68xattr_map_add (struct xattr_map *map,
69 const char *key, const char *val, size_t len)
70{
71 struct xattr_array *p;
2ccd643d 72
66262c10
SP
73 if (map->xm_size == map->xm_max)
74 map->xm_map = x2nrealloc (map->xm_map, &map->xm_max,
75 sizeof (map->xm_map[0]));
76 p = &map->xm_map[map->xm_size];
77 p->xkey = xstrdup (key);
78 p->xval_ptr = xmemdup (val, len + 1);
79 p->xval_len = len;
80 map->xm_size++;
81}
82
83void
84xheader_xattr_add (struct tar_stat_info *st,
85 const char *key, const char *val, size_t len)
86{
87 size_t klen = strlen (key);
88 char *xkey = xmalloc (XATTRS_PREFIX_LEN + klen + 1);
89 char *tmp = xkey;
90
91 tmp = stpcpy (tmp, XATTRS_PREFIX);
92 stpcpy (tmp, key);
93
94 xattr_map_add (&st->xattr_map, xkey, val, len);
95
96 free (xkey);
97}
98
99void
100xattr_map_copy (struct xattr_map *dst, const struct xattr_map *src)
101{
102 size_t i;
103
104 for (i = 0; i < src->xm_size; i++)
105 xattr_map_add (dst, src->xm_map[i].xkey,
106 src->xm_map[i].xval_ptr,
107 src->xm_map[i].xval_len);
108}
109\f
69633804
PR
110struct xattrs_mask_map
111{
112 const char **masks;
3c4e51fa
SP
113 size_t size;
114 size_t used;
69633804
PR
115};
116
117/* list of fnmatch patterns */
118static struct
119{
120 /* lists of fnmatch patterns */
121 struct xattrs_mask_map incl;
122 struct xattrs_mask_map excl;
123} xattrs_setup;
124
d36f5a3c
PR
125/* disable posix acls when problem found in gnulib script m4/acl.m4 */
126#if ! USE_ACL
127# undef HAVE_POSIX_ACLS
128#endif
129
130#ifdef HAVE_POSIX_ACLS
131# include "acl.h"
132# include <sys/acl.h>
54610255
SP
133# ifdef HAVE_ACL_LIBACL_H
134# /* needed for numeric-owner support */
135# include <acl/libacl.h>
136# endif
d36f5a3c
PR
137#endif
138
139#ifdef HAVE_POSIX_ACLS
140
141/* acl-at wrappers, TODO: move to gnulib in future? */
8ebbef8a
PE
142static acl_t acl_get_file_at (int, const char *, acl_type_t);
143static int acl_set_file_at (int, const char *, acl_type_t, acl_t);
144static int file_has_acl_at (int, char const *, struct stat const *);
7fe7adcb 145static int acl_delete_def_file_at (int, char const *);
d36f5a3c
PR
146
147/* acl_get_file_at */
148#define AT_FUNC_NAME acl_get_file_at
149#define AT_FUNC_RESULT acl_t
150#define AT_FUNC_FAIL (acl_t)NULL
151#define AT_FUNC_F1 acl_get_file
152#define AT_FUNC_POST_FILE_PARAM_DECLS , acl_type_t type
153#define AT_FUNC_POST_FILE_ARGS , type
154#include "at-func.c"
155#undef AT_FUNC_NAME
156#undef AT_FUNC_F1
157#undef AT_FUNC_RESULT
158#undef AT_FUNC_FAIL
159#undef AT_FUNC_POST_FILE_PARAM_DECLS
160#undef AT_FUNC_POST_FILE_ARGS
161
162/* acl_set_file_at */
163#define AT_FUNC_NAME acl_set_file_at
164#define AT_FUNC_F1 acl_set_file
165#define AT_FUNC_POST_FILE_PARAM_DECLS , acl_type_t type, acl_t acl
166#define AT_FUNC_POST_FILE_ARGS , type, acl
167#include "at-func.c"
168#undef AT_FUNC_NAME
169#undef AT_FUNC_F1
170#undef AT_FUNC_POST_FILE_PARAM_DECLS
171#undef AT_FUNC_POST_FILE_ARGS
172
7fe7adcb
PR
173/* acl_delete_def_file_at */
174#define AT_FUNC_NAME acl_delete_def_file_at
175#define AT_FUNC_F1 acl_delete_def_file
176#define AT_FUNC_POST_FILE_PARAM_DECLS
177#define AT_FUNC_POST_FILE_ARGS
178#include "at-func.c"
179#undef AT_FUNC_NAME
180#undef AT_FUNC_F1
181#undef AT_FUNC_POST_FILE_PARAM_DECLS
182#undef AT_FUNC_POST_FILE_ARGS
183
d36f5a3c
PR
184/* gnulib file_has_acl_at */
185#define AT_FUNC_NAME file_has_acl_at
186#define AT_FUNC_F1 file_has_acl
187#define AT_FUNC_POST_FILE_PARAM_DECLS , struct stat const *st
188#define AT_FUNC_POST_FILE_ARGS , st
189#include "at-func.c"
190#undef AT_FUNC_NAME
191#undef AT_FUNC_F1
192#undef AT_FUNC_POST_FILE_PARAM_DECLS
193#undef AT_FUNC_POST_FILE_ARGS
194
195/* convert unix permissions into an ACL ... needed due to "default" ACLs */
4ac671c4
SP
196static acl_t
197perms2acl (int perms)
d36f5a3c
PR
198{
199 char val[] = "user::---,group::---,other::---";
200 /* 0123456789 123456789 123456789 123456789 */
201
4ac671c4
SP
202 /* user */
203 if (perms & 0400)
204 val[6] = 'r';
205 if (perms & 0200)
206 val[7] = 'w';
207 if (perms & 0100)
208 val[8] = 'x';
d36f5a3c
PR
209
210 /* group */
4ac671c4
SP
211 if (perms & 0040)
212 val[17] = 'r';
213 if (perms & 0020)
214 val[18] = 'w';
215 if (perms & 0010)
216 val[19] = 'x';
d36f5a3c
PR
217
218 /* other */
4ac671c4
SP
219 if (perms & 0004)
220 val[28] = 'r';
221 if (perms & 0002)
222 val[29] = 'w';
223 if (perms & 0001)
224 val[30] = 'x';
225
226 return acl_from_text (val);
d36f5a3c
PR
227}
228
4ac671c4
SP
229static char *
230skip_to_ext_fields (char *ptr)
d36f5a3c 231{
3c4e51fa 232 /* skip tag name (user/group/default/mask) */
cbc51277 233 ptr += strcspn (ptr, ":,\n");
d36f5a3c
PR
234
235 if (*ptr != ':')
3c4e51fa 236 return ptr;
d36f5a3c
PR
237 ++ptr;
238
3c4e51fa 239 ptr += strcspn (ptr, ":,\n"); /* skip user/group name */
d36f5a3c
PR
240
241 if (*ptr != ':')
3c4e51fa 242 return ptr;
d36f5a3c
PR
243 ++ptr;
244
3c4e51fa 245 ptr += strcspn (ptr, ":,\n"); /* skip perms */
d36f5a3c 246
4ac671c4 247 return ptr;
d36f5a3c
PR
248}
249
250/* The POSIX draft allows extra fields after the three main ones. Star
251 uses this to add a fourth field for user/group which is the numeric ID.
3c4e51fa
SP
252 This function removes such extra fields by overwriting them with the
253 characters that follow. */
254static char *
255fixup_extra_acl_fields (char *ptr)
d36f5a3c 256{
3c4e51fa
SP
257 char *src = ptr;
258 char *dst = ptr;
d36f5a3c
PR
259
260 while (*src)
261 {
262 const char *old = src;
263 size_t len = 0;
264
265 src = skip_to_ext_fields (src);
266 len = src - old;
4ac671c4 267 if (old != dst)
3c4e51fa 268 memmove (dst, old, len);
d36f5a3c
PR
269 dst += len;
270
3c4e51fa
SP
271 if (*src == ':') /* We have extra fields, skip them all */
272 src += strcspn (src, "\n,");
d36f5a3c
PR
273
274 if ((*src == '\n') || (*src == ','))
3c4e51fa 275 *dst++ = *src++; /* also done when dst == src, but that's ok */
d36f5a3c
PR
276 }
277 if (src != dst)
278 *dst = 0;
279
280 return ptr;
281}
282
7fe7adcb
PR
283/* Set the "system.posix_acl_access/system.posix_acl_default" extended
284 attribute. Called only when acls_option > 0. */
4ac671c4
SP
285static void
286xattrs__acls_set (struct tar_stat_info const *st,
3c4e51fa 287 char const *file_name, int type,
2ccd643d 288 char *ptr, bool def)
cbc51277 289{
d36f5a3c
PR
290 acl_t acl;
291
292 if (ptr)
293 {
d36f5a3c 294 ptr = fixup_extra_acl_fields (ptr);
d36f5a3c 295 acl = acl_from_text (ptr);
d36f5a3c 296 }
7fe7adcb
PR
297 else if (def)
298 {
299 /* No "default" IEEE 1003.1e ACL set for directory. At this moment,
300 FILE_NAME may already have inherited default acls from parent
301 directory; clean them up. */
302 if (acl_delete_def_file_at (chdir_fd, file_name))
303 WARNOPT (WARN_XATTR_WRITE,
304 (0, errno,
305 _("acl_delete_def_file_at: Cannot drop default POSIX ACLs "
306 "for file '%s'"),
307 file_name));
308 return;
309 }
d36f5a3c 310 else
7fe7adcb 311 acl = perms2acl (st->stat.st_mode);
d36f5a3c 312
3c4e51fa 313 if (!acl)
d36f5a3c
PR
314 {
315 call_arg_warn ("acl_from_text", file_name);
316 return;
317 }
318
319 if (acl_set_file_at (chdir_fd, file_name, type, acl) == -1)
320 /* warn even if filesystem does not support acls */
4ac671c4
SP
321 WARNOPT (WARN_XATTR_WRITE,
322 (0, errno,
3c4e51fa 323 _ ("acl_set_file_at: Cannot set POSIX ACLs for file '%s'"),
4ac671c4 324 file_name));
d36f5a3c
PR
325
326 acl_free (acl);
327}
328
62c0c3a7
SP
329/* Cleanup textual representation of the ACL in VAL by eliminating tab
330 characters and comments */
331static void
332xattrs_acls_cleanup (char *val, size_t *plen)
333{
334 char *p, *q;
335
336 p = q = val + strcspn (val, "#\t");
337 while (*q)
338 {
339 if (*q == '\t')
340 q++;
341 else if (*q == '#')
342 {
343 while (*q != '\n')
344 q++;
345 }
346 else
347 *p++ = *q++;
348 }
349 *plen = p - val;
350 *p++ = 0;
351}
352
4ac671c4 353static void
54610255
SP
354acls_get_text (int parentfd, const char *file_name, acl_type_t type,
355 char **ret_ptr, size_t * ret_len)
cbc51277 356{
d36f5a3c 357 char *val = NULL;
d36f5a3c
PR
358 acl_t acl;
359
54610255 360 if (!(acl = acl_get_file_at (parentfd, file_name, type)))
d36f5a3c
PR
361 {
362 if (errno != ENOTSUP)
3c4e51fa 363 call_arg_warn ("acl_get_file_at", file_name);
d36f5a3c
PR
364 return;
365 }
366
54610255
SP
367 if (numeric_owner_option)
368 {
369#ifdef HAVE_ACL_LIBACL_H
370 val = acl_to_any_text (acl, NULL, '\n',
371 TEXT_SOME_EFFECTIVE | TEXT_NUMERIC_IDS);
372#else
373 static int warned;
374 if (!warned)
375 {
376 WARN ((0, 0, _("--numeric-owner is ignored for ACLs: libacl is not available")));
377 warned = 1;
378 }
379#endif
380 }
381 else
382 val = acl_to_text (acl, NULL);
d36f5a3c
PR
383 acl_free (acl);
384
3c4e51fa 385 if (!val)
d36f5a3c
PR
386 {
387 call_arg_warn ("acl_to_text", file_name);
388 return;
389 }
390
391 *ret_ptr = xstrdup (val);
62c0c3a7 392 xattrs_acls_cleanup (*ret_ptr, ret_len);
d36f5a3c
PR
393 acl_free (val);
394}
395
54610255
SP
396static void
397xattrs__acls_get_a (int parentfd, const char *file_name,
54610255
SP
398 char **ret_ptr, size_t *ret_len)
399{
400 acls_get_text (parentfd, file_name, ACL_TYPE_ACCESS, ret_ptr, ret_len);
401}
402
3c4e51fa 403/* "system.posix_acl_default" */
4ac671c4
SP
404static void
405xattrs__acls_get_d (int parentfd, char const *file_name,
3c4e51fa 406 char **ret_ptr, size_t * ret_len)
cbc51277 407{
54610255 408 acls_get_text (parentfd, file_name, ACL_TYPE_DEFAULT, ret_ptr, ret_len);
d36f5a3c
PR
409}
410#endif /* HAVE_POSIX_ACLS */
411
4ac671c4
SP
412static void
413acls_one_line (const char *prefix, char delim,
3c4e51fa 414 const char *aclstring, size_t len)
d36f5a3c
PR
415{
416 /* support both long and short text representation of posix acls */
417 struct obstack stk;
d36f5a3c
PR
418 int pref_len = strlen (prefix);
419 const char *oldstring = aclstring;
3c4e51fa 420 int pos = 0;
d36f5a3c
PR
421
422 if (!aclstring || !len)
423 return;
424
3c4e51fa 425 obstack_init (&stk);
d36f5a3c
PR
426 while (pos <= len)
427 {
428 int move = strcspn (aclstring, ",\n");
429 if (!move)
3c4e51fa 430 break;
d36f5a3c
PR
431
432 if (oldstring != aclstring)
3c4e51fa 433 obstack_1grow (&stk, delim);
d36f5a3c
PR
434
435 obstack_grow (&stk, prefix, pref_len);
436 obstack_grow (&stk, aclstring, move);
437
f6e2860e 438 pos += move + 1;
d36f5a3c
PR
439 aclstring += move + 1;
440 }
441
442 obstack_1grow (&stk, '\0');
d36f5a3c 443
3c4e51fa 444 fprintf (stdlis, "%s", (char *) obstack_finish (&stk));
d36f5a3c
PR
445
446 obstack_free (&stk, NULL);
447}
448
4ac671c4 449void
fac2b4c1
SP
450xattrs_acls_get (MAYBE_UNUSED int parentfd, MAYBE_UNUSED char const *file_name,
451 MAYBE_UNUSED struct tar_stat_info *st,
452 MAYBE_UNUSED int xisfile)
d36f5a3c
PR
453{
454 if (acls_option > 0)
455 {
456#ifndef HAVE_POSIX_ACLS
457 static int done = 0;
458 if (!done)
3c4e51fa 459 WARN ((0, 0, _("POSIX ACL support is not available")));
d36f5a3c
PR
460 done = 1;
461#else
462 int err = file_has_acl_at (parentfd, file_name, &st->stat);
463 if (err == 0)
3c4e51fa 464 return;
d36f5a3c 465 if (err == -1)
3c4e51fa
SP
466 {
467 call_arg_warn ("file_has_acl_at", file_name);
468 return;
469 }
d36f5a3c 470
2ccd643d 471 xattrs__acls_get_a (parentfd, file_name,
3c4e51fa 472 &st->acls_a_ptr, &st->acls_a_len);
d36f5a3c 473 if (!xisfile)
2ccd643d 474 xattrs__acls_get_d (parentfd, file_name,
3c4e51fa 475 &st->acls_d_ptr, &st->acls_d_len);
d36f5a3c
PR
476#endif
477 }
478}
479
4ac671c4 480void
fac2b4c1
SP
481xattrs_acls_set (MAYBE_UNUSED struct tar_stat_info const *st,
482 MAYBE_UNUSED char const *file_name, char typeflag)
d36f5a3c 483{
3c4e51fa 484 if (acls_option > 0 && typeflag != SYMTYPE)
d36f5a3c
PR
485 {
486#ifndef HAVE_POSIX_ACLS
487 static int done = 0;
488 if (!done)
3c4e51fa 489 WARN ((0, 0, _("POSIX ACL support is not available")));
d36f5a3c
PR
490 done = 1;
491#else
492 xattrs__acls_set (st, file_name, ACL_TYPE_ACCESS,
2ccd643d 493 st->acls_a_ptr, false);
3c4e51fa
SP
494 if (typeflag == DIRTYPE || typeflag == GNUTYPE_DUMPDIR)
495 xattrs__acls_set (st, file_name, ACL_TYPE_DEFAULT,
2ccd643d 496 st->acls_d_ptr, true);
d36f5a3c
PR
497#endif
498 }
499}
500
4ac671c4
SP
501static void
502mask_map_realloc (struct xattrs_mask_map *map)
69633804 503{
3c4e51fa 504 if (map->used == map->size)
69633804 505 {
3c4e51fa
SP
506 if (map->size == 0)
507 map->size = 4;
508 map->masks = x2nrealloc (map->masks, &map->size, sizeof (map->masks[0]));
69633804
PR
509 }
510}
511
4ac671c4
SP
512void
513xattrs_mask_add (const char *mask, bool incl)
69633804 514{
3c4e51fa
SP
515 struct xattrs_mask_map *mask_map =
516 incl ? &xattrs_setup.incl : &xattrs_setup.excl;
69633804
PR
517 /* ensure there is enough space */
518 mask_map_realloc (mask_map);
519 /* just assign pointers -- we silently expect that pointer "mask" is valid
520 through the whole program (pointer to argv array) */
521 mask_map->masks[mask_map->used++] = mask;
522}
523
4ac671c4
SP
524static void
525clear_mask_map (struct xattrs_mask_map *mask_map)
69633804
PR
526{
527 if (mask_map->size)
528 free (mask_map->masks);
529}
530
4ac671c4 531void
cbc51277 532xattrs_clear_setup (void)
69633804
PR
533{
534 clear_mask_map (&xattrs_setup.incl);
535 clear_mask_map (&xattrs_setup.excl);
536}
537
bb6ddd8e
IM
538static bool xattrs_masked_out (const char *kw, bool archiving);
539
540/* get xattrs from file given by FILE_NAME or FD (when non-zero)
541 xattrs are checked against the user supplied include/exclude mask
542 if no mask is given this includes all the user.*, security.*, system.*,
543 etc. available domains */
4ac671c4
SP
544void
545xattrs_xattrs_get (int parentfd, char const *file_name,
3c4e51fa 546 struct tar_stat_info *st, int fd)
69633804
PR
547{
548 if (xattrs_option > 0)
549 {
550#ifndef HAVE_XATTRS
551 static int done = 0;
552 if (!done)
3c4e51fa 553 WARN ((0, 0, _("XATTR support is not available")));
69633804
PR
554 done = 1;
555#else
3c4e51fa 556 static size_t xsz = 1024;
69633804
PR
557 static char *xatrs = NULL;
558 ssize_t xret = -1;
559
4ac671c4 560 if (!xatrs)
3c4e51fa 561 xatrs = x2nrealloc (xatrs, &xsz, 1);
69633804
PR
562
563 while (((fd == 0) ?
3c4e51fa
SP
564 ((xret =
565 llistxattrat (parentfd, file_name, xatrs, xsz)) == -1) :
566 ((xret = flistxattr (fd, xatrs, xsz)) == -1))
567 && (errno == ERANGE))
568 {
569 xatrs = x2nrealloc (xatrs, &xsz, 1);
570 }
69633804
PR
571
572 if (xret == -1)
3c4e51fa 573 call_arg_warn ((fd == 0) ? "llistxattrat" : "flistxattr", file_name);
69633804 574 else
3c4e51fa
SP
575 {
576 const char *attr = xatrs;
577 static size_t asz = 1024;
578 static char *val = NULL;
579
580 if (!val)
581 val = x2nrealloc (val, &asz, 1);
582
583 while (xret > 0)
584 {
585 size_t len = strlen (attr);
586 ssize_t aret = 0;
587
3c4e51fa
SP
588 while (((fd == 0)
589 ? ((aret = lgetxattrat (parentfd, file_name, attr,
590 val, asz)) == -1)
591 : ((aret = fgetxattr (fd, attr, val, asz)) == -1))
592 && (errno == ERANGE))
593 {
594 val = x2nrealloc (val, &asz, 1);
595 }
596
597 if (aret != -1)
bb6ddd8e 598 {
c81a0853 599 if (!xattrs_masked_out (attr, true))
bb6ddd8e
IM
600 xheader_xattr_add (st, attr, val, aret);
601 }
3c4e51fa
SP
602 else if (errno != ENOATTR)
603 call_arg_warn ((fd == 0) ? "lgetxattrat"
604 : "fgetxattr", file_name);
605
606 attr += len + 1;
607 xret -= len + 1;
608 }
609 }
69633804
PR
610#endif
611 }
612}
613
f678e47e 614#ifdef HAVE_XATTRS
4ac671c4 615static void
2ccd643d 616xattrs__fd_set (char const *file_name, char typeflag,
3c4e51fa 617 const char *attr, const char *ptr, size_t len)
69633804
PR
618{
619 if (ptr)
620 {
621 const char *sysname = "setxattrat";
622 int ret = -1;
623
624 if (typeflag != SYMTYPE)
3c4e51fa 625 ret = setxattrat (chdir_fd, file_name, attr, ptr, len, 0);
69633804 626 else
3c4e51fa
SP
627 {
628 sysname = "lsetxattr";
629 ret = lsetxattrat (chdir_fd, file_name, attr, ptr, len, 0);
630 }
69633804
PR
631
632 if (ret == -1)
3c4e51fa 633 WARNOPT (WARN_XATTR_WRITE,
4ac671c4
SP
634 (0, errno,
635 _("%s: Cannot set '%s' extended attribute for file '%s'"),
636 sysname, attr, file_name));
69633804
PR
637 }
638}
f678e47e 639#endif
69633804 640
085cace1
PR
641/* lgetfileconat is called against FILE_NAME iff the FD parameter is set to
642 zero, otherwise the fgetfileconat is used against correct file descriptor */
4ac671c4 643void
fac2b4c1
SP
644xattrs_selinux_get (MAYBE_UNUSED int parentfd, MAYBE_UNUSED char const *file_name,
645 MAYBE_UNUSED struct tar_stat_info *st, MAYBE_UNUSED int fd)
085cace1
PR
646{
647 if (selinux_context_option > 0)
648 {
649#if HAVE_SELINUX_SELINUX_H != 1
650 static int done = 0;
651 if (!done)
3c4e51fa 652 WARN ((0, 0, _("SELinux support is not available")));
085cace1
PR
653 done = 1;
654#else
3c4e51fa
SP
655 int result = fd ?
656 fgetfilecon (fd, &st->cntx_name)
657 : lgetfileconat (parentfd, file_name, &st->cntx_name);
085cace1
PR
658
659 if (result == -1 && errno != ENODATA && errno != ENOTSUP)
3c4e51fa 660 call_arg_warn (fd ? "fgetfilecon" : "lgetfileconat", file_name);
085cace1
PR
661#endif
662 }
663}
664
4ac671c4 665void
fac2b4c1
SP
666xattrs_selinux_set (MAYBE_UNUSED struct tar_stat_info const *st,
667 MAYBE_UNUSED char const *file_name, MAYBE_UNUSED char typeflag)
085cace1
PR
668{
669 if (selinux_context_option > 0)
670 {
671#if HAVE_SELINUX_SELINUX_H != 1
672 static int done = 0;
673 if (!done)
3c4e51fa 674 WARN ((0, 0, _("SELinux support is not available")));
085cace1
PR
675 done = 1;
676#else
677 const char *sysname = "setfilecon";
678 int ret;
679
680 if (!st->cntx_name)
3c4e51fa 681 return;
085cace1
PR
682
683 if (typeflag != SYMTYPE)
3c4e51fa
SP
684 {
685 ret = setfileconat (chdir_fd, file_name, st->cntx_name);
686 sysname = "setfileconat";
687 }
085cace1 688 else
3c4e51fa
SP
689 {
690 ret = lsetfileconat (chdir_fd, file_name, st->cntx_name);
691 sysname = "lsetfileconat";
692 }
085cace1
PR
693
694 if (ret == -1)
3c4e51fa 695 WARNOPT (WARN_XATTR_WRITE,
4ac671c4
SP
696 (0, errno,
697 _("%s: Cannot set SELinux context for file '%s'"),
698 sysname, file_name));
085cace1
PR
699#endif
700 }
701}
702
4ac671c4
SP
703static bool
704xattrs_matches_mask (const char *kw, struct xattrs_mask_map *mm)
69633804
PR
705{
706 int i;
707
708 if (!mm->size)
709 return false;
710
711 for (i = 0; i < mm->used; i++)
712 if (fnmatch (mm->masks[i], kw, 0) == 0)
713 return true;
714
715 return false;
716}
717
3c4e51fa
SP
718#define USER_DOT_PFX "user."
719
4ac671c4
SP
720static bool
721xattrs_kw_included (const char *kw, bool archiving)
69633804 722{
4ac671c4
SP
723 if (xattrs_setup.incl.size)
724 return xattrs_matches_mask (kw, &xattrs_setup.incl);
3c4e51fa
SP
725 else if (archiving)
726 return true;
4ac671c4 727 else
3c4e51fa 728 return strncmp (kw, USER_DOT_PFX, sizeof (USER_DOT_PFX) - 1) == 0;
69633804
PR
729}
730
4ac671c4 731static bool
2ccd643d 732xattrs_kw_excluded (const char *kw)
69633804 733{
3c4e51fa
SP
734 return xattrs_setup.excl.size ?
735 xattrs_matches_mask (kw, &xattrs_setup.excl) : false;
69633804
PR
736}
737
738/* Check whether the xattr with keyword KW should be discarded from list of
739 attributes that are going to be archived/excluded (set ARCHIVING=true for
740 archiving, false for excluding) */
4ac671c4
SP
741static bool
742xattrs_masked_out (const char *kw, bool archiving)
69633804 743{
2ccd643d 744 return xattrs_kw_included (kw, archiving) ? xattrs_kw_excluded (kw) : true;
69633804
PR
745}
746
4ac671c4
SP
747void
748xattrs_xattrs_set (struct tar_stat_info const *st,
3c4e51fa 749 char const *file_name, char typeflag, int later_run)
69633804
PR
750{
751 if (xattrs_option > 0)
752 {
753#ifndef HAVE_XATTRS
754 static int done = 0;
755 if (!done)
3c4e51fa 756 WARN ((0, 0, _("XATTR support is not available")));
69633804
PR
757 done = 1;
758#else
66262c10 759 size_t i;
69633804 760
66262c10 761 if (!st->xattr_map.xm_size)
3c4e51fa 762 return;
69633804 763
66262c10 764 for (i = 0; i < st->xattr_map.xm_size; i++)
3c4e51fa 765 {
66262c10 766 char *keyword = st->xattr_map.xm_map[i].xkey + XATTRS_PREFIX_LEN;
3c4e51fa
SP
767
768 /* TODO: this 'later_run' workaround is temporary solution -> once
769 capabilities should become fully supported by it's API and there
770 should exist something like xattrs_capabilities_set() call.
771 For a regular files: all extended attributes are restored during
772 the first run except 'security.capability' which is restored in
773 'later_run == 1'. */
774 if (typeflag == REGTYPE
775 && later_run == !!strcmp (keyword, "security.capability"))
776 continue;
777
778 if (xattrs_masked_out (keyword, false /* extracting */ ))
779 /* we don't want to restore this keyword */
780 continue;
781
2ccd643d 782 xattrs__fd_set (file_name, typeflag, keyword,
66262c10
SP
783 st->xattr_map.xm_map[i].xval_ptr,
784 st->xattr_map.xm_map[i].xval_len);
3c4e51fa 785 }
69633804
PR
786#endif
787 }
788}
789
4ac671c4
SP
790void
791xattrs_print_char (struct tar_stat_info const *st, char *output)
69633804
PR
792{
793 int i;
3c4e51fa 794
69633804
PR
795 if (verbose_option < 2)
796 {
797 *output = 0;
798 return;
799 }
800
4ac671c4 801 if (xattrs_option > 0 || selinux_context_option > 0 || acls_option > 0)
69633804
PR
802 {
803 /* placeholders */
804 *output = ' ';
3c4e51fa 805 output[1] = 0;
69633804
PR
806 }
807
66262c10
SP
808 if (xattrs_option > 0 && st->xattr_map.xm_size)
809 for (i = 0; i < st->xattr_map.xm_size; ++i)
69633804 810 {
66262c10 811 char *keyword = st->xattr_map.xm_map[i].xkey + XATTRS_PREFIX_LEN;
3c4e51fa
SP
812 if (!xattrs_masked_out (keyword, false /* like extracting */ ))
813 {
814 *output = '*';
815 break;
816 }
69633804 817 }
d36f5a3c 818
085cace1
PR
819 if (selinux_context_option > 0 && st->cntx_name)
820 *output = '.';
821
8e10d93d 822 if (acls_option > 0 && (st->acls_a_len || st->acls_d_len))
d36f5a3c 823 *output = '+';
69633804
PR
824}
825
4ac671c4
SP
826void
827xattrs_print (struct tar_stat_info const *st)
69633804
PR
828{
829 if (verbose_option < 3)
830 return;
831
085cace1 832 /* selinux */
8e10d93d 833 if (selinux_context_option > 0 && st->cntx_name)
085cace1
PR
834 fprintf (stdlis, " s: %s\n", st->cntx_name);
835
d36f5a3c 836 /* acls */
8e10d93d 837 if (acls_option > 0 && (st->acls_a_len || st->acls_d_len))
d36f5a3c
PR
838 {
839 fprintf (stdlis, " a: ");
840 acls_one_line ("", ',', st->acls_a_ptr, st->acls_a_len);
f6e2860e
SP
841 if (st->acls_a_len && st->acls_d_len)
842 fprintf (stdlis, ",");
d36f5a3c
PR
843 acls_one_line ("default:", ',', st->acls_d_ptr, st->acls_d_len);
844 fprintf (stdlis, "\n");
845 }
846
69633804 847 /* xattrs */
66262c10 848 if (xattrs_option > 0 && st->xattr_map.xm_size)
69633804
PR
849 {
850 int i;
cbc51277 851
66262c10 852 for (i = 0; i < st->xattr_map.xm_size; ++i)
3c4e51fa 853 {
66262c10 854 char *keyword = st->xattr_map.xm_map[i].xkey + XATTRS_PREFIX_LEN;
3c4e51fa
SP
855 if (!xattrs_masked_out (keyword, false /* like extracting */ ))
856 fprintf (stdlis, " x: %lu %s\n",
66262c10 857 (unsigned long) st->xattr_map.xm_map[i].xval_len, keyword);
3c4e51fa 858 }
69633804
PR
859 }
860}