我正在试验FSCTL_MOVE_FILE
。一切都按预期工作。但是,有时如果我尝试重新阅读(通过FSCTL_GET_NTFS_FILE_RECORD
)移动的Mft记录,我会收到一些不良数据。
具体来说,如果文件记录显示$ ATTRIBUTE_LIST属性是非驻留的并且我使用我的卷句柄从磁盘读取数据,我发现那里的数据内部不一致(记录长度大于实际长度)数据)。
当我看到这种情况发生时,原因很明显:我在Ntfs驱动程序完成编写之前读取了记录。调试支持这一理论。但知道这并没有帮助我解决它。我使用同步方法进行FSCTL_MOVE_FILE
调用,但显然文件系统仍然可以在后台更新内容。 HMM。
在普通文件中,我正在考虑使用共享锁LockFileEx
(因为我只是在阅读)。但我不确定卷句处理有什么意义吗?而且我甚至不太确定Ntfs在内部使用这种机制来确保一致性。
不过,它似乎是一个开始的地方。但我对卷句柄的LockFileEx
调用正在返回ERROR_INVALID_PARAMETER
。我没有看到哪个参数可能出错,除非它是音量句柄本身。也许他们只是不支持锁?或者在打开音量控制柄时,我可能会在CreateFile
中设置一些特殊标志?我已尝试启用SE_BACKUP_NAME
和FILE_FLAG_BACKUP_SEMANTICS
,但错误仍未改变。
继续前进,我可以在这里看到一些替代方案:
ReadFile
涉及的非驻留数据的方法?我没找到,但也许我错过了。 FWIW,这是针对卷句柄执行LockFileEx的一些测试代码。请注意,您必须以管理员身份运行才能锁定卷句柄。我使用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_LIST条目。 length,导致无限循环,因为它看起来像我从未读完整个缓冲区。如果长度为零,我会通过退出来解决它,但我担心剩下的垃圾"在缓冲区而不是干净的零。检测到这是不可能的,所以我希望有更好的解决方案。
毫不奇怪,没有任何关于此的信息。所以如果有人在这里有一些经验,我可以使用一些见解。
编辑1:
更多不能发挥作用的事情:
我的下一个最好的想法是,在更新记录长度之前(或者每当记录长度缩小时),Ntfs是否总是将新字节归零()。如果我可以依赖于记录长度为零(而不是任何剩余数据可能占用这些字节),我可以假装称之为固定。
答案 0 :(得分:2)
问题的解决方案确实似乎是通过卷的句柄调用FlushFileBuffers()
。靠近页面底部MSDN可以这样说:
要刷新卷上的所有打开文件,请使用卷的句柄调用FlushFileBuffers。调用者必须具有管理权限...
该页面上的其他信息让我相信这也会刷新元数据,尽管在这种特定情况下它并没有直接说明。也许你可以更新我。
要退出细节并暂时查看大图,有作为此处的API,出于各种原因,尽管我认为它可能不公开
答案 1 :(得分:1)
我想我已经明白了。
重申目标:
使用FSCTL_GET_NTFS_FILE_RECORD
从Mft读取记录后,我一直发现ATTRIBUTE_LIST
记录处于“不一致状态”,以致报告的记录长度大于实际记录中的数据量。读取超出已写入数据的数据似乎存在风险,因为我无法确定我所阅读的内容是有效的还是剩余的垃圾。
为此,我提出了4个替代方案,我希望能让我解决这个问题。
FSCTL_MOVE_FILE
之后等待一些(未指明的)时间不是一个计划,这是一个希望。对于brief time,看起来检查NtfsRecord中的UpdateSequenceNumber可能会提供解决方案。但是,更新记录时Ntfs使用的事件顺序意味着ATTRIBUTE_LIST的记录长度在UpdateSequenceNumber之前更新(好)。
然后我开始考虑这可能是一个什么问题。如果我忽略它,它会在哪里失败?
目前我遇到了问题,因为ATTRIBUTE_LIST正在增长(因为我故意并大规模地分割文件)。那时,由于零记录长度,它很容易被检测到。我已经多次运行该程序,虽然它只是轶事,但随着记录的增长,额外的空间一直被归零。这是有道理的,因为当您第一次分配它时,您将整个缓冲区归零。标准编程实践和观察都支持这一结论。
但是当唱片开始缩小时呢?或缩小然后增长?你最终可以得到剩余的数据而不是(容易解释的)零吗?
然后它击中了我:ATTRIBUTE_LIST 永不缩小 。几个星期前,我just complaining就此问题。即使您完全对文件进行碎片整理并且不再需要所有这些额外的DATA记录,Ntfs也不会压缩它们。现在我第一次看到为什么会这样。这可能会在W10中发生possibility,但这可能只是对未记录的函数过于乐观的解释。
所以,我不需要担心读取垃圾数据(可能包括无意义的记录长度导致我超出缓冲区)。 ATTRIBUTE_LIST中的记录长度可以信任。最后一条记录可能只有零记录长度。
我可以忽略零长度记录(基本上返回预增长信息)或重新读取记录,直到UpdateSequenceNumber发生变化(表明更新已完成)。
多田。