blob: 257e140d566c1115acff84d511e27ac429221c65 [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
bigbiff bigbiff9c754052013-01-09 09:09:08 -050023#ifdef STDC_HEADERS
24# include <stdlib.h>
25#endif
26
27#ifdef HAVE_UNISTD_H
28# include <unistd.h>
29#endif
30
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050031#ifdef HAVE_SELINUX
32# include "selinux/selinux.h"
33#endif
bigbiff bigbiff9c754052013-01-09 09:09:08 -050034
35static int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050036tar_set_file_perms(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050037{
38 mode_t mode;
39 uid_t uid;
40 gid_t gid;
41 struct utimbuf ut;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050042 const char *filename;
43 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -050044
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050045 pn = th_get_pathname(t);
46 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -050047 mode = th_get_mode(t);
48 uid = th_get_uid(t);
49 gid = th_get_gid(t);
50 ut.modtime = ut.actime = th_get_mtime(t);
51
Dees_Troy71796592013-03-14 20:16:29 +000052#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050053 printf("tar_set_file_perms(): setting perms: %s (mode %04o, uid %d, gid %d)\n",
54 filename, mode, uid, gid);
Dees_Troy71796592013-03-14 20:16:29 +000055#endif
56
bigbiff bigbiff9c754052013-01-09 09:09:08 -050057 /* change owner/group */
58 if (geteuid() == 0)
59#ifdef HAVE_LCHOWN
60 if (lchown(filename, uid, gid) == -1)
61 {
62# ifdef DEBUG
63 fprintf(stderr, "lchown(\"%s\", %d, %d): %s\n",
64 filename, uid, gid, strerror(errno));
65# endif
66#else /* ! HAVE_LCHOWN */
67 if (!TH_ISSYM(t) && chown(filename, uid, gid) == -1)
68 {
69# ifdef DEBUG
70 fprintf(stderr, "chown(\"%s\", %d, %d): %s\n",
71 filename, uid, gid, strerror(errno));
72# endif
73#endif /* HAVE_LCHOWN */
74 return -1;
75 }
76
77 /* change access/modification time */
78 if (!TH_ISSYM(t) && utime(filename, &ut) == -1)
79 {
80#ifdef DEBUG
81 perror("utime()");
82#endif
83 return -1;
84 }
85
86 /* change permissions */
87 if (!TH_ISSYM(t) && chmod(filename, mode) == -1)
88 {
89#ifdef DEBUG
90 perror("chmod()");
91#endif
92 return -1;
93 }
94
95 return 0;
96}
97
98
99/* switchboard */
100int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500101tar_extract_file(TAR *t, const char *realname, const char *prefix, const int *progress_fd)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500102{
103 int i;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500104#ifdef LIBTAR_FILE_HASH
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500105 char *lnp;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500106 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500107 int pathname_len;
108 int realname_len;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500109#endif
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500110
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500111 if (t->options & TAR_NOOVERWRITE)
112 {
113 struct stat s;
114
115 if (lstat(realname, &s) == 0 || errno != ENOENT)
116 {
117 errno = EEXIST;
118 return -1;
119 }
120 }
121
122 if (TH_ISDIR(t))
123 {
124 i = tar_extract_dir(t, realname);
125 if (i == 1)
126 i = 0;
127 }
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500128 else if (TH_ISLNK(t))
Dees_Troyee6632c2013-02-27 18:07:32 +0000129 i = tar_extract_hardlink(t, realname, prefix);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500130 else if (TH_ISSYM(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500131 i = tar_extract_symlink(t, realname);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500132 else if (TH_ISCHR(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500133 i = tar_extract_chardev(t, realname);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500134 else if (TH_ISBLK(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500135 i = tar_extract_blockdev(t, realname);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500136 else if (TH_ISFIFO(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500137 i = tar_extract_fifo(t, realname);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500138 else /* if (TH_ISREG(t)) */
Ethan Yonker1b7a31b2014-07-03 15:09:22 -0500139 i = tar_extract_regfile(t, realname, progress_fd);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500140
141 if (i != 0) {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500142 fprintf(stderr, "tar_extract_file(): failed to extract %s !!!\n", realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500143 return i;
144 }
145
146 i = tar_set_file_perms(t, realname);
147 if (i != 0) {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500148 fprintf(stderr, "tar_extract_file(): failed to set permissions on %s !!!\n", realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500149 return i;
150 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200151
152#ifdef HAVE_SELINUX
153 if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL)
154 {
155#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500156 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 +0200157#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500158 if (lsetfilecon(realname, t->th_buf.selinux_context) < 0)
159 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 +0200160 }
161#endif
162
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500163#ifdef LIBTAR_FILE_HASH
164 pn = th_get_pathname(t);
165 pathname_len = strlen(pn) + 1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500166 realname_len = strlen(realname) + 1;
167 lnp = (char *)calloc(1, pathname_len + realname_len);
168 if (lnp == NULL)
169 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500170 strcpy(&lnp[0], pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500171 strcpy(&lnp[pathname_len], realname);
172#ifdef DEBUG
173 printf("tar_extract_file(): calling libtar_hash_add(): key=\"%s\", "
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500174 "value=\"%s\"\n", pn, realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500175#endif
176 if (libtar_hash_add(t->h, lnp) != 0)
177 return -1;
178 free(lnp);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500179#endif
180
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500181 return 0;
182}
183
184
185/* extract regular file */
186int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500187tar_extract_regfile(TAR *t, const char *realname, const int *progress_fd)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500188{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500189 int64_t size, i;
190 ssize_t k;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500191 int fdout;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500192 char buf[T_BLOCKSIZE];
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500193 const char *filename;
194 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500195
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500196#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500197 printf(" ==> tar_extract_regfile(realname=\"%s\")\n", realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500198#endif
199
200 if (!TH_ISREG(t))
201 {
202 errno = EINVAL;
203 return -1;
204 }
205
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500206 pn = th_get_pathname(t);
207 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500208 size = th_get_size(t);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500209
210 if (mkdirhier(dirname(filename)) == -1)
211 return -1;
212
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500213 printf(" ==> extracting: %s (file size %lld bytes)\n",
214 filename, size);
215
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500216 fdout = open(filename, O_WRONLY | O_CREAT | O_TRUNC
217#ifdef O_BINARY
218 | O_BINARY
219#endif
220 , 0666);
221 if (fdout == -1)
222 {
223#ifdef DEBUG
224 perror("open()");
225#endif
226 return -1;
227 }
228
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500229 /* extract the file */
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500230 for (i = size; i > 0; i -= T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500231 {
232 k = tar_block_read(t, buf);
233 if (k != T_BLOCKSIZE)
234 {
235 if (k != -1)
236 errno = EINVAL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500237 close(fdout);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500238 return -1;
239 }
240
241 /* write block to output file */
242 if (write(fdout, buf,
243 ((i > T_BLOCKSIZE) ? T_BLOCKSIZE : i)) == -1)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500244 {
245 close(fdout);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500246 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500247 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500248 }
249
250 /* close output file */
251 if (close(fdout) == -1)
252 return -1;
253
254#ifdef DEBUG
255 printf("### done extracting %s\n", filename);
256#endif
257
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500258 if (*progress_fd != 0)
259 {
Ethan Yonker1b7a31b2014-07-03 15:09:22 -0500260 unsigned long long file_size = (unsigned long long)(size);
261 write(*progress_fd, &file_size, sizeof(file_size));
262 }
263
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500264 return 0;
265}
266
267
268/* skip regfile */
269int
270tar_skip_regfile(TAR *t)
271{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500272 int64_t size, i;
273 ssize_t k;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500274 char buf[T_BLOCKSIZE];
275
276 if (!TH_ISREG(t))
277 {
278 errno = EINVAL;
279 return -1;
280 }
281
282 size = th_get_size(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500283 for (i = size; i > 0; i -= T_BLOCKSIZE)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500284 {
285 k = tar_block_read(t, buf);
286 if (k != T_BLOCKSIZE)
287 {
288 if (k != -1)
289 errno = EINVAL;
290 return -1;
291 }
292 }
293
294 return 0;
295}
296
297
298/* hardlink */
299int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500300tar_extract_hardlink(TAR * t, const char *realname, const char *prefix)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500301{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500302 const char *filename;
303 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500304 char *linktgt = NULL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500305 char *newtgt = NULL;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500306 char *lnp;
307 libtar_hashptr_t hp;
308
309 if (!TH_ISLNK(t))
310 {
311 errno = EINVAL;
312 return -1;
313 }
314
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500315 pn = th_get_pathname(t);
316 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500317 if (mkdirhier(dirname(filename)) == -1)
318 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500319 if (unlink(filename) == -1 && errno != ENOENT)
320 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500321 libtar_hashptr_reset(&hp);
322 if (libtar_hash_getkey(t->h, &hp, th_get_linkname(t),
323 (libtar_matchfunc_t)libtar_str_match) != 0)
324 {
325 lnp = (char *)libtar_hashptr_data(&hp);
326 linktgt = &lnp[strlen(lnp) + 1];
327 }
328 else
329 linktgt = th_get_linkname(t);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500330
331 newtgt = strdup(linktgt);
Dees_Troyee6632c2013-02-27 18:07:32 +0000332 sprintf(linktgt, "%s/%s", prefix, newtgt);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500333
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500334 printf(" ==> extracting: %s (link to %s)\n", filename, linktgt);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500335
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500336 if (link(linktgt, filename) == -1)
337 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500338 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 +0000339 return 0; // Used to be -1
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500340 }
341
342 return 0;
343}
344
345
346/* symlink */
347int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500348tar_extract_symlink(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500349{
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500350 const char *filename;
351 char *pn;
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500352
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500353 if (!TH_ISSYM(t))
354 {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500355 errno = EINVAL;
356 return -1;
357 }
358
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500359 pn = th_get_pathname(t);
360 filename = (realname ? realname : pn);
361 if (mkdirhier(dirname(filename)) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500362 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500363
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500364 if (unlink(filename) == -1 && errno != ENOENT)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500365 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500366
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500367 printf(" ==> extracting: %s (symlink to %s)\n",
368 filename, th_get_linkname(t));
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500369
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500370 if (symlink(th_get_linkname(t), filename) == -1)
371 {
372#ifdef DEBUG
373 perror("symlink()");
374#endif
375 return -1;
376 }
377
378 return 0;
379}
380
381
382/* character device */
383int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500384tar_extract_chardev(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500385{
386 mode_t mode;
387 unsigned long devmaj, devmin;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500388 const char *filename;
389 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500390
391 if (!TH_ISCHR(t))
392 {
393 errno = EINVAL;
394 return -1;
395 }
396
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500397 pn = th_get_pathname(t);
398 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500399 mode = th_get_mode(t);
400 devmaj = th_get_devmajor(t);
401 devmin = th_get_devminor(t);
402
403 if (mkdirhier(dirname(filename)) == -1)
404 return -1;
405
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500406 printf(" ==> extracting: %s (character device %ld,%ld)\n",
407 filename, devmaj, devmin);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500408
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500409 if (mknod(filename, mode | S_IFCHR,
410 compat_makedev(devmaj, devmin)) == -1)
411 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500412 fprintf(stderr, "tar_extract_chardev(): failed restore of character device '%s' but returning as if nothing bad happened\n", filename);
413 return 0; // Used to be -1
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500414 }
415
416 return 0;
417}
418
419
420/* block device */
421int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500422tar_extract_blockdev(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500423{
424 mode_t mode;
425 unsigned long devmaj, devmin;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500426 const char *filename;
427 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500428
429 if (!TH_ISBLK(t))
430 {
431 errno = EINVAL;
432 return -1;
433 }
434
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500435 pn = th_get_pathname(t);
436 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500437 mode = th_get_mode(t);
438 devmaj = th_get_devmajor(t);
439 devmin = th_get_devminor(t);
440
441 if (mkdirhier(dirname(filename)) == -1)
442 return -1;
443
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500444 printf(" ==> extracting: %s (block device %ld,%ld)\n",
445 filename, devmaj, devmin);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500446
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500447 if (mknod(filename, mode | S_IFBLK,
448 compat_makedev(devmaj, devmin)) == -1)
449 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500450 fprintf(stderr, "tar_extract_blockdev(): failed restore of block device '%s' but returning as if nothing bad happened\n", filename);
451 return 0; // Used to be -1
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500452 }
453
454 return 0;
455}
456
457
458/* directory */
459int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500460tar_extract_dir(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500461{
462 mode_t mode;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500463 const char *filename;
464 char *pn;
465
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500466 if (!TH_ISDIR(t))
467 {
468 errno = EINVAL;
469 return -1;
470 }
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500471 pn = th_get_pathname(t);
472 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500473 mode = th_get_mode(t);
474
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500475 if (mkdirhier(dirname(filename)) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500476 return -1;
477
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500478 printf(" ==> extracting: %s (mode %04o, directory)\n", filename,
479 mode);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500480
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500481 if (mkdir(filename, mode) == -1)
482 {
483 if (errno == EEXIST)
484 {
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500485 if (chmod(filename, mode) == -1)
486 {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500487#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500488 perror("chmod()");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500489#endif
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500490 return -1;
491 }
492 else
493 {
494#ifdef DEBUG
495 puts(" *** using existing directory");
496#endif
497 return 1;
498 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500499 }
500 else
501 {
502#ifdef DEBUG
503 perror("mkdir()");
504#endif
505 return -1;
506 }
507 }
508
509 return 0;
510}
511
512
513/* FIFO */
514int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500515tar_extract_fifo(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500516{
517 mode_t mode;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500518 const char *filename;
519 char *pn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500520
521 if (!TH_ISFIFO(t))
522 {
523 errno = EINVAL;
524 return -1;
525 }
526
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500527 pn = th_get_pathname(t);
528 filename = (realname ? realname : pn);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500529 mode = th_get_mode(t);
530
531 if (mkdirhier(dirname(filename)) == -1)
532 return -1;
533
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500534
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500535 printf(" ==> extracting: %s (fifo)\n", filename);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500536
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500537 if (mkfifo(filename, mode) == -1)
538 {
539#ifdef DEBUG
540 perror("mkfifo()");
541#endif
542 return -1;
543 }
544
545 return 0;
546}
547
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500548/* extract file contents from a tarchive */
549int
550tar_extract_file_contents(TAR *t, void *buf, size_t *lenp)
551{
552 char block[T_BLOCKSIZE];
553 int64_t size, i;
554 ssize_t k;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500555
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500556#ifdef DEBUG
557 printf(" ==> tar_extract_file_contents\n");
558#endif
559
560 if (!TH_ISREG(t))
561 {
562 errno = EINVAL;
563 return -1;
564 }
565
566 size = th_get_size(t);
567 if ((uint64_t)size > *lenp)
568 {
569 errno = ENOSPC;
570 return -1;
571 }
572
573 /* extract the file */
574 for (i = size; i >= T_BLOCKSIZE; i -= T_BLOCKSIZE)
575 {
576 k = tar_block_read(t, buf);
577 if (k != T_BLOCKSIZE)
578 {
579 if (k != -1)
580 errno = EINVAL;
581 return -1;
582 }
583 buf = (char *)buf + T_BLOCKSIZE;
584 }
585 if (i > 0) {
586 k = tar_block_read(t, block);
587 if (k != T_BLOCKSIZE)
588 {
589 if (k != -1)
590 errno = EINVAL;
591 return -1;
592 }
593 memcpy(buf, block, i);
594 }
595 *lenp = (size_t)size;
596
597#ifdef DEBUG
598 printf("### done extracting contents\n");
599#endif
600 return 0;
601}