mirror of https://github.com/tongzx/nt5src
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.
830 lines
22 KiB
830 lines
22 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name :
|
|
|
|
getdirp.cxx
|
|
|
|
Abstract:
|
|
This module implements the functions for getting directory listings
|
|
and transparently caching them.
|
|
( This uses OS specific functions to obtain the directory).
|
|
|
|
Author:
|
|
|
|
Murali R. Krishnan ( MuraliK ) 13-Jan-1995
|
|
|
|
Project:
|
|
|
|
Tsunami Lib
|
|
( Common caching and directory functions for Internet Services)
|
|
|
|
Functions Exported:
|
|
BOOL TsGetDirectoryListingA()
|
|
BOOL TsFreeDirectoryListing()
|
|
int __cdecl
|
|
AlphaCompareFileBothDirInfo(
|
|
IN const void * pvFileInfo1,
|
|
IN const void * pvFileInfo2)
|
|
|
|
TS_DIRECTORY_HEADER::ReadFromNtDirectoryFile(
|
|
IN LPCWSTR pwszDirectoryName
|
|
)
|
|
TS_DIRECTORY_HEADER::BuildInfoPointers(
|
|
IN LPCWSTR pwszDirectoryName
|
|
)
|
|
TS_DIRECTORY_HEADER::CleanupThis()
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
/************************************************************
|
|
* Include Headers
|
|
************************************************************/
|
|
|
|
# include "tsunamip.hxx"
|
|
|
|
# include <stdlib.h>
|
|
# include <string.h>
|
|
# include <dbgutil.h>
|
|
|
|
/************************************************************
|
|
* Type Definitions
|
|
************************************************************/
|
|
|
|
|
|
#define DIRECTORY_BUFFER_SIZE 8160 /* < 8192 bytes */
|
|
|
|
/************************************************************
|
|
* Functions
|
|
************************************************************/
|
|
|
|
|
|
BOOL FreeDirectoryHeaderContents( PVOID pvOldBlock );
|
|
|
|
|
|
dllexp
|
|
BOOL
|
|
TsGetDirectoryListing(
|
|
IN const TSVC_CACHE &tsCache,
|
|
IN PCSTR pszDirectoryName,
|
|
IN HANDLE ListingUser,
|
|
OUT PTS_DIRECTORY_HEADER * ppTsDirectoryHeader
|
|
)
|
|
/*++
|
|
This function obtains the directory listing for dir specified
|
|
in pszDirectoryName.
|
|
|
|
Arguments:
|
|
tsCache Cache structure which is used for lookup
|
|
pwszDirectoryName pointer to string containing the directory name
|
|
ListingUser Handle for the user opening the directory
|
|
ppTsDirectoryHeader
|
|
pointer to pointer to class containing directory information.
|
|
Filled on successful return. On failure this will be NULL
|
|
|
|
Returns:
|
|
TRUE on success and FALSE if there is a failure.
|
|
--*/
|
|
{
|
|
ASSERT( tsCache.IsValid() );
|
|
ASSERT( pszDirectoryName != NULL );
|
|
ASSERT( ppTsDirectoryHeader != NULL);
|
|
|
|
PVOID pvBlob = NULL;
|
|
ULONG ulSize = 0;
|
|
BOOL bSuccess;
|
|
|
|
//
|
|
// First, check to see if we have already cached a listing of this
|
|
// directory.
|
|
//
|
|
|
|
*ppTsDirectoryHeader = NULL;
|
|
bSuccess = TsCheckOutCachedBlob( tsCache,
|
|
pszDirectoryName,
|
|
RESERVED_DEMUX_DIRECTORY_LISTING,
|
|
( PVOID * )&pvBlob,
|
|
&ulSize );
|
|
|
|
if ( bSuccess )
|
|
{
|
|
ASSERT( BLOB_IS_OR_WAS_CACHED( pvBlob ) );
|
|
|
|
*ppTsDirectoryHeader = (PTS_DIRECTORY_HEADER )pvBlob;
|
|
ASSERT ( (*ppTsDirectoryHeader)->IsValid());
|
|
|
|
//
|
|
// Make sure the user tokens match
|
|
//
|
|
|
|
if ( hListingUser == (*ppTsDirectoryHeader)->QueryListingUser() )
|
|
{
|
|
IF_DEBUG( DIR_LIST) {
|
|
|
|
DBGPRINTF( (DBG_CONTEXT,
|
|
" Obtained DirectoryListing (%s) from Cache ( %08x)\n",
|
|
pszDirectoryName,
|
|
*ppTsDirectoryHeader));
|
|
|
|
(*ppTsDirectoryHeader)->Print();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// User token doesn't match, don't return it
|
|
//
|
|
|
|
bSuccess = TsCheckInCachedBlob( pvBlob );
|
|
|
|
ASSERT( bSuccess );
|
|
}
|
|
|
|
//
|
|
// The block was not present in cache.
|
|
// Obtain a fresh copy of the directory listing and cache it.
|
|
//
|
|
|
|
IF_DEBUG( DIR_LIST) {
|
|
|
|
DBGPRINTF( (DBG_CONTEXT,
|
|
"Missing DirListing (%s) in cache. Generating newly\n",
|
|
pszDirectoryName));
|
|
}
|
|
|
|
*ppTsDirectoryHeader = TsGetFreshDirectoryHeader(
|
|
tsCache,
|
|
pszDirectoryName,
|
|
hListingUser );
|
|
|
|
|
|
bSuccess = ( *ppTsDirectoryHeader != NULL);
|
|
|
|
return ( bSuccess);
|
|
|
|
} // TsGetDirectoryListing
|
|
|
|
|
|
|
|
|
|
dllexp
|
|
BOOL
|
|
TsFreeDirectoryListing(
|
|
IN const TSVC_CACHE & tsCache,
|
|
IN PTS_DIRECTORY_HEADER pDirectoryHeader
|
|
)
|
|
{
|
|
BOOL fReturn;
|
|
BOOL fCached = BLOB_IS_OR_WAS_CACHED( (PVOID ) pDirectoryHeader);
|
|
|
|
IF_DEBUG( DIR_LIST) {
|
|
|
|
DBGPRINTF( ( DBG_CONTEXT,
|
|
"TsFreeDirectoryListing( %08x) called. Cached = %d\n",
|
|
pDirectoryHeader,
|
|
fCached));
|
|
|
|
pDirectoryHeader->Print();
|
|
}
|
|
|
|
if ( fCached )
|
|
{
|
|
fReturn = TsCheckInCachedBlob( ( PVOID )pDirectoryHeader );
|
|
}
|
|
else
|
|
{
|
|
fReturn = TsFree( tsCache, ( PVOID )pDirectoryHeader );
|
|
}
|
|
|
|
return( fReturn);
|
|
} // TsFreeDirectoryListing()
|
|
|
|
|
|
|
|
BOOL
|
|
FreeDirectoryHeaderContents(
|
|
PVOID pvOldBlock
|
|
)
|
|
{
|
|
PTS_DIRECTORY_HEADER pDirectoryHeader;
|
|
|
|
pDirectoryHeader = ( PTS_DIRECTORY_HEADER )pvOldBlock;
|
|
|
|
pDirectoryHeader->CleanupThis();
|
|
|
|
//
|
|
// The item may never have been added to the cache, don't
|
|
// count it in this case
|
|
//
|
|
|
|
if ( BLOB_IS_OR_WAS_CACHED( pvOldBlock ) )
|
|
{
|
|
DEC_COUNTER( BLOB_GET_SVC_ID( pvOldBlock ),
|
|
CurrentDirLists );
|
|
}
|
|
|
|
return ( TRUE);
|
|
} // FreeDirectoryHeaderContents()
|
|
|
|
|
|
|
|
|
|
int __cdecl
|
|
AlphaCompareFileBothDirInfo(
|
|
IN const void * pvFileInfo1,
|
|
IN const void * pvFileInfo2)
|
|
{
|
|
const FILE_BOTH_DIR_INFORMATION * pFileInfo1 =
|
|
*((const FILE_BOTH_DIR_INFORMATION **) pvFileInfo1);
|
|
const FILE_BOTH_DIR_INFORMATION * pFileInfo2 =
|
|
*((const FILE_BOTH_DIR_INFORMATION **) pvFileInfo2);
|
|
|
|
ASSERT( pFileInfo1 != NULL && pFileInfo2 != NULL);
|
|
|
|
return ( lstrcmp( (LPCSTR )pFileInfo1->FileName,
|
|
(LPCSTR )pFileInfo2->FileName));
|
|
|
|
} // AlphaCompareFileBothDirInfo()
|
|
|
|
|
|
|
|
BOOL
|
|
SortInPlaceFileInfoPointers(
|
|
IN OUT PFILE_BOTH_DIR_INFORMATION * prgFileInfo,
|
|
IN int nEntries,
|
|
IN PFN_CMP_FILE_BOTH_DIR_INFO pfnCompare)
|
|
/*++
|
|
This is a generic function to sort the pointers to file information
|
|
array in place using pfnCompare to compare the records for ordering.
|
|
|
|
Returns:
|
|
TRUE on success and FALSE on failure.
|
|
--*/
|
|
{
|
|
DWORD dwTime;
|
|
|
|
#ifdef INSERTION_SORT
|
|
int idxInner;
|
|
int idxOuter;
|
|
|
|
dwTime = GetTickCount();
|
|
//
|
|
// A simple insertion sort is performed. May be modified in future.
|
|
//
|
|
|
|
for( idxOuter = 1; idxOuter < nEntries; idxOuter++) {
|
|
|
|
for( idxInner = idxOuter; idxInner > 0; idxInner-- ) {
|
|
|
|
int iCmp = ( *pfnCompare)( prgFileInfo[ idxInner - 1],
|
|
prgFileInfo[ idxInner]);
|
|
|
|
if ( iCmp <= 0) {
|
|
//
|
|
// The entries in prgFileInfo[0 .. idxOuter] are in order.
|
|
// Stop bubbling the outer down.
|
|
//
|
|
break;
|
|
} else {
|
|
|
|
//
|
|
// Swap the two entries. idxInner, idxInner - 1
|
|
//
|
|
|
|
PFILE_BOTH_DIR_INFORMATION pFInfoTmp;
|
|
|
|
pFInfoTmp = prgFileInfo[ idxInner - 1];
|
|
prgFileInfo[ idxInner - 1] = prgFileInfo[idxInner];
|
|
prgFileInfo[ idxInner] = pFInfoTmp;
|
|
}
|
|
} // inner for
|
|
|
|
} // for
|
|
|
|
dwTime = GetTickCount() - dwTime;
|
|
|
|
# else
|
|
|
|
IF_DEBUG( DIR_LIST) {
|
|
|
|
DBGPRINTF( ( DBG_CONTEXT,
|
|
"Qsorting the FileInfo Array %08x ( Total = %d)\n",
|
|
prgFileInfo, nEntries));
|
|
}
|
|
|
|
dwTime = GetTickCount();
|
|
qsort( (PVOID ) prgFileInfo, nEntries,
|
|
sizeof( PFILE_BOTH_DIR_INFORMATION),
|
|
pfnCompare);
|
|
|
|
dwTime = GetTickCount() - dwTime;
|
|
|
|
# endif // INSERTION_SORT
|
|
|
|
IF_DEBUG( DIR_LIST) {
|
|
|
|
DBGPRINTF( ( DBG_CONTEXT,
|
|
" Time to sort %d entries = %d\n",
|
|
nEntries, dwTime));
|
|
}
|
|
|
|
return ( TRUE);
|
|
} // SortInPlaceFileInfoPointers()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
* TS_DIRECTORY_HEADER related member functions
|
|
**********************************************************************/
|
|
|
|
inline USHORT
|
|
ConvertUnicodeToAnsiInPlace(
|
|
IN OUT LPWSTR pwszUnicode,
|
|
IN USHORT usLen)
|
|
/*++
|
|
Converts given Unicode strings to Ansi In place and returns the
|
|
length of the modified string.
|
|
--*/
|
|
{
|
|
CHAR achAnsi[MAX_PATH+1];
|
|
DWORD cch;
|
|
|
|
if ( usLen > sizeof(achAnsi) )
|
|
{
|
|
ASSERT( FALSE );
|
|
*pwszUnicode = L'\0';
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// usLen is a byte count and the unicode string isn't terminated
|
|
//
|
|
|
|
cch = WideCharToMultiByte( CP_ACP,
|
|
WC_COMPOSITECHECK,
|
|
pwszUnicode,
|
|
usLen / sizeof(WCHAR),
|
|
achAnsi,
|
|
sizeof( achAnsi ),
|
|
NULL,
|
|
NULL );
|
|
|
|
if ( !cch || (cch + 1) > sizeof( achAnsi ) )
|
|
{
|
|
ASSERT( FALSE );
|
|
*pwszUnicode = L'\0';
|
|
return 0;
|
|
}
|
|
|
|
achAnsi[cch] = '\0';
|
|
|
|
RtlCopyMemory( pwszUnicode, achAnsi, cch + 1 );
|
|
|
|
return (USHORT) cch;
|
|
} // ConvertUnicodeToAnsiInPlace()
|
|
|
|
|
|
|
|
BOOL
|
|
TS_DIRECTORY_HEADER::ReadFromNtDirectoryFile(
|
|
IN LPCWSTR pwszDirectoryName,
|
|
IN OUT DWORD * pcbMemUsed
|
|
)
|
|
/*++
|
|
Opens and reads the directory file for given directory to obtain
|
|
information about files and directories in the dir.
|
|
|
|
Returns:
|
|
TRUE on success and FALSE on failure.
|
|
Use GetLastError() for further error information.
|
|
|
|
--*/
|
|
{
|
|
BOOL fReturn = TRUE; // default assumed.
|
|
UNICODE_STRING PathName;
|
|
RTL_RELATIVE_NAME RelativeName;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
HANDLE hFindFile = INVALID_HANDLE_VALUE;
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
BOOL fFirstTime;
|
|
DWORD cbExtraMem = 0;
|
|
|
|
PFILE_BOTH_DIR_INFORMATION pFileDirInfo;
|
|
PFILE_BOTH_DIR_INFORMATION pFileDirInfoPrior;
|
|
|
|
//
|
|
// Initialize the variables properly
|
|
//
|
|
|
|
memset( (PVOID ) &PathName, 0, sizeof(PathName));
|
|
memset( (PVOID ) &RelativeName, 0, sizeof(RelativeName));
|
|
|
|
//
|
|
// Convert the DOS name of directory to NT name for NT API to open it.
|
|
//
|
|
|
|
fReturn = RtlDosPathNameToNtPathName_U(
|
|
pwszDirectoryName,
|
|
&PathName,
|
|
NULL,
|
|
&RelativeName );
|
|
|
|
//
|
|
// If translation fails or
|
|
// If this directory name is in the form <dirname>\<filespec>,
|
|
// the caller has messed up.
|
|
//
|
|
|
|
if ( !fReturn || RelativeName.RelativeName.Length != 0) {
|
|
|
|
SetLastError(ERROR_PATH_NOT_FOUND);
|
|
|
|
if ( PathName.Buffer != NULL) { // free up the space.
|
|
|
|
RtlFreeHeap( RtlProcessHeap(), 0, PathName.Buffer);
|
|
}
|
|
|
|
return( fReturn);
|
|
}
|
|
|
|
//
|
|
// Remember that we need to free the buffer containing the NT name.
|
|
// i.e. PathName.Buffer
|
|
//
|
|
|
|
ASSERT( RelativeName.ContainingDirectory == NULL );
|
|
ASSERT( RelativeName.RelativeName.Length == 0);
|
|
|
|
InitializeObjectAttributes( &Obja,
|
|
&PathName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
RelativeName.ContainingDirectory,
|
|
NULL );
|
|
|
|
//
|
|
// Open the directory for list access
|
|
//
|
|
|
|
Status = NtOpenFile( &hFindFile,
|
|
FILE_LIST_DIRECTORY | SYNCHRONIZE,
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
|
|
FILE_OPEN_FOR_BACKUP_INTENT
|
|
);
|
|
|
|
//
|
|
// The Buffer is not required any more. Free it before checking status.
|
|
//
|
|
|
|
RtlFreeHeap( RtlProcessHeap(), 0, PathName.Buffer );
|
|
PathName.Buffer = NULL;
|
|
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
|
|
//
|
|
// The full path does not refer to a directory. This could be a
|
|
// device, but (unlike FindFirstFile()...) we don't care. If it's
|
|
// not a directory, we don't list it.
|
|
//
|
|
|
|
IF_DEBUG( DIR_LIST) {
|
|
DBGPRINTF( ( DBG_CONTEXT, "Failed to open Dir %ws. Handle = %x\n",
|
|
pwszDirectoryName, hFindFile));
|
|
}
|
|
|
|
SetLastError( ERROR_PATH_NOT_FOUND);
|
|
return ( FALSE);
|
|
}
|
|
|
|
InitializeListHead( &m_listDirectoryBuffers);
|
|
|
|
//
|
|
// Loop through getting subsequent entries in the directory.
|
|
//
|
|
for( fFirstTime = TRUE; ; fFirstTime = FALSE)
|
|
{
|
|
PVOID pvBuffer;
|
|
|
|
//
|
|
// Get the next chunk of directory information.
|
|
// Obtained in a buffer with LIST_ENTRY as the first member of buffer
|
|
//
|
|
|
|
#define DIR_ALLOC_SIZE (DIRECTORY_BUFFER_SIZE + sizeof (LIST_ENTRY))
|
|
|
|
pvBuffer = ALLOC( DIR_ALLOC_SIZE );
|
|
cbExtraMem += DIR_ALLOC_SIZE;
|
|
|
|
if ( pvBuffer == NULL ) {
|
|
|
|
//
|
|
// Allocation failure.
|
|
//
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY);
|
|
fReturn = FALSE;
|
|
break; // Get out of the loop with failure.
|
|
}
|
|
|
|
pFileDirInfo = ( PFILE_BOTH_DIR_INFORMATION )
|
|
((( PCHAR ) pvBuffer) + sizeof( LIST_ENTRY ) );
|
|
|
|
Status = NtQueryDirectoryFile( hFindFile, // fileHandle
|
|
NULL, // Event
|
|
NULL, // Apc Routine
|
|
NULL, // ApcContext
|
|
&IoStatusBlock, // PIoStatusBlock
|
|
pFileDirInfo, // PFileInfo
|
|
DIRECTORY_BUFFER_SIZE, // Len
|
|
FileBothDirectoryInformation, //Class
|
|
FALSE, // fSingleEntry ?
|
|
NULL, //FileName
|
|
fFirstTime ); // RestartScan ?
|
|
|
|
//
|
|
// If the NT API returns STATUS_NO_MORE_FILES, then it did not use
|
|
// our buffer at all. We can just free it.
|
|
// Now's the time that we leave this loop, and stop reading the
|
|
// directory file.
|
|
//
|
|
|
|
if ( Status == STATUS_NO_MORE_FILES ) {
|
|
|
|
FREE( pvBuffer );
|
|
|
|
//
|
|
// Decrement the memory size so we don't get charged for it
|
|
//
|
|
|
|
cbExtraMem -= DIR_ALLOC_SIZE;
|
|
|
|
fReturn = TRUE;
|
|
break;
|
|
}
|
|
|
|
if ( NT_SUCCESS( Status ) || ( Status == STATUS_BUFFER_OVERFLOW ) )
|
|
{
|
|
|
|
ULONG Offset;
|
|
|
|
//
|
|
// The buffer contains directory entries.
|
|
// Place it on the list of such buffers for this directory.
|
|
//
|
|
|
|
InsertBufferInTail( (PLIST_ENTRY ) pvBuffer);
|
|
|
|
pFileDirInfoPrior = NULL;
|
|
|
|
//
|
|
// Scan thru the entries in the buffer,
|
|
// truncate the last entry ( if partial) and
|
|
// convert the Unicode strings, inplace to ansi strings.
|
|
//
|
|
|
|
do
|
|
{
|
|
pFileDirInfoPrior = pFileDirInfo;
|
|
|
|
Offset = pFileDirInfo->NextEntryOffset;
|
|
|
|
if ( ( Offset == 0 ) && ( Status == STATUS_BUFFER_OVERFLOW ) )
|
|
{
|
|
//
|
|
// If Status==STATUS_BUFFER_OVERFLOW, the last entry in
|
|
// buffer may be a partial entry, broken on boundary of
|
|
// buffer. The NT API will give us this entry again next
|
|
// time around, so for now we patch the buffer up to
|
|
// appear as if it does not contain the partial entry.
|
|
//
|
|
|
|
if ( pFileDirInfoPrior != NULL )
|
|
{
|
|
pFileDirInfoPrior->NextEntryOffset = 0;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Some fatal problem. Should get out this loop.
|
|
//
|
|
BREAKPOINT();
|
|
fReturn = FALSE;
|
|
goto Failure;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IncrementDirEntries();
|
|
|
|
if ( pFileDirInfo->FileNameLength != 0) {
|
|
pFileDirInfo->FileNameLength =
|
|
ConvertUnicodeToAnsiInPlace(
|
|
(LPWSTR ) pFileDirInfo->FileName,
|
|
(USHORT ) pFileDirInfo->FileNameLength);
|
|
}
|
|
|
|
if ( pFileDirInfo->ShortNameLength != 0) {
|
|
pFileDirInfo->ShortNameLength =
|
|
(CCHAR ) ConvertUnicodeToAnsiInPlace(
|
|
(LPWSTR ) pFileDirInfo->ShortName,
|
|
pFileDirInfo->ShortNameLength);
|
|
}
|
|
|
|
|
|
// Get the next entry in buffer
|
|
pFileDirInfo =
|
|
( PFILE_BOTH_DIR_INFORMATION )
|
|
((( PCHAR )pFileDirInfo ) + Offset );
|
|
}
|
|
}
|
|
while ( Offset != 0);
|
|
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
if ( !NT_SUCCESS(Status) )
|
|
{
|
|
fReturn = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Failure:
|
|
|
|
ASSERT( PathName.Buffer == NULL);
|
|
if ( hFindFile != INVALID_HANDLE_VALUE) {
|
|
NtClose( hFindFile );
|
|
hFindFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
*pcbMemUsed += cbExtraMem;
|
|
|
|
return ( fReturn);
|
|
} // TS_DIRECTORY_HEADER::ReadFromNtDirectoryFile()
|
|
|
|
|
|
|
|
|
|
VOID
|
|
TS_DIRECTORY_HEADER::CleanupThis( VOID)
|
|
{
|
|
PLIST_ENTRY pEntry;
|
|
PLIST_ENTRY pNextEntry;
|
|
|
|
for ( pEntry = QueryDirBuffersListEntry()->Flink;
|
|
pEntry != QueryDirBuffersListEntry();
|
|
pEntry = pNextEntry )
|
|
{
|
|
pNextEntry = pEntry->Flink;
|
|
|
|
//
|
|
// The buffers are allocated such that first member of buffer is
|
|
// LIST_ENTRY object. Free it entirely.
|
|
//
|
|
FREE( pEntry );
|
|
}
|
|
|
|
InitializeListHead( QueryDirBuffersListEntry());
|
|
|
|
if ( m_ppFileInfo != NULL) {
|
|
|
|
FREE( m_ppFileInfo);
|
|
m_ppFileInfo = NULL;
|
|
}
|
|
|
|
m_hListingUser = INVALID_HANDLE_VALUE;
|
|
m_nEntries = 0;
|
|
|
|
return;
|
|
} // TS_DIRECTORY_HEADER::CleanupThis()
|
|
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
TS_DIRECTORY_HEADER::BuildFileInfoPointers(
|
|
IN OUT DWORD * pcbMemUsed
|
|
)
|
|
/*++
|
|
|
|
This constructs the indirection pointers from the buffers containing the
|
|
file information.
|
|
This array of indirection enables faster access to the file information
|
|
structures stored.
|
|
|
|
Should be always called after ReadFromNtDirectoryFile() to construct the
|
|
appropriate pointers.
|
|
|
|
Returns:
|
|
TRUE on success and FALSE if there are any failures.
|
|
--*/
|
|
{
|
|
BOOL fReturn = FALSE;
|
|
DWORD cbAlloc;
|
|
|
|
ASSERT( QueryNumEntries() != 0); // Any directory will atleast have "."
|
|
|
|
//
|
|
// Alloc space for holding the pointers for numEntries pointers.
|
|
//
|
|
|
|
cbAlloc = QueryNumEntries() * sizeof( PFILE_BOTH_DIR_INFORMATION );
|
|
|
|
m_ppFileInfo = (PFILE_BOTH_DIR_INFORMATION *) ALLOC( cbAlloc );
|
|
|
|
if ( m_ppFileInfo != NULL ) {
|
|
|
|
int index;
|
|
PLIST_ENTRY pEntry;
|
|
ULONG Offset;
|
|
PFILE_BOTH_DIR_INFORMATION pFileDirInfo;
|
|
|
|
//
|
|
// Get the link to first buffer and start enumeration.
|
|
//
|
|
pEntry = QueryDirBuffersListEntry()->Flink;
|
|
pFileDirInfo = (PFILE_BOTH_DIR_INFORMATION )( pEntry + 1 );
|
|
|
|
for ( index = 0;
|
|
index < QueryNumEntries();
|
|
index++ ) {
|
|
|
|
ASSERT( pEntry != QueryDirBuffersListEntry());
|
|
|
|
m_ppFileInfo[index] = pFileDirInfo; // store the pointer.
|
|
|
|
Offset = pFileDirInfo->NextEntryOffset;
|
|
|
|
if ( Offset != 0 ) {
|
|
|
|
pFileDirInfo = (PFILE_BOTH_DIR_INFORMATION )
|
|
((( PCHAR )pFileDirInfo ) + Offset );
|
|
} else {
|
|
|
|
//
|
|
// we are moving to the next buffer.
|
|
//
|
|
pEntry = pEntry->Flink;
|
|
if ( pEntry == QueryDirBuffersListEntry()) {
|
|
|
|
ASSERT( index == QueryNumEntries() - 1);
|
|
break;
|
|
}
|
|
pFileDirInfo = ( PFILE_BOTH_DIR_INFORMATION )( pEntry + 1 );
|
|
}
|
|
|
|
|
|
} // for
|
|
ASSERT( Offset == 0 );
|
|
fReturn = SortInPlaceFileInfoPointers( m_ppFileInfo,
|
|
QueryNumEntries(),
|
|
AlphaCompareFileBothDirInfo);
|
|
|
|
} // valid alloc of the pointers.
|
|
|
|
*pcbMemUsed += cbAlloc;
|
|
|
|
return ( fReturn);
|
|
} // TS_DIRECTORY_HEADER::BuildFileInfoPointers()
|
|
|
|
|
|
|
|
|
|
# if DBG
|
|
|
|
VOID
|
|
TS_DIRECTORY_HEADER::Print( VOID) const
|
|
{
|
|
DBGPRINTF( ( DBG_CONTEXT,
|
|
"Printing TS_DIRECTORY_HEADER ( %08x).\n", this));
|
|
DBGPRINTF( ( DBG_CONTEXT,
|
|
"ListingUser Handle = %08x\t Num Entries = %08x\n",
|
|
m_hListingUser, m_nEntries));
|
|
DBGPRINTF( ( DBG_CONTEXT,
|
|
"Pointer to array of indirection pointers %08x\n",
|
|
m_ppFileInfo));
|
|
//
|
|
// The buffers containing the data of the file information not printed
|
|
//
|
|
|
|
return;
|
|
} // TS_DIRECTORY_HEADER::Print()
|
|
|
|
|
|
# endif // DBG
|
|
|
|
/************************ End of File ***********************/
|
|
|