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
17 #include <sys/param.h>
18 #include <sys/types.h>
34 char ln_save
[MAXPATHLEN
];
35 char ln_real
[MAXPATHLEN
];
37 typedef struct linkname linkname_t
;
41 tar_set_file_perms(TAR
*t
, char *realname
)
49 filename
= (realname
? realname
: th_get_pathname(t
));
50 mode
= th_get_mode(t
);
53 ut
.modtime
= ut
.actime
= th_get_mtime(t
);
55 /* change owner/group */
58 if (lchown(filename
, uid
, gid
) == -1)
61 fprintf(stderr
, "lchown(\"%s\", %d, %d): %s\n",
62 filename
, uid
, gid
, strerror(errno
));
64 #else /* ! HAVE_LCHOWN */
65 if (!TH_ISSYM(t
) && chown(filename
, uid
, gid
) == -1)
68 fprintf(stderr
, "chown(\"%s\", %d, %d): %s\n",
69 filename
, uid
, gid
, strerror(errno
));
71 #endif /* HAVE_LCHOWN */
75 /* change access/modification time */
76 if (!TH_ISSYM(t
) && utime(filename
, &ut
) == -1)
84 /* change permissions */
85 if (!TH_ISSYM(t
) && chmod(filename
, mode
) == -1)
99 tar_extract_file(TAR
*t
, char *realname
)
104 if (t
->options
& TAR_NOOVERWRITE
)
108 if (lstat(realname
, &s
) == 0 || errno
!= ENOENT
)
117 i
= tar_extract_dir(t
, realname
);
121 else if (TH_ISLNK(t
))
122 i
= tar_extract_hardlink(t
, realname
);
123 else if (TH_ISSYM(t
))
124 i
= tar_extract_symlink(t
, realname
);
125 else if (TH_ISCHR(t
))
126 i
= tar_extract_chardev(t
, realname
);
127 else if (TH_ISBLK(t
))
128 i
= tar_extract_blockdev(t
, realname
);
129 else if (TH_ISFIFO(t
))
130 i
= tar_extract_fifo(t
, realname
);
131 else /* if (TH_ISREG(t)) */
132 i
= tar_extract_regfile(t
, realname
);
137 i
= tar_set_file_perms(t
, realname
);
141 lnp
= (linkname_t
*)calloc(1, sizeof(linkname_t
));
144 strlcpy(lnp
->ln_save
, th_get_pathname(t
), sizeof(lnp
->ln_save
));
145 strlcpy(lnp
->ln_real
, realname
, sizeof(lnp
->ln_real
));
147 printf("tar_extract_file(): calling libtar_hash_add(): key=\"%s\", "
148 "value=\"%s\"\n", th_get_pathname(t
), realname
);
150 if (libtar_hash_add(t
->h
, lnp
) != 0)
157 /* extract regular file */
159 tar_extract_regfile(TAR
*t
, char *realname
)
167 char buf
[T_BLOCKSIZE
];
171 printf("==> tar_extract_regfile(t=0x%lx, realname=\"%s\")\n", t
,
181 filename
= (realname
? realname
: th_get_pathname(t
));
182 mode
= th_get_mode(t
);
183 size
= th_get_size(t
);
187 if (mkdirhier(dirname(filename
)) == -1)
191 printf(" ==> extracting: %s (mode %04o, uid %d, gid %d, %d bytes)\n",
192 filename
, mode
, uid
, gid
, size
);
194 fdout
= open(filename
, O_WRONLY
| O_CREAT
| O_TRUNC
208 /* change the owner. (will only work if run as root) */
209 if (fchown(fdout
, uid
, gid
) == -1 && errno
!= EPERM
)
217 /* make sure the mode isn't inheritted from a file we're overwriting */
218 if (fchmod(fdout
, mode
& 07777) == -1)
227 /* extract the file */
228 for (i
= size
; i
> 0; i
-= T_BLOCKSIZE
)
230 k
= tar_block_read(t
, buf
);
231 if (k
!= T_BLOCKSIZE
)
238 /* write block to output file */
239 if (write(fdout
, buf
,
240 ((i
> T_BLOCKSIZE
) ? T_BLOCKSIZE
: i
)) == -1)
244 /* close output file */
245 if (close(fdout
) == -1)
249 printf("### done extracting %s\n", filename
);
258 tar_skip_regfile(TAR
*t
)
262 char buf
[T_BLOCKSIZE
];
270 size
= th_get_size(t
);
271 for (i
= size
; i
> 0; i
-= T_BLOCKSIZE
)
273 k
= tar_block_read(t
, buf
);
274 if (k
!= T_BLOCKSIZE
)
288 tar_extract_hardlink(TAR
* t
, char *realname
)
291 char *linktgt
= NULL
;
301 filename
= (realname
? realname
: th_get_pathname(t
));
302 if (mkdirhier(dirname(filename
)) == -1)
304 libtar_hashptr_reset(&hp
);
305 if (libtar_hash_getkey(t
->h
, &hp
, th_get_linkname(t
),
306 (libtar_matchfunc_t
)libtar_str_match
) != 0)
308 lnp
= (linkname_t
*)libtar_hashptr_data(&hp
);
309 linktgt
= lnp
->ln_real
;
312 linktgt
= th_get_linkname(t
);
315 printf(" ==> extracting: %s (link to %s)\n", filename
, linktgt
);
317 if (link(linktgt
, filename
) == -1)
331 tar_extract_symlink(TAR
*t
, char *realname
)
341 filename
= (realname
? realname
: th_get_pathname(t
));
342 if (mkdirhier(dirname(filename
)) == -1)
345 if (unlink(filename
) == -1 && errno
!= ENOENT
)
349 printf(" ==> extracting: %s (symlink to %s)\n",
350 filename
, th_get_linkname(t
));
352 if (symlink(th_get_linkname(t
), filename
) == -1)
364 /* character device */
366 tar_extract_chardev(TAR
*t
, char *realname
)
369 unsigned long devmaj
, devmin
;
378 filename
= (realname
? realname
: th_get_pathname(t
));
379 mode
= th_get_mode(t
);
380 devmaj
= th_get_devmajor(t
);
381 devmin
= th_get_devminor(t
);
383 if (mkdirhier(dirname(filename
)) == -1)
387 printf(" ==> extracting: %s (character device %ld,%ld)\n",
388 filename
, devmaj
, devmin
);
390 if (mknod(filename
, mode
| S_IFCHR
,
391 compat_makedev(devmaj
, devmin
)) == -1)
405 tar_extract_blockdev(TAR
*t
, char *realname
)
408 unsigned long devmaj
, devmin
;
417 filename
= (realname
? realname
: th_get_pathname(t
));
418 mode
= th_get_mode(t
);
419 devmaj
= th_get_devmajor(t
);
420 devmin
= th_get_devminor(t
);
422 if (mkdirhier(dirname(filename
)) == -1)
426 printf(" ==> extracting: %s (block device %ld,%ld)\n",
427 filename
, devmaj
, devmin
);
429 if (mknod(filename
, mode
| S_IFBLK
,
430 compat_makedev(devmaj
, devmin
)) == -1)
444 tar_extract_dir(TAR
*t
, char *realname
)
455 filename
= (realname
? realname
: th_get_pathname(t
));
456 mode
= th_get_mode(t
);
458 if (mkdirhier(dirname(filename
)) == -1)
462 printf(" ==> extracting: %s (mode %04o, directory)\n", filename
,
465 if (mkdir(filename
, mode
) == -1)
469 if (chmod(filename
, mode
) == -1)
479 puts(" *** using existing directory");
499 tar_extract_fifo(TAR
*t
, char *realname
)
510 filename
= (realname
? realname
: th_get_pathname(t
));
511 mode
= th_get_mode(t
);
513 if (mkdirhier(dirname(filename
)) == -1)
517 printf(" ==> extracting: %s (fifo)\n", filename
);
519 if (mkfifo(filename
, mode
) == -1)