~akopytov/percona-xtrabackup/bug1166888-2.1

« back to all changes in this revision

Viewing changes to src/libarchive/libarchive/archive_write_set_format_ustar.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 "archive_platform.h"
 
27
__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_ustar.c 191579 2009-04-27 18:35:03Z kientzle $");
 
28
 
 
29
 
 
30
#ifdef HAVE_ERRNO_H
 
31
#include <errno.h>
 
32
#endif
 
33
#include <stdio.h>
 
34
#ifdef HAVE_STDLIB_H
 
35
#include <stdlib.h>
 
36
#endif
 
37
#ifdef HAVE_STRING_H
 
38
#include <string.h>
 
39
#endif
 
40
 
 
41
#include "archive.h"
 
42
#include "archive_entry.h"
 
43
#include "archive_private.h"
 
44
#include "archive_write_private.h"
 
45
 
 
46
struct ustar {
 
47
        uint64_t        entry_bytes_remaining;
 
48
        uint64_t        entry_padding;
 
49
};
 
50
 
 
51
/*
 
52
 * Define structure of POSIX 'ustar' tar header.
 
53
 */
 
54
#define USTAR_name_offset 0
 
55
#define USTAR_name_size 100
 
56
#define USTAR_mode_offset 100
 
57
#define USTAR_mode_size 6
 
58
#define USTAR_mode_max_size 8
 
59
#define USTAR_uid_offset 108
 
60
#define USTAR_uid_size 6
 
61
#define USTAR_uid_max_size 8
 
62
#define USTAR_gid_offset 116
 
63
#define USTAR_gid_size 6
 
64
#define USTAR_gid_max_size 8
 
65
#define USTAR_size_offset 124
 
66
#define USTAR_size_size 11
 
67
#define USTAR_size_max_size 12
 
68
#define USTAR_mtime_offset 136
 
69
#define USTAR_mtime_size 11
 
70
#define USTAR_mtime_max_size 11
 
71
#define USTAR_checksum_offset 148
 
72
#define USTAR_checksum_size 8
 
73
#define USTAR_typeflag_offset 156
 
74
#define USTAR_typeflag_size 1
 
75
#define USTAR_linkname_offset 157
 
76
#define USTAR_linkname_size 100
 
77
#define USTAR_magic_offset 257
 
78
#define USTAR_magic_size 6
 
79
#define USTAR_version_offset 263
 
80
#define USTAR_version_size 2
 
81
#define USTAR_uname_offset 265
 
82
#define USTAR_uname_size 32
 
83
#define USTAR_gname_offset 297
 
84
#define USTAR_gname_size 32
 
85
#define USTAR_rdevmajor_offset 329
 
86
#define USTAR_rdevmajor_size 6
 
87
#define USTAR_rdevmajor_max_size 8
 
88
#define USTAR_rdevminor_offset 337
 
89
#define USTAR_rdevminor_size 6
 
90
#define USTAR_rdevminor_max_size 8
 
91
#define USTAR_prefix_offset 345
 
92
#define USTAR_prefix_size 155
 
93
#define USTAR_padding_offset 500
 
94
#define USTAR_padding_size 12
 
95
 
 
96
/*
 
97
 * A filled-in copy of the header for initialization.
 
98
 */
 
99
static const char template_header[] = {
 
100
        /* name: 100 bytes */
 
101
        0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
 
102
        0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
 
103
        0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
 
104
        0,0,0,0,
 
105
        /* Mode, space-null termination: 8 bytes */
 
106
        '0','0','0','0','0','0', ' ','\0',
 
107
        /* uid, space-null termination: 8 bytes */
 
108
        '0','0','0','0','0','0', ' ','\0',
 
109
        /* gid, space-null termination: 8 bytes */
 
110
        '0','0','0','0','0','0', ' ','\0',
 
111
        /* size, space termation: 12 bytes */
 
112
        '0','0','0','0','0','0','0','0','0','0','0', ' ',
 
113
        /* mtime, space termation: 12 bytes */
 
114
        '0','0','0','0','0','0','0','0','0','0','0', ' ',
 
115
        /* Initial checksum value: 8 spaces */
 
116
        ' ',' ',' ',' ',' ',' ',' ',' ',
 
117
        /* Typeflag: 1 byte */
 
118
        '0',                    /* '0' = regular file */
 
119
        /* Linkname: 100 bytes */
 
120
        0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
 
121
        0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
 
122
        0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
 
123
        0,0,0,0,
 
124
        /* Magic: 6 bytes, Version: 2 bytes */
 
125
        'u','s','t','a','r','\0', '0','0',
 
126
        /* Uname: 32 bytes */
 
127
        0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
 
128
        /* Gname: 32 bytes */
 
129
        0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
 
130
        /* rdevmajor + space/null padding: 8 bytes */
 
131
        '0','0','0','0','0','0', ' ','\0',
 
132
        /* rdevminor + space/null padding: 8 bytes */
 
133
        '0','0','0','0','0','0', ' ','\0',
 
134
        /* Prefix: 155 bytes */
 
135
        0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
 
136
        0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
 
137
        0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
 
138
        0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
 
139
        0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,
 
140
        /* Padding: 12 bytes */
 
141
        0,0,0,0,0,0,0,0, 0,0,0,0
 
142
};
 
143
 
 
144
static ssize_t  archive_write_ustar_data(struct archive_write *a, const void *buff,
 
145
                    size_t s);
 
146
static int      archive_write_ustar_destroy(struct archive_write *);
 
147
static int      archive_write_ustar_finish(struct archive_write *);
 
148
static int      archive_write_ustar_finish_entry(struct archive_write *);
 
149
static int      archive_write_ustar_header(struct archive_write *,
 
150
                    struct archive_entry *entry);
 
151
static int      format_256(int64_t, char *, int);
 
152
static int      format_number(int64_t, char *, int size, int max, int strict);
 
153
static int      format_octal(int64_t, char *, int);
 
154
static int      write_nulls(struct archive_write *a, size_t);
 
155
 
 
156
/*
 
157
 * Set output format to 'ustar' format.
 
158
 */
 
159
int
 
160
archive_write_set_format_ustar(struct archive *_a)
 
161
{
 
162
        struct archive_write *a = (struct archive_write *)_a;
 
163
        struct ustar *ustar;
 
164
 
 
165
        /* If someone else was already registered, unregister them. */
 
166
        if (a->format_destroy != NULL)
 
167
                (a->format_destroy)(a);
 
168
 
 
169
        /* Basic internal sanity test. */
 
170
        if (sizeof(template_header) != 512) {
 
171
                archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Internal: template_header wrong size: %d should be 512", sizeof(template_header));
 
172
                return (ARCHIVE_FATAL);
 
173
        }
 
174
 
 
175
        ustar = (struct ustar *)malloc(sizeof(*ustar));
 
176
        if (ustar == NULL) {
 
177
                archive_set_error(&a->archive, ENOMEM, "Can't allocate ustar data");
 
178
                return (ARCHIVE_FATAL);
 
179
        }
 
180
        memset(ustar, 0, sizeof(*ustar));
 
181
        a->format_data = ustar;
 
182
 
 
183
        a->pad_uncompressed = 1;        /* Mimic gtar in this respect. */
 
184
        a->format_name = "ustar";
 
185
        a->format_write_header = archive_write_ustar_header;
 
186
        a->format_write_data = archive_write_ustar_data;
 
187
        a->format_finish = archive_write_ustar_finish;
 
188
        a->format_destroy = archive_write_ustar_destroy;
 
189
        a->format_finish_entry = archive_write_ustar_finish_entry;
 
190
        a->archive.archive_format = ARCHIVE_FORMAT_TAR_USTAR;
 
191
        a->archive.archive_format_name = "POSIX ustar";
 
192
        return (ARCHIVE_OK);
 
193
}
 
194
 
 
195
static int
 
196
archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
 
197
{
 
198
        char buff[512];
 
199
        int ret, ret2;
 
200
        struct ustar *ustar;
 
201
 
 
202
        ustar = (struct ustar *)a->format_data;
 
203
 
 
204
        /* Only regular files (not hardlinks) have data. */
 
205
        if (archive_entry_hardlink(entry) != NULL ||
 
206
            archive_entry_symlink(entry) != NULL ||
 
207
            !(archive_entry_filetype(entry) == AE_IFREG))
 
208
                archive_entry_set_size(entry, 0);
 
209
 
 
210
        if (AE_IFDIR == archive_entry_filetype(entry)) {
 
211
                const char *p;
 
212
                char *t;
 
213
                /*
 
214
                 * Ensure a trailing '/'.  Modify the entry so
 
215
                 * the client sees the change.
 
216
                 */
 
217
                p = archive_entry_pathname(entry);
 
218
                if (p[strlen(p) - 1] != '/') {
 
219
                        t = (char *)malloc(strlen(p) + 2);
 
220
                        if (t == NULL) {
 
221
                                archive_set_error(&a->archive, ENOMEM,
 
222
                                "Can't allocate ustar data");
 
223
                                return(ARCHIVE_FATAL);
 
224
                        }
 
225
                        strcpy(t, p);
 
226
                        strcat(t, "/");
 
227
                        archive_entry_copy_pathname(entry, t);
 
228
                        free(t);
 
229
                }
 
230
        }
 
231
 
 
232
        ret = __archive_write_format_header_ustar(a, buff, entry, -1, 1);
 
233
        if (ret < ARCHIVE_WARN)
 
234
                return (ret);
 
235
        ret2 = (a->compressor.write)(a, buff, 512);
 
236
        if (ret2 < ARCHIVE_WARN)
 
237
                return (ret2);
 
238
        if (ret2 < ret)
 
239
                ret = ret2;
 
240
 
 
241
        ustar->entry_bytes_remaining = archive_entry_size(entry);
 
242
        ustar->entry_padding = 0x1ff & (-(int64_t)ustar->entry_bytes_remaining);
 
243
        return (ret);
 
244
}
 
245
 
 
246
/*
 
247
 * Format a basic 512-byte "ustar" header.
 
248
 *
 
249
 * Returns -1 if format failed (due to field overflow).
 
250
 * Note that this always formats as much of the header as possible.
 
251
 * If "strict" is set to zero, it will extend numeric fields as
 
252
 * necessary (overwriting terminators or using base-256 extensions).
 
253
 *
 
254
 * This is exported so that other 'tar' formats can use it.
 
255
 */
 
256
int
 
257
__archive_write_format_header_ustar(struct archive_write *a, char h[512],
 
258
    struct archive_entry *entry, int tartype, int strict)
 
259
{
 
260
        unsigned int checksum;
 
261
        int i, ret;
 
262
        size_t copy_length;
 
263
        const char *p, *pp;
 
264
        int mytartype;
 
265
 
 
266
        ret = 0;
 
267
        mytartype = -1;
 
268
        /*
 
269
         * The "template header" already includes the "ustar"
 
270
         * signature, various end-of-field markers and other required
 
271
         * elements.
 
272
         */
 
273
        memcpy(h, &template_header, 512);
 
274
 
 
275
        /*
 
276
         * Because the block is already null-filled, and strings
 
277
         * are allowed to exactly fill their destination (without null),
 
278
         * I use memcpy(dest, src, strlen()) here a lot to copy strings.
 
279
         */
 
280
 
 
281
        pp = archive_entry_pathname(entry);
 
282
        if (strlen(pp) <= USTAR_name_size)
 
283
                memcpy(h + USTAR_name_offset, pp, strlen(pp));
 
284
        else {
 
285
                /* Store in two pieces, splitting at a '/'. */
 
286
                p = strchr(pp + strlen(pp) - USTAR_name_size - 1, '/');
 
287
                /*
 
288
                 * Look for the next '/' if we chose the first character
 
289
                 * as the separator.  (ustar format doesn't permit
 
290
                 * an empty prefix.)
 
291
                 */
 
292
                if (p == pp)
 
293
                        p = strchr(p + 1, '/');
 
294
                /* Fail if the name won't fit. */
 
295
                if (!p) {
 
296
                        /* No separator. */
 
297
                        archive_set_error(&a->archive, ENAMETOOLONG,
 
298
                            "Pathname too long");
 
299
                        ret = ARCHIVE_FAILED;
 
300
                } else if (p[1] == '\0') {
 
301
                        /*
 
302
                         * The only feasible separator is a final '/';
 
303
                         * this would result in a non-empty prefix and
 
304
                         * an empty name, which POSIX doesn't
 
305
                         * explicity forbid, but it just feels wrong.
 
306
                         */
 
307
                        archive_set_error(&a->archive, ENAMETOOLONG,
 
308
                            "Pathname too long");
 
309
                        ret = ARCHIVE_FAILED;
 
310
                } else if (p  > pp + USTAR_prefix_size) {
 
311
                        /* Prefix is too long. */
 
312
                        archive_set_error(&a->archive, ENAMETOOLONG,
 
313
                            "Pathname too long");
 
314
                        ret = ARCHIVE_FAILED;
 
315
                } else {
 
316
                        /* Copy prefix and remainder to appropriate places */
 
317
                        memcpy(h + USTAR_prefix_offset, pp, p - pp);
 
318
                        memcpy(h + USTAR_name_offset, p + 1, pp + strlen(pp) - p - 1);
 
319
                }
 
320
        }
 
321
 
 
322
        p = archive_entry_hardlink(entry);
 
323
        if (p != NULL)
 
324
                mytartype = '1';
 
325
        else
 
326
                p = archive_entry_symlink(entry);
 
327
        if (p != NULL && p[0] != '\0') {
 
328
                copy_length = strlen(p);
 
329
                if (copy_length > USTAR_linkname_size) {
 
330
                        archive_set_error(&a->archive, ENAMETOOLONG,
 
331
                            "Link contents too long");
 
332
                        ret = ARCHIVE_FAILED;
 
333
                        copy_length = USTAR_linkname_size;
 
334
                }
 
335
                memcpy(h + USTAR_linkname_offset, p, copy_length);
 
336
        }
 
337
 
 
338
        p = archive_entry_uname(entry);
 
339
        if (p != NULL && p[0] != '\0') {
 
340
                copy_length = strlen(p);
 
341
                if (copy_length > USTAR_uname_size) {
 
342
                        archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 
343
                            "Username too long");
 
344
                        ret = ARCHIVE_FAILED;
 
345
                        copy_length = USTAR_uname_size;
 
346
                }
 
347
                memcpy(h + USTAR_uname_offset, p, copy_length);
 
348
        }
 
349
 
 
350
        p = archive_entry_gname(entry);
 
351
        if (p != NULL && p[0] != '\0') {
 
352
                copy_length = strlen(p);
 
353
                if (strlen(p) > USTAR_gname_size) {
 
354
                        archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 
355
                            "Group name too long");
 
356
                        ret = ARCHIVE_FAILED;
 
357
                        copy_length = USTAR_gname_size;
 
358
                }
 
359
                memcpy(h + USTAR_gname_offset, p, copy_length);
 
360
        }
 
361
 
 
362
        if (format_number(archive_entry_mode(entry) & 07777, h + USTAR_mode_offset, USTAR_mode_size, USTAR_mode_max_size, strict)) {
 
363
                archive_set_error(&a->archive, ERANGE, "Numeric mode too large");
 
364
                ret = ARCHIVE_FAILED;
 
365
        }
 
366
 
 
367
        if (format_number(archive_entry_uid(entry), h + USTAR_uid_offset, USTAR_uid_size, USTAR_uid_max_size, strict)) {
 
368
                archive_set_error(&a->archive, ERANGE, "Numeric user ID too large");
 
369
                ret = ARCHIVE_FAILED;
 
370
        }
 
371
 
 
372
        if (format_number(archive_entry_gid(entry), h + USTAR_gid_offset, USTAR_gid_size, USTAR_gid_max_size, strict)) {
 
373
                archive_set_error(&a->archive, ERANGE, "Numeric group ID too large");
 
374
                ret = ARCHIVE_FAILED;
 
375
        }
 
376
 
 
377
        if (format_number(archive_entry_size(entry), h + USTAR_size_offset, USTAR_size_size, USTAR_size_max_size, strict)) {
 
378
                archive_set_error(&a->archive, ERANGE, "File size out of range");
 
379
                ret = ARCHIVE_FAILED;
 
380
        }
 
381
 
 
382
        if (format_number(archive_entry_mtime(entry), h + USTAR_mtime_offset, USTAR_mtime_size, USTAR_mtime_max_size, strict)) {
 
383
                archive_set_error(&a->archive, ERANGE,
 
384
                    "File modification time too large");
 
385
                ret = ARCHIVE_FAILED;
 
386
        }
 
387
 
 
388
        if (archive_entry_filetype(entry) == AE_IFBLK
 
389
            || archive_entry_filetype(entry) == AE_IFCHR) {
 
390
                if (format_number(archive_entry_rdevmajor(entry), h + USTAR_rdevmajor_offset,
 
391
                        USTAR_rdevmajor_size, USTAR_rdevmajor_max_size, strict)) {
 
392
                        archive_set_error(&a->archive, ERANGE,
 
393
                            "Major device number too large");
 
394
                        ret = ARCHIVE_FAILED;
 
395
                }
 
396
 
 
397
                if (format_number(archive_entry_rdevminor(entry), h + USTAR_rdevminor_offset,
 
398
                        USTAR_rdevminor_size, USTAR_rdevminor_max_size, strict)) {
 
399
                        archive_set_error(&a->archive, ERANGE,
 
400
                            "Minor device number too large");
 
401
                        ret = ARCHIVE_FAILED;
 
402
                }
 
403
        }
 
404
 
 
405
        if (tartype >= 0) {
 
406
                h[USTAR_typeflag_offset] = tartype;
 
407
        } else if (mytartype >= 0) {
 
408
                h[USTAR_typeflag_offset] = mytartype;
 
409
        } else {
 
410
                switch (archive_entry_filetype(entry)) {
 
411
                case AE_IFREG: h[USTAR_typeflag_offset] = '0' ; break;
 
412
                case AE_IFLNK: h[USTAR_typeflag_offset] = '2' ; break;
 
413
                case AE_IFCHR: h[USTAR_typeflag_offset] = '3' ; break;
 
414
                case AE_IFBLK: h[USTAR_typeflag_offset] = '4' ; break;
 
415
                case AE_IFDIR: h[USTAR_typeflag_offset] = '5' ; break;
 
416
                case AE_IFIFO: h[USTAR_typeflag_offset] = '6' ; break;
 
417
                case AE_IFSOCK:
 
418
                        archive_set_error(&a->archive,
 
419
                            ARCHIVE_ERRNO_FILE_FORMAT,
 
420
                            "tar format cannot archive socket");
 
421
                        return (ARCHIVE_FAILED);
 
422
                default:
 
423
                        archive_set_error(&a->archive,
 
424
                            ARCHIVE_ERRNO_FILE_FORMAT,
 
425
                            "tar format cannot archive this (mode=0%lo)",
 
426
                            (unsigned long)archive_entry_mode(entry));
 
427
                        ret = ARCHIVE_FAILED;
 
428
                }
 
429
        }
 
430
 
 
431
        checksum = 0;
 
432
        for (i = 0; i < 512; i++)
 
433
                checksum += 255 & (unsigned int)h[i];
 
434
        h[USTAR_checksum_offset + 6] = '\0'; /* Can't be pre-set in the template. */
 
435
        /* h[USTAR_checksum_offset + 7] = ' '; */ /* This is pre-set in the template. */
 
436
        format_octal(checksum, h + USTAR_checksum_offset, 6);
 
437
        return (ret);
 
438
}
 
439
 
 
440
/*
 
441
 * Format a number into a field, with some intelligence.
 
442
 */
 
443
static int
 
444
format_number(int64_t v, char *p, int s, int maxsize, int strict)
 
445
{
 
446
        int64_t limit;
 
447
 
 
448
        limit = ((int64_t)1 << (s*3));
 
449
 
 
450
        /* "Strict" only permits octal values with proper termination. */
 
451
        if (strict)
 
452
                return (format_octal(v, p, s));
 
453
 
 
454
        /*
 
455
         * In non-strict mode, we allow the number to overwrite one or
 
456
         * more bytes of the field termination.  Even old tar
 
457
         * implementations should be able to handle this with no
 
458
         * problem.
 
459
         */
 
460
        if (v >= 0) {
 
461
                while (s <= maxsize) {
 
462
                        if (v < limit)
 
463
                                return (format_octal(v, p, s));
 
464
                        s++;
 
465
                        limit <<= 3;
 
466
                }
 
467
        }
 
468
 
 
469
        /* Base-256 can handle any number, positive or negative. */
 
470
        return (format_256(v, p, maxsize));
 
471
}
 
472
 
 
473
/*
 
474
 * Format a number into the specified field using base-256.
 
475
 */
 
476
static int
 
477
format_256(int64_t v, char *p, int s)
 
478
{
 
479
        p += s;
 
480
        while (s-- > 0) {
 
481
                *--p = (char)(v & 0xff);
 
482
                v >>= 8;
 
483
        }
 
484
        *p |= 0x80; /* Set the base-256 marker bit. */
 
485
        return (0);
 
486
}
 
487
 
 
488
/*
 
489
 * Format a number into the specified field.
 
490
 */
 
491
static int
 
492
format_octal(int64_t v, char *p, int s)
 
493
{
 
494
        int len;
 
495
 
 
496
        len = s;
 
497
 
 
498
        /* Octal values can't be negative, so use 0. */
 
499
        if (v < 0) {
 
500
                while (len-- > 0)
 
501
                        *p++ = '0';
 
502
                return (-1);
 
503
        }
 
504
 
 
505
        p += s;         /* Start at the end and work backwards. */
 
506
        while (s-- > 0) {
 
507
                *--p = (char)('0' + (v & 7));
 
508
                v >>= 3;
 
509
        }
 
510
 
 
511
        if (v == 0)
 
512
                return (0);
 
513
 
 
514
        /* If it overflowed, fill field with max value. */
 
515
        while (len-- > 0)
 
516
                *p++ = '7';
 
517
 
 
518
        return (-1);
 
519
}
 
520
 
 
521
static int
 
522
archive_write_ustar_finish(struct archive_write *a)
 
523
{
 
524
        int r;
 
525
 
 
526
        if (a->compressor.write == NULL)
 
527
                return (ARCHIVE_OK);
 
528
 
 
529
        r = write_nulls(a, 512*2);
 
530
        return (r);
 
531
}
 
532
 
 
533
static int
 
534
archive_write_ustar_destroy(struct archive_write *a)
 
535
{
 
536
        struct ustar *ustar;
 
537
 
 
538
        ustar = (struct ustar *)a->format_data;
 
539
        free(ustar);
 
540
        a->format_data = NULL;
 
541
        return (ARCHIVE_OK);
 
542
}
 
543
 
 
544
static int
 
545
archive_write_ustar_finish_entry(struct archive_write *a)
 
546
{
 
547
        struct ustar *ustar;
 
548
        int ret;
 
549
 
 
550
        ustar = (struct ustar *)a->format_data;
 
551
        ret = write_nulls(a,
 
552
            ustar->entry_bytes_remaining + ustar->entry_padding);
 
553
        ustar->entry_bytes_remaining = ustar->entry_padding = 0;
 
554
        return (ret);
 
555
}
 
556
 
 
557
static int
 
558
write_nulls(struct archive_write *a, size_t padding)
 
559
{
 
560
        int ret;
 
561
        size_t to_write;
 
562
 
 
563
        while (padding > 0) {
 
564
                to_write = padding < a->null_length ? padding : a->null_length;
 
565
                ret = (a->compressor.write)(a, a->nulls, to_write);
 
566
                if (ret != ARCHIVE_OK)
 
567
                        return (ret);
 
568
                padding -= to_write;
 
569
        }
 
570
        return (ARCHIVE_OK);
 
571
}
 
572
 
 
573
static ssize_t
 
574
archive_write_ustar_data(struct archive_write *a, const void *buff, size_t s)
 
575
{
 
576
        struct ustar *ustar;
 
577
        int ret;
 
578
 
 
579
        ustar = (struct ustar *)a->format_data;
 
580
        if (s > ustar->entry_bytes_remaining)
 
581
                s = ustar->entry_bytes_remaining;
 
582
        ret = (a->compressor.write)(a, buff, s);
 
583
        ustar->entry_bytes_remaining -= s;
 
584
        if (ret != ARCHIVE_OK)
 
585
                return (ret);
 
586
        return (s);
 
587
}