Everything 搜索文件

http://univasity.iteye.com/blog/805234

/*
* * 对Ntfs下USN操作的示例程序 * * author: univasity * qq: 595920004 * * --------------- 2010.11.10 * 1.修改lowUsn的问题,将原来的通过USN_JOURNAL获取,改为直接设置为0. *

USN是Update Service Number Journal or Change Journal的英文缩写,直译为“更新序列号”,是对NTFS卷里所修改过的信息进行相关记录的功能。当年微软发布Windows 2000时,建立NTFS 5.0的同时,加入了一些新功能和改进了旧版本的文件系统,为它请来了一位可靠的秘书,它可以在分区中设置监视更改的文件和目录的数量,记录下监视对象修改时间和修改内容。没错,它就是USN日志。当这个功能启用时,对于每一个NTFS卷,当发生有关添加、删除和修改文件的信息时,NTFS都使用USN日志记录下来。
  
  NTFS秘书——USN日志的工作方式,相对来说很简单,所以非常的高效。它开始的时候是一个空文件,包括NTFS每个卷的信息。每当NTFS卷有改变的时候,所改变的信息会马上被添加到这个文件里。这其中,每条修改的记录都使用特定符号来标识为日志形式,也就是USN日志。每条日志,记录了包括文件名、文件信息做出的改变。怎样在系统中让秘书开始干活儿呢?如图2所示,在NTFS分区的图标上右击选择“属性”,勾选圈中部分即可。
  
  USN秘书不仅工作高效,而且非常的忠诚,虽然这种忠诚看起来有点迫不得已。日志里包括发生了什么变化(添加、删除或其他操作),但并不会记录数据或其他变化的细节,所以它只能工作在NTFS文件系统中。
  看到上面的描述,你也许还是比较难以理解,那么就举个例子说明一下。USN日志为什么不能在FAT32文件系统下运用呢?就像钢笔不能在宣纸上记录,只能在普通纸上记录一样。USN日志相当于一本书的索引,当然书里面内容发生添加、修改或删除的时候,USN日志会记录下来何时做了修改,并使用特定序列号来标识,但它并不会记录里面具体修改了什么东西,所以索引文件很小。而当你想查找某一篇文章时,你就不用一页一页去翻书,可以直接通过查找USN日志(也就是建立的索引)就知道这篇文章是否存在。

*/
#include <iostream>
#include <Windows.h>
#include <fstream>

using namespace std;

char* volName = "e:\"; // 驱动盘名称
    
HANDLE hVol; // 用于储存驱动盘句柄

USN_JOURNAL_DATA UsnInfo; // 用于储存USN日志的基本信息

#define BUF_LEN 4096

ofstream fout("H:\log.txt"); // 用来将数据记录到文本,方便查看

long counter = 0;

int main(){

    bool status;
    bool isNTFS = false;
    bool getHandleSuccess = false;
    bool initUsnJournalSuccess = false;

    /**
     * step 01. 判断驱动盘是否NTFS格式
     * msdn:http://msdn.microsoft.com/en-us/library/aa364993%28VS.85%29.aspx
     */
    char sysNameBuf[MAX_PATH] = {0};
    status = GetVolumeInformationA(volName,
                                   NULL, // 驱动盘名缓冲,这里我们不需要
                                   0,
                                   NULL,
                                   NULL,
                                   NULL,
                                   sysNameBuf, // 驱动盘的系统名(FAT/NTFS)
                                   MAX_PATH);

    if(0!=status){
        printf("文件系统名: %s
", sysNameBuf);

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

    }

    // 只有NTFS才有USN,才能进行操作
    if(isNTFS){
        /**
         * step 02. 获取驱动盘句柄
         * msdn:http://msdn.microsoft.com/en-us/library/aa363858%28VS.85%29.aspx
         */
        char fileName[MAX_PATH];
        fileName[0] = '';

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

        printf("驱动盘地址: %s
", 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
", hVol, GetLastError());
        }

    }

    if(getHandleSuccess){

        /**
         * step 03. 初始化USN日志文件
         * msdn:http://msdn.microsoft.com/en-us/library/aa364558%28v=VS.85%29.aspx
         */
        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
", status, GetLastError());
        }

    }

    if(initUsnJournalSuccess){
        
        bool getBasicInfoSuccess = false;

        /**
         * step 04. 获取USN日志基本信息(用于后续操作)
         * msdn:http://msdn.microsoft.com/en-us/library/aa364583%28v=VS.85%29.aspx
         */
        DWORD br;
        status = DeviceIoControl(hVol,
                                 FSCTL_QUERY_USN_JOURNAL,
                                 NULL,
                                 0,
                                 &UsnInfo,
                                 sizeof(USN_JOURNAL_DATA),
                                 &br,
                                 NULL);

        if(0!=status){
            getBasicInfoSuccess = true;
        }else{
            printf("获取USN日志基本信息失败 —— status:%x error:%d
", status, GetLastError());
        }

        if(getBasicInfoSuccess){

            printf("UsnJournalID: %xI64
", UsnInfo.UsnJournalID);
            printf("lowUsn: %xI64
", UsnInfo.FirstUsn);
            printf("highUsn: %xI64
", UsnInfo.NextUsn);

            /**
             * step 05. 枚举USN日志文件中的所有记录
             * msdn:http://msdn.microsoft.com/en-us/library/aa364563%28v=VS.85%29.aspx
             */
            
            // from MSDN
            // On the first call, set the starting point, the StartFileReferenceNumber member of the MFT_ENUM_DATA structure, to (DWORDLONG)0. 
            // Each call to FSCTL_ENUM_USN_DATA retrieves the starting point for the subsequent call as the first entry in the output buffer.
            MFT_ENUM_DATA med;
            med.StartFileReferenceNumber = 0;
            med.LowUsn = 0;//UsnInfo.FirstUsn; 这里经测试发现,如果用FirstUsn有时候不正确,导致获取到不完整的数据,还是直接写0好.
            med.HighUsn = UsnInfo.NextUsn;

            CHAR buffer[BUF_LEN]; // 用于储存记录的缓冲,尽量足够地大
            DWORD usnDataSize;
            PUSN_RECORD UsnRecord;

            while(0!=DeviceIoControl(hVol,
                                     FSCTL_ENUM_USN_DATA,
                                     &med,
                                     sizeof(med),
                                     buffer,
                                     BUF_LEN,
                                     &usnDataSize,
                                     NULL))
            {

                DWORD dwRetBytes = usnDataSize - sizeof(USN);

                // 找到第一个USN记录
                // from MSDN(http://msdn.microsoft.com/en-us/library/aa365736%28v=VS.85%29.aspx):
                // return a USN followed by zero or more change journal records, each in a USN_RECORD structure. 
                UsnRecord = (PUSN_RECORD)(((PCHAR)buffer)+sizeof(USN));

                printf(" ********************************** 
");
                while(dwRetBytes>0){

                    // 打印获取到的信息
                    const int strLen = UsnRecord->FileNameLength;
                    char fileName[MAX_PATH] = {0};
                    WideCharToMultiByte(CP_OEMCP,NULL,UsnRecord->FileName,strLen/2,fileName,strLen,NULL,FALSE);
                    printf("FileName: %s
", fileName);
                    // 下面两个file reference number可以用来获取文件的路径信息
                    printf("FileReferenceNumber: %xI64
", UsnRecord->FileReferenceNumber);
                    printf("ParentFileReferenceNumber: %xI64
", UsnRecord->ParentFileReferenceNumber);
                    printf("
");

                    fout << "FileName:" << fileName << endl;
                    fout << "frn:" << UsnRecord->FileReferenceNumber << endl;
                    fout << "pfrn:" << UsnRecord->ParentFileReferenceNumber << endl;
                    fout << endl;
                    counter++;

                    // 获取下一个记录
                    DWORD recordLen = UsnRecord->RecordLength;
                    dwRetBytes -= recordLen;
                    UsnRecord = (PUSN_RECORD)(((PCHAR)UsnRecord)+recordLen);
                }

                //获取下一页数据,MTF大概是分多页来储存的吧?
                // from MSDN(http://msdn.microsoft.com/en-us/library/aa365736%28v=VS.85%29.aspx):
                // The USN returned as the first item in the output buffer is the USN of the next record number to be retrieved. 
                // Use this value to continue reading records from the end boundary forward.
                med.StartFileReferenceNumber = *(USN *)&buffer;

            }

            printf("共%d个文件
", counter);

            fout << "" << counter << "个文件" << endl;
            fout << flush;
            fout.close();

        }

        /**
         * step 06. 删除USN日志文件(当然也可以不删除)
         * msdn:http://msdn.microsoft.com/en-us/library/aa364561%28v=VS.85%29.aspx
         */
        DELETE_USN_JOURNAL_DATA dujd;
        dujd.UsnJournalID = UsnInfo.UsnJournalID;
        dujd.DeleteFlags = USN_DELETE_FLAG_DELETE;
        
        status = DeviceIoControl(hVol,
                                 FSCTL_DELETE_USN_JOURNAL,
                                 &dujd,
                                 sizeof(dujd),
                                 NULL,
                                 0,
                                 &br,
                                 NULL);

        if(0!=status){
            printf("成功删除USN日志文件!
");
        }else{
            printf("删除USN日志文件失败 —— status:%x error:%d
", status, GetLastError());
        }

    }

    // 最后释放一些资源
    if(getHandleSuccess){
        CloseHandle(hVol);
    }

    // 避免后台程序一闪而过
    MessageBox(0, "按确定退出", "结束", MB_OK);

    return 0;
}
爱程序 不爱bug 爱生活 不爱黑眼圈 我和你们一样 我和你们不一样 我不是凡客 我要做geek
原文地址:https://www.cnblogs.com/yifi/p/6420205.html