1228753Smm/*- 2228753Smm * Copyright (c) 2008 Joerg Sonnenberger 3232153Smm * Copyright (c) 2009-2012 Michihiro NAKAJIMA 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" 28228763Smm__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" 38232153Smm#include "archive_crypto_private.h" 39228753Smm#include "archive_entry.h" 40228753Smm#include "archive_private.h" 41248616Smm#include "archive_rb.h" 42248616Smm#include "archive_string.h" 43228753Smm#include "archive_write_private.h" 44228753Smm 45228753Smm#define INDENTNAMELEN 15 46228753Smm#define MAXLINELEN 80 47232153Smm#define SET_KEYS \ 48232153Smm (F_FLAGS | F_GID | F_GNAME | F_MODE | F_TYPE | F_UID | F_UNAME) 49228753Smm 50248616Smmstruct attr_counter { 51248616Smm struct attr_counter *prev; 52248616Smm struct attr_counter *next; 53248616Smm struct mtree_entry *m_entry; 54248616Smm int count; 55248616Smm}; 56232153Smm 57248616Smmstruct att_counter_set { 58248616Smm struct attr_counter *uid_list; 59248616Smm struct attr_counter *gid_list; 60248616Smm struct attr_counter *mode_list; 61248616Smm struct attr_counter *flags_list; 62248616Smm}; 63232153Smm 64248616Smmstruct mtree_chain { 65248616Smm struct mtree_entry *first; 66248616Smm struct mtree_entry **last; 67248616Smm}; 68248616Smm 69248616Smm/* 70248616Smm * The Data only for a directory file. 71248616Smm */ 72248616Smmstruct dir_info { 73248616Smm struct archive_rb_tree rbtree; 74248616Smm struct mtree_chain children; 75248616Smm struct mtree_entry *chnext; 76248616Smm int virtual; 77248616Smm}; 78248616Smm 79248616Smm/* 80248616Smm * The Data only for a regular file. 81248616Smm */ 82248616Smmstruct reg_info { 83232153Smm int compute_sum; 84232153Smm uint32_t crc; 85232153Smm#ifdef ARCHIVE_HAS_MD5 86232153Smm unsigned char buf_md5[16]; 87232153Smm#endif 88232153Smm#ifdef ARCHIVE_HAS_RMD160 89232153Smm unsigned char buf_rmd160[20]; 90232153Smm#endif 91232153Smm#ifdef ARCHIVE_HAS_SHA1 92232153Smm unsigned char buf_sha1[20]; 93232153Smm#endif 94232153Smm#ifdef ARCHIVE_HAS_SHA256 95232153Smm unsigned char buf_sha256[32]; 96232153Smm#endif 97232153Smm#ifdef ARCHIVE_HAS_SHA384 98232153Smm unsigned char buf_sha384[48]; 99232153Smm#endif 100232153Smm#ifdef ARCHIVE_HAS_SHA512 101232153Smm unsigned char buf_sha512[64]; 102232153Smm#endif 103232153Smm}; 104232153Smm 105248616Smmstruct mtree_entry { 106248616Smm struct archive_rb_node rbnode; 107248616Smm struct mtree_entry *next; 108248616Smm struct mtree_entry *parent; 109248616Smm struct dir_info *dir_info; 110248616Smm struct reg_info *reg_info; 111248616Smm 112248616Smm struct archive_string parentdir; 113248616Smm struct archive_string basename; 114248616Smm struct archive_string pathname; 115248616Smm struct archive_string symlink; 116248616Smm struct archive_string uname; 117248616Smm struct archive_string gname; 118248616Smm struct archive_string fflags_text; 119248616Smm unsigned int nlink; 120248616Smm mode_t filetype; 121248616Smm mode_t mode; 122248616Smm int64_t size; 123248616Smm int64_t uid; 124248616Smm int64_t gid; 125248616Smm time_t mtime; 126248616Smm long mtime_nsec; 127248616Smm unsigned long fflags_set; 128248616Smm unsigned long fflags_clear; 129248616Smm dev_t rdevmajor; 130248616Smm dev_t rdevminor; 131232153Smm}; 132232153Smm 133228753Smmstruct mtree_writer { 134232153Smm struct mtree_entry *mtree_entry; 135248616Smm struct mtree_entry *root; 136248616Smm struct mtree_entry *cur_dirent; 137248616Smm struct archive_string cur_dirstr; 138248616Smm struct mtree_chain file_list; 139248616Smm 140228753Smm struct archive_string ebuf; 141228753Smm struct archive_string buf; 142228753Smm int first; 143228753Smm uint64_t entry_bytes_remaining; 144248616Smm 145248616Smm /* 146248616Smm * Set global value. 147248616Smm */ 148228753Smm struct { 149248616Smm int processing; 150228753Smm mode_t type; 151228753Smm int keys; 152232153Smm int64_t uid; 153232153Smm int64_t gid; 154228753Smm mode_t mode; 155228753Smm unsigned long fflags_set; 156228753Smm unsigned long fflags_clear; 157248616Smm } set; 158248616Smm struct att_counter_set acs; 159248616Smm int classic; 160248616Smm int depth; 161232153Smm 162232153Smm /* check sum */ 163228753Smm int compute_sum; 164228753Smm uint32_t crc; 165228753Smm uint64_t crc_len; 166228753Smm#ifdef ARCHIVE_HAS_MD5 167228753Smm archive_md5_ctx md5ctx; 168228753Smm#endif 169228753Smm#ifdef ARCHIVE_HAS_RMD160 170228753Smm archive_rmd160_ctx rmd160ctx; 171228753Smm#endif 172228753Smm#ifdef ARCHIVE_HAS_SHA1 173228753Smm archive_sha1_ctx sha1ctx; 174228753Smm#endif 175228753Smm#ifdef ARCHIVE_HAS_SHA256 176228753Smm archive_sha256_ctx sha256ctx; 177228753Smm#endif 178228753Smm#ifdef ARCHIVE_HAS_SHA384 179228753Smm archive_sha384_ctx sha384ctx; 180228753Smm#endif 181228753Smm#ifdef ARCHIVE_HAS_SHA512 182228753Smm archive_sha512_ctx sha512ctx; 183228753Smm#endif 184228753Smm /* Keyword options */ 185228753Smm int keys; 186228753Smm#define F_CKSUM 0x00000001 /* check sum */ 187228753Smm#define F_DEV 0x00000002 /* device type */ 188228753Smm#define F_DONE 0x00000004 /* directory done */ 189228753Smm#define F_FLAGS 0x00000008 /* file flags */ 190228753Smm#define F_GID 0x00000010 /* gid */ 191228753Smm#define F_GNAME 0x00000020 /* group name */ 192228753Smm#define F_IGN 0x00000040 /* ignore */ 193228753Smm#define F_MAGIC 0x00000080 /* name has magic chars */ 194228753Smm#define F_MD5 0x00000100 /* MD5 digest */ 195228753Smm#define F_MODE 0x00000200 /* mode */ 196228753Smm#define F_NLINK 0x00000400 /* number of links */ 197228753Smm#define F_NOCHANGE 0x00000800 /* If owner/mode "wrong", do 198228753Smm * not change */ 199228753Smm#define F_OPT 0x00001000 /* existence optional */ 200228753Smm#define F_RMD160 0x00002000 /* RIPEMD160 digest */ 201228753Smm#define F_SHA1 0x00004000 /* SHA-1 digest */ 202228753Smm#define F_SIZE 0x00008000 /* size */ 203228753Smm#define F_SLINK 0x00010000 /* symbolic link */ 204228753Smm#define F_TAGS 0x00020000 /* tags */ 205228753Smm#define F_TIME 0x00040000 /* modification time */ 206228753Smm#define F_TYPE 0x00080000 /* file type */ 207228753Smm#define F_UID 0x00100000 /* uid */ 208228753Smm#define F_UNAME 0x00200000 /* user name */ 209228753Smm#define F_VISIT 0x00400000 /* file visited */ 210228753Smm#define F_SHA256 0x00800000 /* SHA-256 digest */ 211228753Smm#define F_SHA384 0x01000000 /* SHA-384 digest */ 212228753Smm#define F_SHA512 0x02000000 /* SHA-512 digest */ 213228753Smm 214228753Smm /* Options */ 215248616Smm int dironly; /* If it is set, ignore all files except 216248616Smm * directory files, like mtree(8) -d option. */ 217248616Smm int indent; /* If it is set, indent output data. */ 218248616Smm int output_global_set; /* If it is set, use /set keyword to set 219248616Smm * global values. When generating mtree 220248616Smm * classic format, it is set by default. */ 221228753Smm}; 222228753Smm 223228753Smm#define DEFAULT_KEYS (F_DEV | F_FLAGS | F_GID | F_GNAME | F_SLINK | F_MODE\ 224228753Smm | F_NLINK | F_SIZE | F_TIME | F_TYPE | F_UID\ 225228753Smm | F_UNAME) 226248616Smm#define attr_counter_set_reset attr_counter_set_free 227228753Smm 228248616Smmstatic void attr_counter_free(struct attr_counter **); 229248616Smmstatic int attr_counter_inc(struct attr_counter **, struct attr_counter *, 230248616Smm struct attr_counter *, struct mtree_entry *); 231248616Smmstatic struct attr_counter * attr_counter_new(struct mtree_entry *, 232232153Smm struct attr_counter *); 233248616Smmstatic int attr_counter_set_collect(struct mtree_writer *, 234248616Smm struct mtree_entry *); 235248616Smmstatic void attr_counter_set_free(struct mtree_writer *); 236248616Smmstatic int get_global_set_keys(struct mtree_writer *, struct mtree_entry *); 237248616Smmstatic int mtree_entry_add_child_tail(struct mtree_entry *, 238248616Smm struct mtree_entry *); 239248616Smmstatic int mtree_entry_create_virtual_dir(struct archive_write *, const char *, 240248616Smm struct mtree_entry **); 241248616Smmstatic int mtree_entry_cmp_node(const struct archive_rb_node *, 242248616Smm const struct archive_rb_node *); 243248616Smmstatic int mtree_entry_cmp_key(const struct archive_rb_node *, const void *); 244248616Smmstatic int mtree_entry_exchange_same_entry(struct archive_write *, 245248616Smm struct mtree_entry *, struct mtree_entry *); 246248616Smmstatic void mtree_entry_free(struct mtree_entry *); 247248616Smmstatic int mtree_entry_new(struct archive_write *, struct archive_entry *, 248248616Smm struct mtree_entry **); 249248616Smmstatic void mtree_entry_register_free(struct mtree_writer *); 250248616Smmstatic void mtree_entry_register_init(struct mtree_writer *); 251248616Smmstatic int mtree_entry_setup_filenames(struct archive_write *, 252248616Smm struct mtree_entry *, struct archive_entry *); 253248616Smmstatic int mtree_entry_tree_add(struct archive_write *, struct mtree_entry **); 254232153Smmstatic void sum_init(struct mtree_writer *); 255232153Smmstatic void sum_update(struct mtree_writer *, const void *, size_t); 256248616Smmstatic void sum_final(struct mtree_writer *, struct reg_info *); 257248616Smmstatic void sum_write(struct archive_string *, struct reg_info *); 258248616Smmstatic int write_mtree_entry(struct archive_write *, struct mtree_entry *); 259248616Smmstatic int write_dot_dot_entry(struct archive_write *, struct mtree_entry *); 260232153Smm 261228753Smm#define COMPUTE_CRC(var, ch) (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)] 262228753Smmstatic const uint32_t crctab[] = { 263228753Smm 0x0, 264228753Smm 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 265228753Smm 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 266228753Smm 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 267228753Smm 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 268228753Smm 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 269228753Smm 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 270228753Smm 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 271228753Smm 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 272228753Smm 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 273228753Smm 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, 274228753Smm 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, 275228753Smm 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 276228753Smm 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 277228753Smm 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 278228753Smm 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 279228753Smm 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 280228753Smm 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 281228753Smm 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 282228753Smm 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 283228753Smm 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 284228753Smm 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 285228753Smm 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 286228753Smm 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 287228753Smm 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, 288228753Smm 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 289228753Smm 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 290228753Smm 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 291228753Smm 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 292228753Smm 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, 293228753Smm 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 294228753Smm 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 295228753Smm 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 296228753Smm 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 297228753Smm 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 298228753Smm 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, 299228753Smm 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 300228753Smm 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 301228753Smm 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 302228753Smm 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 303228753Smm 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 304228753Smm 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 305228753Smm 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, 306228753Smm 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 307228753Smm 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 308228753Smm 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 309228753Smm 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 310228753Smm 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 311228753Smm 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, 312228753Smm 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 313228753Smm 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 314228753Smm 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 315228753Smm}; 316228753Smm 317248616Smmstatic const unsigned char safe_char[256] = { 318248616Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */ 319248616Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */ 320248616Smm /* !"$%&'()*+,-./ EXCLUSION:0x20( ) 0x23(#) */ 321248616Smm 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */ 322248616Smm /* 0123456789:;<>? EXCLUSION:0x3d(=) */ 323248616Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, /* 30 - 3F */ 324248616Smm /* @ABCDEFGHIJKLMNO */ 325248616Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */ 326248616Smm /* PQRSTUVWXYZ[]^_ EXCLUSION:0x5c(\) */ 327248616Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, /* 50 - 5F */ 328248616Smm /* `abcdefghijklmno */ 329248616Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */ 330248616Smm /* pqrstuvwxyz{|}~ */ 331248616Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */ 332248616Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */ 333248616Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */ 334248616Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */ 335248616Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */ 336248616Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */ 337248616Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */ 338248616Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */ 339248616Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */ 340248616Smm}; 341228753Smm 342228753Smmstatic void 343228753Smmmtree_quote(struct archive_string *s, const char *str) 344228753Smm{ 345228753Smm const char *start; 346228753Smm char buf[4]; 347228753Smm unsigned char c; 348228753Smm 349228753Smm for (start = str; *str != '\0'; ++str) { 350248616Smm if (safe_char[*(const unsigned char *)str]) 351228753Smm continue; 352228753Smm if (start != str) 353228753Smm archive_strncat(s, start, str - start); 354228753Smm c = (unsigned char)*str; 355228753Smm buf[0] = '\\'; 356228753Smm buf[1] = (c / 64) + '0'; 357228753Smm buf[2] = (c / 8 % 8) + '0'; 358228753Smm buf[3] = (c % 8) + '0'; 359228753Smm archive_strncat(s, buf, 4); 360228753Smm start = str + 1; 361228753Smm } 362228753Smm 363228753Smm if (start != str) 364228753Smm archive_strncat(s, start, str - start); 365228753Smm} 366228753Smm 367232153Smm/* 368232153Smm * Indent a line as mtree utility to be readable for people. 369232153Smm */ 370228753Smmstatic void 371228753Smmmtree_indent(struct mtree_writer *mtree) 372228753Smm{ 373248616Smm int i, fn, nd, pd; 374228753Smm const char *r, *s, *x; 375228753Smm 376248616Smm if (mtree->classic) { 377248616Smm if (mtree->indent) { 378248616Smm nd = 0; 379248616Smm pd = mtree->depth * 4; 380248616Smm } else { 381248616Smm nd = mtree->depth?4:0; 382248616Smm pd = 0; 383248616Smm } 384248616Smm } else 385248616Smm nd = pd = 0; 386228753Smm fn = 1; 387228753Smm s = r = mtree->ebuf.s; 388228753Smm x = NULL; 389228753Smm while (*r == ' ') 390228753Smm r++; 391228753Smm while ((r = strchr(r, ' ')) != NULL) { 392228753Smm if (fn) { 393228753Smm fn = 0; 394248616Smm for (i = 0; i < nd + pd; i++) 395248616Smm archive_strappend_char(&mtree->buf, ' '); 396228753Smm archive_strncat(&mtree->buf, s, r - s); 397248616Smm if (nd + (r -s) > INDENTNAMELEN) { 398228753Smm archive_strncat(&mtree->buf, " \\\n", 3); 399248616Smm for (i = 0; i < (INDENTNAMELEN + 1 + pd); i++) 400228753Smm archive_strappend_char(&mtree->buf, ' '); 401228753Smm } else { 402248616Smm for (i = (int)(r -s + nd); 403248616Smm i < (INDENTNAMELEN + 1); i++) 404228753Smm archive_strappend_char(&mtree->buf, ' '); 405228753Smm } 406228753Smm s = ++r; 407228753Smm x = NULL; 408228753Smm continue; 409228753Smm } 410248616Smm if (pd + (r - s) <= MAXLINELEN - 3 - INDENTNAMELEN) 411228753Smm x = r++; 412228753Smm else { 413228753Smm if (x == NULL) 414228753Smm x = r; 415228753Smm archive_strncat(&mtree->buf, s, x - s); 416228753Smm archive_strncat(&mtree->buf, " \\\n", 3); 417248616Smm for (i = 0; i < (INDENTNAMELEN + 1 + pd); i++) 418228753Smm archive_strappend_char(&mtree->buf, ' '); 419228753Smm s = r = ++x; 420228753Smm x = NULL; 421228753Smm } 422228753Smm } 423248616Smm if (fn) { 424248616Smm for (i = 0; i < nd + pd; i++) 425248616Smm archive_strappend_char(&mtree->buf, ' '); 426248616Smm archive_strcat(&mtree->buf, s); 427248616Smm s += strlen(s); 428248616Smm } 429248616Smm if (x != NULL && pd + strlen(s) > MAXLINELEN - 3 - INDENTNAMELEN) { 430228753Smm /* Last keyword is longer. */ 431228753Smm archive_strncat(&mtree->buf, s, x - s); 432228753Smm archive_strncat(&mtree->buf, " \\\n", 3); 433248616Smm for (i = 0; i < (INDENTNAMELEN + 1 + pd); i++) 434228753Smm archive_strappend_char(&mtree->buf, ' '); 435228753Smm s = ++x; 436228753Smm } 437228753Smm archive_strcat(&mtree->buf, s); 438228753Smm archive_string_empty(&mtree->ebuf); 439228753Smm} 440228753Smm 441228753Smm/* 442232153Smm * Write /set keyword. 443232153Smm * Set most used value of uid,gid,mode and fflags, which are 444248616Smm * collected by attr_counter_set_collect() function. 445228753Smm */ 446228753Smmstatic void 447232153Smmwrite_global(struct mtree_writer *mtree) 448228753Smm{ 449228753Smm struct archive_string setstr; 450228753Smm struct archive_string unsetstr; 451248616Smm struct att_counter_set *acs; 452228753Smm int keys, oldkeys, effkeys; 453228753Smm 454228753Smm archive_string_init(&setstr); 455228753Smm archive_string_init(&unsetstr); 456232153Smm keys = mtree->keys & SET_KEYS; 457228753Smm oldkeys = mtree->set.keys; 458228753Smm effkeys = keys; 459248616Smm acs = &mtree->acs; 460248616Smm if (mtree->set.processing) { 461228753Smm /* 462232153Smm * Check if the global data needs updating. 463228753Smm */ 464228753Smm effkeys &= ~F_TYPE; 465248616Smm if (acs->uid_list == NULL) 466248616Smm effkeys &= ~(F_UNAME | F_UID); 467248616Smm else if (oldkeys & (F_UNAME | F_UID)) { 468248616Smm if (acs->uid_list->count < 2 || 469248616Smm mtree->set.uid == acs->uid_list->m_entry->uid) 470248616Smm effkeys &= ~(F_UNAME | F_UID); 471232153Smm } 472248616Smm if (acs->gid_list == NULL) 473248616Smm effkeys &= ~(F_GNAME | F_GID); 474248616Smm else if (oldkeys & (F_GNAME | F_GID)) { 475248616Smm if (acs->gid_list->count < 2 || 476248616Smm mtree->set.gid == acs->gid_list->m_entry->gid) 477248616Smm effkeys &= ~(F_GNAME | F_GID); 478232153Smm } 479248616Smm if (acs->mode_list == NULL) 480248616Smm effkeys &= ~F_MODE; 481248616Smm else if (oldkeys & F_MODE) { 482248616Smm if (acs->mode_list->count < 2 || 483248616Smm mtree->set.mode == acs->mode_list->m_entry->mode) 484248616Smm effkeys &= ~F_MODE; 485232153Smm } 486248616Smm if (acs->flags_list == NULL) 487248616Smm effkeys &= ~F_FLAGS; 488248616Smm else if ((oldkeys & F_FLAGS) != 0) { 489248616Smm if (acs->flags_list->count < 2 || 490248616Smm (acs->flags_list->m_entry->fflags_set == 491248616Smm mtree->set.fflags_set && 492248616Smm acs->flags_list->m_entry->fflags_clear == 493248616Smm mtree->set.fflags_clear)) 494248616Smm effkeys &= ~F_FLAGS; 495228753Smm } 496248616Smm } else { 497248616Smm if (acs->uid_list == NULL) 498248616Smm keys &= ~(F_UNAME | F_UID); 499248616Smm if (acs->gid_list == NULL) 500248616Smm keys &= ~(F_GNAME | F_GID); 501248616Smm if (acs->mode_list == NULL) 502248616Smm keys &= ~F_MODE; 503248616Smm if (acs->flags_list == NULL) 504248616Smm keys &= ~F_FLAGS; 505228753Smm } 506228753Smm if ((keys & effkeys & F_TYPE) != 0) { 507232153Smm if (mtree->dironly) { 508228753Smm archive_strcat(&setstr, " type=dir"); 509232153Smm mtree->set.type = AE_IFDIR; 510232153Smm } else { 511228753Smm archive_strcat(&setstr, " type=file"); 512232153Smm mtree->set.type = AE_IFREG; 513232153Smm } 514228753Smm } 515228753Smm if ((keys & effkeys & F_UNAME) != 0) { 516248616Smm if (archive_strlen(&(acs->uid_list->m_entry->uname)) > 0) { 517228753Smm archive_strcat(&setstr, " uname="); 518248616Smm mtree_quote(&setstr, acs->uid_list->m_entry->uname.s); 519232153Smm } else { 520228753Smm keys &= ~F_UNAME; 521232153Smm if ((oldkeys & F_UNAME) != 0) 522232153Smm archive_strcat(&unsetstr, " uname"); 523232153Smm } 524228753Smm } 525228753Smm if ((keys & effkeys & F_UID) != 0) { 526248616Smm mtree->set.uid = acs->uid_list->m_entry->uid; 527228753Smm archive_string_sprintf(&setstr, " uid=%jd", 528228753Smm (intmax_t)mtree->set.uid); 529228753Smm } 530228753Smm if ((keys & effkeys & F_GNAME) != 0) { 531248616Smm if (archive_strlen(&(acs->gid_list->m_entry->gname)) > 0) { 532228753Smm archive_strcat(&setstr, " gname="); 533248616Smm mtree_quote(&setstr, acs->gid_list->m_entry->gname.s); 534232153Smm } else { 535228753Smm keys &= ~F_GNAME; 536232153Smm if ((oldkeys & F_GNAME) != 0) 537232153Smm archive_strcat(&unsetstr, " gname"); 538232153Smm } 539228753Smm } 540228753Smm if ((keys & effkeys & F_GID) != 0) { 541248616Smm mtree->set.gid = acs->gid_list->m_entry->gid; 542228753Smm archive_string_sprintf(&setstr, " gid=%jd", 543228753Smm (intmax_t)mtree->set.gid); 544228753Smm } 545228753Smm if ((keys & effkeys & F_MODE) != 0) { 546248616Smm mtree->set.mode = acs->mode_list->m_entry->mode; 547232153Smm archive_string_sprintf(&setstr, " mode=%o", 548232153Smm (unsigned int)mtree->set.mode); 549228753Smm } 550228753Smm if ((keys & effkeys & F_FLAGS) != 0) { 551248616Smm if (archive_strlen( 552248616Smm &(acs->flags_list->m_entry->fflags_text)) > 0) { 553228753Smm archive_strcat(&setstr, " flags="); 554248616Smm mtree_quote(&setstr, 555248616Smm acs->flags_list->m_entry->fflags_text.s); 556232153Smm mtree->set.fflags_set = 557248616Smm acs->flags_list->m_entry->fflags_set; 558232153Smm mtree->set.fflags_clear = 559248616Smm acs->flags_list->m_entry->fflags_clear; 560232153Smm } else { 561228753Smm keys &= ~F_FLAGS; 562232153Smm if ((oldkeys & F_FLAGS) != 0) 563232153Smm archive_strcat(&unsetstr, " flags"); 564232153Smm } 565228753Smm } 566228753Smm if (unsetstr.length > 0) 567228753Smm archive_string_sprintf(&mtree->buf, "/unset%s\n", unsetstr.s); 568228753Smm archive_string_free(&unsetstr); 569228753Smm if (setstr.length > 0) 570228753Smm archive_string_sprintf(&mtree->buf, "/set%s\n", setstr.s); 571228753Smm archive_string_free(&setstr); 572228753Smm mtree->set.keys = keys; 573248616Smm mtree->set.processing = 1; 574228753Smm} 575228753Smm 576232153Smmstatic struct attr_counter * 577248616Smmattr_counter_new(struct mtree_entry *me, struct attr_counter *prev) 578232153Smm{ 579232153Smm struct attr_counter *ac; 580232153Smm 581232153Smm ac = malloc(sizeof(*ac)); 582232153Smm if (ac != NULL) { 583232153Smm ac->prev = prev; 584232153Smm ac->next = NULL; 585232153Smm ac->count = 1; 586232153Smm ac->m_entry = me; 587232153Smm } 588232153Smm return (ac); 589232153Smm} 590232153Smm 591232153Smmstatic void 592248616Smmattr_counter_free(struct attr_counter **top) 593232153Smm{ 594232153Smm struct attr_counter *ac, *tac; 595232153Smm 596232153Smm if (*top == NULL) 597232153Smm return; 598232153Smm ac = *top; 599232153Smm while (ac != NULL) { 600232153Smm tac = ac->next; 601232153Smm free(ac); 602232153Smm ac = tac; 603232153Smm } 604232153Smm *top = NULL; 605232153Smm} 606232153Smm 607228753Smmstatic int 608248616Smmattr_counter_inc(struct attr_counter **top, struct attr_counter *ac, 609232153Smm struct attr_counter *last, struct mtree_entry *me) 610228753Smm{ 611232153Smm struct attr_counter *pac; 612232153Smm 613232153Smm if (ac != NULL) { 614232153Smm ac->count++; 615232153Smm if (*top == ac || ac->prev->count >= ac->count) 616232153Smm return (0); 617232153Smm for (pac = ac->prev; pac; pac = pac->prev) { 618232153Smm if (pac->count >= ac->count) 619232153Smm break; 620232153Smm } 621232153Smm ac->prev->next = ac->next; 622232153Smm if (ac->next != NULL) 623232153Smm ac->next->prev = ac->prev; 624232153Smm if (pac != NULL) { 625232153Smm ac->prev = pac; 626232153Smm ac->next = pac->next; 627232153Smm pac->next = ac; 628232153Smm if (ac->next != NULL) 629232153Smm ac->next->prev = ac; 630232153Smm } else { 631232153Smm ac->prev = NULL; 632232153Smm ac->next = *top; 633232153Smm *top = ac; 634232153Smm ac->next->prev = ac; 635232153Smm } 636232153Smm } else { 637248616Smm ac = attr_counter_new(me, last); 638232153Smm if (ac == NULL) 639232153Smm return (-1); 640232153Smm last->next = ac; 641232153Smm } 642232153Smm return (0); 643232153Smm} 644232153Smm 645248616Smm/* 646248616Smm * Tabulate uid,gid,mode and fflags of a entry in order to be used for /set. 647248616Smm */ 648232153Smmstatic int 649248616Smmattr_counter_set_collect(struct mtree_writer *mtree, struct mtree_entry *me) 650232153Smm{ 651248616Smm struct attr_counter *ac, *last; 652248616Smm struct att_counter_set *acs = &mtree->acs; 653232153Smm int keys = mtree->keys; 654232153Smm 655232153Smm if (keys & (F_UNAME | F_UID)) { 656248616Smm if (acs->uid_list == NULL) { 657248616Smm acs->uid_list = attr_counter_new(me, NULL); 658248616Smm if (acs->uid_list == NULL) 659232153Smm return (-1); 660232153Smm } else { 661232153Smm last = NULL; 662248616Smm for (ac = acs->uid_list; ac; ac = ac->next) { 663232153Smm if (ac->m_entry->uid == me->uid) 664232153Smm break; 665232153Smm last = ac; 666232153Smm } 667248616Smm if (attr_counter_inc(&acs->uid_list, ac, last, me) < 0) 668232153Smm return (-1); 669232153Smm } 670232153Smm } 671232153Smm if (keys & (F_GNAME | F_GID)) { 672248616Smm if (acs->gid_list == NULL) { 673248616Smm acs->gid_list = attr_counter_new(me, NULL); 674248616Smm if (acs->gid_list == NULL) 675232153Smm return (-1); 676232153Smm } else { 677232153Smm last = NULL; 678248616Smm for (ac = acs->gid_list; ac; ac = ac->next) { 679232153Smm if (ac->m_entry->gid == me->gid) 680232153Smm break; 681232153Smm last = ac; 682232153Smm } 683248616Smm if (attr_counter_inc(&acs->gid_list, ac, last, me) < 0) 684232153Smm return (-1); 685232153Smm } 686232153Smm } 687232153Smm if (keys & F_MODE) { 688248616Smm if (acs->mode_list == NULL) { 689248616Smm acs->mode_list = attr_counter_new(me, NULL); 690248616Smm if (acs->mode_list == NULL) 691232153Smm return (-1); 692232153Smm } else { 693232153Smm last = NULL; 694248616Smm for (ac = acs->mode_list; ac; ac = ac->next) { 695232153Smm if (ac->m_entry->mode == me->mode) 696232153Smm break; 697232153Smm last = ac; 698232153Smm } 699248616Smm if (attr_counter_inc(&acs->mode_list, ac, last, me) < 0) 700232153Smm return (-1); 701232153Smm } 702232153Smm } 703232153Smm if (keys & F_FLAGS) { 704248616Smm if (acs->flags_list == NULL) { 705248616Smm acs->flags_list = attr_counter_new(me, NULL); 706248616Smm if (acs->flags_list == NULL) 707232153Smm return (-1); 708232153Smm } else { 709232153Smm last = NULL; 710248616Smm for (ac = acs->flags_list; ac; ac = ac->next) { 711232153Smm if (ac->m_entry->fflags_set == me->fflags_set && 712248616Smm ac->m_entry->fflags_clear == 713248616Smm me->fflags_clear) 714232153Smm break; 715232153Smm last = ac; 716232153Smm } 717248616Smm if (attr_counter_inc(&acs->flags_list, ac, last, me) < 0) 718232153Smm return (-1); 719232153Smm } 720232153Smm } 721232153Smm 722232153Smm return (0); 723232153Smm} 724232153Smm 725248616Smmstatic void 726248616Smmattr_counter_set_free(struct mtree_writer *mtree) 727248616Smm{ 728248616Smm struct att_counter_set *acs = &mtree->acs; 729248616Smm 730248616Smm attr_counter_free(&acs->uid_list); 731248616Smm attr_counter_free(&acs->gid_list); 732248616Smm attr_counter_free(&acs->mode_list); 733248616Smm attr_counter_free(&acs->flags_list); 734248616Smm} 735248616Smm 736232153Smmstatic int 737248616Smmget_global_set_keys(struct mtree_writer *mtree, struct mtree_entry *me) 738232153Smm{ 739228753Smm int keys; 740228753Smm 741228753Smm keys = mtree->keys; 742232153Smm 743232153Smm /* 744232153Smm * If a keyword has been set by /set, we do not need to 745232153Smm * output it. 746232153Smm */ 747228753Smm if (mtree->set.keys == 0) 748232153Smm return (keys);/* /set is not used. */ 749232153Smm 750228753Smm if ((mtree->set.keys & (F_GNAME | F_GID)) != 0 && 751232153Smm mtree->set.gid == me->gid) 752228753Smm keys &= ~(F_GNAME | F_GID); 753228753Smm if ((mtree->set.keys & (F_UNAME | F_UID)) != 0 && 754232153Smm mtree->set.uid == me->uid) 755228753Smm keys &= ~(F_UNAME | F_UID); 756228753Smm if (mtree->set.keys & F_FLAGS) { 757232153Smm if (mtree->set.fflags_set == me->fflags_set && 758232153Smm mtree->set.fflags_clear == me->fflags_clear) 759228753Smm keys &= ~F_FLAGS; 760228753Smm } 761232153Smm if ((mtree->set.keys & F_MODE) != 0 && mtree->set.mode == me->mode) 762228753Smm keys &= ~F_MODE; 763228753Smm 764232153Smm switch (me->filetype) { 765228753Smm case AE_IFLNK: case AE_IFSOCK: case AE_IFCHR: 766228753Smm case AE_IFBLK: case AE_IFIFO: 767228753Smm break; 768228753Smm case AE_IFDIR: 769228753Smm if ((mtree->set.keys & F_TYPE) != 0 && 770228753Smm mtree->set.type == AE_IFDIR) 771228753Smm keys &= ~F_TYPE; 772228753Smm break; 773228753Smm case AE_IFREG: 774228753Smm default: /* Handle unknown file types as regular files. */ 775228753Smm if ((mtree->set.keys & F_TYPE) != 0 && 776228753Smm mtree->set.type == AE_IFREG) 777228753Smm keys &= ~F_TYPE; 778228753Smm break; 779228753Smm } 780228753Smm 781228753Smm return (keys); 782228753Smm} 783228753Smm 784248616Smmstatic int 785248616Smmmtree_entry_new(struct archive_write *a, struct archive_entry *entry, 786248616Smm struct mtree_entry **m_entry) 787232153Smm{ 788232153Smm struct mtree_entry *me; 789232153Smm const char *s; 790248616Smm int r; 791248616Smm static const struct archive_rb_tree_ops rb_ops = { 792248616Smm mtree_entry_cmp_node, mtree_entry_cmp_key 793248616Smm }; 794232153Smm 795232153Smm me = calloc(1, sizeof(*me)); 796248616Smm if (me == NULL) { 797248616Smm archive_set_error(&a->archive, ENOMEM, 798248616Smm "Can't allocate memory for a mtree entry"); 799248616Smm *m_entry = NULL; 800248616Smm return (ARCHIVE_FATAL); 801248616Smm } 802248616Smm 803248616Smm r = mtree_entry_setup_filenames(a, me, entry); 804248616Smm if (r < ARCHIVE_WARN) { 805248616Smm mtree_entry_free(me); 806248616Smm *m_entry = NULL; 807248616Smm return (r); 808248616Smm } 809248616Smm 810232153Smm if ((s = archive_entry_symlink(entry)) != NULL) 811248616Smm archive_strcpy(&me->symlink, s); 812232153Smm me->nlink = archive_entry_nlink(entry); 813232153Smm me->filetype = archive_entry_filetype(entry); 814232153Smm me->mode = archive_entry_mode(entry) & 07777; 815232153Smm me->uid = archive_entry_uid(entry); 816232153Smm me->gid = archive_entry_gid(entry); 817232153Smm if ((s = archive_entry_uname(entry)) != NULL) 818248616Smm archive_strcpy(&me->uname, s); 819232153Smm if ((s = archive_entry_gname(entry)) != NULL) 820248616Smm archive_strcpy(&me->gname, s); 821232153Smm if ((s = archive_entry_fflags_text(entry)) != NULL) 822248616Smm archive_strcpy(&me->fflags_text, s); 823232153Smm archive_entry_fflags(entry, &me->fflags_set, &me->fflags_clear); 824232153Smm me->mtime = archive_entry_mtime(entry); 825232153Smm me->mtime_nsec = archive_entry_mtime_nsec(entry); 826232153Smm me->rdevmajor = archive_entry_rdevmajor(entry); 827232153Smm me->rdevminor = archive_entry_rdevminor(entry); 828232153Smm me->size = archive_entry_size(entry); 829248616Smm if (me->filetype == AE_IFDIR) { 830248616Smm me->dir_info = calloc(1, sizeof(*me->dir_info)); 831248616Smm if (me->dir_info == NULL) { 832248616Smm mtree_entry_free(me); 833248616Smm archive_set_error(&a->archive, ENOMEM, 834248616Smm "Can't allocate memory for a mtree entry"); 835248616Smm *m_entry = NULL; 836248616Smm return (ARCHIVE_FATAL); 837248616Smm } 838248616Smm __archive_rb_tree_init(&me->dir_info->rbtree, &rb_ops); 839248616Smm me->dir_info->children.first = NULL; 840248616Smm me->dir_info->children.last = &(me->dir_info->children.first); 841248616Smm me->dir_info->chnext = NULL; 842248616Smm } else if (me->filetype == AE_IFREG) { 843248616Smm me->reg_info = calloc(1, sizeof(*me->reg_info)); 844248616Smm if (me->reg_info == NULL) { 845248616Smm mtree_entry_free(me); 846248616Smm archive_set_error(&a->archive, ENOMEM, 847248616Smm "Can't allocate memory for a mtree entry"); 848248616Smm *m_entry = NULL; 849248616Smm return (ARCHIVE_FATAL); 850248616Smm } 851248616Smm me->reg_info->compute_sum = 0; 852248616Smm } 853232153Smm 854248616Smm *m_entry = me; 855248616Smm return (ARCHIVE_OK); 856232153Smm} 857232153Smm 858232153Smmstatic void 859248616Smmmtree_entry_free(struct mtree_entry *me) 860232153Smm{ 861248616Smm archive_string_free(&me->parentdir); 862248616Smm archive_string_free(&me->basename); 863248616Smm archive_string_free(&me->pathname); 864248616Smm archive_string_free(&me->symlink); 865248616Smm archive_string_free(&me->uname); 866248616Smm archive_string_free(&me->gname); 867248616Smm archive_string_free(&me->fflags_text); 868248616Smm free(me->dir_info); 869248616Smm free(me->reg_info); 870232153Smm free(me); 871232153Smm} 872232153Smm 873228753Smmstatic int 874228753Smmarchive_write_mtree_header(struct archive_write *a, 875228753Smm struct archive_entry *entry) 876228753Smm{ 877228753Smm struct mtree_writer *mtree= a->format_data; 878248616Smm struct mtree_entry *mtree_entry; 879248616Smm int r, r2; 880228753Smm 881228753Smm if (mtree->first) { 882228753Smm mtree->first = 0; 883228753Smm archive_strcat(&mtree->buf, "#mtree\n"); 884232153Smm if ((mtree->keys & SET_KEYS) == 0) 885248616Smm mtree->output_global_set = 0;/* Disalbed. */ 886228753Smm } 887228753Smm 888228753Smm mtree->entry_bytes_remaining = archive_entry_size(entry); 889248616Smm 890248616Smm /* While directory only mode, we do not handle non directory files. */ 891232153Smm if (mtree->dironly && archive_entry_filetype(entry) != AE_IFDIR) 892232153Smm return (ARCHIVE_OK); 893228753Smm 894248616Smm r2 = mtree_entry_new(a, entry, &mtree_entry); 895248616Smm if (r2 < ARCHIVE_WARN) 896248616Smm return (r2); 897248616Smm r = mtree_entry_tree_add(a, &mtree_entry); 898248616Smm if (r < ARCHIVE_WARN) { 899248616Smm mtree_entry_free(mtree_entry); 900248616Smm return (r); 901232153Smm } 902248616Smm mtree->mtree_entry = mtree_entry; 903228753Smm 904248616Smm /* If the current file is a regular file, we have to 905248616Smm * compute the sum of its content. 906248616Smm * Initialize a bunch of sum check context. */ 907248616Smm if (mtree_entry->reg_info) 908248616Smm sum_init(mtree); 909228753Smm 910248616Smm return (r2); 911228753Smm} 912228753Smm 913228753Smmstatic int 914248616Smmwrite_mtree_entry(struct archive_write *a, struct mtree_entry *me) 915228753Smm{ 916228753Smm struct mtree_writer *mtree = a->format_data; 917228753Smm struct archive_string *str; 918228753Smm int keys, ret; 919228753Smm 920248616Smm if (me->dir_info) { 921248616Smm if (mtree->classic) { 922248616Smm /* 923248616Smm * Output a comment line to describe the full 924248616Smm * pathname of the entry as mtree utility does 925248616Smm * while generating classic format. 926248616Smm */ 927248616Smm if (!mtree->dironly) 928248616Smm archive_strappend_char(&mtree->buf, '\n'); 929248616Smm if (me->parentdir.s) 930248616Smm archive_string_sprintf(&mtree->buf, 931248616Smm "# %s/%s\n", 932248616Smm me->parentdir.s, me->basename.s); 933248616Smm else 934248616Smm archive_string_sprintf(&mtree->buf, 935248616Smm "# %s\n", 936248616Smm me->basename.s); 937248616Smm } 938248616Smm if (mtree->output_global_set) 939248616Smm write_global(mtree); 940248616Smm } 941232153Smm archive_string_empty(&mtree->ebuf); 942248616Smm str = (mtree->indent || mtree->classic)? &mtree->ebuf : &mtree->buf; 943248616Smm 944248616Smm if (!mtree->classic && me->parentdir.s) { 945248616Smm /* 946248616Smm * If generating format is not classic one(v1), output 947248616Smm * a full pathname. 948248616Smm */ 949248616Smm mtree_quote(str, me->parentdir.s); 950248616Smm archive_strappend_char(str, '/'); 951248616Smm } 952248616Smm mtree_quote(str, me->basename.s); 953248616Smm 954248616Smm keys = get_global_set_keys(mtree, me); 955228753Smm if ((keys & F_NLINK) != 0 && 956232153Smm me->nlink != 1 && me->filetype != AE_IFDIR) 957232153Smm archive_string_sprintf(str, " nlink=%u", me->nlink); 958228753Smm 959248616Smm if ((keys & F_GNAME) != 0 && archive_strlen(&me->gname) > 0) { 960228753Smm archive_strcat(str, " gname="); 961248616Smm mtree_quote(str, me->gname.s); 962228753Smm } 963248616Smm if ((keys & F_UNAME) != 0 && archive_strlen(&me->uname) > 0) { 964228753Smm archive_strcat(str, " uname="); 965248616Smm mtree_quote(str, me->uname.s); 966228753Smm } 967232153Smm if ((keys & F_FLAGS) != 0) { 968248616Smm if (archive_strlen(&me->fflags_text) > 0) { 969232153Smm archive_strcat(str, " flags="); 970248616Smm mtree_quote(str, me->fflags_text.s); 971248616Smm } else if (mtree->set.processing && 972232153Smm (mtree->set.keys & F_FLAGS) != 0) 973232153Smm /* Overwrite the global parameter. */ 974232153Smm archive_strcat(str, " flags=none"); 975228753Smm } 976228753Smm if ((keys & F_TIME) != 0) 977228753Smm archive_string_sprintf(str, " time=%jd.%jd", 978232153Smm (intmax_t)me->mtime, (intmax_t)me->mtime_nsec); 979228753Smm if ((keys & F_MODE) != 0) 980232153Smm archive_string_sprintf(str, " mode=%o", (unsigned int)me->mode); 981228753Smm if ((keys & F_GID) != 0) 982232153Smm archive_string_sprintf(str, " gid=%jd", (intmax_t)me->gid); 983228753Smm if ((keys & F_UID) != 0) 984232153Smm archive_string_sprintf(str, " uid=%jd", (intmax_t)me->uid); 985228753Smm 986232153Smm switch (me->filetype) { 987228753Smm case AE_IFLNK: 988228753Smm if ((keys & F_TYPE) != 0) 989228753Smm archive_strcat(str, " type=link"); 990228753Smm if ((keys & F_SLINK) != 0) { 991228753Smm archive_strcat(str, " link="); 992248616Smm mtree_quote(str, me->symlink.s); 993228753Smm } 994228753Smm break; 995228753Smm case AE_IFSOCK: 996228753Smm if ((keys & F_TYPE) != 0) 997228753Smm archive_strcat(str, " type=socket"); 998228753Smm break; 999228753Smm case AE_IFCHR: 1000228753Smm if ((keys & F_TYPE) != 0) 1001228753Smm archive_strcat(str, " type=char"); 1002228753Smm if ((keys & F_DEV) != 0) { 1003228753Smm archive_string_sprintf(str, 1004232153Smm " device=native,%ju,%ju", 1005232153Smm (uintmax_t)me->rdevmajor, 1006232153Smm (uintmax_t)me->rdevminor); 1007228753Smm } 1008228753Smm break; 1009228753Smm case AE_IFBLK: 1010228753Smm if ((keys & F_TYPE) != 0) 1011228753Smm archive_strcat(str, " type=block"); 1012228753Smm if ((keys & F_DEV) != 0) { 1013228753Smm archive_string_sprintf(str, 1014232153Smm " device=native,%ju,%ju", 1015232153Smm (uintmax_t)me->rdevmajor, 1016232153Smm (uintmax_t)me->rdevminor); 1017228753Smm } 1018228753Smm break; 1019228753Smm case AE_IFDIR: 1020228753Smm if ((keys & F_TYPE) != 0) 1021228753Smm archive_strcat(str, " type=dir"); 1022228753Smm break; 1023228753Smm case AE_IFIFO: 1024228753Smm if ((keys & F_TYPE) != 0) 1025228753Smm archive_strcat(str, " type=fifo"); 1026228753Smm break; 1027228753Smm case AE_IFREG: 1028228753Smm default: /* Handle unknown file types as regular files. */ 1029228753Smm if ((keys & F_TYPE) != 0) 1030228753Smm archive_strcat(str, " type=file"); 1031228753Smm if ((keys & F_SIZE) != 0) 1032228753Smm archive_string_sprintf(str, " size=%jd", 1033232153Smm (intmax_t)me->size); 1034228753Smm break; 1035228753Smm } 1036228753Smm 1037232153Smm /* Write a bunch of sum. */ 1038248616Smm if (me->reg_info) 1039248616Smm sum_write(str, me->reg_info); 1040228753Smm 1041248616Smm archive_strappend_char(str, '\n'); 1042248616Smm if (mtree->indent || mtree->classic) 1043232153Smm mtree_indent(mtree); 1044228753Smm 1045232153Smm if (mtree->buf.length > 32768) { 1046248616Smm ret = __archive_write_output( 1047248616Smm a, mtree->buf.s, mtree->buf.length); 1048232153Smm archive_string_empty(&mtree->buf); 1049232153Smm } else 1050232153Smm ret = ARCHIVE_OK; 1051232153Smm return (ret); 1052232153Smm} 1053228753Smm 1054248616Smmstatic int 1055248616Smmwrite_dot_dot_entry(struct archive_write *a, struct mtree_entry *n) 1056248616Smm{ 1057248616Smm struct mtree_writer *mtree = a->format_data; 1058248616Smm int ret; 1059248616Smm 1060248616Smm if (n->parentdir.s) { 1061248616Smm if (mtree->indent) { 1062248616Smm int i, pd = mtree->depth * 4; 1063248616Smm for (i = 0; i < pd; i++) 1064248616Smm archive_strappend_char(&mtree->buf, ' '); 1065248616Smm } 1066248616Smm archive_string_sprintf(&mtree->buf, "# %s/%s\n", 1067248616Smm n->parentdir.s, n->basename.s); 1068248616Smm } 1069248616Smm 1070248616Smm if (mtree->indent) { 1071248616Smm archive_string_empty(&mtree->ebuf); 1072248616Smm archive_strncat(&mtree->ebuf, "..\n\n", (mtree->dironly)?3:4); 1073248616Smm mtree_indent(mtree); 1074248616Smm } else 1075248616Smm archive_strncat(&mtree->buf, "..\n\n", (mtree->dironly)?3:4); 1076248616Smm 1077248616Smm if (mtree->buf.length > 32768) { 1078248616Smm ret = __archive_write_output( 1079248616Smm a, mtree->buf.s, mtree->buf.length); 1080248616Smm archive_string_empty(&mtree->buf); 1081248616Smm } else 1082248616Smm ret = ARCHIVE_OK; 1083248616Smm return (ret); 1084248616Smm} 1085248616Smm 1086232153Smm/* 1087248616Smm * Write mtree entries saved at attr_counter_set_collect() function. 1088232153Smm */ 1089232153Smmstatic int 1090248616Smmwrite_mtree_entry_tree(struct archive_write *a) 1091232153Smm{ 1092232153Smm struct mtree_writer *mtree = a->format_data; 1093248616Smm struct mtree_entry *np = mtree->root; 1094248616Smm struct archive_rb_node *n; 1095232153Smm int ret; 1096228753Smm 1097248616Smm do { 1098248616Smm if (mtree->output_global_set) { 1099248616Smm /* 1100248616Smm * Collect attribute infomation to know which value 1101248616Smm * is frequently used among the children. 1102248616Smm */ 1103248616Smm attr_counter_set_reset(mtree); 1104248616Smm ARCHIVE_RB_TREE_FOREACH(n, &(np->dir_info->rbtree)) { 1105248616Smm struct mtree_entry *e = (struct mtree_entry *)n; 1106248616Smm if (attr_counter_set_collect(mtree, e) < 0) { 1107248616Smm archive_set_error(&a->archive, ENOMEM, 1108248616Smm "Can't allocate memory"); 1109248616Smm return (ARCHIVE_FATAL); 1110248616Smm } 1111248616Smm } 1112248616Smm } 1113248616Smm if (!np->dir_info->virtual || mtree->classic) { 1114248616Smm ret = write_mtree_entry(a, np); 1115248616Smm if (ret != ARCHIVE_OK) 1116248616Smm return (ARCHIVE_FATAL); 1117248616Smm } else { 1118248616Smm /* Whenever output_global_set is enabled 1119248616Smm * output global value(/set keywords) 1120248616Smm * even if the directory entry is not allowd 1121248616Smm * to be written because the global values 1122248616Smm * can be used for the children. */ 1123248616Smm if (mtree->output_global_set) 1124248616Smm write_global(mtree); 1125248616Smm } 1126248616Smm /* 1127248616Smm * Output the attribute of all files except directory files. 1128248616Smm */ 1129248616Smm mtree->depth++; 1130248616Smm ARCHIVE_RB_TREE_FOREACH(n, &(np->dir_info->rbtree)) { 1131248616Smm struct mtree_entry *e = (struct mtree_entry *)n; 1132228753Smm 1133248616Smm if (e->dir_info) 1134248616Smm mtree_entry_add_child_tail(np, e); 1135248616Smm else { 1136248616Smm ret = write_mtree_entry(a, e); 1137248616Smm if (ret != ARCHIVE_OK) 1138248616Smm return (ARCHIVE_FATAL); 1139248616Smm } 1140248616Smm } 1141248616Smm mtree->depth--; 1142248616Smm 1143248616Smm if (np->dir_info->children.first != NULL) { 1144248616Smm /* 1145248616Smm * Descend the tree. 1146248616Smm */ 1147248616Smm np = np->dir_info->children.first; 1148248616Smm if (mtree->indent) 1149248616Smm mtree->depth++; 1150248616Smm continue; 1151248616Smm } else if (mtree->classic) { 1152248616Smm /* 1153248616Smm * While printing mtree classic, if there are not 1154248616Smm * any directory files(except "." and "..") in the 1155248616Smm * directory, output two dots ".." as returning 1156248616Smm * the parent directory. 1157248616Smm */ 1158248616Smm ret = write_dot_dot_entry(a, np); 1159248616Smm if (ret != ARCHIVE_OK) 1160248616Smm return (ARCHIVE_FATAL); 1161248616Smm } 1162248616Smm 1163248616Smm while (np != np->parent) { 1164248616Smm if (np->dir_info->chnext == NULL) { 1165248616Smm /* 1166248616Smm * Ascend the tree; go back to the parent. 1167248616Smm */ 1168248616Smm if (mtree->indent) 1169248616Smm mtree->depth--; 1170248616Smm if (mtree->classic) { 1171248616Smm ret = write_dot_dot_entry(a, 1172248616Smm np->parent); 1173248616Smm if (ret != ARCHIVE_OK) 1174248616Smm return (ARCHIVE_FATAL); 1175248616Smm } 1176248616Smm np = np->parent; 1177248616Smm } else { 1178248616Smm /* 1179248616Smm * Switch to next mtree entry in the directory. 1180248616Smm */ 1181248616Smm np = np->dir_info->chnext; 1182248616Smm break; 1183248616Smm } 1184248616Smm } 1185248616Smm } while (np != np->parent); 1186248616Smm 1187232153Smm return (ARCHIVE_OK); 1188232153Smm} 1189228753Smm 1190232153Smmstatic int 1191232153Smmarchive_write_mtree_finish_entry(struct archive_write *a) 1192232153Smm{ 1193232153Smm struct mtree_writer *mtree = a->format_data; 1194232153Smm struct mtree_entry *me; 1195228753Smm 1196232153Smm if ((me = mtree->mtree_entry) == NULL) 1197232153Smm return (ARCHIVE_OK); 1198232153Smm mtree->mtree_entry = NULL; 1199228753Smm 1200248616Smm if (me->reg_info) 1201248616Smm sum_final(mtree, me->reg_info); 1202228753Smm 1203248616Smm return (ARCHIVE_OK); 1204228753Smm} 1205228753Smm 1206228753Smmstatic int 1207232153Smmarchive_write_mtree_close(struct archive_write *a) 1208228753Smm{ 1209228753Smm struct mtree_writer *mtree= a->format_data; 1210232153Smm int ret; 1211228753Smm 1212248616Smm if (mtree->root != NULL) { 1213248616Smm ret = write_mtree_entry_tree(a); 1214232153Smm if (ret != ARCHIVE_OK) 1215232153Smm return (ARCHIVE_FATAL); 1216232153Smm } 1217232153Smm 1218228753Smm archive_write_set_bytes_in_last_block(&a->archive, 1); 1219228753Smm 1220232153Smm return __archive_write_output(a, mtree->buf.s, mtree->buf.length); 1221228753Smm} 1222228753Smm 1223228753Smmstatic ssize_t 1224228753Smmarchive_write_mtree_data(struct archive_write *a, const void *buff, size_t n) 1225228753Smm{ 1226228753Smm struct mtree_writer *mtree= a->format_data; 1227228753Smm 1228228753Smm if (n > mtree->entry_bytes_remaining) 1229238856Smm n = (size_t)mtree->entry_bytes_remaining; 1230232153Smm mtree->entry_bytes_remaining -= n; 1231232153Smm 1232232153Smm /* We don't need to compute a regular file sum */ 1233232153Smm if (mtree->mtree_entry == NULL) 1234228753Smm return (n); 1235228753Smm 1236232153Smm if (mtree->mtree_entry->filetype == AE_IFREG) 1237232153Smm sum_update(mtree, buff, n); 1238232153Smm 1239228753Smm return (n); 1240228753Smm} 1241228753Smm 1242228753Smmstatic int 1243232153Smmarchive_write_mtree_free(struct archive_write *a) 1244228753Smm{ 1245228753Smm struct mtree_writer *mtree= a->format_data; 1246228753Smm 1247228753Smm if (mtree == NULL) 1248228753Smm return (ARCHIVE_OK); 1249228753Smm 1250232153Smm /* Make sure we dot not leave any entries. */ 1251248616Smm mtree_entry_register_free(mtree); 1252248616Smm archive_string_free(&mtree->cur_dirstr); 1253228753Smm archive_string_free(&mtree->ebuf); 1254228753Smm archive_string_free(&mtree->buf); 1255248616Smm attr_counter_set_free(mtree); 1256228753Smm free(mtree); 1257228753Smm a->format_data = NULL; 1258228753Smm return (ARCHIVE_OK); 1259228753Smm} 1260228753Smm 1261228753Smmstatic int 1262228753Smmarchive_write_mtree_options(struct archive_write *a, const char *key, 1263228753Smm const char *value) 1264228753Smm{ 1265228753Smm struct mtree_writer *mtree= a->format_data; 1266228753Smm int keybit = 0; 1267228753Smm 1268228753Smm switch (key[0]) { 1269228753Smm case 'a': 1270228753Smm if (strcmp(key, "all") == 0) 1271228753Smm keybit = ~0; 1272228753Smm break; 1273228753Smm case 'c': 1274228753Smm if (strcmp(key, "cksum") == 0) 1275228753Smm keybit = F_CKSUM; 1276228753Smm break; 1277228753Smm case 'd': 1278228753Smm if (strcmp(key, "device") == 0) 1279228753Smm keybit = F_DEV; 1280228753Smm else if (strcmp(key, "dironly") == 0) { 1281228753Smm mtree->dironly = (value != NULL)? 1: 0; 1282228753Smm return (ARCHIVE_OK); 1283228753Smm } 1284228753Smm break; 1285228753Smm case 'f': 1286228753Smm if (strcmp(key, "flags") == 0) 1287228753Smm keybit = F_FLAGS; 1288228753Smm break; 1289228753Smm case 'g': 1290228753Smm if (strcmp(key, "gid") == 0) 1291228753Smm keybit = F_GID; 1292228753Smm else if (strcmp(key, "gname") == 0) 1293228753Smm keybit = F_GNAME; 1294228753Smm break; 1295228753Smm case 'i': 1296228753Smm if (strcmp(key, "indent") == 0) { 1297228753Smm mtree->indent = (value != NULL)? 1: 0; 1298228753Smm return (ARCHIVE_OK); 1299228753Smm } 1300228753Smm break; 1301228753Smm case 'l': 1302228753Smm if (strcmp(key, "link") == 0) 1303228753Smm keybit = F_SLINK; 1304228753Smm break; 1305228753Smm case 'm': 1306228753Smm if (strcmp(key, "md5") == 0 || 1307228753Smm strcmp(key, "md5digest") == 0) 1308228753Smm keybit = F_MD5; 1309228753Smm if (strcmp(key, "mode") == 0) 1310228753Smm keybit = F_MODE; 1311228753Smm break; 1312228753Smm case 'n': 1313228753Smm if (strcmp(key, "nlink") == 0) 1314228753Smm keybit = F_NLINK; 1315228753Smm break; 1316228753Smm case 'r': 1317228753Smm if (strcmp(key, "ripemd160digest") == 0 || 1318228753Smm strcmp(key, "rmd160") == 0 || 1319228753Smm strcmp(key, "rmd160digest") == 0) 1320228753Smm keybit = F_RMD160; 1321228753Smm break; 1322228753Smm case 's': 1323228753Smm if (strcmp(key, "sha1") == 0 || 1324228753Smm strcmp(key, "sha1digest") == 0) 1325228753Smm keybit = F_SHA1; 1326228753Smm if (strcmp(key, "sha256") == 0 || 1327228753Smm strcmp(key, "sha256digest") == 0) 1328228753Smm keybit = F_SHA256; 1329228753Smm if (strcmp(key, "sha384") == 0 || 1330228753Smm strcmp(key, "sha384digest") == 0) 1331228753Smm keybit = F_SHA384; 1332228753Smm if (strcmp(key, "sha512") == 0 || 1333228753Smm strcmp(key, "sha512digest") == 0) 1334228753Smm keybit = F_SHA512; 1335228753Smm if (strcmp(key, "size") == 0) 1336228753Smm keybit = F_SIZE; 1337228753Smm break; 1338228753Smm case 't': 1339228753Smm if (strcmp(key, "time") == 0) 1340228753Smm keybit = F_TIME; 1341228753Smm else if (strcmp(key, "type") == 0) 1342228753Smm keybit = F_TYPE; 1343228753Smm break; 1344228753Smm case 'u': 1345228753Smm if (strcmp(key, "uid") == 0) 1346228753Smm keybit = F_UID; 1347228753Smm else if (strcmp(key, "uname") == 0) 1348228753Smm keybit = F_UNAME; 1349228753Smm else if (strcmp(key, "use-set") == 0) { 1350248616Smm mtree->output_global_set = (value != NULL)? 1: 0; 1351228753Smm return (ARCHIVE_OK); 1352228753Smm } 1353228753Smm break; 1354228753Smm } 1355228753Smm if (keybit != 0) { 1356228753Smm if (value != NULL) 1357228753Smm mtree->keys |= keybit; 1358228753Smm else 1359228753Smm mtree->keys &= ~keybit; 1360228753Smm return (ARCHIVE_OK); 1361228753Smm } 1362228753Smm 1363232153Smm /* Note: The "warn" return is just to inform the options 1364232153Smm * supervisor that we didn't handle it. It will generate 1365232153Smm * a suitable error if no one used this option. */ 1366228753Smm return (ARCHIVE_WARN); 1367228753Smm} 1368228753Smm 1369248616Smmstatic int 1370248616Smmarchive_write_set_format_mtree_default(struct archive *_a, const char *fn) 1371228753Smm{ 1372228753Smm struct archive_write *a = (struct archive_write *)_a; 1373228753Smm struct mtree_writer *mtree; 1374228753Smm 1375248616Smm archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, fn); 1376228753Smm 1377232153Smm if (a->format_free != NULL) 1378232153Smm (a->format_free)(a); 1379232153Smm 1380232153Smm if ((mtree = calloc(1, sizeof(*mtree))) == NULL) { 1381228753Smm archive_set_error(&a->archive, ENOMEM, 1382228753Smm "Can't allocate mtree data"); 1383228753Smm return (ARCHIVE_FATAL); 1384228753Smm } 1385228753Smm 1386232153Smm mtree->mtree_entry = NULL; 1387228753Smm mtree->first = 1; 1388228753Smm memset(&(mtree->set), 0, sizeof(mtree->set)); 1389228753Smm mtree->keys = DEFAULT_KEYS; 1390228753Smm mtree->dironly = 0; 1391228753Smm mtree->indent = 0; 1392228753Smm archive_string_init(&mtree->ebuf); 1393228753Smm archive_string_init(&mtree->buf); 1394248616Smm mtree_entry_register_init(mtree); 1395228753Smm a->format_data = mtree; 1396232153Smm a->format_free = archive_write_mtree_free; 1397228753Smm a->format_name = "mtree"; 1398228753Smm a->format_options = archive_write_mtree_options; 1399228753Smm a->format_write_header = archive_write_mtree_header; 1400232153Smm a->format_close = archive_write_mtree_close; 1401228753Smm a->format_write_data = archive_write_mtree_data; 1402228753Smm a->format_finish_entry = archive_write_mtree_finish_entry; 1403228753Smm a->archive.archive_format = ARCHIVE_FORMAT_MTREE; 1404228753Smm a->archive.archive_format_name = "mtree"; 1405228753Smm 1406228753Smm return (ARCHIVE_OK); 1407228753Smm} 1408232153Smm 1409248616Smmint 1410248616Smmarchive_write_set_format_mtree(struct archive *_a) 1411248616Smm{ 1412248616Smm return archive_write_set_format_mtree_default(_a, 1413248616Smm "archive_write_set_format_mtree"); 1414248616Smm} 1415248616Smm 1416248616Smmint 1417248616Smmarchive_write_set_format_mtree_classic(struct archive *_a) 1418248616Smm{ 1419248616Smm int r; 1420248616Smm 1421248616Smm r = archive_write_set_format_mtree_default(_a, 1422248616Smm "archive_write_set_format_mtree_classic"); 1423248616Smm if (r == ARCHIVE_OK) { 1424248616Smm struct archive_write *a = (struct archive_write *)_a; 1425248616Smm struct mtree_writer *mtree; 1426248616Smm 1427248616Smm mtree = (struct mtree_writer *)a->format_data; 1428248616Smm 1429248616Smm /* Set to output a mtree archive in classic format. */ 1430248616Smm mtree->classic = 1; 1431248616Smm /* Basically, mtree classic format uses '/set' global 1432248616Smm * value. */ 1433248616Smm mtree->output_global_set = 1; 1434248616Smm } 1435248616Smm return (r); 1436248616Smm} 1437248616Smm 1438232153Smmstatic void 1439232153Smmsum_init(struct mtree_writer *mtree) 1440232153Smm{ 1441248616Smm 1442248616Smm mtree->compute_sum = 0; 1443248616Smm 1444232153Smm if (mtree->keys & F_CKSUM) { 1445232153Smm mtree->compute_sum |= F_CKSUM; 1446232153Smm mtree->crc = 0; 1447232153Smm mtree->crc_len = 0; 1448232153Smm } 1449232153Smm#ifdef ARCHIVE_HAS_MD5 1450232153Smm if (mtree->keys & F_MD5) { 1451232153Smm if (archive_md5_init(&mtree->md5ctx) == ARCHIVE_OK) 1452232153Smm mtree->compute_sum |= F_MD5; 1453232153Smm else 1454232153Smm mtree->keys &= ~F_MD5;/* Not supported. */ 1455232153Smm } 1456232153Smm#endif 1457232153Smm#ifdef ARCHIVE_HAS_RMD160 1458232153Smm if (mtree->keys & F_RMD160) { 1459232153Smm if (archive_rmd160_init(&mtree->rmd160ctx) == ARCHIVE_OK) 1460232153Smm mtree->compute_sum |= F_RMD160; 1461232153Smm else 1462232153Smm mtree->keys &= ~F_RMD160;/* Not supported. */ 1463232153Smm } 1464232153Smm#endif 1465232153Smm#ifdef ARCHIVE_HAS_SHA1 1466232153Smm if (mtree->keys & F_SHA1) { 1467232153Smm if (archive_sha1_init(&mtree->sha1ctx) == ARCHIVE_OK) 1468232153Smm mtree->compute_sum |= F_SHA1; 1469232153Smm else 1470232153Smm mtree->keys &= ~F_SHA1;/* Not supported. */ 1471232153Smm } 1472232153Smm#endif 1473232153Smm#ifdef ARCHIVE_HAS_SHA256 1474232153Smm if (mtree->keys & F_SHA256) { 1475232153Smm if (archive_sha256_init(&mtree->sha256ctx) == ARCHIVE_OK) 1476232153Smm mtree->compute_sum |= F_SHA256; 1477232153Smm else 1478232153Smm mtree->keys &= ~F_SHA256;/* Not supported. */ 1479232153Smm } 1480232153Smm#endif 1481232153Smm#ifdef ARCHIVE_HAS_SHA384 1482232153Smm if (mtree->keys & F_SHA384) { 1483232153Smm if (archive_sha384_init(&mtree->sha384ctx) == ARCHIVE_OK) 1484232153Smm mtree->compute_sum |= F_SHA384; 1485232153Smm else 1486232153Smm mtree->keys &= ~F_SHA384;/* Not supported. */ 1487232153Smm } 1488232153Smm#endif 1489232153Smm#ifdef ARCHIVE_HAS_SHA512 1490232153Smm if (mtree->keys & F_SHA512) { 1491232153Smm if (archive_sha512_init(&mtree->sha512ctx) == ARCHIVE_OK) 1492232153Smm mtree->compute_sum |= F_SHA512; 1493232153Smm else 1494232153Smm mtree->keys &= ~F_SHA512;/* Not supported. */ 1495232153Smm } 1496232153Smm#endif 1497232153Smm} 1498232153Smm 1499232153Smmstatic void 1500232153Smmsum_update(struct mtree_writer *mtree, const void *buff, size_t n) 1501232153Smm{ 1502232153Smm if (mtree->compute_sum & F_CKSUM) { 1503232153Smm /* 1504232153Smm * Compute a POSIX 1003.2 checksum 1505232153Smm */ 1506232153Smm const unsigned char *p; 1507232153Smm size_t nn; 1508232153Smm 1509232153Smm for (nn = n, p = buff; nn--; ++p) 1510232153Smm COMPUTE_CRC(mtree->crc, *p); 1511232153Smm mtree->crc_len += n; 1512232153Smm } 1513232153Smm#ifdef ARCHIVE_HAS_MD5 1514232153Smm if (mtree->compute_sum & F_MD5) 1515232153Smm archive_md5_update(&mtree->md5ctx, buff, n); 1516232153Smm#endif 1517232153Smm#ifdef ARCHIVE_HAS_RMD160 1518232153Smm if (mtree->compute_sum & F_RMD160) 1519232153Smm archive_rmd160_update(&mtree->rmd160ctx, buff, n); 1520232153Smm#endif 1521232153Smm#ifdef ARCHIVE_HAS_SHA1 1522232153Smm if (mtree->compute_sum & F_SHA1) 1523232153Smm archive_sha1_update(&mtree->sha1ctx, buff, n); 1524232153Smm#endif 1525232153Smm#ifdef ARCHIVE_HAS_SHA256 1526232153Smm if (mtree->compute_sum & F_SHA256) 1527232153Smm archive_sha256_update(&mtree->sha256ctx, buff, n); 1528232153Smm#endif 1529232153Smm#ifdef ARCHIVE_HAS_SHA384 1530232153Smm if (mtree->compute_sum & F_SHA384) 1531232153Smm archive_sha384_update(&mtree->sha384ctx, buff, n); 1532232153Smm#endif 1533232153Smm#ifdef ARCHIVE_HAS_SHA512 1534232153Smm if (mtree->compute_sum & F_SHA512) 1535232153Smm archive_sha512_update(&mtree->sha512ctx, buff, n); 1536232153Smm#endif 1537232153Smm} 1538232153Smm 1539232153Smmstatic void 1540248616Smmsum_final(struct mtree_writer *mtree, struct reg_info *reg) 1541232153Smm{ 1542232153Smm 1543232153Smm if (mtree->compute_sum & F_CKSUM) { 1544232153Smm uint64_t len; 1545232153Smm /* Include the length of the file. */ 1546232153Smm for (len = mtree->crc_len; len != 0; len >>= 8) 1547232153Smm COMPUTE_CRC(mtree->crc, len & 0xff); 1548248616Smm reg->crc = ~mtree->crc; 1549232153Smm } 1550232153Smm#ifdef ARCHIVE_HAS_MD5 1551232153Smm if (mtree->compute_sum & F_MD5) 1552248616Smm archive_md5_final(&mtree->md5ctx, reg->buf_md5); 1553232153Smm#endif 1554232153Smm#ifdef ARCHIVE_HAS_RMD160 1555232153Smm if (mtree->compute_sum & F_RMD160) 1556248616Smm archive_rmd160_final(&mtree->rmd160ctx, reg->buf_rmd160); 1557232153Smm#endif 1558232153Smm#ifdef ARCHIVE_HAS_SHA1 1559232153Smm if (mtree->compute_sum & F_SHA1) 1560248616Smm archive_sha1_final(&mtree->sha1ctx, reg->buf_sha1); 1561232153Smm#endif 1562232153Smm#ifdef ARCHIVE_HAS_SHA256 1563232153Smm if (mtree->compute_sum & F_SHA256) 1564248616Smm archive_sha256_final(&mtree->sha256ctx, reg->buf_sha256); 1565232153Smm#endif 1566232153Smm#ifdef ARCHIVE_HAS_SHA384 1567232153Smm if (mtree->compute_sum & F_SHA384) 1568248616Smm archive_sha384_final(&mtree->sha384ctx, reg->buf_sha384); 1569232153Smm#endif 1570232153Smm#ifdef ARCHIVE_HAS_SHA512 1571232153Smm if (mtree->compute_sum & F_SHA512) 1572248616Smm archive_sha512_final(&mtree->sha512ctx, reg->buf_sha512); 1573232153Smm#endif 1574232153Smm /* Save what types of sum are computed. */ 1575248616Smm reg->compute_sum = mtree->compute_sum; 1576232153Smm} 1577232153Smm 1578232153Smm#if defined(ARCHIVE_HAS_MD5) || defined(ARCHIVE_HAS_RMD160) || \ 1579232153Smm defined(ARCHIVE_HAS_SHA1) || defined(ARCHIVE_HAS_SHA256) || \ 1580232153Smm defined(ARCHIVE_HAS_SHA384) || defined(ARCHIVE_HAS_SHA512) 1581232153Smmstatic void 1582232153Smmstrappend_bin(struct archive_string *s, const unsigned char *bin, int n) 1583232153Smm{ 1584232153Smm static const char hex[] = "0123456789abcdef"; 1585232153Smm int i; 1586232153Smm 1587232153Smm for (i = 0; i < n; i++) { 1588232153Smm archive_strappend_char(s, hex[bin[i] >> 4]); 1589232153Smm archive_strappend_char(s, hex[bin[i] & 0x0f]); 1590232153Smm } 1591232153Smm} 1592232153Smm#endif 1593232153Smm 1594232153Smmstatic void 1595248616Smmsum_write(struct archive_string *str, struct reg_info *reg) 1596232153Smm{ 1597232153Smm 1598248616Smm if (reg->compute_sum & F_CKSUM) { 1599232153Smm archive_string_sprintf(str, " cksum=%ju", 1600248616Smm (uintmax_t)reg->crc); 1601232153Smm } 1602232153Smm#ifdef ARCHIVE_HAS_MD5 1603248616Smm if (reg->compute_sum & F_MD5) { 1604232153Smm archive_strcat(str, " md5digest="); 1605248616Smm strappend_bin(str, reg->buf_md5, sizeof(reg->buf_md5)); 1606232153Smm } 1607232153Smm#endif 1608232153Smm#ifdef ARCHIVE_HAS_RMD160 1609248616Smm if (reg->compute_sum & F_RMD160) { 1610232153Smm archive_strcat(str, " rmd160digest="); 1611248616Smm strappend_bin(str, reg->buf_rmd160, sizeof(reg->buf_rmd160)); 1612232153Smm } 1613232153Smm#endif 1614232153Smm#ifdef ARCHIVE_HAS_SHA1 1615248616Smm if (reg->compute_sum & F_SHA1) { 1616232153Smm archive_strcat(str, " sha1digest="); 1617248616Smm strappend_bin(str, reg->buf_sha1, sizeof(reg->buf_sha1)); 1618232153Smm } 1619232153Smm#endif 1620232153Smm#ifdef ARCHIVE_HAS_SHA256 1621248616Smm if (reg->compute_sum & F_SHA256) { 1622232153Smm archive_strcat(str, " sha256digest="); 1623248616Smm strappend_bin(str, reg->buf_sha256, sizeof(reg->buf_sha256)); 1624232153Smm } 1625232153Smm#endif 1626232153Smm#ifdef ARCHIVE_HAS_SHA384 1627248616Smm if (reg->compute_sum & F_SHA384) { 1628232153Smm archive_strcat(str, " sha384digest="); 1629248616Smm strappend_bin(str, reg->buf_sha384, sizeof(reg->buf_sha384)); 1630232153Smm } 1631232153Smm#endif 1632232153Smm#ifdef ARCHIVE_HAS_SHA512 1633248616Smm if (reg->compute_sum & F_SHA512) { 1634232153Smm archive_strcat(str, " sha512digest="); 1635248616Smm strappend_bin(str, reg->buf_sha512, sizeof(reg->buf_sha512)); 1636232153Smm } 1637232153Smm#endif 1638232153Smm} 1639248616Smm 1640248616Smmstatic int 1641248616Smmmtree_entry_cmp_node(const struct archive_rb_node *n1, 1642248616Smm const struct archive_rb_node *n2) 1643248616Smm{ 1644248616Smm const struct mtree_entry *e1 = (const struct mtree_entry *)n1; 1645248616Smm const struct mtree_entry *e2 = (const struct mtree_entry *)n2; 1646248616Smm 1647248616Smm return (strcmp(e2->basename.s, e1->basename.s)); 1648248616Smm} 1649248616Smm 1650248616Smmstatic int 1651248616Smmmtree_entry_cmp_key(const struct archive_rb_node *n, const void *key) 1652248616Smm{ 1653248616Smm const struct mtree_entry *e = (const struct mtree_entry *)n; 1654248616Smm 1655248616Smm return (strcmp((const char *)key, e->basename.s)); 1656248616Smm} 1657248616Smm 1658248616Smm#if defined(_WIN32) || defined(__CYGWIN__) 1659248616Smmstatic int 1660248616Smmcleanup_backslash_1(char *p) 1661248616Smm{ 1662248616Smm int mb, dos; 1663248616Smm 1664248616Smm mb = dos = 0; 1665248616Smm while (*p) { 1666248616Smm if (*(unsigned char *)p > 127) 1667248616Smm mb = 1; 1668248616Smm if (*p == '\\') { 1669248616Smm /* If we have not met any multi-byte characters, 1670248616Smm * we can replace '\' with '/'. */ 1671248616Smm if (!mb) 1672248616Smm *p = '/'; 1673248616Smm dos = 1; 1674248616Smm } 1675248616Smm p++; 1676248616Smm } 1677248616Smm if (!mb || !dos) 1678248616Smm return (0); 1679248616Smm return (-1); 1680248616Smm} 1681248616Smm 1682248616Smmstatic void 1683248616Smmcleanup_backslash_2(wchar_t *p) 1684248616Smm{ 1685248616Smm 1686248616Smm /* Convert a path-separator from '\' to '/' */ 1687248616Smm while (*p != L'\0') { 1688248616Smm if (*p == L'\\') 1689248616Smm *p = L'/'; 1690248616Smm p++; 1691248616Smm } 1692248616Smm} 1693248616Smm#endif 1694248616Smm 1695248616Smm/* 1696248616Smm * Generate a parent directory name and a base name from a pathname. 1697248616Smm */ 1698248616Smmstatic int 1699248616Smmmtree_entry_setup_filenames(struct archive_write *a, struct mtree_entry *file, 1700248616Smm struct archive_entry *entry) 1701248616Smm{ 1702248616Smm const char *pathname; 1703248616Smm char *p, *dirname, *slash; 1704248616Smm size_t len; 1705248616Smm int ret = ARCHIVE_OK; 1706248616Smm 1707248616Smm archive_strcpy(&file->pathname, archive_entry_pathname(entry)); 1708248616Smm#if defined(_WIN32) || defined(__CYGWIN__) 1709248616Smm /* 1710248616Smm * Convert a path-separator from '\' to '/' 1711248616Smm */ 1712248616Smm if (cleanup_backslash_1(file->pathname.s) != 0) { 1713248616Smm const wchar_t *wp = archive_entry_pathname_w(entry); 1714248616Smm struct archive_wstring ws; 1715248616Smm 1716248616Smm if (wp != NULL) { 1717248616Smm int r; 1718248616Smm archive_string_init(&ws); 1719248616Smm archive_wstrcpy(&ws, wp); 1720248616Smm cleanup_backslash_2(ws.s); 1721248616Smm archive_string_empty(&(file->pathname)); 1722248616Smm r = archive_string_append_from_wcs(&(file->pathname), 1723248616Smm ws.s, ws.length); 1724248616Smm archive_wstring_free(&ws); 1725248616Smm if (r < 0 && errno == ENOMEM) { 1726248616Smm archive_set_error(&a->archive, ENOMEM, 1727248616Smm "Can't allocate memory"); 1728248616Smm return (ARCHIVE_FATAL); 1729248616Smm } 1730248616Smm } 1731248616Smm } 1732248616Smm#else 1733248616Smm (void)a; /* UNUSED */ 1734248616Smm#endif 1735248616Smm pathname = file->pathname.s; 1736248616Smm if (strcmp(pathname, ".") == 0) { 1737248616Smm archive_strcpy(&file->basename, "."); 1738248616Smm return (ARCHIVE_OK); 1739248616Smm } 1740248616Smm 1741248616Smm archive_strcpy(&(file->parentdir), pathname); 1742248616Smm 1743248616Smm len = file->parentdir.length; 1744248616Smm p = dirname = file->parentdir.s; 1745248616Smm 1746248616Smm /* 1747248616Smm * Remove leading '/' and '../' elements 1748248616Smm */ 1749248616Smm while (*p) { 1750248616Smm if (p[0] == '/') { 1751248616Smm p++; 1752248616Smm len--; 1753248616Smm } else if (p[0] != '.') 1754248616Smm break; 1755248616Smm else if (p[1] == '.' && p[2] == '/') { 1756248616Smm p += 3; 1757248616Smm len -= 3; 1758248616Smm } else 1759248616Smm break; 1760248616Smm } 1761248616Smm if (p != dirname) { 1762248616Smm memmove(dirname, p, len+1); 1763248616Smm p = dirname; 1764248616Smm } 1765248616Smm /* 1766248616Smm * Remove "/","/." and "/.." elements from tail. 1767248616Smm */ 1768248616Smm while (len > 0) { 1769248616Smm size_t ll = len; 1770248616Smm 1771248616Smm if (len > 0 && p[len-1] == '/') { 1772248616Smm p[len-1] = '\0'; 1773248616Smm len--; 1774248616Smm } 1775248616Smm if (len > 1 && p[len-2] == '/' && p[len-1] == '.') { 1776248616Smm p[len-2] = '\0'; 1777248616Smm len -= 2; 1778248616Smm } 1779248616Smm if (len > 2 && p[len-3] == '/' && p[len-2] == '.' && 1780248616Smm p[len-1] == '.') { 1781248616Smm p[len-3] = '\0'; 1782248616Smm len -= 3; 1783248616Smm } 1784248616Smm if (ll == len) 1785248616Smm break; 1786248616Smm } 1787248616Smm while (*p) { 1788248616Smm if (p[0] == '/') { 1789248616Smm if (p[1] == '/') 1790248616Smm /* Convert '//' --> '/' */ 1791248616Smm strcpy(p, p+1); 1792248616Smm else if (p[1] == '.' && p[2] == '/') 1793248616Smm /* Convert '/./' --> '/' */ 1794248616Smm strcpy(p, p+2); 1795248616Smm else if (p[1] == '.' && p[2] == '.' && p[3] == '/') { 1796248616Smm /* Convert 'dir/dir1/../dir2/' 1797248616Smm * --> 'dir/dir2/' 1798248616Smm */ 1799248616Smm char *rp = p -1; 1800248616Smm while (rp >= dirname) { 1801248616Smm if (*rp == '/') 1802248616Smm break; 1803248616Smm --rp; 1804248616Smm } 1805248616Smm if (rp > dirname) { 1806248616Smm strcpy(rp, p+3); 1807248616Smm p = rp; 1808248616Smm } else { 1809248616Smm strcpy(dirname, p+4); 1810248616Smm p = dirname; 1811248616Smm } 1812248616Smm } else 1813248616Smm p++; 1814248616Smm } else 1815248616Smm p++; 1816248616Smm } 1817248616Smm p = dirname; 1818248616Smm len = strlen(p); 1819248616Smm 1820248616Smm /* 1821248616Smm * Add "./" prefiex. 1822248616Smm * NOTE: If the pathname does not have a path separator, we have 1823248616Smm * to add "./" to the head of the pathename because mtree reader 1824248616Smm * will suppose that it is v1(a.k.a classic) mtree format and 1825248616Smm * change the directory unexpectedly and so it will make a wrong 1826248616Smm * path. 1827248616Smm */ 1828248616Smm if (strcmp(p, ".") != 0 && strncmp(p, "./", 2) != 0) { 1829248616Smm struct archive_string as; 1830248616Smm archive_string_init(&as); 1831248616Smm archive_strcpy(&as, "./"); 1832248616Smm archive_strncat(&as, p, len); 1833248616Smm archive_string_empty(&file->parentdir); 1834248616Smm archive_string_concat(&file->parentdir, &as); 1835248616Smm archive_string_free(&as); 1836248616Smm p = file->parentdir.s; 1837248616Smm len = archive_strlen(&file->parentdir); 1838248616Smm } 1839248616Smm 1840248616Smm /* 1841248616Smm * Find out the position which points the last position of 1842248616Smm * path separator('/'). 1843248616Smm */ 1844248616Smm slash = NULL; 1845248616Smm for (; *p != '\0'; p++) { 1846248616Smm if (*p == '/') 1847248616Smm slash = p; 1848248616Smm } 1849248616Smm if (slash == NULL) { 1850248616Smm /* The pathname doesn't have a parent directory. */ 1851248616Smm file->parentdir.length = len; 1852248616Smm archive_string_copy(&(file->basename), &(file->parentdir)); 1853248616Smm archive_string_empty(&(file->parentdir)); 1854248616Smm *file->parentdir.s = '\0'; 1855248616Smm return (ret); 1856248616Smm } 1857248616Smm 1858248616Smm /* Make a basename from dirname and slash */ 1859248616Smm *slash = '\0'; 1860248616Smm file->parentdir.length = slash - dirname; 1861248616Smm archive_strcpy(&(file->basename), slash + 1); 1862248616Smm return (ret); 1863248616Smm} 1864248616Smm 1865248616Smmstatic int 1866248616Smmmtree_entry_create_virtual_dir(struct archive_write *a, const char *pathname, 1867248616Smm struct mtree_entry **m_entry) 1868248616Smm{ 1869248616Smm struct archive_entry *entry; 1870248616Smm struct mtree_entry *file; 1871248616Smm int r; 1872248616Smm 1873248616Smm entry = archive_entry_new(); 1874248616Smm if (entry == NULL) { 1875248616Smm *m_entry = NULL; 1876248616Smm archive_set_error(&a->archive, ENOMEM, 1877248616Smm "Can't allocate memory"); 1878248616Smm return (ARCHIVE_FATAL); 1879248616Smm } 1880248616Smm archive_entry_copy_pathname(entry, pathname); 1881248616Smm archive_entry_set_mode(entry, AE_IFDIR | 0755); 1882248616Smm archive_entry_set_mtime(entry, time(NULL), 0); 1883248616Smm 1884248616Smm r = mtree_entry_new(a, entry, &file); 1885248616Smm archive_entry_free(entry); 1886248616Smm if (r < ARCHIVE_WARN) { 1887248616Smm *m_entry = NULL; 1888248616Smm archive_set_error(&a->archive, ENOMEM, 1889248616Smm "Can't allocate memory"); 1890248616Smm return (ARCHIVE_FATAL); 1891248616Smm } 1892248616Smm 1893248616Smm file->dir_info->virtual = 1; 1894248616Smm 1895248616Smm *m_entry = file; 1896248616Smm return (ARCHIVE_OK); 1897248616Smm} 1898248616Smm 1899248616Smmstatic void 1900248616Smmmtree_entry_register_add(struct mtree_writer *mtree, struct mtree_entry *file) 1901248616Smm{ 1902248616Smm file->next = NULL; 1903248616Smm *mtree->file_list.last = file; 1904248616Smm mtree->file_list.last = &(file->next); 1905248616Smm} 1906248616Smm 1907248616Smmstatic void 1908248616Smmmtree_entry_register_init(struct mtree_writer *mtree) 1909248616Smm{ 1910248616Smm mtree->file_list.first = NULL; 1911248616Smm mtree->file_list.last = &(mtree->file_list.first); 1912248616Smm} 1913248616Smm 1914248616Smmstatic void 1915248616Smmmtree_entry_register_free(struct mtree_writer *mtree) 1916248616Smm{ 1917248616Smm struct mtree_entry *file, *file_next; 1918248616Smm 1919248616Smm file = mtree->file_list.first; 1920248616Smm while (file != NULL) { 1921248616Smm file_next = file->next; 1922248616Smm mtree_entry_free(file); 1923248616Smm file = file_next; 1924248616Smm } 1925248616Smm} 1926248616Smm 1927248616Smmstatic int 1928248616Smmmtree_entry_add_child_tail(struct mtree_entry *parent, 1929248616Smm struct mtree_entry *child) 1930248616Smm{ 1931248616Smm child->dir_info->chnext = NULL; 1932248616Smm *parent->dir_info->children.last = child; 1933248616Smm parent->dir_info->children.last = &(child->dir_info->chnext); 1934248616Smm return (1); 1935248616Smm} 1936248616Smm 1937248616Smm/* 1938248616Smm * Find a entry from a parent entry with the name. 1939248616Smm */ 1940248616Smmstatic struct mtree_entry * 1941248616Smmmtree_entry_find_child(struct mtree_entry *parent, const char *child_name) 1942248616Smm{ 1943248616Smm struct mtree_entry *np; 1944248616Smm 1945248616Smm if (parent == NULL) 1946248616Smm return (NULL); 1947248616Smm np = (struct mtree_entry *)__archive_rb_tree_find_node( 1948248616Smm &(parent->dir_info->rbtree), child_name); 1949248616Smm return (np); 1950248616Smm} 1951248616Smm 1952248616Smmstatic int 1953248616Smmget_path_component(char *name, size_t n, const char *fn) 1954248616Smm{ 1955248616Smm char *p; 1956248616Smm size_t l; 1957248616Smm 1958248616Smm p = strchr(fn, '/'); 1959248616Smm if (p == NULL) { 1960248616Smm if ((l = strlen(fn)) == 0) 1961248616Smm return (0); 1962248616Smm } else 1963248616Smm l = p - fn; 1964248616Smm if (l > n -1) 1965248616Smm return (-1); 1966248616Smm memcpy(name, fn, l); 1967248616Smm name[l] = '\0'; 1968248616Smm 1969248616Smm return ((int)l); 1970248616Smm} 1971248616Smm 1972248616Smm/* 1973248616Smm * Add a new entry into the tree. 1974248616Smm */ 1975248616Smmstatic int 1976248616Smmmtree_entry_tree_add(struct archive_write *a, struct mtree_entry **filep) 1977248616Smm{ 1978248616Smm#if defined(_WIN32) && !defined(__CYGWIN__) 1979248616Smm char name[_MAX_FNAME];/* Included null terminator size. */ 1980248616Smm#elif defined(NAME_MAX) && NAME_MAX >= 255 1981248616Smm char name[NAME_MAX+1]; 1982248616Smm#else 1983248616Smm char name[256]; 1984248616Smm#endif 1985248616Smm struct mtree_writer *mtree = (struct mtree_writer *)a->format_data; 1986248616Smm struct mtree_entry *dent, *file, *np; 1987248616Smm const char *fn, *p; 1988248616Smm int l, r; 1989248616Smm 1990248616Smm file = *filep; 1991248616Smm if (file->parentdir.length == 0 && file->basename.length == 1 && 1992248616Smm file->basename.s[0] == '.') { 1993248616Smm file->parent = file; 1994248616Smm if (mtree->root != NULL) { 1995248616Smm np = mtree->root; 1996248616Smm goto same_entry; 1997248616Smm } 1998248616Smm mtree->root = file; 1999248616Smm mtree_entry_register_add(mtree, file); 2000248616Smm return (ARCHIVE_OK); 2001248616Smm } 2002248616Smm 2003248616Smm if (file->parentdir.length == 0) { 2004248616Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 2005248616Smm "Internal programing error " 2006248616Smm "in generating canonical name for %s", 2007248616Smm file->pathname.s); 2008248616Smm return (ARCHIVE_FAILED); 2009248616Smm } 2010248616Smm 2011248616Smm fn = p = file->parentdir.s; 2012248616Smm 2013248616Smm /* 2014248616Smm * If the path of the parent directory of `file' entry is 2015248616Smm * the same as the path of `cur_dirent', add `file' entry to 2016248616Smm * `cur_dirent'. 2017248616Smm */ 2018248616Smm if (archive_strlen(&(mtree->cur_dirstr)) 2019248616Smm == archive_strlen(&(file->parentdir)) && 2020248616Smm strcmp(mtree->cur_dirstr.s, fn) == 0) { 2021248616Smm if (!__archive_rb_tree_insert_node( 2022248616Smm &(mtree->cur_dirent->dir_info->rbtree), 2023248616Smm (struct archive_rb_node *)file)) { 2024248616Smm /* There is the same name in the tree. */ 2025248616Smm np = (struct mtree_entry *)__archive_rb_tree_find_node( 2026248616Smm &(mtree->cur_dirent->dir_info->rbtree), 2027248616Smm file->basename.s); 2028248616Smm goto same_entry; 2029248616Smm } 2030248616Smm file->parent = mtree->cur_dirent; 2031248616Smm mtree_entry_register_add(mtree, file); 2032248616Smm return (ARCHIVE_OK); 2033248616Smm } 2034248616Smm 2035248616Smm dent = mtree->root; 2036248616Smm for (;;) { 2037248616Smm l = get_path_component(name, sizeof(name), fn); 2038248616Smm if (l == 0) { 2039248616Smm np = NULL; 2040248616Smm break; 2041248616Smm } 2042248616Smm if (l < 0) { 2043248616Smm archive_set_error(&a->archive, 2044248616Smm ARCHIVE_ERRNO_MISC, 2045248616Smm "A name buffer is too small"); 2046248616Smm return (ARCHIVE_FATAL); 2047248616Smm } 2048248616Smm if (l == 1 && name[0] == '.' && dent != NULL && 2049248616Smm dent == mtree->root) { 2050248616Smm fn += l; 2051248616Smm if (fn[0] == '/') 2052248616Smm fn++; 2053248616Smm continue; 2054248616Smm } 2055248616Smm 2056248616Smm np = mtree_entry_find_child(dent, name); 2057248616Smm if (np == NULL || fn[0] == '\0') 2058248616Smm break; 2059248616Smm 2060248616Smm /* Find next sub directory. */ 2061248616Smm if (!np->dir_info) { 2062248616Smm /* NOT Directory! */ 2063248616Smm archive_set_error(&a->archive, 2064248616Smm ARCHIVE_ERRNO_MISC, 2065248616Smm "`%s' is not directory, we cannot insert `%s' ", 2066248616Smm np->pathname.s, file->pathname.s); 2067248616Smm return (ARCHIVE_FAILED); 2068248616Smm } 2069248616Smm fn += l; 2070248616Smm if (fn[0] == '/') 2071248616Smm fn++; 2072248616Smm dent = np; 2073248616Smm } 2074248616Smm if (np == NULL) { 2075248616Smm /* 2076248616Smm * Create virtual parent directories. 2077248616Smm */ 2078248616Smm while (fn[0] != '\0') { 2079248616Smm struct mtree_entry *vp; 2080248616Smm struct archive_string as; 2081248616Smm 2082248616Smm archive_string_init(&as); 2083248616Smm archive_strncat(&as, p, fn - p + l); 2084248616Smm if (as.s[as.length-1] == '/') { 2085248616Smm as.s[as.length-1] = '\0'; 2086248616Smm as.length--; 2087248616Smm } 2088248616Smm r = mtree_entry_create_virtual_dir(a, as.s, &vp); 2089248616Smm archive_string_free(&as); 2090248616Smm if (r < ARCHIVE_WARN) 2091248616Smm return (r); 2092248616Smm 2093248616Smm if (strcmp(vp->pathname.s, ".") == 0) { 2094248616Smm vp->parent = vp; 2095248616Smm mtree->root = vp; 2096248616Smm } else { 2097248616Smm __archive_rb_tree_insert_node( 2098248616Smm &(dent->dir_info->rbtree), 2099248616Smm (struct archive_rb_node *)vp); 2100248616Smm vp->parent = dent; 2101248616Smm } 2102248616Smm mtree_entry_register_add(mtree, vp); 2103248616Smm np = vp; 2104248616Smm 2105248616Smm fn += l; 2106248616Smm if (fn[0] == '/') 2107248616Smm fn++; 2108248616Smm l = get_path_component(name, sizeof(name), fn); 2109248616Smm if (l < 0) { 2110248616Smm archive_string_free(&as); 2111248616Smm archive_set_error(&a->archive, 2112248616Smm ARCHIVE_ERRNO_MISC, 2113248616Smm "A name buffer is too small"); 2114248616Smm return (ARCHIVE_FATAL); 2115248616Smm } 2116248616Smm dent = np; 2117248616Smm } 2118248616Smm 2119248616Smm /* Found out the parent directory where `file' can be 2120248616Smm * inserted. */ 2121248616Smm mtree->cur_dirent = dent; 2122248616Smm archive_string_empty(&(mtree->cur_dirstr)); 2123248616Smm archive_string_ensure(&(mtree->cur_dirstr), 2124248616Smm archive_strlen(&(dent->parentdir)) + 2125248616Smm archive_strlen(&(dent->basename)) + 2); 2126248616Smm if (archive_strlen(&(dent->parentdir)) + 2127248616Smm archive_strlen(&(dent->basename)) == 0) 2128248616Smm mtree->cur_dirstr.s[0] = 0; 2129248616Smm else { 2130248616Smm if (archive_strlen(&(dent->parentdir)) > 0) { 2131248616Smm archive_string_copy(&(mtree->cur_dirstr), 2132248616Smm &(dent->parentdir)); 2133248616Smm archive_strappend_char( 2134248616Smm &(mtree->cur_dirstr), '/'); 2135248616Smm } 2136248616Smm archive_string_concat(&(mtree->cur_dirstr), 2137248616Smm &(dent->basename)); 2138248616Smm } 2139248616Smm 2140248616Smm if (!__archive_rb_tree_insert_node( 2141248616Smm &(dent->dir_info->rbtree), 2142248616Smm (struct archive_rb_node *)file)) { 2143248616Smm np = (struct mtree_entry *)__archive_rb_tree_find_node( 2144248616Smm &(dent->dir_info->rbtree), file->basename.s); 2145248616Smm goto same_entry; 2146248616Smm } 2147248616Smm file->parent = dent; 2148248616Smm mtree_entry_register_add(mtree, file); 2149248616Smm return (ARCHIVE_OK); 2150248616Smm } 2151248616Smm 2152248616Smmsame_entry: 2153248616Smm /* 2154248616Smm * We have already has the entry the filename of which is 2155248616Smm * the same. 2156248616Smm */ 2157248616Smm r = mtree_entry_exchange_same_entry(a, np, file); 2158248616Smm if (r < ARCHIVE_WARN) 2159248616Smm return (r); 2160248616Smm if (np->dir_info) 2161248616Smm np->dir_info->virtual = 0; 2162248616Smm *filep = np; 2163248616Smm mtree_entry_free(file); 2164248616Smm return (ARCHIVE_WARN); 2165248616Smm} 2166248616Smm 2167248616Smmstatic int 2168248616Smmmtree_entry_exchange_same_entry(struct archive_write *a, struct mtree_entry *np, 2169248616Smm struct mtree_entry *file) 2170248616Smm{ 2171248616Smm 2172248616Smm if ((np->mode & AE_IFMT) != (file->mode & AE_IFMT)) { 2173248616Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 2174248616Smm "Found duplicate entries `%s' and its file type is " 2175248616Smm "different", 2176248616Smm np->pathname.s); 2177248616Smm return (ARCHIVE_FAILED); 2178248616Smm } 2179248616Smm 2180248616Smm /* Update the existent mtree entry's attributes by the new one's. */ 2181248616Smm archive_string_empty(&np->symlink); 2182248616Smm archive_string_concat(&np->symlink, &file->symlink); 2183248616Smm archive_string_empty(&np->uname); 2184248616Smm archive_string_concat(&np->uname, &file->uname); 2185248616Smm archive_string_empty(&np->gname); 2186248616Smm archive_string_concat(&np->gname, &file->gname); 2187248616Smm archive_string_empty(&np->fflags_text); 2188248616Smm archive_string_concat(&np->fflags_text, &file->fflags_text); 2189248616Smm np->nlink = file->nlink; 2190248616Smm np->filetype = file->filetype; 2191248616Smm np->mode = file->mode; 2192248616Smm np->size = file->size; 2193248616Smm np->uid = file->uid; 2194248616Smm np->gid = file->gid; 2195248616Smm np->fflags_set = file->fflags_set; 2196248616Smm np->fflags_clear = file->fflags_clear; 2197248616Smm np->mtime = file->mtime; 2198248616Smm np->mtime_nsec = file->mtime_nsec; 2199248616Smm np->rdevmajor = file->rdevmajor; 2200248616Smm np->rdevminor = file->rdevminor; 2201248616Smm 2202248616Smm return (ARCHIVE_WARN); 2203248616Smm} 2204