I'm trying to get file HANDLE by NTFS file id.
Memory p = new Memory(128);
Kernel32.INSTANCE.GetFileInformationByHandleEx(
hFile,
WinBase.FileIdInfo,
p,
new DWORD(p.size())
);
FILE_ID_INFO fii = new FILE_ID_INFO(p);
From FILE_ID_INFO I can get VolumeSerialNumber and FileId.Identifier
Kernel32.INSTANCE.CreateFile(
path,
FILE_READ_ATTRIBUTES,
1 | 2 | 4,
null,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
null
)
HANDLE OpenFileById(
HANDLE hVolumeHint,
Structure lpFileId,
int dwDesiredAccess,
int dwShareMode,
SECURITY_ATTRIBUTES lpSecurityAttributes,
int dwFlagsAndAttributes
);
Required structure
@FieldOrder({"dwSize", "Type", "Id"})
public static class FILE_ID_DESCRIPTOR extends Structure {
public UINT dwSize;
public int Type;
public DUMMYUNIONNAME Id;
@FieldOrder({"FileId", "ObjectId", "ExtendedFileId"})
public static class DUMMYUNIONNAME extends Union {
public long FileId;
public GUID ObjectId;
public FILE_ID_128 ExtendedFileId;
public DUMMYUNIONNAME() {
super();
}
public DUMMYUNIONNAME(long Id) {
this.FileId = Id;
write();
}
}
public static UINT sizeOf() {
return new UINT(Native.getNativeSize(FILE_ID_DESCRIPTOR.class, null));
}
public FILE_ID_DESCRIPTOR() {
super();
}
public FILE_ID_DESCRIPTOR(Pointer memory) {
super(memory);
read();
}
public FILE_ID_DESCRIPTOR(UINT dwSize, int type,
DUMMYUNIONNAME id) {
this.dwSize = dwSize;
this.Type = type;
this.Id = id;
write();
}
}
Usage
FILE_ID_DESCRIPTOR fileIdDesc = new FILE_ID_DESCRIPTOR(FILE_ID_DESCRIPTOR.sizeOf(), 0, new DUMMYUNIONNAME(fii.FileId.Identifier));
HANDLE handle = Kernel32.INSTANCE.OpenFileById(hVolume, fileIdDesc, FILE_READ_ATTRIBUTES, 1 | 2 | 4, null, FILE_FLAG_BACKUP_SEMANTICS);
When I after executing Kernel32.INSTANCE.GetLastError(); It gives me - 87 Invalid Parameter.
I've change FILE_ID_DESCRIPTOR to accept long instead of byte[], and other changes - but everytime - same error.
Similar code works successfully in C#, but I need it to run in Java as well.
Please advise.
You've incorrectly initialized your FILE_ID_DESCRIPTOR
values:
new FILE_ID_DESCRIPTOR(
FILE_ID_DESCRIPTOR.sizeOf(),
0,
new DUMMYUNIONNAME(fii.FileId.Identifier)
);
You're passing the Type
parameter as 0, indicating you want the long FileId
from the union.
But you have hardcoded your dummy union constructor to assign the value to the 8-byte long
member when the value of fii.FileId.Identifier
is a 16-byte array.
You've indicated in the comments that:
this what you see in the post - is the last version I was trying. The DUMMYUNIONNAME was Structure, Pointer, there were NO DUMMYUNIONNAME, but just Id, etc. I was trying from 4 - to 512 bits - error code never changed.
There is exactly one right answer and it's 16 bytes (128 bits). However, if you pass a Type
of 0, it's only reading the first 8 bytes (64 bits) of your fii.FileId.Identifier
.
Most likely you want to set/read the ExtendedFileId
field in the union, by setting a Type
of 2.
There are several other issues with your code that are not the cause of the error:
FILE_ID_INFO
by giving 128 bytes to p
. You haven't shown your mapping for it, but it's an 8-byte long
followed by a structure wrapping a 16-byte array so you only need 24 bytes.sizeOf()
. JNA's Structure
has a size()
method that does exactly what you're asking. Or you can just use your knowledge that in this case the size is always 24.dwSize
field of FILE_ID_DESCRIPTOR
is a DWORD
not a UINT
. Since these are both 32-bit values it doesn't make a difference. Since Java does not have a concept of signed integers you may as well just simplify and pass an int
here.Union
class you should fully implement it including overriding the read()
in the union to read the appropriate native value. In your case, you're only writing it for use once, so you can just skip the complexity of the union and directly assign the internal field you want. If that's the largest size value (the FILE_ID_128
) you can just assign it directly. If it's a smaller size value (the long
then you could just add padding to make sure the entire structure size is 24 bytes).