- Timestamp:
- Jul 20, 2015 1:06:56 PM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp
r56290 r57020 313 313 { 314 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. 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. 317 333 */ 318 334 pThis->enmInfoClass = FileIdBothDirectoryInformation; … … 328 344 pThis->pNtFilterStr, 329 345 FALSE /*RestartScan */); 330 if (!NT_SUCCESS(rcNt)) 346 if (NT_SUCCESS(rcNt)) 347 { /* likely */ } 348 else 331 349 { 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 } 344 396 } 345 397 }
Note:
See TracChangeset
for help on using the changeset viewer.