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