VirtualBox

Changeset 57020 in vbox for trunk


Ignore:
Timestamp:
Jul 20, 2015 1:06:56 PM (9 years ago)
Author:
vboxsync
Message:

direnum-r3-nt.cpp: Workaround for windows CIFS servers with directories containing lots of files, they don't like large buffers (limit seems to be 64KB).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp

    r56290 r57020  
    313313    {
    314314        /*
    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.
     315         * The first time around we have to figure which info class we can use
     316         * as well as the right buffer size.  We prefer an info class which
     317         * gives us file IDs (Vista+ IIRC) and we prefer large buffers (for long
     318         * ReFS file names and such), but we'll settle for whatever works...
     319         *
     320         * The windows 7 thru 8.1 CIFS servers have been observed to have
     321         * trouble with large buffers, but weirdly only when listing large
     322         * directories.  Seems 0x10000 is the max.  (Samba does not exhibit
     323         * these problems, of course.)
     324         *
     325         * This complicates things.  The buffer size issues causes an
     326         * STATUS_INVALID_PARAMETER error.  Now, you would expect the lack of
     327         * FileIdBothDirectoryInformation support to return
     328         * STATUS_INVALID_INFO_CLASS, but I'm not entirely sure if we can 100%
     329         * depend on third IFSs to get that right.  Nor, am I entirely confident
     330         * that we can depend on them to check the class before the buffer size.
     331         *
     332         * Thus the mess.
    317333         */
    318334        pThis->enmInfoClass = FileIdBothDirectoryInformation;
     
    328344                                    pThis->pNtFilterStr,
    329345                                    FALSE /*RestartScan */);
    330         if (!NT_SUCCESS(rcNt))
     346        if (NT_SUCCESS(rcNt))
     347        { /* likely */ }
     348        else
    331349        {
    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 */);
     350            for (unsigned iRetry = 0; iRetry < 2; iRetry++)
     351            {
     352                if (   rcNt == STATUS_INVALID_INFO_CLASS
     353                    || rcNt == STATUS_INVALID_PARAMETER_8
     354                    || iRetry != 0)
     355                    pThis->enmInfoClass = FileBothDirectoryInformation;
     356
     357                uint32_t cbBuffer = pThis->cbBufferAlloc;
     358                if (   rcNt == STATUS_INVALID_PARAMETER
     359                    || rcNt == STATUS_INVALID_PARAMETER_7
     360                    || iRetry != 0)
     361                    cbBuffer = RT_MIN(cbBuffer / 2, 0x10000);
     362
     363                for (;;)
     364                {
     365                    rcNt = NtQueryDirectoryFile(pThis->hDir,
     366                                                NULL /* Event */,
     367                                                NULL /* ApcRoutine */,
     368                                                NULL /* ApcContext */,
     369                                                &Ios,
     370                                                pThis->pabBuffer,
     371                                                cbBuffer,
     372                                                pThis->enmInfoClass,
     373                                                RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
     374                                                pThis->pNtFilterStr,
     375                                                FALSE /*RestartScan */);
     376                    if (   NT_SUCCESS(rcNt)
     377                        || cbBuffer == pThis->cbBufferAlloc
     378                        || cbBuffer <= sizeof(*pThis->uCurData.pBothId) + sizeof(WCHAR) * 260)
     379                        break;
     380
     381                    /* Reduce the buffer size agressivly and try again.  We fall back to
     382                       FindFirstFile values for the final lap.  This means we'll do 4 rounds
     383                       with the current initial buffer size (64KB, 8KB, 1KB, 0x278/0x268). */
     384                    cbBuffer /= 8;
     385                    if (cbBuffer < 1024)
     386                        cbBuffer = pThis->enmInfoClass == FileIdBothDirectoryInformation
     387                                 ? sizeof(*pThis->uCurData.pBothId) + sizeof(WCHAR) * 260
     388                                 : sizeof(*pThis->uCurData.pBoth)   + sizeof(WCHAR) * 260;
     389                }
     390                if (NT_SUCCESS(rcNt))
     391                {
     392                    pThis->cbBufferAlloc = cbBuffer;
     393                    break;
     394                }
     395            }
    344396        }
    345397    }
Note: See TracChangeset for help on using the changeset viewer.

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