LCOV - code coverage report
Current view: top level - src - ar.c (source / functions) Hit Total Coverage
Test: elfutils-0.190 Lines: 425 749 56.7 %
Date: 2024-02-13 02:22:07 Functions: 10 11 90.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 236 545 43.3 %

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

Generated by: LCOV version 1.16