blob: 8b2205933147ac0cf2c6c8d4a9df74b1a7490207 [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');
Ethan Yonkerda056fd2017-07-05 22:10:24 -0500350 if(!end)
351 end = strchr(start, '\0');
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600352 if(end)
353 {
Ethan Yonkerda056fd2017-07-05 22:10:24 -0500354 t->th_buf.e4crypt_policy = strndup(start, end-start);
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600355#ifdef DEBUG
Ethan Yonkerda056fd2017-07-05 22:10:24 -0500356 printf(" th_read(): E4Crypt policy detected: %s\n", t->th_buf.e4crypt_policy);
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600357#endif
358 }
359 }
Ethan Yonker71187742017-01-13 13:30:10 -0600360#endif // HAVE_EXT4_CRYPT
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600361 }
362
363 i = th_read_internal(t);
364 if (i != T_BLOCKSIZE)
365 {
366 if (i != -1)
367 errno = EINVAL;
368 return -1;
369 }
370 }
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600371
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500372 return 0;
373}
374
Ethan Yonker71187742017-01-13 13:30:10 -0600375/* write an extended block */
376static int
377th_write_extended(TAR *t, char* buf, uint64_t sz)
378{
379 char type2;
380 uint64_t sz2;
381 int i;
382
383 /* save old size and type */
384 type2 = t->th_buf.typeflag;
385 sz2 = th_get_size(t);
386
387 /* write out initial header block with fake size and type */
388 t->th_buf.typeflag = TH_EXT_TYPE;
389
390 if(sz >= T_BLOCKSIZE) // impossible
391 {
392 errno = EINVAL;
393 return -1;
394 }
395
396 th_set_size(t, sz);
397 th_finish(t);
398 i = tar_block_write(t, &(t->th_buf));
399 if (i != T_BLOCKSIZE)
400 {
401 if (i != -1)
402 errno = EINVAL;
403 return -1;
404 }
405
406 i = tar_block_write(t, buf);
407 if (i != T_BLOCKSIZE)
408 {
409 if (i != -1)
410 errno = EINVAL;
411 return -1;
412 }
413
414 /* reset type and size to original values */
415 t->th_buf.typeflag = type2;
416 th_set_size(t, sz2);
417 memset(buf, 0, T_BLOCKSIZE);
418 return 0;
419}
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500420
421/* write a header block */
422int
423th_write(TAR *t)
424{
425 int i, j;
426 char type2;
Ethan Yonker71187742017-01-13 13:30:10 -0600427 uint64_t sz, sz2, total_sz = 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500428 char *ptr;
429 char buf[T_BLOCKSIZE];
430
431#ifdef DEBUG
432 printf("==> th_write(TAR=\"%s\")\n", t->pathname);
433 th_print(t);
434#endif
435
436 if ((t->options & TAR_GNU) && t->th_buf.gnu_longlink != NULL)
437 {
438#ifdef DEBUG
439 printf("th_write(): using gnu_longlink (\"%s\")\n",
440 t->th_buf.gnu_longlink);
441#endif
442 /* save old size and type */
443 type2 = t->th_buf.typeflag;
444 sz2 = th_get_size(t);
445
446 /* write out initial header block with fake size and type */
447 t->th_buf.typeflag = GNU_LONGLINK_TYPE;
448 sz = strlen(t->th_buf.gnu_longlink);
449 th_set_size(t, sz);
450 th_finish(t);
451 i = tar_block_write(t, &(t->th_buf));
452 if (i != T_BLOCKSIZE)
453 {
454 if (i != -1)
455 errno = EINVAL;
456 return -1;
457 }
458
459 /* write out extra blocks containing long name */
460 for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
461 ptr = t->th_buf.gnu_longlink; j > 1;
462 j--, ptr += T_BLOCKSIZE)
463 {
464 i = tar_block_write(t, ptr);
465 if (i != T_BLOCKSIZE)
466 {
467 if (i != -1)
468 errno = EINVAL;
469 return -1;
470 }
471 }
472 memset(buf, 0, T_BLOCKSIZE);
473 strncpy(buf, ptr, T_BLOCKSIZE);
474 i = tar_block_write(t, &buf);
475 if (i != T_BLOCKSIZE)
476 {
477 if (i != -1)
478 errno = EINVAL;
479 return -1;
480 }
481
482 /* reset type and size to original values */
483 t->th_buf.typeflag = type2;
484 th_set_size(t, sz2);
485 }
486
487 if ((t->options & TAR_GNU) && t->th_buf.gnu_longname != NULL)
488 {
489#ifdef DEBUG
490 printf("th_write(): using gnu_longname (\"%s\")\n",
491 t->th_buf.gnu_longname);
492#endif
493 /* save old size and type */
494 type2 = t->th_buf.typeflag;
495 sz2 = th_get_size(t);
496
497 /* write out initial header block with fake size and type */
498 t->th_buf.typeflag = GNU_LONGNAME_TYPE;
499 sz = strlen(t->th_buf.gnu_longname);
500 th_set_size(t, sz);
501 th_finish(t);
502 i = tar_block_write(t, &(t->th_buf));
503 if (i != T_BLOCKSIZE)
504 {
505 if (i != -1)
506 errno = EINVAL;
507 return -1;
508 }
509
510 /* write out extra blocks containing long name */
511 for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
512 ptr = t->th_buf.gnu_longname; j > 1;
513 j--, ptr += T_BLOCKSIZE)
514 {
515 i = tar_block_write(t, ptr);
516 if (i != T_BLOCKSIZE)
517 {
518 if (i != -1)
519 errno = EINVAL;
520 return -1;
521 }
522 }
523 memset(buf, 0, T_BLOCKSIZE);
524 strncpy(buf, ptr, T_BLOCKSIZE);
525 i = tar_block_write(t, &buf);
526 if (i != T_BLOCKSIZE)
527 {
528 if (i != -1)
529 errno = EINVAL;
530 return -1;
531 }
532
533 /* reset type and size to original values */
534 t->th_buf.typeflag = type2;
535 th_set_size(t, sz2);
536 }
537
Ethan Yonker71187742017-01-13 13:30:10 -0600538 memset(buf, 0, T_BLOCKSIZE);
539 ptr = buf;
Matt Mower87413642017-01-17 21:14:46 -0600540
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200541 if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL)
542 {
543#ifdef DEBUG
544 printf("th_write(): using selinux_context (\"%s\")\n",
545 t->th_buf.selinux_context);
546#endif
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200547 /* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *content* *newline* */
548 // size newline
549 sz = SELINUX_TAG_LEN + strlen(t->th_buf.selinux_context) + 3 + 1;
550
551 if(sz >= 100) // another ascci digit for size
552 ++sz;
553
Ethan Yonker71187742017-01-13 13:30:10 -0600554 total_sz += sz;
555 snprintf(ptr, T_BLOCKSIZE, "%d "SELINUX_TAG"%s\n", (int)sz, t->th_buf.selinux_context);
556 ptr += sz;
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200557 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200558
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600559#ifdef HAVE_EXT4_CRYPT
560 if((t->options & TAR_STORE_EXT4_POL) && t->th_buf.e4crypt_policy != NULL)
561 {
562#ifdef DEBUG
563 printf("th_write(): using e4crypt_policy %s\n",
564 t->th_buf.e4crypt_policy);
565#endif
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600566 /* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *content* *newline* */
567 // size newline
Ethan Yonkerda056fd2017-07-05 22:10:24 -0500568 sz = E4CRYPT_TAG_LEN + strlen(t->th_buf.e4crypt_policy) + 3 + 1;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600569
570 if(sz >= 100) // another ascci digit for size
571 ++sz;
572
Ethan Yonker71187742017-01-13 13:30:10 -0600573 if (total_sz + sz >= T_BLOCKSIZE)
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600574 {
Ethan Yonker71187742017-01-13 13:30:10 -0600575 if (th_write_extended(t, &buf, total_sz))
576 return -1;
577 ptr = buf;
578 total_sz = sz;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600579 }
Ethan Yonker71187742017-01-13 13:30:10 -0600580 else
581 total_sz += sz;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600582
Ethan Yonker71187742017-01-13 13:30:10 -0600583 snprintf(ptr, T_BLOCKSIZE, "%d "E4CRYPT_TAG"%s", (int)sz, t->th_buf.e4crypt_policy);
584 char *nlptr = ptr + sz - 1;
585 *nlptr = '\n';
586 ptr += sz;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600587 }
588#endif
589
Ethan Yonker71187742017-01-13 13:30:10 -0600590 if((t->options & TAR_STORE_POSIX_CAP) && t->th_buf.has_cap_data)
591 {
592#ifdef DEBUG
593 printf("th_write(): has a posix capability\n");
594#endif
595 sz = CAPABILITIES_TAG_LEN + sizeof(struct vfs_cap_data) + 3 + 1;
596
597 if(sz >= 100) // another ascci digit for size
598 ++sz;
599
600 if (total_sz + sz >= T_BLOCKSIZE)
601 {
602 if (th_write_extended(t, &buf, total_sz))
603 return -1;
604 ptr = buf;
605 total_sz = sz;
606 }
607 else
608 total_sz += sz;
609
610 snprintf(ptr, T_BLOCKSIZE, "%d "CAPABILITIES_TAG, (int)sz);
611 memcpy(ptr + CAPABILITIES_TAG_LEN + 3, &t->th_buf.cap_data, sizeof(struct vfs_cap_data));
612 char *nlptr = ptr + sz - 1;
613 *nlptr = '\n';
614 ptr += sz;
615 }
Ethan Yonker8d039f72017-02-03 14:26:15 -0600616 if (t->options & TAR_STORE_ANDROID_USER_XATTR)
617 {
618 if (t->th_buf.has_user_default) {
619#ifdef DEBUG
620 printf("th_write(): has android user.default xattr\n");
621#endif
622 sz = ANDROID_USER_DEFAULT_TAG_LEN + 3 + 1;
623
624 if (total_sz + sz >= T_BLOCKSIZE)
625 {
626 if (th_write_extended(t, &buf, total_sz))
627 return -1;
628 ptr = buf;
629 total_sz = sz;
630 }
631 else
632 total_sz += sz;
633
634 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_DEFAULT_TAG, (int)sz);
635 char *nlptr = ptr + sz - 1;
636 *nlptr = '\n';
637 ptr += sz;
638 }
639 if (t->th_buf.has_user_cache) {
640#ifdef DEBUG
641 printf("th_write(): has android user.inode_cache xattr\n");
642#endif
643 sz = ANDROID_USER_CACHE_TAG_LEN + 3 + 1;
644
645 if (total_sz + sz >= T_BLOCKSIZE)
646 {
647 if (th_write_extended(t, &buf, total_sz))
648 return -1;
649 ptr = buf;
650 total_sz = sz;
651 }
652 else
653 total_sz += sz;
654
655 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_CACHE_TAG, (int)sz);
656 char *nlptr = ptr + sz - 1;
657 *nlptr = '\n';
658 ptr += sz;
659 }
660 if (t->th_buf.has_user_code_cache) {
661#ifdef DEBUG
662 printf("th_write(): has android user.inode_code_cache xattr\n");
663#endif
664 sz = ANDROID_USER_CODE_CACHE_TAG_LEN + 3 + 1;
665
666 if (total_sz + sz >= T_BLOCKSIZE)
667 {
668 if (th_write_extended(t, &buf, total_sz))
669 return -1;
670 ptr = buf;
671 total_sz = sz;
672 }
673 else
674 total_sz += sz;
675
676 snprintf(ptr, T_BLOCKSIZE, "%d "ANDROID_USER_CODE_CACHE_TAG, (int)sz);
677 char *nlptr = ptr + sz - 1;
678 *nlptr = '\n';
679 ptr += sz;
680 }
681 }
Ethan Yonker71187742017-01-13 13:30:10 -0600682 if (total_sz > 0 && th_write_extended(t, &buf, total_sz)) // write any outstanding tar extended header
683 return -1;
684
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500685 th_finish(t);
686
687#ifdef DEBUG
688 /* print tar header */
689 th_print(t);
690#endif
691
692 i = tar_block_write(t, &(t->th_buf));
693 if (i != T_BLOCKSIZE)
694 {
695 if (i != -1)
696 errno = EINVAL;
697 return -1;
698 }
699
700#ifdef DEBUG
701 puts("th_write(): returning 0");
702#endif
703 return 0;
704}
705
706