首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > VSTS >

Everything研究之读取NTFS上的USN日志文件(2)

2012-09-01 
Everything研究之读取NTFS下的USN日志文件(2)续/******************************************?2010.11.1

Everything研究之读取NTFS下的USN日志文件(2)

续>>

/******************************************

?2010.11.10更新了代码,调整了一处地方,lowUsn的设置。

?

******************************************/

?

第四步:获取USN Journal文件的基本信息

MSDN: http://msdn.microsoft.com/en-us/library/aa364583%28v=VS.85%29.aspx

?

[[

他是这么一个结构:

typedef struct {

? DWORDLONG UsnJournalID;

? USN?????? FirstUsn;

? USN?????? NextUsn;

? USN?????? LowestValidUsn;

? USN?????? MaxUsn;

? DWORDLONGMaximumSize;

? DWORDLONGAllocationDelta;

} USN_JOURNAL_DATA, *PUSN_JOURNAL_DATA;

?

其中的UsnJournalID,FirstUsn,NextUsn是我们后续操作需要用到的。

?

获取他很简单,通过DeviceIoControl()配合FSCTL_QUERY_USN_JOURNAL来实现。

]]

?

?

给出一个实现参考:

第五步:列出USN Journal文件的数据

前面提到USN日志的数据是以USN_RECORD形式储存的,在MSDN的介绍:

http://msdn.microsoft.com/en-us/library/aa365722%28VS.85%29.aspx

[[

同时分享一个网上找到的带中文注释的USN_RECORD:(原文链接)

typedefstruct {

DWORD RecordLength; // 记录长度

WORD MajorVersion; // 主版本

WORD MinorVersion; // 次版本

DWORDLONG FileReferenceNumber; // 文件引用数

DWORDLONG ParentFileReferenceNumber; // 父目录引用数

USN Usn; // USN

LARGE_INTEGER TimeStamp; // 时间戳

DWORD Reason; // 原因

DWORD SourceInfo; // 源信息

DWORD SecurityId; // 安全

ID DWORD FileAttributes; // 文件属性

WORD FileNameLength; // 文件长度

WORD FileNameOffset; // penultimate of original version2.0 <文件名偏移>

DWORD ExtraInfo1; // Hypothetically added in version2.1

DWORD ExtraInfo2; // Hypothetically added in version2.2

DWORD ExtraInfo3; // Hypothetically added in version2.3

WCHAR FileName[1]; // variable length always at the end<文件名第一位的指针>

}USN_RECORD, *PUSN_RECORD;

?

其中<>是我补充上的,要实现类似Everything的搜索,我们主要关注下面几个参数:

FileReferenceNumber,ParentFileReferenceNumber -> 可以用来找回文件路径

FileNameLength,FileName[1] -> 储存了文件名

]]

?

需要枚举USN的数据,我们需要使用DeviceIoControl()和FSCTL_ENUM_USN_DATA配合。

MSDN:http://msdn.microsoft.com/en-us/library/aa364563%28v=VS.85%29.aspx

?

这里需要提供一个MTF_ENUM_DATA的结构作为参数,正如描述所指:

Enumerates the update sequencenumber (USN) data between two specified boundaries to obtain master file table(MFT) records.

?

这些USN_RECORD储存在一个叫MFT的表里,MTF_ENUM_DATA的作用就是制定一个范围。对这个我也不是很了解,不管他,把参数填上看看结果再说。

?

[[

关键就是如何构建一个MFT_ENUM_DATA的结构来指定获取数据的范围,我们来看一下这个结构:

typedef struct {

? DWORDLONGStartFileReferenceNumber;

? USN?????? LowUsn;

? USN?????? HighUsn;

} MFT_ENUM_DATA, *PMFT_ENUM_DATA;

?

最后我在MSDN中找到关键的一段话:

The firstcall to FSCTL_ENUM_USN_DATA during an enumeration must have the StartFileReferenceNumber memberset to (DWORDLONG)0. Each call to FSCTL_ENUM_USN_DATAretrieves the starting point for the subsequent call as the first entry in theoutput buffer. Subsequent calls must be made with StartFileReferenceNumber set tothis value. For more information, see FSCTL_ENUM_USN_DATA.

大概意思是:

初始时将StartFileReferenceNumber设置为0,然后每次进行枚举后获取起始点进行下一次操作,这个新的起始点包含在返回的buffer的开头。

?

我们不难发现,这里指的buffer就是DeviceIoControl函数中的:

BOOL DeviceIoControl(

? (HANDLE)hDevice,??????????? // handle to volume

?FSCTL_ENUM_USN_DATA,???????? //dwIoControlCode

? (LPVOID)lpInBuffer,???????? // input buffer

? (DWORD)nInBufferSize,?????? // size of inputbuffer

? (LPVOID)lpOutBuffer,??????? // output buffer <这里>

? (DWORD)nOutBufferSize,????? // size of outputbuffer

? (LPDWORD)lpBytesReturned,?? // number of bytesreturned

? (LPOVERLAPPED)lpOverlapped? // OVERLAPPED structure

);

?

在MFT_ENUM_DATA中还有另外两个参数:

LowUsn, HighUsn

分别制定范围的起止。

?

我们这里要获取所有USN的数据,需要知道整个USN的起止位置。可通过DeviceIoControl()配合FSCTL_QUERY_USN_JOURNAL来获取一个USN_JOURNAL_DATA结构体,里面包含我们需要的信息(后续的删除操作也要用到这些信息):

typedef struct {

? DWORDLONGUsnJournalID;

? USN?????? FirstUsn;

? USN?????? NextUsn;

? USN?????? LowestValidUsn;

? USN?????? MaxUsn;

? DWORDLONGMaximumSize;

? DWORDLONGAllocationDelta;

} USN_JOURNAL_DATA, *PUSN_JOURNAL_DATA;

?

其中的FirstUsn和NextUsn就分别对应了LowUsn和HighUsn.

]]

?

首先需要构建一个MFT_ENUM_DATA,我们用上一步获取到的USN_JOURNAL_DATA进行填充。?

这里给出一个实现参考:

?

?

有了MFT_ENUM_DATA,就可以获取到USN的数据了。

MSDN上也提供了一个例子可做参考,虽然是FSCTL_READ_USN_JOURNAL,和我们要执行的ENUM是类似的。

?

枚举USN数据,这里给出实现参考:

?

?

现在只要对列出的数据进行筛选,基本就可以实现Everything的快速搜索了。

还需要结合索引的建立,才能达到更快的速度。

?

下面再介绍下如何删除USNJournal文件,当你不再需要他的时候。

?

第六步:删除USN Journal文件

MSDN参考:http://msdn.microsoft.com/en-us/library/aa363928%28v=VS.85%29.aspx

?

实现参考:

?

?

拓展实现:通过File Reference Number获取文件路径

这个这里暂时不讲了,感兴趣的可以参考文章最后给出的链接的实现。

C++上可以通过使用NtCreateFile()和NtQueryFileInformation()来实现路径获取。
基本MSDN上有比较详细的说明了。

===================================================================================================================
>>最后
附上一个完整的C++实现的例子:?
NftsUsnJournalDemo_2010.11.10_.rar

另外,还有一个在国外BLOG找到的C#实现的例子,比较完成,注释也很清晰。我也参考了不少。
原BLOG上是以文本贴出代码的,我这里整理成可编译的项目提供下载。
原文BLOG:http://www.dreamincode.net/forums/blog/1017-stcroixskippers-blog/
整理的项目:
UsnJournalProject_v1.3.rar


===================================================================================================================
以上都是出于个人兴趣的研究,接触C++实在迫不得已……Java某些部分的局限性太大了。


上面很多东西都是GOOGLE+MSDN完成的,若有疏忽请指教。


下一步准备将这些基本操作封装成DLL,再通过JNI供JAVA使用。欢迎交流。

?

1 楼 laorer 2010-11-08   嗯,当时也想看下 everything的实现机制,不过太懒了,一直没去找,多谢博主 2 楼 lslin 2010-12-25   博主你好!
一直都在使用Everything,实在是太赞了。以前知道Everything的大概原理,但是自己却不回实现,看了博主的介绍后对受益匪浅。
不过,在初始化USN日记的时候,我遇到了以下问题(我用的是VC++6.0编译器):

error C2065: 'CREATE_USN_JOURNAL_DATA' : undeclared identifier
error C2146: syntax error : missing ';' before identifier 'cujd'
error C2065: 'cujd' : undeclared identifier
error C2228: left of '.MaximumSize' must have class/struct/union type
error C2228: left of '.AllocationDelta' must have class/struct/union type
error C2065: 'FSCTL_CREATE_USN_JOURNAL' : undeclared identifier

我已经在原文件中加入了以下语句:
#include <winioctl.h>

请问博主知道是怎么回事吗?
我看了一下你提供的源代码,发现你只是include了Windows.h,这样也可以使用'CREATE_USN_JOURNAL_DATA' 这个结构体吗?
谢谢! 3 楼 univasity 2010-12-30   lslin 写道博主你好!
一直都在使用Everything,实在是太赞了。以前知道Everything的大概原理,但是自己却不回实现,看了博主的介绍后对受益匪浅。
不过,在初始化USN日记的时候,我遇到了以下问题(我用的是VC++6.0编译器):

error C2065: 'CREATE_USN_JOURNAL_DATA' : undeclared identifier
error C2146: syntax error : missing ';' before identifier 'cujd'
error C2065: 'cujd' : undeclared identifier
error C2228: left of '.MaximumSize' must have class/struct/union type
error C2228: left of '.AllocationDelta' must have class/struct/union type
error C2065: 'FSCTL_CREATE_USN_JOURNAL' : undeclared identifier

我已经在原文件中加入了以下语句:
#include <winioctl.h>

请问博主知道是怎么回事吗?
我看了一下你提供的源代码,发现你只是include了Windows.h,这样也可以使用'CREATE_USN_JOURNAL_DATA' 这个结构体吗?
谢谢!

提示未定义的错误。我用2010的,可能版本问题。

这些结构体如果没有可以自己定义,具体参考MSDN,直接将结构体代码拷贝到使用前的位置就可以。

我引用的这些是被定义在一个叫WinIoCtl.h的头文件。你需要的结构体如下:

#define FSCTL_CREATE_USN_JOURNAL        CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 57,  METHOD_NEITHER, FILE_ANY_ACCESS) // CREATE_USN_JOURNAL_DATA,

typedef struct {

    DWORDLONG MaximumSize;
    DWORDLONG AllocationDelta;

} CREATE_USN_JOURNAL_DATA, *PCREATE_USN_JOURNAL_DATA;

VC++6下我暂时无法测试,希望能帮到你。

热点排行