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