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