blob: ea86c233b20b62039e92c37c29a67f683208b427 [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
Ethan Yonker58f21322018-08-24 11:17:36 -050015#include <inttypes.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050016#include <stdio.h>
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050017#include <string.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050018#include <sys/param.h>
19#include <sys/types.h>
20#include <fcntl.h>
21#include <errno.h>
22#include <utime.h>
23
Ethan Yonker71187742017-01-13 13:30:10 -060024#include <sys/capability.h>
25#include <sys/xattr.h>
26#include <linux/xattr.h>
27
bigbiff bigbiff9c754052013-01-09 09:09:08 -050028#ifdef STDC_HEADERS
29# include <stdlib.h>
30#endif
31
32#ifdef HAVE_UNISTD_H
33# include <unistd.h>
34#endif
35
Matt Mower87413642017-01-17 21:14:46 -060036#include <selinux/selinux.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050037
Ethan Yonker79f88bd2016-12-09 14:52:12 -060038#ifdef HAVE_EXT4_CRYPT
39# include "ext4crypt_tar.h"
40#endif
Ethan Yonker8d039f72017-02-03 14:26:15 -060041#include "android_utils.h"
Ethan Yonker79f88bd2016-12-09 14:52:12 -060042
Ethan Yonker472f5062016-02-25 13:47:30 -060043const unsigned long long progress_size = (unsigned long long)(T_BLOCKSIZE);
44
bigbiff bigbiff9c754052013-01-09 09:09:08 -050045static int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050046tar_set_file_perms(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050047{
48 mode_t mode;
49 uid_t uid;
50 gid_t gid;
51 struct utimbuf ut;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050052 const char *filename;
53 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -050054
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050055 pn = th_get_pathname(t);
56 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -050057 mode = th_get_mode(t);
58 uid = th_get_uid(t);
59 gid = th_get_gid(t);
60 ut.modtime = ut.actime = th_get_mtime(t);
61
Dees_Troy71796592013-03-14 20:16:29 +000062#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050063 printf("tar_set_file_perms(): setting perms: %s (mode %04o, uid %d, gid %d)\n",
64 filename, mode, uid, gid);
Dees_Troy71796592013-03-14 20:16:29 +000065#endif
66
bigbiff bigbiff9c754052013-01-09 09:09:08 -050067 /* change owner/group */
68 if (geteuid() == 0)
69#ifdef HAVE_LCHOWN
70 if (lchown(filename, uid, gid) == -1)
71 {
72# ifdef DEBUG
73 fprintf(stderr, "lchown(\"%s\", %d, %d): %s\n",
74 filename, uid, gid, strerror(errno));
75# endif
76#else /* ! HAVE_LCHOWN */
77 if (!TH_ISSYM(t) && chown(filename, uid, gid) == -1)
78 {
79# ifdef DEBUG
80 fprintf(stderr, "chown(\"%s\", %d, %d): %s\n",
81 filename, uid, gid, strerror(errno));
82# endif
83#endif /* HAVE_LCHOWN */
84 return -1;
85 }
86
87 /* change access/modification time */
88 if (!TH_ISSYM(t) && utime(filename, &ut) == -1)
89 {
90#ifdef DEBUG
91 perror("utime()");
92#endif
93 return -1;
94 }
95
96 /* change permissions */
97 if (!TH_ISSYM(t) && chmod(filename, mode) == -1)
98 {
99#ifdef DEBUG
100 perror("chmod()");
101#endif
102 return -1;
103 }
104
105 return 0;
106}
107
108
109/* switchboard */
110int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500111tar_extract_file(TAR *t, const char *realname, const char *prefix, const int *progress_fd)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500112{
113 int i;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500114#ifdef LIBTAR_FILE_HASH
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500115 char *lnp;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500116 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500117 int pathname_len;
118 int realname_len;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500119#endif
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500120
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500121 if (t->options & TAR_NOOVERWRITE)
122 {
123 struct stat s;
124
125 if (lstat(realname, &s) == 0 || errno != ENOENT)
126 {
127 errno = EEXIST;
128 return -1;
129 }
130 }
131
132 if (TH_ISDIR(t))
133 {
134 i = tar_extract_dir(t, realname);
135 if (i == 1)
136 i = 0;
137 }
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500138 else if (TH_ISLNK(t))
Dees_Troyee6632c2013-02-27 18:07:32 +0000139 i = tar_extract_hardlink(t, realname, prefix);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500140 else if (TH_ISSYM(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500141 i = tar_extract_symlink(t, realname);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500142 else if (TH_ISCHR(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500143 i = tar_extract_chardev(t, realname);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500144 else if (TH_ISBLK(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500145 i = tar_extract_blockdev(t, realname);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500146 else if (TH_ISFIFO(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500147 i = tar_extract_fifo(t, realname);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500148 else /* if (TH_ISREG(t)) */
Ethan Yonker1b7a31b2014-07-03 15:09:22 -0500149 i = tar_extract_regfile(t, realname, progress_fd);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500150
151 if (i != 0) {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500152 fprintf(stderr, "tar_extract_file(): failed to extract %s !!!\n", realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500153 return i;
154 }
155
156 i = tar_set_file_perms(t, realname);
157 if (i != 0) {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500158 fprintf(stderr, "tar_extract_file(): failed to set permissions on %s !!!\n", realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500159 return i;
160 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200161
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200162 if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL)
163 {
164#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500165 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 +0200166#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500167 if (lsetfilecon(realname, t->th_buf.selinux_context) < 0)
168 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 +0200169 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200170
Ethan Yonker71187742017-01-13 13:30:10 -0600171 if((t->options & TAR_STORE_POSIX_CAP) && t->th_buf.has_cap_data)
172 {
173#if 1 //def DEBUG
174 printf("tar_extract_file(): restoring posix capabilities to file %s\n", realname);
175 print_caps(&t->th_buf.cap_data);
176#endif
177 if (setxattr(realname, XATTR_NAME_CAPS, &t->th_buf.cap_data, sizeof(struct vfs_cap_data), 0) < 0)
178 fprintf(stderr, "tar_extract_file(): failed to restore posix capabilities to file %s !!!\n", realname);
179 }
180
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500181#ifdef LIBTAR_FILE_HASH
182 pn = th_get_pathname(t);
183 pathname_len = strlen(pn) + 1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500184 realname_len = strlen(realname) + 1;
185 lnp = (char *)calloc(1, pathname_len + realname_len);
186 if (lnp == NULL)
187 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500188 strcpy(&lnp[0], pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500189 strcpy(&lnp[pathname_len], realname);
190#ifdef DEBUG
191 printf("tar_extract_file(): calling libtar_hash_add(): key=\"%s\", "
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500192 "value=\"%s\"\n", pn, realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500193#endif
194 if (libtar_hash_add(t->h, lnp) != 0)
195 return -1;
196 free(lnp);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500197#endif
198
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500199 return 0;
200}
201
202
203/* extract regular file */
204int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500205tar_extract_regfile(TAR *t, const char *realname, const int *progress_fd)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500206{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500207 int64_t size, i;
208 ssize_t k;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500209 int fdout;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500210 char buf[T_BLOCKSIZE];
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500211 const char *filename;
212 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500213
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500214#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500215 printf(" ==> tar_extract_regfile(realname=\"%s\")\n", realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500216#endif
217
218 if (!TH_ISREG(t))
219 {
220 errno = EINVAL;
221 return -1;
222 }
223
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500224 pn = th_get_pathname(t);
225 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500226 size = th_get_size(t);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500227
228 if (mkdirhier(dirname(filename)) == -1)
229 return -1;
230
Ethan Yonker58f21322018-08-24 11:17:36 -0500231 printf(" ==> extracting: %s (file size %" PRId64 " bytes)\n",
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500232 filename, size);
233
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500234 fdout = open(filename, O_WRONLY | O_CREAT | O_TRUNC
235#ifdef O_BINARY
236 | O_BINARY
237#endif
238 , 0666);
239 if (fdout == -1)
240 {
241#ifdef DEBUG
242 perror("open()");
243#endif
244 return -1;
245 }
246
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500247 /* extract the file */
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500248 for (i = size; i > 0; i -= T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500249 {
250 k = tar_block_read(t, buf);
251 if (k != T_BLOCKSIZE)
252 {
253 if (k != -1)
254 errno = EINVAL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500255 close(fdout);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500256 return -1;
257 }
258
259 /* write block to output file */
260 if (write(fdout, buf,
261 ((i > T_BLOCKSIZE) ? T_BLOCKSIZE : i)) == -1)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500262 {
263 close(fdout);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500264 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500265 }
Ethan Yonker472f5062016-02-25 13:47:30 -0600266 else
267 {
268 if (*progress_fd != 0)
269 write(*progress_fd, &progress_size, sizeof(progress_size));
270 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500271 }
272
273 /* close output file */
274 if (close(fdout) == -1)
275 return -1;
276
277#ifdef DEBUG
278 printf("### done extracting %s\n", filename);
279#endif
280
281 return 0;
282}
283
284
285/* skip regfile */
286int
287tar_skip_regfile(TAR *t)
288{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500289 int64_t size, i;
290 ssize_t k;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500291 char buf[T_BLOCKSIZE];
292
293 if (!TH_ISREG(t))
294 {
295 errno = EINVAL;
296 return -1;
297 }
298
299 size = th_get_size(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500300 for (i = size; i > 0; i -= T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500301 {
302 k = tar_block_read(t, buf);
303 if (k != T_BLOCKSIZE)
304 {
305 if (k != -1)
306 errno = EINVAL;
307 return -1;
308 }
309 }
310
311 return 0;
312}
313
314
315/* hardlink */
316int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500317tar_extract_hardlink(TAR * t, const char *realname, const char *prefix)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500318{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500319 const char *filename;
320 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500321 char *linktgt = NULL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500322 char *newtgt = NULL;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500323 char *lnp;
324 libtar_hashptr_t hp;
325
326 if (!TH_ISLNK(t))
327 {
328 errno = EINVAL;
329 return -1;
330 }
331
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500332 pn = th_get_pathname(t);
333 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500334 if (mkdirhier(dirname(filename)) == -1)
335 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500336 if (unlink(filename) == -1 && errno != ENOENT)
337 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500338 libtar_hashptr_reset(&hp);
339 if (libtar_hash_getkey(t->h, &hp, th_get_linkname(t),
340 (libtar_matchfunc_t)libtar_str_match) != 0)
341 {
342 lnp = (char *)libtar_hashptr_data(&hp);
343 linktgt = &lnp[strlen(lnp) + 1];
344 }
345 else
346 linktgt = th_get_linkname(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500347
348 newtgt = strdup(linktgt);
Dees_Troyee6632c2013-02-27 18:07:32 +0000349 sprintf(linktgt, "%s/%s", prefix, newtgt);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500350
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500351 printf(" ==> extracting: %s (link to %s)\n", filename, linktgt);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500352
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500353 if (link(linktgt, filename) == -1)
354 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500355 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 +0000356 return 0; // Used to be -1
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500357 }
358
359 return 0;
360}
361
362
363/* symlink */
364int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500365tar_extract_symlink(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500366{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500367 const char *filename;
368 char *pn;
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500369
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500370 if (!TH_ISSYM(t))
371 {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500372 errno = EINVAL;
373 return -1;
374 }
375
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500376 pn = th_get_pathname(t);
377 filename = (realname ? realname : pn);
378 if (mkdirhier(dirname(filename)) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500379 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500380
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500381 if (unlink(filename) == -1 && errno != ENOENT)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500382 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500383
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500384 printf(" ==> extracting: %s (symlink to %s)\n",
385 filename, th_get_linkname(t));
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500386
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500387 if (symlink(th_get_linkname(t), filename) == -1)
388 {
389#ifdef DEBUG
390 perror("symlink()");
391#endif
392 return -1;
393 }
394
395 return 0;
396}
397
398
399/* character device */
400int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500401tar_extract_chardev(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500402{
403 mode_t mode;
404 unsigned long devmaj, devmin;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500405 const char *filename;
406 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500407
408 if (!TH_ISCHR(t))
409 {
410 errno = EINVAL;
411 return -1;
412 }
413
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500414 pn = th_get_pathname(t);
415 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500416 mode = th_get_mode(t);
417 devmaj = th_get_devmajor(t);
418 devmin = th_get_devminor(t);
419
420 if (mkdirhier(dirname(filename)) == -1)
421 return -1;
422
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500423 printf(" ==> extracting: %s (character device %ld,%ld)\n",
424 filename, devmaj, devmin);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500425
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500426 if (mknod(filename, mode | S_IFCHR,
427 compat_makedev(devmaj, devmin)) == -1)
428 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500429 fprintf(stderr, "tar_extract_chardev(): failed restore of character device '%s' but returning as if nothing bad happened\n", filename);
430 return 0; // Used to be -1
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500431 }
432
433 return 0;
434}
435
436
437/* block device */
438int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500439tar_extract_blockdev(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500440{
441 mode_t mode;
442 unsigned long devmaj, devmin;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500443 const char *filename;
444 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500445
446 if (!TH_ISBLK(t))
447 {
448 errno = EINVAL;
449 return -1;
450 }
451
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500452 pn = th_get_pathname(t);
453 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500454 mode = th_get_mode(t);
455 devmaj = th_get_devmajor(t);
456 devmin = th_get_devminor(t);
457
458 if (mkdirhier(dirname(filename)) == -1)
459 return -1;
460
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500461 printf(" ==> extracting: %s (block device %ld,%ld)\n",
462 filename, devmaj, devmin);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500463
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500464 if (mknod(filename, mode | S_IFBLK,
465 compat_makedev(devmaj, devmin)) == -1)
466 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500467 fprintf(stderr, "tar_extract_blockdev(): failed restore of block device '%s' but returning as if nothing bad happened\n", filename);
468 return 0; // Used to be -1
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500469 }
470
471 return 0;
472}
473
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500474/* directory */
475int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500476tar_extract_dir(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500477{
478 mode_t mode;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500479 const char *filename;
480 char *pn;
481
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500482 if (!TH_ISDIR(t))
483 {
484 errno = EINVAL;
485 return -1;
486 }
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500487 pn = th_get_pathname(t);
488 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500489 mode = th_get_mode(t);
490
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500491 if (mkdirhier(dirname(filename)) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500492 return -1;
493
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500494 printf(" ==> extracting: %s (mode %04o, directory)\n", filename,
495 mode);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500496
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500497 if (mkdir(filename, mode) == -1)
498 {
499 if (errno == EEXIST)
500 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500501 if (chmod(filename, mode) == -1)
502 {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500503#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500504 perror("chmod()");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500505#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500506 return -1;
507 }
508 else
509 {
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600510#if 1 //def DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500511 puts(" *** using existing directory");
512#endif
513 return 1;
514 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500515 }
516 else
517 {
518#ifdef DEBUG
519 perror("mkdir()");
520#endif
521 return -1;
522 }
523 }
524
Ethan Yonker8d039f72017-02-03 14:26:15 -0600525 if (t->options & TAR_STORE_ANDROID_USER_XATTR)
526 {
527 if (t->th_buf.has_user_default) {
528#if 1 //def DEBUG
529 printf("tar_extract_file(): restoring android user.default xattr to %s\n", realname);
530#endif
531 if (setxattr(realname, "user.default", NULL, 0, 0) < 0) {
532 fprintf(stderr, "tar_extract_file(): failed to restore android user.default to file %s !!!\n", realname);
533 return -1;
534 }
535 }
536 if (t->th_buf.has_user_cache) {
537#if 1 //def DEBUG
538 printf("tar_extract_file(): restoring android user.inode_cache xattr to %s\n", realname);
539#endif
540 if (write_path_inode(realname, "cache", "user.inode_cache"))
541 return -1;
542 }
543 if (t->th_buf.has_user_code_cache) {
544#if 1 //def DEBUG
545 printf("tar_extract_file(): restoring android user.inode_code_cache xattr to %s\n", realname);
546#endif
547 if (write_path_inode(realname, "code_cache", "user.inode_code_cache"))
548 return -1;
549 }
550 }
551
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600552#ifdef HAVE_EXT4_CRYPT
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500553 if(t->th_buf.eep != NULL)
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600554 {
555#ifdef DEBUG
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500556 printf("tar_extract_file(): restoring EXT4 crypt policy %s to dir %s\n", t->th_buf.eep->master_key_descriptor, realname);
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600557#endif
558 char binary_policy[EXT4_KEY_DESCRIPTOR_SIZE];
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500559 if (!lookup_ref_tar(t->th_buf.eep->master_key_descriptor, &binary_policy[0])) {
560 printf("error looking up proper e4crypt policy for '%s' - %s\n", realname, t->th_buf.eep->master_key_descriptor);
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600561 return -1;
562 }
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500563 char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600564 policy_to_hex(binary_policy, policy_hex);
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500565 printf("restoring policy %s > '%s' to '%s'\n", t->th_buf.eep->master_key_descriptor, policy_hex, realname);
566 memcpy(&t->th_buf.eep->master_key_descriptor, binary_policy, EXT4_KEY_DESCRIPTOR_SIZE);
567 if (!e4crypt_policy_set_struct(realname, t->th_buf.eep))
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600568 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500569 printf("tar_extract_file(): failed to restore EXT4 crypt policy to dir '%s' '%s'!!!\n", realname, policy_hex);
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600570 //return -1; // This may not be an error in some cases, so log and ignore
571 }
572 }
573#endif
574
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500575 return 0;
576}
577
578
579/* FIFO */
580int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500581tar_extract_fifo(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500582{
583 mode_t mode;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500584 const char *filename;
585 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500586
587 if (!TH_ISFIFO(t))
588 {
589 errno = EINVAL;
590 return -1;
591 }
592
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500593 pn = th_get_pathname(t);
594 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500595 mode = th_get_mode(t);
596
597 if (mkdirhier(dirname(filename)) == -1)
598 return -1;
599
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500600
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500601 printf(" ==> extracting: %s (fifo)\n", filename);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500602
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500603 if (mkfifo(filename, mode) == -1)
604 {
605#ifdef DEBUG
606 perror("mkfifo()");
607#endif
608 return -1;
609 }
610
611 return 0;
612}
613
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500614/* extract file contents from a tarchive */
615int
616tar_extract_file_contents(TAR *t, void *buf, size_t *lenp)
617{
618 char block[T_BLOCKSIZE];
619 int64_t size, i;
620 ssize_t k;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500621
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500622#ifdef DEBUG
623 printf(" ==> tar_extract_file_contents\n");
624#endif
625
626 if (!TH_ISREG(t))
627 {
628 errno = EINVAL;
629 return -1;
630 }
631
632 size = th_get_size(t);
633 if ((uint64_t)size > *lenp)
634 {
635 errno = ENOSPC;
636 return -1;
637 }
638
639 /* extract the file */
640 for (i = size; i >= T_BLOCKSIZE; i -= T_BLOCKSIZE)
641 {
642 k = tar_block_read(t, buf);
643 if (k != T_BLOCKSIZE)
644 {
645 if (k != -1)
646 errno = EINVAL;
647 return -1;
648 }
649 buf = (char *)buf + T_BLOCKSIZE;
650 }
651 if (i > 0) {
652 k = tar_block_read(t, block);
653 if (k != T_BLOCKSIZE)
654 {
655 if (k != -1)
656 errno = EINVAL;
657 return -1;
658 }
659 memcpy(buf, block, i);
660 }
661 *lenp = (size_t)size;
662
663#ifdef DEBUG
664 printf("### done extracting contents\n");
665#endif
666 return 0;
667}