xref: /openbsd-src/gnu/usr.bin/binutils-2.17/bfd/archive.c (revision 314e8fdf1443639b5fc22b2a54bda4404fbe472a)
13d8817e4Smiod /* BFD back-end for archive files (libraries).
23d8817e4Smiod    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
33d8817e4Smiod    2000, 2001, 2002, 2003, 2004, 2005
43d8817e4Smiod    Free Software Foundation, Inc.
53d8817e4Smiod    Written by Cygnus Support.  Mostly Gumby Henkel-Wallace's fault.
63d8817e4Smiod 
73d8817e4Smiod    This file is part of BFD, the Binary File Descriptor library.
83d8817e4Smiod 
93d8817e4Smiod    This program is free software; you can redistribute it and/or modify
103d8817e4Smiod    it under the terms of the GNU General Public License as published by
113d8817e4Smiod    the Free Software Foundation; either version 2 of the License, or
123d8817e4Smiod    (at your option) any later version.
133d8817e4Smiod 
143d8817e4Smiod    This program is distributed in the hope that it will be useful,
153d8817e4Smiod    but WITHOUT ANY WARRANTY; without even the implied warranty of
163d8817e4Smiod    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
173d8817e4Smiod    GNU General Public License for more details.
183d8817e4Smiod 
193d8817e4Smiod    You should have received a copy of the GNU General Public License
203d8817e4Smiod    along with this program; if not, write to the Free Software
213d8817e4Smiod    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
223d8817e4Smiod 
233d8817e4Smiod /*
243d8817e4Smiod @setfilename archive-info
253d8817e4Smiod SECTION
263d8817e4Smiod 	Archives
273d8817e4Smiod 
283d8817e4Smiod DESCRIPTION
293d8817e4Smiod 	An archive (or library) is just another BFD.  It has a symbol
303d8817e4Smiod 	table, although there's not much a user program will do with it.
313d8817e4Smiod 
323d8817e4Smiod 	The big difference between an archive BFD and an ordinary BFD
333d8817e4Smiod 	is that the archive doesn't have sections.  Instead it has a
343d8817e4Smiod 	chain of BFDs that are considered its contents.  These BFDs can
353d8817e4Smiod 	be manipulated like any other.  The BFDs contained in an
363d8817e4Smiod 	archive opened for reading will all be opened for reading.  You
373d8817e4Smiod 	may put either input or output BFDs into an archive opened for
383d8817e4Smiod 	output; they will be handled correctly when the archive is closed.
393d8817e4Smiod 
403d8817e4Smiod 	Use <<bfd_openr_next_archived_file>> to step through
413d8817e4Smiod 	the contents of an archive opened for input.  You don't
423d8817e4Smiod 	have to read the entire archive if you don't want
433d8817e4Smiod 	to!  Read it until you find what you want.
443d8817e4Smiod 
453d8817e4Smiod 	Archive contents of output BFDs are chained through the
463d8817e4Smiod 	<<next>> pointer in a BFD.  The first one is findable through
473d8817e4Smiod 	the <<archive_head>> slot of the archive.  Set it with
483d8817e4Smiod 	<<bfd_set_archive_head>> (q.v.).  A given BFD may be in only one
493d8817e4Smiod 	open output archive at a time.
503d8817e4Smiod 
513d8817e4Smiod 	As expected, the BFD archive code is more general than the
523d8817e4Smiod 	archive code of any given environment.  BFD archives may
533d8817e4Smiod 	contain files of different formats (e.g., a.out and coff) and
543d8817e4Smiod 	even different architectures.  You may even place archives
553d8817e4Smiod 	recursively into archives!
563d8817e4Smiod 
573d8817e4Smiod 	This can cause unexpected confusion, since some archive
583d8817e4Smiod 	formats are more expressive than others.  For instance, Intel
593d8817e4Smiod 	COFF archives can preserve long filenames; SunOS a.out archives
603d8817e4Smiod 	cannot.  If you move a file from the first to the second
613d8817e4Smiod 	format and back again, the filename may be truncated.
623d8817e4Smiod 	Likewise, different a.out environments have different
633d8817e4Smiod 	conventions as to how they truncate filenames, whether they
643d8817e4Smiod 	preserve directory names in filenames, etc.  When
653d8817e4Smiod 	interoperating with native tools, be sure your files are
663d8817e4Smiod 	homogeneous.
673d8817e4Smiod 
683d8817e4Smiod 	Beware: most of these formats do not react well to the
693d8817e4Smiod 	presence of spaces in filenames.  We do the best we can, but
703d8817e4Smiod 	can't always handle this case due to restrictions in the format of
713d8817e4Smiod 	archives.  Many Unix utilities are braindead in regards to
723d8817e4Smiod 	spaces and such in filenames anyway, so this shouldn't be much
733d8817e4Smiod 	of a restriction.
743d8817e4Smiod 
753d8817e4Smiod 	Archives are supported in BFD in <<archive.c>>.
763d8817e4Smiod 
773d8817e4Smiod SUBSECTION
783d8817e4Smiod 	Archive functions
793d8817e4Smiod */
803d8817e4Smiod 
813d8817e4Smiod /* Assumes:
823d8817e4Smiod    o - all archive elements start on an even boundary, newline padded;
833d8817e4Smiod    o - all arch headers are char *;
843d8817e4Smiod    o - all arch headers are the same size (across architectures).
853d8817e4Smiod */
863d8817e4Smiod 
873d8817e4Smiod /* Some formats provide a way to cram a long filename into the short
883d8817e4Smiod    (16 chars) space provided by a BSD archive.  The trick is: make a
893d8817e4Smiod    special "file" in the front of the archive, sort of like the SYMDEF
903d8817e4Smiod    entry.  If the filename is too long to fit, put it in the extended
913d8817e4Smiod    name table, and use its index as the filename.  To prevent
923d8817e4Smiod    confusion prepend the index with a space.  This means you can't
933d8817e4Smiod    have filenames that start with a space, but then again, many Unix
943d8817e4Smiod    utilities can't handle that anyway.
953d8817e4Smiod 
963d8817e4Smiod    This scheme unfortunately requires that you stand on your head in
973d8817e4Smiod    order to write an archive since you need to put a magic file at the
983d8817e4Smiod    front, and need to touch every entry to do so.  C'est la vie.
993d8817e4Smiod 
1003d8817e4Smiod    We support two variants of this idea:
1013d8817e4Smiod    The SVR4 format (extended name table is named "//"),
1023d8817e4Smiod    and an extended pseudo-BSD variant (extended name table is named
1033d8817e4Smiod    "ARFILENAMES/").  The origin of the latter format is uncertain.
1043d8817e4Smiod 
1053d8817e4Smiod    BSD 4.4 uses a third scheme:  It writes a long filename
1063d8817e4Smiod    directly after the header.  This allows 'ar q' to work.
1073d8817e4Smiod    We currently can read BSD 4.4 archives, but not write them.
1083d8817e4Smiod */
1093d8817e4Smiod 
1103d8817e4Smiod /* Summary of archive member names:
1113d8817e4Smiod 
1123d8817e4Smiod  Symbol table (must be first):
1133d8817e4Smiod  "__.SYMDEF       " - Symbol table, Berkeley style, produced by ranlib.
1143d8817e4Smiod  "/               " - Symbol table, system 5 style.
1153d8817e4Smiod 
1163d8817e4Smiod  Long name table (must be before regular file members):
1173d8817e4Smiod  "//              " - Long name table, System 5 R4 style.
1183d8817e4Smiod  "ARFILENAMES/    " - Long name table, non-standard extended BSD (not BSD 4.4).
1193d8817e4Smiod 
1203d8817e4Smiod  Regular file members with short names:
1213d8817e4Smiod  "filename.o/     " - Regular file, System 5 style (embedded spaces ok).
1223d8817e4Smiod  "filename.o      " - Regular file, Berkeley style (no embedded spaces).
1233d8817e4Smiod 
1243d8817e4Smiod  Regular files with long names (or embedded spaces, for BSD variants):
1253d8817e4Smiod  "/18             " - SVR4 style, name at offset 18 in name table.
1263d8817e4Smiod  "#1/23           " - Long name (or embedded spaces) 23 characters long,
1273d8817e4Smiod 		      BSD 4.4 style, full name follows header.
1283d8817e4Smiod 		      Implemented for reading, not writing.
1293d8817e4Smiod  " 18             " - Long name 18 characters long, extended pseudo-BSD.
1303d8817e4Smiod  */
1313d8817e4Smiod 
1323d8817e4Smiod #include "bfd.h"
1333d8817e4Smiod #include "sysdep.h"
1343d8817e4Smiod #include "libiberty.h"
1353d8817e4Smiod #include "libbfd.h"
1363d8817e4Smiod #include "aout/ar.h"
1373d8817e4Smiod #include "aout/ranlib.h"
1383d8817e4Smiod #include "safe-ctype.h"
1393d8817e4Smiod #include "hashtab.h"
1403d8817e4Smiod 
1413d8817e4Smiod #ifndef errno
1423d8817e4Smiod extern int errno;
1433d8817e4Smiod #endif
1443d8817e4Smiod 
1453d8817e4Smiod /* We keep a cache of archive filepointers to archive elements to
1463d8817e4Smiod    speed up searching the archive by filepos.  We only add an entry to
1473d8817e4Smiod    the cache when we actually read one.  We also don't sort the cache;
1483d8817e4Smiod    it's generally short enough to search linearly.
1493d8817e4Smiod    Note that the pointers here point to the front of the ar_hdr, not
1503d8817e4Smiod    to the front of the contents!  */
1513d8817e4Smiod struct ar_cache {
1523d8817e4Smiod   file_ptr ptr;
1533d8817e4Smiod   bfd *arbfd;
1543d8817e4Smiod };
1553d8817e4Smiod 
1563d8817e4Smiod #define ar_padchar(abfd) ((abfd)->xvec->ar_pad_char)
1573d8817e4Smiod #define ar_maxnamelen(abfd) ((abfd)->xvec->ar_max_namelen)
1583d8817e4Smiod 
1593d8817e4Smiod #define arch_eltdata(bfd) ((struct areltdata *) ((bfd)->arelt_data))
1603d8817e4Smiod #define arch_hdr(bfd) ((struct ar_hdr *) arch_eltdata(bfd)->arch_header)
1613d8817e4Smiod 
1623d8817e4Smiod void
_bfd_ar_spacepad(char * p,size_t n,const char * fmt,long val)1633d8817e4Smiod _bfd_ar_spacepad (char *p, size_t n, const char *fmt, long val)
1643d8817e4Smiod {
1653d8817e4Smiod   static char buf[20];
1663d8817e4Smiod   size_t len;
1673d8817e4Smiod   snprintf (buf, sizeof (buf), fmt, val);
1683d8817e4Smiod   len = strlen (buf);
1693d8817e4Smiod   if (len < n)
1703d8817e4Smiod     {
1713d8817e4Smiod       memcpy (p, buf, len);
1723d8817e4Smiod       memset (p + len, ' ', n - len);
1733d8817e4Smiod     }
1743d8817e4Smiod   else
1753d8817e4Smiod     memcpy (p, buf, n);
1763d8817e4Smiod }
1773d8817e4Smiod 
17804a47612Sguenther void
_bfd_ar_spacepadll(char * p,size_t n,const char * fmt,long long val)17904a47612Sguenther _bfd_ar_spacepadll (char *p, size_t n, const char *fmt, long long val)
18004a47612Sguenther {
18104a47612Sguenther   static char buf[20];
18204a47612Sguenther   size_t len;
18304a47612Sguenther   snprintf (buf, sizeof (buf), fmt, val);
18404a47612Sguenther   len = strlen (buf);
18504a47612Sguenther   if (len < n)
18604a47612Sguenther     {
18704a47612Sguenther       memcpy (p, buf, len);
18804a47612Sguenther       memset (p + len, ' ', n - len);
18904a47612Sguenther     }
19004a47612Sguenther   else
19104a47612Sguenther     memcpy (p, buf, n);
19204a47612Sguenther }
19304a47612Sguenther 
1943d8817e4Smiod bfd_boolean
_bfd_generic_mkarchive(bfd * abfd)1953d8817e4Smiod _bfd_generic_mkarchive (bfd *abfd)
1963d8817e4Smiod {
1973d8817e4Smiod   bfd_size_type amt = sizeof (struct artdata);
1983d8817e4Smiod 
1993d8817e4Smiod   abfd->tdata.aout_ar_data = bfd_zalloc (abfd, amt);
2003d8817e4Smiod   if (bfd_ardata (abfd) == NULL)
2013d8817e4Smiod     return FALSE;
2023d8817e4Smiod 
2033d8817e4Smiod   /* Already cleared by bfd_zalloc above.
2043d8817e4Smiod      bfd_ardata (abfd)->cache = NULL;
2053d8817e4Smiod      bfd_ardata (abfd)->archive_head = NULL;
2063d8817e4Smiod      bfd_ardata (abfd)->symdefs = NULL;
2073d8817e4Smiod      bfd_ardata (abfd)->extended_names = NULL;
2083d8817e4Smiod      bfd_ardata (abfd)->extended_names_size = 0;
2093d8817e4Smiod      bfd_ardata (abfd)->tdata = NULL;  */
2103d8817e4Smiod 
2113d8817e4Smiod   return TRUE;
2123d8817e4Smiod }
2133d8817e4Smiod 
2143d8817e4Smiod /*
2153d8817e4Smiod FUNCTION
2163d8817e4Smiod 	bfd_get_next_mapent
2173d8817e4Smiod 
2183d8817e4Smiod SYNOPSIS
2193d8817e4Smiod 	symindex bfd_get_next_mapent
2203d8817e4Smiod 	  (bfd *abfd, symindex previous, carsym **sym);
2213d8817e4Smiod 
2223d8817e4Smiod DESCRIPTION
2233d8817e4Smiod 	Step through archive @var{abfd}'s symbol table (if it
2243d8817e4Smiod 	has one).  Successively update @var{sym} with the next symbol's
2253d8817e4Smiod 	information, returning that symbol's (internal) index into the
2263d8817e4Smiod 	symbol table.
2273d8817e4Smiod 
2283d8817e4Smiod 	Supply <<BFD_NO_MORE_SYMBOLS>> as the @var{previous} entry to get
2293d8817e4Smiod 	the first one; returns <<BFD_NO_MORE_SYMBOLS>> when you've already
2303d8817e4Smiod 	got the last one.
2313d8817e4Smiod 
2323d8817e4Smiod 	A <<carsym>> is a canonical archive symbol.  The only
2333d8817e4Smiod 	user-visible element is its name, a null-terminated string.
2343d8817e4Smiod */
2353d8817e4Smiod 
2363d8817e4Smiod symindex
bfd_get_next_mapent(bfd * abfd,symindex prev,carsym ** entry)2373d8817e4Smiod bfd_get_next_mapent (bfd *abfd, symindex prev, carsym **entry)
2383d8817e4Smiod {
2393d8817e4Smiod   if (!bfd_has_map (abfd))
2403d8817e4Smiod     {
2413d8817e4Smiod       bfd_set_error (bfd_error_invalid_operation);
2423d8817e4Smiod       return BFD_NO_MORE_SYMBOLS;
2433d8817e4Smiod     }
2443d8817e4Smiod 
2453d8817e4Smiod   if (prev == BFD_NO_MORE_SYMBOLS)
2463d8817e4Smiod     prev = 0;
2473d8817e4Smiod   else
2483d8817e4Smiod     ++prev;
2493d8817e4Smiod   if (prev >= bfd_ardata (abfd)->symdef_count)
2503d8817e4Smiod     return BFD_NO_MORE_SYMBOLS;
2513d8817e4Smiod 
2523d8817e4Smiod   *entry = (bfd_ardata (abfd)->symdefs + prev);
2533d8817e4Smiod   return prev;
2543d8817e4Smiod }
2553d8817e4Smiod 
2563d8817e4Smiod /* To be called by backends only.  */
2573d8817e4Smiod 
2583d8817e4Smiod bfd *
_bfd_create_empty_archive_element_shell(bfd * obfd)2593d8817e4Smiod _bfd_create_empty_archive_element_shell (bfd *obfd)
2603d8817e4Smiod {
2613d8817e4Smiod   return _bfd_new_bfd_contained_in (obfd);
2623d8817e4Smiod }
2633d8817e4Smiod 
2643d8817e4Smiod /*
2653d8817e4Smiod FUNCTION
2663d8817e4Smiod 	bfd_set_archive_head
2673d8817e4Smiod 
2683d8817e4Smiod SYNOPSIS
2693d8817e4Smiod 	bfd_boolean bfd_set_archive_head (bfd *output, bfd *new_head);
2703d8817e4Smiod 
2713d8817e4Smiod DESCRIPTION
2723d8817e4Smiod 	Set the head of the chain of
2733d8817e4Smiod 	BFDs contained in the archive @var{output} to @var{new_head}.
2743d8817e4Smiod */
2753d8817e4Smiod 
2763d8817e4Smiod bfd_boolean
bfd_set_archive_head(bfd * output_archive,bfd * new_head)2773d8817e4Smiod bfd_set_archive_head (bfd *output_archive, bfd *new_head)
2783d8817e4Smiod {
2793d8817e4Smiod   output_archive->archive_head = new_head;
2803d8817e4Smiod   return TRUE;
2813d8817e4Smiod }
2823d8817e4Smiod 
2833d8817e4Smiod bfd *
_bfd_look_for_bfd_in_cache(bfd * arch_bfd,file_ptr filepos)2843d8817e4Smiod _bfd_look_for_bfd_in_cache (bfd *arch_bfd, file_ptr filepos)
2853d8817e4Smiod {
2863d8817e4Smiod   htab_t hash_table = bfd_ardata (arch_bfd)->cache;
2873d8817e4Smiod   struct ar_cache m;
2883d8817e4Smiod   m.ptr = filepos;
2893d8817e4Smiod 
2903d8817e4Smiod   if (hash_table)
2913d8817e4Smiod     {
2923d8817e4Smiod       struct ar_cache *entry = (struct ar_cache *) htab_find (hash_table, &m);
2933d8817e4Smiod       if (!entry)
2943d8817e4Smiod 	return NULL;
2953d8817e4Smiod       else
2963d8817e4Smiod 	return entry->arbfd;
2973d8817e4Smiod     }
2983d8817e4Smiod   else
2993d8817e4Smiod     return NULL;
3003d8817e4Smiod }
3013d8817e4Smiod 
3023d8817e4Smiod static hashval_t
hash_file_ptr(const PTR p)3033d8817e4Smiod hash_file_ptr (const PTR p)
3043d8817e4Smiod {
3053d8817e4Smiod   return (hashval_t) (((struct ar_cache *) p)->ptr);
3063d8817e4Smiod }
3073d8817e4Smiod 
3083d8817e4Smiod /* Returns non-zero if P1 and P2 are equal.  */
3093d8817e4Smiod 
3103d8817e4Smiod static int
eq_file_ptr(const PTR p1,const PTR p2)3113d8817e4Smiod eq_file_ptr (const PTR p1, const PTR p2)
3123d8817e4Smiod {
3133d8817e4Smiod   struct ar_cache *arc1 = (struct ar_cache *) p1;
3143d8817e4Smiod   struct ar_cache *arc2 = (struct ar_cache *) p2;
3153d8817e4Smiod   return arc1->ptr == arc2->ptr;
3163d8817e4Smiod }
3173d8817e4Smiod 
3183d8817e4Smiod /* Kind of stupid to call cons for each one, but we don't do too many.  */
3193d8817e4Smiod 
3203d8817e4Smiod bfd_boolean
_bfd_add_bfd_to_archive_cache(bfd * arch_bfd,file_ptr filepos,bfd * new_elt)3213d8817e4Smiod _bfd_add_bfd_to_archive_cache (bfd *arch_bfd, file_ptr filepos, bfd *new_elt)
3223d8817e4Smiod {
3233d8817e4Smiod   struct ar_cache *cache;
3243d8817e4Smiod   htab_t hash_table = bfd_ardata (arch_bfd)->cache;
3253d8817e4Smiod 
3263d8817e4Smiod   /* If the hash table hasn't been created, create it.  */
3273d8817e4Smiod   if (hash_table == NULL)
3283d8817e4Smiod     {
3293d8817e4Smiod       hash_table = htab_create_alloc (16, hash_file_ptr, eq_file_ptr,
3303d8817e4Smiod 				      NULL, calloc, free);
3313d8817e4Smiod       if (hash_table == NULL)
3323d8817e4Smiod 	return FALSE;
3333d8817e4Smiod       bfd_ardata (arch_bfd)->cache = hash_table;
3343d8817e4Smiod     }
3353d8817e4Smiod 
3363d8817e4Smiod   /* Insert new_elt into the hash table by filepos.  */
3373d8817e4Smiod   cache = bfd_zalloc (arch_bfd, sizeof (struct ar_cache));
3383d8817e4Smiod   cache->ptr = filepos;
3393d8817e4Smiod   cache->arbfd = new_elt;
3403d8817e4Smiod   *htab_find_slot (hash_table, (const void *) cache, INSERT) = cache;
3413d8817e4Smiod 
3423d8817e4Smiod   return TRUE;
3433d8817e4Smiod }
3443d8817e4Smiod 
3453d8817e4Smiod /* The name begins with space.  Hence the rest of the name is an index into
3463d8817e4Smiod    the string table.  */
3473d8817e4Smiod 
3483d8817e4Smiod static char *
get_extended_arelt_filename(bfd * arch,const char * name)3493d8817e4Smiod get_extended_arelt_filename (bfd *arch, const char *name)
3503d8817e4Smiod {
3513d8817e4Smiod   unsigned long index = 0;
3523d8817e4Smiod 
3533d8817e4Smiod   /* Should extract string so that I can guarantee not to overflow into
3543d8817e4Smiod      the next region, but I'm too lazy.  */
3553d8817e4Smiod   errno = 0;
3563d8817e4Smiod   /* Skip first char, which is '/' in SVR4 or ' ' in some other variants.  */
3573d8817e4Smiod   index = strtol (name + 1, NULL, 10);
3583d8817e4Smiod   if (errno != 0 || index >= bfd_ardata (arch)->extended_names_size)
3593d8817e4Smiod     {
3603d8817e4Smiod       bfd_set_error (bfd_error_malformed_archive);
3613d8817e4Smiod       return NULL;
3623d8817e4Smiod     }
3633d8817e4Smiod 
3643d8817e4Smiod   return bfd_ardata (arch)->extended_names + index;
3653d8817e4Smiod }
3663d8817e4Smiod 
3673d8817e4Smiod /* This functions reads an arch header and returns an areltdata pointer, or
3683d8817e4Smiod    NULL on error.
3693d8817e4Smiod 
3703d8817e4Smiod    Presumes the file pointer is already in the right place (ie pointing
3713d8817e4Smiod    to the ar_hdr in the file).   Moves the file pointer; on success it
3723d8817e4Smiod    should be pointing to the front of the file contents; on failure it
3733d8817e4Smiod    could have been moved arbitrarily.  */
3743d8817e4Smiod 
3753d8817e4Smiod void *
_bfd_generic_read_ar_hdr(bfd * abfd)3763d8817e4Smiod _bfd_generic_read_ar_hdr (bfd *abfd)
3773d8817e4Smiod {
3783d8817e4Smiod   return _bfd_generic_read_ar_hdr_mag (abfd, NULL);
3793d8817e4Smiod }
3803d8817e4Smiod 
3813d8817e4Smiod /* Alpha ECOFF uses an optional different ARFMAG value, so we have a
3823d8817e4Smiod    variant of _bfd_generic_read_ar_hdr which accepts a magic string.  */
3833d8817e4Smiod 
3843d8817e4Smiod void *
_bfd_generic_read_ar_hdr_mag(bfd * abfd,const char * mag)3853d8817e4Smiod _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag)
3863d8817e4Smiod {
3873d8817e4Smiod   struct ar_hdr hdr;
3883d8817e4Smiod   char *hdrp = (char *) &hdr;
3893d8817e4Smiod   size_t parsed_size;
3903d8817e4Smiod   struct areltdata *ared;
3913d8817e4Smiod   char *filename = NULL;
3923d8817e4Smiod   bfd_size_type namelen = 0;
3933d8817e4Smiod   bfd_size_type allocsize = sizeof (struct areltdata) + sizeof (struct ar_hdr);
3943d8817e4Smiod   char *allocptr = 0;
3953d8817e4Smiod 
3963d8817e4Smiod   if (bfd_bread (hdrp, sizeof (struct ar_hdr), abfd) != sizeof (struct ar_hdr))
3973d8817e4Smiod     {
3983d8817e4Smiod       if (bfd_get_error () != bfd_error_system_call)
3993d8817e4Smiod 	bfd_set_error (bfd_error_no_more_archived_files);
4003d8817e4Smiod       return NULL;
4013d8817e4Smiod     }
4023d8817e4Smiod   if (strncmp (hdr.ar_fmag, ARFMAG, 2) != 0
4033d8817e4Smiod       && (mag == NULL
4043d8817e4Smiod 	  || strncmp (hdr.ar_fmag, mag, 2) != 0))
4053d8817e4Smiod     {
4063d8817e4Smiod       bfd_set_error (bfd_error_malformed_archive);
4073d8817e4Smiod       return NULL;
4083d8817e4Smiod     }
4093d8817e4Smiod 
4103d8817e4Smiod   errno = 0;
4113d8817e4Smiod   parsed_size = strtol (hdr.ar_size, NULL, 10);
4123d8817e4Smiod   if (errno != 0)
4133d8817e4Smiod     {
4143d8817e4Smiod       bfd_set_error (bfd_error_malformed_archive);
4153d8817e4Smiod       return NULL;
4163d8817e4Smiod     }
4173d8817e4Smiod 
4183d8817e4Smiod   /* Extract the filename from the archive - there are two ways to
4193d8817e4Smiod      specify an extended name table, either the first char of the
4203d8817e4Smiod      name is a space, or it's a slash.  */
4213d8817e4Smiod   if ((hdr.ar_name[0] == '/'
4223d8817e4Smiod        || (hdr.ar_name[0] == ' '
4233d8817e4Smiod 	   && memchr (hdr.ar_name, '/', ar_maxnamelen (abfd)) == NULL))
4243d8817e4Smiod       && bfd_ardata (abfd)->extended_names != NULL)
4253d8817e4Smiod     {
4263d8817e4Smiod       filename = get_extended_arelt_filename (abfd, hdr.ar_name);
4273d8817e4Smiod       if (filename == NULL)
4283d8817e4Smiod 	return NULL;
4293d8817e4Smiod     }
4303d8817e4Smiod   /* BSD4.4-style long filename.
4313d8817e4Smiod      Only implemented for reading, so far!  */
4323d8817e4Smiod   else if (hdr.ar_name[0] == '#'
4333d8817e4Smiod 	   && hdr.ar_name[1] == '1'
4343d8817e4Smiod 	   && hdr.ar_name[2] == '/'
4353d8817e4Smiod 	   && ISDIGIT (hdr.ar_name[3]))
4363d8817e4Smiod     {
4373d8817e4Smiod       /* BSD-4.4 extended name */
4383d8817e4Smiod       namelen = atoi (&hdr.ar_name[3]);
4393d8817e4Smiod       allocsize += namelen + 1;
4403d8817e4Smiod       parsed_size -= namelen;
4413d8817e4Smiod 
4423d8817e4Smiod       allocptr = bfd_zalloc (abfd, allocsize);
4433d8817e4Smiod       if (allocptr == NULL)
4443d8817e4Smiod 	return NULL;
4453d8817e4Smiod       filename = (allocptr
4463d8817e4Smiod 		  + sizeof (struct areltdata)
4473d8817e4Smiod 		  + sizeof (struct ar_hdr));
4483d8817e4Smiod       if (bfd_bread (filename, namelen, abfd) != namelen)
4493d8817e4Smiod 	{
4503d8817e4Smiod 	  if (bfd_get_error () != bfd_error_system_call)
4513d8817e4Smiod 	    bfd_set_error (bfd_error_no_more_archived_files);
4523d8817e4Smiod 	  return NULL;
4533d8817e4Smiod 	}
4543d8817e4Smiod       filename[namelen] = '\0';
4553d8817e4Smiod     }
4563d8817e4Smiod   else
4573d8817e4Smiod     {
4583d8817e4Smiod       /* We judge the end of the name by looking for '/' or ' '.
4593d8817e4Smiod 	 Note:  The SYSV format (terminated by '/') allows embedded
4603d8817e4Smiod 	 spaces, so only look for ' ' if we don't find '/'.  */
4613d8817e4Smiod 
4623d8817e4Smiod       char *e;
4633d8817e4Smiod       e = memchr (hdr.ar_name, '\0', ar_maxnamelen (abfd));
4643d8817e4Smiod       if (e == NULL)
4653d8817e4Smiod 	{
4663d8817e4Smiod 	  e = memchr (hdr.ar_name, '/', ar_maxnamelen (abfd));
4673d8817e4Smiod 	  if (e == NULL)
4683d8817e4Smiod 	    e = memchr (hdr.ar_name, ' ', ar_maxnamelen (abfd));
4693d8817e4Smiod 	}
4703d8817e4Smiod 
4713d8817e4Smiod       if (e != NULL)
4723d8817e4Smiod 	namelen = e - hdr.ar_name;
4733d8817e4Smiod       else
4743d8817e4Smiod 	{
4753d8817e4Smiod 	  /* If we didn't find a termination character, then the name
4763d8817e4Smiod 	     must be the entire field.  */
4773d8817e4Smiod 	  namelen = ar_maxnamelen (abfd);
4783d8817e4Smiod 	}
4793d8817e4Smiod 
4803d8817e4Smiod       allocsize += namelen + 1;
4813d8817e4Smiod     }
4823d8817e4Smiod 
4833d8817e4Smiod   if (!allocptr)
4843d8817e4Smiod     {
4853d8817e4Smiod       allocptr = bfd_zalloc (abfd, allocsize);
4863d8817e4Smiod       if (allocptr == NULL)
4873d8817e4Smiod 	return NULL;
4883d8817e4Smiod     }
4893d8817e4Smiod 
4903d8817e4Smiod   ared = (struct areltdata *) allocptr;
4913d8817e4Smiod 
4923d8817e4Smiod   ared->arch_header = allocptr + sizeof (struct areltdata);
4933d8817e4Smiod   memcpy (ared->arch_header, &hdr, sizeof (struct ar_hdr));
4943d8817e4Smiod   ared->parsed_size = parsed_size;
4953d8817e4Smiod 
4963d8817e4Smiod   if (filename != NULL)
4973d8817e4Smiod     ared->filename = filename;
4983d8817e4Smiod   else
4993d8817e4Smiod     {
5003d8817e4Smiod       ared->filename = allocptr + (sizeof (struct areltdata) +
5013d8817e4Smiod 				   sizeof (struct ar_hdr));
5023d8817e4Smiod       if (namelen)
5033d8817e4Smiod 	memcpy (ared->filename, hdr.ar_name, namelen);
5043d8817e4Smiod       ared->filename[namelen] = '\0';
5053d8817e4Smiod     }
5063d8817e4Smiod 
5073d8817e4Smiod   return ared;
5083d8817e4Smiod }
5093d8817e4Smiod 
5103d8817e4Smiod /* This is an internal function; it's mainly used when indexing
5113d8817e4Smiod    through the archive symbol table, but also used to get the next
5123d8817e4Smiod    element, since it handles the bookkeeping so nicely for us.  */
5133d8817e4Smiod 
5143d8817e4Smiod bfd *
_bfd_get_elt_at_filepos(bfd * archive,file_ptr filepos)5153d8817e4Smiod _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos)
5163d8817e4Smiod {
5173d8817e4Smiod   struct areltdata *new_areldata;
5183d8817e4Smiod   bfd *n_nfd;
5193d8817e4Smiod 
5203d8817e4Smiod   if (archive->my_archive)
5213d8817e4Smiod     {
5223d8817e4Smiod       filepos += archive->origin;
5233d8817e4Smiod       archive = archive->my_archive;
5243d8817e4Smiod     }
5253d8817e4Smiod 
5263d8817e4Smiod   n_nfd = _bfd_look_for_bfd_in_cache (archive, filepos);
5273d8817e4Smiod   if (n_nfd)
5283d8817e4Smiod     return n_nfd;
5293d8817e4Smiod 
5303d8817e4Smiod   if (0 > bfd_seek (archive, filepos, SEEK_SET))
5313d8817e4Smiod     return NULL;
5323d8817e4Smiod 
5333d8817e4Smiod   if ((new_areldata = _bfd_read_ar_hdr (archive)) == NULL)
5343d8817e4Smiod     return NULL;
5353d8817e4Smiod 
5363d8817e4Smiod   n_nfd = _bfd_create_empty_archive_element_shell (archive);
5373d8817e4Smiod   if (n_nfd == NULL)
5383d8817e4Smiod     {
5393d8817e4Smiod       bfd_release (archive, new_areldata);
5403d8817e4Smiod       return NULL;
5413d8817e4Smiod     }
5423d8817e4Smiod 
5433d8817e4Smiod   n_nfd->origin = bfd_tell (archive);
5443d8817e4Smiod   n_nfd->arelt_data = new_areldata;
5453d8817e4Smiod   n_nfd->filename = new_areldata->filename;
5463d8817e4Smiod 
5473d8817e4Smiod   if (_bfd_add_bfd_to_archive_cache (archive, filepos, n_nfd))
5483d8817e4Smiod     return n_nfd;
5493d8817e4Smiod 
5503d8817e4Smiod   /* Huh?  */
5513d8817e4Smiod   bfd_release (archive, n_nfd);
5523d8817e4Smiod   bfd_release (archive, new_areldata);
5533d8817e4Smiod   return NULL;
5543d8817e4Smiod }
5553d8817e4Smiod 
5563d8817e4Smiod /* Return the BFD which is referenced by the symbol in ABFD indexed by
5573d8817e4Smiod    INDEX.  INDEX should have been returned by bfd_get_next_mapent.  */
5583d8817e4Smiod 
5593d8817e4Smiod bfd *
_bfd_generic_get_elt_at_index(bfd * abfd,symindex index)5603d8817e4Smiod _bfd_generic_get_elt_at_index (bfd *abfd, symindex index)
5613d8817e4Smiod {
5623d8817e4Smiod   carsym *entry;
5633d8817e4Smiod 
5643d8817e4Smiod   entry = bfd_ardata (abfd)->symdefs + index;
5653d8817e4Smiod   return _bfd_get_elt_at_filepos (abfd, entry->file_offset);
5663d8817e4Smiod }
5673d8817e4Smiod 
5683d8817e4Smiod /*
5693d8817e4Smiod FUNCTION
5703d8817e4Smiod 	bfd_openr_next_archived_file
5713d8817e4Smiod 
5723d8817e4Smiod SYNOPSIS
5733d8817e4Smiod 	bfd *bfd_openr_next_archived_file (bfd *archive, bfd *previous);
5743d8817e4Smiod 
5753d8817e4Smiod DESCRIPTION
5763d8817e4Smiod 	Provided a BFD, @var{archive}, containing an archive and NULL, open
5773d8817e4Smiod 	an input BFD on the first contained element and returns that.
5783d8817e4Smiod 	Subsequent calls should pass
5793d8817e4Smiod 	the archive and the previous return value to return a created
5803d8817e4Smiod 	BFD to the next contained element. NULL is returned when there
5813d8817e4Smiod 	are no more.
5823d8817e4Smiod */
5833d8817e4Smiod 
5843d8817e4Smiod bfd *
bfd_openr_next_archived_file(bfd * archive,bfd * last_file)5853d8817e4Smiod bfd_openr_next_archived_file (bfd *archive, bfd *last_file)
5863d8817e4Smiod {
5873d8817e4Smiod   if ((bfd_get_format (archive) != bfd_archive) ||
5883d8817e4Smiod       (archive->direction == write_direction))
5893d8817e4Smiod     {
5903d8817e4Smiod       bfd_set_error (bfd_error_invalid_operation);
5913d8817e4Smiod       return NULL;
5923d8817e4Smiod     }
5933d8817e4Smiod 
5943d8817e4Smiod   return BFD_SEND (archive,
5953d8817e4Smiod 		   openr_next_archived_file, (archive, last_file));
5963d8817e4Smiod }
5973d8817e4Smiod 
5983d8817e4Smiod bfd *
bfd_generic_openr_next_archived_file(bfd * archive,bfd * last_file)5993d8817e4Smiod bfd_generic_openr_next_archived_file (bfd *archive, bfd *last_file)
6003d8817e4Smiod {
6013d8817e4Smiod   file_ptr filestart;
6023d8817e4Smiod 
6033d8817e4Smiod   if (!last_file)
6043d8817e4Smiod     filestart = bfd_ardata (archive)->first_file_filepos;
6053d8817e4Smiod   else
6063d8817e4Smiod     {
6073d8817e4Smiod       unsigned int size = arelt_size (last_file);
6083d8817e4Smiod       filestart = last_file->origin + size;
6093d8817e4Smiod       if (archive->my_archive)
6103d8817e4Smiod 	filestart -= archive->origin;
6113d8817e4Smiod       /* Pad to an even boundary...
6123d8817e4Smiod 	 Note that last_file->origin can be odd in the case of
6133d8817e4Smiod 	 BSD-4.4-style element with a long odd size.  */
6143d8817e4Smiod       filestart += filestart % 2;
6153d8817e4Smiod     }
6163d8817e4Smiod 
6173d8817e4Smiod   return _bfd_get_elt_at_filepos (archive, filestart);
6183d8817e4Smiod }
6193d8817e4Smiod 
6203d8817e4Smiod const bfd_target *
bfd_generic_archive_p(bfd * abfd)6213d8817e4Smiod bfd_generic_archive_p (bfd *abfd)
6223d8817e4Smiod {
6233d8817e4Smiod   struct artdata *tdata_hold;
6243d8817e4Smiod   char armag[SARMAG + 1];
6253d8817e4Smiod   bfd_size_type amt;
6263d8817e4Smiod 
6273d8817e4Smiod   if (bfd_bread (armag, SARMAG, abfd) != SARMAG)
6283d8817e4Smiod     {
6293d8817e4Smiod       if (bfd_get_error () != bfd_error_system_call)
6303d8817e4Smiod 	bfd_set_error (bfd_error_wrong_format);
6313d8817e4Smiod       return NULL;
6323d8817e4Smiod     }
6333d8817e4Smiod 
6343d8817e4Smiod   if (strncmp (armag, ARMAG, SARMAG) != 0 &&
6353d8817e4Smiod       strncmp (armag, ARMAGB, SARMAG) != 0)
6363d8817e4Smiod     return 0;
6373d8817e4Smiod 
6383d8817e4Smiod   tdata_hold = bfd_ardata (abfd);
6393d8817e4Smiod 
6403d8817e4Smiod   amt = sizeof (struct artdata);
6413d8817e4Smiod   bfd_ardata (abfd) = bfd_zalloc (abfd, amt);
6423d8817e4Smiod   if (bfd_ardata (abfd) == NULL)
6433d8817e4Smiod     {
6443d8817e4Smiod       bfd_ardata (abfd) = tdata_hold;
6453d8817e4Smiod       return NULL;
6463d8817e4Smiod     }
6473d8817e4Smiod 
6483d8817e4Smiod   bfd_ardata (abfd)->first_file_filepos = SARMAG;
6493d8817e4Smiod   /* Cleared by bfd_zalloc above.
6503d8817e4Smiod      bfd_ardata (abfd)->cache = NULL;
6513d8817e4Smiod      bfd_ardata (abfd)->archive_head = NULL;
6523d8817e4Smiod      bfd_ardata (abfd)->symdefs = NULL;
6533d8817e4Smiod      bfd_ardata (abfd)->extended_names = NULL;
6543d8817e4Smiod      bfd_ardata (abfd)->extended_names_size = 0;
6553d8817e4Smiod      bfd_ardata (abfd)->tdata = NULL;  */
6563d8817e4Smiod 
6573d8817e4Smiod   if (!BFD_SEND (abfd, _bfd_slurp_armap, (abfd))
6583d8817e4Smiod       || !BFD_SEND (abfd, _bfd_slurp_extended_name_table, (abfd)))
6593d8817e4Smiod     {
6603d8817e4Smiod       if (bfd_get_error () != bfd_error_system_call)
6613d8817e4Smiod 	bfd_set_error (bfd_error_wrong_format);
6623d8817e4Smiod       bfd_release (abfd, bfd_ardata (abfd));
6633d8817e4Smiod       bfd_ardata (abfd) = tdata_hold;
6643d8817e4Smiod       return NULL;
6653d8817e4Smiod     }
6663d8817e4Smiod 
6673d8817e4Smiod   if (bfd_has_map (abfd))
6683d8817e4Smiod     {
6693d8817e4Smiod       bfd *first;
6703d8817e4Smiod 
6713d8817e4Smiod       /* This archive has a map, so we may presume that the contents
6723d8817e4Smiod 	 are object files.  Make sure that if the first file in the
6733d8817e4Smiod 	 archive can be recognized as an object file, it is for this
6743d8817e4Smiod 	 target.  If not, assume that this is the wrong format.  If
6753d8817e4Smiod 	 the first file is not an object file, somebody is doing
6763d8817e4Smiod 	 something weird, and we permit it so that ar -t will work.
6773d8817e4Smiod 
6783d8817e4Smiod 	 This is done because any normal format will recognize any
6793d8817e4Smiod 	 normal archive, regardless of the format of the object files.
6803d8817e4Smiod 	 We do accept an empty archive.  */
6813d8817e4Smiod 
6823d8817e4Smiod       first = bfd_openr_next_archived_file (abfd, NULL);
6833d8817e4Smiod       if (first != NULL)
6843d8817e4Smiod 	{
6853d8817e4Smiod 	  bfd_boolean fail;
6863d8817e4Smiod 
6873d8817e4Smiod 	  first->target_defaulted = FALSE;
6883d8817e4Smiod 	  fail = FALSE;
6893d8817e4Smiod 	  if (bfd_check_format (first, bfd_object)
6903d8817e4Smiod 	      && first->xvec != abfd->xvec)
6913d8817e4Smiod 	    {
6923d8817e4Smiod 	      bfd_set_error (bfd_error_wrong_object_format);
6933d8817e4Smiod 	      bfd_ardata (abfd) = tdata_hold;
6943d8817e4Smiod 	      return NULL;
6953d8817e4Smiod 	    }
6963d8817e4Smiod 	  /* And we ought to close `first' here too.  */
6973d8817e4Smiod 	}
6983d8817e4Smiod     }
6993d8817e4Smiod 
7003d8817e4Smiod   return abfd->xvec;
7013d8817e4Smiod }
7023d8817e4Smiod 
7033d8817e4Smiod /* Some constants for a 32 bit BSD archive structure.  We do not
7043d8817e4Smiod    support 64 bit archives presently; so far as I know, none actually
7053d8817e4Smiod    exist.  Supporting them would require changing these constants, and
7063d8817e4Smiod    changing some H_GET_32 to H_GET_64.  */
7073d8817e4Smiod 
7083d8817e4Smiod /* The size of an external symdef structure.  */
7093d8817e4Smiod #define BSD_SYMDEF_SIZE 8
7103d8817e4Smiod 
7113d8817e4Smiod /* The offset from the start of a symdef structure to the file offset.  */
7123d8817e4Smiod #define BSD_SYMDEF_OFFSET_SIZE 4
7133d8817e4Smiod 
7143d8817e4Smiod /* The size of the symdef count.  */
7153d8817e4Smiod #define BSD_SYMDEF_COUNT_SIZE 4
7163d8817e4Smiod 
7173d8817e4Smiod /* The size of the string count.  */
7183d8817e4Smiod #define BSD_STRING_COUNT_SIZE 4
7193d8817e4Smiod 
7203d8817e4Smiod /* Returns FALSE on error, TRUE otherwise.  */
7213d8817e4Smiod 
7223d8817e4Smiod static bfd_boolean
do_slurp_bsd_armap(bfd * abfd)7233d8817e4Smiod do_slurp_bsd_armap (bfd *abfd)
7243d8817e4Smiod {
7253d8817e4Smiod   struct areltdata *mapdata;
7263d8817e4Smiod   unsigned int counter;
7273d8817e4Smiod   bfd_byte *raw_armap, *rbase;
7283d8817e4Smiod   struct artdata *ardata = bfd_ardata (abfd);
7293d8817e4Smiod   char *stringbase;
7303d8817e4Smiod   bfd_size_type parsed_size, amt;
7313d8817e4Smiod   carsym *set;
7323d8817e4Smiod 
7333d8817e4Smiod   mapdata = _bfd_read_ar_hdr (abfd);
7343d8817e4Smiod   if (mapdata == NULL)
7353d8817e4Smiod     return FALSE;
7363d8817e4Smiod   parsed_size = mapdata->parsed_size;
7373d8817e4Smiod   bfd_release (abfd, mapdata);	/* Don't need it any more.  */
7383d8817e4Smiod 
7393d8817e4Smiod   raw_armap = bfd_zalloc (abfd, parsed_size);
7403d8817e4Smiod   if (raw_armap == NULL)
7413d8817e4Smiod     return FALSE;
7423d8817e4Smiod 
7433d8817e4Smiod   if (bfd_bread (raw_armap, parsed_size, abfd) != parsed_size)
7443d8817e4Smiod     {
7453d8817e4Smiod       if (bfd_get_error () != bfd_error_system_call)
7463d8817e4Smiod 	bfd_set_error (bfd_error_malformed_archive);
7473d8817e4Smiod     byebye:
7483d8817e4Smiod       bfd_release (abfd, raw_armap);
7493d8817e4Smiod       return FALSE;
7503d8817e4Smiod     }
7513d8817e4Smiod 
7523d8817e4Smiod   ardata->symdef_count = H_GET_32 (abfd, raw_armap) / BSD_SYMDEF_SIZE;
7533d8817e4Smiod 
7543d8817e4Smiod   if (ardata->symdef_count * BSD_SYMDEF_SIZE >
7553d8817e4Smiod       parsed_size - BSD_SYMDEF_COUNT_SIZE)
7563d8817e4Smiod     {
7573d8817e4Smiod       /* Probably we're using the wrong byte ordering.  */
7583d8817e4Smiod       bfd_set_error (bfd_error_wrong_format);
7593d8817e4Smiod       goto byebye;
7603d8817e4Smiod     }
7613d8817e4Smiod 
7623d8817e4Smiod   ardata->cache = 0;
7633d8817e4Smiod   rbase = raw_armap + BSD_SYMDEF_COUNT_SIZE;
7643d8817e4Smiod   stringbase = ((char *) rbase
7653d8817e4Smiod 		+ ardata->symdef_count * BSD_SYMDEF_SIZE
7663d8817e4Smiod 		+ BSD_STRING_COUNT_SIZE);
7673d8817e4Smiod   amt = ardata->symdef_count * sizeof (carsym);
7683d8817e4Smiod   ardata->symdefs = bfd_alloc (abfd, amt);
7693d8817e4Smiod   if (!ardata->symdefs)
7703d8817e4Smiod     return FALSE;
7713d8817e4Smiod 
7723d8817e4Smiod   for (counter = 0, set = ardata->symdefs;
7733d8817e4Smiod        counter < ardata->symdef_count;
7743d8817e4Smiod        counter++, set++, rbase += BSD_SYMDEF_SIZE)
7753d8817e4Smiod     {
7763d8817e4Smiod       set->name = H_GET_32 (abfd, rbase) + stringbase;
7773d8817e4Smiod       set->file_offset = H_GET_32 (abfd, rbase + BSD_SYMDEF_OFFSET_SIZE);
7783d8817e4Smiod     }
7793d8817e4Smiod 
7803d8817e4Smiod   ardata->first_file_filepos = bfd_tell (abfd);
7813d8817e4Smiod   /* Pad to an even boundary if you have to.  */
7823d8817e4Smiod   ardata->first_file_filepos += (ardata->first_file_filepos) % 2;
7833d8817e4Smiod   /* FIXME, we should provide some way to free raw_ardata when
7843d8817e4Smiod      we are done using the strings from it.  For now, it seems
7853d8817e4Smiod      to be allocated on an objalloc anyway...  */
7863d8817e4Smiod   bfd_has_map (abfd) = TRUE;
7873d8817e4Smiod   return TRUE;
7883d8817e4Smiod }
7893d8817e4Smiod 
7903d8817e4Smiod /* Returns FALSE on error, TRUE otherwise.  */
7913d8817e4Smiod 
7923d8817e4Smiod static bfd_boolean
do_slurp_coff_armap(bfd * abfd)7933d8817e4Smiod do_slurp_coff_armap (bfd *abfd)
7943d8817e4Smiod {
7953d8817e4Smiod   struct areltdata *mapdata;
7963d8817e4Smiod   int *raw_armap, *rawptr;
7973d8817e4Smiod   struct artdata *ardata = bfd_ardata (abfd);
7983d8817e4Smiod   char *stringbase;
7993d8817e4Smiod   bfd_size_type stringsize;
8003d8817e4Smiod   unsigned int parsed_size;
8013d8817e4Smiod   carsym *carsyms;
8023d8817e4Smiod   bfd_size_type nsymz;		/* Number of symbols in armap.  */
8033d8817e4Smiod   bfd_vma (*swap) (const void *);
8043d8817e4Smiod   char int_buf[sizeof (long)];
8053d8817e4Smiod   bfd_size_type carsym_size, ptrsize;
8063d8817e4Smiod   unsigned int i;
8073d8817e4Smiod 
8083d8817e4Smiod   mapdata = _bfd_read_ar_hdr (abfd);
8093d8817e4Smiod   if (mapdata == NULL)
8103d8817e4Smiod     return FALSE;
8113d8817e4Smiod   parsed_size = mapdata->parsed_size;
8123d8817e4Smiod   bfd_release (abfd, mapdata);	/* Don't need it any more.  */
8133d8817e4Smiod 
8143d8817e4Smiod   if (bfd_bread (int_buf, 4, abfd) != 4)
8153d8817e4Smiod     {
8163d8817e4Smiod       if (bfd_get_error () != bfd_error_system_call)
8173d8817e4Smiod 	bfd_set_error (bfd_error_malformed_archive);
8183d8817e4Smiod       return FALSE;
8193d8817e4Smiod     }
8203d8817e4Smiod   /* It seems that all numeric information in a coff archive is always
8213d8817e4Smiod      in big endian format, nomatter the host or target.  */
8223d8817e4Smiod   swap = bfd_getb32;
8233d8817e4Smiod   nsymz = bfd_getb32 (int_buf);
8243d8817e4Smiod   stringsize = parsed_size - (4 * nsymz) - 4;
8253d8817e4Smiod 
8263d8817e4Smiod   /* ... except that some archive formats are broken, and it may be our
8273d8817e4Smiod      fault - the i960 little endian coff sometimes has big and sometimes
8283d8817e4Smiod      little, because our tools changed.  Here's a horrible hack to clean
8293d8817e4Smiod      up the crap.  */
8303d8817e4Smiod 
8313d8817e4Smiod   if (stringsize > 0xfffff
8323d8817e4Smiod       && bfd_get_arch (abfd) == bfd_arch_i960
8333d8817e4Smiod       && bfd_get_flavour (abfd) == bfd_target_coff_flavour)
8343d8817e4Smiod     {
8353d8817e4Smiod       /* This looks dangerous, let's do it the other way around.  */
8363d8817e4Smiod       nsymz = bfd_getl32 (int_buf);
8373d8817e4Smiod       stringsize = parsed_size - (4 * nsymz) - 4;
8383d8817e4Smiod       swap = bfd_getl32;
8393d8817e4Smiod     }
8403d8817e4Smiod 
8413d8817e4Smiod   /* The coff armap must be read sequentially.  So we construct a
8423d8817e4Smiod      bsd-style one in core all at once, for simplicity.  */
8433d8817e4Smiod 
8443d8817e4Smiod   if (nsymz > ~ (bfd_size_type) 0 / sizeof (carsym))
8453d8817e4Smiod     return FALSE;
8463d8817e4Smiod 
8473d8817e4Smiod   carsym_size = (nsymz * sizeof (carsym));
8483d8817e4Smiod   ptrsize = (4 * nsymz);
8493d8817e4Smiod 
8503d8817e4Smiod   if (carsym_size + stringsize + 1 <= carsym_size)
8513d8817e4Smiod     return FALSE;
8523d8817e4Smiod 
8533d8817e4Smiod   ardata->symdefs = bfd_zalloc (abfd, carsym_size + stringsize + 1);
8543d8817e4Smiod   if (ardata->symdefs == NULL)
8553d8817e4Smiod     return FALSE;
8563d8817e4Smiod   carsyms = ardata->symdefs;
8573d8817e4Smiod   stringbase = ((char *) ardata->symdefs) + carsym_size;
8583d8817e4Smiod 
8593d8817e4Smiod   /* Allocate and read in the raw offsets.  */
8603d8817e4Smiod   raw_armap = bfd_alloc (abfd, ptrsize);
8613d8817e4Smiod   if (raw_armap == NULL)
8623d8817e4Smiod     goto release_symdefs;
8633d8817e4Smiod   if (bfd_bread (raw_armap, ptrsize, abfd) != ptrsize
8643d8817e4Smiod       || (bfd_bread (stringbase, stringsize, abfd) != stringsize))
8653d8817e4Smiod     {
8663d8817e4Smiod       if (bfd_get_error () != bfd_error_system_call)
8673d8817e4Smiod 	bfd_set_error (bfd_error_malformed_archive);
8683d8817e4Smiod       goto release_raw_armap;
8693d8817e4Smiod     }
8703d8817e4Smiod 
8713d8817e4Smiod   /* OK, build the carsyms.  */
8723d8817e4Smiod   for (i = 0; i < nsymz; i++)
8733d8817e4Smiod     {
8743d8817e4Smiod       rawptr = raw_armap + i;
8753d8817e4Smiod       carsyms->file_offset = swap ((bfd_byte *) rawptr);
8763d8817e4Smiod       carsyms->name = stringbase;
8773d8817e4Smiod       stringbase += strlen (stringbase) + 1;
8783d8817e4Smiod       carsyms++;
8793d8817e4Smiod     }
8803d8817e4Smiod   *stringbase = 0;
8813d8817e4Smiod 
8823d8817e4Smiod   ardata->symdef_count = nsymz;
8833d8817e4Smiod   ardata->first_file_filepos = bfd_tell (abfd);
8843d8817e4Smiod   /* Pad to an even boundary if you have to.  */
8853d8817e4Smiod   ardata->first_file_filepos += (ardata->first_file_filepos) % 2;
8863d8817e4Smiod 
8873d8817e4Smiod   bfd_has_map (abfd) = TRUE;
8883d8817e4Smiod   bfd_release (abfd, raw_armap);
8893d8817e4Smiod 
8903d8817e4Smiod   /* Check for a second archive header (as used by PE).  */
8913d8817e4Smiod   {
8923d8817e4Smiod     struct areltdata *tmp;
8933d8817e4Smiod 
8943d8817e4Smiod     bfd_seek (abfd, ardata->first_file_filepos, SEEK_SET);
8953d8817e4Smiod     tmp = _bfd_read_ar_hdr (abfd);
8963d8817e4Smiod     if (tmp != NULL)
8973d8817e4Smiod       {
8983d8817e4Smiod 	if (tmp->arch_header[0] == '/'
8993d8817e4Smiod 	    && tmp->arch_header[1] == ' ')
9003d8817e4Smiod 	  {
9013d8817e4Smiod 	    ardata->first_file_filepos +=
9023d8817e4Smiod 	      (tmp->parsed_size + sizeof (struct ar_hdr) + 1) & ~(unsigned) 1;
9033d8817e4Smiod 	  }
9043d8817e4Smiod 	bfd_release (abfd, tmp);
9053d8817e4Smiod       }
9063d8817e4Smiod   }
9073d8817e4Smiod 
9083d8817e4Smiod   return TRUE;
9093d8817e4Smiod 
9103d8817e4Smiod release_raw_armap:
9113d8817e4Smiod   bfd_release (abfd, raw_armap);
9123d8817e4Smiod release_symdefs:
9133d8817e4Smiod   bfd_release (abfd, (ardata)->symdefs);
9143d8817e4Smiod   return FALSE;
9153d8817e4Smiod }
9163d8817e4Smiod 
9173d8817e4Smiod /* This routine can handle either coff-style or bsd-style armaps.
9183d8817e4Smiod    Returns FALSE on error, TRUE otherwise */
9193d8817e4Smiod 
9203d8817e4Smiod bfd_boolean
bfd_slurp_armap(bfd * abfd)9213d8817e4Smiod bfd_slurp_armap (bfd *abfd)
9223d8817e4Smiod {
9233d8817e4Smiod   char nextname[17];
9243d8817e4Smiod   int i = bfd_bread (nextname, 16, abfd);
9253d8817e4Smiod 
9263d8817e4Smiod   if (i == 0)
9273d8817e4Smiod     return TRUE;
9283d8817e4Smiod   if (i != 16)
9293d8817e4Smiod     return FALSE;
9303d8817e4Smiod 
9313d8817e4Smiod   if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0)
9323d8817e4Smiod     return FALSE;
9333d8817e4Smiod 
9343d8817e4Smiod   if (!strncmp (nextname, "__.SYMDEF       ", 16)
9353d8817e4Smiod       || !strncmp (nextname, "__.SYMDEF/      ", 16)) /* old Linux archives */
9363d8817e4Smiod     return do_slurp_bsd_armap (abfd);
9373d8817e4Smiod   else if (!strncmp (nextname, "/               ", 16))
9383d8817e4Smiod     return do_slurp_coff_armap (abfd);
9393d8817e4Smiod   else if (!strncmp (nextname, "/SYM64/         ", 16))
9403d8817e4Smiod     {
9413d8817e4Smiod       /* 64bit ELF (Irix 6) archive.  */
9423d8817e4Smiod #ifdef BFD64
9433d8817e4Smiod       extern bfd_boolean bfd_elf64_archive_slurp_armap (bfd *);
9443d8817e4Smiod       return bfd_elf64_archive_slurp_armap (abfd);
9453d8817e4Smiod #else
9463d8817e4Smiod       bfd_set_error (bfd_error_wrong_format);
9473d8817e4Smiod       return FALSE;
9483d8817e4Smiod #endif
9493d8817e4Smiod     }
9503d8817e4Smiod 
9513d8817e4Smiod   bfd_has_map (abfd) = FALSE;
9523d8817e4Smiod   return TRUE;
9533d8817e4Smiod }
9543d8817e4Smiod 
9553d8817e4Smiod /* Returns FALSE on error, TRUE otherwise.  */
9563d8817e4Smiod /* Flavor 2 of a bsd armap, similar to bfd_slurp_bsd_armap except the
9573d8817e4Smiod    header is in a slightly different order and the map name is '/'.
9583d8817e4Smiod    This flavour is used by hp300hpux.  */
9593d8817e4Smiod 
9603d8817e4Smiod #define HPUX_SYMDEF_COUNT_SIZE 2
9613d8817e4Smiod 
9623d8817e4Smiod bfd_boolean
bfd_slurp_bsd_armap_f2(bfd * abfd)9633d8817e4Smiod bfd_slurp_bsd_armap_f2 (bfd *abfd)
9643d8817e4Smiod {
9653d8817e4Smiod   struct areltdata *mapdata;
9663d8817e4Smiod   char nextname[17];
9673d8817e4Smiod   unsigned int counter;
9683d8817e4Smiod   bfd_byte *raw_armap, *rbase;
9693d8817e4Smiod   struct artdata *ardata = bfd_ardata (abfd);
9703d8817e4Smiod   char *stringbase;
9713d8817e4Smiod   unsigned int stringsize;
9723d8817e4Smiod   bfd_size_type amt;
9733d8817e4Smiod   carsym *set;
9743d8817e4Smiod   int i = bfd_bread (nextname, 16, abfd);
9753d8817e4Smiod 
9763d8817e4Smiod   if (i == 0)
9773d8817e4Smiod     return TRUE;
9783d8817e4Smiod   if (i != 16)
9793d8817e4Smiod     return FALSE;
9803d8817e4Smiod 
9813d8817e4Smiod   /* The archive has at least 16 bytes in it.  */
9823d8817e4Smiod   if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0)
9833d8817e4Smiod     return FALSE;
9843d8817e4Smiod 
9853d8817e4Smiod   if (!strncmp (nextname, "__.SYMDEF       ", 16)
9863d8817e4Smiod       || !strncmp (nextname, "__.SYMDEF/      ", 16)) /* Old Linux archives.  */
9873d8817e4Smiod     return do_slurp_bsd_armap (abfd);
9883d8817e4Smiod 
9893d8817e4Smiod   if (strncmp (nextname, "/               ", 16))
9903d8817e4Smiod     {
9913d8817e4Smiod       bfd_has_map (abfd) = FALSE;
9923d8817e4Smiod       return TRUE;
9933d8817e4Smiod     }
9943d8817e4Smiod 
9953d8817e4Smiod   mapdata = _bfd_read_ar_hdr (abfd);
9963d8817e4Smiod   if (mapdata == NULL)
9973d8817e4Smiod     return FALSE;
9983d8817e4Smiod 
9993d8817e4Smiod   amt = mapdata->parsed_size;
10003d8817e4Smiod   raw_armap = bfd_zalloc (abfd, amt);
10013d8817e4Smiod   if (raw_armap == NULL)
10023d8817e4Smiod     {
10033d8817e4Smiod     byebye:
10043d8817e4Smiod       bfd_release (abfd, mapdata);
10053d8817e4Smiod       return FALSE;
10063d8817e4Smiod     }
10073d8817e4Smiod 
10083d8817e4Smiod   if (bfd_bread (raw_armap, amt, abfd) != amt)
10093d8817e4Smiod     {
10103d8817e4Smiod       if (bfd_get_error () != bfd_error_system_call)
10113d8817e4Smiod 	bfd_set_error (bfd_error_malformed_archive);
10123d8817e4Smiod     byebyebye:
10133d8817e4Smiod       bfd_release (abfd, raw_armap);
10143d8817e4Smiod       goto byebye;
10153d8817e4Smiod     }
10163d8817e4Smiod 
10173d8817e4Smiod   ardata->symdef_count = H_GET_16 (abfd, raw_armap);
10183d8817e4Smiod 
10193d8817e4Smiod   if (ardata->symdef_count * BSD_SYMDEF_SIZE
10203d8817e4Smiod       > mapdata->parsed_size - HPUX_SYMDEF_COUNT_SIZE)
10213d8817e4Smiod     {
10223d8817e4Smiod       /* Probably we're using the wrong byte ordering.  */
10233d8817e4Smiod       bfd_set_error (bfd_error_wrong_format);
10243d8817e4Smiod       goto byebyebye;
10253d8817e4Smiod     }
10263d8817e4Smiod 
10273d8817e4Smiod   ardata->cache = 0;
10283d8817e4Smiod 
10293d8817e4Smiod   stringsize = H_GET_32 (abfd, raw_armap + HPUX_SYMDEF_COUNT_SIZE);
10303d8817e4Smiod   /* Skip sym count and string sz.  */
10313d8817e4Smiod   stringbase = ((char *) raw_armap
10323d8817e4Smiod 		+ HPUX_SYMDEF_COUNT_SIZE
10333d8817e4Smiod 		+ BSD_STRING_COUNT_SIZE);
10343d8817e4Smiod   rbase = (bfd_byte *) stringbase + stringsize;
10353d8817e4Smiod   amt = ardata->symdef_count * BSD_SYMDEF_SIZE;
10363d8817e4Smiod   ardata->symdefs = bfd_alloc (abfd, amt);
10373d8817e4Smiod   if (!ardata->symdefs)
10383d8817e4Smiod     return FALSE;
10393d8817e4Smiod 
10403d8817e4Smiod   for (counter = 0, set = ardata->symdefs;
10413d8817e4Smiod        counter < ardata->symdef_count;
10423d8817e4Smiod        counter++, set++, rbase += BSD_SYMDEF_SIZE)
10433d8817e4Smiod     {
10443d8817e4Smiod       set->name = H_GET_32 (abfd, rbase) + stringbase;
10453d8817e4Smiod       set->file_offset = H_GET_32 (abfd, rbase + BSD_SYMDEF_OFFSET_SIZE);
10463d8817e4Smiod     }
10473d8817e4Smiod 
10483d8817e4Smiod   ardata->first_file_filepos = bfd_tell (abfd);
10493d8817e4Smiod   /* Pad to an even boundary if you have to.  */
10503d8817e4Smiod   ardata->first_file_filepos += (ardata->first_file_filepos) % 2;
10513d8817e4Smiod   /* FIXME, we should provide some way to free raw_ardata when
10523d8817e4Smiod      we are done using the strings from it.  For now, it seems
10533d8817e4Smiod      to be allocated on an objalloc anyway...  */
10543d8817e4Smiod   bfd_has_map (abfd) = TRUE;
10553d8817e4Smiod   return TRUE;
10563d8817e4Smiod }
10573d8817e4Smiod 
10583d8817e4Smiod /** Extended name table.
10593d8817e4Smiod 
10603d8817e4Smiod   Normally archives support only 14-character filenames.
10613d8817e4Smiod 
10623d8817e4Smiod   Intel has extended the format: longer names are stored in a special
10633d8817e4Smiod   element (the first in the archive, or second if there is an armap);
10643d8817e4Smiod   the name in the ar_hdr is replaced by <space><index into filename
10653d8817e4Smiod   element>.  Index is the P.R. of an int (decimal).  Data General have
10663d8817e4Smiod   extended the format by using the prefix // for the special element.  */
10673d8817e4Smiod 
10683d8817e4Smiod /* Returns FALSE on error, TRUE otherwise.  */
10693d8817e4Smiod 
10703d8817e4Smiod bfd_boolean
_bfd_slurp_extended_name_table(bfd * abfd)10713d8817e4Smiod _bfd_slurp_extended_name_table (bfd *abfd)
10723d8817e4Smiod {
10733d8817e4Smiod   char nextname[17];
10743d8817e4Smiod   struct areltdata *namedata;
10753d8817e4Smiod   bfd_size_type amt;
10763d8817e4Smiod 
10773d8817e4Smiod   /* FIXME:  Formatting sucks here, and in case of failure of BFD_READ,
10783d8817e4Smiod      we probably don't want to return TRUE.  */
10793d8817e4Smiod   bfd_seek (abfd, bfd_ardata (abfd)->first_file_filepos, SEEK_SET);
10803d8817e4Smiod   if (bfd_bread (nextname, 16, abfd) == 16)
10813d8817e4Smiod     {
10823d8817e4Smiod       if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0)
10833d8817e4Smiod 	return FALSE;
10843d8817e4Smiod 
10853d8817e4Smiod       if (strncmp (nextname, "ARFILENAMES/    ", 16) != 0 &&
10863d8817e4Smiod 	  strncmp (nextname, "//              ", 16) != 0)
10873d8817e4Smiod 	{
10883d8817e4Smiod 	  bfd_ardata (abfd)->extended_names = NULL;
10893d8817e4Smiod 	  bfd_ardata (abfd)->extended_names_size = 0;
10903d8817e4Smiod 	  return TRUE;
10913d8817e4Smiod 	}
10923d8817e4Smiod 
10933d8817e4Smiod       namedata = _bfd_read_ar_hdr (abfd);
10943d8817e4Smiod       if (namedata == NULL)
10953d8817e4Smiod 	return FALSE;
10963d8817e4Smiod 
10973d8817e4Smiod       amt = namedata->parsed_size;
10983d8817e4Smiod       if (amt + 1 == 0)
10993d8817e4Smiod         goto byebye;
11003d8817e4Smiod 
11013d8817e4Smiod       bfd_ardata (abfd)->extended_names_size = amt;
11023d8817e4Smiod       bfd_ardata (abfd)->extended_names = bfd_zalloc (abfd, amt + 1);
11033d8817e4Smiod       if (bfd_ardata (abfd)->extended_names == NULL)
11043d8817e4Smiod 	{
11053d8817e4Smiod 	byebye:
11063d8817e4Smiod 	  bfd_release (abfd, namedata);
11073d8817e4Smiod 	  return FALSE;
11083d8817e4Smiod 	}
11093d8817e4Smiod 
11103d8817e4Smiod       if (bfd_bread (bfd_ardata (abfd)->extended_names, amt, abfd) != amt)
11113d8817e4Smiod 	{
11123d8817e4Smiod 	  if (bfd_get_error () != bfd_error_system_call)
11133d8817e4Smiod 	    bfd_set_error (bfd_error_malformed_archive);
11143d8817e4Smiod 	  bfd_release (abfd, (bfd_ardata (abfd)->extended_names));
11153d8817e4Smiod 	  bfd_ardata (abfd)->extended_names = NULL;
11163d8817e4Smiod 	  goto byebye;
11173d8817e4Smiod 	}
11183d8817e4Smiod 
11193d8817e4Smiod       /* Since the archive is supposed to be printable if it contains
11203d8817e4Smiod 	 text, the entries in the list are newline-padded, not null
11213d8817e4Smiod 	 padded. In SVR4-style archives, the names also have a
11223d8817e4Smiod 	 trailing '/'.  DOS/NT created archive often have \ in them
11233d8817e4Smiod 	 We'll fix all problems here..  */
11243d8817e4Smiod       {
11253d8817e4Smiod         char *ext_names = bfd_ardata (abfd)->extended_names;
11263d8817e4Smiod 	char *temp = ext_names;
11273d8817e4Smiod 	char *limit = temp + namedata->parsed_size;
11283d8817e4Smiod 	for (; temp < limit; ++temp)
11293d8817e4Smiod 	  {
11303d8817e4Smiod 	    if (*temp == '\012')
11313d8817e4Smiod 	      temp[temp > ext_names && temp[-1] == '/' ? -1 : 0] = '\0';
11323d8817e4Smiod 	    if (*temp == '\\')
11333d8817e4Smiod 	      *temp = '/';
11343d8817e4Smiod 	  }
11353d8817e4Smiod 	*limit = '\0';
11363d8817e4Smiod       }
11373d8817e4Smiod 
11383d8817e4Smiod       /* Pad to an even boundary if you have to.  */
11393d8817e4Smiod       bfd_ardata (abfd)->first_file_filepos = bfd_tell (abfd);
11403d8817e4Smiod       bfd_ardata (abfd)->first_file_filepos +=
11413d8817e4Smiod 	(bfd_ardata (abfd)->first_file_filepos) % 2;
11423d8817e4Smiod 
11433d8817e4Smiod       /* FIXME, we can't release namedata here because it was allocated
11443d8817e4Smiod 	 below extended_names on the objalloc...  */
11453d8817e4Smiod     }
11463d8817e4Smiod   return TRUE;
11473d8817e4Smiod }
11483d8817e4Smiod 
11493d8817e4Smiod #ifdef VMS
11503d8817e4Smiod 
11513d8817e4Smiod /* Return a copy of the stuff in the filename between any :]> and a
11523d8817e4Smiod    semicolon.  */
11533d8817e4Smiod 
11543d8817e4Smiod static const char *
normalize(bfd * abfd,const char * file)11553d8817e4Smiod normalize (bfd *abfd, const char *file)
11563d8817e4Smiod {
11573d8817e4Smiod   const char *first;
11583d8817e4Smiod   const char *last;
11593d8817e4Smiod   char *copy;
11603d8817e4Smiod 
11613d8817e4Smiod   first = file + strlen (file) - 1;
11623d8817e4Smiod   last = first + 1;
11633d8817e4Smiod 
11643d8817e4Smiod   while (first != file)
11653d8817e4Smiod     {
11663d8817e4Smiod       if (*first == ';')
11673d8817e4Smiod 	last = first;
11683d8817e4Smiod       if (*first == ':' || *first == ']' || *first == '>')
11693d8817e4Smiod 	{
11703d8817e4Smiod 	  first++;
11713d8817e4Smiod 	  break;
11723d8817e4Smiod 	}
11733d8817e4Smiod       first--;
11743d8817e4Smiod     }
11753d8817e4Smiod 
11763d8817e4Smiod   copy = bfd_alloc (abfd, last - first + 1);
11773d8817e4Smiod   if (copy == NULL)
11783d8817e4Smiod     return NULL;
11793d8817e4Smiod 
11803d8817e4Smiod   memcpy (copy, first, last - first);
11813d8817e4Smiod   copy[last - first] = 0;
11823d8817e4Smiod 
11833d8817e4Smiod   return copy;
11843d8817e4Smiod }
11853d8817e4Smiod 
11863d8817e4Smiod #else
11873d8817e4Smiod static const char *
normalize(bfd * abfd ATTRIBUTE_UNUSED,const char * file)11883d8817e4Smiod normalize (bfd *abfd ATTRIBUTE_UNUSED, const char *file)
11893d8817e4Smiod {
11903d8817e4Smiod   const char *filename = strrchr (file, '/');
11913d8817e4Smiod 
11923d8817e4Smiod #ifdef HAVE_DOS_BASED_FILE_SYSTEM
11933d8817e4Smiod   {
11943d8817e4Smiod     /* We could have foo/bar\\baz, or foo\\bar, or d:bar.  */
11953d8817e4Smiod     char *bslash = strrchr (file, '\\');
11963d8817e4Smiod     if (filename == NULL || (bslash != NULL && bslash > filename))
11973d8817e4Smiod       filename = bslash;
11983d8817e4Smiod     if (filename == NULL && file[0] != '\0' && file[1] == ':')
11993d8817e4Smiod       filename = file + 1;
12003d8817e4Smiod   }
12013d8817e4Smiod #endif
12023d8817e4Smiod   if (filename != NULL)
12033d8817e4Smiod     filename++;
12043d8817e4Smiod   else
12053d8817e4Smiod     filename = file;
12063d8817e4Smiod   return filename;
12073d8817e4Smiod }
12083d8817e4Smiod #endif
12093d8817e4Smiod 
12103d8817e4Smiod /* Build a BFD style extended name table.  */
12113d8817e4Smiod 
12123d8817e4Smiod bfd_boolean
_bfd_archive_bsd_construct_extended_name_table(bfd * abfd,char ** tabloc,bfd_size_type * tablen,const char ** name)12133d8817e4Smiod _bfd_archive_bsd_construct_extended_name_table (bfd *abfd,
12143d8817e4Smiod 						char **tabloc,
12153d8817e4Smiod 						bfd_size_type *tablen,
12163d8817e4Smiod 						const char **name)
12173d8817e4Smiod {
12183d8817e4Smiod   *name = "ARFILENAMES/";
12193d8817e4Smiod   return _bfd_construct_extended_name_table (abfd, FALSE, tabloc, tablen);
12203d8817e4Smiod }
12213d8817e4Smiod 
12223d8817e4Smiod /* Build an SVR4 style extended name table.  */
12233d8817e4Smiod 
12243d8817e4Smiod bfd_boolean
_bfd_archive_coff_construct_extended_name_table(bfd * abfd,char ** tabloc,bfd_size_type * tablen,const char ** name)12253d8817e4Smiod _bfd_archive_coff_construct_extended_name_table (bfd *abfd,
12263d8817e4Smiod 						 char **tabloc,
12273d8817e4Smiod 						 bfd_size_type *tablen,
12283d8817e4Smiod 						 const char **name)
12293d8817e4Smiod {
12303d8817e4Smiod   *name = "//";
12313d8817e4Smiod   return _bfd_construct_extended_name_table (abfd, TRUE, tabloc, tablen);
12323d8817e4Smiod }
12333d8817e4Smiod 
12343d8817e4Smiod /* Follows archive_head and produces an extended name table if
12353d8817e4Smiod    necessary.  Returns (in tabloc) a pointer to an extended name
12363d8817e4Smiod    table, and in tablen the length of the table.  If it makes an entry
12373d8817e4Smiod    it clobbers the filename so that the element may be written without
12383d8817e4Smiod    further massage.  Returns TRUE if it ran successfully, FALSE if
12393d8817e4Smiod    something went wrong.  A successful return may still involve a
12403d8817e4Smiod    zero-length tablen!  */
12413d8817e4Smiod 
12423d8817e4Smiod bfd_boolean
_bfd_construct_extended_name_table(bfd * abfd,bfd_boolean trailing_slash,char ** tabloc,bfd_size_type * tablen)12433d8817e4Smiod _bfd_construct_extended_name_table (bfd *abfd,
12443d8817e4Smiod 				    bfd_boolean trailing_slash,
12453d8817e4Smiod 				    char **tabloc,
12463d8817e4Smiod 				    bfd_size_type *tablen)
12473d8817e4Smiod {
12483d8817e4Smiod   unsigned int maxname = abfd->xvec->ar_max_namelen;
12493d8817e4Smiod   bfd_size_type total_namelen = 0;
12503d8817e4Smiod   bfd *current;
12513d8817e4Smiod   char *strptr;
12523d8817e4Smiod 
12533d8817e4Smiod   *tablen = 0;
12543d8817e4Smiod 
12553d8817e4Smiod   /* Figure out how long the table should be.  */
12563d8817e4Smiod   for (current = abfd->archive_head; current != NULL; current = current->next)
12573d8817e4Smiod     {
12583d8817e4Smiod       const char *normal;
12593d8817e4Smiod       unsigned int thislen;
12603d8817e4Smiod 
12613d8817e4Smiod       normal = normalize (current, current->filename);
12623d8817e4Smiod       if (normal == NULL)
12633d8817e4Smiod 	return FALSE;
12643d8817e4Smiod 
12653d8817e4Smiod       thislen = strlen (normal);
12663d8817e4Smiod 
12673d8817e4Smiod       if (thislen > maxname
12683d8817e4Smiod 	  && (bfd_get_file_flags (abfd) & BFD_TRADITIONAL_FORMAT) != 0)
12693d8817e4Smiod 	thislen = maxname;
12703d8817e4Smiod 
12713d8817e4Smiod       if (thislen > maxname)
12723d8817e4Smiod 	{
12733d8817e4Smiod 	  /* Add one to leave room for \n.  */
12743d8817e4Smiod 	  total_namelen += thislen + 1;
12753d8817e4Smiod 	  if (trailing_slash)
12763d8817e4Smiod 	    {
12773d8817e4Smiod 	      /* Leave room for trailing slash.  */
12783d8817e4Smiod 	      ++total_namelen;
12793d8817e4Smiod 	    }
12803d8817e4Smiod 	}
12813d8817e4Smiod       else
12823d8817e4Smiod 	{
12833d8817e4Smiod 	  struct ar_hdr *hdr = arch_hdr (current);
12843d8817e4Smiod 	  if (strncmp (normal, hdr->ar_name, thislen) != 0
12853d8817e4Smiod 	      || (thislen < sizeof hdr->ar_name
12863d8817e4Smiod 		  && hdr->ar_name[thislen] != ar_padchar (current)))
12873d8817e4Smiod 	    {
12883d8817e4Smiod 	      /* Must have been using extended format even though it
12893d8817e4Smiod 	         didn't need to.  Fix it to use normal format.  */
12903d8817e4Smiod 	      memcpy (hdr->ar_name, normal, thislen);
12913d8817e4Smiod 	      if (thislen < maxname
12923d8817e4Smiod 		  || (thislen == maxname && thislen < sizeof hdr->ar_name))
12933d8817e4Smiod 		hdr->ar_name[thislen] = ar_padchar (current);
12943d8817e4Smiod 	    }
12953d8817e4Smiod 	}
12963d8817e4Smiod     }
12973d8817e4Smiod 
12983d8817e4Smiod   if (total_namelen == 0)
12993d8817e4Smiod     return TRUE;
13003d8817e4Smiod 
13013d8817e4Smiod   *tabloc = bfd_zalloc (abfd, total_namelen);
13023d8817e4Smiod   if (*tabloc == NULL)
13033d8817e4Smiod     return FALSE;
13043d8817e4Smiod 
13053d8817e4Smiod   *tablen = total_namelen;
13063d8817e4Smiod   strptr = *tabloc;
13073d8817e4Smiod 
13083d8817e4Smiod   for (current = abfd->archive_head; current != NULL; current =
13093d8817e4Smiod        current->next)
13103d8817e4Smiod     {
13113d8817e4Smiod       const char *normal;
13123d8817e4Smiod       unsigned int thislen;
13133d8817e4Smiod 
13143d8817e4Smiod       normal = normalize (current, current->filename);
13153d8817e4Smiod       if (normal == NULL)
13163d8817e4Smiod 	return FALSE;
13173d8817e4Smiod 
13183d8817e4Smiod       thislen = strlen (normal);
13193d8817e4Smiod       if (thislen > maxname)
13203d8817e4Smiod 	{
13213d8817e4Smiod 	  /* Works for now; may need to be re-engineered if we
13223d8817e4Smiod 	     encounter an oddball archive format and want to
13233d8817e4Smiod 	     generalise this hack.  */
13243d8817e4Smiod 	  struct ar_hdr *hdr = arch_hdr (current);
13253d8817e4Smiod 	  strcpy (strptr, normal);
13263d8817e4Smiod 	  if (! trailing_slash)
13273d8817e4Smiod 	    strptr[thislen] = '\012';
13283d8817e4Smiod 	  else
13293d8817e4Smiod 	    {
13303d8817e4Smiod 	      strptr[thislen] = '/';
13313d8817e4Smiod 	      strptr[thislen + 1] = '\012';
13323d8817e4Smiod 	    }
13333d8817e4Smiod 	  hdr->ar_name[0] = ar_padchar (current);
13343d8817e4Smiod           _bfd_ar_spacepad (hdr->ar_name + 1, maxname - 1, "%-ld",
13353d8817e4Smiod                             strptr - *tabloc);
13363d8817e4Smiod 	  strptr += thislen + 1;
13373d8817e4Smiod 	  if (trailing_slash)
13383d8817e4Smiod 	    ++strptr;
13393d8817e4Smiod 	}
13403d8817e4Smiod     }
13413d8817e4Smiod 
13423d8817e4Smiod   return TRUE;
13433d8817e4Smiod }
13443d8817e4Smiod 
13453d8817e4Smiod /* A couple of functions for creating ar_hdrs.  */
13463d8817e4Smiod 
13473d8817e4Smiod #ifdef HPUX_LARGE_AR_IDS
13483d8817e4Smiod /* Function to encode large UID/GID values according to HP.  */
13493d8817e4Smiod 
13503d8817e4Smiod static void
hpux_uid_gid_encode(char str[6],long int id)13513d8817e4Smiod hpux_uid_gid_encode (char str[6], long int id)
13523d8817e4Smiod {
13533d8817e4Smiod   int cnt;
13543d8817e4Smiod 
13553d8817e4Smiod   str[5] = '@' + (id & 3);
13563d8817e4Smiod   id >>= 2;
13573d8817e4Smiod 
13583d8817e4Smiod   for (cnt = 4; cnt >= 0; ++cnt, id >>= 6)
13593d8817e4Smiod     str[cnt] = ' ' + (id & 0x3f);
13603d8817e4Smiod }
13613d8817e4Smiod #endif	/* HPUX_LARGE_AR_IDS */
13623d8817e4Smiod 
13633d8817e4Smiod #ifndef HAVE_GETUID
13643d8817e4Smiod #define getuid() 0
13653d8817e4Smiod #endif
13663d8817e4Smiod 
13673d8817e4Smiod #ifndef HAVE_GETGID
13683d8817e4Smiod #define getgid() 0
13693d8817e4Smiod #endif
13703d8817e4Smiod 
13713d8817e4Smiod /* Takes a filename, returns an arelt_data for it, or NULL if it can't
13723d8817e4Smiod    make one.  The filename must refer to a filename in the filesystem.
13733d8817e4Smiod    The filename field of the ar_hdr will NOT be initialized.  If member
13743d8817e4Smiod    is set, and it's an in-memory bfd, we fake it.  */
13753d8817e4Smiod 
13763d8817e4Smiod static struct areltdata *
bfd_ar_hdr_from_filesystem(bfd * abfd,const char * filename,bfd * member)13773d8817e4Smiod bfd_ar_hdr_from_filesystem (bfd *abfd, const char *filename, bfd *member)
13783d8817e4Smiod {
13793d8817e4Smiod   struct stat status;
13803d8817e4Smiod   struct areltdata *ared;
13813d8817e4Smiod   struct ar_hdr *hdr;
13823d8817e4Smiod   bfd_size_type amt;
13833d8817e4Smiod 
13843d8817e4Smiod   if (member && (member->flags & BFD_IN_MEMORY) != 0)
13853d8817e4Smiod     {
13863d8817e4Smiod       /* Assume we just "made" the member, and fake it.  */
13873d8817e4Smiod       struct bfd_in_memory *bim = member->iostream;
13883d8817e4Smiod       time (&status.st_mtime);
13893d8817e4Smiod       status.st_uid = getuid ();
13903d8817e4Smiod       status.st_gid = getgid ();
13913d8817e4Smiod       status.st_mode = 0644;
13923d8817e4Smiod       status.st_size = bim->size;
13933d8817e4Smiod     }
13943d8817e4Smiod   else if (stat (filename, &status) != 0)
13953d8817e4Smiod     {
13963d8817e4Smiod       bfd_set_error (bfd_error_system_call);
13973d8817e4Smiod       return NULL;
13983d8817e4Smiod     }
13993d8817e4Smiod 
1400*314e8fdfSguenther   if ((abfd->flags & BFD_DETERMINISTIC) != 0)
1401*314e8fdfSguenther     {
1402*314e8fdfSguenther       status.st_mtime = 0;
1403*314e8fdfSguenther       status.st_uid = 0;
1404*314e8fdfSguenther       status.st_gid = 0;
1405*314e8fdfSguenther       status.st_mode = 0644;
1406*314e8fdfSguenther     }
1407*314e8fdfSguenther 
14083d8817e4Smiod   amt = sizeof (struct ar_hdr) + sizeof (struct areltdata);
14093d8817e4Smiod   ared = bfd_zalloc (abfd, amt);
14103d8817e4Smiod   if (ared == NULL)
14113d8817e4Smiod     return NULL;
14123d8817e4Smiod   hdr = (struct ar_hdr *) (((char *) ared) + sizeof (struct areltdata));
14133d8817e4Smiod 
14143d8817e4Smiod   /* ar headers are space padded, not null padded!  */
14153d8817e4Smiod   memset (hdr, ' ', sizeof (struct ar_hdr));
14163d8817e4Smiod 
141704a47612Sguenther   _bfd_ar_spacepadll (hdr->ar_date, sizeof (hdr->ar_date), "%-12lld",
141804a47612Sguenther                     status.st_mtime);
14193d8817e4Smiod #ifdef HPUX_LARGE_AR_IDS
14203d8817e4Smiod   /* HP has a very "special" way to handle UID/GID's with numeric values
14213d8817e4Smiod      > 99999.  */
14223d8817e4Smiod   if (status.st_uid > 99999)
14233d8817e4Smiod     hpux_uid_gid_encode (hdr->ar_uid, (long) status.st_uid);
14243d8817e4Smiod   else
14253d8817e4Smiod #endif
14263d8817e4Smiod     _bfd_ar_spacepad (hdr->ar_uid, sizeof (hdr->ar_uid), "%ld",
14273d8817e4Smiod                       status.st_uid);
14283d8817e4Smiod #ifdef HPUX_LARGE_AR_IDS
14293d8817e4Smiod   /* HP has a very "special" way to handle UID/GID's with numeric values
14303d8817e4Smiod      > 99999.  */
14313d8817e4Smiod   if (status.st_gid > 99999)
14323d8817e4Smiod     hpux_uid_gid_encode (hdr->ar_gid, (long) status.st_gid);
14333d8817e4Smiod   else
14343d8817e4Smiod #endif
14353d8817e4Smiod     _bfd_ar_spacepad (hdr->ar_gid, sizeof (hdr->ar_gid), "%ld",
14363d8817e4Smiod                       status.st_gid);
14373d8817e4Smiod   _bfd_ar_spacepad (hdr->ar_mode, sizeof (hdr->ar_mode), "%-8lo",
14383d8817e4Smiod                     status.st_mode);
143904a47612Sguenther   _bfd_ar_spacepadll (hdr->ar_size, sizeof (hdr->ar_size), "%-10lld",
14403d8817e4Smiod                     status.st_size);
14413d8817e4Smiod   memcpy (hdr->ar_fmag, ARFMAG, 2);
14423d8817e4Smiod   ared->parsed_size = status.st_size;
14433d8817e4Smiod   ared->arch_header = (char *) hdr;
14443d8817e4Smiod 
14453d8817e4Smiod   return ared;
14463d8817e4Smiod }
14473d8817e4Smiod 
14483d8817e4Smiod /* This is magic required by the "ar" program.  Since it's
14493d8817e4Smiod    undocumented, it's undocumented.  You may think that it would take
14503d8817e4Smiod    a strong stomach to write this, and it does, but it takes even a
14513d8817e4Smiod    stronger stomach to try to code around such a thing!  */
14523d8817e4Smiod 
14533d8817e4Smiod struct ar_hdr *bfd_special_undocumented_glue (bfd *, const char *);
14543d8817e4Smiod 
14553d8817e4Smiod struct ar_hdr *
bfd_special_undocumented_glue(bfd * abfd,const char * filename)14563d8817e4Smiod bfd_special_undocumented_glue (bfd *abfd, const char *filename)
14573d8817e4Smiod {
14583d8817e4Smiod   struct areltdata *ar_elt = bfd_ar_hdr_from_filesystem (abfd, filename, 0);
14593d8817e4Smiod   if (ar_elt == NULL)
14603d8817e4Smiod     return NULL;
14613d8817e4Smiod   return (struct ar_hdr *) ar_elt->arch_header;
14623d8817e4Smiod }
14633d8817e4Smiod 
14643d8817e4Smiod /* Analogous to stat call.  */
14653d8817e4Smiod 
14663d8817e4Smiod int
bfd_generic_stat_arch_elt(bfd * abfd,struct stat * buf)14673d8817e4Smiod bfd_generic_stat_arch_elt (bfd *abfd, struct stat *buf)
14683d8817e4Smiod {
14693d8817e4Smiod   struct ar_hdr *hdr;
14703d8817e4Smiod   char *aloser;
14713d8817e4Smiod 
14723d8817e4Smiod   if (abfd->arelt_data == NULL)
14733d8817e4Smiod     {
14743d8817e4Smiod       bfd_set_error (bfd_error_invalid_operation);
14753d8817e4Smiod       return -1;
14763d8817e4Smiod     }
14773d8817e4Smiod 
14783d8817e4Smiod   hdr = arch_hdr (abfd);
14793d8817e4Smiod 
14803d8817e4Smiod #define foo(arelt, stelt, size)				\
14813d8817e4Smiod   buf->stelt = strtol (hdr->arelt, &aloser, size);	\
14823d8817e4Smiod   if (aloser == hdr->arelt)	      			\
14833d8817e4Smiod     return -1;
14843d8817e4Smiod 
1485d04417c8Smiod #define fooll(arelt, stelt, size)			\
1486d04417c8Smiod   buf->stelt = strtoll (hdr->arelt, &aloser, size);	\
1487d04417c8Smiod   if (aloser == hdr->arelt)	      			\
1488d04417c8Smiod     return -1;
1489d04417c8Smiod 
14903d8817e4Smiod   /* Some platforms support special notations for large IDs.  */
14913d8817e4Smiod #ifdef HPUX_LARGE_AR_IDS
14923d8817e4Smiod # define foo2(arelt, stelt, size)					\
14933d8817e4Smiod   if (hdr->arelt[5] == ' ')						\
14943d8817e4Smiod     {									\
14953d8817e4Smiod       foo (arelt, stelt, size);						\
14963d8817e4Smiod     }									\
14973d8817e4Smiod   else									\
14983d8817e4Smiod     {									\
14993d8817e4Smiod       int cnt;								\
15003d8817e4Smiod       for (buf->stelt = cnt = 0; cnt < 5; ++cnt)			\
15013d8817e4Smiod 	{								\
15023d8817e4Smiod 	  if (hdr->arelt[cnt] < ' ' || hdr->arelt[cnt] > ' ' + 0x3f)	\
15033d8817e4Smiod 	    return -1;							\
15043d8817e4Smiod 	  buf->stelt <<= 6;						\
15053d8817e4Smiod 	  buf->stelt += hdr->arelt[cnt] - ' ';				\
15063d8817e4Smiod 	}								\
15073d8817e4Smiod       if (hdr->arelt[5] < '@' || hdr->arelt[5] > '@' + 3)		\
15083d8817e4Smiod 	return -1;							\
15093d8817e4Smiod       buf->stelt <<= 2;							\
15103d8817e4Smiod       buf->stelt += hdr->arelt[5] - '@';				\
15113d8817e4Smiod     }
15123d8817e4Smiod #else
15133d8817e4Smiod # define foo2(arelt, stelt, size) foo (arelt, stelt, size)
15143d8817e4Smiod #endif
15153d8817e4Smiod 
1516d04417c8Smiod   fooll (ar_date, st_mtime, 10);
15173d8817e4Smiod   foo2 (ar_uid, st_uid, 10);
15183d8817e4Smiod   foo2 (ar_gid, st_gid, 10);
15193d8817e4Smiod   foo (ar_mode, st_mode, 8);
15203d8817e4Smiod 
15213d8817e4Smiod   buf->st_size = arch_eltdata (abfd)->parsed_size;
15223d8817e4Smiod 
15233d8817e4Smiod   return 0;
15243d8817e4Smiod }
15253d8817e4Smiod 
15263d8817e4Smiod void
bfd_dont_truncate_arname(bfd * abfd,const char * pathname,char * arhdr)15273d8817e4Smiod bfd_dont_truncate_arname (bfd *abfd, const char *pathname, char *arhdr)
15283d8817e4Smiod {
15293d8817e4Smiod   /* FIXME: This interacts unpleasantly with ar's quick-append option.
15303d8817e4Smiod      Fortunately ic960 users will never use that option.  Fixing this
15313d8817e4Smiod      is very hard; fortunately I know how to do it and will do so once
15323d8817e4Smiod      intel's release is out the door.  */
15333d8817e4Smiod 
15343d8817e4Smiod   struct ar_hdr *hdr = (struct ar_hdr *) arhdr;
15353d8817e4Smiod   size_t length;
15363d8817e4Smiod   const char *filename;
15373d8817e4Smiod   size_t maxlen = ar_maxnamelen (abfd);
15383d8817e4Smiod 
15393d8817e4Smiod   if ((bfd_get_file_flags (abfd) & BFD_TRADITIONAL_FORMAT) != 0)
15403d8817e4Smiod     {
15413d8817e4Smiod       bfd_bsd_truncate_arname (abfd, pathname, arhdr);
15423d8817e4Smiod       return;
15433d8817e4Smiod     }
15443d8817e4Smiod 
15453d8817e4Smiod   filename = normalize (abfd, pathname);
15463d8817e4Smiod   if (filename == NULL)
15473d8817e4Smiod     {
15483d8817e4Smiod       /* FIXME */
15493d8817e4Smiod       abort ();
15503d8817e4Smiod     }
15513d8817e4Smiod 
15523d8817e4Smiod   length = strlen (filename);
15533d8817e4Smiod 
15543d8817e4Smiod   if (length <= maxlen)
15553d8817e4Smiod     memcpy (hdr->ar_name, filename, length);
15563d8817e4Smiod 
15573d8817e4Smiod   /* Add the padding character if there is room for it.  */
15583d8817e4Smiod   if (length < maxlen
15593d8817e4Smiod       || (length == maxlen && length < sizeof hdr->ar_name))
15603d8817e4Smiod     (hdr->ar_name)[length] = ar_padchar (abfd);
15613d8817e4Smiod }
15623d8817e4Smiod 
15633d8817e4Smiod void
bfd_bsd_truncate_arname(bfd * abfd,const char * pathname,char * arhdr)15643d8817e4Smiod bfd_bsd_truncate_arname (bfd *abfd, const char *pathname, char *arhdr)
15653d8817e4Smiod {
15663d8817e4Smiod   struct ar_hdr *hdr = (struct ar_hdr *) arhdr;
15673d8817e4Smiod   size_t length;
15683d8817e4Smiod   const char *filename = strrchr (pathname, '/');
15693d8817e4Smiod   size_t maxlen = ar_maxnamelen (abfd);
15703d8817e4Smiod 
15713d8817e4Smiod #ifdef HAVE_DOS_BASED_FILE_SYSTEM
15723d8817e4Smiod   {
15733d8817e4Smiod     /* We could have foo/bar\\baz, or foo\\bar, or d:bar.  */
15743d8817e4Smiod     char *bslash = strrchr (pathname, '\\');
15753d8817e4Smiod     if (filename == NULL || (bslash != NULL && bslash > filename))
15763d8817e4Smiod       filename = bslash;
15773d8817e4Smiod     if (filename == NULL && pathname[0] != '\0' && pathname[1] == ':')
15783d8817e4Smiod       filename = pathname + 1;
15793d8817e4Smiod   }
15803d8817e4Smiod #endif
15813d8817e4Smiod 
15823d8817e4Smiod   if (filename == NULL)
15833d8817e4Smiod     filename = pathname;
15843d8817e4Smiod   else
15853d8817e4Smiod     ++filename;
15863d8817e4Smiod 
15873d8817e4Smiod   length = strlen (filename);
15883d8817e4Smiod 
15893d8817e4Smiod   if (length <= maxlen)
15903d8817e4Smiod     memcpy (hdr->ar_name, filename, length);
15913d8817e4Smiod   else
15923d8817e4Smiod     {
15933d8817e4Smiod       /* pathname: meet procrustes */
15943d8817e4Smiod       memcpy (hdr->ar_name, filename, maxlen);
15953d8817e4Smiod       length = maxlen;
15963d8817e4Smiod     }
15973d8817e4Smiod 
15983d8817e4Smiod   if (length < maxlen)
15993d8817e4Smiod     (hdr->ar_name)[length] = ar_padchar (abfd);
16003d8817e4Smiod }
16013d8817e4Smiod 
16023d8817e4Smiod /* Store name into ar header.  Truncates the name to fit.
16033d8817e4Smiod    1> strip pathname to be just the basename.
16043d8817e4Smiod    2> if it's short enuf to fit, stuff it in.
16053d8817e4Smiod    3> If it doesn't end with .o, truncate it to fit
16063d8817e4Smiod    4> truncate it before the .o, append .o, stuff THAT in.  */
16073d8817e4Smiod 
16083d8817e4Smiod /* This is what gnu ar does.  It's better but incompatible with the
16093d8817e4Smiod    bsd ar.  */
16103d8817e4Smiod 
16113d8817e4Smiod void
bfd_gnu_truncate_arname(bfd * abfd,const char * pathname,char * arhdr)16123d8817e4Smiod bfd_gnu_truncate_arname (bfd *abfd, const char *pathname, char *arhdr)
16133d8817e4Smiod {
16143d8817e4Smiod   struct ar_hdr *hdr = (struct ar_hdr *) arhdr;
16153d8817e4Smiod   size_t length;
16163d8817e4Smiod   const char *filename = strrchr (pathname, '/');
16173d8817e4Smiod   size_t maxlen = ar_maxnamelen (abfd);
16183d8817e4Smiod 
16193d8817e4Smiod #ifdef HAVE_DOS_BASED_FILE_SYSTEM
16203d8817e4Smiod   {
16213d8817e4Smiod     /* We could have foo/bar\\baz, or foo\\bar, or d:bar.  */
16223d8817e4Smiod     char *bslash = strrchr (pathname, '\\');
16233d8817e4Smiod     if (filename == NULL || (bslash != NULL && bslash > filename))
16243d8817e4Smiod       filename = bslash;
16253d8817e4Smiod     if (filename == NULL && pathname[0] != '\0' && pathname[1] == ':')
16263d8817e4Smiod       filename = pathname + 1;
16273d8817e4Smiod   }
16283d8817e4Smiod #endif
16293d8817e4Smiod 
16303d8817e4Smiod   if (filename == NULL)
16313d8817e4Smiod     filename = pathname;
16323d8817e4Smiod   else
16333d8817e4Smiod     ++filename;
16343d8817e4Smiod 
16353d8817e4Smiod   length = strlen (filename);
16363d8817e4Smiod 
16373d8817e4Smiod   if (length <= maxlen)
16383d8817e4Smiod     memcpy (hdr->ar_name, filename, length);
16393d8817e4Smiod   else
16403d8817e4Smiod     {				/* pathname: meet procrustes */
16413d8817e4Smiod       memcpy (hdr->ar_name, filename, maxlen);
16423d8817e4Smiod       if ((filename[length - 2] == '.') && (filename[length - 1] == 'o'))
16433d8817e4Smiod 	{
16443d8817e4Smiod 	  hdr->ar_name[maxlen - 2] = '.';
16453d8817e4Smiod 	  hdr->ar_name[maxlen - 1] = 'o';
16463d8817e4Smiod 	}
16473d8817e4Smiod       length = maxlen;
16483d8817e4Smiod     }
16493d8817e4Smiod 
16503d8817e4Smiod   if (length < 16)
16513d8817e4Smiod     (hdr->ar_name)[length] = ar_padchar (abfd);
16523d8817e4Smiod }
16533d8817e4Smiod 
16543d8817e4Smiod /* The BFD is open for write and has its format set to bfd_archive.  */
16553d8817e4Smiod 
16563d8817e4Smiod bfd_boolean
_bfd_write_archive_contents(bfd * arch)16573d8817e4Smiod _bfd_write_archive_contents (bfd *arch)
16583d8817e4Smiod {
16593d8817e4Smiod   bfd *current;
16603d8817e4Smiod   char *etable = NULL;
16613d8817e4Smiod   bfd_size_type elength = 0;
16623d8817e4Smiod   const char *ename = NULL;
16633d8817e4Smiod   bfd_boolean makemap = bfd_has_map (arch);
16643d8817e4Smiod   /* If no .o's, don't bother to make a map.  */
16653d8817e4Smiod   bfd_boolean hasobjects = FALSE;
16663d8817e4Smiod   bfd_size_type wrote;
16673d8817e4Smiod   int tries;
16683d8817e4Smiod 
16693d8817e4Smiod   /* Verify the viability of all entries; if any of them live in the
16703d8817e4Smiod      filesystem (as opposed to living in an archive open for input)
16713d8817e4Smiod      then construct a fresh ar_hdr for them.  */
16723d8817e4Smiod   for (current = arch->archive_head; current; current = current->next)
16733d8817e4Smiod     {
16743d8817e4Smiod       /* This check is checking the bfds for the objects we're reading
16753d8817e4Smiod 	 from (which are usually either an object file or archive on
16763d8817e4Smiod 	 disk), not the archive entries we're writing to.  We don't
16773d8817e4Smiod 	 actually create bfds for the archive members, we just copy
16783d8817e4Smiod 	 them byte-wise when we write out the archive.  */
16793d8817e4Smiod       if (bfd_write_p (current))
16803d8817e4Smiod 	{
16813d8817e4Smiod 	  bfd_set_error (bfd_error_invalid_operation);
16823d8817e4Smiod 	  return FALSE;
16833d8817e4Smiod 	}
16843d8817e4Smiod       if (!current->arelt_data)
16853d8817e4Smiod 	{
16863d8817e4Smiod 	  current->arelt_data =
16873d8817e4Smiod 	    bfd_ar_hdr_from_filesystem (arch, current->filename, current);
16883d8817e4Smiod 	  if (!current->arelt_data)
16893d8817e4Smiod 	    return FALSE;
16903d8817e4Smiod 
16913d8817e4Smiod 	  /* Put in the file name.  */
16923d8817e4Smiod 	  BFD_SEND (arch, _bfd_truncate_arname,
16933d8817e4Smiod 		    (arch, current->filename, (char *) arch_hdr (current)));
16943d8817e4Smiod 	}
16953d8817e4Smiod 
16963d8817e4Smiod       if (makemap && ! hasobjects)
16973d8817e4Smiod 	{			/* Don't bother if we won't make a map!  */
16983d8817e4Smiod 	  if ((bfd_check_format (current, bfd_object)))
16993d8817e4Smiod 	    hasobjects = TRUE;
17003d8817e4Smiod 	}
17013d8817e4Smiod     }
17023d8817e4Smiod 
17033d8817e4Smiod   if (!BFD_SEND (arch, _bfd_construct_extended_name_table,
17043d8817e4Smiod 		 (arch, &etable, &elength, &ename)))
17053d8817e4Smiod     return FALSE;
17063d8817e4Smiod 
17073d8817e4Smiod   if (bfd_seek (arch, (file_ptr) 0, SEEK_SET) != 0)
17083d8817e4Smiod     return FALSE;
17093d8817e4Smiod   wrote = bfd_bwrite (ARMAG, SARMAG, arch);
17103d8817e4Smiod   if (wrote != SARMAG)
17113d8817e4Smiod     return FALSE;
17123d8817e4Smiod 
17133d8817e4Smiod   if (makemap && hasobjects)
17143d8817e4Smiod     {
17153d8817e4Smiod       if (! _bfd_compute_and_write_armap (arch, (unsigned int) elength))
17163d8817e4Smiod 	return FALSE;
17173d8817e4Smiod     }
17183d8817e4Smiod 
17193d8817e4Smiod   if (elength != 0)
17203d8817e4Smiod     {
17213d8817e4Smiod       struct ar_hdr hdr;
17223d8817e4Smiod 
17233d8817e4Smiod       memset (&hdr, ' ', sizeof (struct ar_hdr));
17243d8817e4Smiod       memcpy (hdr.ar_name, ename, strlen (ename));
17253d8817e4Smiod       /* Round size up to even number in archive header.  */
17263d8817e4Smiod       _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld",
17273d8817e4Smiod                         (elength + 1) & ~(bfd_size_type) 1);
17283d8817e4Smiod       memcpy (hdr.ar_fmag, ARFMAG, 2);
17293d8817e4Smiod       if ((bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch)
17303d8817e4Smiod 	   != sizeof (struct ar_hdr))
17313d8817e4Smiod 	  || bfd_bwrite (etable, elength, arch) != elength)
17323d8817e4Smiod 	return FALSE;
17333d8817e4Smiod       if ((elength % 2) == 1)
17343d8817e4Smiod 	{
17353d8817e4Smiod 	  if (bfd_bwrite ("\012", 1, arch) != 1)
17363d8817e4Smiod 	    return FALSE;
17373d8817e4Smiod 	}
17383d8817e4Smiod     }
17393d8817e4Smiod 
17403d8817e4Smiod   for (current = arch->archive_head; current; current = current->next)
17413d8817e4Smiod     {
17423d8817e4Smiod       char buffer[DEFAULT_BUFFERSIZE];
17433d8817e4Smiod       unsigned int remaining = arelt_size (current);
17443d8817e4Smiod       struct ar_hdr *hdr = arch_hdr (current);
17453d8817e4Smiod 
17463d8817e4Smiod       /* Write ar header.  */
17473d8817e4Smiod       if (bfd_bwrite (hdr, sizeof (*hdr), arch)
17483d8817e4Smiod 	  != sizeof (*hdr))
17493d8817e4Smiod 	return FALSE;
17503d8817e4Smiod       if (bfd_seek (current, (file_ptr) 0, SEEK_SET) != 0)
17513d8817e4Smiod 	return FALSE;
17523d8817e4Smiod       while (remaining)
17533d8817e4Smiod 	{
17543d8817e4Smiod 	  unsigned int amt = DEFAULT_BUFFERSIZE;
17553d8817e4Smiod 	  if (amt > remaining)
17563d8817e4Smiod 	    amt = remaining;
17573d8817e4Smiod 	  errno = 0;
17583d8817e4Smiod 	  if (bfd_bread (buffer, amt, current) != amt)
17593d8817e4Smiod 	    {
17603d8817e4Smiod 	      if (bfd_get_error () != bfd_error_system_call)
17613d8817e4Smiod 		bfd_set_error (bfd_error_malformed_archive);
17623d8817e4Smiod 	      return FALSE;
17633d8817e4Smiod 	    }
17643d8817e4Smiod 	  if (bfd_bwrite (buffer, amt, arch) != amt)
17653d8817e4Smiod 	    return FALSE;
17663d8817e4Smiod 	  remaining -= amt;
17673d8817e4Smiod 	}
17683d8817e4Smiod       if ((arelt_size (current) % 2) == 1)
17693d8817e4Smiod 	{
17703d8817e4Smiod 	  if (bfd_bwrite ("\012", 1, arch) != 1)
17713d8817e4Smiod 	    return FALSE;
17723d8817e4Smiod 	}
17733d8817e4Smiod     }
17743d8817e4Smiod 
17753d8817e4Smiod   if (makemap && hasobjects)
17763d8817e4Smiod     {
17773d8817e4Smiod       /* Verify the timestamp in the archive file.  If it would not be
17783d8817e4Smiod 	 accepted by the linker, rewrite it until it would be.  If
17793d8817e4Smiod 	 anything odd happens, break out and just return.  (The
17803d8817e4Smiod 	 Berkeley linker checks the timestamp and refuses to read the
17813d8817e4Smiod 	 table-of-contents if it is >60 seconds less than the file's
17823d8817e4Smiod 	 modified-time.  That painful hack requires this painful hack.  */
17833d8817e4Smiod       tries = 1;
17843d8817e4Smiod       do
17853d8817e4Smiod 	{
17863d8817e4Smiod 	  if (bfd_update_armap_timestamp (arch))
17873d8817e4Smiod 	    break;
17883d8817e4Smiod 	  (*_bfd_error_handler)
17893d8817e4Smiod 	    (_("Warning: writing archive was slow: rewriting timestamp\n"));
17903d8817e4Smiod 	}
17913d8817e4Smiod       while (++tries < 6);
17923d8817e4Smiod     }
17933d8817e4Smiod 
17943d8817e4Smiod   return TRUE;
17953d8817e4Smiod }
17963d8817e4Smiod 
17973d8817e4Smiod /* Note that the namidx for the first symbol is 0.  */
17983d8817e4Smiod 
17993d8817e4Smiod bfd_boolean
_bfd_compute_and_write_armap(bfd * arch,unsigned int elength)18003d8817e4Smiod _bfd_compute_and_write_armap (bfd *arch, unsigned int elength)
18013d8817e4Smiod {
18023d8817e4Smiod   char *first_name = NULL;
18033d8817e4Smiod   bfd *current;
18043d8817e4Smiod   file_ptr elt_no = 0;
18053d8817e4Smiod   struct orl *map = NULL;
18063d8817e4Smiod   unsigned int orl_max = 1024;		/* Fine initial default.  */
18073d8817e4Smiod   unsigned int orl_count = 0;
18083d8817e4Smiod   int stridx = 0;
18093d8817e4Smiod   asymbol **syms = NULL;
18103d8817e4Smiod   long syms_max = 0;
18113d8817e4Smiod   bfd_boolean ret;
18123d8817e4Smiod   bfd_size_type amt;
18133d8817e4Smiod 
18143d8817e4Smiod   /* Dunno if this is the best place for this info...  */
18153d8817e4Smiod   if (elength != 0)
18163d8817e4Smiod     elength += sizeof (struct ar_hdr);
18173d8817e4Smiod   elength += elength % 2;
18183d8817e4Smiod 
18193d8817e4Smiod   amt = orl_max * sizeof (struct orl);
18203d8817e4Smiod   map = bfd_malloc (amt);
18213d8817e4Smiod   if (map == NULL)
18223d8817e4Smiod     goto error_return;
18233d8817e4Smiod 
18243d8817e4Smiod   /* We put the symbol names on the arch objalloc, and then discard
18253d8817e4Smiod      them when done.  */
18263d8817e4Smiod   first_name = bfd_alloc (arch, 1);
18273d8817e4Smiod   if (first_name == NULL)
18283d8817e4Smiod     goto error_return;
18293d8817e4Smiod 
18303d8817e4Smiod   /* Drop all the files called __.SYMDEF, we're going to make our own.  */
18313d8817e4Smiod   while (arch->archive_head &&
18323d8817e4Smiod 	 strcmp (arch->archive_head->filename, "__.SYMDEF") == 0)
18333d8817e4Smiod     arch->archive_head = arch->archive_head->next;
18343d8817e4Smiod 
18353d8817e4Smiod   /* Map over each element.  */
18363d8817e4Smiod   for (current = arch->archive_head;
18373d8817e4Smiod        current != NULL;
18383d8817e4Smiod        current = current->next, elt_no++)
18393d8817e4Smiod     {
18403d8817e4Smiod       if (bfd_check_format (current, bfd_object)
18413d8817e4Smiod 	  && (bfd_get_file_flags (current) & HAS_SYMS) != 0)
18423d8817e4Smiod 	{
18433d8817e4Smiod 	  long storage;
18443d8817e4Smiod 	  long symcount;
18453d8817e4Smiod 	  long src_count;
18463d8817e4Smiod 
18473d8817e4Smiod 	  storage = bfd_get_symtab_upper_bound (current);
18483d8817e4Smiod 	  if (storage < 0)
18493d8817e4Smiod 	    goto error_return;
18503d8817e4Smiod 
18513d8817e4Smiod 	  if (storage != 0)
18523d8817e4Smiod 	    {
18533d8817e4Smiod 	      if (storage > syms_max)
18543d8817e4Smiod 		{
18553d8817e4Smiod 		  if (syms_max > 0)
18563d8817e4Smiod 		    free (syms);
18573d8817e4Smiod 		  syms_max = storage;
18583d8817e4Smiod 		  syms = bfd_malloc (syms_max);
18593d8817e4Smiod 		  if (syms == NULL)
18603d8817e4Smiod 		    goto error_return;
18613d8817e4Smiod 		}
18623d8817e4Smiod 	      symcount = bfd_canonicalize_symtab (current, syms);
18633d8817e4Smiod 	      if (symcount < 0)
18643d8817e4Smiod 		goto error_return;
18653d8817e4Smiod 
18663d8817e4Smiod 	      /* Now map over all the symbols, picking out the ones we
18673d8817e4Smiod                  want.  */
18683d8817e4Smiod 	      for (src_count = 0; src_count < symcount; src_count++)
18693d8817e4Smiod 		{
18703d8817e4Smiod 		  flagword flags = (syms[src_count])->flags;
18713d8817e4Smiod 		  asection *sec = syms[src_count]->section;
18723d8817e4Smiod 
18733d8817e4Smiod 		  if ((flags & BSF_GLOBAL ||
18743d8817e4Smiod 		       flags & BSF_WEAK ||
18753d8817e4Smiod 		       flags & BSF_INDIRECT ||
18763d8817e4Smiod 		       bfd_is_com_section (sec))
18773d8817e4Smiod 		      && ! bfd_is_und_section (sec))
18783d8817e4Smiod 		    {
18793d8817e4Smiod 		      bfd_size_type namelen;
18803d8817e4Smiod 		      struct orl *new_map;
18813d8817e4Smiod 
18823d8817e4Smiod 		      /* This symbol will go into the archive header.  */
18833d8817e4Smiod 		      if (orl_count == orl_max)
18843d8817e4Smiod 			{
18853d8817e4Smiod 			  orl_max *= 2;
18863d8817e4Smiod 			  amt = orl_max * sizeof (struct orl);
18873d8817e4Smiod 			  new_map = bfd_realloc (map, amt);
18883d8817e4Smiod 			  if (new_map == NULL)
18893d8817e4Smiod 			    goto error_return;
18903d8817e4Smiod 
18913d8817e4Smiod 			  map = new_map;
18923d8817e4Smiod 			}
18933d8817e4Smiod 
18943d8817e4Smiod 		      namelen = strlen (syms[src_count]->name);
18953d8817e4Smiod 		      amt = sizeof (char *);
18963d8817e4Smiod 		      map[orl_count].name = bfd_alloc (arch, amt);
18973d8817e4Smiod 		      if (map[orl_count].name == NULL)
18983d8817e4Smiod 			goto error_return;
18993d8817e4Smiod 		      *(map[orl_count].name) = bfd_alloc (arch, namelen + 1);
19003d8817e4Smiod 		      if (*(map[orl_count].name) == NULL)
19013d8817e4Smiod 			goto error_return;
19023d8817e4Smiod 		      strcpy (*(map[orl_count].name), syms[src_count]->name);
19033d8817e4Smiod 		      map[orl_count].u.abfd = current;
19043d8817e4Smiod 		      map[orl_count].namidx = stridx;
19053d8817e4Smiod 
19063d8817e4Smiod 		      stridx += namelen + 1;
19073d8817e4Smiod 		      ++orl_count;
19083d8817e4Smiod 		    }
19093d8817e4Smiod 		}
19103d8817e4Smiod 	    }
19113d8817e4Smiod 
19123d8817e4Smiod 	  /* Now ask the BFD to free up any cached information, so we
19133d8817e4Smiod 	     don't fill all of memory with symbol tables.  */
19143d8817e4Smiod 	  if (! bfd_free_cached_info (current))
19153d8817e4Smiod 	    goto error_return;
19163d8817e4Smiod 	}
19173d8817e4Smiod     }
19183d8817e4Smiod 
19193d8817e4Smiod   /* OK, now we have collected all the data, let's write them out.  */
19203d8817e4Smiod   ret = BFD_SEND (arch, write_armap,
19213d8817e4Smiod 		  (arch, elength, map, orl_count, stridx));
19223d8817e4Smiod 
19233d8817e4Smiod   if (syms_max > 0)
19243d8817e4Smiod     free (syms);
19253d8817e4Smiod   if (map != NULL)
19263d8817e4Smiod     free (map);
19273d8817e4Smiod   if (first_name != NULL)
19283d8817e4Smiod     bfd_release (arch, first_name);
19293d8817e4Smiod 
19303d8817e4Smiod   return ret;
19313d8817e4Smiod 
19323d8817e4Smiod  error_return:
19333d8817e4Smiod   if (syms_max > 0)
19343d8817e4Smiod     free (syms);
19353d8817e4Smiod   if (map != NULL)
19363d8817e4Smiod     free (map);
19373d8817e4Smiod   if (first_name != NULL)
19383d8817e4Smiod     bfd_release (arch, first_name);
19393d8817e4Smiod 
19403d8817e4Smiod   return FALSE;
19413d8817e4Smiod }
19423d8817e4Smiod 
19433d8817e4Smiod bfd_boolean
bsd_write_armap(bfd * arch,unsigned int elength,struct orl * map,unsigned int orl_count,int stridx)19443d8817e4Smiod bsd_write_armap (bfd *arch,
19453d8817e4Smiod 		 unsigned int elength,
19463d8817e4Smiod 		 struct orl *map,
19473d8817e4Smiod 		 unsigned int orl_count,
19483d8817e4Smiod 		 int stridx)
19493d8817e4Smiod {
19503d8817e4Smiod   int padit = stridx & 1;
19513d8817e4Smiod   unsigned int ranlibsize = orl_count * BSD_SYMDEF_SIZE;
19523d8817e4Smiod   unsigned int stringsize = stridx + padit;
19533d8817e4Smiod   /* Include 8 bytes to store ranlibsize and stringsize in output.  */
19543d8817e4Smiod   unsigned int mapsize = ranlibsize + stringsize + 8;
19553d8817e4Smiod   file_ptr firstreal;
19563d8817e4Smiod   bfd *current = arch->archive_head;
19573d8817e4Smiod   bfd *last_elt = current;	/* Last element arch seen.  */
19583d8817e4Smiod   bfd_byte temp[4];
19593d8817e4Smiod   unsigned int count;
19603d8817e4Smiod   struct ar_hdr hdr;
19613d8817e4Smiod   struct stat statbuf;
1962*314e8fdfSguenther   long int uid, gid;
19633d8817e4Smiod 
19643d8817e4Smiod   firstreal = mapsize + elength + sizeof (struct ar_hdr) + SARMAG;
19653d8817e4Smiod 
19663d8817e4Smiod   stat (arch->filename, &statbuf);
19673d8817e4Smiod   memset (&hdr, ' ', sizeof (struct ar_hdr));
19683d8817e4Smiod   memcpy (hdr.ar_name, RANLIBMAG, strlen (RANLIBMAG));
19693d8817e4Smiod   /* Remember the timestamp, to keep it holy.  But fudge it a little.  */
19703d8817e4Smiod   bfd_ardata (arch)->armap_timestamp = statbuf.st_mtime + ARMAP_TIME_OFFSET;
19713d8817e4Smiod   bfd_ardata (arch)->armap_datepos = (SARMAG
19723d8817e4Smiod 				      + offsetof (struct ar_hdr, ar_date[0]));
197304a47612Sguenther   _bfd_ar_spacepadll (hdr.ar_date, sizeof (hdr.ar_date), "%lld",
19743d8817e4Smiod                     bfd_ardata (arch)->armap_timestamp);
1975*314e8fdfSguenther   if ((arch->flags & BFD_DETERMINISTIC) != 0)
1976*314e8fdfSguenther     uid = gid = 0;
1977*314e8fdfSguenther   else
1978*314e8fdfSguenther     {
1979*314e8fdfSguenther       uid = getuid ();
1980*314e8fdfSguenther       gid = getgid ();
1981*314e8fdfSguenther     }
1982*314e8fdfSguenther   _bfd_ar_spacepad (hdr.ar_uid, sizeof (hdr.ar_uid), "%ld", uid);
1983*314e8fdfSguenther   _bfd_ar_spacepad (hdr.ar_gid, sizeof (hdr.ar_gid), "%ld", gid);
19843d8817e4Smiod   _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld", mapsize);
19853d8817e4Smiod   memcpy (hdr.ar_fmag, ARFMAG, 2);
19863d8817e4Smiod   if (bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch)
19873d8817e4Smiod       != sizeof (struct ar_hdr))
19883d8817e4Smiod     return FALSE;
19893d8817e4Smiod   H_PUT_32 (arch, ranlibsize, temp);
19903d8817e4Smiod   if (bfd_bwrite (temp, sizeof (temp), arch) != sizeof (temp))
19913d8817e4Smiod     return FALSE;
19923d8817e4Smiod 
19933d8817e4Smiod   for (count = 0; count < orl_count; count++)
19943d8817e4Smiod     {
19953d8817e4Smiod       bfd_byte buf[BSD_SYMDEF_SIZE];
19963d8817e4Smiod 
19973d8817e4Smiod       if (map[count].u.abfd != last_elt)
19983d8817e4Smiod 	{
19993d8817e4Smiod 	  do
20003d8817e4Smiod 	    {
20013d8817e4Smiod 	      firstreal += arelt_size (current) + sizeof (struct ar_hdr);
20023d8817e4Smiod 	      firstreal += firstreal % 2;
20033d8817e4Smiod 	      current = current->next;
20043d8817e4Smiod 	    }
20053d8817e4Smiod 	  while (current != map[count].u.abfd);
20063d8817e4Smiod 	}
20073d8817e4Smiod 
20083d8817e4Smiod       last_elt = current;
20093d8817e4Smiod       H_PUT_32 (arch, map[count].namidx, buf);
20103d8817e4Smiod       H_PUT_32 (arch, firstreal, buf + BSD_SYMDEF_OFFSET_SIZE);
20113d8817e4Smiod       if (bfd_bwrite (buf, BSD_SYMDEF_SIZE, arch)
20123d8817e4Smiod 	  != BSD_SYMDEF_SIZE)
20133d8817e4Smiod 	return FALSE;
20143d8817e4Smiod     }
20153d8817e4Smiod 
20163d8817e4Smiod   /* Now write the strings themselves.  */
20173d8817e4Smiod   H_PUT_32 (arch, stringsize, temp);
20183d8817e4Smiod   if (bfd_bwrite (temp, sizeof (temp), arch) != sizeof (temp))
20193d8817e4Smiod     return FALSE;
20203d8817e4Smiod   for (count = 0; count < orl_count; count++)
20213d8817e4Smiod     {
20223d8817e4Smiod       size_t len = strlen (*map[count].name) + 1;
20233d8817e4Smiod 
20243d8817e4Smiod       if (bfd_bwrite (*map[count].name, len, arch) != len)
20253d8817e4Smiod 	return FALSE;
20263d8817e4Smiod     }
20273d8817e4Smiod 
20283d8817e4Smiod   /* The spec sez this should be a newline.  But in order to be
20293d8817e4Smiod      bug-compatible for sun's ar we use a null.  */
20303d8817e4Smiod   if (padit)
20313d8817e4Smiod     {
20323d8817e4Smiod       if (bfd_bwrite ("", 1, arch) != 1)
20333d8817e4Smiod 	return FALSE;
20343d8817e4Smiod     }
20353d8817e4Smiod 
20363d8817e4Smiod   return TRUE;
20373d8817e4Smiod }
20383d8817e4Smiod 
20393d8817e4Smiod /* At the end of archive file handling, update the timestamp in the
20403d8817e4Smiod    file, so the linker will accept it.
20413d8817e4Smiod 
20423d8817e4Smiod    Return TRUE if the timestamp was OK, or an unusual problem happened.
20433d8817e4Smiod    Return FALSE if we updated the timestamp.  */
20443d8817e4Smiod 
20453d8817e4Smiod bfd_boolean
_bfd_archive_bsd_update_armap_timestamp(bfd * arch)20463d8817e4Smiod _bfd_archive_bsd_update_armap_timestamp (bfd *arch)
20473d8817e4Smiod {
20483d8817e4Smiod   struct stat archstat;
20493d8817e4Smiod   struct ar_hdr hdr;
20503d8817e4Smiod 
20513d8817e4Smiod   /* Flush writes, get last-write timestamp from file, and compare it
20523d8817e4Smiod      to the timestamp IN the file.  */
20533d8817e4Smiod   bfd_flush (arch);
20543d8817e4Smiod   if (bfd_stat (arch, &archstat) == -1)
20553d8817e4Smiod     {
20563d8817e4Smiod       bfd_perror (_("Reading archive file mod timestamp"));
20573d8817e4Smiod 
20583d8817e4Smiod       /* Can't read mod time for some reason.  */
20593d8817e4Smiod       return TRUE;
20603d8817e4Smiod     }
20613d8817e4Smiod   if (archstat.st_mtime <= bfd_ardata (arch)->armap_timestamp)
20623d8817e4Smiod     /* OK by the linker's rules.  */
20633d8817e4Smiod     return TRUE;
20643d8817e4Smiod 
20653d8817e4Smiod   /* Update the timestamp.  */
20663d8817e4Smiod   bfd_ardata (arch)->armap_timestamp = archstat.st_mtime + ARMAP_TIME_OFFSET;
20673d8817e4Smiod 
20683d8817e4Smiod   /* Prepare an ASCII version suitable for writing.  */
20693d8817e4Smiod   memset (hdr.ar_date, ' ', sizeof (hdr.ar_date));
207004a47612Sguenther   _bfd_ar_spacepadll (hdr.ar_date, sizeof (hdr.ar_date), "%lld",
20713d8817e4Smiod                     bfd_ardata (arch)->armap_timestamp);
20723d8817e4Smiod 
20733d8817e4Smiod   /* Write it into the file.  */
20743d8817e4Smiod   bfd_ardata (arch)->armap_datepos = (SARMAG
20753d8817e4Smiod 				      + offsetof (struct ar_hdr, ar_date[0]));
20763d8817e4Smiod   if (bfd_seek (arch, bfd_ardata (arch)->armap_datepos, SEEK_SET) != 0
20773d8817e4Smiod       || (bfd_bwrite (hdr.ar_date, sizeof (hdr.ar_date), arch)
20783d8817e4Smiod 	  != sizeof (hdr.ar_date)))
20793d8817e4Smiod     {
20803d8817e4Smiod       bfd_perror (_("Writing updated armap timestamp"));
20813d8817e4Smiod 
20823d8817e4Smiod       /* Some error while writing.  */
20833d8817e4Smiod       return TRUE;
20843d8817e4Smiod     }
20853d8817e4Smiod 
20863d8817e4Smiod   /* We updated the timestamp successfully.  */
20873d8817e4Smiod   return FALSE;
20883d8817e4Smiod }
20893d8817e4Smiod 
20903d8817e4Smiod /* A coff armap looks like :
20913d8817e4Smiod    lARMAG
20923d8817e4Smiod    struct ar_hdr with name = '/'
20933d8817e4Smiod    number of symbols
20943d8817e4Smiod    offset of file for symbol 0
20953d8817e4Smiod    offset of file for symbol 1
20963d8817e4Smiod 
20973d8817e4Smiod    offset of file for symbol n-1
20983d8817e4Smiod    symbol name 0
20993d8817e4Smiod    symbol name 1
21003d8817e4Smiod 
21013d8817e4Smiod    symbol name n-1  */
21023d8817e4Smiod 
21033d8817e4Smiod bfd_boolean
coff_write_armap(bfd * arch,unsigned int elength,struct orl * map,unsigned int symbol_count,int stridx)21043d8817e4Smiod coff_write_armap (bfd *arch,
21053d8817e4Smiod 		  unsigned int elength,
21063d8817e4Smiod 		  struct orl *map,
21073d8817e4Smiod 		  unsigned int symbol_count,
21083d8817e4Smiod 		  int stridx)
21093d8817e4Smiod {
21103d8817e4Smiod   /* The size of the ranlib is the number of exported symbols in the
21113d8817e4Smiod      archive * the number of bytes in an int, + an int for the count.  */
21123d8817e4Smiod   unsigned int ranlibsize = (symbol_count * 4) + 4;
21133d8817e4Smiod   unsigned int stringsize = stridx;
21143d8817e4Smiod   unsigned int mapsize = stringsize + ranlibsize;
21153d8817e4Smiod   unsigned int archive_member_file_ptr;
21163d8817e4Smiod   bfd *current = arch->archive_head;
21173d8817e4Smiod   unsigned int count;
21183d8817e4Smiod   struct ar_hdr hdr;
21193d8817e4Smiod   int padit = mapsize & 1;
21203d8817e4Smiod 
21213d8817e4Smiod   if (padit)
21223d8817e4Smiod     mapsize++;
21233d8817e4Smiod 
21243d8817e4Smiod   /* Work out where the first object file will go in the archive.  */
21253d8817e4Smiod   archive_member_file_ptr = (mapsize
21263d8817e4Smiod 			     + elength
21273d8817e4Smiod 			     + sizeof (struct ar_hdr)
21283d8817e4Smiod 			     + SARMAG);
21293d8817e4Smiod 
21303d8817e4Smiod   memset (&hdr, ' ', sizeof (struct ar_hdr));
21313d8817e4Smiod   hdr.ar_name[0] = '/';
21323d8817e4Smiod   _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld",
21333d8817e4Smiod                     mapsize);
213404a47612Sguenther   _bfd_ar_spacepadll (hdr.ar_date, sizeof (hdr.ar_date), "%lld",
21353d8817e4Smiod                     time (NULL));
21363d8817e4Smiod   /* This, at least, is what Intel coff sets the values to.  */
21373d8817e4Smiod   _bfd_ar_spacepad (hdr.ar_uid, sizeof (hdr.ar_uid), "%ld", 0);
21383d8817e4Smiod   _bfd_ar_spacepad (hdr.ar_gid, sizeof (hdr.ar_gid), "%ld", 0);
21393d8817e4Smiod   _bfd_ar_spacepad (hdr.ar_mode, sizeof (hdr.ar_mode), "%-7lo", 0);
21403d8817e4Smiod   memcpy (hdr.ar_fmag, ARFMAG, 2);
21413d8817e4Smiod 
21423d8817e4Smiod   /* Write the ar header for this item and the number of symbols.  */
21433d8817e4Smiod   if (bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch)
21443d8817e4Smiod       != sizeof (struct ar_hdr))
21453d8817e4Smiod     return FALSE;
21463d8817e4Smiod 
21473d8817e4Smiod   if (!bfd_write_bigendian_4byte_int (arch, symbol_count))
21483d8817e4Smiod     return FALSE;
21493d8817e4Smiod 
21503d8817e4Smiod   /* Two passes, first write the file offsets for each symbol -
21513d8817e4Smiod      remembering that each offset is on a two byte boundary.  */
21523d8817e4Smiod 
21533d8817e4Smiod   /* Write out the file offset for the file associated with each
21543d8817e4Smiod      symbol, and remember to keep the offsets padded out.  */
21553d8817e4Smiod 
21563d8817e4Smiod   current = arch->archive_head;
21573d8817e4Smiod   count = 0;
21583d8817e4Smiod   while (current != NULL && count < symbol_count)
21593d8817e4Smiod     {
21603d8817e4Smiod       /* For each symbol which is used defined in this object, write
21613d8817e4Smiod 	 out the object file's address in the archive.  */
21623d8817e4Smiod 
21633d8817e4Smiod       while (count < symbol_count && map[count].u.abfd == current)
21643d8817e4Smiod 	{
21653d8817e4Smiod 	  if (!bfd_write_bigendian_4byte_int (arch, archive_member_file_ptr))
21663d8817e4Smiod 	    return FALSE;
21673d8817e4Smiod 	  count++;
21683d8817e4Smiod 	}
21693d8817e4Smiod       /* Add size of this archive entry.  */
21703d8817e4Smiod       archive_member_file_ptr += arelt_size (current) + sizeof (struct ar_hdr);
21713d8817e4Smiod       /* Remember aboout the even alignment.  */
21723d8817e4Smiod       archive_member_file_ptr += archive_member_file_ptr % 2;
21733d8817e4Smiod       current = current->next;
21743d8817e4Smiod     }
21753d8817e4Smiod 
21763d8817e4Smiod   /* Now write the strings themselves.  */
21773d8817e4Smiod   for (count = 0; count < symbol_count; count++)
21783d8817e4Smiod     {
21793d8817e4Smiod       size_t len = strlen (*map[count].name) + 1;
21803d8817e4Smiod 
21813d8817e4Smiod       if (bfd_bwrite (*map[count].name, len, arch) != len)
21823d8817e4Smiod 	return FALSE;
21833d8817e4Smiod     }
21843d8817e4Smiod 
21853d8817e4Smiod   /* The spec sez this should be a newline.  But in order to be
21863d8817e4Smiod      bug-compatible for arc960 we use a null.  */
21873d8817e4Smiod   if (padit)
21883d8817e4Smiod     {
21893d8817e4Smiod       if (bfd_bwrite ("", 1, arch) != 1)
21903d8817e4Smiod 	return FALSE;
21913d8817e4Smiod     }
21923d8817e4Smiod 
21933d8817e4Smiod   return TRUE;
21943d8817e4Smiod }
2195