`
univasity
  • 浏览: 809736 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

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

阅读更多

我在第一次使用 Everything 时,对其速度确实感到惊讶,后来了解到是通过操作 USN 实现的,并且有一定的局限性(只有 NTFS 下才能使用)。

 

近来清闲无事(失业了),搞些自己的小项目玩玩。其中也要处理到本地搜索这块,首先我想到的就是 Everything

 

我仔细地将官网和他论坛的帖子都看了遍,基本没找到什么讲到原理的。倒是官网上提供了一个 Everything SDK 下载,是一个 IPC 的实现(我不是很懂,大概是程序关联之类的),需要 Everything 在后台跑才能调用操作。我也试了下效果,可以实现的,就是这样太麻烦了。

 

经过多日的搜搜,我发现了一个帖子,讨论的正是对 USN 的操作,同时我搜到了回帖者的 BLOG ,这一切让我有了开始的基础

 

 

言归正传:

 

初步认识 USN

USN Journal 相当于 NTFS 的秘书,为他记录下改动的一切,并储存为 USN_RECORD 的格式。

更多的介绍请看以下链接:

Keeping an Eye on Your NTFS Drives: the Windows 2000 Change Journal Explained

fsutil_usn

NTFS文件系统 USN日志

 

下面来分享下近日研究的成果,一步步来探索 Everything 神奇的速度 USN的使用(Everything的快不单是用了USN,还需要建立索引,原来表达有误,改过来)

整个实现分为 6 步:

1.       判断驱动盘是否为 NTFS 格式

2.       获取驱动盘句柄

3.       初始化 USN 日志文件

4.       获取 USN 基本信息

5.       列出 USN 日志的所有数据

6.       删除 USN 日志文件

 

第一步:判断驱动盘是否 NTFS 格式

我们可以通过 GetVolumeInformation() 函数获取相关的信息进行判断。

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

 

[[

这里我还找到了一个中文的说明:

GetVolumeInformation(

  lpRootPathName: PChar;               { 磁盘驱动器代码字符串}

  lpVolumeNameBuffer: PChar;           { 磁盘驱动器卷标名称}

  nVolumeNameSize: DWORD;              { 磁盘驱动器卷标名称长度}

  lpVolumeSerialNumber: PDWORD;        { 磁盘驱动器卷标序列号}

  var lpMaximumComponentLength: DWORD; { 系统允许的最大文件名长度}

  var lpFileSystemFlags: DWORD;        { 文件系统标识}

  lpFileSystemNameBuffer: PChar;       { 文件操作系统名称}

  nFileSystemNameSize: DWORD           { 文件操作系统名称长度}

): BOOL;

上图可以看到,最后一个就是格式类型了,对应 lpFileSystemNameBuffer

]]

 

下面给出C++ 的实现作为参考:

/**
 * step 01. 判断驱动盘是否 NTFS 格式
 */
char sysNameBuf[MAX_PATH] = {0};
int status = GetVolumeInformationA(volName,
                                   NULL, // 驱动盘名缓冲,这里我们不需要
                                   0,
                                   NULL,
                                   NULL,
                                   NULL,
                                   sysNameBuf, // 驱动盘的系统名( FAT/NTFS)
                                   MAX_PATH);

if (0!=status){

    printf(" 文件系统名 : %s\n" , sysNameBuf);

    // 比较字符串
    if (0==strcmp(sysNameBuf, "NTFS" )){
        isNTFS = true ;
    }else {
        printf(" 该驱动盘非 NTFS 格式 \n" );
    }

} 
 

 

USN Journal 并非一开始就存在的,需要手动打开。我们可以使用函数 DeviceIoControl() 并通过参数 FSCTL_CREATE_USN_JOURNAL 来操作。但仔细看 MSDN 会发现,需要先通过 CreateFile() 获取一个驱动盘的句柄。很多的后续操作都要用到这个句柄。

 

第二步:获取驱动盘句柄

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

 

[[

对于我们目前的操作,注意看最后 Remarks

Physical Disks and Volumes 中的一段:

The following requirements must be met for such a call to succeed:

  • The caller must have administrative privileges. For more information, see Running with Special Privileges .
  • The dwCreationDisposition parameter must have the OPEN_EXISTINGflag.
  • When opening a volume or floppy disk, the dwShareMode parameter must have the FILE_SHARE_WRITEflag.

大概意思是,要成功执行需要满足一下条件:

1.  使用者需要获取管理员权限

2.  dwCreationDisposition 参数 ( 倒数第三个 ) 必须带有 OPEN_EXISTIN 标识

3.  当打开一个驱动盘或软盘 dwShareMode 参数 ( 第三个 ) 必须带有 FILE_SHARE_WRITE 标识

 

再有就是 Files 中的一段 :

Windows Server 2003 and Windows XP/2000: 

If CREATE_ALWAYS and FILE_ATTRIBUTE_NORMAL are specified, CreateFile fails and sets the last error to ERROR_ACCESS_DENIED if the file exists and has the FILE_ATTRIBUTE_HIDDEN or FILE_ATTRIBUTE_SYSTEM attribute. To avoid the error, specify the same attributes as the existing file.

 

大概意思是:

windows2003,xp 2000 中如果设定了 CREATE_ALWAYS FILE_ATTRIBUTE_NORMAL 两个属性,如果文件存在,并带有属性 FILE_ATTRIBUTE_HIDDEN FILE_ATTRIBUTE_SYSTEM 的话, CreateFile 会失败,并且返回的错误信息为 ERROR_ACCESS_DENIED 。要避免这个错误,需要制定与文件本身相同的属性。

 

>> 所以我们这里尽量不使用 CREATE_ALWAYS FILE_ATTRIBUTE_NORMAL 。我这里使用 FILE_ATTRIBUTE_HIDDEN

]]

 

 

照样贴上例子(我很少用 C++ ,写得不好,仅参考) :

/**
 * step 02. 获取驱动盘句柄
 */
char fileName[MAX_PATH];
fileName[0] = '\0';

// 传入的文件名必须为\\.\C:的形式
strcpy(fileName, "\\\\.\\");
strcat(fileName, volName);
// 为了方便操作,这里转为string进行去尾
string fileNameStr = (string)fileName;
fileNameStr.erase(fileNameStr.find_last_of(":")+1);

printf("驱动盘地址: %s\n", fileNameStr.data());

// 调用该函数需要管理员权限
hVol = CreateFileA(fileNameStr.data(),
                   GENERIC_READ | GENERIC_WRITE, // 可以为0
                   FILE_SHARE_READ | FILE_SHARE_WRITE, // 必须包含有FILE_SHARE_WRITE
                   NULL, // 这里不需要
                   OPEN_EXISTING, // 必须包含OPEN_EXISTING, CREATE_ALWAYS可能会导致错误
                   FILE_ATTRIBUTE_READONLY, // FILE_ATTRIBUTE_NORMAL可能会导致错误
                   NULL); // 这里不需要

if(INVALID_HANDLE_VALUE!=hVol){
    getHandleSuccess = true;
}else{
    printf("获取驱动盘句柄失败 —— handle:%x error:%d\n", hVol, GetLastError());
}
 

 

第三步:打开 USN Journal 文件

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

 

 

代码参考:

/**
 * step 03. 初始化USN日志文件
 */
DWORD br;
CREATE_USN_JOURNAL_DATA cujd;
cujd.MaximumSize = 0; // 0表示使用默认值
cujd.AllocationDelta = 0; // 0表示使用默认值
status = DeviceIoControl(hVol,
                         FSCTL_CREATE_USN_JOURNAL,
                         &cujd,
                         sizeof(cujd),
                         NULL,
                         0,
                         &br,
                         NULL);

if(0!=status){
    initUsnJournalSuccess = true;
}else{
    printf("初始化USN日志文件失败 —— status:%x error:%d\n", status, GetLastError());
}
 

 

这时如果你能成功创建 USN 日志,那么对 USN 的探索即将开始

 

>> 目前你手上有的资源是 :

1.  某个 NTFS 驱动盘的 HANDLE;

2.  该驱动盘的 USN 日记已成功创建 .

 

--------------------------------------------- 未完待续 ------------------------------------------

 

10
0
分享到:
评论

相关推荐

    C#制作的windows系统文件快速搜索工具,读取USN,易用性与速度都已优化的很好。程序为免安装的exe文件。

    原理是读取ntfs的USN文件日志,然后内建索引加速文件搜索过程。 1、列表文件支持批量处理(删除、复制、复制文件名路径、打开、重命名),或者引用系统菜单。 2、支持拼音首字母缩写搜索,指定文件夹内搜索,多...

    Everything:基于 NTFS 文件系统,实现 Windows 文件的实时搜索

    不同于 Windows 自带的搜索功能,Everything 不依赖于文件名中的关键词,而是直接读取 NTFS 文件系统的 USN 日志,这意味着即使文件内容发生变化,它也能快速更新索引。输入关键词后,搜索结果几乎是即时显示的,...

    Everything1.3.4.67中文版(支持Win7).rar

    Everything在首次使用时会建立一个索引数据库,通过读取NTFS USN日志来建立文件索引树,生成的索引文件非常小。在搜索栏中输入要搜索的文件名,瞬间就能够帮助你找到要找的文件。支持使用搜索语法及正则表达式语法...

    everything源码模拟

    NTFS(New Technology File System)是Windows操作系统中广泛使用的文件系统,它支持多种高级功能,其中之一就是USN(Update Sequence Number)日志。USN日志是一个记录文件系统变化的系统,每次文件或目录发生更改...

    Everything-1.2.1.371

    这种快速,是因为Everything的索引无需逐一扫描硬盘文件,而是直接读取NTFS磁盘USN日志。这当然是既省力,又合理的做法。 第二个快速体现在搜索速度。在搜索框中键入字符后,搜索结果——或许称为过滤结果更准确...

    很小但极高速的本地文件搜索工具Everything

    原理是:Everything是靠读取NTFS文件系统中的USN日志来完成的,所以如果你的硬盘不是NTFS的,那就没有什么用了。 这是免安装版,解压使用时,默认是日文界面,要把那个.lng文件放到Everything的执行文件所在文件夹...

    Everything山寨版源码

    这个"Everything山寨版源码"显然是一款基于"Everything"的仿制品或修改版,其核心也是通过读取NTFS文件系统的USN(Update Sequence Number)日志来实现即时的文件索引和搜索功能。 NTFS USN日志是Windows操作系统为...

    Everything快速搜索

    "Everything"的核心优势在于其利用了NTFS文件系统的USN(Update Sequence Number)日志。USN日志是NTFS文件系统的一个关键特性,它记录了文件系统中所有更改的历史。每当文件被创建、修改、删除或移动,USN日志都会...

    filesearch_everything.rar

    1. **USN日志读取**:程序会包含如何打开并解析USN日志的代码,这涉及对`DeviceIoControl`函数的调用,传递`FSCTL_READ_FILE_USN_DATA`控制代码来获取特定文件的USN记录。 2. **变更通知注册**:为了实时跟踪文件...

    NTFS-Search

    NTFS-Search通过读取和解析MFT,结合USN Journal的变化记录,能够在短时间内获取到最新的文件信息,为用户提供即时的文件搜索服务。 项目包含的文件中,UpgradeLog.htm可能是软件升级或更新的日志文件,LICENSE文件...

    Everything软件及源码学习资料

    这是因为Everything通过读取NTFS文件系统的USN日志(Update Sequence Number Journal)和MFT(Master File Table)来构建索引,这两种数据结构记录了文件系统的所有变化,使得搜索结果始终保持最新。 《探索...

    everything

    这种快速,是因为Everything的索引无需逐一扫描硬盘文件,而是直接读取NTFS文件系统的USN日志。这当然是既省力,又合理的做法。 第二个快速体现在搜索速度。在搜索框中键入字符后,搜索结果——或许称为过滤结果更...

    Everything 全球速度最快的电脑文件搜索工具 快到你吐血喷饭

    这种快速,是因为Everything的索引无需逐一扫描硬盘文件,而是直接读取NTFS文件系统的USN日志。这当然是既省力,又合理的做法。 第二个快速体现在搜索速度。在搜索框中键入字符后,搜索结果——或许称为过滤结果更...

    探索Everything背后的技术1

    综上所述,"Everything背后的技术1"主要是利用NTFS的MFT和Change Journal,通过顺序遍历MFT条目和监听Change Journal记录,实现对文件系统的快速索引和实时更新。这样的设计使得用户可以在短时间内找到所需文件,极...

Global site tag (gtag.js) - Google Analytics