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