* ar.c (mri_mode): Make static.
[external/binutils.git] / binutils / ar.c
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
21 \f
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 #define BUFSIZE 8192
53
54 /* Kludge declaration from BFD!  This is ugly!  FIXME!  XXX */
55
56 struct ar_hdr *
57   bfd_special_undocumented_glue (bfd * abfd, const char *filename);
58
59 /* Static declarations */
60
61 static void mri_emul (void);
62 static const char *normalize (const char *, bfd *);
63 static void remove_output (void);
64 static void map_over_members (bfd *, void (*)(bfd *), char **, int);
65 static void print_contents (bfd * member);
66 static void delete_members (bfd *, char **files_to_delete);
67
68 static void move_members (bfd *, char **files_to_move);
69 static void replace_members
70   (bfd *, char **files_to_replace, bfd_boolean quick);
71 static void print_descr (bfd * abfd);
72 static void write_archive (bfd *);
73 static void ranlib_only (const char *archname);
74 static void ranlib_touch (const char *archname);
75 static void usage (int);
76 \f
77 /** Globals and flags */
78
79 static int mri_mode;
80
81 /* This flag distinguishes between ar and ranlib:
82    1 means this is 'ranlib'; 0 means this is 'ar'.
83    -1 means if we should use argv[0] to decide.  */
84 extern int is_ranlib;
85
86 /* Nonzero means don't warn about creating the archive file if necessary.  */
87 int silent_create = 0;
88
89 /* Nonzero means describe each action performed.  */
90 int verbose = 0;
91
92 /* Nonzero means preserve dates of members when extracting them.  */
93 int preserve_dates = 0;
94
95 /* Nonzero means don't replace existing members whose dates are more recent
96    than the corresponding files.  */
97 int newer_only = 0;
98
99 /* Controls the writing of an archive symbol table (in BSD: a __.SYMDEF
100    member).  -1 means we've been explicitly asked to not write a symbol table;
101    +1 means we've been explicitly asked to write it;
102    0 is the default.
103    Traditionally, the default in BSD has been to not write the table.
104    However, for POSIX.2 compliance the default is now to write a symbol table
105    if any of the members are object files.  */
106 int write_armap = 0;
107
108 /* Nonzero means it's the name of an existing member; position new or moved
109    files with respect to this one.  */
110 char *posname = NULL;
111
112 /* Sez how to use `posname': pos_before means position before that member.
113    pos_after means position after that member. pos_end means always at end.
114    pos_default means default appropriately. For the latter two, `posname'
115    should also be zero.  */
116 enum pos
117   {
118     pos_default, pos_before, pos_after, pos_end
119   } postype = pos_default;
120
121 static bfd **
122 get_pos_bfd (bfd **, enum pos, const char *);
123
124 /* For extract/delete only.  If COUNTED_NAME_MODE is TRUE, we only
125    extract the COUNTED_NAME_COUNTER instance of that name.  */
126 static bfd_boolean counted_name_mode = 0;
127 static int counted_name_counter = 0;
128
129 /* Whether to truncate names of files stored in the archive.  */
130 static bfd_boolean ar_truncate = FALSE;
131
132 /* Whether to use a full file name match when searching an archive.
133    This is convenient for archives created by the Microsoft lib
134    program.  */
135 static bfd_boolean full_pathname = FALSE;
136
137 int interactive = 0;
138
139 static void
140 mri_emul (void)
141 {
142   interactive = isatty (fileno (stdin));
143   yyparse ();
144 }
145
146 /* If COUNT is 0, then FUNCTION is called once on each entry.  If nonzero,
147    COUNT is the length of the FILES chain; FUNCTION is called on each entry
148    whose name matches one in FILES.  */
149
150 static void
151 map_over_members (bfd *arch, void (*function)(bfd *), char **files, int count)
152 {
153   bfd *head;
154   int match_count;
155
156   if (count == 0)
157     {
158       for (head = arch->next; head; head = head->next)
159         {
160           PROGRESS (1);
161           function (head);
162         }
163       return;
164     }
165
166   /* This may appear to be a baroque way of accomplishing what we want.
167      However we have to iterate over the filenames in order to notice where
168      a filename is requested but does not exist in the archive.  Ditto
169      mapping over each file each time -- we want to hack multiple
170      references.  */
171
172   for (; count > 0; files++, count--)
173     {
174       bfd_boolean found = FALSE;
175
176       match_count = 0;
177       for (head = arch->next; head; head = head->next)
178         {
179           PROGRESS (1);
180           if (head->filename == NULL)
181             {
182               /* Some archive formats don't get the filenames filled in
183                  until the elements are opened.  */
184               struct stat buf;
185               bfd_stat_arch_elt (head, &buf);
186             }
187           if ((head->filename != NULL) &&
188               (!FILENAME_CMP (normalize (*files, arch), head->filename)))
189             {
190               ++match_count;
191               if (counted_name_mode
192                   && match_count != counted_name_counter)
193                 {
194                   /* Counting, and didn't match on count; go on to the
195                      next one.  */
196                   continue;
197                 }
198
199               found = TRUE;
200               function (head);
201             }
202         }
203       if (!found)
204         /* xgettext:c-format */
205         fprintf (stderr, _("no entry %s in archive\n"), *files);
206     }
207 }
208 \f
209 bfd_boolean operation_alters_arch = FALSE;
210
211 static void
212 usage (int help)
213 {
214   FILE *s;
215
216   s = help ? stdout : stderr;
217
218   if (! is_ranlib)
219     {
220       /* xgettext:c-format */
221       fprintf (s, _("Usage: %s [emulation options] [-]{dmpqrstx}[abcfilNoPsSuvV] [member-name] [count] archive-file file...\n"),
222                program_name);
223       /* xgettext:c-format */
224       fprintf (s, _("       %s -M [<mri-script]\n"), program_name);
225       fprintf (s, _(" commands:\n"));
226       fprintf (s, _("  d            - delete file(s) from the archive\n"));
227       fprintf (s, _("  m[ab]        - move file(s) in the archive\n"));
228       fprintf (s, _("  p            - print file(s) found in the archive\n"));
229       fprintf (s, _("  q[f]         - quick append file(s) to the archive\n"));
230       fprintf (s, _("  r[ab][f][u]  - replace existing or insert new file(s) into the archive\n"));
231       fprintf (s, _("  t            - display contents of archive\n"));
232       fprintf (s, _("  x[o]         - extract file(s) from the archive\n"));
233       fprintf (s, _(" command specific modifiers:\n"));
234       fprintf (s, _("  [a]          - put file(s) after [member-name]\n"));
235       fprintf (s, _("  [b]          - put file(s) before [member-name] (same as [i])\n"));
236       fprintf (s, _("  [N]          - use instance [count] of name\n"));
237       fprintf (s, _("  [f]          - truncate inserted file names\n"));
238       fprintf (s, _("  [P]          - use full path names when matching\n"));
239       fprintf (s, _("  [o]          - preserve original dates\n"));
240       fprintf (s, _("  [u]          - only replace files that are newer than current archive contents\n"));
241       fprintf (s, _(" generic modifiers:\n"));
242       fprintf (s, _("  [c]          - do not warn if the library had to be created\n"));
243       fprintf (s, _("  [s]          - create an archive index (cf. ranlib)\n"));
244       fprintf (s, _("  [S]          - do not build a symbol table\n"));
245       fprintf (s, _("  [v]          - be verbose\n"));
246       fprintf (s, _("  [V]          - display the version number\n"));
247
248       ar_emul_usage (s);
249     }
250   else
251     {
252       /* xgettext:c-format */
253       fprintf (s, _("Usage: %s [options] archive\n"), program_name);
254       fprintf (s, _(" Generate an index to speed access to archives\n"));
255       fprintf (s, _(" The options are:\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
271 static const char *
272 normalize (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
313 static const char *output_filename = NULL;
314 static FILE *output_file = NULL;
315 static bfd *output_bfd = NULL;
316
317 static void
318 remove_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
333 int main (int, char **);
334
335 int
336 main (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   if (is_ranlib < 0)
366     {
367       char *temp;
368
369       temp = strrchr (program_name, '/');
370 #ifdef HAVE_DOS_BASED_FILE_SYSTEM
371       {
372         /* We could have foo/bar\\baz, or foo\\bar, or d:bar.  */
373         char *bslash = strrchr (program_name, '\\');
374         if (temp == NULL || (bslash != NULL && bslash > temp))
375           temp = bslash;
376         if (temp == NULL && program_name[0] != '\0' && program_name[1] == ':')
377           temp = program_name + 1;
378       }
379 #endif
380       if (temp == NULL)
381         temp = program_name;
382       else
383         ++temp;
384       if (strlen (temp) >= 6
385           && FILENAME_CMP (temp + strlen (temp) - 6, "ranlib") == 0)
386         is_ranlib = 1;
387       else
388         is_ranlib = 0;
389     }
390
391   if (argc > 1 && argv[1][0] == '-')
392     {
393       if (strcmp (argv[1], "--help") == 0)
394         usage (1);
395       else if (strcmp (argv[1], "--version") == 0)
396         {
397           if (is_ranlib)
398             print_version ("ranlib");
399           else
400             print_version ("ar");
401         }
402     }
403
404   START_PROGRESS (program_name, 0);
405
406   bfd_init ();
407   set_default_bfd_target ();
408
409   show_version = 0;
410
411   xatexit (remove_output);
412
413   for (i = 1; i < argc; i++)
414     if (! ar_emul_parse_arg (argv[i]))
415       break;
416   argv += (i - 1);
417   argc -= (i - 1);
418
419   if (is_ranlib)
420     {
421       bfd_boolean touch = FALSE;
422
423       if (argc < 2
424           || strcmp (argv[1], "--help") == 0
425           || strcmp (argv[1], "-h") == 0
426           || strcmp (argv[1], "-H") == 0)
427         usage (0);
428       if (strcmp (argv[1], "-V") == 0
429           || strcmp (argv[1], "-v") == 0
430           || strncmp (argv[1], "--v", 3) == 0)
431         print_version ("ranlib");
432       arg_index = 1;
433       if (strcmp (argv[1], "-t") == 0)
434         {
435           ++arg_index;
436           touch = TRUE;
437         }
438       while (arg_index < argc)
439         {
440           if (! touch)
441             ranlib_only (argv[arg_index]);
442           else
443             ranlib_touch (argv[arg_index]);
444           ++arg_index;
445         }
446       xexit (0);
447     }
448
449   if (argc == 2 && strcmp (argv[1], "-M") == 0)
450     {
451       mri_emul ();
452       xexit (0);
453     }
454
455   if (argc < 2)
456     usage (0);
457
458   arg_index = 1;
459   arg_ptr = argv[arg_index];
460
461   if (*arg_ptr == '-')
462     {
463       /* When the first option starts with '-' we support POSIX-compatible
464          option parsing.  */
465       do_posix = 1;
466       ++arg_ptr;                        /* compatibility */
467     }
468
469   do
470     {
471       while ((c = *arg_ptr++) != '\0')
472         {
473           switch (c)
474             {
475             case 'd':
476             case 'm':
477             case 'p':
478             case 'q':
479             case 'r':
480             case 't':
481             case 'x':
482               if (operation != none)
483                 fatal (_("two different operation options specified"));
484               switch (c)
485                 {
486                 case 'd':
487                   operation = delete;
488                   operation_alters_arch = TRUE;
489                   break;
490                 case 'm':
491                   operation = move;
492                   operation_alters_arch = TRUE;
493                   break;
494                 case 'p':
495                   operation = print_files;
496                   break;
497                 case 'q':
498                   operation = quick_append;
499                   operation_alters_arch = TRUE;
500                   break;
501                 case 'r':
502                   operation = replace;
503                   operation_alters_arch = TRUE;
504                   break;
505                 case 't':
506                   operation = print_table;
507                   break;
508                 case 'x':
509                   operation = extract;
510                   break;
511                 }
512             case 'l':
513               break;
514             case 'c':
515               silent_create = 1;
516               break;
517             case 'o':
518               preserve_dates = 1;
519               break;
520             case 'V':
521               show_version = TRUE;
522               break;
523             case 's':
524               write_armap = 1;
525               break;
526             case 'S':
527               write_armap = -1;
528               break;
529             case 'u':
530               newer_only = 1;
531               break;
532             case 'v':
533               verbose = 1;
534               break;
535             case 'a':
536               postype = pos_after;
537               break;
538             case 'b':
539               postype = pos_before;
540               break;
541             case 'i':
542               postype = pos_before;
543               break;
544             case 'M':
545               mri_mode = 1;
546               break;
547             case 'N':
548               counted_name_mode = TRUE;
549               break;
550             case 'f':
551               ar_truncate = TRUE;
552               break;
553             case 'P':
554               full_pathname = TRUE;
555               break;
556             default:
557               /* xgettext:c-format */
558               non_fatal (_("illegal option -- %c"), c);
559               usage (0);
560             }
561         }
562
563       /* With POSIX-compatible option parsing continue with the next
564          argument if it starts with '-'.  */
565       if (do_posix && arg_index + 1 < argc && argv[arg_index + 1][0] == '-')
566         arg_ptr = argv[++arg_index] + 1;
567       else
568         do_posix = 0;
569     }
570   while (do_posix);
571
572   if (show_version)
573     print_version ("ar");
574
575   ++arg_index;
576   if (arg_index >= argc)
577     usage (0);
578
579   if (mri_mode)
580     {
581       mri_emul ();
582     }
583   else
584     {
585       bfd *arch;
586
587       /* We don't use do_quick_append any more.  Too many systems
588          expect ar to always rebuild the symbol table even when q is
589          used.  */
590
591       /* We can't write an armap when using ar q, so just do ar r
592          instead.  */
593       if (operation == quick_append && write_armap)
594         operation = replace;
595
596       if ((operation == none || operation == print_table)
597           && write_armap == 1)
598         {
599           ranlib_only (argv[arg_index]);
600           xexit (0);
601         }
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
678 bfd *
679 open_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
777 static void
778 print_contents (bfd *abfd)
779 {
780   int ncopied = 0;
781   char *cbuf = xmalloc (BUFSIZE);
782   struct stat buf;
783   long 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       int nread;
799       int 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       fwrite (cbuf, 1, nread, stdout);
809       ncopied += tocopy;
810     }
811   free (cbuf);
812 }
813
814 /* Extract a member of the archive into its own file.
815
816    We defer opening the new file until after we have read a BUFSIZ chunk of the
817    old one, since we know we have just read the archive header for the old
818    one.  Since most members are shorter than BUFSIZ, this means we will read
819    the old header, read the old data, write a new inode for the new file, and
820    write the new data, and be done. This 'optimization' is what comes from
821    sitting next to a bare disk and hearing it every time it seeks.  -- Gnu
822    Gilmore  */
823
824 void
825 extract_file (bfd *abfd)
826 {
827   FILE *ostream;
828   char *cbuf = xmalloc (BUFSIZE);
829   int nread, tocopy;
830   long ncopied = 0;
831   long size;
832   struct stat buf;
833
834   if (bfd_stat_arch_elt (abfd, &buf) != 0)
835     /* xgettext:c-format */
836     fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
837   size = buf.st_size;
838
839   if (size < 0)
840     /* xgettext:c-format */
841     fatal (_("stat returns negative size for %s"), bfd_get_filename (abfd));
842
843   if (verbose)
844     printf ("x - %s\n", bfd_get_filename (abfd));
845
846   bfd_seek (abfd, (file_ptr) 0, SEEK_SET);
847
848   ostream = NULL;
849   if (size == 0)
850     {
851       /* Seems like an abstraction violation, eh?  Well it's OK! */
852       output_filename = bfd_get_filename (abfd);
853
854       ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
855       if (ostream == NULL)
856         {
857           perror (bfd_get_filename (abfd));
858           xexit (1);
859         }
860
861       output_file = ostream;
862     }
863   else
864     while (ncopied < size)
865       {
866         tocopy = size - ncopied;
867         if (tocopy > BUFSIZE)
868           tocopy = BUFSIZE;
869
870         nread = bfd_bread (cbuf, (bfd_size_type) tocopy, abfd);
871         if (nread != tocopy)
872           /* xgettext:c-format */
873           fatal (_("%s is not a valid archive"),
874                  bfd_get_filename (bfd_my_archive (abfd)));
875
876         /* See comment above; this saves disk arm motion */
877         if (ostream == NULL)
878           {
879             /* Seems like an abstraction violation, eh?  Well it's OK! */
880             output_filename = bfd_get_filename (abfd);
881
882             ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
883             if (ostream == NULL)
884               {
885                 perror (bfd_get_filename (abfd));
886                 xexit (1);
887               }
888
889             output_file = ostream;
890           }
891         fwrite (cbuf, 1, nread, ostream);
892         ncopied += tocopy;
893       }
894
895   if (ostream != NULL)
896     fclose (ostream);
897
898   output_file = NULL;
899   output_filename = NULL;
900
901   chmod (bfd_get_filename (abfd), buf.st_mode);
902
903   if (preserve_dates)
904     {
905       /* Set access time to modification time.  Only st_mtime is
906          initialized by bfd_stat_arch_elt.  */
907       buf.st_atime = buf.st_mtime;
908       set_times (bfd_get_filename (abfd), &buf);
909     }
910
911   free (cbuf);
912 }
913
914 static void
915 write_archive (bfd *iarch)
916 {
917   bfd *obfd;
918   char *old_name, *new_name;
919   bfd *contents_head = iarch->next;
920
921   old_name = xmalloc (strlen (bfd_get_filename (iarch)) + 1);
922   strcpy (old_name, bfd_get_filename (iarch));
923   new_name = make_tempname (old_name);
924
925   output_filename = new_name;
926
927   obfd = bfd_openw (new_name, bfd_get_target (iarch));
928
929   if (obfd == NULL)
930     bfd_fatal (old_name);
931
932   output_bfd = obfd;
933
934   bfd_set_format (obfd, bfd_archive);
935
936   /* Request writing the archive symbol table unless we've
937      been explicitly requested not to.  */
938   obfd->has_armap = write_armap >= 0;
939
940   if (ar_truncate)
941     {
942       /* This should really use bfd_set_file_flags, but that rejects
943          archives.  */
944       obfd->flags |= BFD_TRADITIONAL_FORMAT;
945     }
946
947   if (!bfd_set_archive_head (obfd, contents_head))
948     bfd_fatal (old_name);
949
950   if (!bfd_close (obfd))
951     bfd_fatal (old_name);
952
953   output_bfd = NULL;
954   output_filename = NULL;
955
956   /* We don't care if this fails; we might be creating the archive.  */
957   bfd_close (iarch);
958
959   if (smart_rename (new_name, old_name, 0) != 0)
960     xexit (1);
961 }
962
963 /* Return a pointer to the pointer to the entry which should be rplacd'd
964    into when altering.  DEFAULT_POS should be how to interpret pos_default,
965    and should be a pos value.  */
966
967 static bfd **
968 get_pos_bfd (bfd **contents, enum pos default_pos, const char *default_posname)
969 {
970   bfd **after_bfd = contents;
971   enum pos realpos;
972   const char *realposname;
973
974   if (postype == pos_default)
975     {
976       realpos = default_pos;
977       realposname = default_posname;
978     }
979   else
980     {
981       realpos = postype;
982       realposname = posname;
983     }
984
985   if (realpos == pos_end)
986     {
987       while (*after_bfd)
988         after_bfd = &((*after_bfd)->next);
989     }
990   else
991     {
992       for (; *after_bfd; after_bfd = &(*after_bfd)->next)
993         if (FILENAME_CMP ((*after_bfd)->filename, realposname) == 0)
994           {
995             if (realpos == pos_after)
996               after_bfd = &(*after_bfd)->next;
997             break;
998           }
999     }
1000   return after_bfd;
1001 }
1002
1003 static void
1004 delete_members (bfd *arch, char **files_to_delete)
1005 {
1006   bfd **current_ptr_ptr;
1007   bfd_boolean found;
1008   bfd_boolean something_changed = FALSE;
1009   int match_count;
1010
1011   for (; *files_to_delete != NULL; ++files_to_delete)
1012     {
1013       /* In a.out systems, the armap is optional.  It's also called
1014          __.SYMDEF.  So if the user asked to delete it, we should remember
1015          that fact. This isn't quite right for COFF systems (where
1016          __.SYMDEF might be regular member), but it's very unlikely
1017          to be a problem.  FIXME */
1018
1019       if (!strcmp (*files_to_delete, "__.SYMDEF"))
1020         {
1021           arch->has_armap = FALSE;
1022           write_armap = -1;
1023           continue;
1024         }
1025
1026       found = FALSE;
1027       match_count = 0;
1028       current_ptr_ptr = &(arch->next);
1029       while (*current_ptr_ptr)
1030         {
1031           if (FILENAME_CMP (normalize (*files_to_delete, arch),
1032                             (*current_ptr_ptr)->filename) == 0)
1033             {
1034               ++match_count;
1035               if (counted_name_mode
1036                   && match_count != counted_name_counter)
1037                 {
1038                   /* Counting, and didn't match on count; go on to the
1039                      next one.  */
1040                 }
1041               else
1042                 {
1043                   found = TRUE;
1044                   something_changed = TRUE;
1045                   if (verbose)
1046                     printf ("d - %s\n",
1047                             *files_to_delete);
1048                   *current_ptr_ptr = ((*current_ptr_ptr)->next);
1049                   goto next_file;
1050                 }
1051             }
1052
1053           current_ptr_ptr = &((*current_ptr_ptr)->next);
1054         }
1055
1056       if (verbose && !found)
1057         {
1058           /* xgettext:c-format */
1059           printf (_("No member named `%s'\n"), *files_to_delete);
1060         }
1061     next_file:
1062       ;
1063     }
1064
1065   if (something_changed)
1066     write_archive (arch);
1067   else
1068     output_filename = NULL;
1069 }
1070
1071
1072 /* Reposition existing members within an archive */
1073
1074 static void
1075 move_members (bfd *arch, char **files_to_move)
1076 {
1077   bfd **after_bfd;              /* New entries go after this one */
1078   bfd **current_ptr_ptr;        /* cdr pointer into contents */
1079
1080   for (; *files_to_move; ++files_to_move)
1081     {
1082       current_ptr_ptr = &(arch->next);
1083       while (*current_ptr_ptr)
1084         {
1085           bfd *current_ptr = *current_ptr_ptr;
1086           if (FILENAME_CMP (normalize (*files_to_move, arch),
1087                             current_ptr->filename) == 0)
1088             {
1089               /* Move this file to the end of the list - first cut from
1090                  where it is.  */
1091               bfd *link;
1092               *current_ptr_ptr = current_ptr->next;
1093
1094               /* Now glue to end */
1095               after_bfd = get_pos_bfd (&arch->next, pos_end, NULL);
1096               link = *after_bfd;
1097               *after_bfd = current_ptr;
1098               current_ptr->next = link;
1099
1100               if (verbose)
1101                 printf ("m - %s\n", *files_to_move);
1102
1103               goto next_file;
1104             }
1105
1106           current_ptr_ptr = &((*current_ptr_ptr)->next);
1107         }
1108       /* xgettext:c-format */
1109       fatal (_("no entry %s in archive %s!"), *files_to_move, arch->filename);
1110
1111     next_file:;
1112     }
1113
1114   write_archive (arch);
1115 }
1116
1117 /* Ought to default to replacing in place, but this is existing practice!  */
1118
1119 static void
1120 replace_members (bfd *arch, char **files_to_move, bfd_boolean quick)
1121 {
1122   bfd_boolean changed = FALSE;
1123   bfd **after_bfd;              /* New entries go after this one.  */
1124   bfd *current;
1125   bfd **current_ptr;
1126
1127   while (files_to_move && *files_to_move)
1128     {
1129       if (! quick)
1130         {
1131           current_ptr = &arch->next;
1132           while (*current_ptr)
1133             {
1134               current = *current_ptr;
1135
1136               /* For compatibility with existing ar programs, we
1137                  permit the same file to be added multiple times.  */
1138               if (FILENAME_CMP (normalize (*files_to_move, arch),
1139                                 normalize (current->filename, arch)) == 0
1140                   && current->arelt_data != NULL)
1141                 {
1142                   if (newer_only)
1143                     {
1144                       struct stat fsbuf, asbuf;
1145
1146                       if (stat (*files_to_move, &fsbuf) != 0)
1147                         {
1148                           if (errno != ENOENT)
1149                             bfd_fatal (*files_to_move);
1150                           goto next_file;
1151                         }
1152                       if (bfd_stat_arch_elt (current, &asbuf) != 0)
1153                         /* xgettext:c-format */
1154                         fatal (_("internal stat error on %s"),
1155                                current->filename);
1156
1157                       if (fsbuf.st_mtime <= asbuf.st_mtime)
1158                         goto next_file;
1159                     }
1160
1161                   after_bfd = get_pos_bfd (&arch->next, pos_after,
1162                                            current->filename);
1163                   if (ar_emul_replace (after_bfd, *files_to_move,
1164                                        verbose))
1165                     {
1166                       /* Snip out this entry from the chain.  */
1167                       *current_ptr = (*current_ptr)->next;
1168                       changed = TRUE;
1169                     }
1170
1171                   goto next_file;
1172                 }
1173               current_ptr = &(current->next);
1174             }
1175         }
1176
1177       /* Add to the end of the archive.  */
1178       after_bfd = get_pos_bfd (&arch->next, pos_end, NULL);
1179
1180       if (ar_emul_append (after_bfd, *files_to_move, verbose))
1181         changed = TRUE;
1182
1183     next_file:;
1184
1185       files_to_move++;
1186     }
1187
1188   if (changed)
1189     write_archive (arch);
1190   else
1191     output_filename = NULL;
1192 }
1193
1194 static void
1195 ranlib_only (const char *archname)
1196 {
1197   bfd *arch;
1198
1199   if (get_file_size (archname) < 1)
1200     return;
1201   write_armap = 1;
1202   arch = open_inarch (archname, (char *) NULL);
1203   if (arch == NULL)
1204     xexit (1);
1205   write_archive (arch);
1206 }
1207
1208 /* Update the timestamp of the symbol map of an archive.  */
1209
1210 static void
1211 ranlib_touch (const char *archname)
1212 {
1213 #ifdef __GO32__
1214   /* I don't think updating works on go32.  */
1215   ranlib_only (archname);
1216 #else
1217   int f;
1218   bfd *arch;
1219   char **matching;
1220
1221   if (get_file_size (archname) < 1)
1222     return;
1223   f = open (archname, O_RDWR | O_BINARY, 0);
1224   if (f < 0)
1225     {
1226       bfd_set_error (bfd_error_system_call);
1227       bfd_fatal (archname);
1228     }
1229
1230   arch = bfd_fdopenr (archname, (const char *) NULL, f);
1231   if (arch == NULL)
1232     bfd_fatal (archname);
1233   if (! bfd_check_format_matches (arch, bfd_archive, &matching))
1234     {
1235       bfd_nonfatal (archname);
1236       if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
1237         {
1238           list_matching_formats (matching);
1239           free (matching);
1240         }
1241       xexit (1);
1242     }
1243
1244   if (! bfd_has_map (arch))
1245     /* xgettext:c-format */
1246     fatal (_("%s: no archive map to update"), archname);
1247
1248   bfd_update_armap_timestamp (arch);
1249
1250   if (! bfd_close (arch))
1251     bfd_fatal (archname);
1252 #endif
1253 }
1254
1255 /* Things which are interesting to map over all or some of the files: */
1256
1257 static void
1258 print_descr (bfd *abfd)
1259 {
1260   print_arelt_descr (stdout, abfd, verbose);
1261 }