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 jboolean extendExceptionsWithPath = JNI_FALSE;
82
83 JNIEXPORT void JNICALL
84 Java_java_io_WinNTFileSystem_initIncludeInExceptions(JNIEnv *env, jclass cls, jboolean b)
85 {
86 extendExceptionsWithPath = b;
87 }
88
89 /* -- Path operations -- */
90
91 extern int wcanonicalize(const WCHAR *path, WCHAR *out, int len);
92 extern int wcanonicalizeWithPrefix(const WCHAR *canonicalPrefix, const WCHAR *pathWithCanonicalPrefix, WCHAR *out, int len);
93
94 /**
95 * Retrieves the fully resolved (final) path for the given path or NULL
96 * if the function fails.
97 */
98 static WCHAR* getFinalPath(JNIEnv *env, const WCHAR *path)
99 {
100 HANDLE h;
101 WCHAR *result;
102 DWORD error;
103
104 /* Need Windows Vista or newer to get the final path */
105 if (GetFinalPathNameByHandle_func == NULL)
106 return NULL;
107
108 h = CreateFileW(path,
247 /* we estimate the max length of memory needed as
248 "currentDir. length + pathname.length"
249 */
250 int len = (int)wcslen(path);
251 len += currentDirLength(path, len);
252 if (len > MAX_PATH_LENGTH - 1) {
253 WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));
254 if (cp != NULL) {
255 if (wcanonicalize(path, cp, len) >= 0) {
256 rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));
257 }
258 free(cp);
259 } else {
260 JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
261 }
262 } else if (wcanonicalize(path, canonicalPath, MAX_PATH_LENGTH) >= 0) {
263 rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));
264 }
265 } END_UNICODE_STRING(env, path);
266 if (rv == NULL && !(*env)->ExceptionCheck(env)) {
267 if (extendExceptionsWithPath) {
268 WITH_PLATFORM_STRING(env, pathname, pathstr) {
269 JNU_ThrowByNameWithTwoMessagesAndLastError(env, "java/io/IOException", "Bad pathname", pathstr);
270 } END_PLATFORM_STRING(env, pathstr);
271 } else {
272 JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
273 }
274 }
275 return rv;
276 }
277
278
279 JNIEXPORT jstring JNICALL
280 Java_java_io_WinNTFileSystem_canonicalizeWithPrefix0(JNIEnv *env, jobject this,
281 jstring canonicalPrefixString,
282 jstring pathWithCanonicalPrefixString)
283 {
284 jstring rv = NULL;
285 WCHAR canonicalPath[MAX_PATH_LENGTH];
286 WITH_UNICODE_STRING(env, canonicalPrefixString, canonicalPrefix) {
287 WITH_UNICODE_STRING(env, pathWithCanonicalPrefixString, pathWithCanonicalPrefix) {
288 int len = (int)wcslen(canonicalPrefix) + MAX_PATH;
289 if (len > MAX_PATH_LENGTH) {
290 WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));
291 if (cp != NULL) {
292 if (wcanonicalizeWithPrefix(canonicalPrefix,
293 pathWithCanonicalPrefix,
294 cp, len) >= 0) {
295 rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));
296 }
297 free(cp);
298 } else {
299 JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
300 }
301 } else if (wcanonicalizeWithPrefix(canonicalPrefix,
302 pathWithCanonicalPrefix,
303 canonicalPath, MAX_PATH_LENGTH) >= 0) {
304 rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));
305 }
306 } END_UNICODE_STRING(env, pathWithCanonicalPrefix);
307 } END_UNICODE_STRING(env, canonicalPrefix);
308 if (rv == NULL && !(*env)->ExceptionCheck(env)) {
309 if (extendExceptionsWithPath) {
310 WITH_PLATFORM_STRING(env, pathWithCanonicalPrefixString, path) {
311 JNU_ThrowByNameWithTwoMessagesAndLastError(env, "java/io/IOException", "Bad pathname", path);
312 } END_PLATFORM_STRING(env, path);
313 } else {
314 JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
315 }
316 }
317 return rv;
318 }
319
320 /* -- Attribute accessors -- */
321
322 /* Check whether or not the file name in "path" is a Windows reserved
323 device name (CON, PRN, AUX, NUL, COM[1-9], LPT[1-9]) based on the
324 returned result from GetFullPathName, which should be in thr form of
325 "\\.\[ReservedDeviceName]" if the path represents a reserved device
326 name.
327 Note1: GetFullPathName doesn't think "CLOCK$" (which is no longer
328 important anyway) is a device name, so we don't check it here.
329 GetFileAttributesEx will catch it later by returning 0 on NT/XP/
330 200X.
331
332 Note2: Theoretically the implementation could just lookup the table
333 below linearly if the first 4 characters of the fullpath returned
334 from GetFullPathName are "\\.\". The current implementation should
335 achieve the same result. If Microsoft add more names into their
336 reserved device name repository in the future, which probably will
587 return JNI_FALSE;
588 }
589 h = CreateFileW(
590 pathbuf, /* Wide char path name */
591 GENERIC_READ | GENERIC_WRITE, /* Read and write permission */
592 FILE_SHARE_READ | FILE_SHARE_WRITE, /* File sharing flags */
593 NULL, /* Security attributes */
594 CREATE_NEW, /* creation disposition */
595 FILE_ATTRIBUTE_NORMAL |
596 FILE_FLAG_OPEN_REPARSE_POINT, /* flags and attributes */
597 NULL);
598
599 if (h == INVALID_HANDLE_VALUE) {
600 DWORD error = GetLastError();
601 if ((error != ERROR_FILE_EXISTS) && (error != ERROR_ALREADY_EXISTS)) {
602 // return false rather than throwing an exception when there is
603 // an existing file.
604 DWORD a = GetFileAttributesW(pathbuf);
605 if (a == INVALID_FILE_ATTRIBUTES) {
606 SetLastError(error);
607 if (extendExceptionsWithPath) {
608 WITH_PLATFORM_STRING(env, path, pathstr) {
609 JNU_ThrowByNameWithTwoMessagesAndLastError(env, "java/io/IOException", "Could not open file", pathstr);
610 } END_PLATFORM_STRING(env, pathstr);
611 } else {
612 JNU_ThrowIOExceptionWithLastError(env, "Could not open file");
613 }
614 }
615 }
616 free(pathbuf);
617 return JNI_FALSE;
618 }
619 free(pathbuf);
620 CloseHandle(h);
621 return JNI_TRUE;
622 }
623
624 static int
625 removeFileOrDirectory(const jchar *path)
626 {
627 /* Returns 0 on success */
628 DWORD a;
629
630 SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL);
631 a = GetFileAttributesW(path);
632 if (a == INVALID_FILE_ATTRIBUTES) {
633 return 1;
|