Windows-Server-2003/inetsrv/query/fsci/dll/scopeenm.cxx

1124 lines
34 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2000.
//
// File: scopeenm.cxx
//
// Contents: File system scope enumerator
//
// History: 12-Dec-96 SitaramR Created
//
//--------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <scopeenm.hxx>
#include <catalog.hxx>
#include <prcstob.hxx>
#include <notifmgr.hxx>
#include <scanmgr.hxx>
#include <scopetbl.hxx>
//+-------------------------------------------------------------------------
//
// Member: CScopeEnum::CScopeEnum, public
//
// Synopsis: Initialize scope enumerator
//
// Arguments: [cat] -- Catalog
// [pQueryPropMapper] -- Pid Remapper associated with the query
// [fUsePathAlias] -- TRUE if client is going through rdr/svr
// [scope] -- Root of scope
//
// Requires: [cbBuf] is at least some minimum size of about 1K.
//
// History: 17-May-93 KyleP Created
//
//--------------------------------------------------------------------------
CScopeEnum::CScopeEnum( PCatalog & cat,
ICiQueryPropertyMapper *pQueryPropMapper,
CSecurityCache & secCache,
BOOL fUsePathAlias,
CRestriction const & scope )
: CGenericPropRetriever( cat,
pQueryPropMapper,
secCache,
fUsePathAlias ? &scope : 0,
FILE_READ_ATTRIBUTES ),
_scope( scope ),
_xbBuf( FINDFIRST_BUFFER ),
_hDir( INVALID_HANDLE_VALUE ),
_pCurEntry( 0 ),
_iFirstSubDir( 2 ),
_num( 0 ),
_numHighValue( 10000 ), // Numerator ranges from 0 to 10,000 and the denominator is always 10,000
_numLowValue( 0 ),
_fNullCatalog( cat.IsNullCatalog() )
{
_VPath.Buffer = _awcVPath;
//
// Allocate buffer.
//
Win4Assert( _xbBuf.SizeOf() >= MAX_PATH * sizeof(WCHAR) +
sizeof(FILE_DIRECTORY_INFORMATION) );
}
//+-------------------------------------------------------------------------
//
// Member: CScopeEnum::~CScopeEnum, public
//
// Synopsis: Close file store scope enumerator
//
// History: 17-May-93 KyleP Created
//
//--------------------------------------------------------------------------
CScopeEnum::~CScopeEnum()
{
_xDirStackEntry.Free();
if ( INVALID_HANDLE_VALUE != _hDir )
NtClose( _hDir );
}
//+-------------------------------------------------------------------------
//
// Member: CScopeEnum::PushScope
//
// Synopsis: Adds scope
//
// History: 12-Dec-96 SitaramR Added header
//
//--------------------------------------------------------------------------
void CScopeEnum::PushScope( CScopeRestriction const & scp )
{
//
// Push initial directories
//
if ( scp.IsVirtual() )
{
unsigned iBmk = 0;
XGrowable<WCHAR> xwcsVPath;
CLowerFunnyPath lcaseFunnyPPath;
unsigned ccVPath = xwcsVPath.Count();
unsigned ccPPath = lcaseFunnyPPath.Count();
while ( _cat.VirtualToPhysicalRoot( scp.GetPath(), // Virtual scope (prefix)
scp.PathLength(), // + length
xwcsVPath, // Full virtual root
ccVPath, // + max length / return length
lcaseFunnyPPath, // Full physical root
ccPPath, // + max length / return length
iBmk ) ) // Bookmark
{
vqDebugOut(( DEB_ITRACE, "VPath %.*ws --> PPath %ws\n",
ccVPath, xwcsVPath.Get(),
lcaseFunnyPPath.GetActualPath() ));
//
// Use the directory if it is eligible, and is either
// a deep scope
// not the root "/", which by this point is an empty string
// is the root, is shallow, and this is the 1 and only "/"
//
if ( ( _cat.IsEligibleForFiltering( lcaseFunnyPPath.GetActualPath() ) ) &&
( ( scp.IsDeep() ) ||
( 0 != scp.PathLength() ) ||
( 1 == ccVPath ) ) )
{
XPtr<CDirStackEntry> xDirStackEntry(
new CDirStackEntry(
lcaseFunnyPPath,
10000, 0, // For scope progress
scp.IsDeep(),
xwcsVPath.Get(),
ccVPath, // Virtual root
lcaseFunnyPPath.GetActualLength()));
// Amount of proot to replace. Do
// not count \\?\ as replace chars
_stack.Push( xDirStackEntry.GetPointer() );
xDirStackEntry.Acquire();
}
else
{
vqDebugOut(( DEB_IWARN, "Skipped scope: file %ws\n",
lcaseFunnyPPath.GetActualPath() ));
}
ccVPath = xwcsVPath.Count();
ccPPath = lcaseFunnyPPath.Count();
}
}
else
{
WCHAR const *pwcScope = scp.GetPath();
Win4Assert( 0 != pwcScope );
if ( 0 == *pwcScope )
{
//
// Add all physical scopes if scope is root, but not for shallow
// traversal.
//
if ( scp.IsDeep() )
{
CCiScopeTable *pScopes = _cat.GetScopeTable();
if ( 0 != pScopes )
{
unsigned iBmk = 0;
WCHAR awc[MAX_PATH];
while ( pScopes->Enumerate( awc,
sizeof awc / sizeof WCHAR,
iBmk ) )
{
if ( _cat.IsEligibleForFiltering( awc ) )
{
XPtr<CDirStackEntry> xDirStackEntry(
new CDirStackEntry( awc,
wcslen(awc),
10000,
0,
scp.IsDeep() ) );
_stack.Push( xDirStackEntry.GetPointer() );
xDirStackEntry.Acquire();
vqDebugOut(( DEB_ITRACE, "adding enum scope '%ws'\n", awc ));
}
}
}
}
}
else
{
CLowerFunnyPath lcaseFunnyFixedPath = scp.GetFunnyPath();
//
// if scope is unc, use fixed up version
//
if ( lcaseFunnyFixedPath.IsRemote() )
{
// unc -- try to unfixup the scope. if there is no unfixup,
// it'll just use the original path.
_cat.InverseFixupPath( lcaseFunnyFixedPath );
}
//
// Check to see if the input path name contains an 8.3 short name
//
if ( lcaseFunnyFixedPath.IsShortPath() )
{
vqDebugOut(( DEB_WARN,
"CScopeEnum::PushScope: possible shortname path\n\t%ws ==>\n",
lcaseFunnyFixedPath.GetActualPath() ));
if ( lcaseFunnyFixedPath.ConvertToLongName() )
{
vqDebugOut(( DEB_WARN|DEB_NOCOMPNAME,
"\t%ws\n",
lcaseFunnyFixedPath.GetActualPath() ));
}
else
{
vqDebugOut(( DEB_ERROR, "longname path conversion failed!\n" ));
}
}
if ( _cat.IsEligibleForFiltering( lcaseFunnyFixedPath.GetActualPath() ) )
{
XPtr<CDirStackEntry> xDirStackEntry(
new CDirStackEntry( lcaseFunnyFixedPath.GetActualPath(),
lcaseFunnyFixedPath.GetActualLength(),
10000,
0,
scp.IsDeep() ) );
_stack.Push( xDirStackEntry.GetPointer() );
xDirStackEntry.Acquire();
}
else
{
vqDebugOut(( DEB_IWARN, "Unfiltered scope: %ws\n", scp.GetPath() ));
}
}
}
} //PushScope
//+-------------------------------------------------------------------------
//
// Member: CScopeEnum::NextObject, public
//
// Synopsis: Move to next object.
//
// Returns: WORKID of object. widInvalid if no more objects to iterate.
//
// History: 17-May-93 KyleP Created
//
//--------------------------------------------------------------------------
WORKID CScopeEnum::NextObject()
{
_VPath.Length = flagNoValueYet;
WORKID wid = widInvalid;
while ( TRUE )
{
//
// Move to next entry in current buffer.
//
if ( _pCurEntry )
_pCurEntry = _pCurEntry->Next();
//
// Out of entries in buffer? Try to reload buffer.
//
if ( _pCurEntry == 0 )
{
if ( Refresh() )
_pCurEntry = (CDirEntry *)_xbBuf.GetPointer();
else
break;
}
//
// Get rid of . and ..
//
WCHAR const * pwcsFilename = _pCurEntry->Filename();
USHORT cbFilename = _pCurEntry->FilenameSize();
if ( pwcsFilename[0] == L'.' )
{
if ( cbFilename == sizeof(WCHAR) )
continue;
else if ( pwcsFilename[1] == L'.' )
{
if ( cbFilename == sizeof(WCHAR)*2 )
continue;
}
}
// normalize the filename
ULONG cwcInOut = _pCurEntry->FilenameSize() / sizeof WCHAR;
ULONG cwc = LCMapStringW( LOCALE_NEUTRAL,
LCMAP_LOWERCASE,
(WCHAR *) _pCurEntry->Filename(),
cwcInOut,
(WCHAR *) _pCurEntry->Filename(),
cwcInOut );
if ( 0 == cwc )
{
ciDebugOut(( DEB_WARN, "unable to lowcase filename\n" ));
}
_Name.Length = _Name.MaximumLength = (USHORT) cwc * sizeof WCHAR;
//
// If it's a directory and not a reparse point, push on stack. We
// don't fully handle reparse points so we must deny their existence.
//
if ( ( _xDirStackEntry->isDeep() ) &&
( _pCurEntry->Attributes() & FILE_ATTRIBUTE_DIRECTORY ) &&
( 0 == ( _pCurEntry->Attributes() & FILE_ATTRIBUTE_REPARSE_POINT ) ) )
{
XPtr<CDirStackEntry> xDirStackEntry(
new CDirStackEntry( GetPath(),
GetName(),
0,
0,
_xDirStackEntry->isDeep(),
_xDirStackEntry.GetPointer() ) );
if (_cat.IsEligibleForFiltering( xDirStackEntry->GetFileName().GetActualPath() ))
{
_stack.Push( xDirStackEntry.GetPointer() );
xDirStackEntry.Acquire();
}
else
{
vqDebugOut(( DEB_IWARN, "Unfiltered directory: %ws\n",
xDirStackEntry->GetFileName() ));
continue;
}
}
//
// Filter based upon file attributes
//
if ( 0 == _ulAttribFilter || ( _ulAttribFilter & _pCurEntry->Attributes() ) == 0 )
{
Win4Assert( 0 != _pCurEntry );
vqDebugOut(( DEB_FINDFIRST, "Found %.*ws\n",
_pCurEntry->FilenameSize() / sizeof(WCHAR),
_pCurEntry->Filename() ));
if ( _xDirStackEntry->isDeep() )
{
//
// It's a deep query, so we allocate 30% to traversing the current dir
// (remaining 70% is allocated to the sub-directories). However, if _numHighValue
// is 0 then it means that the quota allocated to this directory is too small to
// impact RatioFinished, so we stay put at the current value of RatioFinished
//
if ( _numHighValue != 0 )
{
if ( (_num + 100) < ( (100 - DIRECTORY_QUOTA) * _numLowValue) / 100 + (DIRECTORY_QUOTA * _numHighValue) / 100 )
_num += 100;
}
}
else
{
//
// It's a shallow query, so we go upto 90% and then we stay put until we are done
//
if ( _num < _xDirStackEntry->GetHighValue() * SHALLOW_DIR_LIMIT / 100 )
_num += 100;
}
// this is just a file index -- not of much value, since it isn't
// the same as the workid in the CCI (if one exists)
//return( _pCurEntry->WorkId() );
// If a catalog exists, look up the path or add the path and get
// a workid back. This can be really expensive if every path is
// added to the catalog, but there is no alternative for multi-cursor
// queries.
PCatalog & cat = _cat;
CLowerFunnyPath lcaseFunnyBuf;
if (!_fNullCatalog)
{
UNICODE_STRING const * pFilename = GetName();
UNICODE_STRING const * pPath = GetPath();
lcaseFunnyBuf.SetPath( pPath->Buffer, pPath->Length/sizeof(WCHAR) );
lcaseFunnyBuf.AppendBackSlash();
lcaseFunnyBuf.AppendPath( pFilename->Buffer, pFilename->Length/sizeof(WCHAR) );
Win4Assert( IsPropRecReleased() );
wid = cat.PathToWorkId( lcaseFunnyBuf, TRUE );
}
else
{
lcaseFunnyBuf.InitBlank();
wid = cat.PathToWorkId(lcaseFunnyBuf, TRUE);
}
//
// If we got widInvalid back here, then the file is not eligible for search
// and we need to go to the next one.
//
if ( widInvalid != wid )
break;
}
}
return wid;
}
//+---------------------------------------------------------------------------
//
// Member: CScopeEnum::RatioFinished, public
//
// Synopsis: Returns query progress estimate
//
// Arguments: [denom] -- Denominator returned here.
// [num] -- Numerator returned here.
//
// History: 19-Jul-95 KyleP Added header
//
//----------------------------------------------------------------------------
SCODE STDMETHODCALLTYPE CScopeEnum::RatioFinished (ULONG *pDenom, ULONG *pNum)
{
*pDenom = 10000;
*pNum = _num;
Win4Assert( *pNum <= *pDenom );
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Member: CScopeEnum::GetVirtualPath, public
//
// Returns: A virtual path to file, or 0 if none exists.
//
// History: 07-Feb-96 KyleP Added header
//
//----------------------------------------------------------------------------
UNICODE_STRING const * CScopeEnum::GetVirtualPath()
{
if ( _VPath.Length == flagNoValueYet )
{
//
// Fast path: Iterating by virtual scope.
//
Win4Assert( !_xDirStackEntry.IsNull() );
if ( _xDirStackEntry->GetVirtualRoot() )
{
RtlCopyMemory( _VPath.Buffer,
_xDirStackEntry->GetVirtualRoot(),
_xDirStackEntry->VirtualRootLength() * sizeof(WCHAR) );
if ( _Path.Length >= _xDirStackEntry->ReplaceLength() * sizeof(WCHAR) )
{
if ( ( _xDirStackEntry->VirtualRootLength() +
( _Path.Length - _xDirStackEntry->ReplaceLength() ) ) >= MAX_PATH )
THROW( CException( E_INVALIDARG ) );
RtlCopyMemory( _VPath.Buffer + _xDirStackEntry->VirtualRootLength(),
_Path.Buffer + _xDirStackEntry->ReplaceLength(),
_Path.Length - _xDirStackEntry->ReplaceLength() * sizeof(WCHAR) );
_VPath.Length = (USHORT)(_xDirStackEntry->VirtualRootLength() * sizeof(WCHAR) +
_Path.Length - _xDirStackEntry->ReplaceLength() * sizeof(WCHAR));
}
else
{
Win4Assert( _Path.Length == (_xDirStackEntry->ReplaceLength() - 1) * sizeof(WCHAR) );
_VPath.Length = (USHORT)((_xDirStackEntry->VirtualRootLength() - 1) * sizeof(WCHAR));
}
_VPath.Buffer[_VPath.Length / sizeof(WCHAR)] = 0;
}
else
{
//
// Get a virtual path from catalog.
//
PCatalog & cat = _cat;
//
// It's slow to Quiesce here, but after all this is an
// enumeration query and this can't affect the run time
// substantially. We can re-address this if some important
// customer scenario is hit.
//
Quiesce();
unsigned cwc = sizeof( _awcVPath ) / sizeof( WCHAR );
XGrowable<WCHAR> xTemp;
cwc = cat.WorkIdToVirtualPath ( _widPrimedForPropRetrieval, 0, xTemp );
RtlCopyMemory( _VPath.Buffer, xTemp.Get(), __min( cwc * sizeof(WCHAR), sizeof( _awcVPath ) ) );
if ( cwc == 0 )
_VPath.Length = flagNoValue;
else
_VPath.Length = (USHORT)(cwc * sizeof(WCHAR) - _pCurEntry->FilenameSize() - sizeof(WCHAR));
}
}
if ( flagNoValue == _VPath.Length )
return 0;
return &_VPath;
} //GetVirtualPath
//+-------------------------------------------------------------------------
//
// Member: CScopeEnum::Refresh, private
//
// Synopsis: Load stat properties
//
// Returns: TRUE if load succeeds.
//
// History: 19-Aug-93 KyleP Created
//
//--------------------------------------------------------------------------
BOOL CScopeEnum::Refresh()
{
BOOL fRetVal = FALSE;
CImpersonateClient impClient( GetClientToken() );
IO_STATUS_BLOCK IoStatus;
//
// Continue existing search if possible
//
if ( _hDir != INVALID_HANDLE_VALUE )
{
if ( SUCCEEDED( NtQueryDirectoryFile( _hDir, // File
0, // Event
0, // APC routine
0, // APC context
&IoStatus, // I/O Status
_xbBuf.GetPointer(), // Buffer
_xbBuf.SizeOf(), // Buffer Length
FileBothDirectoryInformation,
0, // Multiple entry
0, // Filename
0 ) ) ) // Continue scan
{
return( TRUE );
}
else
{
NtClose( _hDir );
_hDir = INVALID_HANDLE_VALUE;
}
}
//
// Is there another directory?
//
_xDirStackEntry.Free();
//
// If _numHighValue is 0, then it means that the quota allocated to this directory
// is too small to impact RatioFinished, so we stay put at current value of RatioFinished
//
if ( _numHighValue != 0 )
{
Win4Assert( _iFirstSubDir >= 0 );
if ( _stack.Count() > (unsigned) _iFirstSubDir ) // Are there any sub-directories ?
{
//
// We divide up the remaining 70% of our quota among our sub-directories
//
ULONG cSubDir = _stack.Count() - _iFirstSubDir;
ULONG numIncrement = ( _numHighValue - _num ) / cSubDir;
if ( numIncrement > 0 )
{
ULONG num = _num;
for ( int i = _stack.Count()-1; i>_iFirstSubDir; i-- )
{
CDirStackEntry *pDirStackEntry = _stack.Get( i );
Win4Assert( pDirStackEntry );
pDirStackEntry->SetLowValue( num );
num += numIncrement;
pDirStackEntry->SetHighValue( num );
Win4Assert( pDirStackEntry->IsRangeOK() );
}
//
// Allocate all remaining quota to the last sub-directory
//
CDirStackEntry *pDirStackEntry = _stack.Get( _iFirstSubDir );
Win4Assert( pDirStackEntry );
pDirStackEntry->SetLowValue( num );
pDirStackEntry->SetHighValue( _numHighValue );
Win4Assert( pDirStackEntry->IsRangeOK() );
}
else
{
//
// Since numIncrement is too small, we allocate all quota to just the last sub-directory
//
CDirStackEntry *pDirStackEntry = _stack.Get( _iFirstSubDir );
Win4Assert( pDirStackEntry );
pDirStackEntry->SetLowValue( _num );
pDirStackEntry->SetHighValue( _numHighValue );
Win4Assert( pDirStackEntry->IsRangeOK() );
}
}
}
while ( _stack.Count() > 0 )
{
Win4Assert( _xDirStackEntry.IsNull() );
_xDirStackEntry.Set( _stack.Pop() );
_VPath.Length = flagNoValueYet;
_Path.Buffer = (WCHAR*)_xDirStackEntry->GetFileName().GetActualPath();
_numHighValue = _xDirStackEntry->GetHighValue();
_numLowValue = _xDirStackEntry->GetLowValue();
#if CIDBG == 1
if ( _numHighValue != 0 )
{
Win4Assert( _numLowValue >= _num );
Win4Assert( _numHighValue >= _numLowValue );
}
#endif CIDBG
_iFirstSubDir = _stack.Count(); // This will be the stack index of the first subdirectory (if any)
unsigned cc = _xDirStackEntry->GetFileName().GetActualLength();
//
// Remove trailing '\' from root.
//
if ( _Path.Buffer[cc-1] == L'\\' )
cc--;
if ( cc >= 32768 )
THROW( CException( E_INVALIDARG ) );
_Path.Length = _Path.MaximumLength = (USHORT)(cc * sizeof(WCHAR));
if ( CImpersonateRemoteAccess::IsNetPath( _Path.Buffer ) )
{
WCHAR const * pwszVPath = 0;
if ( _xDirStackEntry->isVirtual() )
{
UNICODE_STRING const * vPath = GetVirtualPath();
if ( vPath )
pwszVPath = vPath->Buffer;
}
if ( !_remoteAccess.ImpersonateIfNoThrow( _Path.Buffer, pwszVPath ) )
{
vqDebugOut(( DEB_WARN,
"CScopeEnum::Refresh -- Skipping unavailable remote path %ws\n", _Path.Buffer ));
_num = _numHighValue;
_xDirStackEntry.Free();
continue;
}
}
else if ( _remoteAccess.IsImpersonated() )
{
_remoteAccess.Release();
}
UNICODE_STRING uScope;
if ( !RtlDosPathNameToNtPathName_U( _xDirStackEntry->GetFileName().GetPath(),
&uScope,
0,
0 ) )
{
_xDirStackEntry.Free();
break; // fRetVal = FALSE;
}
// Set the state of the funnypath in _xDirStackEntry to ActualPath
// as the above call would have changed it to the funny state
_xDirStackEntry->GetFileName().SetState( CFunnyPath::ACTUAL_PATH_STATE );
//
// Open scope.
//
OBJECT_ATTRIBUTES ObjectAttr;
InitializeObjectAttributes( &ObjectAttr, // Structure
&uScope, // Name
OBJ_CASE_INSENSITIVE, // Attributes
0, // Root
0 ); // Security
NTSTATUS Status = NtOpenFile( &_hDir, // Handle
FILE_LIST_DIRECTORY |
SYNCHRONIZE, // Access
&ObjectAttr, // Object Attributes
&IoStatus, // I/O Status block
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_DIRECTORY_FILE |
FILE_OPEN_FOR_BACKUP_INTENT |
FILE_SYNCHRONOUS_IO_NONALERT ); // Flags
RtlFreeHeap( RtlProcessHeap(), 0, uScope.Buffer );
UNICODE_STRING uFilename;
uFilename.Buffer = L"*";
uFilename.Length = uFilename.MaximumLength = sizeof(WCHAR);
if ( SUCCEEDED( Status ) )
{
Status = NtQueryDirectoryFile( _hDir, // File
0, // Event
0, // APC routine
0, // APC context
&IoStatus, // I/O Status
_xbBuf.GetPointer(), // Buffer
_xbBuf.SizeOf(), // Buffer Length
FileBothDirectoryInformation,
0, // Multiple entry
&uFilename, // Filename
1 ); // Restart scan
}
if ( SUCCEEDED( Status ) )
{
fRetVal = TRUE;
break;
}
_xDirStackEntry.Free();
}
if ( _remoteAccess.IsImpersonated() )
{
_remoteAccess.Release();
}
return fRetVal;
}
//+-------------------------------------------------------------------------
//
// Member: CScopeEnum::BeginPropertyRetrieval
//
// Synopsis: Prime wid for property retrieval
//
// Arguments: [wid] -- Wid to prime
//
// History: 12-Dec-96 SitaramR Created
//
//--------------------------------------------------------------------------
SCODE STDMETHODCALLTYPE CScopeEnum::BeginPropertyRetrieval( WORKID wid )
{
//
// Check that we are retrieving the property for the wid on
// which we are currently positioned. In the case of the null catalog,
// we always have _widCurrent as 1, so allow for that special case.
//
Win4Assert( wid == _widCurrent || 1 == _widCurrent);
Win4Assert( _widPrimedForPropRetrieval == widInvalid );
if ( wid == _widCurrent || 1 == _widCurrent)
{
_widPrimedForPropRetrieval = wid;
return S_OK;
}
else
return E_FAIL;
}
//+-------------------------------------------------------------------------
//
// Member: CScopeEnum::IsInScope
//
// Synopsis: Checks if current wid is in scope
//
// Arguments: [pfInScope] -- Scope check result returned here
//
// History: 12-Dec-96 SitaramR Created
//
//--------------------------------------------------------------------------
SCODE STDMETHODCALLTYPE CScopeEnum::IsInScope( BOOL *pfInScope )
{
if ( widInvalid == _widPrimedForPropRetrieval )
return CI_E_WORKID_NOTVALID;
*pfInScope = TRUE;
return S_OK;
}
//+-------------------------------------------------------------------------
//
// Member: CScopeEnum::Begin
//
// Synopsis: Begins an enumeration
//
// History: 12-Dec-96 SitaramR Created
//
//--------------------------------------------------------------------------
SCODE STDMETHODCALLTYPE CScopeEnum::Begin()
{
SCODE sc = S_OK;
TRY
{
Win4Assert( _stack.Count() == 0 );
Win4Assert( _hDir == INVALID_HANDLE_VALUE );
Win4Assert( _xDirStackEntry.IsNull() );
Win4Assert( _pCurEntry == 0 );
_VPath.Length = flagNoValueYet;
_Path.Buffer = 0;
if ( RTScope == _scope.Type() )
{
PushScope( (CScopeRestriction const &) _scope );
}
else if ( RTOr == _scope.Type() )
{
CNodeRestriction const & node = * _scope.CastToNode();
for ( ULONG x = 0; x < node.Count(); x++ )
{
Win4Assert( RTScope == node.GetChild( x )->Type() );
PushScope( * (CScopeRestriction *) node.GetChild( x ) );
}
}
//
// Adjust 'percent-done' counters.
//
if ( _stack.Count() > 1 )
{
ULONG cPerDir = 10000 / _stack.Count();
ULONG cLow = 0;
for ( unsigned i = 1; i <= _stack.Count(); i++ )
{
CDirStackEntry * pEntry = _stack.Get( _stack.Count() - i );
pEntry->SetLowValue( cLow );
cLow += cPerDir;
pEntry->SetHighValue( cLow );
Win4Assert( pEntry->IsRangeOK() );
cLow++;
}
_stack.Get( 0 )->SetHighValue( 10000 );
Win4Assert( _stack.Get( 0 )->IsRangeOK() );
_iFirstSubDir = _stack.Count() + 1;
}
//
// Get first object
//
_widCurrent = NextObject();
}
CATCH( CException, e )
{
sc = e.GetErrorCode();
vqDebugOut(( DEB_ERROR, "CScopeEnum::Begin - Exception caught 0x%x\n", sc ));
}
END_CATCH;
return sc;
}
//+-------------------------------------------------------------------------
//
// Member: CScopeEnum::CurrentDocument
//
// Synopsis: Returns current document
//
// Arguments: [pWorkId] -- Wid of current doc returned here
//
// History: 12-Dec-96 SitaramR Created
//
//--------------------------------------------------------------------------
SCODE STDMETHODCALLTYPE CScopeEnum::CurrentDocument( WORKID *pWorkId )
{
*pWorkId = _widCurrent;
if ( _widCurrent == widInvalid )
return CI_S_END_OF_ENUMERATION;
else
return S_OK;
}
//+-------------------------------------------------------------------------
//
// Member: CScopeEnum::NextDocument
//
// Synopsis: Returns next document
//
// Arguments: [pWorkId] -- Wid of next doc returned here
//
// History: 12-Dec-96 SitaramR Created
//
//--------------------------------------------------------------------------
SCODE STDMETHODCALLTYPE CScopeEnum::NextDocument( WORKID *pWorkId )
{
SCODE sc = S_OK;
TRY
{
_widCurrent = NextObject();
sc = CurrentDocument( pWorkId );
}
CATCH( CException, e )
{
sc = e.GetErrorCode();
vqDebugOut(( DEB_ERROR,
"CScopeEnum::NextDocument - Exception caught 0x%x\n",
sc ));
}
END_CATCH;
return sc;
}
//+-------------------------------------------------------------------------
//
// Member: CScopeEnum::End
//
// Synopsis: Ends an enumeration
//
// History: 12-Dec-96 SitaramR Created
//
//--------------------------------------------------------------------------
SCODE STDMETHODCALLTYPE CScopeEnum::End()
{
SCODE sc = S_OK;
TRY
{
_stack.Clear();
if ( INVALID_HANDLE_VALUE != _hDir )
{
NtClose( _hDir );
_hDir = INVALID_HANDLE_VALUE;
}
_xDirStackEntry.Free();
_pCurEntry = 0;
}
CATCH( CException, e )
{
sc = e.GetErrorCode();
vqDebugOut(( DEB_ERROR,
"CScopeEnum::End - Exception caught 0x%x\n",
sc ));
}
END_CATCH;
return sc;
} //End
//+-------------------------------------------------------------------------
//
// Method: CScopeEnum::AddRef
//
// Synopsis: Increments refcount
//
// History: 12-Dec-1996 SitaramR Created
//
//--------------------------------------------------------------------------
ULONG STDMETHODCALLTYPE CScopeEnum::AddRef()
{
return CGenericPropRetriever::AddRef();
}
//+-------------------------------------------------------------------------
//
// Method: CScopeEnum::Release
//
// Synopsis: Decrement refcount. Delete if necessary.
//
// History: 12-Dec-1996 SitaramR Created
//
//--------------------------------------------------------------------------
ULONG STDMETHODCALLTYPE CScopeEnum::Release()
{
return CGenericPropRetriever::Release();
}
//+-------------------------------------------------------------------------
//
// Method: CScopeEnum::QueryInterface
//
// Synopsis: Rebind to other interface
//
// Arguments: [riid] -- IID of new interface
// [ppvObject] -- New interface * returned here
//
// Returns: S_OK if bind succeeded, E_NOINTERFACE if bind failed
//
// History: 12-Dec-1996 SitaramR Created
//
//--------------------------------------------------------------------------
SCODE STDMETHODCALLTYPE CScopeEnum::QueryInterface(
REFIID riid,
void ** ppvObject)
{
if ( IID_ICiCScopeEnumerator == riid )
*ppvObject = (ICiCScopeEnumerator *)this;
else if ( IID_ICiCPropRetriever == riid )
*ppvObject = (ICiCPropRetriever *)this;
else if ( IID_IUnknown == riid )
*ppvObject = (IUnknown *)(ICiCScopeEnumerator *) this;
else
{
*ppvObject = 0;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}