summaryrefslogtreecommitdiff
path: root/bfd/archive.c
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2011-05-27 10:52:30 +0000
committerNick Clifton <nickc@redhat.com>2011-05-27 10:52:30 +0000
commitf860b29386dd6cb18333989320bc8996551fbe17 (patch)
tree1705dd595e8a821bd559028f1ecb2884f8ecb40f /bfd/archive.c
parentb1dfeca469a3d63bca56050fc229437bafd94846 (diff)
downloadbinutils-redhat-f860b29386dd6cb18333989320bc8996551fbe17.tar.gz
PR binutils/12710
* archive.c (_bfd_get_elt_at_filepos): Set correct error value if unable to read a file pointed to by an entry in a thin archive. (adjust_relative_path): Use lrealpath to canonicalize paths. Handle the case where the reference path is above the current path in the directory tree.
Diffstat (limited to 'bfd/archive.c')
-rw-r--r--bfd/archive.c92
1 files changed, 80 insertions, 12 deletions
diff --git a/bfd/archive.c b/bfd/archive.c
index 5de7a3e656..14136a045e 100644
--- a/bfd/archive.c
+++ b/bfd/archive.c
@@ -629,6 +629,8 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos)
/* 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
{
@@ -717,6 +719,7 @@ bfd_generic_openr_next_archived_file (bfd *archive, bfd *last_file)
else
{
unsigned int size = arelt_size (last_file);
+
filestart = last_file->proxy_origin;
if (! bfd_is_thin_archive (archive))
filestart += size;
@@ -750,7 +753,7 @@ bfd_generic_archive_p (bfd *abfd)
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);
@@ -1333,19 +1336,47 @@ normalize (bfd *abfd ATTRIBUTE_UNUSED, const char *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 returned string is 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 (;;)
{
@@ -1363,12 +1394,42 @@ adjust_relative_path (const char * path, const char * ref_path)
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)
{
@@ -1377,19 +1438,26 @@ adjust_relative_path (const char * path, const char * ref_path)
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;
}