LCOV - code coverage report
Current view: top level - src - ar.c (source / functions) Hit Total Coverage
Test: elfutils-0.178 Lines: 272 726 37.5 %
Date: 2019-11-26 23:55:16 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             :                   /* Even if the original file had content before the
     798             :                      symbol table, we write it in the correct order.  */
     799           0 :                   || (index_off != SARMAG
     800           0 :                       && copy_content (elf, newfd, SARMAG, index_off - SARMAG))
     801           0 :                   || copy_content (elf, newfd, rest_off, st.st_size - rest_off)
     802             :                   /* Set the mode of the new file to the same values the
     803             :                      original file has.  */
     804           0 :                   || fchmod (newfd, st.st_mode & ALLPERMS) != 0
     805             :                   /* Never complain about fchown failing.  */
     806           0 :                   || (({asm ("" :: "r" (fchown (newfd, st.st_uid,
     807             :                                                 st.st_gid))); }),
     808           0 :                       close (newfd) != 0)
     809           0 :                   || (newfd = -1, rename (tmpfname, arfname) != 0))
     810           0 :                 goto nonew_unlink;
     811             :             }
     812             :         }
     813             :     }
     814             : 
     815           2 :   elf_end (elf);
     816             : 
     817           2 :   close (fd);
     818             : 
     819           2 :   not_found (argc, argv, found);
     820             : 
     821           2 :   return status;
     822             : }
     823             : 
     824             : 
     825             : struct armem
     826             : {
     827             :   off_t off;
     828             :   off_t old_off;
     829             :   size_t size;
     830             :   long int long_name_off;
     831             :   struct armem *next;
     832             :   void *mem;
     833             :   time_t sec;
     834             :   uid_t uid;
     835             :   gid_t gid;
     836             :   mode_t mode;
     837             :   const char *name;
     838             :   Elf *elf;
     839             : };
     840             : 
     841             : 
     842             : static int
     843           0 : write_member (struct armem *memb, off_t *startp, off_t *lenp, Elf *elf,
     844             :               off_t end_off, int newfd)
     845             : {
     846           0 :   struct ar_hdr arhdr;
     847             :   /* The ar_name is not actually zero teminated, but we need that for
     848             :      snprintf.  Also if the name is too long, then the string starts
     849             :      with '/' plus an index off number (decimal).  */
     850           0 :   char tmpbuf[sizeof (arhdr.ar_name) + 2];
     851             : 
     852           0 :   bool changed_header = memb->long_name_off != -1;
     853           0 :   if (changed_header)
     854             :     {
     855             :       /* In case of a long file name we assume the archive header
     856             :          changed and we write it here.  */
     857           0 :       memcpy (&arhdr, elf_rawfile (elf, NULL) + *startp, sizeof (arhdr));
     858             : 
     859           0 :       snprintf (tmpbuf, sizeof (tmpbuf), "/%-*ld",
     860             :                 (int) sizeof (arhdr.ar_name), memb->long_name_off);
     861           0 :       changed_header = memcmp (arhdr.ar_name, tmpbuf,
     862             :                                sizeof (arhdr.ar_name)) != 0;
     863             :     }
     864             : 
     865             :   /* If the files are adjacent in the old file extend the range.  */
     866           0 :   if (*startp != -1 && !changed_header && *startp + *lenp == memb->old_off)
     867             :     {
     868             :       /* Extend the current range.  */
     869           0 :       *lenp += (memb->next != NULL
     870           0 :                 ? memb->next->off : end_off) - memb->off;
     871           0 :       return 0;
     872             :     }
     873             : 
     874             :   /* Write out the old range.  */
     875           0 :   if (*startp != -1 && copy_content (elf, newfd, *startp, *lenp))
     876             :     return -1;
     877             : 
     878           0 :   *startp = memb->old_off;
     879           0 :   *lenp = (memb->next != NULL ? memb->next->off : end_off) - memb->off;
     880             : 
     881           0 :   if (changed_header)
     882             :     {
     883           0 :       memcpy (arhdr.ar_name, tmpbuf, sizeof (arhdr.ar_name));
     884             : 
     885           0 :       if (unlikely (write_retry (newfd, &arhdr, sizeof (arhdr))
     886             :                     != sizeof (arhdr)))
     887             :         return -1;
     888             : 
     889           0 :       *startp += sizeof (struct ar_hdr);
     890           0 :       assert ((size_t) *lenp >= sizeof (struct ar_hdr));
     891           0 :       *lenp -= sizeof (struct ar_hdr);
     892             :     }
     893             : 
     894             :   return 0;
     895             : }
     896             : 
     897             : /* Store the name in the long name table if necessary.
     898             :    Record its offset or -1 if we did not need to use the table.  */
     899             : static void
     900           0 : remember_long_name (struct armem *mem, const char *name, size_t namelen)
     901             : {
     902          19 :   mem->long_name_off = (namelen > MAX_AR_NAME_LEN
     903           0 :                         ? arlib_add_long_name (name, namelen)
     904           0 :                         : -1l);
     905           0 : }
     906             : 
     907             : static int
     908           1 : do_oper_delete (const char *arfname, char **argv, int argc,
     909             :                 long int instance)
     910             : {
     911           1 :   bool *found = alloca (sizeof (bool) * argc);
     912           1 :   memset (found, '\0', sizeof (bool) * argc);
     913             : 
     914             :   /* List of the files we keep.  */
     915           1 :   struct armem *to_copy = NULL;
     916             : 
     917           1 :   int status = 0;
     918           1 :   Elf *elf;
     919           1 :   struct stat st;
     920           1 :   int fd = open_archive (arfname, O_RDONLY, 0, &elf, &st, false);
     921             : 
     922           1 :   if (hcreate (2 * argc) == 0)
     923           0 :     error (EXIT_FAILURE, errno, gettext ("cannot create hash table"));
     924             : 
     925          20 :   for (int cnt = 0; cnt < argc; ++cnt)
     926             :     {
     927          19 :       ENTRY entry = { .key = argv[cnt], .data = &argv[cnt] };
     928          19 :       if (hsearch (entry, ENTER) == NULL)
     929           0 :         error (EXIT_FAILURE, errno,
     930           0 :                gettext ("cannot insert into hash table"));
     931             :     }
     932             : 
     933           1 :   arlib_init ();
     934             : 
     935           1 :   off_t cur_off = SARMAG;
     936           1 :   Elf_Cmd cmd = ELF_C_READ_MMAP;
     937           1 :   Elf *subelf;
     938          21 :   while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
     939             :     {
     940          20 :       Elf_Arhdr *arhdr = elf_getarhdr (subelf);
     941             : 
     942             :       /* Ignore the symbol table and the long file name table here.  */
     943          20 :       if (strcmp (arhdr->ar_name, "/") == 0
     944          19 :           || strcmp (arhdr->ar_name, "//") == 0)
     945             :         goto next;
     946             : 
     947          19 :       bool do_delete = argc <= 0;
     948          19 :       if (!do_delete)
     949             :         {
     950          19 :           ENTRY entry;
     951          19 :           entry.key = arhdr->ar_name;
     952          19 :           ENTRY *res = hsearch (entry, FIND);
     953          19 :           if (res != NULL && (instance < 0 || instance-- == 0)
     954          19 :               && !found[(char **) res->data - argv])
     955          19 :             found[(char **) res->data - argv] = do_delete = true;
     956             :         }
     957             : 
     958          19 :       if (do_delete)
     959             :         {
     960          19 :           if (verbose)
     961           0 :             printf ("d - %s\n", arhdr->ar_name);
     962             :         }
     963             :       else
     964             :         {
     965           0 :           struct armem *newp = alloca (sizeof (struct armem));
     966           0 :           newp->old_off = elf_getaroff (subelf);
     967           0 :           newp->off = cur_off;
     968             : 
     969           0 :           cur_off += (((arhdr->ar_size + 1) & ~((off_t) 1))
     970             :                       + sizeof (struct ar_hdr));
     971             : 
     972           0 :           if (to_copy == NULL)
     973           0 :             to_copy = newp->next = newp;
     974             :           else
     975             :             {
     976           0 :               newp->next = to_copy->next;
     977           0 :               to_copy = to_copy->next = newp;
     978             :             }
     979             : 
     980             :           /* If we recreate the symbol table read the file's symbol
     981             :              table now.  */
     982           0 :           arlib_add_symbols (subelf, arfname, arhdr->ar_name, newp->off);
     983             : 
     984             :           /* Remember long file names.  */
     985           0 :           remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name));
     986             :         }
     987             : 
     988          20 :     next:
     989          20 :       cmd = elf_next (subelf);
     990          20 :       if (elf_end (subelf) != 0)
     991           0 :         error (1, 0, "%s: %s", arfname, elf_errmsg (-1));
     992             :     }
     993             : 
     994           1 :   arlib_finalize ();
     995             : 
     996           1 :   hdestroy ();
     997             : 
     998             :   /* Create a new, temporary file in the same directory as the
     999             :      original file.  */
    1000           1 :   char tmpfname[strlen (arfname) + 7];
    1001           2 :   strcpy (stpcpy (tmpfname, arfname), "XXXXXX");
    1002           1 :   int newfd = mkstemp (tmpfname);
    1003           1 :   if (unlikely (newfd == -1))
    1004             :     goto nonew;
    1005             : 
    1006             :   /* Create the header.  */
    1007           1 :   if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
    1008             :     {
    1009             :       // XXX Use /prof/self/fd/%d ???
    1010           0 :     nonew_unlink:
    1011           0 :       unlink (tmpfname);
    1012           0 :       if (newfd != -1)
    1013           0 :         close (newfd);
    1014           0 :     nonew:
    1015           0 :       error (0, errno, gettext ("cannot create new file"));
    1016           0 :       status = 1;
    1017           0 :       goto errout;
    1018             :     }
    1019             : 
    1020             :   /* If the archive is empty that is all we have to do.  */
    1021           1 :   if (likely (to_copy != NULL))
    1022             :     {
    1023             :       /* Write the symbol table or the long file name table or both.  */
    1024           0 :       if (symtab.symsnamelen != 0
    1025           0 :           && ((write_retry (newfd, symtab.symsoff, symtab.symsofflen)
    1026           0 :                != (ssize_t) symtab.symsofflen)
    1027           0 :               || (write_retry (newfd, symtab.symsname, symtab.symsnamelen)
    1028           0 :                   != (ssize_t) symtab.symsnamelen)))
    1029           0 :         goto nonew_unlink;
    1030             : 
    1031           0 :       if (symtab.longnameslen > sizeof (struct ar_hdr)
    1032           0 :           && (write_retry (newfd, symtab.longnames, symtab.longnameslen)
    1033           0 :               != (ssize_t) symtab.longnameslen))
    1034             :         goto nonew_unlink;
    1035             : 
    1036             :       /* NULL-terminate the list of files to copy.  */
    1037           0 :       struct armem *last = to_copy;
    1038           0 :       to_copy = to_copy->next;
    1039           0 :       last->next = NULL;
    1040             : 
    1041           0 :       off_t start = -1;
    1042           0 :       off_t len = -1;
    1043             : 
    1044           0 :       do
    1045           0 :         if (write_member (to_copy, &start, &len, elf, cur_off, newfd) != 0)
    1046             :           goto nonew_unlink;
    1047           0 :       while ((to_copy = to_copy->next) != NULL);
    1048             : 
    1049             :       /* Write the last part.  */
    1050           0 :       if (copy_content (elf, newfd, start, len))
    1051             :         goto nonew_unlink;
    1052             :     }
    1053             : 
    1054             :   /* Set the mode of the new file to the same values the original file
    1055             :      has.  */
    1056           1 :   if (fchmod (newfd, st.st_mode & ALLPERMS) != 0
    1057             :       /* Never complain about fchown failing.  */
    1058           2 :       || (({asm ("" :: "r" (fchown (newfd, st.st_uid, st.st_gid))); }),
    1059           1 :           close (newfd) != 0)
    1060           1 :       || (newfd = -1, rename (tmpfname, arfname) != 0))
    1061           0 :     goto nonew_unlink;
    1062             : 
    1063           1 :  errout:
    1064           1 :   elf_end (elf);
    1065             : 
    1066           1 :   arlib_fini ();
    1067             : 
    1068           1 :   close (fd);
    1069             : 
    1070           1 :   not_found (argc, argv, found);
    1071             : 
    1072           1 :   return status;
    1073             : }
    1074             : 
    1075             : 
    1076             : /* Prints the given value in the given buffer without a trailing zero char.
    1077             :    Returns false if the given value doesn't fit in the given buffer.  */
    1078             : static bool
    1079          95 : no0print (bool ofmt, char *buf, int bufsize, long int val)
    1080          95 : {
    1081          95 :   char tmpbuf[bufsize + 1];
    1082         171 :   int ret = snprintf (tmpbuf, sizeof (tmpbuf), ofmt ? "%-*lo" : "%-*ld",
    1083             :                       bufsize, val);
    1084          95 :   if (ret >= (int) sizeof (tmpbuf))
    1085             :     return false;
    1086          95 :   memcpy (buf, tmpbuf, bufsize);
    1087          95 :   return true;
    1088             : }
    1089             : 
    1090             : 
    1091             : static int
    1092           1 : do_oper_insert (int oper, const char *arfname, char **argv, int argc,
    1093             :                 const char *member)
    1094             : {
    1095           1 :   int status = 0;
    1096           1 :   Elf *elf = NULL;
    1097           1 :   struct stat st;
    1098           1 :   int fd = open_archive (arfname, O_RDONLY, 0, &elf, &st, oper != oper_move);
    1099             : 
    1100             :   /* List of the files we keep.  */
    1101           1 :   struct armem *all = NULL;
    1102           1 :   struct armem *after_memberelem = NULL;
    1103           1 :   struct armem **found = alloca (sizeof (*found) * argc);
    1104           1 :   memset (found, '\0', sizeof (*found) * argc);
    1105             : 
    1106           1 :   arlib_init ();
    1107             : 
    1108             :   /* Initialize early for no_old case.  */
    1109           1 :   off_t cur_off = SARMAG;
    1110             : 
    1111           1 :   if (fd == -1)
    1112             :     {
    1113           1 :       if (!suppress_create_msg)
    1114           1 :         fprintf (stderr, "%s: creating %s\n",
    1115             :                  program_invocation_short_name, arfname);
    1116             : 
    1117           1 :       goto no_old;
    1118             :     }
    1119             : 
    1120             :   /* Store the names of all files from the command line in a hash
    1121             :      table so that we can match it.  Note that when no file name is
    1122             :      given we are basically doing nothing except recreating the
    1123             :      index.  */
    1124           0 :   if (oper != oper_qappend)
    1125             :     {
    1126           0 :       if (hcreate (2 * argc) == 0)
    1127           0 :         error (EXIT_FAILURE, errno, gettext ("cannot create hash table"));
    1128             : 
    1129           0 :       for (int cnt = 0; cnt < argc; ++cnt)
    1130             :         {
    1131           0 :           ENTRY entry;
    1132           0 :           entry.key = full_path ? argv[cnt] : basename (argv[cnt]);
    1133           0 :           entry.data = &argv[cnt];
    1134           0 :           if (hsearch (entry, ENTER) == NULL)
    1135           0 :             error (EXIT_FAILURE, errno,
    1136           0 :                    gettext ("cannot insert into hash table"));
    1137             :         }
    1138             :     }
    1139             : 
    1140             :   /* While iterating over the current content of the archive we must
    1141             :      determine a number of things: which archive members to keep,
    1142             :      which are replaced, and where to insert the new members.  */
    1143             :   Elf_Cmd cmd = ELF_C_READ_MMAP;
    1144             :   Elf *subelf;
    1145           0 :   while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
    1146             :     {
    1147           0 :       Elf_Arhdr *arhdr = elf_getarhdr (subelf);
    1148             : 
    1149             :       /* Ignore the symbol table and the long file name table here.  */
    1150           0 :       if (strcmp (arhdr->ar_name, "/") == 0
    1151           0 :           || strcmp (arhdr->ar_name, "//") == 0)
    1152             :         goto next;
    1153             : 
    1154           0 :       struct armem *newp = alloca (sizeof (struct armem));
    1155           0 :       newp->old_off = elf_getaroff (subelf);
    1156           0 :       newp->size = arhdr->ar_size;
    1157           0 :       newp->sec = arhdr->ar_date;
    1158           0 :       newp->mem = NULL;
    1159             : 
    1160             :       /* Remember long file names.  */
    1161           0 :       remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name));
    1162             : 
    1163             :       /* Check whether this is a file we are looking for.  */
    1164           0 :       if (oper != oper_qappend)
    1165             :         {
    1166             :           /* Check whether this is the member used as the insert point.  */
    1167           0 :           if (member != NULL && strcmp (arhdr->ar_name, member) == 0)
    1168             :             {
    1169             :               /* Note that all == NULL means insert at the beginning.  */
    1170           0 :               if (ipos == ipos_before)
    1171             :                 after_memberelem = all;
    1172             :               else
    1173           0 :                 after_memberelem = newp;
    1174             :               member = NULL;
    1175             :             }
    1176             : 
    1177           0 :           ENTRY entry;
    1178           0 :           entry.key = arhdr->ar_name;
    1179           0 :           ENTRY *res = hsearch (entry, FIND);
    1180           0 :           if (res != NULL && found[(char **) res->data - argv] == NULL)
    1181             :             {
    1182           0 :               found[(char **) res->data - argv] = newp;
    1183             : 
    1184             :               /* If we insert before or after a certain element move
    1185             :                  all files to a special list.  */
    1186           0 :               if (unlikely (ipos != ipos_none || oper == oper_move))
    1187             :                 {
    1188           0 :                   if (after_memberelem == newp)
    1189             :                     /* Since we remove this element even though we should
    1190             :                        insert everything after it, we in fact insert
    1191             :                        everything after the previous element.  */
    1192           0 :                     after_memberelem = all;
    1193             : 
    1194           0 :                   goto next;
    1195             :                 }
    1196             :             }
    1197             :         }
    1198             : 
    1199           0 :       if (all == NULL)
    1200           0 :         all = newp->next = newp;
    1201             :       else
    1202             :         {
    1203           0 :           newp->next = all->next;
    1204           0 :           all = all->next = newp;
    1205             :         }
    1206             : 
    1207           0 :     next:
    1208           0 :       cmd = elf_next (subelf);
    1209           0 :       if (elf_end (subelf) != 0)
    1210           0 :         error (EXIT_FAILURE, 0, "%s: %s", arfname, elf_errmsg (-1));
    1211             :     }
    1212             : 
    1213           0 :   if (oper != oper_qappend)
    1214           0 :     hdestroy ();
    1215             : 
    1216           0 :  no_old:
    1217           1 :   if (member != NULL)
    1218           0 :     error (EXIT_FAILURE, 0, gettext ("position member %s not found"),
    1219             :            member);
    1220             : 
    1221           1 :   if (oper == oper_move)
    1222             :     {
    1223             :       /* Make sure all requested elements are found in the archive.  */
    1224           0 :       for (int cnt = 0; cnt < argc; ++cnt)
    1225             :         {
    1226           0 :           if (found[cnt] == NULL)
    1227             :             {
    1228           0 :               fprintf (stderr, gettext ("%s: no entry %s in archive!\n"),
    1229           0 :                        program_invocation_short_name, argv[cnt]);
    1230           0 :               status = 1;
    1231             :             }
    1232             : 
    1233           0 :           if (verbose)
    1234           0 :             printf ("m - %s\n", argv[cnt]);
    1235             :         }
    1236             :     }
    1237             :   else
    1238             :     {
    1239             :       /* Open all the new files, get their sizes and add all symbols.  */
    1240          20 :       for (int cnt = 0; cnt < argc; ++cnt)
    1241             :         {
    1242          19 :           const char *bname = basename (argv[cnt]);
    1243          19 :           size_t bnamelen = strlen (bname);
    1244          19 :           if (found[cnt] == NULL)
    1245             :             {
    1246          19 :               found[cnt] = alloca (sizeof (struct armem));
    1247          19 :               found[cnt]->old_off = -1;
    1248             : 
    1249          19 :               remember_long_name (found[cnt], bname, bnamelen);
    1250             :             }
    1251             : 
    1252          19 :           struct stat newst;
    1253          19 :           Elf *newelf;
    1254          19 :           int newfd = open (argv[cnt], O_RDONLY);
    1255          19 :           if (newfd == -1)
    1256             :             {
    1257           0 :               error (0, errno, gettext ("cannot open %s"), argv[cnt]);
    1258           0 :               status = 1;
    1259             :             }
    1260          19 :           else if (fstat (newfd, &newst) == -1)
    1261             :             {
    1262           0 :               error (0, errno, gettext ("cannot stat %s"), argv[cnt]);
    1263           0 :               close (newfd);
    1264           0 :               status = 1;
    1265             :             }
    1266          19 :           else if (!S_ISREG (newst.st_mode))
    1267             :             {
    1268           0 :               error (0, errno, gettext ("%s is no regular file"), argv[cnt]);
    1269           0 :               close (newfd);
    1270           0 :               status = 1;
    1271             :             }
    1272          19 :           else if (update_newer
    1273           0 :                    && found[cnt]->old_off != -1l
    1274           0 :                    && found[cnt]->sec > st.st_mtime)
    1275             :             /* Do nothing, the file in the archive is younger.  */
    1276           0 :             close (newfd);
    1277          19 :           else if ((newelf = elf_begin (newfd, ELF_C_READ_MMAP, NULL))
    1278             :                    == NULL)
    1279             :             {
    1280           0 :               fprintf (stderr,
    1281           0 :                        gettext ("cannot get ELF descriptor for %s: %s\n"),
    1282             :                        argv[cnt], elf_errmsg (-1));
    1283           0 :               status = 1;
    1284             :             }
    1285             :           else
    1286             :             {
    1287          19 :               if (verbose)
    1288           0 :                 printf ("%c - %s\n",
    1289           0 :                         found[cnt]->old_off == -1l ? 'a' : 'r', argv[cnt]);
    1290             : 
    1291          19 :               found[cnt]->elf = newelf;
    1292          19 :               found[cnt]->sec = arlib_deterministic_output ? 0 : newst.st_mtime;
    1293          19 :               found[cnt]->uid = arlib_deterministic_output ? 0 : newst.st_uid;
    1294          19 :               found[cnt]->gid = arlib_deterministic_output ? 0 : newst.st_gid;
    1295          19 :               found[cnt]->mode = newst.st_mode;
    1296          19 :               found[cnt]->name = bname;
    1297             : 
    1298          19 :               found[cnt]->mem = elf_rawfile (newelf, &found[cnt]->size);
    1299          19 :               if (found[cnt]->mem == NULL
    1300          19 :                   || elf_cntl (newelf, ELF_C_FDDONE) != 0)
    1301           0 :                 error (EXIT_FAILURE, 0, gettext ("cannot read %s: %s"),
    1302             :                        argv[cnt], elf_errmsg (-1));
    1303             : 
    1304          19 :               close (newfd);
    1305             : 
    1306          19 :               if (found[cnt]->old_off != -1l)
    1307             :                 /* Remember long file names.  */
    1308           0 :                 remember_long_name (found[cnt], bname, bnamelen);
    1309             :             }
    1310             :         }
    1311             :     }
    1312             : 
    1313           1 :   if (status != 0)
    1314             :     {
    1315           0 :       elf_end (elf);
    1316             : 
    1317           0 :       arlib_fini ();
    1318             : 
    1319           0 :       close (fd);
    1320             : 
    1321           0 :       return status;
    1322             :     }
    1323             : 
    1324             :   /* If we have no entry point so far add at the end.  AFTER_MEMBERELEM
    1325             :      being NULL when adding before an entry means add at the beginning.  */
    1326           1 :   if (ipos != ipos_before && after_memberelem == NULL)
    1327           1 :     after_memberelem = all;
    1328             : 
    1329             :   /* Convert the circular list into a normal list first.  */
    1330           1 :   if (all != NULL)
    1331             :     {
    1332           0 :       struct armem *tmp = all;
    1333           0 :       all = all->next;
    1334           0 :       tmp->next = NULL;
    1335             :     }
    1336             : 
    1337             :   struct armem *last_added = after_memberelem;
    1338          20 :   for (int cnt = 0; cnt < argc; ++cnt)
    1339          19 :     if (oper != oper_replace || found[cnt]->old_off == -1)
    1340             :       {
    1341          19 :         if (last_added == NULL)
    1342             :           {
    1343           1 :             found[cnt]->next = all;
    1344           1 :             last_added = all = found[cnt];
    1345             :           }
    1346             :         else
    1347             :           {
    1348          18 :             found[cnt]->next = last_added->next;
    1349          18 :             last_added = last_added->next = found[cnt];
    1350             :           }
    1351             :       }
    1352             : 
    1353             :   /* Finally compute the offset and add the symbols for the files
    1354             :      after the insert point.  */
    1355           1 :   if (likely (all != NULL))
    1356          20 :     for (struct armem *memp = all; memp != NULL; memp = memp->next)
    1357             :       {
    1358          19 :         memp->off = cur_off;
    1359             : 
    1360          19 :         if (memp->mem == NULL)
    1361             :           {
    1362           0 :             Elf_Arhdr *arhdr;
    1363             :             /* Fake initializing arhdr and subelf to keep gcc calm.  */
    1364           0 :             asm ("" : "=m" (arhdr), "=m" (subelf));
    1365           0 :             if (elf_rand (elf, memp->old_off) == 0
    1366           0 :                 || (subelf = elf_begin (fd, ELF_C_READ_MMAP, elf)) == NULL
    1367           0 :                 || (arhdr = elf_getarhdr (subelf)) == NULL)
    1368             :               /* This should never happen since we already looked at the
    1369             :                  archive content.  But who knows...  */
    1370           0 :               error (EXIT_FAILURE, 0, "%s: %s", arfname, elf_errmsg (-1));
    1371             : 
    1372           0 :             arlib_add_symbols (subelf, arfname, arhdr->ar_name, cur_off);
    1373             : 
    1374           0 :             elf_end (subelf);
    1375             :           }
    1376             :         else
    1377          19 :           arlib_add_symbols (memp->elf, arfname, memp->name, cur_off);
    1378             : 
    1379          19 :         cur_off += (((memp->size + 1) & ~((off_t) 1))
    1380             :                     + sizeof (struct ar_hdr));
    1381             :       }
    1382             : 
    1383             :   /* Now we have all the information for the symbol table and long
    1384             :      file name table.  Construct the final layout.  */
    1385           1 :   arlib_finalize ();
    1386             : 
    1387             :   /* Create a new, temporary file in the same directory as the
    1388             :      original file.  */
    1389           1 :   char tmpfname[strlen (arfname) + 7];
    1390           2 :   strcpy (stpcpy (tmpfname, arfname), "XXXXXX");
    1391           1 :   int newfd;
    1392           1 :   if (fd != -1)
    1393           0 :     newfd = mkstemp (tmpfname);
    1394             :   else
    1395             :     {
    1396           1 :       newfd = open (arfname, O_RDWR | O_CREAT | O_EXCL, DEFFILEMODE);
    1397           1 :       if (newfd == -1 && errno == EEXIST)
    1398             :         /* Bah, first the file did not exist, now it does.  Restart.  */
    1399           0 :         return do_oper_insert (oper, arfname, argv, argc, member);
    1400             :     }
    1401           1 :   if (unlikely (newfd == -1))
    1402             :     goto nonew;
    1403             : 
    1404             :   /* Create the header.  */
    1405           1 :   if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
    1406             :     {
    1407           0 :     nonew_unlink:
    1408           0 :       if (fd != -1)
    1409             :         {
    1410             :           // XXX Use /prof/self/fd/%d ???
    1411           0 :           unlink (tmpfname);
    1412           0 :           if (newfd != -1)
    1413           0 :             close (newfd);
    1414             :         }
    1415           0 :     nonew:
    1416           0 :       error (0, errno, gettext ("cannot create new file"));
    1417           0 :       status = 1;
    1418           0 :       goto errout;
    1419             :     }
    1420             : 
    1421             :   /* If the new archive is not empty we actually have something to do.  */
    1422           1 :   if (likely (all != NULL))
    1423             :     {
    1424             :       /* Write the symbol table or the long file name table or both.  */
    1425           1 :       if (symtab.symsnamelen != 0
    1426           1 :           && ((write_retry (newfd, symtab.symsoff, symtab.symsofflen)
    1427           1 :                != (ssize_t) symtab.symsofflen)
    1428           1 :               || (write_retry (newfd, symtab.symsname, symtab.symsnamelen)
    1429           1 :                   != (ssize_t) symtab.symsnamelen)))
    1430           0 :         goto nonew_unlink;
    1431             : 
    1432           1 :       if (symtab.longnameslen > sizeof (struct ar_hdr)
    1433           0 :           && (write_retry (newfd, symtab.longnames, symtab.longnameslen)
    1434           0 :               != (ssize_t) symtab.longnameslen))
    1435             :         goto nonew_unlink;
    1436             : 
    1437           1 :       off_t start = -1;
    1438           1 :       off_t len = -1;
    1439             : 
    1440          20 :       while (all != NULL)
    1441             :         {
    1442          19 :           if (all->mem != NULL)
    1443             :             {
    1444             :               /* This is a new file.  If there is anything from the
    1445             :                  archive left to be written do it now.  */
    1446          19 :               if (start != -1  && copy_content (elf, newfd, start, len))
    1447           0 :                 goto nonew_unlink;
    1448             : 
    1449          19 :               start = -1;
    1450          19 :               len = -1;
    1451             : 
    1452             :               /* Create the header.  */
    1453          19 :               struct ar_hdr arhdr;
    1454             :               /* The ar_name is not actually zero teminated, but we
    1455             :                  need that for snprintf.  Also if the name is too
    1456             :                  long, then the string starts with '/' plus an index
    1457             :                  off number (decimal).  */
    1458          19 :               char tmpbuf[sizeof (arhdr.ar_name) + 2];
    1459          19 :               if (all->long_name_off == -1)
    1460             :                 {
    1461          19 :                   size_t namelen = strlen (all->name);
    1462          19 :                   char *p = mempcpy (arhdr.ar_name, all->name, namelen);
    1463          19 :                   *p++ = '/';
    1464          19 :                   memset (p, ' ', sizeof (arhdr.ar_name) - namelen - 1);
    1465             :                 }
    1466             :               else
    1467             :                 {
    1468           0 :                   snprintf (tmpbuf, sizeof (tmpbuf), "/%-*ld",
    1469             :                             (int) sizeof (arhdr.ar_name), all->long_name_off);
    1470           0 :                   memcpy (arhdr.ar_name, tmpbuf, sizeof (arhdr.ar_name));
    1471             :                 }
    1472             : 
    1473          19 :               if (! no0print (false, arhdr.ar_date, sizeof (arhdr.ar_date),
    1474             :                               all->sec))
    1475             :                 {
    1476           0 :                   error (0, errno, gettext ("cannot represent ar_date"));
    1477           0 :                   goto nonew_unlink;
    1478             :                 }
    1479          19 :               if (! no0print (false, arhdr.ar_uid, sizeof (arhdr.ar_uid),
    1480          19 :                               all->uid))
    1481             :                 {
    1482           0 :                   error (0, errno, gettext ("cannot represent ar_uid"));
    1483           0 :                   goto nonew_unlink;
    1484             :                 }
    1485          19 :               if (! no0print (false, arhdr.ar_gid, sizeof (arhdr.ar_gid),
    1486          19 :                               all->gid))
    1487             :                 {
    1488           0 :                   error (0, errno, gettext ("cannot represent ar_gid"));
    1489           0 :                   goto nonew_unlink;
    1490             :                 }
    1491          19 :               if (! no0print (true, arhdr.ar_mode, sizeof (arhdr.ar_mode),
    1492          19 :                         all->mode))
    1493             :                 {
    1494           0 :                   error (0, errno, gettext ("cannot represent ar_mode"));
    1495           0 :                   goto nonew_unlink;
    1496             :                 }
    1497          19 :               if (! no0print (false, arhdr.ar_size, sizeof (arhdr.ar_size),
    1498          19 :                         all->size))
    1499             :                 {
    1500           0 :                   error (0, errno, gettext ("cannot represent ar_size"));
    1501           0 :                   goto nonew_unlink;
    1502             :                 }
    1503          19 :               memcpy (arhdr.ar_fmag, ARFMAG, sizeof (arhdr.ar_fmag));
    1504             : 
    1505          19 :               if (unlikely (write_retry (newfd, &arhdr, sizeof (arhdr))
    1506             :                             != sizeof (arhdr)))
    1507             :                 goto nonew_unlink;
    1508             : 
    1509             :               /* Now the file itself.  */
    1510          19 :               if (unlikely (write_retry (newfd, all->mem, all->size)
    1511             :                             != (off_t) all->size))
    1512             :                 goto nonew_unlink;
    1513             : 
    1514             :               /* Pad the file if its size is odd.  */
    1515          19 :               if ((all->size & 1) != 0)
    1516           0 :                 if (unlikely (write_retry (newfd, "\n", 1) != 1))
    1517             :                   goto nonew_unlink;
    1518             :             }
    1519             :           else
    1520             :             {
    1521             :               /* This is a member from the archive.  */
    1522           0 :               if (write_member (all, &start, &len, elf, cur_off, newfd)
    1523             :                   != 0)
    1524             :                 goto nonew_unlink;
    1525             :             }
    1526             : 
    1527          19 :           all = all->next;
    1528             :         }
    1529             : 
    1530             :       /* Write the last part.  */
    1531           1 :       if (start != -1 && copy_content (elf, newfd, start, len))
    1532             :         goto nonew_unlink;
    1533             :     }
    1534             : 
    1535             :   /* Set the mode of the new file to the same values the original file
    1536             :      has.  */
    1537           1 :   if (fd != -1
    1538           0 :       && (fchmod (newfd, st.st_mode & ALLPERMS) != 0
    1539             :           /* Never complain about fchown failing.  */
    1540           0 :           || (({asm ("" :: "r" (fchown (newfd, st.st_uid, st.st_gid))); }),
    1541           0 :               close (newfd) != 0)
    1542           0 :           || (newfd = -1, rename (tmpfname, arfname) != 0)))
    1543           0 :       goto nonew_unlink;
    1544             : 
    1545           1 :  errout:
    1546          20 :   for (int cnt = 0; cnt < argc; ++cnt)
    1547          19 :     elf_end (found[cnt]->elf);
    1548             : 
    1549           1 :   elf_end (elf);
    1550             : 
    1551           1 :   arlib_fini ();
    1552             : 
    1553           1 :   if (fd != -1)
    1554           0 :     close (fd);
    1555             : 
    1556             :   return status;
    1557             : }
    1558             : 
    1559             : 
    1560             : #include "debugpred.h"

Generated by: LCOV version 1.13