2
* Copyright (c) 2009 Michihiro NAKAJIMA
3
* Copyright (c) 2008 Joerg Sonnenberger
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
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.
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.
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 $");
30
#ifdef HAVE_SYS_TYPES_H
31
#include <sys/types.h>
38
#include "archive_entry.h"
39
#include "archive_private.h"
40
#include "archive_write_private.h"
42
#include "archive_hash.h"
44
#define INDENTNAMELEN 15
48
struct archive_entry *entry;
49
struct archive_string ebuf;
50
struct archive_string buf;
52
uint64_t entry_bytes_remaining;
56
struct archive_string parent;
62
unsigned long fflags_set;
63
unsigned long fflags_clear;
69
#ifdef ARCHIVE_HAS_MD5
70
archive_md5_ctx md5ctx;
72
#ifdef ARCHIVE_HAS_RMD160
73
archive_rmd160_ctx rmd160ctx;
75
#ifdef ARCHIVE_HAS_SHA1
76
archive_sha1_ctx sha1ctx;
78
#ifdef ARCHIVE_HAS_SHA256
79
archive_sha256_ctx sha256ctx;
81
#ifdef ARCHIVE_HAS_SHA384
82
archive_sha384_ctx sha384ctx;
84
#ifdef ARCHIVE_HAS_SHA512
85
archive_sha512_ctx sha512ctx;
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
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 */
118
int dironly; /* if the dironly is 1, ignore everything except
119
* directory type files. like mtree(8) -d option.
121
int indent; /* if the indent is 1, indent writing data. */
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\
128
#define COMPUTE_CRC(var, ch) (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)]
129
static const uint32_t crctab[] = {
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
185
mtree_safe_char(char c)
187
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
189
if (c >= '0' && c <= '9')
191
if (c == 35 || c == 61 || c == 92)
192
return 0; /* #, = and \ are always quoted */
194
if (c >= 33 && c <= 47) /* !"$%&'()*+,-./ */
196
if (c >= 58 && c <= 64) /* :;<>?@ */
198
if (c >= 91 && c <= 96) /* []^_` */
200
if (c >= 123 && c <= 126) /* {|}~ */
206
mtree_quote(struct archive_string *s, const char *str)
212
for (start = str; *str != '\0'; ++str) {
213
if (mtree_safe_char(*str))
216
archive_strncat(s, start, str - start);
217
c = (unsigned char)*str;
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);
227
archive_strncat(s, start, str - start);
231
mtree_indent(struct mtree_writer *mtree)
234
const char *r, *s, *x;
237
s = r = mtree->ebuf.s;
241
while ((r = strchr(r, ' ')) != NULL) {
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, ' ');
250
for (i = r -s; i < (INDENTNAMELEN + 1); i++)
251
archive_strappend_char(&mtree->buf, ' ');
257
if (r - s <= MAXLINELEN - 3 - INDENTNAMELEN)
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, ' ');
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, ' ');
278
archive_strcat(&mtree->buf, s);
279
archive_string_empty(&mtree->ebuf);
282
#if !defined(_WIN32) || defined(__CYGWIN__)
284
dir_len(struct archive_entry *entry)
286
const char *path, *r;
288
path = archive_entry_pathname(entry);
289
r = strrchr(path, '/');
292
/* Include a separator size */
293
return (r - path + 1);
296
#else /* _WIN32 && !__CYGWIN__ */
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
304
dir_len(struct archive_entry *entry)
311
path = archive_entry_pathname(entry);
313
for (p = path; *p != '\0'; ++p) {
324
l = mbtowc(&wc, p, size);
327
if (l == 1 && (wc == L'/' || wc == L'\\'))
332
return (rp - path + 1);
338
#endif /* _WIN32 && !__CYGWIN__ */
341
parent_dir_changed(struct archive_string *dir, struct archive_entry *entry)
347
path = archive_entry_pathname(entry);
348
if (archive_strlen(dir) > 0) {
350
archive_string_empty(dir);
353
if (strncmp(dir->s, path, l) == 0)
354
return (0); /* The parent directory is the same. */
356
return (0); /* The parent directory is the same. */
357
archive_strncpy(dir, path, l);
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
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.
374
set_global(struct mtree_writer *mtree, struct archive_entry *entry)
376
struct archive_string setstr;
377
struct archive_string unsetstr;
379
int keys, oldkeys, effkeys;
382
switch (archive_entry_filetype(entry)) {
383
case AE_IFLNK: case AE_IFSOCK: case AE_IFCHR:
384
case AE_IFBLK: case AE_IFIFO:
391
default: /* Handle unknown file types as regular files. */
398
if (mtree->set.processed &&
399
!parent_dir_changed(&mtree->set.parent, entry))
401
/* At first, save a parent directory of the entry for following
403
if (!mtree->set.processed && set_type == AE_IFREG)
404
parent_dir_changed(&mtree->set.parent, entry);
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;
412
if (mtree->set.processed) {
414
* Check the global datas for whether it needs updating.
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))
426
if ((oldkeys & F_FLAGS) != 0) {
427
unsigned long fflags_set;
428
unsigned long fflags_clear;
430
archive_entry_fflags(entry, &fflags_set, &fflags_clear);
431
if (fflags_set == mtree->set.fflags_set &&
432
fflags_clear == mtree->set.fflags_clear)
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");
441
archive_strcat(&setstr, " type=file");
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");
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);
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");
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);
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);
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");
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. */
496
mtree->set.output = 0;
500
get_keys(struct mtree_writer *mtree, struct archive_entry *entry)
505
if (mtree->set.keys == 0)
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;
516
archive_entry_fflags(entry, &set, &clear);
517
if (mtree->set.fflags_set == set &&
518
mtree->set.fflags_clear == clear)
521
if ((mtree->set.keys & F_MODE) != 0 &&
522
mtree->set.mode == (archive_entry_mode(entry) & 07777))
525
switch (archive_entry_filetype(entry)) {
526
case AE_IFLNK: case AE_IFSOCK: case AE_IFCHR:
527
case AE_IFBLK: case AE_IFIFO:
530
if ((mtree->set.keys & F_TYPE) != 0 &&
531
mtree->set.type == AE_IFDIR)
535
default: /* Handle unknown file types as regular files. */
536
if ((mtree->set.keys & F_TYPE) != 0 &&
537
mtree->set.type == AE_IFREG)
546
archive_write_mtree_header(struct archive_write *a,
547
struct archive_entry *entry)
549
struct mtree_writer *mtree= a->format_data;
550
struct archive_string *str;
553
mtree->entry = archive_entry_clone(entry);
554
path = archive_entry_pathname(mtree->entry);
558
archive_strcat(&mtree->buf, "#mtree\n");
560
if (mtree->set.output)
561
set_global(mtree, entry);
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);
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;
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);
582
mtree->compute_sum &= ~F_MD5;
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);
590
mtree->compute_sum &= ~F_RMD160;
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);
598
mtree->compute_sum &= ~F_SHA1;
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);
606
mtree->compute_sum &= ~F_SHA256;
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);
614
mtree->compute_sum &= ~F_SHA384;
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);
622
mtree->compute_sum &= ~F_SHA512;
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)
632
strappend_bin(struct archive_string *s, const unsigned char *bin, int n)
634
static const char hex[] = "0123456789abcdef";
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]);
645
archive_write_mtree_finish_entry(struct archive_write *a)
647
struct mtree_writer *mtree = a->format_data;
648
struct archive_entry *entry;
649
struct archive_string *str;
653
entry = mtree->entry;
655
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
656
"Finished entry without being open first.");
657
return (ARCHIVE_FATAL);
661
if (mtree->dironly && archive_entry_filetype(entry) != AE_IFDIR) {
662
archive_entry_free(entry);
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));
674
if ((keys & F_GNAME) != 0 &&
675
(name = archive_entry_gname(entry)) != NULL) {
676
archive_strcat(str, " gname=");
677
mtree_quote(str, name);
679
if ((keys & F_UNAME) != 0 &&
680
(name = archive_entry_uname(entry)) != NULL) {
681
archive_strcat(str, " uname=");
682
mtree_quote(str, name);
684
if ((keys & F_FLAGS) != 0 &&
685
(name = archive_entry_fflags_text(entry)) != NULL) {
686
archive_strcat(str, " flags=");
687
mtree_quote(str, name);
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));
703
switch (archive_entry_filetype(entry)) {
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));
713
if ((keys & F_TYPE) != 0)
714
archive_strcat(str, " type=socket");
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));
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));
737
if ((keys & F_TYPE) != 0)
738
archive_strcat(str, " type=dir");
741
if ((keys & F_TYPE) != 0)
742
archive_strcat(str, " type=fifo");
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));
754
if (mtree->compute_sum & F_CKSUM) {
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);
763
#ifdef ARCHIVE_HAS_MD5
764
if (mtree->compute_sum & F_MD5) {
765
unsigned char buf[16];
767
archive_md5_final(&mtree->md5ctx, buf);
768
archive_strcat(str, " md5digest=");
769
strappend_bin(str, buf, sizeof(buf));
772
#ifdef ARCHIVE_HAS_RMD160
773
if (mtree->compute_sum & F_RMD160) {
774
unsigned char buf[20];
776
archive_rmd160_final(&mtree->rmd160ctx, buf);
777
archive_strcat(str, " rmd160digest=");
778
strappend_bin(str, buf, sizeof(buf));
781
#ifdef ARCHIVE_HAS_SHA1
782
if (mtree->compute_sum & F_SHA1) {
783
unsigned char buf[20];
785
archive_sha1_final(&mtree->sha1ctx, buf);
786
archive_strcat(str, " sha1digest=");
787
strappend_bin(str, buf, sizeof(buf));
790
#ifdef ARCHIVE_HAS_SHA256
791
if (mtree->compute_sum & F_SHA256) {
792
unsigned char buf[32];
794
archive_sha256_final(&mtree->sha256ctx, buf);
795
archive_strcat(str, " sha256digest=");
796
strappend_bin(str, buf, sizeof(buf));
799
#ifdef ARCHIVE_HAS_SHA384
800
if (mtree->compute_sum & F_SHA384) {
801
unsigned char buf[48];
803
archive_sha384_final(&mtree->sha384ctx, buf);
804
archive_strcat(str, " sha384digest=");
805
strappend_bin(str, buf, sizeof(buf));
808
#ifdef ARCHIVE_HAS_SHA512
809
if (mtree->compute_sum & F_SHA512) {
810
unsigned char buf[64];
812
archive_sha512_final(&mtree->sha512ctx, buf);
813
archive_strcat(str, " sha512digest=");
814
strappend_bin(str, buf, sizeof(buf));
817
archive_strcat(str, "\n");
821
archive_entry_free(entry);
823
if (mtree->buf.length > 32768) {
824
ret = (a->compressor.write)(a, mtree->buf.s, mtree->buf.length);
825
archive_string_empty(&mtree->buf);
829
return (ret == ARCHIVE_OK ? ret : ARCHIVE_FATAL);
833
archive_write_mtree_finish(struct archive_write *a)
835
struct mtree_writer *mtree= a->format_data;
837
archive_write_set_bytes_in_last_block(&a->archive, 1);
839
return (a->compressor.write)(a, mtree->buf.s, mtree->buf.length);
843
archive_write_mtree_data(struct archive_write *a, const void *buff, size_t n)
845
struct mtree_writer *mtree= a->format_data;
847
if (n > mtree->entry_bytes_remaining)
848
n = mtree->entry_bytes_remaining;
850
/* We don't need compute a regular file sum */
852
if (mtree->compute_sum & F_CKSUM) {
854
* Compute a POSIX 1003.2 checksum
856
const unsigned char *p;
859
for (nn = n, p = buff; nn--; ++p)
860
COMPUTE_CRC(mtree->crc, *p);
863
#ifdef ARCHIVE_HAS_MD5
864
if (mtree->compute_sum & F_MD5)
865
archive_md5_update(&mtree->md5ctx, buff, n);
867
#ifdef ARCHIVE_HAS_RMD160
868
if (mtree->compute_sum & F_RMD160)
869
archive_rmd160_update(&mtree->rmd160ctx, buff, n);
871
#ifdef ARCHIVE_HAS_SHA1
872
if (mtree->compute_sum & F_SHA1)
873
archive_sha1_update(&mtree->sha1ctx, buff, n);
875
#ifdef ARCHIVE_HAS_SHA256
876
if (mtree->compute_sum & F_SHA256)
877
archive_sha256_update(&mtree->sha256ctx, buff, n);
879
#ifdef ARCHIVE_HAS_SHA384
880
if (mtree->compute_sum & F_SHA384)
881
archive_sha384_update(&mtree->sha384ctx, buff, n);
883
#ifdef ARCHIVE_HAS_SHA512
884
if (mtree->compute_sum & F_SHA512)
885
archive_sha512_update(&mtree->sha512ctx, buff, n);
891
archive_write_mtree_destroy(struct archive_write *a)
893
struct mtree_writer *mtree= a->format_data;
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);
903
a->format_data = NULL;
908
archive_write_mtree_options(struct archive_write *a, const char *key,
911
struct mtree_writer *mtree= a->format_data;
916
if (strcmp(key, "all") == 0)
920
if (strcmp(key, "cksum") == 0)
924
if (strcmp(key, "device") == 0)
926
else if (strcmp(key, "dironly") == 0) {
927
mtree->dironly = (value != NULL)? 1: 0;
932
if (strcmp(key, "flags") == 0)
936
if (strcmp(key, "gid") == 0)
938
else if (strcmp(key, "gname") == 0)
942
if (strcmp(key, "indent") == 0) {
943
mtree->indent = (value != NULL)? 1: 0;
948
if (strcmp(key, "link") == 0)
952
if (strcmp(key, "md5") == 0 ||
953
strcmp(key, "md5digest") == 0)
955
if (strcmp(key, "mode") == 0)
959
if (strcmp(key, "nlink") == 0)
963
if (strcmp(key, "ripemd160digest") == 0 ||
964
strcmp(key, "rmd160") == 0 ||
965
strcmp(key, "rmd160digest") == 0)
969
if (strcmp(key, "sha1") == 0 ||
970
strcmp(key, "sha1digest") == 0)
972
if (strcmp(key, "sha256") == 0 ||
973
strcmp(key, "sha256digest") == 0)
975
if (strcmp(key, "sha384") == 0 ||
976
strcmp(key, "sha384digest") == 0)
978
if (strcmp(key, "sha512") == 0 ||
979
strcmp(key, "sha512digest") == 0)
981
if (strcmp(key, "size") == 0)
985
if (strcmp(key, "time") == 0)
987
else if (strcmp(key, "type") == 0)
991
if (strcmp(key, "uid") == 0)
993
else if (strcmp(key, "uname") == 0)
995
else if (strcmp(key, "use-set") == 0) {
996
mtree->set.output = (value != NULL)? 1: 0;
1003
mtree->keys |= keybit;
1005
mtree->keys &= ~keybit;
1006
return (ARCHIVE_OK);
1009
return (ARCHIVE_WARN);
1013
archive_write_set_format_mtree(struct archive *_a)
1015
struct archive_write *a = (struct archive_write *)_a;
1016
struct mtree_writer *mtree;
1018
if (a->format_destroy != NULL)
1019
(a->format_destroy)(a);
1021
if ((mtree = malloc(sizeof(*mtree))) == NULL) {
1022
archive_set_error(&a->archive, ENOMEM,
1023
"Can't allocate mtree data");
1024
return (ARCHIVE_FATAL);
1027
mtree->entry = NULL;
1029
memset(&(mtree->set), 0, sizeof(mtree->set));
1030
archive_string_init(&mtree->set.parent);
1031
mtree->keys = DEFAULT_KEYS;
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;
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";
1049
return (ARCHIVE_OK);