8190737: use unicode version of the canonicalize() function to handle long path on windows

Also calling CreateFileW in zip_util.c to handle long path

Reviewed-by: sherman, iklam
This commit is contained in:
Calvin Cheung 2018-09-14 11:17:25 -07:00
parent d4612426ce
commit fcc414655b
5 changed files with 111 additions and 33 deletions

View File

@ -63,7 +63,7 @@ typedef struct {
#include <stddef.h> /* For uintptr_t */
#include <stdlib.h>
#define JVM_MAXPATHLEN _MAX_PATH
#define JVM_MAXPATHLEN 1024
#define JVM_R_OK 4
#define JVM_W_OK 2

View File

@ -100,6 +100,9 @@ DEF_STATIC_JNI_OnLoad
static ZFILE
ZFILE_Open(const char *fname, int flags) {
#ifdef WIN32
WCHAR *wfname, *wprefixed_fname;
size_t converted_chars, fname_length;
jlong fhandle;
const DWORD access =
(flags & O_RDWR) ? (GENERIC_WRITE | GENERIC_READ) :
(flags & O_WRONLY) ? GENERIC_WRITE :
@ -121,14 +124,37 @@ ZFILE_Open(const char *fname, int flags) {
FILE_ATTRIBUTE_NORMAL;
const DWORD flagsAndAttributes = maybeWriteThrough | maybeDeleteOnClose;
return (jlong) CreateFile(
fname, /* Wide char path name */
access, /* Read and/or write permission */
sharing, /* File sharing flags */
NULL, /* Security attributes */
disposition, /* creation disposition */
flagsAndAttributes, /* flags and attributes */
NULL);
fname_length = strlen(fname);
if (fname_length < MAX_PATH) {
return (jlong)CreateFile(
fname, /* path name in multibyte char */
access, /* Read and/or write permission */
sharing, /* File sharing flags */
NULL, /* Security attributes */
disposition, /* creation disposition */
flagsAndAttributes, /* flags and attributes */
NULL);
} else {
if ((wfname = (WCHAR*)malloc((fname_length + 1) * sizeof(WCHAR))) == NULL)
return (jlong)INVALID_HANDLE_VALUE;
if (mbstowcs_s(&converted_chars, wfname, fname_length + 1, fname, fname_length) != 0) {
free(wfname);
return (jlong)INVALID_HANDLE_VALUE;
}
wprefixed_fname = getPrefixed(wfname, (int)fname_length);
fhandle = (jlong)CreateFileW(
wprefixed_fname, /* Wide char path name */
access, /* Read and/or write permission */
sharing, /* File sharing flags */
NULL, /* Security attributes */
disposition, /* creation disposition */
flagsAndAttributes, /* flags and attributes */
NULL);
free(wfname);
free(wprefixed_fname);
return fhandle;
}
#else
return open(fname, flags, 0);
#endif

View File

@ -225,6 +225,8 @@ lastErrorReportable()
return 1;
}
int wcanonicalize(WCHAR *orig_path, WCHAR *result, int size);
/* Convert a pathname to canonical form. The input orig_path is assumed to
have been converted to native form already, via JVM_NativePath(). This is
necessary because _fullpath() rejects duplicate separator characters on
@ -237,6 +239,38 @@ canonicalize(char *orig_path, char *result, int size)
HANDLE h;
char path[1024]; /* Working copy of path */
char *src, *dst, *dend;
wchar_t *worig_path, *wresult;
size_t converted_chars = 0;
/* handle long path with length >= MAX_PATH */
if (strlen(orig_path) >= MAX_PATH) {
if ((worig_path = (WCHAR*)malloc(size * sizeof(WCHAR))) == NULL)
return -1;
if (mbstowcs_s(&converted_chars, worig_path, (size_t)size, orig_path, (size_t)(size - 1)) != 0) {
free(worig_path);
return -1;
}
if ((wresult = (WCHAR*)malloc(size * sizeof(WCHAR))) == NULL)
return -1;
if (wcanonicalize(worig_path, wresult, size) != 0) {
free(worig_path);
free(wresult);
return -1;
}
if (wcstombs_s(&converted_chars, result, (size_t)size, wresult, (size_t)(size - 1)) != 0) {
free(worig_path);
free(wresult);
return -1;
}
free(worig_path);
free(wresult);
return 0;
}
/* Reject paths that contain wildcards */
if (wild(orig_path)) {
@ -245,15 +279,15 @@ canonicalize(char *orig_path, char *result, int size)
}
/* Collapse instances of "foo\.." and ensure absoluteness. Note that
contrary to the documentation, the _fullpath procedure does not require
the drive to be available. It also does not reliably change all
occurrences of '/' to '\\' on Win95, so now JVM_NativePath does that. */
if(!_fullpath(path, orig_path, sizeof(path))) {
contrary to the documentation, the _fullpath procedure does not require
the drive to be available. It also does not reliably change all
occurrences of '/' to '\\' on Win95, so now JVM_NativePath does that. */
if (!_fullpath(path, orig_path, sizeof(path))) {
return -1;
}
/* Correction for Win95: _fullpath may leave a trailing "\\"
on a UNC pathname */
on a UNC pathname */
if ((path[0] == '\\') && (path[1] == '\\')) {
char *p = path + strlen(path);
if ((p[-1] == '\\') && !islb(p[-2])) {
@ -281,16 +315,16 @@ canonicalize(char *orig_path, char *result, int size)
char *p;
p = nextsep(src + 2); /* Skip past host name */
if (!*p) {
/* A UNC pathname must begin with "\\\\host\\share",
so reject this path as invalid if there is no share name */
/* A UNC pathname must begin with "\\\\host\\share",
so reject this path as invalid if there is no share name */
errno = EINVAL;
return -1;
}
p = nextsep(p + 1); /* Skip past share name */
if (!(dst = cp(dst, dend, '\0', src, p))) {
return -1;
}
src = p;
}
p = nextsep(p + 1); /* Skip past share name */
if (!(dst = cp(dst, dend, '\0', src, p))) {
return -1;
}
src = p;
} else {
/* Invalid path */
errno = EINVAL;
@ -309,11 +343,11 @@ canonicalize(char *orig_path, char *result, int size)
}
/* At this point we have copied either a drive specifier ("z:") or a UNC
prefix ("\\\\host\\share") to the result buffer, and src points to the
first byte of the remainder of the path. We now scan through the rest
of the path, looking up each prefix in order to find the true name of
the last element of each prefix, thereby computing the full true name of
the original path. */
prefix ("\\\\host\\share") to the result buffer, and src points to the
first byte of the remainder of the path. We now scan through the rest
of the path, looking up each prefix in order to find the true name of
the last element of each prefix, thereby computing the full true name of
the original path. */
while (*src) {
char *p = nextsep(src + 1); /* Find next separator */
char c = *p;
@ -325,8 +359,8 @@ canonicalize(char *orig_path, char *result, int size)
/* Lookup succeeded; append true name to result and continue */
FindClose(h);
if (!(dst = cp(dst, dend, '\\',
fd.cFileName,
fd.cFileName + strlen(fd.cFileName)))) {
fd.cFileName,
fd.cFileName + strlen(fd.cFileName)))) {
return -1;
}
src = p;
@ -344,8 +378,8 @@ canonicalize(char *orig_path, char *result, int size)
}
if (dst >= dend) {
errno = ENAMETOOLONG;
return -1;
errno = ENAMETOOLONG;
return -1;
}
*dst = '\0';
return 0;
@ -587,7 +621,7 @@ wcanonicalizeWithPrefix(WCHAR *canonicalPrefix, WCHAR *pathWithCanonicalPrefix,
*/
/* copy \\?\ or \\?\UNC\ to the front of path*/
WCHAR*
__declspec(dllexport) WCHAR*
getPrefixed(const WCHAR* path, int pathlen) {
WCHAR* pathbuf = (WCHAR*)malloc((pathlen + 10) * sizeof (WCHAR));
if (pathbuf != 0) {

View File

@ -38,7 +38,7 @@
*/
WCHAR* pathToNTPath(JNIEnv *env, jstring path, jboolean throwFNFE);
WCHAR* fileToNTPath(JNIEnv *env, jobject file, jfieldID id);
WCHAR* getPrefixed(const WCHAR* path, int pathlen);
__declspec(dllexport) WCHAR* getPrefixed(const WCHAR* path, int pathlen);
WCHAR* currentDir(int di);
int currentDirLength(const WCHAR* path, int pathlen);
int handleAvailable(FD fd, jlong *pbytes);

View File

@ -29,6 +29,7 @@
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.management
* jdk.jartool/sun.tools.jar
* @run main LongBCP
*/
@ -84,6 +85,23 @@ public class LongBCP {
output.shouldContain("Hello World")
.shouldHaveExitValue(0);
// create a hello.jar
sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar");
String helloJar = destDir.toString() + File.separator + "hello.jar";
if (!jarTool.run(new String[]
{"-cf", helloJar, "-C", destDir.toString(), "Hello.class"})) {
throw new RuntimeException("Could not write the Hello jar file");
}
// run with long bootclasspath to hello.jar
bootCP = "-Xbootclasspath/a:" + helloJar;
pb = ProcessTools.createJavaProcessBuilder(
bootCP, "Hello");
output = new OutputAnalyzer(pb.start());
output.shouldContain("Hello World")
.shouldHaveExitValue(0);
// relative path tests
// We currently cannot handle relative path specified in the
// -Xbootclasspath/a on windows.