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

Generated by: LCOV version 1.16