1/* ar.c - Archive modify and extract.
2   Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
3   2001, 2002, 2003, 2004, 2005
4   Free Software Foundation, Inc.
5
6   This file is part of GNU Binutils.
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
21
22/*
23   Bugs: should use getopt the way tar does (complete w/optional -) and
24   should have long options too. GNU ar used to check file against filesystem
25   in quick_update and replace operations (would check mtime). Doesn't warn
26   when name truncated. No way to specify pos_end. Error messages should be
27   more consistent.  */
28
29#include "bfd.h"
30#include "libiberty.h"
31#include "progress.h"
32#include "bucomm.h"
33#include "aout/ar.h"
34#include "libbfd.h"
35#include "arsup.h"
36#include "filenames.h"
37#include "binemul.h"
38#include <sys/stat.h>
39
40#ifdef __GO32___
41#define EXT_NAME_LEN 3		/* bufflen of addition to name if it's MS-DOS */
42#else
43#define EXT_NAME_LEN 6		/* ditto for *NIX */
44#endif
45
46/* We need to open files in binary modes on system where that makes a
47   difference.  */
48#ifndef O_BINARY
49#define O_BINARY 0
50#endif
51
52#if defined(__BEOS__) || defined(__HAIKU__)
53#include <OS.h>
54/* the thread priority used for all gcc-tools */
55static int priority = B_LOW_PRIORITY;
56#endif
57
58/* Kludge declaration from BFD!  This is ugly!  FIXME!  XXX */
59
60struct ar_hdr *
61  bfd_special_undocumented_glue (bfd * abfd, const char *filename);
62
63/* Static declarations */
64
65static void mri_emul (void);
66static const char *normalize (const char *, bfd *);
67static void remove_output (void);
68static void map_over_members (bfd *, void (*)(bfd *), char **, int);
69static void print_contents (bfd * member);
70static void delete_members (bfd *, char **files_to_delete);
71
72static void move_members (bfd *, char **files_to_move);
73static void replace_members
74  (bfd *, char **files_to_replace, bfd_boolean quick);
75static void print_descr (bfd * abfd);
76static void write_archive (bfd *);
77static void ranlib_only (const char *archname);
78static void ranlib_touch (const char *archname);
79static void usage (int);
80
81/** Globals and flags */
82
83static int mri_mode;
84
85/* This flag distinguishes between ar and ranlib:
86   1 means this is 'ranlib'; 0 means this is 'ar'.
87   -1 means if we should use argv[0] to decide.  */
88extern int is_ranlib;
89
90/* Nonzero means don't warn about creating the archive file if necessary.  */
91int silent_create = 0;
92
93/* Nonzero means describe each action performed.  */
94int verbose = 0;
95
96/* Nonzero means preserve dates of members when extracting them.  */
97int preserve_dates = 0;
98
99/* Nonzero means don't replace existing members whose dates are more recent
100   than the corresponding files.  */
101int newer_only = 0;
102
103/* Controls the writing of an archive symbol table (in BSD: a __.SYMDEF
104   member).  -1 means we've been explicitly asked to not write a symbol table;
105   +1 means we've been explicitly asked to write it;
106   0 is the default.
107   Traditionally, the default in BSD has been to not write the table.
108   However, for POSIX.2 compliance the default is now to write a symbol table
109   if any of the members are object files.  */
110int write_armap = 0;
111
112/* Nonzero means it's the name of an existing member; position new or moved
113   files with respect to this one.  */
114char *posname = NULL;
115
116/* Sez how to use `posname': pos_before means position before that member.
117   pos_after means position after that member. pos_end means always at end.
118   pos_default means default appropriately. For the latter two, `posname'
119   should also be zero.  */
120enum pos
121  {
122    pos_default, pos_before, pos_after, pos_end
123  } postype = pos_default;
124
125static bfd **
126get_pos_bfd (bfd **, enum pos, const char *);
127
128/* For extract/delete only.  If COUNTED_NAME_MODE is TRUE, we only
129   extract the COUNTED_NAME_COUNTER instance of that name.  */
130static bfd_boolean counted_name_mode = 0;
131static int counted_name_counter = 0;
132
133/* Whether to truncate names of files stored in the archive.  */
134static bfd_boolean ar_truncate = FALSE;
135
136/* Whether to use a full file name match when searching an archive.
137   This is convenient for archives created by the Microsoft lib
138   program.  */
139static bfd_boolean full_pathname = FALSE;
140
141int interactive = 0;
142
143static void
144mri_emul (void)
145{
146  interactive = isatty (fileno (stdin));
147  yyparse ();
148}
149
150/* If COUNT is 0, then FUNCTION is called once on each entry.  If nonzero,
151   COUNT is the length of the FILES chain; FUNCTION is called on each entry
152   whose name matches one in FILES.  */
153
154static void
155map_over_members (bfd *arch, void (*function)(bfd *), char **files, int count)
156{
157  bfd *head;
158  int match_count;
159
160  if (count == 0)
161    {
162      for (head = arch->next; head; head = head->next)
163	{
164	  PROGRESS (1);
165	  function (head);
166	}
167      return;
168    }
169
170  /* This may appear to be a baroque way of accomplishing what we want.
171     However we have to iterate over the filenames in order to notice where
172     a filename is requested but does not exist in the archive.  Ditto
173     mapping over each file each time -- we want to hack multiple
174     references.  */
175
176  for (; count > 0; files++, count--)
177    {
178      bfd_boolean found = FALSE;
179
180      match_count = 0;
181      for (head = arch->next; head; head = head->next)
182	{
183	  PROGRESS (1);
184	  if (head->filename == NULL)
185	    {
186	      /* Some archive formats don't get the filenames filled in
187		 until the elements are opened.  */
188	      struct stat buf;
189	      bfd_stat_arch_elt (head, &buf);
190	    }
191	  if ((head->filename != NULL) &&
192	      (!FILENAME_CMP (normalize (*files, arch), head->filename)))
193	    {
194	      ++match_count;
195	      if (counted_name_mode
196		  && match_count != counted_name_counter)
197		{
198		  /* Counting, and didn't match on count; go on to the
199                     next one.  */
200		  continue;
201		}
202
203	      found = TRUE;
204	      function (head);
205	    }
206	}
207      if (!found)
208	/* xgettext:c-format */
209	fprintf (stderr, _("no entry %s in archive\n"), *files);
210    }
211}
212
213bfd_boolean operation_alters_arch = FALSE;
214
215static void
216usage (int help)
217{
218  FILE *s;
219
220  s = help ? stdout : stderr;
221
222  if (! is_ranlib)
223    {
224      /* xgettext:c-format */
225      fprintf (s, _("Usage: %s [emulation options] [-]{dmpqrstx}[abcfilNoPsSuvV] [member-name] [count] archive-file file...\n"),
226	       program_name);
227      /* xgettext:c-format */
228      fprintf (s, _("       %s -M [<mri-script]\n"), program_name);
229      fprintf (s, _(" commands:\n"));
230      fprintf (s, _("  d            - delete file(s) from the archive\n"));
231      fprintf (s, _("  m[ab]        - move file(s) in the archive\n"));
232      fprintf (s, _("  p            - print file(s) found in the archive\n"));
233      fprintf (s, _("  q[f]         - quick append file(s) to the archive\n"));
234      fprintf (s, _("  r[ab][f][u]  - replace existing or insert new file(s) into the archive\n"));
235      fprintf (s, _("  t            - display contents of archive\n"));
236      fprintf (s, _("  x[o]         - extract file(s) from the archive\n"));
237      fprintf (s, _(" command specific modifiers:\n"));
238      fprintf (s, _("  [a]          - put file(s) after [member-name]\n"));
239      fprintf (s, _("  [b]          - put file(s) before [member-name] (same as [i])\n"));
240      fprintf (s, _("  [N]          - use instance [count] of name\n"));
241      fprintf (s, _("  [f]          - truncate inserted file names\n"));
242      fprintf (s, _("  [P]          - use full path names when matching\n"));
243      fprintf (s, _("  [o]          - preserve original dates\n"));
244      fprintf (s, _("  [u]          - only replace files that are newer than current archive contents\n"));
245      fprintf (s, _(" generic modifiers:\n"));
246      fprintf (s, _("  [c]          - do not warn if the library had to be created\n"));
247      fprintf (s, _("  [s]          - create an archive index (cf. ranlib)\n"));
248      fprintf (s, _("  [S]          - do not build a symbol table\n"));
249      fprintf (s, _("  [v]          - be verbose\n"));
250      fprintf (s, _("  [V]          - display the version number\n"));
251      fprintf (s, _("  @<file>      - read options from <file>\n"));
252
253      ar_emul_usage (s);
254    }
255  else
256    {
257      /* xgettext:c-format */
258      fprintf (s, _("Usage: %s [options] archive\n"), program_name);
259      fprintf (s, _(" Generate an index to speed access to archives\n"));
260      fprintf (s, _(" The options are:\n\
261  @<file>                      Read options from <file>\n\
262  -h --help                    Print this help message\n\
263  -V --version                 Print version information\n"));
264    }
265
266  list_supported_targets (program_name, stderr);
267
268  if (help)
269    fprintf (s, _("Report bugs to %s\n"), REPORT_BUGS_TO);
270
271  xexit (help ? 0 : 1);
272}
273
274/* Normalize a file name specified on the command line into a file
275   name which we will use in an archive.  */
276
277static const char *
278normalize (const char *file, bfd *abfd)
279{
280  const char *filename;
281
282  if (full_pathname)
283    return file;
284
285  filename = strrchr (file, '/');
286#ifdef HAVE_DOS_BASED_FILE_SYSTEM
287  {
288    /* We could have foo/bar\\baz, or foo\\bar, or d:bar.  */
289    char *bslash = strrchr (file, '\\');
290    if (filename == NULL || (bslash != NULL && bslash > filename))
291      filename = bslash;
292    if (filename == NULL && file[0] != '\0' && file[1] == ':')
293      filename = file + 1;
294  }
295#endif
296  if (filename != (char *) NULL)
297    filename++;
298  else
299    filename = file;
300
301  if (ar_truncate
302      && abfd != NULL
303      && strlen (filename) > abfd->xvec->ar_max_namelen)
304    {
305      char *s;
306
307      /* Space leak.  */
308      s = (char *) xmalloc (abfd->xvec->ar_max_namelen + 1);
309      memcpy (s, filename, abfd->xvec->ar_max_namelen);
310      s[abfd->xvec->ar_max_namelen] = '\0';
311      filename = s;
312    }
313
314  return filename;
315}
316
317/* Remove any output file.  This is only called via xatexit.  */
318
319static const char *output_filename = NULL;
320static FILE *output_file = NULL;
321static bfd *output_bfd = NULL;
322
323static void
324remove_output (void)
325{
326  if (output_filename != NULL)
327    {
328      if (output_bfd != NULL)
329	bfd_cache_close (output_bfd);
330      if (output_file != NULL)
331	fclose (output_file);
332      unlink_if_ordinary (output_filename);
333    }
334}
335
336/* The option parsing should be in its own function.
337   It will be when I have getopt working.  */
338
339int main (int, char **);
340
341int
342main (int argc, char **argv)
343{
344  char *arg_ptr;
345  char c;
346  enum
347    {
348      none = 0, delete, replace, print_table,
349      print_files, extract, move, quick_append
350    } operation = none;
351  int arg_index;
352  char **files;
353  int file_count;
354  char *inarch_filename;
355  int show_version;
356  int i;
357  int do_posix = 0;
358
359#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
360  setlocale (LC_MESSAGES, "");
361#endif
362#if defined (HAVE_SETLOCALE)
363  setlocale (LC_CTYPE, "");
364#endif
365  bindtextdomain (PACKAGE, LOCALEDIR);
366  textdomain (PACKAGE);
367
368  program_name = argv[0];
369  xmalloc_set_program_name (program_name);
370
371  expandargv (&argc, &argv);
372
373  if (is_ranlib < 0)
374    {
375      char *temp;
376
377      temp = strrchr (program_name, '/');
378#ifdef HAVE_DOS_BASED_FILE_SYSTEM
379      {
380	/* We could have foo/bar\\baz, or foo\\bar, or d:bar.  */
381	char *bslash = strrchr (program_name, '\\');
382	if (temp == NULL || (bslash != NULL && bslash > temp))
383	  temp = bslash;
384	if (temp == NULL && program_name[0] != '\0' && program_name[1] == ':')
385	  temp = program_name + 1;
386      }
387#endif
388      if (temp == NULL)
389	temp = program_name;
390      else
391	++temp;
392      if (strlen (temp) >= 6
393	  && FILENAME_CMP (temp + strlen (temp) - 6, "ranlib") == 0)
394	is_ranlib = 1;
395      else
396	is_ranlib = 0;
397    }
398
399  if (argc > 1 && argv[1][0] == '-')
400    {
401      if (strcmp (argv[1], "--help") == 0)
402	usage (1);
403      else if (strcmp (argv[1], "--version") == 0)
404	{
405	  if (is_ranlib)
406	    print_version ("ranlib");
407	  else
408	    print_version ("ar");
409	}
410#if defined(__BEOS__) || defined(__HAIKU__)
411      else if (!strncmp (argv[1], "-priority=", 10))
412	{
413	  priority = atol (argv[1] + 10);
414    }
415#endif
416    }
417
418#if defined(__BEOS__) || defined(__HAIKU__)
419  set_thread_priority (find_thread(NULL), priority);
420#endif
421
422  START_PROGRESS (program_name, 0);
423
424  bfd_init ();
425  set_default_bfd_target ();
426
427  show_version = 0;
428
429  xatexit (remove_output);
430
431  for (i = 1; i < argc; i++)
432    if (! ar_emul_parse_arg (argv[i]))
433      break;
434  argv += (i - 1);
435  argc -= (i - 1);
436
437  if (is_ranlib)
438    {
439      bfd_boolean touch = FALSE;
440
441      if (argc < 2
442	  || strcmp (argv[1], "--help") == 0
443	  || strcmp (argv[1], "-h") == 0
444	  || strcmp (argv[1], "-H") == 0)
445	usage (0);
446      if (strcmp (argv[1], "-V") == 0
447	  || strcmp (argv[1], "-v") == 0
448	  || strncmp (argv[1], "--v", 3) == 0)
449	print_version ("ranlib");
450      arg_index = 1;
451      if (strcmp (argv[1], "-t") == 0)
452	{
453	  ++arg_index;
454	  touch = TRUE;
455	}
456      while (arg_index < argc)
457	{
458	  if (! touch)
459	    ranlib_only (argv[arg_index]);
460	  else
461	    ranlib_touch (argv[arg_index]);
462	  ++arg_index;
463	}
464      xexit (0);
465    }
466
467  if (argc == 2 && strcmp (argv[1], "-M") == 0)
468    {
469      mri_emul ();
470      xexit (0);
471    }
472
473  if (argc < 2)
474    usage (0);
475
476  arg_index = 1;
477  arg_ptr = argv[arg_index];
478
479  if (*arg_ptr == '-')
480    {
481      /* When the first option starts with '-' we support POSIX-compatible
482	 option parsing.  */
483      do_posix = 1;
484      ++arg_ptr;			/* compatibility */
485    }
486
487  do
488    {
489      while ((c = *arg_ptr++) != '\0')
490	{
491	  switch (c)
492	    {
493	    case 'd':
494	    case 'm':
495	    case 'p':
496	    case 'q':
497	    case 'r':
498	    case 't':
499	    case 'x':
500	      if (operation != none)
501		fatal (_("two different operation options specified"));
502	      switch (c)
503		{
504		case 'd':
505		  operation = delete;
506		  operation_alters_arch = TRUE;
507		  break;
508		case 'm':
509		  operation = move;
510		  operation_alters_arch = TRUE;
511		  break;
512		case 'p':
513		  operation = print_files;
514		  break;
515		case 'q':
516		  operation = quick_append;
517		  operation_alters_arch = TRUE;
518		  break;
519		case 'r':
520		  operation = replace;
521		  operation_alters_arch = TRUE;
522		  break;
523		case 't':
524		  operation = print_table;
525		  break;
526		case 'x':
527		  operation = extract;
528		  break;
529		}
530	    case 'l':
531	      break;
532	    case 'c':
533	      silent_create = 1;
534	      break;
535	    case 'o':
536	      preserve_dates = 1;
537	      break;
538	    case 'V':
539	      show_version = TRUE;
540	      break;
541	    case 's':
542	      write_armap = 1;
543	      break;
544	    case 'S':
545	      write_armap = -1;
546	      break;
547	    case 'u':
548	      newer_only = 1;
549	      break;
550	    case 'v':
551	      verbose = 1;
552	      break;
553	    case 'a':
554	      postype = pos_after;
555	      break;
556	    case 'b':
557	      postype = pos_before;
558	      break;
559	    case 'i':
560	      postype = pos_before;
561	      break;
562	    case 'M':
563	      mri_mode = 1;
564	      break;
565	    case 'N':
566	      counted_name_mode = TRUE;
567	      break;
568	    case 'f':
569	      ar_truncate = TRUE;
570	      break;
571	    case 'P':
572	      full_pathname = TRUE;
573	      break;
574	    default:
575	      /* xgettext:c-format */
576	      non_fatal (_("illegal option -- %c"), c);
577	      usage (0);
578	    }
579	}
580
581      /* With POSIX-compatible option parsing continue with the next
582	 argument if it starts with '-'.  */
583      if (do_posix && arg_index + 1 < argc && argv[arg_index + 1][0] == '-')
584	arg_ptr = argv[++arg_index] + 1;
585      else
586	do_posix = 0;
587    }
588  while (do_posix);
589
590  if (show_version)
591    print_version ("ar");
592
593  ++arg_index;
594  if (arg_index >= argc)
595    usage (0);
596
597  if (mri_mode)
598    {
599      mri_emul ();
600    }
601  else
602    {
603      bfd *arch;
604
605      /* We don't use do_quick_append any more.  Too many systems
606	 expect ar to always rebuild the symbol table even when q is
607	 used.  */
608
609      /* We can't write an armap when using ar q, so just do ar r
610         instead.  */
611      if (operation == quick_append && write_armap)
612	operation = replace;
613
614      if ((operation == none || operation == print_table)
615	  && write_armap == 1)
616	{
617	  ranlib_only (argv[arg_index]);
618	  xexit (0);
619	}
620
621      if (operation == none)
622	fatal (_("no operation specified"));
623
624      if (newer_only && operation != replace)
625	fatal (_("`u' is only meaningful with the `r' option."));
626
627      if (postype != pos_default)
628	posname = argv[arg_index++];
629
630      if (counted_name_mode)
631	{
632	  if (operation != extract && operation != delete)
633	     fatal (_("`N' is only meaningful with the `x' and `d' options."));
634	  counted_name_counter = atoi (argv[arg_index++]);
635	  if (counted_name_counter <= 0)
636	    fatal (_("Value for `N' must be positive."));
637	}
638
639      inarch_filename = argv[arg_index++];
640
641      files = arg_index < argc ? argv + arg_index : NULL;
642      file_count = argc - arg_index;
643
644      arch = open_inarch (inarch_filename,
645			  files == NULL ? (char *) NULL : files[0]);
646
647      switch (operation)
648	{
649	case print_table:
650	  map_over_members (arch, print_descr, files, file_count);
651	  break;
652
653	case print_files:
654	  map_over_members (arch, print_contents, files, file_count);
655	  break;
656
657	case extract:
658	  map_over_members (arch, extract_file, files, file_count);
659	  break;
660
661	case delete:
662	  if (files != NULL)
663	    delete_members (arch, files);
664	  else
665	    output_filename = NULL;
666	  break;
667
668	case move:
669	  if (files != NULL)
670	    move_members (arch, files);
671	  else
672	    output_filename = NULL;
673	  break;
674
675	case replace:
676	case quick_append:
677	  if (files != NULL || write_armap > 0)
678	    replace_members (arch, files, operation == quick_append);
679	  else
680	    output_filename = NULL;
681	  break;
682
683	  /* Shouldn't happen! */
684	default:
685	  /* xgettext:c-format */
686	  fatal (_("internal error -- this option not implemented"));
687	}
688    }
689
690  END_PROGRESS (program_name);
691
692  xexit (0);
693  return 0;
694}
695
696bfd *
697open_inarch (const char *archive_filename, const char *file)
698{
699  const char *target;
700  bfd **last_one;
701  bfd *next_one;
702  struct stat sbuf;
703  bfd *arch;
704  char **matching;
705
706  bfd_set_error (bfd_error_no_error);
707
708  target = NULL;
709
710  if (stat (archive_filename, &sbuf) != 0)
711    {
712#if !defined(__GO32__) || defined(__DJGPP__)
713
714      /* FIXME: I don't understand why this fragment was ifndef'ed
715	 away for __GO32__; perhaps it was in the days of DJGPP v1.x.
716	 stat() works just fine in v2.x, so I think this should be
717	 removed.  For now, I enable it for DJGPP v2. -- EZ.  */
718
719/* KLUDGE ALERT! Temporary fix until I figger why
720   stat() is wrong ... think it's buried in GO32's IDT - Jax */
721      if (errno != ENOENT)
722	bfd_fatal (archive_filename);
723#endif
724
725      if (!operation_alters_arch)
726	{
727	  fprintf (stderr, "%s: ", program_name);
728	  perror (archive_filename);
729	  maybequit ();
730	  return NULL;
731	}
732
733      /* Try to figure out the target to use for the archive from the
734         first object on the list.  */
735      if (file != NULL)
736	{
737	  bfd *obj;
738
739	  obj = bfd_openr (file, NULL);
740	  if (obj != NULL)
741	    {
742	      if (bfd_check_format (obj, bfd_object))
743		target = bfd_get_target (obj);
744	      (void) bfd_close (obj);
745	    }
746	}
747
748      /* Create an empty archive.  */
749      arch = bfd_openw (archive_filename, target);
750      if (arch == NULL
751	  || ! bfd_set_format (arch, bfd_archive)
752	  || ! bfd_close (arch))
753	bfd_fatal (archive_filename);
754      else if (!silent_create)
755        non_fatal (_("creating %s"), archive_filename);
756
757      /* If we die creating a new archive, don't leave it around.  */
758      output_filename = archive_filename;
759    }
760
761  arch = bfd_openr (archive_filename, target);
762  if (arch == NULL)
763    {
764    bloser:
765      bfd_fatal (archive_filename);
766    }
767
768  if (! bfd_check_format_matches (arch, bfd_archive, &matching))
769    {
770      bfd_nonfatal (archive_filename);
771      if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
772	{
773	  list_matching_formats (matching);
774	  free (matching);
775	}
776      xexit (1);
777    }
778
779  last_one = &(arch->next);
780  /* Read all the contents right away, regardless.  */
781  for (next_one = bfd_openr_next_archived_file (arch, NULL);
782       next_one;
783       next_one = bfd_openr_next_archived_file (arch, next_one))
784    {
785      PROGRESS (1);
786      *last_one = next_one;
787      last_one = &next_one->next;
788    }
789  *last_one = (bfd *) NULL;
790  if (bfd_get_error () != bfd_error_no_more_archived_files)
791    goto bloser;
792  return arch;
793}
794
795static void
796print_contents (bfd *abfd)
797{
798  int ncopied = 0;
799  char *cbuf = xmalloc (BUFSIZE);
800  struct stat buf;
801  long size;
802  if (bfd_stat_arch_elt (abfd, &buf) != 0)
803    /* xgettext:c-format */
804    fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
805
806  if (verbose)
807    /* xgettext:c-format */
808    printf (_("\n<%s>\n\n"), bfd_get_filename (abfd));
809
810  bfd_seek (abfd, (file_ptr) 0, SEEK_SET);
811
812  size = buf.st_size;
813  while (ncopied < size)
814    {
815
816      int nread;
817      int tocopy = size - ncopied;
818      if (tocopy > BUFSIZE)
819	tocopy = BUFSIZE;
820
821      nread = bfd_bread (cbuf, (bfd_size_type) tocopy, abfd);
822      if (nread != tocopy)
823	/* xgettext:c-format */
824	fatal (_("%s is not a valid archive"),
825	       bfd_get_filename (bfd_my_archive (abfd)));
826      fwrite (cbuf, 1, nread, stdout);
827      ncopied += tocopy;
828    }
829  free (cbuf);
830}
831
832/* Extract a member of the archive into its own file.
833
834   We defer opening the new file until after we have read a BUFSIZ chunk of the
835   old one, since we know we have just read the archive header for the old
836   one.  Since most members are shorter than BUFSIZ, this means we will read
837   the old header, read the old data, write a new inode for the new file, and
838   write the new data, and be done. This 'optimization' is what comes from
839   sitting next to a bare disk and hearing it every time it seeks.  -- Gnu
840   Gilmore  */
841
842void
843extract_file (bfd *abfd)
844{
845  FILE *ostream;
846  char *cbuf = xmalloc (BUFSIZE);
847  int nread, tocopy;
848  long ncopied = 0;
849  long size;
850  struct stat buf;
851
852  if (bfd_stat_arch_elt (abfd, &buf) != 0)
853    /* xgettext:c-format */
854    fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
855  size = buf.st_size;
856
857  if (size < 0)
858    /* xgettext:c-format */
859    fatal (_("stat returns negative size for %s"), bfd_get_filename (abfd));
860
861  if (verbose)
862    printf ("x - %s\n", bfd_get_filename (abfd));
863
864  bfd_seek (abfd, (file_ptr) 0, SEEK_SET);
865
866  ostream = NULL;
867  if (size == 0)
868    {
869      /* Seems like an abstraction violation, eh?  Well it's OK! */
870      output_filename = bfd_get_filename (abfd);
871
872      ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
873      if (ostream == NULL)
874	{
875	  perror (bfd_get_filename (abfd));
876	  xexit (1);
877	}
878
879      output_file = ostream;
880    }
881  else
882    while (ncopied < size)
883      {
884	tocopy = size - ncopied;
885	if (tocopy > BUFSIZE)
886	  tocopy = BUFSIZE;
887
888	nread = bfd_bread (cbuf, (bfd_size_type) tocopy, abfd);
889	if (nread != tocopy)
890	  /* xgettext:c-format */
891	  fatal (_("%s is not a valid archive"),
892		 bfd_get_filename (bfd_my_archive (abfd)));
893
894	/* See comment above; this saves disk arm motion */
895	if (ostream == NULL)
896	  {
897	    /* Seems like an abstraction violation, eh?  Well it's OK! */
898	    output_filename = bfd_get_filename (abfd);
899
900	    ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
901	    if (ostream == NULL)
902	      {
903		perror (bfd_get_filename (abfd));
904		xexit (1);
905	      }
906
907	    output_file = ostream;
908	  }
909	fwrite (cbuf, 1, nread, ostream);
910	ncopied += tocopy;
911      }
912
913  if (ostream != NULL)
914    fclose (ostream);
915
916  output_file = NULL;
917  output_filename = NULL;
918
919  chmod (bfd_get_filename (abfd), buf.st_mode);
920
921  if (preserve_dates)
922    {
923      /* Set access time to modification time.  Only st_mtime is
924	 initialized by bfd_stat_arch_elt.  */
925      buf.st_atime = buf.st_mtime;
926      set_times (bfd_get_filename (abfd), &buf);
927    }
928
929  free (cbuf);
930}
931
932static void
933write_archive (bfd *iarch)
934{
935  bfd *obfd;
936  char *old_name, *new_name;
937  bfd *contents_head = iarch->next;
938
939  old_name = xmalloc (strlen (bfd_get_filename (iarch)) + 1);
940  strcpy (old_name, bfd_get_filename (iarch));
941  new_name = make_tempname (old_name);
942
943  output_filename = new_name;
944
945  obfd = bfd_openw (new_name, bfd_get_target (iarch));
946
947  if (obfd == NULL)
948    bfd_fatal (old_name);
949
950  output_bfd = obfd;
951
952  bfd_set_format (obfd, bfd_archive);
953
954  /* Request writing the archive symbol table unless we've
955     been explicitly requested not to.  */
956  obfd->has_armap = write_armap >= 0;
957
958  if (ar_truncate)
959    {
960      /* This should really use bfd_set_file_flags, but that rejects
961         archives.  */
962      obfd->flags |= BFD_TRADITIONAL_FORMAT;
963    }
964
965  if (!bfd_set_archive_head (obfd, contents_head))
966    bfd_fatal (old_name);
967
968  if (!bfd_close (obfd))
969    bfd_fatal (old_name);
970
971  output_bfd = NULL;
972  output_filename = NULL;
973
974  /* We don't care if this fails; we might be creating the archive.  */
975  bfd_close (iarch);
976
977  if (smart_rename (new_name, old_name, 0) != 0)
978    xexit (1);
979}
980
981/* Return a pointer to the pointer to the entry which should be rplacd'd
982   into when altering.  DEFAULT_POS should be how to interpret pos_default,
983   and should be a pos value.  */
984
985static bfd **
986get_pos_bfd (bfd **contents, enum pos default_pos, const char *default_posname)
987{
988  bfd **after_bfd = contents;
989  enum pos realpos;
990  const char *realposname;
991
992  if (postype == pos_default)
993    {
994      realpos = default_pos;
995      realposname = default_posname;
996    }
997  else
998    {
999      realpos = postype;
1000      realposname = posname;
1001    }
1002
1003  if (realpos == pos_end)
1004    {
1005      while (*after_bfd)
1006	after_bfd = &((*after_bfd)->next);
1007    }
1008  else
1009    {
1010      for (; *after_bfd; after_bfd = &(*after_bfd)->next)
1011	if (FILENAME_CMP ((*after_bfd)->filename, realposname) == 0)
1012	  {
1013	    if (realpos == pos_after)
1014	      after_bfd = &(*after_bfd)->next;
1015	    break;
1016	  }
1017    }
1018  return after_bfd;
1019}
1020
1021static void
1022delete_members (bfd *arch, char **files_to_delete)
1023{
1024  bfd **current_ptr_ptr;
1025  bfd_boolean found;
1026  bfd_boolean something_changed = FALSE;
1027  int match_count;
1028
1029  for (; *files_to_delete != NULL; ++files_to_delete)
1030    {
1031      /* In a.out systems, the armap is optional.  It's also called
1032	 __.SYMDEF.  So if the user asked to delete it, we should remember
1033	 that fact. This isn't quite right for COFF systems (where
1034	 __.SYMDEF might be regular member), but it's very unlikely
1035	 to be a problem.  FIXME */
1036
1037      if (!strcmp (*files_to_delete, "__.SYMDEF"))
1038	{
1039	  arch->has_armap = FALSE;
1040	  write_armap = -1;
1041	  continue;
1042	}
1043
1044      found = FALSE;
1045      match_count = 0;
1046      current_ptr_ptr = &(arch->next);
1047      while (*current_ptr_ptr)
1048	{
1049	  if (FILENAME_CMP (normalize (*files_to_delete, arch),
1050			    (*current_ptr_ptr)->filename) == 0)
1051	    {
1052	      ++match_count;
1053	      if (counted_name_mode
1054		  && match_count != counted_name_counter)
1055		{
1056		  /* Counting, and didn't match on count; go on to the
1057                     next one.  */
1058		}
1059	      else
1060		{
1061		  found = TRUE;
1062		  something_changed = TRUE;
1063		  if (verbose)
1064		    printf ("d - %s\n",
1065			    *files_to_delete);
1066		  *current_ptr_ptr = ((*current_ptr_ptr)->next);
1067		  goto next_file;
1068		}
1069	    }
1070
1071	  current_ptr_ptr = &((*current_ptr_ptr)->next);
1072	}
1073
1074      if (verbose && !found)
1075	{
1076	  /* xgettext:c-format */
1077	  printf (_("No member named `%s'\n"), *files_to_delete);
1078	}
1079    next_file:
1080      ;
1081    }
1082
1083  if (something_changed)
1084    write_archive (arch);
1085  else
1086    output_filename = NULL;
1087}
1088
1089
1090/* Reposition existing members within an archive */
1091
1092static void
1093move_members (bfd *arch, char **files_to_move)
1094{
1095  bfd **after_bfd;		/* New entries go after this one */
1096  bfd **current_ptr_ptr;	/* cdr pointer into contents */
1097
1098  for (; *files_to_move; ++files_to_move)
1099    {
1100      current_ptr_ptr = &(arch->next);
1101      while (*current_ptr_ptr)
1102	{
1103	  bfd *current_ptr = *current_ptr_ptr;
1104	  if (FILENAME_CMP (normalize (*files_to_move, arch),
1105			    current_ptr->filename) == 0)
1106	    {
1107	      /* Move this file to the end of the list - first cut from
1108		 where it is.  */
1109	      bfd *link;
1110	      *current_ptr_ptr = current_ptr->next;
1111
1112	      /* Now glue to end */
1113	      after_bfd = get_pos_bfd (&arch->next, pos_end, NULL);
1114	      link = *after_bfd;
1115	      *after_bfd = current_ptr;
1116	      current_ptr->next = link;
1117
1118	      if (verbose)
1119		printf ("m - %s\n", *files_to_move);
1120
1121	      goto next_file;
1122	    }
1123
1124	  current_ptr_ptr = &((*current_ptr_ptr)->next);
1125	}
1126      /* xgettext:c-format */
1127      fatal (_("no entry %s in archive %s!"), *files_to_move, arch->filename);
1128
1129    next_file:;
1130    }
1131
1132  write_archive (arch);
1133}
1134
1135/* Ought to default to replacing in place, but this is existing practice!  */
1136
1137static void
1138replace_members (bfd *arch, char **files_to_move, bfd_boolean quick)
1139{
1140  bfd_boolean changed = FALSE;
1141  bfd **after_bfd;		/* New entries go after this one.  */
1142  bfd *current;
1143  bfd **current_ptr;
1144
1145  while (files_to_move && *files_to_move)
1146    {
1147      if (! quick)
1148	{
1149	  current_ptr = &arch->next;
1150	  while (*current_ptr)
1151	    {
1152	      current = *current_ptr;
1153
1154	      /* For compatibility with existing ar programs, we
1155		 permit the same file to be added multiple times.  */
1156	      if (FILENAME_CMP (normalize (*files_to_move, arch),
1157				normalize (current->filename, arch)) == 0
1158		  && current->arelt_data != NULL)
1159		{
1160		  if (newer_only)
1161		    {
1162		      struct stat fsbuf, asbuf;
1163
1164		      if (stat (*files_to_move, &fsbuf) != 0)
1165			{
1166			  if (errno != ENOENT)
1167			    bfd_fatal (*files_to_move);
1168			  goto next_file;
1169			}
1170		      if (bfd_stat_arch_elt (current, &asbuf) != 0)
1171			/* xgettext:c-format */
1172			fatal (_("internal stat error on %s"),
1173			       current->filename);
1174
1175		      if (fsbuf.st_mtime <= asbuf.st_mtime)
1176			goto next_file;
1177		    }
1178
1179		  after_bfd = get_pos_bfd (&arch->next, pos_after,
1180					   current->filename);
1181		  if (ar_emul_replace (after_bfd, *files_to_move,
1182				       verbose))
1183		    {
1184		      /* Snip out this entry from the chain.  */
1185		      *current_ptr = (*current_ptr)->next;
1186		      changed = TRUE;
1187		    }
1188
1189		  goto next_file;
1190		}
1191	      current_ptr = &(current->next);
1192	    }
1193	}
1194
1195      /* Add to the end of the archive.  */
1196      after_bfd = get_pos_bfd (&arch->next, pos_end, NULL);
1197
1198      if (ar_emul_append (after_bfd, *files_to_move, verbose))
1199	changed = TRUE;
1200
1201    next_file:;
1202
1203      files_to_move++;
1204    }
1205
1206  if (changed)
1207    write_archive (arch);
1208  else
1209    output_filename = NULL;
1210}
1211
1212static void
1213ranlib_only (const char *archname)
1214{
1215  bfd *arch;
1216
1217  if (get_file_size (archname) < 1)
1218    return;
1219  write_armap = 1;
1220  arch = open_inarch (archname, (char *) NULL);
1221  if (arch == NULL)
1222    xexit (1);
1223  write_archive (arch);
1224}
1225
1226/* Update the timestamp of the symbol map of an archive.  */
1227
1228static void
1229ranlib_touch (const char *archname)
1230{
1231#ifdef __GO32__
1232  /* I don't think updating works on go32.  */
1233  ranlib_only (archname);
1234#else
1235  int f;
1236  bfd *arch;
1237  char **matching;
1238
1239  if (get_file_size (archname) < 1)
1240    return;
1241  f = open (archname, O_RDWR | O_BINARY, 0);
1242  if (f < 0)
1243    {
1244      bfd_set_error (bfd_error_system_call);
1245      bfd_fatal (archname);
1246    }
1247
1248  arch = bfd_fdopenr (archname, (const char *) NULL, f);
1249  if (arch == NULL)
1250    bfd_fatal (archname);
1251  if (! bfd_check_format_matches (arch, bfd_archive, &matching))
1252    {
1253      bfd_nonfatal (archname);
1254      if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
1255	{
1256	  list_matching_formats (matching);
1257	  free (matching);
1258	}
1259      xexit (1);
1260    }
1261
1262  if (! bfd_has_map (arch))
1263    /* xgettext:c-format */
1264    fatal (_("%s: no archive map to update"), archname);
1265
1266  bfd_update_armap_timestamp (arch);
1267
1268  if (! bfd_close (arch))
1269    bfd_fatal (archname);
1270#endif
1271}
1272
1273/* Things which are interesting to map over all or some of the files: */
1274
1275static void
1276print_descr (bfd *abfd)
1277{
1278  print_arelt_descr (stdout, abfd, verbose);
1279}
1280