Home | History | Annotate | Download | only in src
      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