/* BFD back-end for archive files (libraries).
- Copyright (C) 1990-1991 Free Software Foundation, Inc.
+ Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
Written by Cygnus Support. Mostly Gumby Henkel-Wallace's fault.
This file is part of BFD, the Binary File Descriptor library.
As expected, the BFD archive code is more general than the
archive code of any given environment. BFD archives may
- contain files of different formats (eg a.out and coff) and
+ contain files of different formats (e.g., a.out and coff) and
even different architectures. You may even place archives
recursively into archives!
This can cause unexpected confusion, since some archive
- formats are more expressive than others. For instance intel
+ formats are more expressive than others. For instance, Intel
COFF archives can preserve long filenames; Sun a.out archives
cannot. If you move a file from the first to the second
format and back again, the filename may be truncated.
This scheme unfortunately requires that you stand on your head in
order to write an archive since you need to put a magic file at the
front, and need to touch every entry to do so. C'est la vie.
+
+ We support two variants of this idea:
+ The SVR4 format (extended name table is named "//"),
+ and an extended pseudo-BSD variant (extended name table is named
+ "ARFILENAMES/"). The origin of the latter format is uncertain.
+
+ BSD 4.4 uses a third scheme: It writes a long filename
+ directly after the header. This allows 'ar q' to work.
+ We current can read BSD 4.4 archives, but not write them.
*/
+/* Summary of archive member names:
+
+ Symbol table (must be first):
+ "__.SYMDEF " - Symbol table, Berkeley style, produced by ranlib.
+ "/ " - Symbol table, system 5 style.
+
+ Long name table (must be before regular file members):
+ "// " - Long name table, System 5 R4 style.
+ "ARFILENAMES/ " - Long name table, non-standard extended BSD (not BSD 4.4).
+
+ Regular file members with short names:
+ "filename.o/ " - Regular file, System 5 style (embedded spaces ok).
+ "filename.o " - Regular file, Berkeley style (no embedded spaces).
+
+ Regular files with long names (or embedded spaces, for BSD variants):
+ "/18 " - SVR4 style, name at offset 18 in name table.
+ "#1/23 " - Long name (or embedded paces) 23 characters long,
+ BSD 4.4 style, full name follows header.
+ Implemented for reading, not writing.
+ " 18 " - Long name 18 characters long, extended pseudo-BSD.
+ */
+
#include "bfd.h"
#include "sysdep.h"
#include "libbfd.h"
#include "aout/ar.h"
#include "aout/ranlib.h"
#include <errno.h>
+#include <string.h> /* For memchr, strrchr and friends */
+#include <ctype.h>
#ifndef errno
extern int errno;
#define ar_padchar(abfd) ((abfd)->xvec->ar_pad_char)
#define ar_maxnamelen(abfd) ((abfd)->xvec->ar_max_namelen)
-#define arch_hdr(bfd) ((struct ar_hdr *) \
- (((struct areltdata *)((bfd)->arelt_data))->arch_header))
+#define arch_eltdata(bfd) ((struct areltdata *)((bfd)->arelt_data))
+#define arch_hdr(bfd) ((struct ar_hdr *)arch_eltdata(bfd)->arch_header)
+
+/* Forward declarations of functions */
+
+boolean
+compute_and_write_armap PARAMS ((bfd *arch, unsigned int elength));
+
+static boolean
+bsd_update_armap_timestamp PARAMS ((bfd *arch));
+
+
\f
boolean
_bfd_generic_mkarchive (abfd)
bfd *abfd;
{
- abfd->tdata.aout_ar_data = (struct artdata *)bfd_zalloc(abfd, sizeof (struct artdata));
+ abfd->tdata.aout_ar_data = (struct artdata *)bfd_zalloc(abfd,
+ sizeof (struct artdata));
if (bfd_ardata (abfd) == NULL) {
bfd_error = no_memory;
unsigned long index = 0;
/* Should extract string so that I can guarantee not to overflow into
- the next region, but I"m too lazy. */
+ the next region, but I'm too lazy. */
errno = 0;
- index = strtol (name, NULL, 10);
+ /* Skip first char, which is '/' in SVR4 or ' ' in some other variants. */
+ index = strtol (name+1, NULL, 10);
if (errno != 0) {
bfd_error = malformed_archive;
return NULL;
char *filename = NULL;
unsigned int namelen = 0;
unsigned int allocsize = sizeof (struct areltdata) + sizeof (struct ar_hdr);
- char *allocptr;
+ char *allocptr = 0;
if (bfd_read ((PTR)hdrp, 1, sizeof (struct ar_hdr), abfd)
!= sizeof (struct ar_hdr)) {
/* extract the filename from the archive - there are two ways to
specify an extendend name table, either the first char of the
- name is a space, or it's a slash */
- if ((hdr.ar_name[0] == '/' || hdr.ar_name[0] == ' ')
+ name is a space, or it's a slash. */
+ if ((hdr.ar_name[0] == '/'
+ || (hdr.ar_name[0] == ' '
+ && memchr (hdr.ar_name, '/', ar_maxnamelen(abfd)) == NULL))
&& bfd_ardata (abfd)->extended_names != NULL) {
filename = get_extended_arelt_filename (abfd, hdr.ar_name);
if (filename == NULL) {
bfd_error = malformed_archive;
return NULL;
}
- }
+ }
+ /* BSD4.4-style long filename.
+ Only implemented for reading, so far! */
+ else if (hdr.ar_name[0] == '#' && hdr.ar_name[1] == '1'
+ && hdr.ar_name[2] == '/' && isdigit(hdr.ar_name[3]))
+ {
+ /* BSD-4.4 extended name */
+ namelen = atoi (&hdr.ar_name[3]);
+ allocsize += namelen + 1;
+ parsed_size -= namelen;
+
+ allocptr = bfd_zalloc(abfd, allocsize);
+ if (allocptr == NULL) {
+ bfd_error = no_memory;
+ return NULL;
+ }
+ filename = allocptr
+ + (sizeof (struct areltdata) + sizeof (struct ar_hdr));
+ if (bfd_read (filename, 1, namelen, abfd) != namelen) {
+ bfd_error = no_more_archived_files;
+ return NULL;
+ }
+ filename[namelen] = '\0';
+ }
else
{
- /* We judge the end of the name by looking for a space or a
- padchar */
+ /* We judge the end of the name by looking for '/' or ' '.
+ Note: The SYSV format (terminated by '/') allows embedded
+ spaces, so only look for ' ' if we don't find '/'. */
namelen = 0;
-
- while (namelen < (unsigned)ar_maxnamelen(abfd) &&
- ( hdr.ar_name[namelen] != 0 &&
- hdr.ar_name[namelen] != ' ' &&
- hdr.ar_name[namelen] != ar_padchar(abfd))) {
+ while (hdr.ar_name[namelen] != '\0' &&
+ hdr.ar_name[namelen] != '/') {
namelen++;
+ if (namelen == (unsigned)ar_maxnamelen(abfd)) {
+ namelen = 0;
+ while (hdr.ar_name[namelen] != ' '
+ && namelen < (unsigned)ar_maxnamelen(abfd)) {
+ namelen++;
+ }
+ break;
+ }
}
allocsize += namelen + 1;
}
- allocptr = bfd_zalloc(abfd, allocsize);
- if (allocptr == NULL) {
+ if (!allocptr) {
+ allocptr = bfd_zalloc(abfd, allocsize);
+ if (allocptr == NULL) {
bfd_error = no_memory;
return NULL;
+ }
}
ared = (struct areltdata *) allocptr;
*/
bfd *
-get_elt_at_filepos (archive, filepos)
- bfd *archive;
- file_ptr filepos;
+DEFUN (get_elt_at_filepos, (archive, filepos),
+ bfd *archive AND
+ file_ptr filepos)
{
struct areltdata *new_areldata;
bfd *n_nfd;
filestart = bfd_ardata (archive)->first_file_filepos;
else {
unsigned int size = arelt_size(last_file);
- /* Pad to an even boundary... */
- filestart = last_file->origin + size + size%2;
+ /* Pad to an even boundary...
+ Note that last_file->origin can be odd in the case of
+ BSD-4.4-style element with a long odd size. */
+ filestart = last_file->origin + size;
+ filestart += filestart % 2;
}
return get_elt_at_filepos (archive, filestart);
}
/* Returns false on error, true otherwise */
-boolean
-bfd_slurp_bsd_armap (abfd)
- bfd *abfd;
+static boolean
+DEFUN (do_slurp_bsd_armap, (abfd),
+ bfd *abfd)
{
+ struct areltdata *mapdata;
+ unsigned int counter = 0;
+ int *raw_armap, *rbase;
+ struct artdata *ardata = bfd_ardata (abfd);
+ char *stringbase;
+ unsigned int parsed_size;
- struct areltdata *mapdata;
- char nextname[17];
- unsigned int counter = 0;
- int *raw_armap, *rbase;
- struct artdata *ardata = bfd_ardata (abfd);
- char *stringbase;
-
- /* FIXME, if the read fails, this routine quietly returns "true"!!
- It should probably do that if the read gives 0 bytes (empty archive),
- but fail for any other size... */
- if (bfd_read ((PTR)nextname, 1, 16, abfd) == 16) {
- /* The archive has at least 16 bytes in it */
- bfd_seek (abfd, -16L, SEEK_CUR);
-
- /* This should be using RANLIBMAG, but at least it can be grepped for
- in this comment. */
- if (strncmp (nextname, "__.SYMDEF ", 16)) {
- bfd_has_map (abfd) = false;
- return true;
- }
+ mapdata = snarf_ar_hdr (abfd);
+ if (mapdata == NULL) return false;
+ parsed_size = mapdata->parsed_size;
+ bfd_release (abfd, (PTR)mapdata); /* Don't need it any more. */
+
+ raw_armap = (int *) bfd_zalloc(abfd, parsed_size);
+ if (raw_armap == NULL) {
+ bfd_error = no_memory;
+ return false;
+ }
+
+ if (bfd_read ((PTR)raw_armap, 1, parsed_size, abfd) != parsed_size) {
+ bfd_error = malformed_archive;
+ byebye:
+ bfd_release (abfd, (PTR)raw_armap);
+ return false;
+ }
+
+ ardata->symdef_count =
+ bfd_h_get_32(abfd, (PTR)raw_armap) / sizeof (struct symdef);
+
+ if (ardata->symdef_count * sizeof (struct symdef)
+ > parsed_size - sizeof (*raw_armap)) {
+ /* Probably we're using the wrong byte ordering. */
+ bfd_error = wrong_format;
+ goto byebye;
+ }
+
+ ardata->cache = 0;
+ rbase = raw_armap+1;
+ ardata->symdefs = (carsym *) rbase;
+ stringbase = ((char *) (ardata->symdefs + ardata->symdef_count)) + 4;
+
+ for (;counter < ardata->symdef_count; counter++) {
+ struct symdef *sym = ((struct symdef *) rbase) + counter;
+ sym->s.name = bfd_h_get_32(abfd, (PTR)(&(sym->s.string_offset))) + stringbase;
+ sym->file_offset = bfd_h_get_32(abfd, (PTR)( &(sym->file_offset)));
+ }
+
+ ardata->first_file_filepos = bfd_tell (abfd);
+ /* Pad to an even boundary if you have to */
+ ardata->first_file_filepos += (ardata-> first_file_filepos) %2;
+ /* FIXME, we should provide some way to free raw_ardata when
+ we are done using the strings from it. For now, it seems
+ to be allocated on an obstack anyway... */
+ bfd_has_map (abfd) = true;
+ return true;
+}
- mapdata = snarf_ar_hdr (abfd);
- if (mapdata == NULL) return false;
+/* Returns false on error, true otherwise */
+static boolean
+DEFUN (do_slurp_coff_armap, (abfd),
+ bfd *abfd)
+{
+ struct areltdata *mapdata;
+ int *raw_armap, *rawptr;
+ struct artdata *ardata = bfd_ardata (abfd);
+ char *stringbase;
+ unsigned int stringsize;
+ unsigned int parsed_size;
+ carsym *carsyms;
+ unsigned int nsymz; /* Number of symbols in armap. */
- raw_armap = (int *) bfd_zalloc(abfd,mapdata->parsed_size);
- if (raw_armap == NULL) {
- bfd_error = no_memory;
- byebye:
- bfd_release (abfd, (PTR)mapdata);
- return false;
- }
+ bfd_vma (*swap) PARAMS ((bfd_byte*));
+ char int_buf[sizeof(long)];
+ unsigned int carsym_size, ptrsize, i;
+
+ mapdata = snarf_ar_hdr (abfd);
+ if (mapdata == NULL) return false;
+ parsed_size = mapdata->parsed_size;
+ bfd_release (abfd, (PTR)mapdata); /* Don't need it any more. */
- if (bfd_read ((PTR)raw_armap, 1, mapdata->parsed_size, abfd) !=
- mapdata->parsed_size) {
- bfd_error = malformed_archive;
- byebyebye:
- bfd_release (abfd, (PTR)raw_armap);
- goto byebye;
- }
+ if (bfd_read ((PTR)int_buf, 1, 4, abfd) != 4) {
+ bfd_error = malformed_archive;
+ return false;
+ }
+ /* It seems that all numeric information in a coff archive is always
+ in big endian format, nomatter the host or target. */
+ swap = bfd_getb32;
+ nsymz = bfd_getb32((PTR)int_buf);
+ stringsize = parsed_size - (4 * nsymz) - 4;
- ardata->symdef_count = bfd_h_get_32(abfd, (PTR)raw_armap) / sizeof (struct symdef);
+#if 1
+ /* ... except that some archive formats are broken, and it may be our
+ fault - the i960 little endian coff sometimes has big and sometimes
+ little, because our tools changed. Here's a horrible hack to clean
+ up the crap. */
+
+ if (stringsize > 0xfffff) {
+ /* This looks dangerous, let's do it the other way around */
+ nsymz = bfd_getl32((PTR)int_buf);
+ stringsize = parsed_size - (4 * nsymz) - 4;
+ swap = bfd_getl32;
+ }
+#endif
+
+ /* The coff armap must be read sequentially. So we construct a bsd-style
+ one in core all at once, for simplicity. */
+
+ carsym_size = (nsymz * sizeof (carsym));
+ ptrsize = (4 * nsymz);
- if (ardata->symdef_count * sizeof (struct symdef)
- > mapdata->parsed_size - sizeof (*raw_armap)) {
- /* Probably we're using the wrong byte ordering. */
- bfd_error = wrong_format;
- goto byebyebye;
- }
+ ardata->symdefs = (carsym *) bfd_zalloc(abfd, carsym_size + stringsize + 1);
+ if (ardata->symdefs == NULL) {
+ bfd_error = no_memory;
+ return false;
+ }
+ carsyms = ardata->symdefs;
+ stringbase = ((char *) ardata->symdefs) + carsym_size;
- ardata->cache = 0;
- rbase = raw_armap+1;
- ardata->symdefs = (carsym *) rbase;
- stringbase = ((char *) (ardata->symdefs + ardata->symdef_count)) + 4;
+ /* Allocate and read in the raw offsets. */
+ raw_armap = (int *) bfd_alloc(abfd, ptrsize);
+ if (raw_armap == NULL) {
+ bfd_error = no_memory;
+ goto release_symdefs;
+ }
+ if (bfd_read ((PTR)raw_armap, 1, ptrsize, abfd) != ptrsize
+ || bfd_read ((PTR)stringbase, 1, stringsize, abfd) != stringsize) {
+ bfd_error = malformed_archive;
+ goto release_raw_armap;
+ }
- for (;counter < ardata->symdef_count; counter++) {
- struct symdef *sym = ((struct symdef *) rbase) + counter;
- sym->s.name = bfd_h_get_32(abfd, (PTR)(&(sym->s.string_offset))) + stringbase;
- sym->file_offset = bfd_h_get_32(abfd, (PTR)( &(sym->file_offset)));
- }
-
- ardata->first_file_filepos = bfd_tell (abfd);
- /* Pad to an even boundary if you have to */
- ardata->first_file_filepos += (ardata-> first_file_filepos) %2;
- /* FIXME, we should provide some way to free raw_ardata when
- we are done using the strings from it. For now, it seems
- to be allocated on an obstack anyway... */
- bfd_has_map (abfd) = true;
- }
- return true;
+ /* OK, build the carsyms */
+ for (i = 0; i < nsymz; i++) {
+ rawptr = raw_armap + i;
+ carsyms->file_offset = swap((PTR)rawptr);
+ carsyms->name = stringbase;
+ while (*stringbase++) ;
+ carsyms++;
+ }
+ *stringbase = 0;
+
+ ardata->symdef_count = nsymz;
+ ardata->first_file_filepos = bfd_tell (abfd);
+ /* Pad to an even boundary if you have to */
+ ardata->first_file_filepos += (ardata->first_file_filepos) %2;
+
+ bfd_has_map (abfd) = true;
+ bfd_release (abfd, (PTR)raw_armap);
+ return true;
+
+ release_raw_armap:
+ bfd_release (abfd, (PTR)raw_armap);
+ release_symdefs:
+ bfd_release (abfd, (PTR)(ardata)->symdefs);
+ return false;
}
+/* This routine can handle either coff-style or bsd-style armaps.
+ Returns false on error, true otherwise */
+
+boolean
+bfd_slurp_armap (abfd)
+ bfd *abfd;
+{
+ char nextname[17];
+ int i = bfd_read ((PTR)nextname, 1, 16, abfd);
+
+ if (i == 0)
+ return true;
+ if (i != 16)
+ return false;
+
+ bfd_seek (abfd, (file_ptr) -16, SEEK_CUR);
+
+ if (!strncmp (nextname, "__.SYMDEF ", 16))
+ return do_slurp_bsd_armap (abfd);
+ else if (!strncmp (nextname, "/ ", 16))
+ return do_slurp_coff_armap (abfd);
+
+ bfd_has_map (abfd) = false;
+ return true;
+}
+\f
/* Returns false on error, true otherwise */
+/* flavor 2 of a bsd armap, similar to bfd_slurp_bsd_armap except the
+ header is in a slightly different order and the map name is '/'.
+ This flavour is used by hp300hpux. */
boolean
-bfd_slurp_coff_armap (abfd)
+bfd_slurp_bsd_armap_f2 (abfd)
bfd *abfd;
{
struct areltdata *mapdata;
- char nextname;
- int *raw_armap, *rawptr;
+ char nextname[17];
+ unsigned int counter = 0;
+ int *raw_armap, *rbase;
struct artdata *ardata = bfd_ardata (abfd);
char *stringbase;
unsigned int stringsize;
- carsym *carsyms;
- int result;
- bfd_vma (*swap)();
-
- result = bfd_read ((PTR)&nextname, 1, 1, abfd);
- bfd_seek (abfd, -1L, SEEK_CUR);
+ int i = bfd_read ((PTR)nextname, 1, 16, abfd);
- if (result != 1 || nextname != '/') {
- /* Actually I think this is an error for a COFF archive */
- bfd_has_map (abfd) = false;
+ if (i == 0)
return true;
- }
+ if (i != 16)
+ return false;
+
+ /* The archive has at least 16 bytes in it */
+ bfd_seek (abfd, -16L, SEEK_CUR);
+
+ if (!strncmp (nextname, "__.SYMDEF ", 16))
+ return do_slurp_bsd_armap (abfd);
+
+ if (strncmp (nextname, "/ ", 16))
+ {
+ bfd_has_map (abfd) = false;
+ return true;
+ }
mapdata = snarf_ar_hdr (abfd);
if (mapdata == NULL) return false;
- raw_armap = (int *) bfd_alloc(abfd,mapdata->parsed_size);
-
- if (raw_armap == NULL)
- {
- bfd_error = no_memory;
- byebye:
- bfd_release (abfd, (PTR)mapdata);
- return false;
- }
+ raw_armap = (int *) bfd_zalloc(abfd,mapdata->parsed_size);
+ if (raw_armap == NULL)
+ {
+ bfd_error = no_memory;
+ byebye:
+ bfd_release (abfd, (PTR)mapdata);
+ return false;
+ }
- /* read in the raw map */
if (bfd_read ((PTR)raw_armap, 1, mapdata->parsed_size, abfd) !=
- mapdata->parsed_size) {
- bfd_error = malformed_archive;
- oops:
- bfd_release (abfd, (PTR)raw_armap);
- goto byebye;
- }
+ mapdata->parsed_size)
+ {
+ bfd_error = malformed_archive;
+ byebyebye:
+ bfd_release (abfd, (PTR)raw_armap);
+ goto byebye;
+ }
- /* The coff armap must be read sequentially. So we construct a bsd-style
- one in core all at once, for simplicity.
-
- It seems that all numeric information in a coff archive is always
- in big endian format, nomatter the host or target. */
+ ardata->symdef_count = bfd_h_get_16(abfd, (PTR)raw_armap);
- stringsize
- = mapdata->parsed_size - (4 * (_do_getb32((PTR)raw_armap))) - 4;
- /* Except that some archive formats are broken, and it may be our
- fault - the i960 little endian coff sometimes has big and sometimes
- little, because our tools changed. Here's a horrible hack to clean
- up the crap
- */
- swap = _do_getb32;
-
- if (stringsize > 0xfffff)
- {
- /* This looks dangerous, let's do it the other way around */
- stringsize = mapdata->parsed_size - (4 *
- (_do_getl32((PTR)raw_armap))) - 4;
+ if (ardata->symdef_count * sizeof (struct symdef)
+ > mapdata->parsed_size - sizeof (*raw_armap))
+ {
+ /* Probably we're using the wrong byte ordering. */
+ bfd_error = wrong_format;
+ goto byebyebye;
+ }
- swap = _do_getl32;
- }
-
+ ardata->cache = 0;
+
+ stringsize = bfd_h_get_32(abfd, (PTR)(((char*)raw_armap)+2));
+ /* skip sym count and string sz */
+ rbase = (int*)(((char*)raw_armap) + 6);
+ stringbase = (char *) rbase;
+ ardata->symdefs = (carsym *)(((char*) rbase) + stringsize);
+
+ for (;counter < ardata->symdef_count; counter++)
+ {
+ struct symdef *sym = ((struct symdef *) ardata->symdefs) + counter;
+ sym->s.name = bfd_h_get_32(abfd, (PTR)(&(sym->s.string_offset))) + stringbase;
+ sym->file_offset = bfd_h_get_32(abfd, (PTR)( &(sym->file_offset)));
+ }
- {
- unsigned int nsymz = swap( (PTR)raw_armap);
- unsigned int carsym_size = (nsymz * sizeof (carsym));
- unsigned int ptrsize = (4 * nsymz);
- unsigned int i;
- ardata->symdefs = (carsym *) bfd_zalloc(abfd,carsym_size + stringsize + 1);
- if (ardata->symdefs == NULL) {
- bfd_error = no_memory;
- goto oops;
- }
- carsyms = ardata->symdefs;
-
- stringbase = ((char *) ardata->symdefs) + carsym_size;
- memcpy (stringbase, (char*)raw_armap + ptrsize + 4, stringsize);
-
-
- /* OK, build the carsyms */
- for (i = 0; i < nsymz; i++)
- {
- rawptr = raw_armap + i + 1;
- carsyms->file_offset = swap((PTR)rawptr);
- carsyms->name = stringbase;
- for (; *(stringbase++););
- carsyms++;
- }
- *stringbase = 0;
- }
- ardata->symdef_count = swap((PTR)raw_armap);
ardata->first_file_filepos = bfd_tell (abfd);
/* Pad to an even boundary if you have to */
- ardata->first_file_filepos += (ardata->first_file_filepos) %2;
-
- /* We'd like to release these allocations, but we have allocated stuff
- since then (using the same obstack, if bfd_release is obstack based).
- So they will stick around until the BFD is closed. */
- /* bfd_release (abfd, (PTR)raw_armap);
- bfd_release (abfd, (PTR)mapdata); */
+ ardata->first_file_filepos += (ardata-> first_file_filepos) %2;
+ /* FIXME, we should provide some way to free raw_ardata when
+ we are done using the strings from it. For now, it seems
+ to be allocated on an obstack anyway... */
bfd_has_map (abfd) = true;
return true;
}
we probably don't want to return true. */
if (bfd_read ((PTR)nextname, 1, 16, abfd) == 16) {
- bfd_seek (abfd, -16L, SEEK_CUR);
+ bfd_seek (abfd, (file_ptr) -16, SEEK_CUR);
if (strncmp (nextname, "ARFILENAMES/ ", 16) != 0 &&
strncmp (nextname, "// ", 16) != 0)
/* Since the archive is supposed to be printable if it contains
text, the entries in the list are newline-padded, not null
- padded. We'll fix that there.. */
+ padded. In SVR4-style archives, the names also have a
+ trailing '/'. We'll fix both problems here.. */
{
char *temp = bfd_ardata (abfd)->extended_names;
- for (; *temp != '\0'; ++temp)
- if (*temp == '\n') *temp = '\0';
+ char *limit = temp + namedata->parsed_size;
+ for (; temp < limit; ++temp)
+ if (*temp == '\n')
+ temp[temp[-1] == '/' ? -1 : 0] = '\0';
}
/* Pad to an even boundary if you have to */
}
- copy = malloc(last - first + 1);
+ copy = bfd_xmalloc(last - first + 1);
memcpy(copy, first, last-first);
copy[last-first] = 0;
}
#else
-static
-CONST char *normalize(file)
-CONST char *file;
+static CONST char *
+DEFUN (normalize, (file),
+ CONST char *file)
{
CONST char * filename = strrchr(file, '/');
A successful return may still involve a zero-length tablen!
*/
boolean
-bfd_construct_extended_name_table (abfd, tabloc, tablen)
- bfd *abfd;
- char **tabloc;
- unsigned int *tablen;
+DEFUN (bfd_construct_extended_name_table, (abfd, tabloc, tablen),
+ bfd *abfd AND
+ char **tabloc AND
+ unsigned int *tablen)
{
unsigned int maxname = abfd->xvec->ar_max_namelen;
unsigned int total_namelen = 0;
foo (ar_uid, st_uid, 10);
foo (ar_gid, st_gid, 10);
foo (ar_mode, st_mode, 8);
- foo (ar_size, st_size, 10);
+
+ buf->st_size = arch_eltdata (abfd)->parsed_size;
return 0;
}
}
\f
-PROTO (boolean, compute_and_write_armap, (bfd *arch, unsigned int elength));
-
/* The BFD is open for write and has its format set to bfd_archive */
boolean
_bfd_write_archive_contents (arch)
boolean makemap = bfd_has_map (arch);
boolean hasobjects = false; /* if no .o's, don't bother to make a map */
unsigned int i;
+ int tries;
/* Verify the viability of all entries; if any of them live in the
filesystem (as opposed to living in an archive open for input)
if (!bfd_construct_extended_name_table (arch, &etable, &elength))
return false;
- bfd_seek (arch, 0, SEEK_SET);
+ bfd_seek (arch, (file_ptr) 0, SEEK_SET);
#ifdef GNU960
bfd_write (BFD_GNU960_ARMAG(arch), 1, SARMAG, arch);
#else
bfd_error = system_call_error;
return false;
}
- if (bfd_seek (current, 0L, SEEK_SET) != 0L) goto syserr;
+ if (bfd_seek (current, (file_ptr) 0, SEEK_SET) != 0) goto syserr;
while (remaining)
{
unsigned int amt = DEFAULT_BUFFERSIZE;
}
if ((arelt_size (current) % 2) == 1) bfd_write ("\n", 1, 1, arch);
}
-return true;
+
+ /* Verify the timestamp in the archive file. If it would
+ not be accepted by the linker, rewrite it until it would be.
+ If anything odd happens, break out and just return.
+ (The Berkeley linker checks the timestamp and refuses to read the
+ table-of-contents if it is >60 seconds less than the file's
+ modified-time. That painful hack requires this painful hack. */
+
+ tries = 1;
+ do {
+ /* FIXME! This kludge is to avoid adding a member to the xvec,
+ while generating a small patch for Adobe. FIXME! The
+ update_armap_timestamp function call should be in the xvec,
+ thus:
+
+ if (bfd_update_armap_timestamp (arch) == true) break;
+ ^
+
+ Instead, we check whether in a BSD archive, and call directly. */
+
+ if (arch->xvec->write_armap != bsd_write_armap)
+ break;
+ if (bsd_update_armap_timestamp(arch) == true) /* FIXME!!! Vector it */
+ break;
+ if (tries > 0)
+ fprintf (stderr,
+ "Warning: writing archive was slow: rewriting timestamp\n");
+ } while (++tries < 6 );
+
+ return true;
}
\f
/* Note that the namidx for the first symbol is 0 */
asection *sec =
syms[src_count]->section;
- if ((flags & BSF_GLOBAL) ||
- (flags & BSF_INDIRECT) ||
- (sec == &bfd_com_section)) {
+ if ((flags & BSF_GLOBAL ||
+ flags & BSF_INDIRECT ||
+ bfd_is_com_section (sec))
+ && (sec != &bfd_und_section)) {
/* This symbol will go into the archive header */
if (orl_count == orl_max)
stat (arch->filename, &statbuf);
memset ((char *)(&hdr), 0, sizeof (struct ar_hdr));
sprintf (hdr.ar_name, RANLIBMAG);
-
- /* write the timestamp of the archive header to be just a little bit
- later than the timestamp of the file, otherwise the linker will
- complain that the index is out of date.
- */
-
- sprintf (hdr.ar_date, "%ld", statbuf.st_mtime + 60);
+ /* Remember the timestamp, to keep it holy. But fudge it a little. */
+ bfd_ardata(arch)->armap_timestamp = statbuf.st_mtime + ARMAP_TIME_OFFSET;
+ bfd_ardata(arch)->armap_datepos = SARMAG + offsetof(struct ar_hdr, ar_date);
+ sprintf (hdr.ar_date, "%ld", bfd_ardata(arch)->armap_timestamp);
sprintf (hdr.ar_uid, "%d", getuid());
sprintf (hdr.ar_gid, "%d", getgid());
sprintf (hdr.ar_size, "%-10d", (int) mapsize);
for (i = 0; i < sizeof (struct ar_hdr); i++)
if (((char *)(&hdr))[i] == '\0') (((char *)(&hdr))[i]) = ' ';
bfd_write ((char *)&hdr, 1, sizeof (struct ar_hdr), arch);
- bfd_h_put_32(arch, ranlibsize, (PTR)&temp);
+ bfd_h_put_32(arch, (bfd_vma) ranlibsize, (PTR)&temp);
bfd_write (&temp, 1, sizeof (temp), arch);
for (count = 0; count < orl_count; count++) {
return true;
}
+
+
+/* At the end of archive file handling, update the timestamp in the
+ file, so the linker will accept it.
+
+ Return true if the timestamp was OK, or an unusual problem happened.
+ Return false if we updated the timestamp. */
+
+static boolean
+bsd_update_armap_timestamp (arch)
+ bfd *arch;
+{
+ struct stat archstat;
+ struct ar_hdr hdr;
+ int i;
+
+ /* Flush writes, get last-write timestamp from file, and compare it
+ to the timestamp IN the file. */
+ bfd_flush (arch);
+ if (bfd_stat (arch, &archstat) == -1) {
+ perror ("Reading archive file mod timestamp");
+ return true; /* Can't read mod time for some reason */
+ }
+ if (archstat.st_mtime <= bfd_ardata(arch)->armap_timestamp)
+ return true; /* OK by the linker's rules */
+
+ /* Update the timestamp. */
+ bfd_ardata(arch)->armap_timestamp = archstat.st_mtime + ARMAP_TIME_OFFSET;
+
+ /* Prepare an ASCII version suitable for writing. */
+ memset (hdr.ar_date, 0, sizeof (hdr.ar_date));
+ sprintf (hdr.ar_date, "%ld", bfd_ardata(arch)->armap_timestamp);
+ for (i = 0; i < sizeof (hdr.ar_date); i++)
+ if (hdr.ar_date[i] == '\0')
+ (hdr.ar_date)[i] = ' ';
+
+ /* Write it into the file. */
+ bfd_seek (arch, bfd_ardata(arch)->armap_datepos, SEEK_SET);
+ if (bfd_write (hdr.ar_date, sizeof(hdr.ar_date), 1, arch)
+ != sizeof(hdr.ar_date)) {
+ perror ("Writing updated armap timestamp");
+ return true; /* Some error while writing */
+ }
+
+ return false; /* We updated the timestamp successfully. */
+}
\f
/* A coff armap looks like :