From fec9712b151ad31b053fe700cb0f809b9715407c Mon Sep 17 00:00:00 2001
From: Sven Gothel
Date: Wed, 23 Oct 2013 16:48:42 +0200
Subject: Fix Bug 865: Safari >= 6.1 [OSX]: May employ xattr on
'com.apple.quarantine' on 'PluginProcess.app'
- IOUtil.getTempDir(..): Don't test executable caps on OSX for java_io_tmpdir
- JarUtil.extract(..): Issue native fixNativeLibAttribs(..) on OSX for native library files,
i.e. remove xattr 'com.apple.quarantine'
---
make/build.xml | 5 +-
src/java/com/jogamp/common/util/IOUtil.java | 97 +++++++++++++++-------
src/java/com/jogamp/common/util/JarUtil.java | 28 +++++++
.../jogamp/common/util/cache/TempFileCache.java | 2 +-
src/native/common/JarUtil.c | 39 +++++++++
5 files changed, 138 insertions(+), 33 deletions(-)
create mode 100644 src/native/common/JarUtil.c
diff --git a/make/build.xml b/make/build.xml
index 554ba43..55ef270 100644
--- a/make/build.xml
+++ b/make/build.xml
@@ -457,10 +457,7 @@
-
-
-
-
+
diff --git a/src/java/com/jogamp/common/util/IOUtil.java b/src/java/com/jogamp/common/util/IOUtil.java
index ef6a633..45cb6ec 100644
--- a/src/java/com/jogamp/common/util/IOUtil.java
+++ b/src/java/com/jogamp/common/util/IOUtil.java
@@ -1006,9 +1006,15 @@ public class IOUtil {
throws SecurityException
{
if (!testFile(dir, true, true)) {
+ if(DEBUG) {
+ System.err.println("IOUtil.testDirExec: <"+dir.getAbsolutePath()+">: Not writeable dir");
+ }
return false;
}
if(!getOSHasNoexecFS()) {
+ if(DEBUG) {
+ System.err.println("IOUtil.testDirExec: <"+dir.getAbsolutePath()+">: Always executable");
+ }
return true;
}
@@ -1023,40 +1029,45 @@ public class IOUtil {
}
return false;
}
- int ok = -1;
- if(exetst.setExecutable(true)) {
+ int res = -1;
+ if(exetst.setExecutable(true /* exec */, true /* ownerOnly */)) {
try {
Process pr = Runtime.getRuntime().exec(exetst.getCanonicalPath());
pr.waitFor() ;
- ok = pr.exitValue();
+ res = pr.exitValue();
} catch (SecurityException se) {
throw se; // fwd Security exception
} catch (Throwable t) {
- ok = -2;
+ res = -2;
if(DEBUG) {
- System.err.println("IOUtil.testDirExec: <"+exetst.getAbsolutePath()+">: "+t.getMessage());
+ System.err.println("IOUtil.testDirExec: <"+exetst.getAbsolutePath()+">: Catched "+t.getClass().getSimpleName()+": "+t.getMessage());
// t.printStackTrace();
}
}
}
exetst.delete();
- return 0 == ok;
+ if(DEBUG) {
+ System.err.println("IOUtil.testDirExec(): <"+dir.getAbsolutePath()+">: res "+res);
+ }
+ return 0 == res;
}
- private static File testDirImpl(File dir, boolean create, boolean executable)
+ private static File testDirImpl(File dir, boolean create, boolean executable, String dbgMsg)
throws SecurityException
{
+ final File res;
if (create && !dir.exists()) {
dir.mkdirs();
}
if( executable ) {
- if(testDirExec(dir)) {
- return dir;
- }
- } else if(testFile(dir, true, true)) {
- return dir;
+ res = testDirExec(dir) ? dir : null;
+ } else {
+ res = testFile(dir, true, true) ? dir : null;
}
- return null;
+ if(DEBUG) {
+ System.err.println("IOUtil.testDirImpl("+dbgMsg+"): <"+dir.getAbsolutePath()+">, create "+create+", exec "+executable+": "+(null != res));
+ }
+ return res;
}
/**
@@ -1076,7 +1087,7 @@ public class IOUtil {
public static File testDir(final File dir, final boolean create, final boolean executable)
throws SecurityException
{
- return testDirImpl(dir, create, executable);
+ return testDirImpl(dir, create, executable, "testDir");
}
private static boolean isStringSet(String s) { return null != s && 0 < s.length(); }
@@ -1100,18 +1111,19 @@ public class IOUtil {
*
* @param tmpRoot
* @param executable
+ * @param dbgMsg TODO
* @param tmpDirPrefix
* @return a temporary directory, writable by this user
* @throws SecurityException
*/
- private static File getSubTempDir(File tmpRoot, String tmpSubDirPrefix, boolean executable)
+ private static File getSubTempDir(File tmpRoot, String tmpSubDirPrefix, boolean executable, String dbgMsg)
throws SecurityException
{
File tmpBaseDir = null;
- if(null != testDirImpl(tmpRoot, true /* create */, executable)) { // check tmpRoot first
+ if(null != testDirImpl(tmpRoot, true /* create */, executable, dbgMsg)) { // check tmpRoot first
for(int i = 0; null == tmpBaseDir && i<=9999; i++) {
final String tmpDirSuffix = String.format("_%04d", i); // 4 digits for iteration
- tmpBaseDir = testDirImpl(new File(tmpRoot, tmpSubDirPrefix+tmpDirSuffix), true /* create */, executable);
+ tmpBaseDir = testDirImpl(new File(tmpRoot, tmpSubDirPrefix+tmpDirSuffix), true /* create */, executable, dbgMsg);
}
}
return tmpBaseDir;
@@ -1153,13 +1165,25 @@ public class IOUtil {
{
final File ctxTempDir = AndroidUtils.getTempRoot(); // null if ( !Android || no android-ctx )
if(null != ctxTempDir) {
- tempRootNoexec = getSubTempDir(ctxTempDir, tmpSubDir, false /* executable, see below */);
+ tempRootNoexec = getSubTempDir(ctxTempDir, tmpSubDir, false /* executable, see below */, "Android.ctxTemp");
tempRootExec = tempRootNoexec; // FIXME: Android temp root is always executable (?)
return tempRootExec;
}
}
final String java_io_tmpdir = PropertyAccess.getProperty(java_io_tmpdir_propkey, false);
+ final String user_temp; // only if diff than java_io_tmpdir
+ {
+ String _user_temp = System.getenv("TMPDIR");
+ if( !isStringSet(_user_temp) ) {
+ _user_temp = System.getenv("TEMP");
+ }
+ if( isStringSet(_user_temp) && !_user_temp.equals(java_io_tmpdir) ) {
+ user_temp = _user_temp;
+ } else {
+ user_temp = null;
+ }
+ }
final String user_home = PropertyAccess.getProperty(user_home_propkey, false);
final String xdg_cache_home;
@@ -1178,41 +1202,58 @@ public class IOUtil {
// 1) java.io.tmpdir/jogamp
if( null == tempRootExec && isStringSet(java_io_tmpdir) ) {
- tempRootExec = getSubTempDir(new File(java_io_tmpdir), tmpSubDir, true /* executable */);
+ if( Platform.OSType.MACOS == Platform.getOSType() ) {
+ // Bug 865: Safari >= 6.1 [OSX] May employ xattr on 'com.apple.quarantine' on 'PluginProcess.app'
+ // We attempt to fix this issue _after_ gluegen native lib is loaded, see JarUtil.fixNativeLibAttribs(File).
+ tempRootExec = getSubTempDir(new File(java_io_tmpdir), tmpSubDir, false /* executable */, "tempX1");
+ } else {
+ tempRootExec = getSubTempDir(new File(java_io_tmpdir), tmpSubDir, true /* executable */, "tempX1");
+ }
}
// 2) $XDG_CACHE_HOME/jogamp
if(null == tempRootExec && isStringSet(xdg_cache_home)) {
- tempRootExec = getSubTempDir(new File(xdg_cache_home), tmpSubDir, true /* executable */);
+ tempRootExec = getSubTempDir(new File(xdg_cache_home), tmpSubDir, true /* executable */, "tempX2");
}
- // 3) $HOME/.jogamp
- if(null == tempRootExec && isStringSet(user_home)) {
- tempRootExec = getSubTempDir(new File(user_home), "." + tmpSubDir, true /* executable */);
+ // 3) $TMPDIR/jogamp
+ if(null == tempRootExec && isStringSet(user_temp)) {
+ tempRootExec = getSubTempDir(new File(user_temp), tmpSubDir, true /* executable */, "tempX3");
}
+ // 4) $HOME/.jogamp
+ if(null == tempRootExec && isStringSet(user_home)) {
+ tempRootExec = getSubTempDir(new File(user_home), "." + tmpSubDir, true /* executable */, "tempX4");
+ }
if(null != tempRootExec) {
tempRootNoexec = tempRootExec;
} else {
// 1) java.io.tmpdir/jogamp
if( null == tempRootNoexec && isStringSet(java_io_tmpdir) ) {
- tempRootNoexec = getSubTempDir(new File(java_io_tmpdir), tmpSubDir, false /* executable */);
+ tempRootNoexec = getSubTempDir(new File(java_io_tmpdir), tmpSubDir, false /* executable */, "temp01");
}
// 2) $XDG_CACHE_HOME/jogamp
if(null == tempRootNoexec && isStringSet(xdg_cache_home)) {
- tempRootNoexec = getSubTempDir(new File(xdg_cache_home), tmpSubDir, false /* executable */);
+ tempRootNoexec = getSubTempDir(new File(xdg_cache_home), tmpSubDir, false /* executable */, "temp02");
+ }
+
+ // 3) $TMPDIR/jogamp
+ if(null == tempRootNoexec && isStringSet(user_temp)) {
+ tempRootNoexec = getSubTempDir(new File(user_temp), tmpSubDir, false /* executable */, "temp03");
}
- // 3) $HOME/.jogamp
+ // 4) $HOME/.jogamp
if(null == tempRootNoexec && isStringSet(user_home)) {
- tempRootNoexec = getSubTempDir(new File(user_home), "." + tmpSubDir, false /* executable */);
+ tempRootNoexec = getSubTempDir(new File(user_home), "." + tmpSubDir, false /* executable */, "temp04");
}
}
if(DEBUG) {
- System.err.println("IOUtil.getTempRoot(): temp dirs: exec: "+tempRootExec.getAbsolutePath()+", noexec: "+tempRootNoexec.getAbsolutePath());
+ final String tempRootExecAbsPath = null != tempRootExec ? tempRootExec.getAbsolutePath() : null;
+ final String tempRootNoexecAbsPath = null != tempRootNoexec ? tempRootNoexec.getAbsolutePath() : null;
+ System.err.println("IOUtil.getTempRoot(): temp dirs: exec: "+tempRootExecAbsPath+", noexec: "+tempRootNoexecAbsPath);
}
}
}
diff --git a/src/java/com/jogamp/common/util/JarUtil.java b/src/java/com/jogamp/common/util/JarUtil.java
index 5411d66..b5f8850 100644
--- a/src/java/com/jogamp/common/util/JarUtil.java
+++ b/src/java/com/jogamp/common/util/JarUtil.java
@@ -47,6 +47,7 @@ import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import com.jogamp.common.os.NativeLibrary;
+import com.jogamp.common.os.Platform;
import jogamp.common.Debug;
@@ -632,6 +633,7 @@ public class JarUtil {
if (isNativeLib && ( isRootEntry || !nativeLibMap.containsKey(libBaseName) ) ) {
nativeLibMap.put(libBaseName, destFile.getAbsolutePath());
addedAsNativeLib = true;
+ fixNativeLibAttribs(destFile);
}
}
if (DEBUG) {
@@ -642,6 +644,32 @@ public class JarUtil {
return num;
}
+ /**
+ * Mitigate file permission issues of native library files, i.e.:
+ *
+ * - Bug 865: Safari >= 6.1 [OSX]: May employ xattr on 'com.apple.quarantine' on 'PluginProcess.app'
+ *
+ */
+ private final static void fixNativeLibAttribs(File file) {
+ // We tolerate UnsatisfiedLinkError (and derived) to solve the chicken and egg problem
+ // of loading gluegen's native library.
+ // On Safari(OSX), Bug 865, we simply hope the destination folder is executable.
+ if( Platform.OSType.MACOS == Platform.getOSType() ) {
+ final String fileAbsPath = file.getAbsolutePath();
+ try {
+ fixNativeLibAttribs(fileAbsPath);
+ if( DEBUG ) {
+ System.err.println("JarUtil.fixNativeLibAttribs: "+fileAbsPath+" - OK");
+ }
+ } catch (Throwable t) {
+ if( DEBUG ) {
+ System.err.println("JarUtil.fixNativeLibAttribs: "+fileAbsPath+" - "+t.getClass().getSimpleName()+": "+t.getMessage());
+ }
+ }
+ }
+ }
+ private native static boolean fixNativeLibAttribs(String fname);
+
/**
* Validate the certificates for each native Lib in the jar file.
* Throws an IOException if any certificate is not valid.
diff --git a/src/java/com/jogamp/common/util/cache/TempFileCache.java b/src/java/com/jogamp/common/util/cache/TempFileCache.java
index cc7014a..3fd0a59 100644
--- a/src/java/com/jogamp/common/util/cache/TempFileCache.java
+++ b/src/java/com/jogamp/common/util/cache/TempFileCache.java
@@ -80,7 +80,7 @@ public class TempFileCache {
_tmpBaseDir = new File(IOUtil.getTempDir(true /* executable */), tmpDirPrefix);
_tmpBaseDir = IOUtil.testDir(_tmpBaseDir, true /* create */, false /* executable */); // executable already checked
} catch (Exception ex) {
- System.err.println("Warning: Catched Exception while retrieving temp base directory:");
+ System.err.println("Warning: Catched Exception while retrieving executable temp base directory:");
ex.printStackTrace();
staticInitError = true;
}
diff --git a/src/native/common/JarUtil.c b/src/native/common/JarUtil.c
new file mode 100644
index 0000000..c918f77
--- /dev/null
+++ b/src/native/common/JarUtil.c
@@ -0,0 +1,39 @@
+#include
+
+#include
+
+#include "com_jogamp_common_util_JarUtil.h"
+
+#if defined(__APPLE__)
+ #include
+ static const char kQuarantineAttrName[] = "com.apple.quarantine";
+#endif
+
+/*
+ * Class: com_jogamp_common_util_JarUtil
+ * Method: fixNativeLibAttribs
+ * Signature: (Ljava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_jogamp_common_util_JarUtil_fixNativeLibAttribs
+ (JNIEnv *env, jclass _unused, jstring fname) {
+ const char* _UTF8fname = NULL;
+ int status = 0;
+ if (fname != NULL) {
+ if (fname != NULL) {
+ _UTF8fname = (*env)->GetStringUTFChars(env, fname, (jboolean*)NULL);
+ if (_UTF8fname == NULL) {
+ (*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/OutOfMemoryError"),
+ "Failed to get UTF-8 chars for argument \"fname\" in native dispatcher for \"removexattr\"");
+ return 0;
+ }
+ }
+ }
+#if defined(__APPLE__)
+ status = removexattr(_UTF8fname, kQuarantineAttrName, 0);
+#endif
+ if (fname != NULL) {
+ (*env)->ReleaseStringUTFChars(env, fname, _UTF8fname);
+ }
+ return 0 == status ? JNI_TRUE : JNI_FALSE;
+}
+
--
cgit v1.2.3