1 /* vi: set sw=4 ts=4: */
3 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 void FAST_FUNC
data_extract_all(archive_handle_t
*archive_handle
)
11 file_header_t
*file_header
= archive_handle
->file_header
;
15 if (archive_handle
->ah_flags
& ARCHIVE_CREATE_LEADING_DIRS
) {
16 char *name
= xstrdup(file_header
->name
);
17 bb_make_directory(dirname(name
), -1, FILEUTILS_RECUR
);
21 /* Check if the file already exists */
22 if (archive_handle
->ah_flags
& ARCHIVE_EXTRACT_UNCONDITIONAL
) {
23 /* Remove the entry if it exists */
24 if (((file_header
->mode
& S_IFMT
) != S_IFDIR
)
25 && (unlink(file_header
->name
) == -1)
28 bb_perror_msg_and_die("cannot remove old file %s",
32 else if (archive_handle
->ah_flags
& ARCHIVE_EXTRACT_NEWER
) {
33 /* Remove the existing entry if its older than the extracted entry */
35 if (lstat(file_header
->name
, &statbuf
) == -1) {
36 if (errno
!= ENOENT
) {
37 bb_perror_msg_and_die("cannot stat old file");
40 else if (statbuf
.st_mtime
<= file_header
->mtime
) {
41 if (!(archive_handle
->ah_flags
& ARCHIVE_EXTRACT_QUIET
)) {
42 bb_error_msg("%s not created: newer or "
43 "same age file exists", file_header
->name
);
45 data_skip(archive_handle
);
48 else if ((unlink(file_header
->name
) == -1) && (errno
!= EISDIR
)) {
49 bb_perror_msg_and_die("cannot remove old file %s",
54 /* Handle hard links separately
55 * We identified hard links as regular files of size 0 with a symlink */
56 if (S_ISREG(file_header
->mode
) && (file_header
->link_target
)
57 && (file_header
->size
== 0)
60 res
= link(file_header
->link_target
, file_header
->name
);
61 if ((res
== -1) && !(archive_handle
->ah_flags
& ARCHIVE_EXTRACT_QUIET
)) {
62 bb_perror_msg("cannot create %slink "
63 "from %s to %s", "hard",
65 file_header
->link_target
);
68 /* Create the filesystem entry */
69 switch (file_header
->mode
& S_IFMT
) {
72 dst_fd
= xopen3(file_header
->name
, O_WRONLY
| O_CREAT
| O_EXCL
,
74 bb_copyfd_exact_size(archive_handle
->src_fd
, dst_fd
, file_header
->size
);
79 res
= mkdir(file_header
->name
, file_header
->mode
);
81 && (errno
!= EISDIR
) /* btw, Linux doesn't return this */
83 && !(archive_handle
->ah_flags
& ARCHIVE_EXTRACT_QUIET
)
85 bb_perror_msg("cannot make dir %s", file_header
->name
);
90 res
= symlink(file_header
->link_target
, file_header
->name
);
92 && !(archive_handle
->ah_flags
& ARCHIVE_EXTRACT_QUIET
)
94 bb_perror_msg("cannot create %slink "
95 "from %s to %s", "sym",
97 file_header
->link_target
);
104 res
= mknod(file_header
->name
, file_header
->mode
, file_header
->device
);
106 && !(archive_handle
->ah_flags
& ARCHIVE_EXTRACT_QUIET
)
108 bb_perror_msg("cannot create node %s", file_header
->name
);
112 bb_error_msg_and_die("unrecognized file type");
116 if (!(archive_handle
->ah_flags
& ARCHIVE_NOPRESERVE_OWN
)) {
117 #if ENABLE_FEATURE_TAR_UNAME_GNAME
118 uid_t uid
= file_header
->uid
;
119 gid_t gid
= file_header
->gid
;
121 if (file_header
->uname
) {
122 struct passwd
*pwd
= getpwnam(file_header
->uname
);
123 if (pwd
) uid
= pwd
->pw_uid
;
125 if (file_header
->gname
) {
126 struct group
*grp
= getgrnam(file_header
->gname
);
127 if (grp
) gid
= grp
->gr_gid
;
129 lchown(file_header
->name
, uid
, gid
);
131 lchown(file_header
->name
, file_header
->uid
, file_header
->gid
);
134 if ((file_header
->mode
& S_IFMT
) != S_IFLNK
) {
135 /* uclibc has no lchmod, glibc is even stranger -
136 * it has lchmod which seems to do nothing!
137 * so we use chmod... */
138 if (!(archive_handle
->ah_flags
& ARCHIVE_NOPRESERVE_PERM
)) {
139 chmod(file_header
->name
, file_header
->mode
);
142 if (archive_handle
->ah_flags
& ARCHIVE_PRESERVE_DATE
) {
144 t
.actime
= t
.modtime
= file_header
->mtime
;
145 utime(file_header
->name
, &t
);