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: stable/10/contrib/libarchive/libarchive/archive_write_set_format_mtree.c 368708 2020-12-16 22:25:40Z mm $"); 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" 38302001Smm#include "archive_digest_private.h" 39228753Smm#include "archive_entry.h" 40368708Smm#include "archive_entry_private.h" 41228753Smm#include "archive_private.h" 42248616Smm#include "archive_rb.h" 43248616Smm#include "archive_string.h" 44228753Smm#include "archive_write_private.h" 45228753Smm 46228753Smm#define INDENTNAMELEN 15 47228753Smm#define MAXLINELEN 80 48232153Smm#define SET_KEYS \ 49232153Smm (F_FLAGS | F_GID | F_GNAME | F_MODE | F_TYPE | F_UID | F_UNAME) 50228753Smm 51248616Smmstruct attr_counter { 52248616Smm struct attr_counter *prev; 53248616Smm struct attr_counter *next; 54248616Smm struct mtree_entry *m_entry; 55248616Smm int count; 56248616Smm}; 57232153Smm 58248616Smmstruct att_counter_set { 59248616Smm struct attr_counter *uid_list; 60248616Smm struct attr_counter *gid_list; 61248616Smm struct attr_counter *mode_list; 62248616Smm struct attr_counter *flags_list; 63248616Smm}; 64232153Smm 65248616Smmstruct mtree_chain { 66248616Smm struct mtree_entry *first; 67248616Smm struct mtree_entry **last; 68248616Smm}; 69248616Smm 70248616Smm/* 71248616Smm * The Data only for a directory file. 72248616Smm */ 73248616Smmstruct dir_info { 74248616Smm struct archive_rb_tree rbtree; 75248616Smm struct mtree_chain children; 76248616Smm struct mtree_entry *chnext; 77248616Smm int virtual; 78248616Smm}; 79248616Smm 80248616Smm/* 81248616Smm * The Data only for a regular file. 82248616Smm */ 83248616Smmstruct reg_info { 84232153Smm int compute_sum; 85232153Smm uint32_t crc; 86368708Smm struct ae_digest digest; 87232153Smm}; 88232153Smm 89248616Smmstruct mtree_entry { 90248616Smm struct archive_rb_node rbnode; 91248616Smm struct mtree_entry *next; 92248616Smm struct mtree_entry *parent; 93248616Smm struct dir_info *dir_info; 94248616Smm struct reg_info *reg_info; 95248616Smm 96248616Smm struct archive_string parentdir; 97248616Smm struct archive_string basename; 98248616Smm struct archive_string pathname; 99248616Smm struct archive_string symlink; 100248616Smm struct archive_string uname; 101248616Smm struct archive_string gname; 102248616Smm struct archive_string fflags_text; 103248616Smm unsigned int nlink; 104248616Smm mode_t filetype; 105248616Smm mode_t mode; 106248616Smm int64_t size; 107248616Smm int64_t uid; 108248616Smm int64_t gid; 109248616Smm time_t mtime; 110248616Smm long mtime_nsec; 111248616Smm unsigned long fflags_set; 112248616Smm unsigned long fflags_clear; 113248616Smm dev_t rdevmajor; 114248616Smm dev_t rdevminor; 115302001Smm dev_t devmajor; 116302001Smm dev_t devminor; 117302001Smm int64_t ino; 118232153Smm}; 119232153Smm 120228753Smmstruct mtree_writer { 121232153Smm struct mtree_entry *mtree_entry; 122248616Smm struct mtree_entry *root; 123248616Smm struct mtree_entry *cur_dirent; 124248616Smm struct archive_string cur_dirstr; 125248616Smm struct mtree_chain file_list; 126248616Smm 127228753Smm struct archive_string ebuf; 128228753Smm struct archive_string buf; 129228753Smm int first; 130228753Smm uint64_t entry_bytes_remaining; 131248616Smm 132248616Smm /* 133248616Smm * Set global value. 134248616Smm */ 135228753Smm struct { 136248616Smm int processing; 137228753Smm mode_t type; 138228753Smm int keys; 139232153Smm int64_t uid; 140232153Smm int64_t gid; 141228753Smm mode_t mode; 142228753Smm unsigned long fflags_set; 143228753Smm unsigned long fflags_clear; 144248616Smm } set; 145248616Smm struct att_counter_set acs; 146248616Smm int classic; 147248616Smm int depth; 148232153Smm 149232153Smm /* check sum */ 150228753Smm int compute_sum; 151228753Smm uint32_t crc; 152228753Smm uint64_t crc_len; 153228753Smm#ifdef ARCHIVE_HAS_MD5 154228753Smm archive_md5_ctx md5ctx; 155228753Smm#endif 156228753Smm#ifdef ARCHIVE_HAS_RMD160 157228753Smm archive_rmd160_ctx rmd160ctx; 158228753Smm#endif 159228753Smm#ifdef ARCHIVE_HAS_SHA1 160228753Smm archive_sha1_ctx sha1ctx; 161228753Smm#endif 162228753Smm#ifdef ARCHIVE_HAS_SHA256 163228753Smm archive_sha256_ctx sha256ctx; 164228753Smm#endif 165228753Smm#ifdef ARCHIVE_HAS_SHA384 166228753Smm archive_sha384_ctx sha384ctx; 167228753Smm#endif 168228753Smm#ifdef ARCHIVE_HAS_SHA512 169228753Smm archive_sha512_ctx sha512ctx; 170228753Smm#endif 171228753Smm /* Keyword options */ 172228753Smm int keys; 173353377Smm#define F_CKSUM 0x00000001 /* checksum */ 174228753Smm#define F_DEV 0x00000002 /* device type */ 175228753Smm#define F_DONE 0x00000004 /* directory done */ 176228753Smm#define F_FLAGS 0x00000008 /* file flags */ 177228753Smm#define F_GID 0x00000010 /* gid */ 178228753Smm#define F_GNAME 0x00000020 /* group name */ 179228753Smm#define F_IGN 0x00000040 /* ignore */ 180228753Smm#define F_MAGIC 0x00000080 /* name has magic chars */ 181228753Smm#define F_MD5 0x00000100 /* MD5 digest */ 182228753Smm#define F_MODE 0x00000200 /* mode */ 183228753Smm#define F_NLINK 0x00000400 /* number of links */ 184228753Smm#define F_NOCHANGE 0x00000800 /* If owner/mode "wrong", do 185228753Smm * not change */ 186228753Smm#define F_OPT 0x00001000 /* existence optional */ 187228753Smm#define F_RMD160 0x00002000 /* RIPEMD160 digest */ 188228753Smm#define F_SHA1 0x00004000 /* SHA-1 digest */ 189228753Smm#define F_SIZE 0x00008000 /* size */ 190228753Smm#define F_SLINK 0x00010000 /* symbolic link */ 191228753Smm#define F_TAGS 0x00020000 /* tags */ 192228753Smm#define F_TIME 0x00040000 /* modification time */ 193228753Smm#define F_TYPE 0x00080000 /* file type */ 194228753Smm#define F_UID 0x00100000 /* uid */ 195228753Smm#define F_UNAME 0x00200000 /* user name */ 196228753Smm#define F_VISIT 0x00400000 /* file visited */ 197228753Smm#define F_SHA256 0x00800000 /* SHA-256 digest */ 198228753Smm#define F_SHA384 0x01000000 /* SHA-384 digest */ 199228753Smm#define F_SHA512 0x02000000 /* SHA-512 digest */ 200302001Smm#define F_INO 0x04000000 /* inode number */ 201302001Smm#define F_RESDEV 0x08000000 /* device ID on which the 202302001Smm * entry resides */ 203228753Smm 204228753Smm /* Options */ 205248616Smm int dironly; /* If it is set, ignore all files except 206248616Smm * directory files, like mtree(8) -d option. */ 207248616Smm int indent; /* If it is set, indent output data. */ 208248616Smm int output_global_set; /* If it is set, use /set keyword to set 209248616Smm * global values. When generating mtree 210248616Smm * classic format, it is set by default. */ 211228753Smm}; 212228753Smm 213228753Smm#define DEFAULT_KEYS (F_DEV | F_FLAGS | F_GID | F_GNAME | F_SLINK | F_MODE\ 214228753Smm | F_NLINK | F_SIZE | F_TIME | F_TYPE | F_UID\ 215228753Smm | F_UNAME) 216248616Smm#define attr_counter_set_reset attr_counter_set_free 217228753Smm 218248616Smmstatic void attr_counter_free(struct attr_counter **); 219248616Smmstatic int attr_counter_inc(struct attr_counter **, struct attr_counter *, 220248616Smm struct attr_counter *, struct mtree_entry *); 221248616Smmstatic struct attr_counter * attr_counter_new(struct mtree_entry *, 222232153Smm struct attr_counter *); 223248616Smmstatic int attr_counter_set_collect(struct mtree_writer *, 224248616Smm struct mtree_entry *); 225248616Smmstatic void attr_counter_set_free(struct mtree_writer *); 226248616Smmstatic int get_global_set_keys(struct mtree_writer *, struct mtree_entry *); 227248616Smmstatic int mtree_entry_add_child_tail(struct mtree_entry *, 228248616Smm struct mtree_entry *); 229248616Smmstatic int mtree_entry_create_virtual_dir(struct archive_write *, const char *, 230248616Smm struct mtree_entry **); 231248616Smmstatic int mtree_entry_cmp_node(const struct archive_rb_node *, 232248616Smm const struct archive_rb_node *); 233248616Smmstatic int mtree_entry_cmp_key(const struct archive_rb_node *, const void *); 234248616Smmstatic int mtree_entry_exchange_same_entry(struct archive_write *, 235248616Smm struct mtree_entry *, struct mtree_entry *); 236248616Smmstatic void mtree_entry_free(struct mtree_entry *); 237248616Smmstatic int mtree_entry_new(struct archive_write *, struct archive_entry *, 238248616Smm struct mtree_entry **); 239248616Smmstatic void mtree_entry_register_free(struct mtree_writer *); 240248616Smmstatic void mtree_entry_register_init(struct mtree_writer *); 241248616Smmstatic int mtree_entry_setup_filenames(struct archive_write *, 242248616Smm struct mtree_entry *, struct archive_entry *); 243248616Smmstatic int mtree_entry_tree_add(struct archive_write *, struct mtree_entry **); 244232153Smmstatic void sum_init(struct mtree_writer *); 245232153Smmstatic void sum_update(struct mtree_writer *, const void *, size_t); 246248616Smmstatic void sum_final(struct mtree_writer *, struct reg_info *); 247248616Smmstatic void sum_write(struct archive_string *, struct reg_info *); 248248616Smmstatic int write_mtree_entry(struct archive_write *, struct mtree_entry *); 249248616Smmstatic int write_dot_dot_entry(struct archive_write *, struct mtree_entry *); 250232153Smm 251228753Smm#define COMPUTE_CRC(var, ch) (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)] 252228753Smmstatic const uint32_t crctab[] = { 253228753Smm 0x0, 254228753Smm 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 255228753Smm 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 256228753Smm 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 257228753Smm 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 258228753Smm 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 259228753Smm 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 260228753Smm 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 261228753Smm 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 262228753Smm 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 263228753Smm 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, 264228753Smm 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, 265228753Smm 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 266228753Smm 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 267228753Smm 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 268228753Smm 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 269228753Smm 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 270228753Smm 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 271228753Smm 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 272228753Smm 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 273228753Smm 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 274228753Smm 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 275228753Smm 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 276228753Smm 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 277228753Smm 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, 278228753Smm 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 279228753Smm 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 280228753Smm 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 281228753Smm 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 282228753Smm 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, 283228753Smm 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 284228753Smm 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 285228753Smm 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 286228753Smm 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 287228753Smm 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 288228753Smm 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, 289228753Smm 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 290228753Smm 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 291228753Smm 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 292228753Smm 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 293228753Smm 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 294228753Smm 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 295228753Smm 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, 296228753Smm 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 297228753Smm 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 298228753Smm 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 299228753Smm 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 300228753Smm 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 301228753Smm 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, 302228753Smm 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 303228753Smm 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 304228753Smm 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 305228753Smm}; 306228753Smm 307248616Smmstatic const unsigned char safe_char[256] = { 308248616Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */ 309248616Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */ 310248616Smm /* !"$%&'()*+,-./ EXCLUSION:0x20( ) 0x23(#) */ 311248616Smm 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */ 312248616Smm /* 0123456789:;<>? EXCLUSION:0x3d(=) */ 313248616Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, /* 30 - 3F */ 314248616Smm /* @ABCDEFGHIJKLMNO */ 315248616Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */ 316248616Smm /* PQRSTUVWXYZ[]^_ EXCLUSION:0x5c(\) */ 317248616Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, /* 50 - 5F */ 318248616Smm /* `abcdefghijklmno */ 319248616Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */ 320248616Smm /* pqrstuvwxyz{|}~ */ 321248616Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */ 322248616Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */ 323248616Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */ 324248616Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */ 325248616Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */ 326248616Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */ 327248616Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */ 328248616Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */ 329248616Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */ 330248616Smm}; 331228753Smm 332228753Smmstatic void 333228753Smmmtree_quote(struct archive_string *s, const char *str) 334228753Smm{ 335228753Smm const char *start; 336228753Smm char buf[4]; 337228753Smm unsigned char c; 338228753Smm 339228753Smm for (start = str; *str != '\0'; ++str) { 340248616Smm if (safe_char[*(const unsigned char *)str]) 341228753Smm continue; 342228753Smm if (start != str) 343228753Smm archive_strncat(s, start, str - start); 344228753Smm c = (unsigned char)*str; 345228753Smm buf[0] = '\\'; 346228753Smm buf[1] = (c / 64) + '0'; 347228753Smm buf[2] = (c / 8 % 8) + '0'; 348228753Smm buf[3] = (c % 8) + '0'; 349228753Smm archive_strncat(s, buf, 4); 350228753Smm start = str + 1; 351228753Smm } 352228753Smm 353228753Smm if (start != str) 354228753Smm archive_strncat(s, start, str - start); 355228753Smm} 356228753Smm 357232153Smm/* 358353377Smm * Indent a line as the mtree utility does so it is readable for people. 359232153Smm */ 360228753Smmstatic void 361228753Smmmtree_indent(struct mtree_writer *mtree) 362228753Smm{ 363248616Smm int i, fn, nd, pd; 364228753Smm const char *r, *s, *x; 365228753Smm 366248616Smm if (mtree->classic) { 367248616Smm if (mtree->indent) { 368248616Smm nd = 0; 369248616Smm pd = mtree->depth * 4; 370248616Smm } else { 371248616Smm nd = mtree->depth?4:0; 372248616Smm pd = 0; 373248616Smm } 374248616Smm } else 375248616Smm nd = pd = 0; 376228753Smm fn = 1; 377228753Smm s = r = mtree->ebuf.s; 378228753Smm x = NULL; 379228753Smm while (*r == ' ') 380228753Smm r++; 381228753Smm while ((r = strchr(r, ' ')) != NULL) { 382228753Smm if (fn) { 383228753Smm fn = 0; 384248616Smm for (i = 0; i < nd + pd; i++) 385248616Smm archive_strappend_char(&mtree->buf, ' '); 386228753Smm archive_strncat(&mtree->buf, s, r - s); 387248616Smm if (nd + (r -s) > INDENTNAMELEN) { 388228753Smm archive_strncat(&mtree->buf, " \\\n", 3); 389248616Smm for (i = 0; i < (INDENTNAMELEN + 1 + pd); i++) 390228753Smm archive_strappend_char(&mtree->buf, ' '); 391228753Smm } else { 392248616Smm for (i = (int)(r -s + nd); 393248616Smm i < (INDENTNAMELEN + 1); i++) 394228753Smm archive_strappend_char(&mtree->buf, ' '); 395228753Smm } 396228753Smm s = ++r; 397228753Smm x = NULL; 398228753Smm continue; 399228753Smm } 400248616Smm if (pd + (r - s) <= MAXLINELEN - 3 - INDENTNAMELEN) 401228753Smm x = r++; 402228753Smm else { 403228753Smm if (x == NULL) 404228753Smm x = r; 405228753Smm archive_strncat(&mtree->buf, s, x - s); 406228753Smm archive_strncat(&mtree->buf, " \\\n", 3); 407248616Smm for (i = 0; i < (INDENTNAMELEN + 1 + pd); i++) 408228753Smm archive_strappend_char(&mtree->buf, ' '); 409228753Smm s = r = ++x; 410228753Smm x = NULL; 411228753Smm } 412228753Smm } 413248616Smm if (fn) { 414248616Smm for (i = 0; i < nd + pd; i++) 415248616Smm archive_strappend_char(&mtree->buf, ' '); 416248616Smm archive_strcat(&mtree->buf, s); 417248616Smm s += strlen(s); 418248616Smm } 419248616Smm if (x != NULL && pd + strlen(s) > MAXLINELEN - 3 - INDENTNAMELEN) { 420228753Smm /* Last keyword is longer. */ 421228753Smm archive_strncat(&mtree->buf, s, x - s); 422228753Smm archive_strncat(&mtree->buf, " \\\n", 3); 423248616Smm for (i = 0; i < (INDENTNAMELEN + 1 + pd); i++) 424228753Smm archive_strappend_char(&mtree->buf, ' '); 425228753Smm s = ++x; 426228753Smm } 427228753Smm archive_strcat(&mtree->buf, s); 428228753Smm archive_string_empty(&mtree->ebuf); 429228753Smm} 430228753Smm 431228753Smm/* 432232153Smm * Write /set keyword. 433353377Smm * Set the most used value of uid, gid, mode and fflags, which are 434353377Smm * collected by the attr_counter_set_collect() function. 435228753Smm */ 436228753Smmstatic void 437232153Smmwrite_global(struct mtree_writer *mtree) 438228753Smm{ 439228753Smm struct archive_string setstr; 440228753Smm struct archive_string unsetstr; 441248616Smm struct att_counter_set *acs; 442228753Smm int keys, oldkeys, effkeys; 443228753Smm 444228753Smm archive_string_init(&setstr); 445228753Smm archive_string_init(&unsetstr); 446232153Smm keys = mtree->keys & SET_KEYS; 447228753Smm oldkeys = mtree->set.keys; 448228753Smm effkeys = keys; 449248616Smm acs = &mtree->acs; 450248616Smm if (mtree->set.processing) { 451228753Smm /* 452232153Smm * Check if the global data needs updating. 453228753Smm */ 454228753Smm effkeys &= ~F_TYPE; 455248616Smm if (acs->uid_list == NULL) 456248616Smm effkeys &= ~(F_UNAME | F_UID); 457248616Smm else if (oldkeys & (F_UNAME | F_UID)) { 458248616Smm if (acs->uid_list->count < 2 || 459248616Smm mtree->set.uid == acs->uid_list->m_entry->uid) 460248616Smm effkeys &= ~(F_UNAME | F_UID); 461232153Smm } 462248616Smm if (acs->gid_list == NULL) 463248616Smm effkeys &= ~(F_GNAME | F_GID); 464248616Smm else if (oldkeys & (F_GNAME | F_GID)) { 465248616Smm if (acs->gid_list->count < 2 || 466248616Smm mtree->set.gid == acs->gid_list->m_entry->gid) 467248616Smm effkeys &= ~(F_GNAME | F_GID); 468232153Smm } 469248616Smm if (acs->mode_list == NULL) 470248616Smm effkeys &= ~F_MODE; 471248616Smm else if (oldkeys & F_MODE) { 472248616Smm if (acs->mode_list->count < 2 || 473248616Smm mtree->set.mode == acs->mode_list->m_entry->mode) 474248616Smm effkeys &= ~F_MODE; 475232153Smm } 476248616Smm if (acs->flags_list == NULL) 477248616Smm effkeys &= ~F_FLAGS; 478248616Smm else if ((oldkeys & F_FLAGS) != 0) { 479248616Smm if (acs->flags_list->count < 2 || 480248616Smm (acs->flags_list->m_entry->fflags_set == 481248616Smm mtree->set.fflags_set && 482248616Smm acs->flags_list->m_entry->fflags_clear == 483248616Smm mtree->set.fflags_clear)) 484248616Smm effkeys &= ~F_FLAGS; 485228753Smm } 486248616Smm } else { 487248616Smm if (acs->uid_list == NULL) 488248616Smm keys &= ~(F_UNAME | F_UID); 489248616Smm if (acs->gid_list == NULL) 490248616Smm keys &= ~(F_GNAME | F_GID); 491248616Smm if (acs->mode_list == NULL) 492248616Smm keys &= ~F_MODE; 493248616Smm if (acs->flags_list == NULL) 494248616Smm keys &= ~F_FLAGS; 495228753Smm } 496228753Smm if ((keys & effkeys & F_TYPE) != 0) { 497232153Smm if (mtree->dironly) { 498228753Smm archive_strcat(&setstr, " type=dir"); 499232153Smm mtree->set.type = AE_IFDIR; 500232153Smm } else { 501228753Smm archive_strcat(&setstr, " type=file"); 502232153Smm mtree->set.type = AE_IFREG; 503232153Smm } 504228753Smm } 505228753Smm if ((keys & effkeys & F_UNAME) != 0) { 506248616Smm if (archive_strlen(&(acs->uid_list->m_entry->uname)) > 0) { 507228753Smm archive_strcat(&setstr, " uname="); 508248616Smm mtree_quote(&setstr, acs->uid_list->m_entry->uname.s); 509232153Smm } else { 510228753Smm keys &= ~F_UNAME; 511232153Smm if ((oldkeys & F_UNAME) != 0) 512232153Smm archive_strcat(&unsetstr, " uname"); 513232153Smm } 514228753Smm } 515228753Smm if ((keys & effkeys & F_UID) != 0) { 516248616Smm mtree->set.uid = acs->uid_list->m_entry->uid; 517228753Smm archive_string_sprintf(&setstr, " uid=%jd", 518228753Smm (intmax_t)mtree->set.uid); 519228753Smm } 520228753Smm if ((keys & effkeys & F_GNAME) != 0) { 521248616Smm if (archive_strlen(&(acs->gid_list->m_entry->gname)) > 0) { 522228753Smm archive_strcat(&setstr, " gname="); 523248616Smm mtree_quote(&setstr, acs->gid_list->m_entry->gname.s); 524232153Smm } else { 525228753Smm keys &= ~F_GNAME; 526232153Smm if ((oldkeys & F_GNAME) != 0) 527232153Smm archive_strcat(&unsetstr, " gname"); 528232153Smm } 529228753Smm } 530228753Smm if ((keys & effkeys & F_GID) != 0) { 531248616Smm mtree->set.gid = acs->gid_list->m_entry->gid; 532228753Smm archive_string_sprintf(&setstr, " gid=%jd", 533228753Smm (intmax_t)mtree->set.gid); 534228753Smm } 535228753Smm if ((keys & effkeys & F_MODE) != 0) { 536248616Smm mtree->set.mode = acs->mode_list->m_entry->mode; 537232153Smm archive_string_sprintf(&setstr, " mode=%o", 538232153Smm (unsigned int)mtree->set.mode); 539228753Smm } 540228753Smm if ((keys & effkeys & F_FLAGS) != 0) { 541248616Smm if (archive_strlen( 542248616Smm &(acs->flags_list->m_entry->fflags_text)) > 0) { 543228753Smm archive_strcat(&setstr, " flags="); 544248616Smm mtree_quote(&setstr, 545248616Smm acs->flags_list->m_entry->fflags_text.s); 546232153Smm mtree->set.fflags_set = 547248616Smm acs->flags_list->m_entry->fflags_set; 548232153Smm mtree->set.fflags_clear = 549248616Smm acs->flags_list->m_entry->fflags_clear; 550232153Smm } else { 551228753Smm keys &= ~F_FLAGS; 552232153Smm if ((oldkeys & F_FLAGS) != 0) 553232153Smm archive_strcat(&unsetstr, " flags"); 554232153Smm } 555228753Smm } 556228753Smm if (unsetstr.length > 0) 557228753Smm archive_string_sprintf(&mtree->buf, "/unset%s\n", unsetstr.s); 558228753Smm archive_string_free(&unsetstr); 559228753Smm if (setstr.length > 0) 560228753Smm archive_string_sprintf(&mtree->buf, "/set%s\n", setstr.s); 561228753Smm archive_string_free(&setstr); 562228753Smm mtree->set.keys = keys; 563248616Smm mtree->set.processing = 1; 564228753Smm} 565228753Smm 566232153Smmstatic struct attr_counter * 567248616Smmattr_counter_new(struct mtree_entry *me, struct attr_counter *prev) 568232153Smm{ 569232153Smm struct attr_counter *ac; 570232153Smm 571232153Smm ac = malloc(sizeof(*ac)); 572232153Smm if (ac != NULL) { 573232153Smm ac->prev = prev; 574232153Smm ac->next = NULL; 575232153Smm ac->count = 1; 576232153Smm ac->m_entry = me; 577232153Smm } 578232153Smm return (ac); 579232153Smm} 580232153Smm 581232153Smmstatic void 582248616Smmattr_counter_free(struct attr_counter **top) 583232153Smm{ 584232153Smm struct attr_counter *ac, *tac; 585232153Smm 586232153Smm if (*top == NULL) 587232153Smm return; 588232153Smm ac = *top; 589232153Smm while (ac != NULL) { 590232153Smm tac = ac->next; 591232153Smm free(ac); 592232153Smm ac = tac; 593232153Smm } 594232153Smm *top = NULL; 595232153Smm} 596232153Smm 597228753Smmstatic int 598248616Smmattr_counter_inc(struct attr_counter **top, struct attr_counter *ac, 599232153Smm struct attr_counter *last, struct mtree_entry *me) 600228753Smm{ 601232153Smm struct attr_counter *pac; 602232153Smm 603232153Smm if (ac != NULL) { 604232153Smm ac->count++; 605232153Smm if (*top == ac || ac->prev->count >= ac->count) 606232153Smm return (0); 607232153Smm for (pac = ac->prev; pac; pac = pac->prev) { 608232153Smm if (pac->count >= ac->count) 609232153Smm break; 610232153Smm } 611232153Smm ac->prev->next = ac->next; 612232153Smm if (ac->next != NULL) 613232153Smm ac->next->prev = ac->prev; 614232153Smm if (pac != NULL) { 615232153Smm ac->prev = pac; 616232153Smm ac->next = pac->next; 617232153Smm pac->next = ac; 618232153Smm if (ac->next != NULL) 619232153Smm ac->next->prev = ac; 620232153Smm } else { 621232153Smm ac->prev = NULL; 622232153Smm ac->next = *top; 623232153Smm *top = ac; 624232153Smm ac->next->prev = ac; 625232153Smm } 626302001Smm } else if (last != NULL) { 627248616Smm ac = attr_counter_new(me, last); 628232153Smm if (ac == NULL) 629232153Smm return (-1); 630232153Smm last->next = ac; 631232153Smm } 632232153Smm return (0); 633232153Smm} 634232153Smm 635248616Smm/* 636353377Smm * Tabulate uid, gid, mode and fflags of a entry in order to be used for /set. 637248616Smm */ 638232153Smmstatic int 639248616Smmattr_counter_set_collect(struct mtree_writer *mtree, struct mtree_entry *me) 640232153Smm{ 641248616Smm struct attr_counter *ac, *last; 642248616Smm struct att_counter_set *acs = &mtree->acs; 643232153Smm int keys = mtree->keys; 644232153Smm 645232153Smm if (keys & (F_UNAME | F_UID)) { 646248616Smm if (acs->uid_list == NULL) { 647248616Smm acs->uid_list = attr_counter_new(me, NULL); 648248616Smm if (acs->uid_list == NULL) 649232153Smm return (-1); 650232153Smm } else { 651232153Smm last = NULL; 652248616Smm for (ac = acs->uid_list; ac; ac = ac->next) { 653232153Smm if (ac->m_entry->uid == me->uid) 654232153Smm break; 655232153Smm last = ac; 656232153Smm } 657248616Smm if (attr_counter_inc(&acs->uid_list, ac, last, me) < 0) 658232153Smm return (-1); 659232153Smm } 660232153Smm } 661232153Smm if (keys & (F_GNAME | F_GID)) { 662248616Smm if (acs->gid_list == NULL) { 663248616Smm acs->gid_list = attr_counter_new(me, NULL); 664248616Smm if (acs->gid_list == NULL) 665232153Smm return (-1); 666232153Smm } else { 667232153Smm last = NULL; 668248616Smm for (ac = acs->gid_list; ac; ac = ac->next) { 669232153Smm if (ac->m_entry->gid == me->gid) 670232153Smm break; 671232153Smm last = ac; 672232153Smm } 673248616Smm if (attr_counter_inc(&acs->gid_list, ac, last, me) < 0) 674232153Smm return (-1); 675232153Smm } 676232153Smm } 677232153Smm if (keys & F_MODE) { 678248616Smm if (acs->mode_list == NULL) { 679248616Smm acs->mode_list = attr_counter_new(me, NULL); 680248616Smm if (acs->mode_list == NULL) 681232153Smm return (-1); 682232153Smm } else { 683232153Smm last = NULL; 684248616Smm for (ac = acs->mode_list; ac; ac = ac->next) { 685232153Smm if (ac->m_entry->mode == me->mode) 686232153Smm break; 687232153Smm last = ac; 688232153Smm } 689248616Smm if (attr_counter_inc(&acs->mode_list, ac, last, me) < 0) 690232153Smm return (-1); 691232153Smm } 692232153Smm } 693232153Smm if (keys & F_FLAGS) { 694248616Smm if (acs->flags_list == NULL) { 695248616Smm acs->flags_list = attr_counter_new(me, NULL); 696248616Smm if (acs->flags_list == NULL) 697232153Smm return (-1); 698232153Smm } else { 699232153Smm last = NULL; 700248616Smm for (ac = acs->flags_list; ac; ac = ac->next) { 701232153Smm if (ac->m_entry->fflags_set == me->fflags_set && 702248616Smm ac->m_entry->fflags_clear == 703248616Smm me->fflags_clear) 704232153Smm break; 705232153Smm last = ac; 706232153Smm } 707248616Smm if (attr_counter_inc(&acs->flags_list, ac, last, me) < 0) 708232153Smm return (-1); 709232153Smm } 710232153Smm } 711232153Smm 712232153Smm return (0); 713232153Smm} 714232153Smm 715248616Smmstatic void 716248616Smmattr_counter_set_free(struct mtree_writer *mtree) 717248616Smm{ 718248616Smm struct att_counter_set *acs = &mtree->acs; 719248616Smm 720248616Smm attr_counter_free(&acs->uid_list); 721248616Smm attr_counter_free(&acs->gid_list); 722248616Smm attr_counter_free(&acs->mode_list); 723248616Smm attr_counter_free(&acs->flags_list); 724248616Smm} 725248616Smm 726232153Smmstatic int 727248616Smmget_global_set_keys(struct mtree_writer *mtree, struct mtree_entry *me) 728232153Smm{ 729228753Smm int keys; 730228753Smm 731228753Smm keys = mtree->keys; 732232153Smm 733232153Smm /* 734232153Smm * If a keyword has been set by /set, we do not need to 735232153Smm * output it. 736232153Smm */ 737228753Smm if (mtree->set.keys == 0) 738232153Smm return (keys);/* /set is not used. */ 739232153Smm 740228753Smm if ((mtree->set.keys & (F_GNAME | F_GID)) != 0 && 741232153Smm mtree->set.gid == me->gid) 742228753Smm keys &= ~(F_GNAME | F_GID); 743228753Smm if ((mtree->set.keys & (F_UNAME | F_UID)) != 0 && 744232153Smm mtree->set.uid == me->uid) 745228753Smm keys &= ~(F_UNAME | F_UID); 746228753Smm if (mtree->set.keys & F_FLAGS) { 747232153Smm if (mtree->set.fflags_set == me->fflags_set && 748232153Smm mtree->set.fflags_clear == me->fflags_clear) 749228753Smm keys &= ~F_FLAGS; 750228753Smm } 751232153Smm if ((mtree->set.keys & F_MODE) != 0 && mtree->set.mode == me->mode) 752228753Smm keys &= ~F_MODE; 753228753Smm 754232153Smm switch (me->filetype) { 755228753Smm case AE_IFLNK: case AE_IFSOCK: case AE_IFCHR: 756228753Smm case AE_IFBLK: case AE_IFIFO: 757228753Smm break; 758228753Smm case AE_IFDIR: 759228753Smm if ((mtree->set.keys & F_TYPE) != 0 && 760228753Smm mtree->set.type == AE_IFDIR) 761228753Smm keys &= ~F_TYPE; 762228753Smm break; 763228753Smm case AE_IFREG: 764228753Smm default: /* Handle unknown file types as regular files. */ 765228753Smm if ((mtree->set.keys & F_TYPE) != 0 && 766228753Smm mtree->set.type == AE_IFREG) 767228753Smm keys &= ~F_TYPE; 768228753Smm break; 769228753Smm } 770228753Smm 771228753Smm return (keys); 772228753Smm} 773228753Smm 774248616Smmstatic int 775248616Smmmtree_entry_new(struct archive_write *a, struct archive_entry *entry, 776248616Smm struct mtree_entry **m_entry) 777232153Smm{ 778232153Smm struct mtree_entry *me; 779232153Smm const char *s; 780248616Smm int r; 781248616Smm static const struct archive_rb_tree_ops rb_ops = { 782248616Smm mtree_entry_cmp_node, mtree_entry_cmp_key 783248616Smm }; 784232153Smm 785232153Smm me = calloc(1, sizeof(*me)); 786248616Smm if (me == NULL) { 787248616Smm archive_set_error(&a->archive, ENOMEM, 788248616Smm "Can't allocate memory for a mtree entry"); 789248616Smm *m_entry = NULL; 790248616Smm return (ARCHIVE_FATAL); 791248616Smm } 792248616Smm 793248616Smm r = mtree_entry_setup_filenames(a, me, entry); 794248616Smm if (r < ARCHIVE_WARN) { 795248616Smm mtree_entry_free(me); 796248616Smm *m_entry = NULL; 797248616Smm return (r); 798248616Smm } 799248616Smm 800232153Smm if ((s = archive_entry_symlink(entry)) != NULL) 801248616Smm archive_strcpy(&me->symlink, s); 802232153Smm me->nlink = archive_entry_nlink(entry); 803232153Smm me->filetype = archive_entry_filetype(entry); 804232153Smm me->mode = archive_entry_mode(entry) & 07777; 805232153Smm me->uid = archive_entry_uid(entry); 806232153Smm me->gid = archive_entry_gid(entry); 807232153Smm if ((s = archive_entry_uname(entry)) != NULL) 808248616Smm archive_strcpy(&me->uname, s); 809232153Smm if ((s = archive_entry_gname(entry)) != NULL) 810248616Smm archive_strcpy(&me->gname, s); 811232153Smm if ((s = archive_entry_fflags_text(entry)) != NULL) 812248616Smm archive_strcpy(&me->fflags_text, s); 813232153Smm archive_entry_fflags(entry, &me->fflags_set, &me->fflags_clear); 814232153Smm me->mtime = archive_entry_mtime(entry); 815232153Smm me->mtime_nsec = archive_entry_mtime_nsec(entry); 816302001Smm me->rdevmajor = archive_entry_rdevmajor(entry); 817232153Smm me->rdevminor = archive_entry_rdevminor(entry); 818302001Smm me->devmajor = archive_entry_devmajor(entry); 819302001Smm me->devminor = archive_entry_devminor(entry); 820302001Smm me->ino = archive_entry_ino(entry); 821232153Smm me->size = archive_entry_size(entry); 822248616Smm if (me->filetype == AE_IFDIR) { 823248616Smm me->dir_info = calloc(1, sizeof(*me->dir_info)); 824248616Smm if (me->dir_info == NULL) { 825248616Smm mtree_entry_free(me); 826248616Smm archive_set_error(&a->archive, ENOMEM, 827248616Smm "Can't allocate memory for a mtree entry"); 828248616Smm *m_entry = NULL; 829248616Smm return (ARCHIVE_FATAL); 830248616Smm } 831248616Smm __archive_rb_tree_init(&me->dir_info->rbtree, &rb_ops); 832248616Smm me->dir_info->children.first = NULL; 833248616Smm me->dir_info->children.last = &(me->dir_info->children.first); 834248616Smm me->dir_info->chnext = NULL; 835248616Smm } else if (me->filetype == AE_IFREG) { 836248616Smm me->reg_info = calloc(1, sizeof(*me->reg_info)); 837248616Smm if (me->reg_info == NULL) { 838248616Smm mtree_entry_free(me); 839248616Smm archive_set_error(&a->archive, ENOMEM, 840248616Smm "Can't allocate memory for a mtree entry"); 841248616Smm *m_entry = NULL; 842248616Smm return (ARCHIVE_FATAL); 843248616Smm } 844248616Smm me->reg_info->compute_sum = 0; 845248616Smm } 846232153Smm 847248616Smm *m_entry = me; 848248616Smm return (ARCHIVE_OK); 849232153Smm} 850232153Smm 851232153Smmstatic void 852248616Smmmtree_entry_free(struct mtree_entry *me) 853232153Smm{ 854248616Smm archive_string_free(&me->parentdir); 855248616Smm archive_string_free(&me->basename); 856248616Smm archive_string_free(&me->pathname); 857248616Smm archive_string_free(&me->symlink); 858248616Smm archive_string_free(&me->uname); 859248616Smm archive_string_free(&me->gname); 860248616Smm archive_string_free(&me->fflags_text); 861248616Smm free(me->dir_info); 862248616Smm free(me->reg_info); 863232153Smm free(me); 864232153Smm} 865232153Smm 866228753Smmstatic int 867228753Smmarchive_write_mtree_header(struct archive_write *a, 868228753Smm struct archive_entry *entry) 869228753Smm{ 870228753Smm struct mtree_writer *mtree= a->format_data; 871248616Smm struct mtree_entry *mtree_entry; 872248616Smm int r, r2; 873228753Smm 874228753Smm if (mtree->first) { 875228753Smm mtree->first = 0; 876228753Smm archive_strcat(&mtree->buf, "#mtree\n"); 877232153Smm if ((mtree->keys & SET_KEYS) == 0) 878302001Smm mtree->output_global_set = 0;/* Disabled. */ 879228753Smm } 880228753Smm 881228753Smm mtree->entry_bytes_remaining = archive_entry_size(entry); 882248616Smm 883248616Smm /* While directory only mode, we do not handle non directory files. */ 884232153Smm if (mtree->dironly && archive_entry_filetype(entry) != AE_IFDIR) 885232153Smm return (ARCHIVE_OK); 886228753Smm 887248616Smm r2 = mtree_entry_new(a, entry, &mtree_entry); 888248616Smm if (r2 < ARCHIVE_WARN) 889248616Smm return (r2); 890248616Smm r = mtree_entry_tree_add(a, &mtree_entry); 891248616Smm if (r < ARCHIVE_WARN) { 892248616Smm mtree_entry_free(mtree_entry); 893248616Smm return (r); 894232153Smm } 895248616Smm mtree->mtree_entry = mtree_entry; 896228753Smm 897248616Smm /* If the current file is a regular file, we have to 898248616Smm * compute the sum of its content. 899353377Smm * Initialize a bunch of checksum context. */ 900248616Smm if (mtree_entry->reg_info) 901248616Smm sum_init(mtree); 902228753Smm 903248616Smm return (r2); 904228753Smm} 905228753Smm 906228753Smmstatic int 907248616Smmwrite_mtree_entry(struct archive_write *a, struct mtree_entry *me) 908228753Smm{ 909228753Smm struct mtree_writer *mtree = a->format_data; 910228753Smm struct archive_string *str; 911228753Smm int keys, ret; 912228753Smm 913248616Smm if (me->dir_info) { 914248616Smm if (mtree->classic) { 915248616Smm /* 916248616Smm * Output a comment line to describe the full 917248616Smm * pathname of the entry as mtree utility does 918248616Smm * while generating classic format. 919248616Smm */ 920248616Smm if (!mtree->dironly) 921248616Smm archive_strappend_char(&mtree->buf, '\n'); 922248616Smm if (me->parentdir.s) 923248616Smm archive_string_sprintf(&mtree->buf, 924248616Smm "# %s/%s\n", 925248616Smm me->parentdir.s, me->basename.s); 926248616Smm else 927248616Smm archive_string_sprintf(&mtree->buf, 928248616Smm "# %s\n", 929248616Smm me->basename.s); 930248616Smm } 931248616Smm if (mtree->output_global_set) 932248616Smm write_global(mtree); 933248616Smm } 934232153Smm archive_string_empty(&mtree->ebuf); 935248616Smm str = (mtree->indent || mtree->classic)? &mtree->ebuf : &mtree->buf; 936248616Smm 937248616Smm if (!mtree->classic && me->parentdir.s) { 938248616Smm /* 939248616Smm * If generating format is not classic one(v1), output 940248616Smm * a full pathname. 941248616Smm */ 942248616Smm mtree_quote(str, me->parentdir.s); 943248616Smm archive_strappend_char(str, '/'); 944248616Smm } 945248616Smm mtree_quote(str, me->basename.s); 946248616Smm 947248616Smm keys = get_global_set_keys(mtree, me); 948228753Smm if ((keys & F_NLINK) != 0 && 949232153Smm me->nlink != 1 && me->filetype != AE_IFDIR) 950232153Smm archive_string_sprintf(str, " nlink=%u", me->nlink); 951228753Smm 952248616Smm if ((keys & F_GNAME) != 0 && archive_strlen(&me->gname) > 0) { 953228753Smm archive_strcat(str, " gname="); 954248616Smm mtree_quote(str, me->gname.s); 955228753Smm } 956248616Smm if ((keys & F_UNAME) != 0 && archive_strlen(&me->uname) > 0) { 957228753Smm archive_strcat(str, " uname="); 958248616Smm mtree_quote(str, me->uname.s); 959228753Smm } 960232153Smm if ((keys & F_FLAGS) != 0) { 961248616Smm if (archive_strlen(&me->fflags_text) > 0) { 962232153Smm archive_strcat(str, " flags="); 963248616Smm mtree_quote(str, me->fflags_text.s); 964248616Smm } else if (mtree->set.processing && 965232153Smm (mtree->set.keys & F_FLAGS) != 0) 966232153Smm /* Overwrite the global parameter. */ 967232153Smm archive_strcat(str, " flags=none"); 968228753Smm } 969228753Smm if ((keys & F_TIME) != 0) 970228753Smm archive_string_sprintf(str, " time=%jd.%jd", 971232153Smm (intmax_t)me->mtime, (intmax_t)me->mtime_nsec); 972228753Smm if ((keys & F_MODE) != 0) 973232153Smm archive_string_sprintf(str, " mode=%o", (unsigned int)me->mode); 974228753Smm if ((keys & F_GID) != 0) 975232153Smm archive_string_sprintf(str, " gid=%jd", (intmax_t)me->gid); 976228753Smm if ((keys & F_UID) != 0) 977232153Smm archive_string_sprintf(str, " uid=%jd", (intmax_t)me->uid); 978228753Smm 979302001Smm if ((keys & F_INO) != 0) 980302001Smm archive_string_sprintf(str, " inode=%jd", (intmax_t)me->ino); 981302001Smm if ((keys & F_RESDEV) != 0) { 982302001Smm archive_string_sprintf(str, 983302001Smm " resdevice=native,%ju,%ju", 984302001Smm (uintmax_t)me->devmajor, 985302001Smm (uintmax_t)me->devminor); 986302001Smm } 987302001Smm 988232153Smm switch (me->filetype) { 989228753Smm case AE_IFLNK: 990228753Smm if ((keys & F_TYPE) != 0) 991228753Smm archive_strcat(str, " type=link"); 992228753Smm if ((keys & F_SLINK) != 0) { 993228753Smm archive_strcat(str, " link="); 994248616Smm mtree_quote(str, me->symlink.s); 995228753Smm } 996228753Smm break; 997228753Smm case AE_IFSOCK: 998228753Smm if ((keys & F_TYPE) != 0) 999228753Smm archive_strcat(str, " type=socket"); 1000228753Smm break; 1001228753Smm case AE_IFCHR: 1002228753Smm if ((keys & F_TYPE) != 0) 1003228753Smm archive_strcat(str, " type=char"); 1004228753Smm if ((keys & F_DEV) != 0) { 1005228753Smm archive_string_sprintf(str, 1006232153Smm " device=native,%ju,%ju", 1007232153Smm (uintmax_t)me->rdevmajor, 1008232153Smm (uintmax_t)me->rdevminor); 1009228753Smm } 1010228753Smm break; 1011228753Smm case AE_IFBLK: 1012228753Smm if ((keys & F_TYPE) != 0) 1013228753Smm archive_strcat(str, " type=block"); 1014228753Smm if ((keys & F_DEV) != 0) { 1015228753Smm archive_string_sprintf(str, 1016232153Smm " device=native,%ju,%ju", 1017232153Smm (uintmax_t)me->rdevmajor, 1018232153Smm (uintmax_t)me->rdevminor); 1019228753Smm } 1020228753Smm break; 1021228753Smm case AE_IFDIR: 1022228753Smm if ((keys & F_TYPE) != 0) 1023228753Smm archive_strcat(str, " type=dir"); 1024228753Smm break; 1025228753Smm case AE_IFIFO: 1026228753Smm if ((keys & F_TYPE) != 0) 1027228753Smm archive_strcat(str, " type=fifo"); 1028228753Smm break; 1029228753Smm case AE_IFREG: 1030228753Smm default: /* Handle unknown file types as regular files. */ 1031228753Smm if ((keys & F_TYPE) != 0) 1032228753Smm archive_strcat(str, " type=file"); 1033228753Smm if ((keys & F_SIZE) != 0) 1034228753Smm archive_string_sprintf(str, " size=%jd", 1035232153Smm (intmax_t)me->size); 1036228753Smm break; 1037228753Smm } 1038228753Smm 1039232153Smm /* Write a bunch of sum. */ 1040248616Smm if (me->reg_info) 1041248616Smm sum_write(str, me->reg_info); 1042228753Smm 1043248616Smm archive_strappend_char(str, '\n'); 1044248616Smm if (mtree->indent || mtree->classic) 1045232153Smm mtree_indent(mtree); 1046228753Smm 1047232153Smm if (mtree->buf.length > 32768) { 1048248616Smm ret = __archive_write_output( 1049248616Smm a, mtree->buf.s, mtree->buf.length); 1050232153Smm archive_string_empty(&mtree->buf); 1051232153Smm } else 1052232153Smm ret = ARCHIVE_OK; 1053232153Smm return (ret); 1054232153Smm} 1055228753Smm 1056248616Smmstatic int 1057248616Smmwrite_dot_dot_entry(struct archive_write *a, struct mtree_entry *n) 1058248616Smm{ 1059248616Smm struct mtree_writer *mtree = a->format_data; 1060248616Smm int ret; 1061248616Smm 1062248616Smm if (n->parentdir.s) { 1063248616Smm if (mtree->indent) { 1064248616Smm int i, pd = mtree->depth * 4; 1065248616Smm for (i = 0; i < pd; i++) 1066248616Smm archive_strappend_char(&mtree->buf, ' '); 1067248616Smm } 1068248616Smm archive_string_sprintf(&mtree->buf, "# %s/%s\n", 1069248616Smm n->parentdir.s, n->basename.s); 1070248616Smm } 1071248616Smm 1072248616Smm if (mtree->indent) { 1073248616Smm archive_string_empty(&mtree->ebuf); 1074248616Smm archive_strncat(&mtree->ebuf, "..\n\n", (mtree->dironly)?3:4); 1075248616Smm mtree_indent(mtree); 1076248616Smm } else 1077248616Smm archive_strncat(&mtree->buf, "..\n\n", (mtree->dironly)?3:4); 1078248616Smm 1079248616Smm if (mtree->buf.length > 32768) { 1080248616Smm ret = __archive_write_output( 1081248616Smm a, mtree->buf.s, mtree->buf.length); 1082248616Smm archive_string_empty(&mtree->buf); 1083248616Smm } else 1084248616Smm ret = ARCHIVE_OK; 1085248616Smm return (ret); 1086248616Smm} 1087248616Smm 1088232153Smm/* 1089248616Smm * Write mtree entries saved at attr_counter_set_collect() function. 1090232153Smm */ 1091232153Smmstatic int 1092248616Smmwrite_mtree_entry_tree(struct archive_write *a) 1093232153Smm{ 1094232153Smm struct mtree_writer *mtree = a->format_data; 1095248616Smm struct mtree_entry *np = mtree->root; 1096248616Smm struct archive_rb_node *n; 1097232153Smm int ret; 1098228753Smm 1099248616Smm do { 1100248616Smm if (mtree->output_global_set) { 1101248616Smm /* 1102302001Smm * Collect attribute information to know which value 1103248616Smm * is frequently used among the children. 1104248616Smm */ 1105248616Smm attr_counter_set_reset(mtree); 1106248616Smm ARCHIVE_RB_TREE_FOREACH(n, &(np->dir_info->rbtree)) { 1107248616Smm struct mtree_entry *e = (struct mtree_entry *)n; 1108248616Smm if (attr_counter_set_collect(mtree, e) < 0) { 1109248616Smm archive_set_error(&a->archive, ENOMEM, 1110248616Smm "Can't allocate memory"); 1111248616Smm return (ARCHIVE_FATAL); 1112248616Smm } 1113248616Smm } 1114248616Smm } 1115248616Smm if (!np->dir_info->virtual || mtree->classic) { 1116248616Smm ret = write_mtree_entry(a, np); 1117248616Smm if (ret != ARCHIVE_OK) 1118248616Smm return (ARCHIVE_FATAL); 1119248616Smm } else { 1120248616Smm /* Whenever output_global_set is enabled 1121248616Smm * output global value(/set keywords) 1122302001Smm * even if the directory entry is not allowed 1123248616Smm * to be written because the global values 1124248616Smm * can be used for the children. */ 1125248616Smm if (mtree->output_global_set) 1126248616Smm write_global(mtree); 1127248616Smm } 1128248616Smm /* 1129248616Smm * Output the attribute of all files except directory files. 1130248616Smm */ 1131248616Smm mtree->depth++; 1132248616Smm ARCHIVE_RB_TREE_FOREACH(n, &(np->dir_info->rbtree)) { 1133248616Smm struct mtree_entry *e = (struct mtree_entry *)n; 1134228753Smm 1135248616Smm if (e->dir_info) 1136248616Smm mtree_entry_add_child_tail(np, e); 1137248616Smm else { 1138248616Smm ret = write_mtree_entry(a, e); 1139248616Smm if (ret != ARCHIVE_OK) 1140248616Smm return (ARCHIVE_FATAL); 1141248616Smm } 1142248616Smm } 1143248616Smm mtree->depth--; 1144248616Smm 1145248616Smm if (np->dir_info->children.first != NULL) { 1146248616Smm /* 1147248616Smm * Descend the tree. 1148248616Smm */ 1149248616Smm np = np->dir_info->children.first; 1150248616Smm if (mtree->indent) 1151248616Smm mtree->depth++; 1152248616Smm continue; 1153248616Smm } else if (mtree->classic) { 1154248616Smm /* 1155248616Smm * While printing mtree classic, if there are not 1156248616Smm * any directory files(except "." and "..") in the 1157248616Smm * directory, output two dots ".." as returning 1158248616Smm * the parent directory. 1159248616Smm */ 1160248616Smm ret = write_dot_dot_entry(a, np); 1161248616Smm if (ret != ARCHIVE_OK) 1162248616Smm return (ARCHIVE_FATAL); 1163248616Smm } 1164248616Smm 1165248616Smm while (np != np->parent) { 1166248616Smm if (np->dir_info->chnext == NULL) { 1167248616Smm /* 1168248616Smm * Ascend the tree; go back to the parent. 1169248616Smm */ 1170248616Smm if (mtree->indent) 1171248616Smm mtree->depth--; 1172248616Smm if (mtree->classic) { 1173248616Smm ret = write_dot_dot_entry(a, 1174248616Smm np->parent); 1175248616Smm if (ret != ARCHIVE_OK) 1176248616Smm return (ARCHIVE_FATAL); 1177248616Smm } 1178248616Smm np = np->parent; 1179248616Smm } else { 1180248616Smm /* 1181248616Smm * Switch to next mtree entry in the directory. 1182248616Smm */ 1183248616Smm np = np->dir_info->chnext; 1184248616Smm break; 1185248616Smm } 1186248616Smm } 1187248616Smm } while (np != np->parent); 1188248616Smm 1189232153Smm return (ARCHIVE_OK); 1190232153Smm} 1191228753Smm 1192232153Smmstatic int 1193232153Smmarchive_write_mtree_finish_entry(struct archive_write *a) 1194232153Smm{ 1195232153Smm struct mtree_writer *mtree = a->format_data; 1196232153Smm struct mtree_entry *me; 1197228753Smm 1198232153Smm if ((me = mtree->mtree_entry) == NULL) 1199232153Smm return (ARCHIVE_OK); 1200232153Smm mtree->mtree_entry = NULL; 1201228753Smm 1202248616Smm if (me->reg_info) 1203248616Smm sum_final(mtree, me->reg_info); 1204228753Smm 1205248616Smm return (ARCHIVE_OK); 1206228753Smm} 1207228753Smm 1208228753Smmstatic int 1209232153Smmarchive_write_mtree_close(struct archive_write *a) 1210228753Smm{ 1211228753Smm struct mtree_writer *mtree= a->format_data; 1212232153Smm int ret; 1213228753Smm 1214248616Smm if (mtree->root != NULL) { 1215248616Smm ret = write_mtree_entry_tree(a); 1216232153Smm if (ret != ARCHIVE_OK) 1217232153Smm return (ARCHIVE_FATAL); 1218232153Smm } 1219232153Smm 1220228753Smm archive_write_set_bytes_in_last_block(&a->archive, 1); 1221228753Smm 1222232153Smm return __archive_write_output(a, mtree->buf.s, mtree->buf.length); 1223228753Smm} 1224228753Smm 1225228753Smmstatic ssize_t 1226228753Smmarchive_write_mtree_data(struct archive_write *a, const void *buff, size_t n) 1227228753Smm{ 1228228753Smm struct mtree_writer *mtree= a->format_data; 1229228753Smm 1230228753Smm if (n > mtree->entry_bytes_remaining) 1231238856Smm n = (size_t)mtree->entry_bytes_remaining; 1232232153Smm mtree->entry_bytes_remaining -= n; 1233232153Smm 1234232153Smm /* We don't need to compute a regular file sum */ 1235232153Smm if (mtree->mtree_entry == NULL) 1236228753Smm return (n); 1237228753Smm 1238232153Smm if (mtree->mtree_entry->filetype == AE_IFREG) 1239232153Smm sum_update(mtree, buff, n); 1240232153Smm 1241228753Smm return (n); 1242228753Smm} 1243228753Smm 1244228753Smmstatic int 1245232153Smmarchive_write_mtree_free(struct archive_write *a) 1246228753Smm{ 1247228753Smm struct mtree_writer *mtree= a->format_data; 1248228753Smm 1249228753Smm if (mtree == NULL) 1250228753Smm return (ARCHIVE_OK); 1251228753Smm 1252353377Smm /* Make sure we do not leave any entries. */ 1253248616Smm mtree_entry_register_free(mtree); 1254248616Smm archive_string_free(&mtree->cur_dirstr); 1255228753Smm archive_string_free(&mtree->ebuf); 1256228753Smm archive_string_free(&mtree->buf); 1257248616Smm attr_counter_set_free(mtree); 1258228753Smm free(mtree); 1259228753Smm a->format_data = NULL; 1260228753Smm return (ARCHIVE_OK); 1261228753Smm} 1262228753Smm 1263228753Smmstatic int 1264228753Smmarchive_write_mtree_options(struct archive_write *a, const char *key, 1265228753Smm const char *value) 1266228753Smm{ 1267228753Smm struct mtree_writer *mtree= a->format_data; 1268228753Smm int keybit = 0; 1269228753Smm 1270228753Smm switch (key[0]) { 1271228753Smm case 'a': 1272228753Smm if (strcmp(key, "all") == 0) 1273228753Smm keybit = ~0; 1274228753Smm break; 1275228753Smm case 'c': 1276228753Smm if (strcmp(key, "cksum") == 0) 1277228753Smm keybit = F_CKSUM; 1278228753Smm break; 1279228753Smm case 'd': 1280228753Smm if (strcmp(key, "device") == 0) 1281228753Smm keybit = F_DEV; 1282228753Smm else if (strcmp(key, "dironly") == 0) { 1283228753Smm mtree->dironly = (value != NULL)? 1: 0; 1284228753Smm return (ARCHIVE_OK); 1285228753Smm } 1286228753Smm break; 1287228753Smm case 'f': 1288228753Smm if (strcmp(key, "flags") == 0) 1289228753Smm keybit = F_FLAGS; 1290228753Smm break; 1291228753Smm case 'g': 1292228753Smm if (strcmp(key, "gid") == 0) 1293228753Smm keybit = F_GID; 1294228753Smm else if (strcmp(key, "gname") == 0) 1295228753Smm keybit = F_GNAME; 1296228753Smm break; 1297228753Smm case 'i': 1298228753Smm if (strcmp(key, "indent") == 0) { 1299228753Smm mtree->indent = (value != NULL)? 1: 0; 1300228753Smm return (ARCHIVE_OK); 1301302001Smm } else if (strcmp(key, "inode") == 0) { 1302302001Smm keybit = F_INO; 1303228753Smm } 1304228753Smm break; 1305228753Smm case 'l': 1306228753Smm if (strcmp(key, "link") == 0) 1307228753Smm keybit = F_SLINK; 1308228753Smm break; 1309228753Smm case 'm': 1310228753Smm if (strcmp(key, "md5") == 0 || 1311228753Smm strcmp(key, "md5digest") == 0) 1312228753Smm keybit = F_MD5; 1313228753Smm if (strcmp(key, "mode") == 0) 1314228753Smm keybit = F_MODE; 1315228753Smm break; 1316228753Smm case 'n': 1317228753Smm if (strcmp(key, "nlink") == 0) 1318228753Smm keybit = F_NLINK; 1319228753Smm break; 1320228753Smm case 'r': 1321302001Smm if (strcmp(key, "resdevice") == 0) { 1322302001Smm keybit = F_RESDEV; 1323302001Smm } else if (strcmp(key, "ripemd160digest") == 0 || 1324228753Smm strcmp(key, "rmd160") == 0 || 1325228753Smm strcmp(key, "rmd160digest") == 0) 1326228753Smm keybit = F_RMD160; 1327228753Smm break; 1328228753Smm case 's': 1329228753Smm if (strcmp(key, "sha1") == 0 || 1330228753Smm strcmp(key, "sha1digest") == 0) 1331228753Smm keybit = F_SHA1; 1332228753Smm if (strcmp(key, "sha256") == 0 || 1333228753Smm strcmp(key, "sha256digest") == 0) 1334228753Smm keybit = F_SHA256; 1335228753Smm if (strcmp(key, "sha384") == 0 || 1336228753Smm strcmp(key, "sha384digest") == 0) 1337228753Smm keybit = F_SHA384; 1338228753Smm if (strcmp(key, "sha512") == 0 || 1339228753Smm strcmp(key, "sha512digest") == 0) 1340228753Smm keybit = F_SHA512; 1341228753Smm if (strcmp(key, "size") == 0) 1342228753Smm keybit = F_SIZE; 1343228753Smm break; 1344228753Smm case 't': 1345228753Smm if (strcmp(key, "time") == 0) 1346228753Smm keybit = F_TIME; 1347228753Smm else if (strcmp(key, "type") == 0) 1348228753Smm keybit = F_TYPE; 1349228753Smm break; 1350228753Smm case 'u': 1351228753Smm if (strcmp(key, "uid") == 0) 1352228753Smm keybit = F_UID; 1353228753Smm else if (strcmp(key, "uname") == 0) 1354228753Smm keybit = F_UNAME; 1355228753Smm else if (strcmp(key, "use-set") == 0) { 1356248616Smm mtree->output_global_set = (value != NULL)? 1: 0; 1357228753Smm return (ARCHIVE_OK); 1358228753Smm } 1359228753Smm break; 1360228753Smm } 1361228753Smm if (keybit != 0) { 1362228753Smm if (value != NULL) 1363228753Smm mtree->keys |= keybit; 1364228753Smm else 1365228753Smm mtree->keys &= ~keybit; 1366228753Smm return (ARCHIVE_OK); 1367228753Smm } 1368228753Smm 1369232153Smm /* Note: The "warn" return is just to inform the options 1370232153Smm * supervisor that we didn't handle it. It will generate 1371232153Smm * a suitable error if no one used this option. */ 1372228753Smm return (ARCHIVE_WARN); 1373228753Smm} 1374228753Smm 1375248616Smmstatic int 1376248616Smmarchive_write_set_format_mtree_default(struct archive *_a, const char *fn) 1377228753Smm{ 1378228753Smm struct archive_write *a = (struct archive_write *)_a; 1379228753Smm struct mtree_writer *mtree; 1380228753Smm 1381248616Smm archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, fn); 1382228753Smm 1383232153Smm if (a->format_free != NULL) 1384232153Smm (a->format_free)(a); 1385232153Smm 1386232153Smm if ((mtree = calloc(1, sizeof(*mtree))) == NULL) { 1387228753Smm archive_set_error(&a->archive, ENOMEM, 1388228753Smm "Can't allocate mtree data"); 1389228753Smm return (ARCHIVE_FATAL); 1390228753Smm } 1391228753Smm 1392232153Smm mtree->mtree_entry = NULL; 1393228753Smm mtree->first = 1; 1394228753Smm memset(&(mtree->set), 0, sizeof(mtree->set)); 1395228753Smm mtree->keys = DEFAULT_KEYS; 1396228753Smm mtree->dironly = 0; 1397228753Smm mtree->indent = 0; 1398228753Smm archive_string_init(&mtree->ebuf); 1399228753Smm archive_string_init(&mtree->buf); 1400248616Smm mtree_entry_register_init(mtree); 1401228753Smm a->format_data = mtree; 1402232153Smm a->format_free = archive_write_mtree_free; 1403228753Smm a->format_name = "mtree"; 1404228753Smm a->format_options = archive_write_mtree_options; 1405228753Smm a->format_write_header = archive_write_mtree_header; 1406232153Smm a->format_close = archive_write_mtree_close; 1407228753Smm a->format_write_data = archive_write_mtree_data; 1408228753Smm a->format_finish_entry = archive_write_mtree_finish_entry; 1409228753Smm a->archive.archive_format = ARCHIVE_FORMAT_MTREE; 1410228753Smm a->archive.archive_format_name = "mtree"; 1411228753Smm 1412228753Smm return (ARCHIVE_OK); 1413228753Smm} 1414232153Smm 1415248616Smmint 1416248616Smmarchive_write_set_format_mtree(struct archive *_a) 1417248616Smm{ 1418248616Smm return archive_write_set_format_mtree_default(_a, 1419248616Smm "archive_write_set_format_mtree"); 1420248616Smm} 1421248616Smm 1422248616Smmint 1423248616Smmarchive_write_set_format_mtree_classic(struct archive *_a) 1424248616Smm{ 1425248616Smm int r; 1426248616Smm 1427248616Smm r = archive_write_set_format_mtree_default(_a, 1428248616Smm "archive_write_set_format_mtree_classic"); 1429248616Smm if (r == ARCHIVE_OK) { 1430248616Smm struct archive_write *a = (struct archive_write *)_a; 1431248616Smm struct mtree_writer *mtree; 1432248616Smm 1433248616Smm mtree = (struct mtree_writer *)a->format_data; 1434248616Smm 1435248616Smm /* Set to output a mtree archive in classic format. */ 1436248616Smm mtree->classic = 1; 1437248616Smm /* Basically, mtree classic format uses '/set' global 1438248616Smm * value. */ 1439248616Smm mtree->output_global_set = 1; 1440248616Smm } 1441248616Smm return (r); 1442248616Smm} 1443248616Smm 1444232153Smmstatic void 1445232153Smmsum_init(struct mtree_writer *mtree) 1446232153Smm{ 1447248616Smm 1448248616Smm mtree->compute_sum = 0; 1449248616Smm 1450232153Smm if (mtree->keys & F_CKSUM) { 1451232153Smm mtree->compute_sum |= F_CKSUM; 1452232153Smm mtree->crc = 0; 1453232153Smm mtree->crc_len = 0; 1454232153Smm } 1455232153Smm#ifdef ARCHIVE_HAS_MD5 1456232153Smm if (mtree->keys & F_MD5) { 1457232153Smm if (archive_md5_init(&mtree->md5ctx) == ARCHIVE_OK) 1458232153Smm mtree->compute_sum |= F_MD5; 1459232153Smm else 1460232153Smm mtree->keys &= ~F_MD5;/* Not supported. */ 1461232153Smm } 1462232153Smm#endif 1463232153Smm#ifdef ARCHIVE_HAS_RMD160 1464232153Smm if (mtree->keys & F_RMD160) { 1465232153Smm if (archive_rmd160_init(&mtree->rmd160ctx) == ARCHIVE_OK) 1466232153Smm mtree->compute_sum |= F_RMD160; 1467232153Smm else 1468232153Smm mtree->keys &= ~F_RMD160;/* Not supported. */ 1469232153Smm } 1470232153Smm#endif 1471232153Smm#ifdef ARCHIVE_HAS_SHA1 1472232153Smm if (mtree->keys & F_SHA1) { 1473232153Smm if (archive_sha1_init(&mtree->sha1ctx) == ARCHIVE_OK) 1474232153Smm mtree->compute_sum |= F_SHA1; 1475232153Smm else 1476232153Smm mtree->keys &= ~F_SHA1;/* Not supported. */ 1477232153Smm } 1478232153Smm#endif 1479232153Smm#ifdef ARCHIVE_HAS_SHA256 1480232153Smm if (mtree->keys & F_SHA256) { 1481232153Smm if (archive_sha256_init(&mtree->sha256ctx) == ARCHIVE_OK) 1482232153Smm mtree->compute_sum |= F_SHA256; 1483232153Smm else 1484232153Smm mtree->keys &= ~F_SHA256;/* Not supported. */ 1485232153Smm } 1486232153Smm#endif 1487232153Smm#ifdef ARCHIVE_HAS_SHA384 1488232153Smm if (mtree->keys & F_SHA384) { 1489232153Smm if (archive_sha384_init(&mtree->sha384ctx) == ARCHIVE_OK) 1490232153Smm mtree->compute_sum |= F_SHA384; 1491232153Smm else 1492232153Smm mtree->keys &= ~F_SHA384;/* Not supported. */ 1493232153Smm } 1494232153Smm#endif 1495232153Smm#ifdef ARCHIVE_HAS_SHA512 1496232153Smm if (mtree->keys & F_SHA512) { 1497232153Smm if (archive_sha512_init(&mtree->sha512ctx) == ARCHIVE_OK) 1498232153Smm mtree->compute_sum |= F_SHA512; 1499232153Smm else 1500232153Smm mtree->keys &= ~F_SHA512;/* Not supported. */ 1501232153Smm } 1502232153Smm#endif 1503232153Smm} 1504232153Smm 1505232153Smmstatic void 1506232153Smmsum_update(struct mtree_writer *mtree, const void *buff, size_t n) 1507232153Smm{ 1508232153Smm if (mtree->compute_sum & F_CKSUM) { 1509232153Smm /* 1510232153Smm * Compute a POSIX 1003.2 checksum 1511232153Smm */ 1512232153Smm const unsigned char *p; 1513232153Smm size_t nn; 1514232153Smm 1515232153Smm for (nn = n, p = buff; nn--; ++p) 1516232153Smm COMPUTE_CRC(mtree->crc, *p); 1517232153Smm mtree->crc_len += n; 1518232153Smm } 1519232153Smm#ifdef ARCHIVE_HAS_MD5 1520232153Smm if (mtree->compute_sum & F_MD5) 1521232153Smm archive_md5_update(&mtree->md5ctx, buff, n); 1522232153Smm#endif 1523232153Smm#ifdef ARCHIVE_HAS_RMD160 1524232153Smm if (mtree->compute_sum & F_RMD160) 1525232153Smm archive_rmd160_update(&mtree->rmd160ctx, buff, n); 1526232153Smm#endif 1527232153Smm#ifdef ARCHIVE_HAS_SHA1 1528232153Smm if (mtree->compute_sum & F_SHA1) 1529232153Smm archive_sha1_update(&mtree->sha1ctx, buff, n); 1530232153Smm#endif 1531232153Smm#ifdef ARCHIVE_HAS_SHA256 1532232153Smm if (mtree->compute_sum & F_SHA256) 1533232153Smm archive_sha256_update(&mtree->sha256ctx, buff, n); 1534232153Smm#endif 1535232153Smm#ifdef ARCHIVE_HAS_SHA384 1536232153Smm if (mtree->compute_sum & F_SHA384) 1537232153Smm archive_sha384_update(&mtree->sha384ctx, buff, n); 1538232153Smm#endif 1539232153Smm#ifdef ARCHIVE_HAS_SHA512 1540232153Smm if (mtree->compute_sum & F_SHA512) 1541232153Smm archive_sha512_update(&mtree->sha512ctx, buff, n); 1542232153Smm#endif 1543232153Smm} 1544232153Smm 1545232153Smmstatic void 1546248616Smmsum_final(struct mtree_writer *mtree, struct reg_info *reg) 1547232153Smm{ 1548232153Smm 1549232153Smm if (mtree->compute_sum & F_CKSUM) { 1550232153Smm uint64_t len; 1551232153Smm /* Include the length of the file. */ 1552232153Smm for (len = mtree->crc_len; len != 0; len >>= 8) 1553232153Smm COMPUTE_CRC(mtree->crc, len & 0xff); 1554248616Smm reg->crc = ~mtree->crc; 1555232153Smm } 1556232153Smm#ifdef ARCHIVE_HAS_MD5 1557232153Smm if (mtree->compute_sum & F_MD5) 1558368708Smm archive_md5_final(&mtree->md5ctx, reg->digest.md5); 1559232153Smm#endif 1560232153Smm#ifdef ARCHIVE_HAS_RMD160 1561232153Smm if (mtree->compute_sum & F_RMD160) 1562368708Smm archive_rmd160_final(&mtree->rmd160ctx, reg->digest.rmd160); 1563232153Smm#endif 1564232153Smm#ifdef ARCHIVE_HAS_SHA1 1565232153Smm if (mtree->compute_sum & F_SHA1) 1566368708Smm archive_sha1_final(&mtree->sha1ctx, reg->digest.sha1); 1567232153Smm#endif 1568232153Smm#ifdef ARCHIVE_HAS_SHA256 1569232153Smm if (mtree->compute_sum & F_SHA256) 1570368708Smm archive_sha256_final(&mtree->sha256ctx, reg->digest.sha256); 1571232153Smm#endif 1572232153Smm#ifdef ARCHIVE_HAS_SHA384 1573232153Smm if (mtree->compute_sum & F_SHA384) 1574368708Smm archive_sha384_final(&mtree->sha384ctx, reg->digest.sha384); 1575232153Smm#endif 1576232153Smm#ifdef ARCHIVE_HAS_SHA512 1577232153Smm if (mtree->compute_sum & F_SHA512) 1578368708Smm archive_sha512_final(&mtree->sha512ctx, reg->digest.sha512); 1579232153Smm#endif 1580232153Smm /* Save what types of sum are computed. */ 1581248616Smm reg->compute_sum = mtree->compute_sum; 1582232153Smm} 1583232153Smm 1584232153Smm#if defined(ARCHIVE_HAS_MD5) || defined(ARCHIVE_HAS_RMD160) || \ 1585232153Smm defined(ARCHIVE_HAS_SHA1) || defined(ARCHIVE_HAS_SHA256) || \ 1586232153Smm defined(ARCHIVE_HAS_SHA384) || defined(ARCHIVE_HAS_SHA512) 1587232153Smmstatic void 1588232153Smmstrappend_bin(struct archive_string *s, const unsigned char *bin, int n) 1589232153Smm{ 1590232153Smm static const char hex[] = "0123456789abcdef"; 1591232153Smm int i; 1592232153Smm 1593232153Smm for (i = 0; i < n; i++) { 1594232153Smm archive_strappend_char(s, hex[bin[i] >> 4]); 1595232153Smm archive_strappend_char(s, hex[bin[i] & 0x0f]); 1596232153Smm } 1597232153Smm} 1598232153Smm#endif 1599232153Smm 1600232153Smmstatic void 1601248616Smmsum_write(struct archive_string *str, struct reg_info *reg) 1602232153Smm{ 1603232153Smm 1604248616Smm if (reg->compute_sum & F_CKSUM) { 1605232153Smm archive_string_sprintf(str, " cksum=%ju", 1606248616Smm (uintmax_t)reg->crc); 1607232153Smm } 1608368708Smm 1609368708Smm#define append_digest(_s, _r, _t) \ 1610368708Smm strappend_bin(_s, _r->digest._t, sizeof(_r->digest._t)) 1611368708Smm 1612232153Smm#ifdef ARCHIVE_HAS_MD5 1613248616Smm if (reg->compute_sum & F_MD5) { 1614232153Smm archive_strcat(str, " md5digest="); 1615368708Smm append_digest(str, reg, md5); 1616232153Smm } 1617232153Smm#endif 1618232153Smm#ifdef ARCHIVE_HAS_RMD160 1619248616Smm if (reg->compute_sum & F_RMD160) { 1620232153Smm archive_strcat(str, " rmd160digest="); 1621368708Smm append_digest(str, reg, rmd160); 1622232153Smm } 1623232153Smm#endif 1624232153Smm#ifdef ARCHIVE_HAS_SHA1 1625248616Smm if (reg->compute_sum & F_SHA1) { 1626232153Smm archive_strcat(str, " sha1digest="); 1627368708Smm append_digest(str, reg, sha1); 1628232153Smm } 1629232153Smm#endif 1630232153Smm#ifdef ARCHIVE_HAS_SHA256 1631248616Smm if (reg->compute_sum & F_SHA256) { 1632232153Smm archive_strcat(str, " sha256digest="); 1633368708Smm append_digest(str, reg, sha256); 1634232153Smm } 1635232153Smm#endif 1636232153Smm#ifdef ARCHIVE_HAS_SHA384 1637248616Smm if (reg->compute_sum & F_SHA384) { 1638232153Smm archive_strcat(str, " sha384digest="); 1639368708Smm append_digest(str, reg, sha384); 1640232153Smm } 1641232153Smm#endif 1642232153Smm#ifdef ARCHIVE_HAS_SHA512 1643248616Smm if (reg->compute_sum & F_SHA512) { 1644232153Smm archive_strcat(str, " sha512digest="); 1645368708Smm append_digest(str, reg, sha512); 1646232153Smm } 1647232153Smm#endif 1648368708Smm#undef append_digest 1649232153Smm} 1650248616Smm 1651248616Smmstatic int 1652248616Smmmtree_entry_cmp_node(const struct archive_rb_node *n1, 1653248616Smm const struct archive_rb_node *n2) 1654248616Smm{ 1655248616Smm const struct mtree_entry *e1 = (const struct mtree_entry *)n1; 1656248616Smm const struct mtree_entry *e2 = (const struct mtree_entry *)n2; 1657248616Smm 1658248616Smm return (strcmp(e2->basename.s, e1->basename.s)); 1659248616Smm} 1660248616Smm 1661248616Smmstatic int 1662248616Smmmtree_entry_cmp_key(const struct archive_rb_node *n, const void *key) 1663248616Smm{ 1664248616Smm const struct mtree_entry *e = (const struct mtree_entry *)n; 1665248616Smm 1666248616Smm return (strcmp((const char *)key, e->basename.s)); 1667248616Smm} 1668248616Smm 1669248616Smm#if defined(_WIN32) || defined(__CYGWIN__) 1670248616Smmstatic int 1671248616Smmcleanup_backslash_1(char *p) 1672248616Smm{ 1673248616Smm int mb, dos; 1674248616Smm 1675248616Smm mb = dos = 0; 1676248616Smm while (*p) { 1677248616Smm if (*(unsigned char *)p > 127) 1678248616Smm mb = 1; 1679248616Smm if (*p == '\\') { 1680248616Smm /* If we have not met any multi-byte characters, 1681248616Smm * we can replace '\' with '/'. */ 1682248616Smm if (!mb) 1683248616Smm *p = '/'; 1684248616Smm dos = 1; 1685248616Smm } 1686248616Smm p++; 1687248616Smm } 1688248616Smm if (!mb || !dos) 1689248616Smm return (0); 1690248616Smm return (-1); 1691248616Smm} 1692248616Smm 1693248616Smmstatic void 1694248616Smmcleanup_backslash_2(wchar_t *p) 1695248616Smm{ 1696248616Smm 1697248616Smm /* Convert a path-separator from '\' to '/' */ 1698248616Smm while (*p != L'\0') { 1699248616Smm if (*p == L'\\') 1700248616Smm *p = L'/'; 1701248616Smm p++; 1702248616Smm } 1703248616Smm} 1704248616Smm#endif 1705248616Smm 1706248616Smm/* 1707248616Smm * Generate a parent directory name and a base name from a pathname. 1708248616Smm */ 1709248616Smmstatic int 1710248616Smmmtree_entry_setup_filenames(struct archive_write *a, struct mtree_entry *file, 1711248616Smm struct archive_entry *entry) 1712248616Smm{ 1713248616Smm const char *pathname; 1714248616Smm char *p, *dirname, *slash; 1715248616Smm size_t len; 1716248616Smm int ret = ARCHIVE_OK; 1717248616Smm 1718248616Smm archive_strcpy(&file->pathname, archive_entry_pathname(entry)); 1719248616Smm#if defined(_WIN32) || defined(__CYGWIN__) 1720248616Smm /* 1721248616Smm * Convert a path-separator from '\' to '/' 1722248616Smm */ 1723248616Smm if (cleanup_backslash_1(file->pathname.s) != 0) { 1724248616Smm const wchar_t *wp = archive_entry_pathname_w(entry); 1725248616Smm struct archive_wstring ws; 1726248616Smm 1727248616Smm if (wp != NULL) { 1728248616Smm int r; 1729248616Smm archive_string_init(&ws); 1730248616Smm archive_wstrcpy(&ws, wp); 1731248616Smm cleanup_backslash_2(ws.s); 1732248616Smm archive_string_empty(&(file->pathname)); 1733248616Smm r = archive_string_append_from_wcs(&(file->pathname), 1734248616Smm ws.s, ws.length); 1735248616Smm archive_wstring_free(&ws); 1736248616Smm if (r < 0 && errno == ENOMEM) { 1737248616Smm archive_set_error(&a->archive, ENOMEM, 1738248616Smm "Can't allocate memory"); 1739248616Smm return (ARCHIVE_FATAL); 1740248616Smm } 1741248616Smm } 1742248616Smm } 1743248616Smm#else 1744248616Smm (void)a; /* UNUSED */ 1745248616Smm#endif 1746248616Smm pathname = file->pathname.s; 1747248616Smm if (strcmp(pathname, ".") == 0) { 1748248616Smm archive_strcpy(&file->basename, "."); 1749248616Smm return (ARCHIVE_OK); 1750248616Smm } 1751248616Smm 1752248616Smm archive_strcpy(&(file->parentdir), pathname); 1753248616Smm 1754248616Smm len = file->parentdir.length; 1755248616Smm p = dirname = file->parentdir.s; 1756248616Smm 1757248616Smm /* 1758248616Smm * Remove leading '/' and '../' elements 1759248616Smm */ 1760248616Smm while (*p) { 1761248616Smm if (p[0] == '/') { 1762248616Smm p++; 1763248616Smm len--; 1764248616Smm } else if (p[0] != '.') 1765248616Smm break; 1766248616Smm else if (p[1] == '.' && p[2] == '/') { 1767248616Smm p += 3; 1768248616Smm len -= 3; 1769248616Smm } else 1770248616Smm break; 1771248616Smm } 1772248616Smm if (p != dirname) { 1773248616Smm memmove(dirname, p, len+1); 1774248616Smm p = dirname; 1775248616Smm } 1776248616Smm /* 1777248616Smm * Remove "/","/." and "/.." elements from tail. 1778248616Smm */ 1779248616Smm while (len > 0) { 1780248616Smm size_t ll = len; 1781248616Smm 1782248616Smm if (len > 0 && p[len-1] == '/') { 1783248616Smm p[len-1] = '\0'; 1784248616Smm len--; 1785248616Smm } 1786248616Smm if (len > 1 && p[len-2] == '/' && p[len-1] == '.') { 1787248616Smm p[len-2] = '\0'; 1788248616Smm len -= 2; 1789248616Smm } 1790248616Smm if (len > 2 && p[len-3] == '/' && p[len-2] == '.' && 1791248616Smm p[len-1] == '.') { 1792248616Smm p[len-3] = '\0'; 1793248616Smm len -= 3; 1794248616Smm } 1795248616Smm if (ll == len) 1796248616Smm break; 1797248616Smm } 1798248616Smm while (*p) { 1799248616Smm if (p[0] == '/') { 1800248616Smm if (p[1] == '/') 1801248616Smm /* Convert '//' --> '/' */ 1802248616Smm strcpy(p, p+1); 1803248616Smm else if (p[1] == '.' && p[2] == '/') 1804248616Smm /* Convert '/./' --> '/' */ 1805248616Smm strcpy(p, p+2); 1806248616Smm else if (p[1] == '.' && p[2] == '.' && p[3] == '/') { 1807248616Smm /* Convert 'dir/dir1/../dir2/' 1808248616Smm * --> 'dir/dir2/' 1809248616Smm */ 1810248616Smm char *rp = p -1; 1811248616Smm while (rp >= dirname) { 1812248616Smm if (*rp == '/') 1813248616Smm break; 1814248616Smm --rp; 1815248616Smm } 1816248616Smm if (rp > dirname) { 1817248616Smm strcpy(rp, p+3); 1818248616Smm p = rp; 1819248616Smm } else { 1820248616Smm strcpy(dirname, p+4); 1821248616Smm p = dirname; 1822248616Smm } 1823248616Smm } else 1824248616Smm p++; 1825248616Smm } else 1826248616Smm p++; 1827248616Smm } 1828248616Smm p = dirname; 1829248616Smm len = strlen(p); 1830248616Smm 1831248616Smm /* 1832311042Smm * Add "./" prefix. 1833248616Smm * NOTE: If the pathname does not have a path separator, we have 1834311042Smm * to add "./" to the head of the pathname because mtree reader 1835248616Smm * will suppose that it is v1(a.k.a classic) mtree format and 1836248616Smm * change the directory unexpectedly and so it will make a wrong 1837248616Smm * path. 1838248616Smm */ 1839248616Smm if (strcmp(p, ".") != 0 && strncmp(p, "./", 2) != 0) { 1840248616Smm struct archive_string as; 1841248616Smm archive_string_init(&as); 1842248616Smm archive_strcpy(&as, "./"); 1843248616Smm archive_strncat(&as, p, len); 1844248616Smm archive_string_empty(&file->parentdir); 1845248616Smm archive_string_concat(&file->parentdir, &as); 1846248616Smm archive_string_free(&as); 1847248616Smm p = file->parentdir.s; 1848248616Smm len = archive_strlen(&file->parentdir); 1849248616Smm } 1850248616Smm 1851248616Smm /* 1852248616Smm * Find out the position which points the last position of 1853248616Smm * path separator('/'). 1854248616Smm */ 1855248616Smm slash = NULL; 1856248616Smm for (; *p != '\0'; p++) { 1857248616Smm if (*p == '/') 1858248616Smm slash = p; 1859248616Smm } 1860248616Smm if (slash == NULL) { 1861248616Smm /* The pathname doesn't have a parent directory. */ 1862248616Smm file->parentdir.length = len; 1863248616Smm archive_string_copy(&(file->basename), &(file->parentdir)); 1864248616Smm archive_string_empty(&(file->parentdir)); 1865248616Smm *file->parentdir.s = '\0'; 1866248616Smm return (ret); 1867248616Smm } 1868248616Smm 1869302001Smm /* Make a basename from file->parentdir.s and slash */ 1870248616Smm *slash = '\0'; 1871302001Smm file->parentdir.length = slash - file->parentdir.s; 1872248616Smm archive_strcpy(&(file->basename), slash + 1); 1873248616Smm return (ret); 1874248616Smm} 1875248616Smm 1876248616Smmstatic int 1877248616Smmmtree_entry_create_virtual_dir(struct archive_write *a, const char *pathname, 1878248616Smm struct mtree_entry **m_entry) 1879248616Smm{ 1880248616Smm struct archive_entry *entry; 1881248616Smm struct mtree_entry *file; 1882248616Smm int r; 1883248616Smm 1884248616Smm entry = archive_entry_new(); 1885248616Smm if (entry == NULL) { 1886248616Smm *m_entry = NULL; 1887248616Smm archive_set_error(&a->archive, ENOMEM, 1888248616Smm "Can't allocate memory"); 1889248616Smm return (ARCHIVE_FATAL); 1890248616Smm } 1891248616Smm archive_entry_copy_pathname(entry, pathname); 1892248616Smm archive_entry_set_mode(entry, AE_IFDIR | 0755); 1893248616Smm archive_entry_set_mtime(entry, time(NULL), 0); 1894248616Smm 1895248616Smm r = mtree_entry_new(a, entry, &file); 1896248616Smm archive_entry_free(entry); 1897248616Smm if (r < ARCHIVE_WARN) { 1898248616Smm *m_entry = NULL; 1899248616Smm archive_set_error(&a->archive, ENOMEM, 1900248616Smm "Can't allocate memory"); 1901248616Smm return (ARCHIVE_FATAL); 1902248616Smm } 1903248616Smm 1904248616Smm file->dir_info->virtual = 1; 1905248616Smm 1906248616Smm *m_entry = file; 1907248616Smm return (ARCHIVE_OK); 1908248616Smm} 1909248616Smm 1910248616Smmstatic void 1911248616Smmmtree_entry_register_add(struct mtree_writer *mtree, struct mtree_entry *file) 1912248616Smm{ 1913248616Smm file->next = NULL; 1914248616Smm *mtree->file_list.last = file; 1915248616Smm mtree->file_list.last = &(file->next); 1916248616Smm} 1917248616Smm 1918248616Smmstatic void 1919248616Smmmtree_entry_register_init(struct mtree_writer *mtree) 1920248616Smm{ 1921248616Smm mtree->file_list.first = NULL; 1922248616Smm mtree->file_list.last = &(mtree->file_list.first); 1923248616Smm} 1924248616Smm 1925248616Smmstatic void 1926248616Smmmtree_entry_register_free(struct mtree_writer *mtree) 1927248616Smm{ 1928248616Smm struct mtree_entry *file, *file_next; 1929248616Smm 1930248616Smm file = mtree->file_list.first; 1931248616Smm while (file != NULL) { 1932248616Smm file_next = file->next; 1933248616Smm mtree_entry_free(file); 1934248616Smm file = file_next; 1935248616Smm } 1936248616Smm} 1937248616Smm 1938248616Smmstatic int 1939248616Smmmtree_entry_add_child_tail(struct mtree_entry *parent, 1940248616Smm struct mtree_entry *child) 1941248616Smm{ 1942248616Smm child->dir_info->chnext = NULL; 1943248616Smm *parent->dir_info->children.last = child; 1944248616Smm parent->dir_info->children.last = &(child->dir_info->chnext); 1945248616Smm return (1); 1946248616Smm} 1947248616Smm 1948248616Smm/* 1949248616Smm * Find a entry from a parent entry with the name. 1950248616Smm */ 1951248616Smmstatic struct mtree_entry * 1952248616Smmmtree_entry_find_child(struct mtree_entry *parent, const char *child_name) 1953248616Smm{ 1954248616Smm struct mtree_entry *np; 1955248616Smm 1956248616Smm if (parent == NULL) 1957248616Smm return (NULL); 1958248616Smm np = (struct mtree_entry *)__archive_rb_tree_find_node( 1959248616Smm &(parent->dir_info->rbtree), child_name); 1960248616Smm return (np); 1961248616Smm} 1962248616Smm 1963248616Smmstatic int 1964248616Smmget_path_component(char *name, size_t n, const char *fn) 1965248616Smm{ 1966248616Smm char *p; 1967248616Smm size_t l; 1968248616Smm 1969248616Smm p = strchr(fn, '/'); 1970248616Smm if (p == NULL) { 1971248616Smm if ((l = strlen(fn)) == 0) 1972248616Smm return (0); 1973248616Smm } else 1974248616Smm l = p - fn; 1975248616Smm if (l > n -1) 1976248616Smm return (-1); 1977248616Smm memcpy(name, fn, l); 1978248616Smm name[l] = '\0'; 1979248616Smm 1980248616Smm return ((int)l); 1981248616Smm} 1982248616Smm 1983248616Smm/* 1984248616Smm * Add a new entry into the tree. 1985248616Smm */ 1986248616Smmstatic int 1987248616Smmmtree_entry_tree_add(struct archive_write *a, struct mtree_entry **filep) 1988248616Smm{ 1989248616Smm#if defined(_WIN32) && !defined(__CYGWIN__) 1990248616Smm char name[_MAX_FNAME];/* Included null terminator size. */ 1991248616Smm#elif defined(NAME_MAX) && NAME_MAX >= 255 1992248616Smm char name[NAME_MAX+1]; 1993248616Smm#else 1994248616Smm char name[256]; 1995248616Smm#endif 1996248616Smm struct mtree_writer *mtree = (struct mtree_writer *)a->format_data; 1997248616Smm struct mtree_entry *dent, *file, *np; 1998248616Smm const char *fn, *p; 1999248616Smm int l, r; 2000248616Smm 2001248616Smm file = *filep; 2002248616Smm if (file->parentdir.length == 0 && file->basename.length == 1 && 2003248616Smm file->basename.s[0] == '.') { 2004248616Smm file->parent = file; 2005248616Smm if (mtree->root != NULL) { 2006248616Smm np = mtree->root; 2007248616Smm goto same_entry; 2008248616Smm } 2009248616Smm mtree->root = file; 2010248616Smm mtree_entry_register_add(mtree, file); 2011248616Smm return (ARCHIVE_OK); 2012248616Smm } 2013248616Smm 2014248616Smm if (file->parentdir.length == 0) { 2015248616Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 2016353377Smm "Internal programming error " 2017248616Smm "in generating canonical name for %s", 2018248616Smm file->pathname.s); 2019248616Smm return (ARCHIVE_FAILED); 2020248616Smm } 2021248616Smm 2022248616Smm fn = p = file->parentdir.s; 2023248616Smm 2024248616Smm /* 2025248616Smm * If the path of the parent directory of `file' entry is 2026248616Smm * the same as the path of `cur_dirent', add `file' entry to 2027248616Smm * `cur_dirent'. 2028248616Smm */ 2029248616Smm if (archive_strlen(&(mtree->cur_dirstr)) 2030248616Smm == archive_strlen(&(file->parentdir)) && 2031248616Smm strcmp(mtree->cur_dirstr.s, fn) == 0) { 2032248616Smm if (!__archive_rb_tree_insert_node( 2033248616Smm &(mtree->cur_dirent->dir_info->rbtree), 2034248616Smm (struct archive_rb_node *)file)) { 2035248616Smm /* There is the same name in the tree. */ 2036248616Smm np = (struct mtree_entry *)__archive_rb_tree_find_node( 2037248616Smm &(mtree->cur_dirent->dir_info->rbtree), 2038248616Smm file->basename.s); 2039248616Smm goto same_entry; 2040248616Smm } 2041248616Smm file->parent = mtree->cur_dirent; 2042248616Smm mtree_entry_register_add(mtree, file); 2043248616Smm return (ARCHIVE_OK); 2044248616Smm } 2045248616Smm 2046248616Smm dent = mtree->root; 2047248616Smm for (;;) { 2048248616Smm l = get_path_component(name, sizeof(name), fn); 2049248616Smm if (l == 0) { 2050248616Smm np = NULL; 2051248616Smm break; 2052248616Smm } 2053248616Smm if (l < 0) { 2054248616Smm archive_set_error(&a->archive, 2055248616Smm ARCHIVE_ERRNO_MISC, 2056248616Smm "A name buffer is too small"); 2057248616Smm return (ARCHIVE_FATAL); 2058248616Smm } 2059248616Smm if (l == 1 && name[0] == '.' && dent != NULL && 2060248616Smm dent == mtree->root) { 2061248616Smm fn += l; 2062248616Smm if (fn[0] == '/') 2063248616Smm fn++; 2064248616Smm continue; 2065248616Smm } 2066248616Smm 2067248616Smm np = mtree_entry_find_child(dent, name); 2068248616Smm if (np == NULL || fn[0] == '\0') 2069248616Smm break; 2070248616Smm 2071248616Smm /* Find next sub directory. */ 2072248616Smm if (!np->dir_info) { 2073248616Smm /* NOT Directory! */ 2074248616Smm archive_set_error(&a->archive, 2075248616Smm ARCHIVE_ERRNO_MISC, 2076248616Smm "`%s' is not directory, we cannot insert `%s' ", 2077248616Smm np->pathname.s, file->pathname.s); 2078248616Smm return (ARCHIVE_FAILED); 2079248616Smm } 2080248616Smm fn += l; 2081248616Smm if (fn[0] == '/') 2082248616Smm fn++; 2083248616Smm dent = np; 2084248616Smm } 2085248616Smm if (np == NULL) { 2086248616Smm /* 2087248616Smm * Create virtual parent directories. 2088248616Smm */ 2089248616Smm while (fn[0] != '\0') { 2090248616Smm struct mtree_entry *vp; 2091248616Smm struct archive_string as; 2092248616Smm 2093248616Smm archive_string_init(&as); 2094248616Smm archive_strncat(&as, p, fn - p + l); 2095248616Smm if (as.s[as.length-1] == '/') { 2096248616Smm as.s[as.length-1] = '\0'; 2097248616Smm as.length--; 2098248616Smm } 2099248616Smm r = mtree_entry_create_virtual_dir(a, as.s, &vp); 2100248616Smm archive_string_free(&as); 2101248616Smm if (r < ARCHIVE_WARN) 2102248616Smm return (r); 2103248616Smm 2104248616Smm if (strcmp(vp->pathname.s, ".") == 0) { 2105248616Smm vp->parent = vp; 2106248616Smm mtree->root = vp; 2107248616Smm } else { 2108248616Smm __archive_rb_tree_insert_node( 2109248616Smm &(dent->dir_info->rbtree), 2110248616Smm (struct archive_rb_node *)vp); 2111248616Smm vp->parent = dent; 2112248616Smm } 2113248616Smm mtree_entry_register_add(mtree, vp); 2114248616Smm np = vp; 2115248616Smm 2116248616Smm fn += l; 2117248616Smm if (fn[0] == '/') 2118248616Smm fn++; 2119248616Smm l = get_path_component(name, sizeof(name), fn); 2120248616Smm if (l < 0) { 2121248616Smm archive_string_free(&as); 2122248616Smm archive_set_error(&a->archive, 2123248616Smm ARCHIVE_ERRNO_MISC, 2124248616Smm "A name buffer is too small"); 2125248616Smm return (ARCHIVE_FATAL); 2126248616Smm } 2127248616Smm dent = np; 2128248616Smm } 2129248616Smm 2130248616Smm /* Found out the parent directory where `file' can be 2131248616Smm * inserted. */ 2132248616Smm mtree->cur_dirent = dent; 2133248616Smm archive_string_empty(&(mtree->cur_dirstr)); 2134248616Smm archive_string_ensure(&(mtree->cur_dirstr), 2135248616Smm archive_strlen(&(dent->parentdir)) + 2136248616Smm archive_strlen(&(dent->basename)) + 2); 2137248616Smm if (archive_strlen(&(dent->parentdir)) + 2138248616Smm archive_strlen(&(dent->basename)) == 0) 2139248616Smm mtree->cur_dirstr.s[0] = 0; 2140248616Smm else { 2141248616Smm if (archive_strlen(&(dent->parentdir)) > 0) { 2142248616Smm archive_string_copy(&(mtree->cur_dirstr), 2143248616Smm &(dent->parentdir)); 2144248616Smm archive_strappend_char( 2145248616Smm &(mtree->cur_dirstr), '/'); 2146248616Smm } 2147248616Smm archive_string_concat(&(mtree->cur_dirstr), 2148248616Smm &(dent->basename)); 2149248616Smm } 2150248616Smm 2151248616Smm if (!__archive_rb_tree_insert_node( 2152248616Smm &(dent->dir_info->rbtree), 2153248616Smm (struct archive_rb_node *)file)) { 2154248616Smm np = (struct mtree_entry *)__archive_rb_tree_find_node( 2155248616Smm &(dent->dir_info->rbtree), file->basename.s); 2156248616Smm goto same_entry; 2157248616Smm } 2158248616Smm file->parent = dent; 2159248616Smm mtree_entry_register_add(mtree, file); 2160248616Smm return (ARCHIVE_OK); 2161248616Smm } 2162248616Smm 2163248616Smmsame_entry: 2164248616Smm /* 2165248616Smm * We have already has the entry the filename of which is 2166248616Smm * the same. 2167248616Smm */ 2168248616Smm r = mtree_entry_exchange_same_entry(a, np, file); 2169248616Smm if (r < ARCHIVE_WARN) 2170248616Smm return (r); 2171248616Smm if (np->dir_info) 2172248616Smm np->dir_info->virtual = 0; 2173248616Smm *filep = np; 2174248616Smm mtree_entry_free(file); 2175248616Smm return (ARCHIVE_WARN); 2176248616Smm} 2177248616Smm 2178248616Smmstatic int 2179248616Smmmtree_entry_exchange_same_entry(struct archive_write *a, struct mtree_entry *np, 2180248616Smm struct mtree_entry *file) 2181248616Smm{ 2182248616Smm 2183248616Smm if ((np->mode & AE_IFMT) != (file->mode & AE_IFMT)) { 2184248616Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 2185248616Smm "Found duplicate entries `%s' and its file type is " 2186248616Smm "different", 2187248616Smm np->pathname.s); 2188248616Smm return (ARCHIVE_FAILED); 2189248616Smm } 2190248616Smm 2191248616Smm /* Update the existent mtree entry's attributes by the new one's. */ 2192248616Smm archive_string_empty(&np->symlink); 2193248616Smm archive_string_concat(&np->symlink, &file->symlink); 2194248616Smm archive_string_empty(&np->uname); 2195248616Smm archive_string_concat(&np->uname, &file->uname); 2196248616Smm archive_string_empty(&np->gname); 2197248616Smm archive_string_concat(&np->gname, &file->gname); 2198248616Smm archive_string_empty(&np->fflags_text); 2199248616Smm archive_string_concat(&np->fflags_text, &file->fflags_text); 2200248616Smm np->nlink = file->nlink; 2201248616Smm np->filetype = file->filetype; 2202248616Smm np->mode = file->mode; 2203248616Smm np->size = file->size; 2204248616Smm np->uid = file->uid; 2205248616Smm np->gid = file->gid; 2206248616Smm np->fflags_set = file->fflags_set; 2207248616Smm np->fflags_clear = file->fflags_clear; 2208248616Smm np->mtime = file->mtime; 2209248616Smm np->mtime_nsec = file->mtime_nsec; 2210248616Smm np->rdevmajor = file->rdevmajor; 2211248616Smm np->rdevminor = file->rdevminor; 2212302001Smm np->devmajor = file->devmajor; 2213302001Smm np->devminor = file->devminor; 2214302001Smm np->ino = file->ino; 2215248616Smm 2216248616Smm return (ARCHIVE_WARN); 2217248616Smm} 2218