11package cpw .mods .niofs .union ;
22
3- import java .io .FileNotFoundException ;
4- import java .io .IOException ;
3+ import java .io .*;
54import java .lang .invoke .MethodHandle ;
65import java .lang .invoke .MethodHandles ;
76import java .lang .invoke .MethodType ;
7+ import java .lang .reflect .Method ;
8+ import java .nio .channels .ClosedByInterruptException ;
9+ import java .nio .channels .FileChannel ;
10+ import java .nio .channels .InterruptibleChannel ;
811import java .nio .channels .SeekableByteChannel ;
912import java .nio .file .AccessMode ;
1013import java .nio .file .DirectoryStream ;
3740
3841public class UnionFileSystem extends FileSystem {
3942 private static final MethodHandle ZIPFS_EXISTS ;
43+ private static final MethodHandle ZIPFS_CH ;
44+ private static final MethodHandle FCI_UNINTERUPTIBLE ;
4045 static final String SEP_STRING = "/" ;
4146
47+
48+
4249 static {
4350 try {
4451 var hackfield = MethodHandles .Lookup .class .getDeclaredField ("IMPL_LOOKUP" );
@@ -47,10 +54,27 @@ public class UnionFileSystem extends FileSystem {
4754
4855 var clz = Class .forName ("jdk.nio.zipfs.ZipPath" );
4956 ZIPFS_EXISTS = hack .findSpecial (clz , "exists" , MethodType .methodType (boolean .class ), clz );
57+
58+ clz = Class .forName ("jdk.nio.zipfs.ZipFileSystem" );
59+ ZIPFS_CH = hack .findGetter (clz , "ch" , SeekableByteChannel .class );
60+
61+ clz = Class .forName ("sun.nio.ch.FileChannelImpl" );
62+ FCI_UNINTERUPTIBLE = hack .findSpecial (clz , "setUninterruptible" , MethodType .methodType (void .class ), clz );
5063 } catch (NoSuchFieldException | IllegalAccessException | ClassNotFoundException | NoSuchMethodException e ) {
5164 throw new RuntimeException (e );
5265 }
5366 }
67+
68+ public InputStream buildInputStream (final UnionPath path ) {
69+ try {
70+ var bytes = Files .readAllBytes (path );
71+ return new ByteArrayInputStream (bytes );
72+ } catch (IOException ioe )
73+ {
74+ throw new UncheckedIOException (ioe );
75+ }
76+ }
77+
5478 private static class NoSuchFileException extends java .nio .file .NoSuchFileException {
5579 public NoSuchFileException (final String file ) {
5680 super (file );
@@ -91,7 +115,7 @@ String getKey() {
91115 return this .key ;
92116 }
93117
94- private record EmbeddedFileSystemMetadata (Path path , FileSystem fs ) {}
118+ private record EmbeddedFileSystemMetadata (Path path , FileSystem fs , SeekableByteChannel fsCh ) {}
95119
96120 public UnionFileSystem (final UnionFileSystemProvider provider , final BiPredicate <String , String > pathFilter , final String key , final Path ... basepaths ) {
97121 this .pathFilter = pathFilter ;
@@ -109,9 +133,14 @@ public UnionFileSystem(final UnionFileSystemProvider provider, final BiPredicate
109133
110134 private static Optional <EmbeddedFileSystemMetadata > openFileSystem (final Path path ) {
111135 try {
112- return Optional .of (new EmbeddedFileSystemMetadata (path , FileSystems .newFileSystem (path )));
136+ var zfs = FileSystems .newFileSystem (path );
137+ FileChannel fci = (FileChannel ) ZIPFS_CH .invoke (zfs );
138+ FCI_UNINTERUPTIBLE .invoke (fci );
139+ return Optional .of (new EmbeddedFileSystemMetadata (path , zfs , fci ));
113140 } catch (IOException e ) {
114141 throw new UncheckedIOException (e );
142+ } catch (Throwable t ) {
143+ throw new IllegalStateException (t );
115144 }
116145 }
117146
@@ -197,7 +226,7 @@ private Optional<BasicFileAttributes> getFileAttributes(final Path path) {
197226 try {
198227 if (path .getFileSystem () == FileSystems .getDefault () && !path .toFile ().exists ()) {
199228 return Optional .empty ();
200- } else if (path .getFileSystem ().provider ().getScheme ().equals ("jar" ) && !zipFsExists (path )) {
229+ } else if (path .getFileSystem ().provider ().getScheme ().equals ("jar" ) && !zipFsExists (this , path )) {
201230 return Optional .empty ();
202231 } else {
203232 return Optional .of (path .getFileSystem ().provider ().readAttributes (path , BasicFileAttributes .class ));
@@ -215,8 +244,9 @@ private Optional<Path> findFirstPathAt(final UnionPath path) {
215244 .findFirst ();
216245 }
217246
218- private static boolean zipFsExists (Path path ) {
247+ private static boolean zipFsExists (UnionFileSystem ufs , Path path ) {
219248 try {
249+ if (Optional .ofNullable (ufs .embeddedFileSystems .get (path .getFileSystem ())).filter (efs ->!efs .fsCh .isOpen ()).isPresent ()) throw new IllegalStateException ("The zip file has closed!" );
220250 return (boolean ) ZIPFS_EXISTS .invoke (path );
221251 } catch (Throwable t ) {
222252 throw new IllegalStateException (t );
@@ -231,7 +261,7 @@ private Optional<Path> findFirstFiltered(final UnionPath path) {
231261 return Optional .of (realPath );
232262 }
233263 } else if (realPath .getFileSystem ().provider ().getScheme ().equals ("jar" )) {
234- if (zipFsExists (realPath )) {
264+ if (zipFsExists (this , realPath )) {
235265 return Optional .of (realPath );
236266 }
237267 } else if (Files .exists (realPath )) {
@@ -327,7 +357,7 @@ public DirectoryStream<Path> newDirStream(final UnionPath path, final DirectoryS
327357 continue ;
328358 } else if (dir .getFileSystem () == FileSystems .getDefault () && !dir .toFile ().exists ()) {
329359 continue ;
330- } else if (dir .getFileSystem ().provider ().getScheme () == "jar" && !zipFsExists (dir )) {
360+ } else if (dir .getFileSystem ().provider ().getScheme () == "jar" && !zipFsExists (this , dir )) {
331361 continue ;
332362 } else if (Files .notExists (dir )) {
333363 continue ;
0 commit comments