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: head/lib/libarchive/archive_read_support_format_mtree.c 201165 2009-12-29 05:52:13Z kientzle $"); 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 * (int)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 == NULL || 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 402 for (counter = 1; ; ++counter) { 403 len = readline(a, mtree, &p, 256); 404 if (len == 0) { 405 mtree->this_entry = mtree->entries; 406 free_options(global); 407 return (ARCHIVE_OK); 408 } 409 if (len < 0) { 410 free_options(global); 411 return (len); 412 } 413 /* Leading whitespace is never significant, ignore it. */ 414 while (*p == ' ' || *p == '\t') { 415 ++p; 416 --len; 417 } 418 /* Skip content lines and blank lines. */ 419 if (*p == '#') 420 continue; 421 if (*p == '\r' || *p == '\n' || *p == '\0') 422 continue; 423 if (*p != '/') { 424 r = process_add_entry(a, mtree, &global, p, 425 &last_entry); 426 } else if (strncmp(p, "/set", 4) == 0) { 427 if (p[4] != ' ' && p[4] != '\t') 428 break; 429 r = process_global_set(a, &global, p); 430 } else if (strncmp(p, "/unset", 6) == 0) { 431 if (p[6] != ' ' && p[6] != '\t') 432 break; 433 r = process_global_unset(a, &global, p); 434 } else 435 break; 436 437 if (r != ARCHIVE_OK) { 438 free_options(global); 439 return r; 440 } 441 } 442 443 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 444 "Can't parse line %ju", counter); 445 free_options(global); 446 return (ARCHIVE_FATAL); 447 } 448 449 /* 450 * Read in the entire mtree file into memory on the first request. 451 * Then use the next unused file to satisfy each header request. 452 */ 453 static int 454 read_header(struct archive_read *a, struct archive_entry *entry) 455 { 456 struct mtree *mtree; 457 char *p; 458 int r, use_next; 459 460 mtree = (struct mtree *)(a->format->data); 461 462 if (mtree->fd >= 0) { 463 close(mtree->fd); 464 mtree->fd = -1; 465 } 466 467 if (mtree->entries == NULL) { 468 mtree->resolver = archive_entry_linkresolver_new(); 469 if (mtree->resolver == NULL) 470 return ARCHIVE_FATAL; 471 archive_entry_linkresolver_set_strategy(mtree->resolver, 472 ARCHIVE_FORMAT_MTREE); 473 r = read_mtree(a, mtree); 474 if (r != ARCHIVE_OK) 475 return (r); 476 } 477 478 a->archive.archive_format = mtree->archive_format; 479 a->archive.archive_format_name = mtree->archive_format_name; 480 481 for (;;) { 482 if (mtree->this_entry == NULL) 483 return (ARCHIVE_EOF); 484 if (strcmp(mtree->this_entry->name, "..") == 0) { 485 mtree->this_entry->used = 1; 486 if (archive_strlen(&mtree->current_dir) > 0) { 487 /* Roll back current path. */ 488 p = mtree->current_dir.s 489 + mtree->current_dir.length - 1; 490 while (p >= mtree->current_dir.s && *p != '/') 491 --p; 492 if (p >= mtree->current_dir.s) 493 --p; 494 mtree->current_dir.length 495 = p - mtree->current_dir.s + 1; 496 } 497 } 498 if (!mtree->this_entry->used) { 499 use_next = 0; 500 r = parse_file(a, entry, mtree, mtree->this_entry, &use_next); 501 if (use_next == 0) 502 return (r); 503 } 504 mtree->this_entry = mtree->this_entry->next; 505 } 506 } 507 508 /* 509 * A single file can have multiple lines contribute specifications. 510 * Parse as many lines as necessary, then pull additional information 511 * from a backing file on disk as necessary. 512 */ 513 static int 514 parse_file(struct archive_read *a, struct archive_entry *entry, 515 struct mtree *mtree, struct mtree_entry *mentry, int *use_next) 516 { 517 const char *path; 518 struct stat st_storage, *st; 519 struct mtree_entry *mp; 520 struct archive_entry *sparse_entry; 521 int r = ARCHIVE_OK, r1, parsed_kws, mismatched_type; 522 523 mentry->used = 1; 524 525 /* Initialize reasonable defaults. */ 526 mtree->filetype = AE_IFREG; 527 archive_entry_set_size(entry, 0); 528 529 /* Parse options from this line. */ 530 parsed_kws = 0; 531 r = parse_line(a, entry, mtree, mentry, &parsed_kws); 532 533 if (mentry->full) { 534 archive_entry_copy_pathname(entry, mentry->name); 535 /* 536 * "Full" entries are allowed to have multiple lines 537 * and those lines aren't required to be adjacent. We 538 * don't support multiple lines for "relative" entries 539 * nor do we make any attempt to merge data from 540 * separate "relative" and "full" entries. (Merging 541 * "relative" and "full" entries would require dealing 542 * with pathname canonicalization, which is a very 543 * tricky subject.) 544 */ 545 for (mp = mentry->next; mp != NULL; mp = mp->next) { 546 if (mp->full && !mp->used 547 && strcmp(mentry->name, mp->name) == 0) { 548 /* Later lines override earlier ones. */ 549 mp->used = 1; 550 r1 = parse_line(a, entry, mtree, mp, 551 &parsed_kws); 552 if (r1 < r) 553 r = r1; 554 } 555 } 556 } else { 557 /* 558 * Relative entries require us to construct 559 * the full path and possibly update the 560 * current directory. 561 */ 562 size_t n = archive_strlen(&mtree->current_dir); 563 if (n > 0) 564 archive_strcat(&mtree->current_dir, "/"); 565 archive_strcat(&mtree->current_dir, mentry->name); 566 archive_entry_copy_pathname(entry, mtree->current_dir.s); 567 if (archive_entry_filetype(entry) != AE_IFDIR) 568 mtree->current_dir.length = n; 569 } 570 571 /* 572 * Try to open and stat the file to get the real size 573 * and other file info. It would be nice to avoid 574 * this here so that getting a listing of an mtree 575 * wouldn't require opening every referenced contents 576 * file. But then we wouldn't know the actual 577 * contents size, so I don't see a really viable way 578 * around this. (Also, we may want to someday pull 579 * other unspecified info from the contents file on 580 * disk.) 581 */ 582 mtree->fd = -1; 583 if (archive_strlen(&mtree->contents_name) > 0) 584 path = mtree->contents_name.s; 585 else 586 path = archive_entry_pathname(entry); 587 588 if (archive_entry_filetype(entry) == AE_IFREG || 589 archive_entry_filetype(entry) == AE_IFDIR) { 590 mtree->fd = open(path, O_RDONLY | O_BINARY); 591 if (mtree->fd == -1 && 592 (errno != ENOENT || 593 archive_strlen(&mtree->contents_name) > 0)) { 594 archive_set_error(&a->archive, errno, 595 "Can't open %s", path); 596 r = ARCHIVE_WARN; 597 } 598 } 599 600 st = &st_storage; 601 if (mtree->fd >= 0) { 602 if (fstat(mtree->fd, st) == -1) { 603 archive_set_error(&a->archive, errno, 604 "Could not fstat %s", path); 605 r = ARCHIVE_WARN; 606 /* If we can't stat it, don't keep it open. */ 607 close(mtree->fd); 608 mtree->fd = -1; 609 st = NULL; 610 } 611 } else if (lstat(path, st) == -1) { 612 st = NULL; 613 } 614 615 /* 616 * If there is a contents file on disk, use that size; 617 * otherwise leave it as-is (it might have been set from 618 * the mtree size= keyword). 619 */ 620 if (st != NULL) { 621 mismatched_type = 0; 622 if ((st->st_mode & S_IFMT) == S_IFREG && 623 archive_entry_filetype(entry) != AE_IFREG) 624 mismatched_type = 1; 625 if ((st->st_mode & S_IFMT) == S_IFLNK && 626 archive_entry_filetype(entry) != AE_IFLNK) 627 mismatched_type = 1; 628 if ((st->st_mode & S_IFSOCK) == S_IFSOCK && 629 archive_entry_filetype(entry) != AE_IFSOCK) 630 mismatched_type = 1; 631 if ((st->st_mode & S_IFMT) == S_IFCHR && 632 archive_entry_filetype(entry) != AE_IFCHR) 633 mismatched_type = 1; 634 if ((st->st_mode & S_IFMT) == S_IFBLK && 635 archive_entry_filetype(entry) != AE_IFBLK) 636 mismatched_type = 1; 637 if ((st->st_mode & S_IFMT) == S_IFDIR && 638 archive_entry_filetype(entry) != AE_IFDIR) 639 mismatched_type = 1; 640 if ((st->st_mode & S_IFMT) == S_IFIFO && 641 archive_entry_filetype(entry) != AE_IFIFO) 642 mismatched_type = 1; 643 644 if (mismatched_type) { 645 if ((parsed_kws & MTREE_HAS_OPTIONAL) == 0) { 646 archive_set_error(&a->archive, 647 ARCHIVE_ERRNO_MISC, 648 "mtree specification has different type for %s", 649 archive_entry_pathname(entry)); 650 r = ARCHIVE_WARN; 651 } else { 652 *use_next = 1; 653 } 654 /* Don't hold a non-regular file open. */ 655 if (mtree->fd >= 0) 656 close(mtree->fd); 657 mtree->fd = -1; 658 st = NULL; 659 return r; 660 } 661 } 662 663 if (st != NULL) { 664 if ((parsed_kws & MTREE_HAS_DEVICE) == 0 && 665 (archive_entry_filetype(entry) == AE_IFCHR || 666 archive_entry_filetype(entry) == AE_IFBLK)) 667 archive_entry_set_rdev(entry, st->st_rdev); 668 if ((parsed_kws & (MTREE_HAS_GID | MTREE_HAS_GNAME)) == 0) 669 archive_entry_set_gid(entry, st->st_gid); 670 if ((parsed_kws & (MTREE_HAS_UID | MTREE_HAS_UNAME)) == 0) 671 archive_entry_set_uid(entry, st->st_uid); 672 if ((parsed_kws & MTREE_HAS_MTIME) == 0) { 673 #if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 674 archive_entry_set_mtime(entry, st->st_mtime, 675 st->st_mtimespec.tv_nsec); 676 #elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 677 archive_entry_set_mtime(entry, st->st_mtime, 678 st->st_mtim.tv_nsec); 679 #elif HAVE_STRUCT_STAT_ST_MTIME_N 680 archive_entry_set_mtime(entry, st->st_mtime, 681 st->st_mtime_n); 682 #elif HAVE_STRUCT_STAT_ST_UMTIME 683 archive_entry_set_mtime(entry, st->st_mtime, 684 st->st_umtime*1000); 685 #elif HAVE_STRUCT_STAT_ST_MTIME_USEC 686 archive_entry_set_mtime(entry, st->st_mtime, 687 st->st_mtime_usec*1000); 688 #else 689 archive_entry_set_mtime(entry, st->st_mtime, 0); 690 #endif 691 } 692 if ((parsed_kws & MTREE_HAS_NLINK) == 0) 693 archive_entry_set_nlink(entry, st->st_nlink); 694 if ((parsed_kws & MTREE_HAS_PERM) == 0) 695 archive_entry_set_perm(entry, st->st_mode); 696 if ((parsed_kws & MTREE_HAS_SIZE) == 0) 697 archive_entry_set_size(entry, st->st_size); 698 archive_entry_set_ino(entry, st->st_ino); 699 archive_entry_set_dev(entry, st->st_dev); 700 701 archive_entry_linkify(mtree->resolver, &entry, &sparse_entry); 702 } else if (parsed_kws & MTREE_HAS_OPTIONAL) { 703 /* 704 * Couldn't open the entry, stat it or the on-disk type 705 * didn't match. If this entry is optional, just ignore it 706 * and read the next header entry. 707 */ 708 *use_next = 1; 709 return ARCHIVE_OK; 710 } 711 712 mtree->cur_size = archive_entry_size(entry); 713 mtree->offset = 0; 714 715 return r; 716 } 717 718 /* 719 * Each line contains a sequence of keywords. 720 */ 721 static int 722 parse_line(struct archive_read *a, struct archive_entry *entry, 723 struct mtree *mtree, struct mtree_entry *mp, int *parsed_kws) 724 { 725 struct mtree_option *iter; 726 int r = ARCHIVE_OK, r1; 727 728 for (iter = mp->options; iter != NULL; iter = iter->next) { 729 r1 = parse_keyword(a, mtree, entry, iter, parsed_kws); 730 if (r1 < r) 731 r = r1; 732 } 733 if ((*parsed_kws & MTREE_HAS_TYPE) == 0) { 734 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 735 "Missing type keyword in mtree specification"); 736 return (ARCHIVE_WARN); 737 } 738 return (r); 739 } 740 741 /* 742 * Device entries have one of the following forms: 743 * raw dev_t 744 * format,major,minor[,subdevice] 745 * 746 * Just use major and minor, no translation etc is done 747 * between formats. 748 */ 749 static int 750 parse_device(struct archive *a, struct archive_entry *entry, char *val) 751 { 752 char *comma1, *comma2; 753 754 comma1 = strchr(val, ','); 755 if (comma1 == NULL) { 756 archive_entry_set_dev(entry, mtree_atol10(&val)); 757 return (ARCHIVE_OK); 758 } 759 ++comma1; 760 comma2 = strchr(comma1, ','); 761 if (comma2 == NULL) { 762 archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, 763 "Malformed device attribute"); 764 return (ARCHIVE_WARN); 765 } 766 ++comma2; 767 archive_entry_set_rdevmajor(entry, mtree_atol(&comma1)); 768 archive_entry_set_rdevminor(entry, mtree_atol(&comma2)); 769 return (ARCHIVE_OK); 770 } 771 772 /* 773 * Parse a single keyword and its value. 774 */ 775 static int 776 parse_keyword(struct archive_read *a, struct mtree *mtree, 777 struct archive_entry *entry, struct mtree_option *option, int *parsed_kws) 778 { 779 char *val, *key; 780 781 key = option->value; 782 783 if (*key == '\0') 784 return (ARCHIVE_OK); 785 786 if (strcmp(key, "optional") == 0) { 787 *parsed_kws |= MTREE_HAS_OPTIONAL; 788 return (ARCHIVE_OK); 789 } 790 if (strcmp(key, "ignore") == 0) { 791 /* 792 * The mtree processing is not recursive, so 793 * recursion will only happen for explicitly listed 794 * entries. 795 */ 796 return (ARCHIVE_OK); 797 } 798 799 val = strchr(key, '='); 800 if (val == NULL) { 801 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 802 "Malformed attribute \"%s\" (%d)", key, key[0]); 803 return (ARCHIVE_WARN); 804 } 805 806 *val = '\0'; 807 ++val; 808 809 switch (key[0]) { 810 case 'c': 811 if (strcmp(key, "content") == 0 812 || strcmp(key, "contents") == 0) { 813 parse_escapes(val, NULL); 814 archive_strcpy(&mtree->contents_name, val); 815 break; 816 } 817 if (strcmp(key, "cksum") == 0) 818 break; 819 case 'd': 820 if (strcmp(key, "device") == 0) { 821 *parsed_kws |= MTREE_HAS_DEVICE; 822 return parse_device(&a->archive, entry, val); 823 } 824 case 'f': 825 if (strcmp(key, "flags") == 0) { 826 *parsed_kws |= MTREE_HAS_FFLAGS; 827 archive_entry_copy_fflags_text(entry, val); 828 break; 829 } 830 case 'g': 831 if (strcmp(key, "gid") == 0) { 832 *parsed_kws |= MTREE_HAS_GID; 833 archive_entry_set_gid(entry, mtree_atol10(&val)); 834 break; 835 } 836 if (strcmp(key, "gname") == 0) { 837 *parsed_kws |= MTREE_HAS_GNAME; 838 archive_entry_copy_gname(entry, val); 839 break; 840 } 841 case 'l': 842 if (strcmp(key, "link") == 0) { 843 archive_entry_copy_symlink(entry, val); 844 break; 845 } 846 case 'm': 847 if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0) 848 break; 849 if (strcmp(key, "mode") == 0) { 850 if (val[0] >= '0' && val[0] <= '9') { 851 *parsed_kws |= MTREE_HAS_PERM; 852 archive_entry_set_perm(entry, 853 mtree_atol8(&val)); 854 } else { 855 archive_set_error(&a->archive, 856 ARCHIVE_ERRNO_FILE_FORMAT, 857 "Symbolic mode \"%s\" unsupported", val); 858 return ARCHIVE_WARN; 859 } 860 break; 861 } 862 case 'n': 863 if (strcmp(key, "nlink") == 0) { 864 *parsed_kws |= MTREE_HAS_NLINK; 865 archive_entry_set_nlink(entry, mtree_atol10(&val)); 866 break; 867 } 868 case 'r': 869 if (strcmp(key, "rmd160") == 0 || 870 strcmp(key, "rmd160digest") == 0) 871 break; 872 case 's': 873 if (strcmp(key, "sha1") == 0 || strcmp(key, "sha1digest") == 0) 874 break; 875 if (strcmp(key, "sha256") == 0 || 876 strcmp(key, "sha256digest") == 0) 877 break; 878 if (strcmp(key, "sha384") == 0 || 879 strcmp(key, "sha384digest") == 0) 880 break; 881 if (strcmp(key, "sha512") == 0 || 882 strcmp(key, "sha512digest") == 0) 883 break; 884 if (strcmp(key, "size") == 0) { 885 archive_entry_set_size(entry, mtree_atol10(&val)); 886 break; 887 } 888 case 't': 889 if (strcmp(key, "tags") == 0) { 890 /* 891 * Comma delimited list of tags. 892 * Ignore the tags for now, but the interface 893 * should be extended to allow inclusion/exclusion. 894 */ 895 break; 896 } 897 if (strcmp(key, "time") == 0) { 898 time_t m; 899 long ns; 900 901 *parsed_kws |= MTREE_HAS_MTIME; 902 m = (time_t)mtree_atol10(&val); 903 if (*val == '.') { 904 ++val; 905 ns = (long)mtree_atol10(&val); 906 } else 907 ns = 0; 908 archive_entry_set_mtime(entry, m, ns); 909 break; 910 } 911 if (strcmp(key, "type") == 0) { 912 *parsed_kws |= MTREE_HAS_TYPE; 913 switch (val[0]) { 914 case 'b': 915 if (strcmp(val, "block") == 0) { 916 mtree->filetype = AE_IFBLK; 917 break; 918 } 919 case 'c': 920 if (strcmp(val, "char") == 0) { 921 mtree->filetype = AE_IFCHR; 922 break; 923 } 924 case 'd': 925 if (strcmp(val, "dir") == 0) { 926 mtree->filetype = AE_IFDIR; 927 break; 928 } 929 case 'f': 930 if (strcmp(val, "fifo") == 0) { 931 mtree->filetype = AE_IFIFO; 932 break; 933 } 934 if (strcmp(val, "file") == 0) { 935 mtree->filetype = AE_IFREG; 936 break; 937 } 938 case 'l': 939 if (strcmp(val, "link") == 0) { 940 mtree->filetype = AE_IFLNK; 941 break; 942 } 943 default: 944 archive_set_error(&a->archive, 945 ARCHIVE_ERRNO_FILE_FORMAT, 946 "Unrecognized file type \"%s\"", val); 947 return (ARCHIVE_WARN); 948 } 949 archive_entry_set_filetype(entry, mtree->filetype); 950 break; 951 } 952 case 'u': 953 if (strcmp(key, "uid") == 0) { 954 *parsed_kws |= MTREE_HAS_UID; 955 archive_entry_set_uid(entry, mtree_atol10(&val)); 956 break; 957 } 958 if (strcmp(key, "uname") == 0) { 959 *parsed_kws |= MTREE_HAS_UNAME; 960 archive_entry_copy_uname(entry, val); 961 break; 962 } 963 default: 964 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 965 "Unrecognized key %s=%s", key, val); 966 return (ARCHIVE_WARN); 967 } 968 return (ARCHIVE_OK); 969 } 970 971 static int 972 read_data(struct archive_read *a, const void **buff, size_t *size, off_t *offset) 973 { 974 size_t bytes_to_read; 975 ssize_t bytes_read; 976 struct mtree *mtree; 977 978 mtree = (struct mtree *)(a->format->data); 979 if (mtree->fd < 0) { 980 *buff = NULL; 981 *offset = 0; 982 *size = 0; 983 return (ARCHIVE_EOF); 984 } 985 if (mtree->buff == NULL) { 986 mtree->buffsize = 64 * 1024; 987 mtree->buff = malloc(mtree->buffsize); 988 if (mtree->buff == NULL) { 989 archive_set_error(&a->archive, ENOMEM, 990 "Can't allocate memory"); 991 return (ARCHIVE_FATAL); 992 } 993 } 994 995 *buff = mtree->buff; 996 *offset = mtree->offset; 997 if ((off_t)mtree->buffsize > mtree->cur_size - mtree->offset) 998 bytes_to_read = mtree->cur_size - mtree->offset; 999 else 1000 bytes_to_read = mtree->buffsize; 1001 bytes_read = read(mtree->fd, mtree->buff, bytes_to_read); 1002 if (bytes_read < 0) { 1003 archive_set_error(&a->archive, errno, "Can't read"); 1004 return (ARCHIVE_WARN); 1005 } 1006 if (bytes_read == 0) { 1007 *size = 0; 1008 return (ARCHIVE_EOF); 1009 } 1010 mtree->offset += bytes_read; 1011 *size = bytes_read; 1012 return (ARCHIVE_OK); 1013 } 1014 1015 /* Skip does nothing except possibly close the contents file. */ 1016 static int 1017 skip(struct archive_read *a) 1018 { 1019 struct mtree *mtree; 1020 1021 mtree = (struct mtree *)(a->format->data); 1022 if (mtree->fd >= 0) { 1023 close(mtree->fd); 1024 mtree->fd = -1; 1025 } 1026 return (ARCHIVE_OK); 1027 } 1028 1029 /* 1030 * Since parsing backslash sequences always makes strings shorter, 1031 * we can always do this conversion in-place. 1032 */ 1033 static void 1034 parse_escapes(char *src, struct mtree_entry *mentry) 1035 { 1036 char *dest = src; 1037 char c; 1038 1039 if (mentry != NULL && strcmp(src, ".") == 0) 1040 mentry->full = 1; 1041 1042 while (*src != '\0') { 1043 c = *src++; 1044 if (c == '/' && mentry != NULL) 1045 mentry->full = 1; 1046 if (c == '\\') { 1047 switch (src[0]) { 1048 case '0': 1049 if (src[1] < '0' || src[1] > '7') { 1050 c = 0; 1051 ++src; 1052 break; 1053 } 1054 /* FALLTHROUGH */ 1055 case '1': 1056 case '2': 1057 case '3': 1058 if (src[1] >= '0' && src[1] <= '7' && 1059 src[2] >= '0' && src[2] <= '7') { 1060 c = (src[0] - '0') << 6; 1061 c |= (src[1] - '0') << 3; 1062 c |= (src[2] - '0'); 1063 src += 3; 1064 } 1065 break; 1066 case 'a': 1067 c = '\a'; 1068 ++src; 1069 break; 1070 case 'b': 1071 c = '\b'; 1072 ++src; 1073 break; 1074 case 'f': 1075 c = '\f'; 1076 ++src; 1077 break; 1078 case 'n': 1079 c = '\n'; 1080 ++src; 1081 break; 1082 case 'r': 1083 c = '\r'; 1084 ++src; 1085 break; 1086 case 's': 1087 c = ' '; 1088 ++src; 1089 break; 1090 case 't': 1091 c = '\t'; 1092 ++src; 1093 break; 1094 case 'v': 1095 c = '\v'; 1096 ++src; 1097 break; 1098 } 1099 } 1100 *dest++ = c; 1101 } 1102 *dest = '\0'; 1103 } 1104 1105 /* 1106 * Note that this implementation does not (and should not!) obey 1107 * locale settings; you cannot simply substitute strtol here, since 1108 * it does obey locale. 1109 */ 1110 static int64_t 1111 mtree_atol8(char **p) 1112 { 1113 int64_t l, limit, last_digit_limit; 1114 int digit, base; 1115 1116 base = 8; 1117 limit = INT64_MAX / base; 1118 last_digit_limit = INT64_MAX % base; 1119 1120 l = 0; 1121 digit = **p - '0'; 1122 while (digit >= 0 && digit < base) { 1123 if (l>limit || (l == limit && digit > last_digit_limit)) { 1124 l = INT64_MAX; /* Truncate on overflow. */ 1125 break; 1126 } 1127 l = (l * base) + digit; 1128 digit = *++(*p) - '0'; 1129 } 1130 return (l); 1131 } 1132 1133 /* 1134 * Note that this implementation does not (and should not!) obey 1135 * locale settings; you cannot simply substitute strtol here, since 1136 * it does obey locale. 1137 */ 1138 static int64_t 1139 mtree_atol10(char **p) 1140 { 1141 int64_t l, limit, last_digit_limit; 1142 int base, digit, sign; 1143 1144 base = 10; 1145 limit = INT64_MAX / base; 1146 last_digit_limit = INT64_MAX % base; 1147 1148 if (**p == '-') { 1149 sign = -1; 1150 ++(*p); 1151 } else 1152 sign = 1; 1153 1154 l = 0; 1155 digit = **p - '0'; 1156 while (digit >= 0 && digit < base) { 1157 if (l > limit || (l == limit && digit > last_digit_limit)) { 1158 l = INT64_MAX; /* Truncate on overflow. */ 1159 break; 1160 } 1161 l = (l * base) + digit; 1162 digit = *++(*p) - '0'; 1163 } 1164 return (sign < 0) ? -l : l; 1165 } 1166 1167 /* 1168 * Note that this implementation does not (and should not!) obey 1169 * locale settings; you cannot simply substitute strtol here, since 1170 * it does obey locale. 1171 */ 1172 static int64_t 1173 mtree_atol16(char **p) 1174 { 1175 int64_t l, limit, last_digit_limit; 1176 int base, digit, sign; 1177 1178 base = 16; 1179 limit = INT64_MAX / base; 1180 last_digit_limit = INT64_MAX % base; 1181 1182 if (**p == '-') { 1183 sign = -1; 1184 ++(*p); 1185 } else 1186 sign = 1; 1187 1188 l = 0; 1189 if (**p >= '0' && **p <= '9') 1190 digit = **p - '0'; 1191 else if (**p >= 'a' && **p <= 'f') 1192 digit = **p - 'a' + 10; 1193 else if (**p >= 'A' && **p <= 'F') 1194 digit = **p - 'A' + 10; 1195 else 1196 digit = -1; 1197 while (digit >= 0 && digit < base) { 1198 if (l > limit || (l == limit && digit > last_digit_limit)) { 1199 l = INT64_MAX; /* Truncate on overflow. */ 1200 break; 1201 } 1202 l = (l * base) + digit; 1203 if (**p >= '0' && **p <= '9') 1204 digit = **p - '0'; 1205 else if (**p >= 'a' && **p <= 'f') 1206 digit = **p - 'a' + 10; 1207 else if (**p >= 'A' && **p <= 'F') 1208 digit = **p - 'A' + 10; 1209 else 1210 digit = -1; 1211 } 1212 return (sign < 0) ? -l : l; 1213 } 1214 1215 static int64_t 1216 mtree_atol(char **p) 1217 { 1218 if (**p != '0') 1219 return mtree_atol10(p); 1220 if ((*p)[1] == 'x' || (*p)[1] == 'X') { 1221 *p += 2; 1222 return mtree_atol16(p); 1223 } 1224 return mtree_atol8(p); 1225 } 1226 1227 /* 1228 * Returns length of line (including trailing newline) 1229 * or negative on error. 'start' argument is updated to 1230 * point to first character of line. 1231 */ 1232 static ssize_t 1233 readline(struct archive_read *a, struct mtree *mtree, char **start, ssize_t limit) 1234 { 1235 ssize_t bytes_read; 1236 ssize_t total_size = 0; 1237 ssize_t find_off = 0; 1238 const void *t; 1239 const char *s; 1240 void *p; 1241 char *u; 1242 1243 /* Accumulate line in a line buffer. */ 1244 for (;;) { 1245 /* Read some more. */ 1246 t = __archive_read_ahead(a, 1, &bytes_read); 1247 if (t == NULL) 1248 return (0); 1249 if (bytes_read < 0) 1250 return (ARCHIVE_FATAL); 1251 s = t; /* Start of line? */ 1252 p = memchr(t, '\n', bytes_read); 1253 /* If we found '\n', trim the read. */ 1254 if (p != NULL) { 1255 bytes_read = 1 + ((const char *)p) - s; 1256 } 1257 if (total_size + bytes_read + 1 > limit) { 1258 archive_set_error(&a->archive, 1259 ARCHIVE_ERRNO_FILE_FORMAT, 1260 "Line too long"); 1261 return (ARCHIVE_FATAL); 1262 } 1263 if (archive_string_ensure(&mtree->line, 1264 total_size + bytes_read + 1) == NULL) { 1265 archive_set_error(&a->archive, ENOMEM, 1266 "Can't allocate working buffer"); 1267 return (ARCHIVE_FATAL); 1268 } 1269 memcpy(mtree->line.s + total_size, t, bytes_read); 1270 __archive_read_consume(a, bytes_read); 1271 total_size += bytes_read; 1272 /* Null terminate. */ 1273 mtree->line.s[total_size] = '\0'; 1274 /* If we found an unescaped '\n', clean up and return. */ 1275 for (u = mtree->line.s + find_off; *u; ++u) { 1276 if (u[0] == '\n') { 1277 *start = mtree->line.s; 1278 return total_size; 1279 } 1280 if (u[0] == '#') { 1281 if (p == NULL) 1282 break; 1283 *start = mtree->line.s; 1284 return total_size; 1285 } 1286 if (u[0] != '\\') 1287 continue; 1288 if (u[1] == '\\') { 1289 ++u; 1290 continue; 1291 } 1292 if (u[1] == '\n') { 1293 memmove(u, u + 1, 1294 total_size - (u - mtree->line.s) + 1); 1295 --total_size; 1296 ++u; 1297 break; 1298 } 1299 if (u[1] == '\0') 1300 break; 1301 } 1302 find_off = u - mtree->line.s; 1303 } 1304 } 1305