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, ¤t_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 |
¤t_mode, ¤t_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 (¤t_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 |
}; |