1124 lines
34 KiB
C++
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|