JDK-6481955 : Uncanonicalized absolute filepath with length 248-260 no longer works (win)
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.io
  • Affected Version: 5.0u6,OpenJDK6,6
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2006-10-13
  • Updated: 2010-04-02
  • Resolved: 2006-12-12
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other JDK 6 JDK 7 Other
5.0u11,OpenJDK6Fixed 6u1 b01Fixed 7Fixed OpenJDK6Fixed
Related Reports
Relates :  
Description
Between 1.5.0_05 and 1.5.0_06 a length limit on 248 characters
was introduced on relative paths which can cause severe grievances
for people upgrading. Before the "fix" files of length 260 could be used.

import java.io.*;

public class TestPathLength {
	private static String longFilename = "C:\\tmp\\.\\";
	private static String padding = "1234567890123456789012345678901234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890";
	
	public static void main(String[] args) {
		for (int i = 230; i < 260; i++) {
			String tmpName = longFilename + padding.substring(0, i) + ".txt";
			try {
				FileWriter fw = new FileWriter(tmpName);
				fw.close();
			} catch (Exception e) {
				System.out.println("Failed at length: " + tmpName.length());
				break;
			}
		}
	}
}

Comments
EVALUATION Regression introduced with the fix for #4403166. The implementation has a lopehole when dealing with a un-canonicalized absolute filepath (means it's in absolute form but has relative components, such as "../" or "./" in its path). As specified by the Windows API, the "\\?\" prefix does not work with a relative path, obviously this also includes the "relative path component". Invoking the _wfullpath to "canonicalize" the path before adding the prefix to solve this problem. See suggested fix. The fix need go back to 5.0u and 6.0u asap.
13-10-2006

SUGGESTED FIX --- io_util_md.c Fri Oct 13 11:53:52 2006 *************** *** 86,91 **** --- 86,113 ---- } } + WCHAR* prefixAbpath(const WCHAR* path, int pathlen, int abpathlen) { + WCHAR* pathbuf = NULL; + WCHAR* abpath = (WCHAR*)malloc(abpathlen * sizeof(WCHAR)); + if (abpath) { + 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) { *************** *** 102,108 **** (ps[0] == L'\\' && ps[1] == L'\\' || //UNC ps[1] == L':' && ps[2] == L'\\')) { //absolute if (pathlen > max_path - 1) { ! pathbuf = getPrefixed(ps, pathlen); } else { pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR)); if (pathbuf != 0) { --- 124,130 ---- (ps[0] == L'\\' && ps[1] == L'\\' || //UNC ps[1] == L':' && ps[2] == L'\\')) { //absolute if (pathlen > max_path - 1) { ! pathbuf = prefixAbpath(ps, pathlen, pathlen); } else { pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR)); if (pathbuf != 0) { *************** *** 126,148 **** 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); ! } } else { pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR)); if (pathbuf != 0) { --- 148,154 ---- int dirlen = currentDirLength(ps, pathlen); if (dirlen + pathlen + 1 > max_path - 1) { int abpathlen = dirlen + pathlen + 10; ! pathbuf = prefixAbpath(ps, pathlen, abpathlen); } else { pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR)); if (pathbuf != 0) {
13-10-2006

WORK AROUND Canonicalize the filepath if its length is bigger than 248. For example, new File(path).getCanonicalPath().
13-10-2006