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