LCOV - code coverage report
Current view: top level - src - ar.c (source / functions) Hit Total Coverage
Test: elfutils-0.174 Lines: 256 676 37.9 %
Date: 2018-09-14 13:30:33 Functions: 8 11 72.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13