Example #1
0
int rtDirNativeOpen(PRTDIR pDir, char *pszPathBuf)
{
    /*
     * Convert the filter to UTF-16.
     */
    int rc;
    pDir->pNtFilterStr = NULL;
    if (   pDir->cchFilter > 0
            && pDir->enmFilter == RTDIRFILTER_WINNT)
    {
        PRTUTF16 pwszTmp;
        rc = RTStrToUtf16(pDir->pszFilter, &pwszTmp);
        if (RT_FAILURE(rc))
            return rc;
        pDir->NtFilterStr.Buffer = pwszTmp;
        pDir->NtFilterStr.Length = pDir->NtFilterStr.MaximumLength = (uint16_t)(RTUtf16Len(pwszTmp) * sizeof(RTUTF16));
        pDir->pNtFilterStr = &pDir->NtFilterStr;
    }

    /*
     * Try open the directory
     */
#ifdef IPRT_WITH_NT_PATH_PASSTHRU
    bool fObjDir;
#endif
    rc = RTNtPathOpenDir(pszPathBuf,
                         FILE_READ_DATA | SYNCHRONIZE,
                         FILE_SHARE_READ | FILE_SHARE_WRITE,
                         FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
                         OBJ_CASE_INSENSITIVE,
                         &pDir->hDir,
#ifdef IPRT_WITH_NT_PATH_PASSTHRU
                         &fObjDir
#else
                         NULL
#endif
                        );
    if (RT_SUCCESS(rc))
    {
        /*
         * Init data.
         */
        pDir->fDataUnread = false; /* spelling it out */
#ifdef IPRT_WITH_NT_PATH_PASSTHRU
        if (fObjDir)
            pDir->enmInfoClass = FileMaximumInformation; /* object directory. */
#endif
    }
    return rc;
}
int rtDirNativeOpen(PRTDIRINTERNAL pDir, uintptr_t hRelativeDir, void *pvNativeRelative)
{
    /*
     * Convert the filter to UTF-16.
     */
    int rc;
    pDir->pNtFilterStr = NULL;
    if (   pDir->cchFilter > 0
        && pDir->enmFilter == RTDIRFILTER_WINNT)
    {
        PRTUTF16 pwszTmp;
        rc = RTStrToUtf16(pDir->pszFilter, &pwszTmp);
        if (RT_FAILURE(rc))
            return rc;
        pDir->NtFilterStr.Buffer = pwszTmp;
        pDir->NtFilterStr.Length = pDir->NtFilterStr.MaximumLength = (uint16_t)(RTUtf16Len(pwszTmp) * sizeof(RTUTF16));
        pDir->pNtFilterStr = &pDir->NtFilterStr;
    }

    /*
     * Try open the directory
     */
#ifdef IPRT_WITH_NT_PATH_PASSTHRU
    bool fObjDir = false;
#endif
    if (hRelativeDir != ~(uintptr_t)0 && pvNativeRelative == NULL)
    {
        /* Caller already opened it, easy! */
        pDir->hDir = (HANDLE)hRelativeDir;
        rc = VINF_SUCCESS;
    }
    else
    {
        /*
         * If we have to check for reparse points, this gets complicated!
         */
        static int volatile g_fReparsePoints = -1;
        uint32_t            fOptions         = FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT;
        int fReparsePoints = g_fReparsePoints;
        if (   fReparsePoints != 0
            && (pDir->fFlags & RTDIR_F_NO_FOLLOW)
            && !pDir->fDirSlash)
            fOptions |= FILE_OPEN_REPARSE_POINT;

        for (;;)
        {
            if (pvNativeRelative == NULL)
                rc = RTNtPathOpenDir(pDir->pszPath,
                                     FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | FILE_TRAVERSE | SYNCHRONIZE,
                                     FILE_SHARE_READ | FILE_SHARE_WRITE,
                                     fOptions,
                                     OBJ_CASE_INSENSITIVE,
                                     &pDir->hDir,
#ifdef IPRT_WITH_NT_PATH_PASSTHRU
                                     &fObjDir
#else
                                     NULL
#endif
                                     );
            else
                rc = RTNtPathOpenDirEx((HANDLE)hRelativeDir,
                                       (struct _UNICODE_STRING *)pvNativeRelative,
                                       FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | FILE_TRAVERSE | SYNCHRONIZE,
                                       FILE_SHARE_READ | FILE_SHARE_WRITE,
                                       fOptions,
                                       OBJ_CASE_INSENSITIVE,
                                       &pDir->hDir,
#ifdef IPRT_WITH_NT_PATH_PASSTHRU
                                       &fObjDir
#else
                                       NULL
#endif
                                       );
            if (   !(fOptions & FILE_OPEN_REPARSE_POINT)
                || (rc != VINF_SUCCESS && rc != VERR_INVALID_PARAMETER) )
                break;
            if (rc == VINF_SUCCESS)
            {
                if (fReparsePoints == -1)
                    g_fReparsePoints = 1;

                /*
                 * We now need to check if we opened a symbolic directory link.
                 * (These can be enumerated, but contains only '.' and '..'.)
                 */
                FILE_ATTRIBUTE_TAG_INFORMATION  TagInfo = { 0, 0 };
                IO_STATUS_BLOCK                 Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
                NTSTATUS rcNt = NtQueryInformationFile(pDir->hDir, &Ios, &TagInfo, sizeof(TagInfo), FileAttributeTagInformation);
                AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt));
                if (!NT_SUCCESS(rcNt))
                    TagInfo.FileAttributes = TagInfo.ReparseTag = 0;
                if (!(TagInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
                    break;

                NtClose(pDir->hDir);
                pDir->hDir = RTNT_INVALID_HANDLE_VALUE;

                if (TagInfo.ReparseTag == IO_REPARSE_TAG_SYMLINK)
                {
                    rc = VERR_IS_A_SYMLINK;
                    break;
                }

                /* Reparse point that isn't a symbolic link, try follow the reparsing. */
            }
            else if (fReparsePoints == -1)
                g_fReparsePoints = fReparsePoints = 0;
            fOptions &= ~FILE_OPEN_REPARSE_POINT;
        }

    }
    if (RT_SUCCESS(rc))
    {
        /*
         * Init data.
         */
        pDir->fDataUnread = false; /* spelling it out */
        pDir->uDirDev     = 0;
#ifdef IPRT_WITH_NT_PATH_PASSTHRU
        if (fObjDir)
            pDir->enmInfoClass = FileMaximumInformation; /* object directory. */
#endif
    }
    return rc;
}