zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    1755:菲波那契数列
    1788:Pell数列
    3089:爬楼梯
    7832:最接近的分数
    7649:我家的门牌号
    7216:Minecraft
    7213:垃圾炸弹
    2983:谁是你的潜在朋友
    2723:因子问题
    2722:和数
  • 原文地址:https://www.cnblogs.com/yifi/p/6420205.html
Copyright © 2011-2022 走看看