LCOV - code coverage report
Current view: top level - src - ar.c (source / functions) Hit Total Coverage
Test: elfutils-0.173 Lines: 245 636 38.5 %
Date: 2018-06-29 23:49:12 Functions: 8 11 72.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13