X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=binutils%2Far.c;h=b8342ce65a1b530cff68e3287e706ba13988b593;hb=2365f8d70c50afbfd6be69a4076ea6e78fb5485d;hp=94c79e21540e2241db80b3a5291df29d06da248d;hpb=86eafac0aad7edbc1ccea6daf53480a36339250a;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/ar.c b/binutils/ar.c index 94c79e2154..b8342ce65a 100644 --- a/binutils/ar.c +++ b/binutils/ar.c @@ -1,5 +1,5 @@ /* ar.c - Archive modify and extract. - Copyright (C) 1991-2015 Free Software Foundation, Inc. + Copyright (C) 1991-2019 Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -29,12 +29,13 @@ #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} }; @@ -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 ] [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, _(" @ - read options from \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

- 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]; } @@ -711,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); @@ -747,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. */ @@ -776,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; @@ -955,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. */ @@ -1003,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 @@ -1015,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 @@ -1028,101 +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)); - 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 (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)); - /* 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 @@ -1164,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); @@ -1182,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 @@ -1487,5 +1555,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); }