如何使用Java或C ++获取文件MFT入口/ inode

时间:2012-02-19 22:05:53

标签: windows filesystems ntfs hardlink ntfs-mft

我在Java中编写了一个重复的查找器,但我需要为它添加硬链接支持。不幸的是,似乎没有办法在Java中挖出文件的MFT条目。

虽然在BasicFileAttributeView类中有一个名为fileKey()的方法,但它在NTFS文件系统上不起作用(我还没有在ext上测试过它)。

我还找到了方法isSameFile()(在java.nio.file.Path中)。有谁知道这种方法是如何工作的?它似乎正在做正确的事情,但它返回一个布尔值,所以它对我来说毫无价值(我希望将结果放入地图并按照MFT条目对它们进行分组)。

我总能比较每个文件的创建时间,修改时间等,但这只是放弃了。

有没有办法在C ++或Java中完成我想要做的事情?我更关心的是让它在NTFS上工作而不是分机。

4 个答案:

答案 0 :(得分:1)

通常通过调用FindFirstFileNameW来完成检测硬链接。但是有一个较低层次的方式。

要使NTFS等同于inode,请尝试使用FSCTL_GET_OBJECT_ID ioctl代码。

BY_HANDLE_FILE_INFORMATION structure中还有一个唯一的(直到文件被删除)标识符。

如果卷已启用USN Change Journal,您可以发出FSCTL_READ_FILE_USN_DATA ioctl代码。查看USN_RECORD structure

中的FileReferenceNumber成员

答案 1 :(得分:1)

您需要使用FILE_ID_FULL_DIRECTORY_INFORMATION结构以及NtQueryDirectoryFile功能(或FILE_INTERNAL_INFORMATION结构以及NtQueryInformationFile,如果您已经拥有句柄) ntdll.dll(自Windows XP以来可用,如果不是更早的话)获取8字节文件ID并检查它们是否相同。

这将告诉您它们是否是相同的文件,但如果它们是同一文件的 stream ,则不会。

我不确定如何检测两个文件是否是来自用户模式的相同流 - 有一个名为FILE_STREAM_INFORMATION的结构可以返回与文件关联的所有流,但它不会告诉你你当前打开了哪个流。

答案 2 :(得分:0)

在Java中,您可以使用sun.nio.ch.FileKey,它是NTFS Inode的非透明机箱。所有硬链接共享相同的Inode。

因此,如果您需要收集硬链接,可以从每个嫌疑人创建FileKey并进行比较(例如,将一对FileKey - >文件放入Multimap

答案 3 :(得分:0)

我发现fileKey始终为空。这是一些可以实际读取NTFS索引节点号的代码。我仍然不满意许多方面,尤其是它依赖反思。

import sun.nio.ch.FileKey;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Path;

public class NTFS {
    static long inodeFromPath(Path path) throws IOException, NoSuchFieldException, IllegalAccessException {
        try (FileInputStream fi = new FileInputStream(path.toFile())) {
            FileDescriptor fd = fi.getFD();

            FileKey fk = FileKey.create(fd);
            Field privateStringField = FileKey.class.getDeclaredField("nFileIndexHigh");
            privateStringField.setAccessible(true);
            long high = (long) privateStringField.get(fk);
            privateStringField = FileKey.class.getDeclaredField("nFileIndexLow");
            privateStringField.setAccessible(true);
            long low = (long) privateStringField.get(fk);

            long power = (long) 1 << 32;
            long inode = high * power + low;
            return inode;
        }
    }
}