1471 lines
42 KiB
C++
1471 lines
42 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1991 - 1999.
|
||
|
//
|
||
|
// File: VMap.cxx
|
||
|
//
|
||
|
// Contents: Virtual <--> physical path map.
|
||
|
//
|
||
|
// Classes: CVMap
|
||
|
//
|
||
|
// History: 05-Feb-96 KyleP Created
|
||
|
//
|
||
|
// Notes: Automatic and manual roots have the following relationship.
|
||
|
//
|
||
|
// 1. If a root is purely manual (e.g. not in Gibraltar), then
|
||
|
// addition is only by the user, and deletion really deletes
|
||
|
// the root. A placeholder is not maintained in the vroot
|
||
|
// list.
|
||
|
//
|
||
|
// 2. If a root is purely automatic, then it is always used,
|
||
|
// and is added and removed in complete sync with Gibraltar.
|
||
|
//
|
||
|
// 3. If a root was manual and was automatically added, the 'in-use'
|
||
|
// state from pure-manual mode is maintained.
|
||
|
//
|
||
|
// 4. If a root was automatic and was manually added, it is
|
||
|
// always set to 'in-use'.
|
||
|
//
|
||
|
// 5. If a root was both manual and automatic and automaticlly
|
||
|
// deleted the deletion occurs. Period.
|
||
|
//
|
||
|
// 6. If a root was both manual and automatic and manually deleted,
|
||
|
// the root is kept as an out-of-use placeholder.
|
||
|
//
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include <pch.cxx>
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include <rcstxact.hxx>
|
||
|
#include <rcstrmit.hxx>
|
||
|
|
||
|
#include <vmap.hxx>
|
||
|
#include <funypath.hxx>
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CVMapDesc::Init, public
|
||
|
//
|
||
|
// Synopsis: Initialize virtual root descriptor
|
||
|
//
|
||
|
// Arguments: [pVRoot] -- Virtual root
|
||
|
// [ccVRoot] -- Size in chars of [pwcVRoot]
|
||
|
// [pPRoot] -- Physical root
|
||
|
// [ccPRoot] -- Size in chars of [pwcPRoot]
|
||
|
// [idParent] -- Link to parent
|
||
|
// [fAutomatic] -- TRUE for root tied to IIS
|
||
|
// [eType] -- VRoot type
|
||
|
// [fIsIndexed] -- TRUE if the item should be indexed (used)
|
||
|
// [fNonIndexedVDir] -- TRUE if a non-indexed virtual directory
|
||
|
//
|
||
|
// History: 11-Feb-96 KyleP Created
|
||
|
// 24 Nov 99 KLam Don't pre-reference zero length strings.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void CVMapDesc::Init( WCHAR const * pVRoot,
|
||
|
ULONG ccVRoot,
|
||
|
WCHAR const * pPRoot,
|
||
|
ULONG ccPRoot,
|
||
|
ULONG idParent,
|
||
|
BOOL fAutomatic,
|
||
|
CiVRootTypeEnum eType,
|
||
|
BOOL fIsIndexed,
|
||
|
BOOL fNonIndexedVDir )
|
||
|
{
|
||
|
Win4Assert( ccVRoot < MAX_PATH );
|
||
|
Win4Assert( ccPRoot < MAX_PATH );
|
||
|
|
||
|
RtlCopyMemory( _wcVScope, pVRoot, ccVRoot * sizeof(WCHAR ) );
|
||
|
RtlCopyMemory( _wcPScope, pPRoot, ccPRoot * sizeof(WCHAR ) );
|
||
|
|
||
|
_ccVScope = ccVRoot;
|
||
|
_ccPScope = ccPRoot;
|
||
|
if ( (0 == _ccVScope) || (_wcVScope[_ccVScope - 1] != L'\\') )
|
||
|
_wcVScope[_ccVScope++] = L'\\';
|
||
|
|
||
|
if ( (0 == _ccPScope) || (_wcPScope[_ccPScope - 1] != L'\\') )
|
||
|
_wcPScope[_ccPScope++] = L'\\';
|
||
|
|
||
|
// null-terminate these for readability
|
||
|
|
||
|
_wcVScope[ _ccVScope ] = 0;
|
||
|
_wcPScope[ _ccPScope ] = 0;
|
||
|
|
||
|
_idParent = idParent;
|
||
|
|
||
|
if ( fAutomatic )
|
||
|
_Type = PCatalog::AutomaticRoot;
|
||
|
else
|
||
|
_Type = PCatalog::ManualRoot;
|
||
|
|
||
|
if ( fIsIndexed )
|
||
|
_Type |= PCatalog::UsedRoot;
|
||
|
|
||
|
if ( fNonIndexedVDir )
|
||
|
_Type |= PCatalog::NonIndexedVDir;
|
||
|
|
||
|
#if CIDBG == 1
|
||
|
if ( fNonIndexedVDir )
|
||
|
Win4Assert( !fIsIndexed );
|
||
|
#endif // CIDBG == 1
|
||
|
|
||
|
if ( NNTPVRoot == eType )
|
||
|
_Type |= PCatalog::NNTPRoot;
|
||
|
else if ( IMAPVRoot == eType )
|
||
|
_Type |= PCatalog::IMAPRoot;
|
||
|
} //Init
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CVMapDesc::IsVirtualMatch, public
|
||
|
//
|
||
|
// Synopsis: Virtual scope test
|
||
|
//
|
||
|
// Arguments: [pVPath] -- Virtual path
|
||
|
// [ccVPath] -- Size in chars of [pVPath]
|
||
|
//
|
||
|
// Returns: TRUE if [pVPath] is an exact match (sans slash)
|
||
|
//
|
||
|
// History: 11-Feb-96 KyleP Created
|
||
|
// 24 Nov 99 KLam Don't pre-reference zero length strings.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CVMapDesc::IsVirtualMatch( WCHAR const * pVPath, unsigned ccVPath ) const
|
||
|
{
|
||
|
//
|
||
|
// Adjust for possible lack of terminating backslash.
|
||
|
//
|
||
|
|
||
|
unsigned ccComp;
|
||
|
|
||
|
if ( (0 == ccVPath) || (pVPath[ccVPath-1] != L'\\') )
|
||
|
ccComp = _ccVScope - 1;
|
||
|
else
|
||
|
ccComp = _ccVScope;
|
||
|
|
||
|
//
|
||
|
// Compare strings.
|
||
|
//
|
||
|
|
||
|
if ( ccComp == ccVPath )
|
||
|
return RtlEqualMemory( _wcVScope, pVPath, ccVPath * sizeof(WCHAR) );
|
||
|
else
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CVMapDesc::IsPhysicalMatch, public
|
||
|
//
|
||
|
// Synopsis: Physical scope test
|
||
|
//
|
||
|
// Arguments: [pPPath] -- Virtual path
|
||
|
// [ccPPath] -- Size in chars of [pPPath]
|
||
|
//
|
||
|
// Returns: TRUE if [pPPath] is an exact match (sans slash)
|
||
|
//
|
||
|
// History: 11-Feb-96 KyleP Created
|
||
|
// 24 Nov 99 KLam Don't pre-reference zero length strings.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CVMapDesc::IsPhysicalMatch( WCHAR const * pPPath, unsigned ccPPath ) const
|
||
|
{
|
||
|
//
|
||
|
// Adjust for possible lack of terminating backslash.
|
||
|
//
|
||
|
|
||
|
unsigned ccComp;
|
||
|
|
||
|
if ( (0 == ccPPath) || (pPPath[ccPPath-1] != L'\\') )
|
||
|
ccComp = _ccPScope - 1;
|
||
|
else
|
||
|
ccComp = _ccPScope;
|
||
|
|
||
|
//
|
||
|
// Compare strings.
|
||
|
//
|
||
|
|
||
|
if ( ccComp == ccPPath )
|
||
|
return RtlEqualMemory( _wcPScope, pPPath, ccPPath * sizeof(WCHAR) );
|
||
|
else
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CVMap::CVMap, public
|
||
|
//
|
||
|
// Synopsis: Null ctor for 2-phase initialization
|
||
|
//
|
||
|
// History: 11-Feb-96 KyleP Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
CVMap::CVMap()
|
||
|
{
|
||
|
END_CONSTRUCTION( CVMap );
|
||
|
}
|
||
|
|
||
|
void CVMap::Empty()
|
||
|
{
|
||
|
delete _xrsoMap.Acquire();
|
||
|
_aMap.Clear();
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CVMap::Init, public
|
||
|
//
|
||
|
// Synopsis: 2nd half of 2-phase initialization
|
||
|
//
|
||
|
// Arguments: [pobj] -- Recoverable storage for descriptors
|
||
|
//
|
||
|
// Returns: TRUE if map was shut down cleanly
|
||
|
//
|
||
|
// History: 11-Feb-96 KyleP Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CVMap::Init( PRcovStorageObj * pobj )
|
||
|
{
|
||
|
_xrsoMap.Set( pobj );
|
||
|
|
||
|
//
|
||
|
// Initialize array.
|
||
|
//
|
||
|
|
||
|
CRcovStorageHdr & hdr = _xrsoMap->GetHeader();
|
||
|
|
||
|
struct CRcovUserHdr data;
|
||
|
hdr.GetUserHdr( hdr.GetPrimary(), data );
|
||
|
|
||
|
RtlCopyMemory( &_fDirty, &data._abHdr, sizeof(_fDirty) );
|
||
|
|
||
|
//
|
||
|
// Load records into memory.
|
||
|
//
|
||
|
|
||
|
CRcovStrmReadTrans xact( _xrsoMap.GetReference() );
|
||
|
CRcovStrmReadIter iter( xact, sizeof( CVMapDesc ) );
|
||
|
|
||
|
unsigned i = 0;
|
||
|
|
||
|
while ( !iter.AtEnd() )
|
||
|
{
|
||
|
iter.GetRec( &_aMap[i] );
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
if (_aMap.Count() != hdr.GetCount( hdr.GetPrimary() ) )
|
||
|
{
|
||
|
ciDebugOut(( DEB_ERROR,
|
||
|
"_aMap.Count() == %d, hdr.GetCount(...) = %d\n",
|
||
|
_aMap.Count(), hdr.GetCount( hdr.GetPrimary() ) ));
|
||
|
}
|
||
|
|
||
|
Win4Assert( _aMap.Count() == hdr.GetCount( hdr.GetPrimary() ) );
|
||
|
|
||
|
RecomputeNonIndexedInfo();
|
||
|
|
||
|
DumpVMap();
|
||
|
|
||
|
return !_fDirty;
|
||
|
} //Init
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CVMap::RecomputeNonIndexedInfo, private
|
||
|
//
|
||
|
// Synopsis: Rebuilds _aExcludeParent when vroot info changes
|
||
|
//
|
||
|
// History: 1-Apr-97 dlee Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void CVMap::RecomputeNonIndexedInfo()
|
||
|
{
|
||
|
// blow away existing info and create it all again
|
||
|
|
||
|
_aExcludeParent.Clear();
|
||
|
|
||
|
for ( unsigned i = 0; i < _aMap.Count(); i++ )
|
||
|
_aExcludeParent[i] = INVALID_VMAP_INDEX;
|
||
|
|
||
|
// look for non-indexed vdirs, and note the vroot that matches
|
||
|
// both virtual and physical paths.
|
||
|
|
||
|
for ( i = 0; i < _aMap.Count(); i++ )
|
||
|
{
|
||
|
if ( !_aMap[i].IsFree() &&
|
||
|
_aMap[i].IsNonIndexedVDir() )
|
||
|
{
|
||
|
unsigned int ccBestMatch = 0;
|
||
|
|
||
|
for ( unsigned r = 0; r < _aMap.Count(); r++ )
|
||
|
{
|
||
|
// if 'i' is in both virtual and physical paths of 'r',
|
||
|
// make 'r' the exclude parent of 'i'.
|
||
|
|
||
|
if ( i != r &&
|
||
|
!_aMap[r].IsFree() &&
|
||
|
!_aMap[r].IsNonIndexedVDir() )
|
||
|
{
|
||
|
// -1 since we don't need to match on the '\' at the end
|
||
|
|
||
|
if ( _aMap[r].IsInPhysicalScope( _aMap[i].PhysicalPath(),
|
||
|
_aMap[i].PhysicalLength() - 1 ) )
|
||
|
{
|
||
|
if ( ( _aMap[r].VirtualLength() < _aMap[i].VirtualLength() ) &&
|
||
|
( _aMap[r].IsVirtualMatch( _aMap[i].VirtualPath(),
|
||
|
_aMap[r].VirtualLength() ) ) )
|
||
|
{
|
||
|
ciDebugOut(( DEB_ITRACE, "nivd %ws found match %ws, old cc %d\n",
|
||
|
_aMap[i].VirtualPath(),
|
||
|
_aMap[r].VirtualPath(),
|
||
|
ccBestMatch ));
|
||
|
|
||
|
if ( _aMap[r].VirtualLength() > ccBestMatch )
|
||
|
{
|
||
|
_aExcludeParent[i] = r;
|
||
|
ccBestMatch = _aMap[r].VirtualLength();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} //RecomputeNonIndexedInfo
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CVMap::DumpVMap, private
|
||
|
//
|
||
|
// Synopsis: Dumps the current state of the vmap table
|
||
|
//
|
||
|
// History: 1-Apr-97 dlee Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void CVMap::DumpVMap()
|
||
|
{
|
||
|
#if CIDBG == 1
|
||
|
for ( unsigned i = 0; i < _aMap.Count(); i++ )
|
||
|
{
|
||
|
ciDebugOut(( DEB_ITRACE,
|
||
|
"vmap 0x%x, isfree %d parent 0x%x\n",
|
||
|
i, _aMap[i].IsFree(), _aMap[i].Parent() ));
|
||
|
|
||
|
if ( !_aMap[i].IsFree() )
|
||
|
ciDebugOut(( DEB_ITRACE,
|
||
|
" expar: 0x%x, nonivdir %d, inuse %d, manual %d, auto %d, nntp %d, imap %d, vpath '%ws', ppath '%ws'\n",
|
||
|
_aExcludeParent[i],
|
||
|
_aMap[i].IsNonIndexedVDir(),
|
||
|
_aMap[i].IsInUse(),
|
||
|
_aMap[i].IsManual(),
|
||
|
_aMap[i].IsAutomatic(),
|
||
|
_aMap[i].IsNNTP(),
|
||
|
_aMap[i].IsIMAP(),
|
||
|
_aMap[i].VirtualPath(),
|
||
|
_aMap[i].PhysicalPath() ));
|
||
|
}
|
||
|
#endif // CIDBG
|
||
|
} //DumpVMap
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CVMap::Add, public
|
||
|
//
|
||
|
// Synopsis: Add new virtual/physical mapping
|
||
|
//
|
||
|
// Arguments: [vroot] -- New virtual root
|
||
|
// [root] -- Place in physical hierarchy
|
||
|
// [fAutomatic] -- TRUE for root tied to Gibraltar
|
||
|
// [idNew] -- Id of new root returned here
|
||
|
// [eType] -- vroot type
|
||
|
// [fVRoot] -- TRUE if a vroot, not a vdir
|
||
|
// [fIsIndexed] -- TRUE if it should be indexed, FALSE otherwise
|
||
|
//
|
||
|
// Returns: TRUE if scope was added or changed
|
||
|
//
|
||
|
// History: 11-Feb-96 KyleP Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CVMap::Add( WCHAR const * vroot,
|
||
|
WCHAR const * root,
|
||
|
BOOL fAutomatic,
|
||
|
ULONG & idNew,
|
||
|
CiVRootTypeEnum eType,
|
||
|
BOOL fVRoot,
|
||
|
BOOL fIsIndexed )
|
||
|
{
|
||
|
Win4Assert( eType == W3VRoot ||
|
||
|
eType == NNTPVRoot ||
|
||
|
eType == IMAPVRoot );
|
||
|
|
||
|
Win4Assert( !fIsIndexed || fVRoot );
|
||
|
|
||
|
CLock lock(_mutex);
|
||
|
|
||
|
unsigned ccVRoot = wcslen(vroot);
|
||
|
unsigned ccPRoot = wcslen(root);
|
||
|
|
||
|
Win4Assert( ccVRoot < MAX_PATH );
|
||
|
Win4Assert( ccPRoot < MAX_PATH );
|
||
|
|
||
|
ULONG idParent = INVALID_VMAP_INDEX;
|
||
|
ULONG ccParent = 0;
|
||
|
|
||
|
idNew = INVALID_VMAP_INDEX;
|
||
|
BOOL fWasInUse = FALSE;
|
||
|
BOOL fWasAutomatic = FALSE;
|
||
|
BOOL fWasManual = FALSE;
|
||
|
BOOL fPRootChanged = TRUE;
|
||
|
BOOL fWasNonIndexedVDir = FALSE;
|
||
|
ULONG idOldParent = INVALID_VMAP_INDEX;
|
||
|
|
||
|
//
|
||
|
// Find virtual parent.
|
||
|
//
|
||
|
|
||
|
for ( unsigned i = 0; i < _aMap.Count(); i++ )
|
||
|
{
|
||
|
//
|
||
|
// Is the new entry already in the list?
|
||
|
//
|
||
|
|
||
|
if ( !_aMap[i].IsFree() )
|
||
|
{
|
||
|
//
|
||
|
// Should we even consider this entry?
|
||
|
//
|
||
|
|
||
|
if ( (W3VRoot == eType) && !_aMap[i].IsW3() )
|
||
|
continue;
|
||
|
|
||
|
if ( (NNTPVRoot == eType) && !_aMap[i].IsNNTP() )
|
||
|
continue;
|
||
|
|
||
|
if ( (IMAPVRoot == eType) && !_aMap[i].IsIMAP() )
|
||
|
continue;
|
||
|
|
||
|
if ( _aMap[i].IsVirtualMatch( vroot, ccVRoot ) )
|
||
|
{
|
||
|
//
|
||
|
// Collect stats:
|
||
|
//
|
||
|
|
||
|
fWasInUse = _aMap[i].IsInUse();
|
||
|
fWasAutomatic = _aMap[i].IsAutomatic();
|
||
|
fWasManual = _aMap[i].IsManual();
|
||
|
fWasNonIndexedVDir = _aMap[i].IsNonIndexedVDir();
|
||
|
fPRootChanged = !_aMap[i].IsPhysicalMatch( root, ccPRoot );
|
||
|
idOldParent = _aMap[i].Parent();
|
||
|
|
||
|
ciDebugOut(( DEB_ITRACE,
|
||
|
"vroot '%ws', fWasInUse %d, fIsIndexed %d, fWasNonIndexedVDir %d\n",
|
||
|
vroot, fWasInUse, fIsIndexed, fWasNonIndexedVDir ));
|
||
|
|
||
|
//
|
||
|
// If there is no change, we can return w/o doing anything.
|
||
|
//
|
||
|
|
||
|
if ( ( ( fWasInUse && fIsIndexed ) || ( !fWasInUse && !fIsIndexed ) ) &&
|
||
|
( (fWasNonIndexedVDir && !fVRoot) || (!fWasNonIndexedVDir && fVRoot) ) &&
|
||
|
( (fAutomatic && fWasAutomatic) || (!fAutomatic && fWasManual) ) &&
|
||
|
!fPRootChanged )
|
||
|
{
|
||
|
ciDebugOut(( DEB_ITRACE, "no change for '%ws'\n", vroot ));
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ciDebugOut(( DEB_ITRACE, "modified vroot entry for '%ws'\n", vroot ));
|
||
|
idNew = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Is this a longer physical path match?
|
||
|
//
|
||
|
|
||
|
unsigned ccMatch = _aMap[i].PhysicalMatchLen( root );
|
||
|
|
||
|
if ( ccMatch > ccParent && ccMatch <= ccPRoot )
|
||
|
{
|
||
|
ccParent = ccMatch;
|
||
|
idParent = i;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
idNew = i;
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Add new root.
|
||
|
//
|
||
|
|
||
|
CRcovStorageHdr & hdr = _xrsoMap->GetHeader();
|
||
|
CRcovStrmWriteTrans xact( _xrsoMap.GetReference() );
|
||
|
CRcovStrmWriteIter iter( xact, sizeof(CVMapDesc) );
|
||
|
|
||
|
Win4Assert( _aMap.Count() == hdr.GetCount( hdr.GetPrimary() ) );
|
||
|
|
||
|
//
|
||
|
// This may be a new record.
|
||
|
//
|
||
|
|
||
|
BOOL fAppend;
|
||
|
|
||
|
if ( idNew == INVALID_VMAP_INDEX )
|
||
|
{
|
||
|
ciDebugOut(( DEB_ITRACE, "new vroot entry for '%ws'\n", vroot ));
|
||
|
idNew = _aMap.Count();
|
||
|
fAppend = TRUE;
|
||
|
}
|
||
|
else
|
||
|
fAppend = FALSE;
|
||
|
|
||
|
_aMap[idNew].Init( vroot,
|
||
|
ccVRoot,
|
||
|
root,
|
||
|
ccPRoot,
|
||
|
idParent,
|
||
|
fAutomatic,
|
||
|
eType,
|
||
|
fIsIndexed,
|
||
|
!fVRoot );
|
||
|
|
||
|
//
|
||
|
// This may have been an upgrade (not a new root), so add back previous state.
|
||
|
//
|
||
|
|
||
|
if ( fWasAutomatic )
|
||
|
_aMap[idNew].SetAutomatic();
|
||
|
|
||
|
if ( fWasManual )
|
||
|
_aMap[idNew].SetManual();
|
||
|
|
||
|
//
|
||
|
// Write out changes.
|
||
|
//
|
||
|
if ( fAppend )
|
||
|
iter.AppendRec( &_aMap[idNew] );
|
||
|
else
|
||
|
iter.SetRec( &_aMap[idNew], idNew );
|
||
|
//
|
||
|
// Look for roots that used to point at parent. They may need to be changed.
|
||
|
// Only bother if root was not previously in use.
|
||
|
//
|
||
|
|
||
|
Win4Assert( !_fDirty );
|
||
|
_fDirty = (fWasInUse != _aMap[idNew].IsInUse() || fPRootChanged);
|
||
|
|
||
|
//
|
||
|
// Put this root in the hierarchy.
|
||
|
//
|
||
|
|
||
|
if ( _fDirty && fVRoot )
|
||
|
{
|
||
|
for ( i = 0; i < _aMap.Count(); i++ )
|
||
|
{
|
||
|
if ( _aMap[i].IsFree() || !_aMap[i].IsInUse() )
|
||
|
continue;
|
||
|
|
||
|
//
|
||
|
// If physical root changed, then we need to adjust a lot of parent pointers.
|
||
|
// Stage one is equivalent to removing the old root.
|
||
|
//
|
||
|
|
||
|
if ( fPRootChanged && _aMap[i].Parent() == idNew )
|
||
|
{
|
||
|
Win4Assert( i != idNew );
|
||
|
ciDebugOut(( DEB_ITRACE, "VRoot %d has new parent %d\n", i, idNew ));
|
||
|
|
||
|
_aMap[i].SetParent( idOldParent );
|
||
|
|
||
|
iter.SetRec( &_aMap[i], i );
|
||
|
}
|
||
|
|
||
|
if ( _aMap[i].Parent() != idParent )
|
||
|
continue;
|
||
|
|
||
|
if ( i == idNew )
|
||
|
continue;
|
||
|
|
||
|
//
|
||
|
// Is this a longer physical path match?
|
||
|
//
|
||
|
|
||
|
unsigned ccMatch = _aMap[i].PhysicalMatchLen( root );
|
||
|
|
||
|
if ( ccMatch >= ccPRoot )
|
||
|
{
|
||
|
ciDebugOut(( DEB_ITRACE, "VRoot %d has new parent %d\n", i, idNew ));
|
||
|
|
||
|
_aMap[i].SetParent( idNew );
|
||
|
|
||
|
iter.SetRec( &_aMap[i], i );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Finish transaction
|
||
|
//
|
||
|
|
||
|
struct CRcovUserHdr data;
|
||
|
RtlCopyMemory( &data._abHdr, &_fDirty, sizeof(_fDirty) );
|
||
|
|
||
|
hdr.SetUserHdr( hdr.GetBackup(), data );
|
||
|
hdr.SetCount( hdr.GetBackup(), _aMap.Count() );
|
||
|
|
||
|
xact.Commit();
|
||
|
|
||
|
RecomputeNonIndexedInfo();
|
||
|
DumpVMap();
|
||
|
|
||
|
return _fDirty;
|
||
|
} //Add
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CVMap::Remove, public
|
||
|
//
|
||
|
// Synopsis: Remove virtual/physical mapping
|
||
|
//
|
||
|
// Arguments: [vroot] -- New virtual root
|
||
|
// [fOnlyIfAutomatic] -- If TRUE, then a manual root will not
|
||
|
// be removed
|
||
|
// [idOld] -- Id which was removed
|
||
|
// [idNew] -- Id which replaces [idOld] (farther up physical path)
|
||
|
// [eType] -- VRoot type
|
||
|
// [fVRoot] -- TRUE if a vroot, FALSE if a vdir
|
||
|
//
|
||
|
// Returns: TRUE if scope was removed
|
||
|
//
|
||
|
// History: 11-Feb-96 KyleP Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CVMap::Remove( WCHAR const * vroot,
|
||
|
BOOL fOnlyIfAutomatic,
|
||
|
ULONG & idOld,
|
||
|
ULONG & idNew,
|
||
|
CiVRootTypeEnum eType,
|
||
|
BOOL fVRoot )
|
||
|
{
|
||
|
Win4Assert( eType == W3VRoot ||
|
||
|
eType == NNTPVRoot ||
|
||
|
eType == IMAPVRoot );
|
||
|
|
||
|
CLock lock(_mutex);
|
||
|
|
||
|
unsigned ccVRoot = wcslen(vroot);
|
||
|
|
||
|
//
|
||
|
// Find id of root.
|
||
|
//
|
||
|
|
||
|
idOld = INVALID_VMAP_INDEX;
|
||
|
|
||
|
for ( unsigned i = 0; i < _aMap.Count(); i++ )
|
||
|
{
|
||
|
BOOL fSameType = ( ( ( W3VRoot == eType ) && _aMap[i].IsW3() ) ||
|
||
|
( ( NNTPVRoot == eType ) && _aMap[i].IsNNTP() ) ||
|
||
|
( ( IMAPVRoot == eType ) && _aMap[i].IsIMAP() ) );
|
||
|
|
||
|
if ( !_aMap[i].IsFree() &&
|
||
|
fSameType &&
|
||
|
_aMap[i].IsVirtualMatch( vroot, ccVRoot ) )
|
||
|
{
|
||
|
idOld = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( idOld == INVALID_VMAP_INDEX )
|
||
|
return FALSE;
|
||
|
|
||
|
BOOL fWasInUse = _aMap[idOld].IsInUse();
|
||
|
|
||
|
//
|
||
|
// Turn off either automatic bit or manual bit.
|
||
|
//
|
||
|
|
||
|
if ( fOnlyIfAutomatic )
|
||
|
{
|
||
|
//
|
||
|
// When a root is deleted by Gibraltar, it is *really* deleted.
|
||
|
//
|
||
|
|
||
|
_aMap[idOld].ClearAutomatic();
|
||
|
_aMap[idOld].ClearManual();
|
||
|
_aMap[idOld].ClearInUse();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// If this is an automatic root, then put the
|
||
|
// root under manual control (to keep it deleted),
|
||
|
// otherwise clear the manual flag to free up the entry.
|
||
|
//
|
||
|
|
||
|
if ( _aMap[idOld].IsAutomatic() )
|
||
|
_aMap[idOld].SetManual();
|
||
|
else
|
||
|
_aMap[idOld].ClearManual();
|
||
|
|
||
|
_aMap[idOld].ClearInUse();
|
||
|
}
|
||
|
|
||
|
idNew = _aMap[i].Parent();
|
||
|
|
||
|
//
|
||
|
// Make persistent changes
|
||
|
//
|
||
|
|
||
|
CRcovStorageHdr & hdr = _xrsoMap->GetHeader();
|
||
|
CRcovStrmWriteTrans xact( _xrsoMap.GetReference() );
|
||
|
CRcovStrmWriteIter iter( xact, sizeof(CVMapDesc) );
|
||
|
|
||
|
if ( !_aMap[idOld].IsAutomatic() && !_aMap[idOld].IsManual() )
|
||
|
_aMap[idOld].Delete();
|
||
|
|
||
|
iter.SetRec( &_aMap[idOld], idOld );
|
||
|
|
||
|
//
|
||
|
// Look for roots that used to point here. They will need to be changed.
|
||
|
// Change *only* if we really decided we're not tracking this root.
|
||
|
// Only bother if we really stopped using the root.
|
||
|
//
|
||
|
|
||
|
# if CIDBG == 1
|
||
|
if( _aMap[idOld].IsFree() )
|
||
|
Win4Assert( !_aMap[idOld].IsInUse() );
|
||
|
# endif
|
||
|
|
||
|
if ( !_aMap[idOld].IsInUse() && fWasInUse )
|
||
|
{
|
||
|
for ( i = 0; i < _aMap.Count(); i++ )
|
||
|
{
|
||
|
if ( _aMap[i].IsFree() )
|
||
|
continue;
|
||
|
|
||
|
if ( _aMap[i].Parent() == idOld )
|
||
|
{
|
||
|
ciDebugOut(( DEB_ITRACE, "VRoot %d has new parent %d\n", i, idNew ));
|
||
|
|
||
|
_aMap[i].SetParent( idNew );
|
||
|
|
||
|
iter.SetRec( &_aMap[i], i );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Finish transaction
|
||
|
//
|
||
|
|
||
|
Win4Assert( !_fDirty );
|
||
|
ciDebugOut(( DEB_ITRACE, "fVRoot, isinuse %d, wasinuse %d\n",
|
||
|
_aMap[idOld].IsInUse(), fWasInUse ));
|
||
|
_fDirty = (!fVRoot || !_aMap[idOld].IsInUse() && fWasInUse);
|
||
|
struct CRcovUserHdr data;
|
||
|
RtlCopyMemory( &data._abHdr, &_fDirty, sizeof(_fDirty) );
|
||
|
|
||
|
hdr.SetUserHdr( hdr.GetBackup(), data );
|
||
|
hdr.SetCount( hdr.GetBackup(), _aMap.Count() );
|
||
|
|
||
|
xact.Commit();
|
||
|
|
||
|
RecomputeNonIndexedInfo();
|
||
|
DumpVMap();
|
||
|
|
||
|
ciDebugOut(( DEB_ITRACE, "vmap::remove fDirty: %d\n", _fDirty ));
|
||
|
|
||
|
return _fDirty;
|
||
|
} //Remove
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CVMap::MarkClean, public
|
||
|
//
|
||
|
// Synopsis: Used to indicate all modifications based on path
|
||
|
// addition/removal are complete.
|
||
|
//
|
||
|
// History: 14-Feb-96 KyleP Added header
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void CVMap::MarkClean()
|
||
|
{
|
||
|
CLock lock(_mutex);
|
||
|
|
||
|
CRcovStorageHdr & hdr = _xrsoMap->GetHeader();
|
||
|
CRcovStrmAppendTrans xact( _xrsoMap.GetReference() );
|
||
|
|
||
|
_fDirty = FALSE;
|
||
|
struct CRcovUserHdr data;
|
||
|
RtlCopyMemory( &data._abHdr, &_fDirty, sizeof(_fDirty) );
|
||
|
|
||
|
hdr.SetUserHdr( hdr.GetBackup(), data );
|
||
|
hdr.SetCount( hdr.GetBackup(), _aMap.Count() );
|
||
|
|
||
|
xact.Commit();
|
||
|
} //MarkClean
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CVMap::PhysicalPathToId, private
|
||
|
//
|
||
|
// Synopsis: Given a physical path, find the virtual root that should
|
||
|
// be associated with it.
|
||
|
//
|
||
|
// Arguments: [path] -- Physical path
|
||
|
// [fNonIndexedVDirs] -- If TRUE, returns 0xffffffff or a
|
||
|
// non-indexed vdir. If FALSE, returns
|
||
|
// an indexed vroot or 0xffffffff.
|
||
|
//
|
||
|
// Returns: Id of virtual root
|
||
|
//
|
||
|
// History: 11-Feb-96 KyleP Added header
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
ULONG CVMap::PhysicalPathToId(
|
||
|
WCHAR const * path,
|
||
|
BOOL fNonIndexedVDirs )
|
||
|
{
|
||
|
//
|
||
|
// Find virtual parent.
|
||
|
//
|
||
|
|
||
|
unsigned ccPath = wcslen(path);
|
||
|
|
||
|
ULONG idParent = INVALID_VMAP_INDEX;
|
||
|
ULONG ccParent = 0;
|
||
|
|
||
|
for ( unsigned i = 0; i < _aMap.Count(); i++ )
|
||
|
{
|
||
|
if ( _aMap[i].IsFree() ||
|
||
|
( !fNonIndexedVDirs && !_aMap[i].IsInUse() ) ||
|
||
|
( fNonIndexedVDirs && !_aMap[i].IsNonIndexedVDir() ) )
|
||
|
continue;
|
||
|
|
||
|
if ( !fNonIndexedVDirs )
|
||
|
{
|
||
|
BOOL fIgnore = FALSE;
|
||
|
|
||
|
for ( unsigned x = 0; x < _aExcludeParent.Count(); x++ )
|
||
|
{
|
||
|
// If 'i' is a parent that should be excluded because the
|
||
|
// file is in a non-indexed vdir of vroot 'i', ignore it.
|
||
|
|
||
|
if ( i == _aExcludeParent[x] )
|
||
|
{
|
||
|
Win4Assert( _aMap[x].IsNonIndexedVDir() );
|
||
|
if ( _aMap[x].IsInPhysicalScope( path, ccPath ) )
|
||
|
{
|
||
|
fIgnore = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( fIgnore )
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Is this a longer physical path match?
|
||
|
//
|
||
|
|
||
|
unsigned ccMatch = _aMap[i].PhysicalMatchLen( path );
|
||
|
|
||
|
if ( ccMatch > ccParent && ccMatch < ccPath )
|
||
|
{
|
||
|
ccParent = ccMatch;
|
||
|
idParent = i;
|
||
|
}
|
||
|
else if ( ccMatch > 0 && ccMatch == ccParent )
|
||
|
{
|
||
|
//
|
||
|
// Consider the case of multiple virtual roots pointing to the
|
||
|
// same place in the physical heirarchy:
|
||
|
//
|
||
|
// v0
|
||
|
// \
|
||
|
// \
|
||
|
// v1 -> v2 -> v3
|
||
|
//
|
||
|
// Files under v1/v2/v3 must be tagged with id v1, or we will
|
||
|
// not recognize v1 as a valid virtual root for the file. So
|
||
|
// if we happened to find v2 or v3 first, we need to swap
|
||
|
// roots if we can get to the old best match from the new best
|
||
|
// match by traversing parent links.
|
||
|
//
|
||
|
|
||
|
for ( unsigned id = _aMap[i].Parent();
|
||
|
id != INVALID_VMAP_INDEX;
|
||
|
id = _aMap[id].Parent() )
|
||
|
{
|
||
|
//
|
||
|
// Have we traversed up the tree?
|
||
|
//
|
||
|
|
||
|
if ( _aMap[id].PhysicalLength() < ccParent )
|
||
|
break;
|
||
|
|
||
|
//
|
||
|
// Did we find the previous parent?
|
||
|
//
|
||
|
|
||
|
if ( id == idParent )
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( id == idParent )
|
||
|
idParent = i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return idParent;
|
||
|
} //PhysicalPathToId
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CVMap::PhysicalPathToId, public
|
||
|
//
|
||
|
// Synopsis: Given a physical path, find the virtual root that should
|
||
|
// be associated with it.
|
||
|
//
|
||
|
// Arguments: [path] -- Physical path
|
||
|
//
|
||
|
// Returns: Id of virtual root
|
||
|
//
|
||
|
// History: 11-Feb-96 KyleP Added header
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
ULONG CVMap::PhysicalPathToId( WCHAR const * path )
|
||
|
{
|
||
|
CLock lock(_mutex);
|
||
|
|
||
|
// first try an indexed vroot, but settle for a non-indexed-vdir
|
||
|
|
||
|
ULONG id = PhysicalPathToId( path, FALSE );
|
||
|
|
||
|
if ( INVALID_VMAP_INDEX == id )
|
||
|
id = PhysicalPathToId( path, TRUE );
|
||
|
|
||
|
return id;
|
||
|
} //PhysicalPathToId
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CVMap::VirtualToPhysicalRoot, public
|
||
|
//
|
||
|
// Synopsis: Given a virtual path, returns corresponding physical root.
|
||
|
// Unlike the iterative version of this method, this version
|
||
|
// requires an exact match on virtual root.
|
||
|
//
|
||
|
// Arguments: [pwcVRoot] -- Virtual root
|
||
|
// [ccVRoot] -- Size in chars of [pwcVRoot]
|
||
|
// [lcaseFunnyPRoot] -- Physical root
|
||
|
// [ccPRoot] -- returns actual count of chars in [lcaseFunnyPRoot]
|
||
|
//
|
||
|
// Returns: TRUE if match was found.
|
||
|
//
|
||
|
// History: 11-Feb-96 KyleP Created
|
||
|
// 15 Mar 96 AlanW Fixed bugs in enumeration which missed
|
||
|
// some roots and erroneously added others.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CVMap::VirtualToPhysicalRoot( WCHAR const * pwcVRoot,
|
||
|
unsigned ccVRoot,
|
||
|
CLowerFunnyPath & lcaseFunnyPRoot,
|
||
|
unsigned & ccPRoot )
|
||
|
{
|
||
|
//
|
||
|
// Find id of root.
|
||
|
//
|
||
|
|
||
|
unsigned iBmk = INVALID_VMAP_INDEX;
|
||
|
|
||
|
for ( unsigned i = 0; i < _aMap.Count(); i++ )
|
||
|
{
|
||
|
if ( !_aMap[i].IsFree() &&
|
||
|
_aMap[i].IsVirtualMatch( pwcVRoot, ccVRoot ) )
|
||
|
{
|
||
|
iBmk = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( iBmk == INVALID_VMAP_INDEX )
|
||
|
return FALSE;
|
||
|
|
||
|
//
|
||
|
// Copy out physical root.
|
||
|
//
|
||
|
|
||
|
ccPRoot = _aMap[iBmk].PhysicalLength() - 1;
|
||
|
|
||
|
//
|
||
|
// Special case root.
|
||
|
//
|
||
|
|
||
|
if ( _aMap[iBmk].PhysicalPath()[1] == L':' )
|
||
|
{
|
||
|
if ( ccPRoot == 2 )
|
||
|
ccPRoot++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
unsigned cSlash = 0;
|
||
|
|
||
|
for ( unsigned i = 0; i < ccPRoot && cSlash < 4; i++ )
|
||
|
{
|
||
|
if ( _aMap[iBmk].PhysicalPath()[i] == L'\\' )
|
||
|
cSlash++;
|
||
|
}
|
||
|
|
||
|
if ( cSlash < 4 )
|
||
|
{
|
||
|
Win4Assert( cSlash == 3 );
|
||
|
ccPRoot++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
lcaseFunnyPRoot.SetPath( _aMap[iBmk].PhysicalPath(), ccPRoot );
|
||
|
|
||
|
return TRUE;
|
||
|
} //VirtualToPhysicalRoot
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CVMap::VirtualToPhysicalRoot, public
|
||
|
//
|
||
|
// Synopsis: Given a virtual path, returns a virtual root under that
|
||
|
// virtual path, and the corresponding physical root. Will
|
||
|
// not return overlapping virtual roots.
|
||
|
//
|
||
|
// There may be multiple virtual roots that match the virtual
|
||
|
// path passed in, so this should be called in a loop until
|
||
|
// FALSE is returned. The [iBmk] should be zero for the first
|
||
|
// call in the iteration.
|
||
|
//
|
||
|
// Arguments: [pwcVPath] -- Virtual path
|
||
|
// [ccVPath] -- Size in chars of [pwcVPath]
|
||
|
// [xwcsVRoot] -- Virtual root
|
||
|
// [ccVRoot] -- returns count of chars in [xwcsVRoot]
|
||
|
// [lcaseFunnyPRoot] -- Physical root
|
||
|
// [ccPRoot] -- Size in actual chars of [lcaseFunnyPRoot]
|
||
|
// [iBmk] -- Bookmark for iteration.
|
||
|
//
|
||
|
// Returns: TRUE if match was found.
|
||
|
//
|
||
|
// History: 11-Feb-96 KyleP Created
|
||
|
// 15 Mar 96 AlanW Fixed bugs in enumeration which missed
|
||
|
// some roots and erroneously added others.
|
||
|
// 24 Nov 99 KLam Don't pre-reference zero length strings.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CVMap::VirtualToPhysicalRoot( WCHAR const * pwcVPath,
|
||
|
unsigned ccVPath,
|
||
|
XGrowable<WCHAR> & xwcsVRoot,
|
||
|
unsigned & ccVRoot,
|
||
|
CLowerFunnyPath & lcaseFunnyPRoot,
|
||
|
unsigned & ccPRoot,
|
||
|
unsigned & iBmk )
|
||
|
{
|
||
|
|
||
|
CLock lock(_mutex);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Path must be terminated with a backslash, or the path can be of
|
||
|
// 0 characters.
|
||
|
//
|
||
|
|
||
|
XGrowable<WCHAR> xwcTemp;
|
||
|
|
||
|
if ( (0 != ccVPath) && (pwcVPath[ccVPath-1] != L'\\') )
|
||
|
{
|
||
|
xwcTemp.SetSize( ccVPath + 1 );
|
||
|
RtlCopyMemory( xwcTemp.Get(), pwcVPath, ccVPath * sizeof(WCHAR) );
|
||
|
xwcTemp[ccVPath] = L'\\';
|
||
|
|
||
|
pwcVPath = xwcTemp.Get();
|
||
|
ccVPath++;
|
||
|
}
|
||
|
|
||
|
CScopeMatch Match( pwcVPath, ccVPath );
|
||
|
|
||
|
for ( ; iBmk < _aMap.Count(); iBmk++ )
|
||
|
{
|
||
|
if ( _aMap[iBmk].IsFree() || !_aMap[iBmk].IsInUse() )
|
||
|
continue;
|
||
|
|
||
|
//
|
||
|
// Possible match?
|
||
|
//
|
||
|
|
||
|
if ( Match.IsInScope( _aMap[iBmk].VirtualPath(),
|
||
|
_aMap[iBmk].VirtualLength() ) )
|
||
|
{
|
||
|
//
|
||
|
// The virtual root is a match. If there is a parent of
|
||
|
// this virtual root in the physical name space, ignore this
|
||
|
// one in favor of the other one, farther up the tree (as long
|
||
|
// as the parent root is also a scope match).
|
||
|
//
|
||
|
|
||
|
for ( unsigned idParent = _aMap[ iBmk ].Parent();
|
||
|
idParent != INVALID_VMAP_INDEX;
|
||
|
idParent = _aMap[idParent].Parent() )
|
||
|
{
|
||
|
if ( Match.IsInScope( _aMap[idParent].VirtualPath(),
|
||
|
_aMap[idParent].VirtualLength() ) )
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Did we get all the way to the top of chain without
|
||
|
// finding another match?
|
||
|
//
|
||
|
|
||
|
if ( idParent == INVALID_VMAP_INDEX )
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( Match.IsPrefix( _aMap[iBmk].VirtualPath(),
|
||
|
_aMap[iBmk].VirtualLength() ) )
|
||
|
{
|
||
|
//
|
||
|
// The virtual root is a prefix of the path. Return it only
|
||
|
// if there is not some other vroot that is a better match.
|
||
|
//
|
||
|
|
||
|
BOOL fBetterMatch = FALSE;
|
||
|
for ( unsigned iRoot = 0;
|
||
|
!fBetterMatch && iRoot < _aMap.Count();
|
||
|
iRoot++ )
|
||
|
{
|
||
|
if ( iRoot == iBmk ||
|
||
|
_aMap[iRoot].IsFree() )
|
||
|
continue;
|
||
|
|
||
|
if ( _aMap[iBmk].VirtualLength() < _aMap[iRoot].VirtualLength() &&
|
||
|
Match.IsPrefix( _aMap[iRoot].VirtualPath(),
|
||
|
_aMap[iRoot].VirtualLength() ) )
|
||
|
{
|
||
|
fBetterMatch = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Was there no better match? If so, return this root.
|
||
|
//
|
||
|
if ( ! fBetterMatch )
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( iBmk < _aMap.Count() )
|
||
|
{
|
||
|
if ( ccVPath > _aMap[iBmk].VirtualLength() )
|
||
|
{
|
||
|
ccVRoot = ccVPath;
|
||
|
xwcsVRoot.SetBuf( pwcVPath, ccVPath );
|
||
|
|
||
|
unsigned ccExtra = ccVPath - _aMap[iBmk].VirtualLength();
|
||
|
ccPRoot = _aMap[iBmk].PhysicalLength() + ccExtra;
|
||
|
|
||
|
lcaseFunnyPRoot.SetPath( _aMap[iBmk].PhysicalPath(), _aMap[iBmk].PhysicalLength() );
|
||
|
lcaseFunnyPRoot.AppendPath( pwcVPath + _aMap[iBmk].VirtualLength(), ccExtra );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ccVRoot = _aMap[iBmk].VirtualLength();
|
||
|
xwcsVRoot.SetBuf( _aMap[iBmk].VirtualPath(), ccVRoot * sizeof(WCHAR) );
|
||
|
|
||
|
lcaseFunnyPRoot.SetPath( _aMap[iBmk].PhysicalPath(), ccPRoot = _aMap[iBmk].PhysicalLength() );
|
||
|
}
|
||
|
iBmk++;
|
||
|
return TRUE;
|
||
|
}
|
||
|
else
|
||
|
return FALSE;
|
||
|
} //VirtualToPhysicalRoot
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CVMap::VirtualToAllPhysicalRoots, public
|
||
|
//
|
||
|
// Synopsis: Like VirtualToPhysicalRoot, except returns all matches
|
||
|
// (rather than just the highest parent which matches)
|
||
|
// and also returns non-indexed matches. Returns type
|
||
|
// in ulType so caller can decide what to do with
|
||
|
// non-indexed matches.
|
||
|
//
|
||
|
// Arguments: [pwcVPath] -- Virtual path
|
||
|
// [ccVPath] -- Size in chars of [pwcVPath]
|
||
|
// [xwcsVRoot] -- Virtual root
|
||
|
// [ccVRoot] -- returns count of chars in [pwcVRoot]
|
||
|
// [lcaseFunnyPRoot] -- Physical root
|
||
|
// [ccPRoot] -- returns count of actual chars in [lcaseFunnyPRoot]
|
||
|
// [ulType] -- Match type
|
||
|
// [iBmk] -- Bookmark for iteration.
|
||
|
//
|
||
|
// Returns: TRUE if match was found.
|
||
|
//
|
||
|
// History: 01-Sep-97 Emilyb Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CVMap::VirtualToAllPhysicalRoots( WCHAR const * pwcVPath,
|
||
|
unsigned ccVPath,
|
||
|
XGrowable<WCHAR> & xwcsVRoot,
|
||
|
unsigned & ccVRoot,
|
||
|
CLowerFunnyPath & lcaseFunnyPRoot,
|
||
|
unsigned & ccPRoot,
|
||
|
ULONG & ulType,
|
||
|
unsigned & iBmk )
|
||
|
{
|
||
|
|
||
|
CLock lock(_mutex);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Path must be terminated with a backslash, or the path can be of
|
||
|
// 0 characters.
|
||
|
//
|
||
|
|
||
|
XGrowable<WCHAR> xwcTemp;
|
||
|
|
||
|
if ( ( 0 != ccVPath ) && ( pwcVPath[ccVPath-1] != L'\\' ) )
|
||
|
{
|
||
|
xwcTemp.SetSize( ccVPath + 1 );
|
||
|
RtlCopyMemory( xwcTemp.Get(), pwcVPath, ccVPath * sizeof(WCHAR) );
|
||
|
xwcTemp[ccVPath] = L'\\';
|
||
|
|
||
|
pwcVPath = xwcTemp.Get();
|
||
|
ccVPath++;
|
||
|
}
|
||
|
|
||
|
CScopeMatch Match( pwcVPath, ccVPath );
|
||
|
|
||
|
for ( ; iBmk < _aMap.Count(); iBmk++ )
|
||
|
{
|
||
|
if ( _aMap[iBmk].IsFree() )
|
||
|
continue;
|
||
|
|
||
|
//
|
||
|
// Possible match?
|
||
|
//
|
||
|
|
||
|
if ( Match.IsInScope( _aMap[iBmk].VirtualPath(),
|
||
|
_aMap[iBmk].VirtualLength() ) )
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( Match.IsPrefix( _aMap[iBmk].VirtualPath(),
|
||
|
_aMap[iBmk].VirtualLength() ) )
|
||
|
{
|
||
|
//
|
||
|
// The virtual root is a prefix of the path. Return it only
|
||
|
// if there is not some other vroot that is a better match.
|
||
|
//
|
||
|
|
||
|
BOOL fBetterMatch = FALSE;
|
||
|
for ( unsigned iRoot = 0;
|
||
|
!fBetterMatch && iRoot < _aMap.Count();
|
||
|
iRoot++ )
|
||
|
{
|
||
|
if ( iRoot == iBmk ||
|
||
|
_aMap[iRoot].IsFree() )
|
||
|
continue;
|
||
|
|
||
|
if ( _aMap[iBmk].VirtualLength() < _aMap[iRoot].VirtualLength() &&
|
||
|
Match.IsPrefix( _aMap[iRoot].VirtualPath(),
|
||
|
_aMap[iRoot].VirtualLength() ) )
|
||
|
{
|
||
|
fBetterMatch = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Was there no better match? If so, return this root.
|
||
|
//
|
||
|
if ( ! fBetterMatch )
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if ( iBmk < _aMap.Count() )
|
||
|
{
|
||
|
if ( ccVPath > _aMap[iBmk].VirtualLength() )
|
||
|
{
|
||
|
ccVRoot = ccVPath;
|
||
|
xwcsVRoot.SetBuf( pwcVPath, ccVPath );
|
||
|
|
||
|
unsigned ccExtra = ccVPath - _aMap[iBmk].VirtualLength();
|
||
|
ccPRoot = _aMap[iBmk].PhysicalLength() + ccExtra;
|
||
|
|
||
|
lcaseFunnyPRoot.SetPath( _aMap[iBmk].PhysicalPath(), _aMap[iBmk].PhysicalLength() );
|
||
|
lcaseFunnyPRoot.AppendPath( pwcVPath + _aMap[iBmk].VirtualLength(), ccExtra );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ccVRoot = _aMap[iBmk].VirtualLength();
|
||
|
xwcsVRoot.SetBuf( _aMap[iBmk].VirtualPath(), ccVRoot );
|
||
|
|
||
|
lcaseFunnyPRoot.SetPath( _aMap[iBmk].PhysicalPath(), ccPRoot = _aMap[iBmk].PhysicalLength() );
|
||
|
}
|
||
|
ulType = _aMap[iBmk].RootType();
|
||
|
|
||
|
iBmk++;
|
||
|
return TRUE;
|
||
|
}
|
||
|
else
|
||
|
return FALSE;
|
||
|
} //VirtualToAllPhysicalRoots
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CVMap::EnumerateRoot, public
|
||
|
//
|
||
|
// Synopsis: Enumerate all virtual paths
|
||
|
//
|
||
|
// Arguments: [xwcVRoot] -- Virtual root
|
||
|
// [ccVRoot] -- returns count of chars in [xwcVRoot]
|
||
|
// [lcaseFunnyPRoot] -- Physical root as funny path
|
||
|
// [ccPRoot] -- returns count of actual chars in [lcaseFunnyPRoot]
|
||
|
// [iBmk] -- Bookmark for iteration.
|
||
|
//
|
||
|
// Returns: Type of root (Manual or Automatic)
|
||
|
//
|
||
|
// History: 15-Feb-96 KyleP Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
ULONG CVMap::EnumerateRoot( XGrowable<WCHAR> & xwcVRoot,
|
||
|
unsigned & ccVRoot,
|
||
|
CLowerFunnyPath & lcaseFunnyPRoot,
|
||
|
unsigned & ccPRoot,
|
||
|
unsigned & iBmk )
|
||
|
{
|
||
|
|
||
|
CLock lock(_mutex);
|
||
|
|
||
|
for ( ; iBmk < _aMap.Count(); iBmk++ )
|
||
|
{
|
||
|
if ( !_aMap[iBmk].IsFree() )
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( iBmk < _aMap.Count() )
|
||
|
{
|
||
|
ccVRoot = _aMap[iBmk].VirtualLength() - 1;
|
||
|
|
||
|
//
|
||
|
// Special case root.
|
||
|
//
|
||
|
|
||
|
if ( 0 == ccVRoot )
|
||
|
ccVRoot++;
|
||
|
|
||
|
xwcVRoot.SetSize( ccVRoot + 1 );
|
||
|
xwcVRoot.SetBuf( _aMap[iBmk].VirtualPath(), ccVRoot );
|
||
|
xwcVRoot[ccVRoot] = 0;
|
||
|
|
||
|
ccPRoot = _aMap[iBmk].PhysicalLength() - 1;
|
||
|
|
||
|
//
|
||
|
// Special case root.
|
||
|
//
|
||
|
|
||
|
if ( _aMap[iBmk].PhysicalPath()[1] == L':' )
|
||
|
{
|
||
|
if ( ccPRoot == 2 )
|
||
|
ccPRoot++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
unsigned cSlash = 0;
|
||
|
|
||
|
for ( unsigned i = 0; i < ccPRoot && cSlash < 4; i++ )
|
||
|
{
|
||
|
if ( _aMap[iBmk].PhysicalPath()[i] == L'\\' )
|
||
|
cSlash++;
|
||
|
}
|
||
|
|
||
|
if ( cSlash < 4 )
|
||
|
{
|
||
|
Win4Assert( cSlash == 3 );
|
||
|
ccPRoot++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
lcaseFunnyPRoot.SetPath( _aMap[iBmk].PhysicalPath(), ccPRoot );
|
||
|
|
||
|
ULONG eType = _aMap[iBmk].RootType();
|
||
|
|
||
|
iBmk++;
|
||
|
|
||
|
return eType;
|
||
|
}
|
||
|
else
|
||
|
return (ULONG) PCatalog::EndRoot;
|
||
|
} //EnumerateRoot
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CVMap::DoesPhysicalRootExist, public
|
||
|
//
|
||
|
// Synopsis: Determines whether a physical root is in the table
|
||
|
//
|
||
|
// Arguments: [pwcPRoot] -- Physical root to find
|
||
|
//
|
||
|
// Returns: TRUE if the physical root exists in the table
|
||
|
//
|
||
|
// History: 16-Oct-96 dlee Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CVMap::DoesPhysicalRootExist(
|
||
|
WCHAR const * pwcPRoot )
|
||
|
{
|
||
|
unsigned cwcPRoot = wcslen( pwcPRoot );
|
||
|
|
||
|
for ( unsigned i = 0; i < _aMap.Count(); i++ )
|
||
|
{
|
||
|
if ( !_aMap[i].IsFree() &&
|
||
|
!_aMap[i].IsNonIndexedVDir() &&
|
||
|
_aMap[i].IsPhysicalMatch( pwcPRoot, cwcPRoot ) )
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
} //DoesPhysicalRootExist
|
||
|
|