You can use reflection to get the file descriptor from a RandomAccessFile
:
long pid = ProcessHandle.current().pid();
long guessedFd = Files.list(Path.of("/proc/"+pid+"/fd")).count();
var file = new java.io.RandomAccessFile(FUSE_DEVICE_PATH.toFile(), "rw");
FileChannel fc = file.getChannel(); // Use FileChannel for fast NIO
var javaFd = file.getFD();
try {
Field f = FileDescriptor.class.getDeclaredField("fd");
f.setAccessible(true);
var trueFd = (int) f.get(javaFd);
return trueFd;
}
catch (InaccessibleObjectException | NoSuchFieldException | IllegalAccessException e) {
return guessedFd;
}
On Java 11+ you will the jvm option --add-opens=java.base/java.io=ALL-UNNAMED
at startup. Tested on Java 18.
In Java 17 you can use SharedSecrets
instead of reflection:
FileDescriptor javaFd = ...
try {
int trueFd = jdk.internal.access.SharedSecrets.getJavaIOFileDescriptorAccess().get(javaFd);
return trueFd;
}
catch (IllegalAccessError e) {
return guessedFd;
}
You will need to add --add-exports=java.base/jdk.internal.access=ALL-UNNAMED
when compiling and running. See for Maven.