VirtualBox

vbox的更動 47535 路徑 trunk/src/VBox/Runtime/r3/nt


忽略:
時間撮記:
2013-8-5 上午01:54:25 (11 年 以前)
作者:
vboxsync
訊息:

IPRT: Wrote native NT directory enumeration - not enabled by default. Provides ChangeTime and later file ID (inode no). Can also enumerate object directories, just for the fun of it.

位置:
trunk/src/VBox/Runtime/r3/nt
檔案:
修改 3 筆資料
複製 1 筆資料

圖例:

未更動
新增
刪除
  • trunk/src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp

    r47534 r47535  
    11/* $Id$ */
    22/** @file
    3  * IPRT - Directory Enumeration, Windows.
     3 * IPRT - Directory Enumeration, Native NT.
    44 */
    55
     
    3030*******************************************************************************/
    3131#define LOG_GROUP RTLOGGROUP_DIR
    32 #include <Windows.h>
     32#include "internal-r3-nt.h"
    3333
    3434#include <iprt/dir.h>
     
    4444
    4545
     46/*******************************************************************************
     47*   Defined Constants And Macros                                               *
     48*******************************************************************************/
     49/** Whether to return a single record (TRUE) or multiple (FALSE)o. */
     50#define RTDIR_NT_SINGLE_RECORD  FALSE
     51
     52/** Go hard on record chaining (has slight performance impact). */
     53#ifdef RT_STRICT
     54# define RTDIR_NT_STRICT
     55#endif
     56
     57
     58/* ASSUMES FileID comes after ShortName and the structus are identical up to that point. */
     59AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, NextEntryOffset, FILE_ID_BOTH_DIR_INFORMATION, NextEntryOffset);
     60AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, FileIndex      , FILE_ID_BOTH_DIR_INFORMATION, FileIndex      );
     61AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, CreationTime   , FILE_ID_BOTH_DIR_INFORMATION, CreationTime   );
     62AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, LastAccessTime , FILE_ID_BOTH_DIR_INFORMATION, LastAccessTime );
     63AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, LastWriteTime  , FILE_ID_BOTH_DIR_INFORMATION, LastWriteTime  );
     64AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, ChangeTime     , FILE_ID_BOTH_DIR_INFORMATION, ChangeTime     );
     65AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, EndOfFile      , FILE_ID_BOTH_DIR_INFORMATION, EndOfFile      );
     66AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, AllocationSize , FILE_ID_BOTH_DIR_INFORMATION, AllocationSize );
     67AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, FileAttributes , FILE_ID_BOTH_DIR_INFORMATION, FileAttributes );
     68AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, FileNameLength , FILE_ID_BOTH_DIR_INFORMATION, FileNameLength );
     69AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, EaSize         , FILE_ID_BOTH_DIR_INFORMATION, EaSize         );
     70AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, ShortNameLength, FILE_ID_BOTH_DIR_INFORMATION, ShortNameLength);
     71AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, ShortName      , FILE_ID_BOTH_DIR_INFORMATION, ShortName      );
     72
     73
     74
     75size_t rtDirNativeGetStructSize(const char *pszPath)
     76{
     77    NOREF(pszPath);
     78    return sizeof(RTDIR);
     79}
     80
     81
    4682int rtDirNativeOpen(PRTDIR pDir, char *pszPathBuf)
    4783{
    4884    /*
    49      * Setup the search expression.
    50      *
    51      * pszPathBuf is pointing to the return 4K return buffer for the RTPathReal()
    52      * call in rtDirOpenCommon(), so all we gota do is check that we don't overflow
    53      * it when adding the wildcard expression.
    54      */
    55     size_t cbExpr;
    56     const char *pszExpr;
    57     if (pDir->enmFilter == RTDIRFILTER_WINNT)
    58     {
    59         pszExpr = pDir->pszFilter;
    60         cbExpr  = pDir->cchFilter + 1;
    61     }
    62     else
    63     {
    64         pszExpr = "*";
    65         cbExpr  = sizeof("*");
    66     }
    67     if (pDir->cchPath + cbExpr > RTPATH_MAX)
    68         return VERR_FILENAME_TOO_LONG;
    69     memcpy(pszPathBuf + pDir->cchPath, pszExpr, cbExpr);
    70 
    71 
    72     /*
    73      * Attempt opening the search.
    74      */
    75     int rc = VINF_SUCCESS;
    76     PRTUTF16 pwszName;
    77     rc = RTStrToUtf16(pszPathBuf, &pwszName);
     85     * Convert the filter to UTF-16.
     86     */
     87    int rc;
     88    pDir->pNtFilterStr = NULL;
     89    if (   pDir->cchFilter > 0
     90        && pDir->enmFilter == RTDIRFILTER_WINNT)
     91    {
     92        PRTUTF16 pwszTmp;
     93        rc = RTStrToUtf16(pDir->pszFilter, &pwszTmp);
     94        if (RT_FAILURE(rc))
     95            return rc;
     96        pDir->NtFilterStr.Buffer = pwszTmp;
     97        pDir->NtFilterStr.Length = pDir->NtFilterStr.MaximumLength = (uint16_t)(RTUtf16Len(pwszTmp) * sizeof(RTUTF16));
     98        pDir->pNtFilterStr = &pDir->NtFilterStr;
     99    }
     100
     101    /*
     102     * Try open the directory
     103     */
     104#ifdef IPRT_WITH_NT_PATH_PASSTHRU
     105    bool fObjDir;
     106#endif
     107    rc = rtNtPathOpenDir(pszPathBuf,
     108                         FILE_READ_DATA | SYNCHRONIZE,
     109                         FILE_SHARE_READ | FILE_SHARE_WRITE,
     110                         FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
     111                         OBJ_CASE_INSENSITIVE,
     112                         &pDir->hDir,
     113#ifdef IPRT_WITH_NT_PATH_PASSTHRU
     114                         &fObjDir
     115#else
     116                         NULL
     117#endif
     118                         );
    78119    if (RT_SUCCESS(rc))
    79120    {
    80         pDir->hDir    = FindFirstFileW((LPCWSTR)pwszName, &pDir->Data);
    81         if (pDir->hDir != INVALID_HANDLE_VALUE)
    82             pDir->fDataUnread = true;
    83         else
    84         {
    85             DWORD dwErr = GetLastError();
    86             /* Theoretical case of an empty directory or more normal case of no matches. */
    87             if (   dwErr == ERROR_FILE_NOT_FOUND
    88                 || dwErr == ERROR_NO_MORE_FILES /* ???*/)
    89                 pDir->fDataUnread = false;
    90             else
    91                 rc = RTErrConvertFromWin32(GetLastError());
    92         }
    93         RTUtf16Free(pwszName);
    94     }
    95 
     121        /*
     122         * Init data.
     123         */
     124        pDir->fDataUnread = false; /* spelling it out */
     125#ifdef IPRT_WITH_NT_PATH_PASSTHRU
     126        if (fObjDir)
     127            pDir->enmInfoClass = FileMaximumInformation; /* object directory. */
     128#endif
     129    }
    96130    return rc;
    97131}
     
    114148     * Close the handle.
    115149     */
    116     pDir->u32Magic++;
    117     if (pDir->hDir != INVALID_HANDLE_VALUE)
    118     {
    119         BOOL fRc = FindClose(pDir->hDir);
    120         Assert(fRc);
    121         pDir->hDir = INVALID_HANDLE_VALUE;
     150    pDir->u32Magic = ~RTDIR_MAGIC;
     151    if (pDir->hDir != MY_INVALID_HANDLE_VALUE)
     152    {
     153        int rc = rtNtPathClose(pDir->hDir);
     154        AssertRC(rc);
     155        pDir->hDir = MY_INVALID_HANDLE_VALUE;
    122156    }
    123157    RTStrFree(pDir->pszName);
    124158    pDir->pszName = NULL;
     159    RTUtf16Free(pDir->NtFilterStr.Buffer);
     160    pDir->NtFilterStr.Buffer = NULL;
     161    RTMemFree(pDir->pabBuffer);
     162    pDir->pabBuffer = NULL;
    125163    RTMemFree(pDir);
    126164
     
    129167
    130168
     169/**
     170 * Checks the validity of the current record.
     171 *
     172 * @returns IPRT status code
     173 * @param   pThis       The directory instance data.
     174 */
     175static int rtDirNtCheckRecord(PRTDIR pThis)
     176{
     177#ifdef RTDIR_NT_STRICT
     178# ifdef IPRT_WITH_NT_PATH_PASSTHRU
     179    if (pThis->enmInfoClass != FileMaximumInformation)
     180# endif
     181    {
     182        uintptr_t uEndAddr;
     183        if (pThis->enmInfoClass == FileIdBothDirectoryInformation)
     184            uEndAddr = (uintptr_t)&pThis->uCurData.pBothId->FileName[0];
     185        else
     186            uEndAddr = (uintptr_t)&pThis->uCurData.pBoth->FileName[0];
     187        AssertReturn(uEndAddr < (uintptr_t)&pThis->pabBuffer[pThis->cbBuffer], VERR_IO_GEN_FAILURE);
     188
     189        AssertReturn(pThis->uCurData.pBoth->FileNameLength < _64K, VERR_FILENAME_TOO_LONG);
     190        AssertReturn((pThis->uCurData.pBoth->FileNameLength & 1) == 0, VERR_IO_GEN_FAILURE);
     191
     192        uEndAddr += pThis->uCurData.pBoth->FileNameLength;
     193        AssertReturn(uEndAddr <= (uintptr_t)&pThis->pabBuffer[pThis->cbBuffer], VERR_IO_GEN_FAILURE);
     194
     195        AssertReturn((unsigned)pThis->uCurData.pBoth->ShortNameLength <= sizeof(pThis->uCurData.pBoth->ShortName),
     196                     VERR_IO_GEN_FAILURE);
     197    }
     198#endif
     199
     200    return VINF_SUCCESS;
     201}
     202
     203
     204/**
     205 * Advances the buffer pointer.
     206 *
     207 * @param   pThis       The directory instance data.
     208 */
     209static int rtDirNtAdvanceBuffer(PRTDIR pThis)
     210{
     211    int rc;
     212
     213#ifdef IPRT_WITH_NT_PATH_PASSTHRU
     214    if (pThis->enmInfoClass == FileMaximumInformation)
     215    {
     216        pThis->uCurData.pObjDir++;
     217        pThis->fDataUnread = pThis->uCurData.pObjDir->Name.Length != 0;
     218        return VINF_SUCCESS;
     219    }
     220#endif
     221
     222    pThis->fDataUnread = false;
     223
     224    uint32_t const offNext = pThis->uCurData.pBoth->NextEntryOffset;
     225    if (offNext == 0)
     226        return VINF_SUCCESS;
     227
     228#ifdef RTDIR_NT_STRICT
     229    /* Make sure the next-record offset is beyond the current record. */
     230    size_t cbRec;
     231    if (pThis->enmInfoClass == FileIdBothDirectoryInformation)
     232        cbRec = RT_UOFFSETOF(FILE_ID_BOTH_DIR_INFORMATION, FileName);
     233    else
     234        cbRec = RT_UOFFSETOF(FILE_BOTH_DIR_INFORMATION, FileName);
     235    cbRec += pThis->uCurData.pBoth->FileNameLength;
     236    AssertReturn(offNext >= cbRec, VERR_IO_GEN_FAILURE);
     237#endif
     238    pThis->uCurData.u += offNext;
     239
     240    rc = rtDirNtCheckRecord(pThis);
     241    pThis->fDataUnread = RT_SUCCESS(rc);
     242    return rc;
     243}
     244
     245
     246/**
     247 * Fetches more data from the file system.
     248 *
     249 * @returns IPRT status code
     250 * @param   pThis       The directory instance data.
     251 */
     252static int rtDirNtFetchMore(PRTDIR pThis)
     253{
     254    Assert(!pThis->fDataUnread);
     255
     256    /*
     257     * Allocate the buffer the first time around.
     258     * We do this in lazy fashion as some users of RTDirOpen will not actually
     259     * list any files, just open it for various reasons.
     260     */
     261    bool fFirst = false;
     262    if (!pThis->pabBuffer)
     263    {
     264        fFirst = false;
     265        pThis->cbBufferAlloc = _256K;
     266        pThis->pabBuffer = (uint8_t *)RTMemAlloc(pThis->cbBufferAlloc);
     267        if (!pThis->pabBuffer)
     268        {
     269            do
     270            {
     271                pThis->cbBufferAlloc /= 4;
     272                pThis->pabBuffer = (uint8_t *)RTMemAlloc(pThis->cbBufferAlloc);
     273            } while (pThis->pabBuffer == NULL && pThis->cbBufferAlloc > _4K);
     274            if (!pThis->pabBuffer)
     275                return VERR_NO_MEMORY;
     276        }
     277    }
     278
     279    /*
     280     * Read more.
     281     */
     282    NTSTATUS rcNt;
     283    IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
     284    if (pThis->enmInfoClass != (FILE_INFORMATION_CLASS)0)
     285    {
     286#ifdef IPRT_WITH_NT_PATH_PASSTHRU
     287        if (pThis->enmInfoClass == FileMaximumInformation)
     288        {
     289            Ios.Information = 0;
     290            Ios.Status = rcNt = NtQueryDirectoryObject(pThis->hDir,
     291                                                       pThis->pabBuffer,
     292                                                       pThis->cbBufferAlloc,
     293                                                       RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
     294                                                       FALSE /*RestartScan*/,
     295                                                       &pThis->uObjDirCtx,
     296                                                       (PULONG)&Ios.Information);
     297        }
     298        else
     299#endif
     300            rcNt = NtQueryDirectoryFile(pThis->hDir,
     301                                        NULL /* Event */,
     302                                        NULL /* ApcRoutine */,
     303                                        NULL /* ApcContext */,
     304                                        &Ios,
     305                                        pThis->pabBuffer,
     306                                        pThis->cbBufferAlloc,
     307                                        pThis->enmInfoClass,
     308                                        RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
     309                                        pThis->pNtFilterStr,
     310                                        FALSE /*RestartScan */);
     311    }
     312    else
     313    {
     314        /*
     315         * The first time around we have figure which info class we can use.
     316         * We prefer one which gives us file IDs, but we'll settle for less.
     317         */
     318        pThis->enmInfoClass = FileIdBothDirectoryInformation;
     319        rcNt = NtQueryDirectoryFile(pThis->hDir,
     320                                    NULL /* Event */,
     321                                    NULL /* ApcRoutine */,
     322                                    NULL /* ApcContext */,
     323                                    &Ios,
     324                                    pThis->pabBuffer,
     325                                    pThis->cbBufferAlloc,
     326                                    pThis->enmInfoClass,
     327                                    RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
     328                                    pThis->pNtFilterStr,
     329                                    FALSE /*RestartScan */);
     330        if (!NT_SUCCESS(rcNt))
     331        {
     332            pThis->enmInfoClass = FileBothDirectoryInformation;
     333            rcNt = NtQueryDirectoryFile(pThis->hDir,
     334                                        NULL /* Event */,
     335                                        NULL /* ApcRoutine */,
     336                                        NULL /* ApcContext */,
     337                                        &Ios,
     338                                        pThis->pabBuffer,
     339                                        pThis->cbBufferAlloc,
     340                                        pThis->enmInfoClass,
     341                                        RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
     342                                        pThis->pNtFilterStr,
     343                                        FALSE /*RestartScan */);
     344        }
     345    }
     346    if (!NT_SUCCESS(rcNt))
     347    {
     348        if (rcNt == STATUS_NO_MORE_FILES || rcNt == STATUS_NO_MORE_ENTRIES)
     349            return VERR_NO_MORE_FILES;
     350        return RTErrConvertFromNtStatus(rcNt);
     351    }
     352    Assert(Ios.Information > sizeof(*pThis->uCurData.pBoth));
     353
     354    /*
     355     * Set up the data members.
     356     */
     357    pThis->uCurData.u  = (uintptr_t)pThis->pabBuffer;
     358    pThis->cbBuffer    = Ios.Information;
     359
     360    int rc = rtDirNtCheckRecord(pThis);
     361    pThis->fDataUnread = RT_SUCCESS(rc);
     362
     363    return rc;
     364}
     365
     366
     367/**
     368 * Converts the name from UTF-16 to UTF-8.
     369 *
     370 * Fortunately, the names are relative to the directory, so we won't have to do
     371 * any sweaty path style coversion. :-)
     372 *
     373 * @returns IPRT status code
     374 * @param   pThis       The directory instance data.
     375 * @param   cbName      The file name length in bytes.
     376 * @param   pwsName     The file name, not terminated.
     377 */
     378static int rtDirNtConvertName(PRTDIR pThis, uint32_t cbName, PCRTUTF16 pwsName)
     379{
     380    int rc = RTUtf16ToUtf8Ex(pwsName, cbName / 2, &pThis->pszName, pThis->cbNameAlloc, &pThis->cchName);
     381    if (RT_SUCCESS(rc))
     382    {
     383        if (!pThis->cbNameAlloc)
     384            pThis->cbNameAlloc = pThis->cchName + 1;
     385    }
     386    else if (rc == VERR_BUFFER_OVERFLOW)
     387    {
     388        RTStrFree(pThis->pszName);
     389        pThis->pszName = NULL;
     390        pThis->cbNameAlloc = 0;
     391
     392        rc = RTUtf16ToUtf8Ex(pwsName, cbName / 2, &pThis->pszName, pThis->cbNameAlloc, &pThis->cchName);
     393        if (RT_SUCCESS(rc))
     394            pThis->cbNameAlloc = pThis->cchName + 1;
     395    }
     396    Assert(RT_SUCCESS(rc) ? pThis->pszName != NULL : pThis->pszName == NULL);
     397    return rc;
     398}
     399
     400
     401/**
     402 * Converts the name of the current record.
     403 *
     404 * @returns IPRT status code.
     405 * @param   pThis       The directory instance data.
     406 */
     407static int rtDirNtConvertCurName(PRTDIR pThis)
     408{
     409    switch (pThis->enmInfoClass)
     410    {
     411        case FileIdBothDirectoryInformation:
     412            return rtDirNtConvertName(pThis, pThis->uCurData.pBothId->FileNameLength, pThis->uCurData.pBothId->FileName);
     413        case FileBothDirectoryInformation:
     414            return rtDirNtConvertName(pThis, pThis->uCurData.pBoth->FileNameLength, pThis->uCurData.pBoth->FileName);
     415#ifdef IPRT_WITH_NT_PATH_PASSTHRU
     416        case FileMaximumInformation:
     417            return rtDirNtConvertName(pThis, pThis->uCurData.pObjDir->Name.Length, pThis->uCurData.pObjDir->Name.Buffer);
     418#endif
     419
     420        default:
     421            AssertFailedReturn(VERR_INTERNAL_ERROR_3);
     422    }
     423}
     424
     425
    131426RTDECL(int) RTDirRead(PRTDIR pDir, PRTDIRENTRY pDirEntry, size_t *pcbDirEntry)
    132427{
     428    int rc;
     429
    133430    /*
    134431     * Validate input.
    135432     */
    136     if (!pDir || pDir->u32Magic != RTDIR_MAGIC)
    137     {
    138         AssertMsgFailed(("Invalid pDir=%p\n", pDir));
    139         return VERR_INVALID_PARAMETER;
    140     }
    141     if (!pDirEntry)
    142     {
    143         AssertMsgFailed(("Invalid pDirEntry=%p\n", pDirEntry));
    144         return VERR_INVALID_PARAMETER;
    145     }
     433    AssertPtrReturn(pDir, VERR_INVALID_POINTER);
     434    AssertReturn(pDir->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE);
     435    AssertPtrReturn(pDirEntry, VERR_INVALID_POINTER);
    146436    size_t cbDirEntry = sizeof(*pDirEntry);
    147437    if (pcbDirEntry)
    148438    {
    149439        cbDirEntry = *pcbDirEntry;
    150         if (cbDirEntry < RT_UOFFSETOF(RTDIRENTRY, szName[2]))
    151         {
    152             AssertMsgFailed(("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRY, szName[2])));
    153             return VERR_INVALID_PARAMETER;
    154         }
     440        AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRY, szName[2]),
     441                        ("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRY, szName[2])),
     442                        VERR_INVALID_PARAMETER);
    155443    }
    156444
     
    160448    if (!pDir->fDataUnread)
    161449    {
    162         RTStrFree(pDir->pszName);
    163         pDir->pszName = NULL;
    164 
    165         BOOL fRc = FindNextFileW(pDir->hDir, &pDir->Data);
    166         if (!fRc)
    167         {
    168             int iErr = GetLastError();
    169             if (pDir->hDir == INVALID_HANDLE_VALUE || iErr == ERROR_NO_MORE_FILES)
    170                 return VERR_NO_MORE_FILES;
    171             return RTErrConvertFromWin32(iErr);
    172         }
     450        rc = rtDirNtFetchMore(pDir);
     451        if (RT_FAILURE(rc))
     452            return rc;
    173453    }
    174454
     
    176456     * Convert the filename to UTF-8.
    177457     */
    178     if (!pDir->pszName)
    179     {
    180         int rc = RTUtf16ToUtf8((PCRTUTF16)pDir->Data.cFileName, &pDir->pszName);
    181         if (RT_FAILURE(rc))
    182         {
    183             pDir->pszName = NULL;
    184             return rc;
    185         }
    186         pDir->cchName = strlen(pDir->pszName);
    187     }
     458    rc = rtDirNtConvertCurName(pDir);
     459    if (RT_FAILURE(rc))
     460        return rc;
    188461
    189462    /*
     
    201474     * Setup the returned data.
    202475     */
    203     pDir->fDataUnread  = false;
    204     pDirEntry->INodeId = 0; /** @todo we can use the fileid here if we must (see GetFileInformationByHandle). */
    205     pDirEntry->enmType = pDir->Data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
    206                        ? RTDIRENTRYTYPE_DIRECTORY : RTDIRENTRYTYPE_FILE;
    207     pDirEntry->cbName  = (uint16_t)cchName;
    208     Assert(pDirEntry->cbName == cchName);
     476    pDirEntry->cbName = (uint16_t)cchName; Assert(pDirEntry->cbName == cchName);
    209477    memcpy(pDirEntry->szName, pszName, cchName + 1);
    210478
    211     return VINF_SUCCESS;
    212 }
    213 
    214 
    215 RTDECL(int) RTDirReadEx(PRTDIR pDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)
    216 {
    217     /** @todo Symlinks: Find[First|Next]FileW will return info about
    218         the link, so RTPATH_F_FOLLOW_LINK is not handled correctly. */
     479    pDirEntry->INodeId = pDir->enmInfoClass == FileIdBothDirectoryInformation
     480                       ? pDir->uCurData.pBothId->FileId.QuadPart : 0;
     481
     482#ifdef IPRT_WITH_NT_PATH_PASSTHRU
     483    if (pDir->enmInfoClass != FileMaximumInformation)
     484#endif
     485    {
     486        switch (   pDir->uCurData.pBoth->FileAttributes
     487                & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY))
     488        {
     489            default:
     490                AssertFailed();
     491            case 0:
     492                pDirEntry->enmType = RTDIRENTRYTYPE_FILE;
     493                break;
     494
     495            case FILE_ATTRIBUTE_DIRECTORY:
     496                pDirEntry->enmType = RTDIRENTRYTYPE_DIRECTORY;
     497                break;
     498
     499            case FILE_ATTRIBUTE_REPARSE_POINT:
     500            case FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY:
     501                pDirEntry->enmType = RTDIRENTRYTYPE_SYMLINK;
     502                break;
     503        }
     504    }
     505#ifdef IPRT_WITH_NT_PATH_PASSTHRU
     506    else
     507    {
     508        pDirEntry->enmType = RTDIRENTRYTYPE_UNKNOWN;
     509        if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length,
     510                                    RT_STR_TUPLE("Directory")))
     511            pDirEntry->enmType = RTDIRENTRYTYPE_DIRECTORY;
     512        else if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length,
     513                                         RT_STR_TUPLE("SymbolicLink")))
     514            pDirEntry->enmType = RTDIRENTRYTYPE_SYMLINK;
     515    }
     516#endif
     517
     518    return rtDirNtAdvanceBuffer(pDir);
     519}
     520
     521
     522RTDECL(int) RTDirReadEx(PRTDIR pDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry,
     523                        RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)
     524{
     525    int rc;
     526
    219527    /*
    220528     * Validate input.
    221529     */
    222     if (!pDir || pDir->u32Magic != RTDIR_MAGIC)
    223     {
    224         AssertMsgFailed(("Invalid pDir=%p\n", pDir));
    225         return VERR_INVALID_PARAMETER;
    226     }
    227     if (!pDirEntry)
    228     {
    229         AssertMsgFailed(("Invalid pDirEntry=%p\n", pDirEntry));
    230         return VERR_INVALID_PARAMETER;
    231     }
    232     if (    enmAdditionalAttribs < RTFSOBJATTRADD_NOTHING
    233         ||  enmAdditionalAttribs > RTFSOBJATTRADD_LAST)
    234     {
    235         AssertMsgFailed(("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs));
    236         return VERR_INVALID_PARAMETER;
    237     }
     530    AssertPtrReturn(pDir, VERR_INVALID_POINTER);
     531    AssertReturn(pDir->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE);
     532    AssertPtrReturn(pDirEntry, VERR_INVALID_POINTER);
     533
     534    AssertReturn(enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING && enmAdditionalAttribs <= RTFSOBJATTRADD_LAST,
     535                 VERR_INVALID_PARAMETER);
    238536    AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
     537
    239538    size_t cbDirEntry = sizeof(*pDirEntry);
    240539    if (pcbDirEntry)
    241540    {
    242541        cbDirEntry = *pcbDirEntry;
    243         if (cbDirEntry < RT_UOFFSETOF(RTDIRENTRYEX, szName[2]))
    244         {
    245             AssertMsgFailed(("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2])));
    246             return VERR_INVALID_PARAMETER;
    247         }
     542        AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRYEX, szName[2]),
     543                        ("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2])),
     544                        VERR_INVALID_PARAMETER);
    248545    }
    249546
     
    253550    if (!pDir->fDataUnread)
    254551    {
    255         RTStrFree(pDir->pszName);
    256         pDir->pszName = NULL;
    257 
    258         BOOL fRc = FindNextFileW(pDir->hDir, &pDir->Data);
    259         if (!fRc)
    260         {
    261             int iErr = GetLastError();
    262             if (pDir->hDir == INVALID_HANDLE_VALUE || iErr == ERROR_NO_MORE_FILES)
    263                 return VERR_NO_MORE_FILES;
    264             return RTErrConvertFromWin32(iErr);
    265         }
     552        rc = rtDirNtFetchMore(pDir);
     553        if (RT_FAILURE(rc))
     554            return rc;
    266555    }
    267556
     
    269558     * Convert the filename to UTF-8.
    270559     */
    271     if (!pDir->pszName)
    272     {
    273         int rc = RTUtf16ToUtf8((PCRTUTF16)pDir->Data.cFileName, &pDir->pszName);
    274         if (RT_FAILURE(rc))
    275         {
    276             pDir->pszName = NULL;
    277             return rc;
    278         }
    279         pDir->cchName = strlen(pDir->pszName);
    280     }
     560    rc = rtDirNtConvertCurName(pDir);
     561    if (RT_FAILURE(rc))
     562        return rc;
    281563
    282564    /*
     
    294576     * Setup the returned data.
    295577     */
    296     pDir->fDataUnread  = false;
    297     pDirEntry->cbName  = (uint16_t)cchName;
    298     Assert(pDirEntry->cbName == cchName);
     578    PFILE_BOTH_DIR_INFORMATION pBoth = pDir->uCurData.pBoth;
     579
     580    pDirEntry->cbName  = (uint16_t)cchName;  Assert(pDirEntry->cbName == cchName);
    299581    memcpy(pDirEntry->szName, pszName, cchName + 1);
    300     if (pDir->Data.cAlternateFileName[0])
    301     {
    302         /* copy and calc length */
    303         PCRTUTF16 pwszSrc = (PCRTUTF16)pDir->Data.cAlternateFileName;
    304         PRTUTF16  pwszDst = pDirEntry->wszShortName;
    305         uint32_t  off = 0;
    306         while (pwszSrc[off] && off < RT_ELEMENTS(pDirEntry->wszShortName) - 1U)
     582    memset(pDirEntry->wszShortName, 0, sizeof(pDirEntry->wszShortName));
     583#ifdef IPRT_WITH_NT_PATH_PASSTHRU
     584    if (pDir->enmInfoClass != FileMaximumInformation)
     585#endif
     586    {
     587        uint8_t cbShort = pBoth->ShortNameLength;
     588        if (cbShort > 0)
    307589        {
    308             pwszDst[off] = pwszSrc[off];
    309             off++;
     590            AssertStmt(cbShort < sizeof(pDirEntry->wszShortName), cbShort = sizeof(pDirEntry->wszShortName) - 2);
     591            memcpy(pDirEntry->wszShortName, pBoth->ShortName, cbShort);
     592            pDirEntry->cwcShortName = cbShort / 2;
    310593        }
    311         pDirEntry->cwcShortName = (uint16_t)off;
    312 
    313         /* zero the rest */
    314         do
    315             pwszDst[off++] = '\0';
    316         while (off < RT_ELEMENTS(pDirEntry->wszShortName));
    317     }
     594        else
     595            pDirEntry->cwcShortName = 0;
     596
     597        pDirEntry->Info.cbObject    = pBoth->EndOfFile.QuadPart;
     598        pDirEntry->Info.cbAllocated = pBoth->AllocationSize.QuadPart;
     599
     600        Assert(sizeof(uint64_t) == sizeof(pBoth->CreationTime));
     601        RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime,         pBoth->CreationTime.QuadPart);
     602        RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime,        pBoth->LastAccessTime.QuadPart);
     603        RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime,  pBoth->LastWriteTime.QuadPart);
     604        RTTimeSpecSetNtTime(&pDirEntry->Info.ChangeTime,        pBoth->ChangeTime.QuadPart);
     605
     606        pDirEntry->Info.Attr.fMode  = rtFsModeFromDos((pBoth->FileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT,
     607                                                       pszName, cchName);
     608    }
     609#ifdef IPRT_WITH_NT_PATH_PASSTHRU
    318610    else
    319611    {
    320         memset(pDirEntry->wszShortName, 0, sizeof(pDirEntry->wszShortName));
    321612        pDirEntry->cwcShortName = 0;
    322     }
    323 
    324     pDirEntry->Info.cbObject    = ((uint64_t)pDir->Data.nFileSizeHigh << 32)
    325                                 |  (uint64_t)pDir->Data.nFileSizeLow;
    326     pDirEntry->Info.cbAllocated = pDirEntry->Info.cbObject;
    327 
    328     Assert(sizeof(uint64_t) == sizeof(pDir->Data.ftCreationTime));
    329     RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime,         *(uint64_t *)&pDir->Data.ftCreationTime);
    330     RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime,        *(uint64_t *)&pDir->Data.ftLastAccessTime);
    331     RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime,  *(uint64_t *)&pDir->Data.ftLastWriteTime);
    332     pDirEntry->Info.ChangeTime  = pDirEntry->Info.ModificationTime;
    333 
    334     pDirEntry->Info.Attr.fMode  = rtFsModeFromDos((pDir->Data.dwFileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT,
    335                                                    pszName, cchName);
     613        pDirEntry->Info.cbObject    = 0;
     614        pDirEntry->Info.cbAllocated = 0;
     615        RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime,         0);
     616        RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime,        0);
     617        RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime,  0);
     618        RTTimeSpecSetNtTime(&pDirEntry->Info.ChangeTime,        0);
     619
     620        if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length,
     621                                    RT_STR_TUPLE("Directory")))
     622            pDirEntry->Info.Attr.fMode = RTFS_DOS_DIRECTORY | RTFS_TYPE_DIRECTORY | 0777;
     623        else if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length,
     624                                         RT_STR_TUPLE("SymbolicLink")))
     625            pDirEntry->Info.Attr.fMode = RTFS_DOS_NT_REPARSE_POINT | RTFS_TYPE_SYMLINK | 0777;
     626        else if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length,
     627                                         RT_STR_TUPLE("Device")))
     628            pDirEntry->Info.Attr.fMode = RTFS_DOS_NT_DEVICE | RTFS_TYPE_DEV_CHAR | 0666;
     629        else
     630            pDirEntry->Info.Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_FILE | 0666;
     631    }
     632#endif
    336633
    337634    /*
     
    342639        case RTFSOBJATTRADD_EASIZE:
    343640            pDirEntry->Info.Attr.enmAdditional          = RTFSOBJATTRADD_EASIZE;
    344             pDirEntry->Info.Attr.u.EASize.cb            = 0;
     641#ifdef IPRT_WITH_NT_PATH_PASSTHRU
     642            if (pDir->enmInfoClass == FileMaximumInformation)
     643                pDirEntry->Info.Attr.u.EASize.cb        = 0;
     644            else
     645#endif
     646                pDirEntry->Info.Attr.u.EASize.cb        = pBoth->EaSize;
    345647            break;
    346648
     
    378680    }
    379681
    380     return VINF_SUCCESS;
    381 }
    382 
     682    /*
     683     * Follow links if requested.
     684     */
     685    if (   (fFlags & RTPATH_F_FOLLOW_LINK)
     686        && RTFS_IS_SYMLINK(fFlags))
     687    {
     688        /** @todo Symlinks: Find[First|Next]FileW will return info about
     689            the link, so RTPATH_F_FOLLOW_LINK is not handled correctly. */
     690    }
     691
     692    /*
     693     * Finally advance the buffer.
     694     */
     695    return rtDirNtAdvanceBuffer(pDir);
     696}
     697
  • trunk/src/VBox/Runtime/r3/nt/fs-nt.cpp

    r47533 r47535  
    226226
    227227
    228 /**
    229  * Internal helper for comparing a WCHAR string with a char string.
    230  *
    231  * @returns @c true if equal, @c false if not.
    232  * @param   pwsz1               The first string.
    233  * @param   cb1                 The length of the first string, in bytes.
    234  * @param   psz2                The second string.
    235  * @param   cch2                The length of the second string.
    236  */
    237 static bool rtFsCompWideStrAndAscii(WCHAR const *pwsz1, size_t cch1, const char *psz2, size_t cch2)
    238 {
    239     if (cch1 != cch2 * 2)
    240         return false;
    241     while (cch2-- > 0)
    242     {
    243         unsigned ch1 = *pwsz1++;
    244         unsigned ch2 = (unsigned char)*psz2++;
    245         if (ch1 != ch2)
    246             return false;
    247     }
    248     return true;
    249 }
    250 
    251228
    252229RTR3DECL(int) RTFsQueryType(const char *pszFsPath, PRTFSTYPE penmType)
     
    287264        {
    288265#define IS_FS(a_szName) \
    289 rtFsCompWideStrAndAscii(u.FsAttrInfo.FileSystemName, u.FsAttrInfo.FileSystemNameLength, RT_STR_TUPLE(a_szName))
     266    rtNtCompWideStrAndAscii(u.FsAttrInfo.FileSystemName, u.FsAttrInfo.FileSystemNameLength, RT_STR_TUPLE(a_szName))
    290267            if (IS_FS("NTFS"))
    291268                *penmType = RTFSTYPE_NTFS;
  • trunk/src/VBox/Runtime/r3/nt/internal-r3-nt.h

    r47533 r47535  
    4848# include <ntifs.h>
    4949#endif
     50#include "internal/iprt.h"
    5051
    5152
     
    5354*   Defined Constants And Macros                                               *
    5455*******************************************************************************/
     56/** Indicates that we're targetting native NT in the current source. */
     57#define RT_USE_NATIVE_NT                1
    5558/** Initializes a IO_STATUS_BLOCK. */
    5659#define MY_IO_STATUS_BLOCK_INITIALIZER  { STATUS_FAILED_DRIVER_ENTRY, ~(uintptr_t)42 }
    5760/** Similar to INVALID_HANDLE_VALUE in the Windows environment. */
    5861#define MY_INVALID_HANDLE_VALUE         ( (HANDLE)~(uintptr_t)0 )
     62
     63#ifdef DEBUG_bird
     64/** Enables the "\\!\" NT path pass thru as well as hacks for listing NT object
     65 * directories. */
     66# define IPRT_WITH_NT_PATH_PASSTHRU 1
     67#endif
    5968
    6069
     
    6574                  ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
    6675                  PHANDLE phHandle, PULONG_PTR puDisposition);
     76int  rtNtPathOpenDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fShareAccess, ULONG fCreateOptions,
     77                     ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir);
    6778int  rtNtPathClose(HANDLE hHandle);
     79
     80
     81/**
     82 * Internal helper for comparing a WCHAR string with a char string.
     83 *
     84 * @returns @c true if equal, @c false if not.
     85 * @param   pwsz1               The first string.
     86 * @param   cb1                 The length of the first string, in bytes.
     87 * @param   psz2                The second string.
     88 * @param   cch2                The length of the second string.
     89 */
     90DECLINLINE(bool) rtNtCompWideStrAndAscii(WCHAR const *pwsz1, size_t cch1, const char *psz2, size_t cch2)
     91{
     92    if (cch1 != cch2 * 2)
     93        return false;
     94    while (cch2-- > 0)
     95    {
     96        unsigned ch1 = *pwsz1++;
     97        unsigned ch2 = (unsigned char)*psz2++;
     98        if (ch1 != ch2)
     99            return false;
     100    }
     101    return true;
     102}
    68103
    69104
     
    71106*   NT APIs                                                                    *
    72107*******************************************************************************/
     108
     109RT_C_DECLS_BEGIN
    73110
    74111#ifdef IPRT_NT_NEED_API_GROUP_1
     
    86123#endif
    87124
     125NTSTATUS NTAPI NtOpenDirectoryObject(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
     126
     127typedef struct _OBJECT_DIRECTORY_INFORMATION
     128{
     129    UNICODE_STRING Name;
     130    UNICODE_STRING TypeName;
     131} OBJECT_DIRECTORY_INFORMATION;
     132typedef OBJECT_DIRECTORY_INFORMATION *POBJECT_DIRECTORY_INFORMATION;
     133
     134NTSTATUS NTAPI NtQueryDirectoryObject(HANDLE, PVOID, ULONG, BOOLEAN, BOOLEAN, PULONG, PULONG);
     135
     136
     137RT_C_DECLS_END
    88138
    89139#endif
  • trunk/src/VBox/Runtime/r3/nt/pathint-nt.cpp

    r47533 r47535  
    4747 * @param   pszPath             The UTF-8 path.
    4848 */
    49 static int rtNtPathToNativePassThru(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
    50 {
    51     PRTUTF16 pwszPath;
    52     int rc = RTStrToUtf16(pszPath + 1, &pwszPath);
     49static int rtNtPathToNativePassThruWin(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
     50{
     51    PRTUTF16 pwszPath = NULL;
     52    size_t   cwcLen;
     53    int rc = RTStrToUtf16Ex(pszPath + 1, RTSTR_MAX, &pwszPath, 0, &cwcLen);
    5354    if (RT_SUCCESS(rc))
    5455    {
    55         pwszPath[0] = '\\';
    56         pwszPath[1] = '.';
    57         pwszPath[2] = '\\';
    58 
    59         size_t cwcLen = RTUtf16Len(pwszPath);
    6056        if (cwcLen < _32K - 1)
    6157        {
     58            pwszPath[0] = '\\';
     59            pwszPath[1] = '.';
     60            pwszPath[2] = '\\';
     61
    6262            pNtName->Buffer = pwszPath;
    63             pNtName->MaximumLength = pNtName->Length = (uint16_t)((cwcLen + 0) * 2);
     63            pNtName->MaximumLength = pNtName->Length = (uint16_t)(cwcLen * 2);
     64            *phRootDir = NULL;
     65            return VINF_SUCCESS;
     66        }
     67
     68        RTUtf16Free(pwszPath);
     69        rc = VERR_FILENAME_TOO_LONG;
     70    }
     71    return rc;
     72}
     73
     74
     75/**
     76 * Converts the path to UTF-16 and sets all the return values.
     77 *
     78 * @returns IPRT status code.
     79 * @param   pNtName             Where to return the NT name.
     80 * @param   phRootDir           Where to return the root handle, if applicable.
     81 * @param   pszPath             The UTF-8 path.
     82 */
     83static int rtNtPathToNativeToUtf16(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
     84{
     85    PRTUTF16 pwszPath = NULL;
     86    size_t   cwcLen;
     87    int rc = RTStrToUtf16Ex(pszPath, RTSTR_MAX, &pwszPath, 0, &cwcLen);
     88    if (RT_SUCCESS(rc))
     89    {
     90        if (cwcLen < _32K - 1)
     91        {
     92            pNtName->Buffer = pwszPath;
     93            pNtName->MaximumLength = pNtName->Length = (uint16_t)(cwcLen * 2);
    6494            *phRootDir = NULL;
    6595            return VINF_SUCCESS;
     
    100130        if (   pszPath[2] == '?'
    101131            && RTPATH_IS_SLASH(pszPath[3]))
    102             return rtNtPathToNativePassThru(pNtName, phRootDir, pszPath);
     132            return rtNtPathToNativePassThruWin(pNtName, phRootDir, pszPath);
     133
     134#ifdef IPRT_WITH_NT_PATH_PASSTHRU
     135        /* Special hack: The path starts with "\\\\!\\", we will skip past the bang and pass it thru. */
     136        if (   pszPath[2] == '!'
     137            && RTPATH_IS_SLASH(pszPath[3]))
     138            return rtNtPathToNativeToUtf16(pNtName, phRootDir, pszPath + 3);
     139#endif
    103140
    104141        if (   pszPath[2] == '.'
     
    132169     */
    133170    memcpy(szPath, pszPrefix, cchPrefix);
    134     PRTUTF16 pwszPath;
    135     rc = RTStrToUtf16(szPath, &pwszPath);
    136     if (RT_FAILURE(rc))
    137         return rc;
    138 
    139     size_t cwcLen = RTUtf16Len(pwszPath);
    140     if (cwcLen >= _32K - 1)
    141     {
    142         RTUtf16Free(pwszPath);
    143         return VERR_FILENAME_TOO_LONG;
    144     }
    145 
    146     /*
    147      * Success.
    148      */
    149     pNtName->Buffer = pwszPath;
    150     pNtName->MaximumLength = pNtName->Length = (uint16_t)((cwcLen + 0) * 2);
    151     *phRootDir = NULL;
    152     return VINF_SUCCESS;
     171    return rtNtPathToNativeToUtf16(pNtName, phRootDir, szPath);
    153172}
    154173
     
    227246
    228247/**
     248 * Wrapper around NtCreateFile.
     249 *
     250 * @returns IPRT status code.
     251 * @param   pszPath             The UTF-8 path.
     252 * @param   fDesiredAccess      See NtCreateFile.
     253 * @param   fFileAttribs        See NtCreateFile.
     254 * @param   fShareAccess        See NtCreateFile.
     255 * @param   fCreateDisposition  See NtCreateFile.
     256 * @param   fCreateOptions      See NtCreateFile.
     257 * @param   fObjAttribs         The OBJECT_ATTRIBUTES::Attributes value, see
     258 *                              NtCreateFile and InitializeObjectAttributes.
     259 * @param   phHandle            Where to return the handle.
     260 * @param   pfObjDir            If not NULL, the variable pointed to will be set
     261 *                              to @c true if we opened an object directory and
     262 *                              @c false if we opened an directory file (normal
     263 *                              directory).
     264 */
     265int  rtNtPathOpenDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fShareAccess, ULONG fCreateOptions,
     266                     ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir)
     267{
     268    *phHandle = MY_INVALID_HANDLE_VALUE;
     269
     270    HANDLE         hRootDir;
     271    UNICODE_STRING NtName;
     272    int rc = rtNtPathToNative(&NtName, &hRootDir, pszPath);
     273    if (RT_SUCCESS(rc))
     274    {
     275        HANDLE              hFile = MY_INVALID_HANDLE_VALUE;
     276        IO_STATUS_BLOCK     Ios   = MY_IO_STATUS_BLOCK_INITIALIZER;
     277        OBJECT_ATTRIBUTES   ObjAttr;
     278        InitializeObjectAttributes(&ObjAttr, &NtName, fObjAttribs, hRootDir, NULL);
     279
     280        NTSTATUS rcNt = NtCreateFile(&hFile,
     281                                     fDesiredAccess,
     282                                     &ObjAttr,
     283                                     &Ios,
     284                                     NULL /* AllocationSize*/,
     285                                     FILE_ATTRIBUTE_NORMAL,
     286                                     fShareAccess,
     287                                     FILE_OPEN,
     288                                     fCreateOptions,
     289                                     NULL /*EaBuffer*/,
     290                                     0 /*EaLength*/);
     291        if (NT_SUCCESS(rcNt))
     292        {
     293            if (pfObjDir)
     294                *pfObjDir = false;
     295            *phHandle = hFile;
     296            rc = VINF_SUCCESS;
     297        }
     298#ifdef IPRT_WITH_NT_PATH_PASSTHRU
     299        else if (   pfObjDir
     300                 && (rcNt == STATUS_OBJECT_NAME_INVALID || rcNt == STATUS_OBJECT_TYPE_MISMATCH)
     301                 && RTPATH_IS_SLASH(pszPath[0])
     302                 && RTPATH_IS_SLASH(pszPath[1])
     303                 && pszPath[2] == '!'
     304                 && RTPATH_IS_SLASH(pszPath[3]))
     305        {
     306            /* Strip trailing slash. */
     307            if (   NtName.Length > 2
     308                && RTPATH_IS_SLASH(NtName.Buffer[(NtName.Length / 2) - 1]))
     309                NtName.Length -= 2;
     310
     311            /* Rought conversion of the access flags. */
     312            ULONG fObjDesiredAccess = 0;
     313            if (fDesiredAccess & (GENERIC_ALL | STANDARD_RIGHTS_ALL))
     314                fObjDesiredAccess = DIRECTORY_ALL_ACCESS;
     315            else
     316            {
     317                if (fDesiredAccess & (FILE_GENERIC_WRITE | GENERIC_WRITE | STANDARD_RIGHTS_WRITE))
     318                    fObjDesiredAccess |= DIRECTORY_CREATE_OBJECT | DIRECTORY_CREATE_OBJECT;
     319                if (   (fDesiredAccess & (FILE_LIST_DIRECTORY | FILE_GENERIC_READ | GENERIC_READ | STANDARD_RIGHTS_READ))
     320                    || !fObjDesiredAccess)
     321                    fObjDesiredAccess |= DIRECTORY_QUERY | FILE_LIST_DIRECTORY;
     322            }
     323
     324            rcNt = NtOpenDirectoryObject(&hFile, fObjDesiredAccess, &ObjAttr);
     325            if (NT_SUCCESS(rcNt))
     326            {
     327                *pfObjDir = true;
     328                *phHandle = hFile;
     329                rc = VINF_SUCCESS;
     330            }
     331            else
     332                rc = RTErrConvertFromNtStatus(rcNt);
     333        }
     334#endif
     335        else
     336            rc = RTErrConvertFromNtStatus(rcNt);
     337        rtNtPathFreeNative(&NtName, &hRootDir);
     338    }
     339    return rc;
     340}
     341
     342
     343/**
    229344 * Closes an handled open by rtNtPathOpen.
    230345 *
注意: 瀏覽 TracChangeset 來幫助您使用更動檢視器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette