8218547: Simplify JLI_Open on Windows in native code (libjli)
authormbaesken
Tue, 02 Apr 2019 13:54:00 +0200
changeset 54434 dad2c80ae0b2
parent 54433 b34bcfbcc2fd
child 54435 776b261dff84
8218547: Simplify JLI_Open on Windows in native code (libjli) Reviewed-by: alanb, clanger
src/java.base/windows/native/libjli/java_md.c
test/jdk/tools/launcher/Arrrghs.java
--- a/src/java.base/windows/native/libjli/java_md.c	Fri Apr 05 07:59:13 2019 +0200
+++ b/src/java.base/windows/native/libjli/java_md.c	Tue Apr 02 13:54:00 2019 +0200
@@ -41,8 +41,6 @@
 #define JVM_DLL "jvm.dll"
 #define JAVA_DLL "java.dll"
 
-#define ELP_PREFIX L"\\\\?\\"
-
 /*
  * Prototypes.
  */
@@ -497,57 +495,67 @@
     return rc;
 }
 
-/* On Windows, if _open fails, retry again with CreateFileW and
- *  "\\?\" prefix ( extended-length paths) - this allows to open paths with larger file names;
- * otherwise we run into the MAX_PATH limitation */
-int JLI_Open(const char* name, int flags) {
-    int fd = _open(name, flags);
-    if (fd == -1 && errno == ENOENT) {
-        wchar_t* wname = NULL;
-        wchar_t* wfullname = NULL;
-        wchar_t* wfullname_w_prefix = NULL;
-        size_t wnamelen, wfullnamelen, elplen;
-        HANDLE h;
-
-        wnamelen = strlen(name) + 1;
-        wname = (wchar_t*) malloc(wnamelen*sizeof(wchar_t));
-        if (wname == NULL) {
-            goto end;
-        }
-        if (mbstowcs(wname, name, wnamelen - 1) == -1) {
-            goto end;
+/* taken from hotspot and slightly adjusted for jli lib;
+ * creates a UNC/ELP path from input 'path'
+ * the return buffer is allocated in C heap and needs to be freed using
+ * JLI_MemFree by the caller.
+ */
+static wchar_t* create_unc_path(const char* path, errno_t* err) {
+    wchar_t* wpath = NULL;
+    size_t converted_chars = 0;
+    size_t path_len = strlen(path) + 1; /* includes the terminating NULL */
+    if (path[0] == '\\' && path[1] == '\\') {
+        if (path[2] == '?' && path[3] == '\\') {
+            /* if it already has a \\?\ don't do the prefix */
+            wpath = (wchar_t*) JLI_MemAlloc(path_len * sizeof(wchar_t));
+            if (wpath != NULL) {
+                *err = mbstowcs_s(&converted_chars, wpath, path_len, path, path_len);
+            } else {
+                *err = ENOMEM;
+            }
+        } else {
+            /* only UNC pathname includes double slashes here */
+            wpath = (wchar_t*) JLI_MemAlloc((path_len + 7) * sizeof(wchar_t));
+            if (wpath != NULL) {
+                wcscpy(wpath, L"\\\\?\\UNC\0");
+                *err = mbstowcs_s(&converted_chars, &wpath[7], path_len, path, path_len);
+            } else {
+                *err = ENOMEM;
+            }
         }
-        wname[wnamelen - 1] = L'\0';
-        wfullname = _wfullpath(wfullname, wname, 0);
-        if (wfullname == NULL) {
-            goto end;
+    } else {
+        wpath = (wchar_t*) JLI_MemAlloc((path_len + 4) * sizeof(wchar_t));
+        if (wpath != NULL) {
+            wcscpy(wpath, L"\\\\?\\\0");
+            *err = mbstowcs_s(&converted_chars, &wpath[4], path_len, path, path_len);
+        } else {
+            *err = ENOMEM;
         }
-
-        wfullnamelen = wcslen(wfullname);
-        if (wfullnamelen > 247) {
-            elplen = wcslen(ELP_PREFIX);
-            wfullname_w_prefix = (wchar_t*) malloc((elplen+wfullnamelen+1)*sizeof(wchar_t));
-            wcscpy(wfullname_w_prefix, ELP_PREFIX);
-            wcscpy(wfullname_w_prefix+elplen, wfullname);
+    }
+    return wpath;
+}
 
-            h = CreateFileW(wfullname_w_prefix, GENERIC_READ, FILE_SHARE_READ, NULL,
-                            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-            if (h == INVALID_HANDLE_VALUE) {
-                goto end;
-            }
-            /* associates fd with handle */
-            fd = _open_osfhandle((intptr_t)h, _O_RDONLY);
+int JLI_Open(const char* name, int flags) {
+    int fd;
+    if (strlen(name) < MAX_PATH) {
+        fd = _open(name, flags);
+    } else {
+        errno_t err = ERROR_SUCCESS;
+        wchar_t* wpath = create_unc_path(name, &err);
+        if (err != ERROR_SUCCESS) {
+            if (wpath != NULL) JLI_MemFree(wpath);
+            errno = err;
+            return -1;
         }
-end:
-        free(wname);
-        free(wfullname);
-        free(wfullname_w_prefix);
+        fd = _wopen(wpath, flags);
+        if (fd == -1) {
+            errno = GetLastError();
+        }
+        JLI_MemFree(wpath);
     }
     return fd;
 }
 
-
-
 JNIEXPORT void JNICALL
 JLI_ReportErrorMessage(const char* fmt, ...) {
     va_list vl;
--- a/test/jdk/tools/launcher/Arrrghs.java	Fri Apr 05 07:59:13 2019 +0200
+++ b/test/jdk/tools/launcher/Arrrghs.java	Tue Apr 02 13:54:00 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,7 +24,7 @@
 /**
  * @test
  * @bug 5030233 6214916 6356475 6571029 6684582 6742159 4459600 6758881 6753938
- *      6894719 6968053 7151434 7146424 8007333 8077822 8143640 8132379
+ *      6894719 6968053 7151434 7146424 8007333 8077822 8143640 8132379 8218547
  * @summary Argument parsing validation.
  * @modules jdk.compiler
  *          jdk.zipfs
@@ -36,6 +36,9 @@
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -55,20 +58,6 @@
      *
      */
 
-    /*
-     * SIGH, On Windows all strings are quoted, we need to unwrap it
-     */
-    private static String removeExtraQuotes(String in) {
-        if (isWindows) {
-            // Trim the string and remove the enclosed quotes if any.
-            in = in.trim();
-            if (in.startsWith("\"") && in.endsWith("\"")) {
-                return in.substring(1, in.length()-1);
-            }
-        }
-        return in;
-    }
-
     // the pattern we hope to see in the output
     static final Pattern ArgPattern = Pattern.compile("\\s*argv\\[[0-9]*\\].*=.*");
 
@@ -490,6 +479,27 @@
     }
 
     /*
+     * Tests -jar command on a jar file with "long" (> 260 chars) full path on Windows
+     */
+    @Test
+    void testLongPathJarFile() throws IOException {
+        if (!isWindows) {
+            return;
+        }
+        // put the jar file to a location with long path
+        String longPathPart = "longpathtest_longpathtest/";
+        String longPathStr = longPathPart.repeat(15);
+        Path longPath = Paths.get(longPathStr);
+        Path jarPath = Files.createDirectories(longPath).resolve("elp.jar");
+        File elp = jarPath.toFile();
+        createJar(elp, new File("Foo"), "public static void main(String[] args){ System.out.println(\"Hello from ELP\"); }");
+        System.out.println("execute " + elp.getAbsolutePath());
+        TestResult tr = doExec(javaCmd, "-jar", elp.getAbsolutePath());
+        tr.checkPositive();
+        tr.contains("Hello from ELP");
+    }
+
+    /*
      * Tests various dispositions of the main method, these tests are limited
      * to English locales as they check for error messages that are localized.
      */