xref: /freebsd/contrib/libarchive/tar/write.c (revision caf54c4f6ce7f1612a528170c1aa3c3fe4f8b153)
1*caf54c4fSMartin Matuska /*-
2*caf54c4fSMartin Matuska  * Copyright (c) 2003-2007 Tim Kientzle
3*caf54c4fSMartin Matuska  * All rights reserved.
4*caf54c4fSMartin Matuska  *
5*caf54c4fSMartin Matuska  * Redistribution and use in source and binary forms, with or without
6*caf54c4fSMartin Matuska  * modification, are permitted provided that the following conditions
7*caf54c4fSMartin Matuska  * are met:
8*caf54c4fSMartin Matuska  * 1. Redistributions of source code must retain the above copyright
9*caf54c4fSMartin Matuska  *    notice, this list of conditions and the following disclaimer.
10*caf54c4fSMartin Matuska  * 2. Redistributions in binary form must reproduce the above copyright
11*caf54c4fSMartin Matuska  *    notice, this list of conditions and the following disclaimer in the
12*caf54c4fSMartin Matuska  *    documentation and/or other materials provided with the distribution.
13*caf54c4fSMartin Matuska  *
14*caf54c4fSMartin Matuska  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15*caf54c4fSMartin Matuska  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16*caf54c4fSMartin Matuska  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17*caf54c4fSMartin Matuska  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18*caf54c4fSMartin Matuska  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19*caf54c4fSMartin Matuska  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20*caf54c4fSMartin Matuska  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21*caf54c4fSMartin Matuska  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22*caf54c4fSMartin Matuska  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23*caf54c4fSMartin Matuska  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24*caf54c4fSMartin Matuska  */
25*caf54c4fSMartin Matuska 
26*caf54c4fSMartin Matuska #include "bsdtar_platform.h"
27*caf54c4fSMartin Matuska __FBSDID("$FreeBSD: src/usr.bin/tar/write.c,v 1.79 2008/11/27 05:49:52 kientzle Exp $");
28*caf54c4fSMartin Matuska 
29*caf54c4fSMartin Matuska #ifdef HAVE_SYS_TYPES_H
30*caf54c4fSMartin Matuska #include <sys/types.h>
31*caf54c4fSMartin Matuska #endif
32*caf54c4fSMartin Matuska #ifdef HAVE_SYS_IOCTL_H
33*caf54c4fSMartin Matuska #include <sys/ioctl.h>
34*caf54c4fSMartin Matuska #endif
35*caf54c4fSMartin Matuska #ifdef HAVE_SYS_STAT_H
36*caf54c4fSMartin Matuska #include <sys/stat.h>
37*caf54c4fSMartin Matuska #endif
38*caf54c4fSMartin Matuska #ifdef HAVE_ATTR_XATTR_H
39*caf54c4fSMartin Matuska #include <attr/xattr.h>
40*caf54c4fSMartin Matuska #endif
41*caf54c4fSMartin Matuska #ifdef HAVE_ERRNO_H
42*caf54c4fSMartin Matuska #include <errno.h>
43*caf54c4fSMartin Matuska #endif
44*caf54c4fSMartin Matuska #ifdef HAVE_FCNTL_H
45*caf54c4fSMartin Matuska #include <fcntl.h>
46*caf54c4fSMartin Matuska #endif
47*caf54c4fSMartin Matuska #ifdef HAVE_GRP_H
48*caf54c4fSMartin Matuska #include <grp.h>
49*caf54c4fSMartin Matuska #endif
50*caf54c4fSMartin Matuska #ifdef HAVE_IO_H
51*caf54c4fSMartin Matuska #include <io.h>
52*caf54c4fSMartin Matuska #endif
53*caf54c4fSMartin Matuska #ifdef HAVE_LIMITS_H
54*caf54c4fSMartin Matuska #include <limits.h>
55*caf54c4fSMartin Matuska #endif
56*caf54c4fSMartin Matuska #ifdef HAVE_LINUX_FS_H
57*caf54c4fSMartin Matuska #include <linux/fs.h>	/* for Linux file flags */
58*caf54c4fSMartin Matuska #endif
59*caf54c4fSMartin Matuska /*
60*caf54c4fSMartin Matuska  * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
61*caf54c4fSMartin Matuska  * As the include guards don't agree, the order of include is important.
62*caf54c4fSMartin Matuska  */
63*caf54c4fSMartin Matuska #ifdef HAVE_LINUX_EXT2_FS_H
64*caf54c4fSMartin Matuska #include <linux/ext2_fs.h>	/* for Linux file flags */
65*caf54c4fSMartin Matuska #endif
66*caf54c4fSMartin Matuska #if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
67*caf54c4fSMartin Matuska /* This header exists but is broken on Cygwin. */
68*caf54c4fSMartin Matuska #include <ext2fs/ext2_fs.h>
69*caf54c4fSMartin Matuska #endif
70*caf54c4fSMartin Matuska #ifdef HAVE_PWD_H
71*caf54c4fSMartin Matuska #include <pwd.h>
72*caf54c4fSMartin Matuska #endif
73*caf54c4fSMartin Matuska #ifdef HAVE_STDINT_H
74*caf54c4fSMartin Matuska #include <stdint.h>
75*caf54c4fSMartin Matuska #endif
76*caf54c4fSMartin Matuska #include <stdio.h>
77*caf54c4fSMartin Matuska #ifdef HAVE_STDLIB_H
78*caf54c4fSMartin Matuska #include <stdlib.h>
79*caf54c4fSMartin Matuska #endif
80*caf54c4fSMartin Matuska #ifdef HAVE_STRING_H
81*caf54c4fSMartin Matuska #include <string.h>
82*caf54c4fSMartin Matuska #endif
83*caf54c4fSMartin Matuska #ifdef HAVE_UNISTD_H
84*caf54c4fSMartin Matuska #include <unistd.h>
85*caf54c4fSMartin Matuska #endif
86*caf54c4fSMartin Matuska 
87*caf54c4fSMartin Matuska #include "bsdtar.h"
88*caf54c4fSMartin Matuska #include "err.h"
89*caf54c4fSMartin Matuska #include "line_reader.h"
90*caf54c4fSMartin Matuska #include "tree.h"
91*caf54c4fSMartin Matuska 
92*caf54c4fSMartin Matuska /* Size of buffer for holding file data prior to writing. */
93*caf54c4fSMartin Matuska #define FILEDATABUFLEN	65536
94*caf54c4fSMartin Matuska 
95*caf54c4fSMartin Matuska /* Fixed size of uname/gname caches. */
96*caf54c4fSMartin Matuska #define	name_cache_size 101
97*caf54c4fSMartin Matuska 
98*caf54c4fSMartin Matuska #ifndef O_BINARY
99*caf54c4fSMartin Matuska #define O_BINARY 0
100*caf54c4fSMartin Matuska #endif
101*caf54c4fSMartin Matuska 
102*caf54c4fSMartin Matuska static const char * const NO_NAME = "(noname)";
103*caf54c4fSMartin Matuska 
104*caf54c4fSMartin Matuska struct archive_dir_entry {
105*caf54c4fSMartin Matuska 	struct archive_dir_entry	*next;
106*caf54c4fSMartin Matuska 	time_t			 mtime_sec;
107*caf54c4fSMartin Matuska 	int			 mtime_nsec;
108*caf54c4fSMartin Matuska 	char			*name;
109*caf54c4fSMartin Matuska };
110*caf54c4fSMartin Matuska 
111*caf54c4fSMartin Matuska struct archive_dir {
112*caf54c4fSMartin Matuska 	struct archive_dir_entry *head, *tail;
113*caf54c4fSMartin Matuska };
114*caf54c4fSMartin Matuska 
115*caf54c4fSMartin Matuska struct name_cache {
116*caf54c4fSMartin Matuska 	int	probes;
117*caf54c4fSMartin Matuska 	int	hits;
118*caf54c4fSMartin Matuska 	size_t	size;
119*caf54c4fSMartin Matuska 	struct {
120*caf54c4fSMartin Matuska 		id_t id;
121*caf54c4fSMartin Matuska 		const char *name;
122*caf54c4fSMartin Matuska 	} cache[name_cache_size];
123*caf54c4fSMartin Matuska };
124*caf54c4fSMartin Matuska 
125*caf54c4fSMartin Matuska static void		 add_dir_list(struct bsdtar *bsdtar, const char *path,
126*caf54c4fSMartin Matuska 			     time_t mtime_sec, int mtime_nsec);
127*caf54c4fSMartin Matuska static int		 append_archive(struct bsdtar *, struct archive *,
128*caf54c4fSMartin Matuska 			     struct archive *ina);
129*caf54c4fSMartin Matuska static int		 append_archive_filename(struct bsdtar *,
130*caf54c4fSMartin Matuska 			     struct archive *, const char *fname);
131*caf54c4fSMartin Matuska static void		 archive_names_from_file(struct bsdtar *bsdtar,
132*caf54c4fSMartin Matuska 			     struct archive *a);
133*caf54c4fSMartin Matuska static int		 copy_file_data(struct bsdtar *, struct archive *a,
134*caf54c4fSMartin Matuska 			     struct archive *ina, struct archive_entry *);
135*caf54c4fSMartin Matuska static int		 new_enough(struct bsdtar *, const char *path,
136*caf54c4fSMartin Matuska 			     const struct stat *);
137*caf54c4fSMartin Matuska static void		 report_write(struct bsdtar *, struct archive *,
138*caf54c4fSMartin Matuska 			     struct archive_entry *, int64_t progress);
139*caf54c4fSMartin Matuska static void		 test_for_append(struct bsdtar *);
140*caf54c4fSMartin Matuska static void		 write_archive(struct archive *, struct bsdtar *);
141*caf54c4fSMartin Matuska static void		 write_entry_backend(struct bsdtar *, struct archive *,
142*caf54c4fSMartin Matuska 			     struct archive_entry *);
143*caf54c4fSMartin Matuska static int		 write_file_data(struct bsdtar *, struct archive *,
144*caf54c4fSMartin Matuska 			     struct archive_entry *, int fd);
145*caf54c4fSMartin Matuska static void		 write_hierarchy(struct bsdtar *, struct archive *,
146*caf54c4fSMartin Matuska 			     const char *);
147*caf54c4fSMartin Matuska 
148*caf54c4fSMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
149*caf54c4fSMartin Matuska /* Not a full lseek() emulation, but enough for our needs here. */
150*caf54c4fSMartin Matuska static int
151*caf54c4fSMartin Matuska seek_file(int fd, int64_t offset, int whence)
152*caf54c4fSMartin Matuska {
153*caf54c4fSMartin Matuska 	LARGE_INTEGER distance;
154*caf54c4fSMartin Matuska 	(void)whence; /* UNUSED */
155*caf54c4fSMartin Matuska 	distance.QuadPart = offset;
156*caf54c4fSMartin Matuska 	return (SetFilePointerEx((HANDLE)_get_osfhandle(fd),
157*caf54c4fSMartin Matuska 		distance, NULL, FILE_BEGIN) ? 1 : -1);
158*caf54c4fSMartin Matuska }
159*caf54c4fSMartin Matuska #define open _open
160*caf54c4fSMartin Matuska #define close _close
161*caf54c4fSMartin Matuska #define read _read
162*caf54c4fSMartin Matuska #define lseek seek_file
163*caf54c4fSMartin Matuska #endif
164*caf54c4fSMartin Matuska 
165*caf54c4fSMartin Matuska void
166*caf54c4fSMartin Matuska tar_mode_c(struct bsdtar *bsdtar)
167*caf54c4fSMartin Matuska {
168*caf54c4fSMartin Matuska 	struct archive *a;
169*caf54c4fSMartin Matuska 	int r;
170*caf54c4fSMartin Matuska 
171*caf54c4fSMartin Matuska 	if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL)
172*caf54c4fSMartin Matuska 		lafe_errc(1, 0, "no files or directories specified");
173*caf54c4fSMartin Matuska 
174*caf54c4fSMartin Matuska 	a = archive_write_new();
175*caf54c4fSMartin Matuska 
176*caf54c4fSMartin Matuska 	/* Support any format that the library supports. */
177*caf54c4fSMartin Matuska 	if (bsdtar->create_format == NULL) {
178*caf54c4fSMartin Matuska 		r = archive_write_set_format_pax_restricted(a);
179*caf54c4fSMartin Matuska 		bsdtar->create_format = "pax restricted";
180*caf54c4fSMartin Matuska 	} else {
181*caf54c4fSMartin Matuska 		r = archive_write_set_format_by_name(a, bsdtar->create_format);
182*caf54c4fSMartin Matuska 	}
183*caf54c4fSMartin Matuska 	if (r != ARCHIVE_OK) {
184*caf54c4fSMartin Matuska 		fprintf(stderr, "Can't use format %s: %s\n",
185*caf54c4fSMartin Matuska 		    bsdtar->create_format,
186*caf54c4fSMartin Matuska 		    archive_error_string(a));
187*caf54c4fSMartin Matuska 		usage();
188*caf54c4fSMartin Matuska 	}
189*caf54c4fSMartin Matuska 
190*caf54c4fSMartin Matuska 	/*
191*caf54c4fSMartin Matuska 	 * If user explicitly set the block size, then assume they
192*caf54c4fSMartin Matuska 	 * want the last block padded as well.  Otherwise, use the
193*caf54c4fSMartin Matuska 	 * default block size and accept archive_write_open_file()'s
194*caf54c4fSMartin Matuska 	 * default padding decisions.
195*caf54c4fSMartin Matuska 	 */
196*caf54c4fSMartin Matuska 	if (bsdtar->bytes_per_block != 0) {
197*caf54c4fSMartin Matuska 		archive_write_set_bytes_per_block(a, bsdtar->bytes_per_block);
198*caf54c4fSMartin Matuska 		archive_write_set_bytes_in_last_block(a,
199*caf54c4fSMartin Matuska 		    bsdtar->bytes_per_block);
200*caf54c4fSMartin Matuska 	} else
201*caf54c4fSMartin Matuska 		archive_write_set_bytes_per_block(a, DEFAULT_BYTES_PER_BLOCK);
202*caf54c4fSMartin Matuska 
203*caf54c4fSMartin Matuska 	if (bsdtar->compress_program) {
204*caf54c4fSMartin Matuska 		archive_write_set_compression_program(a, bsdtar->compress_program);
205*caf54c4fSMartin Matuska 	} else {
206*caf54c4fSMartin Matuska 		switch (bsdtar->create_compression) {
207*caf54c4fSMartin Matuska 		case 0:
208*caf54c4fSMartin Matuska 			r = archive_write_set_compression_none(a);
209*caf54c4fSMartin Matuska 			break;
210*caf54c4fSMartin Matuska 		case 'j': case 'y':
211*caf54c4fSMartin Matuska 			r = archive_write_set_compression_bzip2(a);
212*caf54c4fSMartin Matuska 			break;
213*caf54c4fSMartin Matuska 		case 'J':
214*caf54c4fSMartin Matuska 			r = archive_write_set_compression_xz(a);
215*caf54c4fSMartin Matuska 			break;
216*caf54c4fSMartin Matuska 		case OPTION_LZMA:
217*caf54c4fSMartin Matuska 			r = archive_write_set_compression_lzma(a);
218*caf54c4fSMartin Matuska 			break;
219*caf54c4fSMartin Matuska 		case 'z':
220*caf54c4fSMartin Matuska 			r = archive_write_set_compression_gzip(a);
221*caf54c4fSMartin Matuska 			break;
222*caf54c4fSMartin Matuska 		case 'Z':
223*caf54c4fSMartin Matuska 			r = archive_write_set_compression_compress(a);
224*caf54c4fSMartin Matuska 			break;
225*caf54c4fSMartin Matuska 		default:
226*caf54c4fSMartin Matuska 			lafe_errc(1, 0,
227*caf54c4fSMartin Matuska 			    "Unrecognized compression option -%c",
228*caf54c4fSMartin Matuska 			    bsdtar->create_compression);
229*caf54c4fSMartin Matuska 		}
230*caf54c4fSMartin Matuska 		if (r != ARCHIVE_OK) {
231*caf54c4fSMartin Matuska 			lafe_errc(1, 0,
232*caf54c4fSMartin Matuska 			    "Unsupported compression option -%c",
233*caf54c4fSMartin Matuska 			    bsdtar->create_compression);
234*caf54c4fSMartin Matuska 		}
235*caf54c4fSMartin Matuska 	}
236*caf54c4fSMartin Matuska 
237*caf54c4fSMartin Matuska 	if (ARCHIVE_OK != archive_write_set_options(a, bsdtar->option_options))
238*caf54c4fSMartin Matuska 		lafe_errc(1, 0, "%s", archive_error_string(a));
239*caf54c4fSMartin Matuska 	if (ARCHIVE_OK != archive_write_open_file(a, bsdtar->filename))
240*caf54c4fSMartin Matuska 		lafe_errc(1, 0, "%s", archive_error_string(a));
241*caf54c4fSMartin Matuska 	write_archive(a, bsdtar);
242*caf54c4fSMartin Matuska }
243*caf54c4fSMartin Matuska 
244*caf54c4fSMartin Matuska /*
245*caf54c4fSMartin Matuska  * Same as 'c', except we only support tar or empty formats in
246*caf54c4fSMartin Matuska  * uncompressed files on disk.
247*caf54c4fSMartin Matuska  */
248*caf54c4fSMartin Matuska void
249*caf54c4fSMartin Matuska tar_mode_r(struct bsdtar *bsdtar)
250*caf54c4fSMartin Matuska {
251*caf54c4fSMartin Matuska 	int64_t	end_offset;
252*caf54c4fSMartin Matuska 	int	format;
253*caf54c4fSMartin Matuska 	struct archive *a;
254*caf54c4fSMartin Matuska 	struct archive_entry *entry;
255*caf54c4fSMartin Matuska 	int	r;
256*caf54c4fSMartin Matuska 
257*caf54c4fSMartin Matuska 	/* Sanity-test some arguments and the file. */
258*caf54c4fSMartin Matuska 	test_for_append(bsdtar);
259*caf54c4fSMartin Matuska 
260*caf54c4fSMartin Matuska 	format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED;
261*caf54c4fSMartin Matuska 
262*caf54c4fSMartin Matuska #if defined(__BORLANDC__)
263*caf54c4fSMartin Matuska 	bsdtar->fd = open(bsdtar->filename, O_RDWR | O_CREAT | O_BINARY);
264*caf54c4fSMartin Matuska #else
265*caf54c4fSMartin Matuska 	bsdtar->fd = open(bsdtar->filename, O_RDWR | O_CREAT | O_BINARY, 0666);
266*caf54c4fSMartin Matuska #endif
267*caf54c4fSMartin Matuska 	if (bsdtar->fd < 0)
268*caf54c4fSMartin Matuska 		lafe_errc(1, errno,
269*caf54c4fSMartin Matuska 		    "Cannot open %s", bsdtar->filename);
270*caf54c4fSMartin Matuska 
271*caf54c4fSMartin Matuska 	a = archive_read_new();
272*caf54c4fSMartin Matuska 	archive_read_support_compression_all(a);
273*caf54c4fSMartin Matuska 	archive_read_support_format_tar(a);
274*caf54c4fSMartin Matuska 	archive_read_support_format_gnutar(a);
275*caf54c4fSMartin Matuska 	r = archive_read_open_fd(a, bsdtar->fd, 10240);
276*caf54c4fSMartin Matuska 	if (r != ARCHIVE_OK)
277*caf54c4fSMartin Matuska 		lafe_errc(1, archive_errno(a),
278*caf54c4fSMartin Matuska 		    "Can't read archive %s: %s", bsdtar->filename,
279*caf54c4fSMartin Matuska 		    archive_error_string(a));
280*caf54c4fSMartin Matuska 	while (0 == archive_read_next_header(a, &entry)) {
281*caf54c4fSMartin Matuska 		if (archive_compression(a) != ARCHIVE_COMPRESSION_NONE) {
282*caf54c4fSMartin Matuska 			archive_read_finish(a);
283*caf54c4fSMartin Matuska 			close(bsdtar->fd);
284*caf54c4fSMartin Matuska 			lafe_errc(1, 0,
285*caf54c4fSMartin Matuska 			    "Cannot append to compressed archive.");
286*caf54c4fSMartin Matuska 		}
287*caf54c4fSMartin Matuska 		/* Keep going until we hit end-of-archive */
288*caf54c4fSMartin Matuska 		format = archive_format(a);
289*caf54c4fSMartin Matuska 	}
290*caf54c4fSMartin Matuska 
291*caf54c4fSMartin Matuska 	end_offset = archive_read_header_position(a);
292*caf54c4fSMartin Matuska 	archive_read_finish(a);
293*caf54c4fSMartin Matuska 
294*caf54c4fSMartin Matuska 	/* Re-open archive for writing */
295*caf54c4fSMartin Matuska 	a = archive_write_new();
296*caf54c4fSMartin Matuska 	archive_write_set_compression_none(a);
297*caf54c4fSMartin Matuska 	/*
298*caf54c4fSMartin Matuska 	 * Set the format to be used for writing.  To allow people to
299*caf54c4fSMartin Matuska 	 * extend empty files, we need to allow them to specify the format,
300*caf54c4fSMartin Matuska 	 * which opens the possibility that they will specify a format that
301*caf54c4fSMartin Matuska 	 * doesn't match the existing format.  Hence, the following bit
302*caf54c4fSMartin Matuska 	 * of arcane ugliness.
303*caf54c4fSMartin Matuska 	 */
304*caf54c4fSMartin Matuska 
305*caf54c4fSMartin Matuska 	if (bsdtar->create_format != NULL) {
306*caf54c4fSMartin Matuska 		/* If the user requested a format, use that, but ... */
307*caf54c4fSMartin Matuska 		archive_write_set_format_by_name(a,
308*caf54c4fSMartin Matuska 		    bsdtar->create_format);
309*caf54c4fSMartin Matuska 		/* ... complain if it's not compatible. */
310*caf54c4fSMartin Matuska 		format &= ARCHIVE_FORMAT_BASE_MASK;
311*caf54c4fSMartin Matuska 		if (format != (int)(archive_format(a) & ARCHIVE_FORMAT_BASE_MASK)
312*caf54c4fSMartin Matuska 		    && format != ARCHIVE_FORMAT_EMPTY) {
313*caf54c4fSMartin Matuska 			lafe_errc(1, 0,
314*caf54c4fSMartin Matuska 			    "Format %s is incompatible with the archive %s.",
315*caf54c4fSMartin Matuska 			    bsdtar->create_format, bsdtar->filename);
316*caf54c4fSMartin Matuska 		}
317*caf54c4fSMartin Matuska 	} else {
318*caf54c4fSMartin Matuska 		/*
319*caf54c4fSMartin Matuska 		 * Just preserve the current format, with a little care
320*caf54c4fSMartin Matuska 		 * for formats that libarchive can't write.
321*caf54c4fSMartin Matuska 		 */
322*caf54c4fSMartin Matuska 		if (format == ARCHIVE_FORMAT_TAR_GNUTAR)
323*caf54c4fSMartin Matuska 			/* TODO: When gtar supports pax, use pax restricted. */
324*caf54c4fSMartin Matuska 			format = ARCHIVE_FORMAT_TAR_USTAR;
325*caf54c4fSMartin Matuska 		if (format == ARCHIVE_FORMAT_EMPTY)
326*caf54c4fSMartin Matuska 			format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED;
327*caf54c4fSMartin Matuska 		archive_write_set_format(a, format);
328*caf54c4fSMartin Matuska 	}
329*caf54c4fSMartin Matuska 	if (lseek(bsdtar->fd, end_offset, SEEK_SET) < 0)
330*caf54c4fSMartin Matuska 		lafe_errc(1, errno, "Could not seek to archive end");
331*caf54c4fSMartin Matuska 	if (ARCHIVE_OK != archive_write_set_options(a, bsdtar->option_options))
332*caf54c4fSMartin Matuska 		lafe_errc(1, 0, "%s", archive_error_string(a));
333*caf54c4fSMartin Matuska 	if (ARCHIVE_OK != archive_write_open_fd(a, bsdtar->fd))
334*caf54c4fSMartin Matuska 		lafe_errc(1, 0, "%s", archive_error_string(a));
335*caf54c4fSMartin Matuska 
336*caf54c4fSMartin Matuska 	write_archive(a, bsdtar); /* XXX check return val XXX */
337*caf54c4fSMartin Matuska 
338*caf54c4fSMartin Matuska 	close(bsdtar->fd);
339*caf54c4fSMartin Matuska 	bsdtar->fd = -1;
340*caf54c4fSMartin Matuska }
341*caf54c4fSMartin Matuska 
342*caf54c4fSMartin Matuska void
343*caf54c4fSMartin Matuska tar_mode_u(struct bsdtar *bsdtar)
344*caf54c4fSMartin Matuska {
345*caf54c4fSMartin Matuska 	int64_t			 end_offset;
346*caf54c4fSMartin Matuska 	struct archive		*a;
347*caf54c4fSMartin Matuska 	struct archive_entry	*entry;
348*caf54c4fSMartin Matuska 	int			 format;
349*caf54c4fSMartin Matuska 	struct archive_dir_entry	*p;
350*caf54c4fSMartin Matuska 	struct archive_dir	 archive_dir;
351*caf54c4fSMartin Matuska 
352*caf54c4fSMartin Matuska 	bsdtar->archive_dir = &archive_dir;
353*caf54c4fSMartin Matuska 	memset(&archive_dir, 0, sizeof(archive_dir));
354*caf54c4fSMartin Matuska 
355*caf54c4fSMartin Matuska 	format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED;
356*caf54c4fSMartin Matuska 
357*caf54c4fSMartin Matuska 	/* Sanity-test some arguments and the file. */
358*caf54c4fSMartin Matuska 	test_for_append(bsdtar);
359*caf54c4fSMartin Matuska 
360*caf54c4fSMartin Matuska 	bsdtar->fd = open(bsdtar->filename, O_RDWR | O_BINARY);
361*caf54c4fSMartin Matuska 	if (bsdtar->fd < 0)
362*caf54c4fSMartin Matuska 		lafe_errc(1, errno,
363*caf54c4fSMartin Matuska 		    "Cannot open %s", bsdtar->filename);
364*caf54c4fSMartin Matuska 
365*caf54c4fSMartin Matuska 	a = archive_read_new();
366*caf54c4fSMartin Matuska 	archive_read_support_compression_all(a);
367*caf54c4fSMartin Matuska 	archive_read_support_format_tar(a);
368*caf54c4fSMartin Matuska 	archive_read_support_format_gnutar(a);
369*caf54c4fSMartin Matuska 	if (archive_read_open_fd(a, bsdtar->fd,
370*caf54c4fSMartin Matuska 	    bsdtar->bytes_per_block != 0 ? bsdtar->bytes_per_block :
371*caf54c4fSMartin Matuska 		DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
372*caf54c4fSMartin Matuska 		lafe_errc(1, 0,
373*caf54c4fSMartin Matuska 		    "Can't open %s: %s", bsdtar->filename,
374*caf54c4fSMartin Matuska 		    archive_error_string(a));
375*caf54c4fSMartin Matuska 	}
376*caf54c4fSMartin Matuska 
377*caf54c4fSMartin Matuska 	/* Build a list of all entries and their recorded mod times. */
378*caf54c4fSMartin Matuska 	while (0 == archive_read_next_header(a, &entry)) {
379*caf54c4fSMartin Matuska 		if (archive_compression(a) != ARCHIVE_COMPRESSION_NONE) {
380*caf54c4fSMartin Matuska 			archive_read_finish(a);
381*caf54c4fSMartin Matuska 			close(bsdtar->fd);
382*caf54c4fSMartin Matuska 			lafe_errc(1, 0,
383*caf54c4fSMartin Matuska 			    "Cannot append to compressed archive.");
384*caf54c4fSMartin Matuska 		}
385*caf54c4fSMartin Matuska 		add_dir_list(bsdtar, archive_entry_pathname(entry),
386*caf54c4fSMartin Matuska 		    archive_entry_mtime(entry),
387*caf54c4fSMartin Matuska 		    archive_entry_mtime_nsec(entry));
388*caf54c4fSMartin Matuska 		/* Record the last format determination we see */
389*caf54c4fSMartin Matuska 		format = archive_format(a);
390*caf54c4fSMartin Matuska 		/* Keep going until we hit end-of-archive */
391*caf54c4fSMartin Matuska 	}
392*caf54c4fSMartin Matuska 
393*caf54c4fSMartin Matuska 	end_offset = archive_read_header_position(a);
394*caf54c4fSMartin Matuska 	archive_read_finish(a);
395*caf54c4fSMartin Matuska 
396*caf54c4fSMartin Matuska 	/* Re-open archive for writing. */
397*caf54c4fSMartin Matuska 	a = archive_write_new();
398*caf54c4fSMartin Matuska 	archive_write_set_compression_none(a);
399*caf54c4fSMartin Matuska 	/*
400*caf54c4fSMartin Matuska 	 * Set format to same one auto-detected above, except that
401*caf54c4fSMartin Matuska 	 * we don't write GNU tar format, so use ustar instead.
402*caf54c4fSMartin Matuska 	 */
403*caf54c4fSMartin Matuska 	if (format == ARCHIVE_FORMAT_TAR_GNUTAR)
404*caf54c4fSMartin Matuska 		format = ARCHIVE_FORMAT_TAR_USTAR;
405*caf54c4fSMartin Matuska 	archive_write_set_format(a, format);
406*caf54c4fSMartin Matuska 	if (bsdtar->bytes_per_block != 0) {
407*caf54c4fSMartin Matuska 		archive_write_set_bytes_per_block(a, bsdtar->bytes_per_block);
408*caf54c4fSMartin Matuska 		archive_write_set_bytes_in_last_block(a,
409*caf54c4fSMartin Matuska 		    bsdtar->bytes_per_block);
410*caf54c4fSMartin Matuska 	} else
411*caf54c4fSMartin Matuska 		archive_write_set_bytes_per_block(a, DEFAULT_BYTES_PER_BLOCK);
412*caf54c4fSMartin Matuska 	if (lseek(bsdtar->fd, end_offset, SEEK_SET) < 0)
413*caf54c4fSMartin Matuska 		lafe_errc(1, errno, "Could not seek to archive end");
414*caf54c4fSMartin Matuska 	if (ARCHIVE_OK != archive_write_set_options(a, bsdtar->option_options))
415*caf54c4fSMartin Matuska 		lafe_errc(1, 0, "%s", archive_error_string(a));
416*caf54c4fSMartin Matuska 	if (ARCHIVE_OK != archive_write_open_fd(a, bsdtar->fd))
417*caf54c4fSMartin Matuska 		lafe_errc(1, 0, "%s", archive_error_string(a));
418*caf54c4fSMartin Matuska 
419*caf54c4fSMartin Matuska 	write_archive(a, bsdtar);
420*caf54c4fSMartin Matuska 
421*caf54c4fSMartin Matuska 	close(bsdtar->fd);
422*caf54c4fSMartin Matuska 	bsdtar->fd = -1;
423*caf54c4fSMartin Matuska 
424*caf54c4fSMartin Matuska 	while (bsdtar->archive_dir->head != NULL) {
425*caf54c4fSMartin Matuska 		p = bsdtar->archive_dir->head->next;
426*caf54c4fSMartin Matuska 		free(bsdtar->archive_dir->head->name);
427*caf54c4fSMartin Matuska 		free(bsdtar->archive_dir->head);
428*caf54c4fSMartin Matuska 		bsdtar->archive_dir->head = p;
429*caf54c4fSMartin Matuska 	}
430*caf54c4fSMartin Matuska 	bsdtar->archive_dir->tail = NULL;
431*caf54c4fSMartin Matuska }
432*caf54c4fSMartin Matuska 
433*caf54c4fSMartin Matuska 
434*caf54c4fSMartin Matuska /*
435*caf54c4fSMartin Matuska  * Write user-specified files/dirs to opened archive.
436*caf54c4fSMartin Matuska  */
437*caf54c4fSMartin Matuska static void
438*caf54c4fSMartin Matuska write_archive(struct archive *a, struct bsdtar *bsdtar)
439*caf54c4fSMartin Matuska {
440*caf54c4fSMartin Matuska 	const char *arg;
441*caf54c4fSMartin Matuska 	struct archive_entry *entry, *sparse_entry;
442*caf54c4fSMartin Matuska 
443*caf54c4fSMartin Matuska 	/* Allocate a buffer for file data. */
444*caf54c4fSMartin Matuska 	if ((bsdtar->buff = malloc(FILEDATABUFLEN)) == NULL)
445*caf54c4fSMartin Matuska 		lafe_errc(1, 0, "cannot allocate memory");
446*caf54c4fSMartin Matuska 
447*caf54c4fSMartin Matuska 	if ((bsdtar->resolver = archive_entry_linkresolver_new()) == NULL)
448*caf54c4fSMartin Matuska 		lafe_errc(1, 0, "cannot create link resolver");
449*caf54c4fSMartin Matuska 	archive_entry_linkresolver_set_strategy(bsdtar->resolver,
450*caf54c4fSMartin Matuska 	    archive_format(a));
451*caf54c4fSMartin Matuska 	if ((bsdtar->diskreader = archive_read_disk_new()) == NULL)
452*caf54c4fSMartin Matuska 		lafe_errc(1, 0, "Cannot create read_disk object");
453*caf54c4fSMartin Matuska 	archive_read_disk_set_standard_lookup(bsdtar->diskreader);
454*caf54c4fSMartin Matuska 
455*caf54c4fSMartin Matuska 	if (bsdtar->names_from_file != NULL)
456*caf54c4fSMartin Matuska 		archive_names_from_file(bsdtar, a);
457*caf54c4fSMartin Matuska 
458*caf54c4fSMartin Matuska 	while (*bsdtar->argv) {
459*caf54c4fSMartin Matuska 		arg = *bsdtar->argv;
460*caf54c4fSMartin Matuska 		if (arg[0] == '-' && arg[1] == 'C') {
461*caf54c4fSMartin Matuska 			arg += 2;
462*caf54c4fSMartin Matuska 			if (*arg == '\0') {
463*caf54c4fSMartin Matuska 				bsdtar->argv++;
464*caf54c4fSMartin Matuska 				arg = *bsdtar->argv;
465*caf54c4fSMartin Matuska 				if (arg == NULL) {
466*caf54c4fSMartin Matuska 					lafe_warnc(0, "%s",
467*caf54c4fSMartin Matuska 					    "Missing argument for -C");
468*caf54c4fSMartin Matuska 					bsdtar->return_value = 1;
469*caf54c4fSMartin Matuska 					goto cleanup;
470*caf54c4fSMartin Matuska 				}
471*caf54c4fSMartin Matuska 			}
472*caf54c4fSMartin Matuska 			set_chdir(bsdtar, arg);
473*caf54c4fSMartin Matuska 		} else {
474*caf54c4fSMartin Matuska 			if (*arg != '/' && (arg[0] != '@' || arg[1] != '/'))
475*caf54c4fSMartin Matuska 				do_chdir(bsdtar); /* Handle a deferred -C */
476*caf54c4fSMartin Matuska 			if (*arg == '@') {
477*caf54c4fSMartin Matuska 				if (append_archive_filename(bsdtar, a,
478*caf54c4fSMartin Matuska 				    arg + 1) != 0)
479*caf54c4fSMartin Matuska 					break;
480*caf54c4fSMartin Matuska 			} else
481*caf54c4fSMartin Matuska 				write_hierarchy(bsdtar, a, arg);
482*caf54c4fSMartin Matuska 		}
483*caf54c4fSMartin Matuska 		bsdtar->argv++;
484*caf54c4fSMartin Matuska 	}
485*caf54c4fSMartin Matuska 
486*caf54c4fSMartin Matuska 	entry = NULL;
487*caf54c4fSMartin Matuska 	archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry);
488*caf54c4fSMartin Matuska 	while (entry != NULL) {
489*caf54c4fSMartin Matuska 		write_entry_backend(bsdtar, a, entry);
490*caf54c4fSMartin Matuska 		archive_entry_free(entry);
491*caf54c4fSMartin Matuska 		entry = NULL;
492*caf54c4fSMartin Matuska 		archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry);
493*caf54c4fSMartin Matuska 	}
494*caf54c4fSMartin Matuska 
495*caf54c4fSMartin Matuska 	if (archive_write_close(a)) {
496*caf54c4fSMartin Matuska 		lafe_warnc(0, "%s", archive_error_string(a));
497*caf54c4fSMartin Matuska 		bsdtar->return_value = 1;
498*caf54c4fSMartin Matuska 	}
499*caf54c4fSMartin Matuska 
500*caf54c4fSMartin Matuska cleanup:
501*caf54c4fSMartin Matuska 	/* Free file data buffer. */
502*caf54c4fSMartin Matuska 	free(bsdtar->buff);
503*caf54c4fSMartin Matuska 	archive_entry_linkresolver_free(bsdtar->resolver);
504*caf54c4fSMartin Matuska 	bsdtar->resolver = NULL;
505*caf54c4fSMartin Matuska 	archive_read_finish(bsdtar->diskreader);
506*caf54c4fSMartin Matuska 	bsdtar->diskreader = NULL;
507*caf54c4fSMartin Matuska 
508*caf54c4fSMartin Matuska 	if (bsdtar->option_totals) {
509*caf54c4fSMartin Matuska 		fprintf(stderr, "Total bytes written: %s\n",
510*caf54c4fSMartin Matuska 		    tar_i64toa(archive_position_compressed(a)));
511*caf54c4fSMartin Matuska 	}
512*caf54c4fSMartin Matuska 
513*caf54c4fSMartin Matuska 	archive_write_finish(a);
514*caf54c4fSMartin Matuska }
515*caf54c4fSMartin Matuska 
516*caf54c4fSMartin Matuska /*
517*caf54c4fSMartin Matuska  * Archive names specified in file.
518*caf54c4fSMartin Matuska  *
519*caf54c4fSMartin Matuska  * Unless --null was specified, a line containing exactly "-C" will
520*caf54c4fSMartin Matuska  * cause the next line to be a directory to pass to chdir().  If
521*caf54c4fSMartin Matuska  * --null is specified, then a line "-C" is just another filename.
522*caf54c4fSMartin Matuska  */
523*caf54c4fSMartin Matuska static void
524*caf54c4fSMartin Matuska archive_names_from_file(struct bsdtar *bsdtar, struct archive *a)
525*caf54c4fSMartin Matuska {
526*caf54c4fSMartin Matuska 	struct lafe_line_reader *lr;
527*caf54c4fSMartin Matuska 	const char *line;
528*caf54c4fSMartin Matuska 
529*caf54c4fSMartin Matuska 	bsdtar->next_line_is_dir = 0;
530*caf54c4fSMartin Matuska 
531*caf54c4fSMartin Matuska 	lr = lafe_line_reader(bsdtar->names_from_file, bsdtar->option_null);
532*caf54c4fSMartin Matuska 	while ((line = lafe_line_reader_next(lr)) != NULL) {
533*caf54c4fSMartin Matuska 		if (bsdtar->next_line_is_dir) {
534*caf54c4fSMartin Matuska 			set_chdir(bsdtar, line);
535*caf54c4fSMartin Matuska 			bsdtar->next_line_is_dir = 0;
536*caf54c4fSMartin Matuska 		} else if (!bsdtar->option_null && strcmp(line, "-C") == 0)
537*caf54c4fSMartin Matuska 			bsdtar->next_line_is_dir = 1;
538*caf54c4fSMartin Matuska 		else {
539*caf54c4fSMartin Matuska 			if (*line != '/')
540*caf54c4fSMartin Matuska 				do_chdir(bsdtar); /* Handle a deferred -C */
541*caf54c4fSMartin Matuska 			write_hierarchy(bsdtar, a, line);
542*caf54c4fSMartin Matuska 		}
543*caf54c4fSMartin Matuska 	}
544*caf54c4fSMartin Matuska 	lafe_line_reader_free(lr);
545*caf54c4fSMartin Matuska 	if (bsdtar->next_line_is_dir)
546*caf54c4fSMartin Matuska 		lafe_errc(1, errno,
547*caf54c4fSMartin Matuska 		    "Unexpected end of filename list; "
548*caf54c4fSMartin Matuska 		    "directory expected after -C");
549*caf54c4fSMartin Matuska }
550*caf54c4fSMartin Matuska 
551*caf54c4fSMartin Matuska /*
552*caf54c4fSMartin Matuska  * Copy from specified archive to current archive.  Returns non-zero
553*caf54c4fSMartin Matuska  * for write errors (which force us to terminate the entire archiving
554*caf54c4fSMartin Matuska  * operation).  If there are errors reading the input archive, we set
555*caf54c4fSMartin Matuska  * bsdtar->return_value but return zero, so the overall archiving
556*caf54c4fSMartin Matuska  * operation will complete and return non-zero.
557*caf54c4fSMartin Matuska  */
558*caf54c4fSMartin Matuska static int
559*caf54c4fSMartin Matuska append_archive_filename(struct bsdtar *bsdtar, struct archive *a,
560*caf54c4fSMartin Matuska     const char *filename)
561*caf54c4fSMartin Matuska {
562*caf54c4fSMartin Matuska 	struct archive *ina;
563*caf54c4fSMartin Matuska 	int rc;
564*caf54c4fSMartin Matuska 
565*caf54c4fSMartin Matuska 	if (strcmp(filename, "-") == 0)
566*caf54c4fSMartin Matuska 		filename = NULL; /* Library uses NULL for stdio. */
567*caf54c4fSMartin Matuska 
568*caf54c4fSMartin Matuska 	ina = archive_read_new();
569*caf54c4fSMartin Matuska 	archive_read_support_format_all(ina);
570*caf54c4fSMartin Matuska 	archive_read_support_compression_all(ina);
571*caf54c4fSMartin Matuska 	if (archive_read_open_file(ina, filename, 10240)) {
572*caf54c4fSMartin Matuska 		lafe_warnc(0, "%s", archive_error_string(ina));
573*caf54c4fSMartin Matuska 		bsdtar->return_value = 1;
574*caf54c4fSMartin Matuska 		return (0);
575*caf54c4fSMartin Matuska 	}
576*caf54c4fSMartin Matuska 
577*caf54c4fSMartin Matuska 	rc = append_archive(bsdtar, a, ina);
578*caf54c4fSMartin Matuska 
579*caf54c4fSMartin Matuska 	if (rc != ARCHIVE_OK) {
580*caf54c4fSMartin Matuska 		lafe_warnc(0, "Error reading archive %s: %s",
581*caf54c4fSMartin Matuska 		    filename, archive_error_string(ina));
582*caf54c4fSMartin Matuska 		bsdtar->return_value = 1;
583*caf54c4fSMartin Matuska 	}
584*caf54c4fSMartin Matuska 	archive_read_finish(ina);
585*caf54c4fSMartin Matuska 
586*caf54c4fSMartin Matuska 	return (rc);
587*caf54c4fSMartin Matuska }
588*caf54c4fSMartin Matuska 
589*caf54c4fSMartin Matuska static int
590*caf54c4fSMartin Matuska append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina)
591*caf54c4fSMartin Matuska {
592*caf54c4fSMartin Matuska 	struct archive_entry *in_entry;
593*caf54c4fSMartin Matuska 	int e;
594*caf54c4fSMartin Matuska 
595*caf54c4fSMartin Matuska 	while (ARCHIVE_OK == (e = archive_read_next_header(ina, &in_entry))) {
596*caf54c4fSMartin Matuska 		if (!new_enough(bsdtar, archive_entry_pathname(in_entry),
597*caf54c4fSMartin Matuska 			archive_entry_stat(in_entry)))
598*caf54c4fSMartin Matuska 			continue;
599*caf54c4fSMartin Matuska 		if (lafe_excluded(bsdtar->matching, archive_entry_pathname(in_entry)))
600*caf54c4fSMartin Matuska 			continue;
601*caf54c4fSMartin Matuska 		if (bsdtar->option_interactive &&
602*caf54c4fSMartin Matuska 		    !yes("copy '%s'", archive_entry_pathname(in_entry)))
603*caf54c4fSMartin Matuska 			continue;
604*caf54c4fSMartin Matuska 		if (bsdtar->verbose)
605*caf54c4fSMartin Matuska 			safe_fprintf(stderr, "a %s",
606*caf54c4fSMartin Matuska 			    archive_entry_pathname(in_entry));
607*caf54c4fSMartin Matuska 		if (need_report())
608*caf54c4fSMartin Matuska 			report_write(bsdtar, a, in_entry, 0);
609*caf54c4fSMartin Matuska 
610*caf54c4fSMartin Matuska 		e = archive_write_header(a, in_entry);
611*caf54c4fSMartin Matuska 		if (e != ARCHIVE_OK) {
612*caf54c4fSMartin Matuska 			if (!bsdtar->verbose)
613*caf54c4fSMartin Matuska 				lafe_warnc(0, "%s: %s",
614*caf54c4fSMartin Matuska 				    archive_entry_pathname(in_entry),
615*caf54c4fSMartin Matuska 				    archive_error_string(a));
616*caf54c4fSMartin Matuska 			else
617*caf54c4fSMartin Matuska 				fprintf(stderr, ": %s", archive_error_string(a));
618*caf54c4fSMartin Matuska 		}
619*caf54c4fSMartin Matuska 		if (e == ARCHIVE_FATAL)
620*caf54c4fSMartin Matuska 			exit(1);
621*caf54c4fSMartin Matuska 
622*caf54c4fSMartin Matuska 		if (e >= ARCHIVE_WARN) {
623*caf54c4fSMartin Matuska 			if (archive_entry_size(in_entry) == 0)
624*caf54c4fSMartin Matuska 				archive_read_data_skip(ina);
625*caf54c4fSMartin Matuska 			else if (copy_file_data(bsdtar, a, ina, in_entry))
626*caf54c4fSMartin Matuska 				exit(1);
627*caf54c4fSMartin Matuska 		}
628*caf54c4fSMartin Matuska 
629*caf54c4fSMartin Matuska 		if (bsdtar->verbose)
630*caf54c4fSMartin Matuska 			fprintf(stderr, "\n");
631*caf54c4fSMartin Matuska 	}
632*caf54c4fSMartin Matuska 
633*caf54c4fSMartin Matuska 	return (e == ARCHIVE_EOF ? ARCHIVE_OK : e);
634*caf54c4fSMartin Matuska }
635*caf54c4fSMartin Matuska 
636*caf54c4fSMartin Matuska /* Helper function to copy data between archives. */
637*caf54c4fSMartin Matuska static int
638*caf54c4fSMartin Matuska copy_file_data(struct bsdtar *bsdtar, struct archive *a,
639*caf54c4fSMartin Matuska     struct archive *ina, struct archive_entry *entry)
640*caf54c4fSMartin Matuska {
641*caf54c4fSMartin Matuska 	ssize_t	bytes_read;
642*caf54c4fSMartin Matuska 	ssize_t	bytes_written;
643*caf54c4fSMartin Matuska 	int64_t	progress = 0;
644*caf54c4fSMartin Matuska 
645*caf54c4fSMartin Matuska 	bytes_read = archive_read_data(ina, bsdtar->buff, FILEDATABUFLEN);
646*caf54c4fSMartin Matuska 	while (bytes_read > 0) {
647*caf54c4fSMartin Matuska 		if (need_report())
648*caf54c4fSMartin Matuska 			report_write(bsdtar, a, entry, progress);
649*caf54c4fSMartin Matuska 
650*caf54c4fSMartin Matuska 		bytes_written = archive_write_data(a, bsdtar->buff,
651*caf54c4fSMartin Matuska 		    bytes_read);
652*caf54c4fSMartin Matuska 		if (bytes_written < bytes_read) {
653*caf54c4fSMartin Matuska 			lafe_warnc(0, "%s", archive_error_string(a));
654*caf54c4fSMartin Matuska 			return (-1);
655*caf54c4fSMartin Matuska 		}
656*caf54c4fSMartin Matuska 		progress += bytes_written;
657*caf54c4fSMartin Matuska 		bytes_read = archive_read_data(ina, bsdtar->buff,
658*caf54c4fSMartin Matuska 		    FILEDATABUFLEN);
659*caf54c4fSMartin Matuska 	}
660*caf54c4fSMartin Matuska 
661*caf54c4fSMartin Matuska 	return (0);
662*caf54c4fSMartin Matuska }
663*caf54c4fSMartin Matuska 
664*caf54c4fSMartin Matuska /*
665*caf54c4fSMartin Matuska  * Add the file or dir hierarchy named by 'path' to the archive
666*caf54c4fSMartin Matuska  */
667*caf54c4fSMartin Matuska static void
668*caf54c4fSMartin Matuska write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path)
669*caf54c4fSMartin Matuska {
670*caf54c4fSMartin Matuska 	struct archive_entry *entry = NULL, *spare_entry = NULL;
671*caf54c4fSMartin Matuska 	struct tree *tree;
672*caf54c4fSMartin Matuska 	char symlink_mode = bsdtar->symlink_mode;
673*caf54c4fSMartin Matuska 	dev_t first_dev = 0;
674*caf54c4fSMartin Matuska 	int dev_recorded = 0;
675*caf54c4fSMartin Matuska 	int tree_ret;
676*caf54c4fSMartin Matuska 
677*caf54c4fSMartin Matuska 	tree = tree_open(path);
678*caf54c4fSMartin Matuska 
679*caf54c4fSMartin Matuska 	if (!tree) {
680*caf54c4fSMartin Matuska 		lafe_warnc(errno, "%s: Cannot open", path);
681*caf54c4fSMartin Matuska 		bsdtar->return_value = 1;
682*caf54c4fSMartin Matuska 		return;
683*caf54c4fSMartin Matuska 	}
684*caf54c4fSMartin Matuska 
685*caf54c4fSMartin Matuska 	while ((tree_ret = tree_next(tree)) != 0) {
686*caf54c4fSMartin Matuska 		int r;
687*caf54c4fSMartin Matuska 		const char *name = tree_current_path(tree);
688*caf54c4fSMartin Matuska 		const struct stat *st = NULL; /* info to use for this entry */
689*caf54c4fSMartin Matuska 		const struct stat *lst = NULL; /* lstat() information */
690*caf54c4fSMartin Matuska 		int descend;
691*caf54c4fSMartin Matuska 
692*caf54c4fSMartin Matuska 		if (tree_ret == TREE_ERROR_FATAL)
693*caf54c4fSMartin Matuska 			lafe_errc(1, tree_errno(tree),
694*caf54c4fSMartin Matuska 			    "%s: Unable to continue traversing directory tree",
695*caf54c4fSMartin Matuska 			    name);
696*caf54c4fSMartin Matuska 		if (tree_ret == TREE_ERROR_DIR) {
697*caf54c4fSMartin Matuska 			lafe_warnc(errno,
698*caf54c4fSMartin Matuska 			    "%s: Couldn't visit directory", name);
699*caf54c4fSMartin Matuska 			bsdtar->return_value = 1;
700*caf54c4fSMartin Matuska 		}
701*caf54c4fSMartin Matuska 		if (tree_ret != TREE_REGULAR)
702*caf54c4fSMartin Matuska 			continue;
703*caf54c4fSMartin Matuska 
704*caf54c4fSMartin Matuska 		/*
705*caf54c4fSMartin Matuska 		 * If this file/dir is excluded by a filename
706*caf54c4fSMartin Matuska 		 * pattern, skip it.
707*caf54c4fSMartin Matuska 		 */
708*caf54c4fSMartin Matuska 		if (lafe_excluded(bsdtar->matching, name))
709*caf54c4fSMartin Matuska 			continue;
710*caf54c4fSMartin Matuska 
711*caf54c4fSMartin Matuska 		/*
712*caf54c4fSMartin Matuska 		 * Get lstat() info from the tree library.
713*caf54c4fSMartin Matuska 		 */
714*caf54c4fSMartin Matuska 		lst = tree_current_lstat(tree);
715*caf54c4fSMartin Matuska 		if (lst == NULL) {
716*caf54c4fSMartin Matuska 			/* Couldn't lstat(); must not exist. */
717*caf54c4fSMartin Matuska 			lafe_warnc(errno, "%s: Cannot stat", name);
718*caf54c4fSMartin Matuska 			/* Return error if files disappear during traverse. */
719*caf54c4fSMartin Matuska 			bsdtar->return_value = 1;
720*caf54c4fSMartin Matuska 			continue;
721*caf54c4fSMartin Matuska 		}
722*caf54c4fSMartin Matuska 
723*caf54c4fSMartin Matuska 		/*
724*caf54c4fSMartin Matuska 		 * Distinguish 'L'/'P'/'H' symlink following.
725*caf54c4fSMartin Matuska 		 */
726*caf54c4fSMartin Matuska 		switch(symlink_mode) {
727*caf54c4fSMartin Matuska 		case 'H':
728*caf54c4fSMartin Matuska 			/* 'H': After the first item, rest like 'P'. */
729*caf54c4fSMartin Matuska 			symlink_mode = 'P';
730*caf54c4fSMartin Matuska 			/* 'H': First item (from command line) like 'L'. */
731*caf54c4fSMartin Matuska 			/* FALLTHROUGH */
732*caf54c4fSMartin Matuska 		case 'L':
733*caf54c4fSMartin Matuska 			/* 'L': Do descend through a symlink to dir. */
734*caf54c4fSMartin Matuska 			descend = tree_current_is_dir(tree);
735*caf54c4fSMartin Matuska 			/* 'L': Follow symlinks to files. */
736*caf54c4fSMartin Matuska 			archive_read_disk_set_symlink_logical(bsdtar->diskreader);
737*caf54c4fSMartin Matuska 			/* 'L': Archive symlinks as targets, if we can. */
738*caf54c4fSMartin Matuska 			st = tree_current_stat(tree);
739*caf54c4fSMartin Matuska 			if (st != NULL)
740*caf54c4fSMartin Matuska 				break;
741*caf54c4fSMartin Matuska 			/* If stat fails, we have a broken symlink;
742*caf54c4fSMartin Matuska 			 * in that case, don't follow the link. */
743*caf54c4fSMartin Matuska 			/* FALLTHROUGH */
744*caf54c4fSMartin Matuska 		default:
745*caf54c4fSMartin Matuska 			/* 'P': Don't descend through a symlink to dir. */
746*caf54c4fSMartin Matuska 			descend = tree_current_is_physical_dir(tree);
747*caf54c4fSMartin Matuska 			/* 'P': Don't follow symlinks to files. */
748*caf54c4fSMartin Matuska 			archive_read_disk_set_symlink_physical(bsdtar->diskreader);
749*caf54c4fSMartin Matuska 			/* 'P': Archive symlinks as symlinks. */
750*caf54c4fSMartin Matuska 			st = lst;
751*caf54c4fSMartin Matuska 			break;
752*caf54c4fSMartin Matuska 		}
753*caf54c4fSMartin Matuska 
754*caf54c4fSMartin Matuska 		/*
755*caf54c4fSMartin Matuska 		 * Are we about to cross to a new filesystem?
756*caf54c4fSMartin Matuska 		 */
757*caf54c4fSMartin Matuska 		if (!dev_recorded) {
758*caf54c4fSMartin Matuska 			/* This is the initial file system. */
759*caf54c4fSMartin Matuska 			first_dev = lst->st_dev;
760*caf54c4fSMartin Matuska 			dev_recorded = 1;
761*caf54c4fSMartin Matuska 		} else if (lst->st_dev == first_dev) {
762*caf54c4fSMartin Matuska 			/* The starting file system is always acceptable. */
763*caf54c4fSMartin Matuska 		} else if (descend == 0) {
764*caf54c4fSMartin Matuska 			/* We're not descending, so no need to check. */
765*caf54c4fSMartin Matuska 		} else if (bsdtar->option_dont_traverse_mounts) {
766*caf54c4fSMartin Matuska 			/* User has asked us not to cross mount points. */
767*caf54c4fSMartin Matuska 			descend = 0;
768*caf54c4fSMartin Matuska 		} else {
769*caf54c4fSMartin Matuska 			/* We're prepared to cross a mount point. */
770*caf54c4fSMartin Matuska 
771*caf54c4fSMartin Matuska 			/* XXX TODO: check whether this filesystem is
772*caf54c4fSMartin Matuska 			 * synthetic and/or local.  Add a new
773*caf54c4fSMartin Matuska 			 * --local-only option to skip non-local
774*caf54c4fSMartin Matuska 			 * filesystems.  Skip synthetic filesystems
775*caf54c4fSMartin Matuska 			 * regardless.
776*caf54c4fSMartin Matuska 			 *
777*caf54c4fSMartin Matuska 			 * The results should be cached, since
778*caf54c4fSMartin Matuska 			 * tree.c doesn't usually visit a directory
779*caf54c4fSMartin Matuska 			 * and the directory contents together.  A simple
780*caf54c4fSMartin Matuska 			 * move-to-front list should perform quite well.
781*caf54c4fSMartin Matuska 			 *
782*caf54c4fSMartin Matuska 			 * This is going to be heavily OS dependent:
783*caf54c4fSMartin Matuska 			 * FreeBSD's statfs() in conjunction with getvfsbyname()
784*caf54c4fSMartin Matuska 			 * provides all of this; NetBSD's statvfs() does
785*caf54c4fSMartin Matuska 			 * most of it; other systems will vary.
786*caf54c4fSMartin Matuska 			 */
787*caf54c4fSMartin Matuska 		}
788*caf54c4fSMartin Matuska 
789*caf54c4fSMartin Matuska 		/*
790*caf54c4fSMartin Matuska 		 * In -u mode, check that the file is newer than what's
791*caf54c4fSMartin Matuska 		 * already in the archive; in all modes, obey --newerXXX flags.
792*caf54c4fSMartin Matuska 		 */
793*caf54c4fSMartin Matuska 		if (!new_enough(bsdtar, name, st))
794*caf54c4fSMartin Matuska 			continue;
795*caf54c4fSMartin Matuska 
796*caf54c4fSMartin Matuska 		archive_entry_free(entry);
797*caf54c4fSMartin Matuska 		entry = archive_entry_new();
798*caf54c4fSMartin Matuska 
799*caf54c4fSMartin Matuska 		archive_entry_set_pathname(entry, name);
800*caf54c4fSMartin Matuska 		archive_entry_copy_sourcepath(entry,
801*caf54c4fSMartin Matuska 		    tree_current_access_path(tree));
802*caf54c4fSMartin Matuska 
803*caf54c4fSMartin Matuska 		/* Populate the archive_entry with metadata from the disk. */
804*caf54c4fSMartin Matuska 		/* XXX TODO: Arrange to open a regular file before
805*caf54c4fSMartin Matuska 		 * calling this so we can pass in an fd and shorten
806*caf54c4fSMartin Matuska 		 * the race to query metadata.  The linkify dance
807*caf54c4fSMartin Matuska 		 * makes this more complex than it might sound. */
808*caf54c4fSMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
809*caf54c4fSMartin Matuska 		/* TODO: tree.c uses stat(), which is badly broken
810*caf54c4fSMartin Matuska 		 * on Windows.  To fix this, we should
811*caf54c4fSMartin Matuska 		 * deprecate tree_current_stat() and provide a new
812*caf54c4fSMartin Matuska 		 * call tree_populate_entry(t, entry).  This call
813*caf54c4fSMartin Matuska 		 * would use stat() internally on POSIX and
814*caf54c4fSMartin Matuska 		 * GetInfoByFileHandle() internally on Windows.
815*caf54c4fSMartin Matuska 		 * This would be another step towards a tree-walker
816*caf54c4fSMartin Matuska 		 * that can be integrated deep into libarchive.
817*caf54c4fSMartin Matuska 		 * For now, just set st to NULL on Windows;
818*caf54c4fSMartin Matuska 		 * archive_read_disk_entry_from_file() should
819*caf54c4fSMartin Matuska 		 * be smart enough to use platform-appropriate
820*caf54c4fSMartin Matuska 		 * ways to probe file information.
821*caf54c4fSMartin Matuska 		 */
822*caf54c4fSMartin Matuska 		st = NULL;
823*caf54c4fSMartin Matuska #endif
824*caf54c4fSMartin Matuska 		r = archive_read_disk_entry_from_file(bsdtar->diskreader,
825*caf54c4fSMartin Matuska 		    entry, -1, st);
826*caf54c4fSMartin Matuska 		if (bsdtar->uid >= 0) {
827*caf54c4fSMartin Matuska 			archive_entry_set_uid(entry, bsdtar->uid);
828*caf54c4fSMartin Matuska 			if (!bsdtar->uname)
829*caf54c4fSMartin Matuska 				archive_entry_set_uname(entry,
830*caf54c4fSMartin Matuska 				    archive_read_disk_uname(bsdtar->diskreader,
831*caf54c4fSMartin Matuska 					bsdtar->uid));
832*caf54c4fSMartin Matuska 		}
833*caf54c4fSMartin Matuska 		if (bsdtar->gid >= 0) {
834*caf54c4fSMartin Matuska 			archive_entry_set_gid(entry, bsdtar->gid);
835*caf54c4fSMartin Matuska 			if (!bsdtar->gname)
836*caf54c4fSMartin Matuska 				archive_entry_set_gname(entry,
837*caf54c4fSMartin Matuska 				    archive_read_disk_gname(bsdtar->diskreader,
838*caf54c4fSMartin Matuska 					bsdtar->gid));
839*caf54c4fSMartin Matuska 		}
840*caf54c4fSMartin Matuska 		if (bsdtar->uname)
841*caf54c4fSMartin Matuska 			archive_entry_set_uname(entry, bsdtar->uname);
842*caf54c4fSMartin Matuska 		if (bsdtar->gname)
843*caf54c4fSMartin Matuska 			archive_entry_set_gname(entry, bsdtar->gname);
844*caf54c4fSMartin Matuska 		if (r != ARCHIVE_OK)
845*caf54c4fSMartin Matuska 			lafe_warnc(archive_errno(bsdtar->diskreader),
846*caf54c4fSMartin Matuska 			    "%s", archive_error_string(bsdtar->diskreader));
847*caf54c4fSMartin Matuska 		if (r < ARCHIVE_WARN)
848*caf54c4fSMartin Matuska 			continue;
849*caf54c4fSMartin Matuska 
850*caf54c4fSMartin Matuska 		/* XXX TODO: Just use flag data from entry; avoid the
851*caf54c4fSMartin Matuska 		 * duplicate check here. */
852*caf54c4fSMartin Matuska 
853*caf54c4fSMartin Matuska 		/*
854*caf54c4fSMartin Matuska 		 * If this file/dir is flagged "nodump" and we're
855*caf54c4fSMartin Matuska 		 * honoring such flags, skip this file/dir.
856*caf54c4fSMartin Matuska 		 */
857*caf54c4fSMartin Matuska #if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
858*caf54c4fSMartin Matuska 		/* BSD systems store flags in struct stat */
859*caf54c4fSMartin Matuska 		if (bsdtar->option_honor_nodump &&
860*caf54c4fSMartin Matuska 		    (lst->st_flags & UF_NODUMP))
861*caf54c4fSMartin Matuska 			continue;
862*caf54c4fSMartin Matuska #endif
863*caf54c4fSMartin Matuska 
864*caf54c4fSMartin Matuska #if defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL)
865*caf54c4fSMartin Matuska 		/* Linux uses ioctl to read flags. */
866*caf54c4fSMartin Matuska 		if (bsdtar->option_honor_nodump) {
867*caf54c4fSMartin Matuska 			int fd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY);
868*caf54c4fSMartin Matuska 			if (fd >= 0) {
869*caf54c4fSMartin Matuska 				unsigned long fflags;
870*caf54c4fSMartin Matuska 				int r = ioctl(fd, EXT2_IOC_GETFLAGS, &fflags);
871*caf54c4fSMartin Matuska 				close(fd);
872*caf54c4fSMartin Matuska 				if (r >= 0 && (fflags & EXT2_NODUMP_FL))
873*caf54c4fSMartin Matuska 					continue;
874*caf54c4fSMartin Matuska 			}
875*caf54c4fSMartin Matuska 		}
876*caf54c4fSMartin Matuska #endif
877*caf54c4fSMartin Matuska 
878*caf54c4fSMartin Matuska 		/*
879*caf54c4fSMartin Matuska 		 * If the user vetoes this file/directory, skip it.
880*caf54c4fSMartin Matuska 		 * We want this to be fairly late; if some other
881*caf54c4fSMartin Matuska 		 * check would veto this file, we shouldn't bother
882*caf54c4fSMartin Matuska 		 * the user with it.
883*caf54c4fSMartin Matuska 		 */
884*caf54c4fSMartin Matuska 		if (bsdtar->option_interactive &&
885*caf54c4fSMartin Matuska 		    !yes("add '%s'", name))
886*caf54c4fSMartin Matuska 			continue;
887*caf54c4fSMartin Matuska 
888*caf54c4fSMartin Matuska 		/* Note: if user vetoes, we won't descend. */
889*caf54c4fSMartin Matuska 		if (descend && !bsdtar->option_no_subdirs)
890*caf54c4fSMartin Matuska 			tree_descend(tree);
891*caf54c4fSMartin Matuska 
892*caf54c4fSMartin Matuska 		/*
893*caf54c4fSMartin Matuska 		 * Rewrite the pathname to be archived.  If rewrite
894*caf54c4fSMartin Matuska 		 * fails, skip the entry.
895*caf54c4fSMartin Matuska 		 */
896*caf54c4fSMartin Matuska 		if (edit_pathname(bsdtar, entry))
897*caf54c4fSMartin Matuska 			continue;
898*caf54c4fSMartin Matuska 
899*caf54c4fSMartin Matuska 		/* Display entry as we process it.
900*caf54c4fSMartin Matuska 		 * This format is required by SUSv2. */
901*caf54c4fSMartin Matuska 		if (bsdtar->verbose)
902*caf54c4fSMartin Matuska 			safe_fprintf(stderr, "a %s",
903*caf54c4fSMartin Matuska 			    archive_entry_pathname(entry));
904*caf54c4fSMartin Matuska 
905*caf54c4fSMartin Matuska 		/* Non-regular files get archived with zero size. */
906*caf54c4fSMartin Matuska 		if (archive_entry_filetype(entry) != AE_IFREG)
907*caf54c4fSMartin Matuska 			archive_entry_set_size(entry, 0);
908*caf54c4fSMartin Matuska 
909*caf54c4fSMartin Matuska 		archive_entry_linkify(bsdtar->resolver, &entry, &spare_entry);
910*caf54c4fSMartin Matuska 
911*caf54c4fSMartin Matuska 		while (entry != NULL) {
912*caf54c4fSMartin Matuska 			write_entry_backend(bsdtar, a, entry);
913*caf54c4fSMartin Matuska 			archive_entry_free(entry);
914*caf54c4fSMartin Matuska 			entry = spare_entry;
915*caf54c4fSMartin Matuska 			spare_entry = NULL;
916*caf54c4fSMartin Matuska 		}
917*caf54c4fSMartin Matuska 
918*caf54c4fSMartin Matuska 		if (bsdtar->verbose)
919*caf54c4fSMartin Matuska 			fprintf(stderr, "\n");
920*caf54c4fSMartin Matuska 	}
921*caf54c4fSMartin Matuska 	archive_entry_free(entry);
922*caf54c4fSMartin Matuska 	tree_close(tree);
923*caf54c4fSMartin Matuska }
924*caf54c4fSMartin Matuska 
925*caf54c4fSMartin Matuska /*
926*caf54c4fSMartin Matuska  * Backend for write_entry.
927*caf54c4fSMartin Matuska  */
928*caf54c4fSMartin Matuska static void
929*caf54c4fSMartin Matuska write_entry_backend(struct bsdtar *bsdtar, struct archive *a,
930*caf54c4fSMartin Matuska     struct archive_entry *entry)
931*caf54c4fSMartin Matuska {
932*caf54c4fSMartin Matuska 	int fd = -1;
933*caf54c4fSMartin Matuska 	int e;
934*caf54c4fSMartin Matuska 
935*caf54c4fSMartin Matuska 	if (archive_entry_size(entry) > 0) {
936*caf54c4fSMartin Matuska 		const char *pathname = archive_entry_sourcepath(entry);
937*caf54c4fSMartin Matuska 		fd = open(pathname, O_RDONLY | O_BINARY);
938*caf54c4fSMartin Matuska 		if (fd == -1) {
939*caf54c4fSMartin Matuska 			if (!bsdtar->verbose)
940*caf54c4fSMartin Matuska 				lafe_warnc(errno,
941*caf54c4fSMartin Matuska 				    "%s: could not open file", pathname);
942*caf54c4fSMartin Matuska 			else
943*caf54c4fSMartin Matuska 				fprintf(stderr, ": %s", strerror(errno));
944*caf54c4fSMartin Matuska 			return;
945*caf54c4fSMartin Matuska 		}
946*caf54c4fSMartin Matuska 	}
947*caf54c4fSMartin Matuska 
948*caf54c4fSMartin Matuska 	e = archive_write_header(a, entry);
949*caf54c4fSMartin Matuska 	if (e != ARCHIVE_OK) {
950*caf54c4fSMartin Matuska 		if (!bsdtar->verbose)
951*caf54c4fSMartin Matuska 			lafe_warnc(0, "%s: %s",
952*caf54c4fSMartin Matuska 			    archive_entry_pathname(entry),
953*caf54c4fSMartin Matuska 			    archive_error_string(a));
954*caf54c4fSMartin Matuska 		else
955*caf54c4fSMartin Matuska 			fprintf(stderr, ": %s", archive_error_string(a));
956*caf54c4fSMartin Matuska 	}
957*caf54c4fSMartin Matuska 
958*caf54c4fSMartin Matuska 	if (e == ARCHIVE_FATAL)
959*caf54c4fSMartin Matuska 		exit(1);
960*caf54c4fSMartin Matuska 
961*caf54c4fSMartin Matuska 	/*
962*caf54c4fSMartin Matuska 	 * If we opened a file earlier, write it out now.  Note that
963*caf54c4fSMartin Matuska 	 * the format handler might have reset the size field to zero
964*caf54c4fSMartin Matuska 	 * to inform us that the archive body won't get stored.  In
965*caf54c4fSMartin Matuska 	 * that case, just skip the write.
966*caf54c4fSMartin Matuska 	 */
967*caf54c4fSMartin Matuska 	if (e >= ARCHIVE_WARN && fd >= 0 && archive_entry_size(entry) > 0) {
968*caf54c4fSMartin Matuska 		if (write_file_data(bsdtar, a, entry, fd))
969*caf54c4fSMartin Matuska 			exit(1);
970*caf54c4fSMartin Matuska 	}
971*caf54c4fSMartin Matuska 
972*caf54c4fSMartin Matuska 	/*
973*caf54c4fSMartin Matuska 	 * If we opened a file, close it now even if there was an error
974*caf54c4fSMartin Matuska 	 * which made us decide not to write the archive body.
975*caf54c4fSMartin Matuska 	 */
976*caf54c4fSMartin Matuska 	if (fd >= 0)
977*caf54c4fSMartin Matuska 		close(fd);
978*caf54c4fSMartin Matuska }
979*caf54c4fSMartin Matuska 
980*caf54c4fSMartin Matuska static void
981*caf54c4fSMartin Matuska report_write(struct bsdtar *bsdtar, struct archive *a,
982*caf54c4fSMartin Matuska     struct archive_entry *entry, int64_t progress)
983*caf54c4fSMartin Matuska {
984*caf54c4fSMartin Matuska 	uint64_t comp, uncomp;
985*caf54c4fSMartin Matuska 	if (bsdtar->verbose)
986*caf54c4fSMartin Matuska 		fprintf(stderr, "\n");
987*caf54c4fSMartin Matuska 	comp = archive_position_compressed(a);
988*caf54c4fSMartin Matuska 	uncomp = archive_position_uncompressed(a);
989*caf54c4fSMartin Matuska 	fprintf(stderr, "In: %d files, %s bytes;",
990*caf54c4fSMartin Matuska 	    archive_file_count(a), tar_i64toa(uncomp));
991*caf54c4fSMartin Matuska 	fprintf(stderr,
992*caf54c4fSMartin Matuska 	    " Out: %s bytes, compression %d%%\n",
993*caf54c4fSMartin Matuska 	    tar_i64toa(comp), (int)((uncomp - comp) * 100 / uncomp));
994*caf54c4fSMartin Matuska 	/* Can't have two calls to tar_i64toa() pending, so split the output. */
995*caf54c4fSMartin Matuska 	safe_fprintf(stderr, "Current: %s (%s",
996*caf54c4fSMartin Matuska 	    archive_entry_pathname(entry),
997*caf54c4fSMartin Matuska 	    tar_i64toa(progress));
998*caf54c4fSMartin Matuska 	fprintf(stderr, "/%s bytes)\n",
999*caf54c4fSMartin Matuska 	    tar_i64toa(archive_entry_size(entry)));
1000*caf54c4fSMartin Matuska }
1001*caf54c4fSMartin Matuska 
1002*caf54c4fSMartin Matuska 
1003*caf54c4fSMartin Matuska /* Helper function to copy file to archive. */
1004*caf54c4fSMartin Matuska static int
1005*caf54c4fSMartin Matuska write_file_data(struct bsdtar *bsdtar, struct archive *a,
1006*caf54c4fSMartin Matuska     struct archive_entry *entry, int fd)
1007*caf54c4fSMartin Matuska {
1008*caf54c4fSMartin Matuska 	ssize_t	bytes_read;
1009*caf54c4fSMartin Matuska 	ssize_t	bytes_written;
1010*caf54c4fSMartin Matuska 	int64_t	progress = 0;
1011*caf54c4fSMartin Matuska 
1012*caf54c4fSMartin Matuska 	bytes_read = read(fd, bsdtar->buff, FILEDATABUFLEN);
1013*caf54c4fSMartin Matuska 	while (bytes_read > 0) {
1014*caf54c4fSMartin Matuska 		if (need_report())
1015*caf54c4fSMartin Matuska 			report_write(bsdtar, a, entry, progress);
1016*caf54c4fSMartin Matuska 
1017*caf54c4fSMartin Matuska 		bytes_written = archive_write_data(a, bsdtar->buff,
1018*caf54c4fSMartin Matuska 		    bytes_read);
1019*caf54c4fSMartin Matuska 		if (bytes_written < 0) {
1020*caf54c4fSMartin Matuska 			/* Write failed; this is bad */
1021*caf54c4fSMartin Matuska 			lafe_warnc(0, "%s", archive_error_string(a));
1022*caf54c4fSMartin Matuska 			return (-1);
1023*caf54c4fSMartin Matuska 		}
1024*caf54c4fSMartin Matuska 		if (bytes_written < bytes_read) {
1025*caf54c4fSMartin Matuska 			/* Write was truncated; warn but continue. */
1026*caf54c4fSMartin Matuska 			lafe_warnc(0,
1027*caf54c4fSMartin Matuska 			    "%s: Truncated write; file may have grown while being archived.",
1028*caf54c4fSMartin Matuska 			    archive_entry_pathname(entry));
1029*caf54c4fSMartin Matuska 			return (0);
1030*caf54c4fSMartin Matuska 		}
1031*caf54c4fSMartin Matuska 		progress += bytes_written;
1032*caf54c4fSMartin Matuska 		bytes_read = read(fd, bsdtar->buff, FILEDATABUFLEN);
1033*caf54c4fSMartin Matuska 	}
1034*caf54c4fSMartin Matuska 	return 0;
1035*caf54c4fSMartin Matuska }
1036*caf54c4fSMartin Matuska 
1037*caf54c4fSMartin Matuska /*
1038*caf54c4fSMartin Matuska  * Test if the specified file is new enough to include in the archive.
1039*caf54c4fSMartin Matuska  */
1040*caf54c4fSMartin Matuska static int
1041*caf54c4fSMartin Matuska new_enough(struct bsdtar *bsdtar, const char *path, const struct stat *st)
1042*caf54c4fSMartin Matuska {
1043*caf54c4fSMartin Matuska 	struct archive_dir_entry *p;
1044*caf54c4fSMartin Matuska 
1045*caf54c4fSMartin Matuska 	/*
1046*caf54c4fSMartin Matuska 	 * If this file/dir is excluded by a time comparison, skip it.
1047*caf54c4fSMartin Matuska 	 */
1048*caf54c4fSMartin Matuska 	if (bsdtar->newer_ctime_sec > 0) {
1049*caf54c4fSMartin Matuska 		if (st->st_ctime < bsdtar->newer_ctime_sec)
1050*caf54c4fSMartin Matuska 			return (0); /* Too old, skip it. */
1051*caf54c4fSMartin Matuska 		if (st->st_ctime == bsdtar->newer_ctime_sec
1052*caf54c4fSMartin Matuska 		    && ARCHIVE_STAT_CTIME_NANOS(st)
1053*caf54c4fSMartin Matuska 		    <= bsdtar->newer_ctime_nsec)
1054*caf54c4fSMartin Matuska 			return (0); /* Too old, skip it. */
1055*caf54c4fSMartin Matuska 	}
1056*caf54c4fSMartin Matuska 	if (bsdtar->newer_mtime_sec > 0) {
1057*caf54c4fSMartin Matuska 		if (st->st_mtime < bsdtar->newer_mtime_sec)
1058*caf54c4fSMartin Matuska 			return (0); /* Too old, skip it. */
1059*caf54c4fSMartin Matuska 		if (st->st_mtime == bsdtar->newer_mtime_sec
1060*caf54c4fSMartin Matuska 		    && ARCHIVE_STAT_MTIME_NANOS(st)
1061*caf54c4fSMartin Matuska 		    <= bsdtar->newer_mtime_nsec)
1062*caf54c4fSMartin Matuska 			return (0); /* Too old, skip it. */
1063*caf54c4fSMartin Matuska 	}
1064*caf54c4fSMartin Matuska 
1065*caf54c4fSMartin Matuska 	/*
1066*caf54c4fSMartin Matuska 	 * In -u mode, we only write an entry if it's newer than
1067*caf54c4fSMartin Matuska 	 * what was already in the archive.
1068*caf54c4fSMartin Matuska 	 */
1069*caf54c4fSMartin Matuska 	if (bsdtar->archive_dir != NULL &&
1070*caf54c4fSMartin Matuska 	    bsdtar->archive_dir->head != NULL) {
1071*caf54c4fSMartin Matuska 		for (p = bsdtar->archive_dir->head; p != NULL; p = p->next) {
1072*caf54c4fSMartin Matuska 			if (pathcmp(path, p->name)==0)
1073*caf54c4fSMartin Matuska 				return (p->mtime_sec < st->st_mtime ||
1074*caf54c4fSMartin Matuska 				    (p->mtime_sec == st->st_mtime &&
1075*caf54c4fSMartin Matuska 					p->mtime_nsec
1076*caf54c4fSMartin Matuska 					< ARCHIVE_STAT_MTIME_NANOS(st)));
1077*caf54c4fSMartin Matuska 		}
1078*caf54c4fSMartin Matuska 	}
1079*caf54c4fSMartin Matuska 
1080*caf54c4fSMartin Matuska 	/* If the file wasn't rejected, include it. */
1081*caf54c4fSMartin Matuska 	return (1);
1082*caf54c4fSMartin Matuska }
1083*caf54c4fSMartin Matuska 
1084*caf54c4fSMartin Matuska /*
1085*caf54c4fSMartin Matuska  * Add an entry to the dir list for 'u' mode.
1086*caf54c4fSMartin Matuska  *
1087*caf54c4fSMartin Matuska  * XXX TODO: Make this fast.
1088*caf54c4fSMartin Matuska  */
1089*caf54c4fSMartin Matuska static void
1090*caf54c4fSMartin Matuska add_dir_list(struct bsdtar *bsdtar, const char *path,
1091*caf54c4fSMartin Matuska     time_t mtime_sec, int mtime_nsec)
1092*caf54c4fSMartin Matuska {
1093*caf54c4fSMartin Matuska 	struct archive_dir_entry	*p;
1094*caf54c4fSMartin Matuska 
1095*caf54c4fSMartin Matuska 	/*
1096*caf54c4fSMartin Matuska 	 * Search entire list to see if this file has appeared before.
1097*caf54c4fSMartin Matuska 	 * If it has, override the timestamp data.
1098*caf54c4fSMartin Matuska 	 */
1099*caf54c4fSMartin Matuska 	p = bsdtar->archive_dir->head;
1100*caf54c4fSMartin Matuska 	while (p != NULL) {
1101*caf54c4fSMartin Matuska 		if (strcmp(path, p->name)==0) {
1102*caf54c4fSMartin Matuska 			p->mtime_sec = mtime_sec;
1103*caf54c4fSMartin Matuska 			p->mtime_nsec = mtime_nsec;
1104*caf54c4fSMartin Matuska 			return;
1105*caf54c4fSMartin Matuska 		}
1106*caf54c4fSMartin Matuska 		p = p->next;
1107*caf54c4fSMartin Matuska 	}
1108*caf54c4fSMartin Matuska 
1109*caf54c4fSMartin Matuska 	p = malloc(sizeof(*p));
1110*caf54c4fSMartin Matuska 	if (p == NULL)
1111*caf54c4fSMartin Matuska 		lafe_errc(1, ENOMEM, "Can't read archive directory");
1112*caf54c4fSMartin Matuska 
1113*caf54c4fSMartin Matuska 	p->name = strdup(path);
1114*caf54c4fSMartin Matuska 	if (p->name == NULL)
1115*caf54c4fSMartin Matuska 		lafe_errc(1, ENOMEM, "Can't read archive directory");
1116*caf54c4fSMartin Matuska 	p->mtime_sec = mtime_sec;
1117*caf54c4fSMartin Matuska 	p->mtime_nsec = mtime_nsec;
1118*caf54c4fSMartin Matuska 	p->next = NULL;
1119*caf54c4fSMartin Matuska 	if (bsdtar->archive_dir->tail == NULL) {
1120*caf54c4fSMartin Matuska 		bsdtar->archive_dir->head = bsdtar->archive_dir->tail = p;
1121*caf54c4fSMartin Matuska 	} else {
1122*caf54c4fSMartin Matuska 		bsdtar->archive_dir->tail->next = p;
1123*caf54c4fSMartin Matuska 		bsdtar->archive_dir->tail = p;
1124*caf54c4fSMartin Matuska 	}
1125*caf54c4fSMartin Matuska }
1126*caf54c4fSMartin Matuska 
1127*caf54c4fSMartin Matuska static void
1128*caf54c4fSMartin Matuska test_for_append(struct bsdtar *bsdtar)
1129*caf54c4fSMartin Matuska {
1130*caf54c4fSMartin Matuska 	struct stat s;
1131*caf54c4fSMartin Matuska 
1132*caf54c4fSMartin Matuska 	if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL)
1133*caf54c4fSMartin Matuska 		lafe_errc(1, 0, "no files or directories specified");
1134*caf54c4fSMartin Matuska 	if (bsdtar->filename == NULL)
1135*caf54c4fSMartin Matuska 		lafe_errc(1, 0, "Cannot append to stdout.");
1136*caf54c4fSMartin Matuska 
1137*caf54c4fSMartin Matuska 	if (bsdtar->create_compression != 0)
1138*caf54c4fSMartin Matuska 		lafe_errc(1, 0,
1139*caf54c4fSMartin Matuska 		    "Cannot append to %s with compression", bsdtar->filename);
1140*caf54c4fSMartin Matuska 
1141*caf54c4fSMartin Matuska 	if (stat(bsdtar->filename, &s) != 0)
1142*caf54c4fSMartin Matuska 		return;
1143*caf54c4fSMartin Matuska 
1144*caf54c4fSMartin Matuska 	if (!S_ISREG(s.st_mode) && !S_ISBLK(s.st_mode))
1145*caf54c4fSMartin Matuska 		lafe_errc(1, 0,
1146*caf54c4fSMartin Matuska 		    "Cannot append to %s: not a regular file.",
1147*caf54c4fSMartin Matuska 		    bsdtar->filename);
1148*caf54c4fSMartin Matuska 
1149*caf54c4fSMartin Matuska /* Is this an appropriate check here on Windows? */
1150*caf54c4fSMartin Matuska /*
1151*caf54c4fSMartin Matuska 	if (GetFileType(handle) != FILE_TYPE_DISK)
1152*caf54c4fSMartin Matuska 		lafe_errc(1, 0, "Cannot append");
1153*caf54c4fSMartin Matuska */
1154*caf54c4fSMartin Matuska 
1155*caf54c4fSMartin Matuska }
1156