blob: 8081aa2b904f5afd6e36e3b906466d8638948096 [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>
16#include <sys/param.h>
17#include <sys/types.h>
18#include <fcntl.h>
19#include <errno.h>
20#include <utime.h>
21
22#define DEBUG
23#ifdef STDC_HEADERS
24# include <stdlib.h>
25#endif
26
27#ifdef HAVE_UNISTD_H
28# include <unistd.h>
29#endif
30
31#define DEBUG
32
33static int
34tar_set_file_perms(TAR *t, char *realname)
35{
36 mode_t mode;
37 uid_t uid;
38 gid_t gid;
39 struct utimbuf ut;
40 char *filename;
41
42 filename = (realname ? realname : th_get_pathname(t));
43 mode = th_get_mode(t);
44 uid = th_get_uid(t);
45 gid = th_get_gid(t);
46 ut.modtime = ut.actime = th_get_mtime(t);
47
Dees_Troy71796592013-03-14 20:16:29 +000048#ifdef DEBUG
49 printf(" ==> setting perms: %s (mode %04o, uid %d, gid %d)\n",
50 filename, mode, uid, gid);
51#endif
52
bigbiff bigbiff9c754052013-01-09 09:09:08 -050053 /* change owner/group */
54 if (geteuid() == 0)
55#ifdef HAVE_LCHOWN
56 if (lchown(filename, uid, gid) == -1)
57 {
58# ifdef DEBUG
59 fprintf(stderr, "lchown(\"%s\", %d, %d): %s\n",
60 filename, uid, gid, strerror(errno));
61# endif
62#else /* ! HAVE_LCHOWN */
63 if (!TH_ISSYM(t) && chown(filename, uid, gid) == -1)
64 {
65# ifdef DEBUG
66 fprintf(stderr, "chown(\"%s\", %d, %d): %s\n",
67 filename, uid, gid, strerror(errno));
68# endif
69#endif /* HAVE_LCHOWN */
70 return -1;
71 }
72
73 /* change access/modification time */
74 if (!TH_ISSYM(t) && utime(filename, &ut) == -1)
75 {
76#ifdef DEBUG
77 perror("utime()");
78#endif
79 return -1;
80 }
81
82 /* change permissions */
83 if (!TH_ISSYM(t) && chmod(filename, mode) == -1)
84 {
85#ifdef DEBUG
86 perror("chmod()");
87#endif
88 return -1;
89 }
90
91 return 0;
92}
93
94
95/* switchboard */
96int
Dees_Troyee6632c2013-02-27 18:07:32 +000097tar_extract_file(TAR *t, char *realname, char *prefix)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050098{
99 int i;
100 char *lnp;
101 int pathname_len;
102 int realname_len;
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500103
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500104 if (t->options & TAR_NOOVERWRITE)
105 {
106 struct stat s;
107
108 if (lstat(realname, &s) == 0 || errno != ENOENT)
109 {
110 errno = EEXIST;
111 return -1;
112 }
113 }
114
115 if (TH_ISDIR(t))
116 {
Dees_Troy71796592013-03-14 20:16:29 +0000117 printf("dir\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500118 i = tar_extract_dir(t, realname);
119 if (i == 1)
120 i = 0;
121 }
122 else if (TH_ISLNK(t)) {
123 printf("link\n");
Dees_Troyee6632c2013-02-27 18:07:32 +0000124 i = tar_extract_hardlink(t, realname, prefix);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500125 }
126 else if (TH_ISSYM(t)) {
127 printf("sym\n");
128 i = tar_extract_symlink(t, realname);
129 }
130 else if (TH_ISCHR(t)) {
131 printf("chr\n");
132 i = tar_extract_chardev(t, realname);
133 }
134 else if (TH_ISBLK(t)) {
135 printf("blk\n");
136 i = tar_extract_blockdev(t, realname);
137 }
138 else if (TH_ISFIFO(t)) {
139 printf("fifo\n");
140 i = tar_extract_fifo(t, realname);
141 }
142 else /* if (TH_ISREG(t)) */ {
143 printf("reg\n");
144 i = tar_extract_regfile(t, realname);
145 }
146
147 if (i != 0) {
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500148 printf("FAILED RESTORE OF FILE i: %s\n", realname);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500149 return i;
150 }
151
152 i = tar_set_file_perms(t, realname);
153 if (i != 0) {
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500154 printf("FAILED SETTING PERMS: %d\n", i);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500155 return i;
156 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200157
158#ifdef HAVE_SELINUX
159 if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL)
160 {
161#ifdef DEBUG
162 printf(" Restoring SELinux context %s to file %s\n", t->th_buf.selinux_context, realname);
163#endif
bigbiff bigbiffc49d7062013-10-11 20:28:00 -0400164 if (lsetfilecon(realname, t->th_buf.selinux_context) < 0) {
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200165 fprintf(stderr, "Failed to restore SELinux context %s!\n", strerror(errno));
bigbiff bigbiffc49d7062013-10-11 20:28:00 -0400166 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200167 }
168#endif
169
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500170/*
171 pathname_len = strlen(th_get_pathname(t)) + 1;
172 realname_len = strlen(realname) + 1;
173 lnp = (char *)calloc(1, pathname_len + realname_len);
174 if (lnp == NULL)
175 return -1;
176 strcpy(&lnp[0], th_get_pathname(t));
177 strcpy(&lnp[pathname_len], realname);
178#ifdef DEBUG
179 printf("tar_extract_file(): calling libtar_hash_add(): key=\"%s\", "
180 "value=\"%s\"\n", th_get_pathname(t), realname);
181#endif
182 if (libtar_hash_add(t->h, lnp) != 0)
183 return -1;
184 free(lnp);
185*/
186 return 0;
187}
188
189
190/* extract regular file */
191int
192tar_extract_regfile(TAR *t, char *realname)
193{
Dees_Troy71796592013-03-14 20:16:29 +0000194 //mode_t mode;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500195 size_t size;
Dees_Troy71796592013-03-14 20:16:29 +0000196 //uid_t uid;
197 //gid_t gid;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500198 int fdout;
199 int i, k;
200 char buf[T_BLOCKSIZE];
201 char *filename;
202
203 fflush(NULL);
204#ifdef DEBUG
205 printf("==> tar_extract_regfile(t=0x%lx, realname=\"%s\")\n", t,
206 realname);
207#endif
208
209 if (!TH_ISREG(t))
210 {
211 errno = EINVAL;
212 return -1;
213 }
214
215 filename = (realname ? realname : th_get_pathname(t));
Dees_Troy71796592013-03-14 20:16:29 +0000216 //mode = th_get_mode(t);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500217 size = th_get_size(t);
Dees_Troy71796592013-03-14 20:16:29 +0000218 //uid = th_get_uid(t);
219 //gid = th_get_gid(t);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500220
221 if (mkdirhier(dirname(filename)) == -1)
222 return -1;
223
224#ifdef DEBUG
Dees_Troy71796592013-03-14 20:16:29 +0000225 //printf(" ==> extracting: %s (mode %04o, uid %d, gid %d, %d bytes)\n",
226 // filename, mode, uid, gid, size);
227 printf(" ==> extracting: %s (file size %d bytes)\n",
228 filename, size);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500229#endif
230 fdout = open(filename, O_WRONLY | O_CREAT | O_TRUNC
231#ifdef O_BINARY
232 | O_BINARY
233#endif
234 , 0666);
235 if (fdout == -1)
236 {
237#ifdef DEBUG
238 perror("open()");
239#endif
240 return -1;
241 }
242
243#if 0
244 /* change the owner. (will only work if run as root) */
245 if (fchown(fdout, uid, gid) == -1 && errno != EPERM)
246 {
247#ifdef DEBUG
248 perror("fchown()");
249#endif
250 return -1;
251 }
252
253 /* make sure the mode isn't inheritted from a file we're overwriting */
254 if (fchmod(fdout, mode & 07777) == -1)
255 {
256#ifdef DEBUG
257 perror("fchmod()");
258#endif
259 return -1;
260 }
261#endif
262
263 /* extract the file */
264 for (i = size; i > 0; i -= T_BLOCKSIZE)
265 {
266 k = tar_block_read(t, buf);
267 if (k != T_BLOCKSIZE)
268 {
269 if (k != -1)
270 errno = EINVAL;
271 return -1;
272 }
273
274 /* write block to output file */
275 if (write(fdout, buf,
276 ((i > T_BLOCKSIZE) ? T_BLOCKSIZE : i)) == -1)
277 return -1;
278 }
279
280 /* close output file */
281 if (close(fdout) == -1)
282 return -1;
283
284#ifdef DEBUG
285 printf("### done extracting %s\n", filename);
286#endif
287
288 return 0;
289}
290
291
292/* skip regfile */
293int
294tar_skip_regfile(TAR *t)
295{
296 int i, k;
297 size_t size;
298 char buf[T_BLOCKSIZE];
299
300 if (!TH_ISREG(t))
301 {
302 errno = EINVAL;
303 return -1;
304 }
305
306 size = th_get_size(t);
307 for (i = size; i > 0; i -= T_BLOCKSIZE)
308 {
309 k = tar_block_read(t, buf);
310 if (k != T_BLOCKSIZE)
311 {
312 if (k != -1)
313 errno = EINVAL;
314 return -1;
315 }
316 }
317
318 return 0;
319}
320
321
322/* hardlink */
323int
Dees_Troyee6632c2013-02-27 18:07:32 +0000324tar_extract_hardlink(TAR * t, char *realname, char *prefix)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500325{
326 char *filename;
327 char *linktgt = NULL;
328 char *lnp;
329 libtar_hashptr_t hp;
330
331 if (!TH_ISLNK(t))
332 {
333 errno = EINVAL;
334 return -1;
335 }
336
337 filename = (realname ? realname : th_get_pathname(t));
338 if (mkdirhier(dirname(filename)) == -1)
339 return -1;
340 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);
Dees_Troyee6632c2013-02-27 18:07:32 +0000349 char *newtgt = strdup(linktgt);
350 sprintf(linktgt, "%s/%s", prefix, newtgt);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500351#ifdef DEBUG
352 printf(" ==> extracting: %s (link to %s)\n", filename, linktgt);
353#endif
354 if (link(linktgt, filename) == -1)
355 {
356#ifdef DEBUG
357 perror("link()");
358#endif
Dees_Troyf96fb972013-03-01 22:34:25 +0000359 printf("Failed restore of hardlink '%s' but returning as if nothing bad happened anyway\n", filename);
360 return 0; // Used to be -1
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500361 }
362
363 return 0;
364}
365
366
367/* symlink */
368int
369tar_extract_symlink(TAR *t, char *realname)
370{
371 char *filename;
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500372
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500373 if (!TH_ISSYM(t))
374 {
375 printf("not a sym\n");
376 errno = EINVAL;
377 return -1;
378 }
379
380 filename = (realname ? realname : th_get_pathname(t));
381 printf("file: %s\n", filename);
382 if (mkdirhier(dirname(filename)) == -1) {
383 printf("mkdirhier\n");
384 return -1;
385 }
386
387 if (unlink(filename) == -1 && errno != ENOENT) {
388 printf("unlink\n");
389 return -1;
390 }
391
392#ifdef DEBUG
393 printf(" ==> extracting: %s (symlink to %s)\n",
394 filename, th_get_linkname(t));
395#endif
396 if (symlink(th_get_linkname(t), filename) == -1)
397 {
398#ifdef DEBUG
399 perror("symlink()");
400#endif
401 return -1;
402 }
403
404 return 0;
405}
406
407
408/* character device */
409int
410tar_extract_chardev(TAR *t, char *realname)
411{
412 mode_t mode;
413 unsigned long devmaj, devmin;
414 char *filename;
415
416 if (!TH_ISCHR(t))
417 {
418 errno = EINVAL;
419 return -1;
420 }
421
422 filename = (realname ? realname : th_get_pathname(t));
423 mode = th_get_mode(t);
424 devmaj = th_get_devmajor(t);
425 devmin = th_get_devminor(t);
426
427 if (mkdirhier(dirname(filename)) == -1)
428 return -1;
429
430#ifdef DEBUG
431 printf(" ==> extracting: %s (character device %ld,%ld)\n",
432 filename, devmaj, devmin);
433#endif
434 if (mknod(filename, mode | S_IFCHR,
435 compat_makedev(devmaj, devmin)) == -1)
436 {
437#ifdef DEBUG
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500438 printf("mknod() failed, returning good anyway");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500439#endif
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500440 return 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500441 }
442
443 return 0;
444}
445
446
447/* block device */
448int
449tar_extract_blockdev(TAR *t, char *realname)
450{
451 mode_t mode;
452 unsigned long devmaj, devmin;
453 char *filename;
454
455 if (!TH_ISBLK(t))
456 {
457 errno = EINVAL;
458 return -1;
459 }
460
461 filename = (realname ? realname : th_get_pathname(t));
462 mode = th_get_mode(t);
463 devmaj = th_get_devmajor(t);
464 devmin = th_get_devminor(t);
465
466 if (mkdirhier(dirname(filename)) == -1)
467 return -1;
468
469#ifdef DEBUG
470 printf(" ==> extracting: %s (block device %ld,%ld)\n",
471 filename, devmaj, devmin);
472#endif
473 if (mknod(filename, mode | S_IFBLK,
474 compat_makedev(devmaj, devmin)) == -1)
475 {
476#ifdef DEBUG
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500477 printf("mknod() failed but returning anyway");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500478#endif
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500479 return 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500480 }
481
482 return 0;
483}
484
485
486/* directory */
487int
488tar_extract_dir(TAR *t, char *realname)
489{
490 mode_t mode;
491 char *filename;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500492 if (!TH_ISDIR(t))
493 {
494 errno = EINVAL;
495 return -1;
496 }
497
498 filename = (realname ? realname : th_get_pathname(t));
499 mode = th_get_mode(t);
500
Dees_Troy71796592013-03-14 20:16:29 +0000501 if (mkdirhier(dirname(filename)) == -1) {
502 printf("tar_extract_dir mkdirhier failed\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500503 return -1;
Dees_Troy71796592013-03-14 20:16:29 +0000504 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500505
506#ifdef DEBUG
507 printf(" ==> extracting: %s (mode %04o, directory)\n", filename,
508 mode);
509#endif
510 if (mkdir(filename, mode) == -1)
511 {
512 if (errno == EEXIST)
513 {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500514#ifdef DEBUG
Dees_Troy71796592013-03-14 20:16:29 +0000515 printf(" *** using existing directory");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500516#endif
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500517 }
518 else
519 {
520#ifdef DEBUG
521 perror("mkdir()");
522#endif
523 return -1;
524 }
525 }
526
527 return 0;
528}
529
530
531/* FIFO */
532int
533tar_extract_fifo(TAR *t, char *realname)
534{
535 mode_t mode;
536 char *filename;
537
538 if (!TH_ISFIFO(t))
539 {
540 errno = EINVAL;
541 return -1;
542 }
543
544 filename = (realname ? realname : th_get_pathname(t));
545 mode = th_get_mode(t);
546
547 if (mkdirhier(dirname(filename)) == -1)
548 return -1;
549
550#ifdef DEBUG
551 printf(" ==> extracting: %s (fifo)\n", filename);
552#endif
553 if (mkfifo(filename, mode) == -1)
554 {
555#ifdef DEBUG
556 perror("mkfifo()");
557#endif
558 return -1;
559 }
560
561 return 0;
562}
563
564