'Get Linux file descriptor of FileChannel
Is there a way to get the Linux file descriptor for an opened FileChannel?
I need it to call mount.fuse -o fd=...
(for implementing FUSE).
As a hacky workaround, I'm doing:
var pid = ProcessHandle.current().pid();
var fd = Files.list(Path.of("/proc/"+pid+"/fd")).count();
var fc = FileChannel.open(path);
System.out.println("file descriptor: " + fd);
Note that two file descriptors appear. One for path
and another socket
. I'm using the first one. What is the socket for?
Solution 1:[1]
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.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |