@@ -178,7 +178,7 @@ private static String absoluteResourcePath(String... components) {
178
178
private static final char RESOURCE_SEPARATOR_CHAR = '/' ;
179
179
private static final String RESOURCE_SEPARATOR = String .valueOf (RESOURCE_SEPARATOR_CHAR );
180
180
181
- private abstract class BaseEntry {
181
+ private abstract sealed class BaseEntry permits FileEntry , DirEntry {
182
182
final String platformPath ;
183
183
184
184
private BaseEntry (String platformPath ) {
@@ -192,6 +192,10 @@ String getPlatformPath() {
192
192
String getResourcePath () {
193
193
return platformPathToResourcePath (platformPath );
194
194
}
195
+
196
+ static AssertionError throwUnexpectedSubclass () {
197
+ throw new AssertionError ("Unexpected subclass of sealed DirEntry" );
198
+ }
195
199
}
196
200
197
201
private final class FileEntry extends BaseEntry {
@@ -735,6 +739,15 @@ private BaseEntry getEntry(Path inputPath) {
735
739
return vfsEntries .get (toCaseComparable (path .toString ()));
736
740
}
737
741
742
+ private BaseEntry getEntrySafe (String callerId , Path path ) throws NoSuchFileException {
743
+ BaseEntry entry = getEntry (path );
744
+ if (entry == null ) {
745
+ finer ("%s: no such file or directory: '%s'" , callerId , path );
746
+ throw new NoSuchFileException (path .toString ());
747
+ }
748
+ return entry ;
749
+ }
750
+
738
751
/**
739
752
* Determines if the given path belongs to the VFS. The path should be already normalized
740
753
*/
@@ -947,11 +960,7 @@ public void checkAccess(Path p, Set<? extends AccessMode> modes, LinkOption... l
947
960
throw securityException ("VFS.checkAccess" , String .format ("execute access not supported for '%s'" , p ));
948
961
}
949
962
950
- if (getEntry (path ) == null ) {
951
- String msg = String .format ("no such file or directory: '%s'" , path );
952
- finer ("VFS.checkAccess %s" , msg );
953
- throw new NoSuchFileException (msg );
954
- }
963
+ getEntrySafe ("VFS.checkAccess" , path );
955
964
finer ("VFS.checkAccess %s OK" , path );
956
965
}
957
966
@@ -1100,7 +1109,7 @@ public DirectoryStream<Path> newDirectoryStream(Path d, DirectoryStream.Filter<?
1100
1109
Objects .requireNonNull (d );
1101
1110
Path dir = toAbsoluteNormalizedPath (d );
1102
1111
Objects .requireNonNull (filter );
1103
- BaseEntry entry = getEntry ( dir );
1112
+ BaseEntry entry = getEntrySafe ( "VFS.newDirectoryStream" , dir );
1104
1113
if (entry instanceof FileEntry ) {
1105
1114
finer ("VFS.newDirectoryStream not a directory %s" , dir );
1106
1115
throw new NotDirectoryException (dir .toString ());
@@ -1127,9 +1136,8 @@ public Iterator<Path> iterator() {
1127
1136
}).map (e -> Path .of (e .getPlatformPath ())).iterator ();
1128
1137
}
1129
1138
};
1130
- } else {
1131
- throw new NoSuchFileException (dir .toString ());
1132
1139
}
1140
+ throw BaseEntry .throwUnexpectedSubclass ();
1133
1141
}
1134
1142
1135
1143
private static Path toAbsoluteNormalizedPath (Path path ) {
@@ -1195,12 +1203,7 @@ public Map<String, Object> readAttributes(Path p, String attributes, LinkOption.
1195
1203
}
1196
1204
}
1197
1205
1198
- BaseEntry entry = getEntry (path );
1199
- if (entry == null ) {
1200
- String msg = String .format ("no such file or directory: '%s'" , path );
1201
- finer ("VFS.readAttributes %s" , msg );
1202
- throw new NoSuchFileException (msg );
1203
- }
1206
+ BaseEntry entry = getEntrySafe ("VFS.readAttributes" , path );
1204
1207
HashMap <String , Object > attrs = new HashMap <>();
1205
1208
if (attributes .startsWith ("unix:" ) || attributes .startsWith ("posix:" )) {
1206
1209
finer ("VFS.readAttributes unsupported attributes '%s' %s" , path , attributes );
@@ -1282,7 +1285,7 @@ public Path readSymbolicLink(Path link) throws IOException {
1282
1285
}
1283
1286
if (getEntry (path ) == null ) {
1284
1287
finer ("VFS.readSymbolicLink no entry for path '%s'" , link );
1285
- throw new NoSuchFileException (String . format ( "no such file or directory: '%s'" , path ));
1288
+ throw new NoSuchFileException (path . toString ( ));
1286
1289
}
1287
1290
throw new NotLinkException (link .toString ());
1288
1291
}
@@ -1304,6 +1307,63 @@ public Path getTempDirectory() {
1304
1307
throw new RuntimeException ("should not reach here" );
1305
1308
}
1306
1309
1310
+ @ Override
1311
+ public boolean isFileStoreReadOnly (Path path ) throws NoSuchFileException {
1312
+ Objects .requireNonNull (path );
1313
+ getEntrySafe ("VFS.isFileStoreReadOnly" , path );
1314
+ return true ;
1315
+ }
1316
+
1317
+ @ Override
1318
+ public long getFileStoreTotalSpace (Path path ) throws IOException {
1319
+ Objects .requireNonNull (path );
1320
+ getEntrySafe ("VFS.getFileStoreTotalSpace" , path );
1321
+ return getEntryTotalSpace (getEntrySafe ("VFS.getFileStoreTotalSpace:VFS-root:" , mountPoint ));
1322
+ }
1323
+
1324
+ private long getEntryTotalSpace (BaseEntry entry ) throws IOException {
1325
+ // This is a bit arbitrary best effort approximation.
1326
+ // For each file we count its data size and for each entry we take its full path size (+1
1327
+ // for newline) as this is what we store in the filelist.txt, so the total should
1328
+ // approximate the size the VFS takes up in the resources.
1329
+ try {
1330
+ long size = entry .getResourcePath ().length () + 1 ;
1331
+ if (entry instanceof FileEntry fe ) {
1332
+ size = Math .addExact (size , fe .getData ().length );
1333
+ } else if (entry instanceof DirEntry de ) {
1334
+ for (BaseEntry e : de .entries ) {
1335
+ size = Math .addExact (size , getEntryTotalSpace (e ));
1336
+ }
1337
+ } else {
1338
+ throw BaseEntry .throwUnexpectedSubclass ();
1339
+ }
1340
+ return size ;
1341
+ } catch (ArithmeticException ex ) {
1342
+ return Long .MAX_VALUE ;
1343
+ }
1344
+ }
1345
+
1346
+ @ Override
1347
+ public long getFileStoreUsableSpace (Path path ) throws NoSuchFileException {
1348
+ Objects .requireNonNull (path );
1349
+ getEntrySafe ("VFS.getFileStoreUsableSpace" , path );
1350
+ return 0 ;
1351
+ }
1352
+
1353
+ @ Override
1354
+ public long getFileStoreUnallocatedSpace (Path path ) throws NoSuchFileException {
1355
+ Objects .requireNonNull (path );
1356
+ getEntrySafe ("VFS.getFileStoreUnallocatedSpace" , path );
1357
+ return 0 ;
1358
+ }
1359
+
1360
+ @ Override
1361
+ public long getFileStoreBlockSize (Path path ) throws NoSuchFileException {
1362
+ Objects .requireNonNull (path );
1363
+ getEntrySafe ("VFS.getFileStoreBlockSize" , path );
1364
+ return 4096 ;
1365
+ }
1366
+
1307
1367
private static void warn (String msgFormat , Object ... args ) {
1308
1368
if (LOGGER .isLoggable (Level .WARNING )) {
1309
1369
LOGGER .log (Level .WARNING , String .format (msgFormat , args ));
0 commit comments