blob: a94ba445d4590a4b36058e48eed09265f6ad0a47 [file] [log] [blame]
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001/*
2** Copyright 1998-2003 University of Illinois Board of Trustees
3** Copyright 1998-2003 Mark D. Roth
4** All rights reserved.
5**
6** block.c - libtar code to handle tar archive header blocks
7**
8** Mark D. Roth <roth@uiuc.edu>
9** Campus Information Technologies and Educational Services
10** University of Illinois at Urbana-Champaign
11*/
12
13#include <internal.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050014#include <errno.h>
15
16#ifdef STDC_HEADERS
17# include <string.h>
18# include <stdlib.h>
19#endif
20
21#define BIT_ISSET(bitmask, bit) ((bitmask) & (bit))
22
Vojtech Bocek25fd68d2013-08-27 03:10:10 +020023// Used to identify selinux_context in extended ('x')
24// metadata. From RedHat implementation.
25#define SELINUX_TAG "RHT.security.selinux="
Ethan Yonker8d039f72017-02-03 14:26:15 -060026#define SELINUX_TAG_LEN strlen(SELINUX_TAG)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050027
Ethan Yonker79f88bd2016-12-09 14:52:12 -060028// Used to identify e4crypt_policy in extended ('x')
29#define E4CRYPT_TAG "TWRP.security.e4crypt="
Ethan Yonker8d039f72017-02-03 14:26:15 -060030#define E4CRYPT_TAG_LEN strlen(E4CRYPT_TAG)
Ethan Yonker79f88bd2016-12-09 14:52:12 -060031
Ethan Yonker71187742017-01-13 13:30:10 -060032// Used to identify Posix capabilities in extended ('x')
33#define CAPABILITIES_TAG "SCHILY.xattr.security.capability="
Ethan Yonker8d039f72017-02-03 14:26:15 -060034#define CAPABILITIES_TAG_LEN strlen(CAPABILITIES_TAG)
35
36// Used to identify Android user.default xattr in extended ('x')
37#define ANDROID_USER_DEFAULT_TAG "ANDROID.user.default"
38#define ANDROID_USER_DEFAULT_TAG_LEN strlen(ANDROID_USER_DEFAULT_TAG)
39
40// Used to identify Android user.inode_cache xattr in extended ('x')
41#define ANDROID_USER_CACHE_TAG "ANDROID.user.inode_cache"
42#define ANDROID_USER_CACHE_TAG_LEN strlen(ANDROID_USER_CACHE_TAG)
43
44// Used to identify Android user.inode_code_cache xattr in extended ('x')
45#define ANDROID_USER_CODE_CACHE_TAG "ANDROID.user.inode_code_cache"
46#define ANDROID_USER_CODE_CACHE_TAG_LEN strlen(ANDROID_USER_CODE_CACHE_TAG)
Ethan Yonker71187742017-01-13 13:30:10 -060047
bigbiff bigbiff9c754052013-01-09 09:09:08 -050048/* read a header block */
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050049/* FIXME: the return value of this function should match the return value
50 of tar_block_read(), which is a macro which references a prototype
51 that returns a ssize_t. So far, this is safe, since tar_block_read()
52 only ever reads 512 (T_BLOCKSIZE) bytes at a time, so any difference
53 in size of ssize_t and int is of negligible risk. BUT, if
54 T_BLOCKSIZE ever changes, or ever becomes a variable parameter
55 controllable by the user, all the code that calls it,
56 including this function and all code that calls it, should be
57 fixed for security reasons.
58 Thanks to Chris Palmer for the critique.
59*/
bigbiff bigbiff9c754052013-01-09 09:09:08 -050060int
61th_read_internal(TAR *t)
62{
63 int i;
64 int num_zero_blocks = 0;
65
66#ifdef DEBUG
67 printf("==> th_read_internal(TAR=\"%s\")\n", t->pathname);
68#endif
69
70 while ((i = tar_block_read(t, &(t->th_buf))) == T_BLOCKSIZE)
71 {
72 /* two all-zero blocks mark EOF */
73 if (t->th_buf.name[0] == '\0')
74 {
75 num_zero_blocks++;
76 if (!BIT_ISSET(t->options, TAR_IGNORE_EOT)
77 && num_zero_blocks >= 2)
78 return 0; /* EOF */
79 else
80 continue;
81 }
82
83 /* verify magic and version */
84 if (BIT_ISSET(t->options, TAR_CHECK_MAGIC)
85 && strncmp(t->th_buf.magic, TMAGIC, TMAGLEN - 1) != 0)
86 {
87#ifdef DEBUG
88 puts("!!! unknown magic value in tar header");
89#endif
90 return -2;
91 }
92
93 if (BIT_ISSET(t->options, TAR_CHECK_VERSION)
94 && strncmp(t->th_buf.version, TVERSION, TVERSLEN) != 0)
95 {
96#ifdef DEBUG
97 puts("!!! unknown version value in tar header");
98#endif
99 return -2;
100 }
101
102 /* check chksum */
103 if (!BIT_ISSET(t->options, TAR_IGNORE_CRC)
104 && !th_crc_ok(t))
105 {
106#ifdef DEBUG
107 puts("!!! tar header checksum error");
108#endif
109 return -2;
110 }
111
112 break;
113 }
114
115#ifdef DEBUG
116 printf("<== th_read_internal(): returning %d\n", i);
117#endif
118 return i;
119}
120
121
122/* wrapper function for th_read_internal() to handle GNU extensions */
123int
124th_read(TAR *t)
125{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500126 int i;
127 size_t sz, j, blocks;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500128 char *ptr;
129
130#ifdef DEBUG
131 printf("==> th_read(t=0x%lx)\n", t);
132#endif
133
134 if (t->th_buf.gnu_longname != NULL)
135 free(t->th_buf.gnu_longname);
136 if (t->th_buf.gnu_longlink != NULL)
137 free(t->th_buf.gnu_longlink);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200138 if (t->th_buf.selinux_context != NULL)
139 free(t->th_buf.selinux_context);
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600140#ifdef HAVE_EXT4_CRYPT
141 if (t->th_buf.e4crypt_policy != NULL) {
142 free(t->th_buf.e4crypt_policy);
143 }
144#endif
Ethan Yonker71187742017-01-13 13:30:10 -0600145 if (t->th_buf.has_cap_data)
146 {
147 memset(&t->th_buf.cap_data, 0, sizeof(struct vfs_cap_data));
148 t->th_buf.has_cap_data = 0;
149 }
Ethan Yonker8d039f72017-02-03 14:26:15 -0600150 t->th_buf.has_user_default = 0;
151 t->th_buf.has_user_cache = 0;
152 t->th_buf.has_user_code_cache = 0;
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200153
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500154 memset(&(t->th_buf), 0, sizeof(struct tar_header));
155
156 i = th_read_internal(t);
157 if (i == 0)
158 return 1;
159 else if (i != T_BLOCKSIZE)
160 {
161 if (i != -1)
162 errno = EINVAL;
163 return -1;
164 }
165
166 /* check for GNU long link extention */
167 if (TH_ISLONGLINK(t))
168 {
169 sz = th_get_size(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500170 blocks = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
171 if (blocks > ((size_t)-1 / T_BLOCKSIZE))
172 {
173 errno = E2BIG;
174 return -1;
175 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500176#ifdef DEBUG
177 printf(" th_read(): GNU long linkname detected "
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500178 "(%ld bytes, %d blocks)\n", sz, blocks);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500179#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500180 t->th_buf.gnu_longlink = (char *)malloc(blocks * T_BLOCKSIZE);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500181 if (t->th_buf.gnu_longlink == NULL)
182 return -1;
183
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500184 for (j = 0, ptr = t->th_buf.gnu_longlink; j < blocks;
185 j++, ptr += T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500186 {
187#ifdef DEBUG
188 printf(" th_read(): reading long linkname "
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500189 "(%d blocks left, ptr == %ld)\n", blocks-j, ptr);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500190#endif
191 i = tar_block_read(t, ptr);
192 if (i != T_BLOCKSIZE)
193 {
194 if (i != -1)
195 errno = EINVAL;
196 return -1;
197 }
198#ifdef DEBUG
199 printf(" th_read(): read block == \"%s\"\n", ptr);
200#endif
201 }
202#ifdef DEBUG
203 printf(" th_read(): t->th_buf.gnu_longlink == \"%s\"\n",
204 t->th_buf.gnu_longlink);
205#endif
206
207 i = th_read_internal(t);
208 if (i != T_BLOCKSIZE)
209 {
210 if (i != -1)
211 errno = EINVAL;
212 return -1;
213 }
214 }
215
216 /* check for GNU long name extention */
217 if (TH_ISLONGNAME(t))
218 {
219 sz = th_get_size(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500220 blocks = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
221 if (blocks > ((size_t)-1 / T_BLOCKSIZE))
222 {
223 errno = E2BIG;
224 return -1;
225 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500226#ifdef DEBUG
227 printf(" th_read(): GNU long filename detected "
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500228 "(%ld bytes, %d blocks)\n", sz, blocks);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500229#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500230 t->th_buf.gnu_longname = (char *)malloc(blocks * T_BLOCKSIZE);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500231 if (t->th_buf.gnu_longname == NULL)
232 return -1;
233
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500234 for (j = 0, ptr = t->th_buf.gnu_longname; j < blocks;
235 j++, ptr += T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500236 {
237#ifdef DEBUG
238 printf(" th_read(): reading long filename "
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500239 "(%d blocks left, ptr == %ld)\n", blocks-j, ptr);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500240#endif
241 i = tar_block_read(t, ptr);
242 if (i != T_BLOCKSIZE)
243 {
244 if (i != -1)
245 errno = EINVAL;
246 return -1;
247 }
248#ifdef DEBUG
249 printf(" th_read(): read block == \"%s\"\n", ptr);
250#endif
251 }
252#ifdef DEBUG
253 printf(" th_read(): t->th_buf.gnu_longname == \"%s\"\n",
254 t->th_buf.gnu_longname);
255#endif
256
257 i = th_read_internal(t);
258 if (i != T_BLOCKSIZE)
259 {
260 if (i != -1)
261 errno = EINVAL;
262 return -1;
263 }
264 }
265
Ethan Yonker71187742017-01-13 13:30:10 -0600266 // Extended headers (selinux contexts, posix file capabilities, ext4 encryption policies)
267 while(TH_ISEXTHEADER(t) || TH_ISPOLHEADER(t))
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200268 {
269 sz = th_get_size(t);
270
271 if(sz >= T_BLOCKSIZE) // Not supported
272 {
273#ifdef DEBUG
274 printf(" th_read(): Extended header is too long!\n");
275#endif
276 }
277 else
278 {
279 char buf[T_BLOCKSIZE];
280 i = tar_block_read(t, buf);
281 if (i != T_BLOCKSIZE)
282 {
283 if (i != -1)
284 errno = EINVAL;
285 return -1;
286 }
287
288 // To be sure
289 buf[T_BLOCKSIZE-1] = 0;
290
291 int len = strlen(buf);
Ethan Yonker71187742017-01-13 13:30:10 -0600292 // posix capabilities
293 char *start = strstr(buf, CAPABILITIES_TAG);
Ethan Yonker8d039f72017-02-03 14:26:15 -0600294 if (start && start+CAPABILITIES_TAG_LEN < buf+len)
Ethan Yonker71187742017-01-13 13:30:10 -0600295 {
296 start += CAPABILITIES_TAG_LEN;
297 memcpy(&t->th_buf.cap_data, start, sizeof(struct vfs_cap_data));
298 t->th_buf.has_cap_data = 1;
299#ifdef DEBUG
300 printf(" th_read(): Posix capabilities detected\n");
301#endif
302 } // end posix capabilities
Matt Mower87413642017-01-17 21:14:46 -0600303 // selinux contexts
Ethan Yonker71187742017-01-13 13:30:10 -0600304 start = strstr(buf, SELINUX_TAG);
Ethan Yonker8d039f72017-02-03 14:26:15 -0600305 if (start && start+SELINUX_TAG_LEN < buf+len)
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200306 {
307 start += SELINUX_TAG_LEN;
308 char *end = strchr(start, '\n');
309 if(end)
310 {
311 t->th_buf.selinux_context = strndup(start, end-start);
312#ifdef DEBUG
313 printf(" th_read(): SELinux context xattr detected: %s\n", t->th_buf.selinux_context);
314#endif
315 }
Matt Mower87413642017-01-17 21:14:46 -0600316 } // end selinux contexts
Ethan Yonker8d039f72017-02-03 14:26:15 -0600317 // android user.default xattr
318 start = strstr(buf, ANDROID_USER_DEFAULT_TAG);
319 if (start)
320 {
321 t->th_buf.has_user_default = 1;
322#ifdef DEBUG
323 printf(" th_read(): android user.default xattr detected\n");
324#endif
325 } // end android user.default xattr
326 // android user.inode_cache xattr
327 start = strstr(buf, ANDROID_USER_CACHE_TAG);
328 if (start)
329 {
330 t->th_buf.has_user_cache = 1;
331#ifdef DEBUG
332 printf(" th_read(): android user.inode_cache xattr detected\n");
333#endif
334 } // end android user.inode_cache xattr
335 // android user.inode_code_cache xattr
336 start = strstr(buf, ANDROID_USER_CODE_CACHE_TAG);
337 if (start)
338 {
339 t->th_buf.has_user_code_cache = 1;
340#ifdef DEBUG
341 printf(" th_read(): android user.inode_code_cache xattr detected\n");
342#endif
343 } // end android user.inode_code_cache xattr
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600344#ifdef HAVE_EXT4_CRYPT
Ethan Yonker71187742017-01-13 13:30:10 -0600345 start = strstr(buf, E4CRYPT_TAG);
Ethan Yonker8d039f72017-02-03 14:26:15 -0600346 if (start && start+E4CRYPT_TAG_LEN < buf+len)
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600347 {
348 start += E4CRYPT_TAG_LEN;
349 char *end = strchr(start, '\n');
350 if(end)
351 {
352 t->th_buf.e4crypt_policy = strndup(start, end-start);
353#ifdef DEBUG
354 printf(" th_read(): E4Crypt policy detected: %s\n", t->th_buf.e4crypt_policy);
355#endif
356 }
357 }
Ethan Yonker71187742017-01-13 13:30:10 -0600358#endif // HAVE_EXT4_CRYPT
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600359 }
360
361 i = th_read_internal(t);
362 if (i != T_BLOCKSIZE)
363 {
364 if (i != -1)
365 errno = EINVAL;
366 return -1;
367 }
368 }
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600369
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500370 return 0;
371}
372
Ethan Yonker71187742017-01-13 13:30:10 -0600373/* write an extended block */
374static int
375th_write_extended(TAR *t, char* buf, uint64_t sz)
376{
377 char type2;
378 uint64_t sz2;
379 int i;
380
381 /* save old size and type */
382 type2 = t->th_buf.typeflag;
383 sz2 = th_get_size(t);
384
385 /* write out initial header block with fake size and type */
386 t->th_buf.typeflag = TH_EXT_TYPE;
387
388 if(sz >= T_BLOCKSIZE) // impossible
389 {
390 errno = EINVAL;
391 return -1;
392 }
393
394 th_set_size(t, sz);
395 th_finish(t);
396 i = tar_block_write(t, &(t->th_buf));
397 if (i != T_BLOCKSIZE)
398 {
399 if (i != -1)
400 errno = EINVAL;
401 return -1;
402 }
403
404 i = tar_block_write(t, buf);
405 if (i != T_BLOCKSIZE)
406 {
407 if (i != -1)
408 errno = EINVAL;
409 return -1;
410 }
411
412 /* reset type and size to original values */
413 t->th_buf.typeflag = type2;
414 th_set_size(t, sz2);
415 memset(buf, 0, T_BLOCKSIZE);
416 return 0;
417}
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500418
419/* write a header block */
420int
421th_write(TAR *t)
422{
423 int i, j;
424 char type2;
Ethan Yonker71187742017-01-13 13:30:10 -0600425 uint64_t sz, sz2, total_sz = 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500426 char *ptr;
427 char buf[T_BLOCKSIZE];
428
429#ifdef DEBUG
430 printf("==> th_write(TAR=\"%s\")\n", t->pathname);
431 th_print(t);
432#endif
433
434 if ((t->options & TAR_GNU) && t->th_buf.gnu_longlink != NULL)
435 {
436#ifdef DEBUG
437 printf("th_write(): using gnu_longlink (\"%s\")\n",
438 t->th_buf.gnu_longlink);
439#endif
440 /* save old size and type */
441 type2 = t->th_buf.typeflag;
442 sz2 = th_get_size(t);
443
444 /* write out initial header block with fake size and type */
445 t->th_buf.typeflag = GNU_LONGLINK_TYPE;
446 sz = strlen(t->th_buf.gnu_longlink);
447 th_set_size(t, sz);
448 th_finish(t);
449 i = tar_block_write(t, &(t->th_buf));
450 if (i != T_BLOCKSIZE)
451 {
452 if (i != -1)
453 errno = EINVAL;
454 return -1;
455 }
456
457 /* write out extra blocks containing long name */
458 for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
459 ptr = t->th_buf.gnu_longlink; j > 1;
460 j--, ptr += T_BLOCKSIZE)
461 {
462 i = tar_block_write(t, ptr);
463 if (i != T_BLOCKSIZE)
464 {
465 if (i != -1)
466 errno = EINVAL;
467 return -1;
468 }
469 }
470 memset(buf, 0, T_BLOCKSIZE);
471 strncpy(buf, ptr, T_BLOCKSIZE);
472 i = tar_block_write(t, &buf);
473 if (i != T_BLOCKSIZE)
474 {
475 if (i != -1)
476 errno = EINVAL;
477 return -1;
478 }
479
480 /* reset type and size to original values */
481 t->th_buf.typeflag = type2;
482 th_set_size(t, sz2);
483 }
484
485 if ((t->options & TAR_GNU) && t->th_buf.gnu_longname != NULL)
486 {
487#ifdef DEBUG
488 printf("th_write(): using gnu_longname (\"%s\")\n",
489 t->th_buf.gnu_longname);
490#endif
491 /* save old size and type */
492 type2 = t->th_buf.typeflag;
493 sz2 = th_get_size(t);
494
495 /* write out initial header block with fake size and type */
496 t->th_buf.typeflag = GNU_LONGNAME_TYPE;
497 sz = strlen(t->th_buf.gnu_longname);
498 th_set_size(t, sz);
499 th_finish(t);
500 i = tar_block_write(t, &(t->th_buf));
501 if (i != T_BLOCKSIZE)
502 {
503 if (i != -1)
504 errno = EINVAL;
505 return -1;
506 }
507
508 /* write out extra blocks containing long name */
509 for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
510 ptr = t->th_buf.gnu_longname; j > 1;
511 j--, ptr += T_BLOCKSIZE)
512 {
513 i = tar_block_write(t, ptr);
514 if (i != T_BLOCKSIZE)
515 {
516 if (i != -1)
517 errno = EINVAL;
518 return -1;
519 }
520 }
521 memset(buf, 0, T_BLOCKSIZE);
522 strncpy(buf, ptr, T_BLOCKSIZE);
523 i = tar_block_write(t, &buf);
524 if (i != T_BLOCKSIZE)
525 {
526 if (i != -1)
527 errno = EINVAL;
528 return -1;
529 }
530
531 /* reset type and size to original values */
532 t->th_buf.typeflag = type2;
533 th_set_size(t, sz2);
534 }
535
Ethan Yonker71187742017-01-13 13:30:10 -0600536 memset(buf, 0, T_BLOCKSIZE);
537 ptr = buf;
Matt Mower87413642017-01-17 21:14:46 -0600538
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200539 if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL)
540 {
541#ifdef DEBUG
542 printf("th_write(): using selinux_context (\"%s\")\n",
543 t->th_buf.selinux_context);
544#endif
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200545 /* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *content* *newline* */
546 // size newline
547 sz = SELINUX_TAG_LEN + strlen(t->th_buf.selinux_context) + 3 + 1;
548
549 if(sz >= 100) // another ascci digit for size
550 ++sz;
551
Ethan Yonker71187742017-01-13 13:30:10 -0600552 total_sz += sz;
553 snprintf(ptr, T_BLOCKSIZE, "%d "SELINUX_TAG"%s\n", (int)sz, t->th_buf.selinux_context);
554 ptr += sz;
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200555 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200556
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600557#ifdef HAVE_EXT4_CRYPT
558 if((t->options & TAR_STORE_EXT4_POL) && t->th_buf.e4crypt_policy != NULL)
559 {
560#ifdef DEBUG
561 printf("th_write(): using e4crypt_policy %s\n",
562 t->th_buf.e4crypt_policy);
563#endif
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600564 /* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *content* *newline* */
565 // size newline
566 sz = E4CRYPT_TAG_LEN + EXT4_KEY_DESCRIPTOR_HEX + 3 + 1;
567
568 if(sz >= 100) // another ascci digit for size
569 ++sz;
570
Ethan Yonker71187742017-01-13 13:30:10 -0600571 if (total_sz + sz >= T_BLOCKSIZE)
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600572 {
Ethan Yonker71187742017-01-13 13:30:10 -0600573 if (th_write_extended(t, &buf, total_sz))
574 return -1;
575 ptr = buf;
576 total_sz = sz;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600577 }
Ethan Yonker71187742017-01-13 13:30:10 -0600578 else
579 total_sz += sz;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600580
Ethan Yonker71187742017-01-13 13:30:10 -0600581 snprintf(ptr, T_BLOCKSIZE, "%d "E4CRYPT_TAG"%s", (int)sz, t->th_buf.e4crypt_policy);
582 char *nlptr = ptr + sz - 1;
583 *nlptr = '\n';
584 ptr += sz;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600585 }
586#endif
587
Ethan Yonker71187742017-01-13 13:30:10 -0600588 if((t->options & TAR_STORE_POSIX_CAP) && t->th_buf.has_cap_data)
589 {
590#ifdef DEBUG
591 printf("th_write(): has a posix capability\n");
592#endif
593 sz = CAPABILITIES_TAG_LEN + sizeof(struct vfs_cap_data) + 3 + 1;
594
595 if(sz >= 100) // another ascci digit for size
596 ++sz;
597
598 if (total_sz + sz >= T_BLOCKSIZE)
599 {
600 if (th_write_extended(t, &buf, total_sz))
601 return -1;
602 ptr = buf;
603 total_sz = sz;
604 }
605 else
606 total_sz += sz;
607
608 snprintf(ptr, T_BLOCKSIZE, "%d "CAPABILITIES_TAG, (int)sz);
609 memcpy(ptr + CAPABILITIES_TAG_LEN + 3, &t->th_buf.cap_data, sizeof(struct vfs_cap_data));
610 char *nlptr = ptr + sz - 1;
611 *nlptr = '\n';
612 ptr += sz;
613 }
Ethan Yonker8d039f72017-02-03 14:26:15 -0600614 if (t->options & TAR_STORE_ANDROID_USER_XATTR)
615 {
616 if (t->th_buf.has_user_default) {
617#ifdef DEBUG
618 printf("th_write(): has android user.default xattr\n");
619#endif
620 sz = ANDROID_USER_DEFAULT_TAG_LEN + 3 + 1;
621
622 if (total_sz + sz >= T_BLOCKSIZE)
623 {
624 if (th_write_extended(t, &buf, total_sz))
625 return -1;
626 ptr = buf;
627 total_sz = sz;
628 }
629 else
630 total_sz += sz;
631
632 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_DEFAULT_TAG, (int)sz);
633 char *nlptr = ptr + sz - 1;
634 *nlptr = '\n';
635 ptr += sz;
636 }
637 if (t->th_buf.has_user_cache) {
638#ifdef DEBUG
639 printf("th_write(): has android user.inode_cache xattr\n");
640#endif
641 sz = ANDROID_USER_CACHE_TAG_LEN + 3 + 1;
642
643 if (total_sz + sz >= T_BLOCKSIZE)
644 {
645 if (th_write_extended(t, &buf, total_sz))
646 return -1;
647 ptr = buf;
648 total_sz = sz;
649 }
650 else
651 total_sz += sz;
652
653 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_CACHE_TAG, (int)sz);
654 char *nlptr = ptr + sz - 1;
655 *nlptr = '\n';
656 ptr += sz;
657 }
658 if (t->th_buf.has_user_code_cache) {
659#ifdef DEBUG
660 printf("th_write(): has android user.inode_code_cache xattr\n");
661#endif
662 sz = ANDROID_USER_CODE_CACHE_TAG_LEN + 3 + 1;
663
664 if (total_sz + sz >= T_BLOCKSIZE)
665 {
666 if (th_write_extended(t, &buf, total_sz))
667 return -1;
668 ptr = buf;
669 total_sz = sz;
670 }
671 else
672 total_sz += sz;
673
674 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_CODE_CACHE_TAG, (int)sz);
675 char *nlptr = ptr + sz - 1;
676 *nlptr = '\n';
677 ptr += sz;
678 }
679 }
Ethan Yonker71187742017-01-13 13:30:10 -0600680 if (total_sz > 0 && th_write_extended(t, &buf, total_sz)) // write any outstanding tar extended header
681 return -1;
682
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500683 th_finish(t);
684
685#ifdef DEBUG
686 /* print tar header */
687 th_print(t);
688#endif
689
690 i = tar_block_write(t, &(t->th_buf));
691 if (i != T_BLOCKSIZE)
692 {
693 if (i != -1)
694 errno = EINVAL;
695 return -1;
696 }
697
698#ifdef DEBUG
699 puts("th_write(): returning 0");
700#endif
701 return 0;
702}
703
704