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