src/windows/native/java/io/WinNTFileSystem_md.c

Print this page




  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);