|  | /* arsup.c - Archive support for MRI compatibility | 
|  | Copyright (C) 1992-2025 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 temp_fd; | 
|  | 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) | 
|  | { | 
|  | bool 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, &temp_fd); | 
|  |  | 
|  | 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); | 
|  |  | 
|  | 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; | 
|  |  | 
|  | #if BFD_SUPPORTS_PLUGINS | 
|  | ibfd = bfd_openr (name, "plugin"); | 
|  | #else | 
|  | ibfd = bfd_openr (name, NULL); | 
|  | #endif | 
|  |  | 
|  | 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; | 
|  |  | 
|  | temp_fd = dup (temp_fd); | 
|  | 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, temp_fd, NULL, false); | 
|  | 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) | 
|  | { | 
|  | const char *filename = bfd_get_filename (obfd); | 
|  | bfd_close_all_done (obfd); | 
|  | unlink (filename); | 
|  | } | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  | } | 
|  | } |