1ed0d50c3Schristos /* ar.c - Archive modify and extract.
2*b88e3e88Schristos    Copyright (C) 1991-2020 Free Software Foundation, Inc.
3ed0d50c3Schristos 
4ed0d50c3Schristos    This file is part of GNU Binutils.
5ed0d50c3Schristos 
6ed0d50c3Schristos    This program is free software; you can redistribute it and/or modify
7ed0d50c3Schristos    it under the terms of the GNU General Public License as published by
8ed0d50c3Schristos    the Free Software Foundation; either version 3 of the License, or
9ed0d50c3Schristos    (at your option) any later version.
10ed0d50c3Schristos 
11ed0d50c3Schristos    This program is distributed in the hope that it will be useful,
12ed0d50c3Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
13ed0d50c3Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14ed0d50c3Schristos    GNU General Public License for more details.
15ed0d50c3Schristos 
16ed0d50c3Schristos    You should have received a copy of the GNU General Public License
17ed0d50c3Schristos    along with this program; if not, write to the Free Software
18ed0d50c3Schristos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19ed0d50c3Schristos    MA 02110-1301, USA.  */
20ed0d50c3Schristos 
21ed0d50c3Schristos /*
22ed0d50c3Schristos    Bugs: GNU ar used to check file against filesystem in quick_update and
23ed0d50c3Schristos    replace operations (would check mtime). Doesn't warn when name truncated.
24ed0d50c3Schristos    No way to specify pos_end. Error messages should be more consistent.  */
25ed0d50c3Schristos 
26ed0d50c3Schristos #include "sysdep.h"
27ed0d50c3Schristos #include "bfd.h"
28ed0d50c3Schristos #include "libiberty.h"
29ed0d50c3Schristos #include "progress.h"
30ed0d50c3Schristos #include "getopt.h"
31ed0d50c3Schristos #include "aout/ar.h"
32ed0d50c3Schristos #include "bucomm.h"
33ed0d50c3Schristos #include "arsup.h"
34ed0d50c3Schristos #include "filenames.h"
35ed0d50c3Schristos #include "binemul.h"
3606324dcfSchristos #include "plugin-api.h"
37ed0d50c3Schristos #include "plugin.h"
38*b88e3e88Schristos #include "ansidecl.h"
39ed0d50c3Schristos 
40ed0d50c3Schristos #ifdef __GO32___
41ed0d50c3Schristos #define EXT_NAME_LEN 3		/* Bufflen of addition to name if it's MS-DOS.  */
42ed0d50c3Schristos #else
43ed0d50c3Schristos #define EXT_NAME_LEN 6		/* Ditto for *NIX.  */
44ed0d50c3Schristos #endif
45ed0d50c3Schristos 
46ed0d50c3Schristos /* Static declarations.  */
47ed0d50c3Schristos 
48ed0d50c3Schristos static void mri_emul (void);
49ed0d50c3Schristos static const char *normalize (const char *, bfd *);
50ed0d50c3Schristos static void remove_output (void);
51ed0d50c3Schristos static void map_over_members (bfd *, void (*)(bfd *), char **, int);
52ed0d50c3Schristos static void print_contents (bfd * member);
53ed0d50c3Schristos static void delete_members (bfd *, char **files_to_delete);
54ed0d50c3Schristos 
55ed0d50c3Schristos static void move_members (bfd *, char **files_to_move);
56ed0d50c3Schristos static void replace_members
57ed0d50c3Schristos   (bfd *, char **files_to_replace, bfd_boolean quick);
58ed0d50c3Schristos static void print_descr (bfd * abfd);
59ed0d50c3Schristos static void write_archive (bfd *);
60ed0d50c3Schristos static int  ranlib_only (const char *archname);
61ed0d50c3Schristos static int  ranlib_touch (const char *archname);
62ed0d50c3Schristos static void usage (int);
63ed0d50c3Schristos 
64ed0d50c3Schristos /** Globals and flags.  */
65ed0d50c3Schristos 
66ed0d50c3Schristos static int mri_mode;
67ed0d50c3Schristos 
68ed0d50c3Schristos /* This flag distinguishes between ar and ranlib:
69ed0d50c3Schristos    1 means this is 'ranlib'; 0 means this is 'ar'.
70ed0d50c3Schristos    -1 means if we should use argv[0] to decide.  */
71ed0d50c3Schristos extern int is_ranlib;
72ed0d50c3Schristos 
73ed0d50c3Schristos /* Nonzero means don't warn about creating the archive file if necessary.  */
74ed0d50c3Schristos int silent_create = 0;
75ed0d50c3Schristos 
76ed0d50c3Schristos /* Nonzero means describe each action performed.  */
77ed0d50c3Schristos int verbose = 0;
78ed0d50c3Schristos 
7906324dcfSchristos /* Nonzero means display offsets of files in the archive.  */
8006324dcfSchristos int display_offsets = 0;
8106324dcfSchristos 
82ed0d50c3Schristos /* Nonzero means preserve dates of members when extracting them.  */
83ed0d50c3Schristos int preserve_dates = 0;
84ed0d50c3Schristos 
85ed0d50c3Schristos /* Nonzero means don't replace existing members whose dates are more recent
86ed0d50c3Schristos    than the corresponding files.  */
87ed0d50c3Schristos int newer_only = 0;
88ed0d50c3Schristos 
89ed0d50c3Schristos /* Controls the writing of an archive symbol table (in BSD: a __.SYMDEF
90ed0d50c3Schristos    member).  -1 means we've been explicitly asked to not write a symbol table;
91ed0d50c3Schristos    +1 means we've been explicitly asked to write it;
92ed0d50c3Schristos    0 is the default.
93ed0d50c3Schristos    Traditionally, the default in BSD has been to not write the table.
94ed0d50c3Schristos    However, for POSIX.2 compliance the default is now to write a symbol table
95ed0d50c3Schristos    if any of the members are object files.  */
96ed0d50c3Schristos int write_armap = 0;
97ed0d50c3Schristos 
98ed0d50c3Schristos /* Operate in deterministic mode: write zero for timestamps, uids,
99ed0d50c3Schristos    and gids for archive members and the archive symbol table, and write
100ed0d50c3Schristos    consistent file modes.  */
101ed0d50c3Schristos int deterministic = -1;			/* Determinism indeterminate.  */
102ed0d50c3Schristos 
103ed0d50c3Schristos /* Nonzero means it's the name of an existing member; position new or moved
104ed0d50c3Schristos    files with respect to this one.  */
105ed0d50c3Schristos char *posname = NULL;
106ed0d50c3Schristos 
107ed0d50c3Schristos /* Sez how to use `posname': pos_before means position before that member.
108ed0d50c3Schristos    pos_after means position after that member. pos_end means always at end.
109ed0d50c3Schristos    pos_default means default appropriately. For the latter two, `posname'
110ed0d50c3Schristos    should also be zero.  */
111ed0d50c3Schristos enum pos
112ed0d50c3Schristos   {
113ed0d50c3Schristos     pos_default, pos_before, pos_after, pos_end
114ed0d50c3Schristos   } postype = pos_default;
115ed0d50c3Schristos 
116ed0d50c3Schristos enum operations
117ed0d50c3Schristos   {
118ed0d50c3Schristos     none = 0, del, replace, print_table,
119ed0d50c3Schristos     print_files, extract, move, quick_append
120ed0d50c3Schristos   } operation = none;
121ed0d50c3Schristos 
122ed0d50c3Schristos static bfd **
123ed0d50c3Schristos get_pos_bfd (bfd **, enum pos, const char *);
124ed0d50c3Schristos 
125ed0d50c3Schristos /* For extract/delete only.  If COUNTED_NAME_MODE is TRUE, we only
126ed0d50c3Schristos    extract the COUNTED_NAME_COUNTER instance of that name.  */
127ed0d50c3Schristos static bfd_boolean counted_name_mode = 0;
128ed0d50c3Schristos static int counted_name_counter = 0;
129ed0d50c3Schristos 
130ed0d50c3Schristos /* Whether to truncate names of files stored in the archive.  */
131ed0d50c3Schristos static bfd_boolean ar_truncate = FALSE;
132ed0d50c3Schristos 
133ed0d50c3Schristos /* Whether to use a full file name match when searching an archive.
134ed0d50c3Schristos    This is convenient for archives created by the Microsoft lib
135ed0d50c3Schristos    program.  */
136ed0d50c3Schristos static bfd_boolean full_pathname = FALSE;
137ed0d50c3Schristos 
138ed0d50c3Schristos /* Whether to create a "thin" archive (symbol index only -- no files).  */
139ed0d50c3Schristos static bfd_boolean make_thin_archive = FALSE;
140ed0d50c3Schristos 
141ed0d50c3Schristos static int show_version = 0;
142ed0d50c3Schristos 
143ed0d50c3Schristos static int show_help = 0;
144ed0d50c3Schristos 
145ed0d50c3Schristos #if BFD_SUPPORTS_PLUGINS
146ed0d50c3Schristos static const char *plugin_target = "plugin";
147ed0d50c3Schristos #else
148ed0d50c3Schristos static const char *plugin_target = NULL;
149ed0d50c3Schristos #endif
150ed0d50c3Schristos 
151ed0d50c3Schristos static const char *target = NULL;
152ed0d50c3Schristos 
153*b88e3e88Schristos enum long_option_numbers
154*b88e3e88Schristos {
155*b88e3e88Schristos   OPTION_PLUGIN = 201,
156*b88e3e88Schristos   OPTION_TARGET,
157*b88e3e88Schristos   OPTION_OUTPUT
158*b88e3e88Schristos };
159*b88e3e88Schristos 
160*b88e3e88Schristos static const char * output_dir = NULL;
161ed0d50c3Schristos 
162ed0d50c3Schristos static struct option long_options[] =
163ed0d50c3Schristos {
164ed0d50c3Schristos   {"help", no_argument, &show_help, 1},
165ed0d50c3Schristos   {"plugin", required_argument, NULL, OPTION_PLUGIN},
166ed0d50c3Schristos   {"target", required_argument, NULL, OPTION_TARGET},
167ed0d50c3Schristos   {"version", no_argument, &show_version, 1},
168*b88e3e88Schristos   {"output", required_argument, NULL, OPTION_OUTPUT},
169ed0d50c3Schristos   {NULL, no_argument, NULL, 0}
170ed0d50c3Schristos };
171ed0d50c3Schristos 
172ed0d50c3Schristos int interactive = 0;
173ed0d50c3Schristos 
174ed0d50c3Schristos static void
mri_emul(void)175ed0d50c3Schristos mri_emul (void)
176ed0d50c3Schristos {
177ed0d50c3Schristos   interactive = isatty (fileno (stdin));
178ed0d50c3Schristos   yyparse ();
179ed0d50c3Schristos }
180ed0d50c3Schristos 
181ed0d50c3Schristos /* If COUNT is 0, then FUNCTION is called once on each entry.  If nonzero,
182ed0d50c3Schristos    COUNT is the length of the FILES chain; FUNCTION is called on each entry
183ed0d50c3Schristos    whose name matches one in FILES.  */
184ed0d50c3Schristos 
185ed0d50c3Schristos static void
map_over_members(bfd * arch,void (* function)(bfd *),char ** files,int count)186ed0d50c3Schristos map_over_members (bfd *arch, void (*function)(bfd *), char **files, int count)
187ed0d50c3Schristos {
188ed0d50c3Schristos   bfd *head;
189ed0d50c3Schristos   int match_count;
190ed0d50c3Schristos 
191ed0d50c3Schristos   if (count == 0)
192ed0d50c3Schristos     {
193ed0d50c3Schristos       for (head = arch->archive_next; head; head = head->archive_next)
194ed0d50c3Schristos 	{
195ed0d50c3Schristos 	  PROGRESS (1);
196ed0d50c3Schristos 	  function (head);
197ed0d50c3Schristos 	}
198ed0d50c3Schristos       return;
199ed0d50c3Schristos     }
200ed0d50c3Schristos 
201ed0d50c3Schristos   /* This may appear to be a baroque way of accomplishing what we want.
202ed0d50c3Schristos      However we have to iterate over the filenames in order to notice where
203ed0d50c3Schristos      a filename is requested but does not exist in the archive.  Ditto
204ed0d50c3Schristos      mapping over each file each time -- we want to hack multiple
205ed0d50c3Schristos      references.  */
206ed0d50c3Schristos 
207ed0d50c3Schristos   for (head = arch->archive_next; head; head = head->archive_next)
208ed0d50c3Schristos     head->archive_pass = 0;
209ed0d50c3Schristos 
210ed0d50c3Schristos   for (; count > 0; files++, count--)
211ed0d50c3Schristos     {
212ed0d50c3Schristos       bfd_boolean found = FALSE;
213ed0d50c3Schristos 
214ed0d50c3Schristos       match_count = 0;
215ed0d50c3Schristos       for (head = arch->archive_next; head; head = head->archive_next)
216ed0d50c3Schristos 	{
217ed0d50c3Schristos 	  const char * filename;
218ed0d50c3Schristos 
219ed0d50c3Schristos 	  PROGRESS (1);
220ed0d50c3Schristos 	  /* PR binutils/15796: Once an archive element has been matched
221ed0d50c3Schristos 	     do not match it again.  If the user provides multiple same-named
222ed0d50c3Schristos 	     parameters on the command line their intent is to match multiple
223ed0d50c3Schristos 	     same-named entries in the archive, not the same entry multiple
224ed0d50c3Schristos 	     times.  */
225ed0d50c3Schristos 	  if (head->archive_pass)
226ed0d50c3Schristos 	    continue;
227ed0d50c3Schristos 
228ed0d50c3Schristos 	  filename = head->filename;
229ed0d50c3Schristos 	  if (filename == NULL)
230ed0d50c3Schristos 	    {
231ed0d50c3Schristos 	      /* Some archive formats don't get the filenames filled in
232ed0d50c3Schristos 		 until the elements are opened.  */
233ed0d50c3Schristos 	      struct stat buf;
234ed0d50c3Schristos 	      bfd_stat_arch_elt (head, &buf);
235ed0d50c3Schristos 	    }
236ed0d50c3Schristos 	  else if (bfd_is_thin_archive (arch))
237ed0d50c3Schristos 	    {
238ed0d50c3Schristos 	      /* Thin archives store full pathnames.  Need to normalize.  */
239ed0d50c3Schristos 	      filename = normalize (filename, arch);
240ed0d50c3Schristos 	    }
241ed0d50c3Schristos 
242ed0d50c3Schristos 	  if (filename != NULL
243ed0d50c3Schristos 	      && !FILENAME_CMP (normalize (*files, arch), filename))
244ed0d50c3Schristos 	    {
245ed0d50c3Schristos 	      ++match_count;
246ed0d50c3Schristos 	      if (counted_name_mode
247ed0d50c3Schristos 		  && match_count != counted_name_counter)
248ed0d50c3Schristos 		{
249ed0d50c3Schristos 		  /* Counting, and didn't match on count; go on to the
250ed0d50c3Schristos                      next one.  */
251ed0d50c3Schristos 		  continue;
252ed0d50c3Schristos 		}
253ed0d50c3Schristos 
254ed0d50c3Schristos 	      found = TRUE;
255ed0d50c3Schristos 	      function (head);
256ed0d50c3Schristos 	      head->archive_pass = 1;
257ed0d50c3Schristos 	      /* PR binutils/15796: Once a file has been matched, do not
258ed0d50c3Schristos 		 match any more same-named files in the archive.  If the
259ed0d50c3Schristos 		 user does want to match multiple same-name files in an
260ed0d50c3Schristos 		 archive they should provide multiple same-name parameters
261ed0d50c3Schristos 		 to the ar command.  */
262ed0d50c3Schristos 	      break;
263ed0d50c3Schristos 	    }
264ed0d50c3Schristos 	}
265ed0d50c3Schristos 
266ed0d50c3Schristos       if (!found)
267ed0d50c3Schristos 	/* xgettext:c-format */
268ed0d50c3Schristos 	fprintf (stderr, _("no entry %s in archive\n"), *files);
269ed0d50c3Schristos     }
270ed0d50c3Schristos }
271ed0d50c3Schristos 
272ed0d50c3Schristos bfd_boolean operation_alters_arch = FALSE;
273ed0d50c3Schristos 
274ed0d50c3Schristos static void
usage(int help)275ed0d50c3Schristos usage (int help)
276ed0d50c3Schristos {
277ed0d50c3Schristos   FILE *s;
278ed0d50c3Schristos 
279ed0d50c3Schristos #if BFD_SUPPORTS_PLUGINS
280ed0d50c3Schristos   /* xgettext:c-format */
281ed0d50c3Schristos   const char *command_line
28206324dcfSchristos     = _("Usage: %s [emulation options] [-]{dmpqrstx}[abcDfilMNoOPsSTuvV]"
283ed0d50c3Schristos 	" [--plugin <name>] [member-name] [count] archive-file file...\n");
284ed0d50c3Schristos 
285ed0d50c3Schristos #else
286ed0d50c3Schristos   /* xgettext:c-format */
287ed0d50c3Schristos   const char *command_line
28806324dcfSchristos     = _("Usage: %s [emulation options] [-]{dmpqrstx}[abcDfilMNoOPsSTuvV]"
289ed0d50c3Schristos 	" [member-name] [count] archive-file file...\n");
290ed0d50c3Schristos #endif
291ed0d50c3Schristos   s = help ? stdout : stderr;
292ed0d50c3Schristos 
293ed0d50c3Schristos   fprintf (s, command_line, program_name);
294ed0d50c3Schristos 
295ed0d50c3Schristos   /* xgettext:c-format */
296ed0d50c3Schristos   fprintf (s, _("       %s -M [<mri-script]\n"), program_name);
297ed0d50c3Schristos   fprintf (s, _(" commands:\n"));
298ed0d50c3Schristos   fprintf (s, _("  d            - delete file(s) from the archive\n"));
299ed0d50c3Schristos   fprintf (s, _("  m[ab]        - move file(s) in the archive\n"));
300ed0d50c3Schristos   fprintf (s, _("  p            - print file(s) found in the archive\n"));
301ed0d50c3Schristos   fprintf (s, _("  q[f]         - quick append file(s) to the archive\n"));
302ed0d50c3Schristos   fprintf (s, _("  r[ab][f][u]  - replace existing or insert new file(s) into the archive\n"));
303ed0d50c3Schristos   fprintf (s, _("  s            - act as ranlib\n"));
30406324dcfSchristos   fprintf (s, _("  t[O][v]      - display contents of the archive\n"));
305ed0d50c3Schristos   fprintf (s, _("  x[o]         - extract file(s) from the archive\n"));
306ed0d50c3Schristos   fprintf (s, _(" command specific modifiers:\n"));
307ed0d50c3Schristos   fprintf (s, _("  [a]          - put file(s) after [member-name]\n"));
308ed0d50c3Schristos   fprintf (s, _("  [b]          - put file(s) before [member-name] (same as [i])\n"));
309ed0d50c3Schristos   if (DEFAULT_AR_DETERMINISTIC)
310ed0d50c3Schristos     {
311ed0d50c3Schristos       fprintf (s, _("\
312ed0d50c3Schristos   [D]          - use zero for timestamps and uids/gids (default)\n"));
313ed0d50c3Schristos       fprintf (s, _("\
314ed0d50c3Schristos   [U]          - use actual timestamps and uids/gids\n"));
315ed0d50c3Schristos     }
316ed0d50c3Schristos   else
317ed0d50c3Schristos     {
318ed0d50c3Schristos       fprintf (s, _("\
319ed0d50c3Schristos   [D]          - use zero for timestamps and uids/gids\n"));
320ed0d50c3Schristos       fprintf (s, _("\
321ed0d50c3Schristos   [U]          - use actual timestamps and uids/gids (default)\n"));
322ed0d50c3Schristos     }
323ed0d50c3Schristos   fprintf (s, _("  [N]          - use instance [count] of name\n"));
324ed0d50c3Schristos   fprintf (s, _("  [f]          - truncate inserted file names\n"));
325ed0d50c3Schristos   fprintf (s, _("  [P]          - use full path names when matching\n"));
326ed0d50c3Schristos   fprintf (s, _("  [o]          - preserve original dates\n"));
32706324dcfSchristos   fprintf (s, _("  [O]          - display offsets of files in the archive\n"));
328ed0d50c3Schristos   fprintf (s, _("  [u]          - only replace files that are newer than current archive contents\n"));
329ed0d50c3Schristos   fprintf (s, _(" generic modifiers:\n"));
330ed0d50c3Schristos   fprintf (s, _("  [c]          - do not warn if the library had to be created\n"));
331ed0d50c3Schristos   fprintf (s, _("  [s]          - create an archive index (cf. ranlib)\n"));
332ed0d50c3Schristos   fprintf (s, _("  [S]          - do not build a symbol table\n"));
333ed0d50c3Schristos   fprintf (s, _("  [T]          - make a thin archive\n"));
334ed0d50c3Schristos   fprintf (s, _("  [v]          - be verbose\n"));
335ed0d50c3Schristos   fprintf (s, _("  [V]          - display the version number\n"));
336ed0d50c3Schristos   fprintf (s, _("  @<file>      - read options from <file>\n"));
337ed0d50c3Schristos   fprintf (s, _("  --target=BFDNAME - specify the target object format as BFDNAME\n"));
338*b88e3e88Schristos   fprintf (s, _("  --output=DIRNAME - specify the output directory for extraction operations\n"));
339ed0d50c3Schristos #if BFD_SUPPORTS_PLUGINS
340ed0d50c3Schristos   fprintf (s, _(" optional:\n"));
341ed0d50c3Schristos   fprintf (s, _("  --plugin <p> - load the specified plugin\n"));
342ed0d50c3Schristos #endif
343ed0d50c3Schristos 
344ed0d50c3Schristos   ar_emul_usage (s);
345ed0d50c3Schristos 
346ed0d50c3Schristos   list_supported_targets (program_name, s);
347ed0d50c3Schristos 
348ed0d50c3Schristos   if (REPORT_BUGS_TO[0] && help)
349ed0d50c3Schristos     fprintf (s, _("Report bugs to %s\n"), REPORT_BUGS_TO);
350ed0d50c3Schristos 
351ed0d50c3Schristos   xexit (help ? 0 : 1);
352ed0d50c3Schristos }
353ed0d50c3Schristos 
354ed0d50c3Schristos static void
ranlib_usage(int help)355ed0d50c3Schristos ranlib_usage (int help)
356ed0d50c3Schristos {
357ed0d50c3Schristos   FILE *s;
358ed0d50c3Schristos 
359ed0d50c3Schristos   s = help ? stdout : stderr;
360ed0d50c3Schristos 
361ed0d50c3Schristos   /* xgettext:c-format */
362ed0d50c3Schristos   fprintf (s, _("Usage: %s [options] archive\n"), program_name);
363ed0d50c3Schristos   fprintf (s, _(" Generate an index to speed access to archives\n"));
364ed0d50c3Schristos   fprintf (s, _(" The options are:\n\
365ed0d50c3Schristos   @<file>                      Read options from <file>\n"));
366ed0d50c3Schristos #if BFD_SUPPORTS_PLUGINS
367ed0d50c3Schristos   fprintf (s, _("\
368ed0d50c3Schristos   --plugin <name>              Load the specified plugin\n"));
369ed0d50c3Schristos #endif
370ed0d50c3Schristos   if (DEFAULT_AR_DETERMINISTIC)
371ed0d50c3Schristos     fprintf (s, _("\
372ed0d50c3Schristos   -D                           Use zero for symbol map timestamp (default)\n\
373ed0d50c3Schristos   -U                           Use an actual symbol map timestamp\n"));
374ed0d50c3Schristos   else
375ed0d50c3Schristos     fprintf (s, _("\
376ed0d50c3Schristos   -D                           Use zero for symbol map timestamp\n\
377ed0d50c3Schristos   -U                           Use actual symbol map timestamp (default)\n"));
378ed0d50c3Schristos   fprintf (s, _("\
379ed0d50c3Schristos   -t                           Update the archive's symbol map timestamp\n\
380ed0d50c3Schristos   -h --help                    Print this help message\n\
381ed0d50c3Schristos   -v --version                 Print version information\n"));
382ed0d50c3Schristos 
383ed0d50c3Schristos   list_supported_targets (program_name, s);
384ed0d50c3Schristos 
385ed0d50c3Schristos   if (REPORT_BUGS_TO[0] && help)
386ed0d50c3Schristos     fprintf (s, _("Report bugs to %s\n"), REPORT_BUGS_TO);
387ed0d50c3Schristos 
388ed0d50c3Schristos   xexit (help ? 0 : 1);
389ed0d50c3Schristos }
390ed0d50c3Schristos 
391ed0d50c3Schristos /* Normalize a file name specified on the command line into a file
392ed0d50c3Schristos    name which we will use in an archive.  */
393ed0d50c3Schristos 
394ed0d50c3Schristos static const char *
normalize(const char * file,bfd * abfd)395ed0d50c3Schristos normalize (const char *file, bfd *abfd)
396ed0d50c3Schristos {
397ed0d50c3Schristos   const char *filename;
398ed0d50c3Schristos 
399ed0d50c3Schristos   if (full_pathname)
400ed0d50c3Schristos     return file;
401ed0d50c3Schristos 
402ed0d50c3Schristos   filename = lbasename (file);
403ed0d50c3Schristos 
404ed0d50c3Schristos   if (ar_truncate
405ed0d50c3Schristos       && abfd != NULL
406ed0d50c3Schristos       && strlen (filename) > abfd->xvec->ar_max_namelen)
407ed0d50c3Schristos     {
408ed0d50c3Schristos       char *s;
409ed0d50c3Schristos 
410ed0d50c3Schristos       /* Space leak.  */
411ed0d50c3Schristos       s = (char *) xmalloc (abfd->xvec->ar_max_namelen + 1);
412ed0d50c3Schristos       memcpy (s, filename, abfd->xvec->ar_max_namelen);
413ed0d50c3Schristos       s[abfd->xvec->ar_max_namelen] = '\0';
414ed0d50c3Schristos       filename = s;
415ed0d50c3Schristos     }
416ed0d50c3Schristos 
417ed0d50c3Schristos   return filename;
418ed0d50c3Schristos }
419ed0d50c3Schristos 
420ed0d50c3Schristos /* Remove any output file.  This is only called via xatexit.  */
421ed0d50c3Schristos 
422ed0d50c3Schristos static const char *output_filename = NULL;
423ed0d50c3Schristos static FILE *output_file = NULL;
424ed0d50c3Schristos static bfd *output_bfd = NULL;
425ed0d50c3Schristos 
426ed0d50c3Schristos static void
remove_output(void)427ed0d50c3Schristos remove_output (void)
428ed0d50c3Schristos {
429ed0d50c3Schristos   if (output_filename != NULL)
430ed0d50c3Schristos     {
431ed0d50c3Schristos       if (output_bfd != NULL)
432ed0d50c3Schristos 	bfd_cache_close (output_bfd);
433ed0d50c3Schristos       if (output_file != NULL)
434ed0d50c3Schristos 	fclose (output_file);
435ed0d50c3Schristos       unlink_if_ordinary (output_filename);
436ed0d50c3Schristos     }
437ed0d50c3Schristos }
438ed0d50c3Schristos 
439ed0d50c3Schristos static char **
decode_options(int argc,char ** argv)440ed0d50c3Schristos decode_options (int argc, char **argv)
441ed0d50c3Schristos {
442ed0d50c3Schristos   int c;
443ed0d50c3Schristos 
444*b88e3e88Schristos   /* Convert old-style ar call by exploding option element and rearranging
445ed0d50c3Schristos      options accordingly.  */
446ed0d50c3Schristos 
447*b88e3e88Schristos  restart:
448ed0d50c3Schristos   if (argc > 1 && argv[1][0] != '-')
449ed0d50c3Schristos     {
450ed0d50c3Schristos       int new_argc;		/* argc value for rearranged arguments */
451ed0d50c3Schristos       char **new_argv;		/* argv value for rearranged arguments */
452ed0d50c3Schristos       char *const *in;		/* cursor into original argv */
453ed0d50c3Schristos       char **out;		/* cursor into rearranged argv */
454ed0d50c3Schristos       const char *letter;	/* cursor into old option letters */
455ed0d50c3Schristos       char buffer[3];		/* constructed option buffer */
456ed0d50c3Schristos 
457ed0d50c3Schristos       /* Initialize a constructed option.  */
458ed0d50c3Schristos 
459ed0d50c3Schristos       buffer[0] = '-';
460ed0d50c3Schristos       buffer[2] = '\0';
461ed0d50c3Schristos 
462ed0d50c3Schristos       /* Allocate a new argument array, and copy program name in it.  */
463ed0d50c3Schristos 
464ed0d50c3Schristos       new_argc = argc - 1 + strlen (argv[1]);
465ed0d50c3Schristos       new_argv = xmalloc ((new_argc + 1) * sizeof (*argv));
466ed0d50c3Schristos       in = argv;
467ed0d50c3Schristos       out = new_argv;
468ed0d50c3Schristos       *out++ = *in++;
469ed0d50c3Schristos 
470ed0d50c3Schristos       /* Copy each old letter option as a separate option.  */
471ed0d50c3Schristos 
472ed0d50c3Schristos       for (letter = *in++; *letter; letter++)
473ed0d50c3Schristos 	{
474ed0d50c3Schristos 	  buffer[1] = *letter;
475ed0d50c3Schristos 	  *out++ = xstrdup (buffer);
476ed0d50c3Schristos 	}
477ed0d50c3Schristos 
478ed0d50c3Schristos       /* Copy all remaining options.  */
479ed0d50c3Schristos 
480ed0d50c3Schristos       while (in < argv + argc)
481ed0d50c3Schristos 	*out++ = *in++;
482ed0d50c3Schristos       *out = NULL;
483ed0d50c3Schristos 
484ed0d50c3Schristos       /* Replace the old option list by the new one.  */
485ed0d50c3Schristos 
486ed0d50c3Schristos       argc = new_argc;
487ed0d50c3Schristos       argv = new_argv;
488ed0d50c3Schristos     }
489ed0d50c3Schristos 
49006324dcfSchristos   while ((c = getopt_long (argc, argv, "hdmpqrtxlcoOVsSuvabiMNfPTDU",
491ed0d50c3Schristos 			   long_options, NULL)) != EOF)
492ed0d50c3Schristos     {
493ed0d50c3Schristos       switch (c)
494ed0d50c3Schristos         {
495ed0d50c3Schristos         case 'd':
496ed0d50c3Schristos         case 'm':
497ed0d50c3Schristos         case 'p':
498ed0d50c3Schristos         case 'q':
499ed0d50c3Schristos         case 'r':
500ed0d50c3Schristos         case 't':
501ed0d50c3Schristos         case 'x':
502ed0d50c3Schristos           if (operation != none)
503ed0d50c3Schristos             fatal (_("two different operation options specified"));
504ed0d50c3Schristos 	  break;
505ed0d50c3Schristos 	}
506ed0d50c3Schristos 
507ed0d50c3Schristos       switch (c)
508ed0d50c3Schristos         {
509ed0d50c3Schristos         case 'h':
510ed0d50c3Schristos 	  show_help = 1;
511ed0d50c3Schristos 	  break;
512ed0d50c3Schristos         case 'd':
513ed0d50c3Schristos           operation = del;
514ed0d50c3Schristos           operation_alters_arch = TRUE;
515ed0d50c3Schristos           break;
516ed0d50c3Schristos         case 'm':
517ed0d50c3Schristos           operation = move;
518ed0d50c3Schristos           operation_alters_arch = TRUE;
519ed0d50c3Schristos           break;
520ed0d50c3Schristos         case 'p':
521ed0d50c3Schristos           operation = print_files;
522ed0d50c3Schristos           break;
523ed0d50c3Schristos         case 'q':
524ed0d50c3Schristos           operation = quick_append;
525ed0d50c3Schristos           operation_alters_arch = TRUE;
526ed0d50c3Schristos           break;
527ed0d50c3Schristos         case 'r':
528ed0d50c3Schristos           operation = replace;
529ed0d50c3Schristos           operation_alters_arch = TRUE;
530ed0d50c3Schristos           break;
531ed0d50c3Schristos         case 't':
532ed0d50c3Schristos           operation = print_table;
533ed0d50c3Schristos           break;
534ed0d50c3Schristos         case 'x':
535ed0d50c3Schristos           operation = extract;
536ed0d50c3Schristos           break;
537ed0d50c3Schristos         case 'l':
538ed0d50c3Schristos           break;
539ed0d50c3Schristos         case 'c':
540ed0d50c3Schristos           silent_create = 1;
541ed0d50c3Schristos           break;
542ed0d50c3Schristos         case 'o':
543ed0d50c3Schristos           preserve_dates = 1;
544ed0d50c3Schristos           break;
54506324dcfSchristos         case 'O':
54606324dcfSchristos           display_offsets = 1;
54706324dcfSchristos           break;
548ed0d50c3Schristos         case 'V':
549ed0d50c3Schristos           show_version = TRUE;
550ed0d50c3Schristos           break;
551ed0d50c3Schristos         case 's':
552ed0d50c3Schristos           write_armap = 1;
553ed0d50c3Schristos           break;
554ed0d50c3Schristos         case 'S':
555ed0d50c3Schristos           write_armap = -1;
556ed0d50c3Schristos           break;
557ed0d50c3Schristos         case 'u':
558ed0d50c3Schristos           newer_only = 1;
559ed0d50c3Schristos           break;
560ed0d50c3Schristos         case 'v':
561ed0d50c3Schristos           verbose = 1;
562ed0d50c3Schristos           break;
563ed0d50c3Schristos         case 'a':
564ed0d50c3Schristos           postype = pos_after;
565ed0d50c3Schristos           break;
566ed0d50c3Schristos         case 'b':
567ed0d50c3Schristos           postype = pos_before;
568ed0d50c3Schristos           break;
569ed0d50c3Schristos         case 'i':
570ed0d50c3Schristos           postype = pos_before;
571ed0d50c3Schristos           break;
572ed0d50c3Schristos         case 'M':
573ed0d50c3Schristos           mri_mode = 1;
574ed0d50c3Schristos           break;
575ed0d50c3Schristos         case 'N':
576ed0d50c3Schristos           counted_name_mode = TRUE;
577ed0d50c3Schristos           break;
578ed0d50c3Schristos         case 'f':
579ed0d50c3Schristos           ar_truncate = TRUE;
580ed0d50c3Schristos           break;
581ed0d50c3Schristos         case 'P':
582ed0d50c3Schristos           full_pathname = TRUE;
583ed0d50c3Schristos           break;
584ed0d50c3Schristos         case 'T':
585ed0d50c3Schristos           make_thin_archive = TRUE;
586ed0d50c3Schristos           break;
587ed0d50c3Schristos         case 'D':
588ed0d50c3Schristos           deterministic = TRUE;
589ed0d50c3Schristos           break;
590ed0d50c3Schristos         case 'U':
591ed0d50c3Schristos           deterministic = FALSE;
592ed0d50c3Schristos           break;
593ed0d50c3Schristos 	case OPTION_PLUGIN:
594ed0d50c3Schristos #if BFD_SUPPORTS_PLUGINS
595ed0d50c3Schristos 	  bfd_plugin_set_plugin (optarg);
596ed0d50c3Schristos #else
597ed0d50c3Schristos 	  fprintf (stderr, _("sorry - this program has been built without plugin support\n"));
598ed0d50c3Schristos 	  xexit (1);
599ed0d50c3Schristos #endif
600ed0d50c3Schristos 	  break;
601ed0d50c3Schristos 	case OPTION_TARGET:
602ed0d50c3Schristos 	  target = optarg;
603ed0d50c3Schristos 	  break;
604*b88e3e88Schristos 	case OPTION_OUTPUT:
605*b88e3e88Schristos 	  output_dir = optarg;
606*b88e3e88Schristos 	  break;
607ed0d50c3Schristos 	case 0:		/* A long option that just sets a flag.  */
608ed0d50c3Schristos 	  break;
609ed0d50c3Schristos         default:
610ed0d50c3Schristos           usage (0);
611ed0d50c3Schristos         }
612ed0d50c3Schristos     }
613ed0d50c3Schristos 
614*b88e3e88Schristos   /* PR 13256: Allow for the possibility that the first command line option
615*b88e3e88Schristos      started with a dash (eg --plugin) but then the following option(s) are
616*b88e3e88Schristos      old style, non-dash-prefixed versions.  */
617*b88e3e88Schristos   if (operation == none && write_armap != 1 && !mri_mode
618*b88e3e88Schristos       && optind > 0 && optind < argc)
619*b88e3e88Schristos     {
620*b88e3e88Schristos       argv += (optind - 1);
621*b88e3e88Schristos       argc -= (optind - 1);
622*b88e3e88Schristos       optind = 0;
623*b88e3e88Schristos       goto restart;
624*b88e3e88Schristos     }
625*b88e3e88Schristos 
626ed0d50c3Schristos   return &argv[optind];
627ed0d50c3Schristos }
628ed0d50c3Schristos 
629ed0d50c3Schristos /* If neither -D nor -U was specified explicitly,
630ed0d50c3Schristos    then use the configured default.  */
631ed0d50c3Schristos static void
default_deterministic(void)632ed0d50c3Schristos default_deterministic (void)
633ed0d50c3Schristos {
634ed0d50c3Schristos   if (deterministic < 0)
635ed0d50c3Schristos     deterministic = DEFAULT_AR_DETERMINISTIC;
636ed0d50c3Schristos }
637ed0d50c3Schristos 
638ed0d50c3Schristos static void
ranlib_main(int argc,char ** argv)639ed0d50c3Schristos ranlib_main (int argc, char **argv)
640ed0d50c3Schristos {
641ed0d50c3Schristos   int arg_index, status = 0;
642ed0d50c3Schristos   bfd_boolean touch = FALSE;
643ed0d50c3Schristos   int c;
644ed0d50c3Schristos 
645ed0d50c3Schristos   while ((c = getopt_long (argc, argv, "DhHUvVt", long_options, NULL)) != EOF)
646ed0d50c3Schristos     {
647ed0d50c3Schristos       switch (c)
648ed0d50c3Schristos         {
649ed0d50c3Schristos 	case 'D':
650ed0d50c3Schristos 	  deterministic = TRUE;
651ed0d50c3Schristos 	  break;
652ed0d50c3Schristos         case 'U':
653ed0d50c3Schristos           deterministic = FALSE;
654ed0d50c3Schristos           break;
655ed0d50c3Schristos 	case 'h':
656ed0d50c3Schristos 	case 'H':
657ed0d50c3Schristos 	  show_help = 1;
658ed0d50c3Schristos 	  break;
659ed0d50c3Schristos 	case 't':
660ed0d50c3Schristos 	  touch = TRUE;
661ed0d50c3Schristos 	  break;
662ed0d50c3Schristos 	case 'v':
663ed0d50c3Schristos 	case 'V':
664ed0d50c3Schristos 	  show_version = 1;
665ed0d50c3Schristos 	  break;
666ed0d50c3Schristos 
667ed0d50c3Schristos 	  /* PR binutils/13493: Support plugins.  */
668ed0d50c3Schristos 	case OPTION_PLUGIN:
669ed0d50c3Schristos #if BFD_SUPPORTS_PLUGINS
670ed0d50c3Schristos 	  bfd_plugin_set_plugin (optarg);
671ed0d50c3Schristos #else
672ed0d50c3Schristos 	  fprintf (stderr, _("sorry - this program has been built without plugin support\n"));
673ed0d50c3Schristos 	  xexit (1);
674ed0d50c3Schristos #endif
675ed0d50c3Schristos 	  break;
676ed0d50c3Schristos 	}
677ed0d50c3Schristos     }
678ed0d50c3Schristos 
679ed0d50c3Schristos   if (argc < 2)
680ed0d50c3Schristos     ranlib_usage (0);
681ed0d50c3Schristos 
682ed0d50c3Schristos   if (show_help)
683ed0d50c3Schristos     ranlib_usage (1);
684ed0d50c3Schristos 
685ed0d50c3Schristos   if (show_version)
686ed0d50c3Schristos     print_version ("ranlib");
687ed0d50c3Schristos 
688ed0d50c3Schristos   default_deterministic ();
689ed0d50c3Schristos 
690ed0d50c3Schristos   arg_index = optind;
691ed0d50c3Schristos 
692ed0d50c3Schristos   while (arg_index < argc)
693ed0d50c3Schristos     {
694ed0d50c3Schristos       if (! touch)
695ed0d50c3Schristos         status |= ranlib_only (argv[arg_index]);
696ed0d50c3Schristos       else
697ed0d50c3Schristos         status |= ranlib_touch (argv[arg_index]);
698ed0d50c3Schristos       ++arg_index;
699ed0d50c3Schristos     }
700ed0d50c3Schristos 
701ed0d50c3Schristos   xexit (status);
702ed0d50c3Schristos }
703ed0d50c3Schristos 
704ed0d50c3Schristos int main (int, char **);
705ed0d50c3Schristos 
706ed0d50c3Schristos int
main(int argc,char ** argv)707ed0d50c3Schristos main (int argc, char **argv)
708ed0d50c3Schristos {
709ed0d50c3Schristos   int arg_index;
710ed0d50c3Schristos   char **files;
711ed0d50c3Schristos   int file_count;
712ed0d50c3Schristos   char *inarch_filename;
713ed0d50c3Schristos   int i;
714ed0d50c3Schristos 
715ed0d50c3Schristos #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
716ed0d50c3Schristos   setlocale (LC_MESSAGES, "");
717ed0d50c3Schristos #endif
718ed0d50c3Schristos #if defined (HAVE_SETLOCALE)
719ed0d50c3Schristos   setlocale (LC_CTYPE, "");
720ed0d50c3Schristos #endif
721ed0d50c3Schristos   bindtextdomain (PACKAGE, LOCALEDIR);
722ed0d50c3Schristos   textdomain (PACKAGE);
723ed0d50c3Schristos 
724ed0d50c3Schristos   program_name = argv[0];
725ed0d50c3Schristos   xmalloc_set_program_name (program_name);
726ed0d50c3Schristos   bfd_set_error_program_name (program_name);
727ed0d50c3Schristos #if BFD_SUPPORTS_PLUGINS
728ed0d50c3Schristos   bfd_plugin_set_program_name (program_name);
729ed0d50c3Schristos #endif
730ed0d50c3Schristos 
731ed0d50c3Schristos   expandargv (&argc, &argv);
732ed0d50c3Schristos 
733ed0d50c3Schristos   if (is_ranlib < 0)
734ed0d50c3Schristos     {
735ed0d50c3Schristos       const char *temp = lbasename (program_name);
736ed0d50c3Schristos 
737ed0d50c3Schristos       if (strlen (temp) >= 6
738ed0d50c3Schristos 	  && FILENAME_CMP (temp + strlen (temp) - 6, "ranlib") == 0)
739ed0d50c3Schristos 	is_ranlib = 1;
740ed0d50c3Schristos       else
741ed0d50c3Schristos 	is_ranlib = 0;
742ed0d50c3Schristos     }
743ed0d50c3Schristos 
744ed0d50c3Schristos   START_PROGRESS (program_name, 0);
745ed0d50c3Schristos 
746*b88e3e88Schristos   if (bfd_init () != BFD_INIT_MAGIC)
747*b88e3e88Schristos     fatal (_("fatal error: libbfd ABI mismatch"));
748ed0d50c3Schristos   set_default_bfd_target ();
749ed0d50c3Schristos 
750ed0d50c3Schristos   xatexit (remove_output);
751ed0d50c3Schristos 
752ed0d50c3Schristos   for (i = 1; i < argc; i++)
753ed0d50c3Schristos     if (! ar_emul_parse_arg (argv[i]))
754ed0d50c3Schristos       break;
755ed0d50c3Schristos   argv += (i - 1);
756ed0d50c3Schristos   argc -= (i - 1);
757ed0d50c3Schristos 
758ed0d50c3Schristos   if (is_ranlib)
759ed0d50c3Schristos     ranlib_main (argc, argv);
760ed0d50c3Schristos 
761ed0d50c3Schristos   if (argc < 2)
762ed0d50c3Schristos     usage (0);
763ed0d50c3Schristos 
764ed0d50c3Schristos   argv = decode_options (argc, argv);
765ed0d50c3Schristos 
766ed0d50c3Schristos   if (show_help)
767ed0d50c3Schristos     usage (1);
768ed0d50c3Schristos 
769ed0d50c3Schristos   if (show_version)
770ed0d50c3Schristos     print_version ("ar");
771ed0d50c3Schristos 
772ed0d50c3Schristos   arg_index = 0;
773ed0d50c3Schristos 
774ed0d50c3Schristos   if (mri_mode)
775ed0d50c3Schristos     {
776ed0d50c3Schristos       default_deterministic ();
777ed0d50c3Schristos       mri_emul ();
778ed0d50c3Schristos     }
779ed0d50c3Schristos   else
780ed0d50c3Schristos     {
781ed0d50c3Schristos       bfd *arch;
782ed0d50c3Schristos 
78306324dcfSchristos       /* Fail if no files are specified on the command line.
78406324dcfSchristos 	 (But not for MRI mode which allows for reading arguments
78506324dcfSchristos 	 and filenames from stdin).  */
78606324dcfSchristos       if (argv[arg_index] == NULL)
78706324dcfSchristos 	usage (0);
78806324dcfSchristos 
789ed0d50c3Schristos       /* We don't use do_quick_append any more.  Too many systems
790ed0d50c3Schristos 	 expect ar to always rebuild the symbol table even when q is
791ed0d50c3Schristos 	 used.  */
792ed0d50c3Schristos 
793ed0d50c3Schristos       /* We can't write an armap when using ar q, so just do ar r
794ed0d50c3Schristos          instead.  */
795ed0d50c3Schristos       if (operation == quick_append && write_armap)
796ed0d50c3Schristos 	operation = replace;
797ed0d50c3Schristos 
798ed0d50c3Schristos       if ((operation == none || operation == print_table)
799ed0d50c3Schristos 	  && write_armap == 1)
800ed0d50c3Schristos 	xexit (ranlib_only (argv[arg_index]));
801ed0d50c3Schristos 
802ed0d50c3Schristos       if (operation == none)
803ed0d50c3Schristos 	fatal (_("no operation specified"));
804ed0d50c3Schristos 
805ed0d50c3Schristos       if (newer_only && operation != replace)
806ed0d50c3Schristos 	fatal (_("`u' is only meaningful with the `r' option."));
807ed0d50c3Schristos 
808ed0d50c3Schristos       if (newer_only && deterministic > 0)
809ed0d50c3Schristos         fatal (_("`u' is not meaningful with the `D' option."));
810ed0d50c3Schristos 
811ed0d50c3Schristos       if (newer_only && deterministic < 0 && DEFAULT_AR_DETERMINISTIC)
812ed0d50c3Schristos         non_fatal (_("\
813ed0d50c3Schristos `u' modifier ignored since `D' is the default (see `U')"));
814ed0d50c3Schristos 
815ed0d50c3Schristos       default_deterministic ();
816ed0d50c3Schristos 
817ed0d50c3Schristos       if (postype != pos_default)
81806324dcfSchristos 	{
819ed0d50c3Schristos 	  posname = argv[arg_index++];
82006324dcfSchristos 	  if (posname == NULL)
82106324dcfSchristos 	    fatal (_("missing position arg."));
82206324dcfSchristos 	}
823ed0d50c3Schristos 
824ed0d50c3Schristos       if (counted_name_mode)
825ed0d50c3Schristos 	{
826ed0d50c3Schristos 	  if (operation != extract && operation != del)
827ed0d50c3Schristos 	    fatal (_("`N' is only meaningful with the `x' and `d' options."));
82806324dcfSchristos 	  if (argv[arg_index] == NULL)
82906324dcfSchristos 	    fatal (_("`N' missing value."));
830ed0d50c3Schristos 	  counted_name_counter = atoi (argv[arg_index++]);
831ed0d50c3Schristos 	  if (counted_name_counter <= 0)
832ed0d50c3Schristos 	    fatal (_("Value for `N' must be positive."));
833ed0d50c3Schristos 	}
834ed0d50c3Schristos 
835ed0d50c3Schristos       inarch_filename = argv[arg_index++];
83606324dcfSchristos       if (inarch_filename == NULL)
83706324dcfSchristos 	usage (0);
838ed0d50c3Schristos 
839ed0d50c3Schristos       for (file_count = 0; argv[arg_index + file_count] != NULL; file_count++)
840ed0d50c3Schristos 	continue;
841ed0d50c3Schristos 
842ed0d50c3Schristos       files = (file_count > 0) ? argv + arg_index : NULL;
843ed0d50c3Schristos 
844ed0d50c3Schristos       arch = open_inarch (inarch_filename,
845ed0d50c3Schristos 			  files == NULL ? (char *) NULL : files[0]);
846ed0d50c3Schristos 
847ed0d50c3Schristos       if (operation == extract && bfd_is_thin_archive (arch))
848ed0d50c3Schristos 	fatal (_("`x' cannot be used on thin archives."));
849ed0d50c3Schristos 
850ed0d50c3Schristos       switch (operation)
851ed0d50c3Schristos 	{
852ed0d50c3Schristos 	case print_table:
853ed0d50c3Schristos 	  map_over_members (arch, print_descr, files, file_count);
854ed0d50c3Schristos 	  break;
855ed0d50c3Schristos 
856ed0d50c3Schristos 	case print_files:
857ed0d50c3Schristos 	  map_over_members (arch, print_contents, files, file_count);
858ed0d50c3Schristos 	  break;
859ed0d50c3Schristos 
860ed0d50c3Schristos 	case extract:
861ed0d50c3Schristos 	  map_over_members (arch, extract_file, files, file_count);
862ed0d50c3Schristos 	  break;
863ed0d50c3Schristos 
864ed0d50c3Schristos 	case del:
865ed0d50c3Schristos 	  if (files != NULL)
866ed0d50c3Schristos 	    delete_members (arch, files);
867ed0d50c3Schristos 	  else
868ed0d50c3Schristos 	    output_filename = NULL;
869ed0d50c3Schristos 	  break;
870ed0d50c3Schristos 
871ed0d50c3Schristos 	case move:
872ed0d50c3Schristos 	  /* PR 12558: Creating and moving at the same time does
873ed0d50c3Schristos 	     not make sense.  Just create the archive instead.  */
874ed0d50c3Schristos 	  if (! silent_create)
875ed0d50c3Schristos 	    {
876ed0d50c3Schristos 	      if (files != NULL)
877ed0d50c3Schristos 		move_members (arch, files);
878ed0d50c3Schristos 	      else
879ed0d50c3Schristos 		output_filename = NULL;
880ed0d50c3Schristos 	      break;
881ed0d50c3Schristos 	    }
882ed0d50c3Schristos 	  /* Fall through.  */
883ed0d50c3Schristos 
884ed0d50c3Schristos 	case replace:
885ed0d50c3Schristos 	case quick_append:
886ed0d50c3Schristos 	  if (files != NULL || write_armap > 0)
887ed0d50c3Schristos 	    replace_members (arch, files, operation == quick_append);
888ed0d50c3Schristos 	  else
889ed0d50c3Schristos 	    output_filename = NULL;
890ed0d50c3Schristos 	  break;
891ed0d50c3Schristos 
892ed0d50c3Schristos 	  /* Shouldn't happen! */
893ed0d50c3Schristos 	default:
894ed0d50c3Schristos 	  /* xgettext:c-format */
895ed0d50c3Schristos 	  fatal (_("internal error -- this option not implemented"));
896ed0d50c3Schristos 	}
897ed0d50c3Schristos     }
898ed0d50c3Schristos 
899ed0d50c3Schristos   END_PROGRESS (program_name);
900ed0d50c3Schristos 
901ed0d50c3Schristos   xexit (0);
902ed0d50c3Schristos   return 0;
903ed0d50c3Schristos }
904ed0d50c3Schristos 
905ed0d50c3Schristos bfd *
open_inarch(const char * archive_filename,const char * file)906ed0d50c3Schristos open_inarch (const char *archive_filename, const char *file)
907ed0d50c3Schristos {
908ed0d50c3Schristos   bfd **last_one;
909ed0d50c3Schristos   bfd *next_one;
910ed0d50c3Schristos   struct stat sbuf;
911ed0d50c3Schristos   bfd *arch;
912ed0d50c3Schristos   char **matching;
913ed0d50c3Schristos 
914ed0d50c3Schristos   bfd_set_error (bfd_error_no_error);
915ed0d50c3Schristos 
916ed0d50c3Schristos   if (target == NULL)
917ed0d50c3Schristos     target = plugin_target;
918ed0d50c3Schristos 
919ed0d50c3Schristos   if (stat (archive_filename, &sbuf) != 0)
920ed0d50c3Schristos     {
921ed0d50c3Schristos #if !defined(__GO32__) || defined(__DJGPP__)
922ed0d50c3Schristos 
923ed0d50c3Schristos       /* FIXME: I don't understand why this fragment was ifndef'ed
924ed0d50c3Schristos 	 away for __GO32__; perhaps it was in the days of DJGPP v1.x.
925ed0d50c3Schristos 	 stat() works just fine in v2.x, so I think this should be
926ed0d50c3Schristos 	 removed.  For now, I enable it for DJGPP v2. -- EZ.  */
927ed0d50c3Schristos 
928ed0d50c3Schristos       /* KLUDGE ALERT! Temporary fix until I figger why
929ed0d50c3Schristos 	 stat() is wrong ... think it's buried in GO32's IDT - Jax */
930ed0d50c3Schristos       if (errno != ENOENT)
931ed0d50c3Schristos 	bfd_fatal (archive_filename);
932ed0d50c3Schristos #endif
933ed0d50c3Schristos 
934ed0d50c3Schristos       if (!operation_alters_arch)
935ed0d50c3Schristos 	{
936ed0d50c3Schristos 	  fprintf (stderr, "%s: ", program_name);
937ed0d50c3Schristos 	  perror (archive_filename);
938ed0d50c3Schristos 	  maybequit ();
939ed0d50c3Schristos 	  return NULL;
940ed0d50c3Schristos 	}
941ed0d50c3Schristos 
942ed0d50c3Schristos       /* If the target isn't set, try to figure out the target to use
943ed0d50c3Schristos 	 for the archive from the first object on the list.  */
944ed0d50c3Schristos       if (target == NULL && file != NULL)
945ed0d50c3Schristos 	{
946ed0d50c3Schristos 	  bfd *obj;
947ed0d50c3Schristos 
948ed0d50c3Schristos 	  obj = bfd_openr (file, target);
949ed0d50c3Schristos 	  if (obj != NULL)
950ed0d50c3Schristos 	    {
951ed0d50c3Schristos 	      if (bfd_check_format (obj, bfd_object))
952ed0d50c3Schristos 		target = bfd_get_target (obj);
953ed0d50c3Schristos 	      (void) bfd_close (obj);
954ed0d50c3Schristos 	    }
955ed0d50c3Schristos 	}
956ed0d50c3Schristos 
957ed0d50c3Schristos       /* Create an empty archive.  */
958ed0d50c3Schristos       arch = bfd_openw (archive_filename, target);
959ed0d50c3Schristos       if (arch == NULL
960ed0d50c3Schristos 	  || ! bfd_set_format (arch, bfd_archive)
961ed0d50c3Schristos 	  || ! bfd_close (arch))
962ed0d50c3Schristos 	bfd_fatal (archive_filename);
963ed0d50c3Schristos       else if (!silent_create)
964ed0d50c3Schristos         non_fatal (_("creating %s"), archive_filename);
965ed0d50c3Schristos 
966ed0d50c3Schristos       /* If we die creating a new archive, don't leave it around.  */
967ed0d50c3Schristos       output_filename = archive_filename;
968ed0d50c3Schristos     }
969ed0d50c3Schristos 
970ed0d50c3Schristos   arch = bfd_openr (archive_filename, target);
971ed0d50c3Schristos   if (arch == NULL)
972ed0d50c3Schristos     {
973ed0d50c3Schristos     bloser:
974ed0d50c3Schristos       bfd_fatal (archive_filename);
975ed0d50c3Schristos     }
976ed0d50c3Schristos 
977ed0d50c3Schristos   if (! bfd_check_format_matches (arch, bfd_archive, &matching))
978ed0d50c3Schristos     {
979ed0d50c3Schristos       bfd_nonfatal (archive_filename);
980ed0d50c3Schristos       if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
981ed0d50c3Schristos 	{
982ed0d50c3Schristos 	  list_matching_formats (matching);
983ed0d50c3Schristos 	  free (matching);
984ed0d50c3Schristos 	}
985ed0d50c3Schristos       xexit (1);
986ed0d50c3Schristos     }
987ed0d50c3Schristos 
988ed0d50c3Schristos   if ((operation == replace || operation == quick_append)
989ed0d50c3Schristos       && bfd_openr_next_archived_file (arch, NULL) != NULL)
990ed0d50c3Schristos     {
991ed0d50c3Schristos       /* PR 15140: Catch attempts to convert a normal
992ed0d50c3Schristos 	 archive into a thin archive or vice versa.  */
993ed0d50c3Schristos       if (make_thin_archive && ! bfd_is_thin_archive (arch))
994ed0d50c3Schristos 	{
995ed0d50c3Schristos 	  fatal (_("Cannot convert existing library %s to thin format"),
996ed0d50c3Schristos 		 bfd_get_filename (arch));
997ed0d50c3Schristos 	  goto bloser;
998ed0d50c3Schristos 	}
999ed0d50c3Schristos       else if (! make_thin_archive && bfd_is_thin_archive (arch))
1000ed0d50c3Schristos 	{
1001ed0d50c3Schristos 	  fatal (_("Cannot convert existing thin library %s to normal format"),
1002ed0d50c3Schristos 		 bfd_get_filename (arch));
1003ed0d50c3Schristos 	  goto bloser;
1004ed0d50c3Schristos 	}
1005ed0d50c3Schristos     }
1006ed0d50c3Schristos 
1007ed0d50c3Schristos   last_one = &(arch->archive_next);
1008ed0d50c3Schristos   /* Read all the contents right away, regardless.  */
1009ed0d50c3Schristos   for (next_one = bfd_openr_next_archived_file (arch, NULL);
1010ed0d50c3Schristos        next_one;
1011ed0d50c3Schristos        next_one = bfd_openr_next_archived_file (arch, next_one))
1012ed0d50c3Schristos     {
1013ed0d50c3Schristos       PROGRESS (1);
1014ed0d50c3Schristos       *last_one = next_one;
1015ed0d50c3Schristos       last_one = &next_one->archive_next;
1016ed0d50c3Schristos     }
1017ed0d50c3Schristos   *last_one = (bfd *) NULL;
1018ed0d50c3Schristos   if (bfd_get_error () != bfd_error_no_more_archived_files)
1019ed0d50c3Schristos     goto bloser;
1020ed0d50c3Schristos   return arch;
1021ed0d50c3Schristos }
1022ed0d50c3Schristos 
1023ed0d50c3Schristos static void
print_contents(bfd * abfd)1024ed0d50c3Schristos print_contents (bfd *abfd)
1025ed0d50c3Schristos {
1026ed0d50c3Schristos   bfd_size_type ncopied = 0;
1027ed0d50c3Schristos   bfd_size_type size;
1028ed0d50c3Schristos   char *cbuf = (char *) xmalloc (BUFSIZE);
1029ed0d50c3Schristos   struct stat buf;
1030ed0d50c3Schristos 
1031ed0d50c3Schristos   if (bfd_stat_arch_elt (abfd, &buf) != 0)
1032ed0d50c3Schristos     /* xgettext:c-format */
1033ed0d50c3Schristos     fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
1034ed0d50c3Schristos 
1035ed0d50c3Schristos   if (verbose)
1036ed0d50c3Schristos     printf ("\n<%s>\n\n", bfd_get_filename (abfd));
1037ed0d50c3Schristos 
1038ed0d50c3Schristos   bfd_seek (abfd, (file_ptr) 0, SEEK_SET);
1039ed0d50c3Schristos 
1040ed0d50c3Schristos   size = buf.st_size;
1041ed0d50c3Schristos   while (ncopied < size)
1042ed0d50c3Schristos     {
1043ed0d50c3Schristos       bfd_size_type nread;
1044ed0d50c3Schristos       bfd_size_type tocopy = size - ncopied;
1045ed0d50c3Schristos 
1046ed0d50c3Schristos       if (tocopy > BUFSIZE)
1047ed0d50c3Schristos 	tocopy = BUFSIZE;
1048ed0d50c3Schristos 
1049ed0d50c3Schristos       nread = bfd_bread (cbuf, tocopy, abfd);
1050ed0d50c3Schristos       if (nread != tocopy)
1051ed0d50c3Schristos 	/* xgettext:c-format */
1052ed0d50c3Schristos 	fatal (_("%s is not a valid archive"),
1053ed0d50c3Schristos 	       bfd_get_filename (abfd->my_archive));
1054ed0d50c3Schristos 
1055ed0d50c3Schristos       /* fwrite in mingw32 may return int instead of bfd_size_type. Cast the
1056ed0d50c3Schristos 	 return value to bfd_size_type to avoid comparison between signed and
1057ed0d50c3Schristos 	 unsigned values.  */
1058ed0d50c3Schristos       if ((bfd_size_type) fwrite (cbuf, 1, nread, stdout) != nread)
1059ed0d50c3Schristos 	fatal ("stdout: %s", strerror (errno));
1060ed0d50c3Schristos       ncopied += tocopy;
1061ed0d50c3Schristos     }
1062ed0d50c3Schristos   free (cbuf);
1063ed0d50c3Schristos }
1064ed0d50c3Schristos 
1065*b88e3e88Schristos 
1066*b88e3e88Schristos static FILE * open_output_file (bfd *) ATTRIBUTE_RETURNS_NONNULL;
1067*b88e3e88Schristos 
1068*b88e3e88Schristos static FILE *
open_output_file(bfd * abfd)1069*b88e3e88Schristos open_output_file (bfd * abfd)
1070*b88e3e88Schristos {
1071*b88e3e88Schristos   output_filename = bfd_get_filename (abfd);
1072*b88e3e88Schristos 
1073*b88e3e88Schristos   /* PR binutils/17533: Do not allow directory traversal
1074*b88e3e88Schristos      outside of the current directory tree - unless the
1075*b88e3e88Schristos      user has explicitly specified an output directory.  */
1076*b88e3e88Schristos   if (! is_valid_archive_path (output_filename))
1077*b88e3e88Schristos     {
1078*b88e3e88Schristos       char * base = (char *) lbasename (output_filename);
1079*b88e3e88Schristos 
1080*b88e3e88Schristos       non_fatal (_("illegal output pathname for archive member: %s, using '%s' instead"),
1081*b88e3e88Schristos 		 output_filename, base);
1082*b88e3e88Schristos       output_filename = base;
1083*b88e3e88Schristos     }
1084*b88e3e88Schristos 
1085*b88e3e88Schristos   if (output_dir)
1086*b88e3e88Schristos     {
1087*b88e3e88Schristos       size_t len = strlen (output_dir);
1088*b88e3e88Schristos 
1089*b88e3e88Schristos       if (len > 0)
1090*b88e3e88Schristos 	{
1091*b88e3e88Schristos 	  /* FIXME: There is a memory leak here, but it is not serious.  */
1092*b88e3e88Schristos 	  if (IS_DIR_SEPARATOR (output_dir [len - 1]))
1093*b88e3e88Schristos 	    output_filename = concat (output_dir, output_filename, NULL);
1094*b88e3e88Schristos 	  else
1095*b88e3e88Schristos 	    output_filename = concat (output_dir, "/", output_filename, NULL);
1096*b88e3e88Schristos 	}
1097*b88e3e88Schristos     }
1098*b88e3e88Schristos 
1099*b88e3e88Schristos   if (verbose)
1100*b88e3e88Schristos     printf ("x - %s\n", output_filename);
1101*b88e3e88Schristos 
1102*b88e3e88Schristos   FILE * ostream = fopen (output_filename, FOPEN_WB);
1103*b88e3e88Schristos   if (ostream == NULL)
1104*b88e3e88Schristos     {
1105*b88e3e88Schristos       perror (output_filename);
1106*b88e3e88Schristos       xexit (1);
1107*b88e3e88Schristos     }
1108*b88e3e88Schristos 
1109*b88e3e88Schristos   return ostream;
1110*b88e3e88Schristos }
1111*b88e3e88Schristos 
1112ed0d50c3Schristos /* Extract a member of the archive into its own file.
1113ed0d50c3Schristos 
1114ed0d50c3Schristos    We defer opening the new file until after we have read a BUFSIZ chunk of the
1115ed0d50c3Schristos    old one, since we know we have just read the archive header for the old
1116ed0d50c3Schristos    one.  Since most members are shorter than BUFSIZ, this means we will read
1117ed0d50c3Schristos    the old header, read the old data, write a new inode for the new file, and
1118ed0d50c3Schristos    write the new data, and be done. This 'optimization' is what comes from
1119ed0d50c3Schristos    sitting next to a bare disk and hearing it every time it seeks.  -- Gnu
1120ed0d50c3Schristos    Gilmore  */
1121ed0d50c3Schristos 
1122ed0d50c3Schristos void
extract_file(bfd * abfd)1123ed0d50c3Schristos extract_file (bfd *abfd)
1124ed0d50c3Schristos {
1125ed0d50c3Schristos   bfd_size_type size;
1126ed0d50c3Schristos   struct stat buf;
1127ed0d50c3Schristos 
1128ed0d50c3Schristos   if (bfd_stat_arch_elt (abfd, &buf) != 0)
1129ed0d50c3Schristos     /* xgettext:c-format */
1130ed0d50c3Schristos     fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
1131ed0d50c3Schristos   size = buf.st_size;
1132ed0d50c3Schristos 
1133ed0d50c3Schristos   bfd_seek (abfd, (file_ptr) 0, SEEK_SET);
1134ed0d50c3Schristos 
1135*b88e3e88Schristos   output_file = NULL;
1136ed0d50c3Schristos   if (size == 0)
1137ed0d50c3Schristos     {
1138*b88e3e88Schristos       output_file = open_output_file (abfd);
1139ed0d50c3Schristos     }
1140ed0d50c3Schristos   else
1141*b88e3e88Schristos     {
1142*b88e3e88Schristos       bfd_size_type ncopied = 0;
1143*b88e3e88Schristos       char *cbuf = (char *) xmalloc (BUFSIZE);
1144*b88e3e88Schristos 
1145ed0d50c3Schristos       while (ncopied < size)
1146ed0d50c3Schristos 	{
1147*b88e3e88Schristos 	  bfd_size_type nread, tocopy;
1148*b88e3e88Schristos 
1149ed0d50c3Schristos 	  tocopy = size - ncopied;
1150ed0d50c3Schristos 	  if (tocopy > BUFSIZE)
1151ed0d50c3Schristos 	    tocopy = BUFSIZE;
1152ed0d50c3Schristos 
1153ed0d50c3Schristos 	  nread = bfd_bread (cbuf, tocopy, abfd);
1154ed0d50c3Schristos 	  if (nread != tocopy)
1155ed0d50c3Schristos 	    /* xgettext:c-format */
1156ed0d50c3Schristos 	    fatal (_("%s is not a valid archive"),
1157ed0d50c3Schristos 		   bfd_get_filename (abfd->my_archive));
1158ed0d50c3Schristos 
1159*b88e3e88Schristos 	  /* See comment above; this saves disk arm motion.  */
1160*b88e3e88Schristos 	  if (output_file == NULL)
1161*b88e3e88Schristos 	    output_file = open_output_file (abfd);
1162ed0d50c3Schristos 
1163ed0d50c3Schristos 	  /* fwrite in mingw32 may return int instead of bfd_size_type. Cast
1164ed0d50c3Schristos 	     the return value to bfd_size_type to avoid comparison between
1165ed0d50c3Schristos 	     signed and unsigned values.  */
1166*b88e3e88Schristos 	  if ((bfd_size_type) fwrite (cbuf, 1, nread, output_file) != nread)
1167ed0d50c3Schristos 	    fatal ("%s: %s", output_filename, strerror (errno));
1168*b88e3e88Schristos 
1169ed0d50c3Schristos 	  ncopied += tocopy;
1170ed0d50c3Schristos 	}
1171ed0d50c3Schristos 
1172*b88e3e88Schristos       free (cbuf);
1173*b88e3e88Schristos     }
1174*b88e3e88Schristos 
1175*b88e3e88Schristos   fclose (output_file);
1176ed0d50c3Schristos 
1177ed0d50c3Schristos   output_file = NULL;
1178ed0d50c3Schristos 
1179*b88e3e88Schristos   chmod (output_filename, buf.st_mode);
1180ed0d50c3Schristos 
1181ed0d50c3Schristos   if (preserve_dates)
1182ed0d50c3Schristos     {
1183ed0d50c3Schristos       /* Set access time to modification time.  Only st_mtime is
1184ed0d50c3Schristos 	 initialized by bfd_stat_arch_elt.  */
1185ed0d50c3Schristos       buf.st_atime = buf.st_mtime;
1186*b88e3e88Schristos       set_times (output_filename, &buf);
1187ed0d50c3Schristos     }
1188ed0d50c3Schristos 
1189*b88e3e88Schristos   output_filename = NULL;
1190ed0d50c3Schristos }
1191ed0d50c3Schristos 
1192ed0d50c3Schristos static void
write_archive(bfd * iarch)1193ed0d50c3Schristos write_archive (bfd *iarch)
1194ed0d50c3Schristos {
1195ed0d50c3Schristos   bfd *obfd;
1196ed0d50c3Schristos   char *old_name, *new_name;
1197ed0d50c3Schristos   bfd *contents_head = iarch->archive_next;
1198ed0d50c3Schristos 
1199ed0d50c3Schristos   old_name = (char *) xmalloc (strlen (bfd_get_filename (iarch)) + 1);
1200ed0d50c3Schristos   strcpy (old_name, bfd_get_filename (iarch));
1201ed0d50c3Schristos   new_name = make_tempname (old_name);
1202ed0d50c3Schristos 
1203ed0d50c3Schristos   if (new_name == NULL)
1204ed0d50c3Schristos     bfd_fatal (_("could not create temporary file whilst writing archive"));
1205ed0d50c3Schristos 
1206ed0d50c3Schristos   output_filename = new_name;
1207ed0d50c3Schristos 
1208ed0d50c3Schristos   obfd = bfd_openw (new_name, bfd_get_target (iarch));
1209ed0d50c3Schristos 
1210ed0d50c3Schristos   if (obfd == NULL)
1211ed0d50c3Schristos     bfd_fatal (old_name);
1212ed0d50c3Schristos 
1213ed0d50c3Schristos   output_bfd = obfd;
1214ed0d50c3Schristos 
1215ed0d50c3Schristos   bfd_set_format (obfd, bfd_archive);
1216ed0d50c3Schristos 
1217ed0d50c3Schristos   /* Request writing the archive symbol table unless we've
1218ed0d50c3Schristos      been explicitly requested not to.  */
1219ed0d50c3Schristos   obfd->has_armap = write_armap >= 0;
1220ed0d50c3Schristos 
1221ed0d50c3Schristos   if (ar_truncate)
1222ed0d50c3Schristos     {
1223ed0d50c3Schristos       /* This should really use bfd_set_file_flags, but that rejects
1224ed0d50c3Schristos          archives.  */
1225ed0d50c3Schristos       obfd->flags |= BFD_TRADITIONAL_FORMAT;
1226ed0d50c3Schristos     }
1227ed0d50c3Schristos 
1228ed0d50c3Schristos   if (deterministic)
1229ed0d50c3Schristos     obfd->flags |= BFD_DETERMINISTIC_OUTPUT;
1230ed0d50c3Schristos 
1231*b88e3e88Schristos   if (full_pathname)
1232*b88e3e88Schristos     obfd->flags |= BFD_ARCHIVE_FULL_PATH;
1233*b88e3e88Schristos 
1234ed0d50c3Schristos   if (make_thin_archive || bfd_is_thin_archive (iarch))
1235*b88e3e88Schristos     bfd_set_thin_archive (obfd, TRUE);
1236ed0d50c3Schristos 
1237ed0d50c3Schristos   if (!bfd_set_archive_head (obfd, contents_head))
1238ed0d50c3Schristos     bfd_fatal (old_name);
1239ed0d50c3Schristos 
1240ed0d50c3Schristos   if (!bfd_close (obfd))
1241ed0d50c3Schristos     bfd_fatal (old_name);
1242ed0d50c3Schristos 
1243ed0d50c3Schristos   output_bfd = NULL;
1244ed0d50c3Schristos   output_filename = NULL;
1245ed0d50c3Schristos 
1246ed0d50c3Schristos   /* We don't care if this fails; we might be creating the archive.  */
1247ed0d50c3Schristos   bfd_close (iarch);
1248ed0d50c3Schristos 
1249ed0d50c3Schristos   if (smart_rename (new_name, old_name, 0) != 0)
1250ed0d50c3Schristos     xexit (1);
1251ed0d50c3Schristos   free (old_name);
125206324dcfSchristos   free (new_name);
1253ed0d50c3Schristos }
1254ed0d50c3Schristos 
1255ed0d50c3Schristos /* Return a pointer to the pointer to the entry which should be rplacd'd
1256ed0d50c3Schristos    into when altering.  DEFAULT_POS should be how to interpret pos_default,
1257ed0d50c3Schristos    and should be a pos value.  */
1258ed0d50c3Schristos 
1259ed0d50c3Schristos static bfd **
get_pos_bfd(bfd ** contents,enum pos default_pos,const char * default_posname)1260ed0d50c3Schristos get_pos_bfd (bfd **contents, enum pos default_pos, const char *default_posname)
1261ed0d50c3Schristos {
1262ed0d50c3Schristos   bfd **after_bfd = contents;
1263ed0d50c3Schristos   enum pos realpos;
1264ed0d50c3Schristos   const char *realposname;
1265ed0d50c3Schristos 
1266ed0d50c3Schristos   if (postype == pos_default)
1267ed0d50c3Schristos     {
1268ed0d50c3Schristos       realpos = default_pos;
1269ed0d50c3Schristos       realposname = default_posname;
1270ed0d50c3Schristos     }
1271ed0d50c3Schristos   else
1272ed0d50c3Schristos     {
1273ed0d50c3Schristos       realpos = postype;
1274ed0d50c3Schristos       realposname = posname;
1275ed0d50c3Schristos     }
1276ed0d50c3Schristos 
1277ed0d50c3Schristos   if (realpos == pos_end)
1278ed0d50c3Schristos     {
1279ed0d50c3Schristos       while (*after_bfd)
1280ed0d50c3Schristos 	after_bfd = &((*after_bfd)->archive_next);
1281ed0d50c3Schristos     }
1282ed0d50c3Schristos   else
1283ed0d50c3Schristos     {
1284ed0d50c3Schristos       for (; *after_bfd; after_bfd = &(*after_bfd)->archive_next)
1285ed0d50c3Schristos 	if (FILENAME_CMP ((*after_bfd)->filename, realposname) == 0)
1286ed0d50c3Schristos 	  {
1287ed0d50c3Schristos 	    if (realpos == pos_after)
1288ed0d50c3Schristos 	      after_bfd = &(*after_bfd)->archive_next;
1289ed0d50c3Schristos 	    break;
1290ed0d50c3Schristos 	  }
1291ed0d50c3Schristos     }
1292ed0d50c3Schristos   return after_bfd;
1293ed0d50c3Schristos }
1294ed0d50c3Schristos 
1295ed0d50c3Schristos static void
delete_members(bfd * arch,char ** files_to_delete)1296ed0d50c3Schristos delete_members (bfd *arch, char **files_to_delete)
1297ed0d50c3Schristos {
1298ed0d50c3Schristos   bfd **current_ptr_ptr;
1299ed0d50c3Schristos   bfd_boolean found;
1300ed0d50c3Schristos   bfd_boolean something_changed = FALSE;
1301ed0d50c3Schristos   int match_count;
1302ed0d50c3Schristos 
1303ed0d50c3Schristos   for (; *files_to_delete != NULL; ++files_to_delete)
1304ed0d50c3Schristos     {
1305ed0d50c3Schristos       /* In a.out systems, the armap is optional.  It's also called
1306ed0d50c3Schristos 	 __.SYMDEF.  So if the user asked to delete it, we should remember
1307ed0d50c3Schristos 	 that fact. This isn't quite right for COFF systems (where
1308ed0d50c3Schristos 	 __.SYMDEF might be regular member), but it's very unlikely
1309ed0d50c3Schristos 	 to be a problem.  FIXME */
1310ed0d50c3Schristos 
1311ed0d50c3Schristos       if (!strcmp (*files_to_delete, "__.SYMDEF"))
1312ed0d50c3Schristos 	{
1313ed0d50c3Schristos 	  arch->has_armap = FALSE;
1314ed0d50c3Schristos 	  write_armap = -1;
1315ed0d50c3Schristos 	  continue;
1316ed0d50c3Schristos 	}
1317ed0d50c3Schristos 
1318ed0d50c3Schristos       found = FALSE;
1319ed0d50c3Schristos       match_count = 0;
1320ed0d50c3Schristos       current_ptr_ptr = &(arch->archive_next);
1321ed0d50c3Schristos       while (*current_ptr_ptr)
1322ed0d50c3Schristos 	{
1323ed0d50c3Schristos 	  if (FILENAME_CMP (normalize (*files_to_delete, arch),
1324ed0d50c3Schristos 			    (*current_ptr_ptr)->filename) == 0)
1325ed0d50c3Schristos 	    {
1326ed0d50c3Schristos 	      ++match_count;
1327ed0d50c3Schristos 	      if (counted_name_mode
1328ed0d50c3Schristos 		  && match_count != counted_name_counter)
1329ed0d50c3Schristos 		{
1330ed0d50c3Schristos 		  /* Counting, and didn't match on count; go on to the
1331ed0d50c3Schristos                      next one.  */
1332ed0d50c3Schristos 		}
1333ed0d50c3Schristos 	      else
1334ed0d50c3Schristos 		{
1335ed0d50c3Schristos 		  found = TRUE;
1336ed0d50c3Schristos 		  something_changed = TRUE;
1337ed0d50c3Schristos 		  if (verbose)
1338ed0d50c3Schristos 		    printf ("d - %s\n",
1339ed0d50c3Schristos 			    *files_to_delete);
1340ed0d50c3Schristos 		  *current_ptr_ptr = ((*current_ptr_ptr)->archive_next);
1341ed0d50c3Schristos 		  goto next_file;
1342ed0d50c3Schristos 		}
1343ed0d50c3Schristos 	    }
1344ed0d50c3Schristos 
1345ed0d50c3Schristos 	  current_ptr_ptr = &((*current_ptr_ptr)->archive_next);
1346ed0d50c3Schristos 	}
1347ed0d50c3Schristos 
1348ed0d50c3Schristos       if (verbose && !found)
1349ed0d50c3Schristos 	{
1350ed0d50c3Schristos 	  /* xgettext:c-format */
1351ed0d50c3Schristos 	  printf (_("No member named `%s'\n"), *files_to_delete);
1352ed0d50c3Schristos 	}
1353ed0d50c3Schristos     next_file:
1354ed0d50c3Schristos       ;
1355ed0d50c3Schristos     }
1356ed0d50c3Schristos 
1357ed0d50c3Schristos   if (something_changed)
1358ed0d50c3Schristos     write_archive (arch);
1359ed0d50c3Schristos   else
1360ed0d50c3Schristos     output_filename = NULL;
1361ed0d50c3Schristos }
1362ed0d50c3Schristos 
1363ed0d50c3Schristos 
1364ed0d50c3Schristos /* Reposition existing members within an archive */
1365ed0d50c3Schristos 
1366ed0d50c3Schristos static void
move_members(bfd * arch,char ** files_to_move)1367ed0d50c3Schristos move_members (bfd *arch, char **files_to_move)
1368ed0d50c3Schristos {
1369ed0d50c3Schristos   bfd **after_bfd;		/* New entries go after this one */
1370ed0d50c3Schristos   bfd **current_ptr_ptr;	/* cdr pointer into contents */
1371ed0d50c3Schristos 
1372ed0d50c3Schristos   for (; *files_to_move; ++files_to_move)
1373ed0d50c3Schristos     {
1374ed0d50c3Schristos       current_ptr_ptr = &(arch->archive_next);
1375ed0d50c3Schristos       while (*current_ptr_ptr)
1376ed0d50c3Schristos 	{
1377ed0d50c3Schristos 	  bfd *current_ptr = *current_ptr_ptr;
1378ed0d50c3Schristos 	  if (FILENAME_CMP (normalize (*files_to_move, arch),
1379ed0d50c3Schristos 			    current_ptr->filename) == 0)
1380ed0d50c3Schristos 	    {
1381ed0d50c3Schristos 	      /* Move this file to the end of the list - first cut from
1382ed0d50c3Schristos 		 where it is.  */
1383ed0d50c3Schristos 	      bfd *link_bfd;
1384ed0d50c3Schristos 	      *current_ptr_ptr = current_ptr->archive_next;
1385ed0d50c3Schristos 
1386ed0d50c3Schristos 	      /* Now glue to end */
1387ed0d50c3Schristos 	      after_bfd = get_pos_bfd (&arch->archive_next, pos_end, NULL);
1388ed0d50c3Schristos 	      link_bfd = *after_bfd;
1389ed0d50c3Schristos 	      *after_bfd = current_ptr;
1390ed0d50c3Schristos 	      current_ptr->archive_next = link_bfd;
1391ed0d50c3Schristos 
1392ed0d50c3Schristos 	      if (verbose)
1393ed0d50c3Schristos 		printf ("m - %s\n", *files_to_move);
1394ed0d50c3Schristos 
1395ed0d50c3Schristos 	      goto next_file;
1396ed0d50c3Schristos 	    }
1397ed0d50c3Schristos 
1398ed0d50c3Schristos 	  current_ptr_ptr = &((*current_ptr_ptr)->archive_next);
1399ed0d50c3Schristos 	}
1400ed0d50c3Schristos       /* xgettext:c-format */
1401ed0d50c3Schristos       fatal (_("no entry %s in archive %s!"), *files_to_move, arch->filename);
1402ed0d50c3Schristos 
1403ed0d50c3Schristos     next_file:;
1404ed0d50c3Schristos     }
1405ed0d50c3Schristos 
1406ed0d50c3Schristos   write_archive (arch);
1407ed0d50c3Schristos }
1408ed0d50c3Schristos 
1409ed0d50c3Schristos /* Ought to default to replacing in place, but this is existing practice!  */
1410ed0d50c3Schristos 
1411ed0d50c3Schristos static void
replace_members(bfd * arch,char ** files_to_move,bfd_boolean quick)1412ed0d50c3Schristos replace_members (bfd *arch, char **files_to_move, bfd_boolean quick)
1413ed0d50c3Schristos {
1414ed0d50c3Schristos   bfd_boolean changed = FALSE;
1415ed0d50c3Schristos   bfd **after_bfd;		/* New entries go after this one.  */
1416ed0d50c3Schristos   bfd *current;
1417ed0d50c3Schristos   bfd **current_ptr;
1418ed0d50c3Schristos 
1419ed0d50c3Schristos   while (files_to_move && *files_to_move)
1420ed0d50c3Schristos     {
1421ed0d50c3Schristos       if (! quick)
1422ed0d50c3Schristos 	{
1423ed0d50c3Schristos 	  current_ptr = &arch->archive_next;
1424ed0d50c3Schristos 	  while (*current_ptr)
1425ed0d50c3Schristos 	    {
1426ed0d50c3Schristos 	      current = *current_ptr;
1427ed0d50c3Schristos 
1428ed0d50c3Schristos 	      /* For compatibility with existing ar programs, we
1429ed0d50c3Schristos 		 permit the same file to be added multiple times.  */
1430ed0d50c3Schristos 	      if (FILENAME_CMP (normalize (*files_to_move, arch),
1431ed0d50c3Schristos 				normalize (current->filename, arch)) == 0
1432ed0d50c3Schristos 		  && current->arelt_data != NULL)
1433ed0d50c3Schristos 		{
1434ed0d50c3Schristos 		  if (newer_only)
1435ed0d50c3Schristos 		    {
1436ed0d50c3Schristos 		      struct stat fsbuf, asbuf;
1437ed0d50c3Schristos 
1438ed0d50c3Schristos 		      if (stat (*files_to_move, &fsbuf) != 0)
1439ed0d50c3Schristos 			{
1440ed0d50c3Schristos 			  if (errno != ENOENT)
1441ed0d50c3Schristos 			    bfd_fatal (*files_to_move);
1442ed0d50c3Schristos 			  goto next_file;
1443ed0d50c3Schristos 			}
1444ed0d50c3Schristos 		      if (bfd_stat_arch_elt (current, &asbuf) != 0)
1445ed0d50c3Schristos 			/* xgettext:c-format */
1446ed0d50c3Schristos 			fatal (_("internal stat error on %s"),
1447ed0d50c3Schristos 			       current->filename);
1448ed0d50c3Schristos 
1449ed0d50c3Schristos 		      if (fsbuf.st_mtime <= asbuf.st_mtime)
1450ed0d50c3Schristos 			goto next_file;
1451ed0d50c3Schristos 		    }
1452ed0d50c3Schristos 
1453ed0d50c3Schristos 		  after_bfd = get_pos_bfd (&arch->archive_next, pos_after,
1454ed0d50c3Schristos 					   current->filename);
1455ed0d50c3Schristos 		  if (ar_emul_replace (after_bfd, *files_to_move,
1456ed0d50c3Schristos 				       target, verbose))
1457ed0d50c3Schristos 		    {
1458ed0d50c3Schristos 		      /* Snip out this entry from the chain.  */
1459ed0d50c3Schristos 		      *current_ptr = (*current_ptr)->archive_next;
1460ed0d50c3Schristos 		      changed = TRUE;
1461ed0d50c3Schristos 		    }
1462ed0d50c3Schristos 
1463ed0d50c3Schristos 		  goto next_file;
1464ed0d50c3Schristos 		}
1465ed0d50c3Schristos 	      current_ptr = &(current->archive_next);
1466ed0d50c3Schristos 	    }
1467ed0d50c3Schristos 	}
1468ed0d50c3Schristos 
1469ed0d50c3Schristos       /* Add to the end of the archive.  */
1470ed0d50c3Schristos       after_bfd = get_pos_bfd (&arch->archive_next, pos_end, NULL);
1471ed0d50c3Schristos 
1472ed0d50c3Schristos       if (ar_emul_append (after_bfd, *files_to_move, target,
1473ed0d50c3Schristos 			  verbose, make_thin_archive))
1474ed0d50c3Schristos 	changed = TRUE;
1475ed0d50c3Schristos 
1476ed0d50c3Schristos     next_file:;
1477ed0d50c3Schristos 
1478ed0d50c3Schristos       files_to_move++;
1479ed0d50c3Schristos     }
1480ed0d50c3Schristos 
1481ed0d50c3Schristos   if (changed)
1482ed0d50c3Schristos     write_archive (arch);
1483ed0d50c3Schristos   else
1484ed0d50c3Schristos     output_filename = NULL;
1485ed0d50c3Schristos }
1486ed0d50c3Schristos 
1487ed0d50c3Schristos static int
ranlib_only(const char * archname)1488ed0d50c3Schristos ranlib_only (const char *archname)
1489ed0d50c3Schristos {
1490ed0d50c3Schristos   bfd *arch;
1491ed0d50c3Schristos 
1492ed0d50c3Schristos   if (get_file_size (archname) < 1)
1493ed0d50c3Schristos     return 1;
1494ed0d50c3Schristos   write_armap = 1;
1495ed0d50c3Schristos   arch = open_inarch (archname, (char *) NULL);
1496ed0d50c3Schristos   if (arch == NULL)
1497ed0d50c3Schristos     xexit (1);
1498ed0d50c3Schristos   write_archive (arch);
1499ed0d50c3Schristos   return 0;
1500ed0d50c3Schristos }
1501ed0d50c3Schristos 
1502ed0d50c3Schristos /* Update the timestamp of the symbol map of an archive.  */
1503ed0d50c3Schristos 
1504ed0d50c3Schristos static int
ranlib_touch(const char * archname)1505ed0d50c3Schristos ranlib_touch (const char *archname)
1506ed0d50c3Schristos {
1507ed0d50c3Schristos #ifdef __GO32__
1508ed0d50c3Schristos   /* I don't think updating works on go32.  */
1509ed0d50c3Schristos   ranlib_only (archname);
1510ed0d50c3Schristos #else
1511ed0d50c3Schristos   int f;
1512ed0d50c3Schristos   bfd *arch;
1513ed0d50c3Schristos   char **matching;
1514ed0d50c3Schristos 
1515ed0d50c3Schristos   if (get_file_size (archname) < 1)
1516ed0d50c3Schristos     return 1;
1517ed0d50c3Schristos   f = open (archname, O_RDWR | O_BINARY, 0);
1518ed0d50c3Schristos   if (f < 0)
1519ed0d50c3Schristos     {
1520ed0d50c3Schristos       bfd_set_error (bfd_error_system_call);
1521ed0d50c3Schristos       bfd_fatal (archname);
1522ed0d50c3Schristos     }
1523ed0d50c3Schristos 
1524ed0d50c3Schristos   arch = bfd_fdopenr (archname, (const char *) NULL, f);
1525ed0d50c3Schristos   if (arch == NULL)
1526ed0d50c3Schristos     bfd_fatal (archname);
1527ed0d50c3Schristos   if (! bfd_check_format_matches (arch, bfd_archive, &matching))
1528ed0d50c3Schristos     {
1529ed0d50c3Schristos       bfd_nonfatal (archname);
1530ed0d50c3Schristos       if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
1531ed0d50c3Schristos 	{
1532ed0d50c3Schristos 	  list_matching_formats (matching);
1533ed0d50c3Schristos 	  free (matching);
1534ed0d50c3Schristos 	}
1535ed0d50c3Schristos       xexit (1);
1536ed0d50c3Schristos     }
1537ed0d50c3Schristos 
1538ed0d50c3Schristos   if (! bfd_has_map (arch))
1539ed0d50c3Schristos     /* xgettext:c-format */
1540ed0d50c3Schristos     fatal (_("%s: no archive map to update"), archname);
1541ed0d50c3Schristos 
1542ed0d50c3Schristos   if (deterministic)
1543ed0d50c3Schristos     arch->flags |= BFD_DETERMINISTIC_OUTPUT;
1544ed0d50c3Schristos 
1545ed0d50c3Schristos   bfd_update_armap_timestamp (arch);
1546ed0d50c3Schristos 
1547ed0d50c3Schristos   if (! bfd_close (arch))
1548ed0d50c3Schristos     bfd_fatal (archname);
1549ed0d50c3Schristos #endif
1550ed0d50c3Schristos   return 0;
1551ed0d50c3Schristos }
1552ed0d50c3Schristos 
1553ed0d50c3Schristos /* Things which are interesting to map over all or some of the files: */
1554ed0d50c3Schristos 
1555ed0d50c3Schristos static void
print_descr(bfd * abfd)1556ed0d50c3Schristos print_descr (bfd *abfd)
1557ed0d50c3Schristos {
155806324dcfSchristos   print_arelt_descr (stdout, abfd, verbose, display_offsets);
1559ed0d50c3Schristos }
1560