Petri Hintukainen pushed to branch master at VideoLAN / libbluray
Commits: f43a2a8d by hpi1 at 2019-04-15T06:07:50Z Cosmetics - - - - - 487fc80c by hpi1 at 2019-04-16T09:03:31Z BDFileSystem: enable hooks after JVM has been booted - - - - - a1869cb4 by hpi1 at 2019-04-16T09:54:08Z Java 8+: Unconditionally hook java.io.FileSystem class This is done during JVM boot stage => unsupported FileSystem implementation will prevent JVM boot. Fixes skipping wrapper class sometimes when java.io.File.fs is static final. - - - - - 3 changed files: - src/libbluray/bdj/java/java/io/BDFileSystem.java - + src/libbluray/bdj/java/java/io/DefaultFileSystem.java - src/libbluray/bdj/java/org/videolan/Libbluray.java Changes: ===================================== src/libbluray/bdj/java/java/io/BDFileSystem.java ===================================== @@ -19,6 +19,7 @@ /* * Wrapper for java.io.FileSystem class. * + * - resolve relative files to Xlet home directory. * - replace getBooleanAttributes() for relative paths. * Pretend files exist, if those are in xlet home directory (inside .jar). * No other relative paths are allowed. @@ -40,30 +41,50 @@ import org.videolan.Logger; public abstract class BDFileSystem extends FileSystem { - private static final Logger logger = Logger.getLogger(BDFileSystem.class.getName()); - - protected final FileSystem fs; + /* + * Access to native filesystem + * + * (for org.videolan.VFSCache, org.videolan.CacheDir) + */ private static FileSystem nativeFileSystem; static { - /* Java 8: getFileSystem() no longer exists on java.io.FileSystem */ try { - nativeFileSystem = (FileSystem)Class.forName("java.io.DefaultFileSystem") - .getDeclaredMethod("getFileSystem", new Class[0]) + /* Java < 8 */ + nativeFileSystem = (FileSystem)FileSystem.class + .getDeclaredMethod("getFileSystem",new Class[0]) .invoke(null, new Object[0]); } catch (Exception e) { try { - nativeFileSystem = (FileSystem)FileSystem.class - .getDeclaredMethod("getFileSystem",new Class[0]) - .invoke(null, new Object[0]); - } catch (Exception t) { - System.err.print("Couldn't find native filesystem: " + t); + /* Just use our wrapper. If it fails, JVM won't be booted anyway ... */ + nativeFileSystem = DefaultFileSystem.getNativeFileSystem(); + } catch (Throwable t) { + System.err.print("Couldn't find native filesystem: " + e); } } } + /* org.videolan.CacheDir uses this function to clean up cache directory */ + public static String[] nativeList(File f) { + return nativeFileSystem.list(f); + } + + /* org.videolan.VFSCache uses this function to check if file has been cached */ + public static boolean nativeFileExists(String path) { + return nativeFileSystem.getBooleanAttributes(new File(path)) != 0; + } + + /* + * Replace File.fs for Xlets (required with Java < 8 where this is not done unconditionally) + * + * (called by org.videolan.BDJClassLoader) + */ + public static void init(final Class c) { + + setBooted(); + AccessController.doPrivileged( new PrivilegedAction() { public Object run() { @@ -79,33 +100,49 @@ public abstract class BDFileSystem extends FileSystem { filesystem = c.getDeclaredField("fs"); filesystem.setAccessible(true); - /* Java 8: remove "final" modifier from the field */ - Field modifiersField = Field.class.getDeclaredField("modifiers"); - modifiersField.setAccessible(true); - modifiersField.setInt(filesystem, filesystem.getModifiers() & ~Modifier.FINAL); - FileSystem fs = (FileSystem)filesystem.get(null); if (fs instanceof BDFileSystemImpl) { //System.err.print("FileSystem already wrapped"); } else { + /* Java 8: we should never end up here ... */ + /* Java 8: remove "final" modifier from the field */ + //Field modifiersField = Field.class.getDeclaredField("modifiers"); + //modifiersField.setAccessible(true); + //modifiersField.setInt(filesystem, filesystem.getModifiers() & ~Modifier.FINAL); filesystem.set(null, new BDFileSystemImpl(fs)); } } catch (Exception t) { - System.err.print("Hooking FileSystem class failed: " + t); + error("Hooking FileSystem class failed: " + t); } } - public static String[] nativeList(File f) { - return nativeFileSystem.list(f); + /* + * enable after JVM boot is completed + */ + + private static Logger logger = null; + private static boolean booted = false; + + /* Called by org.videolan.Libbluray.initOnce() */ + public static void setBooted() { + if (!booted) { + booted = true; + logger = Logger.getLogger(BDFileSystem.class.getName()); + } } - public static boolean nativeFileExists(String path) { - return nativeFileSystem.getBooleanAttributes(new File(path)) != 0; + private static void error(String msg) { + if (logger != null) { + logger.error(msg); + } } /* + * */ + protected final FileSystem fs; + public BDFileSystem(FileSystem fs) { this.fs = fs; } @@ -139,6 +176,9 @@ public abstract class BDFileSystem extends FileSystem { } public String resolve(String parent, String child) { + if (!booted) + return fs.resolve(parent, child); + if (parent == null || parent.equals("") || parent.equals(".")) { parent = getHomeDir(); } @@ -168,6 +208,9 @@ public abstract class BDFileSystem extends FileSystem { } public String resolve(File f) { + if (!booted) + return fs.resolve(f); + if (!f.isAbsolute()) { logger.info("resolve relative file " + f.getPath()); return resolve(BDJXletContext.getCurrentXletHome(), f.getPath()); @@ -182,6 +225,9 @@ public abstract class BDFileSystem extends FileSystem { } public String canonicalize(String path) throws IOException { + if (!booted) + return fs.canonicalize(path); + String canonPath = fs.canonicalize(path); String cachePath = BDJLoader.getCachedFile(canonPath); if (cachePath != canonPath) { @@ -191,6 +237,9 @@ public abstract class BDFileSystem extends FileSystem { } public int getBooleanAttributes(File f) { + if (!booted) + return fs.getBooleanAttributes(f); + if (f.isAbsolute()) { return fs.getBooleanAttributes(f); } @@ -217,6 +266,9 @@ public abstract class BDFileSystem extends FileSystem { } public long getLength(File f) { + if (!booted) + return fs.getLength(f); + if (f.isAbsolute()) { return fs.getLength(f); } @@ -263,7 +315,7 @@ public abstract class BDFileSystem extends FileSystem { args = new Object[] {(Object)path, (Object)new Boolean(restrictive)}; } } catch (NoSuchMethodException e) { - logger.error("no matching FileSystem.createFileExclusively found !"); + error("no matching FileSystem.createFileExclusively found !"); throw new IOException(); } @@ -272,14 +324,14 @@ public abstract class BDFileSystem extends FileSystem { Boolean result = (Boolean)m.invoke(fs, args); return result.booleanValue(); } catch (IllegalAccessException e) { - logger.error("" + e); + error("" + e); throw new IOException(); } catch (InvocationTargetException e) { Throwable t = e.getTargetException(); if (t instanceof IOException) { throw (IOException)t; } - logger.error("" + t); + error("" + t); throw new IOException(); } } @@ -299,6 +351,8 @@ public abstract class BDFileSystem extends FileSystem { } public String[] list(File f) { + if (!booted) + return fs.list(f); String path = f.getPath(); String root = System.getProperty("bluray.vfs.root"); ===================================== src/libbluray/bdj/java/java/io/DefaultFileSystem.java ===================================== @@ -0,0 +1,51 @@ +/* + * This file is part of libbluray + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +package java.io; + +class DefaultFileSystem { + + static FileSystem getNativeFileSystem() { + Exception e1, e2, e3; + try { + return (FileSystem)Class.forName(System.getProperty("org.videolan.bdj_filesystem")).newInstance(); + } catch (Exception e) { + e3 = e; + } + try { + return (FileSystem)Class.forName("java.io.UnixFileSystem").newInstance(); + } catch (Exception e) { + e1 = e; + } + try { + return (FileSystem)Class.forName("java.io.WinNTFileSystem").newInstance(); + } catch (Exception e) { + e2 = e; + } + + /* No way to recover from here */ + System.err.println("Unsupported native filesystem !\n\t" + e1 + "\n\t" + e2 + "\n\t" + e3); + //Runtime.getRuntime().halt(-1); + throw new Error("No filesystem implementation found"); + } + + public static FileSystem getFileSystem() { + FileSystem nativeFs = getNativeFileSystem(); + return new BDFileSystemImpl(nativeFs); + } +} ===================================== src/libbluray/bdj/java/org/videolan/Libbluray.java ===================================== @@ -138,6 +138,9 @@ public class Libbluray { } catch (Throwable t) { System.err.println("Hooking socket factory failed: " + t + "\n" + Logger.dumpStack(t)); } + + /* enable filesystem hooks */ + java.io.BDFileSystem.setBooted(); } private static String canonicalize(String path, boolean create) { View it on GitLab: https://code.videolan.org/videolan/libbluray/compare/6c0e42b88ee167e052944757b57537a72b3ddcda...a1869cb4a18b12f4c5a1bb6b69f8b0da24c28f73 -- View it on GitLab: https://code.videolan.org/videolan/libbluray/compare/6c0e42b88ee167e052944757b57537a72b3ddcda...a1869cb4a18b12f4c5a1bb6b69f8b0da24c28f73 You're receiving this email because of your account on code.videolan.org.
_______________________________________________ libbluray-devel mailing list libbluray-devel@videolan.org https://mailman.videolan.org/listinfo/libbluray-devel