~akopytov/percona-xtrabackup/bug1166888-2.1

« back to all changes in this revision

Viewing changes to src/libarchive/tar/write.c

  • Committer: Alexey Kopytov
  • Date: 2012-02-10 20:05:56 UTC
  • mto: (391.1.5 staging)
  • mto: This revision was merged to the branch mainline in revision 390.
  • Revision ID: akopytov@gmail.com-20120210200556-6kx41z8wwrqfucro
Rebase of the parallel compression patch on new trunk + post-review
fixes.

Implementation of parallel compression and streaming for XtraBackup.

This revision implements the following changes:

* InnoDB files are now streamed by the xtrabackup binary rather than
innobackupex. As a result, integrity is now verified by xtrabackup and
thus tar4ibd is no longer needed, so it was removed.

* xtrabackup binary now accepts the new '--stream' option which has
exactly the same semantics as the '--stream' option in
innobackupex: it tells xtrabackup to stream all files to the standard
output in the specified format rather than storing them locally.

* The xtrabackup binary can now do parallel compression using the
quicklz library. Two new options were added to xtrabackup to support
this feature:

- '--compress' tells xtrabackup to compress all output data, including
the transaction log file and meta data files, using the specified
compression algorithm. The only currently supported algorithm is
'quicklz'. The resulting files have the qpress archive format,
i.e. every *.qp file produced by xtrabackup is essentially a one-file
qpress archive and can be extracted and uncompressed by the qpress
file archiver (http://www.quicklz.com/).

- '--compress-threads' specifies the number of worker threads used by
xtrabackup for parallel data compression. This option defaults to 1.

Parallel compression ('--compress-threads') can be used together with
parallel file copying ('--parallel'). For example, '--parallel=4
--compress --compress-threads=2' will create 4 IO threads that will
read the data and pipe it to 2 compression threads.

* To support simultaneous compression and streaming, a new custom
streaming format called 'xbstream' was introduced to XtraBackup in
addition to the 'tar' format. That was required to overcome some
limitations of traditional archive formats such as 'tar', 'cpio' and
others that do not allow streaming dynamically generated files, for
example dynamically compressed files.  Other advantages of xbstream over
traditional streaming/archive formats include ability to stream multiple
files concurrently (so it is possible to use streaming in the xbstream
format together with the --parallel option) and more compact data
storage.

* To allow streaming and extracting files to/from the xbstream format
produced by xtrabackup, a new utility aptly called 'xbstream' was
added to the XtraBackup distribution. This utility has a tar-like
interface:

- with the '-x' option it extracts files from the stream read from its
standard input to the current directory unless specified otherwise
with the '-C' option.

- with the '-c' option it streams files specified on the command line
to its standard output.

The utility also tries to minimize its impact on the OS page cache by
using the appropriate posix_fadvise() calls when available.

Show diffs side-by-side

added added

removed removed

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