1 /*- 2 * Copyright (c) 2003-2007 Tim Kientzle 3 * Copyright (c) 2008 Joerg Sonnenberger 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "archive_platform.h" 28 __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_mtree.c,v 1.11 2008/12/06 06:45:15 kientzle Exp $"); 29 30 #ifdef HAVE_SYS_STAT_H 31 #include <sys/stat.h> 32 #endif 33 #ifdef HAVE_ERRNO_H 34 #include <errno.h> 35 #endif 36 #ifdef HAVE_FCNTL_H 37 #include <fcntl.h> 38 #endif 39 #include <stddef.h> 40 /* #include <stdint.h> */ /* See archive_platform.h */ 41 #ifdef HAVE_STDLIB_H 42 #include <stdlib.h> 43 #endif 44 #ifdef HAVE_STRING_H 45 #include <string.h> 46 #endif 47 48 #include "archive.h" 49 #include "archive_entry.h" 50 #include "archive_private.h" 51 #include "archive_read_private.h" 52 #include "archive_string.h" 53 54 #ifndef O_BINARY 55 #define O_BINARY 0 56 #endif 57 58 #define MTREE_HAS_DEVICE 0x0001 59 #define MTREE_HAS_FFLAGS 0x0002 60 #define MTREE_HAS_GID 0x0004 61 #define MTREE_HAS_GNAME 0x0008 62 #define MTREE_HAS_MTIME 0x0010 63 #define MTREE_HAS_NLINK 0x0020 64 #define MTREE_HAS_PERM 0x0040 65 #define MTREE_HAS_SIZE 0x0080 66 #define MTREE_HAS_TYPE 0x0100 67 #define MTREE_HAS_UID 0x0200 68 #define MTREE_HAS_UNAME 0x0400 69 70 #define MTREE_HAS_OPTIONAL 0x0800 71 72 struct mtree_option { 73 struct mtree_option *next; 74 char *value; 75 }; 76 77 struct mtree_entry { 78 struct mtree_entry *next; 79 struct mtree_option *options; 80 char *name; 81 char full; 82 char used; 83 }; 84 85 struct mtree { 86 struct archive_string line; 87 size_t buffsize; 88 char *buff; 89 off_t offset; 90 int fd; 91 int filetype; 92 int archive_format; 93 const char *archive_format_name; 94 struct mtree_entry *entries; 95 struct mtree_entry *this_entry; 96 struct archive_string current_dir; 97 struct archive_string contents_name; 98 99 struct archive_entry_linkresolver *resolver; 100 101 off_t cur_size, cur_offset; 102 }; 103 104 static int cleanup(struct archive_read *); 105 static int mtree_bid(struct archive_read *); 106 static int parse_file(struct archive_read *, struct archive_entry *, 107 struct mtree *, struct mtree_entry *, int *); 108 static void parse_escapes(char *, struct mtree_entry *); 109 static int parse_line(struct archive_read *, struct archive_entry *, 110 struct mtree *, struct mtree_entry *, int *); 111 static int parse_keyword(struct archive_read *, struct mtree *, 112 struct archive_entry *, struct mtree_option *, int *); 113 static int read_data(struct archive_read *a, 114 const void **buff, size_t *size, off_t *offset); 115 static ssize_t readline(struct archive_read *, struct mtree *, char **, ssize_t); 116 static int skip(struct archive_read *a); 117 static int read_header(struct archive_read *, 118 struct archive_entry *); 119 static int64_t mtree_atol10(char **); 120 static int64_t mtree_atol8(char **); 121 static int64_t mtree_atol(char **); 122 123 static void 124 free_options(struct mtree_option *head) 125 { 126 struct mtree_option *next; 127 128 for (; head != NULL; head = next) { 129 next = head->next; 130 free(head->value); 131 free(head); 132 } 133 } 134 135 int 136 archive_read_support_format_mtree(struct archive *_a) 137 { 138 struct archive_read *a = (struct archive_read *)_a; 139 struct mtree *mtree; 140 int r; 141 142 mtree = (struct mtree *)malloc(sizeof(*mtree)); 143 if (mtree == NULL) { 144 archive_set_error(&a->archive, ENOMEM, 145 "Can't allocate mtree data"); 146 return (ARCHIVE_FATAL); 147 } 148 memset(mtree, 0, sizeof(*mtree)); 149 mtree->fd = -1; 150 151 r = __archive_read_register_format(a, mtree, "mtree", 152 mtree_bid, NULL, read_header, read_data, skip, cleanup); 153 154 if (r != ARCHIVE_OK) 155 free(mtree); 156 return (ARCHIVE_OK); 157 } 158 159 static int 160 cleanup(struct archive_read *a) 161 { 162 struct mtree *mtree; 163 struct mtree_entry *p, *q; 164 165 mtree = (struct mtree *)(a->format->data); 166 167 p = mtree->entries; 168 while (p != NULL) { 169 q = p->next; 170 free(p->name); 171 free_options(p->options); 172 free(p); 173 p = q; 174 } 175 archive_string_free(&mtree->line); 176 archive_string_free(&mtree->current_dir); 177 archive_string_free(&mtree->contents_name); 178 archive_entry_linkresolver_free(mtree->resolver); 179 180 free(mtree->buff); 181 free(mtree); 182 (a->format->data) = NULL; 183 return (ARCHIVE_OK); 184 } 185 186 187 static int 188 mtree_bid(struct archive_read *a) 189 { 190 const char *signature = "#mtree"; 191 const char *p; 192 193 /* Now let's look at the actual header and see if it matches. */ 194 p = __archive_read_ahead(a, strlen(signature), NULL); 195 if (p == NULL) 196 return (-1); 197 198 if (strncmp(p, signature, strlen(signature)) == 0) 199 return (8 * strlen(signature)); 200 return (0); 201 } 202 203 /* 204 * The extended mtree format permits multiple lines specifying 205 * attributes for each file. For those entries, only the last line 206 * is actually used. Practically speaking, that means we have 207 * to read the entire mtree file into memory up front. 208 * 209 * The parsing is done in two steps. First, it is decided if a line 210 * changes the global defaults and if it is, processed accordingly. 211 * Otherwise, the options of the line are merged with the current 212 * global options. 213 */ 214 static int 215 add_option(struct archive_read *a, struct mtree_option **global, 216 const char *value, size_t len) 217 { 218 struct mtree_option *option; 219 220 if ((option = malloc(sizeof(*option))) == NULL) { 221 archive_set_error(&a->archive, errno, "Can't allocate memory"); 222 return (ARCHIVE_FATAL); 223 } 224 if ((option->value = malloc(len + 1)) == NULL) { 225 free(option); 226 archive_set_error(&a->archive, errno, "Can't allocate memory"); 227 return (ARCHIVE_FATAL); 228 } 229 memcpy(option->value, value, len); 230 option->value[len] = '\0'; 231 option->next = *global; 232 *global = option; 233 return (ARCHIVE_OK); 234 } 235 236 static void 237 remove_option(struct mtree_option **global, const char *value, size_t len) 238 { 239 struct mtree_option *iter, *last; 240 241 last = NULL; 242 for (iter = *global; iter != NULL; last = iter, iter = iter->next) { 243 if (strncmp(iter->value, value, len) == 0 && 244 (iter->value[len] == '\0' || 245 iter->value[len] == '=')) 246 break; 247 } 248 if (iter == NULL) 249 return; 250 if (last == NULL) 251 *global = iter->next; 252 else 253 last->next = iter->next; 254 255 free(iter->value); 256 free(iter); 257 } 258 259 static int 260 process_global_set(struct archive_read *a, 261 struct mtree_option **global, const char *line) 262 { 263 const char *next, *eq; 264 size_t len; 265 int r; 266 267 line += 4; 268 for (;;) { 269 next = line + strspn(line, " \t\r\n"); 270 if (*next == '\0') 271 return (ARCHIVE_OK); 272 line = next; 273 next = line + strcspn(line, " \t\r\n"); 274 eq = strchr(line, '='); 275 if (eq > next) 276 len = next - line; 277 else 278 len = eq - line; 279 280 remove_option(global, line, len); 281 r = add_option(a, global, line, next - line); 282 if (r != ARCHIVE_OK) 283 return (r); 284 line = next; 285 } 286 } 287 288 static int 289 process_global_unset(struct archive_read *a, 290 struct mtree_option **global, const char *line) 291 { 292 const char *next; 293 size_t len; 294 295 line += 6; 296 if (strchr(line, '=') != NULL) { 297 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 298 "/unset shall not contain `='"); 299 return ARCHIVE_FATAL; 300 } 301 302 for (;;) { 303 next = line + strspn(line, " \t\r\n"); 304 if (*next == '\0') 305 return (ARCHIVE_OK); 306 line = next; 307 len = strcspn(line, " \t\r\n"); 308 309 if (len == 3 && strncmp(line, "all", 3) == 0) { 310 free_options(*global); 311 *global = NULL; 312 } else { 313 remove_option(global, line, len); 314 } 315 316 line += len; 317 } 318 } 319 320 static int 321 process_add_entry(struct archive_read *a, struct mtree *mtree, 322 struct mtree_option **global, const char *line, 323 struct mtree_entry **last_entry) 324 { 325 struct mtree_entry *entry; 326 struct mtree_option *iter; 327 const char *next, *eq; 328 size_t len; 329 int r; 330 331 if ((entry = malloc(sizeof(*entry))) == NULL) { 332 archive_set_error(&a->archive, errno, "Can't allocate memory"); 333 return (ARCHIVE_FATAL); 334 } 335 entry->next = NULL; 336 entry->options = NULL; 337 entry->name = NULL; 338 entry->used = 0; 339 entry->full = 0; 340 341 /* Add this entry to list. */ 342 if (*last_entry == NULL) 343 mtree->entries = entry; 344 else 345 (*last_entry)->next = entry; 346 *last_entry = entry; 347 348 len = strcspn(line, " \t\r\n"); 349 if ((entry->name = malloc(len + 1)) == NULL) { 350 archive_set_error(&a->archive, errno, "Can't allocate memory"); 351 return (ARCHIVE_FATAL); 352 } 353 354 memcpy(entry->name, line, len); 355 entry->name[len] = '\0'; 356 parse_escapes(entry->name, entry); 357 358 line += len; 359 for (iter = *global; iter != NULL; iter = iter->next) { 360 r = add_option(a, &entry->options, iter->value, 361 strlen(iter->value)); 362 if (r != ARCHIVE_OK) 363 return (r); 364 } 365 366 for (;;) { 367 next = line + strspn(line, " \t\r\n"); 368 if (*next == '\0') 369 return (ARCHIVE_OK); 370 line = next; 371 next = line + strcspn(line, " \t\r\n"); 372 eq = strchr(line, '='); 373 if (eq > next) 374 len = next - line; 375 else 376 len = eq - line; 377 378 remove_option(&entry->options, line, len); 379 r = add_option(a, &entry->options, line, next - line); 380 if (r != ARCHIVE_OK) 381 return (r); 382 line = next; 383 } 384 } 385 386 static int 387 read_mtree(struct archive_read *a, struct mtree *mtree) 388 { 389 ssize_t len; 390 uintmax_t counter; 391 char *p; 392 struct mtree_option *global; 393 struct mtree_entry *last_entry; 394 int r; 395 396 mtree->archive_format = ARCHIVE_FORMAT_MTREE; 397 mtree->archive_format_name = "mtree"; 398 399 global = NULL; 400 last_entry = NULL; 401 r = ARCHIVE_OK; 402 403 for (counter = 1; ; ++counter) { 404 len = readline(a, mtree, &p, 256); 405 if (len == 0) { 406 mtree->this_entry = mtree->entries; 407 free_options(global); 408 return (ARCHIVE_OK); 409 } 410 if (len < 0) { 411 free_options(global); 412 return (len); 413 } 414 /* Leading whitespace is never significant, ignore it. */ 415 while (*p == ' ' || *p == '\t') { 416 ++p; 417 --len; 418 } 419 /* Skip content lines and blank lines. */ 420 if (*p == '#') 421 continue; 422 if (*p == '\r' || *p == '\n' || *p == '\0') 423 continue; 424 if (*p != '/') { 425 r = process_add_entry(a, mtree, &global, p, 426 &last_entry); 427 } else if (strncmp(p, "/set", 4) == 0) { 428 if (p[4] != ' ' && p[4] != '\t') 429 break; 430 r = process_global_set(a, &global, p); 431 } else if (strncmp(p, "/unset", 6) == 0) { 432 if (p[6] != ' ' && p[6] != '\t') 433 break; 434 r = process_global_unset(a, &global, p); 435 } else 436 break; 437 438 if (r != ARCHIVE_OK) { 439 free_options(global); 440 return r; 441 } 442 } 443 444 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 445 "Can't parse line %ju", counter); 446 free_options(global); 447 return (ARCHIVE_FATAL); 448 } 449 450 /* 451 * Read in the entire mtree file into memory on the first request. 452 * Then use the next unused file to satisfy each header request. 453 */ 454 static int 455 read_header(struct archive_read *a, struct archive_entry *entry) 456 { 457 struct mtree *mtree; 458 char *p; 459 int r, use_next; 460 461 mtree = (struct mtree *)(a->format->data); 462 463 if (mtree->fd >= 0) { 464 close(mtree->fd); 465 mtree->fd = -1; 466 } 467 468 if (mtree->entries == NULL) { 469 mtree->resolver = archive_entry_linkresolver_new(); 470 if (mtree->resolver == NULL) 471 return ARCHIVE_FATAL; 472 archive_entry_linkresolver_set_strategy(mtree->resolver, 473 ARCHIVE_FORMAT_MTREE); 474 r = read_mtree(a, mtree); 475 if (r != ARCHIVE_OK) 476 return (r); 477 } 478 479 a->archive.archive_format = mtree->archive_format; 480 a->archive.archive_format_name = mtree->archive_format_name; 481 482 for (;;) { 483 if (mtree->this_entry == NULL) 484 return (ARCHIVE_EOF); 485 if (strcmp(mtree->this_entry->name, "..") == 0) { 486 mtree->this_entry->used = 1; 487 if (archive_strlen(&mtree->current_dir) > 0) { 488 /* Roll back current path. */ 489 p = mtree->current_dir.s 490 + mtree->current_dir.length - 1; 491 while (p >= mtree->current_dir.s && *p != '/') 492 --p; 493 if (p >= mtree->current_dir.s) 494 --p; 495 mtree->current_dir.length 496 = p - mtree->current_dir.s + 1; 497 } 498 } 499 if (!mtree->this_entry->used) { 500 use_next = 0; 501 r = parse_file(a, entry, mtree, mtree->this_entry, &use_next); 502 if (use_next == 0) 503 return (r); 504 } 505 mtree->this_entry = mtree->this_entry->next; 506 } 507 } 508 509 /* 510 * A single file can have multiple lines contribute specifications. 511 * Parse as many lines as necessary, then pull additional information 512 * from a backing file on disk as necessary. 513 */ 514 static int 515 parse_file(struct archive_read *a, struct archive_entry *entry, 516 struct mtree *mtree, struct mtree_entry *mentry, int *use_next) 517 { 518 const char *path; 519 struct stat st_storage, *st; 520 struct mtree_entry *mp; 521 struct archive_entry *sparse_entry; 522 int r = ARCHIVE_OK, r1, parsed_kws, mismatched_type; 523 524 mentry->used = 1; 525 526 /* Initialize reasonable defaults. */ 527 mtree->filetype = AE_IFREG; 528 archive_entry_set_size(entry, 0); 529 530 /* Parse options from this line. */ 531 parsed_kws = 0; 532 r = parse_line(a, entry, mtree, mentry, &parsed_kws); 533 534 if (mentry->full) { 535 archive_entry_copy_pathname(entry, mentry->name); 536 /* 537 * "Full" entries are allowed to have multiple lines 538 * and those lines aren't required to be adjacent. We 539 * don't support multiple lines for "relative" entries 540 * nor do we make any attempt to merge data from 541 * separate "relative" and "full" entries. (Merging 542 * "relative" and "full" entries would require dealing 543 * with pathname canonicalization, which is a very 544 * tricky subject.) 545 */ 546 for (mp = mentry->next; mp != NULL; mp = mp->next) { 547 if (mp->full && !mp->used 548 && strcmp(mentry->name, mp->name) == 0) { 549 /* Later lines override earlier ones. */ 550 mp->used = 1; 551 r1 = parse_line(a, entry, mtree, mp, 552 &parsed_kws); 553 if (r1 < r) 554 r = r1; 555 } 556 } 557 } else { 558 /* 559 * Relative entries require us to construct 560 * the full path and possibly update the 561 * current directory. 562 */ 563 size_t n = archive_strlen(&mtree->current_dir); 564 if (n > 0) 565 archive_strcat(&mtree->current_dir, "/"); 566 archive_strcat(&mtree->current_dir, mentry->name); 567 archive_entry_copy_pathname(entry, mtree->current_dir.s); 568 if (archive_entry_filetype(entry) != AE_IFDIR) 569 mtree->current_dir.length = n; 570 } 571 572 /* 573 * Try to open and stat the file to get the real size 574 * and other file info. It would be nice to avoid 575 * this here so that getting a listing of an mtree 576 * wouldn't require opening every referenced contents 577 * file. But then we wouldn't know the actual 578 * contents size, so I don't see a really viable way 579 * around this. (Also, we may want to someday pull 580 * other unspecified info from the contents file on 581 * disk.) 582 */ 583 mtree->fd = -1; 584 if (archive_strlen(&mtree->contents_name) > 0) 585 path = mtree->contents_name.s; 586 else 587 path = archive_entry_pathname(entry); 588 589 if (archive_entry_filetype(entry) == AE_IFREG || 590 archive_entry_filetype(entry) == AE_IFDIR) { 591 mtree->fd = open(path, 592 O_RDONLY | O_BINARY); 593 if (mtree->fd == -1 && 594 (errno != ENOENT || 595 archive_strlen(&mtree->contents_name) > 0)) { 596 archive_set_error(&a->archive, errno, 597 "Can't open %s", path); 598 r = ARCHIVE_WARN; 599 } 600 } 601 602 st = &st_storage; 603 if (mtree->fd >= 0) { 604 if (fstat(mtree->fd, st) == -1) { 605 archive_set_error(&a->archive, errno, 606 "Could not fstat %s", path); 607 r = ARCHIVE_WARN; 608 /* If we can't stat it, don't keep it open. */ 609 close(mtree->fd); 610 mtree->fd = -1; 611 st = NULL; 612 } 613 } else if (lstat(path, st) == -1) { 614 st = NULL; 615 } 616 617 /* 618 * If there is a contents file on disk, use that size; 619 * otherwise leave it as-is (it might have been set from 620 * the mtree size= keyword). 621 */ 622 if (st != NULL) { 623 mismatched_type = 0; 624 if ((st->st_mode & S_IFMT) == S_IFREG && 625 archive_entry_filetype(entry) != AE_IFREG) 626 mismatched_type = 1; 627 if ((st->st_mode & S_IFMT) == S_IFLNK && 628 archive_entry_filetype(entry) != AE_IFLNK) 629 mismatched_type = 1; 630 if ((st->st_mode & S_IFSOCK) == S_IFSOCK && 631 archive_entry_filetype(entry) != AE_IFSOCK) 632 mismatched_type = 1; 633 if ((st->st_mode & S_IFMT) == S_IFCHR && 634 archive_entry_filetype(entry) != AE_IFCHR) 635 mismatched_type = 1; 636 if ((st->st_mode & S_IFMT) == S_IFBLK && 637 archive_entry_filetype(entry) != AE_IFBLK) 638 mismatched_type = 1; 639 if ((st->st_mode & S_IFMT) == S_IFDIR && 640 archive_entry_filetype(entry) != AE_IFDIR) 641 mismatched_type = 1; 642 if ((st->st_mode & S_IFMT) == S_IFIFO && 643 archive_entry_filetype(entry) != AE_IFIFO) 644 mismatched_type = 1; 645 646 if (mismatched_type) { 647 if ((parsed_kws & MTREE_HAS_OPTIONAL) == 0) { 648 archive_set_error(&a->archive, 649 ARCHIVE_ERRNO_MISC, 650 "mtree specification has different type for %s", 651 archive_entry_pathname(entry)); 652 r = ARCHIVE_WARN; 653 } else { 654 *use_next = 1; 655 } 656 /* Don't hold a non-regular file open. */ 657 if (mtree->fd >= 0) 658 close(mtree->fd); 659 mtree->fd = -1; 660 st = NULL; 661 return r; 662 } 663 } 664 665 if (st != NULL) { 666 if ((parsed_kws & MTREE_HAS_DEVICE) == 0 && 667 (archive_entry_filetype(entry) == AE_IFCHR || 668 archive_entry_filetype(entry) == AE_IFBLK)) 669 archive_entry_set_rdev(entry, st->st_rdev); 670 if ((parsed_kws & (MTREE_HAS_GID | MTREE_HAS_GNAME)) == 0) 671 archive_entry_set_gid(entry, st->st_gid); 672 if ((parsed_kws & (MTREE_HAS_UID | MTREE_HAS_UNAME)) == 0) 673 archive_entry_set_uid(entry, st->st_uid); 674 if ((parsed_kws & MTREE_HAS_MTIME) == 0) { 675 #if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 676 archive_entry_set_mtime(entry, st->st_mtime, 677 st->st_mtimespec.tv_nsec); 678 #elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 679 archive_entry_set_mtime(entry, st->st_mtime, 680 st->st_mtim.tv_nsec); 681 #elif HAVE_STRUCT_STAT_ST_MTIME_N 682 archive_entry_set_mtime(entry, st->st_mtime, 683 st->st_mtime_n); 684 #elif HAVE_STRUCT_STAT_ST_UMTIME 685 archive_entry_set_mtime(entry, st->st_mtime, 686 st->st_umtime*1000); 687 #elif HAVE_STRUCT_STAT_ST_MTIME_USEC 688 archive_entry_set_mtime(entry, st->st_mtime, 689 st->st_mtime_usec*1000); 690 #else 691 archive_entry_set_mtime(entry, st->st_mtime, 0); 692 #endif 693 } 694 if ((parsed_kws & MTREE_HAS_NLINK) == 0) 695 archive_entry_set_nlink(entry, st->st_nlink); 696 if ((parsed_kws & MTREE_HAS_PERM) == 0) 697 archive_entry_set_perm(entry, st->st_mode); 698 if ((parsed_kws & MTREE_HAS_SIZE) == 0) 699 archive_entry_set_size(entry, st->st_size); 700 archive_entry_set_ino(entry, st->st_ino); 701 archive_entry_set_dev(entry, st->st_dev); 702 703 archive_entry_linkify(mtree->resolver, &entry, &sparse_entry); 704 } else if (parsed_kws & MTREE_HAS_OPTIONAL) { 705 /* 706 * Couldn't open the entry, stat it or the on-disk type 707 * didn't match. If this entry is optional, just ignore it 708 * and read the next header entry. 709 */ 710 *use_next = 1; 711 return ARCHIVE_OK; 712 } 713 714 mtree->cur_size = archive_entry_size(entry); 715 mtree->offset = 0; 716 717 return r; 718 } 719 720 /* 721 * Each line contains a sequence of keywords. 722 */ 723 static int 724 parse_line(struct archive_read *a, struct archive_entry *entry, 725 struct mtree *mtree, struct mtree_entry *mp, int *parsed_kws) 726 { 727 struct mtree_option *iter; 728 int r = ARCHIVE_OK, r1; 729 730 for (iter = mp->options; iter != NULL; iter = iter->next) { 731 r1 = parse_keyword(a, mtree, entry, iter, parsed_kws); 732 if (r1 < r) 733 r = r1; 734 } 735 if ((*parsed_kws & MTREE_HAS_TYPE) == 0) { 736 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 737 "Missing type keyword in mtree specification"); 738 return (ARCHIVE_WARN); 739 } 740 return (r); 741 } 742 743 /* 744 * Device entries have one of the following forms: 745 * raw dev_t 746 * format,major,minor[,subdevice] 747 * 748 * Just use major and minor, no translation etc is done 749 * between formats. 750 */ 751 static int 752 parse_device(struct archive *a, struct archive_entry *entry, char *val) 753 { 754 char *comma1, *comma2; 755 756 comma1 = strchr(val, ','); 757 if (comma1 == NULL) { 758 archive_entry_set_dev(entry, mtree_atol10(&val)); 759 return (ARCHIVE_OK); 760 } 761 ++comma1; 762 comma2 = strchr(comma1, ','); 763 if (comma2 == NULL) { 764 archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, 765 "Malformed device attribute"); 766 return (ARCHIVE_WARN); 767 } 768 ++comma2; 769 archive_entry_set_rdevmajor(entry, mtree_atol(&comma1)); 770 archive_entry_set_rdevminor(entry, mtree_atol(&comma2)); 771 return (ARCHIVE_OK); 772 } 773 774 /* 775 * Parse a single keyword and its value. 776 */ 777 static int 778 parse_keyword(struct archive_read *a, struct mtree *mtree, 779 struct archive_entry *entry, struct mtree_option *option, int *parsed_kws) 780 { 781 char *val, *key; 782 783 key = option->value; 784 785 if (*key == '\0') 786 return (ARCHIVE_OK); 787 788 if (strcmp(key, "optional") == 0) { 789 *parsed_kws |= MTREE_HAS_OPTIONAL; 790 return (ARCHIVE_OK); 791 } 792 if (strcmp(key, "ignore") == 0) { 793 /* 794 * The mtree processing is not recursive, so 795 * recursion will only happen for explicitly listed 796 * entries. 797 */ 798 return (ARCHIVE_OK); 799 } 800 801 val = strchr(key, '='); 802 if (val == NULL) { 803 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 804 "Malformed attribute \"%s\" (%d)", key, key[0]); 805 return (ARCHIVE_WARN); 806 } 807 808 *val = '\0'; 809 ++val; 810 811 switch (key[0]) { 812 case 'c': 813 if (strcmp(key, "content") == 0 814 || strcmp(key, "contents") == 0) { 815 parse_escapes(val, NULL); 816 archive_strcpy(&mtree->contents_name, val); 817 break; 818 } 819 if (strcmp(key, "cksum") == 0) 820 break; 821 case 'd': 822 if (strcmp(key, "device") == 0) { 823 *parsed_kws |= MTREE_HAS_DEVICE; 824 return parse_device(&a->archive, entry, val); 825 } 826 case 'f': 827 if (strcmp(key, "flags") == 0) { 828 *parsed_kws |= MTREE_HAS_FFLAGS; 829 archive_entry_copy_fflags_text(entry, val); 830 break; 831 } 832 case 'g': 833 if (strcmp(key, "gid") == 0) { 834 *parsed_kws |= MTREE_HAS_GID; 835 archive_entry_set_gid(entry, mtree_atol10(&val)); 836 break; 837 } 838 if (strcmp(key, "gname") == 0) { 839 *parsed_kws |= MTREE_HAS_GNAME; 840 archive_entry_copy_gname(entry, val); 841 break; 842 } 843 case 'l': 844 if (strcmp(key, "link") == 0) { 845 archive_entry_copy_symlink(entry, val); 846 break; 847 } 848 case 'm': 849 if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0) 850 break; 851 if (strcmp(key, "mode") == 0) { 852 if (val[0] >= '0' && val[0] <= '9') { 853 *parsed_kws |= MTREE_HAS_PERM; 854 archive_entry_set_perm(entry, 855 mtree_atol8(&val)); 856 } else { 857 archive_set_error(&a->archive, 858 ARCHIVE_ERRNO_FILE_FORMAT, 859 "Symbolic mode \"%s\" unsupported", val); 860 return ARCHIVE_WARN; 861 } 862 break; 863 } 864 case 'n': 865 if (strcmp(key, "nlink") == 0) { 866 *parsed_kws |= MTREE_HAS_NLINK; 867 archive_entry_set_nlink(entry, mtree_atol10(&val)); 868 break; 869 } 870 case 'r': 871 if (strcmp(key, "rmd160") == 0 || 872 strcmp(key, "rmd160digest") == 0) 873 break; 874 case 's': 875 if (strcmp(key, "sha1") == 0 || strcmp(key, "sha1digest") == 0) 876 break; 877 if (strcmp(key, "sha256") == 0 || 878 strcmp(key, "sha256digest") == 0) 879 break; 880 if (strcmp(key, "sha384") == 0 || 881 strcmp(key, "sha384digest") == 0) 882 break; 883 if (strcmp(key, "sha512") == 0 || 884 strcmp(key, "sha512digest") == 0) 885 break; 886 if (strcmp(key, "size") == 0) { 887 archive_entry_set_size(entry, mtree_atol10(&val)); 888 break; 889 } 890 case 't': 891 if (strcmp(key, "tags") == 0) { 892 /* 893 * Comma delimited list of tags. 894 * Ignore the tags for now, but the interface 895 * should be extended to allow inclusion/exclusion. 896 */ 897 break; 898 } 899 if (strcmp(key, "time") == 0) { 900 time_t m; 901 long ns; 902 903 *parsed_kws |= MTREE_HAS_MTIME; 904 m = (time_t)mtree_atol10(&val); 905 if (*val == '.') { 906 ++val; 907 ns = (long)mtree_atol10(&val); 908 } else 909 ns = 0; 910 archive_entry_set_mtime(entry, m, ns); 911 break; 912 } 913 if (strcmp(key, "type") == 0) { 914 *parsed_kws |= MTREE_HAS_TYPE; 915 switch (val[0]) { 916 case 'b': 917 if (strcmp(val, "block") == 0) { 918 mtree->filetype = AE_IFBLK; 919 break; 920 } 921 case 'c': 922 if (strcmp(val, "char") == 0) { 923 mtree->filetype = AE_IFCHR; 924 break; 925 } 926 case 'd': 927 if (strcmp(val, "dir") == 0) { 928 mtree->filetype = AE_IFDIR; 929 break; 930 } 931 case 'f': 932 if (strcmp(val, "fifo") == 0) { 933 mtree->filetype = AE_IFIFO; 934 break; 935 } 936 if (strcmp(val, "file") == 0) { 937 mtree->filetype = AE_IFREG; 938 break; 939 } 940 case 'l': 941 if (strcmp(val, "link") == 0) { 942 mtree->filetype = AE_IFLNK; 943 break; 944 } 945 default: 946 archive_set_error(&a->archive, 947 ARCHIVE_ERRNO_FILE_FORMAT, 948 "Unrecognized file type \"%s\"", val); 949 return (ARCHIVE_WARN); 950 } 951 archive_entry_set_filetype(entry, mtree->filetype); 952 break; 953 } 954 case 'u': 955 if (strcmp(key, "uid") == 0) { 956 *parsed_kws |= MTREE_HAS_UID; 957 archive_entry_set_uid(entry, mtree_atol10(&val)); 958 break; 959 } 960 if (strcmp(key, "uname") == 0) { 961 *parsed_kws |= MTREE_HAS_UNAME; 962 archive_entry_copy_uname(entry, val); 963 break; 964 } 965 default: 966 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 967 "Unrecognized key %s=%s", key, val); 968 return (ARCHIVE_WARN); 969 } 970 return (ARCHIVE_OK); 971 } 972 973 static int 974 read_data(struct archive_read *a, const void **buff, size_t *size, off_t *offset) 975 { 976 size_t bytes_to_read; 977 ssize_t bytes_read; 978 struct mtree *mtree; 979 980 mtree = (struct mtree *)(a->format->data); 981 if (mtree->fd < 0) { 982 *buff = NULL; 983 *offset = 0; 984 *size = 0; 985 return (ARCHIVE_EOF); 986 } 987 if (mtree->buff == NULL) { 988 mtree->buffsize = 64 * 1024; 989 mtree->buff = malloc(mtree->buffsize); 990 if (mtree->buff == NULL) { 991 archive_set_error(&a->archive, ENOMEM, 992 "Can't allocate memory"); 993 return (ARCHIVE_FATAL); 994 } 995 } 996 997 *buff = mtree->buff; 998 *offset = mtree->offset; 999 if ((off_t)mtree->buffsize > mtree->cur_size - mtree->offset) 1000 bytes_to_read = mtree->cur_size - mtree->offset; 1001 else 1002 bytes_to_read = mtree->buffsize; 1003 bytes_read = read(mtree->fd, mtree->buff, bytes_to_read); 1004 if (bytes_read < 0) { 1005 archive_set_error(&a->archive, errno, "Can't read"); 1006 return (ARCHIVE_WARN); 1007 } 1008 if (bytes_read == 0) { 1009 *size = 0; 1010 return (ARCHIVE_EOF); 1011 } 1012 mtree->offset += bytes_read; 1013 *size = bytes_read; 1014 return (ARCHIVE_OK); 1015 } 1016 1017 /* Skip does nothing except possibly close the contents file. */ 1018 static int 1019 skip(struct archive_read *a) 1020 { 1021 struct mtree *mtree; 1022 1023 mtree = (struct mtree *)(a->format->data); 1024 if (mtree->fd >= 0) { 1025 close(mtree->fd); 1026 mtree->fd = -1; 1027 } 1028 return (ARCHIVE_OK); 1029 } 1030 1031 /* 1032 * Since parsing backslash sequences always makes strings shorter, 1033 * we can always do this conversion in-place. 1034 */ 1035 static void 1036 parse_escapes(char *src, struct mtree_entry *mentry) 1037 { 1038 char *dest = src; 1039 char c; 1040 1041 /* 1042 * The current directory is somewhat special, it should be archived 1043 * only once as it will confuse extraction otherwise. 1044 */ 1045 if (strcmp(src, ".") == 0) 1046 mentry->full = 1; 1047 1048 while (*src != '\0') { 1049 c = *src++; 1050 if (c == '/' && mentry != NULL) 1051 mentry->full = 1; 1052 if (c == '\\') { 1053 switch (src[0]) { 1054 case '0': 1055 if (src[1] < '0' || src[1] > '7') { 1056 c = 0; 1057 ++src; 1058 break; 1059 } 1060 /* FALLTHROUGH */ 1061 case '1': 1062 case '2': 1063 case '3': 1064 if (src[1] >= '0' && src[1] <= '7' && 1065 src[2] >= '0' && src[2] <= '7') { 1066 c = (src[0] - '0') << 6; 1067 c |= (src[1] - '0') << 3; 1068 c |= (src[2] - '0'); 1069 src += 3; 1070 } 1071 break; 1072 case 'a': 1073 c = '\a'; 1074 ++src; 1075 break; 1076 case 'b': 1077 c = '\b'; 1078 ++src; 1079 break; 1080 case 'f': 1081 c = '\f'; 1082 ++src; 1083 break; 1084 case 'n': 1085 c = '\n'; 1086 ++src; 1087 break; 1088 case 'r': 1089 c = '\r'; 1090 ++src; 1091 break; 1092 case 's': 1093 c = ' '; 1094 ++src; 1095 break; 1096 case 't': 1097 c = '\t'; 1098 ++src; 1099 break; 1100 case 'v': 1101 c = '\v'; 1102 ++src; 1103 break; 1104 } 1105 } 1106 *dest++ = c; 1107 } 1108 *dest = '\0'; 1109 } 1110 1111 /* 1112 * Note that this implementation does not (and should not!) obey 1113 * locale settings; you cannot simply substitute strtol here, since 1114 * it does obey locale. 1115 */ 1116 static int64_t 1117 mtree_atol8(char **p) 1118 { 1119 int64_t l, limit, last_digit_limit; 1120 int digit, base; 1121 1122 base = 8; 1123 limit = INT64_MAX / base; 1124 last_digit_limit = INT64_MAX % base; 1125 1126 l = 0; 1127 digit = **p - '0'; 1128 while (digit >= 0 && digit < base) { 1129 if (l>limit || (l == limit && digit > last_digit_limit)) { 1130 l = INT64_MAX; /* Truncate on overflow. */ 1131 break; 1132 } 1133 l = (l * base) + digit; 1134 digit = *++(*p) - '0'; 1135 } 1136 return (l); 1137 } 1138 1139 /* 1140 * Note that this implementation does not (and should not!) obey 1141 * locale settings; you cannot simply substitute strtol here, since 1142 * it does obey locale. 1143 */ 1144 static int64_t 1145 mtree_atol10(char **p) 1146 { 1147 int64_t l, limit, last_digit_limit; 1148 int base, digit, sign; 1149 1150 base = 10; 1151 limit = INT64_MAX / base; 1152 last_digit_limit = INT64_MAX % base; 1153 1154 if (**p == '-') { 1155 sign = -1; 1156 ++(*p); 1157 } else 1158 sign = 1; 1159 1160 l = 0; 1161 digit = **p - '0'; 1162 while (digit >= 0 && digit < base) { 1163 if (l > limit || (l == limit && digit > last_digit_limit)) { 1164 l = UINT64_MAX; /* Truncate on overflow. */ 1165 break; 1166 } 1167 l = (l * base) + digit; 1168 digit = *++(*p) - '0'; 1169 } 1170 return (sign < 0) ? -l : l; 1171 } 1172 1173 /* 1174 * Note that this implementation does not (and should not!) obey 1175 * locale settings; you cannot simply substitute strtol here, since 1176 * it does obey locale. 1177 */ 1178 static int64_t 1179 mtree_atol16(char **p) 1180 { 1181 int64_t l, limit, last_digit_limit; 1182 int base, digit, sign; 1183 1184 base = 16; 1185 limit = INT64_MAX / base; 1186 last_digit_limit = INT64_MAX % base; 1187 1188 if (**p == '-') { 1189 sign = -1; 1190 ++(*p); 1191 } else 1192 sign = 1; 1193 1194 l = 0; 1195 if (**p >= '0' && **p <= '9') 1196 digit = **p - '0'; 1197 else if (**p >= 'a' && **p <= 'f') 1198 digit = **p - 'a' + 10; 1199 else if (**p >= 'A' && **p <= 'F') 1200 digit = **p - 'A' + 10; 1201 else 1202 digit = -1; 1203 while (digit >= 0 && digit < base) { 1204 if (l > limit || (l == limit && digit > last_digit_limit)) { 1205 l = UINT64_MAX; /* Truncate on overflow. */ 1206 break; 1207 } 1208 l = (l * base) + digit; 1209 if (**p >= '0' && **p <= '9') 1210 digit = **p - '0'; 1211 else if (**p >= 'a' && **p <= 'f') 1212 digit = **p - 'a' + 10; 1213 else if (**p >= 'A' && **p <= 'F') 1214 digit = **p - 'A' + 10; 1215 else 1216 digit = -1; 1217 } 1218 return (sign < 0) ? -l : l; 1219 } 1220 1221 static int64_t 1222 mtree_atol(char **p) 1223 { 1224 if (**p != '0') 1225 return mtree_atol10(p); 1226 if ((*p)[1] == 'x' || (*p)[1] == 'X') { 1227 *p += 2; 1228 return mtree_atol16(p); 1229 } 1230 return mtree_atol8(p); 1231 } 1232 1233 /* 1234 * Returns length of line (including trailing newline) 1235 * or negative on error. 'start' argument is updated to 1236 * point to first character of line. 1237 */ 1238 static ssize_t 1239 readline(struct archive_read *a, struct mtree *mtree, char **start, ssize_t limit) 1240 { 1241 ssize_t bytes_read; 1242 ssize_t total_size = 0; 1243 ssize_t find_off = 0; 1244 const void *t; 1245 const char *s; 1246 void *p; 1247 char *u; 1248 1249 /* Accumulate line in a line buffer. */ 1250 for (;;) { 1251 /* Read some more. */ 1252 t = __archive_read_ahead(a, 1, &bytes_read); 1253 if (t == NULL) 1254 return (0); 1255 if (bytes_read < 0) 1256 return (ARCHIVE_FATAL); 1257 s = t; /* Start of line? */ 1258 p = memchr(t, '\n', bytes_read); 1259 /* If we found '\n', trim the read. */ 1260 if (p != NULL) { 1261 bytes_read = 1 + ((const char *)p) - s; 1262 } 1263 if (total_size + bytes_read + 1 > limit) { 1264 archive_set_error(&a->archive, 1265 ARCHIVE_ERRNO_FILE_FORMAT, 1266 "Line too long"); 1267 return (ARCHIVE_FATAL); 1268 } 1269 if (archive_string_ensure(&mtree->line, 1270 total_size + bytes_read + 1) == NULL) { 1271 archive_set_error(&a->archive, ENOMEM, 1272 "Can't allocate working buffer"); 1273 return (ARCHIVE_FATAL); 1274 } 1275 memcpy(mtree->line.s + total_size, t, bytes_read); 1276 __archive_read_consume(a, bytes_read); 1277 total_size += bytes_read; 1278 /* Null terminate. */ 1279 mtree->line.s[total_size] = '\0'; 1280 /* If we found an unescaped '\n', clean up and return. */ 1281 for (u = mtree->line.s + find_off; *u; ++u) { 1282 if (u[0] == '\n') { 1283 *start = mtree->line.s; 1284 return total_size; 1285 } 1286 if (u[0] == '#') { 1287 if (p == NULL) 1288 break; 1289 *start = mtree->line.s; 1290 return total_size; 1291 } 1292 if (u[0] != '\\') 1293 continue; 1294 if (u[1] == '\\') { 1295 ++u; 1296 continue; 1297 } 1298 if (u[1] == '\n') { 1299 memmove(u, u + 1, 1300 total_size - (u - mtree->line.s) + 1); 1301 --total_size; 1302 ++u; 1303 break; 1304 } 1305 if (u[1] == '\0') 1306 break; 1307 } 1308 find_off = u - mtree->line.s; 1309 } 1310 } 1311