13 |
int res; |
int res; |
14 |
|
|
15 |
if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { |
if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { |
16 |
char *name = xstrdup(file_header->name); |
char *slash = strrchr(file_header->name, '/'); |
17 |
bb_make_directory(dirname(name), -1, FILEUTILS_RECUR); |
if (slash) { |
18 |
free(name); |
*slash = '\0'; |
19 |
|
bb_make_directory(file_header->name, -1, FILEUTILS_RECUR); |
20 |
|
*slash = '/'; |
21 |
|
} |
22 |
} |
} |
23 |
|
|
24 |
/* Check if the file already exists */ |
if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) { |
|
if (archive_handle->ah_flags & ARCHIVE_EXTRACT_UNCONDITIONAL) { |
|
25 |
/* Remove the entry if it exists */ |
/* Remove the entry if it exists */ |
26 |
if (((file_header->mode & S_IFMT) != S_IFDIR) |
if ((!S_ISDIR(file_header->mode)) |
27 |
&& (unlink(file_header->name) == -1) |
&& (unlink(file_header->name) == -1) |
28 |
&& (errno != ENOENT) |
&& (errno != ENOENT) |
29 |
) { |
) { |
30 |
bb_perror_msg_and_die("cannot remove old file %s", |
bb_perror_msg_and_die("can't remove old file %s", |
31 |
file_header->name); |
file_header->name); |
32 |
} |
} |
33 |
} |
} |
34 |
else if (archive_handle->ah_flags & ARCHIVE_EXTRACT_NEWER) { |
else if (archive_handle->ah_flags & ARCHIVE_EXTRACT_NEWER) { |
35 |
/* Remove the existing entry if its older than the extracted entry */ |
/* Remove the existing entry if its older than the extracted entry */ |
36 |
struct stat statbuf; |
struct stat existing_sb; |
37 |
if (lstat(file_header->name, &statbuf) == -1) { |
if (lstat(file_header->name, &existing_sb) == -1) { |
38 |
if (errno != ENOENT) { |
if (errno != ENOENT) { |
39 |
bb_perror_msg_and_die("cannot stat old file"); |
bb_perror_msg_and_die("can't stat old file"); |
40 |
} |
} |
41 |
} |
} |
42 |
else if (statbuf.st_mtime <= file_header->mtime) { |
else if (existing_sb.st_mtime >= file_header->mtime) { |
43 |
if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { |
if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { |
44 |
bb_error_msg("%s not created: newer or " |
bb_error_msg("%s not created: newer or " |
45 |
"same age file exists", file_header->name); |
"same age file exists", file_header->name); |
48 |
return; |
return; |
49 |
} |
} |
50 |
else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) { |
else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) { |
51 |
bb_perror_msg_and_die("cannot remove old file %s", |
bb_perror_msg_and_die("can't remove old file %s", |
52 |
file_header->name); |
file_header->name); |
53 |
} |
} |
54 |
} |
} |
55 |
|
|
56 |
/* Handle hard links separately |
/* Handle hard links separately |
57 |
* We identified hard links as regular files of size 0 with a symlink */ |
* We identified hard links as regular files of size 0 with a symlink */ |
58 |
if (S_ISREG(file_header->mode) && (file_header->link_target) |
if (S_ISREG(file_header->mode) |
59 |
&& (file_header->size == 0) |
&& file_header->link_target |
60 |
|
&& file_header->size == 0 |
61 |
) { |
) { |
62 |
/* hard link */ |
/* hard link */ |
63 |
res = link(file_header->link_target, file_header->name); |
res = link(file_header->link_target, file_header->name); |
64 |
if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { |
if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { |
65 |
bb_perror_msg("cannot create %slink " |
bb_perror_msg("can't create %slink " |
66 |
"from %s to %s", "hard", |
"from %s to %s", "hard", |
67 |
file_header->name, |
file_header->name, |
68 |
file_header->link_target); |
file_header->link_target); |
72 |
switch (file_header->mode & S_IFMT) { |
switch (file_header->mode & S_IFMT) { |
73 |
case S_IFREG: { |
case S_IFREG: { |
74 |
/* Regular file */ |
/* Regular file */ |
75 |
dst_fd = xopen3(file_header->name, O_WRONLY | O_CREAT | O_EXCL, |
int flags = O_WRONLY | O_CREAT | O_EXCL; |
76 |
file_header->mode); |
if (archive_handle->ah_flags & ARCHIVE_O_TRUNC) |
77 |
|
flags = O_WRONLY | O_CREAT | O_TRUNC; |
78 |
|
dst_fd = xopen3(file_header->name, |
79 |
|
flags, |
80 |
|
file_header->mode |
81 |
|
); |
82 |
bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size); |
bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size); |
83 |
close(dst_fd); |
close(dst_fd); |
84 |
break; |
break; |
90 |
&& (errno != EEXIST) |
&& (errno != EEXIST) |
91 |
&& !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) |
&& !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) |
92 |
) { |
) { |
93 |
bb_perror_msg("cannot make dir %s", file_header->name); |
bb_perror_msg("can't make dir %s", file_header->name); |
94 |
} |
} |
95 |
break; |
break; |
96 |
case S_IFLNK: |
case S_IFLNK: |
99 |
if ((res == -1) |
if ((res == -1) |
100 |
&& !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) |
&& !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) |
101 |
) { |
) { |
102 |
bb_perror_msg("cannot create %slink " |
bb_perror_msg("can't create %slink " |
103 |
"from %s to %s", "sym", |
"from %s to %s", "sym", |
104 |
file_header->name, |
file_header->name, |
105 |
file_header->link_target); |
file_header->link_target); |
113 |
if ((res == -1) |
if ((res == -1) |
114 |
&& !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) |
&& !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) |
115 |
) { |
) { |
116 |
bb_perror_msg("cannot create node %s", file_header->name); |
bb_perror_msg("can't create node %s", file_header->name); |
117 |
} |
} |
118 |
break; |
break; |
119 |
default: |
default: |
121 |
} |
} |
122 |
} |
} |
123 |
|
|
124 |
if (!(archive_handle->ah_flags & ARCHIVE_NOPRESERVE_OWN)) { |
if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_OWNER)) { |
125 |
#if ENABLE_FEATURE_TAR_UNAME_GNAME |
#if ENABLE_FEATURE_TAR_UNAME_GNAME |
126 |
uid_t uid = file_header->uid; |
if (!(archive_handle->ah_flags & ARCHIVE_NUMERIC_OWNER)) { |
127 |
gid_t gid = file_header->gid; |
uid_t uid = file_header->uid; |
128 |
|
gid_t gid = file_header->gid; |
129 |
|
|
130 |
if (file_header->uname) { |
if (file_header->tar__uname) { |
131 |
struct passwd *pwd = getpwnam(file_header->uname); |
//TODO: cache last name/id pair? |
132 |
if (pwd) uid = pwd->pw_uid; |
struct passwd *pwd = getpwnam(file_header->tar__uname); |
133 |
} |
if (pwd) uid = pwd->pw_uid; |
134 |
if (file_header->gname) { |
} |
135 |
struct group *grp = getgrnam(file_header->gname); |
if (file_header->tar__gname) { |
136 |
if (grp) gid = grp->gr_gid; |
struct group *grp = getgrnam(file_header->tar__gname); |
137 |
} |
if (grp) gid = grp->gr_gid; |
138 |
lchown(file_header->name, uid, gid); |
} |
139 |
#else |
/* GNU tar 1.15.1 uses chown, not lchown */ |
140 |
lchown(file_header->name, file_header->uid, file_header->gid); |
chown(file_header->name, uid, gid); |
141 |
|
} else |
142 |
#endif |
#endif |
143 |
|
chown(file_header->name, file_header->uid, file_header->gid); |
144 |
} |
} |
145 |
if ((file_header->mode & S_IFMT) != S_IFLNK) { |
if (!S_ISLNK(file_header->mode)) { |
146 |
/* uclibc has no lchmod, glibc is even stranger - |
/* uclibc has no lchmod, glibc is even stranger - |
147 |
* it has lchmod which seems to do nothing! |
* it has lchmod which seems to do nothing! |
148 |
* so we use chmod... */ |
* so we use chmod... */ |
149 |
if (!(archive_handle->ah_flags & ARCHIVE_NOPRESERVE_PERM)) { |
if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_PERM)) { |
150 |
chmod(file_header->name, file_header->mode); |
chmod(file_header->name, file_header->mode); |
151 |
} |
} |
152 |
/* same for utime */ |
/* same for utime */ |
153 |
if (archive_handle->ah_flags & ARCHIVE_PRESERVE_DATE) { |
if (archive_handle->ah_flags & ARCHIVE_RESTORE_DATE) { |
154 |
struct utimbuf t; |
struct timeval t[2]; |
155 |
t.actime = t.modtime = file_header->mtime; |
|
156 |
utime(file_header->name, &t); |
t[1].tv_sec = t[0].tv_sec = file_header->mtime; |
157 |
|
t[1].tv_usec = t[0].tv_usec = 0; |
158 |
|
utimes(file_header->name, t); |
159 |
} |
} |
160 |
} |
} |
161 |
} |
} |