1/* Create, modify, and extract from archives. 2 Copyright (C) 2005-2012, 2016, 2017 Red Hat, Inc. 3 This file is part of elfutils. 4 Written by Ulrich Drepper <drepper@redhat.com>, 2005. 5 6 This file is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 elfutils is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18 19#ifdef HAVE_CONFIG_H 20# include <config.h> 21#endif 22 23#include <argp.h> 24#include <assert.h> 25#include <fcntl.h> 26#include <gelf.h> 27#include <limits.h> 28#include <locale.h> 29#include <search.h> 30#include <stdbool.h> 31#include <stdlib.h> 32#include <stdio.h> 33#include <stdio_ext.h> 34#include <string.h> 35#include <time.h> 36#include <unistd.h> 37#include <sys/mman.h> 38#include <sys/stat.h> 39#include <sys/time.h> 40 41#include <system.h> 42#include <printversion.h> 43 44#include "arlib.h" 45 46 47/* Name and version of program. */ 48ARGP_PROGRAM_VERSION_HOOK_DEF = print_version; 49 50/* Prototypes for local functions. */ 51static int do_oper_extract (int oper, const char *arfname, char **argv, 52 int argc, long int instance); 53static int do_oper_delete (const char *arfname, char **argv, int argc, 54 long int instance); 55static int do_oper_insert (int oper, const char *arfname, char **argv, 56 int argc, const char *member); 57 58 59/* Bug report address. */ 60ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; 61 62 63/* Definitions of arguments for argp functions. */ 64static const struct argp_option options[] = 65{ 66 { NULL, 0, NULL, 0, N_("Commands:"), 1 }, 67 { NULL, 'd', NULL, 0, N_("Delete files from archive."), 0 }, 68 { NULL, 'm', NULL, 0, N_("Move files in archive."), 0 }, 69 { NULL, 'p', NULL, 0, N_("Print files in archive."), 0 }, 70 { NULL, 'q', NULL, 0, N_("Quick append files to archive."), 0 }, 71 { NULL, 'r', NULL, 0, 72 N_("Replace existing or insert new file into archive."), 0 }, 73 { NULL, 't', NULL, 0, N_("Display content of archive."), 0 }, 74 { NULL, 'x', NULL, 0, N_("Extract files from archive."), 0 }, 75 76 { NULL, 0, NULL, 0, N_("Command Modifiers:"), 2 }, 77 { NULL, 'o', NULL, 0, N_("Preserve original dates."), 0 }, 78 { NULL, 'N', NULL, 0, N_("Use instance [COUNT] of name."), 0 }, 79 { NULL, 'C', NULL, 0, 80 N_("Do not replace existing files with extracted files."), 0 }, 81 { NULL, 'T', NULL, 0, N_("Allow filename to be truncated if necessary."), 82 0 }, 83 { NULL, 'v', NULL, 0, N_("Provide verbose output."), 0 }, 84 { NULL, 's', NULL, 0, N_("Force regeneration of symbol table."), 0 }, 85 { NULL, 'a', NULL, 0, N_("Insert file after [MEMBER]."), 0 }, 86 { NULL, 'b', NULL, 0, N_("Insert file before [MEMBER]."), 0 }, 87 { NULL, 'i', NULL, 0, N_("Same as -b."), 0 }, 88 { NULL, 'c', NULL, 0, N_("Suppress message when library has to be created."), 89 0 }, 90 { NULL, 'P', NULL, 0, N_("Use full path for file matching."), 0 }, 91 { NULL, 'u', NULL, 0, N_("Update only older files in archive."), 0 }, 92 93 { NULL, 0, NULL, 0, NULL, 0 } 94}; 95 96/* Short description of program. */ 97static const char doc[] = N_("Create, modify, and extract from archives."); 98 99/* Strings for arguments in help texts. */ 100static const char args_doc[] = N_("[MEMBER] [COUNT] ARCHIVE [FILE...]"); 101 102/* Prototype for option handler. */ 103static error_t parse_opt (int key, char *arg, struct argp_state *state); 104 105/* Data structure to communicate with argp functions. */ 106static struct argp argp = 107{ 108 options, parse_opt, args_doc, doc, arlib_argp_children, NULL, NULL 109}; 110 111 112/* What operation to perform. */ 113static enum 114 { 115 oper_none, 116 oper_delete, 117 oper_move, 118 oper_print, 119 oper_qappend, 120 oper_replace, 121 oper_list, 122 oper_extract 123 } operation; 124 125/* Modifiers. */ 126static bool verbose; 127static bool preserve_dates; 128static bool instance_specifed; 129static bool dont_replace_existing; 130static bool allow_truncate_fname; 131static bool force_symtab; 132static bool suppress_create_msg; 133static bool full_path; 134static bool update_newer; 135static enum { ipos_none, ipos_before, ipos_after } ipos; 136 137 138int 139main (int argc, char *argv[]) 140{ 141 /* We use no threads here which can interfere with handling a stream. */ 142 (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER); 143 (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER); 144 (void) __fsetlocking (stderr, FSETLOCKING_BYCALLER); 145 146 /* Set locale. */ 147 (void) setlocale (LC_ALL, ""); 148 149 /* Make sure the message catalog can be found. */ 150 (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR); 151 152 /* Initialize the message catalog. */ 153 (void) textdomain (PACKAGE_TARNAME); 154 155 /* For historical reasons the options in the first parameter need 156 not be preceded by a dash. Add it now if necessary. */ 157 if (argc > 1 && argv[1][0] != '-') 158 { 159 size_t len = strlen (argv[1]) + 1; 160 char *newp = alloca (len + 1); 161 newp[0] = '-'; 162 memcpy (&newp[1], argv[1], len); 163 argv[1] = newp; 164 } 165 166 /* Parse and process arguments. */ 167 int remaining; 168 (void) argp_parse (&argp, argc, argv, ARGP_IN_ORDER, &remaining, NULL); 169 170 /* Tell the library which version we are expecting. */ 171 (void) elf_version (EV_CURRENT); 172 173 /* Handle the [MEMBER] parameter. */ 174 const char *member = NULL; 175 if (ipos != ipos_none) 176 { 177 /* Only valid for certain operations. */ 178 if (operation != oper_move && operation != oper_replace) 179 error (1, 0, _("\ 180'a', 'b', and 'i' are only allowed with the 'm' and 'r' options")); 181 182 if (remaining == argc) 183 { 184 error (0, 0, _("\ 185MEMBER parameter required for 'a', 'b', and 'i' modifiers")); 186 argp_help (&argp, stderr, ARGP_HELP_USAGE | ARGP_HELP_SEE, 187 program_invocation_short_name); 188 exit (EXIT_FAILURE); 189 } 190 191 member = argv[remaining++]; 192 } 193 194 /* Handle the [COUNT] parameter. */ 195 long int instance = -1; 196 if (instance_specifed) 197 { 198 /* Only valid for certain operations. */ 199 if (operation != oper_extract && operation != oper_delete) 200 error (1, 0, _("\ 201'N' is only meaningful with the 'x' and 'd' options")); 202 203 if (remaining == argc) 204 { 205 error (0, 0, _("COUNT parameter required")); 206 argp_help (&argp, stderr, ARGP_HELP_SEE, 207 program_invocation_short_name); 208 exit (EXIT_FAILURE); 209 } 210 211 char *endp; 212 errno = 0; 213 if (((instance = strtol (argv[remaining], &endp, 10)) == LONG_MAX 214 && errno == ERANGE) 215 || instance <= 0 216 || *endp != '\0') 217 error (1, 0, _("invalid COUNT parameter %s"), argv[remaining]); 218 219 ++remaining; 220 } 221 222 if ((dont_replace_existing || allow_truncate_fname) 223 && unlikely (operation != oper_extract)) 224 error (1, 0, _("'%c' is only meaningful with the 'x' option"), 225 dont_replace_existing ? 'C' : 'T'); 226 227 /* There must at least be one more parameter specifying the archive. */ 228 if (remaining == argc) 229 { 230 error (0, 0, _("archive name required")); 231 argp_help (&argp, stderr, ARGP_HELP_SEE, program_invocation_short_name); 232 exit (EXIT_FAILURE); 233 } 234 235 const char *arfname = argv[remaining++]; 236 argv += remaining; 237 argc -= remaining; 238 239 int status; 240 switch (operation) 241 { 242 case oper_none: 243 error (0, 0, _("command option required")); 244 argp_help (&argp, stderr, ARGP_HELP_STD_ERR, 245 program_invocation_short_name); 246 status = 1; 247 break; 248 249 case oper_list: 250 case oper_print: 251 status = do_oper_extract (operation, arfname, argv, argc, -1); 252 break; 253 254 case oper_extract: 255 status = do_oper_extract (operation, arfname, argv, argc, instance); 256 break; 257 258 case oper_delete: 259 status = do_oper_delete (arfname, argv, argc, instance); 260 break; 261 262 case oper_move: 263 case oper_qappend: 264 case oper_replace: 265 status = do_oper_insert (operation, arfname, argv, argc, member); 266 break; 267 268 default: 269 assert (! "should not happen"); 270 status = 1; 271 break; 272 } 273 274 return status; 275} 276 277 278/* Handle program arguments. */ 279static error_t 280parse_opt (int key, char *arg __attribute__ ((unused)), 281 struct argp_state *state __attribute__ ((unused))) 282{ 283 switch (key) 284 { 285 case 'd': 286 case 'm': 287 case 'p': 288 case 'q': 289 case 'r': 290 case 't': 291 case 'x': 292 if (operation != oper_none) 293 { 294 error (0, 0, _("More than one operation specified")); 295 argp_help (&argp, stderr, ARGP_HELP_SEE, 296 program_invocation_short_name); 297 exit (EXIT_FAILURE); 298 } 299 300 switch (key) 301 { 302 case 'd': 303 operation = oper_delete; 304 break; 305 case 'm': 306 operation = oper_move; 307 break; 308 case 'p': 309 operation = oper_print; 310 break; 311 case 'q': 312 operation = oper_qappend; 313 break; 314 case 'r': 315 operation = oper_replace; 316 break; 317 case 't': 318 operation = oper_list; 319 break; 320 case 'x': 321 operation = oper_extract; 322 break; 323 } 324 break; 325 326 case 'a': 327 ipos = ipos_after; 328 break; 329 330 case 'b': 331 case 'i': 332 ipos = ipos_before; 333 break; 334 335 case 'c': 336 suppress_create_msg = true; 337 break; 338 339 case 'C': 340 dont_replace_existing = true; 341 break; 342 343 case 'N': 344 instance_specifed = true; 345 break; 346 347 case 'o': 348 preserve_dates = true; 349 break; 350 351 case 'P': 352 full_path = true; 353 break; 354 355 case 's': 356 force_symtab = true; 357 break; 358 359 case 'T': 360 allow_truncate_fname = true; 361 break; 362 363 case 'u': 364 update_newer = true; 365 break; 366 367 case 'v': 368 verbose = true; 369 break; 370 371 default: 372 return ARGP_ERR_UNKNOWN; 373 } 374 return 0; 375} 376 377 378static int 379open_archive (const char *arfname, int flags, int mode, Elf **elf, 380 struct stat *st, bool miss_allowed) 381{ 382 int fd = open (arfname, flags, mode); 383 if (fd == -1) 384 { 385 if (miss_allowed) 386 return -1; 387 388 error_exit (errno, _("cannot open archive '%s'"), 389 arfname); 390 } 391 392 if (elf != NULL) 393 { 394 Elf_Cmd cmd = flags == O_RDONLY ? ELF_C_READ_MMAP : ELF_C_RDWR_MMAP; 395 396 *elf = elf_begin (fd, cmd, NULL); 397 if (*elf == NULL) 398 error_exit (0, _("cannot open archive '%s': %s"), 399 arfname, elf_errmsg (-1)); 400 401 if (flags == O_RDONLY && elf_kind (*elf) != ELF_K_AR) 402 error_exit (0, _("%s: not an archive file"), arfname); 403 } 404 405 if (st != NULL && fstat (fd, st) != 0) 406 error_exit (errno, _("cannot stat archive '%s'"), 407 arfname); 408 409 return fd; 410} 411 412 413static void 414not_found (int argc, char *argv[argc], bool found[argc]) 415{ 416 for (int i = 0; i < argc; ++i) 417 if (!found[i]) 418 printf (_("no entry %s in archive\n"), argv[i]); 419} 420 421 422static int 423copy_content (Elf *elf, int newfd, off_t off, size_t n) 424{ 425 size_t len; 426 char *rawfile = elf_rawfile (elf, &len); 427 428 assert (off + n <= len); 429 430 /* Tell the kernel we will read all the pages sequentially. */ 431 size_t ps = sysconf (_SC_PAGESIZE); 432 if (n > 2 * ps) 433 posix_madvise (rawfile + (off & ~(ps - 1)), n, POSIX_MADV_SEQUENTIAL); 434 435 return write_retry (newfd, rawfile + off, n) != (ssize_t) n; 436} 437 438static inline bool 439should_truncate_fname (size_t *name_max) 440{ 441 if (errno == ENAMETOOLONG && allow_truncate_fname) 442 { 443 if (*name_max == 0) 444 { 445 long int len = pathconf (".", _PC_NAME_MAX); 446 if (len > 0) 447 *name_max = len; 448 } 449 return *name_max != 0; 450 } 451 return false; 452} 453 454static int 455do_oper_extract (int oper, const char *arfname, char **argv, int argc, 456 long int instance) 457{ 458 bool found[argc > 0 ? argc : 1]; 459 memset (found, '\0', sizeof (found)); 460 461 size_t name_max = 0; 462 off_t index_off = -1; 463 size_t index_size = 0; 464 off_t cur_off = SARMAG; 465 466 int status = 0; 467 Elf *elf; 468 int fd = open_archive (arfname, O_RDONLY, 0, &elf, NULL, false); 469 470 if (hcreate (2 * argc) == 0) 471 error_exit (errno, _("cannot create hash table")); 472 473 for (int cnt = 0; cnt < argc; ++cnt) 474 { 475 ENTRY entry = { .key = argv[cnt], .data = &argv[cnt] }; 476 if (hsearch (entry, ENTER) == NULL) 477 error_exit (errno, _("cannot insert into hash table")); 478 } 479 480 struct stat st; 481 if (force_symtab) 482 { 483 if (fstat (fd, &st) != 0) 484 { 485 error (0, errno, _("cannot stat '%s'"), arfname); 486 close (fd); 487 return 1; 488 } 489 arlib_init (); 490 } 491 492 Elf_Cmd cmd = ELF_C_READ_MMAP; 493 Elf *subelf; 494 while ((subelf = elf_begin (fd, cmd, elf)) != NULL) 495 { 496 Elf_Arhdr *arhdr = elf_getarhdr (subelf); 497 498 if (strcmp (arhdr->ar_name, "/") == 0) 499 { 500 index_off = elf_getaroff (subelf); 501 index_size = arhdr->ar_size; 502 goto next; 503 } 504 if (strcmp (arhdr->ar_name, "//") == 0) 505 goto next; 506 507 if (force_symtab) 508 { 509 arlib_add_symbols (elf, arfname, arhdr->ar_name, cur_off); 510 cur_off += (((arhdr->ar_size + 1) & ~((off_t) 1)) 511 + sizeof (struct ar_hdr)); 512 } 513 514 bool do_extract = argc <= 0; 515 if (!do_extract) 516 { 517 ENTRY entry; 518 entry.key = arhdr->ar_name; 519 ENTRY *res = hsearch (entry, FIND); 520 if (res != NULL && (instance < 0 || --instance == 0) 521 && !found[(char **) res->data - argv]) 522 found[(char **) res->data - argv] = do_extract = true; 523 } 524 525 if (do_extract) 526 { 527 if (verbose) 528 { 529 if (oper == oper_print) 530 { 531 printf ("\n<%s>\n\n", arhdr->ar_name); 532 533 /* We have to flush now because now we use the descriptor 534 directly. */ 535 fflush (stdout); 536 } 537 else if (oper == oper_list) 538 { 539 char datestr[100]; 540 struct tm *tp = localtime (&arhdr->ar_date); 541 if (tp == NULL) 542 { 543 time_t time = 0; 544 tp = localtime (&time); 545 } 546 547 strftime (datestr, sizeof (datestr), "%b %e %H:%M %Y", tp); 548 549 printf ("%c%c%c%c%c%c%c%c%c %u/%u %6ju %s %s\n", 550 (arhdr->ar_mode & S_IRUSR) ? 'r' : '-', 551 (arhdr->ar_mode & S_IWUSR) ? 'w' : '-', 552 (arhdr->ar_mode & S_IXUSR) 553 ? ((arhdr->ar_mode & S_ISUID) ? 's' : 'x') 554 : ((arhdr->ar_mode & S_ISUID) ? 'S' : '-'), 555 (arhdr->ar_mode & S_IRGRP) ? 'r' : '-', 556 (arhdr->ar_mode & S_IWGRP) ? 'w' : '-', 557 (arhdr->ar_mode & S_IXGRP) 558 ? ((arhdr->ar_mode & S_ISGID) ? 's' : 'x') 559 : ((arhdr->ar_mode & S_ISGID) ? 'S' : '-'), 560 (arhdr->ar_mode & S_IROTH) ? 'r' : '-', 561 (arhdr->ar_mode & S_IWOTH) ? 'w' : '-', 562 (arhdr->ar_mode & S_IXOTH) 563 ? ((arhdr->ar_mode & S_ISVTX) ? 't' : 'x') 564 : ((arhdr->ar_mode & S_ISVTX) ? 'T' : '-'), 565 arhdr->ar_uid, 566 arhdr->ar_gid, 567 (uintmax_t) arhdr->ar_size, 568 datestr, 569 arhdr->ar_name); 570 } 571 else 572 printf ("x - %s\n", arhdr->ar_name); 573 } 574 575 if (oper == oper_list) 576 { 577 if (!verbose) 578 puts (arhdr->ar_name); 579 580 goto next; 581 } 582 583 size_t nleft; 584 char *data = elf_rawfile (subelf, &nleft); 585 if (data == NULL) 586 { 587 error (0, 0, _("cannot read content of %s: %s"), 588 arhdr->ar_name, elf_errmsg (-1)); 589 status = 1; 590 goto next; 591 } 592 593 int xfd; 594 char tempfname[] = "XXXXXX"; 595 bool use_mkstemp = true; 596 597 if (oper == oper_print) 598 xfd = STDOUT_FILENO; 599 else 600 { 601 xfd = mkstemp (tempfname); 602 if (unlikely (xfd == -1)) 603 { 604 /* We cannot create a temporary file. Try to overwrite 605 the file or create it if it does not exist. */ 606 int flags = O_WRONLY | O_CREAT; 607 if (dont_replace_existing) 608 flags |= O_EXCL; 609 else 610 flags |= O_TRUNC; 611 xfd = open (arhdr->ar_name, flags, 0600); 612 if (unlikely (xfd == -1)) 613 { 614 int printlen = INT_MAX; 615 616 if (should_truncate_fname (&name_max)) 617 { 618 /* Try to truncate the name. First find out by how 619 much. */ 620 printlen = name_max; 621 char truncfname[name_max + 1]; 622 *((char *) mempcpy (truncfname, arhdr->ar_name, 623 name_max)) = '\0'; 624 625 xfd = open (truncfname, flags, 0600); 626 } 627 628 if (xfd == -1) 629 { 630 error (0, errno, _("cannot open %.*s"), 631 (int) printlen, arhdr->ar_name); 632 status = 1; 633 goto next; 634 } 635 } 636 637 use_mkstemp = false; 638 } 639 } 640 641 ssize_t n; 642 while ((n = TEMP_FAILURE_RETRY (write (xfd, data, nleft))) != -1) 643 { 644 nleft -= n; 645 if (nleft == 0) 646 break; 647 data += n; 648 } 649 650 if (unlikely (n == -1)) 651 { 652 error (0, errno, _("failed to write %s"), arhdr->ar_name); 653 status = 1; 654 unlink (tempfname); 655 close (xfd); 656 goto next; 657 } 658 659 if (oper != oper_print) 660 { 661 /* Fix up the mode. */ 662 if (unlikely (fchmod (xfd, arhdr->ar_mode) != 0)) 663 { 664 error (0, errno, _("cannot change mode of %s"), 665 arhdr->ar_name); 666 status = 0; 667 } 668 669 if (preserve_dates) 670 { 671 struct timespec tv[2]; 672 tv[0].tv_sec = arhdr->ar_date; 673 tv[0].tv_nsec = 0; 674 tv[1].tv_sec = arhdr->ar_date; 675 tv[1].tv_nsec = 0; 676 677 if (unlikely (futimens (xfd, tv) != 0)) 678 { 679 error (0, errno, 680 _("cannot change modification time of %s"), 681 arhdr->ar_name); 682 status = 1; 683 } 684 } 685 686 /* If we used a temporary file, move it do the right 687 name now. */ 688 if (use_mkstemp) 689 { 690 int r; 691 692 if (dont_replace_existing) 693 { 694 r = link (tempfname, arhdr->ar_name); 695 if (likely (r == 0)) 696 unlink (tempfname); 697 } 698 else 699 r = rename (tempfname, arhdr->ar_name); 700 701 if (unlikely (r) != 0) 702 { 703 int printlen = INT_MAX; 704 705 if (should_truncate_fname (&name_max)) 706 { 707 /* Try to truncate the name. First find out by how 708 much. */ 709 printlen = name_max; 710 char truncfname[name_max + 1]; 711 *((char *) mempcpy (truncfname, arhdr->ar_name, 712 name_max)) = '\0'; 713 714 if (dont_replace_existing) 715 { 716 r = link (tempfname, truncfname); 717 if (likely (r == 0)) 718 unlink (tempfname); 719 } 720 else 721 r = rename (tempfname, truncfname); 722 } 723 724 if (r != 0) 725 { 726 error (0, errno, _("\ 727cannot rename temporary file to %.*s"), 728 printlen, arhdr->ar_name); 729 unlink (tempfname); 730 status = 1; 731 } 732 } 733 } 734 735 close (xfd); 736 } 737 } 738 739 next: 740 cmd = elf_next (subelf); 741 if (elf_end (subelf) != 0) 742 error (1, 0, "%s: %s", arfname, elf_errmsg (-1)); 743 } 744 745 hdestroy (); 746 747 if (force_symtab) 748 { 749 arlib_finalize (); 750 751 if (symtab.symsnamelen != 0 752 /* We have to rewrite the file also if it initially had an index 753 but now does not need one anymore. */ 754 || (symtab.symsnamelen == 0 && index_size != 0)) 755 { 756 char tmpfname[strlen (arfname) + 7]; 757 strcpy (stpcpy (tmpfname, arfname), "XXXXXX"); 758 int newfd = mkstemp (tmpfname); 759 if (unlikely (newfd == -1)) 760 { 761 nonew: 762 error (0, errno, _("cannot create new file")); 763 status = 1; 764 } 765 else 766 { 767 /* Create the header. */ 768 if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG)) 769 { 770 // XXX Use /prof/self/fd/%d ??? 771 nonew_unlink: 772 unlink (tmpfname); 773 if (newfd != -1) 774 close (newfd); 775 goto nonew; 776 } 777 778 /* Create the new file. There are three parts as far we are 779 concerned: 1. original context before the index, 2. the 780 new index, 3. everything after the new index. */ 781 off_t rest_off; 782 if (index_off != -1) 783 rest_off = (index_off + sizeof (struct ar_hdr) 784 + ((index_size + 1) & ~1ul)); 785 else 786 rest_off = SARMAG; 787 788 if (symtab.symsnamelen != 0 789 && ((write_retry (newfd, symtab.symsoff, 790 symtab.symsofflen) 791 != (ssize_t) symtab.symsofflen) 792 || (write_retry (newfd, symtab.symsname, 793 symtab.symsnamelen) 794 != (ssize_t) symtab.symsnamelen))) 795 goto nonew_unlink; 796 /* Even if the original file had content before the 797 symbol table, we write it in the correct order. */ 798 if ((index_off != SARMAG 799 && copy_content (elf, newfd, SARMAG, index_off - SARMAG)) 800 || copy_content (elf, newfd, rest_off, st.st_size - rest_off)) 801 goto nonew_unlink; 802 803 /* Never complain about fchown failing. */ 804 if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; } 805 /* Set the mode of the new file to the same values the 806 original file has. */ 807 if (fchmod (newfd, st.st_mode & ALLPERMS) != 0 808 || close (newfd) != 0) 809 goto nonew_unlink; 810 newfd = -1; 811 if (rename (tmpfname, arfname) != 0) 812 goto nonew_unlink; 813 } 814 } 815 } 816 817 elf_end (elf); 818 819 close (fd); 820 821 not_found (argc, argv, found); 822 823 return status; 824} 825 826 827struct armem 828{ 829 off_t off; 830 off_t old_off; 831 size_t size; 832 long int long_name_off; 833 struct armem *next; 834 void *mem; 835 time_t sec; 836 uid_t uid; 837 gid_t gid; 838 mode_t mode; 839 const char *name; 840 Elf *elf; 841}; 842 843 844static int 845write_member (struct armem *memb, off_t *startp, off_t *lenp, Elf *elf, 846 off_t end_off, int newfd) 847{ 848 struct ar_hdr arhdr; 849 /* The ar_name is not actually zero terminated, but we need that for 850 snprintf. Also if the name is too long, then the string starts 851 with '/' plus an index off number (decimal). */ 852 char tmpbuf[sizeof (arhdr.ar_name) + 2]; 853 854 bool changed_header = memb->long_name_off != -1; 855 if (changed_header) 856 { 857 /* In case of a long file name we assume the archive header 858 changed and we write it here. */ 859 memcpy (&arhdr, elf_rawfile (elf, NULL) + *startp, sizeof (arhdr)); 860 861 snprintf (tmpbuf, sizeof (tmpbuf), "/%-*ld", 862 (int) sizeof (arhdr.ar_name), memb->long_name_off); 863 changed_header = memcmp (arhdr.ar_name, tmpbuf, 864 sizeof (arhdr.ar_name)) != 0; 865 } 866 867 /* If the files are adjacent in the old file extend the range. */ 868 if (*startp != -1 && !changed_header && *startp + *lenp == memb->old_off) 869 { 870 /* Extend the current range. */ 871 *lenp += (memb->next != NULL 872 ? memb->next->off : end_off) - memb->off; 873 return 0; 874 } 875 876 /* Write out the old range. */ 877 if (*startp != -1 && copy_content (elf, newfd, *startp, *lenp)) 878 return -1; 879 880 *startp = memb->old_off; 881 *lenp = (memb->next != NULL ? memb->next->off : end_off) - memb->off; 882 883 if (changed_header) 884 { 885 memcpy (arhdr.ar_name, tmpbuf, sizeof (arhdr.ar_name)); 886 887 if (unlikely (write_retry (newfd, &arhdr, sizeof (arhdr)) 888 != sizeof (arhdr))) 889 return -1; 890 891 *startp += sizeof (struct ar_hdr); 892 assert ((size_t) *lenp >= sizeof (struct ar_hdr)); 893 *lenp -= sizeof (struct ar_hdr); 894 } 895 896 return 0; 897} 898 899/* Store the name in the long name table if necessary. 900 Record its offset or -1 if we did not need to use the table. */ 901static void 902remember_long_name (struct armem *mem, const char *name, size_t namelen) 903{ 904 mem->long_name_off = (namelen > MAX_AR_NAME_LEN 905 ? arlib_add_long_name (name, namelen) 906 : -1l); 907} 908 909static int 910do_oper_delete (const char *arfname, char **argv, int argc, 911 long int instance) 912{ 913 bool *found = alloca (sizeof (bool) * argc); 914 memset (found, '\0', sizeof (bool) * argc); 915 916 /* List of the files we keep. */ 917 struct armem *to_copy = NULL; 918 919 int status = 0; 920 Elf *elf; 921 struct stat st; 922 int fd = open_archive (arfname, O_RDONLY, 0, &elf, &st, false); 923 924 if (hcreate (2 * argc) == 0) 925 error_exit (errno, _("cannot create hash table")); 926 927 for (int cnt = 0; cnt < argc; ++cnt) 928 { 929 ENTRY entry = { .key = argv[cnt], .data = &argv[cnt] }; 930 if (hsearch (entry, ENTER) == NULL) 931 error_exit (errno, _("cannot insert into hash table")); 932 } 933 934 arlib_init (); 935 936 off_t cur_off = SARMAG; 937 Elf_Cmd cmd = ELF_C_READ_MMAP; 938 Elf *subelf; 939 while ((subelf = elf_begin (fd, cmd, elf)) != NULL) 940 { 941 Elf_Arhdr *arhdr = elf_getarhdr (subelf); 942 943 /* Ignore the symbol table and the long file name table here. */ 944 if (strcmp (arhdr->ar_name, "/") == 0 945 || strcmp (arhdr->ar_name, "//") == 0) 946 goto next; 947 948 bool do_delete = argc <= 0; 949 if (!do_delete) 950 { 951 ENTRY entry; 952 entry.key = arhdr->ar_name; 953 ENTRY *res = hsearch (entry, FIND); 954 if (res != NULL && (instance < 0 || --instance == 0) 955 && !found[(char **) res->data - argv]) 956 found[(char **) res->data - argv] = do_delete = true; 957 } 958 959 if (do_delete) 960 { 961 if (verbose) 962 printf ("d - %s\n", arhdr->ar_name); 963 } 964 else 965 { 966 struct armem *newp = alloca (sizeof (struct armem)); 967 newp->old_off = elf_getaroff (subelf); 968 newp->off = cur_off; 969 970 cur_off += (((arhdr->ar_size + 1) & ~((off_t) 1)) 971 + sizeof (struct ar_hdr)); 972 973 if (to_copy == NULL) 974 to_copy = newp->next = newp; 975 else 976 { 977 newp->next = to_copy->next; 978 to_copy = to_copy->next = newp; 979 } 980 981 /* If we recreate the symbol table read the file's symbol 982 table now. */ 983 arlib_add_symbols (subelf, arfname, arhdr->ar_name, newp->off); 984 985 /* Remember long file names. */ 986 remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name)); 987 } 988 989 next: 990 cmd = elf_next (subelf); 991 if (elf_end (subelf) != 0) 992 error (1, 0, "%s: %s", arfname, elf_errmsg (-1)); 993 } 994 995 arlib_finalize (); 996 997 hdestroy (); 998 999 /* Create a new, temporary file in the same directory as the 1000 original file. */ 1001 char tmpfname[strlen (arfname) + 7]; 1002 strcpy (stpcpy (tmpfname, arfname), "XXXXXX"); 1003 int newfd = mkstemp (tmpfname); 1004 if (unlikely (newfd == -1)) 1005 goto nonew; 1006 1007 /* Create the header. */ 1008 if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG)) 1009 { 1010 // XXX Use /prof/self/fd/%d ??? 1011 nonew_unlink: 1012 unlink (tmpfname); 1013 if (newfd != -1) 1014 close (newfd); 1015 nonew: 1016 error (0, errno, _("cannot create new file")); 1017 status = 1; 1018 goto errout; 1019 } 1020 1021 /* If the archive is empty that is all we have to do. */ 1022 if (likely (to_copy != NULL)) 1023 { 1024 /* Write the symbol table or the long file name table or both. */ 1025 if (symtab.symsnamelen != 0 1026 && ((write_retry (newfd, symtab.symsoff, symtab.symsofflen) 1027 != (ssize_t) symtab.symsofflen) 1028 || (write_retry (newfd, symtab.symsname, symtab.symsnamelen) 1029 != (ssize_t) symtab.symsnamelen))) 1030 goto nonew_unlink; 1031 1032 if (symtab.longnameslen > sizeof (struct ar_hdr) 1033 && (write_retry (newfd, symtab.longnames, symtab.longnameslen) 1034 != (ssize_t) symtab.longnameslen)) 1035 goto nonew_unlink; 1036 1037 /* NULL-terminate the list of files to copy. */ 1038 struct armem *last = to_copy; 1039 to_copy = to_copy->next; 1040 last->next = NULL; 1041 1042 off_t start = -1; 1043 off_t len = -1; 1044 1045 do 1046 if (write_member (to_copy, &start, &len, elf, cur_off, newfd) != 0) 1047 goto nonew_unlink; 1048 while ((to_copy = to_copy->next) != NULL); 1049 1050 /* Write the last part. */ 1051 if (copy_content (elf, newfd, start, len)) 1052 goto nonew_unlink; 1053 } 1054 1055 /* Set the mode of the new file to the same values the original file 1056 has. Never complain about fchown failing. But do it before 1057 setting the mode (which might be reset/ignored if the owner is 1058 wrong. */ 1059 if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; } 1060 if (fchmod (newfd, st.st_mode & ALLPERMS) != 0 1061 || close (newfd) != 0) 1062 goto nonew_unlink; 1063 newfd = -1; 1064 if (rename (tmpfname, arfname) != 0) 1065 goto nonew_unlink; 1066 1067 errout: 1068 elf_end (elf); 1069 1070 arlib_fini (); 1071 1072 close (fd); 1073 1074 not_found (argc, argv, found); 1075 1076 return status; 1077} 1078 1079 1080/* Prints the given value in the given buffer without a trailing zero char. 1081 Returns false if the given value doesn't fit in the given buffer. */ 1082static bool 1083no0print (bool ofmt, char *buf, int bufsize, long int val) 1084{ 1085 char tmpbuf[bufsize + 1]; 1086 int ret = snprintf (tmpbuf, sizeof (tmpbuf), ofmt ? "%-*lo" : "%-*ld", 1087 bufsize, val); 1088 if (ret >= (int) sizeof (tmpbuf)) 1089 return false; 1090 memcpy (buf, tmpbuf, bufsize); 1091 return true; 1092} 1093 1094 1095static int 1096do_oper_insert (int oper, const char *arfname, char **argv, int argc, 1097 const char *member) 1098{ 1099 int status = 0; 1100 Elf *elf = NULL; 1101 struct stat st; 1102 int fd = open_archive (arfname, O_RDONLY, 0, &elf, &st, oper != oper_move); 1103 1104 /* List of the files we keep. */ 1105 struct armem *all = NULL; 1106 struct armem *after_memberelem = NULL; 1107 struct armem **found = alloca (sizeof (*found) * argc); 1108 memset (found, '\0', sizeof (*found) * argc); 1109 1110 arlib_init (); 1111 1112 /* Initialize early for no_old case. */ 1113 off_t cur_off = SARMAG; 1114 1115 if (fd == -1) 1116 { 1117 if (!suppress_create_msg) 1118 fprintf (stderr, "%s: creating %s\n", 1119 program_invocation_short_name, arfname); 1120 1121 goto no_old; 1122 } 1123 1124 /* Store the names of all files from the command line in a hash 1125 table so that we can match it. Note that when no file name is 1126 given we are basically doing nothing except recreating the 1127 index. */ 1128 if (oper != oper_qappend) 1129 { 1130 if (hcreate (2 * argc) == 0) 1131 error_exit (errno, _("cannot create hash table")); 1132 1133 for (int cnt = 0; cnt < argc; ++cnt) 1134 { 1135 ENTRY entry; 1136 entry.key = full_path ? argv[cnt] : basename (argv[cnt]); 1137 entry.data = &argv[cnt]; 1138 if (hsearch (entry, ENTER) == NULL) 1139 error_exit (errno, _("cannot insert into hash table")); 1140 } 1141 } 1142 1143 /* While iterating over the current content of the archive we must 1144 determine a number of things: which archive members to keep, 1145 which are replaced, and where to insert the new members. */ 1146 Elf_Cmd cmd = ELF_C_READ_MMAP; 1147 Elf *subelf; 1148 while ((subelf = elf_begin (fd, cmd, elf)) != NULL) 1149 { 1150 Elf_Arhdr *arhdr = elf_getarhdr (subelf); 1151 1152 /* Ignore the symbol table and the long file name table here. */ 1153 if (strcmp (arhdr->ar_name, "/") == 0 1154 || strcmp (arhdr->ar_name, "//") == 0) 1155 goto next; 1156 1157 struct armem *newp = alloca (sizeof (struct armem)); 1158 newp->old_off = elf_getaroff (subelf); 1159 newp->size = arhdr->ar_size; 1160 newp->sec = arhdr->ar_date; 1161 newp->mem = NULL; 1162 1163 /* Remember long file names. */ 1164 remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name)); 1165 1166 /* Check whether this is a file we are looking for. */ 1167 if (oper != oper_qappend) 1168 { 1169 /* Check whether this is the member used as the insert point. */ 1170 if (member != NULL && strcmp (arhdr->ar_name, member) == 0) 1171 { 1172 /* Note that all == NULL means insert at the beginning. */ 1173 if (ipos == ipos_before) 1174 after_memberelem = all; 1175 else 1176 after_memberelem = newp; 1177 member = NULL; 1178 } 1179 1180 ENTRY entry; 1181 entry.key = arhdr->ar_name; 1182 ENTRY *res = hsearch (entry, FIND); 1183 if (res != NULL && found[(char **) res->data - argv] == NULL) 1184 { 1185 found[(char **) res->data - argv] = newp; 1186 1187 /* If we insert before or after a certain element move 1188 all files to a special list. */ 1189 if (unlikely (ipos != ipos_none || oper == oper_move)) 1190 { 1191 if (after_memberelem == newp) 1192 /* Since we remove this element even though we should 1193 insert everything after it, we in fact insert 1194 everything after the previous element. */ 1195 after_memberelem = all; 1196 1197 goto next; 1198 } 1199 } 1200 } 1201 1202 if (all == NULL) 1203 all = newp->next = newp; 1204 else 1205 { 1206 newp->next = all->next; 1207 all = all->next = newp; 1208 } 1209 1210 next: 1211 cmd = elf_next (subelf); 1212 if (elf_end (subelf) != 0) 1213 error_exit (0, "%s: %s", arfname, elf_errmsg (-1)); 1214 } 1215 1216 if (oper != oper_qappend) 1217 hdestroy (); 1218 1219 no_old: 1220 if (member != NULL) 1221 error_exit (0, _("position member %s not found"), 1222 member); 1223 1224 if (oper == oper_move) 1225 { 1226 /* Make sure all requested elements are found in the archive. */ 1227 for (int cnt = 0; cnt < argc; ++cnt) 1228 { 1229 if (found[cnt] == NULL) 1230 { 1231 fprintf (stderr, _("%s: no entry %s in archive!\n"), 1232 program_invocation_short_name, argv[cnt]); 1233 status = 1; 1234 } 1235 1236 if (verbose) 1237 printf ("m - %s\n", argv[cnt]); 1238 } 1239 } 1240 else 1241 { 1242 /* Open all the new files, get their sizes and add all symbols. */ 1243 for (int cnt = 0; cnt < argc; ++cnt) 1244 { 1245 const char *bname = basename (argv[cnt]); 1246 size_t bnamelen = strlen (bname); 1247 if (found[cnt] == NULL) 1248 { 1249 found[cnt] = alloca (sizeof (struct armem)); 1250 found[cnt]->old_off = -1; 1251 1252 remember_long_name (found[cnt], bname, bnamelen); 1253 } 1254 1255 struct stat newst; 1256 Elf *newelf; 1257 int newfd = open (argv[cnt], O_RDONLY); 1258 if (newfd == -1) 1259 { 1260 error (0, errno, _("cannot open %s"), argv[cnt]); 1261 status = 1; 1262 } 1263 else if (fstat (newfd, &newst) == -1) 1264 { 1265 error (0, errno, _("cannot stat %s"), argv[cnt]); 1266 close (newfd); 1267 status = 1; 1268 } 1269 else if (!S_ISREG (newst.st_mode)) 1270 { 1271 error (0, errno, _("%s is no regular file"), argv[cnt]); 1272 close (newfd); 1273 status = 1; 1274 } 1275 else if (update_newer 1276 && found[cnt]->old_off != -1l 1277 && found[cnt]->sec > st.st_mtime) 1278 /* Do nothing, the file in the archive is younger. */ 1279 close (newfd); 1280 else if ((newelf = elf_begin (newfd, ELF_C_READ_MMAP, NULL)) 1281 == NULL) 1282 { 1283 fprintf (stderr, 1284 _("cannot get ELF descriptor for %s: %s\n"), 1285 argv[cnt], elf_errmsg (-1)); 1286 status = 1; 1287 } 1288 else 1289 { 1290 if (verbose) 1291 printf ("%c - %s\n", 1292 found[cnt]->old_off == -1l ? 'a' : 'r', argv[cnt]); 1293 1294 found[cnt]->elf = newelf; 1295 found[cnt]->sec = arlib_deterministic_output ? 0 : newst.st_mtime; 1296 found[cnt]->uid = arlib_deterministic_output ? 0 : newst.st_uid; 1297 found[cnt]->gid = arlib_deterministic_output ? 0 : newst.st_gid; 1298 found[cnt]->mode = newst.st_mode; 1299 found[cnt]->name = bname; 1300 1301 found[cnt]->mem = elf_rawfile (newelf, &found[cnt]->size); 1302 if (found[cnt]->mem == NULL 1303 || elf_cntl (newelf, ELF_C_FDDONE) != 0) 1304 error_exit (0, _("cannot read %s: %s"), 1305 argv[cnt], elf_errmsg (-1)); 1306 1307 close (newfd); 1308 1309 if (found[cnt]->old_off != -1l) 1310 /* Remember long file names. */ 1311 remember_long_name (found[cnt], bname, bnamelen); 1312 } 1313 } 1314 } 1315 1316 if (status != 0) 1317 { 1318 elf_end (elf); 1319 1320 arlib_fini (); 1321 1322 close (fd); 1323 1324 return status; 1325 } 1326 1327 /* If we have no entry point so far add at the end. AFTER_MEMBERELEM 1328 being NULL when adding before an entry means add at the beginning. */ 1329 if (ipos != ipos_before && after_memberelem == NULL) 1330 after_memberelem = all; 1331 1332 /* Convert the circular list into a normal list first. */ 1333 if (all != NULL) 1334 { 1335 struct armem *tmp = all; 1336 all = all->next; 1337 tmp->next = NULL; 1338 } 1339 1340 struct armem *last_added = after_memberelem; 1341 for (int cnt = 0; cnt < argc; ++cnt) 1342 if (oper != oper_replace || found[cnt]->old_off == -1) 1343 { 1344 if (last_added == NULL) 1345 { 1346 found[cnt]->next = all; 1347 last_added = all = found[cnt]; 1348 } 1349 else 1350 { 1351 found[cnt]->next = last_added->next; 1352 last_added = last_added->next = found[cnt]; 1353 } 1354 } 1355 1356 /* Finally compute the offset and add the symbols for the files 1357 after the insert point. */ 1358 if (likely (all != NULL)) 1359 for (struct armem *memp = all; memp != NULL; memp = memp->next) 1360 { 1361 memp->off = cur_off; 1362 1363 if (memp->mem == NULL) 1364 { 1365 Elf_Arhdr *arhdr; 1366 /* Fake initializing arhdr and subelf to keep gcc calm. */ 1367 asm ("" : "=m" (arhdr), "=m" (subelf)); 1368 if (elf_rand (elf, memp->old_off) == 0 1369 || (subelf = elf_begin (fd, ELF_C_READ_MMAP, elf)) == NULL 1370 || (arhdr = elf_getarhdr (subelf)) == NULL) 1371 /* This should never happen since we already looked at the 1372 archive content. But who knows... */ 1373 error_exit (0, "%s: %s", arfname, elf_errmsg (-1)); 1374 1375 arlib_add_symbols (subelf, arfname, arhdr->ar_name, cur_off); 1376 1377 elf_end (subelf); 1378 } 1379 else 1380 arlib_add_symbols (memp->elf, arfname, memp->name, cur_off); 1381 1382 cur_off += (((memp->size + 1) & ~((off_t) 1)) 1383 + sizeof (struct ar_hdr)); 1384 } 1385 1386 /* Now we have all the information for the symbol table and long 1387 file name table. Construct the final layout. */ 1388 arlib_finalize (); 1389 1390 /* Create a new, temporary file in the same directory as the 1391 original file. */ 1392 char tmpfname[strlen (arfname) + 7]; 1393 strcpy (stpcpy (tmpfname, arfname), "XXXXXX"); 1394 int newfd; 1395 if (fd != -1) 1396 newfd = mkstemp (tmpfname); 1397 else 1398 { 1399 newfd = open (arfname, O_RDWR | O_CREAT | O_EXCL, DEFFILEMODE); 1400 if (newfd == -1 && errno == EEXIST) 1401 /* Bah, first the file did not exist, now it does. Restart. */ 1402 return do_oper_insert (oper, arfname, argv, argc, member); 1403 } 1404 if (unlikely (newfd == -1)) 1405 goto nonew; 1406 1407 /* Create the header. */ 1408 if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG)) 1409 { 1410 nonew_unlink: 1411 if (fd != -1) 1412 { 1413 // XXX Use /prof/self/fd/%d ??? 1414 unlink (tmpfname); 1415 if (newfd != -1) 1416 close (newfd); 1417 } 1418 nonew: 1419 error (0, errno, _("cannot create new file")); 1420 status = 1; 1421 goto errout; 1422 } 1423 1424 /* If the new archive is not empty we actually have something to do. */ 1425 if (likely (all != NULL)) 1426 { 1427 /* Write the symbol table or the long file name table or both. */ 1428 if (symtab.symsnamelen != 0 1429 && ((write_retry (newfd, symtab.symsoff, symtab.symsofflen) 1430 != (ssize_t) symtab.symsofflen) 1431 || (write_retry (newfd, symtab.symsname, symtab.symsnamelen) 1432 != (ssize_t) symtab.symsnamelen))) 1433 goto nonew_unlink; 1434 1435 if (symtab.longnameslen > sizeof (struct ar_hdr) 1436 && (write_retry (newfd, symtab.longnames, symtab.longnameslen) 1437 != (ssize_t) symtab.longnameslen)) 1438 goto nonew_unlink; 1439 1440 off_t start = -1; 1441 off_t len = -1; 1442 1443 while (all != NULL) 1444 { 1445 if (all->mem != NULL) 1446 { 1447 /* This is a new file. If there is anything from the 1448 archive left to be written do it now. */ 1449 if (start != -1 && copy_content (elf, newfd, start, len)) 1450 goto nonew_unlink; 1451 1452 start = -1; 1453 len = -1; 1454 1455 /* Create the header. */ 1456 struct ar_hdr arhdr; 1457 /* The ar_name is not actually zero terminated, but we 1458 need that for snprintf. Also if the name is too 1459 long, then the string starts with '/' plus an index 1460 off number (decimal). */ 1461 char tmpbuf[sizeof (arhdr.ar_name) + 2]; 1462 if (all->long_name_off == -1) 1463 { 1464 size_t namelen = strlen (all->name); 1465 char *p = mempcpy (arhdr.ar_name, all->name, namelen); 1466 *p++ = '/'; 1467 memset (p, ' ', sizeof (arhdr.ar_name) - namelen - 1); 1468 } 1469 else 1470 { 1471 snprintf (tmpbuf, sizeof (tmpbuf), "/%-*ld", 1472 (int) sizeof (arhdr.ar_name), all->long_name_off); 1473 memcpy (arhdr.ar_name, tmpbuf, sizeof (arhdr.ar_name)); 1474 } 1475 1476 if (! no0print (false, arhdr.ar_date, sizeof (arhdr.ar_date), 1477 all->sec)) 1478 { 1479 error (0, errno, _("cannot represent ar_date")); 1480 goto nonew_unlink; 1481 } 1482 if (! no0print (false, arhdr.ar_uid, sizeof (arhdr.ar_uid), 1483 all->uid)) 1484 { 1485 error (0, errno, _("cannot represent ar_uid")); 1486 goto nonew_unlink; 1487 } 1488 if (! no0print (false, arhdr.ar_gid, sizeof (arhdr.ar_gid), 1489 all->gid)) 1490 { 1491 error (0, errno, _("cannot represent ar_gid")); 1492 goto nonew_unlink; 1493 } 1494 if (! no0print (true, arhdr.ar_mode, sizeof (arhdr.ar_mode), 1495 all->mode)) 1496 { 1497 error (0, errno, _("cannot represent ar_mode")); 1498 goto nonew_unlink; 1499 } 1500 if (! no0print (false, arhdr.ar_size, sizeof (arhdr.ar_size), 1501 all->size)) 1502 { 1503 error (0, errno, _("cannot represent ar_size")); 1504 goto nonew_unlink; 1505 } 1506 memcpy (arhdr.ar_fmag, ARFMAG, sizeof (arhdr.ar_fmag)); 1507 1508 if (unlikely (write_retry (newfd, &arhdr, sizeof (arhdr)) 1509 != sizeof (arhdr))) 1510 goto nonew_unlink; 1511 1512 /* Now the file itself. */ 1513 if (unlikely (write_retry (newfd, all->mem, all->size) 1514 != (off_t) all->size)) 1515 goto nonew_unlink; 1516 1517 /* Pad the file if its size is odd. */ 1518 if ((all->size & 1) != 0) 1519 if (unlikely (write_retry (newfd, "\n", 1) != 1)) 1520 goto nonew_unlink; 1521 } 1522 else 1523 { 1524 /* This is a member from the archive. */ 1525 if (write_member (all, &start, &len, elf, cur_off, newfd) 1526 != 0) 1527 goto nonew_unlink; 1528 } 1529 1530 all = all->next; 1531 } 1532 1533 /* Write the last part. */ 1534 if (start != -1 && copy_content (elf, newfd, start, len)) 1535 goto nonew_unlink; 1536 } 1537 1538 /* Set the mode of the new file to the same values the original file 1539 has. */ 1540 if (fd != -1) 1541 { 1542 /* Never complain about fchown failing. But do it before 1543 setting the modes, or they might be reset/ignored if the 1544 owner is wrong. */ 1545 if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; } 1546 if (fchmod (newfd, st.st_mode & ALLPERMS) != 0 1547 || close (newfd) != 0) 1548 goto nonew_unlink; 1549 newfd = -1; 1550 if (rename (tmpfname, arfname) != 0) 1551 goto nonew_unlink; 1552 } 1553 1554 errout: 1555 for (int cnt = 0; cnt < argc; ++cnt) 1556 elf_end (found[cnt]->elf); 1557 1558 elf_end (elf); 1559 1560 arlib_fini (); 1561 1562 if (fd != -1) 1563 close (fd); 1564 1565 if (newfd != -1) 1566 close (newfd); 1567 1568 return status; 1569} 1570 1571 1572#include "debugpred.h" 1573