• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Create, modify, and extract from archives.
2    Copyright (C) 2005-2012, 2016, 2017 Red Hat, Inc.
3    This file is part of elfutils.
4    Written by Ulrich Drepper <drepper@redhat.com>, 2005.
5 
6    This file is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    elfutils is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18 
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22 
23 #include <argp.h>
24 #include <assert.h>
25 #include <fcntl.h>
26 #include <gelf.h>
27 #include <limits.h>
28 #include <locale.h>
29 #include <search.h>
30 #include <stdbool.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <stdio_ext.h>
34 #include <string.h>
35 #include <time.h>
36 #include <unistd.h>
37 #include <sys/mman.h>
38 #include <sys/stat.h>
39 #include <sys/time.h>
40 
41 #include <system.h>
42 #include <printversion.h>
43 
44 #include "arlib.h"
45 
46 
47 /* Name and version of program.  */
48 ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
49 
50 /* Prototypes for local functions.  */
51 static int do_oper_extract (int oper, const char *arfname, char **argv,
52 			    int argc, long int instance);
53 static int do_oper_delete (const char *arfname, char **argv, int argc,
54 			   long int instance);
55 static int do_oper_insert (int oper, const char *arfname, char **argv,
56 			   int argc, const char *member);
57 
58 
59 /* Bug report address.  */
60 ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
61 
62 
63 /* Definitions of arguments for argp functions.  */
64 static const struct argp_option options[] =
65 {
66   { NULL, 0, NULL, 0, N_("Commands:"), 1 },
67   { NULL, 'd', NULL, 0, N_("Delete files from archive."), 0 },
68   { NULL, 'm', NULL, 0, N_("Move files in archive."), 0 },
69   { NULL, 'p', NULL, 0, N_("Print files in archive."), 0 },
70   { NULL, 'q', NULL, 0, N_("Quick append files to archive."), 0 },
71   { NULL, 'r', NULL, 0,
72     N_("Replace existing or insert new file into archive."), 0 },
73   { NULL, 't', NULL, 0, N_("Display content of archive."), 0 },
74   { NULL, 'x', NULL, 0, N_("Extract files from archive."), 0 },
75 
76   { NULL, 0, NULL, 0, N_("Command Modifiers:"), 2 },
77   { NULL, 'o', NULL, 0, N_("Preserve original dates."), 0 },
78   { NULL, 'N', NULL, 0, N_("Use instance [COUNT] of name."), 0 },
79   { NULL, 'C', NULL, 0,
80     N_("Do not replace existing files with extracted files."), 0 },
81   { NULL, 'T', NULL, 0, N_("Allow filename to be truncated if necessary."),
82     0 },
83   { NULL, 'v', NULL, 0, N_("Provide verbose output."), 0 },
84   { NULL, 's', NULL, 0, N_("Force regeneration of symbol table."), 0 },
85   { NULL, 'a', NULL, 0, N_("Insert file after [MEMBER]."), 0 },
86   { NULL, 'b', NULL, 0, N_("Insert file before [MEMBER]."), 0 },
87   { NULL, 'i', NULL, 0, N_("Same as -b."), 0 },
88   { NULL, 'c', NULL, 0, N_("Suppress message when library has to be created."),
89     0 },
90   { NULL, 'P', NULL, 0, N_("Use full path for file matching."), 0 },
91   { NULL, 'u', NULL, 0, N_("Update only older files in archive."), 0 },
92 
93   { NULL, 0, NULL, 0, NULL, 0 }
94 };
95 
96 /* Short description of program.  */
97 static const char doc[] = N_("Create, modify, and extract from archives.");
98 
99 /* Strings for arguments in help texts.  */
100 static const char args_doc[] = N_("[MEMBER] [COUNT] ARCHIVE [FILE...]");
101 
102 /* Prototype for option handler.  */
103 static error_t parse_opt (int key, char *arg, struct argp_state *state);
104 
105 /* Data structure to communicate with argp functions.  */
106 static struct argp argp =
107 {
108   options, parse_opt, args_doc, doc, arlib_argp_children, NULL, NULL
109 };
110 
111 
112 /* What operation to perform.  */
113 static enum
114   {
115     oper_none,
116     oper_delete,
117     oper_move,
118     oper_print,
119     oper_qappend,
120     oper_replace,
121     oper_list,
122     oper_extract
123   } operation;
124 
125 /* Modifiers.  */
126 static bool verbose;
127 static bool preserve_dates;
128 static bool instance_specifed;
129 static bool dont_replace_existing;
130 static bool allow_truncate_fname;
131 static bool force_symtab;
132 static bool suppress_create_msg;
133 static bool full_path;
134 static bool update_newer;
135 static enum { ipos_none, ipos_before, ipos_after } ipos;
136 
137 
138 int
main(int argc,char * argv[])139 main (int argc, char *argv[])
140 {
141   /* We use no threads here which can interfere with handling a stream.  */
142   (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
143   (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
144   (void) __fsetlocking (stderr, FSETLOCKING_BYCALLER);
145 
146   /* Set locale.  */
147   (void) setlocale (LC_ALL, "");
148 
149   /* Make sure the message catalog can be found.  */
150   (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
151 
152   /* Initialize the message catalog.  */
153   (void) textdomain (PACKAGE_TARNAME);
154 
155   /* For historical reasons the options in the first parameter need
156      not be preceded by a dash.  Add it now if necessary.  */
157   if (argc > 1 && argv[1][0] != '-')
158     {
159       size_t len = strlen (argv[1]) + 1;
160       char *newp = alloca (len + 1);
161       newp[0] = '-';
162       memcpy (&newp[1], argv[1], len);
163       argv[1] = newp;
164     }
165 
166   /* Parse and process arguments.  */
167   int remaining;
168   (void) argp_parse (&argp, argc, argv, ARGP_IN_ORDER, &remaining, NULL);
169 
170   /* Tell the library which version we are expecting.  */
171   (void) elf_version (EV_CURRENT);
172 
173   /* Handle the [MEMBER] parameter.  */
174   const char *member = NULL;
175   if (ipos != ipos_none)
176     {
177       /* Only valid for certain operations.  */
178       if (operation != oper_move && operation != oper_replace)
179 	error (1, 0, _("\
180 'a', 'b', and 'i' are only allowed with the 'm' and 'r' options"));
181 
182       if (remaining == argc)
183 	{
184 	  error (0, 0, _("\
185 MEMBER parameter required for 'a', 'b', and 'i' modifiers"));
186 	  argp_help (&argp, stderr, ARGP_HELP_USAGE | ARGP_HELP_SEE,
187 		     program_invocation_short_name);
188 	  exit (EXIT_FAILURE);
189 	}
190 
191       member = argv[remaining++];
192     }
193 
194   /* Handle the [COUNT] parameter.  */
195   long int instance = -1;
196   if (instance_specifed)
197     {
198       /* Only valid for certain operations.  */
199       if (operation != oper_extract && operation != oper_delete)
200 	error (1, 0, _("\
201 'N' is only meaningful with the 'x' and 'd' options"));
202 
203       if (remaining == argc)
204 	{
205 	  error (0, 0, _("COUNT parameter required"));
206 	  argp_help (&argp, stderr, ARGP_HELP_SEE,
207 		     program_invocation_short_name);
208 	  exit (EXIT_FAILURE);
209 	}
210 
211       char *endp;
212       errno = 0;
213       if (((instance = strtol (argv[remaining], &endp, 10)) == LONG_MAX
214 	   && errno == ERANGE)
215 	  || instance <= 0
216 	  || *endp != '\0')
217 	error (1, 0, _("invalid COUNT parameter %s"), argv[remaining]);
218 
219       ++remaining;
220     }
221 
222   if ((dont_replace_existing || allow_truncate_fname)
223       && unlikely (operation != oper_extract))
224     error (1, 0, _("'%c' is only meaningful with the 'x' option"),
225 	   dont_replace_existing ? 'C' : 'T');
226 
227   /* There must at least be one more parameter specifying the archive.   */
228   if (remaining == argc)
229     {
230       error (0, 0, _("archive name required"));
231       argp_help (&argp, stderr, ARGP_HELP_SEE, program_invocation_short_name);
232       exit (EXIT_FAILURE);
233     }
234 
235   const char *arfname = argv[remaining++];
236   argv += remaining;
237   argc -= remaining;
238 
239   int status;
240   switch (operation)
241     {
242     case oper_none:
243       error (0, 0, _("command option required"));
244       argp_help (&argp, stderr, ARGP_HELP_STD_ERR,
245 		 program_invocation_short_name);
246       status = 1;
247       break;
248 
249     case oper_list:
250     case oper_print:
251       status = do_oper_extract (operation, arfname, argv, argc, -1);
252       break;
253 
254     case oper_extract:
255       status = do_oper_extract (operation, arfname, argv, argc, instance);
256       break;
257 
258     case oper_delete:
259       status = do_oper_delete (arfname, argv, argc, instance);
260       break;
261 
262     case oper_move:
263     case oper_qappend:
264     case oper_replace:
265       status = do_oper_insert (operation, arfname, argv, argc, member);
266       break;
267 
268     default:
269       assert (! "should not happen");
270       status = 1;
271       break;
272     }
273 
274   return status;
275 }
276 
277 
278 /* Handle program arguments.  */
279 static error_t
parse_opt(int key,char * arg,struct argp_state * state)280 parse_opt (int key, char *arg __attribute__ ((unused)),
281 	   struct argp_state *state __attribute__ ((unused)))
282 {
283   switch (key)
284     {
285     case 'd':
286     case 'm':
287     case 'p':
288     case 'q':
289     case 'r':
290     case 't':
291     case 'x':
292       if (operation != oper_none)
293 	{
294 	  error (0, 0, _("More than one operation specified"));
295 	  argp_help (&argp, stderr, ARGP_HELP_SEE,
296 		     program_invocation_short_name);
297 	  exit (EXIT_FAILURE);
298 	}
299 
300       switch (key)
301 	{
302 	case 'd':
303 	  operation = oper_delete;
304 	  break;
305 	case 'm':
306 	  operation = oper_move;
307 	  break;
308 	case 'p':
309 	  operation = oper_print;
310 	  break;
311 	case 'q':
312 	  operation = oper_qappend;
313 	  break;
314 	case 'r':
315 	  operation = oper_replace;
316 	  break;
317 	case 't':
318 	  operation = oper_list;
319 	  break;
320 	case 'x':
321 	  operation = oper_extract;
322 	  break;
323 	}
324       break;
325 
326     case 'a':
327       ipos = ipos_after;
328       break;
329 
330     case 'b':
331     case 'i':
332       ipos = ipos_before;
333       break;
334 
335     case 'c':
336       suppress_create_msg = true;
337       break;
338 
339     case 'C':
340       dont_replace_existing = true;
341       break;
342 
343     case 'N':
344       instance_specifed = true;
345       break;
346 
347     case 'o':
348       preserve_dates = true;
349       break;
350 
351     case 'P':
352       full_path = true;
353       break;
354 
355     case 's':
356       force_symtab = true;
357       break;
358 
359     case 'T':
360       allow_truncate_fname = true;
361       break;
362 
363     case 'u':
364       update_newer = true;
365       break;
366 
367     case 'v':
368       verbose = true;
369       break;
370 
371     default:
372       return ARGP_ERR_UNKNOWN;
373     }
374   return 0;
375 }
376 
377 
378 static int
open_archive(const char * arfname,int flags,int mode,Elf ** elf,struct stat * st,bool miss_allowed)379 open_archive (const char *arfname, int flags, int mode, Elf **elf,
380 	      struct stat *st, bool miss_allowed)
381 {
382   int fd = open (arfname, flags, mode);
383   if (fd == -1)
384     {
385       if (miss_allowed)
386 	return -1;
387 
388       error_exit (errno, _("cannot open archive '%s'"),
389 		  arfname);
390     }
391 
392   if (elf != NULL)
393     {
394       Elf_Cmd cmd = flags == O_RDONLY ? ELF_C_READ_MMAP : ELF_C_RDWR_MMAP;
395 
396       *elf = elf_begin (fd, cmd, NULL);
397       if (*elf == NULL)
398 	error_exit (0, _("cannot open archive '%s': %s"),
399 		    arfname, elf_errmsg (-1));
400 
401       if (flags == O_RDONLY && elf_kind (*elf) != ELF_K_AR)
402 	error_exit (0, _("%s: not an archive file"), arfname);
403     }
404 
405   if (st != NULL && fstat (fd, st) != 0)
406     error_exit (errno, _("cannot stat archive '%s'"),
407 		arfname);
408 
409   return fd;
410 }
411 
412 
413 static void
not_found(int argc,char * argv[argc],bool found[argc])414 not_found (int argc, char *argv[argc], bool found[argc])
415 {
416   for (int i = 0; i < argc; ++i)
417     if (!found[i])
418       printf (_("no entry %s in archive\n"), argv[i]);
419 }
420 
421 
422 static int
copy_content(Elf * elf,int newfd,off_t off,size_t n)423 copy_content (Elf *elf, int newfd, off_t off, size_t n)
424 {
425   size_t len;
426   char *rawfile = elf_rawfile (elf, &len);
427 
428   assert (off + n <= len);
429 
430   /* Tell the kernel we will read all the pages sequentially.  */
431   size_t ps = sysconf (_SC_PAGESIZE);
432   if (n > 2 * ps)
433     posix_madvise (rawfile + (off & ~(ps - 1)), n, POSIX_MADV_SEQUENTIAL);
434 
435   return write_retry (newfd, rawfile + off, n) != (ssize_t) n;
436 }
437 
438 static inline bool
should_truncate_fname(size_t * name_max)439 should_truncate_fname (size_t *name_max)
440 {
441   if (errno == ENAMETOOLONG && allow_truncate_fname)
442     {
443       if (*name_max == 0)
444 	{
445 	  long int len = pathconf (".", _PC_NAME_MAX);
446 	  if (len > 0)
447 	    *name_max = len;
448 	}
449       return *name_max != 0;
450     }
451   return false;
452 }
453 
454 static int
do_oper_extract(int oper,const char * arfname,char ** argv,int argc,long int instance)455 do_oper_extract (int oper, const char *arfname, char **argv, int argc,
456 		 long int instance)
457 {
458   bool found[argc > 0 ? argc : 1];
459   memset (found, '\0', sizeof (found));
460 
461   size_t name_max = 0;
462   off_t index_off = -1;
463   size_t index_size = 0;
464   off_t cur_off = SARMAG;
465 
466   int status = 0;
467   Elf *elf;
468   int fd = open_archive (arfname, O_RDONLY, 0, &elf, NULL, false);
469 
470   if (hcreate (2 * argc) == 0)
471     error_exit (errno, _("cannot create hash table"));
472 
473   for (int cnt = 0; cnt < argc; ++cnt)
474     {
475       ENTRY entry = { .key = argv[cnt], .data = &argv[cnt] };
476       if (hsearch (entry, ENTER) == NULL)
477 	error_exit (errno, _("cannot insert into hash table"));
478     }
479 
480   struct stat st;
481   if (force_symtab)
482     {
483       if (fstat (fd, &st) != 0)
484 	{
485 	  error (0, errno, _("cannot stat '%s'"), arfname);
486 	  close (fd);
487 	  return 1;
488 	}
489       arlib_init ();
490     }
491 
492   Elf_Cmd cmd = ELF_C_READ_MMAP;
493   Elf *subelf;
494   while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
495     {
496       Elf_Arhdr *arhdr = elf_getarhdr (subelf);
497       if (arhdr == NULL)
498         goto next;
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 (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 (errno, _("cannot insert into hash table"));
934     }
935 
936   arlib_init ();
937 
938   off_t cur_off = SARMAG;
939   Elf_Cmd cmd = ELF_C_READ_MMAP;
940   Elf *subelf;
941   while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
942     {
943       Elf_Arhdr *arhdr = elf_getarhdr (subelf);
944       if (arhdr == NULL)
945         goto next;
946 
947       /* Ignore the symbol table and the long file name table here.  */
948       if (strcmp (arhdr->ar_name, "/") == 0
949 	  || strcmp (arhdr->ar_name, "//") == 0)
950 	goto next;
951 
952       bool do_delete = argc <= 0;
953       if (!do_delete)
954 	{
955 	  ENTRY entry;
956 	  entry.key = arhdr->ar_name;
957 	  ENTRY *res = hsearch (entry, FIND);
958 	  if (res != NULL && (instance < 0 || --instance == 0)
959 	      && !found[(char **) res->data - argv])
960 	    found[(char **) res->data - argv] = do_delete = true;
961 	}
962 
963       if (do_delete)
964 	{
965 	  if (verbose)
966 	    printf ("d - %s\n", arhdr->ar_name);
967 	}
968       else
969 	{
970 	  struct armem *newp = alloca (sizeof (struct armem));
971 	  newp->old_off = elf_getaroff (subelf);
972 	  newp->off = cur_off;
973 
974 	  cur_off += (((arhdr->ar_size + 1) & ~((off_t) 1))
975 		      + sizeof (struct ar_hdr));
976 
977 	  if (to_copy == NULL)
978 	    to_copy = newp->next = newp;
979 	  else
980 	    {
981 	      newp->next = to_copy->next;
982 	      to_copy = to_copy->next = newp;
983 	    }
984 
985 	  /* If we recreate the symbol table read the file's symbol
986 	     table now.  */
987 	  arlib_add_symbols (subelf, arfname, arhdr->ar_name, newp->off);
988 
989 	  /* Remember long file names.  */
990 	  remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name));
991 	}
992 
993     next:
994       cmd = elf_next (subelf);
995       if (elf_end (subelf) != 0)
996 	error (1, 0, "%s: %s", arfname, elf_errmsg (-1));
997     }
998 
999   arlib_finalize ();
1000 
1001   hdestroy ();
1002 
1003   /* Create a new, temporary file in the same directory as the
1004      original file.  */
1005   char tmpfname[strlen (arfname) + 7];
1006   strcpy (stpcpy (tmpfname, arfname), "XXXXXX");
1007   int newfd = mkstemp (tmpfname);
1008   if (unlikely (newfd == -1))
1009     goto nonew;
1010 
1011   /* Create the header.  */
1012   if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
1013     {
1014       // XXX Use /prof/self/fd/%d ???
1015     nonew_unlink:
1016       unlink (tmpfname);
1017       if (newfd != -1)
1018 	close (newfd);
1019     nonew:
1020       error (0, errno, _("cannot create new file"));
1021       status = 1;
1022       goto errout;
1023     }
1024 
1025   /* If the archive is empty that is all we have to do.  */
1026   if (likely (to_copy != NULL))
1027     {
1028       /* Write the symbol table or the long file name table or both.  */
1029       if (symtab.symsnamelen != 0
1030 	  && ((write_retry (newfd, symtab.symsoff, symtab.symsofflen)
1031 	       != (ssize_t) symtab.symsofflen)
1032 	      || (write_retry (newfd, symtab.symsname, symtab.symsnamelen)
1033 		  != (ssize_t) symtab.symsnamelen)))
1034 	goto nonew_unlink;
1035 
1036       if (symtab.longnameslen > sizeof (struct ar_hdr)
1037 	  && (write_retry (newfd, symtab.longnames, symtab.longnameslen)
1038 	      != (ssize_t) symtab.longnameslen))
1039 	goto nonew_unlink;
1040 
1041       /* NULL-terminate the list of files to copy.  */
1042       struct armem *last = to_copy;
1043       to_copy = to_copy->next;
1044       last->next = NULL;
1045 
1046       off_t start = -1;
1047       off_t len = -1;
1048 
1049       do
1050 	if (write_member (to_copy, &start, &len, elf, cur_off, newfd) != 0)
1051 	  goto nonew_unlink;
1052       while ((to_copy = to_copy->next) != NULL);
1053 
1054       /* Write the last part.  */
1055       if (copy_content (elf, newfd, start, len))
1056 	goto nonew_unlink;
1057     }
1058 
1059   /* Set the mode of the new file to the same values the original file
1060      has.  Never complain about fchown failing.  But do it before
1061      setting the mode (which might be reset/ignored if the owner is
1062      wrong.  */
1063   if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; }
1064   if (fchmod (newfd, st.st_mode & ALLPERMS) != 0
1065       || close (newfd) != 0)
1066     goto nonew_unlink;
1067   newfd = -1;
1068   if (rename (tmpfname, arfname) != 0)
1069     goto nonew_unlink;
1070 
1071  errout:
1072   elf_end (elf);
1073 
1074   arlib_fini ();
1075 
1076   close (fd);
1077 
1078   not_found (argc, argv, found);
1079 
1080   return status;
1081 }
1082 
1083 
1084 /* Prints the given value in the given buffer without a trailing zero char.
1085    Returns false if the given value doesn't fit in the given buffer.  */
1086 static bool
no0print(bool ofmt,char * buf,int bufsize,long int val)1087 no0print (bool ofmt, char *buf, int bufsize, long int val)
1088 {
1089   char tmpbuf[bufsize + 1];
1090   int ret = snprintf (tmpbuf, sizeof (tmpbuf), ofmt ? "%-*lo" : "%-*ld",
1091 		      bufsize, val);
1092   if (ret >= (int) sizeof (tmpbuf))
1093     return false;
1094   memcpy (buf, tmpbuf, bufsize);
1095   return true;
1096 }
1097 
1098 
1099 static int
do_oper_insert(int oper,const char * arfname,char ** argv,int argc,const char * member)1100 do_oper_insert (int oper, const char *arfname, char **argv, int argc,
1101 		const char *member)
1102 {
1103   int status = 0;
1104   Elf *elf = NULL;
1105   struct stat st;
1106   int fd = open_archive (arfname, O_RDONLY, 0, &elf, &st, oper != oper_move);
1107 
1108   /* List of the files we keep.  */
1109   struct armem *all = NULL;
1110   struct armem *after_memberelem = NULL;
1111   struct armem **found = alloca (sizeof (*found) * argc);
1112   memset (found, '\0', sizeof (*found) * argc);
1113 
1114   arlib_init ();
1115 
1116   /* Initialize early for no_old case.  */
1117   off_t cur_off = SARMAG;
1118 
1119   if (fd == -1)
1120     {
1121       if (!suppress_create_msg)
1122 	fprintf (stderr, "%s: creating %s\n",
1123 		 program_invocation_short_name, arfname);
1124 
1125       goto no_old;
1126     }
1127 
1128   /* Store the names of all files from the command line in a hash
1129      table so that we can match it.  Note that when no file name is
1130      given we are basically doing nothing except recreating the
1131      index.  */
1132   if (oper != oper_qappend)
1133     {
1134       if (hcreate (2 * argc) == 0)
1135 	error_exit (errno, _("cannot create hash table"));
1136 
1137       for (int cnt = 0; cnt < argc; ++cnt)
1138 	{
1139 	  ENTRY entry;
1140 	  entry.key = full_path ? argv[cnt] : basename (argv[cnt]);
1141 	  entry.data = &argv[cnt];
1142 	  if (hsearch (entry, ENTER) == NULL)
1143 	    error_exit (errno, _("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       if (arhdr == NULL)
1156         goto next;
1157 
1158       /* Ignore the symbol table and the long file name table here.  */
1159       if (strcmp (arhdr->ar_name, "/") == 0
1160 	  || strcmp (arhdr->ar_name, "//") == 0)
1161 	goto next;
1162 
1163       struct armem *newp = alloca (sizeof (struct armem));
1164       newp->old_off = elf_getaroff (subelf);
1165       newp->size = arhdr->ar_size;
1166       newp->sec = arhdr->ar_date;
1167       newp->mem = NULL;
1168 
1169       /* Remember long file names.  */
1170       remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name));
1171 
1172       /* Check whether this is a file we are looking for.  */
1173       if (oper != oper_qappend)
1174 	{
1175 	  /* Check whether this is the member used as the insert point.  */
1176 	  if (member != NULL && strcmp (arhdr->ar_name, member) == 0)
1177 	    {
1178 	      /* Note that all == NULL means insert at the beginning.  */
1179 	      if (ipos == ipos_before)
1180 		after_memberelem = all;
1181 	      else
1182 		after_memberelem = newp;
1183 	      member = NULL;
1184 	    }
1185 
1186 	  ENTRY entry;
1187 	  entry.key = arhdr->ar_name;
1188 	  ENTRY *res = hsearch (entry, FIND);
1189 	  if (res != NULL && found[(char **) res->data - argv] == NULL)
1190 	    {
1191 	      found[(char **) res->data - argv] = newp;
1192 
1193 	      /* If we insert before or after a certain element move
1194 		 all files to a special list.  */
1195 	      if (unlikely (ipos != ipos_none || oper == oper_move))
1196 		{
1197 		  if (after_memberelem == newp)
1198 		    /* Since we remove this element even though we should
1199 		       insert everything after it, we in fact insert
1200 		       everything after the previous element.  */
1201 		    after_memberelem = all;
1202 
1203 		  goto next;
1204 		}
1205 	    }
1206 	}
1207 
1208       if (all == NULL)
1209 	all = newp->next = newp;
1210       else
1211 	{
1212 	  newp->next = all->next;
1213 	  all = all->next = newp;
1214 	}
1215 
1216     next:
1217       cmd = elf_next (subelf);
1218       if (elf_end (subelf) != 0)
1219 	error_exit (0, "%s: %s", arfname, elf_errmsg (-1));
1220     }
1221 
1222   if (oper != oper_qappend)
1223     hdestroy ();
1224 
1225  no_old:
1226   if (member != NULL)
1227     error_exit (0, _("position member %s not found"),
1228 		member);
1229 
1230   if (oper == oper_move)
1231     {
1232       /* Make sure all requested elements are found in the archive.  */
1233       for (int cnt = 0; cnt < argc; ++cnt)
1234 	{
1235 	  if (found[cnt] == NULL)
1236 	    {
1237 	      fprintf (stderr, _("%s: no entry %s in archive!\n"),
1238 		       program_invocation_short_name, argv[cnt]);
1239 	      status = 1;
1240 	    }
1241 
1242 	  if (verbose)
1243 	    printf ("m - %s\n", argv[cnt]);
1244 	}
1245     }
1246   else
1247     {
1248       /* Open all the new files, get their sizes and add all symbols.  */
1249       for (int cnt = 0; cnt < argc; ++cnt)
1250 	{
1251 	  const char *bname = basename (argv[cnt]);
1252 	  size_t bnamelen = strlen (bname);
1253 	  if (found[cnt] == NULL)
1254 	    {
1255 	      found[cnt] = alloca (sizeof (struct armem));
1256 	      found[cnt]->old_off = -1;
1257 
1258 	      remember_long_name (found[cnt], bname, bnamelen);
1259 	    }
1260 
1261 	  struct stat newst;
1262 	  Elf *newelf;
1263 	  int newfd = open (argv[cnt], O_RDONLY);
1264 	  if (newfd == -1)
1265 	    {
1266 	      error (0, errno, _("cannot open %s"), argv[cnt]);
1267 	      status = 1;
1268 	    }
1269 	  else if (fstat (newfd, &newst) == -1)
1270 	    {
1271 	      error (0, errno, _("cannot stat %s"), argv[cnt]);
1272 	      close (newfd);
1273 	      status = 1;
1274 	    }
1275 	  else if (!S_ISREG (newst.st_mode))
1276 	    {
1277 	      error (0, errno, _("%s is no regular file"), argv[cnt]);
1278 	      close (newfd);
1279 	      status = 1;
1280 	    }
1281 	  else if (update_newer
1282 		   && found[cnt]->old_off != -1l
1283 		   && found[cnt]->sec > st.st_mtime)
1284 	    /* Do nothing, the file in the archive is younger.  */
1285 	    close (newfd);
1286 	  else if ((newelf = elf_begin (newfd, ELF_C_READ_MMAP, NULL))
1287 		   == NULL)
1288 	    {
1289 	      fprintf (stderr,
1290 		       _("cannot get ELF descriptor for %s: %s\n"),
1291 		       argv[cnt], elf_errmsg (-1));
1292 	      status = 1;
1293 	    }
1294 	  else
1295 	    {
1296 	      if (verbose)
1297 		printf ("%c - %s\n",
1298 			found[cnt]->old_off == -1l ? 'a' : 'r', argv[cnt]);
1299 
1300 	      found[cnt]->elf = newelf;
1301 	      found[cnt]->sec = arlib_deterministic_output ? 0 : newst.st_mtime;
1302 	      found[cnt]->uid = arlib_deterministic_output ? 0 : newst.st_uid;
1303 	      found[cnt]->gid = arlib_deterministic_output ? 0 : newst.st_gid;
1304 	      found[cnt]->mode = newst.st_mode;
1305 	      found[cnt]->name = bname;
1306 
1307 	      found[cnt]->mem = elf_rawfile (newelf, &found[cnt]->size);
1308 	      if (found[cnt]->mem == NULL
1309 		  || elf_cntl (newelf, ELF_C_FDDONE) != 0)
1310 		error_exit (0, _("cannot read %s: %s"),
1311 			    argv[cnt], elf_errmsg (-1));
1312 
1313 	      close (newfd);
1314 
1315 	      if (found[cnt]->old_off != -1l)
1316 		/* Remember long file names.  */
1317 		remember_long_name (found[cnt], bname, bnamelen);
1318 	    }
1319 	}
1320     }
1321 
1322   if (status != 0)
1323     {
1324       elf_end (elf);
1325 
1326       arlib_fini ();
1327 
1328       close (fd);
1329 
1330       return status;
1331     }
1332 
1333   /* If we have no entry point so far add at the end.  AFTER_MEMBERELEM
1334      being NULL when adding before an entry means add at the beginning.  */
1335   if (ipos != ipos_before && after_memberelem == NULL)
1336     after_memberelem = all;
1337 
1338   /* Convert the circular list into a normal list first.  */
1339   if (all != NULL)
1340     {
1341       struct armem *tmp = all;
1342       all = all->next;
1343       tmp->next = NULL;
1344     }
1345 
1346   struct armem *last_added = after_memberelem;
1347   for (int cnt = 0; cnt < argc; ++cnt)
1348     if (oper != oper_replace || found[cnt]->old_off == -1)
1349       {
1350 	if (last_added == NULL)
1351 	  {
1352 	    found[cnt]->next = all;
1353 	    last_added = all = found[cnt];
1354 	  }
1355 	else
1356 	  {
1357 	    found[cnt]->next = last_added->next;
1358 	    last_added = last_added->next = found[cnt];
1359 	  }
1360       }
1361 
1362   /* Finally compute the offset and add the symbols for the files
1363      after the insert point.  */
1364   if (likely (all != NULL))
1365     for (struct armem *memp = all; memp != NULL; memp = memp->next)
1366       {
1367 	memp->off = cur_off;
1368 
1369 	if (memp->mem == NULL)
1370 	  {
1371 	    Elf_Arhdr *arhdr;
1372 	    /* Fake initializing arhdr and subelf to keep gcc calm.  */
1373 	    asm ("" : "=m" (arhdr), "=m" (subelf));
1374 	    if (elf_rand (elf, memp->old_off) == 0
1375 		|| (subelf = elf_begin (fd, ELF_C_READ_MMAP, elf)) == NULL
1376 		|| (arhdr = elf_getarhdr (subelf)) == NULL)
1377 	      /* This should never happen since we already looked at the
1378 		 archive content.  But who knows...  */
1379 	      error_exit (0, "%s: %s", arfname, elf_errmsg (-1));
1380 
1381 	    arlib_add_symbols (subelf, arfname, arhdr->ar_name, cur_off);
1382 
1383 	    elf_end (subelf);
1384 	  }
1385 	else
1386 	  arlib_add_symbols (memp->elf, arfname, memp->name, cur_off);
1387 
1388 	cur_off += (((memp->size + 1) & ~((off_t) 1))
1389 		    + sizeof (struct ar_hdr));
1390       }
1391 
1392   /* Now we have all the information for the symbol table and long
1393      file name table.  Construct the final layout.  */
1394   arlib_finalize ();
1395 
1396   /* Create a new, temporary file in the same directory as the
1397      original file.  */
1398   char tmpfname[strlen (arfname) + 7];
1399   strcpy (stpcpy (tmpfname, arfname), "XXXXXX");
1400   int newfd;
1401   if (fd != -1)
1402     newfd = mkstemp (tmpfname);
1403   else
1404     {
1405       newfd = open (arfname, O_RDWR | O_CREAT | O_EXCL, DEFFILEMODE);
1406       if (newfd == -1 && errno == EEXIST)
1407 	/* Bah, first the file did not exist, now it does.  Restart.  */
1408 	return do_oper_insert (oper, arfname, argv, argc, member);
1409     }
1410   if (unlikely (newfd == -1))
1411     goto nonew;
1412 
1413   /* Create the header.  */
1414   if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
1415     {
1416     nonew_unlink:
1417       if (fd != -1)
1418 	{
1419 	  // XXX Use /prof/self/fd/%d ???
1420 	  unlink (tmpfname);
1421 	  if (newfd != -1)
1422 	    close (newfd);
1423 	}
1424     nonew:
1425       error (0, errno, _("cannot create new file"));
1426       status = 1;
1427       goto errout;
1428     }
1429 
1430   /* If the new archive is not empty we actually have something to do.  */
1431   if (likely (all != NULL))
1432     {
1433       /* Write the symbol table or the long file name table or both.  */
1434       if (symtab.symsnamelen != 0
1435 	  && ((write_retry (newfd, symtab.symsoff, symtab.symsofflen)
1436 	       != (ssize_t) symtab.symsofflen)
1437 	      || (write_retry (newfd, symtab.symsname, symtab.symsnamelen)
1438 		  != (ssize_t) symtab.symsnamelen)))
1439 	goto nonew_unlink;
1440 
1441       if (symtab.longnameslen > sizeof (struct ar_hdr)
1442 	  && (write_retry (newfd, symtab.longnames, symtab.longnameslen)
1443 	      != (ssize_t) symtab.longnameslen))
1444 	goto nonew_unlink;
1445 
1446       off_t start = -1;
1447       off_t len = -1;
1448 
1449       while (all != NULL)
1450 	{
1451 	  if (all->mem != NULL)
1452 	    {
1453 	      /* This is a new file.  If there is anything from the
1454 		 archive left to be written do it now.  */
1455 	      if (start != -1  && copy_content (elf, newfd, start, len))
1456 		goto nonew_unlink;
1457 
1458 	      start = -1;
1459 	      len = -1;
1460 
1461 	      /* Create the header.  */
1462 	      struct ar_hdr arhdr;
1463 	      /* The ar_name is not actually zero terminated, but we
1464 		 need that for snprintf.  Also if the name is too
1465 		 long, then the string starts with '/' plus an index
1466 		 off number (decimal).  */
1467 	      char tmpbuf[sizeof (arhdr.ar_name) + 2];
1468 	      if (all->long_name_off == -1)
1469 		{
1470 		  size_t namelen = strlen (all->name);
1471 		  char *p = mempcpy (arhdr.ar_name, all->name, namelen);
1472 		  *p++ = '/';
1473 		  memset (p, ' ', sizeof (arhdr.ar_name) - namelen - 1);
1474 		}
1475 	      else
1476 		{
1477 		  snprintf (tmpbuf, sizeof (tmpbuf), "/%-*ld",
1478 			    (int) sizeof (arhdr.ar_name), all->long_name_off);
1479 		  memcpy (arhdr.ar_name, tmpbuf, sizeof (arhdr.ar_name));
1480 		}
1481 
1482 	      if (! no0print (false, arhdr.ar_date, sizeof (arhdr.ar_date),
1483 			      all->sec))
1484 		{
1485 		  error (0, errno, _("cannot represent ar_date"));
1486 		  goto nonew_unlink;
1487 		}
1488 	      if (! no0print (false, arhdr.ar_uid, sizeof (arhdr.ar_uid),
1489 			      all->uid))
1490 		{
1491 		  error (0, errno, _("cannot represent ar_uid"));
1492 		  goto nonew_unlink;
1493 		}
1494 	      if (! no0print (false, arhdr.ar_gid, sizeof (arhdr.ar_gid),
1495 			      all->gid))
1496 		{
1497 		  error (0, errno, _("cannot represent ar_gid"));
1498 		  goto nonew_unlink;
1499 		}
1500 	      if (! no0print (true, arhdr.ar_mode, sizeof (arhdr.ar_mode),
1501 			all->mode))
1502 		{
1503 		  error (0, errno, _("cannot represent ar_mode"));
1504 		  goto nonew_unlink;
1505 		}
1506 	      if (! no0print (false, arhdr.ar_size, sizeof (arhdr.ar_size),
1507 			all->size))
1508 		{
1509 		  error (0, errno, _("cannot represent ar_size"));
1510 		  goto nonew_unlink;
1511 		}
1512 	      memcpy (arhdr.ar_fmag, ARFMAG, sizeof (arhdr.ar_fmag));
1513 
1514 	      if (unlikely (write_retry (newfd, &arhdr, sizeof (arhdr))
1515 			    != sizeof (arhdr)))
1516 		goto nonew_unlink;
1517 
1518 	      /* Now the file itself.  */
1519 	      if (unlikely (write_retry (newfd, all->mem, all->size)
1520 			    != (off_t) all->size))
1521 		goto nonew_unlink;
1522 
1523 	      /* Pad the file if its size is odd.  */
1524 	      if ((all->size & 1) != 0)
1525 		if (unlikely (write_retry (newfd, "\n", 1) != 1))
1526 		  goto nonew_unlink;
1527 	    }
1528 	  else
1529 	    {
1530 	      /* This is a member from the archive.  */
1531 	      if (write_member (all, &start, &len, elf, cur_off, newfd)
1532 		  != 0)
1533 		goto nonew_unlink;
1534 	    }
1535 
1536 	  all = all->next;
1537 	}
1538 
1539       /* Write the last part.  */
1540       if (start != -1 && copy_content (elf, newfd, start, len))
1541 	goto nonew_unlink;
1542     }
1543 
1544   /* Set the mode of the new file to the same values the original file
1545      has.  */
1546   if (fd != -1)
1547     {
1548       /* Never complain about fchown failing.  But do it before
1549 	 setting the modes, or they might be reset/ignored if the
1550 	 owner is wrong.  */
1551       if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; }
1552       if (fchmod (newfd, st.st_mode & ALLPERMS) != 0
1553 	  || close (newfd) != 0)
1554         goto nonew_unlink;
1555       newfd = -1;
1556       if (rename (tmpfname, arfname) != 0)
1557 	goto nonew_unlink;
1558     }
1559 
1560  errout:
1561   for (int cnt = 0; cnt < argc; ++cnt)
1562     elf_end (found[cnt]->elf);
1563 
1564   elf_end (elf);
1565 
1566   arlib_fini ();
1567 
1568   if (fd != -1)
1569     close (fd);
1570 
1571   if (newfd != -1)
1572     close (newfd);
1573 
1574   return status;
1575 }
1576 
1577 
1578 #include "debugpred.h"
1579