61 Java_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls)
62 {
63 HMODULE handle;
64 jclass fileClass;
65
66 fileClass = (*env)->FindClass(env, "java/io/File");
67 CHECK_NULL(fileClass);
68 ids.path = (*env)->GetFieldID(env, fileClass, "path", "Ljava/lang/String;");
69 CHECK_NULL(ids.path);
70
71 // GetFinalPathNameByHandle requires Windows Vista or newer
72 if (GetModuleHandleExW((GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
73 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT),
74 (LPCWSTR)&CreateFileW, &handle) != 0)
75 {
76 GetFinalPathNameByHandle_func = (GetFinalPathNameByHandleProc)
77 GetProcAddress(handle, "GetFinalPathNameByHandleW");
78 }
79 }
80
81 /* -- Path operations -- */
82
83 extern int wcanonicalize(const WCHAR *path, WCHAR *out, int len);
84 extern int wcanonicalizeWithPrefix(const WCHAR *canonicalPrefix, const WCHAR *pathWithCanonicalPrefix, WCHAR *out, int len);
85
86 /**
87 * Retrieves the fully resolved (final) path for the given path or NULL
88 * if the function fails.
89 */
90 static WCHAR* getFinalPath(JNIEnv *env, const WCHAR *path)
91 {
92 HANDLE h;
93 WCHAR *result;
94 DWORD error;
95
96 /* Need Windows Vista or newer to get the final path */
97 if (GetFinalPathNameByHandle_func == NULL)
98 return NULL;
99
100 h = CreateFileW(path,
239 /* we estimate the max length of memory needed as
240 "currentDir. length + pathname.length"
241 */
242 int len = (int)wcslen(path);
243 len += currentDirLength(path, len);
244 if (len > MAX_PATH_LENGTH - 1) {
245 WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));
246 if (cp != NULL) {
247 if (wcanonicalize(path, cp, len) >= 0) {
248 rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));
249 }
250 free(cp);
251 } else {
252 JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
253 }
254 } else if (wcanonicalize(path, canonicalPath, MAX_PATH_LENGTH) >= 0) {
255 rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));
256 }
257 } END_UNICODE_STRING(env, path);
258 if (rv == NULL && !(*env)->ExceptionCheck(env)) {
259 JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
260 }
261 return rv;
262 }
263
264
265 JNIEXPORT jstring JNICALL
266 Java_java_io_WinNTFileSystem_canonicalizeWithPrefix0(JNIEnv *env, jobject this,
267 jstring canonicalPrefixString,
268 jstring pathWithCanonicalPrefixString)
269 {
270 jstring rv = NULL;
271 WCHAR canonicalPath[MAX_PATH_LENGTH];
272 WITH_UNICODE_STRING(env, canonicalPrefixString, canonicalPrefix) {
273 WITH_UNICODE_STRING(env, pathWithCanonicalPrefixString, pathWithCanonicalPrefix) {
274 int len = (int)wcslen(canonicalPrefix) + MAX_PATH;
275 if (len > MAX_PATH_LENGTH) {
276 WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));
277 if (cp != NULL) {
278 if (wcanonicalizeWithPrefix(canonicalPrefix,
279 pathWithCanonicalPrefix,
280 cp, len) >= 0) {
281 rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));
282 }
283 free(cp);
284 } else {
285 JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
286 }
287 } else if (wcanonicalizeWithPrefix(canonicalPrefix,
288 pathWithCanonicalPrefix,
289 canonicalPath, MAX_PATH_LENGTH) >= 0) {
290 rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));
291 }
292 } END_UNICODE_STRING(env, pathWithCanonicalPrefix);
293 } END_UNICODE_STRING(env, canonicalPrefix);
294 if (rv == NULL && !(*env)->ExceptionCheck(env)) {
295 JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
296 }
297 return rv;
298 }
299
300 /* -- Attribute accessors -- */
301
302 /* Check whether or not the file name in "path" is a Windows reserved
303 device name (CON, PRN, AUX, NUL, COM[1-9], LPT[1-9]) based on the
304 returned result from GetFullPathName, which should be in thr form of
305 "\\.\[ReservedDeviceName]" if the path represents a reserved device
306 name.
307 Note1: GetFullPathName doesn't think "CLOCK$" (which is no longer
308 important anyway) is a device name, so we don't check it here.
309 GetFileAttributesEx will catch it later by returning 0 on NT/XP/
310 200X.
311
312 Note2: Theoretically the implementation could just lookup the table
313 below linearly if the first 4 characters of the fullpath returned
314 from GetFullPathName are "\\.\". The current implementation should
315 achieve the same result. If Microsoft add more names into their
316 reserved device name repository in the future, which probably will
567 return JNI_FALSE;
568 }
569 h = CreateFileW(
570 pathbuf, /* Wide char path name */
571 GENERIC_READ | GENERIC_WRITE, /* Read and write permission */
572 FILE_SHARE_READ | FILE_SHARE_WRITE, /* File sharing flags */
573 NULL, /* Security attributes */
574 CREATE_NEW, /* creation disposition */
575 FILE_ATTRIBUTE_NORMAL |
576 FILE_FLAG_OPEN_REPARSE_POINT, /* flags and attributes */
577 NULL);
578
579 if (h == INVALID_HANDLE_VALUE) {
580 DWORD error = GetLastError();
581 if ((error != ERROR_FILE_EXISTS) && (error != ERROR_ALREADY_EXISTS)) {
582 // return false rather than throwing an exception when there is
583 // an existing file.
584 DWORD a = GetFileAttributesW(pathbuf);
585 if (a == INVALID_FILE_ATTRIBUTES) {
586 SetLastError(error);
587 JNU_ThrowIOExceptionWithLastError(env, "Could not open file");
588 }
589 }
590 free(pathbuf);
591 return JNI_FALSE;
592 }
593 free(pathbuf);
594 CloseHandle(h);
595 return JNI_TRUE;
596 }
597
598 static int
599 removeFileOrDirectory(const jchar *path)
600 {
601 /* Returns 0 on success */
602 DWORD a;
603
604 SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL);
605 a = GetFileAttributesW(path);
606 if (a == INVALID_FILE_ATTRIBUTES) {
607 return 1;
|
61 Java_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls)
62 {
63 HMODULE handle;
64 jclass fileClass;
65
66 fileClass = (*env)->FindClass(env, "java/io/File");
67 CHECK_NULL(fileClass);
68 ids.path = (*env)->GetFieldID(env, fileClass, "path", "Ljava/lang/String;");
69 CHECK_NULL(ids.path);
70
71 // GetFinalPathNameByHandle requires Windows Vista or newer
72 if (GetModuleHandleExW((GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
73 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT),
74 (LPCWSTR)&CreateFileW, &handle) != 0)
75 {
76 GetFinalPathNameByHandle_func = (GetFinalPathNameByHandleProc)
77 GetProcAddress(handle, "GetFinalPathNameByHandleW");
78 }
79 }
80
81 static int extendExceptionsWithPath = -1;
82
83 static int checkExtendExceptionsWithPath(JNIEnv *env) {
84 if (extendExceptionsWithPath == -1) {
85 jclass cls = (*env)->FindClass(env, "java/io/FileSystem");
86 if (cls == NULL) return -1;
87 jmethodID hasPathInExceptionsMethod = (*env)->GetStaticMethodID(env, cls,
88 "hasPathInExceptions", "()Z");
89 if (hasPathInExceptionsMethod == NULL) return -1;
90 jboolean res = (*env)->CallStaticBooleanMethod(env, cls, hasPathInExceptionsMethod);
91 if (res == JNI_TRUE) {
92 extendExceptionsWithPath = 1;
93 } else {
94 extendExceptionsWithPath = 0;
95 }
96 }
97 return extendExceptionsWithPath;
98 }
99
100 /* -- Path operations -- */
101
102 extern int wcanonicalize(const WCHAR *path, WCHAR *out, int len);
103 extern int wcanonicalizeWithPrefix(const WCHAR *canonicalPrefix, const WCHAR *pathWithCanonicalPrefix, WCHAR *out, int len);
104
105 /**
106 * Retrieves the fully resolved (final) path for the given path or NULL
107 * if the function fails.
108 */
109 static WCHAR* getFinalPath(JNIEnv *env, const WCHAR *path)
110 {
111 HANDLE h;
112 WCHAR *result;
113 DWORD error;
114
115 /* Need Windows Vista or newer to get the final path */
116 if (GetFinalPathNameByHandle_func == NULL)
117 return NULL;
118
119 h = CreateFileW(path,
258 /* we estimate the max length of memory needed as
259 "currentDir. length + pathname.length"
260 */
261 int len = (int)wcslen(path);
262 len += currentDirLength(path, len);
263 if (len > MAX_PATH_LENGTH - 1) {
264 WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));
265 if (cp != NULL) {
266 if (wcanonicalize(path, cp, len) >= 0) {
267 rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));
268 }
269 free(cp);
270 } else {
271 JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
272 }
273 } else if (wcanonicalize(path, canonicalPath, MAX_PATH_LENGTH) >= 0) {
274 rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));
275 }
276 } END_UNICODE_STRING(env, path);
277 if (rv == NULL && !(*env)->ExceptionCheck(env)) {
278 if (checkExtendExceptionsWithPath(env) == 1) {
279 WITH_PLATFORM_STRING(env, pathname, pathstr) {
280 JNU_ThrowByNameWithTwoMessagesAndLastError(env, "java/io/IOException", "Bad pathname", pathstr);
281 } END_PLATFORM_STRING(env, pathstr);
282 } else {
283 JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
284 }
285 }
286 return rv;
287 }
288
289
290 JNIEXPORT jstring JNICALL
291 Java_java_io_WinNTFileSystem_canonicalizeWithPrefix0(JNIEnv *env, jobject this,
292 jstring canonicalPrefixString,
293 jstring pathWithCanonicalPrefixString)
294 {
295 jstring rv = NULL;
296 WCHAR canonicalPath[MAX_PATH_LENGTH];
297 WITH_UNICODE_STRING(env, canonicalPrefixString, canonicalPrefix) {
298 WITH_UNICODE_STRING(env, pathWithCanonicalPrefixString, pathWithCanonicalPrefix) {
299 int len = (int)wcslen(canonicalPrefix) + MAX_PATH;
300 if (len > MAX_PATH_LENGTH) {
301 WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));
302 if (cp != NULL) {
303 if (wcanonicalizeWithPrefix(canonicalPrefix,
304 pathWithCanonicalPrefix,
305 cp, len) >= 0) {
306 rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));
307 }
308 free(cp);
309 } else {
310 JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
311 }
312 } else if (wcanonicalizeWithPrefix(canonicalPrefix,
313 pathWithCanonicalPrefix,
314 canonicalPath, MAX_PATH_LENGTH) >= 0) {
315 rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));
316 }
317 } END_UNICODE_STRING(env, pathWithCanonicalPrefix);
318 } END_UNICODE_STRING(env, canonicalPrefix);
319 if (rv == NULL && !(*env)->ExceptionCheck(env)) {
320 if (checkExtendExceptionsWithPath(env) == 1) {
321 WITH_PLATFORM_STRING(env, pathWithCanonicalPrefixString, path) {
322 JNU_ThrowByNameWithTwoMessagesAndLastError(env, "java/io/IOException", "Bad pathname", path);
323 } END_PLATFORM_STRING(env, path);
324 } else {
325 JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
326 }
327 }
328 return rv;
329 }
330
331 /* -- Attribute accessors -- */
332
333 /* Check whether or not the file name in "path" is a Windows reserved
334 device name (CON, PRN, AUX, NUL, COM[1-9], LPT[1-9]) based on the
335 returned result from GetFullPathName, which should be in thr form of
336 "\\.\[ReservedDeviceName]" if the path represents a reserved device
337 name.
338 Note1: GetFullPathName doesn't think "CLOCK$" (which is no longer
339 important anyway) is a device name, so we don't check it here.
340 GetFileAttributesEx will catch it later by returning 0 on NT/XP/
341 200X.
342
343 Note2: Theoretically the implementation could just lookup the table
344 below linearly if the first 4 characters of the fullpath returned
345 from GetFullPathName are "\\.\". The current implementation should
346 achieve the same result. If Microsoft add more names into their
347 reserved device name repository in the future, which probably will
598 return JNI_FALSE;
599 }
600 h = CreateFileW(
601 pathbuf, /* Wide char path name */
602 GENERIC_READ | GENERIC_WRITE, /* Read and write permission */
603 FILE_SHARE_READ | FILE_SHARE_WRITE, /* File sharing flags */
604 NULL, /* Security attributes */
605 CREATE_NEW, /* creation disposition */
606 FILE_ATTRIBUTE_NORMAL |
607 FILE_FLAG_OPEN_REPARSE_POINT, /* flags and attributes */
608 NULL);
609
610 if (h == INVALID_HANDLE_VALUE) {
611 DWORD error = GetLastError();
612 if ((error != ERROR_FILE_EXISTS) && (error != ERROR_ALREADY_EXISTS)) {
613 // return false rather than throwing an exception when there is
614 // an existing file.
615 DWORD a = GetFileAttributesW(pathbuf);
616 if (a == INVALID_FILE_ATTRIBUTES) {
617 SetLastError(error);
618 if (checkExtendExceptionsWithPath(env) == 1) {
619 WITH_PLATFORM_STRING(env, path, pathstr) {
620 JNU_ThrowByNameWithTwoMessagesAndLastError(env, "java/io/IOException", "Could not open file", pathstr);
621 } END_PLATFORM_STRING(env, pathstr);
622 } else {
623 JNU_ThrowIOExceptionWithLastError(env, "Could not open file");
624 }
625 }
626 }
627 free(pathbuf);
628 return JNI_FALSE;
629 }
630 free(pathbuf);
631 CloseHandle(h);
632 return JNI_TRUE;
633 }
634
635 static int
636 removeFileOrDirectory(const jchar *path)
637 {
638 /* Returns 0 on success */
639 DWORD a;
640
641 SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL);
642 a = GetFileAttributesW(path);
643 if (a == INVALID_FILE_ATTRIBUTES) {
644 return 1;
|