Java JNA OpenFileById 失败,错误代码为 87 InvalidParameter

问题描述 投票:0回答:1

我正在尝试通过 NTFS 文件 ID 获取文件 HANDLE

  1. 有文件 HANLDE 我得到 FILE_ID_INFO
            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);

从 FILE_ID_INFO 我可以得到 VolumeSerialNumberFileId.Identifier

  1. 现在当我有了它时——我想使用 VolumeSerialNumber 和 FileId.Identifier 打开 HANDLE
  2. 首先使用 Kernel32Util.getLogicalDriveStrings()Kernel32.INSTANCE.GetVolumeInformation 我可以通过 VolumeSerialNumber 找到 VolumeId - 在我的例子中是 D:\
  3. 现在我打开 HANDLE for D:\ 使用 Kernel32.INSTANCE.CreateFile
Kernel32.INSTANCE.CreateFile(path, FILE_READ_ATTRIBUTES, 1 | 2 | 4, null, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, null)
  1. 最后一步 - 使用 OpenFileById 我正在尝试通过其 ID 打开文件 HANDLE。 方法定义
HANDLE OpenFileById(HANDLE hVolumeHint, Structure lpFileId, int dwDesiredAccess, int dwShareMode, SECURITY_ATTRIBUTES lpSecurityAttributes, int dwFlagsAndAttributes);

所需结构

@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();
        }
    }

用法

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);

当我执行后 Kernel32.INSTANCE.GetLastError(); 它给了我 - 87 Invalid Parameter.

我已经更改 FILE_ID_DESCRIPTOR 以接受 long 而不是 byte[],以及其他更改 - 但每次 - 同样的错误。

类似的代码在 C# 中成功运行,但我也需要它在 Java 中运行。

请指教

java windows filesystems jna ntfs
1个回答
0
投票

你错误地初始化了你的

FILE_ID_DESCRIPTOR
值:

new FILE_ID_DESCRIPTOR(
   FILE_ID_DESCRIPTOR.sizeOf(),
   0,
   new DUMMYUNIONNAME(fii.FileId.Identifier)
);

您将

Type
参数传递为 0,表示您想要联合中的
long FileId

但是当

long
的值是 16 字节数组时,您已将虚拟联合构造函数硬编码为将值分配给 8 字节
fii.FileId.Identifier
成员。

您在评论中指出:

这是你在帖子中看到的 - 是我尝试的最后一个版本。 DUMMYUNIONNAME 是结构、指针,没有 DUMMYUNIONNAME,只有 Id 等。我尝试从 4 位到 512 位 - 错误代码从未改变。

只有一个正确答案,它是 16 个字节(128 位)。但是,如果您传递 0 的

Type
,它只会读取您的
fii.FileId.Identifier
的前 8 个字节(64 位)。

您很可能想通过设置 2 的

ExtendedFileId
来设置/读取联合中的
Type
字段。

您的代码还有其他几个问题不是错误原因:

  1. 创建
    FILE_ID_INFO
    时,通过为
    p
    提供 128 个字节来过度分配内存。您还没有显示它的映射,但它是一个 8 字节的
    long
    后跟一个包装 16 字节数组的结构,因此您只需要 24 个字节。
  2. 您不需要实施自己的
    sizeOf()
    。 JNA 的
    Structure
    有一个
    size()
    方法可以完全满足您的要求。或者你可以只使用你的知识,在这种情况下大小总是 24.
  3. dwSize
    FILE_ID_DESCRIPTOR
    场是一个
    DWORD
    而不是一个
    UINT
    。因为它们都是 32 位值,所以没有区别。由于 Java 没有带符号整数的概念,您不妨在这里简化并传递一个
    int
  4. 如果你想真正利用 JNA 的
    Union
    类,你应该完全实现它,包括覆盖联合中的
    read()
    以读取适当的本机值。在你的情况下,你只写它一次使用,所以你可以跳过联合的复杂性并直接分配你想要的内部字段。如果这是最大的尺寸值(
    FILE_ID_128
    ),您可以直接分配它。如果它的大小值较小(
    long
    ,那么您可以添加填充以确保整个结构大小为 24 字节)。
© www.soinside.com 2019 - 2024. All rights reserved.