]> git.ipfire.org Git - thirdparty/tar.git/blame - src/xattrs.c
* po/.gitignore: Omit redundant *~ entries.
[thirdparty/tar.git] / src / xattrs.c
CommitLineData
69633804
PR
1/* Support for extended attributes.
2
719d3b44 3 Copyright (C) 2006-2023 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;
72
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
SP
287 char const *file_name, int type,
288 char *ptr, size_t len, bool def)
cbc51277 289{
d36f5a3c
PR
290 acl_t acl;
291
292 if (ptr)
293 {
294 /* assert (strlen (ptr) == len); */
295 ptr = fixup_extra_acl_fields (ptr);
d36f5a3c 296 acl = acl_from_text (ptr);
d36f5a3c 297 }
7fe7adcb
PR
298 else if (def)
299 {
300 /* No "default" IEEE 1003.1e ACL set for directory. At this moment,
301 FILE_NAME may already have inherited default acls from parent
302 directory; clean them up. */
303 if (acl_delete_def_file_at (chdir_fd, file_name))
304 WARNOPT (WARN_XATTR_WRITE,
305 (0, errno,
306 _("acl_delete_def_file_at: Cannot drop default POSIX ACLs "
307 "for file '%s'"),
308 file_name));
309 return;
310 }
d36f5a3c 311 else
7fe7adcb 312 acl = perms2acl (st->stat.st_mode);
d36f5a3c 313
3c4e51fa 314 if (!acl)
d36f5a3c
PR
315 {
316 call_arg_warn ("acl_from_text", file_name);
317 return;
318 }
319
320 if (acl_set_file_at (chdir_fd, file_name, type, acl) == -1)
321 /* warn even if filesystem does not support acls */
4ac671c4
SP
322 WARNOPT (WARN_XATTR_WRITE,
323 (0, errno,
3c4e51fa 324 _ ("acl_set_file_at: Cannot set POSIX ACLs for file '%s'"),
4ac671c4 325 file_name));
d36f5a3c
PR
326
327 acl_free (acl);
328}
329
62c0c3a7
SP
330/* Cleanup textual representation of the ACL in VAL by eliminating tab
331 characters and comments */
332static void
333xattrs_acls_cleanup (char *val, size_t *plen)
334{
335 char *p, *q;
336
337 p = q = val + strcspn (val, "#\t");
338 while (*q)
339 {
340 if (*q == '\t')
341 q++;
342 else if (*q == '#')
343 {
344 while (*q != '\n')
345 q++;
346 }
347 else
348 *p++ = *q++;
349 }
350 *plen = p - val;
351 *p++ = 0;
352}
353
4ac671c4 354static void
54610255
SP
355acls_get_text (int parentfd, const char *file_name, acl_type_t type,
356 char **ret_ptr, size_t * ret_len)
cbc51277 357{
d36f5a3c 358 char *val = NULL;
d36f5a3c
PR
359 acl_t acl;
360
54610255 361 if (!(acl = acl_get_file_at (parentfd, file_name, type)))
d36f5a3c
PR
362 {
363 if (errno != ENOTSUP)
3c4e51fa 364 call_arg_warn ("acl_get_file_at", file_name);
d36f5a3c
PR
365 return;
366 }
367
54610255
SP
368 if (numeric_owner_option)
369 {
370#ifdef HAVE_ACL_LIBACL_H
371 val = acl_to_any_text (acl, NULL, '\n',
372 TEXT_SOME_EFFECTIVE | TEXT_NUMERIC_IDS);
373#else
374 static int warned;
375 if (!warned)
376 {
377 WARN ((0, 0, _("--numeric-owner is ignored for ACLs: libacl is not available")));
378 warned = 1;
379 }
380#endif
381 }
382 else
383 val = acl_to_text (acl, NULL);
d36f5a3c
PR
384 acl_free (acl);
385
3c4e51fa 386 if (!val)
d36f5a3c
PR
387 {
388 call_arg_warn ("acl_to_text", file_name);
389 return;
390 }
391
392 *ret_ptr = xstrdup (val);
62c0c3a7 393 xattrs_acls_cleanup (*ret_ptr, ret_len);
d36f5a3c
PR
394 acl_free (val);
395}
396
54610255
SP
397static void
398xattrs__acls_get_a (int parentfd, const char *file_name,
399 struct tar_stat_info *st,
400 char **ret_ptr, size_t *ret_len)
401{
402 acls_get_text (parentfd, file_name, ACL_TYPE_ACCESS, ret_ptr, ret_len);
403}
404
3c4e51fa 405/* "system.posix_acl_default" */
4ac671c4
SP
406static void
407xattrs__acls_get_d (int parentfd, char const *file_name,
3c4e51fa
SP
408 struct tar_stat_info *st,
409 char **ret_ptr, size_t * ret_len)
cbc51277 410{
54610255 411 acls_get_text (parentfd, file_name, ACL_TYPE_DEFAULT, ret_ptr, ret_len);
d36f5a3c
PR
412}
413#endif /* HAVE_POSIX_ACLS */
414
4ac671c4
SP
415static void
416acls_one_line (const char *prefix, char delim,
3c4e51fa 417 const char *aclstring, size_t len)
d36f5a3c
PR
418{
419 /* support both long and short text representation of posix acls */
420 struct obstack stk;
d36f5a3c
PR
421 int pref_len = strlen (prefix);
422 const char *oldstring = aclstring;
3c4e51fa 423 int pos = 0;
d36f5a3c
PR
424
425 if (!aclstring || !len)
426 return;
427
3c4e51fa 428 obstack_init (&stk);
d36f5a3c
PR
429 while (pos <= len)
430 {
431 int move = strcspn (aclstring, ",\n");
432 if (!move)
3c4e51fa 433 break;
d36f5a3c
PR
434
435 if (oldstring != aclstring)
3c4e51fa 436 obstack_1grow (&stk, delim);
d36f5a3c
PR
437
438 obstack_grow (&stk, prefix, pref_len);
439 obstack_grow (&stk, aclstring, move);
440
f6e2860e 441 pos += move + 1;
d36f5a3c
PR
442 aclstring += move + 1;
443 }
444
445 obstack_1grow (&stk, '\0');
d36f5a3c 446
3c4e51fa 447 fprintf (stdlis, "%s", (char *) obstack_finish (&stk));
d36f5a3c
PR
448
449 obstack_free (&stk, NULL);
450}
451
4ac671c4
SP
452void
453xattrs_acls_get (int parentfd, char const *file_name,
3c4e51fa 454 struct tar_stat_info *st, int fd, int xisfile)
d36f5a3c
PR
455{
456 if (acls_option > 0)
457 {
458#ifndef HAVE_POSIX_ACLS
459 static int done = 0;
460 if (!done)
3c4e51fa 461 WARN ((0, 0, _("POSIX ACL support is not available")));
d36f5a3c
PR
462 done = 1;
463#else
464 int err = file_has_acl_at (parentfd, file_name, &st->stat);
465 if (err == 0)
3c4e51fa 466 return;
d36f5a3c 467 if (err == -1)
3c4e51fa
SP
468 {
469 call_arg_warn ("file_has_acl_at", file_name);
470 return;
471 }
d36f5a3c
PR
472
473 xattrs__acls_get_a (parentfd, file_name, st,
3c4e51fa 474 &st->acls_a_ptr, &st->acls_a_len);
d36f5a3c 475 if (!xisfile)
3c4e51fa
SP
476 xattrs__acls_get_d (parentfd, file_name, st,
477 &st->acls_d_ptr, &st->acls_d_len);
d36f5a3c
PR
478#endif
479 }
480}
481
4ac671c4
SP
482void
483xattrs_acls_set (struct tar_stat_info const *st,
3c4e51fa 484 char const *file_name, char typeflag)
d36f5a3c 485{
3c4e51fa 486 if (acls_option > 0 && typeflag != SYMTYPE)
d36f5a3c
PR
487 {
488#ifndef HAVE_POSIX_ACLS
489 static int done = 0;
490 if (!done)
3c4e51fa 491 WARN ((0, 0, _("POSIX ACL support is not available")));
d36f5a3c
PR
492 done = 1;
493#else
494 xattrs__acls_set (st, file_name, ACL_TYPE_ACCESS,
3c4e51fa
SP
495 st->acls_a_ptr, st->acls_a_len, false);
496 if (typeflag == DIRTYPE || typeflag == GNUTYPE_DUMPDIR)
497 xattrs__acls_set (st, file_name, ACL_TYPE_DEFAULT,
498 st->acls_d_ptr, st->acls_d_len, true);
d36f5a3c
PR
499#endif
500 }
501}
502
4ac671c4
SP
503static void
504mask_map_realloc (struct xattrs_mask_map *map)
69633804 505{
3c4e51fa 506 if (map->used == map->size)
69633804 507 {
3c4e51fa
SP
508 if (map->size == 0)
509 map->size = 4;
510 map->masks = x2nrealloc (map->masks, &map->size, sizeof (map->masks[0]));
69633804
PR
511 }
512}
513
4ac671c4
SP
514void
515xattrs_mask_add (const char *mask, bool incl)
69633804 516{
3c4e51fa
SP
517 struct xattrs_mask_map *mask_map =
518 incl ? &xattrs_setup.incl : &xattrs_setup.excl;
69633804
PR
519 /* ensure there is enough space */
520 mask_map_realloc (mask_map);
521 /* just assign pointers -- we silently expect that pointer "mask" is valid
522 through the whole program (pointer to argv array) */
523 mask_map->masks[mask_map->used++] = mask;
524}
525
4ac671c4
SP
526static void
527clear_mask_map (struct xattrs_mask_map *mask_map)
69633804
PR
528{
529 if (mask_map->size)
530 free (mask_map->masks);
531}
532
4ac671c4 533void
cbc51277 534xattrs_clear_setup (void)
69633804
PR
535{
536 clear_mask_map (&xattrs_setup.incl);
537 clear_mask_map (&xattrs_setup.excl);
538}
539
bb6ddd8e
IM
540static bool xattrs_masked_out (const char *kw, bool archiving);
541
542/* get xattrs from file given by FILE_NAME or FD (when non-zero)
543 xattrs are checked against the user supplied include/exclude mask
544 if no mask is given this includes all the user.*, security.*, system.*,
545 etc. available domains */
4ac671c4
SP
546void
547xattrs_xattrs_get (int parentfd, char const *file_name,
3c4e51fa 548 struct tar_stat_info *st, int fd)
69633804
PR
549{
550 if (xattrs_option > 0)
551 {
552#ifndef HAVE_XATTRS
553 static int done = 0;
554 if (!done)
3c4e51fa 555 WARN ((0, 0, _("XATTR support is not available")));
69633804
PR
556 done = 1;
557#else
3c4e51fa 558 static size_t xsz = 1024;
69633804
PR
559 static char *xatrs = NULL;
560 ssize_t xret = -1;
561
4ac671c4 562 if (!xatrs)
3c4e51fa 563 xatrs = x2nrealloc (xatrs, &xsz, 1);
69633804
PR
564
565 while (((fd == 0) ?
3c4e51fa
SP
566 ((xret =
567 llistxattrat (parentfd, file_name, xatrs, xsz)) == -1) :
568 ((xret = flistxattr (fd, xatrs, xsz)) == -1))
569 && (errno == ERANGE))
570 {
571 xatrs = x2nrealloc (xatrs, &xsz, 1);
572 }
69633804
PR
573
574 if (xret == -1)
3c4e51fa 575 call_arg_warn ((fd == 0) ? "llistxattrat" : "flistxattr", file_name);
69633804 576 else
3c4e51fa
SP
577 {
578 const char *attr = xatrs;
579 static size_t asz = 1024;
580 static char *val = NULL;
581
582 if (!val)
583 val = x2nrealloc (val, &asz, 1);
584
585 while (xret > 0)
586 {
587 size_t len = strlen (attr);
588 ssize_t aret = 0;
589
3c4e51fa
SP
590 while (((fd == 0)
591 ? ((aret = lgetxattrat (parentfd, file_name, attr,
592 val, asz)) == -1)
593 : ((aret = fgetxattr (fd, attr, val, asz)) == -1))
594 && (errno == ERANGE))
595 {
596 val = x2nrealloc (val, &asz, 1);
597 }
598
599 if (aret != -1)
bb6ddd8e 600 {
c81a0853 601 if (!xattrs_masked_out (attr, true))
bb6ddd8e
IM
602 xheader_xattr_add (st, attr, val, aret);
603 }
3c4e51fa
SP
604 else if (errno != ENOATTR)
605 call_arg_warn ((fd == 0) ? "lgetxattrat"
606 : "fgetxattr", file_name);
607
608 attr += len + 1;
609 xret -= len + 1;
610 }
611 }
69633804
PR
612#endif
613 }
614}
615
f678e47e 616#ifdef HAVE_XATTRS
4ac671c4
SP
617static void
618xattrs__fd_set (struct tar_stat_info const *st,
3c4e51fa
SP
619 char const *file_name, char typeflag,
620 const char *attr, const char *ptr, size_t len)
69633804
PR
621{
622 if (ptr)
623 {
624 const char *sysname = "setxattrat";
625 int ret = -1;
626
627 if (typeflag != SYMTYPE)
3c4e51fa 628 ret = setxattrat (chdir_fd, file_name, attr, ptr, len, 0);
69633804 629 else
3c4e51fa
SP
630 {
631 sysname = "lsetxattr";
632 ret = lsetxattrat (chdir_fd, file_name, attr, ptr, len, 0);
633 }
69633804
PR
634
635 if (ret == -1)
3c4e51fa 636 WARNOPT (WARN_XATTR_WRITE,
4ac671c4
SP
637 (0, errno,
638 _("%s: Cannot set '%s' extended attribute for file '%s'"),
639 sysname, attr, file_name));
69633804
PR
640 }
641}
f678e47e 642#endif
69633804 643
085cace1
PR
644/* lgetfileconat is called against FILE_NAME iff the FD parameter is set to
645 zero, otherwise the fgetfileconat is used against correct file descriptor */
4ac671c4
SP
646void
647xattrs_selinux_get (int parentfd, char const *file_name,
3c4e51fa 648 struct tar_stat_info *st, int fd)
085cace1
PR
649{
650 if (selinux_context_option > 0)
651 {
652#if HAVE_SELINUX_SELINUX_H != 1
653 static int done = 0;
654 if (!done)
3c4e51fa 655 WARN ((0, 0, _("SELinux support is not available")));
085cace1
PR
656 done = 1;
657#else
3c4e51fa
SP
658 int result = fd ?
659 fgetfilecon (fd, &st->cntx_name)
660 : lgetfileconat (parentfd, file_name, &st->cntx_name);
085cace1
PR
661
662 if (result == -1 && errno != ENODATA && errno != ENOTSUP)
3c4e51fa 663 call_arg_warn (fd ? "fgetfilecon" : "lgetfileconat", file_name);
085cace1
PR
664#endif
665 }
666}
667
4ac671c4
SP
668void
669xattrs_selinux_set (struct tar_stat_info const *st,
3c4e51fa 670 char const *file_name, char typeflag)
085cace1
PR
671{
672 if (selinux_context_option > 0)
673 {
674#if HAVE_SELINUX_SELINUX_H != 1
675 static int done = 0;
676 if (!done)
3c4e51fa 677 WARN ((0, 0, _("SELinux support is not available")));
085cace1
PR
678 done = 1;
679#else
680 const char *sysname = "setfilecon";
681 int ret;
682
683 if (!st->cntx_name)
3c4e51fa 684 return;
085cace1
PR
685
686 if (typeflag != SYMTYPE)
3c4e51fa
SP
687 {
688 ret = setfileconat (chdir_fd, file_name, st->cntx_name);
689 sysname = "setfileconat";
690 }
085cace1 691 else
3c4e51fa
SP
692 {
693 ret = lsetfileconat (chdir_fd, file_name, st->cntx_name);
694 sysname = "lsetfileconat";
695 }
085cace1
PR
696
697 if (ret == -1)
3c4e51fa 698 WARNOPT (WARN_XATTR_WRITE,
4ac671c4
SP
699 (0, errno,
700 _("%s: Cannot set SELinux context for file '%s'"),
701 sysname, file_name));
085cace1
PR
702#endif
703 }
704}
705
4ac671c4
SP
706static bool
707xattrs_matches_mask (const char *kw, struct xattrs_mask_map *mm)
69633804
PR
708{
709 int i;
710
711 if (!mm->size)
712 return false;
713
714 for (i = 0; i < mm->used; i++)
715 if (fnmatch (mm->masks[i], kw, 0) == 0)
716 return true;
717
718 return false;
719}
720
3c4e51fa
SP
721#define USER_DOT_PFX "user."
722
4ac671c4
SP
723static bool
724xattrs_kw_included (const char *kw, bool archiving)
69633804 725{
4ac671c4
SP
726 if (xattrs_setup.incl.size)
727 return xattrs_matches_mask (kw, &xattrs_setup.incl);
3c4e51fa
SP
728 else if (archiving)
729 return true;
4ac671c4 730 else
3c4e51fa 731 return strncmp (kw, USER_DOT_PFX, sizeof (USER_DOT_PFX) - 1) == 0;
69633804
PR
732}
733
4ac671c4
SP
734static bool
735xattrs_kw_excluded (const char *kw, bool archiving)
69633804 736{
3c4e51fa
SP
737 return xattrs_setup.excl.size ?
738 xattrs_matches_mask (kw, &xattrs_setup.excl) : false;
69633804
PR
739}
740
741/* Check whether the xattr with keyword KW should be discarded from list of
742 attributes that are going to be archived/excluded (set ARCHIVING=true for
743 archiving, false for excluding) */
4ac671c4
SP
744static bool
745xattrs_masked_out (const char *kw, bool archiving)
69633804 746{
3c4e51fa 747 return xattrs_kw_included (kw, archiving) ?
cbc51277 748 xattrs_kw_excluded (kw, archiving) : true;
69633804
PR
749}
750
4ac671c4
SP
751void
752xattrs_xattrs_set (struct tar_stat_info const *st,
3c4e51fa 753 char const *file_name, char typeflag, int later_run)
69633804
PR
754{
755 if (xattrs_option > 0)
756 {
757#ifndef HAVE_XATTRS
758 static int done = 0;
759 if (!done)
3c4e51fa 760 WARN ((0, 0, _("XATTR support is not available")));
69633804
PR
761 done = 1;
762#else
66262c10 763 size_t i;
69633804 764
66262c10 765 if (!st->xattr_map.xm_size)
3c4e51fa 766 return;
69633804 767
66262c10 768 for (i = 0; i < st->xattr_map.xm_size; i++)
3c4e51fa 769 {
66262c10 770 char *keyword = st->xattr_map.xm_map[i].xkey + XATTRS_PREFIX_LEN;
3c4e51fa
SP
771
772 /* TODO: this 'later_run' workaround is temporary solution -> once
773 capabilities should become fully supported by it's API and there
774 should exist something like xattrs_capabilities_set() call.
775 For a regular files: all extended attributes are restored during
776 the first run except 'security.capability' which is restored in
777 'later_run == 1'. */
778 if (typeflag == REGTYPE
779 && later_run == !!strcmp (keyword, "security.capability"))
780 continue;
781
782 if (xattrs_masked_out (keyword, false /* extracting */ ))
783 /* we don't want to restore this keyword */
784 continue;
785
786 xattrs__fd_set (st, file_name, typeflag, keyword,
66262c10
SP
787 st->xattr_map.xm_map[i].xval_ptr,
788 st->xattr_map.xm_map[i].xval_len);
3c4e51fa 789 }
69633804
PR
790#endif
791 }
792}
793
4ac671c4
SP
794void
795xattrs_print_char (struct tar_stat_info const *st, char *output)
69633804
PR
796{
797 int i;
3c4e51fa 798
69633804
PR
799 if (verbose_option < 2)
800 {
801 *output = 0;
802 return;
803 }
804
4ac671c4 805 if (xattrs_option > 0 || selinux_context_option > 0 || acls_option > 0)
69633804
PR
806 {
807 /* placeholders */
808 *output = ' ';
3c4e51fa 809 output[1] = 0;
69633804
PR
810 }
811
66262c10
SP
812 if (xattrs_option > 0 && st->xattr_map.xm_size)
813 for (i = 0; i < st->xattr_map.xm_size; ++i)
69633804 814 {
66262c10 815 char *keyword = st->xattr_map.xm_map[i].xkey + XATTRS_PREFIX_LEN;
3c4e51fa
SP
816 if (!xattrs_masked_out (keyword, false /* like extracting */ ))
817 {
818 *output = '*';
819 break;
820 }
69633804 821 }
d36f5a3c 822
085cace1
PR
823 if (selinux_context_option > 0 && st->cntx_name)
824 *output = '.';
825
8e10d93d 826 if (acls_option > 0 && (st->acls_a_len || st->acls_d_len))
d36f5a3c 827 *output = '+';
69633804
PR
828}
829
4ac671c4
SP
830void
831xattrs_print (struct tar_stat_info const *st)
69633804
PR
832{
833 if (verbose_option < 3)
834 return;
835
085cace1 836 /* selinux */
8e10d93d 837 if (selinux_context_option > 0 && st->cntx_name)
085cace1
PR
838 fprintf (stdlis, " s: %s\n", st->cntx_name);
839
d36f5a3c 840 /* acls */
8e10d93d 841 if (acls_option > 0 && (st->acls_a_len || st->acls_d_len))
d36f5a3c
PR
842 {
843 fprintf (stdlis, " a: ");
844 acls_one_line ("", ',', st->acls_a_ptr, st->acls_a_len);
f6e2860e
SP
845 if (st->acls_a_len && st->acls_d_len)
846 fprintf (stdlis, ",");
d36f5a3c
PR
847 acls_one_line ("default:", ',', st->acls_d_ptr, st->acls_d_len);
848 fprintf (stdlis, "\n");
849 }
850
69633804 851 /* xattrs */
66262c10 852 if (xattrs_option > 0 && st->xattr_map.xm_size)
69633804
PR
853 {
854 int i;
cbc51277 855
66262c10 856 for (i = 0; i < st->xattr_map.xm_size; ++i)
3c4e51fa 857 {
66262c10 858 char *keyword = st->xattr_map.xm_map[i].xkey + XATTRS_PREFIX_LEN;
3c4e51fa
SP
859 if (!xattrs_masked_out (keyword, false /* like extracting */ ))
860 fprintf (stdlis, " x: %lu %s\n",
66262c10 861 (unsigned long) st->xattr_map.xm_map[i].xval_len, keyword);
3c4e51fa 862 }
69633804
PR
863 }
864}