Skip to content

Commit f83e55c

Browse files
committed
Add jffi.extract.name for specific file
Normally the library is extracted to a temp directory with an appropriately-mangled temp name, but on platforms that cannot delete the file before exiting the JVM this leaves those library files to accumulate. This change builds on the jffi.extract.dir property and adds jffi.extract.name to specify a specific filename to use every time, reusing any existing file at that location. Depending on how these two properties are combined, the file will be extracted as follows: * Set neither: file will be extracted with a temp name under the default temp dir, with attempt to delete and no reuse. * Set both: file will be the given name in the given path, reused if existing or extracted otherwise. * Set only dir: file will be extracted with a temp name under the specified directory, with attempt to delete and no reuse. * Set only name: file will be extracted with the given name under the default temp dir, reused if existing or extracted otherwise. Note that this does not verify that the loaded file matches the one bundled with jffi. This is left up to the user, since any verification of the existing file will be subject to TOC-to-TOU vulnerability. It is not possible to have the JVM atomically verify and load the given file. This partially addresses #97 by allowing Windows users to specify a known file path to reuse across runs.
1 parent 92cefde commit f83e55c

File tree

2 files changed

+68
-16
lines changed

2 files changed

+68
-16
lines changed

src/main/java/com/kenai/jffi/internal/StubLoader.java

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,25 @@ public class StubLoader {
6767
private static volatile Throwable failureCause = null;
6868
private static volatile boolean loaded = false;
6969
private static final File jffiExtractDir;
70+
private static final String jffiExtractName;
71+
72+
private static final String JFFI_EXTRACT_DIR = "jffi.extract.dir";
73+
private static final String JFFI_EXTRACT_NAME = "jffi.extract.name";
7074

7175
static {
72-
String extractDir = System.getProperty("jffi.extract.dir");
76+
String extractDir = System.getProperty(JFFI_EXTRACT_DIR);
7377
if (extractDir != null) {
7478
jffiExtractDir = new File(extractDir);
7579
} else {
7680
jffiExtractDir = null;
7781
}
82+
83+
String extractName = System.getProperty(JFFI_EXTRACT_NAME);
84+
if (extractName != null) {
85+
jffiExtractName = extractName;
86+
} else {
87+
jffiExtractName = null;
88+
}
7889
}
7990

8091
public static final boolean isLoaded() {
@@ -400,23 +411,25 @@ private static void loadFromJar(File tmpDirFile) throws IOException, LinkageErro
400411
File dstFile;
401412

402413
// Install the stub library to a temporary location
414+
String jffiExtractName = StubLoader.jffiExtractName;
403415
try {
416+
dstFile = calculateExtractPath(tmpDirFile, jffiExtractName);
417+
418+
if (dstFile.exists()) {
419+
// attempt to load existing file
420+
// TODO: verify file matches bundled library
421+
} else {
422+
// Write the library to the tempfile
423+
FileOutputStream os = new FileOutputStream(dstFile);
424+
try {
425+
ReadableByteChannel srcChannel = Channels.newChannel(is);
404426

405-
// Create tempfile.
406-
dstFile = null == tmpDirFile ? File.createTempFile("jffi", "." + dlExtension()):
407-
File.createTempFile("jffi", "." + dlExtension(), tmpDirFile);
408-
dstFile.deleteOnExit();
409-
410-
// Write the library to the tempfile
411-
FileOutputStream os = new FileOutputStream(dstFile);
412-
try {
413-
ReadableByteChannel srcChannel = Channels.newChannel(is);
414-
415-
for (long pos = 0; is.available() > 0; ) {
416-
pos += os.getChannel().transferFrom(srcChannel, pos, Math.max(4096, is.available()));
427+
for (long pos = 0; is.available() > 0; ) {
428+
pos += os.getChannel().transferFrom(srcChannel, pos, Math.max(4096, is.available()));
429+
}
430+
} finally {
431+
os.close();
417432
}
418-
} finally {
419-
os.close();
420433
}
421434
} catch (IOException ioe) {
422435
// If we get here it means we are unable to write the stub library to the system default temp location.
@@ -427,13 +440,35 @@ private static void loadFromJar(File tmpDirFile) throws IOException, LinkageErro
427440

428441
try {
429442
System.load(dstFile.getAbsolutePath());
430-
dstFile.delete();
443+
if (null == jffiExtractName) dstFile.delete();
431444
} catch (UnsatisfiedLinkError ule) {
432445
// If we get here it means the file wrote to temp ok but can't be loaded from there.
433446
throw tempLoadError(ule);
434447
}
435448
}
436449

450+
static File calculateExtractPath(File tmpDirFile, String jffiExtractName) throws IOException {
451+
File dstFile;
452+
if (null == tmpDirFile) {
453+
if (null == jffiExtractName) {
454+
// Create tempfile.
455+
dstFile = File.createTempFile("jffi", "." + dlExtension());
456+
dstFile.deleteOnExit();
457+
} else {
458+
dstFile = new File(System.getProperty("java.io.tmpdir"), jffiExtractName);
459+
}
460+
} else {
461+
if (null == jffiExtractName) {
462+
// Create tempfile.
463+
dstFile = File.createTempFile("jffi", "." + dlExtension(), tmpDirFile);
464+
dstFile.deleteOnExit();
465+
} else {
466+
dstFile = new File(tmpDirFile, jffiExtractName);
467+
}
468+
}
469+
return dstFile;
470+
}
471+
437472
private static IOException tempReadonlyError(IOException ioe) {
438473
return new IOException(
439474
TMPDIR_WRITE_ERROR + " " +
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.kenai.jffi.internal;
2+
3+
import com.kenai.jffi.internal.StubLoader;
4+
import org.junit.Assert;
5+
import org.junit.Test;
6+
7+
import java.io.File;
8+
9+
public class StubLoaderTest {
10+
@Test
11+
public void testExtractName() throws Throwable {
12+
File path = StubLoader.calculateExtractPath(new File("foo"), "bar");
13+
14+
Assert.assertEquals("foo", path.getParent());
15+
Assert.assertEquals("bar", path.getName());
16+
}
17+
}

0 commit comments

Comments
 (0)