LCOV - code coverage report
Current view: top level - src - ar.c (source / functions) Hit Total Coverage
Test: elfutils-0.187 Lines: 281 750 37.5 %
Date: 2022-04-26 02:07:47 Functions: 8 11 72.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 134 545 24.6 %

           Branch data     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                 :          4 :   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, _("\
     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, _("\
     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, _("\
     202                 :            : 'N' is only meaningful with the 'x' and 'd' options"));
     203                 :            : 
     204         [ #  # ]:          0 :       if (remaining == argc)
     205                 :            :         {
     206                 :          0 :           error (0, 0, _("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                 :          0 :       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, _("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, _("'%c' is only meaningful with the 'x' option"),
     226         [ #  # ]:          0 :            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, _("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                 :          4 :   int status;
     241   [ -  +  -  +  :          4 :   switch (operation)
                   +  - ]
     242                 :            :     {
     243                 :          0 :     case oper_none:
     244                 :          0 :       error (0, 0, _("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                 :          4 :   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, _("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 (errno, _("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 (0, _("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 (0, _("%s: not an archive file"), arfname);
     404                 :            :     }
     405                 :            : 
     406   [ +  +  -  + ]:          4 :   if (st != NULL && fstat (fd, st) != 0)
     407                 :          0 :     error_exit (errno, _("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         [ +  + ]:         22 :   for (int i = 0; i < argc; ++i)
     418         [ -  + ]:         19 :     if (!found[i])
     419                 :         19 :       printf (_("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                 :          0 :   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                 :            : static inline bool
     440                 :          0 : should_truncate_fname (size_t *name_max)
     441                 :            : {
     442   [ #  #  #  # ]:          0 :   if (errno == ENAMETOOLONG && allow_truncate_fname)
     443                 :            :     {
     444         [ #  # ]:          0 :       if (*name_max == 0)
     445                 :            :         {
     446                 :          0 :           long int len = pathconf (".", _PC_NAME_MAX);
     447         [ #  # ]:          0 :           if (len > 0)
     448                 :          0 :             *name_max = len;
     449                 :            :         }
     450                 :          0 :       return *name_max != 0;
     451                 :            :     }
     452                 :            :   return false;
     453                 :            : }
     454                 :            : 
     455                 :            : static int
     456                 :          2 : do_oper_extract (int oper, const char *arfname, char **argv, int argc,
     457                 :            :                  long int instance)
     458                 :          2 : {
     459                 :          2 :   bool found[argc > 0 ? argc : 1];
     460                 :          2 :   memset (found, '\0', sizeof (found));
     461                 :            : 
     462                 :          2 :   size_t name_max = 0;
     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                 :          2 :   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 (errno, _("cannot create hash table"));
     473                 :            : 
     474         [ -  + ]:          2 :   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 (errno, _("cannot insert into hash table"));
     479                 :            :     }
     480                 :            : 
     481                 :          2 :   struct stat st;
     482         [ -  + ]:          2 :   if (force_symtab)
     483                 :            :     {
     484         [ #  # ]:          0 :       if (fstat (fd, &st) != 0)
     485                 :            :         {
     486                 :          0 :           error (0, errno, _("cannot stat '%s'"), arfname);
     487                 :          0 :           close (fd);
     488                 :          0 :           return 1;
     489                 :            :         }
     490                 :          0 :       arlib_init ();
     491                 :            :     }
     492                 :            : 
     493                 :            :   Elf_Cmd cmd = ELF_C_READ_MMAP;
     494                 :            :   Elf *subelf;
     495         [ +  + ]:         22 :   while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
     496                 :            :     {
     497                 :         20 :       Elf_Arhdr *arhdr = elf_getarhdr (subelf);
     498                 :            : 
     499         [ +  + ]:         20 :       if (strcmp (arhdr->ar_name, "/") == 0)
     500                 :            :         {
     501                 :          1 :           index_off = elf_getaroff (subelf);
     502                 :          1 :           index_size = arhdr->ar_size;
     503                 :          1 :           goto next;
     504                 :            :         }
     505         [ -  + ]:         19 :       if (strcmp (arhdr->ar_name, "//") == 0)
     506                 :          0 :         goto next;
     507                 :            : 
     508         [ -  + ]:         19 :       if (force_symtab)
     509                 :            :         {
     510                 :          0 :           arlib_add_symbols (elf, arfname, arhdr->ar_name, cur_off);
     511                 :          0 :           cur_off += (((arhdr->ar_size + 1) & ~((off_t) 1))
     512                 :            :                       + sizeof (struct ar_hdr));
     513                 :            :         }
     514                 :            : 
     515                 :         19 :       bool do_extract = argc <= 0;
     516         [ -  + ]:         19 :       if (!do_extract)
     517                 :            :         {
     518                 :          0 :           ENTRY entry;
     519                 :          0 :           entry.key = arhdr->ar_name;
     520                 :          0 :           ENTRY *res = hsearch (entry, FIND);
     521   [ #  #  #  #  :          0 :           if (res != NULL && (instance < 0 || instance-- == 0)
                   #  # ]
     522         [ #  # ]:          0 :               && !found[(char **) res->data - argv])
     523                 :          0 :             found[(char **) res->data - argv] = do_extract = true;
     524                 :            :         }
     525                 :            : 
     526         [ -  + ]:         19 :       if (do_extract)
     527                 :            :         {
     528         [ -  + ]:         19 :           if (verbose)
     529                 :            :             {
     530         [ #  # ]:          0 :               if (oper == oper_print)
     531                 :            :                 {
     532                 :          0 :                   printf ("\n<%s>\n\n", arhdr->ar_name);
     533                 :            : 
     534                 :            :                   /* We have to flush now because now we use the descriptor
     535                 :            :                      directly.  */
     536                 :          0 :                   fflush (stdout);
     537                 :            :                 }
     538         [ #  # ]:          0 :               else if (oper == oper_list)
     539                 :            :                 {
     540                 :          0 :                   char datestr[100];
     541                 :          0 :                   struct tm *tp = localtime (&arhdr->ar_date);
     542         [ #  # ]:          0 :                   if (tp == NULL)
     543                 :            :                     {
     544                 :          0 :                       time_t time = 0;
     545                 :          0 :                       tp = localtime (&time);
     546                 :            :                     }
     547                 :            : 
     548                 :          0 :                   strftime (datestr, sizeof (datestr), "%b %e %H:%M %Y", tp);
     549                 :            : 
     550                 :          0 :                   printf ("%c%c%c%c%c%c%c%c%c %u/%u %6ju %s %s\n",
     551         [ #  # ]:          0 :                           (arhdr->ar_mode & S_IRUSR) ? 'r' : '-',
     552         [ #  # ]:          0 :                           (arhdr->ar_mode & S_IWUSR) ? 'w' : '-',
     553         [ #  # ]:          0 :                           (arhdr->ar_mode & S_IXUSR)
     554         [ #  # ]:          0 :                           ? ((arhdr->ar_mode & S_ISUID) ? 's' : 'x')
     555         [ #  # ]:          0 :                           : ((arhdr->ar_mode & S_ISUID) ? 'S' : '-'),
     556         [ #  # ]:          0 :                           (arhdr->ar_mode & S_IRGRP) ? 'r' : '-',
     557         [ #  # ]:          0 :                           (arhdr->ar_mode & S_IWGRP) ? 'w' : '-',
     558         [ #  # ]:          0 :                           (arhdr->ar_mode & S_IXGRP)
     559         [ #  # ]:          0 :                           ? ((arhdr->ar_mode & S_ISGID) ? 's' : 'x')
     560         [ #  # ]:          0 :                           : ((arhdr->ar_mode & S_ISGID) ? 'S' : '-'),
     561         [ #  # ]:          0 :                           (arhdr->ar_mode & S_IROTH) ? 'r' : '-',
     562         [ #  # ]:          0 :                           (arhdr->ar_mode & S_IWOTH) ? 'w' : '-',
     563         [ #  # ]:          0 :                           (arhdr->ar_mode & S_IXOTH)
     564         [ #  # ]:          0 :                           ? ((arhdr->ar_mode & S_ISVTX) ? 't' : 'x')
     565         [ #  # ]:          0 :                           : ((arhdr->ar_mode & S_ISVTX) ? 'T' : '-'),
     566                 :            :                           arhdr->ar_uid,
     567                 :            :                           arhdr->ar_gid,
     568                 :          0 :                           (uintmax_t) arhdr->ar_size,
     569                 :            :                           datestr,
     570                 :            :                           arhdr->ar_name);
     571                 :            :                 }
     572                 :            :               else
     573                 :          0 :                 printf ("x - %s\n", arhdr->ar_name);
     574                 :            :             }
     575                 :            : 
     576         [ +  - ]:         19 :           if (oper == oper_list)
     577                 :            :             {
     578         [ +  - ]:         19 :               if (!verbose)
     579                 :         19 :                 puts (arhdr->ar_name);
     580                 :            : 
     581                 :         19 :               goto next;
     582                 :            :             }
     583                 :            : 
     584                 :          0 :           size_t nleft;
     585                 :          0 :           char *data = elf_rawfile (subelf, &nleft);
     586         [ #  # ]:          0 :           if (data == NULL)
     587                 :            :             {
     588                 :          0 :               error (0, 0, _("cannot read content of %s: %s"),
     589                 :            :                      arhdr->ar_name, elf_errmsg (-1));
     590                 :          0 :               status = 1;
     591                 :          0 :               goto next;
     592                 :            :             }
     593                 :            : 
     594                 :          0 :           int xfd;
     595                 :          0 :           char tempfname[] = "XXXXXX";
     596                 :          0 :           bool use_mkstemp = true;
     597                 :            : 
     598         [ #  # ]:          0 :           if (oper == oper_print)
     599                 :          0 :             xfd = STDOUT_FILENO;
     600                 :            :           else
     601                 :            :             {
     602                 :          0 :               xfd = mkstemp (tempfname);
     603         [ #  # ]:          0 :               if (unlikely (xfd == -1))
     604                 :            :                 {
     605                 :            :                   /* We cannot create a temporary file.  Try to overwrite
     606                 :            :                      the file or create it if it does not exist.  */
     607                 :          0 :                   int flags = O_WRONLY | O_CREAT;
     608         [ #  # ]:          0 :                   if (dont_replace_existing)
     609                 :            :                     flags |= O_EXCL;
     610                 :            :                   else
     611                 :          0 :                     flags |= O_TRUNC;
     612         [ #  # ]:          0 :                   xfd = open (arhdr->ar_name, flags, 0600);
     613         [ #  # ]:          0 :                   if (unlikely (xfd == -1))
     614                 :            :                     {
     615                 :          0 :                       int printlen = INT_MAX;
     616                 :            : 
     617         [ #  # ]:          0 :                       if (should_truncate_fname (&name_max))
     618                 :          0 :                         {
     619                 :            :                           /* Try to truncate the name.  First find out by how
     620                 :            :                              much.  */
     621                 :          0 :                           printlen = name_max;
     622                 :          0 :                           char truncfname[name_max + 1];
     623         [ #  # ]:          0 :                           *((char *) mempcpy (truncfname, arhdr->ar_name,
     624                 :          0 :                                               name_max)) = '\0';
     625                 :            : 
     626         [ #  # ]:          0 :                           xfd = open (truncfname, flags, 0600);
     627                 :            :                         }
     628                 :            : 
     629         [ #  # ]:          0 :                       if (xfd == -1)
     630                 :            :                         {
     631                 :          0 :                           error (0, errno, _("cannot open %.*s"),
     632                 :            :                                  (int) printlen, arhdr->ar_name);
     633                 :          0 :                           status = 1;
     634                 :          0 :                           goto next;
     635                 :            :                         }
     636                 :            :                     }
     637                 :            : 
     638                 :          0 :                   use_mkstemp = false;
     639                 :            :                 }
     640                 :            :             }
     641                 :            : 
     642                 :            :           ssize_t n;
     643   [ #  #  #  #  :          0 :           while ((n = TEMP_FAILURE_RETRY (write (xfd, data, nleft))) != -1)
                   #  # ]
     644                 :            :             {
     645                 :          0 :               nleft -= n;
     646         [ #  # ]:          0 :               if (nleft == 0)
     647                 :            :                 break;
     648                 :          0 :               data += n;
     649                 :            :             }
     650                 :            : 
     651         [ #  # ]:          0 :           if (unlikely (n == -1))
     652                 :            :             {
     653                 :          0 :               error (0, errno, _("failed to write %s"), arhdr->ar_name);
     654                 :          0 :               status = 1;
     655                 :          0 :               unlink (tempfname);
     656                 :          0 :               close (xfd);
     657                 :          0 :               goto next;
     658                 :            :             }
     659                 :            : 
     660         [ #  # ]:          0 :           if (oper != oper_print)
     661                 :            :             {
     662                 :            :               /* Fix up the mode.  */
     663         [ #  # ]:          0 :               if (unlikely (fchmod (xfd, arhdr->ar_mode) != 0))
     664                 :            :                 {
     665                 :          0 :                   error (0, errno, _("cannot change mode of %s"),
     666                 :            :                          arhdr->ar_name);
     667                 :          0 :                   status = 0;
     668                 :            :                 }
     669                 :            : 
     670         [ #  # ]:          0 :               if (preserve_dates)
     671                 :            :                 {
     672                 :          0 :                   struct timespec tv[2];
     673                 :          0 :                   tv[0].tv_sec = arhdr->ar_date;
     674                 :          0 :                   tv[0].tv_nsec = 0;
     675                 :          0 :                   tv[1].tv_sec = arhdr->ar_date;
     676                 :          0 :                   tv[1].tv_nsec = 0;
     677                 :            : 
     678         [ #  # ]:          0 :                   if (unlikely (futimens (xfd, tv) != 0))
     679                 :            :                     {
     680                 :          0 :                       error (0, errno,
     681                 :          0 :                              _("cannot change modification time of %s"),
     682                 :            :                              arhdr->ar_name);
     683                 :          0 :                       status = 1;
     684                 :            :                     }
     685                 :            :                 }
     686                 :            : 
     687                 :            :               /* If we used a temporary file, move it do the right
     688                 :            :                  name now.  */
     689         [ #  # ]:          0 :               if (use_mkstemp)
     690                 :            :                 {
     691                 :          0 :                   int r;
     692                 :            : 
     693         [ #  # ]:          0 :                   if (dont_replace_existing)
     694                 :            :                     {
     695                 :          0 :                       r = link (tempfname, arhdr->ar_name);
     696         [ #  # ]:          0 :                       if (likely (r == 0))
     697                 :          0 :                         unlink (tempfname);
     698                 :            :                     }
     699                 :            :                   else
     700                 :          0 :                     r = rename (tempfname, arhdr->ar_name);
     701                 :            : 
     702         [ #  # ]:          0 :                   if (unlikely (r) != 0)
     703                 :            :                     {
     704                 :          0 :                       int printlen = INT_MAX;
     705                 :            : 
     706         [ #  # ]:          0 :                       if (should_truncate_fname (&name_max))
     707                 :          0 :                         {
     708                 :            :                           /* Try to truncate the name.  First find out by how
     709                 :            :                              much.  */
     710                 :          0 :                           printlen = name_max;
     711                 :          0 :                           char truncfname[name_max + 1];
     712         [ #  # ]:          0 :                           *((char *) mempcpy (truncfname, arhdr->ar_name,
     713                 :          0 :                                               name_max)) = '\0';
     714                 :            : 
     715         [ #  # ]:          0 :                           if (dont_replace_existing)
     716                 :            :                             {
     717                 :          0 :                               r = link (tempfname, truncfname);
     718         [ #  # ]:          0 :                               if (likely (r == 0))
     719                 :          0 :                                 unlink (tempfname);
     720                 :            :                             }
     721                 :            :                           else
     722                 :          0 :                             r = rename (tempfname, truncfname);
     723                 :            :                         }
     724                 :            : 
     725         [ #  # ]:          0 :                       if (r != 0)
     726                 :            :                         {
     727                 :          0 :                           error (0, errno, _("\
     728                 :            : cannot rename temporary file to %.*s"),
     729                 :            :                                  printlen, arhdr->ar_name);
     730                 :          0 :                           unlink (tempfname);
     731                 :          0 :                           status = 1;
     732                 :            :                         }
     733                 :            :                     }
     734                 :            :                 }
     735                 :            : 
     736                 :          0 :               close (xfd);
     737                 :            :             }
     738                 :            :         }
     739                 :            : 
     740                 :          0 :     next:
     741                 :         20 :       cmd = elf_next (subelf);
     742         [ -  + ]:         20 :       if (elf_end (subelf) != 0)
     743                 :          0 :         error (1, 0, "%s: %s", arfname, elf_errmsg (-1));
     744                 :            :     }
     745                 :            : 
     746                 :          2 :   hdestroy ();
     747                 :            : 
     748         [ -  + ]:          2 :   if (force_symtab)
     749                 :            :     {
     750                 :          0 :       arlib_finalize ();
     751                 :            : 
     752                 :          0 :       if (symtab.symsnamelen != 0
     753                 :            :           /* We have to rewrite the file also if it initially had an index
     754                 :            :              but now does not need one anymore.  */
     755         [ #  # ]:          0 :           || (symtab.symsnamelen == 0 && index_size != 0))
     756                 :          0 :         {
     757                 :          0 :           char tmpfname[strlen (arfname) + 7];
     758                 :          0 :           strcpy (stpcpy (tmpfname, arfname), "XXXXXX");
     759                 :          0 :           int newfd = mkstemp (tmpfname);
     760         [ #  # ]:          0 :           if (unlikely (newfd == -1))
     761                 :            :             {
     762                 :          0 :             nonew:
     763                 :          0 :               error (0, errno, _("cannot create new file"));
     764                 :          0 :               status = 1;
     765                 :            :             }
     766                 :            :           else
     767                 :            :             {
     768                 :            :               /* Create the header.  */
     769         [ #  # ]:          0 :               if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
     770                 :            :                 {
     771                 :            :                   // XXX Use /prof/self/fd/%d ???
     772                 :          0 :                 nonew_unlink:
     773                 :          0 :                   unlink (tmpfname);
     774         [ #  # ]:          0 :                   if (newfd != -1)
     775                 :          0 :                     close (newfd);
     776                 :          0 :                   goto nonew;
     777                 :            :                 }
     778                 :            : 
     779                 :            :               /* Create the new file.  There are three parts as far we are
     780                 :            :                  concerned: 1. original context before the index, 2. the
     781                 :            :                  new index, 3. everything after the new index.  */
     782                 :          0 :               off_t rest_off;
     783         [ #  # ]:          0 :               if (index_off != -1)
     784                 :          0 :                 rest_off = (index_off + sizeof (struct ar_hdr)
     785                 :          0 :                             + ((index_size + 1) & ~1ul));
     786                 :            :               else
     787                 :            :                 rest_off = SARMAG;
     788                 :            : 
     789         [ #  # ]:          0 :               if (symtab.symsnamelen != 0
     790                 :          0 :                    && ((write_retry (newfd, symtab.symsoff,
     791                 :            :                                      symtab.symsofflen)
     792         [ #  # ]:          0 :                         != (ssize_t) symtab.symsofflen)
     793                 :          0 :                        || (write_retry (newfd, symtab.symsname,
     794                 :            :                                         symtab.symsnamelen)
     795         [ #  # ]:          0 :                            != (ssize_t) symtab.symsnamelen)))
     796                 :          0 :                 goto nonew_unlink;
     797                 :            :               /* Even if the original file had content before the
     798                 :            :                  symbol table, we write it in the correct order.  */
     799         [ #  # ]:          0 :               if ((index_off != SARMAG
     800         [ #  # ]:          0 :                    && copy_content (elf, newfd, SARMAG, index_off - SARMAG))
     801         [ #  # ]:          0 :                   || copy_content (elf, newfd, rest_off, st.st_size - rest_off))
     802                 :          0 :                 goto nonew_unlink;
     803                 :            : 
     804                 :            :               /* Never complain about fchown failing.  */
     805                 :          0 :               if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; }
     806                 :            :               /* Set the mode of the new file to the same values the
     807                 :            :                  original file has.  */
     808         [ #  # ]:          0 :               if (fchmod (newfd, st.st_mode & ALLPERMS) != 0
     809         [ #  # ]:          0 :                   || close (newfd) != 0)
     810                 :          0 :                 goto nonew_unlink;
     811                 :          0 :               newfd = -1;
     812         [ #  # ]:          0 :               if (rename (tmpfname, arfname) != 0)
     813                 :          0 :                 goto nonew_unlink;
     814                 :            :             }
     815                 :            :         }
     816                 :            :     }
     817                 :            : 
     818                 :          2 :   elf_end (elf);
     819                 :            : 
     820                 :          2 :   close (fd);
     821                 :            : 
     822                 :          2 :   not_found (argc, argv, found);
     823                 :            : 
     824                 :          2 :   return status;
     825                 :            : }
     826                 :            : 
     827                 :            : 
     828                 :            : struct armem
     829                 :            : {
     830                 :            :   off_t off;
     831                 :            :   off_t old_off;
     832                 :            :   size_t size;
     833                 :            :   long int long_name_off;
     834                 :            :   struct armem *next;
     835                 :            :   void *mem;
     836                 :            :   time_t sec;
     837                 :            :   uid_t uid;
     838                 :            :   gid_t gid;
     839                 :            :   mode_t mode;
     840                 :            :   const char *name;
     841                 :            :   Elf *elf;
     842                 :            : };
     843                 :            : 
     844                 :            : 
     845                 :            : static int
     846                 :          0 : write_member (struct armem *memb, off_t *startp, off_t *lenp, Elf *elf,
     847                 :            :               off_t end_off, int newfd)
     848                 :            : {
     849                 :          0 :   struct ar_hdr arhdr;
     850                 :            :   /* The ar_name is not actually zero terminated, but we need that for
     851                 :            :      snprintf.  Also if the name is too long, then the string starts
     852                 :            :      with '/' plus an index off number (decimal).  */
     853                 :          0 :   char tmpbuf[sizeof (arhdr.ar_name) + 2];
     854                 :            : 
     855                 :          0 :   bool changed_header = memb->long_name_off != -1;
     856         [ #  # ]:          0 :   if (changed_header)
     857                 :            :     {
     858                 :            :       /* In case of a long file name we assume the archive header
     859                 :            :          changed and we write it here.  */
     860                 :          0 :       memcpy (&arhdr, elf_rawfile (elf, NULL) + *startp, sizeof (arhdr));
     861                 :            : 
     862                 :          0 :       snprintf (tmpbuf, sizeof (tmpbuf), "/%-*ld",
     863                 :            :                 (int) sizeof (arhdr.ar_name), memb->long_name_off);
     864                 :          0 :       changed_header = memcmp (arhdr.ar_name, tmpbuf,
     865                 :            :                                sizeof (arhdr.ar_name)) != 0;
     866                 :            :     }
     867                 :            : 
     868                 :            :   /* If the files are adjacent in the old file extend the range.  */
     869   [ #  #  #  #  :          0 :   if (*startp != -1 && !changed_header && *startp + *lenp == memb->old_off)
                   #  # ]
     870                 :            :     {
     871                 :            :       /* Extend the current range.  */
     872                 :          0 :       *lenp += (memb->next != NULL
     873         [ #  # ]:          0 :                 ? memb->next->off : end_off) - memb->off;
     874                 :          0 :       return 0;
     875                 :            :     }
     876                 :            : 
     877                 :            :   /* Write out the old range.  */
     878   [ #  #  #  # ]:          0 :   if (*startp != -1 && copy_content (elf, newfd, *startp, *lenp))
     879                 :            :     return -1;
     880                 :            : 
     881                 :          0 :   *startp = memb->old_off;
     882         [ #  # ]:          0 :   *lenp = (memb->next != NULL ? memb->next->off : end_off) - memb->off;
     883                 :            : 
     884         [ #  # ]:          0 :   if (changed_header)
     885                 :            :     {
     886                 :          0 :       memcpy (arhdr.ar_name, tmpbuf, sizeof (arhdr.ar_name));
     887                 :            : 
     888         [ #  # ]:          0 :       if (unlikely (write_retry (newfd, &arhdr, sizeof (arhdr))
     889                 :            :                     != sizeof (arhdr)))
     890                 :            :         return -1;
     891                 :            : 
     892                 :          0 :       *startp += sizeof (struct ar_hdr);
     893         [ #  # ]:          0 :       assert ((size_t) *lenp >= sizeof (struct ar_hdr));
     894                 :          0 :       *lenp -= sizeof (struct ar_hdr);
     895                 :            :     }
     896                 :            : 
     897                 :            :   return 0;
     898                 :            : }
     899                 :            : 
     900                 :            : /* Store the name in the long name table if necessary.
     901                 :            :    Record its offset or -1 if we did not need to use the table.  */
     902                 :            : static void
     903                 :         19 : remember_long_name (struct armem *mem, const char *name, size_t namelen)
     904                 :            : {
     905                 :         38 :   mem->long_name_off = (namelen > MAX_AR_NAME_LEN
     906                 :          0 :                         ? arlib_add_long_name (name, namelen)
     907                 :         19 :                         : -1l);
     908                 :         19 : }
     909                 :            : 
     910                 :            : static int
     911                 :          1 : do_oper_delete (const char *arfname, char **argv, int argc,
     912                 :            :                 long int instance)
     913                 :            : {
     914                 :          1 :   bool *found = alloca (sizeof (bool) * argc);
     915                 :          1 :   memset (found, '\0', sizeof (bool) * argc);
     916                 :            : 
     917                 :            :   /* List of the files we keep.  */
     918                 :          1 :   struct armem *to_copy = NULL;
     919                 :            : 
     920                 :          1 :   int status = 0;
     921                 :          1 :   Elf *elf;
     922                 :          1 :   struct stat st;
     923                 :          1 :   int fd = open_archive (arfname, O_RDONLY, 0, &elf, &st, false);
     924                 :            : 
     925         [ -  + ]:          1 :   if (hcreate (2 * argc) == 0)
     926                 :          0 :     error_exit (errno, _("cannot create hash table"));
     927                 :            : 
     928         [ +  + ]:         20 :   for (int cnt = 0; cnt < argc; ++cnt)
     929                 :            :     {
     930                 :         19 :       ENTRY entry = { .key = argv[cnt], .data = &argv[cnt] };
     931         [ -  + ]:         19 :       if (hsearch (entry, ENTER) == NULL)
     932                 :         19 :         error_exit (errno, _("cannot insert into hash table"));
     933                 :            :     }
     934                 :            : 
     935                 :          1 :   arlib_init ();
     936                 :            : 
     937                 :          1 :   off_t cur_off = SARMAG;
     938                 :          1 :   Elf_Cmd cmd = ELF_C_READ_MMAP;
     939                 :          1 :   Elf *subelf;
     940         [ +  + ]:         21 :   while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
     941                 :            :     {
     942                 :         20 :       Elf_Arhdr *arhdr = elf_getarhdr (subelf);
     943                 :            : 
     944                 :            :       /* Ignore the symbol table and the long file name table here.  */
     945         [ +  + ]:         20 :       if (strcmp (arhdr->ar_name, "/") == 0
     946         [ -  + ]:         19 :           || strcmp (arhdr->ar_name, "//") == 0)
     947                 :          1 :         goto next;
     948                 :            : 
     949                 :         19 :       bool do_delete = argc <= 0;
     950         [ +  - ]:         19 :       if (!do_delete)
     951                 :            :         {
     952                 :         19 :           ENTRY entry;
     953                 :         19 :           entry.key = arhdr->ar_name;
     954                 :         19 :           ENTRY *res = hsearch (entry, FIND);
     955   [ +  -  -  +  :         19 :           if (res != NULL && (instance < 0 || instance-- == 0)
                   -  - ]
     956         [ +  - ]:         19 :               && !found[(char **) res->data - argv])
     957                 :         19 :             found[(char **) res->data - argv] = do_delete = true;
     958                 :            :         }
     959                 :            : 
     960         [ -  - ]:         19 :       if (do_delete)
     961                 :            :         {
     962         [ -  + ]:         19 :           if (verbose)
     963                 :          0 :             printf ("d - %s\n", arhdr->ar_name);
     964                 :            :         }
     965                 :            :       else
     966                 :            :         {
     967                 :          0 :           struct armem *newp = alloca (sizeof (struct armem));
     968                 :          0 :           newp->old_off = elf_getaroff (subelf);
     969                 :          0 :           newp->off = cur_off;
     970                 :            : 
     971                 :          0 :           cur_off += (((arhdr->ar_size + 1) & ~((off_t) 1))
     972                 :            :                       + sizeof (struct ar_hdr));
     973                 :            : 
     974         [ #  # ]:          0 :           if (to_copy == NULL)
     975                 :          0 :             to_copy = newp->next = newp;
     976                 :            :           else
     977                 :            :             {
     978                 :          0 :               newp->next = to_copy->next;
     979                 :          0 :               to_copy = to_copy->next = newp;
     980                 :            :             }
     981                 :            : 
     982                 :            :           /* If we recreate the symbol table read the file's symbol
     983                 :            :              table now.  */
     984                 :          0 :           arlib_add_symbols (subelf, arfname, arhdr->ar_name, newp->off);
     985                 :            : 
     986                 :            :           /* Remember long file names.  */
     987         [ #  # ]:          0 :           remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name));
     988                 :            :         }
     989                 :            : 
     990                 :         20 :     next:
     991                 :         20 :       cmd = elf_next (subelf);
     992         [ -  + ]:         20 :       if (elf_end (subelf) != 0)
     993                 :          0 :         error (1, 0, "%s: %s", arfname, elf_errmsg (-1));
     994                 :            :     }
     995                 :            : 
     996                 :          1 :   arlib_finalize ();
     997                 :            : 
     998                 :          1 :   hdestroy ();
     999                 :            : 
    1000                 :            :   /* Create a new, temporary file in the same directory as the
    1001                 :            :      original file.  */
    1002                 :          1 :   char tmpfname[strlen (arfname) + 7];
    1003                 :          1 :   strcpy (stpcpy (tmpfname, arfname), "XXXXXX");
    1004                 :          1 :   int newfd = mkstemp (tmpfname);
    1005         [ -  + ]:          1 :   if (unlikely (newfd == -1))
    1006                 :          0 :     goto nonew;
    1007                 :            : 
    1008                 :            :   /* Create the header.  */
    1009         [ -  + ]:          1 :   if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
    1010                 :            :     {
    1011                 :            :       // XXX Use /prof/self/fd/%d ???
    1012                 :          0 :     nonew_unlink:
    1013                 :          0 :       unlink (tmpfname);
    1014         [ #  # ]:          0 :       if (newfd != -1)
    1015                 :          0 :         close (newfd);
    1016                 :          0 :     nonew:
    1017                 :          0 :       error (0, errno, _("cannot create new file"));
    1018                 :          0 :       status = 1;
    1019                 :          0 :       goto errout;
    1020                 :            :     }
    1021                 :            : 
    1022                 :            :   /* If the archive is empty that is all we have to do.  */
    1023         [ -  + ]:          1 :   if (likely (to_copy != NULL))
    1024                 :            :     {
    1025                 :            :       /* Write the symbol table or the long file name table or both.  */
    1026         [ #  # ]:          0 :       if (symtab.symsnamelen != 0
    1027                 :          0 :           && ((write_retry (newfd, symtab.symsoff, symtab.symsofflen)
    1028         [ #  # ]:          0 :                != (ssize_t) symtab.symsofflen)
    1029                 :          0 :               || (write_retry (newfd, symtab.symsname, symtab.symsnamelen)
    1030         [ #  # ]:          0 :                   != (ssize_t) symtab.symsnamelen)))
    1031                 :          0 :         goto nonew_unlink;
    1032                 :            : 
    1033         [ #  # ]:          0 :       if (symtab.longnameslen > sizeof (struct ar_hdr)
    1034                 :          0 :           && (write_retry (newfd, symtab.longnames, symtab.longnameslen)
    1035         [ #  # ]:          0 :               != (ssize_t) symtab.longnameslen))
    1036                 :          0 :         goto nonew_unlink;
    1037                 :            : 
    1038                 :            :       /* NULL-terminate the list of files to copy.  */
    1039                 :          0 :       struct armem *last = to_copy;
    1040                 :          0 :       to_copy = to_copy->next;
    1041                 :          0 :       last->next = NULL;
    1042                 :            : 
    1043                 :          0 :       off_t start = -1;
    1044                 :          0 :       off_t len = -1;
    1045                 :            : 
    1046                 :          0 :       do
    1047         [ #  # ]:          0 :         if (write_member (to_copy, &start, &len, elf, cur_off, newfd) != 0)
    1048                 :          0 :           goto nonew_unlink;
    1049         [ #  # ]:          0 :       while ((to_copy = to_copy->next) != NULL);
    1050                 :            : 
    1051                 :            :       /* Write the last part.  */
    1052         [ #  # ]:          0 :       if (copy_content (elf, newfd, start, len))
    1053                 :          0 :         goto nonew_unlink;
    1054                 :            :     }
    1055                 :            : 
    1056                 :            :   /* Set the mode of the new file to the same values the original file
    1057                 :            :      has.  Never complain about fchown failing.  But do it before
    1058                 :            :      setting the mode (which might be reset/ignored if the owner is
    1059                 :            :      wrong.  */
    1060                 :          1 :   if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; }
    1061         [ +  - ]:          1 :   if (fchmod (newfd, st.st_mode & ALLPERMS) != 0
    1062         [ -  + ]:          1 :       || close (newfd) != 0)
    1063                 :          0 :     goto nonew_unlink;
    1064                 :          1 :   newfd = -1;
    1065         [ -  + ]:          1 :   if (rename (tmpfname, arfname) != 0)
    1066                 :          0 :     goto nonew_unlink;
    1067                 :            : 
    1068                 :          1 :  errout:
    1069                 :          1 :   elf_end (elf);
    1070                 :            : 
    1071                 :          1 :   arlib_fini ();
    1072                 :            : 
    1073                 :          1 :   close (fd);
    1074                 :            : 
    1075                 :          1 :   not_found (argc, argv, found);
    1076                 :            : 
    1077                 :          1 :   return status;
    1078                 :            : }
    1079                 :            : 
    1080                 :            : 
    1081                 :            : /* Prints the given value in the given buffer without a trailing zero char.
    1082                 :            :    Returns false if the given value doesn't fit in the given buffer.  */
    1083                 :            : static bool
    1084                 :         95 : no0print (bool ofmt, char *buf, int bufsize, long int val)
    1085                 :         95 : {
    1086                 :         95 :   char tmpbuf[bufsize + 1];
    1087         [ +  + ]:         95 :   int ret = snprintf (tmpbuf, sizeof (tmpbuf), ofmt ? "%-*lo" : "%-*ld",
    1088                 :            :                       bufsize, val);
    1089         [ +  - ]:         95 :   if (ret >= (int) sizeof (tmpbuf))
    1090                 :            :     return false;
    1091                 :         95 :   memcpy (buf, tmpbuf, bufsize);
    1092                 :         95 :   return true;
    1093                 :            : }
    1094                 :            : 
    1095                 :            : 
    1096                 :            : static int
    1097                 :          1 : do_oper_insert (int oper, const char *arfname, char **argv, int argc,
    1098                 :            :                 const char *member)
    1099                 :            : {
    1100                 :          1 :   int status = 0;
    1101                 :          1 :   Elf *elf = NULL;
    1102                 :          1 :   struct stat st;
    1103                 :          1 :   int fd = open_archive (arfname, O_RDONLY, 0, &elf, &st, oper != oper_move);
    1104                 :            : 
    1105                 :            :   /* List of the files we keep.  */
    1106                 :          1 :   struct armem *all = NULL;
    1107                 :          1 :   struct armem *after_memberelem = NULL;
    1108                 :          1 :   struct armem **found = alloca (sizeof (*found) * argc);
    1109                 :          1 :   memset (found, '\0', sizeof (*found) * argc);
    1110                 :            : 
    1111                 :          1 :   arlib_init ();
    1112                 :            : 
    1113                 :            :   /* Initialize early for no_old case.  */
    1114                 :          1 :   off_t cur_off = SARMAG;
    1115                 :            : 
    1116         [ +  - ]:          1 :   if (fd == -1)
    1117                 :            :     {
    1118         [ +  - ]:          1 :       if (!suppress_create_msg)
    1119                 :          1 :         fprintf (stderr, "%s: creating %s\n",
    1120                 :            :                  program_invocation_short_name, arfname);
    1121                 :            : 
    1122                 :          1 :       goto no_old;
    1123                 :            :     }
    1124                 :            : 
    1125                 :            :   /* Store the names of all files from the command line in a hash
    1126                 :            :      table so that we can match it.  Note that when no file name is
    1127                 :            :      given we are basically doing nothing except recreating the
    1128                 :            :      index.  */
    1129         [ #  # ]:          0 :   if (oper != oper_qappend)
    1130                 :            :     {
    1131         [ #  # ]:          0 :       if (hcreate (2 * argc) == 0)
    1132                 :          0 :         error_exit (errno, _("cannot create hash table"));
    1133                 :            : 
    1134         [ #  # ]:          0 :       for (int cnt = 0; cnt < argc; ++cnt)
    1135                 :            :         {
    1136                 :          0 :           ENTRY entry;
    1137         [ #  # ]:          0 :           entry.key = full_path ? argv[cnt] : basename (argv[cnt]);
    1138                 :          0 :           entry.data = &argv[cnt];
    1139         [ #  # ]:          0 :           if (hsearch (entry, ENTER) == NULL)
    1140                 :          0 :             error_exit (errno, _("cannot insert into hash table"));
    1141                 :            :         }
    1142                 :            :     }
    1143                 :            : 
    1144                 :            :   /* While iterating over the current content of the archive we must
    1145                 :            :      determine a number of things: which archive members to keep,
    1146                 :            :      which are replaced, and where to insert the new members.  */
    1147                 :            :   Elf_Cmd cmd = ELF_C_READ_MMAP;
    1148                 :            :   Elf *subelf;
    1149         [ #  # ]:          0 :   while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
    1150                 :            :     {
    1151                 :          0 :       Elf_Arhdr *arhdr = elf_getarhdr (subelf);
    1152                 :            : 
    1153                 :            :       /* Ignore the symbol table and the long file name table here.  */
    1154         [ #  # ]:          0 :       if (strcmp (arhdr->ar_name, "/") == 0
    1155         [ #  # ]:          0 :           || strcmp (arhdr->ar_name, "//") == 0)
    1156                 :          0 :         goto next;
    1157                 :            : 
    1158                 :          0 :       struct armem *newp = alloca (sizeof (struct armem));
    1159                 :          0 :       newp->old_off = elf_getaroff (subelf);
    1160                 :          0 :       newp->size = arhdr->ar_size;
    1161                 :          0 :       newp->sec = arhdr->ar_date;
    1162                 :          0 :       newp->mem = NULL;
    1163                 :            : 
    1164                 :            :       /* Remember long file names.  */
    1165         [ #  # ]:          0 :       remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name));
    1166                 :            : 
    1167                 :            :       /* Check whether this is a file we are looking for.  */
    1168         [ #  # ]:          0 :       if (oper != oper_qappend)
    1169                 :            :         {
    1170                 :            :           /* Check whether this is the member used as the insert point.  */
    1171   [ #  #  #  # ]:          0 :           if (member != NULL && strcmp (arhdr->ar_name, member) == 0)
    1172                 :            :             {
    1173                 :            :               /* Note that all == NULL means insert at the beginning.  */
    1174         [ #  # ]:          0 :               if (ipos == ipos_before)
    1175                 :            :                 after_memberelem = all;
    1176                 :            :               else
    1177                 :          0 :                 after_memberelem = newp;
    1178                 :            :               member = NULL;
    1179                 :            :             }
    1180                 :            : 
    1181                 :          0 :           ENTRY entry;
    1182                 :          0 :           entry.key = arhdr->ar_name;
    1183                 :          0 :           ENTRY *res = hsearch (entry, FIND);
    1184   [ #  #  #  # ]:          0 :           if (res != NULL && found[(char **) res->data - argv] == NULL)
    1185                 :            :             {
    1186                 :          0 :               found[(char **) res->data - argv] = newp;
    1187                 :            : 
    1188                 :            :               /* If we insert before or after a certain element move
    1189                 :            :                  all files to a special list.  */
    1190   [ #  #  #  # ]:          0 :               if (unlikely (ipos != ipos_none || oper == oper_move))
    1191                 :            :                 {
    1192         [ #  # ]:          0 :                   if (after_memberelem == newp)
    1193                 :            :                     /* Since we remove this element even though we should
    1194                 :            :                        insert everything after it, we in fact insert
    1195                 :            :                        everything after the previous element.  */
    1196                 :          0 :                     after_memberelem = all;
    1197                 :            : 
    1198                 :          0 :                   goto next;
    1199                 :            :                 }
    1200                 :            :             }
    1201                 :            :         }
    1202                 :            : 
    1203         [ #  # ]:          0 :       if (all == NULL)
    1204                 :          0 :         all = newp->next = newp;
    1205                 :            :       else
    1206                 :            :         {
    1207                 :          0 :           newp->next = all->next;
    1208                 :          0 :           all = all->next = newp;
    1209                 :            :         }
    1210                 :            : 
    1211                 :          0 :     next:
    1212                 :          0 :       cmd = elf_next (subelf);
    1213         [ #  # ]:          0 :       if (elf_end (subelf) != 0)
    1214                 :          0 :         error_exit (0, "%s: %s", arfname, elf_errmsg (-1));
    1215                 :            :     }
    1216                 :            : 
    1217         [ #  # ]:          0 :   if (oper != oper_qappend)
    1218                 :          0 :     hdestroy ();
    1219                 :            : 
    1220                 :          0 :  no_old:
    1221         [ -  + ]:          1 :   if (member != NULL)
    1222                 :          0 :     error_exit (0, _("position member %s not found"),
    1223                 :            :                 member);
    1224                 :            : 
    1225         [ -  + ]:          1 :   if (oper == oper_move)
    1226                 :            :     {
    1227                 :            :       /* Make sure all requested elements are found in the archive.  */
    1228         [ #  # ]:          0 :       for (int cnt = 0; cnt < argc; ++cnt)
    1229                 :            :         {
    1230         [ #  # ]:          0 :           if (found[cnt] == NULL)
    1231                 :            :             {
    1232                 :          0 :               fprintf (stderr, _("%s: no entry %s in archive!\n"),
    1233                 :          0 :                        program_invocation_short_name, argv[cnt]);
    1234                 :          0 :               status = 1;
    1235                 :            :             }
    1236                 :            : 
    1237         [ #  # ]:          0 :           if (verbose)
    1238                 :          0 :             printf ("m - %s\n", argv[cnt]);
    1239                 :            :         }
    1240                 :            :     }
    1241                 :            :   else
    1242                 :            :     {
    1243                 :            :       /* Open all the new files, get their sizes and add all symbols.  */
    1244         [ +  + ]:         20 :       for (int cnt = 0; cnt < argc; ++cnt)
    1245                 :            :         {
    1246                 :         19 :           const char *bname = basename (argv[cnt]);
    1247                 :         19 :           size_t bnamelen = strlen (bname);
    1248         [ +  - ]:         19 :           if (found[cnt] == NULL)
    1249                 :            :             {
    1250                 :         19 :               found[cnt] = alloca (sizeof (struct armem));
    1251                 :         19 :               found[cnt]->old_off = -1;
    1252                 :            : 
    1253         [ -  + ]:         19 :               remember_long_name (found[cnt], bname, bnamelen);
    1254                 :            :             }
    1255                 :            : 
    1256                 :         19 :           struct stat newst;
    1257                 :         19 :           Elf *newelf;
    1258                 :         19 :           int newfd = open (argv[cnt], O_RDONLY);
    1259         [ -  + ]:         19 :           if (newfd == -1)
    1260                 :            :             {
    1261                 :          0 :               error (0, errno, _("cannot open %s"), argv[cnt]);
    1262                 :          0 :               status = 1;
    1263                 :            :             }
    1264         [ -  + ]:         19 :           else if (fstat (newfd, &newst) == -1)
    1265                 :            :             {
    1266                 :          0 :               error (0, errno, _("cannot stat %s"), argv[cnt]);
    1267                 :          0 :               close (newfd);
    1268                 :          0 :               status = 1;
    1269                 :            :             }
    1270         [ -  + ]:         19 :           else if (!S_ISREG (newst.st_mode))
    1271                 :            :             {
    1272                 :          0 :               error (0, errno, _("%s is no regular file"), argv[cnt]);
    1273                 :          0 :               close (newfd);
    1274                 :          0 :               status = 1;
    1275                 :            :             }
    1276         [ -  + ]:         19 :           else if (update_newer
    1277         [ #  # ]:          0 :                    && found[cnt]->old_off != -1l
    1278         [ #  # ]:          0 :                    && found[cnt]->sec > st.st_mtime)
    1279                 :            :             /* Do nothing, the file in the archive is younger.  */
    1280                 :          0 :             close (newfd);
    1281         [ -  + ]:         19 :           else if ((newelf = elf_begin (newfd, ELF_C_READ_MMAP, NULL))
    1282                 :            :                    == NULL)
    1283                 :            :             {
    1284                 :          0 :               fprintf (stderr,
    1285                 :          0 :                        _("cannot get ELF descriptor for %s: %s\n"),
    1286                 :            :                        argv[cnt], elf_errmsg (-1));
    1287                 :          0 :               status = 1;
    1288                 :            :             }
    1289                 :            :           else
    1290                 :            :             {
    1291         [ -  + ]:         19 :               if (verbose)
    1292                 :          0 :                 printf ("%c - %s\n",
    1293         [ #  # ]:          0 :                         found[cnt]->old_off == -1l ? 'a' : 'r', argv[cnt]);
    1294                 :            : 
    1295                 :         19 :               found[cnt]->elf = newelf;
    1296         [ +  - ]:         19 :               found[cnt]->sec = arlib_deterministic_output ? 0 : newst.st_mtime;
    1297         [ +  - ]:         19 :               found[cnt]->uid = arlib_deterministic_output ? 0 : newst.st_uid;
    1298         [ +  - ]:         19 :               found[cnt]->gid = arlib_deterministic_output ? 0 : newst.st_gid;
    1299                 :         19 :               found[cnt]->mode = newst.st_mode;
    1300                 :         19 :               found[cnt]->name = bname;
    1301                 :            : 
    1302                 :         19 :               found[cnt]->mem = elf_rawfile (newelf, &found[cnt]->size);
    1303         [ +  - ]:         19 :               if (found[cnt]->mem == NULL
    1304         [ -  + ]:         19 :                   || elf_cntl (newelf, ELF_C_FDDONE) != 0)
    1305                 :          0 :                 error_exit (0, _("cannot read %s: %s"),
    1306                 :            :                             argv[cnt], elf_errmsg (-1));
    1307                 :            : 
    1308                 :         19 :               close (newfd);
    1309                 :            : 
    1310         [ -  + ]:         19 :               if (found[cnt]->old_off != -1l)
    1311                 :            :                 /* Remember long file names.  */
    1312         [ -  - ]:         19 :                 remember_long_name (found[cnt], bname, bnamelen);
    1313                 :            :             }
    1314                 :            :         }
    1315                 :            :     }
    1316                 :            : 
    1317         [ -  + ]:          1 :   if (status != 0)
    1318                 :            :     {
    1319                 :          0 :       elf_end (elf);
    1320                 :            : 
    1321                 :          0 :       arlib_fini ();
    1322                 :            : 
    1323                 :          0 :       close (fd);
    1324                 :            : 
    1325                 :          0 :       return status;
    1326                 :            :     }
    1327                 :            : 
    1328                 :            :   /* If we have no entry point so far add at the end.  AFTER_MEMBERELEM
    1329                 :            :      being NULL when adding before an entry means add at the beginning.  */
    1330   [ +  -  +  - ]:          1 :   if (ipos != ipos_before && after_memberelem == NULL)
    1331                 :          1 :     after_memberelem = all;
    1332                 :            : 
    1333                 :            :   /* Convert the circular list into a normal list first.  */
    1334         [ -  + ]:          1 :   if (all != NULL)
    1335                 :            :     {
    1336                 :          0 :       struct armem *tmp = all;
    1337                 :          0 :       all = all->next;
    1338                 :          0 :       tmp->next = NULL;
    1339                 :            :     }
    1340                 :            : 
    1341                 :            :   struct armem *last_added = after_memberelem;
    1342         [ +  + ]:         20 :   for (int cnt = 0; cnt < argc; ++cnt)
    1343   [ +  -  +  - ]:         19 :     if (oper != oper_replace || found[cnt]->old_off == -1)
    1344                 :            :       {
    1345         [ +  + ]:         19 :         if (last_added == NULL)
    1346                 :            :           {
    1347                 :          1 :             found[cnt]->next = all;
    1348                 :          1 :             last_added = all = found[cnt];
    1349                 :            :           }
    1350                 :            :         else
    1351                 :            :           {
    1352                 :         18 :             found[cnt]->next = last_added->next;
    1353                 :         18 :             last_added = last_added->next = found[cnt];
    1354                 :            :           }
    1355                 :            :       }
    1356                 :            : 
    1357                 :            :   /* Finally compute the offset and add the symbols for the files
    1358                 :            :      after the insert point.  */
    1359         [ +  - ]:          1 :   if (likely (all != NULL))
    1360         [ +  + ]:         20 :     for (struct armem *memp = all; memp != NULL; memp = memp->next)
    1361                 :            :       {
    1362                 :         19 :         memp->off = cur_off;
    1363                 :            : 
    1364         [ -  + ]:         19 :         if (memp->mem == NULL)
    1365                 :            :           {
    1366                 :          0 :             Elf_Arhdr *arhdr;
    1367                 :            :             /* Fake initializing arhdr and subelf to keep gcc calm.  */
    1368                 :          0 :             asm ("" : "=m" (arhdr), "=m" (subelf));
    1369         [ #  # ]:          0 :             if (elf_rand (elf, memp->old_off) == 0
    1370         [ #  # ]:          0 :                 || (subelf = elf_begin (fd, ELF_C_READ_MMAP, elf)) == NULL
    1371         [ #  # ]:          0 :                 || (arhdr = elf_getarhdr (subelf)) == NULL)
    1372                 :            :               /* This should never happen since we already looked at the
    1373                 :            :                  archive content.  But who knows...  */
    1374                 :          0 :               error_exit (0, "%s: %s", arfname, elf_errmsg (-1));
    1375                 :            : 
    1376                 :          0 :             arlib_add_symbols (subelf, arfname, arhdr->ar_name, cur_off);
    1377                 :            : 
    1378                 :          0 :             elf_end (subelf);
    1379                 :            :           }
    1380                 :            :         else
    1381                 :         19 :           arlib_add_symbols (memp->elf, arfname, memp->name, cur_off);
    1382                 :            : 
    1383                 :         19 :         cur_off += (((memp->size + 1) & ~((off_t) 1))
    1384                 :            :                     + sizeof (struct ar_hdr));
    1385                 :            :       }
    1386                 :            : 
    1387                 :            :   /* Now we have all the information for the symbol table and long
    1388                 :            :      file name table.  Construct the final layout.  */
    1389                 :          1 :   arlib_finalize ();
    1390                 :            : 
    1391                 :            :   /* Create a new, temporary file in the same directory as the
    1392                 :            :      original file.  */
    1393                 :          1 :   char tmpfname[strlen (arfname) + 7];
    1394         [ -  + ]:          1 :   strcpy (stpcpy (tmpfname, arfname), "XXXXXX");
    1395                 :          1 :   int newfd;
    1396         [ -  + ]:          1 :   if (fd != -1)
    1397                 :          0 :     newfd = mkstemp (tmpfname);
    1398                 :            :   else
    1399                 :            :     {
    1400                 :          1 :       newfd = open (arfname, O_RDWR | O_CREAT | O_EXCL, DEFFILEMODE);
    1401   [ -  +  -  - ]:          1 :       if (newfd == -1 && errno == EEXIST)
    1402                 :            :         /* Bah, first the file did not exist, now it does.  Restart.  */
    1403                 :          0 :         return do_oper_insert (oper, arfname, argv, argc, member);
    1404                 :            :     }
    1405         [ -  + ]:          1 :   if (unlikely (newfd == -1))
    1406                 :          0 :     goto nonew;
    1407                 :            : 
    1408                 :            :   /* Create the header.  */
    1409         [ -  + ]:          1 :   if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
    1410                 :            :     {
    1411                 :          0 :     nonew_unlink:
    1412         [ #  # ]:          0 :       if (fd != -1)
    1413                 :            :         {
    1414                 :            :           // XXX Use /prof/self/fd/%d ???
    1415                 :          0 :           unlink (tmpfname);
    1416         [ #  # ]:          0 :           if (newfd != -1)
    1417                 :          0 :             close (newfd);
    1418                 :            :         }
    1419                 :          0 :     nonew:
    1420                 :          0 :       error (0, errno, _("cannot create new file"));
    1421                 :          0 :       status = 1;
    1422                 :          0 :       goto errout;
    1423                 :            :     }
    1424                 :            : 
    1425                 :            :   /* If the new archive is not empty we actually have something to do.  */
    1426         [ +  - ]:          1 :   if (likely (all != NULL))
    1427                 :            :     {
    1428                 :            :       /* Write the symbol table or the long file name table or both.  */
    1429         [ +  - ]:          1 :       if (symtab.symsnamelen != 0
    1430                 :          1 :           && ((write_retry (newfd, symtab.symsoff, symtab.symsofflen)
    1431         [ +  - ]:          1 :                != (ssize_t) symtab.symsofflen)
    1432                 :          1 :               || (write_retry (newfd, symtab.symsname, symtab.symsnamelen)
    1433         [ -  + ]:          1 :                   != (ssize_t) symtab.symsnamelen)))
    1434                 :          0 :         goto nonew_unlink;
    1435                 :            : 
    1436         [ -  + ]:          1 :       if (symtab.longnameslen > sizeof (struct ar_hdr)
    1437                 :          0 :           && (write_retry (newfd, symtab.longnames, symtab.longnameslen)
    1438         [ #  # ]:          0 :               != (ssize_t) symtab.longnameslen))
    1439                 :          0 :         goto nonew_unlink;
    1440                 :            : 
    1441                 :          1 :       off_t start = -1;
    1442                 :          1 :       off_t len = -1;
    1443                 :            : 
    1444         [ +  + ]:         20 :       while (all != NULL)
    1445                 :            :         {
    1446         [ +  - ]:         19 :           if (all->mem != NULL)
    1447                 :            :             {
    1448                 :            :               /* This is a new file.  If there is anything from the
    1449                 :            :                  archive left to be written do it now.  */
    1450   [ -  +  -  - ]:         19 :               if (start != -1  && copy_content (elf, newfd, start, len))
    1451                 :          0 :                 goto nonew_unlink;
    1452                 :            : 
    1453                 :         19 :               start = -1;
    1454                 :         19 :               len = -1;
    1455                 :            : 
    1456                 :            :               /* Create the header.  */
    1457                 :         19 :               struct ar_hdr arhdr;
    1458                 :            :               /* The ar_name is not actually zero terminated, but we
    1459                 :            :                  need that for snprintf.  Also if the name is too
    1460                 :            :                  long, then the string starts with '/' plus an index
    1461                 :            :                  off number (decimal).  */
    1462                 :         19 :               char tmpbuf[sizeof (arhdr.ar_name) + 2];
    1463         [ +  - ]:         19 :               if (all->long_name_off == -1)
    1464                 :            :                 {
    1465                 :         19 :                   size_t namelen = strlen (all->name);
    1466                 :         19 :                   char *p = mempcpy (arhdr.ar_name, all->name, namelen);
    1467                 :         19 :                   *p++ = '/';
    1468                 :         19 :                   memset (p, ' ', sizeof (arhdr.ar_name) - namelen - 1);
    1469                 :            :                 }
    1470                 :            :               else
    1471                 :            :                 {
    1472                 :          0 :                   snprintf (tmpbuf, sizeof (tmpbuf), "/%-*ld",
    1473                 :            :                             (int) sizeof (arhdr.ar_name), all->long_name_off);
    1474                 :          0 :                   memcpy (arhdr.ar_name, tmpbuf, sizeof (arhdr.ar_name));
    1475                 :            :                 }
    1476                 :            : 
    1477         [ -  + ]:         19 :               if (! no0print (false, arhdr.ar_date, sizeof (arhdr.ar_date),
    1478                 :            :                               all->sec))
    1479                 :            :                 {
    1480                 :          0 :                   error (0, errno, _("cannot represent ar_date"));
    1481                 :          0 :                   goto nonew_unlink;
    1482                 :            :                 }
    1483         [ -  + ]:         19 :               if (! no0print (false, arhdr.ar_uid, sizeof (arhdr.ar_uid),
    1484                 :         19 :                               all->uid))
    1485                 :            :                 {
    1486                 :          0 :                   error (0, errno, _("cannot represent ar_uid"));
    1487                 :          0 :                   goto nonew_unlink;
    1488                 :            :                 }
    1489         [ -  + ]:         19 :               if (! no0print (false, arhdr.ar_gid, sizeof (arhdr.ar_gid),
    1490                 :         19 :                               all->gid))
    1491                 :            :                 {
    1492                 :          0 :                   error (0, errno, _("cannot represent ar_gid"));
    1493                 :          0 :                   goto nonew_unlink;
    1494                 :            :                 }
    1495         [ -  + ]:         19 :               if (! no0print (true, arhdr.ar_mode, sizeof (arhdr.ar_mode),
    1496                 :         19 :                         all->mode))
    1497                 :            :                 {
    1498                 :          0 :                   error (0, errno, _("cannot represent ar_mode"));
    1499                 :          0 :                   goto nonew_unlink;
    1500                 :            :                 }
    1501         [ -  + ]:         19 :               if (! no0print (false, arhdr.ar_size, sizeof (arhdr.ar_size),
    1502                 :         19 :                         all->size))
    1503                 :            :                 {
    1504                 :          0 :                   error (0, errno, _("cannot represent ar_size"));
    1505                 :          0 :                   goto nonew_unlink;
    1506                 :            :                 }
    1507                 :         19 :               memcpy (arhdr.ar_fmag, ARFMAG, sizeof (arhdr.ar_fmag));
    1508                 :            : 
    1509         [ -  + ]:         19 :               if (unlikely (write_retry (newfd, &arhdr, sizeof (arhdr))
    1510                 :            :                             != sizeof (arhdr)))
    1511                 :          0 :                 goto nonew_unlink;
    1512                 :            : 
    1513                 :            :               /* Now the file itself.  */
    1514         [ -  + ]:         19 :               if (unlikely (write_retry (newfd, all->mem, all->size)
    1515                 :            :                             != (off_t) all->size))
    1516                 :          0 :                 goto nonew_unlink;
    1517                 :            : 
    1518                 :            :               /* Pad the file if its size is odd.  */
    1519         [ -  + ]:         19 :               if ((all->size & 1) != 0)
    1520         [ #  # ]:          0 :                 if (unlikely (write_retry (newfd, "\n", 1) != 1))
    1521                 :          0 :                   goto nonew_unlink;
    1522                 :            :             }
    1523                 :            :           else
    1524                 :            :             {
    1525                 :            :               /* This is a member from the archive.  */
    1526         [ #  # ]:          0 :               if (write_member (all, &start, &len, elf, cur_off, newfd)
    1527                 :            :                   != 0)
    1528                 :          0 :                 goto nonew_unlink;
    1529                 :            :             }
    1530                 :            : 
    1531                 :         19 :           all = all->next;
    1532                 :            :         }
    1533                 :            : 
    1534                 :            :       /* Write the last part.  */
    1535   [ -  +  -  - ]:          1 :       if (start != -1 && copy_content (elf, newfd, start, len))
    1536                 :          0 :         goto nonew_unlink;
    1537                 :            :     }
    1538                 :            : 
    1539                 :            :   /* Set the mode of the new file to the same values the original file
    1540                 :            :      has.  */
    1541         [ -  + ]:          1 :   if (fd != -1)
    1542                 :            :     {
    1543                 :            :       /* Never complain about fchown failing.  But do it before
    1544                 :            :          setting the modes, or they might be reset/ignored if the
    1545                 :            :          owner is wrong.  */
    1546                 :          0 :       if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; }
    1547         [ #  # ]:          0 :       if (fchmod (newfd, st.st_mode & ALLPERMS) != 0
    1548         [ #  # ]:          0 :           || close (newfd) != 0)
    1549                 :          0 :         goto nonew_unlink;
    1550                 :          0 :       newfd = -1;
    1551         [ #  # ]:          0 :       if (rename (tmpfname, arfname) != 0)
    1552                 :          0 :         goto nonew_unlink;
    1553                 :            :     }
    1554                 :            : 
    1555                 :          1 :  errout:
    1556         [ +  + ]:         20 :   for (int cnt = 0; cnt < argc; ++cnt)
    1557                 :         19 :     elf_end (found[cnt]->elf);
    1558                 :            : 
    1559                 :          1 :   elf_end (elf);
    1560                 :            : 
    1561                 :          1 :   arlib_fini ();
    1562                 :            : 
    1563         [ -  + ]:          1 :   if (fd != -1)
    1564                 :          0 :     close (fd);
    1565                 :            : 
    1566         [ +  - ]:          1 :   if (newfd != -1)
    1567                 :          1 :     close (newfd);
    1568                 :            : 
    1569                 :            :   return status;
    1570                 :            : }
    1571                 :            : 
    1572                 :            : 
    1573                 :            : #include "debugpred.h"

Generated by: LCOV version 1.14