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