blob: 613e29fffef7c13bcc103047b004853b9138cd17 [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 }
157/*
158 pathname_len = strlen(th_get_pathname(t)) + 1;
159 realname_len = strlen(realname) + 1;
160 lnp = (char *)calloc(1, pathname_len + realname_len);
161 if (lnp == NULL)
162 return -1;
163 strcpy(&lnp[0], th_get_pathname(t));
164 strcpy(&lnp[pathname_len], realname);
165#ifdef DEBUG
166 printf("tar_extract_file(): calling libtar_hash_add(): key=\"%s\", "
167 "value=\"%s\"\n", th_get_pathname(t), realname);
168#endif
169 if (libtar_hash_add(t->h, lnp) != 0)
170 return -1;
171 free(lnp);
172*/
173 return 0;
174}
175
176
177/* extract regular file */
178int
179tar_extract_regfile(TAR *t, char *realname)
180{
Dees_Troy71796592013-03-14 20:16:29 +0000181 //mode_t mode;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500182 size_t size;
Dees_Troy71796592013-03-14 20:16:29 +0000183 //uid_t uid;
184 //gid_t gid;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500185 int fdout;
186 int i, k;
187 char buf[T_BLOCKSIZE];
188 char *filename;
189
190 fflush(NULL);
191#ifdef DEBUG
192 printf("==> tar_extract_regfile(t=0x%lx, realname=\"%s\")\n", t,
193 realname);
194#endif
195
196 if (!TH_ISREG(t))
197 {
198 errno = EINVAL;
199 return -1;
200 }
201
202 filename = (realname ? realname : th_get_pathname(t));
Dees_Troy71796592013-03-14 20:16:29 +0000203 //mode = th_get_mode(t);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500204 size = th_get_size(t);
Dees_Troy71796592013-03-14 20:16:29 +0000205 //uid = th_get_uid(t);
206 //gid = th_get_gid(t);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500207
208 if (mkdirhier(dirname(filename)) == -1)
209 return -1;
210
211#ifdef DEBUG
Dees_Troy71796592013-03-14 20:16:29 +0000212 //printf(" ==> extracting: %s (mode %04o, uid %d, gid %d, %d bytes)\n",
213 // filename, mode, uid, gid, size);
214 printf(" ==> extracting: %s (file size %d bytes)\n",
215 filename, size);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500216#endif
217 fdout = open(filename, O_WRONLY | O_CREAT | O_TRUNC
218#ifdef O_BINARY
219 | O_BINARY
220#endif
221 , 0666);
222 if (fdout == -1)
223 {
224#ifdef DEBUG
225 perror("open()");
226#endif
227 return -1;
228 }
229
230#if 0
231 /* change the owner. (will only work if run as root) */
232 if (fchown(fdout, uid, gid) == -1 && errno != EPERM)
233 {
234#ifdef DEBUG
235 perror("fchown()");
236#endif
237 return -1;
238 }
239
240 /* make sure the mode isn't inheritted from a file we're overwriting */
241 if (fchmod(fdout, mode & 07777) == -1)
242 {
243#ifdef DEBUG
244 perror("fchmod()");
245#endif
246 return -1;
247 }
248#endif
249
250 /* extract the file */
251 for (i = size; i > 0; i -= T_BLOCKSIZE)
252 {
253 k = tar_block_read(t, buf);
254 if (k != T_BLOCKSIZE)
255 {
256 if (k != -1)
257 errno = EINVAL;
258 return -1;
259 }
260
261 /* write block to output file */
262 if (write(fdout, buf,
263 ((i > T_BLOCKSIZE) ? T_BLOCKSIZE : i)) == -1)
264 return -1;
265 }
266
267 /* close output file */
268 if (close(fdout) == -1)
269 return -1;
270
271#ifdef DEBUG
272 printf("### done extracting %s\n", filename);
273#endif
274
275 return 0;
276}
277
278
279/* skip regfile */
280int
281tar_skip_regfile(TAR *t)
282{
283 int i, k;
284 size_t size;
285 char buf[T_BLOCKSIZE];
286
287 if (!TH_ISREG(t))
288 {
289 errno = EINVAL;
290 return -1;
291 }
292
293 size = th_get_size(t);
294 for (i = size; i > 0; i -= T_BLOCKSIZE)
295 {
296 k = tar_block_read(t, buf);
297 if (k != T_BLOCKSIZE)
298 {
299 if (k != -1)
300 errno = EINVAL;
301 return -1;
302 }
303 }
304
305 return 0;
306}
307
308
309/* hardlink */
310int
Dees_Troyee6632c2013-02-27 18:07:32 +0000311tar_extract_hardlink(TAR * t, char *realname, char *prefix)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500312{
313 char *filename;
314 char *linktgt = NULL;
315 char *lnp;
316 libtar_hashptr_t hp;
317
318 if (!TH_ISLNK(t))
319 {
320 errno = EINVAL;
321 return -1;
322 }
323
324 filename = (realname ? realname : th_get_pathname(t));
325 if (mkdirhier(dirname(filename)) == -1)
326 return -1;
327 libtar_hashptr_reset(&hp);
328 if (libtar_hash_getkey(t->h, &hp, th_get_linkname(t),
329 (libtar_matchfunc_t)libtar_str_match) != 0)
330 {
331 lnp = (char *)libtar_hashptr_data(&hp);
332 linktgt = &lnp[strlen(lnp) + 1];
333 }
334 else
335 linktgt = th_get_linkname(t);
Dees_Troyee6632c2013-02-27 18:07:32 +0000336 char *newtgt = strdup(linktgt);
337 sprintf(linktgt, "%s/%s", prefix, newtgt);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500338#ifdef DEBUG
339 printf(" ==> extracting: %s (link to %s)\n", filename, linktgt);
340#endif
341 if (link(linktgt, filename) == -1)
342 {
343#ifdef DEBUG
344 perror("link()");
345#endif
Dees_Troyf96fb972013-03-01 22:34:25 +0000346 printf("Failed restore of hardlink '%s' but returning as if nothing bad happened anyway\n", filename);
347 return 0; // Used to be -1
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500348 }
349
350 return 0;
351}
352
353
354/* symlink */
355int
356tar_extract_symlink(TAR *t, char *realname)
357{
358 char *filename;
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500359
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500360 if (!TH_ISSYM(t))
361 {
362 printf("not a sym\n");
363 errno = EINVAL;
364 return -1;
365 }
366
367 filename = (realname ? realname : th_get_pathname(t));
368 printf("file: %s\n", filename);
369 if (mkdirhier(dirname(filename)) == -1) {
370 printf("mkdirhier\n");
371 return -1;
372 }
373
374 if (unlink(filename) == -1 && errno != ENOENT) {
375 printf("unlink\n");
376 return -1;
377 }
378
379#ifdef DEBUG
380 printf(" ==> extracting: %s (symlink to %s)\n",
381 filename, th_get_linkname(t));
382#endif
383 if (symlink(th_get_linkname(t), filename) == -1)
384 {
385#ifdef DEBUG
386 perror("symlink()");
387#endif
388 return -1;
389 }
390
391 return 0;
392}
393
394
395/* character device */
396int
397tar_extract_chardev(TAR *t, char *realname)
398{
399 mode_t mode;
400 unsigned long devmaj, devmin;
401 char *filename;
402
403 if (!TH_ISCHR(t))
404 {
405 errno = EINVAL;
406 return -1;
407 }
408
409 filename = (realname ? realname : th_get_pathname(t));
410 mode = th_get_mode(t);
411 devmaj = th_get_devmajor(t);
412 devmin = th_get_devminor(t);
413
414 if (mkdirhier(dirname(filename)) == -1)
415 return -1;
416
417#ifdef DEBUG
418 printf(" ==> extracting: %s (character device %ld,%ld)\n",
419 filename, devmaj, devmin);
420#endif
421 if (mknod(filename, mode | S_IFCHR,
422 compat_makedev(devmaj, devmin)) == -1)
423 {
424#ifdef DEBUG
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500425 printf("mknod() failed, returning good anyway");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500426#endif
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500427 return 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500428 }
429
430 return 0;
431}
432
433
434/* block device */
435int
436tar_extract_blockdev(TAR *t, char *realname)
437{
438 mode_t mode;
439 unsigned long devmaj, devmin;
440 char *filename;
441
442 if (!TH_ISBLK(t))
443 {
444 errno = EINVAL;
445 return -1;
446 }
447
448 filename = (realname ? realname : th_get_pathname(t));
449 mode = th_get_mode(t);
450 devmaj = th_get_devmajor(t);
451 devmin = th_get_devminor(t);
452
453 if (mkdirhier(dirname(filename)) == -1)
454 return -1;
455
456#ifdef DEBUG
457 printf(" ==> extracting: %s (block device %ld,%ld)\n",
458 filename, devmaj, devmin);
459#endif
460 if (mknod(filename, mode | S_IFBLK,
461 compat_makedev(devmaj, devmin)) == -1)
462 {
463#ifdef DEBUG
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500464 printf("mknod() failed but returning anyway");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500465#endif
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500466 return 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500467 }
468
469 return 0;
470}
471
472
473/* directory */
474int
475tar_extract_dir(TAR *t, char *realname)
476{
477 mode_t mode;
478 char *filename;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500479 if (!TH_ISDIR(t))
480 {
481 errno = EINVAL;
482 return -1;
483 }
484
485 filename = (realname ? realname : th_get_pathname(t));
486 mode = th_get_mode(t);
487
Dees_Troy71796592013-03-14 20:16:29 +0000488 if (mkdirhier(dirname(filename)) == -1) {
489 printf("tar_extract_dir mkdirhier failed\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500490 return -1;
Dees_Troy71796592013-03-14 20:16:29 +0000491 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500492
493#ifdef DEBUG
494 printf(" ==> extracting: %s (mode %04o, directory)\n", filename,
495 mode);
496#endif
497 if (mkdir(filename, mode) == -1)
498 {
499 if (errno == EEXIST)
500 {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500501#ifdef DEBUG
Dees_Troy71796592013-03-14 20:16:29 +0000502 printf(" *** using existing directory");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500503#endif
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500504 }
505 else
506 {
507#ifdef DEBUG
508 perror("mkdir()");
509#endif
510 return -1;
511 }
512 }
513
514 return 0;
515}
516
517
518/* FIFO */
519int
520tar_extract_fifo(TAR *t, char *realname)
521{
522 mode_t mode;
523 char *filename;
524
525 if (!TH_ISFIFO(t))
526 {
527 errno = EINVAL;
528 return -1;
529 }
530
531 filename = (realname ? realname : th_get_pathname(t));
532 mode = th_get_mode(t);
533
534 if (mkdirhier(dirname(filename)) == -1)
535 return -1;
536
537#ifdef DEBUG
538 printf(" ==> extracting: %s (fifo)\n", filename);
539#endif
540 if (mkfifo(filename, mode) == -1)
541 {
542#ifdef DEBUG
543 perror("mkfifo()");
544#endif
545 return -1;
546 }
547
548 return 0;
549}
550
551