binutils-gdb/binutils/arsup.c

485 lines
9.3 KiB
C
Raw Normal View History

1999-05-03 15:29:11 +08:00
/* arsup.c - Archive support for MRI compatibility
Copyright (C) 1992-2015 Free Software Foundation, Inc.
1999-05-03 15:29:11 +08:00
2002-05-27 23:46:10 +08:00
This file is part of GNU Binutils.
1999-05-03 15:29:11 +08:00
2002-05-27 23:46:10 +08:00
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
2007-07-06 00:54:46 +08:00
the Free Software Foundation; either version 3 of the License, or
2002-05-27 23:46:10 +08:00
(at your option) any later version.
1999-05-03 15:29:11 +08:00
2002-05-27 23:46:10 +08:00
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
1999-05-03 15:29:11 +08:00
2002-05-27 23:46:10 +08:00
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
2007-07-06 00:54:46 +08:00
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
1999-05-03 15:29:11 +08:00
/* Contributed by Steve Chamberlain
2002-05-27 23:46:10 +08:00
sac@cygnus.com
1999-05-03 15:29:11 +08:00
2002-05-27 23:46:10 +08:00
This file looks after requests from arparse.y, to provide the MRI
style librarian command syntax + 1 word LIST. */
1999-05-03 15:29:11 +08:00
#include "sysdep.h"
1999-05-03 15:29:11 +08:00
#include "bfd.h"
#include "libiberty.h"
#include "filenames.h"
#include "bucomm.h"
#include "arsup.h"
1999-05-03 15:29:11 +08:00
static void map_over_list
(bfd *, void (*function) (bfd *, bfd *), struct list *);
static void ar_directory_doer (bfd *, bfd *);
static void ar_addlib_doer (bfd *, bfd *);
1999-05-03 15:29:11 +08:00
extern int verbose;
extern int deterministic;
1999-05-03 15:29:11 +08:00
static bfd *obfd;
static char *real_name;
static FILE *outfile;
1999-05-03 15:29:11 +08:00
static void
map_over_list (bfd *arch, void (*function) (bfd *, bfd *), struct list *list)
1999-05-03 15:29:11 +08:00
{
bfd *head;
if (list == NULL)
{
bfd *next;
head = arch->archive_next;
1999-05-03 15:29:11 +08:00
while (head != NULL)
{
next = head->archive_next;
1999-05-03 15:29:11 +08:00
function (head, (bfd *) NULL);
head = next;
}
}
else
{
struct list *ptr;
/* This may appear to be a baroque way of accomplishing what we
want. however we have to iterate over the filenames in order
to notice where a filename is requested but does not exist in
the archive. Ditto mapping over each file each time -- we
want to hack multiple references. */
for (ptr = list; ptr; ptr = ptr->next)
{
bfd_boolean found = FALSE;
1999-05-03 15:29:11 +08:00
bfd *prev = arch;
for (head = arch->archive_next; head; head = head->archive_next)
1999-05-03 15:29:11 +08:00
{
if (head->filename != NULL
&& FILENAME_CMP (ptr->name, head->filename) == 0)
1999-05-03 15:29:11 +08:00
{
found = TRUE;
1999-05-03 15:29:11 +08:00
function (head, prev);
}
prev = head;
}
if (! found)
fprintf (stderr, _("No entry %s in archive.\n"), ptr->name);
}
}
}
static void
ar_directory_doer (bfd *abfd, bfd *ignore ATTRIBUTE_UNUSED)
1999-05-03 15:29:11 +08:00
{
2002-05-27 23:46:10 +08:00
print_arelt_descr(outfile, abfd, verbose);
1999-05-03 15:29:11 +08:00
}
void
ar_directory (char *ar_name, struct list *list, char *output)
1999-05-03 15:29:11 +08:00
{
bfd *arch;
arch = open_inarch (ar_name, (char *) NULL);
if (output)
{
outfile = fopen(output,"w");
if (outfile == 0)
{
outfile = stdout;
fprintf (stderr,_("Can't open file %s\n"), output);
output = 0;
}
}
else
1999-05-03 15:29:11 +08:00
outfile = stdout;
map_over_list (arch, ar_directory_doer, list);
bfd_close (arch);
if (output)
fclose (outfile);
}
void
prompt (void)
1999-05-03 15:29:11 +08:00
{
extern int interactive;
2002-05-27 23:46:10 +08:00
if (interactive)
2002-05-27 23:46:10 +08:00
{
printf ("AR >");
fflush (stdout);
}
1999-05-03 15:29:11 +08:00
}
void
maybequit (void)
1999-05-03 15:29:11 +08:00
{
if (! interactive)
1999-05-03 15:29:11 +08:00
xexit (9);
}
2002-05-27 23:46:10 +08:00
void
ar_open (char *name, int t)
1999-05-03 15:29:11 +08:00
{
char *tname = (char *) xmalloc (strlen (name) + 10);
const char *bname = lbasename (name);
1999-05-03 15:29:11 +08:00
real_name = name;
2002-05-27 23:46:10 +08:00
/* Prepend tmp- to the beginning, to avoid file-name clashes after
truncation on filesystems with limited namespaces (DOS). */
2002-05-27 23:46:10 +08:00
sprintf (tname, "%.*stmp-%s", (int) (bname - name), name, bname);
obfd = bfd_openw (tname, NULL);
if (!obfd)
{
fprintf (stderr,
_("%s: Can't open output archive %s\n"),
program_name, tname);
maybequit ();
1999-05-03 15:29:11 +08:00
}
2002-05-27 23:46:10 +08:00
else
{
if (!t)
{
bfd **ptr;
bfd *element;
bfd *ibfd;
1999-05-03 15:29:11 +08:00
2002-05-27 23:46:10 +08:00
ibfd = bfd_openr (name, NULL);
1999-05-03 15:29:11 +08:00
2002-05-27 23:46:10 +08:00
if (!ibfd)
{
fprintf (stderr,_("%s: Can't open input archive %s\n"),
program_name, name);
maybequit ();
return;
}
if (!bfd_check_format(ibfd, bfd_archive))
2002-05-27 23:46:10 +08:00
{
fprintf (stderr,
_("%s: file %s is not an archive\n"),
program_name, name);
maybequit ();
return;
}
ptr = &(obfd->archive_head);
element = bfd_openr_next_archived_file (ibfd, NULL);
while (element)
{
*ptr = element;
ptr = &element->archive_next;
2002-05-27 23:46:10 +08:00
element = bfd_openr_next_archived_file (ibfd, element);
}
}
bfd_set_format (obfd, bfd_archive);
1999-05-03 15:29:11 +08:00
2002-05-27 23:46:10 +08:00
obfd->has_armap = 1;
Add support for thin archives. * bfd/archive.c (_bfd_find_nested_archive): New function. (get_extended_arelt_filename): Add origin parameter. (_bfd_generic_read_ar_hdr_mag): Deal with extended name combined with a file offset. (append_relative_path): New function. (_bfd_get_elt_at_filepos): Deal with external members and nested archives. (bfd_generic_openr_next_archived_file): Thin archives. (bfd_generic_archive_p): Recognize new magic string. (adjust_relative_path): New function. (_bfd_construct_extended_name_table): Construct extended names for thin archive members. (_bfd_write_archive_contents): Emit new magic string, skip copying files for thin archives. * bfd/bfd-in.h (bfd_is_thin_archive): New macro. * bfd/bfd.c (struct bfd): New fields for thin archives. * bfd/libbfd-in.h (struct areltdata): New field for thin archives. * bfd/opncls.c (bfd_close): Delete BFDs for nested archives. * binutils/ar.c (make_thin_archive): New global flag. (map_over_members): Deal with full pathnames in thin archives. (usage, main): Add 'T' option for building thin archives. (replace_members): Pass thin archive flag to ar_emul_append. * binutils/arsup.c (ar_open): Initialize new flag. * binutils/binemul.c (ar_emul_append): Add new parameter for flattening nested archives. (do_ar_emul_default_append): New function. (ar_emul_default_append): Factored out recursive code. * binutils/binemul.h (ar_emul_default_append): Add new parameter. (struct bin_emulation_xfer_struct): New parameter for ar_append. * binutils/dlltool.c (gen_lib_file): Initialize thin archive flag. * binutils/emul_aix.c (ar_emul_aix_internal): Add new flatten parameter, currently unimplemented. All callers changed. * binutils/objcopy.c (copy_archive): Preserve thin archive flag. * binutils/doc/binutils.texi: Update ar documentation. * binutils/testsuite/binutils-all/ar.exp: Add thin archive tests. * include/aout/ar.h (ARMAGT): New magic string for thin archives.
2008-03-28 14:49:44 +08:00
obfd->is_thin_archive = 0;
2002-05-27 23:46:10 +08:00
}
}
1999-05-03 15:29:11 +08:00
static void
ar_addlib_doer (bfd *abfd, bfd *prev)
1999-05-03 15:29:11 +08:00
{
2002-05-27 23:46:10 +08:00
/* Add this module to the output bfd. */
1999-05-03 15:29:11 +08:00
if (prev != NULL)
prev->archive_next = abfd->archive_next;
2002-05-27 23:46:10 +08:00
abfd->archive_next = obfd->archive_head;
1999-05-03 15:29:11 +08:00
obfd->archive_head = abfd;
}
void
ar_addlib (char *name, struct list *list)
1999-05-03 15:29:11 +08:00
{
if (obfd == NULL)
{
fprintf (stderr, _("%s: no output archive specified yet\n"), program_name);
maybequit ();
}
else
{
bfd *arch;
arch = open_inarch (name, (char *) NULL);
if (arch != NULL)
map_over_list (arch, ar_addlib_doer, list);
/* Don't close the bfd, since it will make the elements disappear. */
1999-05-03 15:29:11 +08:00
}
}
void
ar_addmod (struct list *list)
1999-05-03 15:29:11 +08:00
{
2002-05-27 23:46:10 +08:00
if (!obfd)
{
fprintf (stderr, _("%s: no open output archive\n"), program_name);
maybequit ();
}
else
2002-05-27 23:46:10 +08:00
{
while (list)
{
bfd *abfd = bfd_openr (list->name, NULL);
if (!abfd)
{
fprintf (stderr, _("%s: can't open file %s\n"),
program_name, list->name);
maybequit ();
}
else
{
abfd->archive_next = obfd->archive_head;
2002-05-27 23:46:10 +08:00
obfd->archive_head = abfd;
}
list = list->next;
}
1999-05-03 15:29:11 +08:00
}
}
void
ar_clear (void)
1999-05-03 15:29:11 +08:00
{
2002-05-27 23:46:10 +08:00
if (obfd)
obfd->archive_head = 0;
1999-05-03 15:29:11 +08:00
}
void
ar_delete (struct list *list)
1999-05-03 15:29:11 +08:00
{
2002-05-27 23:46:10 +08:00
if (!obfd)
{
fprintf (stderr, _("%s: no open output archive\n"), program_name);
maybequit ();
}
else
2002-05-27 23:46:10 +08:00
{
while (list)
{
/* Find this name in the archive. */
bfd *member = obfd->archive_head;
bfd **prev = &(obfd->archive_head);
int found = 0;
while (member)
{
if (FILENAME_CMP(member->filename, list->name) == 0)
{
*prev = member->archive_next;
2002-05-27 23:46:10 +08:00
found = 1;
}
else
prev = &(member->archive_next);
2002-05-27 23:46:10 +08:00
member = member->archive_next;
2002-05-27 23:46:10 +08:00
}
if (!found)
{
fprintf (stderr, _("%s: can't find module file %s\n"),
program_name, list->name);
maybequit ();
}
list = list->next;
1999-05-03 15:29:11 +08:00
}
}
}
void
ar_save (void)
1999-05-03 15:29:11 +08:00
{
2002-05-27 23:46:10 +08:00
if (!obfd)
{
fprintf (stderr, _("%s: no open output archive\n"), program_name);
maybequit ();
}
else
{
char *ofilename = xstrdup (bfd_get_filename (obfd));
1999-05-03 15:29:11 +08:00
if (deterministic > 0)
obfd->flags |= BFD_DETERMINISTIC_OUTPUT;
2002-05-27 23:46:10 +08:00
bfd_close (obfd);
1999-05-03 15:29:11 +08:00
smart_rename (ofilename, real_name, 0);
2002-05-27 23:46:10 +08:00
obfd = 0;
free (ofilename);
}
}
1999-05-03 15:29:11 +08:00
void
ar_replace (struct list *list)
1999-05-03 15:29:11 +08:00
{
2002-05-27 23:46:10 +08:00
if (!obfd)
{
fprintf (stderr, _("%s: no open output archive\n"), program_name);
maybequit ();
}
else
2002-05-27 23:46:10 +08:00
{
while (list)
1999-05-03 15:29:11 +08:00
{
2002-05-27 23:46:10 +08:00
/* Find this name in the archive. */
bfd *member = obfd->archive_head;
bfd **prev = &(obfd->archive_head);
int found = 0;
while (member)
{
if (FILENAME_CMP (member->filename, list->name) == 0)
{
/* Found the one to replace. */
bfd *abfd = bfd_openr (list->name, 0);
if (!abfd)
{
fprintf (stderr, _("%s: can't open file %s\n"),
program_name, list->name);
maybequit ();
}
else
{
*prev = abfd;
abfd->archive_next = member->archive_next;
2002-05-27 23:46:10 +08:00
found = 1;
}
}
else
{
prev = &(member->archive_next);
2002-05-27 23:46:10 +08:00
}
member = member->archive_next;
2002-05-27 23:46:10 +08:00
}
if (!found)
{
bfd *abfd = bfd_openr (list->name, 0);
1999-05-03 15:29:11 +08:00
2002-05-27 23:46:10 +08:00
fprintf (stderr,_("%s: can't find module file %s\n"),
program_name, list->name);
if (!abfd)
{
fprintf (stderr, _("%s: can't open file %s\n"),
program_name, list->name);
maybequit ();
}
else
*prev = abfd;
}
list = list->next;
}
1999-05-03 15:29:11 +08:00
}
}
2002-05-27 23:46:10 +08:00
/* And I added this one. */
1999-05-03 15:29:11 +08:00
void
ar_list (void)
1999-05-03 15:29:11 +08:00
{
if (!obfd)
1999-05-03 15:29:11 +08:00
{
2002-05-27 23:46:10 +08:00
fprintf (stderr, _("%s: no open output archive\n"), program_name);
maybequit ();
1999-05-03 15:29:11 +08:00
}
2002-05-27 23:46:10 +08:00
else
{
bfd *abfd;
outfile = stdout;
verbose =1 ;
printf (_("Current open archive is %s\n"), bfd_get_filename (obfd));
1999-05-03 15:29:11 +08:00
2002-05-27 23:46:10 +08:00
for (abfd = obfd->archive_head;
abfd != (bfd *)NULL;
abfd = abfd->archive_next)
2002-05-27 23:46:10 +08:00
ar_directory_doer (abfd, (bfd *) NULL);
}
}
1999-05-03 15:29:11 +08:00
void
ar_end (void)
1999-05-03 15:29:11 +08:00
{
if (obfd)
2002-05-27 23:46:10 +08:00
{
bfd_cache_close (obfd);
2002-05-27 23:46:10 +08:00
unlink (bfd_get_filename (obfd));
}
1999-05-03 15:29:11 +08:00
}
2002-05-27 23:46:10 +08:00
1999-05-03 15:29:11 +08:00
void
ar_extract (struct list *list)
1999-05-03 15:29:11 +08:00
{
if (!obfd)
2002-05-27 23:46:10 +08:00
{
fprintf (stderr, _("%s: no open archive\n"), program_name);
maybequit ();
}
else
2002-05-27 23:46:10 +08:00
{
while (list)
1999-05-03 15:29:11 +08:00
{
2002-05-27 23:46:10 +08:00
/* Find this name in the archive. */
bfd *member = obfd->archive_head;
int found = 0;
while (member && !found)
{
if (FILENAME_CMP (member->filename, list->name) == 0)
{
extract_file (member);
found = 1;
}
member = member->archive_next;
2002-05-27 23:46:10 +08:00
}
if (!found)
{
bfd_openr (list->name, 0);
fprintf (stderr, _("%s: can't find module file %s\n"),
program_name, list->name);
}
list = list->next;
}
1999-05-03 15:29:11 +08:00
}
}