2 * Copyright (c) 2009 Michihiro NAKAJIMA
3 * Copyright (c) 2008 Joerg Sonnenberger
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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$");
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
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 */
52 #endif /* HAVE_OPENSSL_RIPEMD_H */
53 #ifdef HAVE_OPENSSL_SHA_H
54 #include <openssl/sha.h>
55 #else /* HAVE_OPENSSL_SHA_H */
68 #endif /* HAVE_OPENSSL_SHA_H */
71 #include "archive_entry.h"
72 #include "archive_private.h"
73 #include "archive_write_private.h"
75 #define INDENTNAMELEN 15
79 struct archive_entry *entry;
80 struct archive_string ebuf;
81 struct archive_string buf;
83 uint64_t entry_bytes_remaining;
87 struct archive_string parent;
93 unsigned long fflags_set;
94 unsigned long fflags_clear;
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;
109 #if defined(HAVE_OPENSSL_SHA_H) || defined(HAVE_SHA_H)
116 SHA256_CTX sha256ctx;
119 #if defined(HAVE_OPENSSL_SHA_H)
120 SHA512_CTX sha384ctx;
122 SHA384_CTX sha384ctx;
126 SHA512_CTX sha512ctx;
128 /* Keyword options */
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
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 */
159 int dironly; /* if the dironly is 1, ignore everything except
160 * directory type files. like mtree(8) -d option.
162 int indent; /* if the indent is 1, indent writing data. */
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\
169 #define COMPUTE_CRC(var, ch) (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)]
170 static const uint32_t crctab[] = {
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
226 mtree_safe_char(char c)
228 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
230 if (c >= '0' && c <= '9')
232 if (c == 35 || c == 61 || c == 92)
233 return 0; /* #, = and \ are always quoted */
235 if (c >= 33 && c <= 47) /* !"$%&'()*+,-./ */
237 if (c >= 58 && c <= 64) /* :;<>?@ */
239 if (c >= 91 && c <= 96) /* []^_` */
241 if (c >= 123 && c <= 126) /* {|}~ */
247 mtree_quote(struct archive_string *s, const char *str)
253 for (start = str; *str != '\0'; ++str) {
254 if (mtree_safe_char(*str))
257 archive_strncat(s, start, str - start);
258 c = (unsigned char)*str;
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);
268 archive_strncat(s, start, str - start);
272 mtree_indent(struct mtree_writer *mtree)
275 const char *r, *s, *x;
278 s = r = mtree->ebuf.s;
282 while ((r = strchr(r, ' ')) != NULL) {
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, ' ');
291 for (i = r -s; i < (INDENTNAMELEN + 1); i++)
292 archive_strappend_char(&mtree->buf, ' ');
298 if (r - s <= MAXLINELEN - 3 - INDENTNAMELEN)
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, ' ');
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, ' ');
319 archive_strcat(&mtree->buf, s);
320 archive_string_empty(&mtree->ebuf);
323 #if !defined(_WIN32) || defined(__CYGWIN__)
325 dir_len(struct archive_entry *entry)
327 const char *path, *r;
329 path = archive_entry_pathname(entry);
330 r = strrchr(path, '/');
333 /* Include a separator size */
334 return (r - path + 1);
337 #else /* _WIN32 && !__CYGWIN__ */
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
345 dir_len(struct archive_entry *entry)
352 path = archive_entry_pathname(entry);
354 for (p = path; *p != '\0'; ++p) {
365 l = mbtowc(&wc, p, size);
368 if (l == 1 && (wc == L'/' || wc == L'\\'))
373 return (rp - path + 1);
379 #endif /* _WIN32 && !__CYGWIN__ */
382 parent_dir_changed(struct archive_string *dir, struct archive_entry *entry)
388 path = archive_entry_pathname(entry);
389 if (archive_strlen(dir) > 0) {
391 archive_string_empty(dir);
394 if (strncmp(dir->s, path, l) == 0)
395 return (0); /* The parent directory is the same. */
397 return (0); /* The parent directory is the same. */
398 archive_strncpy(dir, path, l);
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
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.
415 set_global(struct mtree_writer *mtree, struct archive_entry *entry)
417 struct archive_string setstr;
418 struct archive_string unsetstr;
420 int keys, oldkeys, effkeys;
423 switch (archive_entry_filetype(entry)) {
424 case AE_IFLNK: case AE_IFSOCK: case AE_IFCHR:
425 case AE_IFBLK: case AE_IFIFO:
432 default: /* Handle unknown file types as regular files. */
439 if (mtree->set.processed &&
440 !parent_dir_changed(&mtree->set.parent, entry))
442 /* At first, save a parent directory of the entry for following
444 if (!mtree->set.processed && set_type == AE_IFREG)
445 parent_dir_changed(&mtree->set.parent, entry);
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;
453 if (mtree->set.processed) {
455 * Check the global datas for whether it needs updating.
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))
467 if ((oldkeys & F_FLAGS) != 0) {
468 unsigned long fflags_set;
469 unsigned long fflags_clear;
471 archive_entry_fflags(entry, &fflags_set, &fflags_clear);
472 if (fflags_set == mtree->set.fflags_set &&
473 fflags_clear == mtree->set.fflags_clear)
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");
482 archive_strcat(&setstr, " type=file");
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");
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);
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");
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);
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);
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");
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. */
537 mtree->set.output = 0;
541 get_keys(struct mtree_writer *mtree, struct archive_entry *entry)
546 if (mtree->set.keys == 0)
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;
557 archive_entry_fflags(entry, &set, &clear);
558 if (mtree->set.fflags_set == set &&
559 mtree->set.fflags_clear == clear)
562 if ((mtree->set.keys & F_MODE) != 0 &&
563 mtree->set.mode == (archive_entry_mode(entry) & 07777))
566 switch (archive_entry_filetype(entry)) {
567 case AE_IFLNK: case AE_IFSOCK: case AE_IFCHR:
568 case AE_IFBLK: case AE_IFIFO:
571 if ((mtree->set.keys & F_TYPE) != 0 &&
572 mtree->set.type == AE_IFDIR)
576 default: /* Handle unknown file types as regular files. */
577 if ((mtree->set.keys & F_TYPE) != 0 &&
578 mtree->set.type == AE_IFREG)
587 archive_write_mtree_header(struct archive_write *a,
588 struct archive_entry *entry)
590 struct mtree_writer *mtree= a->format_data;
591 struct archive_string *str;
594 mtree->entry = archive_entry_clone(entry);
595 path = archive_entry_pathname(mtree->entry);
599 archive_strcat(&mtree->buf, "#mtree\n");
601 if (mtree->set.output)
602 set_global(mtree, entry);
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);
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;
616 mtree->compute_sum &= ~F_CKSUM;
618 if ((mtree->keys & F_MD5) != 0 &&
619 archive_entry_filetype(entry) == AE_IFREG) {
620 mtree->compute_sum |= F_MD5;
621 MD5Init(&mtree->md5ctx);
623 mtree->compute_sum &= ~F_MD5;
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);
631 mtree->compute_sum &= ~F_RMD160;
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);
639 mtree->compute_sum &= ~F_SHA1;
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);
647 mtree->compute_sum &= ~F_SHA256;
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);
655 mtree->compute_sum &= ~F_SHA384;
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);
663 mtree->compute_sum &= ~F_SHA512;
669 #if defined(HAVE_MD5) || defined(HAVE_RMD160) || defined(HAVE_SHA1) || defined(HAVE_SHA256) || defined(HAVE_SHA384) || defined(HAVE_SHA512)
671 strappend_bin(struct archive_string *s, const unsigned char *bin, int n)
673 static const char hex[] = "0123456789abcdef";
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]);
684 archive_write_mtree_finish_entry(struct archive_write *a)
686 struct mtree_writer *mtree = a->format_data;
687 struct archive_entry *entry;
688 struct archive_string *str;
692 entry = mtree->entry;
694 archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
695 "Finished entry without being open first.");
696 return (ARCHIVE_FATAL);
700 if (mtree->dironly && archive_entry_filetype(entry) != AE_IFDIR) {
701 archive_entry_free(entry);
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));
713 if ((keys & F_GNAME) != 0 &&
714 (name = archive_entry_gname(entry)) != NULL) {
715 archive_strcat(str, " gname=");
716 mtree_quote(str, name);
718 if ((keys & F_UNAME) != 0 &&
719 (name = archive_entry_uname(entry)) != NULL) {
720 archive_strcat(str, " uname=");
721 mtree_quote(str, name);
723 if ((keys & F_FLAGS) != 0 &&
724 (name = archive_entry_fflags_text(entry)) != NULL) {
725 archive_strcat(str, " flags=");
726 mtree_quote(str, name);
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));
742 switch (archive_entry_filetype(entry)) {
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));
752 if ((keys & F_TYPE) != 0)
753 archive_strcat(str, " type=socket");
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));
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));
776 if ((keys & F_TYPE) != 0)
777 archive_strcat(str, " type=dir");
780 if ((keys & F_TYPE) != 0)
781 archive_strcat(str, " type=fifo");
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));
793 if (mtree->compute_sum & F_CKSUM) {
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);
803 if (mtree->compute_sum & F_MD5) {
804 unsigned char buf[16];
806 MD5Final(buf, &mtree->md5ctx);
807 archive_strcat(str, " md5digest=");
808 strappend_bin(str, buf, sizeof(buf));
812 if (mtree->compute_sum & F_RMD160) {
813 unsigned char buf[20];
815 RIPEMD160_Final(buf, &mtree->rmd160ctx);
816 archive_strcat(str, " rmd160digest=");
817 strappend_bin(str, buf, sizeof(buf));
821 if (mtree->compute_sum & F_SHA1) {
822 unsigned char buf[20];
824 SHA1_Final(buf, &mtree->sha1ctx);
825 archive_strcat(str, " sha1digest=");
826 strappend_bin(str, buf, sizeof(buf));
830 if (mtree->compute_sum & F_SHA256) {
831 unsigned char buf[32];
833 SHA256_Final(buf, &mtree->sha256ctx);
834 archive_strcat(str, " sha256digest=");
835 strappend_bin(str, buf, sizeof(buf));
839 if (mtree->compute_sum & F_SHA384) {
840 unsigned char buf[48];
842 SHA384_Final(buf, &mtree->sha384ctx);
843 archive_strcat(str, " sha384digest=");
844 strappend_bin(str, buf, sizeof(buf));
848 if (mtree->compute_sum & F_SHA512) {
849 unsigned char buf[64];
851 SHA512_Final(buf, &mtree->sha512ctx);
852 archive_strcat(str, " sha512digest=");
853 strappend_bin(str, buf, sizeof(buf));
856 archive_strcat(str, "\n");
860 archive_entry_free(entry);
862 if (mtree->buf.length > 32768) {
863 ret = (a->compressor.write)(a, mtree->buf.s, mtree->buf.length);
864 archive_string_empty(&mtree->buf);
868 return (ret == ARCHIVE_OK ? ret : ARCHIVE_FATAL);
872 archive_write_mtree_finish(struct archive_write *a)
874 struct mtree_writer *mtree= a->format_data;
876 archive_write_set_bytes_in_last_block(&a->archive, 1);
878 return (a->compressor.write)(a, mtree->buf.s, mtree->buf.length);
882 archive_write_mtree_data(struct archive_write *a, const void *buff, size_t n)
884 struct mtree_writer *mtree= a->format_data;
886 if (n > mtree->entry_bytes_remaining)
887 n = mtree->entry_bytes_remaining;
889 /* We don't need compute a regular file sum */
891 if (mtree->compute_sum & F_CKSUM) {
893 * Compute a POSIX 1003.2 checksum
895 const unsigned char *p;
898 for (nn = n, p = buff; nn--; ++p)
899 COMPUTE_CRC(mtree->crc, *p);
903 if (mtree->compute_sum & F_MD5)
904 MD5Update(&mtree->md5ctx, buff, n);
907 if (mtree->compute_sum & F_RMD160)
908 RIPEMD160_Update(&mtree->rmd160ctx, buff, n);
911 if (mtree->compute_sum & F_SHA1)
912 SHA1_Update(&mtree->sha1ctx, buff, n);
915 if (mtree->compute_sum & F_SHA256)
916 SHA256_Update(&mtree->sha256ctx, buff, n);
919 if (mtree->compute_sum & F_SHA384)
920 SHA384_Update(&mtree->sha384ctx, buff, n);
923 if (mtree->compute_sum & F_SHA512)
924 SHA512_Update(&mtree->sha512ctx, buff, n);
930 archive_write_mtree_destroy(struct archive_write *a)
932 struct mtree_writer *mtree= a->format_data;
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);
942 a->format_data = NULL;
947 archive_write_mtree_options(struct archive_write *a, const char *key,
950 struct mtree_writer *mtree= a->format_data;
955 if (strcmp(key, "all") == 0)
959 if (strcmp(key, "cksum") == 0)
963 if (strcmp(key, "device") == 0)
965 else if (strcmp(key, "dironly") == 0) {
966 mtree->dironly = (value != NULL)? 1: 0;
971 if (strcmp(key, "flags") == 0)
975 if (strcmp(key, "gid") == 0)
977 else if (strcmp(key, "gname") == 0)
981 if (strcmp(key, "indent") == 0) {
982 mtree->indent = (value != NULL)? 1: 0;
987 if (strcmp(key, "link") == 0)
992 if (strcmp(key, "md5") == 0 ||
993 strcmp(key, "md5digest") == 0)
996 if (strcmp(key, "mode") == 0)
1000 if (strcmp(key, "nlink") == 0)
1005 if (strcmp(key, "ripemd160digest") == 0 ||
1006 strcmp(key, "rmd160") == 0 ||
1007 strcmp(key, "rmd160digest") == 0)
1013 if (strcmp(key, "sha1") == 0 ||
1014 strcmp(key, "sha1digest") == 0)
1018 if (strcmp(key, "sha256") == 0 ||
1019 strcmp(key, "sha256digest") == 0)
1023 if (strcmp(key, "sha384") == 0 ||
1024 strcmp(key, "sha384digest") == 0)
1028 if (strcmp(key, "sha512") == 0 ||
1029 strcmp(key, "sha512digest") == 0)
1032 if (strcmp(key, "size") == 0)
1036 if (strcmp(key, "time") == 0)
1038 else if (strcmp(key, "type") == 0)
1042 if (strcmp(key, "uid") == 0)
1044 else if (strcmp(key, "uname") == 0)
1046 else if (strcmp(key, "use-set") == 0) {
1047 mtree->set.output = (value != NULL)? 1: 0;
1048 return (ARCHIVE_OK);
1054 mtree->keys |= keybit;
1056 mtree->keys &= ~keybit;
1057 return (ARCHIVE_OK);
1060 return (ARCHIVE_WARN);
1064 archive_write_set_format_mtree(struct archive *_a)
1066 struct archive_write *a = (struct archive_write *)_a;
1067 struct mtree_writer *mtree;
1069 if (a->format_destroy != NULL)
1070 (a->format_destroy)(a);
1072 if ((mtree = malloc(sizeof(*mtree))) == NULL) {
1073 archive_set_error(&a->archive, ENOMEM,
1074 "Can't allocate mtree data");
1075 return (ARCHIVE_FATAL);
1078 mtree->entry = NULL;
1080 memset(&(mtree->set), 0, sizeof(mtree->set));
1081 archive_string_init(&mtree->set.parent);
1082 mtree->keys = DEFAULT_KEYS;
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;
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";
1100 return (ARCHIVE_OK);