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