~sergei.glushchenko/percona-xtrabackup/xb-pprint

« back to all changes in this revision

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

merge parallel compression branch.

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_entry.c 201096 2009-12-28 02:41:27Z kientzle $");
 
28
 
 
29
#ifdef HAVE_SYS_STAT_H
 
30
#include <sys/stat.h>
 
31
#endif
 
32
#ifdef HAVE_SYS_TYPES_H
 
33
#include <sys/types.h>
 
34
#endif
 
35
#if MAJOR_IN_MKDEV
 
36
#include <sys/mkdev.h>
 
37
#define HAVE_MAJOR
 
38
#elif MAJOR_IN_SYSMACROS
 
39
#include <sys/sysmacros.h>
 
40
#define HAVE_MAJOR
 
41
#endif
 
42
#ifdef HAVE_LIMITS_H
 
43
#include <limits.h>
 
44
#endif
 
45
#ifdef HAVE_LINUX_FS_H
 
46
#include <linux/fs.h>   /* for Linux file flags */
 
47
#endif
 
48
/*
 
49
 * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
 
50
 * As the include guards don't agree, the order of include is important.
 
51
 */
 
52
#ifdef HAVE_LINUX_EXT2_FS_H
 
53
#include <linux/ext2_fs.h>      /* for Linux file flags */
 
54
#endif
 
55
#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
 
56
#include <ext2fs/ext2_fs.h>     /* for Linux file flags */
 
57
#endif
 
58
#include <stddef.h>
 
59
#include <stdio.h>
 
60
#ifdef HAVE_STDLIB_H
 
61
#include <stdlib.h>
 
62
#endif
 
63
#ifdef HAVE_STRING_H
 
64
#include <string.h>
 
65
#endif
 
66
#ifdef HAVE_WCHAR_H
 
67
#include <wchar.h>
 
68
#endif
 
69
 
 
70
#include "archive.h"
 
71
#include "archive_entry.h"
 
72
#include "archive_private.h"
 
73
#include "archive_entry_private.h"
 
74
 
 
75
#undef max
 
76
#define max(a, b)       ((a)>(b)?(a):(b))
 
77
 
 
78
#if !defined(HAVE_MAJOR) && !defined(major)
 
79
/* Replacement for major/minor/makedev. */
 
80
#define major(x) ((int)(0x00ff & ((x) >> 8)))
 
81
#define minor(x) ((int)(0xffff00ff & (x)))
 
82
#define makedev(maj,min) ((0xff00 & ((maj)<<8)) | (0xffff00ff & (min)))
 
83
#endif
 
84
 
 
85
/* Play games to come up with a suitable makedev() definition. */
 
86
#ifdef __QNXNTO__
 
87
/* QNX.  <sigh> */
 
88
#include <sys/netmgr.h>
 
89
#define ae_makedev(maj, min) makedev(ND_LOCAL_NODE, (maj), (min))
 
90
#elif defined makedev
 
91
/* There's a "makedev" macro. */
 
92
#define ae_makedev(maj, min) makedev((maj), (min))
 
93
#elif defined mkdev || ((defined _WIN32 || defined __WIN32__) && !defined(__CYGWIN__))
 
94
/* Windows. <sigh> */
 
95
#define ae_makedev(maj, min) mkdev((maj), (min))
 
96
#else
 
97
/* There's a "makedev" function. */
 
98
#define ae_makedev(maj, min) makedev((maj), (min))
 
99
#endif
 
100
 
 
101
static void     aes_clean(struct aes *);
 
102
static void     aes_copy(struct aes *dest, struct aes *src);
 
103
static const char *     aes_get_mbs(struct aes *);
 
104
static const wchar_t *  aes_get_wcs(struct aes *);
 
105
static int      aes_set_mbs(struct aes *, const char *mbs);
 
106
static int      aes_copy_mbs(struct aes *, const char *mbs);
 
107
/* static void  aes_set_wcs(struct aes *, const wchar_t *wcs); */
 
108
static int      aes_copy_wcs(struct aes *, const wchar_t *wcs);
 
109
static int      aes_copy_wcs_len(struct aes *, const wchar_t *wcs, size_t);
 
110
 
 
111
static char *    ae_fflagstostr(unsigned long bitset, unsigned long bitclear);
 
112
static const wchar_t    *ae_wcstofflags(const wchar_t *stringp,
 
113
                    unsigned long *setp, unsigned long *clrp);
 
114
static const char       *ae_strtofflags(const char *stringp,
 
115
                    unsigned long *setp, unsigned long *clrp);
 
116
static void     append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
 
117
                    const wchar_t *wname, int perm, int id);
 
118
static void     append_id_w(wchar_t **wp, int id);
 
119
 
 
120
static int      acl_special(struct archive_entry *entry,
 
121
                    int type, int permset, int tag);
 
122
static struct ae_acl *acl_new_entry(struct archive_entry *entry,
 
123
                    int type, int permset, int tag, int id);
 
124
static int      isint_w(const wchar_t *start, const wchar_t *end, int *result);
 
125
static int      ismode_w(const wchar_t *start, const wchar_t *end, int *result);
 
126
static void     next_field_w(const wchar_t **wp, const wchar_t **start,
 
127
                    const wchar_t **end, wchar_t *sep);
 
128
static int      prefix_w(const wchar_t *start, const wchar_t *end,
 
129
                    const wchar_t *test);
 
130
static void
 
131
archive_entry_acl_add_entry_w_len(struct archive_entry *entry, int type,
 
132
                    int permset, int tag, int id, const wchar_t *name, size_t);
 
133
 
 
134
 
 
135
#ifndef HAVE_WCSCPY
 
136
static wchar_t * wcscpy(wchar_t *s1, const wchar_t *s2)
 
137
{
 
138
        wchar_t *dest = s1;
 
139
        while ((*s1 = *s2) != L'\0')
 
140
                ++s1, ++s2;
 
141
        return dest;
 
142
}
 
143
#endif
 
144
#ifndef HAVE_WCSLEN
 
145
static size_t wcslen(const wchar_t *s)
 
146
{
 
147
        const wchar_t *p = s;
 
148
        while (*p != L'\0')
 
149
                ++p;
 
150
        return p - s;
 
151
}
 
152
#endif
 
153
#ifndef HAVE_WMEMCMP
 
154
/* Good enough for simple equality testing, but not for sorting. */
 
155
#define wmemcmp(a,b,i)  memcmp((a), (b), (i) * sizeof(wchar_t))
 
156
#endif
 
157
#ifndef HAVE_WMEMCPY
 
158
#define wmemcpy(a,b,i)  (wchar_t *)memcpy((a), (b), (i) * sizeof(wchar_t))
 
159
#endif
 
160
 
 
161
static void
 
162
aes_clean(struct aes *aes)
 
163
{
 
164
        if (aes->aes_wcs) {
 
165
                free((wchar_t *)(uintptr_t)aes->aes_wcs);
 
166
                aes->aes_wcs = NULL;
 
167
        }
 
168
        archive_string_free(&(aes->aes_mbs));
 
169
        archive_string_free(&(aes->aes_utf8));
 
170
        aes->aes_set = 0;
 
171
}
 
172
 
 
173
static void
 
174
aes_copy(struct aes *dest, struct aes *src)
 
175
{
 
176
        wchar_t *wp;
 
177
 
 
178
        dest->aes_set = src->aes_set;
 
179
        archive_string_copy(&(dest->aes_mbs), &(src->aes_mbs));
 
180
        archive_string_copy(&(dest->aes_utf8), &(src->aes_utf8));
 
181
 
 
182
        if (src->aes_wcs != NULL) {
 
183
                wp = (wchar_t *)malloc((wcslen(src->aes_wcs) + 1)
 
184
                    * sizeof(wchar_t));
 
185
                if (wp == NULL)
 
186
                        __archive_errx(1, "No memory for aes_copy()");
 
187
                wcscpy(wp, src->aes_wcs);
 
188
                dest->aes_wcs = wp;
 
189
        }
 
190
}
 
191
 
 
192
static const char *
 
193
aes_get_utf8(struct aes *aes)
 
194
{
 
195
        if (aes->aes_set & AES_SET_UTF8)
 
196
                return (aes->aes_utf8.s);
 
197
        if ((aes->aes_set & AES_SET_WCS)
 
198
            && archive_strappend_w_utf8(&(aes->aes_utf8), aes->aes_wcs) != NULL) {
 
199
                aes->aes_set |= AES_SET_UTF8;
 
200
                return (aes->aes_utf8.s);
 
201
        }
 
202
        return (NULL);
 
203
}
 
204
 
 
205
static const char *
 
206
aes_get_mbs(struct aes *aes)
 
207
{
 
208
        /* If we already have an MBS form, return that immediately. */
 
209
        if (aes->aes_set & AES_SET_MBS)
 
210
                return (aes->aes_mbs.s);
 
211
        /* If there's a WCS form, try converting with the native locale. */
 
212
        if ((aes->aes_set & AES_SET_WCS)
 
213
            && archive_strappend_w_mbs(&(aes->aes_mbs), aes->aes_wcs) != NULL) {
 
214
                aes->aes_set |= AES_SET_MBS;
 
215
                return (aes->aes_mbs.s);
 
216
        }
 
217
        /* We'll use UTF-8 for MBS if all else fails. */
 
218
        return (aes_get_utf8(aes));
 
219
}
 
220
 
 
221
static const wchar_t *
 
222
aes_get_wcs(struct aes *aes)
 
223
{
 
224
        wchar_t *w;
 
225
        size_t r;
 
226
 
 
227
        /* Return WCS form if we already have it. */
 
228
        if (aes->aes_set & AES_SET_WCS)
 
229
                return (aes->aes_wcs);
 
230
 
 
231
        if (aes->aes_set & AES_SET_MBS) {
 
232
                /* Try converting MBS to WCS using native locale. */
 
233
                /*
 
234
                 * No single byte will be more than one wide character,
 
235
                 * so this length estimate will always be big enough.
 
236
                 */
 
237
                size_t wcs_length = aes->aes_mbs.length;
 
238
 
 
239
                w = (wchar_t *)malloc((wcs_length + 1) * sizeof(wchar_t));
 
240
                if (w == NULL)
 
241
                        __archive_errx(1, "No memory for aes_get_wcs()");
 
242
                r = mbstowcs(w, aes->aes_mbs.s, wcs_length);
 
243
                if (r != (size_t)-1 && r != 0) {
 
244
                        w[r] = 0;
 
245
                        aes->aes_set |= AES_SET_WCS;
 
246
                        return (aes->aes_wcs = w);
 
247
                }
 
248
                free(w);
 
249
        }
 
250
 
 
251
        if (aes->aes_set & AES_SET_UTF8) {
 
252
                /* Try converting UTF8 to WCS. */
 
253
                aes->aes_wcs = __archive_string_utf8_w(&(aes->aes_utf8));
 
254
                if (aes->aes_wcs != NULL)
 
255
                        aes->aes_set |= AES_SET_WCS;
 
256
                return (aes->aes_wcs);
 
257
        }
 
258
        return (NULL);
 
259
}
 
260
 
 
261
static int
 
262
aes_set_mbs(struct aes *aes, const char *mbs)
 
263
{
 
264
        return (aes_copy_mbs(aes, mbs));
 
265
}
 
266
 
 
267
static int
 
268
aes_copy_mbs(struct aes *aes, const char *mbs)
 
269
{
 
270
        if (mbs == NULL) {
 
271
                aes->aes_set = 0;
 
272
                return (0);
 
273
        }
 
274
        aes->aes_set = AES_SET_MBS; /* Only MBS form is set now. */
 
275
        archive_strcpy(&(aes->aes_mbs), mbs);
 
276
        archive_string_empty(&(aes->aes_utf8));
 
277
        if (aes->aes_wcs) {
 
278
                free((wchar_t *)(uintptr_t)aes->aes_wcs);
 
279
                aes->aes_wcs = NULL;
 
280
        }
 
281
        return (0);
 
282
}
 
283
 
 
284
/*
 
285
 * The 'update' form tries to proactively update all forms of
 
286
 * this string (WCS and MBS) and returns an error if any of
 
287
 * them fail.  This is used by the 'pax' handler, for instance,
 
288
 * to detect and report character-conversion failures early while
 
289
 * still allowing clients to get potentially useful values from
 
290
 * the more tolerant lazy conversions.  (get_mbs and get_wcs will
 
291
 * strive to give the user something useful, so you can get hopefully
 
292
 * usable values even if some of the character conversions are failing.)
 
293
 */
 
294
static int
 
295
aes_update_utf8(struct aes *aes, const char *utf8)
 
296
{
 
297
        if (utf8 == NULL) {
 
298
                aes->aes_set = 0;
 
299
                return (1); /* Succeeded in clearing everything. */
 
300
        }
 
301
 
 
302
        /* Save the UTF8 string. */
 
303
        archive_strcpy(&(aes->aes_utf8), utf8);
 
304
 
 
305
        /* Empty the mbs and wcs strings. */
 
306
        archive_string_empty(&(aes->aes_mbs));
 
307
        if (aes->aes_wcs) {
 
308
                free((wchar_t *)(uintptr_t)aes->aes_wcs);
 
309
                aes->aes_wcs = NULL;
 
310
        }
 
311
 
 
312
        aes->aes_set = AES_SET_UTF8;    /* Only UTF8 is set now. */
 
313
 
 
314
        /* TODO: We should just do a direct UTF-8 to MBS conversion
 
315
         * here.  That would be faster, use less space, and give the
 
316
         * same information.  (If a UTF-8 to MBS conversion succeeds,
 
317
         * then UTF-8->WCS and Unicode->MBS conversions will both
 
318
         * succeed.) */
 
319
 
 
320
        /* Try converting UTF8 to WCS, return false on failure. */
 
321
        aes->aes_wcs = __archive_string_utf8_w(&(aes->aes_utf8));
 
322
        if (aes->aes_wcs == NULL)
 
323
                return (0);
 
324
        aes->aes_set = AES_SET_UTF8 | AES_SET_WCS; /* Both UTF8 and WCS set. */
 
325
 
 
326
        /* Try converting WCS to MBS, return false on failure. */
 
327
        if (archive_strappend_w_mbs(&(aes->aes_mbs), aes->aes_wcs) == NULL)
 
328
                return (0);
 
329
        aes->aes_set = AES_SET_UTF8 | AES_SET_WCS | AES_SET_MBS;
 
330
 
 
331
        /* All conversions succeeded. */
 
332
        return (1);
 
333
}
 
334
 
 
335
static int
 
336
aes_copy_wcs(struct aes *aes, const wchar_t *wcs)
 
337
{
 
338
        return aes_copy_wcs_len(aes, wcs, wcs == NULL ? 0 : wcslen(wcs));
 
339
}
 
340
 
 
341
static int
 
342
aes_copy_wcs_len(struct aes *aes, const wchar_t *wcs, size_t len)
 
343
{
 
344
        wchar_t *w;
 
345
 
 
346
        if (wcs == NULL) {
 
347
                aes->aes_set = 0;
 
348
                return (0);
 
349
        }
 
350
        aes->aes_set = AES_SET_WCS; /* Only WCS form set. */
 
351
        archive_string_empty(&(aes->aes_mbs));
 
352
        archive_string_empty(&(aes->aes_utf8));
 
353
        if (aes->aes_wcs) {
 
354
                free((wchar_t *)(uintptr_t)aes->aes_wcs);
 
355
                aes->aes_wcs = NULL;
 
356
        }
 
357
        w = (wchar_t *)malloc((len + 1) * sizeof(wchar_t));
 
358
        if (w == NULL)
 
359
                __archive_errx(1, "No memory for aes_copy_wcs()");
 
360
        wmemcpy(w, wcs, len);
 
361
        w[len] = L'\0';
 
362
        aes->aes_wcs = w;
 
363
        return (0);
 
364
}
 
365
 
 
366
/****************************************************************************
 
367
 *
 
368
 * Public Interface
 
369
 *
 
370
 ****************************************************************************/
 
371
 
 
372
struct archive_entry *
 
373
archive_entry_clear(struct archive_entry *entry)
 
374
{
 
375
        if (entry == NULL)
 
376
                return (NULL);
 
377
        aes_clean(&entry->ae_fflags_text);
 
378
        aes_clean(&entry->ae_gname);
 
379
        aes_clean(&entry->ae_hardlink);
 
380
        aes_clean(&entry->ae_pathname);
 
381
        aes_clean(&entry->ae_sourcepath);
 
382
        aes_clean(&entry->ae_symlink);
 
383
        aes_clean(&entry->ae_uname);
 
384
        archive_entry_acl_clear(entry);
 
385
        archive_entry_xattr_clear(entry);
 
386
        free(entry->stat);
 
387
        memset(entry, 0, sizeof(*entry));
 
388
        return entry;
 
389
}
 
390
 
 
391
struct archive_entry *
 
392
archive_entry_clone(struct archive_entry *entry)
 
393
{
 
394
        struct archive_entry *entry2;
 
395
        struct ae_acl *ap, *ap2;
 
396
        struct ae_xattr *xp;
 
397
 
 
398
        /* Allocate new structure and copy over all of the fields. */
 
399
        entry2 = (struct archive_entry *)malloc(sizeof(*entry2));
 
400
        if (entry2 == NULL)
 
401
                return (NULL);
 
402
        memset(entry2, 0, sizeof(*entry2));
 
403
        entry2->ae_stat = entry->ae_stat;
 
404
        entry2->ae_fflags_set = entry->ae_fflags_set;
 
405
        entry2->ae_fflags_clear = entry->ae_fflags_clear;
 
406
 
 
407
        aes_copy(&entry2->ae_fflags_text, &entry->ae_fflags_text);
 
408
        aes_copy(&entry2->ae_gname, &entry->ae_gname);
 
409
        aes_copy(&entry2->ae_hardlink, &entry->ae_hardlink);
 
410
        aes_copy(&entry2->ae_pathname, &entry->ae_pathname);
 
411
        aes_copy(&entry2->ae_sourcepath, &entry->ae_sourcepath);
 
412
        aes_copy(&entry2->ae_symlink, &entry->ae_symlink);
 
413
        entry2->ae_set = entry->ae_set;
 
414
        aes_copy(&entry2->ae_uname, &entry->ae_uname);
 
415
 
 
416
        /* Copy ACL data over. */
 
417
        ap = entry->acl_head;
 
418
        while (ap != NULL) {
 
419
                ap2 = acl_new_entry(entry2,
 
420
                    ap->type, ap->permset, ap->tag, ap->id);
 
421
                if (ap2 != NULL)
 
422
                        aes_copy(&ap2->name, &ap->name);
 
423
                ap = ap->next;
 
424
        }
 
425
 
 
426
        /* Copy xattr data over. */
 
427
        xp = entry->xattr_head;
 
428
        while (xp != NULL) {
 
429
                archive_entry_xattr_add_entry(entry2,
 
430
                    xp->name, xp->value, xp->size);
 
431
                xp = xp->next;
 
432
        }
 
433
 
 
434
        return (entry2);
 
435
}
 
436
 
 
437
void
 
438
archive_entry_free(struct archive_entry *entry)
 
439
{
 
440
        archive_entry_clear(entry);
 
441
        free(entry);
 
442
}
 
443
 
 
444
struct archive_entry *
 
445
archive_entry_new(void)
 
446
{
 
447
        struct archive_entry *entry;
 
448
 
 
449
        entry = (struct archive_entry *)malloc(sizeof(*entry));
 
450
        if (entry == NULL)
 
451
                return (NULL);
 
452
        memset(entry, 0, sizeof(*entry));
 
453
        return (entry);
 
454
}
 
455
 
 
456
/*
 
457
 * Functions for reading fields from an archive_entry.
 
458
 */
 
459
 
 
460
time_t
 
461
archive_entry_atime(struct archive_entry *entry)
 
462
{
 
463
        return (entry->ae_stat.aest_atime);
 
464
}
 
465
 
 
466
long
 
467
archive_entry_atime_nsec(struct archive_entry *entry)
 
468
{
 
469
        return (entry->ae_stat.aest_atime_nsec);
 
470
}
 
471
 
 
472
int
 
473
archive_entry_atime_is_set(struct archive_entry *entry)
 
474
{
 
475
        return (entry->ae_set & AE_SET_ATIME);
 
476
}
 
477
 
 
478
time_t
 
479
archive_entry_birthtime(struct archive_entry *entry)
 
480
{
 
481
        return (entry->ae_stat.aest_birthtime);
 
482
}
 
483
 
 
484
long
 
485
archive_entry_birthtime_nsec(struct archive_entry *entry)
 
486
{
 
487
        return (entry->ae_stat.aest_birthtime_nsec);
 
488
}
 
489
 
 
490
int
 
491
archive_entry_birthtime_is_set(struct archive_entry *entry)
 
492
{
 
493
        return (entry->ae_set & AE_SET_BIRTHTIME);
 
494
}
 
495
 
 
496
time_t
 
497
archive_entry_ctime(struct archive_entry *entry)
 
498
{
 
499
        return (entry->ae_stat.aest_ctime);
 
500
}
 
501
 
 
502
int
 
503
archive_entry_ctime_is_set(struct archive_entry *entry)
 
504
{
 
505
        return (entry->ae_set & AE_SET_CTIME);
 
506
}
 
507
 
 
508
long
 
509
archive_entry_ctime_nsec(struct archive_entry *entry)
 
510
{
 
511
        return (entry->ae_stat.aest_ctime_nsec);
 
512
}
 
513
 
 
514
dev_t
 
515
archive_entry_dev(struct archive_entry *entry)
 
516
{
 
517
        if (entry->ae_stat.aest_dev_is_broken_down)
 
518
                return ae_makedev(entry->ae_stat.aest_devmajor,
 
519
                    entry->ae_stat.aest_devminor);
 
520
        else
 
521
                return (entry->ae_stat.aest_dev);
 
522
}
 
523
 
 
524
dev_t
 
525
archive_entry_devmajor(struct archive_entry *entry)
 
526
{
 
527
        if (entry->ae_stat.aest_dev_is_broken_down)
 
528
                return (entry->ae_stat.aest_devmajor);
 
529
        else
 
530
                return major(entry->ae_stat.aest_dev);
 
531
}
 
532
 
 
533
dev_t
 
534
archive_entry_devminor(struct archive_entry *entry)
 
535
{
 
536
        if (entry->ae_stat.aest_dev_is_broken_down)
 
537
                return (entry->ae_stat.aest_devminor);
 
538
        else
 
539
                return minor(entry->ae_stat.aest_dev);
 
540
}
 
541
 
 
542
mode_t
 
543
archive_entry_filetype(struct archive_entry *entry)
 
544
{
 
545
        return (AE_IFMT & entry->ae_stat.aest_mode);
 
546
}
 
547
 
 
548
void
 
549
archive_entry_fflags(struct archive_entry *entry,
 
550
    unsigned long *set, unsigned long *clear)
 
551
{
 
552
        *set = entry->ae_fflags_set;
 
553
        *clear = entry->ae_fflags_clear;
 
554
}
 
555
 
 
556
/*
 
557
 * Note: if text was provided, this just returns that text.  If you
 
558
 * really need the text to be rebuilt in a canonical form, set the
 
559
 * text, ask for the bitmaps, then set the bitmaps.  (Setting the
 
560
 * bitmaps clears any stored text.)  This design is deliberate: if
 
561
 * we're editing archives, we don't want to discard flags just because
 
562
 * they aren't supported on the current system.  The bitmap<->text
 
563
 * conversions are platform-specific (see below).
 
564
 */
 
565
const char *
 
566
archive_entry_fflags_text(struct archive_entry *entry)
 
567
{
 
568
        const char *f;
 
569
        char *p;
 
570
 
 
571
        f = aes_get_mbs(&entry->ae_fflags_text);
 
572
        if (f != NULL)
 
573
                return (f);
 
574
 
 
575
        if (entry->ae_fflags_set == 0  &&  entry->ae_fflags_clear == 0)
 
576
                return (NULL);
 
577
 
 
578
        p = ae_fflagstostr(entry->ae_fflags_set, entry->ae_fflags_clear);
 
579
        if (p == NULL)
 
580
                return (NULL);
 
581
 
 
582
        aes_copy_mbs(&entry->ae_fflags_text, p);
 
583
        free(p);
 
584
        f = aes_get_mbs(&entry->ae_fflags_text);
 
585
        return (f);
 
586
}
 
587
 
 
588
gid_t
 
589
archive_entry_gid(struct archive_entry *entry)
 
590
{
 
591
        return (entry->ae_stat.aest_gid);
 
592
}
 
593
 
 
594
const char *
 
595
archive_entry_gname(struct archive_entry *entry)
 
596
{
 
597
        return (aes_get_mbs(&entry->ae_gname));
 
598
}
 
599
 
 
600
const wchar_t *
 
601
archive_entry_gname_w(struct archive_entry *entry)
 
602
{
 
603
        return (aes_get_wcs(&entry->ae_gname));
 
604
}
 
605
 
 
606
const char *
 
607
archive_entry_hardlink(struct archive_entry *entry)
 
608
{
 
609
        if (entry->ae_set & AE_SET_HARDLINK)
 
610
                return (aes_get_mbs(&entry->ae_hardlink));
 
611
        return (NULL);
 
612
}
 
613
 
 
614
const wchar_t *
 
615
archive_entry_hardlink_w(struct archive_entry *entry)
 
616
{
 
617
        if (entry->ae_set & AE_SET_HARDLINK)
 
618
                return (aes_get_wcs(&entry->ae_hardlink));
 
619
        return (NULL);
 
620
}
 
621
 
 
622
ino_t
 
623
archive_entry_ino(struct archive_entry *entry)
 
624
{
 
625
        return (entry->ae_stat.aest_ino);
 
626
}
 
627
 
 
628
int64_t
 
629
archive_entry_ino64(struct archive_entry *entry)
 
630
{
 
631
        return (entry->ae_stat.aest_ino);
 
632
}
 
633
 
 
634
mode_t
 
635
archive_entry_mode(struct archive_entry *entry)
 
636
{
 
637
        return (entry->ae_stat.aest_mode);
 
638
}
 
639
 
 
640
time_t
 
641
archive_entry_mtime(struct archive_entry *entry)
 
642
{
 
643
        return (entry->ae_stat.aest_mtime);
 
644
}
 
645
 
 
646
long
 
647
archive_entry_mtime_nsec(struct archive_entry *entry)
 
648
{
 
649
        return (entry->ae_stat.aest_mtime_nsec);
 
650
}
 
651
 
 
652
int
 
653
archive_entry_mtime_is_set(struct archive_entry *entry)
 
654
{
 
655
        return (entry->ae_set & AE_SET_MTIME);
 
656
}
 
657
 
 
658
unsigned int
 
659
archive_entry_nlink(struct archive_entry *entry)
 
660
{
 
661
        return (entry->ae_stat.aest_nlink);
 
662
}
 
663
 
 
664
const char *
 
665
archive_entry_pathname(struct archive_entry *entry)
 
666
{
 
667
        return (aes_get_mbs(&entry->ae_pathname));
 
668
}
 
669
 
 
670
const wchar_t *
 
671
archive_entry_pathname_w(struct archive_entry *entry)
 
672
{
 
673
        return (aes_get_wcs(&entry->ae_pathname));
 
674
}
 
675
 
 
676
dev_t
 
677
archive_entry_rdev(struct archive_entry *entry)
 
678
{
 
679
        if (entry->ae_stat.aest_rdev_is_broken_down)
 
680
                return ae_makedev(entry->ae_stat.aest_rdevmajor,
 
681
                    entry->ae_stat.aest_rdevminor);
 
682
        else
 
683
                return (entry->ae_stat.aest_rdev);
 
684
}
 
685
 
 
686
dev_t
 
687
archive_entry_rdevmajor(struct archive_entry *entry)
 
688
{
 
689
        if (entry->ae_stat.aest_rdev_is_broken_down)
 
690
                return (entry->ae_stat.aest_rdevmajor);
 
691
        else
 
692
                return major(entry->ae_stat.aest_rdev);
 
693
}
 
694
 
 
695
dev_t
 
696
archive_entry_rdevminor(struct archive_entry *entry)
 
697
{
 
698
        if (entry->ae_stat.aest_rdev_is_broken_down)
 
699
                return (entry->ae_stat.aest_rdevminor);
 
700
        else
 
701
                return minor(entry->ae_stat.aest_rdev);
 
702
}
 
703
 
 
704
int64_t
 
705
archive_entry_size(struct archive_entry *entry)
 
706
{
 
707
        return (entry->ae_stat.aest_size);
 
708
}
 
709
 
 
710
int
 
711
archive_entry_size_is_set(struct archive_entry *entry)
 
712
{
 
713
        return (entry->ae_set & AE_SET_SIZE);
 
714
}
 
715
 
 
716
const char *
 
717
archive_entry_sourcepath(struct archive_entry *entry)
 
718
{
 
719
        return (aes_get_mbs(&entry->ae_sourcepath));
 
720
}
 
721
 
 
722
const char *
 
723
archive_entry_symlink(struct archive_entry *entry)
 
724
{
 
725
        if (entry->ae_set & AE_SET_SYMLINK)
 
726
                return (aes_get_mbs(&entry->ae_symlink));
 
727
        return (NULL);
 
728
}
 
729
 
 
730
const wchar_t *
 
731
archive_entry_symlink_w(struct archive_entry *entry)
 
732
{
 
733
        if (entry->ae_set & AE_SET_SYMLINK)
 
734
                return (aes_get_wcs(&entry->ae_symlink));
 
735
        return (NULL);
 
736
}
 
737
 
 
738
uid_t
 
739
archive_entry_uid(struct archive_entry *entry)
 
740
{
 
741
        return (entry->ae_stat.aest_uid);
 
742
}
 
743
 
 
744
const char *
 
745
archive_entry_uname(struct archive_entry *entry)
 
746
{
 
747
        return (aes_get_mbs(&entry->ae_uname));
 
748
}
 
749
 
 
750
const wchar_t *
 
751
archive_entry_uname_w(struct archive_entry *entry)
 
752
{
 
753
        return (aes_get_wcs(&entry->ae_uname));
 
754
}
 
755
 
 
756
/*
 
757
 * Functions to set archive_entry properties.
 
758
 */
 
759
 
 
760
void
 
761
archive_entry_set_filetype(struct archive_entry *entry, unsigned int type)
 
762
{
 
763
        entry->stat_valid = 0;
 
764
        entry->ae_stat.aest_mode &= ~AE_IFMT;
 
765
        entry->ae_stat.aest_mode |= AE_IFMT & type;
 
766
}
 
767
 
 
768
void
 
769
archive_entry_set_fflags(struct archive_entry *entry,
 
770
    unsigned long set, unsigned long clear)
 
771
{
 
772
        aes_clean(&entry->ae_fflags_text);
 
773
        entry->ae_fflags_set = set;
 
774
        entry->ae_fflags_clear = clear;
 
775
}
 
776
 
 
777
const char *
 
778
archive_entry_copy_fflags_text(struct archive_entry *entry,
 
779
    const char *flags)
 
780
{
 
781
        aes_copy_mbs(&entry->ae_fflags_text, flags);
 
782
        return (ae_strtofflags(flags,
 
783
                    &entry->ae_fflags_set, &entry->ae_fflags_clear));
 
784
}
 
785
 
 
786
const wchar_t *
 
787
archive_entry_copy_fflags_text_w(struct archive_entry *entry,
 
788
    const wchar_t *flags)
 
789
{
 
790
        aes_copy_wcs(&entry->ae_fflags_text, flags);
 
791
        return (ae_wcstofflags(flags,
 
792
                    &entry->ae_fflags_set, &entry->ae_fflags_clear));
 
793
}
 
794
 
 
795
void
 
796
archive_entry_set_gid(struct archive_entry *entry, gid_t g)
 
797
{
 
798
        entry->stat_valid = 0;
 
799
        entry->ae_stat.aest_gid = g;
 
800
}
 
801
 
 
802
void
 
803
archive_entry_set_gname(struct archive_entry *entry, const char *name)
 
804
{
 
805
        aes_set_mbs(&entry->ae_gname, name);
 
806
}
 
807
 
 
808
void
 
809
archive_entry_copy_gname(struct archive_entry *entry, const char *name)
 
810
{
 
811
        aes_copy_mbs(&entry->ae_gname, name);
 
812
}
 
813
 
 
814
void
 
815
archive_entry_copy_gname_w(struct archive_entry *entry, const wchar_t *name)
 
816
{
 
817
        aes_copy_wcs(&entry->ae_gname, name);
 
818
}
 
819
 
 
820
int
 
821
archive_entry_update_gname_utf8(struct archive_entry *entry, const char *name)
 
822
{
 
823
        return (aes_update_utf8(&entry->ae_gname, name));
 
824
}
 
825
 
 
826
void
 
827
archive_entry_set_ino(struct archive_entry *entry, unsigned long ino)
 
828
{
 
829
        entry->stat_valid = 0;
 
830
        entry->ae_stat.aest_ino = ino;
 
831
}
 
832
 
 
833
void
 
834
archive_entry_set_ino64(struct archive_entry *entry, int64_t ino)
 
835
{
 
836
        entry->stat_valid = 0;
 
837
        entry->ae_stat.aest_ino = ino;
 
838
}
 
839
 
 
840
void
 
841
archive_entry_set_hardlink(struct archive_entry *entry, const char *target)
 
842
{
 
843
        aes_set_mbs(&entry->ae_hardlink, target);
 
844
        if (target != NULL)
 
845
                entry->ae_set |= AE_SET_HARDLINK;
 
846
        else
 
847
                entry->ae_set &= ~AE_SET_HARDLINK;
 
848
}
 
849
 
 
850
void
 
851
archive_entry_copy_hardlink(struct archive_entry *entry, const char *target)
 
852
{
 
853
        aes_copy_mbs(&entry->ae_hardlink, target);
 
854
        if (target != NULL)
 
855
                entry->ae_set |= AE_SET_HARDLINK;
 
856
        else
 
857
                entry->ae_set &= ~AE_SET_HARDLINK;
 
858
}
 
859
 
 
860
void
 
861
archive_entry_copy_hardlink_w(struct archive_entry *entry, const wchar_t *target)
 
862
{
 
863
        aes_copy_wcs(&entry->ae_hardlink, target);
 
864
        if (target != NULL)
 
865
                entry->ae_set |= AE_SET_HARDLINK;
 
866
        else
 
867
                entry->ae_set &= ~AE_SET_HARDLINK;
 
868
}
 
869
 
 
870
int
 
871
archive_entry_update_hardlink_utf8(struct archive_entry *entry, const char *target)
 
872
{
 
873
        if (target != NULL)
 
874
                entry->ae_set |= AE_SET_HARDLINK;
 
875
        else
 
876
                entry->ae_set &= ~AE_SET_HARDLINK;
 
877
        return (aes_update_utf8(&entry->ae_hardlink, target));
 
878
}
 
879
 
 
880
void
 
881
archive_entry_set_atime(struct archive_entry *entry, time_t t, long ns)
 
882
{
 
883
        entry->stat_valid = 0;
 
884
        entry->ae_set |= AE_SET_ATIME;
 
885
        entry->ae_stat.aest_atime = t;
 
886
        entry->ae_stat.aest_atime_nsec = ns;
 
887
}
 
888
 
 
889
void
 
890
archive_entry_unset_atime(struct archive_entry *entry)
 
891
{
 
892
        archive_entry_set_atime(entry, 0, 0);
 
893
        entry->ae_set &= ~AE_SET_ATIME;
 
894
}
 
895
 
 
896
void
 
897
archive_entry_set_birthtime(struct archive_entry *entry, time_t m, long ns)
 
898
{
 
899
        entry->stat_valid = 0;
 
900
        entry->ae_set |= AE_SET_BIRTHTIME;
 
901
        entry->ae_stat.aest_birthtime = m;
 
902
        entry->ae_stat.aest_birthtime_nsec = ns;
 
903
}
 
904
 
 
905
void
 
906
archive_entry_unset_birthtime(struct archive_entry *entry)
 
907
{
 
908
        archive_entry_set_birthtime(entry, 0, 0);
 
909
        entry->ae_set &= ~AE_SET_BIRTHTIME;
 
910
}
 
911
 
 
912
void
 
913
archive_entry_set_ctime(struct archive_entry *entry, time_t t, long ns)
 
914
{
 
915
        entry->stat_valid = 0;
 
916
        entry->ae_set |= AE_SET_CTIME;
 
917
        entry->ae_stat.aest_ctime = t;
 
918
        entry->ae_stat.aest_ctime_nsec = ns;
 
919
}
 
920
 
 
921
void
 
922
archive_entry_unset_ctime(struct archive_entry *entry)
 
923
{
 
924
        archive_entry_set_ctime(entry, 0, 0);
 
925
        entry->ae_set &= ~AE_SET_CTIME;
 
926
}
 
927
 
 
928
void
 
929
archive_entry_set_dev(struct archive_entry *entry, dev_t d)
 
930
{
 
931
        entry->stat_valid = 0;
 
932
        entry->ae_stat.aest_dev_is_broken_down = 0;
 
933
        entry->ae_stat.aest_dev = d;
 
934
}
 
935
 
 
936
void
 
937
archive_entry_set_devmajor(struct archive_entry *entry, dev_t m)
 
938
{
 
939
        entry->stat_valid = 0;
 
940
        entry->ae_stat.aest_dev_is_broken_down = 1;
 
941
        entry->ae_stat.aest_devmajor = m;
 
942
}
 
943
 
 
944
void
 
945
archive_entry_set_devminor(struct archive_entry *entry, dev_t m)
 
946
{
 
947
        entry->stat_valid = 0;
 
948
        entry->ae_stat.aest_dev_is_broken_down = 1;
 
949
        entry->ae_stat.aest_devminor = m;
 
950
}
 
951
 
 
952
/* Set symlink if symlink is already set, else set hardlink. */
 
953
void
 
954
archive_entry_set_link(struct archive_entry *entry, const char *target)
 
955
{
 
956
        if (entry->ae_set & AE_SET_SYMLINK)
 
957
                aes_set_mbs(&entry->ae_symlink, target);
 
958
        else
 
959
                aes_set_mbs(&entry->ae_hardlink, target);
 
960
}
 
961
 
 
962
/* Set symlink if symlink is already set, else set hardlink. */
 
963
void
 
964
archive_entry_copy_link(struct archive_entry *entry, const char *target)
 
965
{
 
966
        if (entry->ae_set & AE_SET_SYMLINK)
 
967
                aes_copy_mbs(&entry->ae_symlink, target);
 
968
        else
 
969
                aes_copy_mbs(&entry->ae_hardlink, target);
 
970
}
 
971
 
 
972
/* Set symlink if symlink is already set, else set hardlink. */
 
973
void
 
974
archive_entry_copy_link_w(struct archive_entry *entry, const wchar_t *target)
 
975
{
 
976
        if (entry->ae_set & AE_SET_SYMLINK)
 
977
                aes_copy_wcs(&entry->ae_symlink, target);
 
978
        else
 
979
                aes_copy_wcs(&entry->ae_hardlink, target);
 
980
}
 
981
 
 
982
int
 
983
archive_entry_update_link_utf8(struct archive_entry *entry, const char *target)
 
984
{
 
985
        if (entry->ae_set & AE_SET_SYMLINK)
 
986
                return (aes_update_utf8(&entry->ae_symlink, target));
 
987
        else
 
988
                return (aes_update_utf8(&entry->ae_hardlink, target));
 
989
}
 
990
 
 
991
void
 
992
archive_entry_set_mode(struct archive_entry *entry, mode_t m)
 
993
{
 
994
        entry->stat_valid = 0;
 
995
        entry->ae_stat.aest_mode = m;
 
996
}
 
997
 
 
998
void
 
999
archive_entry_set_mtime(struct archive_entry *entry, time_t m, long ns)
 
1000
{
 
1001
        entry->stat_valid = 0;
 
1002
        entry->ae_set |= AE_SET_MTIME;
 
1003
        entry->ae_stat.aest_mtime = m;
 
1004
        entry->ae_stat.aest_mtime_nsec = ns;
 
1005
}
 
1006
 
 
1007
void
 
1008
archive_entry_unset_mtime(struct archive_entry *entry)
 
1009
{
 
1010
        archive_entry_set_mtime(entry, 0, 0);
 
1011
        entry->ae_set &= ~AE_SET_MTIME;
 
1012
}
 
1013
 
 
1014
void
 
1015
archive_entry_set_nlink(struct archive_entry *entry, unsigned int nlink)
 
1016
{
 
1017
        entry->stat_valid = 0;
 
1018
        entry->ae_stat.aest_nlink = nlink;
 
1019
}
 
1020
 
 
1021
void
 
1022
archive_entry_set_pathname(struct archive_entry *entry, const char *name)
 
1023
{
 
1024
        aes_set_mbs(&entry->ae_pathname, name);
 
1025
}
 
1026
 
 
1027
void
 
1028
archive_entry_copy_pathname(struct archive_entry *entry, const char *name)
 
1029
{
 
1030
        aes_copy_mbs(&entry->ae_pathname, name);
 
1031
}
 
1032
 
 
1033
void
 
1034
archive_entry_copy_pathname_w(struct archive_entry *entry, const wchar_t *name)
 
1035
{
 
1036
        aes_copy_wcs(&entry->ae_pathname, name);
 
1037
}
 
1038
 
 
1039
int
 
1040
archive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name)
 
1041
{
 
1042
        return (aes_update_utf8(&entry->ae_pathname, name));
 
1043
}
 
1044
 
 
1045
void
 
1046
archive_entry_set_perm(struct archive_entry *entry, mode_t p)
 
1047
{
 
1048
        entry->stat_valid = 0;
 
1049
        entry->ae_stat.aest_mode &= AE_IFMT;
 
1050
        entry->ae_stat.aest_mode |= ~AE_IFMT & p;
 
1051
}
 
1052
 
 
1053
void
 
1054
archive_entry_set_rdev(struct archive_entry *entry, dev_t m)
 
1055
{
 
1056
        entry->stat_valid = 0;
 
1057
        entry->ae_stat.aest_rdev = m;
 
1058
        entry->ae_stat.aest_rdev_is_broken_down = 0;
 
1059
}
 
1060
 
 
1061
void
 
1062
archive_entry_set_rdevmajor(struct archive_entry *entry, dev_t m)
 
1063
{
 
1064
        entry->stat_valid = 0;
 
1065
        entry->ae_stat.aest_rdev_is_broken_down = 1;
 
1066
        entry->ae_stat.aest_rdevmajor = m;
 
1067
}
 
1068
 
 
1069
void
 
1070
archive_entry_set_rdevminor(struct archive_entry *entry, dev_t m)
 
1071
{
 
1072
        entry->stat_valid = 0;
 
1073
        entry->ae_stat.aest_rdev_is_broken_down = 1;
 
1074
        entry->ae_stat.aest_rdevminor = m;
 
1075
}
 
1076
 
 
1077
void
 
1078
archive_entry_set_size(struct archive_entry *entry, int64_t s)
 
1079
{
 
1080
        entry->stat_valid = 0;
 
1081
        entry->ae_stat.aest_size = s;
 
1082
        entry->ae_set |= AE_SET_SIZE;
 
1083
}
 
1084
 
 
1085
void
 
1086
archive_entry_unset_size(struct archive_entry *entry)
 
1087
{
 
1088
        archive_entry_set_size(entry, 0);
 
1089
        entry->ae_set &= ~AE_SET_SIZE;
 
1090
}
 
1091
 
 
1092
void
 
1093
archive_entry_copy_sourcepath(struct archive_entry *entry, const char *path)
 
1094
{
 
1095
        aes_set_mbs(&entry->ae_sourcepath, path);
 
1096
}
 
1097
 
 
1098
void
 
1099
archive_entry_set_symlink(struct archive_entry *entry, const char *linkname)
 
1100
{
 
1101
        aes_set_mbs(&entry->ae_symlink, linkname);
 
1102
        if (linkname != NULL)
 
1103
                entry->ae_set |= AE_SET_SYMLINK;
 
1104
        else
 
1105
                entry->ae_set &= ~AE_SET_SYMLINK;
 
1106
}
 
1107
 
 
1108
void
 
1109
archive_entry_copy_symlink(struct archive_entry *entry, const char *linkname)
 
1110
{
 
1111
        aes_copy_mbs(&entry->ae_symlink, linkname);
 
1112
        if (linkname != NULL)
 
1113
                entry->ae_set |= AE_SET_SYMLINK;
 
1114
        else
 
1115
                entry->ae_set &= ~AE_SET_SYMLINK;
 
1116
}
 
1117
 
 
1118
void
 
1119
archive_entry_copy_symlink_w(struct archive_entry *entry, const wchar_t *linkname)
 
1120
{
 
1121
        aes_copy_wcs(&entry->ae_symlink, linkname);
 
1122
        if (linkname != NULL)
 
1123
                entry->ae_set |= AE_SET_SYMLINK;
 
1124
        else
 
1125
                entry->ae_set &= ~AE_SET_SYMLINK;
 
1126
}
 
1127
 
 
1128
int
 
1129
archive_entry_update_symlink_utf8(struct archive_entry *entry, const char *linkname)
 
1130
{
 
1131
        if (linkname != NULL)
 
1132
                entry->ae_set |= AE_SET_SYMLINK;
 
1133
        else
 
1134
                entry->ae_set &= ~AE_SET_SYMLINK;
 
1135
        return (aes_update_utf8(&entry->ae_symlink, linkname));
 
1136
}
 
1137
 
 
1138
void
 
1139
archive_entry_set_uid(struct archive_entry *entry, uid_t u)
 
1140
{
 
1141
        entry->stat_valid = 0;
 
1142
        entry->ae_stat.aest_uid = u;
 
1143
}
 
1144
 
 
1145
void
 
1146
archive_entry_set_uname(struct archive_entry *entry, const char *name)
 
1147
{
 
1148
        aes_set_mbs(&entry->ae_uname, name);
 
1149
}
 
1150
 
 
1151
void
 
1152
archive_entry_copy_uname(struct archive_entry *entry, const char *name)
 
1153
{
 
1154
        aes_copy_mbs(&entry->ae_uname, name);
 
1155
}
 
1156
 
 
1157
void
 
1158
archive_entry_copy_uname_w(struct archive_entry *entry, const wchar_t *name)
 
1159
{
 
1160
        aes_copy_wcs(&entry->ae_uname, name);
 
1161
}
 
1162
 
 
1163
int
 
1164
archive_entry_update_uname_utf8(struct archive_entry *entry, const char *name)
 
1165
{
 
1166
        return (aes_update_utf8(&entry->ae_uname, name));
 
1167
}
 
1168
 
 
1169
/*
 
1170
 * ACL management.  The following would, of course, be a lot simpler
 
1171
 * if: 1) the last draft of POSIX.1e were a really thorough and
 
1172
 * complete standard that addressed the needs of ACL archiving and 2)
 
1173
 * everyone followed it faithfully.  Alas, neither is true, so the
 
1174
 * following is a lot more complex than might seem necessary to the
 
1175
 * uninitiated.
 
1176
 */
 
1177
 
 
1178
void
 
1179
archive_entry_acl_clear(struct archive_entry *entry)
 
1180
{
 
1181
        struct ae_acl   *ap;
 
1182
 
 
1183
        while (entry->acl_head != NULL) {
 
1184
                ap = entry->acl_head->next;
 
1185
                aes_clean(&entry->acl_head->name);
 
1186
                free(entry->acl_head);
 
1187
                entry->acl_head = ap;
 
1188
        }
 
1189
        if (entry->acl_text_w != NULL) {
 
1190
                free(entry->acl_text_w);
 
1191
                entry->acl_text_w = NULL;
 
1192
        }
 
1193
        entry->acl_p = NULL;
 
1194
        entry->acl_state = 0; /* Not counting. */
 
1195
}
 
1196
 
 
1197
/*
 
1198
 * Add a single ACL entry to the internal list of ACL data.
 
1199
 */
 
1200
void
 
1201
archive_entry_acl_add_entry(struct archive_entry *entry,
 
1202
    int type, int permset, int tag, int id, const char *name)
 
1203
{
 
1204
        struct ae_acl *ap;
 
1205
 
 
1206
        if (acl_special(entry, type, permset, tag) == 0)
 
1207
                return;
 
1208
        ap = acl_new_entry(entry, type, permset, tag, id);
 
1209
        if (ap == NULL) {
 
1210
                /* XXX Error XXX */
 
1211
                return;
 
1212
        }
 
1213
        if (name != NULL  &&  *name != '\0')
 
1214
                aes_copy_mbs(&ap->name, name);
 
1215
        else
 
1216
                aes_clean(&ap->name);
 
1217
}
 
1218
 
 
1219
/*
 
1220
 * As above, but with a wide-character name.
 
1221
 */
 
1222
void
 
1223
archive_entry_acl_add_entry_w(struct archive_entry *entry,
 
1224
    int type, int permset, int tag, int id, const wchar_t *name)
 
1225
{
 
1226
        archive_entry_acl_add_entry_w_len(entry, type, permset, tag, id, name, wcslen(name));
 
1227
}
 
1228
 
 
1229
static void
 
1230
archive_entry_acl_add_entry_w_len(struct archive_entry *entry,
 
1231
    int type, int permset, int tag, int id, const wchar_t *name, size_t len)
 
1232
{
 
1233
        struct ae_acl *ap;
 
1234
 
 
1235
        if (acl_special(entry, type, permset, tag) == 0)
 
1236
                return;
 
1237
        ap = acl_new_entry(entry, type, permset, tag, id);
 
1238
        if (ap == NULL) {
 
1239
                /* XXX Error XXX */
 
1240
                return;
 
1241
        }
 
1242
        if (name != NULL  &&  *name != L'\0' && len > 0)
 
1243
                aes_copy_wcs_len(&ap->name, name, len);
 
1244
        else
 
1245
                aes_clean(&ap->name);
 
1246
}
 
1247
 
 
1248
/*
 
1249
 * If this ACL entry is part of the standard POSIX permissions set,
 
1250
 * store the permissions in the stat structure and return zero.
 
1251
 */
 
1252
static int
 
1253
acl_special(struct archive_entry *entry, int type, int permset, int tag)
 
1254
{
 
1255
        if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) {
 
1256
                switch (tag) {
 
1257
                case ARCHIVE_ENTRY_ACL_USER_OBJ:
 
1258
                        entry->ae_stat.aest_mode &= ~0700;
 
1259
                        entry->ae_stat.aest_mode |= (permset & 7) << 6;
 
1260
                        return (0);
 
1261
                case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
 
1262
                        entry->ae_stat.aest_mode &= ~0070;
 
1263
                        entry->ae_stat.aest_mode |= (permset & 7) << 3;
 
1264
                        return (0);
 
1265
                case ARCHIVE_ENTRY_ACL_OTHER:
 
1266
                        entry->ae_stat.aest_mode &= ~0007;
 
1267
                        entry->ae_stat.aest_mode |= permset & 7;
 
1268
                        return (0);
 
1269
                }
 
1270
        }
 
1271
        return (1);
 
1272
}
 
1273
 
 
1274
/*
 
1275
 * Allocate and populate a new ACL entry with everything but the
 
1276
 * name.
 
1277
 */
 
1278
static struct ae_acl *
 
1279
acl_new_entry(struct archive_entry *entry,
 
1280
    int type, int permset, int tag, int id)
 
1281
{
 
1282
        struct ae_acl *ap, *aq;
 
1283
 
 
1284
        if (type != ARCHIVE_ENTRY_ACL_TYPE_ACCESS &&
 
1285
            type != ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)
 
1286
                return (NULL);
 
1287
        if (entry->acl_text_w != NULL) {
 
1288
                free(entry->acl_text_w);
 
1289
                entry->acl_text_w = NULL;
 
1290
        }
 
1291
 
 
1292
        /* XXX TODO: More sanity-checks on the arguments XXX */
 
1293
 
 
1294
        /* If there's a matching entry already in the list, overwrite it. */
 
1295
        ap = entry->acl_head;
 
1296
        aq = NULL;
 
1297
        while (ap != NULL) {
 
1298
                if (ap->type == type && ap->tag == tag && ap->id == id) {
 
1299
                        ap->permset = permset;
 
1300
                        return (ap);
 
1301
                }
 
1302
                aq = ap;
 
1303
                ap = ap->next;
 
1304
        }
 
1305
 
 
1306
        /* Add a new entry to the end of the list. */
 
1307
        ap = (struct ae_acl *)malloc(sizeof(*ap));
 
1308
        if (ap == NULL)
 
1309
                return (NULL);
 
1310
        memset(ap, 0, sizeof(*ap));
 
1311
        if (aq == NULL)
 
1312
                entry->acl_head = ap;
 
1313
        else
 
1314
                aq->next = ap;
 
1315
        ap->type = type;
 
1316
        ap->tag = tag;
 
1317
        ap->id = id;
 
1318
        ap->permset = permset;
 
1319
        return (ap);
 
1320
}
 
1321
 
 
1322
/*
 
1323
 * Return a count of entries matching "want_type".
 
1324
 */
 
1325
int
 
1326
archive_entry_acl_count(struct archive_entry *entry, int want_type)
 
1327
{
 
1328
        int count;
 
1329
        struct ae_acl *ap;
 
1330
 
 
1331
        count = 0;
 
1332
        ap = entry->acl_head;
 
1333
        while (ap != NULL) {
 
1334
                if ((ap->type & want_type) != 0)
 
1335
                        count++;
 
1336
                ap = ap->next;
 
1337
        }
 
1338
 
 
1339
        if (count > 0 && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0))
 
1340
                count += 3;
 
1341
        return (count);
 
1342
}
 
1343
 
 
1344
/*
 
1345
 * Prepare for reading entries from the ACL data.  Returns a count
 
1346
 * of entries matching "want_type", or zero if there are no
 
1347
 * non-extended ACL entries of that type.
 
1348
 */
 
1349
int
 
1350
archive_entry_acl_reset(struct archive_entry *entry, int want_type)
 
1351
{
 
1352
        int count, cutoff;
 
1353
 
 
1354
        count = archive_entry_acl_count(entry, want_type);
 
1355
 
 
1356
        /*
 
1357
         * If the only entries are the three standard ones,
 
1358
         * then don't return any ACL data.  (In this case,
 
1359
         * client can just use chmod(2) to set permissions.)
 
1360
         */
 
1361
        if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)
 
1362
                cutoff = 3;
 
1363
        else
 
1364
                cutoff = 0;
 
1365
 
 
1366
        if (count > cutoff)
 
1367
                entry->acl_state = ARCHIVE_ENTRY_ACL_USER_OBJ;
 
1368
        else
 
1369
                entry->acl_state = 0;
 
1370
        entry->acl_p = entry->acl_head;
 
1371
        return (count);
 
1372
}
 
1373
 
 
1374
/*
 
1375
 * Return the next ACL entry in the list.  Fake entries for the
 
1376
 * standard permissions and include them in the returned list.
 
1377
 */
 
1378
 
 
1379
int
 
1380
archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
 
1381
    int *permset, int *tag, int *id, const char **name)
 
1382
{
 
1383
        *name = NULL;
 
1384
        *id = -1;
 
1385
 
 
1386
        /*
 
1387
         * The acl_state is either zero (no entries available), -1
 
1388
         * (reading from list), or an entry type (retrieve that type
 
1389
         * from ae_stat.aest_mode).
 
1390
         */
 
1391
        if (entry->acl_state == 0)
 
1392
                return (ARCHIVE_WARN);
 
1393
 
 
1394
        /* The first three access entries are special. */
 
1395
        if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
 
1396
                switch (entry->acl_state) {
 
1397
                case ARCHIVE_ENTRY_ACL_USER_OBJ:
 
1398
                        *permset = (entry->ae_stat.aest_mode >> 6) & 7;
 
1399
                        *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
 
1400
                        *tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
 
1401
                        entry->acl_state = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
 
1402
                        return (ARCHIVE_OK);
 
1403
                case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
 
1404
                        *permset = (entry->ae_stat.aest_mode >> 3) & 7;
 
1405
                        *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
 
1406
                        *tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
 
1407
                        entry->acl_state = ARCHIVE_ENTRY_ACL_OTHER;
 
1408
                        return (ARCHIVE_OK);
 
1409
                case ARCHIVE_ENTRY_ACL_OTHER:
 
1410
                        *permset = entry->ae_stat.aest_mode & 7;
 
1411
                        *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
 
1412
                        *tag = ARCHIVE_ENTRY_ACL_OTHER;
 
1413
                        entry->acl_state = -1;
 
1414
                        entry->acl_p = entry->acl_head;
 
1415
                        return (ARCHIVE_OK);
 
1416
                default:
 
1417
                        break;
 
1418
                }
 
1419
        }
 
1420
 
 
1421
        while (entry->acl_p != NULL && (entry->acl_p->type & want_type) == 0)
 
1422
                entry->acl_p = entry->acl_p->next;
 
1423
        if (entry->acl_p == NULL) {
 
1424
                entry->acl_state = 0;
 
1425
                *type = 0;
 
1426
                *permset = 0;
 
1427
                *tag = 0;
 
1428
                *id = -1;
 
1429
                *name = NULL;
 
1430
                return (ARCHIVE_EOF); /* End of ACL entries. */
 
1431
        }
 
1432
        *type = entry->acl_p->type;
 
1433
        *permset = entry->acl_p->permset;
 
1434
        *tag = entry->acl_p->tag;
 
1435
        *id = entry->acl_p->id;
 
1436
        *name = aes_get_mbs(&entry->acl_p->name);
 
1437
        entry->acl_p = entry->acl_p->next;
 
1438
        return (ARCHIVE_OK);
 
1439
}
 
1440
 
 
1441
/*
 
1442
 * Generate a text version of the ACL.  The flags parameter controls
 
1443
 * the style of the generated ACL.
 
1444
 */
 
1445
const wchar_t *
 
1446
archive_entry_acl_text_w(struct archive_entry *entry, int flags)
 
1447
{
 
1448
        int count;
 
1449
        size_t length;
 
1450
        const wchar_t *wname;
 
1451
        const wchar_t *prefix;
 
1452
        wchar_t separator;
 
1453
        struct ae_acl *ap;
 
1454
        int id;
 
1455
        wchar_t *wp;
 
1456
 
 
1457
        if (entry->acl_text_w != NULL) {
 
1458
                free (entry->acl_text_w);
 
1459
                entry->acl_text_w = NULL;
 
1460
        }
 
1461
 
 
1462
        separator = L',';
 
1463
        count = 0;
 
1464
        length = 0;
 
1465
        ap = entry->acl_head;
 
1466
        while (ap != NULL) {
 
1467
                if ((ap->type & flags) != 0) {
 
1468
                        count++;
 
1469
                        if ((flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) &&
 
1470
                            (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT))
 
1471
                                length += 8; /* "default:" */
 
1472
                        length += 5; /* tag name */
 
1473
                        length += 1; /* colon */
 
1474
                        wname = aes_get_wcs(&ap->name);
 
1475
                        if (wname != NULL)
 
1476
                                length += wcslen(wname);
 
1477
                        else
 
1478
                                length += sizeof(uid_t) * 3 + 1;
 
1479
                        length ++; /* colon */
 
1480
                        length += 3; /* rwx */
 
1481
                        length += 1; /* colon */
 
1482
                        length += max(sizeof(uid_t), sizeof(gid_t)) * 3 + 1;
 
1483
                        length ++; /* newline */
 
1484
                }
 
1485
                ap = ap->next;
 
1486
        }
 
1487
 
 
1488
        if (count > 0 && ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) {
 
1489
                length += 10; /* "user::rwx\n" */
 
1490
                length += 11; /* "group::rwx\n" */
 
1491
                length += 11; /* "other::rwx\n" */
 
1492
        }
 
1493
 
 
1494
        if (count == 0)
 
1495
                return (NULL);
 
1496
 
 
1497
        /* Now, allocate the string and actually populate it. */
 
1498
        wp = entry->acl_text_w = (wchar_t *)malloc(length * sizeof(wchar_t));
 
1499
        if (wp == NULL)
 
1500
                __archive_errx(1, "No memory to generate the text version of the ACL");
 
1501
        count = 0;
 
1502
        if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
 
1503
                append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
 
1504
                    entry->ae_stat.aest_mode & 0700, -1);
 
1505
                *wp++ = ',';
 
1506
                append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_GROUP_OBJ, NULL,
 
1507
                    entry->ae_stat.aest_mode & 0070, -1);
 
1508
                *wp++ = ',';
 
1509
                append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_OTHER, NULL,
 
1510
                    entry->ae_stat.aest_mode & 0007, -1);
 
1511
                count += 3;
 
1512
 
 
1513
                ap = entry->acl_head;
 
1514
                while (ap != NULL) {
 
1515
                        if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
 
1516
                                wname = aes_get_wcs(&ap->name);
 
1517
                                *wp++ = separator;
 
1518
                                if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
 
1519
                                        id = ap->id;
 
1520
                                else
 
1521
                                        id = -1;
 
1522
                                append_entry_w(&wp, NULL, ap->tag, wname,
 
1523
                                    ap->permset, id);
 
1524
                                count++;
 
1525
                        }
 
1526
                        ap = ap->next;
 
1527
                }
 
1528
        }
 
1529
 
 
1530
 
 
1531
        if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
 
1532
                if (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT)
 
1533
                        prefix = L"default:";
 
1534
                else
 
1535
                        prefix = NULL;
 
1536
                ap = entry->acl_head;
 
1537
                count = 0;
 
1538
                while (ap != NULL) {
 
1539
                        if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
 
1540
                                wname = aes_get_wcs(&ap->name);
 
1541
                                if (count > 0)
 
1542
                                        *wp++ = separator;
 
1543
                                if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
 
1544
                                        id = ap->id;
 
1545
                                else
 
1546
                                        id = -1;
 
1547
                                append_entry_w(&wp, prefix, ap->tag,
 
1548
                                    wname, ap->permset, id);
 
1549
                                count ++;
 
1550
                        }
 
1551
                        ap = ap->next;
 
1552
                }
 
1553
        }
 
1554
 
 
1555
        return (entry->acl_text_w);
 
1556
}
 
1557
 
 
1558
static void
 
1559
append_id_w(wchar_t **wp, int id)
 
1560
{
 
1561
        if (id < 0)
 
1562
                id = 0;
 
1563
        if (id > 9)
 
1564
                append_id_w(wp, id / 10);
 
1565
        *(*wp)++ = L"0123456789"[id % 10];
 
1566
}
 
1567
 
 
1568
static void
 
1569
append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
 
1570
    const wchar_t *wname, int perm, int id)
 
1571
{
 
1572
        if (prefix != NULL) {
 
1573
                wcscpy(*wp, prefix);
 
1574
                *wp += wcslen(*wp);
 
1575
        }
 
1576
        switch (tag) {
 
1577
        case ARCHIVE_ENTRY_ACL_USER_OBJ:
 
1578
                wname = NULL;
 
1579
                id = -1;
 
1580
                /* FALLTHROUGH */
 
1581
        case ARCHIVE_ENTRY_ACL_USER:
 
1582
                wcscpy(*wp, L"user");
 
1583
                break;
 
1584
        case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
 
1585
                wname = NULL;
 
1586
                id = -1;
 
1587
                /* FALLTHROUGH */
 
1588
        case ARCHIVE_ENTRY_ACL_GROUP:
 
1589
                wcscpy(*wp, L"group");
 
1590
                break;
 
1591
        case ARCHIVE_ENTRY_ACL_MASK:
 
1592
                wcscpy(*wp, L"mask");
 
1593
                wname = NULL;
 
1594
                id = -1;
 
1595
                break;
 
1596
        case ARCHIVE_ENTRY_ACL_OTHER:
 
1597
                wcscpy(*wp, L"other");
 
1598
                wname = NULL;
 
1599
                id = -1;
 
1600
                break;
 
1601
        }
 
1602
        *wp += wcslen(*wp);
 
1603
        *(*wp)++ = L':';
 
1604
        if (wname != NULL) {
 
1605
                wcscpy(*wp, wname);
 
1606
                *wp += wcslen(*wp);
 
1607
        } else if (tag == ARCHIVE_ENTRY_ACL_USER
 
1608
            || tag == ARCHIVE_ENTRY_ACL_GROUP) {
 
1609
                append_id_w(wp, id);
 
1610
                id = -1;
 
1611
        }
 
1612
        *(*wp)++ = L':';
 
1613
        *(*wp)++ = (perm & 0444) ? L'r' : L'-';
 
1614
        *(*wp)++ = (perm & 0222) ? L'w' : L'-';
 
1615
        *(*wp)++ = (perm & 0111) ? L'x' : L'-';
 
1616
        if (id != -1) {
 
1617
                *(*wp)++ = L':';
 
1618
                append_id_w(wp, id);
 
1619
        }
 
1620
        **wp = L'\0';
 
1621
}
 
1622
 
 
1623
/*
 
1624
 * Parse a textual ACL.  This automatically recognizes and supports
 
1625
 * extensions described above.  The 'type' argument is used to
 
1626
 * indicate the type that should be used for any entries not
 
1627
 * explicitly marked as "default:".
 
1628
 */
 
1629
int
 
1630
__archive_entry_acl_parse_w(struct archive_entry *entry,
 
1631
    const wchar_t *text, int default_type)
 
1632
{
 
1633
        struct {
 
1634
                const wchar_t *start;
 
1635
                const wchar_t *end;
 
1636
        } field[4], name;
 
1637
 
 
1638
        int fields, n;
 
1639
        int type, tag, permset, id;
 
1640
        wchar_t sep;
 
1641
 
 
1642
        while (text != NULL  &&  *text != L'\0') {
 
1643
                /*
 
1644
                 * Parse the fields out of the next entry,
 
1645
                 * advance 'text' to start of next entry.
 
1646
                 */
 
1647
                fields = 0;
 
1648
                do {
 
1649
                        const wchar_t *start, *end;
 
1650
                        next_field_w(&text, &start, &end, &sep);
 
1651
                        if (fields < 4) {
 
1652
                                field[fields].start = start;
 
1653
                                field[fields].end = end;
 
1654
                        }
 
1655
                        ++fields;
 
1656
                } while (sep == L':');
 
1657
 
 
1658
                /* Set remaining fields to blank. */
 
1659
                for (n = fields; n < 4; ++n)
 
1660
                        field[n].start = field[n].end = NULL;
 
1661
 
 
1662
                /* Check for a numeric ID in field 1 or 3. */
 
1663
                id = -1;
 
1664
                isint_w(field[1].start, field[1].end, &id);
 
1665
                /* Field 3 is optional. */
 
1666
                if (id == -1 && fields > 3)
 
1667
                        isint_w(field[3].start, field[3].end, &id);
 
1668
 
 
1669
                /*
 
1670
                 * Solaris extension:  "defaultuser::rwx" is the
 
1671
                 * default ACL corresponding to "user::rwx", etc.
 
1672
                 */
 
1673
                if (field[0].end - field[0].start > 7
 
1674
                    && wmemcmp(field[0].start, L"default", 7) == 0) {
 
1675
                        type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
 
1676
                        field[0].start += 7;
 
1677
                } else
 
1678
                        type = default_type;
 
1679
 
 
1680
                name.start = name.end = NULL;
 
1681
                if (prefix_w(field[0].start, field[0].end, L"user")) {
 
1682
                        if (!ismode_w(field[2].start, field[2].end, &permset))
 
1683
                                return (ARCHIVE_WARN);
 
1684
                        if (id != -1 || field[1].start < field[1].end) {
 
1685
                                tag = ARCHIVE_ENTRY_ACL_USER;
 
1686
                                name = field[1];
 
1687
                        } else
 
1688
                                tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
 
1689
                } else if (prefix_w(field[0].start, field[0].end, L"group")) {
 
1690
                        if (!ismode_w(field[2].start, field[2].end, &permset))
 
1691
                                return (ARCHIVE_WARN);
 
1692
                        if (id != -1 || field[1].start < field[1].end) {
 
1693
                                tag = ARCHIVE_ENTRY_ACL_GROUP;
 
1694
                                name = field[1];
 
1695
                        } else
 
1696
                                tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
 
1697
                } else if (prefix_w(field[0].start, field[0].end, L"other")) {
 
1698
                        if (fields == 2
 
1699
                            && field[1].start < field[1].end
 
1700
                            && ismode_w(field[1].start, field[1].end, &permset)) {
 
1701
                                /* This is Solaris-style "other:rwx" */
 
1702
                        } else if (fields == 3
 
1703
                            && field[1].start == field[1].end
 
1704
                            && field[2].start < field[2].end
 
1705
                            && ismode_w(field[2].start, field[2].end, &permset)) {
 
1706
                                /* This is FreeBSD-style "other::rwx" */
 
1707
                        } else
 
1708
                                return (ARCHIVE_WARN);
 
1709
                        tag = ARCHIVE_ENTRY_ACL_OTHER;
 
1710
                } else if (prefix_w(field[0].start, field[0].end, L"mask")) {
 
1711
                        if (fields == 2
 
1712
                            && field[1].start < field[1].end
 
1713
                            && ismode_w(field[1].start, field[1].end, &permset)) {
 
1714
                                /* This is Solaris-style "mask:rwx" */
 
1715
                        } else if (fields == 3
 
1716
                            && field[1].start == field[1].end
 
1717
                            && field[2].start < field[2].end
 
1718
                            && ismode_w(field[2].start, field[2].end, &permset)) {
 
1719
                                /* This is FreeBSD-style "mask::rwx" */
 
1720
                        } else
 
1721
                                return (ARCHIVE_WARN);
 
1722
                        tag = ARCHIVE_ENTRY_ACL_MASK;
 
1723
                } else
 
1724
                        return (ARCHIVE_WARN);
 
1725
 
 
1726
                /* Add entry to the internal list. */
 
1727
                archive_entry_acl_add_entry_w_len(entry, type, permset,
 
1728
                    tag, id, name.start, name.end - name.start);
 
1729
        }
 
1730
        return (ARCHIVE_OK);
 
1731
}
 
1732
 
 
1733
/*
 
1734
 * Parse a string to a positive decimal integer.  Returns true if
 
1735
 * the string is non-empty and consists only of decimal digits,
 
1736
 * false otherwise.
 
1737
 */
 
1738
static int
 
1739
isint_w(const wchar_t *start, const wchar_t *end, int *result)
 
1740
{
 
1741
        int n = 0;
 
1742
        if (start >= end)
 
1743
                return (0);
 
1744
        while (start < end) {
 
1745
                if (*start < '0' || *start > '9')
 
1746
                        return (0);
 
1747
                if (n > (INT_MAX / 10))
 
1748
                        n = INT_MAX;
 
1749
                else {
 
1750
                        n *= 10;
 
1751
                        n += *start - '0';
 
1752
                }
 
1753
                start++;
 
1754
        }
 
1755
        *result = n;
 
1756
        return (1);
 
1757
}
 
1758
 
 
1759
/*
 
1760
 * Parse a string as a mode field.  Returns true if
 
1761
 * the string is non-empty and consists only of mode characters,
 
1762
 * false otherwise.
 
1763
 */
 
1764
static int
 
1765
ismode_w(const wchar_t *start, const wchar_t *end, int *permset)
 
1766
{
 
1767
        const wchar_t *p;
 
1768
 
 
1769
        if (start >= end)
 
1770
                return (0);
 
1771
        p = start;
 
1772
        *permset = 0;
 
1773
        while (p < end) {
 
1774
                switch (*p++) {
 
1775
                case 'r': case 'R':
 
1776
                        *permset |= ARCHIVE_ENTRY_ACL_READ;
 
1777
                        break;
 
1778
                case 'w': case 'W':
 
1779
                        *permset |= ARCHIVE_ENTRY_ACL_WRITE;
 
1780
                        break;
 
1781
                case 'x': case 'X':
 
1782
                        *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
 
1783
                        break;
 
1784
                case '-':
 
1785
                        break;
 
1786
                default:
 
1787
                        return (0);
 
1788
                }
 
1789
        }
 
1790
        return (1);
 
1791
}
 
1792
 
 
1793
/*
 
1794
 * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]".  *wp is updated
 
1795
 * to point to just after the separator.  *start points to the first
 
1796
 * character of the matched text and *end just after the last
 
1797
 * character of the matched identifier.  In particular *end - *start
 
1798
 * is the length of the field body, not including leading or trailing
 
1799
 * whitespace.
 
1800
 */
 
1801
static void
 
1802
next_field_w(const wchar_t **wp, const wchar_t **start,
 
1803
    const wchar_t **end, wchar_t *sep)
 
1804
{
 
1805
        /* Skip leading whitespace to find start of field. */
 
1806
        while (**wp == L' ' || **wp == L'\t' || **wp == L'\n') {
 
1807
                (*wp)++;
 
1808
        }
 
1809
        *start = *wp;
 
1810
 
 
1811
        /* Scan for the separator. */
 
1812
        while (**wp != L'\0' && **wp != L',' && **wp != L':' &&
 
1813
            **wp != L'\n') {
 
1814
                (*wp)++;
 
1815
        }
 
1816
        *sep = **wp;
 
1817
 
 
1818
        /* Trim trailing whitespace to locate end of field. */
 
1819
        *end = *wp - 1;
 
1820
        while (**end == L' ' || **end == L'\t' || **end == L'\n') {
 
1821
                (*end)--;
 
1822
        }
 
1823
        (*end)++;
 
1824
 
 
1825
        /* Adjust scanner location. */
 
1826
        if (**wp != L'\0')
 
1827
                (*wp)++;
 
1828
}
 
1829
 
 
1830
/*
 
1831
 * Return true if the characters [start...end) are a prefix of 'test'.
 
1832
 * This makes it easy to handle the obvious abbreviations: 'u' for 'user', etc.
 
1833
 */
 
1834
static int
 
1835
prefix_w(const wchar_t *start, const wchar_t *end, const wchar_t *test)
 
1836
{
 
1837
        if (start == end)
 
1838
                return (0);
 
1839
 
 
1840
        if (*start++ != *test++)
 
1841
                return (0);
 
1842
 
 
1843
        while (start < end  &&  *start++ == *test++)
 
1844
                ;
 
1845
 
 
1846
        if (start < end)
 
1847
                return (0);
 
1848
 
 
1849
        return (1);
 
1850
}
 
1851
 
 
1852
 
 
1853
/*
 
1854
 * Following code is modified from UC Berkeley sources, and
 
1855
 * is subject to the following copyright notice.
 
1856
 */
 
1857
 
 
1858
/*-
 
1859
 * Copyright (c) 1993
 
1860
 *      The Regents of the University of California.  All rights reserved.
 
1861
 *
 
1862
 * Redistribution and use in source and binary forms, with or without
 
1863
 * modification, are permitted provided that the following conditions
 
1864
 * are met:
 
1865
 * 1. Redistributions of source code must retain the above copyright
 
1866
 *    notice, this list of conditions and the following disclaimer.
 
1867
 * 2. Redistributions in binary form must reproduce the above copyright
 
1868
 *    notice, this list of conditions and the following disclaimer in the
 
1869
 *    documentation and/or other materials provided with the distribution.
 
1870
 * 4. Neither the name of the University nor the names of its contributors
 
1871
 *    may be used to endorse or promote products derived from this software
 
1872
 *    without specific prior written permission.
 
1873
 *
 
1874
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 
1875
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
1876
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
1877
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 
1878
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
1879
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
1880
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
1881
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
1882
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
1883
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
1884
 * SUCH DAMAGE.
 
1885
 */
 
1886
 
 
1887
static struct flag {
 
1888
        const char      *name;
 
1889
        const wchar_t   *wname;
 
1890
        unsigned long    set;
 
1891
        unsigned long    clear;
 
1892
} flags[] = {
 
1893
        /* Preferred (shorter) names per flag first, all prefixed by "no" */
 
1894
#ifdef SF_APPEND
 
1895
        { "nosappnd",   L"nosappnd",            SF_APPEND,      0 },
 
1896
        { "nosappend",  L"nosappend",           SF_APPEND,      0 },
 
1897
#endif
 
1898
#ifdef  EXT2_APPEND_FL                          /* 'a' */
 
1899
        { "nosappnd",   L"nosappnd",            EXT2_APPEND_FL, 0 },
 
1900
        { "nosappend",  L"nosappend",           EXT2_APPEND_FL, 0 },
 
1901
#endif
 
1902
#ifdef SF_ARCHIVED
 
1903
        { "noarch",     L"noarch",              SF_ARCHIVED,    0 },
 
1904
        { "noarchived", L"noarchived",          SF_ARCHIVED,    0 },
 
1905
#endif
 
1906
#ifdef SF_IMMUTABLE
 
1907
        { "noschg",     L"noschg",              SF_IMMUTABLE,   0 },
 
1908
        { "noschange",  L"noschange",           SF_IMMUTABLE,   0 },
 
1909
        { "nosimmutable",       L"nosimmutable",        SF_IMMUTABLE,   0 },
 
1910
#endif
 
1911
#ifdef EXT2_IMMUTABLE_FL                        /* 'i' */
 
1912
        { "noschg",     L"noschg",              EXT2_IMMUTABLE_FL,      0 },
 
1913
        { "noschange",  L"noschange",           EXT2_IMMUTABLE_FL,      0 },
 
1914
        { "nosimmutable",       L"nosimmutable",        EXT2_IMMUTABLE_FL,      0 },
 
1915
#endif
 
1916
#ifdef SF_NOUNLINK
 
1917
        { "nosunlnk",   L"nosunlnk",            SF_NOUNLINK,    0 },
 
1918
        { "nosunlink",  L"nosunlink",           SF_NOUNLINK,    0 },
 
1919
#endif
 
1920
#ifdef SF_SNAPSHOT
 
1921
        { "nosnapshot", L"nosnapshot",  SF_SNAPSHOT,    0 },
 
1922
#endif
 
1923
#ifdef UF_APPEND
 
1924
        { "nouappnd",   L"nouappnd",            UF_APPEND,      0 },
 
1925
        { "nouappend",  L"nouappend",           UF_APPEND,      0 },
 
1926
#endif
 
1927
#ifdef UF_IMMUTABLE
 
1928
        { "nouchg",     L"nouchg",              UF_IMMUTABLE,   0 },
 
1929
        { "nouchange",  L"nouchange",           UF_IMMUTABLE,   0 },
 
1930
        { "nouimmutable",       L"nouimmutable",        UF_IMMUTABLE,   0 },
 
1931
#endif
 
1932
#ifdef UF_NODUMP
 
1933
        { "nodump",     L"nodump",              0,              UF_NODUMP},
 
1934
#endif
 
1935
#ifdef EXT2_NODUMP_FL                           /* 'd' */
 
1936
        { "nodump",     L"nodump",              0,              EXT2_NODUMP_FL},
 
1937
#endif
 
1938
#ifdef UF_OPAQUE
 
1939
        { "noopaque",   L"noopaque",            UF_OPAQUE,      0 },
 
1940
#endif
 
1941
#ifdef UF_NOUNLINK
 
1942
        { "nouunlnk",   L"nouunlnk",            UF_NOUNLINK,    0 },
 
1943
        { "nouunlink",  L"nouunlink",           UF_NOUNLINK,    0 },
 
1944
#endif
 
1945
#ifdef EXT2_UNRM_FL
 
1946
        { "nouunlink",  L"nouunlink",           EXT2_UNRM_FL,   0},
 
1947
#endif
 
1948
 
 
1949
#ifdef EXT2_BTREE_FL
 
1950
        { "nobtree",    L"nobtree",             EXT2_BTREE_FL,  0 },
 
1951
#endif
 
1952
 
 
1953
#ifdef EXT2_ECOMPR_FL
 
1954
        { "nocomperr",  L"nocomperr",           EXT2_ECOMPR_FL, 0 },
 
1955
#endif
 
1956
 
 
1957
#ifdef EXT2_COMPR_FL                            /* 'c' */
 
1958
        { "nocompress", L"nocompress",          EXT2_COMPR_FL,  0 },
 
1959
#endif
 
1960
 
 
1961
#ifdef EXT2_NOATIME_FL                          /* 'A' */
 
1962
        { "noatime",    L"noatime",             0,              EXT2_NOATIME_FL},
 
1963
#endif
 
1964
 
 
1965
#ifdef EXT2_DIRTY_FL
 
1966
        { "nocompdirty",L"nocompdirty",         EXT2_DIRTY_FL,          0},
 
1967
#endif
 
1968
 
 
1969
#ifdef EXT2_COMPRBLK_FL
 
1970
#ifdef EXT2_NOCOMPR_FL
 
1971
        { "nocomprblk", L"nocomprblk",          EXT2_COMPRBLK_FL, EXT2_NOCOMPR_FL},
 
1972
#else
 
1973
        { "nocomprblk", L"nocomprblk",          EXT2_COMPRBLK_FL,       0},
 
1974
#endif
 
1975
#endif
 
1976
#ifdef EXT2_DIRSYNC_FL
 
1977
        { "nodirsync",  L"nodirsync",           EXT2_DIRSYNC_FL,        0},
 
1978
#endif
 
1979
#ifdef EXT2_INDEX_FL
 
1980
        { "nohashidx",  L"nohashidx",           EXT2_INDEX_FL,          0},
 
1981
#endif
 
1982
#ifdef EXT2_IMAGIC_FL
 
1983
        { "noimagic",   L"noimagic",            EXT2_IMAGIC_FL,         0},
 
1984
#endif
 
1985
#ifdef EXT3_JOURNAL_DATA_FL
 
1986
        { "nojournal",  L"nojournal",           EXT3_JOURNAL_DATA_FL,   0},
 
1987
#endif
 
1988
#ifdef EXT2_SECRM_FL
 
1989
        { "nosecuredeletion",L"nosecuredeletion",EXT2_SECRM_FL,         0},
 
1990
#endif
 
1991
#ifdef EXT2_SYNC_FL
 
1992
        { "nosync",     L"nosync",              EXT2_SYNC_FL,           0},
 
1993
#endif
 
1994
#ifdef EXT2_NOTAIL_FL
 
1995
        { "notail",     L"notail",              0,              EXT2_NOTAIL_FL},
 
1996
#endif
 
1997
#ifdef EXT2_TOPDIR_FL
 
1998
        { "notopdir",   L"notopdir",            EXT2_TOPDIR_FL,         0},
 
1999
#endif
 
2000
#ifdef EXT2_RESERVED_FL
 
2001
        { "noreserved", L"noreserved",          EXT2_RESERVED_FL,       0},
 
2002
#endif
 
2003
 
 
2004
        { NULL,         NULL,                   0,              0 }
 
2005
};
 
2006
 
 
2007
/*
 
2008
 * fflagstostr --
 
2009
 *      Convert file flags to a comma-separated string.  If no flags
 
2010
 *      are set, return the empty string.
 
2011
 */
 
2012
static char *
 
2013
ae_fflagstostr(unsigned long bitset, unsigned long bitclear)
 
2014
{
 
2015
        char *string, *dp;
 
2016
        const char *sp;
 
2017
        unsigned long bits;
 
2018
        struct flag *flag;
 
2019
        size_t  length;
 
2020
 
 
2021
        bits = bitset | bitclear;
 
2022
        length = 0;
 
2023
        for (flag = flags; flag->name != NULL; flag++)
 
2024
                if (bits & (flag->set | flag->clear)) {
 
2025
                        length += strlen(flag->name) + 1;
 
2026
                        bits &= ~(flag->set | flag->clear);
 
2027
                }
 
2028
 
 
2029
        if (length == 0)
 
2030
                return (NULL);
 
2031
        string = (char *)malloc(length);
 
2032
        if (string == NULL)
 
2033
                return (NULL);
 
2034
 
 
2035
        dp = string;
 
2036
        for (flag = flags; flag->name != NULL; flag++) {
 
2037
                if (bitset & flag->set || bitclear & flag->clear) {
 
2038
                        sp = flag->name + 2;
 
2039
                } else if (bitset & flag->clear  ||  bitclear & flag->set) {
 
2040
                        sp = flag->name;
 
2041
                } else
 
2042
                        continue;
 
2043
                bitset &= ~(flag->set | flag->clear);
 
2044
                bitclear &= ~(flag->set | flag->clear);
 
2045
                if (dp > string)
 
2046
                        *dp++ = ',';
 
2047
                while ((*dp++ = *sp++) != '\0')
 
2048
                        ;
 
2049
                dp--;
 
2050
        }
 
2051
 
 
2052
        *dp = '\0';
 
2053
        return (string);
 
2054
}
 
2055
 
 
2056
/*
 
2057
 * strtofflags --
 
2058
 *      Take string of arguments and return file flags.  This
 
2059
 *      version works a little differently than strtofflags(3).
 
2060
 *      In particular, it always tests every token, skipping any
 
2061
 *      unrecognized tokens.  It returns a pointer to the first
 
2062
 *      unrecognized token, or NULL if every token was recognized.
 
2063
 *      This version is also const-correct and does not modify the
 
2064
 *      provided string.
 
2065
 */
 
2066
static const char *
 
2067
ae_strtofflags(const char *s, unsigned long *setp, unsigned long *clrp)
 
2068
{
 
2069
        const char *start, *end;
 
2070
        struct flag *flag;
 
2071
        unsigned long set, clear;
 
2072
        const char *failed;
 
2073
 
 
2074
        set = clear = 0;
 
2075
        start = s;
 
2076
        failed = NULL;
 
2077
        /* Find start of first token. */
 
2078
        while (*start == '\t'  ||  *start == ' '  ||  *start == ',')
 
2079
                start++;
 
2080
        while (*start != '\0') {
 
2081
                /* Locate end of token. */
 
2082
                end = start;
 
2083
                while (*end != '\0'  &&  *end != '\t'  &&
 
2084
                    *end != ' '  &&  *end != ',')
 
2085
                        end++;
 
2086
                for (flag = flags; flag->name != NULL; flag++) {
 
2087
                        if (memcmp(start, flag->name, end - start) == 0) {
 
2088
                                /* Matched "noXXXX", so reverse the sense. */
 
2089
                                clear |= flag->set;
 
2090
                                set |= flag->clear;
 
2091
                                break;
 
2092
                        } else if (memcmp(start, flag->name + 2, end - start)
 
2093
                            == 0) {
 
2094
                                /* Matched "XXXX", so don't reverse. */
 
2095
                                set |= flag->set;
 
2096
                                clear |= flag->clear;
 
2097
                                break;
 
2098
                        }
 
2099
                }
 
2100
                /* Ignore unknown flag names. */
 
2101
                if (flag->name == NULL  &&  failed == NULL)
 
2102
                        failed = start;
 
2103
 
 
2104
                /* Find start of next token. */
 
2105
                start = end;
 
2106
                while (*start == '\t'  ||  *start == ' '  ||  *start == ',')
 
2107
                        start++;
 
2108
 
 
2109
        }
 
2110
 
 
2111
        if (setp)
 
2112
                *setp = set;
 
2113
        if (clrp)
 
2114
                *clrp = clear;
 
2115
 
 
2116
        /* Return location of first failure. */
 
2117
        return (failed);
 
2118
}
 
2119
 
 
2120
/*
 
2121
 * wcstofflags --
 
2122
 *      Take string of arguments and return file flags.  This
 
2123
 *      version works a little differently than strtofflags(3).
 
2124
 *      In particular, it always tests every token, skipping any
 
2125
 *      unrecognized tokens.  It returns a pointer to the first
 
2126
 *      unrecognized token, or NULL if every token was recognized.
 
2127
 *      This version is also const-correct and does not modify the
 
2128
 *      provided string.
 
2129
 */
 
2130
static const wchar_t *
 
2131
ae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp)
 
2132
{
 
2133
        const wchar_t *start, *end;
 
2134
        struct flag *flag;
 
2135
        unsigned long set, clear;
 
2136
        const wchar_t *failed;
 
2137
 
 
2138
        set = clear = 0;
 
2139
        start = s;
 
2140
        failed = NULL;
 
2141
        /* Find start of first token. */
 
2142
        while (*start == L'\t'  ||  *start == L' '  ||  *start == L',')
 
2143
                start++;
 
2144
        while (*start != L'\0') {
 
2145
                /* Locate end of token. */
 
2146
                end = start;
 
2147
                while (*end != L'\0'  &&  *end != L'\t'  &&
 
2148
                    *end != L' '  &&  *end != L',')
 
2149
                        end++;
 
2150
                for (flag = flags; flag->wname != NULL; flag++) {
 
2151
                        if (wmemcmp(start, flag->wname, end - start) == 0) {
 
2152
                                /* Matched "noXXXX", so reverse the sense. */
 
2153
                                clear |= flag->set;
 
2154
                                set |= flag->clear;
 
2155
                                break;
 
2156
                        } else if (wmemcmp(start, flag->wname + 2, end - start)
 
2157
                            == 0) {
 
2158
                                /* Matched "XXXX", so don't reverse. */
 
2159
                                set |= flag->set;
 
2160
                                clear |= flag->clear;
 
2161
                                break;
 
2162
                        }
 
2163
                }
 
2164
                /* Ignore unknown flag names. */
 
2165
                if (flag->wname == NULL  &&  failed == NULL)
 
2166
                        failed = start;
 
2167
 
 
2168
                /* Find start of next token. */
 
2169
                start = end;
 
2170
                while (*start == L'\t'  ||  *start == L' '  ||  *start == L',')
 
2171
                        start++;
 
2172
 
 
2173
        }
 
2174
 
 
2175
        if (setp)
 
2176
                *setp = set;
 
2177
        if (clrp)
 
2178
                *clrp = clear;
 
2179
 
 
2180
        /* Return location of first failure. */
 
2181
        return (failed);
 
2182
}
 
2183
 
 
2184
 
 
2185
#ifdef TEST
 
2186
#include <stdio.h>
 
2187
int
 
2188
main(int argc, char **argv)
 
2189
{
 
2190
        struct archive_entry *entry = archive_entry_new();
 
2191
        unsigned long set, clear;
 
2192
        const wchar_t *remainder;
 
2193
 
 
2194
        remainder = archive_entry_copy_fflags_text_w(entry, L"nosappnd dump archive,,,,,,,");
 
2195
        archive_entry_fflags(entry, &set, &clear);
 
2196
 
 
2197
        wprintf(L"set=0x%lX clear=0x%lX remainder='%ls'\n", set, clear, remainder);
 
2198
 
 
2199
        wprintf(L"new flags='%s'\n", archive_entry_fflags_text(entry));
 
2200
        return (0);
 
2201
}
 
2202
#endif