您当前的位置:首页 > 计算机 > 精彩资源

Everything实现原理

时间:07-06来源:作者:点击数:

一、USN Journal及MFT原理

everything搜索文件的速度之所以快得令人愤怒,主要原因是利用了NTFS的USNJournal特性,直接从系统的主文件表里读取文件信息。

USNJournal(Update SequenceNumber Journal)也被称作Change Journal。微软在NTFS 5.0(Windows 2000)中引入了USN Journal特性。USN Journal实际上是NTFS分区的一个日志文件,包含了所有对分区操作(文件操作)的记录。操作系统为每一个扇区单独维护一个USN Journal。当扇区的文件有变化时,操作系统会往USN Journal文件中追加一条记录,该记录包含文件名、变化发生的时间、变化的原因等信息,而不包含变化的内容。每一条记录用一个64位数字标识,称作USN(UpdateSequence Number)。微软用每一条记录在日志文件中的偏移作为该记录的USN,这样可以快速地通过USN获取到对应的记录。显而易见,USN是递增的,但是不连续。同时,由于文件名有长有短,每条记录的长度也不固定。在日志文件中,以文件块的形式存储记录。每个文件块大小为4K(USN_PAGE_SIZE),按每条记录100字节计,可以存储30~40条记录。单条记录不允许跨块存储。

USNJournal也有一个64位的ID(Journal ID)。当文件/目录发生变化时,系统除了往USN Journal追加一条日志外,也会更新Journal ID。如果Journal ID没有更新,意味着文件系统没有任何变化。

对NTFS分区,文件信息存储于主文件表(Master File Table,MFT)。MFT是NTFS的核心。主文件表里的每条记录包含文件和目录的所有信息,例如文件名/目录名、路径、大小、属性等。此外,还会存储该文件/目录最后一次变化对应的USN,系统在更新USN Journal时,也会更新这个字段。

小提示:可以用FSUtil.exe获取NTFS信息。FSUtil.exe FSInfoNTFSInfoC:

二、相关API

Windows提供了一系列API供应用程序访问USN Journal及MFT。相关的函数及数据结构罗列如下:

DeviceIoControl 
FSCTL_QUERY_USN_JOURNAL
struct USN_JOURNAL_DATA
FSCTL_ENUM_USN_DATA
FSCTL_READ_USN_JOURNAL
struct USN_RECORD

DeviceIoControl如何使用请查阅MSDN。FSCTL_QUERY_USN_JOURNAL和FSCTL_READ_USN_JOURNAL是DeviceIoControl的两个控制码,分别用于读取USN Journal统计信息和USN Journal记录。

USN_JOURNAL_DATA是USN Journal统计信息结构体,定义如下:

typedefstruct {
    DWORDLONG UsnJournalID;
    USN FirstUsn;
    USN NextUsn;
    USN LowestValidUsn;
    USN MaxUsn;
    DWORDLONG MaximumSize;
    DWORDLONG AllocationDelta;
}USN_JOURNAL_DATA, *PUSN_JOURNAL_DATA;
Members Description
UsnJournalID 64-bit unique journal identifier.
FirstUsn Identifies the first USN actually in the journal. All USNs below this value have been purged.
NextUsn The USN that will be assigned to the next record appended to the journal.
LowestValidUsn The lowest USN that is valid for this journal. On some occasions, the lowest USN number may not be zero. All changes with this USN or higher have been reported in the Change Journal.
MaxUsn The largest USN that will ever be issued in this journal. USNs cannot make use of the entire 64-bit address space-they are limited by the maximum logical size of a sparse file on an NTFS volume. Administrators are responsible for watching this number and deleting the journal if the NextUsn member approaches this value.
MaximumSize The maximum size in bytes that the journal should use on the volume.
AllocationDelta Size to grow the journal when needed, and size to purge from the start of the journal if it grows past MaximumSize.

USN Journal文件中,每一项记录的结构如下:

// Version 2.0 USN_RECORD structure
 typedef struct {
     DWORD         RecordLength;
     WORD          MajorVersion;
     WORD          MinorVersion;
     DWORDLONG     FileReferenceNumber;
     DWORDLONG     ParentFileReferenceNumber;
     USN Usn;
     LARGE_INTEGER TimeStamp;
     DWORD         Reason;
     DWORD         SourceInfo;
     DWORD         SecurityId;
     DWORD         FileAttributes;
     WORD          FileNameLength;
     WORD          FileNameOffset;
     WCHAR         FileName[1];
 } USN_RECORD, *PUSN_RECORD;
Members Description
RecordLength Total length of the record.
MajorVersion USN Journal’s version.
MinorVersion
FileReferenceNumber A File Reference Number (FRN) is 64-bit ID that uniquely identifies any file or directory on an NTFS volume.
ParentFileReferenceNumber Parent’s FRN. It’s always a directory FRN.
Usn Record’s update sequence number.
TimeStamp Standard UTC time stamp of this record, in 64-bit format.
Reason Tells you what sorts of changes have occurred to the file or directory.The Reason member may have one or more of the reason codes set.
SourceInfo Ignore
SecurityId
FileAttributes File information.
FileNameLength
FileNameOffset
FileName

三、实现思路

出于项目保密考虑,这里只大致介绍一下实现思路。

首先对每一个分区用FSCTL_ENUM_USN_DATA遍历文件和目录,建立索引;然后用FSCTL_READ_USN_JOURNAL监控系统中的文件变化(可只监听感兴趣的变化,如新建、删除、改名等操作),更新索引;退出程序时将索引保存到文件中,供下次启动时加载。

四、扩展思考

1. 如何由FRN获取文件/目录的路径?

Windows没有提供相应的API来完成这个功能。只有先建立索引树,然后遍历索引树得到完整的路径。

2. 关闭everything之后的文件变化,重启everything之后如何扫描到?

用FSCTL_ENUM_USN_DATA遍历至MFT的最后一项时,会返回USN Journal最后一项的USN。保存下来,下次重启Everything时,从该USN重新开始遍历即可。

3. 怎样从MFT里获取文件的访问时间?

利用控制码FSCTL_GET_NTFS_FILE_RECORD可以获取MFT里的一条记录。使用时需要提供文件的FRN(FileReferenceNumber)。实现细节可参考以下文章

http://www.codeproject.com/Articles/9293/Undelete-a-file-in-NTFS

https://www.cdsy.xyz/computer/programme/vc/240706/cd62089.html

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门