# HG changeset patch # User sherman # Date 1214427502 25200 # Node ID 36c29b2692f1e989bc8c64a95570efa911b0b60f # Parent b42ef9406aae89cc6cea744f972e25dc7ee9c5af 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 diff -r b42ef9406aae -r 36c29b2692f1 jdk/src/windows/native/java/io/io_util_md.c --- 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) { diff -r b42ef9406aae -r 36c29b2692f1 jdk/test/java/io/File/MaxPath.java --- /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; + } + } + } +}