xref: /openbsd-src/gnu/usr.bin/binutils-2.17/binutils/ar.c (revision 314e8fdf1443639b5fc22b2a54bda4404fbe472a)
13d8817e4Smiod /* ar.c - Archive modify and extract.
23d8817e4Smiod    Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
33d8817e4Smiod    2001, 2002, 2003, 2004, 2005
43d8817e4Smiod    Free Software Foundation, Inc.
53d8817e4Smiod 
63d8817e4Smiod    This file is part of GNU Binutils.
73d8817e4Smiod 
83d8817e4Smiod    This program is free software; you can redistribute it and/or modify
93d8817e4Smiod    it under the terms of the GNU General Public License as published by
103d8817e4Smiod    the Free Software Foundation; either version 2 of the License, or
113d8817e4Smiod    (at your option) any later version.
123d8817e4Smiod 
133d8817e4Smiod    This program is distributed in the hope that it will be useful,
143d8817e4Smiod    but WITHOUT ANY WARRANTY; without even the implied warranty of
153d8817e4Smiod    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
163d8817e4Smiod    GNU General Public License for more details.
173d8817e4Smiod 
183d8817e4Smiod    You should have received a copy of the GNU General Public License
193d8817e4Smiod    along with this program; if not, write to the Free Software
203d8817e4Smiod    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
213d8817e4Smiod 
223d8817e4Smiod /*
233d8817e4Smiod    Bugs: should use getopt the way tar does (complete w/optional -) and
243d8817e4Smiod    should have long options too. GNU ar used to check file against filesystem
253d8817e4Smiod    in quick_update and replace operations (would check mtime). Doesn't warn
263d8817e4Smiod    when name truncated. No way to specify pos_end. Error messages should be
273d8817e4Smiod    more consistent.  */
283d8817e4Smiod 
293d8817e4Smiod #include "bfd.h"
303d8817e4Smiod #include "libiberty.h"
313d8817e4Smiod #include "progress.h"
323d8817e4Smiod #include "bucomm.h"
333d8817e4Smiod #include "aout/ar.h"
343d8817e4Smiod #include "libbfd.h"
353d8817e4Smiod #include "arsup.h"
363d8817e4Smiod #include "filenames.h"
373d8817e4Smiod #include "binemul.h"
383d8817e4Smiod #include <sys/stat.h>
393d8817e4Smiod 
403d8817e4Smiod #ifdef __GO32___
413d8817e4Smiod #define EXT_NAME_LEN 3		/* bufflen of addition to name if it's MS-DOS */
423d8817e4Smiod #else
433d8817e4Smiod #define EXT_NAME_LEN 6		/* ditto for *NIX */
443d8817e4Smiod #endif
453d8817e4Smiod 
463d8817e4Smiod /* We need to open files in binary modes on system where that makes a
473d8817e4Smiod    difference.  */
483d8817e4Smiod #ifndef O_BINARY
493d8817e4Smiod #define O_BINARY 0
503d8817e4Smiod #endif
513d8817e4Smiod 
523d8817e4Smiod /* Kludge declaration from BFD!  This is ugly!  FIXME!  XXX */
533d8817e4Smiod 
543d8817e4Smiod struct ar_hdr *
553d8817e4Smiod   bfd_special_undocumented_glue (bfd * abfd, const char *filename);
563d8817e4Smiod 
573d8817e4Smiod /* Static declarations */
583d8817e4Smiod 
593d8817e4Smiod static void mri_emul (void);
603d8817e4Smiod static const char *normalize (const char *, bfd *);
613d8817e4Smiod static void remove_output (void);
623d8817e4Smiod static void map_over_members (bfd *, void (*)(bfd *), char **, int);
633d8817e4Smiod static void print_contents (bfd * member);
643d8817e4Smiod static void delete_members (bfd *, char **files_to_delete);
653d8817e4Smiod 
663d8817e4Smiod static void move_members (bfd *, char **files_to_move);
673d8817e4Smiod static void replace_members
683d8817e4Smiod   (bfd *, char **files_to_replace, bfd_boolean quick);
693d8817e4Smiod static void print_descr (bfd * abfd);
703d8817e4Smiod static void write_archive (bfd *);
713d8817e4Smiod static void ranlib_only (const char *archname);
723d8817e4Smiod static void ranlib_touch (const char *archname);
733d8817e4Smiod static void usage (int);
743d8817e4Smiod 
753d8817e4Smiod /** Globals and flags */
763d8817e4Smiod 
773d8817e4Smiod static int mri_mode;
783d8817e4Smiod 
793d8817e4Smiod /* This flag distinguishes between ar and ranlib:
803d8817e4Smiod    1 means this is 'ranlib'; 0 means this is 'ar'.
813d8817e4Smiod    -1 means if we should use argv[0] to decide.  */
823d8817e4Smiod extern int is_ranlib;
833d8817e4Smiod 
843d8817e4Smiod /* Nonzero means don't warn about creating the archive file if necessary.  */
853d8817e4Smiod int silent_create = 0;
863d8817e4Smiod 
873d8817e4Smiod /* Nonzero means describe each action performed.  */
883d8817e4Smiod int verbose = 0;
893d8817e4Smiod 
903d8817e4Smiod /* Nonzero means preserve dates of members when extracting them.  */
913d8817e4Smiod int preserve_dates = 0;
923d8817e4Smiod 
933d8817e4Smiod /* Nonzero means don't replace existing members whose dates are more recent
943d8817e4Smiod    than the corresponding files.  */
953d8817e4Smiod int newer_only = 0;
963d8817e4Smiod 
973d8817e4Smiod /* Controls the writing of an archive symbol table (in BSD: a __.SYMDEF
983d8817e4Smiod    member).  -1 means we've been explicitly asked to not write a symbol table;
993d8817e4Smiod    +1 means we've been explicitly asked to write it;
1003d8817e4Smiod    0 is the default.
1013d8817e4Smiod    Traditionally, the default in BSD has been to not write the table.
1023d8817e4Smiod    However, for POSIX.2 compliance the default is now to write a symbol table
1033d8817e4Smiod    if any of the members are object files.  */
1043d8817e4Smiod int write_armap = 0;
1053d8817e4Smiod 
1063d8817e4Smiod /* Nonzero means it's the name of an existing member; position new or moved
1073d8817e4Smiod    files with respect to this one.  */
1083d8817e4Smiod char *posname = NULL;
1093d8817e4Smiod 
1103d8817e4Smiod /* Sez how to use `posname': pos_before means position before that member.
1113d8817e4Smiod    pos_after means position after that member. pos_end means always at end.
1123d8817e4Smiod    pos_default means default appropriately. For the latter two, `posname'
1133d8817e4Smiod    should also be zero.  */
1143d8817e4Smiod enum pos
1153d8817e4Smiod   {
1163d8817e4Smiod     pos_default, pos_before, pos_after, pos_end
1173d8817e4Smiod   } postype = pos_default;
1183d8817e4Smiod 
1193d8817e4Smiod static bfd **
1203d8817e4Smiod get_pos_bfd (bfd **, enum pos, const char *);
1213d8817e4Smiod 
1223d8817e4Smiod /* For extract/delete only.  If COUNTED_NAME_MODE is TRUE, we only
1233d8817e4Smiod    extract the COUNTED_NAME_COUNTER instance of that name.  */
1243d8817e4Smiod static bfd_boolean counted_name_mode = 0;
1253d8817e4Smiod static int counted_name_counter = 0;
1263d8817e4Smiod 
1273d8817e4Smiod /* Whether to truncate names of files stored in the archive.  */
1283d8817e4Smiod static bfd_boolean ar_truncate = FALSE;
1293d8817e4Smiod 
1303d8817e4Smiod /* Whether to use a full file name match when searching an archive.
1313d8817e4Smiod    This is convenient for archives created by the Microsoft lib
1323d8817e4Smiod    program.  */
1333d8817e4Smiod static bfd_boolean full_pathname = FALSE;
1343d8817e4Smiod 
135*314e8fdfSguenther /* Whether archive contents should be deterministic with uid, gid,
136*314e8fdfSguenther    and mtime set to zero and permissions set to 644.  This breaks
137*314e8fdfSguenther    later use of the 'u' option as well as make's lib(member) feature.
138*314e8fdfSguenther    Note that the symbol index may have a non-zero timestamp to meet
139*314e8fdfSguenther    archive format requirements.  */
140*314e8fdfSguenther static bfd_boolean deterministic = FALSE;
141*314e8fdfSguenther 
1423d8817e4Smiod int interactive = 0;
1433d8817e4Smiod 
1443d8817e4Smiod static void
mri_emul(void)1453d8817e4Smiod mri_emul (void)
1463d8817e4Smiod {
1473d8817e4Smiod   interactive = isatty (fileno (stdin));
1483d8817e4Smiod   yyparse ();
1493d8817e4Smiod }
1503d8817e4Smiod 
1513d8817e4Smiod /* If COUNT is 0, then FUNCTION is called once on each entry.  If nonzero,
1523d8817e4Smiod    COUNT is the length of the FILES chain; FUNCTION is called on each entry
1533d8817e4Smiod    whose name matches one in FILES.  */
1543d8817e4Smiod 
1553d8817e4Smiod static void
map_over_members(bfd * arch,void (* function)(bfd *),char ** files,int count)1563d8817e4Smiod map_over_members (bfd *arch, void (*function)(bfd *), char **files, int count)
1573d8817e4Smiod {
1583d8817e4Smiod   bfd *head;
1593d8817e4Smiod   int match_count;
1603d8817e4Smiod 
1613d8817e4Smiod   if (count == 0)
1623d8817e4Smiod     {
1633d8817e4Smiod       for (head = arch->next; head; head = head->next)
1643d8817e4Smiod 	{
1653d8817e4Smiod 	  PROGRESS (1);
1663d8817e4Smiod 	  function (head);
1673d8817e4Smiod 	}
1683d8817e4Smiod       return;
1693d8817e4Smiod     }
1703d8817e4Smiod 
1713d8817e4Smiod   /* This may appear to be a baroque way of accomplishing what we want.
1723d8817e4Smiod      However we have to iterate over the filenames in order to notice where
1733d8817e4Smiod      a filename is requested but does not exist in the archive.  Ditto
1743d8817e4Smiod      mapping over each file each time -- we want to hack multiple
1753d8817e4Smiod      references.  */
1763d8817e4Smiod 
1773d8817e4Smiod   for (; count > 0; files++, count--)
1783d8817e4Smiod     {
1793d8817e4Smiod       bfd_boolean found = FALSE;
1803d8817e4Smiod 
1813d8817e4Smiod       match_count = 0;
1823d8817e4Smiod       for (head = arch->next; head; head = head->next)
1833d8817e4Smiod 	{
1843d8817e4Smiod 	  PROGRESS (1);
1853d8817e4Smiod 	  if (head->filename == NULL)
1863d8817e4Smiod 	    {
1873d8817e4Smiod 	      /* Some archive formats don't get the filenames filled in
1883d8817e4Smiod 		 until the elements are opened.  */
1893d8817e4Smiod 	      struct stat buf;
1903d8817e4Smiod 	      bfd_stat_arch_elt (head, &buf);
1913d8817e4Smiod 	    }
1923d8817e4Smiod 	  if ((head->filename != NULL) &&
1933d8817e4Smiod 	      (!FILENAME_CMP (normalize (*files, arch), head->filename)))
1943d8817e4Smiod 	    {
1953d8817e4Smiod 	      ++match_count;
1963d8817e4Smiod 	      if (counted_name_mode
1973d8817e4Smiod 		  && match_count != counted_name_counter)
1983d8817e4Smiod 		{
1993d8817e4Smiod 		  /* Counting, and didn't match on count; go on to the
2003d8817e4Smiod                      next one.  */
2013d8817e4Smiod 		  continue;
2023d8817e4Smiod 		}
2033d8817e4Smiod 
2043d8817e4Smiod 	      found = TRUE;
2053d8817e4Smiod 	      function (head);
2063d8817e4Smiod 	    }
2073d8817e4Smiod 	}
2083d8817e4Smiod       if (!found)
2093d8817e4Smiod 	/* xgettext:c-format */
2103d8817e4Smiod 	fprintf (stderr, _("no entry %s in archive\n"), *files);
2113d8817e4Smiod     }
2123d8817e4Smiod }
2133d8817e4Smiod 
2143d8817e4Smiod bfd_boolean operation_alters_arch = FALSE;
2153d8817e4Smiod 
2163d8817e4Smiod static void
usage(int help)2173d8817e4Smiod usage (int help)
2183d8817e4Smiod {
2193d8817e4Smiod   FILE *s;
2203d8817e4Smiod 
2213d8817e4Smiod   s = help ? stdout : stderr;
2223d8817e4Smiod 
2233d8817e4Smiod   if (! is_ranlib)
2243d8817e4Smiod     {
2253d8817e4Smiod       /* xgettext:c-format */
2263d8817e4Smiod       fprintf (s, _("Usage: %s [emulation options] [-]{dmpqrstx}[abcfilNoPsSuvV] [member-name] [count] archive-file file...\n"),
2273d8817e4Smiod 	       program_name);
2283d8817e4Smiod       /* xgettext:c-format */
2293d8817e4Smiod       fprintf (s, _("       %s -M [<mri-script]\n"), program_name);
2303d8817e4Smiod       fprintf (s, _(" commands:\n"));
2313d8817e4Smiod       fprintf (s, _("  d            - delete file(s) from the archive\n"));
2323d8817e4Smiod       fprintf (s, _("  m[ab]        - move file(s) in the archive\n"));
2333d8817e4Smiod       fprintf (s, _("  p            - print file(s) found in the archive\n"));
2343d8817e4Smiod       fprintf (s, _("  q[f]         - quick append file(s) to the archive\n"));
2353d8817e4Smiod       fprintf (s, _("  r[ab][f][u]  - replace existing or insert new file(s) into the archive\n"));
2363d8817e4Smiod       fprintf (s, _("  t            - display contents of archive\n"));
2373d8817e4Smiod       fprintf (s, _("  x[o]         - extract file(s) from the archive\n"));
2383d8817e4Smiod       fprintf (s, _(" command specific modifiers:\n"));
2393d8817e4Smiod       fprintf (s, _("  [a]          - put file(s) after [member-name]\n"));
2403d8817e4Smiod       fprintf (s, _("  [b]          - put file(s) before [member-name] (same as [i])\n"));
2413d8817e4Smiod       fprintf (s, _("  [N]          - use instance [count] of name\n"));
2423d8817e4Smiod       fprintf (s, _("  [f]          - truncate inserted file names\n"));
2433d8817e4Smiod       fprintf (s, _("  [P]          - use full path names when matching\n"));
2443d8817e4Smiod       fprintf (s, _("  [o]          - preserve original dates\n"));
2453d8817e4Smiod       fprintf (s, _("  [u]          - only replace files that are newer than current archive contents\n"));
246*314e8fdfSguenther       fprintf (s, _("  [D]          - set deterministic attributes in archive\n"));
247*314e8fdfSguenther       fprintf (s, _("  [U]          - set accurate attributes in archive\n"));
2483d8817e4Smiod       fprintf (s, _(" generic modifiers:\n"));
2493d8817e4Smiod       fprintf (s, _("  [c]          - do not warn if the library had to be created\n"));
2503d8817e4Smiod       fprintf (s, _("  [s]          - create an archive index (cf. ranlib)\n"));
2513d8817e4Smiod       fprintf (s, _("  [S]          - do not build a symbol table\n"));
2523d8817e4Smiod       fprintf (s, _("  [v]          - be verbose\n"));
2533d8817e4Smiod       fprintf (s, _("  [V]          - display the version number\n"));
2543d8817e4Smiod       fprintf (s, _("  @<file>      - read options from <file>\n"));
2553d8817e4Smiod 
2563d8817e4Smiod       ar_emul_usage (s);
2573d8817e4Smiod     }
2583d8817e4Smiod   else
2593d8817e4Smiod     {
2603d8817e4Smiod       /* xgettext:c-format */
2613d8817e4Smiod       fprintf (s, _("Usage: %s [options] archive\n"), program_name);
2623d8817e4Smiod       fprintf (s, _(" Generate an index to speed access to archives\n"));
2633d8817e4Smiod       fprintf (s, _(" The options are:\n\
2643d8817e4Smiod   @<file>                      Read options from <file>\n\
2653d8817e4Smiod   -h --help                    Print this help message\n\
2663d8817e4Smiod   -V --version                 Print version information\n"));
2673d8817e4Smiod     }
2683d8817e4Smiod 
2693d8817e4Smiod   list_supported_targets (program_name, stderr);
2703d8817e4Smiod 
2713d8817e4Smiod   if (help)
2723d8817e4Smiod     fprintf (s, _("Report bugs to %s\n"), REPORT_BUGS_TO);
2733d8817e4Smiod 
2743d8817e4Smiod   xexit (help ? 0 : 1);
2753d8817e4Smiod }
2763d8817e4Smiod 
2773d8817e4Smiod /* Normalize a file name specified on the command line into a file
2783d8817e4Smiod    name which we will use in an archive.  */
2793d8817e4Smiod 
2803d8817e4Smiod static const char *
normalize(const char * file,bfd * abfd)2813d8817e4Smiod normalize (const char *file, bfd *abfd)
2823d8817e4Smiod {
2833d8817e4Smiod   const char *filename;
2843d8817e4Smiod 
2853d8817e4Smiod   if (full_pathname)
2863d8817e4Smiod     return file;
2873d8817e4Smiod 
2883d8817e4Smiod   filename = strrchr (file, '/');
2893d8817e4Smiod #ifdef HAVE_DOS_BASED_FILE_SYSTEM
2903d8817e4Smiod   {
2913d8817e4Smiod     /* We could have foo/bar\\baz, or foo\\bar, or d:bar.  */
2923d8817e4Smiod     char *bslash = strrchr (file, '\\');
2933d8817e4Smiod     if (filename == NULL || (bslash != NULL && bslash > filename))
2943d8817e4Smiod       filename = bslash;
2953d8817e4Smiod     if (filename == NULL && file[0] != '\0' && file[1] == ':')
2963d8817e4Smiod       filename = file + 1;
2973d8817e4Smiod   }
2983d8817e4Smiod #endif
2993d8817e4Smiod   if (filename != (char *) NULL)
3003d8817e4Smiod     filename++;
3013d8817e4Smiod   else
3023d8817e4Smiod     filename = file;
3033d8817e4Smiod 
3043d8817e4Smiod   if (ar_truncate
3053d8817e4Smiod       && abfd != NULL
3063d8817e4Smiod       && strlen (filename) > abfd->xvec->ar_max_namelen)
3073d8817e4Smiod     {
3083d8817e4Smiod       char *s;
3093d8817e4Smiod 
3103d8817e4Smiod       /* Space leak.  */
3113d8817e4Smiod       s = (char *) xmalloc (abfd->xvec->ar_max_namelen + 1);
3123d8817e4Smiod       memcpy (s, filename, abfd->xvec->ar_max_namelen);
3133d8817e4Smiod       s[abfd->xvec->ar_max_namelen] = '\0';
3143d8817e4Smiod       filename = s;
3153d8817e4Smiod     }
3163d8817e4Smiod 
3173d8817e4Smiod   return filename;
3183d8817e4Smiod }
3193d8817e4Smiod 
3203d8817e4Smiod /* Remove any output file.  This is only called via xatexit.  */
3213d8817e4Smiod 
3223d8817e4Smiod static const char *output_filename = NULL;
3233d8817e4Smiod static FILE *output_file = NULL;
3243d8817e4Smiod static bfd *output_bfd = NULL;
3253d8817e4Smiod 
3263d8817e4Smiod static void
remove_output(void)3273d8817e4Smiod remove_output (void)
3283d8817e4Smiod {
3293d8817e4Smiod   if (output_filename != NULL)
3303d8817e4Smiod     {
3313d8817e4Smiod       if (output_bfd != NULL)
3323d8817e4Smiod 	bfd_cache_close (output_bfd);
3333d8817e4Smiod       if (output_file != NULL)
3343d8817e4Smiod 	fclose (output_file);
3353d8817e4Smiod       unlink_if_ordinary (output_filename);
3363d8817e4Smiod     }
3373d8817e4Smiod }
3383d8817e4Smiod 
3393d8817e4Smiod /* The option parsing should be in its own function.
3403d8817e4Smiod    It will be when I have getopt working.  */
3413d8817e4Smiod 
3423d8817e4Smiod int main (int, char **);
3433d8817e4Smiod 
3443d8817e4Smiod int
main(int argc,char ** argv)3453d8817e4Smiod main (int argc, char **argv)
3463d8817e4Smiod {
3473d8817e4Smiod   char *arg_ptr;
3483d8817e4Smiod   char c;
3493d8817e4Smiod   enum
3503d8817e4Smiod     {
3513d8817e4Smiod       none = 0, delete, replace, print_table,
3523d8817e4Smiod       print_files, extract, move, quick_append
3533d8817e4Smiod     } operation = none;
3543d8817e4Smiod   int arg_index;
3553d8817e4Smiod   char **files;
3563d8817e4Smiod   int file_count;
3573d8817e4Smiod   char *inarch_filename;
3583d8817e4Smiod   int show_version;
3593d8817e4Smiod   int i;
3603d8817e4Smiod   int do_posix = 0;
3613d8817e4Smiod 
3623d8817e4Smiod #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
3633d8817e4Smiod   setlocale (LC_MESSAGES, "");
3643d8817e4Smiod #endif
3653d8817e4Smiod #if defined (HAVE_SETLOCALE)
3663d8817e4Smiod   setlocale (LC_CTYPE, "");
3673d8817e4Smiod #endif
3683d8817e4Smiod   bindtextdomain (PACKAGE, LOCALEDIR);
3693d8817e4Smiod   textdomain (PACKAGE);
3703d8817e4Smiod 
3713d8817e4Smiod   program_name = argv[0];
3723d8817e4Smiod   xmalloc_set_program_name (program_name);
3733d8817e4Smiod 
374f9a4b902Sderaadt   if (pledge ("stdio rpath wpath cpath fattr", NULL) == -1)
375f9a4b902Sderaadt     fatal (_("pledge: %s"), strerror (errno));
376f9a4b902Sderaadt 
3773d8817e4Smiod   expandargv (&argc, &argv);
3783d8817e4Smiod 
3793d8817e4Smiod   if (is_ranlib < 0)
3803d8817e4Smiod     {
3813d8817e4Smiod       char *temp;
3823d8817e4Smiod 
3833d8817e4Smiod       temp = strrchr (program_name, '/');
3843d8817e4Smiod #ifdef HAVE_DOS_BASED_FILE_SYSTEM
3853d8817e4Smiod       {
3863d8817e4Smiod 	/* We could have foo/bar\\baz, or foo\\bar, or d:bar.  */
3873d8817e4Smiod 	char *bslash = strrchr (program_name, '\\');
3883d8817e4Smiod 	if (temp == NULL || (bslash != NULL && bslash > temp))
3893d8817e4Smiod 	  temp = bslash;
3903d8817e4Smiod 	if (temp == NULL && program_name[0] != '\0' && program_name[1] == ':')
3913d8817e4Smiod 	  temp = program_name + 1;
3923d8817e4Smiod       }
3933d8817e4Smiod #endif
3943d8817e4Smiod       if (temp == NULL)
3953d8817e4Smiod 	temp = program_name;
3963d8817e4Smiod       else
3973d8817e4Smiod 	++temp;
3983d8817e4Smiod       if (strlen (temp) >= 6
3993d8817e4Smiod 	  && FILENAME_CMP (temp + strlen (temp) - 6, "ranlib") == 0)
4003d8817e4Smiod 	is_ranlib = 1;
4013d8817e4Smiod       else
4023d8817e4Smiod 	is_ranlib = 0;
4033d8817e4Smiod     }
4043d8817e4Smiod 
4053d8817e4Smiod   if (argc > 1 && argv[1][0] == '-')
4063d8817e4Smiod     {
4073d8817e4Smiod       if (strcmp (argv[1], "--help") == 0)
4083d8817e4Smiod 	usage (1);
4093d8817e4Smiod       else if (strcmp (argv[1], "--version") == 0)
4103d8817e4Smiod 	{
4113d8817e4Smiod 	  if (is_ranlib)
4123d8817e4Smiod 	    print_version ("ranlib");
4133d8817e4Smiod 	  else
4143d8817e4Smiod 	    print_version ("ar");
4153d8817e4Smiod 	}
4163d8817e4Smiod     }
4173d8817e4Smiod 
4183d8817e4Smiod   START_PROGRESS (program_name, 0);
4193d8817e4Smiod 
4203d8817e4Smiod   bfd_init ();
4213d8817e4Smiod   set_default_bfd_target ();
4223d8817e4Smiod 
4233d8817e4Smiod   show_version = 0;
4243d8817e4Smiod 
4253d8817e4Smiod   xatexit (remove_output);
4263d8817e4Smiod 
4273d8817e4Smiod   for (i = 1; i < argc; i++)
4283d8817e4Smiod     if (! ar_emul_parse_arg (argv[i]))
4293d8817e4Smiod       break;
4303d8817e4Smiod   argv += (i - 1);
4313d8817e4Smiod   argc -= (i - 1);
4323d8817e4Smiod 
4333d8817e4Smiod   if (is_ranlib)
4343d8817e4Smiod     {
4353d8817e4Smiod       bfd_boolean touch = FALSE;
4363d8817e4Smiod 
4373d8817e4Smiod       if (argc < 2
4383d8817e4Smiod 	  || strcmp (argv[1], "--help") == 0
4393d8817e4Smiod 	  || strcmp (argv[1], "-h") == 0
4403d8817e4Smiod 	  || strcmp (argv[1], "-H") == 0)
4413d8817e4Smiod 	usage (0);
4423d8817e4Smiod       if (strcmp (argv[1], "-V") == 0
4433d8817e4Smiod 	  || strcmp (argv[1], "-v") == 0
4443d8817e4Smiod 	  || strncmp (argv[1], "--v", 3) == 0)
4453d8817e4Smiod 	print_version ("ranlib");
4463d8817e4Smiod       arg_index = 1;
4473d8817e4Smiod       if (strcmp (argv[1], "-t") == 0)
4483d8817e4Smiod 	{
4493d8817e4Smiod 	  ++arg_index;
4503d8817e4Smiod 	  touch = TRUE;
4513d8817e4Smiod 	}
4523d8817e4Smiod       while (arg_index < argc)
4533d8817e4Smiod 	{
4543d8817e4Smiod 	  if (! touch)
4553d8817e4Smiod 	    ranlib_only (argv[arg_index]);
4563d8817e4Smiod 	  else
4573d8817e4Smiod 	    ranlib_touch (argv[arg_index]);
4583d8817e4Smiod 	  ++arg_index;
4593d8817e4Smiod 	}
4603d8817e4Smiod       xexit (0);
4613d8817e4Smiod     }
4623d8817e4Smiod 
4633d8817e4Smiod   if (argc == 2 && strcmp (argv[1], "-M") == 0)
4643d8817e4Smiod     {
4653d8817e4Smiod       mri_emul ();
4663d8817e4Smiod       xexit (0);
4673d8817e4Smiod     }
4683d8817e4Smiod 
4693d8817e4Smiod   if (argc < 2)
4703d8817e4Smiod     usage (0);
4713d8817e4Smiod 
4723d8817e4Smiod   arg_index = 1;
4733d8817e4Smiod   arg_ptr = argv[arg_index];
4743d8817e4Smiod 
4753d8817e4Smiod   if (*arg_ptr == '-')
4763d8817e4Smiod     {
4773d8817e4Smiod       /* When the first option starts with '-' we support POSIX-compatible
4783d8817e4Smiod 	 option parsing.  */
4793d8817e4Smiod       do_posix = 1;
4803d8817e4Smiod       ++arg_ptr;			/* compatibility */
4813d8817e4Smiod     }
4823d8817e4Smiod 
4833d8817e4Smiod   do
4843d8817e4Smiod     {
4853d8817e4Smiod       while ((c = *arg_ptr++) != '\0')
4863d8817e4Smiod 	{
4873d8817e4Smiod 	  switch (c)
4883d8817e4Smiod 	    {
4893d8817e4Smiod 	    case 'd':
4903d8817e4Smiod 	    case 'm':
4913d8817e4Smiod 	    case 'p':
4923d8817e4Smiod 	    case 'q':
4933d8817e4Smiod 	    case 'r':
4943d8817e4Smiod 	    case 't':
4953d8817e4Smiod 	    case 'x':
4963d8817e4Smiod 	      if (operation != none)
4973d8817e4Smiod 		fatal (_("two different operation options specified"));
4983d8817e4Smiod 	      switch (c)
4993d8817e4Smiod 		{
5003d8817e4Smiod 		case 'd':
5013d8817e4Smiod 		  operation = delete;
5023d8817e4Smiod 		  operation_alters_arch = TRUE;
5033d8817e4Smiod 		  break;
5043d8817e4Smiod 		case 'm':
5053d8817e4Smiod 		  operation = move;
5063d8817e4Smiod 		  operation_alters_arch = TRUE;
5073d8817e4Smiod 		  break;
5083d8817e4Smiod 		case 'p':
5093d8817e4Smiod 		  operation = print_files;
5103d8817e4Smiod 		  break;
5113d8817e4Smiod 		case 'q':
5123d8817e4Smiod 		  operation = quick_append;
5133d8817e4Smiod 		  operation_alters_arch = TRUE;
5143d8817e4Smiod 		  break;
5153d8817e4Smiod 		case 'r':
5163d8817e4Smiod 		  operation = replace;
5173d8817e4Smiod 		  operation_alters_arch = TRUE;
5183d8817e4Smiod 		  break;
5193d8817e4Smiod 		case 't':
5203d8817e4Smiod 		  operation = print_table;
5213d8817e4Smiod 		  break;
5223d8817e4Smiod 		case 'x':
5233d8817e4Smiod 		  operation = extract;
5243d8817e4Smiod 		  break;
5253d8817e4Smiod 		}
5263d8817e4Smiod 	    case 'l':
5273d8817e4Smiod 	      break;
5283d8817e4Smiod 	    case 'c':
5293d8817e4Smiod 	      silent_create = 1;
5303d8817e4Smiod 	      break;
5313d8817e4Smiod 	    case 'o':
5323d8817e4Smiod 	      preserve_dates = 1;
5333d8817e4Smiod 	      break;
5343d8817e4Smiod 	    case 'V':
5353d8817e4Smiod 	      show_version = TRUE;
5363d8817e4Smiod 	      break;
5373d8817e4Smiod 	    case 's':
5383d8817e4Smiod 	      write_armap = 1;
5393d8817e4Smiod 	      break;
5403d8817e4Smiod 	    case 'S':
5413d8817e4Smiod 	      write_armap = -1;
5423d8817e4Smiod 	      break;
5433d8817e4Smiod 	    case 'u':
5443d8817e4Smiod 	      newer_only = 1;
5453d8817e4Smiod 	      break;
5463d8817e4Smiod 	    case 'v':
5473d8817e4Smiod 	      verbose = 1;
5483d8817e4Smiod 	      break;
5493d8817e4Smiod 	    case 'a':
5503d8817e4Smiod 	      postype = pos_after;
5513d8817e4Smiod 	      break;
5523d8817e4Smiod 	    case 'b':
5533d8817e4Smiod 	      postype = pos_before;
5543d8817e4Smiod 	      break;
5553d8817e4Smiod 	    case 'i':
5563d8817e4Smiod 	      postype = pos_before;
5573d8817e4Smiod 	      break;
5583d8817e4Smiod 	    case 'M':
5593d8817e4Smiod 	      mri_mode = 1;
5603d8817e4Smiod 	      break;
5613d8817e4Smiod 	    case 'N':
5623d8817e4Smiod 	      counted_name_mode = TRUE;
5633d8817e4Smiod 	      break;
5643d8817e4Smiod 	    case 'f':
5653d8817e4Smiod 	      ar_truncate = TRUE;
5663d8817e4Smiod 	      break;
5673d8817e4Smiod 	    case 'P':
5683d8817e4Smiod 	      full_pathname = TRUE;
5693d8817e4Smiod 	      break;
570*314e8fdfSguenther 	    case 'D':
571*314e8fdfSguenther 	      deterministic = TRUE;
572*314e8fdfSguenther 	      break;
573*314e8fdfSguenther 	    case 'U':
574*314e8fdfSguenther 	      deterministic = FALSE;
575*314e8fdfSguenther 	      break;
5763d8817e4Smiod 	    default:
5773d8817e4Smiod 	      /* xgettext:c-format */
5783d8817e4Smiod 	      non_fatal (_("illegal option -- %c"), c);
5793d8817e4Smiod 	      usage (0);
5803d8817e4Smiod 	    }
5813d8817e4Smiod 	}
5823d8817e4Smiod 
5833d8817e4Smiod       /* With POSIX-compatible option parsing continue with the next
5843d8817e4Smiod 	 argument if it starts with '-'.  */
5853d8817e4Smiod       if (do_posix && arg_index + 1 < argc && argv[arg_index + 1][0] == '-')
5863d8817e4Smiod 	arg_ptr = argv[++arg_index] + 1;
5873d8817e4Smiod       else
5883d8817e4Smiod 	do_posix = 0;
5893d8817e4Smiod     }
5903d8817e4Smiod   while (do_posix);
5913d8817e4Smiod 
5923d8817e4Smiod   if (show_version)
5933d8817e4Smiod     print_version ("ar");
5943d8817e4Smiod 
5953d8817e4Smiod   ++arg_index;
5963d8817e4Smiod   if (arg_index >= argc)
5973d8817e4Smiod     usage (0);
5983d8817e4Smiod 
5993d8817e4Smiod   if (mri_mode)
6003d8817e4Smiod     {
6013d8817e4Smiod       mri_emul ();
6023d8817e4Smiod     }
6033d8817e4Smiod   else
6043d8817e4Smiod     {
6053d8817e4Smiod       bfd *arch;
6063d8817e4Smiod 
6073d8817e4Smiod       /* We don't use do_quick_append any more.  Too many systems
6083d8817e4Smiod 	 expect ar to always rebuild the symbol table even when q is
6093d8817e4Smiod 	 used.  */
6103d8817e4Smiod 
6113d8817e4Smiod       /* We can't write an armap when using ar q, so just do ar r
6123d8817e4Smiod          instead.  */
6133d8817e4Smiod       if (operation == quick_append && write_armap)
6143d8817e4Smiod 	operation = replace;
6153d8817e4Smiod 
6163d8817e4Smiod       if ((operation == none || operation == print_table)
6173d8817e4Smiod 	  && write_armap == 1)
6183d8817e4Smiod 	{
6193d8817e4Smiod 	  ranlib_only (argv[arg_index]);
6203d8817e4Smiod 	  xexit (0);
6213d8817e4Smiod 	}
6223d8817e4Smiod 
6233d8817e4Smiod       if (operation == none)
6243d8817e4Smiod 	fatal (_("no operation specified"));
6253d8817e4Smiod 
6263d8817e4Smiod       if (newer_only && operation != replace)
6273d8817e4Smiod 	fatal (_("`u' is only meaningful with the `r' option."));
6283d8817e4Smiod 
6293d8817e4Smiod       if (postype != pos_default)
6303d8817e4Smiod 	posname = argv[arg_index++];
6313d8817e4Smiod 
6323d8817e4Smiod       if (counted_name_mode)
6333d8817e4Smiod 	{
6343d8817e4Smiod 	  if (operation != extract && operation != delete)
6353d8817e4Smiod 	     fatal (_("`N' is only meaningful with the `x' and `d' options."));
6363d8817e4Smiod 	  counted_name_counter = atoi (argv[arg_index++]);
6373d8817e4Smiod 	  if (counted_name_counter <= 0)
6383d8817e4Smiod 	    fatal (_("Value for `N' must be positive."));
6393d8817e4Smiod 	}
6403d8817e4Smiod 
6413d8817e4Smiod       inarch_filename = argv[arg_index++];
6423d8817e4Smiod 
6433d8817e4Smiod       files = arg_index < argc ? argv + arg_index : NULL;
6443d8817e4Smiod       file_count = argc - arg_index;
6453d8817e4Smiod 
6463d8817e4Smiod       arch = open_inarch (inarch_filename,
6473d8817e4Smiod 			  files == NULL ? (char *) NULL : files[0]);
6483d8817e4Smiod 
6493d8817e4Smiod       switch (operation)
6503d8817e4Smiod 	{
6513d8817e4Smiod 	case print_table:
6523d8817e4Smiod 	  map_over_members (arch, print_descr, files, file_count);
6533d8817e4Smiod 	  break;
6543d8817e4Smiod 
6553d8817e4Smiod 	case print_files:
6563d8817e4Smiod 	  map_over_members (arch, print_contents, files, file_count);
6573d8817e4Smiod 	  break;
6583d8817e4Smiod 
6593d8817e4Smiod 	case extract:
6603d8817e4Smiod 	  map_over_members (arch, extract_file, files, file_count);
6613d8817e4Smiod 	  break;
6623d8817e4Smiod 
6633d8817e4Smiod 	case delete:
6643d8817e4Smiod 	  if (files != NULL)
6653d8817e4Smiod 	    delete_members (arch, files);
6663d8817e4Smiod 	  else
6673d8817e4Smiod 	    output_filename = NULL;
6683d8817e4Smiod 	  break;
6693d8817e4Smiod 
6703d8817e4Smiod 	case move:
6713d8817e4Smiod 	  if (files != NULL)
6723d8817e4Smiod 	    move_members (arch, files);
6733d8817e4Smiod 	  else
6743d8817e4Smiod 	    output_filename = NULL;
6753d8817e4Smiod 	  break;
6763d8817e4Smiod 
6773d8817e4Smiod 	case replace:
6783d8817e4Smiod 	case quick_append:
6793d8817e4Smiod 	  if (files != NULL || write_armap > 0)
6803d8817e4Smiod 	    replace_members (arch, files, operation == quick_append);
6813d8817e4Smiod 	  else
6823d8817e4Smiod 	    output_filename = NULL;
6833d8817e4Smiod 	  break;
6843d8817e4Smiod 
6853d8817e4Smiod 	  /* Shouldn't happen! */
6863d8817e4Smiod 	default:
6873d8817e4Smiod 	  /* xgettext:c-format */
6883d8817e4Smiod 	  fatal (_("internal error -- this option not implemented"));
6893d8817e4Smiod 	}
6903d8817e4Smiod     }
6913d8817e4Smiod 
6923d8817e4Smiod   END_PROGRESS (program_name);
6933d8817e4Smiod 
6943d8817e4Smiod   xexit (0);
6953d8817e4Smiod   return 0;
6963d8817e4Smiod }
6973d8817e4Smiod 
6983d8817e4Smiod bfd *
open_inarch(const char * archive_filename,const char * file)6993d8817e4Smiod open_inarch (const char *archive_filename, const char *file)
7003d8817e4Smiod {
7013d8817e4Smiod   const char *target;
7023d8817e4Smiod   bfd **last_one;
7033d8817e4Smiod   bfd *next_one;
7043d8817e4Smiod   struct stat sbuf;
7053d8817e4Smiod   bfd *arch;
7063d8817e4Smiod   char **matching;
7073d8817e4Smiod 
7083d8817e4Smiod   bfd_set_error (bfd_error_no_error);
7093d8817e4Smiod 
7103d8817e4Smiod   target = NULL;
7113d8817e4Smiod 
7123d8817e4Smiod   if (stat (archive_filename, &sbuf) != 0)
7133d8817e4Smiod     {
7143d8817e4Smiod #if !defined(__GO32__) || defined(__DJGPP__)
7153d8817e4Smiod 
7163d8817e4Smiod       /* FIXME: I don't understand why this fragment was ifndef'ed
7173d8817e4Smiod 	 away for __GO32__; perhaps it was in the days of DJGPP v1.x.
7183d8817e4Smiod 	 stat() works just fine in v2.x, so I think this should be
7193d8817e4Smiod 	 removed.  For now, I enable it for DJGPP v2. -- EZ.  */
7203d8817e4Smiod 
7213d8817e4Smiod /* KLUDGE ALERT! Temporary fix until I figger why
7223d8817e4Smiod    stat() is wrong ... think it's buried in GO32's IDT - Jax */
7233d8817e4Smiod       if (errno != ENOENT)
7243d8817e4Smiod 	bfd_fatal (archive_filename);
7253d8817e4Smiod #endif
7263d8817e4Smiod 
7273d8817e4Smiod       if (!operation_alters_arch)
7283d8817e4Smiod 	{
7293d8817e4Smiod 	  fprintf (stderr, "%s: ", program_name);
7303d8817e4Smiod 	  perror (archive_filename);
7313d8817e4Smiod 	  maybequit ();
7323d8817e4Smiod 	  return NULL;
7333d8817e4Smiod 	}
7343d8817e4Smiod 
7353d8817e4Smiod       /* Try to figure out the target to use for the archive from the
7363d8817e4Smiod          first object on the list.  */
7373d8817e4Smiod       if (file != NULL)
7383d8817e4Smiod 	{
7393d8817e4Smiod 	  bfd *obj;
7403d8817e4Smiod 
7413d8817e4Smiod 	  obj = bfd_openr (file, NULL);
7423d8817e4Smiod 	  if (obj != NULL)
7433d8817e4Smiod 	    {
7443d8817e4Smiod 	      if (bfd_check_format (obj, bfd_object))
7453d8817e4Smiod 		target = bfd_get_target (obj);
7463d8817e4Smiod 	      (void) bfd_close (obj);
7473d8817e4Smiod 	    }
7483d8817e4Smiod 	}
7493d8817e4Smiod 
7503d8817e4Smiod       /* Create an empty archive.  */
7513d8817e4Smiod       arch = bfd_openw (archive_filename, target);
7523d8817e4Smiod       if (arch == NULL
7533d8817e4Smiod 	  || ! bfd_set_format (arch, bfd_archive)
7543d8817e4Smiod 	  || ! bfd_close (arch))
7553d8817e4Smiod 	bfd_fatal (archive_filename);
7563d8817e4Smiod       else if (!silent_create)
7573d8817e4Smiod         non_fatal (_("creating %s"), archive_filename);
7583d8817e4Smiod 
7593d8817e4Smiod       /* If we die creating a new archive, don't leave it around.  */
7603d8817e4Smiod       output_filename = archive_filename;
7613d8817e4Smiod     }
7623d8817e4Smiod 
7633d8817e4Smiod   arch = bfd_openr (archive_filename, target);
7643d8817e4Smiod   if (arch == NULL)
7653d8817e4Smiod     {
7663d8817e4Smiod     bloser:
7673d8817e4Smiod       bfd_fatal (archive_filename);
7683d8817e4Smiod     }
7693d8817e4Smiod 
7703d8817e4Smiod   if (! bfd_check_format_matches (arch, bfd_archive, &matching))
7713d8817e4Smiod     {
7723d8817e4Smiod       bfd_nonfatal (archive_filename);
7733d8817e4Smiod       if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
7743d8817e4Smiod 	{
7753d8817e4Smiod 	  list_matching_formats (matching);
7763d8817e4Smiod 	  free (matching);
7773d8817e4Smiod 	}
7783d8817e4Smiod       xexit (1);
7793d8817e4Smiod     }
7803d8817e4Smiod 
7813d8817e4Smiod   last_one = &(arch->next);
7823d8817e4Smiod   /* Read all the contents right away, regardless.  */
7833d8817e4Smiod   for (next_one = bfd_openr_next_archived_file (arch, NULL);
7843d8817e4Smiod        next_one;
7853d8817e4Smiod        next_one = bfd_openr_next_archived_file (arch, next_one))
7863d8817e4Smiod     {
7873d8817e4Smiod       PROGRESS (1);
7883d8817e4Smiod       *last_one = next_one;
7893d8817e4Smiod       last_one = &next_one->next;
7903d8817e4Smiod     }
7913d8817e4Smiod   *last_one = (bfd *) NULL;
7923d8817e4Smiod   if (bfd_get_error () != bfd_error_no_more_archived_files)
7933d8817e4Smiod     goto bloser;
7943d8817e4Smiod   return arch;
7953d8817e4Smiod }
7963d8817e4Smiod 
7973d8817e4Smiod static void
print_contents(bfd * abfd)7983d8817e4Smiod print_contents (bfd *abfd)
7993d8817e4Smiod {
8003d8817e4Smiod   int ncopied = 0;
8013d8817e4Smiod   char *cbuf = xmalloc (BUFSIZE);
8023d8817e4Smiod   struct stat buf;
8033d8817e4Smiod   long size;
8043d8817e4Smiod   if (bfd_stat_arch_elt (abfd, &buf) != 0)
8053d8817e4Smiod     /* xgettext:c-format */
8063d8817e4Smiod     fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
8073d8817e4Smiod 
8083d8817e4Smiod   if (verbose)
8093d8817e4Smiod     /* xgettext:c-format */
8103d8817e4Smiod     printf (_("\n<%s>\n\n"), bfd_get_filename (abfd));
8113d8817e4Smiod 
8123d8817e4Smiod   bfd_seek (abfd, (file_ptr) 0, SEEK_SET);
8133d8817e4Smiod 
8143d8817e4Smiod   size = buf.st_size;
8153d8817e4Smiod   while (ncopied < size)
8163d8817e4Smiod     {
8173d8817e4Smiod 
8183d8817e4Smiod       int nread;
8193d8817e4Smiod       int tocopy = size - ncopied;
8203d8817e4Smiod       if (tocopy > BUFSIZE)
8213d8817e4Smiod 	tocopy = BUFSIZE;
8223d8817e4Smiod 
8233d8817e4Smiod       nread = bfd_bread (cbuf, (bfd_size_type) tocopy, abfd);
8243d8817e4Smiod       if (nread != tocopy)
8253d8817e4Smiod 	/* xgettext:c-format */
8263d8817e4Smiod 	fatal (_("%s is not a valid archive"),
8273d8817e4Smiod 	       bfd_get_filename (bfd_my_archive (abfd)));
8283d8817e4Smiod       fwrite (cbuf, 1, nread, stdout);
8293d8817e4Smiod       ncopied += tocopy;
8303d8817e4Smiod     }
8313d8817e4Smiod   free (cbuf);
8323d8817e4Smiod }
8333d8817e4Smiod 
8343d8817e4Smiod /* Extract a member of the archive into its own file.
8353d8817e4Smiod 
8363d8817e4Smiod    We defer opening the new file until after we have read a BUFSIZ chunk of the
8373d8817e4Smiod    old one, since we know we have just read the archive header for the old
8383d8817e4Smiod    one.  Since most members are shorter than BUFSIZ, this means we will read
8393d8817e4Smiod    the old header, read the old data, write a new inode for the new file, and
8403d8817e4Smiod    write the new data, and be done. This 'optimization' is what comes from
8413d8817e4Smiod    sitting next to a bare disk and hearing it every time it seeks.  -- Gnu
8423d8817e4Smiod    Gilmore  */
8433d8817e4Smiod 
8443d8817e4Smiod void
extract_file(bfd * abfd)8453d8817e4Smiod extract_file (bfd *abfd)
8463d8817e4Smiod {
8473d8817e4Smiod   FILE *ostream;
8483d8817e4Smiod   char *cbuf = xmalloc (BUFSIZE);
8493d8817e4Smiod   int nread, tocopy;
8503d8817e4Smiod   long ncopied = 0;
8513d8817e4Smiod   long size;
8523d8817e4Smiod   struct stat buf;
8533d8817e4Smiod 
8543d8817e4Smiod   if (bfd_stat_arch_elt (abfd, &buf) != 0)
8553d8817e4Smiod     /* xgettext:c-format */
8563d8817e4Smiod     fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
8573d8817e4Smiod   size = buf.st_size;
8583d8817e4Smiod 
8593d8817e4Smiod   if (size < 0)
8603d8817e4Smiod     /* xgettext:c-format */
8613d8817e4Smiod     fatal (_("stat returns negative size for %s"), bfd_get_filename (abfd));
8623d8817e4Smiod 
8633d8817e4Smiod   if (verbose)
8643d8817e4Smiod     printf ("x - %s\n", bfd_get_filename (abfd));
8653d8817e4Smiod 
8663d8817e4Smiod   bfd_seek (abfd, (file_ptr) 0, SEEK_SET);
8673d8817e4Smiod 
8683d8817e4Smiod   ostream = NULL;
8693d8817e4Smiod   if (size == 0)
8703d8817e4Smiod     {
8713d8817e4Smiod       /* Seems like an abstraction violation, eh?  Well it's OK! */
8723d8817e4Smiod       output_filename = bfd_get_filename (abfd);
8733d8817e4Smiod 
8743d8817e4Smiod       ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
8753d8817e4Smiod       if (ostream == NULL)
8763d8817e4Smiod 	{
8773d8817e4Smiod 	  perror (bfd_get_filename (abfd));
8783d8817e4Smiod 	  xexit (1);
8793d8817e4Smiod 	}
8803d8817e4Smiod 
8813d8817e4Smiod       output_file = ostream;
8823d8817e4Smiod     }
8833d8817e4Smiod   else
8843d8817e4Smiod     while (ncopied < size)
8853d8817e4Smiod       {
8863d8817e4Smiod 	tocopy = size - ncopied;
8873d8817e4Smiod 	if (tocopy > BUFSIZE)
8883d8817e4Smiod 	  tocopy = BUFSIZE;
8893d8817e4Smiod 
8903d8817e4Smiod 	nread = bfd_bread (cbuf, (bfd_size_type) tocopy, abfd);
8913d8817e4Smiod 	if (nread != tocopy)
8923d8817e4Smiod 	  /* xgettext:c-format */
8933d8817e4Smiod 	  fatal (_("%s is not a valid archive"),
8943d8817e4Smiod 		 bfd_get_filename (bfd_my_archive (abfd)));
8953d8817e4Smiod 
8963d8817e4Smiod 	/* See comment above; this saves disk arm motion */
8973d8817e4Smiod 	if (ostream == NULL)
8983d8817e4Smiod 	  {
8993d8817e4Smiod 	    /* Seems like an abstraction violation, eh?  Well it's OK! */
9003d8817e4Smiod 	    output_filename = bfd_get_filename (abfd);
9013d8817e4Smiod 
9023d8817e4Smiod 	    ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
9033d8817e4Smiod 	    if (ostream == NULL)
9043d8817e4Smiod 	      {
9053d8817e4Smiod 		perror (bfd_get_filename (abfd));
9063d8817e4Smiod 		xexit (1);
9073d8817e4Smiod 	      }
9083d8817e4Smiod 
9093d8817e4Smiod 	    output_file = ostream;
9103d8817e4Smiod 	  }
9113d8817e4Smiod 	fwrite (cbuf, 1, nread, ostream);
9123d8817e4Smiod 	ncopied += tocopy;
9133d8817e4Smiod       }
9143d8817e4Smiod 
9153d8817e4Smiod   if (ostream != NULL)
9163d8817e4Smiod     fclose (ostream);
9173d8817e4Smiod 
9183d8817e4Smiod   output_file = NULL;
9193d8817e4Smiod   output_filename = NULL;
9203d8817e4Smiod 
9210153a938Sderaadt   chmod (bfd_get_filename (abfd), buf.st_mode & 0777);
9223d8817e4Smiod 
9233d8817e4Smiod   if (preserve_dates)
9243d8817e4Smiod     {
9253d8817e4Smiod       /* Set access time to modification time.  Only st_mtime is
9263d8817e4Smiod 	 initialized by bfd_stat_arch_elt.  */
9273d8817e4Smiod       buf.st_atime = buf.st_mtime;
9283d8817e4Smiod       set_times (bfd_get_filename (abfd), &buf);
9293d8817e4Smiod     }
9303d8817e4Smiod 
9313d8817e4Smiod   free (cbuf);
9323d8817e4Smiod }
9333d8817e4Smiod 
9343d8817e4Smiod static void
write_archive(bfd * iarch)9353d8817e4Smiod write_archive (bfd *iarch)
9363d8817e4Smiod {
9373d8817e4Smiod   bfd *obfd;
9383d8817e4Smiod   char *old_name, *new_name;
9393d8817e4Smiod   bfd *contents_head = iarch->next;
9403d8817e4Smiod 
9413d8817e4Smiod   old_name = xmalloc (strlen (bfd_get_filename (iarch)) + 1);
9423d8817e4Smiod   strcpy (old_name, bfd_get_filename (iarch));
943d2386abeSmiod   new_name = make_tempname (old_name, 0);
9443d8817e4Smiod 
9453d8817e4Smiod   output_filename = new_name;
9463d8817e4Smiod 
9473d8817e4Smiod   obfd = bfd_openw (new_name, bfd_get_target (iarch));
9483d8817e4Smiod 
9493d8817e4Smiod   if (obfd == NULL)
9503d8817e4Smiod     bfd_fatal (old_name);
9513d8817e4Smiod 
9523d8817e4Smiod   output_bfd = obfd;
9533d8817e4Smiod 
9543d8817e4Smiod   bfd_set_format (obfd, bfd_archive);
9553d8817e4Smiod 
9563d8817e4Smiod   /* Request writing the archive symbol table unless we've
9573d8817e4Smiod      been explicitly requested not to.  */
9583d8817e4Smiod   obfd->has_armap = write_armap >= 0;
9593d8817e4Smiod 
9603d8817e4Smiod   if (ar_truncate)
9613d8817e4Smiod     {
9623d8817e4Smiod       /* This should really use bfd_set_file_flags, but that rejects
9633d8817e4Smiod          archives.  */
9643d8817e4Smiod       obfd->flags |= BFD_TRADITIONAL_FORMAT;
9653d8817e4Smiod     }
9663d8817e4Smiod 
967*314e8fdfSguenther   if (deterministic)
968*314e8fdfSguenther     obfd->flags |= BFD_DETERMINISTIC;
969*314e8fdfSguenther 
9703d8817e4Smiod   if (!bfd_set_archive_head (obfd, contents_head))
9713d8817e4Smiod     bfd_fatal (old_name);
9723d8817e4Smiod 
9733d8817e4Smiod   if (!bfd_close (obfd))
9743d8817e4Smiod     bfd_fatal (old_name);
9753d8817e4Smiod 
9763d8817e4Smiod   output_bfd = NULL;
9773d8817e4Smiod   output_filename = NULL;
9783d8817e4Smiod 
9793d8817e4Smiod   /* We don't care if this fails; we might be creating the archive.  */
9803d8817e4Smiod   bfd_close (iarch);
9813d8817e4Smiod 
9823d8817e4Smiod   if (smart_rename (new_name, old_name, 0) != 0)
9833d8817e4Smiod     xexit (1);
9843d8817e4Smiod }
9853d8817e4Smiod 
9863d8817e4Smiod /* Return a pointer to the pointer to the entry which should be rplacd'd
9873d8817e4Smiod    into when altering.  DEFAULT_POS should be how to interpret pos_default,
9883d8817e4Smiod    and should be a pos value.  */
9893d8817e4Smiod 
9903d8817e4Smiod static bfd **
get_pos_bfd(bfd ** contents,enum pos default_pos,const char * default_posname)9913d8817e4Smiod get_pos_bfd (bfd **contents, enum pos default_pos, const char *default_posname)
9923d8817e4Smiod {
9933d8817e4Smiod   bfd **after_bfd = contents;
9943d8817e4Smiod   enum pos realpos;
9953d8817e4Smiod   const char *realposname;
9963d8817e4Smiod 
9973d8817e4Smiod   if (postype == pos_default)
9983d8817e4Smiod     {
9993d8817e4Smiod       realpos = default_pos;
10003d8817e4Smiod       realposname = default_posname;
10013d8817e4Smiod     }
10023d8817e4Smiod   else
10033d8817e4Smiod     {
10043d8817e4Smiod       realpos = postype;
10053d8817e4Smiod       realposname = posname;
10063d8817e4Smiod     }
10073d8817e4Smiod 
10083d8817e4Smiod   if (realpos == pos_end)
10093d8817e4Smiod     {
10103d8817e4Smiod       while (*after_bfd)
10113d8817e4Smiod 	after_bfd = &((*after_bfd)->next);
10123d8817e4Smiod     }
10133d8817e4Smiod   else
10143d8817e4Smiod     {
10153d8817e4Smiod       for (; *after_bfd; after_bfd = &(*after_bfd)->next)
10163d8817e4Smiod 	if (FILENAME_CMP ((*after_bfd)->filename, realposname) == 0)
10173d8817e4Smiod 	  {
10183d8817e4Smiod 	    if (realpos == pos_after)
10193d8817e4Smiod 	      after_bfd = &(*after_bfd)->next;
10203d8817e4Smiod 	    break;
10213d8817e4Smiod 	  }
10223d8817e4Smiod     }
10233d8817e4Smiod   return after_bfd;
10243d8817e4Smiod }
10253d8817e4Smiod 
10263d8817e4Smiod static void
delete_members(bfd * arch,char ** files_to_delete)10273d8817e4Smiod delete_members (bfd *arch, char **files_to_delete)
10283d8817e4Smiod {
10293d8817e4Smiod   bfd **current_ptr_ptr;
10303d8817e4Smiod   bfd_boolean found;
10313d8817e4Smiod   bfd_boolean something_changed = FALSE;
10323d8817e4Smiod   int match_count;
10333d8817e4Smiod 
10343d8817e4Smiod   for (; *files_to_delete != NULL; ++files_to_delete)
10353d8817e4Smiod     {
10363d8817e4Smiod       /* In a.out systems, the armap is optional.  It's also called
10373d8817e4Smiod 	 __.SYMDEF.  So if the user asked to delete it, we should remember
10383d8817e4Smiod 	 that fact. This isn't quite right for COFF systems (where
10393d8817e4Smiod 	 __.SYMDEF might be regular member), but it's very unlikely
10403d8817e4Smiod 	 to be a problem.  FIXME */
10413d8817e4Smiod 
10423d8817e4Smiod       if (!strcmp (*files_to_delete, "__.SYMDEF"))
10433d8817e4Smiod 	{
10443d8817e4Smiod 	  arch->has_armap = FALSE;
10453d8817e4Smiod 	  write_armap = -1;
10463d8817e4Smiod 	  continue;
10473d8817e4Smiod 	}
10483d8817e4Smiod 
10493d8817e4Smiod       found = FALSE;
10503d8817e4Smiod       match_count = 0;
10513d8817e4Smiod       current_ptr_ptr = &(arch->next);
10523d8817e4Smiod       while (*current_ptr_ptr)
10533d8817e4Smiod 	{
10543d8817e4Smiod 	  if (FILENAME_CMP (normalize (*files_to_delete, arch),
10553d8817e4Smiod 			    (*current_ptr_ptr)->filename) == 0)
10563d8817e4Smiod 	    {
10573d8817e4Smiod 	      ++match_count;
10583d8817e4Smiod 	      if (counted_name_mode
10593d8817e4Smiod 		  && match_count != counted_name_counter)
10603d8817e4Smiod 		{
10613d8817e4Smiod 		  /* Counting, and didn't match on count; go on to the
10623d8817e4Smiod                      next one.  */
10633d8817e4Smiod 		}
10643d8817e4Smiod 	      else
10653d8817e4Smiod 		{
10663d8817e4Smiod 		  found = TRUE;
10673d8817e4Smiod 		  something_changed = TRUE;
10683d8817e4Smiod 		  if (verbose)
10693d8817e4Smiod 		    printf ("d - %s\n",
10703d8817e4Smiod 			    *files_to_delete);
10713d8817e4Smiod 		  *current_ptr_ptr = ((*current_ptr_ptr)->next);
10723d8817e4Smiod 		  goto next_file;
10733d8817e4Smiod 		}
10743d8817e4Smiod 	    }
10753d8817e4Smiod 
10763d8817e4Smiod 	  current_ptr_ptr = &((*current_ptr_ptr)->next);
10773d8817e4Smiod 	}
10783d8817e4Smiod 
10793d8817e4Smiod       if (verbose && !found)
10803d8817e4Smiod 	{
10813d8817e4Smiod 	  /* xgettext:c-format */
10823d8817e4Smiod 	  printf (_("No member named `%s'\n"), *files_to_delete);
10833d8817e4Smiod 	}
10843d8817e4Smiod     next_file:
10853d8817e4Smiod       ;
10863d8817e4Smiod     }
10873d8817e4Smiod 
10883d8817e4Smiod   if (something_changed)
10893d8817e4Smiod     write_archive (arch);
10903d8817e4Smiod   else
10913d8817e4Smiod     output_filename = NULL;
10923d8817e4Smiod }
10933d8817e4Smiod 
10943d8817e4Smiod 
10953d8817e4Smiod /* Reposition existing members within an archive */
10963d8817e4Smiod 
10973d8817e4Smiod static void
move_members(bfd * arch,char ** files_to_move)10983d8817e4Smiod move_members (bfd *arch, char **files_to_move)
10993d8817e4Smiod {
11003d8817e4Smiod   bfd **after_bfd;		/* New entries go after this one */
11013d8817e4Smiod   bfd **current_ptr_ptr;	/* cdr pointer into contents */
11023d8817e4Smiod 
11033d8817e4Smiod   for (; *files_to_move; ++files_to_move)
11043d8817e4Smiod     {
11053d8817e4Smiod       current_ptr_ptr = &(arch->next);
11063d8817e4Smiod       while (*current_ptr_ptr)
11073d8817e4Smiod 	{
11083d8817e4Smiod 	  bfd *current_ptr = *current_ptr_ptr;
11093d8817e4Smiod 	  if (FILENAME_CMP (normalize (*files_to_move, arch),
11103d8817e4Smiod 			    current_ptr->filename) == 0)
11113d8817e4Smiod 	    {
11123d8817e4Smiod 	      /* Move this file to the end of the list - first cut from
11133d8817e4Smiod 		 where it is.  */
11143d8817e4Smiod 	      bfd *link;
11153d8817e4Smiod 	      *current_ptr_ptr = current_ptr->next;
11163d8817e4Smiod 
11173d8817e4Smiod 	      /* Now glue to end */
11183d8817e4Smiod 	      after_bfd = get_pos_bfd (&arch->next, pos_end, NULL);
11193d8817e4Smiod 	      link = *after_bfd;
11203d8817e4Smiod 	      *after_bfd = current_ptr;
11213d8817e4Smiod 	      current_ptr->next = link;
11223d8817e4Smiod 
11233d8817e4Smiod 	      if (verbose)
11243d8817e4Smiod 		printf ("m - %s\n", *files_to_move);
11253d8817e4Smiod 
11263d8817e4Smiod 	      goto next_file;
11273d8817e4Smiod 	    }
11283d8817e4Smiod 
11293d8817e4Smiod 	  current_ptr_ptr = &((*current_ptr_ptr)->next);
11303d8817e4Smiod 	}
11313d8817e4Smiod       /* xgettext:c-format */
11323d8817e4Smiod       fatal (_("no entry %s in archive %s!"), *files_to_move, arch->filename);
11333d8817e4Smiod 
11343d8817e4Smiod     next_file:;
11353d8817e4Smiod     }
11363d8817e4Smiod 
11373d8817e4Smiod   write_archive (arch);
11383d8817e4Smiod }
11393d8817e4Smiod 
11403d8817e4Smiod /* Ought to default to replacing in place, but this is existing practice!  */
11413d8817e4Smiod 
11423d8817e4Smiod static void
replace_members(bfd * arch,char ** files_to_move,bfd_boolean quick)11433d8817e4Smiod replace_members (bfd *arch, char **files_to_move, bfd_boolean quick)
11443d8817e4Smiod {
11453d8817e4Smiod   bfd_boolean changed = FALSE;
11463d8817e4Smiod   bfd **after_bfd;		/* New entries go after this one.  */
11473d8817e4Smiod   bfd *current;
11483d8817e4Smiod   bfd **current_ptr;
11493d8817e4Smiod 
11503d8817e4Smiod   while (files_to_move && *files_to_move)
11513d8817e4Smiod     {
11523d8817e4Smiod       if (! quick)
11533d8817e4Smiod 	{
11543d8817e4Smiod 	  current_ptr = &arch->next;
11553d8817e4Smiod 	  while (*current_ptr)
11563d8817e4Smiod 	    {
11573d8817e4Smiod 	      current = *current_ptr;
11583d8817e4Smiod 
11593d8817e4Smiod 	      /* For compatibility with existing ar programs, we
11603d8817e4Smiod 		 permit the same file to be added multiple times.  */
11613d8817e4Smiod 	      if (FILENAME_CMP (normalize (*files_to_move, arch),
11623d8817e4Smiod 				normalize (current->filename, arch)) == 0
11633d8817e4Smiod 		  && current->arelt_data != NULL)
11643d8817e4Smiod 		{
11653d8817e4Smiod 		  if (newer_only)
11663d8817e4Smiod 		    {
11673d8817e4Smiod 		      struct stat fsbuf, asbuf;
11683d8817e4Smiod 
11693d8817e4Smiod 		      if (stat (*files_to_move, &fsbuf) != 0)
11703d8817e4Smiod 			{
11713d8817e4Smiod 			  if (errno != ENOENT)
11723d8817e4Smiod 			    bfd_fatal (*files_to_move);
11733d8817e4Smiod 			  goto next_file;
11743d8817e4Smiod 			}
11753d8817e4Smiod 		      if (bfd_stat_arch_elt (current, &asbuf) != 0)
11763d8817e4Smiod 			/* xgettext:c-format */
11773d8817e4Smiod 			fatal (_("internal stat error on %s"),
11783d8817e4Smiod 			       current->filename);
11793d8817e4Smiod 
11803d8817e4Smiod 		      if (fsbuf.st_mtime <= asbuf.st_mtime)
11813d8817e4Smiod 			goto next_file;
11823d8817e4Smiod 		    }
11833d8817e4Smiod 
11843d8817e4Smiod 		  after_bfd = get_pos_bfd (&arch->next, pos_after,
11853d8817e4Smiod 					   current->filename);
11863d8817e4Smiod 		  if (ar_emul_replace (after_bfd, *files_to_move,
11873d8817e4Smiod 				       verbose))
11883d8817e4Smiod 		    {
11893d8817e4Smiod 		      /* Snip out this entry from the chain.  */
11903d8817e4Smiod 		      *current_ptr = (*current_ptr)->next;
11913d8817e4Smiod 		      changed = TRUE;
11923d8817e4Smiod 		    }
11933d8817e4Smiod 
11943d8817e4Smiod 		  goto next_file;
11953d8817e4Smiod 		}
11963d8817e4Smiod 	      current_ptr = &(current->next);
11973d8817e4Smiod 	    }
11983d8817e4Smiod 	}
11993d8817e4Smiod 
12003d8817e4Smiod       /* Add to the end of the archive.  */
12013d8817e4Smiod       after_bfd = get_pos_bfd (&arch->next, pos_end, NULL);
12023d8817e4Smiod 
12033d8817e4Smiod       if (ar_emul_append (after_bfd, *files_to_move, verbose))
12043d8817e4Smiod 	changed = TRUE;
12053d8817e4Smiod 
12063d8817e4Smiod     next_file:;
12073d8817e4Smiod 
12083d8817e4Smiod       files_to_move++;
12093d8817e4Smiod     }
12103d8817e4Smiod 
12113d8817e4Smiod   if (changed)
12123d8817e4Smiod     write_archive (arch);
12133d8817e4Smiod   else
12143d8817e4Smiod     output_filename = NULL;
12153d8817e4Smiod }
12163d8817e4Smiod 
12173d8817e4Smiod static void
ranlib_only(const char * archname)12183d8817e4Smiod ranlib_only (const char *archname)
12193d8817e4Smiod {
12203d8817e4Smiod   bfd *arch;
12213d8817e4Smiod 
12223d8817e4Smiod   if (get_file_size (archname) < 1)
12233d8817e4Smiod     return;
12243d8817e4Smiod   write_armap = 1;
12253d8817e4Smiod   arch = open_inarch (archname, (char *) NULL);
12263d8817e4Smiod   if (arch == NULL)
12273d8817e4Smiod     xexit (1);
12283d8817e4Smiod   write_archive (arch);
12293d8817e4Smiod }
12303d8817e4Smiod 
12313d8817e4Smiod /* Update the timestamp of the symbol map of an archive.  */
12323d8817e4Smiod 
12333d8817e4Smiod static void
ranlib_touch(const char * archname)12343d8817e4Smiod ranlib_touch (const char *archname)
12353d8817e4Smiod {
12363d8817e4Smiod #ifdef __GO32__
12373d8817e4Smiod   /* I don't think updating works on go32.  */
12383d8817e4Smiod   ranlib_only (archname);
12393d8817e4Smiod #else
12403d8817e4Smiod   int f;
12413d8817e4Smiod   bfd *arch;
12423d8817e4Smiod   char **matching;
12433d8817e4Smiod 
12443d8817e4Smiod   if (get_file_size (archname) < 1)
12453d8817e4Smiod     return;
12463d8817e4Smiod   f = open (archname, O_RDWR | O_BINARY, 0);
12473d8817e4Smiod   if (f < 0)
12483d8817e4Smiod     {
12493d8817e4Smiod       bfd_set_error (bfd_error_system_call);
12503d8817e4Smiod       bfd_fatal (archname);
12513d8817e4Smiod     }
12523d8817e4Smiod 
12533d8817e4Smiod   arch = bfd_fdopenr (archname, (const char *) NULL, f);
12543d8817e4Smiod   if (arch == NULL)
12553d8817e4Smiod     bfd_fatal (archname);
12563d8817e4Smiod   if (! bfd_check_format_matches (arch, bfd_archive, &matching))
12573d8817e4Smiod     {
12583d8817e4Smiod       bfd_nonfatal (archname);
12593d8817e4Smiod       if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
12603d8817e4Smiod 	{
12613d8817e4Smiod 	  list_matching_formats (matching);
12623d8817e4Smiod 	  free (matching);
12633d8817e4Smiod 	}
12643d8817e4Smiod       xexit (1);
12653d8817e4Smiod     }
12663d8817e4Smiod 
12673d8817e4Smiod   if (! bfd_has_map (arch))
12683d8817e4Smiod     /* xgettext:c-format */
12693d8817e4Smiod     fatal (_("%s: no archive map to update"), archname);
12703d8817e4Smiod 
12713d8817e4Smiod   bfd_update_armap_timestamp (arch);
12723d8817e4Smiod 
12733d8817e4Smiod   if (! bfd_close (arch))
12743d8817e4Smiod     bfd_fatal (archname);
12753d8817e4Smiod #endif
12763d8817e4Smiod }
12773d8817e4Smiod 
12783d8817e4Smiod /* Things which are interesting to map over all or some of the files: */
12793d8817e4Smiod 
12803d8817e4Smiod static void
print_descr(bfd * abfd)12813d8817e4Smiod print_descr (bfd *abfd)
12823d8817e4Smiod {
12833d8817e4Smiod   print_arelt_descr (stdout, abfd, verbose);
12843d8817e4Smiod }
1285