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