2025-04-27 07:49:33 -04:00

703 lines
18 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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).
Rewritten for Windows95
Author:
VladS 11-20-95 WIndows95 version
Project:
Tsunami Lib
( Common caching and directory functions for Internet Services)
Functions Exported:
BOOL TsGetDirectoryListingA()
BOOL TsGetDirectoryListingW()
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 );
PTS_DIRECTORY_HEADER
TsGetFreshDirectoryHeaderW(
IN const TSVC_CACHE & tsCache,
IN LPCWSTR pwszDirectoryName,
IN HANDLE hLisingUser);
dllexp
BOOL
TsGetDirectoryListingA
(
IN const TSVC_CACHE &tsCache,
IN PCSTR pszDirectoryName,
IN HANDLE hListingUser,
OUT PTS_DIRECTORY_HEADER * ppTsDirectoryHeader
)
/*++
This function obtains the directory listing for dir specified
in pwszDirectoryName.
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.
--*/
{
BOOL bSuccess;
BOOL fReadSuccess;
DWORD cbBlob = 0;
PTS_DIRECTORY_HEADER pDirectoryHeader=NULL;
//
// Allocate space for Directory listing
//
bSuccess = TsAllocateEx( tsCache,
sizeof( TS_DIRECTORY_HEADER ),
( PVOID * )&pDirectoryHeader,
FreeDirectoryHeaderContents );
if ( !bSuccess) {
//
// Allocation of Directory Header failed.
//
return FALSE;
}
ASSERT( pDirectoryHeader != NULL);
pDirectoryHeader->ReInitialize(); // called since we raw alloced space
pDirectoryHeader->SetListingUser( hListingUser);
//
// Read fresh directory listing. We don not cache ( now)
// when running on Windows95, but may in future
// We are reusing the same method to obtaining directory information
// as defined in NT class definition, although in reality this is
// platform specific method
//
fReadSuccess = pDirectoryHeader->ReadFromNtDirectoryFile(
(LPCWSTR)pszDirectoryName,
&cbBlob ) &&
pDirectoryHeader->BuildFileInfoPointers( &cbBlob );
if (! fReadSuccess) {
//
// Reading directory failed.
// cleanup directory related data and get out.
//
BOOL fFreed = TsFree( tsCache, pDirectoryHeader);
ASSERT( fFreed);
pDirectoryHeader = NULL;
}
*ppTsDirectoryHeader = pDirectoryHeader;
bSuccess = ( *ppTsDirectoryHeader != NULL);
return bSuccess;
} // TsGetDirectoryListingA()
dllexp
BOOL
TsFreeDirectoryListing
(
IN const TSVC_CACHE & tsCache,
IN PTS_DIRECTORY_HEADER pDirectoryHeader
)
{
BOOL fReturn;
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.
CHAR szDirectoryName[MAX_PATH+5];
WIN32_FIND_DATA fd;
HANDLE hFindFile = INVALID_HANDLE_VALUE;
BOOL fFirstTime,fOverflow=FALSE;
DWORD cbExtraMem = 0, cch;
PFILE_BOTH_DIR_INFORMATION pFileDirInfo = NULL;
PFILE_BOTH_DIR_INFORMATION pFileDirInfoPrior = NULL;
ULONG Offset;
lstrcpy(szDirectoryName,(LPCSTR)pwszDirectoryName);
lstrcat(szDirectoryName,TEXT("\\*.*"));
//
// Open the directory for list access
//
hFindFile = FindFirstFile(szDirectoryName,&fd);
if (hFindFile == INVALID_HANDLE_VALUE) {
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 )
((PLIST_ENTRY)pvBuffer + 1 );
//
// The buffer contains directory entries.
// Place it on the list of such buffers for this directory.
//
InsertBufferInTail( (PLIST_ENTRY ) pvBuffer);
pFileDirInfoPrior = NULL;
fOverflow=FALSE;
Offset = 0;
do {
Offset = sizeof(FILE_BOTH_DIR_INFORMATION)+
lstrlen(fd.cFileName)+sizeof(CHAR);
if (((PCHAR)pFileDirInfo+Offset-(PCHAR)pvBuffer) >= DIR_ALLOC_SIZE) {
fOverflow = TRUE;
break;
}
IncrementDirEntries();
//
// Move Win32 structure into FILE_BOTH
//
if (pFileDirInfoPrior){
pFileDirInfoPrior->NextEntryOffset =
sizeof(FILE_BOTH_DIR_INFORMATION)+
pFileDirInfoPrior->FileNameLength+sizeof(CHAR);
;
}
// BUGBUG THis is not quite correct
pFileDirInfo->NextEntryOffset = 0;
pFileDirInfo->FileIndex = 0;
pFileDirInfo->CreationTime.QuadPart = 0;//(LARGE_INTEGER)fd.ftCreationTime;
pFileDirInfo->LastAccessTime.QuadPart = 0;//fd.ftLastAccessTime;
pFileDirInfo->LastWriteTime.QuadPart = 0;//fd.ftLastWriteTime;
pFileDirInfo->ChangeTime.QuadPart = 0;
pFileDirInfo->EndOfFile.QuadPart = 0;
pFileDirInfo->AllocationSize.QuadPart= fd.nFileSizeLow;
pFileDirInfo->FileAttributes = fd.dwFileAttributes;
pFileDirInfo->FileNameLength = lstrlen(fd.cFileName);
pFileDirInfo->EaSize = 0;
pFileDirInfo->ShortNameLength = min(lstrlen(fd.cAlternateFileName),12);
strncpy((LPSTR)pFileDirInfo->ShortName,fd.cAlternateFileName,pFileDirInfo->ShortNameLength);
strcpy((LPSTR)pFileDirInfo->FileName,fd.cFileName);
pFileDirInfoPrior = pFileDirInfo;
// Get the next entry in buffer
pFileDirInfo =
( PFILE_BOTH_DIR_INFORMATION )
((( PCHAR )pFileDirInfo ) + Offset);
}
while(!fOverflow && FindNextFile(hFindFile,&fd));
if (!fOverflow)
break;
}
if ( hFindFile != INVALID_HANDLE_VALUE) {
FindClose(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()
dllexp
BOOL
TsGetDirectoryListingW
(
IN const TSVC_CACHE &tsCache,
IN PCWSTR pwszDirectoryName,
IN HANDLE hListingUser,
OUT PTS_DIRECTORY_HEADER * ppTsDirectoryHeader
)
/*++
This function obtains the directory listing for dir specified
in pwszDirectoryName.
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.
--*/
{
return ( FALSE);
} // TsGetDirectoryListingW()
# 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