• 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 
498       if (strcmp (arhdr->ar_name, "/") == 0)
499 	{
500 	  index_off = elf_getaroff (subelf);
501 	  index_size = arhdr->ar_size;
502 	  goto next;
503 	}
504       if (strcmp (arhdr->ar_name, "//") == 0)
505 	goto next;
506 
507       if (force_symtab)
508 	{
509 	  arlib_add_symbols (elf, arfname, arhdr->ar_name, cur_off);
510 	  cur_off += (((arhdr->ar_size + 1) & ~((off_t) 1))
511 		      + sizeof (struct ar_hdr));
512 	}
513 
514       bool do_extract = argc <= 0;
515       if (!do_extract)
516 	{
517 	  ENTRY entry;
518 	  entry.key = arhdr->ar_name;
519 	  ENTRY *res = hsearch (entry, FIND);
520 	  if (res != NULL && (instance < 0 || --instance == 0)
521 	      && !found[(char **) res->data - argv])
522 	    found[(char **) res->data - argv] = do_extract = true;
523 	}
524 
525       if (do_extract)
526 	{
527 	  if (verbose)
528 	    {
529 	      if (oper == oper_print)
530 		{
531 		  printf ("\n<%s>\n\n", arhdr->ar_name);
532 
533 		  /* We have to flush now because now we use the descriptor
534 		     directly.  */
535 		  fflush (stdout);
536 		}
537 	      else if (oper == oper_list)
538 		{
539 		  char datestr[100];
540 		  struct tm *tp = localtime (&arhdr->ar_date);
541 		  if (tp == NULL)
542 		    {
543 		      time_t time = 0;
544 		      tp = localtime (&time);
545 		    }
546 
547 		  strftime (datestr, sizeof (datestr), "%b %e %H:%M %Y", tp);
548 
549 		  printf ("%c%c%c%c%c%c%c%c%c %u/%u %6ju %s %s\n",
550 			  (arhdr->ar_mode & S_IRUSR) ? 'r' : '-',
551 			  (arhdr->ar_mode & S_IWUSR) ? 'w' : '-',
552 			  (arhdr->ar_mode & S_IXUSR)
553 			  ? ((arhdr->ar_mode & S_ISUID) ? 's' : 'x')
554 			  : ((arhdr->ar_mode & S_ISUID) ? 'S' : '-'),
555 			  (arhdr->ar_mode & S_IRGRP) ? 'r' : '-',
556 			  (arhdr->ar_mode & S_IWGRP) ? 'w' : '-',
557 			  (arhdr->ar_mode & S_IXGRP)
558 			  ? ((arhdr->ar_mode & S_ISGID) ? 's' : 'x')
559 			  : ((arhdr->ar_mode & S_ISGID) ? 'S' : '-'),
560 			  (arhdr->ar_mode & S_IROTH) ? 'r' : '-',
561 			  (arhdr->ar_mode & S_IWOTH) ? 'w' : '-',
562 			  (arhdr->ar_mode & S_IXOTH)
563 			  ? ((arhdr->ar_mode & S_ISVTX) ? 't' : 'x')
564 			  : ((arhdr->ar_mode & S_ISVTX) ? 'T' : '-'),
565 			  arhdr->ar_uid,
566 			  arhdr->ar_gid,
567 			  (uintmax_t) arhdr->ar_size,
568 			  datestr,
569 			  arhdr->ar_name);
570 		}
571 	      else
572 		printf ("x - %s\n", arhdr->ar_name);
573 	    }
574 
575 	  if (oper == oper_list)
576 	    {
577 	      if (!verbose)
578 		puts (arhdr->ar_name);
579 
580 	      goto next;
581 	    }
582 
583 	  size_t nleft;
584 	  char *data = elf_rawfile (subelf, &nleft);
585 	  if (data == NULL)
586 	    {
587 	      error (0, 0, _("cannot read content of %s: %s"),
588 		     arhdr->ar_name, elf_errmsg (-1));
589 	      status = 1;
590 	      goto next;
591 	    }
592 
593 	  int xfd;
594 	  char tempfname[] = "XXXXXX";
595 	  bool use_mkstemp = true;
596 
597 	  if (oper == oper_print)
598 	    xfd = STDOUT_FILENO;
599 	  else
600 	    {
601 	      xfd = mkstemp (tempfname);
602 	      if (unlikely (xfd == -1))
603 		{
604 		  /* We cannot create a temporary file.  Try to overwrite
605 		     the file or create it if it does not exist.  */
606 		  int flags = O_WRONLY | O_CREAT;
607 		  if (dont_replace_existing)
608 		    flags |= O_EXCL;
609 		  else
610 		    flags |= O_TRUNC;
611 		  xfd = open (arhdr->ar_name, flags, 0600);
612 		  if (unlikely (xfd == -1))
613 		    {
614 		      int printlen = INT_MAX;
615 
616 		      if (should_truncate_fname (&name_max))
617 			{
618 			  /* Try to truncate the name.  First find out by how
619 			     much.  */
620 			  printlen = name_max;
621 			  char truncfname[name_max + 1];
622 			  *((char *) mempcpy (truncfname, arhdr->ar_name,
623 					      name_max)) = '\0';
624 
625 			  xfd = open (truncfname, flags, 0600);
626 			}
627 
628 		      if (xfd == -1)
629 			{
630 			  error (0, errno, _("cannot open %.*s"),
631 				 (int) printlen, arhdr->ar_name);
632 			  status = 1;
633 			  goto next;
634 			}
635 		    }
636 
637 		  use_mkstemp = false;
638 		}
639 	    }
640 
641 	  ssize_t n;
642 	  while ((n = TEMP_FAILURE_RETRY (write (xfd, data, nleft))) != -1)
643 	    {
644 	      nleft -= n;
645 	      if (nleft == 0)
646 		break;
647 	      data += n;
648 	    }
649 
650 	  if (unlikely (n == -1))
651 	    {
652 	      error (0, errno, _("failed to write %s"), arhdr->ar_name);
653 	      status = 1;
654 	      unlink (tempfname);
655 	      close (xfd);
656 	      goto next;
657 	    }
658 
659 	  if (oper != oper_print)
660 	    {
661 	      /* Fix up the mode.  */
662 	      if (unlikely (fchmod (xfd, arhdr->ar_mode) != 0))
663 		{
664 		  error (0, errno, _("cannot change mode of %s"),
665 			 arhdr->ar_name);
666 		  status = 0;
667 		}
668 
669 	      if (preserve_dates)
670 		{
671 		  struct timespec tv[2];
672 		  tv[0].tv_sec = arhdr->ar_date;
673 		  tv[0].tv_nsec = 0;
674 		  tv[1].tv_sec = arhdr->ar_date;
675 		  tv[1].tv_nsec = 0;
676 
677 		  if (unlikely (futimens (xfd, tv) != 0))
678 		    {
679 		      error (0, errno,
680 			     _("cannot change modification time of %s"),
681 			     arhdr->ar_name);
682 		      status = 1;
683 		    }
684 		}
685 
686 	      /* If we used a temporary file, move it do the right
687 		 name now.  */
688 	      if (use_mkstemp)
689 		{
690 		  int r;
691 
692 		  if (dont_replace_existing)
693 		    {
694 		      r = link (tempfname, arhdr->ar_name);
695 		      if (likely (r == 0))
696 			unlink (tempfname);
697 		    }
698 		  else
699 		    r = rename (tempfname, arhdr->ar_name);
700 
701 		  if (unlikely (r) != 0)
702 		    {
703 		      int printlen = INT_MAX;
704 
705 		      if (should_truncate_fname (&name_max))
706 			{
707 			  /* Try to truncate the name.  First find out by how
708 			     much.  */
709 			  printlen = name_max;
710 			  char truncfname[name_max + 1];
711 			  *((char *) mempcpy (truncfname, arhdr->ar_name,
712 					      name_max)) = '\0';
713 
714 			  if (dont_replace_existing)
715 			    {
716 			      r = link (tempfname, truncfname);
717 			      if (likely (r == 0))
718 				unlink (tempfname);
719 			    }
720 			  else
721 			    r = rename (tempfname, truncfname);
722 			}
723 
724 		      if (r != 0)
725 			{
726 			  error (0, errno, _("\
727 cannot rename temporary file to %.*s"),
728 				 printlen, arhdr->ar_name);
729 			  unlink (tempfname);
730 			  status = 1;
731 			}
732 		    }
733 		}
734 
735 	      close (xfd);
736 	    }
737 	}
738 
739     next:
740       cmd = elf_next (subelf);
741       if (elf_end (subelf) != 0)
742 	error (1, 0, "%s: %s", arfname, elf_errmsg (-1));
743     }
744 
745   hdestroy ();
746 
747   if (force_symtab)
748     {
749       arlib_finalize ();
750 
751       if (symtab.symsnamelen != 0
752 	  /* We have to rewrite the file also if it initially had an index
753 	     but now does not need one anymore.  */
754 	  || (symtab.symsnamelen == 0 && index_size != 0))
755 	{
756 	  char tmpfname[strlen (arfname) + 7];
757 	  strcpy (stpcpy (tmpfname, arfname), "XXXXXX");
758 	  int newfd = mkstemp (tmpfname);
759 	  if (unlikely (newfd == -1))
760 	    {
761 	    nonew:
762 	      error (0, errno, _("cannot create new file"));
763 	      status = 1;
764 	    }
765 	  else
766 	    {
767 	      /* Create the header.  */
768 	      if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
769 		{
770 		  // XXX Use /prof/self/fd/%d ???
771 		nonew_unlink:
772 		  unlink (tmpfname);
773 		  if (newfd != -1)
774 		    close (newfd);
775 		  goto nonew;
776 		}
777 
778 	      /* Create the new file.  There are three parts as far we are
779 		 concerned: 1. original context before the index, 2. the
780 		 new index, 3. everything after the new index.  */
781 	      off_t rest_off;
782 	      if (index_off != -1)
783 		rest_off = (index_off + sizeof (struct ar_hdr)
784 			    + ((index_size + 1) & ~1ul));
785 	      else
786 		rest_off = SARMAG;
787 
788 	      if (symtab.symsnamelen != 0
789 		   && ((write_retry (newfd, symtab.symsoff,
790 				     symtab.symsofflen)
791 			!= (ssize_t) symtab.symsofflen)
792 		       || (write_retry (newfd, symtab.symsname,
793 					symtab.symsnamelen)
794 			   != (ssize_t) symtab.symsnamelen)))
795 		goto nonew_unlink;
796 	      /* Even if the original file had content before the
797 		 symbol table, we write it in the correct order.  */
798 	      if ((index_off != SARMAG
799 		   && copy_content (elf, newfd, SARMAG, index_off - SARMAG))
800 		  || copy_content (elf, newfd, rest_off, st.st_size - rest_off))
801 		goto nonew_unlink;
802 
803 	      /* Never complain about fchown failing.  */
804 	      if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; }
805 	      /* Set the mode of the new file to the same values the
806 		 original file has.  */
807 	      if (fchmod (newfd, st.st_mode & ALLPERMS) != 0
808 		  || close (newfd) != 0)
809 		goto nonew_unlink;
810 	      newfd = -1;
811 	      if (rename (tmpfname, arfname) != 0)
812 		goto nonew_unlink;
813 	    }
814 	}
815     }
816 
817   elf_end (elf);
818 
819   close (fd);
820 
821   not_found (argc, argv, found);
822 
823   return status;
824 }
825 
826 
827 struct armem
828 {
829   off_t off;
830   off_t old_off;
831   size_t size;
832   long int long_name_off;
833   struct armem *next;
834   void *mem;
835   time_t sec;
836   uid_t uid;
837   gid_t gid;
838   mode_t mode;
839   const char *name;
840   Elf *elf;
841 };
842 
843 
844 static int
write_member(struct armem * memb,off_t * startp,off_t * lenp,Elf * elf,off_t end_off,int newfd)845 write_member (struct armem *memb, off_t *startp, off_t *lenp, Elf *elf,
846 	      off_t end_off, int newfd)
847 {
848   struct ar_hdr arhdr;
849   /* The ar_name is not actually zero terminated, but we need that for
850      snprintf.  Also if the name is too long, then the string starts
851      with '/' plus an index off number (decimal).  */
852   char tmpbuf[sizeof (arhdr.ar_name) + 2];
853 
854   bool changed_header = memb->long_name_off != -1;
855   if (changed_header)
856     {
857       /* In case of a long file name we assume the archive header
858 	 changed and we write it here.  */
859       memcpy (&arhdr, elf_rawfile (elf, NULL) + *startp, sizeof (arhdr));
860 
861       snprintf (tmpbuf, sizeof (tmpbuf), "/%-*ld",
862 		(int) sizeof (arhdr.ar_name), memb->long_name_off);
863       changed_header = memcmp (arhdr.ar_name, tmpbuf,
864 			       sizeof (arhdr.ar_name)) != 0;
865     }
866 
867   /* If the files are adjacent in the old file extend the range.  */
868   if (*startp != -1 && !changed_header && *startp + *lenp == memb->old_off)
869     {
870       /* Extend the current range.  */
871       *lenp += (memb->next != NULL
872 		? memb->next->off : end_off) - memb->off;
873       return 0;
874     }
875 
876   /* Write out the old range.  */
877   if (*startp != -1 && copy_content (elf, newfd, *startp, *lenp))
878     return -1;
879 
880   *startp = memb->old_off;
881   *lenp = (memb->next != NULL ? memb->next->off : end_off) - memb->off;
882 
883   if (changed_header)
884     {
885       memcpy (arhdr.ar_name, tmpbuf, sizeof (arhdr.ar_name));
886 
887       if (unlikely (write_retry (newfd, &arhdr, sizeof (arhdr))
888 		    != sizeof (arhdr)))
889 	return -1;
890 
891       *startp += sizeof (struct ar_hdr);
892       assert ((size_t) *lenp >= sizeof (struct ar_hdr));
893       *lenp -= sizeof (struct ar_hdr);
894     }
895 
896   return 0;
897 }
898 
899 /* Store the name in the long name table if necessary.
900    Record its offset or -1 if we did not need to use the table.  */
901 static void
remember_long_name(struct armem * mem,const char * name,size_t namelen)902 remember_long_name (struct armem *mem, const char *name, size_t namelen)
903 {
904   mem->long_name_off = (namelen > MAX_AR_NAME_LEN
905 			? arlib_add_long_name (name, namelen)
906 			: -1l);
907 }
908 
909 static int
do_oper_delete(const char * arfname,char ** argv,int argc,long int instance)910 do_oper_delete (const char *arfname, char **argv, int argc,
911 		long int instance)
912 {
913   bool *found = alloca (sizeof (bool) * argc);
914   memset (found, '\0', sizeof (bool) * argc);
915 
916   /* List of the files we keep.  */
917   struct armem *to_copy = NULL;
918 
919   int status = 0;
920   Elf *elf;
921   struct stat st;
922   int fd = open_archive (arfname, O_RDONLY, 0, &elf, &st, false);
923 
924   if (hcreate (2 * argc) == 0)
925     error_exit (errno, _("cannot create hash table"));
926 
927   for (int cnt = 0; cnt < argc; ++cnt)
928     {
929       ENTRY entry = { .key = argv[cnt], .data = &argv[cnt] };
930       if (hsearch (entry, ENTER) == NULL)
931 	error_exit (errno, _("cannot insert into hash table"));
932     }
933 
934   arlib_init ();
935 
936   off_t cur_off = SARMAG;
937   Elf_Cmd cmd = ELF_C_READ_MMAP;
938   Elf *subelf;
939   while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
940     {
941       Elf_Arhdr *arhdr = elf_getarhdr (subelf);
942 
943       /* Ignore the symbol table and the long file name table here.  */
944       if (strcmp (arhdr->ar_name, "/") == 0
945 	  || strcmp (arhdr->ar_name, "//") == 0)
946 	goto next;
947 
948       bool do_delete = argc <= 0;
949       if (!do_delete)
950 	{
951 	  ENTRY entry;
952 	  entry.key = arhdr->ar_name;
953 	  ENTRY *res = hsearch (entry, FIND);
954 	  if (res != NULL && (instance < 0 || --instance == 0)
955 	      && !found[(char **) res->data - argv])
956 	    found[(char **) res->data - argv] = do_delete = true;
957 	}
958 
959       if (do_delete)
960 	{
961 	  if (verbose)
962 	    printf ("d - %s\n", arhdr->ar_name);
963 	}
964       else
965 	{
966 	  struct armem *newp = alloca (sizeof (struct armem));
967 	  newp->old_off = elf_getaroff (subelf);
968 	  newp->off = cur_off;
969 
970 	  cur_off += (((arhdr->ar_size + 1) & ~((off_t) 1))
971 		      + sizeof (struct ar_hdr));
972 
973 	  if (to_copy == NULL)
974 	    to_copy = newp->next = newp;
975 	  else
976 	    {
977 	      newp->next = to_copy->next;
978 	      to_copy = to_copy->next = newp;
979 	    }
980 
981 	  /* If we recreate the symbol table read the file's symbol
982 	     table now.  */
983 	  arlib_add_symbols (subelf, arfname, arhdr->ar_name, newp->off);
984 
985 	  /* Remember long file names.  */
986 	  remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name));
987 	}
988 
989     next:
990       cmd = elf_next (subelf);
991       if (elf_end (subelf) != 0)
992 	error (1, 0, "%s: %s", arfname, elf_errmsg (-1));
993     }
994 
995   arlib_finalize ();
996 
997   hdestroy ();
998 
999   /* Create a new, temporary file in the same directory as the
1000      original file.  */
1001   char tmpfname[strlen (arfname) + 7];
1002   strcpy (stpcpy (tmpfname, arfname), "XXXXXX");
1003   int newfd = mkstemp (tmpfname);
1004   if (unlikely (newfd == -1))
1005     goto nonew;
1006 
1007   /* Create the header.  */
1008   if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
1009     {
1010       // XXX Use /prof/self/fd/%d ???
1011     nonew_unlink:
1012       unlink (tmpfname);
1013       if (newfd != -1)
1014 	close (newfd);
1015     nonew:
1016       error (0, errno, _("cannot create new file"));
1017       status = 1;
1018       goto errout;
1019     }
1020 
1021   /* If the archive is empty that is all we have to do.  */
1022   if (likely (to_copy != NULL))
1023     {
1024       /* Write the symbol table or the long file name table or both.  */
1025       if (symtab.symsnamelen != 0
1026 	  && ((write_retry (newfd, symtab.symsoff, symtab.symsofflen)
1027 	       != (ssize_t) symtab.symsofflen)
1028 	      || (write_retry (newfd, symtab.symsname, symtab.symsnamelen)
1029 		  != (ssize_t) symtab.symsnamelen)))
1030 	goto nonew_unlink;
1031 
1032       if (symtab.longnameslen > sizeof (struct ar_hdr)
1033 	  && (write_retry (newfd, symtab.longnames, symtab.longnameslen)
1034 	      != (ssize_t) symtab.longnameslen))
1035 	goto nonew_unlink;
1036 
1037       /* NULL-terminate the list of files to copy.  */
1038       struct armem *last = to_copy;
1039       to_copy = to_copy->next;
1040       last->next = NULL;
1041 
1042       off_t start = -1;
1043       off_t len = -1;
1044 
1045       do
1046 	if (write_member (to_copy, &start, &len, elf, cur_off, newfd) != 0)
1047 	  goto nonew_unlink;
1048       while ((to_copy = to_copy->next) != NULL);
1049 
1050       /* Write the last part.  */
1051       if (copy_content (elf, newfd, start, len))
1052 	goto nonew_unlink;
1053     }
1054 
1055   /* Set the mode of the new file to the same values the original file
1056      has.  Never complain about fchown failing.  But do it before
1057      setting the mode (which might be reset/ignored if the owner is
1058      wrong.  */
1059   if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; }
1060   if (fchmod (newfd, st.st_mode & ALLPERMS) != 0
1061       || close (newfd) != 0)
1062     goto nonew_unlink;
1063   newfd = -1;
1064   if (rename (tmpfname, arfname) != 0)
1065     goto nonew_unlink;
1066 
1067  errout:
1068   elf_end (elf);
1069 
1070   arlib_fini ();
1071 
1072   close (fd);
1073 
1074   not_found (argc, argv, found);
1075 
1076   return status;
1077 }
1078 
1079 
1080 /* Prints the given value in the given buffer without a trailing zero char.
1081    Returns false if the given value doesn't fit in the given buffer.  */
1082 static bool
no0print(bool ofmt,char * buf,int bufsize,long int val)1083 no0print (bool ofmt, char *buf, int bufsize, long int val)
1084 {
1085   char tmpbuf[bufsize + 1];
1086   int ret = snprintf (tmpbuf, sizeof (tmpbuf), ofmt ? "%-*lo" : "%-*ld",
1087 		      bufsize, val);
1088   if (ret >= (int) sizeof (tmpbuf))
1089     return false;
1090   memcpy (buf, tmpbuf, bufsize);
1091   return true;
1092 }
1093 
1094 
1095 static int
do_oper_insert(int oper,const char * arfname,char ** argv,int argc,const char * member)1096 do_oper_insert (int oper, const char *arfname, char **argv, int argc,
1097 		const char *member)
1098 {
1099   int status = 0;
1100   Elf *elf = NULL;
1101   struct stat st;
1102   int fd = open_archive (arfname, O_RDONLY, 0, &elf, &st, oper != oper_move);
1103 
1104   /* List of the files we keep.  */
1105   struct armem *all = NULL;
1106   struct armem *after_memberelem = NULL;
1107   struct armem **found = alloca (sizeof (*found) * argc);
1108   memset (found, '\0', sizeof (*found) * argc);
1109 
1110   arlib_init ();
1111 
1112   /* Initialize early for no_old case.  */
1113   off_t cur_off = SARMAG;
1114 
1115   if (fd == -1)
1116     {
1117       if (!suppress_create_msg)
1118 	fprintf (stderr, "%s: creating %s\n",
1119 		 program_invocation_short_name, arfname);
1120 
1121       goto no_old;
1122     }
1123 
1124   /* Store the names of all files from the command line in a hash
1125      table so that we can match it.  Note that when no file name is
1126      given we are basically doing nothing except recreating the
1127      index.  */
1128   if (oper != oper_qappend)
1129     {
1130       if (hcreate (2 * argc) == 0)
1131 	error_exit (errno, _("cannot create hash table"));
1132 
1133       for (int cnt = 0; cnt < argc; ++cnt)
1134 	{
1135 	  ENTRY entry;
1136 	  entry.key = full_path ? argv[cnt] : basename (argv[cnt]);
1137 	  entry.data = &argv[cnt];
1138 	  if (hsearch (entry, ENTER) == NULL)
1139 	    error_exit (errno, _("cannot insert into hash table"));
1140 	}
1141     }
1142 
1143   /* While iterating over the current content of the archive we must
1144      determine a number of things: which archive members to keep,
1145      which are replaced, and where to insert the new members.  */
1146   Elf_Cmd cmd = ELF_C_READ_MMAP;
1147   Elf *subelf;
1148   while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
1149     {
1150       Elf_Arhdr *arhdr = elf_getarhdr (subelf);
1151 
1152       /* Ignore the symbol table and the long file name table here.  */
1153       if (strcmp (arhdr->ar_name, "/") == 0
1154 	  || strcmp (arhdr->ar_name, "//") == 0)
1155 	goto next;
1156 
1157       struct armem *newp = alloca (sizeof (struct armem));
1158       newp->old_off = elf_getaroff (subelf);
1159       newp->size = arhdr->ar_size;
1160       newp->sec = arhdr->ar_date;
1161       newp->mem = NULL;
1162 
1163       /* Remember long file names.  */
1164       remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name));
1165 
1166       /* Check whether this is a file we are looking for.  */
1167       if (oper != oper_qappend)
1168 	{
1169 	  /* Check whether this is the member used as the insert point.  */
1170 	  if (member != NULL && strcmp (arhdr->ar_name, member) == 0)
1171 	    {
1172 	      /* Note that all == NULL means insert at the beginning.  */
1173 	      if (ipos == ipos_before)
1174 		after_memberelem = all;
1175 	      else
1176 		after_memberelem = newp;
1177 	      member = NULL;
1178 	    }
1179 
1180 	  ENTRY entry;
1181 	  entry.key = arhdr->ar_name;
1182 	  ENTRY *res = hsearch (entry, FIND);
1183 	  if (res != NULL && found[(char **) res->data - argv] == NULL)
1184 	    {
1185 	      found[(char **) res->data - argv] = newp;
1186 
1187 	      /* If we insert before or after a certain element move
1188 		 all files to a special list.  */
1189 	      if (unlikely (ipos != ipos_none || oper == oper_move))
1190 		{
1191 		  if (after_memberelem == newp)
1192 		    /* Since we remove this element even though we should
1193 		       insert everything after it, we in fact insert
1194 		       everything after the previous element.  */
1195 		    after_memberelem = all;
1196 
1197 		  goto next;
1198 		}
1199 	    }
1200 	}
1201 
1202       if (all == NULL)
1203 	all = newp->next = newp;
1204       else
1205 	{
1206 	  newp->next = all->next;
1207 	  all = all->next = newp;
1208 	}
1209 
1210     next:
1211       cmd = elf_next (subelf);
1212       if (elf_end (subelf) != 0)
1213 	error_exit (0, "%s: %s", arfname, elf_errmsg (-1));
1214     }
1215 
1216   if (oper != oper_qappend)
1217     hdestroy ();
1218 
1219  no_old:
1220   if (member != NULL)
1221     error_exit (0, _("position member %s not found"),
1222 		member);
1223 
1224   if (oper == oper_move)
1225     {
1226       /* Make sure all requested elements are found in the archive.  */
1227       for (int cnt = 0; cnt < argc; ++cnt)
1228 	{
1229 	  if (found[cnt] == NULL)
1230 	    {
1231 	      fprintf (stderr, _("%s: no entry %s in archive!\n"),
1232 		       program_invocation_short_name, argv[cnt]);
1233 	      status = 1;
1234 	    }
1235 
1236 	  if (verbose)
1237 	    printf ("m - %s\n", argv[cnt]);
1238 	}
1239     }
1240   else
1241     {
1242       /* Open all the new files, get their sizes and add all symbols.  */
1243       for (int cnt = 0; cnt < argc; ++cnt)
1244 	{
1245 	  const char *bname = basename (argv[cnt]);
1246 	  size_t bnamelen = strlen (bname);
1247 	  if (found[cnt] == NULL)
1248 	    {
1249 	      found[cnt] = alloca (sizeof (struct armem));
1250 	      found[cnt]->old_off = -1;
1251 
1252 	      remember_long_name (found[cnt], bname, bnamelen);
1253 	    }
1254 
1255 	  struct stat newst;
1256 	  Elf *newelf;
1257 	  int newfd = open (argv[cnt], O_RDONLY);
1258 	  if (newfd == -1)
1259 	    {
1260 	      error (0, errno, _("cannot open %s"), argv[cnt]);
1261 	      status = 1;
1262 	    }
1263 	  else if (fstat (newfd, &newst) == -1)
1264 	    {
1265 	      error (0, errno, _("cannot stat %s"), argv[cnt]);
1266 	      close (newfd);
1267 	      status = 1;
1268 	    }
1269 	  else if (!S_ISREG (newst.st_mode))
1270 	    {
1271 	      error (0, errno, _("%s is no regular file"), argv[cnt]);
1272 	      close (newfd);
1273 	      status = 1;
1274 	    }
1275 	  else if (update_newer
1276 		   && found[cnt]->old_off != -1l
1277 		   && found[cnt]->sec > st.st_mtime)
1278 	    /* Do nothing, the file in the archive is younger.  */
1279 	    close (newfd);
1280 	  else if ((newelf = elf_begin (newfd, ELF_C_READ_MMAP, NULL))
1281 		   == NULL)
1282 	    {
1283 	      fprintf (stderr,
1284 		       _("cannot get ELF descriptor for %s: %s\n"),
1285 		       argv[cnt], elf_errmsg (-1));
1286 	      status = 1;
1287 	    }
1288 	  else
1289 	    {
1290 	      if (verbose)
1291 		printf ("%c - %s\n",
1292 			found[cnt]->old_off == -1l ? 'a' : 'r', argv[cnt]);
1293 
1294 	      found[cnt]->elf = newelf;
1295 	      found[cnt]->sec = arlib_deterministic_output ? 0 : newst.st_mtime;
1296 	      found[cnt]->uid = arlib_deterministic_output ? 0 : newst.st_uid;
1297 	      found[cnt]->gid = arlib_deterministic_output ? 0 : newst.st_gid;
1298 	      found[cnt]->mode = newst.st_mode;
1299 	      found[cnt]->name = bname;
1300 
1301 	      found[cnt]->mem = elf_rawfile (newelf, &found[cnt]->size);
1302 	      if (found[cnt]->mem == NULL
1303 		  || elf_cntl (newelf, ELF_C_FDDONE) != 0)
1304 		error_exit (0, _("cannot read %s: %s"),
1305 			    argv[cnt], elf_errmsg (-1));
1306 
1307 	      close (newfd);
1308 
1309 	      if (found[cnt]->old_off != -1l)
1310 		/* Remember long file names.  */
1311 		remember_long_name (found[cnt], bname, bnamelen);
1312 	    }
1313 	}
1314     }
1315 
1316   if (status != 0)
1317     {
1318       elf_end (elf);
1319 
1320       arlib_fini ();
1321 
1322       close (fd);
1323 
1324       return status;
1325     }
1326 
1327   /* If we have no entry point so far add at the end.  AFTER_MEMBERELEM
1328      being NULL when adding before an entry means add at the beginning.  */
1329   if (ipos != ipos_before && after_memberelem == NULL)
1330     after_memberelem = all;
1331 
1332   /* Convert the circular list into a normal list first.  */
1333   if (all != NULL)
1334     {
1335       struct armem *tmp = all;
1336       all = all->next;
1337       tmp->next = NULL;
1338     }
1339 
1340   struct armem *last_added = after_memberelem;
1341   for (int cnt = 0; cnt < argc; ++cnt)
1342     if (oper != oper_replace || found[cnt]->old_off == -1)
1343       {
1344 	if (last_added == NULL)
1345 	  {
1346 	    found[cnt]->next = all;
1347 	    last_added = all = found[cnt];
1348 	  }
1349 	else
1350 	  {
1351 	    found[cnt]->next = last_added->next;
1352 	    last_added = last_added->next = found[cnt];
1353 	  }
1354       }
1355 
1356   /* Finally compute the offset and add the symbols for the files
1357      after the insert point.  */
1358   if (likely (all != NULL))
1359     for (struct armem *memp = all; memp != NULL; memp = memp->next)
1360       {
1361 	memp->off = cur_off;
1362 
1363 	if (memp->mem == NULL)
1364 	  {
1365 	    Elf_Arhdr *arhdr;
1366 	    /* Fake initializing arhdr and subelf to keep gcc calm.  */
1367 	    asm ("" : "=m" (arhdr), "=m" (subelf));
1368 	    if (elf_rand (elf, memp->old_off) == 0
1369 		|| (subelf = elf_begin (fd, ELF_C_READ_MMAP, elf)) == NULL
1370 		|| (arhdr = elf_getarhdr (subelf)) == NULL)
1371 	      /* This should never happen since we already looked at the
1372 		 archive content.  But who knows...  */
1373 	      error_exit (0, "%s: %s", arfname, elf_errmsg (-1));
1374 
1375 	    arlib_add_symbols (subelf, arfname, arhdr->ar_name, cur_off);
1376 
1377 	    elf_end (subelf);
1378 	  }
1379 	else
1380 	  arlib_add_symbols (memp->elf, arfname, memp->name, cur_off);
1381 
1382 	cur_off += (((memp->size + 1) & ~((off_t) 1))
1383 		    + sizeof (struct ar_hdr));
1384       }
1385 
1386   /* Now we have all the information for the symbol table and long
1387      file name table.  Construct the final layout.  */
1388   arlib_finalize ();
1389 
1390   /* Create a new, temporary file in the same directory as the
1391      original file.  */
1392   char tmpfname[strlen (arfname) + 7];
1393   strcpy (stpcpy (tmpfname, arfname), "XXXXXX");
1394   int newfd;
1395   if (fd != -1)
1396     newfd = mkstemp (tmpfname);
1397   else
1398     {
1399       newfd = open (arfname, O_RDWR | O_CREAT | O_EXCL, DEFFILEMODE);
1400       if (newfd == -1 && errno == EEXIST)
1401 	/* Bah, first the file did not exist, now it does.  Restart.  */
1402 	return do_oper_insert (oper, arfname, argv, argc, member);
1403     }
1404   if (unlikely (newfd == -1))
1405     goto nonew;
1406 
1407   /* Create the header.  */
1408   if (unlikely (write_retry (newfd, ARMAG, SARMAG) != SARMAG))
1409     {
1410     nonew_unlink:
1411       if (fd != -1)
1412 	{
1413 	  // XXX Use /prof/self/fd/%d ???
1414 	  unlink (tmpfname);
1415 	  if (newfd != -1)
1416 	    close (newfd);
1417 	}
1418     nonew:
1419       error (0, errno, _("cannot create new file"));
1420       status = 1;
1421       goto errout;
1422     }
1423 
1424   /* If the new archive is not empty we actually have something to do.  */
1425   if (likely (all != NULL))
1426     {
1427       /* Write the symbol table or the long file name table or both.  */
1428       if (symtab.symsnamelen != 0
1429 	  && ((write_retry (newfd, symtab.symsoff, symtab.symsofflen)
1430 	       != (ssize_t) symtab.symsofflen)
1431 	      || (write_retry (newfd, symtab.symsname, symtab.symsnamelen)
1432 		  != (ssize_t) symtab.symsnamelen)))
1433 	goto nonew_unlink;
1434 
1435       if (symtab.longnameslen > sizeof (struct ar_hdr)
1436 	  && (write_retry (newfd, symtab.longnames, symtab.longnameslen)
1437 	      != (ssize_t) symtab.longnameslen))
1438 	goto nonew_unlink;
1439 
1440       off_t start = -1;
1441       off_t len = -1;
1442 
1443       while (all != NULL)
1444 	{
1445 	  if (all->mem != NULL)
1446 	    {
1447 	      /* This is a new file.  If there is anything from the
1448 		 archive left to be written do it now.  */
1449 	      if (start != -1  && copy_content (elf, newfd, start, len))
1450 		goto nonew_unlink;
1451 
1452 	      start = -1;
1453 	      len = -1;
1454 
1455 	      /* Create the header.  */
1456 	      struct ar_hdr arhdr;
1457 	      /* The ar_name is not actually zero terminated, but we
1458 		 need that for snprintf.  Also if the name is too
1459 		 long, then the string starts with '/' plus an index
1460 		 off number (decimal).  */
1461 	      char tmpbuf[sizeof (arhdr.ar_name) + 2];
1462 	      if (all->long_name_off == -1)
1463 		{
1464 		  size_t namelen = strlen (all->name);
1465 		  char *p = mempcpy (arhdr.ar_name, all->name, namelen);
1466 		  *p++ = '/';
1467 		  memset (p, ' ', sizeof (arhdr.ar_name) - namelen - 1);
1468 		}
1469 	      else
1470 		{
1471 		  snprintf (tmpbuf, sizeof (tmpbuf), "/%-*ld",
1472 			    (int) sizeof (arhdr.ar_name), all->long_name_off);
1473 		  memcpy (arhdr.ar_name, tmpbuf, sizeof (arhdr.ar_name));
1474 		}
1475 
1476 	      if (! no0print (false, arhdr.ar_date, sizeof (arhdr.ar_date),
1477 			      all->sec))
1478 		{
1479 		  error (0, errno, _("cannot represent ar_date"));
1480 		  goto nonew_unlink;
1481 		}
1482 	      if (! no0print (false, arhdr.ar_uid, sizeof (arhdr.ar_uid),
1483 			      all->uid))
1484 		{
1485 		  error (0, errno, _("cannot represent ar_uid"));
1486 		  goto nonew_unlink;
1487 		}
1488 	      if (! no0print (false, arhdr.ar_gid, sizeof (arhdr.ar_gid),
1489 			      all->gid))
1490 		{
1491 		  error (0, errno, _("cannot represent ar_gid"));
1492 		  goto nonew_unlink;
1493 		}
1494 	      if (! no0print (true, arhdr.ar_mode, sizeof (arhdr.ar_mode),
1495 			all->mode))
1496 		{
1497 		  error (0, errno, _("cannot represent ar_mode"));
1498 		  goto nonew_unlink;
1499 		}
1500 	      if (! no0print (false, arhdr.ar_size, sizeof (arhdr.ar_size),
1501 			all->size))
1502 		{
1503 		  error (0, errno, _("cannot represent ar_size"));
1504 		  goto nonew_unlink;
1505 		}
1506 	      memcpy (arhdr.ar_fmag, ARFMAG, sizeof (arhdr.ar_fmag));
1507 
1508 	      if (unlikely (write_retry (newfd, &arhdr, sizeof (arhdr))
1509 			    != sizeof (arhdr)))
1510 		goto nonew_unlink;
1511 
1512 	      /* Now the file itself.  */
1513 	      if (unlikely (write_retry (newfd, all->mem, all->size)
1514 			    != (off_t) all->size))
1515 		goto nonew_unlink;
1516 
1517 	      /* Pad the file if its size is odd.  */
1518 	      if ((all->size & 1) != 0)
1519 		if (unlikely (write_retry (newfd, "\n", 1) != 1))
1520 		  goto nonew_unlink;
1521 	    }
1522 	  else
1523 	    {
1524 	      /* This is a member from the archive.  */
1525 	      if (write_member (all, &start, &len, elf, cur_off, newfd)
1526 		  != 0)
1527 		goto nonew_unlink;
1528 	    }
1529 
1530 	  all = all->next;
1531 	}
1532 
1533       /* Write the last part.  */
1534       if (start != -1 && copy_content (elf, newfd, start, len))
1535 	goto nonew_unlink;
1536     }
1537 
1538   /* Set the mode of the new file to the same values the original file
1539      has.  */
1540   if (fd != -1)
1541     {
1542       /* Never complain about fchown failing.  But do it before
1543 	 setting the modes, or they might be reset/ignored if the
1544 	 owner is wrong.  */
1545       if (fchown (newfd, st.st_uid, st.st_gid) != 0) { ; }
1546       if (fchmod (newfd, st.st_mode & ALLPERMS) != 0
1547 	  || close (newfd) != 0)
1548         goto nonew_unlink;
1549       newfd = -1;
1550       if (rename (tmpfname, arfname) != 0)
1551 	goto nonew_unlink;
1552     }
1553 
1554  errout:
1555   for (int cnt = 0; cnt < argc; ++cnt)
1556     elf_end (found[cnt]->elf);
1557 
1558   elf_end (elf);
1559 
1560   arlib_fini ();
1561 
1562   if (fd != -1)
1563     close (fd);
1564 
1565   if (newfd != -1)
1566     close (newfd);
1567 
1568   return status;
1569 }
1570 
1571 
1572 #include "debugpred.h"
1573