Blob Blame History Raw
2005-11-30  Alexandre Oliva  <aoliva@redhat.com>

	* gcc.c (find_a_file): Use update_path before access tests.
	Mostly from Thomas Walker <thomas.walker@morganstanley.com>
	* prefix.c (update_path): Move dir/../-stripping code to...
	(maybe_strip_dotdots): New function.  Reorganize.

--- gcc/gcc.c.orig	2005-12-01 18:38:38.000000000 -0200
+++ gcc/gcc.c	2005-12-01 18:41:01.000000000 -0200
@@ -2371,7 +2371,7 @@
 find_a_file (struct path_prefix *pprefix, const char *name, int mode,
 	     int multilib)
 {
-  char *temp;
+  char *temp, *temp2;
   const char *const file_suffix =
     ((mode & X_OK) != 0 ? HOST_EXECUTABLE_SUFFIX : "");
   struct prefix_list *pl;
@@ -2407,19 +2407,18 @@
 				    NULL));
     }
 
-  temp = xmalloc (len);
-
   /* Determine the filename to execute (special case for absolute paths).  */
 
   if (IS_ABSOLUTE_PATH (name))
     {
-      if (access (name, mode) == 0)
-	{
-	  strcpy (temp, name);
-	  return temp;
-	}
+      /* IS_ABSOLUTE_PATHNAME lets anything through that starts with '/'  */
+      temp = update_path (name, NULL);
+      if (access (temp, mode) == 0)
+	return temp;
     }
   else
+  {
+    temp = xmalloc (len);
     for (pl = pprefix->plist; pl; pl = pl->next)
       {
 	const char *this_name
@@ -2435,24 +2434,30 @@
 		strcat (temp, machine_suffix);
 		strcat (temp, multilib_name);
 		strcat (temp, file_suffix);
-		if (access_check (temp, mode) == 0)
+		temp2 = update_path (temp, NULL);
+		if (access_check (temp2, mode) == 0)
 		  {
 		    if (pl->used_flag_ptr != 0)
 		      *pl->used_flag_ptr = 1;
-		    return temp;
+		    free (temp);
+		    return temp2;
 		  }
+		free (temp2);
 	      }
 
 	    /* Now try just the multilib_name.  */
 	    strcpy (temp, pl->prefix);
 	    strcat (temp, machine_suffix);
 	    strcat (temp, multilib_name);
-	    if (access_check (temp, mode) == 0)
+	    temp2 = update_path (temp, NULL);
+	    if (access_check (temp2, mode) == 0)
 	      {
 		if (pl->used_flag_ptr != 0)
 		  *pl->used_flag_ptr = 1;
-		return temp;
+		free (temp);
+		return temp2;
 	      }
+	    free (temp2);
 	  }
 
 	/* Certain prefixes are tried with just the machine type,
@@ -2467,23 +2472,29 @@
 		strcat (temp, just_machine_suffix);
 		strcat (temp, multilib_name);
 		strcat (temp, file_suffix);
-		if (access_check (temp, mode) == 0)
+		temp2 = update_path (temp, NULL);
+		if (access_check (temp2, mode) == 0)
 		  {
 		    if (pl->used_flag_ptr != 0)
 		      *pl->used_flag_ptr = 1;
-		    return temp;
+		    free (temp);
+		    return temp2;
 		  }
+		free (temp2);
 	      }
 
 	    strcpy (temp, pl->prefix);
 	    strcat (temp, just_machine_suffix);
 	    strcat (temp, multilib_name);
-	    if (access_check (temp, mode) == 0)
+	    temp2 = update_path (temp, NULL);
+	    if (access_check (temp2, mode) == 0)
 	      {
 		if (pl->used_flag_ptr != 0)
 		  *pl->used_flag_ptr = 1;
-		return temp;
+		free (temp);
+		return temp2;
 	      }
+	    free (temp2);
 	  }
 
 	/* Certain prefixes can't be used without the machine suffix
@@ -2497,24 +2508,31 @@
 		strcpy (temp, pl->prefix);
 		strcat (temp, this_name);
 		strcat (temp, file_suffix);
-		if (access_check (temp, mode) == 0)
+		temp2 = update_path (temp, NULL);
+		if (access_check (temp2, mode) == 0)
 		  {
 		    if (pl->used_flag_ptr != 0)
 		      *pl->used_flag_ptr = 1;
-		    return temp;
+		    free (temp);
+		    return temp2;
 		  }
+		free (temp2);
 	      }
 
 	    strcpy (temp, pl->prefix);
 	    strcat (temp, this_name);
-	    if (access_check (temp, mode) == 0)
+	    temp2 = update_path (temp, NULL);
+	    if (access_check (temp2, mode) == 0)
 	      {
 		if (pl->used_flag_ptr != 0)
 		  *pl->used_flag_ptr = 1;
-		return temp;
+		free (temp);
+		return temp2;
 	      }
+	    free (temp2);
 	  }
       }
+  }
 
   free (temp);
   return 0;
--- gcc/prefix.c.orig	2005-12-01 18:38:38.000000000 -0200
+++ gcc/prefix.c	2005-12-01 18:46:37.000000000 -0200
@@ -238,6 +238,105 @@
   while (*string++);
 }
 
+/* Strip dir/.. from a pathname when it makes sense, e.g., when this
+   would turn an inaccessible pathname into an accessible one.
+
+   We short-circuit dir/.. when dir does not exist, and when
+   some/dir/../thing does not exist but some/thing does.  In case
+   there are multiple possible dir/../ stripping possibilities that
+   would turn an inaccessible pathname into an accessible one, the one
+   closer to the end of the pathname is preferred.
+
+   RESULT is the pathname that might contain such dotdot sequences to
+   be stripped.  P points into RESULT, and indicates the location
+   where we should start looking for ../ sequences.
+
+   Even though RESULT is const, P is not, and that's because
+   characters in it may be temporarily overwritten, so RESULT must not
+   be in read-only storage.
+
+   The returned value is either a newly-allocated memory area, holding
+   a string that is the result of dotdot-stripping from the original
+   input strip, or RESULT itself, in which case any modifications made
+   to the string will have been undone.  */
+
+static const char *
+maybe_strip_dotdots (const char *result, char *p)
+{
+  char *temp;
+  const char *path, *before, *after;
+  size_t len;
+
+  while (1)
+    {
+      p = strchr (p, '.');
+      if (p == NULL)
+	return result;
+      /* Look for `/../'  */
+      if (p[1] == '.'
+	  && IS_DIR_SEPARATOR (p[2])
+	  && (p != result && IS_DIR_SEPARATOR (p[-1])))
+	break;
+      else
+	++p;
+    }
+
+  *p = 0;
+  if (access (result, X_OK) == 0)
+    {
+      *p = '.';
+
+      path = maybe_strip_dotdots (result, p + 3);
+      if (access (path, F_OK) == 0)
+	return path;
+      if (path != result)
+	free ((char *) path);
+    }
+  else
+    *p = '.';
+
+  /* If we couldn't access the dir, or if recursion resulted in a
+     non-accessible pathname, we try stripping out dir/../.  If `dir'
+     turns out to be `.', strip one more path component.  */
+  before = p;
+  do
+    {
+      --before;
+      while (before != result && IS_DIR_SEPARATOR (*before))
+	--before;
+      while (before != result && !IS_DIR_SEPARATOR (before[-1]))
+	--before;
+    }
+  while (before != result && *before == '.'
+	 && IS_DIR_SEPARATOR (*(before + 1)));
+  /* If we have something like `./..' or `/..', don't
+     strip anything more.  */
+  if (*before == '.' || IS_DIR_SEPARATOR (*before))
+    return result;
+
+  after = p + 3;
+  while (IS_DIR_SEPARATOR (*after))
+    ++after;
+
+  len = (after - result) + strlen (after);
+
+  temp = xmalloc (len + 1 - (after - before));
+  memcpy (temp, result, before - result);
+  memcpy (temp + (before - result), after, len + 1 - (after - result));
+
+  path = maybe_strip_dotdots (temp, temp + (before - result));
+
+  if (path != temp)
+    free (temp);
+
+  if (access (path, F_OK) == 0)
+    result = path;
+  else if (path != result)
+    free ((char *) path);
+
+  return result;
+}
+
 /* Update PATH using KEY if PATH starts with PREFIX.  The returned
    string is always malloc-ed, and the caller is responsible for
    freeing it.  */
@@ -245,7 +344,7 @@
 char *
 update_path (const char *path, const char *key)
 {
-  char *result, *p;
+  char *result, *temp;
 
   if (! strncmp (path, std_prefix, strlen (std_prefix)) && key != 0)
     {
@@ -265,62 +364,11 @@
   else
     result = xstrdup (path);
 
-#ifndef ALWAYS_STRIP_DOTDOT
-#define ALWAYS_STRIP_DOTDOT 0
-#endif
+  temp = result;
+  result = (char *) maybe_strip_dotdots (temp, temp);
 
-  p = result;
-  while (1)
-    {
-      char *src, *dest;
-
-      p = strchr (p, '.');
-      if (p == NULL)
-	break;
-      /* Look for `/../'  */
-      if (p[1] == '.'
-	  && IS_DIR_SEPARATOR (p[2])
-	  && (p != result && IS_DIR_SEPARATOR (p[-1])))
-	{
-	  *p = 0;
-	  if (!ALWAYS_STRIP_DOTDOT && access (result, X_OK) == 0)
-	    {
-	      *p = '.';
-	      break;
-	    }
-	  else
-	    {
-	      /* We can't access the dir, so we won't be able to
-		 access dir/.. either.  Strip out `dir/../'.  If `dir'
-		 turns out to be `.', strip one more path component.  */
-	      dest = p;
-	      do
-		{
-		  --dest;
-		  while (dest != result && IS_DIR_SEPARATOR (*dest))
-		    --dest;
-		  while (dest != result && !IS_DIR_SEPARATOR (dest[-1]))
-		    --dest;
-		}
-	      while (dest != result && *dest == '.');
-	      /* If we have something like `./..' or `/..', don't
-		 strip anything more.  */
-	      if (*dest == '.' || IS_DIR_SEPARATOR (*dest))
-		{
-		  *p = '.';
-		  break;
-		}
-	      src = p + 3;
-	      while (IS_DIR_SEPARATOR (*src))
-		++src;
-	      p = dest;
-	      while ((*dest++ = *src++) != 0)
-		;
-	    }
-	}
-      else
-	++p;
-    }
+  if (result != temp)
+    free (temp);
 
 #ifdef UPDATE_PATH_HOST_CANONICALIZE
   /* Perform host dependent canonicalization when needed.  */