1228753Smm/*-
2231200Smm * Copyright (c) 2003-2010 Tim Kientzle
3248616Smm * Copyright (c) 2012 Michihiro NAKAJIMA
4228753Smm * All rights reserved.
5228753Smm *
6228753Smm * Redistribution and use in source and binary forms, with or without
7228753Smm * modification, are permitted provided that the following conditions
8228753Smm * are met:
9228753Smm * 1. Redistributions of source code must retain the above copyright
10228753Smm *    notice, this list of conditions and the following disclaimer
11228753Smm *    in this position and unchanged.
12228753Smm * 2. Redistributions in binary form must reproduce the above copyright
13228753Smm *    notice, this list of conditions and the following disclaimer in the
14228753Smm *    documentation and/or other materials provided with the distribution.
15228753Smm *
16228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
17228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
20228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26228753Smm */
27228753Smm
28228753Smm#include "archive_platform.h"
29231200Smm__FBSDID("$FreeBSD$");
30228753Smm
31231200Smm#if !defined(_WIN32) || defined(__CYGWIN__)
32231200Smm
33228753Smm#ifdef HAVE_SYS_TYPES_H
34228753Smm#include <sys/types.h>
35228753Smm#endif
36248616Smm#ifdef HAVE_SYS_ACL_H
37248616Smm#include <sys/acl.h>
38248616Smm#endif
39228753Smm#ifdef HAVE_SYS_EXTATTR_H
40228753Smm#include <sys/extattr.h>
41228753Smm#endif
42316338Smm#if HAVE_SYS_XATTR_H
43228753Smm#include <sys/xattr.h>
44316338Smm#elif HAVE_ATTR_XATTR_H
45248616Smm#include <attr/xattr.h>
46228753Smm#endif
47231200Smm#ifdef HAVE_SYS_EA_H
48231200Smm#include <sys/ea.h>
49231200Smm#endif
50228753Smm#ifdef HAVE_SYS_IOCTL_H
51228753Smm#include <sys/ioctl.h>
52228753Smm#endif
53228753Smm#ifdef HAVE_SYS_STAT_H
54228753Smm#include <sys/stat.h>
55228753Smm#endif
56228753Smm#ifdef HAVE_SYS_TIME_H
57228753Smm#include <sys/time.h>
58228753Smm#endif
59228753Smm#ifdef HAVE_SYS_UTIME_H
60228753Smm#include <sys/utime.h>
61228753Smm#endif
62231200Smm#ifdef HAVE_COPYFILE_H
63231200Smm#include <copyfile.h>
64231200Smm#endif
65228753Smm#ifdef HAVE_ERRNO_H
66228753Smm#include <errno.h>
67228753Smm#endif
68228753Smm#ifdef HAVE_FCNTL_H
69228753Smm#include <fcntl.h>
70228753Smm#endif
71228753Smm#ifdef HAVE_GRP_H
72228753Smm#include <grp.h>
73228753Smm#endif
74231200Smm#ifdef HAVE_LANGINFO_H
75231200Smm#include <langinfo.h>
76231200Smm#endif
77228753Smm#ifdef HAVE_LINUX_FS_H
78228753Smm#include <linux/fs.h>	/* for Linux file flags */
79228753Smm#endif
80228753Smm/*
81228753Smm * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
82228753Smm * As the include guards don't agree, the order of include is important.
83228753Smm */
84228753Smm#ifdef HAVE_LINUX_EXT2_FS_H
85228753Smm#include <linux/ext2_fs.h>	/* for Linux file flags */
86228753Smm#endif
87228753Smm#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
88228753Smm#include <ext2fs/ext2_fs.h>	/* Linux file flags, broken on Cygwin */
89228753Smm#endif
90228753Smm#ifdef HAVE_LIMITS_H
91228753Smm#include <limits.h>
92228753Smm#endif
93228753Smm#ifdef HAVE_PWD_H
94228753Smm#include <pwd.h>
95228753Smm#endif
96228753Smm#include <stdio.h>
97228753Smm#ifdef HAVE_STDLIB_H
98228753Smm#include <stdlib.h>
99228753Smm#endif
100228753Smm#ifdef HAVE_STRING_H
101228753Smm#include <string.h>
102228753Smm#endif
103228753Smm#ifdef HAVE_UNISTD_H
104228753Smm#include <unistd.h>
105228753Smm#endif
106228753Smm#ifdef HAVE_UTIME_H
107228753Smm#include <utime.h>
108228753Smm#endif
109231200Smm#ifdef F_GETTIMES /* Tru64 specific */
110231200Smm#include <sys/fcntl1.h>
111231200Smm#endif
112228753Smm
113313571Smm/*
114313571Smm * Macro to cast st_mtime and time_t to an int64 so that 2 numbers can reliably be compared.
115313571Smm *
116313571Smm * It assumes that the input is an integer type of no more than 64 bits.
117313571Smm * If the number is less than zero, t must be a signed type, so it fits in
118313571Smm * int64_t. Otherwise, it's a nonnegative value so we can cast it to uint64_t
119313571Smm * without loss. But it could be a large unsigned value, so we have to clip it
120313571Smm * to INT64_MAX.*
121313571Smm */
122313571Smm#define to_int64_time(t) \
123313571Smm   ((t) < 0 ? (int64_t)(t) : (uint64_t)(t) > (uint64_t)INT64_MAX ? INT64_MAX : (int64_t)(t))
124313571Smm
125231200Smm#if __APPLE__
126231200Smm#include <TargetConditionals.h>
127231200Smm#if TARGET_OS_MAC && !TARGET_OS_EMBEDDED && HAVE_QUARANTINE_H
128231200Smm#include <quarantine.h>
129231200Smm#define HAVE_QUARANTINE 1
130231200Smm#endif
131231200Smm#endif
132231200Smm
133248616Smm#ifdef HAVE_ZLIB_H
134248616Smm#include <zlib.h>
135248616Smm#endif
136248616Smm
137231200Smm/* TODO: Support Mac OS 'quarantine' feature.  This is really just a
138231200Smm * standard tag to mark files that have been downloaded as "tainted".
139231200Smm * On Mac OS, we should mark the extracted files as tainted if the
140231200Smm * archive being read was tainted.  Windows has a similar feature; we
141231200Smm * should investigate ways to support this generically. */
142231200Smm
143228753Smm#include "archive.h"
144231200Smm#include "archive_acl_private.h"
145228753Smm#include "archive_string.h"
146248616Smm#include "archive_endian.h"
147228753Smm#include "archive_entry.h"
148228753Smm#include "archive_private.h"
149238909Smm#include "archive_write_disk_private.h"
150228753Smm
151228753Smm#ifndef O_BINARY
152228753Smm#define O_BINARY 0
153228753Smm#endif
154248616Smm#ifndef O_CLOEXEC
155306322Smm#define O_CLOEXEC 0
156248616Smm#endif
157228753Smm
158306322Smm/* Ignore non-int O_NOFOLLOW constant. */
159306322Smm/* gnulib's fcntl.h does this on AIX, but it seems practical everywhere */
160306322Smm#if defined O_NOFOLLOW && !(INT_MIN <= O_NOFOLLOW && O_NOFOLLOW <= INT_MAX)
161306322Smm#undef O_NOFOLLOW
162306322Smm#endif
163306322Smm
164306322Smm#ifndef O_NOFOLLOW
165306322Smm#define O_NOFOLLOW 0
166306322Smm#endif
167306322Smm
168349525Smm#ifndef AT_FDCWD
169349525Smm#define AT_FDCWD -100
170349525Smm#endif
171349525Smm
172228753Smmstruct fixup_entry {
173228753Smm	struct fixup_entry	*next;
174231200Smm	struct archive_acl	 acl;
175228753Smm	mode_t			 mode;
176228753Smm	int64_t			 atime;
177228753Smm	int64_t                  birthtime;
178228753Smm	int64_t			 mtime;
179231200Smm	int64_t			 ctime;
180228753Smm	unsigned long		 atime_nanos;
181228753Smm	unsigned long            birthtime_nanos;
182228753Smm	unsigned long		 mtime_nanos;
183231200Smm	unsigned long		 ctime_nanos;
184228753Smm	unsigned long		 fflags_set;
185231200Smm	size_t			 mac_metadata_size;
186231200Smm	void			*mac_metadata;
187228753Smm	int			 fixup; /* bitmask of what needs fixing */
188228753Smm	char			*name;
189228753Smm};
190228753Smm
191228753Smm/*
192228753Smm * We use a bitmask to track which operations remain to be done for
193228753Smm * this file.  In particular, this helps us avoid unnecessary
194228753Smm * operations when it's possible to take care of one step as a
195228753Smm * side-effect of another.  For example, mkdir() can specify the mode
196228753Smm * for the newly-created object but symlink() cannot.  This means we
197228753Smm * can skip chmod() if mkdir() succeeded, but we must explicitly
198228753Smm * chmod() if we're trying to create a directory that already exists
199228753Smm * (mkdir() failed) or if we're restoring a symlink.  Similarly, we
200228753Smm * need to verify UID/GID before trying to restore SUID/SGID bits;
201228753Smm * that verification can occur explicitly through a stat() call or
202228753Smm * implicitly because of a successful chown() call.
203228753Smm */
204228753Smm#define	TODO_MODE_FORCE		0x40000000
205228753Smm#define	TODO_MODE_BASE		0x20000000
206228753Smm#define	TODO_SUID		0x10000000
207228753Smm#define	TODO_SUID_CHECK		0x08000000
208228753Smm#define	TODO_SGID		0x04000000
209228753Smm#define	TODO_SGID_CHECK		0x02000000
210248616Smm#define	TODO_APPLEDOUBLE	0x01000000
211228753Smm#define	TODO_MODE		(TODO_MODE_BASE|TODO_SUID|TODO_SGID)
212228753Smm#define	TODO_TIMES		ARCHIVE_EXTRACT_TIME
213228753Smm#define	TODO_OWNER		ARCHIVE_EXTRACT_OWNER
214228753Smm#define	TODO_FFLAGS		ARCHIVE_EXTRACT_FFLAGS
215228753Smm#define	TODO_ACLS		ARCHIVE_EXTRACT_ACL
216228753Smm#define	TODO_XATTR		ARCHIVE_EXTRACT_XATTR
217231200Smm#define	TODO_MAC_METADATA	ARCHIVE_EXTRACT_MAC_METADATA
218248616Smm#define	TODO_HFS_COMPRESSION	ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED
219228753Smm
220228753Smmstruct archive_write_disk {
221228753Smm	struct archive	archive;
222228753Smm
223228753Smm	mode_t			 user_umask;
224228753Smm	struct fixup_entry	*fixup_list;
225228753Smm	struct fixup_entry	*current_fixup;
226231200Smm	int64_t			 user_uid;
227231200Smm	int			 skip_file_set;
228238856Smm	int64_t			 skip_file_dev;
229238856Smm	int64_t			 skip_file_ino;
230228753Smm	time_t			 start_time;
231228753Smm
232231200Smm	int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid);
233228753Smm	void  (*cleanup_gid)(void *private);
234228753Smm	void			*lookup_gid_data;
235231200Smm	int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid);
236228753Smm	void  (*cleanup_uid)(void *private);
237228753Smm	void			*lookup_uid_data;
238228753Smm
239228753Smm	/*
240228753Smm	 * Full path of last file to satisfy symlink checks.
241228753Smm	 */
242228753Smm	struct archive_string	path_safe;
243228753Smm
244228753Smm	/*
245228753Smm	 * Cached stat data from disk for the current entry.
246228753Smm	 * If this is valid, pst points to st.  Otherwise,
247228753Smm	 * pst is null.
248228753Smm	 */
249228753Smm	struct stat		 st;
250228753Smm	struct stat		*pst;
251228753Smm
252228753Smm	/* Information about the object being restored right now. */
253228753Smm	struct archive_entry	*entry; /* Entry being extracted. */
254228753Smm	char			*name; /* Name of entry, possibly edited. */
255228753Smm	struct archive_string	 _name_data; /* backing store for 'name' */
256358090Smm	char			*tmpname; /* Temporary name * */
257358090Smm	struct archive_string	 _tmpname_data; /* backing store for 'tmpname' */
258228753Smm	/* Tasks remaining for this object. */
259228753Smm	int			 todo;
260228753Smm	/* Tasks deferred until end-of-archive. */
261228753Smm	int			 deferred;
262228753Smm	/* Options requested by the client. */
263228753Smm	int			 flags;
264228753Smm	/* Handle for the file we're restoring. */
265228753Smm	int			 fd;
266228753Smm	/* Current offset for writing data to the file. */
267231200Smm	int64_t			 offset;
268228753Smm	/* Last offset actually written to disk. */
269231200Smm	int64_t			 fd_offset;
270231200Smm	/* Total bytes actually written to files. */
271231200Smm	int64_t			 total_bytes_written;
272228753Smm	/* Maximum size of file, -1 if unknown. */
273231200Smm	int64_t			 filesize;
274228753Smm	/* Dir we were in before this restore; only for deep paths. */
275228753Smm	int			 restore_pwd;
276228753Smm	/* Mode we should use for this entry; affected by _PERM and umask. */
277228753Smm	mode_t			 mode;
278228753Smm	/* UID/GID to use in restoring this entry. */
279231200Smm	int64_t			 uid;
280231200Smm	int64_t			 gid;
281248616Smm	/*
282248616Smm	 * HFS+ Compression.
283248616Smm	 */
284248616Smm	/* Xattr "com.apple.decmpfs". */
285248616Smm	uint32_t		 decmpfs_attr_size;
286248616Smm	unsigned char		*decmpfs_header_p;
287248616Smm	/* ResourceFork set options used for fsetxattr. */
288248616Smm	int			 rsrc_xattr_options;
289248616Smm	/* Xattr "com.apple.ResourceFork". */
290248616Smm	unsigned char		*resource_fork;
291248616Smm	size_t			 resource_fork_allocated_size;
292248616Smm	unsigned int		 decmpfs_block_count;
293248616Smm	uint32_t		*decmpfs_block_info;
294248616Smm	/* Buffer for compressed data. */
295248616Smm	unsigned char		*compressed_buffer;
296248616Smm	size_t			 compressed_buffer_size;
297248616Smm	size_t			 compressed_buffer_remaining;
298248616Smm	/* The offset of the ResourceFork where compressed data will
299248616Smm	 * be placed. */
300248616Smm	uint32_t		 compressed_rsrc_position;
301248616Smm	uint32_t		 compressed_rsrc_position_v;
302248616Smm	/* Buffer for uncompressed data. */
303248616Smm	char			*uncompressed_buffer;
304248616Smm	size_t			 block_remaining_bytes;
305248616Smm	size_t			 file_remaining_bytes;
306248616Smm#ifdef HAVE_ZLIB_H
307248616Smm	z_stream		 stream;
308248616Smm	int			 stream_valid;
309248616Smm	int			 decmpfs_compression_level;
310248616Smm#endif
311228753Smm};
312228753Smm
313228753Smm/*
314228753Smm * Default mode for dirs created automatically (will be modified by umask).
315231200Smm * Note that POSIX specifies 0777 for implicitly-created dirs, "modified
316228753Smm * by the process' file creation mask."
317228753Smm */
318228753Smm#define	DEFAULT_DIR_MODE 0777
319228753Smm/*
320228753Smm * Dir modes are restored in two steps:  During the extraction, the permissions
321228753Smm * in the archive are modified to match the following limits.  During
322228753Smm * the post-extract fixup pass, the permissions from the archive are
323228753Smm * applied.
324228753Smm */
325228753Smm#define	MINIMUM_DIR_MODE 0700
326228753Smm#define	MAXIMUM_DIR_MODE 0775
327228753Smm
328248616Smm/*
329313571Smm * Maximum uncompressed size of a decmpfs block.
330248616Smm */
331248616Smm#define MAX_DECMPFS_BLOCK_SIZE	(64 * 1024)
332248616Smm/*
333248616Smm * HFS+ compression type.
334248616Smm */
335248616Smm#define CMP_XATTR		3/* Compressed data in xattr. */
336248616Smm#define CMP_RESOURCE_FORK	4/* Compressed data in resource fork. */
337248616Smm/*
338248616Smm * HFS+ compression resource fork.
339248616Smm */
340248616Smm#define RSRC_H_SIZE	260	/* Base size of Resource fork header. */
341248616Smm#define RSRC_F_SIZE	50	/* Size of Resource fork footer. */
342248616Smm/* Size to write compressed data to resource fork. */
343248616Smm#define COMPRESSED_W_SIZE	(64 * 1024)
344313571Smm/* decmpfs definitions. */
345248616Smm#define MAX_DECMPFS_XATTR_SIZE		3802
346248616Smm#ifndef DECMPFS_XATTR_NAME
347248616Smm#define DECMPFS_XATTR_NAME		"com.apple.decmpfs"
348248616Smm#endif
349248616Smm#define DECMPFS_MAGIC			0x636d7066
350248616Smm#define DECMPFS_COMPRESSION_MAGIC	0
351248616Smm#define DECMPFS_COMPRESSION_TYPE	4
352248616Smm#define DECMPFS_UNCOMPRESSED_SIZE	8
353248616Smm#define DECMPFS_HEADER_SIZE		16
354248616Smm
355248616Smm#define HFS_BLOCKS(s)	((s) >> 12)
356248616Smm
357349525Smm
358349525Smmstatic int	la_opendirat(int, const char *);
359358090Smmstatic int	la_mktemp(struct archive_write_disk *);
360309702Smmstatic void	fsobj_error(int *, struct archive_string *, int, const char *,
361309702Smm		    const char *);
362309702Smmstatic int	check_symlinks_fsobj(char *, int *, struct archive_string *,
363309702Smm		    int);
364228753Smmstatic int	check_symlinks(struct archive_write_disk *);
365228753Smmstatic int	create_filesystem_object(struct archive_write_disk *);
366309702Smmstatic struct fixup_entry *current_fixup(struct archive_write_disk *,
367309702Smm		    const char *pathname);
368231200Smm#if defined(HAVE_FCHDIR) && defined(PATH_MAX)
369228753Smmstatic void	edit_deep_directories(struct archive_write_disk *ad);
370228753Smm#endif
371309702Smmstatic int	cleanup_pathname_fsobj(char *, int *, struct archive_string *,
372309702Smm		    int);
373228753Smmstatic int	cleanup_pathname(struct archive_write_disk *);
374228753Smmstatic int	create_dir(struct archive_write_disk *, char *);
375228753Smmstatic int	create_parent_dir(struct archive_write_disk *, char *);
376248616Smmstatic ssize_t	hfs_write_data_block(struct archive_write_disk *,
377248616Smm		    const char *, size_t);
378248616Smmstatic int	fixup_appledouble(struct archive_write_disk *, const char *);
379228753Smmstatic int	older(struct stat *, struct archive_entry *);
380228753Smmstatic int	restore_entry(struct archive_write_disk *);
381231200Smmstatic int	set_mac_metadata(struct archive_write_disk *, const char *,
382231200Smm				 const void *, size_t);
383228753Smmstatic int	set_xattrs(struct archive_write_disk *);
384302001Smmstatic int	clear_nochange_fflags(struct archive_write_disk *);
385228753Smmstatic int	set_fflags(struct archive_write_disk *);
386228753Smmstatic int	set_fflags_platform(struct archive_write_disk *, int fd,
387228753Smm		    const char *name, mode_t mode,
388228753Smm		    unsigned long fflags_set, unsigned long fflags_clear);
389228753Smmstatic int	set_ownership(struct archive_write_disk *);
390228753Smmstatic int	set_mode(struct archive_write_disk *, int mode);
391228753Smmstatic int	set_time(int, int, const char *, time_t, long, time_t, long);
392231200Smmstatic int	set_times(struct archive_write_disk *, int, int, const char *,
393231200Smm		    time_t, long, time_t, long, time_t, long, time_t, long);
394231200Smmstatic int	set_times_from_entry(struct archive_write_disk *);
395228753Smmstatic struct fixup_entry *sort_dir_list(struct fixup_entry *p);
396228753Smmstatic ssize_t	write_data_block(struct archive_write_disk *,
397228753Smm		    const char *, size_t);
398228753Smm
399228753Smmstatic struct archive_vtable *archive_write_disk_vtable(void);
400228753Smm
401231200Smmstatic int	_archive_write_disk_close(struct archive *);
402231200Smmstatic int	_archive_write_disk_free(struct archive *);
403309702Smmstatic int	_archive_write_disk_header(struct archive *,
404309702Smm		    struct archive_entry *);
405231200Smmstatic int64_t	_archive_write_disk_filter_bytes(struct archive *, int);
406231200Smmstatic int	_archive_write_disk_finish_entry(struct archive *);
407309702Smmstatic ssize_t	_archive_write_disk_data(struct archive *, const void *,
408309702Smm		    size_t);
409309702Smmstatic ssize_t	_archive_write_disk_data_block(struct archive *, const void *,
410309702Smm		    size_t, int64_t);
411228753Smm
412228753Smmstatic int
413358090Smmla_mktemp(struct archive_write_disk *a)
414358090Smm{
415358090Smm	int oerrno, fd;
416358090Smm	mode_t mode;
417358090Smm
418358090Smm	archive_string_empty(&a->_tmpname_data);
419358090Smm	archive_string_sprintf(&a->_tmpname_data, "%s.XXXXXX", a->name);
420358090Smm	a->tmpname = a->_tmpname_data.s;
421358090Smm
422358090Smm	fd = __archive_mkstemp(a->tmpname);
423358090Smm	if (fd == -1)
424358090Smm		return -1;
425358090Smm
426358090Smm	mode = a->mode & 0777 & ~a->user_umask;
427358090Smm	if (fchmod(fd, mode) == -1) {
428358090Smm		oerrno = errno;
429358090Smm		close(fd);
430358090Smm		errno = oerrno;
431358090Smm		return -1;
432358090Smm	}
433358090Smm	return fd;
434358090Smm}
435358090Smm
436358090Smmstatic int
437349525Smmla_opendirat(int fd, const char *path) {
438349525Smm	const int flags = O_CLOEXEC
439349525Smm#if defined(O_BINARY)
440349525Smm	    | O_BINARY
441349525Smm#endif
442349525Smm#if defined(O_DIRECTORY)
443349525Smm	    | O_DIRECTORY
444349525Smm#endif
445349525Smm#if defined(O_PATH)
446349525Smm	    | O_PATH
447349525Smm#elif defined(O_SEARCH)
448349525Smm	    | O_SEARCH
449358090Smm#elif defined(__FreeBSD__) && defined(O_EXEC)
450349525Smm	    | O_EXEC
451349525Smm#else
452349525Smm	    | O_RDONLY
453349525Smm#endif
454349525Smm	    ;
455349525Smm
456349525Smm#if !defined(HAVE_OPENAT)
457349525Smm	if (fd != AT_FDCWD) {
458349525Smm		errno = ENOTSUP;
459349525Smm		return (-1);
460349525Smm	} else
461353377Smm		return (open(path, flags));
462349525Smm#else
463349525Smm	return (openat(fd, path, flags));
464349525Smm#endif
465349525Smm}
466349525Smm
467349525Smmstatic int
468231200Smmlazy_stat(struct archive_write_disk *a)
469228753Smm{
470228753Smm	if (a->pst != NULL) {
471228753Smm		/* Already have stat() data available. */
472228753Smm		return (ARCHIVE_OK);
473228753Smm	}
474228753Smm#ifdef HAVE_FSTAT
475228753Smm	if (a->fd >= 0 && fstat(a->fd, &a->st) == 0) {
476228753Smm		a->pst = &a->st;
477228753Smm		return (ARCHIVE_OK);
478228753Smm	}
479228753Smm#endif
480228753Smm	/*
481228753Smm	 * XXX At this point, symlinks should not be hit, otherwise
482231200Smm	 * XXX a race occurred.  Do we want to check explicitly for that?
483228753Smm	 */
484228753Smm	if (lstat(a->name, &a->st) == 0) {
485228753Smm		a->pst = &a->st;
486228753Smm		return (ARCHIVE_OK);
487228753Smm	}
488228753Smm	archive_set_error(&a->archive, errno, "Couldn't stat file");
489228753Smm	return (ARCHIVE_WARN);
490228753Smm}
491228753Smm
492228753Smmstatic struct archive_vtable *
493228753Smmarchive_write_disk_vtable(void)
494228753Smm{
495228753Smm	static struct archive_vtable av;
496228753Smm	static int inited = 0;
497228753Smm
498228753Smm	if (!inited) {
499231200Smm		av.archive_close = _archive_write_disk_close;
500231200Smm		av.archive_filter_bytes = _archive_write_disk_filter_bytes;
501231200Smm		av.archive_free = _archive_write_disk_free;
502231200Smm		av.archive_write_header = _archive_write_disk_header;
503231200Smm		av.archive_write_finish_entry
504231200Smm		    = _archive_write_disk_finish_entry;
505231200Smm		av.archive_write_data = _archive_write_disk_data;
506231200Smm		av.archive_write_data_block = _archive_write_disk_data_block;
507231200Smm		inited = 1;
508228753Smm	}
509228753Smm	return (&av);
510228753Smm}
511228753Smm
512231200Smmstatic int64_t
513231200Smm_archive_write_disk_filter_bytes(struct archive *_a, int n)
514231200Smm{
515231200Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
516231200Smm	(void)n; /* UNUSED */
517231200Smm	if (n == -1 || n == 0)
518231200Smm		return (a->total_bytes_written);
519231200Smm	return (-1);
520231200Smm}
521228753Smm
522231200Smm
523228753Smmint
524228753Smmarchive_write_disk_set_options(struct archive *_a, int flags)
525228753Smm{
526228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
527228753Smm
528228753Smm	a->flags = flags;
529228753Smm	return (ARCHIVE_OK);
530228753Smm}
531228753Smm
532228753Smm
533228753Smm/*
534228753Smm * Extract this entry to disk.
535228753Smm *
536228753Smm * TODO: Validate hardlinks.  According to the standards, we're
537228753Smm * supposed to check each extracted hardlink and squawk if it refers
538228753Smm * to a file that we didn't restore.  I'm not entirely convinced this
539228753Smm * is a good idea, but more importantly: Is there any way to validate
540228753Smm * hardlinks without keeping a complete list of filenames from the
541228753Smm * entire archive?? Ugh.
542228753Smm *
543228753Smm */
544228753Smmstatic int
545231200Smm_archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
546228753Smm{
547228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
548228753Smm	struct fixup_entry *fe;
549368708Smm	const char *linkname;
550228753Smm	int ret, r;
551228753Smm
552231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
553228753Smm	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
554228753Smm	    "archive_write_disk_header");
555228753Smm	archive_clear_error(&a->archive);
556228753Smm	if (a->archive.state & ARCHIVE_STATE_DATA) {
557231200Smm		r = _archive_write_disk_finish_entry(&a->archive);
558228753Smm		if (r == ARCHIVE_FATAL)
559228753Smm			return (r);
560228753Smm	}
561228753Smm
562228753Smm	/* Set up for this particular entry. */
563228753Smm	a->pst = NULL;
564228753Smm	a->current_fixup = NULL;
565228753Smm	a->deferred = 0;
566228753Smm	if (a->entry) {
567228753Smm		archive_entry_free(a->entry);
568228753Smm		a->entry = NULL;
569228753Smm	}
570228753Smm	a->entry = archive_entry_clone(entry);
571228753Smm	a->fd = -1;
572228753Smm	a->fd_offset = 0;
573228753Smm	a->offset = 0;
574231200Smm	a->restore_pwd = -1;
575228753Smm	a->uid = a->user_uid;
576228753Smm	a->mode = archive_entry_mode(a->entry);
577228753Smm	if (archive_entry_size_is_set(a->entry))
578228753Smm		a->filesize = archive_entry_size(a->entry);
579228753Smm	else
580228753Smm		a->filesize = -1;
581228753Smm	archive_strcpy(&(a->_name_data), archive_entry_pathname(a->entry));
582228753Smm	a->name = a->_name_data.s;
583228753Smm	archive_clear_error(&a->archive);
584228753Smm
585228753Smm	/*
586228753Smm	 * Clean up the requested path.  This is necessary for correct
587228753Smm	 * dir restores; the dir restore logic otherwise gets messed
588228753Smm	 * up by nonsense like "dir/.".
589228753Smm	 */
590228753Smm	ret = cleanup_pathname(a);
591228753Smm	if (ret != ARCHIVE_OK)
592228753Smm		return (ret);
593228753Smm
594228753Smm	/*
595368708Smm	 * Check if we have a hardlink that points to itself.
596368708Smm	 */
597368708Smm	linkname = archive_entry_hardlink(a->entry);
598368708Smm	if (linkname != NULL && strcmp(a->name, linkname) == 0) {
599368708Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
600368708Smm		    "Skipping hardlink pointing to itself: %s",
601368708Smm		    a->name);
602368708Smm		return (ARCHIVE_WARN);
603368708Smm	}
604368708Smm
605368708Smm	/*
606231200Smm	 * Query the umask so we get predictable mode settings.
607228753Smm	 * This gets done on every call to _write_header in case the
608228753Smm	 * user edits their umask during the extraction for some
609231200Smm	 * reason.
610228753Smm	 */
611231200Smm	umask(a->user_umask = umask(0));
612228753Smm
613228753Smm	/* Figure out what we need to do for this entry. */
614228753Smm	a->todo = TODO_MODE_BASE;
615228753Smm	if (a->flags & ARCHIVE_EXTRACT_PERM) {
616228753Smm		a->todo |= TODO_MODE_FORCE; /* Be pushy about permissions. */
617228753Smm		/*
618228753Smm		 * SGID requires an extra "check" step because we
619228753Smm		 * cannot easily predict the GID that the system will
620228753Smm		 * assign.  (Different systems assign GIDs to files
621228753Smm		 * based on a variety of criteria, including process
622228753Smm		 * credentials and the gid of the enclosing
623228753Smm		 * directory.)  We can only restore the SGID bit if
624228753Smm		 * the file has the right GID, and we only know the
625228753Smm		 * GID if we either set it (see set_ownership) or if
626228753Smm		 * we've actually called stat() on the file after it
627228753Smm		 * was restored.  Since there are several places at
628228753Smm		 * which we might verify the GID, we need a TODO bit
629228753Smm		 * to keep track.
630228753Smm		 */
631228753Smm		if (a->mode & S_ISGID)
632228753Smm			a->todo |= TODO_SGID | TODO_SGID_CHECK;
633228753Smm		/*
634228753Smm		 * Verifying the SUID is simpler, but can still be
635228753Smm		 * done in multiple ways, hence the separate "check" bit.
636228753Smm		 */
637228753Smm		if (a->mode & S_ISUID)
638228753Smm			a->todo |= TODO_SUID | TODO_SUID_CHECK;
639228753Smm	} else {
640228753Smm		/*
641228753Smm		 * User didn't request full permissions, so don't
642228753Smm		 * restore SUID, SGID bits and obey umask.
643228753Smm		 */
644228753Smm		a->mode &= ~S_ISUID;
645228753Smm		a->mode &= ~S_ISGID;
646228753Smm		a->mode &= ~S_ISVTX;
647228753Smm		a->mode &= ~a->user_umask;
648228753Smm	}
649228753Smm	if (a->flags & ARCHIVE_EXTRACT_OWNER)
650228753Smm		a->todo |= TODO_OWNER;
651228753Smm	if (a->flags & ARCHIVE_EXTRACT_TIME)
652228753Smm		a->todo |= TODO_TIMES;
653231200Smm	if (a->flags & ARCHIVE_EXTRACT_ACL) {
654316338Smm#if ARCHIVE_ACL_DARWIN
655316338Smm		/*
656316338Smm		 * On MacOS, platform ACLs get stored in mac_metadata, too.
657316338Smm		 * If we intend to extract mac_metadata and it is present
658316338Smm		 * we skip extracting libarchive NFSv4 ACLs.
659316338Smm		 */
660316338Smm		size_t metadata_size;
661316338Smm
662316338Smm		if ((a->flags & ARCHIVE_EXTRACT_MAC_METADATA) == 0 ||
663316338Smm		    archive_entry_mac_metadata(a->entry,
664316338Smm		    &metadata_size) == NULL || metadata_size == 0)
665316338Smm#endif
666316338Smm#if ARCHIVE_ACL_LIBRICHACL
667316338Smm		/*
668316338Smm		 * RichACLs are stored in an extended attribute.
669316338Smm		 * If we intend to extract extended attributes and have this
670316338Smm		 * attribute we skip extracting libarchive NFSv4 ACLs.
671316338Smm		 */
672316338Smm		short extract_acls = 1;
673316338Smm		if (a->flags & ARCHIVE_EXTRACT_XATTR && (
674316338Smm		    archive_entry_acl_types(a->entry) &
675316338Smm		    ARCHIVE_ENTRY_ACL_TYPE_NFS4)) {
676316338Smm			const char *attr_name;
677316338Smm			const void *attr_value;
678316338Smm			size_t attr_size;
679316338Smm			int i = archive_entry_xattr_reset(a->entry);
680316338Smm			while (i--) {
681316338Smm				archive_entry_xattr_next(a->entry, &attr_name,
682316338Smm				    &attr_value, &attr_size);
683316338Smm				if (attr_name != NULL && attr_value != NULL &&
684316338Smm				    attr_size > 0 && strcmp(attr_name,
685316338Smm				    "trusted.richacl") == 0) {
686316338Smm					extract_acls = 0;
687316338Smm					break;
688316338Smm				}
689316338Smm			}
690316338Smm		}
691316338Smm		if (extract_acls)
692316338Smm#endif
693316338Smm#if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL
694316338Smm		{
695316338Smm#endif
696231200Smm		if (archive_entry_filetype(a->entry) == AE_IFDIR)
697231200Smm			a->deferred |= TODO_ACLS;
698231200Smm		else
699231200Smm			a->todo |= TODO_ACLS;
700316338Smm#if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL
701316338Smm		}
702316338Smm#endif
703231200Smm	}
704231200Smm	if (a->flags & ARCHIVE_EXTRACT_MAC_METADATA) {
705231200Smm		if (archive_entry_filetype(a->entry) == AE_IFDIR)
706231200Smm			a->deferred |= TODO_MAC_METADATA;
707231200Smm		else
708231200Smm			a->todo |= TODO_MAC_METADATA;
709231200Smm	}
710248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H)
711248616Smm	if ((a->flags & ARCHIVE_EXTRACT_NO_HFS_COMPRESSION) == 0) {
712248616Smm		unsigned long set, clear;
713248616Smm		archive_entry_fflags(a->entry, &set, &clear);
714248616Smm		if ((set & ~clear) & UF_COMPRESSED) {
715248616Smm			a->todo |= TODO_HFS_COMPRESSION;
716248616Smm			a->decmpfs_block_count = (unsigned)-1;
717248616Smm		}
718248616Smm	}
719248616Smm	if ((a->flags & ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED) != 0 &&
720248616Smm	    (a->mode & AE_IFMT) == AE_IFREG && a->filesize > 0) {
721248616Smm		a->todo |= TODO_HFS_COMPRESSION;
722248616Smm		a->decmpfs_block_count = (unsigned)-1;
723248616Smm	}
724248616Smm	{
725248616Smm		const char *p;
726248616Smm
727248616Smm		/* Check if the current file name is a type of the
728248616Smm		 * resource fork file. */
729248616Smm		p = strrchr(a->name, '/');
730248616Smm		if (p == NULL)
731248616Smm			p = a->name;
732248616Smm		else
733248616Smm			p++;
734248616Smm		if (p[0] == '.' && p[1] == '_') {
735248616Smm			/* Do not compress "._XXX" files. */
736248616Smm			a->todo &= ~TODO_HFS_COMPRESSION;
737248616Smm			if (a->filesize > 0)
738248616Smm				a->todo |= TODO_APPLEDOUBLE;
739248616Smm		}
740248616Smm	}
741248616Smm#endif
742248616Smm
743316338Smm	if (a->flags & ARCHIVE_EXTRACT_XATTR) {
744316338Smm#if ARCHIVE_XATTR_DARWIN
745316338Smm		/*
746316338Smm		 * On MacOS, extended attributes get stored in mac_metadata,
747316338Smm		 * too. If we intend to extract mac_metadata and it is present
748316338Smm		 * we skip extracting extended attributes.
749316338Smm		 */
750316338Smm		size_t metadata_size;
751316338Smm
752316338Smm		if ((a->flags & ARCHIVE_EXTRACT_MAC_METADATA) == 0 ||
753316338Smm		    archive_entry_mac_metadata(a->entry,
754316338Smm		    &metadata_size) == NULL || metadata_size == 0)
755316338Smm#endif
756228753Smm		a->todo |= TODO_XATTR;
757316338Smm	}
758228753Smm	if (a->flags & ARCHIVE_EXTRACT_FFLAGS)
759228753Smm		a->todo |= TODO_FFLAGS;
760228753Smm	if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) {
761228753Smm		ret = check_symlinks(a);
762228753Smm		if (ret != ARCHIVE_OK)
763231200Smm			return (ret);
764228753Smm	}
765231200Smm#if defined(HAVE_FCHDIR) && defined(PATH_MAX)
766228753Smm	/* If path exceeds PATH_MAX, shorten the path. */
767228753Smm	edit_deep_directories(a);
768228753Smm#endif
769228753Smm
770228753Smm	ret = restore_entry(a);
771228753Smm
772248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H)
773228753Smm	/*
774248616Smm	 * Check if the filesystem the file is restoring on supports
775248616Smm	 * HFS+ Compression. If not, cancel HFS+ Compression.
776248616Smm	 */
777248616Smm	if (a->todo | TODO_HFS_COMPRESSION) {
778248616Smm		/*
779248616Smm		 * NOTE: UF_COMPRESSED is ignored even if the filesystem
780248616Smm		 * supports HFS+ Compression because the file should
781313571Smm		 * have at least an extended attribute "com.apple.decmpfs"
782248616Smm		 * before the flag is set to indicate that the file have
783313571Smm		 * been compressed. If the filesystem does not support
784248616Smm		 * HFS+ Compression the system call will fail.
785248616Smm		 */
786248616Smm		if (a->fd < 0 || fchflags(a->fd, UF_COMPRESSED) != 0)
787248616Smm			a->todo &= ~TODO_HFS_COMPRESSION;
788248616Smm	}
789248616Smm#endif
790248616Smm
791248616Smm	/*
792228753Smm	 * TODO: There are rumours that some extended attributes must
793228753Smm	 * be restored before file data is written.  If this is true,
794228753Smm	 * then we either need to write all extended attributes both
795228753Smm	 * before and after restoring the data, or find some rule for
796228753Smm	 * determining which must go first and which last.  Due to the
797228753Smm	 * many ways people are using xattrs, this may prove to be an
798228753Smm	 * intractable problem.
799228753Smm	 */
800228753Smm
801228753Smm#ifdef HAVE_FCHDIR
802228753Smm	/* If we changed directory above, restore it here. */
803228753Smm	if (a->restore_pwd >= 0) {
804228753Smm		r = fchdir(a->restore_pwd);
805228753Smm		if (r != 0) {
806309702Smm			archive_set_error(&a->archive, errno,
807309702Smm			    "chdir() failure");
808228753Smm			ret = ARCHIVE_FATAL;
809228753Smm		}
810228753Smm		close(a->restore_pwd);
811228753Smm		a->restore_pwd = -1;
812228753Smm	}
813228753Smm#endif
814228753Smm
815228753Smm	/*
816228753Smm	 * Fixup uses the unedited pathname from archive_entry_pathname(),
817228753Smm	 * because it is relative to the base dir and the edited path
818228753Smm	 * might be relative to some intermediate dir as a result of the
819228753Smm	 * deep restore logic.
820228753Smm	 */
821228753Smm	if (a->deferred & TODO_MODE) {
822228753Smm		fe = current_fixup(a, archive_entry_pathname(entry));
823248616Smm		if (fe == NULL)
824248616Smm			return (ARCHIVE_FATAL);
825228753Smm		fe->fixup |= TODO_MODE_BASE;
826228753Smm		fe->mode = a->mode;
827228753Smm	}
828228753Smm
829228753Smm	if ((a->deferred & TODO_TIMES)
830228753Smm		&& (archive_entry_mtime_is_set(entry)
831228753Smm		    || archive_entry_atime_is_set(entry))) {
832228753Smm		fe = current_fixup(a, archive_entry_pathname(entry));
833248616Smm		if (fe == NULL)
834248616Smm			return (ARCHIVE_FATAL);
835231200Smm		fe->mode = a->mode;
836228753Smm		fe->fixup |= TODO_TIMES;
837228753Smm		if (archive_entry_atime_is_set(entry)) {
838228753Smm			fe->atime = archive_entry_atime(entry);
839228753Smm			fe->atime_nanos = archive_entry_atime_nsec(entry);
840228753Smm		} else {
841228753Smm			/* If atime is unset, use start time. */
842228753Smm			fe->atime = a->start_time;
843228753Smm			fe->atime_nanos = 0;
844228753Smm		}
845228753Smm		if (archive_entry_mtime_is_set(entry)) {
846228753Smm			fe->mtime = archive_entry_mtime(entry);
847228753Smm			fe->mtime_nanos = archive_entry_mtime_nsec(entry);
848228753Smm		} else {
849228753Smm			/* If mtime is unset, use start time. */
850228753Smm			fe->mtime = a->start_time;
851228753Smm			fe->mtime_nanos = 0;
852228753Smm		}
853228753Smm		if (archive_entry_birthtime_is_set(entry)) {
854228753Smm			fe->birthtime = archive_entry_birthtime(entry);
855309702Smm			fe->birthtime_nanos = archive_entry_birthtime_nsec(
856309702Smm			    entry);
857228753Smm		} else {
858228753Smm			/* If birthtime is unset, use mtime. */
859228753Smm			fe->birthtime = fe->mtime;
860228753Smm			fe->birthtime_nanos = fe->mtime_nanos;
861228753Smm		}
862228753Smm	}
863228753Smm
864231200Smm	if (a->deferred & TODO_ACLS) {
865231200Smm		fe = current_fixup(a, archive_entry_pathname(entry));
866248616Smm		if (fe == NULL)
867248616Smm			return (ARCHIVE_FATAL);
868238909Smm		fe->fixup |= TODO_ACLS;
869231200Smm		archive_acl_copy(&fe->acl, archive_entry_acl(entry));
870231200Smm	}
871231200Smm
872231200Smm	if (a->deferred & TODO_MAC_METADATA) {
873231200Smm		const void *metadata;
874231200Smm		size_t metadata_size;
875231200Smm		metadata = archive_entry_mac_metadata(a->entry, &metadata_size);
876231200Smm		if (metadata != NULL && metadata_size > 0) {
877231200Smm			fe = current_fixup(a, archive_entry_pathname(entry));
878248616Smm			if (fe == NULL)
879248616Smm				return (ARCHIVE_FATAL);
880231200Smm			fe->mac_metadata = malloc(metadata_size);
881231200Smm			if (fe->mac_metadata != NULL) {
882309702Smm				memcpy(fe->mac_metadata, metadata,
883309702Smm				    metadata_size);
884231200Smm				fe->mac_metadata_size = metadata_size;
885231200Smm				fe->fixup |= TODO_MAC_METADATA;
886231200Smm			}
887231200Smm		}
888231200Smm	}
889231200Smm
890228753Smm	if (a->deferred & TODO_FFLAGS) {
891228753Smm		fe = current_fixup(a, archive_entry_pathname(entry));
892248616Smm		if (fe == NULL)
893248616Smm			return (ARCHIVE_FATAL);
894228753Smm		fe->fixup |= TODO_FFLAGS;
895228753Smm		/* TODO: Complete this.. defer fflags from below. */
896228753Smm	}
897228753Smm
898228753Smm	/* We've created the object and are ready to pour data into it. */
899228753Smm	if (ret >= ARCHIVE_WARN)
900228753Smm		a->archive.state = ARCHIVE_STATE_DATA;
901228753Smm	/*
902228753Smm	 * If it's not open, tell our client not to try writing.
903228753Smm	 * In particular, dirs, links, etc, don't get written to.
904228753Smm	 */
905228753Smm	if (a->fd < 0) {
906228753Smm		archive_entry_set_size(entry, 0);
907228753Smm		a->filesize = 0;
908228753Smm	}
909228753Smm
910228753Smm	return (ret);
911228753Smm}
912228753Smm
913228753Smmint
914328828Smmarchive_write_disk_set_skip_file(struct archive *_a, la_int64_t d, la_int64_t i)
915228753Smm{
916228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
917231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
918228753Smm	    ARCHIVE_STATE_ANY, "archive_write_disk_set_skip_file");
919231200Smm	a->skip_file_set = 1;
920228753Smm	a->skip_file_dev = d;
921228753Smm	a->skip_file_ino = i;
922228753Smm	return (ARCHIVE_OK);
923228753Smm}
924228753Smm
925228753Smmstatic ssize_t
926228753Smmwrite_data_block(struct archive_write_disk *a, const char *buff, size_t size)
927228753Smm{
928228753Smm	uint64_t start_size = size;
929228753Smm	ssize_t bytes_written = 0;
930228753Smm	ssize_t block_size = 0, bytes_to_write;
931228753Smm
932228753Smm	if (size == 0)
933228753Smm		return (ARCHIVE_OK);
934228753Smm
935228753Smm	if (a->filesize == 0 || a->fd < 0) {
936228753Smm		archive_set_error(&a->archive, 0,
937228753Smm		    "Attempt to write to an empty file");
938228753Smm		return (ARCHIVE_WARN);
939228753Smm	}
940228753Smm
941228753Smm	if (a->flags & ARCHIVE_EXTRACT_SPARSE) {
942228753Smm#if HAVE_STRUCT_STAT_ST_BLKSIZE
943228753Smm		int r;
944231200Smm		if ((r = lazy_stat(a)) != ARCHIVE_OK)
945228753Smm			return (r);
946228753Smm		block_size = a->pst->st_blksize;
947228753Smm#else
948228753Smm		/* XXX TODO XXX Is there a more appropriate choice here ? */
949228753Smm		/* This needn't match the filesystem allocation size. */
950228753Smm		block_size = 16*1024;
951228753Smm#endif
952228753Smm	}
953228753Smm
954228753Smm	/* If this write would run beyond the file size, truncate it. */
955231200Smm	if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize)
956228753Smm		start_size = size = (size_t)(a->filesize - a->offset);
957228753Smm
958228753Smm	/* Write the data. */
959228753Smm	while (size > 0) {
960228753Smm		if (block_size == 0) {
961228753Smm			bytes_to_write = size;
962228753Smm		} else {
963228753Smm			/* We're sparsifying the file. */
964228753Smm			const char *p, *end;
965231200Smm			int64_t block_end;
966228753Smm
967228753Smm			/* Skip leading zero bytes. */
968228753Smm			for (p = buff, end = buff + size; p < end; ++p) {
969228753Smm				if (*p != '\0')
970228753Smm					break;
971228753Smm			}
972228753Smm			a->offset += p - buff;
973228753Smm			size -= p - buff;
974228753Smm			buff = p;
975228753Smm			if (size == 0)
976228753Smm				break;
977228753Smm
978228753Smm			/* Calculate next block boundary after offset. */
979228753Smm			block_end
980228753Smm			    = (a->offset / block_size + 1) * block_size;
981228753Smm
982228753Smm			/* If the adjusted write would cross block boundary,
983228753Smm			 * truncate it to the block boundary. */
984228753Smm			bytes_to_write = size;
985228753Smm			if (a->offset + bytes_to_write > block_end)
986228753Smm				bytes_to_write = block_end - a->offset;
987228753Smm		}
988228753Smm		/* Seek if necessary to the specified offset. */
989228753Smm		if (a->offset != a->fd_offset) {
990228753Smm			if (lseek(a->fd, a->offset, SEEK_SET) < 0) {
991228753Smm				archive_set_error(&a->archive, errno,
992228753Smm				    "Seek failed");
993228753Smm				return (ARCHIVE_FATAL);
994228753Smm			}
995228753Smm			a->fd_offset = a->offset;
996231200Smm		}
997228753Smm		bytes_written = write(a->fd, buff, bytes_to_write);
998228753Smm		if (bytes_written < 0) {
999228753Smm			archive_set_error(&a->archive, errno, "Write failed");
1000228753Smm			return (ARCHIVE_WARN);
1001228753Smm		}
1002228753Smm		buff += bytes_written;
1003228753Smm		size -= bytes_written;
1004231200Smm		a->total_bytes_written += bytes_written;
1005228753Smm		a->offset += bytes_written;
1006228753Smm		a->fd_offset = a->offset;
1007228753Smm	}
1008228753Smm	return (start_size - size);
1009228753Smm}
1010228753Smm
1011248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\
1012248616Smm	&& defined(HAVE_ZLIB_H)
1013248616Smm
1014248616Smm/*
1015248616Smm * Set UF_COMPRESSED file flag.
1016248616Smm * This have to be called after hfs_write_decmpfs() because if the
1017248616Smm * file does not have "com.apple.decmpfs" xattr the flag is ignored.
1018248616Smm */
1019248616Smmstatic int
1020248616Smmhfs_set_compressed_fflag(struct archive_write_disk *a)
1021248616Smm{
1022248616Smm	int r;
1023248616Smm
1024248616Smm	if ((r = lazy_stat(a)) != ARCHIVE_OK)
1025248616Smm		return (r);
1026248616Smm
1027248616Smm	a->st.st_flags |= UF_COMPRESSED;
1028248616Smm	if (fchflags(a->fd, a->st.st_flags) != 0) {
1029248616Smm		archive_set_error(&a->archive, errno,
1030248616Smm		    "Failed to set UF_COMPRESSED file flag");
1031248616Smm		return (ARCHIVE_WARN);
1032248616Smm	}
1033248616Smm	return (ARCHIVE_OK);
1034248616Smm}
1035248616Smm
1036248616Smm/*
1037248616Smm * HFS+ Compression decmpfs
1038248616Smm *
1039248616Smm *     +------------------------------+ +0
1040248616Smm *     |      Magic(LE 4 bytes)       |
1041248616Smm *     +------------------------------+
1042248616Smm *     |      Type(LE 4 bytes)        |
1043248616Smm *     +------------------------------+
1044248616Smm *     | Uncompressed size(LE 8 bytes)|
1045248616Smm *     +------------------------------+ +16
1046248616Smm *     |                              |
1047248616Smm *     |       Compressed data        |
1048248616Smm *     |  (Placed only if Type == 3)  |
1049248616Smm *     |                              |
1050248616Smm *     +------------------------------+  +3802 = MAX_DECMPFS_XATTR_SIZE
1051248616Smm *
1052248616Smm *  Type is 3: decmpfs has compressed data.
1053248616Smm *  Type is 4: Resource Fork has compressed data.
1054248616Smm */
1055248616Smm/*
1056248616Smm * Write "com.apple.decmpfs"
1057248616Smm */
1058248616Smmstatic int
1059248616Smmhfs_write_decmpfs(struct archive_write_disk *a)
1060248616Smm{
1061248616Smm	int r;
1062248616Smm	uint32_t compression_type;
1063248616Smm
1064248616Smm	r = fsetxattr(a->fd, DECMPFS_XATTR_NAME, a->decmpfs_header_p,
1065248616Smm	    a->decmpfs_attr_size, 0, 0);
1066248616Smm	if (r < 0) {
1067248616Smm		archive_set_error(&a->archive, errno,
1068248616Smm		    "Cannot restore xattr:%s", DECMPFS_XATTR_NAME);
1069248616Smm		compression_type = archive_le32dec(
1070248616Smm		    &a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE]);
1071248616Smm		if (compression_type == CMP_RESOURCE_FORK)
1072248616Smm			fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME,
1073248616Smm			    XATTR_SHOWCOMPRESSION);
1074248616Smm		return (ARCHIVE_WARN);
1075248616Smm	}
1076248616Smm	return (ARCHIVE_OK);
1077248616Smm}
1078248616Smm
1079248616Smm/*
1080248616Smm * HFS+ Compression Resource Fork
1081248616Smm *
1082248616Smm *     +-----------------------------+
1083248616Smm *     |     Header(260 bytes)       |
1084248616Smm *     +-----------------------------+
1085248616Smm *     |   Block count(LE 4 bytes)   |
1086248616Smm *     +-----------------------------+  --+
1087248616Smm * +-- |     Offset (LE 4 bytes)     |    |
1088248616Smm * |   | [distance from Block count] |    | Block 0
1089248616Smm * |   +-----------------------------+    |
1090248616Smm * |   | Compressed size(LE 4 bytes) |    |
1091248616Smm * |   +-----------------------------+  --+
1092248616Smm * |   |                             |
1093248616Smm * |   |      ..................     |
1094248616Smm * |   |                             |
1095248616Smm * |   +-----------------------------+  --+
1096248616Smm * |   |     Offset (LE 4 bytes)     |    |
1097248616Smm * |   +-----------------------------+    | Block (Block count -1)
1098248616Smm * |   | Compressed size(LE 4 bytes) |    |
1099248616Smm * +-> +-----------------------------+  --+
1100248616Smm *     |   Compressed data(n bytes)  |  Block 0
1101248616Smm *     +-----------------------------+
1102248616Smm *     |                             |
1103248616Smm *     |      ..................     |
1104248616Smm *     |                             |
1105248616Smm *     +-----------------------------+
1106248616Smm *     |   Compressed data(n bytes)  |  Block (Block count -1)
1107248616Smm *     +-----------------------------+
1108248616Smm *     |      Footer(50 bytes)       |
1109248616Smm *     +-----------------------------+
1110248616Smm *
1111248616Smm */
1112248616Smm/*
1113248616Smm * Write the header of "com.apple.ResourceFork"
1114248616Smm */
1115248616Smmstatic int
1116248616Smmhfs_write_resource_fork(struct archive_write_disk *a, unsigned char *buff,
1117248616Smm    size_t bytes, uint32_t position)
1118248616Smm{
1119248616Smm	int ret;
1120248616Smm
1121248616Smm	ret = fsetxattr(a->fd, XATTR_RESOURCEFORK_NAME, buff, bytes,
1122248616Smm	    position, a->rsrc_xattr_options);
1123248616Smm	if (ret < 0) {
1124248616Smm		archive_set_error(&a->archive, errno,
1125248616Smm		    "Cannot restore xattr: %s at %u pos %u bytes",
1126248616Smm		    XATTR_RESOURCEFORK_NAME,
1127248616Smm		    (unsigned)position,
1128248616Smm		    (unsigned)bytes);
1129248616Smm		return (ARCHIVE_WARN);
1130248616Smm	}
1131248616Smm	a->rsrc_xattr_options &= ~XATTR_CREATE;
1132248616Smm	return (ARCHIVE_OK);
1133248616Smm}
1134248616Smm
1135248616Smmstatic int
1136248616Smmhfs_write_compressed_data(struct archive_write_disk *a, size_t bytes_compressed)
1137248616Smm{
1138248616Smm	int ret;
1139248616Smm
1140248616Smm	ret = hfs_write_resource_fork(a, a->compressed_buffer,
1141248616Smm	    bytes_compressed, a->compressed_rsrc_position);
1142248616Smm	if (ret == ARCHIVE_OK)
1143248616Smm		a->compressed_rsrc_position += bytes_compressed;
1144248616Smm	return (ret);
1145248616Smm}
1146248616Smm
1147248616Smmstatic int
1148248616Smmhfs_write_resource_fork_header(struct archive_write_disk *a)
1149248616Smm{
1150248616Smm	unsigned char *buff;
1151248616Smm	uint32_t rsrc_bytes;
1152248616Smm	uint32_t rsrc_header_bytes;
1153248616Smm
1154248616Smm	/*
1155248616Smm	 * Write resource fork header + block info.
1156248616Smm	 */
1157248616Smm	buff = a->resource_fork;
1158248616Smm	rsrc_bytes = a->compressed_rsrc_position - RSRC_F_SIZE;
1159248616Smm	rsrc_header_bytes =
1160248616Smm		RSRC_H_SIZE +		/* Header base size. */
1161248616Smm		4 +			/* Block count. */
1162248616Smm		(a->decmpfs_block_count * 8);/* Block info */
1163248616Smm	archive_be32enc(buff, 0x100);
1164248616Smm	archive_be32enc(buff + 4, rsrc_bytes);
1165248616Smm	archive_be32enc(buff + 8, rsrc_bytes - 256);
1166248616Smm	archive_be32enc(buff + 12, 0x32);
1167248616Smm	memset(buff + 16, 0, 240);
1168248616Smm	archive_be32enc(buff + 256, rsrc_bytes - 260);
1169248616Smm	return hfs_write_resource_fork(a, buff, rsrc_header_bytes, 0);
1170248616Smm}
1171248616Smm
1172248616Smmstatic size_t
1173248616Smmhfs_set_resource_fork_footer(unsigned char *buff, size_t buff_size)
1174248616Smm{
1175248616Smm	static const char rsrc_footer[RSRC_F_SIZE] = {
1176248616Smm		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1177248616Smm		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1178248616Smm		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1179248616Smm		0x00, 0x1c, 0x00, 0x32, 0x00, 0x00, 'c',  'm',
1180248616Smm		'p', 'f',   0x00, 0x00, 0x00, 0x0a, 0x00, 0x01,
1181248616Smm		0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1182248616Smm		0x00, 0x00
1183248616Smm	};
1184248616Smm	if (buff_size < sizeof(rsrc_footer))
1185248616Smm		return (0);
1186248616Smm	memcpy(buff, rsrc_footer, sizeof(rsrc_footer));
1187248616Smm	return (sizeof(rsrc_footer));
1188248616Smm}
1189248616Smm
1190248616Smmstatic int
1191248616Smmhfs_reset_compressor(struct archive_write_disk *a)
1192248616Smm{
1193248616Smm	int ret;
1194248616Smm
1195248616Smm	if (a->stream_valid)
1196248616Smm		ret = deflateReset(&a->stream);
1197248616Smm	else
1198248616Smm		ret = deflateInit(&a->stream, a->decmpfs_compression_level);
1199248616Smm
1200248616Smm	if (ret != Z_OK) {
1201248616Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1202248616Smm		    "Failed to initialize compressor");
1203248616Smm		return (ARCHIVE_FATAL);
1204248616Smm	} else
1205248616Smm		a->stream_valid = 1;
1206248616Smm
1207248616Smm	return (ARCHIVE_OK);
1208248616Smm}
1209248616Smm
1210248616Smmstatic int
1211248616Smmhfs_decompress(struct archive_write_disk *a)
1212248616Smm{
1213248616Smm	uint32_t *block_info;
1214248616Smm	unsigned int block_count;
1215248616Smm	uint32_t data_pos, data_size;
1216248616Smm	ssize_t r;
1217248616Smm	ssize_t bytes_written, bytes_to_write;
1218248616Smm	unsigned char *b;
1219248616Smm
1220248616Smm	block_info = (uint32_t *)(a->resource_fork + RSRC_H_SIZE);
1221248616Smm	block_count = archive_le32dec(block_info++);
1222248616Smm	while (block_count--) {
1223248616Smm		data_pos = RSRC_H_SIZE + archive_le32dec(block_info++);
1224248616Smm		data_size = archive_le32dec(block_info++);
1225248616Smm		r = fgetxattr(a->fd, XATTR_RESOURCEFORK_NAME,
1226248616Smm		    a->compressed_buffer, data_size, data_pos, 0);
1227248616Smm		if (r != data_size)  {
1228248616Smm			archive_set_error(&a->archive,
1229248616Smm			    (r < 0)?errno:ARCHIVE_ERRNO_MISC,
1230248616Smm			    "Failed to read resource fork");
1231248616Smm			return (ARCHIVE_WARN);
1232248616Smm		}
1233248616Smm		if (a->compressed_buffer[0] == 0xff) {
1234248616Smm			bytes_to_write = data_size -1;
1235248616Smm			b = a->compressed_buffer + 1;
1236248616Smm		} else {
1237248616Smm			uLong dest_len = MAX_DECMPFS_BLOCK_SIZE;
1238248616Smm			int zr;
1239248616Smm
1240248616Smm			zr = uncompress((Bytef *)a->uncompressed_buffer,
1241248616Smm			    &dest_len, a->compressed_buffer, data_size);
1242248616Smm			if (zr != Z_OK) {
1243248616Smm				archive_set_error(&a->archive,
1244248616Smm				    ARCHIVE_ERRNO_MISC,
1245248616Smm				    "Failed to decompress resource fork");
1246248616Smm				return (ARCHIVE_WARN);
1247248616Smm			}
1248248616Smm			bytes_to_write = dest_len;
1249248616Smm			b = (unsigned char *)a->uncompressed_buffer;
1250248616Smm		}
1251248616Smm		do {
1252248616Smm			bytes_written = write(a->fd, b, bytes_to_write);
1253248616Smm			if (bytes_written < 0) {
1254248616Smm				archive_set_error(&a->archive, errno,
1255248616Smm				    "Write failed");
1256248616Smm				return (ARCHIVE_WARN);
1257248616Smm			}
1258248616Smm			bytes_to_write -= bytes_written;
1259248616Smm			b += bytes_written;
1260248616Smm		} while (bytes_to_write > 0);
1261248616Smm	}
1262248616Smm	r = fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME, 0);
1263248616Smm	if (r == -1)  {
1264248616Smm		archive_set_error(&a->archive, errno,
1265248616Smm		    "Failed to remove resource fork");
1266248616Smm		return (ARCHIVE_WARN);
1267248616Smm	}
1268248616Smm	return (ARCHIVE_OK);
1269248616Smm}
1270248616Smm
1271248616Smmstatic int
1272248616Smmhfs_drive_compressor(struct archive_write_disk *a, const char *buff,
1273248616Smm    size_t size)
1274248616Smm{
1275248616Smm	unsigned char *buffer_compressed;
1276248616Smm	size_t bytes_compressed;
1277248616Smm	size_t bytes_used;
1278248616Smm	int ret;
1279248616Smm
1280248616Smm	ret = hfs_reset_compressor(a);
1281248616Smm	if (ret != ARCHIVE_OK)
1282248616Smm		return (ret);
1283248616Smm
1284248616Smm	if (a->compressed_buffer == NULL) {
1285248616Smm		size_t block_size;
1286248616Smm
1287248616Smm		block_size = COMPRESSED_W_SIZE + RSRC_F_SIZE +
1288248616Smm		    + compressBound(MAX_DECMPFS_BLOCK_SIZE);
1289248616Smm		a->compressed_buffer = malloc(block_size);
1290248616Smm		if (a->compressed_buffer == NULL) {
1291248616Smm			archive_set_error(&a->archive, ENOMEM,
1292248616Smm			    "Can't allocate memory for Resource Fork");
1293248616Smm			return (ARCHIVE_FATAL);
1294248616Smm		}
1295248616Smm		a->compressed_buffer_size = block_size;
1296248616Smm		a->compressed_buffer_remaining = block_size;
1297248616Smm	}
1298248616Smm
1299248616Smm	buffer_compressed = a->compressed_buffer +
1300248616Smm	    a->compressed_buffer_size - a->compressed_buffer_remaining;
1301248616Smm	a->stream.next_in = (Bytef *)(uintptr_t)(const void *)buff;
1302248616Smm	a->stream.avail_in = size;
1303248616Smm	a->stream.next_out = buffer_compressed;
1304248616Smm	a->stream.avail_out = a->compressed_buffer_remaining;
1305248616Smm	do {
1306248616Smm		ret = deflate(&a->stream, Z_FINISH);
1307248616Smm		switch (ret) {
1308248616Smm		case Z_OK:
1309248616Smm		case Z_STREAM_END:
1310248616Smm			break;
1311248616Smm		default:
1312248616Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1313248616Smm			    "Failed to compress data");
1314248616Smm			return (ARCHIVE_FAILED);
1315248616Smm		}
1316248616Smm	} while (ret == Z_OK);
1317248616Smm	bytes_compressed = a->compressed_buffer_remaining - a->stream.avail_out;
1318248616Smm
1319248616Smm	/*
1320248616Smm	 * If the compressed size is larger than the original size,
1321248616Smm	 * throw away compressed data, use uncompressed data instead.
1322248616Smm	 */
1323248616Smm	if (bytes_compressed > size) {
1324248616Smm		buffer_compressed[0] = 0xFF;/* uncompressed marker. */
1325248616Smm		memcpy(buffer_compressed + 1, buff, size);
1326248616Smm		bytes_compressed = size + 1;
1327248616Smm	}
1328248616Smm	a->compressed_buffer_remaining -= bytes_compressed;
1329248616Smm
1330248616Smm	/*
1331248616Smm	 * If the compressed size is smaller than MAX_DECMPFS_XATTR_SIZE
1332248616Smm	 * and the block count in the file is only one, store compressed
1333248616Smm	 * data to decmpfs xattr instead of the resource fork.
1334248616Smm	 */
1335248616Smm	if (a->decmpfs_block_count == 1 &&
1336248616Smm	    (a->decmpfs_attr_size + bytes_compressed)
1337248616Smm	      <= MAX_DECMPFS_XATTR_SIZE) {
1338248616Smm		archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE],
1339248616Smm		    CMP_XATTR);
1340248616Smm		memcpy(a->decmpfs_header_p + DECMPFS_HEADER_SIZE,
1341248616Smm		    buffer_compressed, bytes_compressed);
1342248616Smm		a->decmpfs_attr_size += bytes_compressed;
1343248616Smm		a->compressed_buffer_remaining = a->compressed_buffer_size;
1344248616Smm		/*
1345248616Smm		 * Finish HFS+ Compression.
1346248616Smm		 * - Write the decmpfs xattr.
1347248616Smm		 * - Set the UF_COMPRESSED file flag.
1348248616Smm		 */
1349248616Smm		ret = hfs_write_decmpfs(a);
1350248616Smm		if (ret == ARCHIVE_OK)
1351248616Smm			ret = hfs_set_compressed_fflag(a);
1352248616Smm		return (ret);
1353248616Smm	}
1354248616Smm
1355248616Smm	/* Update block info. */
1356248616Smm	archive_le32enc(a->decmpfs_block_info++,
1357248616Smm	    a->compressed_rsrc_position_v - RSRC_H_SIZE);
1358248616Smm	archive_le32enc(a->decmpfs_block_info++, bytes_compressed);
1359248616Smm	a->compressed_rsrc_position_v += bytes_compressed;
1360248616Smm
1361248616Smm	/*
1362248616Smm	 * Write the compressed data to the resource fork.
1363248616Smm	 */
1364248616Smm	bytes_used = a->compressed_buffer_size - a->compressed_buffer_remaining;
1365248616Smm	while (bytes_used >= COMPRESSED_W_SIZE) {
1366248616Smm		ret = hfs_write_compressed_data(a, COMPRESSED_W_SIZE);
1367248616Smm		if (ret != ARCHIVE_OK)
1368248616Smm			return (ret);
1369248616Smm		bytes_used -= COMPRESSED_W_SIZE;
1370248616Smm		if (bytes_used > COMPRESSED_W_SIZE)
1371248616Smm			memmove(a->compressed_buffer,
1372248616Smm			    a->compressed_buffer + COMPRESSED_W_SIZE,
1373248616Smm			    bytes_used);
1374248616Smm		else
1375248616Smm			memcpy(a->compressed_buffer,
1376248616Smm			    a->compressed_buffer + COMPRESSED_W_SIZE,
1377248616Smm			    bytes_used);
1378248616Smm	}
1379248616Smm	a->compressed_buffer_remaining = a->compressed_buffer_size - bytes_used;
1380248616Smm
1381248616Smm	/*
1382248616Smm	 * If the current block is the last block, write the remaining
1383248616Smm	 * compressed data and the resource fork footer.
1384248616Smm	 */
1385248616Smm	if (a->file_remaining_bytes == 0) {
1386248616Smm		size_t rsrc_size;
1387248616Smm		int64_t bk;
1388248616Smm
1389248616Smm		/* Append the resource footer. */
1390248616Smm		rsrc_size = hfs_set_resource_fork_footer(
1391248616Smm		    a->compressed_buffer + bytes_used,
1392248616Smm		    a->compressed_buffer_remaining);
1393248616Smm		ret = hfs_write_compressed_data(a, bytes_used + rsrc_size);
1394248616Smm		a->compressed_buffer_remaining = a->compressed_buffer_size;
1395248616Smm
1396313571Smm		/* If the compressed size is not enough smaller than
1397248616Smm		 * the uncompressed size. cancel HFS+ compression.
1398248616Smm		 * TODO: study a behavior of ditto utility and improve
1399248616Smm		 * the condition to fall back into no HFS+ compression. */
1400248616Smm		bk = HFS_BLOCKS(a->compressed_rsrc_position);
1401248616Smm		bk += bk >> 7;
1402248616Smm		if (bk > HFS_BLOCKS(a->filesize))
1403248616Smm			return hfs_decompress(a);
1404248616Smm		/*
1405248616Smm		 * Write the resourcefork header.
1406248616Smm		 */
1407248616Smm		if (ret == ARCHIVE_OK)
1408248616Smm			ret = hfs_write_resource_fork_header(a);
1409248616Smm		/*
1410248616Smm		 * Finish HFS+ Compression.
1411248616Smm		 * - Write the decmpfs xattr.
1412248616Smm		 * - Set the UF_COMPRESSED file flag.
1413248616Smm		 */
1414248616Smm		if (ret == ARCHIVE_OK)
1415248616Smm			ret = hfs_write_decmpfs(a);
1416248616Smm		if (ret == ARCHIVE_OK)
1417248616Smm			ret = hfs_set_compressed_fflag(a);
1418248616Smm	}
1419248616Smm	return (ret);
1420248616Smm}
1421248616Smm
1422228753Smmstatic ssize_t
1423248616Smmhfs_write_decmpfs_block(struct archive_write_disk *a, const char *buff,
1424248616Smm    size_t size)
1425248616Smm{
1426248616Smm	const char *buffer_to_write;
1427248616Smm	size_t bytes_to_write;
1428248616Smm	int ret;
1429248616Smm
1430248616Smm	if (a->decmpfs_block_count == (unsigned)-1) {
1431248616Smm		void *new_block;
1432248616Smm		size_t new_size;
1433248616Smm		unsigned int block_count;
1434248616Smm
1435248616Smm		if (a->decmpfs_header_p == NULL) {
1436248616Smm			new_block = malloc(MAX_DECMPFS_XATTR_SIZE
1437248616Smm			    + sizeof(uint32_t));
1438248616Smm			if (new_block == NULL) {
1439248616Smm				archive_set_error(&a->archive, ENOMEM,
1440248616Smm				    "Can't allocate memory for decmpfs");
1441248616Smm				return (ARCHIVE_FATAL);
1442248616Smm			}
1443248616Smm			a->decmpfs_header_p = new_block;
1444248616Smm		}
1445248616Smm		a->decmpfs_attr_size = DECMPFS_HEADER_SIZE;
1446248616Smm		archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_MAGIC],
1447248616Smm		    DECMPFS_MAGIC);
1448248616Smm		archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE],
1449248616Smm		    CMP_RESOURCE_FORK);
1450248616Smm		archive_le64enc(&a->decmpfs_header_p[DECMPFS_UNCOMPRESSED_SIZE],
1451248616Smm		    a->filesize);
1452248616Smm
1453248616Smm		/* Calculate a block count of the file. */
1454248616Smm		block_count =
1455248616Smm		    (a->filesize + MAX_DECMPFS_BLOCK_SIZE -1) /
1456248616Smm			MAX_DECMPFS_BLOCK_SIZE;
1457248616Smm		/*
1458248616Smm		 * Allocate buffer for resource fork.
1459248616Smm		 * Set up related pointers;
1460248616Smm		 */
1461248616Smm		new_size =
1462248616Smm		    RSRC_H_SIZE + /* header */
1463248616Smm		    4 + /* Block count */
1464248616Smm		    (block_count * sizeof(uint32_t) * 2) +
1465248616Smm		    RSRC_F_SIZE; /* footer */
1466248616Smm		if (new_size > a->resource_fork_allocated_size) {
1467248616Smm			new_block = realloc(a->resource_fork, new_size);
1468248616Smm			if (new_block == NULL) {
1469248616Smm				archive_set_error(&a->archive, ENOMEM,
1470248616Smm				    "Can't allocate memory for ResourceFork");
1471248616Smm				return (ARCHIVE_FATAL);
1472248616Smm			}
1473248616Smm			a->resource_fork_allocated_size = new_size;
1474248616Smm			a->resource_fork = new_block;
1475248616Smm		}
1476248616Smm
1477248616Smm		/* Allocate uncompressed buffer */
1478248616Smm		if (a->uncompressed_buffer == NULL) {
1479248616Smm			new_block = malloc(MAX_DECMPFS_BLOCK_SIZE);
1480248616Smm			if (new_block == NULL) {
1481248616Smm				archive_set_error(&a->archive, ENOMEM,
1482248616Smm				    "Can't allocate memory for decmpfs");
1483248616Smm				return (ARCHIVE_FATAL);
1484248616Smm			}
1485248616Smm			a->uncompressed_buffer = new_block;
1486248616Smm		}
1487248616Smm		a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE;
1488248616Smm		a->file_remaining_bytes = a->filesize;
1489248616Smm		a->compressed_buffer_remaining = a->compressed_buffer_size;
1490248616Smm
1491248616Smm		/*
1492248616Smm		 * Set up a resource fork.
1493248616Smm		 */
1494248616Smm		a->rsrc_xattr_options = XATTR_CREATE;
1495248616Smm		/* Get the position where we are going to set a bunch
1496248616Smm		 * of block info. */
1497248616Smm		a->decmpfs_block_info =
1498248616Smm		    (uint32_t *)(a->resource_fork + RSRC_H_SIZE);
1499248616Smm		/* Set the block count to the resource fork. */
1500248616Smm		archive_le32enc(a->decmpfs_block_info++, block_count);
1501313571Smm		/* Get the position where we are going to set compressed
1502248616Smm		 * data. */
1503248616Smm		a->compressed_rsrc_position =
1504248616Smm		    RSRC_H_SIZE + 4 + (block_count * 8);
1505248616Smm		a->compressed_rsrc_position_v = a->compressed_rsrc_position;
1506248616Smm		a->decmpfs_block_count = block_count;
1507248616Smm	}
1508248616Smm
1509248616Smm	/* Ignore redundant bytes. */
1510248616Smm	if (a->file_remaining_bytes == 0)
1511248616Smm		return ((ssize_t)size);
1512248616Smm
1513248616Smm	/* Do not overrun a block size. */
1514248616Smm	if (size > a->block_remaining_bytes)
1515248616Smm		bytes_to_write = a->block_remaining_bytes;
1516248616Smm	else
1517248616Smm		bytes_to_write = size;
1518248616Smm	/* Do not overrun the file size. */
1519248616Smm	if (bytes_to_write > a->file_remaining_bytes)
1520248616Smm		bytes_to_write = a->file_remaining_bytes;
1521248616Smm
1522248616Smm	/* For efficiency, if a copy length is full of the uncompressed
1523248616Smm	 * buffer size, do not copy writing data to it. */
1524248616Smm	if (bytes_to_write == MAX_DECMPFS_BLOCK_SIZE)
1525248616Smm		buffer_to_write = buff;
1526248616Smm	else {
1527248616Smm		memcpy(a->uncompressed_buffer +
1528248616Smm		    MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes,
1529248616Smm		    buff, bytes_to_write);
1530248616Smm		buffer_to_write = a->uncompressed_buffer;
1531248616Smm	}
1532248616Smm	a->block_remaining_bytes -= bytes_to_write;
1533248616Smm	a->file_remaining_bytes -= bytes_to_write;
1534248616Smm
1535248616Smm	if (a->block_remaining_bytes == 0 || a->file_remaining_bytes == 0) {
1536248616Smm		ret = hfs_drive_compressor(a, buffer_to_write,
1537248616Smm		    MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes);
1538248616Smm		if (ret < 0)
1539248616Smm			return (ret);
1540248616Smm		a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE;
1541248616Smm	}
1542248616Smm	/* Ignore redundant bytes. */
1543248616Smm	if (a->file_remaining_bytes == 0)
1544248616Smm		return ((ssize_t)size);
1545248616Smm	return (bytes_to_write);
1546248616Smm}
1547248616Smm
1548248616Smmstatic ssize_t
1549248616Smmhfs_write_data_block(struct archive_write_disk *a, const char *buff,
1550248616Smm    size_t size)
1551248616Smm{
1552248616Smm	uint64_t start_size = size;
1553248616Smm	ssize_t bytes_written = 0;
1554248616Smm	ssize_t bytes_to_write;
1555248616Smm
1556248616Smm	if (size == 0)
1557248616Smm		return (ARCHIVE_OK);
1558248616Smm
1559248616Smm	if (a->filesize == 0 || a->fd < 0) {
1560248616Smm		archive_set_error(&a->archive, 0,
1561248616Smm		    "Attempt to write to an empty file");
1562248616Smm		return (ARCHIVE_WARN);
1563248616Smm	}
1564248616Smm
1565248616Smm	/* If this write would run beyond the file size, truncate it. */
1566248616Smm	if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize)
1567248616Smm		start_size = size = (size_t)(a->filesize - a->offset);
1568248616Smm
1569248616Smm	/* Write the data. */
1570248616Smm	while (size > 0) {
1571248616Smm		bytes_to_write = size;
1572248616Smm		/* Seek if necessary to the specified offset. */
1573248616Smm		if (a->offset < a->fd_offset) {
1574313571Smm			/* Can't support backward move. */
1575248616Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1576248616Smm			    "Seek failed");
1577248616Smm			return (ARCHIVE_FATAL);
1578248616Smm		} else if (a->offset > a->fd_offset) {
1579248616Smm			int64_t skip = a->offset - a->fd_offset;
1580248616Smm			char nullblock[1024];
1581248616Smm
1582248616Smm			memset(nullblock, 0, sizeof(nullblock));
1583248616Smm			while (skip > 0) {
1584248616Smm				if (skip > (int64_t)sizeof(nullblock))
1585248616Smm					bytes_written = hfs_write_decmpfs_block(
1586248616Smm					    a, nullblock, sizeof(nullblock));
1587248616Smm				else
1588248616Smm					bytes_written = hfs_write_decmpfs_block(
1589248616Smm					    a, nullblock, skip);
1590248616Smm				if (bytes_written < 0) {
1591248616Smm					archive_set_error(&a->archive, errno,
1592248616Smm					    "Write failed");
1593248616Smm					return (ARCHIVE_WARN);
1594248616Smm				}
1595248616Smm				skip -= bytes_written;
1596248616Smm			}
1597248616Smm
1598248616Smm			a->fd_offset = a->offset;
1599248616Smm		}
1600248616Smm		bytes_written =
1601248616Smm		    hfs_write_decmpfs_block(a, buff, bytes_to_write);
1602248616Smm		if (bytes_written < 0)
1603248616Smm			return (bytes_written);
1604248616Smm		buff += bytes_written;
1605248616Smm		size -= bytes_written;
1606248616Smm		a->total_bytes_written += bytes_written;
1607248616Smm		a->offset += bytes_written;
1608248616Smm		a->fd_offset = a->offset;
1609248616Smm	}
1610248616Smm	return (start_size - size);
1611248616Smm}
1612248616Smm#else
1613248616Smmstatic ssize_t
1614248616Smmhfs_write_data_block(struct archive_write_disk *a, const char *buff,
1615248616Smm    size_t size)
1616248616Smm{
1617248616Smm	return (write_data_block(a, buff, size));
1618248616Smm}
1619248616Smm#endif
1620248616Smm
1621248616Smmstatic ssize_t
1622231200Smm_archive_write_disk_data_block(struct archive *_a,
1623231200Smm    const void *buff, size_t size, int64_t offset)
1624228753Smm{
1625228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
1626228753Smm	ssize_t r;
1627228753Smm
1628231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
1629231200Smm	    ARCHIVE_STATE_DATA, "archive_write_data_block");
1630228753Smm
1631228753Smm	a->offset = offset;
1632248616Smm	if (a->todo & TODO_HFS_COMPRESSION)
1633248616Smm		r = hfs_write_data_block(a, buff, size);
1634248616Smm	else
1635248616Smm		r = write_data_block(a, buff, size);
1636228753Smm	if (r < ARCHIVE_OK)
1637228753Smm		return (r);
1638228753Smm	if ((size_t)r < size) {
1639228753Smm		archive_set_error(&a->archive, 0,
1640309702Smm		    "Too much data: Truncating file at %ju bytes",
1641309702Smm		    (uintmax_t)a->filesize);
1642228753Smm		return (ARCHIVE_WARN);
1643228753Smm	}
1644302001Smm#if ARCHIVE_VERSION_NUMBER < 3999000
1645228753Smm	return (ARCHIVE_OK);
1646302001Smm#else
1647302001Smm	return (size);
1648302001Smm#endif
1649228753Smm}
1650228753Smm
1651228753Smmstatic ssize_t
1652231200Smm_archive_write_disk_data(struct archive *_a, const void *buff, size_t size)
1653228753Smm{
1654228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
1655228753Smm
1656231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
1657228753Smm	    ARCHIVE_STATE_DATA, "archive_write_data");
1658228753Smm
1659248616Smm	if (a->todo & TODO_HFS_COMPRESSION)
1660248616Smm		return (hfs_write_data_block(a, buff, size));
1661228753Smm	return (write_data_block(a, buff, size));
1662228753Smm}
1663228753Smm
1664228753Smmstatic int
1665231200Smm_archive_write_disk_finish_entry(struct archive *_a)
1666228753Smm{
1667228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
1668228753Smm	int ret = ARCHIVE_OK;
1669228753Smm
1670231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
1671228753Smm	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
1672228753Smm	    "archive_write_finish_entry");
1673228753Smm	if (a->archive.state & ARCHIVE_STATE_HEADER)
1674228753Smm		return (ARCHIVE_OK);
1675228753Smm	archive_clear_error(&a->archive);
1676228753Smm
1677228753Smm	/* Pad or truncate file to the right size. */
1678228753Smm	if (a->fd < 0) {
1679228753Smm		/* There's no file. */
1680228753Smm	} else if (a->filesize < 0) {
1681228753Smm		/* File size is unknown, so we can't set the size. */
1682228753Smm	} else if (a->fd_offset == a->filesize) {
1683228753Smm		/* Last write ended at exactly the filesize; we're done. */
1684228753Smm		/* Hopefully, this is the common case. */
1685248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H)
1686248616Smm	} else if (a->todo & TODO_HFS_COMPRESSION) {
1687248616Smm		char null_d[1024];
1688248616Smm		ssize_t r;
1689248616Smm
1690248616Smm		if (a->file_remaining_bytes)
1691248616Smm			memset(null_d, 0, sizeof(null_d));
1692248616Smm		while (a->file_remaining_bytes) {
1693248616Smm			if (a->file_remaining_bytes > sizeof(null_d))
1694248616Smm				r = hfs_write_data_block(
1695248616Smm				    a, null_d, sizeof(null_d));
1696248616Smm			else
1697248616Smm				r = hfs_write_data_block(
1698248616Smm				    a, null_d, a->file_remaining_bytes);
1699248616Smm			if (r < 0)
1700248616Smm				return ((int)r);
1701248616Smm		}
1702248616Smm#endif
1703228753Smm	} else {
1704228753Smm#if HAVE_FTRUNCATE
1705228753Smm		if (ftruncate(a->fd, a->filesize) == -1 &&
1706228753Smm		    a->filesize == 0) {
1707228753Smm			archive_set_error(&a->archive, errno,
1708228753Smm			    "File size could not be restored");
1709228753Smm			return (ARCHIVE_FAILED);
1710228753Smm		}
1711228753Smm#endif
1712228753Smm		/*
1713228753Smm		 * Not all platforms implement the XSI option to
1714228753Smm		 * extend files via ftruncate.  Stat() the file again
1715228753Smm		 * to see what happened.
1716228753Smm		 */
1717228753Smm		a->pst = NULL;
1718231200Smm		if ((ret = lazy_stat(a)) != ARCHIVE_OK)
1719228753Smm			return (ret);
1720228753Smm		/* We can use lseek()/write() to extend the file if
1721228753Smm		 * ftruncate didn't work or isn't available. */
1722228753Smm		if (a->st.st_size < a->filesize) {
1723228753Smm			const char nul = '\0';
1724228753Smm			if (lseek(a->fd, a->filesize - 1, SEEK_SET) < 0) {
1725228753Smm				archive_set_error(&a->archive, errno,
1726228753Smm				    "Seek failed");
1727228753Smm				return (ARCHIVE_FATAL);
1728228753Smm			}
1729228753Smm			if (write(a->fd, &nul, 1) < 0) {
1730228753Smm				archive_set_error(&a->archive, errno,
1731228753Smm				    "Write to restore size failed");
1732228753Smm				return (ARCHIVE_FATAL);
1733228753Smm			}
1734228753Smm			a->pst = NULL;
1735228753Smm		}
1736228753Smm	}
1737228753Smm
1738228753Smm	/* Restore metadata. */
1739228753Smm
1740228753Smm	/*
1741248616Smm	 * This is specific to Mac OS X.
1742248616Smm	 * If the current file is an AppleDouble file, it should be
1743248616Smm	 * linked with the data fork file and remove it.
1744248616Smm	 */
1745248616Smm	if (a->todo & TODO_APPLEDOUBLE) {
1746248616Smm		int r2 = fixup_appledouble(a, a->name);
1747248616Smm		if (r2 == ARCHIVE_EOF) {
1748248616Smm			/* The current file has been successfully linked
1749248616Smm			 * with the data fork file and removed. So there
1750248616Smm			 * is nothing to do on the current file.  */
1751248616Smm			goto finish_metadata;
1752248616Smm		}
1753248616Smm		if (r2 < ret) ret = r2;
1754248616Smm	}
1755248616Smm
1756248616Smm	/*
1757228753Smm	 * Look up the "real" UID only if we're going to need it.
1758228753Smm	 * TODO: the TODO_SGID condition can be dropped here, can't it?
1759228753Smm	 */
1760228753Smm	if (a->todo & (TODO_OWNER | TODO_SUID | TODO_SGID)) {
1761231200Smm		a->uid = archive_write_disk_uid(&a->archive,
1762228753Smm		    archive_entry_uname(a->entry),
1763228753Smm		    archive_entry_uid(a->entry));
1764228753Smm	}
1765228753Smm	/* Look up the "real" GID only if we're going to need it. */
1766228753Smm	/* TODO: the TODO_SUID condition can be dropped here, can't it? */
1767228753Smm	if (a->todo & (TODO_OWNER | TODO_SGID | TODO_SUID)) {
1768231200Smm		a->gid = archive_write_disk_gid(&a->archive,
1769228753Smm		    archive_entry_gname(a->entry),
1770228753Smm		    archive_entry_gid(a->entry));
1771228753Smm	 }
1772231200Smm
1773228753Smm	/*
1774231200Smm	 * Restore ownership before set_mode tries to restore suid/sgid
1775228753Smm	 * bits.  If we set the owner, we know what it is and can skip
1776228753Smm	 * a stat() call to examine the ownership of the file on disk.
1777228753Smm	 */
1778248616Smm	if (a->todo & TODO_OWNER) {
1779248616Smm		int r2 = set_ownership(a);
1780248616Smm		if (r2 < ret) ret = r2;
1781248616Smm	}
1782231200Smm
1783231200Smm	/*
1784231200Smm	 * set_mode must precede ACLs on systems such as Solaris and
1785231200Smm	 * FreeBSD where setting the mode implicitly clears extended ACLs
1786231200Smm	 */
1787228753Smm	if (a->todo & TODO_MODE) {
1788228753Smm		int r2 = set_mode(a, a->mode);
1789228753Smm		if (r2 < ret) ret = r2;
1790228753Smm	}
1791228753Smm
1792228753Smm	/*
1793228753Smm	 * Security-related extended attributes (such as
1794228753Smm	 * security.capability on Linux) have to be restored last,
1795228753Smm	 * since they're implicitly removed by other file changes.
1796228753Smm	 */
1797228753Smm	if (a->todo & TODO_XATTR) {
1798228753Smm		int r2 = set_xattrs(a);
1799228753Smm		if (r2 < ret) ret = r2;
1800228753Smm	}
1801228753Smm
1802228753Smm	/*
1803228753Smm	 * Some flags prevent file modification; they must be restored after
1804228753Smm	 * file contents are written.
1805228753Smm	 */
1806228753Smm	if (a->todo & TODO_FFLAGS) {
1807228753Smm		int r2 = set_fflags(a);
1808228753Smm		if (r2 < ret) ret = r2;
1809228753Smm	}
1810231200Smm
1811228753Smm	/*
1812231200Smm	 * Time must follow most other metadata;
1813228753Smm	 * otherwise atime will get changed.
1814228753Smm	 */
1815228753Smm	if (a->todo & TODO_TIMES) {
1816231200Smm		int r2 = set_times_from_entry(a);
1817228753Smm		if (r2 < ret) ret = r2;
1818228753Smm	}
1819228753Smm
1820231200Smm	/*
1821231200Smm	 * Mac extended metadata includes ACLs.
1822231200Smm	 */
1823231200Smm	if (a->todo & TODO_MAC_METADATA) {
1824231200Smm		const void *metadata;
1825231200Smm		size_t metadata_size;
1826231200Smm		metadata = archive_entry_mac_metadata(a->entry, &metadata_size);
1827231200Smm		if (metadata != NULL && metadata_size > 0) {
1828248616Smm			int r2 = set_mac_metadata(a, archive_entry_pathname(
1829248616Smm			    a->entry), metadata, metadata_size);
1830231200Smm			if (r2 < ret) ret = r2;
1831231200Smm		}
1832231200Smm	}
1833231200Smm
1834231200Smm	/*
1835231200Smm	 * ACLs must be restored after timestamps because there are
1836231200Smm	 * ACLs that prevent attribute changes (including time).
1837231200Smm	 */
1838231200Smm	if (a->todo & TODO_ACLS) {
1839313571Smm		int r2;
1840313571Smm		r2 = archive_write_disk_set_acls(&a->archive, a->fd,
1841313571Smm		    archive_entry_pathname(a->entry),
1842316338Smm		    archive_entry_acl(a->entry),
1843316338Smm		    archive_entry_mode(a->entry));
1844231200Smm		if (r2 < ret) ret = r2;
1845231200Smm	}
1846231200Smm
1847248616Smmfinish_metadata:
1848228753Smm	/* If there's an fd, we can close it now. */
1849228753Smm	if (a->fd >= 0) {
1850228753Smm		close(a->fd);
1851228753Smm		a->fd = -1;
1852358090Smm		if (a->tmpname) {
1853358090Smm			if (rename(a->tmpname, a->name) == -1) {
1854358090Smm				archive_set_error(&a->archive, errno,
1855358927Smm				    "Failed to rename temporary file");
1856358927Smm				ret = ARCHIVE_FAILED;
1857358927Smm				unlink(a->tmpname);
1858358090Smm			}
1859358090Smm			a->tmpname = NULL;
1860358090Smm		}
1861228753Smm	}
1862228753Smm	/* If there's an entry, we can release it now. */
1863344674Smm	archive_entry_free(a->entry);
1864344674Smm	a->entry = NULL;
1865228753Smm	a->archive.state = ARCHIVE_STATE_HEADER;
1866228753Smm	return (ret);
1867228753Smm}
1868228753Smm
1869228753Smmint
1870228753Smmarchive_write_disk_set_group_lookup(struct archive *_a,
1871228753Smm    void *private_data,
1872328828Smm    la_int64_t (*lookup_gid)(void *private, const char *gname, la_int64_t gid),
1873228753Smm    void (*cleanup_gid)(void *private))
1874228753Smm{
1875228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
1876231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
1877228753Smm	    ARCHIVE_STATE_ANY, "archive_write_disk_set_group_lookup");
1878228753Smm
1879231200Smm	if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL)
1880231200Smm		(a->cleanup_gid)(a->lookup_gid_data);
1881231200Smm
1882228753Smm	a->lookup_gid = lookup_gid;
1883228753Smm	a->cleanup_gid = cleanup_gid;
1884228753Smm	a->lookup_gid_data = private_data;
1885228753Smm	return (ARCHIVE_OK);
1886228753Smm}
1887228753Smm
1888228753Smmint
1889228753Smmarchive_write_disk_set_user_lookup(struct archive *_a,
1890228753Smm    void *private_data,
1891231200Smm    int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid),
1892228753Smm    void (*cleanup_uid)(void *private))
1893228753Smm{
1894228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
1895231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
1896228753Smm	    ARCHIVE_STATE_ANY, "archive_write_disk_set_user_lookup");
1897228753Smm
1898231200Smm	if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL)
1899231200Smm		(a->cleanup_uid)(a->lookup_uid_data);
1900231200Smm
1901228753Smm	a->lookup_uid = lookup_uid;
1902228753Smm	a->cleanup_uid = cleanup_uid;
1903228753Smm	a->lookup_uid_data = private_data;
1904228753Smm	return (ARCHIVE_OK);
1905228753Smm}
1906228753Smm
1907231200Smmint64_t
1908328828Smmarchive_write_disk_gid(struct archive *_a, const char *name, la_int64_t id)
1909231200Smm{
1910231200Smm       struct archive_write_disk *a = (struct archive_write_disk *)_a;
1911231200Smm       archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
1912231200Smm           ARCHIVE_STATE_ANY, "archive_write_disk_gid");
1913231200Smm       if (a->lookup_gid)
1914231200Smm               return (a->lookup_gid)(a->lookup_gid_data, name, id);
1915231200Smm       return (id);
1916231200Smm}
1917231200Smm
1918231200Smmint64_t
1919328828Smmarchive_write_disk_uid(struct archive *_a, const char *name, la_int64_t id)
1920231200Smm{
1921238909Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
1922238909Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
1923238909Smm	    ARCHIVE_STATE_ANY, "archive_write_disk_uid");
1924238909Smm	if (a->lookup_uid)
1925238909Smm		return (a->lookup_uid)(a->lookup_uid_data, name, id);
1926238909Smm	return (id);
1927231200Smm}
1928228753Smm
1929228753Smm/*
1930228753Smm * Create a new archive_write_disk object and initialize it with global state.
1931228753Smm */
1932228753Smmstruct archive *
1933228753Smmarchive_write_disk_new(void)
1934228753Smm{
1935228753Smm	struct archive_write_disk *a;
1936228753Smm
1937311042Smm	a = (struct archive_write_disk *)calloc(1, sizeof(*a));
1938228753Smm	if (a == NULL)
1939228753Smm		return (NULL);
1940228753Smm	a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC;
1941228753Smm	/* We're ready to write a header immediately. */
1942228753Smm	a->archive.state = ARCHIVE_STATE_HEADER;
1943228753Smm	a->archive.vtable = archive_write_disk_vtable();
1944228753Smm	a->start_time = time(NULL);
1945231200Smm	/* Query and restore the umask. */
1946231200Smm	umask(a->user_umask = umask(0));
1947228753Smm#ifdef HAVE_GETEUID
1948228753Smm	a->user_uid = geteuid();
1949228753Smm#endif /* HAVE_GETEUID */
1950228753Smm	if (archive_string_ensure(&a->path_safe, 512) == NULL) {
1951228753Smm		free(a);
1952228753Smm		return (NULL);
1953228753Smm	}
1954248616Smm#ifdef HAVE_ZLIB_H
1955248616Smm	a->decmpfs_compression_level = 5;
1956248616Smm#endif
1957228753Smm	return (&a->archive);
1958228753Smm}
1959228753Smm
1960228753Smm
1961228753Smm/*
1962228753Smm * If pathname is longer than PATH_MAX, chdir to a suitable
1963228753Smm * intermediate dir and edit the path down to a shorter suffix.  Note
1964228753Smm * that this routine never returns an error; if the chdir() attempt
1965228753Smm * fails for any reason, we just go ahead with the long pathname.  The
1966228753Smm * object creation is likely to fail, but any error will get handled
1967228753Smm * at that time.
1968228753Smm */
1969231200Smm#if defined(HAVE_FCHDIR) && defined(PATH_MAX)
1970228753Smmstatic void
1971228753Smmedit_deep_directories(struct archive_write_disk *a)
1972228753Smm{
1973228753Smm	int ret;
1974228753Smm	char *tail = a->name;
1975228753Smm
1976228753Smm	/* If path is short, avoid the open() below. */
1977305192Smm	if (strlen(tail) < PATH_MAX)
1978228753Smm		return;
1979228753Smm
1980228753Smm	/* Try to record our starting dir. */
1981349525Smm	a->restore_pwd = la_opendirat(AT_FDCWD, ".");
1982248616Smm	__archive_ensure_cloexec_flag(a->restore_pwd);
1983228753Smm	if (a->restore_pwd < 0)
1984228753Smm		return;
1985228753Smm
1986228753Smm	/* As long as the path is too long... */
1987305192Smm	while (strlen(tail) >= PATH_MAX) {
1988228753Smm		/* Locate a dir prefix shorter than PATH_MAX. */
1989228753Smm		tail += PATH_MAX - 8;
1990228753Smm		while (tail > a->name && *tail != '/')
1991228753Smm			tail--;
1992228753Smm		/* Exit if we find a too-long path component. */
1993228753Smm		if (tail <= a->name)
1994228753Smm			return;
1995228753Smm		/* Create the intermediate dir and chdir to it. */
1996228753Smm		*tail = '\0'; /* Terminate dir portion */
1997228753Smm		ret = create_dir(a, a->name);
1998228753Smm		if (ret == ARCHIVE_OK && chdir(a->name) != 0)
1999228753Smm			ret = ARCHIVE_FAILED;
2000228753Smm		*tail = '/'; /* Restore the / we removed. */
2001228753Smm		if (ret != ARCHIVE_OK)
2002228753Smm			return;
2003228753Smm		tail++;
2004228753Smm		/* The chdir() succeeded; we've now shortened the path. */
2005228753Smm		a->name = tail;
2006228753Smm	}
2007228753Smm	return;
2008228753Smm}
2009228753Smm#endif
2010228753Smm
2011228753Smm/*
2012228753Smm * The main restore function.
2013228753Smm */
2014228753Smmstatic int
2015228753Smmrestore_entry(struct archive_write_disk *a)
2016228753Smm{
2017228753Smm	int ret = ARCHIVE_OK, en;
2018228753Smm
2019228753Smm	if (a->flags & ARCHIVE_EXTRACT_UNLINK && !S_ISDIR(a->mode)) {
2020228753Smm		/*
2021228753Smm		 * TODO: Fix this.  Apparently, there are platforms
2022228753Smm		 * that still allow root to hose the entire filesystem
2023228753Smm		 * by unlinking a dir.  The S_ISDIR() test above
2024228753Smm		 * prevents us from using unlink() here if the new
2025228753Smm		 * object is a dir, but that doesn't mean the old
2026228753Smm		 * object isn't a dir.
2027228753Smm		 */
2028302001Smm		if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS)
2029302001Smm			(void)clear_nochange_fflags(a);
2030228753Smm		if (unlink(a->name) == 0) {
2031228753Smm			/* We removed it, reset cached stat. */
2032228753Smm			a->pst = NULL;
2033228753Smm		} else if (errno == ENOENT) {
2034228753Smm			/* File didn't exist, that's just as good. */
2035228753Smm		} else if (rmdir(a->name) == 0) {
2036228753Smm			/* It was a dir, but now it's gone. */
2037228753Smm			a->pst = NULL;
2038228753Smm		} else {
2039228753Smm			/* We tried, but couldn't get rid of it. */
2040228753Smm			archive_set_error(&a->archive, errno,
2041228753Smm			    "Could not unlink");
2042228753Smm			return(ARCHIVE_FAILED);
2043228753Smm		}
2044228753Smm	}
2045228753Smm
2046228753Smm	/* Try creating it first; if this fails, we'll try to recover. */
2047228753Smm	en = create_filesystem_object(a);
2048228753Smm
2049228753Smm	if ((en == ENOTDIR || en == ENOENT)
2050228753Smm	    && !(a->flags & ARCHIVE_EXTRACT_NO_AUTODIR)) {
2051228753Smm		/* If the parent dir doesn't exist, try creating it. */
2052228753Smm		create_parent_dir(a, a->name);
2053228753Smm		/* Now try to create the object again. */
2054228753Smm		en = create_filesystem_object(a);
2055228753Smm	}
2056228753Smm
2057302001Smm	if ((en == ENOENT) && (archive_entry_hardlink(a->entry) != NULL)) {
2058302001Smm		archive_set_error(&a->archive, en,
2059302001Smm		    "Hard-link target '%s' does not exist.",
2060302001Smm		    archive_entry_hardlink(a->entry));
2061302001Smm		return (ARCHIVE_FAILED);
2062302001Smm	}
2063302001Smm
2064228753Smm	if ((en == EISDIR || en == EEXIST)
2065228753Smm	    && (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
2066228753Smm		/* If we're not overwriting, we're done. */
2067328828Smm		if (S_ISDIR(a->mode)) {
2068328828Smm			/* Don't overwrite any settings on existing directories. */
2069328828Smm			a->todo = 0;
2070328828Smm		}
2071231200Smm		archive_entry_unset_size(a->entry);
2072231200Smm		return (ARCHIVE_OK);
2073228753Smm	}
2074228753Smm
2075228753Smm	/*
2076228753Smm	 * Some platforms return EISDIR if you call
2077228753Smm	 * open(O_WRONLY | O_EXCL | O_CREAT) on a directory, some
2078228753Smm	 * return EEXIST.  POSIX is ambiguous, requiring EISDIR
2079228753Smm	 * for open(O_WRONLY) on a dir and EEXIST for open(O_EXCL | O_CREAT)
2080228753Smm	 * on an existing item.
2081228753Smm	 */
2082228753Smm	if (en == EISDIR) {
2083228753Smm		/* A dir is in the way of a non-dir, rmdir it. */
2084228753Smm		if (rmdir(a->name) != 0) {
2085228753Smm			archive_set_error(&a->archive, errno,
2086228753Smm			    "Can't remove already-existing dir");
2087228753Smm			return (ARCHIVE_FAILED);
2088228753Smm		}
2089228753Smm		a->pst = NULL;
2090228753Smm		/* Try again. */
2091228753Smm		en = create_filesystem_object(a);
2092228753Smm	} else if (en == EEXIST) {
2093228753Smm		/*
2094228753Smm		 * We know something is in the way, but we don't know what;
2095228753Smm		 * we need to find out before we go any further.
2096228753Smm		 */
2097228753Smm		int r = 0;
2098228753Smm		/*
2099231200Smm		 * The SECURE_SYMLINKS logic has already removed a
2100228753Smm		 * symlink to a dir if the client wants that.  So
2101228753Smm		 * follow the symlink if we're creating a dir.
2102228753Smm		 */
2103228753Smm		if (S_ISDIR(a->mode))
2104348608Smm			r = la_stat(a->name, &a->st);
2105228753Smm		/*
2106228753Smm		 * If it's not a dir (or it's a broken symlink),
2107228753Smm		 * then don't follow it.
2108228753Smm		 */
2109228753Smm		if (r != 0 || !S_ISDIR(a->mode))
2110228753Smm			r = lstat(a->name, &a->st);
2111228753Smm		if (r != 0) {
2112228753Smm			archive_set_error(&a->archive, errno,
2113228753Smm			    "Can't stat existing object");
2114228753Smm			return (ARCHIVE_FAILED);
2115228753Smm		}
2116228753Smm
2117228753Smm		/*
2118228753Smm		 * NO_OVERWRITE_NEWER doesn't apply to directories.
2119228753Smm		 */
2120228753Smm		if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER)
2121228753Smm		    &&  !S_ISDIR(a->st.st_mode)) {
2122228753Smm			if (!older(&(a->st), a->entry)) {
2123231200Smm				archive_entry_unset_size(a->entry);
2124231200Smm				return (ARCHIVE_OK);
2125228753Smm			}
2126228753Smm		}
2127228753Smm
2128228753Smm		/* If it's our archive, we're done. */
2129231200Smm		if (a->skip_file_set &&
2130238856Smm		    a->st.st_dev == (dev_t)a->skip_file_dev &&
2131238856Smm		    a->st.st_ino == (ino_t)a->skip_file_ino) {
2132238856Smm			archive_set_error(&a->archive, 0,
2133238856Smm			    "Refusing to overwrite archive");
2134228753Smm			return (ARCHIVE_FAILED);
2135228753Smm		}
2136228753Smm
2137228753Smm		if (!S_ISDIR(a->st.st_mode)) {
2138302001Smm			if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS)
2139302001Smm				(void)clear_nochange_fflags(a);
2140358090Smm
2141358090Smm			if ((a->flags & ARCHIVE_EXTRACT_SAFE_WRITES) &&
2142358090Smm			    S_ISREG(a->st.st_mode)) {
2143358090Smm				/* Use a temporary file to extract */
2144358927Smm				if ((a->fd = la_mktemp(a)) == -1) {
2145358927Smm					archive_set_error(&a->archive, errno,
2146358927Smm					    "Can't create temporary file");
2147358090Smm					return ARCHIVE_FAILED;
2148358927Smm				}
2149358090Smm				a->pst = NULL;
2150358090Smm				en = 0;
2151358090Smm			} else {
2152358090Smm				/* A non-dir is in the way, unlink it. */
2153358090Smm				if (unlink(a->name) != 0) {
2154358090Smm					archive_set_error(&a->archive, errno,
2155358090Smm					    "Can't unlink already-existing "
2156358090Smm					    "object");
2157358090Smm					return (ARCHIVE_FAILED);
2158358090Smm				}
2159358090Smm				a->pst = NULL;
2160358090Smm				/* Try again. */
2161358090Smm				en = create_filesystem_object(a);
2162228753Smm			}
2163228753Smm		} else if (!S_ISDIR(a->mode)) {
2164228753Smm			/* A dir is in the way of a non-dir, rmdir it. */
2165302001Smm			if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS)
2166302001Smm				(void)clear_nochange_fflags(a);
2167228753Smm			if (rmdir(a->name) != 0) {
2168228753Smm				archive_set_error(&a->archive, errno,
2169238856Smm				    "Can't replace existing directory with non-directory");
2170228753Smm				return (ARCHIVE_FAILED);
2171228753Smm			}
2172228753Smm			/* Try again. */
2173228753Smm			en = create_filesystem_object(a);
2174228753Smm		} else {
2175228753Smm			/*
2176228753Smm			 * There's a dir in the way of a dir.  Don't
2177228753Smm			 * waste time with rmdir()/mkdir(), just fix
2178228753Smm			 * up the permissions on the existing dir.
2179228753Smm			 * Note that we don't change perms on existing
2180228753Smm			 * dirs unless _EXTRACT_PERM is specified.
2181228753Smm			 */
2182228753Smm			if ((a->mode != a->st.st_mode)
2183228753Smm			    && (a->todo & TODO_MODE_FORCE))
2184228753Smm				a->deferred |= (a->todo & TODO_MODE);
2185228753Smm			/* Ownership doesn't need deferred fixup. */
2186228753Smm			en = 0; /* Forget the EEXIST. */
2187228753Smm		}
2188228753Smm	}
2189228753Smm
2190228753Smm	if (en) {
2191228753Smm		/* Everything failed; give up here. */
2192309702Smm		if ((&a->archive)->error == NULL)
2193309702Smm			archive_set_error(&a->archive, en, "Can't create '%s'",
2194309702Smm			    a->name);
2195228753Smm		return (ARCHIVE_FAILED);
2196228753Smm	}
2197228753Smm
2198228753Smm	a->pst = NULL; /* Cached stat data no longer valid. */
2199228753Smm	return (ret);
2200228753Smm}
2201228753Smm
2202228753Smm/*
2203228753Smm * Returns 0 if creation succeeds, or else returns errno value from
2204228753Smm * the failed system call.   Note:  This function should only ever perform
2205228753Smm * a single system call.
2206228753Smm */
2207228753Smmstatic int
2208228753Smmcreate_filesystem_object(struct archive_write_disk *a)
2209228753Smm{
2210228753Smm	/* Create the entry. */
2211228753Smm	const char *linkname;
2212228753Smm	mode_t final_mode, mode;
2213228753Smm	int r;
2214306322Smm	/* these for check_symlinks_fsobj */
2215306322Smm	char *linkname_copy;	/* non-const copy of linkname */
2216315433Smm	struct stat st;
2217306322Smm	struct archive_string error_string;
2218306322Smm	int error_number;
2219228753Smm
2220228753Smm	/* We identify hard/symlinks according to the link names. */
2221228753Smm	/* Since link(2) and symlink(2) don't handle modes, we're done here. */
2222228753Smm	linkname = archive_entry_hardlink(a->entry);
2223228753Smm	if (linkname != NULL) {
2224228753Smm#if !HAVE_LINK
2225228753Smm		return (EPERM);
2226228753Smm#else
2227306322Smm		archive_string_init(&error_string);
2228306322Smm		linkname_copy = strdup(linkname);
2229306322Smm		if (linkname_copy == NULL) {
2230306322Smm		    return (EPERM);
2231306322Smm		}
2232309702Smm		/*
2233309702Smm		 * TODO: consider using the cleaned-up path as the link
2234309702Smm		 * target?
2235309702Smm		 */
2236309702Smm		r = cleanup_pathname_fsobj(linkname_copy, &error_number,
2237309702Smm		    &error_string, a->flags);
2238306322Smm		if (r != ARCHIVE_OK) {
2239309702Smm			archive_set_error(&a->archive, error_number, "%s",
2240309702Smm			    error_string.s);
2241306322Smm			free(linkname_copy);
2242313571Smm			archive_string_free(&error_string);
2243309702Smm			/*
2244309702Smm			 * EPERM is more appropriate than error_number for our
2245309702Smm			 * callers
2246309702Smm			 */
2247306322Smm			return (EPERM);
2248306322Smm		}
2249309702Smm		r = check_symlinks_fsobj(linkname_copy, &error_number,
2250309702Smm		    &error_string, a->flags);
2251306322Smm		if (r != ARCHIVE_OK) {
2252309702Smm			archive_set_error(&a->archive, error_number, "%s",
2253309702Smm			    error_string.s);
2254306322Smm			free(linkname_copy);
2255313571Smm			archive_string_free(&error_string);
2256309702Smm			/*
2257309702Smm			 * EPERM is more appropriate than error_number for our
2258309702Smm			 * callers
2259309702Smm			 */
2260306322Smm			return (EPERM);
2261306322Smm		}
2262306322Smm		free(linkname_copy);
2263313571Smm		archive_string_free(&error_string);
2264358090Smm		/*
2265358090Smm		 * Unlinking and linking here is really not atomic,
2266358090Smm		 * but doing it right, would require us to construct
2267358090Smm		 * an mktemplink() function, and then use rename(2).
2268358090Smm		 */
2269358090Smm		if (a->flags & ARCHIVE_EXTRACT_SAFE_WRITES)
2270358090Smm			unlink(a->name);
2271228753Smm		r = link(linkname, a->name) ? errno : 0;
2272228753Smm		/*
2273228753Smm		 * New cpio and pax formats allow hardlink entries
2274228753Smm		 * to carry data, so we may have to open the file
2275228753Smm		 * for hardlink entries.
2276228753Smm		 *
2277228753Smm		 * If the hardlink was successfully created and
2278228753Smm		 * the archive doesn't have carry data for it,
2279231200Smm		 * consider it to be non-authoritative for meta data.
2280228753Smm		 * This is consistent with GNU tar and BSD pax.
2281228753Smm		 * If the hardlink does carry data, let the last
2282228753Smm		 * archive entry decide ownership.
2283228753Smm		 */
2284228753Smm		if (r == 0 && a->filesize <= 0) {
2285228753Smm			a->todo = 0;
2286228753Smm			a->deferred = 0;
2287231200Smm		} else if (r == 0 && a->filesize > 0) {
2288315433Smm#ifdef HAVE_LSTAT
2289315433Smm			r = lstat(a->name, &st);
2290315433Smm#else
2291348608Smm			r = la_stat(a->name, &st);
2292315433Smm#endif
2293315433Smm			if (r != 0)
2294228753Smm				r = errno;
2295315433Smm			else if ((st.st_mode & AE_IFMT) == AE_IFREG) {
2296315433Smm				a->fd = open(a->name, O_WRONLY | O_TRUNC |
2297315433Smm				    O_BINARY | O_CLOEXEC | O_NOFOLLOW);
2298315433Smm				__archive_ensure_cloexec_flag(a->fd);
2299315433Smm				if (a->fd < 0)
2300315433Smm					r = errno;
2301315433Smm			}
2302228753Smm		}
2303228753Smm		return (r);
2304228753Smm#endif
2305228753Smm	}
2306228753Smm	linkname = archive_entry_symlink(a->entry);
2307228753Smm	if (linkname != NULL) {
2308228753Smm#if HAVE_SYMLINK
2309358090Smm		/*
2310358090Smm		 * Unlinking and linking here is really not atomic,
2311358090Smm		 * but doing it right, would require us to construct
2312358090Smm		 * an mktempsymlink() function, and then use rename(2).
2313358090Smm		 */
2314358090Smm		if (a->flags & ARCHIVE_EXTRACT_SAFE_WRITES)
2315358090Smm			unlink(a->name);
2316228753Smm		return symlink(linkname, a->name) ? errno : 0;
2317228753Smm#else
2318228753Smm		return (EPERM);
2319228753Smm#endif
2320228753Smm	}
2321228753Smm
2322228753Smm	/*
2323228753Smm	 * The remaining system calls all set permissions, so let's
2324228753Smm	 * try to take advantage of that to avoid an extra chmod()
2325228753Smm	 * call.  (Recall that umask is set to zero right now!)
2326228753Smm	 */
2327228753Smm
2328228753Smm	/* Mode we want for the final restored object (w/o file type bits). */
2329228753Smm	final_mode = a->mode & 07777;
2330228753Smm	/*
2331228753Smm	 * The mode that will actually be restored in this step.  Note
2332228753Smm	 * that SUID, SGID, etc, require additional work to ensure
2333228753Smm	 * security, so we never restore them at this point.
2334228753Smm	 */
2335248616Smm	mode = final_mode & 0777 & ~a->user_umask;
2336228753Smm
2337228753Smm	switch (a->mode & AE_IFMT) {
2338228753Smm	default:
2339228753Smm		/* POSIX requires that we fall through here. */
2340228753Smm		/* FALLTHROUGH */
2341228753Smm	case AE_IFREG:
2342358090Smm		a->tmpname = NULL;
2343228753Smm		a->fd = open(a->name,
2344248616Smm		    O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, mode);
2345248616Smm		__archive_ensure_cloexec_flag(a->fd);
2346228753Smm		r = (a->fd < 0);
2347228753Smm		break;
2348228753Smm	case AE_IFCHR:
2349228753Smm#ifdef HAVE_MKNOD
2350228753Smm		/* Note: we use AE_IFCHR for the case label, and
2351228753Smm		 * S_IFCHR for the mknod() call.  This is correct.  */
2352228753Smm		r = mknod(a->name, mode | S_IFCHR,
2353228753Smm		    archive_entry_rdev(a->entry));
2354228753Smm		break;
2355228753Smm#else
2356228753Smm		/* TODO: Find a better way to warn about our inability
2357228753Smm		 * to restore a char device node. */
2358228753Smm		return (EINVAL);
2359228753Smm#endif /* HAVE_MKNOD */
2360228753Smm	case AE_IFBLK:
2361228753Smm#ifdef HAVE_MKNOD
2362228753Smm		r = mknod(a->name, mode | S_IFBLK,
2363228753Smm		    archive_entry_rdev(a->entry));
2364228753Smm		break;
2365228753Smm#else
2366228753Smm		/* TODO: Find a better way to warn about our inability
2367228753Smm		 * to restore a block device node. */
2368228753Smm		return (EINVAL);
2369228753Smm#endif /* HAVE_MKNOD */
2370228753Smm	case AE_IFDIR:
2371228753Smm		mode = (mode | MINIMUM_DIR_MODE) & MAXIMUM_DIR_MODE;
2372228753Smm		r = mkdir(a->name, mode);
2373228753Smm		if (r == 0) {
2374228753Smm			/* Defer setting dir times. */
2375228753Smm			a->deferred |= (a->todo & TODO_TIMES);
2376228753Smm			a->todo &= ~TODO_TIMES;
2377228753Smm			/* Never use an immediate chmod(). */
2378228753Smm			/* We can't avoid the chmod() entirely if EXTRACT_PERM
2379228753Smm			 * because of SysV SGID inheritance. */
2380228753Smm			if ((mode != final_mode)
2381228753Smm			    || (a->flags & ARCHIVE_EXTRACT_PERM))
2382228753Smm				a->deferred |= (a->todo & TODO_MODE);
2383228753Smm			a->todo &= ~TODO_MODE;
2384228753Smm		}
2385228753Smm		break;
2386228753Smm	case AE_IFIFO:
2387228753Smm#ifdef HAVE_MKFIFO
2388228753Smm		r = mkfifo(a->name, mode);
2389228753Smm		break;
2390228753Smm#else
2391228753Smm		/* TODO: Find a better way to warn about our inability
2392228753Smm		 * to restore a fifo. */
2393228753Smm		return (EINVAL);
2394228753Smm#endif /* HAVE_MKFIFO */
2395228753Smm	}
2396228753Smm
2397228753Smm	/* All the system calls above set errno on failure. */
2398228753Smm	if (r)
2399228753Smm		return (errno);
2400228753Smm
2401228753Smm	/* If we managed to set the final mode, we've avoided a chmod(). */
2402228753Smm	if (mode == final_mode)
2403228753Smm		a->todo &= ~TODO_MODE;
2404228753Smm	return (0);
2405228753Smm}
2406228753Smm
2407228753Smm/*
2408228753Smm * Cleanup function for archive_extract.  Mostly, this involves processing
2409228753Smm * the fixup list, which is used to address a number of problems:
2410228753Smm *   * Dir permissions might prevent us from restoring a file in that
2411228753Smm *     dir, so we restore the dir with minimum 0700 permissions first,
2412228753Smm *     then correct the mode at the end.
2413228753Smm *   * Similarly, the act of restoring a file touches the directory
2414228753Smm *     and changes the timestamp on the dir, so we have to touch-up dir
2415228753Smm *     timestamps at the end as well.
2416228753Smm *   * Some file flags can interfere with the restore by, for example,
2417228753Smm *     preventing the creation of hardlinks to those files.
2418231200Smm *   * Mac OS extended metadata includes ACLs, so must be deferred on dirs.
2419228753Smm *
2420228753Smm * Note that tar/cpio do not require that archives be in a particular
2421228753Smm * order; there is no way to know when the last file has been restored
2422228753Smm * within a directory, so there's no way to optimize the memory usage
2423228753Smm * here by fixing up the directory any earlier than the
2424228753Smm * end-of-archive.
2425228753Smm *
2426228753Smm * XXX TODO: Directory ACLs should be restored here, for the same
2427228753Smm * reason we set directory perms here. XXX
2428228753Smm */
2429228753Smmstatic int
2430231200Smm_archive_write_disk_close(struct archive *_a)
2431228753Smm{
2432228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
2433228753Smm	struct fixup_entry *next, *p;
2434349525Smm	int fd, ret;
2435228753Smm
2436231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
2437228753Smm	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
2438228753Smm	    "archive_write_disk_close");
2439231200Smm	ret = _archive_write_disk_finish_entry(&a->archive);
2440228753Smm
2441228753Smm	/* Sort dir list so directories are fixed up in depth-first order. */
2442228753Smm	p = sort_dir_list(a->fixup_list);
2443228753Smm
2444228753Smm	while (p != NULL) {
2445349525Smm		fd = -1;
2446228753Smm		a->pst = NULL; /* Mark stat cache as out-of-date. */
2447349525Smm		if (p->fixup &
2448349525Smm		    (TODO_TIMES | TODO_MODE_BASE | TODO_ACLS | TODO_FFLAGS)) {
2449349525Smm			fd = open(p->name,
2450349525Smm			    O_WRONLY | O_BINARY | O_NOFOLLOW | O_CLOEXEC);
2451349525Smm		}
2452228753Smm		if (p->fixup & TODO_TIMES) {
2453349525Smm			set_times(a, fd, p->mode, p->name,
2454231200Smm			    p->atime, p->atime_nanos,
2455231200Smm			    p->birthtime, p->birthtime_nanos,
2456231200Smm			    p->mtime, p->mtime_nanos,
2457231200Smm			    p->ctime, p->ctime_nanos);
2458228753Smm		}
2459349525Smm		if (p->fixup & TODO_MODE_BASE) {
2460349525Smm#ifdef HAVE_FCHMOD
2461349525Smm			if (fd >= 0)
2462349525Smm				fchmod(fd, p->mode);
2463349525Smm			else
2464349525Smm#endif
2465228753Smm			chmod(p->name, p->mode);
2466349525Smm		}
2467231200Smm		if (p->fixup & TODO_ACLS)
2468349525Smm			archive_write_disk_set_acls(&a->archive, fd,
2469349525Smm			    p->name, &p->acl, p->mode);
2470228753Smm		if (p->fixup & TODO_FFLAGS)
2471349525Smm			set_fflags_platform(a, fd, p->name,
2472228753Smm			    p->mode, p->fflags_set, 0);
2473231200Smm		if (p->fixup & TODO_MAC_METADATA)
2474231200Smm			set_mac_metadata(a, p->name, p->mac_metadata,
2475231200Smm					 p->mac_metadata_size);
2476228753Smm		next = p->next;
2477231200Smm		archive_acl_clear(&p->acl);
2478231200Smm		free(p->mac_metadata);
2479228753Smm		free(p->name);
2480349525Smm		if (fd >= 0)
2481349525Smm			close(fd);
2482228753Smm		free(p);
2483228753Smm		p = next;
2484228753Smm	}
2485228753Smm	a->fixup_list = NULL;
2486228753Smm	return (ret);
2487228753Smm}
2488228753Smm
2489228753Smmstatic int
2490231200Smm_archive_write_disk_free(struct archive *_a)
2491228753Smm{
2492231200Smm	struct archive_write_disk *a;
2493228753Smm	int ret;
2494231200Smm	if (_a == NULL)
2495231200Smm		return (ARCHIVE_OK);
2496231200Smm	archive_check_magic(_a, ARCHIVE_WRITE_DISK_MAGIC,
2497231200Smm	    ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_write_disk_free");
2498231200Smm	a = (struct archive_write_disk *)_a;
2499231200Smm	ret = _archive_write_disk_close(&a->archive);
2500231200Smm	archive_write_disk_set_group_lookup(&a->archive, NULL, NULL, NULL);
2501231200Smm	archive_write_disk_set_user_lookup(&a->archive, NULL, NULL, NULL);
2502344674Smm	archive_entry_free(a->entry);
2503228753Smm	archive_string_free(&a->_name_data);
2504358090Smm	archive_string_free(&a->_tmpname_data);
2505228753Smm	archive_string_free(&a->archive.error_string);
2506228753Smm	archive_string_free(&a->path_safe);
2507231200Smm	a->archive.magic = 0;
2508231200Smm	__archive_clean(&a->archive);
2509248616Smm	free(a->decmpfs_header_p);
2510248616Smm	free(a->resource_fork);
2511248616Smm	free(a->compressed_buffer);
2512248616Smm	free(a->uncompressed_buffer);
2513302001Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\
2514302001Smm	&& defined(HAVE_ZLIB_H)
2515248616Smm	if (a->stream_valid) {
2516248616Smm		switch (deflateEnd(&a->stream)) {
2517248616Smm		case Z_OK:
2518248616Smm			break;
2519248616Smm		default:
2520248616Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
2521248616Smm			    "Failed to clean up compressor");
2522248616Smm			ret = ARCHIVE_FATAL;
2523248616Smm			break;
2524248616Smm		}
2525248616Smm	}
2526248616Smm#endif
2527228753Smm	free(a);
2528228753Smm	return (ret);
2529228753Smm}
2530228753Smm
2531228753Smm/*
2532228753Smm * Simple O(n log n) merge sort to order the fixup list.  In
2533228753Smm * particular, we want to restore dir timestamps depth-first.
2534228753Smm */
2535228753Smmstatic struct fixup_entry *
2536228753Smmsort_dir_list(struct fixup_entry *p)
2537228753Smm{
2538228753Smm	struct fixup_entry *a, *b, *t;
2539228753Smm
2540228753Smm	if (p == NULL)
2541228753Smm		return (NULL);
2542228753Smm	/* A one-item list is already sorted. */
2543228753Smm	if (p->next == NULL)
2544228753Smm		return (p);
2545228753Smm
2546228753Smm	/* Step 1: split the list. */
2547228753Smm	t = p;
2548228753Smm	a = p->next->next;
2549228753Smm	while (a != NULL) {
2550228753Smm		/* Step a twice, t once. */
2551228753Smm		a = a->next;
2552228753Smm		if (a != NULL)
2553228753Smm			a = a->next;
2554228753Smm		t = t->next;
2555228753Smm	}
2556228753Smm	/* Now, t is at the mid-point, so break the list here. */
2557228753Smm	b = t->next;
2558228753Smm	t->next = NULL;
2559228753Smm	a = p;
2560228753Smm
2561228753Smm	/* Step 2: Recursively sort the two sub-lists. */
2562228753Smm	a = sort_dir_list(a);
2563228753Smm	b = sort_dir_list(b);
2564228753Smm
2565228753Smm	/* Step 3: Merge the returned lists. */
2566228753Smm	/* Pick the first element for the merged list. */
2567228753Smm	if (strcmp(a->name, b->name) > 0) {
2568228753Smm		t = p = a;
2569228753Smm		a = a->next;
2570228753Smm	} else {
2571228753Smm		t = p = b;
2572228753Smm		b = b->next;
2573228753Smm	}
2574228753Smm
2575228753Smm	/* Always put the later element on the list first. */
2576228753Smm	while (a != NULL && b != NULL) {
2577228753Smm		if (strcmp(a->name, b->name) > 0) {
2578228753Smm			t->next = a;
2579228753Smm			a = a->next;
2580228753Smm		} else {
2581228753Smm			t->next = b;
2582228753Smm			b = b->next;
2583228753Smm		}
2584228753Smm		t = t->next;
2585228753Smm	}
2586228753Smm
2587228753Smm	/* Only one list is non-empty, so just splice it on. */
2588228753Smm	if (a != NULL)
2589228753Smm		t->next = a;
2590228753Smm	if (b != NULL)
2591228753Smm		t->next = b;
2592228753Smm
2593228753Smm	return (p);
2594228753Smm}
2595228753Smm
2596228753Smm/*
2597228753Smm * Returns a new, initialized fixup entry.
2598228753Smm *
2599228753Smm * TODO: Reduce the memory requirements for this list by using a tree
2600228753Smm * structure rather than a simple list of names.
2601228753Smm */
2602228753Smmstatic struct fixup_entry *
2603228753Smmnew_fixup(struct archive_write_disk *a, const char *pathname)
2604228753Smm{
2605228753Smm	struct fixup_entry *fe;
2606228753Smm
2607231200Smm	fe = (struct fixup_entry *)calloc(1, sizeof(struct fixup_entry));
2608248616Smm	if (fe == NULL) {
2609248616Smm		archive_set_error(&a->archive, ENOMEM,
2610248616Smm		    "Can't allocate memory for a fixup");
2611228753Smm		return (NULL);
2612248616Smm	}
2613228753Smm	fe->next = a->fixup_list;
2614228753Smm	a->fixup_list = fe;
2615228753Smm	fe->fixup = 0;
2616228753Smm	fe->name = strdup(pathname);
2617228753Smm	return (fe);
2618228753Smm}
2619228753Smm
2620228753Smm/*
2621228753Smm * Returns a fixup structure for the current entry.
2622228753Smm */
2623228753Smmstatic struct fixup_entry *
2624228753Smmcurrent_fixup(struct archive_write_disk *a, const char *pathname)
2625228753Smm{
2626228753Smm	if (a->current_fixup == NULL)
2627228753Smm		a->current_fixup = new_fixup(a, pathname);
2628228753Smm	return (a->current_fixup);
2629228753Smm}
2630228753Smm
2631309702Smm/* Error helper for new *_fsobj functions */
2632309702Smmstatic void
2633309702Smmfsobj_error(int *a_eno, struct archive_string *a_estr,
2634309702Smm    int err, const char *errstr, const char *path)
2635309702Smm{
2636309702Smm	if (a_eno)
2637309702Smm		*a_eno = err;
2638309702Smm	if (a_estr)
2639315433Smm		archive_string_sprintf(a_estr, "%s%s", errstr, path);
2640309702Smm}
2641309702Smm
2642228753Smm/*
2643228753Smm * TODO: Someday, integrate this with the deep dir support; they both
2644228753Smm * scan the path and both can be optimized by comparing against other
2645228753Smm * recent paths.
2646228753Smm */
2647306322Smm/*
2648306322Smm * Checks the given path to see if any elements along it are symlinks.  Returns
2649306322Smm * ARCHIVE_OK if there are none, otherwise puts an error in errmsg.
2650306322Smm */
2651228753Smmstatic int
2652309702Smmcheck_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
2653309702Smm    int flags)
2654228753Smm{
2655349525Smm#if !defined(HAVE_LSTAT) && \
2656349525Smm    !(defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT))
2657228753Smm	/* Platform doesn't have lstat, so we can't look for symlinks. */
2658306322Smm	(void)path; /* UNUSED */
2659306322Smm	(void)error_number; /* UNUSED */
2660306322Smm	(void)error_string; /* UNUSED */
2661306322Smm	(void)flags; /* UNUSED */
2662228753Smm	return (ARCHIVE_OK);
2663228753Smm#else
2664306322Smm	int res = ARCHIVE_OK;
2665306322Smm	char *tail;
2666306322Smm	char *head;
2667306322Smm	int last;
2668228753Smm	char c;
2669228753Smm	int r;
2670228753Smm	struct stat st;
2671349525Smm	int chdir_fd;
2672349525Smm#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)
2673349525Smm	int fd;
2674349525Smm#endif
2675228753Smm
2676306322Smm	/* Nothing to do here if name is empty */
2677306322Smm	if(path[0] == '\0')
2678306322Smm	    return (ARCHIVE_OK);
2679306322Smm
2680228753Smm	/*
2681228753Smm	 * Guard against symlink tricks.  Reject any archive entry whose
2682228753Smm	 * destination would be altered by a symlink.
2683306322Smm	 *
2684306322Smm	 * Walk the filename in chunks separated by '/'.  For each segment:
2685306322Smm	 *  - if it doesn't exist, continue
2686306322Smm	 *  - if it's symlink, abort or remove it
2687306322Smm	 *  - if it's a directory and it's not the last chunk, cd into it
2688306322Smm	 * As we go:
2689306322Smm	 *  head points to the current (relative) path
2690309702Smm	 *  tail points to the temporary \0 terminating the segment we're
2691309702Smm	 *      currently examining
2692306322Smm	 *  c holds what used to be in *tail
2693306322Smm	 *  last is 1 if this is the last tail
2694228753Smm	 */
2695349525Smm	chdir_fd = la_opendirat(AT_FDCWD, ".");
2696349525Smm	__archive_ensure_cloexec_flag(chdir_fd);
2697349525Smm	if (chdir_fd < 0) {
2698346105Smm		fsobj_error(a_eno, a_estr, errno,
2699346105Smm		    "Could not open ", path);
2700306322Smm		return (ARCHIVE_FATAL);
2701346105Smm	}
2702306322Smm	head = path;
2703306322Smm	tail = path;
2704306322Smm	last = 0;
2705306322Smm	/* TODO: reintroduce a safe cache here? */
2706302001Smm	/* Skip the root directory if the path is absolute. */
2707306322Smm	if(tail == path && tail[0] == '/')
2708306322Smm		++tail;
2709306322Smm	/* Keep going until we've checked the entire name.
2710306322Smm	 * head, tail, path all alias the same string, which is
2711306322Smm	 * temporarily zeroed at tail, so be careful restoring the
2712306322Smm	 * stashed (c=tail[0]) for error messages.
2713306322Smm	 * Exiting the loop with break is okay; continue is not.
2714306322Smm	 */
2715306322Smm	while (!last) {
2716309702Smm		/*
2717309702Smm		 * Skip the separator we just consumed, plus any adjacent ones
2718309702Smm		 */
2719306322Smm		while (*tail == '/')
2720306322Smm		    ++tail;
2721228753Smm		/* Skip the next path element. */
2722306322Smm		while (*tail != '\0' && *tail != '/')
2723306322Smm			++tail;
2724306322Smm		/* is this the last path component? */
2725306322Smm		last = (tail[0] == '\0') || (tail[0] == '/' && tail[1] == '\0');
2726306322Smm		/* temporarily truncate the string here */
2727306322Smm		c = tail[0];
2728306322Smm		tail[0] = '\0';
2729228753Smm		/* Check that we haven't hit a symlink. */
2730349525Smm#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)
2731349525Smm		r = fstatat(chdir_fd, head, &st, AT_SYMLINK_NOFOLLOW);
2732349525Smm#else
2733306322Smm		r = lstat(head, &st);
2734349525Smm#endif
2735228753Smm		if (r != 0) {
2736306322Smm			tail[0] = c;
2737228753Smm			/* We've hit a dir that doesn't exist; stop now. */
2738305192Smm			if (errno == ENOENT) {
2739228753Smm				break;
2740305192Smm			} else {
2741309702Smm				/*
2742309702Smm				 * Treat any other error as fatal - best to be
2743309702Smm				 * paranoid here.
2744309702Smm				 * Note: This effectively disables deep
2745309702Smm				 * directory support when security checks are
2746309702Smm				 * enabled. Otherwise, very long pathnames that
2747309702Smm				 * trigger an error here could evade the
2748309702Smm				 * sandbox.
2749309702Smm				 * TODO: We could do better, but it would
2750309702Smm				 * probably require merging the symlink checks
2751309702Smm				 * with the deep-directory editing.
2752309702Smm				 */
2753309702Smm				fsobj_error(a_eno, a_estr, errno,
2754315433Smm				    "Could not stat ", path);
2755306322Smm				res = ARCHIVE_FAILED;
2756306322Smm				break;
2757305192Smm			}
2758306322Smm		} else if (S_ISDIR(st.st_mode)) {
2759306322Smm			if (!last) {
2760349525Smm#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)
2761349525Smm				fd = la_opendirat(chdir_fd, head);
2762349525Smm				if (fd < 0)
2763349525Smm					r = -1;
2764349525Smm				else {
2765349525Smm					r = 0;
2766349525Smm					close(chdir_fd);
2767349525Smm					chdir_fd = fd;
2768349525Smm				}
2769349525Smm#else
2770349525Smm				r = chdir(head);
2771349525Smm#endif
2772349525Smm				if (r != 0) {
2773306322Smm					tail[0] = c;
2774309702Smm					fsobj_error(a_eno, a_estr, errno,
2775315433Smm					    "Could not chdir ", path);
2776306322Smm					res = (ARCHIVE_FATAL);
2777306322Smm					break;
2778306322Smm				}
2779306322Smm				/* Our view is now from inside this dir: */
2780306322Smm				head = tail + 1;
2781306322Smm			}
2782228753Smm		} else if (S_ISLNK(st.st_mode)) {
2783306322Smm			if (last) {
2784228753Smm				/*
2785228753Smm				 * Last element is symlink; remove it
2786228753Smm				 * so we can overwrite it with the
2787228753Smm				 * item being extracted.
2788228753Smm				 */
2789349525Smm#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)
2790349525Smm				r = unlinkat(chdir_fd, head, 0);
2791349525Smm#else
2792349525Smm				r = unlink(head);
2793349525Smm#endif
2794349525Smm				if (r != 0) {
2795306322Smm					tail[0] = c;
2796309702Smm					fsobj_error(a_eno, a_estr, errno,
2797315433Smm					    "Could not remove symlink ",
2798309702Smm					    path);
2799306322Smm					res = ARCHIVE_FAILED;
2800306322Smm					break;
2801228753Smm				}
2802228753Smm				/*
2803228753Smm				 * Even if we did remove it, a warning
2804228753Smm				 * is in order.  The warning is silly,
2805228753Smm				 * though, if we're just replacing one
2806228753Smm				 * symlink with another symlink.
2807228753Smm				 */
2808306322Smm				tail[0] = c;
2809309702Smm				/*
2810309702Smm				 * FIXME:  not sure how important this is to
2811309702Smm				 * restore
2812309702Smm				 */
2813309702Smm				/*
2814306322Smm				if (!S_ISLNK(path)) {
2815309702Smm					fsobj_error(a_eno, a_estr, 0,
2816315433Smm					    "Removing symlink ", path);
2817228753Smm				}
2818306322Smm				*/
2819228753Smm				/* Symlink gone.  No more problem! */
2820306322Smm				res = ARCHIVE_OK;
2821306322Smm				break;
2822306322Smm			} else if (flags & ARCHIVE_EXTRACT_UNLINK) {
2823228753Smm				/* User asked us to remove problems. */
2824349525Smm#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)
2825349525Smm				r = unlinkat(chdir_fd, head, 0);
2826349525Smm#else
2827349525Smm				r = unlink(head);
2828349525Smm#endif
2829349525Smm				if (r != 0) {
2830306322Smm					tail[0] = c;
2831309702Smm					fsobj_error(a_eno, a_estr, 0,
2832309702Smm					    "Cannot remove intervening "
2833315433Smm					    "symlink ", path);
2834306322Smm					res = ARCHIVE_FAILED;
2835306322Smm					break;
2836228753Smm				}
2837306322Smm				tail[0] = c;
2838309702Smm			} else if ((flags &
2839309702Smm			    ARCHIVE_EXTRACT_SECURE_SYMLINKS) == 0) {
2840309702Smm				/*
2841309702Smm				 * We are not the last element and we want to
2842309702Smm				 * follow symlinks if they are a directory.
2843309702Smm				 *
2844309702Smm				 * This is needed to extract hardlinks over
2845309702Smm				 * symlinks.
2846309702Smm				 */
2847349525Smm#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)
2848349525Smm				r = fstatat(chdir_fd, head, &st, 0);
2849349525Smm#else
2850348608Smm				r = la_stat(head, &st);
2851349525Smm#endif
2852309702Smm				if (r != 0) {
2853309702Smm					tail[0] = c;
2854309702Smm					if (errno == ENOENT) {
2855309702Smm						break;
2856309702Smm					} else {
2857309702Smm						fsobj_error(a_eno, a_estr,
2858309702Smm						    errno,
2859315433Smm						    "Could not stat ", path);
2860309702Smm						res = (ARCHIVE_FAILED);
2861309702Smm						break;
2862309702Smm					}
2863309702Smm				} else if (S_ISDIR(st.st_mode)) {
2864349525Smm#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)
2865349525Smm					fd = la_opendirat(chdir_fd, head);
2866349525Smm					if (fd < 0)
2867349525Smm						r = -1;
2868349525Smm					else {
2869349525Smm						r = 0;
2870349525Smm						close(chdir_fd);
2871349525Smm						chdir_fd = fd;
2872349525Smm					}
2873349525Smm#else
2874349525Smm					r = chdir(head);
2875349525Smm#endif
2876349525Smm					if (r != 0) {
2877309702Smm						tail[0] = c;
2878309702Smm						fsobj_error(a_eno, a_estr,
2879309702Smm						    errno,
2880315433Smm						    "Could not chdir ", path);
2881309702Smm						res = (ARCHIVE_FATAL);
2882309702Smm						break;
2883309702Smm					}
2884309702Smm					/*
2885309702Smm					 * Our view is now from inside
2886309702Smm					 * this dir:
2887309702Smm					 */
2888309702Smm					head = tail + 1;
2889309702Smm				} else {
2890309702Smm					tail[0] = c;
2891309702Smm					fsobj_error(a_eno, a_estr, 0,
2892309702Smm					    "Cannot extract through "
2893315433Smm					    "symlink ", path);
2894309702Smm					res = ARCHIVE_FAILED;
2895309702Smm					break;
2896309702Smm				}
2897228753Smm			} else {
2898306322Smm				tail[0] = c;
2899309702Smm				fsobj_error(a_eno, a_estr, 0,
2900315433Smm				    "Cannot extract through symlink ", path);
2901306322Smm				res = ARCHIVE_FAILED;
2902306322Smm				break;
2903228753Smm			}
2904228753Smm		}
2905306322Smm		/* be sure to always maintain this */
2906306322Smm		tail[0] = c;
2907306322Smm		if (tail[0] != '\0')
2908306322Smm			tail++; /* Advance to the next segment. */
2909228753Smm	}
2910306322Smm	/* Catches loop exits via break */
2911306322Smm	tail[0] = c;
2912349525Smm#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)
2913349525Smm	/* If we operate with openat(), fstatat() and unlinkat() there was
2914349525Smm	 * no chdir(), so just close the fd */
2915349525Smm	if (chdir_fd >= 0)
2916349525Smm		close(chdir_fd);
2917349525Smm#elif HAVE_FCHDIR
2918306322Smm	/* If we changed directory above, restore it here. */
2919349525Smm	if (chdir_fd >= 0) {
2920349525Smm		r = fchdir(chdir_fd);
2921306322Smm		if (r != 0) {
2922309702Smm			fsobj_error(a_eno, a_estr, errno,
2923309702Smm			    "chdir() failure", "");
2924306322Smm		}
2925349525Smm		close(chdir_fd);
2926349525Smm		chdir_fd = -1;
2927306322Smm		if (r != 0) {
2928306322Smm			res = (ARCHIVE_FATAL);
2929306322Smm		}
2930306322Smm	}
2931228753Smm#endif
2932306322Smm	/* TODO: reintroduce a safe cache here? */
2933306322Smm	return res;
2934306322Smm#endif
2935228753Smm}
2936228753Smm
2937306322Smm/*
2938306322Smm * Check a->name for symlinks, returning ARCHIVE_OK if its clean, otherwise
2939306322Smm * calls archive_set_error and returns ARCHIVE_{FATAL,FAILED}
2940306322Smm */
2941306322Smmstatic int
2942306322Smmcheck_symlinks(struct archive_write_disk *a)
2943306322Smm{
2944306322Smm	struct archive_string error_string;
2945306322Smm	int error_number;
2946306322Smm	int rc;
2947306322Smm	archive_string_init(&error_string);
2948309702Smm	rc = check_symlinks_fsobj(a->name, &error_number, &error_string,
2949309702Smm	    a->flags);
2950306322Smm	if (rc != ARCHIVE_OK) {
2951309702Smm		archive_set_error(&a->archive, error_number, "%s",
2952309702Smm		    error_string.s);
2953306322Smm	}
2954306322Smm	archive_string_free(&error_string);
2955306322Smm	a->pst = NULL;	/* to be safe */
2956306322Smm	return rc;
2957306322Smm}
2958306322Smm
2959306322Smm
2960231200Smm#if defined(__CYGWIN__)
2961228753Smm/*
2962228753Smm * 1. Convert a path separator from '\' to '/' .
2963231200Smm *    We shouldn't check multibyte character directly because some
2964228753Smm *    character-set have been using the '\' character for a part of
2965228753Smm *    its multibyte character code.
2966228753Smm * 2. Replace unusable characters in Windows with underscore('_').
2967228753Smm * See also : http://msdn.microsoft.com/en-us/library/aa365247.aspx
2968228753Smm */
2969231200Smmstatic void
2970311042Smmcleanup_pathname_win(char *path)
2971228753Smm{
2972228753Smm	wchar_t wc;
2973228753Smm	char *p;
2974228753Smm	size_t alen, l;
2975231200Smm	int mb, complete, utf8;
2976228753Smm
2977231200Smm	alen = 0;
2978231200Smm	mb = 0;
2979231200Smm	complete = 1;
2980231200Smm	utf8 = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)? 1: 0;
2981311042Smm	for (p = path; *p != '\0'; p++) {
2982231200Smm		++alen;
2983231200Smm		if (*p == '\\') {
2984231200Smm			/* If previous byte is smaller than 128,
2985231200Smm			 * this is not second byte of multibyte characters,
2986231200Smm			 * so we can replace '\' with '/'. */
2987231200Smm			if (utf8 || !mb)
2988231200Smm				*p = '/';
2989228753Smm			else
2990231200Smm				complete = 0;/* uncompleted. */
2991231200Smm		} else if (*(unsigned char *)p > 127)
2992231200Smm			mb = 1;
2993231200Smm		else
2994231200Smm			mb = 0;
2995231200Smm		/* Rewrite the path name if its next character is unusable. */
2996228753Smm		if (*p == ':' || *p == '*' || *p == '?' || *p == '"' ||
2997228753Smm		    *p == '<' || *p == '>' || *p == '|')
2998228753Smm			*p = '_';
2999228753Smm	}
3000231200Smm	if (complete)
3001231200Smm		return;
3002231200Smm
3003228753Smm	/*
3004231200Smm	 * Convert path separator in wide-character.
3005228753Smm	 */
3006311042Smm	p = path;
3007228753Smm	while (*p != '\0' && alen) {
3008228753Smm		l = mbtowc(&wc, p, alen);
3009232153Smm		if (l == (size_t)-1) {
3010228753Smm			while (*p != '\0') {
3011228753Smm				if (*p == '\\')
3012228753Smm					*p = '/';
3013228753Smm				++p;
3014228753Smm			}
3015228753Smm			break;
3016228753Smm		}
3017228753Smm		if (l == 1 && wc == L'\\')
3018228753Smm			*p = '/';
3019228753Smm		p += l;
3020228753Smm		alen -= l;
3021228753Smm	}
3022228753Smm}
3023228753Smm#endif
3024228753Smm
3025228753Smm/*
3026228753Smm * Canonicalize the pathname.  In particular, this strips duplicate
3027228753Smm * '/' characters, '.' elements, and trailing '/'.  It also raises an
3028300361Smm * error for an empty path, a trailing '..', (if _SECURE_NODOTDOT is
3029300361Smm * set) any '..' in the path or (if ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS
3030300361Smm * is set) if the path is absolute.
3031228753Smm */
3032228753Smmstatic int
3033309702Smmcleanup_pathname_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
3034309702Smm    int flags)
3035228753Smm{
3036228753Smm	char *dest, *src;
3037228753Smm	char separator = '\0';
3038228753Smm
3039306322Smm	dest = src = path;
3040228753Smm	if (*src == '\0') {
3041309702Smm		fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC,
3042309702Smm		    "Invalid empty ", "pathname");
3043228753Smm		return (ARCHIVE_FAILED);
3044228753Smm	}
3045228753Smm
3046231200Smm#if defined(__CYGWIN__)
3047311042Smm	cleanup_pathname_win(path);
3048228753Smm#endif
3049228753Smm	/* Skip leading '/'. */
3050300361Smm	if (*src == '/') {
3051306322Smm		if (flags & ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS) {
3052309702Smm			fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC,
3053309702Smm			    "Path is ", "absolute");
3054300361Smm			return (ARCHIVE_FAILED);
3055300361Smm		}
3056300361Smm
3057228753Smm		separator = *src++;
3058300361Smm	}
3059228753Smm
3060228753Smm	/* Scan the pathname one element at a time. */
3061228753Smm	for (;;) {
3062228753Smm		/* src points to first char after '/' */
3063228753Smm		if (src[0] == '\0') {
3064228753Smm			break;
3065228753Smm		} else if (src[0] == '/') {
3066228753Smm			/* Found '//', ignore second one. */
3067228753Smm			src++;
3068228753Smm			continue;
3069228753Smm		} else if (src[0] == '.') {
3070228753Smm			if (src[1] == '\0') {
3071228753Smm				/* Ignore trailing '.' */
3072228753Smm				break;
3073228753Smm			} else if (src[1] == '/') {
3074228753Smm				/* Skip './'. */
3075228753Smm				src += 2;
3076228753Smm				continue;
3077228753Smm			} else if (src[1] == '.') {
3078228753Smm				if (src[2] == '/' || src[2] == '\0') {
3079228753Smm					/* Conditionally warn about '..' */
3080309702Smm					if (flags
3081309702Smm					    & ARCHIVE_EXTRACT_SECURE_NODOTDOT) {
3082309702Smm						fsobj_error(a_eno, a_estr,
3083309702Smm						    ARCHIVE_ERRNO_MISC,
3084309702Smm						    "Path contains ", "'..'");
3085228753Smm						return (ARCHIVE_FAILED);
3086228753Smm					}
3087228753Smm				}
3088228753Smm				/*
3089228753Smm				 * Note: Under no circumstances do we
3090228753Smm				 * remove '..' elements.  In
3091228753Smm				 * particular, restoring
3092228753Smm				 * '/foo/../bar/' should create the
3093228753Smm				 * 'foo' dir as a side-effect.
3094228753Smm				 */
3095228753Smm			}
3096228753Smm		}
3097228753Smm
3098228753Smm		/* Copy current element, including leading '/'. */
3099228753Smm		if (separator)
3100228753Smm			*dest++ = '/';
3101228753Smm		while (*src != '\0' && *src != '/') {
3102228753Smm			*dest++ = *src++;
3103228753Smm		}
3104228753Smm
3105228753Smm		if (*src == '\0')
3106228753Smm			break;
3107228753Smm
3108228753Smm		/* Skip '/' separator. */
3109228753Smm		separator = *src++;
3110228753Smm	}
3111228753Smm	/*
3112228753Smm	 * We've just copied zero or more path elements, not including the
3113228753Smm	 * final '/'.
3114228753Smm	 */
3115306322Smm	if (dest == path) {
3116228753Smm		/*
3117228753Smm		 * Nothing got copied.  The path must have been something
3118228753Smm		 * like '.' or '/' or './' or '/././././/./'.
3119228753Smm		 */
3120228753Smm		if (separator)
3121228753Smm			*dest++ = '/';
3122228753Smm		else
3123228753Smm			*dest++ = '.';
3124228753Smm	}
3125228753Smm	/* Terminate the result. */
3126228753Smm	*dest = '\0';
3127228753Smm	return (ARCHIVE_OK);
3128228753Smm}
3129228753Smm
3130306322Smmstatic int
3131306322Smmcleanup_pathname(struct archive_write_disk *a)
3132306322Smm{
3133306322Smm	struct archive_string error_string;
3134306322Smm	int error_number;
3135306322Smm	int rc;
3136306322Smm	archive_string_init(&error_string);
3137309702Smm	rc = cleanup_pathname_fsobj(a->name, &error_number, &error_string,
3138309702Smm	    a->flags);
3139306322Smm	if (rc != ARCHIVE_OK) {
3140309702Smm		archive_set_error(&a->archive, error_number, "%s",
3141309702Smm		    error_string.s);
3142306322Smm	}
3143306322Smm	archive_string_free(&error_string);
3144306322Smm	return rc;
3145306322Smm}
3146306322Smm
3147228753Smm/*
3148228753Smm * Create the parent directory of the specified path, assuming path
3149228753Smm * is already in mutable storage.
3150228753Smm */
3151228753Smmstatic int
3152228753Smmcreate_parent_dir(struct archive_write_disk *a, char *path)
3153228753Smm{
3154228753Smm	char *slash;
3155228753Smm	int r;
3156228753Smm
3157228753Smm	/* Remove tail element to obtain parent name. */
3158228753Smm	slash = strrchr(path, '/');
3159228753Smm	if (slash == NULL)
3160228753Smm		return (ARCHIVE_OK);
3161228753Smm	*slash = '\0';
3162228753Smm	r = create_dir(a, path);
3163228753Smm	*slash = '/';
3164228753Smm	return (r);
3165228753Smm}
3166228753Smm
3167228753Smm/*
3168228753Smm * Create the specified dir, recursing to create parents as necessary.
3169228753Smm *
3170228753Smm * Returns ARCHIVE_OK if the path exists when we're done here.
3171228753Smm * Otherwise, returns ARCHIVE_FAILED.
3172228753Smm * Assumes path is in mutable storage; path is unchanged on exit.
3173228753Smm */
3174228753Smmstatic int
3175228753Smmcreate_dir(struct archive_write_disk *a, char *path)
3176228753Smm{
3177228753Smm	struct stat st;
3178228753Smm	struct fixup_entry *le;
3179228753Smm	char *slash, *base;
3180228753Smm	mode_t mode_final, mode;
3181228753Smm	int r;
3182228753Smm
3183228753Smm	/* Check for special names and just skip them. */
3184228753Smm	slash = strrchr(path, '/');
3185228753Smm	if (slash == NULL)
3186228753Smm		base = path;
3187228753Smm	else
3188228753Smm		base = slash + 1;
3189228753Smm
3190228753Smm	if (base[0] == '\0' ||
3191228753Smm	    (base[0] == '.' && base[1] == '\0') ||
3192228753Smm	    (base[0] == '.' && base[1] == '.' && base[2] == '\0')) {
3193228753Smm		/* Don't bother trying to create null path, '.', or '..'. */
3194228753Smm		if (slash != NULL) {
3195228753Smm			*slash = '\0';
3196228753Smm			r = create_dir(a, path);
3197228753Smm			*slash = '/';
3198228753Smm			return (r);
3199228753Smm		}
3200228753Smm		return (ARCHIVE_OK);
3201228753Smm	}
3202228753Smm
3203228753Smm	/*
3204228753Smm	 * Yes, this should be stat() and not lstat().  Using lstat()
3205228753Smm	 * here loses the ability to extract through symlinks.  Also note
3206228753Smm	 * that this should not use the a->st cache.
3207228753Smm	 */
3208348608Smm	if (la_stat(path, &st) == 0) {
3209228753Smm		if (S_ISDIR(st.st_mode))
3210228753Smm			return (ARCHIVE_OK);
3211228753Smm		if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
3212228753Smm			archive_set_error(&a->archive, EEXIST,
3213228753Smm			    "Can't create directory '%s'", path);
3214228753Smm			return (ARCHIVE_FAILED);
3215228753Smm		}
3216228753Smm		if (unlink(path) != 0) {
3217228753Smm			archive_set_error(&a->archive, errno,
3218228753Smm			    "Can't create directory '%s': "
3219231200Smm			    "Conflicting file cannot be removed",
3220231200Smm			    path);
3221228753Smm			return (ARCHIVE_FAILED);
3222228753Smm		}
3223228753Smm	} else if (errno != ENOENT && errno != ENOTDIR) {
3224228753Smm		/* Stat failed? */
3225309702Smm		archive_set_error(&a->archive, errno,
3226309702Smm		    "Can't test directory '%s'", path);
3227228753Smm		return (ARCHIVE_FAILED);
3228228753Smm	} else if (slash != NULL) {
3229228753Smm		*slash = '\0';
3230228753Smm		r = create_dir(a, path);
3231228753Smm		*slash = '/';
3232228753Smm		if (r != ARCHIVE_OK)
3233228753Smm			return (r);
3234228753Smm	}
3235228753Smm
3236228753Smm	/*
3237228753Smm	 * Mode we want for the final restored directory.  Per POSIX,
3238228753Smm	 * implicitly-created dirs must be created obeying the umask.
3239228753Smm	 * There's no mention whether this is different for privileged
3240228753Smm	 * restores (which the rest of this code handles by pretending
3241228753Smm	 * umask=0).  I've chosen here to always obey the user's umask for
3242228753Smm	 * implicit dirs, even if _EXTRACT_PERM was specified.
3243228753Smm	 */
3244228753Smm	mode_final = DEFAULT_DIR_MODE & ~a->user_umask;
3245228753Smm	/* Mode we want on disk during the restore process. */
3246228753Smm	mode = mode_final;
3247228753Smm	mode |= MINIMUM_DIR_MODE;
3248228753Smm	mode &= MAXIMUM_DIR_MODE;
3249228753Smm	if (mkdir(path, mode) == 0) {
3250228753Smm		if (mode != mode_final) {
3251228753Smm			le = new_fixup(a, path);
3252248616Smm			if (le == NULL)
3253248616Smm				return (ARCHIVE_FATAL);
3254228753Smm			le->fixup |=TODO_MODE_BASE;
3255228753Smm			le->mode = mode_final;
3256228753Smm		}
3257228753Smm		return (ARCHIVE_OK);
3258228753Smm	}
3259228753Smm
3260228753Smm	/*
3261228753Smm	 * Without the following check, a/b/../b/c/d fails at the
3262228753Smm	 * second visit to 'b', so 'd' can't be created.  Note that we
3263228753Smm	 * don't add it to the fixup list here, as it's already been
3264228753Smm	 * added.
3265228753Smm	 */
3266348608Smm	if (la_stat(path, &st) == 0 && S_ISDIR(st.st_mode))
3267228753Smm		return (ARCHIVE_OK);
3268228753Smm
3269228753Smm	archive_set_error(&a->archive, errno, "Failed to create dir '%s'",
3270228753Smm	    path);
3271228753Smm	return (ARCHIVE_FAILED);
3272228753Smm}
3273228753Smm
3274228753Smm/*
3275228753Smm * Note: Although we can skip setting the user id if the desired user
3276228753Smm * id matches the current user, we cannot skip setting the group, as
3277228753Smm * many systems set the gid based on the containing directory.  So
3278228753Smm * we have to perform a chown syscall if we want to set the SGID
3279228753Smm * bit.  (The alternative is to stat() and then possibly chown(); it's
3280228753Smm * more efficient to skip the stat() and just always chown().)  Note
3281228753Smm * that a successful chown() here clears the TODO_SGID_CHECK bit, which
3282228753Smm * allows set_mode to skip the stat() check for the GID.
3283228753Smm */
3284228753Smmstatic int
3285228753Smmset_ownership(struct archive_write_disk *a)
3286228753Smm{
3287346105Smm#if !defined(__CYGWIN__) && !defined(__linux__)
3288346105Smm/*
3289346105Smm * On Linux, a process may have the CAP_CHOWN capability.
3290346105Smm * On Windows there is no 'root' user with uid 0.
3291346105Smm * Elsewhere we can skip calling chown if we are not root and the desired
3292346105Smm * user id does not match the current user.
3293346105Smm */
3294346105Smm	if (a->user_uid != 0 && a->user_uid != a->uid) {
3295228753Smm		archive_set_error(&a->archive, errno,
3296231200Smm		    "Can't set UID=%jd", (intmax_t)a->uid);
3297228753Smm		return (ARCHIVE_WARN);
3298228753Smm	}
3299228753Smm#endif
3300228753Smm
3301228753Smm#ifdef HAVE_FCHOWN
3302228753Smm	/* If we have an fd, we can avoid a race. */
3303228753Smm	if (a->fd >= 0 && fchown(a->fd, a->uid, a->gid) == 0) {
3304228753Smm		/* We've set owner and know uid/gid are correct. */
3305228753Smm		a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK);
3306228753Smm		return (ARCHIVE_OK);
3307228753Smm	}
3308228753Smm#endif
3309228753Smm
3310228753Smm	/* We prefer lchown() but will use chown() if that's all we have. */
3311228753Smm	/* Of course, if we have neither, this will always fail. */
3312228753Smm#ifdef HAVE_LCHOWN
3313228753Smm	if (lchown(a->name, a->uid, a->gid) == 0) {
3314228753Smm		/* We've set owner and know uid/gid are correct. */
3315228753Smm		a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK);
3316228753Smm		return (ARCHIVE_OK);
3317228753Smm	}
3318228753Smm#elif HAVE_CHOWN
3319228753Smm	if (!S_ISLNK(a->mode) && chown(a->name, a->uid, a->gid) == 0) {
3320228753Smm		/* We've set owner and know uid/gid are correct. */
3321228753Smm		a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK);
3322228753Smm		return (ARCHIVE_OK);
3323228753Smm	}
3324228753Smm#endif
3325228753Smm
3326228753Smm	archive_set_error(&a->archive, errno,
3327231200Smm	    "Can't set user=%jd/group=%jd for %s",
3328231200Smm	    (intmax_t)a->uid, (intmax_t)a->gid, a->name);
3329228753Smm	return (ARCHIVE_WARN);
3330228753Smm}
3331228753Smm
3332231200Smm/*
3333231200Smm * Note: Returns 0 on success, non-zero on failure.
3334228753Smm */
3335228753Smmstatic int
3336228753Smmset_time(int fd, int mode, const char *name,
3337228753Smm    time_t atime, long atime_nsec,
3338228753Smm    time_t mtime, long mtime_nsec)
3339228753Smm{
3340231200Smm	/* Select the best implementation for this platform. */
3341231200Smm#if defined(HAVE_UTIMENSAT) && defined(HAVE_FUTIMENS)
3342231200Smm	/*
3343231200Smm	 * utimensat() and futimens() are defined in
3344231200Smm	 * POSIX.1-2008. They support ns resolution and setting times
3345231200Smm	 * on fds and symlinks.
3346231200Smm	 */
3347228753Smm	struct timespec ts[2];
3348232153Smm	(void)mode; /* UNUSED */
3349228753Smm	ts[0].tv_sec = atime;
3350228753Smm	ts[0].tv_nsec = atime_nsec;
3351228753Smm	ts[1].tv_sec = mtime;
3352228753Smm	ts[1].tv_nsec = mtime_nsec;
3353228753Smm	if (fd >= 0)
3354228753Smm		return futimens(fd, ts);
3355228753Smm	return utimensat(AT_FDCWD, name, ts, AT_SYMLINK_NOFOLLOW);
3356231200Smm
3357228753Smm#elif HAVE_UTIMES
3358231200Smm	/*
3359231200Smm	 * The utimes()-family functions support ��s-resolution and
3360231200Smm	 * setting times fds and symlinks.  utimes() is documented as
3361231200Smm	 * LEGACY by POSIX, futimes() and lutimes() are not described
3362231200Smm	 * in POSIX.
3363231200Smm	 */
3364228753Smm	struct timeval times[2];
3365228753Smm
3366228753Smm	times[0].tv_sec = atime;
3367228753Smm	times[0].tv_usec = atime_nsec / 1000;
3368228753Smm	times[1].tv_sec = mtime;
3369228753Smm	times[1].tv_usec = mtime_nsec / 1000;
3370228753Smm
3371228753Smm#ifdef HAVE_FUTIMES
3372228753Smm	if (fd >= 0)
3373228753Smm		return (futimes(fd, times));
3374228753Smm#else
3375228753Smm	(void)fd; /* UNUSED */
3376228753Smm#endif
3377228753Smm#ifdef HAVE_LUTIMES
3378228753Smm	(void)mode; /* UNUSED */
3379228753Smm	return (lutimes(name, times));
3380228753Smm#else
3381228753Smm	if (S_ISLNK(mode))
3382228753Smm		return (0);
3383228753Smm	return (utimes(name, times));
3384228753Smm#endif
3385231200Smm
3386228753Smm#elif defined(HAVE_UTIME)
3387231200Smm	/*
3388231200Smm	 * utime() is POSIX-standard but only supports 1s resolution and
3389231200Smm	 * does not support fds or symlinks.
3390231200Smm	 */
3391228753Smm	struct utimbuf times;
3392228753Smm	(void)fd; /* UNUSED */
3393228753Smm	(void)name; /* UNUSED */
3394228753Smm	(void)atime_nsec; /* UNUSED */
3395228753Smm	(void)mtime_nsec; /* UNUSED */
3396228753Smm	times.actime = atime;
3397228753Smm	times.modtime = mtime;
3398228753Smm	if (S_ISLNK(mode))
3399228753Smm		return (ARCHIVE_OK);
3400228753Smm	return (utime(name, &times));
3401231200Smm
3402231200Smm#else
3403231200Smm	/*
3404231200Smm	 * We don't know how to set the time on this platform.
3405231200Smm	 */
3406232153Smm	(void)fd; /* UNUSED */
3407232153Smm	(void)mode; /* UNUSED */
3408232153Smm	(void)name; /* UNUSED */
3409232153Smm	(void)atime_nsec; /* UNUSED */
3410232153Smm	(void)mtime_nsec; /* UNUSED */
3411231200Smm	return (ARCHIVE_WARN);
3412231200Smm#endif
3413228753Smm}
3414231200Smm
3415302001Smm#ifdef F_SETTIMES
3416228753Smmstatic int
3417231200Smmset_time_tru64(int fd, int mode, const char *name,
3418228753Smm    time_t atime, long atime_nsec,
3419231200Smm    time_t mtime, long mtime_nsec,
3420231200Smm    time_t ctime, long ctime_nsec)
3421228753Smm{
3422231200Smm	struct attr_timbuf tstamp;
3423302001Smm	tstamp.atime.tv_sec = atime;
3424302001Smm	tstamp.mtime.tv_sec = mtime;
3425302001Smm	tstamp.ctime.tv_sec = ctime;
3426302001Smm#if defined (__hpux) && defined (__ia64)
3427302001Smm	tstamp.atime.tv_nsec = atime_nsec;
3428302001Smm	tstamp.mtime.tv_nsec = mtime_nsec;
3429302001Smm	tstamp.ctime.tv_nsec = ctime_nsec;
3430302001Smm#else
3431302001Smm	tstamp.atime.tv_usec = atime_nsec / 1000;
3432302001Smm	tstamp.mtime.tv_usec = mtime_nsec / 1000;
3433302001Smm	tstamp.ctime.tv_usec = ctime_nsec / 1000;
3434302001Smm#endif
3435231200Smm	return (fcntl(fd,F_SETTIMES,&tstamp));
3436228753Smm}
3437302001Smm#endif /* F_SETTIMES */
3438231200Smm
3439231200Smmstatic int
3440231200Smmset_times(struct archive_write_disk *a,
3441231200Smm    int fd, int mode, const char *name,
3442231200Smm    time_t atime, long atime_nanos,
3443231200Smm    time_t birthtime, long birthtime_nanos,
3444231200Smm    time_t mtime, long mtime_nanos,
3445232153Smm    time_t cctime, long ctime_nanos)
3446231200Smm{
3447231200Smm	/* Note: set_time doesn't use libarchive return conventions!
3448231200Smm	 * It uses syscall conventions.  So 0 here instead of ARCHIVE_OK. */
3449231200Smm	int r1 = 0, r2 = 0;
3450231200Smm
3451231200Smm#ifdef F_SETTIMES
3452231200Smm	 /*
3453231200Smm	 * on Tru64 try own fcntl first which can restore even the
3454231200Smm	 * ctime, fall back to default code path below if it fails
3455231200Smm	 * or if we are not running as root
3456231200Smm	 */
3457231200Smm	if (a->user_uid == 0 &&
3458231200Smm	    set_time_tru64(fd, mode, name,
3459231200Smm			   atime, atime_nanos, mtime,
3460232153Smm			   mtime_nanos, cctime, ctime_nanos) == 0) {
3461231200Smm		return (ARCHIVE_OK);
3462231200Smm	}
3463232153Smm#else /* Tru64 */
3464232153Smm	(void)cctime; /* UNUSED */
3465232153Smm	(void)ctime_nanos; /* UNUSED */
3466231200Smm#endif /* Tru64 */
3467231200Smm
3468231200Smm#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
3469231200Smm	/*
3470231200Smm	 * If you have struct stat.st_birthtime, we assume BSD
3471231200Smm	 * birthtime semantics, in which {f,l,}utimes() updates
3472231200Smm	 * birthtime to earliest mtime.  So we set the time twice,
3473231200Smm	 * first using the birthtime, then using the mtime.  If
3474231200Smm	 * birthtime == mtime, this isn't necessary, so we skip it.
3475231200Smm	 * If birthtime > mtime, then this won't work, so we skip it.
3476231200Smm	 */
3477231200Smm	if (birthtime < mtime
3478231200Smm	    || (birthtime == mtime && birthtime_nanos < mtime_nanos))
3479231200Smm		r1 = set_time(fd, mode, name,
3480231200Smm			      atime, atime_nanos,
3481231200Smm			      birthtime, birthtime_nanos);
3482232153Smm#else
3483232153Smm	(void)birthtime; /* UNUSED */
3484232153Smm	(void)birthtime_nanos; /* UNUSED */
3485228753Smm#endif
3486231200Smm	r2 = set_time(fd, mode, name,
3487231200Smm		      atime, atime_nanos,
3488231200Smm		      mtime, mtime_nanos);
3489231200Smm	if (r1 != 0 || r2 != 0) {
3490231200Smm		archive_set_error(&a->archive, errno,
3491231200Smm				  "Can't restore time");
3492231200Smm		return (ARCHIVE_WARN);
3493231200Smm	}
3494231200Smm	return (ARCHIVE_OK);
3495231200Smm}
3496228753Smm
3497228753Smmstatic int
3498231200Smmset_times_from_entry(struct archive_write_disk *a)
3499228753Smm{
3500232153Smm	time_t atime, birthtime, mtime, cctime;
3501231200Smm	long atime_nsec, birthtime_nsec, mtime_nsec, ctime_nsec;
3502228753Smm
3503231200Smm	/* Suitable defaults. */
3504232153Smm	atime = birthtime = mtime = cctime = a->start_time;
3505231200Smm	atime_nsec = birthtime_nsec = mtime_nsec = ctime_nsec = 0;
3506231200Smm
3507228753Smm	/* If no time was provided, we're done. */
3508228753Smm	if (!archive_entry_atime_is_set(a->entry)
3509228753Smm#if HAVE_STRUCT_STAT_ST_BIRTHTIME
3510228753Smm	    && !archive_entry_birthtime_is_set(a->entry)
3511228753Smm#endif
3512228753Smm	    && !archive_entry_mtime_is_set(a->entry))
3513228753Smm		return (ARCHIVE_OK);
3514228753Smm
3515228753Smm	if (archive_entry_atime_is_set(a->entry)) {
3516228753Smm		atime = archive_entry_atime(a->entry);
3517228753Smm		atime_nsec = archive_entry_atime_nsec(a->entry);
3518228753Smm	}
3519231200Smm	if (archive_entry_birthtime_is_set(a->entry)) {
3520231200Smm		birthtime = archive_entry_birthtime(a->entry);
3521231200Smm		birthtime_nsec = archive_entry_birthtime_nsec(a->entry);
3522231200Smm	}
3523228753Smm	if (archive_entry_mtime_is_set(a->entry)) {
3524228753Smm		mtime = archive_entry_mtime(a->entry);
3525228753Smm		mtime_nsec = archive_entry_mtime_nsec(a->entry);
3526228753Smm	}
3527231200Smm	if (archive_entry_ctime_is_set(a->entry)) {
3528232153Smm		cctime = archive_entry_ctime(a->entry);
3529231200Smm		ctime_nsec = archive_entry_ctime_nsec(a->entry);
3530228753Smm	}
3531228753Smm
3532231200Smm	return set_times(a, a->fd, a->mode, a->name,
3533231200Smm			 atime, atime_nsec,
3534231200Smm			 birthtime, birthtime_nsec,
3535231200Smm			 mtime, mtime_nsec,
3536232153Smm			 cctime, ctime_nsec);
3537228753Smm}
3538228753Smm
3539228753Smmstatic int
3540228753Smmset_mode(struct archive_write_disk *a, int mode)
3541228753Smm{
3542228753Smm	int r = ARCHIVE_OK;
3543349525Smm	int r2;
3544228753Smm	mode &= 07777; /* Strip off file type bits. */
3545228753Smm
3546228753Smm	if (a->todo & TODO_SGID_CHECK) {
3547228753Smm		/*
3548228753Smm		 * If we don't know the GID is right, we must stat()
3549228753Smm		 * to verify it.  We can't just check the GID of this
3550228753Smm		 * process, since systems sometimes set GID from
3551228753Smm		 * the enclosing dir or based on ACLs.
3552228753Smm		 */
3553231200Smm		if ((r = lazy_stat(a)) != ARCHIVE_OK)
3554228753Smm			return (r);
3555228753Smm		if (a->pst->st_gid != a->gid) {
3556228753Smm			mode &= ~ S_ISGID;
3557228753Smm			if (a->flags & ARCHIVE_EXTRACT_OWNER) {
3558228753Smm				/*
3559228753Smm				 * This is only an error if you
3560228753Smm				 * requested owner restore.  If you
3561228753Smm				 * didn't, we'll try to restore
3562228753Smm				 * sgid/suid, but won't consider it a
3563228753Smm				 * problem if we can't.
3564228753Smm				 */
3565228753Smm				archive_set_error(&a->archive, -1,
3566228753Smm				    "Can't restore SGID bit");
3567228753Smm				r = ARCHIVE_WARN;
3568228753Smm			}
3569228753Smm		}
3570228753Smm		/* While we're here, double-check the UID. */
3571228753Smm		if (a->pst->st_uid != a->uid
3572228753Smm		    && (a->todo & TODO_SUID)) {
3573228753Smm			mode &= ~ S_ISUID;
3574228753Smm			if (a->flags & ARCHIVE_EXTRACT_OWNER) {
3575228753Smm				archive_set_error(&a->archive, -1,
3576228753Smm				    "Can't restore SUID bit");
3577228753Smm				r = ARCHIVE_WARN;
3578228753Smm			}
3579228753Smm		}
3580228753Smm		a->todo &= ~TODO_SGID_CHECK;
3581228753Smm		a->todo &= ~TODO_SUID_CHECK;
3582228753Smm	} else if (a->todo & TODO_SUID_CHECK) {
3583228753Smm		/*
3584228753Smm		 * If we don't know the UID is right, we can just check
3585228753Smm		 * the user, since all systems set the file UID from
3586228753Smm		 * the process UID.
3587228753Smm		 */
3588228753Smm		if (a->user_uid != a->uid) {
3589228753Smm			mode &= ~ S_ISUID;
3590228753Smm			if (a->flags & ARCHIVE_EXTRACT_OWNER) {
3591228753Smm				archive_set_error(&a->archive, -1,
3592228753Smm				    "Can't make file SUID");
3593228753Smm				r = ARCHIVE_WARN;
3594228753Smm			}
3595228753Smm		}
3596228753Smm		a->todo &= ~TODO_SUID_CHECK;
3597228753Smm	}
3598228753Smm
3599228753Smm	if (S_ISLNK(a->mode)) {
3600228753Smm#ifdef HAVE_LCHMOD
3601228753Smm		/*
3602228753Smm		 * If this is a symlink, use lchmod().  If the
3603228753Smm		 * platform doesn't support lchmod(), just skip it.  A
3604228753Smm		 * platform that doesn't provide a way to set
3605228753Smm		 * permissions on symlinks probably ignores
3606228753Smm		 * permissions on symlinks, so a failure here has no
3607228753Smm		 * impact.
3608228753Smm		 */
3609228753Smm		if (lchmod(a->name, mode) != 0) {
3610302001Smm			switch (errno) {
3611302001Smm			case ENOTSUP:
3612302001Smm			case ENOSYS:
3613302001Smm#if ENOTSUP != EOPNOTSUPP
3614302001Smm			case EOPNOTSUPP:
3615302001Smm#endif
3616302001Smm				/*
3617302001Smm				 * if lchmod is defined but the platform
3618302001Smm				 * doesn't support it, silently ignore
3619302001Smm				 * error
3620302001Smm				 */
3621302001Smm				break;
3622302001Smm			default:
3623302001Smm				archive_set_error(&a->archive, errno,
3624302001Smm				    "Can't set permissions to 0%o", (int)mode);
3625302001Smm				r = ARCHIVE_WARN;
3626302001Smm			}
3627228753Smm		}
3628228753Smm#endif
3629228753Smm	} else if (!S_ISDIR(a->mode)) {
3630228753Smm		/*
3631228753Smm		 * If it's not a symlink and not a dir, then use
3632228753Smm		 * fchmod() or chmod(), depending on whether we have
3633228753Smm		 * an fd.  Dirs get their perms set during the
3634228753Smm		 * post-extract fixup, which is handled elsewhere.
3635228753Smm		 */
3636228753Smm#ifdef HAVE_FCHMOD
3637349525Smm		if (a->fd >= 0)
3638349525Smm			r2 = fchmod(a->fd, mode);
3639349525Smm		else
3640228753Smm#endif
3641349525Smm		/* If this platform lacks fchmod(), then
3642349525Smm		 * we'll just use chmod(). */
3643349525Smm		r2 = chmod(a->name, mode);
3644349525Smm
3645349525Smm		if (r2 != 0) {
3646349525Smm			archive_set_error(&a->archive, errno,
3647349525Smm			    "Can't set permissions to 0%o", (int)mode);
3648349525Smm			r = ARCHIVE_WARN;
3649349525Smm		}
3650228753Smm	}
3651228753Smm	return (r);
3652228753Smm}
3653228753Smm
3654228753Smmstatic int
3655228753Smmset_fflags(struct archive_write_disk *a)
3656228753Smm{
3657228753Smm	struct fixup_entry *le;
3658228753Smm	unsigned long	set, clear;
3659228753Smm	int		r;
3660228753Smm	mode_t		mode = archive_entry_mode(a->entry);
3661228753Smm	/*
3662228753Smm	 * Make 'critical_flags' hold all file flags that can't be
3663228753Smm	 * immediately restored.  For example, on BSD systems,
3664228753Smm	 * SF_IMMUTABLE prevents hardlinks from being created, so
3665228753Smm	 * should not be set until after any hardlinks are created.  To
3666228753Smm	 * preserve some semblance of portability, this uses #ifdef
3667228753Smm	 * extensively.  Ugly, but it works.
3668228753Smm	 *
3669228753Smm	 * Yes, Virginia, this does create a security race.  It's mitigated
3670228753Smm	 * somewhat by the practice of creating dirs 0700 until the extract
3671228753Smm	 * is done, but it would be nice if we could do more than that.
3672228753Smm	 * People restoring critical file systems should be wary of
3673228753Smm	 * other programs that might try to muck with files as they're
3674228753Smm	 * being restored.
3675228753Smm	 */
3676346105Smm	const int	critical_flags = 0
3677228753Smm#ifdef SF_IMMUTABLE
3678346105Smm	    | SF_IMMUTABLE
3679228753Smm#endif
3680228753Smm#ifdef UF_IMMUTABLE
3681346105Smm	    | UF_IMMUTABLE
3682228753Smm#endif
3683228753Smm#ifdef SF_APPEND
3684346105Smm	    | SF_APPEND
3685228753Smm#endif
3686228753Smm#ifdef UF_APPEND
3687346105Smm	    | UF_APPEND
3688228753Smm#endif
3689315433Smm#if defined(FS_APPEND_FL)
3690346105Smm	    | FS_APPEND_FL
3691315433Smm#elif defined(EXT2_APPEND_FL)
3692346105Smm	    | EXT2_APPEND_FL
3693228753Smm#endif
3694315433Smm#if defined(FS_IMMUTABLE_FL)
3695346105Smm	    | FS_IMMUTABLE_FL
3696315433Smm#elif defined(EXT2_IMMUTABLE_FL)
3697346105Smm	    | EXT2_IMMUTABLE_FL
3698228753Smm#endif
3699315433Smm#ifdef FS_JOURNAL_DATA_FL
3700346105Smm	    | FS_JOURNAL_DATA_FL
3701315433Smm#endif
3702346105Smm	;
3703228753Smm
3704228753Smm	if (a->todo & TODO_FFLAGS) {
3705228753Smm		archive_entry_fflags(a->entry, &set, &clear);
3706228753Smm
3707228753Smm		/*
3708228753Smm		 * The first test encourages the compiler to eliminate
3709228753Smm		 * all of this if it's not necessary.
3710228753Smm		 */
3711228753Smm		if ((critical_flags != 0)  &&  (set & critical_flags)) {
3712228753Smm			le = current_fixup(a, a->name);
3713248616Smm			if (le == NULL)
3714248616Smm				return (ARCHIVE_FATAL);
3715228753Smm			le->fixup |= TODO_FFLAGS;
3716228753Smm			le->fflags_set = set;
3717228753Smm			/* Store the mode if it's not already there. */
3718228753Smm			if ((le->fixup & TODO_MODE) == 0)
3719228753Smm				le->mode = mode;
3720228753Smm		} else {
3721228753Smm			r = set_fflags_platform(a, a->fd,
3722228753Smm			    a->name, mode, set, clear);
3723228753Smm			if (r != ARCHIVE_OK)
3724228753Smm				return (r);
3725228753Smm		}
3726228753Smm	}
3727228753Smm	return (ARCHIVE_OK);
3728228753Smm}
3729228753Smm
3730302001Smmstatic int
3731302001Smmclear_nochange_fflags(struct archive_write_disk *a)
3732302001Smm{
3733302001Smm	mode_t		mode = archive_entry_mode(a->entry);
3734346105Smm	const int nochange_flags = 0
3735302001Smm#ifdef SF_IMMUTABLE
3736346105Smm	    | SF_IMMUTABLE
3737302001Smm#endif
3738302001Smm#ifdef UF_IMMUTABLE
3739346105Smm	    | UF_IMMUTABLE
3740302001Smm#endif
3741302001Smm#ifdef SF_APPEND
3742346105Smm	    | SF_APPEND
3743302001Smm#endif
3744302001Smm#ifdef UF_APPEND
3745346105Smm	    | UF_APPEND
3746302001Smm#endif
3747302001Smm#ifdef EXT2_APPEND_FL
3748346105Smm	    | EXT2_APPEND_FL
3749302001Smm#endif
3750302001Smm#ifdef EXT2_IMMUTABLE_FL
3751346105Smm	    | EXT2_IMMUTABLE_FL
3752302001Smm#endif
3753346105Smm	;
3754302001Smm
3755309702Smm	return (set_fflags_platform(a, a->fd, a->name, mode, 0,
3756309702Smm	    nochange_flags));
3757302001Smm}
3758302001Smm
3759302001Smm
3760228753Smm#if ( defined(HAVE_LCHFLAGS) || defined(HAVE_CHFLAGS) || defined(HAVE_FCHFLAGS) ) && defined(HAVE_STRUCT_STAT_ST_FLAGS)
3761228753Smm/*
3762228753Smm * BSD reads flags using stat() and sets them with one of {f,l,}chflags()
3763228753Smm */
3764228753Smmstatic int
3765228753Smmset_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
3766228753Smm    mode_t mode, unsigned long set, unsigned long clear)
3767228753Smm{
3768228753Smm	int r;
3769346105Smm	const int sf_mask = 0
3770346105Smm#ifdef SF_APPEND
3771346105Smm	    | SF_APPEND
3772346105Smm#endif
3773346105Smm#ifdef SF_ARCHIVED
3774346105Smm	    | SF_ARCHIVED
3775346105Smm#endif
3776346105Smm#ifdef SF_IMMUTABLE
3777346105Smm	    | SF_IMMUTABLE
3778346105Smm#endif
3779346105Smm#ifdef SF_NOUNLINK
3780346105Smm	    | SF_NOUNLINK
3781346105Smm#endif
3782346105Smm	;
3783346105Smm	(void)mode; /* UNUSED */
3784228753Smm
3785228753Smm	if (set == 0  && clear == 0)
3786228753Smm		return (ARCHIVE_OK);
3787228753Smm
3788228753Smm	/*
3789228753Smm	 * XXX Is the stat here really necessary?  Or can I just use
3790228753Smm	 * the 'set' flags directly?  In particular, I'm not sure
3791228753Smm	 * about the correct approach if we're overwriting an existing
3792228753Smm	 * file that already has flags on it. XXX
3793228753Smm	 */
3794231200Smm	if ((r = lazy_stat(a)) != ARCHIVE_OK)
3795228753Smm		return (r);
3796228753Smm
3797228753Smm	a->st.st_flags &= ~clear;
3798228753Smm	a->st.st_flags |= set;
3799346105Smm
3800346105Smm	/* Only super-user may change SF_* flags */
3801346105Smm
3802346105Smm	if (a->user_uid != 0)
3803346105Smm		a->st.st_flags &= ~sf_mask;
3804346105Smm
3805228753Smm#ifdef HAVE_FCHFLAGS
3806228753Smm	/* If platform has fchflags() and we were given an fd, use it. */
3807228753Smm	if (fd >= 0 && fchflags(fd, a->st.st_flags) == 0)
3808228753Smm		return (ARCHIVE_OK);
3809228753Smm#endif
3810228753Smm	/*
3811228753Smm	 * If we can't use the fd to set the flags, we'll use the
3812228753Smm	 * pathname to set flags.  We prefer lchflags() but will use
3813228753Smm	 * chflags() if we must.
3814228753Smm	 */
3815228753Smm#ifdef HAVE_LCHFLAGS
3816228753Smm	if (lchflags(name, a->st.st_flags) == 0)
3817228753Smm		return (ARCHIVE_OK);
3818228753Smm#elif defined(HAVE_CHFLAGS)
3819228753Smm	if (S_ISLNK(a->st.st_mode)) {
3820228753Smm		archive_set_error(&a->archive, errno,
3821228753Smm		    "Can't set file flags on symlink.");
3822228753Smm		return (ARCHIVE_WARN);
3823228753Smm	}
3824228753Smm	if (chflags(name, a->st.st_flags) == 0)
3825228753Smm		return (ARCHIVE_OK);
3826228753Smm#endif
3827228753Smm	archive_set_error(&a->archive, errno,
3828228753Smm	    "Failed to set file flags");
3829228753Smm	return (ARCHIVE_WARN);
3830228753Smm}
3831228753Smm
3832315433Smm#elif (defined(FS_IOC_GETFLAGS) && defined(FS_IOC_SETFLAGS) && \
3833315433Smm       defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \
3834315433Smm      (defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS) && \
3835315433Smm       defined(HAVE_WORKING_EXT2_IOC_GETFLAGS))
3836228753Smm/*
3837228753Smm * Linux uses ioctl() to read and write file flags.
3838228753Smm */
3839228753Smmstatic int
3840228753Smmset_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
3841228753Smm    mode_t mode, unsigned long set, unsigned long clear)
3842228753Smm{
3843228753Smm	int		 ret;
3844228753Smm	int		 myfd = fd;
3845248616Smm	int newflags, oldflags;
3846346105Smm	/*
3847346105Smm	 * Linux has no define for the flags that are only settable by
3848346105Smm	 * the root user.  This code may seem a little complex, but
3849346105Smm	 * there seem to be some Linux systems that lack these
3850346105Smm	 * defines. (?)  The code below degrades reasonably gracefully
3851346105Smm	 * if sf_mask is incomplete.
3852346105Smm	 */
3853346105Smm	const int sf_mask = 0
3854346105Smm#if defined(FS_IMMUTABLE_FL)
3855346105Smm	    | FS_IMMUTABLE_FL
3856346105Smm#elif defined(EXT2_IMMUTABLE_FL)
3857346105Smm	    | EXT2_IMMUTABLE_FL
3858346105Smm#endif
3859346105Smm#if defined(FS_APPEND_FL)
3860346105Smm	    | FS_APPEND_FL
3861346105Smm#elif defined(EXT2_APPEND_FL)
3862346105Smm	    | EXT2_APPEND_FL
3863346105Smm#endif
3864346105Smm#if defined(FS_JOURNAL_DATA_FL)
3865346105Smm	    | FS_JOURNAL_DATA_FL
3866346105Smm#endif
3867346105Smm	;
3868228753Smm
3869315433Smm	if (set == 0 && clear == 0)
3870228753Smm		return (ARCHIVE_OK);
3871228753Smm	/* Only regular files and dirs can have flags. */
3872228753Smm	if (!S_ISREG(mode) && !S_ISDIR(mode))
3873228753Smm		return (ARCHIVE_OK);
3874228753Smm
3875228753Smm	/* If we weren't given an fd, open it ourselves. */
3876248616Smm	if (myfd < 0) {
3877248616Smm		myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY | O_CLOEXEC);
3878248616Smm		__archive_ensure_cloexec_flag(myfd);
3879248616Smm	}
3880228753Smm	if (myfd < 0)
3881228753Smm		return (ARCHIVE_OK);
3882228753Smm
3883228753Smm	/*
3884228753Smm	 * XXX As above, this would be way simpler if we didn't have
3885228753Smm	 * to read the current flags from disk. XXX
3886228753Smm	 */
3887228753Smm	ret = ARCHIVE_OK;
3888231200Smm
3889231200Smm	/* Read the current file flags. */
3890315433Smm	if (ioctl(myfd,
3891315433Smm#ifdef FS_IOC_GETFLAGS
3892315433Smm	    FS_IOC_GETFLAGS,
3893315433Smm#else
3894315433Smm	    EXT2_IOC_GETFLAGS,
3895315433Smm#endif
3896315433Smm	    &oldflags) < 0)
3897231200Smm		goto fail;
3898231200Smm
3899228753Smm	/* Try setting the flags as given. */
3900231200Smm	newflags = (oldflags & ~clear) | set;
3901315433Smm	if (ioctl(myfd,
3902315433Smm#ifdef FS_IOC_SETFLAGS
3903315433Smm	    FS_IOC_SETFLAGS,
3904315433Smm#else
3905315433Smm	    EXT2_IOC_SETFLAGS,
3906315433Smm#endif
3907315433Smm	    &newflags) >= 0)
3908231200Smm		goto cleanup;
3909231200Smm	if (errno != EPERM)
3910231200Smm		goto fail;
3911231200Smm
3912228753Smm	/* If we couldn't set all the flags, try again with a subset. */
3913231200Smm	newflags &= ~sf_mask;
3914231200Smm	oldflags &= sf_mask;
3915231200Smm	newflags |= oldflags;
3916315433Smm	if (ioctl(myfd,
3917315433Smm#ifdef FS_IOC_SETFLAGS
3918315433Smm	    FS_IOC_SETFLAGS,
3919315433Smm#else
3920315433Smm	    EXT2_IOC_SETFLAGS,
3921315433Smm#endif
3922315433Smm	    &newflags) >= 0)
3923231200Smm		goto cleanup;
3924231200Smm
3925228753Smm	/* We couldn't set the flags, so report the failure. */
3926228753Smmfail:
3927228753Smm	archive_set_error(&a->archive, errno,
3928228753Smm	    "Failed to set file flags");
3929228753Smm	ret = ARCHIVE_WARN;
3930228753Smmcleanup:
3931228753Smm	if (fd < 0)
3932228753Smm		close(myfd);
3933228753Smm	return (ret);
3934228753Smm}
3935228753Smm
3936228753Smm#else
3937228753Smm
3938228753Smm/*
3939228753Smm * Of course, some systems have neither BSD chflags() nor Linux' flags
3940228753Smm * support through ioctl().
3941228753Smm */
3942228753Smmstatic int
3943228753Smmset_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
3944228753Smm    mode_t mode, unsigned long set, unsigned long clear)
3945228753Smm{
3946228753Smm	(void)a; /* UNUSED */
3947228753Smm	(void)fd; /* UNUSED */
3948228753Smm	(void)name; /* UNUSED */
3949228753Smm	(void)mode; /* UNUSED */
3950228753Smm	(void)set; /* UNUSED */
3951228753Smm	(void)clear; /* UNUSED */
3952228753Smm	return (ARCHIVE_OK);
3953228753Smm}
3954228753Smm
3955228753Smm#endif /* __linux */
3956228753Smm
3957231200Smm#ifndef HAVE_COPYFILE_H
3958231200Smm/* Default is to simply drop Mac extended metadata. */
3959231200Smmstatic int
3960231200Smmset_mac_metadata(struct archive_write_disk *a, const char *pathname,
3961231200Smm		 const void *metadata, size_t metadata_size)
3962231200Smm{
3963231200Smm	(void)a; /* UNUSED */
3964231200Smm	(void)pathname; /* UNUSED */
3965231200Smm	(void)metadata; /* UNUSED */
3966231200Smm	(void)metadata_size; /* UNUSED */
3967231200Smm	return (ARCHIVE_OK);
3968231200Smm}
3969248616Smm
3970248616Smmstatic int
3971248616Smmfixup_appledouble(struct archive_write_disk *a, const char *pathname)
3972248616Smm{
3973248616Smm	(void)a; /* UNUSED */
3974248616Smm	(void)pathname; /* UNUSED */
3975248616Smm	return (ARCHIVE_OK);
3976248616Smm}
3977231200Smm#else
3978231200Smm
3979231200Smm/*
3980231200Smm * On Mac OS, we use copyfile() to unpack the metadata and
3981231200Smm * apply it to the target file.
3982231200Smm */
3983248616Smm
3984248616Smm#if defined(HAVE_SYS_XATTR_H)
3985231200Smmstatic int
3986248616Smmcopy_xattrs(struct archive_write_disk *a, int tmpfd, int dffd)
3987248616Smm{
3988248616Smm	ssize_t xattr_size;
3989248616Smm	char *xattr_names = NULL, *xattr_val = NULL;
3990248616Smm	int ret = ARCHIVE_OK, xattr_i;
3991248616Smm
3992248616Smm	xattr_size = flistxattr(tmpfd, NULL, 0, 0);
3993248616Smm	if (xattr_size == -1) {
3994248616Smm		archive_set_error(&a->archive, errno,
3995248616Smm		    "Failed to read metadata(xattr)");
3996248616Smm		ret = ARCHIVE_WARN;
3997248616Smm		goto exit_xattr;
3998248616Smm	}
3999248616Smm	xattr_names = malloc(xattr_size);
4000248616Smm	if (xattr_names == NULL) {
4001248616Smm		archive_set_error(&a->archive, ENOMEM,
4002248616Smm		    "Can't allocate memory for metadata(xattr)");
4003248616Smm		ret = ARCHIVE_FATAL;
4004248616Smm		goto exit_xattr;
4005248616Smm	}
4006248616Smm	xattr_size = flistxattr(tmpfd, xattr_names, xattr_size, 0);
4007248616Smm	if (xattr_size == -1) {
4008248616Smm		archive_set_error(&a->archive, errno,
4009248616Smm		    "Failed to read metadata(xattr)");
4010248616Smm		ret = ARCHIVE_WARN;
4011248616Smm		goto exit_xattr;
4012248616Smm	}
4013248616Smm	for (xattr_i = 0; xattr_i < xattr_size;
4014248616Smm	    xattr_i += strlen(xattr_names + xattr_i) + 1) {
4015302001Smm		char *xattr_val_saved;
4016248616Smm		ssize_t s;
4017248616Smm		int f;
4018248616Smm
4019248616Smm		s = fgetxattr(tmpfd, xattr_names + xattr_i, NULL, 0, 0, 0);
4020248616Smm		if (s == -1) {
4021248616Smm			archive_set_error(&a->archive, errno,
4022248616Smm			    "Failed to get metadata(xattr)");
4023248616Smm			ret = ARCHIVE_WARN;
4024248616Smm			goto exit_xattr;
4025248616Smm		}
4026302001Smm		xattr_val_saved = xattr_val;
4027248616Smm		xattr_val = realloc(xattr_val, s);
4028248616Smm		if (xattr_val == NULL) {
4029248616Smm			archive_set_error(&a->archive, ENOMEM,
4030248616Smm			    "Failed to get metadata(xattr)");
4031248616Smm			ret = ARCHIVE_WARN;
4032302001Smm			free(xattr_val_saved);
4033248616Smm			goto exit_xattr;
4034248616Smm		}
4035248616Smm		s = fgetxattr(tmpfd, xattr_names + xattr_i, xattr_val, s, 0, 0);
4036248616Smm		if (s == -1) {
4037248616Smm			archive_set_error(&a->archive, errno,
4038248616Smm			    "Failed to get metadata(xattr)");
4039248616Smm			ret = ARCHIVE_WARN;
4040248616Smm			goto exit_xattr;
4041248616Smm		}
4042248616Smm		f = fsetxattr(dffd, xattr_names + xattr_i, xattr_val, s, 0, 0);
4043248616Smm		if (f == -1) {
4044248616Smm			archive_set_error(&a->archive, errno,
4045248616Smm			    "Failed to get metadata(xattr)");
4046248616Smm			ret = ARCHIVE_WARN;
4047248616Smm			goto exit_xattr;
4048248616Smm		}
4049248616Smm	}
4050248616Smmexit_xattr:
4051248616Smm	free(xattr_names);
4052248616Smm	free(xattr_val);
4053248616Smm	return (ret);
4054248616Smm}
4055248616Smm#endif
4056248616Smm
4057248616Smmstatic int
4058248616Smmcopy_acls(struct archive_write_disk *a, int tmpfd, int dffd)
4059248616Smm{
4060302425Smm#ifndef HAVE_SYS_ACL_H
4061302425Smm	return 0;
4062302425Smm#else
4063248616Smm	acl_t acl, dfacl = NULL;
4064248616Smm	int acl_r, ret = ARCHIVE_OK;
4065248616Smm
4066248616Smm	acl = acl_get_fd(tmpfd);
4067248616Smm	if (acl == NULL) {
4068248616Smm		if (errno == ENOENT)
4069248616Smm			/* There are not any ACLs. */
4070248616Smm			return (ret);
4071248616Smm		archive_set_error(&a->archive, errno,
4072248616Smm		    "Failed to get metadata(acl)");
4073248616Smm		ret = ARCHIVE_WARN;
4074248616Smm		goto exit_acl;
4075248616Smm	}
4076248616Smm	dfacl = acl_dup(acl);
4077248616Smm	acl_r = acl_set_fd(dffd, dfacl);
4078248616Smm	if (acl_r == -1) {
4079248616Smm		archive_set_error(&a->archive, errno,
4080248616Smm		    "Failed to get metadata(acl)");
4081248616Smm		ret = ARCHIVE_WARN;
4082248616Smm		goto exit_acl;
4083248616Smm	}
4084248616Smmexit_acl:
4085248616Smm	if (acl)
4086248616Smm		acl_free(acl);
4087248616Smm	if (dfacl)
4088248616Smm		acl_free(dfacl);
4089248616Smm	return (ret);
4090302425Smm#endif
4091248616Smm}
4092248616Smm
4093248616Smmstatic int
4094248616Smmcreate_tempdatafork(struct archive_write_disk *a, const char *pathname)
4095248616Smm{
4096248616Smm	struct archive_string tmpdatafork;
4097248616Smm	int tmpfd;
4098248616Smm
4099248616Smm	archive_string_init(&tmpdatafork);
4100248616Smm	archive_strcpy(&tmpdatafork, "tar.md.XXXXXX");
4101248616Smm	tmpfd = mkstemp(tmpdatafork.s);
4102248616Smm	if (tmpfd < 0) {
4103248616Smm		archive_set_error(&a->archive, errno,
4104248616Smm		    "Failed to mkstemp");
4105248616Smm		archive_string_free(&tmpdatafork);
4106248616Smm		return (-1);
4107248616Smm	}
4108248616Smm	if (copyfile(pathname, tmpdatafork.s, 0,
4109248616Smm	    COPYFILE_UNPACK | COPYFILE_NOFOLLOW
4110248616Smm	    | COPYFILE_ACL | COPYFILE_XATTR) < 0) {
4111248616Smm		archive_set_error(&a->archive, errno,
4112248616Smm		    "Failed to restore metadata");
4113248616Smm		close(tmpfd);
4114248616Smm		tmpfd = -1;
4115248616Smm	}
4116248616Smm	unlink(tmpdatafork.s);
4117248616Smm	archive_string_free(&tmpdatafork);
4118248616Smm	return (tmpfd);
4119248616Smm}
4120248616Smm
4121248616Smmstatic int
4122248616Smmcopy_metadata(struct archive_write_disk *a, const char *metadata,
4123248616Smm    const char *datafork, int datafork_compressed)
4124248616Smm{
4125248616Smm	int ret = ARCHIVE_OK;
4126248616Smm
4127248616Smm	if (datafork_compressed) {
4128248616Smm		int dffd, tmpfd;
4129248616Smm
4130248616Smm		tmpfd = create_tempdatafork(a, metadata);
4131248616Smm		if (tmpfd == -1)
4132248616Smm			return (ARCHIVE_WARN);
4133248616Smm
4134248616Smm		/*
4135248616Smm		 * Do not open the data fork compressed by HFS+ compression
4136248616Smm		 * with at least a writing mode(O_RDWR or O_WRONLY). it
4137248616Smm		 * makes the data fork uncompressed.
4138248616Smm		 */
4139248616Smm		dffd = open(datafork, 0);
4140248616Smm		if (dffd == -1) {
4141248616Smm			archive_set_error(&a->archive, errno,
4142248616Smm			    "Failed to open the data fork for metadata");
4143248616Smm			close(tmpfd);
4144248616Smm			return (ARCHIVE_WARN);
4145248616Smm		}
4146248616Smm
4147248616Smm#if defined(HAVE_SYS_XATTR_H)
4148248616Smm		ret = copy_xattrs(a, tmpfd, dffd);
4149248616Smm		if (ret == ARCHIVE_OK)
4150248616Smm#endif
4151248616Smm			ret = copy_acls(a, tmpfd, dffd);
4152248616Smm		close(tmpfd);
4153248616Smm		close(dffd);
4154248616Smm	} else {
4155248616Smm		if (copyfile(metadata, datafork, 0,
4156248616Smm		    COPYFILE_UNPACK | COPYFILE_NOFOLLOW
4157248616Smm		    | COPYFILE_ACL | COPYFILE_XATTR) < 0) {
4158248616Smm			archive_set_error(&a->archive, errno,
4159248616Smm			    "Failed to restore metadata");
4160248616Smm			ret = ARCHIVE_WARN;
4161248616Smm		}
4162248616Smm	}
4163248616Smm	return (ret);
4164248616Smm}
4165248616Smm
4166248616Smmstatic int
4167231200Smmset_mac_metadata(struct archive_write_disk *a, const char *pathname,
4168231200Smm		 const void *metadata, size_t metadata_size)
4169231200Smm{
4170231200Smm	struct archive_string tmp;
4171231200Smm	ssize_t written;
4172231200Smm	int fd;
4173231200Smm	int ret = ARCHIVE_OK;
4174231200Smm
4175231200Smm	/* This would be simpler if copyfile() could just accept the
4176231200Smm	 * metadata as a block of memory; then we could sidestep this
4177231200Smm	 * silly dance of writing the data to disk just so that
4178231200Smm	 * copyfile() can read it back in again. */
4179231200Smm	archive_string_init(&tmp);
4180231200Smm	archive_strcpy(&tmp, pathname);
4181231200Smm	archive_strcat(&tmp, ".XXXXXX");
4182231200Smm	fd = mkstemp(tmp.s);
4183231200Smm
4184231200Smm	if (fd < 0) {
4185231200Smm		archive_set_error(&a->archive, errno,
4186231200Smm				  "Failed to restore metadata");
4187248616Smm		archive_string_free(&tmp);
4188231200Smm		return (ARCHIVE_WARN);
4189231200Smm	}
4190231200Smm	written = write(fd, metadata, metadata_size);
4191231200Smm	close(fd);
4192248616Smm	if ((size_t)written != metadata_size) {
4193231200Smm		archive_set_error(&a->archive, errno,
4194231200Smm				  "Failed to restore metadata");
4195231200Smm		ret = ARCHIVE_WARN;
4196248616Smm	} else {
4197248616Smm		int compressed;
4198248616Smm
4199248616Smm#if defined(UF_COMPRESSED)
4200248616Smm		if ((a->todo & TODO_HFS_COMPRESSION) != 0 &&
4201248616Smm		    (ret = lazy_stat(a)) == ARCHIVE_OK)
4202248616Smm			compressed = a->st.st_flags & UF_COMPRESSED;
4203248616Smm		else
4204248616Smm#endif
4205248616Smm			compressed = 0;
4206248616Smm		ret = copy_metadata(a, tmp.s, pathname, compressed);
4207231200Smm	}
4208231200Smm	unlink(tmp.s);
4209248616Smm	archive_string_free(&tmp);
4210231200Smm	return (ret);
4211231200Smm}
4212248616Smm
4213248616Smmstatic int
4214248616Smmfixup_appledouble(struct archive_write_disk *a, const char *pathname)
4215248616Smm{
4216248616Smm	char buff[8];
4217248616Smm	struct stat st;
4218248616Smm	const char *p;
4219248616Smm	struct archive_string datafork;
4220248616Smm	int fd = -1, ret = ARCHIVE_OK;
4221248616Smm
4222248616Smm	archive_string_init(&datafork);
4223248616Smm	/* Check if the current file name is a type of the resource
4224248616Smm	 * fork file. */
4225248616Smm	p = strrchr(pathname, '/');
4226248616Smm	if (p == NULL)
4227248616Smm		p = pathname;
4228248616Smm	else
4229248616Smm		p++;
4230248616Smm	if (p[0] != '.' || p[1] != '_')
4231248616Smm		goto skip_appledouble;
4232248616Smm
4233248616Smm	/*
4234248616Smm	 * Check if the data fork file exists.
4235248616Smm	 *
4236248616Smm	 * TODO: Check if this write disk object has handled it.
4237248616Smm	 */
4238248616Smm	archive_strncpy(&datafork, pathname, p - pathname);
4239248616Smm	archive_strcat(&datafork, p + 2);
4240248616Smm	if (lstat(datafork.s, &st) == -1 ||
4241248616Smm	    (st.st_mode & AE_IFMT) != AE_IFREG)
4242248616Smm		goto skip_appledouble;
4243248616Smm
4244248616Smm	/*
4245248616Smm	 * Check if the file is in the AppleDouble form.
4246248616Smm	 */
4247248616Smm	fd = open(pathname, O_RDONLY | O_BINARY | O_CLOEXEC);
4248248616Smm	__archive_ensure_cloexec_flag(fd);
4249248616Smm	if (fd == -1) {
4250248616Smm		archive_set_error(&a->archive, errno,
4251248616Smm		    "Failed to open a restoring file");
4252248616Smm		ret = ARCHIVE_WARN;
4253248616Smm		goto skip_appledouble;
4254248616Smm	}
4255248616Smm	if (read(fd, buff, 8) == -1) {
4256248616Smm		archive_set_error(&a->archive, errno,
4257248616Smm		    "Failed to read a restoring file");
4258248616Smm		close(fd);
4259248616Smm		ret = ARCHIVE_WARN;
4260248616Smm		goto skip_appledouble;
4261248616Smm	}
4262248616Smm	close(fd);
4263248616Smm	/* Check AppleDouble Magic Code. */
4264248616Smm	if (archive_be32dec(buff) != 0x00051607)
4265248616Smm		goto skip_appledouble;
4266248616Smm	/* Check AppleDouble Version. */
4267248616Smm	if (archive_be32dec(buff+4) != 0x00020000)
4268248616Smm		goto skip_appledouble;
4269248616Smm
4270248616Smm	ret = copy_metadata(a, pathname, datafork.s,
4271248616Smm#if defined(UF_COMPRESSED)
4272248616Smm	    st.st_flags & UF_COMPRESSED);
4273248616Smm#else
4274248616Smm	    0);
4275231200Smm#endif
4276248616Smm	if (ret == ARCHIVE_OK) {
4277248616Smm		unlink(pathname);
4278248616Smm		ret = ARCHIVE_EOF;
4279248616Smm	}
4280248616Smmskip_appledouble:
4281248616Smm	archive_string_free(&datafork);
4282248616Smm	return (ret);
4283248616Smm}
4284248616Smm#endif
4285231200Smm
4286316338Smm#if ARCHIVE_XATTR_LINUX || ARCHIVE_XATTR_DARWIN || ARCHIVE_XATTR_AIX
4287228753Smm/*
4288316338Smm * Restore extended attributes -  Linux, Darwin and AIX implementations:
4289231200Smm * AIX' ea interface is syntaxwise identical to the Linux xattr interface.
4290228753Smm */
4291228753Smmstatic int
4292228753Smmset_xattrs(struct archive_write_disk *a)
4293228753Smm{
4294228753Smm	struct archive_entry *entry = a->entry;
4295353377Smm	struct archive_string errlist;
4296228753Smm	int ret = ARCHIVE_OK;
4297228753Smm	int i = archive_entry_xattr_reset(entry);
4298353377Smm	short fail = 0;
4299228753Smm
4300353377Smm	archive_string_init(&errlist);
4301353377Smm
4302228753Smm	while (i--) {
4303228753Smm		const char *name;
4304228753Smm		const void *value;
4305228753Smm		size_t size;
4306353377Smm		int e;
4307353377Smm
4308228753Smm		archive_entry_xattr_next(entry, &name, &value, &size);
4309353377Smm
4310353377Smm		if (name == NULL)
4311353377Smm			continue;
4312316338Smm#if ARCHIVE_XATTR_LINUX
4313353377Smm		/* Linux: quietly skip POSIX.1e ACL extended attributes */
4314353377Smm		if (strncmp(name, "system.", 7) == 0 &&
4315353377Smm		   (strcmp(name + 7, "posix_acl_access") == 0 ||
4316353377Smm		    strcmp(name + 7, "posix_acl_default") == 0))
4317353377Smm			continue;
4318353377Smm		if (strncmp(name, "trusted.SGI_", 12) == 0 &&
4319353377Smm		   (strcmp(name + 12, "ACL_DEFAULT") == 0 ||
4320353377Smm		    strcmp(name + 12, "ACL_FILE") == 0))
4321353377Smm			continue;
4322353377Smm
4323353377Smm		/* Linux: xfsroot namespace is obsolete and unsupported */
4324353377Smm		if (strncmp(name, "xfsroot.", 8) == 0) {
4325353377Smm			fail = 1;
4326353377Smm			archive_strcat(&errlist, name);
4327353377Smm			archive_strappend_char(&errlist, ' ');
4328353377Smm			continue;
4329353377Smm		}
4330353377Smm#endif
4331353377Smm
4332353377Smm		if (a->fd >= 0) {
4333353377Smm#if ARCHIVE_XATTR_LINUX
4334353377Smm			e = fsetxattr(a->fd, name, value, size, 0);
4335316338Smm#elif ARCHIVE_XATTR_DARWIN
4336353377Smm			e = fsetxattr(a->fd, name, value, size, 0, 0);
4337316338Smm#elif ARCHIVE_XATTR_AIX
4338353377Smm			e = fsetea(a->fd, name, value, size, 0);
4339228753Smm#endif
4340353377Smm		} else {
4341316338Smm#if ARCHIVE_XATTR_LINUX
4342353377Smm			e = lsetxattr(archive_entry_pathname(entry),
4343353377Smm			    name, value, size, 0);
4344316338Smm#elif ARCHIVE_XATTR_DARWIN
4345353377Smm			e = setxattr(archive_entry_pathname(entry),
4346353377Smm			    name, value, size, 0, XATTR_NOFOLLOW);
4347316338Smm#elif ARCHIVE_XATTR_AIX
4348353377Smm			e = lsetea(archive_entry_pathname(entry),
4349353377Smm			    name, value, size, 0);
4350231200Smm#endif
4351353377Smm		}
4352353377Smm		if (e == -1) {
4353228753Smm			ret = ARCHIVE_WARN;
4354353377Smm			archive_strcat(&errlist, name);
4355353377Smm			archive_strappend_char(&errlist, ' ');
4356353377Smm			if (errno != ENOTSUP && errno != ENOSYS)
4357353377Smm				fail = 1;
4358228753Smm		}
4359228753Smm	}
4360353377Smm
4361353377Smm	if (ret == ARCHIVE_WARN) {
4362353377Smm		if (fail && errlist.length > 0) {
4363353377Smm			errlist.length--;
4364353377Smm			errlist.s[errlist.length] = '\0';
4365353377Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
4366353377Smm			    "Cannot restore extended attributes: %s",
4367353377Smm			    errlist.s);
4368353377Smm		} else
4369353377Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
4370353377Smm			    "Cannot restore extended "
4371353377Smm			    "attributes on this file system.");
4372353377Smm	}
4373353377Smm
4374353377Smm	archive_string_free(&errlist);
4375228753Smm	return (ret);
4376228753Smm}
4377316338Smm#elif ARCHIVE_XATTR_FREEBSD
4378228753Smm/*
4379228753Smm * Restore extended attributes -  FreeBSD implementation
4380228753Smm */
4381228753Smmstatic int
4382228753Smmset_xattrs(struct archive_write_disk *a)
4383228753Smm{
4384228753Smm	struct archive_entry *entry = a->entry;
4385353377Smm	struct archive_string errlist;
4386228753Smm	int ret = ARCHIVE_OK;
4387228753Smm	int i = archive_entry_xattr_reset(entry);
4388353377Smm	short fail = 0;
4389228753Smm
4390353377Smm	archive_string_init(&errlist);
4391353377Smm
4392228753Smm	while (i--) {
4393228753Smm		const char *name;
4394228753Smm		const void *value;
4395228753Smm		size_t size;
4396228753Smm		archive_entry_xattr_next(entry, &name, &value, &size);
4397228753Smm		if (name != NULL) {
4398248995Smdf			ssize_t e;
4399228753Smm			int namespace;
4400228753Smm
4401368708Smm			namespace = EXTATTR_NAMESPACE_USER;
4402368708Smm
4403228753Smm			if (strncmp(name, "user.", 5) == 0) {
4404228753Smm				/* "user." attributes go to user namespace */
4405228753Smm				name += 5;
4406228753Smm				namespace = EXTATTR_NAMESPACE_USER;
4407368708Smm			} else if (strncmp(name, "system.", 7) == 0) {
4408368708Smm				name += 7;
4409368708Smm				namespace = EXTATTR_NAMESPACE_SYSTEM;
4410368708Smm				if (!strcmp(name, "nfs4.acl") ||
4411368708Smm				    !strcmp(name, "posix1e.acl_access") ||
4412368708Smm				    !strcmp(name, "posix1e.acl_default"))
4413368708Smm					continue;
4414228753Smm			} else {
4415353377Smm				/* Other namespaces are unsupported */
4416353377Smm				archive_strcat(&errlist, name);
4417353377Smm				archive_strappend_char(&errlist, ' ');
4418353377Smm				fail = 1;
4419228753Smm				ret = ARCHIVE_WARN;
4420228753Smm				continue;
4421228753Smm			}
4422316338Smm
4423316338Smm			if (a->fd >= 0) {
4424368708Smm				/*
4425368708Smm				 * On FreeBSD, extattr_set_fd does not
4426368708Smm				 * return the same as
4427368708Smm				 * extattr_set_file. It returns zero
4428368708Smm				 * on success, non-zero on failure.
4429368708Smm				 *
4430368708Smm				 * We can detect the failure by
4431368708Smm				 * manually setting errno prior to the
4432368708Smm				 * call and checking after.
4433368708Smm				 *
4434368708Smm				 * If errno remains zero, fake the
4435368708Smm				 * return value by setting e to size.
4436368708Smm				 *
4437368708Smm				 * This is a hack for now until I
4438368708Smm				 * (Shawn Webb) get FreeBSD to fix the
4439368708Smm				 * issue, if that's even possible.
4440368708Smm				 */
4441368708Smm				errno = 0;
4442309702Smm				e = extattr_set_fd(a->fd, namespace, name,
4443309702Smm				    value, size);
4444368708Smm				if (e == 0 && errno == 0) {
4445368708Smm					e = size;
4446368708Smm				}
4447316338Smm			} else {
4448316338Smm				e = extattr_set_link(
4449309702Smm				    archive_entry_pathname(entry), namespace,
4450309702Smm				    name, value, size);
4451228753Smm			}
4452248995Smdf			if (e != (ssize_t)size) {
4453353377Smm				archive_strcat(&errlist, name);
4454353377Smm				archive_strappend_char(&errlist, ' ');
4455228753Smm				ret = ARCHIVE_WARN;
4456353377Smm				if (errno != ENOTSUP && errno != ENOSYS)
4457353377Smm					fail = 1;
4458228753Smm			}
4459228753Smm		}
4460228753Smm	}
4461353377Smm
4462353377Smm	if (ret == ARCHIVE_WARN) {
4463353377Smm		if (fail && errlist.length > 0) {
4464353377Smm			errlist.length--;
4465353377Smm			errlist.s[errlist.length] = '\0';
4466353377Smm
4467353377Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
4468353377Smm			    "Cannot restore extended attributes: %s",
4469353377Smm			    errlist.s);
4470353377Smm		} else
4471353377Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
4472353377Smm			    "Cannot restore extended "
4473353377Smm			    "attributes on this file system.");
4474353377Smm	}
4475353377Smm
4476353377Smm	archive_string_free(&errlist);
4477228753Smm	return (ret);
4478228753Smm}
4479228753Smm#else
4480228753Smm/*
4481228753Smm * Restore extended attributes - stub implementation for unsupported systems
4482228753Smm */
4483228753Smmstatic int
4484228753Smmset_xattrs(struct archive_write_disk *a)
4485228753Smm{
4486228753Smm	static int warning_done = 0;
4487228753Smm
4488228753Smm	/* If there aren't any extended attributes, then it's okay not
4489228753Smm	 * to extract them, otherwise, issue a single warning. */
4490228753Smm	if (archive_entry_xattr_count(a->entry) != 0 && !warning_done) {
4491228753Smm		warning_done = 1;
4492228753Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
4493228753Smm		    "Cannot restore extended attributes on this system");
4494228753Smm		return (ARCHIVE_WARN);
4495228753Smm	}
4496228753Smm	/* Warning was already emitted; suppress further warnings. */
4497228753Smm	return (ARCHIVE_OK);
4498228753Smm}
4499228753Smm#endif
4500228753Smm
4501228753Smm/*
4502228753Smm * Test if file on disk is older than entry.
4503228753Smm */
4504228753Smmstatic int
4505228753Smmolder(struct stat *st, struct archive_entry *entry)
4506228753Smm{
4507228753Smm	/* First, test the seconds and return if we have a definite answer. */
4508228753Smm	/* Definitely older. */
4509313571Smm	if (to_int64_time(st->st_mtime) < to_int64_time(archive_entry_mtime(entry)))
4510228753Smm		return (1);
4511228753Smm	/* Definitely younger. */
4512313571Smm	if (to_int64_time(st->st_mtime) > to_int64_time(archive_entry_mtime(entry)))
4513228753Smm		return (0);
4514228753Smm	/* If this platform supports fractional seconds, try those. */
4515228753Smm#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
4516228753Smm	/* Definitely older. */
4517228753Smm	if (st->st_mtimespec.tv_nsec < archive_entry_mtime_nsec(entry))
4518228753Smm		return (1);
4519228753Smm#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
4520228753Smm	/* Definitely older. */
4521228753Smm	if (st->st_mtim.tv_nsec < archive_entry_mtime_nsec(entry))
4522228753Smm		return (1);
4523228753Smm#elif HAVE_STRUCT_STAT_ST_MTIME_N
4524228753Smm	/* older. */
4525228753Smm	if (st->st_mtime_n < archive_entry_mtime_nsec(entry))
4526228753Smm		return (1);
4527228753Smm#elif HAVE_STRUCT_STAT_ST_UMTIME
4528228753Smm	/* older. */
4529228753Smm	if (st->st_umtime * 1000 < archive_entry_mtime_nsec(entry))
4530228753Smm		return (1);
4531228753Smm#elif HAVE_STRUCT_STAT_ST_MTIME_USEC
4532228753Smm	/* older. */
4533228753Smm	if (st->st_mtime_usec * 1000 < archive_entry_mtime_nsec(entry))
4534228753Smm		return (1);
4535228753Smm#else
4536228753Smm	/* This system doesn't have high-res timestamps. */
4537228753Smm#endif
4538228753Smm	/* Same age or newer, so not older. */
4539228753Smm	return (0);
4540228753Smm}
4541231200Smm
4542316338Smm#ifndef ARCHIVE_ACL_SUPPORT
4543316338Smmint
4544316338Smmarchive_write_disk_set_acls(struct archive *a, int fd, const char *name,
4545316338Smm    struct archive_acl *abstract_acl, __LA_MODE_T mode)
4546316338Smm{
4547316338Smm	(void)a; /* UNUSED */
4548316338Smm	(void)fd; /* UNUSED */
4549316338Smm	(void)name; /* UNUSED */
4550316338Smm	(void)abstract_acl; /* UNUSED */
4551316338Smm	(void)mode; /* UNUSED */
4552316338Smm	return (ARCHIVE_OK);
4553316338Smm}
4554316338Smm#endif
4555316338Smm
4556231200Smm#endif /* !_WIN32 || __CYGWIN__ */
4557231200Smm
4558