Esempio n. 1
0
int main(int argc, char **argv) {
  // Validate command line format.
  if (argc != 2) {
    printf("Usage: %s <path to a writable shared folder>\n", argv[0]);
    return 1;
  }

  // Initialize the PRNG.
  srand((unsigned int)time(NULL));

  // Create a subdirectory dedicated to demonstrating the vulnerability.
  CHAR TmpDirectoryName[MAX_PATH];
  _snprintf_s(TmpDirectoryName, sizeof(TmpDirectoryName), "%s\\vbox_crash", argv[1]);

  if (!CreateDirectoryA(TmpDirectoryName, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) {
    printf("CreateDirectory failed, %d\n", GetLastError());
    return 1;
  }

  // Create 16 files with long (128-byte) names, which appears to always be sufficient to trigger the bug.
  CONST UINT kTempFilesCount = 16;
  CONST UINT kTempFilenameLength = 128;
  CHAR TmpFilename[kTempFilenameLength + 1], TmpFilePath[MAX_PATH];

  memset(TmpFilename, 'A', kTempFilenameLength);
  TmpFilename[kTempFilenameLength] = '\0';

  for (UINT i = 0; i < kTempFilesCount; i++) {
    _snprintf_s(TmpFilePath, sizeof(TmpFilePath), "%s\\%s.%u", TmpDirectoryName, TmpFilename, rand());
    HANDLE hFile = CreateFileA(TmpFilePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
      printf("CreateFile#1 failed, %d\n", GetLastError());
      return 1;
    }

    CloseHandle(hFile);
  }
  
  // Open the temporary directory.
  HANDLE hDirectory = CreateFileA(TmpDirectoryName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
  if (hDirectory == INVALID_HANDLE_VALUE) {
    printf("CreateFile#2 failed, %d\n", GetLastError());
    return 1;
  }

  IO_STATUS_BLOCK iosb;
  FILE_DIRECTORY_INFORMATION fdi;

  // Perform the first call, with ReturnSingleEntry set to FALSE.
  NtQueryDirectoryFile(hDirectory, NULL, NULL, NULL, &iosb, &fdi, sizeof(fdi), FileDirectoryInformation, FALSE, NULL, TRUE);

  // Now make the same call, but with ReturnSingleEntry=TRUE. This should crash VirtualBox.exe on the host with a double-free exception.
  NtQueryDirectoryFile(hDirectory, NULL, NULL, NULL, &iosb, &fdi, sizeof(fdi), FileDirectoryInformation, TRUE, NULL, TRUE);

  // We should never reach here.
  CloseHandle(hDirectory);

  return 0;
}
Esempio n. 2
0
NTSTATUS WINAPI SafeNtQueryDirectoryFile(
        HANDLE hFile,
        HANDLE hEvent,
        PIO_APC_ROUTINE IoApcRoutine,
        PVOID IoApcContext,
        PIO_STATUS_BLOCK pIoStatusBlock,
        PVOID FileInformationBuffer,
        ULONG FileInformationBufferLength,
        FILE_INFORMATION_CLASS FileInfoClass,
        BOOLEAN bReturnOnlyOneEntry,
        PUNICODE_STRING PathMask,
        BOOLEAN bRestartQuery
)
{
	NTSTATUS rc;

	if (CheckOldFunction(&OldNtQueryDirectoryFile))
		rc=OldNtQueryDirectoryFile(hFile,hEvent,IoApcRoutine,IoApcContext,pIoStatusBlock,FileInformationBuffer,
			FileInformationBufferLength,FileInfoClass,bReturnOnlyOneEntry,PathMask,bRestartQuery);
	else
		rc=NtQueryDirectoryFile(hFile,hEvent,IoApcRoutine,IoApcContext,pIoStatusBlock,FileInformationBuffer,
			FileInformationBufferLength,FileInfoClass,bReturnOnlyOneEntry,PathMask,bRestartQuery);

	return rc;
}
Esempio n. 3
0
NTSTATUS query_one(POBJECT_ATTRIBUTES oa, PWSTR mask_str, BYTE *buffer, ULONG len, PIO_STATUS_BLOCK iosb)
{
	UNICODE_STRING mask;
	HANDLE dir = 0;
	NTSTATUS r;

	init_us(&mask, mask_str);

	r = NtOpenFile( &dir, GENERIC_READ | FILE_LIST_DIRECTORY, oa, iosb,
				FILE_SHARE_READ, FILE_DIRECTORY_FILE );
	if( r != STATUS_SUCCESS)
		return r;

	r = NtQueryDirectoryFile( dir, 0, 0, 0, iosb, buffer, len, FileBothDirectoryInformation, TRUE, &mask, TRUE);

	NtClose( dir );
	return r;
}
Esempio n. 4
0
int XFindNextFile(
	unsigned int handle,
	PWIN32_FIND_DATA findFileData)
{
#ifdef DEBUG
	debugPrint("XFindNextFile handle=%d\n", handle);
#endif

	IO_STATUS_BLOCK IoStatusBlock;
	FILE_DIRECTORY_INFORMATION FileInformation;
	ANSI_STRING FileMask;
	ANSI_STRING FileName;
	FILE_INFORMATION_CLASS FileInformationClass = FileDirectoryInformation;
	OBJECT_ATTRIBUTES Attributes;

	// and now actually do the looping over each file...
	memset(&FileInformation, 0, sizeof(FILE_DIRECTORY_INFORMATION));
	NTSTATUS status = NtQueryDirectoryFile(
		(HANDLE)handle, 
		NULL, 
		NULL, 
		NULL,
		&IoStatusBlock, 
		&FileInformation, 
		sizeof(FILE_DIRECTORY_INFORMATION),
		FileInformationClass, 
		&FileMask, 
		FALSE);
	if (!NT_SUCCESS(status))
		return ERROR_NO_MORE_FILES;
		
	/*findFileData->dwFileAttributes = FileInformation.FileAttributes;
	findFileData->ftCreationTime = FileInformation.CreationTime.QuadPart;
	findFileData->ftLastAccessTime = FileInformation.LastAccessTime.QuadPart;
	findFileData->ftLastWriteTime = FileInformation.LastWriteTime.QuadPart;
	findFileData->nFileSize = FileInformation.AllocationSize.QuadPart;*/
	strcpy(findFileData->cFileName, FileInformation.FileName);

	return STATUS_SUCCESS;
}
Esempio n. 5
0
VOID Directory(
    IN PCHAR String
    )
{
    NTSTATUS Status;

    HANDLE FileHandle;
    OBJECT_ATTRIBUTES ObjectAttributes;
    STRING NameString;
    IO_STATUS_BLOCK IoStatus;

    NTSTATUS NtStatus;

    PFILE_ADIRECTORY_INFORMATION FileInfo;
    ULONG i;

    //
    //  Get the filename
    //

    simprintf("Directory ", 0);
    simprintf(String, 0);
    simprintf("\n", 0);

    //
    //  Open the file for list directory access
    //

    RtlInitString( &NameString, String );
    InitializeObjectAttributes( &ObjectAttributes, &NameString, 0, NULL, NULL );
    if (!NT_SUCCESS(Status = NtOpenFile( &FileHandle,
                               FILE_LIST_DIRECTORY | SYNCHRONIZE,
                               &ObjectAttributes,
                               &IoStatus,
                               FILE_SHARE_READ,
                               WriteThrough | FILE_DIRECTORY_FILE ))) {
        OpenFileError( Status , String );
        return;
    }

    //
    //  zero out the buffer so next time we'll recognize the end of data
    //

    for (i = 0; i < BUFFERSIZE; i += 1) { Buffer[i] = 0; }

    //
    //  Do the directory loop
    //

    for (NtStatus = NtQueryDirectoryFile( FileHandle,
                                          (HANDLE)NULL,
                                          (PIO_APC_ROUTINE)NULL,
                                          (PVOID)NULL,
                                          &IoStatus,
                                          Buffer,
                                          BUFFERSIZE,
                                          FileADirectoryInformation,
                                          FALSE,
                                          (PSTRING)NULL,
                                          TRUE);
         NT_SUCCESS(NtStatus);
         NtStatus = NtQueryDirectoryFile( FileHandle,
                                          (HANDLE)NULL,
                                          (PIO_APC_ROUTINE)NULL,
                                          (PVOID)NULL,
                                          &IoStatus,
                                          Buffer,
                                          BUFFERSIZE,
                                          FileADirectoryInformation,
                                          FALSE,
                                          (PSTRING)NULL,
                                          FALSE) ) {

        if (!NT_SUCCESS(Status = NtWaitForSingleObject(FileHandle, TRUE, NULL))) {
//            NtPartyByNumber(50);
            WaitForSingleObjectError( Status );
            return;
        }

        //
        //  Check the Irp for success
        //

        if (!NT_SUCCESS(IoStatus.Status)) {

            break;

        }

        //
        //  For every record in the buffer type out the directory information
        //

        //
        //  Point to the first record in the buffer, we are guaranteed to have
        //  one otherwise IoStatus would have been No More Files
        //

        FileInfo = (PFILE_ADIRECTORY_INFORMATION)&Buffer[0];

        while (TRUE) {

            //
            //  Print out information about the file
            //

            simprintf("%8lx ", FileInfo->FileAttributes);
            simprintf("%8lx/", FileInfo->EndOfFile.LowPart);
            simprintf("%8lx ", FileInfo->AllocationSize.LowPart);

            {
                CHAR Saved;
                Saved = FileInfo->FileName[FileInfo->FileNameLength];
                FileInfo->FileName[FileInfo->FileNameLength] = 0;
                simprintf(FileInfo->FileName, 0);
                FileInfo->FileName[FileInfo->FileNameLength] = Saved;
            }

            simprintf("\n", 0);

            //
            //  Check if there is another record, if there isn't then we
            //  simply get out of this loop
            //

            if (FileInfo->NextEntryOffset == 0) {
                break;
            }

            //
            //  There is another record so advance FileInfo to the next
            //  record
            //

            FileInfo = (PFILE_ADIRECTORY_INFORMATION)(((PUCHAR)FileInfo) + FileInfo->NextEntryOffset);

        }

        //
        //  zero out the buffer so next time we'll recognize the end of data
        //

        for (i = 0; i < BUFFERSIZE; i += 1) { Buffer[i] = 0; }

    }

    //
    //  Now close the file
    //

    if (!NT_SUCCESS(Status = NtClose( FileHandle ))) {
        CloseError( Status );
    }

    //
    //  And return to our caller
    //

    return;

}
Esempio n. 6
0
NTSTATUS Directory_Enum(
    WCHAR* Directory,
    WCHAR* SearchPattern,
    SL_ENUM_DIRECTORY Callback
    )
{
    NTSTATUS status;
    IO_STATUS_BLOCK isb;
    BOOLEAN firstTime = TRUE;
    VOID *directoryHandle, *buffer;
    UINT32 bufferSize = 0x400;
    UINT32 i;
    UNICODE_STRING pattern;

    status = File_Create(
        &directoryHandle,
        Directory,
        FILE_LIST_DIRECTORY | SYNCHRONIZE,
        FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
        FILE_OPEN,
        FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
        NULL
        );

    if (!NT_SUCCESS(status))
        return status;

    buffer = Memory_Allocate(bufferSize);

    UnicodeString_Init(&pattern, SearchPattern);

    while (TRUE)
    {
        // Query the directory, doubling the buffer each time NtQueryDirectoryFile fails.
        while (TRUE)
        {
            status = NtQueryDirectoryFile(
                directoryHandle,
                NULL,
                NULL,
                NULL,
                &isb,
                buffer,
                bufferSize,
                FileDirectoryInformation,
                FALSE,
                &pattern,
                firstTime
                );

            // Our ISB is on the stack, so we have to wait for the operation to complete
            // before continuing.
            if (status == STATUS_PENDING)
            {
                status = NtWaitForSingleObject(directoryHandle, FALSE, NULL);

                if (NT_SUCCESS(status))
                    status = isb.Status;
            }

            if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_INFO_LENGTH_MISMATCH)
            {
                Memory_Free(buffer);

                bufferSize *= 2;
                buffer = Memory_Allocate(bufferSize);
            }
            else
            {
                break;
            }

        }

        // If we don't have any entries to read, exit.
        if (status == STATUS_NO_MORE_FILES)
        {
            status = STATUS_SUCCESS;
            break;
        }

        if (!NT_SUCCESS(status))
            break;

        // Read the batch and execute the callback function for each file.

        i = 0;

        while (TRUE)
        {
            FILE_DIRECTORY_INFORMATION *information;

            information = (FILE_DIRECTORY_INFORMATION *)(((UINT_B)(buffer)) + i);

            if (Callback)
                Callback(Directory, information);

            if (information->NextEntryOffset != 0)
                i += information->NextEntryOffset;
            else
                break;
        }

        firstTime = FALSE;
    }

    Memory_Free(buffer);

    NtClose(directoryHandle);

    return status;
}
// Querying the file ID from the file itself
static int OnFileIdGetClick(HWND hDlg)
{
    TFileTestData * pData = GetDialogData(hDlg);
    OBJECT_ATTRIBUTES ObjAttr;
    IO_STATUS_BLOCK IoStatus;
    UNICODE_STRING FolderName = {0, 0, NULL};
    UNICODE_STRING FileName = {0, 0, NULL};
    ULARGE_INTEGER FileId = {0};
    NTSTATUS Status = STATUS_SUCCESS;
    HANDLE Handle = NULL;
    TCHAR szFileID[MAX_FILEID_PATH];
    BYTE InfoBuff[0x200];

    // Convert the file name to the NT file name
    if(NT_SUCCESS(Status))
    {
        SaveDialog(hDlg);
        Status = FileNameToUnicodeString(&FolderName, pData->szFileName1);
    }

    // Get the directory name from the file name
    if(NT_SUCCESS(Status))
    {
        PWSTR sz = FolderName.Buffer + (FolderName.Length / sizeof(WCHAR));

        // Go back and find the last directory name
        while(sz > FolderName.Buffer && sz[0] != L'\\')
            sz--;

        // Did we find it?
        if(sz[0] == L'\\' && sz > FolderName.Buffer)
        {
            // Initialize the file name
            sz = sz + 1;
            RtlInitUnicodeString(&FileName, sz);

            // Cut the folder name. Make sure that the ending backslash is there,
            // because we don't want to open "\??\C:" instead of "\??\C:\"
            FolderName.MaximumLength =
            FolderName.Length = (USHORT)((sz - FolderName.Buffer) * sizeof(WCHAR));

            // Attempt to open the folder and query the ID
            InitializeObjectAttributes(&ObjAttr, &FolderName, OBJ_CASE_INSENSITIVE, NULL, NULL);
            Status = NtOpenFile(&Handle,
                                 FILE_READ_DATA | SYNCHRONIZE,
                                &ObjAttr,
                                &IoStatus,
                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
                                 FILE_SYNCHRONOUS_IO_ALERT);

            // If succeeded, we call for query directory on thet file
            if(NT_SUCCESS(Status))
            {
                PFILE_ID_BOTH_DIR_INFORMATION pDirInfo = (PFILE_ID_BOTH_DIR_INFORMATION)InfoBuff;

                Status = NtQueryDirectoryFile(Handle,
                                              NULL,
                                              NULL,
                                              NULL,
                                             &IoStatus,
                                              pDirInfo,
                                              sizeof(InfoBuff),
                                              FileIdBothDirectoryInformation,
                                              TRUE,
                                             &FileName,
                                              FALSE);
                if(NT_SUCCESS(Status))
                    FileId.QuadPart = pDirInfo->FileId.QuadPart;
                NtClose(Handle);
            }
        }
        else
        {
            // Do it by Open - QueryID - Close
            InitializeObjectAttributes(&ObjAttr, &FileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
            Status = NtOpenFile(&Handle,
                                 FILE_READ_ATTRIBUTES,
                                &ObjAttr,
                                &IoStatus,
                                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                                 0);

            if(NT_SUCCESS(Status))
            {
                PFILE_INTERNAL_INFORMATION pFileInfo = (PFILE_INTERNAL_INFORMATION)InfoBuff;

                Status = NtQueryInformationFile(Handle,
                                               &IoStatus,
                                                pFileInfo,
                                                sizeof(FILE_INTERNAL_INFORMATION),
                                                FileInternalInformation);
                if(NT_SUCCESS(Status))
                    FileId.QuadPart = pFileInfo->IndexNumber.QuadPart;
                NtClose(Handle);
            }
        }
    }

    // Did we query the file ID just fine?
    if(NT_SUCCESS(Status))
    {
        FileIDToString(pData, FileId.QuadPart, szFileID);
        SetDlgItemText(hDlg, IDC_FILE_ID, szFileID);
    }

    // On the end, set the file ID
    SetResultInfo(hDlg, RtlNtStatusToDosError(Status));
    FreeFileNameString(&FolderName);
    return TRUE;
}
static NTSTATUS NtRemoveDirectoryTree(POBJECT_ATTRIBUTES PtrObjectAttributes)
{
    PFILE_DIRECTORY_INFORMATION pDirInfo;
    OBJECT_ATTRIBUTES ChildAttr;
    IO_STATUS_BLOCK IoStatus;
    UNICODE_STRING ChildPath;
    NTSTATUS DelStatus;
    NTSTATUS Status;
    HANDLE DirHandle = NULL;
    ULONG TryCount = 0;
    BYTE DirBuffer[0x300];

    // Open the directory for enumeration+delete
    // Use FILE_OPEN_REPARSE_POINT, because the directory can be
    // a reparse point (even an invalid one) and still contain files/subdirs
    __TryOpenDirectory:
    Status = NtOpenFile(&DirHandle,
                         FILE_LIST_DIRECTORY | DELETE | SYNCHRONIZE,
                         PtrObjectAttributes,
                        &IoStatus,
                         FILE_SHARE_READ,
                         FILE_SYNCHRONOUS_IO_ALERT | FILE_DELETE_ON_CLOSE | FILE_OPEN_REPARSE_POINT);
    
    // When the access is denied, we can try to reset the permissions
    if(Status == STATUS_ACCESS_DENIED && TryCount == 0)
    {
        Status = NtSetFileAccessToEveryone(PtrObjectAttributes, GENERIC_ALL | DELETE);
        if(NT_SUCCESS(Status))
        {
            TryCount++;
            goto __TryOpenDirectory;
        }
    }

    if(NT_SUCCESS(Status))
    {
        // Prepare the child object attributes and the pointer to directory entry
        InitializeObjectAttributes(&ChildAttr, &ChildPath, OBJ_CASE_INSENSITIVE, DirHandle, NULL);
        pDirInfo = (PFILE_DIRECTORY_INFORMATION)DirBuffer;

        // Work as long as we have something
        while(Status == STATUS_SUCCESS)
        {
            // Query a single item
            Status = NtQueryDirectoryFile(DirHandle,
                                          NULL,
                                          NULL,
                                          NULL,
                                         &IoStatus,
                                          pDirInfo,
                                          sizeof(DirBuffer),
                                          FileDirectoryInformation,
                                          TRUE,
                                          NULL,
                                          FALSE);
            if(Status == STATUS_SUCCESS && !IsDotDirectoryName(pDirInfo))
            {
                // Create the child path
                ChildPath.MaximumLength =
                ChildPath.Length = (USHORT)pDirInfo->FileNameLength;
                ChildPath.Buffer = pDirInfo->FileName;

                // If the entry is a reparse point, we need to delete the reparse first
                if(pDirInfo->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
                {
                    Status = NtDeleteReparsePoint(&ChildAttr);
                    if(!NT_SUCCESS(Status))
                        break;
                }

                // If the entry has the FILE_ATTRIBUTE_READONLY (both file/subdir),
                // we need to clear it first
                if(pDirInfo->FileAttributes & FILE_ATTRIBUTE_READONLY)
                {
                    Status = NtSetFileAccessToEveryone(&ChildAttr, GENERIC_ALL | DELETE);
                    if(!NT_SUCCESS(Status))
                        break;
                }

                // If this is a directory, we need to delete the directory
                if(pDirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                {
                    Status = NtRemoveDirectoryTree(&ChildAttr);
                }
                else
                {
                    Status = NtRemoveSingleFile(&ChildAttr);
                }
            }
        }

        // Close the directory handle, (also) performing the delete
        DelStatus = NtClose(DirHandle);
        if(NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES)
            Status = DelStatus;
    }

    // Return the result
    return Status;
}
/**
 * Fetches more data from the file system.
 *
 * @returns IPRT status code
 * @param   pThis       The directory instance data.
 */
static int rtDirNtFetchMore(PRTDIR pThis)
{
    Assert(!pThis->fDataUnread);

    /*
     * Allocate the buffer the first time around.
     * We do this in lazy fashion as some users of RTDirOpen will not actually
     * list any files, just open it for various reasons.
     */
    bool fFirst = false;
    if (!pThis->pabBuffer)
    {
        fFirst = false;
        pThis->cbBufferAlloc = _256K;
        pThis->pabBuffer = (uint8_t *)RTMemAlloc(pThis->cbBufferAlloc);
        if (!pThis->pabBuffer)
        {
            do
            {
                pThis->cbBufferAlloc /= 4;
                pThis->pabBuffer = (uint8_t *)RTMemAlloc(pThis->cbBufferAlloc);
            } while (pThis->pabBuffer == NULL && pThis->cbBufferAlloc > _4K);
            if (!pThis->pabBuffer)
                return VERR_NO_MEMORY;
        }
    }

    /*
     * Read more.
     */
    NTSTATUS rcNt;
    IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
    if (pThis->enmInfoClass != (FILE_INFORMATION_CLASS)0)
    {
#ifdef IPRT_WITH_NT_PATH_PASSTHRU
        if (pThis->enmInfoClass == FileMaximumInformation)
        {
            Ios.Information = 0;
            Ios.Status = rcNt = NtQueryDirectoryObject(pThis->hDir,
                                                       pThis->pabBuffer,
                                                       pThis->cbBufferAlloc,
                                                       RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
                                                       FALSE /*RestartScan*/,
                                                       &pThis->uObjDirCtx,
                                                       (PULONG)&Ios.Information);
        }
        else
#endif
            rcNt = NtQueryDirectoryFile(pThis->hDir,
                                        NULL /* Event */,
                                        NULL /* ApcRoutine */,
                                        NULL /* ApcContext */,
                                        &Ios,
                                        pThis->pabBuffer,
                                        pThis->cbBufferAlloc,
                                        pThis->enmInfoClass,
                                        RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
                                        pThis->pNtFilterStr,
                                        FALSE /*RestartScan */);
    }
    else
    {
        /*
         * The first time around we have figure which info class we can use.
         * We prefer one which gives us file IDs, but we'll settle for less.
         */
        pThis->enmInfoClass = FileIdBothDirectoryInformation;
        rcNt = NtQueryDirectoryFile(pThis->hDir,
                                    NULL /* Event */,
                                    NULL /* ApcRoutine */,
                                    NULL /* ApcContext */,
                                    &Ios,
                                    pThis->pabBuffer,
                                    pThis->cbBufferAlloc,
                                    pThis->enmInfoClass,
                                    RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
                                    pThis->pNtFilterStr,
                                    FALSE /*RestartScan */);
        if (!NT_SUCCESS(rcNt))
        {
            pThis->enmInfoClass = FileBothDirectoryInformation;
            rcNt = NtQueryDirectoryFile(pThis->hDir,
                                        NULL /* Event */,
                                        NULL /* ApcRoutine */,
                                        NULL /* ApcContext */,
                                        &Ios,
                                        pThis->pabBuffer,
                                        pThis->cbBufferAlloc,
                                        pThis->enmInfoClass,
                                        RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
                                        pThis->pNtFilterStr,
                                        FALSE /*RestartScan */);
        }
    }
    if (!NT_SUCCESS(rcNt))
    {
        if (rcNt == STATUS_NO_MORE_FILES || rcNt == STATUS_NO_MORE_ENTRIES)
            return VERR_NO_MORE_FILES;
        return RTErrConvertFromNtStatus(rcNt);
    }
    Assert(Ios.Information > sizeof(*pThis->uCurData.pBoth));

    /*
     * Set up the data members.
     */
    pThis->uCurData.u  = (uintptr_t)pThis->pabBuffer;
    pThis->cbBuffer    = Ios.Information;

    int rc = rtDirNtCheckRecord(pThis);
    pThis->fDataUnread = RT_SUCCESS(rc);

    return rc;
}
/**
 * Worker for RTPathQueryInfoEx and RTDirRelPathQueryInfo.
 *
 * @returns IPRT status code.
 * @param   hRootDir            The root directory that pNtName is relative to.
 * @param   pNtName             The NT path which we want to query info for.
 * @param   pObjInfo            Where to return the info.
 * @param   enmAddAttr          What additional info to get/fake.
 * @param   fFlags              Query flags (RTPATH_F_XXX).
 * @param   pszPath             The path for detecting executables and such.
 *                              Pass empty string if not applicable/available.
 */
DECLHIDDEN(int) rtPathNtQueryInfoWorker(HANDLE hRootDir, UNICODE_STRING *pNtName, PRTFSOBJINFO pObjInfo,
                                        RTFSOBJATTRADD enmAddAttr, uint32_t fFlags, const char *pszPath)
{
    /*
     * There are a three different ways of doing this:
     *   1. Use NtQueryFullAttributesFile to the get basic file info.
     *   2. Open whatever the path points to and use NtQueryInformationFile.
     *   3. Open the parent directory and use NtQueryDirectoryFile like RTDirReadEx.
     *
     * The first two options may fail with sharing violations or access denied,
     * in which case we must use the last one as fallback.
     */
    HANDLE              hFile = RTNT_INVALID_HANDLE_VALUE;
    IO_STATUS_BLOCK     Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
    NTSTATUS            rcNt;
    OBJECT_ATTRIBUTES   ObjAttr;
    union
    {
        FILE_NETWORK_OPEN_INFORMATION   NetOpenInfo;
        FILE_ALL_INFORMATION            AllInfo;
        FILE_FS_VOLUME_INFORMATION      VolInfo;
        FILE_BOTH_DIR_INFORMATION       Both;
        FILE_ID_BOTH_DIR_INFORMATION    BothId;
        uint8_t                         abPadding[sizeof(FILE_ID_BOTH_DIR_INFORMATION) + RTPATH_MAX * sizeof(wchar_t)];
    } uBuf;

    /*
     * We can only use the first option if no additional UNIX attribs are
     * requested and it isn't a symbolic link.  NT directory object
     */
    int rc = VINF_TRY_AGAIN;
    if (   enmAddAttr != RTFSOBJATTRADD_UNIX
        && g_pfnNtQueryFullAttributesFile)
    {
        InitializeObjectAttributes(&ObjAttr, pNtName, OBJ_CASE_INSENSITIVE, hRootDir, NULL);
        rcNt = g_pfnNtQueryFullAttributesFile(&ObjAttr, &uBuf.NetOpenInfo);
        if (NT_SUCCESS(rcNt))
        {
            if (!(uBuf.NetOpenInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
            {
                pObjInfo->cbObject    = uBuf.NetOpenInfo.EndOfFile.QuadPart;
                pObjInfo->cbAllocated = uBuf.NetOpenInfo.AllocationSize.QuadPart;
                RTTimeSpecSetNtTime(&pObjInfo->BirthTime,         uBuf.NetOpenInfo.CreationTime.QuadPart);
                RTTimeSpecSetNtTime(&pObjInfo->AccessTime,        uBuf.NetOpenInfo.LastAccessTime.QuadPart);
                RTTimeSpecSetNtTime(&pObjInfo->ModificationTime,  uBuf.NetOpenInfo.LastWriteTime.QuadPart);
                RTTimeSpecSetNtTime(&pObjInfo->ChangeTime,        uBuf.NetOpenInfo.ChangeTime.QuadPart);
                pObjInfo->Attr.fMode = rtFsModeFromDos((uBuf.NetOpenInfo.FileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT,
                                                       pszPath, strlen(pszPath), 0 /*uReparseTag*/);
                pObjInfo->Attr.enmAdditional = enmAddAttr;

                return rtPathNtQueryInfoFillInDummyData(VINF_SUCCESS, pObjInfo, enmAddAttr);
            }
        }
        else if (   rcNt == STATUS_OBJECT_TYPE_MISMATCH
                 || rcNt == STATUS_OBJECT_NAME_INVALID
                 || rcNt == STATUS_INVALID_PARAMETER)
        {
            rc = rtPathNtQueryInfoInDirectoryObject(&ObjAttr, pObjInfo, enmAddAttr, fFlags, &uBuf, sizeof(uBuf), rcNt);
            if (RT_SUCCESS(rc))
                return rc;
        }
        else if (   rcNt != STATUS_ACCESS_DENIED
                 && rcNt != STATUS_SHARING_VIOLATION)
            rc = RTErrConvertFromNtStatus(rcNt);
        else
            RTNT_IO_STATUS_BLOCK_REINIT(&Ios);
    }

    /*
     * Try the 2nd option.  We might have to redo this if not following symbolic
     * links and the reparse point isn't a symbolic link but a mount point or similar.
     * We want to return information about the mounted root directory if we can, not
     * the directory in which it was mounted.
     */
    if (rc == VINF_TRY_AGAIN)
    {
        static int volatile g_fReparsePoints = -1;
        uint32_t            fOptions         = FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT;
        int fReparsePoints = g_fReparsePoints;
        if (fReparsePoints != 0 && !(fFlags & RTPATH_F_FOLLOW_LINK))
            fOptions |= FILE_OPEN_REPARSE_POINT;

        InitializeObjectAttributes(&ObjAttr, pNtName, OBJ_CASE_INSENSITIVE, hRootDir, NULL);
        rcNt = NtCreateFile(&hFile,
                            FILE_READ_ATTRIBUTES | SYNCHRONIZE,
                            &ObjAttr,
                            &Ios,
                            NULL /*pcbFile*/,
                            FILE_ATTRIBUTE_NORMAL,
                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                            FILE_OPEN,
                            fOptions,
                            NULL /*pvEaBuffer*/,
                            0 /*cbEa*/);
        if (   (   rcNt == STATUS_INVALID_PARAMETER
                || rcNt == STATUS_INVALID_PARAMETER_9)
            && fReparsePoints == -1
            && (fOptions & FILE_OPEN_REPARSE_POINT))
        {
            fOptions &= ~FILE_OPEN_REPARSE_POINT;
            rcNt = NtCreateFile(&hFile,
                                FILE_READ_ATTRIBUTES | SYNCHRONIZE,
                                &ObjAttr,
                                &Ios,
                                NULL /*pcbFile*/,
                                FILE_ATTRIBUTE_NORMAL,
                                FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                                FILE_OPEN,
                                fOptions,
                                NULL /*pvEaBuffer*/,
                                0 /*cbEa*/);
            if (rcNt != STATUS_INVALID_PARAMETER)
                g_fReparsePoints = fReparsePoints = 0;
        }
        if (NT_SUCCESS(rcNt))
        {
            /* Query tag information first in order to try re-open non-symlink reparse points. */
            FILE_ATTRIBUTE_TAG_INFORMATION TagInfo;
            rcNt = NtQueryInformationFile(hFile, &Ios, &TagInfo, sizeof(TagInfo), FileAttributeTagInformation);
            if (!NT_SUCCESS(rcNt))
                TagInfo.FileAttributes = TagInfo.ReparseTag = 0;
            if (   !(TagInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
                || TagInfo.ReparseTag == IO_REPARSE_TAG_SYMLINK
                || (fFlags & RTPATH_F_FOLLOW_LINK))
            { /* likely */ }
            else
            {
                /* Reparse point that isn't a symbolic link, try follow the reparsing. */
                HANDLE hFile2;
                RTNT_IO_STATUS_BLOCK_REINIT(&Ios);
                rcNt = NtCreateFile(&hFile2,
                                    FILE_READ_ATTRIBUTES | SYNCHRONIZE,
                                    &ObjAttr,
                                    &Ios,
                                    NULL /*pcbFile*/,
                                    FILE_ATTRIBUTE_NORMAL,
                                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                                    FILE_OPEN,
                                    FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
                                    NULL /*pvEaBuffer*/,
                                    0 /*cbEa*/);
                if (NT_SUCCESS(rcNt))
                {
                    NtClose(hFile);
                    hFile = hFile2;
                    TagInfo.FileAttributes = TagInfo.ReparseTag = 0;
                }
            }

            /*
             * Get the information we need and convert it.
             */
            rc = rtPathNtQueryInfoFromHandle(hFile, &uBuf, sizeof(uBuf), pObjInfo, enmAddAttr, pszPath, TagInfo.ReparseTag);
            NtClose(hFile);
            if (RT_SUCCESS(rc))
                return rc;

            if (RT_FAILURE(rc))
                rc = VINF_TRY_AGAIN;
        }
        else if (   rcNt == STATUS_OBJECT_TYPE_MISMATCH
                 || rcNt == STATUS_OBJECT_NAME_INVALID
                 /*|| rcNt == STATUS_INVALID_PARAMETER*/)
        {
            rc = rtPathNtQueryInfoInDirectoryObject(&ObjAttr, pObjInfo, enmAddAttr, fFlags, &uBuf, sizeof(uBuf), rcNt);
            if (RT_SUCCESS(rc))
                return rc;
        }
        else if (   rcNt != STATUS_ACCESS_DENIED
                 && rcNt != STATUS_SHARING_VIOLATION)
            rc = RTErrConvertFromNtStatus(rcNt);
        else
            RTNT_IO_STATUS_BLOCK_REINIT(&Ios);
    }

    /*
     * Try the 3rd option if none of the other worked.
     * If none of the above worked, try open the directory and enumerate
     * the file we're after.  This
     */
    if (rc == VINF_TRY_AGAIN)
    {
        /* Split up the name into parent directory path and filename. */
        UNICODE_STRING NtDirName;
        UNICODE_STRING NtFilter;
        ntPathNtSplitName(pNtName, &NtDirName, &NtFilter, false /*fNoParentDirSlash*/);

        /* Try open the directory. */
        InitializeObjectAttributes(&ObjAttr, &NtDirName, OBJ_CASE_INSENSITIVE, hRootDir, NULL);
        rcNt = NtCreateFile(&hFile,
                            FILE_LIST_DIRECTORY | SYNCHRONIZE,
                            &ObjAttr,
                            &Ios,
                            NULL /*pcbFile*/,
                            FILE_ATTRIBUTE_NORMAL,
                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                            FILE_OPEN,
                            FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
                            NULL /*pvEaBuffer*/,
                            0 /*cbEa*/);
        if (NT_SUCCESS(rcNt))
        {
            FILE_INFORMATION_CLASS enmInfoClass;
            if (RT_MAKE_U64(RTNtCurrentPeb()->OSMinorVersion, RTNtCurrentPeb()->OSMajorVersion) > RT_MAKE_U64(0,5) /* > W2K */)
                enmInfoClass = FileIdBothDirectoryInformation; /* Introduced in XP, from I can tell. */
            else
                enmInfoClass = FileBothDirectoryInformation;
            rcNt = NtQueryDirectoryFile(hFile,
                                        NULL /* Event */,
                                        NULL /* ApcRoutine */,
                                        NULL /* ApcContext */,
                                        &Ios,
                                        &uBuf,
                                        RT_MIN(sizeof(uBuf), 0xfff0),
                                        enmInfoClass,
                                        TRUE /*ReturnSingleEntry */,
                                        &NtFilter,
                                        FALSE /*RestartScan */);
            if (NT_SUCCESS(rcNt))
            {
                pObjInfo->cbObject    = uBuf.Both.EndOfFile.QuadPart;
                pObjInfo->cbAllocated = uBuf.Both.AllocationSize.QuadPart;

                RTTimeSpecSetNtTime(&pObjInfo->BirthTime,         uBuf.Both.CreationTime.QuadPart);
                RTTimeSpecSetNtTime(&pObjInfo->AccessTime,        uBuf.Both.LastAccessTime.QuadPart);
                RTTimeSpecSetNtTime(&pObjInfo->ModificationTime,  uBuf.Both.LastWriteTime.QuadPart);
                RTTimeSpecSetNtTime(&pObjInfo->ChangeTime,        uBuf.Both.ChangeTime.QuadPart);

                pObjInfo->Attr.fMode  = rtFsModeFromDos((uBuf.Both.FileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT,
                                                        pszPath, strlen(pszPath), uBuf.Both.EaSize);

                pObjInfo->Attr.enmAdditional = enmAddAttr;
                if (enmAddAttr == RTFSOBJATTRADD_UNIX)
                {
                    pObjInfo->Attr.u.Unix.uid             = ~0U;
                    pObjInfo->Attr.u.Unix.gid             = ~0U;
                    pObjInfo->Attr.u.Unix.cHardlinks      = 1;
                    pObjInfo->Attr.u.Unix.INodeIdDevice   = 0; /* below */
                    pObjInfo->Attr.u.Unix.INodeId         = enmInfoClass == FileIdBothDirectoryInformation
                                                          ? uBuf.BothId.FileId.QuadPart : 0;
                    pObjInfo->Attr.u.Unix.fFlags          = 0;
                    pObjInfo->Attr.u.Unix.GenerationId    = 0;
                    pObjInfo->Attr.u.Unix.Device          = 0;

                    /* Get the serial number. */
                    rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &uBuf, RT_MIN(sizeof(uBuf), _2K),
                                                        FileFsVolumeInformation);
                    if (NT_SUCCESS(rcNt))
                        pObjInfo->Attr.u.Unix.INodeIdDevice = uBuf.VolInfo.VolumeSerialNumber;
                }

                rc = rtPathNtQueryInfoFillInDummyData(VINF_SUCCESS, pObjInfo, enmAddAttr);
            }
            else
                rc = RTErrConvertFromNtStatus(rcNt);

            NtClose(hFile);
        }
        /*
         * Quite possibly a object directory.
         */
        else if (   rcNt == STATUS_OBJECT_NAME_INVALID  /* with trailing slash */
                 || rcNt == STATUS_OBJECT_TYPE_MISMATCH /* without trailing slash */ )
        {
            InitializeObjectAttributes(&ObjAttr, pNtName, OBJ_CASE_INSENSITIVE, hRootDir, NULL);
            rc = rtPathNtQueryInfoInDirectoryObject(&ObjAttr, pObjInfo, enmAddAttr, fFlags, &uBuf, sizeof(uBuf), rcNt);
            if (RT_FAILURE(rc))
                rc = RTErrConvertFromNtStatus(rcNt);
        }
        else
            rc = RTErrConvertFromNtStatus(rcNt);
    }

    return rc;
}
/**
 * Fetches more data from the file system.
 *
 * @returns IPRT status code
 * @param   pThis       The directory instance data.
 */
static int rtDirNtFetchMore(PRTDIRINTERNAL pThis)
{
    Assert(!pThis->fDataUnread);

    /*
     * Allocate the buffer the first time around.
     * We do this in lazy fashion as some users of RTDirOpen will not actually
     * list any files, just open it for various reasons.
     *
     * We also reduce the buffer size for networked devices as the windows 7-8.1,
     * server 2012, ++ CIFS servers or/and IFSes screws up buffers larger than 64KB.
     * There is an alternative hack below, btw.  We'll leave both in for now.
     */
    bool fFirst = false;
    if (!pThis->pabBuffer)
    {
        pThis->cbBufferAlloc = _256K;
        if (true) /** @todo skip for known local devices, like the boot device? */
        {
            IO_STATUS_BLOCK Ios2 = RTNT_IO_STATUS_BLOCK_INITIALIZER;
            FILE_FS_DEVICE_INFORMATION Info = { 0, 0 };
            NTSTATUS rcNt2 = NtQueryVolumeInformationFile(pThis->hDir, &Ios2, &Info, sizeof(Info), FileFsDeviceInformation);
            if (   !NT_SUCCESS(rcNt2)
                || (Info.Characteristics & FILE_REMOTE_DEVICE)
                || Info.DeviceType == FILE_DEVICE_NETWORK
                || Info.DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM
                || Info.DeviceType == FILE_DEVICE_NETWORK_REDIRECTOR
                || Info.DeviceType == FILE_DEVICE_SMB)
                pThis->cbBufferAlloc = _64K;
        }

        fFirst = false;
        pThis->pabBuffer = (uint8_t *)RTMemAlloc(pThis->cbBufferAlloc);
        if (!pThis->pabBuffer)
        {
            do
            {
                pThis->cbBufferAlloc /= 4;
                pThis->pabBuffer = (uint8_t *)RTMemAlloc(pThis->cbBufferAlloc);
            } while (pThis->pabBuffer == NULL && pThis->cbBufferAlloc > _4K);
            if (!pThis->pabBuffer)
                return VERR_NO_MEMORY;
        }

        /*
         * Also try determining the device number.
         */
        PFILE_FS_VOLUME_INFORMATION pVolInfo = (PFILE_FS_VOLUME_INFORMATION)pThis->pabBuffer;
        pVolInfo->VolumeSerialNumber = 0;
        IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
        NTSTATUS rcNt = NtQueryVolumeInformationFile(pThis->hDir, &Ios,
                                                     pVolInfo, RT_MIN(_2K, pThis->cbBufferAlloc),
                                                     FileFsVolumeInformation);
        if (NT_SUCCESS(rcNt) && NT_SUCCESS(Ios.Status))
            pThis->uDirDev = pVolInfo->VolumeSerialNumber;
        else
            pThis->uDirDev = 0;
        AssertCompile(sizeof(pThis->uDirDev) == sizeof(pVolInfo->VolumeSerialNumber));
        /** @todo Grow RTDEV to 64-bit and add low dword of VolumeCreationTime to the top of uDirDev. */
    }

    /*
     * Read more.
     */
    NTSTATUS rcNt;
    IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
    if (pThis->enmInfoClass != (FILE_INFORMATION_CLASS)0)
    {
#ifdef IPRT_WITH_NT_PATH_PASSTHRU
        if (pThis->enmInfoClass == FileMaximumInformation)
        {
            Ios.Information = 0;
            Ios.Status = rcNt = NtQueryDirectoryObject(pThis->hDir,
                                                       pThis->pabBuffer,
                                                       pThis->cbBufferAlloc,
                                                       RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
                                                       pThis->fRestartScan,
                                                       &pThis->uObjDirCtx,
                                                       (PULONG)&Ios.Information);
        }
        else
#endif
            rcNt = NtQueryDirectoryFile(pThis->hDir,
                                        NULL /* Event */,
                                        NULL /* ApcRoutine */,
                                        NULL /* ApcContext */,
                                        &Ios,
                                        pThis->pabBuffer,
                                        pThis->cbBufferAlloc,
                                        pThis->enmInfoClass,
                                        RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
                                        pThis->pNtFilterStr,
                                        pThis->fRestartScan);
    }
    else
    {
        /*
         * The first time around we have to figure which info class we can use
         * as well as the right buffer size.  We prefer an info class which
         * gives us file IDs (Vista+ IIRC) and we prefer large buffers (for long
         * ReFS file names and such), but we'll settle for whatever works...
         *
         * The windows 7 thru 8.1 CIFS servers have been observed to have
         * trouble with large buffers, but weirdly only when listing large
         * directories.  Seems 0x10000 is the max.  (Samba does not exhibit
         * these problems, of course.)
         *
         * This complicates things.  The buffer size issues causes an
         * STATUS_INVALID_PARAMETER error.  Now, you would expect the lack of
         * FileIdBothDirectoryInformation support to return
         * STATUS_INVALID_INFO_CLASS, but I'm not entirely sure if we can 100%
         * depend on third IFSs to get that right.  Nor, am I entirely confident
         * that we can depend on them to check the class before the buffer size.
         *
         * Thus the mess.
         */
        if (RT_MAKE_U64(RTNtCurrentPeb()->OSMinorVersion, RTNtCurrentPeb()->OSMajorVersion) > RT_MAKE_U64(0,5) /* > W2K */)
            pThis->enmInfoClass = FileIdBothDirectoryInformation; /* Introduced in XP, from I can tell. */
        else
            pThis->enmInfoClass = FileBothDirectoryInformation;
        rcNt = NtQueryDirectoryFile(pThis->hDir,
                                    NULL /* Event */,
                                    NULL /* ApcRoutine */,
                                    NULL /* ApcContext */,
                                    &Ios,
                                    pThis->pabBuffer,
                                    pThis->cbBufferAlloc,
                                    pThis->enmInfoClass,
                                    RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
                                    pThis->pNtFilterStr,
                                    pThis->fRestartScan);
        if (NT_SUCCESS(rcNt))
        { /* likely */ }
        else
        {
            bool fRestartScan = pThis->fRestartScan;
            for (unsigned iRetry = 0; iRetry < 2; iRetry++)
            {
                if (   rcNt == STATUS_INVALID_INFO_CLASS
                    || rcNt == STATUS_INVALID_PARAMETER_8
                    || iRetry != 0)
                    pThis->enmInfoClass = FileBothDirectoryInformation;

                uint32_t cbBuffer = pThis->cbBufferAlloc;
                if (   rcNt == STATUS_INVALID_PARAMETER
                    || rcNt == STATUS_INVALID_PARAMETER_7
                    || rcNt == STATUS_INVALID_NETWORK_RESPONSE
                    || iRetry != 0)
                {
                    cbBuffer = RT_MIN(cbBuffer / 2, _64K);
                    fRestartScan = true;
                }

                for (;;)
                {
                    rcNt = NtQueryDirectoryFile(pThis->hDir,
                                                NULL /* Event */,
                                                NULL /* ApcRoutine */,
                                                NULL /* ApcContext */,
                                                &Ios,
                                                pThis->pabBuffer,
                                                cbBuffer,
                                                pThis->enmInfoClass,
                                                RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
                                                pThis->pNtFilterStr,
                                                fRestartScan);
                    if (   NT_SUCCESS(rcNt)
                        || cbBuffer == pThis->cbBufferAlloc
                        || cbBuffer <= sizeof(*pThis->uCurData.pBothId) + sizeof(WCHAR) * 260)
                        break;

                    /* Reduce the buffer size agressivly and try again.  We fall back to
                       FindFirstFile values for the final lap.  This means we'll do 4 rounds
                       with the current initial buffer size (64KB, 8KB, 1KB, 0x278/0x268). */
                    cbBuffer /= 8;
                    if (cbBuffer < 1024)
                        cbBuffer = pThis->enmInfoClass == FileIdBothDirectoryInformation
                                 ? sizeof(*pThis->uCurData.pBothId) + sizeof(WCHAR) * 260
                                 : sizeof(*pThis->uCurData.pBoth)   + sizeof(WCHAR) * 260;
                }
                if (NT_SUCCESS(rcNt))
                {
                    pThis->cbBufferAlloc = cbBuffer;
                    break;
                }
            }
        }
    }
    if (!NT_SUCCESS(rcNt))
    {
        /* Note! VBoxSVR and CIFS file systems both ends up with STATUS_NO_SUCH_FILE here instead of STATUS_NO_MORE_FILES. */
        if (rcNt == STATUS_NO_MORE_FILES || rcNt == STATUS_NO_MORE_ENTRIES || rcNt == STATUS_NO_SUCH_FILE)
            return VERR_NO_MORE_FILES;
        return RTErrConvertFromNtStatus(rcNt);
    }
    pThis->fRestartScan = false;
    AssertMsg(  Ios.Information
              > (pThis->enmInfoClass == FileMaximumInformation ? sizeof(*pThis->uCurData.pObjDir) : sizeof(*pThis->uCurData.pBoth)),
              ("Ios.Information=%#x\n", Ios.Information));

    /*
     * Set up the data members.
     */
    pThis->uCurData.u  = (uintptr_t)pThis->pabBuffer;
    pThis->cbBuffer    = Ios.Information;

    int rc = rtDirNtCheckRecord(pThis);
    pThis->fDataUnread = RT_SUCCESS(rc);

    return rc;
}
Esempio n. 12
0
static int winfs_getdents(struct file *f, void *dirent, size_t count, getdents_callback *fill_callback)
{
	AcquireSRWLockShared(&f->rw_lock);
	NTSTATUS status;
	struct winfs_file *winfile = (struct winfs_file *) f;
	IO_STATUS_BLOCK status_block;
	#define BUFFER_SIZE	32768
	char buffer[BUFFER_SIZE];
	int size = 0;

	for (;;)
	{
		/* sizeof(FILE_ID_FULL_DIR_INFORMATION) is larger than both sizeof(struct dirent) and sizeof(struct dirent64)
		 * So we don't need to worry about header size.
		 * For the file name, in worst case, a UTF-16 character (2 bytes) requires 4 bytes to store */
		int buffer_size = (count - size) / 2;
		if (buffer_size >= BUFFER_SIZE)
			buffer_size = BUFFER_SIZE;
		status = NtQueryDirectoryFile(winfile->handle, NULL, NULL, NULL, &status_block, buffer, buffer_size, FileIdFullDirectoryInformation, FALSE, NULL, winfile->restart_scan);
		winfile->restart_scan = 0;
		if (!NT_SUCCESS(status))
		{
			if (status != STATUS_NO_MORE_FILES)
				log_error("NtQueryDirectoryFile() failed, status: %x", status);
			break;
		}
		if (status_block.Information == 0)
			break;
		int offset = 0;
		FILE_ID_FULL_DIR_INFORMATION *info;
		do
		{
			info = (FILE_ID_FULL_DIR_INFORMATION *) &buffer[offset];
			offset += info->NextEntryOffset;
			void *p = (char *)dirent + size;
			//uint64_t inode = info->FileId.QuadPart;
			/* Hash 64 bit inode to 32 bit to fix legacy applications
			 * We may later add an option for changing this behaviour
			 */
			uint64_t inode = info->FileId.HighPart ^ info->FileId.LowPart;
			char type = DT_REG;
			if (info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
				type = DT_DIR;
			else if (info->FileAttributes & FILE_ATTRIBUTE_SYSTEM)
			{
				/* Test if it is a symlink */
				UNICODE_STRING pathname;
				pathname.Length = info->FileNameLength;
				pathname.MaximumLength = info->FileNameLength;
				pathname.Buffer = info->FileName;

				NTSTATUS status;
				IO_STATUS_BLOCK status_block;
				OBJECT_ATTRIBUTES attr;
				attr.Length = sizeof(OBJECT_ATTRIBUTES);
				attr.RootDirectory = winfile->handle;
				attr.ObjectName = &pathname;
				attr.Attributes = 0;
				attr.SecurityDescriptor = NULL;
				attr.SecurityQualityOfService = NULL;
				HANDLE handle;
				status = NtCreateFile(&handle, SYNCHRONIZE | FILE_READ_DATA, &attr, &status_block, NULL,
					FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN,
					FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
				if (NT_SUCCESS(status))
				{
					int type = winfs_get_special_file_type(handle);
					if (type == SPECIAL_FILE_SYMLINK)
						type = DT_LNK;
					else if (type == SPECIAL_FILE_SOCKET)
						type = DT_SOCK;
					NtClose(handle);
				}
				else
					log_warning("NtCreateFile() failed, status: %x", status);
			}
			intptr_t reclen = fill_callback(p, inode, info->FileName, info->FileNameLength / 2, type, count - size, GETDENTS_UTF16);
			if (reclen < 0)
			{
				size = reclen;
				goto out;
			}
			size += reclen;
		} while (info->NextEntryOffset);
	}
out:
	ReleaseSRWLockShared(&f->rw_lock);
	return size;
	#undef BUFFER_SIZE
}
Esempio n. 13
0
/*
 * Create an fsentry-based directory listing (similar to opendir / readdir).
 * Dir should not contain trailing '/'. Use an empty string for the current
 * directory (not "."!).
 */
static struct fsentry *fsentry_create_list(struct fscache *cache, const struct fsentry *dir,
					   int *dir_not_found)
{
	wchar_t pattern[MAX_LONG_PATH];
	NTSTATUS status;
	IO_STATUS_BLOCK iosb;
	PFILE_FULL_DIR_INFORMATION di;
	HANDLE h;
	int wlen;
	struct fsentry *list, **phead;
	DWORD err;

	*dir_not_found = 0;

	/* convert name to UTF-16 and check length */
	if ((wlen = xutftowcs_path_ex(pattern, dir->name, MAX_LONG_PATH,
			dir->len, MAX_PATH - 2, core_long_paths)) < 0)
		return NULL;

	/* handle CWD */
	if (!wlen) {
		wlen = GetCurrentDirectoryW(ARRAY_SIZE(pattern), pattern);
		if (!wlen || wlen >= ARRAY_SIZE(pattern)) {
			errno = wlen ? ENAMETOOLONG : err_win_to_posix(GetLastError());
			return NULL;
		}
	}

	h = CreateFileW(pattern, FILE_LIST_DIRECTORY,
		FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
		NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
	if (h == INVALID_HANDLE_VALUE) {
		err = GetLastError();
		*dir_not_found = 1; /* or empty directory */
		errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
		trace_printf_key(&trace_fscache, "fscache: error(%d) '%.*s'\n",
						 errno, dir->len, dir->name);
		return NULL;
	}

	/* allocate object to hold directory listing */
	list = fsentry_alloc(cache, NULL, dir->name, dir->len);
	list->st_mode = S_IFDIR;

	/* walk directory and build linked list of fsentry structures */
	phead = &list->next;
	status = NtQueryDirectoryFile(h, NULL, 0, 0, &iosb, cache->buffer,
		sizeof(cache->buffer), FileFullDirectoryInformation, FALSE, NULL, FALSE);
	if (!NT_SUCCESS(status)) {
		/*
		 * NtQueryDirectoryFile returns STATUS_INVALID_PARAMETER when
		 * asked to enumerate an invalid directory (ie it is a file
		 * instead of a directory).  Verify that is the actual cause
		 * of the error.
		*/
		if (status == STATUS_INVALID_PARAMETER) {
			DWORD attributes = GetFileAttributesW(pattern);
			if (!(attributes & FILE_ATTRIBUTE_DIRECTORY))
				status = ERROR_DIRECTORY;
		}
		goto Error;
	}
	di = (PFILE_FULL_DIR_INFORMATION)(cache->buffer);
	for (;;) {

		*phead = fseentry_create_entry(cache, list, di);
		phead = &(*phead)->next;

		/* If there is no offset in the entry, the buffer has been exhausted. */
		if (di->NextEntryOffset == 0) {
			status = NtQueryDirectoryFile(h, NULL, 0, 0, &iosb, cache->buffer,
				sizeof(cache->buffer), FileFullDirectoryInformation, FALSE, NULL, FALSE);
			if (!NT_SUCCESS(status)) {
				if (status == STATUS_NO_MORE_FILES)
					break;
				goto Error;
			}

			di = (PFILE_FULL_DIR_INFORMATION)(cache->buffer);
			continue;
		}

		/* Advance to the next entry. */
		di = (PFILE_FULL_DIR_INFORMATION)(((PUCHAR)di) + di->NextEntryOffset);
	}

	CloseHandle(h);
	return list;

Error:
	errno = (status == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(status);
	trace_printf_key(&trace_fscache, "fscache: error(%d) unable to query directory contents '%.*s'\n",
		errno, dir->len, dir->name);
	CloseHandle(h);
	fsentry_release(list);
	return NULL;
}
Esempio n. 14
0
NTSTATUS query_one(HANDLE handle, HANDLE event, PUNICODE_STRING mask)
{
	IO_STATUS_BLOCK iosb;
	BYTE info[0x400];
	NTSTATUS r;
	PFILE_FULL_DIR_INFORMATION fdi;
	//PFILE_DIRECTORY_INFORMATION fdi;

	memset(&info, 0, sizeof info);
	r = NtQueryDirectoryFile (
		handle,
		event,
		0,
		0,
		&iosb,
		info,
		sizeof info,
		2, //FileInformation...
		TRUE,
		mask,
		FALSE);

	if (r == STATUS_PENDING)
	{
		r = WaitForSingleObject(event, INFINITE);
		if (r != STATUS_SUCCESS)
		{
			fprintf(stderr, "wait failed %08lx\n", r);
			return 1;
		}
		r = iosb.Status;
	}
	//fprintf(stderr, "completed %08lx\n", r);

	if (r != STATUS_SUCCESS)
	{
		if (r == STATUS_OBJECT_NAME_INVALID)
			fprintf(stderr, "query returned STATUS_OBJECT_NAME_INVALID\n");
		else if (r == STATUS_NO_MORE_FILES)
			/* fprintf(stderr, "query returned STATUS_NO_MORE_FILES\n")*/ ;
		else if (r == STATUS_NO_SUCH_FILE)
			fprintf(stderr, "query returned STATUS_NO_SUCH_FILE\n");
		else if (r == STATUS_INVALID_PARAMETER)
			fprintf(stderr, "query returned STATUS_INVALID_PARAMETER\n");
		else
			fprintf(stderr, "query failed %08lx\n", r);
		return r;
	}

	int i;
	if (0)
	{
		fprintf(stderr, "size = %08lx\n", iosb.Information);
		for (i=0; i<iosb.Information; i++)
			fprintf(stderr, "%02x%c", info[i], (i+1)%16?' ':'\n');
		fprintf(stderr, "\n");
	}

#if 0
	// fprintf("%S\n") doesn't seem to like a string with a single .
	fprintf(stderr, "name = ");
	for (i=0; i<iosb.Information - 0x40; i++)
			fprintf(stderr, "%c", ((PWCHAR)(info+0x40))[i]);
#endif
	fdi = (void*)info;
	fprintf(stderr, "%08lx ", fdi->FileAttributes);
	fprintf(stderr, "%08lx ", fdi->EaSize);
	dump_string(fdi->FileName, fdi->FileNameLength/2);
	fprintf(stderr, "\n");

	return STATUS_SUCCESS;
}
Esempio n. 15
0
unsigned int XFindFirstFile(
	char *directoryName,
	char *mask,
	PWIN32_FIND_DATA findFileData)
{
#ifdef DEBUG
	debugPrint("XFindFirstFile directoryName=%s mask=%s\n", directoryName, mask);
#endif

	IO_STATUS_BLOCK IoStatusBlock;
	FILE_DIRECTORY_INFORMATION FileInformation;
	HANDLE handle = NULL;
	ANSI_STRING FileMask;
	ANSI_STRING FileName;
	FILE_INFORMATION_CLASS FileInformationClass = FileDirectoryInformation;
	OBJECT_ATTRIBUTES Attributes;

	if (!strcmp(directoryName, "."))
		directoryName = getPartitionString(currentDrive);
		
	char *directoryBuffer = (char *)malloc(200);
	int rc = XConvertDOSFilenameToXBOX(directoryName, directoryBuffer);
	if (rc != STATUS_SUCCESS)
		return INVALID_HANDLE_VALUE;

	RtlInitAnsiString(&FileMask, mask);
	RtlInitAnsiString(&FileName, directoryBuffer);
	Attributes.RootDirectory = NULL;
	Attributes.ObjectName = &FileName;
	Attributes.Attributes = OBJ_CASE_INSENSITIVE;
	
	NTSTATUS status = NtCreateFile(
		&handle, 
		FILE_LIST_DIRECTORY,
		&Attributes, 
		&IoStatusBlock,
		NULL, 
		FILE_ATTRIBUTE_NORMAL,
		FILE_SHARE_READ, 
		FILE_OPEN, 
		FILE_DIRECTORY_FILE);
	if (!NT_SUCCESS(status))
		return INVALID_HANDLE_VALUE;

	// and now actually do the looping over each file...
	memset(&FileInformation, 0, sizeof(FILE_DIRECTORY_INFORMATION));
	status = NtQueryDirectoryFile(
		handle, 
		NULL, 
		NULL, 
		NULL,
		&IoStatusBlock, 
		&FileInformation, 
		sizeof(FILE_DIRECTORY_INFORMATION),
		FileInformationClass, 
		&FileMask, 
		TRUE);
	if (!NT_SUCCESS(status))
		return INVALID_HANDLE_VALUE;
		
	/*findFileData->dwFileAttributes = FileInformation.FileAttributes;
	findFileData->ftCreationTime = FileInformation.CreationTime.QuadPart;
	findFileData->ftLastAccessTime = FileInformation.LastAccessTime.QuadPart;
	findFileData->ftLastWriteTime = FileInformation.LastWriteTime.QuadPart;
	findFileData->nFileSize = FileInformation.AllocationSize.QuadPart;*/
	strcpy(findFileData->cFileName, FileInformation.FileName);

	return (unsigned int)handle;
}
Esempio n. 16
0
void test_query_directory( void )
{
	WCHAR dirname[] = L"\\??\\c:\\filetest";
	WCHAR filename[] = L"\\??\\c:\\filetest\\edb.chk";
	WCHAR edb[] = L"edb<\"*";
	UNICODE_STRING path, mask, empty;
	OBJECT_ATTRIBUTES oa;
	HANDLE dir, file;
	IO_STATUS_BLOCK iosb;
	BYTE buffer[0x100];
	NTSTATUS r;

	iosb.Status = ~0;
	iosb.Information = ~0;

	empty.Buffer = 0;
	empty.Length = 0;
	empty.MaximumLength = 0;

	init_us(&mask, edb);

	oa.Length = sizeof oa;
	oa.RootDirectory = 0;
	oa.ObjectName = &path;
	oa.Attributes = OBJ_CASE_INSENSITIVE;
	oa.SecurityDescriptor = 0;
	oa.SecurityQualityOfService = 0;

	init_us(&path, filename);
	r = NtDeleteFile( &oa );

	// delete the file to ensure preconditions
	init_us(&path, dirname);
	r = NtDeleteFile( &oa );

	// create a test directory
	r = NtCreateFile( &dir, GENERIC_READ | GENERIC_WRITE | FILE_LIST_DIRECTORY, &oa, &iosb,
			0, FILE_ATTRIBUTE_DIRECTORY, FILE_SHARE_READ, FILE_CREATE, FILE_DIRECTORY_FILE, 0, 0 );
	ok( r == STATUS_SUCCESS, "failed to create dir %08lx\n", r);
	ok( iosb.Status == STATUS_SUCCESS, "status wrong %08lx\n", iosb.Status);
	ok( iosb.Information == FILE_CREATED, "information wrong %08lx\n", iosb.Information);

	// add a file to the directory
	init_us(&path, filename);

	r = NtCreateFile( &file, GENERIC_READ | GENERIC_WRITE, &oa, &iosb,
			0, FILE_ATTRIBUTE_DIRECTORY, FILE_SHARE_READ, FILE_CREATE, 0, 0, 0 );
	ok( r == STATUS_SUCCESS, "failed to create file %08lx\n", r);
	ok( iosb.Status == STATUS_SUCCESS, "status wrong %08lx\n", iosb.Status);
	ok( iosb.Information == FILE_CREATED, "information wrong %08lx\n", iosb.Information);

	r = NtClose( file );
	ok( r == STATUS_SUCCESS, "status wrong %08lx\n", r);

	// query first file... should be "."
	r = NtQueryDirectoryFile( dir, 0, 0, 0, &iosb, buffer, sizeof buffer, FileBothDirectoryInformation, TRUE, 0, 0);
	ok( r == STATUS_SUCCESS, "failed to query directory %08lx\n", r);
	check_dot(&iosb, buffer);

	// query second file... should be ".."
	r = NtQueryDirectoryFile( dir, 0, 0, 0, &iosb, buffer, sizeof buffer, FileBothDirectoryInformation, TRUE, 0, 0);
	ok( r == STATUS_SUCCESS, "failed to query directory %08lx\n", r);
	check_dotdot(&iosb, buffer);

	// query third file... should be "edb.chk"
	r = NtQueryDirectoryFile( dir, 0, 0, 0, &iosb, buffer, sizeof buffer, FileBothDirectoryInformation, TRUE, 0, 0);
	ok( r == STATUS_SUCCESS, "failed to query directory %08lx\n", r);
	check_edb(&iosb, buffer);

	// no more files...
	r = NtQueryDirectoryFile( dir, 0, 0, 0, &iosb, buffer, sizeof buffer, FileBothDirectoryInformation, TRUE, 0, 0);
	ok( r == STATUS_NO_MORE_FILES, "failed to query directory %08lx\n", r);

	// try with a mask
	r = NtQueryDirectoryFile( dir, 0, 0, 0, &iosb, buffer, sizeof buffer, FileBothDirectoryInformation, TRUE, &mask, TRUE);
	ok( r == STATUS_SUCCESS, "failed to query directory %08lx\n", r);
	ok( iosb.Status == STATUS_SUCCESS, "status wrong %08lx\n", iosb.Status);
	check_dot(&iosb, buffer);

	r = NtClose( dir );
	ok( r == STATUS_SUCCESS, "failed to close handle %08lx\n", r);

	// set oa to point the the directory again
	init_us(&path, dirname);

	// re-open the file and scan with a mask
	// looks like the mask is set on the first scan after opening the directory
	r = query_one(&oa, edb, buffer, sizeof buffer, &iosb);
	ok( r == STATUS_SUCCESS, "query failed %08lx\n", r);
	check_edb(&iosb, buffer);

	// what happens if the mask is present but empty?
	r = query_one(&oa, L"", buffer, sizeof buffer, &iosb);
	ok( r == STATUS_SUCCESS, "query failed %08lx\n", r);
	check_dot(&iosb, buffer);

	// how does * work?
	r = query_one(&oa, L"*", buffer, sizeof buffer, &iosb);
	ok( r == STATUS_SUCCESS, "query failed %08lx\n", r);
	check_dot(&iosb, buffer);

	// how does * work?
	r = query_one(&oa, L"*.*", buffer, sizeof buffer, &iosb);
	ok( r == STATUS_SUCCESS, "query failed %08lx\n", r);
	check_dot(&iosb, buffer);

	// what does *e return?
	r = query_one(&oa, L"e*", buffer, sizeof buffer, &iosb);
	ok( r == STATUS_SUCCESS, "query failed %08lx\n", r);
	check_edb(&iosb, buffer);

	// can we get back ..
	r = query_one(&oa, L"..", buffer, sizeof buffer, &iosb);
	ok( r == STATUS_NO_SUCH_FILE, "query failed %08lx\n", r);

	// what about ... ?
	r = query_one(&oa, L"...", buffer, sizeof buffer, &iosb);
	ok( r == STATUS_NO_SUCH_FILE, "query failed %08lx\n", r);

	// does ? work
	r = query_one(&oa, L"??", buffer, sizeof buffer, &iosb);
	ok( r == STATUS_NO_SUCH_FILE, "query failed %08lx\n", r);

	// does ? work
	r = query_one(&oa, L"?.", buffer, sizeof buffer, &iosb);
	ok( r == STATUS_NO_SUCH_FILE, "query failed %08lx\n", r);

	// exact match
	r = query_one(&oa, L"edb.chk", buffer, sizeof buffer, &iosb);
	ok( r == STATUS_SUCCESS, "query failed %08lx\n", r);
	check_edb(&iosb, buffer);

	// almost exact match
	r = query_one(&oa, L"edb.ch", buffer, sizeof buffer, &iosb);
	ok( r == STATUS_NO_SUCH_FILE, "query failed %08lx\n", r);

	// case insensitive match
	r = query_one(&oa, L"EDB.CHK", buffer, sizeof buffer, &iosb);
	ok( r == STATUS_SUCCESS, "query failed %08lx\n", r);
	check_edb(&iosb, buffer);

	// dot star?
	r = query_one(&oa, L"edb.*", buffer, sizeof buffer, &iosb);
	ok( r == STATUS_SUCCESS, "query failed %08lx\n", r);
	check_edb(&iosb, buffer);

	// bad masks
	r = query_one(&oa, L"|", buffer, sizeof buffer, &iosb);
	ok( r == STATUS_NO_SUCH_FILE, "query failed %08lx\n", r);
	r = query_one(&oa, L":", buffer, sizeof buffer, &iosb);
	ok( r == STATUS_NO_SUCH_FILE, "query failed %08lx\n", r);
	r = query_one(&oa, L"/", buffer, sizeof buffer, &iosb);
	ok( r == STATUS_NO_SUCH_FILE, "query failed %08lx\n", r);
	r = query_one(&oa, L"\\", buffer, sizeof buffer, &iosb);
	ok( r == STATUS_NO_SUCH_FILE, "query failed %08lx\n", r);

	// delete the file
	init_us(&path, filename);
	r = NtDeleteFile( &oa );
	ok( r == STATUS_SUCCESS, "failed to delete directory %08lx\n", r);

	// delete the directory
	init_us(&path, dirname);
	r = NtDeleteFile( &oa );
	ok( r == STATUS_SUCCESS, "failed to delete directory %08lx\n", r);
}
Esempio n. 17
0
/*
* PipeDlgQueryInfo
*
* Purpose:
*
* List pipes from pipe device.
*
*/
VOID PipeDlgQueryInfo(
    VOID
)
{
    BOOL                        cond = FALSE, cond2 = TRUE;
    BOOLEAN                     bRestartScan;
    HANDLE                      hObject = NULL;
    FILE_DIRECTORY_INFORMATION *DirectoryInfo = NULL;
    NTSTATUS                    status;
    OBJECT_ATTRIBUTES           obja;
    UNICODE_STRING              uStr;
    IO_STATUS_BLOCK             iost;
    LVITEM                      lvitem;
    INT                         c;

    do {

        RtlSecureZeroMemory(&uStr, sizeof(uStr));
        RtlInitUnicodeString(&uStr, T_DEVICE_NAMED_PIPE);
        InitializeObjectAttributes(&obja, &uStr, OBJ_CASE_INSENSITIVE, NULL, NULL);
        status = NtOpenFile(&hObject, FILE_LIST_DIRECTORY, &obja, &iost,
            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SUPERSEDE);
        if (!NT_SUCCESS(status)) {
            break;
        }

        DirectoryInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 0x1000);
        if (DirectoryInfo == NULL) {
            break;
        }

        c = 0;
        bRestartScan = TRUE;
        while (cond2) {

            RtlSecureZeroMemory(&iost, sizeof(iost));

            status = NtQueryDirectoryFile(hObject, NULL, NULL, NULL, &iost,
                DirectoryInfo, 0x1000, FileDirectoryInformation,
                TRUE, //ReturnSingleEntry
                NULL,
                bRestartScan //RestartScan
            );

            if (
                (!NT_SUCCESS(status)) ||
                (!NT_SUCCESS(iost.Status)) ||
                (iost.Information == 0)
                )
            {
                break;
            }

            //Name
            RtlSecureZeroMemory(&lvitem, sizeof(lvitem));
            lvitem.mask = LVIF_TEXT | LVIF_IMAGE;
            lvitem.pszText = DirectoryInfo->FileName;
            lvitem.iItem = MAXINT;
            ListView_InsertItem(PipeDlgContext.ListView, &lvitem);
            bRestartScan = FALSE;
            RtlSecureZeroMemory(DirectoryInfo, 0x1000);

            c++;
            if (c > 0x1000) {//its a trap
                break;
            }
        }

    } while (cond);

    if (DirectoryInfo != NULL) {
        HeapFree(GetProcessHeap(), 0, DirectoryInfo);
    }

    if (hObject) {
        NtClose(hObject);
    }
}