Thread: Traversing directories using the NtQueryDirectoryFile()

  1. #1
    Registered User
    Join Date
    May 2008
    Posts
    31

    Traversing directories using the NtQueryDirectoryFile()

    Hi All,

    I am trying to traverse directories using the undocumented API NtQueryDirectoryFile() to compare its performance against FindFirstFile/FindNextFile
    I have written this program:
    Code:
    #include<stdio.h>
    #include<windows.h>
    #include<string.h>
    #include<wchar.h>
    #include <ntsecapi.h>
    #include<time.h>
    #include<stdlib.h>
    #include<malloc.h>
    
    typedef enum _FILE_INFORMATION_CLASS {
    	FileDirectoryInformation = 1,
    	FileFullDirectoryInformation,
    	FileBothDirectoryInformation,
    	FileBasicInformation,
    	FileStandardInformation,
    	FileInternalInformation,
    	FileEaInformation,
    	FileAccessInformation,
    	FileNameInformation,
    	FileRenameInformation,
    	FileLinkInformation,
    	FileNamesInformation,
    	FileDispositionInformation,
    	FilePositionInformation,
    	FileFullEaInformation,
    	FileModeInformation,
    	FileAlignmentInformation,
    	FileAllInformation,
    	FileAllocationInformation,
    	FileEndOfFileInformation,
    	FileAlternateNameInformation,
    	FileStreamInformation,
    	FilePipeInformation,
    	FilePipeLocalInformation,
    	FilePipeRemoteInformation,
    	FileMailslotQueryInformation,
    	FileMailslotSetInformation,
    	FileCompressionInformation,
    	FileCopyOnWriteInformation,
    	FileCompletionInformation,
    	FileMoveClusterInformation,
    	FileOleClassIdInformation,
    	FileOleStateBitsInformation,
    	FileNetworkOpenInformation,
    	FileObjectIdInformation,
    	FileOleAllInformation,
    	FileOleDirectoryInformation,
    	FileContentIndexInformation,
    	FileInheritContentIndexInformation,
    	FileOleInformation,
    	FileMaximumInformation
    } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
    
    typedef struct _IO_STATUS_BLOCK {
      union {
        NTSTATUS  Status;
        PVOID  Pointer;
      }StatusBlock;
      ULONG_PTR  Information;
    } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
    
    
    typedef struct _FILE_FULL_DIR_INFORMATION {
      ULONG  NextEntryOffset;
      ULONG  FileIndex;
      LARGE_INTEGER  CreationTime;
      LARGE_INTEGER  LastAccessTime;
      LARGE_INTEGER  LastWriteTime;
      LARGE_INTEGER  ChangeTime;
      LARGE_INTEGER  EndOfFile;
      LARGE_INTEGER  AllocationSize;
      ULONG  FileAttributes;
      ULONG  FileNameLength;
      ULONG  EaSize;
      WCHAR  FileName[1];
    } FILE_FULL_DIR_INFORMATION, *PFILE_FULL_DIR_INFORMATION;
    
    /*typedef
    VOID WINAPI
    (*PIO_APC_ROUTINE) (
        IN PVOID ApcContext,
        IN PIO_STATUS_BLOCK IoStatusBlock,
        IN ULONG Reserved
        );
    */
    
    DWORD __stdcall NtQueryDirectoryFile(
    
      IN HANDLE               FileHandle,
      IN HANDLE               Event,
      //IN PIO_APC_ROUTINE    ApcRoutine,
      IN void*                x,
      IN PVOID                ApcContext,
      OUT PIO_STATUS_BLOCK    IoStatusBlock,
      OUT PVOID               FileInformation,
      IN ULONG                Length,
      IN FILE_INFORMATION_CLASS FileInformationClass,
      IN BOOLEAN              ReturnSingleEntry,
      IN PUNICODE_STRING      FileMask,
      IN BOOLEAN              RestartScan );
    
    typedef DWORD (__stdcall *NQDF)(
    
      IN HANDLE               FileHandle,
      IN HANDLE               Event,
      //IN PIO_APC_ROUTINE    ApcRoutine,
      IN void*                x,
      IN PVOID                ApcContext,
      OUT PIO_STATUS_BLOCK    IoStatusBlock,
      OUT PVOID               FileInformation,
      IN ULONG                Length,
      IN FILE_INFORMATION_CLASS FileInformationClass,
      IN BOOLEAN              ReturnSingleEntry,
      IN PUNICODE_STRING      FileMask,
      IN BOOLEAN              RestartScan );
    
    NQDF nqdf = NULL;
    
    unsigned long FileCount = 0, DirCount = 0;
    
    HMODULE hNtdll = NULL;
    
    #define BACKSLASH L"\\"
    
    #define SUCCESS TRUE
    #define FAILURE FALSE
    
    #define ALLOCSIZE sizeof(FILE_FULL_DIR_INFORMATION) * 512
    
    void ntTraverse(PWSTR DirName)
    {
    	HANDLE hFile=INVALID_HANDLE_VALUE;
    	IO_STATUS_BLOCK IoStatusBlock;
    	PFILE_FULL_DIR_INFORMATION DirInfo=NULL, buffer=NULL;
    	DWORD err;
    	
    	BOOLEAN done = TRUE;
    
    	hFile = CreateFileW(DirName,
    		   FILE_LIST_DIRECTORY,
    		   FILE_SHARE_READ | FILE_SHARE_WRITE,
    		   NULL,
    		   OPEN_EXISTING,
    		   FILE_FLAG_BACKUP_SEMANTICS,
    		   NULL
    		);
    
    	if (hFile == INVALID_HANDLE_VALUE)
    	{
    		wprintf( L"Error 0x%x opening Directory %ws\n", GetLastError(), DirName);
    		return;
    	}
    	
    	buffer = (PFILE_FULL_DIR_INFORMATION)calloc(ALLOCSIZE,1);
    	if (buffer == NULL)
    	{
    		wprintf( L"Memory allocation failed\n");
        	wprintf( L"error = %ld\n", GetLastError());
           	exit(1);
    	}
    		
    	if ((nqdf = (NQDF) GetProcAddress( hNtdll, "NtQueryDirectoryFile" )) == NULL)
    	{
    		wprintf( L"NQDF() missing from NTDLL.DLL\n" );
    		FreeLibrary( hNtdll );
    		exit(1);
    	}
    
    	err = nqdf(hFile, NULL, NULL, NULL, &IoStatusBlock, buffer, ALLOCSIZE, FileFullDirectoryInformation, 0, NULL, FALSE);
    	DirInfo = buffer;
    
    	while (err == 0 && DirInfo != NULL)
    	{
    		while(done == TRUE)
    		{
    			ULONG NameLength = 0;
    			PWSTR pathname = NULL, FileString = NULL;
    			size_t pathname_len = 0;
    
    			NameLength = DirInfo->FileNameLength;
    			FileString = DirInfo->FileName;
    
         		pathname_len = wcslen(DirName) + wcslen(BACKSLASH) + NameLength + 1;
    
    			pathname = (PWSTR)calloc(pathname_len,sizeof(WCHAR));	
    
    			if(pathname == NULL)
    			{
    				wprintf( L"could not allocate pathname\n");
    				exit(1);
    			}
    
    			wcscpy(pathname, DirName);
    			wcscat(pathname, BACKSLASH);
    			wcscat(pathname, FileString);
    	
    			if(DirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
    			{
    				/* Is a directory */
    				if (wcscmp(DirInfo->FileName, L".") && wcscmp(DirInfo->FileName, L".."))
    				{
    					printf("Directory name = %ws\n", pathname);
    					DirCount++;
    					ntTraverse(pathname);
    				}
    			}
    			else
    			{
    				/* Is a file */
    				wprintf( L"Filename = %ws\n", pathname);
    				FileCount++;
    			}
    
    			printf("offset = %lu\n", DirInfo->NextEntryOffset);
    
    			if ( DirInfo->NextEntryOffset == 0 )
    				done=FALSE;
    			else
    			{
    				DirInfo = (PFILE_FULL_DIR_INFORMATION)(((PUCHAR)DirInfo) + (DirInfo->NextEntryOffset));
    				wprintf( L"name = %ws\n", DirInfo->FileName);
    			}
    
    			free(pathname);
    		}
    
    		err = nqdf(hFile, NULL, NULL, NULL, &IoStatusBlock, buffer, ALLOCSIZE, FileFullDirectoryInformation, 0, NULL, FALSE);
    		DirInfo = buffer;
    	
    	}
    	
    	free(buffer);
    	CloseHandle(hFile);
    			
    }
    
    BOOLEAN LoadDll()
    {
    	BOOLEAN ret = SUCCESS;
    
    	hNtdll = LoadLibrary( L"ntdll.dll" );
    	if ( hNtdll == NULL )
    	{
    		wprintf( L"Error loading NTDLL.DLL\nerror = 0x%x\n", GetLastError() );
    		ret = FAILURE;
    	}
    	return ret;
    }
    
    int wmain(int argc, wchar_t *argv[])
    {
    	time_t StartTime, EndTime;
    	BOOLEAN ret = SUCCESS;
    
    	if(argc != 2)
    	{
    		printf("Usage : traversal.exe <Directory Name>\n");
    		ret = FAILURE;
    	}
    	else
    	{
    		if (LoadDll() == SUCCESS)
    		{
    			time(&StartTime);
    			ntTraverse(argv[1]);
    			time(&EndTime);
    
    			wprintf( L"time required = %llu\n", EndTime-StartTime);
    			wprintf( L"FileCount = %d\nDirCount = %d\n", FileCount, DirCount);
    
    			FreeLibrary( hNtdll );
    		}
    		else
    		{
    			printf("Exiting application\n");
    			ret = FAILURE;
    		}
    	}
    	
    	return ret;
    }
    However, when I update the DirInfo pointer as in:
    Code:
    DirInfo = (PFILE_FULL_DIR_INFORMATION)(((PUCHAR)DirInfo) + (DirInfo->NextEntryOffset));
    The pointer gets updated, however the file name gets appended with a `
    ex: for a directory xyz : xyz`
    What must be the problem ?

    Thanks

  2. #2
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Code:
    #include <windows.h>
    #include <stdio.h>
    
    typedef LONG NTSTATUS;
    typedef NTSTATUS *PNTSTATUS;
    typedef DWORD ULONG_PTR;
    
    #define STATUS_SUCCESS (NTSTATUS)0x00000000L
    #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
    #define FILE_OPEN               0x00000001
    #define OBJ_CASE_INSENSITIVE    0x00000040L
    #define FILE_DIRECTORY_FILE     0x00000001
    
    #define InitializeObjectAttributes( p, n, a, r, s ) {    \
        (p)->uLength = sizeof( OBJECT_ATTRIBUTES );          \
        (p)->hRootDirectory = r;                             \
        (p)->uAttributes = a;                                \
        (p)->pObjectName = n;                                \
        (p)->pSecurityDescriptor = s;                        \
        (p)->pSecurityQualityOfService = NULL;               \
    }
    
    typedef struct _UNICODE_STRING {
    	USHORT Length;
    	USHORT MaximumLength;
    	PWSTR  Buffer;
    } UNICODE_STRING;
    
    typedef UNICODE_STRING *PUNICODE_STRING;
    typedef const UNICODE_STRING *PCUNICODE_STRING;
    typedef USHORT RTL_STRING_LENGTH_TYPE;
    
    typedef struct _STRING {
    	USHORT Length;
    	USHORT MaximumLength;
    	PCHAR Buffer;
    } STRING;
    
    typedef STRING *PSTRING;
    typedef STRING ANSI_STRING;
    typedef PSTRING PANSI_STRING;
    
    typedef struct _OBJECT_ATTRIBUTES {
    	ULONG uLength;
    	HANDLE hRootDirectory;
    	PUNICODE_STRING pObjectName;
    	ULONG uAttributes;
    	PVOID pSecurityDescriptor;        
    	PVOID pSecurityQualityOfService;  
    } OBJECT_ATTRIBUTES;
    
    #define InitializeObjectAttributes( p, n, a, r, s ) {    \
        (p)->uLength = sizeof( OBJECT_ATTRIBUTES );          \
        (p)->hRootDirectory = r;                             \
        (p)->uAttributes = a;                                \
        (p)->pObjectName = n;                                \
        (p)->pSecurityDescriptor = s;                        \
        (p)->pSecurityQualityOfService = NULL;               \
    }
    
    typedef OBJECT_ATTRIBUTES * POBJECT_ATTRIBUTES;
    
    typedef struct _IO_STATUS_BLOCK {
    	union {
    		NTSTATUS Status;
    		PVOID Pointer;
    	};
    	ULONG_PTR Information;
    } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
    
    typedef VOID (NTAPI *PIO_APC_ROUTINE) (IN PVOID ApcContext, IN PIO_STATUS_BLOCK IoStatusBlock, IN ULONG Reserved);
    
    typedef enum _FILE_INFORMATION_CLASS {
    	FileDirectoryInformation         = 1,
    		FileFullDirectoryInformation,   
    		FileBothDirectoryInformation,   
    		FileBasicInformation,          
    		FileStandardInformation,        
    		FileInternalInformation,        
    		FileEaInformation,              
    		FileAccessInformation,          
    		FileNameInformation,            
    		FileRenameInformation,          
    		FileLinkInformation,            
    		FileNamesInformation,           
    		FileDispositionInformation,    
    		FilePositionInformation,       
    		FileFullEaInformation,         
    		FileModeInformation,            
    		FileAlignmentInformation,       
    		FileAllInformation,             
    		FileAllocationInformation,     
    		FileEndOfFileInformation,      
    		FileAlternateNameInformation,  
    		FileStreamInformation,          
    		FilePipeInformation,          
    		FilePipeLocalInformation,       
    		FilePipeRemoteInformation,     
    		FileMailslotQueryInformation,   
    		FileMailslotSetInformation,     
    		FileCompressionInformation,    
    		FileObjectIdInformation,        
    		FileCompletionInformation,      
    		FileMoveClusterInformation,     
    		FileQuotaInformation,           
    		FileReparsePointInformation,   
    		FileNetworkOpenInformation,    
    		FileAttributeTagInformation,   
    		FileTrackingInformation,        
    		FileIdBothDirectoryInformation, 
    		FileIdFullDirectoryInformation, 
    		FileValidDataLengthInformation, 
    		FileShortNameInformation,       
    		FileMaximumInformation
    } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
    
    typedef enum _EVENT_TYPE {NotificationEvent, SynchronizationEvent} EVENT_TYPE;
    
    typedef struct _FILE_BOTH_DIR_INFORMATION {
    	ULONG NextEntryOffset;
    	ULONG FileIndex;
    	LARGE_INTEGER CreationTime;
    	LARGE_INTEGER LastAccessTime;
    	LARGE_INTEGER LastWriteTime;
    	LARGE_INTEGER ChangeTime;
    	LARGE_INTEGER EndOfFile;
    	LARGE_INTEGER AllocationSize;
    	ULONG FileAttributes;
    	ULONG FileNameLength;
    	ULONG EaSize;
    	CCHAR ShortNameLength;
    	WCHAR ShortName[12];
    	WCHAR FileName[1];
    } FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;
    
    NTSTATUS (WINAPI * pRtlInitUnicodeString)(PUNICODE_STRING, PCWSTR);
    NTSTATUS (WINAPI * pNtCreateFile)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG);
    NTSTATUS (WINAPI * pNtCreateEvent)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, EVENT_TYPE, BOOLEAN);
    NTSTATUS (WINAPI * pNtQuerydirectoryFile)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS, BOOLEAN, PUNICODE_STRING, BOOLEAN);
    NTSTATUS (WINAPI * pNtWaitForSingleobject)(HANDLE, BOOLEAN, PLARGE_INTEGER);
    NTSTATUS (WINAPI * pRtlUnicodeStringToAnsiString)(PANSI_STRING, PCUNICODE_STRING, BOOLEAN);
    NTSTATUS (WINAPI * pNtClose)(HANDLE);
    
    void IntializeNativeFunctions(VOID)
    {
    	HMODULE hModule = LoadLibrary ("Ntdll.dll");
    
    	pRtlInitUnicodeString = (NTSTATUS (WINAPI *)(PUNICODE_STRING, PCWSTR)) GetProcAddress (hModule, "RtlInitUnicodeString");
    	pNtCreateFile = (NTSTATUS (WINAPI *)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG)) GetProcAddress (hModule, "NtCreateFile");
    	pNtCreateEvent = (NTSTATUS (WINAPI *)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, EVENT_TYPE, BOOLEAN)) GetProcAddress (hModule, "NtCreateEvent");
    	pNtQuerydirectoryFile = (NTSTATUS (WINAPI *)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS, BOOLEAN, PUNICODE_STRING, BOOLEAN)) GetProcAddress (hModule, "NtQueryDirectoryFile");
    	pNtWaitForSingleobject = (NTSTATUS (WINAPI *)(HANDLE, BOOLEAN, PLARGE_INTEGER)) GetProcAddress (hModule, "NtWaitForSingleObject");
    	pRtlUnicodeStringToAnsiString = (NTSTATUS (WINAPI *)(PANSI_STRING, PCUNICODE_STRING, BOOLEAN)) GetProcAddress (hModule, "RtlUnicodeStringToAnsiString");
    	pNtClose = (NTSTATUS (WINAPI *)(HANDLE)) GetProcAddress (hModule, "NtClose");
    }
    
    NTSTATUS ListDirectory(WCHAR * pszDirectoryName)
    {
    	UNICODE_STRING RootDirectoryName;
    	ANSI_STRING as;
    	OBJECT_ATTRIBUTES RootDirectoryAttributes;
    	NTSTATUS ntStatus = STATUS_SUCCESS;
    	HANDLE RootDirectoryHandle;
    	IO_STATUS_BLOCK Iosb;
    	HANDLE Event;
    	PUCHAR Buffer[65536];
    	WCHAR wszBuffer[50];
    
    	PFILE_BOTH_DIR_INFORMATION DirInformation;
    
    	if(pRtlInitUnicodeString == NULL) return -1;
    	if(pRtlUnicodeStringToAnsiString == NULL) return -1;
    	_snwprintf(wszBuffer,sizeof(wszBuffer),L"\\??\\%s\\",pszDirectoryName);
    	ntStatus = ((pRtlInitUnicodeString)(&RootDirectoryName, wszBuffer));
    	if (!NT_SUCCESS(ntStatus))
    		return ntStatus;
    	InitializeObjectAttributes (&RootDirectoryAttributes, &RootDirectoryName, OBJ_CASE_INSENSITIVE, 0, 0);
    	if(pNtCreateFile == NULL) return -1;
    	ntStatus =((pNtCreateFile)(&RootDirectoryHandle,
    		GENERIC_READ,
    		&RootDirectoryAttributes,
    		&Iosb,
    		0,
    		FILE_ATTRIBUTE_DIRECTORY,
    		FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
    		FILE_OPEN,
    		FILE_DIRECTORY_FILE,
    		0, 0));
    
    	if (!NT_SUCCESS(ntStatus))
    	{
    		printf("Unable to open %s, error = 0x%x\n", &RootDirectoryName, ntStatus);
    		return ntStatus;
    	}
    	if(pNtCreateEvent == NULL) return -1;
    	ntStatus = ((pNtCreateEvent)(&Event, GENERIC_ALL, 0, NotificationEvent, FALSE));
    	if (!NT_SUCCESS(ntStatus))
    	{
    		printf("Event creation failed with error 0x%x\n", ntStatus);
    		return ntStatus;
    	}
    	if(pNtQuerydirectoryFile == NULL) return -1;
    	if(((pNtQuerydirectoryFile)(RootDirectoryHandle,
    		Event, 0, 0,
    		&Iosb,
    		Buffer,
    		sizeof(Buffer),
    		FileBothDirectoryInformation,
    		FALSE,
    		NULL,
    		FALSE)) == STATUS_PENDING)
    	{
    		if(pNtWaitForSingleobject == NULL) return -1;
    		ntStatus = ((pNtWaitForSingleobject)(Event, TRUE, 0));
    	}
    	if (!NT_SUCCESS(ntStatus))
    	{
    		printf("Unable to query directory contents, error 0x%x\n", ntStatus);
    		return ntStatus;
    	}
    	DirInformation = (PFILE_BOTH_DIR_INFORMATION) Buffer;
    	while (1)
    	{
    		UNICODE_STRING EntryName;
    		EntryName.MaximumLength = EntryName.Length = (USHORT) DirInformation -> FileNameLength;
    		EntryName.Buffer = &DirInformation -> FileName[0];
    		((pRtlUnicodeStringToAnsiString)(&as, &EntryName, TRUE));
    		if(DirInformation->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
    			printf("Directory name: ");
    		else printf("Filename: "           );
    		printf("%s\n", as.Buffer);
    		if (0 == DirInformation -> NextEntryOffset)
    			break;
    		else
    			DirInformation = (PFILE_BOTH_DIR_INFORMATION) (((PUCHAR)DirInformation) + DirInformation -> NextEntryOffset);
    	}
    	((pNtClose)(RootDirectoryHandle));
    	return ntStatus;
    }
    
    int main(VOID)
    {
    	WCHAR wszDirectory[] = {L"C:\\Temp"};
    	IntializeNativeFunctions();
    	ListDirectory(wszDirectory);
    	return 0;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Creating and deleting directories and deleting files
    By fguy817817 in forum C Programming
    Replies: 1
    Last Post: 04-08-2009, 07:26 AM
  2. Comparing 2 directories
    By Opel_Corsa in forum C++ Programming
    Replies: 4
    Last Post: 01-19-2007, 11:30 PM
  3. VC6 directories
    By Magos in forum Tech Board
    Replies: 0
    Last Post: 03-11-2005, 05:52 PM
  4. Traversing Directories
    By C Minor in forum C Programming
    Replies: 4
    Last Post: 06-16-2002, 11:28 PM
  5. Working with directories...
    By C Seņor in forum C Programming
    Replies: 4
    Last Post: 04-20-2002, 11:45 AM