|
|
//+---------------------------------------------------------------------------
//
// 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
|