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