/* BFD back-end for archive files (libraries).
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
Written by Cygnus Support. Mostly Gumby Henkel-Wallace's fault.
BSD 4.4 uses a third scheme: It writes a long filename
directly after the header. This allows 'ar q' to work.
- We currently can read BSD 4.4 archives, but not write them.
*/
/* Summary of archive member names:
"/18 " - SVR4 style, name at offset 18 in name table.
"#1/23 " - Long name (or embedded spaces) 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.
*/
#define arch_eltdata(bfd) ((struct areltdata *) ((bfd)->arelt_data))
#define arch_hdr(bfd) ((struct ar_hdr *) arch_eltdata (bfd)->arch_header)
+
+/* True iff NAME designated a BSD 4.4 extended name. */
+
+#define is_bsd44_extended_name(NAME) \
+ (NAME[0] == '#' && NAME[1] == '1' && NAME[2] == '/' && ISDIGIT (NAME[3]))
\f
void
_bfd_ar_spacepad (char *p, size_t n, const char *fmt, long val)
{
bfd_size_type amt = sizeof (struct artdata);
- abfd->tdata.aout_ar_data = bfd_zalloc (abfd, amt);
+ abfd->tdata.aout_ar_data = (struct artdata *) bfd_zalloc (abfd, amt);
if (bfd_ardata (abfd) == NULL)
return FALSE;
return arc1->ptr == arc2->ptr;
}
+/* The calloc function doesn't always take size_t (e.g. on VMS)
+ so wrap it to avoid a compile time warning. */
+
+static void *
+_bfd_calloc_wrapper (size_t a, size_t b)
+{
+ return calloc (a, b);
+}
+
/* Kind of stupid to call cons for each one, but we don't do too many. */
bfd_boolean
if (hash_table == NULL)
{
hash_table = htab_create_alloc (16, hash_file_ptr, eq_file_ptr,
- NULL, calloc, free);
+ NULL, _bfd_calloc_wrapper, free);
if (hash_table == NULL)
return FALSE;
bfd_ardata (arch_bfd)->cache = hash_table;
}
/* Insert new_elt into the hash table by filepos. */
- cache = bfd_zalloc (arch_bfd, sizeof (struct ar_cache));
+ cache = (struct ar_cache *) bfd_zalloc (arch_bfd, sizeof (struct ar_cache));
cache->ptr = filepos;
cache->arbfd = new_elt;
*htab_find_slot (hash_table, (const void *) cache, INSERT) = cache;
abfd != NULL;
abfd = abfd->archive_next)
{
- if (strcmp (filename, abfd->filename) == 0)
+ if (filename_cmp (filename, abfd->filename) == 0)
return abfd;
}
abfd = bfd_openr (filename, NULL);
static char *
get_extended_arelt_filename (bfd *arch, const char *name, file_ptr *originp)
{
- unsigned long index = 0;
+ unsigned long table_index = 0;
const char *endp;
/* Should extract string so that I can guarantee not to overflow into
the next region, but I'm too lazy. */
errno = 0;
/* Skip first char, which is '/' in SVR4 or ' ' in some other variants. */
- index = strtol (name + 1, (char **) &endp, 10);
- if (errno != 0 || index >= bfd_ardata (arch)->extended_names_size)
+ table_index = strtol (name + 1, (char **) &endp, 10);
+ if (errno != 0 || table_index >= bfd_ardata (arch)->extended_names_size)
{
bfd_set_error (bfd_error_malformed_archive);
return NULL;
{
file_ptr origin = strtol (endp + 1, NULL, 10);
- if (errno != 0 || index >= bfd_ardata (arch)->extended_names_size)
+ if (errno != 0)
{
bfd_set_error (bfd_error_malformed_archive);
return NULL;
else
*originp = 0;
- return bfd_ardata (arch)->extended_names + index;
+ return bfd_ardata (arch)->extended_names + table_index;
}
/* This functions reads an arch header and returns an areltdata pointer, or
bfd_size_type allocsize = sizeof (struct areltdata) + sizeof (struct ar_hdr);
char *allocptr = 0;
file_ptr origin = 0;
+ unsigned int extra_size = 0;
if (bfd_bread (hdrp, sizeof (struct ar_hdr), abfd) != sizeof (struct ar_hdr))
{
if (filename == NULL)
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]))
+ /* BSD4.4-style long filename. */
+ else if (is_bsd44_extended_name (hdr.ar_name))
{
/* BSD-4.4 extended name */
namelen = atoi (&hdr.ar_name[3]);
allocsize += namelen + 1;
parsed_size -= namelen;
+ extra_size = namelen;
- allocptr = bfd_zalloc (abfd, allocsize);
+ allocptr = (char *) bfd_zalloc (abfd, allocsize);
if (allocptr == NULL)
return NULL;
filename = (allocptr
spaces, so only look for ' ' if we don't find '/'. */
char *e;
- e = memchr (hdr.ar_name, '\0', ar_maxnamelen (abfd));
+ e = (char *) memchr (hdr.ar_name, '\0', ar_maxnamelen (abfd));
if (e == NULL)
{
- e = memchr (hdr.ar_name, '/', ar_maxnamelen (abfd));
+ e = (char *) memchr (hdr.ar_name, '/', ar_maxnamelen (abfd));
if (e == NULL)
- e = memchr (hdr.ar_name, ' ', ar_maxnamelen (abfd));
+ e = (char *) memchr (hdr.ar_name, ' ', ar_maxnamelen (abfd));
}
if (e != NULL)
if (!allocptr)
{
- allocptr = bfd_zalloc (abfd, allocsize);
+ allocptr = (char *) bfd_zalloc (abfd, allocsize);
if (allocptr == NULL)
return NULL;
}
ared->arch_header = allocptr + sizeof (struct areltdata);
memcpy (ared->arch_header, &hdr, sizeof (struct ar_hdr));
ared->parsed_size = parsed_size;
+ ared->extra_size = extra_size;
ared->origin = origin;
if (filename != NULL)
/* Append the relative pathname for a member of the thin archive
to the pathname of the directory containing the archive. */
-static char *
-append_relative_path (bfd *arch, char *elt_name)
+char *
+_bfd_append_relative_path (bfd *arch, char *elt_name)
{
const char *arch_name = arch->filename;
const char *base_name = lbasename (arch_name);
return elt_name;
prefix_len = base_name - arch_name;
- filename = bfd_alloc (arch, prefix_len + strlen (elt_name) + 1);
+ filename = (char *) bfd_alloc (arch, prefix_len + strlen (elt_name) + 1);
if (filename == NULL)
return NULL;
if (0 > bfd_seek (archive, filepos, SEEK_SET))
return NULL;
- if ((new_areldata = _bfd_read_ar_hdr (archive)) == NULL)
+ if ((new_areldata = (struct areltdata *) _bfd_read_ar_hdr (archive)) == NULL)
return NULL;
filename = new_areldata->filename;
/* This is a proxy entry for an external file. */
if (! IS_ABSOLUTE_PATH (filename))
{
- filename = append_relative_path (archive, filename);
+ filename = _bfd_append_relative_path (archive, filename);
if (filename == NULL)
return NULL;
}
/* It's not an element of a nested archive;
open the external file as a bfd. */
n_nfd = bfd_openr (filename, NULL);
+ if (n_nfd == NULL)
+ bfd_set_error (bfd_error_malformed_archive);
}
else
{
n_nfd->arelt_data = new_areldata;
+ /* Copy BFD_COMPRESS and BFD_DECOMPRESS flags. */
+ n_nfd->flags |= archive->flags & (BFD_COMPRESS | BFD_DECOMPRESS);
+
if (_bfd_add_bfd_to_archive_cache (archive, filepos, n_nfd))
return n_nfd;
- /* Huh? */
- /* FIXME: n_nfd isn't allocated in the archive's memory pool.
- If we reach this point, I think bfd_release will abort. */
- bfd_release (archive, n_nfd);
bfd_release (archive, new_areldata);
return NULL;
}
/* Return the BFD which is referenced by the symbol in ABFD indexed by
- INDEX. INDEX should have been returned by bfd_get_next_mapent. */
+ SYM_INDEX. SYM_INDEX should have been returned by bfd_get_next_mapent. */
bfd *
-_bfd_generic_get_elt_at_index (bfd *abfd, symindex index)
+_bfd_generic_get_elt_at_index (bfd *abfd, symindex sym_index)
{
carsym *entry;
- entry = bfd_ardata (abfd)->symdefs + index;
+ entry = bfd_ardata (abfd)->symdefs + sym_index;
return _bfd_get_elt_at_filepos (abfd, entry->file_offset);
}
else
{
unsigned int size = arelt_size (last_file);
+
filestart = last_file->proxy_origin;
if (! bfd_is_thin_archive (archive))
filestart += size;
if (strncmp (armag, ARMAG, SARMAG) != 0
&& strncmp (armag, ARMAGB, SARMAG) != 0
&& ! bfd_is_thin_archive (abfd))
- return 0;
+ return NULL;
tdata_hold = bfd_ardata (abfd);
amt = sizeof (struct artdata);
- bfd_ardata (abfd) = bfd_zalloc (abfd, amt);
+ bfd_ardata (abfd) = (struct artdata *) bfd_zalloc (abfd, amt);
if (bfd_ardata (abfd) == NULL)
{
bfd_ardata (abfd) = tdata_hold;
bfd_size_type parsed_size, amt;
carsym *set;
- mapdata = _bfd_read_ar_hdr (abfd);
+ mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd);
if (mapdata == NULL)
return FALSE;
parsed_size = mapdata->parsed_size;
bfd_release (abfd, mapdata); /* Don't need it any more. */
- raw_armap = bfd_zalloc (abfd, parsed_size);
+ raw_armap = (bfd_byte *) bfd_zalloc (abfd, parsed_size);
if (raw_armap == NULL)
return FALSE;
+ ardata->symdef_count * BSD_SYMDEF_SIZE
+ BSD_STRING_COUNT_SIZE);
amt = ardata->symdef_count * sizeof (carsym);
- ardata->symdefs = bfd_alloc (abfd, amt);
+ ardata->symdefs = (struct carsym *) bfd_alloc (abfd, amt);
if (!ardata->symdefs)
return FALSE;
bfd_size_type carsym_size, ptrsize;
unsigned int i;
- mapdata = _bfd_read_ar_hdr (abfd);
+ mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd);
if (mapdata == NULL)
return FALSE;
parsed_size = mapdata->parsed_size;
if (carsym_size + stringsize + 1 <= carsym_size)
return FALSE;
- ardata->symdefs = bfd_zalloc (abfd, carsym_size + stringsize + 1);
+ ardata->symdefs = (struct carsym *) bfd_zalloc (abfd,
+ carsym_size + stringsize + 1);
if (ardata->symdefs == NULL)
return FALSE;
carsyms = ardata->symdefs;
stringbase = ((char *) ardata->symdefs) + carsym_size;
/* Allocate and read in the raw offsets. */
- raw_armap = bfd_alloc (abfd, ptrsize);
+ raw_armap = (int *) bfd_alloc (abfd, ptrsize);
if (raw_armap == NULL)
goto release_symdefs;
if (bfd_bread (raw_armap, ptrsize, abfd) != ptrsize
struct areltdata *tmp;
bfd_seek (abfd, ardata->first_file_filepos, SEEK_SET);
- tmp = _bfd_read_ar_hdr (abfd);
+ tmp = (struct areltdata *) _bfd_read_ar_hdr (abfd);
if (tmp != NULL)
{
if (tmp->arch_header[0] == '/'
return FALSE;
#endif
}
+ else if (CONST_STRNEQ (nextname, "#1/20 "))
+ {
+ /* Mach-O has a special name for armap when the map is sorted by name.
+ However because this name has a space it is slightly more difficult
+ to check it. */
+ struct ar_hdr hdr;
+ char extname[21];
+
+ if (bfd_bread (&hdr, sizeof (hdr), abfd) != sizeof (hdr))
+ return FALSE;
+ /* Read the extended name. We know its length. */
+ if (bfd_bread (extname, 20, abfd) != 20)
+ return FALSE;
+ if (bfd_seek (abfd, (file_ptr) -(sizeof (hdr) + 20), SEEK_CUR) != 0)
+ return FALSE;
+ if (CONST_STRNEQ (extname, "__.SYMDEF SORTED")
+ || CONST_STRNEQ (extname, "__.SYMDEF"))
+ return do_slurp_bsd_armap (abfd);
+ }
bfd_has_map (abfd) = FALSE;
return TRUE;
struct artdata *ardata = bfd_ardata (abfd);
char *stringbase;
unsigned int stringsize;
+ unsigned int left;
bfd_size_type amt;
carsym *set;
int i = bfd_bread (nextname, 16, abfd);
return TRUE;
}
- mapdata = _bfd_read_ar_hdr (abfd);
+ mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd);
if (mapdata == NULL)
return FALSE;
- amt = mapdata->parsed_size;
- raw_armap = bfd_zalloc (abfd, amt);
- if (raw_armap == NULL)
+ if (mapdata->parsed_size < HPUX_SYMDEF_COUNT_SIZE + BSD_STRING_COUNT_SIZE)
{
+ wrong_format:
+ bfd_set_error (bfd_error_wrong_format);
byebye:
bfd_release (abfd, mapdata);
return FALSE;
}
+ left = mapdata->parsed_size - HPUX_SYMDEF_COUNT_SIZE - BSD_STRING_COUNT_SIZE;
+
+ amt = mapdata->parsed_size;
+ raw_armap = (bfd_byte *) bfd_zalloc (abfd, amt);
+ if (raw_armap == NULL)
+ goto byebye;
if (bfd_bread (raw_armap, amt, abfd) != amt)
{
if (bfd_get_error () != bfd_error_system_call)
bfd_set_error (bfd_error_malformed_archive);
- byebyebye:
- bfd_release (abfd, raw_armap);
goto byebye;
}
ardata->symdef_count = H_GET_16 (abfd, raw_armap);
- if (ardata->symdef_count * BSD_SYMDEF_SIZE
- > mapdata->parsed_size - HPUX_SYMDEF_COUNT_SIZE)
- {
- /* Probably we're using the wrong byte ordering. */
- bfd_set_error (bfd_error_wrong_format);
- goto byebyebye;
- }
-
ardata->cache = 0;
stringsize = H_GET_32 (abfd, raw_armap + HPUX_SYMDEF_COUNT_SIZE);
+ if (stringsize > left)
+ goto wrong_format;
+ left -= stringsize;
+
/* Skip sym count and string sz. */
stringbase = ((char *) raw_armap
+ HPUX_SYMDEF_COUNT_SIZE
+ BSD_STRING_COUNT_SIZE);
rbase = (bfd_byte *) stringbase + stringsize;
amt = ardata->symdef_count * BSD_SYMDEF_SIZE;
- ardata->symdefs = bfd_alloc (abfd, amt);
+ if (amt > left)
+ goto wrong_format;
+
+ ardata->symdefs = (struct carsym *) bfd_alloc (abfd, amt);
if (!ardata->symdefs)
return FALSE;
/* FIXME: Formatting sucks here, and in case of failure of BFD_READ,
we probably don't want to return TRUE. */
- bfd_seek (abfd, bfd_ardata (abfd)->first_file_filepos, SEEK_SET);
+ if (bfd_seek (abfd, bfd_ardata (abfd)->first_file_filepos, SEEK_SET) != 0)
+ return FALSE;
+
if (bfd_bread (nextname, 16, abfd) == 16)
{
if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0)
return TRUE;
}
- namedata = _bfd_read_ar_hdr (abfd);
+ namedata = (struct areltdata *) _bfd_read_ar_hdr (abfd);
if (namedata == NULL)
return FALSE;
goto byebye;
bfd_ardata (abfd)->extended_names_size = amt;
- bfd_ardata (abfd)->extended_names = bfd_zalloc (abfd, amt + 1);
+ bfd_ardata (abfd)->extended_names = (char *) bfd_zalloc (abfd, amt + 1);
if (bfd_ardata (abfd)->extended_names == NULL)
{
byebye:
static const char *
normalize (bfd *abfd ATTRIBUTE_UNUSED, const char *file)
{
- const char *filename = strrchr (file, '/');
-
-#ifdef HAVE_DOS_BASED_FILE_SYSTEM
- {
- /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */
- char *bslash = strrchr (file, '\\');
- if (filename == NULL || (bslash != NULL && bslash > filename))
- filename = bslash;
- if (filename == NULL && file[0] != '\0' && file[1] == ':')
- filename = file + 1;
- }
-#endif
- if (filename != NULL)
- filename++;
- else
- filename = file;
- return filename;
+ return lbasename (file);
}
#endif
-/* Adjust a relative path name based on the reference path. */
-
+/* Adjust a relative path name based on the reference path.
+ For example:
+
+ Relative path Reference path Result
+ ------------- -------------- ------
+ bar.o lib.a bar.o
+ foo/bar.o lib.a foo/bar.o
+ bar.o foo/lib.a ../bar.o
+ foo/bar.o baz/lib.a ../foo/bar.o
+ bar.o ../lib.a <parent of current dir>/bar.o
+ ; ../bar.o ../lib.a bar.o
+ ; ../bar.o lib.a ../bar.o
+ foo/bar.o ../lib.a <parent of current dir>/foo/bar.o
+ bar.o ../../lib.a <grandparent>/<parent>/bar.o
+ bar.o foo/baz/lib.a ../../bar.o
+
+ Note - the semicolons above are there to prevent the BFD chew
+ utility from interpreting those lines as prototypes to put into
+ the autogenerated bfd.h header...
+
+ Note - the string is returned in a static buffer. */
+
static const char *
adjust_relative_path (const char * path, const char * ref_path)
{
static char *pathbuf = NULL;
- static int pathbuf_len = 0;
- const char *pathp = path;
- const char *refp = ref_path;
- int element_count = 0;
- int len;
+ static unsigned int pathbuf_len = 0;
+ const char *pathp;
+ const char *refp;
+ char * lpath;
+ char * rpath;
+ unsigned int len;
+ unsigned int dir_up = 0;
+ unsigned int dir_down = 0;
char *newp;
+ char * pwd = getpwd ();
+ const char * down;
+
+ /* Remove symlinks, '.' and '..' from the paths, if possible. */
+ lpath = lrealpath (path);
+ pathp = lpath == NULL ? path : lpath;
+ rpath = lrealpath (ref_path);
+ refp = rpath == NULL ? ref_path : rpath;
+
/* Remove common leading path elements. */
for (;;)
{
while (*e2 && ! IS_DIR_SEPARATOR (*e2))
++e2;
if (*e1 == '\0' || *e2 == '\0' || e1 - pathp != e2 - refp
- || strncmp (pathp, refp, e1 - pathp) != 0)
+ || filename_ncmp (pathp, refp, e1 - pathp) != 0)
break;
pathp = e1 + 1;
refp = e2 + 1;
}
+ len = strlen (pathp) + 1;
/* For each leading path element in the reference path,
insert "../" into the path. */
for (; *refp; ++refp)
if (IS_DIR_SEPARATOR (*refp))
- ++element_count;
- len = 3 * element_count + strlen (path) + 1;
+ {
+ /* PR 12710: If the path element is "../" then instead of
+ inserting "../" we need to insert the name of the directory
+ at the current level. */
+ if (refp > ref_path + 1
+ && refp[-1] == '.'
+ && refp[-2] == '.')
+ dir_down ++;
+ else
+ dir_up ++;
+ }
+
+ /* If the lrealpath calls above succeeded then we should never
+ see dir_up and dir_down both being non-zero. */
+
+ len += 3 * dir_up;
+
+ if (dir_down)
+ {
+ down = pwd + strlen (pwd) - 1;
+
+ while (dir_down && down > pwd)
+ {
+ if (IS_DIR_SEPARATOR (*down))
+ --dir_down;
+ }
+ BFD_ASSERT (dir_down == 0);
+ len += strlen (down) + 1;
+ }
+ else
+ down = NULL;
if (len > pathbuf_len)
{
if (pathbuf != NULL)
free (pathbuf);
pathbuf_len = 0;
- pathbuf = bfd_malloc (len);
+ pathbuf = (char *) bfd_malloc (len);
if (pathbuf == NULL)
- return path;
+ goto out;
pathbuf_len = len;
}
newp = pathbuf;
- while (element_count-- > 0)
+ while (dir_up-- > 0)
{
/* FIXME: Support Windows style path separators as well. */
strcpy (newp, "../");
newp += 3;
}
- strcpy (newp, pathp);
+ if (down)
+ sprintf (newp, "%s/%s", down, pathp);
+ else
+ strcpy (newp, pathp);
+
+ out:
+ free (lpath);
+ free (rpath);
return pathbuf;
}
/* If the path is the same as the previous path seen,
reuse it. This can happen when flattening a thin
archive that contains other archives. */
- if (last_filename && strcmp (last_filename, filename) == 0)
+ if (last_filename && filename_cmp (last_filename, filename) == 0)
continue;
last_filename = filename;
else
{
struct ar_hdr *hdr = arch_hdr (current);
- if (strncmp (normal, hdr->ar_name, thislen) != 0
+ if (filename_ncmp (normal, hdr->ar_name, thislen) != 0
|| (thislen < sizeof hdr->ar_name
&& hdr->ar_name[thislen] != ar_padchar (current)))
{
if (total_namelen == 0)
return TRUE;
- *tabloc = bfd_zalloc (abfd, total_namelen);
+ *tabloc = (char *) bfd_zalloc (abfd, total_namelen);
if (*tabloc == NULL)
return FALSE;
archive that contains other archives.
If the path is relative, adjust it relative to
the containing archive. */
- if (last_filename && strcmp (last_filename, filename) == 0)
+ if (last_filename && filename_cmp (last_filename, filename) == 0)
normal = last_filename;
else if (! IS_ABSOLUTE_PATH (filename)
&& ! IS_ABSOLUTE_PATH (abfd->filename))
return TRUE;
}
+
+/* Do not construct an extended name table but transforms name field into
+ its extended form. */
+
+bfd_boolean
+_bfd_archive_bsd44_construct_extended_name_table (bfd *abfd,
+ char **tabloc,
+ bfd_size_type *tablen,
+ const char **name)
+{
+ unsigned int maxname = abfd->xvec->ar_max_namelen;
+ bfd *current;
+
+ *tablen = 0;
+ *tabloc = NULL;
+ *name = NULL;
+
+ for (current = abfd->archive_head;
+ current != NULL;
+ current = current->archive_next)
+ {
+ const char *normal = normalize (current, current->filename);
+ int has_space = 0;
+ unsigned int len;
+
+ if (normal == NULL)
+ return FALSE;
+
+ for (len = 0; normal[len]; len++)
+ if (normal[len] == ' ')
+ has_space = 1;
+
+ if (len > maxname || has_space)
+ {
+ struct ar_hdr *hdr = arch_hdr (current);
+
+ len = (len + 3) & ~3;
+ arch_eltdata (current)->extra_size = len;
+ _bfd_ar_spacepad (hdr->ar_name, maxname, "#1/%lu", len);
+ }
+ }
+
+ return TRUE;
+}
+\f
+/* Write an archive header. */
+
+bfd_boolean
+_bfd_generic_write_ar_hdr (bfd *archive, bfd *abfd)
+{
+ struct ar_hdr *hdr = arch_hdr (abfd);
+
+ if (bfd_bwrite (hdr, sizeof (*hdr), archive) != sizeof (*hdr))
+ return FALSE;
+ return TRUE;
+}
+
+/* Write an archive header using BSD4.4 convention. */
+
+bfd_boolean
+_bfd_bsd44_write_ar_hdr (bfd *archive, bfd *abfd)
+{
+ struct ar_hdr *hdr = arch_hdr (abfd);
+
+ if (is_bsd44_extended_name (hdr->ar_name))
+ {
+ /* This is a BSD 4.4 extended name. */
+ const char *fullname = normalize (abfd, abfd->filename);
+ unsigned int len = strlen (fullname);
+ unsigned int padded_len = (len + 3) & ~3;
+
+ BFD_ASSERT (padded_len == arch_eltdata (abfd)->extra_size);
+
+ _bfd_ar_spacepad (hdr->ar_size, sizeof (hdr->ar_size), "%-10ld",
+ arch_eltdata (abfd)->parsed_size + padded_len);
+
+ if (bfd_bwrite (hdr, sizeof (*hdr), archive) != sizeof (*hdr))
+ return FALSE;
+
+ if (bfd_bwrite (fullname, len, archive) != len)
+ return FALSE;
+ if (len & 3)
+ {
+ static const char pad[3] = { 0, 0, 0 };
+
+ len = 4 - (len & 3);
+ if (bfd_bwrite (pad, len, archive) != len)
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (bfd_bwrite (hdr, sizeof (*hdr), archive) != sizeof (*hdr))
+ return FALSE;
+ }
+ return TRUE;
+}
\f
/* A couple of functions for creating ar_hdrs. */
if (member && (member->flags & BFD_IN_MEMORY) != 0)
{
/* Assume we just "made" the member, and fake it. */
- struct bfd_in_memory *bim = member->iostream;
+ struct bfd_in_memory *bim = (struct bfd_in_memory *) member->iostream;
time (&status.st_mtime);
status.st_uid = getuid ();
status.st_gid = getgid ();
return NULL;
}
+ /* If the caller requested that the BFD generate deterministic output,
+ fake values for modification time, UID, GID, and file mode. */
+ if ((abfd->flags & BFD_DETERMINISTIC_OUTPUT) != 0)
+ {
+ status.st_mtime = 0;
+ status.st_uid = 0;
+ status.st_gid = 0;
+ status.st_mode = 0644;
+ }
+
amt = sizeof (struct ar_hdr) + sizeof (struct areltdata);
- ared = bfd_zalloc (abfd, amt);
+ ared = (struct areltdata *) bfd_zalloc (abfd, amt);
if (ared == NULL)
return NULL;
hdr = (struct ar_hdr *) (((char *) ared) + sizeof (struct areltdata));
return ared;
}
-/* This is magic required by the "ar" program. Since it's
- undocumented, it's undocumented. You may think that it would take
- a strong stomach to write this, and it does, but it takes even a
- stronger stomach to try to code around such a thing! */
-
-struct ar_hdr *bfd_special_undocumented_glue (bfd *, const char *);
-
-struct ar_hdr *
-bfd_special_undocumented_glue (bfd *abfd, const char *filename)
-{
- struct areltdata *ar_elt = bfd_ar_hdr_from_filesystem (abfd, filename, 0);
- if (ar_elt == NULL)
- return NULL;
- return (struct ar_hdr *) ar_elt->arch_header;
-}
-
/* Analogous to stat call. */
int
{
struct ar_hdr *hdr = (struct ar_hdr *) arhdr;
size_t length;
- const char *filename = strrchr (pathname, '/');
+ const char *filename = lbasename (pathname);
size_t maxlen = ar_maxnamelen (abfd);
-#ifdef HAVE_DOS_BASED_FILE_SYSTEM
- {
- /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */
- char *bslash = strrchr (pathname, '\\');
- if (filename == NULL || (bslash != NULL && bslash > filename))
- filename = bslash;
- if (filename == NULL && pathname[0] != '\0' && pathname[1] == ':')
- filename = pathname + 1;
- }
-#endif
-
- if (filename == NULL)
- filename = pathname;
- else
- ++filename;
-
length = strlen (filename);
if (length <= maxlen)
{
struct ar_hdr *hdr = (struct ar_hdr *) arhdr;
size_t length;
- const char *filename = strrchr (pathname, '/');
+ const char *filename = lbasename (pathname);
size_t maxlen = ar_maxnamelen (abfd);
-#ifdef HAVE_DOS_BASED_FILE_SYSTEM
- {
- /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */
- char *bslash = strrchr (pathname, '\\');
-
- if (filename == NULL || (bslash != NULL && bslash > filename))
- filename = bslash;
- if (filename == NULL && pathname[0] != '\0' && pathname[1] == ':')
- filename = pathname + 1;
- }
-#endif
-
- if (filename == NULL)
- filename = pathname;
- else
- ++filename;
-
length = strlen (filename);
if (length <= maxlen)
{
char buffer[DEFAULT_BUFFERSIZE];
unsigned int remaining = arelt_size (current);
- struct ar_hdr *hdr = arch_hdr (current);
/* Write ar header. */
- if (bfd_bwrite (hdr, sizeof (*hdr), arch)
- != sizeof (*hdr))
- return FALSE;
+ if (!_bfd_write_ar_hdr (arch, current))
+ return FALSE;
if (bfd_is_thin_archive (arch))
continue;
if (bfd_seek (current, (file_ptr) 0, SEEK_SET) != 0)
elength += elength % 2;
amt = orl_max * sizeof (struct orl);
- map = bfd_malloc (amt);
+ map = (struct orl *) bfd_malloc (amt);
if (map == NULL)
goto error_return;
/* We put the symbol names on the arch objalloc, and then discard
them when done. */
- first_name = bfd_alloc (arch, 1);
+ first_name = (char *) bfd_alloc (arch, 1);
if (first_name == NULL)
goto error_return;
if (syms_max > 0)
free (syms);
syms_max = storage;
- syms = bfd_malloc (syms_max);
+ syms = (asymbol **) bfd_malloc (syms_max);
if (syms == NULL)
goto error_return;
}
if ((flags & BSF_GLOBAL
|| flags & BSF_WEAK
|| flags & BSF_INDIRECT
+ || flags & BSF_GNU_UNIQUE
|| bfd_is_com_section (sec))
&& ! bfd_is_und_section (sec))
{
{
orl_max *= 2;
amt = orl_max * sizeof (struct orl);
- new_map = bfd_realloc (map, amt);
+ new_map = (struct orl *) bfd_realloc (map, amt);
if (new_map == NULL)
goto error_return;
namelen = strlen (syms[src_count]->name);
amt = sizeof (char *);
- map[orl_count].name = bfd_alloc (arch, amt);
+ map[orl_count].name = (char **) bfd_alloc (arch, amt);
if (map[orl_count].name == NULL)
goto error_return;
- *(map[orl_count].name) = bfd_alloc (arch, namelen + 1);
+ *(map[orl_count].name) = (char *) bfd_alloc (arch,
+ namelen + 1);
if (*(map[orl_count].name) == NULL)
goto error_return;
strcpy (*(map[orl_count].name), syms[src_count]->name);
bfd_byte temp[4];
unsigned int count;
struct ar_hdr hdr;
- struct stat statbuf;
+ long uid, gid;
firstreal = mapsize + elength + sizeof (struct ar_hdr) + SARMAG;
- stat (arch->filename, &statbuf);
+ /* If deterministic, we use 0 as the timestamp in the map.
+ Some linkers may require that the archive filesystem modification
+ time is less than (or near to) the archive map timestamp. Those
+ linkers should not be used with deterministic mode. (GNU ld and
+ Gold do not have this restriction.) */
+ bfd_ardata (arch)->armap_timestamp = 0;
+ uid = 0;
+ gid = 0;
+ if ((arch->flags & BFD_DETERMINISTIC_OUTPUT) == 0)
+ {
+ struct stat statbuf;
+
+ if (stat (arch->filename, &statbuf) == 0)
+ bfd_ardata (arch)->armap_timestamp = (statbuf.st_mtime
+ + ARMAP_TIME_OFFSET);
+ uid = getuid();
+ gid = getgid();
+ }
+
memset (&hdr, ' ', sizeof (struct ar_hdr));
memcpy (hdr.ar_name, RANLIBMAG, strlen (RANLIBMAG));
- /* 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[0]));
_bfd_ar_spacepad (hdr.ar_date, sizeof (hdr.ar_date), "%ld",
bfd_ardata (arch)->armap_timestamp);
- _bfd_ar_spacepad (hdr.ar_uid, sizeof (hdr.ar_uid), "%ld", getuid ());
- _bfd_ar_spacepad (hdr.ar_gid, sizeof (hdr.ar_gid), "%ld", getgid ());
+ _bfd_ar_spacepad (hdr.ar_uid, sizeof (hdr.ar_uid), "%ld", uid);
+ _bfd_ar_spacepad (hdr.ar_gid, sizeof (hdr.ar_gid), "%ld", gid);
_bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld", mapsize);
memcpy (hdr.ar_fmag, ARFMAG, 2);
if (bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch)
{
do
{
- firstreal += arelt_size (current) + sizeof (struct ar_hdr);
+ struct areltdata *ared = arch_eltdata (current);
+
+ firstreal += (ared->parsed_size + ared->extra_size
+ + sizeof (struct ar_hdr));
firstreal += firstreal % 2;
current = current->archive_next;
}
struct stat archstat;
struct ar_hdr hdr;
+ /* If creating deterministic archives, just leave the timestamp as-is. */
+ if ((arch->flags & BFD_DETERMINISTIC_OUTPUT) != 0)
+ return TRUE;
+
/* Flush writes, get last-write timestamp from file, and compare it
to the timestamp IN the file. */
bfd_flush (arch);
/* Can't read mod time for some reason. */
return TRUE;
}
- if (archstat.st_mtime <= bfd_ardata (arch)->armap_timestamp)
+ if (((long) archstat.st_mtime) <= bfd_ardata (arch)->armap_timestamp)
/* OK by the linker's rules. */
return TRUE;
_bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld",
mapsize);
_bfd_ar_spacepad (hdr.ar_date, sizeof (hdr.ar_date), "%ld",
- time (NULL));
+ ((arch->flags & BFD_DETERMINISTIC_OUTPUT) == 0
+ ? time (NULL) : 0));
/* This, at least, is what Intel coff sets the values to. */
_bfd_ar_spacepad (hdr.ar_uid, sizeof (hdr.ar_uid), "%ld", 0);
_bfd_ar_spacepad (hdr.ar_gid, sizeof (hdr.ar_gid), "%ld", 0);