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