Remove building with NOCRYPTO option
[minix.git] / external / bsd / libarchive / dist / libarchive / archive_write_set_format_mtree.c
blob7feeca92e6219da9cd996190a5393113dc2216bf
1 /*-
2 * Copyright (c) 2009 Michihiro NAKAJIMA
3 * Copyright (c) 2008 Joerg Sonnenberger
4 * All rights reserved.
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.
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.
27 #include "archive_platform.h"
28 __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_mtree.c 201171 2009-12-29 06:39:07Z kientzle $");
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>
37 #include "archive.h"
38 #include "archive_entry.h"
39 #include "archive_private.h"
40 #include "archive_write_private.h"
42 #include "archive_hash.h"
44 #define INDENTNAMELEN 15
45 #define MAXLINELEN 80
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 */
117 /* Options */
118 int dironly; /* if the dironly is 1, ignore everything except
119 * directory type files. like mtree(8) -d option.
121 int indent; /* if the indent is 1, indent writing data. */
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)
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
184 static int
185 mtree_safe_char(char c)
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 */
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;
205 static void
206 mtree_quote(struct archive_string *s, const char *str)
208 const char *start;
209 char buf[4];
210 unsigned char c;
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;
226 if (start != str)
227 archive_strncat(s, start, str - start);
230 static void
231 mtree_indent(struct mtree_writer *mtree)
233 int i, fn;
234 const char *r, *s, *x;
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, ' ');
253 s = ++r;
254 x = NULL;
255 continue;
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;
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;
278 archive_strcat(&mtree->buf, s);
279 archive_string_empty(&mtree->ebuf);
282 #if !defined(_WIN32) || defined(__CYGWIN__)
283 static size_t
284 dir_len(struct archive_entry *entry)
286 const char *path, *r;
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);
296 #else /* _WIN32 && !__CYGWIN__ */
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.
303 static size_t
304 dir_len(struct archive_entry *entry)
306 wchar_t wc;
307 const char *path;
308 const char *p, *rp;
309 size_t al, l, size;
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;
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;
332 return (rp - path + 1);
333 alen:
334 if (al == -1)
335 return (0);
336 return (al + 1);
338 #endif /* _WIN32 && !__CYGWIN__ */
340 static int
341 parent_dir_changed(struct archive_string *dir, struct archive_entry *entry)
343 const char *path;
344 size_t l;
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);
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);
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.
373 static void
374 set_global(struct mtree_writer *mtree, struct archive_entry *entry)
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;
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;
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);
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) {
414 * Check the global datas for whether it needs updating.
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;
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;
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");
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;
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);
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;
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);
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);
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;
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;
499 static int
500 get_keys(struct mtree_writer *mtree, struct archive_entry *entry)
502 int keys;
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;
516 archive_entry_fflags(entry, &set, &clear);
517 if (mtree->set.fflags_set == set &&
518 mtree->set.fflags_clear == clear)
519 keys &= ~F_FLAGS;
521 if ((mtree->set.keys & F_MODE) != 0 &&
522 mtree->set.mode == (archive_entry_mode(entry) & 07777))
523 keys &= ~F_MODE;
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;
542 return (keys);
545 static int
546 archive_write_mtree_header(struct archive_write *a,
547 struct archive_entry *entry)
549 struct mtree_writer *mtree= a->format_data;
550 struct archive_string *str;
551 const char *path;
553 mtree->entry = archive_entry_clone(entry);
554 path = archive_entry_pathname(mtree->entry);
556 if (mtree->first) {
557 mtree->first = 0;
558 archive_strcat(&mtree->buf, "#mtree\n");
560 if (mtree->set.output)
561 set_global(mtree, entry);
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);
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
625 return (ARCHIVE_OK);
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)
634 static const char hex[] = "0123456789abcdef";
635 int i;
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]);
642 #endif
644 static int
645 archive_write_mtree_finish_entry(struct archive_write *a)
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;
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);
659 mtree->entry = NULL;
661 if (mtree->dironly && archive_entry_filetype(entry) != AE_IFDIR) {
662 archive_entry_free(entry);
663 return (ARCHIVE_OK);
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));
674 if ((keys & F_GNAME) != 0 &&
675 (name = archive_entry_gname(entry)) != NULL) {
676 archive_strcat(str, " gname=");
677 mtree_quote(str, name);
679 if ((keys & F_UNAME) != 0 &&
680 (name = archive_entry_uname(entry)) != NULL) {
681 archive_strcat(str, " uname=");
682 mtree_quote(str, name);
684 if ((keys & F_FLAGS) != 0 &&
685 (name = archive_entry_fflags_text(entry)) != NULL) {
686 archive_strcat(str, " flags=");
687 mtree_quote(str, name);
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));
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));
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));
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));
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;
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);
763 #ifdef ARCHIVE_HAS_MD5
764 if (mtree->compute_sum & F_MD5) {
765 unsigned char buf[16];
767 archive_md5_final(&mtree->md5ctx, buf);
768 archive_strcat(str, " md5digest=");
769 strappend_bin(str, buf, sizeof(buf));
771 #endif
772 #ifdef ARCHIVE_HAS_RMD160
773 if (mtree->compute_sum & F_RMD160) {
774 unsigned char buf[20];
776 archive_rmd160_final(&mtree->rmd160ctx, buf);
777 archive_strcat(str, " rmd160digest=");
778 strappend_bin(str, buf, sizeof(buf));
780 #endif
781 #ifdef ARCHIVE_HAS_SHA1
782 if (mtree->compute_sum & F_SHA1) {
783 unsigned char buf[20];
785 archive_sha1_final(&mtree->sha1ctx, buf);
786 archive_strcat(str, " sha1digest=");
787 strappend_bin(str, buf, sizeof(buf));
789 #endif
790 #ifdef ARCHIVE_HAS_SHA256
791 if (mtree->compute_sum & F_SHA256) {
792 unsigned char buf[32];
794 archive_sha256_final(&mtree->sha256ctx, buf);
795 archive_strcat(str, " sha256digest=");
796 strappend_bin(str, buf, sizeof(buf));
798 #endif
799 #ifdef ARCHIVE_HAS_SHA384
800 if (mtree->compute_sum & F_SHA384) {
801 unsigned char buf[48];
803 archive_sha384_final(&mtree->sha384ctx, buf);
804 archive_strcat(str, " sha384digest=");
805 strappend_bin(str, buf, sizeof(buf));
807 #endif
808 #ifdef ARCHIVE_HAS_SHA512
809 if (mtree->compute_sum & F_SHA512) {
810 unsigned char buf[64];
812 archive_sha512_final(&mtree->sha512ctx, buf);
813 archive_strcat(str, " sha512digest=");
814 strappend_bin(str, buf, sizeof(buf));
816 #endif
817 archive_strcat(str, "\n");
818 if (mtree->indent)
819 mtree_indent(mtree);
821 archive_entry_free(entry);
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;
829 return (ret == ARCHIVE_OK ? ret : ARCHIVE_FATAL);
832 static int
833 archive_write_mtree_finish(struct archive_write *a)
835 struct mtree_writer *mtree= a->format_data;
837 archive_write_set_bytes_in_last_block(&a->archive, 1);
839 return (a->compressor.write)(a, mtree->buf.s, mtree->buf.length);
842 static ssize_t
843 archive_write_mtree_data(struct archive_write *a, const void *buff, size_t n)
845 struct mtree_writer *mtree= a->format_data;
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) {
854 * Compute a POSIX 1003.2 checksum
856 const unsigned char *p;
857 size_t nn;
859 for (nn = n, p = buff; nn--; ++p)
860 COMPUTE_CRC(mtree->crc, *p);
861 mtree->crc_len += n;
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);
890 static int
891 archive_write_mtree_destroy(struct archive_write *a)
893 struct mtree_writer *mtree= a->format_data;
895 if (mtree == NULL)
896 return (ARCHIVE_OK);
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);
907 static int
908 archive_write_mtree_options(struct archive_write *a, const char *key,
909 const char *value)
911 struct mtree_writer *mtree= a->format_data;
912 int keybit = 0;
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);
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);
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);
999 break;
1001 if (keybit != 0) {
1002 if (value != NULL)
1003 mtree->keys |= keybit;
1004 else
1005 mtree->keys &= ~keybit;
1006 return (ARCHIVE_OK);
1009 return (ARCHIVE_WARN);
1013 archive_write_set_format_mtree(struct archive *_a)
1015 struct archive_write *a = (struct archive_write *)_a;
1016 struct mtree_writer *mtree;
1018 if (a->format_destroy != NULL)
1019 (a->format_destroy)(a);
1021 if ((mtree = malloc(sizeof(*mtree))) == NULL) {
1022 archive_set_error(&a->archive, ENOMEM,
1023 "Can't allocate mtree data");
1024 return (ARCHIVE_FATAL);
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;
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";
1049 return (ARCHIVE_OK);