12 |
int dst_fd; |
int dst_fd; |
13 |
int res; |
int res; |
14 |
|
|
15 |
|
#if ENABLE_FEATURE_TAR_SELINUX |
16 |
|
char *sctx = archive_handle->tar__next_file_sctx; |
17 |
|
if (!sctx) |
18 |
|
sctx = archive_handle->tar__global_sctx; |
19 |
|
if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ |
20 |
|
setfscreatecon(sctx); |
21 |
|
free(archive_handle->tar__next_file_sctx); |
22 |
|
archive_handle->tar__next_file_sctx = NULL; |
23 |
|
} |
24 |
|
#endif |
25 |
|
|
26 |
if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { |
if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { |
27 |
char *slash = strrchr(file_header->name, '/'); |
char *slash = strrchr(file_header->name, '/'); |
28 |
if (slash) { |
if (slash) { |
34 |
|
|
35 |
if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) { |
if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) { |
36 |
/* Remove the entry if it exists */ |
/* Remove the entry if it exists */ |
37 |
if ((!S_ISDIR(file_header->mode)) |
if (!S_ISDIR(file_header->mode)) { |
38 |
&& (unlink(file_header->name) == -1) |
/* Is it hardlink? |
39 |
&& (errno != ENOENT) |
* We encode hard links as regular files of size 0 with a symlink */ |
40 |
) { |
if (S_ISREG(file_header->mode) |
41 |
bb_perror_msg_and_die("can't remove old file %s", |
&& file_header->link_target |
42 |
file_header->name); |
&& file_header->size == 0 |
43 |
|
) { |
44 |
|
/* Ugly special case: |
45 |
|
* tar cf t.tar hardlink1 hardlink2 hardlink1 |
46 |
|
* results in this tarball structure: |
47 |
|
* hardlink1 |
48 |
|
* hardlink2 -> hardlink1 |
49 |
|
* hardlink1 -> hardlink1 <== !!! |
50 |
|
*/ |
51 |
|
if (strcmp(file_header->link_target, file_header->name) == 0) |
52 |
|
goto ret; |
53 |
|
} |
54 |
|
/* Proceed with deleting */ |
55 |
|
if (unlink(file_header->name) == -1 |
56 |
|
&& errno != ENOENT |
57 |
|
) { |
58 |
|
bb_perror_msg_and_die("can't remove old file %s", |
59 |
|
file_header->name); |
60 |
|
} |
61 |
} |
} |
62 |
} |
} |
63 |
else if (archive_handle->ah_flags & ARCHIVE_EXTRACT_NEWER) { |
else if (archive_handle->ah_flags & ARCHIVE_EXTRACT_NEWER) { |
74 |
"same age file exists", file_header->name); |
"same age file exists", file_header->name); |
75 |
} |
} |
76 |
data_skip(archive_handle); |
data_skip(archive_handle); |
77 |
return; |
goto ret; |
78 |
} |
} |
79 |
else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) { |
else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) { |
80 |
bb_perror_msg_and_die("can't remove old file %s", |
bb_perror_msg_and_die("can't remove old file %s", |
83 |
} |
} |
84 |
|
|
85 |
/* Handle hard links separately |
/* Handle hard links separately |
86 |
* We identified hard links as regular files of size 0 with a symlink */ |
* We encode hard links as regular files of size 0 with a symlink */ |
87 |
if (S_ISREG(file_header->mode) |
if (S_ISREG(file_header->mode) |
88 |
&& file_header->link_target |
&& file_header->link_target |
89 |
&& file_header->size == 0 |
&& file_header->size == 0 |
96 |
file_header->name, |
file_header->name, |
97 |
file_header->link_target); |
file_header->link_target); |
98 |
} |
} |
99 |
} else { |
/* Hardlinks have no separate mode/ownership, skip chown/chmod */ |
100 |
/* Create the filesystem entry */ |
goto ret; |
101 |
switch (file_header->mode & S_IFMT) { |
} |
102 |
case S_IFREG: { |
|
103 |
/* Regular file */ |
/* Create the filesystem entry */ |
104 |
int flags = O_WRONLY | O_CREAT | O_EXCL; |
switch (file_header->mode & S_IFMT) { |
105 |
if (archive_handle->ah_flags & ARCHIVE_O_TRUNC) |
case S_IFREG: { |
106 |
flags = O_WRONLY | O_CREAT | O_TRUNC; |
/* Regular file */ |
107 |
dst_fd = xopen3(file_header->name, |
int flags = O_WRONLY | O_CREAT | O_EXCL; |
108 |
flags, |
if (archive_handle->ah_flags & ARCHIVE_O_TRUNC) |
109 |
file_header->mode |
flags = O_WRONLY | O_CREAT | O_TRUNC; |
110 |
); |
dst_fd = xopen3(file_header->name, |
111 |
bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size); |
flags, |
112 |
close(dst_fd); |
file_header->mode |
113 |
break; |
); |
114 |
} |
bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size); |
115 |
case S_IFDIR: |
close(dst_fd); |
116 |
res = mkdir(file_header->name, file_header->mode); |
break; |
117 |
if ((res == -1) |
} |
118 |
&& (errno != EISDIR) /* btw, Linux doesn't return this */ |
case S_IFDIR: |
119 |
&& (errno != EEXIST) |
res = mkdir(file_header->name, file_header->mode); |
120 |
&& !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) |
if ((res == -1) |
121 |
) { |
&& (errno != EISDIR) /* btw, Linux doesn't return this */ |
122 |
bb_perror_msg("can't make dir %s", file_header->name); |
&& (errno != EEXIST) |
123 |
} |
&& !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) |
124 |
break; |
) { |
125 |
case S_IFLNK: |
bb_perror_msg("can't make dir %s", file_header->name); |
126 |
/* Symlink */ |
} |
127 |
res = symlink(file_header->link_target, file_header->name); |
break; |
128 |
if ((res == -1) |
case S_IFLNK: |
129 |
&& !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) |
/* Symlink */ |
130 |
) { |
//TODO: what if file_header->link_target == NULL (say, corrupted tarball?) |
131 |
bb_perror_msg("can't create %slink " |
res = symlink(file_header->link_target, file_header->name); |
132 |
"from %s to %s", "sym", |
if ((res == -1) |
133 |
file_header->name, |
&& !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) |
134 |
file_header->link_target); |
) { |
135 |
} |
bb_perror_msg("can't create %slink " |
136 |
break; |
"from %s to %s", "sym", |
137 |
case S_IFSOCK: |
file_header->name, |
138 |
case S_IFBLK: |
file_header->link_target); |
139 |
case S_IFCHR: |
} |
140 |
case S_IFIFO: |
break; |
141 |
res = mknod(file_header->name, file_header->mode, file_header->device); |
case S_IFSOCK: |
142 |
if ((res == -1) |
case S_IFBLK: |
143 |
&& !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) |
case S_IFCHR: |
144 |
) { |
case S_IFIFO: |
145 |
bb_perror_msg("can't create node %s", file_header->name); |
res = mknod(file_header->name, file_header->mode, file_header->device); |
146 |
} |
if ((res == -1) |
147 |
break; |
&& !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) |
148 |
default: |
) { |
149 |
bb_error_msg_and_die("unrecognized file type"); |
bb_perror_msg("can't create node %s", file_header->name); |
150 |
} |
} |
151 |
|
break; |
152 |
|
default: |
153 |
|
bb_error_msg_and_die("unrecognized file type"); |
154 |
} |
} |
155 |
|
|
156 |
if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_OWNER)) { |
if (!S_ISLNK(file_header->mode)) { |
157 |
#if ENABLE_FEATURE_TAR_UNAME_GNAME |
if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_OWNER)) { |
|
if (!(archive_handle->ah_flags & ARCHIVE_NUMERIC_OWNER)) { |
|
158 |
uid_t uid = file_header->uid; |
uid_t uid = file_header->uid; |
159 |
gid_t gid = file_header->gid; |
gid_t gid = file_header->gid; |
160 |
|
#if ENABLE_FEATURE_TAR_UNAME_GNAME |
161 |
if (file_header->tar__uname) { |
if (!(archive_handle->ah_flags & ARCHIVE_NUMERIC_OWNER)) { |
162 |
|
if (file_header->tar__uname) { |
163 |
//TODO: cache last name/id pair? |
//TODO: cache last name/id pair? |
164 |
struct passwd *pwd = getpwnam(file_header->tar__uname); |
struct passwd *pwd = getpwnam(file_header->tar__uname); |
165 |
if (pwd) uid = pwd->pw_uid; |
if (pwd) uid = pwd->pw_uid; |
166 |
} |
} |
167 |
if (file_header->tar__gname) { |
if (file_header->tar__gname) { |
168 |
struct group *grp = getgrnam(file_header->tar__gname); |
struct group *grp = getgrnam(file_header->tar__gname); |
169 |
if (grp) gid = grp->gr_gid; |
if (grp) gid = grp->gr_gid; |
170 |
|
} |
171 |
} |
} |
172 |
|
#endif |
173 |
/* GNU tar 1.15.1 uses chown, not lchown */ |
/* GNU tar 1.15.1 uses chown, not lchown */ |
174 |
chown(file_header->name, uid, gid); |
chown(file_header->name, uid, gid); |
175 |
} else |
} |
|
#endif |
|
|
chown(file_header->name, file_header->uid, file_header->gid); |
|
|
} |
|
|
if (!S_ISLNK(file_header->mode)) { |
|
176 |
/* uclibc has no lchmod, glibc is even stranger - |
/* uclibc has no lchmod, glibc is even stranger - |
177 |
* it has lchmod which seems to do nothing! |
* it has lchmod which seems to do nothing! |
178 |
* so we use chmod... */ |
* so we use chmod... */ |
179 |
if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_PERM)) { |
if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_PERM)) { |
180 |
chmod(file_header->name, file_header->mode); |
chmod(file_header->name, file_header->mode); |
181 |
} |
} |
|
/* same for utime */ |
|
182 |
if (archive_handle->ah_flags & ARCHIVE_RESTORE_DATE) { |
if (archive_handle->ah_flags & ARCHIVE_RESTORE_DATE) { |
183 |
struct timeval t[2]; |
struct timeval t[2]; |
184 |
|
|
187 |
utimes(file_header->name, t); |
utimes(file_header->name, t); |
188 |
} |
} |
189 |
} |
} |
190 |
|
|
191 |
|
ret: ; |
192 |
|
#if ENABLE_FEATURE_TAR_SELINUX |
193 |
|
if (sctx) { |
194 |
|
/* reset the context after creating an entry */ |
195 |
|
setfscreatecon(NULL); |
196 |
|
} |
197 |
|
#endif |
198 |
} |
} |