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