/* 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
+ 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.
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);
/* 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;
}
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);
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);
if (mapdata == NULL)
return FALSE;
- amt = mapdata->parsed_size;
- raw_armap = (bfd_byte *) 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;
+ 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)
}
#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)
{
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;
}
/* 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)))
{
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))
len = (len + 3) & ~3;
arch_eltdata (current)->extra_size = len;
- _bfd_ar_spacepad (hdr->ar_name, maxname, "#1/%u", len);
+ _bfd_ar_spacepad (hdr->ar_name, maxname, "#1/%lu", len);
}
}
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)
{
- /* Remember the timestamp, to keep it holy. But fudge it a little. */
- bfd_ardata (arch)->armap_timestamp = (statbuf.st_mtime
- + ARMAP_TIME_OFFSET);
+ struct stat statbuf;
+
+ if (stat (arch->filename, &statbuf) == 0)
+ bfd_ardata (arch)->armap_timestamp = (statbuf.st_mtime
+ + ARMAP_TIME_OFFSET);
uid = getuid();
gid = getgid();
}
- else
- {
- /* 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;
- }
memset (&hdr, ' ', sizeof (struct ar_hdr));
memcpy (hdr.ar_name, RANLIBMAG, strlen (RANLIBMAG));