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