6481955: Uncanonicalized absolute filepath with length 248-260 no longer works (win)
authorsherman
Wed, 25 Jun 2008 13:58:22 -0700
changeset 785 36c29b2692f1
parent 784 b42ef9406aae
child 786 3cfaed48dbf4
child 787 637b139ce684
child 794 2ba8b05f177a
child 829 813b4d167747
6481955: Uncanonicalized absolute filepath with length 248-260 no longer works (win) Summary: Uncanonicalized absolute filepath with length 248-260 no longer works (win) Reviewed-by: alanb
jdk/src/windows/native/java/io/io_util_md.c
jdk/test/java/io/File/MaxPath.java
--- a/jdk/src/windows/native/java/io/io_util_md.c	Wed Jun 25 08:27:06 2008 -0700
+++ b/jdk/src/windows/native/java/io/io_util_md.c	Wed Jun 25 13:58:22 2008 -0700
@@ -104,23 +104,56 @@
     }
 }
 
+/*
+  The "abpathlen" is the size of the buffer needed by _wfullpath. If the
+  "path" is a relative path, it is "the length of the current dir" + "the
+  length of the path", if it's "absolute" already, it's the same as
+  pathlen which is the length of "path".
+ */
+WCHAR* prefixAbpath(const WCHAR* path, int pathlen, int abpathlen) {
+    WCHAR* pathbuf = NULL;
+    WCHAR* abpath = NULL;
+
+    abpathlen += 10;  //padding
+    abpath = (WCHAR*)malloc(abpathlen * sizeof(WCHAR));
+    if (abpath) {
+        /* Collapse instances of "foo\.." and ensure absoluteness before
+           going down to prefixing.
+        */
+        if (_wfullpath(abpath, path, abpathlen)) {
+            pathbuf = getPrefixed(abpath, abpathlen);
+        } else {
+            /* _wfullpath fails if the pathlength exceeds 32k wchar.
+               Instead of doing more fancy things we simply copy the
+               ps into the return buffer, the subsequent win32 API will
+               probably fail with FileNotFoundException, which is expected
+            */
+            pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
+            if (pathbuf != 0) {
+                wcscpy(pathbuf, path);
+            }
+        }
+        free(abpath);
+    }
+    return pathbuf;
+}
+
 /* If this returns NULL then an exception is pending */
 WCHAR*
 pathToNTPath(JNIEnv *env, jstring path, jboolean throwFNFE) {
     int pathlen = 0;
     WCHAR *pathbuf = NULL;
-    int max_path = 248;   /* Since CreateDirectoryW() has the limit of
-                             248 instead of the normal MAX_PATH, we
-                             use 248 as the max_path to satisfy both
-                           */
+    int max_path = 248; /* CreateDirectoryW() has the limit of 248 */
+
     WITH_UNICODE_STRING(env, path, ps) {
         pathlen = wcslen(ps);
         if (pathlen != 0) {
             if (pathlen > 2 &&
                 (ps[0] == L'\\' && ps[1] == L'\\' ||   //UNC
-                 ps[1] == L':' && ps[2] == L'\\')) {   //absolute
+                 ps[1] == L':' && ps[2] == L'\\'))     //absolute
+            {
                  if (pathlen > max_path - 1) {
-                     pathbuf = getPrefixed(ps, pathlen);
+                     pathbuf = prefixAbpath(ps, pathlen, pathlen);
                  } else {
                      pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
                      if (pathbuf != 0) {
@@ -132,7 +165,7 @@
                    its absolute form is bigger than max_path or not, if yes
                    need to (1)convert it to absolute and (2)prefix. This is
                    obviously a burden to all relative paths (The current dir/len
-                   for "dirve & directory" relative path is cached, so we only
+                   for "drive & directory" relative path is cached, so we only
                    calculate it once but for "drive-relative path we call
                    _wgetdcwd() and wcslen() everytime), but a hit we have
                    to take if we want to support relative path beyond max_path.
@@ -143,24 +176,7 @@
                 WCHAR *abpath = NULL;
                 int dirlen = currentDirLength(ps, pathlen);
                 if (dirlen + pathlen + 1 > max_path - 1) {
-                    int abpathlen = dirlen + pathlen + 10;
-                    abpath = (WCHAR*)malloc(abpathlen * sizeof(WCHAR));
-                    if (abpath) {
-                        if (_wfullpath(abpath, ps, abpathlen)) {
-                            pathbuf = getPrefixed(abpath, abpathlen);
-                        } else {
-                            /* _wfullpath fails if the pathlength exceeds 32k wchar.
-                               Instead of doing more fancy things we simply copy the
-                               ps into the return buffer, the subsequent win32 API will
-                               probably fail with FileNotFoundException, which is expected
-                             */
-                            pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
-                            if (pathbuf != 0) {
-                                wcscpy(pathbuf, ps);
-                            }
-                        }
-                        free(abpath);
-                    }
+                    pathbuf = prefixAbpath(ps, pathlen, dirlen + pathlen);
                 } else {
                     pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
                     if (pathbuf != 0) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/File/MaxPath.java	Wed Jun 25 13:58:22 2008 -0700
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+   @bug 6481955
+   @summary Path length less than MAX_PATH (260) works on Windows
+ */
+
+import java.io.*;
+
+public class MaxPath {
+    public static void main(String[] args) throws Exception {
+        String osName = System.getProperty("os.name");
+        if (!osName.startsWith("Windows")) {
+            return;
+        }
+        int MAX_PATH = 260;
+        String dir = new File(".").getAbsolutePath() + "\\";
+        String padding = "1234567890123456789012345678901234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890";
+        for (int i = 240 - dir.length(); i < MAX_PATH - dir.length(); i++) {
+            String longname = dir + padding.substring(0, i);
+            try {
+                File f = new File(longname);
+                if (f.createNewFile()) {
+                    if (!f.exists() || !f.canRead()) {
+                        throw new RuntimeException("Failed at length: " + longname.length());
+                    }
+                    f.delete();
+                }
+            } catch (IOException e) {
+                System.out.println("Failed at length: " + longname.length());
+                throw e;
+            }
+        }
+    }
+}