@@ -57,6 +57,76 @@ wchar_t* java_to_wchar(JNIEnv *env, jstring string, jobject result) {
5757 return str;
5858}
5959
60+ //
61+ // Returns 'true' if the path of the form "X:\", where 'X' is a drive letter.
62+ //
63+ bool is_path_absolute_local (wchar_t * path, int path_len) {
64+ if (path_len < 3 ) {
65+ return false ;
66+ }
67+ return ((' a' <= path[0 ] && path[0 ] <= ' z' ) || (' A' <= path[0 ] && path[0 ] <= ' Z' )) &&
68+ path[1 ] == ' :' &&
69+ path[2 ] == ' \\ ' ;
70+ }
71+
72+ //
73+ // Returns 'true' if the path is of the form "\\server\share", i.e. is a UNC path.
74+ //
75+ bool is_path_absolute_unc (wchar_t * path, int path_len) {
76+ if (path_len < 3 ) {
77+ return false ;
78+ }
79+ return path[0 ] == ' \\ ' && path[1 ] == ' \\ ' ;
80+ }
81+
82+ //
83+ // Returns a UTF-16 string that is the concatenation of |prefix| and |path|.
84+ //
85+ wchar_t * add_prefix (wchar_t * path, int path_len, wchar_t * prefix) {
86+ int prefix_len = wcslen (prefix);
87+ int str_len = path_len + prefix_len;
88+ wchar_t * str = (wchar_t *)malloc (sizeof (wchar_t ) * (str_len + 1 ));
89+ wcscpy_s (str, str_len + 1 , prefix);
90+ wcscat_s (str, str_len + 1 , path);
91+ return str;
92+ }
93+
94+ //
95+ // Converts a Java string to a UNICODE path, including the Long Path prefix ("\\?\")
96+ // so that the resulting path supports paths longer than MAX_PATH (260 characters)
97+ //
98+ wchar_t * java_to_wchar_path (JNIEnv *env, jstring string, jobject result) {
99+ // Copy the Java string into a UTF-16 string.
100+ jsize len = env->GetStringLength (string);
101+ wchar_t * str = (wchar_t *)malloc (sizeof (wchar_t ) * (len+1 ));
102+ env->GetStringRegion (string, 0 , len, (jchar*)str);
103+ str[len] = L' \0 ' ;
104+
105+ // Technically, this should be MAX_PATH (i.e. 260), except some Win32 API related
106+ // to working with directory paths are actually limited to 240. It is just
107+ // safer/simpler to cover both cases in one code path.
108+ if (len <= 240 ) {
109+ return str;
110+ }
111+
112+ if (is_path_absolute_local (str, len)) {
113+ // Format: C:\... -> \\?\C:\...
114+ wchar_t * str2 = add_prefix (str, len, L" \\\\\?\\ " );
115+ free (str);
116+ return str2;
117+ } else if (is_path_absolute_unc (str, len)) {
118+ // In this case, we need to skip the first 2 characters:
119+ // Format: \\server\share\... -> \\?\UNC\server\share\...
120+ wchar_t * str2 = add_prefix (&str[2 ], len - 2 , L" \\\\ ?\\ UNC\\ " );
121+ free (str);
122+ return str2;
123+ }
124+ else {
125+ // It is some sort of unknown format, don't mess with it
126+ return str;
127+ }
128+ }
129+
60130JNIEXPORT void JNICALL
61131Java_net_rubygrapefruit_platform_internal_jni_NativeLibraryFunctions_getSystemInfo (JNIEnv *env, jclass target, jobject info, jobject result) {
62132 jclass infoClass = env->GetObjectClass (info);
@@ -280,7 +350,7 @@ typedef struct watch_details {
280350
281351JNIEXPORT jobject JNICALL
282352Java_net_rubygrapefruit_platform_internal_jni_FileEventFunctions_createWatch (JNIEnv *env, jclass target, jstring path, jobject result) {
283- wchar_t * pathStr = java_to_wchar (env, path, result);
353+ wchar_t * pathStr = java_to_wchar_path (env, path, result);
284354 HANDLE h = FindFirstChangeNotificationW (pathStr, FALSE , FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE);
285355 free (pathStr);
286356 if (h == INVALID_HANDLE_VALUE) {
@@ -331,7 +401,7 @@ Java_net_rubygrapefruit_platform_internal_jni_WindowsFileFunctions_stat(JNIEnv *
331401 }
332402
333403 WIN32_FILE_ATTRIBUTE_DATA attr;
334- wchar_t * pathStr = java_to_wchar (env, path, result);
404+ wchar_t * pathStr = java_to_wchar_path (env, path, result);
335405 BOOL ok = GetFileAttributesExW (pathStr, GetFileExInfoStandard, &attr);
336406 free (pathStr);
337407 if (!ok) {
@@ -363,7 +433,7 @@ Java_net_rubygrapefruit_platform_internal_jni_WindowsFileFunctions_readdir(JNIEn
363433 }
364434
365435 WIN32_FIND_DATAW entry;
366- wchar_t * pathStr = java_to_wchar (env, path, result);
436+ wchar_t * pathStr = java_to_wchar_path (env, path, result);
367437 HANDLE dirHandle = FindFirstFileW (pathStr, &entry);
368438 free (pathStr);
369439 if (dirHandle == INVALID_HANDLE_VALUE) {
0 commit comments