blob: 82ed766b2463cb6888c973ba08a8c475291ca911 [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** extract.c - libtar code to extract a file from a tar archive
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>
14
15#include <stdio.h>
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050016#include <string.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050017#include <sys/param.h>
18#include <sys/types.h>
19#include <fcntl.h>
20#include <errno.h>
21#include <utime.h>
22
Ethan Yonker71187742017-01-13 13:30:10 -060023#include <sys/capability.h>
24#include <sys/xattr.h>
25#include <linux/xattr.h>
26
bigbiff bigbiff9c754052013-01-09 09:09:08 -050027#ifdef STDC_HEADERS
28# include <stdlib.h>
29#endif
30
31#ifdef HAVE_UNISTD_H
32# include <unistd.h>
33#endif
34
Matt Mower87413642017-01-17 21:14:46 -060035#include <selinux/selinux.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050036
Ethan Yonker79f88bd2016-12-09 14:52:12 -060037#ifdef HAVE_EXT4_CRYPT
38# include "ext4crypt_tar.h"
39#endif
Ethan Yonker8d039f72017-02-03 14:26:15 -060040#include "android_utils.h"
Ethan Yonker79f88bd2016-12-09 14:52:12 -060041
Ethan Yonker472f5062016-02-25 13:47:30 -060042const unsigned long long progress_size = (unsigned long long)(T_BLOCKSIZE);
43
bigbiff bigbiff9c754052013-01-09 09:09:08 -050044static int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050045tar_set_file_perms(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050046{
47 mode_t mode;
48 uid_t uid;
49 gid_t gid;
50 struct utimbuf ut;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050051 const char *filename;
52 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -050053
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050054 pn = th_get_pathname(t);
55 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -050056 mode = th_get_mode(t);
57 uid = th_get_uid(t);
58 gid = th_get_gid(t);
59 ut.modtime = ut.actime = th_get_mtime(t);
60
Dees_Troy71796592013-03-14 20:16:29 +000061#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050062 printf("tar_set_file_perms(): setting perms: %s (mode %04o, uid %d, gid %d)\n",
63 filename, mode, uid, gid);
Dees_Troy71796592013-03-14 20:16:29 +000064#endif
65
bigbiff bigbiff9c754052013-01-09 09:09:08 -050066 /* change owner/group */
67 if (geteuid() == 0)
68#ifdef HAVE_LCHOWN
69 if (lchown(filename, uid, gid) == -1)
70 {
71# ifdef DEBUG
72 fprintf(stderr, "lchown(\"%s\", %d, %d): %s\n",
73 filename, uid, gid, strerror(errno));
74# endif
75#else /* ! HAVE_LCHOWN */
76 if (!TH_ISSYM(t) && chown(filename, uid, gid) == -1)
77 {
78# ifdef DEBUG
79 fprintf(stderr, "chown(\"%s\", %d, %d): %s\n",
80 filename, uid, gid, strerror(errno));
81# endif
82#endif /* HAVE_LCHOWN */
83 return -1;
84 }
85
86 /* change access/modification time */
87 if (!TH_ISSYM(t) && utime(filename, &ut) == -1)
88 {
89#ifdef DEBUG
90 perror("utime()");
91#endif
92 return -1;
93 }
94
95 /* change permissions */
96 if (!TH_ISSYM(t) && chmod(filename, mode) == -1)
97 {
98#ifdef DEBUG
99 perror("chmod()");
100#endif
101 return -1;
102 }
103
104 return 0;
105}
106
107
108/* switchboard */
109int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500110tar_extract_file(TAR *t, const char *realname, const char *prefix, const int *progress_fd)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500111{
112 int i;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500113#ifdef LIBTAR_FILE_HASH
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500114 char *lnp;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500115 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500116 int pathname_len;
117 int realname_len;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500118#endif
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500119
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500120 if (t->options & TAR_NOOVERWRITE)
121 {
122 struct stat s;
123
124 if (lstat(realname, &s) == 0 || errno != ENOENT)
125 {
126 errno = EEXIST;
127 return -1;
128 }
129 }
130
131 if (TH_ISDIR(t))
132 {
133 i = tar_extract_dir(t, realname);
134 if (i == 1)
135 i = 0;
136 }
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500137 else if (TH_ISLNK(t))
Dees_Troyee6632c2013-02-27 18:07:32 +0000138 i = tar_extract_hardlink(t, realname, prefix);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500139 else if (TH_ISSYM(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500140 i = tar_extract_symlink(t, realname);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500141 else if (TH_ISCHR(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500142 i = tar_extract_chardev(t, realname);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500143 else if (TH_ISBLK(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500144 i = tar_extract_blockdev(t, realname);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500145 else if (TH_ISFIFO(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500146 i = tar_extract_fifo(t, realname);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500147 else /* if (TH_ISREG(t)) */
Ethan Yonker1b7a31b2014-07-03 15:09:22 -0500148 i = tar_extract_regfile(t, realname, progress_fd);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500149
150 if (i != 0) {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500151 fprintf(stderr, "tar_extract_file(): failed to extract %s !!!\n", realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500152 return i;
153 }
154
155 i = tar_set_file_perms(t, realname);
156 if (i != 0) {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500157 fprintf(stderr, "tar_extract_file(): failed to set permissions on %s !!!\n", realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500158 return i;
159 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200160
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200161 if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL)
162 {
163#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500164 printf("tar_extract_file(): restoring SELinux context %s to file %s\n", t->th_buf.selinux_context, realname);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200165#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500166 if (lsetfilecon(realname, t->th_buf.selinux_context) < 0)
167 fprintf(stderr, "tar_extract_file(): failed to restore SELinux context %s to file %s !!!\n", t->th_buf.selinux_context, realname);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200168 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200169
Ethan Yonker71187742017-01-13 13:30:10 -0600170 if((t->options & TAR_STORE_POSIX_CAP) && t->th_buf.has_cap_data)
171 {
172#if 1 //def DEBUG
173 printf("tar_extract_file(): restoring posix capabilities to file %s\n", realname);
174 print_caps(&t->th_buf.cap_data);
175#endif
176 if (setxattr(realname, XATTR_NAME_CAPS, &t->th_buf.cap_data, sizeof(struct vfs_cap_data), 0) < 0)
177 fprintf(stderr, "tar_extract_file(): failed to restore posix capabilities to file %s !!!\n", realname);
178 }
179
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500180#ifdef LIBTAR_FILE_HASH
181 pn = th_get_pathname(t);
182 pathname_len = strlen(pn) + 1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500183 realname_len = strlen(realname) + 1;
184 lnp = (char *)calloc(1, pathname_len + realname_len);
185 if (lnp == NULL)
186 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500187 strcpy(&lnp[0], pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500188 strcpy(&lnp[pathname_len], realname);
189#ifdef DEBUG
190 printf("tar_extract_file(): calling libtar_hash_add(): key=\"%s\", "
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500191 "value=\"%s\"\n", pn, realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500192#endif
193 if (libtar_hash_add(t->h, lnp) != 0)
194 return -1;
195 free(lnp);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500196#endif
197
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500198 return 0;
199}
200
201
202/* extract regular file */
203int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500204tar_extract_regfile(TAR *t, const char *realname, const int *progress_fd)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500205{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500206 int64_t size, i;
207 ssize_t k;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500208 int fdout;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500209 char buf[T_BLOCKSIZE];
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500210 const char *filename;
211 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500212
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500213#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500214 printf(" ==> tar_extract_regfile(realname=\"%s\")\n", realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500215#endif
216
217 if (!TH_ISREG(t))
218 {
219 errno = EINVAL;
220 return -1;
221 }
222
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500223 pn = th_get_pathname(t);
224 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500225 size = th_get_size(t);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500226
227 if (mkdirhier(dirname(filename)) == -1)
228 return -1;
229
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500230 printf(" ==> extracting: %s (file size %lld bytes)\n",
231 filename, size);
232
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500233 fdout = open(filename, O_WRONLY | O_CREAT | O_TRUNC
234#ifdef O_BINARY
235 | O_BINARY
236#endif
237 , 0666);
238 if (fdout == -1)
239 {
240#ifdef DEBUG
241 perror("open()");
242#endif
243 return -1;
244 }
245
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500246 /* extract the file */
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500247 for (i = size; i > 0; i -= T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500248 {
249 k = tar_block_read(t, buf);
250 if (k != T_BLOCKSIZE)
251 {
252 if (k != -1)
253 errno = EINVAL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500254 close(fdout);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500255 return -1;
256 }
257
258 /* write block to output file */
259 if (write(fdout, buf,
260 ((i > T_BLOCKSIZE) ? T_BLOCKSIZE : i)) == -1)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500261 {
262 close(fdout);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500263 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500264 }
Ethan Yonker472f5062016-02-25 13:47:30 -0600265 else
266 {
267 if (*progress_fd != 0)
268 write(*progress_fd, &progress_size, sizeof(progress_size));
269 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500270 }
271
272 /* close output file */
273 if (close(fdout) == -1)
274 return -1;
275
276#ifdef DEBUG
277 printf("### done extracting %s\n", filename);
278#endif
279
280 return 0;
281}
282
283
284/* skip regfile */
285int
286tar_skip_regfile(TAR *t)
287{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500288 int64_t size, i;
289 ssize_t k;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500290 char buf[T_BLOCKSIZE];
291
292 if (!TH_ISREG(t))
293 {
294 errno = EINVAL;
295 return -1;
296 }
297
298 size = th_get_size(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500299 for (i = size; i > 0; i -= T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500300 {
301 k = tar_block_read(t, buf);
302 if (k != T_BLOCKSIZE)
303 {
304 if (k != -1)
305 errno = EINVAL;
306 return -1;
307 }
308 }
309
310 return 0;
311}
312
313
314/* hardlink */
315int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500316tar_extract_hardlink(TAR * t, const char *realname, const char *prefix)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500317{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500318 const char *filename;
319 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500320 char *linktgt = NULL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500321 char *newtgt = NULL;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500322 char *lnp;
323 libtar_hashptr_t hp;
324
325 if (!TH_ISLNK(t))
326 {
327 errno = EINVAL;
328 return -1;
329 }
330
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500331 pn = th_get_pathname(t);
332 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500333 if (mkdirhier(dirname(filename)) == -1)
334 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500335 if (unlink(filename) == -1 && errno != ENOENT)
336 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500337 libtar_hashptr_reset(&hp);
338 if (libtar_hash_getkey(t->h, &hp, th_get_linkname(t),
339 (libtar_matchfunc_t)libtar_str_match) != 0)
340 {
341 lnp = (char *)libtar_hashptr_data(&hp);
342 linktgt = &lnp[strlen(lnp) + 1];
343 }
344 else
345 linktgt = th_get_linkname(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500346
347 newtgt = strdup(linktgt);
Dees_Troyee6632c2013-02-27 18:07:32 +0000348 sprintf(linktgt, "%s/%s", prefix, newtgt);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500349
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500350 printf(" ==> extracting: %s (link to %s)\n", filename, linktgt);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500351
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500352 if (link(linktgt, filename) == -1)
353 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500354 fprintf(stderr, "tar_extract_hardlink(): failed restore of hardlink '%s' but returning as if nothing bad happened\n", filename);
Dees_Troyf96fb972013-03-01 22:34:25 +0000355 return 0; // Used to be -1
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500356 }
357
358 return 0;
359}
360
361
362/* symlink */
363int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500364tar_extract_symlink(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500365{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500366 const char *filename;
367 char *pn;
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500368
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500369 if (!TH_ISSYM(t))
370 {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500371 errno = EINVAL;
372 return -1;
373 }
374
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500375 pn = th_get_pathname(t);
376 filename = (realname ? realname : pn);
377 if (mkdirhier(dirname(filename)) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500378 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500379
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500380 if (unlink(filename) == -1 && errno != ENOENT)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500381 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500382
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500383 printf(" ==> extracting: %s (symlink to %s)\n",
384 filename, th_get_linkname(t));
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500385
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500386 if (symlink(th_get_linkname(t), filename) == -1)
387 {
388#ifdef DEBUG
389 perror("symlink()");
390#endif
391 return -1;
392 }
393
394 return 0;
395}
396
397
398/* character device */
399int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500400tar_extract_chardev(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500401{
402 mode_t mode;
403 unsigned long devmaj, devmin;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500404 const char *filename;
405 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500406
407 if (!TH_ISCHR(t))
408 {
409 errno = EINVAL;
410 return -1;
411 }
412
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500413 pn = th_get_pathname(t);
414 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500415 mode = th_get_mode(t);
416 devmaj = th_get_devmajor(t);
417 devmin = th_get_devminor(t);
418
419 if (mkdirhier(dirname(filename)) == -1)
420 return -1;
421
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500422 printf(" ==> extracting: %s (character device %ld,%ld)\n",
423 filename, devmaj, devmin);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500424
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500425 if (mknod(filename, mode | S_IFCHR,
426 compat_makedev(devmaj, devmin)) == -1)
427 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500428 fprintf(stderr, "tar_extract_chardev(): failed restore of character device '%s' but returning as if nothing bad happened\n", filename);
429 return 0; // Used to be -1
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500430 }
431
432 return 0;
433}
434
435
436/* block device */
437int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500438tar_extract_blockdev(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500439{
440 mode_t mode;
441 unsigned long devmaj, devmin;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500442 const char *filename;
443 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500444
445 if (!TH_ISBLK(t))
446 {
447 errno = EINVAL;
448 return -1;
449 }
450
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500451 pn = th_get_pathname(t);
452 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500453 mode = th_get_mode(t);
454 devmaj = th_get_devmajor(t);
455 devmin = th_get_devminor(t);
456
457 if (mkdirhier(dirname(filename)) == -1)
458 return -1;
459
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500460 printf(" ==> extracting: %s (block device %ld,%ld)\n",
461 filename, devmaj, devmin);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500462
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500463 if (mknod(filename, mode | S_IFBLK,
464 compat_makedev(devmaj, devmin)) == -1)
465 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500466 fprintf(stderr, "tar_extract_blockdev(): failed restore of block device '%s' but returning as if nothing bad happened\n", filename);
467 return 0; // Used to be -1
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500468 }
469
470 return 0;
471}
472
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500473/* directory */
474int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500475tar_extract_dir(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500476{
477 mode_t mode;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500478 const char *filename;
479 char *pn;
480
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500481 if (!TH_ISDIR(t))
482 {
483 errno = EINVAL;
484 return -1;
485 }
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500486 pn = th_get_pathname(t);
487 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500488 mode = th_get_mode(t);
489
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500490 if (mkdirhier(dirname(filename)) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500491 return -1;
492
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500493 printf(" ==> extracting: %s (mode %04o, directory)\n", filename,
494 mode);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500495
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500496 if (mkdir(filename, mode) == -1)
497 {
498 if (errno == EEXIST)
499 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500500 if (chmod(filename, mode) == -1)
501 {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500502#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500503 perror("chmod()");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500504#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500505 return -1;
506 }
507 else
508 {
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600509#if 1 //def DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500510 puts(" *** using existing directory");
511#endif
512 return 1;
513 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500514 }
515 else
516 {
517#ifdef DEBUG
518 perror("mkdir()");
519#endif
520 return -1;
521 }
522 }
523
Ethan Yonker8d039f72017-02-03 14:26:15 -0600524 if (t->options & TAR_STORE_ANDROID_USER_XATTR)
525 {
526 if (t->th_buf.has_user_default) {
527#if 1 //def DEBUG
528 printf("tar_extract_file(): restoring android user.default xattr to %s\n", realname);
529#endif
530 if (setxattr(realname, "user.default", NULL, 0, 0) < 0) {
531 fprintf(stderr, "tar_extract_file(): failed to restore android user.default to file %s !!!\n", realname);
532 return -1;
533 }
534 }
535 if (t->th_buf.has_user_cache) {
536#if 1 //def DEBUG
537 printf("tar_extract_file(): restoring android user.inode_cache xattr to %s\n", realname);
538#endif
539 if (write_path_inode(realname, "cache", "user.inode_cache"))
540 return -1;
541 }
542 if (t->th_buf.has_user_code_cache) {
543#if 1 //def DEBUG
544 printf("tar_extract_file(): restoring android user.inode_code_cache xattr to %s\n", realname);
545#endif
546 if (write_path_inode(realname, "code_cache", "user.inode_code_cache"))
547 return -1;
548 }
549 }
550
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600551#ifdef HAVE_EXT4_CRYPT
552 if(t->th_buf.e4crypt_policy != NULL)
553 {
554#ifdef DEBUG
555 printf("tar_extract_file(): restoring EXT4 crypt policy %s to dir %s\n", t->th_buf.e4crypt_policy, realname);
556#endif
557 char binary_policy[EXT4_KEY_DESCRIPTOR_SIZE];
558 if (!lookup_ref_tar(t->th_buf.e4crypt_policy, &binary_policy)) {
559 printf("error looking up proper e4crypt policy for '%s' - %s\n", realname, t->th_buf.e4crypt_policy);
560 return -1;
561 }
562 char policy_hex[EXT4_KEY_DESCRIPTOR_HEX];
563 policy_to_hex(binary_policy, policy_hex);
564 printf("restoring policy %s > '%s' to '%s'\n", t->th_buf.e4crypt_policy, policy_hex, realname);
565 if (!e4crypt_policy_set(realname, binary_policy, EXT4_KEY_DESCRIPTOR_SIZE, 0))
566 {
567 printf("tar_extract_file(): failed to restore EXT4 crypt policy %s to dir '%s' '%s'!!!\n", t->th_buf.e4crypt_policy, realname, policy_hex);
568 //return -1; // This may not be an error in some cases, so log and ignore
569 }
570 }
571#endif
572
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500573 return 0;
574}
575
576
577/* FIFO */
578int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500579tar_extract_fifo(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500580{
581 mode_t mode;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500582 const char *filename;
583 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500584
585 if (!TH_ISFIFO(t))
586 {
587 errno = EINVAL;
588 return -1;
589 }
590
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500591 pn = th_get_pathname(t);
592 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500593 mode = th_get_mode(t);
594
595 if (mkdirhier(dirname(filename)) == -1)
596 return -1;
597
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500598
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500599 printf(" ==> extracting: %s (fifo)\n", filename);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500600
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500601 if (mkfifo(filename, mode) == -1)
602 {
603#ifdef DEBUG
604 perror("mkfifo()");
605#endif
606 return -1;
607 }
608
609 return 0;
610}
611
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500612/* extract file contents from a tarchive */
613int
614tar_extract_file_contents(TAR *t, void *buf, size_t *lenp)
615{
616 char block[T_BLOCKSIZE];
617 int64_t size, i;
618 ssize_t k;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500619
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500620#ifdef DEBUG
621 printf(" ==> tar_extract_file_contents\n");
622#endif
623
624 if (!TH_ISREG(t))
625 {
626 errno = EINVAL;
627 return -1;
628 }
629
630 size = th_get_size(t);
631 if ((uint64_t)size > *lenp)
632 {
633 errno = ENOSPC;
634 return -1;
635 }
636
637 /* extract the file */
638 for (i = size; i >= T_BLOCKSIZE; i -= T_BLOCKSIZE)
639 {
640 k = tar_block_read(t, buf);
641 if (k != T_BLOCKSIZE)
642 {
643 if (k != -1)
644 errno = EINVAL;
645 return -1;
646 }
647 buf = (char *)buf + T_BLOCKSIZE;
648 }
649 if (i > 0) {
650 k = tar_block_read(t, block);
651 if (k != T_BLOCKSIZE)
652 {
653 if (k != -1)
654 errno = EINVAL;
655 return -1;
656 }
657 memcpy(buf, block, i);
658 }
659 *lenp = (size_t)size;
660
661#ifdef DEBUG
662 printf("### done extracting contents\n");
663#endif
664 return 0;
665}