42 #include "io_util_md.h"
43 #include "dirent_md.h"
44 #include "java_io_FileSystem.h"
45
46 #define MAX_PATH_LENGTH 1024
47
48 static struct {
49 jfieldID path;
50 } ids;
51
52 /**
53 * GetFinalPathNameByHandle is available on Windows Vista and newer
54 */
55 typedef BOOL (WINAPI* GetFinalPathNameByHandleProc) (HANDLE, LPWSTR, DWORD, DWORD);
56 static GetFinalPathNameByHandleProc GetFinalPathNameByHandle_func;
57
58 JNIEXPORT void JNICALL
59 Java_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls)
60 {
61 HMODULE handle;
62 jclass fileClass = (*env)->FindClass(env, "java/io/File");
63 if (!fileClass) return;
64 ids.path =
65 (*env)->GetFieldID(env, fileClass, "path", "Ljava/lang/String;");
66
67 // GetFinalPathNameByHandle requires Windows Vista or newer
68 if (GetModuleHandleExW((GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
69 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT),
70 (LPCWSTR)&CreateFileW, &handle) != 0)
71 {
72 GetFinalPathNameByHandle_func = (GetFinalPathNameByHandleProc)
73 GetProcAddress(handle, "GetFinalPathNameByHandleW");
74 }
75 }
76
77 /* -- Path operations -- */
78
79 extern int wcanonicalize(const WCHAR *path, WCHAR *out, int len);
80 extern int wcanonicalizeWithPrefix(const WCHAR *canonicalPrefix, const WCHAR *pathWithCanonicalPrefix, WCHAR *out, int len);
81
82 /**
83 * Retrieves the fully resolved (final) path for the given path or NULL
84 * if the function fails.
85 */
86 static WCHAR* getFinalPath(JNIEnv *env, const WCHAR *path)
230 HANDLE h;
231
232 if (GetFileAttributesExW(path, GetFileExInfoStandard, &wfad)) {
233 attr = getFinalAttributesIfReparsePoint(path, wfad.dwFileAttributes);
234 } else if (GetLastError() == ERROR_SHARING_VIOLATION &&
235 (h = FindFirstFileW(path, &wfd)) != INVALID_HANDLE_VALUE) {
236 attr = getFinalAttributesIfReparsePoint(path, wfd.dwFileAttributes);
237 FindClose(h);
238 }
239 return attr;
240 }
241
242 JNIEXPORT jstring JNICALL
243 Java_java_io_WinNTFileSystem_canonicalize0(JNIEnv *env, jobject this,
244 jstring pathname)
245 {
246 jstring rv = NULL;
247 WCHAR canonicalPath[MAX_PATH_LENGTH];
248
249 WITH_UNICODE_STRING(env, pathname, path) {
250 /*we estimate the max length of memory needed as
251 "currentDir. length + pathname.length"
252 */
253 int len = (int)wcslen(path);
254 len += currentDirLength(path, len);
255 if (len > MAX_PATH_LENGTH - 1) {
256 WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));
257 if (cp != NULL) {
258 if (wcanonicalize(path, cp, len) >= 0) {
259 rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));
260 }
261 free(cp);
262 } else {
263 JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
264 }
265 } else
266 if (wcanonicalize(path, canonicalPath, MAX_PATH_LENGTH) >= 0) {
267 rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));
268 }
269 } END_UNICODE_STRING(env, path);
270 if (rv == NULL) {
271 JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
272 }
273 return rv;
274 }
275
276
277 JNIEXPORT jstring JNICALL
278 Java_java_io_WinNTFileSystem_canonicalizeWithPrefix0(JNIEnv *env, jobject this,
279 jstring canonicalPrefixString,
280 jstring pathWithCanonicalPrefixString)
281 {
282 jstring rv = NULL;
283 WCHAR canonicalPath[MAX_PATH_LENGTH];
284 WITH_UNICODE_STRING(env, canonicalPrefixString, canonicalPrefix) {
285 WITH_UNICODE_STRING(env, pathWithCanonicalPrefixString, pathWithCanonicalPrefix) {
286 int len = (int)wcslen(canonicalPrefix) + MAX_PATH;
287 if (len > MAX_PATH_LENGTH) {
288 WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));
289 if (cp != NULL) {
290 if (wcanonicalizeWithPrefix(canonicalPrefix,
291 pathWithCanonicalPrefix,
292 cp, len) >= 0) {
293 rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));
294 }
295 free(cp);
296 } else {
297 JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
298 }
299 } else
300 if (wcanonicalizeWithPrefix(canonicalPrefix,
301 pathWithCanonicalPrefix,
302 canonicalPath, MAX_PATH_LENGTH) >= 0) {
303 rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));
304 }
305 } END_UNICODE_STRING(env, pathWithCanonicalPrefix);
306 } END_UNICODE_STRING(env, canonicalPrefix);
307 if (rv == NULL) {
308 JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
309 }
310 return rv;
311 }
312
313 /* -- Attribute accessors -- */
314
315 /* Check whether or not the file name in "path" is a Windows reserved
316 device name (CON, PRN, AUX, NUL, COM[1-9], LPT[1-9]) based on the
317 returned result from GetFullPathName, which should be in thr form of
318 "\\.\[ReservedDeviceName]" if the path represents a reserved device
319 name.
320 Note1: GetFullPathName doesn't think "CLOCK$" (which is no longer
321 important anyway) is a device name, so we don't check it here.
322 GetFileAttributesEx will catch it later by returning 0 on NT/XP/
323 200X.
324
325 Note2: Theoretically the implementation could just lookup the table
326 below linearly if the first 4 characters of the fullpath returned
327 from GetFullPathName are "\\.\". The current implementation should
607 if (pathbuf == NULL) {
608 return JNI_FALSE;
609 }
610 if (removeFileOrDirectory(pathbuf) == 0) {
611 rv = JNI_TRUE;
612 }
613 free(pathbuf);
614 return rv;
615 }
616
617 JNIEXPORT jobjectArray JNICALL
618 Java_java_io_WinNTFileSystem_list(JNIEnv *env, jobject this, jobject file)
619 {
620 WCHAR *search_path;
621 HANDLE handle;
622 WIN32_FIND_DATAW find_data;
623 int len, maxlen;
624 jobjectArray rv, old;
625 DWORD fattr;
626 jstring name;
627
628 WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
629 if (pathbuf == NULL)
630 return NULL;
631 search_path = (WCHAR*)malloc(2*wcslen(pathbuf) + 6);
632 if (search_path == 0) {
633 free (pathbuf);
634 errno = ENOMEM;
635 JNU_ThrowOutOfMemoryError(env, "native memory allocation faiuled");
636 return NULL;
637 }
638 wcscpy(search_path, pathbuf);
639 free(pathbuf);
640 fattr = GetFileAttributesW(search_path);
641 if (fattr == INVALID_FILE_ATTRIBUTES) {
642 free(search_path);
643 return NULL;
644 } else if ((fattr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
645 free(search_path);
646 return NULL;
647 }
648
656 /* Append "*", or possibly "\\*", to path */
657 if ((search_path[0] == L'\\' && search_path[1] == L'\0') ||
658 (search_path[1] == L':'
659 && (search_path[2] == L'\0'
660 || (search_path[2] == L'\\' && search_path[3] == L'\0')))) {
661 /* No '\\' needed for cases like "\" or "Z:" or "Z:\" */
662 wcscat(search_path, L"*");
663 } else {
664 wcscat(search_path, L"\\*");
665 }
666
667 /* Open handle to the first file */
668 handle = FindFirstFileW(search_path, &find_data);
669 free(search_path);
670 if (handle == INVALID_HANDLE_VALUE) {
671 if (GetLastError() != ERROR_FILE_NOT_FOUND) {
672 // error
673 return NULL;
674 } else {
675 // No files found - return an empty array
676 rv = (*env)->NewObjectArray(env, 0, JNU_ClassString(env), NULL);
677 return rv;
678 }
679 }
680
681 /* Allocate an initial String array */
682 len = 0;
683 maxlen = 16;
684 rv = (*env)->NewObjectArray(env, maxlen, JNU_ClassString(env), NULL);
685 if (rv == NULL) // Couldn't allocate an array
686 return NULL;
687 /* Scan the directory */
688 do {
689 if (!wcscmp(find_data.cFileName, L".")
690 || !wcscmp(find_data.cFileName, L".."))
691 continue;
692 name = (*env)->NewString(env, find_data.cFileName,
693 (jsize)wcslen(find_data.cFileName));
694 if (name == NULL)
695 return NULL; // error;
696 if (len == maxlen) {
697 old = rv;
698 rv = (*env)->NewObjectArray(env, maxlen <<= 1,
699 JNU_ClassString(env), NULL);
700 if ( rv == NULL
701 || JNU_CopyObjectArray(env, rv, old, len) < 0)
702 return NULL; // error
703 (*env)->DeleteLocalRef(env, old);
704 }
705 (*env)->SetObjectArrayElement(env, rv, len++, name);
706 (*env)->DeleteLocalRef(env, name);
707
708 } while (FindNextFileW(handle, &find_data));
709
710 if (GetLastError() != ERROR_NO_MORE_FILES)
711 return NULL; // error
712 FindClose(handle);
713
714 /* Copy the final results into an appropriately-sized array */
715 old = rv;
716 rv = (*env)->NewObjectArray(env, len, JNU_ClassString(env), NULL);
717 if (rv == NULL)
718 return NULL; /* error */
719 if (JNU_CopyObjectArray(env, rv, old, len) < 0)
720 return NULL; /* error */
721 return rv;
722 }
723
724
725 JNIEXPORT jboolean JNICALL
726 Java_java_io_WinNTFileSystem_createDirectory(JNIEnv *env, jobject this,
727 jobject file)
728 {
729 BOOL h = FALSE;
730 WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
731 if (pathbuf == NULL) {
732 /* Exception is pending */
733 return JNI_FALSE;
734 }
735 h = CreateDirectoryW(pathbuf, NULL);
736 free(pathbuf);
|
42 #include "io_util_md.h"
43 #include "dirent_md.h"
44 #include "java_io_FileSystem.h"
45
46 #define MAX_PATH_LENGTH 1024
47
48 static struct {
49 jfieldID path;
50 } ids;
51
52 /**
53 * GetFinalPathNameByHandle is available on Windows Vista and newer
54 */
55 typedef BOOL (WINAPI* GetFinalPathNameByHandleProc) (HANDLE, LPWSTR, DWORD, DWORD);
56 static GetFinalPathNameByHandleProc GetFinalPathNameByHandle_func;
57
58 JNIEXPORT void JNICALL
59 Java_java_io_WinNTFileSystem_initIDs(JNIEnv *env, jclass cls)
60 {
61 HMODULE handle;
62 jclass fileClass;
63
64 fileClass = (*env)->FindClass(env, "java/io/File");
65 CHECK_NULL(fileClass);
66 ids.path = (*env)->GetFieldID(env, fileClass, "path", "Ljava/lang/String;");
67 CHECK_NULL(ids.path);
68
69 // GetFinalPathNameByHandle requires Windows Vista or newer
70 if (GetModuleHandleExW((GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
71 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT),
72 (LPCWSTR)&CreateFileW, &handle) != 0)
73 {
74 GetFinalPathNameByHandle_func = (GetFinalPathNameByHandleProc)
75 GetProcAddress(handle, "GetFinalPathNameByHandleW");
76 }
77 }
78
79 /* -- Path operations -- */
80
81 extern int wcanonicalize(const WCHAR *path, WCHAR *out, int len);
82 extern int wcanonicalizeWithPrefix(const WCHAR *canonicalPrefix, const WCHAR *pathWithCanonicalPrefix, WCHAR *out, int len);
83
84 /**
85 * Retrieves the fully resolved (final) path for the given path or NULL
86 * if the function fails.
87 */
88 static WCHAR* getFinalPath(JNIEnv *env, const WCHAR *path)
232 HANDLE h;
233
234 if (GetFileAttributesExW(path, GetFileExInfoStandard, &wfad)) {
235 attr = getFinalAttributesIfReparsePoint(path, wfad.dwFileAttributes);
236 } else if (GetLastError() == ERROR_SHARING_VIOLATION &&
237 (h = FindFirstFileW(path, &wfd)) != INVALID_HANDLE_VALUE) {
238 attr = getFinalAttributesIfReparsePoint(path, wfd.dwFileAttributes);
239 FindClose(h);
240 }
241 return attr;
242 }
243
244 JNIEXPORT jstring JNICALL
245 Java_java_io_WinNTFileSystem_canonicalize0(JNIEnv *env, jobject this,
246 jstring pathname)
247 {
248 jstring rv = NULL;
249 WCHAR canonicalPath[MAX_PATH_LENGTH];
250
251 WITH_UNICODE_STRING(env, pathname, path) {
252 /* we estimate the max length of memory needed as
253 "currentDir. length + pathname.length"
254 */
255 int len = (int)wcslen(path);
256 len += currentDirLength(path, len);
257 if (len > MAX_PATH_LENGTH - 1) {
258 WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));
259 if (cp != NULL) {
260 if (wcanonicalize(path, cp, len) >= 0) {
261 rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));
262 }
263 free(cp);
264 } else {
265 JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
266 }
267 } else if (wcanonicalize(path, canonicalPath, MAX_PATH_LENGTH) >= 0) {
268 rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));
269 }
270 } END_UNICODE_STRING(env, path);
271 if (rv == NULL && !(*env)->ExceptionCheck(env)) {
272 JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
273 }
274 return rv;
275 }
276
277
278 JNIEXPORT jstring JNICALL
279 Java_java_io_WinNTFileSystem_canonicalizeWithPrefix0(JNIEnv *env, jobject this,
280 jstring canonicalPrefixString,
281 jstring pathWithCanonicalPrefixString)
282 {
283 jstring rv = NULL;
284 WCHAR canonicalPath[MAX_PATH_LENGTH];
285 WITH_UNICODE_STRING(env, canonicalPrefixString, canonicalPrefix) {
286 WITH_UNICODE_STRING(env, pathWithCanonicalPrefixString, pathWithCanonicalPrefix) {
287 int len = (int)wcslen(canonicalPrefix) + MAX_PATH;
288 if (len > MAX_PATH_LENGTH) {
289 WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR));
290 if (cp != NULL) {
291 if (wcanonicalizeWithPrefix(canonicalPrefix,
292 pathWithCanonicalPrefix,
293 cp, len) >= 0) {
294 rv = (*env)->NewString(env, cp, (jsize)wcslen(cp));
295 }
296 free(cp);
297 } else {
298 JNU_ThrowOutOfMemoryError(env, "native memory allocation failed");
299 }
300 } else if (wcanonicalizeWithPrefix(canonicalPrefix,
301 pathWithCanonicalPrefix,
302 canonicalPath, MAX_PATH_LENGTH) >= 0) {
303 rv = (*env)->NewString(env, canonicalPath, (jsize)wcslen(canonicalPath));
304 }
305 } END_UNICODE_STRING(env, pathWithCanonicalPrefix);
306 } END_UNICODE_STRING(env, canonicalPrefix);
307 if (rv == NULL && !(*env)->ExceptionCheck(env)) {
308 JNU_ThrowIOExceptionWithLastError(env, "Bad pathname");
309 }
310 return rv;
311 }
312
313 /* -- Attribute accessors -- */
314
315 /* Check whether or not the file name in "path" is a Windows reserved
316 device name (CON, PRN, AUX, NUL, COM[1-9], LPT[1-9]) based on the
317 returned result from GetFullPathName, which should be in thr form of
318 "\\.\[ReservedDeviceName]" if the path represents a reserved device
319 name.
320 Note1: GetFullPathName doesn't think "CLOCK$" (which is no longer
321 important anyway) is a device name, so we don't check it here.
322 GetFileAttributesEx will catch it later by returning 0 on NT/XP/
323 200X.
324
325 Note2: Theoretically the implementation could just lookup the table
326 below linearly if the first 4 characters of the fullpath returned
327 from GetFullPathName are "\\.\". The current implementation should
607 if (pathbuf == NULL) {
608 return JNI_FALSE;
609 }
610 if (removeFileOrDirectory(pathbuf) == 0) {
611 rv = JNI_TRUE;
612 }
613 free(pathbuf);
614 return rv;
615 }
616
617 JNIEXPORT jobjectArray JNICALL
618 Java_java_io_WinNTFileSystem_list(JNIEnv *env, jobject this, jobject file)
619 {
620 WCHAR *search_path;
621 HANDLE handle;
622 WIN32_FIND_DATAW find_data;
623 int len, maxlen;
624 jobjectArray rv, old;
625 DWORD fattr;
626 jstring name;
627 jclass str_class;
628 WCHAR *pathbuf;
629
630 str_class = JNU_ClassString(env);
631 CHECK_NULL_RETURN(str_class, NULL);
632
633 pathbuf = fileToNTPath(env, file, ids.path);
634 if (pathbuf == NULL)
635 return NULL;
636 search_path = (WCHAR*)malloc(2*wcslen(pathbuf) + 6);
637 if (search_path == 0) {
638 free (pathbuf);
639 errno = ENOMEM;
640 JNU_ThrowOutOfMemoryError(env, "native memory allocation faiuled");
641 return NULL;
642 }
643 wcscpy(search_path, pathbuf);
644 free(pathbuf);
645 fattr = GetFileAttributesW(search_path);
646 if (fattr == INVALID_FILE_ATTRIBUTES) {
647 free(search_path);
648 return NULL;
649 } else if ((fattr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
650 free(search_path);
651 return NULL;
652 }
653
661 /* Append "*", or possibly "\\*", to path */
662 if ((search_path[0] == L'\\' && search_path[1] == L'\0') ||
663 (search_path[1] == L':'
664 && (search_path[2] == L'\0'
665 || (search_path[2] == L'\\' && search_path[3] == L'\0')))) {
666 /* No '\\' needed for cases like "\" or "Z:" or "Z:\" */
667 wcscat(search_path, L"*");
668 } else {
669 wcscat(search_path, L"\\*");
670 }
671
672 /* Open handle to the first file */
673 handle = FindFirstFileW(search_path, &find_data);
674 free(search_path);
675 if (handle == INVALID_HANDLE_VALUE) {
676 if (GetLastError() != ERROR_FILE_NOT_FOUND) {
677 // error
678 return NULL;
679 } else {
680 // No files found - return an empty array
681 rv = (*env)->NewObjectArray(env, 0, str_class, NULL);
682 return rv;
683 }
684 }
685
686 /* Allocate an initial String array */
687 len = 0;
688 maxlen = 16;
689 rv = (*env)->NewObjectArray(env, maxlen, str_class, NULL);
690 if (rv == NULL) // Couldn't allocate an array
691 return NULL;
692 /* Scan the directory */
693 do {
694 if (!wcscmp(find_data.cFileName, L".")
695 || !wcscmp(find_data.cFileName, L".."))
696 continue;
697 name = (*env)->NewString(env, find_data.cFileName,
698 (jsize)wcslen(find_data.cFileName));
699 if (name == NULL)
700 return NULL; // error;
701 if (len == maxlen) {
702 old = rv;
703 rv = (*env)->NewObjectArray(env, maxlen <<= 1, str_class, NULL);
704 if (rv == NULL || JNU_CopyObjectArray(env, rv, old, len) < 0)
705 return NULL; // error
706 (*env)->DeleteLocalRef(env, old);
707 }
708 (*env)->SetObjectArrayElement(env, rv, len++, name);
709 (*env)->DeleteLocalRef(env, name);
710
711 } while (FindNextFileW(handle, &find_data));
712
713 if (GetLastError() != ERROR_NO_MORE_FILES)
714 return NULL; // error
715 FindClose(handle);
716
717 /* Copy the final results into an appropriately-sized array */
718 old = rv;
719 rv = (*env)->NewObjectArray(env, len, str_class, NULL);
720 if (rv == NULL)
721 return NULL; /* error */
722 if (JNU_CopyObjectArray(env, rv, old, len) < 0)
723 return NULL; /* error */
724 return rv;
725 }
726
727
728 JNIEXPORT jboolean JNICALL
729 Java_java_io_WinNTFileSystem_createDirectory(JNIEnv *env, jobject this,
730 jobject file)
731 {
732 BOOL h = FALSE;
733 WCHAR *pathbuf = fileToNTPath(env, file, ids.path);
734 if (pathbuf == NULL) {
735 /* Exception is pending */
736 return JNI_FALSE;
737 }
738 h = CreateDirectoryW(pathbuf, NULL);
739 free(pathbuf);
|