binutils-gdb/binutils/arsup.c

516 lines
10 KiB
C
Raw Normal View History

1999-05-03 15:29:11 +08:00
/* arsup.c - Archive support for MRI compatibility
Copyright (C) 1992-2024 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 char *temp_name;
static int temp_fd;
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)
{
bool 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 (bfd_get_filename (head) != NULL
&& FILENAME_CMP (ptr->name, bfd_get_filename (head)) == 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
{
print_arelt_descr(outfile, abfd, verbose, false);
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
{
real_name = xstrdup (name);
temp_name = make_tempname (real_name, &temp_fd);
2002-05-27 23:46:10 +08:00
if (temp_name == NULL)
{
fprintf (stderr, _("%s: Can't open temporary file (%s)\n"),
program_name, strerror(errno));
maybequit ();
return;
}
obfd = bfd_fdopenw (temp_name, NULL, temp_fd);
2002-05-27 23:46:10 +08:00
if (!obfd)
{
fprintf (stderr,
_("%s: Can't open output archive %s\n"),
program_name, temp_name);
2002-05-27 23:46:10 +08:00
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
#if BFD_SUPPORTS_PLUGINS
ibfd = bfd_openr (name, "plugin");
#else
2002-05-27 23:46:10 +08:00
ibfd = bfd_openr (name, NULL);
#endif
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;
2002-05-27 23:46:10 +08:00
#if BFD_SUPPORTS_PLUGINS
abfd = bfd_openr (list->name, "plugin");
#else
abfd = bfd_openr (list->name, NULL);
#endif
2002-05-27 23:46:10 +08:00
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 (bfd_get_filename (member), list->name) == 0)
2002-05-27 23:46:10 +08:00
{
*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
{
binutils: Make smart_rename safe too smart_rename is capable of handling symlinks by copying and it also tries to preserve ownership and permissions of files when they're overwritten during the rename. This is useful in objcopy where the file properties need to be preserved. However because smart_rename does this using file names, it leaves a race window between renames and permission fixes. This change removes this race window by using file descriptors from the original BFDs that were used to manipulate these files wherever possible. The file that is to be renamed is also passed as a file descriptor so that we use fchown/fchmod on the file descriptor, thus making sure that we only modify the file we have opened to write. Further, in case the file is to be overwritten (as is the case in ar or objcopy), the permissions that need to be restored are taken from the file descriptor that was opened for input so that integrity of the file status is maintained all the way through to the rename. binutils/ * rename.c * ar.c (write_archive) [!defined (_WIN32) || defined (__CYGWIN32__)]: Initialize TARGET_STAT and OFD to pass to SMART_RENAME. * arsup.c (ar_save) [defined (_WIN32) || defined (__CYGWIN32__)]: Likewise. * bucomm.h (smart_rename): Add new arguments to declaration. * objcopy.c (strip_main)[defined (_WIN32) || defined (__CYGWIN32__)]: Initialize COPYFD and pass to SMART_RENAME. (copy_main) [defined (_WIN32) || defined (__CYGWIN32__)]: Likewise. * rename.c (try_preserve_permissions): New function. (smart_rename): Use it and add new arguments.
2020-12-07 23:18:33 +08:00
struct stat target_stat;
1999-05-03 15:29:11 +08:00
if (deterministic > 0)
obfd->flags |= BFD_DETERMINISTIC_OUTPUT;
temp_fd = dup (temp_fd);
2002-05-27 23:46:10 +08:00
bfd_close (obfd);
1999-05-03 15:29:11 +08:00
if (stat (real_name, &target_stat) != 0)
{
/* The temp file created in ar_open has mode 0600 as per mkstemp.
Create the real empty output file here so smart_rename will
update the mode according to the process umask. */
obfd = bfd_openw (real_name, NULL);
if (obfd != NULL)
{
bfd_set_format (obfd, bfd_archive);
bfd_close (obfd);
}
}
smart_rename (temp_name, real_name, temp_fd, NULL, false);
2002-05-27 23:46:10 +08:00
obfd = 0;
free (temp_name);
free (real_name);
2002-05-27 23:46:10 +08:00
}
}
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 (bfd_get_filename (member), list->name) == 0)
2002-05-27 23:46:10 +08:00
{
/* Found the one to replace. */
bfd *abfd = bfd_openr (list->name, NULL);
2002-05-27 23:46:10 +08:00
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, NULL);
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
{
const char *filename = bfd_get_filename (obfd);
bfd_close_all_done (obfd);
unlink (filename);
2002-05-27 23:46:10 +08:00
}
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 (bfd_get_filename (member), list->name) == 0)
2002-05-27 23:46:10 +08:00
{
extract_file (member);
found = 1;
}
member = member->archive_next;
2002-05-27 23:46:10 +08:00
}
if (!found)
{
bfd_openr (list->name, NULL);
2002-05-27 23:46:10 +08:00
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
}
}