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