如何在递归模式下使用 NtQueryDirectoryFile 检索完整的文件名?

How retrieve complete filename with NtQueryDirectoryFile in recursive mode?

我正在使用 代码递归地遍历所有文件和目录。

现在我想知道如何提取完整的文件名(路径+文件名+扩展名)?以下行(也出现在参考代码中)只给出文件名+扩展名(没有目录名)。

DbgPrint("%s%8I64u <%wZ>\n", prefix, DirInfo->EndOfFile.QuadPart, &ObjectName);

谢谢。

如果我们想要的不是简单的枚举folders/files而是全名,需要编写适当的代码。例如:

#define ALLOCSIZE PAGE_SIZE

// int nLevel, PSTR prefix for debug only
void ntTraverse(POBJECT_ATTRIBUTES poa, int nLevel, PSTR prefix)
{
    if (IoGetRemainingStackSize() < PAGE_SIZE)
    {
        DbgPrint("no stack!\n");
        return ;
    }

    if (!nLevel)
    {
        DbgPrint("!nLevel\n");
        return ;
    }

    HANDLE hFile;
    NTSTATUS status;
    IO_STATUS_BLOCK iosb;
    UNICODE_STRING ObjectName, *pObjectName = poa->ObjectName;

    DbgPrint("%s[<%wZ>]\n", prefix, pObjectName);

    if (0 <= (status = NtOpenFile(&hFile, FILE_GENERIC_READ, poa, &iosb, FILE_SHARE_VALID_FLAGS, 
        FILE_SYNCHRONOUS_IO_NONALERT|FILE_OPEN_REPARSE_POINT|FILE_OPEN_FOR_BACKUP_INTENT|FILE_DIRECTORY_FILE)))
    {
        if (PVOID buffer = ExAllocatePool(PagedPool, ALLOCSIZE))
        {
            union {
                PVOID pv;
                PBYTE pb;
                PFILE_DIRECTORY_INFORMATION DirInfo;
            };

            while (0 <= (status = NtQueryDirectoryFile(hFile, NULL, NULL, NULL, &iosb, 
                pv = buffer, ALLOCSIZE, FileDirectoryInformation, 0, NULL, FALSE)))
            {

                ULONG NextEntryOffset = 0;

                do 
                {
                    pb += NextEntryOffset;

                    ObjectName.Buffer = DirInfo->FileName;

                    switch (ObjectName.Length = (USHORT)DirInfo->FileNameLength)
                    {
                    case 2*sizeof(WCHAR):
                        if (ObjectName.Buffer[1] != '.') break;
                    case sizeof(WCHAR):
                        if (ObjectName.Buffer[0] == '.') continue;
                    }

                    ObjectName.MaximumLength = ObjectName.Length;

                    USHORT Length = pObjectName->Length;

                    if (0 <= RtlAppendUnicodeToString(pObjectName, L"\") &&
                        0 <= RtlAppendUnicodeStringToString(pObjectName, &ObjectName))
                    {
                        if (FILE_ATTRIBUTE_DIRECTORY == (DirInfo->FileAttributes & 
                            (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_REPARSE_POINT)))
                        {
                            ntTraverse(poa, nLevel - 1, prefix - 1);
                        }
                        else
                        {
                            DbgPrint("%s%8I64u <%wZ>\n", prefix, DirInfo->EndOfFile.QuadPart, pObjectName);
                        }

                        pObjectName->Length = Length;
                    }

                } while (NextEntryOffset = DirInfo->NextEntryOffset);
            }

            ExFreePool(buffer);

            if (status == STATUS_NO_MORE_FILES)
            {
                status = STATUS_SUCCESS;
            }
        }

        NtClose(hFile);
    }

    if (0 > status)
    {
        DbgPrint("---- %x %wZ\n", status, pObjectName);
    }
}

void ntTraverse(PCWSTR path)
{
    char prefix[MAXUCHAR + 1];
    memset(prefix, '\t', MAXUCHAR);
    prefix[MAXUCHAR] = 0;

    UNICODE_STRING ObjectName = { 0, MAXUSHORT, (PWSTR)ExAllocatePool(PagedPool, MAXUSHORT) };
    if (ObjectName.Buffer)
    {
        if (0 <= RtlAppendUnicodeToString(&ObjectName, path))
        {
            OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName };
            ntTraverse(&oa, MAXUCHAR, prefix + MAXUCHAR);
        }

        ExFreePool(ObjectName.Buffer);
    }
}

    ntTraverse(L"\??\c:\users");
    ntTraverse(L"\systemroot");