Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

877 lines
24 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name :
  4. getdirp.cxx
  5. Abstract:
  6. This module implements the functions for getting directory listings
  7. and transparently caching them.
  8. ( This uses OS specific functions to obtain the directory).
  9. Author:
  10. Murali R. Krishnan ( MuraliK ) 13-Jan-1995
  11. Project:
  12. Tsunami Lib
  13. ( Common caching and directory functions for Internet Services)
  14. Functions Exported:
  15. BOOL TsGetDirectoryListing()
  16. BOOL TsFreeDirectoryListing()
  17. int __cdecl
  18. AlphaCompareFileBothDirInfo(
  19. IN const void * pvFileInfo1,
  20. IN const void * pvFileInfo2)
  21. TS_DIRECTORY_HEADER::ReadWin32DirListing( IN LPCSTR pszDirectoryName)
  22. TS_DIRECTORY_HEADER::ReadFromNtDirectoryFile(
  23. IN LPCWSTR pwszDirectoryName
  24. )
  25. TS_DIRECTORY_HEADER::BuildFileInfoPointers(
  26. IN LPCWSTR pwszDirectoryName
  27. )
  28. TS_DIRECTORY_HEADER::CleanupThis()
  29. Revision History:
  30. MuraliK 06-Dec-1995 Used Win32 apis instead of NT apis
  31. MCourage 09-Jan-1998 Stopped caching directory information
  32. Removed "guardian blobs"
  33. --*/
  34. /************************************************************
  35. * Include Headers
  36. ************************************************************/
  37. # include "tsunamip.hxx"
  38. # include <stdlib.h>
  39. # include <string.h>
  40. # include <dbgutil.h>
  41. /************************************************************
  42. * Type Definitions
  43. ************************************************************/
  44. # define DBGCODE(s) DBG_CODE(s)
  45. #define DIRECTORY_BUFFER_SIZE 8160 /* < 8192 bytes */
  46. /************************************************************
  47. * Functions
  48. ************************************************************/
  49. BOOL FreeDirectoryHeaderContents( PVOID pvOldBlock );
  50. PTS_DIRECTORY_HEADER
  51. TsGetFreshDirectoryHeader(
  52. IN const TSVC_CACHE & tsCache,
  53. IN LPCSTR pszDirectoryName,
  54. IN HANDLE hLisingUser);
  55. dllexp
  56. BOOL
  57. TsGetDirectoryListing(
  58. IN const TSVC_CACHE &tsCache,
  59. IN PCSTR pszDirectoryName,
  60. IN HANDLE hListingUser,
  61. OUT PTS_DIRECTORY_HEADER * ppTsDirectoryHeader
  62. )
  63. /*++
  64. This function obtains the directory listing for dir specified
  65. in pszDirectoryName.
  66. Arguments:
  67. tsCache Cache structure which is used for lookup
  68. pszDirectoryName pointer to string containing the directory name
  69. ListingUser Handle for the user opening the directory
  70. ppTsDirectoryHeader
  71. pointer to pointer to class containing directory information.
  72. Filled on successful return. On failure this will be NULL
  73. Returns:
  74. TRUE on success and FALSE if there is a failure.
  75. --*/
  76. {
  77. PVOID pvBlob = NULL;
  78. ULONG ulSize = 0;
  79. BOOL bSuccess;
  80. ASSERT( pszDirectoryName != NULL );
  81. ASSERT( ppTsDirectoryHeader != NULL);
  82. //
  83. // First, check to see if we have already cached a listing of this
  84. // directory.
  85. //
  86. *ppTsDirectoryHeader = NULL;
  87. //
  88. // Dont try to cache directory listings
  89. //
  90. // bSuccess = TsCheckOutCachedBlob( tsCache,
  91. // pszDirectoryName,
  92. // RESERVED_DEMUX_DIRECTORY_LISTING,
  93. // ( PVOID * )&pvBlob,
  94. // &ulSize );
  95. bSuccess = FALSE;
  96. //
  97. // The block was not present in cache.
  98. // Obtain a fresh copy of the directory listing and cache it.
  99. //
  100. IF_DEBUG( DIR_LIST) {
  101. DBGPRINTF( (DBG_CONTEXT,
  102. "Missing DirListing (%s) in cache. Generating newly\n",
  103. pszDirectoryName));
  104. }
  105. *ppTsDirectoryHeader = TsGetFreshDirectoryHeader(
  106. tsCache,
  107. pszDirectoryName,
  108. hListingUser );
  109. bSuccess = ( *ppTsDirectoryHeader != NULL);
  110. IF_DEBUG( DIR_LIST) {
  111. DBGCODE(
  112. CHAR pchBuff[600];
  113. wsprintfA( pchBuff,
  114. "Obtained DirListing (%s). NEntries = %d\n",
  115. pszDirectoryName,
  116. (*ppTsDirectoryHeader)->QueryNumEntries());
  117. OutputDebugString( pchBuff);
  118. );
  119. }
  120. return ( bSuccess);
  121. } // TsGetDirectoryListing()
  122. dllexp
  123. BOOL
  124. TsFreeDirectoryListing
  125. (
  126. IN const TSVC_CACHE & tsCache,
  127. IN PTS_DIRECTORY_HEADER pDirectoryHeader
  128. )
  129. {
  130. BOOL fReturn;
  131. BOOL fCached = pDirectoryHeader->IsCached;
  132. IF_DEBUG( DIR_LIST) {
  133. DBGPRINTF( ( DBG_CONTEXT,
  134. "TsFreeDirectoryListing( %08p) called. Cached = %d\n",
  135. pDirectoryHeader,
  136. fCached));
  137. pDirectoryHeader->Print();
  138. }
  139. if ( fCached )
  140. {
  141. fReturn = TsCheckInCachedBlob( ( PVOID )pDirectoryHeader );
  142. }
  143. else
  144. {
  145. fReturn = TsFree( tsCache, ( PVOID )pDirectoryHeader );
  146. }
  147. return( fReturn);
  148. } // TsFreeDirectoryListing()
  149. PTS_DIRECTORY_HEADER
  150. TsGetFreshDirectoryHeader(
  151. IN const TSVC_CACHE & tsCache,
  152. IN LPCSTR pszDirectoryName,
  153. IN HANDLE hListingUser)
  154. /*++
  155. This function obtains a fresh copy of the directory listing for the
  156. directory specified and caches it if possible, before returning pointer
  157. to the directory information.
  158. Returns:
  159. On success it returns the pointer to newly constructed directory listing.
  160. On failure this returns a NULL
  161. --*/
  162. {
  163. PTS_DIRECTORY_HEADER pDirectoryHeader;
  164. PVOID pvGuardBlob;
  165. BOOL bSuccess;
  166. BOOL bCachedGuardianBlob;
  167. #ifdef TS_USE_DIRECTORY_GUARD
  168. //
  169. // If we are going to cache this directory, we would like to increase the
  170. // likelihood that it is an "atomic" snapshot. This is done as follows:
  171. //
  172. // We cache and hold checked-out a small blob while create the directory
  173. // listing. If that Blob (1) could not be cached, or (2) was ejected
  174. // from the cache while we were generating a listing, then we do not
  175. // attempt to cache the directory.
  176. //
  177. // Reasoning:
  178. //
  179. // 1) If the Blob couldn't be cached then the directory info won't be any
  180. // different.
  181. //
  182. // 2) If the Blob was ejected, the directory must have changed while we
  183. // were reading it. If this happens, we don't want to cache possibly
  184. // inconsistent data.
  185. //
  186. // If the directory changed and the Blob has not yet been ejected, the
  187. // directory will soon be ejected anyway. Notice that the Blob is not
  188. // DeCache()'d until after the directory has been cached.
  189. //
  190. if ( !TsAllocate( tsCache, sizeof( TS_DIRECTORY_HEADER),
  191. (PVOID *) &pvGuardBlob)) {
  192. //
  193. // Failure to allocate and secure a guardian blob.
  194. //
  195. IF_DEBUG( DIR_LIST) {
  196. DBGPRINTF( (DBG_CONTEXT,
  197. "Allocation of Guardianblob for %s failed. Error=%d\n",
  198. pszDirectoryName, GetLastError()));
  199. }
  200. return ( NULL);
  201. }
  202. //
  203. // A successful guardian block allocated. Try and cache it.
  204. //
  205. ULONG cchDirectoryName = strlen(pszDirectoryName);
  206. bCachedGuardianBlob = TsCacheDirectoryBlob(
  207. tsCache,
  208. pszDirectoryName,
  209. cchDirectoryName,
  210. RESERVED_DEMUX_ATOMIC_DIRECTORY_GUARD,
  211. pvGuardBlob,
  212. TRUE );
  213. if ( !bCachedGuardianBlob ) {
  214. BOOL fFreed;
  215. //
  216. // Already there is one such cached blob. ignore this blob.
  217. // So free up the space used.
  218. //
  219. fFreed = TsFree( tsCache, pvGuardBlob );
  220. ASSERT( fFreed);
  221. pvGuardBlob = NULL;
  222. }
  223. #endif // TS_USE_DIRECTORY_GUARD
  224. //
  225. // Allocate space for Directory listing
  226. //
  227. bSuccess = TsAllocateEx( tsCache,
  228. sizeof( TS_DIRECTORY_HEADER ),
  229. ( PVOID * )&pDirectoryHeader,
  230. FreeDirectoryHeaderContents );
  231. if ( bSuccess) {
  232. BOOL fReadSuccess;
  233. DWORD cbBlob = 0;
  234. ASSERT( pDirectoryHeader != NULL);
  235. pDirectoryHeader->ReInitialize(); // called since we raw alloced space
  236. pDirectoryHeader->SetListingUser( hListingUser);
  237. fReadSuccess = (pDirectoryHeader->ReadWin32DirListing(pszDirectoryName,
  238. &cbBlob ) &&
  239. pDirectoryHeader->BuildFileInfoPointers( &cbBlob )
  240. );
  241. if ( fReadSuccess) {
  242. #if TS_USE_DIRECTORY_GUARD
  243. //
  244. // Attempt and cache the blob if the blob size is cacheable
  245. //
  246. if ( bCachedGuardianBlob &&
  247. !BLOB_IS_EJECTATE( pvGuardBlob ) ) {
  248. ASSERT( BLOB_IS_OR_WAS_CACHED( pvGuardBlob ) );
  249. bSuccess =
  250. TsCacheDirectoryBlob(tsCache,
  251. pszDirectoryName,
  252. cchDirectoryName,
  253. RESERVED_DEMUX_DIRECTORY_LISTING,
  254. pDirectoryHeader,
  255. TRUE );
  256. if ( bSuccess ) {
  257. INC_COUNTER( tsCache.GetServiceId(), CurrentDirLists );
  258. }
  259. //
  260. // Even if caching of the blob failed, that is okay!
  261. //
  262. if ( bSuccess && BLOB_IS_EJECTATE( pvGuardBlob ) ) {
  263. TsExpireCachedBlob( tsCache, pDirectoryHeader );
  264. }
  265. }
  266. #endif // TS_USE_DIRECTORY_GUARD
  267. } else {
  268. //
  269. // Reading directory failed.
  270. // cleanup directory related data and get out.
  271. //
  272. BOOL fFreed = TsFree( tsCache, pDirectoryHeader);
  273. ASSERT( fFreed);
  274. pDirectoryHeader = NULL;
  275. bSuccess = FALSE;
  276. }
  277. } else {
  278. //
  279. // Allocation of Directory Header failed.
  280. //
  281. ASSERT( pDirectoryHeader == NULL);
  282. }
  283. #if TS_USE_DIRECTORY_GUARD
  284. // Free up the guardian block and exit.
  285. if ( bCachedGuardianBlob) {
  286. bSuccess = TsExpireCachedBlob( tsCache, pvGuardBlob );
  287. ASSERT( bSuccess );
  288. bSuccess = TsCheckInCachedBlob( pvGuardBlob );
  289. ASSERT( bSuccess );
  290. pvGuardBlob = NULL;
  291. }
  292. ASSERT( pvGuardBlob == NULL);
  293. #endif // TS_USE_DIRECTORY_GUARD
  294. return ( pDirectoryHeader);
  295. } // TsGetFreshDirectoryHeader
  296. BOOL
  297. FreeDirectoryHeaderContents( PVOID pvOldBlock )
  298. {
  299. PTS_DIRECTORY_HEADER pDirectoryHeader;
  300. pDirectoryHeader = ( PTS_DIRECTORY_HEADER )pvOldBlock;
  301. pDirectoryHeader->CleanupThis();
  302. //
  303. // The item may never have been added to the cache, don't
  304. // count it in this case
  305. //
  306. //
  307. // We're never caching dir blobs now
  308. //
  309. // if ( BLOB_IS_OR_WAS_CACHED( pvOldBlock ) ) {
  310. //
  311. // DEC_COUNTER( BLOB_GET_SVC_ID( pvOldBlock ), CurrentDirLists );
  312. // }
  313. return ( TRUE);
  314. } // FreeDirectoryHeaderContents()
  315. int __cdecl
  316. AlphaCompareFileBothDirInfo(
  317. IN const void * pvFileInfo1,
  318. IN const void * pvFileInfo2)
  319. {
  320. const WIN32_FIND_DATA * pFileInfo1 =
  321. *((const WIN32_FIND_DATA **) pvFileInfo1);
  322. const WIN32_FIND_DATA * pFileInfo2 =
  323. *((const WIN32_FIND_DATA **) pvFileInfo2);
  324. ASSERT( pFileInfo1 != NULL && pFileInfo2 != NULL);
  325. return ( lstrcmp( (LPCSTR )pFileInfo1->cFileName,
  326. (LPCSTR )pFileInfo2->cFileName));
  327. } // AlphaCompareFileBothDirInfo()
  328. BOOL
  329. SortInPlaceFileInfoPointers(
  330. IN OUT PWIN32_FIND_DATA * prgFileInfo,
  331. IN int nEntries,
  332. IN PFN_CMP_WIN32_FIND_DATA pfnCompare)
  333. /*++
  334. This is a generic function to sort the pointers to file information
  335. array in place using pfnCompare to compare the records for ordering.
  336. Returns:
  337. TRUE on success and FALSE on failure.
  338. --*/
  339. {
  340. DWORD dwTime;
  341. IF_DEBUG( DIR_LIST) {
  342. DBGPRINTF( ( DBG_CONTEXT,
  343. "Qsorting the FileInfo Array %08p ( Total = %d)\n",
  344. prgFileInfo, nEntries));
  345. dwTime = GetTickCount();
  346. }
  347. qsort( (PVOID ) prgFileInfo, nEntries,
  348. sizeof( PWIN32_FIND_DATA),
  349. pfnCompare);
  350. IF_DEBUG( DIR_LIST) {
  351. dwTime = GetTickCount() - dwTime;
  352. DBGPRINTF( ( DBG_CONTEXT,
  353. " Time to sort %d entries = %d\n",
  354. nEntries, dwTime));
  355. }
  356. return ( TRUE);
  357. } // SortInPlaceFileInfoPointers()
  358. /**********************************************************************
  359. * TS_DIRECTORY_HEADER related member functions
  360. **********************************************************************/
  361. const char PSZ_DIR_STAR_STAR[] = "*.*";
  362. # define LEN_PSZ_DIR_STAR_STAR ( sizeof(PSZ_DIR_STAR_STAR)/sizeof(CHAR))
  363. BOOL
  364. TS_DIRECTORY_HEADER::ReadWin32DirListing(
  365. IN LPCSTR pszDirectoryName,
  366. IN OUT DWORD * pcbMemUsed
  367. )
  368. /*++
  369. Opens and reads the directory file for given directory to obtain
  370. information about files and directories in the dir.
  371. Arguments:
  372. pszDirectoryName - pointer to string containing directory name
  373. with a terminating "\".
  374. pcbMemUsed - pointer to DWORD which on successful return
  375. will contain the memory used.
  376. Returns:
  377. TRUE on success and FALSE on failure.
  378. Use GetLastError() for further error information.
  379. --*/
  380. {
  381. BOOL fReturn = TRUE; // default assumed.
  382. CHAR pchFullPath[MAX_PATH*2];
  383. HANDLE hFindFile = INVALID_HANDLE_VALUE;
  384. BOOL fFirstTime;
  385. DWORD cbExtraMem = 0;
  386. DWORD dwError = NO_ERROR;
  387. PWIN32_FIND_DATA pFileInfo = NULL;
  388. PTS_DIR_BUFFERS pTsDirBuffers = NULL;
  389. DWORD startCount;
  390. DBGCODE( CHAR pchBuff[300];
  391. );
  392. DBG_ASSERT( pszDirectoryName != NULL);
  393. if ( strlen(pszDirectoryName) > MAX_PATH*2 - LEN_PSZ_DIR_STAR_STAR) {
  394. return ( ERROR_PATH_NOT_FOUND);
  395. }
  396. wsprintfA( pchFullPath, "%s%s", pszDirectoryName, PSZ_DIR_STAR_STAR);
  397. InitializeListHead( &m_listDirectoryBuffers);
  398. //
  399. // Get the next chunk of directory information.
  400. //
  401. pTsDirBuffers = (PTS_DIR_BUFFERS ) ALLOC( sizeof(TS_DIR_BUFFERS));
  402. if ( pTsDirBuffers == NULL ) {
  403. //
  404. // Allocation failure.
  405. //
  406. SetLastError( ERROR_NOT_ENOUGH_MEMORY);
  407. fReturn = FALSE;
  408. goto Failure;
  409. }
  410. cbExtraMem += sizeof(TS_DIR_BUFFERS);
  411. // insert the buffer into the list so that it may be freed later.
  412. InsertBufferInTail( &pTsDirBuffers->listEntry);
  413. pTsDirBuffers->nEntries = 0;
  414. pFileInfo = (PWIN32_FIND_DATA ) pTsDirBuffers->rgFindData;
  415. hFindFile = FindFirstFile( pchFullPath, pFileInfo);
  416. if ( hFindFile == INVALID_HANDLE_VALUE) {
  417. dwError = GetLastError();
  418. IF_DEBUG( DIR_LIST) {
  419. DBGPRINTF(( DBG_CONTEXT,
  420. "FindFirstFile(%s, %08p) failed. Error = %d\n",
  421. pchFullPath, pFileInfo, dwError));
  422. }
  423. fReturn = FALSE;
  424. goto Failure;
  425. }
  426. IF_DEBUG( DIR_LIST) {
  427. DBGCODE(
  428. wsprintf( pchBuff, "-%d-[%d](%08p) %s(%s)\t%08x\n",
  429. MAX_DIR_ENTRIES_PER_BLOCK,
  430. 0,
  431. pFileInfo,
  432. pFileInfo->cFileName, pFileInfo->cAlternateFileName,
  433. pFileInfo->dwFileAttributes);
  434. OutputDebugString( pchBuff);
  435. );
  436. }
  437. pFileInfo++;
  438. IncrementDirEntries();
  439. pTsDirBuffers->nEntries++;
  440. startCount = 1;
  441. // atleast 10 to justify overhead
  442. DBG_ASSERT( MAX_DIR_ENTRIES_PER_BLOCK > 10);
  443. //
  444. // Loop through getting subsequent entries in the directory.
  445. //
  446. for( dwError = NO_ERROR; dwError == NO_ERROR; ) {
  447. // loop thru and get a block of items
  448. for( int i = startCount; i < MAX_DIR_ENTRIES_PER_BLOCK; i++ ) {
  449. if ( !FindNextFile( hFindFile, pFileInfo)) {
  450. dwError = GetLastError();
  451. if ( dwError != ERROR_NO_MORE_FILES) {
  452. DBGPRINTF(( DBG_CONTEXT,
  453. "FindNextFile(%s(%08p), %08p) failed."
  454. " Error = %d\n",
  455. pchFullPath, hFindFile, pFileInfo,
  456. dwError));
  457. fReturn = FALSE;
  458. goto Failure;
  459. } else {
  460. break;
  461. }
  462. }
  463. IF_DEBUG( DIR_LIST) {
  464. DBGCODE(
  465. wsprintf( pchBuff, "[%d](%08p) %s(%s)\t%08x\n",
  466. i, pFileInfo,
  467. pFileInfo->cFileName,
  468. pFileInfo->cAlternateFileName,
  469. pFileInfo->dwFileAttributes);
  470. OutputDebugString( pchBuff);
  471. );
  472. }
  473. IncrementDirEntries();
  474. pFileInfo++;
  475. } // for all elements that fit in this block
  476. pTsDirBuffers->nEntries = i;
  477. if ( dwError == ERROR_NO_MORE_FILES) {
  478. //
  479. // info on all entries in a directory obtained. Return back.
  480. //
  481. dwError = NO_ERROR;
  482. break;
  483. } else {
  484. //
  485. // The buffer contains directory entries and is full now.
  486. // Update the count of entries in this buffer and
  487. // Allocate a new buffer and set the start counts properly.
  488. //
  489. IF_DEBUG( DIR_LIST) {
  490. DBGCODE( OutputDebugString( " Allocating Next Chunck\n"););
  491. }
  492. pTsDirBuffers = (PTS_DIR_BUFFERS ) ALLOC(sizeof(TS_DIR_BUFFERS));
  493. if ( pTsDirBuffers == NULL ) {
  494. //
  495. // Allocation failure.
  496. //
  497. dwError = ERROR_NOT_ENOUGH_MEMORY;
  498. fReturn = FALSE;
  499. break; // Get out of the loop with failure.
  500. }
  501. cbExtraMem += sizeof(TS_DIR_BUFFERS);
  502. // insert the buffer into the list so that it may be freed later.
  503. InsertBufferInTail( &pTsDirBuffers->listEntry);
  504. pTsDirBuffers->nEntries = 0;
  505. pFileInfo = ( PWIN32_FIND_DATA ) pTsDirBuffers->rgFindData;
  506. startCount = 0; // start count from zero items on this buffer page
  507. }
  508. } // for all directory entries
  509. Failure:
  510. if ( hFindFile != INVALID_HANDLE_VALUE) {
  511. DBG_REQUIRE( FindClose( hFindFile ));
  512. hFindFile = INVALID_HANDLE_VALUE;
  513. }
  514. *pcbMemUsed += cbExtraMem;
  515. return ( fReturn);
  516. } // TS_DIRECTORY_HEADER::ReadWin32DirListing()
  517. VOID
  518. TS_DIRECTORY_HEADER::CleanupThis( VOID)
  519. {
  520. PLIST_ENTRY pEntry;
  521. PLIST_ENTRY pNextEntry;
  522. for ( pEntry = QueryDirBuffersListEntry()->Flink;
  523. pEntry != QueryDirBuffersListEntry();
  524. pEntry = pNextEntry )
  525. {
  526. PTS_DIR_BUFFERS pTsDirBuffer =
  527. CONTAINING_RECORD( pEntry, TS_DIR_BUFFERS, listEntry);
  528. // cache the next block pointer.
  529. pNextEntry = pEntry->Flink;
  530. // remove the current block from list.
  531. RemoveEntryList( pEntry);
  532. // delete the current block.
  533. FREE( pTsDirBuffer );
  534. }
  535. InitializeListHead( QueryDirBuffersListEntry());
  536. if ( m_ppFileInfo != NULL) {
  537. FREE( m_ppFileInfo);
  538. m_ppFileInfo = NULL;
  539. }
  540. m_hListingUser = INVALID_HANDLE_VALUE;
  541. m_nEntries = 0;
  542. return;
  543. } // TS_DIRECTORY_HEADER::CleanupThis()
  544. BOOL
  545. TS_DIRECTORY_HEADER::BuildFileInfoPointers(
  546. IN OUT DWORD * pcbMemUsed
  547. )
  548. /*++
  549. This constructs the indirection pointers from the buffers containing the
  550. file information.
  551. This array of indirection enables faster access to the file information
  552. structures stored.
  553. Should be always called after ReadFromNtDirectoryFile() to construct the
  554. appropriate pointers.
  555. Returns:
  556. TRUE on success and FALSE if there are any failures.
  557. --*/
  558. {
  559. BOOL fReturn = FALSE;
  560. DWORD cbAlloc;
  561. int maxIndex;
  562. maxIndex = QueryNumEntries();
  563. ASSERT( maxIndex != 0); // Any directory will atleast have "."
  564. //
  565. // Alloc space for holding the pointers for numEntries pointers.
  566. //
  567. cbAlloc = maxIndex * sizeof( PWIN32_FIND_DATA );
  568. m_ppFileInfo = (PWIN32_FIND_DATA *) ALLOC( cbAlloc );
  569. if ( m_ppFileInfo != NULL ) {
  570. int index;
  571. PLIST_ENTRY pEntry;
  572. PTS_DIR_BUFFERS pTsDirBuffers;
  573. PWIN32_FIND_DATA pFileInfo;
  574. //
  575. // Get the link to first buffer and start enumeration.
  576. //
  577. for( pEntry = QueryDirBuffersListEntry()->Flink, index = 0;
  578. pEntry != QueryDirBuffersListEntry();
  579. pEntry = pEntry->Flink
  580. ) {
  581. pTsDirBuffers = CONTAINING_RECORD( pEntry, TS_DIR_BUFFERS,
  582. listEntry);
  583. pFileInfo = pTsDirBuffers->rgFindData;
  584. for (int i = 0;
  585. i < pTsDirBuffers->nEntries;
  586. i++ ) {
  587. m_ppFileInfo[index++] = pFileInfo; // store the pointer.
  588. IF_DEBUG( DIR_LIST) {
  589. DBGCODE(
  590. CHAR pchBuff[300];
  591. wsprintf( pchBuff, "[%d](%08p) %s(%s)\t%08x\n",
  592. index, pFileInfo,
  593. pFileInfo->cFileName,
  594. pFileInfo->cAlternateFileName,
  595. pFileInfo->dwFileAttributes);
  596. OutputDebugString( pchBuff);
  597. );
  598. }
  599. pFileInfo++;
  600. } // for all elements in a buffer
  601. } // for ( all buffers in the list)
  602. ASSERT( index == maxIndex);
  603. fReturn = SortInPlaceFileInfoPointers( m_ppFileInfo,
  604. maxIndex,
  605. AlphaCompareFileBothDirInfo);
  606. } // valid alloc of the pointers.
  607. *pcbMemUsed += cbAlloc;
  608. return ( fReturn);
  609. } // TS_DIRECTORY_HEADER::BuildFileInfoPointers()
  610. # if DBG
  611. VOID
  612. TS_DIRECTORY_HEADER::Print( VOID) const
  613. {
  614. DBGPRINTF( ( DBG_CONTEXT,
  615. "Printing TS_DIRECTORY_HEADER ( %08p).\n"
  616. "ListingUser Handle = %08p\t Num Entries = %08x\n"
  617. "Pointer to array of indirection pointers %08p\n",
  618. this,
  619. m_hListingUser, m_nEntries,
  620. m_ppFileInfo));
  621. //
  622. // The buffers containing the data of the file information not printed
  623. //
  624. return;
  625. } // TS_DIRECTORY_HEADER::Print()
  626. # endif // DBG
  627. /************************ End of File ***********************/
  628. 
  629.