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