mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-01-06 12:09:26 +08:00
3685de750e
Renaming over existing files needs additional care to restore permissions and ownership, which may not always succeed. Additionally, other properties of the file such as extended attributes may be lost, making the operation flaky. For predictable results, resort to rename() only if the file does not exist, otherwise copy the file contents into the existing file. This ensures that no additional tricks are needed to retain file properties. This also allows dropping of the redundant set_times on the tmpfile in objcopy/strip since now we no longer rename over existing files. binutils/ * ar.c (write_archive): Remove TARGET_STAT. Adjust call to SMART_RENAME. * arsup.c (ar_save): Likewise. * objcopy (strip_main): Don't copy TMPFD. Don't set times on temporary file and adjust call to SMART_RENAME. (copy_main): Likewise. * rename.c [!S_ISLNK]: Remove definitions. (try_preserve_permissions): Remove function. (smart_rename): Remove FD, PRESERVE_DATES arguments. Use rename system call only if TO does not exist. * bucomm.h (smart_rename): Adjust declaration.
510 lines
9.9 KiB
C
510 lines
9.9 KiB
C
/* arsup.c - Archive support for MRI compatibility
|
|
Copyright (C) 1992-2021 Free Software Foundation, Inc.
|
|
|
|
This file is part of GNU Binutils.
|
|
|
|
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
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
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.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
|
|
/* Contributed by Steve Chamberlain
|
|
sac@cygnus.com
|
|
|
|
This file looks after requests from arparse.y, to provide the MRI
|
|
style librarian command syntax + 1 word LIST. */
|
|
|
|
#include "sysdep.h"
|
|
#include "bfd.h"
|
|
#include "libiberty.h"
|
|
#include "filenames.h"
|
|
#include "bucomm.h"
|
|
#include "arsup.h"
|
|
|
|
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 *);
|
|
|
|
extern int verbose;
|
|
extern int deterministic;
|
|
|
|
static bfd *obfd;
|
|
static char *real_name;
|
|
static char *temp_name;
|
|
static int real_ofd;
|
|
static FILE *outfile;
|
|
|
|
static void
|
|
map_over_list (bfd *arch, void (*function) (bfd *, bfd *), struct list *list)
|
|
{
|
|
bfd *head;
|
|
|
|
if (list == NULL)
|
|
{
|
|
bfd *next;
|
|
|
|
head = arch->archive_next;
|
|
while (head != NULL)
|
|
{
|
|
next = head->archive_next;
|
|
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;
|
|
bfd *prev = arch;
|
|
|
|
for (head = arch->archive_next; head; head = head->archive_next)
|
|
{
|
|
if (bfd_get_filename (head) != NULL
|
|
&& FILENAME_CMP (ptr->name, bfd_get_filename (head)) == 0)
|
|
{
|
|
found = TRUE;
|
|
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)
|
|
{
|
|
print_arelt_descr(outfile, abfd, verbose, FALSE);
|
|
}
|
|
|
|
void
|
|
ar_directory (char *ar_name, struct list *list, char *output)
|
|
{
|
|
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
|
|
outfile = stdout;
|
|
|
|
map_over_list (arch, ar_directory_doer, list);
|
|
|
|
bfd_close (arch);
|
|
|
|
if (output)
|
|
fclose (outfile);
|
|
}
|
|
|
|
void
|
|
prompt (void)
|
|
{
|
|
extern int interactive;
|
|
|
|
if (interactive)
|
|
{
|
|
printf ("AR >");
|
|
fflush (stdout);
|
|
}
|
|
}
|
|
|
|
void
|
|
maybequit (void)
|
|
{
|
|
if (! interactive)
|
|
xexit (9);
|
|
}
|
|
|
|
|
|
void
|
|
ar_open (char *name, int t)
|
|
{
|
|
real_name = xstrdup (name);
|
|
temp_name = make_tempname (real_name, &real_ofd);
|
|
|
|
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, real_ofd);
|
|
|
|
if (!obfd)
|
|
{
|
|
fprintf (stderr,
|
|
_("%s: Can't open output archive %s\n"),
|
|
program_name, temp_name);
|
|
|
|
maybequit ();
|
|
}
|
|
else
|
|
{
|
|
if (!t)
|
|
{
|
|
bfd **ptr;
|
|
bfd *element;
|
|
bfd *ibfd;
|
|
|
|
ibfd = bfd_openr (name, NULL);
|
|
|
|
if (!ibfd)
|
|
{
|
|
fprintf (stderr,_("%s: Can't open input archive %s\n"),
|
|
program_name, name);
|
|
maybequit ();
|
|
return;
|
|
}
|
|
|
|
if (!bfd_check_format(ibfd, bfd_archive))
|
|
{
|
|
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;
|
|
element = bfd_openr_next_archived_file (ibfd, element);
|
|
}
|
|
}
|
|
|
|
bfd_set_format (obfd, bfd_archive);
|
|
|
|
obfd->has_armap = 1;
|
|
obfd->is_thin_archive = 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
ar_addlib_doer (bfd *abfd, bfd *prev)
|
|
{
|
|
/* Add this module to the output bfd. */
|
|
if (prev != NULL)
|
|
prev->archive_next = abfd->archive_next;
|
|
|
|
abfd->archive_next = obfd->archive_head;
|
|
obfd->archive_head = abfd;
|
|
}
|
|
|
|
void
|
|
ar_addlib (char *name, struct list *list)
|
|
{
|
|
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. */
|
|
}
|
|
}
|
|
|
|
void
|
|
ar_addmod (struct list *list)
|
|
{
|
|
if (!obfd)
|
|
{
|
|
fprintf (stderr, _("%s: no open output archive\n"), program_name);
|
|
maybequit ();
|
|
}
|
|
else
|
|
{
|
|
while (list)
|
|
{
|
|
bfd *abfd;
|
|
|
|
#if BFD_SUPPORTS_PLUGINS
|
|
abfd = bfd_openr (list->name, "plugin");
|
|
#else
|
|
abfd = bfd_openr (list->name, NULL);
|
|
#endif
|
|
if (!abfd)
|
|
{
|
|
fprintf (stderr, _("%s: can't open file %s\n"),
|
|
program_name, list->name);
|
|
maybequit ();
|
|
}
|
|
else
|
|
{
|
|
abfd->archive_next = obfd->archive_head;
|
|
obfd->archive_head = abfd;
|
|
}
|
|
list = list->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ar_clear (void)
|
|
{
|
|
if (obfd)
|
|
obfd->archive_head = 0;
|
|
}
|
|
|
|
void
|
|
ar_delete (struct list *list)
|
|
{
|
|
if (!obfd)
|
|
{
|
|
fprintf (stderr, _("%s: no open output archive\n"), program_name);
|
|
maybequit ();
|
|
}
|
|
else
|
|
{
|
|
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)
|
|
{
|
|
*prev = member->archive_next;
|
|
found = 1;
|
|
}
|
|
else
|
|
prev = &(member->archive_next);
|
|
|
|
member = member->archive_next;
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
fprintf (stderr, _("%s: can't find module file %s\n"),
|
|
program_name, list->name);
|
|
maybequit ();
|
|
}
|
|
|
|
list = list->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
ar_save (void)
|
|
{
|
|
if (!obfd)
|
|
{
|
|
fprintf (stderr, _("%s: no open output archive\n"), program_name);
|
|
maybequit ();
|
|
}
|
|
else
|
|
{
|
|
struct stat target_stat;
|
|
|
|
if (deterministic > 0)
|
|
obfd->flags |= BFD_DETERMINISTIC_OUTPUT;
|
|
|
|
bfd_close (obfd);
|
|
|
|
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, NULL);
|
|
obfd = 0;
|
|
free (temp_name);
|
|
free (real_name);
|
|
}
|
|
}
|
|
|
|
void
|
|
ar_replace (struct list *list)
|
|
{
|
|
if (!obfd)
|
|
{
|
|
fprintf (stderr, _("%s: no open output archive\n"), program_name);
|
|
maybequit ();
|
|
}
|
|
else
|
|
{
|
|
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)
|
|
{
|
|
/* Found the one to replace. */
|
|
bfd *abfd = bfd_openr (list->name, NULL);
|
|
|
|
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;
|
|
found = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
prev = &(member->archive_next);
|
|
}
|
|
member = member->archive_next;
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
bfd *abfd = bfd_openr (list->name, NULL);
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* And I added this one. */
|
|
void
|
|
ar_list (void)
|
|
{
|
|
if (!obfd)
|
|
{
|
|
fprintf (stderr, _("%s: no open output archive\n"), program_name);
|
|
maybequit ();
|
|
}
|
|
else
|
|
{
|
|
bfd *abfd;
|
|
|
|
outfile = stdout;
|
|
verbose =1 ;
|
|
printf (_("Current open archive is %s\n"), bfd_get_filename (obfd));
|
|
|
|
for (abfd = obfd->archive_head;
|
|
abfd != (bfd *)NULL;
|
|
abfd = abfd->archive_next)
|
|
ar_directory_doer (abfd, (bfd *) NULL);
|
|
}
|
|
}
|
|
|
|
void
|
|
ar_end (void)
|
|
{
|
|
if (obfd)
|
|
{
|
|
bfd_cache_close (obfd);
|
|
unlink (bfd_get_filename (obfd));
|
|
}
|
|
}
|
|
|
|
void
|
|
ar_extract (struct list *list)
|
|
{
|
|
if (!obfd)
|
|
{
|
|
fprintf (stderr, _("%s: no open archive\n"), program_name);
|
|
maybequit ();
|
|
}
|
|
else
|
|
{
|
|
while (list)
|
|
{
|
|
/* 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)
|
|
{
|
|
extract_file (member);
|
|
found = 1;
|
|
}
|
|
|
|
member = member->archive_next;
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
bfd_openr (list->name, NULL);
|
|
fprintf (stderr, _("%s: can't find module file %s\n"),
|
|
program_name, list->name);
|
|
}
|
|
|
|
list = list->next;
|
|
}
|
|
}
|
|
}
|