Skip to content

Commit

Permalink
Remove system property toggle
Browse files Browse the repository at this point in the history
Use the same ZipFS hacks as before
  • Loading branch information
shartte committed May 10, 2024
1 parent f4ff187 commit 4e72f7b
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 55 deletions.
13 changes: 4 additions & 9 deletions src/main/java/cpw/mods/jarhandling/impl/JarContentsImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
import cpw.mods.jarhandling.SecureJar;
import cpw.mods.niofs.union.UnionFileSystemProvider;
import cpw.mods.niofs.union.UnionPathFilter;
import cpw.mods.util.ZipFsFactory;
import org.jetbrains.annotations.Nullable;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
Expand All @@ -24,14 +24,12 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiPredicate;
import java.util.function.Supplier;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;

public class JarContentsImpl implements JarContents {
private static final boolean USE_UNION_FS_ONLY_IF_NEEDED = Boolean.getBoolean("securejarhandler.useUnionFsOnlyIfNeeded");
private static final UnionFileSystemProvider UFSP = (UnionFileSystemProvider) FileSystemProvider.installedProviders()
.stream()
.filter(fsp->fsp.getScheme().equals("union"))
Expand Down Expand Up @@ -60,12 +58,9 @@ public JarContentsImpl(Path[] paths, Supplier<Manifest> defaultManifest, @Nullab
var validPaths = Arrays.stream(paths).filter(Files::exists).toArray(Path[]::new);
if (validPaths.length == 0)
throw new UncheckedIOException(new IOException("Invalid paths argument, contained no existing paths: " + Arrays.toString(paths)));
if (USE_UNION_FS_ONLY_IF_NEEDED && pathFilter == null && validPaths.length == 1 && !Files.isDirectory(validPaths[0])) {
try {
this.filesystem = FileSystems.newFileSystem(validPaths[0]);
} catch (IOException e) {
throw new UncheckedIOException("Failed to open " + validPaths[0], e);
}
// Use a ZipFS directly in simple cases
if (pathFilter == null && validPaths.length == 1 && !Files.isDirectory(validPaths[0])) {
this.filesystem = ZipFsFactory.create(validPaths[0]);
} else {
this.filesystem = UFSP.newFileSystem(pathFilter, validPaths);
}
Expand Down
53 changes: 7 additions & 46 deletions src/main/java/cpw/mods/niofs/union/UnionFileSystem.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
package cpw.mods.niofs.union;

import cpw.mods.util.ZipFsFactory;
import org.jetbrains.annotations.Nullable;

import java.io.ByteArrayInputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.nio.channels.FileChannel;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.AccessMode;
import java.nio.file.DirectoryStream;
Expand Down Expand Up @@ -38,27 +35,8 @@
import java.util.stream.StreamSupport;

public class UnionFileSystem extends FileSystem {
private static final MethodHandle ZIPFS_CH;
private static final MethodHandle FCI_UNINTERUPTIBLE;
static final String SEP_STRING = "/";


static {
try {
var hackfield = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
hackfield.setAccessible(true);
MethodHandles.Lookup hack = (MethodHandles.Lookup) hackfield.get(null);

var clz = Class.forName("jdk.nio.zipfs.ZipFileSystem");
ZIPFS_CH = hack.findGetter(clz, "ch", SeekableByteChannel.class);

clz = Class.forName("sun.nio.ch.FileChannelImpl");
FCI_UNINTERUPTIBLE = hack.findSpecial(clz, "setUninterruptible", MethodType.methodType(void.class), clz);
} catch (NoSuchFieldException | IllegalAccessException | ClassNotFoundException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
}

public InputStream buildInputStream(final UnionPath path) {
try {
var bytes = Files.readAllBytes(path);
Expand Down Expand Up @@ -101,7 +79,7 @@ public synchronized Throwable fillInStackTrace() {
private final int lastElementIndex;
@Nullable
private final UnionPathFilter pathFilter;
private final Map<Path, EmbeddedFileSystemMetadata> embeddedFileSystems;
private final Map<Path, FileSystem> embeddedFileSystems;

public Path getPrimaryPath() {
return basepaths.get(basepaths.size() - 1);
Expand All @@ -116,7 +94,7 @@ String getKey() {
return this.key;
}

private record EmbeddedFileSystemMetadata(Path path, FileSystem fs, SeekableByteChannel fsCh) {
private record EmbeddedFileSystemMetadata(Path path, FileSystem fs) {
}

public UnionFileSystem(final UnionFileSystemProvider provider, @Nullable UnionPathFilter pathFilter, final String key, final Path... basepaths) {
Expand All @@ -129,24 +107,7 @@ public UnionFileSystem(final UnionFileSystemProvider provider, @Nullable UnionPa
.toList(); // we flip the list so later elements are first in search order.
lastElementIndex = basepaths.length - 1;
this.embeddedFileSystems = this.basepaths.stream().filter(path -> !Files.isDirectory(path))
.map(UnionFileSystem::openFileSystem)
.flatMap(Optional::stream)
.collect(Collectors.toMap(EmbeddedFileSystemMetadata::path, Function.identity()));
}

private static Optional<EmbeddedFileSystemMetadata> openFileSystem(final Path path) {
try {
var zfs = FileSystems.newFileSystem(path);
SeekableByteChannel fci = (SeekableByteChannel) ZIPFS_CH.invoke(zfs);
if (fci instanceof FileChannel) { // we only make file channels uninterruptible because byte channels (JIJ) already are
FCI_UNINTERUPTIBLE.invoke(fci);
}
return Optional.of(new EmbeddedFileSystemMetadata(path, zfs, fci));
} catch (IOException e) {
throw new UncheckedIOException("Failed to open file system from path " + path, e);
} catch (Throwable t) {
throw new IllegalStateException("Failed to open file system from path " + path, t);
}
.collect(Collectors.toMap(Function.identity(), ZipFsFactory::create));
}

@Override
Expand Down Expand Up @@ -352,9 +313,9 @@ public boolean exists(final UnionPath p) {
private Path toRealPath(final Path basePath, final UnionPath path) {
var embeddedpath = path.isAbsolute() ? this.root.relativize(path) : path;
var resolvepath = embeddedpath.normalize().toString();
var efsm = embeddedFileSystems.get(basePath);
if (efsm != null) {
return efsm.fs().getPath(resolvepath);
var fileSystem = embeddedFileSystems.get(basePath);
if (fileSystem != null) {
return fileSystem.getPath(resolvepath);
} else {
return basePath.resolve(resolvepath);
}
Expand Down
55 changes: 55 additions & 0 deletions src/main/java/cpw/mods/util/ZipFsFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package cpw.mods.util;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.nio.channels.FileChannel;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;

/**
* Utilities for dealing with ZipFilesystems.
*/
public final class ZipFsFactory {
private static final MethodHandle ZIPFS_CH;
private static final MethodHandle FCI_UNINTERUPTIBLE;

static {
try {
var hackfield = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
hackfield.setAccessible(true);
MethodHandles.Lookup hack = (MethodHandles.Lookup) hackfield.get(null);

var clz = Class.forName("jdk.nio.zipfs.ZipFileSystem");
ZIPFS_CH = hack.findGetter(clz, "ch", SeekableByteChannel.class);

clz = Class.forName("sun.nio.ch.FileChannelImpl");
FCI_UNINTERUPTIBLE = hack.findSpecial(clz, "setUninterruptible", MethodType.methodType(void.class), clz);
} catch (NoSuchFieldException | IllegalAccessException | ClassNotFoundException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
}

private ZipFsFactory() {
}

public static FileSystem create(Path path) {
try {
var zfs = FileSystems.newFileSystem(path);
SeekableByteChannel fci = (SeekableByteChannel) ZIPFS_CH.invoke(zfs);
if (fci instanceof FileChannel) { // we only make file channels uninterruptible because byte channels (JIJ) already are
FCI_UNINTERUPTIBLE.invoke(fci);
}
return zfs;
} catch (IOException e) {
throw new UncheckedIOException("Failed to open file system from path " + path, e);
} catch (Throwable t) {
// Rethrow to include the path that caused it
throw new IllegalStateException("Failed to open file system from path " + path, t);
}
}
}
1 change: 1 addition & 0 deletions src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
requires org.objectweb.asm.tree;
requires java.base;
requires static org.jetbrains.annotations;
requires jdk.zipfs;
provides java.nio.file.spi.FileSystemProvider with UnionFileSystemProvider;
uses cpw.mods.cl.ModularURLHandler.IURLProvider;
provides ModularURLHandler.IURLProvider with UnionURLStreamHandler;
Expand Down

0 comments on commit 4e72f7b

Please sign in to comment.