xref: /freebsd/contrib/libarchive/libarchive/archive_write_set_format_mtree.c (revision 185becb1e1bd2657c156f78aeb52edac05ba5fb5)
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 
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32 #include <errno.h>
33 #include <stdlib.h>
34 #include <string.h>
35 
36 #include "archive.h"
37 #include "archive_digest_private.h"
38 #include "archive_entry.h"
39 #include "archive_entry_private.h"
40 #include "archive_private.h"
41 #include "archive_rb.h"
42 #include "archive_string.h"
43 #include "archive_write_private.h"
44 
45 #define INDENTNAMELEN	15
46 #define MAXLINELEN	80
47 #define SET_KEYS	\
48 	(F_FLAGS | F_GID | F_GNAME | F_MODE | F_TYPE | F_UID | F_UNAME)
49 
50 struct attr_counter {
51 	struct attr_counter *prev;
52 	struct attr_counter *next;
53 	struct mtree_entry *m_entry;
54 	int count;
55 };
56 
57 struct attr_counter_set {
58 	struct attr_counter *uid_list;
59 	struct attr_counter *gid_list;
60 	struct attr_counter *mode_list;
61 	struct attr_counter *flags_list;
62 };
63 
64 struct mtree_chain {
65 	struct mtree_entry *first;
66 	struct mtree_entry **last;
67 };
68 
69 /*
70  * The Data only for a directory file.
71  */
72 struct dir_info {
73 	struct archive_rb_tree rbtree;
74 	struct mtree_chain children;
75 	struct mtree_entry *chnext;
76 	int virtual;
77 };
78 
79 /*
80  * The Data only for a regular file.
81  */
82 struct reg_info {
83 	int compute_sum;
84 	uint32_t crc;
85 	uint_least32_t mset_digest;
86 	struct ae_digest digest;
87 };
88 
89 struct mtree_entry {
90 	struct archive_rb_node rbnode;
91 	struct mtree_entry *next;
92 	struct mtree_entry *parent;
93 	struct dir_info *dir_info;
94 	struct reg_info *reg_info;
95 
96 	struct archive_string parentdir;
97 	struct archive_string basename;
98 	struct archive_string pathname;
99 	struct archive_string symlink;
100 	struct archive_string uname;
101 	struct archive_string gname;
102 	struct archive_string fflags_text;
103 	unsigned int nlink;
104 	mode_t filetype;
105 	mode_t mode;
106 	int64_t size;
107 	int64_t uid;
108 	int64_t gid;
109 	time_t mtime;
110 	long mtime_nsec;
111 	unsigned long fflags_set;
112 	unsigned long fflags_clear;
113 	dev_t rdevmajor;
114 	dev_t rdevminor;
115 	dev_t devmajor;
116 	dev_t devminor;
117 	int64_t ino;
118 };
119 
120 struct mtree {
121 	struct mtree_entry *mtree_entry;
122 	struct mtree_entry *root;
123 	struct mtree_entry *cur_dirent;
124 	struct archive_string cur_dirstr;
125 	struct mtree_chain file_list;
126 
127 	struct archive_string ebuf;
128 	struct archive_string buf;
129 	int first;
130 	uint64_t entry_bytes_remaining;
131 
132 	/*
133 	 * Set global value.
134 	 */
135 	struct {
136 		int		processing;
137 		mode_t		type;
138 		int		keys;
139 		int64_t		uid;
140 		int64_t		gid;
141 		mode_t		mode;
142 		unsigned long	fflags_set;
143 		unsigned long	fflags_clear;
144 	} set;
145 	struct attr_counter_set	acs;
146 	int classic;
147 	int depth;
148 
149 	/* check sum */
150 	int compute_sum;
151 	uint32_t crc;
152 	uint64_t crc_len;
153 #ifdef ARCHIVE_HAS_MD5
154 	archive_md5_ctx md5ctx;
155 #endif
156 #ifdef ARCHIVE_HAS_RMD160
157 	archive_rmd160_ctx rmd160ctx;
158 #endif
159 #ifdef ARCHIVE_HAS_SHA1
160 	archive_sha1_ctx sha1ctx;
161 #endif
162 #ifdef ARCHIVE_HAS_SHA256
163 	archive_sha256_ctx sha256ctx;
164 #endif
165 #ifdef ARCHIVE_HAS_SHA384
166 	archive_sha384_ctx sha384ctx;
167 #endif
168 #ifdef ARCHIVE_HAS_SHA512
169 	archive_sha512_ctx sha512ctx;
170 #endif
171 	/* Keyword options */
172 	int keys;
173 #define	F_CKSUM		0x00000001		/* checksum */
174 #define	F_DEV		0x00000002		/* device type */
175 #define	F_DONE		0x00000004		/* directory done */
176 #define	F_FLAGS		0x00000008		/* file flags */
177 #define	F_GID		0x00000010		/* gid */
178 #define	F_GNAME		0x00000020		/* group name */
179 #define	F_IGN		0x00000040		/* ignore */
180 #define	F_MAGIC		0x00000080		/* name has magic chars */
181 #define	F_MD5		0x00000100		/* MD5 digest */
182 #define	F_MODE		0x00000200		/* mode */
183 #define	F_NLINK		0x00000400		/* number of links */
184 #define	F_NOCHANGE 	0x00000800		/* If owner/mode "wrong", do
185 						 * not change */
186 #define	F_OPT		0x00001000		/* existence optional */
187 #define	F_RMD160 	0x00002000		/* RIPEMD160 digest */
188 #define	F_SHA1		0x00004000		/* SHA-1 digest */
189 #define	F_SIZE		0x00008000		/* size */
190 #define	F_SLINK		0x00010000		/* symbolic link */
191 #define	F_TAGS		0x00020000		/* tags */
192 #define	F_TIME		0x00040000		/* modification time */
193 #define	F_TYPE		0x00080000		/* file type */
194 #define	F_UID		0x00100000		/* uid */
195 #define	F_UNAME		0x00200000		/* user name */
196 #define	F_VISIT		0x00400000		/* file visited */
197 #define	F_SHA256	0x00800000		/* SHA-256 digest */
198 #define	F_SHA384	0x01000000		/* SHA-384 digest */
199 #define	F_SHA512	0x02000000		/* SHA-512 digest */
200 #define	F_INO		0x04000000		/* inode number */
201 #define	F_RESDEV	0x08000000		/* device ID on which the
202 						 * entry resides */
203 
204 	/* Options */
205 	int dironly;		/* If it is set, ignore all files except
206 				 * directory files, like mtree(8) -d option. */
207 	int indent;		/* If it is set, indent output data. */
208 	int output_global_set;	/* If it is set, use /set keyword to set
209 				 * global values. When generating mtree
210 				 * classic format, it is set by default. */
211 };
212 
213 #define DEFAULT_KEYS	(F_DEV | F_FLAGS | F_GID | F_GNAME | F_SLINK | F_MODE\
214 			 | F_NLINK | F_SIZE | F_TIME | F_TYPE | F_UID\
215 			 | F_UNAME)
216 #define attr_counter_set_reset	attr_counter_set_free
217 
218 static void attr_counter_free(struct attr_counter **);
219 static int attr_counter_inc(struct attr_counter **, struct attr_counter *,
220 	struct attr_counter *, struct mtree_entry *);
221 static struct attr_counter * attr_counter_new(struct mtree_entry *,
222 	struct attr_counter *);
223 static int attr_counter_set_collect(struct mtree *,
224 	struct mtree_entry *);
225 static void attr_counter_set_free(struct mtree *);
226 static int get_global_set_keys(struct mtree *, struct mtree_entry *);
227 static int mtree_entry_add_child_tail(struct mtree_entry *,
228 	struct mtree_entry *);
229 static int mtree_entry_create_virtual_dir(struct archive_write *, const char *,
230 	struct mtree_entry **);
231 static int mtree_entry_cmp_node(const struct archive_rb_node *,
232 	const struct archive_rb_node *);
233 static int mtree_entry_cmp_key(const struct archive_rb_node *, const void *);
234 static int mtree_entry_exchange_same_entry(struct archive_write *,
235     struct mtree_entry *, struct mtree_entry *);
236 static void mtree_entry_free(struct mtree_entry *);
237 static int mtree_entry_new(struct archive_write *, struct archive_entry *,
238 	struct mtree_entry **);
239 static void mtree_entry_register_free(struct mtree *);
240 static void mtree_entry_register_init(struct mtree *);
241 static int mtree_entry_setup_filenames(struct archive_write *,
242 	struct mtree_entry *, struct archive_entry *);
243 static int mtree_entry_tree_add(struct archive_write *, struct mtree_entry **);
244 static void sum_init(struct mtree *);
245 static void sum_update(struct mtree *, const void *, size_t);
246 static void sum_final(struct mtree *, struct reg_info *);
247 static void sum_write(struct archive_string *, struct reg_info *);
248 static int write_mtree_entry(struct archive_write *, struct mtree_entry *);
249 static int write_dot_dot_entry(struct archive_write *, struct mtree_entry *);
250 
251 #define	COMPUTE_CRC(var, ch)	(var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)]
252 static const uint32_t crctab[] = {
253 	0x0,
254 	0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
255 	0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
256 	0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
257 	0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
258 	0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
259 	0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
260 	0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
261 	0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
262 	0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
263 	0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
264 	0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
265 	0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
266 	0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
267 	0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
268 	0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
269 	0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
270 	0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
271 	0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
272 	0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
273 	0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
274 	0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
275 	0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
276 	0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
277 	0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
278 	0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
279 	0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
280 	0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
281 	0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
282 	0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
283 	0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
284 	0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
285 	0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
286 	0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
287 	0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
288 	0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
289 	0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
290 	0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
291 	0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
292 	0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
293 	0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
294 	0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
295 	0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
296 	0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
297 	0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
298 	0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
299 	0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
300 	0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
301 	0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
302 	0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
303 	0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
304 	0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
305 };
306 
307 static const unsigned char safe_char[256] = {
308 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
309 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
310 	/* !"$%&'()+,-./  EXCLUSION:0x20( ) 0x23(#) 0x2a(*) */
311 	0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* 20 - 2F */
312 	/* 0123456789:;<>  EXCLUSION:0x3d(=) 0x3f(?) */
313 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, /* 30 - 3F */
314 	/* @ABCDEFGHIJKLMNO */
315 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
316 	/* PQRSTUVWXYZ]^_ EXCLUSION:0x5b([) 0x5c(\)  */
317 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, /* 50 - 5F */
318 	/* `abcdefghijklmno */
319 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
320 	/* pqrstuvwxyz{|}~ */
321 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */
322 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
323 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
324 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
325 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
326 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
327 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
328 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
329 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
330 };
331 
332 static void
mtree_quote(struct archive_string * s,const char * str)333 mtree_quote(struct archive_string *s, const char *str)
334 {
335 	const char *start;
336 	char buf[4];
337 	unsigned char c;
338 
339 	for (start = str; *str != '\0'; ++str) {
340 		if (safe_char[*(const unsigned char *)str])
341 			continue;
342 		if (start != str)
343 			archive_strncat(s, start, str - start);
344 		c = (unsigned char)*str;
345 		buf[0] = '\\';
346 		buf[1] = (c / 64) + '0';
347 		buf[2] = (c / 8 % 8) + '0';
348 		buf[3] = (c % 8) + '0';
349 		archive_strncat(s, buf, 4);
350 		start = str + 1;
351 	}
352 
353 	if (start != str)
354 		archive_strncat(s, start, str - start);
355 }
356 
357 /*
358  * Indent a line as the mtree utility does so it is readable for people.
359  */
360 static void
mtree_indent(struct mtree * mtree)361 mtree_indent(struct mtree *mtree)
362 {
363 	int i, fn, nd, pd;
364 	const char *r, *s, *x;
365 
366 	if (mtree->classic) {
367 		if (mtree->indent) {
368 			nd = 0;
369 			pd = mtree->depth * 4;
370 		} else {
371 			nd = mtree->depth?4:0;
372 			pd = 0;
373 		}
374 	} else
375 		nd = pd = 0;
376 	fn = 1;
377 	s = r = mtree->ebuf.s;
378 	x = NULL;
379 	while (*r == ' ')
380 		r++;
381 	while ((r = strchr(r, ' ')) != NULL) {
382 		if (fn) {
383 			fn = 0;
384 			for (i = 0; i < nd + pd; i++)
385 				archive_strappend_char(&mtree->buf, ' ');
386 			archive_strncat(&mtree->buf, s, r - s);
387 			if (nd + (r -s) > INDENTNAMELEN) {
388 				archive_strncat(&mtree->buf, " \\\n", 3);
389 				for (i = 0; i < (INDENTNAMELEN + 1 + pd); i++)
390 					archive_strappend_char(&mtree->buf, ' ');
391 			} else {
392 				for (i = (int)(r -s + nd);
393 				    i < (INDENTNAMELEN + 1); i++)
394 					archive_strappend_char(&mtree->buf, ' ');
395 			}
396 			s = ++r;
397 			x = NULL;
398 			continue;
399 		}
400 		if (pd + (r - s) <= MAXLINELEN - 3 - INDENTNAMELEN)
401 			x = r++;
402 		else {
403 			if (x == NULL)
404 				x = r;
405 			archive_strncat(&mtree->buf, s, x - s);
406 			archive_strncat(&mtree->buf, " \\\n", 3);
407 			for (i = 0; i < (INDENTNAMELEN + 1 + pd); i++)
408 				archive_strappend_char(&mtree->buf, ' ');
409 			s = r = ++x;
410 			x = NULL;
411 		}
412 	}
413 	if (fn) {
414 		for (i = 0; i < nd + pd; i++)
415 			archive_strappend_char(&mtree->buf, ' ');
416 		archive_strcat(&mtree->buf, s);
417 		s += strlen(s);
418 	}
419 	if (x != NULL && pd + strlen(s) > MAXLINELEN - 3 - INDENTNAMELEN) {
420 		/* Last keyword is longer. */
421 		archive_strncat(&mtree->buf, s, x - s);
422 		archive_strncat(&mtree->buf, " \\\n", 3);
423 		for (i = 0; i < (INDENTNAMELEN + 1 + pd); i++)
424 			archive_strappend_char(&mtree->buf, ' ');
425 		s = ++x;
426 	}
427 	archive_strcat(&mtree->buf, s);
428 	archive_string_empty(&mtree->ebuf);
429 }
430 
431 /*
432  * Write /set keyword.
433  * Set the most used value of uid, gid, mode and fflags, which are
434  * collected by the attr_counter_set_collect() function.
435  */
436 static void
write_global(struct mtree * mtree)437 write_global(struct mtree *mtree)
438 {
439 	struct archive_string setstr;
440 	struct archive_string unsetstr;
441 	struct attr_counter_set *acs;
442 	int keys, oldkeys, effkeys;
443 
444 	archive_string_init(&setstr);
445 	archive_string_init(&unsetstr);
446 	keys = mtree->keys & SET_KEYS;
447 	oldkeys = mtree->set.keys;
448 	effkeys = keys;
449 	acs = &mtree->acs;
450 	if (mtree->set.processing) {
451 		/*
452 		 * Check if the global data needs updating.
453 		 */
454 		effkeys &= ~F_TYPE;
455 		if (acs->uid_list == NULL)
456 			effkeys &= ~(F_UNAME | F_UID);
457 		else if (oldkeys & (F_UNAME | F_UID)) {
458 			if (acs->uid_list->count < 2 ||
459 			    mtree->set.uid == acs->uid_list->m_entry->uid)
460 				effkeys &= ~(F_UNAME | F_UID);
461 		}
462 		if (acs->gid_list == NULL)
463 			effkeys &= ~(F_GNAME | F_GID);
464 		else if (oldkeys & (F_GNAME | F_GID)) {
465 			if (acs->gid_list->count < 2 ||
466 			    mtree->set.gid == acs->gid_list->m_entry->gid)
467 				effkeys &= ~(F_GNAME | F_GID);
468 		}
469 		if (acs->mode_list == NULL)
470 			effkeys &= ~F_MODE;
471 		else if (oldkeys & F_MODE) {
472 			if (acs->mode_list->count < 2 ||
473 			    mtree->set.mode == acs->mode_list->m_entry->mode)
474 				effkeys &= ~F_MODE;
475 		}
476 		if (acs->flags_list == NULL)
477 			effkeys &= ~F_FLAGS;
478 		else if ((oldkeys & F_FLAGS) != 0) {
479 			if (acs->flags_list->count < 2 ||
480 			    (acs->flags_list->m_entry->fflags_set ==
481 				mtree->set.fflags_set &&
482 			     acs->flags_list->m_entry->fflags_clear ==
483 				mtree->set.fflags_clear))
484 				effkeys &= ~F_FLAGS;
485 		}
486 	} else {
487 		if (acs->uid_list == NULL)
488 			keys &= ~(F_UNAME | F_UID);
489 		if (acs->gid_list == NULL)
490 			keys &= ~(F_GNAME | F_GID);
491 		if (acs->mode_list == NULL)
492 			keys &= ~F_MODE;
493 		if (acs->flags_list == NULL)
494 			keys &= ~F_FLAGS;
495 	}
496 	if ((keys & effkeys & F_TYPE) != 0) {
497 		if (mtree->dironly) {
498 			archive_strcat(&setstr, " type=dir");
499 			mtree->set.type = AE_IFDIR;
500 		} else {
501 			archive_strcat(&setstr, " type=file");
502 			mtree->set.type = AE_IFREG;
503 		}
504 	}
505 	if ((keys & effkeys & F_UNAME) != 0) {
506 		if (archive_strlen(&(acs->uid_list->m_entry->uname)) > 0) {
507 			archive_strcat(&setstr, " uname=");
508 			mtree_quote(&setstr, acs->uid_list->m_entry->uname.s);
509 		} else {
510 			keys &= ~F_UNAME;
511 			if ((oldkeys & F_UNAME) != 0)
512 				archive_strcat(&unsetstr, " uname");
513 		}
514 	}
515 	if ((keys & effkeys & F_UID) != 0) {
516 		mtree->set.uid = acs->uid_list->m_entry->uid;
517 		archive_string_sprintf(&setstr, " uid=%jd",
518 		    (intmax_t)mtree->set.uid);
519 	}
520 	if ((keys & effkeys & F_GNAME) != 0) {
521 		if (archive_strlen(&(acs->gid_list->m_entry->gname)) > 0) {
522 			archive_strcat(&setstr, " gname=");
523 			mtree_quote(&setstr, acs->gid_list->m_entry->gname.s);
524 		} else {
525 			keys &= ~F_GNAME;
526 			if ((oldkeys & F_GNAME) != 0)
527 				archive_strcat(&unsetstr, " gname");
528 		}
529 	}
530 	if ((keys & effkeys & F_GID) != 0) {
531 		mtree->set.gid = acs->gid_list->m_entry->gid;
532 		archive_string_sprintf(&setstr, " gid=%jd",
533 		    (intmax_t)mtree->set.gid);
534 	}
535 	if ((keys & effkeys & F_MODE) != 0) {
536 		mtree->set.mode = acs->mode_list->m_entry->mode;
537 		archive_string_sprintf(&setstr, " mode=%o",
538 		    (unsigned int)mtree->set.mode);
539 	}
540 	if ((keys & effkeys & F_FLAGS) != 0) {
541 		if (archive_strlen(
542 		    &(acs->flags_list->m_entry->fflags_text)) > 0) {
543 			archive_strcat(&setstr, " flags=");
544 			mtree_quote(&setstr,
545 			    acs->flags_list->m_entry->fflags_text.s);
546 			mtree->set.fflags_set =
547 			    acs->flags_list->m_entry->fflags_set;
548 			mtree->set.fflags_clear =
549 			    acs->flags_list->m_entry->fflags_clear;
550 		} else {
551 			keys &= ~F_FLAGS;
552 			if ((oldkeys & F_FLAGS) != 0)
553 				archive_strcat(&unsetstr, " flags");
554 		}
555 	}
556 	if (unsetstr.length > 0)
557 		archive_string_sprintf(&mtree->buf, "/unset%s\n", unsetstr.s);
558 	archive_string_free(&unsetstr);
559 	if (setstr.length > 0)
560 		archive_string_sprintf(&mtree->buf, "/set%s\n", setstr.s);
561 	archive_string_free(&setstr);
562 	mtree->set.keys = keys;
563 	mtree->set.processing = 1;
564 }
565 
566 static struct attr_counter *
attr_counter_new(struct mtree_entry * me,struct attr_counter * prev)567 attr_counter_new(struct mtree_entry *me, struct attr_counter *prev)
568 {
569 	struct attr_counter *ac;
570 
571 	ac = malloc(sizeof(*ac));
572 	if (ac != NULL) {
573 		ac->prev = prev;
574 		ac->next = NULL;
575 		ac->count = 1;
576 		ac->m_entry = me;
577 	}
578 	return (ac);
579 }
580 
581 static void
attr_counter_free(struct attr_counter ** top)582 attr_counter_free(struct attr_counter **top)
583 {
584 	struct attr_counter *ac, *tac;
585 
586 	if (*top == NULL)
587 		return;
588 	ac = *top;
589         while (ac != NULL) {
590 		tac = ac->next;
591 		free(ac);
592 		ac = tac;
593 	}
594 	*top = NULL;
595 }
596 
597 static int
attr_counter_inc(struct attr_counter ** top,struct attr_counter * ac,struct attr_counter * last,struct mtree_entry * me)598 attr_counter_inc(struct attr_counter **top, struct attr_counter *ac,
599     struct attr_counter *last, struct mtree_entry *me)
600 {
601 	struct attr_counter *pac;
602 
603 	if (ac != NULL) {
604 		ac->count++;
605 		if (*top == ac || ac->prev->count >= ac->count)
606 			return (0);
607 		for (pac = ac->prev; pac; pac = pac->prev) {
608 			if (pac->count >= ac->count)
609 				break;
610 		}
611 		ac->prev->next = ac->next;
612 		if (ac->next != NULL)
613 			ac->next->prev = ac->prev;
614 		if (pac != NULL) {
615 			ac->prev = pac;
616 			ac->next = pac->next;
617 			pac->next = ac;
618 			if (ac->next != NULL)
619 				ac->next->prev = ac;
620 		} else {
621 			ac->prev = NULL;
622 			ac->next = *top;
623 			*top = ac;
624 			ac->next->prev = ac;
625 		}
626 	} else if (last != NULL) {
627 		ac = attr_counter_new(me, last);
628 		if (ac == NULL)
629 			return (-1);
630 		last->next = ac;
631 	}
632 	return (0);
633 }
634 
635 /*
636  * Tabulate uid, gid, mode and fflags of a entry in order to be used for /set.
637  */
638 static int
attr_counter_set_collect(struct mtree * mtree,struct mtree_entry * me)639 attr_counter_set_collect(struct mtree *mtree, struct mtree_entry *me)
640 {
641 	struct attr_counter *ac, *last;
642 	struct attr_counter_set *acs = &mtree->acs;
643 	int keys = mtree->keys;
644 
645 	if (keys & (F_UNAME | F_UID)) {
646 		if (acs->uid_list == NULL) {
647 			acs->uid_list = attr_counter_new(me, NULL);
648 			if (acs->uid_list == NULL)
649 				return (-1);
650 		} else {
651 			last = NULL;
652 			for (ac = acs->uid_list; ac; ac = ac->next) {
653 				if (ac->m_entry->uid == me->uid)
654 					break;
655 				last = ac;
656 			}
657 			if (attr_counter_inc(&acs->uid_list, ac, last, me) < 0)
658 				return (-1);
659 		}
660 	}
661 	if (keys & (F_GNAME | F_GID)) {
662 		if (acs->gid_list == NULL) {
663 			acs->gid_list = attr_counter_new(me, NULL);
664 			if (acs->gid_list == NULL)
665 				return (-1);
666 		} else {
667 			last = NULL;
668 			for (ac = acs->gid_list; ac; ac = ac->next) {
669 				if (ac->m_entry->gid == me->gid)
670 					break;
671 				last = ac;
672 			}
673 			if (attr_counter_inc(&acs->gid_list, ac, last, me) < 0)
674 				return (-1);
675 		}
676 	}
677 	if (keys & F_MODE) {
678 		if (acs->mode_list == NULL) {
679 			acs->mode_list = attr_counter_new(me, NULL);
680 			if (acs->mode_list == NULL)
681 				return (-1);
682 		} else {
683 			last = NULL;
684 			for (ac = acs->mode_list; ac; ac = ac->next) {
685 				if (ac->m_entry->mode == me->mode)
686 					break;
687 				last = ac;
688 			}
689 			if (attr_counter_inc(&acs->mode_list, ac, last, me) < 0)
690 				return (-1);
691 		}
692 	}
693 	if (keys & F_FLAGS) {
694 		if (acs->flags_list == NULL) {
695 			acs->flags_list = attr_counter_new(me, NULL);
696 			if (acs->flags_list == NULL)
697 				return (-1);
698 		} else {
699 			last = NULL;
700 			for (ac = acs->flags_list; ac; ac = ac->next) {
701 				if (ac->m_entry->fflags_set == me->fflags_set &&
702 				    ac->m_entry->fflags_clear ==
703 							me->fflags_clear)
704 					break;
705 				last = ac;
706 			}
707 			if (attr_counter_inc(&acs->flags_list, ac, last, me) < 0)
708 				return (-1);
709 		}
710 	}
711 
712 	return (0);
713 }
714 
715 static void
attr_counter_set_free(struct mtree * mtree)716 attr_counter_set_free(struct mtree *mtree)
717 {
718 	struct attr_counter_set *acs = &mtree->acs;
719 
720 	attr_counter_free(&acs->uid_list);
721 	attr_counter_free(&acs->gid_list);
722 	attr_counter_free(&acs->mode_list);
723 	attr_counter_free(&acs->flags_list);
724 }
725 
726 static int
get_global_set_keys(struct mtree * mtree,struct mtree_entry * me)727 get_global_set_keys(struct mtree *mtree, struct mtree_entry *me)
728 {
729 	int keys;
730 
731 	keys = mtree->keys;
732 
733 	/*
734 	 * If a keyword has been set by /set, we do not need to
735 	 * output it.
736 	 */
737 	if (mtree->set.keys == 0)
738 		return (keys);/* /set is not used. */
739 
740 	if ((mtree->set.keys & (F_GNAME | F_GID)) != 0 &&
741 	     mtree->set.gid == me->gid)
742 		keys &= ~(F_GNAME | F_GID);
743 	if ((mtree->set.keys & (F_UNAME | F_UID)) != 0 &&
744 	     mtree->set.uid == me->uid)
745 		keys &= ~(F_UNAME | F_UID);
746 	if (mtree->set.keys & F_FLAGS) {
747 		if (mtree->set.fflags_set == me->fflags_set &&
748 		    mtree->set.fflags_clear == me->fflags_clear)
749 			keys &= ~F_FLAGS;
750 	}
751 	if ((mtree->set.keys & F_MODE) != 0 && mtree->set.mode == me->mode)
752 		keys &= ~F_MODE;
753 
754 	switch (me->filetype) {
755 	case AE_IFLNK: case AE_IFSOCK: case AE_IFCHR:
756 	case AE_IFBLK: case AE_IFIFO:
757 		break;
758 	case AE_IFDIR:
759 		if ((mtree->set.keys & F_TYPE) != 0 &&
760 		    mtree->set.type == AE_IFDIR)
761 			keys &= ~F_TYPE;
762 		break;
763 	case AE_IFREG:
764 	default:	/* Handle unknown file types as regular files. */
765 		if ((mtree->set.keys & F_TYPE) != 0 &&
766 		    mtree->set.type == AE_IFREG)
767 			keys &= ~F_TYPE;
768 		break;
769 	}
770 
771 	return (keys);
772 }
773 
774 static int
mtree_entry_new(struct archive_write * a,struct archive_entry * entry,struct mtree_entry ** m_entry)775 mtree_entry_new(struct archive_write *a, struct archive_entry *entry,
776     struct mtree_entry **m_entry)
777 {
778 	struct mtree_entry *me;
779 	const char *s;
780 	int r;
781 	static const struct archive_rb_tree_ops rb_ops = {
782 		mtree_entry_cmp_node, mtree_entry_cmp_key
783 	};
784 
785 	me = calloc(1, sizeof(*me));
786 	if (me == NULL) {
787 		archive_set_error(&a->archive, ENOMEM,
788 		    "Can't allocate memory for a mtree entry");
789 		*m_entry = NULL;
790 		return (ARCHIVE_FATAL);
791 	}
792 
793 	r = mtree_entry_setup_filenames(a, me, entry);
794 	if (r < ARCHIVE_WARN) {
795 		mtree_entry_free(me);
796 		*m_entry = NULL;
797 		return (r);
798 	}
799 
800 	if ((s = archive_entry_symlink(entry)) != NULL)
801 		archive_strcpy(&me->symlink, s);
802 	me->nlink = archive_entry_nlink(entry);
803 	me->filetype = archive_entry_filetype(entry);
804 	if (me->filetype == AE_IFLNK && me->symlink.s == NULL)
805 		archive_strcpy(&me->symlink, "");
806 	me->mode = archive_entry_mode(entry) & 07777;
807 	me->uid = archive_entry_uid(entry);
808 	me->gid = archive_entry_gid(entry);
809 	if ((s = archive_entry_uname(entry)) != NULL)
810 		archive_strcpy(&me->uname, s);
811 	if ((s = archive_entry_gname(entry)) != NULL)
812 		archive_strcpy(&me->gname, s);
813 	if ((s = archive_entry_fflags_text(entry)) != NULL)
814 		archive_strcpy(&me->fflags_text, s);
815 	archive_entry_fflags(entry, &me->fflags_set, &me->fflags_clear);
816 	me->mtime = archive_entry_mtime(entry);
817 	me->mtime_nsec = archive_entry_mtime_nsec(entry);
818 	me->rdevmajor = archive_entry_rdevmajor(entry);
819 	me->rdevminor = archive_entry_rdevminor(entry);
820 	me->devmajor = archive_entry_devmajor(entry);
821 	me->devminor = archive_entry_devminor(entry);
822 	me->ino = archive_entry_ino(entry);
823 	me->size = archive_entry_size(entry);
824 	if (me->filetype == AE_IFDIR) {
825 		me->dir_info = calloc(1, sizeof(*me->dir_info));
826 		if (me->dir_info == NULL) {
827 			mtree_entry_free(me);
828 			archive_set_error(&a->archive, ENOMEM,
829 			    "Can't allocate memory for a mtree entry");
830 			*m_entry = NULL;
831 			return (ARCHIVE_FATAL);
832 		}
833 		__archive_rb_tree_init(&me->dir_info->rbtree, &rb_ops);
834 		me->dir_info->children.first = NULL;
835 		me->dir_info->children.last = &(me->dir_info->children.first);
836 		me->dir_info->chnext = NULL;
837 	} else if (me->filetype == AE_IFREG) {
838 		me->reg_info = calloc(1, sizeof(*me->reg_info));
839 		if (me->reg_info == NULL) {
840 			mtree_entry_free(me);
841 			archive_set_error(&a->archive, ENOMEM,
842 			    "Can't allocate memory for a mtree entry");
843 			*m_entry = NULL;
844 			return (ARCHIVE_FATAL);
845 		}
846 		me->reg_info->compute_sum = 0;
847 	}
848 
849 	*m_entry = me;
850 	return (ARCHIVE_OK);
851 }
852 
853 static void
mtree_entry_free(struct mtree_entry * me)854 mtree_entry_free(struct mtree_entry *me)
855 {
856 	archive_string_free(&me->parentdir);
857 	archive_string_free(&me->basename);
858 	archive_string_free(&me->pathname);
859 	archive_string_free(&me->symlink);
860 	archive_string_free(&me->uname);
861 	archive_string_free(&me->gname);
862 	archive_string_free(&me->fflags_text);
863 	free(me->dir_info);
864 	free(me->reg_info);
865 	free(me);
866 }
867 
868 static void
mtree_copy_ae_digests(struct reg_info * reg,struct archive_entry * entry,int compute_sum)869 mtree_copy_ae_digests(struct reg_info *reg, struct archive_entry *entry, int compute_sum)
870 {
871 	reg->compute_sum = compute_sum;
872 	reg->mset_digest = entry->mset_digest;
873 
874 	if ((reg->compute_sum & F_MD5)
875 		&& (reg->mset_digest & AE_MSET_DIGEST_MD5)) {
876 
877 		memcpy(&reg->digest.md5, entry->digest.md5,
878 			sizeof(reg->digest.md5));
879 	}
880 	if ((reg->compute_sum & F_RMD160)
881 		&& (reg->mset_digest & AE_MSET_DIGEST_RMD160)) {
882 
883 		memcpy(&reg->digest.rmd160, entry->digest.rmd160,
884 			sizeof(reg->digest.rmd160));
885 	}
886 	if ((reg->compute_sum & F_SHA1)
887 		&& (reg->mset_digest & AE_MSET_DIGEST_SHA1)) {
888 
889 		memcpy(&reg->digest.sha1, entry->digest.sha1,
890 			sizeof(reg->digest.sha1));
891 	}
892 	if ((reg->compute_sum & F_SHA256)
893 		&& (reg->mset_digest & AE_MSET_DIGEST_SHA256)) {
894 
895 		memcpy(&reg->digest.sha256, entry->digest.sha256,
896 			sizeof(reg->digest.sha256));
897 	}
898 	if ((reg->compute_sum & F_SHA384)
899 		&& (reg->mset_digest & AE_MSET_DIGEST_SHA384)) {
900 
901 		memcpy(&reg->digest.sha384, entry->digest.sha384,
902 			sizeof(reg->digest.sha384));
903 	}
904 	if ((reg->compute_sum & F_SHA512)
905 		&& (reg->mset_digest & AE_MSET_DIGEST_SHA512)) {
906 
907 		memcpy(&reg->digest.sha512, entry->digest.sha512,
908 			sizeof(reg->digest.sha512));
909 	}
910 }
911 
912 static int
archive_write_mtree_header(struct archive_write * a,struct archive_entry * entry)913 archive_write_mtree_header(struct archive_write *a,
914     struct archive_entry *entry)
915 {
916 	struct mtree *mtree = a->format_data;
917 	struct mtree_entry *mtree_entry;
918 	int r, r2;
919 
920 	if (mtree->first) {
921 		mtree->first = 0;
922 		archive_strcat(&mtree->buf, "#mtree\n");
923 		if ((mtree->keys & SET_KEYS) == 0)
924 			mtree->output_global_set = 0;/* Disabled. */
925 	}
926 
927 	mtree->entry_bytes_remaining = archive_entry_size(entry);
928 
929 	/* While directory only mode, we do not handle non directory files. */
930 	if (mtree->dironly && archive_entry_filetype(entry) != AE_IFDIR)
931 		return (ARCHIVE_OK);
932 
933 	r2 = mtree_entry_new(a, entry, &mtree_entry);
934 	if (r2 < ARCHIVE_WARN)
935 		return (r2);
936 	r = mtree_entry_tree_add(a, &mtree_entry);
937 	if (r < ARCHIVE_WARN) {
938 		mtree_entry_free(mtree_entry);
939 		return (r);
940 	}
941 	mtree->mtree_entry = mtree_entry;
942 
943 	/* If the current file is a regular file, we have to
944 	 * compute the sum of its content.
945 	 * Initialize a bunch of checksum context. */
946 	if (mtree_entry->reg_info) {
947 		sum_init(mtree);
948 		/* honor archive_entry_set_digest() calls. These values will be
949 		 * overwritten if archive_write_mtree_data() is called */
950 		mtree_copy_ae_digests(mtree_entry->reg_info, entry, mtree->compute_sum);
951 	}
952 
953 	return (r2);
954 }
955 
956 static int
write_mtree_entry(struct archive_write * a,struct mtree_entry * me)957 write_mtree_entry(struct archive_write *a, struct mtree_entry *me)
958 {
959 	struct mtree *mtree = a->format_data;
960 	struct archive_string *str;
961 	int keys, ret;
962 
963 	if (me->dir_info) {
964 		if (mtree->classic) {
965 			/*
966 			 * Output a comment line to describe the full
967 			 * pathname of the entry as mtree utility does
968 			 * while generating classic format.
969 			 */
970 			if (!mtree->dironly)
971 				archive_strappend_char(&mtree->buf, '\n');
972 			if (me->parentdir.s)
973 				archive_string_sprintf(&mtree->buf,
974 				    "# %s/%s\n",
975 				    me->parentdir.s, me->basename.s);
976 			else
977 				archive_string_sprintf(&mtree->buf,
978 				    "# %s\n",
979 				    me->basename.s);
980 		}
981 		if (mtree->output_global_set)
982 			write_global(mtree);
983 	}
984 	archive_string_empty(&mtree->ebuf);
985 	str = (mtree->indent || mtree->classic)? &mtree->ebuf : &mtree->buf;
986 
987 	if (!mtree->classic && me->parentdir.s) {
988 		/*
989 		 * If generating format is not classic one(v1), output
990 		 * a full pathname.
991 		 */
992 		mtree_quote(str, me->parentdir.s);
993 		if (strcmp(me->basename.s, ".") != 0)
994 			archive_strappend_char(str, '/');
995 	}
996 	mtree_quote(str, me->basename.s);
997 
998 	keys = get_global_set_keys(mtree, me);
999 	if ((keys & F_NLINK) != 0 &&
1000 	    me->nlink != 1 && me->filetype != AE_IFDIR)
1001 		archive_string_sprintf(str, " nlink=%u", me->nlink);
1002 
1003 	if ((keys & F_GNAME) != 0 && archive_strlen(&me->gname) > 0) {
1004 		archive_strcat(str, " gname=");
1005 		mtree_quote(str, me->gname.s);
1006 	}
1007 	if ((keys & F_UNAME) != 0 && archive_strlen(&me->uname) > 0) {
1008 		archive_strcat(str, " uname=");
1009 		mtree_quote(str, me->uname.s);
1010 	}
1011 	if ((keys & F_FLAGS) != 0) {
1012 		if (archive_strlen(&me->fflags_text) > 0) {
1013 			archive_strcat(str, " flags=");
1014 			mtree_quote(str, me->fflags_text.s);
1015 		} else if (mtree->set.processing &&
1016 		    (mtree->set.keys & F_FLAGS) != 0)
1017 			/* Overwrite the global parameter. */
1018 			archive_strcat(str, " flags=none");
1019 	}
1020 	if ((keys & F_TIME) != 0)
1021 		archive_string_sprintf(str, " time=%jd.%jd",
1022 		    (intmax_t)me->mtime, (intmax_t)me->mtime_nsec);
1023 	if ((keys & F_MODE) != 0)
1024 		archive_string_sprintf(str, " mode=%o", (unsigned int)me->mode);
1025 	if ((keys & F_GID) != 0)
1026 		archive_string_sprintf(str, " gid=%jd", (intmax_t)me->gid);
1027 	if ((keys & F_UID) != 0)
1028 		archive_string_sprintf(str, " uid=%jd", (intmax_t)me->uid);
1029 
1030 	if ((keys & F_INO) != 0)
1031 		archive_string_sprintf(str, " inode=%jd", (intmax_t)me->ino);
1032 	if ((keys & F_RESDEV) != 0) {
1033 		archive_string_sprintf(str,
1034 		    " resdevice=native,%ju,%ju",
1035 		    (uintmax_t)me->devmajor,
1036 		    (uintmax_t)me->devminor);
1037 	}
1038 
1039 	switch (me->filetype) {
1040 	case AE_IFLNK:
1041 		if ((keys & F_TYPE) != 0)
1042 			archive_strcat(str, " type=link");
1043 		if ((keys & F_SLINK) != 0) {
1044 			archive_strcat(str, " link=");
1045 			mtree_quote(str, me->symlink.s);
1046 		}
1047 		break;
1048 	case AE_IFSOCK:
1049 		if ((keys & F_TYPE) != 0)
1050 			archive_strcat(str, " type=socket");
1051 		break;
1052 	case AE_IFCHR:
1053 		if ((keys & F_TYPE) != 0)
1054 			archive_strcat(str, " type=char");
1055 		if ((keys & F_DEV) != 0) {
1056 			archive_string_sprintf(str,
1057 			    " device=native,%ju,%ju",
1058 			    (uintmax_t)me->rdevmajor,
1059 			    (uintmax_t)me->rdevminor);
1060 		}
1061 		break;
1062 	case AE_IFBLK:
1063 		if ((keys & F_TYPE) != 0)
1064 			archive_strcat(str, " type=block");
1065 		if ((keys & F_DEV) != 0) {
1066 			archive_string_sprintf(str,
1067 			    " device=native,%ju,%ju",
1068 			    (uintmax_t)me->rdevmajor,
1069 			    (uintmax_t)me->rdevminor);
1070 		}
1071 		break;
1072 	case AE_IFDIR:
1073 		if ((keys & F_TYPE) != 0)
1074 			archive_strcat(str, " type=dir");
1075 		break;
1076 	case AE_IFIFO:
1077 		if ((keys & F_TYPE) != 0)
1078 			archive_strcat(str, " type=fifo");
1079 		break;
1080 	case AE_IFREG:
1081 	default:	/* Handle unknown file types as regular files. */
1082 		if ((keys & F_TYPE) != 0)
1083 			archive_strcat(str, " type=file");
1084 		if ((keys & F_SIZE) != 0)
1085 			archive_string_sprintf(str, " size=%jd",
1086 			    (intmax_t)me->size);
1087 		break;
1088 	}
1089 
1090 	/* Write a bunch of sum. */
1091 	if (me->reg_info)
1092 		sum_write(str, me->reg_info);
1093 
1094 	archive_strappend_char(str, '\n');
1095 	if (mtree->indent || mtree->classic)
1096 		mtree_indent(mtree);
1097 
1098 	if (mtree->buf.length > 32768) {
1099 		ret = __archive_write_output(
1100 			a, mtree->buf.s, mtree->buf.length);
1101 		archive_string_empty(&mtree->buf);
1102 	} else
1103 		ret = ARCHIVE_OK;
1104 	return (ret);
1105 }
1106 
1107 static int
write_dot_dot_entry(struct archive_write * a,struct mtree_entry * n)1108 write_dot_dot_entry(struct archive_write *a, struct mtree_entry *n)
1109 {
1110 	struct mtree *mtree = a->format_data;
1111 	int ret;
1112 
1113 	if (n->parentdir.s) {
1114 		if (mtree->indent) {
1115 			int i, pd = mtree->depth * 4;
1116 			for (i = 0; i < pd; i++)
1117 				archive_strappend_char(&mtree->buf, ' ');
1118 		}
1119 		archive_string_sprintf(&mtree->buf, "# %s/%s\n",
1120 			n->parentdir.s, n->basename.s);
1121 	}
1122 
1123 	if (mtree->indent) {
1124 		archive_string_empty(&mtree->ebuf);
1125 		archive_strncat(&mtree->ebuf, "..\n\n", (mtree->dironly)?3:4);
1126 		mtree_indent(mtree);
1127 	} else
1128 		archive_strncat(&mtree->buf, "..\n\n", (mtree->dironly)?3:4);
1129 
1130 	if (mtree->buf.length > 32768) {
1131 		ret = __archive_write_output(
1132 			a, mtree->buf.s, mtree->buf.length);
1133 		archive_string_empty(&mtree->buf);
1134 	} else
1135 		ret = ARCHIVE_OK;
1136 	return (ret);
1137 }
1138 
1139 /*
1140  * Write mtree entries saved at attr_counter_set_collect() function.
1141  */
1142 static int
write_mtree_entry_tree(struct archive_write * a)1143 write_mtree_entry_tree(struct archive_write *a)
1144 {
1145 	struct mtree *mtree = a->format_data;
1146 	struct mtree_entry *np = mtree->root;
1147 	struct archive_rb_node *n;
1148 	int ret;
1149 
1150 	do {
1151 		if (np->dir_info == NULL)
1152 			break;
1153 		if (mtree->output_global_set) {
1154 			/*
1155 			 * Collect attribute information to know which value
1156 			 * is frequently used among the children.
1157 			 */
1158 			attr_counter_set_reset(mtree);
1159 			ARCHIVE_RB_TREE_FOREACH(n, &(np->dir_info->rbtree)) {
1160 				struct mtree_entry *e = (struct mtree_entry *)n;
1161 				if (attr_counter_set_collect(mtree, e) < 0) {
1162 					archive_set_error(&a->archive, ENOMEM,
1163 					    "Can't allocate memory");
1164 					return (ARCHIVE_FATAL);
1165 				}
1166 			}
1167 		}
1168 		if (!np->dir_info->virtual || mtree->classic) {
1169 			ret = write_mtree_entry(a, np);
1170 			if (ret != ARCHIVE_OK)
1171 				return (ARCHIVE_FATAL);
1172 		} else {
1173 			/* Whenever output_global_set is enabled
1174 			 * output global value(/set keywords)
1175 			 * even if the directory entry is not allowed
1176 			 * to be written because the global values
1177 			 * can be used for the children. */
1178 			if (mtree->output_global_set)
1179 				write_global(mtree);
1180 		}
1181 		/*
1182 		 * Output the attribute of all files except directory files.
1183 		 */
1184 		mtree->depth++;
1185 		ARCHIVE_RB_TREE_FOREACH(n, &(np->dir_info->rbtree)) {
1186 			struct mtree_entry *e = (struct mtree_entry *)n;
1187 
1188 			if (e->dir_info)
1189 				mtree_entry_add_child_tail(np, e);
1190 			else {
1191 				ret = write_mtree_entry(a, e);
1192 				if (ret != ARCHIVE_OK)
1193 					return (ARCHIVE_FATAL);
1194 			}
1195 		}
1196 		mtree->depth--;
1197 
1198 		if (np->dir_info->children.first != NULL) {
1199 			/*
1200 			 * Descend the tree.
1201 			 */
1202 			np = np->dir_info->children.first;
1203 			if (mtree->indent)
1204 				mtree->depth++;
1205 			continue;
1206 		} else if (mtree->classic) {
1207 			/*
1208 			 * While printing mtree classic, if there are not
1209 			 * any directory files(except "." and "..") in the
1210 			 * directory, output two dots ".." as returning
1211 			 * the parent directory.
1212 			 */
1213 			ret = write_dot_dot_entry(a, np);
1214 			if (ret != ARCHIVE_OK)
1215 				return (ARCHIVE_FATAL);
1216 		}
1217 
1218 		while (np != np->parent) {
1219 			if (np->dir_info->chnext == NULL) {
1220 				/*
1221 				 * Ascend the tree; go back to the parent.
1222 				 */
1223 				if (mtree->indent)
1224 					mtree->depth--;
1225 				if (mtree->classic) {
1226 					ret = write_dot_dot_entry(a,
1227 						np->parent);
1228 					if (ret != ARCHIVE_OK)
1229 						return (ARCHIVE_FATAL);
1230 				}
1231 				np = np->parent;
1232 			} else {
1233 				/*
1234 				 * Switch to next mtree entry in the directory.
1235 				 */
1236 				np = np->dir_info->chnext;
1237 				break;
1238 			}
1239 		}
1240 	} while (np != np->parent);
1241 
1242 	return (ARCHIVE_OK);
1243 }
1244 
1245 static int
archive_write_mtree_finish_entry(struct archive_write * a)1246 archive_write_mtree_finish_entry(struct archive_write *a)
1247 {
1248 	struct mtree *mtree = a->format_data;
1249 	struct mtree_entry *me;
1250 
1251 	if ((me = mtree->mtree_entry) == NULL)
1252 		return (ARCHIVE_OK);
1253 	mtree->mtree_entry = NULL;
1254 
1255 	if (me->reg_info)
1256 		sum_final(mtree, me->reg_info);
1257 
1258 	return (ARCHIVE_OK);
1259 }
1260 
1261 static int
archive_write_mtree_close(struct archive_write * a)1262 archive_write_mtree_close(struct archive_write *a)
1263 {
1264 	struct mtree *mtree = a->format_data;
1265 	int ret;
1266 
1267 	if (mtree->root != NULL) {
1268 		ret = write_mtree_entry_tree(a);
1269 		if (ret != ARCHIVE_OK)
1270 			return (ARCHIVE_FATAL);
1271 	}
1272 
1273 	archive_write_set_bytes_in_last_block(&a->archive, 1);
1274 
1275 	return __archive_write_output(a, mtree->buf.s, mtree->buf.length);
1276 }
1277 
1278 static ssize_t
archive_write_mtree_data(struct archive_write * a,const void * buff,size_t n)1279 archive_write_mtree_data(struct archive_write *a, const void *buff, size_t n)
1280 {
1281 	struct mtree *mtree = a->format_data;
1282 
1283 	if (n > mtree->entry_bytes_remaining)
1284 		n = (size_t)mtree->entry_bytes_remaining;
1285 	mtree->entry_bytes_remaining -= n;
1286 
1287 	/* We don't need to compute a regular file sum */
1288 	if (mtree->mtree_entry == NULL)
1289 		return (n);
1290 
1291 	if (mtree->mtree_entry->filetype == AE_IFREG)
1292 		sum_update(mtree, buff, n);
1293 
1294 	return (n);
1295 }
1296 
1297 static int
archive_write_mtree_free(struct archive_write * a)1298 archive_write_mtree_free(struct archive_write *a)
1299 {
1300 	struct mtree *mtree = a->format_data;
1301 
1302 	if (mtree == NULL)
1303 		return (ARCHIVE_OK);
1304 
1305 	/* Make sure we do not leave any entries. */
1306 	mtree_entry_register_free(mtree);
1307 	archive_string_free(&mtree->cur_dirstr);
1308 	archive_string_free(&mtree->ebuf);
1309 	archive_string_free(&mtree->buf);
1310 	attr_counter_set_free(mtree);
1311 	free(mtree);
1312 	a->format_data = NULL;
1313 	return (ARCHIVE_OK);
1314 }
1315 
1316 static int
archive_write_mtree_options(struct archive_write * a,const char * key,const char * value)1317 archive_write_mtree_options(struct archive_write *a, const char *key,
1318     const char *value)
1319 {
1320 	struct mtree *mtree = a->format_data;
1321 	int keybit = 0;
1322 
1323 	switch (key[0]) {
1324 	case 'a':
1325 		if (strcmp(key, "all") == 0)
1326 			keybit = ~0;
1327 		break;
1328 	case 'c':
1329 		if (strcmp(key, "cksum") == 0)
1330 			keybit = F_CKSUM;
1331 		break;
1332 	case 'd':
1333 		if (strcmp(key, "device") == 0)
1334 			keybit = F_DEV;
1335 		else if (strcmp(key, "dironly") == 0) {
1336 			mtree->dironly = (value != NULL)? 1: 0;
1337 			return (ARCHIVE_OK);
1338 		}
1339 		break;
1340 	case 'f':
1341 		if (strcmp(key, "flags") == 0)
1342 			keybit = F_FLAGS;
1343 		break;
1344 	case 'g':
1345 		if (strcmp(key, "gid") == 0)
1346 			keybit = F_GID;
1347 		else if (strcmp(key, "gname") == 0)
1348 			keybit = F_GNAME;
1349 		break;
1350 	case 'i':
1351 		if (strcmp(key, "indent") == 0) {
1352 			mtree->indent = (value != NULL)? 1: 0;
1353 			return (ARCHIVE_OK);
1354 		} else if (strcmp(key, "inode") == 0) {
1355 			keybit = F_INO;
1356 		}
1357 		break;
1358 	case 'l':
1359 		if (strcmp(key, "link") == 0)
1360 			keybit = F_SLINK;
1361 		break;
1362 	case 'm':
1363 		if (strcmp(key, "md5") == 0 ||
1364 		    strcmp(key, "md5digest") == 0)
1365 			keybit = F_MD5;
1366 		if (strcmp(key, "mode") == 0)
1367 			keybit = F_MODE;
1368 		break;
1369 	case 'n':
1370 		if (strcmp(key, "nlink") == 0)
1371 			keybit = F_NLINK;
1372 		break;
1373 	case 'r':
1374 		if (strcmp(key, "resdevice") == 0) {
1375 			keybit = F_RESDEV;
1376 		} else if (strcmp(key, "ripemd160digest") == 0 ||
1377 		    strcmp(key, "rmd160") == 0 ||
1378 		    strcmp(key, "rmd160digest") == 0)
1379 			keybit = F_RMD160;
1380 		break;
1381 	case 's':
1382 		if (strcmp(key, "sha1") == 0 ||
1383 		    strcmp(key, "sha1digest") == 0)
1384 			keybit = F_SHA1;
1385 		if (strcmp(key, "sha256") == 0 ||
1386 		    strcmp(key, "sha256digest") == 0)
1387 			keybit = F_SHA256;
1388 		if (strcmp(key, "sha384") == 0 ||
1389 		    strcmp(key, "sha384digest") == 0)
1390 			keybit = F_SHA384;
1391 		if (strcmp(key, "sha512") == 0 ||
1392 		    strcmp(key, "sha512digest") == 0)
1393 			keybit = F_SHA512;
1394 		if (strcmp(key, "size") == 0)
1395 			keybit = F_SIZE;
1396 		break;
1397 	case 't':
1398 		if (strcmp(key, "time") == 0)
1399 			keybit = F_TIME;
1400 		else if (strcmp(key, "type") == 0)
1401 			keybit = F_TYPE;
1402 		break;
1403 	case 'u':
1404 		if (strcmp(key, "uid") == 0)
1405 			keybit = F_UID;
1406 		else if (strcmp(key, "uname") == 0)
1407 			keybit = F_UNAME;
1408 		else if (strcmp(key, "use-set") == 0) {
1409 			mtree->output_global_set = (value != NULL)? 1: 0;
1410 			return (ARCHIVE_OK);
1411 		}
1412 		break;
1413 	}
1414 	if (keybit != 0) {
1415 		if (value != NULL)
1416 			mtree->keys |= keybit;
1417 		else
1418 			mtree->keys &= ~keybit;
1419 		return (ARCHIVE_OK);
1420 	}
1421 
1422 	/* Note: The "warn" return is just to inform the options
1423 	 * supervisor that we didn't handle it.  It will generate
1424 	 * a suitable error if no one used this option. */
1425 	return (ARCHIVE_WARN);
1426 }
1427 
1428 static int
archive_write_set_format_mtree_default(struct archive * _a,const char * fn)1429 archive_write_set_format_mtree_default(struct archive *_a, const char *fn)
1430 {
1431 	struct archive_write *a = (struct archive_write *)_a;
1432 	struct mtree *mtree;
1433 
1434 	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, fn);
1435 
1436 	(void)__archive_write_unregister_format(a);
1437 
1438 	if ((mtree = calloc(1, sizeof(*mtree))) == NULL) {
1439 		archive_set_error(&a->archive, ENOMEM,
1440 		    "Can't allocate mtree data");
1441 		return (ARCHIVE_FATAL);
1442 	}
1443 
1444 	mtree->mtree_entry = NULL;
1445 	mtree->first = 1;
1446 	memset(&(mtree->set), 0, sizeof(mtree->set));
1447 	mtree->keys = DEFAULT_KEYS;
1448 	mtree->dironly = 0;
1449 	mtree->indent = 0;
1450 	archive_string_init(&mtree->ebuf);
1451 	archive_string_init(&mtree->buf);
1452 	mtree_entry_register_init(mtree);
1453 	a->format_data = mtree;
1454 	a->format_free = archive_write_mtree_free;
1455 	a->format_name = "mtree";
1456 	a->format_options = archive_write_mtree_options;
1457 	a->format_write_header = archive_write_mtree_header;
1458 	a->format_close = archive_write_mtree_close;
1459 	a->format_write_data = archive_write_mtree_data;
1460 	a->format_finish_entry = archive_write_mtree_finish_entry;
1461 	a->archive.archive_format = ARCHIVE_FORMAT_MTREE;
1462 	a->archive.archive_format_name = "mtree";
1463 
1464 	return (ARCHIVE_OK);
1465 }
1466 
1467 int
archive_write_set_format_mtree(struct archive * _a)1468 archive_write_set_format_mtree(struct archive *_a)
1469 {
1470 	return archive_write_set_format_mtree_default(_a,
1471 		"archive_write_set_format_mtree");
1472 }
1473 
1474 int
archive_write_set_format_mtree_classic(struct archive * _a)1475 archive_write_set_format_mtree_classic(struct archive *_a)
1476 {
1477 	int r;
1478 
1479 	r = archive_write_set_format_mtree_default(_a,
1480 		"archive_write_set_format_mtree_classic");
1481 	if (r == ARCHIVE_OK) {
1482 		struct archive_write *a = (struct archive_write *)_a;
1483 		struct mtree *mtree = a->format_data;
1484 
1485 		/* Set to output a mtree archive in classic format. */
1486 		mtree->classic = 1;
1487 		/* Basically, mtree classic format uses '/set' global
1488 		 * value. */
1489 		mtree->output_global_set = 1;
1490 	}
1491 	return (r);
1492 }
1493 
1494 static void
sum_init(struct mtree * mtree)1495 sum_init(struct mtree *mtree)
1496 {
1497 
1498 	mtree->compute_sum = 0;
1499 
1500 	if (mtree->keys & F_CKSUM) {
1501 		mtree->compute_sum |= F_CKSUM;
1502 		mtree->crc = 0;
1503 		mtree->crc_len = 0;
1504 	}
1505 #ifdef ARCHIVE_HAS_MD5
1506 	if (mtree->keys & F_MD5) {
1507 		if (archive_md5_init(&mtree->md5ctx) == ARCHIVE_OK)
1508 			mtree->compute_sum |= F_MD5;
1509 		else
1510 			mtree->keys &= ~F_MD5;/* Not supported. */
1511 	}
1512 #endif
1513 #ifdef ARCHIVE_HAS_RMD160
1514 	if (mtree->keys & F_RMD160) {
1515 		if (archive_rmd160_init(&mtree->rmd160ctx) == ARCHIVE_OK)
1516 			mtree->compute_sum |= F_RMD160;
1517 		else
1518 			mtree->keys &= ~F_RMD160;/* Not supported. */
1519 	}
1520 #endif
1521 #ifdef ARCHIVE_HAS_SHA1
1522 	if (mtree->keys & F_SHA1) {
1523 		if (archive_sha1_init(&mtree->sha1ctx) == ARCHIVE_OK)
1524 			mtree->compute_sum |= F_SHA1;
1525 		else
1526 			mtree->keys &= ~F_SHA1;/* Not supported. */
1527 	}
1528 #endif
1529 #ifdef ARCHIVE_HAS_SHA256
1530 	if (mtree->keys & F_SHA256) {
1531 		if (archive_sha256_init(&mtree->sha256ctx) == ARCHIVE_OK)
1532 			mtree->compute_sum |= F_SHA256;
1533 		else
1534 			mtree->keys &= ~F_SHA256;/* Not supported. */
1535 	}
1536 #endif
1537 #ifdef ARCHIVE_HAS_SHA384
1538 	if (mtree->keys & F_SHA384) {
1539 		if (archive_sha384_init(&mtree->sha384ctx) == ARCHIVE_OK)
1540 			mtree->compute_sum |= F_SHA384;
1541 		else
1542 			mtree->keys &= ~F_SHA384;/* Not supported. */
1543 	}
1544 #endif
1545 #ifdef ARCHIVE_HAS_SHA512
1546 	if (mtree->keys & F_SHA512) {
1547 		if (archive_sha512_init(&mtree->sha512ctx) == ARCHIVE_OK)
1548 			mtree->compute_sum |= F_SHA512;
1549 		else
1550 			mtree->keys &= ~F_SHA512;/* Not supported. */
1551 	}
1552 #endif
1553 }
1554 
1555 static void
sum_update(struct mtree * mtree,const void * buff,size_t n)1556 sum_update(struct mtree *mtree, const void *buff, size_t n)
1557 {
1558 	if (mtree->compute_sum & F_CKSUM) {
1559 		/*
1560 		 * Compute a POSIX 1003.2 checksum
1561 		 */
1562 		const unsigned char *p;
1563 		size_t nn;
1564 
1565 		for (nn = n, p = buff; nn--; ++p)
1566 			COMPUTE_CRC(mtree->crc, *p);
1567 		mtree->crc_len += n;
1568 	}
1569 #ifdef ARCHIVE_HAS_MD5
1570 	if (mtree->compute_sum & F_MD5) {
1571 		archive_md5_update(&mtree->md5ctx, buff, n);
1572 		mtree->mtree_entry->reg_info->mset_digest &=
1573 			~AE_MSET_DIGEST_MD5;
1574 	}
1575 #endif
1576 #ifdef ARCHIVE_HAS_RMD160
1577 	if (mtree->compute_sum & F_RMD160) {
1578 		archive_rmd160_update(&mtree->rmd160ctx, buff, n);
1579 		mtree->mtree_entry->reg_info->mset_digest &=
1580 			~AE_MSET_DIGEST_RMD160;
1581 	}
1582 #endif
1583 #ifdef ARCHIVE_HAS_SHA1
1584 	if (mtree->compute_sum & F_SHA1) {
1585 		archive_sha1_update(&mtree->sha1ctx, buff, n);
1586 		mtree->mtree_entry->reg_info->mset_digest &=
1587 			~AE_MSET_DIGEST_SHA1;
1588 	}
1589 #endif
1590 #ifdef ARCHIVE_HAS_SHA256
1591 	if (mtree->compute_sum & F_SHA256) {
1592 		archive_sha256_update(&mtree->sha256ctx, buff, n);
1593 		mtree->mtree_entry->reg_info->mset_digest &=
1594 			~AE_MSET_DIGEST_SHA256;
1595 	}
1596 #endif
1597 #ifdef ARCHIVE_HAS_SHA384
1598 	if (mtree->compute_sum & F_SHA384) {
1599 		archive_sha384_update(&mtree->sha384ctx, buff, n);
1600 		mtree->mtree_entry->reg_info->mset_digest &=
1601 			~AE_MSET_DIGEST_SHA384;
1602 	}
1603 #endif
1604 #ifdef ARCHIVE_HAS_SHA512
1605 	if (mtree->compute_sum & F_SHA512) {
1606 		archive_sha512_update(&mtree->sha512ctx, buff, n);
1607 		mtree->mtree_entry->reg_info->mset_digest &=
1608 			~AE_MSET_DIGEST_SHA512;
1609 	}
1610 #endif
1611 }
1612 
1613 static void
sum_final(struct mtree * mtree,struct reg_info * reg)1614 sum_final(struct mtree *mtree, struct reg_info *reg)
1615 {
1616 	struct ae_digest digest;
1617 
1618 	if (mtree->compute_sum & F_CKSUM) {
1619 		uint64_t len;
1620 		/* Include the length of the file. */
1621 		for (len = mtree->crc_len; len != 0; len >>= 8)
1622 			COMPUTE_CRC(mtree->crc, len & 0xff);
1623 		reg->crc = ~mtree->crc;
1624 	}
1625 #ifdef ARCHIVE_HAS_MD5
1626 	if (mtree->compute_sum & F_MD5)
1627 
1628 		archive_md5_final(&mtree->md5ctx, (reg->mset_digest & AE_MSET_DIGEST_MD5) ? digest.md5 : reg->digest.md5);
1629 #endif
1630 #ifdef ARCHIVE_HAS_RMD160
1631 	if (mtree->compute_sum & F_RMD160)
1632 
1633 		archive_rmd160_final(&mtree->rmd160ctx, (reg->mset_digest & AE_MSET_DIGEST_RMD160) ? digest.rmd160 : reg->digest.rmd160);
1634 #endif
1635 #ifdef ARCHIVE_HAS_SHA1
1636 	if (mtree->compute_sum & F_SHA1)
1637 
1638 		archive_sha1_final(&mtree->sha1ctx, (reg->mset_digest & AE_MSET_DIGEST_SHA1) ? digest.sha1 : reg->digest.sha1);
1639 #endif
1640 #ifdef ARCHIVE_HAS_SHA256
1641 	if (mtree->compute_sum & F_SHA256)
1642 
1643 		archive_sha256_final(&mtree->sha256ctx, (reg->mset_digest & AE_MSET_DIGEST_SHA256) ? digest.sha256 : reg->digest.sha256);
1644 #endif
1645 #ifdef ARCHIVE_HAS_SHA384
1646 	if (mtree->compute_sum & F_SHA384)
1647 
1648 		archive_sha384_final(&mtree->sha384ctx, (reg->mset_digest & AE_MSET_DIGEST_SHA384) ? digest.sha384 : reg->digest.sha384);
1649 #endif
1650 #ifdef ARCHIVE_HAS_SHA512
1651 	if (mtree->compute_sum & F_SHA512)
1652 
1653 		archive_sha512_final(&mtree->sha512ctx, (reg->mset_digest & AE_MSET_DIGEST_SHA512) ? digest.sha512 : reg->digest.sha512);
1654 #endif
1655 	/* Save what types of sum are computed. */
1656 	reg->compute_sum = mtree->compute_sum;
1657 }
1658 
1659 #if defined(ARCHIVE_HAS_MD5) || defined(ARCHIVE_HAS_RMD160) || \
1660     defined(ARCHIVE_HAS_SHA1) || defined(ARCHIVE_HAS_SHA256) || \
1661     defined(ARCHIVE_HAS_SHA384) || defined(ARCHIVE_HAS_SHA512)
1662 static void
strappend_bin(struct archive_string * s,const unsigned char * bin,int n)1663 strappend_bin(struct archive_string *s, const unsigned char *bin, int n)
1664 {
1665 	static const char hex[] = "0123456789abcdef";
1666 	int i;
1667 
1668 	for (i = 0; i < n; i++) {
1669 		archive_strappend_char(s, hex[bin[i] >> 4]);
1670 		archive_strappend_char(s, hex[bin[i] & 0x0f]);
1671 	}
1672 }
1673 #endif
1674 
1675 static void
sum_write(struct archive_string * str,struct reg_info * reg)1676 sum_write(struct archive_string *str, struct reg_info *reg)
1677 {
1678 
1679 	if (reg->compute_sum & F_CKSUM) {
1680 		archive_string_sprintf(str, " cksum=%ju",
1681 		    (uintmax_t)reg->crc);
1682 	}
1683 
1684 #define append_digest(_s, _r, _t) \
1685 	strappend_bin(_s, _r->digest._t, sizeof(_r->digest._t))
1686 
1687 #ifdef ARCHIVE_HAS_MD5
1688 	if (reg->compute_sum & F_MD5) {
1689 		archive_strcat(str, " md5digest=");
1690 		append_digest(str, reg, md5);
1691 	}
1692 #endif
1693 #ifdef ARCHIVE_HAS_RMD160
1694 	if (reg->compute_sum & F_RMD160) {
1695 		archive_strcat(str, " rmd160digest=");
1696 		append_digest(str, reg, rmd160);
1697 	}
1698 #endif
1699 #ifdef ARCHIVE_HAS_SHA1
1700 	if (reg->compute_sum & F_SHA1) {
1701 		archive_strcat(str, " sha1digest=");
1702 		append_digest(str, reg, sha1);
1703 	}
1704 #endif
1705 #ifdef ARCHIVE_HAS_SHA256
1706 	if (reg->compute_sum & F_SHA256) {
1707 		archive_strcat(str, " sha256digest=");
1708 		append_digest(str, reg, sha256);
1709 	}
1710 #endif
1711 #ifdef ARCHIVE_HAS_SHA384
1712 	if (reg->compute_sum & F_SHA384) {
1713 		archive_strcat(str, " sha384digest=");
1714 		append_digest(str, reg, sha384);
1715 	}
1716 #endif
1717 #ifdef ARCHIVE_HAS_SHA512
1718 	if (reg->compute_sum & F_SHA512) {
1719 		archive_strcat(str, " sha512digest=");
1720 		append_digest(str, reg, sha512);
1721 	}
1722 #endif
1723 #undef append_digest
1724 }
1725 
1726 static int
mtree_entry_cmp_node(const struct archive_rb_node * n1,const struct archive_rb_node * n2)1727 mtree_entry_cmp_node(const struct archive_rb_node *n1,
1728     const struct archive_rb_node *n2)
1729 {
1730 	const struct mtree_entry *e1 = (const struct mtree_entry *)n1;
1731 	const struct mtree_entry *e2 = (const struct mtree_entry *)n2;
1732 
1733 	return (strcmp(e2->basename.s, e1->basename.s));
1734 }
1735 
1736 static int
mtree_entry_cmp_key(const struct archive_rb_node * n,const void * key)1737 mtree_entry_cmp_key(const struct archive_rb_node *n, const void *key)
1738 {
1739 	const struct mtree_entry *e = (const struct mtree_entry *)n;
1740 
1741 	return (strcmp((const char *)key, e->basename.s));
1742 }
1743 
1744 #if defined(_WIN32) || defined(__CYGWIN__)
1745 static int
cleanup_backslash_1(char * p)1746 cleanup_backslash_1(char *p)
1747 {
1748 	int mb, dos;
1749 
1750 	mb = dos = 0;
1751 	while (*p) {
1752 		if (*(unsigned char *)p > 127)
1753 			mb = 1;
1754 		if (*p == '\\') {
1755 			/* If we have not met any multi-byte characters,
1756 			 * we can replace '\' with '/'. */
1757 			if (!mb)
1758 				*p = '/';
1759 			dos = 1;
1760 		}
1761 		p++;
1762 	}
1763 	if (!mb || !dos)
1764 		return (0);
1765 	return (-1);
1766 }
1767 
1768 static void
cleanup_backslash_2(wchar_t * p)1769 cleanup_backslash_2(wchar_t *p)
1770 {
1771 
1772 	/* Convert a path-separator from '\' to  '/' */
1773 	while (*p != L'\0') {
1774 		if (*p == L'\\')
1775 			*p = L'/';
1776 		p++;
1777 	}
1778 }
1779 #endif
1780 
1781 /*
1782  * Generate a parent directory name and a base name from a pathname.
1783  */
1784 static int
mtree_entry_setup_filenames(struct archive_write * a,struct mtree_entry * file,struct archive_entry * entry)1785 mtree_entry_setup_filenames(struct archive_write *a, struct mtree_entry *file,
1786     struct archive_entry *entry)
1787 {
1788 	const char *pathname;
1789 	char *p, *dirname, *slash;
1790 	size_t len;
1791 	int ret = ARCHIVE_OK;
1792 
1793 	archive_strcpy(&file->pathname, archive_entry_pathname(entry));
1794 #if defined(_WIN32) || defined(__CYGWIN__)
1795 	/*
1796 	 * Convert a path-separator from '\' to  '/'
1797 	 */
1798 	if (cleanup_backslash_1(file->pathname.s) != 0) {
1799 		const wchar_t *wp = archive_entry_pathname_w(entry);
1800 		struct archive_wstring ws;
1801 
1802 		if (wp != NULL) {
1803 			int r;
1804 			archive_string_init(&ws);
1805 			archive_wstrcpy(&ws, wp);
1806 			cleanup_backslash_2(ws.s);
1807 			archive_string_empty(&(file->pathname));
1808 			r = archive_string_append_from_wcs(&(file->pathname),
1809 			    ws.s, ws.length);
1810 			archive_wstring_free(&ws);
1811 			if (r < 0 && errno == ENOMEM) {
1812 				archive_set_error(&a->archive, ENOMEM,
1813 				    "Can't allocate memory");
1814 				return (ARCHIVE_FATAL);
1815 			}
1816 		}
1817 	}
1818 #else
1819 	(void)a; /* UNUSED */
1820 #endif
1821 	pathname =  file->pathname.s;
1822 	if (strcmp(pathname, ".") == 0) {
1823 		archive_strcpy(&file->basename, ".");
1824 		return (ARCHIVE_OK);
1825 	}
1826 
1827 	archive_strcpy(&(file->parentdir), pathname);
1828 
1829 	len = file->parentdir.length;
1830 	p = dirname = file->parentdir.s;
1831 
1832 	/*
1833 	 * Remove leading '/' and '../' elements
1834 	 */
1835 	while (*p) {
1836 		if (p[0] == '/') {
1837 			p++;
1838 			len--;
1839 		} else if (p[0] != '.')
1840 			break;
1841 		else if (p[1] == '.' && p[2] == '/') {
1842 			p += 3;
1843 			len -= 3;
1844 		} else
1845 			break;
1846 	}
1847 	if (p != dirname) {
1848 		memmove(dirname, p, len+1);
1849 		p = dirname;
1850 	}
1851 	/*
1852 	 * Remove "/","/." and "/.." elements from tail.
1853 	 */
1854 	while (len > 0) {
1855 		size_t ll = len;
1856 
1857 		if (len > 0 && p[len-1] == '/') {
1858 			p[len-1] = '\0';
1859 			len--;
1860 		}
1861 		if (len > 1 && p[len-2] == '/' && p[len-1] == '.') {
1862 			p[len-2] = '\0';
1863 			len -= 2;
1864 		}
1865 		if (len > 2 && p[len-3] == '/' && p[len-2] == '.' &&
1866 		    p[len-1] == '.') {
1867 			p[len-3] = '\0';
1868 			len -= 3;
1869 		}
1870 		if (ll == len)
1871 			break;
1872 	}
1873 	while (*p) {
1874 		if (p[0] == '/') {
1875 			if (p[1] == '/')
1876 				/* Convert '//' --> '/' */
1877 				memmove(p, p+1, strlen(p+1) + 1);
1878 			else if (p[1] == '.' && p[2] == '/')
1879 				/* Convert '/./' --> '/' */
1880 				memmove(p, p+2, strlen(p+2) + 1);
1881 			else if (p[1] == '.' && p[2] == '.' && p[3] == '/') {
1882 				/* Convert 'dir/dir1/../dir2/'
1883 				 *     --> 'dir/dir2/'
1884 				 */
1885 				char *rp = p -1;
1886 				size_t off;
1887 				for (off = 4; p[off] == '/'; off++)
1888 					;
1889 				while (rp >= dirname) {
1890 					if (*rp == '/')
1891 						break;
1892 					--rp;
1893 				}
1894 				if (rp > dirname) {
1895 					memmove(rp + 1, p + off, strlen(p + off) + 1);
1896 					p = rp;
1897 				} else {
1898 					memmove(dirname, p + off, strlen(p + off) + 1);
1899 					p = dirname;
1900 				}
1901 			} else
1902 				p++;
1903 		} else if (p == dirname && p[0] == '.' && p[1] == '.' && p[2] == '/') {
1904 			size_t off;
1905 			for (off = 3; p[off] == '/'; off++)
1906 				;
1907 			memmove(dirname, p + off, strlen(p + off) + 1);
1908 			p = dirname;
1909 		} else
1910 			p++;
1911 	}
1912 	p = dirname;
1913 	len = strlen(p);
1914 
1915 	/*
1916 	 * Add "./" prefix.
1917 	 * NOTE: If the pathname does not have a path separator, we have
1918 	 * to add "./" to the head of the pathname because mtree reader
1919 	 * will suppose that it is v1(a.k.a classic) mtree format and
1920 	 * change the directory unexpectedly and so it will make a wrong
1921 	 * path.
1922 	 */
1923 	if (strcmp(p, ".") != 0 && strncmp(p, "./", 2) != 0) {
1924 		struct archive_string as;
1925 		archive_string_init(&as);
1926 		archive_strcpy(&as, "./");
1927 		archive_strncat(&as, p, len);
1928 		archive_string_empty(&file->parentdir);
1929 		archive_string_concat(&file->parentdir, &as);
1930 		archive_string_free(&as);
1931 		p = file->parentdir.s;
1932 		len = archive_strlen(&file->parentdir);
1933 	}
1934 
1935 	/*
1936 	 * Find out the position which points to the last position of
1937 	 * path separator('/').
1938 	 */
1939 	slash = NULL;
1940 	for (; *p != '\0'; p++) {
1941 		if (*p == '/')
1942 			slash = p;
1943 	}
1944 	if (slash == NULL) {
1945 		/* The pathname doesn't have a parent directory. */
1946 		file->parentdir.length = len;
1947 		archive_string_copy(&(file->basename), &(file->parentdir));
1948 		archive_string_empty(&(file->parentdir));
1949 		*file->parentdir.s = '\0';
1950 		return (ret);
1951 	}
1952 
1953 	/* Make a basename from file->parentdir.s and slash */
1954 	*slash  = '\0';
1955 	file->parentdir.length = slash - file->parentdir.s;
1956 	archive_strcpy(&(file->basename),  slash + 1);
1957 	return (ret);
1958 }
1959 
1960 static int
mtree_entry_create_virtual_dir(struct archive_write * a,const char * pathname,struct mtree_entry ** m_entry)1961 mtree_entry_create_virtual_dir(struct archive_write *a, const char *pathname,
1962     struct mtree_entry **m_entry)
1963 {
1964 	struct archive_entry *entry;
1965 	struct mtree_entry *file;
1966 	int r;
1967 
1968 	entry = archive_entry_new();
1969 	if (entry == NULL) {
1970 		*m_entry = NULL;
1971 		archive_set_error(&a->archive, ENOMEM,
1972 		    "Can't allocate memory");
1973 		return (ARCHIVE_FATAL);
1974 	}
1975 	archive_entry_copy_pathname(entry, pathname);
1976 	archive_entry_set_mode(entry, AE_IFDIR | 0755);
1977 	archive_entry_set_mtime(entry, time(NULL), 0);
1978 
1979 	r = mtree_entry_new(a, entry, &file);
1980 	archive_entry_free(entry);
1981 	if (r < ARCHIVE_WARN) {
1982 		*m_entry = NULL;
1983 		archive_set_error(&a->archive, ENOMEM,
1984 		    "Can't allocate memory");
1985 		return (ARCHIVE_FATAL);
1986 	}
1987 
1988 	file->dir_info->virtual = 1;
1989 
1990 	*m_entry = file;
1991 	return (ARCHIVE_OK);
1992 }
1993 
1994 static void
mtree_entry_register_add(struct mtree * mtree,struct mtree_entry * file)1995 mtree_entry_register_add(struct mtree *mtree, struct mtree_entry *file)
1996 {
1997         file->next = NULL;
1998         *mtree->file_list.last = file;
1999         mtree->file_list.last = &(file->next);
2000 }
2001 
2002 static void
mtree_entry_register_init(struct mtree * mtree)2003 mtree_entry_register_init(struct mtree *mtree)
2004 {
2005 	mtree->file_list.first = NULL;
2006 	mtree->file_list.last = &(mtree->file_list.first);
2007 }
2008 
2009 static void
mtree_entry_register_free(struct mtree * mtree)2010 mtree_entry_register_free(struct mtree *mtree)
2011 {
2012 	struct mtree_entry *file, *file_next;
2013 
2014 	file = mtree->file_list.first;
2015 	while (file != NULL) {
2016 		file_next = file->next;
2017 		mtree_entry_free(file);
2018 		file = file_next;
2019 	}
2020 }
2021 
2022 static int
mtree_entry_add_child_tail(struct mtree_entry * parent,struct mtree_entry * child)2023 mtree_entry_add_child_tail(struct mtree_entry *parent,
2024     struct mtree_entry *child)
2025 {
2026 	child->dir_info->chnext = NULL;
2027 	*parent->dir_info->children.last = child;
2028 	parent->dir_info->children.last = &(child->dir_info->chnext);
2029 	return (1);
2030 }
2031 
2032 /*
2033  * Find an entry from a parent entry with given name.
2034  */
2035 static struct mtree_entry *
mtree_entry_find_child(struct mtree_entry * parent,const char * child_name)2036 mtree_entry_find_child(struct mtree_entry *parent, const char *child_name)
2037 {
2038 	struct mtree_entry *np;
2039 
2040 	if (parent == NULL)
2041 		return (NULL);
2042 	np = (struct mtree_entry *)__archive_rb_tree_find_node(
2043 	    &(parent->dir_info->rbtree), child_name);
2044 	return (np);
2045 }
2046 
2047 static int
get_path_component(char * name,size_t n,const char * fn)2048 get_path_component(char *name, size_t n, const char *fn)
2049 {
2050 	const char *p;
2051 	size_t l;
2052 
2053 	p = strchr(fn, '/');
2054 	if (p == NULL) {
2055 		if ((l = strlen(fn)) == 0)
2056 			return (0);
2057 	} else
2058 		l = p - fn;
2059 	if (l > n -1)
2060 		return (-1);
2061 	memcpy(name, fn, l);
2062 	name[l] = '\0';
2063 
2064 	return ((int)l);
2065 }
2066 
2067 /*
2068  * Add a new entry into the tree.
2069  */
2070 static int
mtree_entry_tree_add(struct archive_write * a,struct mtree_entry ** filep)2071 mtree_entry_tree_add(struct archive_write *a, struct mtree_entry **filep)
2072 {
2073 	struct mtree *mtree = a->format_data;
2074 #if defined(_WIN32) && !defined(__CYGWIN__)
2075 	char name[_MAX_FNAME];/* Included null terminator size. */
2076 #elif defined(NAME_MAX) && NAME_MAX >= 255
2077 	char name[NAME_MAX+1];
2078 #else
2079 	char name[256];
2080 #endif
2081 	struct mtree_entry *dent, *file, *np;
2082 	const char *fn, *p;
2083 	int l, r;
2084 
2085 	file = *filep;
2086 	if (file->parentdir.length == 0 && file->basename.length == 1 &&
2087 	    file->basename.s[0] == '.') {
2088 		if (file->filetype != AE_IFDIR) {
2089 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
2090 				"Root entry '.' must be a directory");
2091 			return (ARCHIVE_FAILED);
2092 		}
2093 		file->parent = file;
2094 		if (mtree->root != NULL) {
2095 			np = mtree->root;
2096 			goto same_entry;
2097 		}
2098 		mtree->root = file;
2099 		mtree_entry_register_add(mtree, file);
2100 		return (ARCHIVE_OK);
2101 	}
2102 
2103 	if (file->parentdir.length == 0) {
2104 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
2105 		    "Internal programming error "
2106 		    "in generating canonical name for %s",
2107 		    file->pathname.s);
2108 		return (ARCHIVE_FAILED);
2109 	}
2110 
2111 	fn = p = file->parentdir.s;
2112 
2113 	/*
2114 	 * If the path of the parent directory of `file' entry is
2115 	 * the same as the path of `cur_dirent', add `file' entry to
2116 	 * `cur_dirent'.
2117 	 */
2118 	if (archive_strlen(&(mtree->cur_dirstr))
2119 	      == archive_strlen(&(file->parentdir)) &&
2120 	    strcmp(mtree->cur_dirstr.s, fn) == 0) {
2121 		if (!__archive_rb_tree_insert_node(
2122 		    &(mtree->cur_dirent->dir_info->rbtree),
2123 		    (struct archive_rb_node *)file)) {
2124 			/* There is the same name in the tree. */
2125 			np = (struct mtree_entry *)__archive_rb_tree_find_node(
2126 			    &(mtree->cur_dirent->dir_info->rbtree),
2127 			    file->basename.s);
2128 			goto same_entry;
2129 		}
2130 		file->parent = mtree->cur_dirent;
2131 		mtree_entry_register_add(mtree, file);
2132 		return (ARCHIVE_OK);
2133 	}
2134 
2135 	dent = mtree->root;
2136 	for (;;) {
2137 		l = get_path_component(name, sizeof(name), fn);
2138 		if (l == 0) {
2139 			np = NULL;
2140 			break;
2141 		}
2142 		if (l < 0) {
2143 			archive_set_error(&a->archive,
2144 			    ARCHIVE_ERRNO_MISC,
2145 			    "A name buffer is too small");
2146 			return (ARCHIVE_FATAL);
2147 		}
2148 		if (l == 1 && name[0] == '.' && dent != NULL &&
2149 		    dent == mtree->root) {
2150 			fn += l;
2151 			if (fn[0] == '/')
2152 				fn++;
2153 			continue;
2154 		}
2155 
2156 		np = mtree_entry_find_child(dent, name);
2157 		if (np == NULL || fn[0] == '\0')
2158 			break;
2159 
2160 		/* Find next sub directory. */
2161 		if (!np->dir_info) {
2162 			/* NOT a directory! */
2163 			archive_set_error(&a->archive,
2164 			    ARCHIVE_ERRNO_MISC,
2165 			    "`%s' is not a directory, we cannot insert `%s' ",
2166 			    np->pathname.s, file->pathname.s);
2167 			return (ARCHIVE_FAILED);
2168 		}
2169 		fn += l;
2170 		if (fn[0] == '/')
2171 			fn++;
2172 		dent = np;
2173 	}
2174 	if (np == NULL) {
2175 		/*
2176 		 * Create virtual parent directories.
2177 		 */
2178 		while (fn[0] != '\0') {
2179 			struct mtree_entry *vp;
2180 			struct archive_string as;
2181 
2182 			archive_string_init(&as);
2183 			archive_strncat(&as, p, fn - p + l);
2184 			if (as.s[as.length-1] == '/') {
2185 				as.s[as.length-1] = '\0';
2186 				as.length--;
2187 			}
2188 			r = mtree_entry_create_virtual_dir(a, as.s, &vp);
2189 			archive_string_free(&as);
2190 			if (r < ARCHIVE_WARN)
2191 				return (r);
2192 
2193 			if (strcmp(vp->pathname.s, ".") == 0) {
2194 				vp->parent = vp;
2195 				mtree->root = vp;
2196 			} else {
2197 				__archive_rb_tree_insert_node(
2198 				    &(dent->dir_info->rbtree),
2199 				    (struct archive_rb_node *)vp);
2200 				vp->parent = dent;
2201 			}
2202 			mtree_entry_register_add(mtree, vp);
2203 			np = vp;
2204 
2205 			fn += l;
2206 			if (fn[0] == '/')
2207 				fn++;
2208 			l = get_path_component(name, sizeof(name), fn);
2209 			if (l < 0) {
2210 				archive_string_free(&as);
2211 				archive_set_error(&a->archive,
2212 				    ARCHIVE_ERRNO_MISC,
2213 				    "A name buffer is too small");
2214 				return (ARCHIVE_FATAL);
2215 			}
2216 			dent = np;
2217 		}
2218 
2219 		/* Found out the parent directory where `file' can be
2220 		 * inserted. */
2221 		mtree->cur_dirent = dent;
2222 		archive_string_empty(&(mtree->cur_dirstr));
2223 		if (archive_string_ensure(&(mtree->cur_dirstr),
2224 		    archive_strlen(&(dent->parentdir)) +
2225 		    archive_strlen(&(dent->basename)) + 2) == NULL) {
2226 			archive_set_error(&a->archive, ENOMEM,
2227 			    "Can't allocate memory");
2228 			return (ARCHIVE_FATAL);
2229 		}
2230 		if (archive_strlen(&(dent->parentdir)) +
2231 		    archive_strlen(&(dent->basename)) == 0)
2232 			mtree->cur_dirstr.s[0] = 0;
2233 		else {
2234 			if (archive_strlen(&(dent->parentdir)) > 0) {
2235 				archive_string_copy(&(mtree->cur_dirstr),
2236 				    &(dent->parentdir));
2237 				archive_strappend_char(
2238 				    &(mtree->cur_dirstr), '/');
2239 			}
2240 			archive_string_concat(&(mtree->cur_dirstr),
2241 			    &(dent->basename));
2242 		}
2243 
2244 		if (!__archive_rb_tree_insert_node(
2245 		    &(dent->dir_info->rbtree),
2246 		    (struct archive_rb_node *)file)) {
2247 			np = (struct mtree_entry *)__archive_rb_tree_find_node(
2248 			    &(dent->dir_info->rbtree), file->basename.s);
2249 			goto same_entry;
2250 		}
2251 		file->parent = dent;
2252 		mtree_entry_register_add(mtree, file);
2253 		return (ARCHIVE_OK);
2254 	}
2255 
2256 same_entry:
2257 	/* We already have an entry with same filename. */
2258 	r = mtree_entry_exchange_same_entry(a, np, file);
2259 	if (r < ARCHIVE_WARN)
2260 		return (r);
2261 	if (np->dir_info)
2262 		np->dir_info->virtual = 0;
2263 	*filep = np;
2264 	mtree_entry_free(file);
2265 	return (ARCHIVE_WARN);
2266 }
2267 
2268 static int
mtree_entry_exchange_same_entry(struct archive_write * a,struct mtree_entry * np,struct mtree_entry * file)2269 mtree_entry_exchange_same_entry(struct archive_write *a, struct mtree_entry *np,
2270     struct mtree_entry *file)
2271 {
2272 
2273 	if ((np->mode & AE_IFMT) != (file->mode & AE_IFMT)) {
2274 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
2275 		    "Found duplicate entries for `%s' with "
2276 		    "differing file types",
2277 		    np->pathname.s);
2278 		return (ARCHIVE_FAILED);
2279 	}
2280 
2281 	/* Update the existing mtree entry's attributes by the new one's. */
2282 	archive_string_empty(&np->symlink);
2283 	archive_string_concat(&np->symlink, &file->symlink);
2284 	archive_string_empty(&np->uname);
2285 	archive_string_concat(&np->uname, &file->uname);
2286 	archive_string_empty(&np->gname);
2287 	archive_string_concat(&np->gname, &file->gname);
2288 	archive_string_empty(&np->fflags_text);
2289 	archive_string_concat(&np->fflags_text, &file->fflags_text);
2290 	np->nlink = file->nlink;
2291 	np->filetype = file->filetype;
2292 	np->mode = file->mode;
2293 	np->size = file->size;
2294 	np->uid = file->uid;
2295 	np->gid = file->gid;
2296 	np->fflags_set = file->fflags_set;
2297 	np->fflags_clear = file->fflags_clear;
2298 	np->mtime = file->mtime;
2299 	np->mtime_nsec = file->mtime_nsec;
2300 	np->rdevmajor = file->rdevmajor;
2301 	np->rdevminor = file->rdevminor;
2302 	np->devmajor = file->devmajor;
2303 	np->devminor = file->devminor;
2304 	np->ino = file->ino;
2305 
2306 	return (ARCHIVE_WARN);
2307 }
2308