blob: 08e2914c4712a9910f08910cfa68d8f1b6e747e5 [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
bigbiff7ba75002020-04-11 20:47:09 -040038#ifdef USE_FSCRYPT
39#include "fscrypt_policy.h"
40#endif
41
bigbiffa957f072021-03-07 18:20:29 -050042#ifdef TW_LIBTAR_DEBUG
43#define DEBUG 1
44#endif
45
Ethan Yonker8d039f72017-02-03 14:26:15 -060046#include "android_utils.h"
Ethan Yonker79f88bd2016-12-09 14:52:12 -060047
Ethan Yonker472f5062016-02-25 13:47:30 -060048const unsigned long long progress_size = (unsigned long long)(T_BLOCKSIZE);
49
bigbiff bigbiff9c754052013-01-09 09:09:08 -050050static int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050051tar_set_file_perms(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050052{
53 mode_t mode;
54 uid_t uid;
55 gid_t gid;
56 struct utimbuf ut;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050057 const char *filename;
58 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -050059
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050060 pn = th_get_pathname(t);
61 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -050062 mode = th_get_mode(t);
63 uid = th_get_uid(t);
64 gid = th_get_gid(t);
65 ut.modtime = ut.actime = th_get_mtime(t);
66
Dees_Troy71796592013-03-14 20:16:29 +000067#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050068 printf("tar_set_file_perms(): setting perms: %s (mode %04o, uid %d, gid %d)\n",
69 filename, mode, uid, gid);
Dees_Troy71796592013-03-14 20:16:29 +000070#endif
71
bigbiff bigbiff9c754052013-01-09 09:09:08 -050072 /* change owner/group */
73 if (geteuid() == 0)
74#ifdef HAVE_LCHOWN
75 if (lchown(filename, uid, gid) == -1)
76 {
77# ifdef DEBUG
78 fprintf(stderr, "lchown(\"%s\", %d, %d): %s\n",
79 filename, uid, gid, strerror(errno));
80# endif
81#else /* ! HAVE_LCHOWN */
82 if (!TH_ISSYM(t) && chown(filename, uid, gid) == -1)
83 {
84# ifdef DEBUG
85 fprintf(stderr, "chown(\"%s\", %d, %d): %s\n",
86 filename, uid, gid, strerror(errno));
87# endif
88#endif /* HAVE_LCHOWN */
89 return -1;
90 }
91
92 /* change access/modification time */
93 if (!TH_ISSYM(t) && utime(filename, &ut) == -1)
94 {
95#ifdef DEBUG
96 perror("utime()");
97#endif
98 return -1;
99 }
100
101 /* change permissions */
102 if (!TH_ISSYM(t) && chmod(filename, mode) == -1)
103 {
104#ifdef DEBUG
105 perror("chmod()");
106#endif
107 return -1;
108 }
109
110 return 0;
111}
112
113
114/* switchboard */
115int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500116tar_extract_file(TAR *t, const char *realname, const char *prefix, const int *progress_fd)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500117{
118 int i;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500119#ifdef LIBTAR_FILE_HASH
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500120 char *lnp;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500121 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500122 int pathname_len;
123 int realname_len;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500124#endif
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500125
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500126 if (t->options & TAR_NOOVERWRITE)
127 {
128 struct stat s;
129
130 if (lstat(realname, &s) == 0 || errno != ENOENT)
131 {
132 errno = EEXIST;
133 return -1;
134 }
135 }
136
137 if (TH_ISDIR(t))
138 {
139 i = tar_extract_dir(t, realname);
140 if (i == 1)
141 i = 0;
142 }
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500143 else if (TH_ISLNK(t))
Dees_Troyee6632c2013-02-27 18:07:32 +0000144 i = tar_extract_hardlink(t, realname, prefix);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500145 else if (TH_ISSYM(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500146 i = tar_extract_symlink(t, realname);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500147 else if (TH_ISCHR(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500148 i = tar_extract_chardev(t, realname);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500149 else if (TH_ISBLK(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500150 i = tar_extract_blockdev(t, realname);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500151 else if (TH_ISFIFO(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500152 i = tar_extract_fifo(t, realname);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500153 else /* if (TH_ISREG(t)) */
Ethan Yonker1b7a31b2014-07-03 15:09:22 -0500154 i = tar_extract_regfile(t, realname, progress_fd);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500155
156 if (i != 0) {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500157 fprintf(stderr, "tar_extract_file(): failed to extract %s !!!\n", realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500158 return i;
159 }
160
161 i = tar_set_file_perms(t, realname);
162 if (i != 0) {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500163 fprintf(stderr, "tar_extract_file(): failed to set permissions on %s !!!\n", realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500164 return i;
165 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200166
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200167 if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL)
168 {
169#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500170 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 +0200171#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500172 if (lsetfilecon(realname, t->th_buf.selinux_context) < 0)
173 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 +0200174 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200175
Ethan Yonker71187742017-01-13 13:30:10 -0600176 if((t->options & TAR_STORE_POSIX_CAP) && t->th_buf.has_cap_data)
177 {
178#if 1 //def DEBUG
179 printf("tar_extract_file(): restoring posix capabilities to file %s\n", realname);
180 print_caps(&t->th_buf.cap_data);
181#endif
182 if (setxattr(realname, XATTR_NAME_CAPS, &t->th_buf.cap_data, sizeof(struct vfs_cap_data), 0) < 0)
183 fprintf(stderr, "tar_extract_file(): failed to restore posix capabilities to file %s !!!\n", realname);
184 }
185
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500186#ifdef LIBTAR_FILE_HASH
187 pn = th_get_pathname(t);
188 pathname_len = strlen(pn) + 1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500189 realname_len = strlen(realname) + 1;
190 lnp = (char *)calloc(1, pathname_len + realname_len);
191 if (lnp == NULL)
192 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500193 strcpy(&lnp[0], pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500194 strcpy(&lnp[pathname_len], realname);
195#ifdef DEBUG
196 printf("tar_extract_file(): calling libtar_hash_add(): key=\"%s\", "
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500197 "value=\"%s\"\n", pn, realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500198#endif
199 if (libtar_hash_add(t->h, lnp) != 0)
200 return -1;
201 free(lnp);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500202#endif
203
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500204 return 0;
205}
206
207
208/* extract regular file */
209int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500210tar_extract_regfile(TAR *t, const char *realname, const int *progress_fd)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500211{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500212 int64_t size, i;
213 ssize_t k;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500214 int fdout;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500215 char buf[T_BLOCKSIZE];
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500216 const char *filename;
217 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500218
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500219#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500220 printf(" ==> tar_extract_regfile(realname=\"%s\")\n", realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500221#endif
222
223 if (!TH_ISREG(t))
224 {
225 errno = EINVAL;
226 return -1;
227 }
228
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500229 pn = th_get_pathname(t);
230 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500231 size = th_get_size(t);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500232
233 if (mkdirhier(dirname(filename)) == -1)
234 return -1;
235
Ethan Yonker58f21322018-08-24 11:17:36 -0500236 printf(" ==> extracting: %s (file size %" PRId64 " bytes)\n",
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500237 filename, size);
238
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500239 fdout = open(filename, O_WRONLY | O_CREAT | O_TRUNC
240#ifdef O_BINARY
241 | O_BINARY
242#endif
243 , 0666);
244 if (fdout == -1)
245 {
246#ifdef DEBUG
247 perror("open()");
248#endif
249 return -1;
250 }
251
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500252 /* extract the file */
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500253 for (i = size; i > 0; i -= T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500254 {
255 k = tar_block_read(t, buf);
256 if (k != T_BLOCKSIZE)
257 {
258 if (k != -1)
259 errno = EINVAL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500260 close(fdout);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500261 return -1;
262 }
263
264 /* write block to output file */
265 if (write(fdout, buf,
266 ((i > T_BLOCKSIZE) ? T_BLOCKSIZE : i)) == -1)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500267 {
268 close(fdout);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500269 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500270 }
Ethan Yonker472f5062016-02-25 13:47:30 -0600271 else
272 {
273 if (*progress_fd != 0)
274 write(*progress_fd, &progress_size, sizeof(progress_size));
275 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500276 }
277
278 /* close output file */
279 if (close(fdout) == -1)
280 return -1;
281
282#ifdef DEBUG
283 printf("### done extracting %s\n", filename);
284#endif
285
286 return 0;
287}
288
289
290/* skip regfile */
291int
292tar_skip_regfile(TAR *t)
293{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500294 int64_t size, i;
295 ssize_t k;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500296 char buf[T_BLOCKSIZE];
297
298 if (!TH_ISREG(t))
299 {
300 errno = EINVAL;
301 return -1;
302 }
303
304 size = th_get_size(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500305 for (i = size; i > 0; i -= T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500306 {
307 k = tar_block_read(t, buf);
308 if (k != T_BLOCKSIZE)
309 {
310 if (k != -1)
311 errno = EINVAL;
312 return -1;
313 }
314 }
315
316 return 0;
317}
318
319
320/* hardlink */
321int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500322tar_extract_hardlink(TAR * t, const char *realname, const char *prefix)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500323{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500324 const char *filename;
325 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500326 char *linktgt = NULL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500327 char *newtgt = NULL;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500328 char *lnp;
329 libtar_hashptr_t hp;
330
331 if (!TH_ISLNK(t))
332 {
333 errno = EINVAL;
334 return -1;
335 }
336
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500337 pn = th_get_pathname(t);
338 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500339 if (mkdirhier(dirname(filename)) == -1)
340 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500341 if (unlink(filename) == -1 && errno != ENOENT)
342 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500343 libtar_hashptr_reset(&hp);
344 if (libtar_hash_getkey(t->h, &hp, th_get_linkname(t),
345 (libtar_matchfunc_t)libtar_str_match) != 0)
346 {
347 lnp = (char *)libtar_hashptr_data(&hp);
348 linktgt = &lnp[strlen(lnp) + 1];
349 }
350 else
351 linktgt = th_get_linkname(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500352
353 newtgt = strdup(linktgt);
Dees_Troyee6632c2013-02-27 18:07:32 +0000354 sprintf(linktgt, "%s/%s", prefix, newtgt);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500355
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500356 printf(" ==> extracting: %s (link to %s)\n", filename, linktgt);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500357
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500358 if (link(linktgt, filename) == -1)
359 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500360 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 +0000361 return 0; // Used to be -1
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500362 }
363
364 return 0;
365}
366
367
368/* symlink */
369int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500370tar_extract_symlink(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500371{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500372 const char *filename;
373 char *pn;
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500374
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500375 if (!TH_ISSYM(t))
376 {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500377 errno = EINVAL;
378 return -1;
379 }
380
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500381 pn = th_get_pathname(t);
382 filename = (realname ? realname : pn);
383 if (mkdirhier(dirname(filename)) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500384 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500385
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500386 if (unlink(filename) == -1 && errno != ENOENT)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500387 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500388
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500389 printf(" ==> extracting: %s (symlink to %s)\n",
390 filename, th_get_linkname(t));
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500391
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500392 if (symlink(th_get_linkname(t), filename) == -1)
393 {
394#ifdef DEBUG
395 perror("symlink()");
396#endif
397 return -1;
398 }
399
400 return 0;
401}
402
403
404/* character device */
405int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500406tar_extract_chardev(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500407{
408 mode_t mode;
409 unsigned long devmaj, devmin;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500410 const char *filename;
411 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500412
413 if (!TH_ISCHR(t))
414 {
415 errno = EINVAL;
416 return -1;
417 }
418
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500419 pn = th_get_pathname(t);
420 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500421 mode = th_get_mode(t);
422 devmaj = th_get_devmajor(t);
423 devmin = th_get_devminor(t);
424
425 if (mkdirhier(dirname(filename)) == -1)
426 return -1;
427
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500428 printf(" ==> extracting: %s (character device %ld,%ld)\n",
429 filename, devmaj, devmin);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500430
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500431 if (mknod(filename, mode | S_IFCHR,
432 compat_makedev(devmaj, devmin)) == -1)
433 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500434 fprintf(stderr, "tar_extract_chardev(): failed restore of character device '%s' but returning as if nothing bad happened\n", filename);
435 return 0; // Used to be -1
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500436 }
437
438 return 0;
439}
440
441
442/* block device */
443int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500444tar_extract_blockdev(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500445{
446 mode_t mode;
447 unsigned long devmaj, devmin;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500448 const char *filename;
449 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500450
451 if (!TH_ISBLK(t))
452 {
453 errno = EINVAL;
454 return -1;
455 }
456
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500457 pn = th_get_pathname(t);
458 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500459 mode = th_get_mode(t);
460 devmaj = th_get_devmajor(t);
461 devmin = th_get_devminor(t);
462
463 if (mkdirhier(dirname(filename)) == -1)
464 return -1;
465
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500466 printf(" ==> extracting: %s (block device %ld,%ld)\n",
467 filename, devmaj, devmin);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500468
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500469 if (mknod(filename, mode | S_IFBLK,
470 compat_makedev(devmaj, devmin)) == -1)
471 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500472 fprintf(stderr, "tar_extract_blockdev(): failed restore of block device '%s' but returning as if nothing bad happened\n", filename);
473 return 0; // Used to be -1
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500474 }
475
476 return 0;
477}
478
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500479/* directory */
480int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500481tar_extract_dir(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500482{
483 mode_t mode;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500484 const char *filename;
485 char *pn;
486
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500487 if (!TH_ISDIR(t))
488 {
489 errno = EINVAL;
490 return -1;
491 }
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500492 pn = th_get_pathname(t);
493 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500494 mode = th_get_mode(t);
495
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500496 if (mkdirhier(dirname(filename)) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500497 return -1;
498
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500499 printf(" ==> extracting: %s (mode %04o, directory)\n", filename,
500 mode);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500501
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500502 if (mkdir(filename, mode) == -1)
503 {
504 if (errno == EEXIST)
505 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500506 if (chmod(filename, mode) == -1)
507 {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500508#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500509 perror("chmod()");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500510#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500511 return -1;
512 }
513 else
514 {
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600515#if 1 //def DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500516 puts(" *** using existing directory");
517#endif
518 return 1;
519 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500520 }
521 else
522 {
523#ifdef DEBUG
524 perror("mkdir()");
525#endif
526 return -1;
527 }
528 }
529
Ethan Yonker8d039f72017-02-03 14:26:15 -0600530 if (t->options & TAR_STORE_ANDROID_USER_XATTR)
531 {
532 if (t->th_buf.has_user_default) {
533#if 1 //def DEBUG
534 printf("tar_extract_file(): restoring android user.default xattr to %s\n", realname);
535#endif
536 if (setxattr(realname, "user.default", NULL, 0, 0) < 0) {
537 fprintf(stderr, "tar_extract_file(): failed to restore android user.default to file %s !!!\n", realname);
538 return -1;
539 }
540 }
541 if (t->th_buf.has_user_cache) {
542#if 1 //def DEBUG
543 printf("tar_extract_file(): restoring android user.inode_cache xattr to %s\n", realname);
544#endif
545 if (write_path_inode(realname, "cache", "user.inode_cache"))
546 return -1;
547 }
548 if (t->th_buf.has_user_code_cache) {
549#if 1 //def DEBUG
550 printf("tar_extract_file(): restoring android user.inode_code_cache xattr to %s\n", realname);
551#endif
552 if (write_path_inode(realname, "code_cache", "user.inode_code_cache"))
553 return -1;
554 }
555 }
556
bigbiff7ba75002020-04-11 20:47:09 -0400557#ifdef USE_FSCRYPT
558 if(t->th_buf.fep != NULL)
559 {
bigbiff2e344ab2021-05-07 10:41:55 -0400560#ifdef USE_FSCRYPT_POLICY_V1
561 char policy_hex[FS_KEY_DESCRIPTOR_SIZE_HEX];
562#else
563 char policy_hex[FSCRYPT_KEY_IDENTIFIER_HEX_SIZE];
564#endif
bigbiff7ba75002020-04-11 20:47:09 -0400565#ifdef DEBUG
bigbiff2e344ab2021-05-07 10:41:55 -0400566#ifdef USE_FSCRYPT_POLICY_V1
567 bytes_to_hex(t->th_buf.fep->master_key_descriptor, FS_KEY_DESCRIPTOR_SIZE, policy_hex);
568#else
bigbiffa957f072021-03-07 18:20:29 -0500569 bytes_to_hex(t->th_buf.fep->master_key_identifier, FSCRYPT_KEY_IDENTIFIER_SIZE, policy_hex);
bigbiff2e344ab2021-05-07 10:41:55 -0400570#endif
bigbiffa957f072021-03-07 18:20:29 -0500571 printf("tar_extract_dir(): restoring fscrypt policy %s to dir %s\n", (char *)policy_hex, realname);
bigbiff7ba75002020-04-11 20:47:09 -0400572#endif
bigbiffcefb0de2021-08-15 18:52:04 -0400573 bool policy_lookup_error = false;
bigbiff2e344ab2021-05-07 10:41:55 -0400574#ifdef USE_FSCRYPT_POLICY_V1
575 uint8_t binary_policy[FS_KEY_DESCRIPTOR_SIZE];
576 memset(&binary_policy, 0, FS_KEY_DESCRIPTOR_SIZE);
577#else
bigbiffa957f072021-03-07 18:20:29 -0500578 uint8_t binary_policy[FSCRYPT_KEY_IDENTIFIER_SIZE];
579 memset(&binary_policy, 0, FSCRYPT_KEY_IDENTIFIER_SIZE);
bigbiff2e344ab2021-05-07 10:41:55 -0400580#endif
bigbiffa957f072021-03-07 18:20:29 -0500581
bigbiff2e344ab2021-05-07 10:41:55 -0400582#ifdef USE_FSCRYPT_POLICY_V1
583 if (!lookup_ref_tar(t->th_buf.fep->master_key_descriptor, &binary_policy[0])) {
584 printf("error looking up fscrypt policy for '%s' - %s\n", realname, t->th_buf.fep->master_key_descriptor);
bigbiffcefb0de2021-08-15 18:52:04 -0400585 policy_lookup_error = true;
bigbiff2e344ab2021-05-07 10:41:55 -0400586 }
587 memcpy(&t->th_buf.fep->master_key_descriptor, binary_policy, FS_KEY_DESCRIPTOR_SIZE);
588 bytes_to_hex(t->th_buf.fep->master_key_descriptor, FS_KEY_DESCRIPTOR_SIZE, policy_hex);
589#else
bigbiffa957f072021-03-07 18:20:29 -0500590 if (!lookup_ref_tar(t->th_buf.fep->master_key_identifier, &binary_policy[0])) {
591 printf("error looking up fscrypt policy for '%s' - %s\n", realname, t->th_buf.fep->master_key_identifier);
bigbiffcefb0de2021-08-15 18:52:04 -0400592 policy_lookup_error = true;
bigbiff7ba75002020-04-11 20:47:09 -0400593 }
bigbiffa957f072021-03-07 18:20:29 -0500594 memcpy(&t->th_buf.fep->master_key_identifier, binary_policy, FSCRYPT_KEY_IDENTIFIER_SIZE);
595 bytes_to_hex(t->th_buf.fep->master_key_identifier, FSCRYPT_KEY_IDENTIFIER_SIZE, policy_hex);
bigbiff2e344ab2021-05-07 10:41:55 -0400596#endif
bigbiffcefb0de2021-08-15 18:52:04 -0400597 if (!policy_lookup_error)
bigbiff7ba75002020-04-11 20:47:09 -0400598 {
bigbiffcefb0de2021-08-15 18:52:04 -0400599 printf("attempting to restore policy: %s\n", policy_hex);
600 if (!fscrypt_policy_set_struct(realname, t->th_buf.fep))
601 {
602 printf("tar_extract_file(): failed to restore fscrypt policy to dir '%s' '%s'!!!\n", realname, policy_hex);
603 //return -1; // This may not be an error in some cases, so log and ignore
604 }
605 } else
606 printf("No policy was found. Continuing restore.");
bigbiff7ba75002020-04-11 20:47:09 -0400607 }
608 else
609 printf("NULL FSCRYPT\n");
610#endif
611
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500612 return 0;
613}
614
615
616/* FIFO */
617int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500618tar_extract_fifo(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500619{
620 mode_t mode;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500621 const char *filename;
622 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500623
624 if (!TH_ISFIFO(t))
625 {
626 errno = EINVAL;
627 return -1;
628 }
629
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500630 pn = th_get_pathname(t);
631 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500632 mode = th_get_mode(t);
633
634 if (mkdirhier(dirname(filename)) == -1)
635 return -1;
636
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500637
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500638 printf(" ==> extracting: %s (fifo)\n", filename);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500639
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500640 if (mkfifo(filename, mode) == -1)
641 {
642#ifdef DEBUG
643 perror("mkfifo()");
644#endif
645 return -1;
646 }
647
648 return 0;
649}
650
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500651/* extract file contents from a tarchive */
652int
653tar_extract_file_contents(TAR *t, void *buf, size_t *lenp)
654{
655 char block[T_BLOCKSIZE];
656 int64_t size, i;
657 ssize_t k;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500658
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500659#ifdef DEBUG
660 printf(" ==> tar_extract_file_contents\n");
661#endif
662
663 if (!TH_ISREG(t))
664 {
665 errno = EINVAL;
666 return -1;
667 }
668
669 size = th_get_size(t);
670 if ((uint64_t)size > *lenp)
671 {
672 errno = ENOSPC;
673 return -1;
674 }
675
676 /* extract the file */
677 for (i = size; i >= T_BLOCKSIZE; i -= T_BLOCKSIZE)
678 {
679 k = tar_block_read(t, buf);
680 if (k != T_BLOCKSIZE)
681 {
682 if (k != -1)
683 errno = EINVAL;
684 return -1;
685 }
686 buf = (char *)buf + T_BLOCKSIZE;
687 }
688 if (i > 0) {
689 k = tar_block_read(t, block);
690 if (k != T_BLOCKSIZE)
691 {
692 if (k != -1)
693 errno = EINVAL;
694 return -1;
695 }
696 memcpy(buf, block, i);
697 }
698 *lenp = (size_t)size;
699
700#ifdef DEBUG
701 printf("### done extracting contents\n");
702#endif
703 return 0;
704}