LCOV - code coverage report
Current view: top level - src - ar.c (source / functions) Hit Total Coverage
Test: elfutils-0.182 Lines: 273 731 37.3 %
Date: 2020-10-31 23:45:54 Functions: 8 12 66.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13