1228753Smm/*- 2228753Smm * Copyright (c) 2009 Michihiro NAKAJIMA 3228753Smm * Copyright (c) 2008 Joerg Sonnenberger 4228753Smm * All rights reserved. 5228753Smm * 6228753Smm * Redistribution and use in source and binary forms, with or without 7228753Smm * modification, are permitted provided that the following conditions 8228753Smm * are met: 9228753Smm * 1. Redistributions of source code must retain the above copyright 10228753Smm * notice, this list of conditions and the following disclaimer. 11228753Smm * 2. Redistributions in binary form must reproduce the above copyright 12228753Smm * notice, this list of conditions and the following disclaimer in the 13228753Smm * documentation and/or other materials provided with the distribution. 14228753Smm * 15228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25228753Smm */ 26228753Smm 27228753Smm#include "archive_platform.h" 28229592Smm__FBSDID("$FreeBSD$"); 29228753Smm 30228753Smm#ifdef HAVE_SYS_TYPES_H 31228753Smm#include <sys/types.h> 32228753Smm#endif 33228753Smm#include <errno.h> 34228753Smm#include <stdlib.h> 35228753Smm#include <string.h> 36228753Smm 37228753Smm#include "archive.h" 38228753Smm#include "archive_entry.h" 39228753Smm#include "archive_private.h" 40228753Smm#include "archive_write_private.h" 41228753Smm 42228753Smm#include "archive_hash.h" 43228753Smm 44228753Smm#define INDENTNAMELEN 15 45228753Smm#define MAXLINELEN 80 46228753Smm 47228753Smmstruct mtree_writer { 48228753Smm struct archive_entry *entry; 49228753Smm struct archive_string ebuf; 50228753Smm struct archive_string buf; 51228753Smm int first; 52228753Smm uint64_t entry_bytes_remaining; 53228753Smm struct { 54228753Smm int output; 55228753Smm int processed; 56228753Smm struct archive_string parent; 57228753Smm mode_t type; 58228753Smm int keys; 59228753Smm uid_t uid; 60228753Smm gid_t gid; 61228753Smm mode_t mode; 62228753Smm unsigned long fflags_set; 63228753Smm unsigned long fflags_clear; 64228753Smm } set; 65228753Smm /* chekc sum */ 66228753Smm int compute_sum; 67228753Smm uint32_t crc; 68228753Smm uint64_t crc_len; 69228753Smm#ifdef ARCHIVE_HAS_MD5 70228753Smm archive_md5_ctx md5ctx; 71228753Smm#endif 72228753Smm#ifdef ARCHIVE_HAS_RMD160 73228753Smm archive_rmd160_ctx rmd160ctx; 74228753Smm#endif 75228753Smm#ifdef ARCHIVE_HAS_SHA1 76228753Smm archive_sha1_ctx sha1ctx; 77228753Smm#endif 78228753Smm#ifdef ARCHIVE_HAS_SHA256 79228753Smm archive_sha256_ctx sha256ctx; 80228753Smm#endif 81228753Smm#ifdef ARCHIVE_HAS_SHA384 82228753Smm archive_sha384_ctx sha384ctx; 83228753Smm#endif 84228753Smm#ifdef ARCHIVE_HAS_SHA512 85228753Smm archive_sha512_ctx sha512ctx; 86228753Smm#endif 87228753Smm /* Keyword options */ 88228753Smm int keys; 89228753Smm#define F_CKSUM 0x00000001 /* check sum */ 90228753Smm#define F_DEV 0x00000002 /* device type */ 91228753Smm#define F_DONE 0x00000004 /* directory done */ 92228753Smm#define F_FLAGS 0x00000008 /* file flags */ 93228753Smm#define F_GID 0x00000010 /* gid */ 94228753Smm#define F_GNAME 0x00000020 /* group name */ 95228753Smm#define F_IGN 0x00000040 /* ignore */ 96228753Smm#define F_MAGIC 0x00000080 /* name has magic chars */ 97228753Smm#define F_MD5 0x00000100 /* MD5 digest */ 98228753Smm#define F_MODE 0x00000200 /* mode */ 99228753Smm#define F_NLINK 0x00000400 /* number of links */ 100228753Smm#define F_NOCHANGE 0x00000800 /* If owner/mode "wrong", do 101228753Smm * not change */ 102228753Smm#define F_OPT 0x00001000 /* existence optional */ 103228753Smm#define F_RMD160 0x00002000 /* RIPEMD160 digest */ 104228753Smm#define F_SHA1 0x00004000 /* SHA-1 digest */ 105228753Smm#define F_SIZE 0x00008000 /* size */ 106228753Smm#define F_SLINK 0x00010000 /* symbolic link */ 107228753Smm#define F_TAGS 0x00020000 /* tags */ 108228753Smm#define F_TIME 0x00040000 /* modification time */ 109228753Smm#define F_TYPE 0x00080000 /* file type */ 110228753Smm#define F_UID 0x00100000 /* uid */ 111228753Smm#define F_UNAME 0x00200000 /* user name */ 112228753Smm#define F_VISIT 0x00400000 /* file visited */ 113228753Smm#define F_SHA256 0x00800000 /* SHA-256 digest */ 114228753Smm#define F_SHA384 0x01000000 /* SHA-384 digest */ 115228753Smm#define F_SHA512 0x02000000 /* SHA-512 digest */ 116228753Smm 117228753Smm /* Options */ 118228753Smm int dironly; /* if the dironly is 1, ignore everything except 119228753Smm * directory type files. like mtree(8) -d option. 120228753Smm */ 121228753Smm int indent; /* if the indent is 1, indent writing data. */ 122228753Smm}; 123228753Smm 124228753Smm#define DEFAULT_KEYS (F_DEV | F_FLAGS | F_GID | F_GNAME | F_SLINK | F_MODE\ 125228753Smm | F_NLINK | F_SIZE | F_TIME | F_TYPE | F_UID\ 126228753Smm | F_UNAME) 127228753Smm 128228753Smm#define COMPUTE_CRC(var, ch) (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)] 129228753Smmstatic const uint32_t crctab[] = { 130228753Smm 0x0, 131228753Smm 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 132228753Smm 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 133228753Smm 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 134228753Smm 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 135228753Smm 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 136228753Smm 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 137228753Smm 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 138228753Smm 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 139228753Smm 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 140228753Smm 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, 141228753Smm 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, 142228753Smm 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 143228753Smm 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 144228753Smm 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 145228753Smm 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 146228753Smm 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 147228753Smm 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 148228753Smm 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 149228753Smm 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 150228753Smm 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 151228753Smm 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 152228753Smm 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 153228753Smm 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 154228753Smm 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, 155228753Smm 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 156228753Smm 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 157228753Smm 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 158228753Smm 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 159228753Smm 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, 160228753Smm 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 161228753Smm 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 162228753Smm 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 163228753Smm 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 164228753Smm 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 165228753Smm 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, 166228753Smm 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 167228753Smm 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 168228753Smm 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 169228753Smm 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 170228753Smm 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 171228753Smm 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 172228753Smm 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, 173228753Smm 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 174228753Smm 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 175228753Smm 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 176228753Smm 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 177228753Smm 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 178228753Smm 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, 179228753Smm 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 180228753Smm 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 181228753Smm 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 182228753Smm}; 183228753Smm 184228753Smmstatic int 185228753Smmmtree_safe_char(char c) 186228753Smm{ 187228753Smm if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) 188228753Smm return 1; 189228753Smm if (c >= '0' && c <= '9') 190228753Smm return 1; 191228753Smm if (c == 35 || c == 61 || c == 92) 192228753Smm return 0; /* #, = and \ are always quoted */ 193228753Smm 194228753Smm if (c >= 33 && c <= 47) /* !"$%&'()*+,-./ */ 195228753Smm return 1; 196228753Smm if (c >= 58 && c <= 64) /* :;<>?@ */ 197228753Smm return 1; 198228753Smm if (c >= 91 && c <= 96) /* []^_` */ 199228753Smm return 1; 200228753Smm if (c >= 123 && c <= 126) /* {|}~ */ 201228753Smm return 1; 202228753Smm return 0; 203228753Smm} 204228753Smm 205228753Smmstatic void 206228753Smmmtree_quote(struct archive_string *s, const char *str) 207228753Smm{ 208228753Smm const char *start; 209228753Smm char buf[4]; 210228753Smm unsigned char c; 211228753Smm 212228753Smm for (start = str; *str != '\0'; ++str) { 213228753Smm if (mtree_safe_char(*str)) 214228753Smm continue; 215228753Smm if (start != str) 216228753Smm archive_strncat(s, start, str - start); 217228753Smm c = (unsigned char)*str; 218228753Smm buf[0] = '\\'; 219228753Smm buf[1] = (c / 64) + '0'; 220228753Smm buf[2] = (c / 8 % 8) + '0'; 221228753Smm buf[3] = (c % 8) + '0'; 222228753Smm archive_strncat(s, buf, 4); 223228753Smm start = str + 1; 224228753Smm } 225228753Smm 226228753Smm if (start != str) 227228753Smm archive_strncat(s, start, str - start); 228228753Smm} 229228753Smm 230228753Smmstatic void 231228753Smmmtree_indent(struct mtree_writer *mtree) 232228753Smm{ 233228753Smm int i, fn; 234228753Smm const char *r, *s, *x; 235228753Smm 236228753Smm fn = 1; 237228753Smm s = r = mtree->ebuf.s; 238228753Smm x = NULL; 239228753Smm while (*r == ' ') 240228753Smm r++; 241228753Smm while ((r = strchr(r, ' ')) != NULL) { 242228753Smm if (fn) { 243228753Smm fn = 0; 244228753Smm archive_strncat(&mtree->buf, s, r - s); 245228753Smm if (r -s > INDENTNAMELEN) { 246228753Smm archive_strncat(&mtree->buf, " \\\n", 3); 247228753Smm for (i = 0; i < (INDENTNAMELEN + 1); i++) 248228753Smm archive_strappend_char(&mtree->buf, ' '); 249228753Smm } else { 250228753Smm for (i = r -s; i < (INDENTNAMELEN + 1); i++) 251228753Smm archive_strappend_char(&mtree->buf, ' '); 252228753Smm } 253228753Smm s = ++r; 254228753Smm x = NULL; 255228753Smm continue; 256228753Smm } 257228753Smm if (r - s <= MAXLINELEN - 3 - INDENTNAMELEN) 258228753Smm x = r++; 259228753Smm else { 260228753Smm if (x == NULL) 261228753Smm x = r; 262228753Smm archive_strncat(&mtree->buf, s, x - s); 263228753Smm archive_strncat(&mtree->buf, " \\\n", 3); 264228753Smm for (i = 0; i < (INDENTNAMELEN + 1); i++) 265228753Smm archive_strappend_char(&mtree->buf, ' '); 266228753Smm s = r = ++x; 267228753Smm x = NULL; 268228753Smm } 269228753Smm } 270228753Smm if (x != NULL && strlen(s) > MAXLINELEN - 3 - INDENTNAMELEN) { 271228753Smm /* Last keyword is longer. */ 272228753Smm archive_strncat(&mtree->buf, s, x - s); 273228753Smm archive_strncat(&mtree->buf, " \\\n", 3); 274228753Smm for (i = 0; i < (INDENTNAMELEN + 1); i++) 275228753Smm archive_strappend_char(&mtree->buf, ' '); 276228753Smm s = ++x; 277228753Smm } 278228753Smm archive_strcat(&mtree->buf, s); 279228753Smm archive_string_empty(&mtree->ebuf); 280228753Smm} 281228753Smm 282228753Smm#if !defined(_WIN32) || defined(__CYGWIN__) 283228753Smmstatic size_t 284228753Smmdir_len(struct archive_entry *entry) 285228753Smm{ 286228753Smm const char *path, *r; 287228753Smm 288228753Smm path = archive_entry_pathname(entry); 289228753Smm r = strrchr(path, '/'); 290228753Smm if (r == NULL) 291228753Smm return (0); 292228753Smm /* Include a separator size */ 293228753Smm return (r - path + 1); 294228753Smm} 295228753Smm 296228753Smm#else /* _WIN32 && !__CYGWIN__ */ 297228753Smm/* 298228753Smm * Note: We should use wide-character for findng '\' character, 299228753Smm * a directory separator on Windows, because some character-set have 300228753Smm * been using the '\' character for a part of its multibyte character 301228753Smm * code. 302228753Smm */ 303228753Smmstatic size_t 304228753Smmdir_len(struct archive_entry *entry) 305228753Smm{ 306228753Smm wchar_t wc; 307228753Smm const char *path; 308228753Smm const char *p, *rp; 309228753Smm size_t al, l, size; 310228753Smm 311228753Smm path = archive_entry_pathname(entry); 312228753Smm al = l = -1; 313228753Smm for (p = path; *p != '\0'; ++p) { 314228753Smm if (*p == '\\') 315228753Smm al = l = p - path; 316228753Smm else if (*p == '/') 317228753Smm al = p - path; 318228753Smm } 319228753Smm if (l == -1) 320228753Smm goto alen; 321228753Smm size = p - path; 322228753Smm rp = p = path; 323228753Smm while (*p != '\0') { 324228753Smm l = mbtowc(&wc, p, size); 325228753Smm if (l == -1) 326228753Smm goto alen; 327228753Smm if (l == 1 && (wc == L'/' || wc == L'\\')) 328228753Smm rp = p; 329228753Smm p += l; 330228753Smm size -= l; 331228753Smm } 332228753Smm return (rp - path + 1); 333228753Smmalen: 334228753Smm if (al == -1) 335228753Smm return (0); 336228753Smm return (al + 1); 337228753Smm} 338228753Smm#endif /* _WIN32 && !__CYGWIN__ */ 339228753Smm 340228753Smmstatic int 341228753Smmparent_dir_changed(struct archive_string *dir, struct archive_entry *entry) 342228753Smm{ 343228753Smm const char *path; 344228753Smm size_t l; 345228753Smm 346228753Smm l = dir_len(entry); 347228753Smm path = archive_entry_pathname(entry); 348228753Smm if (archive_strlen(dir) > 0) { 349228753Smm if (l == 0) { 350228753Smm archive_string_empty(dir); 351228753Smm return (1); 352228753Smm } 353228753Smm if (strncmp(dir->s, path, l) == 0) 354228753Smm return (0); /* The parent directory is the same. */ 355228753Smm } else if (l == 0) 356228753Smm return (0); /* The parent directory is the same. */ 357228753Smm archive_strncpy(dir, path, l); 358228753Smm return (1); 359228753Smm} 360228753Smm 361228753Smm/* 362228753Smm * Write /set keyword. It means set global datas. 363228753Smm * [directory-only mode] 364228753Smm * - It is only once to write /set keyword. It is using values of the 365228753Smm * first entry. 366228753Smm * [normal mode] 367228753Smm * - Write /set keyword. It is using values of the first entry whose 368228753Smm * filetype is a regular file. 369228753Smm * - When a parent directory of the entry whose filetype is the regular 370228753Smm * file is changed, check the global datas and write it again if its 371228753Smm * values are different from the entry's. 372228753Smm */ 373228753Smmstatic void 374228753Smmset_global(struct mtree_writer *mtree, struct archive_entry *entry) 375228753Smm{ 376228753Smm struct archive_string setstr; 377228753Smm struct archive_string unsetstr; 378228753Smm const char *name; 379228753Smm int keys, oldkeys, effkeys; 380228753Smm mode_t set_type = 0; 381228753Smm 382228753Smm switch (archive_entry_filetype(entry)) { 383228753Smm case AE_IFLNK: case AE_IFSOCK: case AE_IFCHR: 384228753Smm case AE_IFBLK: case AE_IFIFO: 385228753Smm break; 386228753Smm case AE_IFDIR: 387228753Smm if (mtree->dironly) 388228753Smm set_type = AE_IFDIR; 389228753Smm break; 390228753Smm case AE_IFREG: 391228753Smm default: /* Handle unknown file types as regular files. */ 392228753Smm if (!mtree->dironly) 393228753Smm set_type = AE_IFREG; 394228753Smm break; 395228753Smm } 396228753Smm if (set_type == 0) 397228753Smm return; 398228753Smm if (mtree->set.processed && 399228753Smm !parent_dir_changed(&mtree->set.parent, entry)) 400228753Smm return; 401228753Smm /* At first, save a parent directory of the entry for following 402228753Smm * entries. */ 403228753Smm if (!mtree->set.processed && set_type == AE_IFREG) 404228753Smm parent_dir_changed(&mtree->set.parent, entry); 405228753Smm 406228753Smm archive_string_init(&setstr); 407228753Smm archive_string_init(&unsetstr); 408228753Smm keys = mtree->keys & (F_FLAGS | F_GID | F_GNAME | F_NLINK | F_MODE 409228753Smm | F_TYPE | F_UID | F_UNAME); 410228753Smm oldkeys = mtree->set.keys; 411228753Smm effkeys = keys; 412228753Smm if (mtree->set.processed) { 413228753Smm /* 414228753Smm * Check the global datas for whether it needs updating. 415228753Smm */ 416228753Smm effkeys &= ~F_TYPE; 417228753Smm if ((oldkeys & (F_UNAME | F_UID)) != 0 && 418228753Smm mtree->set.uid == archive_entry_uid(entry)) 419228753Smm effkeys &= ~(F_UNAME | F_UID); 420228753Smm if ((oldkeys & (F_GNAME | F_GID)) != 0 && 421228753Smm mtree->set.gid == archive_entry_gid(entry)) 422228753Smm effkeys &= ~(F_GNAME | F_GID); 423228753Smm if ((oldkeys & F_MODE) != 0 && 424228753Smm mtree->set.mode == (archive_entry_mode(entry) & 07777)) 425228753Smm effkeys &= ~F_MODE; 426228753Smm if ((oldkeys & F_FLAGS) != 0) { 427228753Smm unsigned long fflags_set; 428228753Smm unsigned long fflags_clear; 429228753Smm 430228753Smm archive_entry_fflags(entry, &fflags_set, &fflags_clear); 431228753Smm if (fflags_set == mtree->set.fflags_set && 432228753Smm fflags_clear == mtree->set.fflags_clear) 433228753Smm effkeys &= ~F_FLAGS; 434228753Smm } 435228753Smm } 436228753Smm if ((keys & effkeys & F_TYPE) != 0) { 437228753Smm mtree->set.type = set_type; 438228753Smm if (set_type == AE_IFDIR) 439228753Smm archive_strcat(&setstr, " type=dir"); 440228753Smm else 441228753Smm archive_strcat(&setstr, " type=file"); 442228753Smm } 443228753Smm if ((keys & effkeys & F_UNAME) != 0) { 444228753Smm if ((name = archive_entry_uname(entry)) != NULL) { 445228753Smm archive_strcat(&setstr, " uname="); 446228753Smm mtree_quote(&setstr, name); 447228753Smm } else if ((oldkeys & F_UNAME) != 0) 448228753Smm archive_strcat(&unsetstr, " uname"); 449228753Smm else 450228753Smm keys &= ~F_UNAME; 451228753Smm } 452228753Smm if ((keys & effkeys & F_UID) != 0) { 453228753Smm mtree->set.uid = archive_entry_uid(entry); 454228753Smm archive_string_sprintf(&setstr, " uid=%jd", 455228753Smm (intmax_t)mtree->set.uid); 456228753Smm } 457228753Smm if ((keys & effkeys & F_GNAME) != 0) { 458228753Smm if ((name = archive_entry_gname(entry)) != NULL) { 459228753Smm archive_strcat(&setstr, " gname="); 460228753Smm mtree_quote(&setstr, name); 461228753Smm } else if ((oldkeys & F_GNAME) != 0) 462228753Smm archive_strcat(&unsetstr, " gname"); 463228753Smm else 464228753Smm keys &= ~F_GNAME; 465228753Smm } 466228753Smm if ((keys & effkeys & F_GID) != 0) { 467228753Smm mtree->set.gid = archive_entry_gid(entry); 468228753Smm archive_string_sprintf(&setstr, " gid=%jd", 469228753Smm (intmax_t)mtree->set.gid); 470228753Smm } 471228753Smm if ((keys & effkeys & F_MODE) != 0) { 472228753Smm mtree->set.mode = archive_entry_mode(entry) & 07777; 473228753Smm archive_string_sprintf(&setstr, " mode=%o", mtree->set.mode); 474228753Smm } 475228753Smm if ((keys & effkeys & F_FLAGS) != 0) { 476228753Smm if ((name = archive_entry_fflags_text(entry)) != NULL) { 477228753Smm archive_strcat(&setstr, " flags="); 478228753Smm mtree_quote(&setstr, name); 479228753Smm archive_entry_fflags(entry, &mtree->set.fflags_set, 480228753Smm &mtree->set.fflags_clear); 481228753Smm } else if ((oldkeys & F_FLAGS) != 0) 482228753Smm archive_strcat(&unsetstr, " flags"); 483228753Smm else 484228753Smm keys &= ~F_FLAGS; 485228753Smm } 486228753Smm if (unsetstr.length > 0) 487228753Smm archive_string_sprintf(&mtree->buf, "/unset%s\n", unsetstr.s); 488228753Smm archive_string_free(&unsetstr); 489228753Smm if (setstr.length > 0) 490228753Smm archive_string_sprintf(&mtree->buf, "/set%s\n", setstr.s); 491228753Smm archive_string_free(&setstr); 492228753Smm mtree->set.keys = keys; 493228753Smm mtree->set.processed = 1; 494228753Smm /* On directory-only mode, it is only once to write /set keyword. */ 495228753Smm if (mtree->dironly) 496228753Smm mtree->set.output = 0; 497228753Smm} 498228753Smm 499228753Smmstatic int 500228753Smmget_keys(struct mtree_writer *mtree, struct archive_entry *entry) 501228753Smm{ 502228753Smm int keys; 503228753Smm 504228753Smm keys = mtree->keys; 505228753Smm if (mtree->set.keys == 0) 506228753Smm return (keys); 507228753Smm if ((mtree->set.keys & (F_GNAME | F_GID)) != 0 && 508228753Smm mtree->set.gid == archive_entry_gid(entry)) 509228753Smm keys &= ~(F_GNAME | F_GID); 510228753Smm if ((mtree->set.keys & (F_UNAME | F_UID)) != 0 && 511228753Smm mtree->set.uid == archive_entry_uid(entry)) 512228753Smm keys &= ~(F_UNAME | F_UID); 513228753Smm if (mtree->set.keys & F_FLAGS) { 514228753Smm unsigned long set, clear; 515228753Smm 516228753Smm archive_entry_fflags(entry, &set, &clear); 517228753Smm if (mtree->set.fflags_set == set && 518228753Smm mtree->set.fflags_clear == clear) 519228753Smm keys &= ~F_FLAGS; 520228753Smm } 521228753Smm if ((mtree->set.keys & F_MODE) != 0 && 522228753Smm mtree->set.mode == (archive_entry_mode(entry) & 07777)) 523228753Smm keys &= ~F_MODE; 524228753Smm 525228753Smm switch (archive_entry_filetype(entry)) { 526228753Smm case AE_IFLNK: case AE_IFSOCK: case AE_IFCHR: 527228753Smm case AE_IFBLK: case AE_IFIFO: 528228753Smm break; 529228753Smm case AE_IFDIR: 530228753Smm if ((mtree->set.keys & F_TYPE) != 0 && 531228753Smm mtree->set.type == AE_IFDIR) 532228753Smm keys &= ~F_TYPE; 533228753Smm break; 534228753Smm case AE_IFREG: 535228753Smm default: /* Handle unknown file types as regular files. */ 536228753Smm if ((mtree->set.keys & F_TYPE) != 0 && 537228753Smm mtree->set.type == AE_IFREG) 538228753Smm keys &= ~F_TYPE; 539228753Smm break; 540228753Smm } 541228753Smm 542228753Smm return (keys); 543228753Smm} 544228753Smm 545228753Smmstatic int 546228753Smmarchive_write_mtree_header(struct archive_write *a, 547228753Smm struct archive_entry *entry) 548228753Smm{ 549228753Smm struct mtree_writer *mtree= a->format_data; 550228753Smm struct archive_string *str; 551228753Smm const char *path; 552228753Smm 553228753Smm mtree->entry = archive_entry_clone(entry); 554228753Smm path = archive_entry_pathname(mtree->entry); 555228753Smm 556228753Smm if (mtree->first) { 557228753Smm mtree->first = 0; 558228753Smm archive_strcat(&mtree->buf, "#mtree\n"); 559228753Smm } 560228753Smm if (mtree->set.output) 561228753Smm set_global(mtree, entry); 562228753Smm 563228753Smm archive_string_empty(&mtree->ebuf); 564228753Smm str = (mtree->indent)? &mtree->ebuf : &mtree->buf; 565228753Smm if (!mtree->dironly || archive_entry_filetype(entry) == AE_IFDIR) 566228753Smm mtree_quote(str, path); 567228753Smm 568228753Smm mtree->entry_bytes_remaining = archive_entry_size(entry); 569228753Smm if ((mtree->keys & F_CKSUM) != 0 && 570228753Smm archive_entry_filetype(entry) == AE_IFREG) { 571228753Smm mtree->compute_sum |= F_CKSUM; 572228753Smm mtree->crc = 0; 573228753Smm mtree->crc_len = 0; 574228753Smm } else 575228753Smm mtree->compute_sum &= ~F_CKSUM; 576228753Smm#ifdef ARCHIVE_HAS_MD5 577228753Smm if ((mtree->keys & F_MD5) != 0 && 578228753Smm archive_entry_filetype(entry) == AE_IFREG) { 579228753Smm mtree->compute_sum |= F_MD5; 580228753Smm archive_md5_init(&mtree->md5ctx); 581228753Smm } else 582228753Smm mtree->compute_sum &= ~F_MD5; 583228753Smm#endif 584228753Smm#ifdef ARCHIVE_HAS_RMD160 585228753Smm if ((mtree->keys & F_RMD160) != 0 && 586228753Smm archive_entry_filetype(entry) == AE_IFREG) { 587228753Smm mtree->compute_sum |= F_RMD160; 588228753Smm archive_rmd160_init(&mtree->rmd160ctx); 589228753Smm } else 590228753Smm mtree->compute_sum &= ~F_RMD160; 591228753Smm#endif 592228753Smm#ifdef ARCHIVE_HAS_SHA1 593228753Smm if ((mtree->keys & F_SHA1) != 0 && 594228753Smm archive_entry_filetype(entry) == AE_IFREG) { 595228753Smm mtree->compute_sum |= F_SHA1; 596228753Smm archive_sha1_init(&mtree->sha1ctx); 597228753Smm } else 598228753Smm mtree->compute_sum &= ~F_SHA1; 599228753Smm#endif 600228753Smm#ifdef ARCHIVE_HAS_SHA256 601228753Smm if ((mtree->keys & F_SHA256) != 0 && 602228753Smm archive_entry_filetype(entry) == AE_IFREG) { 603228753Smm mtree->compute_sum |= F_SHA256; 604228753Smm archive_sha256_init(&mtree->sha256ctx); 605228753Smm } else 606228753Smm mtree->compute_sum &= ~F_SHA256; 607228753Smm#endif 608228753Smm#ifdef ARCHIVE_HAS_SHA384 609228753Smm if ((mtree->keys & F_SHA384) != 0 && 610228753Smm archive_entry_filetype(entry) == AE_IFREG) { 611228753Smm mtree->compute_sum |= F_SHA384; 612228753Smm archive_sha384_init(&mtree->sha384ctx); 613228753Smm } else 614228753Smm mtree->compute_sum &= ~F_SHA384; 615228753Smm#endif 616228753Smm#ifdef ARCHIVE_HAS_SHA512 617228753Smm if ((mtree->keys & F_SHA512) != 0 && 618228753Smm archive_entry_filetype(entry) == AE_IFREG) { 619228753Smm mtree->compute_sum |= F_SHA512; 620228753Smm archive_sha512_init(&mtree->sha512ctx); 621228753Smm } else 622228753Smm mtree->compute_sum &= ~F_SHA512; 623228753Smm#endif 624228753Smm 625228753Smm return (ARCHIVE_OK); 626228753Smm} 627228753Smm 628228753Smm#if defined(ARCHIVE_HAS_MD5) || defined(ARCHIVE_HAS_RMD160) || \ 629228753Smm defined(ARCHIVE_HAS_SHA1) || defined(ARCHIVE_HAS_SHA256) || \ 630228753Smm defined(ARCHIVE_HAS_SHA384) || defined(ARCHIVE_HAS_SHA512) 631228753Smmstatic void 632228753Smmstrappend_bin(struct archive_string *s, const unsigned char *bin, int n) 633228753Smm{ 634228753Smm static const char hex[] = "0123456789abcdef"; 635228753Smm int i; 636228753Smm 637228753Smm for (i = 0; i < n; i++) { 638228753Smm archive_strappend_char(s, hex[bin[i] >> 4]); 639228753Smm archive_strappend_char(s, hex[bin[i] & 0x0f]); 640228753Smm } 641228753Smm} 642228753Smm#endif 643228753Smm 644228753Smmstatic int 645228753Smmarchive_write_mtree_finish_entry(struct archive_write *a) 646228753Smm{ 647228753Smm struct mtree_writer *mtree = a->format_data; 648228753Smm struct archive_entry *entry; 649228753Smm struct archive_string *str; 650228753Smm const char *name; 651228753Smm int keys, ret; 652228753Smm 653228753Smm entry = mtree->entry; 654228753Smm if (entry == NULL) { 655228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, 656228753Smm "Finished entry without being open first."); 657228753Smm return (ARCHIVE_FATAL); 658228753Smm } 659228753Smm mtree->entry = NULL; 660228753Smm 661228753Smm if (mtree->dironly && archive_entry_filetype(entry) != AE_IFDIR) { 662228753Smm archive_entry_free(entry); 663228753Smm return (ARCHIVE_OK); 664228753Smm } 665228753Smm 666228753Smm str = (mtree->indent)? &mtree->ebuf : &mtree->buf; 667228753Smm keys = get_keys(mtree, entry); 668228753Smm if ((keys & F_NLINK) != 0 && 669228753Smm archive_entry_nlink(entry) != 1 && 670228753Smm archive_entry_filetype(entry) != AE_IFDIR) 671228753Smm archive_string_sprintf(str, 672228753Smm " nlink=%u", archive_entry_nlink(entry)); 673228753Smm 674228753Smm if ((keys & F_GNAME) != 0 && 675228753Smm (name = archive_entry_gname(entry)) != NULL) { 676228753Smm archive_strcat(str, " gname="); 677228753Smm mtree_quote(str, name); 678228753Smm } 679228753Smm if ((keys & F_UNAME) != 0 && 680228753Smm (name = archive_entry_uname(entry)) != NULL) { 681228753Smm archive_strcat(str, " uname="); 682228753Smm mtree_quote(str, name); 683228753Smm } 684228753Smm if ((keys & F_FLAGS) != 0 && 685228753Smm (name = archive_entry_fflags_text(entry)) != NULL) { 686228753Smm archive_strcat(str, " flags="); 687228753Smm mtree_quote(str, name); 688228753Smm } 689228753Smm if ((keys & F_TIME) != 0) 690228753Smm archive_string_sprintf(str, " time=%jd.%jd", 691228753Smm (intmax_t)archive_entry_mtime(entry), 692228753Smm (intmax_t)archive_entry_mtime_nsec(entry)); 693228753Smm if ((keys & F_MODE) != 0) 694228753Smm archive_string_sprintf(str, " mode=%o", 695228753Smm archive_entry_mode(entry) & 07777); 696228753Smm if ((keys & F_GID) != 0) 697228753Smm archive_string_sprintf(str, " gid=%jd", 698228753Smm (intmax_t)archive_entry_gid(entry)); 699228753Smm if ((keys & F_UID) != 0) 700228753Smm archive_string_sprintf(str, " uid=%jd", 701228753Smm (intmax_t)archive_entry_uid(entry)); 702228753Smm 703228753Smm switch (archive_entry_filetype(entry)) { 704228753Smm case AE_IFLNK: 705228753Smm if ((keys & F_TYPE) != 0) 706228753Smm archive_strcat(str, " type=link"); 707228753Smm if ((keys & F_SLINK) != 0) { 708228753Smm archive_strcat(str, " link="); 709228753Smm mtree_quote(str, archive_entry_symlink(entry)); 710228753Smm } 711228753Smm break; 712228753Smm case AE_IFSOCK: 713228753Smm if ((keys & F_TYPE) != 0) 714228753Smm archive_strcat(str, " type=socket"); 715228753Smm break; 716228753Smm case AE_IFCHR: 717228753Smm if ((keys & F_TYPE) != 0) 718228753Smm archive_strcat(str, " type=char"); 719228753Smm if ((keys & F_DEV) != 0) { 720228753Smm archive_string_sprintf(str, 721228753Smm " device=native,%d,%d", 722228753Smm archive_entry_rdevmajor(entry), 723228753Smm archive_entry_rdevminor(entry)); 724228753Smm } 725228753Smm break; 726228753Smm case AE_IFBLK: 727228753Smm if ((keys & F_TYPE) != 0) 728228753Smm archive_strcat(str, " type=block"); 729228753Smm if ((keys & F_DEV) != 0) { 730228753Smm archive_string_sprintf(str, 731228753Smm " device=native,%d,%d", 732228753Smm archive_entry_rdevmajor(entry), 733228753Smm archive_entry_rdevminor(entry)); 734228753Smm } 735228753Smm break; 736228753Smm case AE_IFDIR: 737228753Smm if ((keys & F_TYPE) != 0) 738228753Smm archive_strcat(str, " type=dir"); 739228753Smm break; 740228753Smm case AE_IFIFO: 741228753Smm if ((keys & F_TYPE) != 0) 742228753Smm archive_strcat(str, " type=fifo"); 743228753Smm break; 744228753Smm case AE_IFREG: 745228753Smm default: /* Handle unknown file types as regular files. */ 746228753Smm if ((keys & F_TYPE) != 0) 747228753Smm archive_strcat(str, " type=file"); 748228753Smm if ((keys & F_SIZE) != 0) 749228753Smm archive_string_sprintf(str, " size=%jd", 750228753Smm (intmax_t)archive_entry_size(entry)); 751228753Smm break; 752228753Smm } 753228753Smm 754228753Smm if (mtree->compute_sum & F_CKSUM) { 755228753Smm uint64_t len; 756228753Smm /* Include the length of the file. */ 757228753Smm for (len = mtree->crc_len; len != 0; len >>= 8) 758228753Smm COMPUTE_CRC(mtree->crc, len & 0xff); 759228753Smm mtree->crc = ~mtree->crc; 760228753Smm archive_string_sprintf(str, " cksum=%ju", 761228753Smm (uintmax_t)mtree->crc); 762228753Smm } 763228753Smm#ifdef ARCHIVE_HAS_MD5 764228753Smm if (mtree->compute_sum & F_MD5) { 765228753Smm unsigned char buf[16]; 766228753Smm 767228753Smm archive_md5_final(&mtree->md5ctx, buf); 768228753Smm archive_strcat(str, " md5digest="); 769228753Smm strappend_bin(str, buf, sizeof(buf)); 770228753Smm } 771228753Smm#endif 772228753Smm#ifdef ARCHIVE_HAS_RMD160 773228753Smm if (mtree->compute_sum & F_RMD160) { 774228753Smm unsigned char buf[20]; 775228753Smm 776228753Smm archive_rmd160_final(&mtree->rmd160ctx, buf); 777228753Smm archive_strcat(str, " rmd160digest="); 778228753Smm strappend_bin(str, buf, sizeof(buf)); 779228753Smm } 780228753Smm#endif 781228753Smm#ifdef ARCHIVE_HAS_SHA1 782228753Smm if (mtree->compute_sum & F_SHA1) { 783228753Smm unsigned char buf[20]; 784228753Smm 785228753Smm archive_sha1_final(&mtree->sha1ctx, buf); 786228753Smm archive_strcat(str, " sha1digest="); 787228753Smm strappend_bin(str, buf, sizeof(buf)); 788228753Smm } 789228753Smm#endif 790228753Smm#ifdef ARCHIVE_HAS_SHA256 791228753Smm if (mtree->compute_sum & F_SHA256) { 792228753Smm unsigned char buf[32]; 793228753Smm 794228753Smm archive_sha256_final(&mtree->sha256ctx, buf); 795228753Smm archive_strcat(str, " sha256digest="); 796228753Smm strappend_bin(str, buf, sizeof(buf)); 797228753Smm } 798228753Smm#endif 799228753Smm#ifdef ARCHIVE_HAS_SHA384 800228753Smm if (mtree->compute_sum & F_SHA384) { 801228753Smm unsigned char buf[48]; 802228753Smm 803228753Smm archive_sha384_final(&mtree->sha384ctx, buf); 804228753Smm archive_strcat(str, " sha384digest="); 805228753Smm strappend_bin(str, buf, sizeof(buf)); 806228753Smm } 807228753Smm#endif 808228753Smm#ifdef ARCHIVE_HAS_SHA512 809228753Smm if (mtree->compute_sum & F_SHA512) { 810228753Smm unsigned char buf[64]; 811228753Smm 812228753Smm archive_sha512_final(&mtree->sha512ctx, buf); 813228753Smm archive_strcat(str, " sha512digest="); 814228753Smm strappend_bin(str, buf, sizeof(buf)); 815228753Smm } 816228753Smm#endif 817228753Smm archive_strcat(str, "\n"); 818228753Smm if (mtree->indent) 819228753Smm mtree_indent(mtree); 820228753Smm 821228753Smm archive_entry_free(entry); 822228753Smm 823228753Smm if (mtree->buf.length > 32768) { 824228753Smm ret = (a->compressor.write)(a, mtree->buf.s, mtree->buf.length); 825228753Smm archive_string_empty(&mtree->buf); 826228753Smm } else 827228753Smm ret = ARCHIVE_OK; 828228753Smm 829228753Smm return (ret == ARCHIVE_OK ? ret : ARCHIVE_FATAL); 830228753Smm} 831228753Smm 832228753Smmstatic int 833228753Smmarchive_write_mtree_finish(struct archive_write *a) 834228753Smm{ 835228753Smm struct mtree_writer *mtree= a->format_data; 836228753Smm 837228753Smm archive_write_set_bytes_in_last_block(&a->archive, 1); 838228753Smm 839228753Smm return (a->compressor.write)(a, mtree->buf.s, mtree->buf.length); 840228753Smm} 841228753Smm 842228753Smmstatic ssize_t 843228753Smmarchive_write_mtree_data(struct archive_write *a, const void *buff, size_t n) 844228753Smm{ 845228753Smm struct mtree_writer *mtree= a->format_data; 846228753Smm 847228753Smm if (n > mtree->entry_bytes_remaining) 848228753Smm n = mtree->entry_bytes_remaining; 849228753Smm if (mtree->dironly) 850228753Smm /* We don't need compute a regular file sum */ 851228753Smm return (n); 852228753Smm if (mtree->compute_sum & F_CKSUM) { 853228753Smm /* 854228753Smm * Compute a POSIX 1003.2 checksum 855228753Smm */ 856228753Smm const unsigned char *p; 857228753Smm size_t nn; 858228753Smm 859228753Smm for (nn = n, p = buff; nn--; ++p) 860228753Smm COMPUTE_CRC(mtree->crc, *p); 861228753Smm mtree->crc_len += n; 862228753Smm } 863228753Smm#ifdef ARCHIVE_HAS_MD5 864228753Smm if (mtree->compute_sum & F_MD5) 865228753Smm archive_md5_update(&mtree->md5ctx, buff, n); 866228753Smm#endif 867228753Smm#ifdef ARCHIVE_HAS_RMD160 868228753Smm if (mtree->compute_sum & F_RMD160) 869228753Smm archive_rmd160_update(&mtree->rmd160ctx, buff, n); 870228753Smm#endif 871228753Smm#ifdef ARCHIVE_HAS_SHA1 872228753Smm if (mtree->compute_sum & F_SHA1) 873228753Smm archive_sha1_update(&mtree->sha1ctx, buff, n); 874228753Smm#endif 875228753Smm#ifdef ARCHIVE_HAS_SHA256 876228753Smm if (mtree->compute_sum & F_SHA256) 877228753Smm archive_sha256_update(&mtree->sha256ctx, buff, n); 878228753Smm#endif 879228753Smm#ifdef ARCHIVE_HAS_SHA384 880228753Smm if (mtree->compute_sum & F_SHA384) 881228753Smm archive_sha384_update(&mtree->sha384ctx, buff, n); 882228753Smm#endif 883228753Smm#ifdef ARCHIVE_HAS_SHA512 884228753Smm if (mtree->compute_sum & F_SHA512) 885228753Smm archive_sha512_update(&mtree->sha512ctx, buff, n); 886228753Smm#endif 887228753Smm return (n); 888228753Smm} 889228753Smm 890228753Smmstatic int 891228753Smmarchive_write_mtree_destroy(struct archive_write *a) 892228753Smm{ 893228753Smm struct mtree_writer *mtree= a->format_data; 894228753Smm 895228753Smm if (mtree == NULL) 896228753Smm return (ARCHIVE_OK); 897228753Smm 898228753Smm archive_entry_free(mtree->entry); 899228753Smm archive_string_free(&mtree->ebuf); 900228753Smm archive_string_free(&mtree->buf); 901228753Smm archive_string_free(&mtree->set.parent); 902228753Smm free(mtree); 903228753Smm a->format_data = NULL; 904228753Smm return (ARCHIVE_OK); 905228753Smm} 906228753Smm 907228753Smmstatic int 908228753Smmarchive_write_mtree_options(struct archive_write *a, const char *key, 909228753Smm const char *value) 910228753Smm{ 911228753Smm struct mtree_writer *mtree= a->format_data; 912228753Smm int keybit = 0; 913228753Smm 914228753Smm switch (key[0]) { 915228753Smm case 'a': 916228753Smm if (strcmp(key, "all") == 0) 917228753Smm keybit = ~0; 918228753Smm break; 919228753Smm case 'c': 920228753Smm if (strcmp(key, "cksum") == 0) 921228753Smm keybit = F_CKSUM; 922228753Smm break; 923228753Smm case 'd': 924228753Smm if (strcmp(key, "device") == 0) 925228753Smm keybit = F_DEV; 926228753Smm else if (strcmp(key, "dironly") == 0) { 927228753Smm mtree->dironly = (value != NULL)? 1: 0; 928228753Smm return (ARCHIVE_OK); 929228753Smm } 930228753Smm break; 931228753Smm case 'f': 932228753Smm if (strcmp(key, "flags") == 0) 933228753Smm keybit = F_FLAGS; 934228753Smm break; 935228753Smm case 'g': 936228753Smm if (strcmp(key, "gid") == 0) 937228753Smm keybit = F_GID; 938228753Smm else if (strcmp(key, "gname") == 0) 939228753Smm keybit = F_GNAME; 940228753Smm break; 941228753Smm case 'i': 942228753Smm if (strcmp(key, "indent") == 0) { 943228753Smm mtree->indent = (value != NULL)? 1: 0; 944228753Smm return (ARCHIVE_OK); 945228753Smm } 946228753Smm break; 947228753Smm case 'l': 948228753Smm if (strcmp(key, "link") == 0) 949228753Smm keybit = F_SLINK; 950228753Smm break; 951228753Smm case 'm': 952228753Smm if (strcmp(key, "md5") == 0 || 953228753Smm strcmp(key, "md5digest") == 0) 954228753Smm keybit = F_MD5; 955228753Smm if (strcmp(key, "mode") == 0) 956228753Smm keybit = F_MODE; 957228753Smm break; 958228753Smm case 'n': 959228753Smm if (strcmp(key, "nlink") == 0) 960228753Smm keybit = F_NLINK; 961228753Smm break; 962228753Smm case 'r': 963228753Smm if (strcmp(key, "ripemd160digest") == 0 || 964228753Smm strcmp(key, "rmd160") == 0 || 965228753Smm strcmp(key, "rmd160digest") == 0) 966228753Smm keybit = F_RMD160; 967228753Smm break; 968228753Smm case 's': 969228753Smm if (strcmp(key, "sha1") == 0 || 970228753Smm strcmp(key, "sha1digest") == 0) 971228753Smm keybit = F_SHA1; 972228753Smm if (strcmp(key, "sha256") == 0 || 973228753Smm strcmp(key, "sha256digest") == 0) 974228753Smm keybit = F_SHA256; 975228753Smm if (strcmp(key, "sha384") == 0 || 976228753Smm strcmp(key, "sha384digest") == 0) 977228753Smm keybit = F_SHA384; 978228753Smm if (strcmp(key, "sha512") == 0 || 979228753Smm strcmp(key, "sha512digest") == 0) 980228753Smm keybit = F_SHA512; 981228753Smm if (strcmp(key, "size") == 0) 982228753Smm keybit = F_SIZE; 983228753Smm break; 984228753Smm case 't': 985228753Smm if (strcmp(key, "time") == 0) 986228753Smm keybit = F_TIME; 987228753Smm else if (strcmp(key, "type") == 0) 988228753Smm keybit = F_TYPE; 989228753Smm break; 990228753Smm case 'u': 991228753Smm if (strcmp(key, "uid") == 0) 992228753Smm keybit = F_UID; 993228753Smm else if (strcmp(key, "uname") == 0) 994228753Smm keybit = F_UNAME; 995228753Smm else if (strcmp(key, "use-set") == 0) { 996228753Smm mtree->set.output = (value != NULL)? 1: 0; 997228753Smm return (ARCHIVE_OK); 998228753Smm } 999228753Smm break; 1000228753Smm } 1001228753Smm if (keybit != 0) { 1002228753Smm if (value != NULL) 1003228753Smm mtree->keys |= keybit; 1004228753Smm else 1005228753Smm mtree->keys &= ~keybit; 1006228753Smm return (ARCHIVE_OK); 1007228753Smm } 1008228753Smm 1009228753Smm return (ARCHIVE_WARN); 1010228753Smm} 1011228753Smm 1012228753Smmint 1013228753Smmarchive_write_set_format_mtree(struct archive *_a) 1014228753Smm{ 1015228753Smm struct archive_write *a = (struct archive_write *)_a; 1016228753Smm struct mtree_writer *mtree; 1017228753Smm 1018228753Smm if (a->format_destroy != NULL) 1019228753Smm (a->format_destroy)(a); 1020228753Smm 1021228753Smm if ((mtree = malloc(sizeof(*mtree))) == NULL) { 1022228753Smm archive_set_error(&a->archive, ENOMEM, 1023228753Smm "Can't allocate mtree data"); 1024228753Smm return (ARCHIVE_FATAL); 1025228753Smm } 1026228753Smm 1027228753Smm mtree->entry = NULL; 1028228753Smm mtree->first = 1; 1029228753Smm memset(&(mtree->set), 0, sizeof(mtree->set)); 1030228753Smm archive_string_init(&mtree->set.parent); 1031228753Smm mtree->keys = DEFAULT_KEYS; 1032228753Smm mtree->dironly = 0; 1033228753Smm mtree->indent = 0; 1034228753Smm archive_string_init(&mtree->ebuf); 1035228753Smm archive_string_init(&mtree->buf); 1036228753Smm a->format_data = mtree; 1037228753Smm a->format_destroy = archive_write_mtree_destroy; 1038228753Smm 1039228753Smm a->pad_uncompressed = 0; 1040228753Smm a->format_name = "mtree"; 1041228753Smm a->format_options = archive_write_mtree_options; 1042228753Smm a->format_write_header = archive_write_mtree_header; 1043228753Smm a->format_finish = archive_write_mtree_finish; 1044228753Smm a->format_write_data = archive_write_mtree_data; 1045228753Smm a->format_finish_entry = archive_write_mtree_finish_entry; 1046228753Smm a->archive.archive_format = ARCHIVE_FORMAT_MTREE; 1047228753Smm a->archive.archive_format_name = "mtree"; 1048228753Smm 1049228753Smm return (ARCHIVE_OK); 1050228753Smm} 1051