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
143248616Smm#define O_CLOEXEC	0
144248616Smm#endif
145228753Smm
146228753Smmstruct fixup_entry {
147228753Smm	struct fixup_entry	*next;
148231200Smm	struct archive_acl	 acl;
149228753Smm	mode_t			 mode;
150228753Smm	int64_t			 atime;
151228753Smm	int64_t                  birthtime;
152228753Smm	int64_t			 mtime;
153231200Smm	int64_t			 ctime;
154228753Smm	unsigned long		 atime_nanos;
155228753Smm	unsigned long            birthtime_nanos;
156228753Smm	unsigned long		 mtime_nanos;
157231200Smm	unsigned long		 ctime_nanos;
158228753Smm	unsigned long		 fflags_set;
159231200Smm	size_t			 mac_metadata_size;
160231200Smm	void			*mac_metadata;
161228753Smm	int			 fixup; /* bitmask of what needs fixing */
162228753Smm	char			*name;
163228753Smm};
164228753Smm
165228753Smm/*
166228753Smm * We use a bitmask to track which operations remain to be done for
167228753Smm * this file.  In particular, this helps us avoid unnecessary
168228753Smm * operations when it's possible to take care of one step as a
169228753Smm * side-effect of another.  For example, mkdir() can specify the mode
170228753Smm * for the newly-created object but symlink() cannot.  This means we
171228753Smm * can skip chmod() if mkdir() succeeded, but we must explicitly
172228753Smm * chmod() if we're trying to create a directory that already exists
173228753Smm * (mkdir() failed) or if we're restoring a symlink.  Similarly, we
174228753Smm * need to verify UID/GID before trying to restore SUID/SGID bits;
175228753Smm * that verification can occur explicitly through a stat() call or
176228753Smm * implicitly because of a successful chown() call.
177228753Smm */
178228753Smm#define	TODO_MODE_FORCE		0x40000000
179228753Smm#define	TODO_MODE_BASE		0x20000000
180228753Smm#define	TODO_SUID		0x10000000
181228753Smm#define	TODO_SUID_CHECK		0x08000000
182228753Smm#define	TODO_SGID		0x04000000
183228753Smm#define	TODO_SGID_CHECK		0x02000000
184248616Smm#define	TODO_APPLEDOUBLE	0x01000000
185228753Smm#define	TODO_MODE		(TODO_MODE_BASE|TODO_SUID|TODO_SGID)
186228753Smm#define	TODO_TIMES		ARCHIVE_EXTRACT_TIME
187228753Smm#define	TODO_OWNER		ARCHIVE_EXTRACT_OWNER
188228753Smm#define	TODO_FFLAGS		ARCHIVE_EXTRACT_FFLAGS
189228753Smm#define	TODO_ACLS		ARCHIVE_EXTRACT_ACL
190228753Smm#define	TODO_XATTR		ARCHIVE_EXTRACT_XATTR
191231200Smm#define	TODO_MAC_METADATA	ARCHIVE_EXTRACT_MAC_METADATA
192248616Smm#define	TODO_HFS_COMPRESSION	ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED
193228753Smm
194228753Smmstruct archive_write_disk {
195228753Smm	struct archive	archive;
196228753Smm
197228753Smm	mode_t			 user_umask;
198228753Smm	struct fixup_entry	*fixup_list;
199228753Smm	struct fixup_entry	*current_fixup;
200231200Smm	int64_t			 user_uid;
201231200Smm	int			 skip_file_set;
202238856Smm	int64_t			 skip_file_dev;
203238856Smm	int64_t			 skip_file_ino;
204228753Smm	time_t			 start_time;
205228753Smm
206231200Smm	int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid);
207228753Smm	void  (*cleanup_gid)(void *private);
208228753Smm	void			*lookup_gid_data;
209231200Smm	int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid);
210228753Smm	void  (*cleanup_uid)(void *private);
211228753Smm	void			*lookup_uid_data;
212228753Smm
213228753Smm	/*
214228753Smm	 * Full path of last file to satisfy symlink checks.
215228753Smm	 */
216228753Smm	struct archive_string	path_safe;
217228753Smm
218228753Smm	/*
219228753Smm	 * Cached stat data from disk for the current entry.
220228753Smm	 * If this is valid, pst points to st.  Otherwise,
221228753Smm	 * pst is null.
222228753Smm	 */
223228753Smm	struct stat		 st;
224228753Smm	struct stat		*pst;
225228753Smm
226228753Smm	/* Information about the object being restored right now. */
227228753Smm	struct archive_entry	*entry; /* Entry being extracted. */
228228753Smm	char			*name; /* Name of entry, possibly edited. */
229228753Smm	struct archive_string	 _name_data; /* backing store for 'name' */
230228753Smm	/* Tasks remaining for this object. */
231228753Smm	int			 todo;
232228753Smm	/* Tasks deferred until end-of-archive. */
233228753Smm	int			 deferred;
234228753Smm	/* Options requested by the client. */
235228753Smm	int			 flags;
236228753Smm	/* Handle for the file we're restoring. */
237228753Smm	int			 fd;
238228753Smm	/* Current offset for writing data to the file. */
239231200Smm	int64_t			 offset;
240228753Smm	/* Last offset actually written to disk. */
241231200Smm	int64_t			 fd_offset;
242231200Smm	/* Total bytes actually written to files. */
243231200Smm	int64_t			 total_bytes_written;
244228753Smm	/* Maximum size of file, -1 if unknown. */
245231200Smm	int64_t			 filesize;
246228753Smm	/* Dir we were in before this restore; only for deep paths. */
247228753Smm	int			 restore_pwd;
248228753Smm	/* Mode we should use for this entry; affected by _PERM and umask. */
249228753Smm	mode_t			 mode;
250228753Smm	/* UID/GID to use in restoring this entry. */
251231200Smm	int64_t			 uid;
252231200Smm	int64_t			 gid;
253248616Smm	/*
254248616Smm	 * HFS+ Compression.
255248616Smm	 */
256248616Smm	/* Xattr "com.apple.decmpfs". */
257248616Smm	uint32_t		 decmpfs_attr_size;
258248616Smm	unsigned char		*decmpfs_header_p;
259248616Smm	/* ResourceFork set options used for fsetxattr. */
260248616Smm	int			 rsrc_xattr_options;
261248616Smm	/* Xattr "com.apple.ResourceFork". */
262248616Smm	unsigned char		*resource_fork;
263248616Smm	size_t			 resource_fork_allocated_size;
264248616Smm	unsigned int		 decmpfs_block_count;
265248616Smm	uint32_t		*decmpfs_block_info;
266248616Smm	/* Buffer for compressed data. */
267248616Smm	unsigned char		*compressed_buffer;
268248616Smm	size_t			 compressed_buffer_size;
269248616Smm	size_t			 compressed_buffer_remaining;
270248616Smm	/* The offset of the ResourceFork where compressed data will
271248616Smm	 * be placed. */
272248616Smm	uint32_t		 compressed_rsrc_position;
273248616Smm	uint32_t		 compressed_rsrc_position_v;
274248616Smm	/* Buffer for uncompressed data. */
275248616Smm	char			*uncompressed_buffer;
276248616Smm	size_t			 block_remaining_bytes;
277248616Smm	size_t			 file_remaining_bytes;
278248616Smm#ifdef HAVE_ZLIB_H
279248616Smm	z_stream		 stream;
280248616Smm	int			 stream_valid;
281248616Smm	int			 decmpfs_compression_level;
282248616Smm#endif
283228753Smm};
284228753Smm
285228753Smm/*
286228753Smm * Default mode for dirs created automatically (will be modified by umask).
287231200Smm * Note that POSIX specifies 0777 for implicitly-created dirs, "modified
288228753Smm * by the process' file creation mask."
289228753Smm */
290228753Smm#define	DEFAULT_DIR_MODE 0777
291228753Smm/*
292228753Smm * Dir modes are restored in two steps:  During the extraction, the permissions
293228753Smm * in the archive are modified to match the following limits.  During
294228753Smm * the post-extract fixup pass, the permissions from the archive are
295228753Smm * applied.
296228753Smm */
297228753Smm#define	MINIMUM_DIR_MODE 0700
298228753Smm#define	MAXIMUM_DIR_MODE 0775
299228753Smm
300248616Smm/*
301248616Smm * Maxinum uncompressed size of a decmpfs block.
302248616Smm */
303248616Smm#define MAX_DECMPFS_BLOCK_SIZE	(64 * 1024)
304248616Smm/*
305248616Smm * HFS+ compression type.
306248616Smm */
307248616Smm#define CMP_XATTR		3/* Compressed data in xattr. */
308248616Smm#define CMP_RESOURCE_FORK	4/* Compressed data in resource fork. */
309248616Smm/*
310248616Smm * HFS+ compression resource fork.
311248616Smm */
312248616Smm#define RSRC_H_SIZE	260	/* Base size of Resource fork header. */
313248616Smm#define RSRC_F_SIZE	50	/* Size of Resource fork footer. */
314248616Smm/* Size to write compressed data to resource fork. */
315248616Smm#define COMPRESSED_W_SIZE	(64 * 1024)
316248616Smm/* decmpfs difinitions. */
317248616Smm#define MAX_DECMPFS_XATTR_SIZE		3802
318248616Smm#ifndef DECMPFS_XATTR_NAME
319248616Smm#define DECMPFS_XATTR_NAME		"com.apple.decmpfs"
320248616Smm#endif
321248616Smm#define DECMPFS_MAGIC			0x636d7066
322248616Smm#define DECMPFS_COMPRESSION_MAGIC	0
323248616Smm#define DECMPFS_COMPRESSION_TYPE	4
324248616Smm#define DECMPFS_UNCOMPRESSED_SIZE	8
325248616Smm#define DECMPFS_HEADER_SIZE		16
326248616Smm
327248616Smm#define HFS_BLOCKS(s)	((s) >> 12)
328248616Smm
329228753Smmstatic int	check_symlinks(struct archive_write_disk *);
330228753Smmstatic int	create_filesystem_object(struct archive_write_disk *);
331228753Smmstatic struct fixup_entry *current_fixup(struct archive_write_disk *, const char *pathname);
332231200Smm#if defined(HAVE_FCHDIR) && defined(PATH_MAX)
333228753Smmstatic void	edit_deep_directories(struct archive_write_disk *ad);
334228753Smm#endif
335228753Smmstatic int	cleanup_pathname(struct archive_write_disk *);
336228753Smmstatic int	create_dir(struct archive_write_disk *, char *);
337228753Smmstatic int	create_parent_dir(struct archive_write_disk *, char *);
338248616Smmstatic ssize_t	hfs_write_data_block(struct archive_write_disk *,
339248616Smm		    const char *, size_t);
340248616Smmstatic int	fixup_appledouble(struct archive_write_disk *, const char *);
341228753Smmstatic int	older(struct stat *, struct archive_entry *);
342228753Smmstatic int	restore_entry(struct archive_write_disk *);
343231200Smmstatic int	set_mac_metadata(struct archive_write_disk *, const char *,
344231200Smm				 const void *, size_t);
345228753Smmstatic int	set_xattrs(struct archive_write_disk *);
346228753Smmstatic int	set_fflags(struct archive_write_disk *);
347228753Smmstatic int	set_fflags_platform(struct archive_write_disk *, int fd,
348228753Smm		    const char *name, mode_t mode,
349228753Smm		    unsigned long fflags_set, unsigned long fflags_clear);
350228753Smmstatic int	set_ownership(struct archive_write_disk *);
351228753Smmstatic int	set_mode(struct archive_write_disk *, int mode);
352228753Smmstatic int	set_time(int, int, const char *, time_t, long, time_t, long);
353231200Smmstatic int	set_times(struct archive_write_disk *, int, int, const char *,
354231200Smm		    time_t, long, time_t, long, time_t, long, time_t, long);
355231200Smmstatic int	set_times_from_entry(struct archive_write_disk *);
356228753Smmstatic struct fixup_entry *sort_dir_list(struct fixup_entry *p);
357228753Smmstatic ssize_t	write_data_block(struct archive_write_disk *,
358228753Smm		    const char *, size_t);
359228753Smm
360228753Smmstatic struct archive_vtable *archive_write_disk_vtable(void);
361228753Smm
362231200Smmstatic int	_archive_write_disk_close(struct archive *);
363231200Smmstatic int	_archive_write_disk_free(struct archive *);
364231200Smmstatic int	_archive_write_disk_header(struct archive *, struct archive_entry *);
365231200Smmstatic int64_t	_archive_write_disk_filter_bytes(struct archive *, int);
366231200Smmstatic int	_archive_write_disk_finish_entry(struct archive *);
367231200Smmstatic ssize_t	_archive_write_disk_data(struct archive *, const void *, size_t);
368231200Smmstatic ssize_t	_archive_write_disk_data_block(struct archive *, const void *, size_t, int64_t);
369228753Smm
370228753Smmstatic int
371231200Smmlazy_stat(struct archive_write_disk *a)
372228753Smm{
373228753Smm	if (a->pst != NULL) {
374228753Smm		/* Already have stat() data available. */
375228753Smm		return (ARCHIVE_OK);
376228753Smm	}
377228753Smm#ifdef HAVE_FSTAT
378228753Smm	if (a->fd >= 0 && fstat(a->fd, &a->st) == 0) {
379228753Smm		a->pst = &a->st;
380228753Smm		return (ARCHIVE_OK);
381228753Smm	}
382228753Smm#endif
383228753Smm	/*
384228753Smm	 * XXX At this point, symlinks should not be hit, otherwise
385231200Smm	 * XXX a race occurred.  Do we want to check explicitly for that?
386228753Smm	 */
387228753Smm	if (lstat(a->name, &a->st) == 0) {
388228753Smm		a->pst = &a->st;
389228753Smm		return (ARCHIVE_OK);
390228753Smm	}
391228753Smm	archive_set_error(&a->archive, errno, "Couldn't stat file");
392228753Smm	return (ARCHIVE_WARN);
393228753Smm}
394228753Smm
395228753Smmstatic struct archive_vtable *
396228753Smmarchive_write_disk_vtable(void)
397228753Smm{
398228753Smm	static struct archive_vtable av;
399228753Smm	static int inited = 0;
400228753Smm
401228753Smm	if (!inited) {
402231200Smm		av.archive_close = _archive_write_disk_close;
403231200Smm		av.archive_filter_bytes = _archive_write_disk_filter_bytes;
404231200Smm		av.archive_free = _archive_write_disk_free;
405231200Smm		av.archive_write_header = _archive_write_disk_header;
406231200Smm		av.archive_write_finish_entry
407231200Smm		    = _archive_write_disk_finish_entry;
408231200Smm		av.archive_write_data = _archive_write_disk_data;
409231200Smm		av.archive_write_data_block = _archive_write_disk_data_block;
410231200Smm		inited = 1;
411228753Smm	}
412228753Smm	return (&av);
413228753Smm}
414228753Smm
415231200Smmstatic int64_t
416231200Smm_archive_write_disk_filter_bytes(struct archive *_a, int n)
417231200Smm{
418231200Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
419231200Smm	(void)n; /* UNUSED */
420231200Smm	if (n == -1 || n == 0)
421231200Smm		return (a->total_bytes_written);
422231200Smm	return (-1);
423231200Smm}
424228753Smm
425231200Smm
426228753Smmint
427228753Smmarchive_write_disk_set_options(struct archive *_a, int flags)
428228753Smm{
429228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
430228753Smm
431228753Smm	a->flags = flags;
432228753Smm	return (ARCHIVE_OK);
433228753Smm}
434228753Smm
435228753Smm
436228753Smm/*
437228753Smm * Extract this entry to disk.
438228753Smm *
439228753Smm * TODO: Validate hardlinks.  According to the standards, we're
440228753Smm * supposed to check each extracted hardlink and squawk if it refers
441228753Smm * to a file that we didn't restore.  I'm not entirely convinced this
442228753Smm * is a good idea, but more importantly: Is there any way to validate
443228753Smm * hardlinks without keeping a complete list of filenames from the
444228753Smm * entire archive?? Ugh.
445228753Smm *
446228753Smm */
447228753Smmstatic int
448231200Smm_archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
449228753Smm{
450228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
451228753Smm	struct fixup_entry *fe;
452228753Smm	int ret, r;
453228753Smm
454231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
455228753Smm	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
456228753Smm	    "archive_write_disk_header");
457228753Smm	archive_clear_error(&a->archive);
458228753Smm	if (a->archive.state & ARCHIVE_STATE_DATA) {
459231200Smm		r = _archive_write_disk_finish_entry(&a->archive);
460228753Smm		if (r == ARCHIVE_FATAL)
461228753Smm			return (r);
462228753Smm	}
463228753Smm
464228753Smm	/* Set up for this particular entry. */
465228753Smm	a->pst = NULL;
466228753Smm	a->current_fixup = NULL;
467228753Smm	a->deferred = 0;
468228753Smm	if (a->entry) {
469228753Smm		archive_entry_free(a->entry);
470228753Smm		a->entry = NULL;
471228753Smm	}
472228753Smm	a->entry = archive_entry_clone(entry);
473228753Smm	a->fd = -1;
474228753Smm	a->fd_offset = 0;
475228753Smm	a->offset = 0;
476231200Smm	a->restore_pwd = -1;
477228753Smm	a->uid = a->user_uid;
478228753Smm	a->mode = archive_entry_mode(a->entry);
479228753Smm	if (archive_entry_size_is_set(a->entry))
480228753Smm		a->filesize = archive_entry_size(a->entry);
481228753Smm	else
482228753Smm		a->filesize = -1;
483228753Smm	archive_strcpy(&(a->_name_data), archive_entry_pathname(a->entry));
484228753Smm	a->name = a->_name_data.s;
485228753Smm	archive_clear_error(&a->archive);
486228753Smm
487228753Smm	/*
488228753Smm	 * Clean up the requested path.  This is necessary for correct
489228753Smm	 * dir restores; the dir restore logic otherwise gets messed
490228753Smm	 * up by nonsense like "dir/.".
491228753Smm	 */
492228753Smm	ret = cleanup_pathname(a);
493228753Smm	if (ret != ARCHIVE_OK)
494228753Smm		return (ret);
495228753Smm
496228753Smm	/*
497231200Smm	 * Query the umask so we get predictable mode settings.
498228753Smm	 * This gets done on every call to _write_header in case the
499228753Smm	 * user edits their umask during the extraction for some
500231200Smm	 * reason.
501228753Smm	 */
502231200Smm	umask(a->user_umask = umask(0));
503228753Smm
504228753Smm	/* Figure out what we need to do for this entry. */
505228753Smm	a->todo = TODO_MODE_BASE;
506228753Smm	if (a->flags & ARCHIVE_EXTRACT_PERM) {
507228753Smm		a->todo |= TODO_MODE_FORCE; /* Be pushy about permissions. */
508228753Smm		/*
509228753Smm		 * SGID requires an extra "check" step because we
510228753Smm		 * cannot easily predict the GID that the system will
511228753Smm		 * assign.  (Different systems assign GIDs to files
512228753Smm		 * based on a variety of criteria, including process
513228753Smm		 * credentials and the gid of the enclosing
514228753Smm		 * directory.)  We can only restore the SGID bit if
515228753Smm		 * the file has the right GID, and we only know the
516228753Smm		 * GID if we either set it (see set_ownership) or if
517228753Smm		 * we've actually called stat() on the file after it
518228753Smm		 * was restored.  Since there are several places at
519228753Smm		 * which we might verify the GID, we need a TODO bit
520228753Smm		 * to keep track.
521228753Smm		 */
522228753Smm		if (a->mode & S_ISGID)
523228753Smm			a->todo |= TODO_SGID | TODO_SGID_CHECK;
524228753Smm		/*
525228753Smm		 * Verifying the SUID is simpler, but can still be
526228753Smm		 * done in multiple ways, hence the separate "check" bit.
527228753Smm		 */
528228753Smm		if (a->mode & S_ISUID)
529228753Smm			a->todo |= TODO_SUID | TODO_SUID_CHECK;
530228753Smm	} else {
531228753Smm		/*
532228753Smm		 * User didn't request full permissions, so don't
533228753Smm		 * restore SUID, SGID bits and obey umask.
534228753Smm		 */
535228753Smm		a->mode &= ~S_ISUID;
536228753Smm		a->mode &= ~S_ISGID;
537228753Smm		a->mode &= ~S_ISVTX;
538228753Smm		a->mode &= ~a->user_umask;
539228753Smm	}
540228753Smm	if (a->flags & ARCHIVE_EXTRACT_OWNER)
541228753Smm		a->todo |= TODO_OWNER;
542228753Smm	if (a->flags & ARCHIVE_EXTRACT_TIME)
543228753Smm		a->todo |= TODO_TIMES;
544231200Smm	if (a->flags & ARCHIVE_EXTRACT_ACL) {
545231200Smm		if (archive_entry_filetype(a->entry) == AE_IFDIR)
546231200Smm			a->deferred |= TODO_ACLS;
547231200Smm		else
548231200Smm			a->todo |= TODO_ACLS;
549231200Smm	}
550231200Smm	if (a->flags & ARCHIVE_EXTRACT_MAC_METADATA) {
551231200Smm		if (archive_entry_filetype(a->entry) == AE_IFDIR)
552231200Smm			a->deferred |= TODO_MAC_METADATA;
553231200Smm		else
554231200Smm			a->todo |= TODO_MAC_METADATA;
555231200Smm	}
556248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H)
557248616Smm	if ((a->flags & ARCHIVE_EXTRACT_NO_HFS_COMPRESSION) == 0) {
558248616Smm		unsigned long set, clear;
559248616Smm		archive_entry_fflags(a->entry, &set, &clear);
560248616Smm		if ((set & ~clear) & UF_COMPRESSED) {
561248616Smm			a->todo |= TODO_HFS_COMPRESSION;
562248616Smm			a->decmpfs_block_count = (unsigned)-1;
563248616Smm		}
564248616Smm	}
565248616Smm	if ((a->flags & ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED) != 0 &&
566248616Smm	    (a->mode & AE_IFMT) == AE_IFREG && a->filesize > 0) {
567248616Smm		a->todo |= TODO_HFS_COMPRESSION;
568248616Smm		a->decmpfs_block_count = (unsigned)-1;
569248616Smm	}
570248616Smm	{
571248616Smm		const char *p;
572248616Smm
573248616Smm		/* Check if the current file name is a type of the
574248616Smm		 * resource fork file. */
575248616Smm		p = strrchr(a->name, '/');
576248616Smm		if (p == NULL)
577248616Smm			p = a->name;
578248616Smm		else
579248616Smm			p++;
580248616Smm		if (p[0] == '.' && p[1] == '_') {
581248616Smm			/* Do not compress "._XXX" files. */
582248616Smm			a->todo &= ~TODO_HFS_COMPRESSION;
583248616Smm			if (a->filesize > 0)
584248616Smm				a->todo |= TODO_APPLEDOUBLE;
585248616Smm		}
586248616Smm	}
587248616Smm#endif
588248616Smm
589228753Smm	if (a->flags & ARCHIVE_EXTRACT_XATTR)
590228753Smm		a->todo |= TODO_XATTR;
591228753Smm	if (a->flags & ARCHIVE_EXTRACT_FFLAGS)
592228753Smm		a->todo |= TODO_FFLAGS;
593228753Smm	if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) {
594228753Smm		ret = check_symlinks(a);
595228753Smm		if (ret != ARCHIVE_OK)
596231200Smm			return (ret);
597228753Smm	}
598231200Smm#if defined(HAVE_FCHDIR) && defined(PATH_MAX)
599228753Smm	/* If path exceeds PATH_MAX, shorten the path. */
600228753Smm	edit_deep_directories(a);
601228753Smm#endif
602228753Smm
603228753Smm	ret = restore_entry(a);
604228753Smm
605248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H)
606228753Smm	/*
607248616Smm	 * Check if the filesystem the file is restoring on supports
608248616Smm	 * HFS+ Compression. If not, cancel HFS+ Compression.
609248616Smm	 */
610248616Smm	if (a->todo | TODO_HFS_COMPRESSION) {
611248616Smm		/*
612248616Smm		 * NOTE: UF_COMPRESSED is ignored even if the filesystem
613248616Smm		 * supports HFS+ Compression because the file should
614248616Smm		 * have at least an extended attriute "com.apple.decmpfs"
615248616Smm		 * before the flag is set to indicate that the file have
616248616Smm		 * been compressed. If hte filesystem does not support
617248616Smm		 * HFS+ Compression the system call will fail.
618248616Smm		 */
619248616Smm		if (a->fd < 0 || fchflags(a->fd, UF_COMPRESSED) != 0)
620248616Smm			a->todo &= ~TODO_HFS_COMPRESSION;
621248616Smm	}
622248616Smm#endif
623248616Smm
624248616Smm	/*
625228753Smm	 * TODO: There are rumours that some extended attributes must
626228753Smm	 * be restored before file data is written.  If this is true,
627228753Smm	 * then we either need to write all extended attributes both
628228753Smm	 * before and after restoring the data, or find some rule for
629228753Smm	 * determining which must go first and which last.  Due to the
630228753Smm	 * many ways people are using xattrs, this may prove to be an
631228753Smm	 * intractable problem.
632228753Smm	 */
633228753Smm
634228753Smm#ifdef HAVE_FCHDIR
635228753Smm	/* If we changed directory above, restore it here. */
636228753Smm	if (a->restore_pwd >= 0) {
637228753Smm		r = fchdir(a->restore_pwd);
638228753Smm		if (r != 0) {
639228753Smm			archive_set_error(&a->archive, errno, "chdir() failure");
640228753Smm			ret = ARCHIVE_FATAL;
641228753Smm		}
642228753Smm		close(a->restore_pwd);
643228753Smm		a->restore_pwd = -1;
644228753Smm	}
645228753Smm#endif
646228753Smm
647228753Smm	/*
648228753Smm	 * Fixup uses the unedited pathname from archive_entry_pathname(),
649228753Smm	 * because it is relative to the base dir and the edited path
650228753Smm	 * might be relative to some intermediate dir as a result of the
651228753Smm	 * deep restore logic.
652228753Smm	 */
653228753Smm	if (a->deferred & TODO_MODE) {
654228753Smm		fe = current_fixup(a, archive_entry_pathname(entry));
655248616Smm		if (fe == NULL)
656248616Smm			return (ARCHIVE_FATAL);
657228753Smm		fe->fixup |= TODO_MODE_BASE;
658228753Smm		fe->mode = a->mode;
659228753Smm	}
660228753Smm
661228753Smm	if ((a->deferred & TODO_TIMES)
662228753Smm		&& (archive_entry_mtime_is_set(entry)
663228753Smm		    || archive_entry_atime_is_set(entry))) {
664228753Smm		fe = current_fixup(a, archive_entry_pathname(entry));
665248616Smm		if (fe == NULL)
666248616Smm			return (ARCHIVE_FATAL);
667231200Smm		fe->mode = a->mode;
668228753Smm		fe->fixup |= TODO_TIMES;
669228753Smm		if (archive_entry_atime_is_set(entry)) {
670228753Smm			fe->atime = archive_entry_atime(entry);
671228753Smm			fe->atime_nanos = archive_entry_atime_nsec(entry);
672228753Smm		} else {
673228753Smm			/* If atime is unset, use start time. */
674228753Smm			fe->atime = a->start_time;
675228753Smm			fe->atime_nanos = 0;
676228753Smm		}
677228753Smm		if (archive_entry_mtime_is_set(entry)) {
678228753Smm			fe->mtime = archive_entry_mtime(entry);
679228753Smm			fe->mtime_nanos = archive_entry_mtime_nsec(entry);
680228753Smm		} else {
681228753Smm			/* If mtime is unset, use start time. */
682228753Smm			fe->mtime = a->start_time;
683228753Smm			fe->mtime_nanos = 0;
684228753Smm		}
685228753Smm		if (archive_entry_birthtime_is_set(entry)) {
686228753Smm			fe->birthtime = archive_entry_birthtime(entry);
687228753Smm			fe->birthtime_nanos = archive_entry_birthtime_nsec(entry);
688228753Smm		} else {
689228753Smm			/* If birthtime is unset, use mtime. */
690228753Smm			fe->birthtime = fe->mtime;
691228753Smm			fe->birthtime_nanos = fe->mtime_nanos;
692228753Smm		}
693228753Smm	}
694228753Smm
695231200Smm	if (a->deferred & TODO_ACLS) {
696231200Smm		fe = current_fixup(a, archive_entry_pathname(entry));
697248616Smm		if (fe == NULL)
698248616Smm			return (ARCHIVE_FATAL);
699238909Smm		fe->fixup |= TODO_ACLS;
700231200Smm		archive_acl_copy(&fe->acl, archive_entry_acl(entry));
701231200Smm	}
702231200Smm
703231200Smm	if (a->deferred & TODO_MAC_METADATA) {
704231200Smm		const void *metadata;
705231200Smm		size_t metadata_size;
706231200Smm		metadata = archive_entry_mac_metadata(a->entry, &metadata_size);
707231200Smm		if (metadata != NULL && metadata_size > 0) {
708231200Smm			fe = current_fixup(a, archive_entry_pathname(entry));
709248616Smm			if (fe == NULL)
710248616Smm				return (ARCHIVE_FATAL);
711231200Smm			fe->mac_metadata = malloc(metadata_size);
712231200Smm			if (fe->mac_metadata != NULL) {
713231200Smm				memcpy(fe->mac_metadata, metadata, metadata_size);
714231200Smm				fe->mac_metadata_size = metadata_size;
715231200Smm				fe->fixup |= TODO_MAC_METADATA;
716231200Smm			}
717231200Smm		}
718231200Smm	}
719231200Smm
720228753Smm	if (a->deferred & TODO_FFLAGS) {
721228753Smm		fe = current_fixup(a, archive_entry_pathname(entry));
722248616Smm		if (fe == NULL)
723248616Smm			return (ARCHIVE_FATAL);
724228753Smm		fe->fixup |= TODO_FFLAGS;
725228753Smm		/* TODO: Complete this.. defer fflags from below. */
726228753Smm	}
727228753Smm
728228753Smm	/* We've created the object and are ready to pour data into it. */
729228753Smm	if (ret >= ARCHIVE_WARN)
730228753Smm		a->archive.state = ARCHIVE_STATE_DATA;
731228753Smm	/*
732228753Smm	 * If it's not open, tell our client not to try writing.
733228753Smm	 * In particular, dirs, links, etc, don't get written to.
734228753Smm	 */
735228753Smm	if (a->fd < 0) {
736228753Smm		archive_entry_set_size(entry, 0);
737228753Smm		a->filesize = 0;
738228753Smm	}
739228753Smm
740228753Smm	return (ret);
741228753Smm}
742228753Smm
743228753Smmint
744231200Smmarchive_write_disk_set_skip_file(struct archive *_a, int64_t d, int64_t i)
745228753Smm{
746228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
747231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
748228753Smm	    ARCHIVE_STATE_ANY, "archive_write_disk_set_skip_file");
749231200Smm	a->skip_file_set = 1;
750228753Smm	a->skip_file_dev = d;
751228753Smm	a->skip_file_ino = i;
752228753Smm	return (ARCHIVE_OK);
753228753Smm}
754228753Smm
755228753Smmstatic ssize_t
756228753Smmwrite_data_block(struct archive_write_disk *a, const char *buff, size_t size)
757228753Smm{
758228753Smm	uint64_t start_size = size;
759228753Smm	ssize_t bytes_written = 0;
760228753Smm	ssize_t block_size = 0, bytes_to_write;
761228753Smm
762228753Smm	if (size == 0)
763228753Smm		return (ARCHIVE_OK);
764228753Smm
765228753Smm	if (a->filesize == 0 || a->fd < 0) {
766228753Smm		archive_set_error(&a->archive, 0,
767228753Smm		    "Attempt to write to an empty file");
768228753Smm		return (ARCHIVE_WARN);
769228753Smm	}
770228753Smm
771228753Smm	if (a->flags & ARCHIVE_EXTRACT_SPARSE) {
772228753Smm#if HAVE_STRUCT_STAT_ST_BLKSIZE
773228753Smm		int r;
774231200Smm		if ((r = lazy_stat(a)) != ARCHIVE_OK)
775228753Smm			return (r);
776228753Smm		block_size = a->pst->st_blksize;
777228753Smm#else
778228753Smm		/* XXX TODO XXX Is there a more appropriate choice here ? */
779228753Smm		/* This needn't match the filesystem allocation size. */
780228753Smm		block_size = 16*1024;
781228753Smm#endif
782228753Smm	}
783228753Smm
784228753Smm	/* If this write would run beyond the file size, truncate it. */
785231200Smm	if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize)
786228753Smm		start_size = size = (size_t)(a->filesize - a->offset);
787228753Smm
788228753Smm	/* Write the data. */
789228753Smm	while (size > 0) {
790228753Smm		if (block_size == 0) {
791228753Smm			bytes_to_write = size;
792228753Smm		} else {
793228753Smm			/* We're sparsifying the file. */
794228753Smm			const char *p, *end;
795231200Smm			int64_t block_end;
796228753Smm
797228753Smm			/* Skip leading zero bytes. */
798228753Smm			for (p = buff, end = buff + size; p < end; ++p) {
799228753Smm				if (*p != '\0')
800228753Smm					break;
801228753Smm			}
802228753Smm			a->offset += p - buff;
803228753Smm			size -= p - buff;
804228753Smm			buff = p;
805228753Smm			if (size == 0)
806228753Smm				break;
807228753Smm
808228753Smm			/* Calculate next block boundary after offset. */
809228753Smm			block_end
810228753Smm			    = (a->offset / block_size + 1) * block_size;
811228753Smm
812228753Smm			/* If the adjusted write would cross block boundary,
813228753Smm			 * truncate it to the block boundary. */
814228753Smm			bytes_to_write = size;
815228753Smm			if (a->offset + bytes_to_write > block_end)
816228753Smm				bytes_to_write = block_end - a->offset;
817228753Smm		}
818228753Smm		/* Seek if necessary to the specified offset. */
819228753Smm		if (a->offset != a->fd_offset) {
820228753Smm			if (lseek(a->fd, a->offset, SEEK_SET) < 0) {
821228753Smm				archive_set_error(&a->archive, errno,
822228753Smm				    "Seek failed");
823228753Smm				return (ARCHIVE_FATAL);
824228753Smm			}
825228753Smm			a->fd_offset = a->offset;
826231200Smm		}
827228753Smm		bytes_written = write(a->fd, buff, bytes_to_write);
828228753Smm		if (bytes_written < 0) {
829228753Smm			archive_set_error(&a->archive, errno, "Write failed");
830228753Smm			return (ARCHIVE_WARN);
831228753Smm		}
832228753Smm		buff += bytes_written;
833228753Smm		size -= bytes_written;
834231200Smm		a->total_bytes_written += bytes_written;
835228753Smm		a->offset += bytes_written;
836228753Smm		a->fd_offset = a->offset;
837228753Smm	}
838228753Smm	return (start_size - size);
839228753Smm}
840228753Smm
841248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\
842248616Smm	&& defined(HAVE_ZLIB_H)
843248616Smm
844248616Smm/*
845248616Smm * Set UF_COMPRESSED file flag.
846248616Smm * This have to be called after hfs_write_decmpfs() because if the
847248616Smm * file does not have "com.apple.decmpfs" xattr the flag is ignored.
848248616Smm */
849248616Smmstatic int
850248616Smmhfs_set_compressed_fflag(struct archive_write_disk *a)
851248616Smm{
852248616Smm	int r;
853248616Smm
854248616Smm	if ((r = lazy_stat(a)) != ARCHIVE_OK)
855248616Smm		return (r);
856248616Smm
857248616Smm	a->st.st_flags |= UF_COMPRESSED;
858248616Smm	if (fchflags(a->fd, a->st.st_flags) != 0) {
859248616Smm		archive_set_error(&a->archive, errno,
860248616Smm		    "Failed to set UF_COMPRESSED file flag");
861248616Smm		return (ARCHIVE_WARN);
862248616Smm	}
863248616Smm	return (ARCHIVE_OK);
864248616Smm}
865248616Smm
866248616Smm/*
867248616Smm * HFS+ Compression decmpfs
868248616Smm *
869248616Smm *     +------------------------------+ +0
870248616Smm *     |      Magic(LE 4 bytes)       |
871248616Smm *     +------------------------------+
872248616Smm *     |      Type(LE 4 bytes)        |
873248616Smm *     +------------------------------+
874248616Smm *     | Uncompressed size(LE 8 bytes)|
875248616Smm *     +------------------------------+ +16
876248616Smm *     |                              |
877248616Smm *     |       Compressed data        |
878248616Smm *     |  (Placed only if Type == 3)  |
879248616Smm *     |                              |
880248616Smm *     +------------------------------+  +3802 = MAX_DECMPFS_XATTR_SIZE
881248616Smm *
882248616Smm *  Type is 3: decmpfs has compressed data.
883248616Smm *  Type is 4: Resource Fork has compressed data.
884248616Smm */
885248616Smm/*
886248616Smm * Write "com.apple.decmpfs"
887248616Smm */
888248616Smmstatic int
889248616Smmhfs_write_decmpfs(struct archive_write_disk *a)
890248616Smm{
891248616Smm	int r;
892248616Smm	uint32_t compression_type;
893248616Smm
894248616Smm	r = fsetxattr(a->fd, DECMPFS_XATTR_NAME, a->decmpfs_header_p,
895248616Smm	    a->decmpfs_attr_size, 0, 0);
896248616Smm	if (r < 0) {
897248616Smm		archive_set_error(&a->archive, errno,
898248616Smm		    "Cannot restore xattr:%s", DECMPFS_XATTR_NAME);
899248616Smm		compression_type = archive_le32dec(
900248616Smm		    &a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE]);
901248616Smm		if (compression_type == CMP_RESOURCE_FORK)
902248616Smm			fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME,
903248616Smm			    XATTR_SHOWCOMPRESSION);
904248616Smm		return (ARCHIVE_WARN);
905248616Smm	}
906248616Smm	return (ARCHIVE_OK);
907248616Smm}
908248616Smm
909248616Smm/*
910248616Smm * HFS+ Compression Resource Fork
911248616Smm *
912248616Smm *     +-----------------------------+
913248616Smm *     |     Header(260 bytes)       |
914248616Smm *     +-----------------------------+
915248616Smm *     |   Block count(LE 4 bytes)   |
916248616Smm *     +-----------------------------+  --+
917248616Smm * +-- |     Offset (LE 4 bytes)     |    |
918248616Smm * |   | [distance from Block count] |    | Block 0
919248616Smm * |   +-----------------------------+    |
920248616Smm * |   | Compressed size(LE 4 bytes) |    |
921248616Smm * |   +-----------------------------+  --+
922248616Smm * |   |                             |
923248616Smm * |   |      ..................     |
924248616Smm * |   |                             |
925248616Smm * |   +-----------------------------+  --+
926248616Smm * |   |     Offset (LE 4 bytes)     |    |
927248616Smm * |   +-----------------------------+    | Block (Block count -1)
928248616Smm * |   | Compressed size(LE 4 bytes) |    |
929248616Smm * +-> +-----------------------------+  --+
930248616Smm *     |   Compressed data(n bytes)  |  Block 0
931248616Smm *     +-----------------------------+
932248616Smm *     |                             |
933248616Smm *     |      ..................     |
934248616Smm *     |                             |
935248616Smm *     +-----------------------------+
936248616Smm *     |   Compressed data(n bytes)  |  Block (Block count -1)
937248616Smm *     +-----------------------------+
938248616Smm *     |      Footer(50 bytes)       |
939248616Smm *     +-----------------------------+
940248616Smm *
941248616Smm */
942248616Smm/*
943248616Smm * Write the header of "com.apple.ResourceFork"
944248616Smm */
945248616Smmstatic int
946248616Smmhfs_write_resource_fork(struct archive_write_disk *a, unsigned char *buff,
947248616Smm    size_t bytes, uint32_t position)
948248616Smm{
949248616Smm	int ret;
950248616Smm
951248616Smm	ret = fsetxattr(a->fd, XATTR_RESOURCEFORK_NAME, buff, bytes,
952248616Smm	    position, a->rsrc_xattr_options);
953248616Smm	if (ret < 0) {
954248616Smm		archive_set_error(&a->archive, errno,
955248616Smm		    "Cannot restore xattr: %s at %u pos %u bytes",
956248616Smm		    XATTR_RESOURCEFORK_NAME,
957248616Smm		    (unsigned)position,
958248616Smm		    (unsigned)bytes);
959248616Smm		return (ARCHIVE_WARN);
960248616Smm	}
961248616Smm	a->rsrc_xattr_options &= ~XATTR_CREATE;
962248616Smm	return (ARCHIVE_OK);
963248616Smm}
964248616Smm
965248616Smmstatic int
966248616Smmhfs_write_compressed_data(struct archive_write_disk *a, size_t bytes_compressed)
967248616Smm{
968248616Smm	int ret;
969248616Smm
970248616Smm	ret = hfs_write_resource_fork(a, a->compressed_buffer,
971248616Smm	    bytes_compressed, a->compressed_rsrc_position);
972248616Smm	if (ret == ARCHIVE_OK)
973248616Smm		a->compressed_rsrc_position += bytes_compressed;
974248616Smm	return (ret);
975248616Smm}
976248616Smm
977248616Smmstatic int
978248616Smmhfs_write_resource_fork_header(struct archive_write_disk *a)
979248616Smm{
980248616Smm	unsigned char *buff;
981248616Smm	uint32_t rsrc_bytes;
982248616Smm	uint32_t rsrc_header_bytes;
983248616Smm
984248616Smm	/*
985248616Smm	 * Write resource fork header + block info.
986248616Smm	 */
987248616Smm	buff = a->resource_fork;
988248616Smm	rsrc_bytes = a->compressed_rsrc_position - RSRC_F_SIZE;
989248616Smm	rsrc_header_bytes =
990248616Smm		RSRC_H_SIZE +		/* Header base size. */
991248616Smm		4 +			/* Block count. */
992248616Smm		(a->decmpfs_block_count * 8);/* Block info */
993248616Smm	archive_be32enc(buff, 0x100);
994248616Smm	archive_be32enc(buff + 4, rsrc_bytes);
995248616Smm	archive_be32enc(buff + 8, rsrc_bytes - 256);
996248616Smm	archive_be32enc(buff + 12, 0x32);
997248616Smm	memset(buff + 16, 0, 240);
998248616Smm	archive_be32enc(buff + 256, rsrc_bytes - 260);
999248616Smm	return hfs_write_resource_fork(a, buff, rsrc_header_bytes, 0);
1000248616Smm}
1001248616Smm
1002248616Smmstatic size_t
1003248616Smmhfs_set_resource_fork_footer(unsigned char *buff, size_t buff_size)
1004248616Smm{
1005248616Smm	static const char rsrc_footer[RSRC_F_SIZE] = {
1006248616Smm		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1007248616Smm		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1008248616Smm		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1009248616Smm		0x00, 0x1c, 0x00, 0x32, 0x00, 0x00, 'c',  'm',
1010248616Smm		'p', 'f',   0x00, 0x00, 0x00, 0x0a, 0x00, 0x01,
1011248616Smm		0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1012248616Smm		0x00, 0x00
1013248616Smm	};
1014248616Smm	if (buff_size < sizeof(rsrc_footer))
1015248616Smm		return (0);
1016248616Smm	memcpy(buff, rsrc_footer, sizeof(rsrc_footer));
1017248616Smm	return (sizeof(rsrc_footer));
1018248616Smm}
1019248616Smm
1020248616Smmstatic int
1021248616Smmhfs_reset_compressor(struct archive_write_disk *a)
1022248616Smm{
1023248616Smm	int ret;
1024248616Smm
1025248616Smm	if (a->stream_valid)
1026248616Smm		ret = deflateReset(&a->stream);
1027248616Smm	else
1028248616Smm		ret = deflateInit(&a->stream, a->decmpfs_compression_level);
1029248616Smm
1030248616Smm	if (ret != Z_OK) {
1031248616Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1032248616Smm		    "Failed to initialize compressor");
1033248616Smm		return (ARCHIVE_FATAL);
1034248616Smm	} else
1035248616Smm		a->stream_valid = 1;
1036248616Smm
1037248616Smm	return (ARCHIVE_OK);
1038248616Smm}
1039248616Smm
1040248616Smmstatic int
1041248616Smmhfs_decompress(struct archive_write_disk *a)
1042248616Smm{
1043248616Smm	uint32_t *block_info;
1044248616Smm	unsigned int block_count;
1045248616Smm	uint32_t data_pos, data_size;
1046248616Smm	ssize_t r;
1047248616Smm	ssize_t bytes_written, bytes_to_write;
1048248616Smm	unsigned char *b;
1049248616Smm
1050248616Smm	block_info = (uint32_t *)(a->resource_fork + RSRC_H_SIZE);
1051248616Smm	block_count = archive_le32dec(block_info++);
1052248616Smm	while (block_count--) {
1053248616Smm		data_pos = RSRC_H_SIZE + archive_le32dec(block_info++);
1054248616Smm		data_size = archive_le32dec(block_info++);
1055248616Smm		r = fgetxattr(a->fd, XATTR_RESOURCEFORK_NAME,
1056248616Smm		    a->compressed_buffer, data_size, data_pos, 0);
1057248616Smm		if (r != data_size)  {
1058248616Smm			archive_set_error(&a->archive,
1059248616Smm			    (r < 0)?errno:ARCHIVE_ERRNO_MISC,
1060248616Smm			    "Failed to read resource fork");
1061248616Smm			return (ARCHIVE_WARN);
1062248616Smm		}
1063248616Smm		if (a->compressed_buffer[0] == 0xff) {
1064248616Smm			bytes_to_write = data_size -1;
1065248616Smm			b = a->compressed_buffer + 1;
1066248616Smm		} else {
1067248616Smm			uLong dest_len = MAX_DECMPFS_BLOCK_SIZE;
1068248616Smm			int zr;
1069248616Smm
1070248616Smm			zr = uncompress((Bytef *)a->uncompressed_buffer,
1071248616Smm			    &dest_len, a->compressed_buffer, data_size);
1072248616Smm			if (zr != Z_OK) {
1073248616Smm				archive_set_error(&a->archive,
1074248616Smm				    ARCHIVE_ERRNO_MISC,
1075248616Smm				    "Failed to decompress resource fork");
1076248616Smm				return (ARCHIVE_WARN);
1077248616Smm			}
1078248616Smm			bytes_to_write = dest_len;
1079248616Smm			b = (unsigned char *)a->uncompressed_buffer;
1080248616Smm		}
1081248616Smm		do {
1082248616Smm			bytes_written = write(a->fd, b, bytes_to_write);
1083248616Smm			if (bytes_written < 0) {
1084248616Smm				archive_set_error(&a->archive, errno,
1085248616Smm				    "Write failed");
1086248616Smm				return (ARCHIVE_WARN);
1087248616Smm			}
1088248616Smm			bytes_to_write -= bytes_written;
1089248616Smm			b += bytes_written;
1090248616Smm		} while (bytes_to_write > 0);
1091248616Smm	}
1092248616Smm	r = fremovexattr(a->fd, XATTR_RESOURCEFORK_NAME, 0);
1093248616Smm	if (r == -1)  {
1094248616Smm		archive_set_error(&a->archive, errno,
1095248616Smm		    "Failed to remove resource fork");
1096248616Smm		return (ARCHIVE_WARN);
1097248616Smm	}
1098248616Smm	return (ARCHIVE_OK);
1099248616Smm}
1100248616Smm
1101248616Smmstatic int
1102248616Smmhfs_drive_compressor(struct archive_write_disk *a, const char *buff,
1103248616Smm    size_t size)
1104248616Smm{
1105248616Smm	unsigned char *buffer_compressed;
1106248616Smm	size_t bytes_compressed;
1107248616Smm	size_t bytes_used;
1108248616Smm	int ret;
1109248616Smm
1110248616Smm	ret = hfs_reset_compressor(a);
1111248616Smm	if (ret != ARCHIVE_OK)
1112248616Smm		return (ret);
1113248616Smm
1114248616Smm	if (a->compressed_buffer == NULL) {
1115248616Smm		size_t block_size;
1116248616Smm
1117248616Smm		block_size = COMPRESSED_W_SIZE + RSRC_F_SIZE +
1118248616Smm		    + compressBound(MAX_DECMPFS_BLOCK_SIZE);
1119248616Smm		a->compressed_buffer = malloc(block_size);
1120248616Smm		if (a->compressed_buffer == NULL) {
1121248616Smm			archive_set_error(&a->archive, ENOMEM,
1122248616Smm			    "Can't allocate memory for Resource Fork");
1123248616Smm			return (ARCHIVE_FATAL);
1124248616Smm		}
1125248616Smm		a->compressed_buffer_size = block_size;
1126248616Smm		a->compressed_buffer_remaining = block_size;
1127248616Smm	}
1128248616Smm
1129248616Smm	buffer_compressed = a->compressed_buffer +
1130248616Smm	    a->compressed_buffer_size - a->compressed_buffer_remaining;
1131248616Smm	a->stream.next_in = (Bytef *)(uintptr_t)(const void *)buff;
1132248616Smm	a->stream.avail_in = size;
1133248616Smm	a->stream.next_out = buffer_compressed;
1134248616Smm	a->stream.avail_out = a->compressed_buffer_remaining;
1135248616Smm	do {
1136248616Smm		ret = deflate(&a->stream, Z_FINISH);
1137248616Smm		switch (ret) {
1138248616Smm		case Z_OK:
1139248616Smm		case Z_STREAM_END:
1140248616Smm			break;
1141248616Smm		default:
1142248616Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1143248616Smm			    "Failed to compress data");
1144248616Smm			return (ARCHIVE_FAILED);
1145248616Smm		}
1146248616Smm	} while (ret == Z_OK);
1147248616Smm	bytes_compressed = a->compressed_buffer_remaining - a->stream.avail_out;
1148248616Smm
1149248616Smm	/*
1150248616Smm	 * If the compressed size is larger than the original size,
1151248616Smm	 * throw away compressed data, use uncompressed data instead.
1152248616Smm	 */
1153248616Smm	if (bytes_compressed > size) {
1154248616Smm		buffer_compressed[0] = 0xFF;/* uncompressed marker. */
1155248616Smm		memcpy(buffer_compressed + 1, buff, size);
1156248616Smm		bytes_compressed = size + 1;
1157248616Smm	}
1158248616Smm	a->compressed_buffer_remaining -= bytes_compressed;
1159248616Smm
1160248616Smm	/*
1161248616Smm	 * If the compressed size is smaller than MAX_DECMPFS_XATTR_SIZE
1162248616Smm	 * and the block count in the file is only one, store compressed
1163248616Smm	 * data to decmpfs xattr instead of the resource fork.
1164248616Smm	 */
1165248616Smm	if (a->decmpfs_block_count == 1 &&
1166248616Smm	    (a->decmpfs_attr_size + bytes_compressed)
1167248616Smm	      <= MAX_DECMPFS_XATTR_SIZE) {
1168248616Smm		archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE],
1169248616Smm		    CMP_XATTR);
1170248616Smm		memcpy(a->decmpfs_header_p + DECMPFS_HEADER_SIZE,
1171248616Smm		    buffer_compressed, bytes_compressed);
1172248616Smm		a->decmpfs_attr_size += bytes_compressed;
1173248616Smm		a->compressed_buffer_remaining = a->compressed_buffer_size;
1174248616Smm		/*
1175248616Smm		 * Finish HFS+ Compression.
1176248616Smm		 * - Write the decmpfs xattr.
1177248616Smm		 * - Set the UF_COMPRESSED file flag.
1178248616Smm		 */
1179248616Smm		ret = hfs_write_decmpfs(a);
1180248616Smm		if (ret == ARCHIVE_OK)
1181248616Smm			ret = hfs_set_compressed_fflag(a);
1182248616Smm		return (ret);
1183248616Smm	}
1184248616Smm
1185248616Smm	/* Update block info. */
1186248616Smm	archive_le32enc(a->decmpfs_block_info++,
1187248616Smm	    a->compressed_rsrc_position_v - RSRC_H_SIZE);
1188248616Smm	archive_le32enc(a->decmpfs_block_info++, bytes_compressed);
1189248616Smm	a->compressed_rsrc_position_v += bytes_compressed;
1190248616Smm
1191248616Smm	/*
1192248616Smm	 * Write the compressed data to the resource fork.
1193248616Smm	 */
1194248616Smm	bytes_used = a->compressed_buffer_size - a->compressed_buffer_remaining;
1195248616Smm	while (bytes_used >= COMPRESSED_W_SIZE) {
1196248616Smm		ret = hfs_write_compressed_data(a, COMPRESSED_W_SIZE);
1197248616Smm		if (ret != ARCHIVE_OK)
1198248616Smm			return (ret);
1199248616Smm		bytes_used -= COMPRESSED_W_SIZE;
1200248616Smm		if (bytes_used > COMPRESSED_W_SIZE)
1201248616Smm			memmove(a->compressed_buffer,
1202248616Smm			    a->compressed_buffer + COMPRESSED_W_SIZE,
1203248616Smm			    bytes_used);
1204248616Smm		else
1205248616Smm			memcpy(a->compressed_buffer,
1206248616Smm			    a->compressed_buffer + COMPRESSED_W_SIZE,
1207248616Smm			    bytes_used);
1208248616Smm	}
1209248616Smm	a->compressed_buffer_remaining = a->compressed_buffer_size - bytes_used;
1210248616Smm
1211248616Smm	/*
1212248616Smm	 * If the current block is the last block, write the remaining
1213248616Smm	 * compressed data and the resource fork footer.
1214248616Smm	 */
1215248616Smm	if (a->file_remaining_bytes == 0) {
1216248616Smm		size_t rsrc_size;
1217248616Smm		int64_t bk;
1218248616Smm
1219248616Smm		/* Append the resource footer. */
1220248616Smm		rsrc_size = hfs_set_resource_fork_footer(
1221248616Smm		    a->compressed_buffer + bytes_used,
1222248616Smm		    a->compressed_buffer_remaining);
1223248616Smm		ret = hfs_write_compressed_data(a, bytes_used + rsrc_size);
1224248616Smm		a->compressed_buffer_remaining = a->compressed_buffer_size;
1225248616Smm
1226248616Smm		/* If the compressed size is not enouph smaller than
1227248616Smm		 * the uncompressed size. cancel HFS+ compression.
1228248616Smm		 * TODO: study a behavior of ditto utility and improve
1229248616Smm		 * the condition to fall back into no HFS+ compression. */
1230248616Smm		bk = HFS_BLOCKS(a->compressed_rsrc_position);
1231248616Smm		bk += bk >> 7;
1232248616Smm		if (bk > HFS_BLOCKS(a->filesize))
1233248616Smm			return hfs_decompress(a);
1234248616Smm		/*
1235248616Smm		 * Write the resourcefork header.
1236248616Smm		 */
1237248616Smm		if (ret == ARCHIVE_OK)
1238248616Smm			ret = hfs_write_resource_fork_header(a);
1239248616Smm		/*
1240248616Smm		 * Finish HFS+ Compression.
1241248616Smm		 * - Write the decmpfs xattr.
1242248616Smm		 * - Set the UF_COMPRESSED file flag.
1243248616Smm		 */
1244248616Smm		if (ret == ARCHIVE_OK)
1245248616Smm			ret = hfs_write_decmpfs(a);
1246248616Smm		if (ret == ARCHIVE_OK)
1247248616Smm			ret = hfs_set_compressed_fflag(a);
1248248616Smm	}
1249248616Smm	return (ret);
1250248616Smm}
1251248616Smm
1252228753Smmstatic ssize_t
1253248616Smmhfs_write_decmpfs_block(struct archive_write_disk *a, const char *buff,
1254248616Smm    size_t size)
1255248616Smm{
1256248616Smm	const char *buffer_to_write;
1257248616Smm	size_t bytes_to_write;
1258248616Smm	int ret;
1259248616Smm
1260248616Smm	if (a->decmpfs_block_count == (unsigned)-1) {
1261248616Smm		void *new_block;
1262248616Smm		size_t new_size;
1263248616Smm		unsigned int block_count;
1264248616Smm
1265248616Smm		if (a->decmpfs_header_p == NULL) {
1266248616Smm			new_block = malloc(MAX_DECMPFS_XATTR_SIZE
1267248616Smm			    + sizeof(uint32_t));
1268248616Smm			if (new_block == NULL) {
1269248616Smm				archive_set_error(&a->archive, ENOMEM,
1270248616Smm				    "Can't allocate memory for decmpfs");
1271248616Smm				return (ARCHIVE_FATAL);
1272248616Smm			}
1273248616Smm			a->decmpfs_header_p = new_block;
1274248616Smm		}
1275248616Smm		a->decmpfs_attr_size = DECMPFS_HEADER_SIZE;
1276248616Smm		archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_MAGIC],
1277248616Smm		    DECMPFS_MAGIC);
1278248616Smm		archive_le32enc(&a->decmpfs_header_p[DECMPFS_COMPRESSION_TYPE],
1279248616Smm		    CMP_RESOURCE_FORK);
1280248616Smm		archive_le64enc(&a->decmpfs_header_p[DECMPFS_UNCOMPRESSED_SIZE],
1281248616Smm		    a->filesize);
1282248616Smm
1283248616Smm		/* Calculate a block count of the file. */
1284248616Smm		block_count =
1285248616Smm		    (a->filesize + MAX_DECMPFS_BLOCK_SIZE -1) /
1286248616Smm			MAX_DECMPFS_BLOCK_SIZE;
1287248616Smm		/*
1288248616Smm		 * Allocate buffer for resource fork.
1289248616Smm		 * Set up related pointers;
1290248616Smm		 */
1291248616Smm		new_size =
1292248616Smm		    RSRC_H_SIZE + /* header */
1293248616Smm		    4 + /* Block count */
1294248616Smm		    (block_count * sizeof(uint32_t) * 2) +
1295248616Smm		    RSRC_F_SIZE; /* footer */
1296248616Smm		if (new_size > a->resource_fork_allocated_size) {
1297248616Smm			new_block = realloc(a->resource_fork, new_size);
1298248616Smm			if (new_block == NULL) {
1299248616Smm				archive_set_error(&a->archive, ENOMEM,
1300248616Smm				    "Can't allocate memory for ResourceFork");
1301248616Smm				return (ARCHIVE_FATAL);
1302248616Smm			}
1303248616Smm			a->resource_fork_allocated_size = new_size;
1304248616Smm			a->resource_fork = new_block;
1305248616Smm		}
1306248616Smm
1307248616Smm		/* Allocate uncompressed buffer */
1308248616Smm		if (a->uncompressed_buffer == NULL) {
1309248616Smm			new_block = malloc(MAX_DECMPFS_BLOCK_SIZE);
1310248616Smm			if (new_block == NULL) {
1311248616Smm				archive_set_error(&a->archive, ENOMEM,
1312248616Smm				    "Can't allocate memory for decmpfs");
1313248616Smm				return (ARCHIVE_FATAL);
1314248616Smm			}
1315248616Smm			a->uncompressed_buffer = new_block;
1316248616Smm		}
1317248616Smm		a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE;
1318248616Smm		a->file_remaining_bytes = a->filesize;
1319248616Smm		a->compressed_buffer_remaining = a->compressed_buffer_size;
1320248616Smm
1321248616Smm		/*
1322248616Smm		 * Set up a resource fork.
1323248616Smm		 */
1324248616Smm		a->rsrc_xattr_options = XATTR_CREATE;
1325248616Smm		/* Get the position where we are going to set a bunch
1326248616Smm		 * of block info. */
1327248616Smm		a->decmpfs_block_info =
1328248616Smm		    (uint32_t *)(a->resource_fork + RSRC_H_SIZE);
1329248616Smm		/* Set the block count to the resource fork. */
1330248616Smm		archive_le32enc(a->decmpfs_block_info++, block_count);
1331248616Smm		/* Get the position where we are goint to set compressed
1332248616Smm		 * data. */
1333248616Smm		a->compressed_rsrc_position =
1334248616Smm		    RSRC_H_SIZE + 4 + (block_count * 8);
1335248616Smm		a->compressed_rsrc_position_v = a->compressed_rsrc_position;
1336248616Smm		a->decmpfs_block_count = block_count;
1337248616Smm	}
1338248616Smm
1339248616Smm	/* Ignore redundant bytes. */
1340248616Smm	if (a->file_remaining_bytes == 0)
1341248616Smm		return ((ssize_t)size);
1342248616Smm
1343248616Smm	/* Do not overrun a block size. */
1344248616Smm	if (size > a->block_remaining_bytes)
1345248616Smm		bytes_to_write = a->block_remaining_bytes;
1346248616Smm	else
1347248616Smm		bytes_to_write = size;
1348248616Smm	/* Do not overrun the file size. */
1349248616Smm	if (bytes_to_write > a->file_remaining_bytes)
1350248616Smm		bytes_to_write = a->file_remaining_bytes;
1351248616Smm
1352248616Smm	/* For efficiency, if a copy length is full of the uncompressed
1353248616Smm	 * buffer size, do not copy writing data to it. */
1354248616Smm	if (bytes_to_write == MAX_DECMPFS_BLOCK_SIZE)
1355248616Smm		buffer_to_write = buff;
1356248616Smm	else {
1357248616Smm		memcpy(a->uncompressed_buffer +
1358248616Smm		    MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes,
1359248616Smm		    buff, bytes_to_write);
1360248616Smm		buffer_to_write = a->uncompressed_buffer;
1361248616Smm	}
1362248616Smm	a->block_remaining_bytes -= bytes_to_write;
1363248616Smm	a->file_remaining_bytes -= bytes_to_write;
1364248616Smm
1365248616Smm	if (a->block_remaining_bytes == 0 || a->file_remaining_bytes == 0) {
1366248616Smm		ret = hfs_drive_compressor(a, buffer_to_write,
1367248616Smm		    MAX_DECMPFS_BLOCK_SIZE - a->block_remaining_bytes);
1368248616Smm		if (ret < 0)
1369248616Smm			return (ret);
1370248616Smm		a->block_remaining_bytes = MAX_DECMPFS_BLOCK_SIZE;
1371248616Smm	}
1372248616Smm	/* Ignore redundant bytes. */
1373248616Smm	if (a->file_remaining_bytes == 0)
1374248616Smm		return ((ssize_t)size);
1375248616Smm	return (bytes_to_write);
1376248616Smm}
1377248616Smm
1378248616Smmstatic ssize_t
1379248616Smmhfs_write_data_block(struct archive_write_disk *a, const char *buff,
1380248616Smm    size_t size)
1381248616Smm{
1382248616Smm	uint64_t start_size = size;
1383248616Smm	ssize_t bytes_written = 0;
1384248616Smm	ssize_t bytes_to_write;
1385248616Smm
1386248616Smm	if (size == 0)
1387248616Smm		return (ARCHIVE_OK);
1388248616Smm
1389248616Smm	if (a->filesize == 0 || a->fd < 0) {
1390248616Smm		archive_set_error(&a->archive, 0,
1391248616Smm		    "Attempt to write to an empty file");
1392248616Smm		return (ARCHIVE_WARN);
1393248616Smm	}
1394248616Smm
1395248616Smm	/* If this write would run beyond the file size, truncate it. */
1396248616Smm	if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize)
1397248616Smm		start_size = size = (size_t)(a->filesize - a->offset);
1398248616Smm
1399248616Smm	/* Write the data. */
1400248616Smm	while (size > 0) {
1401248616Smm		bytes_to_write = size;
1402248616Smm		/* Seek if necessary to the specified offset. */
1403248616Smm		if (a->offset < a->fd_offset) {
1404248616Smm			/* Can't support backword move. */
1405248616Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1406248616Smm			    "Seek failed");
1407248616Smm			return (ARCHIVE_FATAL);
1408248616Smm		} else if (a->offset > a->fd_offset) {
1409248616Smm			int64_t skip = a->offset - a->fd_offset;
1410248616Smm			char nullblock[1024];
1411248616Smm
1412248616Smm			memset(nullblock, 0, sizeof(nullblock));
1413248616Smm			while (skip > 0) {
1414248616Smm				if (skip > (int64_t)sizeof(nullblock))
1415248616Smm					bytes_written = hfs_write_decmpfs_block(
1416248616Smm					    a, nullblock, sizeof(nullblock));
1417248616Smm				else
1418248616Smm					bytes_written = hfs_write_decmpfs_block(
1419248616Smm					    a, nullblock, skip);
1420248616Smm				if (bytes_written < 0) {
1421248616Smm					archive_set_error(&a->archive, errno,
1422248616Smm					    "Write failed");
1423248616Smm					return (ARCHIVE_WARN);
1424248616Smm				}
1425248616Smm				skip -= bytes_written;
1426248616Smm			}
1427248616Smm
1428248616Smm			a->fd_offset = a->offset;
1429248616Smm		}
1430248616Smm		bytes_written =
1431248616Smm		    hfs_write_decmpfs_block(a, buff, bytes_to_write);
1432248616Smm		if (bytes_written < 0)
1433248616Smm			return (bytes_written);
1434248616Smm		buff += bytes_written;
1435248616Smm		size -= bytes_written;
1436248616Smm		a->total_bytes_written += bytes_written;
1437248616Smm		a->offset += bytes_written;
1438248616Smm		a->fd_offset = a->offset;
1439248616Smm	}
1440248616Smm	return (start_size - size);
1441248616Smm}
1442248616Smm#else
1443248616Smmstatic ssize_t
1444248616Smmhfs_write_data_block(struct archive_write_disk *a, const char *buff,
1445248616Smm    size_t size)
1446248616Smm{
1447248616Smm	return (write_data_block(a, buff, size));
1448248616Smm}
1449248616Smm#endif
1450248616Smm
1451248616Smmstatic ssize_t
1452231200Smm_archive_write_disk_data_block(struct archive *_a,
1453231200Smm    const void *buff, size_t size, int64_t offset)
1454228753Smm{
1455228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
1456228753Smm	ssize_t r;
1457228753Smm
1458231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
1459231200Smm	    ARCHIVE_STATE_DATA, "archive_write_data_block");
1460228753Smm
1461228753Smm	a->offset = offset;
1462248616Smm	if (a->todo & TODO_HFS_COMPRESSION)
1463248616Smm		r = hfs_write_data_block(a, buff, size);
1464248616Smm	else
1465248616Smm		r = write_data_block(a, buff, size);
1466228753Smm	if (r < ARCHIVE_OK)
1467228753Smm		return (r);
1468228753Smm	if ((size_t)r < size) {
1469228753Smm		archive_set_error(&a->archive, 0,
1470228753Smm		    "Write request too large");
1471228753Smm		return (ARCHIVE_WARN);
1472228753Smm	}
1473228753Smm	return (ARCHIVE_OK);
1474228753Smm}
1475228753Smm
1476228753Smmstatic ssize_t
1477231200Smm_archive_write_disk_data(struct archive *_a, const void *buff, size_t size)
1478228753Smm{
1479228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
1480228753Smm
1481231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
1482228753Smm	    ARCHIVE_STATE_DATA, "archive_write_data");
1483228753Smm
1484248616Smm	if (a->todo & TODO_HFS_COMPRESSION)
1485248616Smm		return (hfs_write_data_block(a, buff, size));
1486228753Smm	return (write_data_block(a, buff, size));
1487228753Smm}
1488228753Smm
1489228753Smmstatic int
1490231200Smm_archive_write_disk_finish_entry(struct archive *_a)
1491228753Smm{
1492228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
1493228753Smm	int ret = ARCHIVE_OK;
1494228753Smm
1495231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
1496228753Smm	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
1497228753Smm	    "archive_write_finish_entry");
1498228753Smm	if (a->archive.state & ARCHIVE_STATE_HEADER)
1499228753Smm		return (ARCHIVE_OK);
1500228753Smm	archive_clear_error(&a->archive);
1501228753Smm
1502228753Smm	/* Pad or truncate file to the right size. */
1503228753Smm	if (a->fd < 0) {
1504228753Smm		/* There's no file. */
1505228753Smm	} else if (a->filesize < 0) {
1506228753Smm		/* File size is unknown, so we can't set the size. */
1507228753Smm	} else if (a->fd_offset == a->filesize) {
1508228753Smm		/* Last write ended at exactly the filesize; we're done. */
1509228753Smm		/* Hopefully, this is the common case. */
1510248616Smm#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_ZLIB_H)
1511248616Smm	} else if (a->todo & TODO_HFS_COMPRESSION) {
1512248616Smm		char null_d[1024];
1513248616Smm		ssize_t r;
1514248616Smm
1515248616Smm		if (a->file_remaining_bytes)
1516248616Smm			memset(null_d, 0, sizeof(null_d));
1517248616Smm		while (a->file_remaining_bytes) {
1518248616Smm			if (a->file_remaining_bytes > sizeof(null_d))
1519248616Smm				r = hfs_write_data_block(
1520248616Smm				    a, null_d, sizeof(null_d));
1521248616Smm			else
1522248616Smm				r = hfs_write_data_block(
1523248616Smm				    a, null_d, a->file_remaining_bytes);
1524248616Smm			if (r < 0)
1525248616Smm				return ((int)r);
1526248616Smm		}
1527248616Smm#endif
1528228753Smm	} else {
1529228753Smm#if HAVE_FTRUNCATE
1530228753Smm		if (ftruncate(a->fd, a->filesize) == -1 &&
1531228753Smm		    a->filesize == 0) {
1532228753Smm			archive_set_error(&a->archive, errno,
1533228753Smm			    "File size could not be restored");
1534228753Smm			return (ARCHIVE_FAILED);
1535228753Smm		}
1536228753Smm#endif
1537228753Smm		/*
1538228753Smm		 * Not all platforms implement the XSI option to
1539228753Smm		 * extend files via ftruncate.  Stat() the file again
1540228753Smm		 * to see what happened.
1541228753Smm		 */
1542228753Smm		a->pst = NULL;
1543231200Smm		if ((ret = lazy_stat(a)) != ARCHIVE_OK)
1544228753Smm			return (ret);
1545228753Smm		/* We can use lseek()/write() to extend the file if
1546228753Smm		 * ftruncate didn't work or isn't available. */
1547228753Smm		if (a->st.st_size < a->filesize) {
1548228753Smm			const char nul = '\0';
1549228753Smm			if (lseek(a->fd, a->filesize - 1, SEEK_SET) < 0) {
1550228753Smm				archive_set_error(&a->archive, errno,
1551228753Smm				    "Seek failed");
1552228753Smm				return (ARCHIVE_FATAL);
1553228753Smm			}
1554228753Smm			if (write(a->fd, &nul, 1) < 0) {
1555228753Smm				archive_set_error(&a->archive, errno,
1556228753Smm				    "Write to restore size failed");
1557228753Smm				return (ARCHIVE_FATAL);
1558228753Smm			}
1559228753Smm			a->pst = NULL;
1560228753Smm		}
1561228753Smm	}
1562228753Smm
1563228753Smm	/* Restore metadata. */
1564228753Smm
1565228753Smm	/*
1566248616Smm	 * This is specific to Mac OS X.
1567248616Smm	 * If the current file is an AppleDouble file, it should be
1568248616Smm	 * linked with the data fork file and remove it.
1569248616Smm	 */
1570248616Smm	if (a->todo & TODO_APPLEDOUBLE) {
1571248616Smm		int r2 = fixup_appledouble(a, a->name);
1572248616Smm		if (r2 == ARCHIVE_EOF) {
1573248616Smm			/* The current file has been successfully linked
1574248616Smm			 * with the data fork file and removed. So there
1575248616Smm			 * is nothing to do on the current file.  */
1576248616Smm			goto finish_metadata;
1577248616Smm		}
1578248616Smm		if (r2 < ret) ret = r2;
1579248616Smm	}
1580248616Smm
1581248616Smm	/*
1582228753Smm	 * Look up the "real" UID only if we're going to need it.
1583228753Smm	 * TODO: the TODO_SGID condition can be dropped here, can't it?
1584228753Smm	 */
1585228753Smm	if (a->todo & (TODO_OWNER | TODO_SUID | TODO_SGID)) {
1586231200Smm		a->uid = archive_write_disk_uid(&a->archive,
1587228753Smm		    archive_entry_uname(a->entry),
1588228753Smm		    archive_entry_uid(a->entry));
1589228753Smm	}
1590228753Smm	/* Look up the "real" GID only if we're going to need it. */
1591228753Smm	/* TODO: the TODO_SUID condition can be dropped here, can't it? */
1592228753Smm	if (a->todo & (TODO_OWNER | TODO_SGID | TODO_SUID)) {
1593231200Smm		a->gid = archive_write_disk_gid(&a->archive,
1594228753Smm		    archive_entry_gname(a->entry),
1595228753Smm		    archive_entry_gid(a->entry));
1596228753Smm	 }
1597231200Smm
1598228753Smm	/*
1599231200Smm	 * Restore ownership before set_mode tries to restore suid/sgid
1600228753Smm	 * bits.  If we set the owner, we know what it is and can skip
1601228753Smm	 * a stat() call to examine the ownership of the file on disk.
1602228753Smm	 */
1603248616Smm	if (a->todo & TODO_OWNER) {
1604248616Smm		int r2 = set_ownership(a);
1605248616Smm		if (r2 < ret) ret = r2;
1606248616Smm	}
1607231200Smm
1608231200Smm	/*
1609231200Smm	 * set_mode must precede ACLs on systems such as Solaris and
1610231200Smm	 * FreeBSD where setting the mode implicitly clears extended ACLs
1611231200Smm	 */
1612228753Smm	if (a->todo & TODO_MODE) {
1613228753Smm		int r2 = set_mode(a, a->mode);
1614228753Smm		if (r2 < ret) ret = r2;
1615228753Smm	}
1616228753Smm
1617228753Smm	/*
1618228753Smm	 * Security-related extended attributes (such as
1619228753Smm	 * security.capability on Linux) have to be restored last,
1620228753Smm	 * since they're implicitly removed by other file changes.
1621228753Smm	 */
1622228753Smm	if (a->todo & TODO_XATTR) {
1623228753Smm		int r2 = set_xattrs(a);
1624228753Smm		if (r2 < ret) ret = r2;
1625228753Smm	}
1626228753Smm
1627228753Smm	/*
1628228753Smm	 * Some flags prevent file modification; they must be restored after
1629228753Smm	 * file contents are written.
1630228753Smm	 */
1631228753Smm	if (a->todo & TODO_FFLAGS) {
1632228753Smm		int r2 = set_fflags(a);
1633228753Smm		if (r2 < ret) ret = r2;
1634228753Smm	}
1635231200Smm
1636228753Smm	/*
1637231200Smm	 * Time must follow most other metadata;
1638228753Smm	 * otherwise atime will get changed.
1639228753Smm	 */
1640228753Smm	if (a->todo & TODO_TIMES) {
1641231200Smm		int r2 = set_times_from_entry(a);
1642228753Smm		if (r2 < ret) ret = r2;
1643228753Smm	}
1644228753Smm
1645231200Smm	/*
1646231200Smm	 * Mac extended metadata includes ACLs.
1647231200Smm	 */
1648231200Smm	if (a->todo & TODO_MAC_METADATA) {
1649231200Smm		const void *metadata;
1650231200Smm		size_t metadata_size;
1651231200Smm		metadata = archive_entry_mac_metadata(a->entry, &metadata_size);
1652231200Smm		if (metadata != NULL && metadata_size > 0) {
1653248616Smm			int r2 = set_mac_metadata(a, archive_entry_pathname(
1654248616Smm			    a->entry), metadata, metadata_size);
1655231200Smm			if (r2 < ret) ret = r2;
1656231200Smm		}
1657231200Smm	}
1658231200Smm
1659231200Smm	/*
1660231200Smm	 * ACLs must be restored after timestamps because there are
1661231200Smm	 * ACLs that prevent attribute changes (including time).
1662231200Smm	 */
1663231200Smm	if (a->todo & TODO_ACLS) {
1664238909Smm		int r2 = archive_write_disk_set_acls(&a->archive, a->fd,
1665231200Smm				  archive_entry_pathname(a->entry),
1666231200Smm				  archive_entry_acl(a->entry));
1667231200Smm		if (r2 < ret) ret = r2;
1668231200Smm	}
1669231200Smm
1670248616Smmfinish_metadata:
1671228753Smm	/* If there's an fd, we can close it now. */
1672228753Smm	if (a->fd >= 0) {
1673228753Smm		close(a->fd);
1674228753Smm		a->fd = -1;
1675228753Smm	}
1676228753Smm	/* If there's an entry, we can release it now. */
1677228753Smm	if (a->entry) {
1678228753Smm		archive_entry_free(a->entry);
1679228753Smm		a->entry = NULL;
1680228753Smm	}
1681228753Smm	a->archive.state = ARCHIVE_STATE_HEADER;
1682228753Smm	return (ret);
1683228753Smm}
1684228753Smm
1685228753Smmint
1686228753Smmarchive_write_disk_set_group_lookup(struct archive *_a,
1687228753Smm    void *private_data,
1688231200Smm    int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid),
1689228753Smm    void (*cleanup_gid)(void *private))
1690228753Smm{
1691228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
1692231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
1693228753Smm	    ARCHIVE_STATE_ANY, "archive_write_disk_set_group_lookup");
1694228753Smm
1695231200Smm	if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL)
1696231200Smm		(a->cleanup_gid)(a->lookup_gid_data);
1697231200Smm
1698228753Smm	a->lookup_gid = lookup_gid;
1699228753Smm	a->cleanup_gid = cleanup_gid;
1700228753Smm	a->lookup_gid_data = private_data;
1701228753Smm	return (ARCHIVE_OK);
1702228753Smm}
1703228753Smm
1704228753Smmint
1705228753Smmarchive_write_disk_set_user_lookup(struct archive *_a,
1706228753Smm    void *private_data,
1707231200Smm    int64_t (*lookup_uid)(void *private, const char *uname, int64_t uid),
1708228753Smm    void (*cleanup_uid)(void *private))
1709228753Smm{
1710228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
1711231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
1712228753Smm	    ARCHIVE_STATE_ANY, "archive_write_disk_set_user_lookup");
1713228753Smm
1714231200Smm	if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL)
1715231200Smm		(a->cleanup_uid)(a->lookup_uid_data);
1716231200Smm
1717228753Smm	a->lookup_uid = lookup_uid;
1718228753Smm	a->cleanup_uid = cleanup_uid;
1719228753Smm	a->lookup_uid_data = private_data;
1720228753Smm	return (ARCHIVE_OK);
1721228753Smm}
1722228753Smm
1723231200Smmint64_t
1724231200Smmarchive_write_disk_gid(struct archive *_a, const char *name, int64_t id)
1725231200Smm{
1726231200Smm       struct archive_write_disk *a = (struct archive_write_disk *)_a;
1727231200Smm       archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
1728231200Smm           ARCHIVE_STATE_ANY, "archive_write_disk_gid");
1729231200Smm       if (a->lookup_gid)
1730231200Smm               return (a->lookup_gid)(a->lookup_gid_data, name, id);
1731231200Smm       return (id);
1732231200Smm}
1733231200Smm
1734231200Smmint64_t
1735231200Smmarchive_write_disk_uid(struct archive *_a, const char *name, int64_t id)
1736231200Smm{
1737238909Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
1738238909Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
1739238909Smm	    ARCHIVE_STATE_ANY, "archive_write_disk_uid");
1740238909Smm	if (a->lookup_uid)
1741238909Smm		return (a->lookup_uid)(a->lookup_uid_data, name, id);
1742238909Smm	return (id);
1743231200Smm}
1744228753Smm
1745228753Smm/*
1746228753Smm * Create a new archive_write_disk object and initialize it with global state.
1747228753Smm */
1748228753Smmstruct archive *
1749228753Smmarchive_write_disk_new(void)
1750228753Smm{
1751228753Smm	struct archive_write_disk *a;
1752228753Smm
1753228753Smm	a = (struct archive_write_disk *)malloc(sizeof(*a));
1754228753Smm	if (a == NULL)
1755228753Smm		return (NULL);
1756228753Smm	memset(a, 0, sizeof(*a));
1757228753Smm	a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC;
1758228753Smm	/* We're ready to write a header immediately. */
1759228753Smm	a->archive.state = ARCHIVE_STATE_HEADER;
1760228753Smm	a->archive.vtable = archive_write_disk_vtable();
1761228753Smm	a->start_time = time(NULL);
1762231200Smm	/* Query and restore the umask. */
1763231200Smm	umask(a->user_umask = umask(0));
1764228753Smm#ifdef HAVE_GETEUID
1765228753Smm	a->user_uid = geteuid();
1766228753Smm#endif /* HAVE_GETEUID */
1767228753Smm	if (archive_string_ensure(&a->path_safe, 512) == NULL) {
1768228753Smm		free(a);
1769228753Smm		return (NULL);
1770228753Smm	}
1771248616Smm#ifdef HAVE_ZLIB_H
1772248616Smm	a->decmpfs_compression_level = 5;
1773248616Smm#endif
1774228753Smm	return (&a->archive);
1775228753Smm}
1776228753Smm
1777228753Smm
1778228753Smm/*
1779228753Smm * If pathname is longer than PATH_MAX, chdir to a suitable
1780228753Smm * intermediate dir and edit the path down to a shorter suffix.  Note
1781228753Smm * that this routine never returns an error; if the chdir() attempt
1782228753Smm * fails for any reason, we just go ahead with the long pathname.  The
1783228753Smm * object creation is likely to fail, but any error will get handled
1784228753Smm * at that time.
1785228753Smm */
1786231200Smm#if defined(HAVE_FCHDIR) && defined(PATH_MAX)
1787228753Smmstatic void
1788228753Smmedit_deep_directories(struct archive_write_disk *a)
1789228753Smm{
1790228753Smm	int ret;
1791228753Smm	char *tail = a->name;
1792228753Smm
1793228753Smm	/* If path is short, avoid the open() below. */
1794228753Smm	if (strlen(tail) <= PATH_MAX)
1795228753Smm		return;
1796228753Smm
1797228753Smm	/* Try to record our starting dir. */
1798248616Smm	a->restore_pwd = open(".", O_RDONLY | O_BINARY | O_CLOEXEC);
1799248616Smm	__archive_ensure_cloexec_flag(a->restore_pwd);
1800228753Smm	if (a->restore_pwd < 0)
1801228753Smm		return;
1802228753Smm
1803228753Smm	/* As long as the path is too long... */
1804228753Smm	while (strlen(tail) > PATH_MAX) {
1805228753Smm		/* Locate a dir prefix shorter than PATH_MAX. */
1806228753Smm		tail += PATH_MAX - 8;
1807228753Smm		while (tail > a->name && *tail != '/')
1808228753Smm			tail--;
1809228753Smm		/* Exit if we find a too-long path component. */
1810228753Smm		if (tail <= a->name)
1811228753Smm			return;
1812228753Smm		/* Create the intermediate dir and chdir to it. */
1813228753Smm		*tail = '\0'; /* Terminate dir portion */
1814228753Smm		ret = create_dir(a, a->name);
1815228753Smm		if (ret == ARCHIVE_OK && chdir(a->name) != 0)
1816228753Smm			ret = ARCHIVE_FAILED;
1817228753Smm		*tail = '/'; /* Restore the / we removed. */
1818228753Smm		if (ret != ARCHIVE_OK)
1819228753Smm			return;
1820228753Smm		tail++;
1821228753Smm		/* The chdir() succeeded; we've now shortened the path. */
1822228753Smm		a->name = tail;
1823228753Smm	}
1824228753Smm	return;
1825228753Smm}
1826228753Smm#endif
1827228753Smm
1828228753Smm/*
1829228753Smm * The main restore function.
1830228753Smm */
1831228753Smmstatic int
1832228753Smmrestore_entry(struct archive_write_disk *a)
1833228753Smm{
1834228753Smm	int ret = ARCHIVE_OK, en;
1835228753Smm
1836228753Smm	if (a->flags & ARCHIVE_EXTRACT_UNLINK && !S_ISDIR(a->mode)) {
1837228753Smm		/*
1838228753Smm		 * TODO: Fix this.  Apparently, there are platforms
1839228753Smm		 * that still allow root to hose the entire filesystem
1840228753Smm		 * by unlinking a dir.  The S_ISDIR() test above
1841228753Smm		 * prevents us from using unlink() here if the new
1842228753Smm		 * object is a dir, but that doesn't mean the old
1843228753Smm		 * object isn't a dir.
1844228753Smm		 */
1845228753Smm		if (unlink(a->name) == 0) {
1846228753Smm			/* We removed it, reset cached stat. */
1847228753Smm			a->pst = NULL;
1848228753Smm		} else if (errno == ENOENT) {
1849228753Smm			/* File didn't exist, that's just as good. */
1850228753Smm		} else if (rmdir(a->name) == 0) {
1851228753Smm			/* It was a dir, but now it's gone. */
1852228753Smm			a->pst = NULL;
1853228753Smm		} else {
1854228753Smm			/* We tried, but couldn't get rid of it. */
1855228753Smm			archive_set_error(&a->archive, errno,
1856228753Smm			    "Could not unlink");
1857228753Smm			return(ARCHIVE_FAILED);
1858228753Smm		}
1859228753Smm	}
1860228753Smm
1861228753Smm	/* Try creating it first; if this fails, we'll try to recover. */
1862228753Smm	en = create_filesystem_object(a);
1863228753Smm
1864228753Smm	if ((en == ENOTDIR || en == ENOENT)
1865228753Smm	    && !(a->flags & ARCHIVE_EXTRACT_NO_AUTODIR)) {
1866228753Smm		/* If the parent dir doesn't exist, try creating it. */
1867228753Smm		create_parent_dir(a, a->name);
1868228753Smm		/* Now try to create the object again. */
1869228753Smm		en = create_filesystem_object(a);
1870228753Smm	}
1871228753Smm
1872228753Smm	if ((en == EISDIR || en == EEXIST)
1873228753Smm	    && (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
1874228753Smm		/* If we're not overwriting, we're done. */
1875231200Smm		archive_entry_unset_size(a->entry);
1876231200Smm		return (ARCHIVE_OK);
1877228753Smm	}
1878228753Smm
1879228753Smm	/*
1880228753Smm	 * Some platforms return EISDIR if you call
1881228753Smm	 * open(O_WRONLY | O_EXCL | O_CREAT) on a directory, some
1882228753Smm	 * return EEXIST.  POSIX is ambiguous, requiring EISDIR
1883228753Smm	 * for open(O_WRONLY) on a dir and EEXIST for open(O_EXCL | O_CREAT)
1884228753Smm	 * on an existing item.
1885228753Smm	 */
1886228753Smm	if (en == EISDIR) {
1887228753Smm		/* A dir is in the way of a non-dir, rmdir it. */
1888228753Smm		if (rmdir(a->name) != 0) {
1889228753Smm			archive_set_error(&a->archive, errno,
1890228753Smm			    "Can't remove already-existing dir");
1891228753Smm			return (ARCHIVE_FAILED);
1892228753Smm		}
1893228753Smm		a->pst = NULL;
1894228753Smm		/* Try again. */
1895228753Smm		en = create_filesystem_object(a);
1896228753Smm	} else if (en == EEXIST) {
1897228753Smm		/*
1898228753Smm		 * We know something is in the way, but we don't know what;
1899228753Smm		 * we need to find out before we go any further.
1900228753Smm		 */
1901228753Smm		int r = 0;
1902228753Smm		/*
1903231200Smm		 * The SECURE_SYMLINKS logic has already removed a
1904228753Smm		 * symlink to a dir if the client wants that.  So
1905228753Smm		 * follow the symlink if we're creating a dir.
1906228753Smm		 */
1907228753Smm		if (S_ISDIR(a->mode))
1908228753Smm			r = stat(a->name, &a->st);
1909228753Smm		/*
1910228753Smm		 * If it's not a dir (or it's a broken symlink),
1911228753Smm		 * then don't follow it.
1912228753Smm		 */
1913228753Smm		if (r != 0 || !S_ISDIR(a->mode))
1914228753Smm			r = lstat(a->name, &a->st);
1915228753Smm		if (r != 0) {
1916228753Smm			archive_set_error(&a->archive, errno,
1917228753Smm			    "Can't stat existing object");
1918228753Smm			return (ARCHIVE_FAILED);
1919228753Smm		}
1920228753Smm
1921228753Smm		/*
1922228753Smm		 * NO_OVERWRITE_NEWER doesn't apply to directories.
1923228753Smm		 */
1924228753Smm		if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER)
1925228753Smm		    &&  !S_ISDIR(a->st.st_mode)) {
1926228753Smm			if (!older(&(a->st), a->entry)) {
1927231200Smm				archive_entry_unset_size(a->entry);
1928231200Smm				return (ARCHIVE_OK);
1929228753Smm			}
1930228753Smm		}
1931228753Smm
1932228753Smm		/* If it's our archive, we're done. */
1933231200Smm		if (a->skip_file_set &&
1934238856Smm		    a->st.st_dev == (dev_t)a->skip_file_dev &&
1935238856Smm		    a->st.st_ino == (ino_t)a->skip_file_ino) {
1936238856Smm			archive_set_error(&a->archive, 0,
1937238856Smm			    "Refusing to overwrite archive");
1938228753Smm			return (ARCHIVE_FAILED);
1939228753Smm		}
1940228753Smm
1941228753Smm		if (!S_ISDIR(a->st.st_mode)) {
1942228753Smm			/* A non-dir is in the way, unlink it. */
1943228753Smm			if (unlink(a->name) != 0) {
1944228753Smm				archive_set_error(&a->archive, errno,
1945228753Smm				    "Can't unlink already-existing object");
1946228753Smm				return (ARCHIVE_FAILED);
1947228753Smm			}
1948228753Smm			a->pst = NULL;
1949228753Smm			/* Try again. */
1950228753Smm			en = create_filesystem_object(a);
1951228753Smm		} else if (!S_ISDIR(a->mode)) {
1952228753Smm			/* A dir is in the way of a non-dir, rmdir it. */
1953228753Smm			if (rmdir(a->name) != 0) {
1954228753Smm				archive_set_error(&a->archive, errno,
1955238856Smm				    "Can't replace existing directory with non-directory");
1956228753Smm				return (ARCHIVE_FAILED);
1957228753Smm			}
1958228753Smm			/* Try again. */
1959228753Smm			en = create_filesystem_object(a);
1960228753Smm		} else {
1961228753Smm			/*
1962228753Smm			 * There's a dir in the way of a dir.  Don't
1963228753Smm			 * waste time with rmdir()/mkdir(), just fix
1964228753Smm			 * up the permissions on the existing dir.
1965228753Smm			 * Note that we don't change perms on existing
1966228753Smm			 * dirs unless _EXTRACT_PERM is specified.
1967228753Smm			 */
1968228753Smm			if ((a->mode != a->st.st_mode)
1969228753Smm			    && (a->todo & TODO_MODE_FORCE))
1970228753Smm				a->deferred |= (a->todo & TODO_MODE);
1971228753Smm			/* Ownership doesn't need deferred fixup. */
1972228753Smm			en = 0; /* Forget the EEXIST. */
1973228753Smm		}
1974228753Smm	}
1975228753Smm
1976228753Smm	if (en) {
1977228753Smm		/* Everything failed; give up here. */
1978228753Smm		archive_set_error(&a->archive, en, "Can't create '%s'",
1979228753Smm		    a->name);
1980228753Smm		return (ARCHIVE_FAILED);
1981228753Smm	}
1982228753Smm
1983228753Smm	a->pst = NULL; /* Cached stat data no longer valid. */
1984228753Smm	return (ret);
1985228753Smm}
1986228753Smm
1987228753Smm/*
1988228753Smm * Returns 0 if creation succeeds, or else returns errno value from
1989228753Smm * the failed system call.   Note:  This function should only ever perform
1990228753Smm * a single system call.
1991228753Smm */
1992228753Smmstatic int
1993228753Smmcreate_filesystem_object(struct archive_write_disk *a)
1994228753Smm{
1995228753Smm	/* Create the entry. */
1996228753Smm	const char *linkname;
1997228753Smm	mode_t final_mode, mode;
1998228753Smm	int r;
1999228753Smm
2000228753Smm	/* We identify hard/symlinks according to the link names. */
2001228753Smm	/* Since link(2) and symlink(2) don't handle modes, we're done here. */
2002228753Smm	linkname = archive_entry_hardlink(a->entry);
2003228753Smm	if (linkname != NULL) {
2004228753Smm#if !HAVE_LINK
2005228753Smm		return (EPERM);
2006228753Smm#else
2007228753Smm		r = link(linkname, a->name) ? errno : 0;
2008228753Smm		/*
2009228753Smm		 * New cpio and pax formats allow hardlink entries
2010228753Smm		 * to carry data, so we may have to open the file
2011228753Smm		 * for hardlink entries.
2012228753Smm		 *
2013228753Smm		 * If the hardlink was successfully created and
2014228753Smm		 * the archive doesn't have carry data for it,
2015231200Smm		 * consider it to be non-authoritative for meta data.
2016228753Smm		 * This is consistent with GNU tar and BSD pax.
2017228753Smm		 * If the hardlink does carry data, let the last
2018228753Smm		 * archive entry decide ownership.
2019228753Smm		 */
2020228753Smm		if (r == 0 && a->filesize <= 0) {
2021228753Smm			a->todo = 0;
2022228753Smm			a->deferred = 0;
2023231200Smm		} else if (r == 0 && a->filesize > 0) {
2024248616Smm			a->fd = open(a->name,
2025248616Smm				     O_WRONLY | O_TRUNC | O_BINARY | O_CLOEXEC);
2026248616Smm			__archive_ensure_cloexec_flag(a->fd);
2027228753Smm			if (a->fd < 0)
2028228753Smm				r = errno;
2029228753Smm		}
2030228753Smm		return (r);
2031228753Smm#endif
2032228753Smm	}
2033228753Smm	linkname = archive_entry_symlink(a->entry);
2034228753Smm	if (linkname != NULL) {
2035228753Smm#if HAVE_SYMLINK
2036228753Smm		return symlink(linkname, a->name) ? errno : 0;
2037228753Smm#else
2038228753Smm		return (EPERM);
2039228753Smm#endif
2040228753Smm	}
2041228753Smm
2042228753Smm	/*
2043228753Smm	 * The remaining system calls all set permissions, so let's
2044228753Smm	 * try to take advantage of that to avoid an extra chmod()
2045228753Smm	 * call.  (Recall that umask is set to zero right now!)
2046228753Smm	 */
2047228753Smm
2048228753Smm	/* Mode we want for the final restored object (w/o file type bits). */
2049228753Smm	final_mode = a->mode & 07777;
2050228753Smm	/*
2051228753Smm	 * The mode that will actually be restored in this step.  Note
2052228753Smm	 * that SUID, SGID, etc, require additional work to ensure
2053228753Smm	 * security, so we never restore them at this point.
2054228753Smm	 */
2055248616Smm	mode = final_mode & 0777 & ~a->user_umask;
2056228753Smm
2057228753Smm	switch (a->mode & AE_IFMT) {
2058228753Smm	default:
2059228753Smm		/* POSIX requires that we fall through here. */
2060228753Smm		/* FALLTHROUGH */
2061228753Smm	case AE_IFREG:
2062228753Smm		a->fd = open(a->name,
2063248616Smm		    O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, mode);
2064248616Smm		__archive_ensure_cloexec_flag(a->fd);
2065228753Smm		r = (a->fd < 0);
2066228753Smm		break;
2067228753Smm	case AE_IFCHR:
2068228753Smm#ifdef HAVE_MKNOD
2069228753Smm		/* Note: we use AE_IFCHR for the case label, and
2070228753Smm		 * S_IFCHR for the mknod() call.  This is correct.  */
2071228753Smm		r = mknod(a->name, mode | S_IFCHR,
2072228753Smm		    archive_entry_rdev(a->entry));
2073228753Smm		break;
2074228753Smm#else
2075228753Smm		/* TODO: Find a better way to warn about our inability
2076228753Smm		 * to restore a char device node. */
2077228753Smm		return (EINVAL);
2078228753Smm#endif /* HAVE_MKNOD */
2079228753Smm	case AE_IFBLK:
2080228753Smm#ifdef HAVE_MKNOD
2081228753Smm		r = mknod(a->name, mode | S_IFBLK,
2082228753Smm		    archive_entry_rdev(a->entry));
2083228753Smm		break;
2084228753Smm#else
2085228753Smm		/* TODO: Find a better way to warn about our inability
2086228753Smm		 * to restore a block device node. */
2087228753Smm		return (EINVAL);
2088228753Smm#endif /* HAVE_MKNOD */
2089228753Smm	case AE_IFDIR:
2090228753Smm		mode = (mode | MINIMUM_DIR_MODE) & MAXIMUM_DIR_MODE;
2091228753Smm		r = mkdir(a->name, mode);
2092228753Smm		if (r == 0) {
2093228753Smm			/* Defer setting dir times. */
2094228753Smm			a->deferred |= (a->todo & TODO_TIMES);
2095228753Smm			a->todo &= ~TODO_TIMES;
2096228753Smm			/* Never use an immediate chmod(). */
2097228753Smm			/* We can't avoid the chmod() entirely if EXTRACT_PERM
2098228753Smm			 * because of SysV SGID inheritance. */
2099228753Smm			if ((mode != final_mode)
2100228753Smm			    || (a->flags & ARCHIVE_EXTRACT_PERM))
2101228753Smm				a->deferred |= (a->todo & TODO_MODE);
2102228753Smm			a->todo &= ~TODO_MODE;
2103228753Smm		}
2104228753Smm		break;
2105228753Smm	case AE_IFIFO:
2106228753Smm#ifdef HAVE_MKFIFO
2107228753Smm		r = mkfifo(a->name, mode);
2108228753Smm		break;
2109228753Smm#else
2110228753Smm		/* TODO: Find a better way to warn about our inability
2111228753Smm		 * to restore a fifo. */
2112228753Smm		return (EINVAL);
2113228753Smm#endif /* HAVE_MKFIFO */
2114228753Smm	}
2115228753Smm
2116228753Smm	/* All the system calls above set errno on failure. */
2117228753Smm	if (r)
2118228753Smm		return (errno);
2119228753Smm
2120228753Smm	/* If we managed to set the final mode, we've avoided a chmod(). */
2121228753Smm	if (mode == final_mode)
2122228753Smm		a->todo &= ~TODO_MODE;
2123228753Smm	return (0);
2124228753Smm}
2125228753Smm
2126228753Smm/*
2127228753Smm * Cleanup function for archive_extract.  Mostly, this involves processing
2128228753Smm * the fixup list, which is used to address a number of problems:
2129228753Smm *   * Dir permissions might prevent us from restoring a file in that
2130228753Smm *     dir, so we restore the dir with minimum 0700 permissions first,
2131228753Smm *     then correct the mode at the end.
2132228753Smm *   * Similarly, the act of restoring a file touches the directory
2133228753Smm *     and changes the timestamp on the dir, so we have to touch-up dir
2134228753Smm *     timestamps at the end as well.
2135228753Smm *   * Some file flags can interfere with the restore by, for example,
2136228753Smm *     preventing the creation of hardlinks to those files.
2137231200Smm *   * Mac OS extended metadata includes ACLs, so must be deferred on dirs.
2138228753Smm *
2139228753Smm * Note that tar/cpio do not require that archives be in a particular
2140228753Smm * order; there is no way to know when the last file has been restored
2141228753Smm * within a directory, so there's no way to optimize the memory usage
2142228753Smm * here by fixing up the directory any earlier than the
2143228753Smm * end-of-archive.
2144228753Smm *
2145228753Smm * XXX TODO: Directory ACLs should be restored here, for the same
2146228753Smm * reason we set directory perms here. XXX
2147228753Smm */
2148228753Smmstatic int
2149231200Smm_archive_write_disk_close(struct archive *_a)
2150228753Smm{
2151228753Smm	struct archive_write_disk *a = (struct archive_write_disk *)_a;
2152228753Smm	struct fixup_entry *next, *p;
2153228753Smm	int ret;
2154228753Smm
2155231200Smm	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
2156228753Smm	    ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
2157228753Smm	    "archive_write_disk_close");
2158231200Smm	ret = _archive_write_disk_finish_entry(&a->archive);
2159228753Smm
2160228753Smm	/* Sort dir list so directories are fixed up in depth-first order. */
2161228753Smm	p = sort_dir_list(a->fixup_list);
2162228753Smm
2163228753Smm	while (p != NULL) {
2164228753Smm		a->pst = NULL; /* Mark stat cache as out-of-date. */
2165228753Smm		if (p->fixup & TODO_TIMES) {
2166231200Smm			set_times(a, -1, p->mode, p->name,
2167231200Smm			    p->atime, p->atime_nanos,
2168231200Smm			    p->birthtime, p->birthtime_nanos,
2169231200Smm			    p->mtime, p->mtime_nanos,
2170231200Smm			    p->ctime, p->ctime_nanos);
2171228753Smm		}
2172228753Smm		if (p->fixup & TODO_MODE_BASE)
2173228753Smm			chmod(p->name, p->mode);
2174231200Smm		if (p->fixup & TODO_ACLS)
2175238909Smm			archive_write_disk_set_acls(&a->archive,
2176238909Smm						    -1, p->name, &p->acl);
2177228753Smm		if (p->fixup & TODO_FFLAGS)
2178228753Smm			set_fflags_platform(a, -1, p->name,
2179228753Smm			    p->mode, p->fflags_set, 0);
2180231200Smm		if (p->fixup & TODO_MAC_METADATA)
2181231200Smm			set_mac_metadata(a, p->name, p->mac_metadata,
2182231200Smm					 p->mac_metadata_size);
2183228753Smm		next = p->next;
2184231200Smm		archive_acl_clear(&p->acl);
2185231200Smm		free(p->mac_metadata);
2186228753Smm		free(p->name);
2187228753Smm		free(p);
2188228753Smm		p = next;
2189228753Smm	}
2190228753Smm	a->fixup_list = NULL;
2191228753Smm	return (ret);
2192228753Smm}
2193228753Smm
2194228753Smmstatic int
2195231200Smm_archive_write_disk_free(struct archive *_a)
2196228753Smm{
2197231200Smm	struct archive_write_disk *a;
2198228753Smm	int ret;
2199231200Smm	if (_a == NULL)
2200231200Smm		return (ARCHIVE_OK);
2201231200Smm	archive_check_magic(_a, ARCHIVE_WRITE_DISK_MAGIC,
2202231200Smm	    ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_write_disk_free");
2203231200Smm	a = (struct archive_write_disk *)_a;
2204231200Smm	ret = _archive_write_disk_close(&a->archive);
2205231200Smm	archive_write_disk_set_group_lookup(&a->archive, NULL, NULL, NULL);
2206231200Smm	archive_write_disk_set_user_lookup(&a->archive, NULL, NULL, NULL);
2207228753Smm	if (a->entry)
2208228753Smm		archive_entry_free(a->entry);
2209228753Smm	archive_string_free(&a->_name_data);
2210228753Smm	archive_string_free(&a->archive.error_string);
2211228753Smm	archive_string_free(&a->path_safe);
2212231200Smm	a->archive.magic = 0;
2213231200Smm	__archive_clean(&a->archive);
2214248616Smm	free(a->decmpfs_header_p);
2215248616Smm	free(a->resource_fork);
2216248616Smm	free(a->compressed_buffer);
2217248616Smm	free(a->uncompressed_buffer);
2218248616Smm#ifdef HAVE_ZLIB_H
2219248616Smm	if (a->stream_valid) {
2220248616Smm		switch (deflateEnd(&a->stream)) {
2221248616Smm		case Z_OK:
2222248616Smm			break;
2223248616Smm		default:
2224248616Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
2225248616Smm			    "Failed to clean up compressor");
2226248616Smm			ret = ARCHIVE_FATAL;
2227248616Smm			break;
2228248616Smm		}
2229248616Smm	}
2230248616Smm#endif
2231228753Smm	free(a);
2232228753Smm	return (ret);
2233228753Smm}
2234228753Smm
2235228753Smm/*
2236228753Smm * Simple O(n log n) merge sort to order the fixup list.  In
2237228753Smm * particular, we want to restore dir timestamps depth-first.
2238228753Smm */
2239228753Smmstatic struct fixup_entry *
2240228753Smmsort_dir_list(struct fixup_entry *p)
2241228753Smm{
2242228753Smm	struct fixup_entry *a, *b, *t;
2243228753Smm
2244228753Smm	if (p == NULL)
2245228753Smm		return (NULL);
2246228753Smm	/* A one-item list is already sorted. */
2247228753Smm	if (p->next == NULL)
2248228753Smm		return (p);
2249228753Smm
2250228753Smm	/* Step 1: split the list. */
2251228753Smm	t = p;
2252228753Smm	a = p->next->next;
2253228753Smm	while (a != NULL) {
2254228753Smm		/* Step a twice, t once. */
2255228753Smm		a = a->next;
2256228753Smm		if (a != NULL)
2257228753Smm			a = a->next;
2258228753Smm		t = t->next;
2259228753Smm	}
2260228753Smm	/* Now, t is at the mid-point, so break the list here. */
2261228753Smm	b = t->next;
2262228753Smm	t->next = NULL;
2263228753Smm	a = p;
2264228753Smm
2265228753Smm	/* Step 2: Recursively sort the two sub-lists. */
2266228753Smm	a = sort_dir_list(a);
2267228753Smm	b = sort_dir_list(b);
2268228753Smm
2269228753Smm	/* Step 3: Merge the returned lists. */
2270228753Smm	/* Pick the first element for the merged list. */
2271228753Smm	if (strcmp(a->name, b->name) > 0) {
2272228753Smm		t = p = a;
2273228753Smm		a = a->next;
2274228753Smm	} else {
2275228753Smm		t = p = b;
2276228753Smm		b = b->next;
2277228753Smm	}
2278228753Smm
2279228753Smm	/* Always put the later element on the list first. */
2280228753Smm	while (a != NULL && b != NULL) {
2281228753Smm		if (strcmp(a->name, b->name) > 0) {
2282228753Smm			t->next = a;
2283228753Smm			a = a->next;
2284228753Smm		} else {
2285228753Smm			t->next = b;
2286228753Smm			b = b->next;
2287228753Smm		}
2288228753Smm		t = t->next;
2289228753Smm	}
2290228753Smm
2291228753Smm	/* Only one list is non-empty, so just splice it on. */
2292228753Smm	if (a != NULL)
2293228753Smm		t->next = a;
2294228753Smm	if (b != NULL)
2295228753Smm		t->next = b;
2296228753Smm
2297228753Smm	return (p);
2298228753Smm}
2299228753Smm
2300228753Smm/*
2301228753Smm * Returns a new, initialized fixup entry.
2302228753Smm *
2303228753Smm * TODO: Reduce the memory requirements for this list by using a tree
2304228753Smm * structure rather than a simple list of names.
2305228753Smm */
2306228753Smmstatic struct fixup_entry *
2307228753Smmnew_fixup(struct archive_write_disk *a, const char *pathname)
2308228753Smm{
2309228753Smm	struct fixup_entry *fe;
2310228753Smm
2311231200Smm	fe = (struct fixup_entry *)calloc(1, sizeof(struct fixup_entry));
2312248616Smm	if (fe == NULL) {
2313248616Smm		archive_set_error(&a->archive, ENOMEM,
2314248616Smm		    "Can't allocate memory for a fixup");
2315228753Smm		return (NULL);
2316248616Smm	}
2317228753Smm	fe->next = a->fixup_list;
2318228753Smm	a->fixup_list = fe;
2319228753Smm	fe->fixup = 0;
2320228753Smm	fe->name = strdup(pathname);
2321228753Smm	return (fe);
2322228753Smm}
2323228753Smm
2324228753Smm/*
2325228753Smm * Returns a fixup structure for the current entry.
2326228753Smm */
2327228753Smmstatic struct fixup_entry *
2328228753Smmcurrent_fixup(struct archive_write_disk *a, const char *pathname)
2329228753Smm{
2330228753Smm	if (a->current_fixup == NULL)
2331228753Smm		a->current_fixup = new_fixup(a, pathname);
2332228753Smm	return (a->current_fixup);
2333228753Smm}
2334228753Smm
2335228753Smm/* TODO: Make this work. */
2336228753Smm/*
2337228753Smm * TODO: The deep-directory support bypasses this; disable deep directory
2338228753Smm * support if we're doing symlink checks.
2339228753Smm */
2340228753Smm/*
2341228753Smm * TODO: Someday, integrate this with the deep dir support; they both
2342228753Smm * scan the path and both can be optimized by comparing against other
2343228753Smm * recent paths.
2344228753Smm */
2345228753Smm/* TODO: Extend this to support symlinks on Windows Vista and later. */
2346228753Smmstatic int
2347228753Smmcheck_symlinks(struct archive_write_disk *a)
2348228753Smm{
2349228753Smm#if !defined(HAVE_LSTAT)
2350228753Smm	/* Platform doesn't have lstat, so we can't look for symlinks. */
2351228753Smm	(void)a; /* UNUSED */
2352228753Smm	return (ARCHIVE_OK);
2353228753Smm#else
2354231200Smm	char *pn;
2355228753Smm	char c;
2356228753Smm	int r;
2357228753Smm	struct stat st;
2358228753Smm
2359228753Smm	/*
2360228753Smm	 * Guard against symlink tricks.  Reject any archive entry whose
2361228753Smm	 * destination would be altered by a symlink.
2362228753Smm	 */
2363228753Smm	/* Whatever we checked last time doesn't need to be re-checked. */
2364228753Smm	pn = a->name;
2365231200Smm	if (archive_strlen(&(a->path_safe)) > 0) {
2366231200Smm		char *p = a->path_safe.s;
2367231200Smm		while ((*pn != '\0') && (*p == *pn))
2368231200Smm			++p, ++pn;
2369231200Smm	}
2370228753Smm	c = pn[0];
2371228753Smm	/* Keep going until we've checked the entire name. */
2372228753Smm	while (pn[0] != '\0' && (pn[0] != '/' || pn[1] != '\0')) {
2373228753Smm		/* Skip the next path element. */
2374228753Smm		while (*pn != '\0' && *pn != '/')
2375228753Smm			++pn;
2376228753Smm		c = pn[0];
2377228753Smm		pn[0] = '\0';
2378228753Smm		/* Check that we haven't hit a symlink. */
2379228753Smm		r = lstat(a->name, &st);
2380228753Smm		if (r != 0) {
2381228753Smm			/* We've hit a dir that doesn't exist; stop now. */
2382228753Smm			if (errno == ENOENT)
2383228753Smm				break;
2384228753Smm		} else if (S_ISLNK(st.st_mode)) {
2385228753Smm			if (c == '\0') {
2386228753Smm				/*
2387228753Smm				 * Last element is symlink; remove it
2388228753Smm				 * so we can overwrite it with the
2389228753Smm				 * item being extracted.
2390228753Smm				 */
2391228753Smm				if (unlink(a->name)) {
2392228753Smm					archive_set_error(&a->archive, errno,
2393228753Smm					    "Could not remove symlink %s",
2394228753Smm					    a->name);
2395228753Smm					pn[0] = c;
2396228753Smm					return (ARCHIVE_FAILED);
2397228753Smm				}
2398228753Smm				a->pst = NULL;
2399228753Smm				/*
2400228753Smm				 * Even if we did remove it, a warning
2401228753Smm				 * is in order.  The warning is silly,
2402228753Smm				 * though, if we're just replacing one
2403228753Smm				 * symlink with another symlink.
2404228753Smm				 */
2405228753Smm				if (!S_ISLNK(a->mode)) {
2406228753Smm					archive_set_error(&a->archive, 0,
2407228753Smm					    "Removing symlink %s",
2408228753Smm					    a->name);
2409228753Smm				}
2410228753Smm				/* Symlink gone.  No more problem! */
2411228753Smm				pn[0] = c;
2412228753Smm				return (0);
2413228753Smm			} else if (a->flags & ARCHIVE_EXTRACT_UNLINK) {
2414228753Smm				/* User asked us to remove problems. */
2415228753Smm				if (unlink(a->name) != 0) {
2416228753Smm					archive_set_error(&a->archive, 0,
2417228753Smm					    "Cannot remove intervening symlink %s",
2418228753Smm					    a->name);
2419228753Smm					pn[0] = c;
2420228753Smm					return (ARCHIVE_FAILED);
2421228753Smm				}
2422228753Smm				a->pst = NULL;
2423228753Smm			} else {
2424228753Smm				archive_set_error(&a->archive, 0,
2425228753Smm				    "Cannot extract through symlink %s",
2426228753Smm				    a->name);
2427228753Smm				pn[0] = c;
2428228753Smm				return (ARCHIVE_FAILED);
2429228753Smm			}
2430228753Smm		}
2431228753Smm	}
2432228753Smm	pn[0] = c;
2433228753Smm	/* We've checked and/or cleaned the whole path, so remember it. */
2434228753Smm	archive_strcpy(&a->path_safe, a->name);
2435228753Smm	return (ARCHIVE_OK);
2436228753Smm#endif
2437228753Smm}
2438228753Smm
2439231200Smm#if defined(__CYGWIN__)
2440228753Smm/*
2441228753Smm * 1. Convert a path separator from '\' to '/' .
2442231200Smm *    We shouldn't check multibyte character directly because some
2443228753Smm *    character-set have been using the '\' character for a part of
2444228753Smm *    its multibyte character code.
2445228753Smm * 2. Replace unusable characters in Windows with underscore('_').
2446228753Smm * See also : http://msdn.microsoft.com/en-us/library/aa365247.aspx
2447228753Smm */
2448231200Smmstatic void
2449228753Smmcleanup_pathname_win(struct archive_write_disk *a)
2450228753Smm{
2451228753Smm	wchar_t wc;
2452228753Smm	char *p;
2453228753Smm	size_t alen, l;
2454231200Smm	int mb, complete, utf8;
2455228753Smm
2456231200Smm	alen = 0;
2457231200Smm	mb = 0;
2458231200Smm	complete = 1;
2459231200Smm	utf8 = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)? 1: 0;
2460231200Smm	for (p = a->name; *p != '\0'; p++) {
2461231200Smm		++alen;
2462231200Smm		if (*p == '\\') {
2463231200Smm			/* If previous byte is smaller than 128,
2464231200Smm			 * this is not second byte of multibyte characters,
2465231200Smm			 * so we can replace '\' with '/'. */
2466231200Smm			if (utf8 || !mb)
2467231200Smm				*p = '/';
2468228753Smm			else
2469231200Smm				complete = 0;/* uncompleted. */
2470231200Smm		} else if (*(unsigned char *)p > 127)
2471231200Smm			mb = 1;
2472231200Smm		else
2473231200Smm			mb = 0;
2474231200Smm		/* Rewrite the path name if its next character is unusable. */
2475228753Smm		if (*p == ':' || *p == '*' || *p == '?' || *p == '"' ||
2476228753Smm		    *p == '<' || *p == '>' || *p == '|')
2477228753Smm			*p = '_';
2478228753Smm	}
2479231200Smm	if (complete)
2480231200Smm		return;
2481231200Smm
2482228753Smm	/*
2483231200Smm	 * Convert path separator in wide-character.
2484228753Smm	 */
2485228753Smm	p = a->name;
2486228753Smm	while (*p != '\0' && alen) {
2487228753Smm		l = mbtowc(&wc, p, alen);
2488232153Smm		if (l == (size_t)-1) {
2489228753Smm			while (*p != '\0') {
2490228753Smm				if (*p == '\\')
2491228753Smm					*p = '/';
2492228753Smm				++p;
2493228753Smm			}
2494228753Smm			break;
2495228753Smm		}
2496228753Smm		if (l == 1 && wc == L'\\')
2497228753Smm			*p = '/';
2498228753Smm		p += l;
2499228753Smm		alen -= l;
2500228753Smm	}
2501228753Smm}
2502228753Smm#endif
2503228753Smm
2504228753Smm/*
2505228753Smm * Canonicalize the pathname.  In particular, this strips duplicate
2506228753Smm * '/' characters, '.' elements, and trailing '/'.  It also raises an
2507228753Smm * error for an empty path, a trailing '..' or (if _SECURE_NODOTDOT is
2508228753Smm * set) any '..' in the path.
2509228753Smm */
2510228753Smmstatic int
2511228753Smmcleanup_pathname(struct archive_write_disk *a)
2512228753Smm{
2513228753Smm	char *dest, *src;
2514228753Smm	char separator = '\0';
2515228753Smm
2516228753Smm	dest = src = a->name;
2517228753Smm	if (*src == '\0') {
2518228753Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
2519228753Smm		    "Invalid empty pathname");
2520228753Smm		return (ARCHIVE_FAILED);
2521228753Smm	}
2522228753Smm
2523231200Smm#if defined(__CYGWIN__)
2524231200Smm	cleanup_pathname_win(a);
2525228753Smm#endif
2526228753Smm	/* Skip leading '/'. */
2527228753Smm	if (*src == '/')
2528228753Smm		separator = *src++;
2529228753Smm
2530228753Smm	/* Scan the pathname one element at a time. */
2531228753Smm	for (;;) {
2532228753Smm		/* src points to first char after '/' */
2533228753Smm		if (src[0] == '\0') {
2534228753Smm			break;
2535228753Smm		} else if (src[0] == '/') {
2536228753Smm			/* Found '//', ignore second one. */
2537228753Smm			src++;
2538228753Smm			continue;
2539228753Smm		} else if (src[0] == '.') {
2540228753Smm			if (src[1] == '\0') {
2541228753Smm				/* Ignore trailing '.' */
2542228753Smm				break;
2543228753Smm			} else if (src[1] == '/') {
2544228753Smm				/* Skip './'. */
2545228753Smm				src += 2;
2546228753Smm				continue;
2547228753Smm			} else if (src[1] == '.') {
2548228753Smm				if (src[2] == '/' || src[2] == '\0') {
2549228753Smm					/* Conditionally warn about '..' */
2550228753Smm					if (a->flags & ARCHIVE_EXTRACT_SECURE_NODOTDOT) {
2551228753Smm						archive_set_error(&a->archive,
2552228753Smm						    ARCHIVE_ERRNO_MISC,
2553228753Smm						    "Path contains '..'");
2554228753Smm						return (ARCHIVE_FAILED);
2555228753Smm					}
2556228753Smm				}
2557228753Smm				/*
2558228753Smm				 * Note: Under no circumstances do we
2559228753Smm				 * remove '..' elements.  In
2560228753Smm				 * particular, restoring
2561228753Smm				 * '/foo/../bar/' should create the
2562228753Smm				 * 'foo' dir as a side-effect.
2563228753Smm				 */
2564228753Smm			}
2565228753Smm		}
2566228753Smm
2567228753Smm		/* Copy current element, including leading '/'. */
2568228753Smm		if (separator)
2569228753Smm			*dest++ = '/';
2570228753Smm		while (*src != '\0' && *src != '/') {
2571228753Smm			*dest++ = *src++;
2572228753Smm		}
2573228753Smm
2574228753Smm		if (*src == '\0')
2575228753Smm			break;
2576228753Smm
2577228753Smm		/* Skip '/' separator. */
2578228753Smm		separator = *src++;
2579228753Smm	}
2580228753Smm	/*
2581228753Smm	 * We've just copied zero or more path elements, not including the
2582228753Smm	 * final '/'.
2583228753Smm	 */
2584228753Smm	if (dest == a->name) {
2585228753Smm		/*
2586228753Smm		 * Nothing got copied.  The path must have been something
2587228753Smm		 * like '.' or '/' or './' or '/././././/./'.
2588228753Smm		 */
2589228753Smm		if (separator)
2590228753Smm			*dest++ = '/';
2591228753Smm		else
2592228753Smm			*dest++ = '.';
2593228753Smm	}
2594228753Smm	/* Terminate the result. */
2595228753Smm	*dest = '\0';
2596228753Smm	return (ARCHIVE_OK);
2597228753Smm}
2598228753Smm
2599228753Smm/*
2600228753Smm * Create the parent directory of the specified path, assuming path
2601228753Smm * is already in mutable storage.
2602228753Smm */
2603228753Smmstatic int
2604228753Smmcreate_parent_dir(struct archive_write_disk *a, char *path)
2605228753Smm{
2606228753Smm	char *slash;
2607228753Smm	int r;
2608228753Smm
2609228753Smm	/* Remove tail element to obtain parent name. */
2610228753Smm	slash = strrchr(path, '/');
2611228753Smm	if (slash == NULL)
2612228753Smm		return (ARCHIVE_OK);
2613228753Smm	*slash = '\0';
2614228753Smm	r = create_dir(a, path);
2615228753Smm	*slash = '/';
2616228753Smm	return (r);
2617228753Smm}
2618228753Smm
2619228753Smm/*
2620228753Smm * Create the specified dir, recursing to create parents as necessary.
2621228753Smm *
2622228753Smm * Returns ARCHIVE_OK if the path exists when we're done here.
2623228753Smm * Otherwise, returns ARCHIVE_FAILED.
2624228753Smm * Assumes path is in mutable storage; path is unchanged on exit.
2625228753Smm */
2626228753Smmstatic int
2627228753Smmcreate_dir(struct archive_write_disk *a, char *path)
2628228753Smm{
2629228753Smm	struct stat st;
2630228753Smm	struct fixup_entry *le;
2631228753Smm	char *slash, *base;
2632228753Smm	mode_t mode_final, mode;
2633228753Smm	int r;
2634228753Smm
2635228753Smm	/* Check for special names and just skip them. */
2636228753Smm	slash = strrchr(path, '/');
2637228753Smm	if (slash == NULL)
2638228753Smm		base = path;
2639228753Smm	else
2640228753Smm		base = slash + 1;
2641228753Smm
2642228753Smm	if (base[0] == '\0' ||
2643228753Smm	    (base[0] == '.' && base[1] == '\0') ||
2644228753Smm	    (base[0] == '.' && base[1] == '.' && base[2] == '\0')) {
2645228753Smm		/* Don't bother trying to create null path, '.', or '..'. */
2646228753Smm		if (slash != NULL) {
2647228753Smm			*slash = '\0';
2648228753Smm			r = create_dir(a, path);
2649228753Smm			*slash = '/';
2650228753Smm			return (r);
2651228753Smm		}
2652228753Smm		return (ARCHIVE_OK);
2653228753Smm	}
2654228753Smm
2655228753Smm	/*
2656228753Smm	 * Yes, this should be stat() and not lstat().  Using lstat()
2657228753Smm	 * here loses the ability to extract through symlinks.  Also note
2658228753Smm	 * that this should not use the a->st cache.
2659228753Smm	 */
2660228753Smm	if (stat(path, &st) == 0) {
2661228753Smm		if (S_ISDIR(st.st_mode))
2662228753Smm			return (ARCHIVE_OK);
2663228753Smm		if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
2664228753Smm			archive_set_error(&a->archive, EEXIST,
2665228753Smm			    "Can't create directory '%s'", path);
2666228753Smm			return (ARCHIVE_FAILED);
2667228753Smm		}
2668228753Smm		if (unlink(path) != 0) {
2669228753Smm			archive_set_error(&a->archive, errno,
2670228753Smm			    "Can't create directory '%s': "
2671231200Smm			    "Conflicting file cannot be removed",
2672231200Smm			    path);
2673228753Smm			return (ARCHIVE_FAILED);
2674228753Smm		}
2675228753Smm	} else if (errno != ENOENT && errno != ENOTDIR) {
2676228753Smm		/* Stat failed? */
2677228753Smm		archive_set_error(&a->archive, errno, "Can't test directory '%s'", path);
2678228753Smm		return (ARCHIVE_FAILED);
2679228753Smm	} else if (slash != NULL) {
2680228753Smm		*slash = '\0';
2681228753Smm		r = create_dir(a, path);
2682228753Smm		*slash = '/';
2683228753Smm		if (r != ARCHIVE_OK)
2684228753Smm			return (r);
2685228753Smm	}
2686228753Smm
2687228753Smm	/*
2688228753Smm	 * Mode we want for the final restored directory.  Per POSIX,
2689228753Smm	 * implicitly-created dirs must be created obeying the umask.
2690228753Smm	 * There's no mention whether this is different for privileged
2691228753Smm	 * restores (which the rest of this code handles by pretending
2692228753Smm	 * umask=0).  I've chosen here to always obey the user's umask for
2693228753Smm	 * implicit dirs, even if _EXTRACT_PERM was specified.
2694228753Smm	 */
2695228753Smm	mode_final = DEFAULT_DIR_MODE & ~a->user_umask;
2696228753Smm	/* Mode we want on disk during the restore process. */
2697228753Smm	mode = mode_final;
2698228753Smm	mode |= MINIMUM_DIR_MODE;
2699228753Smm	mode &= MAXIMUM_DIR_MODE;
2700228753Smm	if (mkdir(path, mode) == 0) {
2701228753Smm		if (mode != mode_final) {
2702228753Smm			le = new_fixup(a, path);
2703248616Smm			if (le == NULL)
2704248616Smm				return (ARCHIVE_FATAL);
2705228753Smm			le->fixup |=TODO_MODE_BASE;
2706228753Smm			le->mode = mode_final;
2707228753Smm		}
2708228753Smm		return (ARCHIVE_OK);
2709228753Smm	}
2710228753Smm
2711228753Smm	/*
2712228753Smm	 * Without the following check, a/b/../b/c/d fails at the
2713228753Smm	 * second visit to 'b', so 'd' can't be created.  Note that we
2714228753Smm	 * don't add it to the fixup list here, as it's already been
2715228753Smm	 * added.
2716228753Smm	 */
2717228753Smm	if (stat(path, &st) == 0 && S_ISDIR(st.st_mode))
2718228753Smm		return (ARCHIVE_OK);
2719228753Smm
2720228753Smm	archive_set_error(&a->archive, errno, "Failed to create dir '%s'",
2721228753Smm	    path);
2722228753Smm	return (ARCHIVE_FAILED);
2723228753Smm}
2724228753Smm
2725228753Smm/*
2726228753Smm * Note: Although we can skip setting the user id if the desired user
2727228753Smm * id matches the current user, we cannot skip setting the group, as
2728228753Smm * many systems set the gid based on the containing directory.  So
2729228753Smm * we have to perform a chown syscall if we want to set the SGID
2730228753Smm * bit.  (The alternative is to stat() and then possibly chown(); it's
2731228753Smm * more efficient to skip the stat() and just always chown().)  Note
2732228753Smm * that a successful chown() here clears the TODO_SGID_CHECK bit, which
2733228753Smm * allows set_mode to skip the stat() check for the GID.
2734228753Smm */
2735228753Smmstatic int
2736228753Smmset_ownership(struct archive_write_disk *a)
2737228753Smm{
2738228753Smm#ifndef __CYGWIN__
2739228753Smm/* unfortunately, on win32 there is no 'root' user with uid 0,
2740228753Smm   so we just have to try the chown and see if it works */
2741228753Smm
2742228753Smm	/* If we know we can't change it, don't bother trying. */
2743228753Smm	if (a->user_uid != 0  &&  a->user_uid != a->uid) {
2744228753Smm		archive_set_error(&a->archive, errno,
2745231200Smm		    "Can't set UID=%jd", (intmax_t)a->uid);
2746228753Smm		return (ARCHIVE_WARN);
2747228753Smm	}
2748228753Smm#endif
2749228753Smm
2750228753Smm#ifdef HAVE_FCHOWN
2751228753Smm	/* If we have an fd, we can avoid a race. */
2752228753Smm	if (a->fd >= 0 && fchown(a->fd, a->uid, a->gid) == 0) {
2753228753Smm		/* We've set owner and know uid/gid are correct. */
2754228753Smm		a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK);
2755228753Smm		return (ARCHIVE_OK);
2756228753Smm	}
2757228753Smm#endif
2758228753Smm
2759228753Smm	/* We prefer lchown() but will use chown() if that's all we have. */
2760228753Smm	/* Of course, if we have neither, this will always fail. */
2761228753Smm#ifdef HAVE_LCHOWN
2762228753Smm	if (lchown(a->name, a->uid, a->gid) == 0) {
2763228753Smm		/* We've set owner and know uid/gid are correct. */
2764228753Smm		a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK);
2765228753Smm		return (ARCHIVE_OK);
2766228753Smm	}
2767228753Smm#elif HAVE_CHOWN
2768228753Smm	if (!S_ISLNK(a->mode) && chown(a->name, a->uid, a->gid) == 0) {
2769228753Smm		/* We've set owner and know uid/gid are correct. */
2770228753Smm		a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK);
2771228753Smm		return (ARCHIVE_OK);
2772228753Smm	}
2773228753Smm#endif
2774228753Smm
2775228753Smm	archive_set_error(&a->archive, errno,
2776231200Smm	    "Can't set user=%jd/group=%jd for %s",
2777231200Smm	    (intmax_t)a->uid, (intmax_t)a->gid, a->name);
2778228753Smm	return (ARCHIVE_WARN);
2779228753Smm}
2780228753Smm
2781231200Smm/*
2782231200Smm * Note: Returns 0 on success, non-zero on failure.
2783228753Smm */
2784228753Smmstatic int
2785228753Smmset_time(int fd, int mode, const char *name,
2786228753Smm    time_t atime, long atime_nsec,
2787228753Smm    time_t mtime, long mtime_nsec)
2788228753Smm{
2789231200Smm	/* Select the best implementation for this platform. */
2790231200Smm#if defined(HAVE_UTIMENSAT) && defined(HAVE_FUTIMENS)
2791231200Smm	/*
2792231200Smm	 * utimensat() and futimens() are defined in
2793231200Smm	 * POSIX.1-2008. They support ns resolution and setting times
2794231200Smm	 * on fds and symlinks.
2795231200Smm	 */
2796228753Smm	struct timespec ts[2];
2797232153Smm	(void)mode; /* UNUSED */
2798228753Smm	ts[0].tv_sec = atime;
2799228753Smm	ts[0].tv_nsec = atime_nsec;
2800228753Smm	ts[1].tv_sec = mtime;
2801228753Smm	ts[1].tv_nsec = mtime_nsec;
2802228753Smm	if (fd >= 0)
2803228753Smm		return futimens(fd, ts);
2804228753Smm	return utimensat(AT_FDCWD, name, ts, AT_SYMLINK_NOFOLLOW);
2805231200Smm
2806228753Smm#elif HAVE_UTIMES
2807231200Smm	/*
2808231200Smm	 * The utimes()-family functions support ��s-resolution and
2809231200Smm	 * setting times fds and symlinks.  utimes() is documented as
2810231200Smm	 * LEGACY by POSIX, futimes() and lutimes() are not described
2811231200Smm	 * in POSIX.
2812231200Smm	 */
2813228753Smm	struct timeval times[2];
2814228753Smm
2815228753Smm	times[0].tv_sec = atime;
2816228753Smm	times[0].tv_usec = atime_nsec / 1000;
2817228753Smm	times[1].tv_sec = mtime;
2818228753Smm	times[1].tv_usec = mtime_nsec / 1000;
2819228753Smm
2820228753Smm#ifdef HAVE_FUTIMES
2821228753Smm	if (fd >= 0)
2822228753Smm		return (futimes(fd, times));
2823228753Smm#else
2824228753Smm	(void)fd; /* UNUSED */
2825228753Smm#endif
2826228753Smm#ifdef HAVE_LUTIMES
2827228753Smm	(void)mode; /* UNUSED */
2828228753Smm	return (lutimes(name, times));
2829228753Smm#else
2830228753Smm	if (S_ISLNK(mode))
2831228753Smm		return (0);
2832228753Smm	return (utimes(name, times));
2833228753Smm#endif
2834231200Smm
2835228753Smm#elif defined(HAVE_UTIME)
2836231200Smm	/*
2837231200Smm	 * utime() is POSIX-standard but only supports 1s resolution and
2838231200Smm	 * does not support fds or symlinks.
2839231200Smm	 */
2840228753Smm	struct utimbuf times;
2841228753Smm	(void)fd; /* UNUSED */
2842228753Smm	(void)name; /* UNUSED */
2843228753Smm	(void)atime_nsec; /* UNUSED */
2844228753Smm	(void)mtime_nsec; /* UNUSED */
2845228753Smm	times.actime = atime;
2846228753Smm	times.modtime = mtime;
2847228753Smm	if (S_ISLNK(mode))
2848228753Smm		return (ARCHIVE_OK);
2849228753Smm	return (utime(name, &times));
2850231200Smm
2851231200Smm#else
2852231200Smm	/*
2853231200Smm	 * We don't know how to set the time on this platform.
2854231200Smm	 */
2855232153Smm	(void)fd; /* UNUSED */
2856232153Smm	(void)mode; /* UNUSED */
2857232153Smm	(void)name; /* UNUSED */
2858232153Smm	(void)atime_nsec; /* UNUSED */
2859232153Smm	(void)mtime_nsec; /* UNUSED */
2860231200Smm	return (ARCHIVE_WARN);
2861231200Smm#endif
2862228753Smm}
2863231200Smm
2864231200Smm#ifdef F_SETTIMES /* Tru64 */
2865228753Smmstatic int
2866231200Smmset_time_tru64(int fd, int mode, const char *name,
2867228753Smm    time_t atime, long atime_nsec,
2868231200Smm    time_t mtime, long mtime_nsec,
2869231200Smm    time_t ctime, long ctime_nsec)
2870228753Smm{
2871231200Smm	struct attr_timbuf tstamp;
2872231200Smm	struct timeval times[3];
2873231200Smm	times[0].tv_sec = atime;
2874231200Smm	times[0].tv_usec = atime_nsec / 1000;
2875231200Smm	times[1].tv_sec = mtime;
2876231200Smm	times[1].tv_usec = mtime_nsec / 1000;
2877231200Smm	times[2].tv_sec = ctime;
2878231200Smm	times[2].tv_usec = ctime_nsec / 1000;
2879231200Smm	tstamp.atime = times[0];
2880231200Smm	tstamp.mtime = times[1];
2881231200Smm	tstamp.ctime = times[2];
2882231200Smm	return (fcntl(fd,F_SETTIMES,&tstamp));
2883228753Smm}
2884231200Smm#endif /* Tru64 */
2885231200Smm
2886231200Smmstatic int
2887231200Smmset_times(struct archive_write_disk *a,
2888231200Smm    int fd, int mode, const char *name,
2889231200Smm    time_t atime, long atime_nanos,
2890231200Smm    time_t birthtime, long birthtime_nanos,
2891231200Smm    time_t mtime, long mtime_nanos,
2892232153Smm    time_t cctime, long ctime_nanos)
2893231200Smm{
2894231200Smm	/* Note: set_time doesn't use libarchive return conventions!
2895231200Smm	 * It uses syscall conventions.  So 0 here instead of ARCHIVE_OK. */
2896231200Smm	int r1 = 0, r2 = 0;
2897231200Smm
2898231200Smm#ifdef F_SETTIMES
2899231200Smm	 /*
2900231200Smm	 * on Tru64 try own fcntl first which can restore even the
2901231200Smm	 * ctime, fall back to default code path below if it fails
2902231200Smm	 * or if we are not running as root
2903231200Smm	 */
2904231200Smm	if (a->user_uid == 0 &&
2905231200Smm	    set_time_tru64(fd, mode, name,
2906231200Smm			   atime, atime_nanos, mtime,
2907232153Smm			   mtime_nanos, cctime, ctime_nanos) == 0) {
2908231200Smm		return (ARCHIVE_OK);
2909231200Smm	}
2910232153Smm#else /* Tru64 */
2911232153Smm	(void)cctime; /* UNUSED */
2912232153Smm	(void)ctime_nanos; /* UNUSED */
2913231200Smm#endif /* Tru64 */
2914231200Smm
2915231200Smm#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
2916231200Smm	/*
2917231200Smm	 * If you have struct stat.st_birthtime, we assume BSD
2918231200Smm	 * birthtime semantics, in which {f,l,}utimes() updates
2919231200Smm	 * birthtime to earliest mtime.  So we set the time twice,
2920231200Smm	 * first using the birthtime, then using the mtime.  If
2921231200Smm	 * birthtime == mtime, this isn't necessary, so we skip it.
2922231200Smm	 * If birthtime > mtime, then this won't work, so we skip it.
2923231200Smm	 */
2924231200Smm	if (birthtime < mtime
2925231200Smm	    || (birthtime == mtime && birthtime_nanos < mtime_nanos))
2926231200Smm		r1 = set_time(fd, mode, name,
2927231200Smm			      atime, atime_nanos,
2928231200Smm			      birthtime, birthtime_nanos);
2929232153Smm#else
2930232153Smm	(void)birthtime; /* UNUSED */
2931232153Smm	(void)birthtime_nanos; /* UNUSED */
2932228753Smm#endif
2933231200Smm	r2 = set_time(fd, mode, name,
2934231200Smm		      atime, atime_nanos,
2935231200Smm		      mtime, mtime_nanos);
2936231200Smm	if (r1 != 0 || r2 != 0) {
2937231200Smm		archive_set_error(&a->archive, errno,
2938231200Smm				  "Can't restore time");
2939231200Smm		return (ARCHIVE_WARN);
2940231200Smm	}
2941231200Smm	return (ARCHIVE_OK);
2942231200Smm}
2943228753Smm
2944228753Smmstatic int
2945231200Smmset_times_from_entry(struct archive_write_disk *a)
2946228753Smm{
2947232153Smm	time_t atime, birthtime, mtime, cctime;
2948231200Smm	long atime_nsec, birthtime_nsec, mtime_nsec, ctime_nsec;
2949228753Smm
2950231200Smm	/* Suitable defaults. */
2951232153Smm	atime = birthtime = mtime = cctime = a->start_time;
2952231200Smm	atime_nsec = birthtime_nsec = mtime_nsec = ctime_nsec = 0;
2953231200Smm
2954228753Smm	/* If no time was provided, we're done. */
2955228753Smm	if (!archive_entry_atime_is_set(a->entry)
2956228753Smm#if HAVE_STRUCT_STAT_ST_BIRTHTIME
2957228753Smm	    && !archive_entry_birthtime_is_set(a->entry)
2958228753Smm#endif
2959228753Smm	    && !archive_entry_mtime_is_set(a->entry))
2960228753Smm		return (ARCHIVE_OK);
2961228753Smm
2962228753Smm	if (archive_entry_atime_is_set(a->entry)) {
2963228753Smm		atime = archive_entry_atime(a->entry);
2964228753Smm		atime_nsec = archive_entry_atime_nsec(a->entry);
2965228753Smm	}
2966231200Smm	if (archive_entry_birthtime_is_set(a->entry)) {
2967231200Smm		birthtime = archive_entry_birthtime(a->entry);
2968231200Smm		birthtime_nsec = archive_entry_birthtime_nsec(a->entry);
2969231200Smm	}
2970228753Smm	if (archive_entry_mtime_is_set(a->entry)) {
2971228753Smm		mtime = archive_entry_mtime(a->entry);
2972228753Smm		mtime_nsec = archive_entry_mtime_nsec(a->entry);
2973228753Smm	}
2974231200Smm	if (archive_entry_ctime_is_set(a->entry)) {
2975232153Smm		cctime = archive_entry_ctime(a->entry);
2976231200Smm		ctime_nsec = archive_entry_ctime_nsec(a->entry);
2977228753Smm	}
2978228753Smm
2979231200Smm	return set_times(a, a->fd, a->mode, a->name,
2980231200Smm			 atime, atime_nsec,
2981231200Smm			 birthtime, birthtime_nsec,
2982231200Smm			 mtime, mtime_nsec,
2983232153Smm			 cctime, ctime_nsec);
2984228753Smm}
2985228753Smm
2986228753Smmstatic int
2987228753Smmset_mode(struct archive_write_disk *a, int mode)
2988228753Smm{
2989228753Smm	int r = ARCHIVE_OK;
2990228753Smm	mode &= 07777; /* Strip off file type bits. */
2991228753Smm
2992228753Smm	if (a->todo & TODO_SGID_CHECK) {
2993228753Smm		/*
2994228753Smm		 * If we don't know the GID is right, we must stat()
2995228753Smm		 * to verify it.  We can't just check the GID of this
2996228753Smm		 * process, since systems sometimes set GID from
2997228753Smm		 * the enclosing dir or based on ACLs.
2998228753Smm		 */
2999231200Smm		if ((r = lazy_stat(a)) != ARCHIVE_OK)
3000228753Smm			return (r);
3001228753Smm		if (a->pst->st_gid != a->gid) {
3002228753Smm			mode &= ~ S_ISGID;
3003228753Smm			if (a->flags & ARCHIVE_EXTRACT_OWNER) {
3004228753Smm				/*
3005228753Smm				 * This is only an error if you
3006228753Smm				 * requested owner restore.  If you
3007228753Smm				 * didn't, we'll try to restore
3008228753Smm				 * sgid/suid, but won't consider it a
3009228753Smm				 * problem if we can't.
3010228753Smm				 */
3011228753Smm				archive_set_error(&a->archive, -1,
3012228753Smm				    "Can't restore SGID bit");
3013228753Smm				r = ARCHIVE_WARN;
3014228753Smm			}
3015228753Smm		}
3016228753Smm		/* While we're here, double-check the UID. */
3017228753Smm		if (a->pst->st_uid != a->uid
3018228753Smm		    && (a->todo & TODO_SUID)) {
3019228753Smm			mode &= ~ S_ISUID;
3020228753Smm			if (a->flags & ARCHIVE_EXTRACT_OWNER) {
3021228753Smm				archive_set_error(&a->archive, -1,
3022228753Smm				    "Can't restore SUID bit");
3023228753Smm				r = ARCHIVE_WARN;
3024228753Smm			}
3025228753Smm		}
3026228753Smm		a->todo &= ~TODO_SGID_CHECK;
3027228753Smm		a->todo &= ~TODO_SUID_CHECK;
3028228753Smm	} else if (a->todo & TODO_SUID_CHECK) {
3029228753Smm		/*
3030228753Smm		 * If we don't know the UID is right, we can just check
3031228753Smm		 * the user, since all systems set the file UID from
3032228753Smm		 * the process UID.
3033228753Smm		 */
3034228753Smm		if (a->user_uid != a->uid) {
3035228753Smm			mode &= ~ S_ISUID;
3036228753Smm			if (a->flags & ARCHIVE_EXTRACT_OWNER) {
3037228753Smm				archive_set_error(&a->archive, -1,
3038228753Smm				    "Can't make file SUID");
3039228753Smm				r = ARCHIVE_WARN;
3040228753Smm			}
3041228753Smm		}
3042228753Smm		a->todo &= ~TODO_SUID_CHECK;
3043228753Smm	}
3044228753Smm
3045228753Smm	if (S_ISLNK(a->mode)) {
3046228753Smm#ifdef HAVE_LCHMOD
3047228753Smm		/*
3048228753Smm		 * If this is a symlink, use lchmod().  If the
3049228753Smm		 * platform doesn't support lchmod(), just skip it.  A
3050228753Smm		 * platform that doesn't provide a way to set
3051228753Smm		 * permissions on symlinks probably ignores
3052228753Smm		 * permissions on symlinks, so a failure here has no
3053228753Smm		 * impact.
3054228753Smm		 */
3055228753Smm		if (lchmod(a->name, mode) != 0) {
3056228753Smm			archive_set_error(&a->archive, errno,
3057228753Smm			    "Can't set permissions to 0%o", (int)mode);
3058228753Smm			r = ARCHIVE_WARN;
3059228753Smm		}
3060228753Smm#endif
3061228753Smm	} else if (!S_ISDIR(a->mode)) {
3062228753Smm		/*
3063228753Smm		 * If it's not a symlink and not a dir, then use
3064228753Smm		 * fchmod() or chmod(), depending on whether we have
3065228753Smm		 * an fd.  Dirs get their perms set during the
3066228753Smm		 * post-extract fixup, which is handled elsewhere.
3067228753Smm		 */
3068228753Smm#ifdef HAVE_FCHMOD
3069228753Smm		if (a->fd >= 0) {
3070228753Smm			if (fchmod(a->fd, mode) != 0) {
3071228753Smm				archive_set_error(&a->archive, errno,
3072228753Smm				    "Can't set permissions to 0%o", (int)mode);
3073228753Smm				r = ARCHIVE_WARN;
3074228753Smm			}
3075228753Smm		} else
3076228753Smm#endif
3077228753Smm			/* If this platform lacks fchmod(), then
3078228753Smm			 * we'll just use chmod(). */
3079228753Smm			if (chmod(a->name, mode) != 0) {
3080228753Smm				archive_set_error(&a->archive, errno,
3081228753Smm				    "Can't set permissions to 0%o", (int)mode);
3082228753Smm				r = ARCHIVE_WARN;
3083228753Smm			}
3084228753Smm	}
3085228753Smm	return (r);
3086228753Smm}
3087228753Smm
3088228753Smmstatic int
3089228753Smmset_fflags(struct archive_write_disk *a)
3090228753Smm{
3091228753Smm	struct fixup_entry *le;
3092228753Smm	unsigned long	set, clear;
3093228753Smm	int		r;
3094228753Smm	int		critical_flags;
3095228753Smm	mode_t		mode = archive_entry_mode(a->entry);
3096228753Smm
3097228753Smm	/*
3098228753Smm	 * Make 'critical_flags' hold all file flags that can't be
3099228753Smm	 * immediately restored.  For example, on BSD systems,
3100228753Smm	 * SF_IMMUTABLE prevents hardlinks from being created, so
3101228753Smm	 * should not be set until after any hardlinks are created.  To
3102228753Smm	 * preserve some semblance of portability, this uses #ifdef
3103228753Smm	 * extensively.  Ugly, but it works.
3104228753Smm	 *
3105228753Smm	 * Yes, Virginia, this does create a security race.  It's mitigated
3106228753Smm	 * somewhat by the practice of creating dirs 0700 until the extract
3107228753Smm	 * is done, but it would be nice if we could do more than that.
3108228753Smm	 * People restoring critical file systems should be wary of
3109228753Smm	 * other programs that might try to muck with files as they're
3110228753Smm	 * being restored.
3111228753Smm	 */
3112228753Smm	/* Hopefully, the compiler will optimize this mess into a constant. */
3113228753Smm	critical_flags = 0;
3114228753Smm#ifdef SF_IMMUTABLE
3115228753Smm	critical_flags |= SF_IMMUTABLE;
3116228753Smm#endif
3117228753Smm#ifdef UF_IMMUTABLE
3118228753Smm	critical_flags |= UF_IMMUTABLE;
3119228753Smm#endif
3120228753Smm#ifdef SF_APPEND
3121228753Smm	critical_flags |= SF_APPEND;
3122228753Smm#endif
3123228753Smm#ifdef UF_APPEND
3124228753Smm	critical_flags |= UF_APPEND;
3125228753Smm#endif
3126228753Smm#ifdef EXT2_APPEND_FL
3127228753Smm	critical_flags |= EXT2_APPEND_FL;
3128228753Smm#endif
3129228753Smm#ifdef EXT2_IMMUTABLE_FL
3130228753Smm	critical_flags |= EXT2_IMMUTABLE_FL;
3131228753Smm#endif
3132228753Smm
3133228753Smm	if (a->todo & TODO_FFLAGS) {
3134228753Smm		archive_entry_fflags(a->entry, &set, &clear);
3135228753Smm
3136228753Smm		/*
3137228753Smm		 * The first test encourages the compiler to eliminate
3138228753Smm		 * all of this if it's not necessary.
3139228753Smm		 */
3140228753Smm		if ((critical_flags != 0)  &&  (set & critical_flags)) {
3141228753Smm			le = current_fixup(a, a->name);
3142248616Smm			if (le == NULL)
3143248616Smm				return (ARCHIVE_FATAL);
3144228753Smm			le->fixup |= TODO_FFLAGS;
3145228753Smm			le->fflags_set = set;
3146228753Smm			/* Store the mode if it's not already there. */
3147228753Smm			if ((le->fixup & TODO_MODE) == 0)
3148228753Smm				le->mode = mode;
3149228753Smm		} else {
3150228753Smm			r = set_fflags_platform(a, a->fd,
3151228753Smm			    a->name, mode, set, clear);
3152228753Smm			if (r != ARCHIVE_OK)
3153228753Smm				return (r);
3154228753Smm		}
3155228753Smm	}
3156228753Smm	return (ARCHIVE_OK);
3157228753Smm}
3158228753Smm
3159228753Smm
3160228753Smm#if ( defined(HAVE_LCHFLAGS) || defined(HAVE_CHFLAGS) || defined(HAVE_FCHFLAGS) ) && defined(HAVE_STRUCT_STAT_ST_FLAGS)
3161228753Smm/*
3162228753Smm * BSD reads flags using stat() and sets them with one of {f,l,}chflags()
3163228753Smm */
3164228753Smmstatic int
3165228753Smmset_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
3166228753Smm    mode_t mode, unsigned long set, unsigned long clear)
3167228753Smm{
3168228753Smm	int r;
3169228753Smm
3170228753Smm	(void)mode; /* UNUSED */
3171228753Smm	if (set == 0  && clear == 0)
3172228753Smm		return (ARCHIVE_OK);
3173228753Smm
3174228753Smm	/*
3175228753Smm	 * XXX Is the stat here really necessary?  Or can I just use
3176228753Smm	 * the 'set' flags directly?  In particular, I'm not sure
3177228753Smm	 * about the correct approach if we're overwriting an existing
3178228753Smm	 * file that already has flags on it. XXX
3179228753Smm	 */
3180231200Smm	if ((r = lazy_stat(a)) != ARCHIVE_OK)
3181228753Smm		return (r);
3182228753Smm
3183228753Smm	a->st.st_flags &= ~clear;
3184228753Smm	a->st.st_flags |= set;
3185228753Smm#ifdef HAVE_FCHFLAGS
3186228753Smm	/* If platform has fchflags() and we were given an fd, use it. */
3187228753Smm	if (fd >= 0 && fchflags(fd, a->st.st_flags) == 0)
3188228753Smm		return (ARCHIVE_OK);
3189228753Smm#endif
3190228753Smm	/*
3191228753Smm	 * If we can't use the fd to set the flags, we'll use the
3192228753Smm	 * pathname to set flags.  We prefer lchflags() but will use
3193228753Smm	 * chflags() if we must.
3194228753Smm	 */
3195228753Smm#ifdef HAVE_LCHFLAGS
3196228753Smm	if (lchflags(name, a->st.st_flags) == 0)
3197228753Smm		return (ARCHIVE_OK);
3198228753Smm#elif defined(HAVE_CHFLAGS)
3199228753Smm	if (S_ISLNK(a->st.st_mode)) {
3200228753Smm		archive_set_error(&a->archive, errno,
3201228753Smm		    "Can't set file flags on symlink.");
3202228753Smm		return (ARCHIVE_WARN);
3203228753Smm	}
3204228753Smm	if (chflags(name, a->st.st_flags) == 0)
3205228753Smm		return (ARCHIVE_OK);
3206228753Smm#endif
3207228753Smm	archive_set_error(&a->archive, errno,
3208228753Smm	    "Failed to set file flags");
3209228753Smm	return (ARCHIVE_WARN);
3210228753Smm}
3211228753Smm
3212231200Smm#elif defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)
3213228753Smm/*
3214228753Smm * Linux uses ioctl() to read and write file flags.
3215228753Smm */
3216228753Smmstatic int
3217228753Smmset_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
3218228753Smm    mode_t mode, unsigned long set, unsigned long clear)
3219228753Smm{
3220228753Smm	int		 ret;
3221228753Smm	int		 myfd = fd;
3222248616Smm	int newflags, oldflags;
3223248616Smm	int sf_mask = 0;
3224228753Smm
3225228753Smm	if (set == 0  && clear == 0)
3226228753Smm		return (ARCHIVE_OK);
3227228753Smm	/* Only regular files and dirs can have flags. */
3228228753Smm	if (!S_ISREG(mode) && !S_ISDIR(mode))
3229228753Smm		return (ARCHIVE_OK);
3230228753Smm
3231228753Smm	/* If we weren't given an fd, open it ourselves. */
3232248616Smm	if (myfd < 0) {
3233248616Smm		myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY | O_CLOEXEC);
3234248616Smm		__archive_ensure_cloexec_flag(myfd);
3235248616Smm	}
3236228753Smm	if (myfd < 0)
3237228753Smm		return (ARCHIVE_OK);
3238228753Smm
3239228753Smm	/*
3240228753Smm	 * Linux has no define for the flags that are only settable by
3241228753Smm	 * the root user.  This code may seem a little complex, but
3242228753Smm	 * there seem to be some Linux systems that lack these
3243228753Smm	 * defines. (?)  The code below degrades reasonably gracefully
3244228753Smm	 * if sf_mask is incomplete.
3245228753Smm	 */
3246228753Smm#ifdef EXT2_IMMUTABLE_FL
3247228753Smm	sf_mask |= EXT2_IMMUTABLE_FL;
3248228753Smm#endif
3249228753Smm#ifdef EXT2_APPEND_FL
3250228753Smm	sf_mask |= EXT2_APPEND_FL;
3251228753Smm#endif
3252228753Smm	/*
3253228753Smm	 * XXX As above, this would be way simpler if we didn't have
3254228753Smm	 * to read the current flags from disk. XXX
3255228753Smm	 */
3256228753Smm	ret = ARCHIVE_OK;
3257231200Smm
3258231200Smm	/* Read the current file flags. */
3259231200Smm	if (ioctl(myfd, EXT2_IOC_GETFLAGS, &oldflags) < 0)
3260231200Smm		goto fail;
3261231200Smm
3262228753Smm	/* Try setting the flags as given. */
3263231200Smm	newflags = (oldflags & ~clear) | set;
3264231200Smm	if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0)
3265231200Smm		goto cleanup;
3266231200Smm	if (errno != EPERM)
3267231200Smm		goto fail;
3268231200Smm
3269228753Smm	/* If we couldn't set all the flags, try again with a subset. */
3270231200Smm	newflags &= ~sf_mask;
3271231200Smm	oldflags &= sf_mask;
3272231200Smm	newflags |= oldflags;
3273231200Smm	if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0)
3274231200Smm		goto cleanup;
3275231200Smm
3276228753Smm	/* We couldn't set the flags, so report the failure. */
3277228753Smmfail:
3278228753Smm	archive_set_error(&a->archive, errno,
3279228753Smm	    "Failed to set file flags");
3280228753Smm	ret = ARCHIVE_WARN;
3281228753Smmcleanup:
3282228753Smm	if (fd < 0)
3283228753Smm		close(myfd);
3284228753Smm	return (ret);
3285228753Smm}
3286228753Smm
3287228753Smm#else
3288228753Smm
3289228753Smm/*
3290228753Smm * Of course, some systems have neither BSD chflags() nor Linux' flags
3291228753Smm * support through ioctl().
3292228753Smm */
3293228753Smmstatic int
3294228753Smmset_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
3295228753Smm    mode_t mode, unsigned long set, unsigned long clear)
3296228753Smm{
3297228753Smm	(void)a; /* UNUSED */
3298228753Smm	(void)fd; /* UNUSED */
3299228753Smm	(void)name; /* UNUSED */
3300228753Smm	(void)mode; /* UNUSED */
3301228753Smm	(void)set; /* UNUSED */
3302228753Smm	(void)clear; /* UNUSED */
3303228753Smm	return (ARCHIVE_OK);
3304228753Smm}
3305228753Smm
3306228753Smm#endif /* __linux */
3307228753Smm
3308231200Smm#ifndef HAVE_COPYFILE_H
3309231200Smm/* Default is to simply drop Mac extended metadata. */
3310231200Smmstatic int
3311231200Smmset_mac_metadata(struct archive_write_disk *a, const char *pathname,
3312231200Smm		 const void *metadata, size_t metadata_size)
3313231200Smm{
3314231200Smm	(void)a; /* UNUSED */
3315231200Smm	(void)pathname; /* UNUSED */
3316231200Smm	(void)metadata; /* UNUSED */
3317231200Smm	(void)metadata_size; /* UNUSED */
3318231200Smm	return (ARCHIVE_OK);
3319231200Smm}
3320248616Smm
3321248616Smmstatic int
3322248616Smmfixup_appledouble(struct archive_write_disk *a, const char *pathname)
3323248616Smm{
3324248616Smm	(void)a; /* UNUSED */
3325248616Smm	(void)pathname; /* UNUSED */
3326248616Smm	return (ARCHIVE_OK);
3327248616Smm}
3328231200Smm#else
3329231200Smm
3330231200Smm/*
3331231200Smm * On Mac OS, we use copyfile() to unpack the metadata and
3332231200Smm * apply it to the target file.
3333231200Smm */
3334248616Smm
3335248616Smm#if defined(HAVE_SYS_XATTR_H)
3336231200Smmstatic int
3337248616Smmcopy_xattrs(struct archive_write_disk *a, int tmpfd, int dffd)
3338248616Smm{
3339248616Smm	ssize_t xattr_size;
3340248616Smm	char *xattr_names = NULL, *xattr_val = NULL;
3341248616Smm	int ret = ARCHIVE_OK, xattr_i;
3342248616Smm
3343248616Smm	xattr_size = flistxattr(tmpfd, NULL, 0, 0);
3344248616Smm	if (xattr_size == -1) {
3345248616Smm		archive_set_error(&a->archive, errno,
3346248616Smm		    "Failed to read metadata(xattr)");
3347248616Smm		ret = ARCHIVE_WARN;
3348248616Smm		goto exit_xattr;
3349248616Smm	}
3350248616Smm	xattr_names = malloc(xattr_size);
3351248616Smm	if (xattr_names == NULL) {
3352248616Smm		archive_set_error(&a->archive, ENOMEM,
3353248616Smm		    "Can't allocate memory for metadata(xattr)");
3354248616Smm		ret = ARCHIVE_FATAL;
3355248616Smm		goto exit_xattr;
3356248616Smm	}
3357248616Smm	xattr_size = flistxattr(tmpfd, xattr_names, xattr_size, 0);
3358248616Smm	if (xattr_size == -1) {
3359248616Smm		archive_set_error(&a->archive, errno,
3360248616Smm		    "Failed to read metadata(xattr)");
3361248616Smm		ret = ARCHIVE_WARN;
3362248616Smm		goto exit_xattr;
3363248616Smm	}
3364248616Smm	for (xattr_i = 0; xattr_i < xattr_size;
3365248616Smm	    xattr_i += strlen(xattr_names + xattr_i) + 1) {
3366248616Smm		ssize_t s;
3367248616Smm		int f;
3368248616Smm
3369248616Smm		s = fgetxattr(tmpfd, xattr_names + xattr_i, NULL, 0, 0, 0);
3370248616Smm		if (s == -1) {
3371248616Smm			archive_set_error(&a->archive, errno,
3372248616Smm			    "Failed to get metadata(xattr)");
3373248616Smm			ret = ARCHIVE_WARN;
3374248616Smm			goto exit_xattr;
3375248616Smm		}
3376248616Smm		xattr_val = realloc(xattr_val, s);
3377248616Smm		if (xattr_val == NULL) {
3378248616Smm			archive_set_error(&a->archive, ENOMEM,
3379248616Smm			    "Failed to get metadata(xattr)");
3380248616Smm			ret = ARCHIVE_WARN;
3381248616Smm			goto exit_xattr;
3382248616Smm		}
3383248616Smm		s = fgetxattr(tmpfd, xattr_names + xattr_i, xattr_val, s, 0, 0);
3384248616Smm		if (s == -1) {
3385248616Smm			archive_set_error(&a->archive, errno,
3386248616Smm			    "Failed to get metadata(xattr)");
3387248616Smm			ret = ARCHIVE_WARN;
3388248616Smm			goto exit_xattr;
3389248616Smm		}
3390248616Smm		f = fsetxattr(dffd, xattr_names + xattr_i, xattr_val, s, 0, 0);
3391248616Smm		if (f == -1) {
3392248616Smm			archive_set_error(&a->archive, errno,
3393248616Smm			    "Failed to get metadata(xattr)");
3394248616Smm			ret = ARCHIVE_WARN;
3395248616Smm			goto exit_xattr;
3396248616Smm		}
3397248616Smm	}
3398248616Smmexit_xattr:
3399248616Smm	free(xattr_names);
3400248616Smm	free(xattr_val);
3401248616Smm	return (ret);
3402248616Smm}
3403248616Smm#endif
3404248616Smm
3405248616Smmstatic int
3406248616Smmcopy_acls(struct archive_write_disk *a, int tmpfd, int dffd)
3407248616Smm{
3408248616Smm	acl_t acl, dfacl = NULL;
3409248616Smm	int acl_r, ret = ARCHIVE_OK;
3410248616Smm
3411248616Smm	acl = acl_get_fd(tmpfd);
3412248616Smm	if (acl == NULL) {
3413248616Smm		if (errno == ENOENT)
3414248616Smm			/* There are not any ACLs. */
3415248616Smm			return (ret);
3416248616Smm		archive_set_error(&a->archive, errno,
3417248616Smm		    "Failed to get metadata(acl)");
3418248616Smm		ret = ARCHIVE_WARN;
3419248616Smm		goto exit_acl;
3420248616Smm	}
3421248616Smm	dfacl = acl_dup(acl);
3422248616Smm	acl_r = acl_set_fd(dffd, dfacl);
3423248616Smm	if (acl_r == -1) {
3424248616Smm		archive_set_error(&a->archive, errno,
3425248616Smm		    "Failed to get metadata(acl)");
3426248616Smm		ret = ARCHIVE_WARN;
3427248616Smm		goto exit_acl;
3428248616Smm	}
3429248616Smmexit_acl:
3430248616Smm	if (acl)
3431248616Smm		acl_free(acl);
3432248616Smm	if (dfacl)
3433248616Smm		acl_free(dfacl);
3434248616Smm	return (ret);
3435248616Smm}
3436248616Smm
3437248616Smmstatic int
3438248616Smmcreate_tempdatafork(struct archive_write_disk *a, const char *pathname)
3439248616Smm{
3440248616Smm	struct archive_string tmpdatafork;
3441248616Smm	int tmpfd;
3442248616Smm
3443248616Smm	archive_string_init(&tmpdatafork);
3444248616Smm	archive_strcpy(&tmpdatafork, "tar.md.XXXXXX");
3445248616Smm	tmpfd = mkstemp(tmpdatafork.s);
3446248616Smm	if (tmpfd < 0) {
3447248616Smm		archive_set_error(&a->archive, errno,
3448248616Smm		    "Failed to mkstemp");
3449248616Smm		archive_string_free(&tmpdatafork);
3450248616Smm		return (-1);
3451248616Smm	}
3452248616Smm	if (copyfile(pathname, tmpdatafork.s, 0,
3453248616Smm	    COPYFILE_UNPACK | COPYFILE_NOFOLLOW
3454248616Smm	    | COPYFILE_ACL | COPYFILE_XATTR) < 0) {
3455248616Smm		archive_set_error(&a->archive, errno,
3456248616Smm		    "Failed to restore metadata");
3457248616Smm		close(tmpfd);
3458248616Smm		tmpfd = -1;
3459248616Smm	}
3460248616Smm	unlink(tmpdatafork.s);
3461248616Smm	archive_string_free(&tmpdatafork);
3462248616Smm	return (tmpfd);
3463248616Smm}
3464248616Smm
3465248616Smmstatic int
3466248616Smmcopy_metadata(struct archive_write_disk *a, const char *metadata,
3467248616Smm    const char *datafork, int datafork_compressed)
3468248616Smm{
3469248616Smm	int ret = ARCHIVE_OK;
3470248616Smm
3471248616Smm	if (datafork_compressed) {
3472248616Smm		int dffd, tmpfd;
3473248616Smm
3474248616Smm		tmpfd = create_tempdatafork(a, metadata);
3475248616Smm		if (tmpfd == -1)
3476248616Smm			return (ARCHIVE_WARN);
3477248616Smm
3478248616Smm		/*
3479248616Smm		 * Do not open the data fork compressed by HFS+ compression
3480248616Smm		 * with at least a writing mode(O_RDWR or O_WRONLY). it
3481248616Smm		 * makes the data fork uncompressed.
3482248616Smm		 */
3483248616Smm		dffd = open(datafork, 0);
3484248616Smm		if (dffd == -1) {
3485248616Smm			archive_set_error(&a->archive, errno,
3486248616Smm			    "Failed to open the data fork for metadata");
3487248616Smm			close(tmpfd);
3488248616Smm			return (ARCHIVE_WARN);
3489248616Smm		}
3490248616Smm
3491248616Smm#if defined(HAVE_SYS_XATTR_H)
3492248616Smm		ret = copy_xattrs(a, tmpfd, dffd);
3493248616Smm		if (ret == ARCHIVE_OK)
3494248616Smm#endif
3495248616Smm			ret = copy_acls(a, tmpfd, dffd);
3496248616Smm		close(tmpfd);
3497248616Smm		close(dffd);
3498248616Smm	} else {
3499248616Smm		if (copyfile(metadata, datafork, 0,
3500248616Smm		    COPYFILE_UNPACK | COPYFILE_NOFOLLOW
3501248616Smm		    | COPYFILE_ACL | COPYFILE_XATTR) < 0) {
3502248616Smm			archive_set_error(&a->archive, errno,
3503248616Smm			    "Failed to restore metadata");
3504248616Smm			ret = ARCHIVE_WARN;
3505248616Smm		}
3506248616Smm	}
3507248616Smm	return (ret);
3508248616Smm}
3509248616Smm
3510248616Smmstatic int
3511231200Smmset_mac_metadata(struct archive_write_disk *a, const char *pathname,
3512231200Smm		 const void *metadata, size_t metadata_size)
3513231200Smm{
3514231200Smm	struct archive_string tmp;
3515231200Smm	ssize_t written;
3516231200Smm	int fd;
3517231200Smm	int ret = ARCHIVE_OK;
3518231200Smm
3519231200Smm	/* This would be simpler if copyfile() could just accept the
3520231200Smm	 * metadata as a block of memory; then we could sidestep this
3521231200Smm	 * silly dance of writing the data to disk just so that
3522231200Smm	 * copyfile() can read it back in again. */
3523231200Smm	archive_string_init(&tmp);
3524231200Smm	archive_strcpy(&tmp, pathname);
3525231200Smm	archive_strcat(&tmp, ".XXXXXX");
3526231200Smm	fd = mkstemp(tmp.s);
3527231200Smm
3528231200Smm	if (fd < 0) {
3529231200Smm		archive_set_error(&a->archive, errno,
3530231200Smm				  "Failed to restore metadata");
3531248616Smm		archive_string_free(&tmp);
3532231200Smm		return (ARCHIVE_WARN);
3533231200Smm	}
3534231200Smm	written = write(fd, metadata, metadata_size);
3535231200Smm	close(fd);
3536248616Smm	if ((size_t)written != metadata_size) {
3537231200Smm		archive_set_error(&a->archive, errno,
3538231200Smm				  "Failed to restore metadata");
3539231200Smm		ret = ARCHIVE_WARN;
3540248616Smm	} else {
3541248616Smm		int compressed;
3542248616Smm
3543248616Smm#if defined(UF_COMPRESSED)
3544248616Smm		if ((a->todo & TODO_HFS_COMPRESSION) != 0 &&
3545248616Smm		    (ret = lazy_stat(a)) == ARCHIVE_OK)
3546248616Smm			compressed = a->st.st_flags & UF_COMPRESSED;
3547248616Smm		else
3548248616Smm#endif
3549248616Smm			compressed = 0;
3550248616Smm		ret = copy_metadata(a, tmp.s, pathname, compressed);
3551231200Smm	}
3552231200Smm	unlink(tmp.s);
3553248616Smm	archive_string_free(&tmp);
3554231200Smm	return (ret);
3555231200Smm}
3556248616Smm
3557248616Smmstatic int
3558248616Smmfixup_appledouble(struct archive_write_disk *a, const char *pathname)
3559248616Smm{
3560248616Smm	char buff[8];
3561248616Smm	struct stat st;
3562248616Smm	const char *p;
3563248616Smm	struct archive_string datafork;
3564248616Smm	int fd = -1, ret = ARCHIVE_OK;
3565248616Smm
3566248616Smm	archive_string_init(&datafork);
3567248616Smm	/* Check if the current file name is a type of the resource
3568248616Smm	 * fork file. */
3569248616Smm	p = strrchr(pathname, '/');
3570248616Smm	if (p == NULL)
3571248616Smm		p = pathname;
3572248616Smm	else
3573248616Smm		p++;
3574248616Smm	if (p[0] != '.' || p[1] != '_')
3575248616Smm		goto skip_appledouble;
3576248616Smm
3577248616Smm	/*
3578248616Smm	 * Check if the data fork file exists.
3579248616Smm	 *
3580248616Smm	 * TODO: Check if this write disk object has handled it.
3581248616Smm	 */
3582248616Smm	archive_strncpy(&datafork, pathname, p - pathname);
3583248616Smm	archive_strcat(&datafork, p + 2);
3584248616Smm	if (lstat(datafork.s, &st) == -1 ||
3585248616Smm	    (st.st_mode & AE_IFMT) != AE_IFREG)
3586248616Smm		goto skip_appledouble;
3587248616Smm
3588248616Smm	/*
3589248616Smm	 * Check if the file is in the AppleDouble form.
3590248616Smm	 */
3591248616Smm	fd = open(pathname, O_RDONLY | O_BINARY | O_CLOEXEC);
3592248616Smm	__archive_ensure_cloexec_flag(fd);
3593248616Smm	if (fd == -1) {
3594248616Smm		archive_set_error(&a->archive, errno,
3595248616Smm		    "Failed to open a restoring file");
3596248616Smm		ret = ARCHIVE_WARN;
3597248616Smm		goto skip_appledouble;
3598248616Smm	}
3599248616Smm	if (read(fd, buff, 8) == -1) {
3600248616Smm		archive_set_error(&a->archive, errno,
3601248616Smm		    "Failed to read a restoring file");
3602248616Smm		close(fd);
3603248616Smm		ret = ARCHIVE_WARN;
3604248616Smm		goto skip_appledouble;
3605248616Smm	}
3606248616Smm	close(fd);
3607248616Smm	/* Check AppleDouble Magic Code. */
3608248616Smm	if (archive_be32dec(buff) != 0x00051607)
3609248616Smm		goto skip_appledouble;
3610248616Smm	/* Check AppleDouble Version. */
3611248616Smm	if (archive_be32dec(buff+4) != 0x00020000)
3612248616Smm		goto skip_appledouble;
3613248616Smm
3614248616Smm	ret = copy_metadata(a, pathname, datafork.s,
3615248616Smm#if defined(UF_COMPRESSED)
3616248616Smm	    st.st_flags & UF_COMPRESSED);
3617248616Smm#else
3618248616Smm	    0);
3619231200Smm#endif
3620248616Smm	if (ret == ARCHIVE_OK) {
3621248616Smm		unlink(pathname);
3622248616Smm		ret = ARCHIVE_EOF;
3623248616Smm	}
3624248616Smmskip_appledouble:
3625248616Smm	archive_string_free(&datafork);
3626248616Smm	return (ret);
3627248616Smm}
3628248616Smm#endif
3629231200Smm
3630231200Smm#if HAVE_LSETXATTR || HAVE_LSETEA
3631228753Smm/*
3632231200Smm * Restore extended attributes -  Linux and AIX implementations:
3633231200Smm * AIX' ea interface is syntaxwise identical to the Linux xattr interface.
3634228753Smm */
3635228753Smmstatic int
3636228753Smmset_xattrs(struct archive_write_disk *a)
3637228753Smm{
3638228753Smm	struct archive_entry *entry = a->entry;
3639228753Smm	static int warning_done = 0;
3640228753Smm	int ret = ARCHIVE_OK;
3641228753Smm	int i = archive_entry_xattr_reset(entry);
3642228753Smm
3643228753Smm	while (i--) {
3644228753Smm		const char *name;
3645228753Smm		const void *value;
3646228753Smm		size_t size;
3647228753Smm		archive_entry_xattr_next(entry, &name, &value, &size);
3648228753Smm		if (name != NULL &&
3649228753Smm				strncmp(name, "xfsroot.", 8) != 0 &&
3650228753Smm				strncmp(name, "system.", 7) != 0) {
3651228753Smm			int e;
3652228753Smm#if HAVE_FSETXATTR
3653228753Smm			if (a->fd >= 0)
3654228753Smm				e = fsetxattr(a->fd, name, value, size, 0);
3655228753Smm			else
3656231200Smm#elif HAVE_FSETEA
3657231200Smm			if (a->fd >= 0)
3658231200Smm				e = fsetea(a->fd, name, value, size, 0);
3659231200Smm			else
3660228753Smm#endif
3661228753Smm			{
3662231200Smm#if HAVE_LSETXATTR
3663228753Smm				e = lsetxattr(archive_entry_pathname(entry),
3664228753Smm				    name, value, size, 0);
3665231200Smm#elif HAVE_LSETEA
3666231200Smm				e = lsetea(archive_entry_pathname(entry),
3667231200Smm				    name, value, size, 0);
3668231200Smm#endif
3669228753Smm			}
3670228753Smm			if (e == -1) {
3671231200Smm				if (errno == ENOTSUP || errno == ENOSYS) {
3672228753Smm					if (!warning_done) {
3673228753Smm						warning_done = 1;
3674228753Smm						archive_set_error(&a->archive, errno,
3675228753Smm						    "Cannot restore extended "
3676228753Smm						    "attributes on this file "
3677228753Smm						    "system");
3678228753Smm					}
3679228753Smm				} else
3680228753Smm					archive_set_error(&a->archive, errno,
3681228753Smm					    "Failed to set extended attribute");
3682228753Smm				ret = ARCHIVE_WARN;
3683228753Smm			}
3684228753Smm		} else {
3685228753Smm			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
3686228753Smm			    "Invalid extended attribute encountered");
3687228753Smm			ret = ARCHIVE_WARN;
3688228753Smm		}
3689228753Smm	}
3690228753Smm	return (ret);
3691228753Smm}
3692228753Smm#elif HAVE_EXTATTR_SET_FILE && HAVE_DECL_EXTATTR_NAMESPACE_USER
3693228753Smm/*
3694228753Smm * Restore extended attributes -  FreeBSD implementation
3695228753Smm */
3696228753Smmstatic int
3697228753Smmset_xattrs(struct archive_write_disk *a)
3698228753Smm{
3699228753Smm	struct archive_entry *entry = a->entry;
3700228753Smm	static int warning_done = 0;
3701228753Smm	int ret = ARCHIVE_OK;
3702228753Smm	int i = archive_entry_xattr_reset(entry);
3703228753Smm
3704228753Smm	while (i--) {
3705228753Smm		const char *name;
3706228753Smm		const void *value;
3707228753Smm		size_t size;
3708228753Smm		archive_entry_xattr_next(entry, &name, &value, &size);
3709228753Smm		if (name != NULL) {
3710248995Smdf			ssize_t e;
3711228753Smm			int namespace;
3712228753Smm
3713228753Smm			if (strncmp(name, "user.", 5) == 0) {
3714228753Smm				/* "user." attributes go to user namespace */
3715228753Smm				name += 5;
3716228753Smm				namespace = EXTATTR_NAMESPACE_USER;
3717228753Smm			} else {
3718228753Smm				/* Warn about other extended attributes. */
3719228753Smm				archive_set_error(&a->archive,
3720228753Smm				    ARCHIVE_ERRNO_FILE_FORMAT,
3721228753Smm				    "Can't restore extended attribute ``%s''",
3722228753Smm				    name);
3723228753Smm				ret = ARCHIVE_WARN;
3724228753Smm				continue;
3725228753Smm			}
3726228753Smm			errno = 0;
3727228753Smm#if HAVE_EXTATTR_SET_FD
3728228753Smm			if (a->fd >= 0)
3729228753Smm				e = extattr_set_fd(a->fd, namespace, name, value, size);
3730228753Smm			else
3731228753Smm#endif
3732228753Smm			/* TODO: should we use extattr_set_link() instead? */
3733228753Smm			{
3734228753Smm				e = extattr_set_file(archive_entry_pathname(entry),
3735228753Smm				    namespace, name, value, size);
3736228753Smm			}
3737248995Smdf			if (e != (ssize_t)size) {
3738231200Smm				if (errno == ENOTSUP || errno == ENOSYS) {
3739228753Smm					if (!warning_done) {
3740228753Smm						warning_done = 1;
3741228753Smm						archive_set_error(&a->archive, errno,
3742228753Smm						    "Cannot restore extended "
3743228753Smm						    "attributes on this file "
3744228753Smm						    "system");
3745228753Smm					}
3746228753Smm				} else {
3747228753Smm					archive_set_error(&a->archive, errno,
3748228753Smm					    "Failed to set extended attribute");
3749228753Smm				}
3750228753Smm
3751228753Smm				ret = ARCHIVE_WARN;
3752228753Smm			}
3753228753Smm		}
3754228753Smm	}
3755228753Smm	return (ret);
3756228753Smm}
3757228753Smm#else
3758228753Smm/*
3759228753Smm * Restore extended attributes - stub implementation for unsupported systems
3760228753Smm */
3761228753Smmstatic int
3762228753Smmset_xattrs(struct archive_write_disk *a)
3763228753Smm{
3764228753Smm	static int warning_done = 0;
3765228753Smm
3766228753Smm	/* If there aren't any extended attributes, then it's okay not
3767228753Smm	 * to extract them, otherwise, issue a single warning. */
3768228753Smm	if (archive_entry_xattr_count(a->entry) != 0 && !warning_done) {
3769228753Smm		warning_done = 1;
3770228753Smm		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
3771228753Smm		    "Cannot restore extended attributes on this system");
3772228753Smm		return (ARCHIVE_WARN);
3773228753Smm	}
3774228753Smm	/* Warning was already emitted; suppress further warnings. */
3775228753Smm	return (ARCHIVE_OK);
3776228753Smm}
3777228753Smm#endif
3778228753Smm
3779228753Smm/*
3780228753Smm * Test if file on disk is older than entry.
3781228753Smm */
3782228753Smmstatic int
3783228753Smmolder(struct stat *st, struct archive_entry *entry)
3784228753Smm{
3785228753Smm	/* First, test the seconds and return if we have a definite answer. */
3786228753Smm	/* Definitely older. */
3787228753Smm	if (st->st_mtime < archive_entry_mtime(entry))
3788228753Smm		return (1);
3789228753Smm	/* Definitely younger. */
3790228753Smm	if (st->st_mtime > archive_entry_mtime(entry))
3791228753Smm		return (0);
3792228753Smm	/* If this platform supports fractional seconds, try those. */
3793228753Smm#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
3794228753Smm	/* Definitely older. */
3795228753Smm	if (st->st_mtimespec.tv_nsec < archive_entry_mtime_nsec(entry))
3796228753Smm		return (1);
3797228753Smm#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
3798228753Smm	/* Definitely older. */
3799228753Smm	if (st->st_mtim.tv_nsec < archive_entry_mtime_nsec(entry))
3800228753Smm		return (1);
3801228753Smm#elif HAVE_STRUCT_STAT_ST_MTIME_N
3802228753Smm	/* older. */
3803228753Smm	if (st->st_mtime_n < archive_entry_mtime_nsec(entry))
3804228753Smm		return (1);
3805228753Smm#elif HAVE_STRUCT_STAT_ST_UMTIME
3806228753Smm	/* older. */
3807228753Smm	if (st->st_umtime * 1000 < archive_entry_mtime_nsec(entry))
3808228753Smm		return (1);
3809228753Smm#elif HAVE_STRUCT_STAT_ST_MTIME_USEC
3810228753Smm	/* older. */
3811228753Smm	if (st->st_mtime_usec * 1000 < archive_entry_mtime_nsec(entry))
3812228753Smm		return (1);
3813228753Smm#else
3814228753Smm	/* This system doesn't have high-res timestamps. */
3815228753Smm#endif
3816228753Smm	/* Same age or newer, so not older. */
3817228753Smm	return (0);
3818228753Smm}
3819231200Smm
3820231200Smm#endif /* !_WIN32 || __CYGWIN__ */
3821231200Smm
3822