# HG changeset patch # User mgronlun # Date 1535054136 -7200 # Thu Aug 23 21:55:36 2018 +0200 # Node ID e67040163fafd54f576289d0d1420409b6ad6131 # Parent 7113784d24eb3c1ce86202ba94a9984edf71a87b [mq]: wcanonicalize_v2 diff --git a/src/java.base/windows/classes/java/io/WinNTFileSystem.java b/src/java.base/windows/classes/java/io/WinNTFileSystem.java --- a/src/java.base/windows/classes/java/io/WinNTFileSystem.java +++ b/src/java.base/windows/classes/java/io/WinNTFileSystem.java @@ -528,7 +528,15 @@ /* -- Attribute accessors -- */ @Override - public native int getBooleanAttributes(File f); + public int getBooleanAttributes(File f) { + if (f != null) { + String path = f.getPath(); + return path != null ? getBooleanAttributes0(path) : 0; + } + return 0; + } + + private native int getBooleanAttributes0(String path); @Override public native boolean checkAccess(File f, int access); diff --git a/src/java.base/windows/native/libjava/WinNTFileSystem_md.c b/src/java.base/windows/native/libjava/WinNTFileSystem_md.c --- a/src/java.base/windows/native/libjava/WinNTFileSystem_md.c +++ b/src/java.base/windows/native/libjava/WinNTFileSystem_md.c @@ -193,9 +193,8 @@ */ DWORD getFinalAttributesIfReparsePoint(WCHAR *path, DWORD a) { - if ((a != INVALID_FILE_ATTRIBUTES) && - ((a & FILE_ATTRIBUTE_REPARSE_POINT) != 0)) - { + assert((a & INVALID_FILE_ATTRIBUTES) != INVALID_FILE_ATTRIBUTES); + if (a & FILE_ATTRIBUTE_REPARSE_POINT) { BY_HANDLE_FILE_INFORMATION finfo; BOOL res = getFileInformation(path, &finfo); a = (res) ? finfo.dwFileAttributes : INVALID_FILE_ATTRIBUTES; @@ -209,25 +208,31 @@ */ DWORD getFinalAttributes(WCHAR *path) { - DWORD attr = INVALID_FILE_ATTRIBUTES; - - WIN32_FILE_ATTRIBUTE_DATA wfad; - WIN32_FIND_DATAW wfd; - HANDLE h; - - if (GetFileAttributesExW(path, GetFileExInfoStandard, &wfad)) { - attr = getFinalAttributesIfReparsePoint(path, wfad.dwFileAttributes); + DWORD attr = getAttributes(path); + if (INVALID_FILE_ATTRIBUTES != attr) { + return getFinalAttributesIfReparsePoint(path, attr); } else { - DWORD lerr = GetLastError(); + WIN32_FIND_DATAW wfd; + HANDLE h; + const DWORD lerr = GetLastError(); if ((lerr == ERROR_SHARING_VIOLATION || lerr == ERROR_ACCESS_DENIED) && (h = FindFirstFileW(path, &wfd)) != INVALID_HANDLE_VALUE) { - attr = getFinalAttributesIfReparsePoint(path, wfd.dwFileAttributes); + if (wfd.dwFileAttributes != INVALID_FILE_ATTRIBUTES) { + attr = getFinalAttributesIfReparsePoint(path, wfd.dwFileAttributes); + } FindClose(h); } } return attr; } +static jint convertAttributes(DWORD file_attributes) { + return INVALID_FILE_ATTRIBUTES == file_attributes ? 0 : + (java_io_FileSystem_BA_EXISTS | ((file_attributes & FILE_ATTRIBUTE_DIRECTORY) ? + java_io_FileSystem_BA_DIRECTORY : java_io_FileSystem_BA_REGULAR) | + ((file_attributes & FILE_ATTRIBUTE_HIDDEN) ? java_io_FileSystem_BA_HIDDEN : 0)); +} + JNIEXPORT jstring JNICALL Java_java_io_WinNTFileSystem_canonicalize0(JNIEnv *env, jobject this, jstring pathname) @@ -236,11 +241,7 @@ WCHAR canonicalPath[MAX_PATH_LENGTH]; WITH_UNICODE_STRING(env, pathname, path) { - /* we estimate the max length of memory needed as - "currentDir. length + pathname.length" - */ - int len = (int)wcslen(path); - len += currentDirLength(path, len); + const int len = (int)wcslen(path); if (len > MAX_PATH_LENGTH - 1) { WCHAR *cp = (WCHAR*)malloc(len * sizeof(WCHAR)); if (cp != NULL) { @@ -350,6 +351,70 @@ return FALSE; } +static BOOL isReservedDeviceNameCanonicalizedW(WCHAR* path, DWORD len) { + assert(path); + +#define BUFSIZE 9 + if ((len == BUFSIZE - 1 || len == BUFSIZE - 2) && + path[0] == L'\\' && path[1] == L'\\' && + path[2] == L'.' && path[3] == L'\\') { + WCHAR* dname = _wcsupr(path + 4); + if (wcscmp(dname, L"CON") == 0 || + wcscmp(dname, L"PRN") == 0 || + wcscmp(dname, L"AUX") == 0 || + wcscmp(dname, L"NUL") == 0) + return TRUE; + if ((wcsncmp(dname, L"COM", 3) == 0 || + wcsncmp(dname, L"LPT", 3) == 0) && + dname[3] - L'0' > 0 && + dname[3] - L'0' <= 9) + return TRUE; + } + return FALSE; +} + +static jint getBooleanAttributesForPath(const WCHAR* original_path, WCHAR* result, int len) { + assert(original_path); + assert(result); + + if (!expandPath(original_path, result, len)) { + return 0; + } + if (isReservedDeviceNameCanonicalizedW(result, len)) { + return 0; + } + return convertAttributes(getFinalAttributes(result)); +} + +JNIEXPORT jint JNICALL +Java_java_io_WinNTFileSystem_getBooleanAttributes0(JNIEnv *env, jobject this, jstring pathname) +{ + WCHAR canonicalPath[MAX_PATH_LENGTH]; + WCHAR* result = canonicalPath; + jint attributes = 0; + + assert(pathname); + + WITH_UNICODE_STRING(env, pathname, path) { + const int len = (int)wcslen(path); + if (len > MAX_PATH_LENGTH - 1) { + result = (WCHAR*)malloc(len * sizeof(WCHAR)); + if (result != NULL) { + attributes = getBooleanAttributesForPath(path, result, len); + free(result); + } else { + JNU_ThrowOutOfMemoryError(env, "native memory allocation failed"); + } + } else { + attributes = getBooleanAttributesForPath(path, result, MAX_PATH_LENGTH); + } + } END_UNICODE_STRING(env, path); + + return attributes; +} + +/* + JNIEXPORT jint JNICALL Java_java_io_WinNTFileSystem_getBooleanAttributes(JNIEnv *env, jobject this, jobject file) @@ -374,6 +439,7 @@ return rv; } +*/ JNIEXPORT jboolean JNICALL Java_java_io_WinNTFileSystem_checkAccess(JNIEnv *env, jobject this, @@ -384,10 +450,13 @@ if (pathbuf == NULL) return JNI_FALSE; attr = GetFileAttributesW(pathbuf); - attr = getFinalAttributesIfReparsePoint(pathbuf, attr); - free(pathbuf); - if (attr == INVALID_FILE_ATTRIBUTES) + if (attr != INVALID_FILE_ATTRIBUTES) { + attr = getFinalAttributesIfReparsePoint(pathbuf, attr); + free(pathbuf); + } else { + free(pathbuf); return JNI_FALSE; + } switch (access) { case java_io_FileSystem_ACCESS_READ: case java_io_FileSystem_ACCESS_EXECUTE: diff --git a/src/java.base/windows/native/libjava/canonicalize_md.c b/src/java.base/windows/native/libjava/canonicalize_md.c --- a/src/java.base/windows/native/libjava/canonicalize_md.c +++ b/src/java.base/windows/native/libjava/canonicalize_md.c @@ -404,11 +404,43 @@ return 0; } +/* Wide character version of canonicalize. Size is a wide-character size. */ + +int +wcanonicalize(WCHAR* orig_path, WCHAR* result, int size) +{ + assert(orig_path); + assert(result); + + /* Reject paths that contain wildcards */ + if (wwild(orig_path)) { + errno = EINVAL; + return -1; + } + + if (!expandPath(orig_path, result, (DWORD)size)) { + return -1; + } + + assert((int)wcslen(result) <= size); + assert(!wdots(result)); + + if (!(isDrivePrefix(result, TRUE) || isUNCPrefix(result))) { + errno = EINVAL; + return -1; + } + + if (!exists(result)) { + return lastErrorReportable() ? -1 : 0; + } + + return 0; +} /* Wide character version of canonicalize. Size is a wide-character size. */ int -wcanonicalize(WCHAR *orig_path, WCHAR *result, int size) +wcanonicalize_old(WCHAR *orig_path, WCHAR *result, int size) { WIN32_FIND_DATAW fd; HANDLE h; diff --git a/src/java.base/windows/native/libjava/io_util_md.c b/src/java.base/windows/native/libjava/io_util_md.c --- a/src/java.base/windows/native/libjava/io_util_md.c +++ b/src/java.base/windows/native/libjava/io_util_md.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -592,3 +593,45 @@ return -1; } } + +BOOL +isDrivePrefix(WCHAR* path, BOOL capitalize) { + assert(path); + if (((path[0] <= L'z' && path[0] >= L'a') || (path[0] <= L'Z' && path[0] >= L'A')) && + (path[1] == L':') && (path[2] == L'\\')) { + if (capitalize) { + /* Canonicalize drive letter */ + *path = (WCHAR)towupper(*path); + } + return TRUE; + } + return FALSE; +} + +BOOL +isUNCPrefix(const WCHAR* path) { + WCHAR* p; + assert(path); + /* valid UNC path ? */ + return ((path[0] == L'\\' && path[1] == L'\\' && + (p = wcschr(&path[2], L'\\')) && wcschr(p + 1, L'\\'))) ? TRUE : FALSE; +} + +BOOL +exists(const WCHAR* path) { + assert(path); + return INVALID_FILE_ATTRIBUTES != GetFileAttributesW(path) ? TRUE : FALSE; +} + +BOOL +expandPath(const WCHAR* orig, WCHAR* result, DWORD size) { + assert(orig); + assert(result); + return GetFullPathNameW(orig, size, result, NULL) ? TRUE : FALSE; +} + +DWORD +getAttributes(const WCHAR* path) { + assert(path); + return GetFileAttributesW(path); +} diff --git a/src/java.base/windows/native/libjava/io_util_md.h b/src/java.base/windows/native/libjava/io_util_md.h --- a/src/java.base/windows/native/libjava/io_util_md.h +++ b/src/java.base/windows/native/libjava/io_util_md.h @@ -49,6 +49,11 @@ jint handleWrite(FD fd, const void *buf, jint len); jint handleAppend(FD fd, const void *buf, jint len); void fileDescriptorClose(JNIEnv *env, jobject this); +BOOL isDrivePrefix(WCHAR* path, BOOL capitialize); +BOOL isUNCPrefix(const WCHAR* path); +BOOL exists(const WCHAR* path); +BOOL expandPath(const WCHAR* original_path, WCHAR* result, DWORD size); +DWORD getAttributes(const WCHAR* path); JNIEXPORT jlong JNICALL handleLseek(FD fd, jlong offset, jint whence);