blob: 87ccf245f0604f18918b531557c0c70404c41701 [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
40
Ethan Yonker472f5062016-02-25 13:47:30 -060041const unsigned long long progress_size = (unsigned long long)(T_BLOCKSIZE);
42
bigbiff bigbiff9c754052013-01-09 09:09:08 -050043static int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050044tar_set_file_perms(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050045{
46 mode_t mode;
47 uid_t uid;
48 gid_t gid;
49 struct utimbuf ut;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050050 const char *filename;
51 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -050052
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050053 pn = th_get_pathname(t);
54 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -050055 mode = th_get_mode(t);
56 uid = th_get_uid(t);
57 gid = th_get_gid(t);
58 ut.modtime = ut.actime = th_get_mtime(t);
59
Dees_Troy71796592013-03-14 20:16:29 +000060#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050061 printf("tar_set_file_perms(): setting perms: %s (mode %04o, uid %d, gid %d)\n",
62 filename, mode, uid, gid);
Dees_Troy71796592013-03-14 20:16:29 +000063#endif
64
bigbiff bigbiff9c754052013-01-09 09:09:08 -050065 /* change owner/group */
66 if (geteuid() == 0)
67#ifdef HAVE_LCHOWN
68 if (lchown(filename, uid, gid) == -1)
69 {
70# ifdef DEBUG
71 fprintf(stderr, "lchown(\"%s\", %d, %d): %s\n",
72 filename, uid, gid, strerror(errno));
73# endif
74#else /* ! HAVE_LCHOWN */
75 if (!TH_ISSYM(t) && chown(filename, uid, gid) == -1)
76 {
77# ifdef DEBUG
78 fprintf(stderr, "chown(\"%s\", %d, %d): %s\n",
79 filename, uid, gid, strerror(errno));
80# endif
81#endif /* HAVE_LCHOWN */
82 return -1;
83 }
84
85 /* change access/modification time */
86 if (!TH_ISSYM(t) && utime(filename, &ut) == -1)
87 {
88#ifdef DEBUG
89 perror("utime()");
90#endif
91 return -1;
92 }
93
94 /* change permissions */
95 if (!TH_ISSYM(t) && chmod(filename, mode) == -1)
96 {
97#ifdef DEBUG
98 perror("chmod()");
99#endif
100 return -1;
101 }
102
103 return 0;
104}
105
106
107/* switchboard */
108int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500109tar_extract_file(TAR *t, const char *realname, const char *prefix, const int *progress_fd)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500110{
111 int i;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500112#ifdef LIBTAR_FILE_HASH
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500113 char *lnp;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500114 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500115 int pathname_len;
116 int realname_len;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500117#endif
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500118
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500119 if (t->options & TAR_NOOVERWRITE)
120 {
121 struct stat s;
122
123 if (lstat(realname, &s) == 0 || errno != ENOENT)
124 {
125 errno = EEXIST;
126 return -1;
127 }
128 }
129
130 if (TH_ISDIR(t))
131 {
132 i = tar_extract_dir(t, realname);
133 if (i == 1)
134 i = 0;
135 }
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500136 else if (TH_ISLNK(t))
Dees_Troyee6632c2013-02-27 18:07:32 +0000137 i = tar_extract_hardlink(t, realname, prefix);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500138 else if (TH_ISSYM(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500139 i = tar_extract_symlink(t, realname);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500140 else if (TH_ISCHR(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500141 i = tar_extract_chardev(t, realname);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500142 else if (TH_ISBLK(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500143 i = tar_extract_blockdev(t, realname);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500144 else if (TH_ISFIFO(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500145 i = tar_extract_fifo(t, realname);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500146 else /* if (TH_ISREG(t)) */
Ethan Yonker1b7a31b2014-07-03 15:09:22 -0500147 i = tar_extract_regfile(t, realname, progress_fd);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500148
149 if (i != 0) {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500150 fprintf(stderr, "tar_extract_file(): failed to extract %s !!!\n", realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500151 return i;
152 }
153
154 i = tar_set_file_perms(t, realname);
155 if (i != 0) {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500156 fprintf(stderr, "tar_extract_file(): failed to set permissions on %s !!!\n", realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500157 return i;
158 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200159
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200160 if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL)
161 {
162#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500163 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 +0200164#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500165 if (lsetfilecon(realname, t->th_buf.selinux_context) < 0)
166 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 +0200167 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200168
Ethan Yonker71187742017-01-13 13:30:10 -0600169 if((t->options & TAR_STORE_POSIX_CAP) && t->th_buf.has_cap_data)
170 {
171#if 1 //def DEBUG
172 printf("tar_extract_file(): restoring posix capabilities to file %s\n", realname);
173 print_caps(&t->th_buf.cap_data);
174#endif
175 if (setxattr(realname, XATTR_NAME_CAPS, &t->th_buf.cap_data, sizeof(struct vfs_cap_data), 0) < 0)
176 fprintf(stderr, "tar_extract_file(): failed to restore posix capabilities to file %s !!!\n", realname);
177 }
178
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500179#ifdef LIBTAR_FILE_HASH
180 pn = th_get_pathname(t);
181 pathname_len = strlen(pn) + 1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500182 realname_len = strlen(realname) + 1;
183 lnp = (char *)calloc(1, pathname_len + realname_len);
184 if (lnp == NULL)
185 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500186 strcpy(&lnp[0], pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500187 strcpy(&lnp[pathname_len], realname);
188#ifdef DEBUG
189 printf("tar_extract_file(): calling libtar_hash_add(): key=\"%s\", "
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500190 "value=\"%s\"\n", pn, realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500191#endif
192 if (libtar_hash_add(t->h, lnp) != 0)
193 return -1;
194 free(lnp);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500195#endif
196
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500197 return 0;
198}
199
200
201/* extract regular file */
202int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500203tar_extract_regfile(TAR *t, const char *realname, const int *progress_fd)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500204{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500205 int64_t size, i;
206 ssize_t k;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500207 int fdout;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500208 char buf[T_BLOCKSIZE];
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500209 const char *filename;
210 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500211
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500212#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500213 printf(" ==> tar_extract_regfile(realname=\"%s\")\n", realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500214#endif
215
216 if (!TH_ISREG(t))
217 {
218 errno = EINVAL;
219 return -1;
220 }
221
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500222 pn = th_get_pathname(t);
223 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500224 size = th_get_size(t);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500225
226 if (mkdirhier(dirname(filename)) == -1)
227 return -1;
228
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500229 printf(" ==> extracting: %s (file size %lld bytes)\n",
230 filename, size);
231
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500232 fdout = open(filename, O_WRONLY | O_CREAT | O_TRUNC
233#ifdef O_BINARY
234 | O_BINARY
235#endif
236 , 0666);
237 if (fdout == -1)
238 {
239#ifdef DEBUG
240 perror("open()");
241#endif
242 return -1;
243 }
244
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500245 /* extract the file */
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500246 for (i = size; i > 0; i -= T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500247 {
248 k = tar_block_read(t, buf);
249 if (k != T_BLOCKSIZE)
250 {
251 if (k != -1)
252 errno = EINVAL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500253 close(fdout);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500254 return -1;
255 }
256
257 /* write block to output file */
258 if (write(fdout, buf,
259 ((i > T_BLOCKSIZE) ? T_BLOCKSIZE : i)) == -1)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500260 {
261 close(fdout);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500262 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500263 }
Ethan Yonker472f5062016-02-25 13:47:30 -0600264 else
265 {
266 if (*progress_fd != 0)
267 write(*progress_fd, &progress_size, sizeof(progress_size));
268 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500269 }
270
271 /* close output file */
272 if (close(fdout) == -1)
273 return -1;
274
275#ifdef DEBUG
276 printf("### done extracting %s\n", filename);
277#endif
278
279 return 0;
280}
281
282
283/* skip regfile */
284int
285tar_skip_regfile(TAR *t)
286{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500287 int64_t size, i;
288 ssize_t k;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500289 char buf[T_BLOCKSIZE];
290
291 if (!TH_ISREG(t))
292 {
293 errno = EINVAL;
294 return -1;
295 }
296
297 size = th_get_size(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500298 for (i = size; i > 0; i -= T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500299 {
300 k = tar_block_read(t, buf);
301 if (k != T_BLOCKSIZE)
302 {
303 if (k != -1)
304 errno = EINVAL;
305 return -1;
306 }
307 }
308
309 return 0;
310}
311
312
313/* hardlink */
314int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500315tar_extract_hardlink(TAR * t, const char *realname, const char *prefix)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500316{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500317 const char *filename;
318 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500319 char *linktgt = NULL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500320 char *newtgt = NULL;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500321 char *lnp;
322 libtar_hashptr_t hp;
323
324 if (!TH_ISLNK(t))
325 {
326 errno = EINVAL;
327 return -1;
328 }
329
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500330 pn = th_get_pathname(t);
331 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500332 if (mkdirhier(dirname(filename)) == -1)
333 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500334 if (unlink(filename) == -1 && errno != ENOENT)
335 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500336 libtar_hashptr_reset(&hp);
337 if (libtar_hash_getkey(t->h, &hp, th_get_linkname(t),
338 (libtar_matchfunc_t)libtar_str_match) != 0)
339 {
340 lnp = (char *)libtar_hashptr_data(&hp);
341 linktgt = &lnp[strlen(lnp) + 1];
342 }
343 else
344 linktgt = th_get_linkname(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500345
346 newtgt = strdup(linktgt);
Dees_Troyee6632c2013-02-27 18:07:32 +0000347 sprintf(linktgt, "%s/%s", prefix, newtgt);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500348
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500349 printf(" ==> extracting: %s (link to %s)\n", filename, linktgt);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500350
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500351 if (link(linktgt, filename) == -1)
352 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500353 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 +0000354 return 0; // Used to be -1
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500355 }
356
357 return 0;
358}
359
360
361/* symlink */
362int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500363tar_extract_symlink(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500364{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500365 const char *filename;
366 char *pn;
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500367
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500368 if (!TH_ISSYM(t))
369 {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500370 errno = EINVAL;
371 return -1;
372 }
373
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500374 pn = th_get_pathname(t);
375 filename = (realname ? realname : pn);
376 if (mkdirhier(dirname(filename)) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500377 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500378
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500379 if (unlink(filename) == -1 && errno != ENOENT)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500380 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500381
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500382 printf(" ==> extracting: %s (symlink to %s)\n",
383 filename, th_get_linkname(t));
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500384
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500385 if (symlink(th_get_linkname(t), filename) == -1)
386 {
387#ifdef DEBUG
388 perror("symlink()");
389#endif
390 return -1;
391 }
392
393 return 0;
394}
395
396
397/* character device */
398int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500399tar_extract_chardev(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500400{
401 mode_t mode;
402 unsigned long devmaj, devmin;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500403 const char *filename;
404 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500405
406 if (!TH_ISCHR(t))
407 {
408 errno = EINVAL;
409 return -1;
410 }
411
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500412 pn = th_get_pathname(t);
413 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500414 mode = th_get_mode(t);
415 devmaj = th_get_devmajor(t);
416 devmin = th_get_devminor(t);
417
418 if (mkdirhier(dirname(filename)) == -1)
419 return -1;
420
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500421 printf(" ==> extracting: %s (character device %ld,%ld)\n",
422 filename, devmaj, devmin);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500423
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500424 if (mknod(filename, mode | S_IFCHR,
425 compat_makedev(devmaj, devmin)) == -1)
426 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500427 fprintf(stderr, "tar_extract_chardev(): failed restore of character device '%s' but returning as if nothing bad happened\n", filename);
428 return 0; // Used to be -1
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500429 }
430
431 return 0;
432}
433
434
435/* block device */
436int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500437tar_extract_blockdev(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500438{
439 mode_t mode;
440 unsigned long devmaj, devmin;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500441 const char *filename;
442 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500443
444 if (!TH_ISBLK(t))
445 {
446 errno = EINVAL;
447 return -1;
448 }
449
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500450 pn = th_get_pathname(t);
451 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500452 mode = th_get_mode(t);
453 devmaj = th_get_devmajor(t);
454 devmin = th_get_devminor(t);
455
456 if (mkdirhier(dirname(filename)) == -1)
457 return -1;
458
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500459 printf(" ==> extracting: %s (block device %ld,%ld)\n",
460 filename, devmaj, devmin);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500461
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500462 if (mknod(filename, mode | S_IFBLK,
463 compat_makedev(devmaj, devmin)) == -1)
464 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500465 fprintf(stderr, "tar_extract_blockdev(): failed restore of block device '%s' but returning as if nothing bad happened\n", filename);
466 return 0; // Used to be -1
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500467 }
468
469 return 0;
470}
471
472
473/* 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 Yonker79f88bd2016-12-09 14:52:12 -0600524#ifdef HAVE_EXT4_CRYPT
525 if(t->th_buf.e4crypt_policy != NULL)
526 {
527#ifdef DEBUG
528 printf("tar_extract_file(): restoring EXT4 crypt policy %s to dir %s\n", t->th_buf.e4crypt_policy, realname);
529#endif
530 char binary_policy[EXT4_KEY_DESCRIPTOR_SIZE];
531 if (!lookup_ref_tar(t->th_buf.e4crypt_policy, &binary_policy)) {
532 printf("error looking up proper e4crypt policy for '%s' - %s\n", realname, t->th_buf.e4crypt_policy);
533 return -1;
534 }
535 char policy_hex[EXT4_KEY_DESCRIPTOR_HEX];
536 policy_to_hex(binary_policy, policy_hex);
537 printf("restoring policy %s > '%s' to '%s'\n", t->th_buf.e4crypt_policy, policy_hex, realname);
538 if (!e4crypt_policy_set(realname, binary_policy, EXT4_KEY_DESCRIPTOR_SIZE, 0))
539 {
540 printf("tar_extract_file(): failed to restore EXT4 crypt policy %s to dir '%s' '%s'!!!\n", t->th_buf.e4crypt_policy, realname, policy_hex);
541 //return -1; // This may not be an error in some cases, so log and ignore
542 }
543 }
544#endif
545
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500546 return 0;
547}
548
549
550/* FIFO */
551int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500552tar_extract_fifo(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500553{
554 mode_t mode;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500555 const char *filename;
556 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500557
558 if (!TH_ISFIFO(t))
559 {
560 errno = EINVAL;
561 return -1;
562 }
563
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500564 pn = th_get_pathname(t);
565 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500566 mode = th_get_mode(t);
567
568 if (mkdirhier(dirname(filename)) == -1)
569 return -1;
570
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500571
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500572 printf(" ==> extracting: %s (fifo)\n", filename);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500573
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500574 if (mkfifo(filename, mode) == -1)
575 {
576#ifdef DEBUG
577 perror("mkfifo()");
578#endif
579 return -1;
580 }
581
582 return 0;
583}
584
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500585/* extract file contents from a tarchive */
586int
587tar_extract_file_contents(TAR *t, void *buf, size_t *lenp)
588{
589 char block[T_BLOCKSIZE];
590 int64_t size, i;
591 ssize_t k;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500592
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500593#ifdef DEBUG
594 printf(" ==> tar_extract_file_contents\n");
595#endif
596
597 if (!TH_ISREG(t))
598 {
599 errno = EINVAL;
600 return -1;
601 }
602
603 size = th_get_size(t);
604 if ((uint64_t)size > *lenp)
605 {
606 errno = ENOSPC;
607 return -1;
608 }
609
610 /* extract the file */
611 for (i = size; i >= T_BLOCKSIZE; i -= T_BLOCKSIZE)
612 {
613 k = tar_block_read(t, buf);
614 if (k != T_BLOCKSIZE)
615 {
616 if (k != -1)
617 errno = EINVAL;
618 return -1;
619 }
620 buf = (char *)buf + T_BLOCKSIZE;
621 }
622 if (i > 0) {
623 k = tar_block_read(t, block);
624 if (k != T_BLOCKSIZE)
625 {
626 if (k != -1)
627 errno = EINVAL;
628 return -1;
629 }
630 memcpy(buf, block, i);
631 }
632 *lenp = (size_t)size;
633
634#ifdef DEBUG
635 printf("### done extracting contents\n");
636#endif
637 return 0;
638}