55
55
import java .lang .reflect .Modifier ;
56
56
import java .net .URI ;
57
57
import java .nio .ByteBuffer ;
58
+ import java .nio .channels .NonWritableChannelException ;
58
59
import java .nio .channels .SeekableByteChannel ;
59
60
import java .nio .file .AccessMode ;
60
61
import java .nio .file .DirectoryStream ;
61
62
import java .nio .file .Files ;
63
+ import java .nio .file .LinkOption ;
62
64
import java .nio .file .NoSuchFileException ;
63
65
import java .nio .file .NotDirectoryException ;
66
+ import java .nio .file .NotLinkException ;
64
67
import java .nio .file .OpenOption ;
65
68
import java .nio .file .Path ;
66
69
import java .nio .file .StandardCopyOption ;
85
88
import static org .graalvm .python .embedding .utils .VirtualFileSystem .HostIO .READ_WRITE ;
86
89
import static org .junit .Assert .assertEquals ;
87
90
import static org .junit .Assert .assertFalse ;
91
+ import static org .junit .Assert .assertNotEquals ;
88
92
import static org .junit .Assert .assertTrue ;
89
93
import static org .junit .Assert .fail ;
90
94
@@ -175,8 +179,10 @@ public void toRealPath() throws Exception {
175
179
private static void toRealPathVFS (FileSystem fs , String pathPrefix ) throws IOException {
176
180
assertEquals (Path .of (VFS_MOUNT_POINT , "dir1" ), fs .toRealPath (Path .of (pathPrefix , "dir1" )));
177
181
assertEquals (Path .of (VFS_MOUNT_POINT , "SomeFile" ), fs .toRealPath (Path .of (pathPrefix , "SomeFile" )));
178
- assertEquals (Path .of (VFS_MOUNT_POINT , "does-not-exist" , "extractme" ), fs .toRealPath (Path .of (pathPrefix , "does-not-exist" , "extractme" )));
182
+ assertEquals (Path .of (VFS_MOUNT_POINT , "does-not-exist" ), fs .toRealPath (Path .of (pathPrefix , "does-not-exist" )));
183
+ assertEquals (Path .of (VFS_MOUNT_POINT , "extractme" ), fs .toRealPath (Path .of (pathPrefix , "extractme" ), LinkOption .NOFOLLOW_LINKS ));
179
184
checkExtractedFile (fs .toRealPath (Path .of (pathPrefix , "extractme" )), new String []{"text1" , "text2" });
185
+ checkException (NoSuchFileException .class , () -> fs .toRealPath (Path .of (pathPrefix , "does-not-exist" , "extractme" )));
180
186
}
181
187
182
188
@ Test
@@ -383,10 +389,23 @@ private static void checkAccessVFS(FileSystem fs, String pathPrefix) throws IOEx
383
389
fs .checkAccess (Path .of (pathPrefix , "dir1" ), Set .of (AccessMode .READ ));
384
390
// check regular resource file
385
391
fs .checkAccess (Path .of (pathPrefix , "SomeFile" ), Set .of (AccessMode .READ ));
392
+
386
393
// check to be extracted file
394
+ fs .checkAccess (Path .of (pathPrefix , "extractme" ), Set .of (AccessMode .READ ), LinkOption .NOFOLLOW_LINKS );
395
+ checkException (SecurityException .class , () -> fs .checkAccess (Path .of (pathPrefix , "extractme" ), Set .of (AccessMode .WRITE ), LinkOption .NOFOLLOW_LINKS ));
387
396
fs .checkAccess (Path .of (pathPrefix , "extractme" ), Set .of (AccessMode .READ ));
397
+ // even though extracted -> FS is read-only and we are limiting the access to read-only also
398
+ // for extracted files
399
+ checkException (IOException .class , () -> fs .checkAccess (Path .of (pathPrefix , "extractme" ), Set .of (AccessMode .WRITE )));
400
+
401
+ checkException (NoSuchFileException .class , () -> fs .checkAccess (Path .of (pathPrefix , "does-not-exits" , "extractme" ), Set .of (AccessMode .READ ), LinkOption .NOFOLLOW_LINKS ));
402
+ checkException (NoSuchFileException .class , () -> fs .checkAccess (Path .of (pathPrefix , "does-not-exits" , "extractme" ), Set .of (AccessMode .READ )));
388
403
389
404
checkException (SecurityException .class , () -> fs .checkAccess (Path .of (pathPrefix , "SomeFile" ), Set .of (AccessMode .WRITE )), "write access should not be possible with VFS" );
405
+ checkException (SecurityException .class , () -> fs .checkAccess (Path .of (pathPrefix , "does-not-exist" ), Set .of (AccessMode .WRITE )), "execute access should not be possible with VFS" );
406
+ checkException (SecurityException .class , () -> fs .checkAccess (Path .of (pathPrefix , "SomeFile" ), Set .of (AccessMode .EXECUTE )), "execute access should not be possible with VFS" );
407
+ checkException (SecurityException .class , () -> fs .checkAccess (Path .of (pathPrefix , "does-not-exist" ), Set .of (AccessMode .EXECUTE )), "execute access should not be possible with VFS" );
408
+
390
409
checkException (NoSuchFileException .class , () -> fs .checkAccess (Path .of (pathPrefix , "does-not-exits" ), Set .of (AccessMode .READ )),
391
410
"should not be able to access a file which does not exist in VFS" );
392
411
checkException (NoSuchFileException .class , () -> fs .checkAccess (Path .of (pathPrefix , "does-not-exits" , "extractme" ), Set .of (AccessMode .READ )),
@@ -485,6 +504,11 @@ public void newByteChannel() throws Exception {
485
504
486
505
newByteChannelVFS (fs , VFS_MOUNT_POINT );
487
506
withCWD (fs , VFS_ROOT_PATH , (fst ) -> newByteChannelVFS (fst , "" ));
507
+
508
+ checkException (NullPointerException .class , () -> fs .newByteChannel (Path .of (VFS_MOUNT_POINT , "does-not-exist" ), null ));
509
+ withCWD (fs , VFS_ROOT_PATH , (fst ) -> checkException (NullPointerException .class , () -> fst .newByteChannel (Path .of ("does-not-exist" ), null )));
510
+ checkException (NullPointerException .class , () -> fs .newByteChannel (Path .of (VFS_MOUNT_POINT , "does-not-exist" , "extractme" ), null ));
511
+ withCWD (fs , VFS_ROOT_PATH , (fst ) -> checkException (NullPointerException .class , () -> fst .newByteChannel (Path .of ("does-not-exist" , "extractme" ), null )));
488
512
}
489
513
490
514
// from real FS
@@ -502,25 +526,34 @@ public void newByteChannel() throws Exception {
502
526
}
503
527
504
528
private static void newByteChannelVFS (FileSystem fs , String pathPrefix ) throws IOException {
505
- Path path = Path .of (pathPrefix , "file1" );
506
- for (StandardOpenOption o : StandardOpenOption .values ()) {
529
+ Path file1 = Path .of (pathPrefix , "file1" );
530
+ Path extractable = Path .of (pathPrefix , "extractme" );
531
+ for (StandardOpenOption o : new StandardOpenOption []{StandardOpenOption .WRITE , StandardOpenOption .READ }) {
507
532
if (o == StandardOpenOption .READ ) {
508
- SeekableByteChannel bch = fs .newByteChannel (path , Set .of (o ));
509
- ByteBuffer buffer = ByteBuffer .allocate (1024 );
510
- bch .read (buffer );
511
- String s = new String (buffer .array ());
512
- String [] ss = s .split (System .lineSeparator ());
513
- assertTrue (ss .length >= 2 );
514
- assertEquals ("text1" , ss [0 ]);
515
- assertEquals ("text2" , ss [1 ]);
516
-
517
- checkException (IOException .class , () -> bch .write (buffer ), "should not be able to write to VFS" );
518
- checkException (IOException .class , () -> bch .truncate (0 ), "should not be able to write to VFS" );
533
+ newByteChannelVFS (fs , file1 , Set .of (o ));
534
+ newByteChannelVFS (fs , file1 , Set .of (o , LinkOption .NOFOLLOW_LINKS ));
535
+ newByteChannelVFS (fs , extractable , Set .of (o ));
536
+ checkException (IOException .class , () -> fs .newByteChannel (extractable , Set .of (o , LinkOption .NOFOLLOW_LINKS )));
519
537
} else {
520
- checkCanOnlyRead (fs , path , o );
538
+ checkCanOnlyRead (fs , file1 , o );
539
+ checkCanOnlyRead (fs , extractable , o );
521
540
}
522
541
}
523
- checkCanOnlyRead (fs , path , StandardOpenOption .READ , StandardOpenOption .WRITE );
542
+ checkCanOnlyRead (fs , file1 , StandardOpenOption .READ , StandardOpenOption .WRITE );
543
+ checkCanOnlyRead (fs , extractable , StandardOpenOption .READ , StandardOpenOption .WRITE );
544
+ }
545
+
546
+ private static void newByteChannelVFS (FileSystem fs , Path path , Set <OpenOption > options ) throws IOException {
547
+ SeekableByteChannel bch = fs .newByteChannel (path , options );
548
+ ByteBuffer buffer = ByteBuffer .allocate (1024 );
549
+ bch .read (buffer );
550
+ String s = new String (buffer .array ());
551
+ String [] ss = s .split (System .lineSeparator ());
552
+ assertTrue (ss .length >= 2 );
553
+ assertEquals ("text1" , ss [0 ]);
554
+ assertEquals ("text2" , ss [1 ]);
555
+ checkException (NonWritableChannelException .class , () -> bch .write (buffer ), "should not be able to write to VFS" );
556
+ checkException (NonWritableChannelException .class , () -> bch .truncate (0 ), "should not be able to write to VFS" );
524
557
}
525
558
526
559
private static void newByteChannelRealFS (FileSystem fs , Path path , String expectedText ) throws IOException {
@@ -622,6 +655,19 @@ private static void readAttributesVFS(FileSystem fs, String pathPrefix) throws I
622
655
Map <String , Object > attrs = fs .readAttributes (Path .of (pathPrefix , "dir1" ), "creationTime" );
623
656
assertEquals (FileTime .fromMillis (0 ), attrs .get ("creationTime" ));
624
657
658
+ attrs = fs .readAttributes (Path .of (pathPrefix , "extractme" ), "creationTime,isSymbolicLink,isRegularFile" , LinkOption .NOFOLLOW_LINKS );
659
+ assertEquals (FileTime .fromMillis (0 ), attrs .get ("creationTime" ));
660
+ assertTrue ((Boolean ) attrs .get ("isSymbolicLink" ));
661
+ assertFalse ((Boolean ) attrs .get ("isRegularFile" )); //
662
+
663
+ attrs = fs .readAttributes (Path .of (pathPrefix , "extractme" ), "creationTime,isSymbolicLink,isRegularFile" );
664
+ assertNotEquals (FileTime .fromMillis (0 ), attrs .get ("creationTime" ));
665
+ assertFalse ((Boolean ) attrs .get ("isSymbolicLink" ));
666
+ assertTrue ((Boolean ) attrs .get ("isRegularFile" ));
667
+
668
+ checkException (NoSuchFileException .class , () -> fs .readAttributes (Path .of (pathPrefix , "does-not-exist" , "extractme" ), "creationTime" , LinkOption .NOFOLLOW_LINKS ));
669
+ checkException (NoSuchFileException .class , () -> fs .readAttributes (Path .of (pathPrefix , "does-not-exist" , "extractme" ), "creationTime" ));
670
+
625
671
checkException (NoSuchFileException .class , () -> fs .readAttributes (Path .of (pathPrefix , "does-not-exist" ), "creationTime" ), "" );
626
672
checkException (UnsupportedOperationException .class , () -> fs .readAttributes (Path .of (pathPrefix , "file1" ), "unix:creationTime" ), "" );
627
673
}
@@ -876,7 +922,6 @@ public void createAndReadSymbolicLink() throws Exception {
876
922
checkException (IOException .class , () -> fs .createSymbolicLink (VFS_ROOT_PATH .resolve ("link1" ), realFSLinkTarget ));
877
923
878
924
checkException (SecurityException .class , () -> fs .createSymbolicLink (VFS_ROOT_PATH , VFS_ROOT_PATH .resolve ("link" )));
879
- checkException (SecurityException .class , () -> fs .readSymbolicLink (VFS_ROOT_PATH .resolve ("link1" )));
880
925
}
881
926
checkException (SecurityException .class , () -> rHostIOVFS .createSymbolicLink (realFSDir .resolve ("link2" ), realFSLinkTarget ));
882
927
checkException (SecurityException .class , () -> noHostIOVFS .createSymbolicLink (realFSDir .resolve ("link3" ), realFSLinkTarget ));
@@ -902,6 +947,20 @@ private void checkSymlink(Path dir, Path target, Path symlink) throws Exception
902
947
}
903
948
}
904
949
950
+ @ Test
951
+ public void readSymbolicLink () throws Exception {
952
+ for (FileSystem fs : new FileSystem []{rwHostIOVFS , rHostIOVFS , noHostIOVFS }) {
953
+ readSymbolicLink (fs , VFS_MOUNT_POINT );
954
+ withCWD (fs , VFS_ROOT_PATH , (fst ) -> readSymbolicLink (fst , "" ));
955
+ }
956
+ }
957
+
958
+ private static void readSymbolicLink (FileSystem fs , String vfsPrefix ) throws IOException {
959
+ checkException (NotLinkException .class , () -> fs .readSymbolicLink (Path .of (vfsPrefix , "file1" )));
960
+ checkException (NoSuchFileException .class , () -> fs .readSymbolicLink (Path .of (vfsPrefix , "does-not-exist" )));
961
+ checkExtractedFile (fs .readSymbolicLink (Path .of (vfsPrefix , "extractme" )), new String []{"text1" , "text2" });
962
+ }
963
+
905
964
@ Test
906
965
public void move () throws Exception {
907
966
Path realFSDir = Files .createTempDirectory ("graalpy.vfs.test" );
0 commit comments