This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
Patch: FYI: File.getCanonicalPath improvement
- From: Tom Tromey <tromey at redhat dot com>
- To: GCC libjava patches <java-patches at gcc dot gnu dot org>
- Date: 10 Sep 2003 17:52:35 -0600
- Subject: Patch: FYI: File.getCanonicalPath improvement
- Reply-to: tromey at redhat dot com
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.