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
42248616Smm#if defined(HAVE_SYS_XATTR_H)
43228753Smm#include <sys/xattr.h>
44248616Smm#elif defined(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
113231200Smm#if __APPLE__
114231200Smm#include <TargetConditionals.h>
115231200Smm#if TARGET_OS_MAC && !TARGET_OS_EMBEDDED && HAVE_QUARANTINE_H
116231200Smm#include <quarantine.h>
117231200Smm#define HAVE_QUARANTINE 1
118231200Smm#endif
119231200Smm#endif
120231200Smm
121248616Smm#ifdef HAVE_ZLIB_H
122248616Smm#include <zlib.h>
123248616Smm#endif
124248616Smm
125231200Smm/* TODO: Support Mac OS 'quarantine' feature.  This is really just a
126231200Smm * standard tag to mark files that have been downloaded as "tainted".
127231200Smm * On Mac OS, we should mark the extracted files as tainted if the
128231200Smm * archive being read was tainted.  Windows has a similar feature; we
129231200Smm * should investigate ways to support this generically. */
130231200Smm
131228753Smm#include "archive.h"
132231200Smm#include "archive_acl_private.h"
133228753Smm#include "archive_string.h"
134248616Smm#include "archive_endian.h"
135228753Smm#include "archive_entry.h"
136228753Smm#include "archive_private.h"
137238909Smm#include "archive_write_disk_private.h"
138228753Smm
139228753Smm#ifndef O_BINARY
140228753Smm#define O_BINARY 0
141228753Smm#endif
142248616Smm#ifndef O_CLOEXEC
143306941Sdelphij#define O_CLOEXEC 0
144248616Smm#endif
145228753Smm
146306941Sdelphij/* Ignore non-int O_NOFOLLOW constant. */
147306941Sdelphij/* gnulib's fcntl.h does this on AIX, but it seems practical everywhere */
148306941Sdelphij#if defined O_NOFOLLOW && !(INT_MIN <= O_NOFOLLOW && O_NOFOLLOW <= INT_MAX)
149306941Sdelphij#undef O_NOFOLLOW
150306941Sdelphij#endif
151306941Sdelphij
152306941Sdelphij#ifndef O_NOFOLLOW
153306941Sdelphij#define O_NOFOLLOW 0
154306941Sdelphij#endif
155306941Sdelphij
156228753Smmstruct fixup_entry {
157228753Smm	struct fixup_entry	*next;
158231200Smm	struct archive_acl	 acl;
159228753Smm	mode_t			 mode;
160228753Smm	int64_t			 atime;
161228753Smm	int64_t                  birthtime;
162228753Smm	int64_t			 mtime;
163231200Smm	int64_t			 ctime;
164228753Smm	unsigned long		 atime_nanos;
165228753Smm	unsigned long            birthtime_nanos;
166228753Smm	unsigned long		 mtime_nanos;
167231200Smm	unsigned long		 ctime_nanos;
168228753Smm	unsigned long		 fflags_set;
169231200Smm	size_t			 mac_metadata_size;
170231200Smm	void			*mac_metadata;
171228753Smm	int			 fixup; /* bitmask of what needs fixing */
172228753Smm	char			*name;
173228753Smm};
174228753Smm
175228753Smm/*
176228753Smm * We use a bitmask to track which operations remain to be done for
177228753Smm * this file.  In particular, this helps us avoid unnecessary
178228753Smm * operations when it's possible to take care of one step as a
179228753Smm * side-effect of another.  For example, mkdir() can specify the mode
180228753Smm * for the newly-created object but symlink() cannot.  This means we
181228753Smm * can skip chmod() if mkdir() succeeded, but we must explicitly
182228753Smm * chmod() if we're trying to create a directory that already exists
183228753Smm * (mkdir() failed) or if we're restoring a symlink.  Similarly, we
184228753Smm * need to verify UID/GID before trying to restore SUID/SGID bits;
185228753Smm * that verification can occur explicitly through a stat() call or
186228753Smm * implicitly because of a successful chown() call.
187228753Smm */
188228753Smm#define	TODO_MODE_FORCE		0x40000000
189228753Smm#define	TODO_MODE_BASE		0x20000000
190228753Smm#define	TODO_SUID		0x10000000
191228753Smm#define	TODO_SUID_CHECK		0x08000000
192228753Smm#define	TODO_SGID		0x04000000
193228753Smm#define	TODO_SGID_CHECK		0x02000000
194248616Smm#define	TODO_APPLEDOUBLE	0x01000000
195228753Smm#define	TODO_MODE		(TODO_MODE_BASE|TODO_SUID|TODO_SGID)
196228753Smm#define	TODO_TIMES		ARCHIVE_EXTRACT_TIME
197228753Smm#define	TODO_OWNER		ARCHIVE_EXTRACT_OWNER
198228753Smm#define	TODO_FFLAGS		ARCHIVE_EXTRACT_FFLAGS
199228753Smm#define	TODO_ACLS		ARCHIVE_EXTRACT_ACL
200228753Smm#define	TODO_XATTR		ARCHIVE_EXTRACT_XATTR
201231200Smm#define	TODO_MAC_METADATA	ARCHIVE_EXTRACT_MAC_METADATA
202248616Smm#define	TODO_HFS_COMPRESSION	ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED
203228753Smm
204228753Smmstruct archive_write_disk {
205228753Smm	struct archive	archive;
206228753Smm
207228753Smm	mode_t			 user_umask;
208228753Smm	struct fixup_entry	*fixup_list;
209228753Smm	struct fixup_entry	*current_fixup;
210231200Smm	int64_t			 user_uid;
211231200Smm	int			 skip_file_set;
212238856Smm	int64_t			 skip_file_dev;
213238856Smm	int64_t			 skip_file_ino;
214228753Smm	time_t			 start_time;
215228753Smm
216231200Smm	int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid);
217228753Smm	void  (*cleanup_gid)(void *private);
218228753Smm	void			*lookup_gid_data;
219231200Smm	int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid);
220228753Smm	void  (*cleanup_uid)(void *private);
221228753Smm	void			*lookup_uid_data;
222228753Smm
223228753Smm	/*
224228753Smm	 * Full path of last file to satisfy symlink checks.
225228753Smm	 */
226228753Smm	struct archive_string	path_safe;
227228753Smm
228228753Smm	/*
229228753Smm	 * Cached stat data from disk for the current entry.
230228753Smm	 * If this is valid, pst points to st.  Otherwise,
231228753Smm	 * pst is null.
232228753Smm	 */
233228753Smm	struct stat		 st;
234228753Smm	struct stat		*pst;
235228753Smm
236228753Smm	/* Information about the object being restored right now. */
237228753Smm	struct archive_entry	*entry; /* Entry being extracted. */
238228753Smm	char			*name; /* Name of entry, possibly edited. */
239228753Smm	struct archive_string	 _name_data; /* backing store for 'name' */
240228753Smm	/* Tasks remaining for this object. */
241228753Smm	int			 todo;
242228753Smm	/* Tasks deferred until end-of-archive. */
243228753Smm	int			 deferred;
244228753Smm	/* Options requested by the client. */
245228753Smm	int			 flags;
246228753Smm	/* Handle for the file we're restoring. */
247228753Smm	int			 fd;
248228753Smm	/* Current offset for writing data to the file. */
249231200Smm	int64_t			 offset;
250228753Smm	/* Last offset actually written to disk. */
251231200Smm	int64_t			 fd_offset;
252231200Smm	/* Total bytes actually written to files. */
253231200Smm	int64_t			 total_bytes_written;
254228753Smm	/* Maximum size of file, -1 if unknown. */
255231200Smm	int64_t			 filesize;
256228753Smm	/* Dir we were in before this restore; only for deep paths. */
257228753Smm	int			 restore_pwd;
258228753Smm	/* Mode we should use for this entry; affected by _PERM and umask. */
259228753Smm	mode_t			 mode;
260228753Smm	/* UID/GID to use in restoring this entry. */
261231200Smm	int64_t			 uid;
262231200Smm	int64_t			 gid;
263248616Smm	/*
264248616Smm	 * HFS+ Compression.
265248616Smm	 */
266248616Smm	/* Xattr "com.apple.decmpfs". */
267248616Smm	uint32_t		 decmpfs_attr_size;
268248616Smm	unsigned char		*decmpfs_header_p;
269248616Smm	/* ResourceFork set options used for fsetxattr. */
270248616Smm	int			 rsrc_xattr_options;
271248616Smm	/* Xattr "com.apple.ResourceFork". */
272248616Smm	unsigned char		*resource_fork;
273248616Smm	size_t			 resource_fork_allocated_size;
274248616Smm	unsigned int		 decmpfs_block_count;
275248616Smm	uint32_t		*decmpfs_block_info;
276248616Smm	/* Buffer for compressed data. */
277248616Smm	unsigned char		*compressed_buffer;
278248616Smm	size_t			 compressed_buffer_size;
279248616Smm	size_t			 compressed_buffer_remaining;
280248616Smm	/* The offset of the ResourceFork where compressed data will
281248616Smm	 * be placed. */
282248616Smm	uint32_t		 compressed_rsrc_position;
283248616Smm	uint32_t		 compressed_rsrc_position_v;
284248616Smm	/* Buffer for uncompressed data. */
285248616Smm	char			*uncompressed_buffer;
286248616Smm	size_t			 block_remaining_bytes;
287248616Smm	size_t			 file_remaining_bytes;
288248616Smm#ifdef HAVE_ZLIB_H
289248616Smm	z_stream		 stream;
290248616Smm	int			 stream_valid;
291248616Smm	int			 decmpfs_compression_level;
292248616Smm#endif
293228753Smm};
294228753Smm
295228753Smm/*
296228753Smm * Default mode for dirs created automatically (will be modified by umask).
297231200Smm * Note that POSIX specifies 0777 for implicitly-created dirs, "modified
298228753Smm * by the process' file creation mask."
299228753Smm */
300228753Smm#define	DEFAULT_DIR_MODE 0777
301228753Smm/*
302228753Smm * Dir modes are restored in two steps:  During the extraction, the permissions
303228753Smm * in the archive are modified to match the following limits.  During
304228753Smm * the post-extract fixup pass, the permissions from the archive are
305228753Smm * applied.
306228753Smm */
307228753Smm#define	MINIMUM_DIR_MODE 0700
308228753Smm#define	MAXIMUM_DIR_MODE 0775
309228753Smm
310248616Smm/*
311248616Smm * Maxinum uncompressed size of a decmpfs block.
312248616Smm */
313248616Smm#define MAX_DECMPFS_BLOCK_SIZE	(64 * 1024)
314248616Smm/*
315248616Smm * HFS+ compression type.
316248616Smm */
317248616Smm#define CMP_XATTR		3/* Compressed data in xattr. */
318248616Smm#define CMP_RESOURCE_FORK	4/* Compressed data in resource fork. */
319248616Smm/*
320248616Smm * HFS+ compression resource fork.
321248616Smm */
322248616Smm#define RSRC_H_SIZE	260	/* Base size of Resource fork header. */
323248616Smm#define RSRC_F_SIZE	50	/* Size of Resource fork footer. */
324248616Smm/* Size to write compressed data to resource fork. */
325248616Smm#define COMPRESSED_W_SIZE	(64 * 1024)
326248616Smm/* decmpfs difinitions. */
327248616Smm#define MAX_DECMPFS_XATTR_SIZE		3802
328248616Smm#ifndef DECMPFS_XATTR_NAME
329248616Smm#define DECMPFS_XATTR_NAME		"com.apple.decmpfs"
330248616Smm#endif
331248616Smm#define DECMPFS_MAGIC			0x636d7066
332248616Smm#define DECMPFS_COMPRESSION_MAGIC	0
333248616Smm#define DECMPFS_COMPRESSION_TYPE	4
334248616Smm#define DECMPFS_UNCOMPRESSED_SIZE	8
335248616Smm#define DECMPFS_HEADER_SIZE		16
336248616Smm
337248616Smm#define HFS_BLOCKS(s)	((s) >> 12)
338248616Smm
339306941Sdelphijstatic int	check_symlinks_fsobj(char *path, int *error_number, struct archive_string *error_string, int flags);
340228753Smmstatic int	check_symlinks(struct archive_write_disk *);
341228753Smmstatic int	create_filesystem_object(struct archive_write_disk *);
342228753Smmstatic struct fixup_entry *current_fixup(struct archive_write_disk *, const char *pathname);
343231200Smm#if defined(HAVE_FCHDIR) && defined(PATH_MAX)
344228753Smmstatic void	edit_deep_directories(struct archive_write_disk *ad);
345228753Smm#endif
346306941Sdelphijstatic int	cleanup_pathname_fsobj(char *path, int *error_number, struct archive_string *error_string, int flags);
347228753Smmstatic int	cleanup_pathname(struct archive_write_disk *);
348228753Smmstatic int	create_dir(struct archive_write_disk *, char *);
349228753Smmstatic int	create_parent_dir(struct archive_write_disk *, char *);
350248616Smmstatic ssize_t	hfs_write_data_block(struct archive_write_disk *,
351248616Smm		    const char *, size_t);
352248616Smmstatic int	fixup_appledouble(struct archive_write_disk *, const char *);
353228753Smmstatic int	older(struct stat *, struct archive_entry *);
354228753Smmstatic int	restore_entry(struct archive_write_disk *);
355231200Smmstatic int	set_mac_metadata(struct archive_write_disk *, const char *,
356231200Smm				 const void *, size_t);
357228753Smmstatic int	set_xattrs(struct archive_write_disk *);
358228753Smmstatic int	set_fflags(struct archive_write_disk *);
359228753Smmstatic int	set_fflags_platform(struct archive_write_disk *, int fd,
360228753Smm		    const char *name, mode_t mode,
361228753Smm		    unsigned long fflags_set, unsigned long fflags_clear);
362228753Smmstatic int	set_ownership(struct archive_write_disk *);
363228753Smmstatic int	set_mode(struct archive_write_disk *, int mode);
364228753Smmstatic int	set_time(int, int, const char *, time_t, long, time_t, long);
365231200Smmstatic int	set_times(struct archive_write_disk *, int, int, const char *,
366231200Smm		    time_t, long, time_t, long, time_t, long, time_t, long);
367231200Smmstatic int	set_times_from_entry(struct archive_write_disk *);
368228753Smmstatic struct fixup_entry *sort_dir_list(struct fixup_entry *p);
369228753Smmstatic ssize_t	write_data_block(struct archive_write_disk *,
370228753Smm		    const char *, size_t);
371228753Smm
372228753Smmstatic struct archive_vtable *archive_write_disk_vtable(void);
373228753Smm
374231200Smmstatic int	_archive_write_disk_close(struct archive *);
375231200Smmstatic int	_archive_write_disk_free(struct archive *);
376231200Smmstatic int	_archive_write_disk_header(struct archive *, struct archive_entry *);
377231200Smmstatic int64_t	_archive_write_disk_filter_bytes(struct archive *, int);
378231200Smmstatic int	_archive_write_disk_finish_entry(struct archive *);
379231200Smmstatic ssize_t	_archive_write_disk_data(struct archive *, const void *, size_t);
380231200Smmstatic ssize_t	_archive_write_disk_data_block(struct archive *, const void *, size_t, int64_t);
381228753Smm
382228753Smmstatic int
383231200Smmlazy_stat(struct archive_write_disk *a)
384228753Smm{
385228753Smm	if (a->pst != NULL) {
386228753Smm		/* Already have stat() data available. */
387228753Smm		return (ARCHIVE_OK);
388228753Smm	}
389228753Smm#ifdef HAVE_FSTAT
390228753Smm	if (a->fd >= 0 && fstat(a->fd, &a->st) == 0) {
391228753Smm		a->pst = &a->st;
392228753Smm		return (ARCHIVE_OK);
393228753Smm	}
394228753Smm#endif
395228753Smm	/*
396228753Smm	 * XXX At this point, symlinks should not be hit, otherwise
397231200Smm	 * XXX a race occurred.  Do we want to check explicitly for that?
398228753Smm	 */
399228753Smm	if (lstat(a->name, &a->st) == 0) {
400228753Smm		a->pst = &a->st;
401228753Smm		return (ARCHIVE_OK);
402228753Smm	}
403228753Smm	archive_set_error(&a->archive, errno, "Couldn't stat file");
404228753Smm	return (ARCHIVE_WARN);
405228753Smm}
406228753Smm
407228753Smmstatic struct archive_vtable *
408228753Smmarchive_write_disk_vtable(void)
409228753Smm{
410228753Smm	static struct archive_vtable av;
411228753Smm	static int inited = 0;
412228753Smm
413228753Smm	if (!inited) {
414231200Smm		av.archive_close = _archive_write_disk_close;
415231200Smm		av.archive_filter_bytes = _archive_write_disk_filter_bytes;
416231200Smm		av.archive_free = _archive_write_disk_free;
417231200Smm		av.archive_write_header = _archive_write_disk_header;
418231200Smm		av.archive_write_finish_entry
419231200Smm		    = _archive_write_disk_finish_entry;
420231200Smm		av.archive_write_data = _archive_write_disk_data;
421231200Smm		av.archive_write_data_block = _archive_write_disk_data_block;
422231200Smm		inited = 1;
423228753Smm	}
424228753Smm	return (&av);
425228753Smm}
426228753Smm
427231200Smmstatic int64_t
428231200Smm_archive_write_disk_filter_bytes(struct archive *_a, int n)
429231200Smm{
430231200Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
431231200Smm	(void)n; /* UNUSED */
432231200Smm	if (n == -1 || n == 0)
433231200Smm		return (a->total_bytes_written);
434231200Smm	return (-1);
435231200Smm}
436228753Smm
437231200Smm
438228753Smmint
439228753Smmarchive_write_disk_set_options(struct archive *_a, int flags)
440228753Smm{
441228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
442228753Smm
443228753Smm	a->flags = flags;
444228753Smm	return (ARCHIVE_OK);
445228753Smm}
446228753Smm
447228753Smm
448228753Smm/*
449228753Smm * Extract this entry to disk.
450228753Smm *
451228753Smm * TODO: Validate hardlinks.  According to the standards, we're
452228753Smm * supposed to check each extracted hardlink and squawk if it refers
453228753Smm * to a file that we didn't restore.  I'm not entirely convinced this
454228753Smm * is a good idea, but more importantly: Is there any way to validate
455228753Smm * hardlinks without keeping a complete list of filenames from the
456228753Smm * entire archive?? Ugh.
457228753Smm *
458228753Smm */
459228753Smmstatic int
460231200Smm_archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
461228753Smm{
462228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
463228753Smm	struct fixup_entry *fe;
464228753Smm	int ret, r;
465228753Smm
466231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
467228753Smm	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
468228753Smm	    "archive_write_disk_header");
469228753Smm	archive_clear_error(&a->archive);
470228753Smm	if (a->archive.state & ARCHIVE_STATE_DATA) {
471231200Smm		r = _archive_write_disk_finish_entry(&a->archive);
472228753Smm		if (r == ARCHIVE_FATAL)
473228753Smm			return (r);
474228753Smm	}
475228753Smm
476228753Smm	/* Set up for this particular entry. */
477228753Smm	a->pst = NULL;
478228753Smm	a->current_fixup = NULL;
479228753Smm	a->deferred = 0;
480228753Smm	if (a->entry) {
481228753Smm		archive_entry_free(a->entry);
482228753Smm		a->entry = NULL;
483228753Smm	}
484228753Smm	a->entry = archive_entry_clone(entry);
485228753Smm	a->fd = -1;
486228753Smm	a->fd_offset = 0;
487228753Smm	a->offset = 0;
488231200Smm	a->restore_pwd = -1;
489228753Smm	a->uid = a->user_uid;
490228753Smm	a->mode = archive_entry_mode(a->entry);
491228753Smm	if (archive_entry_size_is_set(a->entry))
492228753Smm		a->filesize = archive_entry_size(a->entry);
493228753Smm	else
494228753Smm		a->filesize = -1;
495228753Smm	archive_strcpy(&(a->_name_data), archive_entry_pathname(a->entry));
496228753Smm	a->name = a->_name_data.s;
497228753Smm	archive_clear_error(&a->archive);
498228753Smm
499228753Smm	/*
500228753Smm	 * Clean up the requested path.  This is necessary for correct
501228753Smm	 * dir restores; the dir restore logic otherwise gets messed
502228753Smm	 * up by nonsense like "dir/.".
503228753Smm	 */
504228753Smm	ret = cleanup_pathname(a);
505228753Smm	if (ret != ARCHIVE_OK)
506228753Smm		return (ret);
507228753Smm
508228753Smm	/*
509231200Smm	 * Query the umask so we get predictable mode settings.
510228753Smm	 * This gets done on every call to _write_header in case the
511228753Smm	 * user edits their umask during the extraction for some
512231200Smm	 * reason.
513228753Smm	 */
514231200Smm	umask(a->user_umask = umask(0));
515228753Smm
516228753Smm	/* Figure out what we need to do for this entry. */
517228753Smm	a->todo = TODO_MODE_BASE;
518228753Smm	if (a->flags & ARCHIVE_EXTRACT_PERM) {
519228753Smm		a->todo |= TODO_MODE_FORCE; /* Be pushy about permissions. */
520228753Smm		/*
521228753Smm		 * SGID requires an extra "check" step because we
522228753Smm		 * cannot easily predict the GID that the system will
523228753Smm		 * assign.  (Different systems assign GIDs to files
524228753Smm		 * based on a variety of criteria, including process
525228753Smm		 * credentials and the gid of the enclosing
526228753Smm		 * directory.)  We can only restore the SGID bit if
527228753Smm		 * the file has the right GID, and we only know the
528228753Smm		 * GID if we either set it (see set_ownership) or if
529228753Smm		 * we've actually called stat() on the file after it
530228753Smm		 * was restored.  Since there are several places at
531228753Smm		 * which we might verify the GID, we need a TODO bit
532228753Smm		 * to keep track.
533228753Smm		 */
534228753Smm		if (a->mode & S_ISGID)
535228753Smm			a->todo |= TODO_SGID | TODO_SGID_CHECK;
536228753Smm		/*
537228753Smm		 * Verifying the SUID is simpler, but can still be
538228753Smm		 * done in multiple ways, hence the separate "check" bit.
539228753Smm		 */
540228753Smm		if (a->mode & S_ISUID)
541228753Smm			a->todo |= TODO_SUID | TODO_SUID_CHECK;
542228753Smm	} else {
543228753Smm		/*
544228753Smm		 * User didn't request full permissions, so don't
545228753Smm		 * restore SUID, SGID bits and obey umask.
546228753Smm		 */
547228753Smm		a->mode &= ~S_ISUID;
548228753Smm		a->mode &= ~S_ISGID;
549228753Smm		a->mode &= ~S_ISVTX;
550228753Smm		a->mode &= ~a->user_umask;
551228753Smm	}
552228753Smm	if (a->flags & ARCHIVE_EXTRACT_OWNER)
553228753Smm		a->todo |= TODO_OWNER;
554228753Smm	if (a->flags & ARCHIVE_EXTRACT_TIME)
555228753Smm		a->todo |= TODO_TIMES;
556231200Smm	if (a->flags & ARCHIVE_EXTRACT_ACL) {
557231200Smm		if (archive_entry_filetype(a->entry) == AE_IFDIR)
558231200Smm			a->deferred |= TODO_ACLS;
559231200Smm		else
560231200Smm			a->todo |= TODO_ACLS;
561231200Smm	}
562231200Smm	if (a->flags & ARCHIVE_EXTRACT_MAC_METADATA) {
563231200Smm		if (archive_entry_filetype(a->entry) == AE_IFDIR)
564231200Smm			a->deferred |= TODO_MAC_METADATA;
565231200Smm		else
566231200Smm			a->todo |= TODO_MAC_METADATA;
567231200Smm	}
568248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H)
569248616Smm	if ((a->flags & ARCHIVE_EXTRACT_NO_HFS_COMPRESSION) == 0) {
570248616Smm		unsigned long set, clear;
571248616Smm		archive_entry_fflags(a->entry, &set, &clear);
572248616Smm		if ((set & ~clear) & UF_COMPRESSED) {
573248616Smm			a->todo |= TODO_HFS_COMPRESSION;
574248616Smm			a->decmpfs_block_count = (unsigned)-1;
575248616Smm		}
576248616Smm	}
577248616Smm	if ((a->flags & ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED) != 0 &&
578248616Smm	    (a->mode & AE_IFMT) == AE_IFREG && a->filesize > 0) {
579248616Smm		a->todo |= TODO_HFS_COMPRESSION;
580248616Smm		a->decmpfs_block_count = (unsigned)-1;
581248616Smm	}
582248616Smm	{
583248616Smm		const char *p;
584248616Smm
585248616Smm		/* Check if the current file name is a type of the
586248616Smm		 * resource fork file. */
587248616Smm		p = strrchr(a->name, '/');
588248616Smm		if (p == NULL)
589248616Smm			p = a->name;
590248616Smm		else
591248616Smm			p++;
592248616Smm		if (p[0] == '.' && p[1] == '_') {
593248616Smm			/* Do not compress "._XXX" files. */
594248616Smm			a->todo &= ~TODO_HFS_COMPRESSION;
595248616Smm			if (a->filesize > 0)
596248616Smm				a->todo |= TODO_APPLEDOUBLE;
597248616Smm		}
598248616Smm	}
599248616Smm#endif
600248616Smm
601228753Smm	if (a->flags & ARCHIVE_EXTRACT_XATTR)
602228753Smm		a->todo |= TODO_XATTR;
603228753Smm	if (a->flags & ARCHIVE_EXTRACT_FFLAGS)
604228753Smm		a->todo |= TODO_FFLAGS;
605228753Smm	if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) {
606228753Smm		ret = check_symlinks(a);
607228753Smm		if (ret != ARCHIVE_OK)
608231200Smm			return (ret);
609228753Smm	}
610231200Smm#if defined(HAVE_FCHDIR) && defined(PATH_MAX)
611228753Smm	/* If path exceeds PATH_MAX, shorten the path. */
612228753Smm	edit_deep_directories(a);
613228753Smm#endif
614228753Smm
615228753Smm	ret = restore_entry(a);
616228753Smm
617248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H)
618228753Smm	/*
619248616Smm	 * Check if the filesystem the file is restoring on supports
620248616Smm	 * HFS+ Compression. If not, cancel HFS+ Compression.
621248616Smm	 */
622248616Smm	if (a->todo | TODO_HFS_COMPRESSION) {
623248616Smm		/*
624248616Smm		 * NOTE: UF_COMPRESSED is ignored even if the filesystem
625248616Smm		 * supports HFS+ Compression because the file should
626248616Smm		 * have at least an extended attriute "com.apple.decmpfs"
627248616Smm		 * before the flag is set to indicate that the file have
628248616Smm		 * been compressed. If hte filesystem does not support
629248616Smm		 * HFS+ Compression the system call will fail.
630248616Smm		 */
631248616Smm		if (a->fd < 0 || fchflags(a->fd, UF_COMPRESSED) != 0)
632248616Smm			a->todo &= ~TODO_HFS_COMPRESSION;
633248616Smm	}
634248616Smm#endif
635248616Smm
636248616Smm	/*
637228753Smm	 * TODO: There are rumours that some extended attributes must
638228753Smm	 * be restored before file data is written.  If this is true,
639228753Smm	 * then we either need to write all extended attributes both
640228753Smm	 * before and after restoring the data, or find some rule for
641228753Smm	 * determining which must go first and which last.  Due to the
642228753Smm	 * many ways people are using xattrs, this may prove to be an
643228753Smm	 * intractable problem.
644228753Smm	 */
645228753Smm
646228753Smm#ifdef HAVE_FCHDIR
647228753Smm	/* If we changed directory above, restore it here. */
648228753Smm	if (a->restore_pwd >= 0) {
649228753Smm		r = fchdir(a->restore_pwd);
650228753Smm		if (r != 0) {
651228753Smm			archive_set_error(&a->archive, errno, "chdir() failure");
652228753Smm			ret = ARCHIVE_FATAL;
653228753Smm		}
654228753Smm		close(a->restore_pwd);
655228753Smm		a->restore_pwd = -1;
656228753Smm	}
657228753Smm#endif
658228753Smm
659228753Smm	/*
660228753Smm	 * Fixup uses the unedited pathname from archive_entry_pathname(),
661228753Smm	 * because it is relative to the base dir and the edited path
662228753Smm	 * might be relative to some intermediate dir as a result of the
663228753Smm	 * deep restore logic.
664228753Smm	 */
665228753Smm	if (a->deferred & TODO_MODE) {
666228753Smm		fe = current_fixup(a, archive_entry_pathname(entry));
667248616Smm		if (fe == NULL)
668248616Smm			return (ARCHIVE_FATAL);
669228753Smm		fe->fixup |= TODO_MODE_BASE;
670228753Smm		fe->mode = a->mode;
671228753Smm	}
672228753Smm
673228753Smm	if ((a->deferred & TODO_TIMES)
674228753Smm		&& (archive_entry_mtime_is_set(entry)
675228753Smm		    || archive_entry_atime_is_set(entry))) {
676228753Smm		fe = current_fixup(a, archive_entry_pathname(entry));
677248616Smm		if (fe == NULL)
678248616Smm			return (ARCHIVE_FATAL);
679231200Smm		fe->mode = a->mode;
680228753Smm		fe->fixup |= TODO_TIMES;
681228753Smm		if (archive_entry_atime_is_set(entry)) {
682228753Smm			fe->atime = archive_entry_atime(entry);
683228753Smm			fe->atime_nanos = archive_entry_atime_nsec(entry);
684228753Smm		} else {
685228753Smm			/* If atime is unset, use start time. */
686228753Smm			fe->atime = a->start_time;
687228753Smm			fe->atime_nanos = 0;
688228753Smm		}
689228753Smm		if (archive_entry_mtime_is_set(entry)) {
690228753Smm			fe->mtime = archive_entry_mtime(entry);
691228753Smm			fe->mtime_nanos = archive_entry_mtime_nsec(entry);
692228753Smm		} else {
693228753Smm			/* If mtime is unset, use start time. */
694228753Smm			fe->mtime = a->start_time;
695228753Smm			fe->mtime_nanos = 0;
696228753Smm		}
697228753Smm		if (archive_entry_birthtime_is_set(entry)) {
698228753Smm			fe->birthtime = archive_entry_birthtime(entry);
699228753Smm			fe->birthtime_nanos = archive_entry_birthtime_nsec(entry);
700228753Smm		} else {
701228753Smm			/* If birthtime is unset, use mtime. */
702228753Smm			fe->birthtime = fe->mtime;
703228753Smm			fe->birthtime_nanos = fe->mtime_nanos;
704228753Smm		}
705228753Smm	}
706228753Smm
707231200Smm	if (a->deferred & TODO_ACLS) {
708231200Smm		fe = current_fixup(a, archive_entry_pathname(entry));
709248616Smm		if (fe == NULL)
710248616Smm			return (ARCHIVE_FATAL);
711238909Smm		fe->fixup |= TODO_ACLS;
712231200Smm		archive_acl_copy(&fe->acl, archive_entry_acl(entry));
713231200Smm	}
714231200Smm
715231200Smm	if (a->deferred & TODO_MAC_METADATA) {
716231200Smm		const void *metadata;
717231200Smm		size_t metadata_size;
718231200Smm		metadata = archive_entry_mac_metadata(a->entry, &metadata_size);
719231200Smm		if (metadata != NULL && metadata_size > 0) {
720231200Smm			fe = current_fixup(a, archive_entry_pathname(entry));
721248616Smm			if (fe == NULL)
722248616Smm				return (ARCHIVE_FATAL);
723231200Smm			fe->mac_metadata = malloc(metadata_size);
724231200Smm			if (fe->mac_metadata != NULL) {
725231200Smm				memcpy(fe->mac_metadata, metadata, metadata_size);
726231200Smm				fe->mac_metadata_size = metadata_size;
727231200Smm				fe->fixup |= TODO_MAC_METADATA;
728231200Smm			}
729231200Smm		}
730231200Smm	}
731231200Smm
732228753Smm	if (a->deferred & TODO_FFLAGS) {
733228753Smm		fe = current_fixup(a, archive_entry_pathname(entry));
734248616Smm		if (fe == NULL)
735248616Smm			return (ARCHIVE_FATAL);
736228753Smm		fe->fixup |= TODO_FFLAGS;
737228753Smm		/* TODO: Complete this.. defer fflags from below. */
738228753Smm	}
739228753Smm
740228753Smm	/* We've created the object and are ready to pour data into it. */
741228753Smm	if (ret >= ARCHIVE_WARN)
742228753Smm		a->archive.state = ARCHIVE_STATE_DATA;
743228753Smm	/*
744228753Smm	 * If it's not open, tell our client not to try writing.
745228753Smm	 * In particular, dirs, links, etc, don't get written to.
746228753Smm	 */
747228753Smm	if (a->fd < 0) {
748228753Smm		archive_entry_set_size(entry, 0);
749228753Smm		a->filesize = 0;
750228753Smm	}
751228753Smm
752228753Smm	return (ret);
753228753Smm}
754228753Smm
755228753Smmint
756231200Smmarchive_write_disk_set_skip_file(struct archive *_a, int64_t d, int64_t i)
757228753Smm{
758228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
759231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
760228753Smm	    ARCHIVE_STATE_ANY, "archive_write_disk_set_skip_file");
761231200Smm	a->skip_file_set = 1;
762228753Smm	a->skip_file_dev = d;
763228753Smm	a->skip_file_ino = i;
764228753Smm	return (ARCHIVE_OK);
765228753Smm}
766228753Smm
767228753Smmstatic ssize_t
768228753Smmwrite_data_block(struct archive_write_disk *a, const char *buff, size_t size)
769228753Smm{
770228753Smm	uint64_t start_size = size;
771228753Smm	ssize_t bytes_written = 0;
772228753Smm	ssize_t block_size = 0, bytes_to_write;
773228753Smm
774228753Smm	if (size == 0)
775228753Smm		return (ARCHIVE_OK);
776228753Smm
777228753Smm	if (a->filesize == 0 || a->fd < 0) {
778228753Smm		archive_set_error(&a->archive, 0,
779228753Smm		    "Attempt to write to an empty file");
780228753Smm		return (ARCHIVE_WARN);
781228753Smm	}
782228753Smm
783228753Smm	if (a->flags & ARCHIVE_EXTRACT_SPARSE) {
784228753Smm#if HAVE_STRUCT_STAT_ST_BLKSIZE
785228753Smm		int r;
786231200Smm		if ((r = lazy_stat(a)) != ARCHIVE_OK)
787228753Smm			return (r);
788228753Smm		block_size = a->pst->st_blksize;
789228753Smm#else
790228753Smm		/* XXX TODO XXX Is there a more appropriate choice here ? */
791228753Smm		/* This needn't match the filesystem allocation size. */
792228753Smm		block_size = 16*1024;
793228753Smm#endif
794228753Smm	}
795228753Smm
796228753Smm	/* If this write would run beyond the file size, truncate it. */
797231200Smm	if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize)
798228753Smm		start_size = size = (size_t)(a->filesize - a->offset);
799228753Smm
800228753Smm	/* Write the data. */
801228753Smm	while (size > 0) {
802228753Smm		if (block_size == 0) {
803228753Smm			bytes_to_write = size;
804228753Smm		} else {
805228753Smm			/* We're sparsifying the file. */
806228753Smm			const char *p, *end;
807231200Smm			int64_t block_end;
808228753Smm
809228753Smm			/* Skip leading zero bytes. */
810228753Smm			for (p = buff, end = buff + size; p < end; ++p) {
811228753Smm				if (*p != '\0')
812228753Smm					break;
813228753Smm			}
814228753Smm			a->offset += p - buff;
815228753Smm			size -= p - buff;
816228753Smm			buff = p;
817228753Smm			if (size == 0)
818228753Smm				break;
819228753Smm
820228753Smm			/* Calculate next block boundary after offset. */
821228753Smm			block_end
822228753Smm			    = (a->offset / block_size + 1) * block_size;
823228753Smm
824228753Smm			/* If the adjusted write would cross block boundary,
825228753Smm			 * truncate it to the block boundary. */
826228753Smm			bytes_to_write = size;
827228753Smm			if (a->offset + bytes_to_write > block_end)
828228753Smm				bytes_to_write = block_end - a->offset;
829228753Smm		}
830228753Smm		/* Seek if necessary to the specified offset. */
831228753Smm		if (a->offset != a->fd_offset) {
832228753Smm			if (lseek(a->fd, a->offset, SEEK_SET) < 0) {
833228753Smm				archive_set_error(&a->archive, errno,
834228753Smm				    "Seek failed");
835228753Smm				return (ARCHIVE_FATAL);
836228753Smm			}
837228753Smm			a->fd_offset = a->offset;
838231200Smm		}
839228753Smm		bytes_written = write(a->fd, buff, bytes_to_write);
840228753Smm		if (bytes_written < 0) {
841228753Smm			archive_set_error(&a->archive, errno, "Write failed");
842228753Smm			return (ARCHIVE_WARN);
843228753Smm		}
844228753Smm		buff += bytes_written;
845228753Smm		size -= bytes_written;
846231200Smm		a->total_bytes_written += bytes_written;
847228753Smm		a->offset += bytes_written;
848228753Smm		a->fd_offset = a->offset;
849228753Smm	}
850228753Smm	return (start_size - size);
851228753Smm}
852228753Smm
853248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\
854248616Smm	&& defined(HAVE_ZLIB_H)
855248616Smm
856248616Smm/*
857248616Smm * Set UF_COMPRESSED file flag.
858248616Smm * This have to be called after hfs_write_decmpfs() because if the
859248616Smm * file does not have "com.apple.decmpfs" xattr the flag is ignored.
860248616Smm */
861248616Smmstatic int
862248616Smmhfs_set_compressed_fflag(struct archive_write_disk *a)
863248616Smm{
864248616Smm	int r;
865248616Smm
866248616Smm	if ((r = lazy_stat(a)) != ARCHIVE_OK)
867248616Smm		return (r);
868248616Smm
869248616Smm	a->st.st_flags |= UF_COMPRESSED;
870248616Smm	if (fchflags(a->fd, a->st.st_flags) != 0) {
871248616Smm		archive_set_error(&a->archive, errno,
872248616Smm		    "Failed to set UF_COMPRESSED file flag");
873248616Smm		return (ARCHIVE_WARN);
874248616Smm	}
875248616Smm	return (ARCHIVE_OK);
876248616Smm}
877248616Smm
878248616Smm/*
879248616Smm * HFS+ Compression decmpfs
880248616Smm *
881248616Smm *     +------------------------------+ +0
882248616Smm *     |      Magic(LE 4 bytes)       |
883248616Smm *     +------------------------------+
884248616Smm *     |      Type(LE 4 bytes)        |
885248616Smm *     +------------------------------+
886248616Smm *     | Uncompressed size(LE 8 bytes)|
887248616Smm *     +------------------------------+ +16
888248616Smm *     |                              |
889248616Smm *     |       Compressed data        |
890248616Smm *     |  (Placed only if Type == 3)  |
891248616Smm *     |                              |
892248616Smm *     +------------------------------+  +3802 = MAX_DECMPFS_XATTR_SIZE
893248616Smm *
894248616Smm *  Type is 3: decmpfs has compressed data.
895248616Smm *  Type is 4: Resource Fork has compressed data.
896248616Smm */
897248616Smm/*
898248616Smm * Write "com.apple.decmpfs"
899248616Smm */
900248616Smmstatic int
901248616Smmhfs_write_decmpfs(struct archive_write_disk *a)
902248616Smm{
903248616Smm	int r;
904248616Smm	uint32_t compression_type;
905248616Smm
906248616Smm	r = fsetxattr(a->fd, DECMPFS_XATTR_NAME, a->decmpfs_header_p,
907248616Smm	    a->decmpfs_attr_size, 0, 0);
908248616Smm	if (r < 0) {
909248616Smm		archive_set_error(&a->archive, errno,
910248616Smm		    "Cannot restore xattr:%s", DECMPFS_XATTR_NAME);
911248616Smm		compression_type = archive_le32dec(
912248616Smm		    &a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE]);
913248616Smm		if (compression_type == CMP_RESOURCE_FORK)
914248616Smm			fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME,
915248616Smm			    XATTR_SHOWCOMPRESSION);
916248616Smm		return (ARCHIVE_WARN);
917248616Smm	}
918248616Smm	return (ARCHIVE_OK);
919248616Smm}
920248616Smm
921248616Smm/*
922248616Smm * HFS+ Compression Resource Fork
923248616Smm *
924248616Smm *     +-----------------------------+
925248616Smm *     |     Header(260 bytes)       |
926248616Smm *     +-----------------------------+
927248616Smm *     |   Block count(LE 4 bytes)   |
928248616Smm *     +-----------------------------+  --+
929248616Smm * +-- |     Offset (LE 4 bytes)     |    |
930248616Smm * |   | [distance from Block count] |    | Block 0
931248616Smm * |   +-----------------------------+    |
932248616Smm * |   | Compressed size(LE 4 bytes) |    |
933248616Smm * |   +-----------------------------+  --+
934248616Smm * |   |                             |
935248616Smm * |   |      ..................     |
936248616Smm * |   |                             |
937248616Smm * |   +-----------------------------+  --+
938248616Smm * |   |     Offset (LE 4 bytes)     |    |
939248616Smm * |   +-----------------------------+    | Block (Block count -1)
940248616Smm * |   | Compressed size(LE 4 bytes) |    |
941248616Smm * +-> +-----------------------------+  --+
942248616Smm *     |   Compressed data(n bytes)  |  Block 0
943248616Smm *     +-----------------------------+
944248616Smm *     |                             |
945248616Smm *     |      ..................     |
946248616Smm *     |                             |
947248616Smm *     +-----------------------------+
948248616Smm *     |   Compressed data(n bytes)  |  Block (Block count -1)
949248616Smm *     +-----------------------------+
950248616Smm *     |      Footer(50 bytes)       |
951248616Smm *     +-----------------------------+
952248616Smm *
953248616Smm */
954248616Smm/*
955248616Smm * Write the header of "com.apple.ResourceFork"
956248616Smm */
957248616Smmstatic int
958248616Smmhfs_write_resource_fork(struct archive_write_disk *a, unsigned char *buff,
959248616Smm    size_t bytes, uint32_t position)
960248616Smm{
961248616Smm	int ret;
962248616Smm
963248616Smm	ret = fsetxattr(a->fd, XATTR_RESOURCEFORK_NAME, buff, bytes,
964248616Smm	    position, a->rsrc_xattr_options);
965248616Smm	if (ret < 0) {
966248616Smm		archive_set_error(&a->archive, errno,
967248616Smm		    "Cannot restore xattr: %s at %u pos %u bytes",
968248616Smm		    XATTR_RESOURCEFORK_NAME,
969248616Smm		    (unsigned)position,
970248616Smm		    (unsigned)bytes);
971248616Smm		return (ARCHIVE_WARN);
972248616Smm	}
973248616Smm	a->rsrc_xattr_options &= ~XATTR_CREATE;
974248616Smm	return (ARCHIVE_OK);
975248616Smm}
976248616Smm
977248616Smmstatic int
978248616Smmhfs_write_compressed_data(struct archive_write_disk *a, size_t bytes_compressed)
979248616Smm{
980248616Smm	int ret;
981248616Smm
982248616Smm	ret = hfs_write_resource_fork(a, a->compressed_buffer,
983248616Smm	    bytes_compressed, a->compressed_rsrc_position);
984248616Smm	if (ret == ARCHIVE_OK)
985248616Smm		a->compressed_rsrc_position += bytes_compressed;
986248616Smm	return (ret);
987248616Smm}
988248616Smm
989248616Smmstatic int
990248616Smmhfs_write_resource_fork_header(struct archive_write_disk *a)
991248616Smm{
992248616Smm	unsigned char *buff;
993248616Smm	uint32_t rsrc_bytes;
994248616Smm	uint32_t rsrc_header_bytes;
995248616Smm
996248616Smm	/*
997248616Smm	 * Write resource fork header + block info.
998248616Smm	 */
999248616Smm	buff = a->resource_fork;
1000248616Smm	rsrc_bytes = a->compressed_rsrc_position - RSRC_F_SIZE;
1001248616Smm	rsrc_header_bytes =
1002248616Smm		RSRC_H_SIZE +		/* Header base size. */
1003248616Smm		4 +			/* Block count. */
1004248616Smm		(a->decmpfs_block_count * 8);/* Block info */
1005248616Smm	archive_be32enc(buff, 0x100);
1006248616Smm	archive_be32enc(buff + 4, rsrc_bytes);
1007248616Smm	archive_be32enc(buff + 8, rsrc_bytes - 256);
1008248616Smm	archive_be32enc(buff + 12, 0x32);
1009248616Smm	memset(buff + 16, 0, 240);
1010248616Smm	archive_be32enc(buff + 256, rsrc_bytes - 260);
1011248616Smm	return hfs_write_resource_fork(a, buff, rsrc_header_bytes, 0);
1012248616Smm}
1013248616Smm
1014248616Smmstatic size_t
1015248616Smmhfs_set_resource_fork_footer(unsigned char *buff, size_t buff_size)
1016248616Smm{
1017248616Smm	static const char rsrc_footer[RSRC_F_SIZE] = {
1018248616Smm		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1019248616Smm		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1020248616Smm		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1021248616Smm		0x00, 0x1c, 0x00, 0x32, 0x00, 0x00, 'c',  'm',
1022248616Smm		'p', 'f',   0x00, 0x00, 0x00, 0x0a, 0x00, 0x01,
1023248616Smm		0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1024248616Smm		0x00, 0x00
1025248616Smm	};
1026248616Smm	if (buff_size < sizeof(rsrc_footer))
1027248616Smm		return (0);
1028248616Smm	memcpy(buff, rsrc_footer, sizeof(rsrc_footer));
1029248616Smm	return (sizeof(rsrc_footer));
1030248616Smm}
1031248616Smm
1032248616Smmstatic int
1033248616Smmhfs_reset_compressor(struct archive_write_disk *a)
1034248616Smm{
1035248616Smm	int ret;
1036248616Smm
1037248616Smm	if (a->stream_valid)
1038248616Smm		ret = deflateReset(&a->stream);
1039248616Smm	else
1040248616Smm		ret = deflateInit(&a->stream, a->decmpfs_compression_level);
1041248616Smm
1042248616Smm	if (ret != Z_OK) {
1043248616Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1044248616Smm		    "Failed to initialize compressor");
1045248616Smm		return (ARCHIVE_FATAL);
1046248616Smm	} else
1047248616Smm		a->stream_valid = 1;
1048248616Smm
1049248616Smm	return (ARCHIVE_OK);
1050248616Smm}
1051248616Smm
1052248616Smmstatic int
1053248616Smmhfs_decompress(struct archive_write_disk *a)
1054248616Smm{
1055248616Smm	uint32_t *block_info;
1056248616Smm	unsigned int block_count;
1057248616Smm	uint32_t data_pos, data_size;
1058248616Smm	ssize_t r;
1059248616Smm	ssize_t bytes_written, bytes_to_write;
1060248616Smm	unsigned char *b;
1061248616Smm
1062248616Smm	block_info = (uint32_t *)(a->resource_fork + RSRC_H_SIZE);
1063248616Smm	block_count = archive_le32dec(block_info++);
1064248616Smm	while (block_count--) {
1065248616Smm		data_pos = RSRC_H_SIZE + archive_le32dec(block_info++);
1066248616Smm		data_size = archive_le32dec(block_info++);
1067248616Smm		r = fgetxattr(a->fd, XATTR_RESOURCEFORK_NAME,
1068248616Smm		    a->compressed_buffer, data_size, data_pos, 0);
1069248616Smm		if (r != data_size)  {
1070248616Smm			archive_set_error(&a->archive,
1071248616Smm			    (r < 0)?errno:ARCHIVE_ERRNO_MISC,
1072248616Smm			    "Failed to read resource fork");
1073248616Smm			return (ARCHIVE_WARN);
1074248616Smm		}
1075248616Smm		if (a->compressed_buffer[0] == 0xff) {
1076248616Smm			bytes_to_write = data_size -1;
1077248616Smm			b = a->compressed_buffer + 1;
1078248616Smm		} else {
1079248616Smm			uLong dest_len = MAX_DECMPFS_BLOCK_SIZE;
1080248616Smm			int zr;
1081248616Smm
1082248616Smm			zr = uncompress((Bytef *)a->uncompressed_buffer,
1083248616Smm			    &dest_len, a->compressed_buffer, data_size);
1084248616Smm			if (zr != Z_OK) {
1085248616Smm				archive_set_error(&a->archive,
1086248616Smm				    ARCHIVE_ERRNO_MISC,
1087248616Smm				    "Failed to decompress resource fork");
1088248616Smm				return (ARCHIVE_WARN);
1089248616Smm			}
1090248616Smm			bytes_to_write = dest_len;
1091248616Smm			b = (unsigned char *)a->uncompressed_buffer;
1092248616Smm		}
1093248616Smm		do {
1094248616Smm			bytes_written = write(a->fd, b, bytes_to_write);
1095248616Smm			if (bytes_written < 0) {
1096248616Smm				archive_set_error(&a->archive, errno,
1097248616Smm				    "Write failed");
1098248616Smm				return (ARCHIVE_WARN);
1099248616Smm			}
1100248616Smm			bytes_to_write -= bytes_written;
1101248616Smm			b += bytes_written;
1102248616Smm		} while (bytes_to_write > 0);
1103248616Smm	}
1104248616Smm	r = fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME, 0);
1105248616Smm	if (r == -1)  {
1106248616Smm		archive_set_error(&a->archive, errno,
1107248616Smm		    "Failed to remove resource fork");
1108248616Smm		return (ARCHIVE_WARN);
1109248616Smm	}
1110248616Smm	return (ARCHIVE_OK);
1111248616Smm}
1112248616Smm
1113248616Smmstatic int
1114248616Smmhfs_drive_compressor(struct archive_write_disk *a, const char *buff,
1115248616Smm    size_t size)
1116248616Smm{
1117248616Smm	unsigned char *buffer_compressed;
1118248616Smm	size_t bytes_compressed;
1119248616Smm	size_t bytes_used;
1120248616Smm	int ret;
1121248616Smm
1122248616Smm	ret = hfs_reset_compressor(a);
1123248616Smm	if (ret != ARCHIVE_OK)
1124248616Smm		return (ret);
1125248616Smm
1126248616Smm	if (a->compressed_buffer == NULL) {
1127248616Smm		size_t block_size;
1128248616Smm
1129248616Smm		block_size = COMPRESSED_W_SIZE + RSRC_F_SIZE +
1130248616Smm		    + compressBound(MAX_DECMPFS_BLOCK_SIZE);
1131248616Smm		a->compressed_buffer = malloc(block_size);
1132248616Smm		if (a->compressed_buffer == NULL) {
1133248616Smm			archive_set_error(&a->archive, ENOMEM,
1134248616Smm			    "Can't allocate memory for Resource Fork");
1135248616Smm			return (ARCHIVE_FATAL);
1136248616Smm		}
1137248616Smm		a->compressed_buffer_size = block_size;
1138248616Smm		a->compressed_buffer_remaining = block_size;
1139248616Smm	}
1140248616Smm
1141248616Smm	buffer_compressed = a->compressed_buffer +
1142248616Smm	    a->compressed_buffer_size - a->compressed_buffer_remaining;
1143248616Smm	a->stream.next_in = (Bytef *)(uintptr_t)(const void *)buff;
1144248616Smm	a->stream.avail_in = size;
1145248616Smm	a->stream.next_out = buffer_compressed;
1146248616Smm	a->stream.avail_out = a->compressed_buffer_remaining;
1147248616Smm	do {
1148248616Smm		ret = deflate(&a->stream, Z_FINISH);
1149248616Smm		switch (ret) {
1150248616Smm		case Z_OK:
1151248616Smm		case Z_STREAM_END:
1152248616Smm			break;
1153248616Smm		default:
1154248616Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1155248616Smm			    "Failed to compress data");
1156248616Smm			return (ARCHIVE_FAILED);
1157248616Smm		}
1158248616Smm	} while (ret == Z_OK);
1159248616Smm	bytes_compressed = a->compressed_buffer_remaining - a->stream.avail_out;
1160248616Smm
1161248616Smm	/*
1162248616Smm	 * If the compressed size is larger than the original size,
1163248616Smm	 * throw away compressed data, use uncompressed data instead.
1164248616Smm	 */
1165248616Smm	if (bytes_compressed > size) {
1166248616Smm		buffer_compressed[0] = 0xFF;/* uncompressed marker. */
1167248616Smm		memcpy(buffer_compressed + 1, buff, size);
1168248616Smm		bytes_compressed = size + 1;
1169248616Smm	}
1170248616Smm	a->compressed_buffer_remaining -= bytes_compressed;
1171248616Smm
1172248616Smm	/*
1173248616Smm	 * If the compressed size is smaller than MAX_DECMPFS_XATTR_SIZE
1174248616Smm	 * and the block count in the file is only one, store compressed
1175248616Smm	 * data to decmpfs xattr instead of the resource fork.
1176248616Smm	 */
1177248616Smm	if (a->decmpfs_block_count == 1 &&
1178248616Smm	    (a->decmpfs_attr_size + bytes_compressed)
1179248616Smm	      <= MAX_DECMPFS_XATTR_SIZE) {
1180248616Smm		archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE],
1181248616Smm		    CMP_XATTR);
1182248616Smm		memcpy(a->decmpfs_header_p + DECMPFS_HEADER_SIZE,
1183248616Smm		    buffer_compressed, bytes_compressed);
1184248616Smm		a->decmpfs_attr_size += bytes_compressed;
1185248616Smm		a->compressed_buffer_remaining = a->compressed_buffer_size;
1186248616Smm		/*
1187248616Smm		 * Finish HFS+ Compression.
1188248616Smm		 * - Write the decmpfs xattr.
1189248616Smm		 * - Set the UF_COMPRESSED file flag.
1190248616Smm		 */
1191248616Smm		ret = hfs_write_decmpfs(a);
1192248616Smm		if (ret == ARCHIVE_OK)
1193248616Smm			ret = hfs_set_compressed_fflag(a);
1194248616Smm		return (ret);
1195248616Smm	}
1196248616Smm
1197248616Smm	/* Update block info. */
1198248616Smm	archive_le32enc(a->decmpfs_block_info++,
1199248616Smm	    a->compressed_rsrc_position_v - RSRC_H_SIZE);
1200248616Smm	archive_le32enc(a->decmpfs_block_info++, bytes_compressed);
1201248616Smm	a->compressed_rsrc_position_v += bytes_compressed;
1202248616Smm
1203248616Smm	/*
1204248616Smm	 * Write the compressed data to the resource fork.
1205248616Smm	 */
1206248616Smm	bytes_used = a->compressed_buffer_size - a->compressed_buffer_remaining;
1207248616Smm	while (bytes_used >= COMPRESSED_W_SIZE) {
1208248616Smm		ret = hfs_write_compressed_data(a, COMPRESSED_W_SIZE);
1209248616Smm		if (ret != ARCHIVE_OK)
1210248616Smm			return (ret);
1211248616Smm		bytes_used -= COMPRESSED_W_SIZE;
1212248616Smm		if (bytes_used > COMPRESSED_W_SIZE)
1213248616Smm			memmove(a->compressed_buffer,
1214248616Smm			    a->compressed_buffer + COMPRESSED_W_SIZE,
1215248616Smm			    bytes_used);
1216248616Smm		else
1217248616Smm			memcpy(a->compressed_buffer,
1218248616Smm			    a->compressed_buffer + COMPRESSED_W_SIZE,
1219248616Smm			    bytes_used);
1220248616Smm	}
1221248616Smm	a->compressed_buffer_remaining = a->compressed_buffer_size - bytes_used;
1222248616Smm
1223248616Smm	/*
1224248616Smm	 * If the current block is the last block, write the remaining
1225248616Smm	 * compressed data and the resource fork footer.
1226248616Smm	 */
1227248616Smm	if (a->file_remaining_bytes == 0) {
1228248616Smm		size_t rsrc_size;
1229248616Smm		int64_t bk;
1230248616Smm
1231248616Smm		/* Append the resource footer. */
1232248616Smm		rsrc_size = hfs_set_resource_fork_footer(
1233248616Smm		    a->compressed_buffer + bytes_used,
1234248616Smm		    a->compressed_buffer_remaining);
1235248616Smm		ret = hfs_write_compressed_data(a, bytes_used + rsrc_size);
1236248616Smm		a->compressed_buffer_remaining = a->compressed_buffer_size;
1237248616Smm
1238248616Smm		/* If the compressed size is not enouph smaller than
1239248616Smm		 * the uncompressed size. cancel HFS+ compression.
1240248616Smm		 * TODO: study a behavior of ditto utility and improve
1241248616Smm		 * the condition to fall back into no HFS+ compression. */
1242248616Smm		bk = HFS_BLOCKS(a->compressed_rsrc_position);
1243248616Smm		bk += bk >> 7;
1244248616Smm		if (bk > HFS_BLOCKS(a->filesize))
1245248616Smm			return hfs_decompress(a);
1246248616Smm		/*
1247248616Smm		 * Write the resourcefork header.
1248248616Smm		 */
1249248616Smm		if (ret == ARCHIVE_OK)
1250248616Smm			ret = hfs_write_resource_fork_header(a);
1251248616Smm		/*
1252248616Smm		 * Finish HFS+ Compression.
1253248616Smm		 * - Write the decmpfs xattr.
1254248616Smm		 * - Set the UF_COMPRESSED file flag.
1255248616Smm		 */
1256248616Smm		if (ret == ARCHIVE_OK)
1257248616Smm			ret = hfs_write_decmpfs(a);
1258248616Smm		if (ret == ARCHIVE_OK)
1259248616Smm			ret = hfs_set_compressed_fflag(a);
1260248616Smm	}
1261248616Smm	return (ret);
1262248616Smm}
1263248616Smm
1264228753Smmstatic ssize_t
1265248616Smmhfs_write_decmpfs_block(struct archive_write_disk *a, const char *buff,
1266248616Smm    size_t size)
1267248616Smm{
1268248616Smm	const char *buffer_to_write;
1269248616Smm	size_t bytes_to_write;
1270248616Smm	int ret;
1271248616Smm
1272248616Smm	if (a->decmpfs_block_count == (unsigned)-1) {
1273248616Smm		void *new_block;
1274248616Smm		size_t new_size;
1275248616Smm		unsigned int block_count;
1276248616Smm
1277248616Smm		if (a->decmpfs_header_p == NULL) {
1278248616Smm			new_block = malloc(MAX_DECMPFS_XATTR_SIZE
1279248616Smm			    + sizeof(uint32_t));
1280248616Smm			if (new_block == NULL) {
1281248616Smm				archive_set_error(&a->archive, ENOMEM,
1282248616Smm				    "Can't allocate memory for decmpfs");
1283248616Smm				return (ARCHIVE_FATAL);
1284248616Smm			}
1285248616Smm			a->decmpfs_header_p = new_block;
1286248616Smm		}
1287248616Smm		a->decmpfs_attr_size = DECMPFS_HEADER_SIZE;
1288248616Smm		archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_MAGIC],
1289248616Smm		    DECMPFS_MAGIC);
1290248616Smm		archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE],
1291248616Smm		    CMP_RESOURCE_FORK);
1292248616Smm		archive_le64enc(&a->decmpfs_header_p[DECMPFS_UNCOMPRESSED_SIZE],
1293248616Smm		    a->filesize);
1294248616Smm
1295248616Smm		/* Calculate a block count of the file. */
1296248616Smm		block_count =
1297248616Smm		    (a->filesize + MAX_DECMPFS_BLOCK_SIZE -1) /
1298248616Smm			MAX_DECMPFS_BLOCK_SIZE;
1299248616Smm		/*
1300248616Smm		 * Allocate buffer for resource fork.
1301248616Smm		 * Set up related pointers;
1302248616Smm		 */
1303248616Smm		new_size =
1304248616Smm		    RSRC_H_SIZE + /* header */
1305248616Smm		    4 + /* Block count */
1306248616Smm		    (block_count * sizeof(uint32_t) * 2) +
1307248616Smm		    RSRC_F_SIZE; /* footer */
1308248616Smm		if (new_size > a->resource_fork_allocated_size) {
1309248616Smm			new_block = realloc(a->resource_fork, new_size);
1310248616Smm			if (new_block == NULL) {
1311248616Smm				archive_set_error(&a->archive, ENOMEM,
1312248616Smm				    "Can't allocate memory for ResourceFork");
1313248616Smm				return (ARCHIVE_FATAL);
1314248616Smm			}
1315248616Smm			a->resource_fork_allocated_size = new_size;
1316248616Smm			a->resource_fork = new_block;
1317248616Smm		}
1318248616Smm
1319248616Smm		/* Allocate uncompressed buffer */
1320248616Smm		if (a->uncompressed_buffer == NULL) {
1321248616Smm			new_block = malloc(MAX_DECMPFS_BLOCK_SIZE);
1322248616Smm			if (new_block == NULL) {
1323248616Smm				archive_set_error(&a->archive, ENOMEM,
1324248616Smm				    "Can't allocate memory for decmpfs");
1325248616Smm				return (ARCHIVE_FATAL);
1326248616Smm			}
1327248616Smm			a->uncompressed_buffer = new_block;
1328248616Smm		}
1329248616Smm		a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE;
1330248616Smm		a->file_remaining_bytes = a->filesize;
1331248616Smm		a->compressed_buffer_remaining = a->compressed_buffer_size;
1332248616Smm
1333248616Smm		/*
1334248616Smm		 * Set up a resource fork.
1335248616Smm		 */
1336248616Smm		a->rsrc_xattr_options = XATTR_CREATE;
1337248616Smm		/* Get the position where we are going to set a bunch
1338248616Smm		 * of block info. */
1339248616Smm		a->decmpfs_block_info =
1340248616Smm		    (uint32_t *)(a->resource_fork + RSRC_H_SIZE);
1341248616Smm		/* Set the block count to the resource fork. */
1342248616Smm		archive_le32enc(a->decmpfs_block_info++, block_count);
1343248616Smm		/* Get the position where we are goint to set compressed
1344248616Smm		 * data. */
1345248616Smm		a->compressed_rsrc_position =
1346248616Smm		    RSRC_H_SIZE + 4 + (block_count * 8);
1347248616Smm		a->compressed_rsrc_position_v = a->compressed_rsrc_position;
1348248616Smm		a->decmpfs_block_count = block_count;
1349248616Smm	}
1350248616Smm
1351248616Smm	/* Ignore redundant bytes. */
1352248616Smm	if (a->file_remaining_bytes == 0)
1353248616Smm		return ((ssize_t)size);
1354248616Smm
1355248616Smm	/* Do not overrun a block size. */
1356248616Smm	if (size > a->block_remaining_bytes)
1357248616Smm		bytes_to_write = a->block_remaining_bytes;
1358248616Smm	else
1359248616Smm		bytes_to_write = size;
1360248616Smm	/* Do not overrun the file size. */
1361248616Smm	if (bytes_to_write > a->file_remaining_bytes)
1362248616Smm		bytes_to_write = a->file_remaining_bytes;
1363248616Smm
1364248616Smm	/* For efficiency, if a copy length is full of the uncompressed
1365248616Smm	 * buffer size, do not copy writing data to it. */
1366248616Smm	if (bytes_to_write == MAX_DECMPFS_BLOCK_SIZE)
1367248616Smm		buffer_to_write = buff;
1368248616Smm	else {
1369248616Smm		memcpy(a->uncompressed_buffer +
1370248616Smm		    MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes,
1371248616Smm		    buff, bytes_to_write);
1372248616Smm		buffer_to_write = a->uncompressed_buffer;
1373248616Smm	}
1374248616Smm	a->block_remaining_bytes -= bytes_to_write;
1375248616Smm	a->file_remaining_bytes -= bytes_to_write;
1376248616Smm
1377248616Smm	if (a->block_remaining_bytes == 0 || a->file_remaining_bytes == 0) {
1378248616Smm		ret = hfs_drive_compressor(a, buffer_to_write,
1379248616Smm		    MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes);
1380248616Smm		if (ret < 0)
1381248616Smm			return (ret);
1382248616Smm		a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE;
1383248616Smm	}
1384248616Smm	/* Ignore redundant bytes. */
1385248616Smm	if (a->file_remaining_bytes == 0)
1386248616Smm		return ((ssize_t)size);
1387248616Smm	return (bytes_to_write);
1388248616Smm}
1389248616Smm
1390248616Smmstatic ssize_t
1391248616Smmhfs_write_data_block(struct archive_write_disk *a, const char *buff,
1392248616Smm    size_t size)
1393248616Smm{
1394248616Smm	uint64_t start_size = size;
1395248616Smm	ssize_t bytes_written = 0;
1396248616Smm	ssize_t bytes_to_write;
1397248616Smm
1398248616Smm	if (size == 0)
1399248616Smm		return (ARCHIVE_OK);
1400248616Smm
1401248616Smm	if (a->filesize == 0 || a->fd < 0) {
1402248616Smm		archive_set_error(&a->archive, 0,
1403248616Smm		    "Attempt to write to an empty file");
1404248616Smm		return (ARCHIVE_WARN);
1405248616Smm	}
1406248616Smm
1407248616Smm	/* If this write would run beyond the file size, truncate it. */
1408248616Smm	if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize)
1409248616Smm		start_size = size = (size_t)(a->filesize - a->offset);
1410248616Smm
1411248616Smm	/* Write the data. */
1412248616Smm	while (size > 0) {
1413248616Smm		bytes_to_write = size;
1414248616Smm		/* Seek if necessary to the specified offset. */
1415248616Smm		if (a->offset < a->fd_offset) {
1416248616Smm			/* Can't support backword move. */
1417248616Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1418248616Smm			    "Seek failed");
1419248616Smm			return (ARCHIVE_FATAL);
1420248616Smm		} else if (a->offset > a->fd_offset) {
1421248616Smm			int64_t skip = a->offset - a->fd_offset;
1422248616Smm			char nullblock[1024];
1423248616Smm
1424248616Smm			memset(nullblock, 0, sizeof(nullblock));
1425248616Smm			while (skip > 0) {
1426248616Smm				if (skip > (int64_t)sizeof(nullblock))
1427248616Smm					bytes_written = hfs_write_decmpfs_block(
1428248616Smm					    a, nullblock, sizeof(nullblock));
1429248616Smm				else
1430248616Smm					bytes_written = hfs_write_decmpfs_block(
1431248616Smm					    a, nullblock, skip);
1432248616Smm				if (bytes_written < 0) {
1433248616Smm					archive_set_error(&a->archive, errno,
1434248616Smm					    "Write failed");
1435248616Smm					return (ARCHIVE_WARN);
1436248616Smm				}
1437248616Smm				skip -= bytes_written;
1438248616Smm			}
1439248616Smm
1440248616Smm			a->fd_offset = a->offset;
1441248616Smm		}
1442248616Smm		bytes_written =
1443248616Smm		    hfs_write_decmpfs_block(a, buff, bytes_to_write);
1444248616Smm		if (bytes_written < 0)
1445248616Smm			return (bytes_written);
1446248616Smm		buff += bytes_written;
1447248616Smm		size -= bytes_written;
1448248616Smm		a->total_bytes_written += bytes_written;
1449248616Smm		a->offset += bytes_written;
1450248616Smm		a->fd_offset = a->offset;
1451248616Smm	}
1452248616Smm	return (start_size - size);
1453248616Smm}
1454248616Smm#else
1455248616Smmstatic ssize_t
1456248616Smmhfs_write_data_block(struct archive_write_disk *a, const char *buff,
1457248616Smm    size_t size)
1458248616Smm{
1459248616Smm	return (write_data_block(a, buff, size));
1460248616Smm}
1461248616Smm#endif
1462248616Smm
1463248616Smmstatic ssize_t
1464231200Smm_archive_write_disk_data_block(struct archive *_a,
1465231200Smm    const void *buff, size_t size, int64_t offset)
1466228753Smm{
1467228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
1468228753Smm	ssize_t r;
1469228753Smm
1470231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
1471231200Smm	    ARCHIVE_STATE_DATA, "archive_write_data_block");
1472228753Smm
1473228753Smm	a->offset = offset;
1474248616Smm	if (a->todo & TODO_HFS_COMPRESSION)
1475248616Smm		r = hfs_write_data_block(a, buff, size);
1476248616Smm	else
1477248616Smm		r = write_data_block(a, buff, size);
1478228753Smm	if (r < ARCHIVE_OK)
1479228753Smm		return (r);
1480228753Smm	if ((size_t)r < size) {
1481228753Smm		archive_set_error(&a->archive, 0,
1482228753Smm		    "Write request too large");
1483228753Smm		return (ARCHIVE_WARN);
1484228753Smm	}
1485228753Smm	return (ARCHIVE_OK);
1486228753Smm}
1487228753Smm
1488228753Smmstatic ssize_t
1489231200Smm_archive_write_disk_data(struct archive *_a, const void *buff, size_t size)
1490228753Smm{
1491228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
1492228753Smm
1493231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
1494228753Smm	    ARCHIVE_STATE_DATA, "archive_write_data");
1495228753Smm
1496248616Smm	if (a->todo & TODO_HFS_COMPRESSION)
1497248616Smm		return (hfs_write_data_block(a, buff, size));
1498228753Smm	return (write_data_block(a, buff, size));
1499228753Smm}
1500228753Smm
1501228753Smmstatic int
1502231200Smm_archive_write_disk_finish_entry(struct archive *_a)
1503228753Smm{
1504228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
1505228753Smm	int ret = ARCHIVE_OK;
1506228753Smm
1507231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
1508228753Smm	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
1509228753Smm	    "archive_write_finish_entry");
1510228753Smm	if (a->archive.state & ARCHIVE_STATE_HEADER)
1511228753Smm		return (ARCHIVE_OK);
1512228753Smm	archive_clear_error(&a->archive);
1513228753Smm
1514228753Smm	/* Pad or truncate file to the right size. */
1515228753Smm	if (a->fd < 0) {
1516228753Smm		/* There's no file. */
1517228753Smm	} else if (a->filesize < 0) {
1518228753Smm		/* File size is unknown, so we can't set the size. */
1519228753Smm	} else if (a->fd_offset == a->filesize) {
1520228753Smm		/* Last write ended at exactly the filesize; we're done. */
1521228753Smm		/* Hopefully, this is the common case. */
1522248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H)
1523248616Smm	} else if (a->todo & TODO_HFS_COMPRESSION) {
1524248616Smm		char null_d[1024];
1525248616Smm		ssize_t r;
1526248616Smm
1527248616Smm		if (a->file_remaining_bytes)
1528248616Smm			memset(null_d, 0, sizeof(null_d));
1529248616Smm		while (a->file_remaining_bytes) {
1530248616Smm			if (a->file_remaining_bytes > sizeof(null_d))
1531248616Smm				r = hfs_write_data_block(
1532248616Smm				    a, null_d, sizeof(null_d));
1533248616Smm			else
1534248616Smm				r = hfs_write_data_block(
1535248616Smm				    a, null_d, a->file_remaining_bytes);
1536248616Smm			if (r < 0)
1537248616Smm				return ((int)r);
1538248616Smm		}
1539248616Smm#endif
1540228753Smm	} else {
1541228753Smm#if HAVE_FTRUNCATE
1542228753Smm		if (ftruncate(a->fd, a->filesize) == -1 &&
1543228753Smm		    a->filesize == 0) {
1544228753Smm			archive_set_error(&a->archive, errno,
1545228753Smm			    "File size could not be restored");
1546228753Smm			return (ARCHIVE_FAILED);
1547228753Smm		}
1548228753Smm#endif
1549228753Smm		/*
1550228753Smm		 * Not all platforms implement the XSI option to
1551228753Smm		 * extend files via ftruncate.  Stat() the file again
1552228753Smm		 * to see what happened.
1553228753Smm		 */
1554228753Smm		a->pst = NULL;
1555231200Smm		if ((ret = lazy_stat(a)) != ARCHIVE_OK)
1556228753Smm			return (ret);
1557228753Smm		/* We can use lseek()/write() to extend the file if
1558228753Smm		 * ftruncate didn't work or isn't available. */
1559228753Smm		if (a->st.st_size < a->filesize) {
1560228753Smm			const char nul = '\0';
1561228753Smm			if (lseek(a->fd, a->filesize - 1, SEEK_SET) < 0) {
1562228753Smm				archive_set_error(&a->archive, errno,
1563228753Smm				    "Seek failed");
1564228753Smm				return (ARCHIVE_FATAL);
1565228753Smm			}
1566228753Smm			if (write(a->fd, &nul, 1) < 0) {
1567228753Smm				archive_set_error(&a->archive, errno,
1568228753Smm				    "Write to restore size failed");
1569228753Smm				return (ARCHIVE_FATAL);
1570228753Smm			}
1571228753Smm			a->pst = NULL;
1572228753Smm		}
1573228753Smm	}
1574228753Smm
1575228753Smm	/* Restore metadata. */
1576228753Smm
1577228753Smm	/*
1578248616Smm	 * This is specific to Mac OS X.
1579248616Smm	 * If the current file is an AppleDouble file, it should be
1580248616Smm	 * linked with the data fork file and remove it.
1581248616Smm	 */
1582248616Smm	if (a->todo & TODO_APPLEDOUBLE) {
1583248616Smm		int r2 = fixup_appledouble(a, a->name);
1584248616Smm		if (r2 == ARCHIVE_EOF) {
1585248616Smm			/* The current file has been successfully linked
1586248616Smm			 * with the data fork file and removed. So there
1587248616Smm			 * is nothing to do on the current file.  */
1588248616Smm			goto finish_metadata;
1589248616Smm		}
1590248616Smm		if (r2 < ret) ret = r2;
1591248616Smm	}
1592248616Smm
1593248616Smm	/*
1594228753Smm	 * Look up the "real" UID only if we're going to need it.
1595228753Smm	 * TODO: the TODO_SGID condition can be dropped here, can't it?
1596228753Smm	 */
1597228753Smm	if (a->todo & (TODO_OWNER | TODO_SUID | TODO_SGID)) {
1598231200Smm		a->uid = archive_write_disk_uid(&a->archive,
1599228753Smm		    archive_entry_uname(a->entry),
1600228753Smm		    archive_entry_uid(a->entry));
1601228753Smm	}
1602228753Smm	/* Look up the "real" GID only if we're going to need it. */
1603228753Smm	/* TODO: the TODO_SUID condition can be dropped here, can't it? */
1604228753Smm	if (a->todo & (TODO_OWNER | TODO_SGID | TODO_SUID)) {
1605231200Smm		a->gid = archive_write_disk_gid(&a->archive,
1606228753Smm		    archive_entry_gname(a->entry),
1607228753Smm		    archive_entry_gid(a->entry));
1608228753Smm	 }
1609231200Smm
1610228753Smm	/*
1611231200Smm	 * Restore ownership before set_mode tries to restore suid/sgid
1612228753Smm	 * bits.  If we set the owner, we know what it is and can skip
1613228753Smm	 * a stat() call to examine the ownership of the file on disk.
1614228753Smm	 */
1615248616Smm	if (a->todo & TODO_OWNER) {
1616248616Smm		int r2 = set_ownership(a);
1617248616Smm		if (r2 < ret) ret = r2;
1618248616Smm	}
1619231200Smm
1620231200Smm	/*
1621231200Smm	 * set_mode must precede ACLs on systems such as Solaris and
1622231200Smm	 * FreeBSD where setting the mode implicitly clears extended ACLs
1623231200Smm	 */
1624228753Smm	if (a->todo & TODO_MODE) {
1625228753Smm		int r2 = set_mode(a, a->mode);
1626228753Smm		if (r2 < ret) ret = r2;
1627228753Smm	}
1628228753Smm
1629228753Smm	/*
1630228753Smm	 * Security-related extended attributes (such as
1631228753Smm	 * security.capability on Linux) have to be restored last,
1632228753Smm	 * since they're implicitly removed by other file changes.
1633228753Smm	 */
1634228753Smm	if (a->todo & TODO_XATTR) {
1635228753Smm		int r2 = set_xattrs(a);
1636228753Smm		if (r2 < ret) ret = r2;
1637228753Smm	}
1638228753Smm
1639228753Smm	/*
1640228753Smm	 * Some flags prevent file modification; they must be restored after
1641228753Smm	 * file contents are written.
1642228753Smm	 */
1643228753Smm	if (a->todo & TODO_FFLAGS) {
1644228753Smm		int r2 = set_fflags(a);
1645228753Smm		if (r2 < ret) ret = r2;
1646228753Smm	}
1647231200Smm
1648228753Smm	/*
1649231200Smm	 * Time must follow most other metadata;
1650228753Smm	 * otherwise atime will get changed.
1651228753Smm	 */
1652228753Smm	if (a->todo & TODO_TIMES) {
1653231200Smm		int r2 = set_times_from_entry(a);
1654228753Smm		if (r2 < ret) ret = r2;
1655228753Smm	}
1656228753Smm
1657231200Smm	/*
1658231200Smm	 * Mac extended metadata includes ACLs.
1659231200Smm	 */
1660231200Smm	if (a->todo & TODO_MAC_METADATA) {
1661231200Smm		const void *metadata;
1662231200Smm		size_t metadata_size;
1663231200Smm		metadata = archive_entry_mac_metadata(a->entry, &metadata_size);
1664231200Smm		if (metadata != NULL && metadata_size > 0) {
1665248616Smm			int r2 = set_mac_metadata(a, archive_entry_pathname(
1666248616Smm			    a->entry), metadata, metadata_size);
1667231200Smm			if (r2 < ret) ret = r2;
1668231200Smm		}
1669231200Smm	}
1670231200Smm
1671231200Smm	/*
1672231200Smm	 * ACLs must be restored after timestamps because there are
1673231200Smm	 * ACLs that prevent attribute changes (including time).
1674231200Smm	 */
1675231200Smm	if (a->todo & TODO_ACLS) {
1676238909Smm		int r2 = archive_write_disk_set_acls(&a->archive, a->fd,
1677231200Smm				  archive_entry_pathname(a->entry),
1678231200Smm				  archive_entry_acl(a->entry));
1679231200Smm		if (r2 < ret) ret = r2;
1680231200Smm	}
1681231200Smm
1682248616Smmfinish_metadata:
1683228753Smm	/* If there's an fd, we can close it now. */
1684228753Smm	if (a->fd >= 0) {
1685228753Smm		close(a->fd);
1686228753Smm		a->fd = -1;
1687228753Smm	}
1688228753Smm	/* If there's an entry, we can release it now. */
1689228753Smm	if (a->entry) {
1690228753Smm		archive_entry_free(a->entry);
1691228753Smm		a->entry = NULL;
1692228753Smm	}
1693228753Smm	a->archive.state = ARCHIVE_STATE_HEADER;
1694228753Smm	return (ret);
1695228753Smm}
1696228753Smm
1697228753Smmint
1698228753Smmarchive_write_disk_set_group_lookup(struct archive *_a,
1699228753Smm    void *private_data,
1700231200Smm    int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid),
1701228753Smm    void (*cleanup_gid)(void *private))
1702228753Smm{
1703228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
1704231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
1705228753Smm	    ARCHIVE_STATE_ANY, "archive_write_disk_set_group_lookup");
1706228753Smm
1707231200Smm	if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL)
1708231200Smm		(a->cleanup_gid)(a->lookup_gid_data);
1709231200Smm
1710228753Smm	a->lookup_gid = lookup_gid;
1711228753Smm	a->cleanup_gid = cleanup_gid;
1712228753Smm	a->lookup_gid_data = private_data;
1713228753Smm	return (ARCHIVE_OK);
1714228753Smm}
1715228753Smm
1716228753Smmint
1717228753Smmarchive_write_disk_set_user_lookup(struct archive *_a,
1718228753Smm    void *private_data,
1719231200Smm    int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid),
1720228753Smm    void (*cleanup_uid)(void *private))
1721228753Smm{
1722228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
1723231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
1724228753Smm	    ARCHIVE_STATE_ANY, "archive_write_disk_set_user_lookup");
1725228753Smm
1726231200Smm	if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL)
1727231200Smm		(a->cleanup_uid)(a->lookup_uid_data);
1728231200Smm
1729228753Smm	a->lookup_uid = lookup_uid;
1730228753Smm	a->cleanup_uid = cleanup_uid;
1731228753Smm	a->lookup_uid_data = private_data;
1732228753Smm	return (ARCHIVE_OK);
1733228753Smm}
1734228753Smm
1735231200Smmint64_t
1736231200Smmarchive_write_disk_gid(struct archive *_a, const char *name, int64_t id)
1737231200Smm{
1738231200Smm       struct archive_write_disk *a = (struct archive_write_disk *)_a;
1739231200Smm       archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
1740231200Smm           ARCHIVE_STATE_ANY, "archive_write_disk_gid");
1741231200Smm       if (a->lookup_gid)
1742231200Smm               return (a->lookup_gid)(a->lookup_gid_data, name, id);
1743231200Smm       return (id);
1744231200Smm}
1745231200Smm
1746231200Smmint64_t
1747231200Smmarchive_write_disk_uid(struct archive *_a, const char *name, int64_t id)
1748231200Smm{
1749238909Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
1750238909Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
1751238909Smm	    ARCHIVE_STATE_ANY, "archive_write_disk_uid");
1752238909Smm	if (a->lookup_uid)
1753238909Smm		return (a->lookup_uid)(a->lookup_uid_data, name, id);
1754238909Smm	return (id);
1755231200Smm}
1756228753Smm
1757228753Smm/*
1758228753Smm * Create a new archive_write_disk object and initialize it with global state.
1759228753Smm */
1760228753Smmstruct archive *
1761228753Smmarchive_write_disk_new(void)
1762228753Smm{
1763228753Smm	struct archive_write_disk *a;
1764228753Smm
1765228753Smm	a = (struct archive_write_disk *)malloc(sizeof(*a));
1766228753Smm	if (a == NULL)
1767228753Smm		return (NULL);
1768228753Smm	memset(a, 0, sizeof(*a));
1769228753Smm	a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC;
1770228753Smm	/* We're ready to write a header immediately. */
1771228753Smm	a->archive.state = ARCHIVE_STATE_HEADER;
1772228753Smm	a->archive.vtable = archive_write_disk_vtable();
1773228753Smm	a->start_time = time(NULL);
1774231200Smm	/* Query and restore the umask. */
1775231200Smm	umask(a->user_umask = umask(0));
1776228753Smm#ifdef HAVE_GETEUID
1777228753Smm	a->user_uid = geteuid();
1778228753Smm#endif /* HAVE_GETEUID */
1779228753Smm	if (archive_string_ensure(&a->path_safe, 512) == NULL) {
1780228753Smm		free(a);
1781228753Smm		return (NULL);
1782228753Smm	}
1783248616Smm#ifdef HAVE_ZLIB_H
1784248616Smm	a->decmpfs_compression_level = 5;
1785248616Smm#endif
1786228753Smm	return (&a->archive);
1787228753Smm}
1788228753Smm
1789228753Smm
1790228753Smm/*
1791228753Smm * If pathname is longer than PATH_MAX, chdir to a suitable
1792228753Smm * intermediate dir and edit the path down to a shorter suffix.  Note
1793228753Smm * that this routine never returns an error; if the chdir() attempt
1794228753Smm * fails for any reason, we just go ahead with the long pathname.  The
1795228753Smm * object creation is likely to fail, but any error will get handled
1796228753Smm * at that time.
1797228753Smm */
1798231200Smm#if defined(HAVE_FCHDIR) && defined(PATH_MAX)
1799228753Smmstatic void
1800228753Smmedit_deep_directories(struct archive_write_disk *a)
1801228753Smm{
1802228753Smm	int ret;
1803228753Smm	char *tail = a->name;
1804228753Smm
1805228753Smm	/* If path is short, avoid the open() below. */
1806306941Sdelphij	if (strlen(tail) < PATH_MAX)
1807228753Smm		return;
1808228753Smm
1809228753Smm	/* Try to record our starting dir. */
1810248616Smm	a->restore_pwd = open(".", O_RDONLY | O_BINARY | O_CLOEXEC);
1811248616Smm	__archive_ensure_cloexec_flag(a->restore_pwd);
1812228753Smm	if (a->restore_pwd < 0)
1813228753Smm		return;
1814228753Smm
1815228753Smm	/* As long as the path is too long... */
1816306941Sdelphij	while (strlen(tail) >= PATH_MAX) {
1817228753Smm		/* Locate a dir prefix shorter than PATH_MAX. */
1818228753Smm		tail += PATH_MAX - 8;
1819228753Smm		while (tail > a->name && *tail != '/')
1820228753Smm			tail--;
1821228753Smm		/* Exit if we find a too-long path component. */
1822228753Smm		if (tail <= a->name)
1823228753Smm			return;
1824228753Smm		/* Create the intermediate dir and chdir to it. */
1825228753Smm		*tail = '\0'; /* Terminate dir portion */
1826228753Smm		ret = create_dir(a, a->name);
1827228753Smm		if (ret == ARCHIVE_OK && chdir(a->name) != 0)
1828228753Smm			ret = ARCHIVE_FAILED;
1829228753Smm		*tail = '/'; /* Restore the / we removed. */
1830228753Smm		if (ret != ARCHIVE_OK)
1831228753Smm			return;
1832228753Smm		tail++;
1833228753Smm		/* The chdir() succeeded; we've now shortened the path. */
1834228753Smm		a->name = tail;
1835228753Smm	}
1836228753Smm	return;
1837228753Smm}
1838228753Smm#endif
1839228753Smm
1840228753Smm/*
1841228753Smm * The main restore function.
1842228753Smm */
1843228753Smmstatic int
1844228753Smmrestore_entry(struct archive_write_disk *a)
1845228753Smm{
1846228753Smm	int ret = ARCHIVE_OK, en;
1847228753Smm
1848228753Smm	if (a->flags & ARCHIVE_EXTRACT_UNLINK && !S_ISDIR(a->mode)) {
1849228753Smm		/*
1850228753Smm		 * TODO: Fix this.  Apparently, there are platforms
1851228753Smm		 * that still allow root to hose the entire filesystem
1852228753Smm		 * by unlinking a dir.  The S_ISDIR() test above
1853228753Smm		 * prevents us from using unlink() here if the new
1854228753Smm		 * object is a dir, but that doesn't mean the old
1855228753Smm		 * object isn't a dir.
1856228753Smm		 */
1857228753Smm		if (unlink(a->name) == 0) {
1858228753Smm			/* We removed it, reset cached stat. */
1859228753Smm			a->pst = NULL;
1860228753Smm		} else if (errno == ENOENT) {
1861228753Smm			/* File didn't exist, that's just as good. */
1862228753Smm		} else if (rmdir(a->name) == 0) {
1863228753Smm			/* It was a dir, but now it's gone. */
1864228753Smm			a->pst = NULL;
1865228753Smm		} else {
1866228753Smm			/* We tried, but couldn't get rid of it. */
1867228753Smm			archive_set_error(&a->archive, errno,
1868228753Smm			    "Could not unlink");
1869228753Smm			return(ARCHIVE_FAILED);
1870228753Smm		}
1871228753Smm	}
1872228753Smm
1873228753Smm	/* Try creating it first; if this fails, we'll try to recover. */
1874228753Smm	en = create_filesystem_object(a);
1875228753Smm
1876228753Smm	if ((en == ENOTDIR || en == ENOENT)
1877228753Smm	    && !(a->flags & ARCHIVE_EXTRACT_NO_AUTODIR)) {
1878228753Smm		/* If the parent dir doesn't exist, try creating it. */
1879228753Smm		create_parent_dir(a, a->name);
1880228753Smm		/* Now try to create the object again. */
1881228753Smm		en = create_filesystem_object(a);
1882228753Smm	}
1883228753Smm
1884228753Smm	if ((en == EISDIR || en == EEXIST)
1885228753Smm	    && (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
1886228753Smm		/* If we're not overwriting, we're done. */
1887231200Smm		archive_entry_unset_size(a->entry);
1888231200Smm		return (ARCHIVE_OK);
1889228753Smm	}
1890228753Smm
1891228753Smm	/*
1892228753Smm	 * Some platforms return EISDIR if you call
1893228753Smm	 * open(O_WRONLY | O_EXCL | O_CREAT) on a directory, some
1894228753Smm	 * return EEXIST.  POSIX is ambiguous, requiring EISDIR
1895228753Smm	 * for open(O_WRONLY) on a dir and EEXIST for open(O_EXCL | O_CREAT)
1896228753Smm	 * on an existing item.
1897228753Smm	 */
1898228753Smm	if (en == EISDIR) {
1899228753Smm		/* A dir is in the way of a non-dir, rmdir it. */
1900228753Smm		if (rmdir(a->name) != 0) {
1901228753Smm			archive_set_error(&a->archive, errno,
1902228753Smm			    "Can't remove already-existing dir");
1903228753Smm			return (ARCHIVE_FAILED);
1904228753Smm		}
1905228753Smm		a->pst = NULL;
1906228753Smm		/* Try again. */
1907228753Smm		en = create_filesystem_object(a);
1908228753Smm	} else if (en == EEXIST) {
1909228753Smm		/*
1910228753Smm		 * We know something is in the way, but we don't know what;
1911228753Smm		 * we need to find out before we go any further.
1912228753Smm		 */
1913228753Smm		int r = 0;
1914228753Smm		/*
1915231200Smm		 * The SECURE_SYMLINKS logic has already removed a
1916228753Smm		 * symlink to a dir if the client wants that.  So
1917228753Smm		 * follow the symlink if we're creating a dir.
1918228753Smm		 */
1919228753Smm		if (S_ISDIR(a->mode))
1920228753Smm			r = stat(a->name, &a->st);
1921228753Smm		/*
1922228753Smm		 * If it's not a dir (or it's a broken symlink),
1923228753Smm		 * then don't follow it.
1924228753Smm		 */
1925228753Smm		if (r != 0 || !S_ISDIR(a->mode))
1926228753Smm			r = lstat(a->name, &a->st);
1927228753Smm		if (r != 0) {
1928228753Smm			archive_set_error(&a->archive, errno,
1929228753Smm			    "Can't stat existing object");
1930228753Smm			return (ARCHIVE_FAILED);
1931228753Smm		}
1932228753Smm
1933228753Smm		/*
1934228753Smm		 * NO_OVERWRITE_NEWER doesn't apply to directories.
1935228753Smm		 */
1936228753Smm		if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER)
1937228753Smm		    &&  !S_ISDIR(a->st.st_mode)) {
1938228753Smm			if (!older(&(a->st), a->entry)) {
1939231200Smm				archive_entry_unset_size(a->entry);
1940231200Smm				return (ARCHIVE_OK);
1941228753Smm			}
1942228753Smm		}
1943228753Smm
1944228753Smm		/* If it's our archive, we're done. */
1945231200Smm		if (a->skip_file_set &&
1946238856Smm		    a->st.st_dev == (dev_t)a->skip_file_dev &&
1947238856Smm		    a->st.st_ino == (ino_t)a->skip_file_ino) {
1948238856Smm			archive_set_error(&a->archive, 0,
1949238856Smm			    "Refusing to overwrite archive");
1950228753Smm			return (ARCHIVE_FAILED);
1951228753Smm		}
1952228753Smm
1953228753Smm		if (!S_ISDIR(a->st.st_mode)) {
1954228753Smm			/* A non-dir is in the way, unlink it. */
1955228753Smm			if (unlink(a->name) != 0) {
1956228753Smm				archive_set_error(&a->archive, errno,
1957228753Smm				    "Can't unlink already-existing object");
1958228753Smm				return (ARCHIVE_FAILED);
1959228753Smm			}
1960228753Smm			a->pst = NULL;
1961228753Smm			/* Try again. */
1962228753Smm			en = create_filesystem_object(a);
1963228753Smm		} else if (!S_ISDIR(a->mode)) {
1964228753Smm			/* A dir is in the way of a non-dir, rmdir it. */
1965228753Smm			if (rmdir(a->name) != 0) {
1966228753Smm				archive_set_error(&a->archive, errno,
1967238856Smm				    "Can't replace existing directory with non-directory");
1968228753Smm				return (ARCHIVE_FAILED);
1969228753Smm			}
1970228753Smm			/* Try again. */
1971228753Smm			en = create_filesystem_object(a);
1972228753Smm		} else {
1973228753Smm			/*
1974228753Smm			 * There's a dir in the way of a dir.  Don't
1975228753Smm			 * waste time with rmdir()/mkdir(), just fix
1976228753Smm			 * up the permissions on the existing dir.
1977228753Smm			 * Note that we don't change perms on existing
1978228753Smm			 * dirs unless _EXTRACT_PERM is specified.
1979228753Smm			 */
1980228753Smm			if ((a->mode != a->st.st_mode)
1981228753Smm			    && (a->todo & TODO_MODE_FORCE))
1982228753Smm				a->deferred |= (a->todo & TODO_MODE);
1983228753Smm			/* Ownership doesn't need deferred fixup. */
1984228753Smm			en = 0; /* Forget the EEXIST. */
1985228753Smm		}
1986228753Smm	}
1987228753Smm
1988228753Smm	if (en) {
1989228753Smm		/* Everything failed; give up here. */
1990228753Smm		archive_set_error(&a->archive, en, "Can't create '%s'",
1991228753Smm		    a->name);
1992228753Smm		return (ARCHIVE_FAILED);
1993228753Smm	}
1994228753Smm
1995228753Smm	a->pst = NULL; /* Cached stat data no longer valid. */
1996228753Smm	return (ret);
1997228753Smm}
1998228753Smm
1999228753Smm/*
2000228753Smm * Returns 0 if creation succeeds, or else returns errno value from
2001228753Smm * the failed system call.   Note:  This function should only ever perform
2002228753Smm * a single system call.
2003228753Smm */
2004228753Smmstatic int
2005228753Smmcreate_filesystem_object(struct archive_write_disk *a)
2006228753Smm{
2007228753Smm	/* Create the entry. */
2008228753Smm	const char *linkname;
2009228753Smm	mode_t final_mode, mode;
2010228753Smm	int r;
2011306941Sdelphij	/* these for check_symlinks_fsobj */
2012306941Sdelphij	char *linkname_copy;	/* non-const copy of linkname */
2013306941Sdelphij	struct archive_string error_string;
2014306941Sdelphij	int error_number;
2015228753Smm
2016228753Smm	/* We identify hard/symlinks according to the link names. */
2017228753Smm	/* Since link(2) and symlink(2) don't handle modes, we're done here. */
2018228753Smm	linkname = archive_entry_hardlink(a->entry);
2019228753Smm	if (linkname != NULL) {
2020228753Smm#if !HAVE_LINK
2021228753Smm		return (EPERM);
2022228753Smm#else
2023306941Sdelphij		archive_string_init(&error_string);
2024306941Sdelphij		linkname_copy = strdup(linkname);
2025306941Sdelphij		if (linkname_copy == NULL) {
2026306941Sdelphij		    return (EPERM);
2027306941Sdelphij		}
2028306941Sdelphij		/* TODO: consider using the cleaned-up path as the link target? */
2029306941Sdelphij		r = cleanup_pathname_fsobj(linkname_copy, &error_number, &error_string, a->flags);
2030306941Sdelphij		if (r != ARCHIVE_OK) {
2031306941Sdelphij			archive_set_error(&a->archive, error_number, "%s", error_string.s);
2032306941Sdelphij			free(linkname_copy);
2033306941Sdelphij			/* EPERM is more appropriate than error_number for our callers */
2034306941Sdelphij			return (EPERM);
2035306941Sdelphij		}
2036306941Sdelphij		r = check_symlinks_fsobj(linkname_copy, &error_number, &error_string, a->flags);
2037306941Sdelphij		if (r != ARCHIVE_OK) {
2038306941Sdelphij			archive_set_error(&a->archive, error_number, "%s", error_string.s);
2039306941Sdelphij			free(linkname_copy);
2040306941Sdelphij			/* EPERM is more appropriate than error_number for our callers */
2041306941Sdelphij			return (EPERM);
2042306941Sdelphij		}
2043306941Sdelphij		free(linkname_copy);
2044228753Smm		r = link(linkname, a->name) ? errno : 0;
2045228753Smm		/*
2046228753Smm		 * New cpio and pax formats allow hardlink entries
2047228753Smm		 * to carry data, so we may have to open the file
2048228753Smm		 * for hardlink entries.
2049228753Smm		 *
2050228753Smm		 * If the hardlink was successfully created and
2051228753Smm		 * the archive doesn't have carry data for it,
2052231200Smm		 * consider it to be non-authoritative for meta data.
2053228753Smm		 * This is consistent with GNU tar and BSD pax.
2054228753Smm		 * If the hardlink does carry data, let the last
2055228753Smm		 * archive entry decide ownership.
2056228753Smm		 */
2057228753Smm		if (r == 0 && a->filesize <= 0) {
2058228753Smm			a->todo = 0;
2059228753Smm			a->deferred = 0;
2060231200Smm		} else if (r == 0 && a->filesize > 0) {
2061248616Smm			a->fd = open(a->name,
2062306941Sdelphij				     O_WRONLY | O_TRUNC | O_BINARY | O_CLOEXEC | O_NOFOLLOW);
2063248616Smm			__archive_ensure_cloexec_flag(a->fd);
2064228753Smm			if (a->fd < 0)
2065228753Smm				r = errno;
2066228753Smm		}
2067228753Smm		return (r);
2068228753Smm#endif
2069228753Smm	}
2070228753Smm	linkname = archive_entry_symlink(a->entry);
2071228753Smm	if (linkname != NULL) {
2072228753Smm#if HAVE_SYMLINK
2073228753Smm		return symlink(linkname, a->name) ? errno : 0;
2074228753Smm#else
2075228753Smm		return (EPERM);
2076228753Smm#endif
2077228753Smm	}
2078228753Smm
2079228753Smm	/*
2080228753Smm	 * The remaining system calls all set permissions, so let's
2081228753Smm	 * try to take advantage of that to avoid an extra chmod()
2082228753Smm	 * call.  (Recall that umask is set to zero right now!)
2083228753Smm	 */
2084228753Smm
2085228753Smm	/* Mode we want for the final restored object (w/o file type bits). */
2086228753Smm	final_mode = a->mode & 07777;
2087228753Smm	/*
2088228753Smm	 * The mode that will actually be restored in this step.  Note
2089228753Smm	 * that SUID, SGID, etc, require additional work to ensure
2090228753Smm	 * security, so we never restore them at this point.
2091228753Smm	 */
2092248616Smm	mode = final_mode & 0777 & ~a->user_umask;
2093228753Smm
2094228753Smm	switch (a->mode & AE_IFMT) {
2095228753Smm	default:
2096228753Smm		/* POSIX requires that we fall through here. */
2097228753Smm		/* FALLTHROUGH */
2098228753Smm	case AE_IFREG:
2099228753Smm		a->fd = open(a->name,
2100248616Smm		    O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, mode);
2101248616Smm		__archive_ensure_cloexec_flag(a->fd);
2102228753Smm		r = (a->fd < 0);
2103228753Smm		break;
2104228753Smm	case AE_IFCHR:
2105228753Smm#ifdef HAVE_MKNOD
2106228753Smm		/* Note: we use AE_IFCHR for the case label, and
2107228753Smm		 * S_IFCHR for the mknod() call.  This is correct.  */
2108228753Smm		r = mknod(a->name, mode | S_IFCHR,
2109228753Smm		    archive_entry_rdev(a->entry));
2110228753Smm		break;
2111228753Smm#else
2112228753Smm		/* TODO: Find a better way to warn about our inability
2113228753Smm		 * to restore a char device node. */
2114228753Smm		return (EINVAL);
2115228753Smm#endif /* HAVE_MKNOD */
2116228753Smm	case AE_IFBLK:
2117228753Smm#ifdef HAVE_MKNOD
2118228753Smm		r = mknod(a->name, mode | S_IFBLK,
2119228753Smm		    archive_entry_rdev(a->entry));
2120228753Smm		break;
2121228753Smm#else
2122228753Smm		/* TODO: Find a better way to warn about our inability
2123228753Smm		 * to restore a block device node. */
2124228753Smm		return (EINVAL);
2125228753Smm#endif /* HAVE_MKNOD */
2126228753Smm	case AE_IFDIR:
2127228753Smm		mode = (mode | MINIMUM_DIR_MODE) & MAXIMUM_DIR_MODE;
2128228753Smm		r = mkdir(a->name, mode);
2129228753Smm		if (r == 0) {
2130228753Smm			/* Defer setting dir times. */
2131228753Smm			a->deferred |= (a->todo & TODO_TIMES);
2132228753Smm			a->todo &= ~TODO_TIMES;
2133228753Smm			/* Never use an immediate chmod(). */
2134228753Smm			/* We can't avoid the chmod() entirely if EXTRACT_PERM
2135228753Smm			 * because of SysV SGID inheritance. */
2136228753Smm			if ((mode != final_mode)
2137228753Smm			    || (a->flags & ARCHIVE_EXTRACT_PERM))
2138228753Smm				a->deferred |= (a->todo & TODO_MODE);
2139228753Smm			a->todo &= ~TODO_MODE;
2140228753Smm		}
2141228753Smm		break;
2142228753Smm	case AE_IFIFO:
2143228753Smm#ifdef HAVE_MKFIFO
2144228753Smm		r = mkfifo(a->name, mode);
2145228753Smm		break;
2146228753Smm#else
2147228753Smm		/* TODO: Find a better way to warn about our inability
2148228753Smm		 * to restore a fifo. */
2149228753Smm		return (EINVAL);
2150228753Smm#endif /* HAVE_MKFIFO */
2151228753Smm	}
2152228753Smm
2153228753Smm	/* All the system calls above set errno on failure. */
2154228753Smm	if (r)
2155228753Smm		return (errno);
2156228753Smm
2157228753Smm	/* If we managed to set the final mode, we've avoided a chmod(). */
2158228753Smm	if (mode == final_mode)
2159228753Smm		a->todo &= ~TODO_MODE;
2160228753Smm	return (0);
2161228753Smm}
2162228753Smm
2163228753Smm/*
2164228753Smm * Cleanup function for archive_extract.  Mostly, this involves processing
2165228753Smm * the fixup list, which is used to address a number of problems:
2166228753Smm *   * Dir permissions might prevent us from restoring a file in that
2167228753Smm *     dir, so we restore the dir with minimum 0700 permissions first,
2168228753Smm *     then correct the mode at the end.
2169228753Smm *   * Similarly, the act of restoring a file touches the directory
2170228753Smm *     and changes the timestamp on the dir, so we have to touch-up dir
2171228753Smm *     timestamps at the end as well.
2172228753Smm *   * Some file flags can interfere with the restore by, for example,
2173228753Smm *     preventing the creation of hardlinks to those files.
2174231200Smm *   * Mac OS extended metadata includes ACLs, so must be deferred on dirs.
2175228753Smm *
2176228753Smm * Note that tar/cpio do not require that archives be in a particular
2177228753Smm * order; there is no way to know when the last file has been restored
2178228753Smm * within a directory, so there's no way to optimize the memory usage
2179228753Smm * here by fixing up the directory any earlier than the
2180228753Smm * end-of-archive.
2181228753Smm *
2182228753Smm * XXX TODO: Directory ACLs should be restored here, for the same
2183228753Smm * reason we set directory perms here. XXX
2184228753Smm */
2185228753Smmstatic int
2186231200Smm_archive_write_disk_close(struct archive *_a)
2187228753Smm{
2188228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
2189228753Smm	struct fixup_entry *next, *p;
2190228753Smm	int ret;
2191228753Smm
2192231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
2193228753Smm	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
2194228753Smm	    "archive_write_disk_close");
2195231200Smm	ret = _archive_write_disk_finish_entry(&a->archive);
2196228753Smm
2197228753Smm	/* Sort dir list so directories are fixed up in depth-first order. */
2198228753Smm	p = sort_dir_list(a->fixup_list);
2199228753Smm
2200228753Smm	while (p != NULL) {
2201228753Smm		a->pst = NULL; /* Mark stat cache as out-of-date. */
2202228753Smm		if (p->fixup & TODO_TIMES) {
2203231200Smm			set_times(a, -1, p->mode, p->name,
2204231200Smm			    p->atime, p->atime_nanos,
2205231200Smm			    p->birthtime, p->birthtime_nanos,
2206231200Smm			    p->mtime, p->mtime_nanos,
2207231200Smm			    p->ctime, p->ctime_nanos);
2208228753Smm		}
2209228753Smm		if (p->fixup & TODO_MODE_BASE)
2210228753Smm			chmod(p->name, p->mode);
2211231200Smm		if (p->fixup & TODO_ACLS)
2212238909Smm			archive_write_disk_set_acls(&a->archive,
2213238909Smm						    -1, p->name, &p->acl);
2214228753Smm		if (p->fixup & TODO_FFLAGS)
2215228753Smm			set_fflags_platform(a, -1, p->name,
2216228753Smm			    p->mode, p->fflags_set, 0);
2217231200Smm		if (p->fixup & TODO_MAC_METADATA)
2218231200Smm			set_mac_metadata(a, p->name, p->mac_metadata,
2219231200Smm					 p->mac_metadata_size);
2220228753Smm		next = p->next;
2221231200Smm		archive_acl_clear(&p->acl);
2222231200Smm		free(p->mac_metadata);
2223228753Smm		free(p->name);
2224228753Smm		free(p);
2225228753Smm		p = next;
2226228753Smm	}
2227228753Smm	a->fixup_list = NULL;
2228228753Smm	return (ret);
2229228753Smm}
2230228753Smm
2231228753Smmstatic int
2232231200Smm_archive_write_disk_free(struct archive *_a)
2233228753Smm{
2234231200Smm	struct archive_write_disk *a;
2235228753Smm	int ret;
2236231200Smm	if (_a == NULL)
2237231200Smm		return (ARCHIVE_OK);
2238231200Smm	archive_check_magic(_a, ARCHIVE_WRITE_DISK_MAGIC,
2239231200Smm	    ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_write_disk_free");
2240231200Smm	a = (struct archive_write_disk *)_a;
2241231200Smm	ret = _archive_write_disk_close(&a->archive);
2242231200Smm	archive_write_disk_set_group_lookup(&a->archive, NULL, NULL, NULL);
2243231200Smm	archive_write_disk_set_user_lookup(&a->archive, NULL, NULL, NULL);
2244228753Smm	if (a->entry)
2245228753Smm		archive_entry_free(a->entry);
2246228753Smm	archive_string_free(&a->_name_data);
2247228753Smm	archive_string_free(&a->archive.error_string);
2248228753Smm	archive_string_free(&a->path_safe);
2249231200Smm	a->archive.magic = 0;
2250231200Smm	__archive_clean(&a->archive);
2251248616Smm	free(a->decmpfs_header_p);
2252248616Smm	free(a->resource_fork);
2253248616Smm	free(a->compressed_buffer);
2254248616Smm	free(a->uncompressed_buffer);
2255248616Smm#ifdef HAVE_ZLIB_H
2256248616Smm	if (a->stream_valid) {
2257248616Smm		switch (deflateEnd(&a->stream)) {
2258248616Smm		case Z_OK:
2259248616Smm			break;
2260248616Smm		default:
2261248616Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
2262248616Smm			    "Failed to clean up compressor");
2263248616Smm			ret = ARCHIVE_FATAL;
2264248616Smm			break;
2265248616Smm		}
2266248616Smm	}
2267248616Smm#endif
2268228753Smm	free(a);
2269228753Smm	return (ret);
2270228753Smm}
2271228753Smm
2272228753Smm/*
2273228753Smm * Simple O(n log n) merge sort to order the fixup list.  In
2274228753Smm * particular, we want to restore dir timestamps depth-first.
2275228753Smm */
2276228753Smmstatic struct fixup_entry *
2277228753Smmsort_dir_list(struct fixup_entry *p)
2278228753Smm{
2279228753Smm	struct fixup_entry *a, *b, *t;
2280228753Smm
2281228753Smm	if (p == NULL)
2282228753Smm		return (NULL);
2283228753Smm	/* A one-item list is already sorted. */
2284228753Smm	if (p->next == NULL)
2285228753Smm		return (p);
2286228753Smm
2287228753Smm	/* Step 1: split the list. */
2288228753Smm	t = p;
2289228753Smm	a = p->next->next;
2290228753Smm	while (a != NULL) {
2291228753Smm		/* Step a twice, t once. */
2292228753Smm		a = a->next;
2293228753Smm		if (a != NULL)
2294228753Smm			a = a->next;
2295228753Smm		t = t->next;
2296228753Smm	}
2297228753Smm	/* Now, t is at the mid-point, so break the list here. */
2298228753Smm	b = t->next;
2299228753Smm	t->next = NULL;
2300228753Smm	a = p;
2301228753Smm
2302228753Smm	/* Step 2: Recursively sort the two sub-lists. */
2303228753Smm	a = sort_dir_list(a);
2304228753Smm	b = sort_dir_list(b);
2305228753Smm
2306228753Smm	/* Step 3: Merge the returned lists. */
2307228753Smm	/* Pick the first element for the merged list. */
2308228753Smm	if (strcmp(a->name, b->name) > 0) {
2309228753Smm		t = p = a;
2310228753Smm		a = a->next;
2311228753Smm	} else {
2312228753Smm		t = p = b;
2313228753Smm		b = b->next;
2314228753Smm	}
2315228753Smm
2316228753Smm	/* Always put the later element on the list first. */
2317228753Smm	while (a != NULL && b != NULL) {
2318228753Smm		if (strcmp(a->name, b->name) > 0) {
2319228753Smm			t->next = a;
2320228753Smm			a = a->next;
2321228753Smm		} else {
2322228753Smm			t->next = b;
2323228753Smm			b = b->next;
2324228753Smm		}
2325228753Smm		t = t->next;
2326228753Smm	}
2327228753Smm
2328228753Smm	/* Only one list is non-empty, so just splice it on. */
2329228753Smm	if (a != NULL)
2330228753Smm		t->next = a;
2331228753Smm	if (b != NULL)
2332228753Smm		t->next = b;
2333228753Smm
2334228753Smm	return (p);
2335228753Smm}
2336228753Smm
2337228753Smm/*
2338228753Smm * Returns a new, initialized fixup entry.
2339228753Smm *
2340228753Smm * TODO: Reduce the memory requirements for this list by using a tree
2341228753Smm * structure rather than a simple list of names.
2342228753Smm */
2343228753Smmstatic struct fixup_entry *
2344228753Smmnew_fixup(struct archive_write_disk *a, const char *pathname)
2345228753Smm{
2346228753Smm	struct fixup_entry *fe;
2347228753Smm
2348231200Smm	fe = (struct fixup_entry *)calloc(1, sizeof(struct fixup_entry));
2349248616Smm	if (fe == NULL) {
2350248616Smm		archive_set_error(&a->archive, ENOMEM,
2351248616Smm		    "Can't allocate memory for a fixup");
2352228753Smm		return (NULL);
2353248616Smm	}
2354228753Smm	fe->next = a->fixup_list;
2355228753Smm	a->fixup_list = fe;
2356228753Smm	fe->fixup = 0;
2357228753Smm	fe->name = strdup(pathname);
2358228753Smm	return (fe);
2359228753Smm}
2360228753Smm
2361228753Smm/*
2362228753Smm * Returns a fixup structure for the current entry.
2363228753Smm */
2364228753Smmstatic struct fixup_entry *
2365228753Smmcurrent_fixup(struct archive_write_disk *a, const char *pathname)
2366228753Smm{
2367228753Smm	if (a->current_fixup == NULL)
2368228753Smm		a->current_fixup = new_fixup(a, pathname);
2369228753Smm	return (a->current_fixup);
2370228753Smm}
2371228753Smm
2372228753Smm/*
2373228753Smm * TODO: Someday, integrate this with the deep dir support; they both
2374228753Smm * scan the path and both can be optimized by comparing against other
2375228753Smm * recent paths.
2376228753Smm */
2377228753Smm/* TODO: Extend this to support symlinks on Windows Vista and later. */
2378306941Sdelphij
2379306941Sdelphij/*
2380306941Sdelphij * Checks the given path to see if any elements along it are symlinks.  Returns
2381306941Sdelphij * ARCHIVE_OK if there are none, otherwise puts an error in errmsg.
2382306941Sdelphij */
2383228753Smmstatic int
2384306941Sdelphijcheck_symlinks_fsobj(char *path, int *error_number, struct archive_string *error_string, int flags)
2385228753Smm{
2386228753Smm#if !defined(HAVE_LSTAT)
2387228753Smm	/* Platform doesn't have lstat, so we can't look for symlinks. */
2388306941Sdelphij	(void)path; /* UNUSED */
2389306941Sdelphij	(void)error_number; /* UNUSED */
2390306941Sdelphij	(void)error_string; /* UNUSED */
2391306941Sdelphij	(void)flags; /* UNUSED */
2392228753Smm	return (ARCHIVE_OK);
2393228753Smm#else
2394306941Sdelphij	int res = ARCHIVE_OK;
2395306941Sdelphij	char *tail;
2396306941Sdelphij	char *head;
2397306941Sdelphij	int last;
2398228753Smm	char c;
2399228753Smm	int r;
2400228753Smm	struct stat st;
2401306941Sdelphij	int restore_pwd;
2402228753Smm
2403306941Sdelphij	/* Nothing to do here if name is empty */
2404306941Sdelphij	if(path[0] == '\0')
2405306941Sdelphij	    return (ARCHIVE_OK);
2406306941Sdelphij
2407228753Smm	/*
2408228753Smm	 * Guard against symlink tricks.  Reject any archive entry whose
2409228753Smm	 * destination would be altered by a symlink.
2410306941Sdelphij	 *
2411306941Sdelphij	 * Walk the filename in chunks separated by '/'.  For each segment:
2412306941Sdelphij	 *  - if it doesn't exist, continue
2413306941Sdelphij	 *  - if it's symlink, abort or remove it
2414306941Sdelphij	 *  - if it's a directory and it's not the last chunk, cd into it
2415306941Sdelphij	 * As we go:
2416306941Sdelphij	 *  head points to the current (relative) path
2417306941Sdelphij	 *  tail points to the temporary \0 terminating the segment we're currently examining
2418306941Sdelphij	 *  c holds what used to be in *tail
2419306941Sdelphij	 *  last is 1 if this is the last tail
2420228753Smm	 */
2421306941Sdelphij	restore_pwd = open(".", O_RDONLY | O_BINARY | O_CLOEXEC);
2422306941Sdelphij	__archive_ensure_cloexec_flag(restore_pwd);
2423306941Sdelphij	if (restore_pwd < 0)
2424306941Sdelphij		return (ARCHIVE_FATAL);
2425306941Sdelphij	head = path;
2426306941Sdelphij	tail = path;
2427306941Sdelphij	last = 0;
2428306941Sdelphij	/* TODO: reintroduce a safe cache here? */
2429306941Sdelphij	/* Skip the root directory if the path is absolute. */
2430306941Sdelphij	if(tail == path && tail[0] == '/')
2431306941Sdelphij		++tail;
2432306941Sdelphij	/* Keep going until we've checked the entire name.
2433306941Sdelphij	 * head, tail, path all alias the same string, which is
2434306941Sdelphij	 * temporarily zeroed at tail, so be careful restoring the
2435306941Sdelphij	 * stashed (c=tail[0]) for error messages.
2436306941Sdelphij	 * Exiting the loop with break is okay; continue is not.
2437306941Sdelphij	 */
2438306941Sdelphij	while (!last) {
2439306941Sdelphij		/* Skip the separator we just consumed, plus any adjacent ones */
2440306941Sdelphij		while (*tail == '/')
2441306941Sdelphij		    ++tail;
2442228753Smm		/* Skip the next path element. */
2443306941Sdelphij		while (*tail != '\0' && *tail != '/')
2444306941Sdelphij			++tail;
2445306941Sdelphij		/* is this the last path component? */
2446306941Sdelphij		last = (tail[0] == '\0') || (tail[0] == '/' && tail[1] == '\0');
2447306941Sdelphij		/* temporarily truncate the string here */
2448306941Sdelphij		c = tail[0];
2449306941Sdelphij		tail[0] = '\0';
2450228753Smm		/* Check that we haven't hit a symlink. */
2451306941Sdelphij		r = lstat(head, &st);
2452228753Smm		if (r != 0) {
2453306941Sdelphij			tail[0] = c;
2454228753Smm			/* We've hit a dir that doesn't exist; stop now. */
2455306941Sdelphij			if (errno == ENOENT) {
2456228753Smm				break;
2457306941Sdelphij			} else {
2458306941Sdelphij				/* Treat any other error as fatal - best to be paranoid here
2459306941Sdelphij				 * Note: This effectively disables deep directory
2460306941Sdelphij				 * support when security checks are enabled.
2461306941Sdelphij				 * Otherwise, very long pathnames that trigger
2462306941Sdelphij				 * an error here could evade the sandbox.
2463306941Sdelphij				 * TODO: We could do better, but it would probably
2464306941Sdelphij				 * require merging the symlink checks with the
2465306941Sdelphij				 * deep-directory editing. */
2466306941Sdelphij				if (error_number) *error_number = errno;
2467306941Sdelphij				if (error_string)
2468306941Sdelphij					archive_string_sprintf(error_string,
2469306941Sdelphij							"Could not stat %s",
2470306941Sdelphij							path);
2471306941Sdelphij				res = ARCHIVE_FAILED;
2472306941Sdelphij				break;
2473306941Sdelphij			}
2474306941Sdelphij		} else if (S_ISDIR(st.st_mode)) {
2475306941Sdelphij			if (!last) {
2476306941Sdelphij				if (chdir(head) != 0) {
2477306941Sdelphij					tail[0] = c;
2478306941Sdelphij					if (error_number) *error_number = errno;
2479306941Sdelphij					if (error_string)
2480306941Sdelphij						archive_string_sprintf(error_string,
2481306941Sdelphij								"Could not chdir %s",
2482306941Sdelphij								path);
2483306941Sdelphij					res = (ARCHIVE_FATAL);
2484306941Sdelphij					break;
2485306941Sdelphij				}
2486306941Sdelphij				/* Our view is now from inside this dir: */
2487306941Sdelphij				head = tail + 1;
2488306941Sdelphij			}
2489228753Smm		} else if (S_ISLNK(st.st_mode)) {
2490306941Sdelphij			if (last) {
2491228753Smm				/*
2492228753Smm				 * Last element is symlink; remove it
2493228753Smm				 * so we can overwrite it with the
2494228753Smm				 * item being extracted.
2495228753Smm				 */
2496306941Sdelphij				if (unlink(head)) {
2497306941Sdelphij					tail[0] = c;
2498306941Sdelphij					if (error_number) *error_number = errno;
2499306941Sdelphij					if (error_string)
2500306941Sdelphij						archive_string_sprintf(error_string,
2501306941Sdelphij								"Could not remove symlink %s",
2502306941Sdelphij								path);
2503306941Sdelphij					res = ARCHIVE_FAILED;
2504306941Sdelphij					break;
2505228753Smm				}
2506228753Smm				/*
2507228753Smm				 * Even if we did remove it, a warning
2508228753Smm				 * is in order.  The warning is silly,
2509228753Smm				 * though, if we're just replacing one
2510228753Smm				 * symlink with another symlink.
2511228753Smm				 */
2512306941Sdelphij				tail[0] = c;
2513306941Sdelphij				/* FIXME:  not sure how important this is to restore
2514306941Sdelphij				if (!S_ISLNK(path)) {
2515306941Sdelphij					if (error_number) *error_number = 0;
2516306941Sdelphij					if (error_string)
2517306941Sdelphij						archive_string_sprintf(error_string,
2518306941Sdelphij								"Removing symlink %s",
2519306941Sdelphij								path);
2520228753Smm				}
2521306941Sdelphij				*/
2522228753Smm				/* Symlink gone.  No more problem! */
2523306941Sdelphij				res = ARCHIVE_OK;
2524306941Sdelphij				break;
2525306941Sdelphij			} else if (flags & ARCHIVE_EXTRACT_UNLINK) {
2526228753Smm				/* User asked us to remove problems. */
2527306941Sdelphij				if (unlink(head) != 0) {
2528306941Sdelphij					tail[0] = c;
2529306941Sdelphij					if (error_number) *error_number = 0;
2530306941Sdelphij					if (error_string)
2531306941Sdelphij						archive_string_sprintf(error_string,
2532306941Sdelphij								"Cannot remove intervening symlink %s",
2533306941Sdelphij								path);
2534306941Sdelphij					res = ARCHIVE_FAILED;
2535306941Sdelphij					break;
2536228753Smm				}
2537306941Sdelphij				tail[0] = c;
2538228753Smm			} else {
2539306941Sdelphij				tail[0] = c;
2540306941Sdelphij				if (error_number) *error_number = 0;
2541306941Sdelphij				if (error_string)
2542306941Sdelphij					archive_string_sprintf(error_string,
2543306941Sdelphij							"Cannot extract through symlink %s",
2544306941Sdelphij							path);
2545306941Sdelphij				res = ARCHIVE_FAILED;
2546306941Sdelphij				break;
2547228753Smm			}
2548228753Smm		}
2549306941Sdelphij		/* be sure to always maintain this */
2550306941Sdelphij		tail[0] = c;
2551306941Sdelphij		if (tail[0] != '\0')
2552306941Sdelphij			tail++; /* Advance to the next segment. */
2553228753Smm	}
2554306941Sdelphij	/* Catches loop exits via break */
2555306941Sdelphij	tail[0] = c;
2556306941Sdelphij#ifdef HAVE_FCHDIR
2557306941Sdelphij	/* If we changed directory above, restore it here. */
2558306941Sdelphij	if (restore_pwd >= 0) {
2559306941Sdelphij		r = fchdir(restore_pwd);
2560306941Sdelphij		if (r != 0) {
2561306941Sdelphij			if(error_number) *error_number = errno;
2562306941Sdelphij			if(error_string)
2563306941Sdelphij				archive_string_sprintf(error_string,
2564306941Sdelphij						"chdir() failure");
2565306941Sdelphij		}
2566306941Sdelphij		close(restore_pwd);
2567306941Sdelphij		restore_pwd = -1;
2568306941Sdelphij		if (r != 0) {
2569306941Sdelphij			res = (ARCHIVE_FATAL);
2570306941Sdelphij		}
2571306941Sdelphij	}
2572228753Smm#endif
2573306941Sdelphij	/* TODO: reintroduce a safe cache here? */
2574306941Sdelphij	return res;
2575306941Sdelphij#endif
2576228753Smm}
2577228753Smm
2578306941Sdelphij/*
2579306941Sdelphij * Check a->name for symlinks, returning ARCHIVE_OK if its clean, otherwise
2580306941Sdelphij * calls archive_set_error and returns ARCHIVE_{FATAL,FAILED}
2581306941Sdelphij */
2582306941Sdelphijstatic int
2583306941Sdelphijcheck_symlinks(struct archive_write_disk *a)
2584306941Sdelphij{
2585306941Sdelphij	struct archive_string error_string;
2586306941Sdelphij	int error_number;
2587306941Sdelphij	int rc;
2588306941Sdelphij	archive_string_init(&error_string);
2589306941Sdelphij	rc = check_symlinks_fsobj(a->name, &error_number, &error_string, a->flags);
2590306941Sdelphij	if (rc != ARCHIVE_OK) {
2591306941Sdelphij		archive_set_error(&a->archive, error_number, "%s", error_string.s);
2592306941Sdelphij	}
2593306941Sdelphij	archive_string_free(&error_string);
2594306941Sdelphij	a->pst = NULL;	/* to be safe */
2595306941Sdelphij	return rc;
2596306941Sdelphij}
2597306941Sdelphij
2598306941Sdelphij
2599231200Smm#if defined(__CYGWIN__)
2600228753Smm/*
2601228753Smm * 1. Convert a path separator from '\' to '/' .
2602231200Smm *    We shouldn't check multibyte character directly because some
2603228753Smm *    character-set have been using the '\' character for a part of
2604228753Smm *    its multibyte character code.
2605228753Smm * 2. Replace unusable characters in Windows with underscore('_').
2606228753Smm * See also : http://msdn.microsoft.com/en-us/library/aa365247.aspx
2607228753Smm */
2608231200Smmstatic void
2609228753Smmcleanup_pathname_win(struct archive_write_disk *a)
2610228753Smm{
2611228753Smm	wchar_t wc;
2612228753Smm	char *p;
2613228753Smm	size_t alen, l;
2614231200Smm	int mb, complete, utf8;
2615228753Smm
2616231200Smm	alen = 0;
2617231200Smm	mb = 0;
2618231200Smm	complete = 1;
2619231200Smm	utf8 = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)? 1: 0;
2620231200Smm	for (p = a->name; *p != '\0'; p++) {
2621231200Smm		++alen;
2622231200Smm		if (*p == '\\') {
2623231200Smm			/* If previous byte is smaller than 128,
2624231200Smm			 * this is not second byte of multibyte characters,
2625231200Smm			 * so we can replace '\' with '/'. */
2626231200Smm			if (utf8 || !mb)
2627231200Smm				*p = '/';
2628228753Smm			else
2629231200Smm				complete = 0;/* uncompleted. */
2630231200Smm		} else if (*(unsigned char *)p > 127)
2631231200Smm			mb = 1;
2632231200Smm		else
2633231200Smm			mb = 0;
2634231200Smm		/* Rewrite the path name if its next character is unusable. */
2635228753Smm		if (*p == ':' || *p == '*' || *p == '?' || *p == '"' ||
2636228753Smm		    *p == '<' || *p == '>' || *p == '|')
2637228753Smm			*p = '_';
2638228753Smm	}
2639231200Smm	if (complete)
2640231200Smm		return;
2641231200Smm
2642228753Smm	/*
2643231200Smm	 * Convert path separator in wide-character.
2644228753Smm	 */
2645228753Smm	p = a->name;
2646228753Smm	while (*p != '\0' && alen) {
2647228753Smm		l = mbtowc(&wc, p, alen);
2648232153Smm		if (l == (size_t)-1) {
2649228753Smm			while (*p != '\0') {
2650228753Smm				if (*p == '\\')
2651228753Smm					*p = '/';
2652228753Smm				++p;
2653228753Smm			}
2654228753Smm			break;
2655228753Smm		}
2656228753Smm		if (l == 1 && wc == L'\\')
2657228753Smm			*p = '/';
2658228753Smm		p += l;
2659228753Smm		alen -= l;
2660228753Smm	}
2661228753Smm}
2662228753Smm#endif
2663228753Smm
2664228753Smm/*
2665228753Smm * Canonicalize the pathname.  In particular, this strips duplicate
2666228753Smm * '/' characters, '.' elements, and trailing '/'.  It also raises an
2667301046Sglebius * error for an empty path, a trailing '..', (if _SECURE_NODOTDOT is
2668301046Sglebius * set) any '..' in the path or (if ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS
2669301046Sglebius * is set) if the path is absolute.
2670228753Smm */
2671228753Smmstatic int
2672306941Sdelphijcleanup_pathname_fsobj(char *path, int *error_number, struct archive_string *error_string, int flags)
2673228753Smm{
2674228753Smm	char *dest, *src;
2675228753Smm	char separator = '\0';
2676228753Smm
2677306941Sdelphij	dest = src = path;
2678228753Smm	if (*src == '\0') {
2679306941Sdelphij		if (error_number) *error_number = ARCHIVE_ERRNO_MISC;
2680306941Sdelphij		if (error_string)
2681306941Sdelphij		    archive_string_sprintf(error_string,
2682306941Sdelphij			    "Invalid empty pathname");
2683228753Smm		return (ARCHIVE_FAILED);
2684228753Smm	}
2685228753Smm
2686231200Smm#if defined(__CYGWIN__)
2687231200Smm	cleanup_pathname_win(a);
2688228753Smm#endif
2689228753Smm	/* Skip leading '/'. */
2690301046Sglebius	if (*src == '/') {
2691306941Sdelphij		if (flags & ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS) {
2692306941Sdelphij			if (error_number) *error_number = ARCHIVE_ERRNO_MISC;
2693306941Sdelphij			if (error_string)
2694306941Sdelphij			    archive_string_sprintf(error_string,
2695306941Sdelphij				    "Path is absolute");
2696301046Sglebius			return (ARCHIVE_FAILED);
2697301046Sglebius		}
2698301046Sglebius
2699228753Smm		separator = *src++;
2700301046Sglebius	}
2701228753Smm
2702228753Smm	/* Scan the pathname one element at a time. */
2703228753Smm	for (;;) {
2704228753Smm		/* src points to first char after '/' */
2705228753Smm		if (src[0] == '\0') {
2706228753Smm			break;
2707228753Smm		} else if (src[0] == '/') {
2708228753Smm			/* Found '//', ignore second one. */
2709228753Smm			src++;
2710228753Smm			continue;
2711228753Smm		} else if (src[0] == '.') {
2712228753Smm			if (src[1] == '\0') {
2713228753Smm				/* Ignore trailing '.' */
2714228753Smm				break;
2715228753Smm			} else if (src[1] == '/') {
2716228753Smm				/* Skip './'. */
2717228753Smm				src += 2;
2718228753Smm				continue;
2719228753Smm			} else if (src[1] == '.') {
2720228753Smm				if (src[2] == '/' || src[2] == '\0') {
2721228753Smm					/* Conditionally warn about '..' */
2722306941Sdelphij					if (flags & ARCHIVE_EXTRACT_SECURE_NODOTDOT) {
2723306941Sdelphij						if (error_number) *error_number = ARCHIVE_ERRNO_MISC;
2724306941Sdelphij						if (error_string)
2725306941Sdelphij						    archive_string_sprintf(error_string,
2726306941Sdelphij							    "Path contains '..'");
2727228753Smm						return (ARCHIVE_FAILED);
2728228753Smm					}
2729228753Smm				}
2730228753Smm				/*
2731228753Smm				 * Note: Under no circumstances do we
2732228753Smm				 * remove '..' elements.  In
2733228753Smm				 * particular, restoring
2734228753Smm				 * '/foo/../bar/' should create the
2735228753Smm				 * 'foo' dir as a side-effect.
2736228753Smm				 */
2737228753Smm			}
2738228753Smm		}
2739228753Smm
2740228753Smm		/* Copy current element, including leading '/'. */
2741228753Smm		if (separator)
2742228753Smm			*dest++ = '/';
2743228753Smm		while (*src != '\0' && *src != '/') {
2744228753Smm			*dest++ = *src++;
2745228753Smm		}
2746228753Smm
2747228753Smm		if (*src == '\0')
2748228753Smm			break;
2749228753Smm
2750228753Smm		/* Skip '/' separator. */
2751228753Smm		separator = *src++;
2752228753Smm	}
2753228753Smm	/*
2754228753Smm	 * We've just copied zero or more path elements, not including the
2755228753Smm	 * final '/'.
2756228753Smm	 */
2757306941Sdelphij	if (dest == path) {
2758228753Smm		/*
2759228753Smm		 * Nothing got copied.  The path must have been something
2760228753Smm		 * like '.' or '/' or './' or '/././././/./'.
2761228753Smm		 */
2762228753Smm		if (separator)
2763228753Smm			*dest++ = '/';
2764228753Smm		else
2765228753Smm			*dest++ = '.';
2766228753Smm	}
2767228753Smm	/* Terminate the result. */
2768228753Smm	*dest = '\0';
2769228753Smm	return (ARCHIVE_OK);
2770228753Smm}
2771228753Smm
2772306941Sdelphijstatic int
2773306941Sdelphijcleanup_pathname(struct archive_write_disk *a)
2774306941Sdelphij{
2775306941Sdelphij	struct archive_string error_string;
2776306941Sdelphij	int error_number;
2777306941Sdelphij	int rc;
2778306941Sdelphij	archive_string_init(&error_string);
2779306941Sdelphij	rc = cleanup_pathname_fsobj(a->name, &error_number, &error_string, a->flags);
2780306941Sdelphij	if (rc != ARCHIVE_OK) {
2781306941Sdelphij		archive_set_error(&a->archive, error_number, "%s", error_string.s);
2782306941Sdelphij	}
2783306941Sdelphij	archive_string_free(&error_string);
2784306941Sdelphij	return rc;
2785306941Sdelphij}
2786306941Sdelphij
2787228753Smm/*
2788228753Smm * Create the parent directory of the specified path, assuming path
2789228753Smm * is already in mutable storage.
2790228753Smm */
2791228753Smmstatic int
2792228753Smmcreate_parent_dir(struct archive_write_disk *a, char *path)
2793228753Smm{
2794228753Smm	char *slash;
2795228753Smm	int r;
2796228753Smm
2797228753Smm	/* Remove tail element to obtain parent name. */
2798228753Smm	slash = strrchr(path, '/');
2799228753Smm	if (slash == NULL)
2800228753Smm		return (ARCHIVE_OK);
2801228753Smm	*slash = '\0';
2802228753Smm	r = create_dir(a, path);
2803228753Smm	*slash = '/';
2804228753Smm	return (r);
2805228753Smm}
2806228753Smm
2807228753Smm/*
2808228753Smm * Create the specified dir, recursing to create parents as necessary.
2809228753Smm *
2810228753Smm * Returns ARCHIVE_OK if the path exists when we're done here.
2811228753Smm * Otherwise, returns ARCHIVE_FAILED.
2812228753Smm * Assumes path is in mutable storage; path is unchanged on exit.
2813228753Smm */
2814228753Smmstatic int
2815228753Smmcreate_dir(struct archive_write_disk *a, char *path)
2816228753Smm{
2817228753Smm	struct stat st;
2818228753Smm	struct fixup_entry *le;
2819228753Smm	char *slash, *base;
2820228753Smm	mode_t mode_final, mode;
2821228753Smm	int r;
2822228753Smm
2823228753Smm	/* Check for special names and just skip them. */
2824228753Smm	slash = strrchr(path, '/');
2825228753Smm	if (slash == NULL)
2826228753Smm		base = path;
2827228753Smm	else
2828228753Smm		base = slash + 1;
2829228753Smm
2830228753Smm	if (base[0] == '\0' ||
2831228753Smm	    (base[0] == '.' && base[1] == '\0') ||
2832228753Smm	    (base[0] == '.' && base[1] == '.' && base[2] == '\0')) {
2833228753Smm		/* Don't bother trying to create null path, '.', or '..'. */
2834228753Smm		if (slash != NULL) {
2835228753Smm			*slash = '\0';
2836228753Smm			r = create_dir(a, path);
2837228753Smm			*slash = '/';
2838228753Smm			return (r);
2839228753Smm		}
2840228753Smm		return (ARCHIVE_OK);
2841228753Smm	}
2842228753Smm
2843228753Smm	/*
2844228753Smm	 * Yes, this should be stat() and not lstat().  Using lstat()
2845228753Smm	 * here loses the ability to extract through symlinks.  Also note
2846228753Smm	 * that this should not use the a->st cache.
2847228753Smm	 */
2848228753Smm	if (stat(path, &st) == 0) {
2849228753Smm		if (S_ISDIR(st.st_mode))
2850228753Smm			return (ARCHIVE_OK);
2851228753Smm		if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
2852228753Smm			archive_set_error(&a->archive, EEXIST,
2853228753Smm			    "Can't create directory '%s'", path);
2854228753Smm			return (ARCHIVE_FAILED);
2855228753Smm		}
2856228753Smm		if (unlink(path) != 0) {
2857228753Smm			archive_set_error(&a->archive, errno,
2858228753Smm			    "Can't create directory '%s': "
2859231200Smm			    "Conflicting file cannot be removed",
2860231200Smm			    path);
2861228753Smm			return (ARCHIVE_FAILED);
2862228753Smm		}
2863228753Smm	} else if (errno != ENOENT && errno != ENOTDIR) {
2864228753Smm		/* Stat failed? */
2865228753Smm		archive_set_error(&a->archive, errno, "Can't test directory '%s'", path);
2866228753Smm		return (ARCHIVE_FAILED);
2867228753Smm	} else if (slash != NULL) {
2868228753Smm		*slash = '\0';
2869228753Smm		r = create_dir(a, path);
2870228753Smm		*slash = '/';
2871228753Smm		if (r != ARCHIVE_OK)
2872228753Smm			return (r);
2873228753Smm	}
2874228753Smm
2875228753Smm	/*
2876228753Smm	 * Mode we want for the final restored directory.  Per POSIX,
2877228753Smm	 * implicitly-created dirs must be created obeying the umask.
2878228753Smm	 * There's no mention whether this is different for privileged
2879228753Smm	 * restores (which the rest of this code handles by pretending
2880228753Smm	 * umask=0).  I've chosen here to always obey the user's umask for
2881228753Smm	 * implicit dirs, even if _EXTRACT_PERM was specified.
2882228753Smm	 */
2883228753Smm	mode_final = DEFAULT_DIR_MODE & ~a->user_umask;
2884228753Smm	/* Mode we want on disk during the restore process. */
2885228753Smm	mode = mode_final;
2886228753Smm	mode |= MINIMUM_DIR_MODE;
2887228753Smm	mode &= MAXIMUM_DIR_MODE;
2888228753Smm	if (mkdir(path, mode) == 0) {
2889228753Smm		if (mode != mode_final) {
2890228753Smm			le = new_fixup(a, path);
2891248616Smm			if (le == NULL)
2892248616Smm				return (ARCHIVE_FATAL);
2893228753Smm			le->fixup |=TODO_MODE_BASE;
2894228753Smm			le->mode = mode_final;
2895228753Smm		}
2896228753Smm		return (ARCHIVE_OK);
2897228753Smm	}
2898228753Smm
2899228753Smm	/*
2900228753Smm	 * Without the following check, a/b/../b/c/d fails at the
2901228753Smm	 * second visit to 'b', so 'd' can't be created.  Note that we
2902228753Smm	 * don't add it to the fixup list here, as it's already been
2903228753Smm	 * added.
2904228753Smm	 */
2905228753Smm	if (stat(path, &st) == 0 && S_ISDIR(st.st_mode))
2906228753Smm		return (ARCHIVE_OK);
2907228753Smm
2908228753Smm	archive_set_error(&a->archive, errno, "Failed to create dir '%s'",
2909228753Smm	    path);
2910228753Smm	return (ARCHIVE_FAILED);
2911228753Smm}
2912228753Smm
2913228753Smm/*
2914228753Smm * Note: Although we can skip setting the user id if the desired user
2915228753Smm * id matches the current user, we cannot skip setting the group, as
2916228753Smm * many systems set the gid based on the containing directory.  So
2917228753Smm * we have to perform a chown syscall if we want to set the SGID
2918228753Smm * bit.  (The alternative is to stat() and then possibly chown(); it's
2919228753Smm * more efficient to skip the stat() and just always chown().)  Note
2920228753Smm * that a successful chown() here clears the TODO_SGID_CHECK bit, which
2921228753Smm * allows set_mode to skip the stat() check for the GID.
2922228753Smm */
2923228753Smmstatic int
2924228753Smmset_ownership(struct archive_write_disk *a)
2925228753Smm{
2926228753Smm#ifndef __CYGWIN__
2927228753Smm/* unfortunately, on win32 there is no 'root' user with uid 0,
2928228753Smm   so we just have to try the chown and see if it works */
2929228753Smm
2930228753Smm	/* If we know we can't change it, don't bother trying. */
2931228753Smm	if (a->user_uid != 0  &&  a->user_uid != a->uid) {
2932228753Smm		archive_set_error(&a->archive, errno,
2933231200Smm		    "Can't set UID=%jd", (intmax_t)a->uid);
2934228753Smm		return (ARCHIVE_WARN);
2935228753Smm	}
2936228753Smm#endif
2937228753Smm
2938228753Smm#ifdef HAVE_FCHOWN
2939228753Smm	/* If we have an fd, we can avoid a race. */
2940228753Smm	if (a->fd >= 0 && fchown(a->fd, a->uid, a->gid) == 0) {
2941228753Smm		/* We've set owner and know uid/gid are correct. */
2942228753Smm		a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK);
2943228753Smm		return (ARCHIVE_OK);
2944228753Smm	}
2945228753Smm#endif
2946228753Smm
2947228753Smm	/* We prefer lchown() but will use chown() if that's all we have. */
2948228753Smm	/* Of course, if we have neither, this will always fail. */
2949228753Smm#ifdef HAVE_LCHOWN
2950228753Smm	if (lchown(a->name, a->uid, a->gid) == 0) {
2951228753Smm		/* We've set owner and know uid/gid are correct. */
2952228753Smm		a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK);
2953228753Smm		return (ARCHIVE_OK);
2954228753Smm	}
2955228753Smm#elif HAVE_CHOWN
2956228753Smm	if (!S_ISLNK(a->mode) && chown(a->name, a->uid, a->gid) == 0) {
2957228753Smm		/* We've set owner and know uid/gid are correct. */
2958228753Smm		a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK);
2959228753Smm		return (ARCHIVE_OK);
2960228753Smm	}
2961228753Smm#endif
2962228753Smm
2963228753Smm	archive_set_error(&a->archive, errno,
2964231200Smm	    "Can't set user=%jd/group=%jd for %s",
2965231200Smm	    (intmax_t)a->uid, (intmax_t)a->gid, a->name);
2966228753Smm	return (ARCHIVE_WARN);
2967228753Smm}
2968228753Smm
2969231200Smm/*
2970231200Smm * Note: Returns 0 on success, non-zero on failure.
2971228753Smm */
2972228753Smmstatic int
2973228753Smmset_time(int fd, int mode, const char *name,
2974228753Smm    time_t atime, long atime_nsec,
2975228753Smm    time_t mtime, long mtime_nsec)
2976228753Smm{
2977231200Smm	/* Select the best implementation for this platform. */
2978231200Smm#if defined(HAVE_UTIMENSAT) && defined(HAVE_FUTIMENS)
2979231200Smm	/*
2980231200Smm	 * utimensat() and futimens() are defined in
2981231200Smm	 * POSIX.1-2008. They support ns resolution and setting times
2982231200Smm	 * on fds and symlinks.
2983231200Smm	 */
2984228753Smm	struct timespec ts[2];
2985232153Smm	(void)mode; /* UNUSED */
2986228753Smm	ts[0].tv_sec = atime;
2987228753Smm	ts[0].tv_nsec = atime_nsec;
2988228753Smm	ts[1].tv_sec = mtime;
2989228753Smm	ts[1].tv_nsec = mtime_nsec;
2990228753Smm	if (fd >= 0)
2991228753Smm		return futimens(fd, ts);
2992228753Smm	return utimensat(AT_FDCWD, name, ts, AT_SYMLINK_NOFOLLOW);
2993231200Smm
2994228753Smm#elif HAVE_UTIMES
2995231200Smm	/*
2996231200Smm	 * The utimes()-family functions support ��s-resolution and
2997231200Smm	 * setting times fds and symlinks.  utimes() is documented as
2998231200Smm	 * LEGACY by POSIX, futimes() and lutimes() are not described
2999231200Smm	 * in POSIX.
3000231200Smm	 */
3001228753Smm	struct timeval times[2];
3002228753Smm
3003228753Smm	times[0].tv_sec = atime;
3004228753Smm	times[0].tv_usec = atime_nsec / 1000;
3005228753Smm	times[1].tv_sec = mtime;
3006228753Smm	times[1].tv_usec = mtime_nsec / 1000;
3007228753Smm
3008228753Smm#ifdef HAVE_FUTIMES
3009228753Smm	if (fd >= 0)
3010228753Smm		return (futimes(fd, times));
3011228753Smm#else
3012228753Smm	(void)fd; /* UNUSED */
3013228753Smm#endif
3014228753Smm#ifdef HAVE_LUTIMES
3015228753Smm	(void)mode; /* UNUSED */
3016228753Smm	return (lutimes(name, times));
3017228753Smm#else
3018228753Smm	if (S_ISLNK(mode))
3019228753Smm		return (0);
3020228753Smm	return (utimes(name, times));
3021228753Smm#endif
3022231200Smm
3023228753Smm#elif defined(HAVE_UTIME)
3024231200Smm	/*
3025231200Smm	 * utime() is POSIX-standard but only supports 1s resolution and
3026231200Smm	 * does not support fds or symlinks.
3027231200Smm	 */
3028228753Smm	struct utimbuf times;
3029228753Smm	(void)fd; /* UNUSED */
3030228753Smm	(void)name; /* UNUSED */
3031228753Smm	(void)atime_nsec; /* UNUSED */
3032228753Smm	(void)mtime_nsec; /* UNUSED */
3033228753Smm	times.actime = atime;
3034228753Smm	times.modtime = mtime;
3035228753Smm	if (S_ISLNK(mode))
3036228753Smm		return (ARCHIVE_OK);
3037228753Smm	return (utime(name, &times));
3038231200Smm
3039231200Smm#else
3040231200Smm	/*
3041231200Smm	 * We don't know how to set the time on this platform.
3042231200Smm	 */
3043232153Smm	(void)fd; /* UNUSED */
3044232153Smm	(void)mode; /* UNUSED */
3045232153Smm	(void)name; /* UNUSED */
3046232153Smm	(void)atime_nsec; /* UNUSED */
3047232153Smm	(void)mtime_nsec; /* UNUSED */
3048231200Smm	return (ARCHIVE_WARN);
3049231200Smm#endif
3050228753Smm}
3051231200Smm
3052231200Smm#ifdef F_SETTIMES /* Tru64 */
3053228753Smmstatic int
3054231200Smmset_time_tru64(int fd, int mode, const char *name,
3055228753Smm    time_t atime, long atime_nsec,
3056231200Smm    time_t mtime, long mtime_nsec,
3057231200Smm    time_t ctime, long ctime_nsec)
3058228753Smm{
3059231200Smm	struct attr_timbuf tstamp;
3060231200Smm	struct timeval times[3];
3061231200Smm	times[0].tv_sec = atime;
3062231200Smm	times[0].tv_usec = atime_nsec / 1000;
3063231200Smm	times[1].tv_sec = mtime;
3064231200Smm	times[1].tv_usec = mtime_nsec / 1000;
3065231200Smm	times[2].tv_sec = ctime;
3066231200Smm	times[2].tv_usec = ctime_nsec / 1000;
3067231200Smm	tstamp.atime = times[0];
3068231200Smm	tstamp.mtime = times[1];
3069231200Smm	tstamp.ctime = times[2];
3070231200Smm	return (fcntl(fd,F_SETTIMES,&tstamp));
3071228753Smm}
3072231200Smm#endif /* Tru64 */
3073231200Smm
3074231200Smmstatic int
3075231200Smmset_times(struct archive_write_disk *a,
3076231200Smm    int fd, int mode, const char *name,
3077231200Smm    time_t atime, long atime_nanos,
3078231200Smm    time_t birthtime, long birthtime_nanos,
3079231200Smm    time_t mtime, long mtime_nanos,
3080232153Smm    time_t cctime, long ctime_nanos)
3081231200Smm{
3082231200Smm	/* Note: set_time doesn't use libarchive return conventions!
3083231200Smm	 * It uses syscall conventions.  So 0 here instead of ARCHIVE_OK. */
3084231200Smm	int r1 = 0, r2 = 0;
3085231200Smm
3086231200Smm#ifdef F_SETTIMES
3087231200Smm	 /*
3088231200Smm	 * on Tru64 try own fcntl first which can restore even the
3089231200Smm	 * ctime, fall back to default code path below if it fails
3090231200Smm	 * or if we are not running as root
3091231200Smm	 */
3092231200Smm	if (a->user_uid == 0 &&
3093231200Smm	    set_time_tru64(fd, mode, name,
3094231200Smm			   atime, atime_nanos, mtime,
3095232153Smm			   mtime_nanos, cctime, ctime_nanos) == 0) {
3096231200Smm		return (ARCHIVE_OK);
3097231200Smm	}
3098232153Smm#else /* Tru64 */
3099232153Smm	(void)cctime; /* UNUSED */
3100232153Smm	(void)ctime_nanos; /* UNUSED */
3101231200Smm#endif /* Tru64 */
3102231200Smm
3103231200Smm#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
3104231200Smm	/*
3105231200Smm	 * If you have struct stat.st_birthtime, we assume BSD
3106231200Smm	 * birthtime semantics, in which {f,l,}utimes() updates
3107231200Smm	 * birthtime to earliest mtime.  So we set the time twice,
3108231200Smm	 * first using the birthtime, then using the mtime.  If
3109231200Smm	 * birthtime == mtime, this isn't necessary, so we skip it.
3110231200Smm	 * If birthtime > mtime, then this won't work, so we skip it.
3111231200Smm	 */
3112231200Smm	if (birthtime < mtime
3113231200Smm	    || (birthtime == mtime && birthtime_nanos < mtime_nanos))
3114231200Smm		r1 = set_time(fd, mode, name,
3115231200Smm			      atime, atime_nanos,
3116231200Smm			      birthtime, birthtime_nanos);
3117232153Smm#else
3118232153Smm	(void)birthtime; /* UNUSED */
3119232153Smm	(void)birthtime_nanos; /* UNUSED */
3120228753Smm#endif
3121231200Smm	r2 = set_time(fd, mode, name,
3122231200Smm		      atime, atime_nanos,
3123231200Smm		      mtime, mtime_nanos);
3124231200Smm	if (r1 != 0 || r2 != 0) {
3125231200Smm		archive_set_error(&a->archive, errno,
3126231200Smm				  "Can't restore time");
3127231200Smm		return (ARCHIVE_WARN);
3128231200Smm	}
3129231200Smm	return (ARCHIVE_OK);
3130231200Smm}
3131228753Smm
3132228753Smmstatic int
3133231200Smmset_times_from_entry(struct archive_write_disk *a)
3134228753Smm{
3135232153Smm	time_t atime, birthtime, mtime, cctime;
3136231200Smm	long atime_nsec, birthtime_nsec, mtime_nsec, ctime_nsec;
3137228753Smm
3138231200Smm	/* Suitable defaults. */
3139232153Smm	atime = birthtime = mtime = cctime = a->start_time;
3140231200Smm	atime_nsec = birthtime_nsec = mtime_nsec = ctime_nsec = 0;
3141231200Smm
3142228753Smm	/* If no time was provided, we're done. */
3143228753Smm	if (!archive_entry_atime_is_set(a->entry)
3144228753Smm#if HAVE_STRUCT_STAT_ST_BIRTHTIME
3145228753Smm	    && !archive_entry_birthtime_is_set(a->entry)
3146228753Smm#endif
3147228753Smm	    && !archive_entry_mtime_is_set(a->entry))
3148228753Smm		return (ARCHIVE_OK);
3149228753Smm
3150228753Smm	if (archive_entry_atime_is_set(a->entry)) {
3151228753Smm		atime = archive_entry_atime(a->entry);
3152228753Smm		atime_nsec = archive_entry_atime_nsec(a->entry);
3153228753Smm	}
3154231200Smm	if (archive_entry_birthtime_is_set(a->entry)) {
3155231200Smm		birthtime = archive_entry_birthtime(a->entry);
3156231200Smm		birthtime_nsec = archive_entry_birthtime_nsec(a->entry);
3157231200Smm	}
3158228753Smm	if (archive_entry_mtime_is_set(a->entry)) {
3159228753Smm		mtime = archive_entry_mtime(a->entry);
3160228753Smm		mtime_nsec = archive_entry_mtime_nsec(a->entry);
3161228753Smm	}
3162231200Smm	if (archive_entry_ctime_is_set(a->entry)) {
3163232153Smm		cctime = archive_entry_ctime(a->entry);
3164231200Smm		ctime_nsec = archive_entry_ctime_nsec(a->entry);
3165228753Smm	}
3166228753Smm
3167231200Smm	return set_times(a, a->fd, a->mode, a->name,
3168231200Smm			 atime, atime_nsec,
3169231200Smm			 birthtime, birthtime_nsec,
3170231200Smm			 mtime, mtime_nsec,
3171232153Smm			 cctime, ctime_nsec);
3172228753Smm}
3173228753Smm
3174228753Smmstatic int
3175228753Smmset_mode(struct archive_write_disk *a, int mode)
3176228753Smm{
3177228753Smm	int r = ARCHIVE_OK;
3178228753Smm	mode &= 07777; /* Strip off file type bits. */
3179228753Smm
3180228753Smm	if (a->todo & TODO_SGID_CHECK) {
3181228753Smm		/*
3182228753Smm		 * If we don't know the GID is right, we must stat()
3183228753Smm		 * to verify it.  We can't just check the GID of this
3184228753Smm		 * process, since systems sometimes set GID from
3185228753Smm		 * the enclosing dir or based on ACLs.
3186228753Smm		 */
3187231200Smm		if ((r = lazy_stat(a)) != ARCHIVE_OK)
3188228753Smm			return (r);
3189228753Smm		if (a->pst->st_gid != a->gid) {
3190228753Smm			mode &= ~ S_ISGID;
3191228753Smm			if (a->flags & ARCHIVE_EXTRACT_OWNER) {
3192228753Smm				/*
3193228753Smm				 * This is only an error if you
3194228753Smm				 * requested owner restore.  If you
3195228753Smm				 * didn't, we'll try to restore
3196228753Smm				 * sgid/suid, but won't consider it a
3197228753Smm				 * problem if we can't.
3198228753Smm				 */
3199228753Smm				archive_set_error(&a->archive, -1,
3200228753Smm				    "Can't restore SGID bit");
3201228753Smm				r = ARCHIVE_WARN;
3202228753Smm			}
3203228753Smm		}
3204228753Smm		/* While we're here, double-check the UID. */
3205228753Smm		if (a->pst->st_uid != a->uid
3206228753Smm		    && (a->todo & TODO_SUID)) {
3207228753Smm			mode &= ~ S_ISUID;
3208228753Smm			if (a->flags & ARCHIVE_EXTRACT_OWNER) {
3209228753Smm				archive_set_error(&a->archive, -1,
3210228753Smm				    "Can't restore SUID bit");
3211228753Smm				r = ARCHIVE_WARN;
3212228753Smm			}
3213228753Smm		}
3214228753Smm		a->todo &= ~TODO_SGID_CHECK;
3215228753Smm		a->todo &= ~TODO_SUID_CHECK;
3216228753Smm	} else if (a->todo & TODO_SUID_CHECK) {
3217228753Smm		/*
3218228753Smm		 * If we don't know the UID is right, we can just check
3219228753Smm		 * the user, since all systems set the file UID from
3220228753Smm		 * the process UID.
3221228753Smm		 */
3222228753Smm		if (a->user_uid != a->uid) {
3223228753Smm			mode &= ~ S_ISUID;
3224228753Smm			if (a->flags & ARCHIVE_EXTRACT_OWNER) {
3225228753Smm				archive_set_error(&a->archive, -1,
3226228753Smm				    "Can't make file SUID");
3227228753Smm				r = ARCHIVE_WARN;
3228228753Smm			}
3229228753Smm		}
3230228753Smm		a->todo &= ~TODO_SUID_CHECK;
3231228753Smm	}
3232228753Smm
3233228753Smm	if (S_ISLNK(a->mode)) {
3234228753Smm#ifdef HAVE_LCHMOD
3235228753Smm		/*
3236228753Smm		 * If this is a symlink, use lchmod().  If the
3237228753Smm		 * platform doesn't support lchmod(), just skip it.  A
3238228753Smm		 * platform that doesn't provide a way to set
3239228753Smm		 * permissions on symlinks probably ignores
3240228753Smm		 * permissions on symlinks, so a failure here has no
3241228753Smm		 * impact.
3242228753Smm		 */
3243228753Smm		if (lchmod(a->name, mode) != 0) {
3244228753Smm			archive_set_error(&a->archive, errno,
3245228753Smm			    "Can't set permissions to 0%o", (int)mode);
3246228753Smm			r = ARCHIVE_WARN;
3247228753Smm		}
3248228753Smm#endif
3249228753Smm	} else if (!S_ISDIR(a->mode)) {
3250228753Smm		/*
3251228753Smm		 * If it's not a symlink and not a dir, then use
3252228753Smm		 * fchmod() or chmod(), depending on whether we have
3253228753Smm		 * an fd.  Dirs get their perms set during the
3254228753Smm		 * post-extract fixup, which is handled elsewhere.
3255228753Smm		 */
3256228753Smm#ifdef HAVE_FCHMOD
3257228753Smm		if (a->fd >= 0) {
3258228753Smm			if (fchmod(a->fd, mode) != 0) {
3259228753Smm				archive_set_error(&a->archive, errno,
3260228753Smm				    "Can't set permissions to 0%o", (int)mode);
3261228753Smm				r = ARCHIVE_WARN;
3262228753Smm			}
3263228753Smm		} else
3264228753Smm#endif
3265228753Smm			/* If this platform lacks fchmod(), then
3266228753Smm			 * we'll just use chmod(). */
3267228753Smm			if (chmod(a->name, mode) != 0) {
3268228753Smm				archive_set_error(&a->archive, errno,
3269228753Smm				    "Can't set permissions to 0%o", (int)mode);
3270228753Smm				r = ARCHIVE_WARN;
3271228753Smm			}
3272228753Smm	}
3273228753Smm	return (r);
3274228753Smm}
3275228753Smm
3276228753Smmstatic int
3277228753Smmset_fflags(struct archive_write_disk *a)
3278228753Smm{
3279228753Smm	struct fixup_entry *le;
3280228753Smm	unsigned long	set, clear;
3281228753Smm	int		r;
3282228753Smm	int		critical_flags;
3283228753Smm	mode_t		mode = archive_entry_mode(a->entry);
3284228753Smm
3285228753Smm	/*
3286228753Smm	 * Make 'critical_flags' hold all file flags that can't be
3287228753Smm	 * immediately restored.  For example, on BSD systems,
3288228753Smm	 * SF_IMMUTABLE prevents hardlinks from being created, so
3289228753Smm	 * should not be set until after any hardlinks are created.  To
3290228753Smm	 * preserve some semblance of portability, this uses #ifdef
3291228753Smm	 * extensively.  Ugly, but it works.
3292228753Smm	 *
3293228753Smm	 * Yes, Virginia, this does create a security race.  It's mitigated
3294228753Smm	 * somewhat by the practice of creating dirs 0700 until the extract
3295228753Smm	 * is done, but it would be nice if we could do more than that.
3296228753Smm	 * People restoring critical file systems should be wary of
3297228753Smm	 * other programs that might try to muck with files as they're
3298228753Smm	 * being restored.
3299228753Smm	 */
3300228753Smm	/* Hopefully, the compiler will optimize this mess into a constant. */
3301228753Smm	critical_flags = 0;
3302228753Smm#ifdef SF_IMMUTABLE
3303228753Smm	critical_flags |= SF_IMMUTABLE;
3304228753Smm#endif
3305228753Smm#ifdef UF_IMMUTABLE
3306228753Smm	critical_flags |= UF_IMMUTABLE;
3307228753Smm#endif
3308228753Smm#ifdef SF_APPEND
3309228753Smm	critical_flags |= SF_APPEND;
3310228753Smm#endif
3311228753Smm#ifdef UF_APPEND
3312228753Smm	critical_flags |= UF_APPEND;
3313228753Smm#endif
3314228753Smm#ifdef EXT2_APPEND_FL
3315228753Smm	critical_flags |= EXT2_APPEND_FL;
3316228753Smm#endif
3317228753Smm#ifdef EXT2_IMMUTABLE_FL
3318228753Smm	critical_flags |= EXT2_IMMUTABLE_FL;
3319228753Smm#endif
3320228753Smm
3321228753Smm	if (a->todo & TODO_FFLAGS) {
3322228753Smm		archive_entry_fflags(a->entry, &set, &clear);
3323228753Smm
3324228753Smm		/*
3325228753Smm		 * The first test encourages the compiler to eliminate
3326228753Smm		 * all of this if it's not necessary.
3327228753Smm		 */
3328228753Smm		if ((critical_flags != 0)  &&  (set & critical_flags)) {
3329228753Smm			le = current_fixup(a, a->name);
3330248616Smm			if (le == NULL)
3331248616Smm				return (ARCHIVE_FATAL);
3332228753Smm			le->fixup |= TODO_FFLAGS;
3333228753Smm			le->fflags_set = set;
3334228753Smm			/* Store the mode if it's not already there. */
3335228753Smm			if ((le->fixup & TODO_MODE) == 0)
3336228753Smm				le->mode = mode;
3337228753Smm		} else {
3338228753Smm			r = set_fflags_platform(a, a->fd,
3339228753Smm			    a->name, mode, set, clear);
3340228753Smm			if (r != ARCHIVE_OK)
3341228753Smm				return (r);
3342228753Smm		}
3343228753Smm	}
3344228753Smm	return (ARCHIVE_OK);
3345228753Smm}
3346228753Smm
3347228753Smm
3348228753Smm#if ( defined(HAVE_LCHFLAGS) || defined(HAVE_CHFLAGS) || defined(HAVE_FCHFLAGS) ) && defined(HAVE_STRUCT_STAT_ST_FLAGS)
3349228753Smm/*
3350228753Smm * BSD reads flags using stat() and sets them with one of {f,l,}chflags()
3351228753Smm */
3352228753Smmstatic int
3353228753Smmset_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
3354228753Smm    mode_t mode, unsigned long set, unsigned long clear)
3355228753Smm{
3356228753Smm	int r;
3357228753Smm
3358228753Smm	(void)mode; /* UNUSED */
3359228753Smm	if (set == 0  && clear == 0)
3360228753Smm		return (ARCHIVE_OK);
3361228753Smm
3362228753Smm	/*
3363228753Smm	 * XXX Is the stat here really necessary?  Or can I just use
3364228753Smm	 * the 'set' flags directly?  In particular, I'm not sure
3365228753Smm	 * about the correct approach if we're overwriting an existing
3366228753Smm	 * file that already has flags on it. XXX
3367228753Smm	 */
3368231200Smm	if ((r = lazy_stat(a)) != ARCHIVE_OK)
3369228753Smm		return (r);
3370228753Smm
3371228753Smm	a->st.st_flags &= ~clear;
3372228753Smm	a->st.st_flags |= set;
3373228753Smm#ifdef HAVE_FCHFLAGS
3374228753Smm	/* If platform has fchflags() and we were given an fd, use it. */
3375228753Smm	if (fd >= 0 && fchflags(fd, a->st.st_flags) == 0)
3376228753Smm		return (ARCHIVE_OK);
3377228753Smm#endif
3378228753Smm	/*
3379228753Smm	 * If we can't use the fd to set the flags, we'll use the
3380228753Smm	 * pathname to set flags.  We prefer lchflags() but will use
3381228753Smm	 * chflags() if we must.
3382228753Smm	 */
3383228753Smm#ifdef HAVE_LCHFLAGS
3384228753Smm	if (lchflags(name, a->st.st_flags) == 0)
3385228753Smm		return (ARCHIVE_OK);
3386228753Smm#elif defined(HAVE_CHFLAGS)
3387228753Smm	if (S_ISLNK(a->st.st_mode)) {
3388228753Smm		archive_set_error(&a->archive, errno,
3389228753Smm		    "Can't set file flags on symlink.");
3390228753Smm		return (ARCHIVE_WARN);
3391228753Smm	}
3392228753Smm	if (chflags(name, a->st.st_flags) == 0)
3393228753Smm		return (ARCHIVE_OK);
3394228753Smm#endif
3395228753Smm	archive_set_error(&a->archive, errno,
3396228753Smm	    "Failed to set file flags");
3397228753Smm	return (ARCHIVE_WARN);
3398228753Smm}
3399228753Smm
3400231200Smm#elif defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)
3401228753Smm/*
3402228753Smm * Linux uses ioctl() to read and write file flags.
3403228753Smm */
3404228753Smmstatic int
3405228753Smmset_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
3406228753Smm    mode_t mode, unsigned long set, unsigned long clear)
3407228753Smm{
3408228753Smm	int		 ret;
3409228753Smm	int		 myfd = fd;
3410248616Smm	int newflags, oldflags;
3411248616Smm	int sf_mask = 0;
3412228753Smm
3413228753Smm	if (set == 0  && clear == 0)
3414228753Smm		return (ARCHIVE_OK);
3415228753Smm	/* Only regular files and dirs can have flags. */
3416228753Smm	if (!S_ISREG(mode) && !S_ISDIR(mode))
3417228753Smm		return (ARCHIVE_OK);
3418228753Smm
3419228753Smm	/* If we weren't given an fd, open it ourselves. */
3420248616Smm	if (myfd < 0) {
3421248616Smm		myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY | O_CLOEXEC);
3422248616Smm		__archive_ensure_cloexec_flag(myfd);
3423248616Smm	}
3424228753Smm	if (myfd < 0)
3425228753Smm		return (ARCHIVE_OK);
3426228753Smm
3427228753Smm	/*
3428228753Smm	 * Linux has no define for the flags that are only settable by
3429228753Smm	 * the root user.  This code may seem a little complex, but
3430228753Smm	 * there seem to be some Linux systems that lack these
3431228753Smm	 * defines. (?)  The code below degrades reasonably gracefully
3432228753Smm	 * if sf_mask is incomplete.
3433228753Smm	 */
3434228753Smm#ifdef EXT2_IMMUTABLE_FL
3435228753Smm	sf_mask |= EXT2_IMMUTABLE_FL;
3436228753Smm#endif
3437228753Smm#ifdef EXT2_APPEND_FL
3438228753Smm	sf_mask |= EXT2_APPEND_FL;
3439228753Smm#endif
3440228753Smm	/*
3441228753Smm	 * XXX As above, this would be way simpler if we didn't have
3442228753Smm	 * to read the current flags from disk. XXX
3443228753Smm	 */
3444228753Smm	ret = ARCHIVE_OK;
3445231200Smm
3446231200Smm	/* Read the current file flags. */
3447231200Smm	if (ioctl(myfd, EXT2_IOC_GETFLAGS, &oldflags) < 0)
3448231200Smm		goto fail;
3449231200Smm
3450228753Smm	/* Try setting the flags as given. */
3451231200Smm	newflags = (oldflags & ~clear) | set;
3452231200Smm	if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0)
3453231200Smm		goto cleanup;
3454231200Smm	if (errno != EPERM)
3455231200Smm		goto fail;
3456231200Smm
3457228753Smm	/* If we couldn't set all the flags, try again with a subset. */
3458231200Smm	newflags &= ~sf_mask;
3459231200Smm	oldflags &= sf_mask;
3460231200Smm	newflags |= oldflags;
3461231200Smm	if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0)
3462231200Smm		goto cleanup;
3463231200Smm
3464228753Smm	/* We couldn't set the flags, so report the failure. */
3465228753Smmfail:
3466228753Smm	archive_set_error(&a->archive, errno,
3467228753Smm	    "Failed to set file flags");
3468228753Smm	ret = ARCHIVE_WARN;
3469228753Smmcleanup:
3470228753Smm	if (fd < 0)
3471228753Smm		close(myfd);
3472228753Smm	return (ret);
3473228753Smm}
3474228753Smm
3475228753Smm#else
3476228753Smm
3477228753Smm/*
3478228753Smm * Of course, some systems have neither BSD chflags() nor Linux' flags
3479228753Smm * support through ioctl().
3480228753Smm */
3481228753Smmstatic int
3482228753Smmset_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
3483228753Smm    mode_t mode, unsigned long set, unsigned long clear)
3484228753Smm{
3485228753Smm	(void)a; /* UNUSED */
3486228753Smm	(void)fd; /* UNUSED */
3487228753Smm	(void)name; /* UNUSED */
3488228753Smm	(void)mode; /* UNUSED */
3489228753Smm	(void)set; /* UNUSED */
3490228753Smm	(void)clear; /* UNUSED */
3491228753Smm	return (ARCHIVE_OK);
3492228753Smm}
3493228753Smm
3494228753Smm#endif /* __linux */
3495228753Smm
3496231200Smm#ifndef HAVE_COPYFILE_H
3497231200Smm/* Default is to simply drop Mac extended metadata. */
3498231200Smmstatic int
3499231200Smmset_mac_metadata(struct archive_write_disk *a, const char *pathname,
3500231200Smm		 const void *metadata, size_t metadata_size)
3501231200Smm{
3502231200Smm	(void)a; /* UNUSED */
3503231200Smm	(void)pathname; /* UNUSED */
3504231200Smm	(void)metadata; /* UNUSED */
3505231200Smm	(void)metadata_size; /* UNUSED */
3506231200Smm	return (ARCHIVE_OK);
3507231200Smm}
3508248616Smm
3509248616Smmstatic int
3510248616Smmfixup_appledouble(struct archive_write_disk *a, const char *pathname)
3511248616Smm{
3512248616Smm	(void)a; /* UNUSED */
3513248616Smm	(void)pathname; /* UNUSED */
3514248616Smm	return (ARCHIVE_OK);
3515248616Smm}
3516231200Smm#else
3517231200Smm
3518231200Smm/*
3519231200Smm * On Mac OS, we use copyfile() to unpack the metadata and
3520231200Smm * apply it to the target file.
3521231200Smm */
3522248616Smm
3523248616Smm#if defined(HAVE_SYS_XATTR_H)
3524231200Smmstatic int
3525248616Smmcopy_xattrs(struct archive_write_disk *a, int tmpfd, int dffd)
3526248616Smm{
3527248616Smm	ssize_t xattr_size;
3528248616Smm	char *xattr_names = NULL, *xattr_val = NULL;
3529248616Smm	int ret = ARCHIVE_OK, xattr_i;
3530248616Smm
3531248616Smm	xattr_size = flistxattr(tmpfd, NULL, 0, 0);
3532248616Smm	if (xattr_size == -1) {
3533248616Smm		archive_set_error(&a->archive, errno,
3534248616Smm		    "Failed to read metadata(xattr)");
3535248616Smm		ret = ARCHIVE_WARN;
3536248616Smm		goto exit_xattr;
3537248616Smm	}
3538248616Smm	xattr_names = malloc(xattr_size);
3539248616Smm	if (xattr_names == NULL) {
3540248616Smm		archive_set_error(&a->archive, ENOMEM,
3541248616Smm		    "Can't allocate memory for metadata(xattr)");
3542248616Smm		ret = ARCHIVE_FATAL;
3543248616Smm		goto exit_xattr;
3544248616Smm	}
3545248616Smm	xattr_size = flistxattr(tmpfd, xattr_names, xattr_size, 0);
3546248616Smm	if (xattr_size == -1) {
3547248616Smm		archive_set_error(&a->archive, errno,
3548248616Smm		    "Failed to read metadata(xattr)");
3549248616Smm		ret = ARCHIVE_WARN;
3550248616Smm		goto exit_xattr;
3551248616Smm	}
3552248616Smm	for (xattr_i = 0; xattr_i < xattr_size;
3553248616Smm	    xattr_i += strlen(xattr_names + xattr_i) + 1) {
3554248616Smm		ssize_t s;
3555248616Smm		int f;
3556248616Smm
3557248616Smm		s = fgetxattr(tmpfd, xattr_names + xattr_i, NULL, 0, 0, 0);
3558248616Smm		if (s == -1) {
3559248616Smm			archive_set_error(&a->archive, errno,
3560248616Smm			    "Failed to get metadata(xattr)");
3561248616Smm			ret = ARCHIVE_WARN;
3562248616Smm			goto exit_xattr;
3563248616Smm		}
3564248616Smm		xattr_val = realloc(xattr_val, s);
3565248616Smm		if (xattr_val == NULL) {
3566248616Smm			archive_set_error(&a->archive, ENOMEM,
3567248616Smm			    "Failed to get metadata(xattr)");
3568248616Smm			ret = ARCHIVE_WARN;
3569248616Smm			goto exit_xattr;
3570248616Smm		}
3571248616Smm		s = fgetxattr(tmpfd, xattr_names + xattr_i, xattr_val, s, 0, 0);
3572248616Smm		if (s == -1) {
3573248616Smm			archive_set_error(&a->archive, errno,
3574248616Smm			    "Failed to get metadata(xattr)");
3575248616Smm			ret = ARCHIVE_WARN;
3576248616Smm			goto exit_xattr;
3577248616Smm		}
3578248616Smm		f = fsetxattr(dffd, xattr_names + xattr_i, xattr_val, s, 0, 0);
3579248616Smm		if (f == -1) {
3580248616Smm			archive_set_error(&a->archive, errno,
3581248616Smm			    "Failed to get metadata(xattr)");
3582248616Smm			ret = ARCHIVE_WARN;
3583248616Smm			goto exit_xattr;
3584248616Smm		}
3585248616Smm	}
3586248616Smmexit_xattr:
3587248616Smm	free(xattr_names);
3588248616Smm	free(xattr_val);
3589248616Smm	return (ret);
3590248616Smm}
3591248616Smm#endif
3592248616Smm
3593248616Smmstatic int
3594248616Smmcopy_acls(struct archive_write_disk *a, int tmpfd, int dffd)
3595248616Smm{
3596248616Smm	acl_t acl, dfacl = NULL;
3597248616Smm	int acl_r, ret = ARCHIVE_OK;
3598248616Smm
3599248616Smm	acl = acl_get_fd(tmpfd);
3600248616Smm	if (acl == NULL) {
3601248616Smm		if (errno == ENOENT)
3602248616Smm			/* There are not any ACLs. */
3603248616Smm			return (ret);
3604248616Smm		archive_set_error(&a->archive, errno,
3605248616Smm		    "Failed to get metadata(acl)");
3606248616Smm		ret = ARCHIVE_WARN;
3607248616Smm		goto exit_acl;
3608248616Smm	}
3609248616Smm	dfacl = acl_dup(acl);
3610248616Smm	acl_r = acl_set_fd(dffd, dfacl);
3611248616Smm	if (acl_r == -1) {
3612248616Smm		archive_set_error(&a->archive, errno,
3613248616Smm		    "Failed to get metadata(acl)");
3614248616Smm		ret = ARCHIVE_WARN;
3615248616Smm		goto exit_acl;
3616248616Smm	}
3617248616Smmexit_acl:
3618248616Smm	if (acl)
3619248616Smm		acl_free(acl);
3620248616Smm	if (dfacl)
3621248616Smm		acl_free(dfacl);
3622248616Smm	return (ret);
3623248616Smm}
3624248616Smm
3625248616Smmstatic int
3626248616Smmcreate_tempdatafork(struct archive_write_disk *a, const char *pathname)
3627248616Smm{
3628248616Smm	struct archive_string tmpdatafork;
3629248616Smm	int tmpfd;
3630248616Smm
3631248616Smm	archive_string_init(&tmpdatafork);
3632248616Smm	archive_strcpy(&tmpdatafork, "tar.md.XXXXXX");
3633248616Smm	tmpfd = mkstemp(tmpdatafork.s);
3634248616Smm	if (tmpfd < 0) {
3635248616Smm		archive_set_error(&a->archive, errno,
3636248616Smm		    "Failed to mkstemp");
3637248616Smm		archive_string_free(&tmpdatafork);
3638248616Smm		return (-1);
3639248616Smm	}
3640248616Smm	if (copyfile(pathname, tmpdatafork.s, 0,
3641248616Smm	    COPYFILE_UNPACK | COPYFILE_NOFOLLOW
3642248616Smm	    | COPYFILE_ACL | COPYFILE_XATTR) < 0) {
3643248616Smm		archive_set_error(&a->archive, errno,
3644248616Smm		    "Failed to restore metadata");
3645248616Smm		close(tmpfd);
3646248616Smm		tmpfd = -1;
3647248616Smm	}
3648248616Smm	unlink(tmpdatafork.s);
3649248616Smm	archive_string_free(&tmpdatafork);
3650248616Smm	return (tmpfd);
3651248616Smm}
3652248616Smm
3653248616Smmstatic int
3654248616Smmcopy_metadata(struct archive_write_disk *a, const char *metadata,
3655248616Smm    const char *datafork, int datafork_compressed)
3656248616Smm{
3657248616Smm	int ret = ARCHIVE_OK;
3658248616Smm
3659248616Smm	if (datafork_compressed) {
3660248616Smm		int dffd, tmpfd;
3661248616Smm
3662248616Smm		tmpfd = create_tempdatafork(a, metadata);
3663248616Smm		if (tmpfd == -1)
3664248616Smm			return (ARCHIVE_WARN);
3665248616Smm
3666248616Smm		/*
3667248616Smm		 * Do not open the data fork compressed by HFS+ compression
3668248616Smm		 * with at least a writing mode(O_RDWR or O_WRONLY). it
3669248616Smm		 * makes the data fork uncompressed.
3670248616Smm		 */
3671248616Smm		dffd = open(datafork, 0);
3672248616Smm		if (dffd == -1) {
3673248616Smm			archive_set_error(&a->archive, errno,
3674248616Smm			    "Failed to open the data fork for metadata");
3675248616Smm			close(tmpfd);
3676248616Smm			return (ARCHIVE_WARN);
3677248616Smm		}
3678248616Smm
3679248616Smm#if defined(HAVE_SYS_XATTR_H)
3680248616Smm		ret = copy_xattrs(a, tmpfd, dffd);
3681248616Smm		if (ret == ARCHIVE_OK)
3682248616Smm#endif
3683248616Smm			ret = copy_acls(a, tmpfd, dffd);
3684248616Smm		close(tmpfd);
3685248616Smm		close(dffd);
3686248616Smm	} else {
3687248616Smm		if (copyfile(metadata, datafork, 0,
3688248616Smm		    COPYFILE_UNPACK | COPYFILE_NOFOLLOW
3689248616Smm		    | COPYFILE_ACL | COPYFILE_XATTR) < 0) {
3690248616Smm			archive_set_error(&a->archive, errno,
3691248616Smm			    "Failed to restore metadata");
3692248616Smm			ret = ARCHIVE_WARN;
3693248616Smm		}
3694248616Smm	}
3695248616Smm	return (ret);
3696248616Smm}
3697248616Smm
3698248616Smmstatic int
3699231200Smmset_mac_metadata(struct archive_write_disk *a, const char *pathname,
3700231200Smm		 const void *metadata, size_t metadata_size)
3701231200Smm{
3702231200Smm	struct archive_string tmp;
3703231200Smm	ssize_t written;
3704231200Smm	int fd;
3705231200Smm	int ret = ARCHIVE_OK;
3706231200Smm
3707231200Smm	/* This would be simpler if copyfile() could just accept the
3708231200Smm	 * metadata as a block of memory; then we could sidestep this
3709231200Smm	 * silly dance of writing the data to disk just so that
3710231200Smm	 * copyfile() can read it back in again. */
3711231200Smm	archive_string_init(&tmp);
3712231200Smm	archive_strcpy(&tmp, pathname);
3713231200Smm	archive_strcat(&tmp, ".XXXXXX");
3714231200Smm	fd = mkstemp(tmp.s);
3715231200Smm
3716231200Smm	if (fd < 0) {
3717231200Smm		archive_set_error(&a->archive, errno,
3718231200Smm				  "Failed to restore metadata");
3719248616Smm		archive_string_free(&tmp);
3720231200Smm		return (ARCHIVE_WARN);
3721231200Smm	}
3722231200Smm	written = write(fd, metadata, metadata_size);
3723231200Smm	close(fd);
3724248616Smm	if ((size_t)written != metadata_size) {
3725231200Smm		archive_set_error(&a->archive, errno,
3726231200Smm				  "Failed to restore metadata");
3727231200Smm		ret = ARCHIVE_WARN;
3728248616Smm	} else {
3729248616Smm		int compressed;
3730248616Smm
3731248616Smm#if defined(UF_COMPRESSED)
3732248616Smm		if ((a->todo & TODO_HFS_COMPRESSION) != 0 &&
3733248616Smm		    (ret = lazy_stat(a)) == ARCHIVE_OK)
3734248616Smm			compressed = a->st.st_flags & UF_COMPRESSED;
3735248616Smm		else
3736248616Smm#endif
3737248616Smm			compressed = 0;
3738248616Smm		ret = copy_metadata(a, tmp.s, pathname, compressed);
3739231200Smm	}
3740231200Smm	unlink(tmp.s);
3741248616Smm	archive_string_free(&tmp);
3742231200Smm	return (ret);
3743231200Smm}
3744248616Smm
3745248616Smmstatic int
3746248616Smmfixup_appledouble(struct archive_write_disk *a, const char *pathname)
3747248616Smm{
3748248616Smm	char buff[8];
3749248616Smm	struct stat st;
3750248616Smm	const char *p;
3751248616Smm	struct archive_string datafork;
3752248616Smm	int fd = -1, ret = ARCHIVE_OK;
3753248616Smm
3754248616Smm	archive_string_init(&datafork);
3755248616Smm	/* Check if the current file name is a type of the resource
3756248616Smm	 * fork file. */
3757248616Smm	p = strrchr(pathname, '/');
3758248616Smm	if (p == NULL)
3759248616Smm		p = pathname;
3760248616Smm	else
3761248616Smm		p++;
3762248616Smm	if (p[0] != '.' || p[1] != '_')
3763248616Smm		goto skip_appledouble;
3764248616Smm
3765248616Smm	/*
3766248616Smm	 * Check if the data fork file exists.
3767248616Smm	 *
3768248616Smm	 * TODO: Check if this write disk object has handled it.
3769248616Smm	 */
3770248616Smm	archive_strncpy(&datafork, pathname, p - pathname);
3771248616Smm	archive_strcat(&datafork, p + 2);
3772248616Smm	if (lstat(datafork.s, &st) == -1 ||
3773248616Smm	    (st.st_mode & AE_IFMT) != AE_IFREG)
3774248616Smm		goto skip_appledouble;
3775248616Smm
3776248616Smm	/*
3777248616Smm	 * Check if the file is in the AppleDouble form.
3778248616Smm	 */
3779248616Smm	fd = open(pathname, O_RDONLY | O_BINARY | O_CLOEXEC);
3780248616Smm	__archive_ensure_cloexec_flag(fd);
3781248616Smm	if (fd == -1) {
3782248616Smm		archive_set_error(&a->archive, errno,
3783248616Smm		    "Failed to open a restoring file");
3784248616Smm		ret = ARCHIVE_WARN;
3785248616Smm		goto skip_appledouble;
3786248616Smm	}
3787248616Smm	if (read(fd, buff, 8) == -1) {
3788248616Smm		archive_set_error(&a->archive, errno,
3789248616Smm		    "Failed to read a restoring file");
3790248616Smm		close(fd);
3791248616Smm		ret = ARCHIVE_WARN;
3792248616Smm		goto skip_appledouble;
3793248616Smm	}
3794248616Smm	close(fd);
3795248616Smm	/* Check AppleDouble Magic Code. */
3796248616Smm	if (archive_be32dec(buff) != 0x00051607)
3797248616Smm		goto skip_appledouble;
3798248616Smm	/* Check AppleDouble Version. */
3799248616Smm	if (archive_be32dec(buff+4) != 0x00020000)
3800248616Smm		goto skip_appledouble;
3801248616Smm
3802248616Smm	ret = copy_metadata(a, pathname, datafork.s,
3803248616Smm#if defined(UF_COMPRESSED)
3804248616Smm	    st.st_flags & UF_COMPRESSED);
3805248616Smm#else
3806248616Smm	    0);
3807231200Smm#endif
3808248616Smm	if (ret == ARCHIVE_OK) {
3809248616Smm		unlink(pathname);
3810248616Smm		ret = ARCHIVE_EOF;
3811248616Smm	}
3812248616Smmskip_appledouble:
3813248616Smm	archive_string_free(&datafork);
3814248616Smm	return (ret);
3815248616Smm}
3816248616Smm#endif
3817231200Smm
3818231200Smm#if HAVE_LSETXATTR || HAVE_LSETEA
3819228753Smm/*
3820231200Smm * Restore extended attributes -  Linux and AIX implementations:
3821231200Smm * AIX' ea interface is syntaxwise identical to the Linux xattr interface.
3822228753Smm */
3823228753Smmstatic int
3824228753Smmset_xattrs(struct archive_write_disk *a)
3825228753Smm{
3826228753Smm	struct archive_entry *entry = a->entry;
3827228753Smm	static int warning_done = 0;
3828228753Smm	int ret = ARCHIVE_OK;
3829228753Smm	int i = archive_entry_xattr_reset(entry);
3830228753Smm
3831228753Smm	while (i--) {
3832228753Smm		const char *name;
3833228753Smm		const void *value;
3834228753Smm		size_t size;
3835228753Smm		archive_entry_xattr_next(entry, &name, &value, &size);
3836228753Smm		if (name != NULL &&
3837228753Smm				strncmp(name, "xfsroot.", 8) != 0 &&
3838228753Smm				strncmp(name, "system.", 7) != 0) {
3839228753Smm			int e;
3840228753Smm#if HAVE_FSETXATTR
3841228753Smm			if (a->fd >= 0)
3842228753Smm				e = fsetxattr(a->fd, name, value, size, 0);
3843228753Smm			else
3844231200Smm#elif HAVE_FSETEA
3845231200Smm			if (a->fd >= 0)
3846231200Smm				e = fsetea(a->fd, name, value, size, 0);
3847231200Smm			else
3848228753Smm#endif
3849228753Smm			{
3850231200Smm#if HAVE_LSETXATTR
3851228753Smm				e = lsetxattr(archive_entry_pathname(entry),
3852228753Smm				    name, value, size, 0);
3853231200Smm#elif HAVE_LSETEA
3854231200Smm				e = lsetea(archive_entry_pathname(entry),
3855231200Smm				    name, value, size, 0);
3856231200Smm#endif
3857228753Smm			}
3858228753Smm			if (e == -1) {
3859231200Smm				if (errno == ENOTSUP || errno == ENOSYS) {
3860228753Smm					if (!warning_done) {
3861228753Smm						warning_done = 1;
3862228753Smm						archive_set_error(&a->archive, errno,
3863228753Smm						    "Cannot restore extended "
3864228753Smm						    "attributes on this file "
3865228753Smm						    "system");
3866228753Smm					}
3867228753Smm				} else
3868228753Smm					archive_set_error(&a->archive, errno,
3869228753Smm					    "Failed to set extended attribute");
3870228753Smm				ret = ARCHIVE_WARN;
3871228753Smm			}
3872228753Smm		} else {
3873228753Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
3874228753Smm			    "Invalid extended attribute encountered");
3875228753Smm			ret = ARCHIVE_WARN;
3876228753Smm		}
3877228753Smm	}
3878228753Smm	return (ret);
3879228753Smm}
3880228753Smm#elif HAVE_EXTATTR_SET_FILE && HAVE_DECL_EXTATTR_NAMESPACE_USER
3881228753Smm/*
3882228753Smm * Restore extended attributes -  FreeBSD implementation
3883228753Smm */
3884228753Smmstatic int
3885228753Smmset_xattrs(struct archive_write_disk *a)
3886228753Smm{
3887228753Smm	struct archive_entry *entry = a->entry;
3888228753Smm	static int warning_done = 0;
3889228753Smm	int ret = ARCHIVE_OK;
3890228753Smm	int i = archive_entry_xattr_reset(entry);
3891228753Smm
3892228753Smm	while (i--) {
3893228753Smm		const char *name;
3894228753Smm		const void *value;
3895228753Smm		size_t size;
3896228753Smm		archive_entry_xattr_next(entry, &name, &value, &size);
3897228753Smm		if (name != NULL) {
3898248995Smdf			ssize_t e;
3899228753Smm			int namespace;
3900228753Smm
3901228753Smm			if (strncmp(name, "user.", 5) == 0) {
3902228753Smm				/* "user." attributes go to user namespace */
3903228753Smm				name += 5;
3904228753Smm				namespace = EXTATTR_NAMESPACE_USER;
3905228753Smm			} else {
3906228753Smm				/* Warn about other extended attributes. */
3907228753Smm				archive_set_error(&a->archive,
3908228753Smm				    ARCHIVE_ERRNO_FILE_FORMAT,
3909228753Smm				    "Can't restore extended attribute ``%s''",
3910228753Smm				    name);
3911228753Smm				ret = ARCHIVE_WARN;
3912228753Smm				continue;
3913228753Smm			}
3914228753Smm			errno = 0;
3915228753Smm#if HAVE_EXTATTR_SET_FD
3916228753Smm			if (a->fd >= 0)
3917228753Smm				e = extattr_set_fd(a->fd, namespace, name, value, size);
3918228753Smm			else
3919228753Smm#endif
3920228753Smm			/* TODO: should we use extattr_set_link() instead? */
3921228753Smm			{
3922228753Smm				e = extattr_set_file(archive_entry_pathname(entry),
3923228753Smm				    namespace, name, value, size);
3924228753Smm			}
3925248995Smdf			if (e != (ssize_t)size) {
3926231200Smm				if (errno == ENOTSUP || errno == ENOSYS) {
3927228753Smm					if (!warning_done) {
3928228753Smm						warning_done = 1;
3929228753Smm						archive_set_error(&a->archive, errno,
3930228753Smm						    "Cannot restore extended "
3931228753Smm						    "attributes on this file "
3932228753Smm						    "system");
3933228753Smm					}
3934228753Smm				} else {
3935228753Smm					archive_set_error(&a->archive, errno,
3936228753Smm					    "Failed to set extended attribute");
3937228753Smm				}
3938228753Smm
3939228753Smm				ret = ARCHIVE_WARN;
3940228753Smm			}
3941228753Smm		}
3942228753Smm	}
3943228753Smm	return (ret);
3944228753Smm}
3945228753Smm#else
3946228753Smm/*
3947228753Smm * Restore extended attributes - stub implementation for unsupported systems
3948228753Smm */
3949228753Smmstatic int
3950228753Smmset_xattrs(struct archive_write_disk *a)
3951228753Smm{
3952228753Smm	static int warning_done = 0;
3953228753Smm
3954228753Smm	/* If there aren't any extended attributes, then it's okay not
3955228753Smm	 * to extract them, otherwise, issue a single warning. */
3956228753Smm	if (archive_entry_xattr_count(a->entry) != 0 && !warning_done) {
3957228753Smm		warning_done = 1;
3958228753Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
3959228753Smm		    "Cannot restore extended attributes on this system");
3960228753Smm		return (ARCHIVE_WARN);
3961228753Smm	}
3962228753Smm	/* Warning was already emitted; suppress further warnings. */
3963228753Smm	return (ARCHIVE_OK);
3964228753Smm}
3965228753Smm#endif
3966228753Smm
3967228753Smm/*
3968228753Smm * Test if file on disk is older than entry.
3969228753Smm */
3970228753Smmstatic int
3971228753Smmolder(struct stat *st, struct archive_entry *entry)
3972228753Smm{
3973228753Smm	/* First, test the seconds and return if we have a definite answer. */
3974228753Smm	/* Definitely older. */
3975228753Smm	if (st->st_mtime < archive_entry_mtime(entry))
3976228753Smm		return (1);
3977228753Smm	/* Definitely younger. */
3978228753Smm	if (st->st_mtime > archive_entry_mtime(entry))
3979228753Smm		return (0);
3980228753Smm	/* If this platform supports fractional seconds, try those. */
3981228753Smm#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
3982228753Smm	/* Definitely older. */
3983228753Smm	if (st->st_mtimespec.tv_nsec < archive_entry_mtime_nsec(entry))
3984228753Smm		return (1);
3985228753Smm#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
3986228753Smm	/* Definitely older. */
3987228753Smm	if (st->st_mtim.tv_nsec < archive_entry_mtime_nsec(entry))
3988228753Smm		return (1);
3989228753Smm#elif HAVE_STRUCT_STAT_ST_MTIME_N
3990228753Smm	/* older. */
3991228753Smm	if (st->st_mtime_n < archive_entry_mtime_nsec(entry))
3992228753Smm		return (1);
3993228753Smm#elif HAVE_STRUCT_STAT_ST_UMTIME
3994228753Smm	/* older. */
3995228753Smm	if (st->st_umtime * 1000 < archive_entry_mtime_nsec(entry))
3996228753Smm		return (1);
3997228753Smm#elif HAVE_STRUCT_STAT_ST_MTIME_USEC
3998228753Smm	/* older. */
3999228753Smm	if (st->st_mtime_usec * 1000 < archive_entry_mtime_nsec(entry))
4000228753Smm		return (1);
4001228753Smm#else
4002228753Smm	/* This system doesn't have high-res timestamps. */
4003228753Smm#endif
4004228753Smm	/* Same age or newer, so not older. */
4005228753Smm	return (0);
4006228753Smm}
4007231200Smm
4008231200Smm#endif /* !_WIN32 || __CYGWIN__ */
4009231200Smm
4010