diff options
author | Fangrui Song <i@maskray.me> | 2019-10-30 10:50:23 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2019-10-30 10:50:23 +0000 |
commit | 197245e341aeb1b5da8ee5fbe5d6c49de650fb89 (patch) | |
tree | 046f13d6fd30949d79ec6c7eb88b1d39834c0824 /binutils/ar.c | |
parent | a961a1e1749443516d8fe6e0570cf808a09e8f89 (diff) | |
download | gdb-197245e341aeb1b5da8ee5fbe5d6c49de650fb89.zip gdb-197245e341aeb1b5da8ee5fbe5d6c49de650fb89.tar.gz gdb-197245e341aeb1b5da8ee5fbe5d6c49de650fb89.tar.bz2 |
Add a --output=<DIR> option to ar to allow the specifying of an output directory.
* ar.c (emum long option numbers): Declare. Use to provide
numerical values for long options.
(long_options): Add --output option.
(usage): Mention the --output option.
(open_output_file): New function. Create a filepath for an output
file and open it.
(extract_file): Use open_output_file().
(open_output_file):
* testsuite/binutils-all/ar.exp: Add a test of the new feature.
* doc/binutils.texi: Document the new feature.
* NEWS: Mention the new feature.
Diffstat (limited to 'binutils/ar.c')
-rw-r--r-- | binutils/ar.c | 155 |
1 files changed, 91 insertions, 64 deletions
diff --git a/binutils/ar.c b/binutils/ar.c index 38c54c9..0af7954 100644 --- a/binutils/ar.c +++ b/binutils/ar.c @@ -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: @@ -1050,6 +1062,49 @@ 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); + + 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); + } + } + + /* PR binutils/17533: Do not allow directory traversal + outside of the current directory tree. */ + 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; + } + + 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 @@ -1063,23 +1118,9 @@ 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)); @@ -1090,75 +1131,61 @@ extract_file (bfd *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)); - /* 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; - } + ncopied += tocopy; + } - if (ostream != NULL) - fclose (ostream); + free (cbuf); + } + + 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 |