Imported Upstream version 0.153
[platform/upstream/elfutils.git] / src / ar.c
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.  */
57 static void print_version (FILE *stream, struct argp_state *state);
58 ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
59
60 /* Prototypes for local functions.  */
61 static int do_oper_extract (int oper, const char *arfname, char **argv,
62                             int argc, long int instance);
63 static int do_oper_delete (const char *arfname, char **argv, int argc,
64                            long int instance);
65 static int do_oper_insert (int oper, const char *arfname, char **argv,
66                            int argc, const char *member);
67
68
69 /* Bug report address.  */
70 ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
71
72
73 /* Definitions of arguments for argp functions.  */
74 static 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.  */
107 static const char doc[] = N_("Create, modify, and extract from archives.");
108
109 /* Strings for arguments in help texts.  */
110 static const char args_doc[] = N_("[MEMBER] [COUNT] ARCHIVE [FILE...]");
111
112 /* Prototype for option handler.  */
113 static error_t parse_opt (int key, char *arg, struct argp_state *state);
114
115 /* Data structure to communicate with argp functions.  */
116 static struct argp argp =
117 {
118   options, parse_opt, args_doc, doc, arlib_argp_children, NULL, NULL
119 };
120
121
122 /* What operation to perform.  */
123 static 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.  */
136 static bool verbose;
137 static bool preserve_dates;
138 static bool instance_specifed;
139 static bool dont_replace_existing;
140 static bool allow_truncate_fname;
141 static bool force_symtab;
142 static bool suppress_create_msg;
143 static bool full_path;
144 static bool update_newer;
145 static enum { ipos_none, ipos_before, ipos_after } ipos;
146
147
148 int
149 main (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 ("\
198 MEMBER 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.  */
292 static void
293 print_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 ("\
297 Copyright (C) %s Red Hat, Inc.\n\
298 This is free software; see the source for copying conditions.  There is NO\n\
299 warranty; 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.  */
306 static error_t
307 parse_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
405 static int
406 open_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
440 static void
441 not_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
449 static int
450 copy_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
466 static int
467 do_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 ("\
749 cannot 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
845 struct 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
862 static int
863 write_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.  */
916 static void
917 remember_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
924 static int
925 do_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
1095 static void
1096 no0print (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
1104 static int
1105 do_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"