There are a few issues you have to care.
First: you pass ReturnSingleEntry equal to TRUE to ZwQueryDirectoryFile
which is actually not what exactly suits you, because only one instance of
FILE_BOTH_DIR_INFORMATION is returned, and it corresponds only to one file.
If you need to handle multiple files you have to pass FALSE as
ReturnSingleEntry. You also have to iteration several times calling
ZwQueryDirectoryFile untill you recieve STATUS_NO_MORE_FILES.
Second: you have to take care about the size of structure you pass into
ZwQueryDirectoryFile. You have to call ZwQueryDirectoryFile and check
against STATUS_BUFFER_OVERFLOW error. Once you get, you have to re-allocate
your buffer and try again.
I just changed your code a little, it should work. You can copy it below, or
copy a well-formatted C file from the following link (I suggest to download
C file because the code pasted here will become unformatted):
http://msmvps.com/blogs/v_scherbina/pages/samples.aspx
NTSTATUS EnumFilesInDir()
{
HANDLE hFile = NULL;
UNICODE_STRING szFileName = {0};
OBJECT_ATTRIBUTES Oa = {0};
NTSTATUS ntStatus = 0;
IO_STATUS_BLOCK Iosb = {0};
UINT uSize = sizeof(FILE_BOTH_DIR_INFORMATION);
FILE_BOTH_DIR_INFORMATION *pfbInfo = NULL;
BOOLEAN bIsStarted = TRUE;
PAGED_CODE();
RtlInitUnicodeString(&szFileName, L"\??\C:\"); /// let it show files in
C drive
InitializeObjectAttributes(&Oa, &szFileName, OBJ_CASE_INSENSITIVE |
OBJ_KERNEL_HANDLE, NULL, NULL);
ntStatus = ZwCreateFile(&hFile, GENERIC_READ | SYNCHRONIZE, &Oa, &Iosb, 0,
FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (!NT_SUCCESS(ntStatus))
{
return ntStatus;
}
pfbInfo = ExAllocatePoolWithTag(PagedPool, uSize, ‘0000’);
if (pfbInfo == NULL)
{
ZwClose(hFile);
return STATUS_NO_MEMORY;
}
while (TRUE)
{
lbl_retry:
RtlZeroMemory(pfbInfo, uSize);
ntStatus = ZwQueryDirectoryFile(hFile, 0, NULL, NULL, &Iosb, pfbInfo,
uSize, FileBothDirectoryInformation, FALSE, NULL, bIsStarted);
if (STATUS_BUFFER_OVERFLOW == ntStatus)
{
ExFreePoolWithTag(pfbInfo, ‘000’);
uSize = uSize * 2;
pfbInfo = ExAllocatePoolWithTag(PagedPool, uSize, ‘0000’);
if (pfbInfo == NULL)
{
ZwClose(hFile);
return STATUS_NO_MEMORY;
}
goto lbl_retry;
}
else if (STATUS_NO_MORE_FILES == ntStatus)
{
ExFreePoolWithTag(pfbInfo, ‘000’);
ZwClose(hFile);
return STATUS_SUCCESS;
}
else if (STATUS_SUCCESS != ntStatus)
{
ExFreePoolWithTag(pfbInfo, ‘000’);
ZwClose(hFile);
return ntStatus;
}
if (bIsStarted)
{
bIsStarted = FALSE;
}
while (TRUE)
{
WCHAR * szWellFormedFileName = ExAllocatePoolWithTag(PagedPool,
(pfbInfo->FileNameLength + sizeof(WCHAR)), ‘0001’);
if (szWellFormedFileName)
{
RtlZeroMemory(szWellFormedFileName, (pfbInfo->FileNameLength +
sizeof(WCHAR)));
RtlCopyMemory(szWellFormedFileName, pfbInfo->FileName,
pfbInfo->FileNameLength);
KdPrint((“File name is: %S\n”, szWellFormedFileName));
ExFreePoolWithTag(szWellFormedFileName, ‘000’);
}
if (pfbInfo->NextEntryOffset == 0)
{
break;
}
pfbInfo += pfbInfo->NextEntryOffset;
}
}
ZwClose(hFile);
ExFreePoolWithTag(pfbInfo, ‘000’);
return ntStatus;
}
–
V.
This posting is provided “AS IS” with no warranties, and confers no
rights.
wrote in message news:xxxxx@ntdev…
> Hello Guys,
>
> Another question from a newbie here about the driver I created to
> enumerate files and folders inside the directory or in a volume.
>
> Recently, I encountered problems querying list of files’ information in a
> directory. Here’s the code I created for this routine:
>
>
>
> PFILE_BOTH_DIR_INFORMATION DirInfo;
> OBJECT_ATTRIBUTES FileObjectAttributes;
> IO_STATUS_BLOCK IoStatusBlock;
> UNICODE_STRING DirectoryName;
>
> DirInfo = ExAllocatePoolWithTag(
> NonPagedPool,
> sizeof(FILE_BOTH_DIR_INFORMATION),
> TAG_GENERAL
> );
>
>
> if( DirInfo == NULL ) {
> KdPrint( (“%s: Can’t Allocate Buffer.\n”, NAMEBASE) );
> return (STATUS_INSUFFICIENT_RESOURCES);
> }
>
> RtlInitUnicodeString( &DirectoryName, L"\??\C:\TestDir" );
>
> InitializeObjectAttributes(
> &FileObjectAttributes,
> &DirectoryName, //DirectoryName contains 1 file only
> OBJ_CASE_INSENSITIVE,
> NULL,
> NULL
> );
>
> Status = ZwCreateFile(
> &DirectoryHandle,
> FILE_LIST_DIRECTORY | SYNCHRONIZE | FILE_TRAVERSE,
> &FileObjectAttributes,
> &IoStatusBlock,
> NULL,
> FILE_ATTRIBUTE_NORMAL,
> FILE_SHARE_WRITE | FILE_SHARE_READ,
> FILE_OPEN,
> FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE
> NULL,
> 0
> );
>
>
> if( !NT_SUCCESS( Status ) ) {
> return Status;
> } //endif
>
> /*
> NTSTATUS
> ZwQueryDirectoryFile(
> IN HANDLE FileHandle,
> IN HANDLE Event OPTIONAL,
> IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
> IN PVOID ApcContext OPTIONAL,
> OUT PIO_STATUS_BLOCK IoStatusBlock,
> OUT PVOID FileInformation,
> IN ULONG Length,
> IN FILE_INFORMATION_CLASS FileInformationClass,
> IN BOOLEAN ReturnSingleEntry,
> IN PUNICODE_STRING FileName OPTIONAL,
> IN BOOLEAN RestartScan
> );
> */
> Status = ZwQueryDirectoryFile(
> DirectoryHandle,
> NULL,
> NULL,
> NULL,
> &IoStatusBlock,
> (PVOID) DirInfo,
> sizeof( FILE_BOTH_DIR_INFORMATION ),
> FileBothDirectoryInformation,
> TRUE,
> NULL,
> TRUE
> );
>
> if( !NT_SUCCESS( Status ) ) {
> //Error Message
> } //endif
>
> ZwClose( DirectoryHandle );
>
> Now, the problem I encountered is that the FileName and the FileNameLength
> it returns is not correct. The actual filename contained in the current
> directory is TestFile.txt but FileName field in FILE_BOTH_DIR_INFORMATION
> structure that is being returned by ZwQueryDirectoryFile is just “.” and
> the FileNameLength field is 2. The FileName field should have returned “T”
> instead of “.” and the FileNameLength should not equal to 2. The current
> code is designed only to return a single entry from the directory. Any
> thoughts on what I did wrong on the code above?
>
> And also a follow-up question, is ZwQueryDirectoryFile can enumerate files
> on Drives like “??\C:” string as a directory name?
>
> Thanks,
>
> Xyber
>