xref: /netbsd/external/gpl3/binutils/dist/binutils/ar.c (revision e072ec67)
12a6b7db3Sskrll /* ar.c - Archive modify and extract.
2*e072ec67Schristos    Copyright (C) 1991-2022 Free Software Foundation, Inc.
32a6b7db3Sskrll 
42a6b7db3Sskrll    This file is part of GNU Binutils.
52a6b7db3Sskrll 
62a6b7db3Sskrll    This program is free software; you can redistribute it and/or modify
72a6b7db3Sskrll    it under the terms of the GNU General Public License as published by
82a6b7db3Sskrll    the Free Software Foundation; either version 3 of the License, or
92a6b7db3Sskrll    (at your option) any later version.
102a6b7db3Sskrll 
112a6b7db3Sskrll    This program is distributed in the hope that it will be useful,
122a6b7db3Sskrll    but WITHOUT ANY WARRANTY; without even the implied warranty of
132a6b7db3Sskrll    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
142a6b7db3Sskrll    GNU General Public License for more details.
152a6b7db3Sskrll 
162a6b7db3Sskrll    You should have received a copy of the GNU General Public License
172a6b7db3Sskrll    along with this program; if not, write to the Free Software
182a6b7db3Sskrll    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
192a6b7db3Sskrll    MA 02110-1301, USA.  */
202a6b7db3Sskrll 
212a6b7db3Sskrll /*
224c43201bSchristos    Bugs: GNU ar used to check file against filesystem in quick_update and
234c43201bSchristos    replace operations (would check mtime). Doesn't warn when name truncated.
244c43201bSchristos    No way to specify pos_end. Error messages should be more consistent.  */
252a6b7db3Sskrll 
262a6b7db3Sskrll #include "sysdep.h"
272a6b7db3Sskrll #include "bfd.h"
282a6b7db3Sskrll #include "libiberty.h"
292a6b7db3Sskrll #include "progress.h"
304c43201bSchristos #include "getopt.h"
312a6b7db3Sskrll #include "aout/ar.h"
322a6b7db3Sskrll #include "bucomm.h"
332a6b7db3Sskrll #include "arsup.h"
342a6b7db3Sskrll #include "filenames.h"
352a6b7db3Sskrll #include "binemul.h"
36aa4b58b1Schristos #include "plugin-api.h"
378443c5fcSchristos #include "plugin.h"
38c21fdd85Schristos #include "ansidecl.h"
392a6b7db3Sskrll 
402a6b7db3Sskrll #ifdef __GO32___
412a6b7db3Sskrll #define EXT_NAME_LEN 3		/* Bufflen of addition to name if it's MS-DOS.  */
422a6b7db3Sskrll #else
432a6b7db3Sskrll #define EXT_NAME_LEN 6		/* Ditto for *NIX.  */
442a6b7db3Sskrll #endif
452a6b7db3Sskrll 
462a6b7db3Sskrll /* Static declarations.  */
472a6b7db3Sskrll 
482a6b7db3Sskrll static void mri_emul (void);
492a6b7db3Sskrll static const char *normalize (const char *, bfd *);
502a6b7db3Sskrll static void remove_output (void);
512a6b7db3Sskrll static void map_over_members (bfd *, void (*)(bfd *), char **, int);
522a6b7db3Sskrll static void print_contents (bfd * member);
532a6b7db3Sskrll static void delete_members (bfd *, char **files_to_delete);
542a6b7db3Sskrll 
552a6b7db3Sskrll static void move_members (bfd *, char **files_to_move);
562a6b7db3Sskrll static void replace_members
57*e072ec67Schristos   (bfd *, char **files_to_replace, bool quick);
582a6b7db3Sskrll static void print_descr (bfd * abfd);
592a6b7db3Sskrll static void write_archive (bfd *);
602a6b7db3Sskrll static int  ranlib_only (const char *archname);
612a6b7db3Sskrll static int  ranlib_touch (const char *archname);
622a6b7db3Sskrll static void usage (int);
632a6b7db3Sskrll 
642a6b7db3Sskrll /** Globals and flags.  */
652a6b7db3Sskrll 
662a6b7db3Sskrll static int mri_mode;
672a6b7db3Sskrll 
682a6b7db3Sskrll /* This flag distinguishes between ar and ranlib:
692a6b7db3Sskrll    1 means this is 'ranlib'; 0 means this is 'ar'.
702a6b7db3Sskrll    -1 means if we should use argv[0] to decide.  */
712a6b7db3Sskrll extern int is_ranlib;
722a6b7db3Sskrll 
732a6b7db3Sskrll /* Nonzero means don't warn about creating the archive file if necessary.  */
742a6b7db3Sskrll int silent_create = 0;
752a6b7db3Sskrll 
762a6b7db3Sskrll /* Nonzero means describe each action performed.  */
772a6b7db3Sskrll int verbose = 0;
782a6b7db3Sskrll 
79916041edSchristos /* Nonzero means display offsets of files in the archive.  */
80916041edSchristos int display_offsets = 0;
81916041edSchristos 
822a6b7db3Sskrll /* Nonzero means preserve dates of members when extracting them.  */
832a6b7db3Sskrll int preserve_dates = 0;
842a6b7db3Sskrll 
852a6b7db3Sskrll /* Nonzero means don't replace existing members whose dates are more recent
862a6b7db3Sskrll    than the corresponding files.  */
872a6b7db3Sskrll int newer_only = 0;
882a6b7db3Sskrll 
892a6b7db3Sskrll /* Controls the writing of an archive symbol table (in BSD: a __.SYMDEF
902a6b7db3Sskrll    member).  -1 means we've been explicitly asked to not write a symbol table;
912a6b7db3Sskrll    +1 means we've been explicitly asked to write it;
922a6b7db3Sskrll    0 is the default.
932a6b7db3Sskrll    Traditionally, the default in BSD has been to not write the table.
942a6b7db3Sskrll    However, for POSIX.2 compliance the default is now to write a symbol table
952a6b7db3Sskrll    if any of the members are object files.  */
962a6b7db3Sskrll int write_armap = 0;
972a6b7db3Sskrll 
98abf07352Sskrll /* Operate in deterministic mode: write zero for timestamps, uids,
99abf07352Sskrll    and gids for archive members and the archive symbol table, and write
100abf07352Sskrll    consistent file modes.  */
1014c43201bSchristos int deterministic = -1;			/* Determinism indeterminate.  */
102abf07352Sskrll 
1032a6b7db3Sskrll /* Nonzero means it's the name of an existing member; position new or moved
1042a6b7db3Sskrll    files with respect to this one.  */
1052a6b7db3Sskrll char *posname = NULL;
1062a6b7db3Sskrll 
1072a6b7db3Sskrll /* Sez how to use `posname': pos_before means position before that member.
1082a6b7db3Sskrll    pos_after means position after that member. pos_end means always at end.
1092a6b7db3Sskrll    pos_default means default appropriately. For the latter two, `posname'
1102a6b7db3Sskrll    should also be zero.  */
1112a6b7db3Sskrll enum pos
1122a6b7db3Sskrll   {
1132a6b7db3Sskrll     pos_default, pos_before, pos_after, pos_end
1142a6b7db3Sskrll   } postype = pos_default;
1152a6b7db3Sskrll 
1164c43201bSchristos enum operations
1174c43201bSchristos   {
1184c43201bSchristos     none = 0, del, replace, print_table,
1194c43201bSchristos     print_files, extract, move, quick_append
1204c43201bSchristos   } operation = none;
1214c43201bSchristos 
1222a6b7db3Sskrll static bfd **
1232a6b7db3Sskrll get_pos_bfd (bfd **, enum pos, const char *);
1242a6b7db3Sskrll 
1252a6b7db3Sskrll /* For extract/delete only.  If COUNTED_NAME_MODE is TRUE, we only
1262a6b7db3Sskrll    extract the COUNTED_NAME_COUNTER instance of that name.  */
127*e072ec67Schristos static bool counted_name_mode = 0;
1282a6b7db3Sskrll static int counted_name_counter = 0;
1292a6b7db3Sskrll 
1302a6b7db3Sskrll /* Whether to truncate names of files stored in the archive.  */
131*e072ec67Schristos static bool ar_truncate = false;
1322a6b7db3Sskrll 
1332a6b7db3Sskrll /* Whether to use a full file name match when searching an archive.
1342a6b7db3Sskrll    This is convenient for archives created by the Microsoft lib
1352a6b7db3Sskrll    program.  */
136*e072ec67Schristos static bool full_pathname = false;
1372a6b7db3Sskrll 
1382a6b7db3Sskrll /* Whether to create a "thin" archive (symbol index only -- no files).  */
139*e072ec67Schristos static bool make_thin_archive = false;
140*e072ec67Schristos 
141*e072ec67Schristos #define LIBDEPS	"__.LIBDEP"
142*e072ec67Schristos /* Text to store in the __.LIBDEP archive element for the linker to use.  */
143*e072ec67Schristos static char * libdeps = NULL;
144*e072ec67Schristos static bfd *  libdeps_bfd = NULL;
1452a6b7db3Sskrll 
1464c43201bSchristos static int show_version = 0;
1474c43201bSchristos 
1484c43201bSchristos static int show_help = 0;
1494c43201bSchristos 
150438aacb6Schristos #if BFD_SUPPORTS_PLUGINS
151438aacb6Schristos static const char *plugin_target = "plugin";
152438aacb6Schristos #else
1538443c5fcSchristos static const char *plugin_target = NULL;
154438aacb6Schristos #endif
1558443c5fcSchristos 
1564c43201bSchristos static const char *target = NULL;
1574c43201bSchristos 
158c21fdd85Schristos enum long_option_numbers
159c21fdd85Schristos {
160c21fdd85Schristos   OPTION_PLUGIN = 201,
161c21fdd85Schristos   OPTION_TARGET,
162c21fdd85Schristos   OPTION_OUTPUT
163c21fdd85Schristos };
164c21fdd85Schristos 
165c21fdd85Schristos static const char * output_dir = NULL;
1664c43201bSchristos 
1674c43201bSchristos static struct option long_options[] =
1684c43201bSchristos {
1694c43201bSchristos   {"help", no_argument, &show_help, 1},
1704c43201bSchristos   {"plugin", required_argument, NULL, OPTION_PLUGIN},
1714c43201bSchristos   {"target", required_argument, NULL, OPTION_TARGET},
1724c43201bSchristos   {"version", no_argument, &show_version, 1},
173c21fdd85Schristos   {"output", required_argument, NULL, OPTION_OUTPUT},
174*e072ec67Schristos   {"record-libdeps", required_argument, NULL, 'l'},
175*e072ec67Schristos   {"thin", no_argument, NULL, 'T'},
1764c43201bSchristos   {NULL, no_argument, NULL, 0}
1774c43201bSchristos };
1784c43201bSchristos 
1792a6b7db3Sskrll int interactive = 0;
1802a6b7db3Sskrll 
1812a6b7db3Sskrll static void
mri_emul(void)1822a6b7db3Sskrll mri_emul (void)
1832a6b7db3Sskrll {
1842a6b7db3Sskrll   interactive = isatty (fileno (stdin));
1852a6b7db3Sskrll   yyparse ();
1862a6b7db3Sskrll }
1872a6b7db3Sskrll 
1882a6b7db3Sskrll /* If COUNT is 0, then FUNCTION is called once on each entry.  If nonzero,
1892a6b7db3Sskrll    COUNT is the length of the FILES chain; FUNCTION is called on each entry
1902a6b7db3Sskrll    whose name matches one in FILES.  */
1912a6b7db3Sskrll 
1922a6b7db3Sskrll static void
map_over_members(bfd * arch,void (* function)(bfd *),char ** files,int count)1932a6b7db3Sskrll map_over_members (bfd *arch, void (*function)(bfd *), char **files, int count)
1942a6b7db3Sskrll {
1952a6b7db3Sskrll   bfd *head;
1962a6b7db3Sskrll   int match_count;
1972a6b7db3Sskrll 
1982a6b7db3Sskrll   if (count == 0)
1992a6b7db3Sskrll     {
2002a6b7db3Sskrll       for (head = arch->archive_next; head; head = head->archive_next)
2012a6b7db3Sskrll 	{
2022a6b7db3Sskrll 	  PROGRESS (1);
2032a6b7db3Sskrll 	  function (head);
2042a6b7db3Sskrll 	}
2052a6b7db3Sskrll       return;
2062a6b7db3Sskrll     }
2072a6b7db3Sskrll 
2082a6b7db3Sskrll   /* This may appear to be a baroque way of accomplishing what we want.
2092a6b7db3Sskrll      However we have to iterate over the filenames in order to notice where
2102a6b7db3Sskrll      a filename is requested but does not exist in the archive.  Ditto
2112a6b7db3Sskrll      mapping over each file each time -- we want to hack multiple
2122a6b7db3Sskrll      references.  */
2132a6b7db3Sskrll 
214438aacb6Schristos   for (head = arch->archive_next; head; head = head->archive_next)
215438aacb6Schristos     head->archive_pass = 0;
216438aacb6Schristos 
2172a6b7db3Sskrll   for (; count > 0; files++, count--)
2182a6b7db3Sskrll     {
219*e072ec67Schristos       bool found = false;
2202a6b7db3Sskrll 
2212a6b7db3Sskrll       match_count = 0;
2222a6b7db3Sskrll       for (head = arch->archive_next; head; head = head->archive_next)
2232a6b7db3Sskrll 	{
2242a6b7db3Sskrll 	  const char * filename;
2252a6b7db3Sskrll 
2262a6b7db3Sskrll 	  PROGRESS (1);
227438aacb6Schristos 	  /* PR binutils/15796: Once an archive element has been matched
228438aacb6Schristos 	     do not match it again.  If the user provides multiple same-named
229438aacb6Schristos 	     parameters on the command line their intent is to match multiple
230438aacb6Schristos 	     same-named entries in the archive, not the same entry multiple
231438aacb6Schristos 	     times.  */
232438aacb6Schristos 	  if (head->archive_pass)
233438aacb6Schristos 	    continue;
234438aacb6Schristos 
235*e072ec67Schristos 	  filename = bfd_get_filename (head);
2362a6b7db3Sskrll 	  if (filename == NULL)
2372a6b7db3Sskrll 	    {
2382a6b7db3Sskrll 	      /* Some archive formats don't get the filenames filled in
2392a6b7db3Sskrll 		 until the elements are opened.  */
2402a6b7db3Sskrll 	      struct stat buf;
2412a6b7db3Sskrll 	      bfd_stat_arch_elt (head, &buf);
2422a6b7db3Sskrll 	    }
2432a6b7db3Sskrll 	  else if (bfd_is_thin_archive (arch))
2442a6b7db3Sskrll 	    {
2452a6b7db3Sskrll 	      /* Thin archives store full pathnames.  Need to normalize.  */
2462a6b7db3Sskrll 	      filename = normalize (filename, arch);
2472a6b7db3Sskrll 	    }
2482a6b7db3Sskrll 
2494c43201bSchristos 	  if (filename != NULL
2504c43201bSchristos 	      && !FILENAME_CMP (normalize (*files, arch), filename))
2512a6b7db3Sskrll 	    {
2522a6b7db3Sskrll 	      ++match_count;
2532a6b7db3Sskrll 	      if (counted_name_mode
2542a6b7db3Sskrll 		  && match_count != counted_name_counter)
2552a6b7db3Sskrll 		{
2562a6b7db3Sskrll 		  /* Counting, and didn't match on count; go on to the
2572a6b7db3Sskrll                      next one.  */
2582a6b7db3Sskrll 		  continue;
2592a6b7db3Sskrll 		}
2602a6b7db3Sskrll 
261*e072ec67Schristos 	      found = true;
2622a6b7db3Sskrll 	      function (head);
263438aacb6Schristos 	      head->archive_pass = 1;
264438aacb6Schristos 	      /* PR binutils/15796: Once a file has been matched, do not
265438aacb6Schristos 		 match any more same-named files in the archive.  If the
266438aacb6Schristos 		 user does want to match multiple same-name files in an
267438aacb6Schristos 		 archive they should provide multiple same-name parameters
268438aacb6Schristos 		 to the ar command.  */
269438aacb6Schristos 	      break;
2702a6b7db3Sskrll 	    }
2712a6b7db3Sskrll 	}
2722a6b7db3Sskrll 
2732a6b7db3Sskrll       if (!found)
2742a6b7db3Sskrll 	/* xgettext:c-format */
2752a6b7db3Sskrll 	fprintf (stderr, _("no entry %s in archive\n"), *files);
2762a6b7db3Sskrll     }
2772a6b7db3Sskrll }
2782a6b7db3Sskrll 
279*e072ec67Schristos bool operation_alters_arch = false;
2802a6b7db3Sskrll 
2812a6b7db3Sskrll static void
usage(int help)2822a6b7db3Sskrll usage (int help)
2832a6b7db3Sskrll {
2842a6b7db3Sskrll   FILE *s;
2852a6b7db3Sskrll 
2868443c5fcSchristos #if BFD_SUPPORTS_PLUGINS
2874c43201bSchristos   /* xgettext:c-format */
2884c43201bSchristos   const char *command_line
289916041edSchristos     = _("Usage: %s [emulation options] [-]{dmpqrstx}[abcDfilMNoOPsSTuvV]"
2904c43201bSchristos 	" [--plugin <name>] [member-name] [count] archive-file file...\n");
2914c43201bSchristos 
2928443c5fcSchristos #else
2934c43201bSchristos   /* xgettext:c-format */
2944c43201bSchristos   const char *command_line
295916041edSchristos     = _("Usage: %s [emulation options] [-]{dmpqrstx}[abcDfilMNoOPsSTuvV]"
2964c43201bSchristos 	" [member-name] [count] archive-file file...\n");
2978443c5fcSchristos #endif
298438aacb6Schristos   s = help ? stdout : stderr;
299438aacb6Schristos 
3008443c5fcSchristos   fprintf (s, command_line, program_name);
3018443c5fcSchristos 
3022a6b7db3Sskrll   /* xgettext:c-format */
3032a6b7db3Sskrll   fprintf (s, _("       %s -M [<mri-script]\n"), program_name);
3042a6b7db3Sskrll   fprintf (s, _(" commands:\n"));
3052a6b7db3Sskrll   fprintf (s, _("  d            - delete file(s) from the archive\n"));
3062a6b7db3Sskrll   fprintf (s, _("  m[ab]        - move file(s) in the archive\n"));
3072a6b7db3Sskrll   fprintf (s, _("  p            - print file(s) found in the archive\n"));
3082a6b7db3Sskrll   fprintf (s, _("  q[f]         - quick append file(s) to the archive\n"));
3092a6b7db3Sskrll   fprintf (s, _("  r[ab][f][u]  - replace existing or insert new file(s) into the archive\n"));
3108443c5fcSchristos   fprintf (s, _("  s            - act as ranlib\n"));
311916041edSchristos   fprintf (s, _("  t[O][v]      - display contents of the archive\n"));
3122a6b7db3Sskrll   fprintf (s, _("  x[o]         - extract file(s) from the archive\n"));
3132a6b7db3Sskrll   fprintf (s, _(" command specific modifiers:\n"));
3142a6b7db3Sskrll   fprintf (s, _("  [a]          - put file(s) after [member-name]\n"));
3152a6b7db3Sskrll   fprintf (s, _("  [b]          - put file(s) before [member-name] (same as [i])\n"));
3164c43201bSchristos   if (DEFAULT_AR_DETERMINISTIC)
3174c43201bSchristos     {
3184c43201bSchristos       fprintf (s, _("\
3194c43201bSchristos   [D]          - use zero for timestamps and uids/gids (default)\n"));
3204c43201bSchristos       fprintf (s, _("\
3214c43201bSchristos   [U]          - use actual timestamps and uids/gids\n"));
3224c43201bSchristos     }
3234c43201bSchristos   else
3244c43201bSchristos     {
3254c43201bSchristos       fprintf (s, _("\
3264c43201bSchristos   [D]          - use zero for timestamps and uids/gids\n"));
3274c43201bSchristos       fprintf (s, _("\
3284c43201bSchristos   [U]          - use actual timestamps and uids/gids (default)\n"));
3294c43201bSchristos     }
3302a6b7db3Sskrll   fprintf (s, _("  [N]          - use instance [count] of name\n"));
3312a6b7db3Sskrll   fprintf (s, _("  [f]          - truncate inserted file names\n"));
3322a6b7db3Sskrll   fprintf (s, _("  [P]          - use full path names when matching\n"));
3332a6b7db3Sskrll   fprintf (s, _("  [o]          - preserve original dates\n"));
334916041edSchristos   fprintf (s, _("  [O]          - display offsets of files in the archive\n"));
3352a6b7db3Sskrll   fprintf (s, _("  [u]          - only replace files that are newer than current archive contents\n"));
3362a6b7db3Sskrll   fprintf (s, _(" generic modifiers:\n"));
3372a6b7db3Sskrll   fprintf (s, _("  [c]          - do not warn if the library had to be created\n"));
3382a6b7db3Sskrll   fprintf (s, _("  [s]          - create an archive index (cf. ranlib)\n"));
339*e072ec67Schristos   fprintf (s, _("  [l <text> ]  - specify the dependencies of this library\n"));
3402a6b7db3Sskrll   fprintf (s, _("  [S]          - do not build a symbol table\n"));
341*e072ec67Schristos   fprintf (s, _("  [T]          - deprecated, use --thin instead\n"));
3422a6b7db3Sskrll   fprintf (s, _("  [v]          - be verbose\n"));
3432a6b7db3Sskrll   fprintf (s, _("  [V]          - display the version number\n"));
3442a6b7db3Sskrll   fprintf (s, _("  @<file>      - read options from <file>\n"));
3454c43201bSchristos   fprintf (s, _("  --target=BFDNAME - specify the target object format as BFDNAME\n"));
346c21fdd85Schristos   fprintf (s, _("  --output=DIRNAME - specify the output directory for extraction operations\n"));
347*e072ec67Schristos   fprintf (s, _("  --record-libdeps=<text> - specify the dependencies of this library\n"));
348*e072ec67Schristos   fprintf (s, _("  --thin       - make a thin archive\n"));
3498443c5fcSchristos #if BFD_SUPPORTS_PLUGINS
3508443c5fcSchristos   fprintf (s, _(" optional:\n"));
3518443c5fcSchristos   fprintf (s, _("  --plugin <p> - load the specified plugin\n"));
3528443c5fcSchristos #endif
3534c43201bSchristos 
3542a6b7db3Sskrll   ar_emul_usage (s);
3554c43201bSchristos 
3564c43201bSchristos   list_supported_targets (program_name, s);
3574c43201bSchristos 
3584c43201bSchristos   if (REPORT_BUGS_TO[0] && help)
3594c43201bSchristos     fprintf (s, _("Report bugs to %s\n"), REPORT_BUGS_TO);
3604c43201bSchristos 
3614c43201bSchristos   xexit (help ? 0 : 1);
3622a6b7db3Sskrll }
3634c43201bSchristos 
3644c43201bSchristos static void
ranlib_usage(int help)3654c43201bSchristos ranlib_usage (int help)
3662a6b7db3Sskrll {
3674c43201bSchristos   FILE *s;
3684c43201bSchristos 
3694c43201bSchristos   s = help ? stdout : stderr;
3704c43201bSchristos 
3712a6b7db3Sskrll   /* xgettext:c-format */
3722a6b7db3Sskrll   fprintf (s, _("Usage: %s [options] archive\n"), program_name);
3732a6b7db3Sskrll   fprintf (s, _(" Generate an index to speed access to archives\n"));
3742a6b7db3Sskrll   fprintf (s, _(" The options are:\n\
3758443c5fcSchristos   @<file>                      Read options from <file>\n"));
3768443c5fcSchristos #if BFD_SUPPORTS_PLUGINS
3778443c5fcSchristos   fprintf (s, _("\
3788443c5fcSchristos   --plugin <name>              Load the specified plugin\n"));
3798443c5fcSchristos #endif
3804c43201bSchristos   if (DEFAULT_AR_DETERMINISTIC)
3814c43201bSchristos     fprintf (s, _("\
3824c43201bSchristos   -D                           Use zero for symbol map timestamp (default)\n\
3834c43201bSchristos   -U                           Use an actual symbol map timestamp\n"));
3844c43201bSchristos   else
3854c43201bSchristos     fprintf (s, _("\
3864c43201bSchristos   -D                           Use zero for symbol map timestamp\n\
3874c43201bSchristos   -U                           Use actual symbol map timestamp (default)\n"));
3888443c5fcSchristos   fprintf (s, _("\
3892a6b7db3Sskrll   -t                           Update the archive's symbol map timestamp\n\
3902a6b7db3Sskrll   -h --help                    Print this help message\n\
3912a6b7db3Sskrll   -v --version                 Print version information\n"));
3922a6b7db3Sskrll 
3932a6b7db3Sskrll   list_supported_targets (program_name, s);
3942a6b7db3Sskrll 
3952a6b7db3Sskrll   if (REPORT_BUGS_TO[0] && help)
3962a6b7db3Sskrll     fprintf (s, _("Report bugs to %s\n"), REPORT_BUGS_TO);
3972a6b7db3Sskrll 
3982a6b7db3Sskrll   xexit (help ? 0 : 1);
3992a6b7db3Sskrll }
4002a6b7db3Sskrll 
4012a6b7db3Sskrll /* Normalize a file name specified on the command line into a file
4022a6b7db3Sskrll    name which we will use in an archive.  */
4032a6b7db3Sskrll 
4042a6b7db3Sskrll static const char *
normalize(const char * file,bfd * abfd)4052a6b7db3Sskrll normalize (const char *file, bfd *abfd)
4062a6b7db3Sskrll {
4072a6b7db3Sskrll   const char *filename;
4082a6b7db3Sskrll 
4092a6b7db3Sskrll   if (full_pathname)
4102a6b7db3Sskrll     return file;
4112a6b7db3Sskrll 
4128443c5fcSchristos   filename = lbasename (file);
4132a6b7db3Sskrll 
4142a6b7db3Sskrll   if (ar_truncate
4152a6b7db3Sskrll       && abfd != NULL
4162a6b7db3Sskrll       && strlen (filename) > abfd->xvec->ar_max_namelen)
4172a6b7db3Sskrll     {
4182a6b7db3Sskrll       char *s;
4192a6b7db3Sskrll 
4202a6b7db3Sskrll       /* Space leak.  */
4218443c5fcSchristos       s = (char *) xmalloc (abfd->xvec->ar_max_namelen + 1);
4222a6b7db3Sskrll       memcpy (s, filename, abfd->xvec->ar_max_namelen);
4232a6b7db3Sskrll       s[abfd->xvec->ar_max_namelen] = '\0';
4242a6b7db3Sskrll       filename = s;
4252a6b7db3Sskrll     }
4262a6b7db3Sskrll 
4272a6b7db3Sskrll   return filename;
4282a6b7db3Sskrll }
4292a6b7db3Sskrll 
4302a6b7db3Sskrll /* Remove any output file.  This is only called via xatexit.  */
4312a6b7db3Sskrll 
4322a6b7db3Sskrll static const char *output_filename = NULL;
4332a6b7db3Sskrll static FILE *output_file = NULL;
4342a6b7db3Sskrll static bfd *output_bfd = NULL;
4352a6b7db3Sskrll 
4362a6b7db3Sskrll static void
remove_output(void)4372a6b7db3Sskrll remove_output (void)
4382a6b7db3Sskrll {
4392a6b7db3Sskrll   if (output_filename != NULL)
4402a6b7db3Sskrll     {
4412a6b7db3Sskrll       if (output_bfd != NULL)
4422a6b7db3Sskrll 	bfd_cache_close (output_bfd);
4432a6b7db3Sskrll       if (output_file != NULL)
4442a6b7db3Sskrll 	fclose (output_file);
4452a6b7db3Sskrll       unlink_if_ordinary (output_filename);
4462a6b7db3Sskrll     }
4472a6b7db3Sskrll }
4482a6b7db3Sskrll 
4494c43201bSchristos static char **
decode_options(int argc,char ** argv)4504c43201bSchristos decode_options (int argc, char **argv)
4512a6b7db3Sskrll {
4524c43201bSchristos   int c;
4534c43201bSchristos 
454c21fdd85Schristos   /* Convert old-style ar call by exploding option element and rearranging
4554c43201bSchristos      options accordingly.  */
4564c43201bSchristos 
457c21fdd85Schristos  restart:
4584c43201bSchristos   if (argc > 1 && argv[1][0] != '-')
4592a6b7db3Sskrll     {
4604c43201bSchristos       int new_argc;		/* argc value for rearranged arguments */
4614c43201bSchristos       char **new_argv;		/* argv value for rearranged arguments */
4624c43201bSchristos       char *const *in;		/* cursor into original argv */
4634c43201bSchristos       char **out;		/* cursor into rearranged argv */
4644c43201bSchristos       const char *letter;	/* cursor into old option letters */
4654c43201bSchristos       char buffer[3];		/* constructed option buffer */
4662a6b7db3Sskrll 
4674c43201bSchristos       /* Initialize a constructed option.  */
4682a6b7db3Sskrll 
4694c43201bSchristos       buffer[0] = '-';
4704c43201bSchristos       buffer[2] = '\0';
4712a6b7db3Sskrll 
4724c43201bSchristos       /* Allocate a new argument array, and copy program name in it.  */
4732a6b7db3Sskrll 
4744c43201bSchristos       new_argc = argc - 1 + strlen (argv[1]);
4754c43201bSchristos       new_argv = xmalloc ((new_argc + 1) * sizeof (*argv));
4764c43201bSchristos       in = argv;
4774c43201bSchristos       out = new_argv;
4784c43201bSchristos       *out++ = *in++;
4794c43201bSchristos 
4804c43201bSchristos       /* Copy each old letter option as a separate option.  */
4814c43201bSchristos 
4824c43201bSchristos       for (letter = *in++; *letter; letter++)
4832a6b7db3Sskrll 	{
4844c43201bSchristos 	  buffer[1] = *letter;
4854c43201bSchristos 	  *out++ = xstrdup (buffer);
4862a6b7db3Sskrll 	}
4872a6b7db3Sskrll 
4884c43201bSchristos       /* Copy all remaining options.  */
4894c43201bSchristos 
4904c43201bSchristos       while (in < argv + argc)
4914c43201bSchristos 	*out++ = *in++;
4924c43201bSchristos       *out = NULL;
4934c43201bSchristos 
4944c43201bSchristos       /* Replace the old option list by the new one.  */
4954c43201bSchristos 
4964c43201bSchristos       argc = new_argc;
4974c43201bSchristos       argv = new_argv;
4982a6b7db3Sskrll     }
4992a6b7db3Sskrll 
500*e072ec67Schristos   while ((c = getopt_long (argc, argv, "hdmpqrtxl:coOVsSuvabiMNfPTDU",
5014c43201bSchristos 			   long_options, NULL)) != EOF)
5022a6b7db3Sskrll     {
5032a6b7db3Sskrll       switch (c)
5042a6b7db3Sskrll         {
5052a6b7db3Sskrll         case 'd':
5062a6b7db3Sskrll         case 'm':
5072a6b7db3Sskrll         case 'p':
5082a6b7db3Sskrll         case 'q':
5092a6b7db3Sskrll         case 'r':
5102a6b7db3Sskrll         case 't':
5112a6b7db3Sskrll         case 'x':
5122a6b7db3Sskrll           if (operation != none)
5132a6b7db3Sskrll             fatal (_("two different operation options specified"));
5144c43201bSchristos 	  break;
5154c43201bSchristos 	}
5164c43201bSchristos 
5172a6b7db3Sskrll       switch (c)
5182a6b7db3Sskrll         {
5194c43201bSchristos         case 'h':
5204c43201bSchristos 	  show_help = 1;
5214c43201bSchristos 	  break;
5222a6b7db3Sskrll         case 'd':
5238443c5fcSchristos           operation = del;
524*e072ec67Schristos           operation_alters_arch = true;
5252a6b7db3Sskrll           break;
5262a6b7db3Sskrll         case 'm':
5272a6b7db3Sskrll           operation = move;
528*e072ec67Schristos           operation_alters_arch = true;
5292a6b7db3Sskrll           break;
5302a6b7db3Sskrll         case 'p':
5312a6b7db3Sskrll           operation = print_files;
5322a6b7db3Sskrll           break;
5332a6b7db3Sskrll         case 'q':
5342a6b7db3Sskrll           operation = quick_append;
535*e072ec67Schristos           operation_alters_arch = true;
5362a6b7db3Sskrll           break;
5372a6b7db3Sskrll         case 'r':
5382a6b7db3Sskrll           operation = replace;
539*e072ec67Schristos           operation_alters_arch = true;
5402a6b7db3Sskrll           break;
5412a6b7db3Sskrll         case 't':
5422a6b7db3Sskrll           operation = print_table;
5432a6b7db3Sskrll           break;
5442a6b7db3Sskrll         case 'x':
5452a6b7db3Sskrll           operation = extract;
5462a6b7db3Sskrll           break;
5472a6b7db3Sskrll         case 'l':
548*e072ec67Schristos           if (libdeps != NULL)
549*e072ec67Schristos             fatal (_("libdeps specified more than once"));
550*e072ec67Schristos           libdeps = optarg;
5512a6b7db3Sskrll           break;
5522a6b7db3Sskrll         case 'c':
5532a6b7db3Sskrll           silent_create = 1;
5542a6b7db3Sskrll           break;
5552a6b7db3Sskrll         case 'o':
5562a6b7db3Sskrll           preserve_dates = 1;
5572a6b7db3Sskrll           break;
558916041edSchristos         case 'O':
559916041edSchristos           display_offsets = 1;
560916041edSchristos           break;
5612a6b7db3Sskrll         case 'V':
562*e072ec67Schristos           show_version = true;
5632a6b7db3Sskrll           break;
5642a6b7db3Sskrll         case 's':
5652a6b7db3Sskrll           write_armap = 1;
5662a6b7db3Sskrll           break;
5672a6b7db3Sskrll         case 'S':
5682a6b7db3Sskrll           write_armap = -1;
5692a6b7db3Sskrll           break;
5702a6b7db3Sskrll         case 'u':
5712a6b7db3Sskrll           newer_only = 1;
5722a6b7db3Sskrll           break;
5732a6b7db3Sskrll         case 'v':
5742a6b7db3Sskrll           verbose = 1;
5752a6b7db3Sskrll           break;
5762a6b7db3Sskrll         case 'a':
5772a6b7db3Sskrll           postype = pos_after;
5782a6b7db3Sskrll           break;
5792a6b7db3Sskrll         case 'b':
5802a6b7db3Sskrll           postype = pos_before;
5812a6b7db3Sskrll           break;
5822a6b7db3Sskrll         case 'i':
5832a6b7db3Sskrll           postype = pos_before;
5842a6b7db3Sskrll           break;
5852a6b7db3Sskrll         case 'M':
5862a6b7db3Sskrll           mri_mode = 1;
5872a6b7db3Sskrll           break;
5882a6b7db3Sskrll         case 'N':
589*e072ec67Schristos           counted_name_mode = true;
5902a6b7db3Sskrll           break;
5912a6b7db3Sskrll         case 'f':
592*e072ec67Schristos           ar_truncate = true;
5932a6b7db3Sskrll           break;
5942a6b7db3Sskrll         case 'P':
595*e072ec67Schristos           full_pathname = true;
5962a6b7db3Sskrll           break;
5972a6b7db3Sskrll         case 'T':
598*e072ec67Schristos           make_thin_archive = true;
5992a6b7db3Sskrll           break;
6008443c5fcSchristos         case 'D':
601*e072ec67Schristos           deterministic = true;
6028443c5fcSchristos           break;
6034c43201bSchristos         case 'U':
604*e072ec67Schristos           deterministic = false;
6054c43201bSchristos           break;
6064c43201bSchristos 	case OPTION_PLUGIN:
6074c43201bSchristos #if BFD_SUPPORTS_PLUGINS
6084c43201bSchristos 	  bfd_plugin_set_plugin (optarg);
6094c43201bSchristos #else
6104c43201bSchristos 	  fprintf (stderr, _("sorry - this program has been built without plugin support\n"));
6114c43201bSchristos 	  xexit (1);
6124c43201bSchristos #endif
6134c43201bSchristos 	  break;
6144c43201bSchristos 	case OPTION_TARGET:
6154c43201bSchristos 	  target = optarg;
6164c43201bSchristos 	  break;
617c21fdd85Schristos 	case OPTION_OUTPUT:
618c21fdd85Schristos 	  output_dir = optarg;
619c21fdd85Schristos 	  break;
6204c43201bSchristos 	case 0:		/* A long option that just sets a flag.  */
6214c43201bSchristos 	  break;
6222a6b7db3Sskrll         default:
6232a6b7db3Sskrll           usage (0);
6242a6b7db3Sskrll         }
6252a6b7db3Sskrll     }
6262a6b7db3Sskrll 
627c21fdd85Schristos   /* PR 13256: Allow for the possibility that the first command line option
628c21fdd85Schristos      started with a dash (eg --plugin) but then the following option(s) are
629c21fdd85Schristos      old style, non-dash-prefixed versions.  */
630c21fdd85Schristos   if (operation == none && write_armap != 1 && !mri_mode
631c21fdd85Schristos       && optind > 0 && optind < argc)
632c21fdd85Schristos     {
633c21fdd85Schristos       argv += (optind - 1);
634c21fdd85Schristos       argc -= (optind - 1);
635c21fdd85Schristos       optind = 0;
636c21fdd85Schristos       goto restart;
637c21fdd85Schristos     }
638c21fdd85Schristos 
6394c43201bSchristos   return &argv[optind];
6402a6b7db3Sskrll }
6414c43201bSchristos 
6424c43201bSchristos /* If neither -D nor -U was specified explicitly,
6434c43201bSchristos    then use the configured default.  */
6444c43201bSchristos static void
default_deterministic(void)6454c43201bSchristos default_deterministic (void)
6464c43201bSchristos {
6474c43201bSchristos   if (deterministic < 0)
6484c43201bSchristos     deterministic = DEFAULT_AR_DETERMINISTIC;
6494c43201bSchristos }
6504c43201bSchristos 
6514c43201bSchristos static void
ranlib_main(int argc,char ** argv)6524c43201bSchristos ranlib_main (int argc, char **argv)
6534c43201bSchristos {
6544c43201bSchristos   int arg_index, status = 0;
655*e072ec67Schristos   bool touch = false;
6564c43201bSchristos   int c;
6574c43201bSchristos 
6584c43201bSchristos   while ((c = getopt_long (argc, argv, "DhHUvVt", long_options, NULL)) != EOF)
6594c43201bSchristos     {
6604c43201bSchristos       switch (c)
6614c43201bSchristos         {
6624c43201bSchristos 	case 'D':
663*e072ec67Schristos 	  deterministic = true;
6644c43201bSchristos 	  break;
6654c43201bSchristos         case 'U':
666*e072ec67Schristos           deterministic = false;
6674c43201bSchristos           break;
6684c43201bSchristos 	case 'h':
6694c43201bSchristos 	case 'H':
6704c43201bSchristos 	  show_help = 1;
6714c43201bSchristos 	  break;
6724c43201bSchristos 	case 't':
673*e072ec67Schristos 	  touch = true;
6744c43201bSchristos 	  break;
6754c43201bSchristos 	case 'v':
6764c43201bSchristos 	case 'V':
6774c43201bSchristos 	  show_version = 1;
6784c43201bSchristos 	  break;
6794c43201bSchristos 
6804c43201bSchristos 	  /* PR binutils/13493: Support plugins.  */
6814c43201bSchristos 	case OPTION_PLUGIN:
6824c43201bSchristos #if BFD_SUPPORTS_PLUGINS
6834c43201bSchristos 	  bfd_plugin_set_plugin (optarg);
6844c43201bSchristos #else
6854c43201bSchristos 	  fprintf (stderr, _("sorry - this program has been built without plugin support\n"));
6864c43201bSchristos 	  xexit (1);
6874c43201bSchristos #endif
6884c43201bSchristos 	  break;
6894c43201bSchristos 	}
6904c43201bSchristos     }
6914c43201bSchristos 
6924c43201bSchristos   if (argc < 2)
6934c43201bSchristos     ranlib_usage (0);
6944c43201bSchristos 
6954c43201bSchristos   if (show_help)
6964c43201bSchristos     ranlib_usage (1);
6974c43201bSchristos 
6984c43201bSchristos   if (show_version)
6994c43201bSchristos     print_version ("ranlib");
7004c43201bSchristos 
7014c43201bSchristos   default_deterministic ();
7024c43201bSchristos 
7034c43201bSchristos   arg_index = optind;
7044c43201bSchristos 
7054c43201bSchristos   while (arg_index < argc)
7064c43201bSchristos     {
7074c43201bSchristos       if (! touch)
7084c43201bSchristos         status |= ranlib_only (argv[arg_index]);
7094c43201bSchristos       else
7104c43201bSchristos         status |= ranlib_touch (argv[arg_index]);
7114c43201bSchristos       ++arg_index;
7124c43201bSchristos     }
7134c43201bSchristos 
7144c43201bSchristos   xexit (status);
7154c43201bSchristos }
7164c43201bSchristos 
7174c43201bSchristos int main (int, char **);
7184c43201bSchristos 
7194c43201bSchristos int
main(int argc,char ** argv)7204c43201bSchristos main (int argc, char **argv)
7214c43201bSchristos {
7224c43201bSchristos   int arg_index;
7234c43201bSchristos   char **files;
7244c43201bSchristos   int file_count;
7254c43201bSchristos   char *inarch_filename;
7264c43201bSchristos   int i;
7274c43201bSchristos 
728*e072ec67Schristos #ifdef HAVE_LC_MESSAGES
7294c43201bSchristos   setlocale (LC_MESSAGES, "");
7304c43201bSchristos #endif
7314c43201bSchristos   setlocale (LC_CTYPE, "");
7324c43201bSchristos   bindtextdomain (PACKAGE, LOCALEDIR);
7334c43201bSchristos   textdomain (PACKAGE);
7344c43201bSchristos 
7354c43201bSchristos   program_name = argv[0];
7364c43201bSchristos   xmalloc_set_program_name (program_name);
737438aacb6Schristos   bfd_set_error_program_name (program_name);
7384c43201bSchristos #if BFD_SUPPORTS_PLUGINS
7394c43201bSchristos   bfd_plugin_set_program_name (program_name);
7404c43201bSchristos #endif
7414c43201bSchristos 
7424c43201bSchristos   expandargv (&argc, &argv);
7434c43201bSchristos 
7444c43201bSchristos   if (is_ranlib < 0)
7454c43201bSchristos     {
7464c43201bSchristos       const char *temp = lbasename (program_name);
7474c43201bSchristos 
7484c43201bSchristos       if (strlen (temp) >= 6
7494c43201bSchristos 	  && FILENAME_CMP (temp + strlen (temp) - 6, "ranlib") == 0)
7504c43201bSchristos 	is_ranlib = 1;
7514c43201bSchristos       else
7524c43201bSchristos 	is_ranlib = 0;
7534c43201bSchristos     }
7544c43201bSchristos 
7554c43201bSchristos   START_PROGRESS (program_name, 0);
7564c43201bSchristos 
757c21fdd85Schristos   if (bfd_init () != BFD_INIT_MAGIC)
758c21fdd85Schristos     fatal (_("fatal error: libbfd ABI mismatch"));
7594c43201bSchristos   set_default_bfd_target ();
7604c43201bSchristos 
7614c43201bSchristos   xatexit (remove_output);
7624c43201bSchristos 
7634c43201bSchristos   for (i = 1; i < argc; i++)
7644c43201bSchristos     if (! ar_emul_parse_arg (argv[i]))
7654c43201bSchristos       break;
7664c43201bSchristos   argv += (i - 1);
7674c43201bSchristos   argc -= (i - 1);
7684c43201bSchristos 
7694c43201bSchristos   if (is_ranlib)
7704c43201bSchristos     ranlib_main (argc, argv);
7714c43201bSchristos 
7724c43201bSchristos   if (argc < 2)
7734c43201bSchristos     usage (0);
7744c43201bSchristos 
7754c43201bSchristos   argv = decode_options (argc, argv);
7764c43201bSchristos 
7774c43201bSchristos   if (show_help)
7784c43201bSchristos     usage (1);
7792a6b7db3Sskrll 
7802a6b7db3Sskrll   if (show_version)
7812a6b7db3Sskrll     print_version ("ar");
7822a6b7db3Sskrll 
7834c43201bSchristos   arg_index = 0;
7842a6b7db3Sskrll 
7852a6b7db3Sskrll   if (mri_mode)
7862a6b7db3Sskrll     {
787438aacb6Schristos       default_deterministic ();
7882a6b7db3Sskrll       mri_emul ();
7892a6b7db3Sskrll     }
7902a6b7db3Sskrll   else
7912a6b7db3Sskrll     {
7922a6b7db3Sskrll       bfd *arch;
7932a6b7db3Sskrll 
794aa4b58b1Schristos       /* Fail if no files are specified on the command line.
795aa4b58b1Schristos 	 (But not for MRI mode which allows for reading arguments
796aa4b58b1Schristos 	 and filenames from stdin).  */
797aa4b58b1Schristos       if (argv[arg_index] == NULL)
798aa4b58b1Schristos 	usage (0);
799aa4b58b1Schristos 
8002a6b7db3Sskrll       /* We don't use do_quick_append any more.  Too many systems
8012a6b7db3Sskrll 	 expect ar to always rebuild the symbol table even when q is
8022a6b7db3Sskrll 	 used.  */
8032a6b7db3Sskrll 
8042a6b7db3Sskrll       /* We can't write an armap when using ar q, so just do ar r
8052a6b7db3Sskrll          instead.  */
8062a6b7db3Sskrll       if (operation == quick_append && write_armap)
8072a6b7db3Sskrll 	operation = replace;
8082a6b7db3Sskrll 
8092a6b7db3Sskrll       if ((operation == none || operation == print_table)
8102a6b7db3Sskrll 	  && write_armap == 1)
8112a6b7db3Sskrll 	xexit (ranlib_only (argv[arg_index]));
8122a6b7db3Sskrll 
8132a6b7db3Sskrll       if (operation == none)
8142a6b7db3Sskrll 	fatal (_("no operation specified"));
8152a6b7db3Sskrll 
8162a6b7db3Sskrll       if (newer_only && operation != replace)
8172a6b7db3Sskrll 	fatal (_("`u' is only meaningful with the `r' option."));
8182a6b7db3Sskrll 
8194c43201bSchristos       if (newer_only && deterministic > 0)
820abf07352Sskrll         fatal (_("`u' is not meaningful with the `D' option."));
821abf07352Sskrll 
8224c43201bSchristos       if (newer_only && deterministic < 0 && DEFAULT_AR_DETERMINISTIC)
8234c43201bSchristos         non_fatal (_("\
8244c43201bSchristos `u' modifier ignored since `D' is the default (see `U')"));
8254c43201bSchristos 
8264c43201bSchristos       default_deterministic ();
8274c43201bSchristos 
8282a6b7db3Sskrll       if (postype != pos_default)
829aa4b58b1Schristos 	{
8302a6b7db3Sskrll 	  posname = argv[arg_index++];
831aa4b58b1Schristos 	  if (posname == NULL)
832aa4b58b1Schristos 	    fatal (_("missing position arg."));
833aa4b58b1Schristos 	}
8342a6b7db3Sskrll 
8352a6b7db3Sskrll       if (counted_name_mode)
8362a6b7db3Sskrll 	{
8378443c5fcSchristos 	  if (operation != extract && operation != del)
8382a6b7db3Sskrll 	    fatal (_("`N' is only meaningful with the `x' and `d' options."));
839aa4b58b1Schristos 	  if (argv[arg_index] == NULL)
840aa4b58b1Schristos 	    fatal (_("`N' missing value."));
8412a6b7db3Sskrll 	  counted_name_counter = atoi (argv[arg_index++]);
8422a6b7db3Sskrll 	  if (counted_name_counter <= 0)
8432a6b7db3Sskrll 	    fatal (_("Value for `N' must be positive."));
8442a6b7db3Sskrll 	}
8452a6b7db3Sskrll 
8462a6b7db3Sskrll       inarch_filename = argv[arg_index++];
847aa4b58b1Schristos       if (inarch_filename == NULL)
848aa4b58b1Schristos 	usage (0);
8492a6b7db3Sskrll 
8504c43201bSchristos       for (file_count = 0; argv[arg_index + file_count] != NULL; file_count++)
8514c43201bSchristos 	continue;
8524c43201bSchristos 
8534c43201bSchristos       files = (file_count > 0) ? argv + arg_index : NULL;
8542a6b7db3Sskrll 
8552a6b7db3Sskrll       arch = open_inarch (inarch_filename,
8562a6b7db3Sskrll 			  files == NULL ? (char *) NULL : files[0]);
8572a6b7db3Sskrll 
8582a6b7db3Sskrll       if (operation == extract && bfd_is_thin_archive (arch))
8592a6b7db3Sskrll 	fatal (_("`x' cannot be used on thin archives."));
8602a6b7db3Sskrll 
861*e072ec67Schristos       if (libdeps != NULL)
862*e072ec67Schristos 	{
863*e072ec67Schristos 	  char **new_files;
864*e072ec67Schristos 	  bfd_size_type reclen = strlen (libdeps) + 1;
865*e072ec67Schristos 
866*e072ec67Schristos 	  /* Create a bfd to contain the dependencies.
867*e072ec67Schristos 	     It inherits its type from arch, but we must set the type to
868*e072ec67Schristos 	     "binary" otherwise bfd_bwrite() will fail.  After writing, we
869*e072ec67Schristos 	     must set the type back to default otherwise adding it to the
870*e072ec67Schristos 	     archive will fail.  */
871*e072ec67Schristos 	  libdeps_bfd = bfd_create (LIBDEPS, arch);
872*e072ec67Schristos 	  if (libdeps_bfd == NULL)
873*e072ec67Schristos 	    fatal (_("Cannot create libdeps record."));
874*e072ec67Schristos 
875*e072ec67Schristos 	  if (bfd_find_target ("binary", libdeps_bfd) == NULL)
876*e072ec67Schristos 	    fatal (_("Cannot set libdeps record type to binary."));
877*e072ec67Schristos 
878*e072ec67Schristos 	  if (! bfd_set_format (libdeps_bfd, bfd_object))
879*e072ec67Schristos 	    fatal (_("Cannot set libdeps object format."));
880*e072ec67Schristos 
881*e072ec67Schristos 	  if (! bfd_make_writable (libdeps_bfd))
882*e072ec67Schristos 	    fatal (_("Cannot make libdeps object writable."));
883*e072ec67Schristos 
884*e072ec67Schristos 	  if (bfd_bwrite (libdeps, reclen, libdeps_bfd) != reclen)
885*e072ec67Schristos 	    fatal (_("Cannot write libdeps record."));
886*e072ec67Schristos 
887*e072ec67Schristos 	  if (! bfd_make_readable (libdeps_bfd))
888*e072ec67Schristos 	    fatal (_("Cannot make libdeps object readable."));
889*e072ec67Schristos 
890*e072ec67Schristos 	  if (bfd_find_target (plugin_target, libdeps_bfd) == NULL)
891*e072ec67Schristos 	    fatal (_("Cannot reset libdeps record type."));
892*e072ec67Schristos 
893*e072ec67Schristos 	  /* Insert our libdeps record in 2nd slot of the list of files
894*e072ec67Schristos 	     being operated on.  We shouldn't use 1st slot, but we want
895*e072ec67Schristos 	     to avoid having to search all the way to the end of an
896*e072ec67Schristos 	     archive with a large number of members at link time.  */
897*e072ec67Schristos 	  new_files = xmalloc ((file_count + 2) * sizeof (*new_files));
898*e072ec67Schristos 	  if (file_count)
899*e072ec67Schristos 	    {
900*e072ec67Schristos 	      new_files[0] = files[0];
901*e072ec67Schristos 	      memcpy (new_files + 1, files, file_count * sizeof (*files));
902*e072ec67Schristos 	    }
903*e072ec67Schristos 	  new_files[file_count != 0] = LIBDEPS;
904*e072ec67Schristos 	  file_count++;
905*e072ec67Schristos 	  new_files[file_count] = NULL;
906*e072ec67Schristos 	  files = new_files;
907*e072ec67Schristos 	}
908*e072ec67Schristos 
9092a6b7db3Sskrll       switch (operation)
9102a6b7db3Sskrll 	{
9112a6b7db3Sskrll 	case print_table:
9122a6b7db3Sskrll 	  map_over_members (arch, print_descr, files, file_count);
9132a6b7db3Sskrll 	  break;
9142a6b7db3Sskrll 
9152a6b7db3Sskrll 	case print_files:
9162a6b7db3Sskrll 	  map_over_members (arch, print_contents, files, file_count);
9172a6b7db3Sskrll 	  break;
9182a6b7db3Sskrll 
9192a6b7db3Sskrll 	case extract:
9202a6b7db3Sskrll 	  map_over_members (arch, extract_file, files, file_count);
9212a6b7db3Sskrll 	  break;
9222a6b7db3Sskrll 
9238443c5fcSchristos 	case del:
9242a6b7db3Sskrll 	  if (files != NULL)
9252a6b7db3Sskrll 	    delete_members (arch, files);
9262a6b7db3Sskrll 	  else
9272a6b7db3Sskrll 	    output_filename = NULL;
9282a6b7db3Sskrll 	  break;
9292a6b7db3Sskrll 
9302a6b7db3Sskrll 	case move:
9314c43201bSchristos 	  /* PR 12558: Creating and moving at the same time does
9324c43201bSchristos 	     not make sense.  Just create the archive instead.  */
9334c43201bSchristos 	  if (! silent_create)
9344c43201bSchristos 	    {
9352a6b7db3Sskrll 	      if (files != NULL)
9362a6b7db3Sskrll 		move_members (arch, files);
9372a6b7db3Sskrll 	      else
9382a6b7db3Sskrll 		output_filename = NULL;
9392a6b7db3Sskrll 	      break;
9404c43201bSchristos 	    }
9414c43201bSchristos 	  /* Fall through.  */
9422a6b7db3Sskrll 
9432a6b7db3Sskrll 	case replace:
9442a6b7db3Sskrll 	case quick_append:
9452a6b7db3Sskrll 	  if (files != NULL || write_armap > 0)
9462a6b7db3Sskrll 	    replace_members (arch, files, operation == quick_append);
9472a6b7db3Sskrll 	  else
9482a6b7db3Sskrll 	    output_filename = NULL;
9492a6b7db3Sskrll 	  break;
9502a6b7db3Sskrll 
9512a6b7db3Sskrll 	  /* Shouldn't happen! */
9522a6b7db3Sskrll 	default:
9532a6b7db3Sskrll 	  /* xgettext:c-format */
9542a6b7db3Sskrll 	  fatal (_("internal error -- this option not implemented"));
9552a6b7db3Sskrll 	}
9562a6b7db3Sskrll     }
9572a6b7db3Sskrll 
9582a6b7db3Sskrll   END_PROGRESS (program_name);
9592a6b7db3Sskrll 
9602a6b7db3Sskrll   xexit (0);
9612a6b7db3Sskrll   return 0;
9622a6b7db3Sskrll }
9632a6b7db3Sskrll 
9642a6b7db3Sskrll bfd *
open_inarch(const char * archive_filename,const char * file)9652a6b7db3Sskrll open_inarch (const char *archive_filename, const char *file)
9662a6b7db3Sskrll {
9672a6b7db3Sskrll   bfd **last_one;
9682a6b7db3Sskrll   bfd *next_one;
9692a6b7db3Sskrll   struct stat sbuf;
9702a6b7db3Sskrll   bfd *arch;
9712a6b7db3Sskrll   char **matching;
9722a6b7db3Sskrll 
9732a6b7db3Sskrll   bfd_set_error (bfd_error_no_error);
9742a6b7db3Sskrll 
9754c43201bSchristos   if (target == NULL)
9768443c5fcSchristos     target = plugin_target;
9772a6b7db3Sskrll 
9782a6b7db3Sskrll   if (stat (archive_filename, &sbuf) != 0)
9792a6b7db3Sskrll     {
9802a6b7db3Sskrll #if !defined(__GO32__) || defined(__DJGPP__)
9812a6b7db3Sskrll 
9822a6b7db3Sskrll       /* FIXME: I don't understand why this fragment was ifndef'ed
9832a6b7db3Sskrll 	 away for __GO32__; perhaps it was in the days of DJGPP v1.x.
9842a6b7db3Sskrll 	 stat() works just fine in v2.x, so I think this should be
9852a6b7db3Sskrll 	 removed.  For now, I enable it for DJGPP v2. -- EZ.  */
9862a6b7db3Sskrll 
9872a6b7db3Sskrll       /* KLUDGE ALERT! Temporary fix until I figger why
9882a6b7db3Sskrll 	 stat() is wrong ... think it's buried in GO32's IDT - Jax */
9892a6b7db3Sskrll       if (errno != ENOENT)
9902a6b7db3Sskrll 	bfd_fatal (archive_filename);
9912a6b7db3Sskrll #endif
9922a6b7db3Sskrll 
9932a6b7db3Sskrll       if (!operation_alters_arch)
9942a6b7db3Sskrll 	{
9952a6b7db3Sskrll 	  fprintf (stderr, "%s: ", program_name);
9962a6b7db3Sskrll 	  perror (archive_filename);
9972a6b7db3Sskrll 	  maybequit ();
9982a6b7db3Sskrll 	  return NULL;
9992a6b7db3Sskrll 	}
10002a6b7db3Sskrll 
10014c43201bSchristos       /* If the target isn't set, try to figure out the target to use
10024c43201bSchristos 	 for the archive from the first object on the list.  */
10034c43201bSchristos       if (target == NULL && file != NULL)
10042a6b7db3Sskrll 	{
10052a6b7db3Sskrll 	  bfd *obj;
10062a6b7db3Sskrll 
10078443c5fcSchristos 	  obj = bfd_openr (file, target);
10082a6b7db3Sskrll 	  if (obj != NULL)
10092a6b7db3Sskrll 	    {
10102a6b7db3Sskrll 	      if (bfd_check_format (obj, bfd_object))
10112a6b7db3Sskrll 		target = bfd_get_target (obj);
10122a6b7db3Sskrll 	      (void) bfd_close (obj);
10132a6b7db3Sskrll 	    }
10142a6b7db3Sskrll 	}
10152a6b7db3Sskrll 
10162a6b7db3Sskrll       /* Create an empty archive.  */
10172a6b7db3Sskrll       arch = bfd_openw (archive_filename, target);
10182a6b7db3Sskrll       if (arch == NULL
10192a6b7db3Sskrll 	  || ! bfd_set_format (arch, bfd_archive)
10202a6b7db3Sskrll 	  || ! bfd_close (arch))
10212a6b7db3Sskrll 	bfd_fatal (archive_filename);
10222a6b7db3Sskrll       else if (!silent_create)
10232a6b7db3Sskrll         non_fatal (_("creating %s"), archive_filename);
10242a6b7db3Sskrll 
10252a6b7db3Sskrll       /* If we die creating a new archive, don't leave it around.  */
10262a6b7db3Sskrll       output_filename = archive_filename;
10272a6b7db3Sskrll     }
10282a6b7db3Sskrll 
10292a6b7db3Sskrll   arch = bfd_openr (archive_filename, target);
10302a6b7db3Sskrll   if (arch == NULL)
10312a6b7db3Sskrll     {
10322a6b7db3Sskrll     bloser:
10332a6b7db3Sskrll       bfd_fatal (archive_filename);
10342a6b7db3Sskrll     }
10352a6b7db3Sskrll 
10362a6b7db3Sskrll   if (! bfd_check_format_matches (arch, bfd_archive, &matching))
10372a6b7db3Sskrll     {
10382a6b7db3Sskrll       bfd_nonfatal (archive_filename);
10392a6b7db3Sskrll       if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
10402a6b7db3Sskrll 	list_matching_formats (matching);
10412a6b7db3Sskrll       xexit (1);
10422a6b7db3Sskrll     }
10432a6b7db3Sskrll 
1044438aacb6Schristos   if ((operation == replace || operation == quick_append)
1045438aacb6Schristos       && bfd_openr_next_archived_file (arch, NULL) != NULL)
1046438aacb6Schristos     {
1047438aacb6Schristos       /* PR 15140: Catch attempts to convert a normal
1048438aacb6Schristos 	 archive into a thin archive or vice versa.  */
1049438aacb6Schristos       if (make_thin_archive && ! bfd_is_thin_archive (arch))
1050438aacb6Schristos 	{
1051438aacb6Schristos 	  fatal (_("Cannot convert existing library %s to thin format"),
1052438aacb6Schristos 		 bfd_get_filename (arch));
1053438aacb6Schristos 	  goto bloser;
1054438aacb6Schristos 	}
1055438aacb6Schristos       else if (! make_thin_archive && bfd_is_thin_archive (arch))
1056438aacb6Schristos 	{
1057438aacb6Schristos 	  fatal (_("Cannot convert existing thin library %s to normal format"),
1058438aacb6Schristos 		 bfd_get_filename (arch));
1059438aacb6Schristos 	  goto bloser;
1060438aacb6Schristos 	}
1061438aacb6Schristos     }
1062438aacb6Schristos 
10632a6b7db3Sskrll   last_one = &(arch->archive_next);
10642a6b7db3Sskrll   /* Read all the contents right away, regardless.  */
10652a6b7db3Sskrll   for (next_one = bfd_openr_next_archived_file (arch, NULL);
10662a6b7db3Sskrll        next_one;
10672a6b7db3Sskrll        next_one = bfd_openr_next_archived_file (arch, next_one))
10682a6b7db3Sskrll     {
10692a6b7db3Sskrll       PROGRESS (1);
10702a6b7db3Sskrll       *last_one = next_one;
10712a6b7db3Sskrll       last_one = &next_one->archive_next;
10722a6b7db3Sskrll     }
10732a6b7db3Sskrll   *last_one = (bfd *) NULL;
10742a6b7db3Sskrll   if (bfd_get_error () != bfd_error_no_more_archived_files)
10752a6b7db3Sskrll     goto bloser;
10762a6b7db3Sskrll   return arch;
10772a6b7db3Sskrll }
10782a6b7db3Sskrll 
10792a6b7db3Sskrll static void
print_contents(bfd * abfd)10802a6b7db3Sskrll print_contents (bfd *abfd)
10812a6b7db3Sskrll {
10824c43201bSchristos   bfd_size_type ncopied = 0;
10834c43201bSchristos   bfd_size_type size;
10848443c5fcSchristos   char *cbuf = (char *) xmalloc (BUFSIZE);
10852a6b7db3Sskrll   struct stat buf;
10864c43201bSchristos 
10872a6b7db3Sskrll   if (bfd_stat_arch_elt (abfd, &buf) != 0)
10882a6b7db3Sskrll     /* xgettext:c-format */
10892a6b7db3Sskrll     fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
10902a6b7db3Sskrll 
10912a6b7db3Sskrll   if (verbose)
10928443c5fcSchristos     printf ("\n<%s>\n\n", bfd_get_filename (abfd));
10932a6b7db3Sskrll 
10942a6b7db3Sskrll   bfd_seek (abfd, (file_ptr) 0, SEEK_SET);
10952a6b7db3Sskrll 
10962a6b7db3Sskrll   size = buf.st_size;
10972a6b7db3Sskrll   while (ncopied < size)
10982a6b7db3Sskrll     {
10994c43201bSchristos       bfd_size_type nread;
11004c43201bSchristos       bfd_size_type tocopy = size - ncopied;
11012a6b7db3Sskrll 
11022a6b7db3Sskrll       if (tocopy > BUFSIZE)
11032a6b7db3Sskrll 	tocopy = BUFSIZE;
11042a6b7db3Sskrll 
11054c43201bSchristos       nread = bfd_bread (cbuf, tocopy, abfd);
11062a6b7db3Sskrll       if (nread != tocopy)
11072a6b7db3Sskrll 	/* xgettext:c-format */
11082a6b7db3Sskrll 	fatal (_("%s is not a valid archive"),
1109ad93aa80Schristos 	       bfd_get_filename (abfd->my_archive));
11102a6b7db3Sskrll 
11114c43201bSchristos       /* fwrite in mingw32 may return int instead of bfd_size_type. Cast the
11124c43201bSchristos 	 return value to bfd_size_type to avoid comparison between signed and
11132a6b7db3Sskrll 	 unsigned values.  */
11144c43201bSchristos       if ((bfd_size_type) fwrite (cbuf, 1, nread, stdout) != nread)
11152a6b7db3Sskrll 	fatal ("stdout: %s", strerror (errno));
11162a6b7db3Sskrll       ncopied += tocopy;
11172a6b7db3Sskrll     }
11182a6b7db3Sskrll   free (cbuf);
11192a6b7db3Sskrll }
11202a6b7db3Sskrll 
1121c21fdd85Schristos 
1122c21fdd85Schristos static FILE * open_output_file (bfd *) ATTRIBUTE_RETURNS_NONNULL;
1123c21fdd85Schristos 
1124c21fdd85Schristos static FILE *
open_output_file(bfd * abfd)1125c21fdd85Schristos open_output_file (bfd * abfd)
1126c21fdd85Schristos {
1127c21fdd85Schristos   output_filename = bfd_get_filename (abfd);
1128c21fdd85Schristos 
1129c21fdd85Schristos   /* PR binutils/17533: Do not allow directory traversal
1130c21fdd85Schristos      outside of the current directory tree - unless the
1131c21fdd85Schristos      user has explicitly specified an output directory.  */
1132c21fdd85Schristos   if (! is_valid_archive_path (output_filename))
1133c21fdd85Schristos     {
1134c21fdd85Schristos       char * base = (char *) lbasename (output_filename);
1135c21fdd85Schristos 
1136c21fdd85Schristos       non_fatal (_("illegal output pathname for archive member: %s, using '%s' instead"),
1137c21fdd85Schristos 		 output_filename, base);
1138c21fdd85Schristos       output_filename = base;
1139c21fdd85Schristos     }
1140c21fdd85Schristos 
1141c21fdd85Schristos   if (output_dir)
1142c21fdd85Schristos     {
1143c21fdd85Schristos       size_t len = strlen (output_dir);
1144c21fdd85Schristos 
1145c21fdd85Schristos       if (len > 0)
1146c21fdd85Schristos 	{
1147c21fdd85Schristos 	  /* FIXME: There is a memory leak here, but it is not serious.  */
1148c21fdd85Schristos 	  if (IS_DIR_SEPARATOR (output_dir [len - 1]))
1149c21fdd85Schristos 	    output_filename = concat (output_dir, output_filename, NULL);
1150c21fdd85Schristos 	  else
1151c21fdd85Schristos 	    output_filename = concat (output_dir, "/", output_filename, NULL);
1152c21fdd85Schristos 	}
1153c21fdd85Schristos     }
1154c21fdd85Schristos 
1155c21fdd85Schristos   if (verbose)
1156c21fdd85Schristos     printf ("x - %s\n", output_filename);
1157c21fdd85Schristos 
1158c21fdd85Schristos   FILE * ostream = fopen (output_filename, FOPEN_WB);
1159c21fdd85Schristos   if (ostream == NULL)
1160c21fdd85Schristos     {
1161c21fdd85Schristos       perror (output_filename);
1162c21fdd85Schristos       xexit (1);
1163c21fdd85Schristos     }
1164c21fdd85Schristos 
1165c21fdd85Schristos   return ostream;
1166c21fdd85Schristos }
1167c21fdd85Schristos 
11682a6b7db3Sskrll /* Extract a member of the archive into its own file.
11692a6b7db3Sskrll 
11702a6b7db3Sskrll    We defer opening the new file until after we have read a BUFSIZ chunk of the
11712a6b7db3Sskrll    old one, since we know we have just read the archive header for the old
11722a6b7db3Sskrll    one.  Since most members are shorter than BUFSIZ, this means we will read
11732a6b7db3Sskrll    the old header, read the old data, write a new inode for the new file, and
11742a6b7db3Sskrll    write the new data, and be done. This 'optimization' is what comes from
11752a6b7db3Sskrll    sitting next to a bare disk and hearing it every time it seeks.  -- Gnu
11762a6b7db3Sskrll    Gilmore  */
11772a6b7db3Sskrll 
11782a6b7db3Sskrll void
extract_file(bfd * abfd)11792a6b7db3Sskrll extract_file (bfd *abfd)
11802a6b7db3Sskrll {
11814c43201bSchristos   bfd_size_type size;
11822a6b7db3Sskrll   struct stat buf;
11832a6b7db3Sskrll 
1184*e072ec67Schristos   if (preserve_dates)
1185*e072ec67Schristos     memset (&buf, 0, sizeof (buf));
1186*e072ec67Schristos 
11872a6b7db3Sskrll   if (bfd_stat_arch_elt (abfd, &buf) != 0)
11882a6b7db3Sskrll     /* xgettext:c-format */
11892a6b7db3Sskrll     fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
11902a6b7db3Sskrll   size = buf.st_size;
11912a6b7db3Sskrll 
11922a6b7db3Sskrll   bfd_seek (abfd, (file_ptr) 0, SEEK_SET);
11932a6b7db3Sskrll 
1194c21fdd85Schristos   output_file = NULL;
11952a6b7db3Sskrll   if (size == 0)
11962a6b7db3Sskrll     {
1197c21fdd85Schristos       output_file = open_output_file (abfd);
11982a6b7db3Sskrll     }
11992a6b7db3Sskrll   else
1200c21fdd85Schristos     {
1201c21fdd85Schristos       bfd_size_type ncopied = 0;
1202c21fdd85Schristos       char *cbuf = (char *) xmalloc (BUFSIZE);
1203c21fdd85Schristos 
12042a6b7db3Sskrll       while (ncopied < size)
12052a6b7db3Sskrll 	{
1206c21fdd85Schristos 	  bfd_size_type nread, tocopy;
1207c21fdd85Schristos 
12082a6b7db3Sskrll 	  tocopy = size - ncopied;
12092a6b7db3Sskrll 	  if (tocopy > BUFSIZE)
12102a6b7db3Sskrll 	    tocopy = BUFSIZE;
12112a6b7db3Sskrll 
12124c43201bSchristos 	  nread = bfd_bread (cbuf, tocopy, abfd);
12132a6b7db3Sskrll 	  if (nread != tocopy)
12142a6b7db3Sskrll 	    /* xgettext:c-format */
12152a6b7db3Sskrll 	    fatal (_("%s is not a valid archive"),
1216ad93aa80Schristos 		   bfd_get_filename (abfd->my_archive));
12172a6b7db3Sskrll 
1218c21fdd85Schristos 	  /* See comment above; this saves disk arm motion.  */
1219c21fdd85Schristos 	  if (output_file == NULL)
1220c21fdd85Schristos 	    output_file = open_output_file (abfd);
12212a6b7db3Sskrll 
12224c43201bSchristos 	  /* fwrite in mingw32 may return int instead of bfd_size_type. Cast
12234c43201bSchristos 	     the return value to bfd_size_type to avoid comparison between
12242a6b7db3Sskrll 	     signed and unsigned values.  */
1225c21fdd85Schristos 	  if ((bfd_size_type) fwrite (cbuf, 1, nread, output_file) != nread)
12262a6b7db3Sskrll 	    fatal ("%s: %s", output_filename, strerror (errno));
1227c21fdd85Schristos 
12282a6b7db3Sskrll 	  ncopied += tocopy;
12292a6b7db3Sskrll 	}
12302a6b7db3Sskrll 
1231c21fdd85Schristos       free (cbuf);
1232c21fdd85Schristos     }
1233c21fdd85Schristos 
1234c21fdd85Schristos   fclose (output_file);
12352a6b7db3Sskrll 
12362a6b7db3Sskrll   output_file = NULL;
12372a6b7db3Sskrll 
1238c21fdd85Schristos   chmod (output_filename, buf.st_mode);
12392a6b7db3Sskrll 
12402a6b7db3Sskrll   if (preserve_dates)
12412a6b7db3Sskrll     {
12422a6b7db3Sskrll       /* Set access time to modification time.  Only st_mtime is
12432a6b7db3Sskrll 	 initialized by bfd_stat_arch_elt.  */
12442a6b7db3Sskrll       buf.st_atime = buf.st_mtime;
1245c21fdd85Schristos       set_times (output_filename, &buf);
12462a6b7db3Sskrll     }
12472a6b7db3Sskrll 
1248c21fdd85Schristos   output_filename = NULL;
12492a6b7db3Sskrll }
12502a6b7db3Sskrll 
12512a6b7db3Sskrll static void
write_archive(bfd * iarch)12522a6b7db3Sskrll write_archive (bfd *iarch)
12532a6b7db3Sskrll {
12542a6b7db3Sskrll   bfd *obfd;
12552a6b7db3Sskrll   char *old_name, *new_name;
12562a6b7db3Sskrll   bfd *contents_head = iarch->archive_next;
1257*e072ec67Schristos   int tmpfd = -1;
12582a6b7db3Sskrll 
1259*e072ec67Schristos   old_name = xstrdup (bfd_get_filename (iarch));
1260*e072ec67Schristos   new_name = make_tempname (old_name, &tmpfd);
12612a6b7db3Sskrll 
12622a6b7db3Sskrll   if (new_name == NULL)
12634c43201bSchristos     bfd_fatal (_("could not create temporary file whilst writing archive"));
12642a6b7db3Sskrll 
12652a6b7db3Sskrll   output_filename = new_name;
12662a6b7db3Sskrll 
1267*e072ec67Schristos   obfd = bfd_fdopenw (new_name, bfd_get_target (iarch), tmpfd);
12682a6b7db3Sskrll 
12692a6b7db3Sskrll   if (obfd == NULL)
1270*e072ec67Schristos     {
1271*e072ec67Schristos       close (tmpfd);
12722a6b7db3Sskrll       bfd_fatal (old_name);
1273*e072ec67Schristos     }
12742a6b7db3Sskrll 
12752a6b7db3Sskrll   output_bfd = obfd;
12762a6b7db3Sskrll 
12772a6b7db3Sskrll   bfd_set_format (obfd, bfd_archive);
12782a6b7db3Sskrll 
12792a6b7db3Sskrll   /* Request writing the archive symbol table unless we've
12802a6b7db3Sskrll      been explicitly requested not to.  */
12812a6b7db3Sskrll   obfd->has_armap = write_armap >= 0;
12822a6b7db3Sskrll 
12832a6b7db3Sskrll   if (ar_truncate)
12842a6b7db3Sskrll     {
12852a6b7db3Sskrll       /* This should really use bfd_set_file_flags, but that rejects
12862a6b7db3Sskrll          archives.  */
12872a6b7db3Sskrll       obfd->flags |= BFD_TRADITIONAL_FORMAT;
12882a6b7db3Sskrll     }
12892a6b7db3Sskrll 
1290abf07352Sskrll   if (deterministic)
1291abf07352Sskrll     obfd->flags |= BFD_DETERMINISTIC_OUTPUT;
1292abf07352Sskrll 
1293c21fdd85Schristos   if (full_pathname)
1294c21fdd85Schristos     obfd->flags |= BFD_ARCHIVE_FULL_PATH;
1295c21fdd85Schristos 
12962a6b7db3Sskrll   if (make_thin_archive || bfd_is_thin_archive (iarch))
1297*e072ec67Schristos     bfd_set_thin_archive (obfd, true);
12982a6b7db3Sskrll 
12992a6b7db3Sskrll   if (!bfd_set_archive_head (obfd, contents_head))
13002a6b7db3Sskrll     bfd_fatal (old_name);
13012a6b7db3Sskrll 
1302*e072ec67Schristos   tmpfd = dup (tmpfd);
13032a6b7db3Sskrll   if (!bfd_close (obfd))
13042a6b7db3Sskrll     bfd_fatal (old_name);
13052a6b7db3Sskrll 
13062a6b7db3Sskrll   output_bfd = NULL;
13072a6b7db3Sskrll   output_filename = NULL;
13082a6b7db3Sskrll 
13092a6b7db3Sskrll   /* We don't care if this fails; we might be creating the archive.  */
13102a6b7db3Sskrll   bfd_close (iarch);
13112a6b7db3Sskrll 
1312*e072ec67Schristos   if (smart_rename (new_name, old_name, tmpfd, NULL, false) != 0)
13132a6b7db3Sskrll     xexit (1);
13144c43201bSchristos   free (old_name);
1315aa4b58b1Schristos   free (new_name);
13162a6b7db3Sskrll }
13172a6b7db3Sskrll 
13182a6b7db3Sskrll /* Return a pointer to the pointer to the entry which should be rplacd'd
13192a6b7db3Sskrll    into when altering.  DEFAULT_POS should be how to interpret pos_default,
13202a6b7db3Sskrll    and should be a pos value.  */
13212a6b7db3Sskrll 
13222a6b7db3Sskrll static bfd **
get_pos_bfd(bfd ** contents,enum pos default_pos,const char * default_posname)13232a6b7db3Sskrll get_pos_bfd (bfd **contents, enum pos default_pos, const char *default_posname)
13242a6b7db3Sskrll {
13252a6b7db3Sskrll   bfd **after_bfd = contents;
13262a6b7db3Sskrll   enum pos realpos;
13272a6b7db3Sskrll   const char *realposname;
13282a6b7db3Sskrll 
13292a6b7db3Sskrll   if (postype == pos_default)
13302a6b7db3Sskrll     {
13312a6b7db3Sskrll       realpos = default_pos;
13322a6b7db3Sskrll       realposname = default_posname;
13332a6b7db3Sskrll     }
13342a6b7db3Sskrll   else
13352a6b7db3Sskrll     {
13362a6b7db3Sskrll       realpos = postype;
13372a6b7db3Sskrll       realposname = posname;
13382a6b7db3Sskrll     }
13392a6b7db3Sskrll 
13402a6b7db3Sskrll   if (realpos == pos_end)
13412a6b7db3Sskrll     {
13422a6b7db3Sskrll       while (*after_bfd)
13432a6b7db3Sskrll 	after_bfd = &((*after_bfd)->archive_next);
13442a6b7db3Sskrll     }
13452a6b7db3Sskrll   else
13462a6b7db3Sskrll     {
13472a6b7db3Sskrll       for (; *after_bfd; after_bfd = &(*after_bfd)->archive_next)
1348*e072ec67Schristos 	if (FILENAME_CMP (bfd_get_filename (*after_bfd), realposname) == 0)
13492a6b7db3Sskrll 	  {
13502a6b7db3Sskrll 	    if (realpos == pos_after)
13512a6b7db3Sskrll 	      after_bfd = &(*after_bfd)->archive_next;
13522a6b7db3Sskrll 	    break;
13532a6b7db3Sskrll 	  }
13542a6b7db3Sskrll     }
13552a6b7db3Sskrll   return after_bfd;
13562a6b7db3Sskrll }
13572a6b7db3Sskrll 
13582a6b7db3Sskrll static void
delete_members(bfd * arch,char ** files_to_delete)13592a6b7db3Sskrll delete_members (bfd *arch, char **files_to_delete)
13602a6b7db3Sskrll {
13612a6b7db3Sskrll   bfd **current_ptr_ptr;
1362*e072ec67Schristos   bool found;
1363*e072ec67Schristos   bool something_changed = false;
13642a6b7db3Sskrll   int match_count;
13652a6b7db3Sskrll 
13662a6b7db3Sskrll   for (; *files_to_delete != NULL; ++files_to_delete)
13672a6b7db3Sskrll     {
13682a6b7db3Sskrll       /* In a.out systems, the armap is optional.  It's also called
13692a6b7db3Sskrll 	 __.SYMDEF.  So if the user asked to delete it, we should remember
13702a6b7db3Sskrll 	 that fact. This isn't quite right for COFF systems (where
13712a6b7db3Sskrll 	 __.SYMDEF might be regular member), but it's very unlikely
13722a6b7db3Sskrll 	 to be a problem.  FIXME */
13732a6b7db3Sskrll 
13742a6b7db3Sskrll       if (!strcmp (*files_to_delete, "__.SYMDEF"))
13752a6b7db3Sskrll 	{
1376*e072ec67Schristos 	  arch->has_armap = false;
13772a6b7db3Sskrll 	  write_armap = -1;
13782a6b7db3Sskrll 	  continue;
13792a6b7db3Sskrll 	}
13802a6b7db3Sskrll 
1381*e072ec67Schristos       found = false;
13822a6b7db3Sskrll       match_count = 0;
13832a6b7db3Sskrll       current_ptr_ptr = &(arch->archive_next);
13842a6b7db3Sskrll       while (*current_ptr_ptr)
13852a6b7db3Sskrll 	{
13862a6b7db3Sskrll 	  if (FILENAME_CMP (normalize (*files_to_delete, arch),
1387*e072ec67Schristos 			    bfd_get_filename (*current_ptr_ptr)) == 0)
13882a6b7db3Sskrll 	    {
13892a6b7db3Sskrll 	      ++match_count;
13902a6b7db3Sskrll 	      if (counted_name_mode
13912a6b7db3Sskrll 		  && match_count != counted_name_counter)
13922a6b7db3Sskrll 		{
13932a6b7db3Sskrll 		  /* Counting, and didn't match on count; go on to the
13942a6b7db3Sskrll                      next one.  */
13952a6b7db3Sskrll 		}
13962a6b7db3Sskrll 	      else
13972a6b7db3Sskrll 		{
1398*e072ec67Schristos 		  found = true;
1399*e072ec67Schristos 		  something_changed = true;
14002a6b7db3Sskrll 		  if (verbose)
14012a6b7db3Sskrll 		    printf ("d - %s\n",
14022a6b7db3Sskrll 			    *files_to_delete);
14032a6b7db3Sskrll 		  *current_ptr_ptr = ((*current_ptr_ptr)->archive_next);
14042a6b7db3Sskrll 		  goto next_file;
14052a6b7db3Sskrll 		}
14062a6b7db3Sskrll 	    }
14072a6b7db3Sskrll 
14082a6b7db3Sskrll 	  current_ptr_ptr = &((*current_ptr_ptr)->archive_next);
14092a6b7db3Sskrll 	}
14102a6b7db3Sskrll 
14112a6b7db3Sskrll       if (verbose && !found)
14122a6b7db3Sskrll 	{
14132a6b7db3Sskrll 	  /* xgettext:c-format */
14142a6b7db3Sskrll 	  printf (_("No member named `%s'\n"), *files_to_delete);
14152a6b7db3Sskrll 	}
14162a6b7db3Sskrll     next_file:
14172a6b7db3Sskrll       ;
14182a6b7db3Sskrll     }
14192a6b7db3Sskrll 
14202a6b7db3Sskrll   if (something_changed)
14212a6b7db3Sskrll     write_archive (arch);
14222a6b7db3Sskrll   else
14232a6b7db3Sskrll     output_filename = NULL;
14242a6b7db3Sskrll }
14252a6b7db3Sskrll 
14262a6b7db3Sskrll 
14272a6b7db3Sskrll /* Reposition existing members within an archive */
14282a6b7db3Sskrll 
14292a6b7db3Sskrll static void
move_members(bfd * arch,char ** files_to_move)14302a6b7db3Sskrll move_members (bfd *arch, char **files_to_move)
14312a6b7db3Sskrll {
14322a6b7db3Sskrll   bfd **after_bfd;		/* New entries go after this one */
14332a6b7db3Sskrll   bfd **current_ptr_ptr;	/* cdr pointer into contents */
14342a6b7db3Sskrll 
14352a6b7db3Sskrll   for (; *files_to_move; ++files_to_move)
14362a6b7db3Sskrll     {
14372a6b7db3Sskrll       current_ptr_ptr = &(arch->archive_next);
14382a6b7db3Sskrll       while (*current_ptr_ptr)
14392a6b7db3Sskrll 	{
14402a6b7db3Sskrll 	  bfd *current_ptr = *current_ptr_ptr;
14412a6b7db3Sskrll 	  if (FILENAME_CMP (normalize (*files_to_move, arch),
1442*e072ec67Schristos 			    bfd_get_filename (current_ptr)) == 0)
14432a6b7db3Sskrll 	    {
14442a6b7db3Sskrll 	      /* Move this file to the end of the list - first cut from
14452a6b7db3Sskrll 		 where it is.  */
14468443c5fcSchristos 	      bfd *link_bfd;
14472a6b7db3Sskrll 	      *current_ptr_ptr = current_ptr->archive_next;
14482a6b7db3Sskrll 
14492a6b7db3Sskrll 	      /* Now glue to end */
14502a6b7db3Sskrll 	      after_bfd = get_pos_bfd (&arch->archive_next, pos_end, NULL);
14518443c5fcSchristos 	      link_bfd = *after_bfd;
14522a6b7db3Sskrll 	      *after_bfd = current_ptr;
14538443c5fcSchristos 	      current_ptr->archive_next = link_bfd;
14542a6b7db3Sskrll 
14552a6b7db3Sskrll 	      if (verbose)
14562a6b7db3Sskrll 		printf ("m - %s\n", *files_to_move);
14572a6b7db3Sskrll 
14582a6b7db3Sskrll 	      goto next_file;
14592a6b7db3Sskrll 	    }
14602a6b7db3Sskrll 
14612a6b7db3Sskrll 	  current_ptr_ptr = &((*current_ptr_ptr)->archive_next);
14622a6b7db3Sskrll 	}
14632a6b7db3Sskrll       /* xgettext:c-format */
1464*e072ec67Schristos       fatal (_("no entry %s in archive %s!"), *files_to_move,
1465*e072ec67Schristos 	     bfd_get_filename (arch));
14662a6b7db3Sskrll 
14672a6b7db3Sskrll     next_file:;
14682a6b7db3Sskrll     }
14692a6b7db3Sskrll 
14702a6b7db3Sskrll   write_archive (arch);
14712a6b7db3Sskrll }
14722a6b7db3Sskrll 
14732a6b7db3Sskrll /* Ought to default to replacing in place, but this is existing practice!  */
14742a6b7db3Sskrll 
14752a6b7db3Sskrll static void
replace_members(bfd * arch,char ** files_to_move,bool quick)1476*e072ec67Schristos replace_members (bfd *arch, char **files_to_move, bool quick)
14772a6b7db3Sskrll {
1478*e072ec67Schristos   bool changed = false;
14792a6b7db3Sskrll   bfd **after_bfd;		/* New entries go after this one.  */
14802a6b7db3Sskrll   bfd *current;
14812a6b7db3Sskrll   bfd **current_ptr;
14822a6b7db3Sskrll 
14832a6b7db3Sskrll   while (files_to_move && *files_to_move)
14842a6b7db3Sskrll     {
14852a6b7db3Sskrll       if (! quick)
14862a6b7db3Sskrll 	{
14872a6b7db3Sskrll 	  current_ptr = &arch->archive_next;
14882a6b7db3Sskrll 	  while (*current_ptr)
14892a6b7db3Sskrll 	    {
14902a6b7db3Sskrll 	      current = *current_ptr;
14912a6b7db3Sskrll 
14922a6b7db3Sskrll 	      /* For compatibility with existing ar programs, we
14932a6b7db3Sskrll 		 permit the same file to be added multiple times.  */
14942a6b7db3Sskrll 	      if (FILENAME_CMP (normalize (*files_to_move, arch),
1495*e072ec67Schristos 				normalize (bfd_get_filename (current), arch)) == 0
14962a6b7db3Sskrll 		  && current->arelt_data != NULL)
14972a6b7db3Sskrll 		{
1498*e072ec67Schristos 		  bool replaced;
14992a6b7db3Sskrll 		  if (newer_only)
15002a6b7db3Sskrll 		    {
15012a6b7db3Sskrll 		      struct stat fsbuf, asbuf;
15022a6b7db3Sskrll 
15032a6b7db3Sskrll 		      if (stat (*files_to_move, &fsbuf) != 0)
15042a6b7db3Sskrll 			{
15052a6b7db3Sskrll 			  if (errno != ENOENT)
15062a6b7db3Sskrll 			    bfd_fatal (*files_to_move);
15072a6b7db3Sskrll 			  goto next_file;
15082a6b7db3Sskrll 			}
15092a6b7db3Sskrll 		      if (bfd_stat_arch_elt (current, &asbuf) != 0)
15102a6b7db3Sskrll 			/* xgettext:c-format */
15112a6b7db3Sskrll 			fatal (_("internal stat error on %s"),
1512*e072ec67Schristos 			       bfd_get_filename (current));
15132a6b7db3Sskrll 
15142a6b7db3Sskrll 		      if (fsbuf.st_mtime <= asbuf.st_mtime)
15152a6b7db3Sskrll 			goto next_file;
15162a6b7db3Sskrll 		    }
15172a6b7db3Sskrll 
15182a6b7db3Sskrll 		  after_bfd = get_pos_bfd (&arch->archive_next, pos_after,
1519*e072ec67Schristos 					   bfd_get_filename (current));
1520*e072ec67Schristos 		  if (libdeps_bfd != NULL
1521*e072ec67Schristos 		      && FILENAME_CMP (normalize (*files_to_move, arch),
1522*e072ec67Schristos 				       LIBDEPS) == 0)
1523*e072ec67Schristos 		    {
1524*e072ec67Schristos 		      replaced = ar_emul_replace_bfd (after_bfd, libdeps_bfd,
1525*e072ec67Schristos 						      verbose);
1526*e072ec67Schristos 		    }
1527*e072ec67Schristos 		  else
1528*e072ec67Schristos 		    {
1529*e072ec67Schristos 		      replaced = ar_emul_replace (after_bfd, *files_to_move,
1530*e072ec67Schristos 						  target, verbose);
1531*e072ec67Schristos 		    }
1532*e072ec67Schristos 		  if (replaced)
15332a6b7db3Sskrll 		    {
15342a6b7db3Sskrll 		      /* Snip out this entry from the chain.  */
15352a6b7db3Sskrll 		      *current_ptr = (*current_ptr)->archive_next;
1536*e072ec67Schristos 		      changed = true;
15372a6b7db3Sskrll 		    }
15382a6b7db3Sskrll 
15392a6b7db3Sskrll 		  goto next_file;
15402a6b7db3Sskrll 		}
15412a6b7db3Sskrll 	      current_ptr = &(current->archive_next);
15422a6b7db3Sskrll 	    }
15432a6b7db3Sskrll 	}
15442a6b7db3Sskrll 
15452a6b7db3Sskrll       /* Add to the end of the archive.  */
15462a6b7db3Sskrll       after_bfd = get_pos_bfd (&arch->archive_next, pos_end, NULL);
15472a6b7db3Sskrll 
1548*e072ec67Schristos       if (libdeps_bfd != NULL
1549*e072ec67Schristos 	  && FILENAME_CMP (normalize (*files_to_move, arch), LIBDEPS) == 0)
1550*e072ec67Schristos         {
1551*e072ec67Schristos 	  changed |= ar_emul_append_bfd (after_bfd, libdeps_bfd,
1552*e072ec67Schristos 					 verbose, make_thin_archive);
1553*e072ec67Schristos 	}
1554*e072ec67Schristos       else
1555*e072ec67Schristos         {
1556*e072ec67Schristos 	  changed |= ar_emul_append (after_bfd, *files_to_move, target,
1557*e072ec67Schristos 				     verbose, make_thin_archive);
1558*e072ec67Schristos 	}
15592a6b7db3Sskrll 
15602a6b7db3Sskrll     next_file:;
15612a6b7db3Sskrll 
15622a6b7db3Sskrll       files_to_move++;
15632a6b7db3Sskrll     }
15642a6b7db3Sskrll 
15652a6b7db3Sskrll   if (changed)
15662a6b7db3Sskrll     write_archive (arch);
15672a6b7db3Sskrll   else
15682a6b7db3Sskrll     output_filename = NULL;
15692a6b7db3Sskrll }
15702a6b7db3Sskrll 
15712a6b7db3Sskrll static int
ranlib_only(const char * archname)15722a6b7db3Sskrll ranlib_only (const char *archname)
15732a6b7db3Sskrll {
15742a6b7db3Sskrll   bfd *arch;
15752a6b7db3Sskrll 
15762a6b7db3Sskrll   if (get_file_size (archname) < 1)
15772a6b7db3Sskrll     return 1;
15782a6b7db3Sskrll   write_armap = 1;
15792a6b7db3Sskrll   arch = open_inarch (archname, (char *) NULL);
15802a6b7db3Sskrll   if (arch == NULL)
15812a6b7db3Sskrll     xexit (1);
15822a6b7db3Sskrll   write_archive (arch);
15832a6b7db3Sskrll   return 0;
15842a6b7db3Sskrll }
15852a6b7db3Sskrll 
15862a6b7db3Sskrll /* Update the timestamp of the symbol map of an archive.  */
15872a6b7db3Sskrll 
15882a6b7db3Sskrll static int
ranlib_touch(const char * archname)15892a6b7db3Sskrll ranlib_touch (const char *archname)
15902a6b7db3Sskrll {
15912a6b7db3Sskrll #ifdef __GO32__
15922a6b7db3Sskrll   /* I don't think updating works on go32.  */
15932a6b7db3Sskrll   ranlib_only (archname);
15942a6b7db3Sskrll #else
15952a6b7db3Sskrll   int f;
15962a6b7db3Sskrll   bfd *arch;
15972a6b7db3Sskrll   char **matching;
15982a6b7db3Sskrll 
15992a6b7db3Sskrll   if (get_file_size (archname) < 1)
16002a6b7db3Sskrll     return 1;
16012a6b7db3Sskrll   f = open (archname, O_RDWR | O_BINARY, 0);
16022a6b7db3Sskrll   if (f < 0)
16032a6b7db3Sskrll     {
16042a6b7db3Sskrll       bfd_set_error (bfd_error_system_call);
16052a6b7db3Sskrll       bfd_fatal (archname);
16062a6b7db3Sskrll     }
16072a6b7db3Sskrll 
16082a6b7db3Sskrll   arch = bfd_fdopenr (archname, (const char *) NULL, f);
16092a6b7db3Sskrll   if (arch == NULL)
16102a6b7db3Sskrll     bfd_fatal (archname);
16112a6b7db3Sskrll   if (! bfd_check_format_matches (arch, bfd_archive, &matching))
16122a6b7db3Sskrll     {
16132a6b7db3Sskrll       bfd_nonfatal (archname);
16142a6b7db3Sskrll       if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
16152a6b7db3Sskrll 	list_matching_formats (matching);
16162a6b7db3Sskrll       xexit (1);
16172a6b7db3Sskrll     }
16182a6b7db3Sskrll 
16192a6b7db3Sskrll   if (! bfd_has_map (arch))
16202a6b7db3Sskrll     /* xgettext:c-format */
16212a6b7db3Sskrll     fatal (_("%s: no archive map to update"), archname);
16222a6b7db3Sskrll 
16234c43201bSchristos   if (deterministic)
16244c43201bSchristos     arch->flags |= BFD_DETERMINISTIC_OUTPUT;
16254c43201bSchristos 
16262a6b7db3Sskrll   bfd_update_armap_timestamp (arch);
16272a6b7db3Sskrll 
16282a6b7db3Sskrll   if (! bfd_close (arch))
16292a6b7db3Sskrll     bfd_fatal (archname);
16302a6b7db3Sskrll #endif
16312a6b7db3Sskrll   return 0;
16322a6b7db3Sskrll }
16332a6b7db3Sskrll 
16342a6b7db3Sskrll /* Things which are interesting to map over all or some of the files: */
16352a6b7db3Sskrll 
16362a6b7db3Sskrll static void
print_descr(bfd * abfd)16372a6b7db3Sskrll print_descr (bfd *abfd)
16382a6b7db3Sskrll {
1639916041edSchristos   print_arelt_descr (stdout, abfd, verbose, display_offsets);
16402a6b7db3Sskrll }
1641