Winapi LockFileEx可以与卷句柄一起使用吗?
我正在试验Winapi LockFileEx可以与卷句柄一起使用吗?,winapi,ntfs,ntfs-mft,defragmentation,Winapi,Ntfs,Ntfs Mft,Defragmentation,我正在试验FSCTL\u MOVE\u文件。大部分情况下,一切正常。然而,有时如果我试图重新读取(通过FSCTL\u GET\u NTFS\u FILE\u RECORD)我刚刚移动的Mft记录,我会得到一些错误的数据 具体地说,如果文件记录说$ATTRIBUTE_LIST属性是非常驻的,并且我使用卷句柄从磁盘读取数据,我会发现那里的数据内部不一致(记录长度大于数据的实际长度) 当我看到这种情况发生时,原因就很清楚了:在Ntfs驱动程序完成编写之前,我正在读取记录。调试支持这一理论。但知道这一点
FSCTL\u MOVE\u文件
。大部分情况下,一切正常。然而,有时如果我试图重新读取(通过FSCTL\u GET\u NTFS\u FILE\u RECORD
)我刚刚移动的Mft记录,我会得到一些错误的数据
具体地说,如果文件记录说$ATTRIBUTE_LIST属性是非常驻的,并且我使用卷句柄从磁盘读取数据,我会发现那里的数据内部不一致(记录长度大于数据的实际长度)
当我看到这种情况发生时,原因就很清楚了:在Ntfs驱动程序完成编写之前,我正在读取记录。调试支持这一理论。但知道这一点并不能帮我解决问题。我对FSCTL\u MOVE\u FILE
调用使用了同步方法,但显然文件系统仍然可以在后台更新内容。嗯
在普通文件中,我会考虑使用共享锁的LockFileEx
(因为我只是在阅读)。但我不确定这对卷句柄有什么意义?我甚至不太确定Ntfs在内部使用这种机制来确保一致性
不过,这似乎是一个开始。但是我对卷句柄的LockFileEx
调用正在返回ERROR\u INVALID\u参数
。我不知道哪个参数可能出错,除非是卷句柄本身。也许他们只是不支持锁?或者在打开卷句柄时,我应该在CreateFile
中设置一些特殊标志?我已尝试启用SE\u BACKUP\u NAME
和FILE\u FLAG\u BACKUP\u SEMANTICS
,但错误保持不变
展望未来,我可以在这里看到一些备选方案:
ReadFile
的非常驻数据?我没找到,但也许我错过了J:
,因为那是我的闪存驱动器。50000是随机挑选的,但应该小于闪存驱动器的大小
void Lock()
{
WCHAR path[] = L"\\\\.\\j:";
HANDLE hRootHandle = CreateFile(path,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
OVERLAPPED olap;
memset(&olap, 0, sizeof(olap));
olap.Offset = 50000;
// Lock 1k of data at offset 50000
BOOL b = LockFileEx(hRootHandle, 1, 0, 1024, 0, &olap);
DWORD j = GetLastError();
CloseHandle(hRootHandle);
}
查看坏数据的代码是。。。相当复杂。然而,它很容易复制。当它失败时,我最终尝试读取长度为“0”的可变长度$ATTRIBUTE_列表项,这会导致一个无限循环,因为看起来我从未完成整个缓冲区的读取。如果长度为零,我就退出,但我担心缓冲区中的“剩余垃圾”而不是干净的零。检测到这一点是不可能的,所以我希望有一个更好的解决方案
毫不奇怪,关于这一切的信息并不多。因此,如果有人在这里有一些经验,我可以使用一些见解
编辑1: 更多不太有效的事情:
- 在LockFileEx上仍然没有运气
- 我试着冲洗音量手柄(正如保罗建议的那样)。虽然这样做有效,但它使我的执行时间增加了一倍多。严格地说,它仍然不能解决问题。仍然不能保证Ntfs不会在FlushFileBuffers和FSCTL\u GET\u Ntfs\u FILE\u RECORD/ReadFile之间再改变一些东西
- 我想知道$STANDARD_信息属性的“RecordChanged”时间戳。但是,它并没有因为属性列表的这些更改而更改
- 对文件进行碎片化最终会导致添加属性列表,并且随着碎片化的继续增加,更多的数据记录将添加到该列表中。添加数据记录时,UpdateSequenceEnumber(不是MFT_段_引用的一部分,而是另一个)将被更新。不幸的是,有一系列事件要执行此更新。显然,属性_LIST buffer'length'在'updateSequenceEnumber'之前更新。因此,查看“UpdateSequenceEnumber”是否已更改无助于避免读取(潜在的)错误信息
我下一个最好的想法是看看Ntfs是否总是在更新记录长度之前(或者在记录长度缩短时)将新字节归零。如果我可以依赖于记录长度为零(而不是任何可能占用这些字节的剩余数据),我可以假装将其称为固定。您的问题的解决方案似乎确实是使用卷句柄调用
FlushFileBuffers()
。在页面底部附近有这样一句话:
要刷新卷上所有打开的文件,请使用卷句柄调用FlushFileBuffers。调用方必须具有管理权限
该页面上的其他信息让我相信,这也会刷新元数据,尽管在这种特定情况下它没有直接这样说。也许你能告诉我这方面的最新情况
为了从细节上退一步,从更大的角度看一会儿,出于各种原因,必须有一个用于此的API,尽管我认为它可能不是公开的。我想我已经有了它
重申目标:
在使用FSCTL\u GET\u NTFS\u FILE\u RECORD
从Mft读取记录后,我一直发现属性列表
记录处于“不一致状态”,因此报告的记录长度大于记录中的实际数据量。读取写入内容之外的数据似乎有风险,因为我无法确定所读取的内容是否有效,或者是剩余的垃圾