1 /*-
2  * Copyright (c) 2009,2011 Michihiro NAKAJIMA
3  * Copyright (c) 2008 Joerg Sonnenberger
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "archive_platform.h"
28 __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_mtree.c 201171 2009-12-29 06:39:07Z kientzle $");
29 
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
32 #endif
33 #include <errno.h>
34 #include <stdlib.h>
35 #include <string.h>
36 
37 #include "archive.h"
38 #include "archive_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 == -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 == -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 == -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 = 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 	return (ARCHIVE_FAILED);
1226 }
1227 
1228 int
1229 archive_write_set_format_mtree(struct archive *_a)
1230 {
1231 	struct archive_write *a = (struct archive_write *)_a;
1232 	struct mtree_writer *mtree;
1233 
1234 	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
1235 	    ARCHIVE_STATE_NEW, "archive_write_set_format_mtree");
1236 
1237 	if (a->format_free != NULL)
1238 		(a->format_free)(a);
1239 
1240 	if ((mtree = calloc(1, sizeof(*mtree))) == NULL) {
1241 		archive_set_error(&a->archive, ENOMEM,
1242 		    "Can't allocate mtree data");
1243 		return (ARCHIVE_FATAL);
1244 	}
1245 
1246 	mtree->mtree_entry = NULL;
1247 	mtree->first = 1;
1248 	memset(&(mtree->set), 0, sizeof(mtree->set));
1249 	archive_string_init(&mtree->set.parent);
1250 	mtree->keys = DEFAULT_KEYS;
1251 	mtree->dironly = 0;
1252 	mtree->indent = 0;
1253 	archive_string_init(&mtree->ebuf);
1254 	archive_string_init(&mtree->buf);
1255 	mtree->set.me_first = NULL;
1256 	mtree->set.me_last = &mtree->set.me_first;
1257 	a->format_data = mtree;
1258 	a->format_free = archive_write_mtree_free;
1259 	a->format_name = "mtree";
1260 	a->format_options = archive_write_mtree_options;
1261 	a->format_write_header = archive_write_mtree_header;
1262 	a->format_close = archive_write_mtree_close;
1263 	a->format_write_data = archive_write_mtree_data;
1264 	a->format_finish_entry = archive_write_mtree_finish_entry;
1265 	a->archive.archive_format = ARCHIVE_FORMAT_MTREE;
1266 	a->archive.archive_format_name = "mtree";
1267 
1268 	return (ARCHIVE_OK);
1269 }
1270 
1271 static void
1272 sum_init(struct mtree_writer *mtree)
1273 {
1274 	if (mtree->keys & F_CKSUM) {
1275 		mtree->compute_sum |= F_CKSUM;
1276 		mtree->crc = 0;
1277 		mtree->crc_len = 0;
1278 	}
1279 #ifdef ARCHIVE_HAS_MD5
1280 	if (mtree->keys & F_MD5) {
1281 		if (archive_md5_init(&mtree->md5ctx) == ARCHIVE_OK)
1282 			mtree->compute_sum |= F_MD5;
1283 		else
1284 			mtree->keys &= ~F_MD5;/* Not supported. */
1285 	}
1286 #endif
1287 #ifdef ARCHIVE_HAS_RMD160
1288 	if (mtree->keys & F_RMD160) {
1289 		if (archive_rmd160_init(&mtree->rmd160ctx) == ARCHIVE_OK)
1290 			mtree->compute_sum |= F_RMD160;
1291 		else
1292 			mtree->keys &= ~F_RMD160;/* Not supported. */
1293 	}
1294 #endif
1295 #ifdef ARCHIVE_HAS_SHA1
1296 	if (mtree->keys & F_SHA1) {
1297 		if (archive_sha1_init(&mtree->sha1ctx) == ARCHIVE_OK)
1298 			mtree->compute_sum |= F_SHA1;
1299 		else
1300 			mtree->keys &= ~F_SHA1;/* Not supported. */
1301 	}
1302 #endif
1303 #ifdef ARCHIVE_HAS_SHA256
1304 	if (mtree->keys & F_SHA256) {
1305 		if (archive_sha256_init(&mtree->sha256ctx) == ARCHIVE_OK)
1306 			mtree->compute_sum |= F_SHA256;
1307 		else
1308 			mtree->keys &= ~F_SHA256;/* Not supported. */
1309 	}
1310 #endif
1311 #ifdef ARCHIVE_HAS_SHA384
1312 	if (mtree->keys & F_SHA384) {
1313 		if (archive_sha384_init(&mtree->sha384ctx) == ARCHIVE_OK)
1314 			mtree->compute_sum |= F_SHA384;
1315 		else
1316 			mtree->keys &= ~F_SHA384;/* Not supported. */
1317 	}
1318 #endif
1319 #ifdef ARCHIVE_HAS_SHA512
1320 	if (mtree->keys & F_SHA512) {
1321 		if (archive_sha512_init(&mtree->sha512ctx) == ARCHIVE_OK)
1322 			mtree->compute_sum |= F_SHA512;
1323 		else
1324 			mtree->keys &= ~F_SHA512;/* Not supported. */
1325 	}
1326 #endif
1327 }
1328 
1329 static void
1330 sum_update(struct mtree_writer *mtree, const void *buff, size_t n)
1331 {
1332 	if (mtree->compute_sum & F_CKSUM) {
1333 		/*
1334 		 * Compute a POSIX 1003.2 checksum
1335 		 */
1336 		const unsigned char *p;
1337 		size_t nn;
1338 
1339 		for (nn = n, p = buff; nn--; ++p)
1340 			COMPUTE_CRC(mtree->crc, *p);
1341 		mtree->crc_len += n;
1342 	}
1343 #ifdef ARCHIVE_HAS_MD5
1344 	if (mtree->compute_sum & F_MD5)
1345 		archive_md5_update(&mtree->md5ctx, buff, n);
1346 #endif
1347 #ifdef ARCHIVE_HAS_RMD160
1348 	if (mtree->compute_sum & F_RMD160)
1349 		archive_rmd160_update(&mtree->rmd160ctx, buff, n);
1350 #endif
1351 #ifdef ARCHIVE_HAS_SHA1
1352 	if (mtree->compute_sum & F_SHA1)
1353 		archive_sha1_update(&mtree->sha1ctx, buff, n);
1354 #endif
1355 #ifdef ARCHIVE_HAS_SHA256
1356 	if (mtree->compute_sum & F_SHA256)
1357 		archive_sha256_update(&mtree->sha256ctx, buff, n);
1358 #endif
1359 #ifdef ARCHIVE_HAS_SHA384
1360 	if (mtree->compute_sum & F_SHA384)
1361 		archive_sha384_update(&mtree->sha384ctx, buff, n);
1362 #endif
1363 #ifdef ARCHIVE_HAS_SHA512
1364 	if (mtree->compute_sum & F_SHA512)
1365 		archive_sha512_update(&mtree->sha512ctx, buff, n);
1366 #endif
1367 }
1368 
1369 static void
1370 sum_final(struct mtree_writer *mtree, struct mtree_entry *me)
1371 {
1372 
1373 	if (mtree->compute_sum & F_CKSUM) {
1374 		uint64_t len;
1375 		/* Include the length of the file. */
1376 		for (len = mtree->crc_len; len != 0; len >>= 8)
1377 			COMPUTE_CRC(mtree->crc, len & 0xff);
1378 		me->crc = ~mtree->crc;
1379 	}
1380 #ifdef ARCHIVE_HAS_MD5
1381 	if (mtree->compute_sum & F_MD5)
1382 		archive_md5_final(&mtree->md5ctx, me->buf_md5);
1383 #endif
1384 #ifdef ARCHIVE_HAS_RMD160
1385 	if (mtree->compute_sum & F_RMD160)
1386 		archive_rmd160_final(&mtree->rmd160ctx, me->buf_rmd160);
1387 #endif
1388 #ifdef ARCHIVE_HAS_SHA1
1389 	if (mtree->compute_sum & F_SHA1)
1390 		archive_sha1_final(&mtree->sha1ctx, me->buf_sha1);
1391 #endif
1392 #ifdef ARCHIVE_HAS_SHA256
1393 	if (mtree->compute_sum & F_SHA256)
1394 		archive_sha256_final(&mtree->sha256ctx, me->buf_sha256);
1395 #endif
1396 #ifdef ARCHIVE_HAS_SHA384
1397 	if (mtree->compute_sum & F_SHA384)
1398 		archive_sha384_final(&mtree->sha384ctx, me->buf_sha384);
1399 #endif
1400 #ifdef ARCHIVE_HAS_SHA512
1401 	if (mtree->compute_sum & F_SHA512)
1402 		archive_sha512_final(&mtree->sha512ctx, me->buf_sha512);
1403 #endif
1404 	/* Save what types of sum are computed. */
1405 	me->compute_sum = mtree->compute_sum;
1406 }
1407 
1408 #if defined(ARCHIVE_HAS_MD5) || defined(ARCHIVE_HAS_RMD160) || \
1409     defined(ARCHIVE_HAS_SHA1) || defined(ARCHIVE_HAS_SHA256) || \
1410     defined(ARCHIVE_HAS_SHA384) || defined(ARCHIVE_HAS_SHA512)
1411 static void
1412 strappend_bin(struct archive_string *s, const unsigned char *bin, int n)
1413 {
1414 	static const char hex[] = "0123456789abcdef";
1415 	int i;
1416 
1417 	for (i = 0; i < n; i++) {
1418 		archive_strappend_char(s, hex[bin[i] >> 4]);
1419 		archive_strappend_char(s, hex[bin[i] & 0x0f]);
1420 	}
1421 }
1422 #endif
1423 
1424 static void
1425 sum_write(struct archive_string *str, struct mtree_entry *me)
1426 {
1427 
1428 	if (me->compute_sum & F_CKSUM) {
1429 		archive_string_sprintf(str, " cksum=%ju",
1430 		    (uintmax_t)me->crc);
1431 	}
1432 #ifdef ARCHIVE_HAS_MD5
1433 	if (me->compute_sum & F_MD5) {
1434 		archive_strcat(str, " md5digest=");
1435 		strappend_bin(str, me->buf_md5, sizeof(me->buf_md5));
1436 	}
1437 #endif
1438 #ifdef ARCHIVE_HAS_RMD160
1439 	if (me->compute_sum & F_RMD160) {
1440 		archive_strcat(str, " rmd160digest=");
1441 		strappend_bin(str, me->buf_rmd160, sizeof(me->buf_rmd160));
1442 	}
1443 #endif
1444 #ifdef ARCHIVE_HAS_SHA1
1445 	if (me->compute_sum & F_SHA1) {
1446 		archive_strcat(str, " sha1digest=");
1447 		strappend_bin(str, me->buf_sha1, sizeof(me->buf_sha1));
1448 	}
1449 #endif
1450 #ifdef ARCHIVE_HAS_SHA256
1451 	if (me->compute_sum & F_SHA256) {
1452 		archive_strcat(str, " sha256digest=");
1453 		strappend_bin(str, me->buf_sha256, sizeof(me->buf_sha256));
1454 	}
1455 #endif
1456 #ifdef ARCHIVE_HAS_SHA384
1457 	if (me->compute_sum & F_SHA384) {
1458 		archive_strcat(str, " sha384digest=");
1459 		strappend_bin(str, me->buf_sha384, sizeof(me->buf_sha384));
1460 	}
1461 #endif
1462 #ifdef ARCHIVE_HAS_SHA512
1463 	if (me->compute_sum & F_SHA512) {
1464 		archive_strcat(str, " sha512digest=");
1465 		strappend_bin(str, me->buf_sha512, sizeof(me->buf_sha512));
1466 	}
1467 #endif
1468 }
1469