Denys Stetsenko
Denys Stetsenko

Reputation: 43

How can I get POSIX file descriptor in Java 11?

I have method, which using sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess().get(FileDescriptor) by Java 8 for getting the real POSIX file descriptor. In Java 9 (and upper) SharedSecrets was migrated to jdk.internal.misc.

How can I get POSIX file descriptor in Java 11?

private int getFileDescriptor() throws IOException {
      final int fd = SharedSecrets.getJavaIOFileDescriptorAccess().get(getFD());
      if(fd < 1)
                throw new IOException("failed to get POSIX file descriptor!");

      return fd;
}

Thanks in advance!

Upvotes: 2

Views: 785

Answers (2)

Azure
Azure

Reputation: 91

To this I need to add that for newer versions of java you need to do this:

package demo;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;

public class demo {
    public static void main(String[] args) {
        try {
            var file = File.createTempFile("example-", ".log");
            try (var fis = new FileInputStream(file)) {
                var fd = fis.getFD();

                var fieldName = "handle"; // For Windows.
                if (!System.getProperty("os.name").toLowerCase().contains("windows")) {
                    fieldName = "fd"; // Other OS
                }

                var field = FileDescriptor.class.getDeclaredField(fieldName);
                field.setAccessible(true);
                var fdValue = field.get(fd);
                field.setAccessible(false);

                System.out.println(String.format("File: %s, %s: %s", file.getCanonicalPath(), fieldName, fdValue));
            } catch (IOException | NoSuchFieldException | IllegalAccessException e) {
                e.fillInStackTrace();
            }
        } catch (IOException e) {
            e.fillInStackTrace();
        }
    }
}

And, in newer versions of java, running it requires adding the jvm arg.

Otherwise you get errors like this:

Exception in thread "main" java.lang.reflect.InaccessibleObjectException: Unable to make field private int java.io.FileDescriptor.fd accessible: module java.base does not "opens java.io" to unnamed module @6973bf95
        at java.base/java.lang.reflect.AccessibleObject.throwInaccessibleObjectException(AccessibleObject.java:388)
        at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:364)
        at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:312)
        at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:183)
        at java.base/java.lang.reflect.Field.setAccessible(Field.java:177)
        at demo.demo.main(demo.java:21)

Okay, let's get this thing up and running:

java --add-opens=java.base/java.io=ALL-UNNAMED demo.java

# On windows, it will print something like this

File: C:\Users\sa\AppData\Local\Temp\example-3357139619800720980.log, handle: 1176  (long)

# Other operating systems will be

File: /tmp/example-16018319640958431712.log, fd: 6  (int)

They are defined in the jdk source code like this:

public final class FileDescriptor {

    private int fd;

    private long handle;
//...
}

Source: FileDescriptor.java

Upvotes: 0

AlexC
AlexC

Reputation: 1415

This is only to be used in case of emergency (or until you find a different way since this is not supported) because it does things unintended by the API and is not supported. Caveat emptor.

package sandbox;

import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;

public class GetFileHandle {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("somedata.txt")) {
            FileDescriptor fd = fis.getFD();

            Field field = fd.getClass().getDeclaredField("fd");
            field.setAccessible(true);
            Object fdId = field.get(fd);
            field.setAccessible(false);

            field = fd.getClass().getDeclaredField("handle");
            field.setAccessible(true);
            Object handle = field.get(fd);
            field.setAccessible(false);

            // One of these will be -1 (depends on OS)
            // Windows uses handle, non-windows uses fd
            System.out.println("fid.handle="+handle+"  fid.fd"+fdId);
        } catch (IOException | NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

Upvotes: 1

Related Questions