This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Patch: FYI: File.getCanonicalPath improvement


I'm checking this in on the trunk.

This is an improvement to File.getCanonicalPath for POSIX-y systems.
It changes this method to return a result even when the file in
question does not exist.

This still isn't completely correct, in that there are cases (see
patch for one) where we generate a different result from the JDK.  To
achieve this we have to basically inline our own version of
realpath(); I didn't want to do that today, and this code still lets
me achieve my short-term goal (fixing an eclipse bug...).

Windows hackers, does the Windows port need something like this?

Tom

Index: libjava/ChangeLog
from  Tom Tromey  <tromey@redhat.com>

	* java/io/natFilePosix.cc (getCanonicalPath): Handle case where
	file does not exist.

Index: libjava/java/io/natFilePosix.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/natFilePosix.cc,v
retrieving revision 1.3
diff -u -r1.3 natFilePosix.cc
--- libjava/java/io/natFilePosix.cc 21 Jan 2003 20:45:57 -0000 1.3
+++ libjava/java/io/natFilePosix.cc 10 Sep 2003 23:05:33 -0000
@@ -118,7 +118,69 @@
 
 #ifdef HAVE_REALPATH
   if (realpath (buf, buf2) == NULL)
-    throw new IOException (JvNewStringLatin1 (strerror (errno)));
+    {
+      // If realpath failed, we have to come up with a canonical path
+      // anyway.  We do this with purely textual manipulation.
+      // FIXME: this isn't perfect.  You can construct a case where
+      // we get a different answer from the JDK:
+      // mkdir -p /tmp/a/b/c
+      // ln -s /tmp/a/b /tmp/a/z
+      // ... getCanonicalPath("/tmp/a/z/c/nosuchfile")
+      // We will give /tmp/a/z/c/nosuchfile, while the JDK will
+      // give /tmp/a/b/c/nosuchfile.
+      int out_idx;
+      if (buf[0] != '/')
+	{
+	  // Not absolute, so start with current directory.
+	  if (getcwd (buf2, sizeof (buf2)) == NULL)
+	    throw new IOException ();
+	  out_idx = strlen (buf2);
+	}
+      else
+	{
+	  buf2[0] = '/';
+	  out_idx = 1;
+	} 
+      int in_idx = 0;
+      while (buf[in_idx] != '\0')
+	{
+	  // Skip '/'s.
+	  while (buf[in_idx] == '/')
+	    ++in_idx;
+	  int elt_start = in_idx;
+	  // Find next '/' or end of path.
+	  while (buf[in_idx] != '\0' && buf[in_idx] != '/')
+	    ++in_idx;
+	  if (in_idx == elt_start)
+	    {
+	      // An empty component means we've reached the end.
+	      break;
+	    }
+	  int len = in_idx - elt_start;
+	  if (len == 1 && buf[in_idx] == '.')
+	    continue;
+	  if (len == 2 && buf[in_idx] == '.' && buf[in_idx + 1] == '.')
+	    {
+	      // Found ".." component, lop off last part from existing
+	      // buffer.
+	      --out_idx;
+	      while (out_idx > 0 && buf[out_idx] != '/')
+		--out_idx;
+	      // Can't go up past "/".
+	      if (out_idx == 0)
+		++out_idx;
+	    }
+	  else
+	    {
+	      // Append a real path component to the output.
+	      if (out_idx > 1)
+		buf2[out_idx++] = '/';
+	      strncpy (&buf2[out_idx], &buf[elt_start], len);
+	      out_idx += len;
+	    }
+	}
+      buf[out_idx] = '\0';
+    }
 
   // FIXME: what encoding to assume for file names?  This affects many
   // calls.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]