blob: 620513c2914d3dbb8851adb5b2cfd6f2e40880a6 [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
48 /* change owner/group */
49 if (geteuid() == 0)
50#ifdef HAVE_LCHOWN
51 if (lchown(filename, uid, gid) == -1)
52 {
53# ifdef DEBUG
54 fprintf(stderr, "lchown(\"%s\", %d, %d): %s\n",
55 filename, uid, gid, strerror(errno));
56# endif
57#else /* ! HAVE_LCHOWN */
58 if (!TH_ISSYM(t) && chown(filename, uid, gid) == -1)
59 {
60# ifdef DEBUG
61 fprintf(stderr, "chown(\"%s\", %d, %d): %s\n",
62 filename, uid, gid, strerror(errno));
63# endif
64#endif /* HAVE_LCHOWN */
65 return -1;
66 }
67
68 /* change access/modification time */
69 if (!TH_ISSYM(t) && utime(filename, &ut) == -1)
70 {
71#ifdef DEBUG
72 perror("utime()");
73#endif
74 return -1;
75 }
76
77 /* change permissions */
78 if (!TH_ISSYM(t) && chmod(filename, mode) == -1)
79 {
80#ifdef DEBUG
81 perror("chmod()");
82#endif
83 return -1;
84 }
85
86 return 0;
87}
88
89
90/* switchboard */
91int
Dees_Troyee6632c2013-02-27 18:07:32 +000092tar_extract_file(TAR *t, char *realname, char *prefix)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050093{
94 int i;
95 char *lnp;
96 int pathname_len;
97 int realname_len;
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -050098
bigbiff bigbiff9c754052013-01-09 09:09:08 -050099 if (t->options & TAR_NOOVERWRITE)
100 {
101 struct stat s;
102
103 if (lstat(realname, &s) == 0 || errno != ENOENT)
104 {
105 errno = EEXIST;
106 return -1;
107 }
108 }
109
110 if (TH_ISDIR(t))
111 {
112 i = tar_extract_dir(t, realname);
113 if (i == 1)
114 i = 0;
115 }
116 else if (TH_ISLNK(t)) {
117 printf("link\n");
Dees_Troyee6632c2013-02-27 18:07:32 +0000118 i = tar_extract_hardlink(t, realname, prefix);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500119 }
120 else if (TH_ISSYM(t)) {
121 printf("sym\n");
122 i = tar_extract_symlink(t, realname);
123 }
124 else if (TH_ISCHR(t)) {
125 printf("chr\n");
126 i = tar_extract_chardev(t, realname);
127 }
128 else if (TH_ISBLK(t)) {
129 printf("blk\n");
130 i = tar_extract_blockdev(t, realname);
131 }
132 else if (TH_ISFIFO(t)) {
133 printf("fifo\n");
134 i = tar_extract_fifo(t, realname);
135 }
136 else /* if (TH_ISREG(t)) */ {
137 printf("reg\n");
138 i = tar_extract_regfile(t, realname);
139 }
140
141 if (i != 0) {
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500142 printf("FAILED RESTORE OF FILE i: %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) {
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500148 printf("FAILED SETTING PERMS: %d\n", i);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500149 return i;
150 }
151/*
152 pathname_len = strlen(th_get_pathname(t)) + 1;
153 realname_len = strlen(realname) + 1;
154 lnp = (char *)calloc(1, pathname_len + realname_len);
155 if (lnp == NULL)
156 return -1;
157 strcpy(&lnp[0], th_get_pathname(t));
158 strcpy(&lnp[pathname_len], realname);
159#ifdef DEBUG
160 printf("tar_extract_file(): calling libtar_hash_add(): key=\"%s\", "
161 "value=\"%s\"\n", th_get_pathname(t), realname);
162#endif
163 if (libtar_hash_add(t->h, lnp) != 0)
164 return -1;
165 free(lnp);
166*/
167 return 0;
168}
169
170
171/* extract regular file */
172int
173tar_extract_regfile(TAR *t, char *realname)
174{
175 mode_t mode;
176 size_t size;
177 uid_t uid;
178 gid_t gid;
179 int fdout;
180 int i, k;
181 char buf[T_BLOCKSIZE];
182 char *filename;
183
184 fflush(NULL);
185#ifdef DEBUG
186 printf("==> tar_extract_regfile(t=0x%lx, realname=\"%s\")\n", t,
187 realname);
188#endif
189
190 if (!TH_ISREG(t))
191 {
192 errno = EINVAL;
193 return -1;
194 }
195
196 filename = (realname ? realname : th_get_pathname(t));
197 mode = th_get_mode(t);
198 size = th_get_size(t);
199 uid = th_get_uid(t);
200 gid = th_get_gid(t);
201
202 if (mkdirhier(dirname(filename)) == -1)
203 return -1;
204
205#ifdef DEBUG
206 printf(" ==> extracting: %s (mode %04o, uid %d, gid %d, %d bytes)\n",
207 filename, mode, uid, gid, size);
208#endif
209 fdout = open(filename, O_WRONLY | O_CREAT | O_TRUNC
210#ifdef O_BINARY
211 | O_BINARY
212#endif
213 , 0666);
214 if (fdout == -1)
215 {
216#ifdef DEBUG
217 perror("open()");
218#endif
219 return -1;
220 }
221
222#if 0
223 /* change the owner. (will only work if run as root) */
224 if (fchown(fdout, uid, gid) == -1 && errno != EPERM)
225 {
226#ifdef DEBUG
227 perror("fchown()");
228#endif
229 return -1;
230 }
231
232 /* make sure the mode isn't inheritted from a file we're overwriting */
233 if (fchmod(fdout, mode & 07777) == -1)
234 {
235#ifdef DEBUG
236 perror("fchmod()");
237#endif
238 return -1;
239 }
240#endif
241
242 /* extract the file */
243 for (i = size; i > 0; i -= T_BLOCKSIZE)
244 {
245 k = tar_block_read(t, buf);
246 if (k != T_BLOCKSIZE)
247 {
248 if (k != -1)
249 errno = EINVAL;
250 return -1;
251 }
252
253 /* write block to output file */
254 if (write(fdout, buf,
255 ((i > T_BLOCKSIZE) ? T_BLOCKSIZE : i)) == -1)
256 return -1;
257 }
258
259 /* close output file */
260 if (close(fdout) == -1)
261 return -1;
262
263#ifdef DEBUG
264 printf("### done extracting %s\n", filename);
265#endif
266
267 return 0;
268}
269
270
271/* skip regfile */
272int
273tar_skip_regfile(TAR *t)
274{
275 int i, k;
276 size_t size;
277 char buf[T_BLOCKSIZE];
278
279 if (!TH_ISREG(t))
280 {
281 errno = EINVAL;
282 return -1;
283 }
284
285 size = th_get_size(t);
286 for (i = size; i > 0; i -= T_BLOCKSIZE)
287 {
288 k = tar_block_read(t, buf);
289 if (k != T_BLOCKSIZE)
290 {
291 if (k != -1)
292 errno = EINVAL;
293 return -1;
294 }
295 }
296
297 return 0;
298}
299
300
301/* hardlink */
302int
Dees_Troyee6632c2013-02-27 18:07:32 +0000303tar_extract_hardlink(TAR * t, char *realname, char *prefix)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500304{
305 char *filename;
306 char *linktgt = NULL;
307 char *lnp;
308 libtar_hashptr_t hp;
309
310 if (!TH_ISLNK(t))
311 {
312 errno = EINVAL;
313 return -1;
314 }
315
316 filename = (realname ? realname : th_get_pathname(t));
317 if (mkdirhier(dirname(filename)) == -1)
318 return -1;
319 libtar_hashptr_reset(&hp);
320 if (libtar_hash_getkey(t->h, &hp, th_get_linkname(t),
321 (libtar_matchfunc_t)libtar_str_match) != 0)
322 {
323 lnp = (char *)libtar_hashptr_data(&hp);
324 linktgt = &lnp[strlen(lnp) + 1];
325 }
326 else
327 linktgt = th_get_linkname(t);
Dees_Troyee6632c2013-02-27 18:07:32 +0000328 char *newtgt = strdup(linktgt);
329 sprintf(linktgt, "%s/%s", prefix, newtgt);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500330#ifdef DEBUG
331 printf(" ==> extracting: %s (link to %s)\n", filename, linktgt);
332#endif
333 if (link(linktgt, filename) == -1)
334 {
335#ifdef DEBUG
336 perror("link()");
337#endif
338 return -1;
339 }
340
341 return 0;
342}
343
344
345/* symlink */
346int
347tar_extract_symlink(TAR *t, char *realname)
348{
349 char *filename;
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500350
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500351 if (!TH_ISSYM(t))
352 {
353 printf("not a sym\n");
354 errno = EINVAL;
355 return -1;
356 }
357
358 filename = (realname ? realname : th_get_pathname(t));
359 printf("file: %s\n", filename);
360 if (mkdirhier(dirname(filename)) == -1) {
361 printf("mkdirhier\n");
362 return -1;
363 }
364
365 if (unlink(filename) == -1 && errno != ENOENT) {
366 printf("unlink\n");
367 return -1;
368 }
369
370#ifdef DEBUG
371 printf(" ==> extracting: %s (symlink to %s)\n",
372 filename, th_get_linkname(t));
373#endif
374 if (symlink(th_get_linkname(t), filename) == -1)
375 {
376#ifdef DEBUG
377 perror("symlink()");
378#endif
379 return -1;
380 }
381
382 return 0;
383}
384
385
386/* character device */
387int
388tar_extract_chardev(TAR *t, char *realname)
389{
390 mode_t mode;
391 unsigned long devmaj, devmin;
392 char *filename;
393
394 if (!TH_ISCHR(t))
395 {
396 errno = EINVAL;
397 return -1;
398 }
399
400 filename = (realname ? realname : th_get_pathname(t));
401 mode = th_get_mode(t);
402 devmaj = th_get_devmajor(t);
403 devmin = th_get_devminor(t);
404
405 if (mkdirhier(dirname(filename)) == -1)
406 return -1;
407
408#ifdef DEBUG
409 printf(" ==> extracting: %s (character device %ld,%ld)\n",
410 filename, devmaj, devmin);
411#endif
412 if (mknod(filename, mode | S_IFCHR,
413 compat_makedev(devmaj, devmin)) == -1)
414 {
415#ifdef DEBUG
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500416 printf("mknod() failed, returning good anyway");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500417#endif
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500418 return 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500419 }
420
421 return 0;
422}
423
424
425/* block device */
426int
427tar_extract_blockdev(TAR *t, char *realname)
428{
429 mode_t mode;
430 unsigned long devmaj, devmin;
431 char *filename;
432
433 if (!TH_ISBLK(t))
434 {
435 errno = EINVAL;
436 return -1;
437 }
438
439 filename = (realname ? realname : th_get_pathname(t));
440 mode = th_get_mode(t);
441 devmaj = th_get_devmajor(t);
442 devmin = th_get_devminor(t);
443
444 if (mkdirhier(dirname(filename)) == -1)
445 return -1;
446
447#ifdef DEBUG
448 printf(" ==> extracting: %s (block device %ld,%ld)\n",
449 filename, devmaj, devmin);
450#endif
451 if (mknod(filename, mode | S_IFBLK,
452 compat_makedev(devmaj, devmin)) == -1)
453 {
454#ifdef DEBUG
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500455 printf("mknod() failed but returning anyway");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500456#endif
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500457 return 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500458 }
459
460 return 0;
461}
462
463
464/* directory */
465int
466tar_extract_dir(TAR *t, char *realname)
467{
468 mode_t mode;
469 char *filename;
470 printf("filename: %s\n", filename);
471 if (!TH_ISDIR(t))
472 {
473 errno = EINVAL;
474 return -1;
475 }
476
477 filename = (realname ? realname : th_get_pathname(t));
478 mode = th_get_mode(t);
479
480 if (mkdirhier(dirname(filename)) == -1)
481 return -1;
482
483#ifdef DEBUG
484 printf(" ==> extracting: %s (mode %04o, directory)\n", filename,
485 mode);
486#endif
487 if (mkdir(filename, mode) == -1)
488 {
489 if (errno == EEXIST)
490 {
491 if (chmod(filename, mode) == -1)
492 {
493#ifdef DEBUG
494 perror("chmod()");
495#endif
496 return -1;
497 }
498 else
499 {
500#ifdef DEBUG
501 puts(" *** using existing directory");
502#endif
503 return 1;
504 }
505 }
506 else
507 {
508#ifdef DEBUG
509 perror("mkdir()");
510#endif
511 return -1;
512 }
513 }
514
515 return 0;
516}
517
518
519/* FIFO */
520int
521tar_extract_fifo(TAR *t, char *realname)
522{
523 mode_t mode;
524 char *filename;
525
526 if (!TH_ISFIFO(t))
527 {
528 errno = EINVAL;
529 return -1;
530 }
531
532 filename = (realname ? realname : th_get_pathname(t));
533 mode = th_get_mode(t);
534
535 if (mkdirhier(dirname(filename)) == -1)
536 return -1;
537
538#ifdef DEBUG
539 printf(" ==> extracting: %s (fifo)\n", filename);
540#endif
541 if (mkfifo(filename, mode) == -1)
542 {
543#ifdef DEBUG
544 perror("mkfifo()");
545#endif
546 return -1;
547 }
548
549 return 0;
550}
551
552