/* 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, 2009, 2010, 2011
- Free Software Foundation, Inc.
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
+ 2012 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.
else
memcpy (p, buf, n);
}
+
+bfd_boolean
+_bfd_ar_sizepad (char *p, size_t n, bfd_size_type size)
+{
+ static char buf[21];
+ size_t len;
+
+ snprintf (buf, sizeof (buf), "%-10" BFD_VMA_FMT "u", size);
+ len = strlen (buf);
+ if (len > n)
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ return FALSE;
+ }
+ if (len < n)
+ {
+ memcpy (p, buf, len);
+ memset (p + len, ' ', n - len);
+ }
+ else
+ memcpy (p, buf, n);
+ return TRUE;
+}
\f
bfd_boolean
_bfd_generic_mkarchive (bfd *abfd)
_bfd_find_nested_archive (bfd *arch_bfd, const char *filename)
{
bfd *abfd;
+ const char *target;
for (abfd = arch_bfd->nested_archives;
abfd != NULL;
if (filename_cmp (filename, abfd->filename) == 0)
return abfd;
}
- abfd = bfd_openr (filename, NULL);
+ target = NULL;
+ if (!arch_bfd->target_defaulted)
+ target = arch_bfd->xvec->name;
+ abfd = bfd_openr (filename, target);
if (abfd)
{
abfd->archive_next = arch_bfd->nested_archives;
{
struct ar_hdr hdr;
char *hdrp = (char *) &hdr;
- size_t parsed_size;
+ bfd_size_type parsed_size;
struct areltdata *ared;
char *filename = NULL;
bfd_size_type namelen = 0;
}
errno = 0;
- parsed_size = strtol (hdr.ar_size, NULL, 10);
- if (errno != 0)
+ if (sscanf (hdr.ar_size, "%" BFD_VMA_FMT "u", &parsed_size) != 1)
{
bfd_set_error (bfd_error_malformed_archive);
return NULL;
bfd *n_nfd;
char *filename;
- if (archive->my_archive)
- {
- filepos += archive->origin;
- archive = archive->my_archive;
- }
-
n_nfd = _bfd_look_for_bfd_in_cache (archive, filepos);
if (n_nfd)
return n_nfd;
if (bfd_is_thin_archive (archive))
{
+ const char *target;
+
/* This is a proxy entry for an external file. */
if (! IS_ABSOLUTE_PATH (filename))
{
}
/* It's not an element of a nested archive;
open the external file as a bfd. */
- n_nfd = bfd_openr (filename, NULL);
+ target = NULL;
+ if (!archive->target_defaulted)
+ target = archive->xvec->name;
+ n_nfd = bfd_openr (filename, target);
+ if (n_nfd == NULL)
+ bfd_set_error (bfd_error_malformed_archive);
}
else
{
filestart = bfd_ardata (archive)->first_file_filepos;
else
{
- unsigned int size = arelt_size (last_file);
+ bfd_size_type size = arelt_size (last_file);
+
filestart = last_file->proxy_origin;
if (! bfd_is_thin_archive (archive))
filestart += size;
- if (archive->my_archive)
- filestart -= archive->origin;
/* 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. */
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);
return NULL;
}
- if (bfd_has_map (abfd))
+ if (abfd->target_defaulted && bfd_has_map (abfd))
{
bfd *first;
struct artdata *ardata = bfd_ardata (abfd);
char *stringbase;
bfd_size_type stringsize;
- unsigned int parsed_size;
+ bfd_size_type parsed_size;
carsym *carsyms;
bfd_size_type nsymz; /* Number of symbols in armap. */
bfd_vma (*swap) (const void *);
}
#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 (;;)
{
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)
{
pathbuf_len = 0;
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;
}
char **tabloc,
bfd_size_type *tablen)
{
- unsigned int maxname = abfd->xvec->ar_max_namelen;
+ unsigned int maxname = ar_maxnamelen (abfd);
bfd_size_type total_namelen = 0;
bfd *current;
char *strptr;
bfd_size_type *tablen,
const char **name)
{
- unsigned int maxname = abfd->xvec->ar_max_namelen;
+ unsigned int maxname = ar_maxnamelen (abfd);
bfd *current;
*tablen = 0;
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_ar_sizepad (hdr->ar_size, sizeof (hdr->ar_size),
+ arch_eltdata (abfd)->parsed_size + padded_len))
+ return FALSE;
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 };
status.st_gid);
_bfd_ar_spacepad (hdr->ar_mode, sizeof (hdr->ar_mode), "%-8lo",
status.st_mode);
- _bfd_ar_spacepad (hdr->ar_size, sizeof (hdr->ar_size), "%-10ld",
- status.st_size);
+ if (!_bfd_ar_sizepad (hdr->ar_size, sizeof (hdr->ar_size), status.st_size))
+ {
+ free (ared);
+ return NULL;
+ }
memcpy (hdr->ar_fmag, ARFMAG, 2);
ared->parsed_size = status.st_size;
ared->arch_header = (char *) hdr;
memset (&hdr, ' ', sizeof (struct ar_hdr));
memcpy (hdr.ar_name, ename, strlen (ename));
/* Round size up to even number in archive header. */
- _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld",
- (elength + 1) & ~(bfd_size_type) 1);
+ if (!_bfd_ar_sizepad (hdr.ar_size, sizeof (hdr.ar_size),
+ (elength + 1) & ~(bfd_size_type) 1))
+ return FALSE;
memcpy (hdr.ar_fmag, ARFMAG, 2);
if ((bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch)
!= sizeof (struct ar_hdr))
current = current->archive_next)
{
char buffer[DEFAULT_BUFFERSIZE];
- unsigned int remaining = arelt_size (current);
+ bfd_size_type remaining = arelt_size (current);
/* Write ar header. */
if (!_bfd_write_ar_hdr (arch, current))
bfd_ardata (arch)->armap_timestamp);
_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);
+ if (!_bfd_ar_sizepad (hdr.ar_size, sizeof (hdr.ar_size), mapsize))
+ return FALSE;
memcpy (hdr.ar_fmag, ARFMAG, 2);
if (bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch)
!= sizeof (struct ar_hdr))
memset (&hdr, ' ', sizeof (struct ar_hdr));
hdr.ar_name[0] = '/';
- _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld",
- mapsize);
+ if (!_bfd_ar_sizepad (hdr.ar_size, sizeof (hdr.ar_size), mapsize))
+ return FALSE;
_bfd_ar_spacepad (hdr.ar_date, sizeof (hdr.ar_date), "%ld",
((arch->flags & BFD_DETERMINISTIC_OUTPUT) == 0
? time (NULL) : 0));