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