Automatic date update in version.in
[deliverable/binutils-gdb.git] / binutils / ar.c
index 4e953c054dedbdd6489919b337fb3e5f1919a4a0..1057db9980eddc4559ce5d8c253ddf483a29e1f5 100644 (file)
@@ -1,5 +1,5 @@
 /* ar.c - Archive modify and extract.
-   Copyright (C) 1991-2019 Free Software Foundation, Inc.
+   Copyright (C) 1991-2020 Free Software Foundation, Inc.
 
    This file is part of GNU Binutils.
 
@@ -35,6 +35,7 @@
 #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.  */
@@ -149,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[] =
 {
@@ -158,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}
 };
 
@@ -327,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"));
@@ -592,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:
@@ -602,7 +614,8 @@ 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 && optind > 0 && optind < argc)
+  if (operation == none && write_armap != 1 && !mri_mode
+      && optind > 0 && optind < argc)
     {
       argv += (optind - 1);
       argc -= (optind - 1);
@@ -1049,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
@@ -1062,102 +1122,71 @@ 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;
 
-  /* 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));
-      free (cbuf);
-      return;
-    }
-
   if (bfd_stat_arch_elt (abfd, &buf) != 0)
     /* xgettext:c-format */
     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 (abfd->my_archive));
+         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
@@ -1199,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);
This page took 0.026651 seconds and 4 git commands to generate.