windows-nt/Source/XPSP1/NT/inetsrv/query/fsci/dll/propret.cxx
2020-09-26 16:20:57 +08:00

1182 lines
35 KiB
C++

//+------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996-2000.
//
// File: propret.cxx
//
// Contents: Generic property retriever filesystems
//
// Classes: CGenericPropRetriever
//
// History: 12-Dec-96 SitaramR Created
//
//-------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <propret.hxx>
#include <seccache.hxx>
//+---------------------------------------------------------------------------
//
// Member: CGenericPropRetriever::CGenericPropRetriever
//
// Synopsis: Extracts property and object tables from the catalog.
//
// Arguments: [cat] -- Catalog
// [pQueryPropMapper] -- Pid Remapper associated with the query
// [secCache] -- Cache of AccessCheck() results
// [pScope] -- Scope (for fixup match) if client is going
// through rdr/svr, else 0.
// [amAlreadyAccessChecked] -- Don't need to re-check for this
// access mask.
//
// History: 21-Aug-91 KyleP Created
//
//----------------------------------------------------------------------------
CGenericPropRetriever::CGenericPropRetriever( PCatalog & cat,
ICiQueryPropertyMapper *pQueryPropMapper,
CSecurityCache & secCache,
CRestriction const * pScope,
ACCESS_MASK amAlreadyAccessChecked )
: _cat( cat ),
_pQueryPropMapper( pQueryPropMapper ),
_secCache( secCache ),
_widPrimedForPropRetrieval( widInvalid ),
_remoteAccess( cat.GetImpersonationTokenCache() ),
_pScope( pScope ),
_ulAttribFilter( cat.GetRegParams()->FilterDirectories() ?
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED :
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_DIRECTORY ),
_pPropRec( 0 ),
_cRefs( 1 ),
_amAlreadyAccessChecked( amAlreadyAccessChecked )
{
}
//+---------------------------------------------------------------------------
//
// Member: CGenericPropRetriever::~CGenericPropRetriever, public
//
// Synopsis: Closes catalog tables associated with this instance.
//
// History: 21-Aug-91 KyleP Created.
//
//----------------------------------------------------------------------------
CGenericPropRetriever::~CGenericPropRetriever()
{
Quiesce();
}
//+-------------------------------------------------------------------------
//
// Method: CGenericPropRetriever::Quiesce, public
//
// Synopsis: Close any open resources.
//
// History: 3-May-1994 KyleP Created
//
//--------------------------------------------------------------------------
void CGenericPropRetriever::Quiesce()
{
_propMgr.Close();
_cat.CloseValueRecord( _pPropRec );
_pPropRec = 0;
}
//+---------------------------------------------------------------------------
//
// Member: CGenericPropRetriever::RetrieveValueByPid
//
// Effects: Fetch value from the property cache.
//
// Arguments: [pid] -- Property to fetch
// [pbData] -- Place to return the value
// [pcb] -- On input, the maximum number of bytes to
// write at pbData. On output, the number of
// bytes written if the call was successful,
// else the number of bytes required.
//
// History: 12-Dec-96 SitaramR Created
//
//----------------------------------------------------------------------------
inline BYTE * PastHeader( PROPVARIANT * ppv )
{
return( (BYTE *)ppv + sizeof( PROPVARIANT ) );
}
SCODE STDMETHODCALLTYPE CGenericPropRetriever::RetrieveValueByPid( PROPID pid,
PROPVARIANT *pbData,
ULONG *pcb )
{
static const UNICODE_STRING EmptyUnicodeString = { 0, 0, 0 };
if ( widInvalid == _widPrimedForPropRetrieval )
return CI_E_WORKID_NOTVALID;
SCODE sc = S_OK;
TRY
{
unsigned cb = sizeof( PROPVARIANT );
//
// System properties are retrieved directly from FindFirst buffer.
// User properties must be retrieved through the standard retrieval
// mechanism.
//
switch ( pid )
{
case pidDirectory:
{
pbData->vt = VT_LPWSTR;
pbData->pwszVal = (WCHAR *)PastHeader(pbData);
unsigned cbExtra = 0;
// If the client is remote, apply the fixup to the path
if ( IsClientRemote() )
{
XGrowable<WCHAR> xwcBuf;
cbExtra = BuildPath( GetPath(),
& EmptyUnicodeString,
xwcBuf );
if ( 0 != cbExtra )
{
unsigned cwcBuf = ( *pcb - sizeof PROPVARIANT ) / sizeof WCHAR;
unsigned cwc = FixupPath( xwcBuf.Get(),
pbData->pwszVal,
cwcBuf );
cbExtra = (1 + cwc) * sizeof WCHAR;
}
}
else
{
cbExtra = BuildPath( GetPath(),
& EmptyUnicodeString,
pbData->pwszVal,
*pcb - sizeof PROPVARIANT );
}
if ( 0 == cbExtra )
pbData->vt = VT_EMPTY;
else
cb += cbExtra;
break;
}
case pidClassId:
{
//
// If it's a Docfile, retrieve the class ID from the Docfile,
// otherwise, just return a default file or directory class id.
//
pbData->vt = VT_CLSID;
cb += sizeof( GUID );
if ( cb <= *pcb )
{
pbData->puuid = (GUID *)PastHeader(pbData);
SCODE sc = E_FAIL;
CFunnyPath funnyBuf;
if ( 0 == BuildPath( GetPath(), GetName(), funnyBuf ) )
{
pbData->vt = VT_EMPTY;
cb -= sizeof(GUID);
}
else
{
//
// Try to retrieve the class id
//
sc = GetClassFile ( funnyBuf.GetPath(), pbData->puuid );
if ( FAILED(sc) )
{
// OLE was unable to obtain or infer the class id
cb -= sizeof( GUID );
pbData->vt = VT_EMPTY;
}
}
}
break;
}
case pidPath:
{
pbData->vt = VT_LPWSTR;
pbData->pwszVal = (WCHAR *)PastHeader(pbData);
unsigned cbExtra = 0;
// If the client is remote, apply the fixup to the path
if ( IsClientRemote() )
{
XGrowable<WCHAR> xwcBuf;
cbExtra = BuildPath( GetPath(),
GetName(),
xwcBuf );
if ( 0 != cbExtra )
{
unsigned cwcBuf = ( *pcb - sizeof PROPVARIANT ) / sizeof WCHAR;
unsigned cwc = FixupPath( xwcBuf.Get(),
pbData->pwszVal,
cwcBuf );
cbExtra = (1 + cwc) * sizeof WCHAR;
}
}
else
{
cbExtra = BuildPath( GetPath(),
GetName(),
pbData->pwszVal,
*pcb - sizeof PROPVARIANT );
}
if ( 0 == cbExtra )
pbData->vt = VT_EMPTY;
else
cb += cbExtra;
break;
}
case pidVirtualPath:
{
UNICODE_STRING const * pPath = GetVirtualPath();
if ( 0 == pPath )
pbData->vt = VT_EMPTY;
else
{
pbData->vt = VT_LPWSTR;
pbData->pwszVal = (WCHAR *)PastHeader(pbData);
cb += BuildPath( pPath, GetName(), pbData->pwszVal, *pcb - sizeof(PROPVARIANT) );
}
break;
}
case pidName:
cb = *pcb;
StringToVariant( GetName(), pbData, &cb );
break;
case pidShortName:
cb = *pcb;
StringToVariant( GetShortName(), pbData, &cb );
break;
case pidLastChangeUsn:
pbData->vt = VT_I8;
pbData->hVal.QuadPart = 1; // First legal USN
break;
case pidSize:
pbData->vt = VT_I8;
pbData->hVal.QuadPart = ObjectSize();
if ( pbData->hVal.QuadPart == 0xFFFFFFFFFFFFFFFF )
pbData->vt = VT_EMPTY;
#if CIDBG == 1
if ( VT_I8 == pbData->vt )
Win4Assert( 0xdddddddddddddddd != pbData->hVal.QuadPart );
#endif // CIDBG == 1
break;
case pidAttrib:
pbData->vt = VT_UI4;
pbData->ulVal = Attributes();
if ( pbData->ulVal == 0xFFFFFFFF )
pbData->vt = VT_EMPTY;
#if CIDBG == 1
if ( VT_UI4 == pbData->vt )
Win4Assert( 0xdddddddd != pbData->ulVal );
#endif // CIDBG == 1
break;
case pidWriteTime:
pbData->vt = VT_FILETIME;
pbData->hVal.QuadPart = ModifyTime();
if ( pbData->hVal.QuadPart == 0xFFFFFFFFFFFFFFFF )
pbData->vt = VT_EMPTY;
break;
case pidCreateTime:
pbData->vt = VT_FILETIME;
pbData->hVal.QuadPart = CreateTime();
if ( pbData->hVal.QuadPart == 0xFFFFFFFFFFFFFFFF )
pbData->vt = VT_EMPTY;
break;
case pidAccessTime:
pbData->vt = VT_FILETIME;
pbData->hVal.QuadPart = AccessTime();
if ( pbData->hVal.QuadPart == 0xFFFFFFFFFFFFFFFF )
pbData->vt = VT_EMPTY;
break;
case pidStorageType:
pbData->vt = VT_UI4;
pbData->ulVal = StorageType();
if ( 0xFFFFFFFF == pbData->ulVal )
{
//
// Try VRootType
//
if ( GetVRootType( pbData->ulVal ) )
{
if ( pbData->ulVal & PCatalog::NNTPRoot )
pbData->ulVal = 1;
else
pbData->ulVal = 0;
}
else
pbData->vt = VT_EMPTY;
}
break;
case pidPropertyStoreLevel:
pbData->vt = VT_UI4;
pbData->ulVal = StorageLevel();
break;
case pidPropDataModifiable:
pbData->vt = VT_BOOL;
pbData->boolVal = IsModifiable() ? VARIANT_TRUE : VARIANT_FALSE;
break;
case pidVRootUsed:
{
if ( GetVRootType( pbData->ulVal ) )
{
pbData->vt = VT_BOOL;
if ( pbData->ulVal & PCatalog::UsedRoot )
pbData->boolVal = VARIANT_TRUE;
else
pbData->boolVal = VARIANT_FALSE;
}
else
pbData->vt = VT_EMPTY;
break;
}
case pidVRootAutomatic:
{
if ( GetVRootType( pbData->ulVal ) )
{
pbData->vt = VT_BOOL;
if ( pbData->ulVal & PCatalog::AutomaticRoot )
pbData->boolVal = VARIANT_TRUE;
else
pbData->boolVal = VARIANT_FALSE;
}
else
pbData->vt = VT_EMPTY;
break;
}
case pidVRootManual:
{
if ( GetVRootType( pbData->ulVal ) )
{
pbData->vt = VT_BOOL;
if ( pbData->ulVal & PCatalog::ManualRoot )
pbData->boolVal = VARIANT_TRUE;
else
pbData->boolVal = VARIANT_FALSE;
}
else
pbData->vt = VT_EMPTY;
break;
}
case pidPropertyGuid:
cb += sizeof( GUID );
if ( cb <= *pcb )
{
pbData->puuid = (GUID *)PastHeader(pbData);
if ( GetPropGuid( *pbData->puuid ) )
pbData->vt = VT_CLSID;
else
{
cb -= sizeof(GUID);
pbData->vt = VT_EMPTY;
}
}
break;
case pidPropertyDispId:
pbData->ulVal = GetPropPropid();
if ( pbData->ulVal == pidInvalid )
pbData->vt = VT_EMPTY;
else
pbData->vt = VT_UI4;
break;
case pidPropertyName:
cb = *pcb;
StringToVariant( GetPropName(), pbData, &cb );
break;
default:
{
//
// First, try the property cache.
//
cb = *pcb;
BOOL fTryOLE = TRUE;
if ( FetchValue( pid, pbData, &cb ) )
{
fTryOLE = FALSE;
if ( ( cb <= *pcb ) &&
( IsNullPointerVariant( pbData ) ) )
{
pbData->vt = VT_EMPTY;
cb = sizeof( PROPVARIANT );
}
// If we got back VT_EMPTY, it may be because the file has
// been scanned and not filtered. If there is no write time,
// the file hasn't been filtered yet, so trying OLE to load
// the value is worth it.
if ( VT_EMPTY == pbData->vt )
{
PROPVARIANT vWrite;
vWrite.vt = VT_EMPTY;
unsigned cbWrite = sizeof vWrite;
FetchValue( pidWriteTime, &vWrite, &cbWrite );
if ( VT_EMPTY == vWrite.vt )
fTryOLE = TRUE;
}
}
if ( fTryOLE )
{
CImpersonateClient impClient( GetClientToken() );
if ( !_propMgr.isOpen() )
{
//
// Get a full, null-terminated, path.
//
CFunnyPath funnyBuf;
if ( 0 != BuildPath( GetPath(),
GetName(),
funnyBuf ) )
{
// Open property manager.
if ( CImpersonateRemoteAccess::IsNetPath( funnyBuf.GetActualPath() ) )
{
UNICODE_STRING const * pVPath = GetVirtualPath();
WCHAR const * pwszVPath = 0 != pVPath ? pVPath->Buffer : 0;
if ( !_remoteAccess.ImpersonateIfNoThrow( funnyBuf.GetActualPath(),
pwszVPath ) )
{
return CI_E_LOGON_FAILURE;
}
}
else if ( _remoteAccess.IsImpersonated() )
{
_remoteAccess.Release();
}
BOOL fSharingViolation = _propMgr.Open( funnyBuf );
if ( fSharingViolation )
return CI_E_SHARING_VIOLATION;
}
}
FULLPROPSPEC const *pPropSpec;
SCODE sc = _pQueryPropMapper->PropidToProperty( pid, &pPropSpec );
if ( FAILED( sc ) )
{
Win4Assert( !"PropidToProperty failed" );
THROW ( CException( sc ) );
}
CFullPropSpec const * ps = (CFullPropSpec const *) pPropSpec;
cb = *pcb;
_propMgr.FetchProperty( ps->GetPropSet(),
ps->GetPropSpec(),
pbData,
&cb );
}
break;
}
} // case
if ( cb <= *pcb )
{
*pcb = cb;
#if CIDBG == 1
CStorageVariant var( *pbData );
vqDebugOut(( DEB_PROPTIME, "Fetched value (pid = 0x%x): ", pid ));
var.DisplayVariant( DEB_PROPTIME | DEB_NOCOMPNAME, 0 );
vqDebugOut(( DEB_PROPTIME | DEB_NOCOMPNAME, "\n" ));
#endif
}
else
{
*pcb = cb;
vqDebugOut(( DEB_PROPTIME, "Failed to fetch value (pid = 0x%x)\n", pid ));
sc = CI_E_BUFFERTOOSMALL ;
}
}
CATCH( CException, e )
{
sc = e.GetErrorCode();
vqDebugOut(( DEB_ERROR,
"CGenericPropRetriever::RetrieveValueByPid - Exception caught 0x%x\n",
sc ));
}
END_CATCH;
return sc;
}
//+---------------------------------------------------------------------------
//
// Member: CGenericPropRetriever::StringToVariant, private
//
// Arguments: [pString] -- String to copy.
// [pbData] -- String stored here.
// [pcb] -- On input: max length in bytes of [pbData].
// On output: size required by [pString]. If
// less-than-or-equal-to input size, then string
// was copied.
//
// History: 17-Jul-95 KyleP Created header.
//
//----------------------------------------------------------------------------
void CGenericPropRetriever::StringToVariant( UNICODE_STRING const * pString,
PROPVARIANT * pbData,
unsigned * pcb )
{
unsigned cb = sizeof(PROPVARIANT);
if ( 0 == pString || 0 == pString->Length )
{
pbData->vt = VT_EMPTY;
}
else
{
pbData->vt = VT_LPWSTR;
cb += pString->Length + sizeof( WCHAR ); // For L'\0' at end.
if ( cb <= *pcb )
{
WCHAR * pwcName = (WCHAR *)PastHeader(pbData);
pbData->pwszVal = pwcName;
RtlCopyMemory( pwcName,
pString->Buffer,
pString->Length );
pwcName[pString->Length/sizeof(WCHAR)] = L'\0';
}
}
*pcb = cb;
}
//+---------------------------------------------------------------------------
//
// Member: CGenericPropRetriever::BuildPath, private
//
// Synopsis: Gloms path + filename together
//
// Arguments: [pPath] -- Path, sans filename
// [pFilename] -- Filename
// [funnyBuf] -- Full path copied here.
//
// Returns: Size in **bytes** of full path. 0 --> No path
//
// History: 04-Jun-98 VikasMan Created
//
//----------------------------------------------------------------------------
unsigned CGenericPropRetriever::BuildPath( UNICODE_STRING const * pPath,
UNICODE_STRING const * pFilename,
CFunnyPath & funnyBuf)
{
if ( 0 == pPath || 0 == pPath->Length || 0 == pFilename )
return 0;
funnyBuf.SetPath( pPath->Buffer, pPath->Length/sizeof(WCHAR) );
if ( pFilename->Length > 0 )
{
funnyBuf.AppendBackSlash();
funnyBuf.AppendPath( pFilename->Buffer, pFilename->Length/sizeof(WCHAR) );
}
return funnyBuf.GetLength() * sizeof(WCHAR);
}
//+---------------------------------------------------------------------------
//
// Member: CGenericPropRetriever::BuildPath, private
//
// Synopsis: Gloms path + filename together
//
// Arguments: [pPath] -- Path, sans filename
// [pFilename] -- Filename
// [xwcBuf] -- Full path copied here.
//
// Returns: Size in **bytes** of full path. 0 --> No path
//
// History: 04-Jun-98 VikasMan Created
//
//----------------------------------------------------------------------------
unsigned CGenericPropRetriever::BuildPath( UNICODE_STRING const * pPath,
UNICODE_STRING const * pFilename,
XGrowable<WCHAR> & xwcBuf)
{
if ( 0 == pPath || 0 == pFilename )
return 0;
unsigned cb = pPath->Length +
pFilename->Length +
sizeof WCHAR; // L'\0' at end
if ( pFilename->Length > 0 )
cb += sizeof WCHAR; // L'\\' between path and filename
xwcBuf.SetSizeInBytes( cb );
return BuildPath( pPath, pFilename, xwcBuf.Get(), cb );
}
//+---------------------------------------------------------------------------
//
// Member: CGenericPropRetriever::BuildPath, private
//
// Synopsis: Gloms path + filename together
//
// Arguments: [pPath] -- Path, sans filename
// [pFilename] -- Filename
// [pwcBuf] -- Full path copied here.
// [cbBuf] -- Size in **bytes** of pwcBuf.
//
// Returns: Size in **bytes** of full path. Path only built if return
// value is <= [cbBuf]. 0 --> No path
//
// History: 07-Feb-96 KyleP Created header.
//
//----------------------------------------------------------------------------
unsigned CGenericPropRetriever::BuildPath( UNICODE_STRING const * pPath,
UNICODE_STRING const * pFilename,
WCHAR * pwcBuf,
unsigned cbBuf )
{
if ( 0 == pPath || 0 == pFilename )
return 0;
unsigned cb = pPath->Length +
pFilename->Length +
sizeof WCHAR; // L'\0' at end
if ( pFilename->Length > 0 )
cb += sizeof WCHAR; // L'\\' between path and filename
if ( cb <= cbBuf )
{
RtlCopyMemory( pwcBuf, pPath->Buffer, pPath->Length );
pwcBuf += pPath->Length/sizeof(WCHAR);
if ( pFilename->Length > 0 )
{
*pwcBuf++ = L'\\';
RtlCopyMemory( pwcBuf,
pFilename->Buffer,
pFilename->Length );
pwcBuf += pFilename->Length / sizeof WCHAR;
}
*pwcBuf = 0;
}
return cb;
}
//+---------------------------------------------------------------------------
//
// Member: CGenericPropRetriever::FetchValue, protected
//
// Effects: Fetch value from the property cache.
//
// Arguments: [pid] -- Property to fetch
// [pbData] -- Place to return the value
// [pcb] -- On input, the maximum number of bytes to
// write at pbData. On output, the number of
// bytes written if the call was successful,
// else the number of bytes required.
//
// Returns: TRUE if property was fetched
//
// History: 03-Apr-96 KyleP Created.
//
//----------------------------------------------------------------------------
BOOL CGenericPropRetriever::FetchValue( PROPID pid, PROPVARIANT * pbData, unsigned * pcb )
{
OpenPropertyRecord();
return _cat.FetchValue( _pPropRec, pid, pbData, pcb );
}
//+-------------------------------------------------------------------------
//
// Member: CGenericPropRetriever::CheckSecurity
//
// Synopsis: Test wid for security access
//
// Arguments: [am] -- Access Mask
// [pfGranted] -- Result of security check returned here
//
// History: 19-Aug-93 KyleP Created
//
//--------------------------------------------------------------------------
SCODE STDMETHODCALLTYPE CGenericPropRetriever::CheckSecurity( ACCESS_MASK am,
BOOL *pfGranted)
{
//
// No need to impersonate the client because the Win32 AccessCheck API
// takes a client token as a parameter
//
SCODE sc = S_OK;
TRY
{
if ( _widPrimedForPropRetrieval == widInvalid )
sc = CI_E_WORKID_NOTVALID;
else
{
OpenPropertyRecord();
if ( am != _amAlreadyAccessChecked )
{
SDID sdid = _cat.FetchSDID( _pPropRec,
_widPrimedForPropRetrieval );
*pfGranted = _secCache.IsGranted( sdid, am );
}
else
*pfGranted = TRUE;
}
}
CATCH( CException, e )
{
sc = e.GetErrorCode();
vqDebugOut(( DEB_ERROR,
"CGenericPropRetriever::CheckSecurity - Exception caught 0x%x\n",
sc ));
}
END_CATCH;
return sc;
}
//+-------------------------------------------------------------------------
//
// Member: CGenericPropRetriever::EndPropertyRetrieval
//
// Synopsis: Reset wid for property retrieval
//
// History: 12-Dec-96 SitaramR Created
//
//--------------------------------------------------------------------------
SCODE STDMETHODCALLTYPE CGenericPropRetriever::EndPropertyRetrieval()
{
Win4Assert( _widPrimedForPropRetrieval != widInvalid );
SCODE sc = S_OK;
TRY
{
Quiesce();
if ( _remoteAccess.IsImpersonated() )
_remoteAccess.Release();
_widPrimedForPropRetrieval = widInvalid;
}
CATCH( CException, e )
{
sc = e.GetErrorCode();
vqDebugOut(( DEB_ERROR,
"CGenericPropRetriever::EndPropertyRetrieval - Exception caught 0x%x\n",
sc ));
}
END_CATCH;
return sc;
}
//+-------------------------------------------------------------------------
//
// Method: CGenericPropRetriever::AddRef
//
// Synopsis: Increments refcount
//
// History: 12-Dec-1996 SitaramR Created
//
//--------------------------------------------------------------------------
ULONG STDMETHODCALLTYPE CGenericPropRetriever::AddRef()
{
return InterlockedIncrement( (long *) &_cRefs );
}
//+-------------------------------------------------------------------------
//
// Method: CGenericPropRetriever::Release
//
// Synopsis: Decrement refcount. Delete if necessary.
//
// History: 12-Dec-1996 SitaramR Created
//
//--------------------------------------------------------------------------
ULONG STDMETHODCALLTYPE CGenericPropRetriever::Release()
{
Win4Assert( _cRefs > 0 );
ULONG uTmp = InterlockedDecrement( (long *) &_cRefs );
if ( 0 == uTmp )
delete this;
return uTmp;
}
//+-------------------------------------------------------------------------
//
// Method: CGenericPropRetriever::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 CGenericPropRetriever::QueryInterface(
REFIID riid,
void ** ppvObject)
{
*ppvObject = 0;
if ( IID_ICiCPropRetriever == riid )
*ppvObject = (IUnknown *)(ICiCPropRetriever *)this;
else if ( IID_IUnknown == riid )
*ppvObject = (IUnknown *)this;
else
return E_NOINTERFACE;
AddRef();
return S_OK;
}
//+-------------------------------------------------------------------------
//
// Method: CGenericPropRetriever::FetchPath, protected
//
// Synopsis: Reads the path from the open property record
//
// Arguments: [pwcPath] -- where to put the path
// [cwc] -- size of the buffer in/out in characters
//
// History: 15-Jan-1998 dlee Created
//
//--------------------------------------------------------------------------
void CGenericPropRetriever::FetchPath(
WCHAR * pwcPath,
unsigned & cwc )
{
PROPVARIANT var;
unsigned cb = cwc * sizeof WCHAR;
if ( _cat.FetchValue( GetPropertyRecord(),
pidPath,
&var,
(BYTE *) pwcPath,
&cb ) )
cwc = cb / sizeof WCHAR;
else
cwc = 0;
} //FetchPath
//+-------------------------------------------------------------------------
//
// Method: CGenericPropRetriever::FixupPath, private
//
// Synopsis: Fixes up path (e.g. converts E:\Foo --> \\KyleP-1\RootE\Foo)
//
// Arguments: [pwcsPath] -- Source (local) path
// [pwcsFixup] -- Aliased result
// [cwcFixup] -- Count of characters in [pwcsFixup].
//
// Returns: Count of characters that are in [pwcsFixup]. If return
// value is larger than [cwcFixup] then nothing was copied.
//
// History: 01-Oct-1998 KyleP Created (from ciprop.cxx vroot equivalent)
//
//--------------------------------------------------------------------------
unsigned CGenericPropRetriever::FixupPath( WCHAR const * pwcsPath,
WCHAR * pwcsFixup,
unsigned cwcFixup )
{
BOOL fUseAnyPath = FALSE;
unsigned cwc = 0;
if ( RTScope == _pScope->Type() )
{
CScopeRestriction const & scp = * (CScopeRestriction *) _pScope;
if ( scp.IsPhysical() )
{
BOOL fUnchanged;
cwc = FetchFixupInScope( pwcsPath,
pwcsFixup,
cwcFixup,
scp.GetPath(),
scp.PathLength(),
scp.IsDeep(),
fUnchanged );
Win4Assert( cwc > 0 );
}
else
fUseAnyPath = TRUE;
}
else if ( RTOr == _pScope->Type() )
{
CNodeRestriction const & node = * _pScope->CastToNode();
fUseAnyPath = TRUE;
for ( ULONG x = 0; x < node.Count(); x++ )
{
Win4Assert( RTScope == node.GetChild( x )->Type() );
CScopeRestriction const & scp = * (CScopeRestriction *)
node.GetChild( x );
if ( scp.IsPhysical() )
{
BOOL fUnchanged;
cwc = FetchFixupInScope( pwcsPath,
pwcsFixup,
cwcFixup,
scp.GetPath(),
scp.PathLength(),
scp.IsDeep(),
fUnchanged );
if ( cwc > 0 && !fUnchanged )
{
fUseAnyPath = FALSE;
break;
}
}
}
}
//
// If no fixup works for the file, use the first match to physical scope.
//
if ( fUseAnyPath )
cwc = _cat.FixupPath( pwcsPath,
pwcsFixup,
cwcFixup,
0 );
return cwc;
} //FixupPath
//+-------------------------------------------------------------------------
//
// Method: CGenericPropRetriever::FetchFixupInScope, private
//
// Synopsis: Worker subroutine for FixupPath
//
// Arguments: [pwcsPath] -- Source (local) path
// [pwcsFixup] -- Aliased result
// [cwcFixup] -- Count of characters in [pwcsFixup].
// [pwcRoot] -- Root scope (must match alias)
// [cwcRoot] -- Size (in chars) of [pwcRoot]
// [fDeep] -- True if [pwcRoot] is a deep scope.
//
// Returns: Count of characters that are in [pwcsFixup]. If return
// value is larger than [cwcFixup] then nothing was copied.
//
// History: 01-Oct-1998 KyleP Created (from ciprop.cxx vroot equivalent)
//
//--------------------------------------------------------------------------
unsigned CGenericPropRetriever::FetchFixupInScope( WCHAR const * pwcsPath,
WCHAR * pwcsFixup,
unsigned cwcFixup,
WCHAR const * pwcRoot,
unsigned cwcRoot,
BOOL fDeep,
BOOL & fUnchanged )
{
fUnchanged = FALSE;
CScopeMatch Match( pwcRoot, cwcRoot );
unsigned cSkip = 0;
unsigned cwcPath = 0;
unsigned cwcMaxPath = 0; // Used to hold longest path (when cwcFixup == 0)
unsigned cwcOriginalPath = wcslen( pwcsPath );
while ( TRUE )
{
cwcPath = _cat.FixupPath( pwcsPath,
pwcsFixup,
cwcFixup,
cSkip );
if ( 0 == cwcPath )
return cwcMaxPath;
//
// If no fixups matched, return the original path
//
if ( cwcPath == cwcOriginalPath &&
RtlEqualMemory( pwcsPath, pwcsFixup, cwcPath * sizeof WCHAR ) )
{
fUnchanged = TRUE;
return cwcPath;
}
//
// In scope?
//
if ( cwcPath > cwcFixup || !Match.IsInScope( pwcsFixup, cwcFixup ) )
{
cSkip++;
//
// Update max fixup size if we're polling for space requirements.
//
if ( cwcPath > cwcFixup && cwcPath > cwcMaxPath )
cwcMaxPath = cwcPath;
continue;
}
Win4Assert( 0 == pwcsFixup[cwcPath] );
//
// If the scope is shallow, check that it's still in scope
//
if ( !fDeep )
{
unsigned cwcName = 0;
WCHAR * pwcName = pwcsFixup + cwcPath - 1;
while ( L'\\' != *pwcName )
{
Win4Assert( cwcName < cwcPath );
cwcName++;
pwcName--;
}
unsigned cwcJustPath = cwcPath - cwcName - 1;
BOOL fTooDeep = cwcJustPath > cwcRoot;
if ( fTooDeep )
{
cSkip++;
continue;
}
else
break;
}
else
break;
}
if (0 == cwcMaxPath)
return cwcPath;
else
return cwcMaxPath;
} //FetchFixupInScope