Merge branch 'vendor/LIBARCHIVE'
[dragonfly.git] / contrib / libarchive / libarchive / archive_write_set_format_mtree.c
1 /*-
2  * Copyright (c) 2008 Joerg Sonnenberger
3  * Copyright (c) 2009-2012 Michihiro NAKAJIMA
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "archive_platform.h"
28 __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_mtree.c 201171 2009-12-29 06:39:07Z kientzle $");
29
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
32 #endif
33 #include <errno.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "archive.h"
38 #include "archive_crypto_private.h"
39 #include "archive_entry.h"
40 #include "archive_private.h"
41 #include "archive_write_private.h"
42
43 #define INDENTNAMELEN   15
44 #define MAXLINELEN      80
45 #define SET_KEYS        \
46         (F_FLAGS | F_GID | F_GNAME | F_MODE | F_TYPE | F_UID | F_UNAME)
47
48 struct mtree_entry {
49         struct mtree_entry *next;
50
51         char *pathname;
52         char *symlink;
53         unsigned int nlink;
54         mode_t filetype;
55         mode_t mode;
56         int64_t uid;
57         int64_t gid;
58         char *uname;
59         char *gname;
60         char *fflags_text;
61         unsigned long fflags_set;
62         unsigned long fflags_clear;
63         time_t mtime;
64         long mtime_nsec;
65         dev_t rdevmajor;
66         dev_t rdevminor;
67         int64_t size;
68
69         int compute_sum;
70         uint32_t crc;
71 #ifdef ARCHIVE_HAS_MD5
72         unsigned char buf_md5[16];
73 #endif
74 #ifdef ARCHIVE_HAS_RMD160
75         unsigned char buf_rmd160[20];
76 #endif
77 #ifdef ARCHIVE_HAS_SHA1
78         unsigned char buf_sha1[20];
79 #endif
80 #ifdef ARCHIVE_HAS_SHA256
81         unsigned char buf_sha256[32];
82 #endif
83 #ifdef ARCHIVE_HAS_SHA384
84         unsigned char buf_sha384[48];
85 #endif
86 #ifdef ARCHIVE_HAS_SHA512
87         unsigned char buf_sha512[64];
88 #endif
89 };
90
91 struct attr_counter {
92         struct attr_counter *prev;
93         struct attr_counter *next;
94         int count;
95         struct mtree_entry *m_entry;
96 };
97
98 struct mtree_writer {
99         struct mtree_entry *mtree_entry;
100         struct archive_string ebuf;
101         struct archive_string buf;
102         int first;
103         uint64_t entry_bytes_remaining;
104         struct {
105                 int             output;
106                 int             processed;
107                 struct archive_string parent;
108                 mode_t          type;
109                 int             keys;
110                 int64_t         uid;
111                 int64_t         gid;
112                 mode_t          mode;
113                 unsigned long   fflags_set;
114                 unsigned long   fflags_clear;
115
116                 struct attr_counter *uid_list;
117                 struct attr_counter *gid_list;
118                 struct attr_counter *mode_list;
119                 struct attr_counter *flags_list;
120                 struct mtree_entry *me_first;
121                 struct mtree_entry **me_last;
122         } set;
123         /* check sum */
124         int compute_sum;
125         uint32_t crc;
126         uint64_t crc_len;
127 #ifdef ARCHIVE_HAS_MD5
128         archive_md5_ctx md5ctx;
129 #endif
130 #ifdef ARCHIVE_HAS_RMD160
131         archive_rmd160_ctx rmd160ctx;
132 #endif
133 #ifdef ARCHIVE_HAS_SHA1
134         archive_sha1_ctx sha1ctx;
135 #endif
136 #ifdef ARCHIVE_HAS_SHA256
137         archive_sha256_ctx sha256ctx;
138 #endif
139 #ifdef ARCHIVE_HAS_SHA384
140         archive_sha384_ctx sha384ctx;
141 #endif
142 #ifdef ARCHIVE_HAS_SHA512
143         archive_sha512_ctx sha512ctx;
144 #endif
145         /* Keyword options */
146         int keys;
147 #define F_CKSUM         0x00000001              /* check sum */
148 #define F_DEV           0x00000002              /* device type */
149 #define F_DONE          0x00000004              /* directory done */
150 #define F_FLAGS         0x00000008              /* file flags */
151 #define F_GID           0x00000010              /* gid */
152 #define F_GNAME         0x00000020              /* group name */
153 #define F_IGN           0x00000040              /* ignore */
154 #define F_MAGIC         0x00000080              /* name has magic chars */
155 #define F_MD5           0x00000100              /* MD5 digest */
156 #define F_MODE          0x00000200              /* mode */
157 #define F_NLINK         0x00000400              /* number of links */
158 #define F_NOCHANGE      0x00000800              /* If owner/mode "wrong", do
159                                                  * not change */
160 #define F_OPT           0x00001000              /* existence optional */
161 #define F_RMD160        0x00002000              /* RIPEMD160 digest */
162 #define F_SHA1          0x00004000              /* SHA-1 digest */
163 #define F_SIZE          0x00008000              /* size */
164 #define F_SLINK         0x00010000              /* symbolic link */
165 #define F_TAGS          0x00020000              /* tags */
166 #define F_TIME          0x00040000              /* modification time */
167 #define F_TYPE          0x00080000              /* file type */
168 #define F_UID           0x00100000              /* uid */
169 #define F_UNAME         0x00200000              /* user name */
170 #define F_VISIT         0x00400000              /* file visited */
171 #define F_SHA256        0x00800000              /* SHA-256 digest */
172 #define F_SHA384        0x01000000              /* SHA-384 digest */
173 #define F_SHA512        0x02000000              /* SHA-512 digest */
174
175         /* Options */
176         int dironly;            /* if the dironly is 1, ignore everything except
177                                  * directory type files. like mtree(8) -d option.
178                                  */
179         int indent;             /* if the indent is 1, indent writing data. */
180 };
181
182 #define DEFAULT_KEYS    (F_DEV | F_FLAGS | F_GID | F_GNAME | F_SLINK | F_MODE\
183                          | F_NLINK | F_SIZE | F_TIME | F_TYPE | F_UID\
184                          | F_UNAME)
185
186 static struct attr_counter * new_attr_count(struct mtree_entry *,
187         struct attr_counter *);
188 static void free_attr_count(struct attr_counter **);
189 static int inc_attr_count(struct attr_counter **, struct attr_counter *,
190         struct attr_counter *, struct mtree_entry *);
191 static int collect_set_values(struct mtree_writer *, struct mtree_entry *);
192 static int get_keys(struct mtree_writer *, struct mtree_entry *);
193 static void sum_init(struct mtree_writer *);
194 static void sum_update(struct mtree_writer *, const void *, size_t);
195 static void sum_final(struct mtree_writer *, struct mtree_entry *);
196 static void sum_write(struct archive_string *, struct mtree_entry *);
197
198 #define COMPUTE_CRC(var, ch)    (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)]
199 static const uint32_t crctab[] = {
200         0x0,
201         0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
202         0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
203         0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
204         0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
205         0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
206         0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
207         0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
208         0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
209         0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
210         0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
211         0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
212         0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
213         0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
214         0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
215         0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
216         0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
217         0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
218         0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
219         0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
220         0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
221         0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
222         0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
223         0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
224         0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
225         0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
226         0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
227         0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
228         0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
229         0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
230         0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
231         0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
232         0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
233         0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
234         0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
235         0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
236         0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
237         0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
238         0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
239         0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
240         0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
241         0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
242         0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
243         0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
244         0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
245         0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
246         0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
247         0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
248         0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
249         0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
250         0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
251         0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
252 };
253
254 static int
255 mtree_safe_char(char c)
256 {
257         if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
258                 return 1;
259         if (c >= '0' && c <= '9')
260                 return 1;
261         if (c == 35 || c == 61 || c == 92)
262                 return 0; /* #, = and \ are always quoted */
263         
264         if (c >= 33 && c <= 47) /* !"$%&'()*+,-./ */
265                 return 1;
266         if (c >= 58 && c <= 64) /* :;<>?@ */
267                 return 1;
268         if (c >= 91 && c <= 96) /* []^_` */
269                 return 1;
270         if (c >= 123 && c <= 126) /* {|}~ */
271                 return 1;
272         return 0;
273 }
274
275 static void
276 mtree_quote(struct archive_string *s, const char *str)
277 {
278         const char *start;
279         char buf[4];
280         unsigned char c;
281
282         for (start = str; *str != '\0'; ++str) {
283                 if (mtree_safe_char(*str))
284                         continue;
285                 if (start != str)
286                         archive_strncat(s, start, str - start);
287                 c = (unsigned char)*str;
288                 buf[0] = '\\';
289                 buf[1] = (c / 64) + '0';
290                 buf[2] = (c / 8 % 8) + '0';
291                 buf[3] = (c % 8) + '0';
292                 archive_strncat(s, buf, 4);
293                 start = str + 1;
294         }
295
296         if (start != str)
297                 archive_strncat(s, start, str - start);
298 }
299
300 /*
301  * Indent a line as mtree utility to be readable for people.
302  */
303 static void
304 mtree_indent(struct mtree_writer *mtree)
305 {
306         int i, fn;
307         const char *r, *s, *x;
308
309         fn = 1;
310         s = r = mtree->ebuf.s;
311         x = NULL;
312         while (*r == ' ')
313                 r++;
314         while ((r = strchr(r, ' ')) != NULL) {
315                 if (fn) {
316                         fn = 0;
317                         archive_strncat(&mtree->buf, s, r - s);
318                         if (r -s > INDENTNAMELEN) {
319                                 archive_strncat(&mtree->buf, " \\\n", 3);
320                                 for (i = 0; i < (INDENTNAMELEN + 1); i++)
321                                         archive_strappend_char(&mtree->buf, ' ');
322                         } else {
323                                 for (i = r -s; i < (INDENTNAMELEN + 1); i++)
324                                         archive_strappend_char(&mtree->buf, ' ');
325                         }
326                         s = ++r;
327                         x = NULL;
328                         continue;
329                 }
330                 if (r - s <= MAXLINELEN - 3 - INDENTNAMELEN)
331                         x = r++;
332                 else {
333                         if (x == NULL)
334                                 x = r;
335                         archive_strncat(&mtree->buf, s, x - s);
336                         archive_strncat(&mtree->buf, " \\\n", 3);
337                         for (i = 0; i < (INDENTNAMELEN + 1); i++)
338                                 archive_strappend_char(&mtree->buf, ' ');
339                         s = r = ++x;
340                         x = NULL;
341                 }
342         }
343         if (x != NULL && strlen(s) > MAXLINELEN - 3 - INDENTNAMELEN) {
344                 /* Last keyword is longer. */
345                 archive_strncat(&mtree->buf, s, x - s);
346                 archive_strncat(&mtree->buf, " \\\n", 3);
347                 for (i = 0; i < (INDENTNAMELEN + 1); i++)
348                         archive_strappend_char(&mtree->buf, ' ');
349                 s = ++x;
350         }
351         archive_strcat(&mtree->buf, s);
352         archive_string_empty(&mtree->ebuf);
353 }
354
355 #if !defined(_WIN32) || defined(__CYGWIN__)
356 static size_t
357 dir_len(struct mtree_entry *me)
358 {
359         const char *path, *r;
360
361         path = me->pathname;
362         r = strrchr(path, '/');
363         if (r == NULL)
364                 return (0);
365         /* Include a separator size */
366         return (r - path + 1);
367 }
368
369 #else /* _WIN32 && !__CYGWIN__ */
370 /*
371  * Note: We should use wide-character for findng '\' character,
372  * a directory separator on Windows, because some character-set have
373  * been using the '\' character for a part of its multibyte character
374  * code.
375  */
376 static size_t
377 dir_len(struct mtree_entry *me)
378 {
379         wchar_t wc;
380         const char *path;
381         const char *p, *rp;
382         size_t al, l, size;
383
384         path = me->pathname;
385         al = l = -1;
386         for (p = path; *p != '\0'; ++p) {
387                 if (*p == '\\')
388                         al = l = p - path;
389                 else if (*p == '/')
390                         al = p - path;
391         }
392         if (l == (size_t)-1)
393                 goto alen;
394         size = p - path;
395         rp = p = path;
396         while (*p != '\0') {
397                 l = mbtowc(&wc, p, size);
398                 if (l == (size_t)-1)
399                         goto alen;
400                 if (l == 1 && (wc == L'/' || wc == L'\\'))
401                         rp = p;
402                 p += l;
403                 size -= l;
404         }
405         return (rp - path + 1);
406 alen:
407         if (al == (size_t)-1)
408                 return (0);
409         return (al + 1);
410 }
411 #endif /* _WIN32 && !__CYGWIN__ */
412
413 /*
414  * Test if a parent directory of the current entry is changed.
415  */
416 static int
417 parent_dir_changed(struct archive_string *dir, struct mtree_entry *me)
418 {
419         const char *path;
420         size_t l;
421
422         l = dir_len(me);
423         path = me->pathname;
424         if (archive_strlen(dir) > 0) {
425                 if (l == 0) {
426                         archive_string_empty(dir);
427                         return (1);
428                 }
429                 if (strncmp(dir->s, path, l) == 0)
430                         return (0); /* The parent directory is the same. */
431         } else if (l == 0)
432                 return (0);         /* The parent directory is the same. */
433         archive_strncpy(dir, path, l);
434         return (1);
435 }
436
437 /*
438  * Write /set keyword.
439  * Set most used value of uid,gid,mode and fflags, which are
440  * collected by collect_set_values() function.
441  */
442 static void
443 write_global(struct mtree_writer *mtree)
444 {
445         struct archive_string setstr;
446         struct archive_string unsetstr;
447         const char *name;
448         int keys, oldkeys, effkeys;
449         struct attr_counter *ac;
450
451         archive_string_init(&setstr);
452         archive_string_init(&unsetstr);
453         keys = mtree->keys & SET_KEYS;
454         oldkeys = mtree->set.keys;
455         effkeys = keys;
456         if (mtree->set.processed) {
457                 /*
458                  * Check if the global data needs updating.
459                  */
460                 effkeys &= ~F_TYPE;
461                 if (oldkeys & (F_UNAME | F_UID)) {
462                         ac = mtree->set.uid_list;
463                         do {
464                                 if (mtree->set.uid == ac->m_entry->uid) {
465                                         effkeys &= ~(F_UNAME | F_UID);
466                                         break;
467                                 }
468                                 if (ac->next != NULL &&
469                                     ac->next->count == ac->count)
470                                         continue;
471                         } while (0);
472                 }
473                 if (oldkeys & (F_GNAME | F_GID)) {
474                         ac = mtree->set.gid_list;
475                         do {
476                                 if (mtree->set.gid == ac->m_entry->gid) {
477                                         effkeys &= ~(F_GNAME | F_GID);
478                                         break;
479                                 }
480                                 if (ac->next != NULL &&
481                                     ac->next->count == ac->count)
482                                         continue;
483                         } while (0);
484                 }
485                 if (oldkeys & F_MODE) {
486                         ac = mtree->set.mode_list;
487                         do {
488                                 if (mtree->set.mode == ac->m_entry->mode) {
489                                         effkeys &= ~F_MODE;
490                                         break;
491                                 }
492                                 if (ac->next != NULL &&
493                                     ac->next->count == ac->count)
494                                         continue;
495                         } while (0);
496                 }
497                 if ((oldkeys & F_FLAGS) != 0) {
498                         ac = mtree->set.flags_list;
499                         do {
500                                 if (ac->m_entry->fflags_set ==
501                                         mtree->set.fflags_set &&
502                                     ac->m_entry->fflags_clear ==
503                                         mtree->set.fflags_clear) {
504                                         effkeys &= ~F_FLAGS;
505                                         break;
506                                 }
507                                 if (ac->next != NULL &&
508                                     ac->next->count == ac->count)
509                                         continue;
510                         } while (0);
511                 }
512         }
513         if ((keys & effkeys & F_TYPE) != 0) {
514                 if (mtree->dironly) {
515                         archive_strcat(&setstr, " type=dir");
516                         mtree->set.type = AE_IFDIR;
517                 } else {
518                         archive_strcat(&setstr, " type=file");
519                         mtree->set.type = AE_IFREG;
520                 }
521         }
522         if ((keys & effkeys & F_UNAME) != 0) {
523                 name = mtree->set.uid_list->m_entry->uname;
524                 if (name != NULL) {
525                         archive_strcat(&setstr, " uname=");
526                         mtree_quote(&setstr, name);
527                 } else {
528                         keys &= ~F_UNAME;
529                         if ((oldkeys & F_UNAME) != 0)
530                                 archive_strcat(&unsetstr, " uname");
531                 }
532         }
533         if ((keys & effkeys & F_UID) != 0) {
534                 mtree->set.uid = mtree->set.uid_list->m_entry->uid;
535                 archive_string_sprintf(&setstr, " uid=%jd",
536                     (intmax_t)mtree->set.uid);
537         }
538         if ((keys & effkeys & F_GNAME) != 0) {
539                 name = mtree->set.gid_list->m_entry->gname;
540                 if (name != NULL) {
541                         archive_strcat(&setstr, " gname=");
542                         mtree_quote(&setstr, name);
543                 } else {
544                         keys &= ~F_GNAME;
545                         if ((oldkeys & F_GNAME) != 0)
546                                 archive_strcat(&unsetstr, " gname");
547                 }
548         }
549         if ((keys & effkeys & F_GID) != 0) {
550                 mtree->set.gid = mtree->set.gid_list->m_entry->gid;
551                 archive_string_sprintf(&setstr, " gid=%jd",
552                     (intmax_t)mtree->set.gid);
553         }
554         if ((keys & effkeys & F_MODE) != 0) {
555                 mtree->set.mode = mtree->set.mode_list->m_entry->mode;
556                 archive_string_sprintf(&setstr, " mode=%o",
557                     (unsigned int)mtree->set.mode);
558         }
559         if ((keys & effkeys & F_FLAGS) != 0) {
560                 name = mtree->set.flags_list->m_entry->fflags_text;
561                 if (name != NULL) {
562                         archive_strcat(&setstr, " flags=");
563                         mtree_quote(&setstr, name);
564                         mtree->set.fflags_set =
565                             mtree->set.flags_list->m_entry->fflags_set;
566                         mtree->set.fflags_clear =
567                             mtree->set.flags_list->m_entry->fflags_clear;
568                 } else {
569                         keys &= ~F_FLAGS;
570                         if ((oldkeys & F_FLAGS) != 0)
571                                 archive_strcat(&unsetstr, " flags");
572                 }
573         }
574         if (unsetstr.length > 0)
575                 archive_string_sprintf(&mtree->buf, "/unset%s\n", unsetstr.s);
576         archive_string_free(&unsetstr);
577         if (setstr.length > 0)
578                 archive_string_sprintf(&mtree->buf, "/set%s\n", setstr.s);
579         archive_string_free(&setstr);
580         mtree->set.keys = keys;
581         mtree->set.processed = 1;
582
583         free_attr_count(&mtree->set.uid_list);
584         free_attr_count(&mtree->set.gid_list);
585         free_attr_count(&mtree->set.mode_list);
586         free_attr_count(&mtree->set.flags_list);
587 }
588
589 static struct attr_counter *
590 new_attr_count(struct mtree_entry *me, struct attr_counter *prev)
591 {
592         struct attr_counter *ac;
593
594         ac = malloc(sizeof(*ac));
595         if (ac != NULL) {
596                 ac->prev = prev;
597                 ac->next = NULL;
598                 ac->count = 1;
599                 ac->m_entry = me;
600         }
601         return (ac);
602 }
603
604 static void
605 free_attr_count(struct attr_counter **top)
606 {
607         struct attr_counter *ac, *tac;
608
609         if (*top == NULL)
610                 return;
611         ac = *top;
612         while (ac != NULL) {
613                 tac = ac->next;
614                 free(ac);
615                 ac = tac;
616         }
617         *top = NULL;
618 }
619
620 static int
621 inc_attr_count(struct attr_counter **top, struct attr_counter *ac,
622     struct attr_counter *last, struct mtree_entry *me)
623 {
624         struct attr_counter *pac;
625
626         if (ac != NULL) {
627                 ac->count++;
628                 if (*top == ac || ac->prev->count >= ac->count)
629                         return (0);
630                 for (pac = ac->prev; pac; pac = pac->prev) {
631                         if (pac->count >= ac->count)
632                                 break;
633                 }
634                 ac->prev->next = ac->next;
635                 if (ac->next != NULL)
636                         ac->next->prev = ac->prev;
637                 if (pac != NULL) {
638                         ac->prev = pac;
639                         ac->next = pac->next;
640                         pac->next = ac;
641                         if (ac->next != NULL)
642                                 ac->next->prev = ac;
643                 } else {
644                         ac->prev = NULL;
645                         ac->next = *top;
646                         *top = ac;
647                         ac->next->prev = ac;
648                 }
649         } else {
650                 ac = new_attr_count(me, last);
651                 if (ac == NULL)
652                         return (-1);
653                 last->next = ac;
654         }
655         return (0);
656 }
657
658 static int
659 collect_set_values(struct mtree_writer *mtree, struct mtree_entry *me)
660 {
661         int keys = mtree->keys;
662         struct attr_counter *ac, *last;
663
664         if (keys & (F_UNAME | F_UID)) {
665                 if (mtree->set.uid_list == NULL) {
666                         mtree->set.uid_list = new_attr_count(me, NULL);
667                         if (mtree->set.uid_list == NULL)
668                                 return (-1);
669                 } else {
670                         last = NULL;
671                         for (ac = mtree->set.uid_list; ac; ac = ac->next) {
672                                 if (ac->m_entry->uid == me->uid)
673                                         break;
674                                 last = ac;
675                         }
676                         if (inc_attr_count(
677                             &mtree->set.uid_list, ac, last, me) < 0)
678                                 return (-1);
679                 }
680         }
681         if (keys & (F_GNAME | F_GID)) {
682                 if (mtree->set.gid_list == NULL) {
683                         mtree->set.gid_list = new_attr_count(me, NULL);
684                         if (mtree->set.gid_list == NULL)
685                                 return (-1);
686                 } else {
687                         last = NULL;
688                         for (ac = mtree->set.gid_list; ac; ac = ac->next) {
689                                 if (ac->m_entry->gid == me->gid)
690                                         break;
691                                 last = ac;
692                         }
693                         if (inc_attr_count(
694                             &mtree->set.gid_list, ac, last, me) < 0)
695                                 return (-1);
696                 }
697         }
698         if (keys & F_MODE) {
699                 if (mtree->set.mode_list == NULL) {
700                         mtree->set.mode_list = new_attr_count(me, NULL);
701                         if (mtree->set.mode_list == NULL)
702                                 return (-1);
703                 } else {
704                         last = NULL;
705                         for (ac = mtree->set.mode_list; ac; ac = ac->next) {
706                                 if (ac->m_entry->mode == me->mode)
707                                         break;
708                                 last = ac;
709                         }
710                         if (inc_attr_count(
711                             &mtree->set.mode_list, ac, last, me) < 0)
712                                 return (-1);
713                 }
714         }
715         if (keys & F_FLAGS) {
716                 if (mtree->set.flags_list == NULL) {
717                         mtree->set.flags_list = new_attr_count(me, NULL);
718                         if (mtree->set.flags_list == NULL)
719                                 return (-1);
720                 } else {
721                         last = NULL;
722                         for (ac = mtree->set.flags_list; ac; ac = ac->next) {
723                                 if (ac->m_entry->fflags_set == me->fflags_set &&
724                                     ac->m_entry->fflags_clear == me->fflags_clear)
725                                         break;
726                                 last = ac;
727                         }
728                         if (inc_attr_count(
729                             &mtree->set.flags_list, ac, last, me) < 0)
730                                 return (-1);
731                 }
732         }
733
734         /*
735          * Save a entry.
736          */
737         me->next = NULL;
738         *mtree->set.me_last = me;
739         mtree->set.me_last = &me->next;
740         return (0);
741 }
742
743 static int
744 get_keys(struct mtree_writer *mtree, struct mtree_entry *me)
745 {
746         int keys;
747
748         keys = mtree->keys;
749
750         /*
751          * If a keyword has been set by /set, we do not need to
752          * output it.
753          */
754         if (mtree->set.keys == 0)
755                 return (keys);/* /set is not used. */
756
757         if ((mtree->set.keys & (F_GNAME | F_GID)) != 0 &&
758              mtree->set.gid == me->gid)
759                 keys &= ~(F_GNAME | F_GID);
760         if ((mtree->set.keys & (F_UNAME | F_UID)) != 0 &&
761              mtree->set.uid == me->uid)
762                 keys &= ~(F_UNAME | F_UID);
763         if (mtree->set.keys & F_FLAGS) {
764                 if (mtree->set.fflags_set == me->fflags_set &&
765                     mtree->set.fflags_clear == me->fflags_clear)
766                         keys &= ~F_FLAGS;
767         }
768         if ((mtree->set.keys & F_MODE) != 0 && mtree->set.mode == me->mode)
769                 keys &= ~F_MODE;
770
771         switch (me->filetype) {
772         case AE_IFLNK: case AE_IFSOCK: case AE_IFCHR:
773         case AE_IFBLK: case AE_IFIFO:
774                 break;
775         case AE_IFDIR:
776                 if ((mtree->set.keys & F_TYPE) != 0 &&
777                     mtree->set.type == AE_IFDIR)
778                         keys &= ~F_TYPE;
779                 break;
780         case AE_IFREG:
781         default:        /* Handle unknown file types as regular files. */
782                 if ((mtree->set.keys & F_TYPE) != 0 &&
783                     mtree->set.type == AE_IFREG)
784                         keys &= ~F_TYPE;
785                 break;
786         }
787
788         return (keys);
789 }
790
791 static struct mtree_entry *
792 new_mtree_entry(struct archive_entry *entry)
793 {
794         struct mtree_entry *me;
795         const char *s;
796
797         me = calloc(1, sizeof(*me));
798         if (me == NULL)
799                 return (NULL);
800         me->pathname = strdup(archive_entry_pathname(entry));
801         if ((s = archive_entry_symlink(entry)) != NULL)
802                 me->symlink = strdup(s);
803         else
804                 me->symlink = NULL;
805         me->nlink = archive_entry_nlink(entry);
806         me->filetype = archive_entry_filetype(entry);
807         me->mode = archive_entry_mode(entry) & 07777;
808         me->uid = archive_entry_uid(entry);
809         me->gid = archive_entry_gid(entry);
810         if ((s = archive_entry_uname(entry)) != NULL)
811                 me->uname = strdup(s);
812         else
813                 me->uname = NULL;
814         if ((s = archive_entry_gname(entry)) != NULL)
815                 me->gname = strdup(s);
816         else
817                 me->gname = NULL;
818         if ((s = archive_entry_fflags_text(entry)) != NULL)
819                 me->fflags_text = strdup(s);
820         else
821                 me->fflags_text = NULL;
822         archive_entry_fflags(entry, &me->fflags_set, &me->fflags_clear);
823         me->mtime = archive_entry_mtime(entry);
824         me->mtime_nsec = archive_entry_mtime_nsec(entry);
825         me->rdevmajor = archive_entry_rdevmajor(entry);
826         me->rdevminor = archive_entry_rdevminor(entry);
827         me->size = archive_entry_size(entry);
828         me->compute_sum = 0;
829
830         return (me);
831 }
832
833 static void
834 free_mtree_entry(struct mtree_entry *me)
835 {
836         free(me->pathname);
837         free(me->symlink);
838         free(me->uname);
839         free(me->gname);
840         free(me->fflags_text);
841         free(me);
842 }
843
844 static int
845 archive_write_mtree_header(struct archive_write *a,
846     struct archive_entry *entry)
847 {
848         struct mtree_writer *mtree= a->format_data;
849
850         if (mtree->first) {
851                 mtree->first = 0;
852                 archive_strcat(&mtree->buf, "#mtree\n");
853                 if ((mtree->keys & SET_KEYS) == 0)
854                         mtree->set.output = 0;/* Disalbed. */
855         }
856
857         mtree->entry_bytes_remaining = archive_entry_size(entry);
858         if (mtree->dironly && archive_entry_filetype(entry) != AE_IFDIR)
859                 return (ARCHIVE_OK);
860
861         mtree->mtree_entry = new_mtree_entry(entry);
862         if (mtree->mtree_entry == NULL) {
863                 archive_set_error(&a->archive, ENOMEM,
864                     "Can't allocate mtree entry");
865                 return (ARCHIVE_FATAL);
866         }
867
868         mtree->compute_sum = 0;
869
870         /* If current file is not a regular file, we do not have to
871          * compute the sum of its content. */ 
872         if (archive_entry_filetype(entry) != AE_IFREG)
873                 return (ARCHIVE_OK);
874                 
875         /* Initialize a bunch of sum check context. */
876         sum_init(mtree);
877
878         return (ARCHIVE_OK);
879 }
880
881 static int
882 write_entry(struct archive_write *a, struct mtree_entry *me)
883 {
884         struct mtree_writer *mtree = a->format_data;
885         struct archive_string *str;
886         int keys, ret;
887
888         archive_string_empty(&mtree->ebuf);
889         str = (mtree->indent)? &mtree->ebuf : &mtree->buf;
890         mtree_quote(str, me->pathname);
891         keys = get_keys(mtree, me);
892         if ((keys & F_NLINK) != 0 &&
893             me->nlink != 1 && me->filetype != AE_IFDIR)
894                 archive_string_sprintf(str, " nlink=%u", me->nlink);
895
896         if ((keys & F_GNAME) != 0 && me->gname != NULL) {
897                 archive_strcat(str, " gname=");
898                 mtree_quote(str, me->gname);
899         }
900         if ((keys & F_UNAME) != 0 && me->uname != NULL) {
901                 archive_strcat(str, " uname=");
902                 mtree_quote(str, me->uname);
903         }
904         if ((keys & F_FLAGS) != 0) {
905                 if (me->fflags_text != NULL) {
906                         archive_strcat(str, " flags=");
907                         mtree_quote(str, me->fflags_text);
908                 } else if (mtree->set.processed &&
909                     (mtree->set.keys & F_FLAGS) != 0)
910                         /* Overwrite the global parameter. */
911                         archive_strcat(str, " flags=none");
912         }
913         if ((keys & F_TIME) != 0)
914                 archive_string_sprintf(str, " time=%jd.%jd",
915                     (intmax_t)me->mtime, (intmax_t)me->mtime_nsec);
916         if ((keys & F_MODE) != 0)
917                 archive_string_sprintf(str, " mode=%o", (unsigned int)me->mode);
918         if ((keys & F_GID) != 0)
919                 archive_string_sprintf(str, " gid=%jd", (intmax_t)me->gid);
920         if ((keys & F_UID) != 0)
921                 archive_string_sprintf(str, " uid=%jd", (intmax_t)me->uid);
922
923         switch (me->filetype) {
924         case AE_IFLNK:
925                 if ((keys & F_TYPE) != 0)
926                         archive_strcat(str, " type=link");
927                 if ((keys & F_SLINK) != 0) {
928                         archive_strcat(str, " link=");
929                         mtree_quote(str, me->symlink);
930                 }
931                 break;
932         case AE_IFSOCK:
933                 if ((keys & F_TYPE) != 0)
934                         archive_strcat(str, " type=socket");
935                 break;
936         case AE_IFCHR:
937                 if ((keys & F_TYPE) != 0)
938                         archive_strcat(str, " type=char");
939                 if ((keys & F_DEV) != 0) {
940                         archive_string_sprintf(str,
941                             " device=native,%ju,%ju",
942                             (uintmax_t)me->rdevmajor,
943                             (uintmax_t)me->rdevminor);
944                 }
945                 break;
946         case AE_IFBLK:
947                 if ((keys & F_TYPE) != 0)
948                         archive_strcat(str, " type=block");
949                 if ((keys & F_DEV) != 0) {
950                         archive_string_sprintf(str,
951                             " device=native,%ju,%ju",
952                             (uintmax_t)me->rdevmajor,
953                             (uintmax_t)me->rdevminor);
954                 }
955                 break;
956         case AE_IFDIR:
957                 if ((keys & F_TYPE) != 0)
958                         archive_strcat(str, " type=dir");
959                 break;
960         case AE_IFIFO:
961                 if ((keys & F_TYPE) != 0)
962                         archive_strcat(str, " type=fifo");
963                 break;
964         case AE_IFREG:
965         default:        /* Handle unknown file types as regular files. */
966                 if ((keys & F_TYPE) != 0)
967                         archive_strcat(str, " type=file");
968                 if ((keys & F_SIZE) != 0)
969                         archive_string_sprintf(str, " size=%jd",
970                             (intmax_t)me->size);
971                 break;
972         }
973
974         /* Write a bunch of sum. */
975         if (me->filetype == AE_IFREG)
976                 sum_write(str, me);
977
978         archive_strcat(str, "\n");
979         if (mtree->indent)
980                 mtree_indent(mtree);
981
982         if (mtree->buf.length > 32768) {
983                 ret = __archive_write_output(a, mtree->buf.s, mtree->buf.length);
984                 archive_string_empty(&mtree->buf);
985         } else
986                 ret = ARCHIVE_OK;
987         return (ret);
988 }
989
990 /*
991  * Write mtree entries saved at collect_set_values() function.
992  */
993 static int
994 write_mtree_entries(struct archive_write *a)
995 {
996         struct mtree_writer *mtree = a->format_data;
997         struct mtree_entry *me, *tme;
998         int ret;
999
1000         for (me = mtree->set.me_first; me; me = me->next) {
1001                 ret = write_entry(a, me);
1002                 if (ret != ARCHIVE_OK)
1003                         return (ARCHIVE_FATAL);
1004         }
1005
1006         me = mtree->set.me_first;
1007         while (me != NULL) {
1008                 tme = me->next;
1009                 free_mtree_entry(me);
1010                 me = tme;
1011         }
1012         mtree->set.me_first = NULL;
1013         mtree->set.me_last = &mtree->set.me_first;
1014         return (ARCHIVE_OK);
1015 }
1016
1017 static int
1018 archive_write_mtree_finish_entry(struct archive_write *a)
1019 {
1020         struct mtree_writer *mtree = a->format_data;
1021         struct mtree_entry *me;
1022         int ret;
1023
1024         if ((me = mtree->mtree_entry) == NULL)
1025                 return (ARCHIVE_OK);
1026         mtree->mtree_entry = NULL;
1027
1028         if (me->filetype == AE_IFREG)
1029                 sum_final(mtree, me);
1030
1031         if (mtree->set.output) {
1032                 if (!mtree->dironly) {
1033                         if (archive_strlen(&mtree->set.parent) == 0)
1034                                 parent_dir_changed(&mtree->set.parent, me);
1035                         if (parent_dir_changed(&mtree->set.parent, me)) {
1036                                 /* Write /set keyword */
1037                                 write_global(mtree);
1038                                 /* Write entries saved by
1039                                  * collect_set_values() function. */
1040                                 ret = write_mtree_entries(a);
1041                                 if (ret != ARCHIVE_OK)
1042                                         return (ARCHIVE_FATAL);
1043                         }
1044                 }
1045                 /* Tabulate uid,gid,mode and fflags of a entry
1046                  * in order to be used for /set. and, at this time
1047                  * we do not write a entry.  */
1048                 collect_set_values(mtree, me);
1049                 return (ARCHIVE_OK);
1050         } else {
1051                 /* Write the current entry and free it. */
1052                 ret = write_entry(a, me);
1053                 free_mtree_entry(me);
1054         }
1055         return (ret == ARCHIVE_OK ? ret : ARCHIVE_FATAL);
1056 }
1057
1058 static int
1059 archive_write_mtree_close(struct archive_write *a)
1060 {
1061         struct mtree_writer *mtree= a->format_data;
1062         int ret;
1063
1064         if (mtree->set.output && mtree->set.me_first != NULL) {
1065                 write_global(mtree);
1066                 ret = write_mtree_entries(a);
1067                 if (ret != ARCHIVE_OK)
1068                         return (ARCHIVE_FATAL);
1069         }
1070
1071         archive_write_set_bytes_in_last_block(&a->archive, 1);
1072
1073         return __archive_write_output(a, mtree->buf.s, mtree->buf.length);
1074 }
1075
1076 static ssize_t
1077 archive_write_mtree_data(struct archive_write *a, const void *buff, size_t n)
1078 {
1079         struct mtree_writer *mtree= a->format_data;
1080
1081         if (n > mtree->entry_bytes_remaining)
1082                 n = (size_t)mtree->entry_bytes_remaining;
1083         mtree->entry_bytes_remaining -= n;
1084
1085         /* We don't need to compute a regular file sum */
1086         if (mtree->mtree_entry == NULL)
1087                 return (n);
1088
1089         if (mtree->mtree_entry->filetype == AE_IFREG)
1090                 sum_update(mtree, buff, n);
1091
1092         return (n);
1093 }
1094
1095 static int
1096 archive_write_mtree_free(struct archive_write *a)
1097 {
1098         struct mtree_writer *mtree= a->format_data;
1099         struct mtree_entry *me, *tme;
1100
1101         if (mtree == NULL)
1102                 return (ARCHIVE_OK);
1103
1104         /* Make sure we dot not leave any entries. */
1105         me = mtree->set.me_first;
1106         while (me != NULL) {
1107                 tme = me->next;
1108                 free_mtree_entry(me);
1109                 me = tme;
1110         }
1111         archive_string_free(&mtree->ebuf);
1112         archive_string_free(&mtree->buf);
1113         archive_string_free(&mtree->set.parent);
1114         free_attr_count(&mtree->set.uid_list);
1115         free_attr_count(&mtree->set.gid_list);
1116         free_attr_count(&mtree->set.mode_list);
1117         free_attr_count(&mtree->set.flags_list);
1118         free(mtree);
1119         a->format_data = NULL;
1120         return (ARCHIVE_OK);
1121 }
1122
1123 static int
1124 archive_write_mtree_options(struct archive_write *a, const char *key,
1125     const char *value)
1126 {
1127         struct mtree_writer *mtree= a->format_data;
1128         int keybit = 0;
1129
1130         switch (key[0]) {
1131         case 'a':
1132                 if (strcmp(key, "all") == 0)
1133                         keybit = ~0;
1134                 break;
1135         case 'c':
1136                 if (strcmp(key, "cksum") == 0)
1137                         keybit = F_CKSUM;
1138                 break;
1139         case 'd':
1140                 if (strcmp(key, "device") == 0)
1141                         keybit = F_DEV;
1142                 else if (strcmp(key, "dironly") == 0) {
1143                         mtree->dironly = (value != NULL)? 1: 0;
1144                         return (ARCHIVE_OK);
1145                 }
1146                 break;
1147         case 'f':
1148                 if (strcmp(key, "flags") == 0)
1149                         keybit = F_FLAGS;
1150                 break;
1151         case 'g':
1152                 if (strcmp(key, "gid") == 0)
1153                         keybit = F_GID;
1154                 else if (strcmp(key, "gname") == 0)
1155                         keybit = F_GNAME;
1156                 break;
1157         case 'i':
1158                 if (strcmp(key, "indent") == 0) {
1159                         mtree->indent = (value != NULL)? 1: 0;
1160                         return (ARCHIVE_OK);
1161                 }
1162                 break;
1163         case 'l':
1164                 if (strcmp(key, "link") == 0)
1165                         keybit = F_SLINK;
1166                 break;
1167         case 'm':
1168                 if (strcmp(key, "md5") == 0 ||
1169                     strcmp(key, "md5digest") == 0)
1170                         keybit = F_MD5;
1171                 if (strcmp(key, "mode") == 0)
1172                         keybit = F_MODE;
1173                 break;
1174         case 'n':
1175                 if (strcmp(key, "nlink") == 0)
1176                         keybit = F_NLINK;
1177                 break;
1178         case 'r':
1179                 if (strcmp(key, "ripemd160digest") == 0 ||
1180                     strcmp(key, "rmd160") == 0 ||
1181                     strcmp(key, "rmd160digest") == 0)
1182                         keybit = F_RMD160;
1183                 break;
1184         case 's':
1185                 if (strcmp(key, "sha1") == 0 ||
1186                     strcmp(key, "sha1digest") == 0)
1187                         keybit = F_SHA1;
1188                 if (strcmp(key, "sha256") == 0 ||
1189                     strcmp(key, "sha256digest") == 0)
1190                         keybit = F_SHA256;
1191                 if (strcmp(key, "sha384") == 0 ||
1192                     strcmp(key, "sha384digest") == 0)
1193                         keybit = F_SHA384;
1194                 if (strcmp(key, "sha512") == 0 ||
1195                     strcmp(key, "sha512digest") == 0)
1196                         keybit = F_SHA512;
1197                 if (strcmp(key, "size") == 0)
1198                         keybit = F_SIZE;
1199                 break;
1200         case 't':
1201                 if (strcmp(key, "time") == 0)
1202                         keybit = F_TIME;
1203                 else if (strcmp(key, "type") == 0)
1204                         keybit = F_TYPE;
1205                 break;
1206         case 'u':
1207                 if (strcmp(key, "uid") == 0)
1208                         keybit = F_UID;
1209                 else if (strcmp(key, "uname") == 0)
1210                         keybit = F_UNAME;
1211                 else if (strcmp(key, "use-set") == 0) {
1212                         mtree->set.output = (value != NULL)? 1: 0;
1213                         return (ARCHIVE_OK);
1214                 }
1215                 break;
1216         }
1217         if (keybit != 0) {
1218                 if (value != NULL)
1219                         mtree->keys |= keybit;
1220                 else
1221                         mtree->keys &= ~keybit;
1222                 return (ARCHIVE_OK);
1223         }
1224
1225         /* Note: The "warn" return is just to inform the options
1226          * supervisor that we didn't handle it.  It will generate
1227          * a suitable error if no one used this option. */
1228         return (ARCHIVE_WARN);
1229 }
1230
1231 int
1232 archive_write_set_format_mtree(struct archive *_a)
1233 {
1234         struct archive_write *a = (struct archive_write *)_a;
1235         struct mtree_writer *mtree;
1236
1237         archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
1238             ARCHIVE_STATE_NEW, "archive_write_set_format_mtree");
1239
1240         if (a->format_free != NULL)
1241                 (a->format_free)(a);
1242
1243         if ((mtree = calloc(1, sizeof(*mtree))) == NULL) {
1244                 archive_set_error(&a->archive, ENOMEM,
1245                     "Can't allocate mtree data");
1246                 return (ARCHIVE_FATAL);
1247         }
1248
1249         mtree->mtree_entry = NULL;
1250         mtree->first = 1;
1251         memset(&(mtree->set), 0, sizeof(mtree->set));
1252         archive_string_init(&mtree->set.parent);
1253         mtree->keys = DEFAULT_KEYS;
1254         mtree->dironly = 0;
1255         mtree->indent = 0;
1256         archive_string_init(&mtree->ebuf);
1257         archive_string_init(&mtree->buf);
1258         mtree->set.me_first = NULL;
1259         mtree->set.me_last = &mtree->set.me_first;
1260         a->format_data = mtree;
1261         a->format_free = archive_write_mtree_free;
1262         a->format_name = "mtree";
1263         a->format_options = archive_write_mtree_options;
1264         a->format_write_header = archive_write_mtree_header;
1265         a->format_close = archive_write_mtree_close;
1266         a->format_write_data = archive_write_mtree_data;
1267         a->format_finish_entry = archive_write_mtree_finish_entry;
1268         a->archive.archive_format = ARCHIVE_FORMAT_MTREE;
1269         a->archive.archive_format_name = "mtree";
1270
1271         return (ARCHIVE_OK);
1272 }
1273
1274 static void
1275 sum_init(struct mtree_writer *mtree)
1276 {
1277         if (mtree->keys & F_CKSUM) {
1278                 mtree->compute_sum |= F_CKSUM;
1279                 mtree->crc = 0;
1280                 mtree->crc_len = 0;
1281         }
1282 #ifdef ARCHIVE_HAS_MD5
1283         if (mtree->keys & F_MD5) {
1284                 if (archive_md5_init(&mtree->md5ctx) == ARCHIVE_OK)
1285                         mtree->compute_sum |= F_MD5;
1286                 else
1287                         mtree->keys &= ~F_MD5;/* Not supported. */
1288         }
1289 #endif
1290 #ifdef ARCHIVE_HAS_RMD160
1291         if (mtree->keys & F_RMD160) {
1292                 if (archive_rmd160_init(&mtree->rmd160ctx) == ARCHIVE_OK)
1293                         mtree->compute_sum |= F_RMD160;
1294                 else
1295                         mtree->keys &= ~F_RMD160;/* Not supported. */
1296         }
1297 #endif
1298 #ifdef ARCHIVE_HAS_SHA1
1299         if (mtree->keys & F_SHA1) {
1300                 if (archive_sha1_init(&mtree->sha1ctx) == ARCHIVE_OK)
1301                         mtree->compute_sum |= F_SHA1;
1302                 else
1303                         mtree->keys &= ~F_SHA1;/* Not supported. */
1304         }
1305 #endif
1306 #ifdef ARCHIVE_HAS_SHA256
1307         if (mtree->keys & F_SHA256) {
1308                 if (archive_sha256_init(&mtree->sha256ctx) == ARCHIVE_OK)
1309                         mtree->compute_sum |= F_SHA256;
1310                 else
1311                         mtree->keys &= ~F_SHA256;/* Not supported. */
1312         }
1313 #endif
1314 #ifdef ARCHIVE_HAS_SHA384
1315         if (mtree->keys & F_SHA384) {
1316                 if (archive_sha384_init(&mtree->sha384ctx) == ARCHIVE_OK)
1317                         mtree->compute_sum |= F_SHA384;
1318                 else
1319                         mtree->keys &= ~F_SHA384;/* Not supported. */
1320         }
1321 #endif
1322 #ifdef ARCHIVE_HAS_SHA512
1323         if (mtree->keys & F_SHA512) {
1324                 if (archive_sha512_init(&mtree->sha512ctx) == ARCHIVE_OK)
1325                         mtree->compute_sum |= F_SHA512;
1326                 else
1327                         mtree->keys &= ~F_SHA512;/* Not supported. */
1328         }
1329 #endif
1330 }
1331
1332 static void
1333 sum_update(struct mtree_writer *mtree, const void *buff, size_t n)
1334 {
1335         if (mtree->compute_sum & F_CKSUM) {
1336                 /*
1337                  * Compute a POSIX 1003.2 checksum
1338                  */
1339                 const unsigned char *p;
1340                 size_t nn;
1341
1342                 for (nn = n, p = buff; nn--; ++p)
1343                         COMPUTE_CRC(mtree->crc, *p);
1344                 mtree->crc_len += n;
1345         }
1346 #ifdef ARCHIVE_HAS_MD5
1347         if (mtree->compute_sum & F_MD5)
1348                 archive_md5_update(&mtree->md5ctx, buff, n);
1349 #endif
1350 #ifdef ARCHIVE_HAS_RMD160
1351         if (mtree->compute_sum & F_RMD160)
1352                 archive_rmd160_update(&mtree->rmd160ctx, buff, n);
1353 #endif
1354 #ifdef ARCHIVE_HAS_SHA1
1355         if (mtree->compute_sum & F_SHA1)
1356                 archive_sha1_update(&mtree->sha1ctx, buff, n);
1357 #endif
1358 #ifdef ARCHIVE_HAS_SHA256
1359         if (mtree->compute_sum & F_SHA256)
1360                 archive_sha256_update(&mtree->sha256ctx, buff, n);
1361 #endif
1362 #ifdef ARCHIVE_HAS_SHA384
1363         if (mtree->compute_sum & F_SHA384)
1364                 archive_sha384_update(&mtree->sha384ctx, buff, n);
1365 #endif
1366 #ifdef ARCHIVE_HAS_SHA512
1367         if (mtree->compute_sum & F_SHA512)
1368                 archive_sha512_update(&mtree->sha512ctx, buff, n);
1369 #endif
1370 }
1371
1372 static void
1373 sum_final(struct mtree_writer *mtree, struct mtree_entry *me)
1374 {
1375
1376         if (mtree->compute_sum & F_CKSUM) {
1377                 uint64_t len;
1378                 /* Include the length of the file. */
1379                 for (len = mtree->crc_len; len != 0; len >>= 8)
1380                         COMPUTE_CRC(mtree->crc, len & 0xff);
1381                 me->crc = ~mtree->crc;
1382         }
1383 #ifdef ARCHIVE_HAS_MD5
1384         if (mtree->compute_sum & F_MD5)
1385                 archive_md5_final(&mtree->md5ctx, me->buf_md5);
1386 #endif
1387 #ifdef ARCHIVE_HAS_RMD160
1388         if (mtree->compute_sum & F_RMD160)
1389                 archive_rmd160_final(&mtree->rmd160ctx, me->buf_rmd160);
1390 #endif
1391 #ifdef ARCHIVE_HAS_SHA1
1392         if (mtree->compute_sum & F_SHA1)
1393                 archive_sha1_final(&mtree->sha1ctx, me->buf_sha1);
1394 #endif
1395 #ifdef ARCHIVE_HAS_SHA256
1396         if (mtree->compute_sum & F_SHA256)
1397                 archive_sha256_final(&mtree->sha256ctx, me->buf_sha256);
1398 #endif
1399 #ifdef ARCHIVE_HAS_SHA384
1400         if (mtree->compute_sum & F_SHA384)
1401                 archive_sha384_final(&mtree->sha384ctx, me->buf_sha384);
1402 #endif
1403 #ifdef ARCHIVE_HAS_SHA512
1404         if (mtree->compute_sum & F_SHA512)
1405                 archive_sha512_final(&mtree->sha512ctx, me->buf_sha512);
1406 #endif
1407         /* Save what types of sum are computed. */
1408         me->compute_sum = mtree->compute_sum;
1409 }
1410
1411 #if defined(ARCHIVE_HAS_MD5) || defined(ARCHIVE_HAS_RMD160) || \
1412     defined(ARCHIVE_HAS_SHA1) || defined(ARCHIVE_HAS_SHA256) || \
1413     defined(ARCHIVE_HAS_SHA384) || defined(ARCHIVE_HAS_SHA512)
1414 static void
1415 strappend_bin(struct archive_string *s, const unsigned char *bin, int n)
1416 {
1417         static const char hex[] = "0123456789abcdef";
1418         int i;
1419
1420         for (i = 0; i < n; i++) {
1421                 archive_strappend_char(s, hex[bin[i] >> 4]);
1422                 archive_strappend_char(s, hex[bin[i] & 0x0f]);
1423         }
1424 }
1425 #endif
1426
1427 static void
1428 sum_write(struct archive_string *str, struct mtree_entry *me)
1429 {
1430
1431         if (me->compute_sum & F_CKSUM) {
1432                 archive_string_sprintf(str, " cksum=%ju",
1433                     (uintmax_t)me->crc);
1434         }
1435 #ifdef ARCHIVE_HAS_MD5
1436         if (me->compute_sum & F_MD5) {
1437                 archive_strcat(str, " md5digest=");
1438                 strappend_bin(str, me->buf_md5, sizeof(me->buf_md5));
1439         }
1440 #endif
1441 #ifdef ARCHIVE_HAS_RMD160
1442         if (me->compute_sum & F_RMD160) {
1443                 archive_strcat(str, " rmd160digest=");
1444                 strappend_bin(str, me->buf_rmd160, sizeof(me->buf_rmd160));
1445         }
1446 #endif
1447 #ifdef ARCHIVE_HAS_SHA1
1448         if (me->compute_sum & F_SHA1) {
1449                 archive_strcat(str, " sha1digest=");
1450                 strappend_bin(str, me->buf_sha1, sizeof(me->buf_sha1));
1451         }
1452 #endif
1453 #ifdef ARCHIVE_HAS_SHA256
1454         if (me->compute_sum & F_SHA256) {
1455                 archive_strcat(str, " sha256digest=");
1456                 strappend_bin(str, me->buf_sha256, sizeof(me->buf_sha256));
1457         }
1458 #endif
1459 #ifdef ARCHIVE_HAS_SHA384
1460         if (me->compute_sum & F_SHA384) {
1461                 archive_strcat(str, " sha384digest=");
1462                 strappend_bin(str, me->buf_sha384, sizeof(me->buf_sha384));
1463         }
1464 #endif
1465 #ifdef ARCHIVE_HAS_SHA512
1466         if (me->compute_sum & F_SHA512) {
1467                 archive_strcat(str, " sha512digest=");
1468                 strappend_bin(str, me->buf_sha512, sizeof(me->buf_sha512));
1469         }
1470 #endif
1471 }