gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / binutils / ar.c
index ebd9528b837fb0cbd4ffef9847395074e419ad4e..85b342a6502768be49dd2b97362dde96957a6099 100644 (file)
@@ -1,5 +1,5 @@
 /* ar.c - Archive modify and extract.
-   Copyright (C) 1991-2014 Free Software Foundation, Inc.
+   Copyright (C) 1991-2020 Free Software Foundation, Inc.
 
    This file is part of GNU Binutils.
 
 #include "progress.h"
 #include "getopt.h"
 #include "aout/ar.h"
-#include "libbfd.h"
 #include "bucomm.h"
 #include "arsup.h"
 #include "filenames.h"
 #include "binemul.h"
+#include "plugin-api.h"
 #include "plugin.h"
+#include "ansidecl.h"
 
 #ifdef __GO32___
 #define EXT_NAME_LEN 3         /* Bufflen of addition to name if it's MS-DOS.  */
@@ -75,6 +76,9 @@ int silent_create = 0;
 /* Nonzero means describe each action performed.  */
 int verbose = 0;
 
+/* Nonzero means display offsets of files in the archive.  */
+int display_offsets = 0;
+
 /* Nonzero means preserve dates of members when extracting them.  */
 int preserve_dates = 0;
 
@@ -146,8 +150,14 @@ static const char *plugin_target = NULL;
 
 static const char *target = NULL;
 
-#define OPTION_PLUGIN 201
-#define OPTION_TARGET 202
+enum long_option_numbers
+{
+  OPTION_PLUGIN = 201,
+  OPTION_TARGET,
+  OPTION_OUTPUT
+};
+
+static const char * output_dir = NULL;
 
 static struct option long_options[] =
 {
@@ -155,6 +165,7 @@ static struct option long_options[] =
   {"plugin", required_argument, NULL, OPTION_PLUGIN},
   {"target", required_argument, NULL, OPTION_TARGET},
   {"version", no_argument, &show_version, 1},
+  {"output", required_argument, NULL, OPTION_OUTPUT},
   {NULL, no_argument, NULL, 0}
 };
 
@@ -214,7 +225,7 @@ map_over_members (bfd *arch, void (*function)(bfd *), char **files, int count)
          if (head->archive_pass)
            continue;
 
-         filename = head->filename;
+         filename = bfd_get_filename (head);
          if (filename == NULL)
            {
              /* Some archive formats don't get the filenames filled in
@@ -268,13 +279,13 @@ usage (int help)
 #if BFD_SUPPORTS_PLUGINS
   /* xgettext:c-format */
   const char *command_line
-    = _("Usage: %s [emulation options] [-]{dmpqrstx}[abcDfilMNoPsSTuvV]"
+    = _("Usage: %s [emulation options] [-]{dmpqrstx}[abcDfilMNoOPsSTuvV]"
        " [--plugin <name>] [member-name] [count] archive-file file...\n");
 
 #else
   /* xgettext:c-format */
   const char *command_line
-    = _("Usage: %s [emulation options] [-]{dmpqrstx}[abcDfilMNoPsSTuvV]"
+    = _("Usage: %s [emulation options] [-]{dmpqrstx}[abcDfilMNoOPsSTuvV]"
        " [member-name] [count] archive-file file...\n");
 #endif
   s = help ? stdout : stderr;
@@ -290,7 +301,7 @@ usage (int help)
   fprintf (s, _("  q[f]         - quick append file(s) to the archive\n"));
   fprintf (s, _("  r[ab][f][u]  - replace existing or insert new file(s) into the archive\n"));
   fprintf (s, _("  s            - act as ranlib\n"));
-  fprintf (s, _("  t            - display contents of archive\n"));
+  fprintf (s, _("  t[O][v]      - display contents of the archive\n"));
   fprintf (s, _("  x[o]         - extract file(s) from the archive\n"));
   fprintf (s, _(" command specific modifiers:\n"));
   fprintf (s, _("  [a]          - put file(s) after [member-name]\n"));
@@ -313,6 +324,7 @@ usage (int help)
   fprintf (s, _("  [f]          - truncate inserted file names\n"));
   fprintf (s, _("  [P]          - use full path names when matching\n"));
   fprintf (s, _("  [o]          - preserve original dates\n"));
+  fprintf (s, _("  [O]          - display offsets of files in the archive\n"));
   fprintf (s, _("  [u]          - only replace files that are newer than current archive contents\n"));
   fprintf (s, _(" generic modifiers:\n"));
   fprintf (s, _("  [c]          - do not warn if the library had to be created\n"));
@@ -323,6 +335,7 @@ usage (int help)
   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"));
+  fprintf (s, _("  --output=DIRNAME - specify the output directory for extraction operations\n"));
 #if BFD_SUPPORTS_PLUGINS
   fprintf (s, _(" optional:\n"));
   fprintf (s, _("  --plugin <p> - load the specified plugin\n"));
@@ -428,9 +441,10 @@ decode_options (int argc, char **argv)
 {
   int c;
 
-  /* Convert old-style tar call by exploding option element and rearranging
+  /* Convert old-style ar call by exploding option element and rearranging
      options accordingly.  */
 
+ restart:
   if (argc > 1 && argv[1][0] != '-')
     {
       int new_argc;            /* argc value for rearranged arguments */
@@ -473,7 +487,7 @@ decode_options (int argc, char **argv)
       argv = new_argv;
     }
 
-  while ((c = getopt_long (argc, argv, "hdmpqrtxlcoVsSuvabiMNfPTDU",
+  while ((c = getopt_long (argc, argv, "hdmpqrtxlcoOVsSuvabiMNfPTDU",
                           long_options, NULL)) != EOF)
     {
       switch (c)
@@ -528,6 +542,9 @@ decode_options (int argc, char **argv)
         case 'o':
           preserve_dates = 1;
           break;
+        case 'O':
+          display_offsets = 1;
+          break;
         case 'V':
           show_version = TRUE;
           break;
@@ -584,6 +601,9 @@ decode_options (int argc, char **argv)
        case OPTION_TARGET:
          target = optarg;
          break;
+       case OPTION_OUTPUT:
+         output_dir = optarg;
+         break;
        case 0:         /* A long option that just sets a flag.  */
          break;
         default:
@@ -591,6 +611,18 @@ decode_options (int argc, char **argv)
         }
     }
 
+  /* PR 13256: Allow for the possibility that the first command line option
+     started with a dash (eg --plugin) but then the following option(s) are
+     old style, non-dash-prefixed versions.  */
+  if (operation == none && write_armap != 1 && !mri_mode
+      && optind > 0 && optind < argc)
+    {
+      argv += (optind - 1);
+      argc -= (optind - 1);
+      optind = 0;
+      goto restart;
+    }
+
   return &argv[optind];
 }
 
@@ -691,6 +723,7 @@ main (int argc, char **argv)
 
   program_name = argv[0];
   xmalloc_set_program_name (program_name);
+  bfd_set_error_program_name (program_name);
 #if BFD_SUPPORTS_PLUGINS
   bfd_plugin_set_program_name (program_name);
 #endif
@@ -710,7 +743,8 @@ main (int argc, char **argv)
 
   START_PROGRESS (program_name, 0);
 
-  bfd_init ();
+  if (bfd_init () != BFD_INIT_MAGIC)
+    fatal (_("fatal error: libbfd ABI mismatch"));
   set_default_bfd_target ();
 
   xatexit (remove_output);
@@ -746,6 +780,12 @@ main (int argc, char **argv)
     {
       bfd *arch;
 
+      /* Fail if no files are specified on the command line.
+        (But not for MRI mode which allows for reading arguments
+        and filenames from stdin).  */
+      if (argv[arg_index] == NULL)
+       usage (0);
+
       /* We don't use do_quick_append any more.  Too many systems
         expect ar to always rebuild the symbol table even when q is
         used.  */
@@ -775,18 +815,26 @@ main (int argc, char **argv)
       default_deterministic ();
 
       if (postype != pos_default)
-       posname = argv[arg_index++];
+       {
+         posname = argv[arg_index++];
+         if (posname == NULL)
+           fatal (_("missing position arg."));
+       }
 
       if (counted_name_mode)
        {
          if (operation != extract && operation != del)
            fatal (_("`N' is only meaningful with the `x' and `d' options."));
+         if (argv[arg_index] == NULL)
+           fatal (_("`N' missing value."));
          counted_name_counter = atoi (argv[arg_index++]);
          if (counted_name_counter <= 0)
            fatal (_("Value for `N' must be positive."));
        }
 
       inarch_filename = argv[arg_index++];
+      if (inarch_filename == NULL)
+       usage (0);
 
       for (file_count = 0; argv[arg_index + file_count] != NULL; file_count++)
        continue;
@@ -954,7 +1002,7 @@ open_inarch (const char *archive_filename, const char *file)
                 bfd_get_filename (arch));
          goto bloser;
        }
-    }  
+    }
 
   last_one = &(arch->archive_next);
   /* Read all the contents right away, regardless.  */
@@ -1002,7 +1050,7 @@ print_contents (bfd *abfd)
       if (nread != tocopy)
        /* xgettext:c-format */
        fatal (_("%s is not a valid archive"),
-              bfd_get_filename (bfd_my_archive (abfd)));
+              bfd_get_filename (abfd->my_archive));
 
       /* 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
@@ -1014,6 +1062,53 @@ print_contents (bfd *abfd)
   free (cbuf);
 }
 
+
+static FILE * open_output_file (bfd *) ATTRIBUTE_RETURNS_NONNULL;
+
+static FILE *
+open_output_file (bfd * abfd)
+{
+  output_filename = bfd_get_filename (abfd);
+
+  /* PR binutils/17533: Do not allow directory traversal
+     outside of the current directory tree - unless the
+     user has explicitly specified an output directory.  */
+  if (! is_valid_archive_path (output_filename))
+    {
+      char * base = (char *) lbasename (output_filename);
+
+      non_fatal (_("illegal output pathname for archive member: %s, using '%s' instead"),
+                output_filename, base);
+      output_filename = base;
+    }
+  
+  if (output_dir)
+    {
+      size_t len = strlen (output_dir);
+
+      if (len > 0)
+       {
+         /* FIXME: There is a memory leak here, but it is not serious.  */
+         if (IS_DIR_SEPARATOR (output_dir [len - 1]))
+           output_filename = concat (output_dir, output_filename, NULL);
+         else
+           output_filename = concat (output_dir, "/", output_filename, NULL);
+       }
+    }
+
+  if (verbose)
+    printf ("x - %s\n", output_filename);
+  
+  FILE * ostream = fopen (output_filename, FOPEN_WB);
+  if (ostream == NULL)
+    {
+      perror (output_filename);
+      xexit (1);
+    }
+
+  return ostream;
+}
+
 /* Extract a member of the archive into its own file.
 
    We defer opening the new file until after we have read a BUFSIZ chunk of the
@@ -1027,10 +1122,6 @@ print_contents (bfd *abfd)
 void
 extract_file (bfd *abfd)
 {
-  FILE *ostream;
-  char *cbuf = (char *) xmalloc (BUFSIZE);
-  bfd_size_type nread, tocopy;
-  bfd_size_type ncopied = 0;
   bfd_size_type size;
   struct stat buf;
 
@@ -1039,80 +1130,63 @@ extract_file (bfd *abfd)
     fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
   size = buf.st_size;
 
-  if (verbose)
-    printf ("x - %s\n", bfd_get_filename (abfd));
-
   bfd_seek (abfd, (file_ptr) 0, SEEK_SET);
 
-  ostream = NULL;
+  output_file = NULL;
   if (size == 0)
     {
-      /* Seems like an abstraction violation, eh?  Well it's OK! */
-      output_filename = bfd_get_filename (abfd);
+      output_file = open_output_file (abfd);
+    }
+  else
+    {
+      bfd_size_type ncopied = 0;
+      char *cbuf = (char *) xmalloc (BUFSIZE);
 
-      ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
-      if (ostream == NULL)
+      while (ncopied < size)
        {
-         perror (bfd_get_filename (abfd));
-         xexit (1);
-       }
+         bfd_size_type nread, tocopy;
 
-      output_file = ostream;
-    }
-  else
-    while (ncopied < size)
-      {
-       tocopy = size - ncopied;
-       if (tocopy > BUFSIZE)
-         tocopy = BUFSIZE;
-
-       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)));
+         tocopy = size - ncopied;
+         if (tocopy > BUFSIZE)
+           tocopy = BUFSIZE;
 
-       /* See comment above; this saves disk arm motion */
-       if (ostream == NULL)
-         {
-           /* Seems like an abstraction violation, eh?  Well it's OK! */
-           output_filename = bfd_get_filename (abfd);
+         nread = bfd_bread (cbuf, tocopy, abfd);
+         if (nread != tocopy)
+           /* xgettext:c-format */
+           fatal (_("%s is not a valid archive"),
+                  bfd_get_filename (abfd->my_archive));
 
-           ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
-           if (ostream == NULL)
-             {
-               perror (bfd_get_filename (abfd));
-               xexit (1);
-             }
+         /* See comment above; this saves disk arm motion.  */
+         if (output_file == NULL)
+           output_file = open_output_file (abfd);
 
-           output_file = ostream;
-         }
+         /* 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 ((bfd_size_type) fwrite (cbuf, 1, nread, output_file) != nread)
+           fatal ("%s: %s", output_filename, strerror (errno));
+
+         ncopied += tocopy;
+       }
 
-       /* 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 ((bfd_size_type) fwrite (cbuf, 1, nread, ostream) != nread)
-         fatal ("%s: %s", output_filename, strerror (errno));
-       ncopied += tocopy;
-      }
+      free (cbuf);
+    }
 
-  if (ostream != NULL)
-    fclose (ostream);
+  fclose (output_file);
 
   output_file = NULL;
-  output_filename = NULL;
 
-  chmod (bfd_get_filename (abfd), buf.st_mode);
+  chmod (output_filename, buf.st_mode);
 
   if (preserve_dates)
     {
       /* Set access time to modification time.  Only st_mtime is
         initialized by bfd_stat_arch_elt.  */
       buf.st_atime = buf.st_mtime;
-      set_times (bfd_get_filename (abfd), &buf);
+      set_times (output_filename, &buf);
     }
 
-  free (cbuf);
+  output_filename = NULL;
 }
 
 static void
@@ -1154,8 +1228,11 @@ write_archive (bfd *iarch)
   if (deterministic)
     obfd->flags |= BFD_DETERMINISTIC_OUTPUT;
 
+  if (full_pathname)
+    obfd->flags |= BFD_ARCHIVE_FULL_PATH;
+
   if (make_thin_archive || bfd_is_thin_archive (iarch))
-    bfd_is_thin_archive (obfd) = 1;
+    bfd_set_thin_archive (obfd, TRUE);
 
   if (!bfd_set_archive_head (obfd, contents_head))
     bfd_fatal (old_name);
@@ -1172,6 +1249,7 @@ write_archive (bfd *iarch)
   if (smart_rename (new_name, old_name, 0) != 0)
     xexit (1);
   free (old_name);
+  free (new_name);
 }
 
 /* Return a pointer to the pointer to the entry which should be rplacd'd
@@ -1204,7 +1282,7 @@ get_pos_bfd (bfd **contents, enum pos default_pos, const char *default_posname)
   else
     {
       for (; *after_bfd; after_bfd = &(*after_bfd)->archive_next)
-       if (FILENAME_CMP ((*after_bfd)->filename, realposname) == 0)
+       if (FILENAME_CMP (bfd_get_filename (*after_bfd), realposname) == 0)
          {
            if (realpos == pos_after)
              after_bfd = &(*after_bfd)->archive_next;
@@ -1243,7 +1321,7 @@ delete_members (bfd *arch, char **files_to_delete)
       while (*current_ptr_ptr)
        {
          if (FILENAME_CMP (normalize (*files_to_delete, arch),
-                           (*current_ptr_ptr)->filename) == 0)
+                           bfd_get_filename (*current_ptr_ptr)) == 0)
            {
              ++match_count;
              if (counted_name_mode
@@ -1298,7 +1376,7 @@ move_members (bfd *arch, char **files_to_move)
        {
          bfd *current_ptr = *current_ptr_ptr;
          if (FILENAME_CMP (normalize (*files_to_move, arch),
-                           current_ptr->filename) == 0)
+                           bfd_get_filename (current_ptr)) == 0)
            {
              /* Move this file to the end of the list - first cut from
                 where it is.  */
@@ -1320,7 +1398,8 @@ move_members (bfd *arch, char **files_to_move)
          current_ptr_ptr = &((*current_ptr_ptr)->archive_next);
        }
       /* xgettext:c-format */
-      fatal (_("no entry %s in archive %s!"), *files_to_move, arch->filename);
+      fatal (_("no entry %s in archive %s!"), *files_to_move,
+            bfd_get_filename (arch));
 
     next_file:;
     }
@@ -1350,7 +1429,7 @@ replace_members (bfd *arch, char **files_to_move, bfd_boolean quick)
              /* For compatibility with existing ar programs, we
                 permit the same file to be added multiple times.  */
              if (FILENAME_CMP (normalize (*files_to_move, arch),
-                               normalize (current->filename, arch)) == 0
+                               normalize (bfd_get_filename (current), arch)) == 0
                  && current->arelt_data != NULL)
                {
                  if (newer_only)
@@ -1366,14 +1445,14 @@ replace_members (bfd *arch, char **files_to_move, bfd_boolean quick)
                      if (bfd_stat_arch_elt (current, &asbuf) != 0)
                        /* xgettext:c-format */
                        fatal (_("internal stat error on %s"),
-                              current->filename);
+                              bfd_get_filename (current));
 
                      if (fsbuf.st_mtime <= asbuf.st_mtime)
                        goto next_file;
                    }
 
                  after_bfd = get_pos_bfd (&arch->archive_next, pos_after,
-                                          current->filename);
+                                          bfd_get_filename (current));
                  if (ar_emul_replace (after_bfd, *files_to_move,
                                       target, verbose))
                    {
@@ -1477,5 +1556,5 @@ ranlib_touch (const char *archname)
 static void
 print_descr (bfd *abfd)
 {
-  print_arelt_descr (stdout, abfd, verbose);
+  print_arelt_descr (stdout, abfd, verbose, display_offsets);
 }
This page took 0.030306 seconds and 4 git commands to generate.