1228753Smm/*- 2228753Smm * Copyright (c) 2003-2007 Tim Kientzle 3228753Smm * Copyright (c) 2008 Joerg Sonnenberger 4248616Smm * Copyright (c) 2011-2012 Michihiro NAKAJIMA 5228753Smm * All rights reserved. 6228753Smm * 7228753Smm * Redistribution and use in source and binary forms, with or without 8228753Smm * modification, are permitted provided that the following conditions 9228753Smm * are met: 10228753Smm * 1. Redistributions of source code must retain the above copyright 11228753Smm * notice, this list of conditions and the following disclaimer. 12228753Smm * 2. Redistributions in binary form must reproduce the above copyright 13228753Smm * notice, this list of conditions and the following disclaimer in the 14228753Smm * documentation and/or other materials provided with the distribution. 15228753Smm * 16228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 17228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 20228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26228753Smm */ 27228753Smm 28228753Smm#include "archive_platform.h" 29228763Smm__FBSDID("$FreeBSD: stable/11/contrib/libarchive/libarchive/archive_read_support_format_mtree.c 370535 2021-09-10 08:34:36Z git2svn $"); 30228753Smm 31228753Smm#ifdef HAVE_SYS_STAT_H 32228753Smm#include <sys/stat.h> 33228753Smm#endif 34228753Smm#ifdef HAVE_ERRNO_H 35228753Smm#include <errno.h> 36228753Smm#endif 37228753Smm#ifdef HAVE_FCNTL_H 38228753Smm#include <fcntl.h> 39228753Smm#endif 40228753Smm#include <stddef.h> 41228753Smm/* #include <stdint.h> */ /* See archive_platform.h */ 42228753Smm#ifdef HAVE_STDLIB_H 43228753Smm#include <stdlib.h> 44228753Smm#endif 45228753Smm#ifdef HAVE_STRING_H 46228753Smm#include <string.h> 47228753Smm#endif 48348607Smm#ifdef HAVE_CTYPE_H 49348607Smm#include <ctype.h> 50348607Smm#endif 51228753Smm 52228753Smm#include "archive.h" 53228753Smm#include "archive_entry.h" 54368707Smm#include "archive_entry_private.h" 55228753Smm#include "archive_private.h" 56337351Smm#include "archive_rb.h" 57228753Smm#include "archive_read_private.h" 58228753Smm#include "archive_string.h" 59299529Smm#include "archive_pack_dev.h" 60228753Smm 61228753Smm#ifndef O_BINARY 62228753Smm#define O_BINARY 0 63228753Smm#endif 64248616Smm#ifndef O_CLOEXEC 65248616Smm#define O_CLOEXEC 0 66248616Smm#endif 67228753Smm 68228753Smm#define MTREE_HAS_DEVICE 0x0001 69228753Smm#define MTREE_HAS_FFLAGS 0x0002 70228753Smm#define MTREE_HAS_GID 0x0004 71228753Smm#define MTREE_HAS_GNAME 0x0008 72228753Smm#define MTREE_HAS_MTIME 0x0010 73228753Smm#define MTREE_HAS_NLINK 0x0020 74228753Smm#define MTREE_HAS_PERM 0x0040 75228753Smm#define MTREE_HAS_SIZE 0x0080 76228753Smm#define MTREE_HAS_TYPE 0x0100 77228753Smm#define MTREE_HAS_UID 0x0200 78228753Smm#define MTREE_HAS_UNAME 0x0400 79228753Smm 80228753Smm#define MTREE_HAS_OPTIONAL 0x0800 81248616Smm#define MTREE_HAS_NOCHANGE 0x1000 /* FreeBSD specific */ 82228753Smm 83324417Smm#define MAX_LINE_LEN (1024 * 1024) 84324417Smm 85228753Smmstruct mtree_option { 86228753Smm struct mtree_option *next; 87228753Smm char *value; 88228753Smm}; 89228753Smm 90228753Smmstruct mtree_entry { 91337351Smm struct archive_rb_node rbnode; 92337351Smm struct mtree_entry *next_dup; 93228753Smm struct mtree_entry *next; 94228753Smm struct mtree_option *options; 95228753Smm char *name; 96228753Smm char full; 97228753Smm char used; 98228753Smm}; 99228753Smm 100228753Smmstruct mtree { 101228753Smm struct archive_string line; 102228753Smm size_t buffsize; 103228753Smm char *buff; 104232153Smm int64_t offset; 105228753Smm int fd; 106228753Smm int archive_format; 107228753Smm const char *archive_format_name; 108228753Smm struct mtree_entry *entries; 109228753Smm struct mtree_entry *this_entry; 110337351Smm struct archive_rb_tree entry_rbtree; 111228753Smm struct archive_string current_dir; 112228753Smm struct archive_string contents_name; 113228753Smm 114228753Smm struct archive_entry_linkresolver *resolver; 115337351Smm struct archive_rb_tree rbtree; 116228753Smm 117232153Smm int64_t cur_size; 118299529Smm char checkfs; 119228753Smm}; 120228753Smm 121232153Smmstatic int bid_keycmp(const char *, const char *, ssize_t); 122228753Smmstatic int cleanup(struct archive_read *); 123248616Smmstatic int detect_form(struct archive_read *, int *); 124232153Smmstatic int mtree_bid(struct archive_read *, int); 125228753Smmstatic int parse_file(struct archive_read *, struct archive_entry *, 126228753Smm struct mtree *, struct mtree_entry *, int *); 127228753Smmstatic void parse_escapes(char *, struct mtree_entry *); 128228753Smmstatic int parse_line(struct archive_read *, struct archive_entry *, 129228753Smm struct mtree *, struct mtree_entry *, int *); 130228753Smmstatic int parse_keyword(struct archive_read *, struct mtree *, 131228753Smm struct archive_entry *, struct mtree_option *, int *); 132228753Smmstatic int read_data(struct archive_read *a, 133232153Smm const void **buff, size_t *size, int64_t *offset); 134228753Smmstatic ssize_t readline(struct archive_read *, struct mtree *, char **, ssize_t); 135228753Smmstatic int skip(struct archive_read *a); 136228753Smmstatic int read_header(struct archive_read *, 137228753Smm struct archive_entry *); 138318482Smmstatic int64_t mtree_atol(char **, int base); 139368707Smm#ifndef HAVE_STRNLEN 140368707Smmstatic size_t mtree_strnlen(const char *, size_t); 141368707Smm#endif 142228753Smm 143232153Smm/* 144232153Smm * There's no standard for TIME_T_MAX/TIME_T_MIN. So we compute them 145232153Smm * here. TODO: Move this to configure time, but be careful 146232153Smm * about cross-compile environments. 147232153Smm */ 148232153Smmstatic int64_t 149232153Smmget_time_t_max(void) 150232153Smm{ 151232153Smm#if defined(TIME_T_MAX) 152232153Smm return TIME_T_MAX; 153232153Smm#else 154299529Smm /* ISO C allows time_t to be a floating-point type, 155299529Smm but POSIX requires an integer type. The following 156299529Smm should work on any system that follows the POSIX 157299529Smm conventions. */ 158299529Smm if (((time_t)0) < ((time_t)-1)) { 159299529Smm /* Time_t is unsigned */ 160299529Smm return (~(time_t)0); 161299529Smm } else { 162299529Smm /* Time_t is signed. */ 163299529Smm /* Assume it's the same as int64_t or int32_t */ 164299529Smm if (sizeof(time_t) == sizeof(int64_t)) { 165299529Smm return (time_t)INT64_MAX; 166299529Smm } else { 167299529Smm return (time_t)INT32_MAX; 168232153Smm } 169232153Smm } 170232153Smm#endif 171232153Smm} 172232153Smm 173232153Smmstatic int64_t 174232153Smmget_time_t_min(void) 175232153Smm{ 176232153Smm#if defined(TIME_T_MIN) 177232153Smm return TIME_T_MIN; 178232153Smm#else 179299529Smm if (((time_t)0) < ((time_t)-1)) { 180299529Smm /* Time_t is unsigned */ 181299529Smm return (time_t)0; 182299529Smm } else { 183299529Smm /* Time_t is signed. */ 184299529Smm if (sizeof(time_t) == sizeof(int64_t)) { 185299529Smm return (time_t)INT64_MIN; 186299529Smm } else { 187299529Smm return (time_t)INT32_MIN; 188299529Smm } 189232153Smm } 190232153Smm#endif 191232153Smm} 192232153Smm 193368707Smm#ifdef HAVE_STRNLEN 194368707Smm#define mtree_strnlen(a,b) strnlen(a,b) 195368707Smm#else 196368707Smmstatic size_t 197368707Smmmtree_strnlen(const char *p, size_t maxlen) 198368707Smm{ 199368707Smm size_t i; 200368707Smm 201368707Smm for (i = 0; i <= maxlen; i++) { 202368707Smm if (p[i] == 0) 203368707Smm break; 204368707Smm } 205368707Smm if (i > maxlen) 206368707Smm return (-1);/* invalid */ 207368707Smm return (i); 208368707Smm} 209368707Smm#endif 210368707Smm 211299529Smmstatic int 212299529Smmarchive_read_format_mtree_options(struct archive_read *a, 213299529Smm const char *key, const char *val) 214299529Smm{ 215299529Smm struct mtree *mtree; 216299529Smm 217299529Smm mtree = (struct mtree *)(a->format->data); 218299529Smm if (strcmp(key, "checkfs") == 0) { 219299529Smm /* Allows to read information missing from the mtree from the file system */ 220299529Smm if (val == NULL || val[0] == 0) { 221299529Smm mtree->checkfs = 0; 222299529Smm } else { 223299529Smm mtree->checkfs = 1; 224299529Smm } 225299529Smm return (ARCHIVE_OK); 226299529Smm } 227299529Smm 228299529Smm /* Note: The "warn" return is just to inform the options 229299529Smm * supervisor that we didn't handle it. It will generate 230299529Smm * a suitable error if no one used this option. */ 231299529Smm return (ARCHIVE_WARN); 232299529Smm} 233299529Smm 234228753Smmstatic void 235228753Smmfree_options(struct mtree_option *head) 236228753Smm{ 237228753Smm struct mtree_option *next; 238228753Smm 239228753Smm for (; head != NULL; head = next) { 240228753Smm next = head->next; 241228753Smm free(head->value); 242228753Smm free(head); 243228753Smm } 244228753Smm} 245228753Smm 246337351Smmstatic int 247337351Smmmtree_cmp_node(const struct archive_rb_node *n1, 248337351Smm const struct archive_rb_node *n2) 249337351Smm{ 250337351Smm const struct mtree_entry *e1 = (const struct mtree_entry *)n1; 251337351Smm const struct mtree_entry *e2 = (const struct mtree_entry *)n2; 252337351Smm 253337351Smm return (strcmp(e1->name, e2->name)); 254337351Smm} 255337351Smm 256337351Smmstatic int 257337351Smmmtree_cmp_key(const struct archive_rb_node *n, const void *key) 258337351Smm{ 259337351Smm const struct mtree_entry *e = (const struct mtree_entry *)n; 260337351Smm 261337351Smm return (strcmp(e->name, key)); 262337351Smm} 263337351Smm 264228753Smmint 265228753Smmarchive_read_support_format_mtree(struct archive *_a) 266228753Smm{ 267337351Smm static const struct archive_rb_tree_ops rb_ops = { 268337351Smm mtree_cmp_node, mtree_cmp_key, 269337351Smm }; 270228753Smm struct archive_read *a = (struct archive_read *)_a; 271228753Smm struct mtree *mtree; 272228753Smm int r; 273228753Smm 274232153Smm archive_check_magic(_a, ARCHIVE_READ_MAGIC, 275232153Smm ARCHIVE_STATE_NEW, "archive_read_support_format_mtree"); 276232153Smm 277311041Smm mtree = (struct mtree *)calloc(1, sizeof(*mtree)); 278228753Smm if (mtree == NULL) { 279228753Smm archive_set_error(&a->archive, ENOMEM, 280228753Smm "Can't allocate mtree data"); 281228753Smm return (ARCHIVE_FATAL); 282228753Smm } 283358088Smm mtree->checkfs = 0; 284228753Smm mtree->fd = -1; 285228753Smm 286337351Smm __archive_rb_tree_init(&mtree->rbtree, &rb_ops); 287337351Smm 288228753Smm r = __archive_read_register_format(a, mtree, "mtree", 289299529Smm mtree_bid, archive_read_format_mtree_options, read_header, read_data, skip, NULL, cleanup, NULL, NULL); 290228753Smm 291228753Smm if (r != ARCHIVE_OK) 292228753Smm free(mtree); 293228753Smm return (ARCHIVE_OK); 294228753Smm} 295228753Smm 296228753Smmstatic int 297228753Smmcleanup(struct archive_read *a) 298228753Smm{ 299228753Smm struct mtree *mtree; 300228753Smm struct mtree_entry *p, *q; 301228753Smm 302228753Smm mtree = (struct mtree *)(a->format->data); 303228753Smm 304228753Smm p = mtree->entries; 305228753Smm while (p != NULL) { 306228753Smm q = p->next; 307228753Smm free(p->name); 308228753Smm free_options(p->options); 309228753Smm free(p); 310228753Smm p = q; 311228753Smm } 312228753Smm archive_string_free(&mtree->line); 313228753Smm archive_string_free(&mtree->current_dir); 314228753Smm archive_string_free(&mtree->contents_name); 315228753Smm archive_entry_linkresolver_free(mtree->resolver); 316228753Smm 317228753Smm free(mtree->buff); 318228753Smm free(mtree); 319228753Smm (a->format->data) = NULL; 320228753Smm return (ARCHIVE_OK); 321228753Smm} 322228753Smm 323232153Smmstatic ssize_t 324232153Smmget_line_size(const char *b, ssize_t avail, ssize_t *nlsize) 325232153Smm{ 326232153Smm ssize_t len; 327228753Smm 328232153Smm len = 0; 329232153Smm while (len < avail) { 330232153Smm switch (*b) { 331232153Smm case '\0':/* Non-ascii character or control character. */ 332232153Smm if (nlsize != NULL) 333232153Smm *nlsize = 0; 334232153Smm return (-1); 335232153Smm case '\r': 336232153Smm if (avail-len > 1 && b[1] == '\n') { 337232153Smm if (nlsize != NULL) 338232153Smm *nlsize = 2; 339232153Smm return (len+2); 340232153Smm } 341232153Smm /* FALL THROUGH */ 342232153Smm case '\n': 343232153Smm if (nlsize != NULL) 344232153Smm *nlsize = 1; 345232153Smm return (len+1); 346232153Smm default: 347232153Smm b++; 348232153Smm len++; 349232153Smm break; 350232153Smm } 351232153Smm } 352232153Smm if (nlsize != NULL) 353232153Smm *nlsize = 0; 354232153Smm return (avail); 355232153Smm} 356232153Smm 357307138Smm/* 358307138Smm * <---------------- ravail ---------------------> 359307138Smm * <-- diff ------> <--- avail -----------------> 360307138Smm * <---- len -----------> 361307138Smm * | Previous lines | line being parsed nl extra | 362307138Smm * ^ 363307138Smm * b 364307138Smm * 365307138Smm */ 366232153Smmstatic ssize_t 367232153Smmnext_line(struct archive_read *a, 368232153Smm const char **b, ssize_t *avail, ssize_t *ravail, ssize_t *nl) 369232153Smm{ 370232153Smm ssize_t len; 371232153Smm int quit; 372232153Smm 373232153Smm quit = 0; 374232153Smm if (*avail == 0) { 375232153Smm *nl = 0; 376232153Smm len = 0; 377232153Smm } else 378232153Smm len = get_line_size(*b, *avail, nl); 379232153Smm /* 380232153Smm * Read bytes more while it does not reach the end of line. 381232153Smm */ 382232153Smm while (*nl == 0 && len == *avail && !quit) { 383232153Smm ssize_t diff = *ravail - *avail; 384232153Smm size_t nbytes_req = (*ravail+1023) & ~1023U; 385232153Smm ssize_t tested; 386232153Smm 387324417Smm /* 388324417Smm * Place an arbitrary limit on the line length. 389324417Smm * mtree is almost free-form input and without line length limits, 390324417Smm * it can consume a lot of memory. 391324417Smm */ 392324417Smm if (len >= MAX_LINE_LEN) 393324417Smm return (-1); 394324417Smm 395232153Smm /* Increase reading bytes if it is not enough to at least 396232153Smm * new two lines. */ 397232153Smm if (nbytes_req < (size_t)*ravail + 160) 398232153Smm nbytes_req <<= 1; 399232153Smm 400232153Smm *b = __archive_read_ahead(a, nbytes_req, avail); 401232153Smm if (*b == NULL) { 402232153Smm if (*ravail >= *avail) 403232153Smm return (0); 404232153Smm /* Reading bytes reaches the end of file. */ 405232153Smm *b = __archive_read_ahead(a, *avail, avail); 406232153Smm quit = 1; 407232153Smm } 408232153Smm *ravail = *avail; 409232153Smm *b += diff; 410232153Smm *avail -= diff; 411370535Sgit2svn tested = len;/* Skip some bytes we already determined. */ 412307138Smm len = get_line_size(*b + len, *avail - len, nl); 413232153Smm if (len >= 0) 414232153Smm len += tested; 415232153Smm } 416232153Smm return (len); 417232153Smm} 418232153Smm 419232153Smm/* 420232153Smm * Compare characters with a mtree keyword. 421232153Smm * Returns the length of a mtree keyword if matched. 422232153Smm * Returns 0 if not matched. 423232153Smm */ 424228753Smmstatic int 425232153Smmbid_keycmp(const char *p, const char *key, ssize_t len) 426228753Smm{ 427232153Smm int match_len = 0; 428232153Smm 429232153Smm while (len > 0 && *p && *key) { 430232153Smm if (*p == *key) { 431232153Smm --len; 432232153Smm ++p; 433232153Smm ++key; 434232153Smm ++match_len; 435232153Smm continue; 436232153Smm } 437232153Smm return (0);/* Not match */ 438232153Smm } 439232153Smm if (*key != '\0') 440232153Smm return (0);/* Not match */ 441232153Smm 442232153Smm /* A following character should be specified characters */ 443232153Smm if (p[0] == '=' || p[0] == ' ' || p[0] == '\t' || 444232153Smm p[0] == '\n' || p[0] == '\r' || 445232153Smm (p[0] == '\\' && (p[1] == '\n' || p[1] == '\r'))) 446232153Smm return (match_len); 447232153Smm return (0);/* Not match */ 448232153Smm} 449232153Smm 450232153Smm/* 451232153Smm * Test whether the characters 'p' has is mtree keyword. 452232153Smm * Returns the length of a detected keyword. 453232153Smm * Returns 0 if any keywords were not found. 454232153Smm */ 455248616Smmstatic int 456232153Smmbid_keyword(const char *p, ssize_t len) 457232153Smm{ 458316337Smm static const char * const keys_c[] = { 459232153Smm "content", "contents", "cksum", NULL 460232153Smm }; 461316337Smm static const char * const keys_df[] = { 462232153Smm "device", "flags", NULL 463232153Smm }; 464316337Smm static const char * const keys_g[] = { 465232153Smm "gid", "gname", NULL 466232153Smm }; 467316337Smm static const char * const keys_il[] = { 468299529Smm "ignore", "inode", "link", NULL 469232153Smm }; 470316337Smm static const char * const keys_m[] = { 471232153Smm "md5", "md5digest", "mode", NULL 472232153Smm }; 473316337Smm static const char * const keys_no[] = { 474248616Smm "nlink", "nochange", "optional", NULL 475232153Smm }; 476316337Smm static const char * const keys_r[] = { 477299529Smm "resdevice", "rmd160", "rmd160digest", NULL 478232153Smm }; 479316337Smm static const char * const keys_s[] = { 480232153Smm "sha1", "sha1digest", 481232153Smm "sha256", "sha256digest", 482232153Smm "sha384", "sha384digest", 483232153Smm "sha512", "sha512digest", 484232153Smm "size", NULL 485232153Smm }; 486316337Smm static const char * const keys_t[] = { 487232153Smm "tags", "time", "type", NULL 488232153Smm }; 489316337Smm static const char * const keys_u[] = { 490232153Smm "uid", "uname", NULL 491232153Smm }; 492316337Smm const char * const *keys; 493232153Smm int i; 494232153Smm 495232153Smm switch (*p) { 496232153Smm case 'c': keys = keys_c; break; 497232153Smm case 'd': case 'f': keys = keys_df; break; 498232153Smm case 'g': keys = keys_g; break; 499232153Smm case 'i': case 'l': keys = keys_il; break; 500232153Smm case 'm': keys = keys_m; break; 501232153Smm case 'n': case 'o': keys = keys_no; break; 502232153Smm case 'r': keys = keys_r; break; 503232153Smm case 's': keys = keys_s; break; 504232153Smm case 't': keys = keys_t; break; 505232153Smm case 'u': keys = keys_u; break; 506232153Smm default: return (0);/* Unknown key */ 507232153Smm } 508232153Smm 509232153Smm for (i = 0; keys[i] != NULL; i++) { 510232153Smm int l = bid_keycmp(p, keys[i], len); 511232153Smm if (l > 0) 512232153Smm return (l); 513232153Smm } 514232153Smm return (0);/* Unknown key */ 515232153Smm} 516232153Smm 517232153Smm/* 518232153Smm * Test whether there is a set of mtree keywords. 519232153Smm * Returns the number of keyword. 520232153Smm * Returns -1 if we got incorrect sequence. 521232153Smm * This function expects a set of "<space characters>keyword=value". 522232153Smm * When "unset" is specified, expects a set of "<space characters>keyword". 523232153Smm */ 524232153Smmstatic int 525248616Smmbid_keyword_list(const char *p, ssize_t len, int unset, int last_is_path) 526232153Smm{ 527232153Smm int l; 528232153Smm int keycnt = 0; 529232153Smm 530232153Smm while (len > 0 && *p) { 531232153Smm int blank = 0; 532232153Smm 533232153Smm /* Test whether there are blank characters in the line. */ 534232153Smm while (len >0 && (*p == ' ' || *p == '\t')) { 535232153Smm ++p; 536232153Smm --len; 537232153Smm blank = 1; 538232153Smm } 539232153Smm if (*p == '\n' || *p == '\r') 540232153Smm break; 541232153Smm if (p[0] == '\\' && (p[1] == '\n' || p[1] == '\r')) 542232153Smm break; 543248616Smm if (!blank && !last_is_path) /* No blank character. */ 544232153Smm return (-1); 545248616Smm if (last_is_path && len == 0) 546248616Smm return (keycnt); 547232153Smm 548232153Smm if (unset) { 549232153Smm l = bid_keycmp(p, "all", len); 550232153Smm if (l > 0) 551232153Smm return (1); 552232153Smm } 553232153Smm /* Test whether there is a correct key in the line. */ 554232153Smm l = bid_keyword(p, len); 555232153Smm if (l == 0) 556232153Smm return (-1);/* Unknown keyword was found. */ 557232153Smm p += l; 558232153Smm len -= l; 559232153Smm keycnt++; 560232153Smm 561232153Smm /* Skip value */ 562232153Smm if (*p == '=') { 563232153Smm int value = 0; 564232153Smm ++p; 565232153Smm --len; 566232153Smm while (len > 0 && *p != ' ' && *p != '\t') { 567232153Smm ++p; 568232153Smm --len; 569232153Smm value = 1; 570232153Smm } 571232153Smm /* A keyword should have a its value unless 572232153Smm * "/unset" operation. */ 573232153Smm if (!unset && value == 0) 574232153Smm return (-1); 575232153Smm } 576232153Smm } 577232153Smm return (keycnt); 578232153Smm} 579232153Smm 580232153Smmstatic int 581248616Smmbid_entry(const char *p, ssize_t len, ssize_t nl, int *last_is_path) 582232153Smm{ 583232153Smm int f = 0; 584232153Smm static const unsigned char safe_char[256] = { 585232153Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */ 586232153Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */ 587232153Smm /* !"$%&'()*+,-./ EXCLUSION:( )(#) */ 588232153Smm 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */ 589232153Smm /* 0123456789:;<>? EXCLUSION:(=) */ 590232153Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, /* 30 - 3F */ 591232153Smm /* @ABCDEFGHIJKLMNO */ 592232153Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */ 593232153Smm /* PQRSTUVWXYZ[\]^_ */ 594232153Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */ 595232153Smm /* `abcdefghijklmno */ 596232153Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */ 597232153Smm /* pqrstuvwxyz{|}~ */ 598232153Smm 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */ 599232153Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */ 600232153Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */ 601232153Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */ 602232153Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */ 603232153Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */ 604232153Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */ 605232153Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */ 606232153Smm 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */ 607232153Smm }; 608299529Smm ssize_t ll; 609248616Smm const char *pp = p; 610299529Smm const char * const pp_end = pp + len; 611232153Smm 612248616Smm *last_is_path = 0; 613232153Smm /* 614232153Smm * Skip the path-name which is quoted. 615232153Smm */ 616299529Smm for (;pp < pp_end; ++pp) { 617248616Smm if (!safe_char[*(const unsigned char *)pp]) { 618299529Smm if (*pp != ' ' && *pp != '\t' && *pp != '\r' 619299529Smm && *pp != '\n') 620299529Smm f = 0; 621248616Smm break; 622248616Smm } 623299529Smm f = 1; 624232153Smm } 625299529Smm ll = pp_end - pp; 626299529Smm 627248616Smm /* If a path-name was not found at the first, try to check 628299529Smm * a mtree format(a.k.a form D) ``NetBSD's mtree -D'' creates, 629299529Smm * which places the path-name at the last. */ 630248616Smm if (f == 0) { 631248616Smm const char *pb = p + len - nl; 632248616Smm int name_len = 0; 633248616Smm int slash; 634232153Smm 635299529Smm /* The form D accepts only a single line for an entry. */ 636248616Smm if (pb-2 >= p && 637248616Smm pb[-1] == '\\' && (pb[-2] == ' ' || pb[-2] == '\t')) 638248616Smm return (-1); 639248616Smm if (pb-1 >= p && pb[-1] == '\\') 640248616Smm return (-1); 641248616Smm 642248616Smm slash = 0; 643248616Smm while (p <= --pb && *pb != ' ' && *pb != '\t') { 644248616Smm if (!safe_char[*(const unsigned char *)pb]) 645248616Smm return (-1); 646248616Smm name_len++; 647248616Smm /* The pathname should have a slash in this 648248616Smm * format. */ 649248616Smm if (*pb == '/') 650248616Smm slash = 1; 651248616Smm } 652248616Smm if (name_len == 0 || slash == 0) 653248616Smm return (-1); 654248616Smm /* If '/' is placed at the first in this field, this is not 655248616Smm * a valid filename. */ 656248616Smm if (pb[1] == '/') 657248616Smm return (-1); 658248616Smm ll = len - nl - name_len; 659248616Smm pp = p; 660248616Smm *last_is_path = 1; 661248616Smm } 662248616Smm 663248616Smm return (bid_keyword_list(pp, ll, 0, *last_is_path)); 664232153Smm} 665232153Smm 666232153Smm#define MAX_BID_ENTRY 3 667232153Smm 668232153Smmstatic int 669232153Smmmtree_bid(struct archive_read *a, int best_bid) 670232153Smm{ 671228753Smm const char *signature = "#mtree"; 672228753Smm const char *p; 673228753Smm 674232153Smm (void)best_bid; /* UNUSED */ 675232153Smm 676228753Smm /* Now let's look at the actual header and see if it matches. */ 677248616Smm p = __archive_read_ahead(a, strlen(signature), NULL); 678228753Smm if (p == NULL) 679228753Smm return (-1); 680228753Smm 681232153Smm if (memcmp(p, signature, strlen(signature)) == 0) 682228753Smm return (8 * (int)strlen(signature)); 683232153Smm 684232153Smm /* 685232153Smm * There is not a mtree signature. Let's try to detect mtree format. 686232153Smm */ 687248616Smm return (detect_form(a, NULL)); 688248616Smm} 689248616Smm 690248616Smmstatic int 691248616Smmdetect_form(struct archive_read *a, int *is_form_d) 692248616Smm{ 693248616Smm const char *p; 694248616Smm ssize_t avail, ravail; 695248616Smm ssize_t detected_bytes = 0, len, nl; 696248616Smm int entry_cnt = 0, multiline = 0; 697248616Smm int form_D = 0;/* The archive is generated by `NetBSD mtree -D' 698248616Smm * (In this source we call it `form D') . */ 699248616Smm 700248616Smm if (is_form_d != NULL) 701248616Smm *is_form_d = 0; 702248616Smm p = __archive_read_ahead(a, 1, &avail); 703248616Smm if (p == NULL) 704248616Smm return (-1); 705232153Smm ravail = avail; 706232153Smm for (;;) { 707232153Smm len = next_line(a, &p, &avail, &ravail, &nl); 708232153Smm /* The terminal character of the line should be 709232153Smm * a new line character, '\r\n' or '\n'. */ 710232153Smm if (len <= 0 || nl == 0) 711232153Smm break; 712232153Smm if (!multiline) { 713232153Smm /* Leading whitespace is never significant, 714232153Smm * ignore it. */ 715232153Smm while (len > 0 && (*p == ' ' || *p == '\t')) { 716232153Smm ++p; 717232153Smm --avail; 718232153Smm --len; 719232153Smm } 720232153Smm /* Skip comment or empty line. */ 721232153Smm if (p[0] == '#' || p[0] == '\n' || p[0] == '\r') { 722232153Smm p += len; 723232153Smm avail -= len; 724232153Smm continue; 725232153Smm } 726232153Smm } else { 727232153Smm /* A continuance line; the terminal 728232153Smm * character of previous line was '\' character. */ 729248616Smm if (bid_keyword_list(p, len, 0, 0) <= 0) 730232153Smm break; 731232153Smm if (multiline == 1) 732232153Smm detected_bytes += len; 733232153Smm if (p[len-nl-1] != '\\') { 734232153Smm if (multiline == 1 && 735232153Smm ++entry_cnt >= MAX_BID_ENTRY) 736232153Smm break; 737232153Smm multiline = 0; 738232153Smm } 739232153Smm p += len; 740232153Smm avail -= len; 741232153Smm continue; 742232153Smm } 743232153Smm if (p[0] != '/') { 744248616Smm int last_is_path, keywords; 745248616Smm 746248616Smm keywords = bid_entry(p, len, nl, &last_is_path); 747248616Smm if (keywords >= 0) { 748232153Smm detected_bytes += len; 749248616Smm if (form_D == 0) { 750248616Smm if (last_is_path) 751248616Smm form_D = 1; 752248616Smm else if (keywords > 0) 753248616Smm /* This line is not `form D'. */ 754248616Smm form_D = -1; 755248616Smm } else if (form_D == 1) { 756248616Smm if (!last_is_path && keywords > 0) 757248616Smm /* This this is not `form D' 758248616Smm * and We cannot accept mixed 759248616Smm * format. */ 760248616Smm break; 761248616Smm } 762248616Smm if (!last_is_path && p[len-nl-1] == '\\') 763232153Smm /* This line continues. */ 764232153Smm multiline = 1; 765232153Smm else { 766232153Smm /* We've got plenty of correct lines 767232153Smm * to assume that this file is a mtree 768232153Smm * format. */ 769232153Smm if (++entry_cnt >= MAX_BID_ENTRY) 770232153Smm break; 771232153Smm } 772232153Smm } else 773232153Smm break; 774313570Smm } else if (len > 4 && strncmp(p, "/set", 4) == 0) { 775248616Smm if (bid_keyword_list(p+4, len-4, 0, 0) <= 0) 776232153Smm break; 777232153Smm /* This line continues. */ 778232153Smm if (p[len-nl-1] == '\\') 779232153Smm multiline = 2; 780313570Smm } else if (len > 6 && strncmp(p, "/unset", 6) == 0) { 781248616Smm if (bid_keyword_list(p+6, len-6, 1, 0) <= 0) 782232153Smm break; 783232153Smm /* This line continues. */ 784232153Smm if (p[len-nl-1] == '\\') 785232153Smm multiline = 2; 786232153Smm } else 787232153Smm break; 788232153Smm 789232153Smm /* Test next line. */ 790232153Smm p += len; 791232153Smm avail -= len; 792232153Smm } 793248616Smm if (entry_cnt >= MAX_BID_ENTRY || (entry_cnt > 0 && len == 0)) { 794248616Smm if (is_form_d != NULL) { 795248616Smm if (form_D == 1) 796248616Smm *is_form_d = 1; 797248616Smm } 798232153Smm return (32); 799248616Smm } 800232153Smm 801228753Smm return (0); 802228753Smm} 803228753Smm 804228753Smm/* 805228753Smm * The extended mtree format permits multiple lines specifying 806228753Smm * attributes for each file. For those entries, only the last line 807228753Smm * is actually used. Practically speaking, that means we have 808228753Smm * to read the entire mtree file into memory up front. 809228753Smm * 810228753Smm * The parsing is done in two steps. First, it is decided if a line 811228753Smm * changes the global defaults and if it is, processed accordingly. 812228753Smm * Otherwise, the options of the line are merged with the current 813228753Smm * global options. 814228753Smm */ 815228753Smmstatic int 816228753Smmadd_option(struct archive_read *a, struct mtree_option **global, 817228753Smm const char *value, size_t len) 818228753Smm{ 819232153Smm struct mtree_option *opt; 820228753Smm 821232153Smm if ((opt = malloc(sizeof(*opt))) == NULL) { 822228753Smm archive_set_error(&a->archive, errno, "Can't allocate memory"); 823228753Smm return (ARCHIVE_FATAL); 824228753Smm } 825232153Smm if ((opt->value = malloc(len + 1)) == NULL) { 826232153Smm free(opt); 827228753Smm archive_set_error(&a->archive, errno, "Can't allocate memory"); 828228753Smm return (ARCHIVE_FATAL); 829228753Smm } 830232153Smm memcpy(opt->value, value, len); 831232153Smm opt->value[len] = '\0'; 832232153Smm opt->next = *global; 833232153Smm *global = opt; 834228753Smm return (ARCHIVE_OK); 835228753Smm} 836228753Smm 837228753Smmstatic void 838228753Smmremove_option(struct mtree_option **global, const char *value, size_t len) 839228753Smm{ 840228753Smm struct mtree_option *iter, *last; 841228753Smm 842228753Smm last = NULL; 843228753Smm for (iter = *global; iter != NULL; last = iter, iter = iter->next) { 844228753Smm if (strncmp(iter->value, value, len) == 0 && 845228753Smm (iter->value[len] == '\0' || 846228753Smm iter->value[len] == '=')) 847228753Smm break; 848228753Smm } 849228753Smm if (iter == NULL) 850228753Smm return; 851228753Smm if (last == NULL) 852228753Smm *global = iter->next; 853228753Smm else 854228753Smm last->next = iter->next; 855228753Smm 856228753Smm free(iter->value); 857228753Smm free(iter); 858228753Smm} 859228753Smm 860228753Smmstatic int 861228753Smmprocess_global_set(struct archive_read *a, 862228753Smm struct mtree_option **global, const char *line) 863228753Smm{ 864228753Smm const char *next, *eq; 865228753Smm size_t len; 866228753Smm int r; 867228753Smm 868228753Smm line += 4; 869228753Smm for (;;) { 870228753Smm next = line + strspn(line, " \t\r\n"); 871228753Smm if (*next == '\0') 872228753Smm return (ARCHIVE_OK); 873228753Smm line = next; 874228753Smm next = line + strcspn(line, " \t\r\n"); 875228753Smm eq = strchr(line, '='); 876228753Smm if (eq > next) 877228753Smm len = next - line; 878228753Smm else 879228753Smm len = eq - line; 880228753Smm 881228753Smm remove_option(global, line, len); 882228753Smm r = add_option(a, global, line, next - line); 883228753Smm if (r != ARCHIVE_OK) 884228753Smm return (r); 885228753Smm line = next; 886228753Smm } 887228753Smm} 888228753Smm 889228753Smmstatic int 890228753Smmprocess_global_unset(struct archive_read *a, 891228753Smm struct mtree_option **global, const char *line) 892228753Smm{ 893228753Smm const char *next; 894228753Smm size_t len; 895228753Smm 896228753Smm line += 6; 897228753Smm if (strchr(line, '=') != NULL) { 898228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 899228753Smm "/unset shall not contain `='"); 900228753Smm return ARCHIVE_FATAL; 901228753Smm } 902228753Smm 903228753Smm for (;;) { 904228753Smm next = line + strspn(line, " \t\r\n"); 905228753Smm if (*next == '\0') 906228753Smm return (ARCHIVE_OK); 907228753Smm line = next; 908228753Smm len = strcspn(line, " \t\r\n"); 909228753Smm 910228753Smm if (len == 3 && strncmp(line, "all", 3) == 0) { 911228753Smm free_options(*global); 912228753Smm *global = NULL; 913228753Smm } else { 914228753Smm remove_option(global, line, len); 915228753Smm } 916228753Smm 917228753Smm line += len; 918228753Smm } 919228753Smm} 920228753Smm 921228753Smmstatic int 922228753Smmprocess_add_entry(struct archive_read *a, struct mtree *mtree, 923248616Smm struct mtree_option **global, const char *line, ssize_t line_len, 924248616Smm struct mtree_entry **last_entry, int is_form_d) 925228753Smm{ 926337351Smm struct mtree_entry *entry; 927228753Smm struct mtree_option *iter; 928248616Smm const char *next, *eq, *name, *end; 929299529Smm size_t name_len, len; 930299529Smm int r, i; 931228753Smm 932228753Smm if ((entry = malloc(sizeof(*entry))) == NULL) { 933228753Smm archive_set_error(&a->archive, errno, "Can't allocate memory"); 934228753Smm return (ARCHIVE_FATAL); 935228753Smm } 936228753Smm entry->next = NULL; 937228753Smm entry->options = NULL; 938228753Smm entry->name = NULL; 939228753Smm entry->used = 0; 940228753Smm entry->full = 0; 941228753Smm 942228753Smm /* Add this entry to list. */ 943228753Smm if (*last_entry == NULL) 944228753Smm mtree->entries = entry; 945228753Smm else 946228753Smm (*last_entry)->next = entry; 947228753Smm *last_entry = entry; 948228753Smm 949248616Smm if (is_form_d) { 950299529Smm /* Filename is last item on line. */ 951299529Smm /* Adjust line_len to trim trailing whitespace */ 952248616Smm while (line_len > 0) { 953299529Smm char last_character = line[line_len - 1]; 954299529Smm if (last_character == '\r' 955299529Smm || last_character == '\n' 956299529Smm || last_character == '\t' 957299529Smm || last_character == ' ') { 958299529Smm line_len--; 959299529Smm } else { 960248616Smm break; 961299529Smm } 962248616Smm } 963299529Smm /* Name starts after the last whitespace separator */ 964299529Smm name = line; 965299529Smm for (i = 0; i < line_len; i++) { 966299529Smm if (line[i] == '\r' 967299529Smm || line[i] == '\n' 968299529Smm || line[i] == '\t' 969299529Smm || line[i] == ' ') { 970299529Smm name = line + i + 1; 971248616Smm } 972248616Smm } 973299529Smm name_len = line + line_len - name; 974248616Smm end = name; 975248616Smm } else { 976299529Smm /* Filename is first item on line */ 977299529Smm name_len = strcspn(line, " \t\r\n"); 978248616Smm name = line; 979299529Smm line += name_len; 980248616Smm end = line + line_len; 981248616Smm } 982299529Smm /* name/name_len is the name within the line. */ 983299529Smm /* line..end brackets the entire line except the name */ 984248616Smm 985299529Smm if ((entry->name = malloc(name_len + 1)) == NULL) { 986228753Smm archive_set_error(&a->archive, errno, "Can't allocate memory"); 987228753Smm return (ARCHIVE_FATAL); 988228753Smm } 989228753Smm 990299529Smm memcpy(entry->name, name, name_len); 991299529Smm entry->name[name_len] = '\0'; 992228753Smm parse_escapes(entry->name, entry); 993228753Smm 994337351Smm entry->next_dup = NULL; 995337351Smm if (entry->full) { 996337351Smm if (!__archive_rb_tree_insert_node(&mtree->rbtree, &entry->rbnode)) { 997337351Smm struct mtree_entry *alt; 998337351Smm alt = (struct mtree_entry *)__archive_rb_tree_find_node( 999337351Smm &mtree->rbtree, entry->name); 1000337351Smm while (alt->next_dup) 1001337351Smm alt = alt->next_dup; 1002337351Smm alt->next_dup = entry; 1003337351Smm } 1004311041Smm } 1005311041Smm 1006228753Smm for (iter = *global; iter != NULL; iter = iter->next) { 1007228753Smm r = add_option(a, &entry->options, iter->value, 1008228753Smm strlen(iter->value)); 1009228753Smm if (r != ARCHIVE_OK) 1010228753Smm return (r); 1011228753Smm } 1012228753Smm 1013228753Smm for (;;) { 1014228753Smm next = line + strspn(line, " \t\r\n"); 1015228753Smm if (*next == '\0') 1016228753Smm return (ARCHIVE_OK); 1017248616Smm if (next >= end) 1018248616Smm return (ARCHIVE_OK); 1019228753Smm line = next; 1020228753Smm next = line + strcspn(line, " \t\r\n"); 1021228753Smm eq = strchr(line, '='); 1022228753Smm if (eq == NULL || eq > next) 1023228753Smm len = next - line; 1024228753Smm else 1025228753Smm len = eq - line; 1026228753Smm 1027228753Smm remove_option(&entry->options, line, len); 1028228753Smm r = add_option(a, &entry->options, line, next - line); 1029228753Smm if (r != ARCHIVE_OK) 1030228753Smm return (r); 1031228753Smm line = next; 1032228753Smm } 1033228753Smm} 1034228753Smm 1035228753Smmstatic int 1036228753Smmread_mtree(struct archive_read *a, struct mtree *mtree) 1037228753Smm{ 1038228753Smm ssize_t len; 1039228753Smm uintmax_t counter; 1040348607Smm char *p, *s; 1041228753Smm struct mtree_option *global; 1042228753Smm struct mtree_entry *last_entry; 1043248616Smm int r, is_form_d; 1044228753Smm 1045228753Smm mtree->archive_format = ARCHIVE_FORMAT_MTREE; 1046228753Smm mtree->archive_format_name = "mtree"; 1047228753Smm 1048228753Smm global = NULL; 1049228753Smm last_entry = NULL; 1050228753Smm 1051248616Smm (void)detect_form(a, &is_form_d); 1052248616Smm 1053228753Smm for (counter = 1; ; ++counter) { 1054348607Smm r = ARCHIVE_OK; 1055232153Smm len = readline(a, mtree, &p, 65536); 1056228753Smm if (len == 0) { 1057228753Smm mtree->this_entry = mtree->entries; 1058228753Smm free_options(global); 1059228753Smm return (ARCHIVE_OK); 1060228753Smm } 1061228753Smm if (len < 0) { 1062228753Smm free_options(global); 1063248616Smm return ((int)len); 1064228753Smm } 1065228753Smm /* Leading whitespace is never significant, ignore it. */ 1066228753Smm while (*p == ' ' || *p == '\t') { 1067228753Smm ++p; 1068228753Smm --len; 1069228753Smm } 1070228753Smm /* Skip content lines and blank lines. */ 1071228753Smm if (*p == '#') 1072228753Smm continue; 1073228753Smm if (*p == '\r' || *p == '\n' || *p == '\0') 1074228753Smm continue; 1075348607Smm /* Non-printable characters are not allowed */ 1076348607Smm for (s = p;s < p + len - 1; s++) { 1077370535Sgit2svn if (!isprint((unsigned char)*s)) { 1078348607Smm r = ARCHIVE_FATAL; 1079348607Smm break; 1080348607Smm } 1081348607Smm } 1082348607Smm if (r != ARCHIVE_OK) 1083348607Smm break; 1084228753Smm if (*p != '/') { 1085248616Smm r = process_add_entry(a, mtree, &global, p, len, 1086248616Smm &last_entry, is_form_d); 1087313570Smm } else if (len > 4 && strncmp(p, "/set", 4) == 0) { 1088228753Smm if (p[4] != ' ' && p[4] != '\t') 1089228753Smm break; 1090228753Smm r = process_global_set(a, &global, p); 1091313570Smm } else if (len > 6 && strncmp(p, "/unset", 6) == 0) { 1092228753Smm if (p[6] != ' ' && p[6] != '\t') 1093228753Smm break; 1094228753Smm r = process_global_unset(a, &global, p); 1095228753Smm } else 1096228753Smm break; 1097228753Smm 1098228753Smm if (r != ARCHIVE_OK) { 1099228753Smm free_options(global); 1100228753Smm return r; 1101228753Smm } 1102228753Smm } 1103228753Smm 1104228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 1105228753Smm "Can't parse line %ju", counter); 1106228753Smm free_options(global); 1107228753Smm return (ARCHIVE_FATAL); 1108228753Smm} 1109228753Smm 1110228753Smm/* 1111228753Smm * Read in the entire mtree file into memory on the first request. 1112228753Smm * Then use the next unused file to satisfy each header request. 1113228753Smm */ 1114228753Smmstatic int 1115228753Smmread_header(struct archive_read *a, struct archive_entry *entry) 1116228753Smm{ 1117228753Smm struct mtree *mtree; 1118228753Smm char *p; 1119228753Smm int r, use_next; 1120228753Smm 1121228753Smm mtree = (struct mtree *)(a->format->data); 1122228753Smm 1123228753Smm if (mtree->fd >= 0) { 1124228753Smm close(mtree->fd); 1125228753Smm mtree->fd = -1; 1126228753Smm } 1127228753Smm 1128228753Smm if (mtree->entries == NULL) { 1129228753Smm mtree->resolver = archive_entry_linkresolver_new(); 1130228753Smm if (mtree->resolver == NULL) 1131228753Smm return ARCHIVE_FATAL; 1132228753Smm archive_entry_linkresolver_set_strategy(mtree->resolver, 1133228753Smm ARCHIVE_FORMAT_MTREE); 1134228753Smm r = read_mtree(a, mtree); 1135228753Smm if (r != ARCHIVE_OK) 1136228753Smm return (r); 1137228753Smm } 1138228753Smm 1139228753Smm a->archive.archive_format = mtree->archive_format; 1140228753Smm a->archive.archive_format_name = mtree->archive_format_name; 1141228753Smm 1142228753Smm for (;;) { 1143228753Smm if (mtree->this_entry == NULL) 1144228753Smm return (ARCHIVE_EOF); 1145228753Smm if (strcmp(mtree->this_entry->name, "..") == 0) { 1146228753Smm mtree->this_entry->used = 1; 1147228753Smm if (archive_strlen(&mtree->current_dir) > 0) { 1148228753Smm /* Roll back current path. */ 1149228753Smm p = mtree->current_dir.s 1150228753Smm + mtree->current_dir.length - 1; 1151228753Smm while (p >= mtree->current_dir.s && *p != '/') 1152228753Smm --p; 1153228753Smm if (p >= mtree->current_dir.s) 1154228753Smm --p; 1155228753Smm mtree->current_dir.length 1156228753Smm = p - mtree->current_dir.s + 1; 1157228753Smm } 1158228753Smm } 1159228753Smm if (!mtree->this_entry->used) { 1160228753Smm use_next = 0; 1161299529Smm r = parse_file(a, entry, mtree, mtree->this_entry, 1162299529Smm &use_next); 1163228753Smm if (use_next == 0) 1164228753Smm return (r); 1165228753Smm } 1166228753Smm mtree->this_entry = mtree->this_entry->next; 1167228753Smm } 1168228753Smm} 1169228753Smm 1170228753Smm/* 1171228753Smm * A single file can have multiple lines contribute specifications. 1172228753Smm * Parse as many lines as necessary, then pull additional information 1173228753Smm * from a backing file on disk as necessary. 1174228753Smm */ 1175228753Smmstatic int 1176228753Smmparse_file(struct archive_read *a, struct archive_entry *entry, 1177228753Smm struct mtree *mtree, struct mtree_entry *mentry, int *use_next) 1178228753Smm{ 1179228753Smm const char *path; 1180228753Smm struct stat st_storage, *st; 1181228753Smm struct mtree_entry *mp; 1182228753Smm struct archive_entry *sparse_entry; 1183232153Smm int r = ARCHIVE_OK, r1, parsed_kws; 1184228753Smm 1185228753Smm mentry->used = 1; 1186228753Smm 1187228753Smm /* Initialize reasonable defaults. */ 1188232153Smm archive_entry_set_filetype(entry, AE_IFREG); 1189228753Smm archive_entry_set_size(entry, 0); 1190228753Smm archive_string_empty(&mtree->contents_name); 1191228753Smm 1192228753Smm /* Parse options from this line. */ 1193228753Smm parsed_kws = 0; 1194228753Smm r = parse_line(a, entry, mtree, mentry, &parsed_kws); 1195228753Smm 1196228753Smm if (mentry->full) { 1197228753Smm archive_entry_copy_pathname(entry, mentry->name); 1198228753Smm /* 1199228753Smm * "Full" entries are allowed to have multiple lines 1200228753Smm * and those lines aren't required to be adjacent. We 1201228753Smm * don't support multiple lines for "relative" entries 1202228753Smm * nor do we make any attempt to merge data from 1203228753Smm * separate "relative" and "full" entries. (Merging 1204228753Smm * "relative" and "full" entries would require dealing 1205228753Smm * with pathname canonicalization, which is a very 1206228753Smm * tricky subject.) 1207228753Smm */ 1208337351Smm mp = (struct mtree_entry *)__archive_rb_tree_find_node( 1209337351Smm &mtree->rbtree, mentry->name); 1210337351Smm for (; mp; mp = mp->next_dup) { 1211337351Smm if (mp->full && !mp->used) { 1212228753Smm /* Later lines override earlier ones. */ 1213228753Smm mp->used = 1; 1214337351Smm r1 = parse_line(a, entry, mtree, mp, &parsed_kws); 1215228753Smm if (r1 < r) 1216228753Smm r = r1; 1217228753Smm } 1218228753Smm } 1219228753Smm } else { 1220228753Smm /* 1221228753Smm * Relative entries require us to construct 1222228753Smm * the full path and possibly update the 1223228753Smm * current directory. 1224228753Smm */ 1225228753Smm size_t n = archive_strlen(&mtree->current_dir); 1226228753Smm if (n > 0) 1227228753Smm archive_strcat(&mtree->current_dir, "/"); 1228228753Smm archive_strcat(&mtree->current_dir, mentry->name); 1229228753Smm archive_entry_copy_pathname(entry, mtree->current_dir.s); 1230228753Smm if (archive_entry_filetype(entry) != AE_IFDIR) 1231228753Smm mtree->current_dir.length = n; 1232228753Smm } 1233228753Smm 1234299529Smm if (mtree->checkfs) { 1235299529Smm /* 1236299529Smm * Try to open and stat the file to get the real size 1237299529Smm * and other file info. It would be nice to avoid 1238299529Smm * this here so that getting a listing of an mtree 1239299529Smm * wouldn't require opening every referenced contents 1240299529Smm * file. But then we wouldn't know the actual 1241299529Smm * contents size, so I don't see a really viable way 1242299529Smm * around this. (Also, we may want to someday pull 1243299529Smm * other unspecified info from the contents file on 1244299529Smm * disk.) 1245299529Smm */ 1246299529Smm mtree->fd = -1; 1247299529Smm if (archive_strlen(&mtree->contents_name) > 0) 1248299529Smm path = mtree->contents_name.s; 1249299529Smm else 1250299529Smm path = archive_entry_pathname(entry); 1251228753Smm 1252299529Smm if (archive_entry_filetype(entry) == AE_IFREG || 1253299529Smm archive_entry_filetype(entry) == AE_IFDIR) { 1254299529Smm mtree->fd = open(path, O_RDONLY | O_BINARY | O_CLOEXEC); 1255299529Smm __archive_ensure_cloexec_flag(mtree->fd); 1256299529Smm if (mtree->fd == -1 && 1257299529Smm (errno != ENOENT || 1258299529Smm archive_strlen(&mtree->contents_name) > 0)) { 1259299529Smm archive_set_error(&a->archive, errno, 1260299529Smm "Can't open %s", path); 1261299529Smm r = ARCHIVE_WARN; 1262299529Smm } 1263228753Smm } 1264228753Smm 1265299529Smm st = &st_storage; 1266299529Smm if (mtree->fd >= 0) { 1267299529Smm if (fstat(mtree->fd, st) == -1) { 1268299529Smm archive_set_error(&a->archive, errno, 1269299529Smm "Could not fstat %s", path); 1270299529Smm r = ARCHIVE_WARN; 1271299529Smm /* If we can't stat it, don't keep it open. */ 1272299529Smm close(mtree->fd); 1273299529Smm mtree->fd = -1; 1274299529Smm st = NULL; 1275299529Smm } 1276299529Smm } else if (lstat(path, st) == -1) { 1277228753Smm st = NULL; 1278228753Smm } 1279228753Smm 1280299529Smm /* 1281299529Smm * Check for a mismatch between the type in the specification 1282299529Smm * and the type of the contents object on disk. 1283299529Smm */ 1284299529Smm if (st != NULL) { 1285299529Smm if (((st->st_mode & S_IFMT) == S_IFREG && 1286299529Smm archive_entry_filetype(entry) == AE_IFREG) 1287232153Smm#ifdef S_IFLNK 1288299529Smm ||((st->st_mode & S_IFMT) == S_IFLNK && 1289299529Smm archive_entry_filetype(entry) == AE_IFLNK) 1290232153Smm#endif 1291232153Smm#ifdef S_IFSOCK 1292299529Smm ||((st->st_mode & S_IFSOCK) == S_IFSOCK && 1293299529Smm archive_entry_filetype(entry) == AE_IFSOCK) 1294232153Smm#endif 1295232153Smm#ifdef S_IFCHR 1296299529Smm ||((st->st_mode & S_IFMT) == S_IFCHR && 1297299529Smm archive_entry_filetype(entry) == AE_IFCHR) 1298232153Smm#endif 1299232153Smm#ifdef S_IFBLK 1300299529Smm ||((st->st_mode & S_IFMT) == S_IFBLK && 1301299529Smm archive_entry_filetype(entry) == AE_IFBLK) 1302232153Smm#endif 1303299529Smm ||((st->st_mode & S_IFMT) == S_IFDIR && 1304299529Smm archive_entry_filetype(entry) == AE_IFDIR) 1305232153Smm#ifdef S_IFIFO 1306299529Smm ||((st->st_mode & S_IFMT) == S_IFIFO && 1307299529Smm archive_entry_filetype(entry) == AE_IFIFO) 1308232153Smm#endif 1309299529Smm ) { 1310299529Smm /* Types match. */ 1311299529Smm } else { 1312299529Smm /* Types don't match; bail out gracefully. */ 1313299529Smm if (mtree->fd >= 0) 1314299529Smm close(mtree->fd); 1315299529Smm mtree->fd = -1; 1316299529Smm if (parsed_kws & MTREE_HAS_OPTIONAL) { 1317299529Smm /* It's not an error for an optional 1318299529Smm * entry to not match disk. */ 1319299529Smm *use_next = 1; 1320299529Smm } else if (r == ARCHIVE_OK) { 1321299529Smm archive_set_error(&a->archive, 1322299529Smm ARCHIVE_ERRNO_MISC, 1323299529Smm "mtree specification has different" 1324299529Smm " type for %s", 1325299529Smm archive_entry_pathname(entry)); 1326299529Smm r = ARCHIVE_WARN; 1327299529Smm } 1328299529Smm return (r); 1329228753Smm } 1330228753Smm } 1331228753Smm 1332299529Smm /* 1333299529Smm * If there is a contents file on disk, pick some of the 1334299529Smm * metadata from that file. For most of these, we only 1335299529Smm * set it from the contents if it wasn't already parsed 1336299529Smm * from the specification. 1337299529Smm */ 1338299529Smm if (st != NULL) { 1339299529Smm if (((parsed_kws & MTREE_HAS_DEVICE) == 0 || 1340299529Smm (parsed_kws & MTREE_HAS_NOCHANGE) != 0) && 1341299529Smm (archive_entry_filetype(entry) == AE_IFCHR || 1342299529Smm archive_entry_filetype(entry) == AE_IFBLK)) 1343299529Smm archive_entry_set_rdev(entry, st->st_rdev); 1344299529Smm if ((parsed_kws & (MTREE_HAS_GID | MTREE_HAS_GNAME)) 1345299529Smm == 0 || 1346299529Smm (parsed_kws & MTREE_HAS_NOCHANGE) != 0) 1347299529Smm archive_entry_set_gid(entry, st->st_gid); 1348299529Smm if ((parsed_kws & (MTREE_HAS_UID | MTREE_HAS_UNAME)) 1349299529Smm == 0 || 1350299529Smm (parsed_kws & MTREE_HAS_NOCHANGE) != 0) 1351299529Smm archive_entry_set_uid(entry, st->st_uid); 1352299529Smm if ((parsed_kws & MTREE_HAS_MTIME) == 0 || 1353299529Smm (parsed_kws & MTREE_HAS_NOCHANGE) != 0) { 1354228753Smm#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1355299529Smm archive_entry_set_mtime(entry, st->st_mtime, 1356299529Smm st->st_mtimespec.tv_nsec); 1357228753Smm#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1358299529Smm archive_entry_set_mtime(entry, st->st_mtime, 1359299529Smm st->st_mtim.tv_nsec); 1360228753Smm#elif HAVE_STRUCT_STAT_ST_MTIME_N 1361299529Smm archive_entry_set_mtime(entry, st->st_mtime, 1362299529Smm st->st_mtime_n); 1363228753Smm#elif HAVE_STRUCT_STAT_ST_UMTIME 1364299529Smm archive_entry_set_mtime(entry, st->st_mtime, 1365299529Smm st->st_umtime*1000); 1366228753Smm#elif HAVE_STRUCT_STAT_ST_MTIME_USEC 1367299529Smm archive_entry_set_mtime(entry, st->st_mtime, 1368299529Smm st->st_mtime_usec*1000); 1369228753Smm#else 1370299529Smm archive_entry_set_mtime(entry, st->st_mtime, 0); 1371228753Smm#endif 1372299529Smm } 1373299529Smm if ((parsed_kws & MTREE_HAS_NLINK) == 0 || 1374299529Smm (parsed_kws & MTREE_HAS_NOCHANGE) != 0) 1375299529Smm archive_entry_set_nlink(entry, st->st_nlink); 1376299529Smm if ((parsed_kws & MTREE_HAS_PERM) == 0 || 1377299529Smm (parsed_kws & MTREE_HAS_NOCHANGE) != 0) 1378299529Smm archive_entry_set_perm(entry, st->st_mode); 1379299529Smm if ((parsed_kws & MTREE_HAS_SIZE) == 0 || 1380299529Smm (parsed_kws & MTREE_HAS_NOCHANGE) != 0) 1381299529Smm archive_entry_set_size(entry, st->st_size); 1382299529Smm archive_entry_set_ino(entry, st->st_ino); 1383299529Smm archive_entry_set_dev(entry, st->st_dev); 1384299529Smm 1385299529Smm archive_entry_linkify(mtree->resolver, &entry, 1386299529Smm &sparse_entry); 1387299529Smm } else if (parsed_kws & MTREE_HAS_OPTIONAL) { 1388299529Smm /* 1389299529Smm * Couldn't open the entry, stat it or the on-disk type 1390299529Smm * didn't match. If this entry is optional, just 1391299529Smm * ignore it and read the next header entry. 1392299529Smm */ 1393299529Smm *use_next = 1; 1394299529Smm return ARCHIVE_OK; 1395228753Smm } 1396228753Smm } 1397228753Smm 1398228753Smm mtree->cur_size = archive_entry_size(entry); 1399228753Smm mtree->offset = 0; 1400228753Smm 1401228753Smm return r; 1402228753Smm} 1403228753Smm 1404228753Smm/* 1405228753Smm * Each line contains a sequence of keywords. 1406228753Smm */ 1407228753Smmstatic int 1408228753Smmparse_line(struct archive_read *a, struct archive_entry *entry, 1409228753Smm struct mtree *mtree, struct mtree_entry *mp, int *parsed_kws) 1410228753Smm{ 1411228753Smm struct mtree_option *iter; 1412228753Smm int r = ARCHIVE_OK, r1; 1413228753Smm 1414228753Smm for (iter = mp->options; iter != NULL; iter = iter->next) { 1415228753Smm r1 = parse_keyword(a, mtree, entry, iter, parsed_kws); 1416228753Smm if (r1 < r) 1417228753Smm r = r1; 1418228753Smm } 1419232153Smm if (r == ARCHIVE_OK && (*parsed_kws & MTREE_HAS_TYPE) == 0) { 1420228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 1421228753Smm "Missing type keyword in mtree specification"); 1422228753Smm return (ARCHIVE_WARN); 1423228753Smm } 1424228753Smm return (r); 1425228753Smm} 1426228753Smm 1427228753Smm/* 1428228753Smm * Device entries have one of the following forms: 1429299529Smm * - raw dev_t 1430299529Smm * - format,major,minor[,subdevice] 1431299529Smm * When parsing succeeded, `pdev' will contain the appropriate dev_t value. 1432228753Smm */ 1433299529Smm 1434299529Smm/* strsep() is not in C90, but strcspn() is. */ 1435299529Smm/* Taken from http://unixpapa.com/incnote/string.html */ 1436299529Smmstatic char * 1437299529Smmla_strsep(char **sp, const char *sep) 1438299529Smm{ 1439299529Smm char *p, *s; 1440299529Smm if (sp == NULL || *sp == NULL || **sp == '\0') 1441299529Smm return(NULL); 1442299529Smm s = *sp; 1443299529Smm p = s + strcspn(s, sep); 1444299529Smm if (*p != '\0') 1445299529Smm *p++ = '\0'; 1446299529Smm *sp = p; 1447299529Smm return(s); 1448299529Smm} 1449299529Smm 1450228753Smmstatic int 1451299529Smmparse_device(dev_t *pdev, struct archive *a, char *val) 1452228753Smm{ 1453299529Smm#define MAX_PACK_ARGS 3 1454299529Smm unsigned long numbers[MAX_PACK_ARGS]; 1455299529Smm char *p, *dev; 1456299529Smm int argc; 1457299529Smm pack_t *pack; 1458299529Smm dev_t result; 1459299529Smm const char *error = NULL; 1460228753Smm 1461299529Smm memset(pdev, 0, sizeof(*pdev)); 1462299529Smm if ((dev = strchr(val, ',')) != NULL) { 1463299529Smm /* 1464299529Smm * Device's major/minor are given in a specified format. 1465299529Smm * Decode and pack it accordingly. 1466299529Smm */ 1467299529Smm *dev++ = '\0'; 1468299529Smm if ((pack = pack_find(val)) == NULL) { 1469299529Smm archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, 1470299529Smm "Unknown format `%s'", val); 1471299529Smm return ARCHIVE_WARN; 1472299529Smm } 1473299529Smm argc = 0; 1474299529Smm while ((p = la_strsep(&dev, ",")) != NULL) { 1475299529Smm if (*p == '\0') { 1476299529Smm archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, 1477299529Smm "Missing number"); 1478299529Smm return ARCHIVE_WARN; 1479299529Smm } 1480302075Smm if (argc >= MAX_PACK_ARGS) { 1481299529Smm archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, 1482299529Smm "Too many arguments"); 1483299529Smm return ARCHIVE_WARN; 1484299529Smm } 1485318482Smm numbers[argc++] = (unsigned long)mtree_atol(&p, 0); 1486299529Smm } 1487299529Smm if (argc < 2) { 1488299529Smm archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, 1489299529Smm "Not enough arguments"); 1490299529Smm return ARCHIVE_WARN; 1491299529Smm } 1492299529Smm result = (*pack)(argc, numbers, &error); 1493299529Smm if (error != NULL) { 1494299529Smm archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, 1495299529Smm "%s", error); 1496299529Smm return ARCHIVE_WARN; 1497299529Smm } 1498299529Smm } else { 1499299529Smm /* file system raw value. */ 1500318482Smm result = (dev_t)mtree_atol(&val, 0); 1501228753Smm } 1502299529Smm *pdev = result; 1503299529Smm return ARCHIVE_OK; 1504299529Smm#undef MAX_PACK_ARGS 1505228753Smm} 1506228753Smm 1507368707Smmstatic int 1508368707Smmparse_hex_nibble(char c) 1509368707Smm{ 1510368707Smm if (c >= '0' && c <= '9') 1511368707Smm return c - '0'; 1512368707Smm if (c >= 'a' && c <= 'f') 1513368707Smm return 10 + c - 'a'; 1514368707Smm#if 0 1515368707Smm /* XXX: Is uppercase something we should support? */ 1516368707Smm if (c >= 'A' && c <= 'F') 1517368707Smm return 10 + c - 'A'; 1518368707Smm#endif 1519368707Smm 1520368707Smm return -1; 1521368707Smm} 1522368707Smm 1523368707Smmstatic int 1524368707Smmparse_digest(struct archive_read *a, struct archive_entry *entry, 1525368707Smm const char *digest, int type) 1526368707Smm{ 1527368707Smm unsigned char digest_buf[64]; 1528368707Smm int high, low; 1529368707Smm size_t i, j, len; 1530368707Smm 1531368707Smm switch (type) { 1532368707Smm case ARCHIVE_ENTRY_DIGEST_MD5: 1533368707Smm len = sizeof(entry->digest.md5); 1534368707Smm break; 1535368707Smm case ARCHIVE_ENTRY_DIGEST_RMD160: 1536368707Smm len = sizeof(entry->digest.rmd160); 1537368707Smm break; 1538368707Smm case ARCHIVE_ENTRY_DIGEST_SHA1: 1539368707Smm len = sizeof(entry->digest.sha1); 1540368707Smm break; 1541368707Smm case ARCHIVE_ENTRY_DIGEST_SHA256: 1542368707Smm len = sizeof(entry->digest.sha256); 1543368707Smm break; 1544368707Smm case ARCHIVE_ENTRY_DIGEST_SHA384: 1545368707Smm len = sizeof(entry->digest.sha384); 1546368707Smm break; 1547368707Smm case ARCHIVE_ENTRY_DIGEST_SHA512: 1548368707Smm len = sizeof(entry->digest.sha512); 1549368707Smm break; 1550368707Smm default: 1551368707Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, 1552368707Smm "Internal error: Unknown digest type"); 1553368707Smm return ARCHIVE_FATAL; 1554368707Smm } 1555368707Smm 1556368707Smm if (len > sizeof(digest_buf)) { 1557368707Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, 1558368707Smm "Internal error: Digest storage too large"); 1559368707Smm return ARCHIVE_FATAL; 1560368707Smm } 1561368707Smm 1562368707Smm len *= 2; 1563368707Smm 1564368707Smm if (mtree_strnlen(digest, len+1) != len) { 1565368707Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 1566368707Smm "incorrect digest length, ignoring"); 1567368707Smm return ARCHIVE_WARN; 1568368707Smm } 1569368707Smm 1570368707Smm for (i = 0, j = 0; i < len; i += 2, j++) { 1571368707Smm high = parse_hex_nibble(digest[i]); 1572368707Smm low = parse_hex_nibble(digest[i+1]); 1573368707Smm if (high == -1 || low == -1) { 1574368707Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 1575368707Smm "invalid digest data, ignoring"); 1576368707Smm return ARCHIVE_WARN; 1577368707Smm } 1578368707Smm 1579368707Smm digest_buf[j] = high << 4 | low; 1580368707Smm } 1581368707Smm 1582368707Smm return archive_entry_set_digest(entry, type, digest_buf); 1583368707Smm} 1584368707Smm 1585228753Smm/* 1586228753Smm * Parse a single keyword and its value. 1587228753Smm */ 1588228753Smmstatic int 1589228753Smmparse_keyword(struct archive_read *a, struct mtree *mtree, 1590232153Smm struct archive_entry *entry, struct mtree_option *opt, int *parsed_kws) 1591228753Smm{ 1592228753Smm char *val, *key; 1593228753Smm 1594232153Smm key = opt->value; 1595228753Smm 1596228753Smm if (*key == '\0') 1597228753Smm return (ARCHIVE_OK); 1598228753Smm 1599248616Smm if (strcmp(key, "nochange") == 0) { 1600248616Smm *parsed_kws |= MTREE_HAS_NOCHANGE; 1601248616Smm return (ARCHIVE_OK); 1602248616Smm } 1603228753Smm if (strcmp(key, "optional") == 0) { 1604228753Smm *parsed_kws |= MTREE_HAS_OPTIONAL; 1605228753Smm return (ARCHIVE_OK); 1606228753Smm } 1607228753Smm if (strcmp(key, "ignore") == 0) { 1608228753Smm /* 1609228753Smm * The mtree processing is not recursive, so 1610228753Smm * recursion will only happen for explicitly listed 1611228753Smm * entries. 1612228753Smm */ 1613228753Smm return (ARCHIVE_OK); 1614228753Smm } 1615228753Smm 1616228753Smm val = strchr(key, '='); 1617228753Smm if (val == NULL) { 1618228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 1619228753Smm "Malformed attribute \"%s\" (%d)", key, key[0]); 1620228753Smm return (ARCHIVE_WARN); 1621228753Smm } 1622228753Smm 1623228753Smm *val = '\0'; 1624228753Smm ++val; 1625228753Smm 1626228753Smm switch (key[0]) { 1627228753Smm case 'c': 1628228753Smm if (strcmp(key, "content") == 0 1629228753Smm || strcmp(key, "contents") == 0) { 1630228753Smm parse_escapes(val, NULL); 1631228753Smm archive_strcpy(&mtree->contents_name, val); 1632228753Smm break; 1633228753Smm } 1634228753Smm if (strcmp(key, "cksum") == 0) 1635228753Smm break; 1636328827Smm __LA_FALLTHROUGH; 1637228753Smm case 'd': 1638228753Smm if (strcmp(key, "device") == 0) { 1639299529Smm /* stat(2) st_rdev field, e.g. the major/minor IDs 1640299529Smm * of a char/block special file */ 1641299529Smm int r; 1642299529Smm dev_t dev; 1643299529Smm 1644228753Smm *parsed_kws |= MTREE_HAS_DEVICE; 1645299529Smm r = parse_device(&dev, &a->archive, val); 1646299529Smm if (r == ARCHIVE_OK) 1647299529Smm archive_entry_set_rdev(entry, dev); 1648299529Smm return r; 1649228753Smm } 1650328827Smm __LA_FALLTHROUGH; 1651228753Smm case 'f': 1652228753Smm if (strcmp(key, "flags") == 0) { 1653228753Smm *parsed_kws |= MTREE_HAS_FFLAGS; 1654228753Smm archive_entry_copy_fflags_text(entry, val); 1655228753Smm break; 1656228753Smm } 1657328827Smm __LA_FALLTHROUGH; 1658228753Smm case 'g': 1659228753Smm if (strcmp(key, "gid") == 0) { 1660228753Smm *parsed_kws |= MTREE_HAS_GID; 1661318482Smm archive_entry_set_gid(entry, mtree_atol(&val, 10)); 1662228753Smm break; 1663228753Smm } 1664228753Smm if (strcmp(key, "gname") == 0) { 1665228753Smm *parsed_kws |= MTREE_HAS_GNAME; 1666228753Smm archive_entry_copy_gname(entry, val); 1667228753Smm break; 1668228753Smm } 1669328827Smm __LA_FALLTHROUGH; 1670299529Smm case 'i': 1671299529Smm if (strcmp(key, "inode") == 0) { 1672318482Smm archive_entry_set_ino(entry, mtree_atol(&val, 10)); 1673299529Smm break; 1674299529Smm } 1675328827Smm __LA_FALLTHROUGH; 1676228753Smm case 'l': 1677228753Smm if (strcmp(key, "link") == 0) { 1678228753Smm archive_entry_copy_symlink(entry, val); 1679228753Smm break; 1680228753Smm } 1681328827Smm __LA_FALLTHROUGH; 1682228753Smm case 'm': 1683368707Smm if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0) { 1684368707Smm return parse_digest(a, entry, val, 1685368707Smm ARCHIVE_ENTRY_DIGEST_MD5); 1686368707Smm } 1687228753Smm if (strcmp(key, "mode") == 0) { 1688318482Smm if (val[0] >= '0' && val[0] <= '7') { 1689228753Smm *parsed_kws |= MTREE_HAS_PERM; 1690228753Smm archive_entry_set_perm(entry, 1691318482Smm (mode_t)mtree_atol(&val, 8)); 1692228753Smm } else { 1693228753Smm archive_set_error(&a->archive, 1694228753Smm ARCHIVE_ERRNO_FILE_FORMAT, 1695318482Smm "Symbolic or non-octal mode \"%s\" unsupported", val); 1696228753Smm return ARCHIVE_WARN; 1697228753Smm } 1698228753Smm break; 1699228753Smm } 1700328827Smm __LA_FALLTHROUGH; 1701228753Smm case 'n': 1702228753Smm if (strcmp(key, "nlink") == 0) { 1703228753Smm *parsed_kws |= MTREE_HAS_NLINK; 1704238856Smm archive_entry_set_nlink(entry, 1705318482Smm (unsigned int)mtree_atol(&val, 10)); 1706228753Smm break; 1707228753Smm } 1708328827Smm __LA_FALLTHROUGH; 1709228753Smm case 'r': 1710299529Smm if (strcmp(key, "resdevice") == 0) { 1711299529Smm /* stat(2) st_dev field, e.g. the device ID where the 1712299529Smm * inode resides */ 1713299529Smm int r; 1714299529Smm dev_t dev; 1715299529Smm 1716299529Smm r = parse_device(&dev, &a->archive, val); 1717299529Smm if (r == ARCHIVE_OK) 1718299529Smm archive_entry_set_dev(entry, dev); 1719299529Smm return r; 1720299529Smm } 1721228753Smm if (strcmp(key, "rmd160") == 0 || 1722368707Smm strcmp(key, "rmd160digest") == 0) { 1723368707Smm return parse_digest(a, entry, val, 1724368707Smm ARCHIVE_ENTRY_DIGEST_RMD160); 1725368707Smm } 1726328827Smm __LA_FALLTHROUGH; 1727228753Smm case 's': 1728368707Smm if (strcmp(key, "sha1") == 0 || 1729368707Smm strcmp(key, "sha1digest") == 0) { 1730368707Smm return parse_digest(a, entry, val, 1731368707Smm ARCHIVE_ENTRY_DIGEST_SHA1); 1732368707Smm } 1733228753Smm if (strcmp(key, "sha256") == 0 || 1734368707Smm strcmp(key, "sha256digest") == 0) { 1735368707Smm return parse_digest(a, entry, val, 1736368707Smm ARCHIVE_ENTRY_DIGEST_SHA256); 1737368707Smm } 1738228753Smm if (strcmp(key, "sha384") == 0 || 1739368707Smm strcmp(key, "sha384digest") == 0) { 1740368707Smm return parse_digest(a, entry, val, 1741368707Smm ARCHIVE_ENTRY_DIGEST_SHA384); 1742368707Smm } 1743228753Smm if (strcmp(key, "sha512") == 0 || 1744368707Smm strcmp(key, "sha512digest") == 0) { 1745368707Smm return parse_digest(a, entry, val, 1746368707Smm ARCHIVE_ENTRY_DIGEST_SHA512); 1747368707Smm } 1748228753Smm if (strcmp(key, "size") == 0) { 1749318482Smm archive_entry_set_size(entry, mtree_atol(&val, 10)); 1750228753Smm break; 1751228753Smm } 1752328827Smm __LA_FALLTHROUGH; 1753228753Smm case 't': 1754228753Smm if (strcmp(key, "tags") == 0) { 1755228753Smm /* 1756228753Smm * Comma delimited list of tags. 1757228753Smm * Ignore the tags for now, but the interface 1758228753Smm * should be extended to allow inclusion/exclusion. 1759228753Smm */ 1760228753Smm break; 1761228753Smm } 1762228753Smm if (strcmp(key, "time") == 0) { 1763232153Smm int64_t m; 1764232153Smm int64_t my_time_t_max = get_time_t_max(); 1765232153Smm int64_t my_time_t_min = get_time_t_min(); 1766299529Smm long ns = 0; 1767228753Smm 1768228753Smm *parsed_kws |= MTREE_HAS_MTIME; 1769318482Smm m = mtree_atol(&val, 10); 1770232153Smm /* Replicate an old mtree bug: 1771232153Smm * 123456789.1 represents 123456789 1772232153Smm * seconds and 1 nanosecond. */ 1773228753Smm if (*val == '.') { 1774228753Smm ++val; 1775318482Smm ns = (long)mtree_atol(&val, 10); 1776313926Smm if (ns < 0) 1777313926Smm ns = 0; 1778313926Smm else if (ns > 999999999) 1779313926Smm ns = 999999999; 1780313926Smm } 1781232153Smm if (m > my_time_t_max) 1782232153Smm m = my_time_t_max; 1783232153Smm else if (m < my_time_t_min) 1784232153Smm m = my_time_t_min; 1785232153Smm archive_entry_set_mtime(entry, (time_t)m, ns); 1786228753Smm break; 1787228753Smm } 1788228753Smm if (strcmp(key, "type") == 0) { 1789228753Smm switch (val[0]) { 1790228753Smm case 'b': 1791228753Smm if (strcmp(val, "block") == 0) { 1792232153Smm archive_entry_set_filetype(entry, AE_IFBLK); 1793228753Smm break; 1794228753Smm } 1795328827Smm __LA_FALLTHROUGH; 1796228753Smm case 'c': 1797228753Smm if (strcmp(val, "char") == 0) { 1798299529Smm archive_entry_set_filetype(entry, 1799299529Smm AE_IFCHR); 1800228753Smm break; 1801228753Smm } 1802328827Smm __LA_FALLTHROUGH; 1803228753Smm case 'd': 1804228753Smm if (strcmp(val, "dir") == 0) { 1805299529Smm archive_entry_set_filetype(entry, 1806299529Smm AE_IFDIR); 1807228753Smm break; 1808228753Smm } 1809328827Smm __LA_FALLTHROUGH; 1810228753Smm case 'f': 1811228753Smm if (strcmp(val, "fifo") == 0) { 1812299529Smm archive_entry_set_filetype(entry, 1813299529Smm AE_IFIFO); 1814228753Smm break; 1815228753Smm } 1816228753Smm if (strcmp(val, "file") == 0) { 1817299529Smm archive_entry_set_filetype(entry, 1818299529Smm AE_IFREG); 1819228753Smm break; 1820228753Smm } 1821328827Smm __LA_FALLTHROUGH; 1822228753Smm case 'l': 1823228753Smm if (strcmp(val, "link") == 0) { 1824299529Smm archive_entry_set_filetype(entry, 1825299529Smm AE_IFLNK); 1826228753Smm break; 1827228753Smm } 1828328827Smm __LA_FALLTHROUGH; 1829228753Smm default: 1830228753Smm archive_set_error(&a->archive, 1831228753Smm ARCHIVE_ERRNO_FILE_FORMAT, 1832299529Smm "Unrecognized file type \"%s\"; " 1833299529Smm "assuming \"file\"", val); 1834232153Smm archive_entry_set_filetype(entry, AE_IFREG); 1835228753Smm return (ARCHIVE_WARN); 1836228753Smm } 1837232153Smm *parsed_kws |= MTREE_HAS_TYPE; 1838228753Smm break; 1839228753Smm } 1840328827Smm __LA_FALLTHROUGH; 1841228753Smm case 'u': 1842228753Smm if (strcmp(key, "uid") == 0) { 1843228753Smm *parsed_kws |= MTREE_HAS_UID; 1844318482Smm archive_entry_set_uid(entry, mtree_atol(&val, 10)); 1845228753Smm break; 1846228753Smm } 1847228753Smm if (strcmp(key, "uname") == 0) { 1848228753Smm *parsed_kws |= MTREE_HAS_UNAME; 1849228753Smm archive_entry_copy_uname(entry, val); 1850228753Smm break; 1851228753Smm } 1852328827Smm __LA_FALLTHROUGH; 1853228753Smm default: 1854228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 1855228753Smm "Unrecognized key %s=%s", key, val); 1856228753Smm return (ARCHIVE_WARN); 1857228753Smm } 1858228753Smm return (ARCHIVE_OK); 1859228753Smm} 1860228753Smm 1861228753Smmstatic int 1862299529Smmread_data(struct archive_read *a, const void **buff, size_t *size, 1863299529Smm int64_t *offset) 1864228753Smm{ 1865228753Smm size_t bytes_to_read; 1866228753Smm ssize_t bytes_read; 1867228753Smm struct mtree *mtree; 1868228753Smm 1869228753Smm mtree = (struct mtree *)(a->format->data); 1870228753Smm if (mtree->fd < 0) { 1871228753Smm *buff = NULL; 1872228753Smm *offset = 0; 1873228753Smm *size = 0; 1874228753Smm return (ARCHIVE_EOF); 1875228753Smm } 1876228753Smm if (mtree->buff == NULL) { 1877228753Smm mtree->buffsize = 64 * 1024; 1878228753Smm mtree->buff = malloc(mtree->buffsize); 1879228753Smm if (mtree->buff == NULL) { 1880228753Smm archive_set_error(&a->archive, ENOMEM, 1881228753Smm "Can't allocate memory"); 1882228753Smm return (ARCHIVE_FATAL); 1883228753Smm } 1884228753Smm } 1885228753Smm 1886228753Smm *buff = mtree->buff; 1887228753Smm *offset = mtree->offset; 1888232153Smm if ((int64_t)mtree->buffsize > mtree->cur_size - mtree->offset) 1889238856Smm bytes_to_read = (size_t)(mtree->cur_size - mtree->offset); 1890228753Smm else 1891228753Smm bytes_to_read = mtree->buffsize; 1892228753Smm bytes_read = read(mtree->fd, mtree->buff, bytes_to_read); 1893228753Smm if (bytes_read < 0) { 1894228753Smm archive_set_error(&a->archive, errno, "Can't read"); 1895228753Smm return (ARCHIVE_WARN); 1896228753Smm } 1897228753Smm if (bytes_read == 0) { 1898228753Smm *size = 0; 1899228753Smm return (ARCHIVE_EOF); 1900228753Smm } 1901228753Smm mtree->offset += bytes_read; 1902228753Smm *size = bytes_read; 1903228753Smm return (ARCHIVE_OK); 1904228753Smm} 1905228753Smm 1906228753Smm/* Skip does nothing except possibly close the contents file. */ 1907228753Smmstatic int 1908228753Smmskip(struct archive_read *a) 1909228753Smm{ 1910228753Smm struct mtree *mtree; 1911228753Smm 1912228753Smm mtree = (struct mtree *)(a->format->data); 1913228753Smm if (mtree->fd >= 0) { 1914228753Smm close(mtree->fd); 1915228753Smm mtree->fd = -1; 1916228753Smm } 1917228753Smm return (ARCHIVE_OK); 1918228753Smm} 1919228753Smm 1920228753Smm/* 1921228753Smm * Since parsing backslash sequences always makes strings shorter, 1922228753Smm * we can always do this conversion in-place. 1923228753Smm */ 1924228753Smmstatic void 1925228753Smmparse_escapes(char *src, struct mtree_entry *mentry) 1926228753Smm{ 1927228753Smm char *dest = src; 1928228753Smm char c; 1929228753Smm 1930228753Smm if (mentry != NULL && strcmp(src, ".") == 0) 1931228753Smm mentry->full = 1; 1932228753Smm 1933228753Smm while (*src != '\0') { 1934228753Smm c = *src++; 1935228753Smm if (c == '/' && mentry != NULL) 1936228753Smm mentry->full = 1; 1937228753Smm if (c == '\\') { 1938228753Smm switch (src[0]) { 1939228753Smm case '0': 1940228753Smm if (src[1] < '0' || src[1] > '7') { 1941228753Smm c = 0; 1942228753Smm ++src; 1943228753Smm break; 1944228753Smm } 1945228753Smm /* FALLTHROUGH */ 1946228753Smm case '1': 1947228753Smm case '2': 1948228753Smm case '3': 1949228753Smm if (src[1] >= '0' && src[1] <= '7' && 1950228753Smm src[2] >= '0' && src[2] <= '7') { 1951228753Smm c = (src[0] - '0') << 6; 1952228753Smm c |= (src[1] - '0') << 3; 1953228753Smm c |= (src[2] - '0'); 1954228753Smm src += 3; 1955228753Smm } 1956228753Smm break; 1957228753Smm case 'a': 1958228753Smm c = '\a'; 1959228753Smm ++src; 1960228753Smm break; 1961228753Smm case 'b': 1962228753Smm c = '\b'; 1963228753Smm ++src; 1964228753Smm break; 1965228753Smm case 'f': 1966228753Smm c = '\f'; 1967228753Smm ++src; 1968228753Smm break; 1969228753Smm case 'n': 1970228753Smm c = '\n'; 1971228753Smm ++src; 1972228753Smm break; 1973228753Smm case 'r': 1974228753Smm c = '\r'; 1975228753Smm ++src; 1976228753Smm break; 1977228753Smm case 's': 1978228753Smm c = ' '; 1979228753Smm ++src; 1980228753Smm break; 1981228753Smm case 't': 1982228753Smm c = '\t'; 1983228753Smm ++src; 1984228753Smm break; 1985228753Smm case 'v': 1986228753Smm c = '\v'; 1987228753Smm ++src; 1988228753Smm break; 1989299529Smm case '\\': 1990299529Smm c = '\\'; 1991299529Smm ++src; 1992299529Smm break; 1993228753Smm } 1994228753Smm } 1995228753Smm *dest++ = c; 1996228753Smm } 1997228753Smm *dest = '\0'; 1998228753Smm} 1999228753Smm 2000232153Smm/* Parse a hex digit. */ 2001232153Smmstatic int 2002318482Smmparsedigit(char c) 2003232153Smm{ 2004232153Smm if (c >= '0' && c <= '9') 2005232153Smm return c - '0'; 2006232153Smm else if (c >= 'a' && c <= 'f') 2007232153Smm return c - 'a'; 2008232153Smm else if (c >= 'A' && c <= 'F') 2009232153Smm return c - 'A'; 2010232153Smm else 2011232153Smm return -1; 2012232153Smm} 2013232153Smm 2014228753Smm/* 2015228753Smm * Note that this implementation does not (and should not!) obey 2016228753Smm * locale settings; you cannot simply substitute strtol here, since 2017228753Smm * it does obey locale. 2018228753Smm */ 2019228753Smmstatic int64_t 2020318482Smmmtree_atol(char **p, int base) 2021228753Smm{ 2022318482Smm int64_t l, limit; 2023318482Smm int digit, last_digit_limit; 2024228753Smm 2025318482Smm if (base == 0) { 2026318482Smm if (**p != '0') 2027318482Smm base = 10; 2028318482Smm else if ((*p)[1] == 'x' || (*p)[1] == 'X') { 2029318482Smm *p += 2; 2030318482Smm base = 16; 2031318482Smm } else { 2032318482Smm base = 8; 2033318482Smm } 2034318482Smm } 2035228753Smm 2036228753Smm if (**p == '-') { 2037318482Smm limit = INT64_MIN / base; 2038370535Sgit2svn last_digit_limit = -(INT64_MIN % base); 2039228753Smm ++(*p); 2040318482Smm 2041318482Smm l = 0; 2042318482Smm digit = parsedigit(**p); 2043318482Smm while (digit >= 0 && digit < base) { 2044370535Sgit2svn if (l < limit || (l == limit && digit >= last_digit_limit)) 2045318482Smm return INT64_MIN; 2046318482Smm l = (l * base) - digit; 2047318482Smm digit = parsedigit(*++(*p)); 2048318482Smm } 2049318482Smm return l; 2050232153Smm } else { 2051232153Smm limit = INT64_MAX / base; 2052232153Smm last_digit_limit = INT64_MAX % base; 2053228753Smm 2054318482Smm l = 0; 2055318482Smm digit = parsedigit(**p); 2056318482Smm while (digit >= 0 && digit < base) { 2057318482Smm if (l > limit || (l == limit && digit > last_digit_limit)) 2058318482Smm return INT64_MAX; 2059318482Smm l = (l * base) + digit; 2060318482Smm digit = parsedigit(*++(*p)); 2061318482Smm } 2062318482Smm return l; 2063228753Smm } 2064228753Smm} 2065228753Smm 2066228753Smm/* 2067228753Smm * Returns length of line (including trailing newline) 2068228753Smm * or negative on error. 'start' argument is updated to 2069228753Smm * point to first character of line. 2070228753Smm */ 2071228753Smmstatic ssize_t 2072299529Smmreadline(struct archive_read *a, struct mtree *mtree, char **start, 2073299529Smm ssize_t limit) 2074228753Smm{ 2075228753Smm ssize_t bytes_read; 2076228753Smm ssize_t total_size = 0; 2077228753Smm ssize_t find_off = 0; 2078228753Smm const void *t; 2079299529Smm void *nl; 2080228753Smm char *u; 2081228753Smm 2082228753Smm /* Accumulate line in a line buffer. */ 2083228753Smm for (;;) { 2084228753Smm /* Read some more. */ 2085228753Smm t = __archive_read_ahead(a, 1, &bytes_read); 2086228753Smm if (t == NULL) 2087228753Smm return (0); 2088228753Smm if (bytes_read < 0) 2089228753Smm return (ARCHIVE_FATAL); 2090299529Smm nl = memchr(t, '\n', bytes_read); 2091299529Smm /* If we found '\n', trim the read to end exactly there. */ 2092299529Smm if (nl != NULL) { 2093299529Smm bytes_read = ((const char *)nl) - ((const char *)t) + 1; 2094228753Smm } 2095228753Smm if (total_size + bytes_read + 1 > limit) { 2096228753Smm archive_set_error(&a->archive, 2097228753Smm ARCHIVE_ERRNO_FILE_FORMAT, 2098228753Smm "Line too long"); 2099228753Smm return (ARCHIVE_FATAL); 2100228753Smm } 2101228753Smm if (archive_string_ensure(&mtree->line, 2102228753Smm total_size + bytes_read + 1) == NULL) { 2103228753Smm archive_set_error(&a->archive, ENOMEM, 2104228753Smm "Can't allocate working buffer"); 2105228753Smm return (ARCHIVE_FATAL); 2106228753Smm } 2107299529Smm /* Append new bytes to string. */ 2108228753Smm memcpy(mtree->line.s + total_size, t, bytes_read); 2109228753Smm __archive_read_consume(a, bytes_read); 2110228753Smm total_size += bytes_read; 2111228753Smm mtree->line.s[total_size] = '\0'; 2112299529Smm 2113228753Smm for (u = mtree->line.s + find_off; *u; ++u) { 2114228753Smm if (u[0] == '\n') { 2115299529Smm /* Ends with unescaped newline. */ 2116228753Smm *start = mtree->line.s; 2117228753Smm return total_size; 2118299529Smm } else if (u[0] == '#') { 2119299529Smm /* Ends with comment sequence #...\n */ 2120299529Smm if (nl == NULL) { 2121299529Smm /* But we've not found the \n yet */ 2122228753Smm break; 2123299529Smm } 2124299529Smm } else if (u[0] == '\\') { 2125299529Smm if (u[1] == '\n') { 2126299529Smm /* Trim escaped newline. */ 2127299529Smm total_size -= 2; 2128299529Smm mtree->line.s[total_size] = '\0'; 2129299529Smm break; 2130299529Smm } else if (u[1] != '\0') { 2131299529Smm /* Skip the two-char escape sequence */ 2132299529Smm ++u; 2133299529Smm } 2134228753Smm } 2135228753Smm } 2136228753Smm find_off = u - mtree->line.s; 2137228753Smm } 2138228753Smm} 2139