blob: 9e24e8ee7106b1bd20dd6e5d0c1f07a3c95644a0 [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
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050035#ifdef HAVE_SELINUX
36# include "selinux/selinux.h"
37#endif
bigbiff bigbiff9c754052013-01-09 09:09:08 -050038
Ethan Yonker79f88bd2016-12-09 14:52:12 -060039#ifdef HAVE_EXT4_CRYPT
40# include "ext4crypt_tar.h"
41#endif
42
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
162#ifdef HAVE_SELINUX
163 if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL)
164 {
165#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500166 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 +0200167#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500168 if (lsetfilecon(realname, t->th_buf.selinux_context) < 0)
169 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 +0200170 }
171#endif
172
Ethan Yonker71187742017-01-13 13:30:10 -0600173 if((t->options & TAR_STORE_POSIX_CAP) && t->th_buf.has_cap_data)
174 {
175#if 1 //def DEBUG
176 printf("tar_extract_file(): restoring posix capabilities to file %s\n", realname);
177 print_caps(&t->th_buf.cap_data);
178#endif
179 if (setxattr(realname, XATTR_NAME_CAPS, &t->th_buf.cap_data, sizeof(struct vfs_cap_data), 0) < 0)
180 fprintf(stderr, "tar_extract_file(): failed to restore posix capabilities to file %s !!!\n", realname);
181 }
182
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500183#ifdef LIBTAR_FILE_HASH
184 pn = th_get_pathname(t);
185 pathname_len = strlen(pn) + 1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500186 realname_len = strlen(realname) + 1;
187 lnp = (char *)calloc(1, pathname_len + realname_len);
188 if (lnp == NULL)
189 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500190 strcpy(&lnp[0], pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500191 strcpy(&lnp[pathname_len], realname);
192#ifdef DEBUG
193 printf("tar_extract_file(): calling libtar_hash_add(): key=\"%s\", "
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500194 "value=\"%s\"\n", pn, realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500195#endif
196 if (libtar_hash_add(t->h, lnp) != 0)
197 return -1;
198 free(lnp);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500199#endif
200
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500201 return 0;
202}
203
204
205/* extract regular file */
206int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500207tar_extract_regfile(TAR *t, const char *realname, const int *progress_fd)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500208{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500209 int64_t size, i;
210 ssize_t k;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500211 int fdout;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500212 char buf[T_BLOCKSIZE];
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500213 const char *filename;
214 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500215
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500216#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500217 printf(" ==> tar_extract_regfile(realname=\"%s\")\n", realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500218#endif
219
220 if (!TH_ISREG(t))
221 {
222 errno = EINVAL;
223 return -1;
224 }
225
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500226 pn = th_get_pathname(t);
227 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500228 size = th_get_size(t);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500229
230 if (mkdirhier(dirname(filename)) == -1)
231 return -1;
232
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500233 printf(" ==> extracting: %s (file size %lld bytes)\n",
234 filename, size);
235
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500236 fdout = open(filename, O_WRONLY | O_CREAT | O_TRUNC
237#ifdef O_BINARY
238 | O_BINARY
239#endif
240 , 0666);
241 if (fdout == -1)
242 {
243#ifdef DEBUG
244 perror("open()");
245#endif
246 return -1;
247 }
248
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500249 /* extract the file */
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500250 for (i = size; i > 0; i -= T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500251 {
252 k = tar_block_read(t, buf);
253 if (k != T_BLOCKSIZE)
254 {
255 if (k != -1)
256 errno = EINVAL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500257 close(fdout);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500258 return -1;
259 }
260
261 /* write block to output file */
262 if (write(fdout, buf,
263 ((i > T_BLOCKSIZE) ? T_BLOCKSIZE : i)) == -1)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500264 {
265 close(fdout);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500266 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500267 }
Ethan Yonker472f5062016-02-25 13:47:30 -0600268 else
269 {
270 if (*progress_fd != 0)
271 write(*progress_fd, &progress_size, sizeof(progress_size));
272 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500273 }
274
275 /* close output file */
276 if (close(fdout) == -1)
277 return -1;
278
279#ifdef DEBUG
280 printf("### done extracting %s\n", filename);
281#endif
282
283 return 0;
284}
285
286
287/* skip regfile */
288int
289tar_skip_regfile(TAR *t)
290{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500291 int64_t size, i;
292 ssize_t k;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500293 char buf[T_BLOCKSIZE];
294
295 if (!TH_ISREG(t))
296 {
297 errno = EINVAL;
298 return -1;
299 }
300
301 size = th_get_size(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500302 for (i = size; i > 0; i -= T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500303 {
304 k = tar_block_read(t, buf);
305 if (k != T_BLOCKSIZE)
306 {
307 if (k != -1)
308 errno = EINVAL;
309 return -1;
310 }
311 }
312
313 return 0;
314}
315
316
317/* hardlink */
318int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500319tar_extract_hardlink(TAR * t, const char *realname, const char *prefix)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500320{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500321 const char *filename;
322 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500323 char *linktgt = NULL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500324 char *newtgt = NULL;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500325 char *lnp;
326 libtar_hashptr_t hp;
327
328 if (!TH_ISLNK(t))
329 {
330 errno = EINVAL;
331 return -1;
332 }
333
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500334 pn = th_get_pathname(t);
335 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500336 if (mkdirhier(dirname(filename)) == -1)
337 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500338 if (unlink(filename) == -1 && errno != ENOENT)
339 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500340 libtar_hashptr_reset(&hp);
341 if (libtar_hash_getkey(t->h, &hp, th_get_linkname(t),
342 (libtar_matchfunc_t)libtar_str_match) != 0)
343 {
344 lnp = (char *)libtar_hashptr_data(&hp);
345 linktgt = &lnp[strlen(lnp) + 1];
346 }
347 else
348 linktgt = th_get_linkname(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500349
350 newtgt = strdup(linktgt);
Dees_Troyee6632c2013-02-27 18:07:32 +0000351 sprintf(linktgt, "%s/%s", prefix, newtgt);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500352
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500353 printf(" ==> extracting: %s (link to %s)\n", filename, linktgt);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500354
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500355 if (link(linktgt, filename) == -1)
356 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500357 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 +0000358 return 0; // Used to be -1
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500359 }
360
361 return 0;
362}
363
364
365/* symlink */
366int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500367tar_extract_symlink(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500368{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500369 const char *filename;
370 char *pn;
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500371
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500372 if (!TH_ISSYM(t))
373 {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500374 errno = EINVAL;
375 return -1;
376 }
377
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500378 pn = th_get_pathname(t);
379 filename = (realname ? realname : pn);
380 if (mkdirhier(dirname(filename)) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500381 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500382
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500383 if (unlink(filename) == -1 && errno != ENOENT)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500384 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500385
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500386 printf(" ==> extracting: %s (symlink to %s)\n",
387 filename, th_get_linkname(t));
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500388
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500389 if (symlink(th_get_linkname(t), filename) == -1)
390 {
391#ifdef DEBUG
392 perror("symlink()");
393#endif
394 return -1;
395 }
396
397 return 0;
398}
399
400
401/* character device */
402int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500403tar_extract_chardev(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500404{
405 mode_t mode;
406 unsigned long devmaj, devmin;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500407 const char *filename;
408 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500409
410 if (!TH_ISCHR(t))
411 {
412 errno = EINVAL;
413 return -1;
414 }
415
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500416 pn = th_get_pathname(t);
417 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500418 mode = th_get_mode(t);
419 devmaj = th_get_devmajor(t);
420 devmin = th_get_devminor(t);
421
422 if (mkdirhier(dirname(filename)) == -1)
423 return -1;
424
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500425 printf(" ==> extracting: %s (character device %ld,%ld)\n",
426 filename, devmaj, devmin);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500427
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500428 if (mknod(filename, mode | S_IFCHR,
429 compat_makedev(devmaj, devmin)) == -1)
430 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500431 fprintf(stderr, "tar_extract_chardev(): failed restore of character device '%s' but returning as if nothing bad happened\n", filename);
432 return 0; // Used to be -1
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500433 }
434
435 return 0;
436}
437
438
439/* block device */
440int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500441tar_extract_blockdev(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500442{
443 mode_t mode;
444 unsigned long devmaj, devmin;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500445 const char *filename;
446 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500447
448 if (!TH_ISBLK(t))
449 {
450 errno = EINVAL;
451 return -1;
452 }
453
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500454 pn = th_get_pathname(t);
455 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500456 mode = th_get_mode(t);
457 devmaj = th_get_devmajor(t);
458 devmin = th_get_devminor(t);
459
460 if (mkdirhier(dirname(filename)) == -1)
461 return -1;
462
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500463 printf(" ==> extracting: %s (block device %ld,%ld)\n",
464 filename, devmaj, devmin);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500465
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500466 if (mknod(filename, mode | S_IFBLK,
467 compat_makedev(devmaj, devmin)) == -1)
468 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500469 fprintf(stderr, "tar_extract_blockdev(): failed restore of block device '%s' but returning as if nothing bad happened\n", filename);
470 return 0; // Used to be -1
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500471 }
472
473 return 0;
474}
475
476
477/* directory */
478int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500479tar_extract_dir(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500480{
481 mode_t mode;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500482 const char *filename;
483 char *pn;
484
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500485 if (!TH_ISDIR(t))
486 {
487 errno = EINVAL;
488 return -1;
489 }
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500490 pn = th_get_pathname(t);
491 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500492 mode = th_get_mode(t);
493
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500494 if (mkdirhier(dirname(filename)) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500495 return -1;
496
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500497 printf(" ==> extracting: %s (mode %04o, directory)\n", filename,
498 mode);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500499
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500500 if (mkdir(filename, mode) == -1)
501 {
502 if (errno == EEXIST)
503 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500504 if (chmod(filename, mode) == -1)
505 {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500506#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500507 perror("chmod()");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500508#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500509 return -1;
510 }
511 else
512 {
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600513#if 1 //def DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500514 puts(" *** using existing directory");
515#endif
516 return 1;
517 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500518 }
519 else
520 {
521#ifdef DEBUG
522 perror("mkdir()");
523#endif
524 return -1;
525 }
526 }
527
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600528#ifdef HAVE_EXT4_CRYPT
529 if(t->th_buf.e4crypt_policy != NULL)
530 {
531#ifdef DEBUG
532 printf("tar_extract_file(): restoring EXT4 crypt policy %s to dir %s\n", t->th_buf.e4crypt_policy, realname);
533#endif
534 char binary_policy[EXT4_KEY_DESCRIPTOR_SIZE];
535 if (!lookup_ref_tar(t->th_buf.e4crypt_policy, &binary_policy)) {
536 printf("error looking up proper e4crypt policy for '%s' - %s\n", realname, t->th_buf.e4crypt_policy);
537 return -1;
538 }
539 char policy_hex[EXT4_KEY_DESCRIPTOR_HEX];
540 policy_to_hex(binary_policy, policy_hex);
541 printf("restoring policy %s > '%s' to '%s'\n", t->th_buf.e4crypt_policy, policy_hex, realname);
542 if (!e4crypt_policy_set(realname, binary_policy, EXT4_KEY_DESCRIPTOR_SIZE, 0))
543 {
544 printf("tar_extract_file(): failed to restore EXT4 crypt policy %s to dir '%s' '%s'!!!\n", t->th_buf.e4crypt_policy, realname, policy_hex);
545 //return -1; // This may not be an error in some cases, so log and ignore
546 }
547 }
548#endif
549
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500550 return 0;
551}
552
553
554/* FIFO */
555int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500556tar_extract_fifo(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500557{
558 mode_t mode;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500559 const char *filename;
560 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500561
562 if (!TH_ISFIFO(t))
563 {
564 errno = EINVAL;
565 return -1;
566 }
567
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500568 pn = th_get_pathname(t);
569 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500570 mode = th_get_mode(t);
571
572 if (mkdirhier(dirname(filename)) == -1)
573 return -1;
574
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500575
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500576 printf(" ==> extracting: %s (fifo)\n", filename);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500577
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500578 if (mkfifo(filename, mode) == -1)
579 {
580#ifdef DEBUG
581 perror("mkfifo()");
582#endif
583 return -1;
584 }
585
586 return 0;
587}
588
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500589/* extract file contents from a tarchive */
590int
591tar_extract_file_contents(TAR *t, void *buf, size_t *lenp)
592{
593 char block[T_BLOCKSIZE];
594 int64_t size, i;
595 ssize_t k;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500596
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500597#ifdef DEBUG
598 printf(" ==> tar_extract_file_contents\n");
599#endif
600
601 if (!TH_ISREG(t))
602 {
603 errno = EINVAL;
604 return -1;
605 }
606
607 size = th_get_size(t);
608 if ((uint64_t)size > *lenp)
609 {
610 errno = ENOSPC;
611 return -1;
612 }
613
614 /* extract the file */
615 for (i = size; i >= T_BLOCKSIZE; i -= T_BLOCKSIZE)
616 {
617 k = tar_block_read(t, buf);
618 if (k != T_BLOCKSIZE)
619 {
620 if (k != -1)
621 errno = EINVAL;
622 return -1;
623 }
624 buf = (char *)buf + T_BLOCKSIZE;
625 }
626 if (i > 0) {
627 k = tar_block_read(t, block);
628 if (k != T_BLOCKSIZE)
629 {
630 if (k != -1)
631 errno = EINVAL;
632 return -1;
633 }
634 memcpy(buf, block, i);
635 }
636 *lenp = (size_t)size;
637
638#ifdef DEBUG
639 printf("### done extracting contents\n");
640#endif
641 return 0;
642}