删除文章

确定要删除这篇文章吗?

取消
确定

快速遍历磁盘

     阅读(304)  2020-07-23 03:03:46

快速遍历磁盘,不用遍历每个目录,主要使用DeviceIoControl 函数
需要用管理员权限运行

参考链接

使用命令行工具也可以遍历出所有文件:
注意C盘需要管理员权限

dir c:\*.* /b /s /a-d >>c:\allfile.txt
// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <Windows.h>
#include <string>
#include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <algorithm>

struct Record {
    uint64_t parentNumber;  // 父目录编号
    std::wstring name;      // 文件名
    uint32_t attr;          // 文件属性
};

// driveletter  - 磁盘,如:"E:"
// fileRecord   - 文件记录
// dirRecord    - 目录记录
// ignores      - 忽略的文件
void GetRecord(const std::wstring &driveletter, std::unordered_map<uint64_t, Record> &fileRecord, std::unordered_map<uint64_t, Record> &dirRecord, std::unordered_set<uint64_t> &ignores)
{
    HANDLE hVol = CreateFile(driveletter.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
    USN_JOURNAL_DATA journalData;
    PUSN_RECORD usnRecord;
    DWORD dwBytes;
    DWORD dwRetBytes;
    char buffer[USN_PAGE_SIZE];
    BOOL bDioControl = DeviceIoControl(hVol, FSCTL_QUERY_USN_JOURNAL, NULL, 0, &journalData, sizeof(journalData), &dwBytes, NULL);
    if (!bDioControl)
    {
        printf("[!]DeviceIoControl error\n");
        return;
    }

    MFT_ENUM_DATA med;
    med.StartFileReferenceNumber = 0;
    med.LowUsn = 0;
    med.HighUsn = journalData.NextUsn;
    int count = 0;
    while (dwBytes > sizeof(USN))
    {
        memset(buffer, 0, sizeof(USN_PAGE_SIZE));
        bDioControl = DeviceIoControl(hVol, FSCTL_ENUM_USN_DATA, &med, sizeof(med), &buffer, USN_PAGE_SIZE, &dwBytes, NULL);
        if (!bDioControl)
            break;
        dwRetBytes = dwBytes - sizeof(USN);
        usnRecord = (PUSN_RECORD)(((PUCHAR)buffer) + sizeof(USN));
        while (dwRetBytes > 0)
        {
            count++;
            int len = usnRecord->FileNameLength / 2;
            if (len > 0) {
                std::wstring name;
                name.resize(len, 0);
                wmemcpy_s(&name[0], len, usnRecord->FileName, len);
                if (usnRecord->FileAttributes & FILE_ATTRIBUTE_SYSTEM) {
                    ignores.emplace(usnRecord->FileReferenceNumber);
                    std::wcout << "ignore system:" << name << std::endl;
                }
                else if (usnRecord->FileAttributes & FILE_ATTRIBUTE_HIDDEN) {
                    ignores.emplace(usnRecord->FileReferenceNumber);
                    std::wcout << "ignore hidden:" << name << std::endl;
                }
                else {
                    if (usnRecord->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                        dirRecord[usnRecord->FileReferenceNumber] = Record{ usnRecord->ParentFileReferenceNumber, name, usnRecord->FileAttributes };
                    }
                    else {
                        fileRecord[usnRecord->FileReferenceNumber] = Record{ usnRecord->ParentFileReferenceNumber, name, usnRecord->FileAttributes };
                    }
                }
            }

            //printf("%.*ws\n", (int)(usnRecord->FileNameLength / 2), usnRecord->FileName);
            dwRetBytes -= usnRecord->RecordLength;
            usnRecord = (PUSN_RECORD)(((PCHAR)usnRecord) + usnRecord->RecordLength);
        }
        med.StartFileReferenceNumber = *(DWORDLONG*)buffer;
    }
    CloseHandle(hVol);
    std::cout << "total:" << count << std::endl;
}

void GetAllFiles(const std::wstring driver, std::vector<std::wstring> &allFiles)
{
    std::unordered_map<uint64_t, Record> files;
    std::unordered_map<uint64_t, std::wstring> fullDirs;
    {
        std::unordered_map<uint64_t, Record> dirs;
        std::unordered_set<uint64_t> ignores;
        GetRecord(L"\\\\.\\" + driver, files, dirs, ignores);

// 拼装完整目录
        for (auto &dir : dirs) {
            uint64_t number = dir.second.parentNumber;
            std::wstring full = dir.second.name;
            bool ignore = false;
            while (1) {
                if (ignores.find(number) != ignores.end()) {
                    ignore = true;
                    break;
                }
                auto i = dirs.find(number);
                if (i == dirs.end()) {
                    break;
                }
                full.insert(0, i->second.name + L"\\");
                number = i->second.parentNumber;
            }
            if (ignore) {
                continue;
            }
            full.insert(0, driver + L"\\");
            fullDirs[dir.first] = full;
        }
    }

    for (auto &file : files) {
        auto iter = fullDirs.find(file.second.parentNumber);
        if (iter != fullDirs.end()) {
            allFiles.emplace_back(iter->second + L"\\" + file.second.name);
        }
    }
}

int wmain(int argc, wchar_t *argv[])
{
    setlocale(LC_ALL, "");

    if (argc != 2) {
        std::wcout << L"please input driver name!" << std::endl;
        return 1;
    }

    std::wstring driver(argv[1]);
    if (driver.empty()) {
        std::wcout << L"params error" << std::endl;
        return 1;
    }

    if (driver[driver.size() - 1] != L':') {
        driver += L":";
    }

    std::wcout << L"fetch dir " << driver << std::endl;
    std::vector<std::wstring> allFiles;
    GetAllFiles(driver, allFiles);

    std::wcout << L"----------------------------------------" << std::endl;
    std::wcout << L"files:" << allFiles.size() << std::endl;

    system("pause");
    return 0;
}

文章评论

Keep it simple,stupid
文章数
355
今日访问
296
今日IP数
188
最近评论

liangzi: 不错 谢谢分享
tujiaw: registerThreadInactive:如果当前没有激活的线程,就去激活线程,让等待的线程去执行任务。
hgzzx: 佩服佩服。 请教:registerThreadInactive的作用是什么?
xuehaoyun: 很不错,来围观一下
tujiaw: 抱歉csdn code服务关闭了,这个代码我也找不到了
于淞: 你好,这个文章的源码能分享一下吗,songsong9181@163.com,谢谢了 上面的写错了
回到顶部