X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=binutils%2Far.c;h=28a67891753f3608fa54679b48a4e021cba04ccc;hb=9108bc33b1ca0b2e930c0cce5b1a0394e33e86be;hp=de2f631a396fe8610037f839d356c7c4a007f429;hpb=4e4075512b08d37e1431411d3e59bb3cc25fd490;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/ar.c b/binutils/ar.c index de2f631a39..28a6789175 100644 --- a/binutils/ar.c +++ b/binutils/ar.c @@ -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-2018 Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -31,13 +29,12 @@ #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 #ifdef __GO32___ #define EXT_NAME_LEN 3 /* Bufflen of addition to name if it's MS-DOS. */ @@ -78,6 +75,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; @@ -97,7 +97,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,14 +141,22 @@ 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; #define OPTION_PLUGIN 201 +#define OPTION_TARGET 202 static struct option long_options[] = { {"help", no_argument, &show_help, 1}, {"plugin", required_argument, NULL, OPTION_PLUGIN}, + {"target", required_argument, NULL, OPTION_TARGET}, {"version", no_argument, &show_version, 1}, {NULL, no_argument, NULL, 0} }; @@ -188,6 +196,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; @@ -198,6 +209,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) { @@ -212,8 +231,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 @@ -226,6 +245,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; } } @@ -242,15 +268,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 ] [member-name] [count] archive-file file...\n"); + /* xgettext:c-format */ + const char *command_line + = _("Usage: %s [emulation options] [-]{dmpqrstx}[abcDfilMNoOPsSTuvV]" + " [--plugin ] [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}[abcDfilMNoOPsSTuvV]" + " [member-name] [count] archive-file file...\n"); #endif + s = help ? stdout : stderr; + fprintf (s, command_line, program_name); /* xgettext:c-format */ @@ -262,16 +293,30 @@ 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")); 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")); 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")); @@ -281,6 +326,7 @@ usage (int help) fprintf (s, _(" [v] - be verbose\n")); 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")); #if BFD_SUPPORTS_PLUGINS fprintf (s, _(" optional:\n")); fprintf (s, _(" --plugin

- load the specified plugin\n")); @@ -297,7 +343,7 @@ usage (int help) } static void -ranlib_usage(int help) +ranlib_usage (int help) { FILE *s; @@ -312,6 +358,14 @@ ranlib_usage(int help) fprintf (s, _("\ --plugin 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\ @@ -374,7 +428,7 @@ remove_output (void) } static char ** -decode_options(int argc, char **argv) +decode_options (int argc, char **argv) { int c; @@ -423,7 +477,7 @@ decode_options(int argc, char **argv) argv = new_argv; } - while ((c = getopt_long (argc, argv, "hdmpqrstxabcfilNoPsSuvV", + while ((c = getopt_long (argc, argv, "hdmpqrtxlcoOVsSuvabiMNfPTDU", long_options, NULL)) != EOF) { switch (c) @@ -478,6 +532,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; @@ -520,20 +577,23 @@ 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")); xexit (1); #endif break; + case OPTION_TARGET: + target = optarg; + break; case 0: /* A long option that just sets a flag. */ break; default: - /* xgettext:c-format */ - non_fatal (_("illegal option -- '%d'"), c); usage (0); } } @@ -541,17 +601,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; @@ -563,19 +638,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) { @@ -589,9 +676,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 @@ -614,6 +698,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 @@ -645,21 +730,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"); @@ -668,12 +747,19 @@ main (int argc, char **argv) if (mri_mode) { + default_deterministic (); mri_emul (); } else { 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. */ @@ -693,25 +779,39 @@ 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++]; + { + 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.")); + 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; + continue; files = (file_count > 0) ? argv + arg_index : NULL; @@ -743,11 +843,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: @@ -773,7 +879,6 @@ main (int argc, char **argv) bfd * open_inarch (const char *archive_filename, const char *file) { - const char *target; bfd **last_one; bfd *next_one; struct stat sbuf; @@ -782,7 +887,8 @@ open_inarch (const char *archive_filename, const char *file) bfd_set_error (bfd_error_no_error); - target = plugin_target; + if (target == NULL) + target = plugin_target; if (stat (archive_filename, &sbuf) != 0) { @@ -793,8 +899,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 @@ -807,9 +913,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; @@ -853,6 +959,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); @@ -872,10 +997,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)); @@ -888,22 +1014,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))); + bfd_get_filename (abfd->my_archive)); - /* 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; } @@ -925,11 +1051,21 @@ 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)); + free (cbuf); + return; + } + if (bfd_stat_arch_elt (abfd, &buf) != 0) /* xgettext:c-format */ fatal (_("internal stat error on %s"), bfd_get_filename (abfd)); @@ -962,11 +1098,11 @@ 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"), - bfd_get_filename (bfd_my_archive (abfd))); + bfd_get_filename (abfd->my_archive)); /* See comment above; this saves disk arm motion */ if (ostream == NULL) @@ -984,10 +1120,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; } @@ -1023,7 +1159,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; @@ -1067,6 +1203,8 @@ 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 @@ -1270,7 +1408,7 @@ replace_members (bfd *arch, char **files_to_move, bfd_boolean quick) after_bfd = get_pos_bfd (&arch->archive_next, pos_after, current->filename); if (ar_emul_replace (after_bfd, *files_to_move, - plugin_target, verbose)) + target, verbose)) { /* Snip out this entry from the chain. */ *current_ptr = (*current_ptr)->archive_next; @@ -1286,7 +1424,7 @@ replace_members (bfd *arch, char **files_to_move, bfd_boolean quick) /* Add to the end of the archive. */ after_bfd = get_pos_bfd (&arch->archive_next, pos_end, NULL); - if (ar_emul_append (after_bfd, *files_to_move, plugin_target, + if (ar_emul_append (after_bfd, *files_to_move, target, verbose, make_thin_archive)) changed = TRUE; @@ -1356,6 +1494,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)) @@ -1369,5 +1510,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); }