summaryrefslogtreecommitdiff
path: root/bfd/archive.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@bigpond.net.au>2012-08-09 06:25:51 +0000
committerAlan Modra <amodra@bigpond.net.au>2012-08-09 06:25:51 +0000
commit65ee7152078ced10bdaf73f843bc2690b37e6181 (patch)
tree9e479575db8f703bee5c8fdc7a96278a43638fbd /bfd/archive.c
parent0c795959aeca42776a247b32853454e003f4f95a (diff)
downloadbinutils-redhat-65ee7152078ced10bdaf73f843bc2690b37e6181.tar.gz
* archive.c (SECTION Archives): Update documentation.
(_bfd_delete_archive_data): Remove. (_bfd_add_bfd_to_archive_cache): Set 'parent_cache' and 'key'. (archive_close_worker, _bfd_archive_close_and_cleanup): New functions. * libbfd-in.h (struct areltdata <parent_cache, key>): New fields. (_bfd_delete_archive_data): Don't declare. (_bfd_archive_close_and_cleanup): Declare. (_bfd_generic_close_and_cleanup): Redefine. * libbfd.h: Rebuild. * opncls.c (_bfd_delete_bfd): Don't call _bfd_delete_archive_data. (bfd_close): Don't close nested thin archives here.
Diffstat (limited to 'bfd/archive.c')
-rw-r--r--bfd/archive.c86
1 files changed, 69 insertions, 17 deletions
diff --git a/bfd/archive.c b/bfd/archive.c
index 1148c115fd..dc67da79e0 100644
--- a/bfd/archive.c
+++ b/bfd/archive.c
@@ -42,11 +42,17 @@ DESCRIPTION
have to read the entire archive if you don't want
to! Read it until you find what you want.
+ A BFD returned by <<bfd_openr_next_archived_file>> can be
+ closed manually with <<bfd_close>>. If you do not close it,
+ then a second iteration through the members of an archive may
+ return the same BFD. If you close the archive BFD, then all
+ the member BFDs will automatically be closed as well.
+
Archive contents of output BFDs are chained through the
- <<next>> pointer in a BFD. The first one is findable through
- the <<archive_head>> slot of the archive. Set it with
- <<bfd_set_archive_head>> (q.v.). A given BFD may be in only one
- open output archive at a time.
+ <<archive_next>> pointer in a BFD. The first one is findable
+ through the <<archive_head>> slot of the archive. Set it with
+ <<bfd_set_archive_head>> (q.v.). A given BFD may be in only
+ one open output archive at a time.
As expected, the BFD archive code is more general than the
archive code of any given environment. BFD archives may
@@ -293,19 +299,6 @@ bfd_set_archive_head (bfd *output_archive, bfd *new_head)
return TRUE;
}
-/* Free the archive hash table, if it exists. */
-
-void
-_bfd_delete_archive_data (bfd *abfd)
-{
- struct artdata *ardata = bfd_ardata (abfd);
-
- BFD_ASSERT (abfd->format == bfd_archive);
-
- if (ardata && ardata->cache)
- htab_delete (ardata->cache);
-}
-
bfd *
_bfd_look_for_bfd_in_cache (bfd *arch_bfd, file_ptr filepos)
{
@@ -375,6 +368,10 @@ _bfd_add_bfd_to_archive_cache (bfd *arch_bfd, file_ptr filepos, bfd *new_elt)
cache->arbfd = new_elt;
*htab_find_slot (hash_table, (const void *) cache, INSERT) = cache;
+ /* Provide a means of accessing this from child. */
+ arch_eltdata (new_elt)->parent_cache = hash_table;
+ arch_eltdata (new_elt)->key = filepos;
+
return TRUE;
}
@@ -2695,3 +2692,58 @@ coff_write_armap (bfd *arch,
return TRUE;
}
+
+static int
+archive_close_worker (void **slot, void *inf ATTRIBUTE_UNUSED)
+{
+ struct ar_cache *ent = (struct ar_cache *) *slot;
+
+ bfd_close_all_done (ent->arbfd);
+ return 1;
+}
+
+bfd_boolean
+_bfd_archive_close_and_cleanup (bfd *abfd)
+{
+ if (bfd_read_p (abfd) && abfd->format == bfd_archive)
+ {
+ bfd *nbfd;
+ bfd *next;
+ htab_t htab;
+
+ /* Close nested archives (if this bfd is a thin archive). */
+ for (nbfd = abfd->nested_archives; nbfd; nbfd = next)
+ {
+ next = nbfd->archive_next;
+ bfd_close (nbfd);
+ }
+
+ htab = bfd_ardata (abfd)->cache;
+ if (htab)
+ {
+ htab_traverse_noresize (htab, archive_close_worker, NULL);
+ htab_delete (htab);
+ bfd_ardata (abfd)->cache = NULL;
+ }
+ }
+ else if (arch_eltdata (abfd) != NULL)
+ {
+ struct areltdata *ared = arch_eltdata (abfd);
+ htab_t htab = (htab_t) ared->parent_cache;
+
+ if (htab)
+ {
+ struct ar_cache ent;
+ void **slot;
+
+ ent.ptr = ared->key;
+ slot = htab_find_slot (htab, &ent, NO_INSERT);
+ if (slot != NULL)
+ {
+ BFD_ASSERT (((struct ar_cache *) *slot)->arbfd == abfd);
+ htab_clear_slot (htab, slot);
+ }
+ }
+ }
+ return TRUE;
+}