~akopytov/percona-xtrabackup/bug1002688-2.1

« back to all changes in this revision

Viewing changes to src/libarchive/libarchive/archive_write_set_format_mtree.c

merge parallel compression branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-
 
2
 * Copyright (c) 2009 Michihiro NAKAJIMA
 
3
 * Copyright (c) 2008 Joerg Sonnenberger
 
4
 * All rights reserved.
 
5
 *
 
6
 * Redistribution and use in source and binary forms, with or without
 
7
 * modification, are permitted provided that the following conditions
 
8
 * are met:
 
9
 * 1. Redistributions of source code must retain the above copyright
 
10
 *    notice, this list of conditions and the following disclaimer.
 
11
 * 2. Redistributions in binary form must reproduce the above copyright
 
12
 *    notice, this list of conditions and the following disclaimer in the
 
13
 *    documentation and/or other materials provided with the distribution.
 
14
 *
 
15
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 
16
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
17
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
18
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 
19
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
20
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
21
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
22
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
23
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
24
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
25
 */
 
26
 
 
27
#include "archive_platform.h"
 
28
__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_mtree.c 201171 2009-12-29 06:39:07Z kientzle $");
 
29
 
 
30
#ifdef HAVE_SYS_TYPES_H
 
31
#include <sys/types.h>
 
32
#endif
 
33
#include <errno.h>
 
34
#include <stdlib.h>
 
35
#include <string.h>
 
36
 
 
37
#include "archive.h"
 
38
#include "archive_entry.h"
 
39
#include "archive_private.h"
 
40
#include "archive_write_private.h"
 
41
 
 
42
#include "archive_hash.h"
 
43
 
 
44
#define INDENTNAMELEN   15
 
45
#define MAXLINELEN      80
 
46
 
 
47
struct mtree_writer {
 
48
        struct archive_entry *entry;
 
49
        struct archive_string ebuf;
 
50
        struct archive_string buf;
 
51
        int first;
 
52
        uint64_t entry_bytes_remaining;
 
53
        struct {
 
54
                int             output;
 
55
                int             processed;
 
56
                struct archive_string parent;
 
57
                mode_t          type;
 
58
                int             keys;
 
59
                uid_t           uid;
 
60
                gid_t           gid;
 
61
                mode_t          mode;
 
62
                unsigned long   fflags_set;
 
63
                unsigned long   fflags_clear;
 
64
        } set;
 
65
        /* chekc sum */
 
66
        int compute_sum;
 
67
        uint32_t crc;
 
68
        uint64_t crc_len;
 
69
#ifdef ARCHIVE_HAS_MD5
 
70
        archive_md5_ctx md5ctx;
 
71
#endif
 
72
#ifdef ARCHIVE_HAS_RMD160
 
73
        archive_rmd160_ctx rmd160ctx;
 
74
#endif
 
75
#ifdef ARCHIVE_HAS_SHA1
 
76
        archive_sha1_ctx sha1ctx;
 
77
#endif
 
78
#ifdef ARCHIVE_HAS_SHA256
 
79
        archive_sha256_ctx sha256ctx;
 
80
#endif
 
81
#ifdef ARCHIVE_HAS_SHA384
 
82
        archive_sha384_ctx sha384ctx;
 
83
#endif
 
84
#ifdef ARCHIVE_HAS_SHA512
 
85
        archive_sha512_ctx sha512ctx;
 
86
#endif
 
87
        /* Keyword options */
 
88
        int keys;
 
89
#define F_CKSUM         0x00000001              /* check sum */
 
90
#define F_DEV           0x00000002              /* device type */
 
91
#define F_DONE          0x00000004              /* directory done */
 
92
#define F_FLAGS         0x00000008              /* file flags */
 
93
#define F_GID           0x00000010              /* gid */
 
94
#define F_GNAME         0x00000020              /* group name */
 
95
#define F_IGN           0x00000040              /* ignore */
 
96
#define F_MAGIC         0x00000080              /* name has magic chars */
 
97
#define F_MD5           0x00000100              /* MD5 digest */
 
98
#define F_MODE          0x00000200              /* mode */
 
99
#define F_NLINK         0x00000400              /* number of links */
 
100
#define F_NOCHANGE      0x00000800              /* If owner/mode "wrong", do
 
101
                                                 * not change */
 
102
#define F_OPT           0x00001000              /* existence optional */
 
103
#define F_RMD160        0x00002000              /* RIPEMD160 digest */
 
104
#define F_SHA1          0x00004000              /* SHA-1 digest */
 
105
#define F_SIZE          0x00008000              /* size */
 
106
#define F_SLINK         0x00010000              /* symbolic link */
 
107
#define F_TAGS          0x00020000              /* tags */
 
108
#define F_TIME          0x00040000              /* modification time */
 
109
#define F_TYPE          0x00080000              /* file type */
 
110
#define F_UID           0x00100000              /* uid */
 
111
#define F_UNAME         0x00200000              /* user name */
 
112
#define F_VISIT         0x00400000              /* file visited */
 
113
#define F_SHA256        0x00800000              /* SHA-256 digest */
 
114
#define F_SHA384        0x01000000              /* SHA-384 digest */
 
115
#define F_SHA512        0x02000000              /* SHA-512 digest */
 
116
 
 
117
        /* Options */
 
118
        int dironly;            /* if the dironly is 1, ignore everything except
 
119
                                 * directory type files. like mtree(8) -d option.
 
120
                                 */
 
121
        int indent;             /* if the indent is 1, indent writing data. */
 
122
};
 
123
 
 
124
#define DEFAULT_KEYS    (F_DEV | F_FLAGS | F_GID | F_GNAME | F_SLINK | F_MODE\
 
125
                         | F_NLINK | F_SIZE | F_TIME | F_TYPE | F_UID\
 
126
                         | F_UNAME)
 
127
 
 
128
#define COMPUTE_CRC(var, ch)    (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)]
 
129
static const uint32_t crctab[] = {
 
130
        0x0,
 
131
        0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
 
132
        0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
 
133
        0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
 
134
        0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
 
135
        0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
 
136
        0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
 
137
        0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
 
138
        0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
 
139
        0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
 
140
        0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
 
141
        0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
 
142
        0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
 
143
        0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
 
144
        0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
 
145
        0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
 
146
        0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
 
147
        0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
 
148
        0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
 
149
        0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
 
150
        0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
 
151
        0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
 
152
        0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
 
153
        0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
 
154
        0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
 
155
        0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
 
156
        0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
 
157
        0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
 
158
        0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
 
159
        0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
 
160
        0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
 
161
        0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
 
162
        0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
 
163
        0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
 
164
        0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
 
165
        0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
 
166
        0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
 
167
        0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
 
168
        0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
 
169
        0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
 
170
        0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
 
171
        0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
 
172
        0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
 
173
        0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
 
174
        0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
 
175
        0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
 
176
        0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
 
177
        0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
 
178
        0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
 
179
        0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
 
180
        0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
 
181
        0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
 
182
};
 
183
 
 
184
static int
 
185
mtree_safe_char(char c)
 
186
{
 
187
        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
 
188
                return 1;
 
189
        if (c >= '0' && c <= '9')
 
190
                return 1;
 
191
        if (c == 35 || c == 61 || c == 92)
 
192
                return 0; /* #, = and \ are always quoted */
 
193
        
 
194
        if (c >= 33 && c <= 47) /* !"$%&'()*+,-./ */
 
195
                return 1;
 
196
        if (c >= 58 && c <= 64) /* :;<>?@ */
 
197
                return 1;
 
198
        if (c >= 91 && c <= 96) /* []^_` */
 
199
                return 1;
 
200
        if (c >= 123 && c <= 126) /* {|}~ */
 
201
                return 1;
 
202
        return 0;
 
203
}
 
204
 
 
205
static void
 
206
mtree_quote(struct archive_string *s, const char *str)
 
207
{
 
208
        const char *start;
 
209
        char buf[4];
 
210
        unsigned char c;
 
211
 
 
212
        for (start = str; *str != '\0'; ++str) {
 
213
                if (mtree_safe_char(*str))
 
214
                        continue;
 
215
                if (start != str)
 
216
                        archive_strncat(s, start, str - start);
 
217
                c = (unsigned char)*str;
 
218
                buf[0] = '\\';
 
219
                buf[1] = (c / 64) + '0';
 
220
                buf[2] = (c / 8 % 8) + '0';
 
221
                buf[3] = (c % 8) + '0';
 
222
                archive_strncat(s, buf, 4);
 
223
                start = str + 1;
 
224
        }
 
225
 
 
226
        if (start != str)
 
227
                archive_strncat(s, start, str - start);
 
228
}
 
229
 
 
230
static void
 
231
mtree_indent(struct mtree_writer *mtree)
 
232
{
 
233
        int i, fn;
 
234
        const char *r, *s, *x;
 
235
 
 
236
        fn = 1;
 
237
        s = r = mtree->ebuf.s;
 
238
        x = NULL;
 
239
        while (*r == ' ')
 
240
                r++;
 
241
        while ((r = strchr(r, ' ')) != NULL) {
 
242
                if (fn) {
 
243
                        fn = 0;
 
244
                        archive_strncat(&mtree->buf, s, r - s);
 
245
                        if (r -s > INDENTNAMELEN) {
 
246
                                archive_strncat(&mtree->buf, " \\\n", 3);
 
247
                                for (i = 0; i < (INDENTNAMELEN + 1); i++)
 
248
                                        archive_strappend_char(&mtree->buf, ' ');
 
249
                        } else {
 
250
                                for (i = r -s; i < (INDENTNAMELEN + 1); i++)
 
251
                                        archive_strappend_char(&mtree->buf, ' ');
 
252
                        }
 
253
                        s = ++r;
 
254
                        x = NULL;
 
255
                        continue;
 
256
                }
 
257
                if (r - s <= MAXLINELEN - 3 - INDENTNAMELEN)
 
258
                        x = r++;
 
259
                else {
 
260
                        if (x == NULL)
 
261
                                x = r;
 
262
                        archive_strncat(&mtree->buf, s, x - s);
 
263
                        archive_strncat(&mtree->buf, " \\\n", 3);
 
264
                        for (i = 0; i < (INDENTNAMELEN + 1); i++)
 
265
                                archive_strappend_char(&mtree->buf, ' ');
 
266
                        s = r = ++x;
 
267
                        x = NULL;
 
268
                }
 
269
        }
 
270
        if (x != NULL && strlen(s) > MAXLINELEN - 3 - INDENTNAMELEN) {
 
271
                /* Last keyword is longer. */
 
272
                archive_strncat(&mtree->buf, s, x - s);
 
273
                archive_strncat(&mtree->buf, " \\\n", 3);
 
274
                for (i = 0; i < (INDENTNAMELEN + 1); i++)
 
275
                        archive_strappend_char(&mtree->buf, ' ');
 
276
                s = ++x;
 
277
        }
 
278
        archive_strcat(&mtree->buf, s);
 
279
        archive_string_empty(&mtree->ebuf);
 
280
}
 
281
 
 
282
#if !defined(_WIN32) || defined(__CYGWIN__)
 
283
static size_t
 
284
dir_len(struct archive_entry *entry)
 
285
{
 
286
        const char *path, *r;
 
287
 
 
288
        path = archive_entry_pathname(entry);
 
289
        r = strrchr(path, '/');
 
290
        if (r == NULL)
 
291
                return (0);
 
292
        /* Include a separator size */
 
293
        return (r - path + 1);
 
294
}
 
295
 
 
296
#else /* _WIN32 && !__CYGWIN__ */
 
297
/*
 
298
 * Note: We should use wide-character for findng '\' character,
 
299
 * a directory separator on Windows, because some character-set have
 
300
 * been using the '\' character for a part of its multibyte character
 
301
 * code.
 
302
 */
 
303
static size_t
 
304
dir_len(struct archive_entry *entry)
 
305
{
 
306
        wchar_t wc;
 
307
        const char *path;
 
308
        const char *p, *rp;
 
309
        size_t al, l, size;
 
310
 
 
311
        path = archive_entry_pathname(entry);
 
312
        al = l = -1;
 
313
        for (p = path; *p != '\0'; ++p) {
 
314
                if (*p == '\\')
 
315
                        al = l = p - path;
 
316
                else if (*p == '/')
 
317
                        al = p - path;
 
318
        }
 
319
        if (l == -1)
 
320
                goto alen;
 
321
        size = p - path;
 
322
        rp = p = path;
 
323
        while (*p != '\0') {
 
324
                l = mbtowc(&wc, p, size);
 
325
                if (l == -1)
 
326
                        goto alen;
 
327
                if (l == 1 && (wc == L'/' || wc == L'\\'))
 
328
                        rp = p;
 
329
                p += l;
 
330
                size -= l;
 
331
        }
 
332
        return (rp - path + 1);
 
333
alen:
 
334
        if (al == -1)
 
335
                return (0);
 
336
        return (al + 1);
 
337
}
 
338
#endif /* _WIN32 && !__CYGWIN__ */
 
339
 
 
340
static int
 
341
parent_dir_changed(struct archive_string *dir, struct archive_entry *entry)
 
342
{
 
343
        const char *path;
 
344
        size_t l;
 
345
 
 
346
        l = dir_len(entry);
 
347
        path = archive_entry_pathname(entry);
 
348
        if (archive_strlen(dir) > 0) {
 
349
                if (l == 0) {
 
350
                        archive_string_empty(dir);
 
351
                        return (1);
 
352
                }
 
353
                if (strncmp(dir->s, path, l) == 0)
 
354
                        return (0); /* The parent directory is the same. */
 
355
        } else if (l == 0)
 
356
                return (0);         /* The parent directory is the same. */
 
357
        archive_strncpy(dir, path, l);
 
358
        return (1);
 
359
}
 
360
 
 
361
/*
 
362
 * Write /set keyword. It means set global datas.
 
363
 * [directory-only mode]
 
364
 *   - It is only once to write /set keyword. It is using values of the
 
365
 *     first entry.
 
366
 * [normal mode]
 
367
 *   - Write /set keyword. It is using values of the first entry whose
 
368
 *     filetype is a regular file.
 
369
 *   - When a parent directory of the entry whose filetype is the regular
 
370
 *     file is changed, check the global datas and write it again if its
 
371
 *     values are different from the entry's.
 
372
 */
 
373
static void
 
374
set_global(struct mtree_writer *mtree, struct archive_entry *entry)
 
375
{
 
376
        struct archive_string setstr;
 
377
        struct archive_string unsetstr;
 
378
        const char *name;
 
379
        int keys, oldkeys, effkeys;
 
380
        mode_t set_type = 0;
 
381
 
 
382
        switch (archive_entry_filetype(entry)) {
 
383
        case AE_IFLNK: case AE_IFSOCK: case AE_IFCHR:
 
384
        case AE_IFBLK: case AE_IFIFO:
 
385
                break;
 
386
        case AE_IFDIR:
 
387
                if (mtree->dironly)
 
388
                        set_type = AE_IFDIR;
 
389
                break;
 
390
        case AE_IFREG:
 
391
        default:        /* Handle unknown file types as regular files. */
 
392
                if (!mtree->dironly)
 
393
                        set_type = AE_IFREG;
 
394
                break;
 
395
        }
 
396
        if (set_type == 0)
 
397
                return;
 
398
        if (mtree->set.processed &&
 
399
            !parent_dir_changed(&mtree->set.parent, entry))
 
400
                return;
 
401
        /* At first, save a parent directory of the entry for following
 
402
         * entries. */
 
403
        if (!mtree->set.processed && set_type == AE_IFREG)
 
404
                parent_dir_changed(&mtree->set.parent, entry);
 
405
 
 
406
        archive_string_init(&setstr);
 
407
        archive_string_init(&unsetstr);
 
408
        keys = mtree->keys & (F_FLAGS | F_GID | F_GNAME | F_NLINK | F_MODE
 
409
            | F_TYPE | F_UID | F_UNAME);
 
410
        oldkeys = mtree->set.keys;
 
411
        effkeys = keys;
 
412
        if (mtree->set.processed) {
 
413
                /*
 
414
                 * Check the global datas for whether it needs updating.
 
415
                 */
 
416
                effkeys &= ~F_TYPE;
 
417
                if ((oldkeys & (F_UNAME | F_UID)) != 0 &&
 
418
                    mtree->set.uid == archive_entry_uid(entry))
 
419
                        effkeys &= ~(F_UNAME | F_UID);
 
420
                if ((oldkeys & (F_GNAME | F_GID)) != 0 &&
 
421
                    mtree->set.gid == archive_entry_gid(entry))
 
422
                        effkeys &= ~(F_GNAME | F_GID);
 
423
                if ((oldkeys & F_MODE) != 0 &&
 
424
                    mtree->set.mode == (archive_entry_mode(entry) & 07777))
 
425
                        effkeys &= ~F_MODE;
 
426
                if ((oldkeys & F_FLAGS) != 0) {
 
427
                        unsigned long   fflags_set;
 
428
                        unsigned long   fflags_clear;
 
429
 
 
430
                        archive_entry_fflags(entry, &fflags_set, &fflags_clear);
 
431
                        if (fflags_set == mtree->set.fflags_set &&
 
432
                            fflags_clear == mtree->set.fflags_clear)
 
433
                                effkeys &= ~F_FLAGS;
 
434
                }
 
435
        }
 
436
        if ((keys & effkeys & F_TYPE) != 0) {
 
437
                mtree->set.type = set_type;
 
438
                if (set_type == AE_IFDIR)
 
439
                        archive_strcat(&setstr, " type=dir");
 
440
                else
 
441
                        archive_strcat(&setstr, " type=file");
 
442
        }
 
443
        if ((keys & effkeys & F_UNAME) != 0) {
 
444
                if ((name = archive_entry_uname(entry)) != NULL) {
 
445
                        archive_strcat(&setstr, " uname=");
 
446
                        mtree_quote(&setstr, name);
 
447
                } else if ((oldkeys & F_UNAME) != 0)
 
448
                        archive_strcat(&unsetstr, " uname");
 
449
                else
 
450
                        keys &= ~F_UNAME;
 
451
        }
 
452
        if ((keys & effkeys & F_UID) != 0) {
 
453
                mtree->set.uid = archive_entry_uid(entry);
 
454
                archive_string_sprintf(&setstr, " uid=%jd",
 
455
                    (intmax_t)mtree->set.uid);
 
456
        }
 
457
        if ((keys & effkeys & F_GNAME) != 0) {
 
458
                if ((name = archive_entry_gname(entry)) != NULL) {
 
459
                        archive_strcat(&setstr, " gname=");
 
460
                        mtree_quote(&setstr, name);
 
461
                } else if ((oldkeys & F_GNAME) != 0)
 
462
                        archive_strcat(&unsetstr, " gname");
 
463
                else
 
464
                        keys &= ~F_GNAME;
 
465
        }
 
466
        if ((keys & effkeys & F_GID) != 0) {
 
467
                mtree->set.gid = archive_entry_gid(entry);
 
468
                archive_string_sprintf(&setstr, " gid=%jd",
 
469
                    (intmax_t)mtree->set.gid);
 
470
        }
 
471
        if ((keys & effkeys & F_MODE) != 0) {
 
472
                mtree->set.mode = archive_entry_mode(entry) & 07777;
 
473
                archive_string_sprintf(&setstr, " mode=%o", mtree->set.mode);
 
474
        }
 
475
        if ((keys & effkeys & F_FLAGS) != 0) {
 
476
                if ((name = archive_entry_fflags_text(entry)) != NULL) {
 
477
                        archive_strcat(&setstr, " flags=");
 
478
                        mtree_quote(&setstr, name);
 
479
                        archive_entry_fflags(entry, &mtree->set.fflags_set,
 
480
                            &mtree->set.fflags_clear);
 
481
                } else if ((oldkeys & F_FLAGS) != 0)
 
482
                        archive_strcat(&unsetstr, " flags");
 
483
                else
 
484
                        keys &= ~F_FLAGS;
 
485
        }
 
486
        if (unsetstr.length > 0)
 
487
                archive_string_sprintf(&mtree->buf, "/unset%s\n", unsetstr.s);
 
488
        archive_string_free(&unsetstr);
 
489
        if (setstr.length > 0)
 
490
                archive_string_sprintf(&mtree->buf, "/set%s\n", setstr.s);
 
491
        archive_string_free(&setstr);
 
492
        mtree->set.keys = keys;
 
493
        mtree->set.processed = 1;
 
494
        /* On directory-only mode, it is only once to write /set keyword. */
 
495
        if (mtree->dironly)
 
496
                mtree->set.output = 0;
 
497
}
 
498
 
 
499
static int
 
500
get_keys(struct mtree_writer *mtree, struct archive_entry *entry)
 
501
{
 
502
        int keys;
 
503
 
 
504
        keys = mtree->keys;
 
505
        if (mtree->set.keys == 0)
 
506
                return (keys);
 
507
        if ((mtree->set.keys & (F_GNAME | F_GID)) != 0 &&
 
508
             mtree->set.gid == archive_entry_gid(entry))
 
509
                keys &= ~(F_GNAME | F_GID);
 
510
        if ((mtree->set.keys & (F_UNAME | F_UID)) != 0 &&
 
511
             mtree->set.uid == archive_entry_uid(entry))
 
512
                keys &= ~(F_UNAME | F_UID);
 
513
        if (mtree->set.keys & F_FLAGS) {
 
514
                unsigned long set, clear;
 
515
 
 
516
                archive_entry_fflags(entry, &set, &clear);
 
517
                if (mtree->set.fflags_set == set &&
 
518
                    mtree->set.fflags_clear == clear)
 
519
                        keys &= ~F_FLAGS;
 
520
        }
 
521
        if ((mtree->set.keys & F_MODE) != 0 &&
 
522
             mtree->set.mode == (archive_entry_mode(entry) & 07777))
 
523
                keys &= ~F_MODE;
 
524
 
 
525
        switch (archive_entry_filetype(entry)) {
 
526
        case AE_IFLNK: case AE_IFSOCK: case AE_IFCHR:
 
527
        case AE_IFBLK: case AE_IFIFO:
 
528
                break;
 
529
        case AE_IFDIR:
 
530
                if ((mtree->set.keys & F_TYPE) != 0 &&
 
531
                    mtree->set.type == AE_IFDIR)
 
532
                        keys &= ~F_TYPE;
 
533
                break;
 
534
        case AE_IFREG:
 
535
        default:        /* Handle unknown file types as regular files. */
 
536
                if ((mtree->set.keys & F_TYPE) != 0 &&
 
537
                    mtree->set.type == AE_IFREG)
 
538
                        keys &= ~F_TYPE;
 
539
                break;
 
540
        }
 
541
 
 
542
        return (keys);
 
543
}
 
544
 
 
545
static int
 
546
archive_write_mtree_header(struct archive_write *a,
 
547
    struct archive_entry *entry)
 
548
{
 
549
        struct mtree_writer *mtree= a->format_data;
 
550
        struct archive_string *str;
 
551
        const char *path;
 
552
 
 
553
        mtree->entry = archive_entry_clone(entry);
 
554
        path = archive_entry_pathname(mtree->entry);
 
555
 
 
556
        if (mtree->first) {
 
557
                mtree->first = 0;
 
558
                archive_strcat(&mtree->buf, "#mtree\n");
 
559
        }
 
560
        if (mtree->set.output)
 
561
                set_global(mtree, entry);
 
562
 
 
563
        archive_string_empty(&mtree->ebuf);
 
564
        str = (mtree->indent)? &mtree->ebuf : &mtree->buf;
 
565
        if (!mtree->dironly || archive_entry_filetype(entry) == AE_IFDIR)
 
566
                mtree_quote(str, path);
 
567
 
 
568
        mtree->entry_bytes_remaining = archive_entry_size(entry);
 
569
        if ((mtree->keys & F_CKSUM) != 0 &&
 
570
            archive_entry_filetype(entry) == AE_IFREG) {
 
571
                mtree->compute_sum |= F_CKSUM;
 
572
                mtree->crc = 0;
 
573
                mtree->crc_len = 0;
 
574
        } else
 
575
                mtree->compute_sum &= ~F_CKSUM;
 
576
#ifdef ARCHIVE_HAS_MD5
 
577
        if ((mtree->keys & F_MD5) != 0 &&
 
578
            archive_entry_filetype(entry) == AE_IFREG) {
 
579
                mtree->compute_sum |= F_MD5;
 
580
                archive_md5_init(&mtree->md5ctx);
 
581
        } else
 
582
                mtree->compute_sum &= ~F_MD5;
 
583
#endif
 
584
#ifdef ARCHIVE_HAS_RMD160
 
585
        if ((mtree->keys & F_RMD160) != 0 &&
 
586
            archive_entry_filetype(entry) == AE_IFREG) {
 
587
                mtree->compute_sum |= F_RMD160;
 
588
                archive_rmd160_init(&mtree->rmd160ctx);
 
589
        } else
 
590
                mtree->compute_sum &= ~F_RMD160;
 
591
#endif
 
592
#ifdef ARCHIVE_HAS_SHA1
 
593
        if ((mtree->keys & F_SHA1) != 0 &&
 
594
            archive_entry_filetype(entry) == AE_IFREG) {
 
595
                mtree->compute_sum |= F_SHA1;
 
596
                archive_sha1_init(&mtree->sha1ctx);
 
597
        } else
 
598
                mtree->compute_sum &= ~F_SHA1;
 
599
#endif
 
600
#ifdef ARCHIVE_HAS_SHA256
 
601
        if ((mtree->keys & F_SHA256) != 0 &&
 
602
            archive_entry_filetype(entry) == AE_IFREG) {
 
603
                mtree->compute_sum |= F_SHA256;
 
604
                archive_sha256_init(&mtree->sha256ctx);
 
605
        } else
 
606
                mtree->compute_sum &= ~F_SHA256;
 
607
#endif
 
608
#ifdef ARCHIVE_HAS_SHA384
 
609
        if ((mtree->keys & F_SHA384) != 0 &&
 
610
            archive_entry_filetype(entry) == AE_IFREG) {
 
611
                mtree->compute_sum |= F_SHA384;
 
612
                archive_sha384_init(&mtree->sha384ctx);
 
613
        } else
 
614
                mtree->compute_sum &= ~F_SHA384;
 
615
#endif
 
616
#ifdef ARCHIVE_HAS_SHA512
 
617
        if ((mtree->keys & F_SHA512) != 0 &&
 
618
            archive_entry_filetype(entry) == AE_IFREG) {
 
619
                mtree->compute_sum |= F_SHA512;
 
620
                archive_sha512_init(&mtree->sha512ctx);
 
621
        } else
 
622
                mtree->compute_sum &= ~F_SHA512;
 
623
#endif
 
624
 
 
625
        return (ARCHIVE_OK);
 
626
}
 
627
 
 
628
#if defined(ARCHIVE_HAS_MD5) || defined(ARCHIVE_HAS_RMD160) || \
 
629
    defined(ARCHIVE_HAS_SHA1) || defined(ARCHIVE_HAS_SHA256) || \
 
630
    defined(ARCHIVE_HAS_SHA384) || defined(ARCHIVE_HAS_SHA512)
 
631
static void
 
632
strappend_bin(struct archive_string *s, const unsigned char *bin, int n)
 
633
{
 
634
        static const char hex[] = "0123456789abcdef";
 
635
        int i;
 
636
 
 
637
        for (i = 0; i < n; i++) {
 
638
                archive_strappend_char(s, hex[bin[i] >> 4]);
 
639
                archive_strappend_char(s, hex[bin[i] & 0x0f]);
 
640
        }
 
641
}
 
642
#endif
 
643
 
 
644
static int
 
645
archive_write_mtree_finish_entry(struct archive_write *a)
 
646
{
 
647
        struct mtree_writer *mtree = a->format_data;
 
648
        struct archive_entry *entry;
 
649
        struct archive_string *str;
 
650
        const char *name;
 
651
        int keys, ret;
 
652
 
 
653
        entry = mtree->entry;
 
654
        if (entry == NULL) {
 
655
                archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
 
656
                    "Finished entry without being open first.");
 
657
                return (ARCHIVE_FATAL);
 
658
        }
 
659
        mtree->entry = NULL;
 
660
 
 
661
        if (mtree->dironly && archive_entry_filetype(entry) != AE_IFDIR) {
 
662
                archive_entry_free(entry);
 
663
                return (ARCHIVE_OK);
 
664
        }
 
665
 
 
666
        str = (mtree->indent)? &mtree->ebuf : &mtree->buf;
 
667
        keys = get_keys(mtree, entry);
 
668
        if ((keys & F_NLINK) != 0 &&
 
669
            archive_entry_nlink(entry) != 1 &&
 
670
            archive_entry_filetype(entry) != AE_IFDIR)
 
671
                archive_string_sprintf(str,
 
672
                    " nlink=%u", archive_entry_nlink(entry));
 
673
 
 
674
        if ((keys & F_GNAME) != 0 &&
 
675
            (name = archive_entry_gname(entry)) != NULL) {
 
676
                archive_strcat(str, " gname=");
 
677
                mtree_quote(str, name);
 
678
        }
 
679
        if ((keys & F_UNAME) != 0 &&
 
680
            (name = archive_entry_uname(entry)) != NULL) {
 
681
                archive_strcat(str, " uname=");
 
682
                mtree_quote(str, name);
 
683
        }
 
684
        if ((keys & F_FLAGS) != 0 &&
 
685
            (name = archive_entry_fflags_text(entry)) != NULL) {
 
686
                archive_strcat(str, " flags=");
 
687
                mtree_quote(str, name);
 
688
        }
 
689
        if ((keys & F_TIME) != 0)
 
690
                archive_string_sprintf(str, " time=%jd.%jd",
 
691
                    (intmax_t)archive_entry_mtime(entry),
 
692
                    (intmax_t)archive_entry_mtime_nsec(entry));
 
693
        if ((keys & F_MODE) != 0)
 
694
                archive_string_sprintf(str, " mode=%o",
 
695
                    archive_entry_mode(entry) & 07777);
 
696
        if ((keys & F_GID) != 0)
 
697
                archive_string_sprintf(str, " gid=%jd",
 
698
                    (intmax_t)archive_entry_gid(entry));
 
699
        if ((keys & F_UID) != 0)
 
700
                archive_string_sprintf(str, " uid=%jd",
 
701
                    (intmax_t)archive_entry_uid(entry));
 
702
 
 
703
        switch (archive_entry_filetype(entry)) {
 
704
        case AE_IFLNK:
 
705
                if ((keys & F_TYPE) != 0)
 
706
                        archive_strcat(str, " type=link");
 
707
                if ((keys & F_SLINK) != 0) {
 
708
                        archive_strcat(str, " link=");
 
709
                        mtree_quote(str, archive_entry_symlink(entry));
 
710
                }
 
711
                break;
 
712
        case AE_IFSOCK:
 
713
                if ((keys & F_TYPE) != 0)
 
714
                        archive_strcat(str, " type=socket");
 
715
                break;
 
716
        case AE_IFCHR:
 
717
                if ((keys & F_TYPE) != 0)
 
718
                        archive_strcat(str, " type=char");
 
719
                if ((keys & F_DEV) != 0) {
 
720
                        archive_string_sprintf(str,
 
721
                            " device=native,%d,%d",
 
722
                            archive_entry_rdevmajor(entry),
 
723
                            archive_entry_rdevminor(entry));
 
724
                }
 
725
                break;
 
726
        case AE_IFBLK:
 
727
                if ((keys & F_TYPE) != 0)
 
728
                        archive_strcat(str, " type=block");
 
729
                if ((keys & F_DEV) != 0) {
 
730
                        archive_string_sprintf(str,
 
731
                            " device=native,%d,%d",
 
732
                            archive_entry_rdevmajor(entry),
 
733
                            archive_entry_rdevminor(entry));
 
734
                }
 
735
                break;
 
736
        case AE_IFDIR:
 
737
                if ((keys & F_TYPE) != 0)
 
738
                        archive_strcat(str, " type=dir");
 
739
                break;
 
740
        case AE_IFIFO:
 
741
                if ((keys & F_TYPE) != 0)
 
742
                        archive_strcat(str, " type=fifo");
 
743
                break;
 
744
        case AE_IFREG:
 
745
        default:        /* Handle unknown file types as regular files. */
 
746
                if ((keys & F_TYPE) != 0)
 
747
                        archive_strcat(str, " type=file");
 
748
                if ((keys & F_SIZE) != 0)
 
749
                        archive_string_sprintf(str, " size=%jd",
 
750
                            (intmax_t)archive_entry_size(entry));
 
751
                break;
 
752
        }
 
753
 
 
754
        if (mtree->compute_sum & F_CKSUM) {
 
755
                uint64_t len;
 
756
                /* Include the length of the file. */
 
757
                for (len = mtree->crc_len; len != 0; len >>= 8)
 
758
                        COMPUTE_CRC(mtree->crc, len & 0xff);
 
759
                mtree->crc = ~mtree->crc;
 
760
                archive_string_sprintf(str, " cksum=%ju",
 
761
                    (uintmax_t)mtree->crc);
 
762
        }
 
763
#ifdef ARCHIVE_HAS_MD5
 
764
        if (mtree->compute_sum & F_MD5) {
 
765
                unsigned char buf[16];
 
766
 
 
767
                archive_md5_final(&mtree->md5ctx, buf);
 
768
                archive_strcat(str, " md5digest=");
 
769
                strappend_bin(str, buf, sizeof(buf));
 
770
        }
 
771
#endif
 
772
#ifdef ARCHIVE_HAS_RMD160
 
773
        if (mtree->compute_sum & F_RMD160) {
 
774
                unsigned char buf[20];
 
775
 
 
776
                archive_rmd160_final(&mtree->rmd160ctx, buf);
 
777
                archive_strcat(str, " rmd160digest=");
 
778
                strappend_bin(str, buf, sizeof(buf));
 
779
        }
 
780
#endif
 
781
#ifdef ARCHIVE_HAS_SHA1
 
782
        if (mtree->compute_sum & F_SHA1) {
 
783
                unsigned char buf[20];
 
784
 
 
785
                archive_sha1_final(&mtree->sha1ctx, buf);
 
786
                archive_strcat(str, " sha1digest=");
 
787
                strappend_bin(str, buf, sizeof(buf));
 
788
        }
 
789
#endif
 
790
#ifdef ARCHIVE_HAS_SHA256
 
791
        if (mtree->compute_sum & F_SHA256) {
 
792
                unsigned char buf[32];
 
793
 
 
794
                archive_sha256_final(&mtree->sha256ctx, buf);
 
795
                archive_strcat(str, " sha256digest=");
 
796
                strappend_bin(str, buf, sizeof(buf));
 
797
        }
 
798
#endif
 
799
#ifdef ARCHIVE_HAS_SHA384
 
800
        if (mtree->compute_sum & F_SHA384) {
 
801
                unsigned char buf[48];
 
802
 
 
803
                archive_sha384_final(&mtree->sha384ctx, buf);
 
804
                archive_strcat(str, " sha384digest=");
 
805
                strappend_bin(str, buf, sizeof(buf));
 
806
        }
 
807
#endif
 
808
#ifdef ARCHIVE_HAS_SHA512
 
809
        if (mtree->compute_sum & F_SHA512) {
 
810
                unsigned char buf[64];
 
811
 
 
812
                archive_sha512_final(&mtree->sha512ctx, buf);
 
813
                archive_strcat(str, " sha512digest=");
 
814
                strappend_bin(str, buf, sizeof(buf));
 
815
        }
 
816
#endif
 
817
        archive_strcat(str, "\n");
 
818
        if (mtree->indent)
 
819
                mtree_indent(mtree);
 
820
 
 
821
        archive_entry_free(entry);
 
822
 
 
823
        if (mtree->buf.length > 32768) {
 
824
                ret = (a->compressor.write)(a, mtree->buf.s, mtree->buf.length);
 
825
                archive_string_empty(&mtree->buf);
 
826
        } else
 
827
                ret = ARCHIVE_OK;
 
828
 
 
829
        return (ret == ARCHIVE_OK ? ret : ARCHIVE_FATAL);
 
830
}
 
831
 
 
832
static int
 
833
archive_write_mtree_finish(struct archive_write *a)
 
834
{
 
835
        struct mtree_writer *mtree= a->format_data;
 
836
 
 
837
        archive_write_set_bytes_in_last_block(&a->archive, 1);
 
838
 
 
839
        return (a->compressor.write)(a, mtree->buf.s, mtree->buf.length);
 
840
}
 
841
 
 
842
static ssize_t
 
843
archive_write_mtree_data(struct archive_write *a, const void *buff, size_t n)
 
844
{
 
845
        struct mtree_writer *mtree= a->format_data;
 
846
 
 
847
        if (n > mtree->entry_bytes_remaining)
 
848
                n = mtree->entry_bytes_remaining;
 
849
        if (mtree->dironly)
 
850
                /* We don't need compute a regular file sum */
 
851
                return (n);
 
852
        if (mtree->compute_sum & F_CKSUM) {
 
853
                /*
 
854
                 * Compute a POSIX 1003.2 checksum
 
855
                 */
 
856
                const unsigned char *p;
 
857
                size_t nn;
 
858
 
 
859
                for (nn = n, p = buff; nn--; ++p)
 
860
                        COMPUTE_CRC(mtree->crc, *p);
 
861
                mtree->crc_len += n;
 
862
        }
 
863
#ifdef ARCHIVE_HAS_MD5
 
864
        if (mtree->compute_sum & F_MD5)
 
865
                archive_md5_update(&mtree->md5ctx, buff, n);
 
866
#endif
 
867
#ifdef ARCHIVE_HAS_RMD160
 
868
        if (mtree->compute_sum & F_RMD160)
 
869
                archive_rmd160_update(&mtree->rmd160ctx, buff, n);
 
870
#endif
 
871
#ifdef ARCHIVE_HAS_SHA1
 
872
        if (mtree->compute_sum & F_SHA1)
 
873
                archive_sha1_update(&mtree->sha1ctx, buff, n);
 
874
#endif
 
875
#ifdef ARCHIVE_HAS_SHA256
 
876
        if (mtree->compute_sum & F_SHA256)
 
877
                archive_sha256_update(&mtree->sha256ctx, buff, n);
 
878
#endif
 
879
#ifdef ARCHIVE_HAS_SHA384
 
880
        if (mtree->compute_sum & F_SHA384)
 
881
                archive_sha384_update(&mtree->sha384ctx, buff, n);
 
882
#endif
 
883
#ifdef ARCHIVE_HAS_SHA512
 
884
        if (mtree->compute_sum & F_SHA512)
 
885
                archive_sha512_update(&mtree->sha512ctx, buff, n);
 
886
#endif
 
887
        return (n);
 
888
}
 
889
 
 
890
static int
 
891
archive_write_mtree_destroy(struct archive_write *a)
 
892
{
 
893
        struct mtree_writer *mtree= a->format_data;
 
894
 
 
895
        if (mtree == NULL)
 
896
                return (ARCHIVE_OK);
 
897
 
 
898
        archive_entry_free(mtree->entry);
 
899
        archive_string_free(&mtree->ebuf);
 
900
        archive_string_free(&mtree->buf);
 
901
        archive_string_free(&mtree->set.parent);
 
902
        free(mtree);
 
903
        a->format_data = NULL;
 
904
        return (ARCHIVE_OK);
 
905
}
 
906
 
 
907
static int
 
908
archive_write_mtree_options(struct archive_write *a, const char *key,
 
909
    const char *value)
 
910
{
 
911
        struct mtree_writer *mtree= a->format_data;
 
912
        int keybit = 0;
 
913
 
 
914
        switch (key[0]) {
 
915
        case 'a':
 
916
                if (strcmp(key, "all") == 0)
 
917
                        keybit = ~0;
 
918
                break;
 
919
        case 'c':
 
920
                if (strcmp(key, "cksum") == 0)
 
921
                        keybit = F_CKSUM;
 
922
                break;
 
923
        case 'd':
 
924
                if (strcmp(key, "device") == 0)
 
925
                        keybit = F_DEV;
 
926
                else if (strcmp(key, "dironly") == 0) {
 
927
                        mtree->dironly = (value != NULL)? 1: 0;
 
928
                        return (ARCHIVE_OK);
 
929
                }
 
930
                break;
 
931
        case 'f':
 
932
                if (strcmp(key, "flags") == 0)
 
933
                        keybit = F_FLAGS;
 
934
                break;
 
935
        case 'g':
 
936
                if (strcmp(key, "gid") == 0)
 
937
                        keybit = F_GID;
 
938
                else if (strcmp(key, "gname") == 0)
 
939
                        keybit = F_GNAME;
 
940
                break;
 
941
        case 'i':
 
942
                if (strcmp(key, "indent") == 0) {
 
943
                        mtree->indent = (value != NULL)? 1: 0;
 
944
                        return (ARCHIVE_OK);
 
945
                }
 
946
                break;
 
947
        case 'l':
 
948
                if (strcmp(key, "link") == 0)
 
949
                        keybit = F_SLINK;
 
950
                break;
 
951
        case 'm':
 
952
                if (strcmp(key, "md5") == 0 ||
 
953
                    strcmp(key, "md5digest") == 0)
 
954
                        keybit = F_MD5;
 
955
                if (strcmp(key, "mode") == 0)
 
956
                        keybit = F_MODE;
 
957
                break;
 
958
        case 'n':
 
959
                if (strcmp(key, "nlink") == 0)
 
960
                        keybit = F_NLINK;
 
961
                break;
 
962
        case 'r':
 
963
                if (strcmp(key, "ripemd160digest") == 0 ||
 
964
                    strcmp(key, "rmd160") == 0 ||
 
965
                    strcmp(key, "rmd160digest") == 0)
 
966
                        keybit = F_RMD160;
 
967
                break;
 
968
        case 's':
 
969
                if (strcmp(key, "sha1") == 0 ||
 
970
                    strcmp(key, "sha1digest") == 0)
 
971
                        keybit = F_SHA1;
 
972
                if (strcmp(key, "sha256") == 0 ||
 
973
                    strcmp(key, "sha256digest") == 0)
 
974
                        keybit = F_SHA256;
 
975
                if (strcmp(key, "sha384") == 0 ||
 
976
                    strcmp(key, "sha384digest") == 0)
 
977
                        keybit = F_SHA384;
 
978
                if (strcmp(key, "sha512") == 0 ||
 
979
                    strcmp(key, "sha512digest") == 0)
 
980
                        keybit = F_SHA512;
 
981
                if (strcmp(key, "size") == 0)
 
982
                        keybit = F_SIZE;
 
983
                break;
 
984
        case 't':
 
985
                if (strcmp(key, "time") == 0)
 
986
                        keybit = F_TIME;
 
987
                else if (strcmp(key, "type") == 0)
 
988
                        keybit = F_TYPE;
 
989
                break;
 
990
        case 'u':
 
991
                if (strcmp(key, "uid") == 0)
 
992
                        keybit = F_UID;
 
993
                else if (strcmp(key, "uname") == 0)
 
994
                        keybit = F_UNAME;
 
995
                else if (strcmp(key, "use-set") == 0) {
 
996
                        mtree->set.output = (value != NULL)? 1: 0;
 
997
                        return (ARCHIVE_OK);
 
998
                }
 
999
                break;
 
1000
        }
 
1001
        if (keybit != 0) {
 
1002
                if (value != NULL)
 
1003
                        mtree->keys |= keybit;
 
1004
                else
 
1005
                        mtree->keys &= ~keybit;
 
1006
                return (ARCHIVE_OK);
 
1007
        }
 
1008
 
 
1009
        return (ARCHIVE_WARN);
 
1010
}
 
1011
 
 
1012
int
 
1013
archive_write_set_format_mtree(struct archive *_a)
 
1014
{
 
1015
        struct archive_write *a = (struct archive_write *)_a;
 
1016
        struct mtree_writer *mtree;
 
1017
 
 
1018
        if (a->format_destroy != NULL)
 
1019
                (a->format_destroy)(a);
 
1020
 
 
1021
        if ((mtree = malloc(sizeof(*mtree))) == NULL) {
 
1022
                archive_set_error(&a->archive, ENOMEM,
 
1023
                    "Can't allocate mtree data");
 
1024
                return (ARCHIVE_FATAL);
 
1025
        }
 
1026
 
 
1027
        mtree->entry = NULL;
 
1028
        mtree->first = 1;
 
1029
        memset(&(mtree->set), 0, sizeof(mtree->set));
 
1030
        archive_string_init(&mtree->set.parent);
 
1031
        mtree->keys = DEFAULT_KEYS;
 
1032
        mtree->dironly = 0;
 
1033
        mtree->indent = 0;
 
1034
        archive_string_init(&mtree->ebuf);
 
1035
        archive_string_init(&mtree->buf);
 
1036
        a->format_data = mtree;
 
1037
        a->format_destroy = archive_write_mtree_destroy;
 
1038
 
 
1039
        a->pad_uncompressed = 0;
 
1040
        a->format_name = "mtree";
 
1041
        a->format_options = archive_write_mtree_options;
 
1042
        a->format_write_header = archive_write_mtree_header;
 
1043
        a->format_finish = archive_write_mtree_finish;
 
1044
        a->format_write_data = archive_write_mtree_data;
 
1045
        a->format_finish_entry = archive_write_mtree_finish_entry;
 
1046
        a->archive.archive_format = ARCHIVE_FORMAT_MTREE;
 
1047
        a->archive.archive_format_name = "mtree";
 
1048
 
 
1049
        return (ARCHIVE_OK);
 
1050
}