2 ** Copyright 1998-2003 University of Illinois Board of Trustees
3 ** Copyright 1998-2003 Mark D. Roth
4 ** All rights reserved.
6 ** extract.c - libtar code to extract a file from a tar archive
8 ** Mark D. Roth <roth@uiuc.edu>
9 ** Campus Information Technologies and Educational Services
10 ** University of Illinois at Urbana-Champaign
16 #include <sys/param.h>
17 #include <sys/types.h>
33 char ln_save
[MAXPATHLEN
];
34 char ln_real
[MAXPATHLEN
];
36 typedef struct linkname linkname_t
;
40 tar_set_file_perms(TAR
*t
, char *realname
)
48 filename
= (realname
? realname
: th_get_pathname(t
));
49 mode
= th_get_mode(t
);
52 ut
.modtime
= ut
.actime
= th_get_mtime(t
);
54 /* change owner/group */
57 if (lchown(filename
, uid
, gid
) == -1)
60 fprintf(stderr
, "lchown(\"%s\", %d, %d): %s\n",
61 filename
, uid
, gid
, strerror(errno
));
63 #else /* ! HAVE_LCHOWN */
64 if (!TH_ISSYM(t
) && chown(filename
, uid
, gid
) == -1)
67 fprintf(stderr
, "chown(\"%s\", %d, %d): %s\n",
68 filename
, uid
, gid
, strerror(errno
));
70 #endif /* HAVE_LCHOWN */
74 /* change access/modification time */
75 if (!TH_ISSYM(t
) && utime(filename
, &ut
) == -1)
83 /* change permissions */
84 if (!TH_ISSYM(t
) && chmod(filename
, mode
) == -1)
98 tar_extract_file(TAR
*t
, char *realname
)
103 if (t
->options
& TAR_NOOVERWRITE
)
107 if (lstat(realname
, &s
) == 0 || errno
!= ENOENT
)
116 i
= tar_extract_dir(t
, realname
);
120 else if (TH_ISLNK(t
))
121 i
= tar_extract_hardlink(t
, realname
);
122 else if (TH_ISSYM(t
))
123 i
= tar_extract_symlink(t
, realname
);
124 else if (TH_ISCHR(t
))
125 i
= tar_extract_chardev(t
, realname
);
126 else if (TH_ISBLK(t
))
127 i
= tar_extract_blockdev(t
, realname
);
128 else if (TH_ISFIFO(t
))
129 i
= tar_extract_fifo(t
, realname
);
130 else /* if (TH_ISREG(t)) */
131 i
= tar_extract_regfile(t
, realname
);
136 i
= tar_set_file_perms(t
, realname
);
140 lnp
= (linkname_t
*)calloc(1, sizeof(linkname_t
));
143 strlcpy(lnp
->ln_save
, th_get_pathname(t
), sizeof(lnp
->ln_save
));
144 strlcpy(lnp
->ln_real
, realname
, sizeof(lnp
->ln_real
));
146 printf("tar_extract_file(): calling libtar_hash_add(): key=\"%s\", "
147 "value=\"%s\"\n", th_get_pathname(t
), realname
);
149 if (libtar_hash_add(t
->h
, lnp
) != 0)
156 /* extract regular file */
158 tar_extract_regfile(TAR
*t
, char *realname
)
166 char buf
[T_BLOCKSIZE
];
170 printf("==> tar_extract_regfile(t=0x%lx, realname=\"%s\")\n", t
,
180 filename
= (realname
? realname
: th_get_pathname(t
));
181 mode
= th_get_mode(t
);
182 size
= th_get_size(t
);
186 if (mkdirhier(dirname(filename
)) == -1)
190 printf(" ==> extracting: %s (mode %04o, uid %d, gid %d, %d bytes)\n",
191 filename
, mode
, uid
, gid
, size
);
193 fdout
= open(filename
, O_WRONLY
| O_CREAT
| O_TRUNC
207 /* change the owner. (will only work if run as root) */
208 if (fchown(fdout
, uid
, gid
) == -1 && errno
!= EPERM
)
216 /* make sure the mode isn't inheritted from a file we're overwriting */
217 if (fchmod(fdout
, mode
& 07777) == -1)
226 /* extract the file */
227 for (i
= size
; i
> 0; i
-= T_BLOCKSIZE
)
229 k
= tar_block_read(t
, buf
);
230 if (k
!= T_BLOCKSIZE
)
237 /* write block to output file */
238 if (write(fdout
, buf
,
239 ((i
> T_BLOCKSIZE
) ? T_BLOCKSIZE
: i
)) == -1)
243 /* close output file */
244 if (close(fdout
) == -1)
248 printf("### done extracting %s\n", filename
);
257 tar_skip_regfile(TAR
*t
)
261 char buf
[T_BLOCKSIZE
];
269 size
= th_get_size(t
);
270 for (i
= size
; i
> 0; i
-= T_BLOCKSIZE
)
272 k
= tar_block_read(t
, buf
);
273 if (k
!= T_BLOCKSIZE
)
287 tar_extract_hardlink(TAR
* t
, char *realname
)
290 char *linktgt
= NULL
;
300 filename
= (realname
? realname
: th_get_pathname(t
));
301 if (mkdirhier(dirname(filename
)) == -1)
303 libtar_hashptr_reset(&hp
);
304 if (libtar_hash_getkey(t
->h
, &hp
, th_get_linkname(t
),
305 (libtar_matchfunc_t
)libtar_str_match
) != 0)
307 lnp
= (linkname_t
*)libtar_hashptr_data(&hp
);
308 linktgt
= lnp
->ln_real
;
311 linktgt
= th_get_linkname(t
);
314 printf(" ==> extracting: %s (link to %s)\n", filename
, linktgt
);
316 if (link(linktgt
, filename
) == -1)
330 tar_extract_symlink(TAR
*t
, char *realname
)
340 filename
= (realname
? realname
: th_get_pathname(t
));
341 if (mkdirhier(dirname(filename
)) == -1)
344 if (unlink(filename
) == -1 && errno
!= ENOENT
)
348 printf(" ==> extracting: %s (symlink to %s)\n",
349 filename
, th_get_linkname(t
));
351 if (symlink(th_get_linkname(t
), filename
) == -1)
363 /* character device */
365 tar_extract_chardev(TAR
*t
, char *realname
)
368 unsigned long devmaj
, devmin
;
377 filename
= (realname
? realname
: th_get_pathname(t
));
378 mode
= th_get_mode(t
);
379 devmaj
= th_get_devmajor(t
);
380 devmin
= th_get_devminor(t
);
382 if (mkdirhier(dirname(filename
)) == -1)
386 printf(" ==> extracting: %s (character device %ld,%ld)\n",
387 filename
, devmaj
, devmin
);
389 if (mknod(filename
, mode
| S_IFCHR
,
390 compat_makedev(devmaj
, devmin
)) == -1)
404 tar_extract_blockdev(TAR
*t
, char *realname
)
407 unsigned long devmaj
, devmin
;
416 filename
= (realname
? realname
: th_get_pathname(t
));
417 mode
= th_get_mode(t
);
418 devmaj
= th_get_devmajor(t
);
419 devmin
= th_get_devminor(t
);
421 if (mkdirhier(dirname(filename
)) == -1)
425 printf(" ==> extracting: %s (block device %ld,%ld)\n",
426 filename
, devmaj
, devmin
);
428 if (mknod(filename
, mode
| S_IFBLK
,
429 compat_makedev(devmaj
, devmin
)) == -1)
443 tar_extract_dir(TAR
*t
, char *realname
)
454 filename
= (realname
? realname
: th_get_pathname(t
));
455 mode
= th_get_mode(t
);
457 if (mkdirhier(dirname(filename
)) == -1)
461 printf(" ==> extracting: %s (mode %04o, directory)\n", filename
,
464 if (mkdir(filename
, mode
) == -1)
468 if (chmod(filename
, mode
) == -1)
478 puts(" *** using existing directory");
498 tar_extract_fifo(TAR
*t
, char *realname
)
509 filename
= (realname
? realname
: th_get_pathname(t
));
510 mode
= th_get_mode(t
);
512 if (mkdirhier(dirname(filename
)) == -1)
516 printf(" ==> extracting: %s (fifo)\n", filename
);
518 if (mkfifo(filename
, mode
) == -1)