除非缓冲区大小是512的倍数,否则读取NTFS卷根目录失败

本文关键字:读取 NTFS 失败 根目录 缓冲区 | 更新日期: 2023-09-27 17:57:58

我在玩MFT,首先使用p/Invoke调用读取C:驱动器的根目录。使用下面的代码,如果缓冲区大小是512的倍数,我会得到预期的结果,但如果不是这样,则读取失败,返回ERROR_INVALID_PARAMETER。这与集群大小有关吗?这似乎不太可能,因为我的集群大小为4k字节。很明显,我可以只使用512的倍数,但在我看来,这可能是不可移植的,当然我想理解为什么会这样

    public void Test()
    {
        string driveRoot = @"''.'" + "C:";
        IntPtr hRoot = MFT.CreateFile(
            driveRoot,
            MFT.GENERIC_READ | MFT.GENERIC_WRITE,
            MFT.FILE_SHARE_READ | MFT.FILE_SHARE_WRITE,
            IntPtr.Zero,
            MFT.OPEN_EXISTING,
            MFT.FILE_ATTRIBUTE_NORMAL,
            IntPtr.Zero);
        if (hRoot.ToInt32() == MFT.INVALID_HANDLE_VALUE)
            throw new IOException(string.Format("CreateFile() returned invalid handle [Win32 error {0}]", Marshal.GetLastWin32Error()));
        // TODO why does this fail unless buffer size is a multiple of 512? Is it to do with cluster size?
        UInt32 numBytesToRead = 512;
        byte[] buffer = new byte[numBytesToRead];
        if (ReadFileFromHandleSync(hRoot, buffer, numBytesToRead))
            Debug.WriteLine("OK " + i);
    }

    public bool ReadFileFromHandleSync(IntPtr handle, byte[] buffer, UInt32 numBytesToRead)
    {
        UInt32 numBytesRead;
        NativeOverlapped overlapped = new NativeOverlapped();
        bool readOK = ReadFile(handle, buffer, numBytesToRead, out numBytesRead, ref overlapped);
        return readOK;
    }
}

除非缓冲区大小是512的倍数,否则读取NTFS卷根目录失败

对于直接卷访问,必须以扇区长度的倍数读取和写入,并从对齐的偏移量开始。也就是说,位置必须是扇区长度的倍数。

您将需要查询卷以找出扇区长度。使用GetDiskFreeSpaceIOCTL_DISK_GET_DRIVE_GEOMETRY_EX

我看到你正在请求写访问权限,并在本地C驱动器上工作。你确定这是明智的吗?一次失误,你就把系统冲洗干净了。也许在VM或卷中工作,但您很乐意失去它。