Skip to content

Commit

Permalink
Merge pull request #27 from gmerkin/issue-26
Browse files Browse the repository at this point in the history
Fix issue #26: fall back on loading DLL via temp file
  • Loading branch information
oleg-nenashev authored Oct 13, 2016
2 parents 7f8f128 + bddd254 commit 331751d
Showing 1 changed file with 91 additions and 99 deletions.
190 changes: 91 additions & 99 deletions src/main/java/org/jvnet/winp/Native.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
* @author Kohsuke Kawaguchi
*/
class Native {

public static final String DLL_NAME = "64".equals(System.getProperty("sun.arch.data.model")) ? "winp.x64" : "winp";

native static boolean kill(int pid, boolean recursive);
native static boolean isCriticalProcess(int pid);
native static int setPriority(int pid, int value);
Expand Down Expand Up @@ -78,114 +81,103 @@ private static String md5(URL res) {
}

private static void load() {
// are we on win32 or win64? err on 32bit side
boolean win64 = "64".equals(System.getProperty("sun.arch.data.model"));
String dllName = win64? "winp.x64" : "winp";

// try loading winp.dll in the same directory as winp.jar
final URL res = Native.class.getClassLoader().getResource(dllName+".dll");
if(res!=null) {
String url = res.toExternalForm();

//patched by JetBrains: do not try to unpack the dll file to the directory containing the jar file by default.
// It can fail because the process has no rights to write to that directory and also pollutes the project directories if the jar is used in development mode.
boolean unpackToParentDir = Boolean.parseBoolean(System.getProperty(UNPACK_DLL_TO_PARENT_DIR, "true"));

if(unpackToParentDir && (url.startsWith("jar:") || url.startsWith("wsjar:"))) {
int idx = url.lastIndexOf('!');
String filePortion = url.substring(url.indexOf(':')+1,idx);
while(filePortion.startsWith("/"))
filePortion = filePortion.substring(1);

if(filePortion.startsWith("file:")) {
filePortion = filePortion.substring(5);
if(filePortion.startsWith("///")) {
// JDK on Unix uses file:/home/kohsuke/abc, whereas
// I believe RFC says file:///home/kohsuke/abc/... is correct.
filePortion = filePortion.substring(2);
} else
if(filePortion.startsWith("//")) {
// this indicates file://host/path-in-host format
// Windows maps UNC path to this. On Unix, there's no well defined
// semantics for this.
}

filePortion = URLDecoder.decode(filePortion);
String preferred = System.getProperty(DLL_TARGET);
File jarFile = new File(filePortion.replace('/',File.separatorChar));
File dllFile = new File(preferred != null ? new File(preferred) : jarFile.getParentFile(),dllName+'.'+md5(res)+".dll");
if(!dllFile.exists()) {
// try to extract from within the jar
try {
copyStream(
res.openStream(),
new FileOutputStream(dllFile));
} catch (IOException e) {
LOGGER.log(Level.WARNING, "Failed to write "+dllFile, e);
}
}

loadDll(dllFile);
return;
}
}
if(url.startsWith("file:")) {
// during debug
File f;
try {
f = new File(res.toURI());
} catch(URISyntaxException e) {
f = new File(res.getPath());
}
loadDll(f);
return;

final URL res = Native.class.getClassLoader().getResource(DLL_NAME + ".dll");

try {
if (res != null) {
loadByUrl(res);
} else {
// we don't know where winp.dll is, so let's just hope the user put it somewhere
System.loadLibrary(DLL_NAME);
}
} catch (Throwable cause) {

File dll=null;
UnsatisfiedLinkError error = new UnsatisfiedLinkError("Unable to load " + DLL_NAME + ".dll");
error.initCause(cause);
throw error;
}
}

private static void loadByUrl(URL res) throws IOException {

String url = res.toExternalForm();

if (url.startsWith("file:")) {
// during debug
File f;
try {
dll = File.createTempFile(dllName, ".dll");
dll.deleteOnExit();
copyStream(res.openStream(),new FileOutputStream(dll));
loadDll(dll);
return;
} catch (IOException e) {
LOGGER.log(Level.WARNING, "Failed to write "+dllName+".dll", e);
// report the UnsatisfiedLinkError below, to encourage the user to put winp.dll to
// java.library.path
} catch (LinkageError e) {
LOGGER.log(Level.WARNING, "Failed to load winp.dll from "+dll, e);
// ditto
f = new File(res.toURI());
} catch (URISyntaxException e) {
f = new File(res.getPath());
}
loadDll(f);
return;
}

// we don't know where winp.dll is, so let's just hope the user put it somewhere
try {
// load the native part of the code.
// first try java.library.path
System.loadLibrary(dllName);
} catch( Throwable cause ) {
// try to put winp.dll into a temporary directory
if(res!=null) {
File dll=null;
try {
dll = File.createTempFile(dllName, "dll");
copyStream(res.openStream(),new FileOutputStream(dll));
loadDll(dll);
return;
} catch (IOException e) {
LOGGER.log(Level.WARNING, "Failed to write "+dllName+".dll", e);
// report the UnsatisfiedLinkError below, to encourage the user to put winp.dll to
// java.library.path
} catch (LinkageError e) {
LOGGER.log(Level.WARNING, "Failed to load winp.dll from "+dll, e);
// ditto
}
}
File dllFile = extractToStaticLocation(res);
loadDll(dllFile);
return;
} catch (Throwable e) {
LOGGER.log(Level.WARNING, "Failed to load DLL from static location", e);
}

UnsatisfiedLinkError error = new UnsatisfiedLinkError("Unable to load "+dllName+".dll");
error.initCause(cause);
throw error;
File dllFile = extractToTmpLocation(res);
loadDll(dllFile);
}

private static File extractToStaticLocation(URL url) throws IOException {

File jarFile = getJarFile(url);
if (jarFile == null) {
throw new RuntimeException("Failed to locate JAR file by URL " + url);
}

String preferred = System.getProperty(DLL_TARGET);
File destFile = new File(preferred != null ? new File(preferred) : jarFile.getParentFile(), DLL_NAME + '.' + md5(url) + ".dll");
if (!destFile.exists()) {
copyStream(url.openStream(), new FileOutputStream(destFile));
}
return destFile;
}

private static File extractToTmpLocation(URL res) throws IOException {

File tmpFile = File.createTempFile(DLL_NAME, ".dll");
tmpFile.deleteOnExit();
copyStream(res.openStream(), new FileOutputStream(tmpFile));
return tmpFile;
}

private static File getJarFile(URL res) {

String url = res.toExternalForm();
if (!(url.startsWith("jar:") || url.startsWith("wsjar:"))) {
return null;
}

int idx = url.lastIndexOf('!');
String filePortion = url.substring(url.indexOf(':') + 1, idx);
while (filePortion.startsWith("/"))
filePortion = filePortion.substring(1);

if (!filePortion.startsWith("file:")) {
return null;
}
filePortion = filePortion.substring(5);
if (filePortion.startsWith("///")) {
// JDK on Unix uses file:/home/kohsuke/abc, whereas
// I believe RFC says file:///home/kohsuke/abc/... is correct.
filePortion = filePortion.substring(2);
} else if (filePortion.startsWith("//")) {
// this indicates file://host/path-in-host format
// Windows maps UNC path to this. On Unix, there's no well defined
// semantics for this.
}

filePortion = URLDecoder.decode(filePortion);
return new File(filePortion.replace('/', File.separatorChar));
}

/**
Expand Down

0 comments on commit 331751d

Please sign in to comment.