1 /* ar.c - Archive modify and extract.
2    Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
3    2001, 2002, 2003, 2004, 2005
4    Free Software Foundation, Inc.
5 
6    This file is part of GNU Binutils.
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
21 
22 /*
23    Bugs: should use getopt the way tar does (complete w/optional -) and
24    should have long options too. GNU ar used to check file against filesystem
25    in quick_update and replace operations (would check mtime). Doesn't warn
26    when name truncated. No way to specify pos_end. Error messages should be
27    more consistent.  */
28 
29 #include "bfd.h"
30 #include "libiberty.h"
31 #include "progress.h"
32 #include "bucomm.h"
33 #include "aout/ar.h"
34 #include "libbfd.h"
35 #include "arsup.h"
36 #include "filenames.h"
37 #include "binemul.h"
38 #include <sys/stat.h>
39 
40 #ifdef __GO32___
41 #define EXT_NAME_LEN 3		/* bufflen of addition to name if it's MS-DOS */
42 #else
43 #define EXT_NAME_LEN 6		/* ditto for *NIX */
44 #endif
45 
46 /* We need to open files in binary modes on system where that makes a
47    difference.  */
48 #ifndef O_BINARY
49 #define O_BINARY 0
50 #endif
51 
52 /* 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 
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
mri_emul(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
map_over_members(bfd * arch,void (* function)(bfd *),char ** files,int count)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 
207 bfd_boolean operation_alters_arch = FALSE;
208 
209 static void
usage(int help)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       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 
271 static const char *
normalize(const char * file,bfd * abfd)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
remove_output(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
main(int argc,char ** argv)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   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       bfd_boolean touch = FALSE;
424 
425       if (argc < 2
426 	  || strcmp (argv[1], "--help") == 0
427 	  || strcmp (argv[1], "-h") == 0
428 	  || strcmp (argv[1], "-H") == 0)
429 	usage (0);
430       if (strcmp (argv[1], "-V") == 0
431 	  || strcmp (argv[1], "-v") == 0
432 	  || strncmp (argv[1], "--v", 3) == 0)
433 	print_version ("ranlib");
434       arg_index = 1;
435       if (strcmp (argv[1], "-t") == 0)
436 	{
437 	  ++arg_index;
438 	  touch = TRUE;
439 	}
440       while (arg_index < argc)
441 	{
442 	  if (! touch)
443 	    ranlib_only (argv[arg_index]);
444 	  else
445 	    ranlib_touch (argv[arg_index]);
446 	  ++arg_index;
447 	}
448       xexit (0);
449     }
450 
451   if (argc == 2 && strcmp (argv[1], "-M") == 0)
452     {
453       mri_emul ();
454       xexit (0);
455     }
456 
457   if (argc < 2)
458     usage (0);
459 
460   arg_index = 1;
461   arg_ptr = argv[arg_index];
462 
463   if (*arg_ptr == '-')
464     {
465       /* When the first option starts with '-' we support POSIX-compatible
466 	 option parsing.  */
467       do_posix = 1;
468       ++arg_ptr;			/* compatibility */
469     }
470 
471   do
472     {
473       while ((c = *arg_ptr++) != '\0')
474 	{
475 	  switch (c)
476 	    {
477 	    case 'd':
478 	    case 'm':
479 	    case 'p':
480 	    case 'q':
481 	    case 'r':
482 	    case 't':
483 	    case 'x':
484 	      if (operation != none)
485 		fatal (_("two different operation options specified"));
486 	      switch (c)
487 		{
488 		case 'd':
489 		  operation = delete;
490 		  operation_alters_arch = TRUE;
491 		  break;
492 		case 'm':
493 		  operation = move;
494 		  operation_alters_arch = TRUE;
495 		  break;
496 		case 'p':
497 		  operation = print_files;
498 		  break;
499 		case 'q':
500 		  operation = quick_append;
501 		  operation_alters_arch = TRUE;
502 		  break;
503 		case 'r':
504 		  operation = replace;
505 		  operation_alters_arch = TRUE;
506 		  break;
507 		case 't':
508 		  operation = print_table;
509 		  break;
510 		case 'x':
511 		  operation = extract;
512 		  break;
513 		}
514 	    case 'l':
515 	      break;
516 	    case 'c':
517 	      silent_create = 1;
518 	      break;
519 	    case 'o':
520 	      preserve_dates = 1;
521 	      break;
522 	    case 'V':
523 	      show_version = TRUE;
524 	      break;
525 	    case 's':
526 	      write_armap = 1;
527 	      break;
528 	    case 'S':
529 	      write_armap = -1;
530 	      break;
531 	    case 'u':
532 	      newer_only = 1;
533 	      break;
534 	    case 'v':
535 	      verbose = 1;
536 	      break;
537 	    case 'a':
538 	      postype = pos_after;
539 	      break;
540 	    case 'b':
541 	      postype = pos_before;
542 	      break;
543 	    case 'i':
544 	      postype = pos_before;
545 	      break;
546 	    case 'M':
547 	      mri_mode = 1;
548 	      break;
549 	    case 'N':
550 	      counted_name_mode = TRUE;
551 	      break;
552 	    case 'f':
553 	      ar_truncate = TRUE;
554 	      break;
555 	    case 'P':
556 	      full_pathname = TRUE;
557 	      break;
558 	    default:
559 	      /* xgettext:c-format */
560 	      non_fatal (_("illegal option -- %c"), c);
561 	      usage (0);
562 	    }
563 	}
564 
565       /* With POSIX-compatible option parsing continue with the next
566 	 argument if it starts with '-'.  */
567       if (do_posix && arg_index + 1 < argc && argv[arg_index + 1][0] == '-')
568 	arg_ptr = argv[++arg_index] + 1;
569       else
570 	do_posix = 0;
571     }
572   while (do_posix);
573 
574   if (show_version)
575     print_version ("ar");
576 
577   ++arg_index;
578   if (arg_index >= argc)
579     usage (0);
580 
581   if (mri_mode)
582     {
583       mri_emul ();
584     }
585   else
586     {
587       bfd *arch;
588 
589       /* We don't use do_quick_append any more.  Too many systems
590 	 expect ar to always rebuild the symbol table even when q is
591 	 used.  */
592 
593       /* We can't write an armap when using ar q, so just do ar r
594          instead.  */
595       if (operation == quick_append && write_armap)
596 	operation = replace;
597 
598       if ((operation == none || operation == print_table)
599 	  && write_armap == 1)
600 	{
601 	  ranlib_only (argv[arg_index]);
602 	  xexit (0);
603 	}
604 
605       if (operation == none)
606 	fatal (_("no operation specified"));
607 
608       if (newer_only && operation != replace)
609 	fatal (_("`u' is only meaningful with the `r' option."));
610 
611       if (postype != pos_default)
612 	posname = argv[arg_index++];
613 
614       if (counted_name_mode)
615 	{
616 	  if (operation != extract && operation != delete)
617 	     fatal (_("`N' is only meaningful with the `x' and `d' options."));
618 	  counted_name_counter = atoi (argv[arg_index++]);
619 	  if (counted_name_counter <= 0)
620 	    fatal (_("Value for `N' must be positive."));
621 	}
622 
623       inarch_filename = argv[arg_index++];
624 
625       files = arg_index < argc ? argv + arg_index : NULL;
626       file_count = argc - arg_index;
627 
628       arch = open_inarch (inarch_filename,
629 			  files == NULL ? (char *) NULL : files[0]);
630 
631       switch (operation)
632 	{
633 	case print_table:
634 	  map_over_members (arch, print_descr, files, file_count);
635 	  break;
636 
637 	case print_files:
638 	  map_over_members (arch, print_contents, files, file_count);
639 	  break;
640 
641 	case extract:
642 	  map_over_members (arch, extract_file, files, file_count);
643 	  break;
644 
645 	case delete:
646 	  if (files != NULL)
647 	    delete_members (arch, files);
648 	  else
649 	    output_filename = NULL;
650 	  break;
651 
652 	case move:
653 	  if (files != NULL)
654 	    move_members (arch, files);
655 	  else
656 	    output_filename = NULL;
657 	  break;
658 
659 	case replace:
660 	case quick_append:
661 	  if (files != NULL || write_armap > 0)
662 	    replace_members (arch, files, operation == quick_append);
663 	  else
664 	    output_filename = NULL;
665 	  break;
666 
667 	  /* Shouldn't happen! */
668 	default:
669 	  /* xgettext:c-format */
670 	  fatal (_("internal error -- this option not implemented"));
671 	}
672     }
673 
674   END_PROGRESS (program_name);
675 
676   xexit (0);
677   return 0;
678 }
679 
680 bfd *
open_inarch(const char * archive_filename,const char * file)681 open_inarch (const char *archive_filename, const char *file)
682 {
683   const char *target;
684   bfd **last_one;
685   bfd *next_one;
686   struct stat sbuf;
687   bfd *arch;
688   char **matching;
689 
690   bfd_set_error (bfd_error_no_error);
691 
692   target = NULL;
693 
694   if (stat (archive_filename, &sbuf) != 0)
695     {
696 #if !defined(__GO32__) || defined(__DJGPP__)
697 
698       /* FIXME: I don't understand why this fragment was ifndef'ed
699 	 away for __GO32__; perhaps it was in the days of DJGPP v1.x.
700 	 stat() works just fine in v2.x, so I think this should be
701 	 removed.  For now, I enable it for DJGPP v2. -- EZ.  */
702 
703 /* KLUDGE ALERT! Temporary fix until I figger why
704    stat() is wrong ... think it's buried in GO32's IDT - Jax */
705       if (errno != ENOENT)
706 	bfd_fatal (archive_filename);
707 #endif
708 
709       if (!operation_alters_arch)
710 	{
711 	  fprintf (stderr, "%s: ", program_name);
712 	  perror (archive_filename);
713 	  maybequit ();
714 	  return NULL;
715 	}
716 
717       /* Try to figure out the target to use for the archive from the
718          first object on the list.  */
719       if (file != NULL)
720 	{
721 	  bfd *obj;
722 
723 	  obj = bfd_openr (file, NULL);
724 	  if (obj != NULL)
725 	    {
726 	      if (bfd_check_format (obj, bfd_object))
727 		target = bfd_get_target (obj);
728 	      (void) bfd_close (obj);
729 	    }
730 	}
731 
732       /* Create an empty archive.  */
733       arch = bfd_openw (archive_filename, target);
734       if (arch == NULL
735 	  || ! bfd_set_format (arch, bfd_archive)
736 	  || ! bfd_close (arch))
737 	bfd_fatal (archive_filename);
738       else if (!silent_create)
739         non_fatal (_("creating %s"), archive_filename);
740 
741       /* If we die creating a new archive, don't leave it around.  */
742       output_filename = archive_filename;
743     }
744 
745   arch = bfd_openr (archive_filename, target);
746   if (arch == NULL)
747     {
748     bloser:
749       bfd_fatal (archive_filename);
750     }
751 
752   if (! bfd_check_format_matches (arch, bfd_archive, &matching))
753     {
754       bfd_nonfatal (archive_filename);
755       if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
756 	{
757 	  list_matching_formats (matching);
758 	  free (matching);
759 	}
760       xexit (1);
761     }
762 
763   last_one = &(arch->next);
764   /* Read all the contents right away, regardless.  */
765   for (next_one = bfd_openr_next_archived_file (arch, NULL);
766        next_one;
767        next_one = bfd_openr_next_archived_file (arch, next_one))
768     {
769       PROGRESS (1);
770       *last_one = next_one;
771       last_one = &next_one->next;
772     }
773   *last_one = (bfd *) NULL;
774   if (bfd_get_error () != bfd_error_no_more_archived_files)
775     goto bloser;
776   return arch;
777 }
778 
779 static void
print_contents(bfd * abfd)780 print_contents (bfd *abfd)
781 {
782   int ncopied = 0;
783   char *cbuf = xmalloc (BUFSIZE);
784   struct stat buf;
785   long size;
786   if (bfd_stat_arch_elt (abfd, &buf) != 0)
787     /* xgettext:c-format */
788     fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
789 
790   if (verbose)
791     /* xgettext:c-format */
792     printf (_("\n<%s>\n\n"), bfd_get_filename (abfd));
793 
794   bfd_seek (abfd, (file_ptr) 0, SEEK_SET);
795 
796   size = buf.st_size;
797   while (ncopied < size)
798     {
799 
800       int nread;
801       int tocopy = size - ncopied;
802       if (tocopy > BUFSIZE)
803 	tocopy = BUFSIZE;
804 
805       nread = bfd_bread (cbuf, (bfd_size_type) tocopy, abfd);
806       if (nread != tocopy)
807 	/* xgettext:c-format */
808 	fatal (_("%s is not a valid archive"),
809 	       bfd_get_filename (bfd_my_archive (abfd)));
810       fwrite (cbuf, 1, nread, stdout);
811       ncopied += tocopy;
812     }
813   free (cbuf);
814 }
815 
816 /* Extract a member of the archive into its own file.
817 
818    We defer opening the new file until after we have read a BUFSIZ chunk of the
819    old one, since we know we have just read the archive header for the old
820    one.  Since most members are shorter than BUFSIZ, this means we will read
821    the old header, read the old data, write a new inode for the new file, and
822    write the new data, and be done. This 'optimization' is what comes from
823    sitting next to a bare disk and hearing it every time it seeks.  -- Gnu
824    Gilmore  */
825 
826 void
extract_file(bfd * abfd)827 extract_file (bfd *abfd)
828 {
829   FILE *ostream;
830   char *cbuf = xmalloc (BUFSIZE);
831   int nread, tocopy;
832   long ncopied = 0;
833   long size;
834   struct stat buf;
835 
836   if (bfd_stat_arch_elt (abfd, &buf) != 0)
837     /* xgettext:c-format */
838     fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
839   size = buf.st_size;
840 
841   if (size < 0)
842     /* xgettext:c-format */
843     fatal (_("stat returns negative size for %s"), bfd_get_filename (abfd));
844 
845   if (verbose)
846     printf ("x - %s\n", bfd_get_filename (abfd));
847 
848   bfd_seek (abfd, (file_ptr) 0, SEEK_SET);
849 
850   ostream = NULL;
851   if (size == 0)
852     {
853       /* Seems like an abstraction violation, eh?  Well it's OK! */
854       output_filename = bfd_get_filename (abfd);
855 
856       ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
857       if (ostream == NULL)
858 	{
859 	  perror (bfd_get_filename (abfd));
860 	  xexit (1);
861 	}
862 
863       output_file = ostream;
864     }
865   else
866     while (ncopied < size)
867       {
868 	tocopy = size - ncopied;
869 	if (tocopy > BUFSIZE)
870 	  tocopy = BUFSIZE;
871 
872 	nread = bfd_bread (cbuf, (bfd_size_type) tocopy, abfd);
873 	if (nread != tocopy)
874 	  /* xgettext:c-format */
875 	  fatal (_("%s is not a valid archive"),
876 		 bfd_get_filename (bfd_my_archive (abfd)));
877 
878 	/* See comment above; this saves disk arm motion */
879 	if (ostream == NULL)
880 	  {
881 	    /* Seems like an abstraction violation, eh?  Well it's OK! */
882 	    output_filename = bfd_get_filename (abfd);
883 
884 	    ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
885 	    if (ostream == NULL)
886 	      {
887 		perror (bfd_get_filename (abfd));
888 		xexit (1);
889 	      }
890 
891 	    output_file = ostream;
892 	  }
893 	fwrite (cbuf, 1, nread, ostream);
894 	ncopied += tocopy;
895       }
896 
897   if (ostream != NULL)
898     fclose (ostream);
899 
900   output_file = NULL;
901   output_filename = NULL;
902 
903   chmod (bfd_get_filename (abfd), buf.st_mode);
904 
905   if (preserve_dates)
906     {
907       /* Set access time to modification time.  Only st_mtime is
908 	 initialized by bfd_stat_arch_elt.  */
909       buf.st_atime = buf.st_mtime;
910       set_times (bfd_get_filename (abfd), &buf);
911     }
912 
913   free (cbuf);
914 }
915 
916 static void
write_archive(bfd * iarch)917 write_archive (bfd *iarch)
918 {
919   bfd *obfd;
920   char *old_name, *new_name;
921   bfd *contents_head = iarch->next;
922 
923   old_name = xmalloc (strlen (bfd_get_filename (iarch)) + 1);
924   strcpy (old_name, bfd_get_filename (iarch));
925   new_name = make_tempname (old_name);
926 
927   output_filename = new_name;
928 
929   obfd = bfd_openw (new_name, bfd_get_target (iarch));
930 
931   if (obfd == NULL)
932     bfd_fatal (old_name);
933 
934   output_bfd = obfd;
935 
936   bfd_set_format (obfd, bfd_archive);
937 
938   /* Request writing the archive symbol table unless we've
939      been explicitly requested not to.  */
940   obfd->has_armap = write_armap >= 0;
941 
942   if (ar_truncate)
943     {
944       /* This should really use bfd_set_file_flags, but that rejects
945          archives.  */
946       obfd->flags |= BFD_TRADITIONAL_FORMAT;
947     }
948 
949   if (!bfd_set_archive_head (obfd, contents_head))
950     bfd_fatal (old_name);
951 
952   if (!bfd_close (obfd))
953     bfd_fatal (old_name);
954 
955   output_bfd = NULL;
956   output_filename = NULL;
957 
958   /* We don't care if this fails; we might be creating the archive.  */
959   bfd_close (iarch);
960 
961   if (smart_rename (new_name, old_name, 0) != 0)
962     xexit (1);
963 }
964 
965 /* Return a pointer to the pointer to the entry which should be rplacd'd
966    into when altering.  DEFAULT_POS should be how to interpret pos_default,
967    and should be a pos value.  */
968 
969 static bfd **
get_pos_bfd(bfd ** contents,enum pos default_pos,const char * default_posname)970 get_pos_bfd (bfd **contents, enum pos default_pos, const char *default_posname)
971 {
972   bfd **after_bfd = contents;
973   enum pos realpos;
974   const char *realposname;
975 
976   if (postype == pos_default)
977     {
978       realpos = default_pos;
979       realposname = default_posname;
980     }
981   else
982     {
983       realpos = postype;
984       realposname = posname;
985     }
986 
987   if (realpos == pos_end)
988     {
989       while (*after_bfd)
990 	after_bfd = &((*after_bfd)->next);
991     }
992   else
993     {
994       for (; *after_bfd; after_bfd = &(*after_bfd)->next)
995 	if (FILENAME_CMP ((*after_bfd)->filename, realposname) == 0)
996 	  {
997 	    if (realpos == pos_after)
998 	      after_bfd = &(*after_bfd)->next;
999 	    break;
1000 	  }
1001     }
1002   return after_bfd;
1003 }
1004 
1005 static void
delete_members(bfd * arch,char ** files_to_delete)1006 delete_members (bfd *arch, char **files_to_delete)
1007 {
1008   bfd **current_ptr_ptr;
1009   bfd_boolean found;
1010   bfd_boolean something_changed = FALSE;
1011   int match_count;
1012 
1013   for (; *files_to_delete != NULL; ++files_to_delete)
1014     {
1015       /* In a.out systems, the armap is optional.  It's also called
1016 	 __.SYMDEF.  So if the user asked to delete it, we should remember
1017 	 that fact. This isn't quite right for COFF systems (where
1018 	 __.SYMDEF might be regular member), but it's very unlikely
1019 	 to be a problem.  FIXME */
1020 
1021       if (!strcmp (*files_to_delete, "__.SYMDEF"))
1022 	{
1023 	  arch->has_armap = FALSE;
1024 	  write_armap = -1;
1025 	  continue;
1026 	}
1027 
1028       found = FALSE;
1029       match_count = 0;
1030       current_ptr_ptr = &(arch->next);
1031       while (*current_ptr_ptr)
1032 	{
1033 	  if (FILENAME_CMP (normalize (*files_to_delete, arch),
1034 			    (*current_ptr_ptr)->filename) == 0)
1035 	    {
1036 	      ++match_count;
1037 	      if (counted_name_mode
1038 		  && match_count != counted_name_counter)
1039 		{
1040 		  /* Counting, and didn't match on count; go on to the
1041                      next one.  */
1042 		}
1043 	      else
1044 		{
1045 		  found = TRUE;
1046 		  something_changed = TRUE;
1047 		  if (verbose)
1048 		    printf ("d - %s\n",
1049 			    *files_to_delete);
1050 		  *current_ptr_ptr = ((*current_ptr_ptr)->next);
1051 		  goto next_file;
1052 		}
1053 	    }
1054 
1055 	  current_ptr_ptr = &((*current_ptr_ptr)->next);
1056 	}
1057 
1058       if (verbose && !found)
1059 	{
1060 	  /* xgettext:c-format */
1061 	  printf (_("No member named `%s'\n"), *files_to_delete);
1062 	}
1063     next_file:
1064       ;
1065     }
1066 
1067   if (something_changed)
1068     write_archive (arch);
1069   else
1070     output_filename = NULL;
1071 }
1072 
1073 
1074 /* Reposition existing members within an archive */
1075 
1076 static void
move_members(bfd * arch,char ** files_to_move)1077 move_members (bfd *arch, char **files_to_move)
1078 {
1079   bfd **after_bfd;		/* New entries go after this one */
1080   bfd **current_ptr_ptr;	/* cdr pointer into contents */
1081 
1082   for (; *files_to_move; ++files_to_move)
1083     {
1084       current_ptr_ptr = &(arch->next);
1085       while (*current_ptr_ptr)
1086 	{
1087 	  bfd *current_ptr = *current_ptr_ptr;
1088 	  if (FILENAME_CMP (normalize (*files_to_move, arch),
1089 			    current_ptr->filename) == 0)
1090 	    {
1091 	      /* Move this file to the end of the list - first cut from
1092 		 where it is.  */
1093 	      bfd *link;
1094 	      *current_ptr_ptr = current_ptr->next;
1095 
1096 	      /* Now glue to end */
1097 	      after_bfd = get_pos_bfd (&arch->next, pos_end, NULL);
1098 	      link = *after_bfd;
1099 	      *after_bfd = current_ptr;
1100 	      current_ptr->next = link;
1101 
1102 	      if (verbose)
1103 		printf ("m - %s\n", *files_to_move);
1104 
1105 	      goto next_file;
1106 	    }
1107 
1108 	  current_ptr_ptr = &((*current_ptr_ptr)->next);
1109 	}
1110       /* xgettext:c-format */
1111       fatal (_("no entry %s in archive %s!"), *files_to_move, arch->filename);
1112 
1113     next_file:;
1114     }
1115 
1116   write_archive (arch);
1117 }
1118 
1119 /* Ought to default to replacing in place, but this is existing practice!  */
1120 
1121 static void
replace_members(bfd * arch,char ** files_to_move,bfd_boolean quick)1122 replace_members (bfd *arch, char **files_to_move, bfd_boolean quick)
1123 {
1124   bfd_boolean changed = FALSE;
1125   bfd **after_bfd;		/* New entries go after this one.  */
1126   bfd *current;
1127   bfd **current_ptr;
1128 
1129   while (files_to_move && *files_to_move)
1130     {
1131       if (! quick)
1132 	{
1133 	  current_ptr = &arch->next;
1134 	  while (*current_ptr)
1135 	    {
1136 	      current = *current_ptr;
1137 
1138 	      /* For compatibility with existing ar programs, we
1139 		 permit the same file to be added multiple times.  */
1140 	      if (FILENAME_CMP (normalize (*files_to_move, arch),
1141 				normalize (current->filename, arch)) == 0
1142 		  && current->arelt_data != NULL)
1143 		{
1144 		  if (newer_only)
1145 		    {
1146 		      struct stat fsbuf, asbuf;
1147 
1148 		      if (stat (*files_to_move, &fsbuf) != 0)
1149 			{
1150 			  if (errno != ENOENT)
1151 			    bfd_fatal (*files_to_move);
1152 			  goto next_file;
1153 			}
1154 		      if (bfd_stat_arch_elt (current, &asbuf) != 0)
1155 			/* xgettext:c-format */
1156 			fatal (_("internal stat error on %s"),
1157 			       current->filename);
1158 
1159 		      if (fsbuf.st_mtime <= asbuf.st_mtime)
1160 			goto next_file;
1161 		    }
1162 
1163 		  after_bfd = get_pos_bfd (&arch->next, pos_after,
1164 					   current->filename);
1165 		  if (ar_emul_replace (after_bfd, *files_to_move,
1166 				       verbose))
1167 		    {
1168 		      /* Snip out this entry from the chain.  */
1169 		      *current_ptr = (*current_ptr)->next;
1170 		      changed = TRUE;
1171 		    }
1172 
1173 		  goto next_file;
1174 		}
1175 	      current_ptr = &(current->next);
1176 	    }
1177 	}
1178 
1179       /* Add to the end of the archive.  */
1180       after_bfd = get_pos_bfd (&arch->next, pos_end, NULL);
1181 
1182       if (ar_emul_append (after_bfd, *files_to_move, verbose))
1183 	changed = TRUE;
1184 
1185     next_file:;
1186 
1187       files_to_move++;
1188     }
1189 
1190   if (changed)
1191     write_archive (arch);
1192   else
1193     output_filename = NULL;
1194 }
1195 
1196 static void
ranlib_only(const char * archname)1197 ranlib_only (const char *archname)
1198 {
1199   bfd *arch;
1200 
1201   if (get_file_size (archname) < 1)
1202     return;
1203   write_armap = 1;
1204   arch = open_inarch (archname, (char *) NULL);
1205   if (arch == NULL)
1206     xexit (1);
1207   write_archive (arch);
1208 }
1209 
1210 /* Update the timestamp of the symbol map of an archive.  */
1211 
1212 static void
ranlib_touch(const char * archname)1213 ranlib_touch (const char *archname)
1214 {
1215 #ifdef __GO32__
1216   /* I don't think updating works on go32.  */
1217   ranlib_only (archname);
1218 #else
1219   int f;
1220   bfd *arch;
1221   char **matching;
1222 
1223   if (get_file_size (archname) < 1)
1224     return;
1225   f = open (archname, O_RDWR | O_BINARY, 0);
1226   if (f < 0)
1227     {
1228       bfd_set_error (bfd_error_system_call);
1229       bfd_fatal (archname);
1230     }
1231 
1232   arch = bfd_fdopenr (archname, (const char *) NULL, f);
1233   if (arch == NULL)
1234     bfd_fatal (archname);
1235   if (! bfd_check_format_matches (arch, bfd_archive, &matching))
1236     {
1237       bfd_nonfatal (archname);
1238       if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
1239 	{
1240 	  list_matching_formats (matching);
1241 	  free (matching);
1242 	}
1243       xexit (1);
1244     }
1245 
1246   if (! bfd_has_map (arch))
1247     /* xgettext:c-format */
1248     fatal (_("%s: no archive map to update"), archname);
1249 
1250   bfd_update_armap_timestamp (arch);
1251 
1252   if (! bfd_close (arch))
1253     bfd_fatal (archname);
1254 #endif
1255 }
1256 
1257 /* Things which are interesting to map over all or some of the files: */
1258 
1259 static void
print_descr(bfd * abfd)1260 print_descr (bfd *abfd)
1261 {
1262   print_arelt_descr (stdout, abfd, verbose);
1263 }
1264