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: 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>
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
48 struct archive_entry
*entry
;
49 struct archive_string ebuf
;
50 struct archive_string buf
;
52 uint64_t entry_bytes_remaining
;
56 struct archive_string parent
;
62 unsigned long fflags_set
;
63 unsigned long fflags_clear
;
69 #ifdef ARCHIVE_HAS_MD5
70 archive_md5_ctx md5ctx
;
72 #ifdef ARCHIVE_HAS_RMD160
73 archive_rmd160_ctx rmd160ctx
;
75 #ifdef ARCHIVE_HAS_SHA1
76 archive_sha1_ctx sha1ctx
;
78 #ifdef ARCHIVE_HAS_SHA256
79 archive_sha256_ctx sha256ctx
;
81 #ifdef ARCHIVE_HAS_SHA384
82 archive_sha384_ctx sha384ctx
;
84 #ifdef ARCHIVE_HAS_SHA512
85 archive_sha512_ctx sha512ctx
;
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
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 */
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\
128 #define COMPUTE_CRC(var, ch) (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)]
129 static const uint32_t crctab
[] = {
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
185 mtree_safe_char(char c
)
187 if ((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z'))
189 if (c
>= '0' && c
<= '9')
191 if (c
== 35 || c
== 61 || c
== 92)
192 return 0; /* #, = and \ are always quoted */
194 if (c
>= 33 && c
<= 47) /* !"$%&'()*+,-./ */
196 if (c
>= 58 && c
<= 64) /* :;<>?@ */
198 if (c
>= 91 && c
<= 96) /* []^_` */
200 if (c
>= 123 && c
<= 126) /* {|}~ */
206 mtree_quote(struct archive_string
*s
, const char *str
)
212 for (start
= str
; *str
!= '\0'; ++str
) {
213 if (mtree_safe_char(*str
))
216 archive_strncat(s
, start
, str
- start
);
217 c
= (unsigned char)*str
;
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);
227 archive_strncat(s
, start
, str
- start
);
231 mtree_indent(struct mtree_writer
*mtree
)
234 const char *r
, *s
, *x
;
237 s
= r
= mtree
->ebuf
.s
;
241 while ((r
= strchr(r
, ' ')) != NULL
) {
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
, ' ');
250 for (i
= r
-s
; i
< (INDENTNAMELEN
+ 1); i
++)
251 archive_strappend_char(&mtree
->buf
, ' ');
257 if (r
- s
<= MAXLINELEN
- 3 - INDENTNAMELEN
)
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
, ' ');
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
, ' ');
278 archive_strcat(&mtree
->buf
, s
);
279 archive_string_empty(&mtree
->ebuf
);
282 #if !defined(_WIN32) || defined(__CYGWIN__)
284 dir_len(struct archive_entry
*entry
)
286 const char *path
, *r
;
288 path
= archive_entry_pathname(entry
);
289 r
= strrchr(path
, '/');
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
304 dir_len(struct archive_entry
*entry
)
311 path
= archive_entry_pathname(entry
);
313 for (p
= path
; *p
!= '\0'; ++p
) {
324 l
= mbtowc(&wc
, p
, size
);
327 if (l
== 1 && (wc
== L
'/' || wc
== L
'\\'))
332 return (rp
- path
+ 1);
338 #endif /* _WIN32 && !__CYGWIN__ */
341 parent_dir_changed(struct archive_string
*dir
, struct archive_entry
*entry
)
347 path
= archive_entry_pathname(entry
);
348 if (archive_strlen(dir
) > 0) {
350 archive_string_empty(dir
);
353 if (strncmp(dir
->s
, path
, l
) == 0)
354 return (0); /* The parent directory is the same. */
356 return (0); /* The parent directory is the same. */
357 archive_strncpy(dir
, path
, l
);
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
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.
374 set_global(struct mtree_writer
*mtree
, struct archive_entry
*entry
)
376 struct archive_string setstr
;
377 struct archive_string unsetstr
;
379 int keys
, oldkeys
, effkeys
;
382 switch (archive_entry_filetype(entry
)) {
383 case AE_IFLNK
: case AE_IFSOCK
: case AE_IFCHR
:
384 case AE_IFBLK
: case AE_IFIFO
:
391 default: /* Handle unknown file types as regular files. */
398 if (mtree
->set
.processed
&&
399 !parent_dir_changed(&mtree
->set
.parent
, entry
))
401 /* At first, save a parent directory of the entry for following
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
;
412 if (mtree
->set
.processed
) {
414 * Check the global datas for whether it needs updating.
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))
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
)
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");
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");
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");
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");
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. */
496 mtree
->set
.output
= 0;
500 get_keys(struct mtree_writer
*mtree
, struct archive_entry
*entry
)
505 if (mtree
->set
.keys
== 0)
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
)
521 if ((mtree
->set
.keys
& F_MODE
) != 0 &&
522 mtree
->set
.mode
== (archive_entry_mode(entry
) & 07777))
525 switch (archive_entry_filetype(entry
)) {
526 case AE_IFLNK
: case AE_IFSOCK
: case AE_IFCHR
:
527 case AE_IFBLK
: case AE_IFIFO
:
530 if ((mtree
->set
.keys
& F_TYPE
) != 0 &&
531 mtree
->set
.type
== AE_IFDIR
)
535 default: /* Handle unknown file types as regular files. */
536 if ((mtree
->set
.keys
& F_TYPE
) != 0 &&
537 mtree
->set
.type
== AE_IFREG
)
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
;
553 mtree
->entry
= archive_entry_clone(entry
);
554 path
= archive_entry_pathname(mtree
->entry
);
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
;
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
);
582 mtree
->compute_sum
&= ~F_MD5
;
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
);
590 mtree
->compute_sum
&= ~F_RMD160
;
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
);
598 mtree
->compute_sum
&= ~F_SHA1
;
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
);
606 mtree
->compute_sum
&= ~F_SHA256
;
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
);
614 mtree
->compute_sum
&= ~F_SHA384
;
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
);
622 mtree
->compute_sum
&= ~F_SHA512
;
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)
632 strappend_bin(struct archive_string
*s
, const unsigned char *bin
, int n
)
634 static const char hex
[] = "0123456789abcdef";
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]);
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
;
653 entry
= mtree
->entry
;
655 archive_set_error(&a
->archive
, ARCHIVE_ERRNO_PROGRAMMER
,
656 "Finished entry without being open first.");
657 return (ARCHIVE_FATAL
);
661 if (mtree
->dironly
&& archive_entry_filetype(entry
) != AE_IFDIR
) {
662 archive_entry_free(entry
);
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
)) {
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
));
713 if ((keys
& F_TYPE
) != 0)
714 archive_strcat(str
, " type=socket");
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
));
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
));
737 if ((keys
& F_TYPE
) != 0)
738 archive_strcat(str
, " type=dir");
741 if ((keys
& F_TYPE
) != 0)
742 archive_strcat(str
, " type=fifo");
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
));
754 if (mtree
->compute_sum
& F_CKSUM
) {
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
));
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
));
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
));
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
));
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
));
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
));
817 archive_strcat(str
, "\n");
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
);
829 return (ret
== ARCHIVE_OK
? ret
: ARCHIVE_FATAL
);
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
);
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
;
850 /* We don't need compute a regular file sum */
852 if (mtree
->compute_sum
& F_CKSUM
) {
854 * Compute a POSIX 1003.2 checksum
856 const unsigned char *p
;
859 for (nn
= n
, p
= buff
; nn
--; ++p
)
860 COMPUTE_CRC(mtree
->crc
, *p
);
863 #ifdef ARCHIVE_HAS_MD5
864 if (mtree
->compute_sum
& F_MD5
)
865 archive_md5_update(&mtree
->md5ctx
, buff
, n
);
867 #ifdef ARCHIVE_HAS_RMD160
868 if (mtree
->compute_sum
& F_RMD160
)
869 archive_rmd160_update(&mtree
->rmd160ctx
, buff
, n
);
871 #ifdef ARCHIVE_HAS_SHA1
872 if (mtree
->compute_sum
& F_SHA1
)
873 archive_sha1_update(&mtree
->sha1ctx
, buff
, n
);
875 #ifdef ARCHIVE_HAS_SHA256
876 if (mtree
->compute_sum
& F_SHA256
)
877 archive_sha256_update(&mtree
->sha256ctx
, buff
, n
);
879 #ifdef ARCHIVE_HAS_SHA384
880 if (mtree
->compute_sum
& F_SHA384
)
881 archive_sha384_update(&mtree
->sha384ctx
, buff
, n
);
883 #ifdef ARCHIVE_HAS_SHA512
884 if (mtree
->compute_sum
& F_SHA512
)
885 archive_sha512_update(&mtree
->sha512ctx
, buff
, n
);
891 archive_write_mtree_destroy(struct archive_write
*a
)
893 struct mtree_writer
*mtree
= a
->format_data
;
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
);
903 a
->format_data
= NULL
;
908 archive_write_mtree_options(struct archive_write
*a
, const char *key
,
911 struct mtree_writer
*mtree
= a
->format_data
;
916 if (strcmp(key
, "all") == 0)
920 if (strcmp(key
, "cksum") == 0)
924 if (strcmp(key
, "device") == 0)
926 else if (strcmp(key
, "dironly") == 0) {
927 mtree
->dironly
= (value
!= NULL
)? 1: 0;
932 if (strcmp(key
, "flags") == 0)
936 if (strcmp(key
, "gid") == 0)
938 else if (strcmp(key
, "gname") == 0)
942 if (strcmp(key
, "indent") == 0) {
943 mtree
->indent
= (value
!= NULL
)? 1: 0;
948 if (strcmp(key
, "link") == 0)
952 if (strcmp(key
, "md5") == 0 ||
953 strcmp(key
, "md5digest") == 0)
955 if (strcmp(key
, "mode") == 0)
959 if (strcmp(key
, "nlink") == 0)
963 if (strcmp(key
, "ripemd160digest") == 0 ||
964 strcmp(key
, "rmd160") == 0 ||
965 strcmp(key
, "rmd160digest") == 0)
969 if (strcmp(key
, "sha1") == 0 ||
970 strcmp(key
, "sha1digest") == 0)
972 if (strcmp(key
, "sha256") == 0 ||
973 strcmp(key
, "sha256digest") == 0)
975 if (strcmp(key
, "sha384") == 0 ||
976 strcmp(key
, "sha384digest") == 0)
978 if (strcmp(key
, "sha512") == 0 ||
979 strcmp(key
, "sha512digest") == 0)
981 if (strcmp(key
, "size") == 0)
985 if (strcmp(key
, "time") == 0)
987 else if (strcmp(key
, "type") == 0)
991 if (strcmp(key
, "uid") == 0)
993 else if (strcmp(key
, "uname") == 0)
995 else if (strcmp(key
, "use-set") == 0) {
996 mtree
->set
.output
= (value
!= NULL
)? 1: 0;
1003 mtree
->keys
|= keybit
;
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
;
1029 memset(&(mtree
->set
), 0, sizeof(mtree
->set
));
1030 archive_string_init(&mtree
->set
.parent
);
1031 mtree
->keys
= DEFAULT_KEYS
;
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
);