]>
Commit | Line | Data |
---|---|---|
8f776fd9 | 1 | /*- |
2f3c9ee6 | 2 | * Copyright (c) 2003-2010 Tim Kientzle |
fb67a295 | 3 | * Copyright (c) 2012 Michihiro NAKAJIMA |
8f776fd9 TK |
4 | * All rights reserved. |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer | |
11 | * in this position and unchanged. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | |
15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR | |
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
19 | * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, | |
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
26 | */ | |
27 | ||
28 | #include "archive_platform.h" | |
5b3644c3 MN |
29 | |
30 | #if !defined(_WIN32) || defined(__CYGWIN__) | |
8f776fd9 TK |
31 | |
32 | #ifdef HAVE_SYS_TYPES_H | |
33 | #include <sys/types.h> | |
34 | #endif | |
4d920441 MN |
35 | #ifdef HAVE_SYS_ACL_H |
36 | #include <sys/acl.h> | |
37 | #endif | |
b21f351a TK |
38 | #ifdef HAVE_SYS_EXTATTR_H |
39 | #include <sys/extattr.h> | |
40 | #endif | |
365a91de | 41 | #if HAVE_SYS_XATTR_H |
280540e0 | 42 | #include <sys/xattr.h> |
365a91de | 43 | #elif HAVE_ATTR_XATTR_H |
97bf284c | 44 | #include <attr/xattr.h> |
280540e0 | 45 | #endif |
d4da0242 | 46 | #ifdef HAVE_SYS_EA_H |
0d621852 BJ |
47 | #include <sys/ea.h> |
48 | #endif | |
8f776fd9 TK |
49 | #ifdef HAVE_SYS_IOCTL_H |
50 | #include <sys/ioctl.h> | |
51 | #endif | |
52 | #ifdef HAVE_SYS_STAT_H | |
53 | #include <sys/stat.h> | |
54 | #endif | |
55 | #ifdef HAVE_SYS_TIME_H | |
56 | #include <sys/time.h> | |
57 | #endif | |
58 | #ifdef HAVE_SYS_UTIME_H | |
59 | #include <sys/utime.h> | |
60 | #endif | |
b8ad1655 TK |
61 | #ifdef HAVE_COPYFILE_H |
62 | #include <copyfile.h> | |
63 | #endif | |
8f776fd9 TK |
64 | #ifdef HAVE_ERRNO_H |
65 | #include <errno.h> | |
66 | #endif | |
67 | #ifdef HAVE_FCNTL_H | |
68 | #include <fcntl.h> | |
69 | #endif | |
70 | #ifdef HAVE_GRP_H | |
71 | #include <grp.h> | |
72 | #endif | |
a4b94153 MN |
73 | #ifdef HAVE_LANGINFO_H |
74 | #include <langinfo.h> | |
75 | #endif | |
8f776fd9 TK |
76 | #ifdef HAVE_LINUX_FS_H |
77 | #include <linux/fs.h> /* for Linux file flags */ | |
78 | #endif | |
06710c34 JS |
79 | /* |
80 | * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. | |
81 | * As the include guards don't agree, the order of include is important. | |
82 | */ | |
83 | #ifdef HAVE_LINUX_EXT2_FS_H | |
84 | #include <linux/ext2_fs.h> /* for Linux file flags */ | |
85 | #endif | |
86 | #if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) | |
87 | #include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */ | |
88 | #endif | |
8f776fd9 TK |
89 | #ifdef HAVE_LIMITS_H |
90 | #include <limits.h> | |
91 | #endif | |
92 | #ifdef HAVE_PWD_H | |
93 | #include <pwd.h> | |
94 | #endif | |
95 | #include <stdio.h> | |
96 | #ifdef HAVE_STDLIB_H | |
97 | #include <stdlib.h> | |
98 | #endif | |
99 | #ifdef HAVE_STRING_H | |
100 | #include <string.h> | |
101 | #endif | |
102 | #ifdef HAVE_UNISTD_H | |
103 | #include <unistd.h> | |
104 | #endif | |
105 | #ifdef HAVE_UTIME_H | |
106 | #include <utime.h> | |
107 | #endif | |
631247e1 BJ |
108 | #ifdef F_GETTIMES /* Tru64 specific */ |
109 | #include <sys/fcntl1.h> | |
110 | #endif | |
8f776fd9 | 111 | |
c89d1a1e BS |
112 | /* |
113 | * Macro to cast st_mtime and time_t to an int64 so that 2 numbers can reliably be compared. | |
114 | * | |
115 | * It assumes that the input is an integer type of no more than 64 bits. | |
116 | * If the number is less than zero, t must be a signed type, so it fits in | |
117 | * int64_t. Otherwise, it's a nonnegative value so we can cast it to uint64_t | |
118 | * without loss. But it could be a large unsigned value, so we have to clip it | |
119 | * to INT64_MAX.* | |
120 | */ | |
121 | #define to_int64_time(t) \ | |
122 | ((t) < 0 ? (int64_t)(t) : (uint64_t)(t) > (uint64_t)INT64_MAX ? INT64_MAX : (int64_t)(t)) | |
123 | ||
b8ad1655 TK |
124 | #if __APPLE__ |
125 | #include <TargetConditionals.h> | |
126 | #if TARGET_OS_MAC && !TARGET_OS_EMBEDDED && HAVE_QUARANTINE_H | |
127 | #include <quarantine.h> | |
128 | #define HAVE_QUARANTINE 1 | |
129 | #endif | |
130 | #endif | |
131 | ||
fb67a295 MN |
132 | #ifdef HAVE_ZLIB_H |
133 | #include <zlib.h> | |
134 | #endif | |
135 | ||
b8ad1655 TK |
136 | /* TODO: Support Mac OS 'quarantine' feature. This is really just a |
137 | * standard tag to mark files that have been downloaded as "tainted". | |
138 | * On Mac OS, we should mark the extracted files as tainted if the | |
139 | * archive being read was tainted. Windows has a similar feature; we | |
140 | * should investigate ways to support this generically. */ | |
141 | ||
8f776fd9 | 142 | #include "archive.h" |
ec502e2d | 143 | #include "archive_acl_private.h" |
8f776fd9 | 144 | #include "archive_string.h" |
fb67a295 | 145 | #include "archive_endian.h" |
8f776fd9 TK |
146 | #include "archive_entry.h" |
147 | #include "archive_private.h" | |
f67370d5 | 148 | #include "archive_write_disk_private.h" |
8f776fd9 TK |
149 | |
150 | #ifndef O_BINARY | |
151 | #define O_BINARY 0 | |
152 | #endif | |
60141df1 | 153 | #ifndef O_CLOEXEC |
9f0dee22 TK |
154 | #define O_CLOEXEC 0 |
155 | #endif | |
156 | ||
157 | /* Ignore non-int O_NOFOLLOW constant. */ | |
158 | /* gnulib's fcntl.h does this on AIX, but it seems practical everywhere */ | |
159 | #if defined O_NOFOLLOW && !(INT_MIN <= O_NOFOLLOW && O_NOFOLLOW <= INT_MAX) | |
160 | #undef O_NOFOLLOW | |
161 | #endif | |
162 | ||
163 | #ifndef O_NOFOLLOW | |
164 | #define O_NOFOLLOW 0 | |
60141df1 | 165 | #endif |
8f776fd9 | 166 | |
b6655592 MM |
167 | #ifndef AT_FDCWD |
168 | #define AT_FDCWD -100 | |
169 | #endif | |
170 | ||
8f776fd9 TK |
171 | struct fixup_entry { |
172 | struct fixup_entry *next; | |
b01b4bc1 | 173 | struct archive_acl acl; |
8f776fd9 | 174 | mode_t mode; |
ede459d2 | 175 | __LA_MODE_T filetype; |
8f776fd9 | 176 | int64_t atime; |
82e3bb2a TK |
177 | int64_t birthtime; |
178 | int64_t mtime; | |
b648c6c7 | 179 | int64_t ctime; |
8f776fd9 | 180 | unsigned long atime_nanos; |
82e3bb2a TK |
181 | unsigned long birthtime_nanos; |
182 | unsigned long mtime_nanos; | |
b648c6c7 | 183 | unsigned long ctime_nanos; |
8f776fd9 | 184 | unsigned long fflags_set; |
b8ad1655 TK |
185 | size_t mac_metadata_size; |
186 | void *mac_metadata; | |
8f776fd9 TK |
187 | int fixup; /* bitmask of what needs fixing */ |
188 | char *name; | |
189 | }; | |
190 | ||
191 | /* | |
192 | * We use a bitmask to track which operations remain to be done for | |
193 | * this file. In particular, this helps us avoid unnecessary | |
194 | * operations when it's possible to take care of one step as a | |
195 | * side-effect of another. For example, mkdir() can specify the mode | |
196 | * for the newly-created object but symlink() cannot. This means we | |
197 | * can skip chmod() if mkdir() succeeded, but we must explicitly | |
198 | * chmod() if we're trying to create a directory that already exists | |
199 | * (mkdir() failed) or if we're restoring a symlink. Similarly, we | |
200 | * need to verify UID/GID before trying to restore SUID/SGID bits; | |
201 | * that verification can occur explicitly through a stat() call or | |
202 | * implicitly because of a successful chown() call. | |
203 | */ | |
204 | #define TODO_MODE_FORCE 0x40000000 | |
205 | #define TODO_MODE_BASE 0x20000000 | |
206 | #define TODO_SUID 0x10000000 | |
207 | #define TODO_SUID_CHECK 0x08000000 | |
208 | #define TODO_SGID 0x04000000 | |
209 | #define TODO_SGID_CHECK 0x02000000 | |
a70241b7 | 210 | #define TODO_APPLEDOUBLE 0x01000000 |
8f776fd9 TK |
211 | #define TODO_MODE (TODO_MODE_BASE|TODO_SUID|TODO_SGID) |
212 | #define TODO_TIMES ARCHIVE_EXTRACT_TIME | |
213 | #define TODO_OWNER ARCHIVE_EXTRACT_OWNER | |
214 | #define TODO_FFLAGS ARCHIVE_EXTRACT_FFLAGS | |
215 | #define TODO_ACLS ARCHIVE_EXTRACT_ACL | |
216 | #define TODO_XATTR ARCHIVE_EXTRACT_XATTR | |
b8ad1655 | 217 | #define TODO_MAC_METADATA ARCHIVE_EXTRACT_MAC_METADATA |
6238bed6 | 218 | #define TODO_HFS_COMPRESSION ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED |
8f776fd9 TK |
219 | |
220 | struct archive_write_disk { | |
221 | struct archive archive; | |
222 | ||
223 | mode_t user_umask; | |
224 | struct fixup_entry *fixup_list; | |
225 | struct fixup_entry *current_fixup; | |
73f39d90 | 226 | int64_t user_uid; |
7457cf54 | 227 | int skip_file_set; |
7d2cbbc5 MN |
228 | int64_t skip_file_dev; |
229 | int64_t skip_file_ino; | |
da0cee61 | 230 | time_t start_time; |
8f776fd9 | 231 | |
73f39d90 | 232 | int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid); |
8f776fd9 TK |
233 | void (*cleanup_gid)(void *private); |
234 | void *lookup_gid_data; | |
73f39d90 | 235 | int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid); |
8f776fd9 TK |
236 | void (*cleanup_uid)(void *private); |
237 | void *lookup_uid_data; | |
238 | ||
239 | /* | |
240 | * Full path of last file to satisfy symlink checks. | |
241 | */ | |
242 | struct archive_string path_safe; | |
243 | ||
244 | /* | |
245 | * Cached stat data from disk for the current entry. | |
246 | * If this is valid, pst points to st. Otherwise, | |
247 | * pst is null. | |
248 | */ | |
249 | struct stat st; | |
250 | struct stat *pst; | |
251 | ||
252 | /* Information about the object being restored right now. */ | |
253 | struct archive_entry *entry; /* Entry being extracted. */ | |
254 | char *name; /* Name of entry, possibly edited. */ | |
255 | struct archive_string _name_data; /* backing store for 'name' */ | |
b51d6b62 | 256 | char *tmpname; /* Temporary name * */ |
257 | struct archive_string _tmpname_data; /* backing store for 'tmpname' */ | |
8f776fd9 TK |
258 | /* Tasks remaining for this object. */ |
259 | int todo; | |
260 | /* Tasks deferred until end-of-archive. */ | |
261 | int deferred; | |
262 | /* Options requested by the client. */ | |
263 | int flags; | |
264 | /* Handle for the file we're restoring. */ | |
265 | int fd; | |
266 | /* Current offset for writing data to the file. */ | |
911dc2bf | 267 | int64_t offset; |
b6c8e140 | 268 | /* Last offset actually written to disk. */ |
911dc2bf TK |
269 | int64_t fd_offset; |
270 | /* Total bytes actually written to files. */ | |
271 | int64_t total_bytes_written; | |
5b5d1d58 | 272 | /* Maximum size of file, -1 if unknown. */ |
911dc2bf | 273 | int64_t filesize; |
8f776fd9 TK |
274 | /* Dir we were in before this restore; only for deep paths. */ |
275 | int restore_pwd; | |
276 | /* Mode we should use for this entry; affected by _PERM and umask. */ | |
277 | mode_t mode; | |
278 | /* UID/GID to use in restoring this entry. */ | |
73f39d90 TK |
279 | int64_t uid; |
280 | int64_t gid; | |
fb67a295 MN |
281 | /* |
282 | * HFS+ Compression. | |
283 | */ | |
fb67a295 | 284 | /* Xattr "com.apple.decmpfs". */ |
3c8570c2 MN |
285 | uint32_t decmpfs_attr_size; |
286 | unsigned char *decmpfs_header_p; | |
fb67a295 MN |
287 | /* ResourceFork set options used for fsetxattr. */ |
288 | int rsrc_xattr_options; | |
289 | /* Xattr "com.apple.ResourceFork". */ | |
290 | unsigned char *resource_fork; | |
291 | size_t resource_fork_allocated_size; | |
292 | unsigned int decmpfs_block_count; | |
293 | uint32_t *decmpfs_block_info; | |
294 | /* Buffer for compressed data. */ | |
295 | unsigned char *compressed_buffer; | |
296 | size_t compressed_buffer_size; | |
297 | size_t compressed_buffer_remaining; | |
298 | /* The offset of the ResourceFork where compressed data will | |
299 | * be placed. */ | |
300 | uint32_t compressed_rsrc_position; | |
fe61ff64 | 301 | uint32_t compressed_rsrc_position_v; |
fb67a295 MN |
302 | /* Buffer for uncompressed data. */ |
303 | char *uncompressed_buffer; | |
304 | size_t block_remaining_bytes; | |
305 | size_t file_remaining_bytes; | |
306 | #ifdef HAVE_ZLIB_H | |
307 | z_stream stream; | |
308 | int stream_valid; | |
309 | int decmpfs_compression_level; | |
310 | #endif | |
8f776fd9 TK |
311 | }; |
312 | ||
313 | /* | |
314 | * Default mode for dirs created automatically (will be modified by umask). | |
cafcd565 | 315 | * Note that POSIX specifies 0777 for implicitly-created dirs, "modified |
8f776fd9 TK |
316 | * by the process' file creation mask." |
317 | */ | |
318 | #define DEFAULT_DIR_MODE 0777 | |
319 | /* | |
320 | * Dir modes are restored in two steps: During the extraction, the permissions | |
321 | * in the archive are modified to match the following limits. During | |
322 | * the post-extract fixup pass, the permissions from the archive are | |
323 | * applied. | |
324 | */ | |
325 | #define MINIMUM_DIR_MODE 0700 | |
326 | #define MAXIMUM_DIR_MODE 0775 | |
327 | ||
fb67a295 | 328 | /* |
0b29066b | 329 | * Maximum uncompressed size of a decmpfs block. |
fb67a295 MN |
330 | */ |
331 | #define MAX_DECMPFS_BLOCK_SIZE (64 * 1024) | |
332 | /* | |
333 | * HFS+ compression type. | |
334 | */ | |
335 | #define CMP_XATTR 3/* Compressed data in xattr. */ | |
336 | #define CMP_RESOURCE_FORK 4/* Compressed data in resource fork. */ | |
337 | /* | |
338 | * HFS+ compression resource fork. | |
339 | */ | |
340 | #define RSRC_H_SIZE 260 /* Base size of Resource fork header. */ | |
341 | #define RSRC_F_SIZE 50 /* Size of Resource fork footer. */ | |
342 | /* Size to write compressed data to resource fork. */ | |
343 | #define COMPRESSED_W_SIZE (64 * 1024) | |
0b29066b | 344 | /* decmpfs definitions. */ |
3c8570c2 MN |
345 | #define MAX_DECMPFS_XATTR_SIZE 3802 |
346 | #ifndef DECMPFS_XATTR_NAME | |
347 | #define DECMPFS_XATTR_NAME "com.apple.decmpfs" | |
348 | #endif | |
349 | #define DECMPFS_MAGIC 0x636d7066 | |
350 | #define DECMPFS_COMPRESSION_MAGIC 0 | |
351 | #define DECMPFS_COMPRESSION_TYPE 4 | |
352 | #define DECMPFS_UNCOMPRESSED_SIZE 8 | |
353 | #define DECMPFS_HEADER_SIZE 16 | |
fb67a295 | 354 | |
8f7fbd41 | 355 | #define HFS_BLOCKS(s) ((s) >> 12) |
fb67a295 | 356 | |
b6655592 MM |
357 | |
358 | static int la_opendirat(int, const char *); | |
b51d6b62 | 359 | static int la_mktemp(struct archive_write_disk *); |
ede459d2 | 360 | static int la_verify_filetype(mode_t, __LA_MODE_T); |
1bed2f31 MM |
361 | static void fsobj_error(int *, struct archive_string *, int, const char *, |
362 | const char *); | |
363 | static int check_symlinks_fsobj(char *, int *, struct archive_string *, | |
5e646b89 | 364 | int, int); |
8f776fd9 TK |
365 | static int check_symlinks(struct archive_write_disk *); |
366 | static int create_filesystem_object(struct archive_write_disk *); | |
cc9cbbb1 MM |
367 | static struct fixup_entry *current_fixup(struct archive_write_disk *, |
368 | const char *pathname); | |
29dfb1f6 | 369 | #if defined(HAVE_FCHDIR) && defined(PATH_MAX) |
8f776fd9 TK |
370 | static void edit_deep_directories(struct archive_write_disk *ad); |
371 | #endif | |
1bed2f31 MM |
372 | static int cleanup_pathname_fsobj(char *, int *, struct archive_string *, |
373 | int); | |
8f776fd9 TK |
374 | static int cleanup_pathname(struct archive_write_disk *); |
375 | static int create_dir(struct archive_write_disk *, char *); | |
376 | static int create_parent_dir(struct archive_write_disk *, char *); | |
fb67a295 MN |
377 | static ssize_t hfs_write_data_block(struct archive_write_disk *, |
378 | const char *, size_t); | |
a70241b7 | 379 | static int fixup_appledouble(struct archive_write_disk *, const char *); |
8f776fd9 TK |
380 | static int older(struct stat *, struct archive_entry *); |
381 | static int restore_entry(struct archive_write_disk *); | |
b8ad1655 TK |
382 | static int set_mac_metadata(struct archive_write_disk *, const char *, |
383 | const void *, size_t); | |
8f776fd9 | 384 | static int set_xattrs(struct archive_write_disk *); |
6a595ef6 | 385 | static int clear_nochange_fflags(struct archive_write_disk *); |
8f776fd9 TK |
386 | static int set_fflags(struct archive_write_disk *); |
387 | static int set_fflags_platform(struct archive_write_disk *, int fd, | |
388 | const char *name, mode_t mode, | |
389 | unsigned long fflags_set, unsigned long fflags_clear); | |
390 | static int set_ownership(struct archive_write_disk *); | |
391 | static int set_mode(struct archive_write_disk *, int mode); | |
82e3bb2a | 392 | static int set_time(int, int, const char *, time_t, long, time_t, long); |
21ebff3b | 393 | static int set_times(struct archive_write_disk *, int, int, const char *, |
b648c6c7 | 394 | time_t, long, time_t, long, time_t, long, time_t, long); |
5223514b | 395 | static int set_times_from_entry(struct archive_write_disk *); |
8f776fd9 | 396 | static struct fixup_entry *sort_dir_list(struct fixup_entry *p); |
5b5d1d58 | 397 | static ssize_t write_data_block(struct archive_write_disk *, |
b6c8e140 | 398 | const char *, size_t); |
0cb9df7f | 399 | static void close_file_descriptor(struct archive_write_disk *); |
8f776fd9 | 400 | |
911dc2bf TK |
401 | static int _archive_write_disk_close(struct archive *); |
402 | static int _archive_write_disk_free(struct archive *); | |
cc9cbbb1 MM |
403 | static int _archive_write_disk_header(struct archive *, |
404 | struct archive_entry *); | |
911dc2bf TK |
405 | static int64_t _archive_write_disk_filter_bytes(struct archive *, int); |
406 | static int _archive_write_disk_finish_entry(struct archive *); | |
cc9cbbb1 MM |
407 | static ssize_t _archive_write_disk_data(struct archive *, const void *, |
408 | size_t); | |
409 | static ssize_t _archive_write_disk_data_block(struct archive *, const void *, | |
410 | size_t, int64_t); | |
8f776fd9 | 411 | |
b51d6b62 | 412 | static int |
413 | la_mktemp(struct archive_write_disk *a) | |
414 | { | |
415 | int oerrno, fd; | |
416 | mode_t mode; | |
417 | ||
418 | archive_string_empty(&a->_tmpname_data); | |
419 | archive_string_sprintf(&a->_tmpname_data, "%s.XXXXXX", a->name); | |
420 | a->tmpname = a->_tmpname_data.s; | |
421 | ||
422 | fd = __archive_mkstemp(a->tmpname); | |
423 | if (fd == -1) | |
424 | return -1; | |
425 | ||
426 | mode = a->mode & 0777 & ~a->user_umask; | |
427 | if (fchmod(fd, mode) == -1) { | |
428 | oerrno = errno; | |
429 | close(fd); | |
430 | errno = oerrno; | |
431 | return -1; | |
432 | } | |
433 | return fd; | |
434 | } | |
435 | ||
b6655592 MM |
436 | static int |
437 | la_opendirat(int fd, const char *path) { | |
438 | const int flags = O_CLOEXEC | |
439 | #if defined(O_BINARY) | |
440 | | O_BINARY | |
441 | #endif | |
442 | #if defined(O_DIRECTORY) | |
443 | | O_DIRECTORY | |
444 | #endif | |
445 | #if defined(O_PATH) | |
446 | | O_PATH | |
447 | #elif defined(O_SEARCH) | |
448 | | O_SEARCH | |
16ad251f | 449 | #elif defined(__FreeBSD__) && defined(O_EXEC) |
b6655592 MM |
450 | | O_EXEC |
451 | #else | |
452 | | O_RDONLY | |
453 | #endif | |
454 | ; | |
455 | ||
456 | #if !defined(HAVE_OPENAT) | |
457 | if (fd != AT_FDCWD) { | |
458 | errno = ENOTSUP; | |
459 | return (-1); | |
460 | } else | |
36c675a4 | 461 | return (open(path, flags)); |
b6655592 MM |
462 | #else |
463 | return (openat(fd, path, flags)); | |
464 | #endif | |
465 | } | |
466 | ||
ede459d2 MM |
467 | static int |
468 | la_verify_filetype(mode_t mode, __LA_MODE_T filetype) { | |
469 | int ret = 0; | |
470 | ||
471 | switch (filetype) { | |
472 | case AE_IFREG: | |
473 | ret = (S_ISREG(mode)); | |
474 | break; | |
475 | case AE_IFDIR: | |
476 | ret = (S_ISDIR(mode)); | |
477 | break; | |
478 | case AE_IFLNK: | |
479 | ret = (S_ISLNK(mode)); | |
480 | break; | |
481 | case AE_IFSOCK: | |
482 | ret = (S_ISSOCK(mode)); | |
483 | break; | |
484 | case AE_IFCHR: | |
485 | ret = (S_ISCHR(mode)); | |
486 | break; | |
487 | case AE_IFBLK: | |
488 | ret = (S_ISBLK(mode)); | |
489 | break; | |
490 | case AE_IFIFO: | |
491 | ret = (S_ISFIFO(mode)); | |
492 | break; | |
493 | default: | |
494 | break; | |
495 | } | |
496 | ||
497 | return (ret); | |
498 | } | |
499 | ||
2f8873c2 | 500 | static int |
911dc2bf | 501 | lazy_stat(struct archive_write_disk *a) |
2f8873c2 JS |
502 | { |
503 | if (a->pst != NULL) { | |
504 | /* Already have stat() data available. */ | |
505 | return (ARCHIVE_OK); | |
506 | } | |
507 | #ifdef HAVE_FSTAT | |
508 | if (a->fd >= 0 && fstat(a->fd, &a->st) == 0) { | |
509 | a->pst = &a->st; | |
510 | return (ARCHIVE_OK); | |
511 | } | |
512 | #endif | |
513 | /* | |
514 | * XXX At this point, symlinks should not be hit, otherwise | |
cafcd565 | 515 | * XXX a race occurred. Do we want to check explicitly for that? |
2f8873c2 | 516 | */ |
e6056040 | 517 | #ifdef HAVE_LSTAT |
518 | if (lstat(a->name, &a->st) == 0) | |
519 | #else | |
520 | if (la_stat(a->name, &a->st) == 0) | |
521 | #endif | |
522 | { | |
2f8873c2 JS |
523 | a->pst = &a->st; |
524 | return (ARCHIVE_OK); | |
525 | } | |
526 | archive_set_error(&a->archive, errno, "Couldn't stat file"); | |
527 | return (ARCHIVE_WARN); | |
528 | } | |
529 | ||
ee99f7fc EV |
530 | static const struct archive_vtable |
531 | archive_write_disk_vtable = { | |
532 | .archive_close = _archive_write_disk_close, | |
533 | .archive_filter_bytes = _archive_write_disk_filter_bytes, | |
534 | .archive_free = _archive_write_disk_free, | |
535 | .archive_write_header = _archive_write_disk_header, | |
536 | .archive_write_finish_entry = _archive_write_disk_finish_entry, | |
537 | .archive_write_data = _archive_write_disk_data, | |
538 | .archive_write_data_block = _archive_write_disk_data_block, | |
539 | }; | |
8f776fd9 | 540 | |
911dc2bf TK |
541 | static int64_t |
542 | _archive_write_disk_filter_bytes(struct archive *_a, int n) | |
543 | { | |
911dc2bf | 544 | struct archive_write_disk *a = (struct archive_write_disk *)_a; |
0eb2fe95 | 545 | (void)n; /* UNUSED */ |
911dc2bf TK |
546 | if (n == -1 || n == 0) |
547 | return (a->total_bytes_written); | |
548 | return (-1); | |
549 | } | |
550 | ||
8f776fd9 TK |
551 | |
552 | int | |
553 | archive_write_disk_set_options(struct archive *_a, int flags) | |
554 | { | |
555 | struct archive_write_disk *a = (struct archive_write_disk *)_a; | |
556 | ||
557 | a->flags = flags; | |
558 | return (ARCHIVE_OK); | |
559 | } | |
560 | ||
561 | ||
562 | /* | |
563 | * Extract this entry to disk. | |
564 | * | |
565 | * TODO: Validate hardlinks. According to the standards, we're | |
566 | * supposed to check each extracted hardlink and squawk if it refers | |
567 | * to a file that we didn't restore. I'm not entirely convinced this | |
568 | * is a good idea, but more importantly: Is there any way to validate | |
569 | * hardlinks without keeping a complete list of filenames from the | |
570 | * entire archive?? Ugh. | |
571 | * | |
572 | */ | |
573 | static int | |
911dc2bf | 574 | _archive_write_disk_header(struct archive *_a, struct archive_entry *entry) |
8f776fd9 TK |
575 | { |
576 | struct archive_write_disk *a = (struct archive_write_disk *)_a; | |
577 | struct fixup_entry *fe; | |
b3073af2 | 578 | const char *linkname; |
8f776fd9 TK |
579 | int ret, r; |
580 | ||
42c1f3e1 | 581 | archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, |
8f776fd9 TK |
582 | ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, |
583 | "archive_write_disk_header"); | |
584 | archive_clear_error(&a->archive); | |
585 | if (a->archive.state & ARCHIVE_STATE_DATA) { | |
911dc2bf | 586 | r = _archive_write_disk_finish_entry(&a->archive); |
9d2e02e2 | 587 | if (r == ARCHIVE_FATAL) |
8f776fd9 TK |
588 | return (r); |
589 | } | |
590 | ||
591 | /* Set up for this particular entry. */ | |
592 | a->pst = NULL; | |
593 | a->current_fixup = NULL; | |
594 | a->deferred = 0; | |
595 | if (a->entry) { | |
596 | archive_entry_free(a->entry); | |
597 | a->entry = NULL; | |
598 | } | |
599 | a->entry = archive_entry_clone(entry); | |
600 | a->fd = -1; | |
b6c8e140 | 601 | a->fd_offset = 0; |
8f776fd9 | 602 | a->offset = 0; |
fa32d137 | 603 | a->restore_pwd = -1; |
8f776fd9 TK |
604 | a->uid = a->user_uid; |
605 | a->mode = archive_entry_mode(a->entry); | |
5b5d1d58 TK |
606 | if (archive_entry_size_is_set(a->entry)) |
607 | a->filesize = archive_entry_size(a->entry); | |
608 | else | |
609 | a->filesize = -1; | |
8f776fd9 TK |
610 | archive_strcpy(&(a->_name_data), archive_entry_pathname(a->entry)); |
611 | a->name = a->_name_data.s; | |
612 | archive_clear_error(&a->archive); | |
613 | ||
614 | /* | |
615 | * Clean up the requested path. This is necessary for correct | |
616 | * dir restores; the dir restore logic otherwise gets messed | |
617 | * up by nonsense like "dir/.". | |
618 | */ | |
619 | ret = cleanup_pathname(a); | |
620 | if (ret != ARCHIVE_OK) | |
621 | return (ret); | |
622 | ||
b3073af2 MM |
623 | /* |
624 | * Check if we have a hardlink that points to itself. | |
625 | */ | |
626 | linkname = archive_entry_hardlink(a->entry); | |
627 | if (linkname != NULL && strcmp(a->name, linkname) == 0) { | |
628 | archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, | |
629 | "Skipping hardlink pointing to itself: %s", | |
630 | a->name); | |
631 | return (ARCHIVE_WARN); | |
632 | } | |
633 | ||
8f776fd9 | 634 | /* |
efaf972d | 635 | * Query the umask so we get predictable mode settings. |
8f776fd9 TK |
636 | * This gets done on every call to _write_header in case the |
637 | * user edits their umask during the extraction for some | |
efaf972d | 638 | * reason. |
8f776fd9 | 639 | */ |
efaf972d | 640 | umask(a->user_umask = umask(0)); |
8f776fd9 TK |
641 | |
642 | /* Figure out what we need to do for this entry. */ | |
643 | a->todo = TODO_MODE_BASE; | |
644 | if (a->flags & ARCHIVE_EXTRACT_PERM) { | |
645 | a->todo |= TODO_MODE_FORCE; /* Be pushy about permissions. */ | |
646 | /* | |
647 | * SGID requires an extra "check" step because we | |
648 | * cannot easily predict the GID that the system will | |
649 | * assign. (Different systems assign GIDs to files | |
650 | * based on a variety of criteria, including process | |
651 | * credentials and the gid of the enclosing | |
652 | * directory.) We can only restore the SGID bit if | |
653 | * the file has the right GID, and we only know the | |
654 | * GID if we either set it (see set_ownership) or if | |
655 | * we've actually called stat() on the file after it | |
656 | * was restored. Since there are several places at | |
657 | * which we might verify the GID, we need a TODO bit | |
658 | * to keep track. | |
659 | */ | |
660 | if (a->mode & S_ISGID) | |
661 | a->todo |= TODO_SGID | TODO_SGID_CHECK; | |
662 | /* | |
663 | * Verifying the SUID is simpler, but can still be | |
664 | * done in multiple ways, hence the separate "check" bit. | |
665 | */ | |
666 | if (a->mode & S_ISUID) | |
667 | a->todo |= TODO_SUID | TODO_SUID_CHECK; | |
668 | } else { | |
669 | /* | |
670 | * User didn't request full permissions, so don't | |
671 | * restore SUID, SGID bits and obey umask. | |
672 | */ | |
673 | a->mode &= ~S_ISUID; | |
674 | a->mode &= ~S_ISGID; | |
675 | a->mode &= ~S_ISVTX; | |
676 | a->mode &= ~a->user_umask; | |
677 | } | |
678 | if (a->flags & ARCHIVE_EXTRACT_OWNER) | |
679 | a->todo |= TODO_OWNER; | |
680 | if (a->flags & ARCHIVE_EXTRACT_TIME) | |
681 | a->todo |= TODO_TIMES; | |
b01b4bc1 | 682 | if (a->flags & ARCHIVE_EXTRACT_ACL) { |
bea9f9cf MM |
683 | #if ARCHIVE_ACL_DARWIN |
684 | /* | |
685 | * On MacOS, platform ACLs get stored in mac_metadata, too. | |
686 | * If we intend to extract mac_metadata and it is present | |
687 | * we skip extracting libarchive NFSv4 ACLs. | |
688 | */ | |
689 | size_t metadata_size; | |
690 | ||
691 | if ((a->flags & ARCHIVE_EXTRACT_MAC_METADATA) == 0 || | |
692 | archive_entry_mac_metadata(a->entry, | |
693 | &metadata_size) == NULL || metadata_size == 0) | |
694 | #endif | |
695 | #if ARCHIVE_ACL_LIBRICHACL | |
696 | /* | |
697 | * RichACLs are stored in an extended attribute. | |
698 | * If we intend to extract extended attributes and have this | |
699 | * attribute we skip extracting libarchive NFSv4 ACLs. | |
700 | */ | |
701 | short extract_acls = 1; | |
702 | if (a->flags & ARCHIVE_EXTRACT_XATTR && ( | |
703 | archive_entry_acl_types(a->entry) & | |
704 | ARCHIVE_ENTRY_ACL_TYPE_NFS4)) { | |
705 | const char *attr_name; | |
706 | const void *attr_value; | |
707 | size_t attr_size; | |
708 | int i = archive_entry_xattr_reset(a->entry); | |
709 | while (i--) { | |
710 | archive_entry_xattr_next(a->entry, &attr_name, | |
711 | &attr_value, &attr_size); | |
712 | if (attr_name != NULL && attr_value != NULL && | |
713 | attr_size > 0 && strcmp(attr_name, | |
714 | "trusted.richacl") == 0) { | |
715 | extract_acls = 0; | |
716 | break; | |
717 | } | |
718 | } | |
719 | } | |
720 | if (extract_acls) | |
721 | #endif | |
722 | #if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL | |
723 | { | |
724 | #endif | |
b01b4bc1 TK |
725 | if (archive_entry_filetype(a->entry) == AE_IFDIR) |
726 | a->deferred |= TODO_ACLS; | |
727 | else | |
728 | a->todo |= TODO_ACLS; | |
bea9f9cf MM |
729 | #if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL |
730 | } | |
731 | #endif | |
b01b4bc1 | 732 | } |
b8ad1655 TK |
733 | if (a->flags & ARCHIVE_EXTRACT_MAC_METADATA) { |
734 | if (archive_entry_filetype(a->entry) == AE_IFDIR) | |
735 | a->deferred |= TODO_MAC_METADATA; | |
736 | else | |
737 | a->todo |= TODO_MAC_METADATA; | |
738 | } | |
213a263c | 739 | #if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H) |
6238bed6 MN |
740 | if ((a->flags & ARCHIVE_EXTRACT_NO_HFS_COMPRESSION) == 0) { |
741 | unsigned long set, clear; | |
742 | archive_entry_fflags(a->entry, &set, &clear); | |
743 | if ((set & ~clear) & UF_COMPRESSED) { | |
cfb7792c | 744 | a->todo |= TODO_HFS_COMPRESSION; |
6238bed6 MN |
745 | a->decmpfs_block_count = (unsigned)-1; |
746 | } | |
747 | } | |
748 | if ((a->flags & ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED) != 0 && | |
fb67a295 | 749 | (a->mode & AE_IFMT) == AE_IFREG && a->filesize > 0) { |
cfb7792c | 750 | a->todo |= TODO_HFS_COMPRESSION; |
fb67a295 MN |
751 | a->decmpfs_block_count = (unsigned)-1; |
752 | } | |
a70241b7 MN |
753 | { |
754 | const char *p; | |
755 | ||
756 | /* Check if the current file name is a type of the | |
757 | * resource fork file. */ | |
758 | p = strrchr(a->name, '/'); | |
759 | if (p == NULL) | |
760 | p = a->name; | |
761 | else | |
762 | p++; | |
763 | if (p[0] == '.' && p[1] == '_') { | |
764 | /* Do not compress "._XXX" files. */ | |
765 | a->todo &= ~TODO_HFS_COMPRESSION; | |
766 | if (a->filesize > 0) | |
767 | a->todo |= TODO_APPLEDOUBLE; | |
768 | } | |
769 | } | |
6238bed6 MN |
770 | #endif |
771 | ||
365a91de MM |
772 | if (a->flags & ARCHIVE_EXTRACT_XATTR) { |
773 | #if ARCHIVE_XATTR_DARWIN | |
774 | /* | |
775 | * On MacOS, extended attributes get stored in mac_metadata, | |
776 | * too. If we intend to extract mac_metadata and it is present | |
777 | * we skip extracting extended attributes. | |
778 | */ | |
779 | size_t metadata_size; | |
780 | ||
781 | if ((a->flags & ARCHIVE_EXTRACT_MAC_METADATA) == 0 || | |
782 | archive_entry_mac_metadata(a->entry, | |
783 | &metadata_size) == NULL || metadata_size == 0) | |
784 | #endif | |
b21f351a | 785 | a->todo |= TODO_XATTR; |
365a91de | 786 | } |
8f776fd9 TK |
787 | if (a->flags & ARCHIVE_EXTRACT_FFLAGS) |
788 | a->todo |= TODO_FFLAGS; | |
789 | if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) { | |
790 | ret = check_symlinks(a); | |
791 | if (ret != ARCHIVE_OK) | |
efaf972d | 792 | return (ret); |
8f776fd9 | 793 | } |
bbb7fde3 | 794 | #if defined(HAVE_FCHDIR) && defined(PATH_MAX) |
8f776fd9 TK |
795 | /* If path exceeds PATH_MAX, shorten the path. */ |
796 | edit_deep_directories(a); | |
797 | #endif | |
798 | ||
799 | ret = restore_entry(a); | |
800 | ||
213a263c | 801 | #if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H) |
cb02c0ff MN |
802 | /* |
803 | * Check if the filesystem the file is restoring on supports | |
804 | * HFS+ Compression. If not, cancel HFS+ Compression. | |
805 | */ | |
806 | if (a->todo | TODO_HFS_COMPRESSION) { | |
807 | /* | |
808 | * NOTE: UF_COMPRESSED is ignored even if the filesystem | |
809 | * supports HFS+ Compression because the file should | |
0b29066b | 810 | * have at least an extended attribute "com.apple.decmpfs" |
cb02c0ff | 811 | * before the flag is set to indicate that the file have |
0b29066b | 812 | * been compressed. If the filesystem does not support |
cb02c0ff MN |
813 | * HFS+ Compression the system call will fail. |
814 | */ | |
815 | if (a->fd < 0 || fchflags(a->fd, UF_COMPRESSED) != 0) | |
816 | a->todo &= ~TODO_HFS_COMPRESSION; | |
817 | } | |
818 | #endif | |
819 | ||
b21f351a | 820 | /* |
26f63f45 TK |
821 | * TODO: There are rumours that some extended attributes must |
822 | * be restored before file data is written. If this is true, | |
823 | * then we either need to write all extended attributes both | |
824 | * before and after restoring the data, or find some rule for | |
825 | * determining which must go first and which last. Due to the | |
826 | * many ways people are using xattrs, this may prove to be an | |
827 | * intractable problem. | |
b21f351a | 828 | */ |
b21f351a | 829 | |
8f776fd9 TK |
830 | #ifdef HAVE_FCHDIR |
831 | /* If we changed directory above, restore it here. */ | |
832 | if (a->restore_pwd >= 0) { | |
b7f3d08e TK |
833 | r = fchdir(a->restore_pwd); |
834 | if (r != 0) { | |
cc9cbbb1 MM |
835 | archive_set_error(&a->archive, errno, |
836 | "chdir() failure"); | |
b7f3d08e TK |
837 | ret = ARCHIVE_FATAL; |
838 | } | |
8f776fd9 TK |
839 | close(a->restore_pwd); |
840 | a->restore_pwd = -1; | |
841 | } | |
842 | #endif | |
843 | ||
844 | /* | |
845 | * Fixup uses the unedited pathname from archive_entry_pathname(), | |
846 | * because it is relative to the base dir and the edited path | |
847 | * might be relative to some intermediate dir as a result of the | |
848 | * deep restore logic. | |
849 | */ | |
850 | if (a->deferred & TODO_MODE) { | |
851 | fe = current_fixup(a, archive_entry_pathname(entry)); | |
62756a10 MN |
852 | if (fe == NULL) |
853 | return (ARCHIVE_FATAL); | |
ede459d2 | 854 | fe->filetype = archive_entry_filetype(entry); |
8f776fd9 TK |
855 | fe->fixup |= TODO_MODE_BASE; |
856 | fe->mode = a->mode; | |
857 | } | |
858 | ||
8e71fa72 TK |
859 | if ((a->deferred & TODO_TIMES) |
860 | && (archive_entry_mtime_is_set(entry) | |
0d6b5cc7 | 861 | || archive_entry_atime_is_set(entry))) { |
8f776fd9 | 862 | fe = current_fixup(a, archive_entry_pathname(entry)); |
62756a10 MN |
863 | if (fe == NULL) |
864 | return (ARCHIVE_FATAL); | |
ede459d2 | 865 | fe->filetype = archive_entry_filetype(entry); |
5223514b | 866 | fe->mode = a->mode; |
8f776fd9 | 867 | fe->fixup |= TODO_TIMES; |
82e3bb2a TK |
868 | if (archive_entry_atime_is_set(entry)) { |
869 | fe->atime = archive_entry_atime(entry); | |
870 | fe->atime_nanos = archive_entry_atime_nsec(entry); | |
871 | } else { | |
872 | /* If atime is unset, use start time. */ | |
873 | fe->atime = a->start_time; | |
874 | fe->atime_nanos = 0; | |
875 | } | |
8e71fa72 TK |
876 | if (archive_entry_mtime_is_set(entry)) { |
877 | fe->mtime = archive_entry_mtime(entry); | |
878 | fe->mtime_nanos = archive_entry_mtime_nsec(entry); | |
879 | } else { | |
82e3bb2a | 880 | /* If mtime is unset, use start time. */ |
f5eb945d TK |
881 | fe->mtime = a->start_time; |
882 | fe->mtime_nanos = 0; | |
8e71fa72 | 883 | } |
82e3bb2a TK |
884 | if (archive_entry_birthtime_is_set(entry)) { |
885 | fe->birthtime = archive_entry_birthtime(entry); | |
cc9cbbb1 MM |
886 | fe->birthtime_nanos = archive_entry_birthtime_nsec( |
887 | entry); | |
da0cee61 | 888 | } else { |
82e3bb2a TK |
889 | /* If birthtime is unset, use mtime. */ |
890 | fe->birthtime = fe->mtime; | |
891 | fe->birthtime_nanos = fe->mtime_nanos; | |
da0cee61 | 892 | } |
8f776fd9 TK |
893 | } |
894 | ||
b01b4bc1 TK |
895 | if (a->deferred & TODO_ACLS) { |
896 | fe = current_fixup(a, archive_entry_pathname(entry)); | |
62756a10 MN |
897 | if (fe == NULL) |
898 | return (ARCHIVE_FATAL); | |
ede459d2 | 899 | fe->filetype = archive_entry_filetype(entry); |
f67370d5 | 900 | fe->fixup |= TODO_ACLS; |
b01b4bc1 TK |
901 | archive_acl_copy(&fe->acl, archive_entry_acl(entry)); |
902 | } | |
903 | ||
b8ad1655 TK |
904 | if (a->deferred & TODO_MAC_METADATA) { |
905 | const void *metadata; | |
906 | size_t metadata_size; | |
907 | metadata = archive_entry_mac_metadata(a->entry, &metadata_size); | |
908 | if (metadata != NULL && metadata_size > 0) { | |
909 | fe = current_fixup(a, archive_entry_pathname(entry)); | |
62756a10 MN |
910 | if (fe == NULL) |
911 | return (ARCHIVE_FATAL); | |
ede459d2 | 912 | fe->filetype = archive_entry_filetype(entry); |
b8ad1655 TK |
913 | fe->mac_metadata = malloc(metadata_size); |
914 | if (fe->mac_metadata != NULL) { | |
cc9cbbb1 MM |
915 | memcpy(fe->mac_metadata, metadata, |
916 | metadata_size); | |
b8ad1655 TK |
917 | fe->mac_metadata_size = metadata_size; |
918 | fe->fixup |= TODO_MAC_METADATA; | |
919 | } | |
920 | } | |
921 | } | |
922 | ||
8f776fd9 TK |
923 | if (a->deferred & TODO_FFLAGS) { |
924 | fe = current_fixup(a, archive_entry_pathname(entry)); | |
62756a10 MN |
925 | if (fe == NULL) |
926 | return (ARCHIVE_FATAL); | |
ede459d2 | 927 | fe->filetype = archive_entry_filetype(entry); |
8f776fd9 TK |
928 | fe->fixup |= TODO_FFLAGS; |
929 | /* TODO: Complete this.. defer fflags from below. */ | |
930 | } | |
931 | ||
932 | /* We've created the object and are ready to pour data into it. */ | |
7d4496e9 | 933 | if (ret >= ARCHIVE_WARN) |
8f776fd9 TK |
934 | a->archive.state = ARCHIVE_STATE_DATA; |
935 | /* | |
936 | * If it's not open, tell our client not to try writing. | |
937 | * In particular, dirs, links, etc, don't get written to. | |
938 | */ | |
939 | if (a->fd < 0) { | |
940 | archive_entry_set_size(entry, 0); | |
941 | a->filesize = 0; | |
942 | } | |
8f776fd9 TK |
943 | |
944 | return (ret); | |
945 | } | |
946 | ||
73f39d90 | 947 | int |
c10875db | 948 | archive_write_disk_set_skip_file(struct archive *_a, la_int64_t d, la_int64_t i) |
8f776fd9 TK |
949 | { |
950 | struct archive_write_disk *a = (struct archive_write_disk *)_a; | |
42c1f3e1 | 951 | archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, |
8f776fd9 | 952 | ARCHIVE_STATE_ANY, "archive_write_disk_set_skip_file"); |
7457cf54 | 953 | a->skip_file_set = 1; |
8f776fd9 TK |
954 | a->skip_file_dev = d; |
955 | a->skip_file_ino = i; | |
956 | return (ARCHIVE_OK); | |
957 | } | |
958 | ||
959 | static ssize_t | |
b6c8e140 | 960 | write_data_block(struct archive_write_disk *a, const char *buff, size_t size) |
8f776fd9 | 961 | { |
b6c8e140 | 962 | uint64_t start_size = size; |
8f776fd9 | 963 | ssize_t bytes_written = 0; |
5b5d1d58 | 964 | ssize_t block_size = 0, bytes_to_write; |
8f776fd9 | 965 | |
398d89f6 TK |
966 | if (size == 0) |
967 | return (ARCHIVE_OK); | |
968 | ||
5b5d1d58 TK |
969 | if (a->filesize == 0 || a->fd < 0) { |
970 | archive_set_error(&a->archive, 0, | |
971 | "Attempt to write to an empty file"); | |
8f776fd9 TK |
972 | return (ARCHIVE_WARN); |
973 | } | |
8f776fd9 | 974 | |
51300afe | 975 | if (a->flags & ARCHIVE_EXTRACT_SPARSE) { |
e55af97f | 976 | #if HAVE_STRUCT_STAT_ST_BLKSIZE |
5c6d3586 | 977 | int r; |
911dc2bf | 978 | if ((r = lazy_stat(a)) != ARCHIVE_OK) |
51300afe JS |
979 | return (r); |
980 | block_size = a->pst->st_blksize; | |
e55af97f TK |
981 | #else |
982 | /* XXX TODO XXX Is there a more appropriate choice here ? */ | |
983 | /* This needn't match the filesystem allocation size. */ | |
984 | block_size = 16*1024; | |
985 | #endif | |
8f776fd9 TK |
986 | } |
987 | ||
b6c8e140 | 988 | /* If this write would run beyond the file size, truncate it. */ |
911dc2bf | 989 | if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize) |
b6c8e140 | 990 | start_size = size = (size_t)(a->filesize - a->offset); |
5b5d1d58 | 991 | |
8f776fd9 | 992 | /* Write the data. */ |
51300afe | 993 | while (size > 0) { |
5b5d1d58 TK |
994 | if (block_size == 0) { |
995 | bytes_to_write = size; | |
996 | } else { | |
997 | /* We're sparsifying the file. */ | |
998 | const char *p, *end; | |
911dc2bf | 999 | int64_t block_end; |
51300afe | 1000 | |
5b5d1d58 TK |
1001 | /* Skip leading zero bytes. */ |
1002 | for (p = buff, end = buff + size; p < end; ++p) { | |
1003 | if (*p != '\0') | |
51300afe JS |
1004 | break; |
1005 | } | |
b6c8e140 | 1006 | a->offset += p - buff; |
5b5d1d58 TK |
1007 | size -= p - buff; |
1008 | buff = p; | |
51300afe JS |
1009 | if (size == 0) |
1010 | break; | |
5b5d1d58 TK |
1011 | |
1012 | /* Calculate next block boundary after offset. */ | |
1013 | block_end | |
b6c8e140 | 1014 | = (a->offset / block_size + 1) * block_size; |
5b5d1d58 TK |
1015 | |
1016 | /* If the adjusted write would cross block boundary, | |
1017 | * truncate it to the block boundary. */ | |
51300afe | 1018 | bytes_to_write = size; |
b6c8e140 TK |
1019 | if (a->offset + bytes_to_write > block_end) |
1020 | bytes_to_write = block_end - a->offset; | |
5b5d1d58 | 1021 | } |
51300afe | 1022 | /* Seek if necessary to the specified offset. */ |
b6c8e140 TK |
1023 | if (a->offset != a->fd_offset) { |
1024 | if (lseek(a->fd, a->offset, SEEK_SET) < 0) { | |
5b5d1d58 TK |
1025 | archive_set_error(&a->archive, errno, |
1026 | "Seek failed"); | |
51300afe JS |
1027 | return (ARCHIVE_FATAL); |
1028 | } | |
b6c8e140 | 1029 | a->fd_offset = a->offset; |
cafcd565 | 1030 | } |
5b5d1d58 | 1031 | bytes_written = write(a->fd, buff, bytes_to_write); |
8f776fd9 TK |
1032 | if (bytes_written < 0) { |
1033 | archive_set_error(&a->archive, errno, "Write failed"); | |
1034 | return (ARCHIVE_WARN); | |
1035 | } | |
5b5d1d58 | 1036 | buff += bytes_written; |
8f776fd9 | 1037 | size -= bytes_written; |
911dc2bf | 1038 | a->total_bytes_written += bytes_written; |
b6c8e140 | 1039 | a->offset += bytes_written; |
b6c8e140 | 1040 | a->fd_offset = a->offset; |
8f776fd9 | 1041 | } |
b6c8e140 | 1042 | return (start_size - size); |
5b5d1d58 TK |
1043 | } |
1044 | ||
213a263c MN |
1045 | #if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\ |
1046 | && defined(HAVE_ZLIB_H) | |
fb67a295 | 1047 | |
cfb7792c MN |
1048 | /* |
1049 | * Set UF_COMPRESSED file flag. | |
1050 | * This have to be called after hfs_write_decmpfs() because if the | |
1051 | * file does not have "com.apple.decmpfs" xattr the flag is ignored. | |
1052 | */ | |
1053 | static int | |
1054 | hfs_set_compressed_fflag(struct archive_write_disk *a) | |
1055 | { | |
1056 | int r; | |
1057 | ||
1058 | if ((r = lazy_stat(a)) != ARCHIVE_OK) | |
1059 | return (r); | |
1060 | ||
1061 | a->st.st_flags |= UF_COMPRESSED; | |
1062 | if (fchflags(a->fd, a->st.st_flags) != 0) { | |
1063 | archive_set_error(&a->archive, errno, | |
1064 | "Failed to set UF_COMPRESSED file flag"); | |
1065 | return (ARCHIVE_WARN); | |
1066 | } | |
1067 | return (ARCHIVE_OK); | |
1068 | } | |
1069 | ||
fb67a295 MN |
1070 | /* |
1071 | * HFS+ Compression decmpfs | |
1072 | * | |
cfb7792c | 1073 | * +------------------------------+ +0 |
fb67a295 MN |
1074 | * | Magic(LE 4 bytes) | |
1075 | * +------------------------------+ | |
1076 | * | Type(LE 4 bytes) | | |
1077 | * +------------------------------+ | |
1078 | * | Uncompressed size(LE 8 bytes)| | |
cfb7792c | 1079 | * +------------------------------+ +16 |
fb67a295 MN |
1080 | * | | |
1081 | * | Compressed data | | |
1082 | * | (Placed only if Type == 3) | | |
1083 | * | | | |
1084 | * +------------------------------+ +3802 = MAX_DECMPFS_XATTR_SIZE | |
1085 | * | |
1086 | * Type is 3: decmpfs has compressed data. | |
1087 | * Type is 4: Resource Fork has compressed data. | |
1088 | */ | |
1089 | /* | |
1090 | * Write "com.apple.decmpfs" | |
1091 | */ | |
1092 | static int | |
1093 | hfs_write_decmpfs(struct archive_write_disk *a) | |
1094 | { | |
fb67a295 | 1095 | int r; |
3c8570c2 | 1096 | uint32_t compression_type; |
fb67a295 | 1097 | |
3c8570c2 MN |
1098 | r = fsetxattr(a->fd, DECMPFS_XATTR_NAME, a->decmpfs_header_p, |
1099 | a->decmpfs_attr_size, 0, 0); | |
fb67a295 MN |
1100 | if (r < 0) { |
1101 | archive_set_error(&a->archive, errno, | |
1102 | "Cannot restore xattr:%s", DECMPFS_XATTR_NAME); | |
a08a9fd4 MN |
1103 | compression_type = archive_le32dec( |
1104 | &a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE]); | |
3c8570c2 | 1105 | if (compression_type == CMP_RESOURCE_FORK) |
fb67a295 MN |
1106 | fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME, |
1107 | XATTR_SHOWCOMPRESSION); | |
1108 | return (ARCHIVE_WARN); | |
1109 | } | |
1110 | return (ARCHIVE_OK); | |
1111 | } | |
1112 | ||
1113 | /* | |
1114 | * HFS+ Compression Resource Fork | |
1115 | * | |
1116 | * +-----------------------------+ | |
1117 | * | Header(260 bytes) | | |
1118 | * +-----------------------------+ | |
1119 | * | Block count(LE 4 bytes) | | |
1120 | * +-----------------------------+ --+ | |
fe61ff64 MN |
1121 | * +-- | Offset (LE 4 bytes) | | |
1122 | * | | [distance from Block count] | | Block 0 | |
1123 | * | +-----------------------------+ | | |
1124 | * | | Compressed size(LE 4 bytes) | | | |
fb67a295 MN |
1125 | * | +-----------------------------+ --+ |
1126 | * | | | | |
1127 | * | | .................. | | |
1128 | * | | | | |
1129 | * | +-----------------------------+ --+ | |
fe61ff64 | 1130 | * | | Offset (LE 4 bytes) | | |
fb67a295 MN |
1131 | * | +-----------------------------+ | Block (Block count -1) |
1132 | * | | Compressed size(LE 4 bytes) | | | |
fe61ff64 MN |
1133 | * +-> +-----------------------------+ --+ |
1134 | * | Compressed data(n bytes) | Block 0 | |
fb67a295 MN |
1135 | * +-----------------------------+ |
1136 | * | | | |
1137 | * | .................. | | |
1138 | * | | | |
1139 | * +-----------------------------+ | |
1140 | * | Compressed data(n bytes) | Block (Block count -1) | |
1141 | * +-----------------------------+ | |
1142 | * | Footer(50 bytes) | | |
1143 | * +-----------------------------+ | |
1144 | * | |
1145 | */ | |
1146 | /* | |
1147 | * Write the header of "com.apple.ResourceFork" | |
1148 | */ | |
1149 | static int | |
1150 | hfs_write_resource_fork(struct archive_write_disk *a, unsigned char *buff, | |
1151 | size_t bytes, uint32_t position) | |
1152 | { | |
1153 | int ret; | |
1154 | ||
1155 | ret = fsetxattr(a->fd, XATTR_RESOURCEFORK_NAME, buff, bytes, | |
1156 | position, a->rsrc_xattr_options); | |
1157 | if (ret < 0) { | |
1158 | archive_set_error(&a->archive, errno, | |
1159 | "Cannot restore xattr: %s at %u pos %u bytes", | |
1160 | XATTR_RESOURCEFORK_NAME, | |
1161 | (unsigned)position, | |
1162 | (unsigned)bytes); | |
1163 | return (ARCHIVE_WARN); | |
1164 | } | |
1165 | a->rsrc_xattr_options &= ~XATTR_CREATE; | |
1166 | return (ARCHIVE_OK); | |
1167 | } | |
1168 | ||
1169 | static int | |
1170 | hfs_write_compressed_data(struct archive_write_disk *a, size_t bytes_compressed) | |
1171 | { | |
1172 | int ret; | |
1173 | ||
1174 | ret = hfs_write_resource_fork(a, a->compressed_buffer, | |
1175 | bytes_compressed, a->compressed_rsrc_position); | |
1176 | if (ret == ARCHIVE_OK) | |
1177 | a->compressed_rsrc_position += bytes_compressed; | |
1178 | return (ret); | |
1179 | } | |
1180 | ||
1181 | static int | |
1182 | hfs_write_resource_fork_header(struct archive_write_disk *a) | |
1183 | { | |
1184 | unsigned char *buff; | |
1185 | uint32_t rsrc_bytes; | |
1186 | uint32_t rsrc_header_bytes; | |
1187 | ||
1188 | /* | |
1189 | * Write resource fork header + block info. | |
1190 | */ | |
1191 | buff = a->resource_fork; | |
fe61ff64 | 1192 | rsrc_bytes = a->compressed_rsrc_position - RSRC_F_SIZE; |
fb67a295 MN |
1193 | rsrc_header_bytes = |
1194 | RSRC_H_SIZE + /* Header base size. */ | |
1195 | 4 + /* Block count. */ | |
1196 | (a->decmpfs_block_count * 8);/* Block info */ | |
1197 | archive_be32enc(buff, 0x100); | |
1198 | archive_be32enc(buff + 4, rsrc_bytes); | |
1199 | archive_be32enc(buff + 8, rsrc_bytes - 256); | |
1200 | archive_be32enc(buff + 12, 0x32); | |
1201 | memset(buff + 16, 0, 240); | |
1202 | archive_be32enc(buff + 256, rsrc_bytes - 260); | |
1203 | return hfs_write_resource_fork(a, buff, rsrc_header_bytes, 0); | |
1204 | } | |
1205 | ||
1206 | static size_t | |
1207 | hfs_set_resource_fork_footer(unsigned char *buff, size_t buff_size) | |
1208 | { | |
1209 | static const char rsrc_footer[RSRC_F_SIZE] = { | |
1210 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1211 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1212 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1213 | 0x00, 0x1c, 0x00, 0x32, 0x00, 0x00, 'c', 'm', | |
1214 | 'p', 'f', 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, | |
1215 | 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1216 | 0x00, 0x00 | |
1217 | }; | |
1218 | if (buff_size < sizeof(rsrc_footer)) | |
1219 | return (0); | |
1220 | memcpy(buff, rsrc_footer, sizeof(rsrc_footer)); | |
1221 | return (sizeof(rsrc_footer)); | |
1222 | } | |
1223 | ||
fb67a295 MN |
1224 | static int |
1225 | hfs_reset_compressor(struct archive_write_disk *a) | |
1226 | { | |
1227 | int ret; | |
1228 | ||
1229 | if (a->stream_valid) | |
1230 | ret = deflateReset(&a->stream); | |
1231 | else | |
1232 | ret = deflateInit(&a->stream, a->decmpfs_compression_level); | |
1233 | ||
1234 | if (ret != Z_OK) { | |
1235 | archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, | |
1236 | "Failed to initialize compressor"); | |
1237 | return (ARCHIVE_FATAL); | |
1238 | } else | |
1239 | a->stream_valid = 1; | |
1240 | ||
1241 | return (ARCHIVE_OK); | |
1242 | } | |
1243 | ||
8f7fbd41 MN |
1244 | static int |
1245 | hfs_decompress(struct archive_write_disk *a) | |
1246 | { | |
1247 | uint32_t *block_info; | |
1248 | unsigned int block_count; | |
1249 | uint32_t data_pos, data_size; | |
1250 | ssize_t r; | |
1251 | ssize_t bytes_written, bytes_to_write; | |
1252 | unsigned char *b; | |
1253 | ||
1254 | block_info = (uint32_t *)(a->resource_fork + RSRC_H_SIZE); | |
1255 | block_count = archive_le32dec(block_info++); | |
1256 | while (block_count--) { | |
1257 | data_pos = RSRC_H_SIZE + archive_le32dec(block_info++); | |
1258 | data_size = archive_le32dec(block_info++); | |
1259 | r = fgetxattr(a->fd, XATTR_RESOURCEFORK_NAME, | |
1260 | a->compressed_buffer, data_size, data_pos, 0); | |
1261 | if (r != data_size) { | |
1262 | archive_set_error(&a->archive, | |
1263 | (r < 0)?errno:ARCHIVE_ERRNO_MISC, | |
1264 | "Failed to read resource fork"); | |
1265 | return (ARCHIVE_WARN); | |
1266 | } | |
1267 | if (a->compressed_buffer[0] == 0xff) { | |
1268 | bytes_to_write = data_size -1; | |
1269 | b = a->compressed_buffer + 1; | |
1270 | } else { | |
1271 | uLong dest_len = MAX_DECMPFS_BLOCK_SIZE; | |
1272 | int zr; | |
1273 | ||
1274 | zr = uncompress((Bytef *)a->uncompressed_buffer, | |
1275 | &dest_len, a->compressed_buffer, data_size); | |
1276 | if (zr != Z_OK) { | |
1277 | archive_set_error(&a->archive, | |
1278 | ARCHIVE_ERRNO_MISC, | |
1279 | "Failed to decompress resource fork"); | |
1280 | return (ARCHIVE_WARN); | |
1281 | } | |
1282 | bytes_to_write = dest_len; | |
1283 | b = (unsigned char *)a->uncompressed_buffer; | |
1284 | } | |
1285 | do { | |
1286 | bytes_written = write(a->fd, b, bytes_to_write); | |
1287 | if (bytes_written < 0) { | |
1288 | archive_set_error(&a->archive, errno, | |
1289 | "Write failed"); | |
1290 | return (ARCHIVE_WARN); | |
1291 | } | |
1292 | bytes_to_write -= bytes_written; | |
1293 | b += bytes_written; | |
1294 | } while (bytes_to_write > 0); | |
1295 | } | |
1296 | r = fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME, 0); | |
1297 | if (r == -1) { | |
1298 | archive_set_error(&a->archive, errno, | |
1299 | "Failed to remove resource fork"); | |
1300 | return (ARCHIVE_WARN); | |
1301 | } | |
1302 | return (ARCHIVE_OK); | |
1303 | } | |
1304 | ||
fb67a295 MN |
1305 | static int |
1306 | hfs_drive_compressor(struct archive_write_disk *a, const char *buff, | |
1307 | size_t size) | |
1308 | { | |
1309 | unsigned char *buffer_compressed; | |
1310 | size_t bytes_compressed; | |
a08a9fd4 | 1311 | size_t bytes_used; |
fb67a295 MN |
1312 | int ret; |
1313 | ||
1314 | ret = hfs_reset_compressor(a); | |
1315 | if (ret != ARCHIVE_OK) | |
1316 | return (ret); | |
1317 | ||
1318 | if (a->compressed_buffer == NULL) { | |
1319 | size_t block_size; | |
1320 | ||
1321 | block_size = COMPRESSED_W_SIZE + RSRC_F_SIZE + | |
1322 | + compressBound(MAX_DECMPFS_BLOCK_SIZE); | |
1323 | a->compressed_buffer = malloc(block_size); | |
1324 | if (a->compressed_buffer == NULL) { | |
1325 | archive_set_error(&a->archive, ENOMEM, | |
1326 | "Can't allocate memory for Resource Fork"); | |
1327 | return (ARCHIVE_FATAL); | |
1328 | } | |
1329 | a->compressed_buffer_size = block_size; | |
1330 | a->compressed_buffer_remaining = block_size; | |
1331 | } | |
1332 | ||
1333 | buffer_compressed = a->compressed_buffer + | |
1334 | a->compressed_buffer_size - a->compressed_buffer_remaining; | |
1335 | a->stream.next_in = (Bytef *)(uintptr_t)(const void *)buff; | |
1336 | a->stream.avail_in = size; | |
1337 | a->stream.next_out = buffer_compressed; | |
1338 | a->stream.avail_out = a->compressed_buffer_remaining; | |
1339 | do { | |
1340 | ret = deflate(&a->stream, Z_FINISH); | |
1341 | switch (ret) { | |
1342 | case Z_OK: | |
1343 | case Z_STREAM_END: | |
1344 | break; | |
1345 | default: | |
1346 | archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, | |
1347 | "Failed to compress data"); | |
1348 | return (ARCHIVE_FAILED); | |
1349 | } | |
1350 | } while (ret == Z_OK); | |
1351 | bytes_compressed = a->compressed_buffer_remaining - a->stream.avail_out; | |
1352 | ||
1353 | /* | |
1354 | * If the compressed size is larger than the original size, | |
1355 | * throw away compressed data, use uncompressed data instead. | |
1356 | */ | |
1357 | if (bytes_compressed > size) { | |
1358 | buffer_compressed[0] = 0xFF;/* uncompressed marker. */ | |
1359 | memcpy(buffer_compressed + 1, buff, size); | |
1360 | bytes_compressed = size + 1; | |
1361 | } | |
1362 | a->compressed_buffer_remaining -= bytes_compressed; | |
1363 | ||
1364 | /* | |
1365 | * If the compressed size is smaller than MAX_DECMPFS_XATTR_SIZE | |
1366 | * and the block count in the file is only one, store compressed | |
1367 | * data to decmpfs xattr instead of the resource fork. | |
1368 | */ | |
1369 | if (a->decmpfs_block_count == 1 && | |
3c8570c2 | 1370 | (a->decmpfs_attr_size + bytes_compressed) |
fb67a295 | 1371 | <= MAX_DECMPFS_XATTR_SIZE) { |
a08a9fd4 MN |
1372 | archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE], |
1373 | CMP_XATTR); | |
3c8570c2 | 1374 | memcpy(a->decmpfs_header_p + DECMPFS_HEADER_SIZE, |
fb67a295 | 1375 | buffer_compressed, bytes_compressed); |
3c8570c2 | 1376 | a->decmpfs_attr_size += bytes_compressed; |
a08a9fd4 | 1377 | a->compressed_buffer_remaining = a->compressed_buffer_size; |
fb67a295 | 1378 | /* |
cfb7792c MN |
1379 | * Finish HFS+ Compression. |
1380 | * - Write the decmpfs xattr. | |
1381 | * - Set the UF_COMPRESSED file flag. | |
fb67a295 | 1382 | */ |
cfb7792c MN |
1383 | ret = hfs_write_decmpfs(a); |
1384 | if (ret == ARCHIVE_OK) | |
1385 | ret = hfs_set_compressed_fflag(a); | |
1386 | return (ret); | |
fb67a295 MN |
1387 | } |
1388 | ||
1389 | /* Update block info. */ | |
fe61ff64 MN |
1390 | archive_le32enc(a->decmpfs_block_info++, |
1391 | a->compressed_rsrc_position_v - RSRC_H_SIZE); | |
fb67a295 | 1392 | archive_le32enc(a->decmpfs_block_info++, bytes_compressed); |
fe61ff64 | 1393 | a->compressed_rsrc_position_v += bytes_compressed; |
fb67a295 | 1394 | |
fb67a295 MN |
1395 | /* |
1396 | * Write the compressed data to the resource fork. | |
1397 | */ | |
a08a9fd4 MN |
1398 | bytes_used = a->compressed_buffer_size - a->compressed_buffer_remaining; |
1399 | while (bytes_used >= COMPRESSED_W_SIZE) { | |
1400 | ret = hfs_write_compressed_data(a, COMPRESSED_W_SIZE); | |
1401 | if (ret != ARCHIVE_OK) | |
1402 | return (ret); | |
1403 | bytes_used -= COMPRESSED_W_SIZE; | |
1404 | if (bytes_used > COMPRESSED_W_SIZE) | |
1405 | memmove(a->compressed_buffer, | |
1406 | a->compressed_buffer + COMPRESSED_W_SIZE, | |
1407 | bytes_used); | |
1408 | else | |
1409 | memcpy(a->compressed_buffer, | |
1410 | a->compressed_buffer + COMPRESSED_W_SIZE, | |
1411 | bytes_used); | |
1412 | } | |
1413 | a->compressed_buffer_remaining = a->compressed_buffer_size - bytes_used; | |
1414 | ||
1415 | /* | |
1416 | * If the current block is the last block, write the remaining | |
1417 | * compressed data and the resource fork footer. | |
1418 | */ | |
fb67a295 MN |
1419 | if (a->file_remaining_bytes == 0) { |
1420 | size_t rsrc_size; | |
8f7fbd41 | 1421 | int64_t bk; |
fb67a295 | 1422 | |
a08a9fd4 | 1423 | /* Append the resource footer. */ |
fb67a295 | 1424 | rsrc_size = hfs_set_resource_fork_footer( |
1fd95bd6 | 1425 | a->compressed_buffer + bytes_used, |
fb67a295 | 1426 | a->compressed_buffer_remaining); |
a08a9fd4 | 1427 | ret = hfs_write_compressed_data(a, bytes_used + rsrc_size); |
fb67a295 | 1428 | a->compressed_buffer_remaining = a->compressed_buffer_size; |
8f7fbd41 | 1429 | |
0b29066b | 1430 | /* If the compressed size is not enough smaller than |
8f7fbd41 MN |
1431 | * the uncompressed size. cancel HFS+ compression. |
1432 | * TODO: study a behavior of ditto utility and improve | |
1433 | * the condition to fall back into no HFS+ compression. */ | |
1434 | bk = HFS_BLOCKS(a->compressed_rsrc_position); | |
1435 | bk += bk >> 7; | |
1436 | if (bk > HFS_BLOCKS(a->filesize)) | |
1437 | return hfs_decompress(a); | |
fb67a295 MN |
1438 | /* |
1439 | * Write the resourcefork header. | |
1440 | */ | |
1441 | if (ret == ARCHIVE_OK) | |
1442 | ret = hfs_write_resource_fork_header(a); | |
1443 | /* | |
cfb7792c MN |
1444 | * Finish HFS+ Compression. |
1445 | * - Write the decmpfs xattr. | |
1446 | * - Set the UF_COMPRESSED file flag. | |
fb67a295 MN |
1447 | */ |
1448 | if (ret == ARCHIVE_OK) | |
1449 | ret = hfs_write_decmpfs(a); | |
cfb7792c MN |
1450 | if (ret == ARCHIVE_OK) |
1451 | ret = hfs_set_compressed_fflag(a); | |
fb67a295 MN |
1452 | } |
1453 | return (ret); | |
1454 | } | |
1455 | ||
1456 | static ssize_t | |
1457 | hfs_write_decmpfs_block(struct archive_write_disk *a, const char *buff, | |
1458 | size_t size) | |
1459 | { | |
1460 | const char *buffer_to_write; | |
1461 | size_t bytes_to_write; | |
1462 | int ret; | |
1463 | ||
1464 | if (a->decmpfs_block_count == (unsigned)-1) { | |
1465 | void *new_block; | |
1466 | size_t new_size; | |
aed6038c | 1467 | unsigned int block_count; |
fb67a295 MN |
1468 | |
1469 | if (a->decmpfs_header_p == NULL) { | |
1470 | new_block = malloc(MAX_DECMPFS_XATTR_SIZE | |
1471 | + sizeof(uint32_t)); | |
1472 | if (new_block == NULL) { | |
1473 | archive_set_error(&a->archive, ENOMEM, | |
1474 | "Can't allocate memory for decmpfs"); | |
1475 | return (ARCHIVE_FATAL); | |
1476 | } | |
1477 | a->decmpfs_header_p = new_block; | |
1478 | } | |
3c8570c2 | 1479 | a->decmpfs_attr_size = DECMPFS_HEADER_SIZE; |
a08a9fd4 MN |
1480 | archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_MAGIC], |
1481 | DECMPFS_MAGIC); | |
1482 | archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE], | |
1483 | CMP_RESOURCE_FORK); | |
1484 | archive_le64enc(&a->decmpfs_header_p[DECMPFS_UNCOMPRESSED_SIZE], | |
1485 | a->filesize); | |
fb67a295 MN |
1486 | |
1487 | /* Calculate a block count of the file. */ | |
aed6038c | 1488 | block_count = |
fb67a295 MN |
1489 | (a->filesize + MAX_DECMPFS_BLOCK_SIZE -1) / |
1490 | MAX_DECMPFS_BLOCK_SIZE; | |
fb67a295 MN |
1491 | /* |
1492 | * Allocate buffer for resource fork. | |
1493 | * Set up related pointers; | |
1494 | */ | |
1495 | new_size = | |
1496 | RSRC_H_SIZE + /* header */ | |
1497 | 4 + /* Block count */ | |
aed6038c | 1498 | (block_count * sizeof(uint32_t) * 2) + |
fb67a295 MN |
1499 | RSRC_F_SIZE; /* footer */ |
1500 | if (new_size > a->resource_fork_allocated_size) { | |
1501 | new_block = realloc(a->resource_fork, new_size); | |
1502 | if (new_block == NULL) { | |
1503 | archive_set_error(&a->archive, ENOMEM, | |
1504 | "Can't allocate memory for ResourceFork"); | |
1505 | return (ARCHIVE_FATAL); | |
1506 | } | |
1507 | a->resource_fork_allocated_size = new_size; | |
1508 | a->resource_fork = new_block; | |
1509 | } | |
1510 | ||
1511 | /* Allocate uncompressed buffer */ | |
1512 | if (a->uncompressed_buffer == NULL) { | |
1513 | new_block = malloc(MAX_DECMPFS_BLOCK_SIZE); | |
1514 | if (new_block == NULL) { | |
1515 | archive_set_error(&a->archive, ENOMEM, | |
1516 | "Can't allocate memory for decmpfs"); | |
1517 | return (ARCHIVE_FATAL); | |
1518 | } | |
1519 | a->uncompressed_buffer = new_block; | |
1520 | } | |
1521 | a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE; | |
1522 | a->file_remaining_bytes = a->filesize; | |
a08a9fd4 | 1523 | a->compressed_buffer_remaining = a->compressed_buffer_size; |
fb67a295 MN |
1524 | |
1525 | /* | |
1526 | * Set up a resource fork. | |
1527 | */ | |
fb67a295 MN |
1528 | a->rsrc_xattr_options = XATTR_CREATE; |
1529 | /* Get the position where we are going to set a bunch | |
1530 | * of block info. */ | |
1531 | a->decmpfs_block_info = | |
1532 | (uint32_t *)(a->resource_fork + RSRC_H_SIZE); | |
1533 | /* Set the block count to the resource fork. */ | |
aed6038c | 1534 | archive_le32enc(a->decmpfs_block_info++, block_count); |
0b29066b | 1535 | /* Get the position where we are going to set compressed |
fb67a295 MN |
1536 | * data. */ |
1537 | a->compressed_rsrc_position = | |
aed6038c | 1538 | RSRC_H_SIZE + 4 + (block_count * 8); |
fe61ff64 | 1539 | a->compressed_rsrc_position_v = a->compressed_rsrc_position; |
aed6038c | 1540 | a->decmpfs_block_count = block_count; |
fb67a295 MN |
1541 | } |
1542 | ||
1543 | /* Ignore redundant bytes. */ | |
1544 | if (a->file_remaining_bytes == 0) | |
1545 | return ((ssize_t)size); | |
1546 | ||
1547 | /* Do not overrun a block size. */ | |
1548 | if (size > a->block_remaining_bytes) | |
1549 | bytes_to_write = a->block_remaining_bytes; | |
1550 | else | |
1551 | bytes_to_write = size; | |
1552 | /* Do not overrun the file size. */ | |
1553 | if (bytes_to_write > a->file_remaining_bytes) | |
1554 | bytes_to_write = a->file_remaining_bytes; | |
1555 | ||
1556 | /* For efficiency, if a copy length is full of the uncompressed | |
1557 | * buffer size, do not copy writing data to it. */ | |
1558 | if (bytes_to_write == MAX_DECMPFS_BLOCK_SIZE) | |
1559 | buffer_to_write = buff; | |
1560 | else { | |
1561 | memcpy(a->uncompressed_buffer + | |
1562 | MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes, | |
1563 | buff, bytes_to_write); | |
1564 | buffer_to_write = a->uncompressed_buffer; | |
1565 | } | |
1566 | a->block_remaining_bytes -= bytes_to_write; | |
1567 | a->file_remaining_bytes -= bytes_to_write; | |
1568 | ||
1569 | if (a->block_remaining_bytes == 0 || a->file_remaining_bytes == 0) { | |
1570 | ret = hfs_drive_compressor(a, buffer_to_write, | |
1571 | MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes); | |
1572 | if (ret < 0) | |
1573 | return (ret); | |
1574 | a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE; | |
1575 | } | |
1576 | /* Ignore redundant bytes. */ | |
1577 | if (a->file_remaining_bytes == 0) | |
1578 | return ((ssize_t)size); | |
1579 | return (bytes_to_write); | |
1580 | } | |
1581 | ||
1582 | static ssize_t | |
1583 | hfs_write_data_block(struct archive_write_disk *a, const char *buff, | |
1584 | size_t size) | |
1585 | { | |
1586 | uint64_t start_size = size; | |
1587 | ssize_t bytes_written = 0; | |
1588 | ssize_t bytes_to_write; | |
1589 | ||
1590 | if (size == 0) | |
1591 | return (ARCHIVE_OK); | |
1592 | ||
1593 | if (a->filesize == 0 || a->fd < 0) { | |
1594 | archive_set_error(&a->archive, 0, | |
1595 | "Attempt to write to an empty file"); | |
1596 | return (ARCHIVE_WARN); | |
1597 | } | |
1598 | ||
1599 | /* If this write would run beyond the file size, truncate it. */ | |
1600 | if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize) | |
1601 | start_size = size = (size_t)(a->filesize - a->offset); | |
1602 | ||
1603 | /* Write the data. */ | |
1604 | while (size > 0) { | |
1605 | bytes_to_write = size; | |
1606 | /* Seek if necessary to the specified offset. */ | |
1607 | if (a->offset < a->fd_offset) { | |
0b29066b | 1608 | /* Can't support backward move. */ |
fb67a295 MN |
1609 | archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, |
1610 | "Seek failed"); | |
1611 | return (ARCHIVE_FATAL); | |
1612 | } else if (a->offset > a->fd_offset) { | |
e7b2ab7a | 1613 | uint64_t skip = a->offset - a->fd_offset; |
fb67a295 MN |
1614 | char nullblock[1024]; |
1615 | ||
1616 | memset(nullblock, 0, sizeof(nullblock)); | |
1617 | while (skip > 0) { | |
e7b2ab7a | 1618 | if (skip > sizeof(nullblock)) |
fb67a295 MN |
1619 | bytes_written = hfs_write_decmpfs_block( |
1620 | a, nullblock, sizeof(nullblock)); | |
1621 | else | |
1622 | bytes_written = hfs_write_decmpfs_block( | |
1623 | a, nullblock, skip); | |
1624 | if (bytes_written < 0) { | |
1625 | archive_set_error(&a->archive, errno, | |
1626 | "Write failed"); | |
1627 | return (ARCHIVE_WARN); | |
1628 | } | |
1629 | skip -= bytes_written; | |
1630 | } | |
1631 | ||
1632 | a->fd_offset = a->offset; | |
1633 | } | |
1634 | bytes_written = | |
1635 | hfs_write_decmpfs_block(a, buff, bytes_to_write); | |
1636 | if (bytes_written < 0) | |
1637 | return (bytes_written); | |
1638 | buff += bytes_written; | |
1639 | size -= bytes_written; | |
1640 | a->total_bytes_written += bytes_written; | |
1641 | a->offset += bytes_written; | |
1642 | a->fd_offset = a->offset; | |
1643 | } | |
1644 | return (start_size - size); | |
1645 | } | |
1646 | #else | |
1647 | static ssize_t | |
1648 | hfs_write_data_block(struct archive_write_disk *a, const char *buff, | |
1649 | size_t size) | |
1650 | { | |
1651 | return (write_data_block(a, buff, size)); | |
1652 | } | |
1653 | #endif | |
1654 | ||
5b5d1d58 | 1655 | static ssize_t |
911dc2bf | 1656 | _archive_write_disk_data_block(struct archive *_a, |
73f39d90 | 1657 | const void *buff, size_t size, int64_t offset) |
5b5d1d58 TK |
1658 | { |
1659 | struct archive_write_disk *a = (struct archive_write_disk *)_a; | |
1660 | ssize_t r; | |
1661 | ||
42c1f3e1 | 1662 | archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, |
911dc2bf | 1663 | ARCHIVE_STATE_DATA, "archive_write_data_block"); |
5b5d1d58 | 1664 | |
b6c8e140 | 1665 | a->offset = offset; |
fb67a295 MN |
1666 | if (a->todo & TODO_HFS_COMPRESSION) |
1667 | r = hfs_write_data_block(a, buff, size); | |
1668 | else | |
1669 | r = write_data_block(a, buff, size); | |
b6c8e140 | 1670 | if (r < ARCHIVE_OK) |
5b5d1d58 TK |
1671 | return (r); |
1672 | if ((size_t)r < size) { | |
1673 | archive_set_error(&a->archive, 0, | |
cc9cbbb1 MM |
1674 | "Too much data: Truncating file at %ju bytes", |
1675 | (uintmax_t)a->filesize); | |
5b5d1d58 TK |
1676 | return (ARCHIVE_WARN); |
1677 | } | |
a654d8a0 | 1678 | #if ARCHIVE_VERSION_NUMBER < 3999000 |
5b5d1d58 | 1679 | return (ARCHIVE_OK); |
a654d8a0 TK |
1680 | #else |
1681 | return (size); | |
1682 | #endif | |
8f776fd9 TK |
1683 | } |
1684 | ||
1685 | static ssize_t | |
911dc2bf | 1686 | _archive_write_disk_data(struct archive *_a, const void *buff, size_t size) |
8f776fd9 TK |
1687 | { |
1688 | struct archive_write_disk *a = (struct archive_write_disk *)_a; | |
8f776fd9 | 1689 | |
42c1f3e1 | 1690 | archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, |
8f776fd9 | 1691 | ARCHIVE_STATE_DATA, "archive_write_data"); |
8f776fd9 | 1692 | |
fb67a295 MN |
1693 | if (a->todo & TODO_HFS_COMPRESSION) |
1694 | return (hfs_write_data_block(a, buff, size)); | |
b6c8e140 | 1695 | return (write_data_block(a, buff, size)); |
8f776fd9 TK |
1696 | } |
1697 | ||
1698 | static int | |
911dc2bf | 1699 | _archive_write_disk_finish_entry(struct archive *_a) |
8f776fd9 TK |
1700 | { |
1701 | struct archive_write_disk *a = (struct archive_write_disk *)_a; | |
1702 | int ret = ARCHIVE_OK; | |
1703 | ||
42c1f3e1 | 1704 | archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, |
8f776fd9 TK |
1705 | ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, |
1706 | "archive_write_finish_entry"); | |
1707 | if (a->archive.state & ARCHIVE_STATE_HEADER) | |
1708 | return (ARCHIVE_OK); | |
1709 | archive_clear_error(&a->archive); | |
1710 | ||
5b5d1d58 TK |
1711 | /* Pad or truncate file to the right size. */ |
1712 | if (a->fd < 0) { | |
1713 | /* There's no file. */ | |
1714 | } else if (a->filesize < 0) { | |
1715 | /* File size is unknown, so we can't set the size. */ | |
b6c8e140 | 1716 | } else if (a->fd_offset == a->filesize) { |
5b5d1d58 TK |
1717 | /* Last write ended at exactly the filesize; we're done. */ |
1718 | /* Hopefully, this is the common case. */ | |
213a263c | 1719 | #if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H) |
fb67a295 MN |
1720 | } else if (a->todo & TODO_HFS_COMPRESSION) { |
1721 | char null_d[1024]; | |
1722 | ssize_t r; | |
1723 | ||
1724 | if (a->file_remaining_bytes) | |
1725 | memset(null_d, 0, sizeof(null_d)); | |
1726 | while (a->file_remaining_bytes) { | |
1727 | if (a->file_remaining_bytes > sizeof(null_d)) | |
1728 | r = hfs_write_data_block( | |
1729 | a, null_d, sizeof(null_d)); | |
1730 | else | |
1731 | r = hfs_write_data_block( | |
1732 | a, null_d, a->file_remaining_bytes); | |
e7b2ab7a | 1733 | if (r < 0) { |
092631ce | 1734 | close_file_descriptor(a); |
fb67a295 | 1735 | return ((int)r); |
e7b2ab7a | 1736 | } |
fb67a295 MN |
1737 | } |
1738 | #endif | |
5b5d1d58 | 1739 | } else { |
e55af97f | 1740 | #if HAVE_FTRUNCATE |
beca31d2 JS |
1741 | if (ftruncate(a->fd, a->filesize) == -1 && |
1742 | a->filesize == 0) { | |
51300afe | 1743 | archive_set_error(&a->archive, errno, |
beca31d2 | 1744 | "File size could not be restored"); |
092631ce | 1745 | close_file_descriptor(a); |
51300afe JS |
1746 | return (ARCHIVE_FAILED); |
1747 | } | |
e55af97f | 1748 | #endif |
beca31d2 | 1749 | /* |
95cfd8e4 TK |
1750 | * Not all platforms implement the XSI option to |
1751 | * extend files via ftruncate. Stat() the file again | |
1752 | * to see what happened. | |
beca31d2 | 1753 | */ |
51300afe | 1754 | a->pst = NULL; |
f030f3ff SG |
1755 | if ((ret = lazy_stat(a)) != ARCHIVE_OK) { |
1756 | close_file_descriptor(a); | |
1757 | return (ret); | |
1758 | } | |
95cfd8e4 TK |
1759 | /* We can use lseek()/write() to extend the file if |
1760 | * ftruncate didn't work or isn't available. */ | |
1761 | if (a->st.st_size < a->filesize) { | |
beca31d2 | 1762 | const char nul = '\0'; |
95cfd8e4 | 1763 | if (lseek(a->fd, a->filesize - 1, SEEK_SET) < 0) { |
beca31d2 JS |
1764 | archive_set_error(&a->archive, errno, |
1765 | "Seek failed"); | |
092631ce | 1766 | close_file_descriptor(a); |
beca31d2 JS |
1767 | return (ARCHIVE_FATAL); |
1768 | } | |
1769 | if (write(a->fd, &nul, 1) < 0) { | |
1770 | archive_set_error(&a->archive, errno, | |
1771 | "Write to restore size failed"); | |
092631ce | 1772 | close_file_descriptor(a); |
beca31d2 JS |
1773 | return (ARCHIVE_FATAL); |
1774 | } | |
1775 | a->pst = NULL; | |
1776 | } | |
51300afe JS |
1777 | } |
1778 | ||
8f776fd9 TK |
1779 | /* Restore metadata. */ |
1780 | ||
a70241b7 MN |
1781 | /* |
1782 | * This is specific to Mac OS X. | |
1783 | * If the current file is an AppleDouble file, it should be | |
1784 | * linked with the data fork file and remove it. | |
1785 | */ | |
1786 | if (a->todo & TODO_APPLEDOUBLE) { | |
1787 | int r2 = fixup_appledouble(a, a->name); | |
1788 | if (r2 == ARCHIVE_EOF) { | |
1789 | /* The current file has been successfully linked | |
1790 | * with the data fork file and removed. So there | |
1791 | * is nothing to do on the current file. */ | |
1792 | goto finish_metadata; | |
1793 | } | |
1794 | if (r2 < ret) ret = r2; | |
1795 | } | |
1796 | ||
8f776fd9 | 1797 | /* |
71362fca TK |
1798 | * Look up the "real" UID only if we're going to need it. |
1799 | * TODO: the TODO_SGID condition can be dropped here, can't it? | |
8f776fd9 TK |
1800 | */ |
1801 | if (a->todo & (TODO_OWNER | TODO_SUID | TODO_SGID)) { | |
f4f791ea | 1802 | a->uid = archive_write_disk_uid(&a->archive, |
8f776fd9 TK |
1803 | archive_entry_uname(a->entry), |
1804 | archive_entry_uid(a->entry)); | |
1805 | } | |
1806 | /* Look up the "real" GID only if we're going to need it. */ | |
71362fca | 1807 | /* TODO: the TODO_SUID condition can be dropped here, can't it? */ |
8f776fd9 | 1808 | if (a->todo & (TODO_OWNER | TODO_SGID | TODO_SUID)) { |
f4f791ea | 1809 | a->gid = archive_write_disk_gid(&a->archive, |
8f776fd9 TK |
1810 | archive_entry_gname(a->entry), |
1811 | archive_entry_gid(a->entry)); | |
1812 | } | |
2f3c9ee6 | 1813 | |
8f776fd9 | 1814 | /* |
2f3c9ee6 | 1815 | * Restore ownership before set_mode tries to restore suid/sgid |
8f776fd9 TK |
1816 | * bits. If we set the owner, we know what it is and can skip |
1817 | * a stat() call to examine the ownership of the file on disk. | |
1818 | */ | |
a70241b7 MN |
1819 | if (a->todo & TODO_OWNER) { |
1820 | int r2 = set_ownership(a); | |
1821 | if (r2 < ret) ret = r2; | |
1822 | } | |
5a796cc6 | 1823 | |
ad58bd61 | 1824 | /* |
5a796cc6 EB |
1825 | * HYPOTHESIS: |
1826 | * If we're not root, we won't be setting any security | |
1827 | * attributes that may be wiped by the set_mode() routine | |
1828 | * below. We also can't set xattr on non-owner-writable files, | |
1829 | * which may be the state after set_mode(). Perform | |
1830 | * set_xattrs() first based on these constraints. | |
ad58bd61 | 1831 | */ |
d30a8faa EB |
1832 | if (a->user_uid != 0 && |
1833 | (a->todo & TODO_XATTR)) { | |
ad58bd61 EB |
1834 | int r2 = set_xattrs(a); |
1835 | if (r2 < ret) ret = r2; | |
1836 | } | |
2f3c9ee6 TK |
1837 | |
1838 | /* | |
1839 | * set_mode must precede ACLs on systems such as Solaris and | |
1840 | * FreeBSD where setting the mode implicitly clears extended ACLs | |
1841 | */ | |
8f776fd9 TK |
1842 | if (a->todo & TODO_MODE) { |
1843 | int r2 = set_mode(a, a->mode); | |
1844 | if (r2 < ret) ret = r2; | |
1845 | } | |
26f63f45 TK |
1846 | |
1847 | /* | |
1848 | * Security-related extended attributes (such as | |
1849 | * security.capability on Linux) have to be restored last, | |
1850 | * since they're implicitly removed by other file changes. | |
5a796cc6 | 1851 | * We do this last only when root. |
26f63f45 | 1852 | */ |
d30a8faa EB |
1853 | if (a->user_uid == 0 && |
1854 | (a->todo & TODO_XATTR)) { | |
26f63f45 TK |
1855 | int r2 = set_xattrs(a); |
1856 | if (r2 < ret) ret = r2; | |
1857 | } | |
1858 | ||
b21f351a TK |
1859 | /* |
1860 | * Some flags prevent file modification; they must be restored after | |
1861 | * file contents are written. | |
1862 | */ | |
8f776fd9 TK |
1863 | if (a->todo & TODO_FFLAGS) { |
1864 | int r2 = set_fflags(a); | |
1865 | if (r2 < ret) ret = r2; | |
1866 | } | |
b8ad1655 | 1867 | |
b21f351a | 1868 | /* |
2f3c9ee6 | 1869 | * Time must follow most other metadata; |
b21f351a TK |
1870 | * otherwise atime will get changed. |
1871 | */ | |
d583bb4e | 1872 | if (a->todo & TODO_TIMES) { |
5223514b | 1873 | int r2 = set_times_from_entry(a); |
d583bb4e TK |
1874 | if (r2 < ret) ret = r2; |
1875 | } | |
8f776fd9 | 1876 | |
b8ad1655 TK |
1877 | /* |
1878 | * Mac extended metadata includes ACLs. | |
1879 | */ | |
1880 | if (a->todo & TODO_MAC_METADATA) { | |
1881 | const void *metadata; | |
1882 | size_t metadata_size; | |
1883 | metadata = archive_entry_mac_metadata(a->entry, &metadata_size); | |
1884 | if (metadata != NULL && metadata_size > 0) { | |
a70241b7 MN |
1885 | int r2 = set_mac_metadata(a, archive_entry_pathname( |
1886 | a->entry), metadata, metadata_size); | |
b8ad1655 TK |
1887 | if (r2 < ret) ret = r2; |
1888 | } | |
1889 | } | |
1890 | ||
21ebff3b TK |
1891 | /* |
1892 | * ACLs must be restored after timestamps because there are | |
1893 | * ACLs that prevent attribute changes (including time). | |
1894 | */ | |
1895 | if (a->todo & TODO_ACLS) { | |
9f43a7d6 | 1896 | int r2; |
9f43a7d6 MM |
1897 | r2 = archive_write_disk_set_acls(&a->archive, a->fd, |
1898 | archive_entry_pathname(a->entry), | |
bea9f9cf MM |
1899 | archive_entry_acl(a->entry), |
1900 | archive_entry_mode(a->entry)); | |
21ebff3b TK |
1901 | if (r2 < ret) ret = r2; |
1902 | } | |
1903 | ||
a70241b7 | 1904 | finish_metadata: |
8f776fd9 TK |
1905 | /* If there's an fd, we can close it now. */ |
1906 | if (a->fd >= 0) { | |
1907 | close(a->fd); | |
1908 | a->fd = -1; | |
b51d6b62 | 1909 | if (a->tmpname) { |
1910 | if (rename(a->tmpname, a->name) == -1) { | |
1911 | archive_set_error(&a->archive, errno, | |
f001f3b0 MM |
1912 | "Failed to rename temporary file"); |
1913 | ret = ARCHIVE_FAILED; | |
1914 | unlink(a->tmpname); | |
b51d6b62 | 1915 | } |
1916 | a->tmpname = NULL; | |
1917 | } | |
8f776fd9 TK |
1918 | } |
1919 | /* If there's an entry, we can release it now. */ | |
4736e4e7 ME |
1920 | archive_entry_free(a->entry); |
1921 | a->entry = NULL; | |
8f776fd9 TK |
1922 | a->archive.state = ARCHIVE_STATE_HEADER; |
1923 | return (ret); | |
1924 | } | |
1925 | ||
73f39d90 TK |
1926 | int |
1927 | archive_write_disk_set_group_lookup(struct archive *_a, | |
1928 | void *private_data, | |
c10875db | 1929 | la_int64_t (*lookup_gid)(void *private, const char *gname, la_int64_t gid), |
73f39d90 | 1930 | void (*cleanup_gid)(void *private)) |
8f776fd9 TK |
1931 | { |
1932 | struct archive_write_disk *a = (struct archive_write_disk *)_a; | |
42c1f3e1 | 1933 | archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, |
8f776fd9 TK |
1934 | ARCHIVE_STATE_ANY, "archive_write_disk_set_group_lookup"); |
1935 | ||
f4f791ea TK |
1936 | if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL) |
1937 | (a->cleanup_gid)(a->lookup_gid_data); | |
1938 | ||
8f776fd9 TK |
1939 | a->lookup_gid = lookup_gid; |
1940 | a->cleanup_gid = cleanup_gid; | |
1941 | a->lookup_gid_data = private_data; | |
1942 | return (ARCHIVE_OK); | |
1943 | } | |
1944 | ||
73f39d90 TK |
1945 | int |
1946 | archive_write_disk_set_user_lookup(struct archive *_a, | |
1947 | void *private_data, | |
1948 | int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid), | |
1949 | void (*cleanup_uid)(void *private)) | |
8f776fd9 TK |
1950 | { |
1951 | struct archive_write_disk *a = (struct archive_write_disk *)_a; | |
42c1f3e1 | 1952 | archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, |
8f776fd9 TK |
1953 | ARCHIVE_STATE_ANY, "archive_write_disk_set_user_lookup"); |
1954 | ||
f4f791ea TK |
1955 | if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL) |
1956 | (a->cleanup_uid)(a->lookup_uid_data); | |
1957 | ||
8f776fd9 TK |
1958 | a->lookup_uid = lookup_uid; |
1959 | a->cleanup_uid = cleanup_uid; | |
1960 | a->lookup_uid_data = private_data; | |
1961 | return (ARCHIVE_OK); | |
1962 | } | |
1963 | ||
f4f791ea | 1964 | int64_t |
c10875db | 1965 | archive_write_disk_gid(struct archive *_a, const char *name, la_int64_t id) |
f4f791ea TK |
1966 | { |
1967 | struct archive_write_disk *a = (struct archive_write_disk *)_a; | |
1968 | archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, | |
1969 | ARCHIVE_STATE_ANY, "archive_write_disk_gid"); | |
1970 | if (a->lookup_gid) | |
1971 | return (a->lookup_gid)(a->lookup_gid_data, name, id); | |
1972 | return (id); | |
1973 | } | |
1974 | ||
1975 | int64_t | |
c10875db | 1976 | archive_write_disk_uid(struct archive *_a, const char *name, la_int64_t id) |
f4f791ea | 1977 | { |
f67370d5 TK |
1978 | struct archive_write_disk *a = (struct archive_write_disk *)_a; |
1979 | archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, | |
1980 | ARCHIVE_STATE_ANY, "archive_write_disk_uid"); | |
1981 | if (a->lookup_uid) | |
1982 | return (a->lookup_uid)(a->lookup_uid_data, name, id); | |
1983 | return (id); | |
f4f791ea | 1984 | } |
8f776fd9 TK |
1985 | |
1986 | /* | |
1987 | * Create a new archive_write_disk object and initialize it with global state. | |
1988 | */ | |
1989 | struct archive * | |
1990 | archive_write_disk_new(void) | |
1991 | { | |
1992 | struct archive_write_disk *a; | |
1993 | ||
72abdbb8 | 1994 | a = (struct archive_write_disk *)calloc(1, sizeof(*a)); |
8f776fd9 TK |
1995 | if (a == NULL) |
1996 | return (NULL); | |
8f776fd9 TK |
1997 | a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC; |
1998 | /* We're ready to write a header immediately. */ | |
1999 | a->archive.state = ARCHIVE_STATE_HEADER; | |
ee99f7fc | 2000 | a->archive.vtable = &archive_write_disk_vtable; |
da0cee61 | 2001 | a->start_time = time(NULL); |
efaf972d TK |
2002 | /* Query and restore the umask. */ |
2003 | umask(a->user_umask = umask(0)); | |
8f776fd9 TK |
2004 | #ifdef HAVE_GETEUID |
2005 | a->user_uid = geteuid(); | |
2006 | #endif /* HAVE_GETEUID */ | |
2007 | if (archive_string_ensure(&a->path_safe, 512) == NULL) { | |
2008 | free(a); | |
2009 | return (NULL); | |
2010 | } | |
0483f5d6 EO |
2011 | a->path_safe.s[0] = 0; |
2012 | ||
fb67a295 | 2013 | #ifdef HAVE_ZLIB_H |
fe61ff64 | 2014 | a->decmpfs_compression_level = 5; |
fb67a295 | 2015 | #endif |
8f776fd9 TK |
2016 | return (&a->archive); |
2017 | } | |
2018 | ||
2019 | ||
2020 | /* | |
2021 | * If pathname is longer than PATH_MAX, chdir to a suitable | |
2022 | * intermediate dir and edit the path down to a shorter suffix. Note | |
2023 | * that this routine never returns an error; if the chdir() attempt | |
2024 | * fails for any reason, we just go ahead with the long pathname. The | |
2025 | * object creation is likely to fail, but any error will get handled | |
2026 | * at that time. | |
2027 | */ | |
bbb7fde3 | 2028 | #if defined(HAVE_FCHDIR) && defined(PATH_MAX) |
8f776fd9 TK |
2029 | static void |
2030 | edit_deep_directories(struct archive_write_disk *a) | |
2031 | { | |
2032 | int ret; | |
2033 | char *tail = a->name; | |
2034 | ||
8f776fd9 | 2035 | /* If path is short, avoid the open() below. */ |
dc1882e4 | 2036 | if (strlen(tail) < PATH_MAX) |
8f776fd9 TK |
2037 | return; |
2038 | ||
2039 | /* Try to record our starting dir. */ | |
6d520405 | 2040 | a->restore_pwd = la_opendirat(AT_FDCWD, "."); |
60141df1 | 2041 | __archive_ensure_cloexec_flag(a->restore_pwd); |
8f776fd9 TK |
2042 | if (a->restore_pwd < 0) |
2043 | return; | |
2044 | ||
2045 | /* As long as the path is too long... */ | |
dc1882e4 | 2046 | while (strlen(tail) >= PATH_MAX) { |
8f776fd9 TK |
2047 | /* Locate a dir prefix shorter than PATH_MAX. */ |
2048 | tail += PATH_MAX - 8; | |
2049 | while (tail > a->name && *tail != '/') | |
2050 | tail--; | |
2051 | /* Exit if we find a too-long path component. */ | |
2052 | if (tail <= a->name) | |
2053 | return; | |
2054 | /* Create the intermediate dir and chdir to it. */ | |
2055 | *tail = '\0'; /* Terminate dir portion */ | |
2056 | ret = create_dir(a, a->name); | |
2057 | if (ret == ARCHIVE_OK && chdir(a->name) != 0) | |
7d4496e9 | 2058 | ret = ARCHIVE_FAILED; |
8f776fd9 TK |
2059 | *tail = '/'; /* Restore the / we removed. */ |
2060 | if (ret != ARCHIVE_OK) | |
2061 | return; | |
2062 | tail++; | |
2063 | /* The chdir() succeeded; we've now shortened the path. */ | |
2064 | a->name = tail; | |
2065 | } | |
2066 | return; | |
2067 | } | |
2068 | #endif | |
2069 | ||
2070 | /* | |
2071 | * The main restore function. | |
2072 | */ | |
2073 | static int | |
2074 | restore_entry(struct archive_write_disk *a) | |
2075 | { | |
2076 | int ret = ARCHIVE_OK, en; | |
2077 | ||
2078 | if (a->flags & ARCHIVE_EXTRACT_UNLINK && !S_ISDIR(a->mode)) { | |
2079 | /* | |
2080 | * TODO: Fix this. Apparently, there are platforms | |
2081 | * that still allow root to hose the entire filesystem | |
2082 | * by unlinking a dir. The S_ISDIR() test above | |
2083 | * prevents us from using unlink() here if the new | |
2084 | * object is a dir, but that doesn't mean the old | |
2085 | * object isn't a dir. | |
2086 | */ | |
6a595ef6 BD |
2087 | if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS) |
2088 | (void)clear_nochange_fflags(a); | |
8f776fd9 | 2089 | if (unlink(a->name) == 0) { |
2f8873c2 JS |
2090 | /* We removed it, reset cached stat. */ |
2091 | a->pst = NULL; | |
8f776fd9 TK |
2092 | } else if (errno == ENOENT) { |
2093 | /* File didn't exist, that's just as good. */ | |
2094 | } else if (rmdir(a->name) == 0) { | |
2095 | /* It was a dir, but now it's gone. */ | |
2f8873c2 | 2096 | a->pst = NULL; |
8f776fd9 TK |
2097 | } else { |
2098 | /* We tried, but couldn't get rid of it. */ | |
2099 | archive_set_error(&a->archive, errno, | |
2100 | "Could not unlink"); | |
7d4496e9 | 2101 | return(ARCHIVE_FAILED); |
8f776fd9 TK |
2102 | } |
2103 | } | |
2104 | ||
2105 | /* Try creating it first; if this fails, we'll try to recover. */ | |
2106 | en = create_filesystem_object(a); | |
2107 | ||
2108 | if ((en == ENOTDIR || en == ENOENT) | |
2109 | && !(a->flags & ARCHIVE_EXTRACT_NO_AUTODIR)) { | |
2110 | /* If the parent dir doesn't exist, try creating it. */ | |
2111 | create_parent_dir(a, a->name); | |
2112 | /* Now try to create the object again. */ | |
2113 | en = create_filesystem_object(a); | |
2114 | } | |
2115 | ||
99d593a4 GP |
2116 | if ((en == ENOENT) && (archive_entry_hardlink(a->entry) != NULL)) { |
2117 | archive_set_error(&a->archive, en, | |
2118 | "Hard-link target '%s' does not exist.", | |
2119 | archive_entry_hardlink(a->entry)); | |
2120 | return (ARCHIVE_FAILED); | |
2121 | } | |
2122 | ||
8f776fd9 TK |
2123 | if ((en == EISDIR || en == EEXIST) |
2124 | && (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) { | |
2125 | /* If we're not overwriting, we're done. */ | |
6674b4aa PS |
2126 | if (S_ISDIR(a->mode)) { |
2127 | /* Don't overwrite any settings on existing directories. */ | |
2128 | a->todo = 0; | |
2129 | } | |
4ec97d24 TK |
2130 | archive_entry_unset_size(a->entry); |
2131 | return (ARCHIVE_OK); | |
8f776fd9 TK |
2132 | } |
2133 | ||
2134 | /* | |
2135 | * Some platforms return EISDIR if you call | |
2136 | * open(O_WRONLY | O_EXCL | O_CREAT) on a directory, some | |
2137 | * return EEXIST. POSIX is ambiguous, requiring EISDIR | |
2138 | * for open(O_WRONLY) on a dir and EEXIST for open(O_EXCL | O_CREAT) | |
2139 | * on an existing item. | |
2140 | */ | |
2141 | if (en == EISDIR) { | |
2142 | /* A dir is in the way of a non-dir, rmdir it. */ | |
2143 | if (rmdir(a->name) != 0) { | |
2144 | archive_set_error(&a->archive, errno, | |
2145 | "Can't remove already-existing dir"); | |
7d4496e9 | 2146 | return (ARCHIVE_FAILED); |
8f776fd9 | 2147 | } |
2f8873c2 | 2148 | a->pst = NULL; |
8f776fd9 TK |
2149 | /* Try again. */ |
2150 | en = create_filesystem_object(a); | |
2151 | } else if (en == EEXIST) { | |
2152 | /* | |
2153 | * We know something is in the way, but we don't know what; | |
2154 | * we need to find out before we go any further. | |
2155 | */ | |
3deba4d2 TK |
2156 | int r = 0; |
2157 | /* | |
cafcd565 | 2158 | * The SECURE_SYMLINKS logic has already removed a |
3deba4d2 TK |
2159 | * symlink to a dir if the client wants that. So |
2160 | * follow the symlink if we're creating a dir. | |
2161 | */ | |
2162 | if (S_ISDIR(a->mode)) | |
bf234723 | 2163 | r = la_stat(a->name, &a->st); |
3deba4d2 TK |
2164 | /* |
2165 | * If it's not a dir (or it's a broken symlink), | |
2166 | * then don't follow it. | |
2167 | */ | |
2168 | if (r != 0 || !S_ISDIR(a->mode)) | |
e6056040 | 2169 | #ifdef HAVE_LSTAT |
3deba4d2 | 2170 | r = lstat(a->name, &a->st); |
e6056040 | 2171 | #else |
2172 | r = la_stat(a->name, &a->st); | |
2173 | #endif | |
3deba4d2 | 2174 | if (r != 0) { |
8f776fd9 TK |
2175 | archive_set_error(&a->archive, errno, |
2176 | "Can't stat existing object"); | |
7d4496e9 | 2177 | return (ARCHIVE_FAILED); |
8f776fd9 TK |
2178 | } |
2179 | ||
623fd7d3 TK |
2180 | /* |
2181 | * NO_OVERWRITE_NEWER doesn't apply to directories. | |
2182 | */ | |
2183 | if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER) | |
2184 | && !S_ISDIR(a->st.st_mode)) { | |
8f776fd9 | 2185 | if (!older(&(a->st), a->entry)) { |
c94df2a2 | 2186 | archive_entry_unset_size(a->entry); |
1584a716 | 2187 | return (ARCHIVE_OK); |
8f776fd9 TK |
2188 | } |
2189 | } | |
2190 | ||
2191 | /* If it's our archive, we're done. */ | |
7457cf54 | 2192 | if (a->skip_file_set && |
7d2cbbc5 MN |
2193 | a->st.st_dev == (dev_t)a->skip_file_dev && |
2194 | a->st.st_ino == (ino_t)a->skip_file_ino) { | |
2195 | archive_set_error(&a->archive, 0, | |
2196 | "Refusing to overwrite archive"); | |
8f776fd9 TK |
2197 | return (ARCHIVE_FAILED); |
2198 | } | |
2199 | ||
2200 | if (!S_ISDIR(a->st.st_mode)) { | |
6a595ef6 BD |
2201 | if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS) |
2202 | (void)clear_nochange_fflags(a); | |
b51d6b62 | 2203 | |
2204 | if ((a->flags & ARCHIVE_EXTRACT_SAFE_WRITES) && | |
2205 | S_ISREG(a->st.st_mode)) { | |
2206 | /* Use a temporary file to extract */ | |
f001f3b0 MM |
2207 | if ((a->fd = la_mktemp(a)) == -1) { |
2208 | archive_set_error(&a->archive, errno, | |
2209 | "Can't create temporary file"); | |
b51d6b62 | 2210 | return ARCHIVE_FAILED; |
f001f3b0 | 2211 | } |
b51d6b62 | 2212 | a->pst = NULL; |
2213 | en = 0; | |
2214 | } else { | |
2215 | /* A non-dir is in the way, unlink it. */ | |
2216 | if (unlink(a->name) != 0) { | |
2217 | archive_set_error(&a->archive, errno, | |
2218 | "Can't unlink already-existing " | |
2219 | "object"); | |
2220 | return (ARCHIVE_FAILED); | |
2221 | } | |
2222 | a->pst = NULL; | |
2223 | /* Try again. */ | |
2224 | en = create_filesystem_object(a); | |
8f776fd9 | 2225 | } |
8f776fd9 TK |
2226 | } else if (!S_ISDIR(a->mode)) { |
2227 | /* A dir is in the way of a non-dir, rmdir it. */ | |
6a595ef6 BD |
2228 | if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS) |
2229 | (void)clear_nochange_fflags(a); | |
8f776fd9 TK |
2230 | if (rmdir(a->name) != 0) { |
2231 | archive_set_error(&a->archive, errno, | |
dc9a0fb4 | 2232 | "Can't replace existing directory with non-directory"); |
7d4496e9 | 2233 | return (ARCHIVE_FAILED); |
8f776fd9 TK |
2234 | } |
2235 | /* Try again. */ | |
2236 | en = create_filesystem_object(a); | |
2237 | } else { | |
2238 | /* | |
2239 | * There's a dir in the way of a dir. Don't | |
2240 | * waste time with rmdir()/mkdir(), just fix | |
2241 | * up the permissions on the existing dir. | |
2242 | * Note that we don't change perms on existing | |
2243 | * dirs unless _EXTRACT_PERM is specified. | |
2244 | */ | |
2245 | if ((a->mode != a->st.st_mode) | |
2246 | && (a->todo & TODO_MODE_FORCE)) | |
2247 | a->deferred |= (a->todo & TODO_MODE); | |
2248 | /* Ownership doesn't need deferred fixup. */ | |
2249 | en = 0; /* Forget the EEXIST. */ | |
2250 | } | |
2251 | } | |
2252 | ||
2253 | if (en) { | |
2254 | /* Everything failed; give up here. */ | |
1bed2f31 MM |
2255 | if ((&a->archive)->error == NULL) |
2256 | archive_set_error(&a->archive, en, "Can't create '%s'", | |
2257 | a->name); | |
7d4496e9 | 2258 | return (ARCHIVE_FAILED); |
8f776fd9 TK |
2259 | } |
2260 | ||
2261 | a->pst = NULL; /* Cached stat data no longer valid. */ | |
2262 | return (ret); | |
2263 | } | |
2264 | ||
2265 | /* | |
2266 | * Returns 0 if creation succeeds, or else returns errno value from | |
2267 | * the failed system call. Note: This function should only ever perform | |
2268 | * a single system call. | |
2269 | */ | |
87599157 | 2270 | static int |
8f776fd9 TK |
2271 | create_filesystem_object(struct archive_write_disk *a) |
2272 | { | |
2273 | /* Create the entry. */ | |
2274 | const char *linkname; | |
2275 | mode_t final_mode, mode; | |
2276 | int r; | |
dfd6b54c TK |
2277 | /* these for check_symlinks_fsobj */ |
2278 | char *linkname_copy; /* non-const copy of linkname */ | |
433e36b0 | 2279 | struct stat st; |
dfd6b54c TK |
2280 | struct archive_string error_string; |
2281 | int error_number; | |
8f776fd9 TK |
2282 | |
2283 | /* We identify hard/symlinks according to the link names. */ | |
2284 | /* Since link(2) and symlink(2) don't handle modes, we're done here. */ | |
2285 | linkname = archive_entry_hardlink(a->entry); | |
2286 | if (linkname != NULL) { | |
4b57c013 TK |
2287 | #if !HAVE_LINK |
2288 | return (EPERM); | |
2289 | #else | |
dfd6b54c TK |
2290 | archive_string_init(&error_string); |
2291 | linkname_copy = strdup(linkname); | |
2292 | if (linkname_copy == NULL) { | |
2293 | return (EPERM); | |
2294 | } | |
cc9cbbb1 MM |
2295 | /* |
2296 | * TODO: consider using the cleaned-up path as the link | |
2297 | * target? | |
2298 | */ | |
2299 | r = cleanup_pathname_fsobj(linkname_copy, &error_number, | |
2300 | &error_string, a->flags); | |
dfd6b54c | 2301 | if (r != ARCHIVE_OK) { |
cc9cbbb1 MM |
2302 | archive_set_error(&a->archive, error_number, "%s", |
2303 | error_string.s); | |
dfd6b54c | 2304 | free(linkname_copy); |
532ff5fb | 2305 | archive_string_free(&error_string); |
cc9cbbb1 MM |
2306 | /* |
2307 | * EPERM is more appropriate than error_number for our | |
2308 | * callers | |
2309 | */ | |
dfd6b54c TK |
2310 | return (EPERM); |
2311 | } | |
cc9cbbb1 | 2312 | r = check_symlinks_fsobj(linkname_copy, &error_number, |
5e646b89 | 2313 | &error_string, a->flags, 1); |
dfd6b54c | 2314 | if (r != ARCHIVE_OK) { |
cc9cbbb1 MM |
2315 | archive_set_error(&a->archive, error_number, "%s", |
2316 | error_string.s); | |
dfd6b54c | 2317 | free(linkname_copy); |
532ff5fb | 2318 | archive_string_free(&error_string); |
cc9cbbb1 MM |
2319 | /* |
2320 | * EPERM is more appropriate than error_number for our | |
2321 | * callers | |
2322 | */ | |
dfd6b54c TK |
2323 | return (EPERM); |
2324 | } | |
2325 | free(linkname_copy); | |
532ff5fb | 2326 | archive_string_free(&error_string); |
b51d6b62 | 2327 | /* |
2328 | * Unlinking and linking here is really not atomic, | |
2329 | * but doing it right, would require us to construct | |
2330 | * an mktemplink() function, and then use rename(2). | |
2331 | */ | |
2332 | if (a->flags & ARCHIVE_EXTRACT_SAFE_WRITES) | |
2333 | unlink(a->name); | |
5e646b89 MM |
2334 | #ifdef HAVE_LINKAT |
2335 | r = linkat(AT_FDCWD, linkname, AT_FDCWD, a->name, | |
2336 | 0) ? errno : 0; | |
2337 | #else | |
8f776fd9 | 2338 | r = link(linkname, a->name) ? errno : 0; |
5e646b89 | 2339 | #endif |
8f776fd9 TK |
2340 | /* |
2341 | * New cpio and pax formats allow hardlink entries | |
2342 | * to carry data, so we may have to open the file | |
2343 | * for hardlink entries. | |
76970580 JS |
2344 | * |
2345 | * If the hardlink was successfully created and | |
2346 | * the archive doesn't have carry data for it, | |
86ada71e | 2347 | * consider it to be non-authoritative for meta data. |
76970580 JS |
2348 | * This is consistent with GNU tar and BSD pax. |
2349 | * If the hardlink does carry data, let the last | |
2350 | * archive entry decide ownership. | |
8f776fd9 | 2351 | */ |
e9c0ba83 | 2352 | if (r == 0 && a->filesize <= 0) { |
76970580 JS |
2353 | a->todo = 0; |
2354 | a->deferred = 0; | |
e47c21de | 2355 | } else if (r == 0 && a->filesize > 0) { |
433e36b0 MM |
2356 | #ifdef HAVE_LSTAT |
2357 | r = lstat(a->name, &st); | |
2358 | #else | |
bf234723 | 2359 | r = la_stat(a->name, &st); |
433e36b0 MM |
2360 | #endif |
2361 | if (r != 0) | |
8f776fd9 | 2362 | r = errno; |
433e36b0 MM |
2363 | else if ((st.st_mode & AE_IFMT) == AE_IFREG) { |
2364 | a->fd = open(a->name, O_WRONLY | O_TRUNC | | |
2365 | O_BINARY | O_CLOEXEC | O_NOFOLLOW); | |
2366 | __archive_ensure_cloexec_flag(a->fd); | |
2367 | if (a->fd < 0) | |
2368 | r = errno; | |
2369 | } | |
8f776fd9 TK |
2370 | } |
2371 | return (r); | |
4b57c013 | 2372 | #endif |
8f776fd9 TK |
2373 | } |
2374 | linkname = archive_entry_symlink(a->entry); | |
4b57c013 TK |
2375 | if (linkname != NULL) { |
2376 | #if HAVE_SYMLINK | |
99e20e46 | 2377 | /* |
2378 | * Unlinking and linking here is really not atomic, | |
2379 | * but doing it right, would require us to construct | |
2380 | * an mktempsymlink() function, and then use rename(2). | |
2381 | */ | |
2382 | if (a->flags & ARCHIVE_EXTRACT_SAFE_WRITES) | |
2383 | unlink(a->name); | |
8f776fd9 | 2384 | return symlink(linkname, a->name) ? errno : 0; |
4b57c013 TK |
2385 | #else |
2386 | return (EPERM); | |
2387 | #endif | |
2388 | } | |
8f776fd9 TK |
2389 | |
2390 | /* | |
2391 | * The remaining system calls all set permissions, so let's | |
2392 | * try to take advantage of that to avoid an extra chmod() | |
2393 | * call. (Recall that umask is set to zero right now!) | |
2394 | */ | |
2395 | ||
2396 | /* Mode we want for the final restored object (w/o file type bits). */ | |
2397 | final_mode = a->mode & 07777; | |
2398 | /* | |
2399 | * The mode that will actually be restored in this step. Note | |
2400 | * that SUID, SGID, etc, require additional work to ensure | |
2401 | * security, so we never restore them at this point. | |
2402 | */ | |
6027a837 | 2403 | mode = final_mode & 0777 & ~a->user_umask; |
8f776fd9 | 2404 | |
d30a8faa EB |
2405 | /* |
2406 | * Always create writable such that [f]setxattr() works if we're not | |
2407 | * root. | |
2408 | */ | |
2409 | if (a->user_uid != 0 && | |
2410 | a->todo & (TODO_HFS_COMPRESSION | TODO_XATTR)) { | |
38c806ec EB |
2411 | mode |= 0200; |
2412 | } | |
2413 | ||
8f776fd9 TK |
2414 | switch (a->mode & AE_IFMT) { |
2415 | default: | |
2416 | /* POSIX requires that we fall through here. */ | |
2417 | /* FALLTHROUGH */ | |
2418 | case AE_IFREG: | |
b51d6b62 | 2419 | a->tmpname = NULL; |
8f776fd9 | 2420 | a->fd = open(a->name, |
60141df1 MN |
2421 | O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, mode); |
2422 | __archive_ensure_cloexec_flag(a->fd); | |
8f776fd9 TK |
2423 | r = (a->fd < 0); |
2424 | break; | |
2425 | case AE_IFCHR: | |
2426 | #ifdef HAVE_MKNOD | |
2427 | /* Note: we use AE_IFCHR for the case label, and | |
2428 | * S_IFCHR for the mknod() call. This is correct. */ | |
2429 | r = mknod(a->name, mode | S_IFCHR, | |
2430 | archive_entry_rdev(a->entry)); | |
3b25664d | 2431 | break; |
8f776fd9 TK |
2432 | #else |
2433 | /* TODO: Find a better way to warn about our inability | |
2434 | * to restore a char device node. */ | |
2435 | return (EINVAL); | |
2436 | #endif /* HAVE_MKNOD */ | |
8f776fd9 TK |
2437 | case AE_IFBLK: |
2438 | #ifdef HAVE_MKNOD | |
2439 | r = mknod(a->name, mode | S_IFBLK, | |
2440 | archive_entry_rdev(a->entry)); | |
3b25664d | 2441 | break; |
8f776fd9 TK |
2442 | #else |
2443 | /* TODO: Find a better way to warn about our inability | |
2444 | * to restore a block device node. */ | |
2445 | return (EINVAL); | |
2446 | #endif /* HAVE_MKNOD */ | |
8f776fd9 TK |
2447 | case AE_IFDIR: |
2448 | mode = (mode | MINIMUM_DIR_MODE) & MAXIMUM_DIR_MODE; | |
2449 | r = mkdir(a->name, mode); | |
2450 | if (r == 0) { | |
2451 | /* Defer setting dir times. */ | |
2452 | a->deferred |= (a->todo & TODO_TIMES); | |
2453 | a->todo &= ~TODO_TIMES; | |
2454 | /* Never use an immediate chmod(). */ | |
71362fca TK |
2455 | /* We can't avoid the chmod() entirely if EXTRACT_PERM |
2456 | * because of SysV SGID inheritance. */ | |
2457 | if ((mode != final_mode) | |
2458 | || (a->flags & ARCHIVE_EXTRACT_PERM)) | |
8f776fd9 TK |
2459 | a->deferred |= (a->todo & TODO_MODE); |
2460 | a->todo &= ~TODO_MODE; | |
2461 | } | |
2462 | break; | |
2463 | case AE_IFIFO: | |
2464 | #ifdef HAVE_MKFIFO | |
2465 | r = mkfifo(a->name, mode); | |
3b25664d | 2466 | break; |
8f776fd9 TK |
2467 | #else |
2468 | /* TODO: Find a better way to warn about our inability | |
2469 | * to restore a fifo. */ | |
2470 | return (EINVAL); | |
2471 | #endif /* HAVE_MKFIFO */ | |
8f776fd9 TK |
2472 | } |
2473 | ||
2474 | /* All the system calls above set errno on failure. */ | |
2475 | if (r) | |
2476 | return (errno); | |
2477 | ||
2478 | /* If we managed to set the final mode, we've avoided a chmod(). */ | |
2479 | if (mode == final_mode) | |
2480 | a->todo &= ~TODO_MODE; | |
2481 | return (0); | |
2482 | } | |
2483 | ||
2484 | /* | |
2485 | * Cleanup function for archive_extract. Mostly, this involves processing | |
2486 | * the fixup list, which is used to address a number of problems: | |
2487 | * * Dir permissions might prevent us from restoring a file in that | |
2488 | * dir, so we restore the dir with minimum 0700 permissions first, | |
2489 | * then correct the mode at the end. | |
2490 | * * Similarly, the act of restoring a file touches the directory | |
2491 | * and changes the timestamp on the dir, so we have to touch-up dir | |
2492 | * timestamps at the end as well. | |
2493 | * * Some file flags can interfere with the restore by, for example, | |
2494 | * preventing the creation of hardlinks to those files. | |
b8ad1655 | 2495 | * * Mac OS extended metadata includes ACLs, so must be deferred on dirs. |
8f776fd9 TK |
2496 | * |
2497 | * Note that tar/cpio do not require that archives be in a particular | |
2498 | * order; there is no way to know when the last file has been restored | |
2499 | * within a directory, so there's no way to optimize the memory usage | |
2500 | * here by fixing up the directory any earlier than the | |
2501 | * end-of-archive. | |
2502 | * | |
2503 | * XXX TODO: Directory ACLs should be restored here, for the same | |
2504 | * reason we set directory perms here. XXX | |
2505 | */ | |
2506 | static int | |
911dc2bf | 2507 | _archive_write_disk_close(struct archive *_a) |
8f776fd9 TK |
2508 | { |
2509 | struct archive_write_disk *a = (struct archive_write_disk *)_a; | |
2510 | struct fixup_entry *next, *p; | |
b41daecb | 2511 | struct stat st; |
8a1bd5c1 | 2512 | char *c; |
ede459d2 | 2513 | int fd, ret, openflags; |
8f776fd9 | 2514 | |
42c1f3e1 | 2515 | archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, |
8f776fd9 TK |
2516 | ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, |
2517 | "archive_write_disk_close"); | |
911dc2bf | 2518 | ret = _archive_write_disk_finish_entry(&a->archive); |
8f776fd9 TK |
2519 | |
2520 | /* Sort dir list so directories are fixed up in depth-first order. */ | |
2521 | p = sort_dir_list(a->fixup_list); | |
2522 | ||
2523 | while (p != NULL) { | |
6d520405 | 2524 | fd = -1; |
8f776fd9 | 2525 | a->pst = NULL; /* Mark stat cache as out-of-date. */ |
8a1bd5c1 MM |
2526 | |
2527 | /* We must strip trailing slashes from the path to avoid | |
2528 | dereferencing symbolic links to directories */ | |
2529 | c = p->name; | |
2530 | while (*c != '\0') | |
2531 | c++; | |
2532 | while (c != p->name && *(c - 1) == '/') { | |
2533 | c--; | |
2534 | *c = '\0'; | |
2535 | } | |
2536 | ||
2537 | if (p->fixup == 0) | |
2538 | goto skip_fixup_entry; | |
2539 | else { | |
ede459d2 MM |
2540 | /* |
2541 | * We need to verify if the type of the file | |
2542 | * we are going to open matches the file type | |
2543 | * of the fixup entry. | |
2544 | */ | |
2545 | openflags = O_BINARY | O_NOFOLLOW | O_RDONLY | |
2546 | | O_CLOEXEC; | |
8a1bd5c1 | 2547 | #if defined(O_DIRECTORY) |
ede459d2 MM |
2548 | if (p->filetype == AE_IFDIR) |
2549 | openflags |= O_DIRECTORY; | |
8a1bd5c1 | 2550 | #endif |
ede459d2 MM |
2551 | fd = open(p->name, openflags); |
2552 | ||
2553 | #if defined(O_DIRECTORY) | |
8a1bd5c1 | 2554 | /* |
ede459d2 MM |
2555 | * If we support O_DIRECTORY and open was |
2556 | * successful we can skip the file type check | |
2557 | * for directories. For other file types | |
2558 | * we need to verify via fstat() or lstat() | |
8a1bd5c1 | 2559 | */ |
ede459d2 MM |
2560 | if (fd == -1 || p->filetype != AE_IFDIR) { |
2561 | #if HAVE_FSTAT | |
2562 | if (fd > 0 && ( | |
2563 | fstat(fd, &st) != 0 || | |
2564 | la_verify_filetype(st.st_mode, | |
2565 | p->filetype) == 0)) { | |
2566 | goto skip_fixup_entry; | |
2567 | } else | |
2568 | #endif | |
e6056040 | 2569 | if ( |
2570 | #ifdef HAVE_LSTAT | |
2571 | lstat(p->name, &st) != 0 || | |
2572 | #else | |
2573 | la_stat(p->name, &st) != 0 || | |
2574 | #endif | |
ede459d2 MM |
2575 | la_verify_filetype(st.st_mode, |
2576 | p->filetype) == 0) { | |
b41daecb | 2577 | goto skip_fixup_entry; |
b41daecb MM |
2578 | } |
2579 | } | |
8a1bd5c1 MM |
2580 | #else |
2581 | #if HAVE_FSTAT | |
2582 | if (fd > 0 && ( | |
ede459d2 MM |
2583 | fstat(fd, &st) != 0 || |
2584 | la_verify_filetype(st.st_mode, | |
2585 | p->filetype) == 0)) { | |
8a1bd5c1 MM |
2586 | goto skip_fixup_entry; |
2587 | } else | |
2588 | #endif | |
e6056040 | 2589 | if ( |
2590 | #ifdef HAVE_LSTAT | |
2591 | lstat(p->name, &st) != 0 || | |
2592 | #else | |
2593 | la_stat(p->name, &st) != 0 || | |
2594 | #endif | |
ede459d2 MM |
2595 | la_verify_filetype(st.st_mode, |
2596 | p->filetype) == 0) { | |
8a1bd5c1 MM |
2597 | goto skip_fixup_entry; |
2598 | } | |
2599 | #endif | |
b837c72c | 2600 | } |
8f776fd9 | 2601 | if (p->fixup & TODO_TIMES) { |
6d520405 | 2602 | set_times(a, fd, p->mode, p->name, |
5223514b TK |
2603 | p->atime, p->atime_nanos, |
2604 | p->birthtime, p->birthtime_nanos, | |
b648c6c7 BJ |
2605 | p->mtime, p->mtime_nanos, |
2606 | p->ctime, p->ctime_nanos); | |
8f776fd9 | 2607 | } |
b837c72c MM |
2608 | if (p->fixup & TODO_MODE_BASE) { |
2609 | #ifdef HAVE_FCHMOD | |
6d520405 | 2610 | if (fd >= 0) |
8a1bd5c1 | 2611 | fchmod(fd, p->mode & 07777); |
b837c72c MM |
2612 | else |
2613 | #endif | |
b41daecb | 2614 | #ifdef HAVE_LCHMOD |
8a1bd5c1 | 2615 | lchmod(p->name, p->mode & 07777); |
b41daecb | 2616 | #else |
8a1bd5c1 | 2617 | chmod(p->name, p->mode & 07777); |
b41daecb | 2618 | #endif |
b837c72c | 2619 | } |
b01b4bc1 | 2620 | if (p->fixup & TODO_ACLS) |
6d520405 | 2621 | archive_write_disk_set_acls(&a->archive, fd, |
b837c72c | 2622 | p->name, &p->acl, p->mode); |
8f776fd9 | 2623 | if (p->fixup & TODO_FFLAGS) |
6d520405 | 2624 | set_fflags_platform(a, fd, p->name, |
8f776fd9 | 2625 | p->mode, p->fflags_set, 0); |
b8ad1655 TK |
2626 | if (p->fixup & TODO_MAC_METADATA) |
2627 | set_mac_metadata(a, p->name, p->mac_metadata, | |
2628 | p->mac_metadata_size); | |
b41daecb | 2629 | skip_fixup_entry: |
8f776fd9 | 2630 | next = p->next; |
b01b4bc1 | 2631 | archive_acl_clear(&p->acl); |
b8ad1655 | 2632 | free(p->mac_metadata); |
8f776fd9 | 2633 | free(p->name); |
6d520405 MM |
2634 | if (fd >= 0) |
2635 | close(fd); | |
8f776fd9 TK |
2636 | free(p); |
2637 | p = next; | |
2638 | } | |
2639 | a->fixup_list = NULL; | |
2640 | return (ret); | |
2641 | } | |
2642 | ||
2643 | static int | |
911dc2bf | 2644 | _archive_write_disk_free(struct archive *_a) |
8f776fd9 | 2645 | { |
42c1f3e1 | 2646 | struct archive_write_disk *a; |
8f776fd9 | 2647 | int ret; |
42c1f3e1 TK |
2648 | if (_a == NULL) |
2649 | return (ARCHIVE_OK); | |
2650 | archive_check_magic(_a, ARCHIVE_WRITE_DISK_MAGIC, | |
2651 | ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_write_disk_free"); | |
2652 | a = (struct archive_write_disk *)_a; | |
911dc2bf | 2653 | ret = _archive_write_disk_close(&a->archive); |
f4f791ea TK |
2654 | archive_write_disk_set_group_lookup(&a->archive, NULL, NULL, NULL); |
2655 | archive_write_disk_set_user_lookup(&a->archive, NULL, NULL, NULL); | |
4736e4e7 | 2656 | archive_entry_free(a->entry); |
8f776fd9 | 2657 | archive_string_free(&a->_name_data); |
b51d6b62 | 2658 | archive_string_free(&a->_tmpname_data); |
8f776fd9 TK |
2659 | archive_string_free(&a->archive.error_string); |
2660 | archive_string_free(&a->path_safe); | |
42c1f3e1 | 2661 | a->archive.magic = 0; |
d1899374 | 2662 | __archive_clean(&a->archive); |
fb67a295 | 2663 | free(a->decmpfs_header_p); |
fb67a295 MN |
2664 | free(a->resource_fork); |
2665 | free(a->compressed_buffer); | |
2666 | free(a->uncompressed_buffer); | |
a9a9683f PB |
2667 | #if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\ |
2668 | && defined(HAVE_ZLIB_H) | |
fb67a295 MN |
2669 | if (a->stream_valid) { |
2670 | switch (deflateEnd(&a->stream)) { | |
2671 | case Z_OK: | |
2672 | break; | |
2673 | default: | |
2674 | archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, | |
2675 | "Failed to clean up compressor"); | |
2676 | ret = ARCHIVE_FATAL; | |
2677 | break; | |
2678 | } | |
2679 | } | |
2680 | #endif | |
8f776fd9 TK |
2681 | free(a); |
2682 | return (ret); | |
2683 | } | |
2684 | ||
2685 | /* | |
2686 | * Simple O(n log n) merge sort to order the fixup list. In | |
2687 | * particular, we want to restore dir timestamps depth-first. | |
2688 | */ | |
2689 | static struct fixup_entry * | |
2690 | sort_dir_list(struct fixup_entry *p) | |
2691 | { | |
2692 | struct fixup_entry *a, *b, *t; | |
2693 | ||
2694 | if (p == NULL) | |
2695 | return (NULL); | |
2696 | /* A one-item list is already sorted. */ | |
2697 | if (p->next == NULL) | |
2698 | return (p); | |
2699 | ||
2700 | /* Step 1: split the list. */ | |
2701 | t = p; | |
2702 | a = p->next->next; | |
2703 | while (a != NULL) { | |
2704 | /* Step a twice, t once. */ | |
2705 | a = a->next; | |
2706 | if (a != NULL) | |
2707 | a = a->next; | |
2708 | t = t->next; | |
2709 | } | |
2710 | /* Now, t is at the mid-point, so break the list here. */ | |
2711 | b = t->next; | |
2712 | t->next = NULL; | |
2713 | a = p; | |
2714 | ||
2715 | /* Step 2: Recursively sort the two sub-lists. */ | |
2716 | a = sort_dir_list(a); | |
2717 | b = sort_dir_list(b); | |
2718 | ||
2719 | /* Step 3: Merge the returned lists. */ | |
2720 | /* Pick the first element for the merged list. */ | |
2721 | if (strcmp(a->name, b->name) > 0) { | |
2722 | t = p = a; | |
2723 | a = a->next; | |
2724 | } else { | |
2725 | t = p = b; | |
2726 | b = b->next; | |
2727 | } | |
2728 | ||
2729 | /* Always put the later element on the list first. */ | |
2730 | while (a != NULL && b != NULL) { | |
2731 | if (strcmp(a->name, b->name) > 0) { | |
2732 | t->next = a; | |
2733 | a = a->next; | |
2734 | } else { | |
2735 | t->next = b; | |
2736 | b = b->next; | |
2737 | } | |
2738 | t = t->next; | |
2739 | } | |
2740 | ||
2741 | /* Only one list is non-empty, so just splice it on. */ | |
2742 | if (a != NULL) | |
2743 | t->next = a; | |
2744 | if (b != NULL) | |
2745 | t->next = b; | |
2746 | ||
2747 | return (p); | |
2748 | } | |
2749 | ||
2750 | /* | |
2751 | * Returns a new, initialized fixup entry. | |
2752 | * | |
2753 | * TODO: Reduce the memory requirements for this list by using a tree | |
2754 | * structure rather than a simple list of names. | |
2755 | */ | |
2756 | static struct fixup_entry * | |
2757 | new_fixup(struct archive_write_disk *a, const char *pathname) | |
2758 | { | |
2759 | struct fixup_entry *fe; | |
2760 | ||
dc467ac4 | 2761 | fe = (struct fixup_entry *)calloc(1, sizeof(struct fixup_entry)); |
62756a10 MN |
2762 | if (fe == NULL) { |
2763 | archive_set_error(&a->archive, ENOMEM, | |
2764 | "Can't allocate memory for a fixup"); | |
8f776fd9 | 2765 | return (NULL); |
62756a10 | 2766 | } |
8f776fd9 TK |
2767 | fe->next = a->fixup_list; |
2768 | a->fixup_list = fe; | |
2769 | fe->fixup = 0; | |
ede459d2 | 2770 | fe->filetype = 0; |
8f776fd9 TK |
2771 | fe->name = strdup(pathname); |
2772 | return (fe); | |
2773 | } | |
2774 | ||
2775 | /* | |
2776 | * Returns a fixup structure for the current entry. | |
2777 | */ | |
2778 | static struct fixup_entry * | |
2779 | current_fixup(struct archive_write_disk *a, const char *pathname) | |
2780 | { | |
2781 | if (a->current_fixup == NULL) | |
2782 | a->current_fixup = new_fixup(a, pathname); | |
2783 | return (a->current_fixup); | |
2784 | } | |
2785 | ||
1bed2f31 MM |
2786 | /* Error helper for new *_fsobj functions */ |
2787 | static void | |
2788 | fsobj_error(int *a_eno, struct archive_string *a_estr, | |
2789 | int err, const char *errstr, const char *path) | |
2790 | { | |
2791 | if (a_eno) | |
2792 | *a_eno = err; | |
2793 | if (a_estr) | |
dce4ade5 | 2794 | archive_string_sprintf(a_estr, "%s%s", errstr, path); |
1bed2f31 MM |
2795 | } |
2796 | ||
8f776fd9 TK |
2797 | /* |
2798 | * TODO: Someday, integrate this with the deep dir support; they both | |
2799 | * scan the path and both can be optimized by comparing against other | |
2800 | * recent paths. | |
2801 | */ | |
dfd6b54c TK |
2802 | /* |
2803 | * Checks the given path to see if any elements along it are symlinks. Returns | |
2804 | * ARCHIVE_OK if there are none, otherwise puts an error in errmsg. | |
2805 | */ | |
8f776fd9 | 2806 | static int |
1bed2f31 | 2807 | check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr, |
13023595 | 2808 | int flags, int checking_linkname) |
8f776fd9 | 2809 | { |
b6655592 MM |
2810 | #if !defined(HAVE_LSTAT) && \ |
2811 | !(defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)) | |
4b57c013 | 2812 | /* Platform doesn't have lstat, so we can't look for symlinks. */ |
dfd6b54c | 2813 | (void)path; /* UNUSED */ |
c684b115 | 2814 | (void)a_eno; /* UNUSED */ |
2815 | (void)a_estr; /* UNUSED */ | |
dfd6b54c | 2816 | (void)flags; /* UNUSED */ |
13023595 | 2817 | (void)checking_linkname; /* UNUSED */ |
4b57c013 TK |
2818 | return (ARCHIVE_OK); |
2819 | #else | |
dfd6b54c TK |
2820 | int res = ARCHIVE_OK; |
2821 | char *tail; | |
2822 | char *head; | |
2823 | int last; | |
186116ce | 2824 | char c = '\0'; |
8f776fd9 TK |
2825 | int r; |
2826 | struct stat st; | |
b6655592 MM |
2827 | int chdir_fd; |
2828 | #if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT) | |
2829 | int fd; | |
2830 | #endif | |
dfd6b54c TK |
2831 | |
2832 | /* Nothing to do here if name is empty */ | |
2833 | if(path[0] == '\0') | |
2834 | return (ARCHIVE_OK); | |
8f776fd9 TK |
2835 | |
2836 | /* | |
2837 | * Guard against symlink tricks. Reject any archive entry whose | |
2838 | * destination would be altered by a symlink. | |
dfd6b54c TK |
2839 | * |
2840 | * Walk the filename in chunks separated by '/'. For each segment: | |
2841 | * - if it doesn't exist, continue | |
2842 | * - if it's symlink, abort or remove it | |
2843 | * - if it's a directory and it's not the last chunk, cd into it | |
2844 | * As we go: | |
2845 | * head points to the current (relative) path | |
cc9cbbb1 MM |
2846 | * tail points to the temporary \0 terminating the segment we're |
2847 | * currently examining | |
dfd6b54c TK |
2848 | * c holds what used to be in *tail |
2849 | * last is 1 if this is the last tail | |
8f776fd9 | 2850 | */ |
b6655592 MM |
2851 | chdir_fd = la_opendirat(AT_FDCWD, "."); |
2852 | __archive_ensure_cloexec_flag(chdir_fd); | |
2853 | if (chdir_fd < 0) { | |
2c65d83f PC |
2854 | fsobj_error(a_eno, a_estr, errno, |
2855 | "Could not open ", path); | |
dfd6b54c | 2856 | return (ARCHIVE_FATAL); |
2c65d83f | 2857 | } |
dfd6b54c TK |
2858 | head = path; |
2859 | tail = path; | |
2860 | last = 0; | |
2861 | /* TODO: reintroduce a safe cache here? */ | |
41ae0cf8 | 2862 | /* Skip the root directory if the path is absolute. */ |
dfd6b54c TK |
2863 | if(tail == path && tail[0] == '/') |
2864 | ++tail; | |
2865 | /* Keep going until we've checked the entire name. | |
2866 | * head, tail, path all alias the same string, which is | |
2867 | * temporarily zeroed at tail, so be careful restoring the | |
2868 | * stashed (c=tail[0]) for error messages. | |
2869 | * Exiting the loop with break is okay; continue is not. | |
2870 | */ | |
2871 | while (!last) { | |
cc9cbbb1 MM |
2872 | /* |
2873 | * Skip the separator we just consumed, plus any adjacent ones | |
2874 | */ | |
dfd6b54c TK |
2875 | while (*tail == '/') |
2876 | ++tail; | |
8f776fd9 | 2877 | /* Skip the next path element. */ |
dfd6b54c TK |
2878 | while (*tail != '\0' && *tail != '/') |
2879 | ++tail; | |
2880 | /* is this the last path component? */ | |
2881 | last = (tail[0] == '\0') || (tail[0] == '/' && tail[1] == '\0'); | |
2882 | /* temporarily truncate the string here */ | |
2883 | c = tail[0]; | |
2884 | tail[0] = '\0'; | |
8f776fd9 | 2885 | /* Check that we haven't hit a symlink. */ |
b6655592 MM |
2886 | #if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT) |
2887 | r = fstatat(chdir_fd, head, &st, AT_SYMLINK_NOFOLLOW); | |
e6056040 | 2888 | #elif defined(HAVE_LSTAT) |
dfd6b54c | 2889 | r = lstat(head, &st); |
e6056040 | 2890 | #else |
2891 | r = la_stat(head, &st); | |
b6655592 | 2892 | #endif |
8f776fd9 | 2893 | if (r != 0) { |
dfd6b54c | 2894 | tail[0] = c; |
8f776fd9 | 2895 | /* We've hit a dir that doesn't exist; stop now. */ |
1fa9c7bf | 2896 | if (errno == ENOENT) { |
8f776fd9 | 2897 | break; |
1fa9c7bf | 2898 | } else { |
cc9cbbb1 MM |
2899 | /* |
2900 | * Treat any other error as fatal - best to be | |
2901 | * paranoid here. | |
2902 | * Note: This effectively disables deep | |
2903 | * directory support when security checks are | |
2904 | * enabled. Otherwise, very long pathnames that | |
2905 | * trigger an error here could evade the | |
2906 | * sandbox. | |
2907 | * TODO: We could do better, but it would | |
2908 | * probably require merging the symlink checks | |
2909 | * with the deep-directory editing. | |
2910 | */ | |
1bed2f31 | 2911 | fsobj_error(a_eno, a_estr, errno, |
dce4ade5 | 2912 | "Could not stat ", path); |
dfd6b54c TK |
2913 | res = ARCHIVE_FAILED; |
2914 | break; | |
2915 | } | |
2916 | } else if (S_ISDIR(st.st_mode)) { | |
2917 | if (!last) { | |
b6655592 MM |
2918 | #if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT) |
2919 | fd = la_opendirat(chdir_fd, head); | |
2920 | if (fd < 0) | |
2921 | r = -1; | |
2922 | else { | |
2923 | r = 0; | |
2924 | close(chdir_fd); | |
2925 | chdir_fd = fd; | |
2926 | } | |
2927 | #else | |
2928 | r = chdir(head); | |
2929 | #endif | |
2930 | if (r != 0) { | |
dfd6b54c | 2931 | tail[0] = c; |
1bed2f31 | 2932 | fsobj_error(a_eno, a_estr, errno, |
dce4ade5 | 2933 | "Could not chdir ", path); |
dfd6b54c TK |
2934 | res = (ARCHIVE_FATAL); |
2935 | break; | |
2936 | } | |
2937 | /* Our view is now from inside this dir: */ | |
2938 | head = tail + 1; | |
1fa9c7bf | 2939 | } |
8f776fd9 | 2940 | } else if (S_ISLNK(st.st_mode)) { |
13023595 | 2941 | if (last && checking_linkname) { |
5e646b89 MM |
2942 | #ifdef HAVE_LINKAT |
2943 | /* | |
2944 | * Hardlinks to symlinks are safe to write | |
2945 | * if linkat() is supported as it does not | |
2946 | * follow symlinks. | |
2947 | */ | |
2948 | res = ARCHIVE_OK; | |
2949 | #else | |
2950 | /* | |
2951 | * We return ARCHIVE_FAILED here as we are | |
2952 | * not able to safely write hardlinks | |
2953 | * to symlinks. | |
2954 | */ | |
2955 | tail[0] = c; | |
2956 | fsobj_error(a_eno, a_estr, errno, | |
2957 | "Cannot write hardlink to symlink ", | |
2958 | path); | |
2959 | res = ARCHIVE_FAILED; | |
2960 | #endif | |
2961 | break; | |
2962 | } else | |
dfd6b54c | 2963 | if (last) { |
8f776fd9 TK |
2964 | /* |
2965 | * Last element is symlink; remove it | |
2966 | * so we can overwrite it with the | |
2967 | * item being extracted. | |
2968 | */ | |
b6655592 MM |
2969 | #if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT) |
2970 | r = unlinkat(chdir_fd, head, 0); | |
2971 | #else | |
2972 | r = unlink(head); | |
2973 | #endif | |
2974 | if (r != 0) { | |
dfd6b54c | 2975 | tail[0] = c; |
1bed2f31 | 2976 | fsobj_error(a_eno, a_estr, errno, |
dce4ade5 | 2977 | "Could not remove symlink ", |
1bed2f31 | 2978 | path); |
dfd6b54c TK |
2979 | res = ARCHIVE_FAILED; |
2980 | break; | |
8f776fd9 TK |
2981 | } |
2982 | /* | |
2983 | * Even if we did remove it, a warning | |
2984 | * is in order. The warning is silly, | |
2985 | * though, if we're just replacing one | |
2986 | * symlink with another symlink. | |
2987 | */ | |
dfd6b54c | 2988 | tail[0] = c; |
cc9cbbb1 MM |
2989 | /* |
2990 | * FIXME: not sure how important this is to | |
2991 | * restore | |
2992 | */ | |
2993 | /* | |
dfd6b54c | 2994 | if (!S_ISLNK(path)) { |
1bed2f31 | 2995 | fsobj_error(a_eno, a_estr, 0, |
dce4ade5 | 2996 | "Removing symlink ", path); |
8f776fd9 | 2997 | } |
dfd6b54c | 2998 | */ |
8f776fd9 | 2999 | /* Symlink gone. No more problem! */ |
dfd6b54c TK |
3000 | res = ARCHIVE_OK; |
3001 | break; | |
3002 | } else if (flags & ARCHIVE_EXTRACT_UNLINK) { | |
8f776fd9 | 3003 | /* User asked us to remove problems. */ |
b6655592 MM |
3004 | #if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT) |
3005 | r = unlinkat(chdir_fd, head, 0); | |
3006 | #else | |
3007 | r = unlink(head); | |
3008 | #endif | |
3009 | if (r != 0) { | |
dfd6b54c | 3010 | tail[0] = c; |
1bed2f31 MM |
3011 | fsobj_error(a_eno, a_estr, 0, |
3012 | "Cannot remove intervening " | |
dce4ade5 | 3013 | "symlink ", path); |
dfd6b54c TK |
3014 | res = ARCHIVE_FAILED; |
3015 | break; | |
8f776fd9 | 3016 | } |
dfd6b54c | 3017 | tail[0] = c; |
256e52f0 MM |
3018 | } else if ((flags & |
3019 | ARCHIVE_EXTRACT_SECURE_SYMLINKS) == 0) { | |
3020 | /* | |
3021 | * We are not the last element and we want to | |
3022 | * follow symlinks if they are a directory. | |
3023 | * | |
3024 | * This is needed to extract hardlinks over | |
3025 | * symlinks. | |
3026 | */ | |
b6655592 MM |
3027 | #if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT) |
3028 | r = fstatat(chdir_fd, head, &st, 0); | |
3029 | #else | |
bf234723 | 3030 | r = la_stat(head, &st); |
b6655592 | 3031 | #endif |
256e52f0 MM |
3032 | if (r != 0) { |
3033 | tail[0] = c; | |
3034 | if (errno == ENOENT) { | |
3035 | break; | |
3036 | } else { | |
3037 | fsobj_error(a_eno, a_estr, | |
3038 | errno, | |
dce4ade5 | 3039 | "Could not stat ", path); |
256e52f0 MM |
3040 | res = (ARCHIVE_FAILED); |
3041 | break; | |
3042 | } | |
3043 | } else if (S_ISDIR(st.st_mode)) { | |
b6655592 MM |
3044 | #if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT) |
3045 | fd = la_opendirat(chdir_fd, head); | |
3046 | if (fd < 0) | |
3047 | r = -1; | |
3048 | else { | |
3049 | r = 0; | |
3050 | close(chdir_fd); | |
3051 | chdir_fd = fd; | |
3052 | } | |
3053 | #else | |
3054 | r = chdir(head); | |
3055 | #endif | |
3056 | if (r != 0) { | |
256e52f0 MM |
3057 | tail[0] = c; |
3058 | fsobj_error(a_eno, a_estr, | |
3059 | errno, | |
dce4ade5 | 3060 | "Could not chdir ", path); |
256e52f0 MM |
3061 | res = (ARCHIVE_FATAL); |
3062 | break; | |
3063 | } | |
3064 | /* | |
3065 | * Our view is now from inside | |
3066 | * this dir: | |
3067 | */ | |
3068 | head = tail + 1; | |
3069 | } else { | |
3070 | tail[0] = c; | |
3071 | fsobj_error(a_eno, a_estr, 0, | |
3072 | "Cannot extract through " | |
dce4ade5 | 3073 | "symlink ", path); |
256e52f0 MM |
3074 | res = ARCHIVE_FAILED; |
3075 | break; | |
3076 | } | |
8f776fd9 | 3077 | } else { |
dfd6b54c | 3078 | tail[0] = c; |
1bed2f31 | 3079 | fsobj_error(a_eno, a_estr, 0, |
dce4ade5 | 3080 | "Cannot extract through symlink ", path); |
dfd6b54c TK |
3081 | res = ARCHIVE_FAILED; |
3082 | break; | |
8f776fd9 TK |
3083 | } |
3084 | } | |
dfd6b54c TK |
3085 | /* be sure to always maintain this */ |
3086 | tail[0] = c; | |
3087 | if (tail[0] != '\0') | |
3088 | tail++; /* Advance to the next segment. */ | |
3089 | } | |
3090 | /* Catches loop exits via break */ | |
3091 | tail[0] = c; | |
b6655592 MM |
3092 | #if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT) |
3093 | /* If we operate with openat(), fstatat() and unlinkat() there was | |
3094 | * no chdir(), so just close the fd */ | |
3095 | if (chdir_fd >= 0) | |
3096 | close(chdir_fd); | |
3097 | #elif HAVE_FCHDIR | |
dfd6b54c | 3098 | /* If we changed directory above, restore it here. */ |
b6655592 MM |
3099 | if (chdir_fd >= 0) { |
3100 | r = fchdir(chdir_fd); | |
dfd6b54c | 3101 | if (r != 0) { |
1bed2f31 MM |
3102 | fsobj_error(a_eno, a_estr, errno, |
3103 | "chdir() failure", ""); | |
dfd6b54c | 3104 | } |
b6655592 MM |
3105 | close(chdir_fd); |
3106 | chdir_fd = -1; | |
dfd6b54c TK |
3107 | if (r != 0) { |
3108 | res = (ARCHIVE_FATAL); | |
3109 | } | |
8f776fd9 | 3110 | } |
dfd6b54c TK |
3111 | #endif |
3112 | /* TODO: reintroduce a safe cache here? */ | |
3113 | return res; | |
4b57c013 | 3114 | #endif |
8f776fd9 TK |
3115 | } |
3116 | ||
dfd6b54c TK |
3117 | /* |
3118 | * Check a->name for symlinks, returning ARCHIVE_OK if its clean, otherwise | |
3119 | * calls archive_set_error and returns ARCHIVE_{FATAL,FAILED} | |
3120 | */ | |
3121 | static int | |
3122 | check_symlinks(struct archive_write_disk *a) | |
3123 | { | |
3124 | struct archive_string error_string; | |
3125 | int error_number; | |
3126 | int rc; | |
3127 | archive_string_init(&error_string); | |
cc9cbbb1 | 3128 | rc = check_symlinks_fsobj(a->name, &error_number, &error_string, |
5e646b89 | 3129 | a->flags, 0); |
dfd6b54c | 3130 | if (rc != ARCHIVE_OK) { |
cc9cbbb1 MM |
3131 | archive_set_error(&a->archive, error_number, "%s", |
3132 | error_string.s); | |
dfd6b54c TK |
3133 | } |
3134 | archive_string_free(&error_string); | |
3135 | a->pst = NULL; /* to be safe */ | |
3136 | return rc; | |
3137 | } | |
3138 | ||
3139 | ||
a4b94153 MN |
3140 | #if defined(__CYGWIN__) |
3141 | /* | |
3142 | * 1. Convert a path separator from '\' to '/' . | |
3143 | * We shouldn't check multibyte character directly because some | |
3144 | * character-set have been using the '\' character for a part of | |
3145 | * its multibyte character code. | |
3146 | * 2. Replace unusable characters in Windows with underscore('_'). | |
3147 | * See also : http://msdn.microsoft.com/en-us/library/aa365247.aspx | |
3148 | */ | |
3149 | static void | |
764f7989 | 3150 | cleanup_pathname_win(char *path) |
a4b94153 MN |
3151 | { |
3152 | wchar_t wc; | |
3153 | char *p; | |
3154 | size_t alen, l; | |
3155 | int mb, complete, utf8; | |
3156 | ||
3157 | alen = 0; | |
3158 | mb = 0; | |
3159 | complete = 1; | |
3160 | utf8 = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)? 1: 0; | |
764f7989 | 3161 | for (p = path; *p != '\0'; p++) { |
a4b94153 MN |
3162 | ++alen; |
3163 | if (*p == '\\') { | |
3164 | /* If previous byte is smaller than 128, | |
3165 | * this is not second byte of multibyte characters, | |
3166 | * so we can replace '\' with '/'. */ | |
3167 | if (utf8 || !mb) | |
3168 | *p = '/'; | |
3169 | else | |
3170 | complete = 0;/* uncompleted. */ | |
3171 | } else if (*(unsigned char *)p > 127) | |
3172 | mb = 1; | |
3173 | else | |
3174 | mb = 0; | |
cafcd565 | 3175 | /* Rewrite the path name if its next character is unusable. */ |
a4b94153 MN |
3176 | if (*p == ':' || *p == '*' || *p == '?' || *p == '"' || |
3177 | *p == '<' || *p == '>' || *p == '|') | |
3178 | *p = '_'; | |
3179 | } | |
3180 | if (complete) | |
3181 | return; | |
3182 | ||
3183 | /* | |
3184 | * Convert path separator in wide-character. | |
3185 | */ | |
764f7989 | 3186 | p = path; |
a4b94153 MN |
3187 | while (*p != '\0' && alen) { |
3188 | l = mbtowc(&wc, p, alen); | |
d2d75ef8 | 3189 | if (l == (size_t)-1) { |
a4b94153 MN |
3190 | while (*p != '\0') { |
3191 | if (*p == '\\') | |
3192 | *p = '/'; | |
3193 | ++p; | |
3194 | } | |
3195 | break; | |
3196 | } | |
3197 | if (l == 1 && wc == L'\\') | |
3198 | *p = '/'; | |
3199 | p += l; | |
3200 | alen -= l; | |
3201 | } | |
3202 | } | |
3203 | #endif | |
3204 | ||
8f776fd9 TK |
3205 | /* |
3206 | * Canonicalize the pathname. In particular, this strips duplicate | |
3207 | * '/' characters, '.' elements, and trailing '/'. It also raises an | |
59357157 AG |
3208 | * error for an empty path, a trailing '..', (if _SECURE_NODOTDOT is |
3209 | * set) any '..' in the path or (if ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS | |
3210 | * is set) if the path is absolute. | |
8f776fd9 TK |
3211 | */ |
3212 | static int | |
1bed2f31 MM |
3213 | cleanup_pathname_fsobj(char *path, int *a_eno, struct archive_string *a_estr, |
3214 | int flags) | |
8f776fd9 TK |
3215 | { |
3216 | char *dest, *src; | |
3217 | char separator = '\0'; | |
8f776fd9 | 3218 | |
dfd6b54c | 3219 | dest = src = path; |
8f776fd9 | 3220 | if (*src == '\0') { |
1bed2f31 MM |
3221 | fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC, |
3222 | "Invalid empty ", "pathname"); | |
114420d4 | 3223 | return (ARCHIVE_FAILED); |
8f776fd9 TK |
3224 | } |
3225 | ||
a4b94153 | 3226 | #if defined(__CYGWIN__) |
764f7989 | 3227 | cleanup_pathname_win(path); |
a4b94153 | 3228 | #endif |
8f776fd9 | 3229 | /* Skip leading '/'. */ |
59357157 | 3230 | if (*src == '/') { |
dfd6b54c | 3231 | if (flags & ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS) { |
1bed2f31 MM |
3232 | fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC, |
3233 | "Path is ", "absolute"); | |
59357157 AG |
3234 | return (ARCHIVE_FAILED); |
3235 | } | |
3236 | ||
8f776fd9 | 3237 | separator = *src++; |
59357157 | 3238 | } |
8f776fd9 TK |
3239 | |
3240 | /* Scan the pathname one element at a time. */ | |
3241 | for (;;) { | |
3242 | /* src points to first char after '/' */ | |
3243 | if (src[0] == '\0') { | |
3244 | break; | |
3245 | } else if (src[0] == '/') { | |
3246 | /* Found '//', ignore second one. */ | |
3247 | src++; | |
3248 | continue; | |
3249 | } else if (src[0] == '.') { | |
3250 | if (src[1] == '\0') { | |
3251 | /* Ignore trailing '.' */ | |
3252 | break; | |
3253 | } else if (src[1] == '/') { | |
3254 | /* Skip './'. */ | |
3255 | src += 2; | |
3256 | continue; | |
3257 | } else if (src[1] == '.') { | |
3258 | if (src[2] == '/' || src[2] == '\0') { | |
3259 | /* Conditionally warn about '..' */ | |
cc9cbbb1 MM |
3260 | if (flags |
3261 | & ARCHIVE_EXTRACT_SECURE_NODOTDOT) { | |
1bed2f31 MM |
3262 | fsobj_error(a_eno, a_estr, |
3263 | ARCHIVE_ERRNO_MISC, | |
3264 | "Path contains ", "'..'"); | |
114420d4 | 3265 | return (ARCHIVE_FAILED); |
8f776fd9 | 3266 | } |
691997fd | 3267 | } |
8f776fd9 TK |
3268 | /* |
3269 | * Note: Under no circumstances do we | |
3270 | * remove '..' elements. In | |
3271 | * particular, restoring | |
3272 | * '/foo/../bar/' should create the | |
3273 | * 'foo' dir as a side-effect. | |
3274 | */ | |
691997fd TK |
3275 | } |
3276 | } | |
8f776fd9 TK |
3277 | |
3278 | /* Copy current element, including leading '/'. */ | |
3279 | if (separator) | |
3280 | *dest++ = '/'; | |
3281 | while (*src != '\0' && *src != '/') { | |
3282 | *dest++ = *src++; | |
3283 | } | |
3284 | ||
3285 | if (*src == '\0') | |
3286 | break; | |
3287 | ||
3288 | /* Skip '/' separator. */ | |
3289 | separator = *src++; | |
3290 | } | |
3291 | /* | |
3292 | * We've just copied zero or more path elements, not including the | |
3293 | * final '/'. | |
3294 | */ | |
dfd6b54c | 3295 | if (dest == path) { |
8f776fd9 TK |
3296 | /* |
3297 | * Nothing got copied. The path must have been something | |
3298 | * like '.' or '/' or './' or '/././././/./'. | |
3299 | */ | |
3300 | if (separator) | |
3301 | *dest++ = '/'; | |
3302 | else | |
3303 | *dest++ = '.'; | |
3304 | } | |
3305 | /* Terminate the result. */ | |
3306 | *dest = '\0'; | |
3307 | return (ARCHIVE_OK); | |
3308 | } | |
3309 | ||
dfd6b54c TK |
3310 | static int |
3311 | cleanup_pathname(struct archive_write_disk *a) | |
3312 | { | |
3313 | struct archive_string error_string; | |
3314 | int error_number; | |
3315 | int rc; | |
3316 | archive_string_init(&error_string); | |
cc9cbbb1 MM |
3317 | rc = cleanup_pathname_fsobj(a->name, &error_number, &error_string, |
3318 | a->flags); | |
dfd6b54c | 3319 | if (rc != ARCHIVE_OK) { |
cc9cbbb1 MM |
3320 | archive_set_error(&a->archive, error_number, "%s", |
3321 | error_string.s); | |
dfd6b54c TK |
3322 | } |
3323 | archive_string_free(&error_string); | |
3324 | return rc; | |
3325 | } | |
3326 | ||
8f776fd9 TK |
3327 | /* |
3328 | * Create the parent directory of the specified path, assuming path | |
3329 | * is already in mutable storage. | |
3330 | */ | |
3331 | static int | |
3332 | create_parent_dir(struct archive_write_disk *a, char *path) | |
3333 | { | |
3334 | char *slash; | |
3335 | int r; | |
3336 | ||
3337 | /* Remove tail element to obtain parent name. */ | |
3338 | slash = strrchr(path, '/'); | |
3339 | if (slash == NULL) | |
3340 | return (ARCHIVE_OK); | |
3341 | *slash = '\0'; | |
3342 | r = create_dir(a, path); | |
3343 | *slash = '/'; | |
3344 | return (r); | |
3345 | } | |
3346 | ||
3347 | /* | |
3348 | * Create the specified dir, recursing to create parents as necessary. | |
3349 | * | |
3350 | * Returns ARCHIVE_OK if the path exists when we're done here. | |
7d4496e9 | 3351 | * Otherwise, returns ARCHIVE_FAILED. |
8f776fd9 TK |
3352 | * Assumes path is in mutable storage; path is unchanged on exit. |
3353 | */ | |
3354 | static int | |
3355 | create_dir(struct archive_write_disk *a, char *path) | |
3356 | { | |
3357 | struct stat st; | |
3358 | struct fixup_entry *le; | |
3359 | char *slash, *base; | |
3360 | mode_t mode_final, mode; | |
3361 | int r; | |
3362 | ||
8f776fd9 TK |
3363 | /* Check for special names and just skip them. */ |
3364 | slash = strrchr(path, '/'); | |
3365 | if (slash == NULL) | |
3366 | base = path; | |
3367 | else | |
3368 | base = slash + 1; | |
3369 | ||
3370 | if (base[0] == '\0' || | |
3371 | (base[0] == '.' && base[1] == '\0') || | |
3372 | (base[0] == '.' && base[1] == '.' && base[2] == '\0')) { | |
3373 | /* Don't bother trying to create null path, '.', or '..'. */ | |
3374 | if (slash != NULL) { | |
3375 | *slash = '\0'; | |
3376 | r = create_dir(a, path); | |
3377 | *slash = '/'; | |
3378 | return (r); | |
3379 | } | |
3380 | return (ARCHIVE_OK); | |
3381 | } | |
3382 | ||
3383 | /* | |
3384 | * Yes, this should be stat() and not lstat(). Using lstat() | |
3385 | * here loses the ability to extract through symlinks. Also note | |
3386 | * that this should not use the a->st cache. | |
3387 | */ | |
bf234723 | 3388 | if (la_stat(path, &st) == 0) { |
8f776fd9 TK |
3389 | if (S_ISDIR(st.st_mode)) |
3390 | return (ARCHIVE_OK); | |
3391 | if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) { | |
3392 | archive_set_error(&a->archive, EEXIST, | |
3393 | "Can't create directory '%s'", path); | |
7d4496e9 | 3394 | return (ARCHIVE_FAILED); |
8f776fd9 TK |
3395 | } |
3396 | if (unlink(path) != 0) { | |
3397 | archive_set_error(&a->archive, errno, | |
3398 | "Can't create directory '%s': " | |
99c02b03 JS |
3399 | "Conflicting file cannot be removed", |
3400 | path); | |
7d4496e9 | 3401 | return (ARCHIVE_FAILED); |
8f776fd9 TK |
3402 | } |
3403 | } else if (errno != ENOENT && errno != ENOTDIR) { | |
3404 | /* Stat failed? */ | |
cc9cbbb1 MM |
3405 | archive_set_error(&a->archive, errno, |
3406 | "Can't test directory '%s'", path); | |
7d4496e9 | 3407 | return (ARCHIVE_FAILED); |
8f776fd9 TK |
3408 | } else if (slash != NULL) { |
3409 | *slash = '\0'; | |
3410 | r = create_dir(a, path); | |
3411 | *slash = '/'; | |
3412 | if (r != ARCHIVE_OK) | |
3413 | return (r); | |
3414 | } | |
3415 | ||
3416 | /* | |
3417 | * Mode we want for the final restored directory. Per POSIX, | |
3418 | * implicitly-created dirs must be created obeying the umask. | |
3419 | * There's no mention whether this is different for privileged | |
3420 | * restores (which the rest of this code handles by pretending | |
3421 | * umask=0). I've chosen here to always obey the user's umask for | |
3422 | * implicit dirs, even if _EXTRACT_PERM was specified. | |
3423 | */ | |
3424 | mode_final = DEFAULT_DIR_MODE & ~a->user_umask; | |
3425 | /* Mode we want on disk during the restore process. */ | |
3426 | mode = mode_final; | |
3427 | mode |= MINIMUM_DIR_MODE; | |
3428 | mode &= MAXIMUM_DIR_MODE; | |
3429 | if (mkdir(path, mode) == 0) { | |
3430 | if (mode != mode_final) { | |
3431 | le = new_fixup(a, path); | |
62756a10 MN |
3432 | if (le == NULL) |
3433 | return (ARCHIVE_FATAL); | |
8f776fd9 TK |
3434 | le->fixup |=TODO_MODE_BASE; |
3435 | le->mode = mode_final; | |
3436 | } | |
3437 | return (ARCHIVE_OK); | |
3438 | } | |
3439 | ||
3440 | /* | |
3441 | * Without the following check, a/b/../b/c/d fails at the | |
3442 | * second visit to 'b', so 'd' can't be created. Note that we | |
3443 | * don't add it to the fixup list here, as it's already been | |
3444 | * added. | |
3445 | */ | |
bf234723 | 3446 | if (la_stat(path, &st) == 0 && S_ISDIR(st.st_mode)) |
8f776fd9 TK |
3447 | return (ARCHIVE_OK); |
3448 | ||
b21f351a TK |
3449 | archive_set_error(&a->archive, errno, "Failed to create dir '%s'", |
3450 | path); | |
7d4496e9 | 3451 | return (ARCHIVE_FAILED); |
8f776fd9 TK |
3452 | } |
3453 | ||
3454 | /* | |
3455 | * Note: Although we can skip setting the user id if the desired user | |
3456 | * id matches the current user, we cannot skip setting the group, as | |
71362fca TK |
3457 | * many systems set the gid based on the containing directory. So |
3458 | * we have to perform a chown syscall if we want to set the SGID | |
8f776fd9 TK |
3459 | * bit. (The alternative is to stat() and then possibly chown(); it's |
3460 | * more efficient to skip the stat() and just always chown().) Note | |
3461 | * that a successful chown() here clears the TODO_SGID_CHECK bit, which | |
3462 | * allows set_mode to skip the stat() check for the GID. | |
3463 | */ | |
3464 | static int | |
3465 | set_ownership(struct archive_write_disk *a) | |
3466 | { | |
7130b9d4 MM |
3467 | #if !defined(__CYGWIN__) && !defined(__linux__) |
3468 | /* | |
3469 | * On Linux, a process may have the CAP_CHOWN capability. | |
3470 | * On Windows there is no 'root' user with uid 0. | |
3471 | * Elsewhere we can skip calling chown if we are not root and the desired | |
3472 | * user id does not match the current user. | |
3473 | */ | |
3474 | if (a->user_uid != 0 && a->user_uid != a->uid) { | |
8f776fd9 | 3475 | archive_set_error(&a->archive, errno, |
19363b4a | 3476 | "Can't set UID=%jd", (intmax_t)a->uid); |
8f776fd9 TK |
3477 | return (ARCHIVE_WARN); |
3478 | } | |
a6ac842e | 3479 | #endif |
8f776fd9 TK |
3480 | |
3481 | #ifdef HAVE_FCHOWN | |
3482 | /* If we have an fd, we can avoid a race. */ | |
3483 | if (a->fd >= 0 && fchown(a->fd, a->uid, a->gid) == 0) { | |
3484 | /* We've set owner and know uid/gid are correct. */ | |
3485 | a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); | |
3486 | return (ARCHIVE_OK); | |
3487 | } | |
3488 | #endif | |
3489 | ||
3490 | /* We prefer lchown() but will use chown() if that's all we have. */ | |
3491 | /* Of course, if we have neither, this will always fail. */ | |
3492 | #ifdef HAVE_LCHOWN | |
3493 | if (lchown(a->name, a->uid, a->gid) == 0) { | |
3494 | /* We've set owner and know uid/gid are correct. */ | |
3495 | a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); | |
3496 | return (ARCHIVE_OK); | |
3497 | } | |
3498 | #elif HAVE_CHOWN | |
3499 | if (!S_ISLNK(a->mode) && chown(a->name, a->uid, a->gid) == 0) { | |
3500 | /* We've set owner and know uid/gid are correct. */ | |
3501 | a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); | |
3502 | return (ARCHIVE_OK); | |
3503 | } | |
3504 | #endif | |
3505 | ||
3506 | archive_set_error(&a->archive, errno, | |
19363b4a MN |
3507 | "Can't set user=%jd/group=%jd for %s", |
3508 | (intmax_t)a->uid, (intmax_t)a->gid, a->name); | |
8f776fd9 TK |
3509 | return (ARCHIVE_WARN); |
3510 | } | |
3511 | ||
21ebff3b TK |
3512 | /* |
3513 | * Note: Returns 0 on success, non-zero on failure. | |
3514 | */ | |
3b73222c BJ |
3515 | static int |
3516 | set_time(int fd, int mode, const char *name, | |
3517 | time_t atime, long atime_nsec, | |
3518 | time_t mtime, long mtime_nsec) | |
3519 | { | |
5223514b TK |
3520 | /* Select the best implementation for this platform. */ |
3521 | #if defined(HAVE_UTIMENSAT) && defined(HAVE_FUTIMENS) | |
3522 | /* | |
3523 | * utimensat() and futimens() are defined in | |
3524 | * POSIX.1-2008. They support ns resolution and setting times | |
3525 | * on fds and symlinks. | |
3526 | */ | |
3b73222c | 3527 | struct timespec ts[2]; |
d2d75ef8 | 3528 | (void)mode; /* UNUSED */ |
3b73222c BJ |
3529 | ts[0].tv_sec = atime; |
3530 | ts[0].tv_nsec = atime_nsec; | |
3531 | ts[1].tv_sec = mtime; | |
3532 | ts[1].tv_nsec = mtime_nsec; | |
3533 | if (fd >= 0) | |
3534 | return futimens(fd, ts); | |
3535 | return utimensat(AT_FDCWD, name, ts, AT_SYMLINK_NOFOLLOW); | |
5223514b | 3536 | |
3b73222c | 3537 | #elif HAVE_UTIMES |
5223514b TK |
3538 | /* |
3539 | * The utimes()-family functions support µs-resolution and | |
3540 | * setting times fds and symlinks. utimes() is documented as | |
3541 | * LEGACY by POSIX, futimes() and lutimes() are not described | |
3542 | * in POSIX. | |
3543 | */ | |
8f776fd9 TK |
3544 | struct timeval times[2]; |
3545 | ||
82e3bb2a TK |
3546 | times[0].tv_sec = atime; |
3547 | times[0].tv_usec = atime_nsec / 1000; | |
3548 | times[1].tv_sec = mtime; | |
3549 | times[1].tv_usec = mtime_nsec / 1000; | |
8f776fd9 TK |
3550 | |
3551 | #ifdef HAVE_FUTIMES | |
82e3bb2a TK |
3552 | if (fd >= 0) |
3553 | return (futimes(fd, times)); | |
3554 | #else | |
3555 | (void)fd; /* UNUSED */ | |
8f776fd9 | 3556 | #endif |
8f776fd9 | 3557 | #ifdef HAVE_LUTIMES |
82e3bb2a TK |
3558 | (void)mode; /* UNUSED */ |
3559 | return (lutimes(name, times)); | |
8f776fd9 | 3560 | #else |
82e3bb2a TK |
3561 | if (S_ISLNK(mode)) |
3562 | return (0); | |
3563 | return (utimes(name, times)); | |
8f776fd9 | 3564 | #endif |
5223514b | 3565 | |
8f776fd9 | 3566 | #elif defined(HAVE_UTIME) |
5223514b TK |
3567 | /* |
3568 | * utime() is POSIX-standard but only supports 1s resolution and | |
3569 | * does not support fds or symlinks. | |
3570 | */ | |
8f776fd9 | 3571 | struct utimbuf times; |
82e3bb2a TK |
3572 | (void)fd; /* UNUSED */ |
3573 | (void)name; /* UNUSED */ | |
3574 | (void)atime_nsec; /* UNUSED */ | |
3575 | (void)mtime_nsec; /* UNUSED */ | |
3576 | times.actime = atime; | |
3577 | times.modtime = mtime; | |
5c6d3586 | 3578 | if (S_ISLNK(mode)) |
82e3bb2a TK |
3579 | return (ARCHIVE_OK); |
3580 | return (utime(name, ×)); | |
5223514b | 3581 | |
82e3bb2a | 3582 | #else |
5223514b TK |
3583 | /* |
3584 | * We don't know how to set the time on this platform. | |
3585 | */ | |
d2d75ef8 MN |
3586 | (void)fd; /* UNUSED */ |
3587 | (void)mode; /* UNUSED */ | |
3588 | (void)name; /* UNUSED */ | |
c684b115 | 3589 | (void)atime; /* UNUSED */ |
d2d75ef8 | 3590 | (void)atime_nsec; /* UNUSED */ |
c684b115 | 3591 | (void)mtime; /* UNUSED */ |
d2d75ef8 | 3592 | (void)mtime_nsec; /* UNUSED */ |
82e3bb2a | 3593 | return (ARCHIVE_WARN); |
5223514b | 3594 | #endif |
82e3bb2a | 3595 | } |
5223514b | 3596 | |
8f2b0013 | 3597 | #ifdef F_SETTIMES |
631247e1 BJ |
3598 | static int |
3599 | set_time_tru64(int fd, int mode, const char *name, | |
3600 | time_t atime, long atime_nsec, | |
3601 | time_t mtime, long mtime_nsec, | |
3602 | time_t ctime, long ctime_nsec) | |
3603 | { | |
3604 | struct attr_timbuf tstamp; | |
8f2b0013 REB |
3605 | tstamp.atime.tv_sec = atime; |
3606 | tstamp.mtime.tv_sec = mtime; | |
3607 | tstamp.ctime.tv_sec = ctime; | |
3608 | #if defined (__hpux) && defined (__ia64) | |
3609 | tstamp.atime.tv_nsec = atime_nsec; | |
3610 | tstamp.mtime.tv_nsec = mtime_nsec; | |
3611 | tstamp.ctime.tv_nsec = ctime_nsec; | |
3612 | #else | |
6893cc54 | 3613 | tstamp.atime.tv_usec = atime_nsec / 1000; |
8f2b0013 REB |
3614 | tstamp.mtime.tv_usec = mtime_nsec / 1000; |
3615 | tstamp.ctime.tv_usec = ctime_nsec / 1000; | |
3616 | #endif | |
631247e1 BJ |
3617 | return (fcntl(fd,F_SETTIMES,&tstamp)); |
3618 | } | |
8f2b0013 | 3619 | #endif /* F_SETTIMES */ |
631247e1 | 3620 | |
5223514b | 3621 | static int |
21ebff3b TK |
3622 | set_times(struct archive_write_disk *a, |
3623 | int fd, int mode, const char *name, | |
5223514b TK |
3624 | time_t atime, long atime_nanos, |
3625 | time_t birthtime, long birthtime_nanos, | |
b648c6c7 | 3626 | time_t mtime, long mtime_nanos, |
fc22f4a6 | 3627 | time_t cctime, long ctime_nanos) |
5223514b | 3628 | { |
21ebff3b TK |
3629 | /* Note: set_time doesn't use libarchive return conventions! |
3630 | * It uses syscall conventions. So 0 here instead of ARCHIVE_OK. */ | |
3631 | int r1 = 0, r2 = 0; | |
5223514b | 3632 | |
631247e1 BJ |
3633 | #ifdef F_SETTIMES |
3634 | /* | |
3635 | * on Tru64 try own fcntl first which can restore even the | |
3636 | * ctime, fall back to default code path below if it fails | |
3637 | * or if we are not running as root | |
3638 | */ | |
3639 | if (a->user_uid == 0 && | |
3640 | set_time_tru64(fd, mode, name, | |
3641 | atime, atime_nanos, mtime, | |
fc22f4a6 | 3642 | mtime_nanos, cctime, ctime_nanos) == 0) { |
631247e1 BJ |
3643 | return (ARCHIVE_OK); |
3644 | } | |
433f74b0 | 3645 | #else /* Tru64 */ |
fc22f4a6 | 3646 | (void)cctime; /* UNUSED */ |
433f74b0 | 3647 | (void)ctime_nanos; /* UNUSED */ |
631247e1 BJ |
3648 | #endif /* Tru64 */ |
3649 | ||
5223514b TK |
3650 | #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME |
3651 | /* | |
3652 | * If you have struct stat.st_birthtime, we assume BSD | |
3653 | * birthtime semantics, in which {f,l,}utimes() updates | |
3654 | * birthtime to earliest mtime. So we set the time twice, | |
3655 | * first using the birthtime, then using the mtime. If | |
3656 | * birthtime == mtime, this isn't necessary, so we skip it. | |
3657 | * If birthtime > mtime, then this won't work, so we skip it. | |
3658 | */ | |
3659 | if (birthtime < mtime | |
3660 | || (birthtime == mtime && birthtime_nanos < mtime_nanos)) | |
3661 | r1 = set_time(fd, mode, name, | |
3662 | atime, atime_nanos, | |
3663 | birthtime, birthtime_nanos); | |
d2d75ef8 MN |
3664 | #else |
3665 | (void)birthtime; /* UNUSED */ | |
3666 | (void)birthtime_nanos; /* UNUSED */ | |
82e3bb2a | 3667 | #endif |
5223514b TK |
3668 | r2 = set_time(fd, mode, name, |
3669 | atime, atime_nanos, | |
3670 | mtime, mtime_nanos); | |
21ebff3b TK |
3671 | if (r1 != 0 || r2 != 0) { |
3672 | archive_set_error(&a->archive, errno, | |
3673 | "Can't restore time"); | |
3674 | return (ARCHIVE_WARN); | |
3675 | } | |
3676 | return (ARCHIVE_OK); | |
5223514b | 3677 | } |
82e3bb2a TK |
3678 | |
3679 | static int | |
5223514b | 3680 | set_times_from_entry(struct archive_write_disk *a) |
82e3bb2a | 3681 | { |
fc22f4a6 | 3682 | time_t atime, birthtime, mtime, cctime; |
b648c6c7 | 3683 | long atime_nsec, birthtime_nsec, mtime_nsec, ctime_nsec; |
5223514b TK |
3684 | |
3685 | /* Suitable defaults. */ | |
fc22f4a6 | 3686 | atime = birthtime = mtime = cctime = a->start_time; |
b648c6c7 | 3687 | atime_nsec = birthtime_nsec = mtime_nsec = ctime_nsec = 0; |
8f776fd9 | 3688 | |
8e71fa72 TK |
3689 | /* If no time was provided, we're done. */ |
3690 | if (!archive_entry_atime_is_set(a->entry) | |
82e3bb2a TK |
3691 | #if HAVE_STRUCT_STAT_ST_BIRTHTIME |
3692 | && !archive_entry_birthtime_is_set(a->entry) | |
3693 | #endif | |
8e71fa72 TK |
3694 | && !archive_entry_mtime_is_set(a->entry)) |
3695 | return (ARCHIVE_OK); | |
3696 | ||
82e3bb2a TK |
3697 | if (archive_entry_atime_is_set(a->entry)) { |
3698 | atime = archive_entry_atime(a->entry); | |
3699 | atime_nsec = archive_entry_atime_nsec(a->entry); | |
3700 | } | |
5223514b TK |
3701 | if (archive_entry_birthtime_is_set(a->entry)) { |
3702 | birthtime = archive_entry_birthtime(a->entry); | |
3703 | birthtime_nsec = archive_entry_birthtime_nsec(a->entry); | |
3704 | } | |
82e3bb2a TK |
3705 | if (archive_entry_mtime_is_set(a->entry)) { |
3706 | mtime = archive_entry_mtime(a->entry); | |
3707 | mtime_nsec = archive_entry_mtime_nsec(a->entry); | |
3708 | } | |
b648c6c7 | 3709 | if (archive_entry_ctime_is_set(a->entry)) { |
fc22f4a6 | 3710 | cctime = archive_entry_ctime(a->entry); |
b648c6c7 BJ |
3711 | ctime_nsec = archive_entry_ctime_nsec(a->entry); |
3712 | } | |
82e3bb2a | 3713 | |
21ebff3b | 3714 | return set_times(a, a->fd, a->mode, a->name, |
5223514b TK |
3715 | atime, atime_nsec, |
3716 | birthtime, birthtime_nsec, | |
b648c6c7 | 3717 | mtime, mtime_nsec, |
fc22f4a6 | 3718 | cctime, ctime_nsec); |
8f776fd9 | 3719 | } |
8f776fd9 TK |
3720 | |
3721 | static int | |
3722 | set_mode(struct archive_write_disk *a, int mode) | |
3723 | { | |
3724 | int r = ARCHIVE_OK; | |
6aea568d | 3725 | int r2; |
8f776fd9 TK |
3726 | mode &= 07777; /* Strip off file type bits. */ |
3727 | ||
3728 | if (a->todo & TODO_SGID_CHECK) { | |
3729 | /* | |
3730 | * If we don't know the GID is right, we must stat() | |
3731 | * to verify it. We can't just check the GID of this | |
3732 | * process, since systems sometimes set GID from | |
3733 | * the enclosing dir or based on ACLs. | |
3734 | */ | |
911dc2bf | 3735 | if ((r = lazy_stat(a)) != ARCHIVE_OK) |
2f8873c2 | 3736 | return (r); |
8f776fd9 TK |
3737 | if (a->pst->st_gid != a->gid) { |
3738 | mode &= ~ S_ISGID; | |
3739 | if (a->flags & ARCHIVE_EXTRACT_OWNER) { | |
3740 | /* | |
3741 | * This is only an error if you | |
3742 | * requested owner restore. If you | |
3743 | * didn't, we'll try to restore | |
3744 | * sgid/suid, but won't consider it a | |
3745 | * problem if we can't. | |
3746 | */ | |
3747 | archive_set_error(&a->archive, -1, | |
3748 | "Can't restore SGID bit"); | |
3749 | r = ARCHIVE_WARN; | |
3750 | } | |
3751 | } | |
3752 | /* While we're here, double-check the UID. */ | |
3753 | if (a->pst->st_uid != a->uid | |
3754 | && (a->todo & TODO_SUID)) { | |
3755 | mode &= ~ S_ISUID; | |
3756 | if (a->flags & ARCHIVE_EXTRACT_OWNER) { | |
3757 | archive_set_error(&a->archive, -1, | |
3758 | "Can't restore SUID bit"); | |
3759 | r = ARCHIVE_WARN; | |
3760 | } | |
3761 | } | |
3762 | a->todo &= ~TODO_SGID_CHECK; | |
3763 | a->todo &= ~TODO_SUID_CHECK; | |
3764 | } else if (a->todo & TODO_SUID_CHECK) { | |
3765 | /* | |
3766 | * If we don't know the UID is right, we can just check | |
3767 | * the user, since all systems set the file UID from | |
3768 | * the process UID. | |
3769 | */ | |
3770 | if (a->user_uid != a->uid) { | |
3771 | mode &= ~ S_ISUID; | |
3772 | if (a->flags & ARCHIVE_EXTRACT_OWNER) { | |
3773 | archive_set_error(&a->archive, -1, | |
3774 | "Can't make file SUID"); | |
3775 | r = ARCHIVE_WARN; | |
3776 | } | |
3777 | } | |
3778 | a->todo &= ~TODO_SUID_CHECK; | |
3779 | } | |
3780 | ||
3781 | if (S_ISLNK(a->mode)) { | |
91b5c59a | 3782 | #ifdef HAVE_LCHMOD |
8f776fd9 | 3783 | /* |
91b5c59a | 3784 | * If this is a symlink, use lchmod(). If the |
8f776fd9 TK |
3785 | * platform doesn't support lchmod(), just skip it. A |
3786 | * platform that doesn't provide a way to set | |
3787 | * permissions on symlinks probably ignores | |
3788 | * permissions on symlinks, so a failure here has no | |
3789 | * impact. | |
3790 | */ | |
91b5c59a | 3791 | if (lchmod(a->name, mode) != 0) { |
65fe1034 RF |
3792 | switch (errno) { |
3793 | case ENOTSUP: | |
3794 | case ENOSYS: | |
5ad9ecdd | 3795 | #if ENOTSUP != EOPNOTSUPP |
65fe1034 | 3796 | case EOPNOTSUPP: |
5ad9ecdd | 3797 | #endif |
65fe1034 RF |
3798 | /* |
3799 | * if lchmod is defined but the platform | |
3800 | * doesn't support it, silently ignore | |
3801 | * error | |
3802 | */ | |
3803 | break; | |
3804 | default: | |
3805 | archive_set_error(&a->archive, errno, | |
3806 | "Can't set permissions to 0%o", (int)mode); | |
3807 | r = ARCHIVE_WARN; | |
3808 | } | |
8f776fd9 | 3809 | } |
91b5c59a | 3810 | #endif |
8f776fd9 TK |
3811 | } else if (!S_ISDIR(a->mode)) { |
3812 | /* | |
3813 | * If it's not a symlink and not a dir, then use | |
3814 | * fchmod() or chmod(), depending on whether we have | |
3815 | * an fd. Dirs get their perms set during the | |
3816 | * post-extract fixup, which is handled elsewhere. | |
3817 | */ | |
3818 | #ifdef HAVE_FCHMOD | |
6aea568d MM |
3819 | if (a->fd >= 0) |
3820 | r2 = fchmod(a->fd, mode); | |
3821 | else | |
8f776fd9 | 3822 | #endif |
6aea568d MM |
3823 | /* If this platform lacks fchmod(), then |
3824 | * we'll just use chmod(). */ | |
3825 | r2 = chmod(a->name, mode); | |
3826 | ||
3827 | if (r2 != 0) { | |
3828 | archive_set_error(&a->archive, errno, | |
3829 | "Can't set permissions to 0%o", (int)mode); | |
3830 | r = ARCHIVE_WARN; | |
3831 | } | |
8f776fd9 TK |
3832 | } |
3833 | return (r); | |
3834 | } | |
3835 | ||
3836 | static int | |
3837 | set_fflags(struct archive_write_disk *a) | |
3838 | { | |
3839 | struct fixup_entry *le; | |
3840 | unsigned long set, clear; | |
3841 | int r; | |
8f776fd9 | 3842 | mode_t mode = archive_entry_mode(a->entry); |
8f776fd9 TK |
3843 | /* |
3844 | * Make 'critical_flags' hold all file flags that can't be | |
3845 | * immediately restored. For example, on BSD systems, | |
3846 | * SF_IMMUTABLE prevents hardlinks from being created, so | |
3847 | * should not be set until after any hardlinks are created. To | |
3848 | * preserve some semblance of portability, this uses #ifdef | |
3849 | * extensively. Ugly, but it works. | |
3850 | * | |
3851 | * Yes, Virginia, this does create a security race. It's mitigated | |
3852 | * somewhat by the practice of creating dirs 0700 until the extract | |
3853 | * is done, but it would be nice if we could do more than that. | |
3854 | * People restoring critical file systems should be wary of | |
3855 | * other programs that might try to muck with files as they're | |
3856 | * being restored. | |
3857 | */ | |
e2441c28 | 3858 | const int critical_flags = 0 |
8f776fd9 | 3859 | #ifdef SF_IMMUTABLE |
e2441c28 | 3860 | | SF_IMMUTABLE |
8f776fd9 TK |
3861 | #endif |
3862 | #ifdef UF_IMMUTABLE | |
e2441c28 | 3863 | | UF_IMMUTABLE |
8f776fd9 TK |
3864 | #endif |
3865 | #ifdef SF_APPEND | |
e2441c28 | 3866 | | SF_APPEND |
8f776fd9 TK |
3867 | #endif |
3868 | #ifdef UF_APPEND | |
e2441c28 | 3869 | | UF_APPEND |
8f776fd9 | 3870 | #endif |
a9c5818b | 3871 | #if defined(FS_APPEND_FL) |
e2441c28 | 3872 | | FS_APPEND_FL |
a9c5818b | 3873 | #elif defined(EXT2_APPEND_FL) |
e2441c28 | 3874 | | EXT2_APPEND_FL |
8f776fd9 | 3875 | #endif |
a9c5818b | 3876 | #if defined(FS_IMMUTABLE_FL) |
e2441c28 | 3877 | | FS_IMMUTABLE_FL |
a9c5818b | 3878 | #elif defined(EXT2_IMMUTABLE_FL) |
e2441c28 | 3879 | | EXT2_IMMUTABLE_FL |
8f776fd9 | 3880 | #endif |
a9c5818b | 3881 | #ifdef FS_JOURNAL_DATA_FL |
e2441c28 | 3882 | | FS_JOURNAL_DATA_FL |
a9c5818b | 3883 | #endif |
e2441c28 | 3884 | ; |
8f776fd9 TK |
3885 | |
3886 | if (a->todo & TODO_FFLAGS) { | |
3887 | archive_entry_fflags(a->entry, &set, &clear); | |
3888 | ||
3889 | /* | |
3890 | * The first test encourages the compiler to eliminate | |
3891 | * all of this if it's not necessary. | |
3892 | */ | |
3893 | if ((critical_flags != 0) && (set & critical_flags)) { | |
3894 | le = current_fixup(a, a->name); | |
62756a10 MN |
3895 | if (le == NULL) |
3896 | return (ARCHIVE_FATAL); | |
ede459d2 | 3897 | le->filetype = archive_entry_filetype(a->entry); |
8f776fd9 TK |
3898 | le->fixup |= TODO_FFLAGS; |
3899 | le->fflags_set = set; | |
3900 | /* Store the mode if it's not already there. */ | |
3901 | if ((le->fixup & TODO_MODE) == 0) | |
3902 | le->mode = mode; | |
3903 | } else { | |
3904 | r = set_fflags_platform(a, a->fd, | |
3905 | a->name, mode, set, clear); | |
3906 | if (r != ARCHIVE_OK) | |
3907 | return (r); | |
3908 | } | |
3909 | } | |
3910 | return (ARCHIVE_OK); | |
3911 | } | |
3912 | ||
6a595ef6 BD |
3913 | static int |
3914 | clear_nochange_fflags(struct archive_write_disk *a) | |
3915 | { | |
6a595ef6 | 3916 | mode_t mode = archive_entry_mode(a->entry); |
e2441c28 | 3917 | const int nochange_flags = 0 |
6a595ef6 | 3918 | #ifdef SF_IMMUTABLE |
e2441c28 | 3919 | | SF_IMMUTABLE |
6a595ef6 BD |
3920 | #endif |
3921 | #ifdef UF_IMMUTABLE | |
e2441c28 | 3922 | | UF_IMMUTABLE |
6a595ef6 BD |
3923 | #endif |
3924 | #ifdef SF_APPEND | |
e2441c28 | 3925 | | SF_APPEND |
6a595ef6 BD |
3926 | #endif |
3927 | #ifdef UF_APPEND | |
e2441c28 | 3928 | | UF_APPEND |
6a595ef6 BD |
3929 | #endif |
3930 | #ifdef EXT2_APPEND_FL | |
e2441c28 | 3931 | | EXT2_APPEND_FL |
6a595ef6 BD |
3932 | #endif |
3933 | #ifdef EXT2_IMMUTABLE_FL | |
e2441c28 | 3934 | | EXT2_IMMUTABLE_FL |
6a595ef6 | 3935 | #endif |
e2441c28 | 3936 | ; |
6a595ef6 | 3937 | |
cc9cbbb1 MM |
3938 | return (set_fflags_platform(a, a->fd, a->name, mode, 0, |
3939 | nochange_flags)); | |
6a595ef6 BD |
3940 | } |
3941 | ||
8f776fd9 | 3942 | |
c5e9786e TK |
3943 | #if ( defined(HAVE_LCHFLAGS) || defined(HAVE_CHFLAGS) || defined(HAVE_FCHFLAGS) ) && defined(HAVE_STRUCT_STAT_ST_FLAGS) |
3944 | /* | |
3945 | * BSD reads flags using stat() and sets them with one of {f,l,}chflags() | |
3946 | */ | |
8f776fd9 TK |
3947 | static int |
3948 | set_fflags_platform(struct archive_write_disk *a, int fd, const char *name, | |
3949 | mode_t mode, unsigned long set, unsigned long clear) | |
3950 | { | |
2f8873c2 | 3951 | int r; |
e2441c28 MM |
3952 | const int sf_mask = 0 |
3953 | #ifdef SF_APPEND | |
3954 | | SF_APPEND | |
3955 | #endif | |
3956 | #ifdef SF_ARCHIVED | |
3957 | | SF_ARCHIVED | |
3958 | #endif | |
3959 | #ifdef SF_IMMUTABLE | |
3960 | | SF_IMMUTABLE | |
3961 | #endif | |
3962 | #ifdef SF_NOUNLINK | |
3963 | | SF_NOUNLINK | |
3964 | #endif | |
3965 | ; | |
8f776fd9 | 3966 | (void)mode; /* UNUSED */ |
1f759ffd | 3967 | |
8f776fd9 TK |
3968 | if (set == 0 && clear == 0) |
3969 | return (ARCHIVE_OK); | |
3970 | ||
3971 | /* | |
3972 | * XXX Is the stat here really necessary? Or can I just use | |
3973 | * the 'set' flags directly? In particular, I'm not sure | |
3974 | * about the correct approach if we're overwriting an existing | |
3975 | * file that already has flags on it. XXX | |
3976 | */ | |
911dc2bf | 3977 | if ((r = lazy_stat(a)) != ARCHIVE_OK) |
2f8873c2 | 3978 | return (r); |
8f776fd9 TK |
3979 | |
3980 | a->st.st_flags &= ~clear; | |
3981 | a->st.st_flags |= set; | |
1f759ffd MM |
3982 | |
3983 | /* Only super-user may change SF_* flags */ | |
e2441c28 | 3984 | |
1f759ffd MM |
3985 | if (a->user_uid != 0) |
3986 | a->st.st_flags &= ~sf_mask; | |
3987 | ||
8f776fd9 TK |
3988 | #ifdef HAVE_FCHFLAGS |
3989 | /* If platform has fchflags() and we were given an fd, use it. */ | |
3990 | if (fd >= 0 && fchflags(fd, a->st.st_flags) == 0) | |
3991 | return (ARCHIVE_OK); | |
3992 | #endif | |
3993 | /* | |
3994 | * If we can't use the fd to set the flags, we'll use the | |
3995 | * pathname to set flags. We prefer lchflags() but will use | |
3996 | * chflags() if we must. | |
3997 | */ | |
3998 | #ifdef HAVE_LCHFLAGS | |
3999 | if (lchflags(name, a->st.st_flags) == 0) | |
4000 | return (ARCHIVE_OK); | |
4001 | #elif defined(HAVE_CHFLAGS) | |
4002 | if (S_ISLNK(a->st.st_mode)) { | |
4003 | archive_set_error(&a->archive, errno, | |
4004 | "Can't set file flags on symlink."); | |
4005 | return (ARCHIVE_WARN); | |
4006 | } | |
4007 | if (chflags(name, a->st.st_flags) == 0) | |
4008 | return (ARCHIVE_OK); | |
4009 | #endif | |
4010 | archive_set_error(&a->archive, errno, | |
4011 | "Failed to set file flags"); | |
4012 | return (ARCHIVE_WARN); | |
4013 | } | |
4014 | ||
a9c5818b MM |
4015 | #elif (defined(FS_IOC_GETFLAGS) && defined(FS_IOC_SETFLAGS) && \ |
4016 | defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \ | |
4017 | (defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS) && \ | |
4018 | defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)) | |
8f776fd9 | 4019 | /* |
c5e9786e | 4020 | * Linux uses ioctl() to read and write file flags. |
8f776fd9 TK |
4021 | */ |
4022 | static int | |
4023 | set_fflags_platform(struct archive_write_disk *a, int fd, const char *name, | |
4024 | mode_t mode, unsigned long set, unsigned long clear) | |
4025 | { | |
4026 | int ret; | |
4027 | int myfd = fd; | |
0970d06a | 4028 | int newflags, oldflags; |
8f776fd9 TK |
4029 | /* |
4030 | * Linux has no define for the flags that are only settable by | |
4031 | * the root user. This code may seem a little complex, but | |
4032 | * there seem to be some Linux systems that lack these | |
4033 | * defines. (?) The code below degrades reasonably gracefully | |
4034 | * if sf_mask is incomplete. | |
4035 | */ | |
e2441c28 | 4036 | const int sf_mask = 0 |
a9c5818b | 4037 | #if defined(FS_IMMUTABLE_FL) |
e2441c28 | 4038 | | FS_IMMUTABLE_FL |
a9c5818b | 4039 | #elif defined(EXT2_IMMUTABLE_FL) |
e2441c28 | 4040 | | EXT2_IMMUTABLE_FL |
8f776fd9 | 4041 | #endif |
a9c5818b | 4042 | #if defined(FS_APPEND_FL) |
e2441c28 | 4043 | | FS_APPEND_FL |
a9c5818b | 4044 | #elif defined(EXT2_APPEND_FL) |
e2441c28 | 4045 | | EXT2_APPEND_FL |
a9c5818b MM |
4046 | #endif |
4047 | #if defined(FS_JOURNAL_DATA_FL) | |
e2441c28 | 4048 | | FS_JOURNAL_DATA_FL |
8f776fd9 | 4049 | #endif |
e2441c28 MM |
4050 | ; |
4051 | ||
4052 | if (set == 0 && clear == 0) | |
4053 | return (ARCHIVE_OK); | |
4054 | /* Only regular files and dirs can have flags. */ | |
4055 | if (!S_ISREG(mode) && !S_ISDIR(mode)) | |
4056 | return (ARCHIVE_OK); | |
4057 | ||
4058 | /* If we weren't given an fd, open it ourselves. */ | |
4059 | if (myfd < 0) { | |
e2ad1a2c MM |
4060 | myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY | |
4061 | O_CLOEXEC | O_NOFOLLOW); | |
e2441c28 MM |
4062 | __archive_ensure_cloexec_flag(myfd); |
4063 | } | |
4064 | if (myfd < 0) | |
4065 | return (ARCHIVE_OK); | |
4066 | ||
8f776fd9 TK |
4067 | /* |
4068 | * XXX As above, this would be way simpler if we didn't have | |
4069 | * to read the current flags from disk. XXX | |
4070 | */ | |
4071 | ret = ARCHIVE_OK; | |
cafcd565 CP |
4072 | |
4073 | /* Read the current file flags. */ | |
a9c5818b MM |
4074 | if (ioctl(myfd, |
4075 | #ifdef FS_IOC_GETFLAGS | |
4076 | FS_IOC_GETFLAGS, | |
4077 | #else | |
4078 | EXT2_IOC_GETFLAGS, | |
4079 | #endif | |
4080 | &oldflags) < 0) | |
cafcd565 CP |
4081 | goto fail; |
4082 | ||
8f776fd9 | 4083 | /* Try setting the flags as given. */ |
cafcd565 | 4084 | newflags = (oldflags & ~clear) | set; |
a9c5818b MM |
4085 | if (ioctl(myfd, |
4086 | #ifdef FS_IOC_SETFLAGS | |
4087 | FS_IOC_SETFLAGS, | |
4088 | #else | |
4089 | EXT2_IOC_SETFLAGS, | |
4090 | #endif | |
4091 | &newflags) >= 0) | |
cafcd565 CP |
4092 | goto cleanup; |
4093 | if (errno != EPERM) | |
4094 | goto fail; | |
4095 | ||
8f776fd9 | 4096 | /* If we couldn't set all the flags, try again with a subset. */ |
cafcd565 CP |
4097 | newflags &= ~sf_mask; |
4098 | oldflags &= sf_mask; | |
4099 | newflags |= oldflags; | |
a9c5818b MM |
4100 | if (ioctl(myfd, |
4101 | #ifdef FS_IOC_SETFLAGS | |
4102 | FS_IOC_SETFLAGS, | |
4103 | #else | |
4104 | EXT2_IOC_SETFLAGS, | |
4105 | #endif | |
4106 | &newflags) >= 0) | |
cafcd565 CP |
4107 | goto cleanup; |
4108 | ||
8f776fd9 TK |
4109 | /* We couldn't set the flags, so report the failure. */ |
4110 | fail: | |
4111 | archive_set_error(&a->archive, errno, | |
4112 | "Failed to set file flags"); | |
4113 | ret = ARCHIVE_WARN; | |
4114 | cleanup: | |
4115 | if (fd < 0) | |
4116 | close(myfd); | |
4117 | return (ret); | |
4118 | } | |
4119 | ||
c5e9786e | 4120 | #else |
8f776fd9 TK |
4121 | |
4122 | /* | |
4123 | * Of course, some systems have neither BSD chflags() nor Linux' flags | |
4124 | * support through ioctl(). | |
4125 | */ | |
4126 | static int | |
4127 | set_fflags_platform(struct archive_write_disk *a, int fd, const char *name, | |
4128 | mode_t mode, unsigned long set, unsigned long clear) | |
4129 | { | |
4130 | (void)a; /* UNUSED */ | |
4131 | (void)fd; /* UNUSED */ | |
4132 | (void)name; /* UNUSED */ | |
4133 | (void)mode; /* UNUSED */ | |
4134 | (void)set; /* UNUSED */ | |
4135 | (void)clear; /* UNUSED */ | |
4136 | return (ARCHIVE_OK); | |
4137 | } | |
4138 | ||
4139 | #endif /* __linux */ | |
4140 | ||
b8ad1655 TK |
4141 | #ifndef HAVE_COPYFILE_H |
4142 | /* Default is to simply drop Mac extended metadata. */ | |
4143 | static int | |
4144 | set_mac_metadata(struct archive_write_disk *a, const char *pathname, | |
4145 | const void *metadata, size_t metadata_size) | |
4146 | { | |
4147 | (void)a; /* UNUSED */ | |
4148 | (void)pathname; /* UNUSED */ | |
4149 | (void)metadata; /* UNUSED */ | |
4150 | (void)metadata_size; /* UNUSED */ | |
4151 | return (ARCHIVE_OK); | |
4152 | } | |
a70241b7 MN |
4153 | |
4154 | static int | |
4155 | fixup_appledouble(struct archive_write_disk *a, const char *pathname) | |
4156 | { | |
4157 | (void)a; /* UNUSED */ | |
4158 | (void)pathname; /* UNUSED */ | |
4159 | return (ARCHIVE_OK); | |
4160 | } | |
b8ad1655 TK |
4161 | #else |
4162 | ||
4163 | /* | |
4164 | * On Mac OS, we use copyfile() to unpack the metadata and | |
4165 | * apply it to the target file. | |
4166 | */ | |
4d920441 | 4167 | |
63f4eb7d | 4168 | #if defined(HAVE_SYS_XATTR_H) |
4d920441 MN |
4169 | static int |
4170 | copy_xattrs(struct archive_write_disk *a, int tmpfd, int dffd) | |
4171 | { | |
4172 | ssize_t xattr_size; | |
4173 | char *xattr_names = NULL, *xattr_val = NULL; | |
4174 | int ret = ARCHIVE_OK, xattr_i; | |
4175 | ||
4176 | xattr_size = flistxattr(tmpfd, NULL, 0, 0); | |
4177 | if (xattr_size == -1) { | |
4178 | archive_set_error(&a->archive, errno, | |
4179 | "Failed to read metadata(xattr)"); | |
4180 | ret = ARCHIVE_WARN; | |
4181 | goto exit_xattr; | |
4182 | } | |
4183 | xattr_names = malloc(xattr_size); | |
4184 | if (xattr_names == NULL) { | |
4185 | archive_set_error(&a->archive, ENOMEM, | |
4186 | "Can't allocate memory for metadata(xattr)"); | |
4187 | ret = ARCHIVE_FATAL; | |
4188 | goto exit_xattr; | |
4189 | } | |
4190 | xattr_size = flistxattr(tmpfd, xattr_names, xattr_size, 0); | |
4191 | if (xattr_size == -1) { | |
4192 | archive_set_error(&a->archive, errno, | |
4193 | "Failed to read metadata(xattr)"); | |
4194 | ret = ARCHIVE_WARN; | |
4195 | goto exit_xattr; | |
4196 | } | |
4197 | for (xattr_i = 0; xattr_i < xattr_size; | |
4198 | xattr_i += strlen(xattr_names + xattr_i) + 1) { | |
ae086fb2 | 4199 | char *xattr_val_saved; |
4d920441 MN |
4200 | ssize_t s; |
4201 | int f; | |
4202 | ||
4203 | s = fgetxattr(tmpfd, xattr_names + xattr_i, NULL, 0, 0, 0); | |
4204 | if (s == -1) { | |
4205 | archive_set_error(&a->archive, errno, | |
4206 | "Failed to get metadata(xattr)"); | |
4207 | ret = ARCHIVE_WARN; | |
4208 | goto exit_xattr; | |
4209 | } | |
ae086fb2 | 4210 | xattr_val_saved = xattr_val; |
4d920441 MN |
4211 | xattr_val = realloc(xattr_val, s); |
4212 | if (xattr_val == NULL) { | |
4213 | archive_set_error(&a->archive, ENOMEM, | |
4214 | "Failed to get metadata(xattr)"); | |
4215 | ret = ARCHIVE_WARN; | |
ae086fb2 | 4216 | free(xattr_val_saved); |
4d920441 MN |
4217 | goto exit_xattr; |
4218 | } | |
4219 | s = fgetxattr(tmpfd, xattr_names + xattr_i, xattr_val, s, 0, 0); | |
4220 | if (s == -1) { | |
4221 | archive_set_error(&a->archive, errno, | |
4222 | "Failed to get metadata(xattr)"); | |
4223 | ret = ARCHIVE_WARN; | |
4224 | goto exit_xattr; | |
4225 | } | |
4226 | f = fsetxattr(dffd, xattr_names + xattr_i, xattr_val, s, 0, 0); | |
4227 | if (f == -1) { | |
4228 | archive_set_error(&a->archive, errno, | |
4229 | "Failed to get metadata(xattr)"); | |
4230 | ret = ARCHIVE_WARN; | |
4231 | goto exit_xattr; | |
4232 | } | |
4233 | } | |
4234 | exit_xattr: | |
4235 | free(xattr_names); | |
4236 | free(xattr_val); | |
4237 | return (ret); | |
4238 | } | |
63f4eb7d | 4239 | #endif |
4d920441 MN |
4240 | |
4241 | static int | |
4242 | copy_acls(struct archive_write_disk *a, int tmpfd, int dffd) | |
4243 | { | |
3e668297 JS |
4244 | #ifndef HAVE_SYS_ACL_H |
4245 | return 0; | |
4246 | #else | |
4d920441 MN |
4247 | acl_t acl, dfacl = NULL; |
4248 | int acl_r, ret = ARCHIVE_OK; | |
4249 | ||
4250 | acl = acl_get_fd(tmpfd); | |
4251 | if (acl == NULL) { | |
4252 | if (errno == ENOENT) | |
4253 | /* There are not any ACLs. */ | |
4254 | return (ret); | |
4255 | archive_set_error(&a->archive, errno, | |
4256 | "Failed to get metadata(acl)"); | |
4257 | ret = ARCHIVE_WARN; | |
4258 | goto exit_acl; | |
4259 | } | |
4260 | dfacl = acl_dup(acl); | |
4261 | acl_r = acl_set_fd(dffd, dfacl); | |
4262 | if (acl_r == -1) { | |
4263 | archive_set_error(&a->archive, errno, | |
4264 | "Failed to get metadata(acl)"); | |
4265 | ret = ARCHIVE_WARN; | |
4266 | goto exit_acl; | |
4267 | } | |
4268 | exit_acl: | |
4269 | if (acl) | |
4270 | acl_free(acl); | |
4271 | if (dfacl) | |
4272 | acl_free(dfacl); | |
4273 | return (ret); | |
3e668297 | 4274 | #endif |
4d920441 MN |
4275 | } |
4276 | ||
4277 | static int | |
4278 | create_tempdatafork(struct archive_write_disk *a, const char *pathname) | |
4279 | { | |
4280 | struct archive_string tmpdatafork; | |
4281 | int tmpfd; | |
4282 | ||
4283 | archive_string_init(&tmpdatafork); | |
4284 | archive_strcpy(&tmpdatafork, "tar.md.XXXXXX"); | |
4285 | tmpfd = mkstemp(tmpdatafork.s); | |
4286 | if (tmpfd < 0) { | |
4287 | archive_set_error(&a->archive, errno, | |
4288 | "Failed to mkstemp"); | |
4289 | archive_string_free(&tmpdatafork); | |
4290 | return (-1); | |
4291 | } | |
4292 | if (copyfile(pathname, tmpdatafork.s, 0, | |
4293 | COPYFILE_UNPACK | COPYFILE_NOFOLLOW | |
4294 | | COPYFILE_ACL | COPYFILE_XATTR) < 0) { | |
4295 | archive_set_error(&a->archive, errno, | |
4296 | "Failed to restore metadata"); | |
4297 | close(tmpfd); | |
4298 | tmpfd = -1; | |
4299 | } | |
4300 | unlink(tmpdatafork.s); | |
4301 | archive_string_free(&tmpdatafork); | |
4302 | return (tmpfd); | |
4303 | } | |
4304 | ||
4305 | static int | |
4306 | copy_metadata(struct archive_write_disk *a, const char *metadata, | |
4307 | const char *datafork, int datafork_compressed) | |
4308 | { | |
4309 | int ret = ARCHIVE_OK; | |
4310 | ||
4311 | if (datafork_compressed) { | |
4312 | int dffd, tmpfd; | |
4313 | ||
4314 | tmpfd = create_tempdatafork(a, metadata); | |
4315 | if (tmpfd == -1) | |
4316 | return (ARCHIVE_WARN); | |
4317 | ||
4318 | /* | |
4319 | * Do not open the data fork compressed by HFS+ compression | |
4320 | * with at least a writing mode(O_RDWR or O_WRONLY). it | |
4321 | * makes the data fork uncompressed. | |
4322 | */ | |
4323 | dffd = open(datafork, 0); | |
4324 | if (dffd == -1) { | |
4325 | archive_set_error(&a->archive, errno, | |
4326 | "Failed to open the data fork for metadata"); | |
4327 | close(tmpfd); | |
4328 | return (ARCHIVE_WARN); | |
4329 | } | |
4330 | ||
63f4eb7d | 4331 | #if defined(HAVE_SYS_XATTR_H) |
4d920441 MN |
4332 | ret = copy_xattrs(a, tmpfd, dffd); |
4333 | if (ret == ARCHIVE_OK) | |
63f4eb7d | 4334 | #endif |
4d920441 MN |
4335 | ret = copy_acls(a, tmpfd, dffd); |
4336 | close(tmpfd); | |
4337 | close(dffd); | |
4338 | } else { | |
4339 | if (copyfile(metadata, datafork, 0, | |
4340 | COPYFILE_UNPACK | COPYFILE_NOFOLLOW | |
4341 | | COPYFILE_ACL | COPYFILE_XATTR) < 0) { | |
4342 | archive_set_error(&a->archive, errno, | |
4343 | "Failed to restore metadata"); | |
4344 | ret = ARCHIVE_WARN; | |
4345 | } | |
4346 | } | |
4347 | return (ret); | |
4348 | } | |
4349 | ||
b8ad1655 TK |
4350 | static int |
4351 | set_mac_metadata(struct archive_write_disk *a, const char *pathname, | |
4352 | const void *metadata, size_t metadata_size) | |
4353 | { | |
4354 | struct archive_string tmp; | |
4355 | ssize_t written; | |
4356 | int fd; | |
4357 | int ret = ARCHIVE_OK; | |
4358 | ||
4359 | /* This would be simpler if copyfile() could just accept the | |
4360 | * metadata as a block of memory; then we could sidestep this | |
4361 | * silly dance of writing the data to disk just so that | |
4362 | * copyfile() can read it back in again. */ | |
4363 | archive_string_init(&tmp); | |
4364 | archive_strcpy(&tmp, pathname); | |
4365 | archive_strcat(&tmp, ".XXXXXX"); | |
4366 | fd = mkstemp(tmp.s); | |
4367 | ||
4368 | if (fd < 0) { | |
4369 | archive_set_error(&a->archive, errno, | |
4370 | "Failed to restore metadata"); | |
f356f0e0 | 4371 | archive_string_free(&tmp); |
b8ad1655 TK |
4372 | return (ARCHIVE_WARN); |
4373 | } | |
4374 | written = write(fd, metadata, metadata_size); | |
4375 | close(fd); | |
4d920441 | 4376 | if ((size_t)written != metadata_size) { |
b8ad1655 TK |
4377 | archive_set_error(&a->archive, errno, |
4378 | "Failed to restore metadata"); | |
4379 | ret = ARCHIVE_WARN; | |
4d920441 MN |
4380 | } else { |
4381 | int compressed; | |
4382 | ||
63f4eb7d | 4383 | #if defined(UF_COMPRESSED) |
4d920441 MN |
4384 | if ((a->todo & TODO_HFS_COMPRESSION) != 0 && |
4385 | (ret = lazy_stat(a)) == ARCHIVE_OK) | |
4386 | compressed = a->st.st_flags & UF_COMPRESSED; | |
4387 | else | |
63f4eb7d | 4388 | #endif |
4d920441 MN |
4389 | compressed = 0; |
4390 | ret = copy_metadata(a, tmp.s, pathname, compressed); | |
b8ad1655 TK |
4391 | } |
4392 | unlink(tmp.s); | |
f356f0e0 | 4393 | archive_string_free(&tmp); |
b8ad1655 TK |
4394 | return (ret); |
4395 | } | |
a70241b7 MN |
4396 | |
4397 | static int | |
4398 | fixup_appledouble(struct archive_write_disk *a, const char *pathname) | |
4399 | { | |
4400 | char buff[8]; | |
4401 | struct stat st; | |
4402 | const char *p; | |
4403 | struct archive_string datafork; | |
4404 | int fd = -1, ret = ARCHIVE_OK; | |
4405 | ||
4406 | archive_string_init(&datafork); | |
4407 | /* Check if the current file name is a type of the resource | |
4408 | * fork file. */ | |
4409 | p = strrchr(pathname, '/'); | |
4410 | if (p == NULL) | |
4411 | p = pathname; | |
4412 | else | |
4413 | p++; | |
4414 | if (p[0] != '.' || p[1] != '_') | |
4415 | goto skip_appledouble; | |
4416 | ||
4417 | /* | |
4418 | * Check if the data fork file exists. | |
4419 | * | |
4420 | * TODO: Check if this write disk object has handled it. | |
4421 | */ | |
4422 | archive_strncpy(&datafork, pathname, p - pathname); | |
4423 | archive_strcat(&datafork, p + 2); | |
e6056040 | 4424 | if ( |
4425 | #ifdef HAVE_LSTAT | |
4426 | lstat(datafork.s, &st) == -1 || | |
4427 | #else | |
4428 | la_stat(datafork.s, &st) == -1 || | |
4429 | #endif | |
390d8301 | 4430 | (((st.st_mode & AE_IFMT) != AE_IFREG) && |
4431 | ((st.st_mode & AE_IFMT) != AE_IFDIR))) | |
a70241b7 MN |
4432 | goto skip_appledouble; |
4433 | ||
4434 | /* | |
4435 | * Check if the file is in the AppleDouble form. | |
4436 | */ | |
4d920441 | 4437 | fd = open(pathname, O_RDONLY | O_BINARY | O_CLOEXEC); |
a70241b7 MN |
4438 | __archive_ensure_cloexec_flag(fd); |
4439 | if (fd == -1) { | |
4440 | archive_set_error(&a->archive, errno, | |
4441 | "Failed to open a restoring file"); | |
4442 | ret = ARCHIVE_WARN; | |
4443 | goto skip_appledouble; | |
4444 | } | |
4445 | if (read(fd, buff, 8) == -1) { | |
4446 | archive_set_error(&a->archive, errno, | |
4447 | "Failed to read a restoring file"); | |
4d920441 | 4448 | close(fd); |
a70241b7 MN |
4449 | ret = ARCHIVE_WARN; |
4450 | goto skip_appledouble; | |
4451 | } | |
4d920441 | 4452 | close(fd); |
a70241b7 MN |
4453 | /* Check AppleDouble Magic Code. */ |
4454 | if (archive_be32dec(buff) != 0x00051607) | |
4455 | goto skip_appledouble; | |
4456 | /* Check AppleDouble Version. */ | |
4457 | if (archive_be32dec(buff+4) != 0x00020000) | |
4458 | goto skip_appledouble; | |
4459 | ||
4d920441 | 4460 | ret = copy_metadata(a, pathname, datafork.s, |
63f4eb7d | 4461 | #if defined(UF_COMPRESSED) |
4d920441 | 4462 | st.st_flags & UF_COMPRESSED); |
63f4eb7d MN |
4463 | #else |
4464 | 0); | |
4465 | #endif | |
4d920441 MN |
4466 | if (ret == ARCHIVE_OK) { |
4467 | unlink(pathname); | |
4468 | ret = ARCHIVE_EOF; | |
a70241b7 | 4469 | } |
a70241b7 | 4470 | skip_appledouble: |
a70241b7 MN |
4471 | archive_string_free(&datafork); |
4472 | return (ret); | |
4473 | } | |
b8ad1655 TK |
4474 | #endif |
4475 | ||
365a91de | 4476 | #if ARCHIVE_XATTR_LINUX || ARCHIVE_XATTR_DARWIN || ARCHIVE_XATTR_AIX |
8f776fd9 | 4477 | /* |
365a91de | 4478 | * Restore extended attributes - Linux, Darwin and AIX implementations: |
0d621852 | 4479 | * AIX' ea interface is syntaxwise identical to the Linux xattr interface. |
8f776fd9 TK |
4480 | */ |
4481 | static int | |
4482 | set_xattrs(struct archive_write_disk *a) | |
4483 | { | |
4484 | struct archive_entry *entry = a->entry; | |
c20d7a5c | 4485 | struct archive_string errlist; |
8f776fd9 TK |
4486 | int ret = ARCHIVE_OK; |
4487 | int i = archive_entry_xattr_reset(entry); | |
c20d7a5c MM |
4488 | short fail = 0; |
4489 | ||
4490 | archive_string_init(&errlist); | |
8f776fd9 TK |
4491 | |
4492 | while (i--) { | |
4493 | const char *name; | |
4494 | const void *value; | |
4495 | size_t size; | |
c20d7a5c MM |
4496 | int e; |
4497 | ||
8f776fd9 | 4498 | archive_entry_xattr_next(entry, &name, &value, &size); |
c20d7a5c MM |
4499 | |
4500 | if (name == NULL) | |
4501 | continue; | |
365a91de | 4502 | #if ARCHIVE_XATTR_LINUX |
c20d7a5c MM |
4503 | /* Linux: quietly skip POSIX.1e ACL extended attributes */ |
4504 | if (strncmp(name, "system.", 7) == 0 && | |
4505 | (strcmp(name + 7, "posix_acl_access") == 0 || | |
4506 | strcmp(name + 7, "posix_acl_default") == 0)) | |
4507 | continue; | |
4508 | if (strncmp(name, "trusted.SGI_", 12) == 0 && | |
4509 | (strcmp(name + 12, "ACL_DEFAULT") == 0 || | |
4510 | strcmp(name + 12, "ACL_FILE") == 0)) | |
4511 | continue; | |
4512 | ||
4513 | /* Linux: xfsroot namespace is obsolete and unsupported */ | |
4514 | if (strncmp(name, "xfsroot.", 8) == 0) { | |
4515 | fail = 1; | |
4516 | archive_strcat(&errlist, name); | |
4517 | archive_strappend_char(&errlist, ' '); | |
4518 | continue; | |
4519 | } | |
4520 | #endif | |
4521 | ||
4522 | if (a->fd >= 0) { | |
4523 | #if ARCHIVE_XATTR_LINUX | |
4524 | e = fsetxattr(a->fd, name, value, size, 0); | |
365a91de | 4525 | #elif ARCHIVE_XATTR_DARWIN |
c20d7a5c | 4526 | e = fsetxattr(a->fd, name, value, size, 0, 0); |
365a91de | 4527 | #elif ARCHIVE_XATTR_AIX |
c20d7a5c | 4528 | e = fsetea(a->fd, name, value, size, 0); |
8f776fd9 | 4529 | #endif |
c20d7a5c | 4530 | } else { |
365a91de | 4531 | #if ARCHIVE_XATTR_LINUX |
c20d7a5c MM |
4532 | e = lsetxattr(archive_entry_pathname(entry), |
4533 | name, value, size, 0); | |
365a91de | 4534 | #elif ARCHIVE_XATTR_DARWIN |
c20d7a5c MM |
4535 | e = setxattr(archive_entry_pathname(entry), |
4536 | name, value, size, 0, XATTR_NOFOLLOW); | |
365a91de | 4537 | #elif ARCHIVE_XATTR_AIX |
c20d7a5c MM |
4538 | e = lsetea(archive_entry_pathname(entry), |
4539 | name, value, size, 0); | |
0d621852 | 4540 | #endif |
c20d7a5c MM |
4541 | } |
4542 | if (e == -1) { | |
8f776fd9 | 4543 | ret = ARCHIVE_WARN; |
c20d7a5c MM |
4544 | archive_strcat(&errlist, name); |
4545 | archive_strappend_char(&errlist, ' '); | |
4546 | if (errno != ENOTSUP && errno != ENOSYS) | |
4547 | fail = 1; | |
8f776fd9 TK |
4548 | } |
4549 | } | |
c20d7a5c MM |
4550 | |
4551 | if (ret == ARCHIVE_WARN) { | |
4552 | if (fail && errlist.length > 0) { | |
4553 | errlist.length--; | |
4554 | errlist.s[errlist.length] = '\0'; | |
4555 | archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, | |
4556 | "Cannot restore extended attributes: %s", | |
4557 | errlist.s); | |
4558 | } else | |
4559 | archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, | |
4560 | "Cannot restore extended " | |
4561 | "attributes on this file system."); | |
4562 | } | |
4563 | ||
4564 | archive_string_free(&errlist); | |
8f776fd9 TK |
4565 | return (ret); |
4566 | } | |
365a91de | 4567 | #elif ARCHIVE_XATTR_FREEBSD |
b21f351a TK |
4568 | /* |
4569 | * Restore extended attributes - FreeBSD implementation | |
4570 | */ | |
4571 | static int | |
4572 | set_xattrs(struct archive_write_disk *a) | |
4573 | { | |
4574 | struct archive_entry *entry = a->entry; | |
c20d7a5c | 4575 | struct archive_string errlist; |
b21f351a TK |
4576 | int ret = ARCHIVE_OK; |
4577 | int i = archive_entry_xattr_reset(entry); | |
c20d7a5c MM |
4578 | short fail = 0; |
4579 | ||
4580 | archive_string_init(&errlist); | |
b21f351a TK |
4581 | |
4582 | while (i--) { | |
4583 | const char *name; | |
4584 | const void *value; | |
4585 | size_t size; | |
4586 | archive_entry_xattr_next(entry, &name, &value, &size); | |
4587 | if (name != NULL) { | |
4588 | int e; | |
4589 | int namespace; | |
4590 | ||
4d1a6ebc SW |
4591 | namespace = EXTATTR_NAMESPACE_USER; |
4592 | ||
b21f351a TK |
4593 | if (strncmp(name, "user.", 5) == 0) { |
4594 | /* "user." attributes go to user namespace */ | |
4595 | name += 5; | |
4596 | namespace = EXTATTR_NAMESPACE_USER; | |
08f53f56 SW |
4597 | } else if (strncmp(name, "system.", 7) == 0) { |
4598 | name += 7; | |
4599 | namespace = EXTATTR_NAMESPACE_SYSTEM; | |
5b4bc233 SW |
4600 | if (!strcmp(name, "nfs4.acl") || |
4601 | !strcmp(name, "posix1e.acl_access") || | |
4602 | !strcmp(name, "posix1e.acl_default")) | |
4603 | continue; | |
b21f351a | 4604 | } else { |
c20d7a5c MM |
4605 | /* Other namespaces are unsupported */ |
4606 | archive_strcat(&errlist, name); | |
4607 | archive_strappend_char(&errlist, ' '); | |
4608 | fail = 1; | |
b21f351a TK |
4609 | ret = ARCHIVE_WARN; |
4610 | continue; | |
4611 | } | |
365a91de MM |
4612 | |
4613 | if (a->fd >= 0) { | |
4d1a6ebc SW |
4614 | /* |
4615 | * On FreeBSD, extattr_set_fd does not | |
4616 | * return the same as | |
4617 | * extattr_set_file. It returns zero | |
4618 | * on success, non-zero on failure. | |
4619 | * | |
4620 | * We can detect the failure by | |
4621 | * manually setting errno prior to the | |
4622 | * call and checking after. | |
4623 | * | |
4624 | * If errno remains zero, fake the | |
4625 | * return value by setting e to size. | |
4626 | * | |
4627 | * This is a hack for now until I | |
4628 | * (Shawn Webb) get FreeBSD to fix the | |
4629 | * issue, if that's even possible. | |
4630 | */ | |
4631 | errno = 0; | |
cc9cbbb1 MM |
4632 | e = extattr_set_fd(a->fd, namespace, name, |
4633 | value, size); | |
4d1a6ebc SW |
4634 | if (e == 0 && errno == 0) { |
4635 | e = size; | |
4636 | } | |
365a91de MM |
4637 | } else { |
4638 | e = extattr_set_link( | |
cc9cbbb1 MM |
4639 | archive_entry_pathname(entry), namespace, |
4640 | name, value, size); | |
b21f351a TK |
4641 | } |
4642 | if (e != (int)size) { | |
c20d7a5c MM |
4643 | archive_strcat(&errlist, name); |
4644 | archive_strappend_char(&errlist, ' '); | |
b21f351a | 4645 | ret = ARCHIVE_WARN; |
c20d7a5c MM |
4646 | if (errno != ENOTSUP && errno != ENOSYS) |
4647 | fail = 1; | |
b21f351a TK |
4648 | } |
4649 | } | |
4650 | } | |
c20d7a5c MM |
4651 | |
4652 | if (ret == ARCHIVE_WARN) { | |
4653 | if (fail && errlist.length > 0) { | |
4654 | errlist.length--; | |
4655 | errlist.s[errlist.length] = '\0'; | |
4656 | ||
4657 | archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, | |
4658 | "Cannot restore extended attributes: %s", | |
4659 | errlist.s); | |
4660 | } else | |
4661 | archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, | |
4662 | "Cannot restore extended " | |
4663 | "attributes on this file system."); | |
4664 | } | |
4665 | ||
4666 | archive_string_free(&errlist); | |
b21f351a TK |
4667 | return (ret); |
4668 | } | |
8f776fd9 TK |
4669 | #else |
4670 | /* | |
4671 | * Restore extended attributes - stub implementation for unsupported systems | |
4672 | */ | |
4673 | static int | |
4674 | set_xattrs(struct archive_write_disk *a) | |
4675 | { | |
4676 | static int warning_done = 0; | |
4677 | ||
4678 | /* If there aren't any extended attributes, then it's okay not | |
4679 | * to extract them, otherwise, issue a single warning. */ | |
4680 | if (archive_entry_xattr_count(a->entry) != 0 && !warning_done) { | |
4681 | warning_done = 1; | |
4682 | archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, | |
4683 | "Cannot restore extended attributes on this system"); | |
4684 | return (ARCHIVE_WARN); | |
4685 | } | |
4686 | /* Warning was already emitted; suppress further warnings. */ | |
4687 | return (ARCHIVE_OK); | |
4688 | } | |
4689 | #endif | |
4690 | ||
8f776fd9 TK |
4691 | /* |
4692 | * Test if file on disk is older than entry. | |
4693 | */ | |
4694 | static int | |
4695 | older(struct stat *st, struct archive_entry *entry) | |
4696 | { | |
4697 | /* First, test the seconds and return if we have a definite answer. */ | |
4698 | /* Definitely older. */ | |
c89d1a1e | 4699 | if (to_int64_time(st->st_mtime) < to_int64_time(archive_entry_mtime(entry))) |
8f776fd9 TK |
4700 | return (1); |
4701 | /* Definitely younger. */ | |
c89d1a1e | 4702 | if (to_int64_time(st->st_mtime) > to_int64_time(archive_entry_mtime(entry))) |
8f776fd9 TK |
4703 | return (0); |
4704 | /* If this platform supports fractional seconds, try those. */ | |
4705 | #if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC | |
4706 | /* Definitely older. */ | |
4707 | if (st->st_mtimespec.tv_nsec < archive_entry_mtime_nsec(entry)) | |
4708 | return (1); | |
8f776fd9 TK |
4709 | #elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC |
4710 | /* Definitely older. */ | |
4711 | if (st->st_mtim.tv_nsec < archive_entry_mtime_nsec(entry)) | |
4712 | return (1); | |
d831cc4b BJ |
4713 | #elif HAVE_STRUCT_STAT_ST_MTIME_N |
4714 | /* older. */ | |
4715 | if (st->st_mtime_n < archive_entry_mtime_nsec(entry)) | |
4716 | return (1); | |
4717 | #elif HAVE_STRUCT_STAT_ST_UMTIME | |
4718 | /* older. */ | |
4719 | if (st->st_umtime * 1000 < archive_entry_mtime_nsec(entry)) | |
4720 | return (1); | |
a0b5f839 BJ |
4721 | #elif HAVE_STRUCT_STAT_ST_MTIME_USEC |
4722 | /* older. */ | |
4723 | if (st->st_mtime_usec * 1000 < archive_entry_mtime_nsec(entry)) | |
4724 | return (1); | |
8f776fd9 TK |
4725 | #else |
4726 | /* This system doesn't have high-res timestamps. */ | |
4727 | #endif | |
d831cc4b | 4728 | /* Same age or newer, so not older. */ |
8f776fd9 TK |
4729 | return (0); |
4730 | } | |
5b3644c3 | 4731 | |
bea9f9cf MM |
4732 | #ifndef ARCHIVE_ACL_SUPPORT |
4733 | int | |
4734 | archive_write_disk_set_acls(struct archive *a, int fd, const char *name, | |
4735 | struct archive_acl *abstract_acl, __LA_MODE_T mode) | |
4736 | { | |
4737 | (void)a; /* UNUSED */ | |
4738 | (void)fd; /* UNUSED */ | |
4739 | (void)name; /* UNUSED */ | |
4740 | (void)abstract_acl; /* UNUSED */ | |
4741 | (void)mode; /* UNUSED */ | |
4742 | return (ARCHIVE_OK); | |
4743 | } | |
4744 | #endif | |
4745 | ||
0cb9df7f SG |
4746 | /* |
4747 | * Close the file descriptor if one is open. | |
4748 | */ | |
4749 | static void close_file_descriptor(struct archive_write_disk* a) | |
4750 | { | |
092631ce SG |
4751 | if (a->fd >= 0) { |
4752 | close(a->fd); | |
4753 | a->fd = -1; | |
4754 | } | |
0cb9df7f SG |
4755 | } |
4756 | ||
4757 | ||
5b3644c3 MN |
4758 | #endif /* !_WIN32 || __CYGWIN__ */ |
4759 |