diff --git a/netx/net/sourceforge/jnlp/cache/NativeLibraryStorage.java b/netx/net/sourceforge/jnlp/cache/NativeLibraryStorage.java new file mode 100644 --- /dev/null +++ b/netx/net/sourceforge/jnlp/cache/NativeLibraryStorage.java @@ -0,0 +1,162 @@ +package net.sourceforge.jnlp.cache; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import net.sourceforge.jnlp.runtime.JNLPRuntime; +import net.sourceforge.jnlp.util.FileUtils; + +/** + * Handles loading and access of native code loading through a JNLP application or applet. + * Stores native code in a temporary folder. + * Be sure to call cleanupTemporayFolder when finished with the object. + */ +public class NativeLibraryStorage { + private ResourceTracker tracker; + private List nativeSearchDirectories = new ArrayList(); + + /* Temporary directory to store native jar entries, added to our search path */ + private File jarEntryDirectory = null; + + public NativeLibraryStorage(ResourceTracker tracker) { + this.tracker = tracker; + } + + /** + * Clean up our temporary folder if we created one. + */ + public void cleanupTemporayFolder() { + if (jarEntryDirectory != null) { + if (JNLPRuntime.isDebug()) { + System.out.println("Cleaning up native directory" + jarEntryDirectory.getAbsolutePath()); + } + try { + FileUtils.recursiveDelete(jarEntryDirectory, + new File(System.getProperty("java.io.tmpdir"))); + jarEntryDirectory = null; + } catch (IOException e) { + /* + * failed to delete a file in tmpdir, no big deal (as well the VM + * might be shutting down at this point so no much we can do) + */ + } + } + } + + /** + * Adds the {@link File} to the search path of this {@link NativeLibraryStorage} + * when trying to find a native library + */ + public void addSearchDirectory(File directory) { + nativeSearchDirectories.add(directory); + } + + public List getSearchDirectories() { + return nativeSearchDirectories; + } + + /** + * Looks in the search directories for 'fileName', + * returning a path to the found file if it exists. + * Returns null otherwise. + */ + public File findLibrary(String fileName) { + for (File dir : getSearchDirectories()) { + File target = new File(dir, fileName); + if (target.exists()) + return target; + } + return null; + } + + /** + * Search for and enable any native code contained in a JAR by copying the + * native files into the filesystem. Called in the security context of the + * classloader. + */ + public void addSearchJar(URL jarLocation) { + if (JNLPRuntime.isDebug()) + System.out.println("Activate native: " + jarLocation); + + File localFile = tracker.getCacheFile(jarLocation); + if (localFile == null) + return; + + String[] librarySuffixes = { ".so", ".dylib", ".jnilib", ".framework", ".dll" }; + + try { + JarFile jarFile = new JarFile(localFile, false); + Enumeration entries = jarFile.entries(); + + while (entries.hasMoreElements()) { + JarEntry e = entries.nextElement(); + + if (e.isDirectory()) { + continue; + } + + String name = new File(e.getName()).getName(); + boolean isLibrary = false; + + for (String suffix : librarySuffixes) { + if (name.endsWith(suffix)) { + isLibrary = true; + break; + } + } + if (!isLibrary) { + continue; + } + + ensureNativeStoreDirectory(); + + File outFile = new File(jarEntryDirectory, name); + if (!outFile.isFile()) { + FileUtils.createRestrictedFile(outFile, true); + } + CacheUtil.streamCopy(jarFile.getInputStream(e), + new FileOutputStream(outFile)); + } + + jarFile.close(); + } catch (IOException ex) { + if (JNLPRuntime.isDebug()) + ex.printStackTrace(); + } + } + + private void ensureNativeStoreDirectory() { + if (jarEntryDirectory == null) { + jarEntryDirectory = createNativeStoreDirectory(); + addSearchDirectory(jarEntryDirectory); + } + } + + /** + * Create a random base directory to store native code files in. + */ + private static File createNativeStoreDirectory() { + final int rand = (int)((Math.random()*2 - 1) * Integer.MAX_VALUE); + File nativeDir = new File(System.getProperty("java.io.tmpdir") + + File.separator + "netx-native-" + + (rand & 0xFFFF)); + File parent = nativeDir.getParentFile(); + if (!parent.isDirectory() && !parent.mkdirs()) { + return null; + } + + try { + FileUtils.createRestrictedDirectory(nativeDir); + return nativeDir; + } catch (IOException e) { + return null; + } + } +} diff --git a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java --- a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java +++ b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java @@ -81,6 +81,7 @@ import net.sourceforge.jnlp.SecurityDesc import net.sourceforge.jnlp.Version; import net.sourceforge.jnlp.cache.CacheUtil; import net.sourceforge.jnlp.cache.IllegalResourceDescriptorException; +import net.sourceforge.jnlp.cache.NativeLibraryStorage; import net.sourceforge.jnlp.cache.ResourceTracker; import net.sourceforge.jnlp.cache.UpdatePolicy; import net.sourceforge.jnlp.security.AppVerifier; @@ -125,11 +126,8 @@ public class JNLPClassLoader extends URL * initialization of applets that share a unique key*/ private static Map uniqueKeyToLock = new HashMap(); - /** the directory for native code */ - private File nativeDir = null; // if set, some native code exists - - /** a list of directories that contain native libraries */ - private List nativeDirectories = Collections.synchronizedList(new LinkedList()); + /** Provides a search path & temporary storage for native code */ + private NativeLibraryStorage nativeLibraryStorage; /** security context */ private AccessControlContext acc = AccessController.getContext(); @@ -229,6 +227,8 @@ public class JNLPClassLoader extends URL this.updatePolicy = policy; this.resources = file.getResources(); + this.nativeLibraryStorage = new NativeLibraryStorage(tracker); + this.mainClass = mainName; AppVerifier verifier; @@ -268,21 +268,7 @@ public class JNLPClassLoader extends URL * there is one). Other classloaders (parent, peers) will all * cleanup things they created */ - if (nativeDir != null) { - if (JNLPRuntime.isDebug()) { - System.out.println("Cleaning up native directory" + nativeDir.getAbsolutePath()); - } - try { - FileUtils.recursiveDelete(nativeDir, - new File(System.getProperty("java.io.tmpdir"))); - } catch (IOException e) { - /* - * failed to delete a file in tmpdir, no big deal (not - * to mention that the VM is shutting down at this - * point so no much we can do) - */ - } - } + nativeLibraryStorage.cleanupTemporayFolder(); } }); } @@ -1347,7 +1333,7 @@ public class JNLPClassLoader extends URL } // some programs place a native library in any jar - activateNative(jar); + nativeLibraryStorage.addSearchJar(jar.getLocation()); } return null; @@ -1358,113 +1344,14 @@ public class JNLPClassLoader extends URL } /** - * Search for and enable any native code contained in a JAR by copying the - * native files into the filesystem. Called in the security context of the - * classloader. - */ - protected void activateNative(JARDesc jar) { - if (JNLPRuntime.isDebug()) - System.out.println("Activate native: " + jar.getLocation()); - - File localFile = tracker.getCacheFile(jar.getLocation()); - if (localFile == null) - return; - - String[] librarySuffixes = { ".so", ".dylib", ".jnilib", ".framework", ".dll" }; - - try { - JarFile jarFile = new JarFile(localFile, false); - Enumeration entries = jarFile.entries(); - - while (entries.hasMoreElements()) { - JarEntry e = entries.nextElement(); - - if (e.isDirectory()) { - continue; - } - - String name = new File(e.getName()).getName(); - boolean isLibrary = false; - - for (String suffix : librarySuffixes) { - if (name.endsWith(suffix)) { - isLibrary = true; - break; - } - } - if (!isLibrary) { - continue; - } - - if (nativeDir == null) - nativeDir = getNativeDir(); - - File outFile = new File(nativeDir, name); - if (!outFile.isFile()) { - FileUtils.createRestrictedFile(outFile, true); - } - CacheUtil.streamCopy(jarFile.getInputStream(e), - new FileOutputStream(outFile)); - - } - } catch (IOException ex) { - if (JNLPRuntime.isDebug()) - ex.printStackTrace(); - } - } - - /** - * Return the base directory to store native code files in. - * This method does not need to return the same directory across - * calls. - */ - protected File getNativeDir() { - final int rand = (int)((Math.random()*2 - 1) * Integer.MAX_VALUE); - nativeDir = new File(System.getProperty("java.io.tmpdir") - + File.separator + "netx-native-" - + (rand & 0xFFFF)); - File parent = nativeDir.getParentFile(); - if (!parent.isDirectory() && !parent.mkdirs()) { - return null; - } - - try { - FileUtils.createRestrictedDirectory(nativeDir); - // add this new native directory to the search path - addNativeDirectory(nativeDir); - return nativeDir; - } catch (IOException e) { - return null; - } - } - - /** - * Adds the {@link File} to the search path of this {@link JNLPClassLoader} - * when trying to find a native library - */ - protected void addNativeDirectory(File nativeDirectory) { - nativeDirectories.add(nativeDirectory); - } - - /** - * Returns a list of all directories in the search path of the current classloader - * when it tires to find a native library. - * @return a list of directories in the search path for native libraries - */ - protected List getNativeDirectories() { - return nativeDirectories; - } - - /** * Return the absolute path to the native library. */ protected String findLibrary(String lib) { String syslib = System.mapLibraryName(lib); + File libFile = nativeLibraryStorage.findLibrary(syslib); - for (File dir : getNativeDirectories()) { - File target = new File(dir, syslib); - if (target.exists()) - return target.toString(); + if (libFile != null) { + return libFile.toString(); } String result = super.findLibrary(lib); @@ -2040,8 +1927,9 @@ public class JNLPClassLoader extends URL addToCodeBaseLoader(extLoader.file.getCodeBase()); // native search paths - for (File nativeDirectory : extLoader.getNativeDirectories()) - addNativeDirectory(nativeDirectory); + for (File nativeDirectory : extLoader.nativeLibraryStorage.getSearchDirectories()) { + nativeLibraryStorage.addSearchDirectory(nativeDirectory); + } // security descriptors for (URL key : extLoader.jarLocationSecurityMap.keySet()) {