ChangeLog rotatation and copyright year update
[deliverable/binutils-gdb.git] / binutils / ar.c
index a5ae4f001a1d0efd502d4fe0e9f72f88473ac321..48a052c2a8cde930edb55f92d2c25747fafd9c8c 100644 (file)
@@ -1,7 +1,5 @@
 /* ar.c - Archive modify and extract.
-   Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
-   Free Software Foundation, Inc.
+   Copyright (C) 1991-2015 Free Software Foundation, Inc.
 
    This file is part of GNU Binutils.
 
@@ -37,7 +35,6 @@
 #include "filenames.h"
 #include "binemul.h"
 #include "plugin.h"
-#include <sys/stat.h>
 
 #ifdef __GO32___
 #define EXT_NAME_LEN 3         /* Bufflen of addition to name if it's MS-DOS.  */
@@ -97,7 +94,7 @@ int write_armap = 0;
 /* Operate in deterministic mode: write zero for timestamps, uids,
    and gids for archive members and the archive symbol table, and write
    consistent file modes.  */
-int deterministic = 0;
+int deterministic = -1;                        /* Determinism indeterminate.  */
 
 /* Nonzero means it's the name of an existing member; position new or moved
    files with respect to this one.  */
@@ -141,7 +138,11 @@ static int show_version = 0;
 
 static int show_help = 0;
 
+#if BFD_SUPPORTS_PLUGINS
+static const char *plugin_target = "plugin";
+#else
 static const char *plugin_target = NULL;
+#endif
 
 static const char *target = NULL;
 
@@ -192,6 +193,9 @@ map_over_members (bfd *arch, void (*function)(bfd *), char **files, int count)
      mapping over each file each time -- we want to hack multiple
      references.  */
 
+  for (head = arch->archive_next; head; head = head->archive_next)
+    head->archive_pass = 0;
+
   for (; count > 0; files++, count--)
     {
       bfd_boolean found = FALSE;
@@ -202,6 +206,14 @@ map_over_members (bfd *arch, void (*function)(bfd *), char **files, int count)
          const char * filename;
 
          PROGRESS (1);
+         /* PR binutils/15796: Once an archive element has been matched
+            do not match it again.  If the user provides multiple same-named
+            parameters on the command line their intent is to match multiple
+            same-named entries in the archive, not the same entry multiple
+            times.  */
+         if (head->archive_pass)
+           continue;
+
          filename = head->filename;
          if (filename == NULL)
            {
@@ -216,8 +228,8 @@ map_over_members (bfd *arch, void (*function)(bfd *), char **files, int count)
              filename = normalize (filename, arch);
            }
 
-         if ((filename != NULL) &&
-             (!FILENAME_CMP (normalize (*files, arch), filename)))
+         if (filename != NULL
+             && !FILENAME_CMP (normalize (*files, arch), filename))
            {
              ++match_count;
              if (counted_name_mode
@@ -230,6 +242,13 @@ map_over_members (bfd *arch, void (*function)(bfd *), char **files, int count)
 
              found = TRUE;
              function (head);
+             head->archive_pass = 1;
+             /* PR binutils/15796: Once a file has been matched, do not
+                match any more same-named files in the archive.  If the
+                user does want to match multiple same-name files in an
+                archive they should provide multiple same-name parameters
+                to the ar command.  */
+             break;
            }
        }
 
@@ -246,15 +265,20 @@ usage (int help)
 {
   FILE *s;
 
-  s = help ? stdout : stderr;
-
-  /* xgettext:c-format */
-  const char * command_line =
 #if BFD_SUPPORTS_PLUGINS
-       _("Usage: %s [emulation options] [-]{dmpqrstx}[abcfilNoPsSuvV] [--plugin <name>] [member-name] [count] archive-file file...\n");
+  /* xgettext:c-format */
+  const char *command_line
+    = _("Usage: %s [emulation options] [-]{dmpqrstx}[abcDfilMNoPsSTuvV]"
+       " [--plugin <name>] [member-name] [count] archive-file file...\n");
+
 #else
-       _("Usage: %s [emulation options] [-]{dmpqrstx}[abcfilNoPsSuvV] [member-name] [count] archive-file file...\n");
+  /* xgettext:c-format */
+  const char *command_line
+    = _("Usage: %s [emulation options] [-]{dmpqrstx}[abcDfilMNoPsSTuvV]"
+       " [member-name] [count] archive-file file...\n");
 #endif
+  s = help ? stdout : stderr;
+
   fprintf (s, command_line, program_name);
 
   /* xgettext:c-format */
@@ -271,7 +295,20 @@ usage (int help)
   fprintf (s, _(" command specific modifiers:\n"));
   fprintf (s, _("  [a]          - put file(s) after [member-name]\n"));
   fprintf (s, _("  [b]          - put file(s) before [member-name] (same as [i])\n"));
-  fprintf (s, _("  [D]          - use zero for timestamps and uids/gids\n"));
+  if (DEFAULT_AR_DETERMINISTIC)
+    {
+      fprintf (s, _("\
+  [D]          - use zero for timestamps and uids/gids (default)\n"));
+      fprintf (s, _("\
+  [U]          - use actual timestamps and uids/gids\n"));
+    }
+  else
+    {
+      fprintf (s, _("\
+  [D]          - use zero for timestamps and uids/gids\n"));
+      fprintf (s, _("\
+  [U]          - use actual timestamps and uids/gids (default)\n"));
+    }
   fprintf (s, _("  [N]          - use instance [count] of name\n"));
   fprintf (s, _("  [f]          - truncate inserted file names\n"));
   fprintf (s, _("  [P]          - use full path names when matching\n"));
@@ -285,6 +322,7 @@ usage (int help)
   fprintf (s, _("  [v]          - be verbose\n"));
   fprintf (s, _("  [V]          - display the version number\n"));
   fprintf (s, _("  @<file>      - read options from <file>\n"));
+  fprintf (s, _("  --target=BFDNAME - specify the target object format as BFDNAME\n"));
 #if BFD_SUPPORTS_PLUGINS
   fprintf (s, _(" optional:\n"));
   fprintf (s, _("  --plugin <p> - load the specified plugin\n"));
@@ -301,7 +339,7 @@ usage (int help)
 }
 
 static void
-ranlib_usage(int help)
+ranlib_usage (int help)
 {
   FILE *s;
 
@@ -316,6 +354,14 @@ ranlib_usage(int help)
   fprintf (s, _("\
   --plugin <name>              Load the specified plugin\n"));
 #endif
+  if (DEFAULT_AR_DETERMINISTIC)
+    fprintf (s, _("\
+  -D                           Use zero for symbol map timestamp (default)\n\
+  -U                           Use an actual symbol map timestamp\n"));
+  else
+    fprintf (s, _("\
+  -D                           Use zero for symbol map timestamp\n\
+  -U                           Use actual symbol map timestamp (default)\n"));
   fprintf (s, _("\
   -t                           Update the archive's symbol map timestamp\n\
   -h --help                    Print this help message\n\
@@ -378,7 +424,7 @@ remove_output (void)
 }
 
 static char **
-decode_options(int argc, char **argv)
+decode_options (int argc, char **argv)
 {
   int c;
 
@@ -427,7 +473,7 @@ decode_options(int argc, char **argv)
       argv = new_argv;
     }
 
-  while ((c = getopt_long (argc, argv, "hdmpqrstxabcfilNoPsSuvV",
+  while ((c = getopt_long (argc, argv, "hdmpqrtxlcoVsSuvabiMNfPTDU",
                           long_options, NULL)) != EOF)
     {
       switch (c)
@@ -524,9 +570,11 @@ decode_options(int argc, char **argv)
         case 'D':
           deterministic = TRUE;
           break;
+        case 'U':
+          deterministic = FALSE;
+          break;
        case OPTION_PLUGIN:
 #if BFD_SUPPORTS_PLUGINS
-         plugin_target = "plugin";
          bfd_plugin_set_plugin (optarg);
 #else
          fprintf (stderr, _("sorry - this program has been built without plugin support\n"));
@@ -539,8 +587,6 @@ decode_options(int argc, char **argv)
        case 0:         /* A long option that just sets a flag.  */
          break;
         default:
-          /* xgettext:c-format */
-          non_fatal (_("illegal option -- '%d'"), c);
           usage (0);
         }
     }
@@ -548,17 +594,32 @@ decode_options(int argc, char **argv)
   return &argv[optind];
 }
 
+/* If neither -D nor -U was specified explicitly,
+   then use the configured default.  */
+static void
+default_deterministic (void)
+{
+  if (deterministic < 0)
+    deterministic = DEFAULT_AR_DETERMINISTIC;
+}
+
 static void
-ranlib_main(int argc, char **argv)
+ranlib_main (int argc, char **argv)
 {
   int arg_index, status = 0;
   bfd_boolean touch = FALSE;
   int c;
 
-  while ((c = getopt_long (argc, argv, "hHvVt", long_options, NULL)) != EOF)
+  while ((c = getopt_long (argc, argv, "DhHUvVt", long_options, NULL)) != EOF)
     {
       switch (c)
         {
+       case 'D':
+         deterministic = TRUE;
+         break;
+        case 'U':
+          deterministic = FALSE;
+          break;
        case 'h':
        case 'H':
          show_help = 1;
@@ -570,19 +631,31 @@ ranlib_main(int argc, char **argv)
        case 'V':
          show_version = 1;
          break;
-        }
+
+         /* PR binutils/13493: Support plugins.  */
+       case OPTION_PLUGIN:
+#if BFD_SUPPORTS_PLUGINS
+         bfd_plugin_set_plugin (optarg);
+#else
+         fprintf (stderr, _("sorry - this program has been built without plugin support\n"));
+         xexit (1);
+#endif
+         break;
+       }
     }
 
   if (argc < 2)
     ranlib_usage (0);
 
   if (show_help)
-    usage(1);
+    ranlib_usage (1);
 
   if (show_version)
     print_version ("ranlib");
 
-  arg_index = 1;
+  default_deterministic ();
+
+  arg_index = optind;
 
   while (arg_index < argc)
     {
@@ -596,9 +669,6 @@ ranlib_main(int argc, char **argv)
   xexit (status);
 }
 
-/* The option parsing should be in its own function.
-   It will be when I have getopt working.  */
-
 int main (int, char **);
 
 int
@@ -652,21 +722,15 @@ main (int argc, char **argv)
   argc -= (i - 1);
 
   if (is_ranlib)
-    ranlib_main(argc, argv);
-
-  if (argc == 2 && strcmp (argv[1], "-M") == 0)
-    {
-      mri_emul ();
-      xexit (0);
-    }
+    ranlib_main (argc, argv);
 
   if (argc < 2)
     usage (0);
 
-  argv = decode_options(argc, argv);
+  argv = decode_options (argc, argv);
 
   if (show_help)
-    usage(1);
+    usage (1);
 
   if (show_version)
     print_version ("ar");
@@ -675,6 +739,7 @@ main (int argc, char **argv)
 
   if (mri_mode)
     {
+      default_deterministic ();
       mri_emul ();
     }
   else
@@ -700,8 +765,14 @@ main (int argc, char **argv)
       if (newer_only && operation != replace)
        fatal (_("`u' is only meaningful with the `r' option."));
 
-      if (newer_only && deterministic)
-       fatal (_("`u' is not meaningful with the `D' option."));
+      if (newer_only && deterministic > 0)
+        fatal (_("`u' is not meaningful with the `D' option."));
+
+      if (newer_only && deterministic < 0 && DEFAULT_AR_DETERMINISTIC)
+        non_fatal (_("\
+`u' modifier ignored since `D' is the default (see `U')"));
+
+      default_deterministic ();
 
       if (postype != pos_default)
        posname = argv[arg_index++];
@@ -709,7 +780,7 @@ main (int argc, char **argv)
       if (counted_name_mode)
        {
          if (operation != extract && operation != del)
-            fatal (_("`N' is only meaningful with the `x' and `d' options."));
+           fatal (_("`N' is only meaningful with the `x' and `d' options."));
          counted_name_counter = atoi (argv[arg_index++]);
          if (counted_name_counter <= 0)
            fatal (_("Value for `N' must be positive."));
@@ -718,7 +789,7 @@ main (int argc, char **argv)
       inarch_filename = argv[arg_index++];
 
       for (file_count = 0; argv[arg_index + file_count] != NULL; file_count++)
-             continue;
+       continue;
 
       files = (file_count > 0) ? argv + arg_index : NULL;
 
@@ -750,11 +821,17 @@ main (int argc, char **argv)
          break;
 
        case move:
-         if (files != NULL)
-           move_members (arch, files);
-         else
-           output_filename = NULL;
-         break;
+         /* PR 12558: Creating and moving at the same time does
+            not make sense.  Just create the archive instead.  */
+         if (! silent_create)
+           {
+             if (files != NULL)
+               move_members (arch, files);
+             else
+               output_filename = NULL;
+             break;
+           }
+         /* Fall through.  */
 
        case replace:
        case quick_append:
@@ -800,8 +877,8 @@ open_inarch (const char *archive_filename, const char *file)
         stat() works just fine in v2.x, so I think this should be
         removed.  For now, I enable it for DJGPP v2. -- EZ.  */
 
-/* KLUDGE ALERT! Temporary fix until I figger why
-   stat() is wrong ... think it's buried in GO32's IDT - Jax */
+      /* KLUDGE ALERT! Temporary fix until I figger why
+        stat() is wrong ... think it's buried in GO32's IDT - Jax */
       if (errno != ENOENT)
        bfd_fatal (archive_filename);
 #endif
@@ -814,9 +891,9 @@ open_inarch (const char *archive_filename, const char *file)
          return NULL;
        }
 
-      /* Try to figure out the target to use for the archive from the
-         first object on the list.  */
-      if (file != NULL)
+      /* If the target isn't set, try to figure out the target to use
+        for the archive from the first object on the list.  */
+      if (target == NULL && file != NULL)
        {
          bfd *obj;
 
@@ -860,6 +937,25 @@ open_inarch (const char *archive_filename, const char *file)
       xexit (1);
     }
 
+  if ((operation == replace || operation == quick_append)
+      && bfd_openr_next_archived_file (arch, NULL) != NULL)
+    {
+      /* PR 15140: Catch attempts to convert a normal
+        archive into a thin archive or vice versa.  */
+      if (make_thin_archive && ! bfd_is_thin_archive (arch))
+       {
+         fatal (_("Cannot convert existing library %s to thin format"),
+                bfd_get_filename (arch));
+         goto bloser;
+       }
+      else if (! make_thin_archive && bfd_is_thin_archive (arch))
+       {
+         fatal (_("Cannot convert existing thin library %s to normal format"),
+                bfd_get_filename (arch));
+         goto bloser;
+       }
+    }  
+
   last_one = &(arch->archive_next);
   /* Read all the contents right away, regardless.  */
   for (next_one = bfd_openr_next_archived_file (arch, NULL);
@@ -879,10 +975,11 @@ open_inarch (const char *archive_filename, const char *file)
 static void
 print_contents (bfd *abfd)
 {
-  size_t ncopied = 0;
+  bfd_size_type ncopied = 0;
+  bfd_size_type size;
   char *cbuf = (char *) xmalloc (BUFSIZE);
   struct stat buf;
-  size_t size;
+
   if (bfd_stat_arch_elt (abfd, &buf) != 0)
     /* xgettext:c-format */
     fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
@@ -895,22 +992,22 @@ print_contents (bfd *abfd)
   size = buf.st_size;
   while (ncopied < size)
     {
+      bfd_size_type nread;
+      bfd_size_type tocopy = size - ncopied;
 
-      size_t nread;
-      size_t tocopy = size - ncopied;
       if (tocopy > BUFSIZE)
        tocopy = BUFSIZE;
 
-      nread = bfd_bread (cbuf, (bfd_size_type) tocopy, abfd);
+      nread = bfd_bread (cbuf, tocopy, abfd);
       if (nread != tocopy)
        /* xgettext:c-format */
        fatal (_("%s is not a valid archive"),
               bfd_get_filename (bfd_my_archive (abfd)));
 
-      /* fwrite in mingw32 may return int instead of size_t. Cast the
-        return value to size_t to avoid comparison between signed and
+      /* fwrite in mingw32 may return int instead of bfd_size_type. Cast the
+        return value to bfd_size_type to avoid comparison between signed and
         unsigned values.  */
-      if ((size_t) fwrite (cbuf, 1, nread, stdout) != nread)
+      if ((bfd_size_type) fwrite (cbuf, 1, nread, stdout) != nread)
        fatal ("stdout: %s", strerror (errno));
       ncopied += tocopy;
     }
@@ -932,11 +1029,20 @@ extract_file (bfd *abfd)
 {
   FILE *ostream;
   char *cbuf = (char *) xmalloc (BUFSIZE);
-  size_t nread, tocopy;
-  size_t ncopied = 0;
-  size_t size;
+  bfd_size_type nread, tocopy;
+  bfd_size_type ncopied = 0;
+  bfd_size_type size;
   struct stat buf;
 
+  /* PR binutils/17533: Do not allow directory traversal
+     outside of the current directory tree.  */
+  if (! is_valid_archive_path (bfd_get_filename (abfd)))
+    {
+      non_fatal (_("illegal pathname found in archive member: %s"),
+                bfd_get_filename (abfd));
+      return;
+    }
+
   if (bfd_stat_arch_elt (abfd, &buf) != 0)
     /* xgettext:c-format */
     fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
@@ -969,7 +1075,7 @@ extract_file (bfd *abfd)
        if (tocopy > BUFSIZE)
          tocopy = BUFSIZE;
 
-       nread = bfd_bread (cbuf, (bfd_size_type) tocopy, abfd);
+       nread = bfd_bread (cbuf, tocopy, abfd);
        if (nread != tocopy)
          /* xgettext:c-format */
          fatal (_("%s is not a valid archive"),
@@ -991,10 +1097,10 @@ extract_file (bfd *abfd)
            output_file = ostream;
          }
 
-       /* fwrite in mingw32 may return int instead of size_t. Cast
-          the return value to size_t to avoid comparison between
+       /* fwrite in mingw32 may return int instead of bfd_size_type. Cast
+          the return value to bfd_size_type to avoid comparison between
           signed and unsigned values.  */
-       if ((size_t) fwrite (cbuf, 1, nread, ostream) != nread)
+       if ((bfd_size_type) fwrite (cbuf, 1, nread, ostream) != nread)
          fatal ("%s: %s", output_filename, strerror (errno));
        ncopied += tocopy;
       }
@@ -1030,7 +1136,7 @@ write_archive (bfd *iarch)
   new_name = make_tempname (old_name);
 
   if (new_name == NULL)
-    bfd_fatal ("could not create temporary file whilst writing archive");
+    bfd_fatal (_("could not create temporary file whilst writing archive"));
 
   output_filename = new_name;
 
@@ -1074,6 +1180,7 @@ write_archive (bfd *iarch)
 
   if (smart_rename (new_name, old_name, 0) != 0)
     xexit (1);
+  free (old_name);
 }
 
 /* Return a pointer to the pointer to the entry which should be rplacd'd
@@ -1363,6 +1470,9 @@ ranlib_touch (const char *archname)
     /* xgettext:c-format */
     fatal (_("%s: no archive map to update"), archname);
 
+  if (deterministic)
+    arch->flags |= BFD_DETERMINISTIC_OUTPUT;
+
   bfd_update_armap_timestamp (arch);
 
   if (! bfd_close (arch))
This page took 0.03119 seconds and 4 git commands to generate.